2 * Copyright (C) 1998-2002 D. Hugh Redelmeier.
3 * Copyright (C) 1999, 2000, 2001 Henry Spencer.
4 * Copyright (C) 2010 Tobias Brunner
5 * Copyright (C) 2005-2008 Martin Willi
6 * Copyright (C) 2005 Jan Hutter
7 * Hochschule fuer Technik Rapperswil
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 #include "gmp_diffie_hellman.h"
24 #include <utils/debug.h>
26 #ifdef HAVE_MPZ_POWM_SEC
28 # define mpz_powm mpz_powm_sec
31 typedef struct private_gmp_diffie_hellman_t private_gmp_diffie_hellman_t
;
34 * Private data of an gmp_diffie_hellman_t object.
36 struct private_gmp_diffie_hellman_t
{
38 * Public gmp_diffie_hellman_t interface.
40 gmp_diffie_hellman_t
public;
43 * Diffie Hellman group number.
45 diffie_hellman_group_t group
;
83 * True if shared secret is computed and stored in my_public_value.
88 METHOD(diffie_hellman_t
, set_other_public_value
, bool,
89 private_gmp_diffie_hellman_t
*this, chunk_t value
)
94 mpz_sub_ui(p_min_1
, this->p
, 1);
96 mpz_import(this->yb
, value
.len
, 1, 1, 1, 0, value
.ptr
);
98 /* check public value:
99 * 1. 0 or 1 is invalid as 0^a = 0 and 1^a = 1
100 * 2. a public value larger or equal the modulus is invalid */
101 if (mpz_cmp_ui(this->yb
, 1) > 0 &&
102 mpz_cmp(this->yb
, p_min_1
) < 0)
104 #ifdef EXTENDED_DH_TEST
105 /* 3. test if y ^ q mod p = 1, where q = (p - 1)/2. */
107 diffie_hellman_params_t
*params
;
112 params
= diffie_hellman_get_params(this->group
);
113 if (!params
->subgroup
.len
)
115 mpz_fdiv_q_2exp(q
, p_min_1
, 1);
119 mpz_import(q
, params
->subgroup
.len
, 1, 1, 1, 0, params
->subgroup
.ptr
);
121 mpz_powm(one
, this->yb
, q
, this->p
);
123 if (mpz_cmp_ui(one
, 1) == 0)
125 mpz_powm(this->zz
, this->yb
, this->xa
, this->p
);
126 this->computed
= TRUE
;
130 DBG1(DBG_LIB
, "public DH value verification failed:"
131 " y ^ q mod p != 1");
135 mpz_powm(this->zz
, this->yb
, this->xa
, this->p
);
136 this->computed
= TRUE
;
141 DBG1(DBG_LIB
, "public DH value verification failed:"
142 " y < 2 || y > p - 1 ");
145 return this->computed
;
148 METHOD(diffie_hellman_t
, get_my_public_value
, bool,
149 private_gmp_diffie_hellman_t
*this,chunk_t
*value
)
151 value
->len
= this->p_len
;
152 value
->ptr
= mpz_export(NULL
, NULL
, 1, value
->len
, 1, 0, this->ya
);
153 if (value
->ptr
== NULL
)
160 METHOD(diffie_hellman_t
, get_shared_secret
, bool,
161 private_gmp_diffie_hellman_t
*this, chunk_t
*secret
)
167 secret
->len
= this->p_len
;
168 secret
->ptr
= mpz_export(NULL
, NULL
, 1, secret
->len
, 1, 0, this->zz
);
169 if (secret
->ptr
== NULL
)
176 METHOD(diffie_hellman_t
, get_dh_group
, diffie_hellman_group_t
,
177 private_gmp_diffie_hellman_t
*this)
182 METHOD(diffie_hellman_t
, destroy
, void,
183 private_gmp_diffie_hellman_t
*this)
195 * Generic internal constructor
197 static gmp_diffie_hellman_t
*create_generic(diffie_hellman_group_t group
,
198 size_t exp_len
, chunk_t g
, chunk_t p
)
200 private_gmp_diffie_hellman_t
*this;
207 .get_shared_secret
= _get_shared_secret
,
208 .set_other_public_value
= _set_other_public_value
,
209 .get_my_public_value
= _get_my_public_value
,
210 .get_dh_group
= _get_dh_group
,
224 mpz_import(this->g
, g
.len
, 1, 1, 1, 0, g
.ptr
);
225 mpz_import(this->p
, p
.len
, 1, 1, 1, 0, p
.ptr
);
227 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_STRONG
);
230 DBG1(DBG_LIB
, "no RNG found for quality %N", rng_quality_names
,
235 if (!rng
->allocate_bytes(rng
, exp_len
, &random
))
237 DBG1(DBG_LIB
, "failed to allocate DH secret");
244 if (exp_len
== this->p_len
)
246 /* achieve bitsof(p)-1 by setting MSB to 0 */
249 mpz_import(this->xa
, random
.len
, 1, 1, 1, 0, random
.ptr
);
251 DBG2(DBG_LIB
, "size of DH secret exponent: %u bits",
252 mpz_sizeinbase(this->xa
, 2));
254 mpz_powm(this->ya
, this->g
, this->xa
, this->p
);
256 return &this->public;
260 * Described in header.
262 gmp_diffie_hellman_t
*gmp_diffie_hellman_create(diffie_hellman_group_t group
)
264 diffie_hellman_params_t
*params
;
266 params
= diffie_hellman_get_params(group
);
271 return create_generic(group
, params
->exp_len
,
272 params
->generator
, params
->prime
);
276 gmp_diffie_hellman_t
*gmp_diffie_hellman_create_custom(
277 diffie_hellman_group_t group
, chunk_t g
, chunk_t p
)
279 if (group
== MODP_CUSTOM
)
281 return create_generic(MODP_CUSTOM
, p
.len
, g
, p
);