]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c
Moved debug.[ch] to utils folder
[thirdparty/strongswan.git] / src / libstrongswan / plugins / gmp / gmp_diffie_hellman.c
CommitLineData
552cc11b
MW
1/*
2 * Copyright (C) 1998-2002 D. Hugh Redelmeier.
3 * Copyright (C) 1999, 2000, 2001 Henry Spencer.
908d5717 4 * Copyright (C) 2010 Tobias Brunner
552cc11b
MW
5 * Copyright (C) 2005-2008 Martin Willi
6 * Copyright (C) 2005 Jan Hutter
7 * Hochschule fuer Technik Rapperswil
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 * for more details.
552cc11b
MW
18 */
19
20#include <gmp.h>
21
22#include "gmp_diffie_hellman.h"
23
f05b4272 24#include <utils/debug.h>
552cc11b 25
3e35a6e7
MW
26#ifdef HAVE_MPZ_POWM_SEC
27# undef mpz_powm
28# define mpz_powm mpz_powm_sec
29#endif
552cc11b 30
552cc11b
MW
31typedef struct private_gmp_diffie_hellman_t private_gmp_diffie_hellman_t;
32
33/**
34 * Private data of an gmp_diffie_hellman_t object.
35 */
36struct private_gmp_diffie_hellman_t {
37 /**
38 * Public gmp_diffie_hellman_t interface.
39 */
40 gmp_diffie_hellman_t public;
7daf5226 41
552cc11b
MW
42 /**
43 * Diffie Hellman group number.
44 */
45 u_int16_t group;
7daf5226
MW
46
47 /*
552cc11b 48 * Generator value.
7daf5226 49 */
552cc11b 50 mpz_t g;
7daf5226 51
552cc11b
MW
52 /**
53 * My private value.
54 */
55 mpz_t xa;
7daf5226 56
552cc11b
MW
57 /**
58 * My public value.
59 */
60 mpz_t ya;
7daf5226 61
552cc11b
MW
62 /**
63 * Other public value.
7daf5226 64 */
552cc11b 65 mpz_t yb;
7daf5226 66
552cc11b
MW
67 /**
68 * Shared secret.
7daf5226 69 */
552cc11b
MW
70 mpz_t zz;
71
72 /**
73 * Modulus.
74 */
75 mpz_t p;
7daf5226 76
552cc11b
MW
77 /**
78 * Modulus length.
79 */
80 size_t p_len;
7daf5226 81
552cc11b
MW
82 /**
83 * True if shared secret is computed and stored in my_public_value.
84 */
85 bool computed;
86};
87
876b61e1
MW
88METHOD(diffie_hellman_t, set_other_public_value, void,
89 private_gmp_diffie_hellman_t *this, chunk_t value)
552cc11b
MW
90{
91 mpz_t p_min_1;
7daf5226 92
552cc11b
MW
93 mpz_init(p_min_1);
94 mpz_sub_ui(p_min_1, this->p, 1);
7daf5226 95
552cc11b 96 mpz_import(this->yb, value.len, 1, 1, 1, 0, value.ptr);
7daf5226
MW
97
98 /* check public value:
552cc11b
MW
99 * 1. 0 or 1 is invalid as 0^a = 0 and 1^a = 1
100 * 2. a public value larger or equal the modulus is invalid */
cdaf57ec 101 if (mpz_cmp_ui(this->yb, 1) > 0 &&
552cc11b
MW
102 mpz_cmp(this->yb, p_min_1) < 0)
103 {
104#ifdef EXTENDED_DH_TEST
105 /* 3. test if y ^ q mod p = 1, where q = (p - 1)/2. */
106 mpz_t q, one;
4590260b 107 diffie_hellman_params_t *params;
7daf5226 108
552cc11b
MW
109 mpz_init(q);
110 mpz_init(one);
4590260b
MW
111
112 params = diffie_hellman_get_params(this->group);
113 if (!params->subgroup.len)
114 {
115 mpz_fdiv_q_2exp(q, p_min_1, 1);
116 }
117 else
118 {
119 mpz_import(q, params->subgroup.len, 1, 1, 1, 0, params->subgroup.ptr);
120 }
552cc11b
MW
121 mpz_powm(one, this->yb, q, this->p);
122 mpz_clear(q);
123 if (mpz_cmp_ui(one, 1) == 0)
124 {
125 mpz_powm(this->zz, this->yb, this->xa, this->p);
126 this->computed = TRUE;
127 }
128 else
129 {
8b0e0910
TB
130 DBG1(DBG_LIB, "public DH value verification failed:"
131 " y ^ q mod p != 1");
552cc11b
MW
132 }
133 mpz_clear(one);
134#else
135 mpz_powm(this->zz, this->yb, this->xa, this->p);
136 this->computed = TRUE;
137#endif
138 }
139 else
140 {
8b0e0910
TB
141 DBG1(DBG_LIB, "public DH value verification failed:"
142 " y < 2 || y > p - 1 ");
552cc11b
MW
143 }
144 mpz_clear(p_min_1);
145}
146
876b61e1
MW
147METHOD(diffie_hellman_t, get_my_public_value, void,
148 private_gmp_diffie_hellman_t *this,chunk_t *value)
552cc11b
MW
149{
150 value->len = this->p_len;
323f9f99
MW
151 value->ptr = mpz_export(NULL, NULL, 1, value->len, 1, 0, this->ya);
152 if (value->ptr == NULL)
153 {
154 value->len = 0;
155 }
552cc11b
MW
156}
157
876b61e1
MW
158METHOD(diffie_hellman_t, get_shared_secret, status_t,
159 private_gmp_diffie_hellman_t *this, chunk_t *secret)
552cc11b
MW
160{
161 if (!this->computed)
162 {
163 return FAILED;
164 }
165 secret->len = this->p_len;
73f6886a
MW
166 secret->ptr = mpz_export(NULL, NULL, 1, secret->len, 1, 0, this->zz);
167 if (secret->ptr == NULL)
168 {
169 return FAILED;
170 }
552cc11b
MW
171 return SUCCESS;
172}
173
876b61e1
MW
174METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
175 private_gmp_diffie_hellman_t *this)
552cc11b
MW
176{
177 return this->group;
178}
179
876b61e1
MW
180METHOD(diffie_hellman_t, destroy, void,
181 private_gmp_diffie_hellman_t *this)
552cc11b
MW
182{
183 mpz_clear(this->p);
184 mpz_clear(this->xa);
185 mpz_clear(this->ya);
186 mpz_clear(this->yb);
187 mpz_clear(this->zz);
188 mpz_clear(this->g);
189 free(this);
190}
191
08d8b940
MW
192/**
193 * Generic internal constructor
552cc11b 194 */
08d8b940
MW
195static gmp_diffie_hellman_t *create_generic(diffie_hellman_group_t group,
196 size_t exp_len, chunk_t g, chunk_t p)
552cc11b 197{
b34b93db 198 private_gmp_diffie_hellman_t *this;
552cc11b 199 chunk_t random;
08d8b940 200 rng_t *rng;
b34b93db 201
876b61e1 202 INIT(this,
ba31fe1f
MW
203 .public = {
204 .dh = {
205 .get_shared_secret = _get_shared_secret,
206 .set_other_public_value = _set_other_public_value,
207 .get_my_public_value = _get_my_public_value,
208 .get_dh_group = _get_dh_group,
209 .destroy = _destroy,
210 },
876b61e1
MW
211 },
212 .group = group,
08d8b940 213 .p_len = p.len,
876b61e1 214 );
7daf5226 215
552cc11b
MW
216 mpz_init(this->p);
217 mpz_init(this->yb);
218 mpz_init(this->ya);
219 mpz_init(this->xa);
220 mpz_init(this->zz);
221 mpz_init(this->g);
08d8b940
MW
222 mpz_import(this->g, g.len, 1, 1, 1, 0, g.ptr);
223 mpz_import(this->p, p.len, 1, 1, 1, 0, p.ptr);
908d5717 224
6a365f07
MW
225 rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
226 if (!rng)
552cc11b 227 {
8b0e0910
TB
228 DBG1(DBG_LIB, "no RNG found for quality %N", rng_quality_names,
229 RNG_STRONG);
552cc11b
MW
230 destroy(this);
231 return NULL;
232 }
5025135f
TB
233 if (!rng->allocate_bytes(rng, exp_len, &random))
234 {
235 DBG1(DBG_LIB, "failed to allocate DH secret");
236 rng->destroy(rng);
237 destroy(this);
238 return NULL;
239 }
6a365f07 240 rng->destroy(rng);
f5ab7f5f 241
08d8b940 242 if (exp_len == this->p_len)
f5ab7f5f
AS
243 {
244 /* achieve bitsof(p)-1 by setting MSB to 0 */
245 *random.ptr &= 0x7F;
246 }
552cc11b
MW
247 mpz_import(this->xa, random.len, 1, 1, 1, 0, random.ptr);
248 chunk_free(&random);
8b0e0910
TB
249 DBG2(DBG_LIB, "size of DH secret exponent: %u bits",
250 mpz_sizeinbase(this->xa, 2));
f5ab7f5f 251
552cc11b 252 mpz_powm(this->ya, this->g, this->xa, this->p);
7daf5226 253
552cc11b
MW
254 return &this->public;
255}
256
08d8b940
MW
257/*
258 * Described in header.
259 */
260gmp_diffie_hellman_t *gmp_diffie_hellman_create(diffie_hellman_group_t group)
261{
262 diffie_hellman_params_t *params;
263
264 params = diffie_hellman_get_params(group);
265 if (!params)
266 {
267 return NULL;
268 }
269 return create_generic(group, params->exp_len,
270 params->generator, params->prime);
271}
272
273
274gmp_diffie_hellman_t *gmp_diffie_hellman_create_custom(
275 diffie_hellman_group_t group, chunk_t g, chunk_t p)
276{
277 if (group == MODP_CUSTOM)
278 {
279 return create_generic(MODP_CUSTOM, p.len, g, p);
280 }
281 return NULL;
282}