FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rtmpdh.c
Go to the documentation of this file.
1 /*
2  * RTMP Diffie-Hellmann utilities
3  * Copyright (c) 2009 Andrej Stepanchuk
4  * Copyright (c) 2009-2010 Howard Chu
5  * Copyright (c) 2012 Samuel Pitoiset
6  *
7  * This file is part of FFmpeg.
8  *
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.
13  *
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.
18  *
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
22  */
23 
24 /**
25  * @file
26  * RTMP Diffie-Hellmann utilities
27  */
28 
29 #include "config.h"
30 #include "rtmpdh.h"
31 #include "libavutil/random_seed.h"
32 
33 #define P1024 \
34  "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
35  "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
36  "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
37  "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
38  "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \
39  "FFFFFFFFFFFFFFFF"
40 
41 #define Q1024 \
42  "7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68" \
43  "948127044533E63A0105DF531D89CD9128A5043CC71A026E" \
44  "F7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122" \
45  "F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6" \
46  "F71C35FDAD44CFD2D74F9208BE258FF324943328F67329C0" \
47  "FFFFFFFFFFFFFFFF"
48 
49 #if CONFIG_GMP || CONFIG_GCRYPT
50 #if CONFIG_GMP
51 #define bn_new(bn) \
52  do { \
53  bn = av_malloc(sizeof(*bn)); \
54  if (bn) \
55  mpz_init2(bn, 1); \
56  } while (0)
57 #define bn_free(bn) \
58  do { \
59  mpz_clear(bn); \
60  av_free(bn); \
61  } while (0)
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) \
69  do { \
70  memset(buf, 0, len); \
71  if (bn_num_bytes(bn) <= len) \
72  mpz_export(buf, NULL, 1, 1, 0, 0, bn); \
73  } while (0)
74 #define bn_bin2bn(bn, buf, len) \
75  do { \
76  bn_new(bn); \
77  if (bn) \
78  mpz_import(bn, len, 1, 1, 0, 0, buf); \
79  } while (0)
80 #define bn_hex2bn(bn, buf, ret) \
81  do { \
82  bn_new(bn); \
83  if (bn) \
84  ret = (mpz_set_str(bn, buf, 16) == 0); \
85  else \
86  ret = 1; \
87  } while (0)
88 #define bn_modexp(bn, y, q, p) mpz_powm(bn, y, q, p)
89 #define bn_random(bn, num_bits) \
90  do { \
91  int bits = num_bits; \
92  mpz_set_ui(bn, 0); \
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()); \
96  } \
97  mpz_fdiv_r_2exp(bn, bn, num_bits); \
98  } while (0)
99 #elif CONFIG_GCRYPT
100 #define bn_new(bn) \
101  do { \
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); \
107  } \
108  bn = gcry_mpi_new(1); \
109  } while (0)
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)
122 #endif
123 
124 #define MAX_BYTES 18000
125 
126 #define dh_new() av_malloc(sizeof(FF_DH))
127 
128 static FFBigNum dh_generate_key(FF_DH *dh)
129 {
130  int num_bytes;
131 
132  num_bytes = bn_num_bytes(dh->p) - 1;
133  if (num_bytes <= 0 || num_bytes > MAX_BYTES)
134  return NULL;
135 
136  bn_new(dh->priv_key);
137  if (!dh->priv_key)
138  return NULL;
139  bn_random(dh->priv_key, 8 * num_bytes);
140 
141  bn_new(dh->pub_key);
142  if (!dh->pub_key) {
143  bn_free(dh->priv_key);
144  return NULL;
145  }
146 
147  bn_modexp(dh->pub_key, dh->g, dh->priv_key, dh->p);
148 
149  return dh->pub_key;
150 }
151 
152 static int dh_compute_key(FF_DH *dh, FFBigNum pub_key_bn,
153  uint32_t secret_key_len, uint8_t *secret_key)
154 {
155  FFBigNum k;
156 
157  bn_new(k);
158  if (!k)
159  return -1;
160 
161  bn_modexp(k, pub_key_bn, dh->priv_key, dh->p);
162  bn_bn2bin(k, secret_key, secret_key_len);
163  bn_free(k);
164 
165  /* return the length of the shared secret key like DH_compute_key */
166  return secret_key_len;
167 }
168 
169 void ff_dh_free(FF_DH *dh)
170 {
171  if (!dh)
172  return;
173  bn_free(dh->p);
174  bn_free(dh->g);
175  bn_free(dh->pub_key);
176  bn_free(dh->priv_key);
177  av_free(dh);
178 }
179 #elif CONFIG_OPENSSL
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) \
192  do { \
193  BN_CTX *ctx = BN_CTX_new(); \
194  if (!ctx) \
195  return AVERROR(ENOMEM); \
196  if (!BN_mod_exp(bn, y, q, p, ctx)) { \
197  BN_CTX_free(ctx); \
198  return AVERROR(EINVAL); \
199  } \
200  BN_CTX_free(ctx); \
201  } while (0)
202 
203 #define dh_new() DH_new()
204 #define dh_generate_key(dh) DH_generate_key(dh)
205 
206 static int dh_compute_key(FF_DH *dh, FFBigNum pub_key_bn,
207  uint32_t secret_key_len, uint8_t *secret_key)
208 {
209  if (secret_key_len < DH_size(dh))
210  return AVERROR(EINVAL);
211  return DH_compute_key(secret_key, pub_key_bn, dh);
212 }
213 
214 void ff_dh_free(FF_DH *dh)
215 {
216  if (!dh)
217  return;
218  DH_free(dh);
219 }
220 #endif
221 
222 static int dh_is_valid_public_key(FFBigNum y, FFBigNum p, FFBigNum q)
223 {
224  FFBigNum bn = NULL;
225  int ret = AVERROR(EINVAL);
226 
227  bn_new(bn);
228  if (!bn)
229  return AVERROR(ENOMEM);
230 
231  /* y must lie in [2, p - 1] */
232  bn_set_word(bn, 1);
233  if (!bn_cmp(y, bn))
234  goto fail;
235 
236  /* bn = p - 2 */
237  bn_copy(bn, p);
238  bn_sub_word(bn, 1);
239  if (!bn_cmp(y, bn))
240  goto fail;
241 
242  /* Verify with Sophie-Germain prime
243  *
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
246  * random data.
247  */
248  /* y must fulfill y^q mod p = 1 */
249  bn_modexp(bn, y, q, p);
250 
251  if (bn_cmp_1(bn))
252  goto fail;
253 
254  ret = 0;
255 fail:
256  bn_free(bn);
257 
258  return ret;
259 }
260 
261 av_cold FF_DH *ff_dh_init(int key_len)
262 {
263  FF_DH *dh;
264  int ret;
265 
266  if (!(dh = dh_new()))
267  return NULL;
268 
269  bn_new(dh->g);
270  if (!dh->g)
271  goto fail;
272 
273  bn_hex2bn(dh->p, P1024, ret);
274  if (!ret)
275  goto fail;
276 
277  bn_set_word(dh->g, 2);
278  dh->length = key_len;
279 
280  return dh;
281 
282 fail:
283  ff_dh_free(dh);
284 
285  return NULL;
286 }
287 
289 {
290  int ret = 0;
291 
292  while (!ret) {
293  FFBigNum q1 = NULL;
294 
295  if (!dh_generate_key(dh))
296  return AVERROR(EINVAL);
297 
298  bn_hex2bn(q1, Q1024, ret);
299  if (!ret)
300  return AVERROR(ENOMEM);
301 
302  ret = dh_is_valid_public_key(dh->pub_key, dh->p, q1);
303  bn_free(q1);
304 
305  if (!ret) {
306  /* the public key is valid */
307  break;
308  }
309  }
310 
311  return ret;
312 }
313 
314 int ff_dh_write_public_key(FF_DH *dh, uint8_t *pub_key, int pub_key_len)
315 {
316  int len;
317 
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);
322 
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);
326 
327  return 0;
328 }
329 
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,
332  int secret_key_len)
333 {
334  FFBigNum q1 = NULL, pub_key_bn = NULL;
335  int ret;
336 
337  /* convert the big-endian form of the public key into a bignum */
338  bn_bin2bn(pub_key_bn, pub_key, pub_key_len);
339  if (!pub_key_bn)
340  return AVERROR(ENOMEM);
341 
342  /* convert the string containing a hexadecimal number into a bignum */
343  bn_hex2bn(q1, Q1024, ret);
344  if (!ret) {
345  ret = AVERROR(ENOMEM);
346  goto fail;
347  }
348 
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) {
351  goto fail;
352  } else if ((ret = dh_compute_key(dh, pub_key_bn, secret_key_len,
353  secret_key)) < 0) {
354  ret = AVERROR(EINVAL);
355  goto fail;
356  }
357 
358 fail:
359  bn_free(pub_key_bn);
360  bn_free(q1);
361 
362  return ret;
363 }
364 
365 #ifdef TEST
366 static int test_random_shared_secret(void)
367 {
368  FF_DH *peer1 = NULL, *peer2 = NULL;
369  int ret;
370  uint8_t pubkey1[128], pubkey2[128];
371  uint8_t sharedkey1[128], sharedkey2[128];
372 
373  peer1 = ff_dh_init(1024);
374  peer2 = ff_dh_init(1024);
375  if (!peer1 || !peer2) {
376  ret = AVERROR(ENOMEM);
377  goto fail;
378  }
379  if ((ret = ff_dh_generate_public_key(peer1)) < 0)
380  goto fail;
381  if ((ret = ff_dh_generate_public_key(peer2)) < 0)
382  goto fail;
383  if ((ret = ff_dh_write_public_key(peer1, pubkey1, sizeof(pubkey1))) < 0)
384  goto fail;
385  if ((ret = ff_dh_write_public_key(peer2, pubkey2, sizeof(pubkey2))) < 0)
386  goto fail;
387  if ((ret = ff_dh_compute_shared_secret_key(peer1, pubkey2, sizeof(pubkey2),
388  sharedkey1, sizeof(sharedkey1))) < 0)
389  goto fail;
390  if ((ret = ff_dh_compute_shared_secret_key(peer2, pubkey1, sizeof(pubkey1),
391  sharedkey2, sizeof(sharedkey2))) < 0)
392  goto fail;
393  if (memcmp(sharedkey1, sharedkey2, sizeof(sharedkey1))) {
394  printf("Mismatched generated shared key\n");
395  ret = AVERROR_INVALIDDATA;
396  } else {
397  printf("Generated shared key ok\n");
398  }
399 fail:
400  ff_dh_free(peer1);
401  ff_dh_free(peer2);
402  return ret;
403 }
404 
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
427 };
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
440 };
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
453 };
454 
455 static int test_ref_data(void)
456 {
457  FF_DH *dh;
458  int ret = AVERROR(ENOMEM);
459  uint8_t pubkey_test[128];
460  uint8_t sharedkey_test[128];
461 
462  dh = ff_dh_init(1024);
463  if (!dh)
464  goto fail;
465  bn_hex2bn(dh->priv_key, private_key, ret);
466  if (!ret)
467  goto fail;
468  bn_hex2bn(dh->pub_key, public_key, ret);
469  if (!ret)
470  goto fail;
471  if ((ret = ff_dh_write_public_key(dh, pubkey_test, sizeof(pubkey_test))) < 0)
472  goto fail;
473  if (memcmp(pubkey_test, public_key_bin, sizeof(pubkey_test))) {
474  printf("Mismatched generated public key\n");
475  ret = AVERROR_INVALIDDATA;
476  goto fail;
477  } else {
478  printf("Generated public key ok\n");
479  }
480  if ((ret = ff_dh_compute_shared_secret_key(dh, peer_public_key, sizeof(peer_public_key),
481  sharedkey_test, sizeof(sharedkey_test))) < 0)
482  goto fail;
483  if (memcmp(shared_secret, sharedkey_test, sizeof(sharedkey_test))) {
484  printf("Mismatched generated shared key\n");
485  ret = AVERROR_INVALIDDATA;
486  } else {
487  printf("Generated shared key ok\n");
488  }
489 fail:
490  ff_dh_free(dh);
491  return ret;
492 }
493 
494 int main(void)
495 {
496  if (test_random_shared_secret() < 0)
497  return 1;
498  if (test_ref_data() < 0)
499  return 1;
500  return 0;
501 }
502 #endif
uint32_t p[AV_BF_ROUNDS+2]
Definition: blowfish.h:36
#define NULL
Definition: coverity.c:32
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
int ff_dh_write_public_key(FF_DH *dh, uint8_t *pub_key, int pub_key_len)
Write the public key into the given buffer.
Definition: rtmpdh.c:314
static int dh_is_valid_public_key(FFBigNum y, FFBigNum p, FFBigNum q)
Definition: rtmpdh.c:222
int ff_dh_compute_shared_secret_key(FF_DH *dh, const uint8_t *pub_key, int pub_key_len, uint8_t *secret_key, int secret_key_len)
Compute the shared secret key from the private FF_DH value and the other party's public value...
Definition: rtmpdh.c:330
#define P1024
Definition: rtmpdh.c:33
static const uint8_t q1[256]
Definition: twofish.c:96
uint8_t
#define av_cold
Definition: attributes.h:82
int ff_dh_generate_public_key(FF_DH *dh)
Generate a public key.
Definition: rtmpdh.c:288
#define AVERROR(e)
Definition: error.h:43
#define fail()
Definition: checkasm.h:80
void ff_dh_free(FF_DH *dh)
Free a Diffie-Hellmann context.
#define Q1024
Definition: rtmpdh.c:41
av_cold FF_DH * ff_dh_init(int key_len)
Initialize a Diffie-Hellmann context.
Definition: rtmpdh.c:261
#define av_free(p)
int len
int main(int argc, char **argv)
Definition: main.c:22