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
34 #include "libavutil/attributes.h"
35 #include "libavutil/error.h"
36 #include "libavutil/mem.h"
37 #include "libavutil/random_seed.h"
42 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
43 "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
44 "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
45 "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
46 "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \
50 "7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68" \
51 "948127044533E63A0105DF531D89CD9128A5043CC71A026E" \
52 "F7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122" \
53 "F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6" \
54 "F71C35FDAD44CFD2D74F9208BE258FF324943328F67329C0" \
57 #if CONFIG_GMP || CONFIG_GCRYPT
61 bn = av_malloc(sizeof(*bn)); \
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) \
78 memset(buf, 0, len); \
79 if (bn_num_bytes(bn) <= len) \
80 mpz_export(buf, NULL, 1, 1, 0, 0, bn); \
82 #define bn_bin2bn(bn, buf, len) \
86 mpz_import(bn, len, 1, 1, 0, 0, buf); \
88 #define bn_hex2bn(bn, buf, ret) \
92 ret = (mpz_set_str(bn, buf, 16) == 0); \
96 #define bn_modexp(bn, y, q, p) mpz_powm(bn, y, q, p)
97 #define bn_random(bn, num_bits) \
99 int bits = num_bits; \
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()); \
105 mpz_fdiv_r_2exp(bn, bn, num_bits); \
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); \
116 bn = gcry_mpi_new(1); \
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)
132 #define MAX_BYTES 18000
134 #define dh_new() av_malloc(sizeof(FF_DH))
136 static FFBigNum dh_generate_key(FF_DH *dh)
140 num_bytes = bn_num_bytes(dh->p) - 1;
141 if (num_bytes <= 0 || num_bytes > MAX_BYTES)
144 bn_new(dh->priv_key);
147 bn_random(dh->priv_key, 8 * num_bytes);
151 bn_free(dh->priv_key);
155 bn_modexp(dh->pub_key, dh->g, dh->priv_key, dh->p);
160 static int dh_compute_key(FF_DH *dh, FFBigNum pub_key_bn,
161 uint32_t secret_key_len, uint8_t *secret_key)
169 bn_modexp(k, pub_key_bn, dh->priv_key, dh->p);
170 bn_bn2bin(k, secret_key, secret_key_len);
173 /* return the length of the shared secret key like DH_compute_key */
174 return secret_key_len;
177 void ff_dh_free(FF_DH *dh)
183 bn_free(dh->pub_key);
184 bn_free(dh->priv_key);
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) \
201 BN_CTX *ctx = BN_CTX_new(); \
203 return AVERROR(ENOMEM); \
204 if (!BN_mod_exp(bn, y, q, p, ctx)) { \
206 return AVERROR(EINVAL); \
211 #define dh_new() DH_new()
212 #define dh_generate_key(dh) DH_generate_key(dh)
214 static int dh_compute_key(FF_DH *dh, FFBigNum pub_key_bn,
215 uint32_t secret_key_len, uint8_t *secret_key)
217 if (secret_key_len < DH_size(dh))
218 return AVERROR(EINVAL);
219 return DH_compute_key(secret_key, pub_key_bn, dh);
222 void ff_dh_free(FF_DH *dh)
230 static int dh_is_valid_public_key(FFBigNum y, FFBigNum p, FFBigNum q)
233 int ret = AVERROR(EINVAL);
237 return AVERROR(ENOMEM);
239 /* y must lie in [2, p - 1] */
250 /* Verify with Sophie-Germain prime
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
256 /* y must fulfill y^q mod p = 1 */
257 bn_modexp(bn, y, q, p);
269 av_cold FF_DH *ff_dh_init(int key_len)
274 if (!(dh = dh_new()))
281 bn_hex2bn(dh->p, P1024, ret);
285 bn_set_word(dh->g, 2);
286 dh->length = key_len;
296 int ff_dh_generate_public_key(FF_DH *dh)
303 if (!dh_generate_key(dh))
304 return AVERROR(EINVAL);
306 bn_hex2bn(q1, Q1024, ret);
308 return AVERROR(ENOMEM);
310 ret = dh_is_valid_public_key(dh->pub_key, dh->p, q1);
314 /* the public key is valid */
322 int ff_dh_write_public_key(FF_DH *dh, uint8_t *pub_key, int pub_key_len)
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);
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);
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,
342 FFBigNum q1 = NULL, pub_key_bn = NULL;
345 /* convert the big-endian form of the public key into a bignum */
346 bn_bin2bn(pub_key_bn, pub_key, pub_key_len);
348 return AVERROR(ENOMEM);
350 /* convert the string containing a hexadecimal number into a bignum */
351 bn_hex2bn(q1, Q1024, ret);
353 ret = AVERROR(ENOMEM);
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) {
360 } else if ((ret = dh_compute_key(dh, pub_key_bn, secret_key_len,
362 ret = AVERROR(EINVAL);
377 static int test_random_shared_secret(void)
379 FF_DH *peer1 = NULL, *peer2 = NULL;
381 uint8_t pubkey1[128], pubkey2[128];
382 uint8_t sharedkey1[128], sharedkey2[128];
384 peer1 = ff_dh_init(1024);
385 peer2 = ff_dh_init(1024);
386 if (!peer1 || !peer2) {
387 ret = AVERROR(ENOMEM);
390 if ((ret = ff_dh_generate_public_key(peer1)) < 0)
392 if ((ret = ff_dh_generate_public_key(peer2)) < 0)
394 if ((ret = ff_dh_write_public_key(peer1, pubkey1, sizeof(pubkey1))) < 0)
396 if ((ret = ff_dh_write_public_key(peer2, pubkey2, sizeof(pubkey2))) < 0)
398 if ((ret = ff_dh_compute_shared_secret_key(peer1, pubkey2, sizeof(pubkey2),
399 sharedkey1, sizeof(sharedkey1))) < 0)
401 if ((ret = ff_dh_compute_shared_secret_key(peer2, pubkey1, sizeof(pubkey1),
402 sharedkey2, sizeof(sharedkey2))) < 0)
404 if (memcmp(sharedkey1, sharedkey2, sizeof(sharedkey1))) {
405 printf("Mismatched generated shared key\n");
406 ret = AVERROR_INVALIDDATA;
408 printf("Generated shared key ok\n");
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
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
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
466 static int test_ref_data(void)
469 int ret = AVERROR(ENOMEM);
470 uint8_t pubkey_test[128];
471 uint8_t sharedkey_test[128];
473 dh = ff_dh_init(1024);
476 bn_hex2bn(dh->priv_key, private_key, ret);
479 bn_hex2bn(dh->pub_key, public_key, ret);
482 if ((ret = ff_dh_write_public_key(dh, pubkey_test, sizeof(pubkey_test))) < 0)
484 if (memcmp(pubkey_test, public_key_bin, sizeof(pubkey_test))) {
485 printf("Mismatched generated public key\n");
486 ret = AVERROR_INVALIDDATA;
489 printf("Generated public key ok\n");
491 if ((ret = ff_dh_compute_shared_secret_key(dh, peer_public_key, sizeof(peer_public_key),
492 sharedkey_test, sizeof(sharedkey_test))) < 0)
494 if (memcmp(shared_secret, sharedkey_test, sizeof(sharedkey_test))) {
495 printf("Mismatched generated shared key\n");
496 ret = AVERROR_INVALIDDATA;
498 printf("Generated shared key ok\n");
507 if (test_random_shared_secret() < 0)
509 if (test_ref_data() < 0)