Bladeren bron

psa: support AES

Marco Oliverio 2 jaren geleden
bovenliggende
commit
a7165907da
6 gewijzigde bestanden met toevoegingen van 393 en 0 verwijderingen
  1. 28 0
      wolfcrypt/src/aes.c
  2. 1 0
      wolfcrypt/src/include.am
  3. 324 0
      wolfcrypt/src/port/psa/psa_aes.c
  4. 3 0
      wolfcrypt/test/test.c
  5. 10 0
      wolfssl/wolfcrypt/aes.h
  6. 27 0
      wolfssl/wolfcrypt/port/psa/psa.h

+ 28 - 0
wolfcrypt/src/aes.c

@@ -76,6 +76,10 @@ block cipher mechanism that uses n-bit binary string parameter key with 128-bits
     #include <wolfssl/wolfcrypt/cmac.h>
 #endif
 
+#if defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES)
+    #include <wolfssl/wolfcrypt/port/psa/psa.h>
+#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;

+ 1 - 0
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

+ 324 - 0
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 <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#if defined(WOLFSSL_HAVE_PSA)
+#if !defined(WOLFSSL_PSA_NO_AES)
+#if !defined(NO_AES)
+
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/port/psa/psa.h>
+#include <wolfssl/wolfcrypt/logging.h>
+
+#ifndef NO_INLINE
+#define WOLFSSL_MISC_INCLUDED
+#include <wolfcrypt/src/misc.c>
+#else
+#include <wolfssl/wolfcrypt/misc.h>
+#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 */

+ 3 - 0
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);

+ 10 - 0
wolfssl/wolfcrypt/aes.h

@@ -96,6 +96,10 @@ block cipher mechanism that uses n-bit binary string parameter key with 128-bits
     #include <wolfssl/wolfcrypt/random.h>
 #endif
 
+#if defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES)
+#include <psa/crypto.h>
+#endif
+
 #if defined(WOLFSSL_CRYPTOCELL)
     #include <wolfssl/wolfcrypt/port/arm/cryptoCell.h>
 #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

+ 27 - 0
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 <wolfssl/wolfcrypt/types.h>
 #include <wolfssl/wolfcrypt/visibility.h>
 
+#if !defined(WOLFSSL_PSA_NO_AES)
+#if !defined(NO_AES)
+#include <wolfssl/wolfcrypt/aes.h>
+#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 */