feat(hal): Add crypto tests for key manager

Added test to verify exporting of ECDSA public key
    Added test to verify XTS_AES in random mode
    Added pytest test case for testing ECDH0 mode for XTS_128 and XTS_256 key
    Add test for ECDSA key in ECDH0 mode
    Update the key manager hal based tests
    Update key manager tests to add ECDH0 workflow
This commit is contained in:
Aditya Patwardhan 2024-03-13 13:10:47 +05:30
parent e5fcc2d315
commit 79b21fb624
No known key found for this signature in database
GPG Key ID: E628B2648FBF0DD8
7 changed files with 890 additions and 25 deletions

View File

@ -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}"

View File

@ -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

View File

@ -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 */

View File

@ -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('<I', flash_address & ~0x7F) + (b'\x00' * 12)
flash_address += 0x80
cipher = Cipher(algorithms.AES(key), modes.XTS(tweak), backend=backend)
encryptor = cipher.encryptor() if not do_decrypt else cipher.decryptor()
outblock = encryptor.update(inblock[::-1])
output += outblock[::-1]
return output[pad_left:len(output) - pad_right]
def generate_xts_test_data(key: bytes, base_flash_address: int = 0x120000) -> 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 <stdint.h>
#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)

View File

@ -0,0 +1,87 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdint.h>
#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 },
}
};

View File

@ -0,0 +1,374 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#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
}

View File

@ -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()