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