2ea7c94cd65166aa580a72fcff378705d1a7657e
[strongswan.git] / src / libstrongswan / plugins / wolfssl / wolfssl_aead.c
1 /*
2 * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23 #include "wolfssl_common.h"
24
25 #if (!defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AESCCM))) || \
26 (defined(HAVE_CHACHA) && defined(HAVE_POLY1305))
27
28 #include "wolfssl_aead.h"
29
30 #include <wolfssl/wolfcrypt/aes.h>
31 #include <wolfssl/wolfcrypt/chacha.h>
32 #include <wolfssl/wolfcrypt/chacha20_poly1305.h>
33 #include <crypto/iv/iv_gen_seq.h>
34
35 /** as defined in RFC 4106 */
36 #define IV_LEN 8
37 #define GCM_SALT_LEN 4
38 #define GCM_NONCE_LEN (GCM_SALT_LEN + IV_LEN)
39
40 #define CCM_SALT_LEN 3
41 #define CCM_NONCE_LEN (CCM_SALT_LEN + IV_LEN)
42
43 typedef struct private_aead_t private_aead_t;
44
45 /**
46 * Private data of aead_t
47 */
48 struct private_aead_t {
49
50 /**
51 * Public interface
52 */
53 aead_t public;
54
55 /**
56 * The encryption key
57 */
58 chunk_t key;
59
60 /**
61 * Salt value
62 */
63 chunk_t salt;
64
65 /**
66 * Size of the integrity check value
67 */
68 size_t icv_size;
69
70 /**
71 * IV generator
72 */
73 iv_gen_t *iv_gen;
74
75 /**
76 * The cipher to use
77 */
78 union {
79 #if !defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AESCCM))
80 Aes aes;
81 #endif
82 } cipher;
83
84 /**
85 * The cipher to use
86 */
87 encryption_algorithm_t alg;
88 };
89
90 METHOD(aead_t, encrypt, bool,
91 private_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
92 chunk_t *encrypted)
93 {
94 chunk_t nonce;
95 u_char *out;
96 bool success = FALSE;
97 int ret;
98
99 out = plain.ptr;
100 if (encrypted)
101 {
102 *encrypted = chunk_alloc(plain.len + this->icv_size);
103 out = encrypted->ptr;
104 }
105
106 nonce = chunk_cata("cc", this->salt, iv);
107
108 switch (this->alg)
109 {
110 #if !defined(NO_AES) && defined(HAVE_AESGCM)
111 case ENCR_AES_GCM_ICV8:
112 case ENCR_AES_GCM_ICV12:
113 case ENCR_AES_GCM_ICV16:
114 ret = wc_AesGcmSetKey(&this->cipher.aes, this->key.ptr,
115 this->key.len);
116 if (ret == 0)
117 {
118 ret = wc_AesGcmEncrypt(&this->cipher.aes, out, plain.ptr,
119 plain.len, nonce.ptr, GCM_NONCE_LEN, out + plain.len,
120 this->icv_size, assoc.ptr, assoc.len);
121 }
122 success = (ret == 0);
123 break;
124 #endif
125 #if !defined(NO_AES) && defined(HAVE_AESCCM)
126 case ENCR_AES_CCM_ICV8:
127 case ENCR_AES_CCM_ICV12:
128 case ENCR_AES_CCM_ICV16:
129 /* wc_AesCcmEncrypt fails if the pointer is NULL */
130 if (!plain.ptr && !plain.len)
131 {
132 plain.ptr = nonce.ptr;
133 }
134 ret = wc_AesCcmSetKey(&this->cipher.aes, this->key.ptr,
135 this->key.len);
136 if (ret == 0)
137 {
138 ret = wc_AesCcmEncrypt(&this->cipher.aes, out, plain.ptr,
139 plain.len, nonce.ptr, CCM_NONCE_LEN, out + plain.len,
140 this->icv_size, assoc.ptr, assoc.len);
141 }
142 success = (ret == 0);
143 break;
144 #endif
145 #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
146 case ENCR_CHACHA20_POLY1305:
147 ret = wc_ChaCha20Poly1305_Encrypt(this->key.ptr, nonce.ptr,
148 assoc.ptr, assoc.len, plain.ptr, plain.len, out,
149 out + plain.len);
150 success = (ret == 0);
151 break;
152 #endif
153 default:
154 break;
155 }
156
157 memwipe(nonce.ptr, nonce.len);
158 return success;
159 }
160
161 METHOD(aead_t, decrypt, bool,
162 private_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
163 chunk_t *plain)
164 {
165 chunk_t nonce;
166 u_char *out;
167 bool success = FALSE;
168 int ret = 0;
169
170 if (encrypted.len < this->icv_size)
171 {
172 return FALSE;
173 }
174 encrypted.len -= this->icv_size;
175
176 out = encrypted.ptr;
177 if (plain)
178 {
179 *plain = chunk_alloc(encrypted.len);
180 out = plain->ptr;
181 }
182
183 nonce = chunk_cata("cc", this->salt, iv);
184
185 switch (this->alg)
186 {
187 #if !defined(NO_AES) && defined(HAVE_AESGCM)
188 case ENCR_AES_GCM_ICV8:
189 case ENCR_AES_GCM_ICV12:
190 case ENCR_AES_GCM_ICV16:
191 ret = wc_AesGcmSetKey(&this->cipher.aes, this->key.ptr,
192 this->key.len);
193 if (ret == 0)
194 {
195 ret = wc_AesGcmDecrypt(&this->cipher.aes, out, encrypted.ptr,
196 encrypted.len, nonce.ptr, GCM_NONCE_LEN,
197 encrypted.ptr + encrypted.len, this->icv_size,
198 assoc.ptr, assoc.len);
199 }
200 success = (ret == 0);
201 break;
202 #endif
203 #if !defined(NO_AES) && defined(HAVE_AESCCM)
204 case ENCR_AES_CCM_ICV8:
205 case ENCR_AES_CCM_ICV12:
206 case ENCR_AES_CCM_ICV16:
207 /* wc_AesCcmDecrypt() fails if the pointers are NULL */
208 if (!encrypted.ptr && !encrypted.len)
209 {
210 encrypted.ptr = nonce.ptr;
211 }
212 if (!out && !encrypted.len)
213 {
214 out = nonce.ptr;
215 }
216 ret = wc_AesCcmSetKey(&this->cipher.aes, this->key.ptr,
217 this->key.len);
218 if (ret == 0)
219 {
220 ret = wc_AesCcmDecrypt(&this->cipher.aes, out, encrypted.ptr,
221 encrypted.len, nonce.ptr, CCM_NONCE_LEN,
222 encrypted.ptr + encrypted.len, this->icv_size,
223 assoc.ptr, assoc.len);
224 }
225 success = (ret == 0);
226 break;
227 #endif
228 #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
229 case ENCR_CHACHA20_POLY1305:
230 ret = wc_ChaCha20Poly1305_Decrypt(this->key.ptr, nonce.ptr,
231 assoc.ptr, assoc.len, encrypted.ptr, encrypted.len,
232 encrypted.ptr + encrypted.len, out);
233 success = (ret == 0);
234 break;
235 #endif
236 default:
237 break;
238 }
239
240 memwipe(nonce.ptr, nonce.len);
241 return success;
242 }
243
244 METHOD(aead_t, get_block_size, size_t,
245 private_aead_t *this)
246 {
247 /* all AEAD algorithms are streaming */
248 return 1;
249 }
250
251 METHOD(aead_t, get_icv_size, size_t,
252 private_aead_t *this)
253 {
254 return this->icv_size;
255 }
256
257 METHOD(aead_t, get_iv_size, size_t,
258 private_aead_t *this)
259 {
260 return IV_LEN;
261 }
262
263 METHOD(aead_t, get_iv_gen, iv_gen_t*,
264 private_aead_t *this)
265 {
266 return this->iv_gen;
267 }
268
269 METHOD(aead_t, get_key_size, size_t,
270 private_aead_t *this)
271 {
272 return this->key.len + this->salt.len;
273 }
274
275 METHOD(aead_t, set_key, bool,
276 private_aead_t *this, chunk_t key)
277 {
278 if (key.len != get_key_size(this))
279 {
280 return FALSE;
281 }
282 memcpy(this->salt.ptr, key.ptr + key.len - this->salt.len, this->salt.len);
283 memcpy(this->key.ptr, key.ptr, this->key.len);
284 return TRUE;
285 }
286
287 METHOD(aead_t, destroy, void,
288 private_aead_t *this)
289 {
290 chunk_clear(&this->key);
291 chunk_clear(&this->salt);
292 switch (this->alg)
293 {
294 #if !defined(NO_AES) && defined(HAVE_AESGCM)
295 case ENCR_AES_GCM_ICV8:
296 case ENCR_AES_GCM_ICV12:
297 case ENCR_AES_GCM_ICV16:
298 wc_AesFree(&this->cipher.aes);
299 break;
300 #endif
301 #if !defined(NO_AES) && defined(HAVE_AESCCM)
302 case ENCR_AES_CCM_ICV8:
303 case ENCR_AES_CCM_ICV12:
304 case ENCR_AES_CCM_ICV16:
305 wc_AesFree(&this->cipher.aes);
306 break;
307 #endif
308 default:
309 break;
310 }
311 this->iv_gen->destroy(this->iv_gen);
312 free(this);
313 }
314
315 /*
316 * Described in header
317 */
318 aead_t *wolfssl_aead_create(encryption_algorithm_t algo,
319 size_t key_size, size_t salt_size)
320 {
321 private_aead_t *this;
322 size_t expected_salt_size;
323
324 INIT(this,
325 .public = {
326 .encrypt = _encrypt,
327 .decrypt = _decrypt,
328 .get_block_size = _get_block_size,
329 .get_icv_size = _get_icv_size,
330 .get_iv_size = _get_iv_size,
331 .get_iv_gen = _get_iv_gen,
332 .get_key_size = _get_key_size,
333 .set_key = _set_key,
334 .destroy = _destroy,
335 },
336 .alg = algo,
337 );
338
339 switch (algo)
340 {
341 #if !defined(NO_AES) && defined(HAVE_AESGCM)
342 #if WOLFSSL_MIN_AUTH_TAG_SZ <= 8
343 case ENCR_AES_GCM_ICV8:
344 this->icv_size = 8;
345 break;
346 #endif
347 #if WOLFSSL_MIN_AUTH_TAG_SZ <= 12
348 case ENCR_AES_GCM_ICV12:
349 this->icv_size = 12;
350 break;
351 #endif
352 case ENCR_AES_GCM_ICV16:
353 this->icv_size = 16;
354 break;
355 #endif
356 #if !defined(NO_AES) && defined(HAVE_AESCCM)
357 case ENCR_AES_CCM_ICV8:
358 this->icv_size = 8;
359 break;
360 case ENCR_AES_CCM_ICV12:
361 this->icv_size = 12;
362 break;
363 case ENCR_AES_CCM_ICV16:
364 this->icv_size = 16;
365 break;
366 #endif
367 #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
368 case ENCR_CHACHA20_POLY1305:
369 this->icv_size = 16;
370 break;
371 #endif
372 default:
373 free(this);
374 return NULL;
375 }
376
377 switch (algo)
378 {
379 #if !defined(NO_AES) && defined(HAVE_AESGCM)
380 case ENCR_AES_GCM_ICV8:
381 case ENCR_AES_GCM_ICV12:
382 case ENCR_AES_GCM_ICV16:
383 switch (key_size)
384 {
385 case 0:
386 key_size = 16;
387 /* FALL */
388 case 16:
389 case 24:
390 case 32:
391 expected_salt_size = GCM_SALT_LEN;
392 if (wc_AesInit(&this->cipher.aes, NULL, INVALID_DEVID) != 0)
393 {
394 DBG1(DBG_LIB, "AES Init failed, aead create failed");
395 free(this);
396 return NULL;
397 }
398 break;
399 default:
400 free(this);
401 return NULL;
402 }
403 break;
404 #endif
405 #if !defined(NO_AES) && defined(HAVE_AESCCM)
406 case ENCR_AES_CCM_ICV8:
407 case ENCR_AES_CCM_ICV12:
408 case ENCR_AES_CCM_ICV16:
409 switch (key_size)
410 {
411 case 0:
412 key_size = 16;
413 /* FALL */
414 case 16:
415 case 24:
416 case 32:
417 expected_salt_size = CCM_SALT_LEN;
418 if (wc_AesInit(&this->cipher.aes, NULL, INVALID_DEVID) != 0)
419 {
420 DBG1(DBG_LIB, "AES Init failed, aead create failed");
421 free(this);
422 return NULL;
423 }
424 break;
425 default:
426 free(this);
427 return NULL;
428 }
429 break;
430 #endif
431 #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
432 case ENCR_CHACHA20_POLY1305:
433 switch (key_size)
434 {
435 case 0:
436 key_size = 32;
437 /* FALL */
438 case 32:
439 expected_salt_size = 4;
440 break;
441 default:
442 free(this);
443 return NULL;
444 }
445 break;
446 #endif
447 default:
448 free(this);
449 return NULL;
450 }
451
452 if (salt_size && salt_size != expected_salt_size)
453 {
454 /* currently not supported */
455 free(this);
456 return NULL;
457 }
458
459 this->key = chunk_alloc(key_size);
460 this->salt = chunk_alloc(expected_salt_size);
461 this->iv_gen = iv_gen_seq_create();
462
463 return &this->public;
464 }
465
466 #endif