]>
Commit | Line | Data |
---|---|---|
146ad86b | 1 | /* |
ac17ca1a | 2 | * Copyright (C) 2013-2014 Andreas Steffen |
146ad86b AS |
3 | * |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms of the GNU General Public License as published by the | |
6 | * Free Software Foundation; either version 2 of the License, or (at your | |
7 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, but | |
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
11 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 | * for more details. | |
13 | */ | |
14 | ||
15 | #include "ntru_ke.h" | |
7befce8c | 16 | #include "ntru_param_set.h" |
337f0c8a AS |
17 | #include "ntru_private_key.h" |
18 | #include "ntru_public_key.h" | |
146ad86b | 19 | |
146ad86b | 20 | #include <crypto/diffie_hellman.h> |
6d3a743d | 21 | #include <crypto/drbgs/drbg.h> |
146ad86b AS |
22 | #include <utils/debug.h> |
23 | ||
24 | typedef struct private_ntru_ke_t private_ntru_ke_t; | |
802eaf37 AS |
25 | |
26 | /* Best bandwidth and speed, no X9.98 compatibility */ | |
b8070e2c | 27 | static const ntru_param_set_id_t param_sets_optimum[] = { |
ac17ca1a | 28 | NTRU_EES401EP2, NTRU_EES439EP1, NTRU_EES593EP1, NTRU_EES743EP1 |
802eaf37 AS |
29 | }; |
30 | ||
31 | /* X9.98/IEEE 1363.1 parameter sets for best speed */ | |
b8070e2c | 32 | static const ntru_param_set_id_t param_sets_x9_98_speed[] = { |
ac17ca1a | 33 | NTRU_EES659EP1, NTRU_EES761EP1, NTRU_EES1087EP1, NTRU_EES1499EP1 |
802eaf37 AS |
34 | }; |
35 | ||
36 | /* X9.98/IEEE 1363.1 parameter sets for best bandwidth (smallest size) */ | |
b8070e2c | 37 | static const ntru_param_set_id_t param_sets_x9_98_bandwidth[] = { |
ac17ca1a | 38 | NTRU_EES401EP1, NTRU_EES449EP1, NTRU_EES677EP1, NTRU_EES1087EP2 |
802eaf37 AS |
39 | }; |
40 | ||
41 | /* X9.98/IEEE 1363.1 parameter sets balancing speed and bandwidth */ | |
b8070e2c | 42 | static const ntru_param_set_id_t param_sets_x9_98_balance[] = { |
ac17ca1a | 43 | NTRU_EES541EP1, NTRU_EES613EP1, NTRU_EES887EP1, NTRU_EES1171EP1 |
802eaf37 | 44 | }; |
146ad86b AS |
45 | |
46 | /** | |
47 | * Private data of an ntru_ke_t object. | |
48 | */ | |
49 | struct private_ntru_ke_t { | |
50 | /** | |
51 | * Public ntru_ke_t interface. | |
52 | */ | |
53 | ntru_ke_t public; | |
54 | ||
55 | /** | |
56 | * Diffie Hellman group number. | |
57 | */ | |
e13ef5c4 | 58 | diffie_hellman_group_t group; |
146ad86b AS |
59 | |
60 | /** | |
802eaf37 | 61 | * NTRU Parameter Set |
146ad86b | 62 | */ |
b8070e2c | 63 | const ntru_param_set_t *param_set; |
146ad86b AS |
64 | |
65 | /** | |
66 | * Cryptographical strength in bits of the NTRU Parameter Set | |
67 | */ | |
b12c53ce | 68 | uint32_t strength; |
146ad86b AS |
69 | |
70 | /** | |
71 | * NTRU Public Key | |
72 | */ | |
337f0c8a | 73 | ntru_public_key_t *pubkey; |
146ad86b AS |
74 | |
75 | /** | |
76 | * NTRU Private Key | |
77 | */ | |
337f0c8a AS |
78 | ntru_private_key_t *privkey; |
79 | ||
146ad86b AS |
80 | /** |
81 | * NTRU encrypted shared secret | |
82 | */ | |
83 | chunk_t ciphertext; | |
84 | ||
85 | /** | |
86 | * Shared secret | |
87 | */ | |
88 | chunk_t shared_secret; | |
89 | ||
90 | /** | |
91 | * True if peer is responder | |
92 | */ | |
93 | bool responder; | |
94 | ||
95 | /** | |
96 | * True if shared secret is computed | |
97 | */ | |
98 | bool computed; | |
99 | ||
98c64216 AS |
100 | /** |
101 | * True Random Generator | |
102 | */ | |
103 | rng_t *entropy; | |
104 | ||
146ad86b AS |
105 | /** |
106 | * Deterministic Random Bit Generator | |
107 | */ | |
6d3a743d | 108 | drbg_t *drbg; |
146ad86b AS |
109 | }; |
110 | ||
42431690 | 111 | METHOD(diffie_hellman_t, get_my_public_value, bool, |
146ad86b AS |
112 | private_ntru_ke_t *this, chunk_t *value) |
113 | { | |
146ad86b AS |
114 | *value = chunk_empty; |
115 | ||
116 | if (this->responder) | |
117 | { | |
118 | if (this->ciphertext.len) | |
119 | { | |
120 | *value = chunk_clone(this->ciphertext); | |
121 | } | |
122 | } | |
123 | else | |
124 | { | |
337f0c8a | 125 | if (!this->pubkey) |
146ad86b | 126 | { |
146ad86b | 127 | /* generate a random NTRU public/private key pair */ |
337f0c8a AS |
128 | this->privkey = ntru_private_key_create(this->drbg, this->param_set); |
129 | if (!this->privkey) | |
146ad86b | 130 | { |
a6691450 | 131 | DBG1(DBG_LIB, "NTRU key pair generation failed"); |
42431690 | 132 | return FALSE; |
146ad86b | 133 | } |
337f0c8a | 134 | this->pubkey = this->privkey->get_public_key(this->privkey); |
146ad86b | 135 | } |
22e1aa51 AS |
136 | *value = chunk_clone(this->pubkey->get_encoding(this->pubkey)); |
137 | DBG3(DBG_LIB, "NTRU public key: %B", value); | |
146ad86b | 138 | } |
42431690 | 139 | return TRUE; |
146ad86b AS |
140 | } |
141 | ||
bace1d64 | 142 | METHOD(diffie_hellman_t, get_shared_secret, bool, |
146ad86b AS |
143 | private_ntru_ke_t *this, chunk_t *secret) |
144 | { | |
145 | if (!this->computed || !this->shared_secret.len) | |
146 | { | |
9013973c | 147 | *secret = chunk_empty; |
bace1d64 | 148 | return FALSE; |
146ad86b AS |
149 | } |
150 | *secret = chunk_clone(this->shared_secret); | |
151 | ||
bace1d64 | 152 | return TRUE; |
146ad86b AS |
153 | } |
154 | ||
a777155f | 155 | METHOD(diffie_hellman_t, set_other_public_value, bool, |
146ad86b AS |
156 | private_ntru_ke_t *this, chunk_t value) |
157 | { | |
337f0c8a | 158 | if (this->privkey) |
146ad86b AS |
159 | { |
160 | /* initiator decrypting shared secret */ | |
885e699b AS |
161 | if (value.len == 0) |
162 | { | |
163 | DBG1(DBG_LIB, "empty NTRU ciphertext"); | |
a777155f | 164 | return FALSE; |
885e699b | 165 | } |
337f0c8a | 166 | DBG3(DBG_LIB, "NTRU ciphertext: %B", &value); |
146ad86b AS |
167 | |
168 | /* decrypt the shared secret */ | |
a777155f | 169 | if (!this->privkey->decrypt(this->privkey, value, &this->shared_secret)) |
146ad86b AS |
170 | { |
171 | DBG1(DBG_LIB, "NTRU decryption of shared secret failed"); | |
a777155f | 172 | return FALSE; |
146ad86b | 173 | } |
146ad86b AS |
174 | this->computed = TRUE; |
175 | } | |
176 | else | |
177 | { | |
22e1aa51 AS |
178 | ntru_public_key_t *pubkey; |
179 | ||
146ad86b AS |
180 | /* responder generating and encrypting the shared secret */ |
181 | this->responder = TRUE; | |
802eaf37 | 182 | |
22e1aa51 AS |
183 | DBG3(DBG_LIB, "NTRU public key: %B", &value); |
184 | pubkey = ntru_public_key_create_from_data(this->drbg, value); | |
185 | if (!pubkey) | |
802eaf37 | 186 | { |
a777155f | 187 | return FALSE; |
802eaf37 | 188 | } |
22e1aa51 | 189 | if (pubkey->get_id(pubkey) != this->param_set->id) |
802eaf37 | 190 | { |
22e1aa51 AS |
191 | DBG1(DBG_LIB, "received NTRU public key with wrong OUI"); |
192 | pubkey->destroy(pubkey); | |
a777155f | 193 | return FALSE; |
802eaf37 | 194 | } |
22e1aa51 | 195 | this->pubkey = pubkey; |
146ad86b AS |
196 | |
197 | /* shared secret size is chosen as twice the cryptographical strength */ | |
198 | this->shared_secret = chunk_alloc(2 * this->strength / BITS_PER_BYTE); | |
199 | ||
200 | /* generate the random shared secret */ | |
6d3a743d AS |
201 | if (!this->drbg->generate(this->drbg, this->shared_secret.len, |
202 | this->shared_secret.ptr)) | |
146ad86b AS |
203 | { |
204 | DBG1(DBG_LIB, "generation of shared secret failed"); | |
205 | chunk_free(&this->shared_secret); | |
a777155f | 206 | return FALSE; |
146ad86b | 207 | } |
1f73969e | 208 | this->computed = TRUE; |
146ad86b | 209 | |
146ad86b | 210 | /* encrypt the shared secret */ |
22e1aa51 | 211 | if (!pubkey->encrypt(pubkey, this->shared_secret, &this->ciphertext)) |
146ad86b AS |
212 | { |
213 | DBG1(DBG_LIB, "NTRU encryption of shared secret failed"); | |
a777155f | 214 | return FALSE; |
146ad86b AS |
215 | } |
216 | DBG3(DBG_LIB, "NTRU ciphertext: %B", &this->ciphertext); | |
217 | } | |
a777155f | 218 | return this->computed; |
146ad86b AS |
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 | { | |
337f0c8a AS |
230 | DESTROY_IF(this->privkey); |
231 | DESTROY_IF(this->pubkey); | |
98c64216 | 232 | this->drbg->destroy(this->drbg); |
146ad86b | 233 | chunk_free(&this->ciphertext); |
146ad86b AS |
234 | chunk_clear(&this->shared_secret); |
235 | free(this); | |
236 | } | |
237 | ||
238 | /* | |
239 | * Described in header. | |
240 | */ | |
241 | ntru_ke_t *ntru_ke_create(diffie_hellman_group_t group, chunk_t g, chunk_t p) | |
242 | { | |
243 | private_ntru_ke_t *this; | |
b8070e2c AS |
244 | const ntru_param_set_id_t *param_sets; |
245 | ntru_param_set_id_t param_set_id; | |
98c64216 | 246 | rng_t *entropy; |
6d3a743d | 247 | drbg_t *drbg; |
802eaf37 | 248 | char *parameter_set; |
b12c53ce | 249 | uint32_t strength; |
146ad86b | 250 | |
802eaf37 | 251 | parameter_set = lib->settings->get_str(lib->settings, |
8dc6e716 | 252 | "%s.plugins.ntru.parameter_set", "optimum", lib->ns); |
1f73969e | 253 | |
802eaf37 | 254 | if (streq(parameter_set, "x9_98_speed")) |
1f73969e | 255 | { |
802eaf37 | 256 | param_sets = param_sets_x9_98_speed; |
1f73969e | 257 | } |
802eaf37 | 258 | else if (streq(parameter_set, "x9_98_bandwidth")) |
1f73969e | 259 | { |
802eaf37 | 260 | param_sets = param_sets_x9_98_bandwidth; |
1f73969e | 261 | } |
802eaf37 | 262 | else if (streq(parameter_set, "x9_98_balance")) |
1f73969e | 263 | { |
802eaf37 | 264 | param_sets = param_sets_x9_98_balance; |
1f73969e AS |
265 | } |
266 | else | |
267 | { | |
802eaf37 | 268 | param_sets = param_sets_optimum; |
1f73969e AS |
269 | } |
270 | ||
146ad86b AS |
271 | switch (group) |
272 | { | |
273 | case NTRU_112_BIT: | |
274 | strength = 112; | |
ac17ca1a | 275 | param_set_id = param_sets[0]; |
146ad86b AS |
276 | break; |
277 | case NTRU_128_BIT: | |
278 | strength = 128; | |
ac17ca1a | 279 | param_set_id = param_sets[1]; |
146ad86b AS |
280 | break; |
281 | case NTRU_192_BIT: | |
282 | strength = 192; | |
ac17ca1a | 283 | param_set_id = param_sets[2]; |
146ad86b AS |
284 | break; |
285 | case NTRU_256_BIT: | |
286 | strength = 256; | |
ac17ca1a | 287 | param_set_id = param_sets[3]; |
146ad86b AS |
288 | break; |
289 | default: | |
290 | return NULL; | |
291 | } | |
ac17ca1a AS |
292 | DBG1(DBG_LIB, "%u bit %s NTRU parameter set %N selected", strength, |
293 | parameter_set, ntru_param_set_id_names, param_set_id); | |
146ad86b | 294 | |
11e9d2b8 | 295 | /* entropy will be owned by drbg */ |
98c64216 AS |
296 | entropy = lib->crypto->create_rng(lib->crypto, RNG_TRUE); |
297 | if (!entropy) | |
298 | { | |
299 | DBG1(DBG_LIB, "could not attach entropy source for DRBG"); | |
300 | return NULL; | |
301 | } | |
302 | ||
6d3a743d AS |
303 | drbg = lib->crypto->create_drbg(lib->crypto, DRBG_HMAC_SHA256, strength, |
304 | entropy, chunk_from_str("IKE NTRU-KE")); | |
98c64216 | 305 | if (!drbg) |
a777155f | 306 | { |
98c64216 AS |
307 | DBG1(DBG_LIB, "could not instantiate DRBG at %u bit security", strength); |
308 | entropy->destroy(entropy); | |
a777155f | 309 | return NULL; |
146ad86b | 310 | } |
146ad86b AS |
311 | |
312 | INIT(this, | |
313 | .public = { | |
314 | .dh = { | |
315 | .get_shared_secret = _get_shared_secret, | |
316 | .set_other_public_value = _set_other_public_value, | |
317 | .get_my_public_value = _get_my_public_value, | |
318 | .get_dh_group = _get_dh_group, | |
319 | .destroy = _destroy, | |
320 | }, | |
321 | }, | |
322 | .group = group, | |
ac17ca1a | 323 | .param_set = ntru_param_set_get_by_id(param_set_id), |
146ad86b | 324 | .strength = strength, |
98c64216 | 325 | .entropy = entropy, |
146ad86b AS |
326 | .drbg = drbg, |
327 | ); | |
328 | ||
329 | return &this->public; | |
330 | } |