]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libstrongswan/plugins/wolfssl/wolfssl_aead.c
1ed0c715ba9fe6850972c995179aab83b4f4778a
[thirdparty/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 #if !defined(NO_AES) && defined(HAVE_AESGCM)
44 #define MAX_NONCE_LEN GCM_NONCE_LEN
45 #define MAX_SALT_LEN GCM_SALT_LEN
46 #elif defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
47 #define MAX_NONCE_LEN 12
48 #define MAX_SALT_LEN 4
49 #elif !defined(NO_AES) && defined(HAVE_AESCCM)
50 #define MAX_NONCE_LEN CCM_NONCE_LEN
51 #define MAX_SALT_LEN GCM_SALT_LEN
52 #endif
53
54 typedef struct private_aead_t private_aead_t;
55
56 /**
57 * Private data of aead_t
58 */
59 struct private_aead_t {
60
61 /**
62 * Public interface
63 */
64 aead_t public;
65
66 /**
67 * The encryption key
68 */
69 chunk_t key;
70
71 /**
72 * Salt value
73 */
74 char salt[MAX_SALT_LEN];
75
76 /**
77 * Length of the salt
78 */
79 size_t salt_len;
80
81 /**
82 * Size of the integrity check value
83 */
84 size_t icv_size;
85
86 /**
87 * Size of the IV
88 */
89 size_t iv_size;
90
91 /**
92 * IV generator
93 */
94 iv_gen_t *iv_gen;
95
96 /**
97 * The cipher to use
98 */
99 union
100 {
101 #if !defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AESCCM))
102 Aes aes;
103 #endif
104 } cipher;
105
106 /**
107 * The cipher to use
108 */
109 encryption_algorithm_t alg;
110 };
111
112
113 METHOD(aead_t, encrypt, bool,
114 private_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
115 chunk_t *encrypted)
116 {
117 bool success = FALSE;
118 int ret = 0;
119 u_char *out;
120 u_char nonce[MAX_NONCE_LEN];
121
122 out = plain.ptr;
123 if (encrypted)
124 {
125 *encrypted = chunk_alloc(plain.len + this->icv_size);
126 out = encrypted->ptr;
127 }
128
129 memcpy(nonce, this->salt, this->salt_len);
130 memcpy(nonce + this->salt_len, iv.ptr, IV_LEN);
131
132 switch (this->alg)
133 {
134 #if !defined(NO_AES) && defined(HAVE_AESGCM)
135 case ENCR_AES_GCM_ICV8:
136 case ENCR_AES_GCM_ICV12:
137 case ENCR_AES_GCM_ICV16:
138 ret = wc_AesGcmSetKey(&this->cipher.aes, this->key.ptr,
139 this->key.len);
140 if (ret == 0)
141 {
142 ret = wc_AesGcmEncrypt(&this->cipher.aes, out, plain.ptr,
143 plain.len, nonce, GCM_NONCE_LEN, out + plain.len,
144 this->icv_size, assoc.ptr, assoc.len);
145 }
146 success = (ret == 0);
147 break;
148 #endif
149 #if !defined(NO_AES) && defined(HAVE_AESCCM)
150 case ENCR_AES_CCM_ICV8:
151 case ENCR_AES_CCM_ICV12:
152 case ENCR_AES_CCM_ICV16:
153 if (plain.ptr == NULL && plain.len == 0)
154 plain.ptr = nonce;
155 ret = wc_AesCcmSetKey(&this->cipher.aes, this->key.ptr,
156 this->key.len);
157 if (ret == 0)
158 {
159 ret = wc_AesCcmEncrypt(&this->cipher.aes, out, plain.ptr,
160 plain.len, nonce, CCM_NONCE_LEN, out + plain.len,
161 this->icv_size, assoc.ptr, assoc.len);
162 }
163 success = (ret == 0);
164 break;
165 #endif
166 #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
167 case ENCR_CHACHA20_POLY1305:
168 ret = wc_ChaCha20Poly1305_Encrypt(this->key.ptr, nonce, assoc.ptr,
169 assoc.len, plain.ptr, plain.len, out, out + plain.len);
170 success = (ret == 0);
171 break;
172 #endif
173 default:
174 break;
175 }
176
177 return success;
178 }
179
180 METHOD(aead_t, decrypt, bool,
181 private_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
182 chunk_t *plain)
183 {
184 bool success = FALSE;
185 int ret = 0;
186 u_char *out;
187 u_char nonce[MAX_NONCE_LEN];
188
189 if (encrypted.len < this->icv_size)
190 {
191 return FALSE;
192 }
193 encrypted.len -= this->icv_size;
194
195 out = encrypted.ptr;
196 if (plain)
197 {
198 *plain = chunk_alloc(encrypted.len);
199 out = plain->ptr;
200 }
201
202 memcpy(nonce, this->salt, this->salt_len);
203 memcpy(nonce + this->salt_len, iv.ptr, IV_LEN);
204
205 switch (this->alg)
206 {
207 #if !defined(NO_AES) && defined(HAVE_AESGCM)
208 case ENCR_AES_GCM_ICV8:
209 case ENCR_AES_GCM_ICV12:
210 case ENCR_AES_GCM_ICV16:
211 ret = wc_AesGcmSetKey(&this->cipher.aes, this->key.ptr,
212 this->key.len);
213 if (ret == 0)
214 {
215 ret = wc_AesGcmDecrypt(&this->cipher.aes, out, encrypted.ptr,
216 encrypted.len, nonce, GCM_NONCE_LEN,
217 encrypted.ptr + encrypted.len, this->icv_size, assoc.ptr,
218 assoc.len);
219 }
220 success = (ret == 0);
221 break;
222 #endif
223 #if !defined(NO_AES) && defined(HAVE_AESCCM)
224 case ENCR_AES_CCM_ICV8:
225 case ENCR_AES_CCM_ICV12:
226 case ENCR_AES_CCM_ICV16:
227 if (encrypted.ptr == NULL && encrypted.len == 0)
228 encrypted.ptr = nonce;
229 if (out == NULL && encrypted.len == 0)
230 out = nonce;
231 ret = wc_AesCcmSetKey(&this->cipher.aes, this->key.ptr,
232 this->key.len);
233 if (ret == 0)
234 {
235 ret = wc_AesCcmDecrypt(&this->cipher.aes, out, encrypted.ptr,
236 encrypted.len, nonce, CCM_NONCE_LEN,
237 encrypted.ptr + encrypted.len, this->icv_size, assoc.ptr,
238 assoc.len);
239 }
240 success = (ret == 0);
241 break;
242 #endif
243 #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
244 case ENCR_CHACHA20_POLY1305:
245 ret = wc_ChaCha20Poly1305_Decrypt(this->key.ptr, nonce, assoc.ptr,
246 assoc.len, encrypted.ptr, encrypted.len,
247 encrypted.ptr + encrypted.len, out);
248 success = (ret == 0);
249 break;
250 #endif
251 default:
252 break;
253 }
254
255 return success;
256 }
257
258 METHOD(aead_t, get_block_size, size_t,
259 private_aead_t *this)
260 {
261 /* All AEAD algorithms are streaming. */
262 return 1;
263 }
264
265 METHOD(aead_t, get_icv_size, size_t,
266 private_aead_t *this)
267 {
268 return this->icv_size;
269 }
270
271 METHOD(aead_t, get_iv_size, size_t,
272 private_aead_t *this)
273 {
274 return IV_LEN;
275 }
276
277 METHOD(aead_t, get_iv_gen, iv_gen_t*,
278 private_aead_t *this)
279 {
280 return this->iv_gen;
281 }
282
283 METHOD(aead_t, get_key_size, size_t,
284 private_aead_t *this)
285 {
286 return this->key.len + this->salt_len;
287 }
288
289 METHOD(aead_t, set_key, bool,
290 private_aead_t *this, chunk_t key)
291 {
292 if (key.len != get_key_size(this))
293 {
294 return FALSE;
295 }
296 memcpy(this->salt, key.ptr + key.len - this->salt_len, this->salt_len);
297 memcpy(this->key.ptr, key.ptr, this->key.len);
298 return TRUE;
299 }
300
301 METHOD(aead_t, destroy, void,
302 private_aead_t *this)
303 {
304 chunk_clear(&this->key);
305 switch (this->alg)
306 {
307 #if !defined(NO_AES) && defined(HAVE_AESGCM)
308 case ENCR_AES_GCM_ICV8:
309 case ENCR_AES_GCM_ICV12:
310 case ENCR_AES_GCM_ICV16:
311 wc_AesFree(&this->cipher.aes);
312 break;
313 #endif
314 #if !defined(NO_AES) && defined(HAVE_AESCCM)
315 case ENCR_AES_CCM_ICV8:
316 case ENCR_AES_CCM_ICV12:
317 case ENCR_AES_CCM_ICV16:
318 wc_AesFree(&this->cipher.aes);
319 break;
320 #endif
321 #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
322 case ENCR_CHACHA20_POLY1305:
323 break;
324 #endif
325 default:
326 break;
327 }
328 this->iv_gen->destroy(this->iv_gen);
329 free(this);
330 }
331
332 /*
333 * Described in header
334 */
335 aead_t *wolfssl_aead_create(encryption_algorithm_t algo,
336 size_t key_size, size_t salt_size)
337 {
338 private_aead_t *this;
339
340 INIT(this,
341 .public = {
342 .encrypt = _encrypt,
343 .decrypt = _decrypt,
344 .get_block_size = _get_block_size,
345 .get_icv_size = _get_icv_size,
346 .get_iv_size = _get_iv_size,
347 .get_iv_gen = _get_iv_gen,
348 .get_key_size = _get_key_size,
349 .set_key = _set_key,
350 .destroy = _destroy,
351 },
352 .alg = algo,
353 );
354
355 switch (algo)
356 {
357 #if !defined(NO_AES) && defined(HAVE_AESGCM)
358 #if WOLFSSL_MIN_AUTH_TAG_SZ <= 8
359 case ENCR_AES_GCM_ICV8:
360 this->icv_size = 8;
361 break;
362 #endif
363 #if WOLFSSL_MIN_AUTH_TAG_SZ <= 12
364 case ENCR_AES_GCM_ICV12:
365 this->icv_size = 12;
366 break;
367 #endif
368 case ENCR_AES_GCM_ICV16:
369 this->icv_size = 16;
370 break;
371 #endif
372 #if !defined(NO_AES) && defined(HAVE_AESCCM)
373 case ENCR_AES_CCM_ICV8:
374 this->icv_size = 8;
375 break;
376 case ENCR_AES_CCM_ICV12:
377 this->icv_size = 12;
378 break;
379 case ENCR_AES_CCM_ICV16:
380 this->icv_size = 16;
381 break;
382 #endif
383 #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
384 case ENCR_CHACHA20_POLY1305:
385 this->icv_size = 16;
386 break;
387 #endif
388 default:
389 free(this);
390 return NULL;
391 }
392
393 switch (algo)
394 {
395 #if !defined(NO_AES) && defined(HAVE_AESGCM)
396 case ENCR_AES_GCM_ICV8:
397 case ENCR_AES_GCM_ICV12:
398 case ENCR_AES_GCM_ICV16:
399 switch (key_size)
400 {
401 case 0:
402 key_size = 16;
403 /* FALL */
404 case 16:
405 case 24:
406 case 32:
407 this->iv_size = GCM_NONCE_LEN;
408 this->salt_len = GCM_SALT_LEN;
409 if (wc_AesInit(&this->cipher.aes, NULL, INVALID_DEVID) != 0)
410 {
411 DBG1(DBG_LIB, "AES Init failed, aead create failed");
412 free(this);
413 return NULL;
414 }
415 break;
416 default:
417 free(this);
418 return NULL;
419 }
420 break;
421 #endif
422 #if !defined(NO_AES) && defined(HAVE_AESCCM)
423 case ENCR_AES_CCM_ICV8:
424 case ENCR_AES_CCM_ICV12:
425 case ENCR_AES_CCM_ICV16:
426 switch (key_size)
427 {
428 case 0:
429 key_size = 16;
430 /* FALL */
431 case 16:
432 case 24:
433 case 32:
434 this->iv_size = CCM_NONCE_LEN;
435 this->salt_len = CCM_SALT_LEN;
436 if (wc_AesInit(&this->cipher.aes, NULL, INVALID_DEVID) != 0)
437 {
438 DBG1(DBG_LIB, "AES Init failed, aead create failed");
439 free(this);
440 return NULL;
441 }
442 break;
443 default:
444 free(this);
445 return NULL;
446 }
447 break;
448 #endif
449 #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
450 case ENCR_CHACHA20_POLY1305:
451 switch (key_size)
452 {
453 case 0:
454 key_size = 32;
455 /* FALL */
456 case 32:
457 this->iv_size = CHACHA_IV_BYTES;
458 this->salt_len = 4;
459 break;
460 default:
461 free(this);
462 return NULL;
463 }
464 break;
465 #endif
466 default:
467 free(this);
468 return NULL;
469 }
470
471 if (salt_size && salt_size != this->salt_len)
472 {
473 /* currently not supported */
474 free(this);
475 return NULL;
476 }
477
478 this->key = chunk_alloc(key_size);
479 this->iv_gen = iv_gen_seq_create();
480
481 return &this->public;
482 }
483
484 #endif