]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/plugins/gcrypt/gcrypt_dh.c
Update copyright headers after acquisition by secunet
[thirdparty/strongswan.git] / src / libstrongswan / plugins / gcrypt / gcrypt_dh.c
CommitLineData
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
24typedef struct private_gcrypt_dh_t private_gcrypt_dh_t;
25
26/**
27 * Private data of an gcrypt_dh_t object.
28 */
29struct 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 77METHOD(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 */
127static 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 142METHOD(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
149METHOD(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 167METHOD(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
178METHOD(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
184METHOD(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
199static 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 */
276gcrypt_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 293gcrypt_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}