6fceb2d0896958b741b526d3875ee9c8668afa32
[strongswan.git] / Source / charon / transforms / diffie_hellman.c
1 /**
2 * @file diffie_hellman.c
3 *
4 * @brief Class to represent a diffie hellman exchange.
5 *
6 */
7
8 /*
9 * Copyright (C) 1998-2002 D. Hugh Redelmeier.
10 * Copyright (C) 1999, 2000, 2001 Henry Spencer.
11 * Copyright (C) 2005 Jan Hutter, Martin Willi
12 * Hochschule fuer Technik Rapperswil
13 *
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 2 of the License, or (at your
17 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
23 */
24
25 #include <gmp.h>
26
27 #include "diffie_hellman.h"
28
29 #include "../payloads/transform_substructure.h"
30 #include "../utils/allocator.h"
31 #include "../utils/randomizer.h"
32 #include "../utils/gmp_helper.h"
33
34
35 /**
36 * Modulus of Group 1
37 */
38 static u_int8_t group1_modulus[] = {
39 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34,
40 0xC4,0xC6,0x62,0x8B,0x80 ,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,
41 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
42 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37,
43 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,
44 0xF4,0x4C,0x42,0xE9,0xA6,0x3A,0x36,0x20,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
45 };
46
47
48 /**
49 * Entry of the modulus list
50 */
51 typedef struct modulus_info_entry_s modulus_info_entry_t;
52
53 struct modulus_info_entry_s{
54 /**
55 * Group number as it is defined in transform_substructure.h
56 */
57 diffie_hellman_group_t group;
58
59 /**
60 * Pointer to first byte of modulus in (network order)
61 */
62 u_int8_t *modulus;
63
64 /*
65 * Length of modulus in bytes
66 */
67 size_t modulus_length;
68
69 /*
70 * Generator value
71 */
72 u_int16_t generator;
73 };
74
75
76 static modulus_info_entry_t modulus_info_entries[] = {
77 {MODP_768_BIT,group1_modulus,sizeof(group1_modulus),2},
78 };
79
80 /**
81 * Private data of an diffie_hellman_t object.
82 *
83 */
84 typedef struct private_diffie_hellman_s private_diffie_hellman_t;
85
86 struct private_diffie_hellman_s {
87 /**
88 * public diffie_hellman_t interface
89 */
90 diffie_hellman_t public;
91
92 /**
93 * Diffie Hellman group number
94 */
95 u_int16_t dh_group_number;
96
97 /**
98 * Modulus
99 */
100 mpz_t modulus;
101
102 /**
103 * Modulus length
104 */
105 size_t modulus_length;
106
107 /*
108 * Generator value
109 */
110 u_int16_t generator;
111
112 /**
113 * My prime
114 */
115 mpz_t my_prime;
116
117 /**
118 * My public value
119 */
120 mpz_t my_public_value;
121
122 /**
123 * Other public value
124 */
125 mpz_t other_public_value;
126
127 /**
128 * Shared secret
129 */
130 mpz_t shared_secret;
131
132 /**
133 * True if public modulus is computed and stored in my_public_value
134 */
135 bool my_public_value_is_computed;
136
137 /**
138 * True if shared secret is computed and stored in my_public_value
139 */
140 bool shared_secret_is_computed;
141
142 /**
143 * helper class for gmp functions
144 */
145 gmp_helper_t *gmp_helper;
146
147 /**
148 * Sets the modulus for a specific diffie hellman group
149 *
150 * @param this calling object
151 * @return
152 * SUCCESS if modulus could be found
153 * NOT_FOUND if modulus not supported
154 */
155 status_t (*set_modulus) (private_diffie_hellman_t *this);
156
157 /**
158 * Makes sure my public value is computed
159 *
160 * @param this calling object
161 */
162 void (*compute_public_value) (private_diffie_hellman_t *this);
163
164 /**
165 * Computes shared secret (other public value must be available)
166 *
167 * @param this calling object
168 */
169 void (*compute_shared_secret) (private_diffie_hellman_t *this);
170 };
171
172 /* Compute DH shared secret from our local secret and the peer's public value.
173 * We make the leap that the length should be that of the group
174 * (see quoted passage at start of ACCEPT_KE).
175 */
176 //static void
177 //compute_dh_shared(struct state *st, const chunk_t g
178 //, const struct oakley_group_desc *group)
179 //{
180 // MP_INT mp_g, mp_shared;
181 // struct timeval tv0, tv1;
182 // unsigned long tv_diff;
183 //
184 // gettimeofday(&tv0, NULL);
185 // passert(st->st_sec_in_use);
186 // n_to_mpz(&mp_g, g.ptr, g.len);
187 // mpz_init(&mp_shared);
188 // mpz_powm(&mp_shared, &mp_g, &st->st_sec, group->modulus);
189 // mpz_clear(&mp_g);
190 // freeanychunk(st->st_shared); /* happens in odd error cases */
191 // st->st_shared = mpz_to_n(&mp_shared, group->bytes);
192 // mpz_clear(&mp_shared);
193 // gettimeofday(&tv1, NULL);
194 // tv_diff=(tv1.tv_sec - tv0.tv_sec) * 1000000 + (tv1.tv_usec - tv0.tv_usec);
195 // DBG(DBG_CRYPT,
196 // DBG_log("compute_dh_shared(): time elapsed (%s): %ld usec"
197 // , enum_show(&oakley_group_names, st->st_oakley.group->group)
198 // , tv_diff);
199 // );
200 // /* if took more than 200 msec ... */
201 // if (tv_diff > 200000) {
202 // loglog(RC_LOG_SERIOUS, "WARNING: compute_dh_shared(): for %s took "
203 // "%ld usec"
204 // , enum_show(&oakley_group_names, st->st_oakley.group->group)
205 // , tv_diff);
206 // }
207 //
208 // DBG_cond_dump_chunk(DBG_CRYPT, "DH shared secret:\n", st->st_shared);
209 //}
210
211
212 /**
213 * Implements private_diffie_hellman_t's set_modulus function.
214 * See #private_diffie_hellman_t.set_modulus for description.
215 */
216 static status_t set_modulus(private_diffie_hellman_t *this)
217 {
218 int i;
219 status_t status = NOT_FOUND;
220
221 for (i = 0; i < (sizeof(modulus_info_entries) / sizeof(modulus_info_entry_t)); i++)
222 {
223 if (modulus_info_entries[i].group == this->dh_group_number)
224 {
225 chunk_t modulus_chunk;
226 modulus_chunk.ptr = modulus_info_entries[i].modulus;
227 modulus_chunk.len = modulus_info_entries[i].modulus_length;
228 this->gmp_helper->chunk_to_mpz(this->gmp_helper,&(this->modulus),modulus_chunk);
229 this->modulus_length = modulus_chunk.len;
230 this->generator = modulus_info_entries[i].generator;
231 status = SUCCESS;
232 break;
233 }
234 }
235 return status;
236 }
237
238 /**
239 * Implements diffie_hellman_t's set_other_public_value function.
240 * See #diffie_hellman_t.set_other_public_value for description.
241 */
242 static status_t set_other_public_value(private_diffie_hellman_t *this,chunk_t public_value)
243 {
244 this->gmp_helper->chunk_to_mpz(this->gmp_helper,&(this->other_public_value),public_value);
245 this->compute_shared_secret(this);
246 return SUCCESS;
247 }
248
249 /**
250 * Implements diffie_hellman_t's get_other_public_value function.
251 * See #diffie_hellman_t.get_other_public_value for description.
252 */
253 static status_t get_other_public_value(private_diffie_hellman_t *this,chunk_t *public_value)
254 {
255 if (!this->shared_secret_is_computed)
256 {
257 return FAILED;
258 }
259 return (this->gmp_helper->mpz_to_chunk(this->gmp_helper,&(this->other_public_value), public_value,this->modulus_length));
260 }
261
262 /**
263 * Implements private_diffie_hellman_t's compute_shared_secret function.
264 * See #private_diffie_hellman_t.compute_shared_secret for description.
265 */
266 static void compute_shared_secret (private_diffie_hellman_t *this)
267 {
268 /* initialize my public value */
269 mpz_init(this->shared_secret);
270 /* calculate my public value */
271 mpz_powm(this->shared_secret,this->other_public_value,this->my_prime,this->modulus);
272
273 this->shared_secret_is_computed = TRUE;
274 }
275
276
277 /**
278 * Implements private_diffie_hellman_t's compute_public_value function.
279 * See #private_diffie_hellman_t.compute_public_value for description.
280 */
281 static void compute_public_value (private_diffie_hellman_t *this)
282 {
283 mpz_t generator;
284 /* initialize generator and set it*/
285 mpz_init_set_ui (generator,this->generator);
286 /* initialize my public value */
287 mpz_init(this->my_public_value);
288 /* calculate my public value */
289 mpz_powm(this->my_public_value,generator,this->my_prime,this->modulus);
290 /* generator not used anymore */
291 mpz_clear(generator);
292 this->my_public_value_is_computed = TRUE;
293 }
294
295 /**
296 * Implements diffie_hellman_t's get_my_public_value function.
297 * See #diffie_hellman_t.get_my_public_value for description.
298 */
299 static status_t get_my_public_value(private_diffie_hellman_t *this,chunk_t *public_value)
300 {
301 if (!this->my_public_value_is_computed)
302 {
303 this->compute_public_value(this);
304 }
305 return (this->gmp_helper->mpz_to_chunk(this->gmp_helper,&(this->my_public_value), public_value,this->modulus_length));
306 }
307
308 /**
309 * Implements diffie_hellman_t's get_shared_secret function.
310 * See #diffie_hellman_t.get_shared_secret for description.
311 */
312 static status_t get_shared_secret(private_diffie_hellman_t *this,chunk_t *secret)
313 {
314 if (!this->shared_secret_is_computed)
315 {
316 return FAILED;
317 }
318 return (this->gmp_helper->mpz_to_chunk(this->gmp_helper,&(this->shared_secret), secret,this->modulus_length));
319 }
320
321 /**
322 * Implements diffie_hellman_t's destroy function.
323 * See #diffie_hellman_t.destroy for description.
324 */
325 static status_t destroy(private_diffie_hellman_t *this)
326 {
327 this->gmp_helper->destroy(this->gmp_helper);
328 mpz_clear(this->modulus);
329 mpz_clear(this->my_prime);
330 if (this->my_public_value_is_computed)
331 {
332 mpz_clear(this->my_public_value);
333 }
334 if (this->shared_secret_is_computed)
335 {
336 /* other public value gets initialized together with shared secret */
337 mpz_clear(this->other_public_value);
338 mpz_clear(this->shared_secret);
339 }
340
341 allocator_free(this);
342 return SUCCESS;
343 }
344
345
346 /*
347 * Described in header
348 */
349 diffie_hellman_t *diffie_hellman_create(u_int16_t dh_group_number)
350 {
351 private_diffie_hellman_t *this = allocator_alloc_thing(private_diffie_hellman_t);
352 if ((this == NULL))
353 {
354 return NULL;
355 }
356
357 /* public functions */
358 this->public.get_shared_secret = (status_t (*)(diffie_hellman_t *, chunk_t *)) get_shared_secret;
359 this->public.set_other_public_value = (status_t (*)(diffie_hellman_t *, chunk_t )) set_other_public_value;
360 this->public.get_other_public_value = (status_t (*)(diffie_hellman_t *, chunk_t *)) get_other_public_value;
361 this->public.get_my_public_value = (status_t (*)(diffie_hellman_t *, chunk_t *)) get_my_public_value;
362 this->public.destroy = (status_t (*)(diffie_hellman_t *)) destroy;
363
364 /* private functions */
365 this->set_modulus = set_modulus;
366 this->compute_public_value = compute_public_value;
367 this->compute_shared_secret = compute_shared_secret;
368
369 /* private variables */
370 this->dh_group_number = dh_group_number;
371
372 this->gmp_helper = gmp_helper_create();
373
374 if (this->gmp_helper == NULL)
375 {
376 allocator_free(this);
377 return NULL;
378 }
379
380 /* set this->modulus */
381 if (this->set_modulus(this) != SUCCESS)
382 {
383 this->gmp_helper->destroy(this->gmp_helper);
384 allocator_free(this);
385 return NULL;
386 }
387
388
389 if (this->gmp_helper->init_prime(this->gmp_helper,&(this->my_prime),10) != SUCCESS)
390 {
391 this->gmp_helper->destroy(this->gmp_helper);
392 allocator_free(this);
393 return NULL;
394 }
395 this->my_public_value_is_computed = FALSE;
396 this->shared_secret_is_computed = FALSE;
397 this->modulus_length = 0;
398
399 return &(this->public);
400 }