rtmpdh: Add fate test for the DH handshake routine
[ffmpeg.git] / libavformat / rtmpdh.c
1 /*
2  * RTMP Diffie-Hellmann utilities
3  * Copyright (c) 2009 Andrej Stepanchuk
4  * Copyright (c) 2009-2010 Howard Chu
5  * Copyright (c) 2012 Samuel Pitoiset
6  *
7  * This file is part of Libav.
8  *
9  * Libav is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * Libav is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with Libav; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23
24 /**
25  * @file
26  * RTMP Diffie-Hellmann utilities
27  */
28
29 #include "config.h"
30 #include "rtmpdh.h"
31 #include "libavutil/random_seed.h"
32
33 #define P1024                                          \
34     "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
35     "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
36     "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
37     "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
38     "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \
39     "FFFFFFFFFFFFFFFF"
40
41 #define Q1024                                          \
42     "7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68" \
43     "948127044533E63A0105DF531D89CD9128A5043CC71A026E" \
44     "F7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122" \
45     "F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6" \
46     "F71C35FDAD44CFD2D74F9208BE258FF324943328F67329C0" \
47     "FFFFFFFFFFFFFFFF"
48
49 #if CONFIG_NETTLE || CONFIG_GCRYPT
50 #if CONFIG_NETTLE
51 #define bn_new(bn)                      \
52     do {                                \
53         bn = av_malloc(sizeof(*bn));    \
54         if (bn)                         \
55             mpz_init2(bn, 1);           \
56     } while (0)
57 #define bn_free(bn)     \
58     do {                \
59         mpz_clear(bn);  \
60         av_free(bn);    \
61     } while (0)
62 #define bn_set_word(bn, w)          mpz_set_ui(bn, w)
63 #define bn_cmp(a, b)                mpz_cmp(a, b)
64 #define bn_copy(to, from)           mpz_set(to, from)
65 #define bn_sub_word(bn, w)          mpz_sub_ui(bn, bn, w)
66 #define bn_cmp_1(bn)                mpz_cmp_ui(bn, 1)
67 #define bn_num_bytes(bn)            (mpz_sizeinbase(bn, 2) + 7) / 8
68 #define bn_bn2bin(bn, buf, len)     nettle_mpz_get_str_256(len, buf, bn)
69 #define bn_bin2bn(bn, buf, len)                     \
70     do {                                            \
71         bn_new(bn);                                 \
72         if (bn)                                     \
73             nettle_mpz_set_str_256_u(bn, len, buf); \
74     } while (0)
75 #define bn_hex2bn(bn, buf, ret)                     \
76     do {                                            \
77         bn_new(bn);                                 \
78         if (bn)                                     \
79             ret = (mpz_set_str(bn, buf, 16) == 0);  \
80         else                                        \
81             ret = 1;                                \
82     } while (0)
83 #define bn_modexp(bn, y, q, p)      mpz_powm(bn, y, q, p)
84 #define bn_random(bn, num_bytes)                    \
85     do {                                            \
86         gmp_randstate_t rs;                         \
87         gmp_randinit_mt(rs);                        \
88         gmp_randseed_ui(rs, av_get_random_seed());  \
89         mpz_urandomb(bn, rs, num_bytes);            \
90         gmp_randclear(rs);                          \
91     } while (0)
92 #elif CONFIG_GCRYPT
93 #define bn_new(bn)                  bn = gcry_mpi_new(1)
94 #define bn_free(bn)                 gcry_mpi_release(bn)
95 #define bn_set_word(bn, w)          gcry_mpi_set_ui(bn, w)
96 #define bn_cmp(a, b)                gcry_mpi_cmp(a, b)
97 #define bn_copy(to, from)           gcry_mpi_set(to, from)
98 #define bn_sub_word(bn, w)          gcry_mpi_sub_ui(bn, bn, w)
99 #define bn_cmp_1(bn)                gcry_mpi_cmp_ui(bn, 1)
100 #define bn_num_bytes(bn)            (gcry_mpi_get_nbits(bn) + 7) / 8
101 #define bn_bn2bin(bn, buf, len)     gcry_mpi_print(GCRYMPI_FMT_USG, buf, len, NULL, bn)
102 #define bn_bin2bn(bn, buf, len)     gcry_mpi_scan(&bn, GCRYMPI_FMT_USG, buf, len, NULL)
103 #define bn_hex2bn(bn, buf, ret)     ret = (gcry_mpi_scan(&bn, GCRYMPI_FMT_HEX, buf, 0, 0) == 0)
104 #define bn_modexp(bn, y, q, p)      gcry_mpi_powm(bn, y, q, p)
105 #define bn_random(bn, num_bytes)    gcry_mpi_randomize(bn, num_bytes, GCRY_WEAK_RANDOM)
106 #endif
107
108 #define MAX_BYTES 18000
109
110 #define dh_new()                    av_malloc(sizeof(FF_DH))
111
112 static FFBigNum dh_generate_key(FF_DH *dh)
113 {
114     int num_bytes;
115
116     num_bytes = bn_num_bytes(dh->p) - 1;
117     if (num_bytes <= 0 || num_bytes > MAX_BYTES)
118         return NULL;
119
120     bn_new(dh->priv_key);
121     if (!dh->priv_key)
122         return NULL;
123     bn_random(dh->priv_key, num_bytes);
124
125     bn_new(dh->pub_key);
126     if (!dh->pub_key) {
127         bn_free(dh->priv_key);
128         return NULL;
129     }
130
131     bn_modexp(dh->pub_key, dh->g, dh->priv_key, dh->p);
132
133     return dh->pub_key;
134 }
135
136 static int dh_compute_key(FF_DH *dh, FFBigNum pub_key_bn,
137                           uint32_t secret_key_len, uint8_t *secret_key)
138 {
139     FFBigNum k;
140     int num_bytes;
141
142     num_bytes = bn_num_bytes(dh->p);
143     if (num_bytes <= 0 || num_bytes > MAX_BYTES)
144         return -1;
145
146     bn_new(k);
147     if (!k)
148         return -1;
149
150     bn_modexp(k, pub_key_bn, dh->priv_key, dh->p);
151     bn_bn2bin(k, secret_key, secret_key_len);
152     bn_free(k);
153
154     /* return the length of the shared secret key like DH_compute_key */
155     return secret_key_len;
156 }
157
158 void ff_dh_free(FF_DH *dh)
159 {
160     if (!dh)
161         return;
162     bn_free(dh->p);
163     bn_free(dh->g);
164     bn_free(dh->pub_key);
165     bn_free(dh->priv_key);
166     av_free(dh);
167 }
168 #elif CONFIG_OPENSSL
169 #define bn_new(bn)                  bn = BN_new()
170 #define bn_free(bn)                 BN_free(bn)
171 #define bn_set_word(bn, w)          BN_set_word(bn, w)
172 #define bn_cmp(a, b)                BN_cmp(a, b)
173 #define bn_copy(to, from)           BN_copy(to, from)
174 #define bn_sub_word(bn, w)          BN_sub_word(bn, w)
175 #define bn_cmp_1(bn)                BN_cmp(bn, BN_value_one())
176 #define bn_num_bytes(bn)            BN_num_bytes(bn)
177 #define bn_bn2bin(bn, buf, len)     BN_bn2bin(bn, buf)
178 #define bn_bin2bn(bn, buf, len)     bn = BN_bin2bn(buf, len, 0)
179 #define bn_hex2bn(bn, buf, ret)     ret = BN_hex2bn(&bn, buf)
180 #define bn_modexp(bn, y, q, p)               \
181     do {                                     \
182         BN_CTX *ctx = BN_CTX_new();          \
183         if (!ctx)                            \
184             return AVERROR(ENOMEM);          \
185         if (!BN_mod_exp(bn, y, q, p, ctx)) { \
186             BN_CTX_free(ctx);                \
187             return AVERROR(EINVAL);          \
188         }                                    \
189         BN_CTX_free(ctx);                    \
190     } while (0)
191
192 #define dh_new()                                DH_new()
193 #define dh_generate_key(dh)                     DH_generate_key(dh)
194
195 static int dh_compute_key(FF_DH *dh, FFBigNum pub_key_bn,
196                           uint32_t secret_key_len, uint8_t *secret_key)
197 {
198     if (secret_key_len < DH_size(dh))
199         return AVERROR(EINVAL);
200     return DH_compute_key(secret_key, pub_key_bn, dh);
201 }
202
203 void ff_dh_free(FF_DH *dh)
204 {
205     if (!dh)
206         return;
207     DH_free(dh);
208 }
209 #endif
210
211 static int dh_is_valid_public_key(FFBigNum y, FFBigNum p, FFBigNum q)
212 {
213     FFBigNum bn = NULL;
214     int ret = AVERROR(EINVAL);
215
216     bn_new(bn);
217     if (!bn)
218         return AVERROR(ENOMEM);
219
220     /* y must lie in [2, p - 1] */
221     bn_set_word(bn, 1);
222     if (!bn_cmp(y, bn))
223         goto fail;
224
225     /* bn = p - 2 */
226     bn_copy(bn, p);
227     bn_sub_word(bn, 1);
228     if (!bn_cmp(y, bn))
229         goto fail;
230
231     /* Verify with Sophie-Germain prime
232      *
233      * This is a nice test to make sure the public key position is calculated
234      * correctly. This test will fail in about 50% of the cases if applied to
235      * random data.
236      */
237     /* y must fulfill y^q mod p = 1 */
238     bn_modexp(bn, y, q, p);
239
240     if (bn_cmp_1(bn))
241         goto fail;
242
243     ret = 0;
244 fail:
245     bn_free(bn);
246
247     return ret;
248 }
249
250 av_cold FF_DH *ff_dh_init(int key_len)
251 {
252     FF_DH *dh;
253     int ret;
254
255     if (!(dh = dh_new()))
256         return NULL;
257
258     bn_new(dh->g);
259     if (!dh->g)
260         goto fail;
261
262     bn_hex2bn(dh->p, P1024, ret);
263     if (!ret)
264         goto fail;
265
266     bn_set_word(dh->g, 2);
267     dh->length = key_len;
268
269     return dh;
270
271 fail:
272     ff_dh_free(dh);
273
274     return NULL;
275 }
276
277 int ff_dh_generate_public_key(FF_DH *dh)
278 {
279     int ret = 0;
280
281     while (!ret) {
282         FFBigNum q1 = NULL;
283
284         if (!dh_generate_key(dh))
285             return AVERROR(EINVAL);
286
287         bn_hex2bn(q1, Q1024, ret);
288         if (!ret)
289             return AVERROR(ENOMEM);
290
291         ret = dh_is_valid_public_key(dh->pub_key, dh->p, q1);
292         bn_free(q1);
293
294         if (!ret) {
295             /* the public key is valid */
296             break;
297         }
298     }
299
300     return ret;
301 }
302
303 int ff_dh_write_public_key(FF_DH *dh, uint8_t *pub_key, int pub_key_len)
304 {
305     int len;
306
307     /* compute the length of the public key */
308     len = bn_num_bytes(dh->pub_key);
309     if (len <= 0 || len > pub_key_len)
310         return AVERROR(EINVAL);
311
312     /* convert the public key value into big-endian form */
313     memset(pub_key, 0, pub_key_len);
314     bn_bn2bin(dh->pub_key, pub_key + pub_key_len - len, len);
315
316     return 0;
317 }
318
319 int ff_dh_compute_shared_secret_key(FF_DH *dh, const uint8_t *pub_key,
320                                     int pub_key_len, uint8_t *secret_key,
321                                     int secret_key_len)
322 {
323     FFBigNum q1 = NULL, pub_key_bn = NULL;
324     int ret;
325
326     /* convert the big-endian form of the public key into a bignum */
327     bn_bin2bn(pub_key_bn, pub_key, pub_key_len);
328     if (!pub_key_bn)
329         return AVERROR(ENOMEM);
330
331     /* convert the string containing a hexadecimal number into a bignum */
332     bn_hex2bn(q1, Q1024, ret);
333     if (!ret) {
334         ret = AVERROR(ENOMEM);
335         goto fail;
336     }
337
338     /* when the public key is valid we have to compute the shared secret key */
339     if ((ret = dh_is_valid_public_key(pub_key_bn, dh->p, q1)) < 0) {
340         goto fail;
341     } else if ((ret = dh_compute_key(dh, pub_key_bn, secret_key_len,
342                                      secret_key)) < 0) {
343         ret = AVERROR(EINVAL);
344         goto fail;
345     }
346
347 fail:
348     bn_free(pub_key_bn);
349     bn_free(q1);
350
351     return ret;
352 }
353
354 #ifdef TEST
355 static int test_random_shared_secret(void)
356 {
357     FF_DH *peer1 = NULL, *peer2 = NULL;
358     int ret;
359     uint8_t pubkey1[128], pubkey2[128];
360     uint8_t sharedkey1[128], sharedkey2[128];
361
362     peer1 = ff_dh_init(1024);
363     peer2 = ff_dh_init(1024);
364     if (!peer1 || !peer2) {
365         ret = AVERROR(ENOMEM);
366         goto fail;
367     }
368     if ((ret = ff_dh_generate_public_key(peer1)) < 0)
369         goto fail;
370     if ((ret = ff_dh_generate_public_key(peer2)) < 0)
371         goto fail;
372     if ((ret = ff_dh_write_public_key(peer1, pubkey1, sizeof(pubkey1))) < 0)
373         goto fail;
374     if ((ret = ff_dh_write_public_key(peer2, pubkey2, sizeof(pubkey2))) < 0)
375         goto fail;
376     if ((ret = ff_dh_compute_shared_secret_key(peer1, pubkey2, sizeof(pubkey2),
377                                                sharedkey1, sizeof(sharedkey1))) < 0)
378         goto fail;
379     if ((ret = ff_dh_compute_shared_secret_key(peer2, pubkey1, sizeof(pubkey1),
380                                                sharedkey2, sizeof(sharedkey2))) < 0)
381         goto fail;
382     if (memcmp(sharedkey1, sharedkey2, sizeof(sharedkey1))) {
383         printf("Mismatched generated shared key\n");
384         ret = AVERROR_INVALIDDATA;
385     } else {
386         printf("Generated shared key ok\n");
387     }
388 fail:
389     ff_dh_free(peer1);
390     ff_dh_free(peer2);
391     return ret;
392 }
393
394 static const char *private_key =
395     "976C18FCADC255B456564F74F3EEDA59D28AF6B744D743F2357BFD2404797EF896EF1A"
396     "7C1CBEAAA3AB60AF3192D189CFF3F991C9CBBFD78119FCA2181384B94011943B6D6F28"
397     "9E1B708E2D1A0C7771169293F03DA27E561F15F16F0AC9BC858C77A80FA98FD088A232"
398     "19D08BE6F165DE0B02034B18705829FAD0ACB26A5B75EF";
399 static const char *public_key =
400     "F272ECF8362257C5D2C3CC2229CF9C0A03225BC109B1DBC76A68C394F256ACA3EF5F64"
401     "FC270C26382BF315C19E97A76104A716FC998A651E8610A3AE6CF65D8FAE5D3F32EEA0"
402     "0B32CB9609B494116A825D7142D17B88E3D20EDD98743DE29CF37A23A9F6A58B960591"
403     "3157D5965FCB46DDA73A1F08DD897BAE88DFE6FC937CBA";
404 static const uint8_t public_key_bin[] = {
405     0xf2, 0x72, 0xec, 0xf8, 0x36, 0x22, 0x57, 0xc5, 0xd2, 0xc3, 0xcc, 0x22,
406     0x29, 0xcf, 0x9c, 0x0a, 0x03, 0x22, 0x5b, 0xc1, 0x09, 0xb1, 0xdb, 0xc7,
407     0x6a, 0x68, 0xc3, 0x94, 0xf2, 0x56, 0xac, 0xa3, 0xef, 0x5f, 0x64, 0xfc,
408     0x27, 0x0c, 0x26, 0x38, 0x2b, 0xf3, 0x15, 0xc1, 0x9e, 0x97, 0xa7, 0x61,
409     0x04, 0xa7, 0x16, 0xfc, 0x99, 0x8a, 0x65, 0x1e, 0x86, 0x10, 0xa3, 0xae,
410     0x6c, 0xf6, 0x5d, 0x8f, 0xae, 0x5d, 0x3f, 0x32, 0xee, 0xa0, 0x0b, 0x32,
411     0xcb, 0x96, 0x09, 0xb4, 0x94, 0x11, 0x6a, 0x82, 0x5d, 0x71, 0x42, 0xd1,
412     0x7b, 0x88, 0xe3, 0xd2, 0x0e, 0xdd, 0x98, 0x74, 0x3d, 0xe2, 0x9c, 0xf3,
413     0x7a, 0x23, 0xa9, 0xf6, 0xa5, 0x8b, 0x96, 0x05, 0x91, 0x31, 0x57, 0xd5,
414     0x96, 0x5f, 0xcb, 0x46, 0xdd, 0xa7, 0x3a, 0x1f, 0x08, 0xdd, 0x89, 0x7b,
415     0xae, 0x88, 0xdf, 0xe6, 0xfc, 0x93, 0x7c, 0xba
416 };
417 static const uint8_t peer_public_key[] = {
418     0x58, 0x66, 0x05, 0x49, 0x94, 0x23, 0x2b, 0x66, 0x52, 0x13, 0xff, 0x46,
419     0xf2, 0xb3, 0x79, 0xa9, 0xee, 0xae, 0x1a, 0x13, 0xf0, 0x71, 0x52, 0xfb,
420     0x93, 0x4e, 0xee, 0x97, 0x05, 0x73, 0x50, 0x7d, 0xaf, 0x02, 0x07, 0x72,
421     0xac, 0xdc, 0xa3, 0x95, 0x78, 0xee, 0x9a, 0x19, 0x71, 0x7e, 0x99, 0x9f,
422     0x2a, 0xd4, 0xb3, 0xe2, 0x0c, 0x1d, 0x1a, 0x78, 0x4c, 0xde, 0xf1, 0xad,
423     0xb4, 0x60, 0xa8, 0x51, 0xac, 0x71, 0xec, 0x86, 0x70, 0xa2, 0x63, 0x36,
424     0x92, 0x7c, 0xe3, 0x87, 0xee, 0xe4, 0xf1, 0x62, 0x24, 0x74, 0xb4, 0x04,
425     0xfa, 0x5c, 0xdf, 0xba, 0xfa, 0xa3, 0xc2, 0xbb, 0x62, 0x27, 0xd0, 0xf4,
426     0xe4, 0x43, 0xda, 0x8a, 0x88, 0x69, 0x60, 0xe2, 0xdb, 0x75, 0x2a, 0x98,
427     0x9d, 0xb5, 0x50, 0xe3, 0x99, 0xda, 0xe0, 0xa6, 0x14, 0xc9, 0x80, 0x12,
428     0xf9, 0x3c, 0xac, 0x06, 0x02, 0x7a, 0xde, 0x74
429 };
430 static const uint8_t shared_secret[] = {
431     0xb2, 0xeb, 0xcb, 0x71, 0xf3, 0x61, 0xfb, 0x5b, 0x4e, 0x5c, 0x4c, 0xcf,
432     0x5c, 0x08, 0x5f, 0x96, 0x26, 0x77, 0x1d, 0x31, 0xf1, 0xe1, 0xf7, 0x4b,
433     0x92, 0xac, 0x82, 0x2a, 0x88, 0xc7, 0x83, 0xe1, 0xc7, 0xf3, 0xd3, 0x1a,
434     0x7d, 0xc8, 0x31, 0xe3, 0x97, 0xe4, 0xec, 0x31, 0x0e, 0x8f, 0x73, 0x1a,
435     0xe4, 0xf6, 0xd8, 0xc8, 0x94, 0xff, 0xa0, 0x03, 0x84, 0x03, 0x0f, 0xa5,
436     0x30, 0x5d, 0x67, 0xe0, 0x7a, 0x3b, 0x5f, 0xed, 0x4c, 0xf5, 0xbc, 0x18,
437     0xea, 0xd4, 0x77, 0xa9, 0x07, 0xb3, 0x54, 0x0b, 0x02, 0xd9, 0xc6, 0xb8,
438     0x66, 0x5e, 0xec, 0xa4, 0xcd, 0x47, 0xed, 0xc9, 0x38, 0xc6, 0x91, 0x08,
439     0xf3, 0x85, 0x9b, 0x69, 0x16, 0x78, 0x0d, 0xb7, 0x74, 0x51, 0xaa, 0x5b,
440     0x4d, 0x74, 0xe4, 0x29, 0x2e, 0x9e, 0x8e, 0xf7, 0xe5, 0x42, 0x83, 0xb0,
441     0x65, 0xb0, 0xce, 0xc6, 0xb2, 0x8f, 0x5b, 0xb0
442 };
443
444 static int test_ref_data(void)
445 {
446     FF_DH *dh;
447     int ret = AVERROR(ENOMEM);
448     uint8_t pubkey_test[128];
449     uint8_t sharedkey_test[128];
450
451     dh = ff_dh_init(1024);
452     if (!dh)
453         goto fail;
454     bn_hex2bn(dh->priv_key, private_key, ret);
455     if (!ret)
456         goto fail;
457     bn_hex2bn(dh->pub_key, public_key, ret);
458     if (!ret)
459         goto fail;
460     if ((ret = ff_dh_write_public_key(dh, pubkey_test, sizeof(pubkey_test))) < 0)
461         goto fail;
462     if (memcmp(pubkey_test, public_key_bin, sizeof(pubkey_test))) {
463         printf("Mismatched generated public key\n");
464         ret = AVERROR_INVALIDDATA;
465         goto fail;
466     } else {
467         printf("Generated public key ok\n");
468     }
469     if ((ret = ff_dh_compute_shared_secret_key(dh, peer_public_key, sizeof(peer_public_key),
470                                                sharedkey_test, sizeof(sharedkey_test))) < 0)
471         goto fail;
472     if (memcmp(shared_secret, sharedkey_test, sizeof(sharedkey_test))) {
473         printf("Mismatched generated shared key\n");
474         ret = AVERROR_INVALIDDATA;
475     } else {
476         printf("Generated shared key ok\n");
477     }
478 fail:
479     ff_dh_free(dh);
480     return ret;
481 }
482
483 int main(void)
484 {
485     if (test_random_shared_secret() < 0)
486         return 1;
487     if (test_ref_data() < 0)
488         return 1;
489     return 0;
490 }
491 #endif