14bd0cd87c855441a8d2a726707547132df29bc9
[strongswan.git] / src / libstrongswan / plugins / ntru / ntru_ke.c
1 /*
2 * Copyright (C) 2013-2014 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "ntru_ke.h"
17 #include "ntru_drbg.h"
18 #include "ntru_param_set.h"
19
20 #include "ntru_crypto/ntru_crypto.h"
21
22 #include <crypto/diffie_hellman.h>
23 #include <utils/debug.h>
24
25 typedef struct private_ntru_ke_t private_ntru_ke_t;
26
27 /* Best bandwidth and speed, no X9.98 compatibility */
28 static ntru_param_set_id_t param_sets_optimum[] = {
29 NTRU_EES401EP2, NTRU_EES439EP1, NTRU_EES593EP1, NTRU_EES743EP1
30 };
31
32 /* X9.98/IEEE 1363.1 parameter sets for best speed */
33 static ntru_param_set_id_t param_sets_x9_98_speed[] = {
34 NTRU_EES659EP1, NTRU_EES761EP1, NTRU_EES1087EP1, NTRU_EES1499EP1
35 };
36
37 /* X9.98/IEEE 1363.1 parameter sets for best bandwidth (smallest size) */
38 static ntru_param_set_id_t param_sets_x9_98_bandwidth[] = {
39 NTRU_EES401EP1, NTRU_EES449EP1, NTRU_EES677EP1, NTRU_EES1087EP2
40 };
41
42 /* X9.98/IEEE 1363.1 parameter sets balancing speed and bandwidth */
43 static ntru_param_set_id_t param_sets_x9_98_balance[] = {
44 NTRU_EES541EP1, NTRU_EES613EP1, NTRU_EES887EP1, NTRU_EES1171EP1
45 };
46
47 /**
48 * Private data of an ntru_ke_t object.
49 */
50 struct private_ntru_ke_t {
51 /**
52 * Public ntru_ke_t interface.
53 */
54 ntru_ke_t public;
55
56 /**
57 * Diffie Hellman group number.
58 */
59 u_int16_t group;
60
61 /**
62 * NTRU Parameter Set
63 */
64 ntru_param_set_t *param_set;
65
66 /**
67 * Cryptographical strength in bits of the NTRU Parameter Set
68 */
69 u_int32_t strength;
70
71 /**
72 * NTRU Public Key
73 */
74 chunk_t pub_key;
75
76 /**
77 * NTRU Private Key
78 */
79 chunk_t priv_key;
80
81 /**
82 * NTRU encrypted shared secret
83 */
84 chunk_t ciphertext;
85
86 /**
87 * Shared secret
88 */
89 chunk_t shared_secret;
90
91 /**
92 * True if peer is responder
93 */
94 bool responder;
95
96 /**
97 * True if shared secret is computed
98 */
99 bool computed;
100
101 /**
102 * True Random Generator
103 */
104 rng_t *entropy;
105
106 /**
107 * Deterministic Random Bit Generator
108 */
109 ntru_drbg_t *drbg;
110 };
111
112 METHOD(diffie_hellman_t, get_my_public_value, void,
113 private_ntru_ke_t *this, chunk_t *value)
114 {
115 uint16_t pub_key_len, priv_key_len;
116
117 *value = chunk_empty;
118
119 if (this->responder)
120 {
121 if (this->ciphertext.len)
122 {
123 *value = chunk_clone(this->ciphertext);
124 }
125 }
126 else
127 {
128 if (this->pub_key.len == 0)
129 {
130 /* determine the NTRU public and private key sizes */
131 if (ntru_crypto_ntru_encrypt_keygen(this->drbg, this->param_set->id,
132 &pub_key_len, NULL,
133 &priv_key_len, NULL) != NTRU_OK)
134 {
135 DBG1(DBG_LIB, "error determining NTRU public and private key "
136 "sizes");
137 return;
138 }
139 this->pub_key = chunk_alloc(pub_key_len);
140 this->priv_key = chunk_alloc(priv_key_len);
141
142 /* generate a random NTRU public/private key pair */
143 if (ntru_crypto_ntru_encrypt_keygen(this->drbg, this->param_set->id,
144 &pub_key_len, this->pub_key.ptr,
145 &priv_key_len, this->priv_key.ptr) != NTRU_OK)
146 {
147 DBG1(DBG_LIB, "NTRU keypair generation failed");
148 chunk_free(&this->priv_key);
149 chunk_free(&this->pub_key);
150 return;
151 }
152 DBG3(DBG_LIB, "NTRU public key: %B", &this->pub_key);
153 DBG4(DBG_LIB, "NTRU private key: %B", &this->priv_key);
154 }
155 *value = chunk_clone(this->pub_key);
156 }
157 }
158
159 METHOD(diffie_hellman_t, get_shared_secret, status_t,
160 private_ntru_ke_t *this, chunk_t *secret)
161 {
162 if (!this->computed || !this->shared_secret.len)
163 {
164 *secret = chunk_empty;
165 return FAILED;
166 }
167 *secret = chunk_clone(this->shared_secret);
168
169 return SUCCESS;
170 }
171
172
173 METHOD(diffie_hellman_t, set_other_public_value, void,
174 private_ntru_ke_t *this, chunk_t value)
175 {
176 u_int16_t plaintext_len, ciphertext_len;
177
178 if (this->priv_key.len)
179 {
180 /* initiator decrypting shared secret */
181 if (value.len == 0)
182 {
183 DBG1(DBG_LIB, "empty NTRU ciphertext");
184 return;
185 }
186 this->ciphertext = chunk_clone(value);
187 DBG3(DBG_LIB, "NTRU ciphertext: %B", &this->ciphertext);
188
189 /* determine the size of the maximum plaintext */
190 if (ntru_crypto_ntru_decrypt(this->priv_key.len, this->priv_key.ptr,
191 this->ciphertext.len, this->ciphertext.ptr,
192 &plaintext_len, NULL) != NTRU_OK)
193 {
194 DBG1(DBG_LIB, "error determining maximum plaintext size");
195 return;
196 }
197 this->shared_secret = chunk_alloc(plaintext_len);
198
199 /* decrypt the shared secret */
200 if (ntru_crypto_ntru_decrypt(this->priv_key.len, this->priv_key.ptr,
201 this->ciphertext.len, this->ciphertext.ptr,
202 &plaintext_len, this->shared_secret.ptr) != NTRU_OK)
203 {
204 DBG1(DBG_LIB, "NTRU decryption of shared secret failed");
205 chunk_free(&this->shared_secret);
206 return;
207 }
208 this->shared_secret.len = plaintext_len;
209 this->computed = TRUE;
210 }
211 else
212 {
213 /* responder generating and encrypting the shared secret */
214 this->responder = TRUE;
215
216 /* check the NTRU public key format */
217 if (value.len < 5 || value.ptr[0] != 1 || value.ptr[1] != 3)
218 {
219 DBG1(DBG_LIB, "received NTRU public key with invalid header");
220 return;
221 }
222 if (!memeq(value.ptr + 2, this->param_set->oid, 3))
223 {
224 DBG1(DBG_LIB, "received NTRU public key with wrong OID");
225 return;
226 }
227 this->pub_key = chunk_clone(value);
228
229 /* shared secret size is chosen as twice the cryptographical strength */
230 this->shared_secret = chunk_alloc(2 * this->strength / BITS_PER_BYTE);
231
232 /* generate the random shared secret */
233 if (!this->drbg->generate(this->drbg, this->strength,
234 this->shared_secret.len, this->shared_secret.ptr))
235 {
236 DBG1(DBG_LIB, "generation of shared secret failed");
237 chunk_free(&this->shared_secret);
238 return;
239 }
240 this->computed = TRUE;
241
242 /* determine the size of the ciphertext */
243 if (ntru_crypto_ntru_encrypt(this->drbg,
244 this->pub_key.len, this->pub_key.ptr,
245 this->shared_secret.len, this->shared_secret.ptr,
246 &ciphertext_len, NULL) != NTRU_OK)
247 {
248 DBG1(DBG_LIB, "error determining ciphertext size");
249 return;
250 }
251 this->ciphertext = chunk_alloc(ciphertext_len);
252
253 /* encrypt the shared secret */
254 if (ntru_crypto_ntru_encrypt(this->drbg,
255 this->pub_key.len, this->pub_key.ptr,
256 this->shared_secret.len, this->shared_secret.ptr,
257 &ciphertext_len, this->ciphertext.ptr) != NTRU_OK)
258 {
259 DBG1(DBG_LIB, "NTRU encryption of shared secret failed");
260 chunk_free(&this->ciphertext);
261 return;
262 }
263 DBG3(DBG_LIB, "NTRU ciphertext: %B", &this->ciphertext);
264 }
265 }
266
267 METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
268 private_ntru_ke_t *this)
269 {
270 return this->group;
271 }
272
273 METHOD(diffie_hellman_t, destroy, void,
274 private_ntru_ke_t *this)
275 {
276 this->drbg->destroy(this->drbg);
277 this->entropy->destroy(this->entropy);
278 chunk_free(&this->pub_key);
279 chunk_free(&this->ciphertext);
280 chunk_clear(&this->priv_key);
281 chunk_clear(&this->shared_secret);
282 free(this);
283 }
284
285 /*
286 * Described in header.
287 */
288 ntru_ke_t *ntru_ke_create(diffie_hellman_group_t group, chunk_t g, chunk_t p)
289 {
290 private_ntru_ke_t *this;
291 ntru_param_set_id_t *param_sets, param_set_id;
292 rng_t *entropy;
293 ntru_drbg_t *drbg;
294 char *parameter_set;
295 u_int32_t strength;
296
297 parameter_set = lib->settings->get_str(lib->settings,
298 "%s.plugins.ntru.parameter_set", "optimum", lib->ns);
299
300 if (streq(parameter_set, "x9_98_speed"))
301 {
302 param_sets = param_sets_x9_98_speed;
303 }
304 else if (streq(parameter_set, "x9_98_bandwidth"))
305 {
306 param_sets = param_sets_x9_98_bandwidth;
307 }
308 else if (streq(parameter_set, "x9_98_balance"))
309 {
310 param_sets = param_sets_x9_98_balance;
311 }
312 else
313 {
314 param_sets = param_sets_optimum;
315 }
316
317 switch (group)
318 {
319 case NTRU_112_BIT:
320 strength = 112;
321 param_set_id = param_sets[0];
322 break;
323 case NTRU_128_BIT:
324 strength = 128;
325 param_set_id = param_sets[1];
326 break;
327 case NTRU_192_BIT:
328 strength = 192;
329 param_set_id = param_sets[2];
330 break;
331 case NTRU_256_BIT:
332 strength = 256;
333 param_set_id = param_sets[3];
334 break;
335 default:
336 return NULL;
337 }
338 DBG1(DBG_LIB, "%u bit %s NTRU parameter set %N selected", strength,
339 parameter_set, ntru_param_set_id_names, param_set_id);
340
341 entropy = lib->crypto->create_rng(lib->crypto, RNG_TRUE);
342 if (!entropy)
343 {
344 DBG1(DBG_LIB, "could not attach entropy source for DRBG");
345 return NULL;
346 }
347
348 drbg = ntru_drbg_create(strength, chunk_from_str("IKE NTRU-KE"), entropy);
349 if (!drbg)
350 {
351 DBG1(DBG_LIB, "could not instantiate DRBG at %u bit security", strength);
352 entropy->destroy(entropy);
353 return NULL;
354 }
355
356 INIT(this,
357 .public = {
358 .dh = {
359 .get_shared_secret = _get_shared_secret,
360 .set_other_public_value = _set_other_public_value,
361 .get_my_public_value = _get_my_public_value,
362 .get_dh_group = _get_dh_group,
363 .destroy = _destroy,
364 },
365 },
366 .group = group,
367 .param_set = ntru_param_set_get_by_id(param_set_id),
368 .strength = strength,
369 .entropy = entropy,
370 .drbg = drbg,
371 );
372
373 return &this->public;
374 }
375