diff --git a/components/hal/test_apps/crypto/main/CMakeLists.txt b/components/hal/test_apps/crypto/main/CMakeLists.txt index 3f7585a3aa..c9644c852e 100644 --- a/components/hal/test_apps/crypto/main/CMakeLists.txt +++ b/components/hal/test_apps/crypto/main/CMakeLists.txt @@ -21,6 +21,12 @@ if(CONFIG_SOC_ECDSA_SUPPORTED) list(APPEND srcs "ecdsa/test_ecdsa.c") endif() +if(CONFIG_SOC_KEY_MANAGER_SUPPORTED) + list(APPEND srcs "key_manager/test_key_manager.c" + "$ENV{IDF_PATH}/components/esp_hw_support/esp_key_mgr.c") + list(APPEND priv_include_dirs "$ENV{IDF_PATH}/components/esp_hw_support/include") +endif() + if(CONFIG_SOC_AES_SUPPORTED) list(APPEND srcs "aes/test_aes.c" "$ENV{IDF_PATH}/components/mbedtls/port/aes/esp_aes_common.c" @@ -68,7 +74,7 @@ if(CONFIG_SOC_SHA_SUPPORTED) endif() idf_component_register(SRCS ${srcs} - PRIV_REQUIRES efuse mbedtls esp_mm bootloader_support + PRIV_REQUIRES efuse mbedtls esp_mm bootloader_support spi_flash REQUIRES test_utils unity WHOLE_ARCHIVE PRIV_INCLUDE_DIRS "${priv_include_dirs}" diff --git a/components/hal/test_apps/crypto/main/app_main.c b/components/hal/test_apps/crypto/main/app_main.c index 6708b7a768..460445a343 100644 --- a/components/hal/test_apps/crypto/main/app_main.c +++ b/components/hal/test_apps/crypto/main/app_main.c @@ -30,6 +30,10 @@ static void run_all_tests(void) #endif /* !CONFIG_SOC_SHA_SUPPORT_PARALLEL_ENG*/ #endif +#if CONFIG_SOC_KEY_MANAGER_SUPPORTED + RUN_TEST_GROUP(key_manager); +#endif + #if CONFIG_IDF_ENV_FPGA #if CONFIG_SOC_HMAC_SUPPORTED && CONFIG_CRYPTO_TEST_APP_ENABLE_HMAC_TESTS diff --git a/components/hal/test_apps/crypto/main/ecdsa/test_ecdsa.c b/components/hal/test_apps/crypto/main/ecdsa/test_ecdsa.c index 2a7e1d4239..343304bd77 100644 --- a/components/hal/test_apps/crypto/main/ecdsa/test_ecdsa.c +++ b/components/hal/test_apps/crypto/main/ecdsa/test_ecdsa.c @@ -72,7 +72,7 @@ static void ecc_be_to_le(const uint8_t* be_point, uint8_t *le_point, uint8_t len } } -static int test_ecdsa_verify(bool is_p256, uint8_t* sha, uint8_t* r_le, uint8_t* s_le, uint8_t *pub_x, uint8_t *pub_y) +int test_ecdsa_verify(bool is_p256, uint8_t* sha, uint8_t* r_le, uint8_t* s_le, uint8_t *pub_x, uint8_t *pub_y) { uint16_t len; uint8_t sha_le[32]; @@ -139,7 +139,7 @@ static void test_ecdsa_corrupt_data(bool is_p256, uint8_t* sha, uint8_t* r_le, u } -static void test_ecdsa_sign(bool is_p256, uint8_t* sha, uint8_t* r_le, uint8_t* s_le, bool use_km_key, ecdsa_sign_type_t k_type) +void test_ecdsa_sign(bool is_p256, uint8_t* sha, uint8_t* r_le, uint8_t* s_le, bool use_km_key, ecdsa_sign_type_t k_type) { uint8_t sha_le[32] = {0}; uint8_t zeroes[32] = {0}; @@ -201,7 +201,7 @@ static void test_ecdsa_sign(bool is_p256, uint8_t* sha, uint8_t* r_le, uint8_t* ecdsa_disable(); } -static void test_ecdsa_sign_and_verify(bool is_p256, uint8_t* sha, uint8_t* pub_x, uint8_t* pub_y, bool use_km_key, ecdsa_sign_type_t k_type) +void test_ecdsa_sign_and_verify(bool is_p256, uint8_t* sha, uint8_t* pub_x, uint8_t* pub_y, bool use_km_key, ecdsa_sign_type_t k_type) { uint8_t r_le[32] = {0}; uint8_t s_le[32] = {0}; @@ -211,13 +211,10 @@ static void test_ecdsa_sign_and_verify(bool is_p256, uint8_t* sha, uint8_t* pub_ } #ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY -static void test_ecdsa_export_pubkey(bool is_p256, bool use_km_key) +void test_ecdsa_export_pubkey_inner(bool is_p256, uint8_t *exported_pub_x, uint8_t *exported_pub_y, bool use_km_key, uint16_t *len) { - uint8_t pub_x[32] = {0}; - uint8_t pub_y[32] = {0}; - uint8_t zeroes[32] = {0}; - uint16_t len; + uint8_t zeroes[32] = {0}; ecdsa_hal_config_t conf = { .mode = ECDSA_MODE_EXPORT_PUBKEY, .use_km_key = use_km_key, @@ -228,13 +225,13 @@ static void test_ecdsa_export_pubkey(bool is_p256, bool use_km_key) if (use_km_key == 0) { conf.efuse_key_blk = EFUSE_BLK_KEY0 + ECDSA_KEY_BLOCK_2; } - len = 32; + *len = 32; } else { conf.curve = ECDSA_CURVE_SECP192R1; if (use_km_key == 0) { conf.efuse_key_blk = EFUSE_BLK_KEY0 + ECDSA_KEY_BLOCK_1; } - len = 24; + *len = 24; } ecdsa_enable_and_reset(); @@ -242,24 +239,28 @@ static void test_ecdsa_export_pubkey(bool is_p256, bool use_km_key) bool process_again = false; do { - ecdsa_hal_export_pubkey(&conf, pub_x, pub_y, len); + ecdsa_hal_export_pubkey(&conf, exported_pub_x, exported_pub_y, *len); process_again = !ecdsa_hal_get_operation_result() - || !memcmp(pub_x, zeroes, len) - || !memcmp(pub_y, zeroes, len); + || !memcmp(exported_pub_x, zeroes, *len) + || !memcmp(exported_pub_y, zeroes, *len); } while (process_again); - if (is_p256) { - TEST_ASSERT_EQUAL_HEX8_ARRAY(ecdsa256_pub_x, pub_x, len); - TEST_ASSERT_EQUAL_HEX8_ARRAY(ecdsa256_pub_y, pub_y, len); - } else { - TEST_ASSERT_EQUAL_HEX8_ARRAY(ecdsa192_pub_x, pub_x, len); - TEST_ASSERT_EQUAL_HEX8_ARRAY(ecdsa192_pub_y, pub_y, len); - } - ecdsa_disable(); } + +void test_ecdsa_export_pubkey(bool is_p256, uint8_t *ecdsa_pub_x, uint8_t *ecdsa_pub_y, bool use_km_key) +{ + uint8_t pub_x[32] = {0}; + uint8_t pub_y[32] = {0}; + uint16_t len; + test_ecdsa_export_pubkey_inner(is_p256, pub_x, pub_y, use_km_key, &len); + + TEST_ASSERT_EQUAL_HEX8_ARRAY(ecdsa_pub_x, pub_x, len); + TEST_ASSERT_EQUAL_HEX8_ARRAY(ecdsa_pub_y, pub_y, len); + +} #endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */ @@ -322,12 +323,12 @@ TEST(ecdsa, ecdsa_SECP256R1_det_sign_and_verify) #ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY TEST(ecdsa, ecdsa_SECP192R1_export_pubkey) { - test_ecdsa_export_pubkey(0, 0); + test_ecdsa_export_pubkey(0, ecdsa192_pub_x, ecdsa192_pub_y, 0); } TEST(ecdsa, ecdsa_SECP256R1_export_pubkey) { - test_ecdsa_export_pubkey(1, 0); + test_ecdsa_export_pubkey(1, ecdsa256_pub_x, ecdsa256_pub_y, 0); } #endif /* SOC_ECDSA_SUPPORT_EXPORT_PUBKEY */ diff --git a/components/hal/test_apps/crypto/main/key_manager/gen_key_manager_test_cases.py b/components/hal/test_apps/crypto/main/key_manager/gen_key_manager_test_cases.py new file mode 100644 index 0000000000..fb2419e716 --- /dev/null +++ b/components/hal/test_apps/crypto/main/key_manager/gen_key_manager_test_cases.py @@ -0,0 +1,257 @@ +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import os +import struct +from typing import Any + +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives.ciphers import algorithms +from cryptography.hazmat.primitives.ciphers import Cipher +from cryptography.hazmat.primitives.ciphers import modes +from ecdsa.curves import NIST256p + +# Constants +TEST_COUNT = 5 + + +# Helper functions +def generate_random_key(size: int = 32) -> bytes: + return os.urandom(size) + + +def save_key_to_file(key: bytes, filename: str) -> None: + with open(filename, 'wb') as file: + file.write(key) + + +def key_from_file_or_generate(filename: str, size: int = 32) -> bytes: + if not os.path.exists(filename): + key = generate_random_key(size) + save_key_to_file(key, filename) + + with open(filename, 'rb') as file: + return file.read() + + +def key_to_c_format(key: bytes) -> str: + return ', '.join([f'0x{byte:02x}' for byte in key]) + + +def calculate_aes_cipher(data: bytes, key: bytes) -> Any: + cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend()) + encryptor = cipher.encryptor() + return encryptor.update(data) + encryptor.finalize() + + +def _flash_encryption_operation_aes_xts(input_data: bytes, flash_address: int, key: bytes, do_decrypt: bool = False) -> bytes: + backend = default_backend() + + indata = input_data + + pad_left = flash_address % 0x80 + indata = (b'\x00' * pad_left) + indata + + pad_right = (0x80 - (len(indata) % 0x80)) % 0x80 + indata += (b'\x00' * pad_right) + + inblocks = [indata[i:i + 0x80] for i in range(0, len(indata), 0x80)] + + output = b'' + for inblock in inblocks: + tweak = struct.pack(' list: + xts_test_data = [] + plaintext_data = bytes(range(1, 129)) + data_size = 16 + flash_address = base_flash_address + for i in range(TEST_COUNT): + data_size = (data_size * 2) % 256 + if (data_size < 16): + data_size = 16 + input_data = plaintext_data[:data_size] + flash_address = base_flash_address + (i * 0x100) + + ciphertext = _flash_encryption_operation_aes_xts(input_data, flash_address, key) + xts_test_data.append((data_size, flash_address, ciphertext[:data_size])) + return xts_test_data + + +def generate_ecdsa_256_key_and_pub_key(filename: str) -> tuple: + with open(filename, 'rb') as f: + private_number = int.from_bytes(f.read(), byteorder='big') + + private_key = ec.derive_private_key(private_number, ec.SECP256R1()) + pem = private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption() + ) + + with open('ecdsa_256_key.pem', 'wb') as pem_file: + pem_file.write(pem) + + public_key = private_key.public_key() + pub_numbers = public_key.public_numbers() + pubx = pub_numbers.x.to_bytes(32, byteorder='little') + puby = pub_numbers.y.to_bytes(32, byteorder='little') + + return pubx, puby + + +def perform_ecc_point_multiplication(k1_int: int) -> Any: + generator = NIST256p.generator.to_affine() + k1_G = k1_int * generator + return k1_G + + +def generate_k1_G(key_file_path: str) -> tuple: + k1_G = [] + if os.path.exists(key_file_path): + with open(key_file_path, 'rb') as key_file: + k1_bytes = key_file.read() + + k1_int = int.from_bytes(k1_bytes, byteorder='big') + k1_G_point = perform_ecc_point_multiplication(k1_int) + k1_G = k1_G_point.to_bytes()[:64] + + k1_G = k1_G[::-1] + k1_G_x = k1_G[:32] + k1_G_y = k1_G[32:] + k1_G = k1_G_y + k1_G_x + + return k1_G, k1_G + + +def write_to_c_header(init_key: bytes, k1: bytes, k2_info: bytes, k1_encrypted_32: list, + test_data_xts_aes_128: list, k1_encrypted_64: list, + xts_test_data_xts_aes_256: list, pubx: bytes, + puby: bytes, k1_G_0: bytes, k1_G_1: bytes) -> None: + with open('key_manager_test_cases.h', 'w') as file: + header_content = """#include + +#define TEST_COUNT 5 + +typedef struct test_xts_data { + uint16_t data_size; + uint32_t data_offset; + uint8_t ciphertext[128]; +} test_xts_data_t; + +typedef struct test_ecdsa_data { + uint8_t pubx[32]; + uint8_t puby[32]; +} test_ecdsa_data_t; + +typedef struct test_data { + uint8_t init_key[32]; + uint8_t k2_info[64]; + uint8_t k1_encrypted[2][32]; // For both 256-bit and 512-bit keys + uint8_t plaintext_data[128]; + test_xts_data_t xts_test_data[TEST_COUNT]; + test_ecdsa_data_t ecdsa_test_data; +} test_data_aes_mode_t; + +typedef struct test_data_ecdh0 { + uint8_t plaintext_data[128]; + uint8_t k1[2][32]; + uint8_t k1_G[2][64]; +} test_data_ecdh0_mode_t; + +// For 32-byte k1 key +test_data_aes_mode_t test_data_xts_aes_128 = { + .init_key = { %s }, + .k2_info = { %s }, + .k1_encrypted = { { %s }, { } }, + .plaintext_data = { %s }, + .xts_test_data = { +""" % (key_to_c_format(init_key), key_to_c_format(k2_info), key_to_c_format(k1_encrypted_32[0]), key_to_c_format(bytes(range(1, 129)))) + + for data_size, flash_address, ciphertext in test_data_xts_aes_128: + header_content += f'\t\t{{.data_size = {data_size}, .data_offset = 0x{flash_address:x}, .ciphertext = {{{key_to_c_format(ciphertext)}}}}},\n' + header_content += '\t}\n};\n\n' + + # For 64-byte k1 key + header_content += '// For 64-byte k1 key\n' + header_content += 'test_data_aes_mode_t test_data_xts_aes_256 = {\n' + header_content += f'\t.init_key = {{{key_to_c_format(init_key)}}},\n' + header_content += f'\t.k2_info = {{{key_to_c_format(k2_info)}}},\n' + header_content += f'\t.k1_encrypted = {{{{{key_to_c_format(k1_encrypted_64[0])}}}, {{{key_to_c_format(k1_encrypted_64[1])}}}}},\n' + header_content += f'\t.plaintext_data = {{{key_to_c_format(bytes(range(1, 129)))}}},\n' + header_content += ' .xts_test_data = {\n' + + for data_size, flash_address, ciphertext in xts_test_data_xts_aes_256: + header_content += f' {{.data_size = {data_size}, .data_offset = 0x{flash_address:x}, .ciphertext = {{{key_to_c_format(ciphertext)}}}}},\n' + header_content += ' }\n};\n' + header_content += ''' +test_data_aes_mode_t test_data_ecdsa = { + .init_key = { %s }, + .k2_info = { %s }, + .k1_encrypted = { { %s }, { } }, + .ecdsa_test_data = { + .pubx = { %s }, + .puby = { %s } + } +};\n +''' % (key_to_c_format(init_key), key_to_c_format(k2_info), key_to_c_format(k1_encrypted_32[0]), key_to_c_format(pubx),key_to_c_format(puby)) + header_content += ''' +test_data_ecdh0_mode_t test_data_ecdh0 = { + .plaintext_data = { %s }, + .k1 = { + { %s }, + { %s }, + }, + .k1_G = { + { %s }, + { %s }, + } +};\n + +''' % (key_to_c_format(bytes(range(1, 129))), key_to_c_format(k1), key_to_c_format(k1), key_to_c_format(k1_G_0), key_to_c_format(k1_G_1)) + + file.write(header_content) + + +# Main script logic follows as per your provided structure +init_key = key_from_file_or_generate('init_key.bin', 32) +k2 = key_from_file_or_generate('k2.bin', 32) +rand_num = key_from_file_or_generate('rand_num.bin', 32) + +temp_result_inner = calculate_aes_cipher(k2, rand_num) +temp_result_outer = calculate_aes_cipher(temp_result_inner + rand_num, init_key) +k2_info = temp_result_outer + +k1_32 = key_from_file_or_generate('k1.bin', 32) +k1_64 = key_from_file_or_generate('k1_64.bin', 64) + +k1_32_reversed = k1_32[::-1] + +k1_64_reversed = k1_64[::-1] + +k1_64_1 = k1_64[:32] +k1_64_1_reversed = k1_64_1[::-1] +k1_64_2 = k1_64[32:] +k1_64_2_reversed = k1_64_2[::-1] + +k1_encrypted_32 = [calculate_aes_cipher(k1_32_reversed, k2)] +k1_encrypted_64 = [calculate_aes_cipher(k1_64_1_reversed, k2), calculate_aes_cipher(k1_64_2_reversed, k2)] + +test_data_xts_aes_128 = generate_xts_test_data(k1_32) +xts_test_data_xts_aes_256 = generate_xts_test_data(k1_64) + +pubx, puby = generate_ecdsa_256_key_and_pub_key('k1.bin') + +k1_G_0, k1_G_1 = generate_k1_G('k1.bin') + +write_to_c_header(init_key, k1_32, k2_info, k1_encrypted_32, test_data_xts_aes_128, k1_encrypted_64, xts_test_data_xts_aes_256, pubx, puby, k1_G_0, k1_G_1) diff --git a/components/hal/test_apps/crypto/main/key_manager/key_manager_test_cases.h b/components/hal/test_apps/crypto/main/key_manager/key_manager_test_cases.h new file mode 100644 index 0000000000..6a7a2abf7a --- /dev/null +++ b/components/hal/test_apps/crypto/main/key_manager/key_manager_test_cases.h @@ -0,0 +1,87 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include + +#define TEST_COUNT 5 + +typedef struct test_xts_data { + uint16_t data_size; + uint32_t data_offset; + uint8_t ciphertext[128]; +} test_xts_data_t; + +typedef struct test_ecdsa_data { + uint8_t pubx[32]; + uint8_t puby[32]; +} test_ecdsa_data_t; + +typedef struct test_data { + uint8_t init_key[32]; + uint8_t k2_info[64]; + uint8_t k1_encrypted[2][32]; // For both 256-bit and 512-bit keys + uint8_t plaintext_data[128]; + test_xts_data_t xts_test_data[TEST_COUNT]; + test_ecdsa_data_t ecdsa_test_data; +} test_data_aes_mode_t; + +typedef struct test_data_ecdh0 { + uint8_t plaintext_data[128]; + uint8_t k1[2][32]; + uint8_t k1_G[2][64]; +} test_data_ecdh0_mode_t; + +// For 32-byte k1 key +test_data_aes_mode_t test_data_xts_aes_128 = { + .init_key = { 0x4d, 0x21, 0x64, 0x21, 0x8f, 0xa2, 0xe3, 0xa0, 0xab, 0x74, 0xb5, 0xab, 0x17, 0x9a, 0x5d, 0x08, 0x58, 0xf4, 0x22, 0x03, 0xbd, 0x52, 0xe7, 0x88, 0x3c, 0x22, 0x0f, 0x95, 0x89, 0x70, 0xe1, 0x93 }, + .k2_info = { 0xd8, 0xcd, 0x04, 0x45, 0xb4, 0x45, 0xc4, 0x15, 0xf6, 0x40, 0x1c, 0x7d, 0x90, 0x1b, 0x99, 0xa4, 0x79, 0x6b, 0xfb, 0x5b, 0x2a, 0x40, 0x60, 0xe1, 0xc1, 0xe1, 0x48, 0xcd, 0x46, 0x6b, 0x9b, 0x48, 0xda, 0x7a, 0x70, 0x0a, 0x78, 0x0b, 0x9d, 0xf9, 0x0e, 0xed, 0x91, 0xfc, 0xa5, 0xc2, 0x96, 0x05, 0x91, 0x76, 0xdb, 0x68, 0x84, 0x5d, 0x5e, 0x5b, 0xa6, 0xe9, 0x6b, 0x3b, 0x12, 0x50, 0x05, 0xc3 }, + .k1_encrypted = { { 0xeb, 0x83, 0x24, 0x7d, 0xf8, 0x40, 0xc9, 0x88, 0x5f, 0x5e, 0x58, 0x57, 0x25, 0xa9, 0x23, 0x4a, 0xa4, 0xc4, 0x12, 0x17, 0xf3, 0x9e, 0x1f, 0xa0, 0xa0, 0xfa, 0xd5, 0xbf, 0xb6, 0x6c, 0xb5, 0x48 }, { } }, + .plaintext_data = { 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, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80 }, + .xts_test_data = { + {.data_size = 32, .data_offset = 0x120000, .ciphertext = {0xe7, 0xf3, 0xb4, 0x51, 0xc6, 0x62, 0x8e, 0x25, 0x10, 0x12, 0xc2, 0x09, 0x82, 0x7b, 0x3e, 0x9a, 0x78, 0xe2, 0x00, 0x9a, 0x96, 0x02, 0x50, 0xeb, 0xff, 0xf1, 0xf8, 0x0d, 0xf6, 0xa6, 0xb8, 0xa1}}, + {.data_size = 64, .data_offset = 0x120100, .ciphertext = {0x3b, 0x54, 0xa8, 0x58, 0xe2, 0x63, 0x7a, 0xb0, 0x7c, 0xc7, 0x37, 0xd8, 0x1e, 0x89, 0x1e, 0x25, 0x39, 0x3d, 0x0d, 0x18, 0x14, 0xb3, 0x2e, 0x18, 0x15, 0xf6, 0xbd, 0xf8, 0xb6, 0x5f, 0x6b, 0x89, 0x1a, 0x0a, 0x53, 0x36, 0xf1, 0x5b, 0x1b, 0x18, 0xd3, 0xf4, 0x7b, 0xd5, 0xcd, 0x4f, 0x48, 0x7b, 0x11, 0xcf, 0xad, 0x6b, 0x79, 0x36, 0x1b, 0xda, 0x5a, 0xd3, 0x18, 0x44, 0xa0, 0xf3, 0xf2, 0xad}}, + {.data_size = 128, .data_offset = 0x120200, .ciphertext = {0x6b, 0x42, 0x10, 0x9f, 0x67, 0x72, 0x31, 0xc7, 0x8f, 0x63, 0xde, 0xc1, 0xf9, 0x84, 0x37, 0x74, 0xe5, 0x5a, 0xe4, 0x31, 0x1a, 0x2e, 0x45, 0x6b, 0xb5, 0xd4, 0xd0, 0x41, 0xe1, 0x2c, 0x0a, 0x43, 0xd9, 0x4c, 0xd5, 0x1c, 0x34, 0xc9, 0x29, 0x39, 0xc8, 0x09, 0xc3, 0xcd, 0x99, 0xaf, 0x3a, 0xe6, 0x4d, 0xae, 0xce, 0xfd, 0x0a, 0xd4, 0x8f, 0x81, 0x4c, 0x25, 0xc5, 0x5e, 0x3d, 0x82, 0x3d, 0x58, 0x55, 0xe5, 0xa4, 0xe4, 0x13, 0x2b, 0xa0, 0x04, 0x3a, 0x7a, 0x65, 0xfa, 0x7a, 0xfb, 0x28, 0x36, 0x1e, 0xfa, 0x71, 0x50, 0x80, 0xa5, 0x0c, 0xa6, 0x4e, 0x45, 0xf9, 0xd9, 0x05, 0xc1, 0x63, 0xa1, 0xf2, 0x7f, 0x54, 0x62, 0xf1, 0x5a, 0xe2, 0x5a, 0x5c, 0x06, 0x16, 0x71, 0xa9, 0x5f, 0xab, 0x7d, 0xc9, 0x85, 0x68, 0xc5, 0x3a, 0xfe, 0xc1, 0xe0, 0xc9, 0xc3, 0xd4, 0x33, 0x10, 0x89, 0x5e, 0x43}}, + {.data_size = 16, .data_offset = 0x120300, .ciphertext = {0xbe, 0xd7, 0x01, 0x8a, 0x60, 0xab, 0x0c, 0xb7, 0xb6, 0x14, 0x9e, 0x64, 0xbc, 0xca, 0xda, 0xaa}}, + {.data_size = 32, .data_offset = 0x120400, .ciphertext = {0xda, 0x84, 0x17, 0x3d, 0x4c, 0x85, 0x07, 0xe2, 0x56, 0x98, 0x69, 0x33, 0x1b, 0x9a, 0x01, 0x9e, 0x6c, 0x81, 0xd8, 0x90, 0x9e, 0x59, 0x92, 0x12, 0x6d, 0xba, 0x58, 0x09, 0x90, 0xe6, 0x50, 0x33}}, + } +}; + +// For 64-byte k1 key +test_data_aes_mode_t test_data_xts_aes_256 = { + .init_key = {0x4d, 0x21, 0x64, 0x21, 0x8f, 0xa2, 0xe3, 0xa0, 0xab, 0x74, 0xb5, 0xab, 0x17, 0x9a, 0x5d, 0x08, 0x58, 0xf4, 0x22, 0x03, 0xbd, 0x52, 0xe7, 0x88, 0x3c, 0x22, 0x0f, 0x95, 0x89, 0x70, 0xe1, 0x93}, + .k2_info = {0xd8, 0xcd, 0x04, 0x45, 0xb4, 0x45, 0xc4, 0x15, 0xf6, 0x40, 0x1c, 0x7d, 0x90, 0x1b, 0x99, 0xa4, 0x79, 0x6b, 0xfb, 0x5b, 0x2a, 0x40, 0x60, 0xe1, 0xc1, 0xe1, 0x48, 0xcd, 0x46, 0x6b, 0x9b, 0x48, 0xda, 0x7a, 0x70, 0x0a, 0x78, 0x0b, 0x9d, 0xf9, 0x0e, 0xed, 0x91, 0xfc, 0xa5, 0xc2, 0x96, 0x05, 0x91, 0x76, 0xdb, 0x68, 0x84, 0x5d, 0x5e, 0x5b, 0xa6, 0xe9, 0x6b, 0x3b, 0x12, 0x50, 0x05, 0xc3}, + .k1_encrypted = {{0xeb, 0x83, 0x24, 0x7d, 0xf8, 0x40, 0xc9, 0x88, 0x5f, 0x5e, 0x58, 0x57, 0x25, 0xa9, 0x23, 0x4a, 0xa4, 0xc4, 0x12, 0x17, 0xf3, 0x9e, 0x1f, 0xa0, 0xa0, 0xfa, 0xd5, 0xbf, 0xb6, 0x6c, 0xb5, 0x48}, {0x65, 0x9e, 0x12, 0x7f, 0xc0, 0x4a, 0xb6, 0x04, 0xa1, 0xd0, 0x38, 0x04, 0x6c, 0x8e, 0x1f, 0xc7, 0x03, 0x24, 0x3e, 0x75, 0x3c, 0x9d, 0x7a, 0xc2, 0xef, 0xd6, 0xf2, 0x60, 0x46, 0xfc, 0x07, 0x3f}}, + .plaintext_data = {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, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80}, + .xts_test_data = { + {.data_size = 32, .data_offset = 0x120000, .ciphertext = {0x9b, 0xd8, 0x2b, 0xc6, 0xae, 0xcc, 0x9d, 0x0c, 0x38, 0x30, 0x85, 0x6a, 0x2b, 0x22, 0x2e, 0x34, 0x9f, 0xa2, 0xcd, 0xe8, 0xec, 0xe3, 0xc4, 0x21, 0xfe, 0xbb, 0x4a, 0x55, 0xf2, 0x4a, 0xe2, 0x14}}, + {.data_size = 64, .data_offset = 0x120100, .ciphertext = {0x1e, 0x36, 0x3f, 0xf6, 0xd6, 0x52, 0x34, 0xce, 0xc3, 0x58, 0x15, 0xa1, 0x15, 0x6f, 0x3d, 0x66, 0xa7, 0x90, 0x14, 0x71, 0xbb, 0x6d, 0x7e, 0x93, 0xf2, 0x4d, 0x5d, 0x74, 0xb2, 0xd7, 0x77, 0x32, 0x2e, 0x31, 0x16, 0x28, 0xd2, 0x10, 0x65, 0x81, 0x49, 0xc0, 0x56, 0xf0, 0x6d, 0x71, 0x5b, 0xc2, 0xf2, 0x01, 0x04, 0xbf, 0x97, 0x77, 0xe6, 0x57, 0xe5, 0xb5, 0xad, 0x73, 0xc0, 0x76, 0x91, 0xb6}}, + {.data_size = 128, .data_offset = 0x120200, .ciphertext = {0xcf, 0x7d, 0xdd, 0x69, 0x69, 0xf4, 0x3b, 0xcd, 0x65, 0x5d, 0xcf, 0xfc, 0xff, 0xd3, 0x45, 0x1c, 0x51, 0xab, 0x2e, 0x26, 0x5c, 0xdc, 0x5b, 0x5a, 0x6e, 0xbb, 0x18, 0x36, 0x55, 0xbe, 0xe7, 0x30, 0x7a, 0x07, 0x48, 0xd8, 0x1a, 0x34, 0xdc, 0xa6, 0x1e, 0xd6, 0x67, 0xa8, 0x90, 0xc3, 0xac, 0x26, 0x7a, 0x52, 0x67, 0x82, 0x71, 0xc9, 0x80, 0x8d, 0xed, 0x20, 0x83, 0x34, 0x10, 0x8e, 0xe5, 0x84, 0x81, 0xa5, 0xe2, 0x42, 0xf0, 0x53, 0xef, 0x93, 0x00, 0xfe, 0xbd, 0x74, 0x14, 0xac, 0x92, 0x37, 0x00, 0x45, 0xd5, 0x71, 0x29, 0xaf, 0x8b, 0x83, 0xe2, 0x20, 0x2e, 0xd0, 0xf6, 0xaa, 0x45, 0x9a, 0x6f, 0x59, 0xb9, 0x8d, 0xef, 0xcd, 0xb6, 0xf6, 0x25, 0x99, 0xd2, 0x32, 0x2e, 0x90, 0x8a, 0x3a, 0x5d, 0xd8, 0x3f, 0xbf, 0x84, 0x80, 0x89, 0xaa, 0x9c, 0xa8, 0x57, 0xc9, 0x1c, 0xc4, 0xaa, 0x64}}, + {.data_size = 16, .data_offset = 0x120300, .ciphertext = {0x1b, 0x7a, 0xf1, 0x35, 0x33, 0x22, 0x64, 0x74, 0x06, 0x6a, 0xc1, 0x0c, 0x39, 0xee, 0x1f, 0x9f}}, + {.data_size = 32, .data_offset = 0x120400, .ciphertext = {0x94, 0xd9, 0x01, 0x0f, 0xec, 0xcc, 0xb5, 0x22, 0x50, 0x8b, 0x8a, 0x3d, 0x01, 0x18, 0x29, 0xda, 0x53, 0x9b, 0xcf, 0x64, 0xac, 0x4f, 0x7b, 0x97, 0xf3, 0xff, 0xfd, 0x33, 0x96, 0x8a, 0xde, 0x27}}, + } +}; + +test_data_aes_mode_t test_data_ecdsa = { + .init_key = { 0x4d, 0x21, 0x64, 0x21, 0x8f, 0xa2, 0xe3, 0xa0, 0xab, 0x74, 0xb5, 0xab, 0x17, 0x9a, 0x5d, 0x08, 0x58, 0xf4, 0x22, 0x03, 0xbd, 0x52, 0xe7, 0x88, 0x3c, 0x22, 0x0f, 0x95, 0x89, 0x70, 0xe1, 0x93 }, + .k2_info = { 0xd8, 0xcd, 0x04, 0x45, 0xb4, 0x45, 0xc4, 0x15, 0xf6, 0x40, 0x1c, 0x7d, 0x90, 0x1b, 0x99, 0xa4, 0x79, 0x6b, 0xfb, 0x5b, 0x2a, 0x40, 0x60, 0xe1, 0xc1, 0xe1, 0x48, 0xcd, 0x46, 0x6b, 0x9b, 0x48, 0xda, 0x7a, 0x70, 0x0a, 0x78, 0x0b, 0x9d, 0xf9, 0x0e, 0xed, 0x91, 0xfc, 0xa5, 0xc2, 0x96, 0x05, 0x91, 0x76, 0xdb, 0x68, 0x84, 0x5d, 0x5e, 0x5b, 0xa6, 0xe9, 0x6b, 0x3b, 0x12, 0x50, 0x05, 0xc3 }, + .k1_encrypted = { { 0xeb, 0x83, 0x24, 0x7d, 0xf8, 0x40, 0xc9, 0x88, 0x5f, 0x5e, 0x58, 0x57, 0x25, 0xa9, 0x23, 0x4a, 0xa4, 0xc4, 0x12, 0x17, 0xf3, 0x9e, 0x1f, 0xa0, 0xa0, 0xfa, 0xd5, 0xbf, 0xb6, 0x6c, 0xb5, 0x48 }, { } }, + .ecdsa_test_data = { + .pubx = { 0x8f, 0xc2, 0x37, 0x2e, 0x36, 0x77, 0x8f, 0xc7, 0x59, 0x18, 0xec, 0x39, 0x23, 0x16, 0x6b, 0x0b, 0x4f, 0xf8, 0x19, 0xa8, 0x9f, 0xd9, 0xf7, 0x59, 0x4d, 0x8a, 0x2d, 0x16, 0xd5, 0x84, 0xe1, 0x21 }, + .puby = { 0xf1, 0x8b, 0x1e, 0x2d, 0x7e, 0xc4, 0x8b, 0xf8, 0xe3, 0xc9, 0xb1, 0x54, 0xa4, 0x65, 0xed, 0x7d, 0xbc, 0x56, 0x1a, 0x66, 0xcd, 0x43, 0x10, 0x2e, 0x46, 0x2a, 0x3f, 0xfe, 0xdb, 0x9a, 0x28, 0xf9 } + } +}; + + +test_data_ecdh0_mode_t test_data_ecdh0 = { + .plaintext_data = { 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, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80 }, + .k1 = { + { 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 }, + { 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 }, + }, + .k1_G = { + { 0x8f, 0xc2, 0x37, 0x2e, 0x36, 0x77, 0x8f, 0xc7, 0x59, 0x18, 0xec, 0x39, 0x23, 0x16, 0x6b, 0x0b, 0x4f, 0xf8, 0x19, 0xa8, 0x9f, 0xd9, 0xf7, 0x59, 0x4d, 0x8a, 0x2d, 0x16, 0xd5, 0x84, 0xe1, 0x21, 0xf1, 0x8b, 0x1e, 0x2d, 0x7e, 0xc4, 0x8b, 0xf8, 0xe3, 0xc9, 0xb1, 0x54, 0xa4, 0x65, 0xed, 0x7d, 0xbc, 0x56, 0x1a, 0x66, 0xcd, 0x43, 0x10, 0x2e, 0x46, 0x2a, 0x3f, 0xfe, 0xdb, 0x9a, 0x28, 0xf9 }, + { 0x8f, 0xc2, 0x37, 0x2e, 0x36, 0x77, 0x8f, 0xc7, 0x59, 0x18, 0xec, 0x39, 0x23, 0x16, 0x6b, 0x0b, 0x4f, 0xf8, 0x19, 0xa8, 0x9f, 0xd9, 0xf7, 0x59, 0x4d, 0x8a, 0x2d, 0x16, 0xd5, 0x84, 0xe1, 0x21, 0xf1, 0x8b, 0x1e, 0x2d, 0x7e, 0xc4, 0x8b, 0xf8, 0xe3, 0xc9, 0xb1, 0x54, 0xa4, 0x65, 0xed, 0x7d, 0xbc, 0x56, 0x1a, 0x66, 0xcd, 0x43, 0x10, 0x2e, 0x46, 0x2a, 0x3f, 0xfe, 0xdb, 0x9a, 0x28, 0xf9 }, + } +}; diff --git a/components/hal/test_apps/crypto/main/key_manager/test_key_manager.c b/components/hal/test_apps/crypto/main/key_manager/test_key_manager.c new file mode 100644 index 0000000000..ca424eb132 --- /dev/null +++ b/components/hal/test_apps/crypto/main/key_manager/test_key_manager.c @@ -0,0 +1,374 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include +#include + +#include "esp_efuse_chip.h" +#include "esp_heap_caps.h" +#include "esp_rom_crc.h" +#include "hal/key_mgr_hal.h" +#include "hal/key_mgr_ll.h" +#include "hal/key_mgr_types.h" +#include "hal/huk_types.h" +#include "hal/huk_hal.h" +#include "esp_key_mgr.h" +#include "memory_checks.h" +#include "unity_fixture.h" +#include "hal_crypto_common.h" +#include "rom/key_mgr.h" +#include "esp_partition.h" +#include "esp_flash.h" +#include "key_manager_test_cases.h" +#include "esp_log.h" + +// For ECDSA tests +#include "hal/ecdsa_hal.h" + +const esp_partition_t *get_test_storage_partition(void) +{ + /* This finds "storage" partition defined partition table */ + const esp_partition_t *result = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, + ESP_PARTITION_SUBTYPE_ANY, "storage"); + if (!result) { + /* means partition table set wrong */ + printf("ERROR in obtaining storage partition"); + return NULL; + } + return result; +} + +static void print_data_in_hex(const uint8_t *data, int size, const char *info_str) +{ + printf("%s: 0x", info_str); + for(int i = 0 ; i < size; i++) { + printf("%02x", data[i]); + } + printf("\n"); +} + +static void test_xts_aes_key_aes_mode(test_data_aes_mode_t *test_data) +{ + const esp_partition_t *partition = get_test_storage_partition(); + ESP_ERROR_CHECK(esp_partition_erase_range(partition, 0, partition->size)); + + for (int i = 0; i < TEST_COUNT; i++) { + uint32_t address = test_data->xts_test_data[i].data_offset; + uint32_t data_size = test_data->xts_test_data[i].data_size; + ESP_ERROR_CHECK(esp_flash_write_encrypted(NULL, address, test_data->plaintext_data, data_size)); + static uint8_t read_data[128]; + ESP_ERROR_CHECK(esp_flash_read(NULL, read_data, address, data_size)); + TEST_ASSERT_EQUAL_HEX8_ARRAY(test_data->xts_test_data[i].ciphertext, read_data, data_size); + } +} + +static void test_xts_aes_key_ecdh0_mode(test_data_ecdh0_mode_t *test_data) +{ + const esp_partition_t *partition = get_test_storage_partition(); + ESP_ERROR_CHECK(esp_partition_erase_range(partition, 0, partition->size)); + + uint32_t address = partition->address; + uint32_t data_size = 32; + + print_data_in_hex(test_data->plaintext_data, data_size, "Plaintext data"); + + ESP_ERROR_CHECK(esp_flash_write_encrypted(NULL, address, test_data->plaintext_data, data_size)); + static uint8_t read_data[128]; + ESP_ERROR_CHECK(esp_flash_read(NULL, read_data, address, data_size)); + print_data_in_hex(read_data, data_size, "Encrypted data"); +} + +static void key_mgr_test_xts_aes_128(void) +{ + static esp_key_mgr_aes_key_config_t key_config; + memcpy(key_config.k2_info, (uint8_t*) test_data_xts_aes_128.k2_info, KEY_MGR_K2_INFO_SIZE); + memcpy(key_config.k1_encrypted, (uint8_t*) test_data_xts_aes_128.k1_encrypted, KEY_MGR_K1_ENCRYPTED_SIZE); + memcpy(key_config.sw_init_key, (uint8_t*) test_data_xts_aes_128.init_key, KEY_MGR_SW_INIT_KEY_SIZE); + key_config.use_pre_generated_sw_init_key = 1; + key_config.key_type = ESP_KEY_MGR_XTS_AES_128_KEY; + + static esp_key_mgr_key_recovery_info_t key_recovery_info; + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deploy_key_in_aes_mode(&key_config, &key_recovery_info)); + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_activate_key(&key_recovery_info)); + test_xts_aes_key_aes_mode(&test_data_xts_aes_128); + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deactivate_key(key_recovery_info.key_type)); + +} + +static void key_mgr_test_xts_aes_256_aes_mode(void) +{ + static esp_key_mgr_aes_key_config_t key_config; + memcpy(key_config.k2_info, (uint8_t*) test_data_xts_aes_256.k2_info, KEY_MGR_K2_INFO_SIZE); + memcpy(key_config.k1_encrypted[0], (uint8_t*) test_data_xts_aes_256.k1_encrypted[0], KEY_MGR_K1_ENCRYPTED_SIZE); + memcpy(key_config.k1_encrypted[1], (uint8_t*) test_data_xts_aes_256.k1_encrypted[1], KEY_MGR_K1_ENCRYPTED_SIZE); + memcpy(key_config.sw_init_key, (uint8_t*) test_data_xts_aes_256.init_key, KEY_MGR_SW_INIT_KEY_SIZE); + key_config.use_pre_generated_sw_init_key = 1; + key_config.key_type = ESP_KEY_MGR_XTS_AES_256_KEY; + + static esp_key_mgr_key_recovery_info_t key_recovery_info; + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deploy_key_in_aes_mode(&key_config, &key_recovery_info)); + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_activate_key(&key_recovery_info)); + test_xts_aes_key_aes_mode(&test_data_xts_aes_256); + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deactivate_key(key_recovery_info.key_type)); +} + +#ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY +extern void test_ecdsa_export_pubkey(bool is_p256, uint8_t *ecdsa_pub_x, uint8_t *ecdsa_pub_y, bool use_km_key); +extern void test_ecdsa_export_pubkey_inner(bool is_p256, uint8_t *exported_pub_x, uint8_t *exported_pub_y, bool use_km_key, uint16_t *len); +#endif + +extern void test_ecdsa_sign_and_verify(bool is_p256, uint8_t* sha, uint8_t* pub_x, uint8_t* pub_y, bool use_km_key, ecdsa_sign_type_t k_type); + +/* +const uint8_t message[32] = { 0xDF, 0xDE, 0xD7, 0x4A, 0x47, 0xB1, 0x4F, 0x73, 0x00, 0x21, 0x62, 0xC7, 0x66, 0x6D, 0xA3, 0x95, 0x66, 0x19, 0x62, 0x7F, 0x71, 0x7B, 0x3C, 0x66, 0x82, 0xD3, 0x9F, 0x71, 0xAC, 0x9C, 0xC3, 0x39 }; +*/ + +/* sha256 digest of the above message */ +uint8_t sha256_digest[32] = { 0x47, 0xA6, 0xEF, 0xBE, 0x39, 0x5E, 0xE4, 0xAE, 0x2B, 0xEC, 0x83, 0xB1, 0xED, 0xAF, 0xC6, 0x78, 0x57, 0x7A, 0x16, 0x8C, 0x22, 0x16, 0x13, 0xE2, 0xAC, 0xA8, 0x50, 0xD5, 0x67, 0x95, 0x9F, 0x71 }; + +void test_ecdsa_key_aes_mode(test_data_aes_mode_t *ecdsa_test_data, ecdsa_sign_type_t k_type) +{ + test_ecdsa_sign_and_verify(1, sha256_digest, ecdsa_test_data->ecdsa_test_data.pubx, ecdsa_test_data->ecdsa_test_data.puby, 1, k_type); +#ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY + test_ecdsa_export_pubkey(1, ecdsa_test_data->ecdsa_test_data.pubx, ecdsa_test_data->ecdsa_test_data.puby, 1); +#endif +} + + +extern void test_ecdsa_sign(bool is_p256, uint8_t* sha, uint8_t* r_le, uint8_t* s_le, bool use_km_key, ecdsa_sign_type_t k_type); + +extern int test_ecdsa_verify(bool is_p256, uint8_t* sha, uint8_t* r_le, uint8_t* s_le, uint8_t *pub_x, uint8_t *pub_y); + +void key_mgr_test_ecdsa_key(bool is_p256, ecdsa_sign_type_t k_type) +{ + uint8_t pub_x[32] = {}; + uint8_t pub_y[32] = {}; + uint8_t r_le[32] = {0}; + uint8_t s_le[32] = {0}; + + test_ecdsa_sign(is_p256, sha256_digest, r_le, s_le, 1, k_type); + + print_data_in_hex(sha256_digest, sizeof(sha256_digest), "ECDSA message sha256 digest"); + print_data_in_hex(r_le, sizeof(r_le), "ECDSA signature r_le"); + print_data_in_hex(s_le, sizeof(s_le), "ECDSA signature s_le"); + + // Export the pubkey from ECDSA peripheral + uint16_t pubkey_len = 0; + test_ecdsa_export_pubkey_inner(is_p256, pub_x, pub_y, 1, &pubkey_len); + + print_data_in_hex(pub_x, pubkey_len, "ECDSA key pubx"); + print_data_in_hex(pub_y, pubkey_len, "ECDSA key puby"); + TEST_ASSERT_EQUAL(0, test_ecdsa_verify(is_p256, sha256_digest, r_le, s_le, pub_x, pub_y)); + +} + +static void key_mgr_test_ecdsa_p256_aes_mode(void) +{ + static esp_key_mgr_aes_key_config_t key_config; + memcpy(key_config.k2_info, (uint8_t*) test_data_ecdsa.k2_info, KEY_MGR_K2_INFO_SIZE); + memcpy(key_config.k1_encrypted, (uint8_t*) test_data_ecdsa.k1_encrypted, KEY_MGR_K1_ENCRYPTED_SIZE); + memcpy(key_config.sw_init_key, (uint8_t*) test_data_ecdsa.init_key, KEY_MGR_SW_INIT_KEY_SIZE); + key_config.use_pre_generated_sw_init_key = 1; + key_config.key_type = ESP_KEY_MGR_ECDSA_KEY; + + static esp_key_mgr_key_recovery_info_t key_recovery_info; + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deploy_key_in_aes_mode(&key_config, &key_recovery_info)); + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_activate_key(&key_recovery_info)); +#ifdef SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE + test_ecdsa_key_aes_mode(&test_data_ecdsa, ECDSA_K_TYPE_DETERMINISITIC); +#endif + test_ecdsa_key_aes_mode(&test_data_ecdsa, ECDSA_K_TYPE_TRNG); + + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deactivate_key(key_recovery_info.key_type)); +} + +static void key_mgr_test_xts_aes_128_ecdh0_mode(void) +{ + printf("\nKey Manager ECDH0 deployment: XTS_AES_128 key\n"); + static esp_key_mgr_ecdh0_key_config_t key_config; + memcpy(key_config.k1_G[0], (uint8_t*) test_data_ecdh0.k1_G[0], KEY_MGR_ECDH0_INFO_SIZE); + key_config.key_type = ESP_KEY_MGR_XTS_AES_128_KEY; + + static esp_key_mgr_key_recovery_info_t key_recovery_info; + static esp_key_mgr_ecdh0_info_t ecdh0_info; + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deploy_key_in_ecdh0_mode(&key_config, &key_recovery_info, &ecdh0_info)); + + print_data_in_hex(ecdh0_info.k2_G[0], KEY_MGR_ECDH0_INFO_SIZE, "K2_G"); + + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_activate_key(&key_recovery_info)); + test_xts_aes_key_ecdh0_mode(&test_data_ecdh0); + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deactivate_key(key_recovery_info.key_type)); +} + +static void key_mgr_test_xts_aes_256_ecdh0_mode(void) +{ + printf("\nKey Manager ECDH0 deployment: XTS_AES_256 key\n"); + static esp_key_mgr_ecdh0_key_config_t key_config; + memcpy(key_config.k1_G[0], (uint8_t*) test_data_ecdh0.k1_G[0], KEY_MGR_ECDH0_INFO_SIZE); + memcpy(key_config.k1_G[1], (uint8_t*) test_data_ecdh0.k1_G[1], KEY_MGR_ECDH0_INFO_SIZE); + key_config.key_type = ESP_KEY_MGR_XTS_AES_256_KEY; + + static esp_key_mgr_key_recovery_info_t key_recovery_info; + static esp_key_mgr_ecdh0_info_t ecdh0_info; + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deploy_key_in_ecdh0_mode(&key_config, &key_recovery_info, &ecdh0_info)); + + print_data_in_hex(ecdh0_info.k2_G[0], KEY_MGR_ECDH0_INFO_SIZE, "K2_G_0"); + print_data_in_hex(ecdh0_info.k2_G[1], KEY_MGR_ECDH0_INFO_SIZE, "K2_G_1"); + + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_activate_key(&key_recovery_info)); + test_xts_aes_key_ecdh0_mode(&test_data_ecdh0); + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deactivate_key(key_recovery_info.key_type)); +} + +static void key_mgr_test_ecdsa_ecdh0_mode(void) +{ + printf("\nKey Manager ECDH0 deployment: ECDSA_256 key\n"); + static esp_key_mgr_ecdh0_key_config_t key_config; + memcpy(key_config.k1_G[0], (uint8_t*) test_data_ecdh0.k1_G[0], KEY_MGR_ECDH0_INFO_SIZE); + key_config.key_type = ESP_KEY_MGR_ECDSA_KEY; + + static esp_key_mgr_key_recovery_info_t key_recovery_info; + static esp_key_mgr_ecdh0_info_t ecdh0_info; + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deploy_key_in_ecdh0_mode(&key_config, &key_recovery_info, &ecdh0_info)); + + print_data_in_hex(ecdh0_info.k2_G[0], KEY_MGR_ECDH0_INFO_SIZE, "K2_G"); + + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_activate_key(&key_recovery_info)); +#ifdef SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE + key_mgr_test_ecdsa_key(1, ECDSA_K_TYPE_DETERMINISITIC); +#endif + key_mgr_test_ecdsa_key(1, ECDSA_K_TYPE_TRNG); + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deactivate_key(key_recovery_info.key_type)); +} + +static void key_mgr_test_ecdsa_random_mode(void) +{ + printf("\nKey Manager Random deployment: ECDSA_256 key\n"); + static esp_key_mgr_random_key_config_t key_config; + key_config.key_type = ESP_KEY_MGR_ECDSA_KEY; + + static esp_key_mgr_key_recovery_info_t key_recovery_info; + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deploy_key_in_random_mode(&key_config, &key_recovery_info)); + + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_activate_key(&key_recovery_info)); + +#ifdef SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE + key_mgr_test_ecdsa_key(1, ECDSA_K_TYPE_DETERMINISITIC); +#endif + key_mgr_test_ecdsa_key(1, ECDSA_K_TYPE_TRNG); + + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deactivate_key(key_recovery_info.key_type)); +} + +#if CONFIG_IDF_ENV_FPGA + +static void test_xts_aes_key_random_mode(void) +{ + const esp_partition_t *partition = get_test_storage_partition(); + ESP_ERROR_CHECK(esp_partition_erase_range(partition, 0, partition->size)); + uint8_t plaintext_data[1024] = {[0 ... 1023] = 0xBE}; + const int write_size = 16; + for (int i = 0; i < sizeof(plaintext_data) / write_size; i++) { + printf("\n i = %d\n", i); + ESP_ERROR_CHECK(esp_flash_write_encrypted(NULL, partition->address + (i * write_size), plaintext_data, write_size)); + static uint8_t read_data[128]; + ESP_ERROR_CHECK(esp_partition_read(partition, write_size * i, read_data, write_size)); + TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext_data + (i * write_size), read_data, write_size); + } +} + + +static void key_mgr_test_xts_aes_128_random_mode(void) +{ + static esp_key_mgr_random_key_config_t key_config; + key_config.key_type = ESP_KEY_MGR_XTS_AES_128_KEY; + + static esp_key_mgr_key_recovery_info_t key_recovery_info; + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deploy_key_in_random_mode(&key_config, &key_recovery_info)); + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_activate_key(&key_recovery_info)); + test_xts_aes_key_random_mode(); + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deactivate_key(key_recovery_info.key_type)); + +} + +static void key_mgr_test_xts_aes_256_random_mode(void) +{ + static esp_key_mgr_random_key_config_t key_config; + key_config.key_type = ESP_KEY_MGR_XTS_AES_256_KEY; + static esp_key_mgr_key_recovery_info_t key_recovery_info; + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deploy_key_in_random_mode(&key_config, &key_recovery_info)); + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_activate_key(&key_recovery_info)); + test_xts_aes_key_random_mode(); + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deactivate_key(key_recovery_info.key_type)); +} +#endif + +TEST_GROUP(key_manager); + +TEST_SETUP(key_manager) +{ + test_utils_record_free_mem(); + TEST_ESP_OK(test_utils_set_leak_level(700, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL)); +} + +TEST_TEAR_DOWN(key_manager) +{ + test_utils_finish_and_evaluate_leaks(test_utils_get_leak_level(ESP_LEAK_TYPE_WARNING, ESP_COMP_LEAK_ALL), + test_utils_get_leak_level(ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_ALL)); +} + +TEST(key_manager, xts_aes_128_key_aes_deployment) +{ + key_mgr_test_xts_aes_128(); +} + +TEST(key_manager, xts_aes_256_key_aes_deployment) +{ + key_mgr_test_xts_aes_256_aes_mode(); +} + +TEST(key_manager, ecdsa_key_aes_deployment) +{ + key_mgr_test_ecdsa_p256_aes_mode(); +} + +TEST(key_manager, xts_key_ecdh0_deployment) +{ + key_mgr_test_xts_aes_128_ecdh0_mode(); + key_mgr_test_xts_aes_256_ecdh0_mode(); +} + +TEST(key_manager, ecdsa_key_ecdh0_deployment) +{ + key_mgr_test_ecdsa_ecdh0_mode(); +} + +TEST(key_manager, ecdsa_key_random_deployment) +{ + key_mgr_test_ecdsa_random_mode(); +} + +#if CONFIG_IDF_ENV_FPGA +TEST(key_manager, xts_key_random_deployment) +{ + key_mgr_test_xts_aes_128_random_mode(); + key_mgr_test_xts_aes_256_random_mode(); +} +#endif + +TEST_GROUP_RUNNER(key_manager) +{ + RUN_TEST_CASE(key_manager, xts_aes_128_key_aes_deployment); + RUN_TEST_CASE(key_manager, xts_aes_256_key_aes_deployment); + RUN_TEST_CASE(key_manager, ecdsa_key_aes_deployment); + RUN_TEST_CASE(key_manager, xts_key_ecdh0_deployment); + RUN_TEST_CASE(key_manager, ecdsa_key_ecdh0_deployment); + RUN_TEST_CASE(key_manager, ecdsa_key_random_deployment); +#if CONFIG_IDF_ENV_FPGA + RUN_TEST_CASE(key_manager, xts_key_random_deployment); +#endif + +} diff --git a/components/hal/test_apps/crypto/pytest_crypto.py b/components/hal/test_apps/crypto/pytest_crypto.py index 462587ecdb..64fe21473b 100644 --- a/components/hal/test_apps/crypto/pytest_crypto.py +++ b/components/hal/test_apps/crypto/pytest_crypto.py @@ -1,17 +1,153 @@ -# SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 +import binascii import os +import subprocess +from typing import Any import pytest +from cryptography import exceptions +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives.asymmetric import utils +from cryptography.hazmat.primitives.asymmetric.ec import SECP256R1 +from cryptography.hazmat.primitives.serialization import load_pem_private_key +from ecdsa import NIST256p +from ecdsa.ellipticcurve import Point from pytest_embedded import Dut +def load_ecdsa_key(filename: str) -> SECP256R1: + with open(filename, 'rb') as key_file: + return load_pem_private_key(key_file.read(), password=None, backend=default_backend()) + + +def test_xts_aes_encryption(negotiated_key: bytes, plaintext_data: bytes, encrypted_data: bytes) -> None: + with open('test/negotiated_key.bin', 'wb+') as key_file: + key_file.write(negotiated_key) + + with open('test/plaintext.bin', 'wb+') as plaintext_file: + plaintext_file.write(plaintext_data) + + command = [ + 'espsecure.py', + 'encrypt_flash_data', + '--aes_xts', + '--keyfile', 'test/negotiated_key.bin', + '--address', '0x120000', + '--output', 'test/enc-data.bin', + 'test/plaintext.bin' + ] + result = subprocess.run(command, capture_output=True, text=True) + assert result.returncode == 0, f'Command failed with error: {result.stderr}' + + with open('test/enc-data.bin', 'rb') as enc_file: + calculated_enc_data = enc_file.read() + + assert calculated_enc_data == encrypted_data, 'Calculated data does not match encrypted data obtained from firmware' + + +def calculate_key_manager_ecdh0_negotiated_key(k2_G_hex: str, k1_ecdsa_key: str) -> Any: + k2_G_bytes_le = binascii.unhexlify(k2_G_hex) + + k2_G_bytes_x_be = bytes(reversed(k2_G_bytes_le[:32])) + k2_G_bytes_y_be = bytes(reversed(k2_G_bytes_le[32:])) + + k2_G_bytes_be = k2_G_bytes_x_be + k2_G_bytes_y_be + + curve = NIST256p.curve + k2_G = Point.from_bytes(curve, k2_G_bytes_be) + + # Load the ECDSA private key (k1) + k1_key = load_ecdsa_key(k1_ecdsa_key) + k1_int = k1_key.private_numbers().private_value + + # Convert the integer to bytes in big endian format + k1_bytes_big_endian = k1_int.to_bytes((k1_int.bit_length() + 7) // 8, byteorder='big') + + # Reverse the bytes to get little endian format + k1_bytes_little_endian = k1_bytes_big_endian[::-1] + + k1_int = int.from_bytes(k1_bytes_little_endian, byteorder='little') + + # Calculate k1*k2*G + k1_k2_G = k1_int * k2_G + + # Extract the x-coordinate of the result and save it as the shared secret + negotiated_key = k1_k2_G.to_bytes()[:32] + return negotiated_key + + +def test_ecdsa_key(negotiated_key: bytes, digest: bytes, signature_r_le: bytes, signature_s_le: bytes, pubx: bytes, puby: bytes) -> None: + r = int.from_bytes(signature_r_le, 'little') + s = int.from_bytes(signature_s_le, 'little') + signature = utils.encode_dss_signature(r, s) + pubx_int = int.from_bytes(pubx, 'little') + puby_int = int.from_bytes(puby, 'little') + private_number = int.from_bytes(negotiated_key, byteorder='big') + ecdsa_private_key = ec.derive_private_key(private_number, ec.SECP256R1()) + # Get the public key + public_key = ecdsa_private_key.public_key() + # Extract the pubx and puby values + calc_pubx, calc_puby = public_key.public_numbers().x, public_key.public_numbers().y + + assert calc_pubx == pubx_int, 'Public key calculated should match with public key obtained' + assert calc_puby == puby_int, 'Public key calculated should match with public key obtained' + + try: + public_key.verify(signature, digest, ec.ECDSA(utils.Prehashed(hashes.SHA256()))) + print('Valid signature') + except exceptions.InvalidSignature: + print('Invalid signature') + raise + + @pytest.mark.supported_targets @pytest.mark.generic def test_crypto(dut: Dut) -> None: # if the env variable IDF_FPGA_ENV is set, we would need a longer timeout # as tests for efuses burning security peripherals would be run timeout = 600 if os.environ.get('IDF_ENV_FPGA') else 60 + # only expect key manager result if it is supported for the SoC + if dut.app.sdkconfig.get('SOC_KEY_MANAGER_SUPPORTED'): + print('Key Manager is supported') + + # Test for ECDH0 deployment XTS-AES-128 key + dut.expect('Key Manager ECDH0 deployment: XTS_AES_128 key', timeout=timeout) + k2_G = dut.expect(r'K2_G: 0x([0-9a-fA-F]+)', timeout=timeout)[1].decode() + plaintext_data = dut.expect(r'Plaintext data: 0x([0-9a-fA-F]+)', timeout=timeout)[1] + plaintext_data = binascii.unhexlify(plaintext_data) + encrypted_data = dut.expect(r'Encrypted data: 0x([0-9a-fA-F]+)', timeout=timeout)[1].decode() + encrypted_data = binascii.unhexlify(encrypted_data) + negotiated_key = calculate_key_manager_ecdh0_negotiated_key(k2_G, 'main/key_manager/k1_ecdsa.pem') + test_xts_aes_encryption(negotiated_key, plaintext_data, encrypted_data) + + # Test for ECDH0 deployment XTS-AES-256 key + dut.expect('Key Manager ECDH0 deployment: XTS_AES_256 key', timeout=timeout) + k2_G_0 = dut.expect(r'K2_G_0: 0x([0-9a-fA-F]+)', timeout=timeout)[1].decode() + k2_G_1 = dut.expect(r'K2_G_1: 0x([0-9a-fA-F]+)', timeout=timeout)[1].decode() + encrypted_data = dut.expect(r'Encrypted data: 0x([0-9a-fA-F]+)', timeout=timeout)[1].decode() + encrypted_data = binascii.unhexlify(encrypted_data) + negotiated_key_0 = calculate_key_manager_ecdh0_negotiated_key(k2_G_0, 'main/key_manager/k1_ecdsa.pem') + negotiated_key_1 = calculate_key_manager_ecdh0_negotiated_key(k2_G_1, 'main/key_manager/k1_ecdsa.pem') + negotiated_key = negotiated_key_0 + negotiated_key_1 + test_xts_aes_encryption(negotiated_key, plaintext_data, encrypted_data) + # Test for ECDH0 deployment ECDSA-256 key + dut.expect('Key Manager ECDH0 deployment: ECDSA_256 key', timeout=timeout) + k2_G = dut.expect(r'K2_G: 0x([0-9a-fA-F]+)', timeout=timeout)[1].decode() + digest = dut.expect(r'ECDSA message sha256 digest: 0x([0-9a-fA-F]+)', timeout=timeout)[1].decode() + digest = binascii.unhexlify(digest) + signature_r_le = dut.expect(r'ECDSA signature r_le: 0x([0-9a-fA-F]+)', timeout=timeout)[1].decode() + signature_r_le = binascii.unhexlify(signature_r_le) + signature_s_le = dut.expect(r'ECDSA signature s_le: 0x([0-9a-fA-F]+)', timeout=timeout)[1].decode() + signature_s_le = binascii.unhexlify(signature_s_le) + pub_x = dut.expect(r'ECDSA key pubx: 0x([0-9a-fA-F]+)', timeout=timeout)[1].decode() + pub_x = binascii.unhexlify(pub_x) + pub_y = dut.expect(r'ECDSA key puby: 0x([0-9a-fA-F]+)', timeout=timeout)[1].decode() + pub_y = binascii.unhexlify(pub_y) + negotiated_key = calculate_key_manager_ecdh0_negotiated_key(k2_G, 'main/key_manager/k1_ecdsa.pem') + test_ecdsa_key(negotiated_key, digest, signature_r_le, signature_s_le, pub_x, pub_y) test_numbers = dut.expect(r'(\d+) Tests (\d+) Failures (\d+) Ignored', timeout=timeout) failures = test_numbers.group(2).decode()