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 Libav.
9 * Libav 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 * Libav 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 Libav; 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); \
108 #define bn_new(bn) bn = gcry_mpi_new(1)
109 #define bn_free(bn) gcry_mpi_release(bn)
110 #define bn_set_word(bn, w) gcry_mpi_set_ui(bn, w)
111 #define bn_cmp(a, b) gcry_mpi_cmp(a, b)
112 #define bn_copy(to, from) gcry_mpi_set(to, from)
113 #define bn_sub_word(bn, w) gcry_mpi_sub_ui(bn, bn, w)
114 #define bn_cmp_1(bn) gcry_mpi_cmp_ui(bn, 1)
115 #define bn_num_bytes(bn) (gcry_mpi_get_nbits(bn) + 7) / 8
116 #define bn_bn2bin(bn, buf, len) gcry_mpi_print(GCRYMPI_FMT_USG, buf, len, NULL, bn)
117 #define bn_bin2bn(bn, buf, len) gcry_mpi_scan(&bn, GCRYMPI_FMT_USG, buf, len, NULL)
118 #define bn_hex2bn(bn, buf, ret) ret = (gcry_mpi_scan(&bn, GCRYMPI_FMT_HEX, buf, 0, 0) == 0)
119 #define bn_modexp(bn, y, q, p) gcry_mpi_powm(bn, y, q, p)
120 #define bn_random(bn, num_bits) gcry_mpi_randomize(bn, num_bits, GCRY_WEAK_RANDOM)
123 #define MAX_BYTES 18000
125 #define dh_new() av_malloc(sizeof(FF_DH))
127 static FFBigNum dh_generate_key(FF_DH *dh)
131 num_bytes = bn_num_bytes(dh->p) - 1;
132 if (num_bytes <= 0 || num_bytes > MAX_BYTES)
135 bn_new(dh->priv_key);
138 bn_random(dh->priv_key, 8 * num_bytes);
142 bn_free(dh->priv_key);
146 bn_modexp(dh->pub_key, dh->g, dh->priv_key, dh->p);
151 static int dh_compute_key(FF_DH *dh, FFBigNum pub_key_bn,
152 uint32_t secret_key_len, uint8_t *secret_key)
160 bn_modexp(k, pub_key_bn, dh->priv_key, dh->p);
161 bn_bn2bin(k, secret_key, secret_key_len);
164 /* return the length of the shared secret key like DH_compute_key */
165 return secret_key_len;
168 void ff_dh_free(FF_DH *dh)
174 bn_free(dh->pub_key);
175 bn_free(dh->priv_key);
179 #define bn_new(bn) bn = BN_new()
180 #define bn_free(bn) BN_free(bn)
181 #define bn_set_word(bn, w) BN_set_word(bn, w)
182 #define bn_cmp(a, b) BN_cmp(a, b)
183 #define bn_copy(to, from) BN_copy(to, from)
184 #define bn_sub_word(bn, w) BN_sub_word(bn, w)
185 #define bn_cmp_1(bn) BN_cmp(bn, BN_value_one())
186 #define bn_num_bytes(bn) BN_num_bytes(bn)
187 #define bn_bn2bin(bn, buf, len) BN_bn2bin(bn, buf)
188 #define bn_bin2bn(bn, buf, len) bn = BN_bin2bn(buf, len, 0)
189 #define bn_hex2bn(bn, buf, ret) ret = BN_hex2bn(&bn, buf)
190 #define bn_modexp(bn, y, q, p) \
192 BN_CTX *ctx = BN_CTX_new(); \
194 return AVERROR(ENOMEM); \
195 if (!BN_mod_exp(bn, y, q, p, ctx)) { \
197 return AVERROR(EINVAL); \
202 #define dh_new() DH_new()
203 #define dh_generate_key(dh) DH_generate_key(dh)
205 static int dh_compute_key(FF_DH *dh, FFBigNum pub_key_bn,
206 uint32_t secret_key_len, uint8_t *secret_key)
208 if (secret_key_len < DH_size(dh))
209 return AVERROR(EINVAL);
210 return DH_compute_key(secret_key, pub_key_bn, dh);
213 void ff_dh_free(FF_DH *dh)
221 static int dh_is_valid_public_key(FFBigNum y, FFBigNum p, FFBigNum q)
224 int ret = AVERROR(EINVAL);
228 return AVERROR(ENOMEM);
230 /* y must lie in [2, p - 1] */
241 /* Verify with Sophie-Germain prime
243 * This is a nice test to make sure the public key position is calculated
244 * correctly. This test will fail in about 50% of the cases if applied to
247 /* y must fulfill y^q mod p = 1 */
248 bn_modexp(bn, y, q, p);
260 av_cold FF_DH *ff_dh_init(int key_len)
265 if (!(dh = dh_new()))
272 bn_hex2bn(dh->p, P1024, ret);
276 bn_set_word(dh->g, 2);
277 dh->length = key_len;
287 int ff_dh_generate_public_key(FF_DH *dh)
294 if (!dh_generate_key(dh))
295 return AVERROR(EINVAL);
297 bn_hex2bn(q1, Q1024, ret);
299 return AVERROR(ENOMEM);
301 ret = dh_is_valid_public_key(dh->pub_key, dh->p, q1);
305 /* the public key is valid */
313 int ff_dh_write_public_key(FF_DH *dh, uint8_t *pub_key, int pub_key_len)
317 /* compute the length of the public key */
318 len = bn_num_bytes(dh->pub_key);
319 if (len <= 0 || len > pub_key_len)
320 return AVERROR(EINVAL);
322 /* convert the public key value into big-endian form */
323 memset(pub_key, 0, pub_key_len);
324 bn_bn2bin(dh->pub_key, pub_key + pub_key_len - len, len);
329 int ff_dh_compute_shared_secret_key(FF_DH *dh, const uint8_t *pub_key,
330 int pub_key_len, uint8_t *secret_key,
333 FFBigNum q1 = NULL, pub_key_bn = NULL;
336 /* convert the big-endian form of the public key into a bignum */
337 bn_bin2bn(pub_key_bn, pub_key, pub_key_len);
339 return AVERROR(ENOMEM);
341 /* convert the string containing a hexadecimal number into a bignum */
342 bn_hex2bn(q1, Q1024, ret);
344 ret = AVERROR(ENOMEM);
348 /* when the public key is valid we have to compute the shared secret key */
349 if ((ret = dh_is_valid_public_key(pub_key_bn, dh->p, q1)) < 0) {
351 } else if ((ret = dh_compute_key(dh, pub_key_bn, secret_key_len,
353 ret = AVERROR(EINVAL);
368 static int test_random_shared_secret(void)
370 FF_DH *peer1 = NULL, *peer2 = NULL;
372 uint8_t pubkey1[128], pubkey2[128];
373 uint8_t sharedkey1[128], sharedkey2[128];
375 peer1 = ff_dh_init(1024);
376 peer2 = ff_dh_init(1024);
377 if (!peer1 || !peer2) {
378 ret = AVERROR(ENOMEM);
381 if ((ret = ff_dh_generate_public_key(peer1)) < 0)
383 if ((ret = ff_dh_generate_public_key(peer2)) < 0)
385 if ((ret = ff_dh_write_public_key(peer1, pubkey1, sizeof(pubkey1))) < 0)
387 if ((ret = ff_dh_write_public_key(peer2, pubkey2, sizeof(pubkey2))) < 0)
389 if ((ret = ff_dh_compute_shared_secret_key(peer1, pubkey2, sizeof(pubkey2),
390 sharedkey1, sizeof(sharedkey1))) < 0)
392 if ((ret = ff_dh_compute_shared_secret_key(peer2, pubkey1, sizeof(pubkey1),
393 sharedkey2, sizeof(sharedkey2))) < 0)
395 if (memcmp(sharedkey1, sharedkey2, sizeof(sharedkey1))) {
396 printf("Mismatched generated shared key\n");
397 ret = AVERROR_INVALIDDATA;
399 printf("Generated shared key ok\n");
407 static const char *private_key =
408 "976C18FCADC255B456564F74F3EEDA59D28AF6B744D743F2357BFD2404797EF896EF1A"
409 "7C1CBEAAA3AB60AF3192D189CFF3F991C9CBBFD78119FCA2181384B94011943B6D6F28"
410 "9E1B708E2D1A0C7771169293F03DA27E561F15F16F0AC9BC858C77A80FA98FD088A232"
411 "19D08BE6F165DE0B02034B18705829FAD0ACB26A5B75EF";
412 static const char *public_key =
413 "F272ECF8362257C5D2C3CC2229CF9C0A03225BC109B1DBC76A68C394F256ACA3EF5F64"
414 "FC270C26382BF315C19E97A76104A716FC998A651E8610A3AE6CF65D8FAE5D3F32EEA0"
415 "0B32CB9609B494116A825D7142D17B88E3D20EDD98743DE29CF37A23A9F6A58B960591"
416 "3157D5965FCB46DDA73A1F08DD897BAE88DFE6FC937CBA";
417 static const uint8_t public_key_bin[] = {
418 0xf2, 0x72, 0xec, 0xf8, 0x36, 0x22, 0x57, 0xc5, 0xd2, 0xc3, 0xcc, 0x22,
419 0x29, 0xcf, 0x9c, 0x0a, 0x03, 0x22, 0x5b, 0xc1, 0x09, 0xb1, 0xdb, 0xc7,
420 0x6a, 0x68, 0xc3, 0x94, 0xf2, 0x56, 0xac, 0xa3, 0xef, 0x5f, 0x64, 0xfc,
421 0x27, 0x0c, 0x26, 0x38, 0x2b, 0xf3, 0x15, 0xc1, 0x9e, 0x97, 0xa7, 0x61,
422 0x04, 0xa7, 0x16, 0xfc, 0x99, 0x8a, 0x65, 0x1e, 0x86, 0x10, 0xa3, 0xae,
423 0x6c, 0xf6, 0x5d, 0x8f, 0xae, 0x5d, 0x3f, 0x32, 0xee, 0xa0, 0x0b, 0x32,
424 0xcb, 0x96, 0x09, 0xb4, 0x94, 0x11, 0x6a, 0x82, 0x5d, 0x71, 0x42, 0xd1,
425 0x7b, 0x88, 0xe3, 0xd2, 0x0e, 0xdd, 0x98, 0x74, 0x3d, 0xe2, 0x9c, 0xf3,
426 0x7a, 0x23, 0xa9, 0xf6, 0xa5, 0x8b, 0x96, 0x05, 0x91, 0x31, 0x57, 0xd5,
427 0x96, 0x5f, 0xcb, 0x46, 0xdd, 0xa7, 0x3a, 0x1f, 0x08, 0xdd, 0x89, 0x7b,
428 0xae, 0x88, 0xdf, 0xe6, 0xfc, 0x93, 0x7c, 0xba
430 static const uint8_t peer_public_key[] = {
431 0x58, 0x66, 0x05, 0x49, 0x94, 0x23, 0x2b, 0x66, 0x52, 0x13, 0xff, 0x46,
432 0xf2, 0xb3, 0x79, 0xa9, 0xee, 0xae, 0x1a, 0x13, 0xf0, 0x71, 0x52, 0xfb,
433 0x93, 0x4e, 0xee, 0x97, 0x05, 0x73, 0x50, 0x7d, 0xaf, 0x02, 0x07, 0x72,
434 0xac, 0xdc, 0xa3, 0x95, 0x78, 0xee, 0x9a, 0x19, 0x71, 0x7e, 0x99, 0x9f,
435 0x2a, 0xd4, 0xb3, 0xe2, 0x0c, 0x1d, 0x1a, 0x78, 0x4c, 0xde, 0xf1, 0xad,
436 0xb4, 0x60, 0xa8, 0x51, 0xac, 0x71, 0xec, 0x86, 0x70, 0xa2, 0x63, 0x36,
437 0x92, 0x7c, 0xe3, 0x87, 0xee, 0xe4, 0xf1, 0x62, 0x24, 0x74, 0xb4, 0x04,
438 0xfa, 0x5c, 0xdf, 0xba, 0xfa, 0xa3, 0xc2, 0xbb, 0x62, 0x27, 0xd0, 0xf4,
439 0xe4, 0x43, 0xda, 0x8a, 0x88, 0x69, 0x60, 0xe2, 0xdb, 0x75, 0x2a, 0x98,
440 0x9d, 0xb5, 0x50, 0xe3, 0x99, 0xda, 0xe0, 0xa6, 0x14, 0xc9, 0x80, 0x12,
441 0xf9, 0x3c, 0xac, 0x06, 0x02, 0x7a, 0xde, 0x74
443 static const uint8_t shared_secret[] = {
444 0xb2, 0xeb, 0xcb, 0x71, 0xf3, 0x61, 0xfb, 0x5b, 0x4e, 0x5c, 0x4c, 0xcf,
445 0x5c, 0x08, 0x5f, 0x96, 0x26, 0x77, 0x1d, 0x31, 0xf1, 0xe1, 0xf7, 0x4b,
446 0x92, 0xac, 0x82, 0x2a, 0x88, 0xc7, 0x83, 0xe1, 0xc7, 0xf3, 0xd3, 0x1a,
447 0x7d, 0xc8, 0x31, 0xe3, 0x97, 0xe4, 0xec, 0x31, 0x0e, 0x8f, 0x73, 0x1a,
448 0xe4, 0xf6, 0xd8, 0xc8, 0x94, 0xff, 0xa0, 0x03, 0x84, 0x03, 0x0f, 0xa5,
449 0x30, 0x5d, 0x67, 0xe0, 0x7a, 0x3b, 0x5f, 0xed, 0x4c, 0xf5, 0xbc, 0x18,
450 0xea, 0xd4, 0x77, 0xa9, 0x07, 0xb3, 0x54, 0x0b, 0x02, 0xd9, 0xc6, 0xb8,
451 0x66, 0x5e, 0xec, 0xa4, 0xcd, 0x47, 0xed, 0xc9, 0x38, 0xc6, 0x91, 0x08,
452 0xf3, 0x85, 0x9b, 0x69, 0x16, 0x78, 0x0d, 0xb7, 0x74, 0x51, 0xaa, 0x5b,
453 0x4d, 0x74, 0xe4, 0x29, 0x2e, 0x9e, 0x8e, 0xf7, 0xe5, 0x42, 0x83, 0xb0,
454 0x65, 0xb0, 0xce, 0xc6, 0xb2, 0x8f, 0x5b, 0xb0
457 static int test_ref_data(void)
460 int ret = AVERROR(ENOMEM);
461 uint8_t pubkey_test[128];
462 uint8_t sharedkey_test[128];
464 dh = ff_dh_init(1024);
467 bn_hex2bn(dh->priv_key, private_key, ret);
470 bn_hex2bn(dh->pub_key, public_key, ret);
473 if ((ret = ff_dh_write_public_key(dh, pubkey_test, sizeof(pubkey_test))) < 0)
475 if (memcmp(pubkey_test, public_key_bin, sizeof(pubkey_test))) {
476 printf("Mismatched generated public key\n");
477 ret = AVERROR_INVALIDDATA;
480 printf("Generated public key ok\n");
482 if ((ret = ff_dh_compute_shared_secret_key(dh, peer_public_key, sizeof(peer_public_key),
483 sharedkey_test, sizeof(sharedkey_test))) < 0)
485 if (memcmp(shared_secret, sharedkey_test, sizeof(sharedkey_test))) {
486 printf("Mismatched generated shared key\n");
487 ret = AVERROR_INVALIDDATA;
489 printf("Generated shared key ok\n");
498 if (test_random_shared_secret() < 0)
500 if (test_ref_data() < 0)