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)
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
)
61 MP_set(&dh
->ctx
.P
, dh
->p
);
62 MP_set(&dh
->ctx
.G
, dh
->g
);
64 dhm_make_public(&dh
->ctx
, 1024, out
, 1, havege_rand
, &RTMP_TLS_ctx
->hs
);
67 MP_set(dh
->pub_key
, &dh
->ctx
.GX
);
68 MP_set(dh
->priv_key
, &dh
->ctx
.X
);
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
);
79 #elif defined(USE_GNUTLS) || defined(USE_GNUTLS_NETTLE)
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)
97 #include <nettle/bignum.h>
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)
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
);
133 MP_setbin(sec
, secret
, len
);
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)
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)
168 #include "dhgroups.h"
170 /* RFC 2631, Section 2.1.5, http://www.ietf.org/rfc/rfc2631.txt */
172 isValidPublicKey(MP_t y
, MP_t p
, MP_t q
)
181 /* y must lie in [2,p-1] */
183 if (MP_cmp(y
, bn
) < 0)
185 RTMP_Log(RTMP_LOGERROR
, "DH public key must be at least 2");
193 if (MP_cmp(y
, bn
) > 0)
195 RTMP_Log(RTMP_LOGERROR
, "DH public key must be at most p-2");
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
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");
236 MP_gethex(dh
->p
, P1024
, res
); /* prime P1024, see dhgroups.h */
242 MP_set_w(dh
->g
, 2); /* base 2 */
244 dh
->length
= nKeyBits
;
255 DHGenerateKey(MDH
*dh
)
265 if (!MDH_generate_key(dh
))
268 MP_gethex(q1
, Q1024
, res
);
271 res
= isValidPublicKey(dh
->pub_key
, dh
->p
, q1
);
274 MP_free(dh
->pub_key
);
275 MP_free(dh
->priv_key
);
276 dh
->pub_key
= dh
->priv_key
= 0;
284 /* fill pubkey with the public key in BIG ENDIAN order
285 * 00 00 00 00 00 x1 x2 x3 .....
289 DHGetPublicKey(MDH
*dh
, uint8_t *pubkey
, size_t nPubkeyLen
)
292 if (!dh
|| !dh
->pub_key
)
295 len
= MP_bytes(dh
->pub_key
);
296 if (len
<= 0 || len
> (int) nPubkeyLen
)
299 memset(pubkey
, 0, nPubkeyLen
);
300 MP_setbin(dh
->pub_key
, pubkey
+ (nPubkeyLen
- len
), len
);
306 DHGetPrivateKey(MDH
*dh
, uint8_t *privkey
, size_t nPrivkeyLen
)
308 if (!dh
|| !dh
->priv_key
)
311 int len
= MP_bytes(dh
->priv_key
);
312 if (len
<= 0 || len
> (int) nPrivkeyLen
)
315 memset(privkey
, 0, nPrivkeyLen
);
316 MP_setbin(dh
->priv_key
, privkey
+ (nPrivkeyLen
- len
), len
);
321 /* computes the shared secret key from the private MDH value and the
322 * other party's public key (pubkey)
325 DHComputeSharedSecretKey(MDH
*dh
, uint8_t *pubkey
, size_t nPubkeyLen
,
328 MP_t q1
= NULL
, pubkeyBn
= NULL
;
332 if (!dh
|| !secret
|| nPubkeyLen
>= INT_MAX
)
335 MP_getbin(pubkeyBn
, pubkey
, nPubkeyLen
);
339 MP_gethex(q1
, Q1024
, len
);
342 if (isValidPublicKey(pubkeyBn
, dh
->p
, q1
))
343 res
= MDH_compute_key(secret
, nPubkeyLen
, pubkeyBn
, dh
);