mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
Merge branch 'fix/mbedtls_gcm_multipart_and_ecp_pubkey_v6.1' into 'release/v6.1'
Fix/mbedTLS port layer security fixes (394, 1214, 1206) (v6.1) See merge request espressif/esp-idf!52194
This commit is contained in:
@@ -314,6 +314,46 @@ static void esp_gcm_ghash(esp_gcm_context *ctx, const unsigned char *x, size_t x
|
||||
}
|
||||
}
|
||||
|
||||
/* Feed data into the running GHASH one full 16-byte block at a time, carrying
|
||||
* any sub-block remainder across calls in ctx->ghash_buf.
|
||||
*/
|
||||
static void esp_gcm_ghash_buffered(esp_gcm_context *ctx, const unsigned char *data, size_t len)
|
||||
{
|
||||
size_t buffered = ctx->ghash_buf_len;
|
||||
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffered) {
|
||||
size_t fill = AES_BLOCK_BYTES - buffered;
|
||||
if (fill > len) {
|
||||
fill = len;
|
||||
}
|
||||
memcpy(ctx->ghash_buf + buffered, data, fill);
|
||||
buffered += fill;
|
||||
data += fill;
|
||||
len -= fill;
|
||||
if (buffered == AES_BLOCK_BYTES) {
|
||||
esp_gcm_ghash(ctx, ctx->ghash_buf, AES_BLOCK_BYTES, ctx->ghash);
|
||||
buffered = 0;
|
||||
}
|
||||
ctx->ghash_buf_len = buffered;
|
||||
}
|
||||
|
||||
size_t full = len - (len % AES_BLOCK_BYTES);
|
||||
if (full) {
|
||||
esp_gcm_ghash(ctx, data, full, ctx->ghash);
|
||||
data += full;
|
||||
len -= full;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
memcpy(ctx->ghash_buf, data, len);
|
||||
ctx->ghash_buf_len = len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Function to init AES GCM context to zero */
|
||||
void esp_aes_gcm_init( esp_gcm_context *ctx)
|
||||
@@ -369,6 +409,12 @@ int esp_aes_gcm_starts( esp_gcm_context *ctx,
|
||||
ctx->aad = NULL;
|
||||
ctx->aad_len = 0;
|
||||
|
||||
/* Reset the streaming state carried across esp_aes_gcm_update() calls */
|
||||
ctx->nc_off = 0;
|
||||
ctx->ghash_buf_len = 0;
|
||||
memset(ctx->stream_block, 0, sizeof(ctx->stream_block));
|
||||
memset(ctx->ghash_buf, 0, sizeof(ctx->ghash_buf));
|
||||
|
||||
ctx->iv = iv;
|
||||
ctx->iv_len = iv_len;
|
||||
ctx->mode = mode;
|
||||
@@ -432,11 +478,13 @@ int esp_aes_gcm_update_ad( esp_gcm_context *ctx,
|
||||
return PSA_ERROR_BAD_STATE;
|
||||
}
|
||||
|
||||
/* Initialise associated data */
|
||||
ctx->aad = aad;
|
||||
ctx->aad_len = aad_len;
|
||||
if ( ( ctx->aad_len + aad_len ) >> 29 != 0 ) {
|
||||
return ( PSA_ERROR_INVALID_ARGUMENT );
|
||||
}
|
||||
|
||||
esp_gcm_ghash(ctx, ctx->aad, ctx->aad_len, ctx->ghash);
|
||||
/* Accumulate the data across (possibly multiple) calls. */
|
||||
ctx->aad_len += aad_len;
|
||||
esp_gcm_ghash_buffered(ctx, aad, aad_len);
|
||||
|
||||
return ( 0 );
|
||||
}
|
||||
@@ -452,9 +500,7 @@ int esp_aes_gcm_update( esp_gcm_context *ctx,
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t nc_off = 0;
|
||||
uint8_t nonce_counter[AES_BLOCK_BYTES] = {0};
|
||||
uint8_t stream[AES_BLOCK_BYTES] = {0};
|
||||
|
||||
if (!output_length) {
|
||||
ESP_LOGE(TAG, "No output length supplied");
|
||||
@@ -471,9 +517,8 @@ int esp_aes_gcm_update( esp_gcm_context *ctx,
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
/* Honor the documented contract: the output buffer must hold input_length bytes, which are
|
||||
* written unconditionally below; without this check an undersized buffer overflows (CWE-20
|
||||
* -> CWE-787). MBEDTLS_ERR_GCM_BAD_INPUT is #defined to PSA_ERROR_INVALID_ARGUMENT. */
|
||||
/* The output buffer must hold input_length bytes, which are
|
||||
* written unconditionally below; without this check an undersized buffer overflows. */
|
||||
if ( output_size < input_length ) {
|
||||
ESP_LOGE(TAG, "Output buffer too small");
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
@@ -490,6 +535,12 @@ int esp_aes_gcm_update( esp_gcm_context *ctx,
|
||||
* operation will auto update it
|
||||
*/
|
||||
increment32_j0(ctx, nonce_counter);
|
||||
/* Zero-pad and flush any buffered partial AAD block so the ciphertext
|
||||
* GHASH starts on a fresh block */
|
||||
if (ctx->ghash_buf_len) {
|
||||
esp_gcm_ghash(ctx, ctx->ghash_buf, ctx->ghash_buf_len, ctx->ghash);
|
||||
ctx->ghash_buf_len = 0;
|
||||
}
|
||||
ctx->gcm_state = ESP_AES_GCM_STATE_UPDATE;
|
||||
} else if (ctx->gcm_state == ESP_AES_GCM_STATE_UPDATE) {
|
||||
memcpy(nonce_counter, ctx->J0, AES_BLOCK_BYTES);
|
||||
@@ -497,11 +548,11 @@ int esp_aes_gcm_update( esp_gcm_context *ctx,
|
||||
|
||||
/* Perform intermediate GHASH on "encrypted" data during decryption */
|
||||
if (ctx->mode == ESP_AES_DECRYPT) {
|
||||
esp_gcm_ghash(ctx, input, input_length, ctx->ghash);
|
||||
esp_gcm_ghash_buffered(ctx, input, input_length);
|
||||
}
|
||||
|
||||
/* Output = GCTR(J0, Input): Encrypt/Decrypt the input */
|
||||
int ret = esp_aes_crypt_ctr(&ctx->aes_ctx, input_length, &nc_off, nonce_counter, stream, input, output);
|
||||
/* Output = GCTR(J0, Input): Encrypt/Decrypt the input. */
|
||||
int ret = esp_aes_crypt_ctr(&ctx->aes_ctx, input_length, &ctx->nc_off, nonce_counter, ctx->stream_block, input, output);
|
||||
if (ret == 0) {
|
||||
/* ICB gets auto incremented after GCTR operation here so update the context */
|
||||
memcpy(ctx->J0, nonce_counter, AES_BLOCK_BYTES);
|
||||
@@ -511,14 +562,13 @@ int esp_aes_gcm_update( esp_gcm_context *ctx,
|
||||
|
||||
/* Perform intermediate GHASH on "encrypted" data during encryption*/
|
||||
if (ctx->mode == ESP_AES_ENCRYPT) {
|
||||
esp_gcm_ghash(ctx, output, input_length, ctx->ghash);
|
||||
esp_gcm_ghash_buffered(ctx, output, input_length);
|
||||
}
|
||||
}
|
||||
|
||||
/* stream holds the AES-CTR keystream and nonce_counter the live CTR state;
|
||||
* both are key-derived secrets. Scrub them on every exit so they cannot be
|
||||
* recovered from stack RAM. */
|
||||
mbedtls_platform_zeroize(stream, sizeof(stream));
|
||||
/* nonce_counter holds the live CTR state (key-derived); scrub the stack
|
||||
* copy on every exit. The persistent keystream in ctx->stream_block is
|
||||
* required for the next update and is scrubbed in esp_aes_gcm_free(). */
|
||||
mbedtls_platform_zeroize(nonce_counter, sizeof(nonce_counter));
|
||||
return ret;
|
||||
}
|
||||
@@ -541,6 +591,13 @@ int esp_aes_gcm_finish( esp_gcm_context *ctx,
|
||||
return ( PSA_ERROR_INVALID_ARGUMENT );
|
||||
}
|
||||
|
||||
/* Flush the final buffered partial block (zero-padded) into GHASH before
|
||||
* the length block, completing the ciphertext portion of the hash. */
|
||||
if (ctx->ghash_buf_len) {
|
||||
esp_gcm_ghash(ctx, ctx->ghash_buf, ctx->ghash_buf_len, ctx->ghash);
|
||||
ctx->ghash_buf_len = 0;
|
||||
}
|
||||
|
||||
/* Calculate final GHASH on aad_len, data length */
|
||||
ESP_PUT_BE64(len_block, ctx->aad_len * 8);
|
||||
ESP_PUT_BE64(len_block + 8, ctx->data_len * 8);
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "esp_mbedtls_dynamic_impl.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
@@ -85,7 +87,7 @@ static void init_tx_buffer(mbedtls_ssl_context *ssl, unsigned char *buf)
|
||||
* In mbedtls, ssl->MBEDTLS_PRIVATE(out_msg) = ssl->MBEDTLS_PRIVATE(out_buf) + offset;
|
||||
*/
|
||||
if (!buf) {
|
||||
int out_msg_off = (int)ssl->MBEDTLS_PRIVATE(out_msg) - (int)ssl->MBEDTLS_PRIVATE(out_buf);
|
||||
ptrdiff_t out_msg_off = ssl->MBEDTLS_PRIVATE(out_msg) - ssl->MBEDTLS_PRIVATE(out_buf);
|
||||
|
||||
if (!out_msg_off) {
|
||||
out_msg_off = MBEDTLS_SSL_HEADER_LEN;
|
||||
@@ -96,9 +98,11 @@ static void init_tx_buffer(mbedtls_ssl_context *ssl, unsigned char *buf)
|
||||
ssl->MBEDTLS_PRIVATE(out_hdr) = NULL;
|
||||
ssl->MBEDTLS_PRIVATE(out_len) = NULL;
|
||||
ssl->MBEDTLS_PRIVATE(out_iv) = NULL;
|
||||
ssl->MBEDTLS_PRIVATE(out_msg) = (unsigned char *)out_msg_off;
|
||||
/* Stash the offset in the pointer field while the buffer is freed; it is
|
||||
* restored to a real pointer on the next allocation below. */
|
||||
ssl->MBEDTLS_PRIVATE(out_msg) = (unsigned char *)(uintptr_t)out_msg_off;
|
||||
} else {
|
||||
int out_msg_off = (int)ssl->MBEDTLS_PRIVATE(out_msg);
|
||||
uintptr_t out_msg_off = (uintptr_t)ssl->MBEDTLS_PRIVATE(out_msg);
|
||||
|
||||
ssl->MBEDTLS_PRIVATE(out_buf) = buf;
|
||||
ssl->MBEDTLS_PRIVATE(out_ctr) = ssl->MBEDTLS_PRIVATE(out_buf);
|
||||
@@ -107,7 +111,7 @@ static void init_tx_buffer(mbedtls_ssl_context *ssl, unsigned char *buf)
|
||||
ssl->MBEDTLS_PRIVATE(out_iv) = ssl->MBEDTLS_PRIVATE(out_buf) + MBEDTLS_SSL_HEADER_LEN;
|
||||
ssl->MBEDTLS_PRIVATE(out_msg) = ssl->MBEDTLS_PRIVATE(out_buf) + out_msg_off;
|
||||
|
||||
ESP_LOGV(TAG, "out msg offset is %d", out_msg_off);
|
||||
ESP_LOGV(TAG, "out msg offset is %u", (unsigned)out_msg_off);
|
||||
}
|
||||
|
||||
ssl->MBEDTLS_PRIVATE(out_msgtype) = 0;
|
||||
@@ -121,7 +125,7 @@ static void init_rx_buffer(mbedtls_ssl_context *ssl, unsigned char *buf)
|
||||
* In mbedtls, ssl->MBEDTLS_PRIVATE(in_msg) = ssl->MBEDTLS_PRIVATE(in_buf) + offset;
|
||||
*/
|
||||
if (!buf) {
|
||||
int in_msg_off = (int)ssl->MBEDTLS_PRIVATE(in_msg) - (int)ssl->MBEDTLS_PRIVATE(in_buf);
|
||||
ptrdiff_t in_msg_off = ssl->MBEDTLS_PRIVATE(in_msg) - ssl->MBEDTLS_PRIVATE(in_buf);
|
||||
|
||||
if (!in_msg_off) {
|
||||
in_msg_off = MBEDTLS_SSL_HEADER_LEN;
|
||||
@@ -132,9 +136,11 @@ static void init_rx_buffer(mbedtls_ssl_context *ssl, unsigned char *buf)
|
||||
ssl->MBEDTLS_PRIVATE(in_hdr) = NULL;
|
||||
ssl->MBEDTLS_PRIVATE(in_len) = NULL;
|
||||
ssl->MBEDTLS_PRIVATE(in_iv) = NULL;
|
||||
ssl->MBEDTLS_PRIVATE(in_msg) = (unsigned char *)in_msg_off;
|
||||
/* Stash the offset in the pointer field while the buffer is freed; it is
|
||||
* restored to a real pointer on the next allocation below. */
|
||||
ssl->MBEDTLS_PRIVATE(in_msg) = (unsigned char *)(uintptr_t)in_msg_off;
|
||||
} else {
|
||||
int in_msg_off = (int)ssl->MBEDTLS_PRIVATE(in_msg);
|
||||
uintptr_t in_msg_off = (uintptr_t)ssl->MBEDTLS_PRIVATE(in_msg);
|
||||
|
||||
ssl->MBEDTLS_PRIVATE(in_buf) = buf;
|
||||
ssl->MBEDTLS_PRIVATE(in_ctr) = ssl->MBEDTLS_PRIVATE(in_buf);
|
||||
@@ -143,7 +149,7 @@ static void init_rx_buffer(mbedtls_ssl_context *ssl, unsigned char *buf)
|
||||
ssl->MBEDTLS_PRIVATE(in_iv) = ssl->MBEDTLS_PRIVATE(in_buf) + MBEDTLS_SSL_HEADER_LEN;
|
||||
ssl->MBEDTLS_PRIVATE(in_msg) = ssl->MBEDTLS_PRIVATE(in_buf) + in_msg_off;
|
||||
|
||||
ESP_LOGV(TAG, "in msg offset is %d", in_msg_off);
|
||||
ESP_LOGV(TAG, "in msg offset is %u", (unsigned)in_msg_off);
|
||||
}
|
||||
|
||||
ssl->MBEDTLS_PRIVATE(in_msgtype) = 0;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "soc/hwcrypto_periph.h"
|
||||
#include "ecc_impl.h"
|
||||
#include "hal/ecc_ll.h"
|
||||
@@ -118,8 +117,10 @@ int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp,
|
||||
|
||||
mbedtls_platform_zeroize((void *)&point, sizeof(ecc_point_t));
|
||||
|
||||
memcpy(&point.x, pt->MBEDTLS_PRIVATE(X).MBEDTLS_PRIVATE(p), mbedtls_mpi_size(&pt->MBEDTLS_PRIVATE(X)));
|
||||
memcpy(&point.y, pt->MBEDTLS_PRIVATE(Y).MBEDTLS_PRIVATE(p), mbedtls_mpi_size(&pt->MBEDTLS_PRIVATE(Y)));
|
||||
if (mbedtls_mpi_write_binary_le(&pt->MBEDTLS_PRIVATE(X), point.x, sizeof(point.x)) != 0 ||
|
||||
mbedtls_mpi_write_binary_le(&pt->MBEDTLS_PRIVATE(Y), point.y, sizeof(point.y)) != 0) {
|
||||
return MBEDTLS_ERR_ECP_INVALID_KEY;
|
||||
}
|
||||
|
||||
point.len = grp->pbits / 8;
|
||||
|
||||
|
||||
@@ -40,6 +40,10 @@ typedef struct {
|
||||
const unsigned char *aad; /*!< The additional data. */
|
||||
esp_aes_context aes_ctx;
|
||||
esp_aes_gcm_state gcm_state;
|
||||
size_t nc_off; /*!< CTR keystream offset carried across update calls. */
|
||||
uint8_t stream_block[16]; /*!< CTR keystream residual carried across update calls. */
|
||||
uint8_t ghash_buf[16]; /*!< Partial (< 16 B) block pending GHASH. */
|
||||
size_t ghash_buf_len; /*!< Number of valid bytes in ghash_buf (0..15). */
|
||||
/* Software context needed for soft fallback for non-AES ciphers */
|
||||
void *ctx_soft;
|
||||
} esp_gcm_context;
|
||||
|
||||
@@ -181,6 +181,133 @@ TEST_CASE("mbedtls GCM stream test", "[aes-gcm]")
|
||||
free(decryptedtext);
|
||||
}
|
||||
|
||||
/* Drive a multipart AEAD encryption feeding AAD in aad_step-byte chunks and
|
||||
* plaintext in data_step-byte chunks (deliberately non-block-aligned). */
|
||||
static void gcm_encrypt_chunked(psa_key_id_t key_id, const uint8_t *nonce, size_t nonce_len,
|
||||
const uint8_t *aad, size_t aad_len, size_t aad_step,
|
||||
const uint8_t *pt, size_t len, size_t data_step,
|
||||
uint8_t *ct, size_t ct_size, uint8_t *tag, size_t *tag_len)
|
||||
{
|
||||
psa_aead_operation_t op = PSA_AEAD_OPERATION_INIT;
|
||||
size_t olen, total = 0;
|
||||
|
||||
TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_encrypt_setup(&op, key_id, PSA_ALG_GCM));
|
||||
TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_set_nonce(&op, nonce, nonce_len));
|
||||
for (size_t i = 0; i < aad_len; i += aad_step) {
|
||||
TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_update_ad(&op, aad + i, MIN(aad_step, aad_len - i)));
|
||||
}
|
||||
for (size_t i = 0; i < len; i += data_step) {
|
||||
TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_update(&op, pt + i, MIN(data_step, len - i),
|
||||
ct + total, ct_size - total, &olen));
|
||||
total += olen;
|
||||
}
|
||||
TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_finish(&op, ct + total, ct_size - total, &olen, tag, 16, tag_len));
|
||||
total += olen;
|
||||
TEST_ASSERT_EQUAL(len, total);
|
||||
psa_aead_abort(&op);
|
||||
}
|
||||
|
||||
/* Multipart AEAD decrypt + verify, chunked the same non-block-aligned way. */
|
||||
static void gcm_decrypt_chunked(psa_key_id_t key_id, const uint8_t *nonce, size_t nonce_len,
|
||||
const uint8_t *aad, size_t aad_len, size_t aad_step,
|
||||
const uint8_t *ct, size_t len, size_t data_step,
|
||||
const uint8_t *tag, size_t tag_len, uint8_t *pt, size_t pt_size)
|
||||
{
|
||||
psa_aead_operation_t op = PSA_AEAD_OPERATION_INIT;
|
||||
size_t olen, total = 0;
|
||||
|
||||
TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_decrypt_setup(&op, key_id, PSA_ALG_GCM));
|
||||
TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_set_nonce(&op, nonce, nonce_len));
|
||||
for (size_t i = 0; i < aad_len; i += aad_step) {
|
||||
TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_update_ad(&op, aad + i, MIN(aad_step, aad_len - i)));
|
||||
}
|
||||
for (size_t i = 0; i < len; i += data_step) {
|
||||
TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_update(&op, ct + i, MIN(data_step, len - i),
|
||||
pt + total, pt_size - total, &olen));
|
||||
total += olen;
|
||||
}
|
||||
TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_verify(&op, pt + total, pt_size - total, &olen, tag, tag_len));
|
||||
total += olen;
|
||||
TEST_ASSERT_EQUAL(len, total);
|
||||
psa_aead_abort(&op);
|
||||
}
|
||||
|
||||
/* Regression test for the multipart GCM streaming bug: feeding a non-block-
|
||||
* aligned stream (and non-block-aligned AAD) across several update calls must
|
||||
* yield the same ciphertext and tag as a single one-shot operation over the
|
||||
* same bytes. The prior implementation reset the CTR keystream offset every
|
||||
* call and zero-padded each GHASH chunk independently, so both ciphertext and
|
||||
* tag diverged for any chunk size that was not a multiple of 16. */
|
||||
TEST_CASE("mbedtls GCM unaligned multipart matches one-shot", "[aes-gcm]")
|
||||
{
|
||||
const size_t SZ = 100;
|
||||
const size_t AAD_SZ = 30;
|
||||
psa_key_id_t key_id;
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
uint8_t nonce[12], key[16], tag[16];
|
||||
size_t tag_len;
|
||||
|
||||
uint8_t *plaintext = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
||||
uint8_t *aad = heap_caps_malloc(AAD_SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
||||
uint8_t *ref = heap_caps_malloc(SZ + 16, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
||||
uint8_t *ct = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
||||
uint8_t *dec = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
||||
TEST_ASSERT_NOT_NULL(plaintext);
|
||||
TEST_ASSERT_NOT_NULL(aad);
|
||||
TEST_ASSERT_NOT_NULL(ref);
|
||||
TEST_ASSERT_NOT_NULL(ct);
|
||||
TEST_ASSERT_NOT_NULL(dec);
|
||||
|
||||
for (size_t i = 0; i < SZ; i++) {
|
||||
plaintext[i] = (uint8_t)(i * 7 + 3);
|
||||
}
|
||||
for (size_t i = 0; i < AAD_SZ; i++) {
|
||||
aad[i] = (uint8_t)(i * 5 + 1);
|
||||
}
|
||||
memset(nonce, 0x24, sizeof(nonce));
|
||||
memset(key, 0x9a, sizeof(key));
|
||||
|
||||
TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_crypto_init());
|
||||
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
|
||||
psa_set_key_algorithm(&attributes, PSA_ALG_GCM);
|
||||
psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
|
||||
psa_set_key_bits(&attributes, 128);
|
||||
TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_import_key(&attributes, key, 16, &key_id));
|
||||
|
||||
/* One-shot reference: ciphertext followed by the 16-byte tag. */
|
||||
size_t ref_len = 0;
|
||||
TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_aead_encrypt(key_id, PSA_ALG_GCM, nonce, sizeof(nonce),
|
||||
aad, AAD_SZ, plaintext, SZ, ref, SZ + 16, &ref_len));
|
||||
TEST_ASSERT_EQUAL(SZ + 16, ref_len);
|
||||
|
||||
const size_t data_steps[] = {1, 7, 13, 20};
|
||||
const size_t aad_steps[] = {1, 7, 13};
|
||||
for (size_t d = 0; d < sizeof(data_steps) / sizeof(data_steps[0]); d++) {
|
||||
for (size_t a = 0; a < sizeof(aad_steps) / sizeof(aad_steps[0]); a++) {
|
||||
memset(ct, 0, SZ);
|
||||
memset(dec, 0, SZ);
|
||||
memset(tag, 0, sizeof(tag));
|
||||
|
||||
gcm_encrypt_chunked(key_id, nonce, sizeof(nonce), aad, AAD_SZ, aad_steps[a],
|
||||
plaintext, SZ, data_steps[d], ct, SZ, tag, &tag_len);
|
||||
TEST_ASSERT_EQUAL(16, tag_len);
|
||||
TEST_ASSERT_EQUAL_HEX8_ARRAY(ref, ct, SZ);
|
||||
TEST_ASSERT_EQUAL_HEX8_ARRAY(ref + SZ, tag, 16);
|
||||
|
||||
gcm_decrypt_chunked(key_id, nonce, sizeof(nonce), aad, AAD_SZ, aad_steps[a],
|
||||
ct, SZ, data_steps[d], tag, tag_len, dec, SZ);
|
||||
TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, dec, SZ);
|
||||
}
|
||||
}
|
||||
|
||||
psa_destroy_key(key_id);
|
||||
free(plaintext);
|
||||
free(aad);
|
||||
free(ref);
|
||||
free(ct);
|
||||
free(dec);
|
||||
}
|
||||
|
||||
// Note: PSA Crypto API does not provide a direct equivalent to mbedtls_gcm_self_test()
|
||||
// The self-test functionality is validated through the individual test cases below
|
||||
|
||||
|
||||
Reference in New Issue
Block a user