Add support for building with gnutls with nettle as backend
[rtmpdump.git] / librtmp / dh.h
blob830000ebee7bcb159ccb7b71966c6a2a803a1e9b
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)
46 typedef struct MDH {
47 MP_t p;
48 MP_t g;
49 MP_t pub_key;
50 MP_t priv_key;
51 long length;
52 dhm_context ctx;
53 } MDH;
55 #define MDH_new() calloc(1,sizeof(MDH))
56 #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);}
58 static int MDH_generate_key(MDH *dh)
60 unsigned char out[2];
61 MP_set(&dh->ctx.P, dh->p);
62 MP_set(&dh->ctx.G, dh->g);
63 dh->ctx.len = 128;
64 dhm_make_public(&dh->ctx, 1024, out, 1, havege_rand, &RTMP_TLS_ctx->hs);
65 MP_new(dh->pub_key);
66 MP_new(dh->priv_key);
67 MP_set(dh->pub_key, &dh->ctx.GX);
68 MP_set(dh->priv_key, &dh->ctx.X);
69 return 1;
72 static int MDH_compute_key(uint8_t *secret, size_t len, MP_t pub, MDH *dh)
74 MP_set(&dh->ctx.GY, pub);
75 dhm_calc_secret(&dh->ctx, secret, &len);
76 return 0;
79 #elif defined(USE_GNUTLS) || defined(USE_GNUTLS_NETTLE)
80 #ifdef USE_GNUTLS
81 #include <gcrypt.h>
82 typedef gcry_mpi_t MP_t;
83 #define MP_new(m) m = gcry_mpi_new(1)
84 #define MP_set_w(mpi, w) gcry_mpi_set_ui(mpi, w)
85 #define MP_cmp(u, v) gcry_mpi_cmp(u, v)
86 #define MP_set(u, v) gcry_mpi_set(u, v)
87 #define MP_sub_w(mpi, w) gcry_mpi_sub_ui(mpi, mpi, w)
88 #define MP_cmp_1(mpi) gcry_mpi_cmp_ui(mpi, 1)
89 #define MP_modexp(r, y, q, p) gcry_mpi_powm(r, y, q, p)
90 #define MP_free(mpi) gcry_mpi_release(mpi)
91 #define MP_gethex(u, hex, res) res = (gcry_mpi_scan(&u, GCRYMPI_FMT_HEX, hex, 0, 0) == 0)
92 #define MP_bytes(u) (gcry_mpi_get_nbits(u) + 7) / 8
93 #define MP_setbin(u,buf,len) gcry_mpi_print(GCRYMPI_FMT_USG,buf,len,NULL,u)
94 #define MP_getbin(u,buf,len) gcry_mpi_scan(&u,GCRYMPI_FMT_USG,buf,len,NULL)
95 #else
96 #include <gmp.h>
97 #include <nettle/bignum.h>
98 typedef mpz_ptr MP_t;
99 #define MP_new(m) m = malloc(sizeof(*m)); mpz_init2(m, 1)
100 #define MP_set_w(mpi, w) mpz_set_ui(mpi, w)
101 #define MP_cmp(u, v) mpz_cmp(u, v)
102 #define MP_set(u, v) mpz_set(u, v)
103 #define MP_sub_w(mpi, w) mpz_sub_ui(mpi, mpi, w)
104 #define MP_cmp_1(mpi) mpz_cmp_ui(mpi, 1)
105 #define MP_modexp(r, y, q, p) mpz_powm(r, y, q, p)
106 #define MP_free(mpi) mpz_clear(mpi); free(mpi)
107 #define MP_gethex(u, hex, res) u = malloc(sizeof(*u)); mpz_init2(u, 1); res = (mpz_set_str(u, hex, 16) == 0)
108 #define MP_bytes(u) (mpz_sizeinbase(u, 2) + 7) / 8
109 #define MP_setbin(u,buf,len) nettle_mpz_get_str_256(len,buf,u)
110 #define MP_getbin(u,buf,len) u = malloc(sizeof(*u)); mpz_init2(u, 1); nettle_mpz_set_str_256_u(u,len,buf)
111 #endif
113 typedef struct MDH {
114 MP_t p;
115 MP_t g;
116 MP_t pub_key;
117 MP_t priv_key;
118 long length;
119 } MDH;
121 #define MDH_new() calloc(1,sizeof(MDH))
122 #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)
124 extern MP_t gnutls_calc_dh_secret(MP_t *priv, MP_t g, MP_t p);
125 extern MP_t gnutls_calc_dh_key(MP_t y, MP_t x, MP_t p);
127 #define MDH_generate_key(dh) (dh->pub_key = gnutls_calc_dh_secret(&dh->priv_key, dh->g, dh->p))
128 static int MDH_compute_key(uint8_t *secret, size_t len, MP_t pub, MDH *dh)
130 MP_t sec = gnutls_calc_dh_key(pub, dh->priv_key, dh->p);
131 if (sec)
133 MP_setbin(sec, secret, len);
134 MP_free(sec);
135 return 0;
137 else
138 return -1;
141 #else /* USE_OPENSSL */
142 #include <openssl/bn.h>
143 #include <openssl/dh.h>
145 typedef BIGNUM * MP_t;
146 #define MP_new(m) m = BN_new()
147 #define MP_set_w(mpi, w) BN_set_word(mpi, w)
148 #define MP_cmp(u, v) BN_cmp(u, v)
149 #define MP_set(u, v) BN_copy(u, v)
150 #define MP_sub_w(mpi, w) BN_sub_word(mpi, w)
151 #define MP_cmp_1(mpi) BN_cmp(mpi, BN_value_one())
152 #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)
153 #define MP_free(mpi) BN_free(mpi)
154 #define MP_gethex(u, hex, res) res = BN_hex2bn(&u, hex)
155 #define MP_bytes(u) BN_num_bytes(u)
156 #define MP_setbin(u,buf,len) BN_bn2bin(u,buf)
157 #define MP_getbin(u,buf,len) u = BN_bin2bn(buf,len,0)
159 #define MDH DH
160 #define MDH_new() DH_new()
161 #define MDH_free(dh) DH_free(dh)
162 #define MDH_generate_key(dh) DH_generate_key(dh)
163 #define MDH_compute_key(secret, seclen, pub, dh) DH_compute_key(secret, pub, dh)
165 #endif
167 #include "log.h"
168 #include "dhgroups.h"
170 /* RFC 2631, Section 2.1.5, http://www.ietf.org/rfc/rfc2631.txt */
171 static int
172 isValidPublicKey(MP_t y, MP_t p, MP_t q)
174 int ret = TRUE;
175 MP_t bn;
176 assert(y);
178 MP_new(bn);
179 assert(bn);
181 /* y must lie in [2,p-1] */
182 MP_set_w(bn, 1);
183 if (MP_cmp(y, bn) < 0)
185 RTMP_Log(RTMP_LOGERROR, "DH public key must be at least 2");
186 ret = FALSE;
187 goto failed;
190 /* bn = p-2 */
191 MP_set(bn, p);
192 MP_sub_w(bn, 1);
193 if (MP_cmp(y, bn) > 0)
195 RTMP_Log(RTMP_LOGERROR, "DH public key must be at most p-2");
196 ret = FALSE;
197 goto failed;
200 /* Verify with Sophie-Germain prime
202 * This is a nice test to make sure the public key position is calculated
203 * correctly. This test will fail in about 50% of the cases if applied to
204 * random data.
206 if (q)
208 /* y must fulfill y^q mod p = 1 */
209 MP_modexp(bn, y, q, p);
211 if (MP_cmp_1(bn) != 0)
213 RTMP_Log(RTMP_LOGWARNING, "DH public key does not fulfill y^q mod p = 1");
217 failed:
218 MP_free(bn);
219 return ret;
222 static MDH *
223 DHInit(int nKeyBits)
225 size_t res;
226 MDH *dh = MDH_new();
228 if (!dh)
229 goto failed;
231 MP_new(dh->g);
233 if (!dh->g)
234 goto failed;
236 MP_gethex(dh->p, P1024, res); /* prime P1024, see dhgroups.h */
237 if (!res)
239 goto failed;
242 MP_set_w(dh->g, 2); /* base 2 */
244 dh->length = nKeyBits;
245 return dh;
247 failed:
248 if (dh)
249 MDH_free(dh);
251 return 0;
254 static int
255 DHGenerateKey(MDH *dh)
257 size_t res = 0;
258 if (!dh)
259 return 0;
261 while (!res)
263 MP_t q1 = NULL;
265 if (!MDH_generate_key(dh))
266 return 0;
268 MP_gethex(q1, Q1024, res);
269 assert(res);
271 res = isValidPublicKey(dh->pub_key, dh->p, q1);
272 if (!res)
274 MP_free(dh->pub_key);
275 MP_free(dh->priv_key);
276 dh->pub_key = dh->priv_key = 0;
279 MP_free(q1);
281 return 1;
284 /* fill pubkey with the public key in BIG ENDIAN order
285 * 00 00 00 00 00 x1 x2 x3 .....
288 static int
289 DHGetPublicKey(MDH *dh, uint8_t *pubkey, size_t nPubkeyLen)
291 int len;
292 if (!dh || !dh->pub_key)
293 return 0;
295 len = MP_bytes(dh->pub_key);
296 if (len <= 0 || len > (int) nPubkeyLen)
297 return 0;
299 memset(pubkey, 0, nPubkeyLen);
300 MP_setbin(dh->pub_key, pubkey + (nPubkeyLen - len), len);
301 return 1;
304 #if 0 /* unused */
305 static int
306 DHGetPrivateKey(MDH *dh, uint8_t *privkey, size_t nPrivkeyLen)
308 if (!dh || !dh->priv_key)
309 return 0;
311 int len = MP_bytes(dh->priv_key);
312 if (len <= 0 || len > (int) nPrivkeyLen)
313 return 0;
315 memset(privkey, 0, nPrivkeyLen);
316 MP_setbin(dh->priv_key, privkey + (nPrivkeyLen - len), len);
317 return 1;
319 #endif
321 /* computes the shared secret key from the private MDH value and the
322 * other party's public key (pubkey)
324 static int
325 DHComputeSharedSecretKey(MDH *dh, uint8_t *pubkey, size_t nPubkeyLen,
326 uint8_t *secret)
328 MP_t q1 = NULL, pubkeyBn = NULL;
329 size_t len;
330 int res;
332 if (!dh || !secret || nPubkeyLen >= INT_MAX)
333 return -1;
335 MP_getbin(pubkeyBn, pubkey, nPubkeyLen);
336 if (!pubkeyBn)
337 return -1;
339 MP_gethex(q1, Q1024, len);
340 assert(len);
342 if (isValidPublicKey(pubkeyBn, dh->p, q1))
343 res = MDH_compute_key(secret, nPubkeyLen, pubkeyBn, dh);
344 else
345 res = -1;
347 MP_free(q1);
348 MP_free(pubkeyBn);
350 return res;