Any of the four NTRU parameter sets can be selected
[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 this->ciphertext = chunk_clone(value);
197 DBG3(DBG_LIB, "NTRU ciphertext: %B", &this->ciphertext);
198
199 /* determine the size of the maximum plaintext */
200 if (ntru_crypto_ntru_decrypt(this->priv_key.len, this->priv_key.ptr,
201 this->ciphertext.len, this->ciphertext.ptr,
202 &plaintext_len, NULL) != NTRU_OK)
203 {
204 DBG1(DBG_LIB, "error determining maximum plaintext size");
205 return;
206 }
207 this->shared_secret = chunk_alloc(plaintext_len);
208
209 /* decrypt the shared secret */
210 if (ntru_crypto_ntru_decrypt(this->priv_key.len, this->priv_key.ptr,
211 this->ciphertext.len, this->ciphertext.ptr,
212 &plaintext_len, this->shared_secret.ptr) != NTRU_OK)
213 {
214 DBG1(DBG_LIB, "NTRU decryption of shared secret failed");
215 chunk_free(&this->shared_secret);
216 return;
217 }
218 this->shared_secret.len = plaintext_len;
219 this->computed = TRUE;
220 }
221 else
222 {
223 /* responder generating and encrypting the shared secret */
224 this->responder = TRUE;
225
226 /* check the NTRU public key format */
227 if (value.len < 5 || value.ptr[0] != 1 || value.ptr[1] != 3)
228 {
229 DBG1(DBG_LIB, "received NTRU public key with invalid header");
230 return;
231 }
232 if (!memeq(value.ptr + 2, this->param_set->oid, 3))
233 {
234 DBG1(DBG_LIB, "received NTRU public key with wrong OID");
235 return;
236 }
237 this->pub_key = chunk_clone(value);
238
239 /* shared secret size is chosen as twice the cryptographical strength */
240 this->shared_secret = chunk_alloc(2 * this->strength / BITS_PER_BYTE);
241
242 /* generate the random shared secret */
243 if (ntru_crypto_drbg_generate(this->drbg, this->strength,
244 this->shared_secret.len, this->shared_secret.ptr) != DRBG_OK)
245 {
246 DBG1(DBG_LIB, "generation of shared secret failed");
247 chunk_free(&this->shared_secret);
248 return;
249 }
250 this->computed = TRUE;
251
252 /* determine the size of the ciphertext */
253 if (ntru_crypto_ntru_encrypt(this->drbg,
254 this->pub_key.len, this->pub_key.ptr,
255 this->shared_secret.len, this->shared_secret.ptr,
256 &ciphertext_len, NULL) != NTRU_OK)
257 {
258 DBG1(DBG_LIB, "error determining ciphertext size");
259 return;
260 }
261 this->ciphertext = chunk_alloc(ciphertext_len);
262
263 /* encrypt the shared secret */
264 if (ntru_crypto_ntru_encrypt(this->drbg,
265 this->pub_key.len, this->pub_key.ptr,
266 this->shared_secret.len, this->shared_secret.ptr,
267 &ciphertext_len, this->ciphertext.ptr) != NTRU_OK)
268 {
269 DBG1(DBG_LIB, "NTRU encryption of shared secret failed");
270 chunk_free(&this->ciphertext);
271 return;
272 }
273 DBG3(DBG_LIB, "NTRU ciphertext: %B", &this->ciphertext);
274 }
275 }
276
277 METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
278 private_ntru_ke_t *this)
279 {
280 return this->group;
281 }
282
283 METHOD(diffie_hellman_t, destroy, void,
284 private_ntru_ke_t *this)
285 {
286 if (ntru_crypto_drbg_uninstantiate(this->drbg) != DRBG_OK)
287 {
288 DBG1(DBG_LIB, "error uninstantiating DRBG");
289 }
290 chunk_free(&this->pub_key);
291 chunk_free(&this->ciphertext);
292 chunk_clear(&this->priv_key);
293 chunk_clear(&this->shared_secret);
294 free(this);
295 }
296
297 /*
298 * Described in header.
299 */
300 ntru_ke_t *ntru_ke_create(diffie_hellman_group_t group, chunk_t g, chunk_t p)
301 {
302 private_ntru_ke_t *this;
303 char personalization_str[] = "strongSwan NTRU-KE";
304 param_set_t *param_sets, *param_set;
305 DRBG_HANDLE drbg;
306 char *parameter_set;
307 u_int32_t strength;
308
309 parameter_set = lib->settings->get_str(lib->settings,
310 "libstrongswan.plugins.ntru.parameter_set", "optimum");
311
312 if (streq(parameter_set, "x9_98_speed"))
313 {
314 param_sets = param_sets_x9_98_speed;
315 }
316 else if (streq(parameter_set, "x9_98_bandwidth"))
317 {
318 param_sets = param_sets_x9_98_bandwidth;
319 }
320 else if (streq(parameter_set, "x9_98_balance"))
321 {
322 param_sets = param_sets_x9_98_balance;
323 }
324 else
325 {
326 param_sets = param_sets_optimum;
327 }
328
329 switch (group)
330 {
331 case NTRU_112_BIT:
332 strength = 112;
333 param_set = &param_sets[0];
334 break;
335 case NTRU_128_BIT:
336 strength = 128;
337 param_set = &param_sets[1];
338 break;
339 case NTRU_192_BIT:
340 strength = 192;
341 param_set = &param_sets[2];
342 break;
343 case NTRU_256_BIT:
344 strength = 256;
345 param_set = &param_sets[3];
346 break;
347 default:
348 return NULL;
349 }
350 DBG1(DBG_LIB, "%u bit %s NTRU parameter set %s selected", strength,
351 parameter_set, param_set->name);
352
353 if (ntru_crypto_drbg_instantiate(strength,
354 personalization_str, strlen(personalization_str),
355 (ENTROPY_FN) &ntru_plugin_get_entropy, &drbg) != DRBG_OK)
356 {
357 DBG1(DBG_LIB, "error instantiating DRBG at %u bit security", strength);
358 return NULL;
359 }
360
361 INIT(this,
362 .public = {
363 .dh = {
364 .get_shared_secret = _get_shared_secret,
365 .set_other_public_value = _set_other_public_value,
366 .get_my_public_value = _get_my_public_value,
367 .get_dh_group = _get_dh_group,
368 .destroy = _destroy,
369 },
370 },
371 .group = group,
372 .param_set = param_set,
373 .strength = strength,
374 .drbg = drbg,
375 );
376
377 return &this->public;
378 }
379