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