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
31 #include <polarssl/dhm.h>
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
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
)
65 MP_set(&dh
->ctx
.P
, dh
->p
);
66 MP_set(&dh
->ctx
.G
, dh
->g
);
68 dhm_make_public(&dh
->ctx
, 1024, out
, 1, havege_random
, &RTMP_TLS_ctx
->hs
);
71 MP_set(dh
->pub_key
, &dh
->ctx
.GX
);
72 MP_set(dh
->priv_key
, &dh
->ctx
.X
);
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
);
83 #elif defined(USE_GNUTLS)
85 #include <nettle/bignum.h>
86 #include <gnutls/crypto.h>
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
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
)
122 num_bytes
= (mpz_sizeinbase(dh
->p
, 2) + 7) / 8 - 1;
123 if (num_bytes
<= 0 || num_bytes
> 18000)
126 dh
->priv_key
= calloc(1, sizeof(*dh
->priv_key
));
129 mpz_init2(dh
->priv_key
, 1);
130 gnutls_rnd(GNUTLS_RND_RANDOM
, &seed
, sizeof(seed
));
132 gmp_randseed_ui(rs
, seed
);
133 mpz_urandomb(dh
->priv_key
, rs
, num_bytes
);
136 dh
->pub_key
= calloc(1, sizeof(*dh
->pub_key
));
139 mpz_init2(dh
->pub_key
, 1);
141 mpz_clear(dh
->priv_key
);
146 mpz_powm(dh
->pub_key
, dh
->g
, dh
->priv_key
, dh
->p
);
151 static int MDH_compute_key(uint8_t *secret
, size_t len
, MP_t pub
, MDH
*dh
)
156 num_bytes
= (mpz_sizeinbase(dh
->p
, 2) + 7) / 8;
157 if (num_bytes
<= 0 || num_bytes
> 18000)
160 k
= calloc(1, sizeof(*k
));
165 mpz_powm(k
, pub
, dh
->priv_key
, dh
->p
);
166 nettle_mpz_get_str_256(len
, secret
, k
);
170 /* return the length of the shared secret key like DH_compute_key */
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)
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)
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
212 #include "dhgroups.h"
214 /* RFC 2631, Section 2.1.5, http://www.ietf.org/rfc/rfc2631.txt */
216 isValidPublicKey(MP_t y
, MP_t p
, MP_t q
)
225 /* y must lie in [2,p-1] */
227 if (MP_cmp(y
, bn
) < 0)
229 RTMP_Log(RTMP_LOGERROR
, "DH public key must be at least 2");
237 if (MP_cmp(y
, bn
) > 0)
239 RTMP_Log(RTMP_LOGERROR
, "DH public key must be at most p-2");
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
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");
281 MP_gethex(p
, P1024
, res
); /* prime P1024, see dhgroups.h */
287 MP_set_w(g
, 2); /* base 2 */
290 MP_setlength(dh
, nKeyBits
);
301 DHGenerateKey(MDH
*dh
)
308 MP_gethex(q1
, Q1024
, 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
);
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;
334 /* fill pubkey with the public key in BIG ENDIAN order
335 * 00 00 00 00 00 x1 x2 x3 .....
339 DHGetPublicKey(MDH
*dh
, uint8_t *pubkey
, size_t nPubkeyLen
)
343 if (!dh
|| !(pub_key
= (MP_t
)MP_getpubkey(dh
)))
346 len
= MP_bytes(pub_key
);
347 if (len
<= 0 || len
> (int) nPubkeyLen
)
350 memset(pubkey
, 0, nPubkeyLen
);
351 MP_setbin(pub_key
, pubkey
+ (nPubkeyLen
- len
), len
);
357 DHGetPrivateKey(MDH
*dh
, uint8_t *privkey
, size_t nPrivkeyLen
)
359 if (!dh
|| !dh
->priv_key
)
362 int len
= MP_bytes(dh
->priv_key
);
363 if (len
<= 0 || len
> (int) nPrivkeyLen
)
366 memset(privkey
, 0, nPrivkeyLen
);
367 MP_setbin(dh
->priv_key
, privkey
+ (nPrivkeyLen
- len
), len
);
372 /* computes the shared secret key from the private MDH value and the
373 * other party's public key (pubkey)
376 DHComputeSharedSecretKey(MDH
*dh
, uint8_t *pubkey
, size_t nPubkeyLen
,
379 MP_t q1
= NULL
, pubkeyBn
= NULL
;
383 if (!dh
|| !secret
|| nPubkeyLen
>= INT_MAX
)
386 MP_getbin(pubkeyBn
, pubkey
, nPubkeyLen
);
390 MP_gethex(q1
, Q1024
, len
);
393 if (isValidPublicKey(pubkeyBn
, (MP_t
)MP_getp(dh
), q1
))
394 res
= MDH_compute_key(secret
, nPubkeyLen
, pubkeyBn
, dh
);