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