]>
Commit | Line | Data |
---|---|---|
1111088a | 1 | /* |
908d5717 | 2 | * Copyright (C) 2010 Tobias Brunner |
1111088a | 3 | * Copyright (C) 2009 Martin Willi |
19ef2aec TB |
4 | * |
5 | * Copyright (C) secunet Security Networks AG | |
1111088a MW |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License as published by the | |
9 | * Free Software Foundation; either version 2 of the License, or (at your | |
10 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 | * for more details. | |
16 | */ | |
17 | ||
18 | #include <gcrypt.h> | |
19 | ||
20 | #include "gcrypt_dh.h" | |
21 | ||
f05b4272 | 22 | #include <utils/debug.h> |
1111088a | 23 | |
1111088a MW |
24 | typedef struct private_gcrypt_dh_t private_gcrypt_dh_t; |
25 | ||
26 | /** | |
27 | * Private data of an gcrypt_dh_t object. | |
28 | */ | |
29 | struct private_gcrypt_dh_t { | |
7daf5226 | 30 | |
1111088a MW |
31 | /** |
32 | * Public gcrypt_dh_t interface | |
33 | */ | |
34 | gcrypt_dh_t public; | |
7daf5226 | 35 | |
1111088a MW |
36 | /** |
37 | * Diffie Hellman group number | |
38 | */ | |
e13ef5c4 | 39 | diffie_hellman_group_t group; |
7daf5226 MW |
40 | |
41 | /* | |
1111088a | 42 | * Generator value |
7daf5226 | 43 | */ |
1111088a | 44 | gcry_mpi_t g; |
7daf5226 | 45 | |
1111088a MW |
46 | /** |
47 | * Own private value | |
48 | */ | |
49 | gcry_mpi_t xa; | |
7daf5226 | 50 | |
1111088a MW |
51 | /** |
52 | * Own public value | |
53 | */ | |
54 | gcry_mpi_t ya; | |
7daf5226 | 55 | |
1111088a MW |
56 | /** |
57 | * Other public value | |
58 | */ | |
59 | gcry_mpi_t yb; | |
7daf5226 | 60 | |
1111088a MW |
61 | /** |
62 | * Shared secret | |
63 | */ | |
64 | gcry_mpi_t zz; | |
7daf5226 | 65 | |
1111088a MW |
66 | /** |
67 | * Modulus | |
68 | */ | |
69 | gcry_mpi_t p; | |
7daf5226 | 70 | |
1111088a MW |
71 | /** |
72 | * Modulus length. | |
73 | */ | |
74 | size_t p_len; | |
75 | }; | |
76 | ||
a777155f | 77 | METHOD(diffie_hellman_t, set_other_public_value, bool, |
646babd3 | 78 | private_gcrypt_dh_t *this, chunk_t value) |
1111088a MW |
79 | { |
80 | gcry_mpi_t p_min_1; | |
81 | gcry_error_t err; | |
7daf5226 | 82 | |
0356089d MW |
83 | if (!diffie_hellman_verify_value(this->group, value)) |
84 | { | |
85 | return FALSE; | |
86 | } | |
87 | ||
1111088a MW |
88 | if (this->yb) |
89 | { | |
90 | gcry_mpi_release(this->yb); | |
91 | this->yb = NULL; | |
92 | } | |
93 | err = gcry_mpi_scan(&this->yb, GCRYMPI_FMT_USG, value.ptr, value.len, NULL); | |
94 | if (err) | |
95 | { | |
8b0e0910 | 96 | DBG1(DBG_LIB, "importing mpi yb failed: %s", gpg_strerror(err)); |
a777155f | 97 | return FALSE; |
1111088a | 98 | } |
7daf5226 | 99 | |
1111088a MW |
100 | p_min_1 = gcry_mpi_new(this->p_len * 8); |
101 | gcry_mpi_sub_ui(p_min_1, this->p, 1); | |
7daf5226 MW |
102 | |
103 | /* check public value: | |
1111088a MW |
104 | * 1. 0 or 1 is invalid as 0^a = 0 and 1^a = 1 |
105 | * 2. a public value larger or equal the modulus is invalid */ | |
106 | if (gcry_mpi_cmp_ui(this->yb, 1) > 0 && | |
107 | gcry_mpi_cmp(this->yb, p_min_1) < 0) | |
108 | { | |
109 | if (!this->zz) | |
110 | { | |
111 | this->zz = gcry_mpi_new(this->p_len * 8); | |
112 | } | |
113 | gcry_mpi_powm(this->zz, this->yb, this->xa, this->p); | |
114 | } | |
115 | else | |
116 | { | |
8b0e0910 TB |
117 | DBG1(DBG_LIB, "public DH value verification failed:" |
118 | " y < 2 || y > p - 1 "); | |
1111088a MW |
119 | } |
120 | gcry_mpi_release(p_min_1); | |
a777155f | 121 | return this->zz != NULL; |
1111088a MW |
122 | } |
123 | ||
124 | /** | |
125 | * export a gcry_mpi to an allocated chunk of len bytes | |
126 | */ | |
127 | static chunk_t export_mpi(gcry_mpi_t value, size_t len) | |
128 | { | |
129 | chunk_t chunk; | |
130 | size_t written; | |
7daf5226 | 131 | |
1111088a MW |
132 | chunk = chunk_alloc(len); |
133 | gcry_mpi_print(GCRYMPI_FMT_USG, chunk.ptr, chunk.len, &written, value); | |
134 | if (written < len) | |
135 | { /* right-align number of written bytes in chunk */ | |
136 | memmove(chunk.ptr + (len - written), chunk.ptr, written); | |
137 | memset(chunk.ptr, 0, len - written); | |
138 | } | |
139 | return chunk; | |
140 | } | |
141 | ||
42431690 | 142 | METHOD(diffie_hellman_t, get_my_public_value, bool, |
646babd3 | 143 | private_gcrypt_dh_t *this, chunk_t *value) |
1111088a MW |
144 | { |
145 | *value = export_mpi(this->ya, this->p_len); | |
42431690 | 146 | return TRUE; |
1111088a MW |
147 | } |
148 | ||
41421b85 MW |
149 | METHOD(diffie_hellman_t, set_private_value, bool, |
150 | private_gcrypt_dh_t *this, chunk_t value) | |
151 | { | |
152 | gcry_error_t err; | |
153 | gcry_mpi_t xa; | |
154 | ||
155 | err = gcry_mpi_scan(&xa, GCRYMPI_FMT_USG, value.ptr, value.len, NULL); | |
156 | if (!err) | |
157 | { | |
158 | gcry_mpi_release(this->xa); | |
159 | this->xa = xa; | |
160 | gcry_mpi_powm(this->ya, this->g, this->xa, this->p); | |
161 | gcry_mpi_release(this->zz); | |
162 | this->zz = NULL; | |
163 | } | |
164 | return !err; | |
165 | } | |
166 | ||
bace1d64 | 167 | METHOD(diffie_hellman_t, get_shared_secret, bool, |
646babd3 | 168 | private_gcrypt_dh_t *this, chunk_t *secret) |
1111088a MW |
169 | { |
170 | if (!this->zz) | |
171 | { | |
bace1d64 | 172 | return FALSE; |
1111088a MW |
173 | } |
174 | *secret = export_mpi(this->zz, this->p_len); | |
bace1d64 | 175 | return TRUE; |
1111088a MW |
176 | } |
177 | ||
646babd3 MW |
178 | METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t, |
179 | private_gcrypt_dh_t *this) | |
1111088a MW |
180 | { |
181 | return this->group; | |
182 | } | |
183 | ||
646babd3 MW |
184 | METHOD(diffie_hellman_t, destroy, void, |
185 | private_gcrypt_dh_t *this) | |
1111088a MW |
186 | { |
187 | gcry_mpi_release(this->p); | |
188 | gcry_mpi_release(this->xa); | |
189 | gcry_mpi_release(this->ya); | |
190 | gcry_mpi_release(this->g); | |
191 | gcry_mpi_release(this->yb); | |
192 | gcry_mpi_release(this->zz); | |
193 | free(this); | |
194 | } | |
195 | ||
196 | /* | |
ed60dfa1 | 197 | * Generic internal constructor |
1111088a | 198 | */ |
a80069e7 TB |
199 | static gcrypt_dh_t *create_generic(diffie_hellman_group_t group, size_t exp_len, |
200 | chunk_t g, chunk_t p) | |
1111088a MW |
201 | { |
202 | private_gcrypt_dh_t *this; | |
1111088a MW |
203 | gcry_error_t err; |
204 | chunk_t random; | |
205 | rng_t *rng; | |
7daf5226 | 206 | |
646babd3 | 207 | INIT(this, |
ba31fe1f MW |
208 | .public = { |
209 | .dh = { | |
210 | .get_shared_secret = _get_shared_secret, | |
211 | .set_other_public_value = _set_other_public_value, | |
212 | .get_my_public_value = _get_my_public_value, | |
41421b85 | 213 | .set_private_value = _set_private_value, |
ba31fe1f MW |
214 | .get_dh_group = _get_dh_group, |
215 | .destroy = _destroy, | |
216 | }, | |
646babd3 MW |
217 | }, |
218 | .group = group, | |
ed60dfa1 | 219 | .p_len = p.len, |
646babd3 | 220 | ); |
ed60dfa1 | 221 | err = gcry_mpi_scan(&this->p, GCRYMPI_FMT_USG, p.ptr, p.len, NULL); |
1111088a MW |
222 | if (err) |
223 | { | |
8b0e0910 | 224 | DBG1(DBG_LIB, "importing mpi modulus failed: %s", gpg_strerror(err)); |
1111088a MW |
225 | free(this); |
226 | return NULL; | |
227 | } | |
ed60dfa1 | 228 | err = gcry_mpi_scan(&this->g, GCRYMPI_FMT_USG, g.ptr, g.len, NULL); |
b34b93db MW |
229 | if (err) |
230 | { | |
231 | DBG1(DBG_LIB, "importing mpi generator failed: %s", gpg_strerror(err)); | |
232 | gcry_mpi_release(this->p); | |
233 | free(this); | |
234 | return NULL; | |
235 | } | |
7daf5226 | 236 | |
1111088a | 237 | rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); |
1f5291b1 | 238 | if (rng && rng->allocate_bytes(rng, exp_len, &random)) |
1111088a | 239 | { /* prefer external randomizer */ |
1111088a MW |
240 | rng->destroy(rng); |
241 | err = gcry_mpi_scan(&this->xa, GCRYMPI_FMT_USG, | |
242 | random.ptr, random.len, NULL); | |
243 | chunk_clear(&random); | |
244 | if (err) | |
245 | { | |
8b0e0910 | 246 | DBG1(DBG_LIB, "importing mpi xa failed: %s", gpg_strerror(err)); |
1111088a | 247 | gcry_mpi_release(this->p); |
b34b93db | 248 | gcry_mpi_release(this->g); |
1111088a MW |
249 | free(this); |
250 | return NULL; | |
251 | } | |
252 | } | |
253 | else | |
254 | { /* fallback to gcrypt internal randomizer, shouldn't ever happen */ | |
1f5291b1 | 255 | DESTROY_IF(rng); |
ed60dfa1 MW |
256 | this->xa = gcry_mpi_new(exp_len * 8); |
257 | gcry_mpi_randomize(this->xa, exp_len * 8, GCRY_STRONG_RANDOM); | |
1111088a | 258 | } |
ed60dfa1 | 259 | if (exp_len == this->p_len) |
1111088a MW |
260 | { |
261 | /* achieve bitsof(p)-1 by setting MSB to 0 */ | |
ed60dfa1 | 262 | gcry_mpi_clear_bit(this->xa, exp_len * 8 - 1); |
1111088a | 263 | } |
7daf5226 | 264 | |
1111088a | 265 | this->ya = gcry_mpi_new(this->p_len * 8); |
7daf5226 | 266 | |
1111088a | 267 | gcry_mpi_powm(this->ya, this->g, this->xa, this->p); |
7daf5226 | 268 | |
1111088a MW |
269 | return &this->public; |
270 | } | |
271 | ||
ed60dfa1 MW |
272 | |
273 | /* | |
274 | * Described in header. | |
275 | */ | |
276 | gcrypt_dh_t *gcrypt_dh_create(diffie_hellman_group_t group) | |
277 | { | |
278 | ||
279 | diffie_hellman_params_t *params; | |
280 | ||
281 | params = diffie_hellman_get_params(group); | |
282 | if (!params) | |
283 | { | |
284 | return NULL; | |
285 | } | |
286 | return create_generic(group, params->exp_len, | |
287 | params->generator, params->prime); | |
288 | } | |
289 | ||
290 | /* | |
291 | * Described in header. | |
292 | */ | |
46a62f01 | 293 | gcrypt_dh_t *gcrypt_dh_create_custom(diffie_hellman_group_t group, ...) |
ed60dfa1 MW |
294 | { |
295 | if (group == MODP_CUSTOM) | |
296 | { | |
46a62f01 TB |
297 | chunk_t g, p; |
298 | ||
299 | VA_ARGS_GET(group, g, p); | |
ed60dfa1 MW |
300 | return create_generic(group, p.len, g, p); |
301 | } | |
302 | return NULL; | |
303 | } |