From 2bc49effb426eb1e54b31eaadd2c45dae09e7fe2 Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Wed, 28 Jan 2026 16:02:08 +0530 Subject: [PATCH] test(mbedtls): Re-introduce the extensive AES, AES-GCM and the SHA tests - Also extend the PSRAM encryption test to ESP32-S3 --- .../test_apps/tee_test_fw/main/CMakeLists.txt | 4 +- .../mbedtls/test_apps/.build-test-rules.yml | 4 +- .../mbedtls/test_apps/main/test_psa_aes.c | 2936 +++++++++++++++-- .../mbedtls/test_apps/main/test_psa_aes_gcm.c | 1107 ++++++- .../{test_aes_perf.c => test_psa_aes_perf.c} | 0 ...parallel.c => test_psa_aes_sha_parallel.c} | 0 ...t_aes_sha_rsa.c => test_psa_aes_sha_rsa.c} | 0 .../mbedtls/test_apps/main/test_psa_sha.c | 776 +++++ components/mbedtls/test_apps/main/test_sha.c | 475 +-- .../mbedtls/test_apps/pytest_mbedtls_ut.py | 15 +- .../sdkconfig.ci.psram_all_ext_flash_enc_f4r8 | 20 + docs/en/security/security.rst | 2 +- docs/zh_CN/security/security.rst | 2 +- 13 files changed, 4566 insertions(+), 775 deletions(-) rename components/mbedtls/test_apps/main/{test_aes_perf.c => test_psa_aes_perf.c} (100%) rename components/mbedtls/test_apps/main/{test_aes_sha_parallel.c => test_psa_aes_sha_parallel.c} (100%) rename components/mbedtls/test_apps/main/{test_aes_sha_rsa.c => test_psa_aes_sha_rsa.c} (100%) create mode 100644 components/mbedtls/test_apps/main/test_psa_sha.c create mode 100644 components/mbedtls/test_apps/sdkconfig.ci.psram_all_ext_flash_enc_f4r8 diff --git a/components/esp_tee/test_apps/tee_test_fw/main/CMakeLists.txt b/components/esp_tee/test_apps/tee_test_fw/main/CMakeLists.txt index 5f18af0d20..e9032a81df 100644 --- a/components/esp_tee/test_apps/tee_test_fw/main/CMakeLists.txt +++ b/components/esp_tee/test_apps/tee_test_fw/main/CMakeLists.txt @@ -25,7 +25,7 @@ set(mbedtls_test_srcs_dir "${idf_path}/components/mbedtls/test_apps/main") if(CONFIG_SOC_AES_SUPPORTED) list(APPEND srcs "${mbedtls_test_srcs_dir}/test_psa_aes.c" "${mbedtls_test_srcs_dir}/test_psa_aes_gcm.c" - "${mbedtls_test_srcs_dir}/test_aes_perf.c" + "${mbedtls_test_srcs_dir}/test_psa_aes_perf.c" ) endif() @@ -37,7 +37,7 @@ endif() # Mixed if(CONFIG_SOC_AES_SUPPORTED AND CONFIG_SOC_SHA_SUPPORTED) - list(APPEND srcs "${mbedtls_test_srcs_dir}/test_aes_sha_parallel.c") + list(APPEND srcs "${mbedtls_test_srcs_dir}/test_psa_aes_sha_parallel.c") endif() #ECC diff --git a/components/mbedtls/test_apps/.build-test-rules.yml b/components/mbedtls/test_apps/.build-test-rules.yml index 1b78bb7e27..bdae617dd0 100644 --- a/components/mbedtls/test_apps/.build-test-rules.yml +++ b/components/mbedtls/test_apps/.build-test-rules.yml @@ -2,10 +2,12 @@ components/mbedtls/test_apps: disable: + - if: CONFIG_NAME == "aes_no_hw" and SOC_AES_SUPPORTED != 1 - if: CONFIG_NAME == "psram" and SOC_SPIRAM_SUPPORTED != 1 - if: CONFIG_NAME == "psram_all_ext" and SOC_SPIRAM_SUPPORTED != 1 - - if: CONFIG_NAME == "ecdsa_sign" and SOC_ECDSA_SUPPORTED != 1 - if: CONFIG_NAME == "psram_all_ext_flash_enc" and SOC_SPIRAM_SUPPORTED != 1 + - if: CONFIG_NAME == "psram_all_ext_flash_enc_f4r8" and IDF_TARGET != "esp32s3" + - if: CONFIG_NAME == "ecdsa_sign" and SOC_ECDSA_SUPPORTED != 1 disable_test: - if: CONFIG_NAME == "psram_all_ext_flash_enc" and IDF_TARGET not in ["esp32", "esp32p4", "esp32c5"] reason: lack of runners diff --git a/components/mbedtls/test_apps/main/test_psa_aes.c b/components/mbedtls/test_apps/main/test_psa_aes.c index a85d55a5d5..e91bdb0f76 100644 --- a/components/mbedtls/test_apps/main/test_psa_aes.c +++ b/components/mbedtls/test_apps/main/test_psa_aes.c @@ -1,19 +1,39 @@ /* - * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ -#include -#include + #include - -#include "esp_heap_caps.h" -#include "esp_log.h" -#include "esp_private/periph_ctrl.h" - +#include +#include +#include +#include #include "psa/crypto.h" - #include "unity.h" +#include "sdkconfig.h" +#include "esp_log.h" +#include "esp_timer.h" +#include "esp_heap_caps.h" +#include "test_utils.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "esp_memory_utils.h" +#include "soc/lldesc.h" + +#define INTERNAL_DMA_CAPS (MALLOC_CAP_8BIT | MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL) +#define PSRAM_DMA_CAPS (MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM) + +#define TEST_AES_CBC_DMA_MODE_LEN 1600 +#define TEST_AES_CTR_DMA_MODE_LEN 1000 +#define TEST_AES_OFB_DMA_MODE_LEN 1000 +#define TEST_AES_CFB8_DMA_MODE_LEN 1000 +#define TEST_AES_CFB128_DMA_MODE_LEN 1000 +#define TEST_AES_CTR_STREAM_DMA_MODE_LEN 1000 +#define TEST_AES_OFB_STREAM_DMA_MODE_LEN 1000 +#define TEST_AES_CFB8_STREAM_DMA_MODE_LEN 1000 +#define TEST_AES_CFB128_STREAM_DMA_MODE_LEN 1000 static const uint8_t key_256[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, @@ -22,86 +42,10 @@ static const uint8_t key_256[] = { 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, }; -TEST_CASE("PSA AES-CTR multipart", "[psa-aes]") -{ - const size_t SZ = 100; - const size_t iv_SZ = 16; - const size_t part_size = 8; - - uint8_t *plaintext = malloc(SZ); - uint8_t *ciphertext = malloc(SZ); - uint8_t *decryptedtext = malloc(SZ); - - TEST_ASSERT_NOT_NULL(plaintext); - TEST_ASSERT_NOT_NULL(ciphertext); - TEST_ASSERT_NOT_NULL(decryptedtext); - uint8_t iv[iv_SZ]; - - memset(plaintext, 0x3A, SZ); - memset(decryptedtext, 0x0, SZ); - - /* Import a key */ - psa_key_id_t key_id; - psa_algorithm_t alg = PSA_ALG_CTR; - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); - psa_set_key_algorithm(&attributes, alg); - psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attributes, sizeof(key_256) * 8); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_import_key(&attributes, key_256, sizeof(key_256), &key_id)); - - psa_reset_key_attributes(&attributes); - - /* Encrypt */ - psa_cipher_operation_t enc_op = PSA_CIPHER_OPERATION_INIT; - size_t out_len, total_out_len = 0; - - memset(iv, 0x3B, iv_SZ); // Initialize IV with known value - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_encrypt_setup(&enc_op, key_id, alg)); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_set_iv(&enc_op, iv, iv_SZ)); - for (size_t offset = 0; offset < SZ; offset += part_size) { - size_t this_part = SZ - offset < part_size ? SZ - offset : part_size; - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_update(&enc_op, plaintext + offset, this_part, - ciphertext + offset, this_part, &out_len)); - total_out_len += out_len; - } - - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_finish(&enc_op, ciphertext + total_out_len, - SZ - total_out_len, &out_len)); - total_out_len += out_len; - TEST_ASSERT_EQUAL_size_t(SZ, total_out_len); - - /* Decrypt */ - psa_cipher_operation_t dec_op = PSA_CIPHER_OPERATION_INIT; - total_out_len = 0; - - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_decrypt_setup(&dec_op, key_id, alg)); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_set_iv(&dec_op, iv, iv_SZ)); - - for (size_t offset = 0; offset < SZ; offset += part_size) { - size_t this_part = SZ - offset < part_size ? SZ - offset : part_size; - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_update(&dec_op, ciphertext + offset, this_part, - decryptedtext + offset, this_part, &out_len)); - total_out_len += out_len; - } - - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_finish(&dec_op, decryptedtext + total_out_len, - SZ - total_out_len, &out_len)); - total_out_len += out_len; - TEST_ASSERT_EQUAL_size_t(SZ, total_out_len); - - TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); - - free(plaintext); - free(ciphertext); - free(decryptedtext); - - psa_cipher_abort(&enc_op); - psa_cipher_abort(&dec_op); - - /* Destroy the key */ - psa_destroy_key(key_id); -} +static const uint8_t iv[] = { + 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, + 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, +}; TEST_CASE("PSA AES-ECB multipart", "[psa-aes]") { @@ -182,6 +126,135 @@ TEST_CASE("PSA AES-ECB multipart", "[psa-aes]") psa_destroy_key(key_id); } +/* Cipher produced via this Python: + from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + from cryptography.hazmat.backends import default_backend + + def as_c_array(byte_arr): + + hex_str = '' + for idx, byte in enumerate(byte_arr): + hex_str += "0x{:02x}, ".format(byte) + bytes_per_line = 8 + if idx % bytes_per_line == bytes_per_line - 1: + hex_str += '\n' + + return hex_str + + key = bytearray(range(32)) + iv = bytearray(range(16, 0, -1)) + + print("Key: \n{}".format(as_c_array(key))) + print("IV: \n{}".format(as_c_array(iv))) + + # Replace CTR with desired mode + cipher = Cipher(algorithms.AES(key), modes.CTR(iv), backend=default_backend()) + encryptor = cipher.encryptor() + + input_len = 1000 + + plain = b'\x3A'*input_len + print(as_c_array(plain)) + ct = encryptor.update(plain) + encryptor.finalize() + + print("Ciphertext: {}".format(as_c_array(ct))) +*/ + +static void aes_cbc_test(unsigned int SZ) +{ + psa_key_id_t key_id; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; + uint8_t nonce[16]; + psa_status_t status; + size_t output_len, total_output_len; + + const uint8_t expected_cipher_end[] = { + 0x3e, 0x68, 0x8a, 0x02, 0xe6, 0xf2, 0x6a, 0x9e, + 0x9b, 0xb2, 0xc0, 0xc4, 0x63, 0x63, 0xd9, 0x25, + 0x51, 0xdc, 0xc2, 0x71, 0x96, 0xb3, 0xe5, 0xcd, + 0xbd, 0x0e, 0xf2, 0xef, 0xa9, 0xab, 0xab, 0x2d, + }; + + memcpy(nonce, iv, 16); + + // allocate internal memory + uint8_t *ciphertext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + uint8_t *plaintext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + uint8_t *decryptedtext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + + TEST_ASSERT_NOT_NULL(ciphertext); + TEST_ASSERT_NOT_NULL(plaintext); + TEST_ASSERT_NOT_NULL(decryptedtext); + + memset(plaintext, 0x3A, SZ); + memset(decryptedtext, 0x0, SZ); + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Set up key attributes + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_CBC_NO_PADDING); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 256); + + // Import key + status = psa_import_key(&attributes, key_256, 32, &key_id); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Encrypt + status = psa_cipher_encrypt_setup(&operation, key_id, PSA_ALG_CBC_NO_PADDING); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_update(&operation, plaintext, SZ, ciphertext, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len = output_len; + + status = psa_cipher_finish(&operation, ciphertext + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len += output_len; + + TEST_ASSERT_EQUAL(SZ, total_output_len); + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_cipher_end, ciphertext + SZ - 32, 32); + + // Decrypt + psa_cipher_abort(&operation); + operation = (psa_cipher_operation_t)PSA_CIPHER_OPERATION_INIT; + memcpy(nonce, iv, 16); + + status = psa_cipher_decrypt_setup(&operation, key_id, PSA_ALG_CBC_NO_PADDING); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_update(&operation, ciphertext, SZ, decryptedtext, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len = output_len; + + status = psa_cipher_finish(&operation, decryptedtext + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len += output_len; + + TEST_ASSERT_EQUAL(SZ, total_output_len); + TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); + + psa_destroy_key(key_id); + free(plaintext); + free(ciphertext); + free(decryptedtext); +} + +TEST_CASE("mbedtls CBC AES-256 test", "[aes]") +{ + aes_cbc_test(TEST_AES_CBC_DMA_MODE_LEN); +} + TEST_CASE("PSA AES-CBC multipart", "[psa-aes]") { const size_t SZ = 112; // Multiple of block size (16) @@ -410,7 +483,195 @@ TEST_CASE("PSA AES-CBC-PKCS7 multipart", "[psa-aes]") psa_destroy_key(key_id); } -TEST_CASE("PSA AES-CFB multipart", "[psa-aes]") +TEST_CASE("mbedtls CBC AES-256 DMA buffer align test", "[aes]") +{ +#define ALIGN_DOWN(val, align) ((val) & ~((align) - 1)) + // Size is taken considering the maximum DMA buffer size + const unsigned SZ = ALIGN_DOWN((2*LLDESC_MAX_NUM_PER_DESC), 16); + psa_key_id_t key_id; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; + uint8_t nonce[16]; + psa_status_t status; + size_t output_len, total_output_len; + + const uint8_t expected_cipher_end[] = { + 0x9e, 0xcb, 0x1d, 0x24, 0x01, 0xc8, 0x3f, 0xba, + 0xde, 0x76, 0xea, 0x9c, 0xf3, 0x64, 0x23, 0x19, + 0x8c, 0x67, 0xd4, 0x1a, 0xd1, 0xe0, 0xbf, 0xc3, + 0xd2, 0xb8, 0x40, 0x95, 0x89, 0x41, 0x09, 0xdb, + }; + + memcpy(nonce, iv, 16); + + // allocate internal memory + uint8_t *ciphertext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + uint8_t *plaintext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + uint8_t *decryptedtext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + + TEST_ASSERT_NOT_NULL(ciphertext); + TEST_ASSERT_NOT_NULL(plaintext); + TEST_ASSERT_NOT_NULL(decryptedtext); + + memset(plaintext, 0x3A, SZ); + memset(decryptedtext, 0x0, SZ); + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Set up key attributes + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_CBC_NO_PADDING); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 256); + + // Import key + status = psa_import_key(&attributes, key_256, 32, &key_id); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Encrypt + status = psa_cipher_encrypt_setup(&operation, key_id, PSA_ALG_CBC_NO_PADDING); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_update(&operation, plaintext, SZ, ciphertext, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len = output_len; + + status = psa_cipher_finish(&operation, ciphertext + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len += output_len; + + TEST_ASSERT_EQUAL(SZ, total_output_len); + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_cipher_end, ciphertext + SZ - 32, 32); + + // Decrypt + psa_cipher_abort(&operation); + operation = (psa_cipher_operation_t)PSA_CIPHER_OPERATION_INIT; + memcpy(nonce, iv, 16); + + status = psa_cipher_decrypt_setup(&operation, key_id, PSA_ALG_CBC_NO_PADDING); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_update(&operation, ciphertext, SZ, decryptedtext, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len = output_len; + + status = psa_cipher_finish(&operation, decryptedtext + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len += output_len; + + TEST_ASSERT_EQUAL(SZ, total_output_len); + TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); + + psa_destroy_key(key_id); + free(plaintext); + free(ciphertext); + free(decryptedtext); +} + +static void aes_ctr_test(unsigned int SZ) +{ + psa_key_id_t key_id; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; + uint8_t nonce[16]; + psa_status_t status; + size_t output_len, total_output_len; + + const uint8_t expected_cipher_end[] = { + 0xd4, 0xdc, 0x4f, 0x8f, 0xfe, 0x86, 0xee, 0xb5, + 0x14, 0x7f, 0xba, 0x30, 0x25, 0xa6, 0x7f, 0x6c, + 0xb5, 0x73, 0xaf, 0x90, 0xd7, 0xff, 0x36, 0xba, + 0x2b, 0x1d, 0xec, 0xb9, 0x38, 0xfa, 0x0d, 0xeb, + }; + + memcpy(nonce, iv, 16); + + // allocate internal memory + uint8_t *ciphertext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + uint8_t *plaintext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + uint8_t *decryptedtext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + + TEST_ASSERT_NOT_NULL(ciphertext); + TEST_ASSERT_NOT_NULL(plaintext); + TEST_ASSERT_NOT_NULL(decryptedtext); + + memset(plaintext, 0x3A, SZ); + memset(decryptedtext, 0x0, SZ); + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Set up key attributes + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_CTR); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 256); + + // Import key + status = psa_import_key(&attributes, key_256, 32, &key_id); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Encrypt + status = psa_cipher_encrypt_setup(&operation, key_id, PSA_ALG_CTR); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_update(&operation, plaintext, SZ, ciphertext, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len = output_len; + + status = psa_cipher_finish(&operation, ciphertext + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len += output_len; + + TEST_ASSERT_EQUAL(SZ, total_output_len); + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_cipher_end, ciphertext + SZ - 32, 32); + + // Decrypt + psa_cipher_abort(&operation); + operation = (psa_cipher_operation_t)PSA_CIPHER_OPERATION_INIT; + memcpy(nonce, iv, 16); + + status = psa_cipher_decrypt_setup(&operation, key_id, PSA_ALG_CTR); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_update(&operation, ciphertext, SZ, decryptedtext, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len = output_len; + + status = psa_cipher_finish(&operation, decryptedtext + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len += output_len; + + TEST_ASSERT_EQUAL(SZ, total_output_len); + TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); + + psa_destroy_key(key_id); + free(plaintext); + free(ciphertext); + free(decryptedtext); +} + +TEST_CASE("mbedtls CTR AES-256 test", "[aes]") +{ + aes_ctr_test(TEST_AES_CTR_DMA_MODE_LEN); +} + +TEST_CASE("PSA AES-CTR multipart", "[psa-aes]") { const size_t SZ = 100; const size_t iv_SZ = 16; @@ -419,6 +680,10 @@ TEST_CASE("PSA AES-CFB multipart", "[psa-aes]") uint8_t *plaintext = malloc(SZ); uint8_t *ciphertext = malloc(SZ); uint8_t *decryptedtext = malloc(SZ); + + TEST_ASSERT_NOT_NULL(plaintext); + TEST_ASSERT_NOT_NULL(ciphertext); + TEST_ASSERT_NOT_NULL(decryptedtext); uint8_t iv[iv_SZ]; memset(plaintext, 0x3A, SZ); @@ -426,7 +691,7 @@ TEST_CASE("PSA AES-CFB multipart", "[psa-aes]") /* Import a key */ psa_key_id_t key_id; - psa_algorithm_t alg = PSA_ALG_CFB; + psa_algorithm_t alg = PSA_ALG_CTR; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); psa_set_key_algorithm(&attributes, alg); @@ -487,6 +752,101 @@ TEST_CASE("PSA AES-CFB multipart", "[psa-aes]") psa_destroy_key(key_id); } +static void aes_ofb_test(unsigned int SZ) +{ + psa_key_id_t key_id; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; + uint8_t nonce[16]; + psa_status_t status; + size_t output_len, total_output_len; + + const uint8_t expected_cipher_end[] = { + 0xca, 0xc3, 0x05, 0x77, 0xae, 0xb9, 0x38, 0xd6, + 0x03, 0x0a, 0xad, 0x90, 0x6e, 0xdd, 0xf3, 0x9a, + 0x41, 0x4d, 0x71, 0x30, 0x04, 0x9f, 0xd3, 0x53, + 0xb7, 0x5e, 0xb4, 0xfd, 0x93, 0xf8, 0x31, 0x6a, + }; + + memcpy(nonce, iv, 16); + + // allocate internal memory + uint8_t *ciphertext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + uint8_t *plaintext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + uint8_t *decryptedtext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + + TEST_ASSERT_NOT_NULL(ciphertext); + TEST_ASSERT_NOT_NULL(plaintext); + TEST_ASSERT_NOT_NULL(decryptedtext); + + memset(plaintext, 0x3A, SZ); + memset(decryptedtext, 0x0, SZ); + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Set up key attributes + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_OFB); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 256); + + // Import key + status = psa_import_key(&attributes, key_256, 32, &key_id); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Encrypt + status = psa_cipher_encrypt_setup(&operation, key_id, PSA_ALG_OFB); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_update(&operation, plaintext, SZ, ciphertext, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len = output_len; + + status = psa_cipher_finish(&operation, ciphertext + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len += output_len; + + TEST_ASSERT_EQUAL(SZ, total_output_len); + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_cipher_end, ciphertext + SZ - 32, 32); + + // Decrypt + psa_cipher_abort(&operation); + operation = (psa_cipher_operation_t)PSA_CIPHER_OPERATION_INIT; + memcpy(nonce, iv, 16); + + status = psa_cipher_decrypt_setup(&operation, key_id, PSA_ALG_OFB); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_update(&operation, ciphertext, SZ, decryptedtext, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len = output_len; + + status = psa_cipher_finish(&operation, decryptedtext + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len += output_len; + + TEST_ASSERT_EQUAL(SZ, total_output_len); + TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); + + psa_destroy_key(key_id); + free(plaintext); + free(ciphertext); + free(decryptedtext); +} + +TEST_CASE("mbedtls OFB AES-256 test", "[aes]") +{ + aes_ofb_test(TEST_AES_OFB_DMA_MODE_LEN); +} + TEST_CASE("PSA AES-OFB multipart", "[psa-aes]") { const size_t SZ = 100; @@ -564,12 +924,222 @@ TEST_CASE("PSA AES-OFB multipart", "[psa-aes]") psa_destroy_key(key_id); } -TEST_CASE("PSA AES-CTR streaming chunk invariance", "[psa-aes]") +// CFB8 is not supported by the PSA Crypto API +#if 0 +static void aes_cfb8_test(unsigned int SZ) { - const size_t SZ = 100; - const size_t iv_SZ = 16; + psa_key_id_t key_id; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; + uint8_t nonce[16]; + psa_status_t status; + size_t output_len, total_output_len; - // Vectors match legacy mbedtls CTR stream test + const uint8_t expected_cipher_end[] = { + 0x69, 0xdc, 0x1d, 0x8a, 0x0b, 0x9e, 0xbc, 0x84, + 0x29, 0xa2, 0x04, 0xb6, 0x91, 0x6b, 0xb2, 0x83, + 0x13, 0x23, 0x54, 0xcb, 0xf9, 0x6d, 0xcc, 0x53, + 0x04, 0x59, 0xd1, 0xc9, 0xff, 0xab, 0xe2, 0x37, + }; + + memcpy(nonce, iv, 16); + + // allocate internal memory + uint8_t *ciphertext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + uint8_t *plaintext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + uint8_t *decryptedtext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + + TEST_ASSERT_NOT_NULL(ciphertext); + TEST_ASSERT_NOT_NULL(plaintext); + TEST_ASSERT_NOT_NULL(decryptedtext); + + memset(plaintext, 0x3A, SZ); + memset(decryptedtext, 0x0, SZ); + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Set up key attributes + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_CFB); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 256); + + // Import key + status = psa_import_key(&attributes, key_256, 32, &key_id); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Encrypt + status = psa_cipher_encrypt_setup(&operation, key_id, PSA_ALG_CFB); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_update(&operation, plaintext, SZ, ciphertext, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len = output_len; + + status = psa_cipher_finish(&operation, ciphertext + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len += output_len; + + TEST_ASSERT_EQUAL(SZ, total_output_len); + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_cipher_end, ciphertext + SZ - 32, 32); + + // Decrypt + psa_cipher_abort(&operation); + operation = (psa_cipher_operation_t)PSA_CIPHER_OPERATION_INIT; + memcpy(nonce, iv, 16); + + status = psa_cipher_decrypt_setup(&operation, key_id, PSA_ALG_CFB); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_update(&operation, ciphertext, SZ, decryptedtext, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len = output_len; + + status = psa_cipher_finish(&operation, decryptedtext + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len += output_len; + + TEST_ASSERT_EQUAL(SZ, total_output_len); + TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); + + psa_destroy_key(key_id); + free(plaintext); + free(ciphertext); + free(decryptedtext); +} +TEST_CASE("mbedtls CFB-8 AES-256 test", "[aes]") +{ + aes_cfb8_test(TEST_AES_CFB8_DMA_MODE_LEN); +} +#endif + +static void aes_cfb128_test(unsigned int SZ) +{ + psa_key_id_t key_id; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; + uint8_t nonce[16]; + psa_status_t status; + size_t output_len, total_output_len; + + const uint8_t expected_cipher_end[] = { + 0xf3, 0x64, 0x20, 0xa1, 0x70, 0x2a, 0xd9, 0x3f, + 0xb7, 0x48, 0x8c, 0x2c, 0x1f, 0x65, 0x53, 0xc2, + 0xac, 0xfd, 0x82, 0xe5, 0x31, 0x24, 0x1f, 0x30, + 0xaf, 0xcc, 0x8d, 0xb3, 0xf3, 0x63, 0xe1, 0xa0, + }; + + memcpy(nonce, iv, 16); + + // allocate internal memory + uint8_t *ciphertext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + uint8_t *plaintext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + uint8_t *decryptedtext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + + TEST_ASSERT_NOT_NULL(ciphertext); + TEST_ASSERT_NOT_NULL(plaintext); + TEST_ASSERT_NOT_NULL(decryptedtext); + + memset(plaintext, 0x3A, SZ); + memset(decryptedtext, 0x0, SZ); + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Set up key attributes + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_CFB); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 256); + + // Import key + status = psa_import_key(&attributes, key_256, 32, &key_id); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Encrypt + status = psa_cipher_encrypt_setup(&operation, key_id, PSA_ALG_CFB); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_update(&operation, plaintext, SZ, ciphertext, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len = output_len; + + status = psa_cipher_finish(&operation, ciphertext + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len += output_len; + + TEST_ASSERT_EQUAL(SZ, total_output_len); + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_cipher_end, ciphertext + SZ - 32, 32); + + // Decrypt + psa_cipher_abort(&operation); + operation = (psa_cipher_operation_t)PSA_CIPHER_OPERATION_INIT; + memcpy(nonce, iv, 16); + + status = psa_cipher_decrypt_setup(&operation, key_id, PSA_ALG_CFB); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_update(&operation, ciphertext, SZ, decryptedtext, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len = output_len; + + status = psa_cipher_finish(&operation, decryptedtext + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output_len += output_len; + + TEST_ASSERT_EQUAL(SZ, total_output_len); + TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); + + psa_destroy_key(key_id); + free(plaintext); + free(ciphertext); + free(decryptedtext); +} + +TEST_CASE("mbedtls CFB-128 AES-256 test", "[aes]") +{ + aes_cfb128_test(TEST_AES_CFB128_DMA_MODE_LEN); +} + +static void aes_ctr_stream_test(uint32_t input_buf_caps, uint32_t output_buf_caps, unsigned int SZ) +{ + psa_key_id_t key_id; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + uint8_t nonce[16]; + uint8_t key[16]; + psa_status_t status; + + /* Cipher produced via this Python: + import os, binascii + from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + from cryptography.hazmat.backends import default_backend + key = b'\x44' * 16 + nonce = b'\xee' * 16 + cipher = Cipher(algorithms.AES(key), modes.CTR(nonce), backend=default_backend()) + encryptor = cipher.encryptor() + ct = encryptor.update(b'\xaa' * 1000) + encryptor.finalize() + ct_arr = "" + for idx, b in enumerate(ct): + if idx % 8 == 0: + ct_arr += '\n' + ct_arr += "0x{}, ".format(format(b, '02x')) + print(ct_arr) + */ const uint8_t expected_cipher[] = { 0xc5, 0x78, 0xa7, 0xb4, 0xf3, 0xb9, 0xcb, 0x8b, 0x09, 0xe0, 0xd6, 0x89, 0x14, 0x6a, 0x19, 0x09, @@ -583,85 +1153,254 @@ TEST_CASE("PSA AES-CTR streaming chunk invariance", "[psa-aes]") 0xd0, 0x5e, 0xe5, 0x3f, 0xc5, 0xed, 0x5c, 0x18, 0xa7, 0x84, 0xd8, 0xdf, 0x9d, 0xb5, 0x06, 0xb1, 0xa7, 0xcf, 0x2e, 0x7a, 0x51, 0xfc, 0x44, 0xc5, - 0xb9, 0x5f, 0x22, 0x47, + 0xb9, 0x5f, 0x22, 0x47, 0x91, 0xbd, 0x67, 0x89, + 0x15, 0xcd, 0x6a, 0xac, 0xa7, 0x8f, 0x6c, 0xff, + 0x64, 0xc4, 0xbd, 0x53, 0xb6, 0x24, 0x13, 0xd4, + 0x30, 0x3e, 0x80, 0xb9, 0x5f, 0xf6, 0x79, 0x4c, + 0x3c, 0x11, 0xce, 0x45, 0xb2, 0x4b, 0x70, 0x2d, + 0x73, 0xc8, 0x0d, 0x4c, 0x82, 0xa6, 0x8a, 0xe2, + 0x4e, 0x56, 0x07, 0xdf, 0xaf, 0x2a, 0x15, 0x08, + 0xef, 0x5d, 0x96, 0x69, 0xe9, 0xe7, 0xc0, 0x1f, + 0x7b, 0x67, 0x68, 0xaf, 0xe9, 0x9c, 0xb4, 0x15, + 0x49, 0x95, 0x1a, 0x71, 0xb3, 0x7b, 0x4b, 0x26, + 0xf1, 0x9e, 0x72, 0xf3, 0xa5, 0x24, 0x46, 0x96, + 0xda, 0x11, 0xd5, 0xa7, 0x05, 0xc4, 0x36, 0x11, + 0xb2, 0x01, 0x5d, 0xe8, 0x67, 0xe6, 0x4a, 0xe7, + 0x44, 0x22, 0xb9, 0xa8, 0x8f, 0x26, 0x62, 0x80, + 0x3e, 0xf5, 0xfe, 0x51, 0x46, 0x20, 0x23, 0x1b, + 0x97, 0xb4, 0x6e, 0x5c, 0xe9, 0x3e, 0xe3, 0x79, + 0xf4, 0xd0, 0xc6, 0x81, 0x59, 0x8d, 0x99, 0x55, + 0x12, 0x37, 0x55, 0x28, 0xda, 0x3d, 0x70, 0xc9, + 0x6a, 0xb9, 0xd7, 0xee, 0x55, 0x35, 0x0f, 0x96, + 0xde, 0x19, 0x6f, 0x44, 0xba, 0x66, 0x9b, 0xdd, + 0x5a, 0x7b, 0xc6, 0x45, 0xf8, 0x6e, 0x8b, 0xa1, + 0xf1, 0xe1, 0x44, 0x33, 0xe9, 0x10, 0x81, 0xed, + 0xba, 0x21, 0xf3, 0x01, 0xab, 0x78, 0x7d, 0x64, + 0x05, 0xda, 0xc7, 0xce, 0x34, 0x8d, 0x74, 0xef, + 0x22, 0xa8, 0x77, 0xc4, 0x43, 0x06, 0xcd, 0x29, + 0xfb, 0xc8, 0x20, 0x13, 0xbb, 0x41, 0xf2, 0x5c, + 0x3b, 0x99, 0x2e, 0xbe, 0xb0, 0xaa, 0x78, 0xd8, + 0xfa, 0xcd, 0x28, 0x30, 0x23, 0xc2, 0xd3, 0xb4, + 0x63, 0x0d, 0x46, 0x14, 0xa1, 0x73, 0xb7, 0xed, + 0xf8, 0xb8, 0x38, 0x0e, 0xde, 0x6a, 0x8a, 0x11, + 0x35, 0x7e, 0xe6, 0x55, 0x2d, 0xe8, 0xa1, 0xa1, + 0xa0, 0x79, 0x8a, 0x47, 0x50, 0xbe, 0x13, 0x93, + 0x05, 0x6c, 0x52, 0x7d, 0x41, 0x79, 0xcd, 0x64, + 0x45, 0x3e, 0xce, 0xa3, 0xa8, 0xf2, 0xa6, 0x0c, + 0xee, 0xf2, 0x13, 0xaa, 0x5d, 0xdc, 0x59, 0x5a, + 0x7a, 0x96, 0x1f, 0xe0, 0xcc, 0x10, 0x46, 0xcd, + 0xfa, 0x9d, 0x85, 0x25, 0xd0, 0x48, 0x2d, 0xb1, + 0x34, 0x81, 0xce, 0xd1, 0xae, 0x4d, 0xd8, 0x6f, + 0xea, 0xbe, 0x42, 0x68, 0x5a, 0xa5, 0x63, 0x68, + 0x86, 0x8a, 0x39, 0x78, 0x2f, 0x66, 0xd9, 0x85, + 0xbf, 0x88, 0x9a, 0x7e, 0xc7, 0xc2, 0x3a, 0xeb, + 0x5e, 0xc8, 0x3c, 0x35, 0xf2, 0xfc, 0x68, 0x21, + 0xca, 0x75, 0xbb, 0x3d, 0x53, 0x02, 0xe8, 0xb1, + 0xba, 0x57, 0x92, 0xd3, 0x8d, 0x69, 0xe7, 0x23, + 0x8f, 0xea, 0xf0, 0xf2, 0x4d, 0xde, 0x9d, 0x2a, + 0xab, 0x3a, 0x90, 0x10, 0x5f, 0x29, 0x19, 0x1a, + 0xf7, 0x02, 0x0a, 0x57, 0x3f, 0x39, 0x7a, 0xd9, + 0xf4, 0x75, 0x95, 0x6c, 0xce, 0x2e, 0xa1, 0xb9, + 0x0d, 0x78, 0x03, 0x42, 0xec, 0x5b, 0x60, 0xcb, + 0xb5, 0x06, 0xde, 0x6e, 0xec, 0x6e, 0x2d, 0x62, + 0x78, 0x1e, 0x8c, 0x40, 0x02, 0x52, 0xeb, 0xe9, + 0xe9, 0x39, 0xea, 0xee, 0x7f, 0xa0, 0x6c, 0x2e, + 0x93, 0x2a, 0xe4, 0xaf, 0x05, 0xa7, 0xa9, 0xc5, + 0x2a, 0x44, 0x6d, 0x5a, 0x46, 0x41, 0x03, 0x85, + 0x4c, 0x27, 0xb5, 0x83, 0xfd, 0xb9, 0xb9, 0x68, + 0x35, 0x26, 0xae, 0xcc, 0xca, 0x59, 0xa2, 0xe8, + 0x9d, 0xa5, 0xde, 0x90, 0x4f, 0xef, 0x8c, 0x92, + 0x11, 0x9f, 0x69, 0xd9, 0x66, 0x1c, 0xee, 0x83, + 0xe3, 0xe9, 0x60, 0x05, 0x0b, 0x43, 0x2b, 0x82, + 0xd7, 0x59, 0xdf, 0xb4, 0x1f, 0x19, 0x1b, 0xbe, + 0x30, 0x98, 0x71, 0x7e, 0xb9, 0xc0, 0xf5, 0xe2, + 0x08, 0xf4, 0x58, 0x42, 0x8a, 0x5b, 0xbb, 0x45, + 0xcf, 0x10, 0x89, 0xdf, 0xec, 0x97, 0x1a, 0x2f, + 0xac, 0xd7, 0xce, 0xd0, 0x62, 0x84, 0x6b, 0xa2, + 0xb6, 0xa8, 0x1b, 0xce, 0x7d, 0x68, 0xac, 0x31, + 0x30, 0x41, 0x09, 0x53, 0xaf, 0x53, 0x41, 0x8e, + 0xef, 0x34, 0x0f, 0x4a, 0xf2, 0xaa, 0x42, 0xc1, + 0x9e, 0x68, 0xf6, 0xda, 0xb0, 0x5d, 0xa8, 0x40, + 0xa5, 0x1f, 0x1d, 0x5f, 0x73, 0xfb, 0x2c, 0x82, + 0x42, 0x24, 0x70, 0xce, 0x30, 0x95, 0x69, 0xd1, + 0xed, 0xa5, 0xd9, 0xd0, 0xab, 0xb8, 0x9d, 0x8a, + 0x4d, 0xa0, 0x89, 0xb1, 0xaf, 0x93, 0x28, 0x59, + 0xfc, 0x6f, 0x5a, 0x97, 0x9a, 0xe9, 0x02, 0x8e, + 0xa1, 0x4e, 0x72, 0xde, 0x53, 0x5a, 0x0b, 0x42, + 0x72, 0x38, 0x41, 0x5f, 0x0c, 0x51, 0xac, 0xa8, + 0xb5, 0x17, 0x32, 0x1e, 0x18, 0xd6, 0x54, 0x67, + 0x0e, 0xc6, 0x43, 0xd0, 0xe0, 0xb6, 0xac, 0x40, + 0xfa, 0xaa, 0x76, 0xe3, 0x8d, 0xdb, 0x8a, 0x4a, + 0xa9, 0x09, 0xbb, 0x65, 0xd5, 0xca, 0xaa, 0xf5, + 0x0b, 0x63, 0xe0, 0x24, 0x79, 0x56, 0xd8, 0x1f, + 0x58, 0xc4, 0xc6, 0x31, 0x56, 0xfe, 0xba, 0xd6, + 0x85, 0xbd, 0x89, 0x92, 0x66, 0xff, 0xf1, 0xaf, + 0x52, 0x35, 0x1e, 0xa6, 0xa5, 0xcc, 0x9a, 0xc1, + 0x3b, 0x61, 0x72, 0x90, 0xaf, 0xab, 0x04, 0xbb, + 0xc0, 0x9a, 0xd1, 0xb9, 0xc0, 0x1b, 0x6b, 0xd0, + 0x6d, 0x95, 0x17, 0x43, 0x2b, 0x78, 0xaa, 0x52, + 0xc1, 0x57, 0x3f, 0xa5, 0xaa, 0x2d, 0xd7, 0x6c, + 0xf7, 0x97, 0x13, 0xb0, 0x99, 0xdb, 0x3f, 0xef, + 0xb8, 0xb0, 0xa6, 0x14, 0xbd, 0xea, 0xc2, 0x0a, + 0x84, 0x56, 0xf8, 0x2b, 0xa3, 0xdc, 0x48, 0xd1, + 0x75, 0xa2, 0xa8, 0x2a, 0xdc, 0xa8, 0x70, 0xe4, + 0xc1, 0x92, 0xb8, 0x71, 0x67, 0x51, 0x92, 0xbb, + 0x7d, 0xba, 0x78, 0xed, 0x93, 0x99, 0x0e, 0x56, + 0x2d, 0xe3, 0x43, 0x7d, 0xee, 0x02, 0x51, 0x15, + 0x64, 0x1e, 0x13, 0x04, 0xbb, 0xa0, 0xb4, 0x0c, + 0xb7, 0x30, 0xbb, 0x1f, 0x93, 0x30, 0x4e, 0x99, + 0xad, 0x4f, 0xce, 0x0b, 0xa1, 0x7f, 0xdf, 0x66, + 0x44, 0xb0, 0x49, 0x2c, 0x16, 0x9e, 0x22, 0x9b, + 0x88, 0xf0, 0x2b, 0x7d, 0xdd, 0x46, 0x50, 0x27, + 0xef, 0x61, 0x7b, 0xe2, 0xd8, 0xfd, 0x42, 0x10, + 0xeb, 0x07, 0xdf, 0x31, 0xf2, 0xb9, 0xab, 0xba, + 0x04, 0x95, 0xa7, 0xb3, 0x74, 0x71, 0xa8, 0x34, + 0x31, 0x95, 0xd6, 0x9a, 0x01, 0xd8, 0xab, 0x94, + 0xcc, 0x38, 0x8d, 0xb1, 0xa2, 0xe4, 0xeb, 0x86, + 0xbc, 0x84, 0x22, 0x23, 0xc2, 0xf3, 0x48, 0xaa, + 0xb9, 0x70, 0xd4, 0x20, 0x3c, 0xef, 0x61, 0xe2, + 0x10, 0x7c, 0x03, 0x6a, 0x8b, 0xab, 0x6b, 0xce, + 0xa2, 0x38, 0xaa, 0xc1, 0x43, 0x5c, 0x9b, 0x06, + 0x1e, 0x55, 0x13, 0x49, 0x36, 0x35, 0x6e, 0x10, + 0x56, 0xe2, 0x0c, 0xe2, 0x2f, 0xb9, 0x67, 0xc6, + 0xb0, 0x61, 0xd9, 0x1d, 0x81, 0xb9, 0x47, 0x64, + 0xd3, 0x7a, 0x55, 0x56, 0x6c, 0xf5, 0x15, 0xc8, + 0x23, 0xdc, 0x5f, 0xf9, 0xff, 0xba, 0x28, 0xe4, }; - uint8_t key[16]; - uint8_t iv[iv_SZ]; - uint8_t *plaintext = malloc(SZ); - uint8_t *ciphertext = malloc(SZ); - uint8_t *decryptedtext = malloc(SZ); + memset(nonce, 0xEE, 16); + memset(key, 0x44, 16); + + // allocate internal memory + uint8_t *ciphertext = heap_caps_malloc(SZ, input_buf_caps); + uint8_t *plaintext = heap_caps_malloc(SZ, output_buf_caps); + uint8_t *decryptedtext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + + TEST_ASSERT_NOT_NULL(ciphertext); + TEST_ASSERT_NOT_NULL(plaintext); + TEST_ASSERT_NOT_NULL(decryptedtext); - memset(key, 0x44, sizeof(key)); - memset(iv, 0xEE, iv_SZ); memset(plaintext, 0xAA, SZ); - psa_key_id_t key_id; - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Set up key attributes psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); psa_set_key_algorithm(&attributes, PSA_ALG_CTR); psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attributes, sizeof(key) * 8); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_import_key(&attributes, key, sizeof(key), &key_id)); - psa_reset_key_attributes(&attributes); + psa_set_key_bits(&attributes, 128); - for (size_t chunk = 1; chunk < SZ; chunk++) { - psa_cipher_operation_t enc_op = PSA_CIPHER_OPERATION_INIT; - size_t out_len = 0, total_out = 0; + // Import key + status = psa_import_key(&attributes, key, 16, &key_id); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - memset(iv, 0xEE, iv_SZ); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_encrypt_setup(&enc_op, key_id, PSA_ALG_CTR)); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_set_iv(&enc_op, iv, iv_SZ)); + /* Test that all the end results are the same + no matter how many bytes we encrypt each call + */ + for (int bytes_to_process = 1; bytes_to_process < SZ; bytes_to_process++) { + ESP_LOGD("test", "bytes_to_process %d", bytes_to_process); + memset(nonce, 0xEE, 16); + memset(ciphertext, 0x0, SZ); + memset(decryptedtext, 0x0, SZ); - for (size_t offset = 0; offset < SZ; offset += chunk) { - size_t this_part = SZ - offset < chunk ? SZ - offset : chunk; - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_update(&enc_op, plaintext + offset, this_part, - ciphertext + offset, this_part, &out_len)); - total_out += out_len; + size_t output_offset = 0; + size_t output_len; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; + + // Encrypt + status = psa_cipher_encrypt_setup(&operation, key_id, PSA_ALG_CTR); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + for (int idx = 0; idx < SZ; idx = idx + bytes_to_process) { + // Limit length of last call to avoid exceeding buffer size + size_t length = (idx + bytes_to_process > SZ) ? (SZ - idx) : bytes_to_process; + + status = psa_cipher_update(&operation, plaintext + idx, length, + ciphertext + output_offset, SZ - output_offset, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + output_offset += output_len; } - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_finish(&enc_op, ciphertext + total_out, - SZ - total_out, &out_len)); - total_out += out_len; - TEST_ASSERT_EQUAL_size_t(SZ, total_out); + status = psa_cipher_finish(&operation, ciphertext + output_offset, SZ - output_offset, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + output_offset += output_len; + + ESP_LOG_BUFFER_HEXDUMP("expected", expected_cipher, SZ, ESP_LOG_DEBUG); + ESP_LOG_BUFFER_HEXDUMP("actual ", ciphertext, SZ, ESP_LOG_DEBUG); + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_cipher, ciphertext, SZ); - psa_cipher_abort(&enc_op); + // Decrypt + memset(nonce, 0xEE, 16); + memset(decryptedtext, 0x22, SZ); + output_offset = 0; - psa_cipher_operation_t dec_op = PSA_CIPHER_OPERATION_INIT; - total_out = 0; - memset(iv, 0xEE, iv_SZ); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_decrypt_setup(&dec_op, key_id, PSA_ALG_CTR)); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_set_iv(&dec_op, iv, iv_SZ)); + psa_cipher_abort(&operation); + operation = (psa_cipher_operation_t)PSA_CIPHER_OPERATION_INIT; + status = psa_cipher_decrypt_setup(&operation, key_id, PSA_ALG_CTR); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - for (size_t offset = 0; offset < SZ; offset += chunk) { - size_t this_part = SZ - offset < chunk ? SZ - offset : chunk; - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_update(&dec_op, ciphertext + offset, this_part, - decryptedtext + offset, this_part, &out_len)); - total_out += out_len; + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + for (int idx = 0; idx < SZ; idx = idx + bytes_to_process) { + // Limit length of last call to avoid exceeding buffer size + size_t length = (idx + bytes_to_process > SZ) ? (SZ - idx) : bytes_to_process; + + status = psa_cipher_update(&operation, ciphertext + idx, length, + decryptedtext + output_offset, SZ - output_offset, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + output_offset += output_len; } - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_finish(&dec_op, decryptedtext + total_out, - SZ - total_out, &out_len)); - total_out += out_len; - TEST_ASSERT_EQUAL_size_t(SZ, total_out); - TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); + status = psa_cipher_finish(&operation, decryptedtext + output_offset, SZ - output_offset, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + output_offset += output_len; - psa_cipher_abort(&dec_op); + ESP_LOG_BUFFER_HEXDUMP("decrypted", decryptedtext, SZ, ESP_LOG_DEBUG); + TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); } + psa_destroy_key(key_id); free(plaintext); free(ciphertext); free(decryptedtext); - psa_destroy_key(key_id); } -TEST_CASE("PSA AES-OFB streaming chunk invariance", "[psa-aes]") +TEST_CASE("mbedtls CTR stream test", "[aes]") { - const size_t SZ = 100; - const size_t iv_SZ = 16; + aes_ctr_stream_test(INTERNAL_DMA_CAPS, INTERNAL_DMA_CAPS, TEST_AES_CTR_STREAM_DMA_MODE_LEN); +} - // Vectors match legacy mbedtls OFB stream test +static void aes_ofb_stream_test(unsigned int SZ) +{ + psa_key_id_t key_id; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + uint8_t iv[16]; + uint8_t key[16]; + psa_status_t status; + + /* Cipher produced via this Python: + import os, binascii + from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + from cryptography.hazmat.backends import default_backend + key = b'\x44' * 16 + iv = b'\xee' * 16 + cipher = Cipher(algorithms.AES(key), modes.OFB(iv), backend=default_backend()) + encryptor = cipher.encryptor() + ct = encryptor.update(b'\xaa' * 1000) + encryptor.finalize() + ct_arr = "" + for idx, b in enumerate(ct): + if idx % 8 == 0: + ct_arr += '\n' + ct_arr += "0x{}, ".format(format(b, '02x')) + print(ct_arr) + */ const uint8_t expected_cipher[] = { 0xc5, 0x78, 0xa7, 0xb4, 0xf3, 0xb9, 0xcb, 0x8b, 0x09, 0xe0, 0xd6, 0x89, 0x14, 0x6a, 0x19, 0x09, @@ -675,188 +1414,538 @@ TEST_CASE("PSA AES-OFB streaming chunk invariance", "[psa-aes]") 0x2a, 0x76, 0x80, 0x20, 0x82, 0x39, 0xa2, 0x21, 0xf8, 0x7a, 0xec, 0xae, 0x82, 0x6a, 0x5c, 0xd3, 0x04, 0xd9, 0xbd, 0xe4, 0x53, 0xc9, 0xdf, 0x67, - 0xaa, 0x5c, 0xaf, 0xa6, + 0xaa, 0x5c, 0xaf, 0xa6, 0x95, 0x84, 0x01, 0xae, + 0x62, 0x24, 0xc7, 0xf5, 0x44, 0x30, 0x9b, 0xea, + 0xd5, 0x53, 0x62, 0xd6, 0x0d, 0x7a, 0x00, 0x19, + 0x86, 0xab, 0x97, 0x7d, 0x28, 0xa9, 0x08, 0xc8, + 0x5e, 0x20, 0x2c, 0x79, 0x24, 0x62, 0x45, 0x3e, + 0x4a, 0x3c, 0x34, 0x73, 0xd3, 0x84, 0xa1, 0xc7, + 0xee, 0x32, 0xe6, 0x29, 0xa7, 0x28, 0x8b, 0x23, + 0x90, 0x7a, 0x51, 0x3d, 0xac, 0x78, 0x08, 0x7a, + 0x9d, 0x01, 0x2e, 0xc4, 0x78, 0xd3, 0x58, 0x1d, + 0x9b, 0x66, 0x67, 0x89, 0x83, 0xfe, 0x28, 0x04, + 0x7e, 0x19, 0x2b, 0x2d, 0xbc, 0x23, 0x36, 0x58, + 0xef, 0x0a, 0x55, 0x8c, 0x8c, 0xa8, 0x70, 0xc6, + 0xd6, 0x60, 0xfa, 0x00, 0x61, 0x72, 0x28, 0x39, + 0xa7, 0xa7, 0x53, 0x26, 0x2b, 0x92, 0x2f, 0x44, + 0xa7, 0xb7, 0x69, 0x2c, 0x2a, 0xef, 0xf1, 0x1d, + 0x04, 0x9f, 0x39, 0x8c, 0xd1, 0x00, 0xf6, 0x93, + 0xdd, 0xe3, 0xd2, 0x7e, 0x68, 0x1a, 0xac, 0x51, + 0x21, 0x3a, 0xfb, 0x7d, 0x58, 0x00, 0x38, 0xa4, + 0xbc, 0xd6, 0x9b, 0xb0, 0xfd, 0x5b, 0x99, 0x40, + 0x0e, 0x35, 0x87, 0x22, 0x59, 0x80, 0xc6, 0x7c, + 0x06, 0x35, 0x22, 0x18, 0x0d, 0xdb, 0x40, 0x8a, + 0xe7, 0x8e, 0x13, 0x4a, 0x8f, 0xe7, 0xe6, 0x5c, + 0x88, 0x21, 0xfa, 0xc1, 0xf2, 0xb0, 0x1e, 0x4a, + 0x49, 0x6d, 0x9c, 0x28, 0x79, 0xa9, 0x2c, 0xea, + 0xb6, 0x14, 0xb0, 0xc9, 0x7a, 0xfe, 0x45, 0x2d, + 0xec, 0xbf, 0x65, 0x51, 0x50, 0x34, 0xf8, 0x25, + 0x7d, 0x47, 0x58, 0xc5, 0x65, 0x88, 0x57, 0x2e, + 0xa5, 0x10, 0xf2, 0xe9, 0x18, 0x2c, 0x90, 0x1e, + 0xb2, 0xf5, 0x4e, 0xd0, 0xd8, 0x02, 0xed, 0x90, + 0xbb, 0x9e, 0xa9, 0x79, 0xbc, 0x5c, 0x4f, 0xb9, + 0xe3, 0x47, 0x75, 0xbe, 0xa7, 0x21, 0xaf, 0x9a, + 0x40, 0xc3, 0x86, 0x34, 0x0d, 0x06, 0xb6, 0x12, + 0xbf, 0x12, 0xee, 0x79, 0xdb, 0xca, 0x44, 0x1f, + 0xc6, 0x6d, 0xab, 0xa7, 0x9c, 0x37, 0x50, 0x5a, + 0x49, 0xff, 0xb4, 0xcf, 0x72, 0xb1, 0x47, 0xd2, + 0xaa, 0xbc, 0xb4, 0xd4, 0xb3, 0x5b, 0xdd, 0x16, + 0x76, 0xc1, 0x85, 0xd0, 0x7d, 0x1a, 0x27, 0xe4, + 0xc8, 0x7b, 0x30, 0x32, 0x5b, 0x6e, 0x51, 0x2d, + 0x00, 0x5a, 0x47, 0x80, 0xdb, 0xe9, 0x07, 0xff, + 0x63, 0xf1, 0x8b, 0xd3, 0x5a, 0xf5, 0xf4, 0x5b, + 0x6c, 0xba, 0x8e, 0x9e, 0x3c, 0x6e, 0x6e, 0xf6, + 0x0f, 0xc9, 0x42, 0xc9, 0xf9, 0x74, 0x87, 0x86, + 0xeb, 0x36, 0x01, 0x69, 0xa4, 0xae, 0x11, 0xfb, + 0x95, 0x7f, 0xe1, 0xc5, 0x6f, 0xe6, 0xe5, 0xfa, + 0x01, 0xb2, 0x82, 0x17, 0x41, 0x2f, 0x91, 0xb0, + 0x99, 0xbd, 0xfb, 0x38, 0xab, 0x7c, 0x31, 0xcf, + 0x7d, 0xbf, 0xb5, 0xee, 0xb0, 0x1c, 0x84, 0x0b, + 0xbc, 0xcd, 0xfa, 0x6f, 0xdb, 0xc1, 0x4d, 0x87, + 0xe7, 0x0a, 0xaf, 0x6b, 0xd3, 0xfc, 0xe0, 0x88, + 0xdc, 0xa5, 0x66, 0xe9, 0x94, 0xd0, 0x3e, 0x00, + 0xc8, 0xf6, 0xc2, 0x2d, 0x00, 0xbf, 0x09, 0x30, + 0xe5, 0x4f, 0xe7, 0x6b, 0x6b, 0x78, 0x68, 0xb6, + 0x9a, 0x45, 0x44, 0x37, 0x18, 0x77, 0xe4, 0xe1, + 0xb4, 0x5d, 0x74, 0x9e, 0xef, 0xaf, 0xe0, 0x10, + 0x48, 0x06, 0xff, 0xcc, 0xb2, 0x7b, 0xbc, 0x40, + 0x64, 0x94, 0x37, 0x60, 0x52, 0xaa, 0xe0, 0xad, + 0xf4, 0x05, 0xf9, 0x24, 0x1b, 0xf1, 0x46, 0x47, + 0x07, 0x42, 0xa4, 0xa6, 0x09, 0x04, 0x71, 0xa6, + 0x8d, 0x42, 0x2a, 0x38, 0x1b, 0x7d, 0xb9, 0x84, + 0xcd, 0xa1, 0x0d, 0x96, 0x11, 0xdb, 0x08, 0xe9, + 0x63, 0x39, 0xf8, 0x91, 0x26, 0x03, 0x01, 0x13, + 0xfb, 0xb2, 0xb6, 0xe5, 0xe0, 0xab, 0x65, 0x1b, + 0xc2, 0x99, 0x16, 0xd7, 0x74, 0xd6, 0x70, 0x39, + 0x43, 0x0e, 0xff, 0x62, 0xcc, 0x46, 0xba, 0x62, + 0x15, 0xba, 0xa8, 0x9d, 0xe6, 0x9d, 0x7b, 0xbc, + 0xfa, 0xb2, 0xde, 0xc5, 0x7a, 0xa2, 0x7a, 0x5f, + 0x1f, 0x66, 0x45, 0x2e, 0x1c, 0xfc, 0xc2, 0x53, + 0xfd, 0x7f, 0x1c, 0x14, 0x42, 0x91, 0x84, 0xea, + 0xaf, 0x6d, 0x95, 0x12, 0x71, 0xbf, 0x5f, 0xf2, + 0x68, 0x05, 0xa6, 0xa8, 0xcb, 0x6e, 0x07, 0x58, + 0xdb, 0xdc, 0x4d, 0x6c, 0x51, 0xa9, 0xe0, 0x93, + 0x7d, 0x00, 0x15, 0x27, 0x13, 0x62, 0x7c, 0xab, + 0x84, 0xf0, 0xbb, 0xb9, 0x50, 0x67, 0x96, 0x9d, + 0x48, 0xe3, 0x43, 0x5f, 0x8d, 0x1d, 0xf4, 0x03, + 0x58, 0xf1, 0xcb, 0x67, 0x6f, 0x5e, 0xb3, 0x4c, + 0x1f, 0x57, 0x9b, 0x29, 0xa6, 0x9b, 0xef, 0x39, + 0xf0, 0xa4, 0x85, 0x1b, 0x59, 0x51, 0x8a, 0x69, + 0x44, 0xcc, 0xeb, 0xf9, 0xf0, 0x01, 0xac, 0xdf, + 0x28, 0xdf, 0x46, 0x2a, 0x50, 0x57, 0xca, 0x21, + 0x93, 0x00, 0x9f, 0x3b, 0xed, 0x72, 0x9b, 0x37, + 0xcf, 0x6a, 0x8b, 0x6c, 0xe7, 0x59, 0xb5, 0x13, + 0x1f, 0x29, 0xf7, 0x89, 0x2d, 0xf4, 0x10, 0xdc, + 0x5d, 0x3e, 0xee, 0x01, 0x5e, 0x62, 0x62, 0xec, + 0x1b, 0x89, 0x2d, 0x3b, 0x9b, 0x5e, 0x48, 0x74, + 0xd4, 0xba, 0x78, 0xf4, 0xfa, 0xfb, 0x4c, 0x3b, + 0xa5, 0xb7, 0x69, 0xb0, 0x36, 0x68, 0xcd, 0x98, + 0xc9, 0x3f, 0x6a, 0x20, 0x10, 0xf6, 0x11, 0x2e, + 0x6d, 0x88, 0x37, 0x77, 0x92, 0xa3, 0x70, 0x16, + 0x41, 0x8c, 0x5f, 0x4a, 0x6f, 0x27, 0x50, 0x07, + 0x7e, 0xc5, 0x04, 0x27, 0xb3, 0xc3, 0x7d, 0xf6, + 0xe1, 0x04, 0xdd, 0xe3, 0xb9, 0xf7, 0x02, 0x74, + 0x5c, 0x00, 0xeb, 0xb5, 0x46, 0x19, 0x36, 0x6a, + 0x23, 0xd6, 0x1d, 0x2d, 0xee, 0xa5, 0x0f, 0x20, + 0x9d, 0xfa, 0x76, 0x57, 0x22, 0x17, 0xfa, 0x5a, + 0x5d, 0x63, 0x85, 0x46, 0x43, 0x10, 0xc2, 0xa7, + 0x05, 0x8c, 0x41, 0x14, 0x0c, 0xa1, 0xdf, 0x26, + 0xee, 0xd3, 0xc7, 0x06, 0x45, 0x54, 0xe3, 0xc5, + 0x7f, 0xfd, 0x52, 0xc3, 0xe8, 0xf9, 0x3a, 0x96, + 0xd7, 0x32, 0x38, 0xa9, 0xd3, 0x7e, 0x15, 0x16, + 0x3e, 0xcd, 0xcf, 0xd2, 0xea, 0x01, 0xd4, 0xc6, + 0x3a, 0x01, 0x4d, 0x0f, 0x64, 0xf9, 0xc1, 0xe0, + 0xf4, 0xcd, 0xc0, 0xe8, 0x50, 0x4f, 0x79, 0xb9, + 0x79, 0xae, 0x15, 0x1e, 0x6d, 0xf9, 0x2a, 0xca, + 0x37, 0x79, 0x34, 0x2b, 0x96, 0x18, 0x2c, 0x88, + 0x3f, 0x2b, 0xf1, 0x8d, 0x6d, 0x56, 0x60, 0xe8, + 0x36, 0x48, 0x0c, 0x0b, 0x78, 0x79, 0x71, 0x67, + 0xf2, 0x35, 0x2d, 0x4c, 0xf2, 0x9f, 0xc7, 0xce, + 0x4d, 0x36, 0x92, 0xeb, 0x81, 0x30, 0xac, 0xcf, + 0xbc, 0x34, 0x13, 0x42, 0x39, 0x74, 0x8f, 0x23, + 0x77, 0xd3, 0x2b, 0x7e, 0xd3, 0x5d, 0x0c, 0x36, + 0x73, 0x4b, 0x09, 0xb2, 0xc9, 0xd2, 0xd2, 0x07, + 0xda, 0xbd, 0x8f, 0x78, 0xb8, 0xdf, 0x29, 0xdb, + 0xe4, 0xbf, 0xcd, 0x23, 0x2f, 0x7a, 0x58, 0x86, }; - uint8_t key[16]; - uint8_t iv[iv_SZ]; - uint8_t *plaintext = malloc(SZ); - uint8_t *ciphertext = malloc(SZ); - uint8_t *decryptedtext = malloc(SZ); + memset(key, 0x44, 16); + + // allocate internal memory + uint8_t *ciphertext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + uint8_t *plaintext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + uint8_t *decryptedtext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + + TEST_ASSERT_NOT_NULL(ciphertext); + TEST_ASSERT_NOT_NULL(plaintext); + TEST_ASSERT_NOT_NULL(decryptedtext); - memset(key, 0x44, sizeof(key)); - memset(iv, 0xEE, iv_SZ); memset(plaintext, 0xAA, SZ); - psa_key_id_t key_id; - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Set up key attributes psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); psa_set_key_algorithm(&attributes, PSA_ALG_OFB); psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attributes, sizeof(key) * 8); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_import_key(&attributes, key, sizeof(key), &key_id)); - psa_reset_key_attributes(&attributes); + psa_set_key_bits(&attributes, 128); - for (size_t chunk = 1; chunk < SZ; chunk++) { - psa_cipher_operation_t enc_op = PSA_CIPHER_OPERATION_INIT; - size_t out_len = 0, total_out = 0; + // Import key + status = psa_import_key(&attributes, key, 16, &key_id); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - memset(iv, 0xEE, iv_SZ); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_encrypt_setup(&enc_op, key_id, PSA_ALG_OFB)); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_set_iv(&enc_op, iv, iv_SZ)); + /* Test that all the end results are the same + no matter how many bytes we encrypt each call + */ - for (size_t offset = 0; offset < SZ; offset += chunk) { - size_t this_part = SZ - offset < chunk ? SZ - offset : chunk; - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_update(&enc_op, plaintext + offset, this_part, - ciphertext + offset, this_part, &out_len)); - total_out += out_len; + for (int bytes_to_process = 1; bytes_to_process < SZ; bytes_to_process++) { + ESP_LOGD("test", "bytes_to_process %d", bytes_to_process); + // Encrypt + memset(iv, 0xEE, 16); + size_t output_offset = 0; + size_t output_len; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; + + status = psa_cipher_encrypt_setup(&operation, key_id, PSA_ALG_OFB); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, iv, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + for (int idx = 0; idx < SZ; idx = idx + bytes_to_process) { + // Limit length of last call to avoid exceeding buffer size + size_t length = ( (idx + bytes_to_process) > SZ) ? (SZ - idx) : bytes_to_process; + + status = psa_cipher_update(&operation, plaintext + idx, length, + ciphertext + output_offset, SZ - output_offset, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + output_offset += output_len; } - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_finish(&enc_op, ciphertext + total_out, - SZ - total_out, &out_len)); - total_out += out_len; - TEST_ASSERT_EQUAL_size_t(SZ, total_out); + status = psa_cipher_finish(&operation, ciphertext + output_offset, SZ - output_offset, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + output_offset += output_len; + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_cipher, ciphertext, SZ); - psa_cipher_abort(&enc_op); + // Decrypt + memset(iv, 0xEE, 16); + memset(decryptedtext, 0x22, SZ); + output_offset = 0; - psa_cipher_operation_t dec_op = PSA_CIPHER_OPERATION_INIT; - total_out = 0; - memset(iv, 0xEE, iv_SZ); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_decrypt_setup(&dec_op, key_id, PSA_ALG_OFB)); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_set_iv(&dec_op, iv, iv_SZ)); + psa_cipher_abort(&operation); + operation = (psa_cipher_operation_t)PSA_CIPHER_OPERATION_INIT; + status = psa_cipher_decrypt_setup(&operation, key_id, PSA_ALG_OFB); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - for (size_t offset = 0; offset < SZ; offset += chunk) { - size_t this_part = SZ - offset < chunk ? SZ - offset : chunk; - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_update(&dec_op, ciphertext + offset, this_part, - decryptedtext + offset, this_part, &out_len)); - total_out += out_len; + status = psa_cipher_set_iv(&operation, iv, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + for (int idx = 0; idx < SZ; idx = idx + bytes_to_process) { + // Limit length of last call to avoid exceeding buffer size + size_t length = (idx + bytes_to_process > SZ) ? (SZ - idx) : bytes_to_process; + + status = psa_cipher_update(&operation, ciphertext + idx, length, + decryptedtext + output_offset, SZ - output_offset, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + output_offset += output_len; } - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_finish(&dec_op, decryptedtext + total_out, - SZ - total_out, &out_len)); - total_out += out_len; - TEST_ASSERT_EQUAL_size_t(SZ, total_out); - TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); + status = psa_cipher_finish(&operation, decryptedtext + output_offset, SZ - output_offset, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + output_offset += output_len; - psa_cipher_abort(&dec_op); + TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); } + psa_destroy_key(key_id); free(plaintext); free(ciphertext); free(decryptedtext); - psa_destroy_key(key_id); } -TEST_CASE("PSA AES-CFB-128", "[psa-aes]") +TEST_CASE("mbedtls OFB stream test", "[aes]") { - const size_t SZ = 1000; - const size_t iv_SZ = 16; - const uint8_t expected_cipher_end[] = { - 0xf3, 0x64, 0x20, 0xa1, 0x70, 0x2a, 0xd9, 0x3f, - 0xb7, 0x48, 0x8c, 0x2c, 0x1f, 0x65, 0x53, 0xc2, - 0xac, 0xfd, 0x82, 0xe5, 0x31, 0x24, 0x1f, 0x30, - 0xaf, 0xcc, 0x8d, 0xb3, 0xf3, 0x63, 0xe1, 0xa0, - }; - - const uint8_t iv_seed[] = { - 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, - 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, - }; - uint8_t iv[iv_SZ]; - uint8_t *plaintext = malloc(SZ); - uint8_t *ciphertext = malloc(SZ); - uint8_t *decryptedtext = malloc(SZ); - - memcpy(iv, iv_seed, iv_SZ); - memset(plaintext, 0x3A, SZ); - memset(decryptedtext, 0x0, SZ); + aes_ofb_stream_test(TEST_AES_OFB_STREAM_DMA_MODE_LEN); +} +#if 0 +static void aes_cfb8_stream_test(unsigned int SZ) +{ psa_key_id_t key_id; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + uint8_t iv[16]; + uint8_t key[16]; + psa_status_t status; + + /* Cipher produced via this Python: + import os, binascii + from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + from cryptography.hazmat.backends import default_backend + key = b'\x44' * 16 + iv = b'\xee' * 16 + cipher = Cipher(algorithms.AES(key), modes.CFB8(iv), backend=default_backend()) + encryptor = cipher.encryptor() + ct = encryptor.update(b'\xaa' * 1000) + encryptor.finalize() + ct_arr = "" + for idx, b in enumerate(ct): + if idx % 8 == 0: + ct_arr += '\n' + ct_arr += "0x{}, ".format(format(b, '02x')) + print(ct_arr) + */ + const uint8_t expected_cipher[] = { + 0xc5, 0x2f, 0xb0, 0x9b, 0x94, 0x9c, 0xa4, 0x5c, + 0x0f, 0x4d, 0xa1, 0x9d, 0xd1, 0x19, 0xfc, 0x04, + 0xe2, 0x7f, 0x04, 0x82, 0x6a, 0xa3, 0x61, 0xbb, + 0x07, 0x6f, 0xac, 0xb9, 0xdf, 0x00, 0xf9, 0xa8, + 0xc4, 0xbe, 0x9d, 0x4d, 0xd9, 0x42, 0x8a, 0x83, + 0x12, 0x8b, 0xeb, 0xd7, 0x88, 0x70, 0x8a, 0xed, + 0x46, 0x81, 0x5b, 0x4c, 0x14, 0x67, 0xe0, 0xfb, + 0xab, 0x34, 0x90, 0x85, 0x24, 0xd2, 0x6b, 0x64, + 0xdf, 0x1d, 0x04, 0xfd, 0x69, 0xf6, 0x30, 0xbe, + 0xa6, 0xac, 0x0b, 0x54, 0x25, 0x24, 0x67, 0xd6, + 0x09, 0xb1, 0x8f, 0x91, 0x63, 0xbd, 0xdf, 0xa1, + 0x8a, 0xa3, 0x2e, 0xeb, 0x15, 0x7d, 0xe5, 0x37, + 0xe5, 0x5a, 0x9f, 0xa5, 0x21, 0xc2, 0xbd, 0xd6, + 0x05, 0xed, 0xf3, 0xbe, 0xe4, 0xf2, 0x8c, 0xd6, + 0x6a, 0xae, 0x1e, 0x3d, 0x7a, 0x5f, 0xf1, 0x1f, + 0x95, 0xe9, 0x6d, 0xbf, 0x14, 0x56, 0x2f, 0x7f, + 0x4e, 0x0d, 0xc7, 0xf0, 0x81, 0x50, 0xca, 0x58, + 0xe4, 0xe3, 0xf0, 0xa7, 0x38, 0x45, 0xfb, 0xc1, + 0xf0, 0x6e, 0xb1, 0x94, 0x08, 0x29, 0xf1, 0x7d, + 0x6f, 0x97, 0x14, 0xb5, 0x2b, 0x6d, 0x9d, 0x6a, + 0x52, 0xc8, 0xd6, 0x64, 0xe4, 0x79, 0x40, 0x8c, + 0x9d, 0x40, 0x81, 0xf0, 0x68, 0xc8, 0xce, 0x4e, + 0xcf, 0xf5, 0xdc, 0x05, 0x49, 0x7c, 0x7c, 0x72, + 0x36, 0xe9, 0x1a, 0x72, 0x15, 0x9c, 0x9a, 0xc4, + 0x62, 0xba, 0xa5, 0xbe, 0xf6, 0x4e, 0x29, 0x6d, + 0xe0, 0xe1, 0x41, 0xbd, 0x7d, 0x7d, 0xe5, 0xbe, + 0xaf, 0xd3, 0x85, 0xb7, 0x0e, 0x7a, 0xd7, 0xe7, + 0xf4, 0xeb, 0x28, 0xd3, 0xa2, 0xf9, 0x30, 0x9b, + 0xe7, 0x61, 0x6b, 0x7c, 0x13, 0x98, 0xa6, 0xc8, + 0xdc, 0xd1, 0xcf, 0x9d, 0xfa, 0xf8, 0xdc, 0x89, + 0xe7, 0xdc, 0x27, 0x38, 0x94, 0x7a, 0x76, 0x49, + 0xe3, 0xfe, 0x3e, 0xc1, 0xc7, 0x95, 0x07, 0x48, + 0x33, 0xf7, 0x54, 0x24, 0x21, 0xc0, 0x86, 0xc5, + 0xcf, 0xd4, 0x67, 0x18, 0x31, 0x5d, 0xb0, 0x40, + 0x7f, 0x37, 0xb7, 0x01, 0xf6, 0x93, 0xbf, 0x4f, + 0x65, 0x19, 0x03, 0xf3, 0x4f, 0x7a, 0x84, 0x13, + 0x4b, 0x3d, 0x4c, 0x83, 0x58, 0xce, 0xe3, 0x84, + 0xf5, 0xea, 0xe2, 0x24, 0x91, 0x04, 0xd9, 0x96, + 0x47, 0x15, 0xdd, 0xfe, 0xae, 0xc3, 0x88, 0xe6, + 0x23, 0xbf, 0x57, 0x9c, 0x46, 0x07, 0xf4, 0x32, + 0x88, 0xb3, 0x99, 0x93, 0xd9, 0x0c, 0x5d, 0x39, + 0xba, 0x7d, 0xd1, 0x92, 0x3c, 0x3c, 0x69, 0xe1, + 0xcc, 0xb2, 0x5f, 0x76, 0x10, 0xd2, 0x9e, 0x60, + 0xb1, 0x5a, 0x1c, 0x9f, 0x88, 0xb1, 0x27, 0xeb, + 0x89, 0x59, 0x29, 0xaa, 0x8f, 0x8c, 0x57, 0x2d, + 0xc8, 0x3e, 0x07, 0xd4, 0x1b, 0x11, 0x6a, 0x7a, + 0x5d, 0x29, 0xf6, 0x56, 0xe2, 0x8f, 0x12, 0xcf, + 0x33, 0x79, 0x02, 0xf2, 0x3b, 0xc2, 0x8f, 0x0d, + 0x02, 0x47, 0xba, 0xdd, 0x55, 0x1f, 0x41, 0x71, + 0x08, 0x1c, 0x9e, 0xa7, 0x79, 0xec, 0x49, 0xf3, + 0x33, 0x2a, 0x09, 0xa8, 0xe6, 0xba, 0x1c, 0xa9, + 0x0f, 0x67, 0xda, 0xc3, 0xec, 0x3c, 0x22, 0xc1, + 0xf5, 0x54, 0x3b, 0x40, 0xdc, 0x47, 0xb8, 0x53, + 0x35, 0x55, 0x1c, 0xa3, 0x76, 0x36, 0x77, 0xe2, + 0xe8, 0x97, 0x25, 0x20, 0x71, 0x39, 0x35, 0x71, + 0x80, 0x35, 0xda, 0x64, 0xab, 0x3c, 0xd1, 0x94, + 0x1d, 0xca, 0x55, 0x83, 0xad, 0xe2, 0xed, 0xb8, + 0x3f, 0xa4, 0x5d, 0xb2, 0xcc, 0x01, 0x90, 0x02, + 0x81, 0xe6, 0xc1, 0x1c, 0x4e, 0x17, 0x32, 0x9f, + 0xdb, 0x24, 0x24, 0x8f, 0x60, 0x71, 0xe2, 0xba, + 0x15, 0x1b, 0x83, 0x7a, 0xdb, 0x21, 0x7d, 0x0b, + 0x67, 0xec, 0xa3, 0xf0, 0x5e, 0xe2, 0xd2, 0x80, + 0xa8, 0x77, 0x4f, 0x7a, 0xf3, 0xb9, 0xef, 0x68, + 0x34, 0xfe, 0x3b, 0x4f, 0x6b, 0xbc, 0xdf, 0x32, + 0x68, 0xc5, 0xea, 0xb5, 0xcf, 0xe3, 0x33, 0xbf, + 0xc7, 0x57, 0xd9, 0x12, 0xa4, 0x2a, 0x09, 0x81, + 0x4e, 0x1b, 0x8c, 0xd9, 0x58, 0x15, 0x5d, 0xe1, + 0xef, 0x13, 0xe7, 0x35, 0xb1, 0x32, 0x00, 0x74, + 0x68, 0x2d, 0x7d, 0x5d, 0xd2, 0xce, 0x72, 0xd6, + 0xe1, 0x67, 0x98, 0xed, 0xfb, 0x0e, 0xee, 0xe8, + 0x9a, 0x0a, 0x57, 0x87, 0xe7, 0x1f, 0xc0, 0xa8, + 0x4a, 0x6a, 0x32, 0x8c, 0x98, 0x72, 0x89, 0x29, + 0xfe, 0xf7, 0x30, 0x7a, 0xa3, 0xd7, 0xcc, 0xa8, + 0x0b, 0x84, 0xf7, 0xfb, 0x58, 0x05, 0x84, 0xa4, + 0xf6, 0x73, 0x5e, 0x5f, 0xb3, 0x9e, 0xa1, 0x24, + 0x8b, 0xd7, 0x2c, 0xbc, 0x9c, 0x0c, 0x17, 0xe2, + 0xac, 0x6a, 0xce, 0x8e, 0x24, 0x56, 0x97, 0x9b, + 0xd4, 0xd8, 0x52, 0x92, 0x3c, 0x23, 0x4b, 0x90, + 0x0c, 0x6c, 0x7c, 0xa4, 0x8f, 0xee, 0xd1, 0x14, + 0x3a, 0x82, 0xae, 0xf2, 0x23, 0xfc, 0xfa, 0x29, + 0x43, 0x9e, 0xa9, 0x8e, 0xd9, 0xa3, 0x37, 0x64, + 0xbe, 0x50, 0x49, 0x34, 0x92, 0x1b, 0x7e, 0x06, + 0x85, 0x51, 0x7f, 0x21, 0x19, 0xa1, 0x9a, 0xfd, + 0x95, 0x76, 0xfd, 0x80, 0x79, 0xdb, 0x40, 0xe2, + 0x6d, 0xfb, 0x38, 0xe9, 0xe4, 0x6d, 0x65, 0x6d, + 0x1f, 0x97, 0x6c, 0x06, 0x3f, 0xee, 0x5b, 0x9a, + 0x85, 0x19, 0xeb, 0xae, 0x65, 0x68, 0x90, 0xa7, + 0xb7, 0x47, 0x0c, 0x08, 0xc6, 0x8f, 0x37, 0x00, + 0xde, 0xe5, 0x3e, 0xe1, 0x60, 0x88, 0x0d, 0x85, + 0x50, 0x30, 0xf2, 0x68, 0x79, 0x39, 0x37, 0xe9, + 0x0c, 0x3f, 0xdd, 0x88, 0x83, 0x3a, 0x00, 0x80, + 0xd4, 0x16, 0x06, 0x84, 0x18, 0xa0, 0x2c, 0x04, + 0x17, 0xae, 0x6a, 0x36, 0x38, 0xe1, 0x40, 0xb0, + 0xfb, 0x77, 0x8f, 0xee, 0x24, 0xe5, 0x5e, 0xec, + 0xa8, 0x7a, 0x0a, 0xec, 0xf9, 0x3d, 0x45, 0x77, + 0x0f, 0x9c, 0x67, 0xa1, 0xc8, 0x80, 0xb8, 0x7e, + 0x41, 0x9b, 0x49, 0x43, 0x7a, 0x06, 0x76, 0x5b, + 0x6e, 0x48, 0xdd, 0x66, 0xc6, 0x4b, 0x55, 0x2f, + 0x45, 0x73, 0xa4, 0x84, 0xbe, 0xcb, 0xe9, 0xc9, + 0x70, 0xbf, 0x54, 0x79, 0x0a, 0x29, 0x2b, 0xa3, + 0x95, 0xe8, 0x08, 0xc7, 0xb2, 0x92, 0x57, 0x6c, + 0x73, 0x3e, 0xe8, 0xff, 0xf7, 0x64, 0x61, 0x89, + 0x68, 0x7e, 0x0c, 0xc7, 0xc3, 0x21, 0xea, 0xcc, + 0x34, 0xda, 0x10, 0x0f, 0x10, 0x35, 0x4c, 0xbf, + 0x1c, 0xa2, 0x3b, 0x1a, 0xba, 0x1c, 0x1d, 0xc3, + 0x1e, 0xb8, 0x7a, 0xf2, 0x7d, 0x31, 0x1d, 0x83, + 0xce, 0x3b, 0x5c, 0x5a, 0x03, 0xe3, 0xfc, 0x9a, + 0xfe, 0xaa, 0x3c, 0xf9, 0x9f, 0x60, 0x7c, 0x54, + 0x02, 0x70, 0x23, 0xdb, 0x23, 0xe7, 0x4d, 0x5b, + 0x41, 0x8c, 0x1b, 0x01, 0xc9, 0x8e, 0x41, 0xb3, + 0xb9, 0x61, 0x90, 0xc1, 0x2b, 0xc5, 0xfa, 0xcf, + 0x05, 0x4d, 0xe0, 0x1a, 0x9f, 0xc3, 0xa3, 0x6c, + 0x81, 0x4c, 0x6a, 0x33, 0x8f, 0x74, 0x71, 0x79, + 0x5d, 0x30, 0x62, 0x03, 0xaa, 0x52, 0x61, 0x0d, + 0xaf, 0xf7, 0xe1, 0x80, 0x5b, 0x97, 0x30, 0x6d, + 0x31, 0x21, 0xc1, 0x02, 0x43, 0x99, 0x2b, 0x49, + 0xe9, 0x83, 0x5d, 0x24, 0x40, 0x5a, 0xcd, 0x2f, + 0x20, 0xe4, 0x69, 0x7a, 0x22, 0xcf, 0x1d, 0xb2, + 0x90, 0x2d, 0xda, 0x42, 0xf8, 0xb3, 0x8a, 0x3d, + 0x55, 0x5a, 0xc5, 0x0f, 0x12, 0x25, 0x3d, 0x98, + 0xa1, 0x83, 0xd3, 0x3b, 0xa5, 0xe1, 0x36, 0x2f, + 0x85, 0xe1, 0x4b, 0x48, 0x5e, 0xe7, 0xc1, 0x57, + 0x19, 0xca, 0xc0, 0xc0, 0x23, 0x59, 0x06, 0xb6, + 0x32, 0xeb, 0x9e, 0x2b, 0xf5, 0x23, 0x5a, 0x90, + 0xfc, 0x6d, 0xd1, 0xcd, 0x3a, 0x93, 0xdd, 0xc2, + }; + + memset(key, 0x44, 16); + + // allocate internal memory + uint8_t *ciphertext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + uint8_t *plaintext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + uint8_t *decryptedtext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + + TEST_ASSERT_NOT_NULL(ciphertext); + TEST_ASSERT_NOT_NULL(plaintext); + TEST_ASSERT_NOT_NULL(decryptedtext); + + memset(plaintext, 0xAA, SZ); + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Set up key attributes psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); psa_set_key_algorithm(&attributes, PSA_ALG_CFB); psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attributes, sizeof(key_256) * 8); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_import_key(&attributes, key_256, sizeof(key_256), &key_id)); - psa_reset_key_attributes(&attributes); + psa_set_key_bits(&attributes, 128); - psa_cipher_operation_t enc_op = PSA_CIPHER_OPERATION_INIT; - size_t out_len = 0, total_out = 0; + // Import key + status = psa_import_key(&attributes, key, 16, &key_id); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_encrypt_setup(&enc_op, key_id, PSA_ALG_CFB)); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_set_iv(&enc_op, iv, iv_SZ)); + /* Test that all the end results are the same + no matter how many bytes we encrypt each call + */ - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_update(&enc_op, plaintext, SZ, ciphertext, SZ, &out_len)); - total_out += out_len; - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_finish(&enc_op, ciphertext + total_out, SZ - total_out, &out_len)); - total_out += out_len; - TEST_ASSERT_EQUAL_size_t(SZ, total_out); - TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_cipher_end, ciphertext + SZ - sizeof(expected_cipher_end), sizeof(expected_cipher_end)); + for (int bytes_to_process = 1; bytes_to_process < SZ; bytes_to_process++) { + memset(iv, 0xEE, 16); + size_t output_offset = 0; + size_t output_len; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; - psa_cipher_operation_t dec_op = PSA_CIPHER_OPERATION_INIT; - total_out = 0; - memcpy(iv, iv_seed, iv_SZ); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_decrypt_setup(&dec_op, key_id, PSA_ALG_CFB)); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_set_iv(&dec_op, iv, iv_SZ)); + status = psa_cipher_encrypt_setup(&operation, key_id, PSA_ALG_CFB); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_update(&dec_op, ciphertext, SZ, decryptedtext, SZ, &out_len)); - total_out += out_len; - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_finish(&dec_op, decryptedtext + total_out, SZ - total_out, &out_len)); - total_out += out_len; - TEST_ASSERT_EQUAL_size_t(SZ, total_out); - TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); + status = psa_cipher_set_iv(&operation, iv, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + for (int idx = 0; idx < SZ; idx = idx + bytes_to_process) { + // Limit length of last call to avoid exceeding buffer size + size_t length = ( (idx + bytes_to_process) > SZ) ? (SZ - idx) : bytes_to_process; + + status = psa_cipher_update(&operation, plaintext + idx, length, + ciphertext + output_offset, SZ - output_offset, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + output_offset += output_len; + } + + status = psa_cipher_finish(&operation, ciphertext + output_offset, SZ - output_offset, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + output_offset += output_len; + + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_cipher, ciphertext, SZ); + + memset(iv, 0xEE, 16); + output_offset = 0; + + psa_cipher_abort(&operation); + operation = (psa_cipher_operation_t)PSA_CIPHER_OPERATION_INIT; + status = psa_cipher_decrypt_setup(&operation, key_id, PSA_ALG_CFB); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, iv, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + for (int idx = 0; idx < SZ; idx = idx + bytes_to_process) { + // Limit length of last call to avoid exceeding buffer size + size_t length = ( (idx + bytes_to_process) > SZ) ? (SZ - idx) : bytes_to_process; + + status = psa_cipher_update(&operation, ciphertext + idx, length, + decryptedtext + output_offset, SZ - output_offset, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + output_offset += output_len; + } + + status = psa_cipher_finish(&operation, decryptedtext + output_offset, SZ - output_offset, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + output_offset += output_len; + + TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); + } - psa_cipher_abort(&enc_op); - psa_cipher_abort(&dec_op); psa_destroy_key(key_id); - free(plaintext); free(ciphertext); free(decryptedtext); } - -TEST_CASE("PSA AES-CBC one-shot", "[psa-aes]") +TEST_CASE("mbedtls CFB8 stream test", "[aes]") { - const size_t SZ = 1600; + aes_cfb8_stream_test(TEST_AES_CFB8_STREAM_DMA_MODE_LEN); +} +#endif + +TEST_CASE("PSA AES-CFB multipart", "[psa-aes]") +{ + const size_t SZ = 100; const size_t iv_SZ = 16; + const size_t part_size = 8; - // allocate internal memory - uint8_t *plaintext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); - uint8_t *ciphertext = heap_caps_malloc(SZ + iv_SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); - uint8_t *decryptedtext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); - - TEST_ASSERT_NOT_NULL(plaintext); - TEST_ASSERT_NOT_NULL(ciphertext); - TEST_ASSERT_NOT_NULL(decryptedtext); + uint8_t *plaintext = malloc(SZ); + uint8_t *ciphertext = malloc(SZ); + uint8_t *decryptedtext = malloc(SZ); + uint8_t iv[iv_SZ]; memset(plaintext, 0x3A, SZ); memset(decryptedtext, 0x0, SZ); /* Import a key */ psa_key_id_t key_id; - psa_algorithm_t alg = PSA_ALG_CBC_NO_PADDING; + psa_algorithm_t alg = PSA_ALG_CFB; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); psa_set_key_algorithm(&attributes, alg); psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); psa_set_key_bits(&attributes, sizeof(key_256) * 8); - TEST_ASSERT_EQUAL(psa_import_key(&attributes, key_256, sizeof(key_256), &key_id), PSA_SUCCESS); + TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_import_key(&attributes, key_256, sizeof(key_256), &key_id)); psa_reset_key_attributes(&attributes); - size_t ciphertext_len = 0; - /* Encrypt the plaintext */ - TEST_ASSERT_EQUAL(psa_cipher_encrypt(key_id, alg, plaintext, SZ, ciphertext, SZ + iv_SZ, &ciphertext_len), PSA_SUCCESS); + /* Encrypt */ + psa_cipher_operation_t enc_op = PSA_CIPHER_OPERATION_INIT; + size_t out_len, total_out_len = 0; - TEST_ASSERT_EQUAL_size_t(ciphertext_len, SZ + iv_SZ); + memset(iv, 0x3B, iv_SZ); // Initialize IV with known value + TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_encrypt_setup(&enc_op, key_id, alg)); + TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_set_iv(&enc_op, iv, iv_SZ)); + for (size_t offset = 0; offset < SZ; offset += part_size) { + size_t this_part = SZ - offset < part_size ? SZ - offset : part_size; + TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_update(&enc_op, plaintext + offset, this_part, + ciphertext + offset, this_part, &out_len)); + total_out_len += out_len; + } - size_t decryptedtext_len = 0; - /* Decrypt the ciphertext */ - TEST_ASSERT_EQUAL(psa_cipher_decrypt(key_id, alg, ciphertext, SZ + iv_SZ, decryptedtext, SZ, &decryptedtext_len), PSA_SUCCESS); + TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_finish(&enc_op, ciphertext + total_out_len, + SZ - total_out_len, &out_len)); + total_out_len += out_len; + TEST_ASSERT_EQUAL_size_t(SZ, total_out_len); - TEST_ASSERT_EQUAL_size_t(decryptedtext_len, SZ); + /* Decrypt */ + psa_cipher_operation_t dec_op = PSA_CIPHER_OPERATION_INIT; + total_out_len = 0; + + TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_decrypt_setup(&dec_op, key_id, alg)); + TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_set_iv(&dec_op, iv, iv_SZ)); + + for (size_t offset = 0; offset < SZ; offset += part_size) { + size_t this_part = SZ - offset < part_size ? SZ - offset : part_size; + TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_update(&dec_op, ciphertext + offset, this_part, + decryptedtext + offset, this_part, &out_len)); + total_out_len += out_len; + } + + TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_cipher_finish(&dec_op, decryptedtext + total_out_len, + SZ - total_out_len, &out_len)); + total_out_len += out_len; + TEST_ASSERT_EQUAL_size_t(SZ, total_out_len); TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); @@ -864,10 +1953,1335 @@ TEST_CASE("PSA AES-CBC one-shot", "[psa-aes]") free(ciphertext); free(decryptedtext); + psa_cipher_abort(&enc_op); + psa_cipher_abort(&dec_op); + /* Destroy the key */ psa_destroy_key(key_id); } +static void aes_cfb128_stream_test(unsigned int SZ) +{ + psa_key_id_t key_id; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + uint8_t iv[16]; + uint8_t key[16]; + psa_status_t status; + + /* Cipher produced via this Python: + import os, binascii + from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + from cryptography.hazmat.backends import default_backend + key = b'\x44' * 16 + iv = b'\xee' * 16 + cipher = Cipher(algorithms.AES(key), modes.CFB(iv), backend=default_backend()) + encryptor = cipher.encryptor() + ct = encryptor.update(b'\xaa' * 1000) + encryptor.finalize() + ct_arr = "" + for idx, b in enumerate(ct): + if idx % 8 == 0: + ct_arr += '\n' + ct_arr += "0x{}, ".format(format(b, '02x')) + print(ct_arr) + */ + const uint8_t expected_cipher[] = { + 0xc5, 0x78, 0xa7, 0xb4, 0xf3, 0xb9, 0xcb, 0x8b, + 0x09, 0xe0, 0xd6, 0x89, 0x14, 0x6a, 0x19, 0x09, + 0xf9, 0x08, 0x7e, 0xe1, 0x92, 0x8a, 0x7c, 0xa4, + 0x25, 0xa5, 0xa7, 0x43, 0x24, 0x8d, 0x85, 0x3e, + 0x99, 0x28, 0xeb, 0x36, 0x59, 0x74, 0x69, 0x0e, + 0x09, 0x9f, 0x4e, 0xc0, 0x6d, 0xc3, 0x2b, 0x80, + 0x01, 0xad, 0xa1, 0x0c, 0x99, 0x90, 0x8b, 0x07, + 0xd6, 0x00, 0xf0, 0x32, 0xd7, 0x6b, 0xa1, 0xf1, + 0x4d, 0x14, 0xd0, 0x28, 0xde, 0x64, 0x23, 0x71, + 0xf4, 0x23, 0x61, 0x12, 0x71, 0xbe, 0x03, 0x74, + 0x99, 0x81, 0x9d, 0x65, 0x48, 0xd9, 0xd4, 0x67, + 0xd1, 0x31, 0xe8, 0x44, 0x27, 0x17, 0xd4, 0x2d, + 0x3d, 0x59, 0xf7, 0xd3, 0x9a, 0x7a, 0x82, 0xac, + 0x6d, 0x78, 0xad, 0xae, 0x07, 0x41, 0xec, 0xce, + 0x55, 0xad, 0x97, 0x1a, 0x2c, 0x87, 0xc6, 0xa1, + 0x4e, 0x25, 0xe7, 0xbd, 0x2d, 0xa4, 0x62, 0xb9, + 0xa1, 0xc4, 0xf2, 0xb3, 0xae, 0x6a, 0x47, 0x06, + 0x5b, 0x18, 0xcc, 0x58, 0x5a, 0x37, 0x8a, 0xe2, + 0x7c, 0x87, 0x77, 0x10, 0xd1, 0xec, 0xbc, 0x5a, + 0xbd, 0xb8, 0x66, 0x20, 0x90, 0xb6, 0x82, 0x53, + 0xe3, 0x7d, 0xbb, 0x68, 0xa0, 0x51, 0x40, 0x1c, + 0x16, 0x66, 0x9a, 0x48, 0xf2, 0xc5, 0xe9, 0xe1, + 0xc2, 0xa9, 0x09, 0xda, 0xa9, 0x75, 0xee, 0xfa, + 0x4e, 0xe0, 0x72, 0x3c, 0x2e, 0x4f, 0xb4, 0x76, + 0x0d, 0x7c, 0x38, 0x36, 0x14, 0xa4, 0x41, 0x90, + 0xc1, 0x65, 0x98, 0x16, 0x73, 0xae, 0x63, 0x6f, + 0x7d, 0xba, 0x25, 0x7c, 0x86, 0x5c, 0x1e, 0x2f, + 0x72, 0x67, 0xfb, 0xe9, 0xd4, 0xad, 0x89, 0x48, + 0x0c, 0xd7, 0x5a, 0xe1, 0x92, 0xf9, 0xc9, 0x8e, + 0xe3, 0x64, 0xcd, 0x20, 0xd8, 0xec, 0x95, 0x39, + 0x78, 0xdb, 0xac, 0x5b, 0xb0, 0x38, 0x13, 0xee, + 0xfe, 0xec, 0x1e, 0x2e, 0xe3, 0x57, 0xc1, 0x04, + 0x7a, 0xee, 0x1b, 0xbc, 0x85, 0x71, 0x26, 0x51, + 0xfb, 0x1d, 0xe4, 0xfb, 0x29, 0x2c, 0xd0, 0x12, + 0x94, 0xcf, 0x2b, 0x01, 0x7f, 0xb4, 0x95, 0x0c, + 0xc6, 0x3c, 0x3b, 0x31, 0x2e, 0x1d, 0x39, 0x85, + 0x50, 0x20, 0x70, 0x68, 0x25, 0x7e, 0xeb, 0xd6, + 0x77, 0xd0, 0x66, 0x0d, 0xd0, 0x69, 0x12, 0x8f, + 0x00, 0x77, 0xd4, 0xcd, 0xcc, 0xd9, 0xd1, 0x1c, + 0x77, 0xf9, 0x57, 0xca, 0xdf, 0x73, 0x90, 0xad, + 0x6e, 0xb7, 0xd8, 0x96, 0x58, 0xc7, 0x7d, 0xd3, + 0x41, 0xb1, 0x74, 0x9f, 0xae, 0x2f, 0x8d, 0x25, + 0xd4, 0xb1, 0xe8, 0xcb, 0x77, 0xe9, 0xb5, 0x57, + 0xfb, 0xc7, 0x4b, 0x06, 0x4f, 0x61, 0xcd, 0x2c, + 0xfe, 0x46, 0x93, 0x2f, 0x60, 0x02, 0x68, 0xe4, + 0x07, 0x85, 0x59, 0x39, 0x07, 0x5d, 0x2f, 0x13, + 0xa3, 0x29, 0x04, 0xab, 0x21, 0xb2, 0x35, 0x8a, + 0xd6, 0xc1, 0x1c, 0x0c, 0xb6, 0x4b, 0x0e, 0x67, + 0xdc, 0xc8, 0xb3, 0x5f, 0x43, 0xde, 0xba, 0x05, + 0xe4, 0xbd, 0xa9, 0xf3, 0x28, 0x67, 0x23, 0x24, + 0x6e, 0x7a, 0xac, 0xce, 0x2b, 0x58, 0x2f, 0xfc, + 0xe8, 0x3e, 0x0b, 0x51, 0x4c, 0xd7, 0x8a, 0xdf, + 0xa8, 0x5a, 0xeb, 0x45, 0xf1, 0x4a, 0x57, 0x0a, + 0x8c, 0xf5, 0x58, 0x7e, 0xb9, 0x1b, 0x11, 0x48, + 0x75, 0x7c, 0x2c, 0x07, 0x31, 0x96, 0x8b, 0xab, + 0x2a, 0x0b, 0x97, 0x6b, 0x59, 0x70, 0xdb, 0x3f, + 0xf0, 0x68, 0xd2, 0x29, 0xef, 0x1a, 0x65, 0x09, + 0xf1, 0x06, 0xc9, 0xd7, 0x68, 0x8d, 0x97, 0x17, + 0x68, 0x5d, 0xdc, 0x62, 0xe9, 0xbb, 0x47, 0xa6, + 0x92, 0x32, 0xb3, 0x1e, 0x5c, 0x81, 0xc6, 0x54, + 0x41, 0xa8, 0xa2, 0x71, 0x3c, 0xf2, 0x48, 0xd3, + 0x4b, 0x23, 0x9d, 0x46, 0x10, 0x90, 0xda, 0xae, + 0x67, 0x3b, 0x21, 0xe2, 0xde, 0x79, 0x29, 0x32, + 0x35, 0x58, 0x15, 0x0c, 0xc3, 0xbf, 0x67, 0xbb, + 0x91, 0x06, 0x6c, 0x7a, 0xb4, 0x58, 0xe1, 0x29, + 0x38, 0xe3, 0xda, 0x66, 0x93, 0x38, 0x42, 0xd3, + 0x01, 0xc0, 0xe7, 0x4d, 0x0c, 0x66, 0x4b, 0x8b, + 0xae, 0x16, 0xba, 0xc4, 0xdb, 0xce, 0x92, 0x2b, + 0x88, 0xed, 0xb2, 0x59, 0xd4, 0x2a, 0x0f, 0x7a, + 0x3a, 0xce, 0xe0, 0xab, 0xa3, 0x46, 0xe4, 0x2b, + 0xd9, 0x0b, 0x14, 0x06, 0xc0, 0x7a, 0xe6, 0x40, + 0x23, 0x5d, 0x4d, 0x57, 0x9f, 0xfc, 0x7e, 0x08, + 0xfc, 0x52, 0x3d, 0x07, 0xd8, 0xee, 0xfa, 0x7c, + 0x2a, 0xbc, 0x93, 0x76, 0x7a, 0xc1, 0x32, 0x7a, + 0xd7, 0x52, 0xc4, 0x29, 0xec, 0x6b, 0x3b, 0x6d, + 0xc8, 0x63, 0xc5, 0x93, 0x60, 0x0a, 0x7d, 0x37, + 0x2e, 0x6c, 0xb0, 0x48, 0xe8, 0x47, 0xa5, 0x6a, + 0x9d, 0x75, 0x15, 0xf5, 0xfb, 0x89, 0x44, 0xf6, + 0x4c, 0x93, 0xc6, 0xdd, 0xe1, 0x72, 0xc3, 0xb9, + 0x77, 0xdf, 0x89, 0xed, 0x01, 0xb0, 0x4f, 0x6d, + 0xcf, 0x80, 0xf3, 0x03, 0xb4, 0xca, 0x58, 0xc8, + 0x55, 0x89, 0x91, 0x64, 0x66, 0xd5, 0xbe, 0x92, + 0xf0, 0x6b, 0xa3, 0xa9, 0xfd, 0x13, 0x31, 0xc2, + 0x6d, 0xab, 0xf0, 0xac, 0xce, 0x8c, 0x9d, 0xda, + 0x33, 0x97, 0x80, 0x9e, 0x9f, 0xcd, 0x57, 0xde, + 0x51, 0x78, 0x2b, 0xc8, 0xe7, 0xe4, 0x46, 0x3a, + 0x40, 0x16, 0xd1, 0xe0, 0xb5, 0xe8, 0x47, 0xfc, + 0x39, 0x0d, 0x68, 0x41, 0x26, 0x08, 0xdb, 0x3f, + 0xf1, 0x54, 0xf1, 0x7e, 0xc8, 0xa9, 0x39, 0x76, + 0x4b, 0xb5, 0xbb, 0x2e, 0xb5, 0x14, 0x98, 0x94, + 0x14, 0xfd, 0xca, 0xaa, 0xa6, 0x5c, 0x1a, 0x85, + 0x9f, 0xab, 0x41, 0x76, 0x6f, 0x5b, 0xaf, 0xc5, + 0x4e, 0x7d, 0x2a, 0xe1, 0x19, 0x29, 0x85, 0x49, + 0x6c, 0x98, 0x46, 0x3a, 0xaf, 0x49, 0x0a, 0x91, + 0x64, 0xd6, 0x0d, 0x82, 0xf5, 0xf1, 0x8e, 0xbb, + 0x4c, 0x33, 0xde, 0xc5, 0x22, 0x89, 0x08, 0xd8, + 0x00, 0x72, 0x2d, 0x68, 0xd7, 0x4f, 0x7b, 0xc4, + 0x1a, 0xa1, 0xfb, 0xd5, 0x41, 0xe2, 0x3b, 0x6c, + 0x65, 0xeb, 0xb5, 0xbd, 0x14, 0xe8, 0x21, 0x07, + 0x71, 0xb5, 0x87, 0xd1, 0x6f, 0x5b, 0x22, 0x68, + 0x25, 0x84, 0xac, 0xfd, 0x4f, 0x51, 0x8b, 0x33, + 0x9c, 0xcb, 0x05, 0x0d, 0x28, 0xfe, 0xb6, 0x57, + 0x25, 0xd0, 0xe8, 0x7f, 0x7f, 0x2e, 0x5a, 0x32, + 0x28, 0x40, 0x5d, 0x7d, 0x74, 0xb4, 0xcd, 0x22, + 0x5e, 0xd4, 0x31, 0x10, 0xf6, 0xf6, 0xd8, 0x44, + 0xe3, 0xbc, 0x85, 0xd4, 0xf7, 0x2c, 0x0d, 0x7b, + 0x88, 0xd0, 0x15, 0x5f, 0x0a, 0x8a, 0x29, 0x01, + 0x29, 0x27, 0x26, 0xf1, 0xa3, 0x0b, 0x53, 0x8f, + 0xed, 0xad, 0x5e, 0xec, 0xb5, 0x1a, 0x3c, 0x7e, + 0x14, 0xaa, 0x47, 0x11, 0xc9, 0x48, 0x32, 0xfe, + 0xa6, 0x58, 0xe1, 0x38, 0x76, 0x90, 0x32, 0x5a, + 0x5b, 0x13, 0x2d, 0x34, 0x14, 0x00, 0x3f, 0xcc, + 0xd7, 0xe8, 0x48, 0x13, 0xe6, 0xfe, 0x8c, 0xd1, + 0x33, 0xfe, 0xf8, 0xa6, 0x75, 0xff, 0x2c, 0xb7, + 0xfc, 0x18, 0x4c, 0x7c, 0x39, 0x48, 0x88, 0xb1, + 0x35, 0x06, 0xfa, 0xad, 0x88, 0xd9, 0xae, 0x42, + 0x1b, 0x0b, 0x54, 0x95, 0x44, 0x5d, 0x39, 0xb6, + 0xda, 0xe5, 0x2d, 0xeb, 0x1b, 0xca, 0x8f, 0xab, + 0xd0, 0xb3, 0x7c, 0xdb, 0x5b, 0x00, 0x92, 0xfb, + 0x27, 0x26, 0x46, 0x84, 0xe9, 0xfe, 0x64, 0x0e, + 0x80, 0x07, 0x48, 0xf6, 0x44, 0x2f, 0xad, 0x94, + 0x54, 0xa0, 0x91, 0x96, 0xc8, 0xf6, 0x55, 0xbd, + 0xd5, 0x59, 0xe0, 0xf3, 0xae, 0x2a, 0xee, 0xd6, + 0x12, 0xec, 0xd7, 0x90, 0x0f, 0x5f, 0x7c, 0x34, + 0x31, 0xdb, 0x42, 0x4d, 0xe4, 0x82, 0x6d, 0xe5, + }; + + memset(key, 0x44, 16); + + // allocate internal memory + uint8_t *ciphertext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + uint8_t *plaintext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + uint8_t *decryptedtext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + + TEST_ASSERT_NOT_NULL(ciphertext); + TEST_ASSERT_NOT_NULL(plaintext); + TEST_ASSERT_NOT_NULL(decryptedtext); + + memset(plaintext, 0xAA, SZ); + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Set up key attributes + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_CFB); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 128); + + // Import key + status = psa_import_key(&attributes, key, 16, &key_id); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + /* Test that all the end results are the same + no matter how many bytes we encrypt each call + */ + + //for (int bytes_to_process = 1; bytes_to_process < SZ; bytes_to_process++) { + int bytes_to_process = 17; + size_t output_offset = 0; + size_t output_len; + memset(iv, 0xEE, 16); + + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; + status = psa_cipher_encrypt_setup(&operation, key_id, PSA_ALG_CFB); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, iv, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + for (int idx = 0; idx < SZ; idx = idx + bytes_to_process) { + // Limit length of last call to avoid exceeding buffer size + size_t length = ( (idx + bytes_to_process) > SZ) ? (SZ - idx) : bytes_to_process; + + status = psa_cipher_update(&operation, plaintext + idx, length, + ciphertext + output_offset, SZ - output_offset, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + output_offset += output_len; + } + + status = psa_cipher_finish(&operation, ciphertext + output_offset, SZ - output_offset, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + output_offset += output_len; + + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_cipher, ciphertext, SZ); + + output_offset = 0; + memset(iv, 0xEE, 16); + + psa_cipher_abort(&operation); + operation = (psa_cipher_operation_t)PSA_CIPHER_OPERATION_INIT; + status = psa_cipher_decrypt_setup(&operation, key_id, PSA_ALG_CFB); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, iv, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + for (int idx = 0; idx < SZ; idx = idx + bytes_to_process) { + // Limit length of last call to avoid exceeding buffer size + size_t length = ( (idx + bytes_to_process) > SZ) ? (SZ - idx) : bytes_to_process; + + status = psa_cipher_update(&operation, ciphertext + idx, length, + decryptedtext + output_offset, SZ - output_offset, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + output_offset += output_len; + } + + status = psa_cipher_finish(&operation, decryptedtext + output_offset, SZ - output_offset, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + output_offset += output_len; + + TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); + + psa_destroy_key(key_id); + free(plaintext); + free(ciphertext); + free(decryptedtext); +} + +TEST_CASE("mbedtls CFB128 stream test", "[aes]") +{ + aes_cfb128_stream_test(TEST_AES_CFB128_DMA_MODE_LEN); +} + +/* Cipher produced via this Python: + import os, binascii + from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + from cryptography.hazmat.backends import default_backend + key = b'\x44' * 16 + nonce = b'\xee' * 16 + cipher = Cipher(algorithms.AES(key), modes.CTR(nonce), backend=default_backend()) + encryptor = cipher.encryptor() + ct = encryptor.update(b'\xaa' * 1000) + encryptor.finalize() + ct_arr = "" + for idx, b in enumerate(ct): + if idx % 8 == 0: + ct_arr += '\n' + ct_arr += "0x{}, ".format(format(b, '02x')) + print(ct_arr) +*/ + +#if CONFIG_MBEDTLS_HARDWARE_AES +/* Test the case where the input and output buffers point to the same location */ +/* As, mbedtls does not support in-place encryption for block cipher modes, hence this test is only applicable for hardware AES */ +TEST_CASE("mbedtls CTR, input buf = output buf", "[aes]") +{ + const unsigned SZ = 1000; + psa_key_id_t key_id; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; + uint8_t nonce[16]; + psa_status_t status; + size_t output_len; + + const uint8_t expected_cipher_end[] = { + 0xd4, 0xdc, 0x4f, 0x8f, 0xfe, 0x86, 0xee, 0xb5, + 0x14, 0x7f, 0xba, 0x30, 0x25, 0xa6, 0x7f, 0x6c, + 0xb5, 0x73, 0xaf, 0x90, 0xd7, 0xff, 0x36, 0xba, + 0x2b, 0x1d, 0xec, 0xb9, 0x38, 0xfa, 0x0d, 0xeb, + }; + + memcpy(nonce, iv, 16); + + // allocate internal memory + uint8_t *buf = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + + TEST_ASSERT_NOT_NULL(buf); + + memset(buf, 0x3A, SZ); + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Set up key attributes + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_CTR); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 256); + + // Import key + status = psa_import_key(&attributes, key_256, 32, &key_id); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Encrypt + status = psa_cipher_encrypt_setup(&operation, key_id, PSA_ALG_CTR); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + size_t total_len = 0; + status = psa_cipher_update(&operation, buf, SZ, buf, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_len += output_len; + + status = psa_cipher_finish(&operation, buf + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_len += output_len; + + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_cipher_end, buf + SZ - 32, 32); + + // Decrypt + memcpy(nonce, iv, 16); + + psa_cipher_abort(&operation); + operation = (psa_cipher_operation_t)PSA_CIPHER_OPERATION_INIT; + status = psa_cipher_decrypt_setup(&operation, key_id, PSA_ALG_CTR); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + total_len = 0; + status = psa_cipher_update(&operation, buf, SZ, buf, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_len += output_len; + + status = psa_cipher_finish(&operation, buf + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_len += output_len; + + for (int i = 0; i < SZ; i++) { + TEST_ASSERT_EQUAL_HEX8(0x3A, buf[i]); + } + + psa_destroy_key(key_id); + free(buf); +} +#endif /* CONFIG_MBEDTLS_HARDWARE_AES */ + +TEST_CASE("mbedtls OFB, chained DMA descriptors", "[aes]") +{ + // Max bytes in a single DMA descriptor is 4095 + const unsigned SZ = 6000; + psa_key_id_t key_id; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; + uint8_t nonce[16]; + psa_status_t status; + size_t output_len; + + const uint8_t expected_cipher_end[] = { + 0xfe, 0xfa, 0xc9, 0x26, 0xb5, 0xc9, 0xea, 0xb0, + 0xdd, 0x1e, 0xe7, 0x0e, 0xfa, 0x5b, 0x4b, 0x94, + 0xaa, 0x5f, 0x60, 0x1e, 0xb2, 0x19, 0x3c, 0x2e, + 0xf6, 0x73, 0x56, 0x9f, 0xa7, 0xd5, 0xb7, 0x21, + }; + + memcpy(nonce, iv, 16); + + // allocate internal memory + uint8_t *ciphertext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + uint8_t *plaintext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + uint8_t *decryptedtext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + + TEST_ASSERT_NOT_NULL(ciphertext); + TEST_ASSERT_NOT_NULL(plaintext); + TEST_ASSERT_NOT_NULL(decryptedtext); + + memset(plaintext, 0x3A, SZ); + memset(decryptedtext, 0x0, SZ); + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Set up key attributes + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_OFB); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 256); + + // Import key + status = psa_import_key(&attributes, key_256, 32, &key_id); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Encrypt + status = psa_cipher_encrypt_setup(&operation, key_id, PSA_ALG_OFB); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + size_t total_len = 0; + status = psa_cipher_update(&operation, plaintext, SZ, ciphertext, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_len += output_len; + + status = psa_cipher_finish(&operation, ciphertext + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_len += output_len; + + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_cipher_end, ciphertext + SZ - 32, 32); + + // Decrypt + memcpy(nonce, iv, 16); + + psa_cipher_abort(&operation); + operation = (psa_cipher_operation_t)PSA_CIPHER_OPERATION_INIT; + status = psa_cipher_decrypt_setup(&operation, key_id, PSA_ALG_OFB); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + total_len = 0; + status = psa_cipher_update(&operation, ciphertext, SZ, decryptedtext, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_len += output_len; + + status = psa_cipher_finish(&operation, decryptedtext + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_len += output_len; + + TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); + + psa_destroy_key(key_id); + free(plaintext); + free(ciphertext); + free(decryptedtext); +} + +const uint8_t expected_cipher_ctr_end[] = { + 0x93, 0xca, 0xe0, 0x44, 0x96, 0x6d, 0xcb, 0xb2, + 0xcf, 0x8a, 0x8d, 0x73, 0x8c, 0x6b, 0xfa, 0x4d, + 0xd6, 0xc4, 0x18, 0x49, 0xdd, 0xc6, 0xbf, 0xc2, + 0xb9, 0xf0, 0x09, 0x69, 0x45, 0x42, 0xc6, 0x05, +}; + +void aes_ctr_alignment_test(uint32_t input_buf_caps, uint32_t output_buf_caps) +{ + psa_key_id_t key_id; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + uint8_t nonce[16]; + uint8_t key[16]; + psa_status_t status; + size_t SZ = 32*200; + size_t ALIGNMENT_SIZE_BYTES = 64; + memset(nonce, 0x2F, 16); + memset(key, 0x1E, 16); + + // allocate memory according the requested caps + uint8_t *ciphertext = heap_caps_malloc(SZ + ALIGNMENT_SIZE_BYTES, output_buf_caps); + uint8_t *plaintext = heap_caps_malloc(SZ + ALIGNMENT_SIZE_BYTES, input_buf_caps); + uint8_t *decryptedtext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + + TEST_ASSERT_NOT_NULL(ciphertext); + TEST_ASSERT_NOT_NULL(plaintext); + TEST_ASSERT_NOT_NULL(decryptedtext); + + memset(plaintext, 0x26, SZ + ALIGNMENT_SIZE_BYTES); + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Set up key attributes + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_CTR); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 128); + + // Import key + status = psa_import_key(&attributes, key, 16, &key_id); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + size_t output_len; + + /* Shift buffers and test for all different misalignments */ + for (int i = 0; i < ALIGNMENT_SIZE_BYTES; i++ ) { + // Encrypt with input buffer in external ram + memset(nonce, 0x2F, 16); + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; + + status = psa_cipher_encrypt_setup(&operation, key_id, PSA_ALG_CTR); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + size_t total_len = 0; + status = psa_cipher_update(&operation, plaintext + i, SZ, ciphertext + i, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_len += output_len; + + status = psa_cipher_finish(&operation, ciphertext + i + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_len += output_len; + + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_cipher_ctr_end, ciphertext + i + SZ - 32, 32); + + // Decrypt + memset(nonce, 0x2F, 16); + + psa_cipher_abort(&operation); + operation = (psa_cipher_operation_t)PSA_CIPHER_OPERATION_INIT; + status = psa_cipher_decrypt_setup(&operation, key_id, PSA_ALG_CTR); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + total_len = 0; + status = psa_cipher_update(&operation, ciphertext + i, SZ, decryptedtext, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_len += output_len; + + status = psa_cipher_finish(&operation, decryptedtext + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_len += output_len; + + TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); + } + + psa_destroy_key(key_id); + free(plaintext); + free(ciphertext); + free(decryptedtext); +} + +TEST_CASE("mbedtls AES internal mem alignment tests", "[aes]") +{ + uint32_t internal_dma_caps = INTERNAL_DMA_CAPS; + aes_ctr_alignment_test(internal_dma_caps, internal_dma_caps); +} + +#ifdef CONFIG_SPIRAM_USE_MALLOC + +void aes_psram_one_buf_ctr_test(void) +{ + psa_key_id_t key_id; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + uint8_t nonce[16]; + uint8_t key[16]; + psa_status_t status; + size_t SZ = 32*200; + size_t ALIGNMENT_SIZE_BYTES = 32; + memset(nonce, 0x2F, 16); + memset(key, 0x1E, 16); + + // allocate external memory + uint8_t *buf = heap_caps_malloc(SZ + ALIGNMENT_SIZE_BYTES, PSRAM_DMA_CAPS); + + TEST_ASSERT_NOT_NULL(buf); + + memset(buf, 0x26, SZ + ALIGNMENT_SIZE_BYTES); + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Set up key attributes + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_CTR); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 128); + + // Import key + status = psa_import_key(&attributes, key, 16, &key_id); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + size_t output_len; + + /* Shift buffers and test for all different misalignments */ + for (int i = 0; i < ALIGNMENT_SIZE_BYTES; i++ ) { + // Encrypt with input buffer in external ram + memset(buf, 0x26, SZ + ALIGNMENT_SIZE_BYTES); + memset(nonce, 0x2F, 16); + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; + + status = psa_cipher_encrypt_setup(&operation, key_id, PSA_ALG_CTR); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + size_t total_len = 0; + status = psa_cipher_update(&operation, buf + i, SZ, buf + i, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_len += output_len; + + status = psa_cipher_finish(&operation, buf + i + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_len += output_len; + + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_cipher_ctr_end, buf + i + SZ - 32, 32); + + // Decrypt + memset(nonce, 0x2F, 16); + + psa_cipher_abort(&operation); + operation = (psa_cipher_operation_t)PSA_CIPHER_OPERATION_INIT; + status = psa_cipher_decrypt_setup(&operation, key_id, PSA_ALG_CTR); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + total_len = 0; + status = psa_cipher_update(&operation, buf + i, SZ, buf, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_len += output_len; + + status = psa_cipher_finish(&operation, buf + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_len += output_len; + + TEST_ASSERT_EACH_EQUAL_HEX8(0x26, buf + i, SZ - i); + } + + psa_destroy_key(key_id); + free(buf); +} + +const uint8_t long_input[] = { + 0xf7, 0xe6, 0x6b, 0x8d, 0x2e, 0xbf, 0x88, 0xd6, + 0xb0, 0x77, 0xdf, 0x72, 0xbf, 0xa8, 0x0, 0x55, + 0xd5, 0xd1, 0x49, 0xa3, 0x2c, 0xc, 0xfe, 0xdb, + 0x17, 0x37, 0xa4, 0x1d, 0x70, 0x6b, 0x99, 0xf5, + 0x9e, 0x6, 0xad, 0x6c, 0xe0, 0x3b, 0xfa, 0x50, + 0x28, 0xb2, 0x62, 0xf2, 0x99, 0x3a, 0xcc, 0xe4, + 0x86, 0x5f, 0x1, 0xf8, 0x69, 0xd7, 0xf5, 0xb2, + 0x8a, 0x5f, 0x5c, 0x38, 0x9f, 0x8a, 0xb8, 0x8c, + 0xea, 0x6, 0xe1, 0x68, 0xff, 0xaf, 0x5d, 0xd9, + 0x1f, 0xa5, 0x5c, 0x8c, 0x52, 0xa1, 0x5f, 0x45, + 0x55, 0xcb, 0x76, 0x59, 0x8f, 0xfe, 0x36, 0xd0, + 0x85, 0x1f, 0x8, 0x90, 0x6f, 0x62, 0xb1, 0x1a, + 0xde, 0x75, 0xab, 0x90, 0xb7, 0x75, 0xe9, 0xa0, + 0xa9, 0xb0, 0xac, 0x61, 0x5, 0x6d, 0x9a, 0xe3, + 0x3b, 0x43, 0x61, 0x13, 0x8c, 0x3a, 0xa0, 0xaa, + 0x91, 0xea, 0x3e, 0xe1, 0x87, 0x35, 0xff, 0x90, + 0xe2, 0x43, 0xa3, 0x70, 0x57, 0x65, 0x2d, 0xa2, + 0x65, 0xe6, 0xde, 0xb0, 0x52, 0x85, 0x5b, 0xb8, + 0x3, 0x8, 0x63, 0x8b, 0xa1, 0xc2, 0xe1, 0x35, + 0x2e, 0xba, 0xe0, 0x84, 0x56, 0x52, 0x5f, 0x12, + 0xd3, 0x22, 0x8d, 0xa5, 0xbb, 0xe1, 0xd3, 0xfc, + 0x18, 0x1c, 0x90, 0x3b, 0x79, 0xe, 0xab, 0x2d, + 0x5e, 0xb0, 0x7, 0xbb, 0x46, 0x73, 0x1d, 0x35, + 0xd9, 0xc5, 0xa7, 0x87, 0x80, 0xf7, 0xee, 0x29, + 0xb5, 0x17, 0xf3, 0xaf, 0x30, 0xe5, 0x19, 0x50, + 0xf9, 0x5d, 0x2b, 0xc3, 0xc0, 0xda, 0x8f, 0xca, + 0x3c, 0x4d, 0xd5, 0xd7, 0x6c, 0xd2, 0x36, 0xa4, + 0x22, 0x8, 0x66, 0x48, 0x31, 0xb4, 0x3d, 0xc2, + 0xf6, 0x6b, 0xce, 0xf0, 0x12, 0xe4, 0x38, 0x5c, + 0xd8, 0x71, 0xea, 0x30, 0x52, 0xdf, 0x34, 0x62, + 0xdc, 0xb4, 0x30, 0xe, 0x74, 0xc, 0x5, 0x14, + 0xf, 0x47, 0x25, 0x5, 0x72, 0xc9, 0x14, 0x7c, + 0x1f, 0x6e, 0xdb, 0x6f, 0x83, 0x6, 0xa0, 0xb2, + 0x7f, 0x29, 0xe6, 0xb6, 0xe3, 0x11, 0x23, 0x4b, + 0x68, 0x92, 0xa, 0x49, 0xb5, 0x9d, 0x5d, 0x39, + 0x90, 0xff, 0x9, 0xa0, 0xa, 0x69, 0x6b, 0x2, + 0x18, 0xfb, 0xca, 0x5a, 0x91, 0x1a, 0xd9, 0x19, + 0x6b, 0xd4, 0x92, 0xd3, 0xd9, 0x7, 0xce, 0xcb, + 0xc7, 0xf3, 0xa1, 0x33, 0xcd, 0xa9, 0xb1, 0x44, + 0x8c, 0x93, 0xcd, 0xac, 0xc1, 0x44, 0x12, 0x48, + 0x95, 0x3, 0xdf, 0xc, 0x2f, 0xfc, 0x34, 0x8d, + 0x3, 0xde, 0xc1, 0xed, 0xdc, 0xf0, 0xfa, 0xa5, + 0xb2, 0x62, 0xcd, 0xa2, 0xbf, 0xf7, 0x7e, 0x47, + 0xb6, 0xcc, 0xe4, 0xa6, 0x4e, 0x51, 0xc6, 0x34, + 0xee, 0x83, 0x21, 0xb7, 0xc2, 0xe3, 0x13, 0x92, + 0xfc, 0xc9, 0x6, 0x6b, 0x91, 0x76, 0x7b, 0x2e, + 0x1e, 0xa2, 0xe0, 0x17, 0xab, 0x10, 0xfa, 0xac, + 0xd1, 0x2, 0x33, 0xb0, 0xd3, 0x3d, 0xb9, 0xce, + 0xea, 0xe9, 0x93, 0x5c, 0x98, 0x14, 0x0, 0xc6, + 0x2c, 0xa6, 0xdb, 0x1f, 0xdc, 0x76, 0xfb, 0xeb, + 0x9d, 0x55, 0xa6, 0x5f, 0xd5, 0x8e, 0x13, 0x39, + 0x88, 0x58, 0xff, 0xe8, 0xb4, 0x98, 0x9e, 0x4b, + 0xe7, 0x46, 0xdc, 0x7a, 0x68, 0x5b, 0xa8, 0xc2, + 0xe5, 0xa9, 0x50, 0xe2, 0x8, 0x31, 0x6, 0x3e, + 0x8e, 0xaf, 0x80, 0x24, 0x4e, 0xbd, 0x73, 0x6d, + 0xd9, 0x4b, 0xb4, 0x3e, 0x84, 0x5e, 0x31, 0x8e, + 0xf7, 0xa8, 0x9b, 0x5e, 0x2c, 0xd5, 0xe9, 0x7c, + 0xca, 0xca, 0xfa, 0x8e, 0x87, 0xbf, 0xf5, 0xa3, + 0x2f, 0x73, 0x2f, 0xc0, 0x5f, 0x46, 0xf4, 0x2, + 0xfd, 0xd1, 0x23, 0x6f, 0xc2, 0xc1, 0xc0, 0x86, + 0x62, 0x43, 0xc3, 0x44, 0x3b, 0x2c, 0x3d, 0xc2, + 0xd5, 0xe0, 0x2, 0xae, 0x1, 0x5a, 0x9, 0x89, + 0x52, 0x34, 0xdf, 0xb1, 0x6c, 0x2b, 0x85, 0x77, + 0xa5, 0x83, 0xe3, 0xa5, 0x50, 0x13, 0x2f, 0xf3, + 0xa6, 0x83, 0x60, 0x33, 0xba, 0xd5, 0xd2, 0x96, + 0x8a, 0xcd, 0xee, 0xfa, 0x76, 0x2a, 0x63, 0xec, + 0x41, 0x3a, 0xf3, 0xe5, 0x9e, 0x1d, 0x5e, 0x46, + 0x8, 0xd7, 0xe2, 0x3a, 0x25, 0x6f, 0x37, 0x7e, + 0x0, 0x2d, 0x3d, 0x1b, 0x86, 0xf4, 0xbe, 0x0, + 0x3c, 0xda, 0x82, 0x4a, 0xa3, 0x8, 0x2a, 0x38, + 0x95, 0xe, 0x38, 0xf8, 0x18, 0x6c, 0x42, 0x6f, + 0x30, 0x19, 0x8e, 0x22, 0xf6, 0xb7, 0x18, 0xb7, + 0x93, 0xd, 0x54, 0x72, 0x4, 0x64, 0xc1, 0x19, + 0x76, 0x6e, 0xfc, 0x9e, 0xb0, 0x7c, 0x20, 0x37, + 0xb0, 0xcb, 0x82, 0x3a, 0x20, 0x1d, 0x12, 0x44, + 0xbf, 0x44, 0xc4, 0x4d, 0x33, 0x7e, 0x7b, 0xeb, + 0xd8, 0xb8, 0xa1, 0x75, 0x9e, 0x47, 0x99, 0x64, + 0x92, 0xd3, 0x21, 0x1d, 0x72, 0x63, 0xc7, 0xb3, + 0x3d, 0xfc, 0xb9, 0x4, 0x65, 0x18, 0x94, 0xcc, + 0x20, 0xfe, 0x6f, 0x66, 0x36, 0xba, 0x36, 0x2a, + 0x7, 0xf0, 0x5e, 0x8a, 0xf2, 0x7, 0x1e, 0x9e, + 0x47, 0x2a, 0xc3, 0x7d, 0x7a, 0x20, 0x3c, 0x30, + 0x6f, 0xbe, 0x43, 0x5e, 0x71, 0x6f, 0xd, 0xb8, + 0x3d, 0x1d, 0x3e, 0x18, 0x65, 0x62, 0x75, 0xe8, + 0x34, 0xfd, 0x72, 0xbb, 0xd9, 0x3f, 0xf0, 0xa2, + 0x55, 0xee, 0x91, 0x12, 0x88, 0xda, 0x7, 0x3d, + 0x44, 0x88, 0x70, 0x1f, 0xe0, 0xbe, 0x4b, 0x88, + 0xa8, 0x8e, 0x28, 0x7, 0x73, 0xfd, 0x3f, 0xff, + 0x3e, 0xb2, 0xb5, 0xdb, 0x18, 0x48, 0x9e, 0x73, + 0x6e, 0xd7, 0x24, 0xa9, 0x25, 0xdb, 0x4, 0xe0, + 0xe0, 0xf4, 0x45, 0xc0, 0x1b, 0x82, 0xdf, 0x4e, + 0x48, 0x60, 0x85, 0x9c, 0xd8, 0x90, 0x32, 0xca, + 0x4b, 0xf9, 0xb4, 0xb8, 0xe1, 0xfe, 0xd2, 0xe0, + 0xb2, 0xd6, 0xb8, 0x19, 0x38, 0x34, 0x17, 0x8d, + 0x5e, 0xdf, 0xf4, 0xf1, 0xac, 0x2c, 0x88, 0x7f, + 0x54, 0xbc, 0xf1, 0x39, 0xf2, 0xaf, 0x5a, 0xff, + 0xa7, 0x96, 0x0, 0xf0, 0x27, 0x79, 0x27, 0x2e, + 0x9c, 0xf1, 0x4b, 0xa3, 0xad, 0xdc, 0x8a, 0x2c, + 0x9, 0x4c, 0xd3, 0xcd, 0xd0, 0x2d, 0xb1, 0xec, + 0x4d, 0x68, 0x40, 0xb8, 0xc5, 0x5, 0xfa, 0xb2, + 0x61, 0xb8, 0x31, 0x5, 0xea, 0xb8, 0xa3, 0x34, + 0xa8, 0x8b, 0x3, 0x5b, 0x22, 0x93, 0xba, 0x91, + 0x33, 0x3f, 0x8b, 0x5e, 0xed, 0x86, 0x23, 0x95, + 0xbc, 0x9e, 0xdf, 0xa9, 0x8c, 0xca, 0xb9, 0x97, + 0x9b, 0xc5, 0xca, 0xf4, 0xff, 0x4d, 0x62, 0x52, + 0x1c, 0xd3, 0x4c, 0x42, 0xbf, 0x8a, 0x25, 0x47, + 0xc7, 0x9, 0x4e, 0xe0, 0xb1, 0x72, 0x7d, 0x2, + 0x8f, 0xca, 0x4f, 0x4, 0xc8, 0x74, 0x82, 0x8e, + 0x53, 0xfd, 0xa1, 0x37, 0xda, 0x29, 0x5c, 0xa3, + 0x83, 0xe9, 0xa8, 0xd8, 0x25, 0x27, 0xfe, 0xf7, + 0x41, 0xc4, 0xb0, 0xee, 0x1d, 0x89, 0x1c, 0xe7, + 0xef, 0x86, 0x68, 0xd8, 0x87, 0x4c, 0x4f, 0x49, + 0xeb, 0xbc, 0xb3, 0x81, 0xa7, 0xf4, 0xb4, 0x9b, + 0xc1, 0x52, 0x93, 0x7e, 0xdf, 0x75, 0x75, 0xfc, + 0x45, 0xb2, 0x86, 0xa9, 0x50, 0xb5, 0xa3, 0xf7, + 0x61, 0x60, 0xe4, 0x13, 0x99, 0xc0, 0xf8, 0x49, + 0x7b, 0x61, 0x8b, 0xa8, 0xfa, 0x77, 0x0, 0xe4, + 0x6, 0x9a, 0xc5, 0x51, 0xe4, 0xeb, 0xaf, 0x5f, + 0xb9, 0x5c, 0x74, 0xc8, 0xf8, 0x3e, 0x62, 0x26, + 0xe, 0xe5, 0x85, 0xca, 0x49, 0xa0, 0x2f, 0xf7, + 0x7, 0x99, 0x3e, 0x5c, 0xe0, 0x72, 0xfa, 0xd4, + 0x80, 0x2e, 0xd6, 0x40, 0x6, 0xde, 0x5f, 0xc5, + 0xc5, 0x1, 0xd, 0xbf, 0xdb, 0xb6, 0xb3, 0x92, + 0x76, 0xb3, 0x3f, 0x3d, 0x5d, 0x1, 0x23, 0xb8, + 0xa, 0xcb, 0x80, 0x17, 0x31, 0x19, 0xc7, 0x64, + 0x69, 0xf1, 0x99, 0x53, 0xe5, 0xf2, 0x9f, 0x9d, + 0x3c, 0xda, 0xcb, 0xa6, 0x94, 0x94, 0x44, 0xd3, + 0xc6, 0x8b, 0xb5, 0xae, 0x45, 0x25, 0xef, 0x2a, + 0x24, 0x1, 0x3a, 0xf6, 0xf, 0xe, 0xcb, 0x10, + 0xc4, 0xe0, 0xf4, 0x3d, 0xf4, 0xf5, 0xea, 0x9b, + 0xd1, 0x16, 0x1b, 0x62, 0x11, 0x3e, 0x20, 0x3a, + 0x68, 0xc8, 0xf0, 0xe, 0x55, 0xbe, 0x51, 0x4d, + 0xbe, 0x1f, 0x4f, 0xda, 0x84, 0xda, 0xc4, 0x9e, + 0x24, 0xd7, 0x46, 0x82, 0x56, 0x4e, 0x61, 0x63, + 0xda, 0x18, 0xea, 0xc6, 0xc3, 0x21, 0x89, 0x18, + 0xe, 0x87, 0xb7, 0x91, 0xfe, 0x8d, 0xe, 0xac, + 0x75, 0x58, 0xe5, 0x9f, 0x1f, 0x93, 0xa6, 0x49, + 0x24, 0xa2, 0xc6, 0xe8, 0x9d, 0x9c, 0x6d, 0xc1, + 0xf, 0xfc, 0xe3, 0x57, 0xd3, 0xc2, 0x10, 0x91, + 0x9a, 0xa8, 0xaa, 0xd7, 0xf, 0xaa, 0x75, 0x90, + 0x4a, 0x10, 0xef, 0xb6, 0xdd, 0x6c, 0xd5, 0x1a, + 0xe3, 0xbb, 0xe0, 0x64, 0x44, 0xc, 0x59, 0xa1, + 0xef, 0x3, 0x52, 0xac, 0xa4, 0x85, 0x3e, 0x40, + 0xee, 0x5c, 0xef, 0xcf, 0xb1, 0xaa, 0x88, 0xe5, + 0x56, 0xb8, 0xcd, 0x87, 0xc7, 0xc6, 0xd3, 0xb4, + 0x85, 0x8f, 0x2a, 0xc9, 0xcd, 0x8a, 0x8b, 0x25, + 0x12, 0x71, 0x76, 0xc9, 0xaa, 0x62, 0x75, 0x80, + 0x6e, 0xa3, 0xf9, 0xa5, 0xfc, 0x90, 0xac, 0x28, + 0x13, 0x82, 0xbb, 0x5d, 0xa6, 0x93, 0x47, 0xd4, + 0xf, 0x3b, 0x19, 0xf6, 0x81, 0xdb, 0x55, 0xb0, + 0x47, 0x75, 0x63, 0x93, 0xb4, 0xdd, 0xf0, 0xaf, + 0xb7, 0x44, 0xcb, 0x7, 0x7b, 0x35, 0xc5, 0xe4, + 0x45, 0xfe, 0xbb, 0x11, 0x1a, 0x90, 0x96, 0x3a, + 0x7, 0x2a, 0xef, 0x9c, 0xc, 0xae, 0x38, 0x26, + 0xef, 0xc2, 0xc3, 0x53, 0xfa, 0x54, 0xcf, 0x6f, + 0xf7, 0xa, 0xea, 0x19, 0xa8, 0xf, 0xbd, 0xa7, + 0x3f, 0xcd, 0x38, 0x2c, 0xf3, 0x97, 0xfb, 0xdb, + 0xcb, 0xc5, 0x83, 0x80, 0x91, 0x3d, 0xc7, 0x29, + 0x67, 0x16, 0xa5, 0xd1, 0x41, 0xd0, 0xa1, 0x9b, + 0xde, 0x13, 0x83, 0x12, 0x36, 0x75, 0x81, 0x71, + 0x6b, 0xbc, 0x72, 0xcb, 0x37, 0x4, 0x6, 0x7c, + 0x3a, 0x22, 0x2b, 0xa, 0x11, 0xd3, 0x33, 0x8f, + 0x3, 0x54, 0x8e, 0x79, 0xb6, 0x36, 0x93, 0x92, + 0xb8, 0xf, 0x24, 0x4a, 0xd3, 0xd5, 0x27, 0x66, + 0xd1, 0xde, 0xe3, 0xaa, 0x4b, 0x2a, 0xe9, 0x22, + 0x9b, 0xbf, 0x6e, 0x9a, 0xf7, 0xa, 0x2f, 0x24, + 0x13, 0xd5, 0xd5, 0xbb, 0xa3, 0xba, 0x8f, 0xfc, + 0x28, 0xa8, 0xbe, 0xe6, 0x9f, 0xea, 0xed, 0xb1, + 0xba, 0xaf, 0xf, 0x1c, 0x1e, 0x51, 0xf8, 0xd7, + 0x1b, 0xa5, 0xa6, 0x63, 0x40, 0x6e, 0x3f, 0xa2, + 0x57, 0x6f, 0x57, 0xe4, 0x27, 0xc2, 0x3c, 0x33, + 0xc6, 0x9c, 0x24, 0xd0, 0x53, 0xc4, 0xfc, 0xed, + 0x8e, 0x1d, 0xf, 0xc3, 0x86, 0x9, 0x3d, 0x1d, + 0xc2, 0xdb, 0x24, 0x1a, 0x65, 0xf4, 0x30, 0xa5, + 0xc, 0x48, 0x37, 0xc5, 0x53, 0x35, 0x3b, 0xab, + 0xd, 0x96, 0x30, 0xd7, 0x1d, 0x66, 0x18, 0xc2, + 0x47, 0x3a, 0xef, 0xbe, 0x2e, 0xe4, 0x54, 0x9d, + 0xc4, 0xa5, 0xb9, 0xb3, 0x4c, 0x12, 0x73, 0x35, + 0xf0, 0x7, 0xe, 0x36, 0x88, 0xb2, 0x4b, 0x29, + 0xb, 0x4e, 0x84, 0x11, 0xaa, 0x9a, 0x3e, 0xb1, + 0xd7, 0xec, 0xfb, 0x7f, 0x10, 0x70, 0x1f, 0x26, + 0xf0, 0x27, 0x46, 0x5d, 0x4, 0x51, 0x97, 0x29, + 0xb4, 0x66, 0x39, 0x1, 0x82, 0x47, 0xd8, 0x5f, + 0xa9, 0xb3, 0xa1, 0xb8, 0xde, 0x1, 0xe1, 0xc4, + 0x47, 0xc5, 0xe8, 0xe6, 0xbb, 0xc0, 0xb6, 0x41, + 0x55, 0x10, 0x79, 0xa8, 0xd0, 0xd, 0x1, 0x56, + 0x29, 0x6c, 0xa5, 0x96, 0x87, 0x59, 0x4b, 0xd, + 0xc8, 0x3, 0x5, 0xaa, 0xa9, 0x6a, 0xb1, 0x10, + 0xbc, 0x1, 0x68, 0xd3, 0xa5, 0x52, 0x41, 0xe1, + 0x1f, 0x53, 0x7, 0xc6, 0xad, 0xb8, 0xc4, 0xf0, + 0x28, 0xe9, 0x3, 0x3a, 0xee, 0xce, 0x2c, 0xe2, + 0xb0, 0xda, 0x78, 0x3d, 0x37, 0x7, 0x2d, 0x1f, + 0xf1, 0x47, 0x81, 0x4, 0x67, 0x6e, 0xd, 0xa1, + 0x2b, 0x4, 0xe8, 0xd9, 0xf4, 0xaf, 0x35, 0xca, + 0xa5, 0xd1, 0xe3, 0xec, 0xc5, 0x82, 0x50, 0x99, + 0x9a, 0xee, 0xea, 0x53, 0x41, 0x86, 0x97, 0x44, + 0xeb, 0x58, 0x43, 0x47, 0xe7, 0xa0, 0xd3, 0x28, + 0xfc, 0xe7, 0x13, 0x8b, 0x56, 0xe3, 0xdb, 0xa9, + 0xcd, 0x9, 0xc8, 0x7, 0x11, 0xeb, 0xbf, 0xac, + 0x76, 0x72, 0x60, 0xaf, 0x9c, 0xba, 0x8a, 0x64, + 0xfb, 0xf4, 0xab, 0x27, 0x29, 0xe7, 0xec, 0x69, + 0x21, 0xcb, 0x5b, 0x79, 0x56, 0x10, 0xc1, 0x8, + 0xd5, 0x5d, 0x93, 0xb1, 0x70, 0x88, 0xf2, 0x19, + 0x41, 0xc6, 0xc2, 0x84, 0xdd, 0xf0, 0xb3, 0x40, + 0x12, 0x71, 0x24, 0x54, 0xc4, 0x5e, 0xfb, 0x5f, + 0x47, 0x8c, 0xa9, 0x4, 0x5a, 0xd5, 0x61, 0x19, + 0xb5, 0x7f, 0xc9, 0xbd, 0x87, 0xb2, 0xcd, 0x57, + 0x99, 0x50, 0x67, 0x1d, 0xb0, 0x1d, 0x82, 0xdd, + 0xef, 0x32, 0x38, 0xb9, 0xc7, 0x86, 0xb4, 0xd2, + 0xd6, 0xe1, 0x33, 0xb2, 0xdb, 0x5e, 0xc2, 0xa3, + 0x49, 0xa6, 0x5f, 0x79, 0x32, 0x50, 0x41, 0x5b, + 0xd7, 0x87, 0x74, 0xf5, 0xc9, 0x9c, 0x78, 0xb7, + 0xb, 0x1f, 0x72, 0xba, 0xd9, 0x3a, 0x4d, 0x18, + 0x45, 0x1d, 0xad, 0xef, 0xc4, 0xdc, 0x30, 0xe8, + 0x2, 0xb1, 0x7f, 0x6c, 0x8f, 0xaa, 0xd0, 0x40, + 0x17, 0xe, 0x58, 0x93, 0x42, 0x49, 0x63, 0x77, + 0x48, 0x55, 0x90, 0x2f, 0x7c, 0x3b, 0xee, 0x3c, + 0xac, 0xd, 0xd8, 0x72, 0x23, 0xd7, 0xa5, 0x6e, + 0xb0, 0xd2, 0x91, 0x25, 0x60, 0x9a, 0x52, 0xab, + 0xbd, 0x63, 0xce, 0xba, 0xda, 0xb1, 0xd7, 0xc7, + 0x3d, 0x21, 0x4e, 0x9c, 0x5a, 0x1e, 0x8d, 0xf4, + 0xa, 0xdb, 0xd9, 0xf, 0x20, 0x7e, 0xfb, 0xbf, + 0x36, 0x9c, 0x4f, 0xbd, 0xf7, 0xdb, 0x5b, 0xa2, + 0x6, 0xb2, 0x0, 0xe2, 0xa2, 0x9e, 0x4e, 0x19, + 0xd4, 0x69, 0xa9, 0x51, 0x69, 0x8b, 0xf5, 0xe1, + 0xad, 0x89, 0x8, 0xc5, 0x4f, 0xac, 0x1b, 0x7d, + 0xe7, 0xa, 0x9, 0x7d, 0x34, 0xf5, 0x3f, 0x46, + 0x80, 0xb9, 0xb9, 0x45, 0x58, 0xcd, 0x6c, 0xb5, + 0x5f, 0x60, 0xeb, 0x5a, 0xe3, 0xa3, 0x8, 0x5e, + 0xb1, 0xc4, 0x73, 0xc5, 0xa5, 0x67, 0x56, 0xd3, + 0xc6, 0x8a, 0x55, 0x6b, 0xd7, 0xd7, 0xc, 0x20, + 0xe6, 0xc, 0x73, 0x8, 0x2, 0x4b, 0xfb, 0xdd, + 0x4d, 0x4e, 0xa8, 0xb8, 0xd8, 0x4b, 0x53, 0x2f, + 0xc2, 0xfb, 0x5d, 0xa1, 0x6a, 0x16, 0x6b, 0xe, + 0xf1, 0xa1, 0xa5, 0x5b, 0xdf, 0x9c, 0x23, 0xb5, + 0x94, 0x9c, 0xae, 0x7b, 0xbe, 0x42, 0xb5, 0x79, + 0x80, 0xc3, 0x43, 0x41, 0xa4, 0x1b, 0x18, 0xfc, + 0x52, 0xcf, 0x43, 0xc5, 0x80, 0x7b, 0xbd, 0xc1, + 0x20, 0x5e, 0x65, 0xec, 0xc5, 0xfc, 0x3, 0xec, + 0x8f, 0x61, 0x66, 0xf5, 0x15, 0x67, 0xc8, 0xb6, + 0xef, 0x9a, 0xba, 0xb7, 0xcb, 0x2c, 0xac, 0x1b, + 0x50, 0xda, 0xb6, 0x29, 0xa4, 0x37, 0xe9, 0x96, + 0xa0, 0x7, 0x7d, 0x49, 0xa6, 0xce, 0xf3, 0xf0, + 0x19, 0xdf, 0x61, 0xc7, 0xa4, 0x7b, 0x5a, 0xd4, + 0x99, 0xb2, 0x64, 0xe7, 0xd1, 0x6b, 0x7f, 0xe8, + 0xb8, 0xd3, 0x89, 0xee, 0x96, 0xc0, 0xed, 0x5d, + 0x7e, 0x48, 0x2, 0xd2, 0x25, 0xd0, 0x5, 0xef, + 0x93, 0x72, 0x7c, 0x8c, 0xbd, 0x6e, 0x49, 0xd3, + 0x38, 0x46, 0x1c, 0xff, 0x28, 0x4e, 0x1b, 0xad, + 0x39, 0x2f, 0x65, 0x26, 0xe2, 0x70, 0x3d, 0xb8, + 0x7a, 0xd3, 0x38, 0x38, 0xfc, 0x3a, 0x67, 0x78, + 0xdb, 0x9, 0xcb, 0xbf, 0xc9, 0xe1, 0xee, 0x69, + 0x2b, 0xd, 0xb1, 0x79, 0x13, 0xd0, 0xa5, 0x75, + 0x6, 0x8, 0x79, 0xa7, 0x7c, 0xc, 0xe7, 0x1b, + 0x9c, 0x36, 0x64, 0xbe, 0x20, 0x65, 0xa2, 0xd4, + 0xd9, 0xc, 0x68, 0xe, 0x88, 0x2b, 0x93, 0x60, + 0xf1, 0xa5, 0x82, 0xc5, 0x4d, 0x2b, 0x7d, 0x73, + 0xe9, 0x13, 0x8c, 0xc1, 0x8, 0xbd, 0x21, 0x65, + 0x77, 0x2f, 0x34, 0xb1, 0x97, 0x9f, 0xd8, 0x55, + 0xcf, 0x75, 0xc2, 0xf2, 0x41, 0x68, 0xc1, 0x9c, + 0x1c, 0xd7, 0x23, 0xbf, 0x83, 0x2a, 0x9, 0x66, + 0xce, 0x8f, 0xd2, 0x12, 0x79, 0x93, 0xef, 0x8, + 0x9b, 0xeb, 0x2f, 0xc, 0xe4, 0x5b, 0x71, 0x1a, + 0xef, 0x11, 0x65, 0xd8, 0x6d, 0x8c, 0x59, 0x53, + 0x70, 0x1d, 0xb5, 0x81, 0xff, 0xc0, 0x7d, 0x87, + 0xa5, 0x21, 0x5d, 0x9f, 0x63, 0xb2, 0xe7, 0xe9, + 0xd0, 0x49, 0x41, 0xc7, 0x3c, 0xe1, 0x2b, 0xb1, + 0xac, 0x15, 0xcd, 0xb0, 0xa8, 0xdc, 0xae, 0x3b, + 0xef, 0x32, 0x98, 0x8c, 0xc7, 0x40, 0xa6, 0x81, + 0x1, 0xa1, 0x7d, 0x89, 0x46, 0x99, 0x91, 0x24, + 0xce, 0xb2, 0x70, 0x82, 0x92, 0xf3, 0x60, 0x66, + 0x34, 0x6, 0x37, 0xad, 0x5c, 0xed, 0xc3, 0x27, + 0x68, 0x8c, 0x56, 0xe7, 0xf, 0x73, 0x5c, 0x7e, + 0x9e, 0xd0, 0x8c, 0x99, 0x5a, 0xb1, 0x15, 0x98, + 0xbb, 0x79, 0x9f, 0xd1, 0x69, 0xce, 0x76, 0x5, + 0xcb, 0x8e, 0x18, 0xb3, 0x84, 0x65, 0xa9, 0x2, + 0xbc, 0x43, 0x8b, 0x7e, 0xe9, 0xe2, 0xe6, 0x74, + 0x31, 0x8d, 0xe7, 0xa2, 0x42, 0x8f, 0xca, 0x38, + 0x59, 0x85, 0x25, 0x47, 0xd2, 0x86, 0x47, 0x9, + 0xc2, 0x11, 0x2, 0x91, 0xe6, 0xf3, 0x47, 0xc2, + 0x9c, 0x28, 0x2f, 0xbb, 0xac, 0xde, 0x9f, 0xd, + 0xc2, 0x96, 0x4f, 0x43, 0xca, 0x32, 0xed, 0x34, + 0xba, 0xad, 0xef, 0xbe, 0x68, 0xc7, 0xa2, 0x83, + 0xaf, 0xe, 0xd3, 0x72, 0x52, 0xd1, 0x76, 0x3d, + 0x9a, 0x98, 0x39, 0xf4, 0x3e, 0x14, 0x27, 0xff, + 0xb2, 0x37, 0x23, 0xc5, 0x6d, 0x66, 0xef, 0xaa, + 0xfe, 0xe7, 0xe4, 0x86, 0xa1, 0xe, 0x4e, 0x36, + 0x64, 0xb1, 0x67, 0xf, 0x94, 0x6f, 0x77, 0xd5, + 0xec, 0xe2, 0x5e, 0xc8, 0xe3, 0x64, 0x29, 0x92, + 0xd, 0x20, 0x34, 0x9f, 0x19, 0x6e, 0x85, 0xf8, + 0x48, 0x78, 0xb0, 0xf, 0x42, 0xb2, 0x8c, 0xea, + 0xc2, 0x4d, 0xd3, 0x23, 0xb, 0x4d, 0x20, 0x33, + 0xc7, 0x46, 0x0, 0x45, 0x37, 0xc6, 0xcb, 0xd0, + 0xec, 0x11, 0xc6, 0x74, 0x91, 0x7d, 0x6b, 0x54, + 0x56, 0x10, 0x8d, 0xd0, 0xce, 0xe8, 0x57, 0x3b, + 0x83, 0xd8, 0x25, 0x51, 0x79, 0x48, 0xa, 0xa5, + 0xc3, 0xe4, 0x65, 0x33, 0xb2, 0x89, 0xa6, 0x4c, + 0xe8, 0xc8, 0x9e, 0xce, 0xea, 0x2a, 0x55, 0x40, + 0xfc, 0x26, 0x29, 0xd4, 0x2d, 0x7e, 0xe1, 0xb1, + 0x4d, 0x65, 0x1, 0xe9, 0x98, 0xc9, 0xf4, 0x69, + 0x10, 0xd9, 0xa3, 0xf9, 0x34, 0xaf, 0x3c, 0x34, + 0x64, 0x23, 0xde, 0xb8, 0x1c, 0x33, 0x18, 0x74, + 0x67, 0xb4, 0x4a, 0x71, 0xa6, 0x89, 0x2, 0xfe, + 0xf7, 0xf1, 0x32, 0xc7, 0x98, 0xad, 0xe5, 0x10, + 0x98, 0x3c, 0x6c, 0xaf, 0x1f, 0x13, 0x3d, 0xcc, + 0xfc, 0x3b, 0x67, 0x33, 0x34, 0xc9, 0x31, 0xcd, + 0x3f, 0xd, 0x3c, 0x5a, 0xb6, 0xc2, 0x8, 0xea, + 0xe2, 0xae, 0xdd, 0xfc, 0x6f, 0xca, 0xb5, 0x67, + 0x11, 0xce, 0xd5, 0xda, 0x3a, 0x8b, 0x7, 0xf2, + 0xc0, 0x9e, 0x78, 0x18, 0x92, 0x9f, 0x64, 0x26, + 0x9f, 0x66, 0x62, 0x66, 0xa1, 0x7e, 0x3, 0xf5, + 0xb9, 0xe6, 0x74, 0x20, 0x88, 0xb7, 0x7e, 0x62, + 0x7a, 0x33, 0x21, 0x9, 0x9c, 0x91, 0x3b, 0x62, + 0x9, 0x46, 0xd3, 0xd1, 0x1f, 0xc5, 0x3a, 0x8f, + 0x69, 0x27, 0x2c, 0x7b, 0xec, 0xda, 0x79, 0xf1, + 0xc9, 0xe9, 0x98, 0xd0, 0xa, 0xc9, 0xf6, 0x37, + 0x28, 0xf8, 0xfc, 0xe, 0xdc, 0xf, 0xe9, 0x23, + 0xf6, 0x84, 0x25, 0x96, 0x2c, 0x24, 0x14, 0xd7, + 0xe2, 0x5e, 0x1c, 0x56, 0x7f, 0x99, 0x98, 0x62, + 0x76, 0xcc, 0x84, 0x44, 0xd6, 0xb9, 0x47, 0x2b, + 0x52, 0xfb, 0x42, 0x40, 0xf3, 0x63, 0xaf, 0xd4, + 0x10, 0x5, 0xf9, 0x3b, 0xc8, 0x53, 0xa9, 0x45, + 0xa4, 0x50, 0x41, 0x83, 0xe8, 0x4a, 0x9, 0xb6, + 0xf1, 0x77, 0x70, 0xe3, 0x61, 0x30, 0xd8, 0x90, + 0x49, 0x52, 0x4b, 0x4a, 0xf2, 0x66, 0x84, 0xaf, + 0x71, 0x1, 0x40, 0x66, 0xf6, 0x3, 0xc9, 0x23, + 0xb1, 0x1a, 0xc1, 0xb2, 0xf7, 0x35, 0x1a, 0xc9, + 0x3a, 0x75, 0xb1, 0xa7, 0x4, 0xff, 0x69, 0xa, + 0x90, 0x58, 0xd4, 0xf4, 0x16, 0x79, 0xe1, 0xae, + 0x39, 0x9d, 0xbb, 0x32, 0x6b, 0x3, 0xe2, 0xf5, + 0x73, 0x83, 0x7e, 0x3c, 0xf8, 0x29, 0xab, 0xcc, + 0xdc, 0xf0, 0x13, 0xdb, 0x86, 0x28, 0x88, 0x8e, + 0xde, 0x6a, 0x29, 0xf1, 0xea, 0x0, 0x83, 0x97, + 0x1, 0x32, 0x5f, 0xaa, 0x5b, 0x1b, 0xe4, 0x87, + 0xec, 0x90, 0x45, 0xc7, 0xc5, 0x6c, 0x11, 0x83, + 0x95, 0xab, 0xdd, 0x71, 0x69, 0x24, 0xc, 0x5c, + 0xc0, 0xf3, 0xc1, 0xb0, 0x5e, 0x1, 0x5e, 0x4, + 0xa1, 0x6e, 0x6e, 0x7d, 0x3f, 0x6f, 0xbd, 0x5d, + 0x9, 0x8f, 0x23, 0x53, 0x74, 0x4b, 0xa9, 0x53, + 0xd2, 0x10, 0xa1, 0xc0, 0x8e, 0x18, 0xa, 0x2f, + 0x88, 0x8d, 0x4b, 0xf8, 0xc2, 0x3d, 0xeb, 0x34, + 0x23, 0xa, 0x80, 0xc, 0x69, 0x21, 0x3, 0xc1, + 0x6f, 0xbe, 0xdf, 0xf6, 0x2c, 0x27, 0x77, 0xa2, + 0xc5, 0x5c, 0x9, 0x54, 0x5d, 0x4a, 0x4c, 0xb, + 0x6b, 0xb5, 0x88, 0x11, 0x42, 0x62, 0x39, 0x89, + 0x9e, 0x36, 0xd3, 0x91, 0xf6, 0x70, 0x18, 0x35, + 0x79, 0xaf, 0x73, 0xf3, 0x0, 0x75, 0x5a, 0xa3, + 0xce, 0xf1, 0x42, 0x80, 0x19, 0x5e, 0x42, 0x56, + 0x53, 0x85, 0xbb, 0xf4, 0x29, 0xac, 0x84, 0x1d, + 0x97, 0x1, 0x1c, 0xc4, 0x58, 0xcb, 0x33, 0xc4, + 0xdc, 0x1e, 0x59, 0x8f, 0x48, 0xa9, 0x59, 0xfd, + 0xaf, 0xa3, 0x5c, 0x19, 0x17, 0x6b, 0x46, 0x2d, + 0xab, 0x44, 0xa3, 0xcc, 0x1a, 0xaa, 0x23, 0x4e, + 0x58, 0x37, 0x7b, 0x11, 0x14, 0xc2, 0xf1, 0xc9, + 0x58, 0x99, 0xd3, 0x3c, 0xec, 0xb9, 0xbe, 0x17, + 0x3c, 0x8d, 0x1c, 0x87, 0x9d, 0xe1, 0xb9, 0xad, + 0x68, 0x36, 0xd5, 0xfc, 0x24, 0x9b, 0x34, 0x5, + 0x26, 0xac, 0x15, 0x9f, 0xd6, 0x70, 0x74, 0x6c, + 0x72, 0xf, 0x6, 0x6, 0x5a, 0xc, 0xc0, 0x78, + 0x47, 0x8e, 0xcf, 0xf2, 0xce, 0x8, 0xe2, 0xa4, + 0xc6, 0x7d, 0x2d, 0x70, 0x14, 0xe2, 0xc6, 0xfc, + 0x63, 0x7a, 0x42, 0x8c, 0x45, 0xae, 0xe8, 0x3b, + 0x30, 0x48, 0xda, 0x3e, 0x14, 0xb5, 0x8b, 0x10, + 0xae, 0x56, 0xbd, 0x17, 0xdf, 0xcb, 0x63, 0xf5, + 0xb, 0x2b, 0xd7, 0x34, 0x7c, 0x96, 0x43, 0xe9, + 0x17, 0xd4, 0x53, 0x2b, 0x4e, 0xba, 0x61, 0x57, + 0x92, 0xdb, 0xe8, 0x37, 0xf4, 0xa3, 0x59, 0x88, + 0x74, 0xc2, 0x3c, 0x5d, 0x54, 0x30, 0xb9, 0x6, + 0xbe, 0x75, 0x13, 0xe8, 0xf2, 0xe8, 0xcb, 0x45, + 0x73, 0x70, 0xaf, 0x94, 0xe6, 0xc5, 0xb0, 0xdf, + 0xd2, 0xd5, 0x57, 0x97, 0x7c, 0x97, 0xde, 0x55, + 0xaf, 0xbb, 0xed, 0x19, 0x35, 0x17, 0xf4, 0x23, + 0x38, 0x9c, 0xce, 0x37, 0xfe, 0xd8, 0x4e, 0xd8, + 0x99, 0xba, 0x33, 0x22, 0xf2, 0xeb, 0xab, 0x97, + 0xee, 0x9d, 0xab, 0x67, 0x95, 0x35, 0xdf, 0xc8, + 0xb6, 0xa0, 0xf, 0x15, 0x51, 0xa9, 0x76, 0x15, + 0xdd, 0xbd, 0xac, 0x12, 0xce, 0x51, 0xde, 0x68, + 0x15, 0xaf, 0x27, 0xcf, 0xd1, 0xba, 0x7c, 0x17, + 0xef, 0xbf, 0xbb, 0xc0, 0x6e, 0x58, 0x73, 0xf6, + 0x57, 0xe1, 0x8d, 0xb0, 0x9a, 0x5a, 0x9, 0x19, + 0xef, 0xdd, 0x4, 0xe1, 0x76, 0x94, 0x31, 0xd7, + 0x26, 0x9f, 0x9c, 0x27, 0xc4, 0x2b, 0x4b, 0xf6, + 0x3b, 0xa1, 0x8c, 0xf4, 0x21, 0xde, 0x39, 0x14, + 0x5a, 0x54, 0xac, 0x95, 0x2f, 0xa0, 0x60, 0x53, + 0x87, 0x5b, 0x71, 0x92, 0xae, 0xf9, 0x6c, 0x62, + 0x76, 0x7e, 0x91, 0x11, 0xa6, 0xf4, 0xf2, 0xa8, + 0xdf, 0xc1, 0xf6, 0x3a, 0xdb, 0x34, 0x96, 0x9, + 0x71, 0xb4, 0x4, 0xfa, 0xd4, 0x3, 0x46, 0x16, + 0x78, 0x41, 0x42, 0x7d, 0x15, 0x68, 0x63, 0x55, + 0x23, 0x4, 0x46, 0x5d, 0xe1, 0xd8, 0xe7, 0x5f, + 0x55, 0x39, 0xd2, 0x45, 0xb2, 0x0, 0x35, 0xde, + 0xd8, 0x9d, 0xc7, 0x3a, 0x8f, 0x37, 0x7e, 0xe5, + 0x9e, 0xcf, 0xd1, 0x6a, 0x22, 0xe1, 0x51, 0xb2, + 0xe6, 0x99, 0x3e, 0x83, 0xeb, 0x34, 0x9d, 0x34, + 0x7, 0x1c, 0xbe, 0x91, 0x69, 0x9e, 0xaa, 0xcb, + 0x86, 0xd2, 0xb6, 0xed, 0xa5, 0x4, 0xf9, 0x7d, + 0xf8, 0xba, 0x2a, 0x27, 0x38, 0xe1, 0xaa, 0x22, + 0x94, 0x46, 0x1f, 0x1b, 0xcf, 0xc4, 0x78, 0x88, + 0x3d, 0x50, 0x83, 0x30, 0x61, 0x87, 0xb6, 0x38, + 0x5b, 0x4f, 0x5a, 0x3, 0x2d, 0x5d, 0xa6, 0x33, + 0x38, 0xe7, 0x8b, 0x60, 0x1, 0x8e, 0xde, 0x69, + 0x8e, 0x4d, 0x60, 0x24, 0x3b, 0x47, 0x4b, 0x56, + 0xea, 0xf9, 0xc8, 0xfa, 0x2d, 0x65, 0x7b, 0xad, + 0xee, 0xe4, 0x91, 0x20, 0x6f, 0x64, 0x6e, 0x81, + 0x69, 0xda, 0xf5, 0x3c, 0x3d, 0xff, 0x4c, 0xe9, + 0x9b, 0x4d, 0xa8, 0x67, 0x9e, 0x67, 0x7f, 0x84, + 0xdb, 0x7a, 0xb7, 0x24, 0x32, 0xa0, 0x80, 0x16, + 0x55, 0x2d, 0x1d, 0xc1, 0x3a, 0x19, 0xd3, 0x17, + 0x74, 0x8e, 0x2a, 0x5c, 0xf6, 0x71, 0xf7, 0x25, + 0x3a, 0x54, 0x28, 0xef, 0x50, 0x78, 0x14, 0x5, + 0x49, 0x8a, 0xbb, 0x71, 0xb2, 0xed, 0xa2, 0x5b, + 0xff, 0x2, 0xe, 0xd8, 0x1a, 0x8b, 0x3c, 0xcc, + 0x58, 0x27, 0x71, 0x2d, 0xb, 0x11, 0x9f, 0x6, + 0xc3, 0xfd, 0x37, 0x19, 0xdb, 0xec, 0xa5, 0x4b, + 0x93, 0x81, 0xb6, 0xff, 0xd4, 0xf5, 0x7b, 0xf5, + 0x49, 0x5b, 0x95, 0x9, 0xa4, 0xca, 0xa5, 0x33, + 0x9a, 0xfc, 0x97, 0xec, 0x7b, 0xb, 0xb9, 0x2e, + 0x3b, 0x9d, 0x52, 0xc2, 0xa2, 0x9, 0xc8, 0xbf, + 0x39, 0x16, 0xce, 0x42, 0x3, 0x4b, 0xe3, 0xfc, + 0xfd, 0xc, 0x37, 0x96, 0x10, 0x36, 0xad, 0x44, + 0xda, 0xc5, 0x58, 0x3e, 0x78, 0x52, 0xa1, 0x65, + 0xed, 0x89, 0xe7, 0xea, 0xbf, 0xa8, 0x6a, 0xf2, + 0xa7, 0x8e, 0x9d, 0x1, 0x25, 0x83, 0x57, 0x5f, + 0x51, 0xe6, 0xe1, 0xa4, 0x4f, 0xf6, 0x81, 0xd7, + 0xe6, 0x98, 0x29, 0x98, 0x58, 0xfe, 0xda, 0x45, + 0xab, 0x38, 0x6, 0x91, 0x97, 0xb7, 0xa3, 0x4f, + 0x93, 0x8d, 0x8a, 0x8b, 0x5, 0xe9, 0x5, 0x98, + 0x3b, 0xc4, 0xb7, 0xe1, 0x68, 0x58, 0xa0, 0x3b, + 0x99, 0xea, 0x8a, 0xa9, 0xfb, 0x55, 0xe2, 0xc7, + 0x1d, 0x87, 0x3, 0x40, 0x24, 0x13, 0x28, 0x6a, + 0x34, 0x8a, 0xff, 0x62, 0x91, 0xb8, 0x7d, 0x28, + 0x1a, 0xd2, 0xfc, 0x4e, 0xa3, 0xda, 0x66, 0x69, + 0x15, 0xc0, 0xda, 0x15, 0x3e, 0x67, 0x12, 0x95, + 0x6, 0x1b, 0xf4, 0x60, 0xe4, 0x39, 0x82, 0xe9, + 0x2e, 0xbe, 0xab, 0x8c, 0x2c, 0x6e, 0xd6, 0x40, + 0x91, 0xc0, 0x68, 0xf7, 0xa2, 0x41, 0xd0, 0xa8, + 0x7, 0xab, 0x13, 0x34, 0x16, 0xf4, 0x73, 0x4f, + 0x1d, 0x21, 0x1a, 0x7d, 0xad, 0x43, 0x12, 0xf, + 0xb7, 0xfe, 0xa3, 0x81, 0xe9, 0xb5, 0x2d, 0xd3, + 0xa, 0x29, 0xb5, 0x32, 0xcb, 0x49, 0x6f, 0x1, + 0x90, 0x45, 0x62, 0xca, 0x1b, 0x66, 0x39, 0x88, + 0x1c, 0xee, 0x30, 0xa8, 0xb5, 0x37, 0xd0, 0xfa, + 0x46, 0x52, 0x16, 0x30, 0x17, 0xcf, 0x88, 0xd0, + 0x4, 0x5d, 0xde, 0x5e, 0x4f, 0xe7, 0xa9, 0xbf, + 0x3c, 0x29, 0x3a, 0x63, 0x67, 0x23, 0xb3, 0x7c, + 0x51, 0x17, 0xfe, 0x8d, 0xdb, 0xc8, 0x8d, 0x70, + 0xe9, 0x6f, 0x56, 0xe5, 0x44, 0xb2, 0x94, 0xeb, + 0x47, 0xca, 0x3a, 0xdc, 0xe3, 0x33, 0x87, 0x9c, + 0xe8, 0x89, 0x4b, 0x41, 0xb8, 0xb3, 0x69, 0xb0, + 0x7f, 0xc8, 0xc7, 0x74, 0xf5, 0xcb, 0x20, 0xad, + 0xea, 0xbb, 0x3d, 0x11, 0xc6, 0xc0, 0xd2, 0x88, + 0x8b, 0x16, 0xee, 0x62, 0x5a, 0x4d, 0x32, 0xe7, + 0x48, 0xae, 0xab, 0x5e, 0xc2, 0x83, 0xc4, 0xfc, + 0xd1, 0xb9, 0x71, 0xf2, 0x9, 0x7f, 0xdc, 0xbc, + 0x28, 0x74, 0xa0, 0x37, 0xa9, 0x5b, 0x6c, 0x7c, + 0x9b, 0x61, 0x94, 0x88, 0xf7, 0x40, 0x84, 0x75, + 0xa5, 0x50, 0xab, 0xb0, 0x92, 0x66, 0x10, 0x66, + 0xf6, 0xec, 0x6b, 0x5e, 0x31, 0x9b, 0xc4, 0xfa, + 0x95, 0x8b, 0xe7, 0xd4, 0xba, 0x81, 0xd2, 0x85, + 0x30, 0x4, 0x8b, 0x3d, 0xfa, 0x8a, 0x8f, 0x9b, + 0x54, 0x6a, 0x4d, 0x35, 0xa2, 0xe9, 0x58, 0x95, + 0xe3, 0xd1, 0x71, 0xcd, 0x3a, 0x54, 0xae, 0xd9, + 0x5c, 0x83, 0xd, 0x15, 0x64, 0x66, 0xee, 0x39, + 0xa1, 0x85, 0xe2, 0x28, 0xf5, 0x66, 0x5f, 0xec, + 0x39, 0x70, 0x96, 0x2c, 0x72, 0x9e, 0x57, 0xfd, + 0x57, 0x27, 0xb7, 0xda, 0x79, 0x39, 0xd8, 0x3b, + 0x2e, 0xa3, 0xb0, 0xde, 0xbf, 0x60, 0xb6, 0x42, + 0x78, 0x9d, 0x8f, 0xe8, 0x1c, 0x7c, 0x45, 0x72, + 0x3, 0xc4, 0xd5, 0x81, 0xf6, 0xe6, 0x9, 0x29, + 0x1e, 0xcd, 0xf3, 0xe, 0xd6, 0x65, 0xee, 0x6d, + 0x90, 0x17, 0x95, 0x20, 0x54, 0xf1, 0xd, 0x2f, + 0xa0, 0xac, 0xe3, 0x4b, 0xfc, 0xa4, 0xdc, 0xab, + 0x9d, 0x9e, 0x32, 0x63, 0x72, 0xd1, 0xb4, 0xef, + 0xf1, 0x83, 0xa7, 0xd7, 0x2b, 0x1a, 0x9a, 0x9e, + 0xfa, 0x1e, 0xb, 0x2b, 0xdc, 0x7b, 0x87, 0x96, + 0xf, 0xdb, 0x75, 0xb9, 0x6, 0x2b, 0xd3, 0x95, + 0xc5, 0xb3, 0x9, 0x53, 0x94, 0x54, 0x1f, 0xd0, + 0x75, 0x5a, 0x36, 0x6a, 0x7c, 0x82, 0xdb, 0xb1, + 0xa2, 0x17, 0xbc, 0xeb, 0x1f, 0xfa, 0x34, 0x3d, + 0xee, 0x68, 0xee, 0x93, 0x33, 0xfb, 0xcb, 0xd2, + 0xa3, 0xd1, 0x24, 0x5e, 0xf4, 0x9, 0xbe, 0x5a, + 0x68, 0x9e, 0x3e, 0xd4, 0x81, 0xcd, 0xa3, 0x1e, + 0x2, 0x13, 0xb4, 0x79, 0x94, 0xc9, 0xb2, 0xde, + 0x56, 0xf1, 0x7b, 0x2f, 0xe2, 0x56, 0xe1, 0x10, + 0xf4, 0x73, 0x2d, 0xc9, 0xca, 0x4d, 0x5f, 0x11, + 0x9e, 0xd6, 0x3c, 0x73, 0x12, 0x57, 0xe9, 0x14, + 0xe0, 0x8d, 0xdd, 0x4b, 0x8a, 0xbb, 0xb3, 0x78, + 0xbe, 0x16, 0x94, 0x93, 0x51, 0x33, 0x7a, 0xa5, + 0x41, 0x14, 0x60, 0x82, 0x94, 0x67, 0x70, 0xea, + 0xe6, 0x3, 0x7f, 0xc5, 0xa0, 0x20, 0x15, 0x88, + 0x53, 0xe3, 0x7e, 0x16, 0x52, 0xe4, 0xca, 0xa0, + 0x6f, 0xb9, 0x68, 0x4e, 0x30, 0xb9, 0x8c, 0xe6, + 0x9c, 0x5e, 0xc2, 0x93, 0xf9, 0xe1, 0x41, 0x4b, + 0x18, 0x42, 0x6f, 0x8f, 0x96, 0x3d, 0x2b, 0x28, + 0xd5, 0x53, 0x62, 0xdd, 0x6b, 0xd0, 0xf8, 0x2e, + 0xa6, 0x97, 0xe5, 0x87, 0xc5, 0xf6, 0x96, 0x7b, + 0xc4, 0x3e, 0x84, 0xc9, 0xf6, 0x34, 0x63, 0x46, + 0xe1, 0x10, 0xa5, 0x91, 0x6b, 0xff, 0x10, 0x3f, + 0x50, 0x2e, 0xd7, 0x39, 0x12, 0x7a, 0x15, 0x85, + 0xed, 0x99, 0xdb, 0x9b, 0x99, 0x6b, 0xfa, 0xfa, + 0x93, 0x7, 0x44, 0xbe, 0xbe, 0x60, 0x23, 0xc1, + 0xec, 0x5c, 0xf6, 0x93, 0x38, 0xf9, 0x89, 0x0, + 0xc5, 0x5f, 0x5b, 0xe2, 0x9d, 0x2b, 0xea, 0x6b, + 0x2e, 0xee, 0xb7, 0x4a, 0x4e, 0x8d, 0xd0, 0x35, + 0xe9, 0xc1, 0x5, 0x2b, 0x83, 0xb7, 0x72, 0x25, + 0xbb, 0xbe, 0xe8, 0x15, 0xf4, 0x74, 0x69, 0x69, + 0x67, 0x8c, 0x5c, 0x31, 0x79, 0x78, 0x2e, 0x43, + 0x83, 0xd1, 0xdd, 0x9, 0xc3, 0xa1, 0x0, 0x13, + 0x31, 0x4b, 0x86, 0xce, 0xee, 0xd7, 0xec, 0xb1, + 0x2c, 0x38, 0x46, 0x68, 0x62, 0xd9, 0x84, 0xdb, + 0x24, 0x62, 0x82, 0xc, 0x12, 0xb7, 0x4f, 0x86, + 0x54, 0x18, 0xc6, 0xd7, 0x94, 0x8b, 0xf2, 0x4c, + 0x17, 0x98, 0xaa, 0xe0, +}; + +const uint8_t expected_cipher_long_input_end[] = { + 0x05, 0x95, 0x58, 0x7b, 0xb4, 0x60, 0x15, + 0x32, 0x9f, 0x38, 0xcc, 0x98, 0x1b, 0xbe, 0x10, 0xa5, 0x06, 0x67, 0xae, 0x38, + 0xbd, 0x7d, 0xb5, 0xcd, 0x58, 0x32, 0xdd, 0x9e, + 0x6a, 0xde, 0xe3, 0x53, +}; + +void aes_ext_flash_ctr_test(uint32_t output_buf_caps) +{ + psa_key_id_t key_id; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + uint8_t nonce[16]; + uint8_t key[16]; + psa_status_t status; + size_t SZ = sizeof(long_input); + memset(nonce, 0x2F, 16); + memset(key, 0x1E, 16); + + uint8_t *ciphertext = heap_caps_malloc(SZ, output_buf_caps); + uint8_t *decryptedtext = heap_caps_malloc(SZ, INTERNAL_DMA_CAPS); + + TEST_ASSERT_NOT_NULL(ciphertext); + TEST_ASSERT_NOT_NULL(decryptedtext); + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Set up key attributes + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_CTR); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 128); + + // Import key + status = psa_import_key(&attributes, key, 16, &key_id); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + size_t output_len; + + // Encrypt with input buffer in external flash + memset(nonce, 0x2F, 16); + + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; + status = psa_cipher_encrypt_setup(&operation, key_id, PSA_ALG_CTR); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + size_t total_len = 0; + status = psa_cipher_update(&operation, long_input, SZ, ciphertext, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_len += output_len; + + status = psa_cipher_finish(&operation, ciphertext + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_len += output_len; + + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_cipher_long_input_end, ciphertext + SZ - 32, 32); + + // Decrypt + memset(nonce, 0x2F, 16); + + psa_cipher_abort(&operation); + operation = (psa_cipher_operation_t)PSA_CIPHER_OPERATION_INIT; + status = psa_cipher_decrypt_setup(&operation, key_id, PSA_ALG_CTR); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_cipher_set_iv(&operation, nonce, 16); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + total_len = 0; + status = psa_cipher_update(&operation, ciphertext, SZ, decryptedtext, SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_len += output_len; + + status = psa_cipher_finish(&operation, decryptedtext + output_len, SZ - output_len, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_len += output_len; + + TEST_ASSERT_EQUAL_HEX8_ARRAY(long_input, decryptedtext, SZ); + + psa_destroy_key(key_id); + free(ciphertext); + free(decryptedtext); +} + +/* Tests how crypto DMA handles data in external memory */ +TEST_CASE("mbedtls AES PSRAM tests", "[aes]") +{ + aes_ctr_alignment_test(INTERNAL_DMA_CAPS, PSRAM_DMA_CAPS); + aes_ctr_alignment_test(PSRAM_DMA_CAPS, INTERNAL_DMA_CAPS); + aes_ctr_alignment_test(PSRAM_DMA_CAPS, PSRAM_DMA_CAPS); + aes_psram_one_buf_ctr_test(); + aes_ctr_stream_test(INTERNAL_DMA_CAPS, PSRAM_DMA_CAPS, TEST_AES_CTR_STREAM_DMA_MODE_LEN); + aes_ctr_stream_test(PSRAM_DMA_CAPS, INTERNAL_DMA_CAPS, TEST_AES_CTR_STREAM_DMA_MODE_LEN); + aes_ctr_stream_test(PSRAM_DMA_CAPS, PSRAM_DMA_CAPS, TEST_AES_CTR_STREAM_DMA_MODE_LEN); +} + +/* Tests how crypto DMA handles data from external flash */ +TEST_CASE("mbedtls AES external flash tests", "[aes]") +{ + aes_ext_flash_ctr_test(PSRAM_DMA_CAPS); + aes_ext_flash_ctr_test(INTERNAL_DMA_CAPS); +} +#endif // CONFIG_SPIRAM_USE_MALLOC + +static SemaphoreHandle_t done_sem; + +static void __attribute__((unused)) aes_ctr_stream_test_task(void *pv) +{ + aes_ctr_stream_test(INTERNAL_DMA_CAPS, INTERNAL_DMA_CAPS, TEST_AES_CTR_STREAM_DMA_MODE_LEN); + xSemaphoreGive(done_sem); + vTaskDelete(NULL); +} + +#if CONFIG_ESP_SYSTEM_RTC_FAST_MEM_AS_HEAP_DEPCHECK && !CONFIG_IDF_TARGET_ESP32H2 +// Not enough rtc memory for test on H2 + +TEST_CASE("mbedtls AES stack in RTC RAM", "[mbedtls]") +{ + done_sem = xSemaphoreCreateBinary(); + static StaticTask_t rtc_task; + size_t STACK_SIZE = 3072; + uint8_t *rtc_stack = heap_caps_calloc(STACK_SIZE, 1, MALLOC_CAP_RTCRAM); + TEST_ASSERT(esp_ptr_in_rtc_dram_fast(rtc_stack)); + + TEST_ASSERT_NOT_NULL(xTaskCreateStatic(aes_ctr_stream_test_task, "aes_ctr_task", STACK_SIZE, NULL, + 3, rtc_stack, &rtc_task)); + TEST_ASSERT_TRUE(xSemaphoreTake(done_sem, 10000 / portTICK_PERIOD_MS)); + + /* Give task time to cleanup before freeing stack */ + vTaskDelay(1000 / portTICK_PERIOD_MS); + free(rtc_stack); + + vSemaphoreDelete(done_sem); +} + +#endif //CONFIG_ESP_SYSTEM_RTC_FAST_MEM_AS_HEAP_DEPCHECK && !CONFIG_IDF_TARGET_ESP32H2 + +#if CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM && CONFIG_SPIRAM_USE_MALLOC + +TEST_CASE("mbedtls AES stack in PSRAM", "[mbedtls]") +{ + done_sem = xSemaphoreCreateBinary(); + static StaticTask_t psram_task; + size_t STACK_SIZE = 3072; + uint8_t *psram_stack = heap_caps_calloc(STACK_SIZE, 1, PSRAM_DMA_CAPS); + + TEST_ASSERT(esp_ptr_external_ram(psram_stack)); + + TEST_ASSERT_NOT_NULL(xTaskCreateStatic(aes_ctr_stream_test_task, "aes_ctr_task", STACK_SIZE, NULL, + 3, psram_stack, &psram_task)); + TEST_ASSERT_TRUE(xSemaphoreTake(done_sem, 10000 / portTICK_PERIOD_MS)); + + /* Give task time to cleanup before freeing stack */ + vTaskDelay(1000 / portTICK_PERIOD_MS); + free(psram_stack); + + vSemaphoreDelete(done_sem); +} + +#endif //CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM && CONFIG_SPIRAM_USE_MALLOC + static const uint8_t key_192[24] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, diff --git a/components/mbedtls/test_apps/main/test_psa_aes_gcm.c b/components/mbedtls/test_apps/main/test_psa_aes_gcm.c index 666714d66a..0f3eff9d3c 100644 --- a/components/mbedtls/test_apps/main/test_psa_aes_gcm.c +++ b/components/mbedtls/test_apps/main/test_psa_aes_gcm.c @@ -1,203 +1,990 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD * - * SPDX-License-Identifier: Unlicense OR CC0-1.0 + * SPDX-License-Identifier: Apache-2.0 */ -#include -#include #include - -#include "esp_log.h" - +#include +#include +#include #include "psa/crypto.h" - #include "unity.h" +#include "sdkconfig.h" +#include "esp_heap_caps.h" +#include "test_utils.h" +#include "ccomp_timer.h" +#include "sys/param.h" +#include "crypto_performance.h" -static const uint8_t key_256[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, -}; +#if CONFIG_MBEDTLS_HARDWARE_AES +/* + Python example code for generating test vectors -TEST_CASE("PSA AES-GCM multipart", "[psa-aes-gcm]") + import os, binascii + from cryptography.hazmat.primitives.ciphers.aead import AESGCM + + def as_c_array(byte_arr): + hex_str = '' + for idx, byte in enumerate(byte_arr): + hex_str += "0x{:02x}, ".format(byte) + bytes_per_line = 8 + if idx % bytes_per_line == bytes_per_line - 1: + hex_str += '\n' + + return hex_str + + key = b'\x44' * 16 + iv = b'\xEE' * 16 + data = b'\xAA' * 3200 + aad = b'\x76' * 16 + + aesgcm = AESGCM(key) + + ct = aesgcm.encrypt(iv, data, aad) + + print(as_c_array(ct)) +*/ + +TEST_CASE("mbedtls GCM stream test", "[aes-gcm]") { - const size_t SZ = 100; - const size_t iv_SZ = 12; // GCM typically uses 12 bytes IV - const size_t tag_SZ = 16; // GCM tag size - const size_t aad_SZ = 16; // Size of Additional Authenticated Data - const size_t part_size = 8; - size_t tag_length = 0; - uint8_t *plaintext = malloc(SZ); - uint8_t *ciphertext = malloc(SZ); - uint8_t *decryptedtext = malloc(SZ); - uint8_t iv[iv_SZ]; - uint8_t tag[tag_SZ]; - uint8_t aad[aad_SZ]; + const unsigned SZ = 100; + psa_key_id_t key_id; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + uint8_t nonce[16]; + uint8_t key[16]; + uint8_t tag[16]; + psa_status_t status; + + const uint8_t expected_cipher[] = { + 0x03, 0x92, 0x13, 0x49, 0x1f, 0x1f, 0x24, 0x41, + 0xe8, 0xeb, 0x89, 0x47, 0x50, 0x0a, 0xce, 0xa3, + 0xc7, 0x1c, 0x10, 0x70, 0xb0, 0x89, 0x82, 0x5e, + 0x0f, 0x4a, 0x23, 0xee, 0xd2, 0xfc, 0xff, 0x45, + 0x61, 0x4c, 0xd1, 0xfb, 0x6d, 0xe2, 0xbe, 0x67, + 0x6f, 0x94, 0x72, 0xa3, 0xe7, 0x04, 0x99, 0xb3, + 0x4a, 0x46, 0xf9, 0x2b, 0xaf, 0xac, 0xa9, 0x0e, + 0x43, 0x7e, 0x8b, 0xc4, 0xbf, 0x49, 0xa4, 0x83, + 0x9c, 0x31, 0x11, 0x1c, 0x09, 0xac, 0x90, 0xdf, + 0x00, 0x34, 0x08, 0xe5, 0x70, 0xa3, 0x7e, 0x4b, + 0x36, 0x48, 0x5a, 0x3f, 0x28, 0xc7, 0x1c, 0xd9, + 0x1b, 0x1b, 0x49, 0x96, 0xe9, 0x7c, 0xea, 0x54, + 0x7c, 0x71, 0x29, 0x0d + }; + const uint8_t expected_tag[] = { + 0x35, 0x1c, 0x21, 0xc6, 0xbc, 0x6b, 0x18, 0x52, + 0x90, 0xe1, 0xf2, 0x5b, 0xe1, 0xf6, 0x15, 0xee, + }; + + + memset(nonce, 0x89, 16); + memset(key, 0x56, 16); + + // allocate internal memory + uint8_t *ciphertext = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + uint8_t *plaintext = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + uint8_t *decryptedtext = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); - TEST_ASSERT_NOT_NULL(plaintext); TEST_ASSERT_NOT_NULL(ciphertext); + TEST_ASSERT_NOT_NULL(plaintext); TEST_ASSERT_NOT_NULL(decryptedtext); - // Initialize test data - memset(plaintext, 0x3A, SZ); - memset(decryptedtext, 0x0, SZ); - memset(iv, 0x3B, iv_SZ); - memset(aad, 0x3C, aad_SZ); + memset(plaintext, 0xAB, SZ); - /* Import a key */ - psa_key_id_t key_id; - psa_algorithm_t alg = PSA_ALG_GCM; - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Set up key attributes psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); - psa_set_key_algorithm(&attributes, alg); + psa_set_key_algorithm(&attributes, PSA_ALG_GCM); psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attributes, sizeof(key_256) * 8); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_import_key(&attributes, key_256, sizeof(key_256), &key_id)); + psa_set_key_bits(&attributes, 128); - psa_reset_key_attributes(&attributes); + // Import key + status = psa_import_key(&attributes, key, 16, &key_id); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - /* Encrypt */ - psa_aead_operation_t enc_op = PSA_AEAD_OPERATION_INIT; - size_t out_len, total_out_len = 0; + /* Test that all the end results are the same + no matter how many bytes we encrypt each call + */ + for (int bytes_to_process = 16; bytes_to_process < SZ; bytes_to_process = bytes_to_process + 16) { + memset(nonce, 0x89, 16); + memset(ciphertext, 0x0, SZ); + memset(decryptedtext, 0x0, SZ); + memset(tag, 0x0, 16); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_encrypt_setup(&enc_op, key_id, alg)); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_set_lengths(&enc_op, aad_SZ, SZ)); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_set_nonce(&enc_op, iv, iv_SZ)); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_update_ad(&enc_op, aad, aad_SZ)); + psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT; - // Process the plaintext in parts - for (size_t offset = 0; offset < SZ; offset += part_size) { - size_t this_part = SZ - offset < part_size ? SZ - offset : part_size; - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_update(&enc_op, plaintext + offset, this_part, - ciphertext + offset, this_part, &out_len)); - total_out_len += out_len; + status = psa_aead_encrypt_setup(&operation, key_id, PSA_ALG_GCM); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_aead_set_nonce(&operation, nonce, sizeof(nonce)); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_aead_update_ad(&operation, NULL, 0); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + size_t output_len; + size_t total_output = 0; + // Encrypt + for (int idx = 0; idx < SZ; idx = idx + bytes_to_process) { + // Limit length of last call to avoid exceeding buffer size + size_t length = (idx + bytes_to_process > SZ) ? (SZ - idx) : bytes_to_process; + status = psa_aead_update(&operation, plaintext + idx, length, ciphertext + total_output, SZ - total_output, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output += output_len; + } + + size_t tag_len; + status = psa_aead_finish(&operation, ciphertext + total_output, SZ - total_output, &output_len, tag, sizeof(tag), &tag_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output += output_len; + + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_cipher, ciphertext, SZ); + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_tag, tag, sizeof(tag)); + + // Decrypt + memset(nonce, 0x89, 16); + + psa_aead_abort(&operation); + + status = psa_aead_decrypt_setup(&operation, key_id, PSA_ALG_GCM); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_aead_set_nonce(&operation, nonce, sizeof(nonce)); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_aead_update_ad(&operation, NULL, 0); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + total_output = 0; + for (int idx = 0; idx < SZ; idx = idx + bytes_to_process) { + // Limit length of last call to avoid exceeding buffer size + size_t length = (idx + bytes_to_process > SZ) ? (SZ - idx) : bytes_to_process; + status = psa_aead_update(&operation, ciphertext + idx, length, decryptedtext + total_output, SZ - total_output, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output += output_len; + } + + status = psa_aead_verify(&operation, decryptedtext + total_output, SZ - total_output, &output_len, tag, sizeof(tag)); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + total_output += output_len; + + TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); } - // Finish encryption and get the tag - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_finish(&enc_op, - ciphertext + total_out_len, - SZ - total_out_len, - &out_len, - tag, - tag_SZ, - &tag_length)); - total_out_len += out_len; - TEST_ASSERT_EQUAL_size_t(SZ, total_out_len); - - /* Decrypt */ - psa_aead_operation_t dec_op = PSA_AEAD_OPERATION_INIT; - total_out_len = 0; - - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_decrypt_setup(&dec_op, key_id, alg)); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_set_lengths(&dec_op, aad_SZ, SZ)); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_set_nonce(&dec_op, iv, iv_SZ)); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_update_ad(&dec_op, aad, aad_SZ)); - - // Process the ciphertext in parts - for (size_t offset = 0; offset < SZ; offset += part_size) { - size_t this_part = SZ - offset < part_size ? SZ - offset : part_size; - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_update(&dec_op, ciphertext + offset, this_part, - decryptedtext + offset, this_part, &out_len)); - total_out_len += out_len; - } - - // Verify the tag and finish decryption - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_verify(&dec_op, - decryptedtext + total_out_len, - SZ - total_out_len, - &out_len, - tag, - tag_SZ)); - total_out_len += out_len; - TEST_ASSERT_EQUAL_size_t(SZ, total_out_len); - - // Verify the decrypted data matches the original plaintext - TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); - - /* Cleanup */ + psa_destroy_key(key_id); free(plaintext); free(ciphertext); free(decryptedtext); - - psa_aead_abort(&enc_op); - psa_aead_abort(&dec_op); - - /* Destroy the key */ - psa_destroy_key(key_id); } -TEST_CASE("PSA AES-GCM one-shot", "[psa-aes-gcm]") +// Note: PSA Crypto API does not provide a direct equivalent to mbedtls_gcm_self_test() +// The self-test functionality is validated through the individual test cases below + +typedef struct { + uint8_t *plaintext; + size_t plaintext_length; + uint32_t output_caps; + uint8_t *add_buf; + size_t add_length; + uint8_t *iv; + size_t iv_length; + uint8_t *key; + size_t key_bits; + size_t tag_len; +} aes_gcm_test_cfg_t; + +typedef struct { + const uint8_t *expected_tag; + const uint8_t *ciphertext_last_block; // Last block of the ciphertext +} aes_gcm_test_expected_res_t; + +static void aes_gcm_test(aes_gcm_test_cfg_t *cfg, aes_gcm_test_expected_res_t *res) { - const size_t SZ = 100; - const size_t iv_SZ = 12; // GCM typically uses 12 bytes IV - const size_t tag_SZ = 16; // GCM tag size - const size_t aad_SZ = 16; // Size of Additional Authenticated Data - - // Allocate memory with proper alignment - uint8_t *plaintext = malloc(SZ); - uint8_t *ciphertext = malloc(SZ + tag_SZ); - uint8_t *decryptedtext = malloc(SZ); - uint8_t *iv = malloc(iv_SZ); - uint8_t *aad = malloc(aad_SZ); - - TEST_ASSERT_NOT_NULL(plaintext); - TEST_ASSERT_NOT_NULL(ciphertext); - TEST_ASSERT_NOT_NULL(decryptedtext); - TEST_ASSERT_NOT_NULL(iv); - TEST_ASSERT_NOT_NULL(aad); - - // Initialize test data - memset(plaintext, 0x3A, SZ); - memset(ciphertext, 0, SZ + tag_SZ); - memset(decryptedtext, 0x0, SZ); - memset(iv, 0x3B, iv_SZ); - memset(aad, 0x3C, aad_SZ); - - /* Import a key */ psa_key_id_t key_id; - psa_algorithm_t alg = PSA_ALG_GCM; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_status_t status; + + uint8_t tag_buf_encrypt[16] = {}; + uint8_t iv_buf[16] = {}; + + uint8_t *ciphertext = heap_caps_malloc(cfg->plaintext_length, cfg->output_caps); + uint8_t *output = heap_caps_malloc(cfg->plaintext_length, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + + if (cfg->plaintext_length != 0) { + TEST_ASSERT_NOT_NULL(ciphertext); + TEST_ASSERT_NOT_NULL(output); + } + + memset(ciphertext, 0, cfg->plaintext_length); + memset(output, 0, cfg->plaintext_length); + memcpy(iv_buf, cfg->iv, cfg->iv_length); + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Determine the GCM algorithm with appropriate tag length + psa_algorithm_t gcm_alg; + if (cfg->tag_len == 16) { + gcm_alg = PSA_ALG_GCM; + } else { + gcm_alg = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, cfg->tag_len); + } + + // Set up key attributes psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); - psa_set_key_algorithm(&attributes, alg); + psa_set_key_algorithm(&attributes, gcm_alg); psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attributes, sizeof(key_256) * 8); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_import_key(&attributes, key_256, sizeof(key_256), &key_id)); - psa_reset_key_attributes(&attributes); + psa_set_key_bits(&attributes, cfg->key_bits); - size_t output_length; + // Import key + status = psa_import_key(&attributes, cfg->key, cfg->key_bits / 8, &key_id); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - /* One-shot encrypt */ - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_encrypt(key_id, alg, - iv, iv_SZ, - aad, aad_SZ, - plaintext, SZ, - ciphertext, SZ + tag_SZ, - &output_length)); + /* Encrypt and tag */ + psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT; - TEST_ASSERT_EQUAL_size_t(SZ + tag_SZ, output_length); + status = psa_aead_encrypt_setup(&operation, key_id, gcm_alg); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - /* One-shot decrypt */ - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_decrypt(key_id, alg, - iv, iv_SZ, - aad, aad_SZ, - ciphertext, SZ + tag_SZ, - decryptedtext, SZ, - &output_length)); + status = psa_aead_set_nonce(&operation, iv_buf, cfg->iv_length); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - TEST_ASSERT_EQUAL_size_t(SZ, output_length); + status = psa_aead_update_ad(&operation, cfg->add_buf, cfg->add_length); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - // Verify the decrypted data matches the original plaintext - TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); + size_t output_len; + status = psa_aead_update(&operation, cfg->plaintext, cfg->plaintext_length, ciphertext, cfg->plaintext_length, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - /* Cleanup */ - free(plaintext); - free(ciphertext); - free(decryptedtext); - free(iv); - free(aad); + size_t tag_len; + status = psa_aead_finish(&operation, ciphertext + output_len, cfg->plaintext_length - output_len, &output_len, tag_buf_encrypt, sizeof(tag_buf_encrypt), &tag_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + TEST_ASSERT_EQUAL(cfg->tag_len, tag_len); + + status = psa_aead_abort(&operation); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + size_t offset = cfg->plaintext_length > 16 ? cfg->plaintext_length - 16 : 0; + /* Sanity check: make sure the last ciphertext block matches what we expect to see. */ + TEST_ASSERT_EQUAL_HEX8_ARRAY(res->ciphertext_last_block, ciphertext + offset, MIN(16, cfg->plaintext_length)); + TEST_ASSERT_EQUAL_HEX8_ARRAY(res->expected_tag, tag_buf_encrypt, cfg->tag_len); + + /* Decrypt and authenticate */ + status = psa_aead_decrypt_setup(&operation, key_id, gcm_alg); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_aead_set_nonce(&operation, iv_buf, cfg->iv_length); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_aead_update_ad(&operation, cfg->add_buf, cfg->add_length); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_aead_update(&operation, ciphertext, cfg->plaintext_length, output, cfg->plaintext_length, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_aead_verify(&operation, output + output_len, cfg->plaintext_length - output_len, &output_len, res->expected_tag, cfg->tag_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + TEST_ASSERT_EQUAL_HEX8_ARRAY(cfg->plaintext, output, cfg->plaintext_length); - /* Destroy the key */ psa_destroy_key(key_id); + free(ciphertext); + free(output); } + +TEST_CASE("mbedtls AES GCM", "[aes-gcm]") +{ + uint8_t iv[16]; + uint8_t key[16]; + uint8_t add[30]; + + memset(iv, 0xB1, sizeof(iv)); + memset(key, 0x27, sizeof(key)); + memset(add, 0x90, sizeof(add)); + + size_t length[] = {10, 16, 500, 5000, 12345}; + + const uint8_t expected_last_block[][16] = { + + { + 0x37, 0x99, 0x4b, 0x16, 0x5f, 0x8d, 0x27, 0xb1, + 0x60, 0x72 + }, + + { + 0x37, 0x99, 0x4b, 0x16, 0x5f, 0x8d, 0x27, 0xb1, + 0x60, 0x72, 0x9a, 0x81, 0x8d, 0x3c, 0x69, 0x66 + }, + + { + 0x9d, 0x7a, 0xac, 0x84, 0xe3, 0x70, 0x43, 0x0f, + 0xa7, 0x83, 0x43, 0xc9, 0x04, 0xf8, 0x7d, 0x48 + }, + + { + 0xee, 0xfd, 0xab, 0x2a, 0x09, 0x44, 0x41, 0x6a, + 0x91, 0xb0, 0x74, 0x24, 0xee, 0x35, 0xb1, 0x39 + }, + + { + 0x51, 0xf7, 0x1f, 0x67, 0x1a, 0x4a, 0x12, 0x37, + 0x60, 0x3b, 0x68, 0x01, 0x20, 0x4f, 0xf3, 0xd9 + }, + }; + + const uint8_t expected_tag[][16] = { + + { + 0x06, 0x4f, 0xb5, 0x91, 0x12, 0x24, 0xb4, 0x24, + 0x0b, 0xc2, 0x85, 0x59, 0x6a, 0x7c, 0x1f, 0xc9 + }, + + { + 0x45, 0xc2, 0xa8, 0xfe, 0xff, 0x49, 0x1f, 0x45, + 0x8e, 0x29, 0x74, 0x41, 0xed, 0x9b, 0x54, 0x28 + }, + + { + 0xe1, 0xf9, 0x40, 0xfa, 0x29, 0x6f, 0x30, 0xae, + 0xb6, 0x9b, 0x33, 0xdb, 0x8a, 0xf9, 0x70, 0xc4 + }, + + { + 0x22, 0xe1, 0x22, 0x34, 0x0c, 0x91, 0x0b, 0xcf, + 0xa3, 0x42, 0xe0, 0x48, 0xe6, 0xfe, 0x2e, 0x28 + }, + + { + 0xfb, 0xfe, 0x5a, 0xed, 0x26, 0x5c, 0x5e, 0x66, + 0x4e, 0xb2, 0x48, 0xce, 0xe9, 0x88, 0x1c, 0xe0 + }, + }; + + aes_gcm_test_cfg_t cfg = { + .output_caps = MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL, + .iv = iv, + .iv_length = sizeof(iv), + .key = key, + .key_bits = 8 * sizeof(key), + .add_buf = add, + .add_length = sizeof(add), + .tag_len = 16 + }; + + aes_gcm_test_expected_res_t res = { + }; + + for (int i = 0; i < sizeof(length) / sizeof(length[0]); i++) { + printf("Test AES-GCM with plaintext length = %d\n", length[i]); + uint8_t *input = heap_caps_malloc(length[i], MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + TEST_ASSERT(input != NULL || length[i] == 0); + memset(input, 0x36, length[i]); + + cfg.plaintext = input; + cfg.plaintext_length = length[i]; + res.expected_tag = expected_tag[i]; + res.ciphertext_last_block = expected_last_block[i], + + aes_gcm_test(&cfg, &res); + + free(input); + } +} + +TEST_CASE("mbedtls AES GCM - Different add messages", "[aes-gcm]") +{ + const unsigned CALL_SZ = 160; + uint8_t iv[16]; + uint8_t key[16]; + uint8_t *input = heap_caps_malloc(CALL_SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + TEST_ASSERT_NOT_NULL(input); + + memset(input, 0x67, CALL_SZ); + memset(iv, 0xA2, sizeof(iv)); + memset(key, 0x48, sizeof(key)); + + const uint8_t expected_last_block[] = { + 0xcd, 0xb9, 0xad, 0x6f, 0xc9, 0x35, 0x21, 0x0d, + 0xc9, 0x5d, 0xea, 0xd9, 0xf7, 0x1d, 0x43, 0xed + }; + + size_t add_len[] = {0, 10, 16, 500, 5000}; + + const uint8_t expected_tag[][16] = { + { + 0xe3, 0x91, 0xad, 0x40, 0x96, 0xb7, 0x8c, 0x53, + 0x4d, 0x15, 0x7d, 0x55, 0x15, 0xdf, 0x10, 0x69 + }, + + { + 0xc2, 0x38, 0x36, 0xe9, 0x12, 0x72, 0x5b, 0x31, + 0x0c, 0xde, 0xb5, 0xc9, 0x8c, 0xa3, 0xcb, 0xe7 + }, + + { + 0x57, 0x10, 0x22, 0x91, 0x65, 0xfa, 0x89, 0xba, + 0x0a, 0x3e, 0xc1, 0x7c, 0x93, 0x6e, 0x35, 0xac + }, + + { + 0x3c, 0x28, 0x03, 0xc2, 0x14, 0x40, 0xec, 0xb6, + 0x25, 0xfb, 0xdd, 0x55, 0xa0, 0xb2, 0x47, 0x7b + }, + + { + 0xfa, 0x66, 0x4a, 0x97, 0x2d, 0x02, 0x32, 0x5b, + 0x92, 0x94, 0xf1, 0x00, 0x1c, 0xfa, 0xe3, 0x07 + } + }; + + aes_gcm_test_cfg_t cfg = { + .plaintext = input, + .plaintext_length = CALL_SZ, + .output_caps = MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL, + .iv = iv, + .iv_length = sizeof(iv), + .key = key, + .key_bits = 8 * sizeof(key), + .tag_len = 16 + }; + + aes_gcm_test_expected_res_t res = { + .ciphertext_last_block = expected_last_block, + }; + + for (int i = 0; i < sizeof(add_len) / sizeof(add_len[0]); i++) { + printf("Test AES-GCM with add length = %d\n", add_len[i]); + uint8_t *add = heap_caps_malloc(add_len[i], MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + TEST_ASSERT(add != NULL || add_len[i] == 0); + memset(add, 0x12, add_len[i]); + + cfg.add_buf = add; + cfg.add_length = add_len[i]; + res.expected_tag = expected_tag[i]; + + aes_gcm_test(&cfg, &res); + + free(add); + } + free(input); +} + +TEST_CASE("mbedtls AES GCM performance, multi-part", "[aes-gcm]") +{ + const unsigned CALL_SZ = 16 * 3200; + psa_key_id_t key_id; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_status_t status; + float elapsed_usec; + unsigned char tag_buf[16]; + uint8_t iv[16]; + uint8_t key[16]; + uint8_t aad[16]; + + memset(iv, 0xEE, 16); + memset(key, 0x44, 16); + memset(aad, 0x76, 16); + + // allocate internal memory + uint8_t *buf = heap_caps_malloc(CALL_SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + TEST_ASSERT_NOT_NULL(buf); + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Set up key attributes + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_GCM); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 128); + + // Import key + status = psa_import_key(&attributes, key, 16, &key_id); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + ccomp_timer_start(); + + memset(buf, 0xAA, CALL_SZ); + + psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT; + + status = psa_aead_encrypt_setup(&operation, key_id, PSA_ALG_GCM); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_aead_set_nonce(&operation, iv, sizeof(iv)); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_aead_update_ad(&operation, aad, sizeof(aad)); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + size_t output_len; + status = psa_aead_update(&operation, buf, CALL_SZ, buf, CALL_SZ, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + size_t tag_len; + status = psa_aead_finish(&operation, buf + output_len, CALL_SZ - output_len, &output_len, tag_buf, 16, &tag_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + elapsed_usec = ccomp_timer_stop(); + + /* Sanity check: make sure the last ciphertext block matches + what we expect to see. + */ + const uint8_t expected_last_block[] = { + 0xd4, 0x25, 0x88, 0xd4, 0x32, 0x52, 0x3d, 0x6f, + 0xae, 0x49, 0x19, 0xb5, 0x95, 0x01, 0xde, 0x7d, + }; + + const uint8_t expected_tag[] = { + 0xf5, 0x10, 0x1f, 0x21, 0x5b, 0x07, 0x0d, 0x3f, + 0xac, 0xc9, 0xd0, 0x42, 0x45, 0xef, 0xc7, 0xfa, + }; + + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_last_block, buf + CALL_SZ - 16, 16); + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_tag, tag_buf, 16); + + psa_destroy_key(key_id); + free(buf); + + // bytes/usec = MB/sec + float mb_sec = CALL_SZ / elapsed_usec; + printf("GCM encryption rate %.3fMB/sec\n", mb_sec); + +#ifdef CONFIG_MBEDTLS_HARDWARE_GCM + // Don't put a hard limit on software AES performance + TEST_PERFORMANCE_CCOMP_GREATER_THAN(AES_GCM_UPDATE_THROUGHPUT_MBSEC, "%.3fMB/sec", mb_sec); +#endif +} + +TEST_CASE("mbedtls AES GCM performance, one-shot", "[aes-gcm]") +{ + const unsigned CALL_SZ = 16 * 3200; + psa_key_id_t key_id; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_status_t status; + float elapsed_usec; + uint8_t iv[16]; + uint8_t key[16]; + uint8_t aad[16]; + + memset(iv, 0xEE, 16); + memset(key, 0x44, 16); + memset(aad, 0x76, 16); + + // allocate internal memory with extra space for tag + uint8_t *buf = heap_caps_malloc(CALL_SZ + 16, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + TEST_ASSERT_NOT_NULL(buf); + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Set up key attributes + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_GCM); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 128); + + // Import key + status = psa_import_key(&attributes, key, 16, &key_id); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + memset(buf, 0xAA, CALL_SZ); + + ccomp_timer_start(); + size_t output_len; + status = psa_aead_encrypt(key_id, PSA_ALG_GCM, iv, sizeof(iv), aad, sizeof(aad), + buf, CALL_SZ, buf, CALL_SZ + 16, &output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + elapsed_usec = ccomp_timer_stop(); + + /* Sanity check: make sure the last ciphertext block matches + what we expect to see. + */ + + const uint8_t expected_last_block[] = { + 0xd4, 0x25, 0x88, 0xd4, 0x32, 0x52, 0x3d, 0x6f, + 0xae, 0x49, 0x19, 0xb5, 0x95, 0x01, 0xde, 0x7d, + }; + + const uint8_t expected_tag[] = { + 0xf5, 0x10, 0x1f, 0x21, 0x5b, 0x07, 0x0d, 0x3f, + 0xac, 0xc9, 0xd0, 0x42, 0x45, 0xef, 0xc7, 0xfa, + }; + + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_last_block, buf + CALL_SZ - 16, 16); + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_tag, buf + CALL_SZ, 16); + + psa_destroy_key(key_id); + free(buf); + + // bytes/usec = MB/sec + float mb_sec = CALL_SZ / elapsed_usec; + printf("GCM encryption rate %.3fMB/sec\n", mb_sec); + +#ifdef CONFIG_MBEDTLS_HARDWARE_GCM + // Don't put a hard limit on software AES performance + TEST_PERFORMANCE_CCOMP_GREATER_THAN(AES_GCM_CRYPT_TAG_THROUGHPUT_MBSEC, "%.3fMB/sec", mb_sec); +#endif +} + +TEST_CASE("mbedtls AES GCM - Combine different IV/Key/Plaintext/AAD lengths", "[aes-gcm]") +{ + #define IV_BYTES_VALUE 0xA2 + #define KEY_BYTES_VALUE 0x48 + #define INPUT_BYTES_VALUE 0x36 + #define ADD_BYTES_VALUE 0x12 + + uint8_t iv[16]; + uint8_t key[32]; + + memset(iv, IV_BYTES_VALUE, sizeof(iv)); + memset(key, KEY_BYTES_VALUE, sizeof(key)); + + /* Key length is: 16 bytes, 32 bytes */ + size_t key_length[] = {16, 32}; + + /* IV length is: 12 bytes (standard), 16 bytes */ + size_t iv_length[] = {12, 16}; + + /* Plaintext length is: a multiple of 16 bytes, a non-multiple of 16 bytes */ + size_t length[] = {160, 321}; + + /* Add len is: 0, a multiple of 16 bytes, a non-multiple of 16 bytes */ + size_t add_len[] = {0, 160, 321}; + + /*indexes: Key - IV - Plaintext */ + const uint8_t expected_last_block[2][2][2][16] = { + { + /* 16 byte key */ + + { + { + 0xa2, 0x1e, 0x23, 0x3c, 0xfc, 0x7c, 0xec, 0x9a, + 0x91, 0xe5, 0xdb, 0x3a, 0xe5, 0x0c, 0x3f, 0xc2, + }, + + { + 0xa8, 0xeb, 0x40, 0x9b, 0x7b, 0x87, 0x07, + 0x68, 0x17, 0x5c, 0xc0, 0xb7, 0xb4, 0xb3, 0x81, + 0xbe, + } + }, + { + { + 0x9c, 0xe8, 0xfc, 0x3e, 0x98, 0x64, 0x70, 0x5c, + 0x98, 0x0c, 0xbb, 0x88, 0xa6, 0x4c, 0x12, 0xbc + }, + + { + 0x8b, 0x66, 0xf5, 0xbc, 0x56, 0x59, 0xae, + 0xf0, 0x9e, 0x5c, 0xdb, 0x6d, 0xfc, 0x1f, 0x2e, + 0x00 + } + }, + }, + { + /* 32 byte key */ + { + { + 0xde, 0xc2, 0xd3, 0xeb, 0x5e, 0x03, 0x53, 0x4b, + 0x04, 0x0d, 0x63, 0xf1, 0xd8, 0x5b, 0x1f, 0x85, + }, + + { + 0xb5, 0x53, 0x8e, 0xd3, 0xab, 0x10, 0xf1, + 0x77, 0x41, 0x92, 0xea, 0xdd, 0xdd, 0x9e, 0x5d, + 0x40, + } + }, + { + { + 0x3b, 0xc7, 0xf0, 0x3f, 0xba, 0x97, 0xbd, 0xa0, + 0xa5, 0x48, 0xf3, 0x7a, 0xde, 0x23, 0x19, 0x7a, + }, + + { + 0x57, 0xc7, 0x4d, 0xe3, 0x79, 0x5e, 0xbd, + 0x0d, 0xd7, 0x6a, 0xef, 0x1f, 0x54, 0x29, 0xa6, + 0xd7, + } + }, + }, + }; + + /*indexes: Key - IV - Plaintext - Add len*/ + const uint8_t expected_tag[2][2][2][3][16] = { + { + { + { + // Plaintext 160 bytes + { + 0x67, 0x92, 0xb1, 0x7f, 0x44, 0x1f, 0x95, 0xfb, + 0x33, 0x76, 0x66, 0xb7, 0x4f, 0x3e, 0xec, 0x4d, + }, + + { + 0xb1, 0x99, 0xed, 0x1b, 0x4e, 0x12, 0x87, 0x5e, + 0xf4, 0xe3, 0x81, 0xd8, 0x96, 0x07, 0xda, 0xff, + }, + + { + 0x73, 0x35, 0x0c, 0xf5, 0x70, 0x1e, 0xc0, 0x99, + 0x34, 0xba, 0x1a, 0x50, 0x23, 0xac, 0x21, 0x33, + }, + }, + { + // Plaintext 321 bytes + { + 0x2d, 0xf6, 0xd0, 0x7a, 0x75, 0x4d, 0x9d, + 0xb5, 0x9d, 0x43, 0xbf, 0x57, 0x10, 0xa3, 0xff, + 0x3d + }, + + { + 0x06, 0x91, 0xe4, 0x38, 0x3a, 0xe1, 0x6e, + 0x2d, 0x83, 0x68, 0x2e, 0xb0, 0x26, 0x2f, 0xe4, + 0x78 + }, + + { + 0x1b, 0x58, 0x2f, 0x9b, 0xe9, 0xe0, 0xe0, + 0x43, 0x83, 0x08, 0xec, 0x58, 0x3a, 0x78, 0xe9, + 0x69, + } + } + }, + { + { + // Plaintext 160 bytes + { + 0x77, 0xe5, 0x2e, 0x2d, 0x94, 0xb8, 0x03, 0x61, + 0x7a, 0xd5, 0x0c, 0x3c, 0x9c, 0x40, 0x92, 0x9b + }, + + { + 0xa1, 0xee, 0x72, 0x49, 0x9e, 0xb5, 0x11, 0xc4, + 0xbd, 0x40, 0xeb, 0x53, 0x45, 0x79, 0xa4, 0x29 + }, + + { + 0x63, 0x42, 0x93, 0xa7, 0xa0, 0xb9, 0x56, 0x03, + 0x7d, 0x19, 0x70, 0xdb, 0xf0, 0xd2, 0x5f, 0xe5 + }, + }, + { + // Plaintext 321 bytes + { + 0x50, 0xa3, 0x79, 0xfc, 0x17, 0xb8, 0xf4, + 0xf6, 0x14, 0xaa, 0x4a, 0xe7, 0xd4, 0xa0, 0xea, + 0xee + }, + + { + 0x7b, 0xc4, 0x4d, 0xbe, 0x58, 0x14, 0x07, + 0x6e, 0x0a, 0x81, 0xdb, 0x00, 0xe2, 0x2c, 0xf1, + 0xab + }, + + { + 0x66, 0x0d, 0x86, 0x1d, 0x8b, 0x15, 0x89, + 0x00, 0x0a, 0xe1, 0x19, 0xe8, 0xfe, 0x7b, 0xfc, + 0xba + } + } + }, + }, + { + { + { + // Plaintext 160 bytes + { + 0x04, 0x04, 0x15, 0xb1, 0xd3, 0x98, 0x15, 0x45, + 0xa2, 0x44, 0xba, 0x4a, 0xde, 0xc2, 0x8d, 0xd6, + }, + + { + 0x94, 0x3e, 0xc3, 0x5d, 0xdc, 0x42, 0xf6, 0x4c, + 0x80, 0x15, 0xe4, 0xb9, 0x0b, 0xc9, 0x87, 0x01, + }, + + { + 0x93, 0x6e, 0x26, 0x5b, 0x7e, 0x17, 0xc8, 0x73, + 0x9b, 0x71, 0x31, 0x7a, 0x8b, 0x0e, 0x19, 0x89, + } + }, + { + // Plaintext 321 bytes + { + 0x99, 0x5e, 0x77, 0x28, 0x8b, 0xa8, 0x9b, + 0xb3, 0x35, 0xc3, 0x99, 0x90, 0xd4, 0x5d, 0x63, + 0xa7, + }, + + { + 0xbc, 0xc2, 0x9f, 0xe6, 0x38, 0xef, 0xf5, + 0x11, 0x76, 0x09, 0x17, 0x3a, 0xd4, 0x91, 0xee, + 0xfe, + }, + + { + 0x9f, 0xa6, 0x23, 0x5a, 0x4d, 0x78, 0xae, + 0xce, 0x10, 0x35, 0xc1, 0x0c, 0x6e, 0xc2, 0x4e, + 0xe8, + } + } + }, + { + { + // Plaintext 160 bytes + { + 0xfb, 0x74, 0x7e, 0x21, 0xf2, 0xe7, 0xe3, 0xf5, + 0xfa, 0xc8, 0x23, 0xab, 0x54, 0x9a, 0xb9, 0xcf, + }, + + { + 0x6b, 0x4e, 0xa8, 0xcd, 0xfd, 0x3d, 0x00, 0xfc, + 0xd8, 0x99, 0x7d, 0x58, 0x81, 0x91, 0xb3, 0x18, + }, + + { + 0x6c, 0x1e, 0x4d, 0xcb, 0x5f, 0x68, 0x3e, 0xc3, + 0xc3, 0xfd, 0xa8, 0x9b, 0x01, 0x56, 0x2d, 0x90, + }, + }, + { + // Plaintext 321 bytes + { + 0xcd, 0x49, 0x75, 0x4c, 0x2a, 0x62, 0x65, + 0x6f, 0xfe, 0x14, 0xc2, 0x5d, 0x41, 0x07, 0x24, + 0x55 + }, + + { + 0xe8, 0xd5, 0x9d, 0x82, 0x99, 0x25, 0x0b, + 0xcd, 0xbd, 0xde, 0x4c, 0xf7, 0x41, 0xcb, 0xa9, + 0x0c, + }, + + { + 0xcb, 0xb1, 0x21, 0x3e, 0xec, 0xb2, 0x50, + 0x12, 0xdb, 0xe2, 0x9a, 0xc1, 0xfb, 0x98, 0x09, + 0x1a, + } + } + }, + }, + }; + + aes_gcm_test_cfg_t cfg = { + .output_caps = MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL, + .tag_len = 16 + }; + + + for (int i_key = 0; i_key < sizeof(key_length) / sizeof(key_length[0]); i_key++) { + printf("Test AES-GCM with key length = %d\n", key_length[i_key]); + + cfg.key = key; + cfg.key_bits = 8 * key_length[i_key]; + + for (int i_iv = 0; i_iv < sizeof(iv_length) / sizeof(iv_length[0]); i_iv++) { + printf("Test AES-GCM with IV length = %d\n", iv_length[i_iv]); + + cfg.iv = iv; + cfg.iv_length = iv_length[i_iv]; + + for (int i_len = 0; i_len < sizeof(length) / sizeof(length[0]); i_len++) { + printf("Test AES-GCM with plaintext length = %d\n", length[i_len]); + uint8_t *input = heap_caps_malloc(length[i_len], MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + TEST_ASSERT(input != NULL || length[i_len] == 0); + memset(input, INPUT_BYTES_VALUE, length[i_len]); + cfg.plaintext = input; + cfg.plaintext_length = length[i_len]; + + aes_gcm_test_expected_res_t res = {0}; + + for (int i_add = 0; i_add < sizeof(add_len) / sizeof(add_len[0]); i_add++) { + + printf("Test AES-GCM with add length = %d\n", add_len[i_add]); + uint8_t *add = heap_caps_malloc(add_len[i_add], MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + TEST_ASSERT(add != NULL || add_len[i_add] == 0); + memset(add, ADD_BYTES_VALUE, add_len[i_add]); + + cfg.add_buf = add; + cfg.add_length = add_len[i_add]; + + res.expected_tag = expected_tag[i_key][i_iv][i_len][i_add]; + res.ciphertext_last_block = expected_last_block[i_key][i_iv][i_len], + + aes_gcm_test(&cfg, &res); + + free(add); + } + free(input); + } + } + } +} + +/* Note: This test validates different GCM authentication tag lengths. + * The PSA standard allows tag lengths of 4, 8, 12-16 bytes for GCM. + */ +TEST_CASE("mbedtls AES GCM - Different Authentication Tag lengths", "[aes-gcm]") +{ + const unsigned CALL_SZ = 160; + uint8_t iv[16]; + uint8_t key[16]; + uint8_t aad[16]; + uint8_t *input = heap_caps_malloc(CALL_SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + TEST_ASSERT_NOT_NULL(input); + + memset(input, 0x67, CALL_SZ); + memset(iv, 0xA2, sizeof(iv)); + memset(key, 0x48, sizeof(key)); + memset(aad, 0x12, sizeof(aad)); + + size_t tag_len[] = {4, 8, 12, 16}; + + const uint8_t expected_last_block[] = { + 0xcd, 0xb9, 0xad, 0x6f, 0xc9, 0x35, 0x21, 0x0d, + 0xc9, 0x5d, 0xea, 0xd9, 0xf7, 0x1d, 0x43, 0xed + }; + + const uint8_t expected_tag[16] = { + 0x57, 0x10, 0x22, 0x91, 0x65, 0xfa, 0x89, 0xba, + 0x0a, 0x3e, 0xc1, 0x7c, 0x93, 0x6e, 0x35, 0xac + }; + + aes_gcm_test_cfg_t cfg = { + .plaintext = input, + .plaintext_length = CALL_SZ, + .output_caps = MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL, + .add_buf = aad, + .add_length = sizeof(aad), + .iv = iv, + .iv_length = sizeof(iv), + .key = key, + .key_bits = 8 * sizeof(key), + }; + + aes_gcm_test_expected_res_t res = { + .expected_tag = expected_tag, + .ciphertext_last_block = expected_last_block, + }; + + for (int i = 0; i < sizeof(tag_len) / sizeof(tag_len[0]); i++) { + printf("Test AES-GCM with tag length = %d\n", tag_len[i]); + cfg.tag_len = tag_len[i]; + aes_gcm_test(&cfg, &res); + } + free(input); +} + +#endif //CONFIG_MBEDTLS_HARDWARE_AES diff --git a/components/mbedtls/test_apps/main/test_aes_perf.c b/components/mbedtls/test_apps/main/test_psa_aes_perf.c similarity index 100% rename from components/mbedtls/test_apps/main/test_aes_perf.c rename to components/mbedtls/test_apps/main/test_psa_aes_perf.c diff --git a/components/mbedtls/test_apps/main/test_aes_sha_parallel.c b/components/mbedtls/test_apps/main/test_psa_aes_sha_parallel.c similarity index 100% rename from components/mbedtls/test_apps/main/test_aes_sha_parallel.c rename to components/mbedtls/test_apps/main/test_psa_aes_sha_parallel.c diff --git a/components/mbedtls/test_apps/main/test_aes_sha_rsa.c b/components/mbedtls/test_apps/main/test_psa_aes_sha_rsa.c similarity index 100% rename from components/mbedtls/test_apps/main/test_aes_sha_rsa.c rename to components/mbedtls/test_apps/main/test_psa_aes_sha_rsa.c diff --git a/components/mbedtls/test_apps/main/test_psa_sha.c b/components/mbedtls/test_apps/main/test_psa_sha.c new file mode 100644 index 0000000000..0b4d836da2 --- /dev/null +++ b/components/mbedtls/test_apps/main/test_psa_sha.c @@ -0,0 +1,776 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "psa/crypto.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "unity.h" +#include "sdkconfig.h" +#include "test_apb_dport_access.h" +#include "soc/soc_caps.h" +#include "test_utils.h" +#include "esp_memory_utils.h" + +#if CONFIG_MBEDTLS_HARDWARE_SHA +static const unsigned char *one_hundred_as = (unsigned char *) + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + +static const unsigned char *one_hundred_bs = (unsigned char *) + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; + +static const uint8_t sha256_thousand_as[32] = { + 0x41, 0xed, 0xec, 0xe4, 0x2d, 0x63, 0xe8, 0xd9, 0xbf, 0x51, 0x5a, 0x9b, 0xa6, 0x93, 0x2e, 0x1c, + 0x20, 0xcb, 0xc9, 0xf5, 0xa5, 0xd1, 0x34, 0x64, 0x5a, 0xdb, 0x5d, 0xb1, 0xb9, 0x73, 0x7e, 0xa3 +}; + + +static const uint8_t sha256_thousand_bs[32] = { + 0xf6, 0xf1, 0x18, 0xe1, 0x20, 0xe5, 0x2b, 0xe0, 0xbd, 0x0c, 0xfd, 0xf2, 0x79, 0x4c, 0xd1, 0x2c, 0x07, 0x68, 0x6c, 0xc8, 0x71, 0x23, 0x5a, 0xc2, 0xf1, 0x14, 0x59, 0x37, 0x8e, 0x6d, 0x23, 0x5b +}; + +static const uint8_t sha512_thousand_bs[64] = { + 0xa6, 0x68, 0x68, 0xa3, 0x73, 0x53, 0x2a, 0x5c, 0xc3, 0x3f, 0xbf, 0x43, 0x4e, 0xba, 0x10, 0x86, 0xb3, 0x87, 0x09, 0xe9, 0x14, 0x3f, 0xbf, 0x37, 0x67, 0x8d, 0x43, 0xd9, 0x9b, 0x95, 0x08, 0xd5, 0x80, 0x2d, 0xbe, 0x9d, 0xe9, 0x1a, 0x54, 0xab, 0x9e, 0xbc, 0x8a, 0x08, 0xa0, 0x1a, 0x89, 0xd8, 0x72, 0x68, 0xdf, 0x52, 0x69, 0x7f, 0x1c, 0x70, 0xda, 0xe8, 0x3f, 0xe5, 0xae, 0x5a, 0xfc, 0x9d +}; + +static const uint8_t sha384_thousand_bs[48] = { + 0x6d, 0xe5, 0xf5, 0x88, 0x57, 0x60, 0x83, 0xff, 0x7c, 0x94, 0x61, 0x5f, 0x8d, 0x96, 0xf2, 0x76, 0xd5, 0x3f, 0x77, 0x0c, 0x8e, 0xc1, 0xbf, 0xb6, 0x04, 0x27, 0xa4, 0xba, 0xea, 0x6c, 0x68, 0x44, 0xbd, 0xb0, 0x9c, 0xef, 0x6a, 0x09, 0x28, 0xe8, 0x1f, 0xfc, 0x95, 0x03, 0x69, 0x99, 0xab, 0x1a +}; + +static const uint8_t sha1_thousand_as[20] = { + 0x29, 0x1e, 0x9a, 0x6c, 0x66, 0x99, 0x49, 0x49, 0xb5, 0x7b, 0xa5, + 0xe6, 0x50, 0x36, 0x1e, 0x98, 0xfc, 0x36, 0xb1, 0xba +}; + +TEST_CASE("mbedtls SHA interleaving", "[mbedtls]") +{ + psa_hash_operation_t sha1_op = PSA_HASH_OPERATION_INIT; + psa_hash_operation_t sha256_op = PSA_HASH_OPERATION_INIT; + psa_hash_operation_t sha512_op = PSA_HASH_OPERATION_INIT; + unsigned char sha1[20], sha256[32], sha512[64]; + psa_status_t status; + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_hash_setup(&sha1_op, PSA_ALG_SHA_1); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_hash_setup(&sha256_op, PSA_ALG_SHA_256); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_hash_setup(&sha512_op, PSA_ALG_SHA_512); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + for (int i = 0; i < 10; i++) { + status = psa_hash_update(&sha1_op, one_hundred_as, 100); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_hash_update(&sha256_op, one_hundred_as, 100); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_hash_update(&sha512_op, one_hundred_bs, 100); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + } + + size_t hash_len; + status = psa_hash_finish(&sha1_op, sha1, sizeof(sha1), &hash_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_hash_finish(&sha256_op, sha256, sizeof(sha256), &hash_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_hash_finish(&sha512_op, sha512, sizeof(sha512), &hash_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha512_thousand_bs, sha512, 64, "SHA512 calculation"); + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha256_thousand_as, sha256, 32, "SHA256 calculation"); + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha1_thousand_as, sha1, 20, "SHA1 calculation"); +} + +#define SHA_TASK_STACK_SIZE (10*1024) +static SemaphoreHandle_t done_sem; + +static void tskRunSHA1Test(void *pvParameters) +{ + psa_hash_operation_t sha1_op; + unsigned char sha1[20]; + psa_status_t status; + size_t hash_len; + + for (int i = 0; i < 1000; i++) { + sha1_op = (psa_hash_operation_t)PSA_HASH_OPERATION_INIT; + + status = psa_hash_setup(&sha1_op, PSA_ALG_SHA_1); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + for (int j = 0; j < 10; j++) { + status = psa_hash_update(&sha1_op, (unsigned char *)one_hundred_as, 100); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + } + + status = psa_hash_finish(&sha1_op, sha1, sizeof(sha1), &hash_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha1_thousand_as, sha1, 20, "SHA1 calculation"); + } + xSemaphoreGive(done_sem); + vTaskDelete(NULL); +} + +static void tskRunSHA256Test(void *pvParameters) +{ + psa_hash_operation_t sha256_op; + unsigned char sha256[32]; + psa_status_t status; + size_t hash_len; + + for (int i = 0; i < 1000; i++) { + sha256_op = (psa_hash_operation_t)PSA_HASH_OPERATION_INIT; + + status = psa_hash_setup(&sha256_op, PSA_ALG_SHA_256); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + for (int j = 0; j < 10; j++) { + status = psa_hash_update(&sha256_op, (unsigned char *)one_hundred_bs, 100); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + } + + status = psa_hash_finish(&sha256_op, sha256, sizeof(sha256), &hash_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha256_thousand_bs, sha256, 32, "SHA256 calculation"); + } + xSemaphoreGive(done_sem); + vTaskDelete(NULL); +} + + +TEST_CASE("mbedtls SHA multithreading", "[mbedtls]") +{ + done_sem = xSemaphoreCreateCounting(4, 0); + xTaskCreate(tskRunSHA1Test, "SHA1Task1", SHA_TASK_STACK_SIZE, NULL, 3, NULL); + xTaskCreate(tskRunSHA1Test, "SHA1Task2", SHA_TASK_STACK_SIZE, NULL, 3, NULL); + xTaskCreate(tskRunSHA256Test, "SHA256Task1", SHA_TASK_STACK_SIZE, NULL, 3, NULL); + xTaskCreate(tskRunSHA256Test, "SHA256Task2", SHA_TASK_STACK_SIZE, NULL, 3, NULL); + + for (int i = 0; i < 4; i++) { + if (!xSemaphoreTake(done_sem, 10000 / portTICK_PERIOD_MS)) { + TEST_FAIL_MESSAGE("done_sem not released by test task"); + } + } + vSemaphoreDelete(done_sem); +} + +void tskRunSHASelftests(void *param) +{ + // PSA Crypto API does not provide self-test functions + // Instead, we run basic validation tests for each algorithm + psa_hash_operation_t op; + unsigned char hash[64]; + size_t hash_len; + psa_status_t status; + + for (int i = 0; i < 5; i++) { +#if CONFIG_MBEDTLS_SHA1_C + // SHA1 validation + op = (psa_hash_operation_t)PSA_HASH_OPERATION_INIT; + status = psa_hash_setup(&op, PSA_ALG_SHA_1); + if (status != PSA_SUCCESS) { + printf("SHA1 setup failed.\n"); + while (1) {} + } + status = psa_hash_update(&op, one_hundred_as, 100); + if (status != PSA_SUCCESS) { + printf("SHA1 update failed.\n"); + while (1) {} + } + status = psa_hash_finish(&op, hash, sizeof(hash), &hash_len); + if (status != PSA_SUCCESS) { + printf("SHA1 finish failed.\n"); + while (1) {} + } +#endif + + // SHA256 validation + op = (psa_hash_operation_t)PSA_HASH_OPERATION_INIT; + status = psa_hash_setup(&op, PSA_ALG_SHA_256); + if (status != PSA_SUCCESS) { + printf("SHA256 setup failed.\n"); + while (1) {} + } + status = psa_hash_update(&op, one_hundred_bs, 100); + if (status != PSA_SUCCESS) { + printf("SHA256 update failed.\n"); + while (1) {} + } + status = psa_hash_finish(&op, hash, sizeof(hash), &hash_len); + if (status != PSA_SUCCESS) { + printf("SHA256 finish failed.\n"); + while (1) {} + } + +#if SOC_SHA_SUPPORT_SHA512 && CONFIG_MBEDTLS_SHA512_C + // SHA512 validation + op = (psa_hash_operation_t)PSA_HASH_OPERATION_INIT; + status = psa_hash_setup(&op, PSA_ALG_SHA_512); + if (status != PSA_SUCCESS) { + printf("SHA512 setup failed.\n"); + while (1) {} + } + status = psa_hash_update(&op, one_hundred_bs, 100); + if (status != PSA_SUCCESS) { + printf("SHA512 update failed.\n"); + while (1) {} + } + status = psa_hash_finish(&op, hash, sizeof(hash), &hash_len); + if (status != PSA_SUCCESS) { + printf("SHA512 finish failed.\n"); + while (1) {} + } +#endif //SOC_SHA_SUPPORT_SHA512 && CONFIG_MBEDTLS_SHA512_C + } + xSemaphoreGive(done_sem); + vTaskDelete(NULL); +} + +TEST_CASE("mbedtls SHA self-tests multithreaded", "[mbedtls]") +{ + done_sem = xSemaphoreCreateCounting(2, 0); + xTaskCreate(tskRunSHASelftests, "SHASelftests1", SHA_TASK_STACK_SIZE, NULL, 3, NULL); + xTaskCreate(tskRunSHASelftests, "SHASelftests2", SHA_TASK_STACK_SIZE, NULL, 3, NULL); + + const int TIMEOUT_MS = 40000; + + for (int i = 0; i < 2; i++) { + if (!xSemaphoreTake(done_sem, TIMEOUT_MS / portTICK_PERIOD_MS)) { + TEST_FAIL_MESSAGE("done_sem not released by test task"); + } + } + vSemaphoreDelete(done_sem); +} + +TEST_CASE("mbedtls SHA512 clone", "[mbedtls]") +{ + psa_hash_operation_t op = PSA_HASH_OPERATION_INIT; + psa_hash_operation_t clone = PSA_HASH_OPERATION_INIT; + unsigned char sha512[64]; + psa_status_t status; + size_t hash_len; + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_hash_setup(&op, PSA_ALG_SHA_512); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + for (int i = 0; i < 5; i++) { + status = psa_hash_update(&op, one_hundred_bs, 100); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + } + + status = psa_hash_clone(&op, &clone); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + for (int i = 0; i < 5; i++) { + status = psa_hash_update(&op, one_hundred_bs, 100); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_hash_update(&clone, one_hundred_bs, 100); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + } + + status = psa_hash_finish(&op, sha512, sizeof(sha512), &hash_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha512_thousand_bs, sha512, 64, "SHA512 original calculation"); + + status = psa_hash_finish(&clone, sha512, sizeof(sha512), &hash_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha512_thousand_bs, sha512, 64, "SHA512 cloned calculation"); +} + +TEST_CASE("mbedtls SHA384 clone", "[mbedtls]") +{ + psa_hash_operation_t op = PSA_HASH_OPERATION_INIT; + psa_hash_operation_t clone = PSA_HASH_OPERATION_INIT; + unsigned char sha384[48]; + psa_status_t status; + size_t hash_len; + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_hash_setup(&op, PSA_ALG_SHA_384); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + for (int i = 0; i < 5; i++) { + status = psa_hash_update(&op, one_hundred_bs, 100); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + } + + status = psa_hash_clone(&op, &clone); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + for (int i = 0; i < 5; i++) { + status = psa_hash_update(&op, one_hundred_bs, 100); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_hash_update(&clone, one_hundred_bs, 100); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + } + + status = psa_hash_finish(&op, sha384, sizeof(sha384), &hash_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha384_thousand_bs, sha384, 48, "SHA512 original calculation"); + + status = psa_hash_finish(&clone, sha384, sizeof(sha384), &hash_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha384_thousand_bs, sha384, 48, "SHA512 cloned calculation"); +} + + +TEST_CASE("mbedtls SHA256 clone", "[mbedtls]") +{ + psa_hash_operation_t op = PSA_HASH_OPERATION_INIT; + psa_hash_operation_t clone = PSA_HASH_OPERATION_INIT; + unsigned char sha256[64]; + psa_status_t status; + size_t hash_len; + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_hash_setup(&op, PSA_ALG_SHA_256); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + for (int i = 0; i < 5; i++) { + status = psa_hash_update(&op, one_hundred_as, 100); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + } + + status = psa_hash_clone(&op, &clone); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + for (int i = 0; i < 5; i++) { + status = psa_hash_update(&op, one_hundred_as, 100); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_hash_update(&clone, one_hundred_as, 100); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + } + + status = psa_hash_finish(&op, sha256, sizeof(sha256), &hash_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha256_thousand_as, sha256, 32, "SHA256 original calculation"); + + status = psa_hash_finish(&clone, sha256, sizeof(sha256), &hash_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha256_thousand_as, sha256, 32, "SHA256 cloned calculation"); +} + +typedef struct { + psa_hash_operation_t op; + uint8_t result[32]; + psa_status_t ret; + bool done; +} finalise_sha_param_t; + +static void tskFinaliseSha(void *v_param) +{ + finalise_sha_param_t *param = (finalise_sha_param_t *)v_param; + psa_status_t status; + + for (int i = 0; i < 5; i++) { + status = psa_hash_update(¶m->op, one_hundred_as, 100); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + } + + size_t hash_len; + param->ret = psa_hash_finish(¶m->op, param->result, sizeof(param->result), &hash_len); + + param->done = true; + vTaskDelete(NULL); +} + + +TEST_CASE("mbedtls SHA session passed between tasks", "[mbedtls]") +{ + finalise_sha_param_t param = { 0 }; + psa_status_t status; + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + param.op = (psa_hash_operation_t)PSA_HASH_OPERATION_INIT; + status = psa_hash_setup(¶m.op, PSA_ALG_SHA_256); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + for (int i = 0; i < 5; i++) { + status = psa_hash_update(¶m.op, one_hundred_as, 100); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + } + + // pass the SHA context off to a different task + // + // note: at the moment this doesn't crash even if a mutex semaphore is used as the + // engine lock, but it can crash... + xTaskCreate(tskFinaliseSha, "SHAFinalise", SHA_TASK_STACK_SIZE, ¶m, 3, NULL); + + while (!param.done) { + vTaskDelay(1); + } + + TEST_ASSERT_EQUAL(PSA_SUCCESS, param.ret); + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha256_thousand_as, param.result, 32, "SHA256 result from other task"); +} + + + +/* Random input generated and hashed using python: + + import hashlib + import os, binascii + + input = bytearray(os.urandom(150)) + arr = '' + for idx, b in enumerate(input): + if idx % 8 == 0: + arr += '\n' + arr += "{}, ".format(hex(b)) + digest = hashlib.sha256(input).hexdigest() + +*/ +const uint8_t test_vector[] = { + 0xe4, 0x1a, 0x1a, 0x30, 0x71, 0xd3, 0x94, 0xb0, + 0xc3, 0x7e, 0x99, 0x9f, 0x1a, 0xde, 0x4a, 0x36, + 0xb1, 0x1, 0x81, 0x2b, 0x41, 0x91, 0x11, 0x7f, + 0xd8, 0xe1, 0xd5, 0xe5, 0x52, 0x6d, 0x92, 0xee, + 0x6c, 0xf7, 0x70, 0xea, 0x3a, 0xb, 0xc9, 0x97, + 0xc0, 0x12, 0x6f, 0x10, 0x5b, 0x90, 0xd8, 0x52, + 0x91, 0x69, 0xea, 0xc4, 0x1f, 0xc, 0xcf, 0xc6, + 0xf0, 0x43, 0xc6, 0xa3, 0x1f, 0x46, 0x3c, 0x3d, + 0x25, 0xe5, 0xa8, 0x27, 0x86, 0x85, 0x32, 0x3f, + 0x33, 0xd8, 0x40, 0xc4, 0x41, 0xf6, 0x4b, 0x12, + 0xd8, 0x5e, 0x4, 0x27, 0x42, 0x90, 0x73, 0x4, + 0x8, 0x42, 0xd1, 0x64, 0xd, 0x84, 0x3, 0x1, + 0x76, 0x88, 0xe4, 0x95, 0xdf, 0xe7, 0x62, 0xb4, + 0xb3, 0xb2, 0x7e, 0x6d, 0x78, 0xca, 0x79, 0x82, + 0xcc, 0xba, 0x22, 0xd2, 0x90, 0x2e, 0xe3, 0xa8, + 0x2a, 0x53, 0x3a, 0xb1, 0x9a, 0x7f, 0xb7, 0x8b, + 0xfa, 0x32, 0x47, 0xc1, 0x5c, 0x6, 0x4f, 0x7b, + 0xcd, 0xb3, 0xf4, 0xf1, 0xd0, 0xb5, 0xbf, 0xfb, + 0x7c, 0xc3, 0xa5, 0xb2, 0xc4, 0xd4, +}; + +const uint8_t test_vector_digest[] = { + 0xff, 0x1c, 0x60, 0xcb, 0x21, 0xf0, 0x63, 0x68, + 0xb9, 0xfc, 0xfe, 0xad, 0x3e, 0xb0, 0x2e, 0xd1, + 0xf9, 0x08, 0x82, 0x82, 0x83, 0x06, 0xc1, 0x8a, + 0x98, 0x5d, 0x36, 0xc0, 0xb7, 0xeb, 0x35, 0xe0, +}; + + +TEST_CASE("mbedtls SHA, input in flash", "[mbedtls]") +{ + psa_hash_operation_t sha256_op = PSA_HASH_OPERATION_INIT; + unsigned char sha256[32]; + psa_status_t status; + size_t hash_len; + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_hash_setup(&sha256_op, PSA_ALG_SHA_256); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_hash_update(&sha256_op, test_vector, sizeof(test_vector)); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_hash_finish(&sha256_op, sha256, sizeof(sha256), &hash_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(test_vector_digest, sha256, 32, "SHA256 calculation"); +} + +#if 0 // PSA Crypto API does not support SHA512/t variants (SHA512/224, SHA512/256) +/* Note: SHA512/t variants (SHA512/224, SHA512/256) use ESP-specific mbedTLS extensions + * (esp_sha512_set_mode, esp_sha512_set_t) which don't have direct PSA Crypto API equivalents. + * PSA Crypto defines PSA_ALG_SHA_512_224 and PSA_ALG_SHA_512_256 for these algorithms. + */ +#if CONFIG_MBEDTLS_HARDWARE_SHA && SOC_SHA_SUPPORT_SHA512_T + +/* + * FIPS-180-2 test vectors + */ +static unsigned char sha512T_test_buf[2][113] = { + { "abc" }, + { + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" + } +}; + +static const size_t sha512T_test_buflen[2] = { + 3, 112 +}; + +static const psa_algorithm_t sha512T_algo[4] = { + PSA_ALG_SHA_512_224, PSA_ALG_SHA_512_256, PSA_ALG_SHA_512_224, PSA_ALG_SHA_512_256 +}; + +static const size_t sha512T_t_len[4] = { 224, 256, 224, 256 }; + +static const unsigned char sha512_test_sum[4][32] = { + /* SHA512-224 */ + { + 0x46, 0x34, 0x27, 0x0f, 0x70, 0x7b, 0x6a, 0x54, + 0xda, 0xae, 0x75, 0x30, 0x46, 0x08, 0x42, 0xe2, + 0x0e, 0x37, 0xed, 0x26, 0x5c, 0xee, 0xe9, 0xa4, + 0x3e, 0x89, 0x24, 0xaa + }, + { + 0x23, 0xfe, 0xc5, 0xbb, 0x94, 0xd6, 0x0b, 0x23, + 0x30, 0x81, 0x92, 0x64, 0x0b, 0x0c, 0x45, 0x33, + 0x35, 0xd6, 0x64, 0x73, 0x4f, 0xe4, 0x0e, 0x72, + 0x68, 0x67, 0x4a, 0xf9 + }, + + /* SHA512-256 */ + { + 0x53, 0x04, 0x8e, 0x26, 0x81, 0x94, 0x1e, 0xf9, + 0x9b, 0x2e, 0x29, 0xb7, 0x6b, 0x4c, 0x7d, 0xab, + 0xe4, 0xc2, 0xd0, 0xc6, 0x34, 0xfc, 0x6d, 0x46, + 0xe0, 0xe2, 0xf1, 0x31, 0x07, 0xe7, 0xaf, 0x23 + }, + { + 0x39, 0x28, 0xe1, 0x84, 0xfb, 0x86, 0x90, 0xf8, + 0x40, 0xda, 0x39, 0x88, 0x12, 0x1d, 0x31, 0xbe, + 0x65, 0xcb, 0x9d, 0x3e, 0xf8, 0x3e, 0xe6, 0x14, + 0x6f, 0xea, 0xc8, 0x61, 0xe1, 0x9b, 0x56, 0x3a + } + + /* For SHA512_T testing we use t=224 & t=256 + * so the hash digest should be same as above + */ +}; + +/* This will run total of 4 test cases (PSA doesn't need separate tests for SHA512/t vs SHA512/224,256) + * SHA512/224, SHA512/256 with PSA Crypto API + */ +TEST_CASE("mbedtls SHA512/t", "[mbedtls]") +{ + psa_hash_operation_t sha512_op; + unsigned char sha512[64]; + psa_status_t status; + size_t hash_len; + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + // Test SHA512/224 and SHA512/256 + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + int k = i * 2 + j; + sha512_op = (psa_hash_operation_t)PSA_HASH_OPERATION_INIT; + + status = psa_hash_setup(&sha512_op, sha512T_algo[i]); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_hash_update(&sha512_op, sha512T_test_buf[j], sha512T_test_buflen[j]); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_hash_finish(&sha512_op, sha512, sizeof(sha512), &hash_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha512_test_sum[k], sha512, sha512T_t_len[i] / 8, "SHA512t calculation"); + } + } +} +#endif //CONFIG_MBEDTLS_HARDWARE_SHA +#endif + +#ifdef CONFIG_SPIRAM_USE_MALLOC +#include "test_mbedtls_utils.h" +TEST_CASE("mbedtls SHA256 PSRAM DMA", "[mbedtls]") +{ + const unsigned CALLS = 256; + const unsigned CALL_SZ = 16 * 1024; + psa_hash_operation_t sha256_op = PSA_HASH_OPERATION_INIT; + unsigned char sha256[32]; + psa_status_t status; + size_t hash_len; + + // allocate external memory + uint8_t *buf = heap_caps_malloc(CALL_SZ, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + TEST_ASSERT(esp_ptr_external_ram(buf)); + memset(buf, 0x54, CALL_SZ); + + status = psa_hash_setup(&sha256_op, PSA_ALG_SHA_256); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + for (int c = 0; c < CALLS; c++) { + status = psa_hash_update(&sha256_op, buf, CALL_SZ); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + } + + status = psa_hash_finish(&sha256_op, sha256, sizeof(sha256), &hash_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + free(buf); + + /* Check the result. Reference value can be calculated using: + * dd if=/dev/zero bs=$((16*1024)) count=256 | tr '\000' '\124' | sha256sum + */ + const char *expected_hash = "8d031167bd706ac337e07aa9129c34ae4ae792d0a79a2c70e7f012102e8adc3d"; + char hash_str[sizeof(sha256) * 2 + 1]; + utils_bin2hex(hash_str, sizeof(hash_str), sha256, sizeof(sha256)); + + TEST_ASSERT_EQUAL_STRING(expected_hash, hash_str); + +} + +#if SOC_SHA_SUPPORT_DMA +TEST_CASE("mbedtls SHA256 PSRAM DMA large buffer", "[hw_crypto]") +{ + psa_hash_operation_t sha256_op = PSA_HASH_OPERATION_INIT; + unsigned char sha256[32]; + psa_status_t status; + size_t hash_len; + + // Initialize PSA Crypto + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + const size_t SZ = 257984; // specific size to cover issue in https://github.com/espressif/esp-idf/issues/11915 + void *buffer = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + TEST_ASSERT_NOT_NULL(buffer); + memset(buffer, 0x55, SZ); + + status = psa_hash_setup(&sha256_op, PSA_ALG_SHA_256); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_hash_update(&sha256_op, buffer, SZ); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_hash_finish(&sha256_op, sha256, sizeof(sha256), &hash_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + free(buffer); + + /* Check the result. Reference value can be calculated using: + * dd if=/dev/zero bs=257984 count=1 | tr '\000' '\125' | sha256sum + */ + const char *expected_hash = "f2330c9f81ff1c8f0515247faa82be8b6f9685601de6f5dae79172766f136c33"; + + char hash_str[sizeof(sha256) * 2 + 1]; + utils_bin2hex(hash_str, sizeof(hash_str), sha256, sizeof(sha256)); + + TEST_ASSERT_EQUAL_STRING(expected_hash, hash_str); +} +#endif // SOC_SHA_SUPPORT_DMA + +#endif //CONFIG_SPIRAM_USE_MALLOC + +#if CONFIG_ESP_SYSTEM_RTC_FAST_MEM_AS_HEAP_DEPCHECK && !CONFIG_IDF_TARGET_ESP32H2 +// Not enough rtc memory for test on H2 + +TEST_CASE("mbedtls SHA stack in RTC RAM", "[mbedtls]") +{ + done_sem = xSemaphoreCreateBinary(); + static StaticTask_t rtc_task; + size_t STACK_SIZE = 3072; + uint8_t *rtc_stack = heap_caps_calloc(STACK_SIZE, 1, MALLOC_CAP_RTCRAM); + + TEST_ASSERT(esp_ptr_in_rtc_dram_fast(rtc_stack)); + + TEST_ASSERT_NOT_NULL(xTaskCreateStatic(tskRunSHA256Test, "tskRunSHA256Test_task", STACK_SIZE, NULL, + 3, rtc_stack, &rtc_task)); + TEST_ASSERT_TRUE(xSemaphoreTake(done_sem, 10000 / portTICK_PERIOD_MS)); + + /* Give task time to cleanup before freeing stack */ + vTaskDelay(1000 / portTICK_PERIOD_MS); + free(rtc_stack); + + vSemaphoreDelete(done_sem); +} + +#endif //CONFIG_ESP_SYSTEM_RTC_FAST_MEM_AS_HEAP_DEPCHECK + +#if CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM && CONFIG_SPIRAM_USE_MALLOC + +TEST_CASE("mbedtls SHA stack in PSRAM", "[mbedtls]") +{ + done_sem = xSemaphoreCreateBinary(); + static StaticTask_t psram_task; + size_t STACK_SIZE = 3072; + uint8_t *psram_stack = heap_caps_calloc(STACK_SIZE, 1, MALLOC_CAP_SPIRAM); + + TEST_ASSERT(esp_ptr_external_ram(psram_stack)); + + TEST_ASSERT_NOT_NULL(xTaskCreateStatic(tskRunSHA256Test, "tskRunSHA256Test_task", STACK_SIZE, NULL, + 3, psram_stack, &psram_task)); + TEST_ASSERT_TRUE(xSemaphoreTake(done_sem, 10000 / portTICK_PERIOD_MS)); + + /* Give task time to cleanup before freeing stack */ + vTaskDelay(1000 / portTICK_PERIOD_MS); + free(psram_stack); + + vSemaphoreDelete(done_sem); +} + +#endif //CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM && CONFIG_SPIRAM_USE_MALLOC + +TEST_CASE("Test PSA SHA-384 with clone", "[hw_crypto][psa]") +{ + // Test Vector 1: SHA-384("hello world") + // Expected: fdbd8e75a67f29f701a4e040385e2e23986303ea10239211af907fcbb83578b3e417cb71ce646efd0819dd8c088de1bd + const unsigned char test3_input[] = "hello world"; + const unsigned char test3_expected[48] = { + 0xfd, 0xbd, 0x8e, 0x75, 0xa6, 0x7f, 0x29, 0xf7, + 0x01, 0xa4, 0xe0, 0x40, 0x38, 0x5e, 0x2e, 0x23, + 0x98, 0x63, 0x03, 0xea, 0x10, 0x23, 0x92, 0x11, + 0xaf, 0x90, 0x7f, 0xcb, 0xb8, 0x35, 0x78, 0xb3, + 0xe4, 0x17, 0xcb, 0x71, 0xce, 0x64, 0x6e, 0xfd, + 0x08, 0x19, 0xdd, 0x8c, 0x08, 0x8d, 0xe1, 0xbd + }; + + psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; + psa_status_t psa_status = psa_hash_setup(&operation, PSA_ALG_SHA_384); + TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); + psa_status = psa_hash_update(&operation, (const uint8_t *)test3_input, 5); // "hello" + TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); + + psa_hash_operation_t clone = PSA_HASH_OPERATION_INIT; + psa_status = psa_hash_clone(&operation, &clone); + TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); + psa_status = psa_hash_update(&clone, (const uint8_t *)(test3_input + 5), 6); // " world" + TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); + unsigned char psa_output[48]; + size_t psa_output_len; + psa_status = psa_hash_finish(&clone, psa_output, sizeof(psa_output), &psa_output_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); + TEST_ASSERT_EQUAL(48, psa_output_len); + TEST_ASSERT_EQUAL_HEX8_ARRAY(test3_expected, psa_output, 48); +} + +#endif // CONFIG_MBEDTLS_HARDWARE_SHA diff --git a/components/mbedtls/test_apps/main/test_sha.c b/components/mbedtls/test_apps/main/test_sha.c index c9ee78b085..e14182975c 100644 --- a/components/mbedtls/test_apps/main/test_sha.c +++ b/components/mbedtls/test_apps/main/test_sha.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,385 +16,164 @@ #include "spi_flash_mmap.h" #include "soc/soc_caps.h" -#define MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS + #include "unity.h" #include "test_utils.h" +#include "psa/crypto.h" #include "sha/sha_parallel_engine.h" -#include "psa/crypto.h" -#include "mbedtls/md.h" + +/* Note: Most of the SHA functions are called as part of mbedTLS, so +are tested as part of mbedTLS tests. Only esp_sha() is different. +*/ + #define TAG "sha_test" -// New test for PSA SHA-512 implementation -TEST_CASE("Test PSA SHA-512 with known test vectors", "[hw_crypto][psa]") +#if SOC_SHA_SUPPORTED && CONFIG_MBEDTLS_HARDWARE_SHA +TEST_CASE("Test esp_sha()", "[hw_crypto]") { - ESP_LOGI(TAG, "Testing PSA SHA-512 implementation with known test vectors"); + const size_t BUFFER_SZ = 32 * 1024 + 6; // NB: not an exact multiple of SHA block size - // Test Vector 1: SHA-512("abc") - // Expected: ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f - const unsigned char test1_input[] = "abc"; - const size_t test1_input_len = 3; - const unsigned char test1_expected[64] = { - 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31, - 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, - 0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, - 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f - }; + int64_t elapsed; + uint32_t us_sha1; + uint8_t sha1_result[20] = { 0 }; - // Test Vector 2: SHA-512("") - // Expected: cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e - const unsigned char test2_input[] = ""; - const size_t test2_input_len = 0; - const unsigned char test2_expected[64] = { - 0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, 0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07, - 0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, 0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce, - 0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0, 0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f, - 0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81, 0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e - }; +#if SOC_SHA_SUPPORT_SHA512 + uint32_t us_sha512; + uint8_t sha512_result[64] = { 0 }; +#endif - unsigned char psa_output[64]; - unsigned char mbedtls_output[64]; - size_t psa_output_len; - psa_status_t psa_status; - int mbedtls_ret; + void *buffer = heap_caps_malloc(BUFFER_SZ, MALLOC_CAP_8BIT|MALLOC_CAP_INTERNAL); + TEST_ASSERT_NOT_NULL(buffer); + memset(buffer, 0xEE, BUFFER_SZ); - ESP_LOGI(TAG, "=== Test 1: SHA-512(\"abc\") ==="); + const uint8_t sha1_expected[20] = { 0xc7, 0xbb, 0xd3, 0x74, 0xf2, 0xf6, 0x20, 0x86, + 0x61, 0xf4, 0x50, 0xd5, 0xf5, 0x18, 0x44, 0xcc, + 0x7a, 0xb7, 0xa5, 0x4a }; +#if SOC_SHA_SUPPORT_SHA512 + const uint8_t sha512_expected[64] = { 0xc7, 0x7f, 0xda, 0x8c, 0xb3, 0x58, 0x14, 0x8a, + 0x52, 0x3b, 0x46, 0x04, 0xc0, 0x85, 0xc5, 0xf0, + 0x46, 0x64, 0x14, 0xd5, 0x96, 0x7a, 0xa2, 0x80, + 0x20, 0x9c, 0x04, 0x27, 0x7d, 0x3b, 0xf9, 0x1f, + 0xb2, 0xa3, 0x45, 0x3c, 0xa1, 0x6a, 0x8d, 0xdd, + 0x35, 0x5e, 0x35, 0x57, 0x76, 0x22, 0x74, 0xd8, + 0x1e, 0x07, 0xc6, 0xa2, 0x9e, 0x3b, 0x65, 0x75, + 0x80, 0x7d, 0xe6, 0x6e, 0x47, 0x61, 0x2c, 0x94 }; +#endif - // Test with PSA - ESP_LOGI(TAG, "Testing PSA psa_hash_compute()..."); - psa_status = psa_hash_compute(PSA_ALG_SHA_512, test1_input, test1_input_len, - psa_output, sizeof(psa_output), &psa_output_len); - ESP_LOGI(TAG, "PSA status: 0x%x, output_len: %zu", (unsigned int)psa_status, psa_output_len); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); - TEST_ASSERT_EQUAL(64, psa_output_len); + ccomp_timer_start(); + esp_sha(SHA1, buffer, BUFFER_SZ, sha1_result); + elapsed = ccomp_timer_stop(); + TEST_ASSERT_EQUAL_HEX8_ARRAY(sha1_expected, sha1_result, sizeof(sha1_expected)); + us_sha1 = elapsed; + ESP_LOGI(TAG, "esp_sha() 32KB SHA1 in %" PRIu32 " us", us_sha1); - ESP_LOGI(TAG, "PSA result: %02x %02x %02x %02x %02x %02x %02x %02x...", - psa_output[0], psa_output[1], psa_output[2], psa_output[3], - psa_output[4], psa_output[5], psa_output[6], psa_output[7]); - ESP_LOGI(TAG, "Expected result: %02x %02x %02x %02x %02x %02x %02x %02x...", - test1_expected[0], test1_expected[1], test1_expected[2], test1_expected[3], - test1_expected[4], test1_expected[5], test1_expected[6], test1_expected[7]); +#if SOC_SHA_SUPPORT_SHA512 + ccomp_timer_start(); + esp_sha(SHA2_512, buffer, BUFFER_SZ, sha512_result); + elapsed = ccomp_timer_stop(); + TEST_ASSERT_EQUAL_HEX8_ARRAY(sha512_expected, sha512_result, sizeof(sha512_expected)); - TEST_ASSERT_EQUAL_HEX8_ARRAY(test1_expected, psa_output, 64); - ESP_LOGI(TAG, "✓ PSA SHA-512(\"abc\") PASSED"); + us_sha512 = elapsed; + ESP_LOGI(TAG, "esp_sha() 32KB SHA512 in %" PRIu32 " us", us_sha512); +#endif - // Test with mbedtls_md - ESP_LOGI(TAG, "Testing mbedtls_md()..."); - const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); - TEST_ASSERT_NOT_NULL(md_info); +/* NOTE: The Mbed TLS ROM implementation needs to updated to support SHA224 operations */ +#if !CONFIG_MBEDTLS_USE_CRYPTO_ROM_IMPL +#if SOC_SHA_SUPPORT_SHA224 + uint8_t sha224_result[28] = { 0 }; + const uint8_t sha224_expected[28] = { 0xc0, 0x2a, 0x54, 0x2f, 0x70, 0x93, 0xaa, 0x3e, + 0xb6, 0xec, 0xe6, 0xb2, 0xb8, 0xe6, 0x57, 0x27, + 0xf9, 0x34, 0x9e, 0xb7, 0xbc, 0x96, 0x0d, 0xf5, + 0xd9, 0x87, 0xa8, 0x17 }; + esp_sha(SHA2_224, buffer, BUFFER_SZ, sha224_result); + TEST_ASSERT_EQUAL_HEX8_ARRAY(sha224_expected, sha224_result, sizeof(sha224_expected)); +#endif +#endif - mbedtls_ret = mbedtls_md(md_info, test1_input, test1_input_len, mbedtls_output); - ESP_LOGI(TAG, "mbedtls_md return: %d", mbedtls_ret); - TEST_ASSERT_EQUAL(0, mbedtls_ret); +#if SOC_SHA_SUPPORT_SHA384 + uint8_t sha384_result[48] = { 0 }; + const uint8_t sha384_expected[48] = { 0x72, 0x13, 0xc8, 0x09, 0x7b, 0xbc, 0x9e, 0x65, + 0x02, 0xf8, 0x1d, 0xd2, 0x02, 0xd3, 0xd1, 0x80, + 0x48, 0xb9, 0xfb, 0x10, 0x2f, 0x1b, 0xd1, 0x40, + 0x4c, 0xc6, 0x3c, 0xfe, 0xcf, 0xa0, 0x83, 0x1b, + 0x6e, 0xfb, 0x97, 0x17, 0x65, 0x08, 0x28, 0x04, + 0x2f, 0x06, 0x2c, 0x97, 0x4e, 0xf8, 0x26, 0x86 }; + esp_sha(SHA2_384, buffer, BUFFER_SZ, sha384_result); + TEST_ASSERT_EQUAL_HEX8_ARRAY(sha384_expected, sha384_result, sizeof(sha384_expected)); +#endif - ESP_LOGI(TAG, "mbedtls result: %02x %02x %02x %02x %02x %02x %02x %02x...", - mbedtls_output[0], mbedtls_output[1], mbedtls_output[2], mbedtls_output[3], - mbedtls_output[4], mbedtls_output[5], mbedtls_output[6], mbedtls_output[7]); + free(buffer); - TEST_ASSERT_EQUAL_HEX8_ARRAY(test1_expected, mbedtls_output, 64); - ESP_LOGI(TAG, "✓ mbedtls_md SHA-512(\"abc\") PASSED"); + TEST_PERFORMANCE_CCOMP_LESS_THAN(TIME_SHA1_32KB, "%" PRId32 " us", us_sha1); - // Verify both methods produce the same result - TEST_ASSERT_EQUAL_MEMORY(psa_output, mbedtls_output, 64); - ESP_LOGI(TAG, "✓ PSA and mbedtls_md results match"); - - ESP_LOGI(TAG, "=== Test 2: SHA-512(\"\") (empty string) ==="); - - // Test with PSA - psa_status = psa_hash_compute(PSA_ALG_SHA_512, test2_input, test2_input_len, - psa_output, sizeof(psa_output), &psa_output_len); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); - TEST_ASSERT_EQUAL(64, psa_output_len); - TEST_ASSERT_EQUAL_HEX8_ARRAY(test2_expected, psa_output, 64); - ESP_LOGI(TAG, "✓ PSA SHA-512(\"\") PASSED"); - - // Test with mbedtls_md - mbedtls_ret = mbedtls_md(md_info, test2_input, test2_input_len, mbedtls_output); - TEST_ASSERT_EQUAL(0, mbedtls_ret); - TEST_ASSERT_EQUAL_HEX8_ARRAY(test2_expected, mbedtls_output, 64); - ESP_LOGI(TAG, "✓ mbedtls_md SHA-512(\"\") PASSED"); - - // Verify both methods produce the same result - TEST_ASSERT_EQUAL_MEMORY(psa_output, mbedtls_output, 64); - ESP_LOGI(TAG, "✓ All PSA SHA-512 tests PASSED!"); +#if SOC_SHA_SUPPORT_SHA512 + TEST_PERFORMANCE_CCOMP_LESS_THAN(TIME_SHA512_32KB, "%" PRId32 " us", us_sha512); +#endif } -TEST_CASE("Test PSA SHA-256 with known test vectors", "[hw_crypto][psa]") +/* NOTE: This test attempts to mmap 1MB of flash starting from address 0x00, which overlaps + * the entire TEE protected region, causing the mmap operation to fail and triggering an + * exception in the subsequent steps. + */ +#if !CONFIG_SECURE_ENABLE_TEE + +TEST_CASE("Test esp_sha() function with long input", "[hw_crypto]") { - ESP_LOGI(TAG, "Testing PSA SHA-256 implementation with known test vectors"); + int r = -1; + const void* ptr; + spi_flash_mmap_handle_t handle; +#if CONFIG_MBEDTLS_SHA1_C + uint8_t sha1_espsha[20] = { 0 }; + uint8_t sha1_mbedtls[20] = { 0 }; +#endif + uint8_t sha256_espsha[32] = { 0 }; + uint8_t sha256_mbedtls[32] = { 0 }; - // Test Vector 1: SHA-256("abc") - // Expected: ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad - const unsigned char test1_input[] = "abc"; - const size_t test1_input_len = 3; - const unsigned char test1_expected[32] = { - 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, - 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, - 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, - 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad - }; +#if SOC_SHA_SUPPORT_SHA512 && CONFIG_MBEDTLS_SHA512_C + uint8_t sha512_espsha[64] = { 0 }; + uint8_t sha512_mbedtls[64] = { 0 }; +#endif - // Test Vector 2: SHA-256("") - // Expected: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 - const unsigned char test2_input[] = ""; - const size_t test2_input_len = 0; - const unsigned char test2_expected[32] = { - 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, - 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, - 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, - 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 - }; + const size_t LEN = 1024 * 1024; - // Test Vector 3: SHA-256("hello world") - // Expected: b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 - const unsigned char test3_input[] = "hello world"; - const unsigned char test3_expected[32] = { - 0xb9, 0x4d, 0x27, 0xb9, 0x93, 0x4d, 0x3e, 0x08, - 0xa5, 0x2e, 0x52, 0xd7, 0xda, 0x7d, 0xab, 0xfa, - 0xc4, 0x84, 0xef, 0xe3, 0x7a, 0x53, 0x80, 0xee, - 0x90, 0x88, 0xf7, 0xac, 0xe2, 0xef, 0xcd, 0xe9 - }; + /* mmap() 1MB of flash, we don't care what it is really */ + esp_err_t err = spi_flash_mmap(0x0, LEN, SPI_FLASH_MMAP_DATA, &ptr, &handle); - unsigned char psa_output[32]; - unsigned char mbedtls_output[32]; - size_t psa_output_len; - psa_status_t psa_status; - int mbedtls_ret; + TEST_ASSERT_EQUAL_HEX32(ESP_OK, err); + TEST_ASSERT_NOT_NULL(ptr); - ESP_LOGI(TAG, "=== Test 1: SHA-256(\"abc\") ==="); + /* Compare esp_sha() result to the PSA result, should always be the same */ +#if CONFIG_MBEDTLS_SHA1_C + esp_sha(SHA1, ptr, LEN, sha1_espsha); + size_t hash_len; + r = psa_hash_compute(PSA_ALG_SHA_1, ptr, LEN, sha1_mbedtls, sizeof(sha1_mbedtls), &hash_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, r); +#endif - // Test with PSA - ESP_LOGI(TAG, "Testing PSA psa_hash_compute()..."); - psa_status = psa_hash_compute(PSA_ALG_SHA_256, test1_input, test1_input_len, - psa_output, sizeof(psa_output), &psa_output_len); - ESP_LOGI(TAG, "PSA status: 0x%x, output_len: %zu", (unsigned int)psa_status, psa_output_len); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); - TEST_ASSERT_EQUAL(32, psa_output_len); + esp_sha(SHA2_256, ptr, LEN, sha256_espsha); + r = psa_hash_compute(PSA_ALG_SHA_256, ptr, LEN, sha256_mbedtls, sizeof(sha256_mbedtls), &hash_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, r); - ESP_LOGI(TAG, "PSA result: %02x %02x %02x %02x %02x %02x %02x %02x...", - psa_output[0], psa_output[1], psa_output[2], psa_output[3], - psa_output[4], psa_output[5], psa_output[6], psa_output[7]); - ESP_LOGI(TAG, "Expected result: %02x %02x %02x %02x %02x %02x %02x %02x...", - test1_expected[0], test1_expected[1], test1_expected[2], test1_expected[3], - test1_expected[4], test1_expected[5], test1_expected[6], test1_expected[7]); +#if SOC_SHA_SUPPORT_SHA512 && CONFIG_MBEDTLS_SHA512_C + esp_sha(SHA2_512, ptr, LEN, sha512_espsha); + r = psa_hash_compute(PSA_ALG_SHA_512, ptr, LEN, sha512_mbedtls, sizeof(sha512_mbedtls), &hash_len); + TEST_ASSERT_EQUAL(PSA_SUCCESS, r); +#endif - TEST_ASSERT_EQUAL_HEX8_ARRAY(test1_expected, psa_output, 32); - ESP_LOGI(TAG, "✓ PSA SHA-256(\"abc\") PASSED"); + /* munmap() 1MB of flash when the usge of memory-mapped ptr is over */ + spi_flash_munmap(handle); - // Test with mbedtls_md - ESP_LOGI(TAG, "Testing mbedtls_md()..."); - const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); - TEST_ASSERT_NOT_NULL(md_info); +#if CONFIG_MBEDTLS_SHA1_C + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha1_espsha, sha1_mbedtls, sizeof(sha1_espsha), "SHA1 results should match"); +#endif - mbedtls_ret = mbedtls_md(md_info, test1_input, test1_input_len, mbedtls_output); - ESP_LOGI(TAG, "mbedtls_md return: %d", mbedtls_ret); - TEST_ASSERT_EQUAL(0, mbedtls_ret); + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha256_espsha, sha256_mbedtls, sizeof(sha256_espsha), "SHA256 results should match"); - ESP_LOGI(TAG, "mbedtls result: %02x %02x %02x %02x %02x %02x %02x %02x...", - mbedtls_output[0], mbedtls_output[1], mbedtls_output[2], mbedtls_output[3], - mbedtls_output[4], mbedtls_output[5], mbedtls_output[6], mbedtls_output[7]); - - TEST_ASSERT_EQUAL_HEX8_ARRAY(test1_expected, mbedtls_output, 32); - ESP_LOGI(TAG, "✓ mbedtls_md SHA-256(\"abc\") PASSED"); - - // Verify both methods produce the same result - TEST_ASSERT_EQUAL_MEMORY(psa_output, mbedtls_output, 32); - ESP_LOGI(TAG, "✓ PSA and mbedtls_md results match"); - - ESP_LOGI(TAG, "=== Test 2: SHA-256(\"\") (empty string) ==="); - - // Test with PSA - psa_status = psa_hash_compute(PSA_ALG_SHA_256, test2_input, test2_input_len, - psa_output, sizeof(psa_output), &psa_output_len); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); - TEST_ASSERT_EQUAL(32, psa_output_len); - TEST_ASSERT_EQUAL_HEX8_ARRAY(test2_expected, psa_output, 32); - ESP_LOGI(TAG, "✓ PSA SHA-256(\"\") PASSED"); - - // Test with mbedtls_md - mbedtls_ret = mbedtls_md(md_info, test2_input, test2_input_len, mbedtls_output); - TEST_ASSERT_EQUAL(0, mbedtls_ret); - TEST_ASSERT_EQUAL_HEX8_ARRAY(test2_expected, mbedtls_output, 32); - ESP_LOGI(TAG, "✓ mbedtls_md SHA-256(\"\") PASSED"); - - // Verify both methods produce the same result - TEST_ASSERT_EQUAL_MEMORY(psa_output, mbedtls_output, 32); - ESP_LOGI(TAG, "✓ All PSA SHA-256 tests PASSED!"); - - // Test Vector 3: SHA-256("hello world") - // This will do with PSA only but _update will be called multiple time - - ESP_LOGI(TAG, "=== Test 3: SHA-256(\"hello world\") ==="); - psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; - psa_status = psa_hash_setup(&operation, PSA_ALG_SHA_256); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); - psa_status = psa_hash_update(&operation, (const uint8_t *)test3_input, 5); // "hello" - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); - psa_status = psa_hash_update(&operation, (const uint8_t *)(test3_input + 5), 6); // " world" - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); - psa_status = psa_hash_finish(&operation, psa_output, sizeof(psa_output), &psa_output_len); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); - TEST_ASSERT_EQUAL(32, psa_output_len); - TEST_ASSERT_EQUAL_HEX8_ARRAY(test3_expected, psa_output, 32); - ESP_LOGI(TAG, "✓ PSA SHA-256(\"hello world\") PASSED"); +#if SOC_SHA_SUPPORT_SHA512 && CONFIG_MBEDTLS_SHA512_C + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha512_espsha, sha512_mbedtls, sizeof(sha512_espsha), "SHA512 results should match"); +#endif } -TEST_CASE("Test PSA SHA-384 with known test vectors", "[hw_crypto][psa]") -{ - ESP_LOGI(TAG, "Testing PSA SHA-384 implementation with known test vectors"); - - // Test Vector 1: SHA-384("abc") - // Expected: cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7 - const unsigned char test1_input[] = "abc"; - const size_t test1_input_len = 3; - const unsigned char test1_expected[48] = { - 0xcb, 0x00, 0x75, 0x3f, 0x45, 0xa3, 0x5e, 0x8b, - 0xb5, 0xa0, 0x3d, 0x69, 0x9a, 0xc6, 0x50, 0x07, - 0x27, 0x2c, 0x32, 0xab, 0x0e, 0xde, 0xd1, 0x63, - 0x1a, 0x8b, 0x60, 0x5a, 0x43, 0xff, 0x5b, 0xed, - 0x80, 0x86, 0x07, 0x2b, 0xa1, 0xe7, 0xcc, 0x23, - 0x58, 0xba, 0xec, 0xa1, 0x34, 0xc8, 0x25, 0xa7 - }; - - // Test Vector 2: SHA-384("") - // Expected: 38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b - const unsigned char test2_input[] = ""; - const size_t test2_input_len = 0; - const unsigned char test2_expected[48] = { - 0x38, 0xb0, 0x60, 0xa7, 0x51, 0xac, 0x96, 0x38, - 0x4c, 0xd9, 0x32, 0x7e, 0xb1, 0xb1, 0xe3, 0x6a, - 0x21, 0xfd, 0xb7, 0x11, 0x14, 0xbe, 0x07, 0x43, - 0x4c, 0x0c, 0xc7, 0xbf, 0x63, 0xf6, 0xe1, 0xda, - 0x27, 0x4e, 0xde, 0xbf, 0xe7, 0x6f, 0x65, 0xfb, - 0xd5, 0x1a, 0xd2, 0xf1, 0x48, 0x98, 0xb9, 0x5b - }; - - // Test Vector 3: SHA-384("hello world") - // Expected: fdbd8e75a67f29f701a4e040385e2e23986303ea10239211af907fcbb83578b3e417cb71ce646efd0819dd8c088de1bd - const unsigned char test3_input[] = "hello world"; - const unsigned char test3_expected[48] = { - 0xfd, 0xbd, 0x8e, 0x75, 0xa6, 0x7f, 0x29, 0xf7, - 0x01, 0xa4, 0xe0, 0x40, 0x38, 0x5e, 0x2e, 0x23, - 0x98, 0x63, 0x03, 0xea, 0x10, 0x23, 0x92, 0x11, - 0xaf, 0x90, 0x7f, 0xcb, 0xb8, 0x35, 0x78, 0xb3, - 0xe4, 0x17, 0xcb, 0x71, 0xce, 0x64, 0x6e, 0xfd, - 0x08, 0x19, 0xdd, 0x8c, 0x08, 0x8d, 0xe1, 0xbd - }; - - unsigned char psa_output[48]; - unsigned char mbedtls_output[48]; - size_t psa_output_len; - psa_status_t psa_status; - int mbedtls_ret; - - ESP_LOGI(TAG, "=== Test 1: SHA-384(\"abc\") ==="); - - // Test with PSA - ESP_LOGI(TAG, "Testing PSA psa_hash_compute()..."); - psa_status = psa_hash_compute(PSA_ALG_SHA_384, test1_input, test1_input_len, - psa_output, sizeof(psa_output), &psa_output_len); - ESP_LOGI(TAG, "PSA status: 0x%x, output_len: %zu", (unsigned int)psa_status, psa_output_len); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); - TEST_ASSERT_EQUAL(48, psa_output_len); - - ESP_LOGI(TAG, "PSA result: %02x %02x %02x %02x %02x %02x %02x %02x...", - psa_output[0], psa_output[1], psa_output[2], psa_output[3], - psa_output[4], psa_output[5], psa_output[6], psa_output[7]); - ESP_LOGI(TAG, "Expected result: %02x %02x %02x %02x %02x %02x %02x %02x...", - test1_expected[0], test1_expected[1], test1_expected[2], test1_expected[3], - test1_expected[4], test1_expected[5], test1_expected[6], test1_expected[7]); - - TEST_ASSERT_EQUAL_HEX8_ARRAY(test1_expected, psa_output, 48); - ESP_LOGI(TAG, "✓ PSA SHA-384(\"abc\") PASSED"); - - // Test with mbedtls_md - ESP_LOGI(TAG, "Testing mbedtls_md()..."); - const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384); - TEST_ASSERT_NOT_NULL(md_info); - - mbedtls_ret = mbedtls_md(md_info, test1_input, test1_input_len, mbedtls_output); - ESP_LOGI(TAG, "mbedtls_md return: %d", mbedtls_ret); - TEST_ASSERT_EQUAL(0, mbedtls_ret); - - ESP_LOGI(TAG, "mbedtls result: %02x %02x %02x %02x %02x %02x %02x %02x...", - mbedtls_output[0], mbedtls_output[1], mbedtls_output[2], mbedtls_output[3], - mbedtls_output[4], mbedtls_output[5], mbedtls_output[6], mbedtls_output[7]); - - TEST_ASSERT_EQUAL_HEX8_ARRAY(test1_expected, mbedtls_output, 48); - ESP_LOGI(TAG, "✓ mbedtls_md SHA-384(\"abc\") PASSED"); - - // Verify both methods produce the same result - TEST_ASSERT_EQUAL_MEMORY(psa_output, mbedtls_output, 48); - ESP_LOGI(TAG, "✓ PSA and mbedtls_md results match"); - - ESP_LOGI(TAG, "=== Test 2: SHA-384(\"\") (empty string) ==="); - - // Test with PSA - psa_status = psa_hash_compute(PSA_ALG_SHA_384, test2_input, test2_input_len, - psa_output, sizeof(psa_output), &psa_output_len); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); - TEST_ASSERT_EQUAL(48, psa_output_len); - TEST_ASSERT_EQUAL_HEX8_ARRAY(test2_expected, psa_output, 48); - ESP_LOGI(TAG, "✓ PSA SHA-384(\"\") PASSED"); - - // Test with mbedtls_md - mbedtls_ret = mbedtls_md(md_info, test2_input, test2_input_len, mbedtls_output); - TEST_ASSERT_EQUAL(0, mbedtls_ret); - TEST_ASSERT_EQUAL_HEX8_ARRAY(test2_expected, mbedtls_output, 48); - ESP_LOGI(TAG, "✓ mbedtls_md SHA-384(\"\") PASSED"); - - // Verify both methods produce the same result - TEST_ASSERT_EQUAL_MEMORY(psa_output, mbedtls_output, 48); - ESP_LOGI(TAG, "✓ All PSA SHA-384 tests PASSED!"); - - // Test Vector 3: SHA-384("hello world") - // This will do with PSA only but _update will be called multiple time - - ESP_LOGI(TAG, "=== Test 3: SHA-384(\"hello world\") ==="); - psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; - psa_status = psa_hash_setup(&operation, PSA_ALG_SHA_384); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); - psa_status = psa_hash_update(&operation, (const uint8_t *)test3_input, 5); // "hello" - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); - psa_status = psa_hash_update(&operation, (const uint8_t *)(test3_input + 5), 6); // " world" - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); - psa_status = psa_hash_finish(&operation, psa_output, sizeof(psa_output), &psa_output_len); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); - TEST_ASSERT_EQUAL(48, psa_output_len); - TEST_ASSERT_EQUAL_HEX8_ARRAY(test3_expected, psa_output, 48); - ESP_LOGI(TAG, "✓ PSA SHA-384(\"hello world\") PASSED"); -} - -TEST_CASE("Test PSA SHA-384 with clone", "[hw_crypto][psa]") -{ - // Test Vector 1: SHA-384("hello world") - // Expected: fdbd8e75a67f29f701a4e040385e2e23986303ea10239211af907fcbb83578b3e417cb71ce646efd0819dd8c088de1bd - const unsigned char test3_input[] = "hello world"; - const unsigned char test3_expected[48] = { - 0xfd, 0xbd, 0x8e, 0x75, 0xa6, 0x7f, 0x29, 0xf7, - 0x01, 0xa4, 0xe0, 0x40, 0x38, 0x5e, 0x2e, 0x23, - 0x98, 0x63, 0x03, 0xea, 0x10, 0x23, 0x92, 0x11, - 0xaf, 0x90, 0x7f, 0xcb, 0xb8, 0x35, 0x78, 0xb3, - 0xe4, 0x17, 0xcb, 0x71, 0xce, 0x64, 0x6e, 0xfd, - 0x08, 0x19, 0xdd, 0x8c, 0x08, 0x8d, 0xe1, 0xbd - }; - - psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; - psa_status_t psa_status = psa_hash_setup(&operation, PSA_ALG_SHA_384); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); - psa_status = psa_hash_update(&operation, (const uint8_t *)test3_input, 5); // "hello" - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); - - psa_hash_operation_t clone = PSA_HASH_OPERATION_INIT; - psa_status = psa_hash_clone(&operation, &clone); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); - psa_status = psa_hash_update(&clone, (const uint8_t *)(test3_input + 5), 6); // " world" - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); - unsigned char psa_output[48]; - size_t psa_output_len; - psa_status = psa_hash_finish(&clone, psa_output, sizeof(psa_output), &psa_output_len); - TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_status); - TEST_ASSERT_EQUAL(48, psa_output_len); - TEST_ASSERT_EQUAL_HEX8_ARRAY(test3_expected, psa_output, 48); - ESP_LOGI(TAG, "✓ PSA SHA-384(\"hello world\") with original PASSED"); -} +#endif +#endif // SOC_SHA_SUPPORTED && CONFIG_MBEDTLS_HARDWARE_SHA diff --git a/components/mbedtls/test_apps/pytest_mbedtls_ut.py b/components/mbedtls/test_apps/pytest_mbedtls_ut.py index 2edea13c17..079cac6529 100644 --- a/components/mbedtls/test_apps/pytest_mbedtls_ut.py +++ b/components/mbedtls/test_apps/pytest_mbedtls_ut.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 import pytest from pytest_embedded import Dut @@ -78,6 +78,19 @@ def test_mbedtls_psram_all_ext_flash_enc(dut: Dut) -> None: dut.run_all_single_board_cases(timeout=180) +@pytest.mark.flash_encryption_f4r8 +@pytest.mark.parametrize( + 'config', + [ + 'psram_all_ext_flash_enc_f4r8', + ], + indirect=True, +) +@idf_parametrize('target', ['esp32s3'], indirect=['target']) +def test_mbedtls_psram_all_ext_flash_enc_s3_f4r8(dut: Dut) -> None: + dut.run_all_single_board_cases(timeout=180) + + @pytest.mark.ecdsa_efuse @pytest.mark.parametrize( 'config', diff --git a/components/mbedtls/test_apps/sdkconfig.ci.psram_all_ext_flash_enc_f4r8 b/components/mbedtls/test_apps/sdkconfig.ci.psram_all_ext_flash_enc_f4r8 new file mode 100644 index 0000000000..11158f3463 --- /dev/null +++ b/components/mbedtls/test_apps/sdkconfig.ci.psram_all_ext_flash_enc_f4r8 @@ -0,0 +1,20 @@ +CONFIG_SPIRAM=y +CONFIG_ESP_INT_WDT_TIMEOUT_MS=800 +CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM=y +CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0 + +# Default settings for testing this example in CI. +# This configuration is not secure, don't use it in production! +# See Flash Encryption API Guide for more details. + +CONFIG_SECURE_FLASH_ENC_ENABLED=y +CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=y +CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC=y +CONFIG_SECURE_BOOT_ALLOW_JTAG=y +CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC=y +CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC=y +CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE=y +CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED=y + +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_TYPE_AUTO=y diff --git a/docs/en/security/security.rst b/docs/en/security/security.rst index 36bb28e0c9..ca0a890d2d 100644 --- a/docs/en/security/security.rst +++ b/docs/en/security/security.rst @@ -157,7 +157,7 @@ Flash Encryption Best Practices * - High - 72.4 % - .. [#] The above performance numbers have been calculated using the AES performance test of the mbedtls test application :component_file:`test_aes_perf.c `. + .. [#] The above performance numbers have been calculated using the AES performance test of the mbedtls test application :component_file:`test_psa_aes_perf.c `. Considering the above performance impact, ESP-IDF by-default does not enable the pseudo-round function to avoid any performance-related degrade. But it is recommended to enable the pseudo-round function for better security. diff --git a/docs/zh_CN/security/security.rst b/docs/zh_CN/security/security.rst index 57e8846c5f..4f7792be59 100644 --- a/docs/zh_CN/security/security.rst +++ b/docs/zh_CN/security/security.rst @@ -157,7 +157,7 @@ flash 加密最佳实践 * - 高 - 72.4 % - .. [#] 上述性能数据通过 mbedtls 测试应用中的 AES 性能测试 :component_file:`test_aes_perf.c ` 计算得出。 + .. [#] 上述性能数据通过 mbedtls 测试应用中的 AES 性能测试 :component_file:`test_psa_aes_perf.c ` 计算得出。 考虑到上述性能影响,ESP-IDF 默认关闭伪轮次功能,避免对相关性能造成影响。但如果需要更高的安全性,仍然建议启用。