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