Add AES key wrap with padding (RFC 5649) and crypto callback support

Adds wc_AesKeyWrap_Pad/wc_AesKeyUnWrap_Pad and their _ex variants plus crypto
callback dispatch, routing blocks through wc_AesEcb* so an ECB only callback works.
This commit is contained in:
night1rider
2026-08-10 15:10:46 -06:00
parent 0ee11c71ac
commit 2fcc341072
13 changed files with 2053 additions and 44 deletions
+9
View File
@@ -190,6 +190,15 @@
"configure": ["--disable-sni", "--disable-ecc", "--disable-tls13",
"--disable-secure-renegotiation-info"]},
{"name": "default", "minutes": 1.6},
{"name": "aeskeywrap-padding", "minutes": 1.6,
"comment": "RFC 5649 AES key wrap with padding; exercises the =padding sub-option (not pulled in by --enable-all).",
"configure": ["--enable-aeskeywrap=padding"]},
{"name": "aeskeywrap-padding-cryptocb", "minutes": 1.6,
"comment": "Key wrap (RFC 3394 + RFC 5649) over WOLF_CRYPTO_CB device offload; runs test_wc_CryptoCb_AesKeyWrap.",
"configure": ["--enable-cryptocb", "--enable-aeskeywrap=padding"]},
{"name": "aeskeywrap-padding-cryptocb-ecb", "minutes": 1.6,
"comment": "Key wrap with HAVE_AES_ECB so the RFC 3394 loops route each block through wc_AesEcb*; runs test_wc_CryptoCb_AesKeyWrapEcbCompose (key wrap composed from an ECB-only crypto callback).",
"configure": ["--enable-cryptocb", "--enable-aeskeywrap=padding", "--enable-aesecb"]},
{"name": "no-client-no-client-auth", "minutes": 1.6,
"configure": ["CPPFLAGS=-DNO_WOLFSSL_CLIENT -DWOLFSSL_NO_CLIENT_AUTH"]},
{"name": "ascon-experimental", "minutes": 1.6,
+2 -2
View File
@@ -72,7 +72,7 @@ jobs:
"--enable-swdev", "--enable-cryptocb", "--enable-ecc",
"--enable-rsa", "--enable-dh", "--enable-aesgcm",
"--enable-aesccm", "--enable-aesctr", "--enable-aescfb",
"--enable-aeskeywrap", "--enable-aessiv", "--enable-aesofb",
"--enable-aeskeywrap=padding", "--enable-aessiv", "--enable-aesofb",
"--enable-aesxts", "--enable-camellia", "--enable-chacha",
"--enable-poly1305", "--enable-sha", "--enable-sha3",
"--enable-shake128", "--enable-shake256", "--enable-blake2",
@@ -103,7 +103,7 @@ jobs:
"comment": "Same as sha512 but tells swdev to refuse the SHA-384 / SHA-512/224 / SHA-512/256 variant callbacks (WOLFSSL_SWDEV_SHA512_GENERAL_ONLY). That forces the cryptocb dispatcher's fallback-to-plain-SHA-512-with-truncation path. The sha512 entry above instead has swdev handle every variant end-to-end, so the dispatcher fallback is otherwise uncovered.",
"configure": ["CPPFLAGS=-DWOLF_CRYPTO_CB_ONLY_SHA512 -DWOLFSSL_SWDEV_SHA512_GENERAL_ONLY"]},
{"name": "aes",
"comment": "WOLF_CRYPTO_CB_ONLY_AES: strips software AES; swdev provides the software path via cryptocb.",
"comment": "WOLF_CRYPTO_CB_ONLY_AES: strips software AES; swdev provides the software path via cryptocb. aeskeywrap=padding covers RFC 3394 + RFC 5649 key wrap via swdev_aes_keywrap.",
"configure": ["CPPFLAGS=-DWOLF_CRYPTO_CB_ONLY_AES"]},
{"name": "aes-gcm-via-ecb",
"comment": "Same as aes but tells swdev to refuse AES-GCM (SWDEV_AES_ONLYECB). That forces the parent's CB_ONLY_AES host-side GCM software path: GHASH runs on the host while AES-CTR blocks dispatch back through cryptocb ECB. The aes entry instead has swdev handle GCM end-to-end, so the host-side GCM path is otherwise uncovered.",
+26 -1
View File
@@ -6983,12 +6983,31 @@ AC_ARG_ENABLE([entropy-memuse],
)
# AES key wrap
# Accepts a comma-separated value list; "padding" adds RFC 5649 key wrap with
# padding on top of the base RFC 3394 key wrap.
AC_ARG_ENABLE([aeskeywrap],
[AS_HELP_STRING([--enable-aeskeywrap],[Enable AES key wrap support (default: disabled)])],
[AS_HELP_STRING([--enable-aeskeywrap],[Enable AES key wrap support, optionally with RFC 5649 padding via "=padding" (default: disabled)])],
[ ENABLED_AESKEYWRAP=$enableval ],
[ ENABLED_AESKEYWRAP=no ]
)
ENABLED_AESKEYWRAP_PADDING=no
for v in `echo $ENABLED_AESKEYWRAP | tr "," " "`
do
case $v in
yes | no)
;;
padding)
# padding (RFC 5649) builds on the base key wrap support
ENABLED_AESKEYWRAP_PADDING=yes
ENABLED_AESKEYWRAP=yes
;;
*)
AC_MSG_ERROR([Invalid aeskeywrap option. Valid are: yes, no, padding. Seen: $ENABLED_AESKEYWRAP.])
;;
esac
done
# FIPS feature and macro setup
AS_CASE([$FIPS_VERSION],
@@ -11725,6 +11744,11 @@ then
AM_CFLAGS="$AM_CFLAGS -DHAVE_AES_KEYWRAP -DWOLFSSL_AES_DIRECT"
fi
if test "$ENABLED_AESKEYWRAP_PADDING" = "yes"
then
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_KEYWRAP_PADDING"
fi
# Old name support for backwards compatibility
AC_ARG_ENABLE([oldnames],
@@ -13739,6 +13763,7 @@ echo " * AES-GCM-SIV: $ENABLED_AESGCMSIV"
echo " * AES-EAX: $ENABLED_AESEAX"
echo " * AES Bitspliced: $ENABLED_AESBS"
echo " * AES Key Wrap: $ENABLED_AESKEYWRAP"
echo " * AES Key Wrap Padding: $ENABLED_AESKEYWRAP_PADDING"
echo " * ARIA: $ENABLED_ARIA"
echo " * ASCON: $ENABLED_ASCON"
echo " * DES3: $ENABLED_DES3"
+3
View File
@@ -38862,6 +38862,9 @@ TEST_CASE testCases[] = {
#if defined(WOLFSSL_AES_SIV) && defined(WOLFSSL_AES_128)
TEST_AES_SIV_DECLS,
#endif /* WOLFSSL_AES_SIV && WOLFSSL_AES_128 */
#if defined(HAVE_AES_KEYWRAP) && defined(WOLFSSL_AES_KEYWRAP_PADDING)
TEST_AES_KEYWRAP_DECLS,
#endif /* HAVE_AES_KEYWRAP && WOLFSSL_AES_KEYWRAP_PADDING */
TEST_GMAC_DECLS,
/* Ascon */
TEST_ASCON_DECLS,
+693
View File
@@ -10254,6 +10254,434 @@ int test_wc_AesSivArgMcdc(void)
}
#endif /* WOLFSSL_AES_SIV && WOLFSSL_AES_128 */
/*----------------------------------------------------------------------------*
| AES Key Wrap with Padding (RFC 5649) Test
*----------------------------------------------------------------------------*/
#if defined(HAVE_AES_KEYWRAP) && defined(WOLFSSL_AES_KEYWRAP_PADDING)
/* Test wc_AesKeyWrap_Pad / wc_AesKeyUnWrap_Pad (RFC 5649). KAT vectors: RFC
* 5649 s6 for 192-bit, OpenSSL aes-wrap-pad for 128/256 (cross-checked). */
int test_wc_AesKeyWrap_Pad(void)
{
EXPECT_DECLS;
/* shared plaintexts */
const byte data20[] = { /* 20 octets -> 32-byte wrap (3394 loop path) */
0xc3, 0x7b, 0x7e, 0x64, 0x92, 0x58, 0x43, 0x40,
0xbe, 0xd1, 0x22, 0x07, 0x80, 0x89, 0x41, 0x15,
0x50, 0x68, 0xf7, 0x38
};
const byte data7[] = { /* 7 octets -> 16-byte wrap (single-block ECB) */
0x46, 0x6f, 0x72, 0x50, 0x61, 0x73, 0x69
};
#ifdef WOLFSSL_AES_128
const byte kek128[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
const byte verify128_20[] = {
0xe1, 0xf7, 0x17, 0x6e, 0xcb, 0xd7, 0x5d, 0x42,
0xe8, 0x2b, 0x24, 0xf9, 0x89, 0xa2, 0x81, 0x6c,
0x20, 0x9c, 0x6e, 0xf2, 0xd1, 0xaa, 0x94, 0xd2,
0xa3, 0xe6, 0x02, 0x84, 0x90, 0x0d, 0x03, 0xa2
};
const byte verify128_7[] = {
0xbe, 0x80, 0x53, 0x5e, 0x12, 0xe9, 0x39, 0x4c,
0x8f, 0x8d, 0xf2, 0x6b, 0xd9, 0x52, 0x8a, 0x35
};
#endif
#ifdef WOLFSSL_AES_192
const byte kek192[] = {
0x58, 0x40, 0xdf, 0x6e, 0x29, 0xb0, 0x2a, 0xf1,
0xab, 0x49, 0x3b, 0x70, 0x5b, 0xf1, 0x6e, 0xa1,
0xae, 0x83, 0x38, 0xf4, 0xdc, 0xc1, 0x76, 0xa8
};
const byte verify192_20[] = {
0x13, 0x8b, 0xde, 0xaa, 0x9b, 0x8f, 0xa7, 0xfc,
0x61, 0xf9, 0x77, 0x42, 0xe7, 0x22, 0x48, 0xee,
0x5a, 0xe6, 0xae, 0x53, 0x60, 0xd1, 0xae, 0x6a,
0x5f, 0x54, 0xf3, 0x73, 0xfa, 0x54, 0x3b, 0x6a
};
const byte verify192_7[] = {
0xaf, 0xbe, 0xb0, 0xf0, 0x7d, 0xfb, 0xf5, 0x41,
0x92, 0x00, 0xf2, 0xcc, 0xb5, 0x0b, 0xb2, 0x4f
};
#endif
#ifdef WOLFSSL_AES_256
const byte kek256[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
};
const byte verify256_20[] = {
0x29, 0xb7, 0xfa, 0x19, 0x1c, 0x21, 0x65, 0x68,
0x43, 0x74, 0xee, 0xe9, 0xf7, 0x45, 0x95, 0xe2,
0xa4, 0x2b, 0xac, 0xe7, 0x5c, 0x42, 0x5b, 0x30,
0x53, 0xef, 0xa2, 0x6f, 0xfe, 0x1b, 0xb3, 0x2f
};
const byte verify256_7[] = {
0x44, 0x3b, 0x17, 0x83, 0x7b, 0xb3, 0x93, 0x48,
0x61, 0x0d, 0x19, 0x20, 0x2d, 0xf8, 0xa1, 0xf9
};
#endif
struct kwpKat {
const byte* kek;
word32 kekSz;
const byte* in;
word32 inSz;
const byte* exp;
word32 expSz;
};
const struct kwpKat kats[] = {
#ifdef WOLFSSL_AES_128
{kek128, (word32)sizeof(kek128), data20, (word32)sizeof(data20),
verify128_20, (word32)sizeof(verify128_20)},
{kek128, (word32)sizeof(kek128), data7, (word32)sizeof(data7),
verify128_7, (word32)sizeof(verify128_7)},
#endif
#ifdef WOLFSSL_AES_192
{kek192, (word32)sizeof(kek192), data20, (word32)sizeof(data20),
verify192_20, (word32)sizeof(verify192_20)},
{kek192, (word32)sizeof(kek192), data7, (word32)sizeof(data7),
verify192_7, (word32)sizeof(verify192_7)},
#endif
#ifdef WOLFSSL_AES_256
{kek256, (word32)sizeof(kek256), data20, (word32)sizeof(data20),
verify256_20, (word32)sizeof(verify256_20)},
{kek256, (word32)sizeof(kek256), data7, (word32)sizeof(data7),
verify256_7, (word32)sizeof(verify256_7)},
#endif
};
word32 katCnt = (word32)(sizeof(kats) / sizeof(kats[0]));
word32 i;
byte out[40];
byte plain[32];
/* --- Known-answer + roundtrip for every KEK size and both paths --- */
for (i = 0; i < katCnt; i++) {
XMEMSET(out, 0, sizeof(out));
XMEMSET(plain, 0, sizeof(plain));
/* wrap matches the published / cross-checked vector */
ExpectIntEQ(wc_AesKeyWrap_Pad(kats[i].kek, kats[i].kekSz,
kats[i].in, kats[i].inSz,
out, sizeof(out), NULL),
(int)kats[i].expSz);
ExpectBufEQ(out, kats[i].exp, kats[i].expSz);
/* unwrap recovers the original plaintext and length */
ExpectIntEQ(wc_AesKeyUnWrap_Pad(kats[i].kek, kats[i].kekSz,
out, kats[i].expSz,
plain, sizeof(plain), NULL),
(int)kats[i].inSz);
ExpectBufEQ(plain, kats[i].in, kats[i].inSz);
}
/* Everything below indexes kats[0]; when no AES key size is enabled kats[]
* is empty (katCnt == 0), so skip it to keep the accesses in-bounds. */
if (katCnt == 0)
return EXPECT_RESULT();
/* --- Negative: a corrupted wrap must fail the integrity check --- */
XMEMSET(out, 0, sizeof(out));
ExpectIntGE(wc_AesKeyWrap_Pad(kats[0].kek, kats[0].kekSz,
kats[0].in, kats[0].inSz,
out, sizeof(out), NULL), 0);
out[0] ^= 0x01;
ExpectIntEQ(wc_AesKeyUnWrap_Pad(kats[0].kek, kats[0].kekSz,
out, kats[0].expSz,
plain, sizeof(plain), NULL),
WC_NO_ERR_TRACE(BAD_KEYWRAP_IV_E));
/* --- Bad args: wrap --- */
ExpectIntEQ(wc_AesKeyWrap_Pad(NULL, kats[0].kekSz, data7, sizeof(data7),
out, sizeof(out), NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_AesKeyWrap_Pad(kats[0].kek, kats[0].kekSz, NULL,
sizeof(data7), out, sizeof(out), NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_AesKeyWrap_Pad(kats[0].kek, kats[0].kekSz, data7, 0,
out, sizeof(out), NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_AesKeyWrap_Pad(kats[0].kek, kats[0].kekSz, data7,
sizeof(data7), NULL, sizeof(out), NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* 7 octets need 16 output bytes; an 8-byte buffer is too small */
ExpectIntEQ(wc_AesKeyWrap_Pad(kats[0].kek, kats[0].kekSz, data7,
sizeof(data7), out, 8, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* an inSz that would overflow ceil(inSz/8)+1 blocks is rejected up front
* (returns before reading 'in', so the short buffer is never accessed) */
ExpectIntEQ(wc_AesKeyWrap_Pad(kats[0].kek, kats[0].kekSz, data7,
0xFFFFFFF1U, out, sizeof(out), NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* --- Bad args: unwrap --- */
ExpectIntEQ(wc_AesKeyUnWrap_Pad(NULL, kats[0].kekSz, out, 16,
plain, sizeof(plain), NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_AesKeyUnWrap_Pad(kats[0].kek, kats[0].kekSz, NULL, 16,
plain, sizeof(plain), NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_AesKeyUnWrap_Pad(kats[0].kek, kats[0].kekSz, out, 16,
NULL, sizeof(plain), NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* input must be at least two 64-bit blocks and a multiple of 8 */
ExpectIntEQ(wc_AesKeyUnWrap_Pad(kats[0].kek, kats[0].kekSz, out, 8,
plain, sizeof(plain), NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_AesKeyUnWrap_Pad(kats[0].kek, kats[0].kekSz, out, 17,
plain, sizeof(plain), NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* output buffer smaller than the recovered padded plaintext */
ExpectIntEQ(wc_AesKeyUnWrap_Pad(kats[0].kek, kats[0].kekSz, out, 16,
plain, 4, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* --- IV override: a custom 4-byte AIV high-half constant --- */
{
const byte altIv[4] = { 0x12, 0x34, 0x56, 0x78 };
int sz;
/* single-block (ECB) path */
XMEMSET(out, 0, sizeof(out));
XMEMSET(plain, 0, sizeof(plain));
sz = wc_AesKeyWrap_Pad(kats[0].kek, kats[0].kekSz, data7, sizeof(data7),
out, sizeof(out), altIv);
ExpectIntGE(sz, 0);
ExpectIntEQ(wc_AesKeyUnWrap_Pad(kats[0].kek, kats[0].kekSz,
out, (word32)sz, plain, sizeof(plain), altIv),
(int)sizeof(data7));
ExpectBufEQ(plain, data7, sizeof(data7));
/* same blob must be rejected when unwrapped under the default AIV */
ExpectIntEQ(wc_AesKeyUnWrap_Pad(kats[0].kek, kats[0].kekSz, out,
(word32)sz, plain, sizeof(plain), NULL),
WC_NO_ERR_TRACE(BAD_KEYWRAP_IV_E));
/* multi-block (RFC 3394 loop) path */
XMEMSET(out, 0, sizeof(out));
XMEMSET(plain, 0, sizeof(plain));
sz = wc_AesKeyWrap_Pad(kats[0].kek, kats[0].kekSz, data20,
sizeof(data20), out, sizeof(out), altIv);
ExpectIntGE(sz, 0);
ExpectIntEQ(wc_AesKeyUnWrap_Pad(kats[0].kek, kats[0].kekSz,
out, (word32)sz, plain, sizeof(plain), altIv),
(int)sizeof(data20));
ExpectBufEQ(plain, data20, sizeof(data20));
}
/* --- Invalid KEK size exercises the SetKey-failure path in wrappers --- */
{
byte badKey[32];
XMEMSET(badKey, 0x0c, sizeof(badKey));
/* 20 octets is not a valid AES key size */
ExpectIntEQ(wc_AesKeyWrap_Pad(badKey, 20, data7, sizeof(data7),
out, sizeof(out), NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_AesKeyUnWrap_Pad(badKey, 20, out, 16,
plain, sizeof(plain), NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
}
/* Forge ciphertexts to drive unwrap checks 2 and 3: a decrypted block is
* AIV(8)|P(8), so ECB-encrypting a chosen block fixes what unwrap sees. */
{
Aes faes;
byte forgeBlk[WC_AES_BLOCK_SIZE];
byte forged[WC_AES_BLOCK_SIZE];
XMEMSET(&faes, 0, sizeof(faes));
/* check 2: correct AIV constant but MLI = 0 (fails 8*(n-1) < MLI) */
XMEMSET(forgeBlk, 0, sizeof(forgeBlk));
forgeBlk[0] = 0xa6; forgeBlk[1] = 0x59; forgeBlk[2] = 0x59;
forgeBlk[3] = 0xa6;
/* MLI bytes [4..7] remain 0 */
forgeBlk[8] = 0x11; /* arbitrary recovered plaintext octet */
ExpectIntEQ(wc_AesInit(&faes, NULL, INVALID_DEVID), 0);
ExpectIntEQ(wc_AesSetKey(&faes, kats[0].kek, kats[0].kekSz, NULL,
AES_ENCRYPTION), 0);
ExpectIntEQ(wc_AesEncryptDirect(&faes, forged, forgeBlk), 0);
wc_AesFree(&faes);
ExpectIntEQ(wc_AesKeyUnWrap_Pad(kats[0].kek, kats[0].kekSz, forged, 16,
plain, sizeof(plain), NULL),
WC_NO_ERR_TRACE(BAD_KEYWRAP_IV_E));
/* check 3: correct AIV constant, MLI = 1, but a nonzero pad octet */
XMEMSET(forgeBlk, 0, sizeof(forgeBlk));
forgeBlk[0] = 0xa6; forgeBlk[1] = 0x59; forgeBlk[2] = 0x59;
forgeBlk[3] = 0xa6;
forgeBlk[7] = 0x01; /* MLI = 1 */
forgeBlk[8] = 0x41; /* the one real octet... */
forgeBlk[9] = 0xff; /* ...followed by a nonzero pad octet -> rejected */
ExpectIntEQ(wc_AesInit(&faes, NULL, INVALID_DEVID), 0);
ExpectIntEQ(wc_AesSetKey(&faes, kats[0].kek, kats[0].kekSz, NULL,
AES_ENCRYPTION), 0);
ExpectIntEQ(wc_AesEncryptDirect(&faes, forged, forgeBlk), 0);
wc_AesFree(&faes);
ExpectIntEQ(wc_AesKeyUnWrap_Pad(kats[0].kek, kats[0].kekSz, forged, 16,
plain, sizeof(plain), NULL),
WC_NO_ERR_TRACE(BAD_KEYWRAP_IV_E));
}
#if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \
defined(WOLFSSL_AES_256)
/* Extended coverage per key size: pyca/cryptography boundary-size KATs
* (reproduce RFC 5649 s6), exhaustive round-trip 1..64, and in-place. */
{
#ifdef WOLFSSL_AES_128
static const byte k128_1[] = {
0xdc, 0x0c, 0xed, 0x32, 0x50, 0xa4, 0x92, 0x77, 0x59, 0xb4, 0xe9, 0x28,
0x73, 0x2e, 0x16, 0x8a };
static const byte k128_8[] = {
0x23, 0xe1, 0xcd, 0x73, 0x92, 0xf0, 0xcc, 0x69, 0xdc, 0x20, 0xdf, 0x56,
0x48, 0x9f, 0xfd, 0xd7 };
static const byte k128_9[] = {
0xe6, 0xe7, 0x6a, 0xfc, 0xf1, 0xf7, 0x1f, 0x43, 0x63, 0x4b, 0x96, 0x91,
0x9c, 0x1e, 0x36, 0xa9, 0x5b, 0xf7, 0xb0, 0x26, 0x0f, 0x51, 0x9b, 0x4b };
static const byte k128_16[] = {
0xa7, 0x41, 0x46, 0x28, 0x3b, 0x00, 0x85, 0x06, 0x23, 0xd3, 0x02, 0xf4,
0x57, 0xb1, 0x8c, 0x96, 0xac, 0xe5, 0xb5, 0xd3, 0x64, 0x7c, 0xc2, 0xf1 };
static const byte k128_17[] = {
0x8d, 0x69, 0xe5, 0xc5, 0x01, 0x98, 0x70, 0xd3, 0x50, 0x37, 0x3a, 0x00,
0xa8, 0xe3, 0xa5, 0x32, 0xdf, 0xce, 0x76, 0x8a, 0x6b, 0x79, 0xef, 0x2c,
0x34, 0xcf, 0xed, 0x5c, 0xb4, 0x09, 0xff, 0xf4 };
static const byte k128_31[] = {
0x50, 0x3e, 0xc4, 0xff, 0x2e, 0xd3, 0x01, 0x14, 0xfa, 0x5a, 0x02, 0x47,
0x9f, 0x20, 0x4c, 0xb1, 0xd8, 0xcb, 0xa2, 0xa3, 0xa3, 0x7d, 0x7b, 0xa5,
0x60, 0x77, 0x01, 0x46, 0xd6, 0x03, 0x93, 0xe0, 0xf0, 0x01, 0xf7, 0x88,
0xb0, 0x4b, 0xc6, 0xb2 };
#endif
#ifdef WOLFSSL_AES_192
static const byte k192_1[] = {
0x95, 0xf7, 0xba, 0x0a, 0x72, 0x6e, 0xed, 0x9a, 0x90, 0xa9, 0x90, 0x00,
0x94, 0xc5, 0xd9, 0x2d };
static const byte k192_8[] = {
0xaa, 0x6f, 0x7d, 0x3b, 0xab, 0x34, 0x91, 0xcc, 0xd9, 0x52, 0xc9, 0x86,
0x64, 0x42, 0x8c, 0x40 };
static const byte k192_9[] = {
0x52, 0xa0, 0xf3, 0xda, 0x5a, 0x48, 0xaf, 0xe9, 0xac, 0x1e, 0x8f, 0x96,
0x84, 0x25, 0x93, 0x8e, 0xd5, 0x35, 0xaa, 0xe9, 0xbc, 0xe1, 0x0b, 0x52 };
static const byte k192_16[] = {
0xe8, 0xba, 0xab, 0xb4, 0xa1, 0xf3, 0x57, 0x6e, 0x72, 0xe4, 0x71, 0xca,
0x51, 0x2b, 0x5b, 0x64, 0xfb, 0x25, 0x25, 0x97, 0xfc, 0x80, 0x75, 0xe3 };
static const byte k192_17[] = {
0xaf, 0x1e, 0xc0, 0xdf, 0x04, 0xef, 0xde, 0xb6, 0x0d, 0xa4, 0xdf, 0xf5,
0x89, 0x84, 0x14, 0x91, 0x11, 0xdf, 0xda, 0x2d, 0xef, 0xc1, 0x30, 0x6e,
0x54, 0x46, 0x2e, 0xc3, 0xac, 0x57, 0xf7, 0x8a };
static const byte k192_31[] = {
0x1d, 0x59, 0x4c, 0x1a, 0x06, 0x03, 0x33, 0x60, 0x03, 0x12, 0x1e, 0x69,
0x81, 0xd8, 0xbe, 0xc6, 0x0a, 0xef, 0x71, 0x7f, 0x62, 0x1e, 0x95, 0xb1,
0xfb, 0x29, 0x96, 0x61, 0x39, 0x78, 0xbb, 0x5f, 0x52, 0xee, 0xc6, 0xda,
0xed, 0xd8, 0x48, 0x97 };
#endif
#ifdef WOLFSSL_AES_256
static const byte k256_1[] = {
0xcc, 0xc4, 0x9f, 0xbf, 0x20, 0xf2, 0xac, 0xe7, 0xeb, 0x31, 0xa8, 0xdd,
0xe2, 0x26, 0x50, 0x6a };
static const byte k256_8[] = {
0xea, 0x91, 0xdd, 0x60, 0xe5, 0x9b, 0xd6, 0x8b, 0xad, 0x0d, 0x6e, 0x25,
0x4b, 0x5e, 0x1c, 0x39 };
static const byte k256_9[] = {
0xc9, 0x72, 0x2a, 0x95, 0x51, 0xdf, 0xa2, 0x83, 0x2a, 0xa1, 0xca, 0xe4,
0x87, 0x82, 0x1e, 0x06, 0x99, 0x12, 0x94, 0xae, 0xbc, 0xe0, 0x98, 0x48 };
static const byte k256_16[] = {
0xb3, 0x33, 0x58, 0x13, 0x95, 0xce, 0xdf, 0x83, 0x56, 0xdc, 0x35, 0x6c,
0x1c, 0xc7, 0x9e, 0x9a, 0x88, 0x5c, 0xb4, 0x98, 0x8e, 0xd6, 0x29, 0xb8 };
static const byte k256_17[] = {
0x18, 0x58, 0x36, 0x63, 0x5d, 0xea, 0xaf, 0x4d, 0xa8, 0x27, 0x0c, 0x04,
0x89, 0x09, 0xae, 0xbf, 0xe9, 0x21, 0x11, 0x66, 0xca, 0x2f, 0xdb, 0x34,
0xa0, 0x93, 0x69, 0xfe, 0x9b, 0xb8, 0x6b, 0x04 };
static const byte k256_31[] = {
0x16, 0x44, 0xf1, 0x8b, 0x57, 0xc7, 0xb3, 0xf1, 0x85, 0x51, 0xbe, 0x73,
0xff, 0xd0, 0x9c, 0xa7, 0x42, 0xf7, 0xf1, 0x56, 0x26, 0x1d, 0x58, 0x95,
0xaa, 0xc0, 0x97, 0xc4, 0xb6, 0x4e, 0x02, 0x80, 0xfc, 0x80, 0xbd, 0xac,
0x45, 0x2c, 0x90, 0x10 };
#endif
static const word32 bsz[] = { 1, 8, 9, 16, 17, 31 };
static const word32 bes[] = { 16, 16, 24, 24, 32, 40 };
const struct { const byte* kek; word32 kekSz; const byte* exp[6]; } ek[] = {
#ifdef WOLFSSL_AES_128
{ kek128, (word32)sizeof(kek128),
{ k128_1, k128_8, k128_9, k128_16, k128_17, k128_31 } },
#endif
#ifdef WOLFSSL_AES_192
{ kek192, (word32)sizeof(kek192),
{ k192_1, k192_8, k192_9, k192_16, k192_17, k192_31 } },
#endif
#ifdef WOLFSSL_AES_256
{ kek256, (word32)sizeof(kek256),
{ k256_1, k256_8, k256_9, k256_16, k256_17, k256_31 } },
#endif
};
byte ewrap[80];
byte eback[80];
byte rpt[64];
word32 ki, bi, s, t;
for (t = 0; t < (word32)sizeof(rpt); t++)
rpt[t] = (byte)(0xA0 + t);
for (ki = 0; ki < (word32)(sizeof(ek) / sizeof(ek[0])); ki++) {
/* boundary-size known-answer + round-trip */
for (bi = 0; bi < (word32)(sizeof(bsz) / sizeof(bsz[0])); bi++) {
XMEMSET(ewrap, 0, sizeof(ewrap));
XMEMSET(eback, 0, sizeof(eback));
ExpectIntEQ(wc_AesKeyWrap_Pad(ek[ki].kek, ek[ki].kekSz,
rpt, bsz[bi], ewrap, sizeof(ewrap), NULL),
(int)bes[bi]);
ExpectBufEQ(ewrap, ek[ki].exp[bi], bes[bi]);
ExpectIntEQ(wc_AesKeyUnWrap_Pad(ek[ki].kek, ek[ki].kekSz,
ewrap, bes[bi], eback, sizeof(eback), NULL),
(int)bsz[bi]);
ExpectBufEQ(eback, rpt, bsz[bi]);
}
/* exhaustive round-trip for every input size 1..64 */
for (s = 1; s <= (word32)sizeof(rpt); s++) {
int w;
word32 expW = ((s + 7u) / 8u) * 8u + 8u;
XMEMSET(ewrap, 0, sizeof(ewrap));
XMEMSET(eback, 0, sizeof(eback));
w = wc_AesKeyWrap_Pad(ek[ki].kek, ek[ki].kekSz,
rpt, s, ewrap, sizeof(ewrap), NULL);
ExpectIntEQ(w, (int)expW);
ExpectIntEQ(wc_AesKeyUnWrap_Pad(ek[ki].kek, ek[ki].kekSz,
ewrap, (word32)w, eback, sizeof(eback), NULL),
(int)s);
ExpectBufEQ(eback, rpt, s);
}
/* in-place (in == out aliasing must be supported) */
{
byte buf[80];
int w;
XMEMSET(buf, 0, sizeof(buf));
XMEMCPY(buf, data20, sizeof(data20));
w = wc_AesKeyWrap_Pad(ek[ki].kek, ek[ki].kekSz, buf,
(word32)sizeof(data20), buf,
sizeof(buf), NULL);
ExpectIntGE(w, 0);
ExpectIntEQ(wc_AesKeyUnWrap_Pad(ek[ki].kek, ek[ki].kekSz, buf,
(word32)w, buf, sizeof(buf), NULL),
(int)sizeof(data20));
ExpectBufEQ(buf, data20, sizeof(data20));
}
}
}
#endif /* WOLFSSL_AES_128 || WOLFSSL_AES_192 || WOLFSSL_AES_256 */
return EXPECT_RESULT();
} /* END test_wc_AesKeyWrap_Pad */
#endif /* HAVE_AES_KEYWRAP && WOLFSSL_AES_KEYWRAP_PADDING */
/*----------------------------------------------------------------------------*
| AES-SIV Test
*----------------------------------------------------------------------------*/
@@ -10431,6 +10859,271 @@ int test_wc_AesSivEncryptDecrypt(void)
#endif /* WOLFSSL_AES_SIV && WOLFSSL_AES_128 */
/*----------------------------------------------------------------------------*
| CryptoCB AES Key Wrap Test
*----------------------------------------------------------------------------*/
#if defined(WOLF_CRYPTO_CB) && defined(HAVE_AES_KEYWRAP) && \
!defined(NO_AES) && defined(WOLFSSL_AES_128)
#include <wolfssl/wolfcrypt/cryptocb.h>
/* Test CryptoCB device IDs (must be unique across test_aes.c); 7/8/9 are used
* by the SetKey/AES-GCM/TLS13 tests above. */
#define TEST_CRYPTOCB_KEYWRAP_DEVID 10
static int cbKwWrapCalled = 0;
static int cbKwUnwrapCalled = 0;
/* Mock device: run the (un)wrap in software via the op's own Aes (holds the
* KEK) with devId cleared so the _ex call does not re-enter the callback. */
static int test_CryptoCb_KeyWrap_Cb(int devId, wc_CryptoInfo* info, void* ctx)
{
Aes* aes;
int r;
int devIdSave;
const byte* in;
word32 inSz;
byte* out;
word32 outSz;
const byte* iv;
int pad;
(void)ctx;
if (devId != TEST_CRYPTOCB_KEYWRAP_DEVID)
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
if (info->algo_type != WC_ALGO_TYPE_CIPHER ||
info->cipher.type != WC_CIPHER_AES_KEYWRAP)
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
aes = info->cipher.aeskeywrap.aes;
in = info->cipher.aeskeywrap.in;
inSz = info->cipher.aeskeywrap.inSz;
out = info->cipher.aeskeywrap.out;
outSz = info->cipher.aeskeywrap.outSz;
iv = info->cipher.aeskeywrap.iv;
pad = info->cipher.aeskeywrap.pad;
devIdSave = aes->devId;
aes->devId = INVALID_DEVID; /* force software, no callback re-entry */
if (info->cipher.enc) {
cbKwWrapCalled++;
#ifdef WOLFSSL_AES_KEYWRAP_PADDING
if (pad)
r = wc_AesKeyWrap_Pad_ex(aes, in, inSz, out, outSz, iv);
else
#endif
r = wc_AesKeyWrap_ex(aes, in, inSz, out, outSz, iv);
}
else {
cbKwUnwrapCalled++;
#ifdef WOLFSSL_AES_KEYWRAP_PADDING
if (pad)
r = wc_AesKeyUnWrap_Pad_ex(aes, in, inSz, out, outSz, iv);
else
#endif
r = wc_AesKeyUnWrap_ex(aes, in, inSz, out, outSz, iv);
}
(void)pad;
aes->devId = devIdSave;
if (r < 0)
return r;
info->cipher.aeskeywrap.outResSz = (word32)r;
return 0;
}
int test_wc_CryptoCb_AesKeyWrap(void)
{
EXPECT_DECLS;
Aes aes;
int sz;
/* RFC 3394 section 4.1: wrap 128 bits with a 128-bit KEK */
WOLFSSL_SMALL_STACK_STATIC const byte kek[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
};
WOLFSSL_SMALL_STACK_STATIC const byte data[] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
};
WOLFSSL_SMALL_STACK_STATIC const byte verify[] = {
0x1F, 0xA6, 0x8B, 0x0A, 0x81, 0x12, 0xB4, 0x47,
0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82,
0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5
};
byte out[40];
byte plain[32];
cbKwWrapCalled = 0;
cbKwUnwrapCalled = 0;
ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_CRYPTOCB_KEYWRAP_DEVID,
test_CryptoCb_KeyWrap_Cb, NULL), 0);
/* RFC 3394 wrap: encryption-keyed Aes carrying the devId dispatches to the
* device, which wraps in software and matches the KAT. */
XMEMSET(&aes, 0, sizeof(aes));
ExpectIntEQ(wc_AesInit(&aes, NULL, TEST_CRYPTOCB_KEYWRAP_DEVID), 0);
ExpectIntEQ(wc_AesSetKey(&aes, kek, (word32)sizeof(kek), NULL,
AES_ENCRYPTION), 0);
XMEMSET(out, 0, sizeof(out));
sz = wc_AesKeyWrap_ex(&aes, data, (word32)sizeof(data), out,
(word32)sizeof(out), NULL);
ExpectIntEQ(sz, (int)sizeof(verify));
ExpectBufEQ(out, verify, sizeof(verify));
ExpectIntGE(cbKwWrapCalled, 1);
wc_AesFree(&aes);
/* RFC 3394 unwrap: decryption-keyed Aes carrying the devId. */
XMEMSET(&aes, 0, sizeof(aes));
ExpectIntEQ(wc_AesInit(&aes, NULL, TEST_CRYPTOCB_KEYWRAP_DEVID), 0);
ExpectIntEQ(wc_AesSetKey(&aes, kek, (word32)sizeof(kek), NULL,
AES_DECRYPTION), 0);
XMEMSET(plain, 0, sizeof(plain));
sz = wc_AesKeyUnWrap_ex(&aes, verify, (word32)sizeof(verify), plain,
(word32)sizeof(plain), NULL);
ExpectIntEQ(sz, (int)sizeof(data));
ExpectBufEQ(plain, data, sizeof(data));
ExpectIntGE(cbKwUnwrapCalled, 1);
wc_AesFree(&aes);
#ifdef WOLFSSL_AES_KEYWRAP_PADDING
/* RFC 5649 padded wrap/unwrap (7 octets -> single-block path) also
* dispatches to the device and round-trips. */
{
WOLFSSL_SMALL_STACK_STATIC const byte pdata[] = {
0x46, 0x6f, 0x72, 0x50, 0x61, 0x73, 0x69
};
cbKwWrapCalled = 0;
cbKwUnwrapCalled = 0;
/* padded wrap (encryption key) */
XMEMSET(&aes, 0, sizeof(aes));
ExpectIntEQ(wc_AesInit(&aes, NULL, TEST_CRYPTOCB_KEYWRAP_DEVID), 0);
ExpectIntEQ(wc_AesSetKey(&aes, kek, (word32)sizeof(kek), NULL,
AES_ENCRYPTION), 0);
XMEMSET(out, 0, sizeof(out));
sz = wc_AesKeyWrap_Pad_ex(&aes, pdata, (word32)sizeof(pdata), out,
(word32)sizeof(out), NULL);
ExpectIntGE(sz, 0);
ExpectIntGE(cbKwWrapCalled, 1);
wc_AesFree(&aes);
/* padded unwrap (decryption key) */
XMEMSET(&aes, 0, sizeof(aes));
ExpectIntEQ(wc_AesInit(&aes, NULL, TEST_CRYPTOCB_KEYWRAP_DEVID), 0);
ExpectIntEQ(wc_AesSetKey(&aes, kek, (word32)sizeof(kek), NULL,
AES_DECRYPTION), 0);
XMEMSET(plain, 0, sizeof(plain));
sz = wc_AesKeyUnWrap_Pad_ex(&aes, out, (word32)sz, plain,
(word32)sizeof(plain), NULL);
ExpectIntEQ(sz, (int)sizeof(pdata));
ExpectBufEQ(plain, pdata, sizeof(pdata));
ExpectIntGE(cbKwUnwrapCalled, 1);
wc_AesFree(&aes);
}
#endif
wc_CryptoCb_UnRegisterDevice(TEST_CRYPTOCB_KEYWRAP_DEVID);
return EXPECT_RESULT();
}
#if defined(HAVE_AES_ECB) && !defined(WOLF_CRYPTO_CB_ONLY_AES)
/* Second mock device: services only AES-ECB and declines key wrap. With
* HAVE_AES_ECB the RFC 3394 loops call wc_AesEcbEncrypt/Decrypt per block, which
* dispatch to a registered ECB crypto callback. This device counts those ECB
* dispatches and declines them so the real work falls back to software - proving
* key wrap routes its blocks through the ECB callback even when the device has
* no key wrap support. (Needs a software AES fallback, so not for CB_ONLY_AES.) */
#define TEST_CRYPTOCB_KEYWRAP_ECB_DEVID 11
static int cbKwEcbEncCalled = 0;
static int cbKwEcbDecCalled = 0;
static int test_CryptoCb_KeyWrapEcb_Cb(int devId, wc_CryptoInfo* info, void* ctx)
{
(void)ctx;
if (devId != TEST_CRYPTOCB_KEYWRAP_ECB_DEVID)
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
if (info->algo_type == WC_ALGO_TYPE_CIPHER &&
info->cipher.type == WC_CIPHER_AES_ECB) {
if (info->cipher.enc)
cbKwEcbEncCalled++;
else
cbKwEcbDecCalled++;
}
/* Decline everything (key wrap and ECB): software performs the actual work;
* we only prove the ECB dispatch is reached during key wrap. */
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
}
int test_wc_CryptoCb_AesKeyWrapEcbCompose(void)
{
EXPECT_DECLS;
Aes aes;
int sz;
/* RFC 3394 section 4.1: wrap 128 bits with a 128-bit KEK */
WOLFSSL_SMALL_STACK_STATIC const byte kek[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
};
WOLFSSL_SMALL_STACK_STATIC const byte data[] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
};
WOLFSSL_SMALL_STACK_STATIC const byte verify[] = {
0x1F, 0xA6, 0x8B, 0x0A, 0x81, 0x12, 0xB4, 0x47,
0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82,
0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5
};
byte out[40];
byte plain[32];
cbKwEcbEncCalled = 0;
cbKwEcbDecCalled = 0;
ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_CRYPTOCB_KEYWRAP_ECB_DEVID,
test_CryptoCb_KeyWrapEcb_Cb, NULL), 0);
/* wrap: device offers only ECB, so key wrap composes RFC 3394 from ECB
* block dispatches; software fallback produces the KAT output. */
XMEMSET(&aes, 0, sizeof(aes));
ExpectIntEQ(wc_AesInit(&aes, NULL, TEST_CRYPTOCB_KEYWRAP_ECB_DEVID), 0);
ExpectIntEQ(wc_AesSetKey(&aes, kek, (word32)sizeof(kek), NULL,
AES_ENCRYPTION), 0);
XMEMSET(out, 0, sizeof(out));
sz = wc_AesKeyWrap_ex(&aes, data, (word32)sizeof(data), out,
(word32)sizeof(out), NULL);
ExpectIntEQ(sz, (int)sizeof(verify));
ExpectBufEQ(out, verify, sizeof(verify));
ExpectIntGE(cbKwEcbEncCalled, 1); /* ECB callback reached during wrap */
wc_AesFree(&aes);
/* unwrap: composes from ECB decrypt block dispatches. */
XMEMSET(&aes, 0, sizeof(aes));
ExpectIntEQ(wc_AesInit(&aes, NULL, TEST_CRYPTOCB_KEYWRAP_ECB_DEVID), 0);
ExpectIntEQ(wc_AesSetKey(&aes, kek, (word32)sizeof(kek), NULL,
AES_DECRYPTION), 0);
XMEMSET(plain, 0, sizeof(plain));
sz = wc_AesKeyUnWrap_ex(&aes, verify, (word32)sizeof(verify), plain,
(word32)sizeof(plain), NULL);
ExpectIntEQ(sz, (int)sizeof(data));
ExpectBufEQ(plain, data, sizeof(data));
ExpectIntGE(cbKwEcbDecCalled, 1); /* ECB callback reached during unwrap */
wc_AesFree(&aes);
wc_CryptoCb_UnRegisterDevice(TEST_CRYPTOCB_KEYWRAP_ECB_DEVID);
return EXPECT_RESULT();
}
#endif /* HAVE_AES_ECB && !WOLF_CRYPTO_CB_ONLY_AES */
#endif /* WOLF_CRYPTO_CB && HAVE_AES_KEYWRAP && !NO_AES && WOLFSSL_AES_128 */
/*----------------------------------------------------------------------------*
| CryptoCB AES SetKey Test
*----------------------------------------------------------------------------*/
+26
View File
@@ -96,6 +96,9 @@ int test_wc_AesEaxArgMcdc(void);
#if defined(WOLFSSL_AES_SIV) && defined(WOLFSSL_AES_128)
int test_wc_AesSivEncryptDecrypt(void);
#endif
#if defined(HAVE_AES_KEYWRAP) && defined(WOLFSSL_AES_KEYWRAP_PADDING)
int test_wc_AesKeyWrap_Pad(void);
#endif
int test_wc_AesCbc_MonteCarlo(void);
int test_wc_AesCtr_MonteCarlo(void);
@@ -162,6 +165,23 @@ int test_wc_CryptoCb_Tls13_Key_No_Zero_Without_Offload(void);
#define TEST_CRYPTOCB_AESOFB_DECL
#endif
#if defined(WOLF_CRYPTO_CB) && defined(HAVE_AES_KEYWRAP) && \
!defined(NO_AES) && defined(WOLFSSL_AES_128)
int test_wc_CryptoCb_AesKeyWrap(void);
#if defined(HAVE_AES_ECB) && !defined(WOLF_CRYPTO_CB_ONLY_AES)
int test_wc_CryptoCb_AesKeyWrapEcbCompose(void);
#define TEST_CRYPTOCB_AES_KEYWRAP_ECB_DECL \
, TEST_DECL_GROUP("aes", test_wc_CryptoCb_AesKeyWrapEcbCompose)
#else
#define TEST_CRYPTOCB_AES_KEYWRAP_ECB_DECL
#endif
#define TEST_CRYPTOCB_AES_KEYWRAP_DECL \
, TEST_DECL_GROUP("aes", test_wc_CryptoCb_AesKeyWrap) \
TEST_CRYPTOCB_AES_KEYWRAP_ECB_DECL
#else
#define TEST_CRYPTOCB_AES_KEYWRAP_DECL
#endif
#define TEST_AES_DECLS \
TEST_DECL_GROUP("aes", test_wc_AesSetKey), \
TEST_DECL_GROUP("aes", test_wc_AesSetIV), \
@@ -228,6 +248,7 @@ 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_AES_KEYWRAP_DECL \
TEST_CRYPTOCB_TLS13_KEY_ZERO_DECL \
TEST_CRYPTOCB_AESCFB_DECL \
TEST_CRYPTOCB_AESOFB_DECL
@@ -248,6 +269,11 @@ int test_wc_CryptoCb_Tls13_Key_No_Zero_Without_Offload(void);
TEST_DECL_GROUP("aes-siv", test_wc_AesSivArgMcdc)
#endif /* WOLFSSL_AES_SIV && WOLFSSL_AES_128 */
#if defined(HAVE_AES_KEYWRAP) && defined(WOLFSSL_AES_KEYWRAP_PADDING)
#define TEST_AES_KEYWRAP_DECLS \
TEST_DECL_GROUP("aes-keywrap", test_wc_AesKeyWrap_Pad)
#endif /* HAVE_AES_KEYWRAP && WOLFSSL_AES_KEYWRAP_PADDING */
#define TEST_GMAC_DECLS \
TEST_DECL_GROUP("gmac", test_wc_GmacSetKey), \
TEST_DECL_GROUP("gmac", test_wc_GmacUpdate)
+60
View File
@@ -829,6 +829,62 @@ static int swdev_aes_ecb(wc_CryptoInfo* info)
}
#endif /* HAVE_AES_ECB || WOLFSSL_AES_DIRECT */
#if defined(HAVE_AES_KEYWRAP) && !defined(SWDEV_AES_ONLYECB)
/* AES Key Wrap (RFC 3394) and, when built, Key Wrap with Padding (RFC 5649).
* enc selects wrap (forward cipher) vs unwrap (inverse cipher); pad selects the
* RFC 5649 variant. The wrap/unwrap helpers return the produced byte count,
* which the cryptocb contract reports via outResSz with a 0 return. Gated like
* swdev_aes_gcm so SWDEV_AES_ONLYECB instead forces the parent's CB_ONLY_AES
* host-side key wrap (block ops dispatch back through cryptocb ECB). */
static int swdev_aes_keywrap(wc_CryptoInfo* info)
{
Aes* aes = info->cipher.aeskeywrap.aes;
const byte* in = info->cipher.aeskeywrap.in;
word32 inSz = info->cipher.aeskeywrap.inSz;
byte* out = info->cipher.aeskeywrap.out;
word32 outSz = info->cipher.aeskeywrap.outSz;
const byte* iv = info->cipher.aeskeywrap.iv;
Aes shadow;
int ret;
int dir;
if (info->cipher.enc)
dir = AES_ENCRYPTION;
else
dir = AES_DECRYPTION;
ret = swdev_aes_shadow_init(&shadow, aes, dir);
if (ret != 0)
return ret;
if (info->cipher.enc) {
#ifdef WOLFSSL_AES_KEYWRAP_PADDING
if (info->cipher.aeskeywrap.pad)
ret = wc_AesKeyWrap_Pad_ex(&shadow, in, inSz, out, outSz, iv);
else
#endif
ret = wc_AesKeyWrap_ex(&shadow, in, inSz, out, outSz, iv);
}
else {
#ifdef WOLFSSL_AES_KEYWRAP_PADDING
if (info->cipher.aeskeywrap.pad)
ret = wc_AesKeyUnWrap_Pad_ex(&shadow, in, inSz, out, outSz, iv);
else
#endif
ret = wc_AesKeyUnWrap_ex(&shadow, in, inSz, out, outSz, iv);
}
wc_AesFree(&shadow);
if (ret < 0)
return ret;
/* success: report produced length; cryptocb returns outResSz on ret==0 */
info->cipher.aeskeywrap.outResSz = (word32)ret;
return 0;
}
#endif /* HAVE_AES_KEYWRAP && !SWDEV_AES_ONLYECB */
/* SWDEV_AES_ONLYECB: when defined, swdev's AES backend returns
* CRYPTOCB_UNAVAILABLE for AES-GCM so the parent's CB_ONLY_AES host-side
* GCM software path runs (GHASH on the host; AES-CTR blocks dispatch back
@@ -1083,6 +1139,10 @@ WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info,
#ifdef HAVE_AESCCM
case WC_CIPHER_AES_CCM:
return swdev_aes_ccm(info);
#endif
#if defined(HAVE_AES_KEYWRAP) && !defined(SWDEV_AES_ONLYECB)
case WC_CIPHER_AES_KEYWRAP:
return swdev_aes_keywrap(info);
#endif
default:
return CRYPTOCB_UNAVAILABLE;
+442 -41
View File
@@ -56,6 +56,7 @@ block cipher mechanism that uses n-bit binary string parameter key with 128-bits
* WOLFSSL_CMAC: Enable AES-CMAC (RFC 4493) default: off
* HAVE_AESCCM: Enable AES-CCM mode default: off
* HAVE_AES_KEYWRAP: Enable AES key wrap (RFC 3394) default: off
* WOLFSSL_AES_KEYWRAP_PADDING: AES key wrap padding (RFC 5649) default: off
* WOLFSSL_AES_CBC_LENGTH_CHECKS: Validate CBC input length default: off
*
* AES-GCM:
@@ -17184,8 +17185,9 @@ static WC_INLINE void DecrementKeyWrapCounter(byte* inOutCtr)
}
}
int wc_AesKeyWrap_ex(Aes *aes, const byte* in, word32 inSz, byte* out,
word32 outSz, const byte* iv)
/* Core RFC 3394 wrapping loop: plaintext at out+8, initial A in aiv; writes
* C[0]=A and wrapped R[i] in place. Caller owns output-buffer sizing. */
static int AesKeyWrapRaw(Aes* aes, word32 inSz, byte* out, const byte* aiv)
{
word32 i;
byte* r;
@@ -17195,34 +17197,34 @@ int wc_AesKeyWrap_ex(Aes *aes, const byte* in, word32 inSz, byte* out,
byte t[KEYWRAP_BLOCK_SIZE];
byte tmp[WC_AES_BLOCK_SIZE];
/* n must be at least 2 64-bit blocks, output size is (n + 1) 8 bytes (64-bit) */
if (aes == NULL || in == NULL || inSz < 2*KEYWRAP_BLOCK_SIZE ||
out == NULL || outSz < (inSz + KEYWRAP_BLOCK_SIZE))
/* at least two 64-bit blocks, on a 64-bit boundary */
if (aes == NULL || out == NULL || aiv == NULL ||
inSz < 2 * KEYWRAP_BLOCK_SIZE || (inSz % KEYWRAP_BLOCK_SIZE) != 0) {
return BAD_FUNC_ARG;
/* input must be multiple of 64-bits */
if (inSz % KEYWRAP_BLOCK_SIZE != 0)
return BAD_FUNC_ARG;
r = out + 8;
XMEMCPY(r, in, inSz);
XMEMSET(t, 0, sizeof(t));
/* user IV is optional */
if (iv == NULL) {
XMEMSET(tmp, 0xA6, KEYWRAP_BLOCK_SIZE);
} else {
XMEMCPY(tmp, iv, KEYWRAP_BLOCK_SIZE);
}
r = out + KEYWRAP_BLOCK_SIZE;
XMEMSET(t, 0, sizeof(t));
/* A = initial value */
XMEMCPY(tmp, aiv, KEYWRAP_BLOCK_SIZE);
#ifndef HAVE_AES_ECB
/* Direct block access must save vector registers across the loop; with
* HAVE_AES_ECB wc_AesEcbEncrypt saves them and can route to an ECB cb. */
VECTOR_REGISTERS_PUSH;
#endif
for (j = 0; j <= 5; j++) {
for (i = 1; i <= inSz / KEYWRAP_BLOCK_SIZE; i++) {
/* load R[i] */
XMEMCPY(tmp + KEYWRAP_BLOCK_SIZE, r, KEYWRAP_BLOCK_SIZE);
#ifdef HAVE_AES_ECB
ret = wc_AesEcbEncrypt(aes, tmp, tmp, WC_AES_BLOCK_SIZE);
#else
ret = wc_AesEncryptDirect(aes, tmp, tmp);
#endif
if (ret != 0)
break;
@@ -17239,7 +17241,9 @@ int wc_AesKeyWrap_ex(Aes *aes, const byte* in, word32 inSz, byte* out,
r = out + KEYWRAP_BLOCK_SIZE;
}
#ifndef HAVE_AES_ECB
VECTOR_REGISTERS_POP;
#endif
if (ret != 0)
return ret;
@@ -17247,6 +17251,55 @@ int wc_AesKeyWrap_ex(Aes *aes, const byte* in, word32 inSz, byte* out,
/* C[0] = A */
XMEMCPY(out, tmp, KEYWRAP_BLOCK_SIZE);
return 0;
}
int wc_AesKeyWrap_ex(Aes *aes, const byte* in, word32 inSz, byte* out,
word32 outSz, const byte* iv)
{
int ret;
byte aiv[KEYWRAP_BLOCK_SIZE];
/* >= two 64-bit blocks on a 64-bit boundary, output fits outSz; inSz
* capped at INT_MAX-8 so the returned inSz+8 stays a non-negative int. */
if (aes == NULL || in == NULL || out == NULL ||
inSz < 2 * KEYWRAP_BLOCK_SIZE || (inSz % KEYWRAP_BLOCK_SIZE) != 0 ||
inSz > 0x7FFFFFFFU - KEYWRAP_BLOCK_SIZE ||
outSz < inSz + KEYWRAP_BLOCK_SIZE)
return BAD_FUNC_ARG;
#ifdef WOLF_CRYPTO_CB
#ifndef WOLF_CRYPTO_CB_FIND
if (aes->devId != INVALID_DEVID)
#endif
{
ret = wc_CryptoCb_AesKeyWrap(aes, in, inSz, out, outSz, iv, 0);
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
return ret;
}
/* fall through to software when unavailable */
}
#endif
/* user IV is optional */
if (iv == NULL) {
XMEMSET(aiv, 0xA6, KEYWRAP_BLOCK_SIZE);
}
else {
XMEMCPY(aiv, iv, KEYWRAP_BLOCK_SIZE);
}
/* stage plaintext at out+8; XMEMMOVE so in-place wrap (in == out) is safe */
XMEMMOVE(out + KEYWRAP_BLOCK_SIZE, in, inSz);
ret = AesKeyWrapRaw(aes, inSz, out, aiv);
if (ret != 0) {
/* wipe the plaintext staged at out+8 (and any partial cipher state
* left there) so it is not leaked to the caller on failure */
ForceZero(out + KEYWRAP_BLOCK_SIZE, inSz);
return ret;
}
return (int)(inSz + KEYWRAP_BLOCK_SIZE);
}
@@ -17286,8 +17339,10 @@ int wc_AesKeyWrap(const byte* key, word32 keySz, const byte* in, word32 inSz,
return ret;
}
int wc_AesKeyUnWrap_ex(Aes *aes, const byte* in, word32 inSz, byte* out,
word32 outSz, const byte* iv)
/* Core RFC 3394 unwrapping loop: decrypts (n+1) blocks in `in` to n blocks in
* out and recovered A in aOut. No integrity check; caller verifies A. */
static int AesKeyUnWrapRaw(Aes* aes, const byte* in, word32 inSz, byte* out,
byte* aOut)
{
byte* r;
word32 i, n;
@@ -17297,31 +17352,22 @@ int wc_AesKeyUnWrap_ex(Aes *aes, const byte* in, word32 inSz, byte* out,
byte t[KEYWRAP_BLOCK_SIZE];
byte tmp[WC_AES_BLOCK_SIZE];
const byte* expIv;
const byte defaultIV[] = {
0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6
};
if (aes == NULL || in == NULL || inSz < 3 * KEYWRAP_BLOCK_SIZE ||
out == NULL || outSz < (inSz - KEYWRAP_BLOCK_SIZE))
/* (n+1) blocks in, n >= 2 recovered blocks out, on a 64-bit boundary */
if (aes == NULL || in == NULL || out == NULL || aOut == NULL ||
inSz < 3 * KEYWRAP_BLOCK_SIZE || (inSz % KEYWRAP_BLOCK_SIZE) != 0) {
return BAD_FUNC_ARG;
}
/* input must be multiple of 64-bits */
if (inSz % KEYWRAP_BLOCK_SIZE != 0)
return BAD_FUNC_ARG;
/* user IV optional */
if (iv != NULL)
expIv = iv;
else
expIv = defaultIV;
/* A = C[0], R[i] = C[i] */
/* A = C[0], R[i] = C[i]; XMEMMOVE so in-place unwrap (in == out) is safe */
XMEMCPY(tmp, in, KEYWRAP_BLOCK_SIZE);
XMEMCPY(out, in + KEYWRAP_BLOCK_SIZE, inSz - KEYWRAP_BLOCK_SIZE);
XMEMMOVE(out, in + KEYWRAP_BLOCK_SIZE, inSz - KEYWRAP_BLOCK_SIZE);
XMEMSET(t, 0, sizeof(t));
#ifndef HAVE_AES_ECB
/* Like AesKeyWrapRaw: HAVE_AES_ECB routes each block through wc_AesEcbDecrypt
* (saves registers + ECB cb); otherwise save vector registers here. */
VECTOR_REGISTERS_PUSH;
#endif
/* initialize counter to 6n */
n = (inSz - 1) / KEYWRAP_BLOCK_SIZE;
@@ -17337,7 +17383,11 @@ int wc_AesKeyUnWrap_ex(Aes *aes, const byte* in, word32 inSz, byte* out,
/* load R[i], starting at end of R */
r = out + ((i - 1) * KEYWRAP_BLOCK_SIZE);
XMEMCPY(tmp + KEYWRAP_BLOCK_SIZE, r, KEYWRAP_BLOCK_SIZE);
#ifdef HAVE_AES_ECB
ret = wc_AesEcbDecrypt(aes, tmp, tmp, WC_AES_BLOCK_SIZE);
#else
ret = wc_AesDecryptDirect(aes, tmp, tmp);
#endif
if (ret != 0)
break;
@@ -17348,14 +17398,70 @@ int wc_AesKeyUnWrap_ex(Aes *aes, const byte* in, word32 inSz, byte* out,
break;
}
#ifndef HAVE_AES_ECB
VECTOR_REGISTERS_POP;
#endif
if (ret != 0)
return ret;
/* return recovered A */
XMEMCPY(aOut, tmp, KEYWRAP_BLOCK_SIZE);
return 0;
}
int wc_AesKeyUnWrap_ex(Aes *aes, const byte* in, word32 inSz, byte* out,
word32 outSz, const byte* iv)
{
int ret;
byte a[KEYWRAP_BLOCK_SIZE];
const byte* expIv;
const byte defaultIV[] = {
0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6
};
/* (n+1) >= 3 blocks on a 64-bit boundary, n blocks fit outSz; inSz capped
* at INT_MAX so the returned inSz-8 stays a non-negative int. */
if (aes == NULL || in == NULL || out == NULL ||
inSz < 3 * KEYWRAP_BLOCK_SIZE || (inSz % KEYWRAP_BLOCK_SIZE) != 0 ||
inSz > 0x7FFFFFFFU || outSz < inSz - KEYWRAP_BLOCK_SIZE)
return BAD_FUNC_ARG;
#ifdef WOLF_CRYPTO_CB
#ifndef WOLF_CRYPTO_CB_FIND
if (aes->devId != INVALID_DEVID)
#endif
{
ret = wc_CryptoCb_AesKeyUnWrap(aes, in, inSz, out, outSz, iv, 0);
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
return ret;
}
/* fall through to software when unavailable */
}
#endif
/* user IV optional */
if (iv != NULL) {
expIv = iv;
}
else {
expIv = defaultIV;
}
ret = AesKeyUnWrapRaw(aes, in, inSz, out, a);
if (ret != 0) {
return ret;
}
/* verify IV */
if (ConstantCompare(tmp, expIv, KEYWRAP_BLOCK_SIZE) != 0)
if (ConstantCompare(a, expIv, KEYWRAP_BLOCK_SIZE) != 0) {
/* IV check failed: wipe the recovered plaintext key material left in
* out before returning so it is not leaked to the caller */
ForceZero(out, inSz - KEYWRAP_BLOCK_SIZE);
return BAD_KEYWRAP_IV_E;
}
return (int)(inSz - KEYWRAP_BLOCK_SIZE);
}
@@ -17398,6 +17504,301 @@ int wc_AesKeyUnWrap(const byte* key, word32 keySz, const byte* in, word32 inSz,
return ret;
}
#ifdef WOLFSSL_AES_KEYWRAP_PADDING
/* RFC 5649 AIV high-half constant; the low half carries the 32-bit MLI. */
static const byte kwpAivConst[] = { 0xA6, 0x59, 0x59, 0xA6 };
/* Build the RFC 5649 AIV: 4-byte constant (iv override or default) | 4-byte
* big-endian MLI m. */
static void BuildKwpAiv(byte* aiv, const byte* iv, word32 m)
{
if (iv == NULL) {
XMEMCPY(aiv, kwpAivConst, sizeof(kwpAivConst));
}
else {
XMEMCPY(aiv, iv, sizeof(kwpAivConst));
}
aiv[4] = (byte)(m >> 24);
aiv[5] = (byte)(m >> 16);
aiv[6] = (byte)(m >> 8);
aiv[7] = (byte)(m);
}
int wc_AesKeyWrap_Pad_ex(Aes* aes, const byte* in, word32 inSz, byte* out,
word32 outSz, const byte* iv)
{
int ret;
word32 n;
word32 padSz;
byte aiv[KEYWRAP_BLOCK_SIZE];
/* inSz capped at INT_MAX-(2*8-1) so rounding up to whole blocks plus the
* AIV block can't overflow padSz+8; too-small output -> BAD_FUNC_ARG. */
if (aes == NULL || in == NULL || inSz == 0 || out == NULL ||
inSz > 0x7FFFFFFFU - (2 * KEYWRAP_BLOCK_SIZE - 1))
return BAD_FUNC_ARG;
/* n = ceil(m/8) padded blocks; output is (n+1) blocks */
n = (inSz + KEYWRAP_BLOCK_SIZE - 1) / KEYWRAP_BLOCK_SIZE;
padSz = n * KEYWRAP_BLOCK_SIZE;
if (outSz < padSz + KEYWRAP_BLOCK_SIZE)
return BAD_FUNC_ARG;
#ifdef WOLF_CRYPTO_CB
#ifndef WOLF_CRYPTO_CB_FIND
if (aes->devId != INVALID_DEVID)
#endif
{
ret = wc_CryptoCb_AesKeyWrap(aes, in, inSz, out, outSz, iv, 1);
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
return ret;
}
/* fall through to software when unavailable */
}
#endif
/* AIV = const | MLI(inSz) */
BuildKwpAiv(aiv, iv, inSz);
/* stage plaintext at out+8 (XMEMMOVE for in-place), zeroing the pad octets */
XMEMMOVE(out + KEYWRAP_BLOCK_SIZE, in, inSz);
if (padSz > inSz) {
XMEMSET(out + KEYWRAP_BLOCK_SIZE + inSz, 0, padSz - inSz);
}
if (n == 1) {
/* single block: C[0]|C[1] = ENC(K, AIV | P[1]) */
byte tmp[WC_AES_BLOCK_SIZE];
XMEMCPY(tmp, aiv, KEYWRAP_BLOCK_SIZE);
XMEMCPY(tmp + KEYWRAP_BLOCK_SIZE, out + KEYWRAP_BLOCK_SIZE,
KEYWRAP_BLOCK_SIZE);
#ifdef HAVE_AES_ECB
/* Route through wc_AesEcbEncrypt so an ECB crypto callback can service
* the block; it saves its own registers. */
ret = wc_AesEcbEncrypt(aes, out, tmp, WC_AES_BLOCK_SIZE);
#else
VECTOR_REGISTERS_PUSH;
ret = wc_AesEncryptDirect(aes, out, tmp);
VECTOR_REGISTERS_POP;
#endif
/* tmp held AIV | plaintext key material */
ForceZero(tmp, sizeof(tmp));
}
else {
/* run the RFC 3394 loop with the AIV as the initial value */
ret = AesKeyWrapRaw(aes, padSz, out, aiv);
}
if (ret != 0) {
/* wipe the plaintext staged at out+8 (and any partial cipher state)
* so it is not leaked to the caller on failure */
ForceZero(out + KEYWRAP_BLOCK_SIZE, padSz);
return ret;
}
return (int)(padSz + KEYWRAP_BLOCK_SIZE);
}
int wc_AesKeyWrap_Pad(const byte* key, word32 keySz, const byte* in,
word32 inSz, byte* out, word32 outSz, const byte* iv)
{
WC_DECLARE_VAR(aes, Aes, 1, NULL);
int ret;
if (key == NULL) {
return BAD_FUNC_ARG;
}
WC_ALLOC_VAR_EX(aes, Aes, 1, NULL, DYNAMIC_TYPE_AES, return MEMORY_E);
ret = wc_AesInit(aes, NULL, INVALID_DEVID);
if (ret != 0) {
goto out;
}
ret = wc_AesSetKey(aes, key, keySz, NULL, AES_ENCRYPTION);
if (ret != 0) {
wc_AesFree(aes);
goto out;
}
ret = wc_AesKeyWrap_Pad_ex(aes, in, inSz, out, outSz, iv);
wc_AesFree(aes);
out:
WC_FREE_VAR_EX(aes, NULL, DYNAMIC_TYPE_AES);
return ret;
}
int wc_AesKeyUnWrap_Pad_ex(Aes* aes, const byte* in, word32 inSz, byte* out,
word32 outSz, const byte* iv)
{
int ret;
word32 n;
word32 mli;
byte a[KEYWRAP_BLOCK_SIZE];
byte expConst[sizeof(kwpAivConst)];
/* (n+1) >= 2 blocks on a 64-bit boundary; inSz capped at INT_MAX so the
* returned MLI stays a non-negative int; too-small output -> BAD_FUNC_ARG. */
if (aes == NULL || in == NULL || out == NULL ||
inSz < 2 * KEYWRAP_BLOCK_SIZE || (inSz % KEYWRAP_BLOCK_SIZE) != 0 ||
inSz > 0x7FFFFFFFU || outSz < inSz - KEYWRAP_BLOCK_SIZE)
return BAD_FUNC_ARG;
#ifdef WOLF_CRYPTO_CB
#ifndef WOLF_CRYPTO_CB_FIND
if (aes->devId != INVALID_DEVID)
#endif
{
ret = wc_CryptoCb_AesKeyUnWrap(aes, in, inSz, out, outSz, iv, 1);
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
return ret;
}
/* fall through to software when unavailable */
}
#endif
/* number of padded 64-bit plaintext blocks */
n = (inSz / KEYWRAP_BLOCK_SIZE) - 1;
if (n == 1) {
/* single block: AIV|P[1] = DEC(K, C[0]|C[1]) */
byte tmp[WC_AES_BLOCK_SIZE];
#ifdef HAVE_AES_ECB
/* Route through wc_AesEcbDecrypt so an ECB crypto callback can service
* the block; it saves its own registers. */
ret = wc_AesEcbDecrypt(aes, tmp, in, WC_AES_BLOCK_SIZE);
#else
VECTOR_REGISTERS_PUSH;
ret = wc_AesDecryptDirect(aes, tmp, in);
VECTOR_REGISTERS_POP;
#endif
if (ret == 0) {
XMEMCPY(a, tmp, KEYWRAP_BLOCK_SIZE);
XMEMCPY(out, tmp + KEYWRAP_BLOCK_SIZE, KEYWRAP_BLOCK_SIZE);
}
/* tmp held AIV | plaintext key material */
ForceZero(tmp, sizeof(tmp));
}
else {
/* recover A and padded plaintext via the RFC 3394 loop (no check) */
ret = AesKeyUnWrapRaw(aes, in, inSz, out, a);
}
if (ret != 0) {
return ret;
}
/* expected high-half constant (iv override or default) */
if (iv == NULL) {
XMEMCPY(expConst, kwpAivConst, sizeof(kwpAivConst));
}
else {
XMEMCPY(expConst, iv, sizeof(kwpAivConst));
}
/* MLI = LSB(32,A) in network order */
mli = ((word32)a[4] << 24) | ((word32)a[5] << 16) |
((word32)a[6] << 8) | (word32)a[7];
/* Validate the three RFC 5649 checks in constant time: fold failures into
* one mask and branch once, so timing does not reveal which check failed. */
{
word32 dataSz = inSz - KEYWRAP_BLOCK_SIZE; /* 8*n plaintext octets */
word32 lastBlk = dataSz - KEYWRAP_BLOCK_SIZE; /* offset 8*(n-1) */
word32 fail;
word32 j;
/* check 1: MSB(32,A) == constant */
fail = (word32)ctMaskNotEq(ConstantCompare(a, expConst,
(int)sizeof(kwpAivConst)), 0);
#ifdef WORD64_AVAILABLE
/* check 2: 8*(n-1) < MLI <= 8*n */
fail |= ~(ctMaskWord32GTE(mli, lastBlk + 1) /* MLI >= 8*(n-1)+1 */
& ctMaskWord32GTE(dataSz, mli)); /* 8*n >= MLI */
/* check 3: octets in [MLI, 8*n) are zero. A valid MLI is in the final
* block, so scan it at fixed offsets, requiring zero where off >= MLI. */
for (j = 0; j < KEYWRAP_BLOCK_SIZE; j++) {
word32 off = lastBlk + j;
fail |= ctMaskWord32GTE(off, mli) /* off >= MLI */
& (word32)ctMaskNotEq((int)out[off], 0);
}
#else
/* No word64: compare in int range. MLI with its high bit set (>= 2^31
* > 8*n) is forced to fail so the int compares see valid values. */
{
byte lowMask = (byte)~(byte)(0u - ((mli >> 31) & 1u));
int mliInt = (int)(mli & 0x7FFFFFFFu);
/* check 2: 8*(n-1) < MLI <= 8*n */
fail |= (word32)(byte)~(byte)(ctMaskGT(mliInt, (int)lastBlk)
& ctMaskLTE(mliInt, (int)dataSz)
& lowMask);
/* check 3: octets in [MLI, 8*n) are zero (see note above). */
for (j = 0; j < KEYWRAP_BLOCK_SIZE; j++) {
int off = (int)(lastBlk + j);
byte isPad = (byte)(ctMaskGTE(off, mliInt) & lowMask);
fail |= (word32)(byte)(isPad &
ctMaskNotEq((int)out[lastBlk + j], 0));
}
}
#endif
if (fail != 0) {
goto badIv;
}
}
return (int)mli;
badIv:
/* integrity check failed: wipe the recovered plaintext in out so it is
* not leaked to the caller */
ForceZero(out, inSz - KEYWRAP_BLOCK_SIZE);
return BAD_KEYWRAP_IV_E;
}
int wc_AesKeyUnWrap_Pad(const byte* key, word32 keySz, const byte* in,
word32 inSz, byte* out, word32 outSz, const byte* iv)
{
WC_DECLARE_VAR(aes, Aes, 1, NULL);
int ret;
if (key == NULL) {
return BAD_FUNC_ARG;
}
WC_ALLOC_VAR_EX(aes, Aes, 1, NULL, DYNAMIC_TYPE_AES, return MEMORY_E);
ret = wc_AesInit(aes, NULL, INVALID_DEVID);
if (ret != 0) {
goto out;
}
ret = wc_AesSetKey(aes, key, keySz, NULL, AES_DECRYPTION);
if (ret != 0) {
wc_AesFree(aes);
goto out;
}
ret = wc_AesKeyUnWrap_Pad_ex(aes, in, inSz, out, outSz, iv);
wc_AesFree(aes);
out:
WC_FREE_VAR_EX(aes, NULL, DYNAMIC_TYPE_AES);
return ret;
}
#endif /* WOLFSSL_AES_KEYWRAP_PADDING */
#endif /* HAVE_AES_KEYWRAP */
#ifdef WOLFSSL_AES_XTS
+84
View File
@@ -176,6 +176,7 @@ static const char* GetCipherTypeStr(int cipher)
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_AES_KEYWRAP: return "AES KeyWrap";
case WC_CIPHER_DES3: return "DES3";
case WC_CIPHER_DES: return "DES";
case WC_CIPHER_CHACHA: return "ChaCha20";
@@ -2270,6 +2271,89 @@ int wc_CryptoCb_AesEcbDecrypt(Aes* aes, byte* out,
}
#endif /* HAVE_AES_ECB || WOLFSSL_AES_DIRECT || WOLF_CRYPTO_CB_ONLY_AES */
#ifdef HAVE_AES_KEYWRAP
/* On success returns the number of output bytes produced (the callback reports
* it via aeskeywrap.outResSz), otherwise a negative error or
* CRYPTOCB_UNAVAILABLE. pad selects RFC 5649 (1) vs RFC 3394 (0). */
int wc_CryptoCb_AesKeyWrap(Aes* aes, const byte* in, word32 inSz, byte* out,
word32 outSz, const byte* iv, int pad)
{
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_KEYWRAP;
cryptoInfo.cipher.enc = 1;
cryptoInfo.cipher.aeskeywrap.aes = aes;
cryptoInfo.cipher.aeskeywrap.in = in;
cryptoInfo.cipher.aeskeywrap.inSz = inSz;
cryptoInfo.cipher.aeskeywrap.out = out;
cryptoInfo.cipher.aeskeywrap.outSz = outSz;
cryptoInfo.cipher.aeskeywrap.iv = iv;
cryptoInfo.cipher.aeskeywrap.pad = pad;
ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx);
if (ret == 0) {
/* device reports the wrapped length */
return (int)cryptoInfo.cipher.aeskeywrap.outResSz;
}
}
return wc_CryptoCb_TranslateErrorCode(ret);
}
int wc_CryptoCb_AesKeyUnWrap(Aes* aes, const byte* in, word32 inSz, byte* out,
word32 outSz, const byte* iv, int pad)
{
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_KEYWRAP;
cryptoInfo.cipher.enc = 0;
cryptoInfo.cipher.aeskeywrap.aes = aes;
cryptoInfo.cipher.aeskeywrap.in = in;
cryptoInfo.cipher.aeskeywrap.inSz = inSz;
cryptoInfo.cipher.aeskeywrap.out = out;
cryptoInfo.cipher.aeskeywrap.outSz = outSz;
cryptoInfo.cipher.aeskeywrap.iv = iv;
cryptoInfo.cipher.aeskeywrap.pad = pad;
ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx);
if (ret == 0) {
/* device reports the recovered length */
return (int)cryptoInfo.cipher.aeskeywrap.outResSz;
}
}
return wc_CryptoCb_TranslateErrorCode(ret);
}
#endif /* HAVE_AES_KEYWRAP */
#ifdef WOLF_CRYPTO_CB_AES_SETKEY
int wc_CryptoCb_AesSetKey(Aes* aes, const byte* key, word32 keySz)
{
+657
View File
@@ -902,6 +902,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aesgcm_siv_test(void);
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t gmac_test(void);
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aesccm_test(void);
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aeskeywrap_test(void);
#ifdef WOLFSSL_AES_KEYWRAP_PADDING
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aeskeywrap_pad_test(void);
#endif
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t camellia_test(void);
#ifdef WOLFSSL_SM4
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t sm4_test(void);
@@ -2966,6 +2969,12 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\
TEST_FAIL("AES Key Wrap test failed!\n", ret);
else
TEST_PASS("AES Key Wrap test passed!\n");
#ifdef WOLFSSL_AES_KEYWRAP_PADDING
if ( (ret = aeskeywrap_pad_test()) != 0)
TEST_FAIL("AES Key Wrap Pad test failed!\n", ret);
else
TEST_PASS("AES Key Wrap Pad test passed!\n");
#endif
#endif
#if defined(WOLFSSL_AES_SIV) && defined(WOLFSSL_AES_128)
if ( (ret = aes_siv_test()) != 0)
@@ -23401,8 +23410,587 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aeskeywrap_test(void)
return WC_TEST_RET_ENC_EC(plainSz);
}
#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
/* Drive wc_AesKeyWrap_ex/wc_AesKeyUnWrap_ex directly with a caller Aes; the
* KAT loop above already covers every vector via the key-based wrappers. */
{
Aes* aes = (Aes*)XMALLOC(sizeof(Aes), HEAP_HINT, DYNAMIC_TYPE_AES);
if (aes == NULL)
return WC_TEST_RET_ENC_NC;
XMEMSET(output, 0, sizeof(output));
XMEMSET(plain, 0, sizeof(plain));
if (wc_AesInit(aes, HEAP_HINT, devId) != 0) {
XFREE(aes, HEAP_HINT, DYNAMIC_TYPE_AES);
return WC_TEST_RET_ENC_NC;
}
if (wc_AesSetKey(aes, test_wrap[0].kek, test_wrap[0].kekLen, NULL,
AES_ENCRYPTION) != 0) {
wc_AesFree(aes);
XFREE(aes, HEAP_HINT, DYNAMIC_TYPE_AES);
return WC_TEST_RET_ENC_NC;
}
wrapSz = wc_AesKeyWrap_ex(aes, test_wrap[0].data, test_wrap[0].dataLen,
output, sizeof(output), NULL);
wc_AesFree(aes);
if ( (wrapSz < 0) || (wrapSz != (int)test_wrap[0].verifyLen) ||
XMEMCMP(output, test_wrap[0].verify, test_wrap[0].verifyLen) != 0) {
XFREE(aes, HEAP_HINT, DYNAMIC_TYPE_AES);
return WC_TEST_RET_ENC_NC;
}
if (wc_AesInit(aes, HEAP_HINT, devId) != 0) {
XFREE(aes, HEAP_HINT, DYNAMIC_TYPE_AES);
return WC_TEST_RET_ENC_NC;
}
if (wc_AesSetKey(aes, test_wrap[0].kek, test_wrap[0].kekLen, NULL,
AES_DECRYPTION) != 0) {
wc_AesFree(aes);
XFREE(aes, HEAP_HINT, DYNAMIC_TYPE_AES);
return WC_TEST_RET_ENC_NC;
}
plainSz = wc_AesKeyUnWrap_ex(aes, output, (word32)wrapSz,
plain, sizeof(plain), NULL);
wc_AesFree(aes);
XFREE(aes, HEAP_HINT, DYNAMIC_TYPE_AES);
if ( (plainSz < 0) || (plainSz != (int)test_wrap[0].dataLen) ||
XMEMCMP(plain, test_wrap[0].data, test_wrap[0].dataLen) != 0)
return WC_TEST_RET_ENC_NC;
}
/* In-place round-trip (in == out): wrap then unwrap a single buffer.
* Exercises the XMEMMOVE staging in wc_AesKeyWrap_ex / AesKeyUnWrapRaw. */
{
XMEMSET(output, 0, sizeof(output));
XMEMCPY(output, test_wrap[0].data, test_wrap[0].dataLen);
wrapSz = wc_AesKeyWrap(test_wrap[0].kek, test_wrap[0].kekLen,
output, test_wrap[0].dataLen,
output, sizeof(output), NULL);
if ( (wrapSz < 0) || (wrapSz != (int)test_wrap[0].verifyLen) )
return WC_TEST_RET_ENC_NC;
if (XMEMCMP(output, test_wrap[0].verify, test_wrap[0].verifyLen) != 0)
return WC_TEST_RET_ENC_NC;
plainSz = wc_AesKeyUnWrap(test_wrap[0].kek, test_wrap[0].kekLen,
output, (word32)wrapSz,
output, sizeof(output), NULL);
if ( (plainSz < 0) || (plainSz != (int)test_wrap[0].dataLen) )
return WC_TEST_RET_ENC_NC;
if (XMEMCMP(output, test_wrap[0].data, test_wrap[0].dataLen) != 0)
return WC_TEST_RET_ENC_NC;
}
#endif /* !HAVE_FIPS && !HAVE_SELFTEST */
return 0;
}
#if defined(WOLFSSL_AES_KEYWRAP_PADDING)
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aeskeywrap_pad_test(void)
{
int wrapSz, plainSz, kwpSz, i;
byte output[MAX_KEYWRAP_TEST_OUTLEN];
byte plain [MAX_KEYWRAP_TEST_PLAINLEN];
/* RFC 5649 padded key wrap vectors: RFC 5649 s6 for 192-bit, OpenSSL
* aes-wrap-pad for 128/256 (cross-checked). 20-octet = loop, 7 = ECB. */
/* shared plaintexts */
/* 20 octets -> 32-byte wrap (RFC 3394 loop path) */
WOLFSSL_SMALL_STACK_STATIC const byte kwpData1[] = {
0xc3, 0x7b, 0x7e, 0x64, 0x92, 0x58, 0x43, 0x40,
0xbe, 0xd1, 0x22, 0x07, 0x80, 0x89, 0x41, 0x15,
0x50, 0x68, 0xf7, 0x38
};
/* 7 octets -> 16-byte wrap (single-block ECB path) */
WOLFSSL_SMALL_STACK_STATIC const byte kwpData2[] = {
0x46, 0x6f, 0x72, 0x50, 0x61, 0x73, 0x69
};
#ifdef WOLFSSL_AES_128
WOLFSSL_SMALL_STACK_STATIC const byte kwpKek128[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
WOLFSSL_SMALL_STACK_STATIC const byte kwpVerify128_1[] = {
0xe1, 0xf7, 0x17, 0x6e, 0xcb, 0xd7, 0x5d, 0x42,
0xe8, 0x2b, 0x24, 0xf9, 0x89, 0xa2, 0x81, 0x6c,
0x20, 0x9c, 0x6e, 0xf2, 0xd1, 0xaa, 0x94, 0xd2,
0xa3, 0xe6, 0x02, 0x84, 0x90, 0x0d, 0x03, 0xa2
};
WOLFSSL_SMALL_STACK_STATIC const byte kwpVerify128_2[] = {
0xbe, 0x80, 0x53, 0x5e, 0x12, 0xe9, 0x39, 0x4c,
0x8f, 0x8d, 0xf2, 0x6b, 0xd9, 0x52, 0x8a, 0x35
};
#endif
#ifdef WOLFSSL_AES_192
WOLFSSL_SMALL_STACK_STATIC const byte kwpKek192[] = {
0x58, 0x40, 0xdf, 0x6e, 0x29, 0xb0, 0x2a, 0xf1,
0xab, 0x49, 0x3b, 0x70, 0x5b, 0xf1, 0x6e, 0xa1,
0xae, 0x83, 0x38, 0xf4, 0xdc, 0xc1, 0x76, 0xa8
};
WOLFSSL_SMALL_STACK_STATIC const byte kwpVerify192_1[] = {
0x13, 0x8b, 0xde, 0xaa, 0x9b, 0x8f, 0xa7, 0xfc,
0x61, 0xf9, 0x77, 0x42, 0xe7, 0x22, 0x48, 0xee,
0x5a, 0xe6, 0xae, 0x53, 0x60, 0xd1, 0xae, 0x6a,
0x5f, 0x54, 0xf3, 0x73, 0xfa, 0x54, 0x3b, 0x6a
};
WOLFSSL_SMALL_STACK_STATIC const byte kwpVerify192_2[] = {
0xaf, 0xbe, 0xb0, 0xf0, 0x7d, 0xfb, 0xf5, 0x41,
0x92, 0x00, 0xf2, 0xcc, 0xb5, 0x0b, 0xb2, 0x4f
};
#endif
#ifdef WOLFSSL_AES_256
WOLFSSL_SMALL_STACK_STATIC const byte kwpKek256[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
};
WOLFSSL_SMALL_STACK_STATIC const byte kwpVerify256_1[] = {
0x29, 0xb7, 0xfa, 0x19, 0x1c, 0x21, 0x65, 0x68,
0x43, 0x74, 0xee, 0xe9, 0xf7, 0x45, 0x95, 0xe2,
0xa4, 0x2b, 0xac, 0xe7, 0x5c, 0x42, 0x5b, 0x30,
0x53, 0xef, 0xa2, 0x6f, 0xfe, 0x1b, 0xb3, 0x2f
};
WOLFSSL_SMALL_STACK_STATIC const byte kwpVerify256_2[] = {
0x44, 0x3b, 0x17, 0x83, 0x7b, 0xb3, 0x93, 0x48,
0x61, 0x0d, 0x19, 0x20, 0x2d, 0xf8, 0xa1, 0xf9
};
#endif
const keywrapVector test_kwp[] = {
#ifdef WOLFSSL_AES_128
{kwpKek128, kwpData1, kwpVerify128_1, sizeof(kwpKek128),
sizeof(kwpData1), sizeof(kwpVerify128_1)},
{kwpKek128, kwpData2, kwpVerify128_2, sizeof(kwpKek128),
sizeof(kwpData2), sizeof(kwpVerify128_2)},
#endif
#ifdef WOLFSSL_AES_192
{kwpKek192, kwpData1, kwpVerify192_1, sizeof(kwpKek192),
sizeof(kwpData1), sizeof(kwpVerify192_1)},
{kwpKek192, kwpData2, kwpVerify192_2, sizeof(kwpKek192),
sizeof(kwpData2), sizeof(kwpVerify192_2)},
#endif
#ifdef WOLFSSL_AES_256
{kwpKek256, kwpData1, kwpVerify256_1, sizeof(kwpKek256),
sizeof(kwpData1), sizeof(kwpVerify256_1)},
{kwpKek256, kwpData2, kwpVerify256_2, sizeof(kwpKek256),
sizeof(kwpData2), sizeof(kwpVerify256_2)},
#endif
};
WOLFSSL_ENTER("aeskeywrap_pad_test");
kwpSz = (int)(sizeof(test_kwp) / sizeof(keywrapVector));
for (i = 0; i < kwpSz; i++) {
XMEMSET(output, 0, sizeof(output));
XMEMSET(plain, 0, sizeof(plain));
wrapSz = wc_AesKeyWrap_Pad(test_kwp[i].kek, test_kwp[i].kekLen,
test_kwp[i].data, test_kwp[i].dataLen,
output, sizeof(output), NULL);
if ( (wrapSz < 0) || (wrapSz != (int)test_kwp[i].verifyLen) ) {
return WC_TEST_RET_ENC_I(i);
}
if (XMEMCMP(output, test_kwp[i].verify, test_kwp[i].verifyLen) != 0) {
return WC_TEST_RET_ENC_I(i);
}
plainSz = wc_AesKeyUnWrap_Pad(test_kwp[i].kek, test_kwp[i].kekLen,
output, (word32)wrapSz,
plain, sizeof(plain), NULL);
if ( (plainSz < 0) || (plainSz != (int)test_kwp[i].dataLen) ) {
return WC_TEST_RET_ENC_I(i);
}
if (XMEMCMP(plain, test_kwp[i].data, test_kwp[i].dataLen) != 0) {
return WC_TEST_RET_ENC_I(i);
}
}
/* Everything below indexes test_kwp[0]; when no AES key size is enabled
* test_kwp[] is empty (kwpSz == 0), so skip it to stay in-bounds. */
if (kwpSz == 0)
return 0;
/* Negative test: corrupted wrapped data must be rejected with
* BAD_KEYWRAP_IV_E. */
wrapSz = wc_AesKeyWrap_Pad(test_kwp[0].kek, test_kwp[0].kekLen,
test_kwp[0].data, test_kwp[0].dataLen,
output, sizeof(output), NULL);
if (wrapSz < 0) {
return WC_TEST_RET_ENC_EC(wrapSz);
}
output[0] ^= 0x01;
plainSz = wc_AesKeyUnWrap_Pad(test_kwp[0].kek, test_kwp[0].kekLen,
output, (word32)wrapSz,
plain, sizeof(plain), NULL);
if (plainSz != WC_NO_ERR_TRACE(BAD_KEYWRAP_IV_E)) {
return WC_TEST_RET_ENC_EC(plainSz);
}
/* Negative: invalid arguments must be rejected with BAD_FUNC_ARG. */
if (wc_AesKeyWrap_Pad(NULL, test_kwp[0].kekLen, test_kwp[0].data,
test_kwp[0].dataLen, output, sizeof(output), NULL)
!= WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_NC;
if (wc_AesKeyWrap_Pad(test_kwp[0].kek, test_kwp[0].kekLen, NULL,
test_kwp[0].dataLen, output, sizeof(output), NULL)
!= WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_NC;
if (wc_AesKeyWrap_Pad(test_kwp[0].kek, test_kwp[0].kekLen, test_kwp[0].data,
0, output, sizeof(output), NULL)
!= WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_NC;
if (wc_AesKeyWrap_Pad(test_kwp[0].kek, test_kwp[0].kekLen, test_kwp[0].data,
test_kwp[0].dataLen, NULL, sizeof(output), NULL)
!= WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_NC;
/* output buffer too small: 7 octets need 16 wrapped bytes, give 8 */
if (wc_AesKeyWrap_Pad(test_kwp[0].kek, test_kwp[0].kekLen, kwpData2,
(word32)sizeof(kwpData2), output, 8, NULL)
!= WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_NC;
if (wc_AesKeyUnWrap_Pad(NULL, test_kwp[0].kekLen, output, 16, plain,
sizeof(plain), NULL) != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_NC;
if (wc_AesKeyUnWrap_Pad(test_kwp[0].kek, test_kwp[0].kekLen, NULL, 16, plain,
sizeof(plain), NULL) != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_NC;
/* ciphertext length must be a multiple of 8 and at least 16 octets */
if (wc_AesKeyUnWrap_Pad(test_kwp[0].kek, test_kwp[0].kekLen, output, 8, plain,
sizeof(plain), NULL) != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_NC;
if (wc_AesKeyUnWrap_Pad(test_kwp[0].kek, test_kwp[0].kekLen, output, 17,
plain, sizeof(plain), NULL) != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_NC;
/* unwrap output buffer smaller than the recovered padded plaintext */
if (wc_AesKeyUnWrap_Pad(test_kwp[0].kek, test_kwp[0].kekLen, output, 16,
plain, 4, NULL) != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_NC;
/* an inSz that would overflow ceil(inSz/8)+1 blocks is rejected up front */
if (wc_AesKeyWrap_Pad(test_kwp[0].kek, test_kwp[0].kekLen, test_kwp[0].data,
0xFFFFFFF1U, output, sizeof(output), NULL)
!= WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_NC;
/* Negative: an invalid KEK size drives the SetKey-failure path in the
* wrappers (20 octets is not a valid AES key length). */
{
WOLFSSL_SMALL_STACK_STATIC const byte badKek[20] = {
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c
};
if (wc_AesKeyWrap_Pad(badKek, (word32)sizeof(badKek), kwpData2,
(word32)sizeof(kwpData2), output, sizeof(output), NULL)
!= WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_NC;
if (wc_AesKeyUnWrap_Pad(badKek, (word32)sizeof(badKek), output, 16,
plain, sizeof(plain), NULL) != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
return WC_TEST_RET_ENC_NC;
}
/* IV override: a custom 4-byte AIV round-trips, and the same blob is
* rejected under the default AIV (check 1, AIV-constant mismatch). */
{
WOLFSSL_SMALL_STACK_STATIC const byte altIv[4] = {
0x12, 0x34, 0x56, 0x78
};
XMEMSET(output, 0, sizeof(output));
XMEMSET(plain, 0, sizeof(plain));
wrapSz = wc_AesKeyWrap_Pad(test_kwp[0].kek, test_kwp[0].kekLen, kwpData2,
(word32)sizeof(kwpData2), output, sizeof(output), altIv);
if (wrapSz < 0)
return WC_TEST_RET_ENC_EC(wrapSz);
plainSz = wc_AesKeyUnWrap_Pad(test_kwp[0].kek, test_kwp[0].kekLen,
output, (word32)wrapSz, plain, sizeof(plain), altIv);
if ((plainSz != (int)sizeof(kwpData2)) ||
(XMEMCMP(plain, kwpData2, sizeof(kwpData2)) != 0))
return WC_TEST_RET_ENC_NC;
if (wc_AesKeyUnWrap_Pad(test_kwp[0].kek, test_kwp[0].kekLen, output,
(word32)wrapSz, plain, sizeof(plain), NULL)
!= WC_NO_ERR_TRACE(BAD_KEYWRAP_IV_E))
return WC_TEST_RET_ENC_NC;
}
#if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \
defined(WOLFSSL_AES_256)
/* Boundary-size KATs (pyca/cryptography, reproduces RFC 5649 s6) plus an
* exhaustive 1..31 round-trip across every enabled key size. */
{
#ifdef WOLFSSL_AES_128
WOLFSSL_SMALL_STACK_STATIC const byte kb128_1[] = {
0xdc, 0x0c, 0xed, 0x32, 0x50, 0xa4, 0x92, 0x77, 0x59, 0xb4, 0xe9, 0x28,
0x73, 0x2e, 0x16, 0x8a };
WOLFSSL_SMALL_STACK_STATIC const byte kb128_8[] = {
0x23, 0xe1, 0xcd, 0x73, 0x92, 0xf0, 0xcc, 0x69, 0xdc, 0x20, 0xdf, 0x56,
0x48, 0x9f, 0xfd, 0xd7 };
WOLFSSL_SMALL_STACK_STATIC const byte kb128_9[] = {
0xe6, 0xe7, 0x6a, 0xfc, 0xf1, 0xf7, 0x1f, 0x43, 0x63, 0x4b, 0x96, 0x91,
0x9c, 0x1e, 0x36, 0xa9, 0x5b, 0xf7, 0xb0, 0x26, 0x0f, 0x51, 0x9b, 0x4b };
WOLFSSL_SMALL_STACK_STATIC const byte kb128_16[] = {
0xa7, 0x41, 0x46, 0x28, 0x3b, 0x00, 0x85, 0x06, 0x23, 0xd3, 0x02, 0xf4,
0x57, 0xb1, 0x8c, 0x96, 0xac, 0xe5, 0xb5, 0xd3, 0x64, 0x7c, 0xc2, 0xf1 };
WOLFSSL_SMALL_STACK_STATIC const byte kb128_17[] = {
0x8d, 0x69, 0xe5, 0xc5, 0x01, 0x98, 0x70, 0xd3, 0x50, 0x37, 0x3a, 0x00,
0xa8, 0xe3, 0xa5, 0x32, 0xdf, 0xce, 0x76, 0x8a, 0x6b, 0x79, 0xef, 0x2c,
0x34, 0xcf, 0xed, 0x5c, 0xb4, 0x09, 0xff, 0xf4 };
WOLFSSL_SMALL_STACK_STATIC const byte kb128_31[] = {
0x50, 0x3e, 0xc4, 0xff, 0x2e, 0xd3, 0x01, 0x14, 0xfa, 0x5a, 0x02, 0x47,
0x9f, 0x20, 0x4c, 0xb1, 0xd8, 0xcb, 0xa2, 0xa3, 0xa3, 0x7d, 0x7b, 0xa5,
0x60, 0x77, 0x01, 0x46, 0xd6, 0x03, 0x93, 0xe0, 0xf0, 0x01, 0xf7, 0x88,
0xb0, 0x4b, 0xc6, 0xb2 };
#endif
#ifdef WOLFSSL_AES_192
WOLFSSL_SMALL_STACK_STATIC const byte kb192_1[] = {
0x95, 0xf7, 0xba, 0x0a, 0x72, 0x6e, 0xed, 0x9a, 0x90, 0xa9, 0x90, 0x00,
0x94, 0xc5, 0xd9, 0x2d };
WOLFSSL_SMALL_STACK_STATIC const byte kb192_8[] = {
0xaa, 0x6f, 0x7d, 0x3b, 0xab, 0x34, 0x91, 0xcc, 0xd9, 0x52, 0xc9, 0x86,
0x64, 0x42, 0x8c, 0x40 };
WOLFSSL_SMALL_STACK_STATIC const byte kb192_9[] = {
0x52, 0xa0, 0xf3, 0xda, 0x5a, 0x48, 0xaf, 0xe9, 0xac, 0x1e, 0x8f, 0x96,
0x84, 0x25, 0x93, 0x8e, 0xd5, 0x35, 0xaa, 0xe9, 0xbc, 0xe1, 0x0b, 0x52 };
WOLFSSL_SMALL_STACK_STATIC const byte kb192_16[] = {
0xe8, 0xba, 0xab, 0xb4, 0xa1, 0xf3, 0x57, 0x6e, 0x72, 0xe4, 0x71, 0xca,
0x51, 0x2b, 0x5b, 0x64, 0xfb, 0x25, 0x25, 0x97, 0xfc, 0x80, 0x75, 0xe3 };
WOLFSSL_SMALL_STACK_STATIC const byte kb192_17[] = {
0xaf, 0x1e, 0xc0, 0xdf, 0x04, 0xef, 0xde, 0xb6, 0x0d, 0xa4, 0xdf, 0xf5,
0x89, 0x84, 0x14, 0x91, 0x11, 0xdf, 0xda, 0x2d, 0xef, 0xc1, 0x30, 0x6e,
0x54, 0x46, 0x2e, 0xc3, 0xac, 0x57, 0xf7, 0x8a };
WOLFSSL_SMALL_STACK_STATIC const byte kb192_31[] = {
0x1d, 0x59, 0x4c, 0x1a, 0x06, 0x03, 0x33, 0x60, 0x03, 0x12, 0x1e, 0x69,
0x81, 0xd8, 0xbe, 0xc6, 0x0a, 0xef, 0x71, 0x7f, 0x62, 0x1e, 0x95, 0xb1,
0xfb, 0x29, 0x96, 0x61, 0x39, 0x78, 0xbb, 0x5f, 0x52, 0xee, 0xc6, 0xda,
0xed, 0xd8, 0x48, 0x97 };
#endif
#ifdef WOLFSSL_AES_256
WOLFSSL_SMALL_STACK_STATIC const byte kb256_1[] = {
0xcc, 0xc4, 0x9f, 0xbf, 0x20, 0xf2, 0xac, 0xe7, 0xeb, 0x31, 0xa8, 0xdd,
0xe2, 0x26, 0x50, 0x6a };
WOLFSSL_SMALL_STACK_STATIC const byte kb256_8[] = {
0xea, 0x91, 0xdd, 0x60, 0xe5, 0x9b, 0xd6, 0x8b, 0xad, 0x0d, 0x6e, 0x25,
0x4b, 0x5e, 0x1c, 0x39 };
WOLFSSL_SMALL_STACK_STATIC const byte kb256_9[] = {
0xc9, 0x72, 0x2a, 0x95, 0x51, 0xdf, 0xa2, 0x83, 0x2a, 0xa1, 0xca, 0xe4,
0x87, 0x82, 0x1e, 0x06, 0x99, 0x12, 0x94, 0xae, 0xbc, 0xe0, 0x98, 0x48 };
WOLFSSL_SMALL_STACK_STATIC const byte kb256_16[] = {
0xb3, 0x33, 0x58, 0x13, 0x95, 0xce, 0xdf, 0x83, 0x56, 0xdc, 0x35, 0x6c,
0x1c, 0xc7, 0x9e, 0x9a, 0x88, 0x5c, 0xb4, 0x98, 0x8e, 0xd6, 0x29, 0xb8 };
WOLFSSL_SMALL_STACK_STATIC const byte kb256_17[] = {
0x18, 0x58, 0x36, 0x63, 0x5d, 0xea, 0xaf, 0x4d, 0xa8, 0x27, 0x0c, 0x04,
0x89, 0x09, 0xae, 0xbf, 0xe9, 0x21, 0x11, 0x66, 0xca, 0x2f, 0xdb, 0x34,
0xa0, 0x93, 0x69, 0xfe, 0x9b, 0xb8, 0x6b, 0x04 };
WOLFSSL_SMALL_STACK_STATIC const byte kb256_31[] = {
0x16, 0x44, 0xf1, 0x8b, 0x57, 0xc7, 0xb3, 0xf1, 0x85, 0x51, 0xbe, 0x73,
0xff, 0xd0, 0x9c, 0xa7, 0x42, 0xf7, 0xf1, 0x56, 0x26, 0x1d, 0x58, 0x95,
0xaa, 0xc0, 0x97, 0xc4, 0xb6, 0x4e, 0x02, 0x80, 0xfc, 0x80, 0xbd, 0xac,
0x45, 0x2c, 0x90, 0x10 };
#endif
WOLFSSL_SMALL_STACK_STATIC const word32 bsz[] = { 1, 8, 9, 16, 17, 31 };
WOLFSSL_SMALL_STACK_STATIC const word32 bes[] = { 16, 16, 24, 24, 32, 40 };
struct { const byte* kek; word32 kekSz; const byte* exp[6]; } ek[] = {
#ifdef WOLFSSL_AES_128
{ kwpKek128, (word32)sizeof(kwpKek128),
{ kb128_1, kb128_8, kb128_9, kb128_16, kb128_17, kb128_31 } },
#endif
#ifdef WOLFSSL_AES_192
{ kwpKek192, (word32)sizeof(kwpKek192),
{ kb192_1, kb192_8, kb192_9, kb192_16, kb192_17, kb192_31 } },
#endif
#ifdef WOLFSSL_AES_256
{ kwpKek256, (word32)sizeof(kwpKek256),
{ kb256_1, kb256_8, kb256_9, kb256_16, kb256_17, kb256_31 } },
#endif
};
byte rtin[32];
int ekSz = (int)(sizeof(ek) / sizeof(ek[0]));
int bSz = (int)(sizeof(bsz) / sizeof(bsz[0]));
int ki, bi, s, t;
for (t = 0; t < (int)sizeof(rtin); t++)
rtin[t] = (byte)(0xA0 + t);
for (ki = 0; ki < ekSz; ki++) {
/* boundary-size known-answer + round-trip */
for (bi = 0; bi < bSz; bi++) {
XMEMSET(output, 0, sizeof(output));
XMEMSET(plain, 0, sizeof(plain));
wrapSz = wc_AesKeyWrap_Pad(ek[ki].kek, ek[ki].kekSz,
rtin, bsz[bi], output, sizeof(output), NULL);
if ((wrapSz < 0) || (wrapSz != (int)bes[bi]))
return WC_TEST_RET_ENC_I(ki * 100 + bi);
if (XMEMCMP(output, ek[ki].exp[bi], bes[bi]) != 0)
return WC_TEST_RET_ENC_I(ki * 100 + bi);
plainSz = wc_AesKeyUnWrap_Pad(ek[ki].kek, ek[ki].kekSz, output,
(word32)wrapSz, plain, sizeof(plain), NULL);
if ((plainSz != (int)bsz[bi]) ||
(XMEMCMP(plain, rtin, bsz[bi]) != 0))
return WC_TEST_RET_ENC_I(ki * 100 + bi);
}
/* exhaustive round-trip for every input size 1..31 */
for (s = 1; s <= (int)sizeof(rtin) - 1; s++) {
int ew = (((s + 7) / 8) * 8) + 8;
XMEMSET(output, 0, sizeof(output));
XMEMSET(plain, 0, sizeof(plain));
wrapSz = wc_AesKeyWrap_Pad(ek[ki].kek, ek[ki].kekSz,
rtin, (word32)s, output, sizeof(output), NULL);
if (wrapSz != ew)
return WC_TEST_RET_ENC_I(ki * 100 + 30 + s);
plainSz = wc_AesKeyUnWrap_Pad(ek[ki].kek, ek[ki].kekSz, output,
(word32)wrapSz, plain, sizeof(plain), NULL);
if ((plainSz != s) ||
(XMEMCMP(plain, rtin, (word32)s) != 0))
return WC_TEST_RET_ENC_I(ki * 100 + 30 + s);
}
}
}
#endif /* WOLFSSL_AES_128 || WOLFSSL_AES_192 || WOLFSSL_AES_256 */
#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
/* Drive wc_AesKeyWrap_Pad_ex/wc_AesKeyUnWrap_Pad_ex directly with a caller
* Aes; the KAT loop above already covers every vector via the wrappers. */
{
Aes* aes = (Aes*)XMALLOC(sizeof(Aes), HEAP_HINT, DYNAMIC_TYPE_AES);
if (aes == NULL)
return WC_TEST_RET_ENC_NC;
XMEMSET(output, 0, sizeof(output));
XMEMSET(plain, 0, sizeof(plain));
if (wc_AesInit(aes, HEAP_HINT, devId) != 0) {
XFREE(aes, HEAP_HINT, DYNAMIC_TYPE_AES);
return WC_TEST_RET_ENC_NC;
}
if (wc_AesSetKey(aes, test_kwp[0].kek, test_kwp[0].kekLen, NULL,
AES_ENCRYPTION) != 0) {
wc_AesFree(aes);
XFREE(aes, HEAP_HINT, DYNAMIC_TYPE_AES);
return WC_TEST_RET_ENC_NC;
}
wrapSz = wc_AesKeyWrap_Pad_ex(aes, test_kwp[0].data, test_kwp[0].dataLen,
output, sizeof(output), NULL);
wc_AesFree(aes);
if ( (wrapSz < 0) || (wrapSz != (int)test_kwp[0].verifyLen) ||
XMEMCMP(output, test_kwp[0].verify, test_kwp[0].verifyLen) != 0) {
XFREE(aes, HEAP_HINT, DYNAMIC_TYPE_AES);
return WC_TEST_RET_ENC_NC;
}
if (wc_AesInit(aes, HEAP_HINT, devId) != 0) {
XFREE(aes, HEAP_HINT, DYNAMIC_TYPE_AES);
return WC_TEST_RET_ENC_NC;
}
if (wc_AesSetKey(aes, test_kwp[0].kek, test_kwp[0].kekLen, NULL,
AES_DECRYPTION) != 0) {
wc_AesFree(aes);
XFREE(aes, HEAP_HINT, DYNAMIC_TYPE_AES);
return WC_TEST_RET_ENC_NC;
}
plainSz = wc_AesKeyUnWrap_Pad_ex(aes, output, (word32)wrapSz,
plain, sizeof(plain), NULL);
wc_AesFree(aes);
XFREE(aes, HEAP_HINT, DYNAMIC_TYPE_AES);
if ( (plainSz < 0) || (plainSz != (int)test_kwp[0].dataLen) ||
XMEMCMP(plain, test_kwp[0].data, test_kwp[0].dataLen) != 0)
return WC_TEST_RET_ENC_NC;
}
/* In-place round-trip (in == out) for every vector: covers the single-block
* and RFC 3394 loop paths, exercising the XMEMMOVE staging. */
for (i = 0; i < kwpSz; i++) {
XMEMSET(output, 0, sizeof(output));
XMEMCPY(output, test_kwp[i].data, test_kwp[i].dataLen);
wrapSz = wc_AesKeyWrap_Pad(test_kwp[i].kek, test_kwp[i].kekLen,
output, test_kwp[i].dataLen,
output, sizeof(output), NULL);
if ( (wrapSz < 0) || (wrapSz != (int)test_kwp[i].verifyLen) )
return WC_TEST_RET_ENC_I(i);
if (XMEMCMP(output, test_kwp[i].verify, test_kwp[i].verifyLen) != 0)
return WC_TEST_RET_ENC_I(i);
plainSz = wc_AesKeyUnWrap_Pad(test_kwp[i].kek, test_kwp[i].kekLen,
output, (word32)wrapSz,
output, sizeof(output), NULL);
if ( (plainSz < 0) || (plainSz != (int)test_kwp[i].dataLen) )
return WC_TEST_RET_ENC_I(i);
if (XMEMCMP(output, test_kwp[i].data, test_kwp[i].dataLen) != 0)
return WC_TEST_RET_ENC_I(i);
}
/* Forge decrypted blocks AIV(8)|P(8) to drive unwrap checks 2 (MLI range)
* and 3 (nonzero pad); ECB-encrypting a chosen block fixes what unwrap sees. */
{
Aes* faes = (Aes*)XMALLOC(sizeof(Aes), HEAP_HINT, DYNAMIC_TYPE_AES);
byte forgeBlk[WC_AES_BLOCK_SIZE];
byte forged[WC_AES_BLOCK_SIZE];
int fr;
if (faes == NULL)
return WC_TEST_RET_ENC_NC;
/* check 2: correct AIV constant but MLI = 0 */
XMEMSET(forgeBlk, 0, sizeof(forgeBlk));
forgeBlk[0] = 0xa6; forgeBlk[1] = 0x59; forgeBlk[2] = 0x59;
forgeBlk[3] = 0xa6;
forgeBlk[8] = 0x11; /* arbitrary recovered plaintext octet */
fr = wc_AesInit(faes, HEAP_HINT, devId);
if (fr == 0)
fr = wc_AesSetKey(faes, test_kwp[0].kek, test_kwp[0].kekLen, NULL,
AES_ENCRYPTION);
if (fr == 0)
fr = wc_AesEncryptDirect(faes, forged, forgeBlk);
wc_AesFree(faes);
if (fr != 0) {
XFREE(faes, HEAP_HINT, DYNAMIC_TYPE_AES);
return WC_TEST_RET_ENC_EC(fr);
}
if (wc_AesKeyUnWrap_Pad(test_kwp[0].kek, test_kwp[0].kekLen, forged, 16,
plain, sizeof(plain), NULL)
!= WC_NO_ERR_TRACE(BAD_KEYWRAP_IV_E)) {
XFREE(faes, HEAP_HINT, DYNAMIC_TYPE_AES);
return WC_TEST_RET_ENC_NC;
}
/* check 3: correct AIV constant, MLI = 1, but a nonzero pad octet */
XMEMSET(forgeBlk, 0, sizeof(forgeBlk));
forgeBlk[0] = 0xa6; forgeBlk[1] = 0x59; forgeBlk[2] = 0x59;
forgeBlk[3] = 0xa6;
forgeBlk[7] = 0x01; /* MLI = 1 */
forgeBlk[8] = 0x41; /* the one real octet... */
forgeBlk[9] = 0xff; /* ...followed by a nonzero pad octet -> rejected */
fr = wc_AesInit(faes, HEAP_HINT, devId);
if (fr == 0)
fr = wc_AesSetKey(faes, test_kwp[0].kek, test_kwp[0].kekLen, NULL,
AES_ENCRYPTION);
if (fr == 0)
fr = wc_AesEncryptDirect(faes, forged, forgeBlk);
wc_AesFree(faes);
if (fr != 0) {
XFREE(faes, HEAP_HINT, DYNAMIC_TYPE_AES);
return WC_TEST_RET_ENC_EC(fr);
}
if (wc_AesKeyUnWrap_Pad(test_kwp[0].kek, test_kwp[0].kekLen, forged, 16,
plain, sizeof(plain), NULL)
!= WC_NO_ERR_TRACE(BAD_KEYWRAP_IV_E)) {
XFREE(faes, HEAP_HINT, DYNAMIC_TYPE_AES);
return WC_TEST_RET_ENC_NC;
}
XFREE(faes, HEAP_HINT, DYNAMIC_TYPE_AES);
}
#endif /* !HAVE_FIPS && !HAVE_SELFTEST */
return 0;
}
#endif /* WOLFSSL_AES_KEYWRAP_PADDING */
#endif /* HAVE_AES_KEYWRAP */
#endif /* !NO_AES */
@@ -79943,6 +80531,67 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
}
}
#endif /* HAVE_AES_ECB */
#ifdef HAVE_AES_KEYWRAP
if (info->cipher.type == WC_CIPHER_AES_KEYWRAP) {
int kwRet;
/* set devId to invalid, so software is used */
info->cipher.aeskeywrap.aes->devId = INVALID_DEVID;
if (info->cipher.enc) {
#ifdef WOLFSSL_AES_KEYWRAP_PADDING
if (info->cipher.aeskeywrap.pad)
kwRet = wc_AesKeyWrap_Pad_ex(
info->cipher.aeskeywrap.aes,
info->cipher.aeskeywrap.in,
info->cipher.aeskeywrap.inSz,
info->cipher.aeskeywrap.out,
info->cipher.aeskeywrap.outSz,
info->cipher.aeskeywrap.iv);
else
#endif
kwRet = wc_AesKeyWrap_ex(
info->cipher.aeskeywrap.aes,
info->cipher.aeskeywrap.in,
info->cipher.aeskeywrap.inSz,
info->cipher.aeskeywrap.out,
info->cipher.aeskeywrap.outSz,
info->cipher.aeskeywrap.iv);
}
else {
#ifdef WOLFSSL_AES_KEYWRAP_PADDING
if (info->cipher.aeskeywrap.pad)
kwRet = wc_AesKeyUnWrap_Pad_ex(
info->cipher.aeskeywrap.aes,
info->cipher.aeskeywrap.in,
info->cipher.aeskeywrap.inSz,
info->cipher.aeskeywrap.out,
info->cipher.aeskeywrap.outSz,
info->cipher.aeskeywrap.iv);
else
#endif
kwRet = wc_AesKeyUnWrap_ex(
info->cipher.aeskeywrap.aes,
info->cipher.aeskeywrap.in,
info->cipher.aeskeywrap.inSz,
info->cipher.aeskeywrap.out,
info->cipher.aeskeywrap.outSz,
info->cipher.aeskeywrap.iv);
}
/* reset devId */
info->cipher.aeskeywrap.aes->devId = devIdArg;
if (kwRet < 0) {
ret = kwRet;
}
else {
/* report produced length back to the dispatcher */
info->cipher.aeskeywrap.outResSz = (word32)kwRet;
ret = 0;
}
}
#endif /* HAVE_AES_KEYWRAP */
#if defined(WOLFSSL_AES_COUNTER) && !defined(HAVE_FIPS) && \
!defined(HAVE_SELFTEST)
if (info->cipher.type == WC_CIPHER_AES_CTR) {
@@ -81765,6 +82414,14 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void)
if (ret == 0)
ret = aesccm_test();
#endif
#ifdef HAVE_AES_KEYWRAP
if (ret == 0)
ret = aeskeywrap_test();
#ifdef WOLFSSL_AES_KEYWRAP_PADDING
if (ret == 0)
ret = aeskeywrap_pad_test();
#endif
#endif /* HAVE_AES_KEYWRAP */
#endif /* !NO_AES && !WOLF_CRYPTO_CB_ONLY_AES */
#ifndef NO_DES3
if (ret == 0)
+32
View File
@@ -737,6 +737,13 @@ WOLFSSL_API WARN_UNUSED_RESULT int wc_AesGcmDecryptFinal(Aes* aes,
#endif /* HAVE_AESCCM */
#ifdef HAVE_AES_KEYWRAP
/* RFC 3394 AES key wrap. On success return the produced (wrap) or recovered
* (unwrap) byte count (>= 0); on failure a negative error (BAD_FUNC_ARG,
* BAD_KEYWRAP_IV_E, ...). in and out may alias (in-place is supported). iv is
* the optional 8-byte integrity check value; NULL uses the default A6..A6.
* The _ex variants take a caller-provided Aes already keyed with the KEK
* (AES_ENCRYPTION to wrap, AES_DECRYPTION to unwrap) and, when its devId is set,
* route through a registered crypto callback. */
WOLFSSL_API int wc_AesKeyWrap(const byte* key, word32 keySz,
const byte* in, word32 inSz,
byte* out, word32 outSz,
@@ -753,6 +760,31 @@ WOLFSSL_API WARN_UNUSED_RESULT int wc_AesGcmDecryptFinal(Aes* aes,
const byte* in, word32 inSz,
byte* out, word32 outSz,
const byte* iv);
#ifdef WOLFSSL_AES_KEYWRAP_PADDING
/* RFC 5649 AES key wrap with padding. Wrap accepts any inSz >= 1 and produces
* ceil(inSz/8)*8 + 8 bytes; unwrap recovers and returns the original inSz. On
* success return that byte count (>= 0); on failure a negative error. in and
* out may alias (in-place is supported). iv is optional: NULL uses the RFC
* 5649 AIV constant (A6 59 59 A6). If non-NULL it overrides ONLY that 4-byte
* high half - the low 4 bytes always carry the computed length indicator. NOTE
* this differs from the non-padded wc_AesKeyWrap* iv, which is a full 8 bytes. */
WOLFSSL_API int wc_AesKeyWrap_Pad(const byte* key, word32 keySz,
const byte* in, word32 inSz,
byte* out, word32 outSz,
const byte* iv);
WOLFSSL_API int wc_AesKeyWrap_Pad_ex(Aes* aes,
const byte* in, word32 inSz,
byte* out, word32 outSz,
const byte* iv);
WOLFSSL_API int wc_AesKeyUnWrap_Pad(const byte* key, word32 keySz,
const byte* in, word32 inSz,
byte* out, word32 outSz,
const byte* iv);
WOLFSSL_API int wc_AesKeyUnWrap_Pad_ex(Aes* aes,
const byte* in, word32 inSz,
byte* out, word32 outSz,
const byte* iv);
#endif /* WOLFSSL_AES_KEYWRAP_PADDING */
#endif /* HAVE_AES_KEYWRAP */
#ifdef WOLFSSL_AES_XTS
+18
View File
@@ -527,6 +527,18 @@ typedef struct wc_CryptoInfo {
const byte* key;
word32 keySz;
} aessetkey;
#endif
#if !defined(NO_AES) && defined(HAVE_AES_KEYWRAP)
struct {
Aes* aes;
const byte* in;
word32 inSz;
byte* out;
word32 outSz; /* size of out buffer (input) */
word32 outResSz; /* bytes produced (output, set by cb) */
const byte* iv;
int pad; /* 1 = RFC 5649 padded, 0 = RFC 3394 */
} aeskeywrap;
#endif
void* ctx;
#ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES
@@ -988,6 +1000,12 @@ WOLFSSL_LOCAL int wc_CryptoCb_AesEcbDecrypt(Aes* aes, byte* out,
#ifdef WOLF_CRYPTO_CB_AES_SETKEY
WOLFSSL_API int wc_CryptoCb_AesSetKey(Aes* aes, const byte* key, word32 keySz);
#endif /* WOLF_CRYPTO_CB_AES_SETKEY */
#ifdef HAVE_AES_KEYWRAP
WOLFSSL_LOCAL int wc_CryptoCb_AesKeyWrap(Aes* aes, const byte* in,
word32 inSz, byte* out, word32 outSz, const byte* iv, int pad);
WOLFSSL_LOCAL int wc_CryptoCb_AesKeyUnWrap(Aes* aes, const byte* in,
word32 inSz, byte* out, word32 outSz, const byte* iv, int pad);
#endif /* HAVE_AES_KEYWRAP */
#endif /* !NO_AES */
#ifndef NO_DES3
+1
View File
@@ -1623,6 +1623,7 @@ enum wc_CipherType {
WC_CIPHER_AES_CCM = 12,
WC_CIPHER_AES_ECB = 13,
WC_CIPHER_AES_OFB = 14,
WC_CIPHER_AES_KEYWRAP = 15,
WC_CIPHER_DES3 = 7,
WC_CIPHER_DES = 8,
WC_CIPHER_CHACHA = 9,