diffie-hellman: Use bool instead of status_t as get_shared_secret() return value
[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 <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 diffie_hellman_group_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 ntru_public_key_t *pubkey;
75
76 /**
77 * NTRU Private Key
78 */
79 ntru_private_key_t *privkey;
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 *value = chunk_empty;
116
117 if (this->responder)
118 {
119 if (this->ciphertext.len)
120 {
121 *value = chunk_clone(this->ciphertext);
122 }
123 }
124 else
125 {
126 if (!this->pubkey)
127 {
128 /* generate a random NTRU public/private key pair */
129 this->privkey = ntru_private_key_create(this->drbg, this->param_set);
130 if (!this->privkey)
131 {
132 DBG1(DBG_LIB, "NTRU keypair generation failed");
133 return;
134 }
135 this->pubkey = this->privkey->get_public_key(this->privkey);
136 }
137 *value = chunk_clone(this->pubkey->get_encoding(this->pubkey));
138 DBG3(DBG_LIB, "NTRU public key: %B", value);
139 }
140 }
141
142 METHOD(diffie_hellman_t, get_shared_secret, bool,
143 private_ntru_ke_t *this, chunk_t *secret)
144 {
145 if (!this->computed || !this->shared_secret.len)
146 {
147 *secret = chunk_empty;
148 return FALSE;
149 }
150 *secret = chunk_clone(this->shared_secret);
151
152 return TRUE;
153 }
154
155
156 METHOD(diffie_hellman_t, set_other_public_value, void,
157 private_ntru_ke_t *this, chunk_t value)
158 {
159 if (this->privkey)
160 {
161 /* initiator decrypting shared secret */
162 if (value.len == 0)
163 {
164 DBG1(DBG_LIB, "empty NTRU ciphertext");
165 return;
166 }
167 DBG3(DBG_LIB, "NTRU ciphertext: %B", &value);
168
169 /* decrypt the shared secret */
170 if (!this->privkey->decrypt(this->privkey, value, &this->shared_secret))
171 {
172 DBG1(DBG_LIB, "NTRU decryption of shared secret failed");
173 return;
174 }
175 this->computed = TRUE;
176 }
177 else
178 {
179 ntru_public_key_t *pubkey;
180
181 /* responder generating and encrypting the shared secret */
182 this->responder = TRUE;
183
184 DBG3(DBG_LIB, "NTRU public key: %B", &value);
185 pubkey = ntru_public_key_create_from_data(this->drbg, value);
186 if (!pubkey)
187 {
188 return;
189 }
190 if (pubkey->get_id(pubkey) != this->param_set->id)
191 {
192 DBG1(DBG_LIB, "received NTRU public key with wrong OUI");
193 pubkey->destroy(pubkey);
194 return;
195 }
196 this->pubkey = pubkey;
197
198 /* shared secret size is chosen as twice the cryptographical strength */
199 this->shared_secret = chunk_alloc(2 * this->strength / BITS_PER_BYTE);
200
201 /* generate the random shared secret */
202 if (!this->drbg->generate(this->drbg, this->strength,
203 this->shared_secret.len, this->shared_secret.ptr))
204 {
205 DBG1(DBG_LIB, "generation of shared secret failed");
206 chunk_free(&this->shared_secret);
207 return;
208 }
209 this->computed = TRUE;
210
211 /* encrypt the shared secret */
212 if (!pubkey->encrypt(pubkey, this->shared_secret, &this->ciphertext))
213 {
214 DBG1(DBG_LIB, "NTRU encryption of shared secret failed");
215 return;
216 }
217 DBG3(DBG_LIB, "NTRU ciphertext: %B", &this->ciphertext);
218 }
219 }
220
221 METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
222 private_ntru_ke_t *this)
223 {
224 return this->group;
225 }
226
227 METHOD(diffie_hellman_t, destroy, void,
228 private_ntru_ke_t *this)
229 {
230 DESTROY_IF(this->privkey);
231 DESTROY_IF(this->pubkey);
232 this->drbg->destroy(this->drbg);
233 this->entropy->destroy(this->entropy);
234 chunk_free(&this->ciphertext);
235 chunk_clear(&this->shared_secret);
236 free(this);
237 }
238
239 /*
240 * Described in header.
241 */
242 ntru_ke_t *ntru_ke_create(diffie_hellman_group_t group, chunk_t g, chunk_t p)
243 {
244 private_ntru_ke_t *this;
245 ntru_param_set_id_t *param_sets, param_set_id;
246 rng_t *entropy;
247 ntru_drbg_t *drbg;
248 char *parameter_set;
249 u_int32_t strength;
250
251 parameter_set = lib->settings->get_str(lib->settings,
252 "%s.plugins.ntru.parameter_set", "optimum", lib->ns);
253
254 if (streq(parameter_set, "x9_98_speed"))
255 {
256 param_sets = param_sets_x9_98_speed;
257 }
258 else if (streq(parameter_set, "x9_98_bandwidth"))
259 {
260 param_sets = param_sets_x9_98_bandwidth;
261 }
262 else if (streq(parameter_set, "x9_98_balance"))
263 {
264 param_sets = param_sets_x9_98_balance;
265 }
266 else
267 {
268 param_sets = param_sets_optimum;
269 }
270
271 switch (group)
272 {
273 case NTRU_112_BIT:
274 strength = 112;
275 param_set_id = param_sets[0];
276 break;
277 case NTRU_128_BIT:
278 strength = 128;
279 param_set_id = param_sets[1];
280 break;
281 case NTRU_192_BIT:
282 strength = 192;
283 param_set_id = param_sets[2];
284 break;
285 case NTRU_256_BIT:
286 strength = 256;
287 param_set_id = param_sets[3];
288 break;
289 default:
290 return NULL;
291 }
292 DBG1(DBG_LIB, "%u bit %s NTRU parameter set %N selected", strength,
293 parameter_set, ntru_param_set_id_names, param_set_id);
294
295 entropy = lib->crypto->create_rng(lib->crypto, RNG_TRUE);
296 if (!entropy)
297 {
298 DBG1(DBG_LIB, "could not attach entropy source for DRBG");
299 return NULL;
300 }
301
302 drbg = ntru_drbg_create(strength, chunk_from_str("IKE NTRU-KE"), entropy);
303 if (!drbg)
304 {
305 DBG1(DBG_LIB, "could not instantiate DRBG at %u bit security", strength);
306 entropy->destroy(entropy);
307 return NULL;
308 }
309
310 INIT(this,
311 .public = {
312 .dh = {
313 .get_shared_secret = _get_shared_secret,
314 .set_other_public_value = _set_other_public_value,
315 .get_my_public_value = _get_my_public_value,
316 .get_dh_group = _get_dh_group,
317 .destroy = _destroy,
318 },
319 },
320 .group = group,
321 .param_set = ntru_param_set_get_by_id(param_set_id),
322 .strength = strength,
323 .entropy = entropy,
324 .drbg = drbg,
325 );
326
327 return &this->public;
328 }
329