]> git.sesse.net Git - ffmpeg/blob - libavformat/rtmpdh.c
Merge commit 'e9e86d9ef637f5a600c76b352ffe5a82b71b25d1'
[ffmpeg] / 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 FFmpeg.
8  *
9  * FFmpeg 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  * FFmpeg 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 FFmpeg; 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_bits)                     \
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_bits);             \
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_bits)     gcry_mpi_randomize(bn, num_bits, 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, 8 * 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
141     bn_new(k);
142     if (!k)
143         return -1;
144
145     bn_modexp(k, pub_key_bn, dh->priv_key, dh->p);
146     bn_bn2bin(k, secret_key, secret_key_len);
147     bn_free(k);
148
149     /* return the length of the shared secret key like DH_compute_key */
150     return secret_key_len;
151 }
152
153 void ff_dh_free(FF_DH *dh)
154 {
155     if (!dh)
156         return;
157     bn_free(dh->p);
158     bn_free(dh->g);
159     bn_free(dh->pub_key);
160     bn_free(dh->priv_key);
161     av_free(dh);
162 }
163 #elif CONFIG_OPENSSL
164 #define bn_new(bn)                  bn = BN_new()
165 #define bn_free(bn)                 BN_free(bn)
166 #define bn_set_word(bn, w)          BN_set_word(bn, w)
167 #define bn_cmp(a, b)                BN_cmp(a, b)
168 #define bn_copy(to, from)           BN_copy(to, from)
169 #define bn_sub_word(bn, w)          BN_sub_word(bn, w)
170 #define bn_cmp_1(bn)                BN_cmp(bn, BN_value_one())
171 #define bn_num_bytes(bn)            BN_num_bytes(bn)
172 #define bn_bn2bin(bn, buf, len)     BN_bn2bin(bn, buf)
173 #define bn_bin2bn(bn, buf, len)     bn = BN_bin2bn(buf, len, 0)
174 #define bn_hex2bn(bn, buf, ret)     ret = BN_hex2bn(&bn, buf)
175 #define bn_modexp(bn, y, q, p)               \
176     do {                                     \
177         BN_CTX *ctx = BN_CTX_new();          \
178         if (!ctx)                            \
179             return AVERROR(ENOMEM);          \
180         if (!BN_mod_exp(bn, y, q, p, ctx)) { \
181             BN_CTX_free(ctx);                \
182             return AVERROR(EINVAL);          \
183         }                                    \
184         BN_CTX_free(ctx);                    \
185     } while (0)
186
187 #define dh_new()                                DH_new()
188 #define dh_generate_key(dh)                     DH_generate_key(dh)
189
190 static int dh_compute_key(FF_DH *dh, FFBigNum pub_key_bn,
191                           uint32_t secret_key_len, uint8_t *secret_key)
192 {
193     if (secret_key_len < DH_size(dh))
194         return AVERROR(EINVAL);
195     return DH_compute_key(secret_key, pub_key_bn, dh);
196 }
197
198 void ff_dh_free(FF_DH *dh)
199 {
200     if (!dh)
201         return;
202     DH_free(dh);
203 }
204 #endif
205
206 static int dh_is_valid_public_key(FFBigNum y, FFBigNum p, FFBigNum q)
207 {
208     FFBigNum bn = NULL;
209     int ret = AVERROR(EINVAL);
210
211     bn_new(bn);
212     if (!bn)
213         return AVERROR(ENOMEM);
214
215     /* y must lie in [2, p - 1] */
216     bn_set_word(bn, 1);
217     if (!bn_cmp(y, bn))
218         goto fail;
219
220     /* bn = p - 2 */
221     bn_copy(bn, p);
222     bn_sub_word(bn, 1);
223     if (!bn_cmp(y, bn))
224         goto fail;
225
226     /* Verify with Sophie-Germain prime
227      *
228      * This is a nice test to make sure the public key position is calculated
229      * correctly. This test will fail in about 50% of the cases if applied to
230      * random data.
231      */
232     /* y must fulfill y^q mod p = 1 */
233     bn_modexp(bn, y, q, p);
234
235     if (bn_cmp_1(bn))
236         goto fail;
237
238     ret = 0;
239 fail:
240     bn_free(bn);
241
242     return ret;
243 }
244
245 av_cold FF_DH *ff_dh_init(int key_len)
246 {
247     FF_DH *dh;
248     int ret;
249
250     if (!(dh = dh_new()))
251         return NULL;
252
253     bn_new(dh->g);
254     if (!dh->g)
255         goto fail;
256
257     bn_hex2bn(dh->p, P1024, ret);
258     if (!ret)
259         goto fail;
260
261     bn_set_word(dh->g, 2);
262     dh->length = key_len;
263
264     return dh;
265
266 fail:
267     ff_dh_free(dh);
268
269     return NULL;
270 }
271
272 int ff_dh_generate_public_key(FF_DH *dh)
273 {
274     int ret = 0;
275
276     while (!ret) {
277         FFBigNum q1 = NULL;
278
279         if (!dh_generate_key(dh))
280             return AVERROR(EINVAL);
281
282         bn_hex2bn(q1, Q1024, ret);
283         if (!ret)
284             return AVERROR(ENOMEM);
285
286         ret = dh_is_valid_public_key(dh->pub_key, dh->p, q1);
287         bn_free(q1);
288
289         if (!ret) {
290             /* the public key is valid */
291             break;
292         }
293     }
294
295     return ret;
296 }
297
298 int ff_dh_write_public_key(FF_DH *dh, uint8_t *pub_key, int pub_key_len)
299 {
300     int len;
301
302     /* compute the length of the public key */
303     len = bn_num_bytes(dh->pub_key);
304     if (len <= 0 || len > pub_key_len)
305         return AVERROR(EINVAL);
306
307     /* convert the public key value into big-endian form */
308     memset(pub_key, 0, pub_key_len);
309     bn_bn2bin(dh->pub_key, pub_key + pub_key_len - len, len);
310
311     return 0;
312 }
313
314 int ff_dh_compute_shared_secret_key(FF_DH *dh, const uint8_t *pub_key,
315                                     int pub_key_len, uint8_t *secret_key,
316                                     int secret_key_len)
317 {
318     FFBigNum q1 = NULL, pub_key_bn = NULL;
319     int ret;
320
321     /* convert the big-endian form of the public key into a bignum */
322     bn_bin2bn(pub_key_bn, pub_key, pub_key_len);
323     if (!pub_key_bn)
324         return AVERROR(ENOMEM);
325
326     /* convert the string containing a hexadecimal number into a bignum */
327     bn_hex2bn(q1, Q1024, ret);
328     if (!ret) {
329         ret = AVERROR(ENOMEM);
330         goto fail;
331     }
332
333     /* when the public key is valid we have to compute the shared secret key */
334     if ((ret = dh_is_valid_public_key(pub_key_bn, dh->p, q1)) < 0) {
335         goto fail;
336     } else if ((ret = dh_compute_key(dh, pub_key_bn, secret_key_len,
337                                      secret_key)) < 0) {
338         ret = AVERROR(EINVAL);
339         goto fail;
340     }
341
342 fail:
343     bn_free(pub_key_bn);
344     bn_free(q1);
345
346     return ret;
347 }
348
349 #ifdef TEST
350 static int test_random_shared_secret(void)
351 {
352     FF_DH *peer1 = NULL, *peer2 = NULL;
353     int ret;
354     uint8_t pubkey1[128], pubkey2[128];
355     uint8_t sharedkey1[128], sharedkey2[128];
356
357     peer1 = ff_dh_init(1024);
358     peer2 = ff_dh_init(1024);
359     if (!peer1 || !peer2) {
360         ret = AVERROR(ENOMEM);
361         goto fail;
362     }
363     if ((ret = ff_dh_generate_public_key(peer1)) < 0)
364         goto fail;
365     if ((ret = ff_dh_generate_public_key(peer2)) < 0)
366         goto fail;
367     if ((ret = ff_dh_write_public_key(peer1, pubkey1, sizeof(pubkey1))) < 0)
368         goto fail;
369     if ((ret = ff_dh_write_public_key(peer2, pubkey2, sizeof(pubkey2))) < 0)
370         goto fail;
371     if ((ret = ff_dh_compute_shared_secret_key(peer1, pubkey2, sizeof(pubkey2),
372                                                sharedkey1, sizeof(sharedkey1))) < 0)
373         goto fail;
374     if ((ret = ff_dh_compute_shared_secret_key(peer2, pubkey1, sizeof(pubkey1),
375                                                sharedkey2, sizeof(sharedkey2))) < 0)
376         goto fail;
377     if (memcmp(sharedkey1, sharedkey2, sizeof(sharedkey1))) {
378         printf("Mismatched generated shared key\n");
379         ret = AVERROR_INVALIDDATA;
380     } else {
381         printf("Generated shared key ok\n");
382     }
383 fail:
384     ff_dh_free(peer1);
385     ff_dh_free(peer2);
386     return ret;
387 }
388
389 static const char *private_key =
390     "976C18FCADC255B456564F74F3EEDA59D28AF6B744D743F2357BFD2404797EF896EF1A"
391     "7C1CBEAAA3AB60AF3192D189CFF3F991C9CBBFD78119FCA2181384B94011943B6D6F28"
392     "9E1B708E2D1A0C7771169293F03DA27E561F15F16F0AC9BC858C77A80FA98FD088A232"
393     "19D08BE6F165DE0B02034B18705829FAD0ACB26A5B75EF";
394 static const char *public_key =
395     "F272ECF8362257C5D2C3CC2229CF9C0A03225BC109B1DBC76A68C394F256ACA3EF5F64"
396     "FC270C26382BF315C19E97A76104A716FC998A651E8610A3AE6CF65D8FAE5D3F32EEA0"
397     "0B32CB9609B494116A825D7142D17B88E3D20EDD98743DE29CF37A23A9F6A58B960591"
398     "3157D5965FCB46DDA73A1F08DD897BAE88DFE6FC937CBA";
399 static const uint8_t public_key_bin[] = {
400     0xf2, 0x72, 0xec, 0xf8, 0x36, 0x22, 0x57, 0xc5, 0xd2, 0xc3, 0xcc, 0x22,
401     0x29, 0xcf, 0x9c, 0x0a, 0x03, 0x22, 0x5b, 0xc1, 0x09, 0xb1, 0xdb, 0xc7,
402     0x6a, 0x68, 0xc3, 0x94, 0xf2, 0x56, 0xac, 0xa3, 0xef, 0x5f, 0x64, 0xfc,
403     0x27, 0x0c, 0x26, 0x38, 0x2b, 0xf3, 0x15, 0xc1, 0x9e, 0x97, 0xa7, 0x61,
404     0x04, 0xa7, 0x16, 0xfc, 0x99, 0x8a, 0x65, 0x1e, 0x86, 0x10, 0xa3, 0xae,
405     0x6c, 0xf6, 0x5d, 0x8f, 0xae, 0x5d, 0x3f, 0x32, 0xee, 0xa0, 0x0b, 0x32,
406     0xcb, 0x96, 0x09, 0xb4, 0x94, 0x11, 0x6a, 0x82, 0x5d, 0x71, 0x42, 0xd1,
407     0x7b, 0x88, 0xe3, 0xd2, 0x0e, 0xdd, 0x98, 0x74, 0x3d, 0xe2, 0x9c, 0xf3,
408     0x7a, 0x23, 0xa9, 0xf6, 0xa5, 0x8b, 0x96, 0x05, 0x91, 0x31, 0x57, 0xd5,
409     0x96, 0x5f, 0xcb, 0x46, 0xdd, 0xa7, 0x3a, 0x1f, 0x08, 0xdd, 0x89, 0x7b,
410     0xae, 0x88, 0xdf, 0xe6, 0xfc, 0x93, 0x7c, 0xba
411 };
412 static const uint8_t peer_public_key[] = {
413     0x58, 0x66, 0x05, 0x49, 0x94, 0x23, 0x2b, 0x66, 0x52, 0x13, 0xff, 0x46,
414     0xf2, 0xb3, 0x79, 0xa9, 0xee, 0xae, 0x1a, 0x13, 0xf0, 0x71, 0x52, 0xfb,
415     0x93, 0x4e, 0xee, 0x97, 0x05, 0x73, 0x50, 0x7d, 0xaf, 0x02, 0x07, 0x72,
416     0xac, 0xdc, 0xa3, 0x95, 0x78, 0xee, 0x9a, 0x19, 0x71, 0x7e, 0x99, 0x9f,
417     0x2a, 0xd4, 0xb3, 0xe2, 0x0c, 0x1d, 0x1a, 0x78, 0x4c, 0xde, 0xf1, 0xad,
418     0xb4, 0x60, 0xa8, 0x51, 0xac, 0x71, 0xec, 0x86, 0x70, 0xa2, 0x63, 0x36,
419     0x92, 0x7c, 0xe3, 0x87, 0xee, 0xe4, 0xf1, 0x62, 0x24, 0x74, 0xb4, 0x04,
420     0xfa, 0x5c, 0xdf, 0xba, 0xfa, 0xa3, 0xc2, 0xbb, 0x62, 0x27, 0xd0, 0xf4,
421     0xe4, 0x43, 0xda, 0x8a, 0x88, 0x69, 0x60, 0xe2, 0xdb, 0x75, 0x2a, 0x98,
422     0x9d, 0xb5, 0x50, 0xe3, 0x99, 0xda, 0xe0, 0xa6, 0x14, 0xc9, 0x80, 0x12,
423     0xf9, 0x3c, 0xac, 0x06, 0x02, 0x7a, 0xde, 0x74
424 };
425 static const uint8_t shared_secret[] = {
426     0xb2, 0xeb, 0xcb, 0x71, 0xf3, 0x61, 0xfb, 0x5b, 0x4e, 0x5c, 0x4c, 0xcf,
427     0x5c, 0x08, 0x5f, 0x96, 0x26, 0x77, 0x1d, 0x31, 0xf1, 0xe1, 0xf7, 0x4b,
428     0x92, 0xac, 0x82, 0x2a, 0x88, 0xc7, 0x83, 0xe1, 0xc7, 0xf3, 0xd3, 0x1a,
429     0x7d, 0xc8, 0x31, 0xe3, 0x97, 0xe4, 0xec, 0x31, 0x0e, 0x8f, 0x73, 0x1a,
430     0xe4, 0xf6, 0xd8, 0xc8, 0x94, 0xff, 0xa0, 0x03, 0x84, 0x03, 0x0f, 0xa5,
431     0x30, 0x5d, 0x67, 0xe0, 0x7a, 0x3b, 0x5f, 0xed, 0x4c, 0xf5, 0xbc, 0x18,
432     0xea, 0xd4, 0x77, 0xa9, 0x07, 0xb3, 0x54, 0x0b, 0x02, 0xd9, 0xc6, 0xb8,
433     0x66, 0x5e, 0xec, 0xa4, 0xcd, 0x47, 0xed, 0xc9, 0x38, 0xc6, 0x91, 0x08,
434     0xf3, 0x85, 0x9b, 0x69, 0x16, 0x78, 0x0d, 0xb7, 0x74, 0x51, 0xaa, 0x5b,
435     0x4d, 0x74, 0xe4, 0x29, 0x2e, 0x9e, 0x8e, 0xf7, 0xe5, 0x42, 0x83, 0xb0,
436     0x65, 0xb0, 0xce, 0xc6, 0xb2, 0x8f, 0x5b, 0xb0
437 };
438
439 static int test_ref_data(void)
440 {
441     FF_DH *dh;
442     int ret = AVERROR(ENOMEM);
443     uint8_t pubkey_test[128];
444     uint8_t sharedkey_test[128];
445
446     dh = ff_dh_init(1024);
447     if (!dh)
448         goto fail;
449     bn_hex2bn(dh->priv_key, private_key, ret);
450     if (!ret)
451         goto fail;
452     bn_hex2bn(dh->pub_key, public_key, ret);
453     if (!ret)
454         goto fail;
455     if ((ret = ff_dh_write_public_key(dh, pubkey_test, sizeof(pubkey_test))) < 0)
456         goto fail;
457     if (memcmp(pubkey_test, public_key_bin, sizeof(pubkey_test))) {
458         printf("Mismatched generated public key\n");
459         ret = AVERROR_INVALIDDATA;
460         goto fail;
461     } else {
462         printf("Generated public key ok\n");
463     }
464     if ((ret = ff_dh_compute_shared_secret_key(dh, peer_public_key, sizeof(peer_public_key),
465                                                sharedkey_test, sizeof(sharedkey_test))) < 0)
466         goto fail;
467     if (memcmp(shared_secret, sharedkey_test, sizeof(sharedkey_test))) {
468         printf("Mismatched generated shared key\n");
469         ret = AVERROR_INVALIDDATA;
470     } else {
471         printf("Generated shared key ok\n");
472     }
473 fail:
474     ff_dh_free(dh);
475     return ret;
476 }
477
478 int main(void)
479 {
480     if (test_random_shared_secret() < 0)
481         return 1;
482     if (test_ref_data() < 0)
483         return 1;
484     return 0;
485 }
486 #endif