Streamlined DRBG and MGF1 debug output
[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_drbg.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 * True Random Generator
124 */
125 rng_t *entropy;
126
127 /**
128 * Deterministic Random Bit Generator
129 */
130 ntru_drbg_t *drbg;
131 };
132
133 METHOD(diffie_hellman_t, get_my_public_value, void,
134 private_ntru_ke_t *this, chunk_t *value)
135 {
136 uint16_t pub_key_len, priv_key_len;
137
138 *value = chunk_empty;
139
140 if (this->responder)
141 {
142 if (this->ciphertext.len)
143 {
144 *value = chunk_clone(this->ciphertext);
145 }
146 }
147 else
148 {
149 if (this->pub_key.len == 0)
150 {
151 /* determine the NTRU public and private key sizes */
152 if (ntru_crypto_ntru_encrypt_keygen(this->drbg, this->param_set->id,
153 &pub_key_len, NULL,
154 &priv_key_len, NULL) != NTRU_OK)
155 {
156 DBG1(DBG_LIB, "error determining NTRU public and private key "
157 "sizes");
158 return;
159 }
160 this->pub_key = chunk_alloc(pub_key_len);
161 this->priv_key = chunk_alloc(priv_key_len);
162
163 /* generate a random NTRU public/private key pair */
164 if (ntru_crypto_ntru_encrypt_keygen(this->drbg, this->param_set->id,
165 &pub_key_len, this->pub_key.ptr,
166 &priv_key_len, this->priv_key.ptr) != NTRU_OK)
167 {
168 DBG1(DBG_LIB, "NTRU keypair generation failed");
169 chunk_free(&this->priv_key);
170 chunk_free(&this->pub_key);
171 return;
172 }
173 DBG3(DBG_LIB, "NTRU public key: %B", &this->pub_key);
174 DBG4(DBG_LIB, "NTRU private key: %B", &this->priv_key);
175 }
176 *value = chunk_clone(this->pub_key);
177 }
178 }
179
180 METHOD(diffie_hellman_t, get_shared_secret, status_t,
181 private_ntru_ke_t *this, chunk_t *secret)
182 {
183 if (!this->computed || !this->shared_secret.len)
184 {
185 *secret = chunk_empty;
186 return FAILED;
187 }
188 *secret = chunk_clone(this->shared_secret);
189
190 return SUCCESS;
191 }
192
193
194 METHOD(diffie_hellman_t, set_other_public_value, void,
195 private_ntru_ke_t *this, chunk_t value)
196 {
197 u_int16_t plaintext_len, ciphertext_len;
198
199 if (this->priv_key.len)
200 {
201 /* initiator decrypting shared secret */
202 if (value.len == 0)
203 {
204 DBG1(DBG_LIB, "empty NTRU ciphertext");
205 return;
206 }
207 this->ciphertext = chunk_clone(value);
208 DBG3(DBG_LIB, "NTRU ciphertext: %B", &this->ciphertext);
209
210 /* determine the size of the maximum plaintext */
211 if (ntru_crypto_ntru_decrypt(this->priv_key.len, this->priv_key.ptr,
212 this->ciphertext.len, this->ciphertext.ptr,
213 &plaintext_len, NULL) != NTRU_OK)
214 {
215 DBG1(DBG_LIB, "error determining maximum plaintext size");
216 return;
217 }
218 this->shared_secret = chunk_alloc(plaintext_len);
219
220 /* decrypt the shared secret */
221 if (ntru_crypto_ntru_decrypt(this->priv_key.len, this->priv_key.ptr,
222 this->ciphertext.len, this->ciphertext.ptr,
223 &plaintext_len, this->shared_secret.ptr) != NTRU_OK)
224 {
225 DBG1(DBG_LIB, "NTRU decryption of shared secret failed");
226 chunk_free(&this->shared_secret);
227 return;
228 }
229 this->shared_secret.len = plaintext_len;
230 this->computed = TRUE;
231 }
232 else
233 {
234 /* responder generating and encrypting the shared secret */
235 this->responder = TRUE;
236
237 /* check the NTRU public key format */
238 if (value.len < 5 || value.ptr[0] != 1 || value.ptr[1] != 3)
239 {
240 DBG1(DBG_LIB, "received NTRU public key with invalid header");
241 return;
242 }
243 if (!memeq(value.ptr + 2, this->param_set->oid, 3))
244 {
245 DBG1(DBG_LIB, "received NTRU public key with wrong OID");
246 return;
247 }
248 this->pub_key = chunk_clone(value);
249
250 /* shared secret size is chosen as twice the cryptographical strength */
251 this->shared_secret = chunk_alloc(2 * this->strength / BITS_PER_BYTE);
252
253 /* generate the random shared secret */
254 if (!this->drbg->generate(this->drbg, this->strength,
255 this->shared_secret.len, this->shared_secret.ptr))
256 {
257 DBG1(DBG_LIB, "generation of shared secret failed");
258 chunk_free(&this->shared_secret);
259 return;
260 }
261 this->computed = TRUE;
262
263 /* determine the size of the ciphertext */
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, NULL) != NTRU_OK)
268 {
269 DBG1(DBG_LIB, "error determining ciphertext size");
270 return;
271 }
272 this->ciphertext = chunk_alloc(ciphertext_len);
273
274 /* encrypt the shared secret */
275 if (ntru_crypto_ntru_encrypt(this->drbg,
276 this->pub_key.len, this->pub_key.ptr,
277 this->shared_secret.len, this->shared_secret.ptr,
278 &ciphertext_len, this->ciphertext.ptr) != NTRU_OK)
279 {
280 DBG1(DBG_LIB, "NTRU encryption of shared secret failed");
281 chunk_free(&this->ciphertext);
282 return;
283 }
284 DBG3(DBG_LIB, "NTRU ciphertext: %B", &this->ciphertext);
285 }
286 }
287
288 METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
289 private_ntru_ke_t *this)
290 {
291 return this->group;
292 }
293
294 METHOD(diffie_hellman_t, destroy, void,
295 private_ntru_ke_t *this)
296 {
297 this->drbg->destroy(this->drbg);
298 this->entropy->destroy(this->entropy);
299 chunk_free(&this->pub_key);
300 chunk_free(&this->ciphertext);
301 chunk_clear(&this->priv_key);
302 chunk_clear(&this->shared_secret);
303 free(this);
304 }
305
306 /*
307 * Described in header.
308 */
309 ntru_ke_t *ntru_ke_create(diffie_hellman_group_t group, chunk_t g, chunk_t p)
310 {
311 private_ntru_ke_t *this;
312 param_set_t *param_sets, *param_set;
313 rng_t *entropy;
314 ntru_drbg_t *drbg;
315 char *parameter_set;
316 u_int32_t strength;
317
318 parameter_set = lib->settings->get_str(lib->settings,
319 "libstrongswan.plugins.ntru.parameter_set", "optimum");
320
321 if (streq(parameter_set, "x9_98_speed"))
322 {
323 param_sets = param_sets_x9_98_speed;
324 }
325 else if (streq(parameter_set, "x9_98_bandwidth"))
326 {
327 param_sets = param_sets_x9_98_bandwidth;
328 }
329 else if (streq(parameter_set, "x9_98_balance"))
330 {
331 param_sets = param_sets_x9_98_balance;
332 }
333 else
334 {
335 param_sets = param_sets_optimum;
336 }
337
338 switch (group)
339 {
340 case NTRU_112_BIT:
341 strength = 112;
342 param_set = &param_sets[0];
343 break;
344 case NTRU_128_BIT:
345 strength = 128;
346 param_set = &param_sets[1];
347 break;
348 case NTRU_192_BIT:
349 strength = 192;
350 param_set = &param_sets[2];
351 break;
352 case NTRU_256_BIT:
353 strength = 256;
354 param_set = &param_sets[3];
355 break;
356 default:
357 return NULL;
358 }
359 DBG1(DBG_LIB, "%u bit %s NTRU parameter set %s selected", strength,
360 parameter_set, param_set->name);
361
362 entropy = lib->crypto->create_rng(lib->crypto, RNG_TRUE);
363 if (!entropy)
364 {
365 DBG1(DBG_LIB, "could not attach entropy source for DRBG");
366 return NULL;
367 }
368
369 drbg = ntru_drbg_create(strength, chunk_from_str("IKE NTRU-KE"), entropy);
370 if (!drbg)
371 {
372 DBG1(DBG_LIB, "could not instantiate DRBG at %u bit security", strength);
373 entropy->destroy(entropy);
374 return NULL;
375 }
376
377 INIT(this,
378 .public = {
379 .dh = {
380 .get_shared_secret = _get_shared_secret,
381 .set_other_public_value = _set_other_public_value,
382 .get_my_public_value = _get_my_public_value,
383 .get_dh_group = _get_dh_group,
384 .destroy = _destroy,
385 },
386 },
387 .group = group,
388 .param_set = param_set,
389 .strength = strength,
390 .entropy = entropy,
391 .drbg = drbg,
392 );
393
394 return &this->public;
395 }
396