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_NETTLE || 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) nettle_mpz_get_str_256(len, buf, bn)
69 #define bn_bin2bn(bn, buf, len) \
73 nettle_mpz_set_str_256_u(bn, len, buf); \
75 #define bn_hex2bn(bn, buf, ret) \
79 ret = (mpz_set_str(bn, buf, 16) == 0); \
83 #define bn_modexp(bn, y, q, p) mpz_powm(bn, y, q, p)
84 #define bn_random(bn, num_bits) \
86 int bits = num_bits; \
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()); \
92 mpz_fdiv_r_2exp(bn, bn, num_bits); \
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)
110 #define MAX_BYTES 18000
112 #define dh_new() av_malloc(sizeof(FF_DH))
114 static FFBigNum dh_generate_key(FF_DH *dh)
118 num_bytes = bn_num_bytes(dh->p) - 1;
119 if (num_bytes <= 0 || num_bytes > MAX_BYTES)
122 bn_new(dh->priv_key);
125 bn_random(dh->priv_key, 8 * num_bytes);
129 bn_free(dh->priv_key);
133 bn_modexp(dh->pub_key, dh->g, dh->priv_key, dh->p);
138 static int dh_compute_key(FF_DH *dh, FFBigNum pub_key_bn,
139 uint32_t secret_key_len, uint8_t *secret_key)
147 bn_modexp(k, pub_key_bn, dh->priv_key, dh->p);
148 bn_bn2bin(k, secret_key, secret_key_len);
151 /* return the length of the shared secret key like DH_compute_key */
152 return secret_key_len;
155 void ff_dh_free(FF_DH *dh)
161 bn_free(dh->pub_key);
162 bn_free(dh->priv_key);
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) \
179 BN_CTX *ctx = BN_CTX_new(); \
181 return AVERROR(ENOMEM); \
182 if (!BN_mod_exp(bn, y, q, p, ctx)) { \
184 return AVERROR(EINVAL); \
189 #define dh_new() DH_new()
190 #define dh_generate_key(dh) DH_generate_key(dh)
192 static int dh_compute_key(FF_DH *dh, FFBigNum pub_key_bn,
193 uint32_t secret_key_len, uint8_t *secret_key)
195 if (secret_key_len < DH_size(dh))
196 return AVERROR(EINVAL);
197 return DH_compute_key(secret_key, pub_key_bn, dh);
200 void ff_dh_free(FF_DH *dh)
208 static int dh_is_valid_public_key(FFBigNum y, FFBigNum p, FFBigNum q)
211 int ret = AVERROR(EINVAL);
215 return AVERROR(ENOMEM);
217 /* y must lie in [2, p - 1] */
228 /* Verify with Sophie-Germain prime
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
234 /* y must fulfill y^q mod p = 1 */
235 bn_modexp(bn, y, q, p);
247 av_cold FF_DH *ff_dh_init(int key_len)
252 if (!(dh = dh_new()))
259 bn_hex2bn(dh->p, P1024, ret);
263 bn_set_word(dh->g, 2);
264 dh->length = key_len;
274 int ff_dh_generate_public_key(FF_DH *dh)
281 if (!dh_generate_key(dh))
282 return AVERROR(EINVAL);
284 bn_hex2bn(q1, Q1024, ret);
286 return AVERROR(ENOMEM);
288 ret = dh_is_valid_public_key(dh->pub_key, dh->p, q1);
292 /* the public key is valid */
300 int ff_dh_write_public_key(FF_DH *dh, uint8_t *pub_key, int pub_key_len)
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);
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);
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,
320 FFBigNum q1 = NULL, pub_key_bn = NULL;
323 /* convert the big-endian form of the public key into a bignum */
324 bn_bin2bn(pub_key_bn, pub_key, pub_key_len);
326 return AVERROR(ENOMEM);
328 /* convert the string containing a hexadecimal number into a bignum */
329 bn_hex2bn(q1, Q1024, ret);
331 ret = AVERROR(ENOMEM);
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) {
338 } else if ((ret = dh_compute_key(dh, pub_key_bn, secret_key_len,
340 ret = AVERROR(EINVAL);
352 static int test_random_shared_secret(void)
354 FF_DH *peer1 = NULL, *peer2 = NULL;
356 uint8_t pubkey1[128], pubkey2[128];
357 uint8_t sharedkey1[128], sharedkey2[128];
359 peer1 = ff_dh_init(1024);
360 peer2 = ff_dh_init(1024);
361 if (!peer1 || !peer2) {
362 ret = AVERROR(ENOMEM);
365 if ((ret = ff_dh_generate_public_key(peer1)) < 0)
367 if ((ret = ff_dh_generate_public_key(peer2)) < 0)
369 if ((ret = ff_dh_write_public_key(peer1, pubkey1, sizeof(pubkey1))) < 0)
371 if ((ret = ff_dh_write_public_key(peer2, pubkey2, sizeof(pubkey2))) < 0)
373 if ((ret = ff_dh_compute_shared_secret_key(peer1, pubkey2, sizeof(pubkey2),
374 sharedkey1, sizeof(sharedkey1))) < 0)
376 if ((ret = ff_dh_compute_shared_secret_key(peer2, pubkey1, sizeof(pubkey1),
377 sharedkey2, sizeof(sharedkey2))) < 0)
379 if (memcmp(sharedkey1, sharedkey2, sizeof(sharedkey1))) {
380 printf("Mismatched generated shared key\n");
381 ret = AVERROR_INVALIDDATA;
383 printf("Generated shared key ok\n");
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
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
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
441 static int test_ref_data(void)
444 int ret = AVERROR(ENOMEM);
445 uint8_t pubkey_test[128];
446 uint8_t sharedkey_test[128];
448 dh = ff_dh_init(1024);
451 bn_hex2bn(dh->priv_key, private_key, ret);
454 bn_hex2bn(dh->pub_key, public_key, ret);
457 if ((ret = ff_dh_write_public_key(dh, pubkey_test, sizeof(pubkey_test))) < 0)
459 if (memcmp(pubkey_test, public_key_bin, sizeof(pubkey_test))) {
460 printf("Mismatched generated public key\n");
461 ret = AVERROR_INVALIDDATA;
464 printf("Generated public key ok\n");
466 if ((ret = ff_dh_compute_shared_secret_key(dh, peer_public_key, sizeof(peer_public_key),
467 sharedkey_test, sizeof(sharedkey_test))) < 0)
469 if (memcmp(shared_secret, sharedkey_test, sizeof(sharedkey_test))) {
470 printf("Mismatched generated shared key\n");
471 ret = AVERROR_INVALIDDATA;
473 printf("Generated shared key ok\n");
482 if (test_random_shared_secret() < 0)
484 if (test_ref_data() < 0)