Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,8 @@ static void create_aead_ccmheader(cracen_aead_operation_t *operation,
size_t m, l;

/* RFC3610 paragraph 2.2 defines the formatting of the first block.
* M, CCM TAG size is one of {4,6,8,10,12,14,16}, CCM* not supported
* (MAC size 0)
* M, CCM TAG size is one of {4,6,8,10,12,14,16}, or 0 for CCM* (IEEE
* P802.15-4/0537r2), in which case the M field is zero.
* L must be between 2 and 8.
* Nonce size should be between 7 and 13 bytes.
* The first block contains:
Expand All @@ -275,7 +275,8 @@ static void create_aead_ccmheader(cracen_aead_operation_t *operation,
l = 15 - operation->nonce_length;

flags = (operation->ad_length > 0) ? (1 << 6) : 0;
m = (operation->tag_size - 2) / 2;
/* CCM* encodes M=0 as a zero M field; (0 - 2) / 2 would underflow. */
m = operation->tag_size ? (operation->tag_size - 2) / 2 : 0;

flags |= (m & 0x7) << 3;
flags |= ((l - 1) & 0x7);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@
#include <cracen_sw_aes_ctr.h>
#endif

/* CCM* is only defined for L = 2, so its nonce is 15 - L octets and the counter
* field it leaves inside the 16-octet block is exactly 16 bits wide
* (IEEE P802.15-4/0537r2 clause 2.2.2 and clause 2.3.1).
*
* PSA_NEED_CRACEN_CTR_SIZE_WORKAROUNDS not needed because CCM* wants precisely the hardware CTR
* width. Adding CCM* to those blocks would replace working hardware with software.
*/
#define CCM_STAR_L 2
#define CCM_STAR_NONCE_LENGTH (SX_BLKCIPHER_IV_SZ - 1 - CCM_STAR_L)
Comment on lines +42 to +43

static bool is_alg_supported(psa_algorithm_t alg, const psa_key_attributes_t *attributes)
{
bool is_supported = false;
Expand Down Expand Up @@ -60,6 +70,10 @@ static bool is_alg_supported(psa_algorithm_t alg, const psa_key_attributes_t *at
IF_ENABLED(PSA_NEED_CRACEN_CTR_AES,
(is_supported = psa_get_key_type(attributes) == PSA_KEY_TYPE_AES));
break;
case PSA_ALG_CCM_STAR_NO_TAG:
IF_ENABLED(PSA_NEED_CRACEN_CCM_STAR_NO_TAG_AES,
(is_supported = psa_get_key_type(attributes) == PSA_KEY_TYPE_AES));
break;
case PSA_ALG_ECB_NO_PADDING:
IF_ENABLED(PSA_NEED_CRACEN_ECB_NO_PADDING_AES,
(is_supported = psa_get_key_type(attributes) == PSA_KEY_TYPE_AES));
Expand Down Expand Up @@ -240,6 +254,22 @@ psa_status_t cracen_cipher_encrypt(const psa_key_attributes_t *attributes,
output_length);
}

static size_t single_part_iv_size(psa_algorithm_t alg)
{
if (alg == PSA_ALG_STREAM_CIPHER) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly return a removed comment stating the following?

"ChaCha20 only supports 12 bytes IV in the single part decryption function"

Or how do you feel about moving this value to some macro? There are also other places in this file where it is used (e.g. in cracen_cipher_set_iv() ).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense.

return 12;
}

/* CCM* has a 13-octet nonce because L is fixed at 2; everything else prepends a full cipher
* block.
Comment on lines +263 to +264

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make more sense to have this comment where CCM_STAR_NONCE_LENGTH is defined as here we are just using it without knowing anything about its value?

*/
if (IS_ENABLED(PSA_NEED_CRACEN_CCM_STAR_NO_TAG_AES) && alg == PSA_ALG_CCM_STAR_NO_TAG) {
return CCM_STAR_NONCE_LENGTH;
}

return SX_BLKCIPHER_IV_SZ;
}

psa_status_t cracen_cipher_decrypt(const psa_key_attributes_t *attributes,
const uint8_t *key_buffer, size_t key_buffer_size,
psa_algorithm_t alg, const uint8_t *input, size_t input_length,
Expand All @@ -251,8 +281,7 @@ psa_status_t cracen_cipher_decrypt(const psa_key_attributes_t *attributes,

cracen_cipher_operation_t operation = {0};
psa_status_t status;
/* ChaCha20 only supports 12 bytes IV in the single part decryption function */
const size_t iv_size = (alg == PSA_ALG_STREAM_CIPHER) ? 12 : SX_BLKCIPHER_IV_SZ;
const size_t iv_size = single_part_iv_size(alg);
*output_length = 0;

#if defined(PSA_NEED_CRACEN_CTR_SIZE_WORKAROUNDS) && defined(PSA_NEED_CRACEN_CTR_AES)
Expand Down Expand Up @@ -353,6 +382,17 @@ static psa_status_t initialize_cipher(cracen_cipher_operation_t *operation)
operation->iv);
}
break;
case PSA_ALG_CCM_STAR_NO_TAG:
if (IS_ENABLED(PSA_NEED_CRACEN_CCM_STAR_NO_TAG_AES)) {
sx_status = operation->dir == CRACEN_DECRYPT
? sx_blkcipher_create_aesctr_dec(&operation->cipher,
&operation->keyref,
operation->iv)
Comment on lines +387 to +390
: sx_blkcipher_create_aesctr_enc(&operation->cipher,
&operation->keyref,
operation->iv);
}
break;
Comment on lines +385 to +395

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could just reuse the PSA_ALG_CTR case? what we could have is IF_DEFINED(PSA_NEED_X, (case PSA_ALG_Y:))

case PSA_ALG_STREAM_CIPHER:
if (IS_ENABLED(PSA_NEED_CRACEN_STREAM_CIPHER_CHACHA20)) {
sx_status = operation->dir == CRACEN_DECRYPT
Expand Down Expand Up @@ -440,6 +480,26 @@ psa_status_t cracen_cipher_set_iv(cracen_cipher_operation_t *operation, const ui
}
}

/* CCM* with a zero-length authentication field is AES-CTR over the
* counter blocks A_i = Flags || Nonce || i, starting at i = 1, where
* Flags holds L-1 in its low three bits and zero elsewhere (IEEE
* P802.15-4/0537r2 clause 2.3.1.3). CCM* fixes L = 2, hence the
* 13-octet nonce that PSA_CIPHER_IV_LENGTH reports for this algorithm.
*/
if (IS_ENABLED(PSA_NEED_CRACEN_CCM_STAR_NO_TAG_AES) &&
operation->alg == PSA_ALG_CCM_STAR_NO_TAG) {
if (iv_length != CCM_STAR_NONCE_LENGTH) {
return PSA_ERROR_INVALID_ARGUMENT;
}

operation->iv[0] = CCM_STAR_L - 1;
memcpy(&operation->iv[1], iv, CCM_STAR_NONCE_LENGTH);
operation->iv[14] = 0;
operation->iv[15] = 1;
Comment on lines +495 to +498

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a mix of define (CCM_STAR_NONCE_LENGTH) and magic values is not great, rather error-prone. Either use only one, or use a local variable to move the pointer every time too?


return PSA_SUCCESS;
}

if (iv_length != SX_BLKCIPHER_IV_SZ) {
return PSA_ERROR_INVALID_ARGUMENT;
}
Expand Down