2 * Copyright (C) 2010 Tobias Brunner
3 * Copyright (C) 2009 Martin Willi
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 #include "gcrypt_dh.h"
21 #include <utils/debug.h>
23 typedef struct private_gcrypt_dh_t private_gcrypt_dh_t
;
26 * Private data of an gcrypt_dh_t object.
28 struct private_gcrypt_dh_t
{
31 * Public gcrypt_dh_t interface
36 * Diffie Hellman group number
38 diffie_hellman_group_t group
;
76 METHOD(diffie_hellman_t
, set_other_public_value
, bool,
77 private_gcrypt_dh_t
*this, chunk_t value
)
82 if (!diffie_hellman_verify_value(this->group
, value
))
89 gcry_mpi_release(this->yb
);
92 err
= gcry_mpi_scan(&this->yb
, GCRYMPI_FMT_USG
, value
.ptr
, value
.len
, NULL
);
95 DBG1(DBG_LIB
, "importing mpi yb failed: %s", gpg_strerror(err
));
99 p_min_1
= gcry_mpi_new(this->p_len
* 8);
100 gcry_mpi_sub_ui(p_min_1
, this->p
, 1);
102 /* check public value:
103 * 1. 0 or 1 is invalid as 0^a = 0 and 1^a = 1
104 * 2. a public value larger or equal the modulus is invalid */
105 if (gcry_mpi_cmp_ui(this->yb
, 1) > 0 &&
106 gcry_mpi_cmp(this->yb
, p_min_1
) < 0)
110 this->zz
= gcry_mpi_new(this->p_len
* 8);
112 gcry_mpi_powm(this->zz
, this->yb
, this->xa
, this->p
);
116 DBG1(DBG_LIB
, "public DH value verification failed:"
117 " y < 2 || y > p - 1 ");
119 gcry_mpi_release(p_min_1
);
120 return this->zz
!= NULL
;
124 * export a gcry_mpi to an allocated chunk of len bytes
126 static chunk_t
export_mpi(gcry_mpi_t value
, size_t len
)
131 chunk
= chunk_alloc(len
);
132 gcry_mpi_print(GCRYMPI_FMT_USG
, chunk
.ptr
, chunk
.len
, &written
, value
);
134 { /* right-align number of written bytes in chunk */
135 memmove(chunk
.ptr
+ (len
- written
), chunk
.ptr
, written
);
136 memset(chunk
.ptr
, 0, len
- written
);
141 METHOD(diffie_hellman_t
, get_my_public_value
, bool,
142 private_gcrypt_dh_t
*this, chunk_t
*value
)
144 *value
= export_mpi(this->ya
, this->p_len
);
148 METHOD(diffie_hellman_t
, set_private_value
, bool,
149 private_gcrypt_dh_t
*this, chunk_t value
)
154 err
= gcry_mpi_scan(&xa
, GCRYMPI_FMT_USG
, value
.ptr
, value
.len
, NULL
);
157 gcry_mpi_release(this->xa
);
159 gcry_mpi_powm(this->ya
, this->g
, this->xa
, this->p
);
160 gcry_mpi_release(this->zz
);
166 METHOD(diffie_hellman_t
, get_shared_secret
, bool,
167 private_gcrypt_dh_t
*this, chunk_t
*secret
)
173 *secret
= export_mpi(this->zz
, this->p_len
);
177 METHOD(diffie_hellman_t
, get_dh_group
, diffie_hellman_group_t
,
178 private_gcrypt_dh_t
*this)
183 METHOD(diffie_hellman_t
, destroy
, void,
184 private_gcrypt_dh_t
*this)
186 gcry_mpi_release(this->p
);
187 gcry_mpi_release(this->xa
);
188 gcry_mpi_release(this->ya
);
189 gcry_mpi_release(this->g
);
190 gcry_mpi_release(this->yb
);
191 gcry_mpi_release(this->zz
);
196 * Generic internal constructor
198 gcrypt_dh_t
*create_generic(diffie_hellman_group_t group
, size_t exp_len
,
199 chunk_t g
, chunk_t p
)
201 private_gcrypt_dh_t
*this;
209 .get_shared_secret
= _get_shared_secret
,
210 .set_other_public_value
= _set_other_public_value
,
211 .get_my_public_value
= _get_my_public_value
,
212 .set_private_value
= _set_private_value
,
213 .get_dh_group
= _get_dh_group
,
220 err
= gcry_mpi_scan(&this->p
, GCRYMPI_FMT_USG
, p
.ptr
, p
.len
, NULL
);
223 DBG1(DBG_LIB
, "importing mpi modulus failed: %s", gpg_strerror(err
));
227 err
= gcry_mpi_scan(&this->g
, GCRYMPI_FMT_USG
, g
.ptr
, g
.len
, NULL
);
230 DBG1(DBG_LIB
, "importing mpi generator failed: %s", gpg_strerror(err
));
231 gcry_mpi_release(this->p
);
236 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_STRONG
);
237 if (rng
&& rng
->allocate_bytes(rng
, exp_len
, &random
))
238 { /* prefer external randomizer */
240 err
= gcry_mpi_scan(&this->xa
, GCRYMPI_FMT_USG
,
241 random
.ptr
, random
.len
, NULL
);
242 chunk_clear(&random
);
245 DBG1(DBG_LIB
, "importing mpi xa failed: %s", gpg_strerror(err
));
246 gcry_mpi_release(this->p
);
247 gcry_mpi_release(this->g
);
253 { /* fallback to gcrypt internal randomizer, shouldn't ever happen */
255 this->xa
= gcry_mpi_new(exp_len
* 8);
256 gcry_mpi_randomize(this->xa
, exp_len
* 8, GCRY_STRONG_RANDOM
);
258 if (exp_len
== this->p_len
)
260 /* achieve bitsof(p)-1 by setting MSB to 0 */
261 gcry_mpi_clear_bit(this->xa
, exp_len
* 8 - 1);
264 this->ya
= gcry_mpi_new(this->p_len
* 8);
266 gcry_mpi_powm(this->ya
, this->g
, this->xa
, this->p
);
268 return &this->public;
273 * Described in header.
275 gcrypt_dh_t
*gcrypt_dh_create(diffie_hellman_group_t group
)
278 diffie_hellman_params_t
*params
;
280 params
= diffie_hellman_get_params(group
);
285 return create_generic(group
, params
->exp_len
,
286 params
->generator
, params
->prime
);
290 * Described in header.
292 gcrypt_dh_t
*gcrypt_dh_create_custom(diffie_hellman_group_t group
,
293 chunk_t g
, chunk_t p
)
295 if (group
== MODP_CUSTOM
)
297 return create_generic(group
, p
.len
, g
, p
);