Skip to content

Commit ff267c5

Browse files
amjoul01adeaarm
authored andcommitted
cc3xx: support multi-part AES CCM when tunneling is off
Perform AES CTR encryption prior to computing CBC-MAC in CCM mode. Also handle unaligned updates by correctly adjusting the input data. Change-Id: I87aece2bcb2e0a40e866a89ec236bbbd678518f6 Signed-off-by: Amjad Ouled-Ameur <[email protected]>
1 parent 44cb03a commit ff267c5

File tree

2 files changed

+157
-6
lines changed

2 files changed

+157
-6
lines changed

platform/ext/target/arm/drivers/cc3xx/psa_driver_api/src/cc3xx_internal_cipher.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,14 @@ psa_status_t cc3xx_internal_cipher_setup_set_iv(
364364
}
365365

366366
operation->iv_length = iv_length;
367+
368+
#if !defined(CC3XX_CONFIG_AES_TUNNELLING_ENABLE) && defined(PSA_WANT_ALG_CCM)
369+
if ((operation->key_type == PSA_KEY_TYPE_AES) &&
370+
(operation->aes.mode == CC3XX_AES_MODE_CCM)) {
371+
c3xx_lowlevel_aes_ccm_init_ctr((uint8_t *)operation->aes.ctr, iv, iv_length);
372+
}
373+
#endif /* !CC3XX_CONFIG_AES_TUNNELLING_ENABLE && PSA_WANT_ALG_CCM */
374+
367375
return PSA_SUCCESS;
368376
#endif /* PSA_WANT_KEY_TYPE_AES */
369377

platform/ext/target/arm/drivers/cc3xx/psa_driver_api/src/cc3xx_psa_aead.c

Lines changed: 149 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,102 @@ psa_status_t cc3xx_aead_update_ad(
393393
return PSA_ERROR_CORRUPTION_DETECTED;
394394
}
395395

396+
#if !defined(CC3XX_CONFIG_AES_TUNNELLING_ENABLE) && defined(PSA_WANT_ALG_CCM)
397+
/**
398+
* @brief Encrypt or decrypt a message fragment in an active AEAD AES-CCM operation.
399+
* This is only required when CryptoCell is operating in non-tunnelling
400+
* mode, in which case AES-CCM only computes the CBC-MAC tag, and thus a
401+
* separate AES-CTR call is required
402+
*
403+
* @param[in] operation Active AEAD operation.
404+
* @param[in] input Buffer containing the message fragment.
405+
* @param[in] input_length Size of the input buffer in bytes.
406+
* @param[out] output Buffer where the output is to be written.
407+
* @param[in] output_size Size of the output buffer in bytes.
408+
* @param[out] output_length The number of bytes that make up the output.
409+
* @param[in] block_buf_size_in_use Current AES DMA buffer usage in bytes.
410+
*
411+
* @return psa_status_t
412+
*/
413+
static psa_status_t cc3xx_aead_ccm_ctr_update(
414+
cc3xx_aead_operation_t *operation,
415+
const uint8_t *input,
416+
size_t input_length,
417+
uint8_t *output,
418+
size_t output_size,
419+
size_t *output_length,
420+
size_t block_buf_size_in_use)
421+
{
422+
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
423+
cc3xx_err_t err;
424+
struct cc3xx_aes_state_t *state = &operation->aes;
425+
size_t processed_bytes = 0;
426+
size_t counter_incr_val = (block_buf_size_in_use + input_length) / AES_BLOCK_SIZE;
427+
428+
err = cc3xx_lowlevel_aes_init(CC3XX_AES_DIRECTION_ENCRYPT,
429+
CC3XX_AES_MODE_CTR, CC3XX_AES_KEY_ID_USER_KEY,
430+
(uint32_t *)state->key_buf, state->key_size,
431+
(uint32_t *)state->ctr, AES_IV_LEN);
432+
if (err != CC3XX_ERR_SUCCESS) {
433+
return cc3xx_to_psa_err(err);
434+
}
435+
436+
if (block_buf_size_in_use > 0) {
437+
size_t partial_len = ((block_buf_size_in_use + input_length) < AES_BLOCK_SIZE) ?
438+
input_length : AES_BLOCK_SIZE - block_buf_size_in_use;
439+
uint8_t scratch_block[AES_BLOCK_SIZE] = {0};
440+
size_t current_output_size = cc3xx_lowlevel_aes_get_current_output_size();
441+
442+
cc3xx_lowlevel_aes_set_output_buffer(scratch_block, AES_BLOCK_SIZE);
443+
444+
err = cc3xx_lowlevel_aes_update(scratch_block, block_buf_size_in_use);
445+
if (err != CC3XX_ERR_SUCCESS) {
446+
return cc3xx_to_psa_err(err);
447+
}
448+
449+
err = cc3xx_lowlevel_aes_update(input, partial_len);
450+
if (err != CC3XX_ERR_SUCCESS) {
451+
return cc3xx_to_psa_err(err);
452+
}
453+
454+
cc3xx_lowlevel_dma_flush_buffer(false);
455+
456+
/* Write-back the partially-encrypted data */
457+
memcpy(output, scratch_block + block_buf_size_in_use, partial_len);
458+
459+
processed_bytes = cc3xx_lowlevel_aes_get_current_output_size() -
460+
(current_output_size + block_buf_size_in_use);
461+
}
462+
463+
if ((input_length - processed_bytes) > 0) {
464+
const uint8_t *remaining_input = input + processed_bytes;
465+
const size_t remaining_input_length = input_length - processed_bytes;
466+
uint8_t *remaining_output = output + processed_bytes;
467+
const size_t remaining_output_size = output_size - processed_bytes;
468+
size_t current_output_size = cc3xx_lowlevel_aes_get_current_output_size();
469+
470+
cc3xx_lowlevel_aes_set_output_buffer(remaining_output, remaining_output_size);
471+
472+
err = cc3xx_lowlevel_aes_update(remaining_input, remaining_input_length);
473+
if (err != CC3XX_ERR_SUCCESS) {
474+
return cc3xx_to_psa_err(err);
475+
}
476+
477+
cc3xx_lowlevel_dma_flush_buffer(false);
478+
479+
processed_bytes += cc3xx_lowlevel_aes_get_current_output_size() - current_output_size;
480+
}
481+
482+
*output_length += processed_bytes;
483+
484+
if (counter_incr_val > 0) {
485+
c3xx_lowlevel_aes_ccm_incr_ctr(state->ctr, counter_incr_val);
486+
}
487+
488+
return PSA_SUCCESS;
489+
}
490+
#endif /* !CC3XX_CONFIG_AES_TUNNELLING_ENABLE && PSA_WANT_ALG_CCM */
491+
396492
psa_status_t cc3xx_aead_update(
397493
cc3xx_aead_operation_t *operation,
398494
const uint8_t *input,
@@ -404,12 +500,46 @@ psa_status_t cc3xx_aead_update(
404500
cc3xx_err_t err;
405501
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
406502
size_t last_output_num_bytes = 0, current_output_size = 0;
503+
#if !defined(CC3XX_CONFIG_AES_TUNNELLING_ENABLE) && defined(PSA_WANT_ALG_CCM)
504+
bool ctr_required;
505+
size_t ctr_block_buf_size_in_use = 0;
506+
#endif /* !CC3XX_CONFIG_AES_TUNNELLING_ENABLE && PSA_WANT_ALG_CCM */
407507

408508
CC3XX_ASSERT(operation != NULL);
409509
CC3XX_ASSERT(input != NULL);
410510
CC3XX_ASSERT(output != NULL);
411511
CC3XX_ASSERT(output_length != NULL);
412512

513+
/* Initialize this length to a safe value that might be overridden */
514+
*output_length = 0;
515+
516+
#if !defined(CC3XX_CONFIG_AES_TUNNELLING_ENABLE) && defined(PSA_WANT_ALG_CCM)
517+
ctr_required = ((operation->key_type == PSA_KEY_TYPE_AES) &&
518+
(operation->aes.mode == CC3XX_AES_MODE_CCM) &&
519+
(input_length > 0 ) && (output_size > 0)) ? true : false;
520+
521+
if (ctr_required) {
522+
ctr_block_buf_size_in_use = (operation->aes.crypted_length > 0) ?
523+
operation->aes.dma_state.block_buf_size_in_use : 0;
524+
525+
if (operation->aes.direction == CC3XX_AES_DIRECTION_DECRYPT) {
526+
status = cc3xx_aead_ccm_ctr_update(operation,
527+
input,
528+
input_length,
529+
output,
530+
output_size,
531+
output_length,
532+
ctr_block_buf_size_in_use);
533+
if (status != PSA_SUCCESS) {
534+
return status;
535+
}
536+
537+
/* CBC-MAC computes the tag on plaintext data */
538+
input = output;
539+
}
540+
}
541+
#endif /* !CC3XX_CONFIG_AES_TUNNELLING_ENABLE && PSA_WANT_ALG_CCM */
542+
413543
/* This either restores the state or completes the init */
414544
status = cc3xx_internal_cipher_setup_complete(operation);
415545
if (status != PSA_SUCCESS) {
@@ -505,21 +635,34 @@ psa_status_t cc3xx_aead_update(
505635

506636
err = cc3xx_lowlevel_aes_update(input, input_length);
507637
if (err != CC3XX_ERR_SUCCESS) {
508-
status = cc3xx_to_psa_err(err);
509-
goto out_aes;
638+
cc3xx_lowlevel_aes_uninit();
639+
return cc3xx_to_psa_err(err);
510640
}
511641
current_output_size = cc3xx_lowlevel_aes_get_current_output_size();
512642

513-
*output_length = current_output_size - last_output_num_bytes;
643+
*output_length += current_output_size - last_output_num_bytes;
514644

515645
operation->last_output_num_bytes = current_output_size;
516646

517647
cc3xx_lowlevel_aes_get_state(&operation->aes);
518648

519-
status = PSA_SUCCESS;
520-
out_aes:
521649
cc3xx_lowlevel_aes_uninit();
522-
return status;
650+
651+
#if !defined(CC3XX_CONFIG_AES_TUNNELLING_ENABLE) && defined(PSA_WANT_ALG_CCM)
652+
if ((ctr_required) && (operation->aes.direction == CC3XX_AES_DIRECTION_ENCRYPT)) {
653+
status = cc3xx_aead_ccm_ctr_update(operation,
654+
input,
655+
input_length,
656+
output,
657+
output_size,
658+
output_length,
659+
ctr_block_buf_size_in_use);
660+
if (status != PSA_SUCCESS) {
661+
return status;
662+
}
663+
}
664+
#endif /* !CC3XX_CONFIG_AES_TUNNELLING_ENABLE && PSA_WANT_ALG_CCM */
665+
return PSA_SUCCESS;
523666
#endif /* PSA_WANT_KEY_TYPE_AES */
524667

525668
default:

0 commit comments

Comments
 (0)