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