v2.6 changes
[rtmpdump.git] / librtmp / dh.h
blobfa2c74ff85bb1a93b623812a005b6fc67167ae71
1 /* RTMPDump - Diffie-Hellmann Key Exchange
2 * Copyright (C) 2009 Andrej Stepanchuk
3 * Copyright (C) 2009-2010 Howard Chu
5 * This file is part of librtmp.
7 * librtmp is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1,
10 * or (at your option) any later version.
12 * librtmp is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with librtmp see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 * http://www.gnu.org/copyleft/lgpl.html
24 #include <stdint.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <limits.h>
30 #ifdef USE_POLARSSL
31 #include <polarssl/dhm.h>
32 typedef mpi * MP_t;
33 #define MP_new(m) m = malloc(sizeof(mpi)); mpi_init(m)
34 #define MP_set_w(mpi, w) mpi_lset(mpi, w)
35 #define MP_cmp(u, v) mpi_cmp_mpi(u, v)
36 #define MP_set(u, v) mpi_copy(u, v)
37 #define MP_sub_w(mpi, w) mpi_sub_int(mpi, mpi, w)
38 #define MP_cmp_1(mpi) mpi_cmp_int(mpi, 1)
39 #define MP_modexp(r, y, q, p) mpi_exp_mod(r, y, q, p, NULL)
40 #define MP_free(mpi) mpi_free(mpi); free(mpi)
41 #define MP_gethex(u, hex, res) MP_new(u); res = mpi_read_string(u, 16, hex) == 0
42 #define MP_bytes(u) mpi_size(u)
43 #define MP_setbin(u,buf,len) mpi_write_binary(u,buf,len)
44 #define MP_getbin(u,buf,len) MP_new(u); mpi_read_binary(u,buf,len)
45 #define MP_setpg(dh, p, g) dh->p = p; dh->g = g
46 #define MP_setlength(dh, l) dh->length = l
47 #define MP_getp(dh) dh->p
48 #define MP_getpubkey(dh) dh->pub_key
50 typedef struct MDH {
51 MP_t p;
52 MP_t g;
53 MP_t pub_key;
54 MP_t priv_key;
55 long length;
56 dhm_context ctx;
57 } MDH;
59 #define MDH_new() calloc(1,sizeof(MDH))
60 #define MDH_free(vp) {MDH *_dh = vp; dhm_free(&_dh->ctx); MP_free(_dh->p); MP_free(_dh->g); MP_free(_dh->pub_key); MP_free(_dh->priv_key); free(_dh);}
62 static int MDH_generate_key(MDH *dh)
64 unsigned char out[2];
65 MP_set(&dh->ctx.P, dh->p);
66 MP_set(&dh->ctx.G, dh->g);
67 dh->ctx.len = 128;
68 dhm_make_public(&dh->ctx, 1024, out, 1, havege_random, &RTMP_TLS_ctx->hs);
69 MP_new(dh->pub_key);
70 MP_new(dh->priv_key);
71 MP_set(dh->pub_key, &dh->ctx.GX);
72 MP_set(dh->priv_key, &dh->ctx.X);
73 return 1;
76 static int MDH_compute_key(uint8_t *secret, size_t len, MP_t pub, MDH *dh)
78 MP_set(&dh->ctx.GY, pub);
79 dhm_calc_secret(&dh->ctx, secret, &len);
80 return 0;
83 #elif defined(USE_GNUTLS)
84 #include <gmp.h>
85 #include <nettle/bignum.h>
86 #include <gnutls/crypto.h>
87 typedef mpz_ptr MP_t;
88 #define MP_new(m) m = malloc(sizeof(*m)); mpz_init2(m, 1)
89 #define MP_set_w(mpi, w) mpz_set_ui(mpi, w)
90 #define MP_cmp(u, v) mpz_cmp(u, v)
91 #define MP_set(u, v) mpz_set(u, v)
92 #define MP_sub_w(mpi, w) mpz_sub_ui(mpi, mpi, w)
93 #define MP_cmp_1(mpi) mpz_cmp_ui(mpi, 1)
94 #define MP_modexp(r, y, q, p) mpz_powm(r, y, q, p)
95 #define MP_free(mpi) mpz_clear(mpi); free(mpi)
96 #define MP_gethex(u, hex, res) u = malloc(sizeof(*u)); mpz_init2(u, 1); res = (mpz_set_str(u, hex, 16) == 0)
97 #define MP_bytes(u) (mpz_sizeinbase(u, 2) + 7) / 8
98 #define MP_setbin(u,buf,len) nettle_mpz_get_str_256(len,buf,u)
99 #define MP_getbin(u,buf,len) u = malloc(sizeof(*u)); mpz_init2(u, 1); nettle_mpz_set_str_256_u(u,len,buf)
100 #define MP_setpg(dh, p, g) dh->p = p; dh->g = g
101 #define MP_setlength(dh, l) dh->length = l
102 #define MP_getp(dh) dh->p
103 #define MP_getpubkey(dh) dh->pub_key
105 typedef struct MDH {
106 MP_t p;
107 MP_t g;
108 MP_t pub_key;
109 MP_t priv_key;
110 long length;
111 } MDH;
113 #define MDH_new() calloc(1,sizeof(MDH))
114 #define MDH_free(dh) do {MP_free(((MDH*)(dh))->p); MP_free(((MDH*)(dh))->g); MP_free(((MDH*)(dh))->pub_key); MP_free(((MDH*)(dh))->priv_key); free(dh);} while(0)
116 static int MDH_generate_key(MDH *dh)
118 int num_bytes;
119 uint32_t seed;
120 gmp_randstate_t rs;
122 num_bytes = (mpz_sizeinbase(dh->p, 2) + 7) / 8 - 1;
123 if (num_bytes <= 0 || num_bytes > 18000)
124 return 0;
126 dh->priv_key = calloc(1, sizeof(*dh->priv_key));
127 if (!dh->priv_key)
128 return 0;
129 mpz_init2(dh->priv_key, 1);
130 gnutls_rnd(GNUTLS_RND_RANDOM, &seed, sizeof(seed));
131 gmp_randinit_mt(rs);
132 gmp_randseed_ui(rs, seed);
133 mpz_urandomb(dh->priv_key, rs, num_bytes);
134 gmp_randclear(rs);
136 dh->pub_key = calloc(1, sizeof(*dh->pub_key));
137 if (!dh->pub_key)
138 return 0;
139 mpz_init2(dh->pub_key, 1);
140 if (!dh->pub_key) {
141 mpz_clear(dh->priv_key);
142 free(dh->priv_key);
143 return 0;
146 mpz_powm(dh->pub_key, dh->g, dh->priv_key, dh->p);
148 return 1;
151 static int MDH_compute_key(uint8_t *secret, size_t len, MP_t pub, MDH *dh)
153 mpz_ptr k;
154 int num_bytes;
156 num_bytes = (mpz_sizeinbase(dh->p, 2) + 7) / 8;
157 if (num_bytes <= 0 || num_bytes > 18000)
158 return -1;
160 k = calloc(1, sizeof(*k));
161 if (!k)
162 return -1;
163 mpz_init2(k, 1);
165 mpz_powm(k, pub, dh->priv_key, dh->p);
166 nettle_mpz_get_str_256(len, secret, k);
167 mpz_clear(k);
168 free(k);
170 /* return the length of the shared secret key like DH_compute_key */
171 return len;
174 #else /* USE_OPENSSL */
175 #include <openssl/bn.h>
176 #include <openssl/dh.h>
178 typedef BIGNUM * MP_t;
179 #define MP_new(m) m = BN_new()
180 #define MP_set_w(mpi, w) BN_set_word(mpi, w)
181 #define MP_cmp(u, v) BN_cmp(u, v)
182 #define MP_set(u, v) BN_copy(u, v)
183 #define MP_sub_w(mpi, w) BN_sub_word(mpi, w)
184 #define MP_cmp_1(mpi) BN_cmp(mpi, BN_value_one())
185 #define MP_modexp(r, y, q, p) do {BN_CTX *ctx = BN_CTX_new(); BN_mod_exp(r, y, q, p, ctx); BN_CTX_free(ctx);} while(0)
186 #define MP_free(mpi) BN_free(mpi)
187 #define MP_gethex(u, hex, res) res = BN_hex2bn(&u, hex)
188 #define MP_bytes(u) BN_num_bytes(u)
189 #define MP_setbin(u,buf,len) BN_bn2bin(u,buf)
190 #define MP_getbin(u,buf,len) u = BN_bin2bn(buf,len,0)
192 #define MDH DH
193 #define MDH_new() DH_new()
194 #define MDH_free(dh) DH_free(dh)
195 #define MDH_generate_key(dh) DH_generate_key(dh)
196 #define MDH_compute_key(secret, seclen, pub, dh) DH_compute_key(secret, pub, dh)
198 #if OPENSSL_VERSION_NUMBER >= 0x10100000
199 #define MP_setpg(dh, p, g) DH_set0_pqg(dh, p, NULL, g)
200 #define MP_setlength(dh, l) DH_set_length(dh, l)
201 #define MP_getp(dh) DH_get0_p(dh)
202 #define MP_getpubkey(dh) DH_get0_pub_key(dh)
203 #else
204 #define MP_setpg(dh, p, g) dh->p = p; dh->g = g
205 #define MP_setlength(dh, l) dh->length = l
206 #define MP_getp(dh) dh->p
207 #define MP_getpubkey(dh) dh->pub_key
208 #endif
209 #endif
211 #include "log.h"
212 #include "dhgroups.h"
214 /* RFC 2631, Section 2.1.5, http://www.ietf.org/rfc/rfc2631.txt */
215 static int
216 isValidPublicKey(MP_t y, MP_t p, MP_t q)
218 int ret = TRUE;
219 MP_t bn;
220 assert(y);
222 MP_new(bn);
223 assert(bn);
225 /* y must lie in [2,p-1] */
226 MP_set_w(bn, 1);
227 if (MP_cmp(y, bn) < 0)
229 RTMP_Log(RTMP_LOGERROR, "DH public key must be at least 2");
230 ret = FALSE;
231 goto failed;
234 /* bn = p-2 */
235 MP_set(bn, p);
236 MP_sub_w(bn, 1);
237 if (MP_cmp(y, bn) > 0)
239 RTMP_Log(RTMP_LOGERROR, "DH public key must be at most p-2");
240 ret = FALSE;
241 goto failed;
244 /* Verify with Sophie-Germain prime
246 * This is a nice test to make sure the public key position is calculated
247 * correctly. This test will fail in about 50% of the cases if applied to
248 * random data.
250 if (q)
252 /* y must fulfill y^q mod p = 1 */
253 MP_modexp(bn, y, q, p);
255 if (MP_cmp_1(bn) != 0)
257 RTMP_Log(RTMP_LOGWARNING, "DH public key does not fulfill y^q mod p = 1");
261 failed:
262 MP_free(bn);
263 return ret;
266 static MDH *
267 DHInit(int nKeyBits)
269 size_t res;
270 MDH *dh = MDH_new();
271 MP_t g, p;
273 if (!dh)
274 goto failed;
276 MP_new(g);
278 if (!g)
279 goto failed;
281 MP_gethex(p, P1024, res); /* prime P1024, see dhgroups.h */
282 if (!res)
284 goto failed;
287 MP_set_w(g, 2); /* base 2 */
288 MP_setpg(dh, p, g);
290 MP_setlength(dh, nKeyBits);
291 return dh;
293 failed:
294 if (dh)
295 MDH_free(dh);
297 return 0;
300 static int
301 DHGenerateKey(MDH *dh)
303 MP_t q1;
304 size_t res;
305 if (!dh)
306 return 0;
308 MP_gethex(q1, Q1024, res);
309 assert(res);
313 if (MDH_generate_key(dh))
315 MP_t key = (MP_t)MP_getpubkey(dh);
316 MP_t p = (MP_t)MP_getp(dh);
317 res = isValidPublicKey(key, p, q1);
319 else
321 #if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000
322 MP_free(dh->pub_key);
323 MP_free(dh->priv_key);
324 dh->pub_key = dh->priv_key = 0;
325 #endif
326 res = 0;
327 break;
329 } while (!res);
330 MP_free(q1);
331 return res;
334 /* fill pubkey with the public key in BIG ENDIAN order
335 * 00 00 00 00 00 x1 x2 x3 .....
338 static int
339 DHGetPublicKey(MDH *dh, uint8_t *pubkey, size_t nPubkeyLen)
341 int len;
342 MP_t pub_key;
343 if (!dh || !(pub_key = (MP_t)MP_getpubkey(dh)))
344 return 0;
346 len = MP_bytes(pub_key);
347 if (len <= 0 || len > (int) nPubkeyLen)
348 return 0;
350 memset(pubkey, 0, nPubkeyLen);
351 MP_setbin(pub_key, pubkey + (nPubkeyLen - len), len);
352 return 1;
355 #if 0 /* unused */
356 static int
357 DHGetPrivateKey(MDH *dh, uint8_t *privkey, size_t nPrivkeyLen)
359 if (!dh || !dh->priv_key)
360 return 0;
362 int len = MP_bytes(dh->priv_key);
363 if (len <= 0 || len > (int) nPrivkeyLen)
364 return 0;
366 memset(privkey, 0, nPrivkeyLen);
367 MP_setbin(dh->priv_key, privkey + (nPrivkeyLen - len), len);
368 return 1;
370 #endif
372 /* computes the shared secret key from the private MDH value and the
373 * other party's public key (pubkey)
375 static int
376 DHComputeSharedSecretKey(MDH *dh, uint8_t *pubkey, size_t nPubkeyLen,
377 uint8_t *secret)
379 MP_t q1 = NULL, pubkeyBn = NULL;
380 size_t len;
381 int res;
383 if (!dh || !secret || nPubkeyLen >= INT_MAX)
384 return -1;
386 MP_getbin(pubkeyBn, pubkey, nPubkeyLen);
387 if (!pubkeyBn)
388 return -1;
390 MP_gethex(q1, Q1024, len);
391 assert(len);
393 if (isValidPublicKey(pubkeyBn, (MP_t)MP_getp(dh), q1))
394 res = MDH_compute_key(secret, nPubkeyLen, pubkeyBn, dh);
395 else
396 res = -1;
398 MP_free(q1);
399 MP_free(pubkeyBn);
401 return res;