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