2 * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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
23 #include "wolfssl_common.h"
25 #if (!defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AESCCM))) || \
26 (defined(HAVE_CHACHA) && defined(HAVE_POLY1305))
28 #include "wolfssl_aead.h"
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>
35 /** as defined in RFC 4106 */
37 #define GCM_SALT_LEN 4
38 #define GCM_NONCE_LEN (GCM_SALT_LEN + IV_LEN)
40 #define CCM_SALT_LEN 3
41 #define CCM_NONCE_LEN (CCM_SALT_LEN + IV_LEN)
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
54 typedef struct private_aead_t private_aead_t
;
57 * Private data of aead_t
59 struct private_aead_t
{
74 char salt
[MAX_SALT_LEN
];
82 * Size of the integrity check value
101 #if !defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AESCCM))
109 encryption_algorithm_t alg
;
113 METHOD(aead_t
, encrypt
, bool,
114 private_aead_t
*this, chunk_t plain
, chunk_t assoc
, chunk_t iv
,
117 bool success
= FALSE
;
120 u_char nonce
[MAX_NONCE_LEN
];
125 *encrypted
= chunk_alloc(plain
.len
+ this->icv_size
);
126 out
= encrypted
->ptr
;
129 memcpy(nonce
, this->salt
, this->salt_len
);
130 memcpy(nonce
+ this->salt_len
, iv
.ptr
, IV_LEN
);
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
,
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
);
146 success
= (ret
== 0);
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)
155 ret
= wc_AesCcmSetKey(&this->cipher
.aes
, this->key
.ptr
,
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
);
163 success
= (ret
== 0);
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);
180 METHOD(aead_t
, decrypt
, bool,
181 private_aead_t
*this, chunk_t encrypted
, chunk_t assoc
, chunk_t iv
,
184 bool success
= FALSE
;
187 u_char nonce
[MAX_NONCE_LEN
];
189 if (encrypted
.len
< this->icv_size
)
193 encrypted
.len
-= this->icv_size
;
198 *plain
= chunk_alloc(encrypted
.len
);
202 memcpy(nonce
, this->salt
, this->salt_len
);
203 memcpy(nonce
+ this->salt_len
, iv
.ptr
, IV_LEN
);
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
,
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
,
220 success
= (ret
== 0);
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)
231 ret
= wc_AesCcmSetKey(&this->cipher
.aes
, this->key
.ptr
,
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
,
240 success
= (ret
== 0);
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);
258 METHOD(aead_t
, get_block_size
, size_t,
259 private_aead_t
*this)
261 /* All AEAD algorithms are streaming. */
265 METHOD(aead_t
, get_icv_size
, size_t,
266 private_aead_t
*this)
268 return this->icv_size
;
271 METHOD(aead_t
, get_iv_size
, size_t,
272 private_aead_t
*this)
277 METHOD(aead_t
, get_iv_gen
, iv_gen_t
*,
278 private_aead_t
*this)
283 METHOD(aead_t
, get_key_size
, size_t,
284 private_aead_t
*this)
286 return this->key
.len
+ this->salt_len
;
289 METHOD(aead_t
, set_key
, bool,
290 private_aead_t
*this, chunk_t key
)
292 if (key
.len
!= get_key_size(this))
296 memcpy(this->salt
, key
.ptr
+ key
.len
- this->salt_len
, this->salt_len
);
297 memcpy(this->key
.ptr
, key
.ptr
, this->key
.len
);
301 METHOD(aead_t
, destroy
, void,
302 private_aead_t
*this)
304 chunk_clear(&this->key
);
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
);
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
);
321 #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
322 case ENCR_CHACHA20_POLY1305
:
328 this->iv_gen
->destroy(this->iv_gen
);
333 * Described in header
335 aead_t
*wolfssl_aead_create(encryption_algorithm_t algo
,
336 size_t key_size
, size_t salt_size
)
338 private_aead_t
*this;
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
,
357 #if !defined(NO_AES) && defined(HAVE_AESGCM)
358 #if WOLFSSL_MIN_AUTH_TAG_SZ <= 8
359 case ENCR_AES_GCM_ICV8
:
363 #if WOLFSSL_MIN_AUTH_TAG_SZ <= 12
364 case ENCR_AES_GCM_ICV12
:
368 case ENCR_AES_GCM_ICV16
:
372 #if !defined(NO_AES) && defined(HAVE_AESCCM)
373 case ENCR_AES_CCM_ICV8
:
376 case ENCR_AES_CCM_ICV12
:
379 case ENCR_AES_CCM_ICV16
:
383 #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
384 case ENCR_CHACHA20_POLY1305
:
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
:
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)
411 DBG1(DBG_LIB
, "AES Init failed, aead create failed");
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
:
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)
438 DBG1(DBG_LIB
, "AES Init failed, aead create failed");
449 #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
450 case ENCR_CHACHA20_POLY1305
:
457 this->iv_size
= CHACHA_IV_BYTES
;
471 if (salt_size
&& salt_size
!= this->salt_len
)
473 /* currently not supported */
478 this->key
= chunk_alloc(key_size
);
479 this->iv_gen
= iv_gen_seq_create();
481 return &this->public;