Xilinx Versal Gen2 ASU port: split AES-CTR at the 32-bit counter wrap and carry in software to keep it on hardware

This commit is contained in:
night1rider
2026-08-08 14:35:12 -06:00
parent 8f5137c08a
commit 0066461776
3 changed files with 49 additions and 26 deletions
+1
View File
@@ -1092,6 +1092,7 @@ WOLFSSL_VALIDATE_DH_KEYGEN
WOLFSSL_VAULTIC_DEBUG
WOLFSSL_VERSAL_GEN2_ASU
WOLFSSL_VERSAL_GEN2_ASU_CCM_ALIGN_DECLINE
WOLFSSL_VERSAL_GEN2_ASU_CTR_WRAP_HW_FIXED
WOLFSSL_VERSAL_GEN2_ASU_RTC
WOLFSSL_VERSAL_GEN2_ASU_TRNG_DIRECT
WOLFSSL_WC_SLHDSA_RECURSIVE
@@ -217,15 +217,26 @@ static int wc_AsuCipherEcb(wc_CryptoInfo* info)
}
#ifdef WOLFSSL_AES_COUNTER
/* AES-CTR (counter in aes->reg). The ASU counts differently than wolfSSL once
* the low 32 counter bits wrap around, so that case runs in software. */
/* Add n to the 16-byte counter, starting at the last byte and carrying toward
* the first, so it matches wolfSSL's software counter. */
static void wc_AsuCtrAdd(byte* ctr, word32 n)
{
word32 carry = n;
int i;
for (i = WC_AES_BLOCK_SIZE - 1; (i >= 0) && (carry != 0); i--) {
carry += (word32)ctr[i];
ctr[i] = (byte)carry;
carry >>= 8;
}
}
/* AES-CTR. The ASU only counts the last 4 bytes of the counter and cannot carry
* past them, so we split the work there and add the carry in software. */
static int wc_AsuCipherCtr(wc_CryptoInfo* info)
{
byte* ctr;
word32 blocks;
word32 carry;
int ret;
int i;
if (info == NULL || info->cipher.aesctr.aes == NULL ||
info->cipher.aesctr.out == NULL || info->cipher.aesctr.in == NULL) {
@@ -234,31 +245,48 @@ static int wc_AsuCipherCtr(wc_CryptoInfo* info)
/* Partly-used keystream from an earlier call lives in the Aes context and
* the ASU always starts fresh, so those calls run in software. */
if (info->cipher.aesctr.aes->left != 0 || info->cipher.aesctr.sz == 0 ||
(info->cipher.aesctr.sz % WC_AES_BLOCK_SIZE) != 0) {
(info->cipher.aesctr.sz % WC_AES_BLOCK_SIZE) != 0 ||
info->cipher.aesctr.sz > XASU_ASU_DMA_MAX_TRANSFER_LENGTH) {
return CRYPTOCB_UNAVAILABLE;
}
/* The ASU counts only the low 32 bits of the counter and wraps them to zero,
* while wolfSSL software carries across the full 128 bits. */
ctr = (byte*)info->cipher.aesctr.aes->reg;
blocks = info->cipher.aesctr.sz / WC_AES_BLOCK_SIZE;
/* CTR encrypt and decrypt are the same operation, so always run encrypt. */
/* Default: do the split. Define this macro on a firmware that carries the
* whole 128-bit counter to skip the split and use one hardware call. */
#ifndef WOLFSSL_VERSAL_GEN2_ASU_CTR_WRAP_HW_FIXED
{
word32 off = 0;
word32 remaining = blocks;
while (remaining != 0) {
word32 low = ((word32)ctr[12] << 24) | ((word32)ctr[13] << 16) |
((word32)ctr[14] << 8) | (word32)ctr[15];
/* How many blocks fit before the last 4 bytes roll over. */
word64 toWrap = (word64)0x100000000ULL - (word64)low;
word32 chunk = ((word64)remaining < toWrap) ? remaining
: (word32)toWrap;
/* CTR encrypt and decrypt are the same op, so always run encrypt. */
ret = wc_AsuCipherOneShot(info->cipher.aesctr.aes,
info->cipher.aesctr.out + off, info->cipher.aesctr.in + off,
chunk * WC_AES_BLOCK_SIZE, 1, (u8)XASU_AES_CTR_MODE, ctr);
if (ret != 0) {
return ret;
}
wc_AsuCtrAdd(ctr, chunk);
off += chunk * WC_AES_BLOCK_SIZE;
remaining -= chunk;
}
}
#else
ret = wc_AsuCipherOneShot(info->cipher.aesctr.aes, info->cipher.aesctr.out,
info->cipher.aesctr.in, info->cipher.aesctr.sz, 1,
(u8)XASU_AES_CTR_MODE, ctr);
if (ret != 0) {
return ret;
}
/* Add the block count to the counter for the next call: start at the last
* byte (ctr[15]) and carry toward the first, matching wolfSSL software. */
carry = blocks;
for (i = WC_AES_BLOCK_SIZE - 1; (i >= 0) && (carry != 0); i--) {
carry += (word32)ctr[i];
ctr[i] = (byte)carry;
carry >>= 8;
}
wc_AsuCtrAdd(ctr, blocks);
#endif
return 0;
}
+3 -9
View File
@@ -15508,8 +15508,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_ctr_test(void)
ctrPlain, (int)sizeof(oddCipher), ctr128Cipher },
/* and an additional 9 bytes to reuse tmp left buffer */
{ NULL, 0, NULL, ctrPlain, (int)sizeof(oddCipher), oddCipher },
/* NO_AES_CTR_WRAP_TEST disables testing counter wrap on the low 32 bits. */
#ifndef NO_AES_CTR_WRAP_TEST
/* Counter wrapping */
#ifndef WOLFSSL_NXP_HASHCRYPT_AES
{ ctr128Key, (int)sizeof(ctr128Key), ctrIvWrap128,
ctrPlain, (int)sizeof(ctr128Wrap128Cipher), ctr128Wrap128Cipher },
@@ -15546,7 +15545,6 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_ctr_test(void)
ctrPlain, (int)sizeof(ctr128Wrap32_2CipherLong),
ctr128Wrap32_2CipherLong },
#endif
#endif /* !NO_AES_CTR_WRAP_TEST */
#endif
#ifdef WOLFSSL_AES_192
{ ctr192Key, (int)sizeof(ctr192Key), ctrIv,
@@ -15554,8 +15552,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_ctr_test(void)
/* let's try with just 9 bytes, non block size test */
{ ctr192Key, (int)sizeof(ctr192Key), ctrIv,
ctrPlain, (int)sizeof(oddCipher), ctr192Cipher },
/* NO_AES_CTR_WRAP_TEST disables testing counter wrap on the low 32 bits. */
#ifndef NO_AES_CTR_WRAP_TEST
/* Counter wrapping */
#ifndef WOLFSSL_NXP_HASHCRYPT_AES
{ ctr192Key, (int)sizeof(ctr192Key), ctrIvWrap128,
ctrPlain, (int)sizeof(ctr192Wrap128Cipher), ctr192Wrap128Cipher },
@@ -15592,7 +15589,6 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_ctr_test(void)
ctrPlain, (int)sizeof(ctr192Wrap32_2CipherLong),
ctr192Wrap32_2CipherLong },
#endif
#endif /* !NO_AES_CTR_WRAP_TEST */
#endif
#ifdef WOLFSSL_AES_256
{ ctr256Key, (int)sizeof(ctr256Key), ctrIv,
@@ -15600,8 +15596,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_ctr_test(void)
/* let's try with just 9 bytes, non block size test */
{ ctr256Key, (int)sizeof(ctr256Key), ctrIv,
ctrPlain, (int)sizeof(oddCipher), ctr256Cipher },
/* NO_AES_CTR_WRAP_TEST disables testing counter wrap on the low 32 bits. */
#ifndef NO_AES_CTR_WRAP_TEST
/* Counter wrapping */
#ifndef WOLFSSL_NXP_HASHCRYPT_AES
{ ctr256Key, (int)sizeof(ctr256Key), ctrIvWrap128,
ctrPlain, (int)sizeof(ctr256Wrap128Cipher), ctr256Wrap128Cipher },
@@ -15638,7 +15633,6 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_ctr_test(void)
ctrPlain, (int)sizeof(ctr256Wrap32_2CipherLong),
ctr256Wrap32_2CipherLong },
#endif
#endif /* !NO_AES_CTR_WRAP_TEST */
#endif
};
#define AES_CTR_TEST_LEN (int)(sizeof(testVec) / sizeof(*testVec))