2 * RTMP Diffie-Hellmann utilities
3 * Copyright (c) 2009 Andrej Stepanchuk
4 * Copyright (c) 2009-2010 Howard Chu
5 * Copyright (c) 2012 Samuel Pitoiset
7 * This file is part of FFmpeg.
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.
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.
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
26 * RTMP Diffie-Hellmann utilities
31 #include "libavutil/random_seed.h"
34 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
35 "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
36 "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
37 "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
38 "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \
42 "7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68" \
43 "948127044533E63A0105DF531D89CD9128A5043CC71A026E" \
44 "F7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122" \
45 "F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6" \
46 "F71C35FDAD44CFD2D74F9208BE258FF324943328F67329C0" \
49 #if CONFIG_GMP || CONFIG_GCRYPT
53 bn = av_malloc(sizeof(*bn)); \
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) \
70 memset(buf, 0, len); \
71 if (bn_num_bytes(bn) <= len) \
72 mpz_export(buf, NULL, 1, 1, 0, 0, bn); \
74 #define bn_bin2bn(bn, buf, len) \
78 mpz_import(bn, len, 1, 1, 0, 0, buf); \
80 #define bn_hex2bn(bn, buf, ret) \
84 ret = (mpz_set_str(bn, buf, 16) == 0); \
88 #define bn_modexp(bn, y, q, p) mpz_powm(bn, y, q, p)
89 #define bn_random(bn, num_bits) \
91 int bits = num_bits; \
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()); \
97 mpz_fdiv_r_2exp(bn, bn, num_bits); \
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); \
108 bn = gcry_mpi_new(1); \
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)
124 #define MAX_BYTES 18000
126 #define dh_new() av_malloc(sizeof(FF_DH))
128 static FFBigNum dh_generate_key(FF_DH *dh)
132 num_bytes = bn_num_bytes(dh->p) - 1;
133 if (num_bytes <= 0 || num_bytes > MAX_BYTES)
136 bn_new(dh->priv_key);
139 bn_random(dh->priv_key, 8 * num_bytes);
143 bn_free(dh->priv_key);
147 bn_modexp(dh->pub_key, dh->g, dh->priv_key, dh->p);
152 static int dh_compute_key(FF_DH *dh, FFBigNum pub_key_bn,
153 uint32_t secret_key_len, uint8_t *secret_key)
161 bn_modexp(k, pub_key_bn, dh->priv_key, dh->p);
162 bn_bn2bin(k, secret_key, secret_key_len);
165 /* return the length of the shared secret key like DH_compute_key */
166 return secret_key_len;
169 void ff_dh_free(FF_DH *dh)
175 bn_free(dh->pub_key);
176 bn_free(dh->priv_key);
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) \
193 BN_CTX *ctx = BN_CTX_new(); \
195 return AVERROR(ENOMEM); \
196 if (!BN_mod_exp(bn, y, q, p, ctx)) { \
198 return AVERROR(EINVAL); \
203 #define dh_new() DH_new()
204 #define dh_generate_key(dh) DH_generate_key(dh)
206 static int dh_compute_key(FF_DH *dh, FFBigNum pub_key_bn,
207 uint32_t secret_key_len, uint8_t *secret_key)
209 if (secret_key_len < DH_size(dh))
210 return AVERROR(EINVAL);
211 return DH_compute_key(secret_key, pub_key_bn, dh);
214 void ff_dh_free(FF_DH *dh)
222 static int dh_is_valid_public_key(FFBigNum y, FFBigNum p, FFBigNum q)
225 int ret = AVERROR(EINVAL);
229 return AVERROR(ENOMEM);
231 /* y must lie in [2, p - 1] */
242 /* Verify with Sophie-Germain prime
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
248 /* y must fulfill y^q mod p = 1 */
249 bn_modexp(bn, y, q, p);
261 av_cold FF_DH *ff_dh_init(int key_len)
266 if (!(dh = dh_new()))
273 bn_hex2bn(dh->p, P1024, ret);
277 bn_set_word(dh->g, 2);
278 dh->length = key_len;
288 int ff_dh_generate_public_key(FF_DH *dh)
295 if (!dh_generate_key(dh))
296 return AVERROR(EINVAL);
298 bn_hex2bn(q1, Q1024, ret);
300 return AVERROR(ENOMEM);
302 ret = dh_is_valid_public_key(dh->pub_key, dh->p, q1);
306 /* the public key is valid */
314 int ff_dh_write_public_key(FF_DH *dh, uint8_t *pub_key, int pub_key_len)
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);
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);
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,
334 FFBigNum q1 = NULL, pub_key_bn = NULL;
337 /* convert the big-endian form of the public key into a bignum */
338 bn_bin2bn(pub_key_bn, pub_key, pub_key_len);
340 return AVERROR(ENOMEM);
342 /* convert the string containing a hexadecimal number into a bignum */
343 bn_hex2bn(q1, Q1024, ret);
345 ret = AVERROR(ENOMEM);
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) {
352 } else if ((ret = dh_compute_key(dh, pub_key_bn, secret_key_len,
354 ret = AVERROR(EINVAL);
366 static int test_random_shared_secret(void)
368 FF_DH *peer1 = NULL, *peer2 = NULL;
370 uint8_t pubkey1[128], pubkey2[128];
371 uint8_t sharedkey1[128], sharedkey2[128];
373 peer1 = ff_dh_init(1024);
374 peer2 = ff_dh_init(1024);
375 if (!peer1 || !peer2) {
376 ret = AVERROR(ENOMEM);
379 if ((ret = ff_dh_generate_public_key(peer1)) < 0)
381 if ((ret = ff_dh_generate_public_key(peer2)) < 0)
383 if ((ret = ff_dh_write_public_key(peer1, pubkey1, sizeof(pubkey1))) < 0)
385 if ((ret = ff_dh_write_public_key(peer2, pubkey2, sizeof(pubkey2))) < 0)
387 if ((ret = ff_dh_compute_shared_secret_key(peer1, pubkey2, sizeof(pubkey2),
388 sharedkey1, sizeof(sharedkey1))) < 0)
390 if ((ret = ff_dh_compute_shared_secret_key(peer2, pubkey1, sizeof(pubkey1),
391 sharedkey2, sizeof(sharedkey2))) < 0)
393 if (memcmp(sharedkey1, sharedkey2, sizeof(sharedkey1))) {
394 printf("Mismatched generated shared key\n");
395 ret = AVERROR_INVALIDDATA;
397 printf("Generated shared key ok\n");
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
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
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
455 static int test_ref_data(void)
458 int ret = AVERROR(ENOMEM);
459 uint8_t pubkey_test[128];
460 uint8_t sharedkey_test[128];
462 dh = ff_dh_init(1024);
465 bn_hex2bn(dh->priv_key, private_key, ret);
468 bn_hex2bn(dh->pub_key, public_key, ret);
471 if ((ret = ff_dh_write_public_key(dh, pubkey_test, sizeof(pubkey_test))) < 0)
473 if (memcmp(pubkey_test, public_key_bin, sizeof(pubkey_test))) {
474 printf("Mismatched generated public key\n");
475 ret = AVERROR_INVALIDDATA;
478 printf("Generated public key ok\n");
480 if ((ret = ff_dh_compute_shared_secret_key(dh, peer_public_key, sizeof(peer_public_key),
481 sharedkey_test, sizeof(sharedkey_test))) < 0)
483 if (memcmp(shared_secret, sharedkey_test, sizeof(sharedkey_test))) {
484 printf("Mismatched generated shared key\n");
485 ret = AVERROR_INVALIDDATA;
487 printf("Generated shared key ok\n");
496 if (test_random_shared_secret() < 0)
498 if (test_ref_data() < 0)