From 90b070750f0b5a1e85e910ebe90230046df25fd6 Mon Sep 17 00:00:00 2001 From: night1rider Date: Thu, 18 Jun 2026 16:32:04 -0600 Subject: [PATCH 1/2] Adding callbacks for AES mode OFB and CFB, along with callback testing/coverage for the callback paths --- .github/workflows/os-check.yml | 4 + tests/api/test_aes.c | 300 +++++++++++++++++++++++++++++++++ tests/api/test_aes.h | 28 ++- wolfcrypt/src/aes.c | 52 ++++++ wolfcrypt/src/cryptocb.c | 131 ++++++++++++++ wolfcrypt/test/test.c | 72 ++++++++ wolfssl/wolfcrypt/cryptocb.h | 28 +++ wolfssl/wolfcrypt/types.h | 1 + 8 files changed, 615 insertions(+), 1 deletion(-) diff --git a/.github/workflows/os-check.yml b/.github/workflows/os-check.yml index a6b9b945940..da114b398d0 100644 --- a/.github/workflows/os-check.yml +++ b/.github/workflows/os-check.yml @@ -243,6 +243,10 @@ jobs: {"name": "cryptocb-utils-setkey-export-find", "minutes": 2.2, "configure": ["--enable-cryptocb", "--enable-keygen", "--enable-cryptocbutils=setkey,export", "CPPFLAGS=-DWOLF_CRYPTO_CB_FIND"]}, + {"name": "cryptocb-aes-cfb-ofb", "minutes": 2.2, + "comment": "Exercises the AES-CFB/OFB crypto callback wiring (wc_CryptoCb_AesCfb/Ofb Encrypt/Decrypt, the aes.c hooks, and the dedicated offload unit tests). A normal (non-ONLY) cryptocb build keeps the host software AES present as the callbacks' offload fallback; WOLF_CRYPTO_CB_ONLY_AES (no software fallback) is covered separately by cryptocb-only.yml via swdev.", + "configure": ["--enable-cryptocb", "--enable-aescfb", + "--enable-aesofb", "--enable-aesctr"]}, {"name": "opensslall-rng-seed-cb-no-getpid", "minutes": 2.1, "configure": ["--enable-opensslall", "--enable-opensslextra", "CPPFLAGS=-DWC_RNG_SEED_CB -DWOLFSSL_NO_GETPID"]}, diff --git a/tests/api/test_aes.c b/tests/api/test_aes.c index 72221cd04ad..322be5ae31a 100644 --- a/tests/api/test_aes.c +++ b/tests/api/test_aes.c @@ -8701,6 +8701,306 @@ int test_wc_CryptoCb_AesGcm_EncryptDecrypt(void) #endif /* WOLF_CRYPTO_CB && WOLF_CRYPTO_CB_AES_SETKEY && !NO_AES && HAVE_AESGCM */ +/*----------------------------------------------------------------------------* + | CryptoCB AES-CFB End-to-End Offload Test + *----------------------------------------------------------------------------*/ + +#if defined(WOLF_CRYPTO_CB) && !defined(NO_AES) && defined(WOLFSSL_AES_CFB) && \ + !defined(WOLF_CRYPTO_CB_ONLY_AES) + +#define TEST_CRYPTOCB_AESCFB_DEVID 10 + +static int cryptoCbAesCfbEncryptCalled = 0; +static int cryptoCbAesCfbDecryptCalled = 0; + +/* Mock CryptoCB callback that "offloads" AES-CFB. It routes the request back + * to the software implementation, temporarily setting devId to INVALID_DEVID + * so the nested wc_AesCfb*crypt() call runs in software instead of recursing + * into the callback. */ +static int test_CryptoCb_AesCfb_Cb(int devId, wc_CryptoInfo* info, void* ctx) +{ + (void)ctx; + + if (devId != TEST_CRYPTOCB_AESCFB_DEVID) + return CRYPTOCB_UNAVAILABLE; + + if (info->algo_type == WC_ALGO_TYPE_CIPHER && + info->cipher.type == WC_CIPHER_AES_CFB) { + Aes* aes = info->cipher.aescfb.aes; + int ret; + + if (aes == NULL) + return BAD_FUNC_ARG; + + /* run software, no recursion */ + aes->devId = INVALID_DEVID; + if (info->cipher.enc) { + cryptoCbAesCfbEncryptCalled++; + ret = wc_AesCfbEncrypt(aes, info->cipher.aescfb.out, + info->cipher.aescfb.in, info->cipher.aescfb.sz); + } +#ifdef HAVE_AES_DECRYPT + else { + cryptoCbAesCfbDecryptCalled++; + ret = wc_AesCfbDecrypt(aes, info->cipher.aescfb.out, + info->cipher.aescfb.in, info->cipher.aescfb.sz); + } +#else + else { + ret = NOT_COMPILED_IN; + } +#endif + aes->devId = TEST_CRYPTOCB_AESCFB_DEVID; + + return ret; + } + + return CRYPTOCB_UNAVAILABLE; +} + +/* + * Test: End-to-End AES-CFB Offload via CryptoCB + * Verifies that wc_AesCfbEncrypt/Decrypt route through a registered CryptoCB + * device, that the callback is invoked for both directions, that the offloaded + * ciphertext matches a software-only reference (correctness), and that the + * offloaded round-trip recovers the plaintext. + */ +int test_wc_CryptoCb_AesCfb_EncryptDecrypt(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_AES_128) + Aes enc; +#ifdef HAVE_AES_DECRYPT + Aes dec; +#endif + static const byte key[AES_128_KEY_SIZE] = { + 0x2b,0x7e,0x15,0x16, 0x28,0xae,0xd2,0xa6, + 0xab,0xf7,0x15,0x88, 0x09,0xcf,0x4f,0x3c + }; + static const byte iv[WC_AES_BLOCK_SIZE] = { + 0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f + }; + static const byte plain[2 * WC_AES_BLOCK_SIZE] = { + 0x6b,0xc1,0xbe,0xe2, 0x2e,0x40,0x9f,0x96, + 0xe9,0x3d,0x7e,0x11, 0x73,0x93,0x17,0x2a, + 0xae,0x2d,0x8a,0x57, 0x1e,0x03,0xac,0x9c, + 0x9e,0xb7,0x6f,0xac, 0x45,0xaf,0x8e,0x51 + }; + byte refCipher[2 * WC_AES_BLOCK_SIZE]; + byte cipher[2 * WC_AES_BLOCK_SIZE]; + byte decrypted[2 * WC_AES_BLOCK_SIZE]; + int devRegistered = 0; + + XMEMSET(&enc, 0, sizeof(enc)); +#ifdef HAVE_AES_DECRYPT + XMEMSET(&dec, 0, sizeof(dec)); +#endif + XMEMSET(refCipher, 0, sizeof(refCipher)); + XMEMSET(cipher, 0, sizeof(cipher)); + XMEMSET(decrypted, 0, sizeof(decrypted)); + + cryptoCbAesCfbEncryptCalled = 0; + cryptoCbAesCfbDecryptCalled = 0; + + /* Software-only reference ciphertext (no devId, no callback). */ + ExpectIntEQ(wc_AesInit(&enc, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_AesSetKey(&enc, key, sizeof(key), iv, AES_ENCRYPTION), 0); + ExpectIntEQ(wc_AesCfbEncrypt(&enc, refCipher, plain, sizeof(plain)), 0); + wc_AesFree(&enc); + XMEMSET(&enc, 0, sizeof(enc)); + + /* Register the offload callback. */ + ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_CRYPTOCB_AESCFB_DEVID, + test_CryptoCb_AesCfb_Cb, NULL), 0); + if (EXPECT_SUCCESS()) + devRegistered = 1; + + /* Both contexts carry the offload devId so the AES-CFB calls route through + * the callback. */ + ExpectIntEQ(wc_AesInit(&enc, NULL, TEST_CRYPTOCB_AESCFB_DEVID), 0); + ExpectIntEQ(wc_AesSetKey(&enc, key, sizeof(key), iv, AES_ENCRYPTION), 0); +#ifdef HAVE_AES_DECRYPT + ExpectIntEQ(wc_AesInit(&dec, NULL, TEST_CRYPTOCB_AESCFB_DEVID), 0); + ExpectIntEQ(wc_AesSetKey(&dec, key, sizeof(key), iv, AES_ENCRYPTION), 0); +#endif + + /* Encrypt - must route through the callback and match the SW reference. */ + ExpectIntEQ(wc_AesCfbEncrypt(&enc, cipher, plain, sizeof(plain)), 0); + ExpectIntEQ(cryptoCbAesCfbEncryptCalled, 1); + ExpectBufEQ(cipher, refCipher, sizeof(refCipher)); + +#ifdef HAVE_AES_DECRYPT + /* Decrypt - must route through the callback and recover the plaintext. */ + ExpectIntEQ(wc_AesCfbDecrypt(&dec, decrypted, cipher, sizeof(cipher)), 0); + ExpectIntEQ(cryptoCbAesCfbDecryptCalled, 1); + ExpectBufEQ(decrypted, plain, sizeof(plain)); +#endif + + wc_AesFree(&enc); +#ifdef HAVE_AES_DECRYPT + wc_AesFree(&dec); +#endif + + if (devRegistered) + wc_CryptoCb_UnRegisterDevice(TEST_CRYPTOCB_AESCFB_DEVID); +#endif /* WOLFSSL_AES_128 */ + return EXPECT_RESULT(); +} + +#endif /* WOLF_CRYPTO_CB && !NO_AES && WOLFSSL_AES_CFB && !WOLF_CRYPTO_CB_ONLY_AES */ + + +/*----------------------------------------------------------------------------* + | CryptoCB AES-OFB End-to-End Offload Test + *----------------------------------------------------------------------------*/ + +#if defined(WOLF_CRYPTO_CB) && !defined(NO_AES) && defined(WOLFSSL_AES_OFB) && \ + !defined(WOLF_CRYPTO_CB_ONLY_AES) + +#define TEST_CRYPTOCB_AESOFB_DEVID 11 + +static int cryptoCbAesOfbEncryptCalled = 0; +static int cryptoCbAesOfbDecryptCalled = 0; + +/* Mock CryptoCB callback that "offloads" AES-OFB. It routes the request back + * to the software implementation, temporarily setting devId to INVALID_DEVID + * so the nested wc_AesOfb*crypt() call runs in software instead of recursing + * into the callback. */ +static int test_CryptoCb_AesOfb_Cb(int devId, wc_CryptoInfo* info, void* ctx) +{ + (void)ctx; + + if (devId != TEST_CRYPTOCB_AESOFB_DEVID) + return CRYPTOCB_UNAVAILABLE; + + if (info->algo_type == WC_ALGO_TYPE_CIPHER && + info->cipher.type == WC_CIPHER_AES_OFB) { + Aes* aes = info->cipher.aesofb.aes; + int ret; + + if (aes == NULL) + return BAD_FUNC_ARG; + + /* run software, no recursion */ + aes->devId = INVALID_DEVID; + if (info->cipher.enc) { + cryptoCbAesOfbEncryptCalled++; + ret = wc_AesOfbEncrypt(aes, info->cipher.aesofb.out, + info->cipher.aesofb.in, info->cipher.aesofb.sz); + } +#ifdef HAVE_AES_DECRYPT + else { + cryptoCbAesOfbDecryptCalled++; + ret = wc_AesOfbDecrypt(aes, info->cipher.aesofb.out, + info->cipher.aesofb.in, info->cipher.aesofb.sz); + } +#else + else { + ret = NOT_COMPILED_IN; + } +#endif + aes->devId = TEST_CRYPTOCB_AESOFB_DEVID; + + return ret; + } + + return CRYPTOCB_UNAVAILABLE; +} + +/* + * Test: End-to-End AES-OFB Offload via CryptoCB + * Verifies that wc_AesOfbEncrypt/Decrypt route through a registered CryptoCB + * device, that the callback is invoked for both directions, that the offloaded + * ciphertext matches a software-only reference (correctness), and that the + * offloaded round-trip recovers the plaintext. + */ +int test_wc_CryptoCb_AesOfb_EncryptDecrypt(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_AES_128) + Aes enc; +#ifdef HAVE_AES_DECRYPT + Aes dec; +#endif + static const byte key[AES_128_KEY_SIZE] = { + 0x2b,0x7e,0x15,0x16, 0x28,0xae,0xd2,0xa6, + 0xab,0xf7,0x15,0x88, 0x09,0xcf,0x4f,0x3c + }; + static const byte iv[WC_AES_BLOCK_SIZE] = { + 0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f + }; + static const byte plain[2 * WC_AES_BLOCK_SIZE] = { + 0x6b,0xc1,0xbe,0xe2, 0x2e,0x40,0x9f,0x96, + 0xe9,0x3d,0x7e,0x11, 0x73,0x93,0x17,0x2a, + 0xae,0x2d,0x8a,0x57, 0x1e,0x03,0xac,0x9c, + 0x9e,0xb7,0x6f,0xac, 0x45,0xaf,0x8e,0x51 + }; + byte refCipher[2 * WC_AES_BLOCK_SIZE]; + byte cipher[2 * WC_AES_BLOCK_SIZE]; + byte decrypted[2 * WC_AES_BLOCK_SIZE]; + int devRegistered = 0; + + XMEMSET(&enc, 0, sizeof(enc)); +#ifdef HAVE_AES_DECRYPT + XMEMSET(&dec, 0, sizeof(dec)); +#endif + XMEMSET(refCipher, 0, sizeof(refCipher)); + XMEMSET(cipher, 0, sizeof(cipher)); + XMEMSET(decrypted, 0, sizeof(decrypted)); + + cryptoCbAesOfbEncryptCalled = 0; + cryptoCbAesOfbDecryptCalled = 0; + + /* Software-only reference ciphertext (no devId, no callback). */ + ExpectIntEQ(wc_AesInit(&enc, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_AesSetKey(&enc, key, sizeof(key), iv, AES_ENCRYPTION), 0); + ExpectIntEQ(wc_AesOfbEncrypt(&enc, refCipher, plain, sizeof(plain)), 0); + wc_AesFree(&enc); + XMEMSET(&enc, 0, sizeof(enc)); + + /* Register the offload callback. */ + ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_CRYPTOCB_AESOFB_DEVID, + test_CryptoCb_AesOfb_Cb, NULL), 0); + if (EXPECT_SUCCESS()) + devRegistered = 1; + + /* Both contexts carry the offload devId so the AES-OFB calls route through + * the callback. */ + ExpectIntEQ(wc_AesInit(&enc, NULL, TEST_CRYPTOCB_AESOFB_DEVID), 0); + ExpectIntEQ(wc_AesSetKey(&enc, key, sizeof(key), iv, AES_ENCRYPTION), 0); +#ifdef HAVE_AES_DECRYPT + ExpectIntEQ(wc_AesInit(&dec, NULL, TEST_CRYPTOCB_AESOFB_DEVID), 0); + ExpectIntEQ(wc_AesSetKey(&dec, key, sizeof(key), iv, AES_ENCRYPTION), 0); +#endif + + /* Encrypt - must route through the callback and match the SW reference. */ + ExpectIntEQ(wc_AesOfbEncrypt(&enc, cipher, plain, sizeof(plain)), 0); + ExpectIntEQ(cryptoCbAesOfbEncryptCalled, 1); + ExpectBufEQ(cipher, refCipher, sizeof(refCipher)); + +#ifdef HAVE_AES_DECRYPT + /* Decrypt - must route through the callback and recover the plaintext. */ + ExpectIntEQ(wc_AesOfbDecrypt(&dec, decrypted, cipher, sizeof(cipher)), 0); + ExpectIntEQ(cryptoCbAesOfbDecryptCalled, 1); + ExpectBufEQ(decrypted, plain, sizeof(plain)); +#endif + + wc_AesFree(&enc); +#ifdef HAVE_AES_DECRYPT + wc_AesFree(&dec); +#endif + + if (devRegistered) + wc_CryptoCb_UnRegisterDevice(TEST_CRYPTOCB_AESOFB_DEVID); +#endif /* WOLFSSL_AES_128 */ + return EXPECT_RESULT(); +} + +#endif /* WOLF_CRYPTO_CB && !NO_AES && WOLFSSL_AES_OFB && !WOLF_CRYPTO_CB_ONLY_AES */ + + /*----------------------------------------------------------------------------* | CryptoCB AES-GCM TLS 1.3 Key Zeroing Tests *----------------------------------------------------------------------------*/ diff --git a/tests/api/test_aes.h b/tests/api/test_aes.h index 73e4b715ac9..42cb36ec71b 100644 --- a/tests/api/test_aes.h +++ b/tests/api/test_aes.h @@ -94,6 +94,14 @@ int test_wc_GmacUpdate(void); int test_wc_CryptoCb_AesSetKey(void); int test_wc_CryptoCb_AesGcm_EncryptDecrypt(void); #endif +#if defined(WOLF_CRYPTO_CB) && !defined(NO_AES) && defined(WOLFSSL_AES_CFB) && \ + !defined(WOLF_CRYPTO_CB_ONLY_AES) +int test_wc_CryptoCb_AesCfb_EncryptDecrypt(void); +#endif +#if defined(WOLF_CRYPTO_CB) && !defined(NO_AES) && defined(WOLFSSL_AES_OFB) && \ + !defined(WOLF_CRYPTO_CB_ONLY_AES) +int test_wc_CryptoCb_AesOfb_EncryptDecrypt(void); +#endif /* These test functions always have a (possibly empty) definition in * test_aes.c so that callers can reference them unconditionally. Declare @@ -121,6 +129,22 @@ int test_wc_CryptoCb_Tls13_Key_No_Zero_Without_Offload(void); #define TEST_CRYPTOCB_AES_SETKEY_DECL #endif +#if defined(WOLF_CRYPTO_CB) && !defined(NO_AES) && defined(WOLFSSL_AES_CFB) && \ + !defined(WOLF_CRYPTO_CB_ONLY_AES) +#define TEST_CRYPTOCB_AESCFB_DECL \ + , TEST_DECL_GROUP("aes", test_wc_CryptoCb_AesCfb_EncryptDecrypt) +#else +#define TEST_CRYPTOCB_AESCFB_DECL +#endif + +#if defined(WOLF_CRYPTO_CB) && !defined(NO_AES) && defined(WOLFSSL_AES_OFB) && \ + !defined(WOLF_CRYPTO_CB_ONLY_AES) +#define TEST_CRYPTOCB_AESOFB_DECL \ + , TEST_DECL_GROUP("aes", test_wc_CryptoCb_AesOfb_EncryptDecrypt) +#else +#define TEST_CRYPTOCB_AESOFB_DECL +#endif + #define TEST_AES_DECLS \ TEST_DECL_GROUP("aes", test_wc_AesSetKey), \ TEST_DECL_GROUP("aes", test_wc_AesSetIV), \ @@ -174,7 +198,9 @@ int test_wc_CryptoCb_Tls13_Key_No_Zero_Without_Offload(void); TEST_DECL_GROUP("aes", test_wc_AesCfb_MonteCarlo), \ TEST_DECL_GROUP("aes", test_wc_AesOfb_MonteCarlo) \ TEST_CRYPTOCB_AES_SETKEY_DECL \ - TEST_CRYPTOCB_TLS13_KEY_ZERO_DECL + TEST_CRYPTOCB_TLS13_KEY_ZERO_DECL \ + TEST_CRYPTOCB_AESCFB_DECL \ + TEST_CRYPTOCB_AESOFB_DECL #if defined(WOLFSSL_AES_EAX) && defined(WOLFSSL_AES_256) && \ (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 3)) && !defined(HAVE_SELFTEST) diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index 6806acbc965..104ab56315d 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -14886,6 +14886,19 @@ static WARN_UNUSED_RESULT int AesCfbDecrypt_C(Aes* aes, byte* out, /* Software AES - CFB Encrypt */ int wc_AesCfbEncrypt(Aes* aes, byte* out, const byte* in, word32 sz) { +#ifdef WOLF_CRYPTO_CB + if (aes == NULL) + return BAD_FUNC_ARG; + #ifndef WOLF_CRYPTO_CB_FIND + if (aes->devId != INVALID_DEVID) + #endif + { + int crypto_cb_ret = wc_CryptoCb_AesCfbEncrypt(aes, out, in, sz); + if (crypto_cb_ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return crypto_cb_ret; + /* fall-through when unavailable */ + } +#endif return AesCfbEncrypt_C(aes, out, in, sz); } @@ -14904,6 +14917,19 @@ 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) { +#ifdef WOLF_CRYPTO_CB + if (aes == NULL) + return BAD_FUNC_ARG; + #ifndef WOLF_CRYPTO_CB_FIND + if (aes->devId != INVALID_DEVID) + #endif + { + int crypto_cb_ret = wc_CryptoCb_AesCfbDecrypt(aes, out, in, sz); + if (crypto_cb_ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return crypto_cb_ret; + /* fall-through when unavailable */ + } +#endif return AesCfbDecrypt_C(aes, out, in, sz, AES_CFB_MODE); } #endif /* HAVE_AES_DECRYPT */ @@ -15224,6 +15250,19 @@ static WARN_UNUSED_RESULT int AesOfbCrypt_C(Aes* aes, byte* out, const byte* in, /* Software AES - OFB Encrypt */ int wc_AesOfbEncrypt(Aes* aes, byte* out, const byte* in, word32 sz) { +#ifdef WOLF_CRYPTO_CB + if (aes == NULL) + return BAD_FUNC_ARG; + #ifndef WOLF_CRYPTO_CB_FIND + if (aes->devId != INVALID_DEVID) + #endif + { + int crypto_cb_ret = wc_CryptoCb_AesOfbEncrypt(aes, out, in, sz); + if (crypto_cb_ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return crypto_cb_ret; + /* fall-through when unavailable */ + } +#endif return AesOfbCrypt_C(aes, out, in, sz); } @@ -15242,6 +15281,19 @@ 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) { +#ifdef WOLF_CRYPTO_CB + if (aes == NULL) + return BAD_FUNC_ARG; + #ifndef WOLF_CRYPTO_CB_FIND + if (aes->devId != INVALID_DEVID) + #endif + { + int crypto_cb_ret = wc_CryptoCb_AesOfbDecrypt(aes, out, in, sz); + if (crypto_cb_ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return crypto_cb_ret; + /* fall-through when unavailable */ + } +#endif return AesOfbCrypt_C(aes, out, in, sz); } #endif /* HAVE_AES_DECRYPT */ diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index 3218e6efb27..492b6351e5c 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -170,6 +170,7 @@ static const char* GetCipherTypeStr(int cipher) case WC_CIPHER_AES_CTR: return "AES CTR"; case WC_CIPHER_AES_XTS: return "AES XTS"; case WC_CIPHER_AES_CFB: return "AES CFB"; + case WC_CIPHER_AES_OFB: return "AES OFB"; case WC_CIPHER_DES3: return "DES3"; case WC_CIPHER_DES: return "DES"; case WC_CIPHER_CHACHA: return "ChaCha20"; @@ -1741,6 +1742,136 @@ int wc_CryptoCb_AesCtrEncrypt(Aes* aes, byte* out, return wc_CryptoCb_TranslateErrorCode(ret); } #endif /* WOLFSSL_AES_COUNTER */ +#ifdef WOLFSSL_AES_CFB +int wc_CryptoCb_AesCfbEncrypt(Aes* aes, byte* out, + const byte* in, word32 sz) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + /* locate registered callback */ + if (aes) { + dev = wc_CryptoCb_FindDevice(aes->devId, WC_ALGO_TYPE_CIPHER); + } + else { + /* locate first callback and try using it */ + dev = wc_CryptoCb_FindDeviceByIndex(0); + } + + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_CIPHER; + cryptoInfo.cipher.type = WC_CIPHER_AES_CFB; + cryptoInfo.cipher.enc = 1; + cryptoInfo.cipher.aescfb.aes = aes; + cryptoInfo.cipher.aescfb.out = out; + cryptoInfo.cipher.aescfb.in = in; + cryptoInfo.cipher.aescfb.sz = sz; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} + +int wc_CryptoCb_AesCfbDecrypt(Aes* aes, byte* out, + const byte* in, word32 sz) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + /* locate registered callback */ + if (aes) { + dev = wc_CryptoCb_FindDevice(aes->devId, WC_ALGO_TYPE_CIPHER); + } + else { + /* locate first callback and try using it */ + dev = wc_CryptoCb_FindDeviceByIndex(0); + } + + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_CIPHER; + cryptoInfo.cipher.type = WC_CIPHER_AES_CFB; + cryptoInfo.cipher.enc = 0; + cryptoInfo.cipher.aescfb.aes = aes; + cryptoInfo.cipher.aescfb.out = out; + cryptoInfo.cipher.aescfb.in = in; + cryptoInfo.cipher.aescfb.sz = sz; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} +#endif /* WOLFSSL_AES_CFB */ +#ifdef WOLFSSL_AES_OFB +int wc_CryptoCb_AesOfbEncrypt(Aes* aes, byte* out, + const byte* in, word32 sz) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + /* locate registered callback */ + if (aes) { + dev = wc_CryptoCb_FindDevice(aes->devId, WC_ALGO_TYPE_CIPHER); + } + else { + /* locate first callback and try using it */ + dev = wc_CryptoCb_FindDeviceByIndex(0); + } + + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_CIPHER; + cryptoInfo.cipher.type = WC_CIPHER_AES_OFB; + cryptoInfo.cipher.enc = 1; + cryptoInfo.cipher.aesofb.aes = aes; + cryptoInfo.cipher.aesofb.out = out; + cryptoInfo.cipher.aesofb.in = in; + cryptoInfo.cipher.aesofb.sz = sz; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} + +int wc_CryptoCb_AesOfbDecrypt(Aes* aes, byte* out, + const byte* in, word32 sz) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + /* locate registered callback */ + if (aes) { + dev = wc_CryptoCb_FindDevice(aes->devId, WC_ALGO_TYPE_CIPHER); + } + else { + /* locate first callback and try using it */ + dev = wc_CryptoCb_FindDeviceByIndex(0); + } + + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_CIPHER; + cryptoInfo.cipher.type = WC_CIPHER_AES_OFB; + cryptoInfo.cipher.enc = 0; + cryptoInfo.cipher.aesofb.aes = aes; + cryptoInfo.cipher.aesofb.out = out; + cryptoInfo.cipher.aesofb.in = in; + cryptoInfo.cipher.aesofb.sz = sz; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} +#endif /* WOLFSSL_AES_OFB */ #if defined(HAVE_AES_ECB) || defined(WOLFSSL_AES_DIRECT) || \ defined(WOLF_CRYPTO_CB_ONLY_AES) int wc_CryptoCb_AesEcbEncrypt(Aes* aes, byte* out, diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index e95bba5ae5e..9a1975ed8d9 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -73420,6 +73420,70 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) info->cipher.aesctr.aes->devId = devIdArg; } #endif /* WOLFSSL_AES_COUNTER */ + #ifdef WOLFSSL_AES_CFB + if (info->cipher.type == WC_CIPHER_AES_CFB) { + if (info->cipher.enc) { + /* set devId to invalid, so software is used */ + info->cipher.aescfb.aes->devId = INVALID_DEVID; + + ret = wc_AesCfbEncrypt( + info->cipher.aescfb.aes, + info->cipher.aescfb.out, + info->cipher.aescfb.in, + info->cipher.aescfb.sz); + + /* reset devId */ + info->cipher.aescfb.aes->devId = devIdArg; + } + #ifdef HAVE_AES_DECRYPT + else { + /* set devId to invalid, so software is used */ + info->cipher.aescfb.aes->devId = INVALID_DEVID; + + ret = wc_AesCfbDecrypt( + info->cipher.aescfb.aes, + info->cipher.aescfb.out, + info->cipher.aescfb.in, + info->cipher.aescfb.sz); + + /* reset devId */ + info->cipher.aescfb.aes->devId = devIdArg; + } + #endif /* HAVE_AES_DECRYPT */ + } + #endif /* WOLFSSL_AES_CFB */ + #ifdef WOLFSSL_AES_OFB + if (info->cipher.type == WC_CIPHER_AES_OFB) { + if (info->cipher.enc) { + /* set devId to invalid, so software is used */ + info->cipher.aesofb.aes->devId = INVALID_DEVID; + + ret = wc_AesOfbEncrypt( + info->cipher.aesofb.aes, + info->cipher.aesofb.out, + info->cipher.aesofb.in, + info->cipher.aesofb.sz); + + /* reset devId */ + info->cipher.aesofb.aes->devId = devIdArg; + } + #ifdef HAVE_AES_DECRYPT + else { + /* set devId to invalid, so software is used */ + info->cipher.aesofb.aes->devId = INVALID_DEVID; + + ret = wc_AesOfbDecrypt( + info->cipher.aesofb.aes, + info->cipher.aesofb.out, + info->cipher.aesofb.in, + info->cipher.aesofb.sz); + + /* reset devId */ + info->cipher.aesofb.aes->devId = devIdArg; + } + #endif /* HAVE_AES_DECRYPT */ + } + #endif /* WOLFSSL_AES_OFB */ #if defined(HAVE_AESCCM) && defined(WOLFSSL_AES_128) if (info->cipher.type == WC_CIPHER_AES_CCM) { if (info->cipher.enc) { @@ -74797,6 +74861,14 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) if (ret == 0) ret = aes_test(); #endif + #ifdef WOLFSSL_AES_CFB + if (ret == 0) + ret = aes_cfb_test(); + #endif + #ifdef WOLFSSL_AES_OFB + if (ret == 0) + ret = aesofb_test(); + #endif #ifdef WOLFSSL_AES_XTS if (ret == 0) ret = aes_xts_test(); diff --git a/wolfssl/wolfcrypt/cryptocb.h b/wolfssl/wolfcrypt/cryptocb.h index b0aaad2f374..2ffbcd8fa48 100644 --- a/wolfssl/wolfcrypt/cryptocb.h +++ b/wolfssl/wolfcrypt/cryptocb.h @@ -418,6 +418,22 @@ typedef struct wc_CryptoInfo { word32 sz; } aesctr; #endif /* WOLFSSL_AES_COUNTER */ + #if defined(WOLFSSL_AES_CFB) + struct { + Aes* aes; + byte* out; + const byte* in; + word32 sz; + } aescfb; + #endif /* WOLFSSL_AES_CFB */ + #if defined(WOLFSSL_AES_OFB) + struct { + Aes* aes; + byte* out; + const byte* in; + word32 sz; + } aesofb; + #endif /* WOLFSSL_AES_OFB */ #if defined(HAVE_AES_ECB) || defined(WOLFSSL_AES_DIRECT) || \ defined(WOLF_CRYPTO_CB_ONLY_AES) struct { @@ -833,6 +849,18 @@ WOLFSSL_LOCAL int wc_CryptoCb_AesCbcDecrypt(Aes* aes, byte* out, WOLFSSL_LOCAL int wc_CryptoCb_AesCtrEncrypt(Aes* aes, byte* out, const byte* in, word32 sz); #endif /* WOLFSSL_AES_COUNTER */ +#ifdef WOLFSSL_AES_CFB +WOLFSSL_LOCAL int wc_CryptoCb_AesCfbEncrypt(Aes* aes, byte* out, + const byte* in, word32 sz); +WOLFSSL_LOCAL int wc_CryptoCb_AesCfbDecrypt(Aes* aes, byte* out, + const byte* in, word32 sz); +#endif /* WOLFSSL_AES_CFB */ +#ifdef WOLFSSL_AES_OFB +WOLFSSL_LOCAL int wc_CryptoCb_AesOfbEncrypt(Aes* aes, byte* out, + const byte* in, word32 sz); +WOLFSSL_LOCAL int wc_CryptoCb_AesOfbDecrypt(Aes* aes, byte* out, + const byte* in, word32 sz); +#endif /* WOLFSSL_AES_OFB */ #if defined(HAVE_AES_ECB) || defined(WOLFSSL_AES_DIRECT) || \ defined(WOLF_CRYPTO_CB_ONLY_AES) WOLFSSL_LOCAL int wc_CryptoCb_AesEcbEncrypt(Aes* aes, byte* out, diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index 3a1efb79556..74fba9de315 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -1538,6 +1538,7 @@ enum wc_CipherType { WC_CIPHER_AES_CFB = 6, WC_CIPHER_AES_CCM = 12, WC_CIPHER_AES_ECB = 13, + WC_CIPHER_AES_OFB = 14, WC_CIPHER_DES3 = 7, WC_CIPHER_DES = 8, WC_CIPHER_CHACHA = 9, From 5cd73e18d831a9dbcd957926a17e42aaf0362e5a Mon Sep 17 00:00:00 2001 From: night1rider Date: Tue, 23 Jun 2026 10:04:18 -0600 Subject: [PATCH 2/2] Add testing for cryptocb only for aes ofb and cfb --- tests/swdev/swdev.c | 70 +++++++++++++++++++++++++++++++++++++++++++ wolfcrypt/test/test.c | 59 ++++++++++++++++++++++++++++++++++-- 2 files changed, 127 insertions(+), 2 deletions(-) diff --git a/tests/swdev/swdev.c b/tests/swdev/swdev.c index 24271eda1ec..7507fd29361 100644 --- a/tests/swdev/swdev.c +++ b/tests/swdev/swdev.c @@ -513,6 +513,68 @@ static int swdev_aes_ctr(wc_CryptoInfo* info) } #endif +#ifdef WOLFSSL_AES_CFB +static int swdev_aes_cfb(wc_CryptoInfo* info) +{ + Aes* aes = info->cipher.aescfb.aes; + byte* out = info->cipher.aescfb.out; + const byte* in = info->cipher.aescfb.in; + word32 sz = info->cipher.aescfb.sz; + Aes shadow; + int ret; + + /* CFB is a stream mode built on the forward cipher, so the shadow key + * schedule is always AES_ENCRYPTION (as for CTR), even when decrypting. */ + ret = swdev_aes_shadow_init(&shadow, aes, AES_ENCRYPTION); + if (ret != 0) + return ret; + + if (info->cipher.enc) + ret = wc_AesCfbEncrypt(&shadow, out, in, sz); +#ifdef HAVE_AES_DECRYPT + else + ret = wc_AesCfbDecrypt(&shadow, out, in, sz); +#else + else + ret = CRYPTOCB_UNAVAILABLE; +#endif + swdev_aes_shadow_sync(aes, &shadow); + wc_AesFree(&shadow); + return ret; +} +#endif /* WOLFSSL_AES_CFB */ + +#ifdef WOLFSSL_AES_OFB +static int swdev_aes_ofb(wc_CryptoInfo* info) +{ + Aes* aes = info->cipher.aesofb.aes; + byte* out = info->cipher.aesofb.out; + const byte* in = info->cipher.aesofb.in; + word32 sz = info->cipher.aesofb.sz; + Aes shadow; + int ret; + + /* OFB is a stream mode built on the forward cipher, so the shadow key + * schedule is always AES_ENCRYPTION (as for CTR), even when decrypting. */ + ret = swdev_aes_shadow_init(&shadow, aes, AES_ENCRYPTION); + if (ret != 0) + return ret; + + if (info->cipher.enc) + ret = wc_AesOfbEncrypt(&shadow, out, in, sz); +#ifdef HAVE_AES_DECRYPT + else + ret = wc_AesOfbDecrypt(&shadow, out, in, sz); +#else + else + ret = CRYPTOCB_UNAVAILABLE; +#endif + swdev_aes_shadow_sync(aes, &shadow); + wc_AesFree(&shadow); + return ret; +} +#endif /* WOLFSSL_AES_OFB */ + #if defined(HAVE_AES_ECB) || defined(WOLFSSL_AES_DIRECT) static int swdev_aes_ecb(wc_CryptoInfo* info) { @@ -762,6 +824,14 @@ WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info, case WC_CIPHER_AES_CTR: return swdev_aes_ctr(info); #endif + #ifdef WOLFSSL_AES_CFB + case WC_CIPHER_AES_CFB: + return swdev_aes_cfb(info); + #endif + #ifdef WOLFSSL_AES_OFB + case WC_CIPHER_AES_OFB: + return swdev_aes_ofb(info); + #endif #if defined(HAVE_AES_ECB) || defined(WOLFSSL_AES_DIRECT) case WC_CIPHER_AES_ECB: return swdev_aes_ecb(info); diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 9a1975ed8d9..f602a45cbd1 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -72675,7 +72675,9 @@ static wc_test_ret_t sha256_onlycb_test(myCryptoDevCtx *ctx) static wc_test_ret_t aes_onlycb_test(myCryptoDevCtx *ctx) { wc_test_ret_t ret = 0; -#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128) +#if !defined(NO_AES) && defined(WOLFSSL_AES_128) && \ + (defined(HAVE_AES_CBC) || defined(WOLFSSL_AES_CFB) || \ + defined(WOLFSSL_AES_OFB)) Aes aes; const byte key[16] = { 0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6, @@ -72695,6 +72697,7 @@ static wc_test_ret_t aes_onlycb_test(myCryptoDevCtx *ctx) if (ret != 0) return WC_TEST_RET_ENC_EC(ret); +#ifdef HAVE_AES_CBC ret = wc_AesSetKey(&aes, key, sizeof(key), iv, AES_ENCRYPTION); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); @@ -72713,10 +72716,54 @@ static wc_test_ret_t aes_onlycb_test(myCryptoDevCtx *ctx) } else { ret = 0; } +#endif /* HAVE_AES_CBC */ + +#ifdef WOLFSSL_AES_CFB + ret = wc_AesSetKey(&aes, key, sizeof(key), iv, AES_ENCRYPTION); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + + /* cb handles the op, expects 0(success) */ + ctx->exampleVar = 99; + ret = wc_AesCfbEncrypt(&aes, out, plain, sizeof(plain)); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + + /* cb delegates to software, expects NO_VALID_DEVID(failure) */ + ctx->exampleVar = 1; + ret = wc_AesCfbEncrypt(&aes, out, plain, sizeof(plain)); + if (ret != WC_NO_ERR_TRACE(NO_VALID_DEVID)) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + } else { + ret = 0; + } +#endif /* WOLFSSL_AES_CFB */ + +#ifdef WOLFSSL_AES_OFB + ret = wc_AesSetKey(&aes, key, sizeof(key), iv, AES_ENCRYPTION); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + + /* cb handles the op, expects 0(success) */ + ctx->exampleVar = 99; + ret = wc_AesOfbEncrypt(&aes, out, plain, sizeof(plain)); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + + /* cb delegates to software, expects NO_VALID_DEVID(failure) */ + ctx->exampleVar = 1; + ret = wc_AesOfbEncrypt(&aes, out, plain, sizeof(plain)); + if (ret != WC_NO_ERR_TRACE(NO_VALID_DEVID)) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + } else { + ret = 0; + } +#endif /* WOLFSSL_AES_OFB */ exit_onlycb: wc_AesFree(&aes); -#endif /* !NO_AES && HAVE_AES_CBC && WOLFSSL_AES_128 */ +#endif /* !NO_AES && WOLFSSL_AES_128 && + * (HAVE_AES_CBC || WOLFSSL_AES_CFB || WOLFSSL_AES_OFB) */ (void)ctx; return ret; } @@ -73422,6 +73469,10 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) #endif /* WOLFSSL_AES_COUNTER */ #ifdef WOLFSSL_AES_CFB if (info->cipher.type == WC_CIPHER_AES_CFB) { + #if defined(WOLF_CRYPTO_CB_ONLY_AES) + if (myCtx->exampleVar == 99) + return 0; + #endif if (info->cipher.enc) { /* set devId to invalid, so software is used */ info->cipher.aescfb.aes->devId = INVALID_DEVID; @@ -73454,6 +73505,10 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) #endif /* WOLFSSL_AES_CFB */ #ifdef WOLFSSL_AES_OFB if (info->cipher.type == WC_CIPHER_AES_OFB) { + #if defined(WOLF_CRYPTO_CB_ONLY_AES) + if (myCtx->exampleVar == 99) + return 0; + #endif if (info->cipher.enc) { /* set devId to invalid, so software is used */ info->cipher.aesofb.aes->devId = INVALID_DEVID;