Skip to content

Commit e655e6b

Browse files
committed
nrf_security: drivers: cracen: make single-part AEAD operations single-part
Make the single-part AEAD operations not use HW context switching (save/wait/resume). As a bonus, make CCM-specific code depend on `PSA_NEED_CRACEN_CCM_AES` so that it gets compiled out if CCM is disabled. ref: NCSDK-31362 Signed-off-by: Tomi Fontanilles <tomi.fontanilles@nordicsemi.no>
1 parent 889f929 commit e655e6b

File tree

2 files changed

+135
-61
lines changed

2 files changed

+135
-61
lines changed

subsys/nrf_security/src/drivers/cracen/cracenpsa/src/aead.c

+134-59
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,16 @@
1414
#include <sxsymcrypt/chachapoly.h>
1515
#include <sxsymcrypt/internal.h>
1616
#include <sxsymcrypt/keyref.h>
17+
#include <cracen/mem_helpers.h>
1718
#include <cracen/statuscodes.h>
1819
#include <zephyr/sys/__assert.h>
19-
2020
#include "common.h"
21-
#include <cracen/mem_helpers.h>
2221

2322
/* CCM, GCM and ChaCha20-Poly1305 have 16 byte tags by default */
2423
#define DEFAULT_TAG_SIZE 16
2524

25+
#define CCM_HEADER_MAX_LENGTH 26
26+
2627
/*
2728
* This function assumes it is given a valid algorithm for aead.
2829
*/
@@ -57,8 +58,10 @@ static bool is_nonce_length_supported(psa_algorithm_t alg, size_t nonce_length)
5758
case PSA_ALG_GCM:
5859
case PSA_ALG_CHACHA20_POLY1305:
5960
return nonce_length == 12u;
61+
#ifdef PSA_NEED_CRACEN_CCM_AES
6062
case PSA_ALG_CCM:
6163
return sx_aead_aesccm_nonce_size_is_valid(nonce_length);
64+
#endif
6265
}
6366

6467
return false;
@@ -195,12 +198,12 @@ static void cracen_writebe(uint8_t *out, uint64_t data, uint16_t targetsz)
195198
}
196199
}
197200

198-
static psa_status_t create_aead_ccmheader(cracen_aead_operation_t *operation)
201+
static void create_aead_ccmheader(cracen_aead_operation_t *operation,
202+
uint8_t header[static CCM_HEADER_MAX_LENGTH],
203+
size_t *header_length)
199204
{
200205
uint8_t flags;
201206
size_t m, l;
202-
uint8_t header[26] = {0};
203-
size_t header_size = 16;
204207

205208
/* RFC3610 paragraph 2.2 defines the formatting of the first block.
206209
* M, CCM TAG size is one of {4,6,8,10,12,14,16}, CCM* not supported
@@ -232,28 +235,27 @@ static psa_status_t create_aead_ccmheader(cracen_aead_operation_t *operation)
232235

233236
cracen_writebe(&(header[1 + operation->nonce_length]), operation->plaintext_length, l);
234237

238+
*header_length = 16;
235239
/*
236240
* If there is additional authentication data, encode the size into
237241
* bytes [16, 17/21/25] depending on the length
238242
*/
239243
if (operation->ad_length > 0) {
240244
if (operation->ad_length < 0xFF00) {
241245
cracen_writebe(&header[16], operation->ad_length, 2);
242-
header_size += 2;
246+
*header_length += 2;
243247
} else if (operation->ad_length <= 0xFFFFFFFF) {
244248
header[16] = 0xFF;
245249
header[17] = 0xFE;
246250
cracen_writebe(&header[18], operation->ad_length, 4);
247-
header_size += 6;
251+
*header_length += 6;
248252
} else {
249253
header[16] = 0xFF;
250254
header[17] = 0xFF;
251255
cracen_writebe(&header[18], operation->ad_length, 8);
252-
header_size += 10;
256+
*header_length += 10;
253257
}
254258
}
255-
256-
return cracen_aead_update_ad(operation, header, header_size);
257259
}
258260

259261
static psa_status_t setup(cracen_aead_operation_t *operation, enum cipher_operation dir,
@@ -343,8 +345,8 @@ psa_status_t cracen_aead_decrypt_setup(cracen_aead_operation_t *operation,
343345
return setup(operation, CRACEN_DECRYPT, attributes, key_buffer, key_buffer_size, alg);
344346
}
345347

346-
psa_status_t cracen_aead_set_nonce(cracen_aead_operation_t *operation, const uint8_t *nonce,
347-
size_t nonce_length)
348+
static psa_status_t set_nonce(cracen_aead_operation_t *operation, const uint8_t *nonce,
349+
size_t nonce_length)
348350
{
349351
if (!is_nonce_length_supported(operation->alg, nonce_length)) {
350352
return PSA_ERROR_NOT_SUPPORTED;
@@ -353,9 +355,26 @@ psa_status_t cracen_aead_set_nonce(cracen_aead_operation_t *operation, const uin
353355
memcpy(operation->nonce, nonce, nonce_length);
354356
operation->nonce_length = nonce_length;
355357

358+
return PSA_SUCCESS;
359+
}
360+
361+
psa_status_t cracen_aead_set_nonce(cracen_aead_operation_t *operation, const uint8_t *nonce,
362+
size_t nonce_length)
363+
{
364+
psa_status_t status;
365+
366+
status = set_nonce(operation, nonce, nonce_length);
367+
if (status != PSA_SUCCESS) {
368+
return status;
369+
}
370+
356371
/* Create the CCM header */
357-
if (operation->alg == PSA_ALG_CCM) {
358-
return create_aead_ccmheader(operation);
372+
if (IS_ENABLED(PSA_NEED_CRACEN_CCM_AES) && operation->alg == PSA_ALG_CCM) {
373+
uint8_t ccm_header[CCM_HEADER_MAX_LENGTH];
374+
size_t ccm_header_length;
375+
376+
create_aead_ccmheader(operation, ccm_header, &ccm_header_length);
377+
return cracen_aead_update_ad(operation, ccm_header, ccm_header_length);
359378
}
360379

361380
return PSA_SUCCESS;
@@ -428,13 +447,14 @@ static psa_status_t cracen_aead_update_internal(cracen_aead_operation_t *operati
428447
/* Clamp input length to a multiple of the block size. */
429448
blk_bytes = input_length & ~(get_block_size(operation->alg) - 1);
430449

431-
/* For CCM, sxsymcrypt driver needs a chunk of input data to produce a tag
450+
/* For CCM, in multi-part mode sxsymcrypt needs a chunk of input data to produce a tag
432451
* therefore we buffer the last block until finish will be called.
433452
* blk_bytes tracks the amount of block-sized input that will be
434453
* processed immediately. So to buffer the input and prevent processing
435454
* we subtract one block from blk_bytes.
436455
*/
437-
if (operation->alg == PSA_ALG_CCM && input_length != 0 && blk_bytes == input_length) {
456+
if (IS_ENABLED(PSA_NEED_CRACEN_CCM_AES) &&
457+
operation->alg == PSA_ALG_CCM && input_length != 0 && blk_bytes == input_length) {
438458
blk_bytes -= get_block_size(operation->alg);
439459
}
440460

@@ -607,7 +627,7 @@ psa_status_t cracen_aead_verify(cracen_aead_operation_t *operation, uint8_t *pla
607627

608628
safe_memzero((void *)operation, sizeof(cracen_aead_operation_t));
609629

610-
return silex_statuscodes_to_psa(sx_status);
630+
return PSA_SUCCESS;
611631
}
612632

613633
psa_status_t cracen_aead_abort(cracen_aead_operation_t *operation)
@@ -616,6 +636,49 @@ psa_status_t cracen_aead_abort(cracen_aead_operation_t *operation)
616636
return PSA_SUCCESS;
617637
}
618638

639+
static psa_status_t feed_singlepart_ccm_aad(cracen_aead_operation_t *operation,
640+
const uint8_t *additional_data,
641+
size_t additional_data_length)
642+
{
643+
psa_status_t status;
644+
/* Data fed to CRACEN needs to remain untouched until it's been consumed
645+
* (sx_aead_wait()), so don't put the CCM header buffer on the stack.
646+
*/
647+
static uint8_t ccm_header_aad[ROUND_UP(CCM_HEADER_MAX_LENGTH,
648+
PSA_BLOCK_CIPHER_BLOCK_LENGTH(PSA_KEY_TYPE_AES))];
649+
size_t ccm_header_length;
650+
size_t aad_fed_count;
651+
652+
create_aead_ccmheader(operation, ccm_header_aad, &ccm_header_length);
653+
654+
if (additional_data_length != 0) {
655+
/* Data fed to CRACEN needs to be block size-aligned, so
656+
* complete the header with the beginning of the user-provided AAD.
657+
*/
658+
aad_fed_count = MIN(additional_data_length,
659+
sizeof(ccm_header_aad) - ccm_header_length);
660+
memcpy(ccm_header_aad + ccm_header_length, additional_data, aad_fed_count);
661+
} else {
662+
aad_fed_count = 0;
663+
}
664+
665+
status = cracen_feed_data_to_hw(operation, ccm_header_aad,
666+
ccm_header_length + aad_fed_count, NULL, true);
667+
if (status != PSA_SUCCESS) {
668+
return status;
669+
}
670+
671+
if (additional_data_length != aad_fed_count) {
672+
/* Feed the rest of the user-provided AAD.
673+
* The last feeding doesn't need to be block size-aligned.
674+
*/
675+
status = cracen_feed_data_to_hw(operation, additional_data + aad_fed_count,
676+
additional_data_length - aad_fed_count, NULL, true);
677+
}
678+
679+
return status;
680+
}
681+
619682
psa_status_t cracen_aead_encrypt(const psa_key_attributes_t *attributes, const uint8_t *key_buffer,
620683
size_t key_buffer_size, psa_algorithm_t alg, const uint8_t *nonce,
621684
size_t nonce_length, const uint8_t *additional_data,
@@ -625,57 +688,57 @@ psa_status_t cracen_aead_encrypt(const psa_key_attributes_t *attributes, const u
625688
{
626689
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
627690
cracen_aead_operation_t operation = {0};
628-
size_t update_length = 0;
629-
uint8_t local_tag_buffer[PSA_AEAD_TAG_MAX_SIZE] = {0};
630-
size_t tag_length = 0;
691+
size_t tag_length;
631692

632-
status =
633-
cracen_aead_encrypt_setup(&operation, attributes, key_buffer, key_buffer_size, alg);
634-
if (status != PSA_SUCCESS) {
635-
goto error_exit;
693+
if (ciphertext_size < plaintext_length) {
694+
return PSA_ERROR_BUFFER_TOO_SMALL;
636695
}
637696

638-
status = cracen_aead_set_lengths(&operation, additional_data_length, plaintext_length);
697+
status = cracen_aead_encrypt_setup(&operation, attributes,
698+
key_buffer, key_buffer_size, alg);
639699
if (status != PSA_SUCCESS) {
640700
goto error_exit;
641701
}
642702

643-
status = cracen_aead_set_nonce(&operation, nonce, nonce_length);
703+
status = cracen_aead_set_lengths(&operation, additional_data_length, plaintext_length);
644704
if (status != PSA_SUCCESS) {
645705
goto error_exit;
646706
}
647707

648-
status = cracen_aead_update_ad(&operation, additional_data, additional_data_length);
708+
/* Do not call the cracen_aead_update*() functions to avoid using
709+
* HW context switching (process_on_hw()) in single-part operations.
710+
*/
711+
712+
status = set_nonce(&operation, nonce, nonce_length);
649713
if (status != PSA_SUCCESS) {
650714
goto error_exit;
651715
}
652716

653-
status = cracen_aead_update(&operation, plaintext, plaintext_length, ciphertext,
654-
ciphertext_size, ciphertext_length);
717+
if (IS_ENABLED(PSA_NEED_CRACEN_CCM_AES) && alg == PSA_ALG_CCM) {
718+
status = feed_singlepart_ccm_aad(&operation, additional_data,
719+
additional_data_length);
720+
} else {
721+
status = cracen_feed_data_to_hw(&operation, additional_data,
722+
additional_data_length, NULL, true);
723+
}
655724
if (status != PSA_SUCCESS) {
656-
*ciphertext_length = 0;
657725
goto error_exit;
658726
}
659727

660-
status = cracen_aead_finish(&operation, &ciphertext[*ciphertext_length],
661-
ciphertext_size - *ciphertext_length, &update_length,
662-
local_tag_buffer, sizeof(local_tag_buffer), &tag_length);
728+
status = cracen_feed_data_to_hw(&operation, plaintext, plaintext_length, ciphertext, false);
663729
if (status != PSA_SUCCESS) {
664-
*ciphertext_length = 0;
665730
goto error_exit;
666731
}
667-
*ciphertext_length += update_length;
668732

669-
/* Copy tag to the end of the ciphertext buffer, if big enough */
670-
if (*ciphertext_length + tag_length > ciphertext_size) {
671-
*ciphertext_length = 0;
672-
status = PSA_ERROR_BUFFER_TOO_SMALL;
733+
status = cracen_aead_finish(&operation, NULL, 0, NULL,
734+
&ciphertext[plaintext_length],
735+
ciphertext_size - plaintext_length, &tag_length);
736+
if (status != PSA_SUCCESS) {
673737
goto error_exit;
674738
}
675-
memcpy(&ciphertext[*ciphertext_length], &local_tag_buffer, tag_length);
676-
*ciphertext_length += tag_length;
677739

678-
return status;
740+
*ciphertext_length = plaintext_length + tag_length;
741+
return PSA_SUCCESS;
679742

680743
error_exit:
681744
cracen_aead_abort(&operation);
@@ -691,49 +754,61 @@ psa_status_t cracen_aead_decrypt(const psa_key_attributes_t *attributes, const u
691754
{
692755
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
693756
cracen_aead_operation_t operation = {0};
694-
size_t update_length = 0;
695757

696-
status =
697-
cracen_aead_decrypt_setup(&operation, attributes, key_buffer, key_buffer_size, alg);
758+
status = cracen_aead_decrypt_setup(&operation, attributes,
759+
key_buffer, key_buffer_size, alg);
698760
if (status != PSA_SUCCESS) {
699761
goto error_exit;
700762
}
701763

702-
status = cracen_aead_set_lengths(&operation, additional_data_length,
703-
ciphertext_length - operation.tag_size);
764+
*plaintext_length = ciphertext_length - operation.tag_size;
765+
766+
if (plaintext_size < *plaintext_length) {
767+
status = PSA_ERROR_BUFFER_TOO_SMALL;
768+
goto error_exit;
769+
}
770+
771+
status = cracen_aead_set_lengths(&operation, additional_data_length, *plaintext_length);
704772
if (status != PSA_SUCCESS) {
705773
goto error_exit;
706774
}
707775

708-
status = cracen_aead_set_nonce(&operation, nonce, nonce_length);
776+
/* Do not call the cracen_aead_update*() functions to avoid using
777+
* HW context switching (process_on_hw()) in single-part operations.
778+
*/
779+
780+
status = set_nonce(&operation, nonce, nonce_length);
709781
if (status != PSA_SUCCESS) {
710782
goto error_exit;
711783
}
712784

713-
status = cracen_aead_update_ad(&operation, additional_data, additional_data_length);
785+
if (IS_ENABLED(PSA_NEED_CRACEN_CCM_AES) && alg == PSA_ALG_CCM) {
786+
status = feed_singlepart_ccm_aad(&operation, additional_data,
787+
additional_data_length);
788+
} else {
789+
status = cracen_feed_data_to_hw(&operation, additional_data,
790+
additional_data_length, NULL, true);
791+
}
714792
if (status != PSA_SUCCESS) {
715793
goto error_exit;
716794
}
717795

718-
status = cracen_aead_update(&operation, ciphertext, ciphertext_length - operation.tag_size,
719-
plaintext, plaintext_size, plaintext_length);
796+
status = cracen_feed_data_to_hw(&operation, ciphertext,
797+
*plaintext_length, plaintext, false);
720798
if (status != PSA_SUCCESS) {
721-
*plaintext_length = 0;
722799
goto error_exit;
723800
}
724801

725-
status = cracen_aead_verify(&operation, &plaintext[*plaintext_length],
726-
plaintext_size - *plaintext_length, &update_length,
727-
&ciphertext[ciphertext_length - operation.tag_size],
728-
operation.tag_size);
802+
status = cracen_aead_verify(&operation, NULL, 0, NULL,
803+
&ciphertext[*plaintext_length], operation.tag_size);
729804
if (status != PSA_SUCCESS) {
730-
*plaintext_length = 0;
731805
goto error_exit;
732806
}
733-
*plaintext_length += update_length;
734807

735-
return status;
808+
return PSA_SUCCESS;
809+
736810
error_exit:
811+
*plaintext_length = 0;
737812
cracen_aead_abort(&operation);
738813
return status;
739814
}

subsys/nrf_security/src/drivers/cracen/cracenpsa/src/blkcipher.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,7 @@ static psa_status_t operation_setup(enum cipher_operation dir, cracen_cipher_ope
316316

317317
psa_status_t status = cracen_load_keyref(attributes, operation->key_buffer, key_buffer_size,
318318
&operation->keyref);
319-
320-
if (status) {
319+
if (status != PSA_SUCCESS) {
321320
return status;
322321
}
323322

0 commit comments

Comments
 (0)