Skip to content

Commit

Permalink
Feature/multiple aes siv ads (#7911)
Browse files Browse the repository at this point in the history
* Proposed new interface for AesSivEncrypt with number of ADs != 1.

* Implement AES SIV S2V computation with a number of ADs not equal to 1.

* Add Example A.1 from RFC5297 to AES SIV test vectors.

* Add tests for new AES SIV interface, and add test vectors for examples given in RFC5297.

* Include the nonce in count of maximum number of ADs.

* Addressing review comments.

* Addressing review comments: Use uppercase 'U' suffix on unsigned constant.

* Rename local variables named 'ad0' to 'ad', since the zero makes no sense, especially since in the RFC 5297 document they're actually counting the ADs from 1.
  • Loading branch information
ptsiewie authored Sep 12, 2024
1 parent 088dfab commit 9e2a7b3
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 29 deletions.
90 changes: 68 additions & 22 deletions wolfcrypt/src/aes.c
Original file line number Diff line number Diff line change
Expand Up @@ -13609,7 +13609,7 @@ int wc_AesXtsDecryptConsecutiveSectors(XtsAes* aes, byte* out, const byte* in,
* See RFC 5297 Section 2.4.
*/
static WARN_UNUSED_RESULT int S2V(
const byte* key, word32 keySz, const byte* assoc, word32 assocSz,
const byte* key, word32 keySz, const AesSivAssoc* assoc, word32 numAssoc,
const byte* nonce, word32 nonceSz, const byte* data,
word32 dataSz, byte* out)
{
Expand All @@ -13623,6 +13623,8 @@ static WARN_UNUSED_RESULT int S2V(
#endif
word32 macSz = AES_BLOCK_SIZE;
int ret = 0;
byte tmpi = 0;
word32 ai;
word32 zeroBytes;

#ifdef WOLFSSL_SMALL_STACK
Expand All @@ -13635,32 +13637,48 @@ static WARN_UNUSED_RESULT int S2V(
}
if (ret == 0)
#endif
{

if ((numAssoc > 126) || ((nonceSz > 0) && (numAssoc > 125))) {
/* See RFC 5297 Section 7. */
WOLFSSL_MSG("Maximum number of ADs (including the nonce) for AES SIV is"
" 126.");
ret = BAD_FUNC_ARG;
}

if (ret == 0) {
XMEMSET(tmp[1], 0, AES_BLOCK_SIZE);
XMEMSET(tmp[2], 0, AES_BLOCK_SIZE);

ret = wc_AesCmacGenerate(tmp[0], &macSz, tmp[1], AES_BLOCK_SIZE,
key, keySz);
if (ret == 0) {
ShiftAndXorRb(tmp[1], tmp[0]);
ret = wc_AesCmacGenerate(tmp[0], &macSz, assoc, assocSz, key,
keySz);
if (ret == 0) {
xorbuf(tmp[1], tmp[0], AES_BLOCK_SIZE);
}
}
}

if (ret == 0) {
if (nonceSz > 0) {
ShiftAndXorRb(tmp[0], tmp[1]);
ret = wc_AesCmacGenerate(tmp[1], &macSz, nonce, nonceSz, key,
keySz);
/* Loop over authenticated associated data AD1..ADn */
for (ai = 0; ai < numAssoc; ++ai) {
ShiftAndXorRb(tmp[1-tmpi], tmp[tmpi]);
ret = wc_AesCmacGenerate(tmp[tmpi], &macSz, assoc[ai].assoc,
assoc[ai].assocSz, key, keySz);
if (ret != 0)
break;
xorbuf(tmp[1-tmpi], tmp[tmpi], AES_BLOCK_SIZE);
tmpi = 1 - tmpi;
}

/* Add nonce as final AD. See RFC 5297 Section 3. */
if ((ret == 0) && (nonceSz > 0)) {
ShiftAndXorRb(tmp[1-tmpi], tmp[tmpi]);
ret = wc_AesCmacGenerate(tmp[tmpi], &macSz, nonce,
nonceSz, key, keySz);
if (ret == 0) {
xorbuf(tmp[0], tmp[1], AES_BLOCK_SIZE);
xorbuf(tmp[1-tmpi], tmp[tmpi], AES_BLOCK_SIZE);
}
tmpi = 1 - tmpi;
}
else {

/* For simplicity of the remaining code, make sure the "final" result
is always in tmp[0]. */
if (tmpi == 1) {
XMEMCPY(tmp[0], tmp[1], AES_BLOCK_SIZE);
}
}
Expand Down Expand Up @@ -13727,8 +13745,8 @@ static WARN_UNUSED_RESULT int S2V(
}

static WARN_UNUSED_RESULT int AesSivCipher(
const byte* key, word32 keySz, const byte* assoc,
word32 assocSz, const byte* nonce, word32 nonceSz,
const byte* key, word32 keySz, const AesSivAssoc* assoc,
word32 numAssoc, const byte* nonce, word32 nonceSz,
const byte* data, word32 dataSz, byte* siv, byte* out,
int enc)
{
Expand All @@ -13752,7 +13770,7 @@ static WARN_UNUSED_RESULT int AesSivCipher(

if (ret == 0) {
if (enc == 1) {
ret = S2V(key, keySz / 2, assoc, assocSz, nonce, nonceSz, data,
ret = S2V(key, keySz / 2, assoc, numAssoc, nonce, nonceSz, data,
dataSz, sivTmp);
if (ret != 0) {
WOLFSSL_MSG("S2V failed.");
Expand Down Expand Up @@ -13799,7 +13817,7 @@ static WARN_UNUSED_RESULT int AesSivCipher(
}

if (ret == 0 && enc == 0) {
ret = S2V(key, keySz / 2, assoc, assocSz, nonce, nonceSz, out, dataSz,
ret = S2V(key, keySz / 2, assoc, numAssoc, nonce, nonceSz, out, dataSz,
sivTmp);
if (ret != 0) {
WOLFSSL_MSG("S2V failed.");
Expand All @@ -13826,7 +13844,10 @@ int wc_AesSivEncrypt(const byte* key, word32 keySz, const byte* assoc,
word32 assocSz, const byte* nonce, word32 nonceSz,
const byte* in, word32 inSz, byte* siv, byte* out)
{
return AesSivCipher(key, keySz, assoc, assocSz, nonce, nonceSz, in, inSz,
AesSivAssoc ad;
ad.assoc = assoc;
ad.assocSz = assocSz;
return AesSivCipher(key, keySz, &ad, 1U, nonce, nonceSz, in, inSz,
siv, out, 1);
}

Expand All @@ -13837,7 +13858,32 @@ int wc_AesSivDecrypt(const byte* key, word32 keySz, const byte* assoc,
word32 assocSz, const byte* nonce, word32 nonceSz,
const byte* in, word32 inSz, byte* siv, byte* out)
{
return AesSivCipher(key, keySz, assoc, assocSz, nonce, nonceSz, in, inSz,
AesSivAssoc ad;
ad.assoc = assoc;
ad.assocSz = assocSz;
return AesSivCipher(key, keySz, &ad, 1U, nonce, nonceSz, in, inSz,
siv, out, 0);
}

/*
* See RFC 5297 Section 2.6.
*/
int wc_AesSivEncrypt_ex(const byte* key, word32 keySz, const AesSivAssoc* assoc,
word32 numAssoc, const byte* nonce, word32 nonceSz,
const byte* in, word32 inSz, byte* siv, byte* out)
{
return AesSivCipher(key, keySz, assoc, numAssoc, nonce, nonceSz, in, inSz,
siv, out, 1);
}

/*
* See RFC 5297 Section 2.7.
*/
int wc_AesSivDecrypt_ex(const byte* key, word32 keySz, const AesSivAssoc* assoc,
word32 numAssoc, const byte* nonce, word32 nonceSz,
const byte* in, word32 inSz, byte* siv, byte* out)
{
return AesSivCipher(key, keySz, assoc, numAssoc, nonce, nonceSz, in, inSz,
siv, out, 0);
}

Expand Down
108 changes: 101 additions & 7 deletions wolfcrypt/test/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -58619,24 +58619,29 @@ typedef struct {
word32 keySz;
const byte nonce[49];
word32 nonceSz;
const byte assoc[81];
word32 assocSz;
byte numAssoc;
const byte assoc1[81];
word32 assoc1Sz;
const byte assoc2[11];
word32 assoc2Sz;
const byte plaintext[83];
word32 plaintextSz;
const byte siv[AES_BLOCK_SIZE+1];
const byte ciphertext[82];
word32 ciphertextSz;
} AesSivTestVector;

#define AES_SIV_TEST_VECTORS 7
#define AES_SIV_TEST_VECTORS 9

WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_siv_test(void)
{
/* These test vectors come from chrony 4.1's SIV unit tests. */
WOLFSSL_SMALL_STACK_STATIC const AesSivTestVector testVectors[AES_SIV_TEST_VECTORS] = {
/* These test vectors come from chrony 4.1's SIV unit tests. */
{ "\x01\x23\x45\x67\x89\xab\xcd\xef\xf0\x12\x34\x56\x78\x9a\xbc\xde"
"\xef\x01\x23\x45\x67\x89\xab\xcd\xde\xf0\x12\x34\x56\x78\x9a\xbc", 32,
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", 16,
1,
"", 0,
"", 0,
"", 0,
"\x22\x3e\xb5\x94\xe0\xe0\x25\x4b\x00\x25\x8e\x21\x9a\x1c\xa4\x21",
Expand All @@ -58645,14 +58650,18 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_siv_test(void)
{ "\x01\x23\x45\x67\x89\xab\xcd\xef\xf0\x12\x34\x56\x78\x9a\xbc\xde"
"\xef\x01\x23\x45\x67\x89\xab\xcd\xde\xf0\x12\x34\x56\x78\x9a\xbc", 32,
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", 16,
1,
"\x4c\x9d\x4f\xca\xed\x8a\xe2\xba\xad\x3f\x3e\xa6\xe9\x3c\x8c\x8b", 16,
"", 0,
"", 0,
"\xd7\x20\x19\x89\xc6\xdb\xc6\xd6\x61\xfc\x62\xbc\x86\x5e\xee\xef",
"", 0
},
{ "\x01\x23\x45\x67\x89\xab\xcd\xef\xf0\x12\x34\x56\x78\x9a\xbc\xde"
"\xef\x01\x23\x45\x67\x89\xab\xcd\xde\xf0\x12\x34\x56\x78\x9a\xbc", 32,
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", 16,
1,
"", 0,
"", 0,
"\x4c\x9d\x4f\xca\xed\x8a\xe2\xba\xad\x3f\x3e\xa6\xe9\x3c\x8c\x8b", 16,
"\xb6\xc1\x60\xe9\xc2\xfd\x2a\xe8\xde\xc5\x36\x8b\x2a\x33\xed\xe1",
Expand All @@ -58661,15 +58670,19 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_siv_test(void)
{ "\x01\x23\x45\x67\x89\xab\xcd\xef\xf0\x12\x34\x56\x78\x9a\xbc\xde"
"\xef\x01\x23\x45\x67\x89\xab\xcd\xde\xf0\x12\x34\x56\x78\x9a\xbc", 32,
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e", 15,
1,
"\x4c\x9d\x4f\xca\xed\x8a\xe2\xba\xad\x3f\x3e\xa6\xe9\x3c\x8c", 15,
"", 0,
"\xba\x99\x79\x31\x23\x7e\x3c\x53\x58\x7e\xd4\x93\x02\xab\xe4", 15,
"\x03\x8c\x41\x51\xba\x7a\x8f\x77\x6e\x56\x31\x99\x42\x0b\xc7\x03",
"\xe7\x6c\x67\xc9\xda\xb7\x0d\x5b\x44\x06\x26\x5a\xd0\xd2\x3b", 15
},
{ "\x01\x23\x45\x67\x89\xab\xcd\xef\xf0\x12\x34\x56\x78\x9a\xbc\xde"
"\xef\x01\x23\x45\x67\x89\xab\xcd\xde\xf0\x12\x34\x56\x78\x9a\xbc", 32,
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", 16,
1,
"\x4c\x9d\x4f\xca\xed\x8a\xe2\xba\xad\x3f\x3e\xa6\xe9\x3c\x8c\x8b", 16,
"", 0,
"\xba\x99\x79\x31\x23\x7e\x3c\x53\x58\x7e\xd4\x93\x02\xab\xe4\xa7", 16,
"\x5c\x05\x23\x65\xf4\x57\x0a\xa0\xfb\x38\x3e\xce\x9b\x75\x85\xeb",
"\x68\x85\x19\x36\x0c\x7c\x48\x11\x40\xcb\x9b\x57\x9a\x0e\x65\x32", 16
Expand All @@ -58678,8 +58691,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_siv_test(void)
"\xef\x01\x23\x45\x67\x89\xab\xcd\xde\xf0\x12\x34\x56\x78\x9a\xbc", 32,
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
"\xd5", 17,
1,
"\x4c\x9d\x4f\xca\xed\x8a\xe2\xba\xad\x3f\x3e\xa6\xe9\x3c\x8c\x8b"
"\xa0", 17,
"", 0,
"\xba\x99\x79\x31\x23\x7e\x3c\x53\x58\x7e\xd4\x93\x02\xab\xe4\xa7"
"\x08", 17,
"\xaf\x58\x4b\xe7\x82\x1e\x96\x19\x29\x91\x25\xe0\xdd\x80\x3b\x49",
Expand All @@ -58691,11 +58706,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_siv_test(void)
"\xb0\x5a\x1b\xc7\x56\xe7\xb6\x2c\xb4\x85\xe5\x56\xa5\x28\xc0\x6c"
"\x2f\x3b\x0b\x9d\x1a\x0c\xdf\x69\x47\xe0\xcc\xc0\x87\xaa\x5c\x09"
"\x98\x48\x8d\x6a\x8e\x1e\x05\xd7\x8b\x68\x74\x83\xb5\x1d\xf1\x2c", 48,
1,
"\xe5\x8b\xd2\x6a\x30\xc5\xc5\x61\xcc\xbd\x7c\x27\xbf\xfe\xf9\x06"
"\x00\x5b\xd7\xfc\x11\x0b\xcf\x16\x61\xef\xac\x05\xa7\xaf\xec\x27"
"\x41\xc8\x5e\x9e\x0d\xf9\x2f\xaf\x20\x79\x17\xe5\x17\x91\x2a\x27"
"\x34\x1c\xbc\xaf\xeb\xef\x7f\x52\xe7\x1e\x4c\x2a\xca\xbd\x2b\xbe"
"\x34\xd6\xfb\x69\xd3\x3e\x49\x59\x60\xb4\x26\xc9\xb8\xce\xba", 79,
"", 0,
"\x6c\xe7\xcf\x7e\xab\x7b\xa0\xe1\xa7\x22\xcb\x88\xde\x5e\x42\xd2"
"\xec\x79\xe0\xa2\xcf\x5f\x0f\x6f\x6b\x89\x57\xcd\xae\x17\xd4\xc2"
"\xf3\x1b\xa2\xa8\x13\x78\x23\x2f\x83\xa8\xd4\x0c\xc0\xd2\xf3\x99"
Expand All @@ -58709,17 +58726,53 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_siv_test(void)
"\x48\xc9\x55\xc5\x2f\x40\x73\x3f\x98\xbb\x8d\x69\x78\x46\x64\x17"
"\x8d\x49\x2f\x14\x62\xa4\x7c\x2a\x57\x38\x87\xce\xc6\x72\xd3\x5c"
"\xa1", 81
}};
},
/* Example A.1 from RFC5297 */
{
"\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", 32,
"", 0,
1,
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
"\x20\x21\x22\x23\x24\x25\x26\x27", 24,
"", 0,
"\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee", 14,
"\x85\x63\x2d\x07\xc6\xe8\xf3\x7f\x95\x0a\xcd\x32\x0a\x2e\xcc\x93",
"\x40\xc0\x2b\x96\x90\xc4\xdc\x04\xda\xef\x7f\x6a\xfe\x5c", 14
},
/* Example A.2 from RFC5297 */
{
"\x7f\x7e\x7d\x7c\x7b\x7a\x79\x78\x77\x76\x75\x74\x73\x72\x71\x70"
"\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f", 32,
"\x09\xf9\x11\x02\x9d\x74\xe3\x5b\xd8\x41\x56\xc5\x63\x56\x88\xc0", 16,
2,
"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff"
"\xde\xad\xda\xda\xde\xad\xda\xda\xff\xee\xdd\xcc\xbb\xaa\x99\x88"
"\x77\x66\x55\x44\x33\x22\x11\x00", 40,
"\x10\x20\x30\x40\x50\x60\x70\x80\x90\xa0", 10,
"\x74\x68\x69\x73\x20\x69\x73\x20\x73\x6f\x6d\x65\x20\x70\x6c\x61"
"\x69\x6e\x74\x65\x78\x74\x20\x74\x6f\x20\x65\x6e\x63\x72\x79\x70"
"\x74\x20\x75\x73\x69\x6e\x67\x20\x53\x49\x56\x2d\x41\x45\x53", 47,
"\x7b\xdb\x6e\x3b\x43\x26\x67\xeb\x06\xf4\xd1\x4b\xff\x2f\xbd\x0f",
"\xcb\x90\x0f\x2f\xdd\xbe\x40\x43\x26\x60\x19\x65\xc8\x89\xbf\x17"
"\xdb\xa7\x7c\xeb\x09\x4f\xa6\x63\xb7\xa3\xf7\x48\xba\x8a\xf8\x29"
"\xea\x64\xad\x54\x4a\x27\x2e\x9c\x48\x5b\x62\xa3\xfd\x5c\x0d", 47
}
};
int i;
byte computedCiphertext[82];
byte computedPlaintext[82];
byte siv[AES_BLOCK_SIZE];
wc_test_ret_t ret = 0;
WOLFSSL_ENTER("aes_siv_test");

/* First test legacy "exactly one Assoc" interface. */
for (i = 0; i < AES_SIV_TEST_VECTORS; ++i) {
if (testVectors[i].numAssoc != 1)
continue;

ret = wc_AesSivEncrypt(testVectors[i].key, testVectors[i].keySz,
testVectors[i].assoc, testVectors[i].assocSz,
testVectors[i].assoc1, testVectors[i].assoc1Sz,
testVectors[i].nonce, testVectors[i].nonceSz,
testVectors[i].plaintext,
testVectors[i].plaintextSz, siv,
Expand All @@ -58737,7 +58790,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_siv_test(void)
return WC_TEST_RET_ENC_NC;
}
ret = wc_AesSivDecrypt(testVectors[i].key, testVectors[i].keySz,
testVectors[i].assoc, testVectors[i].assocSz,
testVectors[i].assoc1, testVectors[i].assoc1Sz,
testVectors[i].nonce, testVectors[i].nonceSz,
computedCiphertext, testVectors[i].plaintextSz,
siv, computedPlaintext);
Expand All @@ -58751,6 +58804,47 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_siv_test(void)
}
}

/* Then test "multiple Assoc" interface. */
for (i = 0; i < AES_SIV_TEST_VECTORS; ++i) {
const struct AesSivAssoc assoc[2] = {
{ testVectors[i].assoc1, testVectors[i].assoc1Sz },
{ testVectors[i].assoc2, testVectors[i].assoc2Sz }
};

ret = wc_AesSivEncrypt_ex(testVectors[i].key, testVectors[i].keySz,
assoc, testVectors[i].numAssoc,
testVectors[i].nonce, testVectors[i].nonceSz,
testVectors[i].plaintext,
testVectors[i].plaintextSz, siv,
computedCiphertext);
if (ret != 0) {
return WC_TEST_RET_ENC_EC(ret);
}
ret = XMEMCMP(siv, testVectors[i].siv, AES_BLOCK_SIZE);
if (ret != 0) {
return WC_TEST_RET_ENC_NC;
}
ret = XMEMCMP(computedCiphertext, testVectors[i].ciphertext,
testVectors[i].ciphertextSz);
if (ret != 0) {
return WC_TEST_RET_ENC_NC;
}
ret = wc_AesSivDecrypt_ex(testVectors[i].key, testVectors[i].keySz,
assoc, testVectors[i].numAssoc,
testVectors[i].nonce, testVectors[i].nonceSz,
computedCiphertext,
testVectors[i].plaintextSz, siv,
computedPlaintext);
if (ret != 0) {
return WC_TEST_RET_ENC_EC(ret);
}
ret = XMEMCMP(computedPlaintext, testVectors[i].plaintext,
testVectors[i].plaintextSz);
if (ret != 0) {
return WC_TEST_RET_ENC_NC;
}
}

return 0;
}
#endif
Expand Down
14 changes: 14 additions & 0 deletions wolfssl/wolfcrypt/aes.h
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,11 @@ WOLFSSL_API int wc_AesInit_Label(Aes* aes, const char* label, void* heap,
WOLFSSL_API void wc_AesFree(Aes* aes);

#ifdef WOLFSSL_AES_SIV
typedef struct AesSivAssoc {
const byte* assoc;
word32 assocSz;
} AesSivAssoc;

WOLFSSL_API
int wc_AesSivEncrypt(const byte* key, word32 keySz, const byte* assoc,
word32 assocSz, const byte* nonce, word32 nonceSz,
Expand All @@ -736,6 +741,15 @@ WOLFSSL_API
int wc_AesSivDecrypt(const byte* key, word32 keySz, const byte* assoc,
word32 assocSz, const byte* nonce, word32 nonceSz,
const byte* in, word32 inSz, byte* siv, byte* out);

WOLFSSL_API
int wc_AesSivEncrypt_ex(const byte* key, word32 keySz, const AesSivAssoc* assoc,
word32 numAssoc, const byte* nonce, word32 nonceSz,
const byte* in, word32 inSz, byte* siv, byte* out);
WOLFSSL_API
int wc_AesSivDecrypt_ex(const byte* key, word32 keySz, const AesSivAssoc* assoc,
word32 numAssoc, const byte* nonce, word32 nonceSz,
const byte* in, word32 inSz, byte* siv, byte* out);
#endif

#ifdef WOLFSSL_AES_EAX
Expand Down

0 comments on commit 9e2a7b3

Please sign in to comment.