]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/plugins/gcrypt/gcrypt_dh.c
diffie-hellman: Add a bool return value to get_my_public_value()
[thirdparty/strongswan.git] / src / libstrongswan / plugins / gcrypt / gcrypt_dh.c
CommitLineData
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
23typedef struct private_gcrypt_dh_t private_gcrypt_dh_t;
24
25/**
26 * Private data of an gcrypt_dh_t object.
27 */
28struct 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
76METHOD(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 */
120static 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 135METHOD(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 142METHOD(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
153METHOD(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
159METHOD(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
174gcrypt_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 */
250gcrypt_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 */
267gcrypt_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}