Add adobe authentication support
[rtmpdump.git] / librtmp / dh.h
blobfa264f87f007d9b94380bdfb699d49ff2b6faf56
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 #if POLARSSL_VERSION_NUMBER < 0x01010100
33 #define havege_random havege_rand
34 #endif
35 typedef mpi * MP_t;
36 #define MP_new(m) m = malloc(sizeof(mpi)); mpi_init(m)
37 #define MP_set_w(mpi, w) mpi_lset(mpi, w)
38 #define MP_cmp(u, v) mpi_cmp_mpi(u, v)
39 #define MP_set(u, v) mpi_copy(u, v)
40 #define MP_sub_w(mpi, w) mpi_sub_int(mpi, mpi, w)
41 #define MP_cmp_1(mpi) mpi_cmp_int(mpi, 1)
42 #define MP_modexp(r, y, q, p) mpi_exp_mod(r, y, q, p, NULL)
43 #define MP_free(mpi) mpi_free(mpi); free(mpi)
44 #define MP_gethex(u, hex, res) MP_new(u); res = mpi_read_string(u, 16, hex) == 0
45 #define MP_bytes(u) mpi_size(u)
46 #define MP_setbin(u,buf,len) mpi_write_binary(u,buf,len)
47 #define MP_getbin(u,buf,len) MP_new(u); mpi_read_binary(u,buf,len)
49 typedef struct MDH {
50 MP_t p;
51 MP_t g;
52 MP_t pub_key;
53 MP_t priv_key;
54 long length;
55 dhm_context ctx;
56 } MDH;
58 #define MDH_new() calloc(1,sizeof(MDH))
59 #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);}
61 static int MDH_generate_key(MDH *dh)
63 unsigned char out[2];
64 MP_set(&dh->ctx.P, dh->p);
65 MP_set(&dh->ctx.G, dh->g);
66 dh->ctx.len = 128;
67 dhm_make_public(&dh->ctx, 1024, out, 1, havege_random, &RTMP_TLS_ctx->hs);
68 MP_new(dh->pub_key);
69 MP_new(dh->priv_key);
70 MP_set(dh->pub_key, &dh->ctx.GX);
71 MP_set(dh->priv_key, &dh->ctx.X);
72 return 1;
75 static int MDH_compute_key(uint8_t *secret, size_t len, MP_t pub, MDH *dh)
77 MP_set(&dh->ctx.GY, pub);
78 dhm_calc_secret(&dh->ctx, secret, &len);
79 return 0;
82 #elif defined(USE_GNUTLS)
83 #include <gmp.h>
84 #include <nettle/bignum.h>
85 typedef mpz_ptr MP_t;
86 #define MP_new(m) m = malloc(sizeof(*m)); mpz_init2(m, 1)
87 #define MP_set_w(mpi, w) mpz_set_ui(mpi, w)
88 #define MP_cmp(u, v) mpz_cmp(u, v)
89 #define MP_set(u, v) mpz_set(u, v)
90 #define MP_sub_w(mpi, w) mpz_sub_ui(mpi, mpi, w)
91 #define MP_cmp_1(mpi) mpz_cmp_ui(mpi, 1)
92 #define MP_modexp(r, y, q, p) mpz_powm(r, y, q, p)
93 #define MP_free(mpi) mpz_clear(mpi); free(mpi)
94 #define MP_gethex(u, hex, res) u = malloc(sizeof(*u)); mpz_init2(u, 1); res = (mpz_set_str(u, hex, 16) == 0)
95 #define MP_bytes(u) (mpz_sizeinbase(u, 2) + 7) / 8
96 #define MP_setbin(u,buf,len) nettle_mpz_get_str_256(len,buf,u)
97 #define MP_getbin(u,buf,len) u = malloc(sizeof(*u)); mpz_init2(u, 1); nettle_mpz_set_str_256_u(u,len,buf)
99 typedef struct MDH {
100 MP_t p;
101 MP_t g;
102 MP_t pub_key;
103 MP_t priv_key;
104 long length;
105 } MDH;
107 #define MDH_new() calloc(1,sizeof(MDH))
108 #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)
110 extern MP_t gnutls_calc_dh_secret(MP_t *priv, MP_t g, MP_t p);
111 extern MP_t gnutls_calc_dh_key(MP_t y, MP_t x, MP_t p);
113 #define MDH_generate_key(dh) (dh->pub_key = gnutls_calc_dh_secret(&dh->priv_key, dh->g, dh->p))
114 static int MDH_compute_key(uint8_t *secret, size_t len, MP_t pub, MDH *dh)
116 MP_t sec = gnutls_calc_dh_key(pub, dh->priv_key, dh->p);
117 if (sec)
119 MP_setbin(sec, secret, len);
120 MP_free(sec);
121 return 0;
123 else
124 return -1;
127 #else /* USE_OPENSSL */
128 #include <openssl/bn.h>
129 #include <openssl/dh.h>
131 typedef BIGNUM * MP_t;
132 #define MP_new(m) m = BN_new()
133 #define MP_set_w(mpi, w) BN_set_word(mpi, w)
134 #define MP_cmp(u, v) BN_cmp(u, v)
135 #define MP_set(u, v) BN_copy(u, v)
136 #define MP_sub_w(mpi, w) BN_sub_word(mpi, w)
137 #define MP_cmp_1(mpi) BN_cmp(mpi, BN_value_one())
138 #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)
139 #define MP_free(mpi) BN_free(mpi)
140 #define MP_gethex(u, hex, res) res = BN_hex2bn(&u, hex)
141 #define MP_bytes(u) BN_num_bytes(u)
142 #define MP_setbin(u,buf,len) BN_bn2bin(u,buf)
143 #define MP_getbin(u,buf,len) u = BN_bin2bn(buf,len,0)
145 #define MDH DH
146 #define MDH_new() DH_new()
147 #define MDH_free(dh) DH_free(dh)
148 #define MDH_generate_key(dh) DH_generate_key(dh)
149 #define MDH_compute_key(secret, seclen, pub, dh) DH_compute_key(secret, pub, dh)
151 #endif
153 #include "log.h"
154 #include "dhgroups.h"
156 /* RFC 2631, Section 2.1.5, http://www.ietf.org/rfc/rfc2631.txt */
157 static int
158 isValidPublicKey(MP_t y, MP_t p, MP_t q)
160 int ret = TRUE;
161 MP_t bn;
162 assert(y);
164 MP_new(bn);
165 assert(bn);
167 /* y must lie in [2,p-1] */
168 MP_set_w(bn, 1);
169 if (MP_cmp(y, bn) < 0)
171 RTMP_Log(RTMP_LOGERROR, "DH public key must be at least 2");
172 ret = FALSE;
173 goto failed;
176 /* bn = p-2 */
177 MP_set(bn, p);
178 MP_sub_w(bn, 1);
179 if (MP_cmp(y, bn) > 0)
181 RTMP_Log(RTMP_LOGERROR, "DH public key must be at most p-2");
182 ret = FALSE;
183 goto failed;
186 /* Verify with Sophie-Germain prime
188 * This is a nice test to make sure the public key position is calculated
189 * correctly. This test will fail in about 50% of the cases if applied to
190 * random data.
192 if (q)
194 /* y must fulfill y^q mod p = 1 */
195 MP_modexp(bn, y, q, p);
197 if (MP_cmp_1(bn) != 0)
199 RTMP_Log(RTMP_LOGWARNING, "DH public key does not fulfill y^q mod p = 1");
203 failed:
204 MP_free(bn);
205 return ret;
208 static MDH *
209 DHInit(int nKeyBits)
211 size_t res;
212 MDH *dh = MDH_new();
214 if (!dh)
215 goto failed;
217 MP_new(dh->g);
219 if (!dh->g)
220 goto failed;
222 MP_gethex(dh->p, P1024, res); /* prime P1024, see dhgroups.h */
223 if (!res)
225 goto failed;
228 MP_set_w(dh->g, 2); /* base 2 */
230 dh->length = nKeyBits;
231 return dh;
233 failed:
234 if (dh)
235 MDH_free(dh);
237 return 0;
240 static int
241 DHGenerateKey(MDH *dh)
243 size_t res = 0;
244 if (!dh)
245 return 0;
247 while (!res)
249 MP_t q1 = NULL;
251 if (!MDH_generate_key(dh))
252 return 0;
254 MP_gethex(q1, Q1024, res);
255 assert(res);
257 res = isValidPublicKey(dh->pub_key, dh->p, q1);
258 if (!res)
260 MP_free(dh->pub_key);
261 MP_free(dh->priv_key);
262 dh->pub_key = dh->priv_key = 0;
265 MP_free(q1);
267 return 1;
270 /* fill pubkey with the public key in BIG ENDIAN order
271 * 00 00 00 00 00 x1 x2 x3 .....
274 static int
275 DHGetPublicKey(MDH *dh, uint8_t *pubkey, size_t nPubkeyLen)
277 int len;
278 if (!dh || !dh->pub_key)
279 return 0;
281 len = MP_bytes(dh->pub_key);
282 if (len <= 0 || len > (int) nPubkeyLen)
283 return 0;
285 memset(pubkey, 0, nPubkeyLen);
286 MP_setbin(dh->pub_key, pubkey + (nPubkeyLen - len), len);
287 return 1;
290 #if 0 /* unused */
291 static int
292 DHGetPrivateKey(MDH *dh, uint8_t *privkey, size_t nPrivkeyLen)
294 if (!dh || !dh->priv_key)
295 return 0;
297 int len = MP_bytes(dh->priv_key);
298 if (len <= 0 || len > (int) nPrivkeyLen)
299 return 0;
301 memset(privkey, 0, nPrivkeyLen);
302 MP_setbin(dh->priv_key, privkey + (nPrivkeyLen - len), len);
303 return 1;
305 #endif
307 /* computes the shared secret key from the private MDH value and the
308 * other party's public key (pubkey)
310 static int
311 DHComputeSharedSecretKey(MDH *dh, uint8_t *pubkey, size_t nPubkeyLen,
312 uint8_t *secret)
314 MP_t q1 = NULL, pubkeyBn = NULL;
315 size_t len;
316 int res;
318 if (!dh || !secret || nPubkeyLen >= INT_MAX)
319 return -1;
321 MP_getbin(pubkeyBn, pubkey, nPubkeyLen);
322 if (!pubkeyBn)
323 return -1;
325 MP_gethex(q1, Q1024, len);
326 assert(len);
328 if (isValidPublicKey(pubkeyBn, dh->p, q1))
329 res = MDH_compute_key(secret, nPubkeyLen, pubkeyBn, dh);
330 else
331 res = -1;
333 MP_free(q1);
334 MP_free(pubkeyBn);
336 return res;