feat: adds PSA MD5 driver support

This commit is contained in:
Ashish Sharma
2026-01-05 16:35:48 +08:00
parent d52166acb5
commit 3d5775e22b
10 changed files with 434 additions and 226 deletions
+7 -4
View File
@@ -363,6 +363,13 @@ if(CONFIG_SOC_SHA_SUPPORTED)
)
endif()
if(CONFIG_MBEDTLS_ROM_MD5)
target_compile_definitions(tfpsacrypto PRIVATE ESP_MD5_DRIVER_ENABLED)
target_sources(tfpsacrypto PRIVATE
"${COMPONENT_DIR}/port/psa_driver/esp_md/psa_crypto_driver_esp_md5.c"
)
endif()
if(CONFIG_SOC_DIG_SIGN_SUPPORTED)
target_sources(tfpsacrypto PRIVATE
"${COMPONENT_DIR}/port/esp_ds/esp_rsa_sign_alt.c"
@@ -448,10 +455,6 @@ CONFIG_MBEDTLS_HARDWARE_ECDSA_VERIFY OR CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN)
endif()
endif()
# if(CONFIG_MBEDTLS_ROM_MD5)
# target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/md/esp_md.c")
# endif()
# if(CONFIG_MBEDTLS_USE_CRYPTO_ROM_IMPL)
# target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/mbedtls_rom/mbedtls_rom_osi.c")
# target_link_libraries(${COMPONENT_LIB} PRIVATE "-u mbedtls_rom_osi_functions_init")
@@ -102,6 +102,13 @@ if(CONFIG_SOC_SHA_SUPPORTED)
"${COMPONENT_DIR}/port/sha/esp_sha.c")
endif()
if(CONFIG_MBEDTLS_ROM_MD5)
target_compile_definitions(tfpsacrypto PRIVATE ESP_MD5_DRIVER_ENABLED)
target_sources(tfpsacrypto PRIVATE
"${COMPONENT_DIR}/port/psa_driver/esp_md/psa_crypto_driver_esp_md5.c"
)
endif()
if(CONFIG_SOC_ECC_SUPPORTED)
target_sources(tfpsacrypto PRIVATE "${COMPONENT_DIR}/port/ecc/esp_ecc.c"
"${COMPONENT_DIR}/port/ecc/ecc_alt.c")
@@ -212,12 +212,10 @@
/* MBEDTLS_MDx_ALT to enable ROM MD support
with software fallback.
*/
/* TODO: IDF-15029 */
// #ifdef CONFIG_MBEDTLS_ROM_MD5
// #define MBEDTLS_MD5_ALT
// #else
// #undef MBEDTLS_MD5_ALT
// #endif
#ifdef CONFIG_MBEDTLS_ROM_MD5
#define MBEDTLS_PSA_ACCEL_ALG_MD5
#undef MBEDTLS_PSA_BUILTIN_ALG_MD5
#endif
/* The following MPI (bignum) functions have hardware support.
* Uncommenting these macros will use the hardware-accelerated
-119
View File
@@ -1,119 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_rom_md5.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_IDF_TARGET_ESP32C2
typedef struct mbedtls_md5_context mbedtls_md5_context;
#else
typedef struct MD5Context mbedtls_md5_context;
#endif
/**
* \brief Initialize MD5 context
*
* \param ctx MD5 context to be initialized
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
void esp_md5_init( mbedtls_md5_context *ctx );
/**
* \brief Clear MD5 context
*
* \param ctx MD5 context to be cleared
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
void esp_md5_free( mbedtls_md5_context *ctx );
/**
* \brief Clone (the state of) an MD5 context
*
* \param dst The destination context
* \param src The context to be cloned
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
void esp_md5_clone( mbedtls_md5_context *dst, const mbedtls_md5_context *src );
/**
* \brief MD5 context setup
*
* \param ctx context to be initialized
*
* \return 0 if successful
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
int mbedtls_md5_starts( mbedtls_md5_context *ctx );
/**
* \brief MD5 process buffer
*
* \param ctx MD5 context
* \param input buffer holding the data
* \param ilen length of the input data
*
* \return 0 if successful
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
int esp_md5_update( mbedtls_md5_context *ctx, const unsigned char *input, size_t ilen );
/**
* \brief MD5 final digest
*
* \param ctx MD5 context
* \param output MD5 checksum result
*
* \return 0 if successful
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
int esp_md5_finish( mbedtls_md5_context *ctx, unsigned char output[16] );
/**
* \brief MD5 process data block (internal use only)
*
* \param ctx MD5 context
* \param data buffer holding one block of data
*
* \return 0 if successful
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
int esp_md5_process( mbedtls_md5_context *ctx, const unsigned char data[64] );
#ifdef __cplusplus
}
#endif
-35
View File
@@ -1,35 +0,0 @@
/*
* md5_alt.h: MD5 block cipher
*
* SPDX-FileCopyrightText: The Mbed TLS Contributors
*
* SPDX-License-Identifier: Apache-2.0
*
* SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD
*/
#ifndef MD5_ALT_H
#define MD5_ALT_H
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MBEDTLS_MD5_ALT)
#include "md/esp_md.h"
#define mbedtls_md5_init esp_md5_init
#define mbedtls_md5_update esp_md5_update
#define mbedtls_md5_finish esp_md5_finish
#define mbedtls_md5_starts esp_md5_starts
#define mbedtls_md5_free esp_md5_free
#define mbedtls_md5_clone esp_md5_clone
#define mbedtls_internal_md5_process esp_md5_process
#endif /* MBEDTLS_MD5_ALT */
#ifdef __cplusplus
}
#endif
#endif
-61
View File
@@ -1,61 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "mbedtls/md5.h"
#include "mbedtls/platform_util.h"
#if defined(MBEDTLS_MD5_ALT)
#include "md/esp_md.h"
int esp_md5_finish( mbedtls_md5_context *ctx, unsigned char output[16] )
{
esp_rom_md5_final(output, ctx);
return 0;
}
int esp_md5_update( mbedtls_md5_context *ctx, const unsigned char *input, size_t ilen )
{
esp_rom_md5_update(ctx, input, ilen);
return 0;
}
void esp_md5_init( mbedtls_md5_context *ctx )
{
esp_rom_md5_init(ctx);
}
int esp_md5_starts( mbedtls_md5_context *ctx )
{
esp_md5_init(ctx);
return 0;
}
void esp_md5_free( mbedtls_md5_context *ctx )
{
if (ctx == NULL) {
return;
}
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md5_context ) );
}
int esp_md5_process( mbedtls_md5_context *ctx, const unsigned char data[64] )
{
esp_md5_update(ctx, data, 64);
return 0;
}
void esp_md5_clone( mbedtls_md5_context *dst, const mbedtls_md5_context *src )
{
*dst = *src;
}
#endif
@@ -0,0 +1,101 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "psa_crypto_driver_esp_md5.h"
psa_status_t esp_md5_hash_compute(psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
uint8_t *hash,
size_t hash_size,
size_t *hash_length)
{
if (hash == NULL || hash_length == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (input_length > 0 && input == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (hash_size < PSA_HASH_LENGTH(PSA_ALG_MD5)) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
if (alg != PSA_ALG_MD5) {
return PSA_ERROR_NOT_SUPPORTED;
}
md5_context_t operation = {0};
esp_rom_md5_init(&operation);
esp_rom_md5_update(&operation, input, input_length);
esp_rom_md5_final(hash, &operation);
*hash_length = PSA_HASH_LENGTH(PSA_ALG_MD5);
return PSA_SUCCESS;
}
psa_status_t esp_md5_hash_setup(md5_context_t *operation,
psa_algorithm_t alg)
{
if (operation == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (alg != PSA_ALG_MD5) {
return PSA_ERROR_NOT_SUPPORTED;
}
esp_rom_md5_init(operation);
return PSA_SUCCESS;
}
psa_status_t esp_md5_hash_update(
md5_context_t *operation,
const uint8_t *input,
size_t input_length )
{
if (operation == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (input_length > 0 && input == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
esp_rom_md5_update(operation, input, input_length);
return PSA_SUCCESS;
}
psa_status_t esp_md5_hash_finish(
md5_context_t *operation,
uint8_t *hash,
size_t hash_size,
size_t *hash_length)
{
if (operation == NULL || hash == NULL || hash_length == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (hash_size < PSA_HASH_LENGTH(PSA_ALG_MD5)) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
esp_rom_md5_final(hash, operation);
*hash_length = PSA_HASH_LENGTH(PSA_ALG_MD5);
return PSA_SUCCESS;
}
psa_status_t esp_md5_hash_abort(md5_context_t *operation)
{
if (operation == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
memset(operation, 0, sizeof(*operation));
return PSA_SUCCESS;
}
psa_status_t esp_md5_hash_clone(
const md5_context_t *source_operation,
md5_context_t *target_operation)
{
if (source_operation == NULL || target_operation == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
memcpy(target_operation, source_operation, sizeof(md5_context_t));
return PSA_SUCCESS;
}
@@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include "psa/crypto.h"
#include "esp_rom_md5.h"
#ifdef CONFIG_MBEDTLS_ROM_MD5
#ifndef PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT
#define PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT
#endif
#endif // CONFIG_MBEDTLS_ROM_MD5
psa_status_t esp_md5_hash_compute(psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
uint8_t *hash,
size_t hash_size,
size_t *hash_length);
psa_status_t esp_md5_hash_setup(md5_context_t *operation,
psa_algorithm_t alg);
psa_status_t esp_md5_hash_update(
md5_context_t *operation,
const uint8_t *input,
size_t input_length );
psa_status_t esp_md5_hash_finish(
md5_context_t *operation,
uint8_t *hash,
size_t hash_size,
size_t *hash_length);
psa_status_t esp_md5_hash_abort(md5_context_t *operation);
psa_status_t esp_md5_hash_clone(
const md5_context_t *source_operation,
md5_context_t *target_operation);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,263 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "psa/crypto.h"
#include "esp_types.h"
#include "esp_log.h"
#include "ccomp_timer.h"
#include "unity.h"
#include "test_utils.h"
#include "esp_heap_caps.h"
#include "test_mbedtls_utils.h"
#define TAG "md5_test"
#define MD5_HASH_LEN 16
TEST_CASE("Test PSA MD5 with known test vectors", "[hw_crypto][psa]")
{
ESP_LOGI(TAG, "Testing MD5 implementation with known test vectors");
uint8_t input[128] = {0};
for (int i = 0; i < 128; i++) {
input[i] = i;
}
uint8_t hash_output[MD5_HASH_LEN] = {0};
psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
psa_status_t status = PSA_ERROR_GENERIC_ERROR;
size_t hash_len = 0;
status = psa_hash_setup(&operation, PSA_ALG_MD5);
TEST_ASSERT_EQUAL(status, PSA_SUCCESS);
status = psa_hash_update(&operation, input, sizeof(input));
TEST_ASSERT_EQUAL(status, PSA_SUCCESS);
status = psa_hash_finish(&operation, hash_output, MD5_HASH_LEN, &hash_len);
TEST_ASSERT_EQUAL(status, PSA_SUCCESS);
uint8_t expected_hash[MD5_HASH_LEN] = {
0x37, 0xEF, 0xF0, 0x18, 0x66, 0xBA, 0x3F, 0x53, 0x84, 0x21, 0xB3, 0x0B, 0x7C, 0xBE, 0xFC, 0xAC
};
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_hash, hash_output, MD5_HASH_LEN);
}
TEST_CASE("Test PSA MD5 error cases", "[hw_crypto][psa]")
{
ESP_LOGI(TAG, "Testing MD5 error handling");
uint8_t input[64] = {0};
uint8_t hash_output[MD5_HASH_LEN] = {0};
size_t hash_len = 0;
psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
psa_status_t status;
// Test 1: NULL hash buffer in hash_compute
status = psa_hash_compute(PSA_ALG_MD5, input, sizeof(input), NULL, MD5_HASH_LEN, &hash_len);
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status);
// Test 2: NULL input with non-zero length in hash_compute
status = psa_hash_compute(PSA_ALG_MD5, NULL, 10, hash_output, MD5_HASH_LEN, &hash_len);
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status);
// Test 3: Buffer too small in hash_compute
status = psa_hash_compute(PSA_ALG_MD5, input, sizeof(input), hash_output, MD5_HASH_LEN - 1, &hash_len);
TEST_ASSERT_EQUAL(PSA_ERROR_BUFFER_TOO_SMALL, status);
// Test 4: NULL input with non-zero length in hash_update
operation = psa_hash_operation_init();
status = psa_hash_setup(&operation, PSA_ALG_MD5);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
status = psa_hash_update(&operation, NULL, 10);
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status);
psa_hash_abort(&operation);
// Test 5: NULL hash buffer in hash_finish
operation = psa_hash_operation_init();
status = psa_hash_setup(&operation, PSA_ALG_MD5);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
status = psa_hash_finish(&operation, NULL, MD5_HASH_LEN, &hash_len);
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status);
psa_hash_abort(&operation);
// Test 6: Buffer too small in hash_finish
operation = psa_hash_operation_init();
status = psa_hash_setup(&operation, PSA_ALG_MD5);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
status = psa_hash_update(&operation, input, sizeof(input));
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
status = psa_hash_finish(&operation, hash_output, 8, &hash_len);
TEST_ASSERT_EQUAL(PSA_ERROR_BUFFER_TOO_SMALL, status);
psa_hash_abort(&operation);
// Test 7: Multiple aborts should be safe
operation = psa_hash_operation_init();
status = psa_hash_setup(&operation, PSA_ALG_MD5);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
status = psa_hash_abort(&operation);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
status = psa_hash_abort(&operation);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
ESP_LOGI(TAG, "All MD5 error cases passed");
}
TEST_CASE("Test PSA MD5 clone operation", "[hw_crypto][psa]")
{
ESP_LOGI(TAG, "Testing MD5 clone operation");
uint8_t input_part1[32];
uint8_t input_part2[32];
for (int i = 0; i < 32; i++) {
input_part1[i] = i;
input_part2[i] = i + 32;
}
uint8_t hash_output1[MD5_HASH_LEN] = {0};
uint8_t hash_output2[MD5_HASH_LEN] = {0};
size_t hash_len1 = 0, hash_len2 = 0;
psa_hash_operation_t operation1 = PSA_HASH_OPERATION_INIT;
psa_hash_operation_t operation2 = PSA_HASH_OPERATION_INIT;
psa_status_t status;
// Setup and update first operation
status = psa_hash_setup(&operation1, PSA_ALG_MD5);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
status = psa_hash_update(&operation1, input_part1, sizeof(input_part1));
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
// Clone the operation
status = psa_hash_clone(&operation1, &operation2);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
// Continue both operations with the same data
status = psa_hash_update(&operation1, input_part2, sizeof(input_part2));
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
status = psa_hash_update(&operation2, input_part2, sizeof(input_part2));
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
// Finish both operations
status = psa_hash_finish(&operation1, hash_output1, MD5_HASH_LEN, &hash_len1);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
status = psa_hash_finish(&operation2, hash_output2, MD5_HASH_LEN, &hash_len2);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
// Both should produce the same hash
TEST_ASSERT_EQUAL_HEX8_ARRAY(hash_output1, hash_output2, MD5_HASH_LEN);
ESP_LOGI(TAG, "MD5 clone operation test passed");
}
TEST_CASE("Test PSA MD5 with zero-length input", "[hw_crypto][psa]")
{
ESP_LOGI(TAG, "Testing MD5 with zero-length input");
uint8_t hash_output[MD5_HASH_LEN] = {0};
size_t hash_len = 0;
psa_status_t status;
// Empty string MD5 hash: d41d8cd98f00b204e9800998ecf8427e
uint8_t expected_hash[MD5_HASH_LEN] = {
0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04,
0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E
};
// Test with hash_compute
status = psa_hash_compute(PSA_ALG_MD5, NULL, 0, hash_output, MD5_HASH_LEN, &hash_len);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
TEST_ASSERT_EQUAL(MD5_HASH_LEN, hash_len);
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_hash, hash_output, MD5_HASH_LEN);
// Test with hash_setup/update/finish
psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
memset(hash_output, 0, MD5_HASH_LEN);
status = psa_hash_setup(&operation, PSA_ALG_MD5);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
status = psa_hash_update(&operation, NULL, 0);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
status = psa_hash_finish(&operation, hash_output, MD5_HASH_LEN, &hash_len);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
TEST_ASSERT_EQUAL(MD5_HASH_LEN, hash_len);
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_hash, hash_output, MD5_HASH_LEN);
ESP_LOGI(TAG, "Zero-length input test passed");
}
TEST_CASE("Test PSA MD5 incremental updates", "[hw_crypto][psa]")
{
ESP_LOGI(TAG, "Testing MD5 incremental updates");
uint8_t input[128];
for (int i = 0; i < 128; i++) {
input[i] = i;
}
uint8_t hash_full[MD5_HASH_LEN] = {0};
uint8_t hash_incremental[MD5_HASH_LEN] = {0};
size_t hash_len = 0;
psa_status_t status;
// Compute hash in one go
status = psa_hash_compute(PSA_ALG_MD5, input, sizeof(input), hash_full, MD5_HASH_LEN, &hash_len);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
// Compute hash incrementally in small chunks
psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
status = psa_hash_setup(&operation, PSA_ALG_MD5);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
for (int i = 0; i < 128; i += 16) {
status = psa_hash_update(&operation, input + i, 16);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
}
status = psa_hash_finish(&operation, hash_incremental, MD5_HASH_LEN, &hash_len);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
// Both methods should produce the same hash
TEST_ASSERT_EQUAL_HEX8_ARRAY(hash_full, hash_incremental, MD5_HASH_LEN);
ESP_LOGI(TAG, "Incremental updates test passed");
}
TEST_CASE("psa MD5 performance", "[mbedtls]")
{
const unsigned CALLS = 256;
const unsigned CALL_SZ = 16 * 1024;
float elapsed_usec;
uint8_t hash_output[MD5_HASH_LEN] = {0};
psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
psa_status_t status = psa_hash_setup(&operation, PSA_ALG_MD5);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
// allocate internal memory
uint8_t *buf = heap_caps_malloc(CALL_SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
TEST_ASSERT_NOT_NULL(buf);
memset(buf, 0x55, CALL_SZ);
ccomp_timer_start();
for (int c = 0; c < CALLS; c++) {
status = psa_hash_update(&operation, buf, CALL_SZ);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
}
size_t hash_length;
status = psa_hash_finish(&operation, hash_output, MD5_HASH_LEN, &hash_length);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
elapsed_usec = ccomp_timer_stop();
free(buf);
const char *expected_hash = "9a9819e47b2014589ae2057458664df7";
char hash_str[MD5_HASH_LEN * 2 + 1];
utils_bin2hex(hash_str, sizeof(hash_str), hash_output, MD5_HASH_LEN);
TEST_ASSERT_EQUAL_STRING(expected_hash, hash_str);
float mb_sec = (CALL_SZ * CALLS) / elapsed_usec;
printf("MD5 rate %.3fMB/sec\n", mb_sec);
}