Merge pull request #9315 from SparkiDev/aes_cfb_ofb_improv

AES: Improve CFB and OFB and add tests
This commit is contained in:
JacobBarthelmeh
2025-10-22 09:06:46 -06:00
committed by GitHub
5 changed files with 2400 additions and 290 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -26,10 +26,16 @@
int test_wc_AesSetKey(void);
int test_wc_AesSetIV(void);
int test_wc_AesEncryptDecryptDirect(void);
int test_wc_AesEcbEncryptDecrypt(void);
int test_wc_AesCbcEncryptDecrypt(void);
int test_wc_AesCfbEncryptDecrypt(void);
int test_wc_AesOfbEncryptDecrypt(void);
int test_wc_AesCtsEncryptDecrypt(void);
int test_wc_AesCtrSetKey(void);
int test_wc_AesCtrEncryptDecrypt(void);
int test_wc_AesGcmSetKey(void);
int test_wc_AesGcmEncryptDecrypt_Sizes(void);
int test_wc_AesGcmEncryptDecrypt(void);
int test_wc_AesGcmMixedEncDecLongIV(void);
int test_wc_AesGcmStream(void);
@@ -48,10 +54,16 @@ int test_wc_GmacUpdate(void);
#define TEST_AES_DECLS \
TEST_DECL_GROUP("aes", test_wc_AesSetKey), \
TEST_DECL_GROUP("aes", test_wc_AesSetIV), \
TEST_DECL_GROUP("aes", test_wc_AesEncryptDecryptDirect), \
TEST_DECL_GROUP("aes", test_wc_AesEcbEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesCbcEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesCfbEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesOfbEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesCtsEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesCtrSetKey), \
TEST_DECL_GROUP("aes", test_wc_AesCtrEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesGcmSetKey), \
TEST_DECL_GROUP("aes", test_wc_AesGcmEncryptDecrypt_Sizes), \
TEST_DECL_GROUP("aes", test_wc_AesGcmEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesGcmMixedEncDecLongIV), \
TEST_DECL_GROUP("aes", test_wc_AesGcmStream), \

View File

@@ -344,6 +344,19 @@
#define DoExpectBufEQ(x, y, z) DoExpectBuf(x, y, z, ==, !=)
#define DoExpectBufNE(x, y, z) DoExpectBuf(x, y, z, !=, ==)
#define ApiDumpData(name, data, len) do { \
int _i; \
fprintf(stderr, "%s: %d bytes\n", name, (int)(len)); \
for (_i = 0; _i < (int)(len); _i++) { \
fprintf(stderr, "0x%02x,", ((byte*)(data))[_i]); \
if ((_i & 7) == 7) fprintf(stderr, "\n"); \
else fprintf(stderr, " "); \
} \
if ((_i & 7) != 0) fprintf(stderr, "\n"); \
} while(0)
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \
!defined(NO_RSA) && \
!defined(NO_WOLFSSL_SERVER) && !defined(NO_WOLFSSL_CLIENT) && \

View File

@@ -5624,7 +5624,7 @@ void bench_aesecb(int useDeviceID)
#ifdef WOLFSSL_AES_CFB
static void bench_aescfb_internal(const byte* key,
word32 keySz, const byte* iv,
const char* label)
const char* label_enc, const char* label_dec)
{
Aes enc;
double start;
@@ -5662,11 +5662,44 @@ static void bench_aescfb_internal(const byte* key,
#endif
);
bench_stats_sym_finish(label, 0, count, bench_size, start, ret);
bench_stats_sym_finish(label_enc, 0, count, bench_size, start, ret);
#ifdef MULTI_VALUE_STATISTICS
bench_multi_value_stats(max, min, sum, squareSum, runs);
#endif
ret = wc_AesSetKey(&enc, key, keySz, iv, AES_DECRYPTION);
if (ret != 0) {
printf("AesSetKey failed, ret = %d\n", ret);
goto out;
}
#ifdef HAVE_AES_DECRYPT
RESET_MULTI_VALUE_STATS_VARS();
bench_stats_start(&count, &start);
do {
for (i = 0; i < numBlocks; i++) {
if((ret = wc_AesCfbDecrypt(&enc, bench_cipher, bench_plain,
bench_size)) != 0) {
printf("wc_AesCfbDecrypt failed, ret = %d\n", ret);
goto out;
}
RECORD_MULTI_VALUE_STATS();
}
count += i;
} while (bench_stats_check(start)
#ifdef MULTI_VALUE_STATISTICS
|| runs < minimum_runs
#endif
);
bench_stats_sym_finish(label_dec, 0, count, bench_size, start, ret);
#ifdef MULTI_VALUE_STATISTICS
bench_multi_value_stats(max, min, sum, squareSum, runs);
#endif
#endif
(void)label_dec;
out:
wc_AesFree(&enc);
@@ -5676,13 +5709,16 @@ out:
void bench_aescfb(void)
{
#ifdef WOLFSSL_AES_128
bench_aescfb_internal(bench_key, 16, bench_iv, "AES-128-CFB");
bench_aescfb_internal(bench_key, 16, bench_iv,
"AES-128-CFB-enc", "AES-128-CFB-dec");
#endif
#ifdef WOLFSSL_AES_192
bench_aescfb_internal(bench_key, 24, bench_iv, "AES-192-CFB");
bench_aescfb_internal(bench_key, 24, bench_iv,
"AES-192-CFB-enc", "AES-192-CFB-dec");
#endif
#ifdef WOLFSSL_AES_256
bench_aescfb_internal(bench_key, 32, bench_iv, "AES-256-CFB");
bench_aescfb_internal(bench_key, 32, bench_iv,
"AES-256-CFB-enc", "AES-256-CFB-dec");
#endif
}
#endif /* WOLFSSL_AES_CFB */
@@ -5691,7 +5727,7 @@ void bench_aescfb(void)
#ifdef WOLFSSL_AES_OFB
static void bench_aesofb_internal(const byte* key,
word32 keySz, const byte* iv,
const char* label)
const char* label_enc, const char* label_dec)
{
Aes enc;
double start;
@@ -5717,7 +5753,7 @@ static void bench_aesofb_internal(const byte* key,
for (i = 0; i < numBlocks; i++) {
if((ret = wc_AesOfbEncrypt(&enc, bench_plain, bench_cipher,
bench_size)) != 0) {
printf("wc_AesCfbEncrypt failed, ret = %d\n", ret);
printf("wc_AesOfbEncrypt failed, ret = %d\n", ret);
return;
}
RECORD_MULTI_VALUE_STATS();
@@ -5729,24 +5765,61 @@ static void bench_aesofb_internal(const byte* key,
#endif
);
bench_stats_sym_finish(label, 0, count, bench_size, start, ret);
bench_stats_sym_finish(label_enc, 0, count, bench_size, start, ret);
#ifdef MULTI_VALUE_STATISTICS
bench_multi_value_stats(max, min, sum, squareSum, runs);
#endif
ret = wc_AesSetKey(&enc, key, keySz, iv, AES_DECRYPTION);
if (ret != 0) {
printf("AesSetKey failed, ret = %d\n", ret);
return;
}
#ifdef HAVE_AES_DECRYPT
RESET_MULTI_VALUE_STATS_VARS();
bench_stats_start(&count, &start);
do {
for (i = 0; i < numBlocks; i++) {
if((ret = wc_AesOfbDecrypt(&enc, bench_cipher, bench_plain,
bench_size)) != 0) {
printf("wc_AesOfbDecrypt failed, ret = %d\n", ret);
return;
}
RECORD_MULTI_VALUE_STATS();
}
count += i;
} while (bench_stats_check(start)
#ifdef MULTI_VALUE_STATISTICS
|| runs < minimum_runs
#endif
);
bench_stats_sym_finish(label_dec, 0, count, bench_size, start, ret);
#ifdef MULTI_VALUE_STATISTICS
bench_multi_value_stats(max, min, sum, squareSum, runs);
#endif
#endif
(void)label_dec;
wc_AesFree(&enc);
}
void bench_aesofb(void)
{
#ifdef WOLFSSL_AES_128
bench_aesofb_internal(bench_key, 16, bench_iv, "AES-128-OFB");
bench_aesofb_internal(bench_key, 16, bench_iv,
"AES-128-OFB-enc", "AES-128-OFB-dec");
#endif
#ifdef WOLFSSL_AES_192
bench_aesofb_internal(bench_key, 24, bench_iv, "AES-192-OFB");
bench_aesofb_internal(bench_key, 24, bench_iv,
"AES-192-OFB-enc", "AES-192-OFB-dec");
#endif
#ifdef WOLFSSL_AES_256
bench_aesofb_internal(bench_key, 32, bench_iv, "AES-256-OFB");
bench_aesofb_internal(bench_key, 32, bench_iv,
"AES-256-OFB-enc", "AES-256-OFB-dec");
#endif
}
#endif /* WOLFSSL_AES_CFB */

View File

@@ -2903,10 +2903,6 @@ static WARN_UNUSED_RESULT int wc_AesEncrypt(
#endif
word32 r;
if (aes == NULL) {
return BAD_FUNC_ARG;
}
#ifdef WC_DEBUG_CIPHER_LIFECYCLE
{
int ret = wc_debug_CipherLifecycleCheck(aes->CipherLifecycleTag, 0);
@@ -3687,10 +3683,6 @@ static WARN_UNUSED_RESULT int wc_AesDecrypt(
#endif
word32 r;
if (aes == NULL) {
return BAD_FUNC_ARG;
}
#ifdef WC_DEBUG_CIPHER_LIFECYCLE
{
int ret = wc_debug_CipherLifecycleCheck(aes->CipherLifecycleTag, 0);
@@ -12265,7 +12257,7 @@ int wc_AesEcbDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
#endif
#endif /* HAVE_AES_ECB */
#if defined(WOLFSSL_AES_CFB) || defined(WOLFSSL_AES_OFB)
#if defined(WOLFSSL_AES_CFB)
/* Feedback AES mode
*
* aes structure holding key to use for encryption
@@ -12278,75 +12270,54 @@ int wc_AesEcbDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
* returns 0 on success and negative error values on failure
*/
/* Software AES - CFB Encrypt */
static WARN_UNUSED_RESULT int wc_AesFeedbackEncrypt(
Aes* aes, byte* out, const byte* in, word32 sz, byte mode)
static WARN_UNUSED_RESULT int AesCfbEncrypt_C(Aes* aes, byte* out,
const byte* in, word32 sz)
{
byte* tmp = NULL;
int ret = 0;
word32 processed;
if (aes == NULL || out == NULL || in == NULL) {
if ((aes == NULL) || (out == NULL) || (in == NULL)) {
return BAD_FUNC_ARG;
}
/* consume any unused bytes left in aes->tmp */
processed = min(aes->left, sz);
xorbufout(out, in, (byte*)aes->tmp + WC_AES_BLOCK_SIZE - aes->left, processed);
#ifdef WOLFSSL_AES_CFB
if (mode == AES_CFB_MODE) {
XMEMCPY((byte*)aes->reg + WC_AES_BLOCK_SIZE - aes->left, out, processed);
if (sz == 0) {
return 0;
}
if (aes->left > 0) {
/* consume any unused bytes left in aes->tmp */
processed = min(aes->left, sz);
xorbufout(out, in, (byte*)aes->tmp + WC_AES_BLOCK_SIZE - aes->left,
processed);
XMEMCPY((byte*)aes->reg + WC_AES_BLOCK_SIZE - aes->left, out,
processed);
aes->left -= processed;
out += processed;
in += processed;
sz -= processed;
}
#endif
aes->left -= processed;
out += processed;
in += processed;
sz -= processed;
VECTOR_REGISTERS_PUSH;
while (sz >= WC_AES_BLOCK_SIZE) {
/* Using aes->tmp here for inline case i.e. in=out */
ret = wc_AesEncryptDirect(aes, (byte*)aes->tmp, (byte*)aes->reg);
if (ret != 0)
ret = wc_AesEncryptDirect(aes, (byte*)aes->reg, (byte*)aes->reg);
if (ret != 0) {
break;
#ifdef WOLFSSL_AES_OFB
if (mode == AES_OFB_MODE) {
XMEMCPY(aes->reg, aes->tmp, WC_AES_BLOCK_SIZE);
}
#endif
xorbuf((byte*)aes->tmp, in, WC_AES_BLOCK_SIZE);
#ifdef WOLFSSL_AES_CFB
if (mode == AES_CFB_MODE) {
XMEMCPY(aes->reg, aes->tmp, WC_AES_BLOCK_SIZE);
}
#endif
XMEMCPY(out, aes->tmp, WC_AES_BLOCK_SIZE);
xorbuf((byte*)aes->reg, in, WC_AES_BLOCK_SIZE);
XMEMCPY(out, aes->reg, WC_AES_BLOCK_SIZE);
out += WC_AES_BLOCK_SIZE;
in += WC_AES_BLOCK_SIZE;
sz -= WC_AES_BLOCK_SIZE;
aes->left = 0;
}
/* encrypt left over data */
if ((ret == 0) && sz) {
ret = wc_AesEncryptDirect(aes, (byte*)aes->tmp, (byte*)aes->reg);
}
if ((ret == 0) && sz) {
aes->left = WC_AES_BLOCK_SIZE;
tmp = (byte*)aes->tmp;
#ifdef WOLFSSL_AES_OFB
if (mode == AES_OFB_MODE) {
XMEMCPY(aes->reg, aes->tmp, WC_AES_BLOCK_SIZE);
}
#endif
xorbufout(out, in, tmp, sz);
#ifdef WOLFSSL_AES_CFB
if (mode == AES_CFB_MODE) {
if (ret == 0) {
xorbufout(out, in, aes->tmp, sz);
XMEMCPY(aes->reg, out, sz);
aes->left = WC_AES_BLOCK_SIZE - sz;
}
#endif
aes->left -= sz;
}
VECTOR_REGISTERS_POP;
@@ -12355,7 +12326,7 @@ static WARN_UNUSED_RESULT int wc_AesFeedbackEncrypt(
}
#ifdef HAVE_AES_DECRYPT
#if defined(HAVE_AES_DECRYPT)
/* CFB 128
*
* aes structure holding key to use for decryption
@@ -12367,76 +12338,76 @@ static WARN_UNUSED_RESULT int wc_AesFeedbackEncrypt(
* returns 0 on success and negative error values on failure
*/
/* Software AES - CFB Decrypt */
static WARN_UNUSED_RESULT int wc_AesFeedbackDecrypt(
Aes* aes, byte* out, const byte* in, word32 sz, byte mode)
static WARN_UNUSED_RESULT int AesCfbDecrypt_C(Aes* aes, byte* out,
const byte* in, word32 sz, byte mode)
{
int ret = 0;
word32 processed;
if (aes == NULL || out == NULL || in == NULL) {
(void)mode;
if ((aes == NULL) || (out == NULL) || (in == NULL)) {
return BAD_FUNC_ARG;
}
#ifdef WOLFSSL_AES_CFB
/* check if more input needs copied over to aes->reg */
if (aes->left && sz && mode == AES_CFB_MODE) {
word32 size = min(aes->left, sz);
XMEMCPY((byte*)aes->reg + WC_AES_BLOCK_SIZE - aes->left, in, size);
if (sz == 0) {
return 0;
}
#endif
/* consume any unused bytes left in aes->tmp */
processed = min(aes->left, sz);
xorbufout(out, in, (byte*)aes->tmp + WC_AES_BLOCK_SIZE - aes->left,
processed);
aes->left -= processed;
out += processed;
in += processed;
sz -= processed;
if (aes->left > 0) {
/* consume any unused bytes left in aes->tmp */
processed = min(aes->left, sz);
/* copy input over to aes->reg */
XMEMCPY((byte*)aes->reg + WC_AES_BLOCK_SIZE - aes->left, in, processed);
xorbufout(out, in, (byte*)aes->tmp + WC_AES_BLOCK_SIZE - aes->left,
processed);
aes->left -= processed;
out += processed;
in += processed;
sz -= processed;
}
VECTOR_REGISTERS_PUSH;
while (sz > WC_AES_BLOCK_SIZE) {
/* Using aes->tmp here for inline case i.e. in=out */
#if !defined(WOLFSSL_SMALL_STACK) && defined(HAVE_AES_ECB) && \
!defined(WOLFSSL_PIC32MZ_CRYPT) && \
(defined(USE_INTEL_SPEEDUP) || defined(WOLFSSL_ARMASM))
{
ALIGN16 byte tmp[4 * WC_AES_BLOCK_SIZE];
while (sz >= 4 * WC_AES_BLOCK_SIZE) {
XMEMCPY(tmp, aes->reg, WC_AES_BLOCK_SIZE);
XMEMCPY(tmp + WC_AES_BLOCK_SIZE, in, 3 * WC_AES_BLOCK_SIZE);
XMEMCPY(aes->reg, in + 3 * WC_AES_BLOCK_SIZE, WC_AES_BLOCK_SIZE);
ret = wc_AesEcbEncrypt(aes, tmp, tmp, 4 * WC_AES_BLOCK_SIZE);
if (ret != 0) {
break;
}
xorbufout(out, in, tmp, 4 * WC_AES_BLOCK_SIZE);
out += 4 * WC_AES_BLOCK_SIZE;
in += 4 * WC_AES_BLOCK_SIZE;
sz -= 4 * WC_AES_BLOCK_SIZE;
}
}
#endif
while (sz >= WC_AES_BLOCK_SIZE) {
ret = wc_AesEncryptDirect(aes, (byte*)aes->tmp, (byte*)aes->reg);
if (ret != 0)
if (ret != 0) {
break;
#ifdef WOLFSSL_AES_OFB
if (mode == AES_OFB_MODE) {
XMEMCPY((byte*)aes->reg, (byte*)aes->tmp, WC_AES_BLOCK_SIZE);
}
#endif
xorbuf((byte*)aes->tmp, in, WC_AES_BLOCK_SIZE);
#ifdef WOLFSSL_AES_CFB
if (mode == AES_CFB_MODE) {
XMEMCPY(aes->reg, in, WC_AES_BLOCK_SIZE);
}
#endif
XMEMCPY(out, (byte*)aes->tmp, WC_AES_BLOCK_SIZE);
XMEMCPY((byte*)aes->reg, in, WC_AES_BLOCK_SIZE);
xorbufout(out, in, (byte*)aes->tmp, WC_AES_BLOCK_SIZE);
out += WC_AES_BLOCK_SIZE;
in += WC_AES_BLOCK_SIZE;
sz -= WC_AES_BLOCK_SIZE;
aes->left = 0;
}
/* decrypt left over data */
if ((ret == 0) && sz) {
ret = wc_AesEncryptDirect(aes, (byte*)aes->tmp, (byte*)aes->reg);
}
if ((ret == 0) && sz) {
#ifdef WOLFSSL_AES_CFB
if (mode == AES_CFB_MODE) {
if (ret == 0) {
XMEMCPY(aes->reg, in, sz);
xorbufout(out, in, aes->tmp, sz);
aes->left = WC_AES_BLOCK_SIZE - sz;
}
#endif
#ifdef WOLFSSL_AES_OFB
if (mode == AES_OFB_MODE) {
XMEMCPY(aes->reg, aes->tmp, WC_AES_BLOCK_SIZE);
}
#endif
aes->left = WC_AES_BLOCK_SIZE - sz;
xorbufout(out, in, aes->tmp, sz);
}
VECTOR_REGISTERS_POP;
@@ -12444,9 +12415,7 @@ static WARN_UNUSED_RESULT int wc_AesFeedbackDecrypt(
return ret;
}
#endif /* HAVE_AES_DECRYPT */
#endif /* WOLFSSL_AES_CFB */
#ifdef WOLFSSL_AES_CFB
/* CFB 128
*
* aes structure holding key to use for encryption
@@ -12460,7 +12429,7 @@ static WARN_UNUSED_RESULT int wc_AesFeedbackDecrypt(
/* Software AES - CFB Encrypt */
int wc_AesCfbEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
{
return wc_AesFeedbackEncrypt(aes, out, in, sz, AES_CFB_MODE);
return AesCfbEncrypt_C(aes, out, in, sz);
}
@@ -12478,7 +12447,7 @@ int wc_AesCfbEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
/* Software AES - CFB Decrypt */
int wc_AesCfbDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
{
return wc_AesFeedbackDecrypt(aes, out, in, sz, AES_CFB_MODE);
return AesCfbDecrypt_C(aes, out, in, sz, AES_CFB_MODE);
}
#endif /* HAVE_AES_DECRYPT */
@@ -12704,6 +12673,69 @@ int wc_AesCfb8Decrypt(Aes* aes, byte* out, const byte* in, word32 sz)
#endif /* WOLFSSL_AES_CFB */
#ifdef WOLFSSL_AES_OFB
/* OFB AES mode
*
* aes structure holding key to use for encryption
* out buffer to hold result of encryption (must be at least as large as input
* buffer)
* in buffer to encrypt
* sz size of input buffer
*
* returns 0 on success and negative error values on failure
*/
/* Software AES - OFB Encrypt/Decrypt */
static WARN_UNUSED_RESULT int AesOfbCrypt_C(Aes* aes, byte* out, const byte* in,
word32 sz)
{
int ret = 0;
word32 processed;
if ((aes == NULL) || (out == NULL) || (in == NULL)) {
return BAD_FUNC_ARG;
}
if (sz == 0) {
return 0;
}
if (aes->left > 0) {
/* consume any unused bytes left in aes->tmp */
processed = min(aes->left, sz);
xorbufout(out, in, (byte*)aes->tmp + WC_AES_BLOCK_SIZE - aes->left,
processed);
aes->left -= processed;
out += processed;
in += processed;
sz -= processed;
}
VECTOR_REGISTERS_PUSH;
while (sz >= WC_AES_BLOCK_SIZE) {
ret = wc_AesEncryptDirect(aes, (byte*)aes->reg, (byte*)aes->reg);
if (ret != 0) {
break;
}
xorbufout(out, in, (byte*)aes->reg, WC_AES_BLOCK_SIZE);
out += WC_AES_BLOCK_SIZE;
in += WC_AES_BLOCK_SIZE;
sz -= WC_AES_BLOCK_SIZE;
}
/* encrypt left over data */
if ((ret == 0) && sz) {
ret = wc_AesEncryptDirect(aes, (byte*)aes->tmp, (byte*)aes->reg);
if (ret == 0) {
XMEMCPY(aes->reg, aes->tmp, WC_AES_BLOCK_SIZE);
xorbufout(out, in, aes->tmp, sz);
aes->left = WC_AES_BLOCK_SIZE - sz;
}
}
VECTOR_REGISTERS_POP;
return ret;
}
/* OFB
*
* aes structure holding key to use for encryption
@@ -12714,10 +12746,10 @@ int wc_AesCfb8Decrypt(Aes* aes, byte* out, const byte* in, word32 sz)
*
* returns 0 on success and negative error values on failure
*/
/* Software AES - CFB Encrypt */
/* Software AES - OFB Encrypt */
int wc_AesOfbEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
{
return wc_AesFeedbackEncrypt(aes, out, in, sz, AES_OFB_MODE);
return AesOfbCrypt_C(aes, out, in, sz);
}
@@ -12735,7 +12767,7 @@ int wc_AesOfbEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
/* Software AES - OFB Decrypt */
int wc_AesOfbDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
{
return wc_AesFeedbackDecrypt(aes, out, in, sz, AES_OFB_MODE);
return AesOfbCrypt_C(aes, out, in, sz);
}
#endif /* HAVE_AES_DECRYPT */
#endif /* WOLFSSL_AES_OFB */