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_NETTLE || CONFIG_GCRYPT
50 #if CONFIG_NETTLE
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) nettle_mpz_get_str_256(len, buf, bn)
69 #define bn_bin2bn(bn, buf, len) \
70  do { \
71  bn_new(bn); \
72  if (bn) \
73  nettle_mpz_set_str_256_u(bn, len, buf); \
74  } while (0)
75 #define bn_hex2bn(bn, buf, ret) \
76  do { \
77  bn_new(bn); \
78  if (bn) \
79  ret = (mpz_set_str(bn, buf, 16) == 0); \
80  } while (0)
81 #define bn_modexp(bn, y, q, p) mpz_powm(bn, y, q, p)
82 #define bn_random(bn, num_bytes) \
83  do { \
84  gmp_randstate_t rs; \
85  gmp_randinit_mt(rs); \
86  gmp_randseed_ui(rs, av_get_random_seed()); \
87  mpz_urandomb(bn, rs, num_bytes); \
88  gmp_randclear(rs); \
89  } while (0)
90 #elif CONFIG_GCRYPT
91 #define bn_new(bn) bn = gcry_mpi_new(1)
92 #define bn_free(bn) gcry_mpi_release(bn)
93 #define bn_set_word(bn, w) gcry_mpi_set_ui(bn, w)
94 #define bn_cmp(a, b) gcry_mpi_cmp(a, b)
95 #define bn_copy(to, from) gcry_mpi_set(to, from)
96 #define bn_sub_word(bn, w) gcry_mpi_sub_ui(bn, bn, w)
97 #define bn_cmp_1(bn) gcry_mpi_cmp_ui(bn, 1)
98 #define bn_num_bytes(bn) (gcry_mpi_get_nbits(bn) + 7) / 8
99 #define bn_bn2bin(bn, buf, len) gcry_mpi_print(GCRYMPI_FMT_USG, buf, len, NULL, bn)
100 #define bn_bin2bn(bn, buf, len) gcry_mpi_scan(&bn, GCRYMPI_FMT_USG, buf, len, NULL)
101 #define bn_hex2bn(bn, buf, ret) ret = (gcry_mpi_scan(&bn, GCRYMPI_FMT_HEX, buf, 0, 0) == 0)
102 #define bn_modexp(bn, y, q, p) gcry_mpi_powm(bn, y, q, p)
103 #define bn_random(bn, num_bytes) gcry_mpi_randomize(bn, num_bytes, GCRY_WEAK_RANDOM)
104 #endif
105 
106 #define MAX_BYTES 18000
107 
108 #define dh_new() av_malloc(sizeof(FF_DH))
109 
110 static FFBigNum dh_generate_key(FF_DH *dh)
111 {
112  int num_bytes;
113 
114  num_bytes = bn_num_bytes(dh->p) - 1;
115  if (num_bytes <= 0 || num_bytes > MAX_BYTES)
116  return NULL;
117 
118  bn_new(dh->priv_key);
119  if (!dh->priv_key)
120  return NULL;
121  bn_random(dh->priv_key, num_bytes);
122 
123  bn_new(dh->pub_key);
124  if (!dh->pub_key) {
125  bn_free(dh->priv_key);
126  return NULL;
127  }
128 
129  bn_modexp(dh->pub_key, dh->g, dh->priv_key, dh->p);
130 
131  return dh->pub_key;
132 }
133 
134 static int dh_compute_key(FF_DH *dh, FFBigNum pub_key_bn,
135  uint32_t pub_key_len, uint8_t *secret_key)
136 {
137  FFBigNum k;
138  int num_bytes;
139 
140  num_bytes = bn_num_bytes(dh->p);
141  if (num_bytes <= 0 || num_bytes > MAX_BYTES)
142  return -1;
143 
144  bn_new(k);
145  if (!k)
146  return -1;
147 
148  bn_modexp(k, pub_key_bn, dh->priv_key, dh->p);
149  bn_bn2bin(k, secret_key, pub_key_len);
150  bn_free(k);
151 
152  /* return the length of the shared secret key like DH_compute_key */
153  return pub_key_len;
154 }
155 
156 void ff_dh_free(FF_DH *dh)
157 {
158  bn_free(dh->p);
159  bn_free(dh->g);
160  bn_free(dh->pub_key);
161  bn_free(dh->priv_key);
162  av_free(dh);
163 }
164 #elif CONFIG_OPENSSL
165 #define bn_new(bn) bn = BN_new()
166 #define bn_free(bn) BN_free(bn)
167 #define bn_set_word(bn, w) BN_set_word(bn, w)
168 #define bn_cmp(a, b) BN_cmp(a, b)
169 #define bn_copy(to, from) BN_copy(to, from)
170 #define bn_sub_word(bn, w) BN_sub_word(bn, w)
171 #define bn_cmp_1(bn) BN_cmp(bn, BN_value_one())
172 #define bn_num_bytes(bn) BN_num_bytes(bn)
173 #define bn_bn2bin(bn, buf, len) BN_bn2bin(bn, buf)
174 #define bn_bin2bn(bn, buf, len) bn = BN_bin2bn(buf, len, 0)
175 #define bn_hex2bn(bn, buf, ret) ret = BN_hex2bn(&bn, buf)
176 #define bn_modexp(bn, y, q, p) \
177  do { \
178  BN_CTX *ctx = BN_CTX_new(); \
179  if (!ctx) \
180  return AVERROR(ENOMEM); \
181  if (!BN_mod_exp(bn, y, q, p, ctx)) { \
182  BN_CTX_free(ctx); \
183  return AVERROR(EINVAL); \
184  } \
185  BN_CTX_free(ctx); \
186  } while (0)
187 
188 #define dh_new() DH_new()
189 #define dh_generate_key(dh) DH_generate_key(dh)
190 #define dh_compute_key(dh, pub, len, secret) DH_compute_key(secret, pub, dh)
191 
192 void ff_dh_free(FF_DH *dh)
193 {
194  DH_free(dh);
195 }
196 #endif
197 
198 static int dh_is_valid_public_key(FFBigNum y, FFBigNum p, FFBigNum q)
199 {
200  FFBigNum bn = NULL;
201  int ret = AVERROR(EINVAL);
202 
203  bn_new(bn);
204  if (!bn)
205  return AVERROR(ENOMEM);
206 
207  /* y must lie in [2, p - 1] */
208  bn_set_word(bn, 1);
209  if (!bn_cmp(y, bn))
210  goto fail;
211 
212  /* bn = p - 2 */
213  bn_copy(bn, p);
214  bn_sub_word(bn, 1);
215  if (!bn_cmp(y, bn))
216  goto fail;
217 
218  /* Verify with Sophie-Germain prime
219  *
220  * This is a nice test to make sure the public key position is calculated
221  * correctly. This test will fail in about 50% of the cases if applied to
222  * random data.
223  */
224  /* y must fulfill y^q mod p = 1 */
225  bn_modexp(bn, y, q, p);
226 
227  if (bn_cmp_1(bn))
228  goto fail;
229 
230  ret = 0;
231 fail:
232  bn_free(bn);
233 
234  return ret;
235 }
236 
237 av_cold FF_DH *ff_dh_init(int key_len)
238 {
239  FF_DH *dh;
240  int ret;
241 
242  if (!(dh = dh_new()))
243  return NULL;
244 
245  bn_new(dh->g);
246  if (!dh->g)
247  goto fail;
248 
249  bn_hex2bn(dh->p, P1024, ret);
250  if (!ret)
251  goto fail;
252 
253  bn_set_word(dh->g, 2);
254  dh->length = key_len;
255 
256  return dh;
257 
258 fail:
259  ff_dh_free(dh);
260 
261  return NULL;
262 }
263 
265 {
266  int ret = 0;
267 
268  while (!ret) {
269  FFBigNum q1 = NULL;
270 
271  if (!dh_generate_key(dh))
272  return AVERROR(EINVAL);
273 
274  bn_hex2bn(q1, Q1024, ret);
275  if (!ret)
276  return AVERROR(ENOMEM);
277 
278  ret = dh_is_valid_public_key(dh->pub_key, dh->p, q1);
279  bn_free(q1);
280 
281  if (!ret) {
282  /* the public key is valid */
283  break;
284  }
285  }
286 
287  return ret;
288 }
289 
290 int ff_dh_write_public_key(FF_DH *dh, uint8_t *pub_key, int pub_key_len)
291 {
292  int len;
293 
294  /* compute the length of the public key */
295  len = bn_num_bytes(dh->pub_key);
296  if (len <= 0 || len > pub_key_len)
297  return AVERROR(EINVAL);
298 
299  /* convert the public key value into big-endian form */
300  memset(pub_key, 0, pub_key_len);
301  bn_bn2bin(dh->pub_key, pub_key + pub_key_len - len, len);
302 
303  return 0;
304 }
305 
306 int ff_dh_compute_shared_secret_key(FF_DH *dh, const uint8_t *pub_key,
307  int pub_key_len, uint8_t *secret_key)
308 {
309  FFBigNum q1 = NULL, pub_key_bn = NULL;
310  int ret;
311 
312  /* convert the big-endian form of the public key into a bignum */
313  bn_bin2bn(pub_key_bn, pub_key, pub_key_len);
314  if (!pub_key_bn)
315  return AVERROR(ENOMEM);
316 
317  /* convert the string containing a hexadecimal number into a bignum */
318  bn_hex2bn(q1, Q1024, ret);
319  if (!ret) {
320  ret = AVERROR(ENOMEM);
321  goto fail;
322  }
323 
324  /* when the public key is valid we have to compute the shared secret key */
325  if ((ret = dh_is_valid_public_key(pub_key_bn, dh->p, q1)) < 0) {
326  goto fail;
327  } else if ((ret = dh_compute_key(dh, pub_key_bn, pub_key_len,
328  secret_key)) < 0) {
329  ret = AVERROR(EINVAL);
330  goto fail;
331  }
332 
333 fail:
334  bn_free(pub_key_bn);
335  bn_free(q1);
336 
337  return ret;
338 }
339 
uint32_t p[AV_BF_ROUNDS+2]
Definition: blowfish.h:36
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:290
static int dh_is_valid_public_key(FFBigNum y, FFBigNum p, FFBigNum q)
Definition: rtmpdh.c:198
#define P1024
Definition: rtmpdh.c:33
uint8_t
#define av_cold
Definition: attributes.h:78
int ff_dh_generate_public_key(FF_DH *dh)
Generate a public key.
Definition: rtmpdh.c:264
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:183
ret
Definition: avfilter.c:821
void ff_dh_free(FF_DH *dh)
Free a Diffie-Hellmann context.
for k
NULL
Definition: eval.c:55
#define Q1024
Definition: rtmpdh.c:41
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
av_cold FF_DH * ff_dh_init(int key_len)
Initialize a Diffie-Hellmann context.
Definition: rtmpdh.c:237
function y
Definition: D.m:1
int len
int ff_dh_compute_shared_secret_key(FF_DH *dh, const uint8_t *pub_key, int pub_key_len, uint8_t *secret_key)
Compute the shared secret key from the private FF_DH value and the other party&#39;s public value...
Definition: rtmpdh.c:306