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) \
87 gmp_randinit_mt(rs); \
88 gmp_randseed_ui(rs, av_get_random_seed()); \
89 mpz_urandomb(bn, rs, num_bits); \
93 #define bn_new(bn) bn = gcry_mpi_new(1)
94 #define bn_free(bn) gcry_mpi_release(bn)
95 #define bn_set_word(bn, w) gcry_mpi_set_ui(bn, w)
96 #define bn_cmp(a, b) gcry_mpi_cmp(a, b)
97 #define bn_copy(to, from) gcry_mpi_set(to, from)
98 #define bn_sub_word(bn, w) gcry_mpi_sub_ui(bn, bn, w)
99 #define bn_cmp_1(bn) gcry_mpi_cmp_ui(bn, 1)
100 #define bn_num_bytes(bn) (gcry_mpi_get_nbits(bn) + 7) / 8
101 #define bn_bn2bin(bn, buf, len) gcry_mpi_print(GCRYMPI_FMT_USG, buf, len, NULL, bn)
102 #define bn_bin2bn(bn, buf, len) gcry_mpi_scan(&bn, GCRYMPI_FMT_USG, buf, len, NULL)
103 #define bn_hex2bn(bn, buf, ret) ret = (gcry_mpi_scan(&bn, GCRYMPI_FMT_HEX, buf, 0, 0) == 0)
104 #define bn_modexp(bn, y, q, p) gcry_mpi_powm(bn, y, q, p)
105 #define bn_random(bn, num_bits) gcry_mpi_randomize(bn, num_bits, GCRY_WEAK_RANDOM)
108 #define MAX_BYTES 18000
110 #define dh_new() av_malloc(sizeof(FF_DH))
112 static FFBigNum dh_generate_key(FF_DH *dh)
116 num_bytes = bn_num_bytes(dh->p) - 1;
117 if (num_bytes <= 0 || num_bytes > MAX_BYTES)
120 bn_new(dh->priv_key);
123 bn_random(dh->priv_key, 8 * num_bytes);
127 bn_free(dh->priv_key);
131 bn_modexp(dh->pub_key, dh->g, dh->priv_key, dh->p);
136 static int dh_compute_key(FF_DH *dh, FFBigNum pub_key_bn,
137 uint32_t secret_key_len, uint8_t *secret_key)
145 bn_modexp(k, pub_key_bn, dh->priv_key, dh->p);
146 bn_bn2bin(k, secret_key, secret_key_len);
149 /* return the length of the shared secret key like DH_compute_key */
150 return secret_key_len;
153 void ff_dh_free(FF_DH *dh)
159 bn_free(dh->pub_key);
160 bn_free(dh->priv_key);
164 #define bn_new(bn) bn = BN_new()
165 #define bn_free(bn) BN_free(bn)
166 #define bn_set_word(bn, w) BN_set_word(bn, w)
167 #define bn_cmp(a, b) BN_cmp(a, b)
168 #define bn_copy(to, from) BN_copy(to, from)
169 #define bn_sub_word(bn, w) BN_sub_word(bn, w)
170 #define bn_cmp_1(bn) BN_cmp(bn, BN_value_one())
171 #define bn_num_bytes(bn) BN_num_bytes(bn)
172 #define bn_bn2bin(bn, buf, len) BN_bn2bin(bn, buf)
173 #define bn_bin2bn(bn, buf, len) bn = BN_bin2bn(buf, len, 0)
174 #define bn_hex2bn(bn, buf, ret) ret = BN_hex2bn(&bn, buf)
175 #define bn_modexp(bn, y, q, p) \
177 BN_CTX *ctx = BN_CTX_new(); \
179 return AVERROR(ENOMEM); \
180 if (!BN_mod_exp(bn, y, q, p, ctx)) { \
182 return AVERROR(EINVAL); \
187 #define dh_new() DH_new()
188 #define dh_generate_key(dh) DH_generate_key(dh)
190 static int dh_compute_key(FF_DH *dh, FFBigNum pub_key_bn,
191 uint32_t secret_key_len, uint8_t *secret_key)
193 if (secret_key_len < DH_size(dh))
194 return AVERROR(EINVAL);
195 return DH_compute_key(secret_key, pub_key_bn, dh);
198 void ff_dh_free(FF_DH *dh)
206 static int dh_is_valid_public_key(FFBigNum y, FFBigNum p, FFBigNum q)
209 int ret = AVERROR(EINVAL);
213 return AVERROR(ENOMEM);
215 /* y must lie in [2, p - 1] */
226 /* Verify with Sophie-Germain prime
228 * This is a nice test to make sure the public key position is calculated
229 * correctly. This test will fail in about 50% of the cases if applied to
232 /* y must fulfill y^q mod p = 1 */
233 bn_modexp(bn, y, q, p);
245 av_cold FF_DH *ff_dh_init(int key_len)
250 if (!(dh = dh_new()))
257 bn_hex2bn(dh->p, P1024, ret);
261 bn_set_word(dh->g, 2);
262 dh->length = key_len;
272 int ff_dh_generate_public_key(FF_DH *dh)
279 if (!dh_generate_key(dh))
280 return AVERROR(EINVAL);
282 bn_hex2bn(q1, Q1024, ret);
284 return AVERROR(ENOMEM);
286 ret = dh_is_valid_public_key(dh->pub_key, dh->p, q1);
290 /* the public key is valid */
298 int ff_dh_write_public_key(FF_DH *dh, uint8_t *pub_key, int pub_key_len)
302 /* compute the length of the public key */
303 len = bn_num_bytes(dh->pub_key);
304 if (len <= 0 || len > pub_key_len)
305 return AVERROR(EINVAL);
307 /* convert the public key value into big-endian form */
308 memset(pub_key, 0, pub_key_len);
309 bn_bn2bin(dh->pub_key, pub_key + pub_key_len - len, len);
314 int ff_dh_compute_shared_secret_key(FF_DH *dh, const uint8_t *pub_key,
315 int pub_key_len, uint8_t *secret_key,
318 FFBigNum q1 = NULL, pub_key_bn = NULL;
321 /* convert the big-endian form of the public key into a bignum */
322 bn_bin2bn(pub_key_bn, pub_key, pub_key_len);
324 return AVERROR(ENOMEM);
326 /* convert the string containing a hexadecimal number into a bignum */
327 bn_hex2bn(q1, Q1024, ret);
329 ret = AVERROR(ENOMEM);
333 /* when the public key is valid we have to compute the shared secret key */
334 if ((ret = dh_is_valid_public_key(pub_key_bn, dh->p, q1)) < 0) {
336 } else if ((ret = dh_compute_key(dh, pub_key_bn, secret_key_len,
338 ret = AVERROR(EINVAL);
350 static int test_random_shared_secret(void)
352 FF_DH *peer1 = NULL, *peer2 = NULL;
354 uint8_t pubkey1[128], pubkey2[128];
355 uint8_t sharedkey1[128], sharedkey2[128];
357 peer1 = ff_dh_init(1024);
358 peer2 = ff_dh_init(1024);
359 if (!peer1 || !peer2) {
360 ret = AVERROR(ENOMEM);
363 if ((ret = ff_dh_generate_public_key(peer1)) < 0)
365 if ((ret = ff_dh_generate_public_key(peer2)) < 0)
367 if ((ret = ff_dh_write_public_key(peer1, pubkey1, sizeof(pubkey1))) < 0)
369 if ((ret = ff_dh_write_public_key(peer2, pubkey2, sizeof(pubkey2))) < 0)
371 if ((ret = ff_dh_compute_shared_secret_key(peer1, pubkey2, sizeof(pubkey2),
372 sharedkey1, sizeof(sharedkey1))) < 0)
374 if ((ret = ff_dh_compute_shared_secret_key(peer2, pubkey1, sizeof(pubkey1),
375 sharedkey2, sizeof(sharedkey2))) < 0)
377 if (memcmp(sharedkey1, sharedkey2, sizeof(sharedkey1))) {
378 printf("Mismatched generated shared key\n");
379 ret = AVERROR_INVALIDDATA;
381 printf("Generated shared key ok\n");
389 static const char *private_key =
390 "976C18FCADC255B456564F74F3EEDA59D28AF6B744D743F2357BFD2404797EF896EF1A"
391 "7C1CBEAAA3AB60AF3192D189CFF3F991C9CBBFD78119FCA2181384B94011943B6D6F28"
392 "9E1B708E2D1A0C7771169293F03DA27E561F15F16F0AC9BC858C77A80FA98FD088A232"
393 "19D08BE6F165DE0B02034B18705829FAD0ACB26A5B75EF";
394 static const char *public_key =
395 "F272ECF8362257C5D2C3CC2229CF9C0A03225BC109B1DBC76A68C394F256ACA3EF5F64"
396 "FC270C26382BF315C19E97A76104A716FC998A651E8610A3AE6CF65D8FAE5D3F32EEA0"
397 "0B32CB9609B494116A825D7142D17B88E3D20EDD98743DE29CF37A23A9F6A58B960591"
398 "3157D5965FCB46DDA73A1F08DD897BAE88DFE6FC937CBA";
399 static const uint8_t public_key_bin[] = {
400 0xf2, 0x72, 0xec, 0xf8, 0x36, 0x22, 0x57, 0xc5, 0xd2, 0xc3, 0xcc, 0x22,
401 0x29, 0xcf, 0x9c, 0x0a, 0x03, 0x22, 0x5b, 0xc1, 0x09, 0xb1, 0xdb, 0xc7,
402 0x6a, 0x68, 0xc3, 0x94, 0xf2, 0x56, 0xac, 0xa3, 0xef, 0x5f, 0x64, 0xfc,
403 0x27, 0x0c, 0x26, 0x38, 0x2b, 0xf3, 0x15, 0xc1, 0x9e, 0x97, 0xa7, 0x61,
404 0x04, 0xa7, 0x16, 0xfc, 0x99, 0x8a, 0x65, 0x1e, 0x86, 0x10, 0xa3, 0xae,
405 0x6c, 0xf6, 0x5d, 0x8f, 0xae, 0x5d, 0x3f, 0x32, 0xee, 0xa0, 0x0b, 0x32,
406 0xcb, 0x96, 0x09, 0xb4, 0x94, 0x11, 0x6a, 0x82, 0x5d, 0x71, 0x42, 0xd1,
407 0x7b, 0x88, 0xe3, 0xd2, 0x0e, 0xdd, 0x98, 0x74, 0x3d, 0xe2, 0x9c, 0xf3,
408 0x7a, 0x23, 0xa9, 0xf6, 0xa5, 0x8b, 0x96, 0x05, 0x91, 0x31, 0x57, 0xd5,
409 0x96, 0x5f, 0xcb, 0x46, 0xdd, 0xa7, 0x3a, 0x1f, 0x08, 0xdd, 0x89, 0x7b,
410 0xae, 0x88, 0xdf, 0xe6, 0xfc, 0x93, 0x7c, 0xba
412 static const uint8_t peer_public_key[] = {
413 0x58, 0x66, 0x05, 0x49, 0x94, 0x23, 0x2b, 0x66, 0x52, 0x13, 0xff, 0x46,
414 0xf2, 0xb3, 0x79, 0xa9, 0xee, 0xae, 0x1a, 0x13, 0xf0, 0x71, 0x52, 0xfb,
415 0x93, 0x4e, 0xee, 0x97, 0x05, 0x73, 0x50, 0x7d, 0xaf, 0x02, 0x07, 0x72,
416 0xac, 0xdc, 0xa3, 0x95, 0x78, 0xee, 0x9a, 0x19, 0x71, 0x7e, 0x99, 0x9f,
417 0x2a, 0xd4, 0xb3, 0xe2, 0x0c, 0x1d, 0x1a, 0x78, 0x4c, 0xde, 0xf1, 0xad,
418 0xb4, 0x60, 0xa8, 0x51, 0xac, 0x71, 0xec, 0x86, 0x70, 0xa2, 0x63, 0x36,
419 0x92, 0x7c, 0xe3, 0x87, 0xee, 0xe4, 0xf1, 0x62, 0x24, 0x74, 0xb4, 0x04,
420 0xfa, 0x5c, 0xdf, 0xba, 0xfa, 0xa3, 0xc2, 0xbb, 0x62, 0x27, 0xd0, 0xf4,
421 0xe4, 0x43, 0xda, 0x8a, 0x88, 0x69, 0x60, 0xe2, 0xdb, 0x75, 0x2a, 0x98,
422 0x9d, 0xb5, 0x50, 0xe3, 0x99, 0xda, 0xe0, 0xa6, 0x14, 0xc9, 0x80, 0x12,
423 0xf9, 0x3c, 0xac, 0x06, 0x02, 0x7a, 0xde, 0x74
425 static const uint8_t shared_secret[] = {
426 0xb2, 0xeb, 0xcb, 0x71, 0xf3, 0x61, 0xfb, 0x5b, 0x4e, 0x5c, 0x4c, 0xcf,
427 0x5c, 0x08, 0x5f, 0x96, 0x26, 0x77, 0x1d, 0x31, 0xf1, 0xe1, 0xf7, 0x4b,
428 0x92, 0xac, 0x82, 0x2a, 0x88, 0xc7, 0x83, 0xe1, 0xc7, 0xf3, 0xd3, 0x1a,
429 0x7d, 0xc8, 0x31, 0xe3, 0x97, 0xe4, 0xec, 0x31, 0x0e, 0x8f, 0x73, 0x1a,
430 0xe4, 0xf6, 0xd8, 0xc8, 0x94, 0xff, 0xa0, 0x03, 0x84, 0x03, 0x0f, 0xa5,
431 0x30, 0x5d, 0x67, 0xe0, 0x7a, 0x3b, 0x5f, 0xed, 0x4c, 0xf5, 0xbc, 0x18,
432 0xea, 0xd4, 0x77, 0xa9, 0x07, 0xb3, 0x54, 0x0b, 0x02, 0xd9, 0xc6, 0xb8,
433 0x66, 0x5e, 0xec, 0xa4, 0xcd, 0x47, 0xed, 0xc9, 0x38, 0xc6, 0x91, 0x08,
434 0xf3, 0x85, 0x9b, 0x69, 0x16, 0x78, 0x0d, 0xb7, 0x74, 0x51, 0xaa, 0x5b,
435 0x4d, 0x74, 0xe4, 0x29, 0x2e, 0x9e, 0x8e, 0xf7, 0xe5, 0x42, 0x83, 0xb0,
436 0x65, 0xb0, 0xce, 0xc6, 0xb2, 0x8f, 0x5b, 0xb0
439 static int test_ref_data(void)
442 int ret = AVERROR(ENOMEM);
443 uint8_t pubkey_test[128];
444 uint8_t sharedkey_test[128];
446 dh = ff_dh_init(1024);
449 bn_hex2bn(dh->priv_key, private_key, ret);
452 bn_hex2bn(dh->pub_key, public_key, ret);
455 if ((ret = ff_dh_write_public_key(dh, pubkey_test, sizeof(pubkey_test))) < 0)
457 if (memcmp(pubkey_test, public_key_bin, sizeof(pubkey_test))) {
458 printf("Mismatched generated public key\n");
459 ret = AVERROR_INVALIDDATA;
462 printf("Generated public key ok\n");
464 if ((ret = ff_dh_compute_shared_secret_key(dh, peer_public_key, sizeof(peer_public_key),
465 sharedkey_test, sizeof(sharedkey_test))) < 0)
467 if (memcmp(shared_secret, sharedkey_test, sizeof(sharedkey_test))) {
468 printf("Mismatched generated shared key\n");
469 ret = AVERROR_INVALIDDATA;
471 printf("Generated shared key ok\n");
480 if (test_random_shared_secret() < 0)
482 if (test_ref_data() < 0)