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