From a7165907dac33e520dd80057df6ff89c63f2226d Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Wed, 22 Dec 2021 17:41:01 +0100 Subject: [PATCH] psa: support AES --- wolfcrypt/src/aes.c | 28 +++ wolfcrypt/src/include.am | 1 + wolfcrypt/src/port/psa/psa_aes.c | 324 +++++++++++++++++++++++++++++++ wolfcrypt/test/test.c | 3 + wolfssl/wolfcrypt/aes.h | 10 + wolfssl/wolfcrypt/port/psa/psa.h | 27 +++ 6 files changed, 393 insertions(+) create mode 100644 wolfcrypt/src/port/psa/psa_aes.c diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index 8cae3ef8a..05e759464 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -76,6 +76,10 @@ block cipher mechanism that uses n-bit binary string parameter key with 128-bits #include #endif +#if defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES) + #include +#endif + /* fips wrapper calls, user can call direct */ #if defined(HAVE_FIPS) && \ (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2)) @@ -1063,6 +1067,8 @@ block cipher mechanism that uses n-bit binary string parameter key with 128-bits defined(WOLFSSL_AES_CFB) || defined(HAVE_AES_ECB) #define NEED_AES_TABLES #endif +#elif defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES) +/* implemented in wolfcrypt/src/port/psa/psa_aes.c */ #else /* using wolfCrypt software implementation */ @@ -2905,6 +2911,11 @@ static WARN_UNUSED_RESULT int wc_AesDecrypt( if (keylen > sizeof(aes->key)) { return BAD_FUNC_ARG; } +#if defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES) + return wc_psa_aes_set_key(aes, userKey, keylen, (uint8_t*)iv, + ((psa_algorithm_t)0), dir); +#endif + rk = aes->key; XMEMCPY(rk, userKey, keylen); #if defined(LITTLE_ENDIAN_ORDER) && !defined(WOLFSSL_PIC32MZ_CRYPT) && \ @@ -3910,6 +3921,9 @@ int wc_AesSetIV(Aes* aes, const byte* iv) #elif defined(WOLFSSL_SILABS_SE_ACCEL) /* implemented in wolfcrypt/src/port/silabs/silabs_hash.c */ +#elif defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES) + /* implemented in wolfcrypt/src/port/psa/psa_aes.c */ + #else /* Software AES - CBC Encrypt */ @@ -4341,6 +4355,8 @@ int wc_AesSetIV(Aes* aes, const byte* iv) /* use aes ecnryption plus sw implementation */ #define NEED_AES_CTR_SOFT + #elif defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES) + /* implemented in wolfcrypt/src/port/psa/psa_aes.c */ #else /* Use software based AES counter */ @@ -10436,6 +10452,10 @@ int wc_AesInit(Aes* aes, void* heap, int devId) aes->ctrSet = 0; #endif +#if defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES) + ret = wc_psa_aes_init(aes); +#endif + return ret; } @@ -10534,6 +10554,10 @@ void wc_AesFree(Aes* aes) se050_aes_free(aes); #endif +#if defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES) + wc_psa_aes_free(aes); +#endif + } @@ -10544,6 +10568,10 @@ int wc_AesGetKeySize(Aes* aes, word32* keySize) if (aes == NULL || keySize == NULL) { return BAD_FUNC_ARG; } + +#if defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES) + return wc_psa_aes_get_key_size(aes, keySize); +#endif #if defined(WOLFSSL_CRYPTOCELL) && defined(WOLFSSL_CRYPTOCELL_AES) *keySize = aes->ctx.key.keySize; return ret; diff --git a/wolfcrypt/src/include.am b/wolfcrypt/src/include.am index 7866a36ec..04dcbc7f0 100644 --- a/wolfcrypt/src/include.am +++ b/wolfcrypt/src/include.am @@ -188,4 +188,5 @@ endif if BUILD_PSA src_libwolfssl_la_SOURCES += wolfcrypt/src/port/psa/psa.c src_libwolfssl_la_SOURCES += wolfcrypt/src/port/psa/psa_hash.c +src_libwolfssl_la_SOURCES += wolfcrypt/src/port/psa/psa_aes.c endif diff --git a/wolfcrypt/src/port/psa/psa_aes.c b/wolfcrypt/src/port/psa/psa_aes.c new file mode 100644 index 000000000..421538643 --- /dev/null +++ b/wolfcrypt/src/port/psa/psa_aes.c @@ -0,0 +1,324 @@ +/* psa_aes.c + * + * Copyright (C) 2006-2021 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#if defined(WOLFSSL_HAVE_PSA) +#if !defined(WOLFSSL_PSA_NO_AES) +#if !defined(NO_AES) + +#include +#include +#include + +#ifndef NO_INLINE +#define WOLFSSL_MISC_INCLUDED +#include +#else +#include +#endif + +static int wc_psa_aes_import_key(Aes *aes, const uint8_t *key, + size_t key_length, psa_algorithm_t alg, + int dir) +{ + psa_key_attributes_t key_attr; + psa_key_id_t id; + psa_status_t s; + + XMEMSET(&key_attr, 0, sizeof(key_attr)); + aes->key_id = 0; + aes->ctx_initialized = 0; + + psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES); + psa_set_key_usage_flags(&key_attr, + dir == AES_ENCRYPTION ? PSA_KEY_USAGE_ENCRYPT : + dir == AES_DECRYPTION ? PSA_KEY_USAGE_DECRYPT : 0); + psa_set_key_algorithm(&key_attr, alg); + + s = psa_import_key(&key_attr, key, key_length, &id); + if (s != PSA_SUCCESS) + return WC_HW_E; + + aes->key_id = id; + aes->key_need_importing = 0; + + return 0; +} + +/** + * wc_psa_aes_init() - init @aes PSA resources + * @aes: Aes object + */ +int wc_psa_aes_init(Aes *aes) +{ + aes->key_id = 0; + aes->ctx_initialized = 0; + aes->key_need_importing = 0; + XMEMSET(&aes->psa_ctx, 0, sizeof(aes->psa_ctx)); + return 0; +} + +/** + * wc_psa_aes_get_key_size() - get the size of the key in @aes + * @aes: Aes object + * @keySize: where to store the size of the key + * + * returns: 0 on success + */ +int wc_psa_aes_get_key_size(Aes *aes, word32 *keySize) +{ + psa_key_attributes_t attr; + psa_status_t s; + + if (aes->key_need_importing == 1) { + *keySize = aes->keylen; + return 0; + } + + if (aes->key_id == PSA_KEY_ID_NULL) + return BAD_FUNC_ARG; + + s = psa_get_key_attributes(aes->key_id, &attr); + if (s != PSA_SUCCESS) + return WC_HW_E; + + *keySize = (word32)(psa_get_key_bits(&attr) / 8); + psa_reset_key_attributes(&attr); + return 0; +} + +/** + * wc_psa_aes_set_key() - set key / iv to object *aes + * @aes: object to set the key into + * @key: key to import + * @key_length: size of the key in bytes + * @iv: IV (can be null) + * @alg: algorithm (mode) to use with this key (can be 0) + * @dir: direction to use with this key + * + * + * NOTE: if we don't know for teh mode or the direction (@alg == 0) the key + * import operation will be delayed until the first wc_psa_aes_encrypt_decrypt() + * invocation. In this case the key is temporary stored inside the AES + * object. Indeed PSA requires that the mode of operation is already known when + * importing a new key. + * + * returns: 0 on success, WC_HW_E on PSA error +*/ +int wc_psa_aes_set_key(Aes *aes, const uint8_t *key, size_t key_length, + uint8_t *iv, psa_algorithm_t alg, int dir) +{ + psa_status_t s; + int ret; + + /* the object was already used for other encryption. Reset the context */ + if (aes->ctx_initialized) { + s = psa_cipher_abort(&aes->psa_ctx); + if (s != PSA_SUCCESS) + return WC_HW_E; + aes->ctx_initialized =0; + } + + /* a key was already imported, destroy it first */ + if (aes->key_id != PSA_KEY_ID_NULL) { + psa_destroy_key(aes->key_id); + aes->key_id = PSA_KEY_ID_NULL; + } + + /* we have been invoked from a generic wcSetKey. We don't know the mode that + will be used, so we can't import the key in PSA yet. Let's copy the key + inside the object, we will import it when we'll know the cipher mode */ + if (alg == PSA_ALG_NONE) { + XMEMCPY(aes->key, key, key_length); + aes->key_need_importing = 1; + } else { + ret = wc_psa_aes_import_key(aes, key, key_length, alg, dir); + if (ret != 0) + return ret; + } + + return wc_AesSetIV(aes, iv); +} + +/** + * wc_psa_aes_encrypt_decrypt() - do an encrypt/decrypt step + * @aes: Aes object + * @input: input data + * @output: where to store the result of the operation + * @length: size of the input data + * @alg: algorithm (mode) to use in the operation + * @direction: either @AES_ENCRYPT or @AES_DECRYPT + * + * returns: + * 0 on success + * BAD_FUNC_ARG for bad argument + * WC_HW_E for PSA error + */ +int wc_psa_aes_encrypt_decrypt(Aes *aes, const uint8_t *input, + uint8_t *output, size_t length, + psa_algorithm_t alg, int direction) +{ + size_t output_length; + psa_status_t s; + int r; + + if (aes == NULL || input == NULL || output == NULL) + return BAD_FUNC_ARG; + + /* This is the first time we invoke encrypt/decrypt */ + if (aes->ctx_initialized == 0) { + + /* import the key */ + if (aes->key_need_importing == 1) { + r = wc_psa_aes_import_key(aes, (uint8_t*)aes->key, aes->keylen, + alg, direction); + if (r != 0) + return r; + + ForceZero(aes->key, aes->keylen); + aes->key_need_importing = 0; + aes->keylen = 0; + } + + if (direction == AES_ENCRYPTION) { + s = psa_cipher_encrypt_setup(&aes->psa_ctx, aes->key_id, alg); + } else { + s = psa_cipher_decrypt_setup(&aes->psa_ctx, aes->key_id, alg); + } + + if (s != PSA_SUCCESS) + goto err; + + aes->ctx_initialized = 1; + + /* ECB doesn't use IV */ + if (alg != PSA_ALG_ECB_NO_PADDING) { + + /* wc_SetIV stores the IV in reg */ + s = psa_cipher_set_iv(&aes->psa_ctx, + (uint8_t*)aes->reg, AES_IV_SIZE); + if (s != PSA_SUCCESS) + goto err; + } + + } + + s = psa_cipher_update(&aes->psa_ctx, input, + length, output, length, &output_length); + if (s != PSA_SUCCESS) + goto err; + + if (output_length != length) + goto err; + + return 0; + + err: + wc_psa_aes_free(aes); + return WC_HW_E; + } + +/** + * wc_psa_aes_free() - PSA cipher cleanup + * @aes: the Aes object to cleanup + */ +int wc_psa_aes_free(Aes *aes) +{ + if (aes->key_id != PSA_KEY_ID_NULL) { + psa_destroy_key(aes->key_id); + aes->key_id = PSA_KEY_ID_NULL; + } + + if (aes->ctx_initialized == 1) { + psa_cipher_abort(&aes->psa_ctx); + aes->ctx_initialized = 0; + } + + aes->ctx_initialized = 0; + aes->key_need_importing = 0; + + return 0; +} + +int wc_AesEncrypt(Aes *aes, const byte *inBlock, byte *outBlock) +{ + return wc_psa_aes_encrypt_decrypt(aes, inBlock, outBlock, + AES_BLOCK_SIZE, PSA_ALG_ECB_NO_PADDING, + AES_ENCRYPTION); +} + +#if defined(HAVE_AES_DECRYPT) +int wc_AesDecrypt(Aes *aes, const byte *inBlock, byte *outBlock) +{ + return wc_psa_aes_encrypt_decrypt(aes, inBlock, outBlock, + AES_BLOCK_SIZE, PSA_ALG_ECB_NO_PADDING, + AES_DECRYPTION); +} +#endif + +#if defined(WOLFSSL_AES_COUNTER) + +int wc_AesCtrEncrypt(Aes *aes, byte *out, const byte *in, word32 sz) +{ + return wc_psa_aes_encrypt_decrypt(aes, in, out, sz, PSA_ALG_CTR, + AES_ENCRYPTION); +} +#endif + +#if defined (HAVE_AES_CBC) +int wc_AesCbcEncrypt(Aes *aes, byte *out, const byte *in, word32 sz) +{ + + if (sz % AES_BLOCK_SIZE != 0) +#if defined (WOLFSSL_AES_CBC_LENGTH_CHECKS) + return BAD_LENGTH_E; +#else + return BAD_FUNC_ARG; +#endif + + return wc_psa_aes_encrypt_decrypt(aes, in, out, sz, + PSA_ALG_CBC_NO_PADDING, + AES_ENCRYPTION); +} + +int wc_AesCbcDecrypt(Aes *aes, byte *out, const byte *in, word32 sz) +{ + + if (sz % AES_BLOCK_SIZE != 0) +#if defined (WOLFSSL_AES_CBC_LENGTH_CHECKS) + return BAD_LENGTH_E; +#else + return BAD_FUNC_ARG; +#endif + + return wc_psa_aes_encrypt_decrypt(aes, in, out, sz, + PSA_ALG_CBC_NO_PADDING, + AES_DECRYPTION); +} +#endif /* HAVE_AES_CBC */ + +#endif /* ! NO_AES */ +#endif /* ! WOLFSSL_PSA_NO_AES */ +#endif /* WOLFSSL_HAVE_PSA */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 8bcfb85a5..e9de88aff 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -7702,11 +7702,14 @@ static int aes_key_size_test(void) ERROR_OUT(-5307, out); /* CryptoCell handles rounds internally */ #if !defined(HAVE_FIPS) && !defined(WOLFSSL_CRYPTOCELL) + /* PSA don't use aes->rounds */ +#if !defined(WOLFSSL_HAVE_PSA) || defined(WOLFSSL_PSA_NO_AES) /* Force invalid rounds */ aes->rounds = 16; ret = wc_AesGetKeySize(aes, &keySize); if (ret != BAD_FUNC_ARG) ERROR_OUT(-5308, out); +#endif #endif ret = wc_AesSetKey(aes, key16, sizeof(key16), iv, AES_ENCRYPTION); diff --git a/wolfssl/wolfcrypt/aes.h b/wolfssl/wolfcrypt/aes.h index 18f2cd0b8..921b3219c 100644 --- a/wolfssl/wolfcrypt/aes.h +++ b/wolfssl/wolfcrypt/aes.h @@ -96,6 +96,10 @@ block cipher mechanism that uses n-bit binary string parameter key with 128-bits #include #endif +#if defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES) +#include +#endif + #if defined(WOLFSSL_CRYPTOCELL) #include #endif @@ -270,6 +274,12 @@ struct Aes { #endif #if defined(WOLFSSL_SILABS_SE_ACCEL) silabs_aes_t ctx; +#endif +#if defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES) + psa_key_id_t key_id; + psa_cipher_operation_t psa_ctx; + int ctx_initialized; + int key_need_importing; #endif void* heap; /* memory hint to use */ #ifdef WOLFSSL_AESGCM_STREAM diff --git a/wolfssl/wolfcrypt/port/psa/psa.h b/wolfssl/wolfcrypt/port/psa/psa.h index aea8fe91e..d938ffefd 100644 --- a/wolfssl/wolfcrypt/port/psa/psa.h +++ b/wolfssl/wolfcrypt/port/psa/psa.h @@ -30,6 +30,7 @@ * WOLFSSL_HAVE_PSA: Global switch to enable PSA * WOLFSSL_PSA_NO_RNG: disable PSA random generator support * WOLFSSL_PSA_NO_HASH: disable PSA hashing support + * WOLFSSL_PSA_NO_AES: disable PSA AES support */ #ifndef WOLFSSL_PSA_H @@ -47,6 +48,11 @@ #include #include +#if !defined(WOLFSSL_PSA_NO_AES) +#if !defined(NO_AES) +#include +#endif +#endif /* WOLFSSL_PSA_NO_AES */ int wc_psa_init(void); @@ -59,7 +65,28 @@ WOLFSSL_API int wc_psa_get_random(unsigned char *out, word32 sz); #define CUSTOM_RAND_GENERATE_SEED wc_psa_get_random #endif +#endif /* WOLFSSL_HAVE_PSA_RNG */ + +#if !defined(WOLFSSL_PSA_NO_AES) && !defined(NO_AES) + +int wc_psa_aes_init(Aes *aes); +int wc_psa_aes_free(Aes *aes); +int wc_psa_aes_get_key_size(Aes *aes, word32 *keySize); +int wc_psa_aes_set_key(Aes *aes, const uint8_t *key, + size_t key_length, uint8_t *iv, + psa_algorithm_t alg, int dir); + +WOLFSSL_API int wc_psa_aes_encrypt_decrypt(Aes *aes, const uint8_t *input, + uint8_t *output, size_t length, + psa_algorithm_t alg, int direction); + +WOLFSSL_API int wc_AesEncrypt(Aes *aes, const byte *inBlock, byte *outBlock); + +#if defined(HAVE_AES_DECRYPT) +WOLFSSL_API int wc_AesDecrypt(Aes *aes, const byte *inBlock, byte *outBlock); #endif #endif + +#endif /* WOLFSSL_HAVE_PSA */ #endif /* WOLFSSL_PSA_H */