Merge pull request #10226 from SparkiDev/api_test_cipher_algs_3

API tests: more cipher tests
This commit is contained in:
David Garske
2026-04-15 14:32:11 -07:00
committed by GitHub
8 changed files with 3345 additions and 30 deletions
+2302 -7
View File
File diff suppressed because it is too large Load Diff
+59 -11
View File
@@ -29,21 +29,45 @@ int test_wc_AesSetIV(void);
int test_wc_AesEncryptDecryptDirect(void);
int test_wc_AesEcbEncryptDecrypt(void);
int test_wc_AesCbcEncryptDecrypt(void);
int test_wc_AesCbcEncryptDecrypt_UnalignedBuffers(void);
int test_wc_AesCbc_CrossCipher(void);
int test_wc_AesCfbEncryptDecrypt(void);
int test_wc_AesCfb_CrossCipher(void);
int test_wc_AesOfbEncryptDecrypt(void);
int test_wc_AesOfb_CrossCipher(void);
int test_wc_AesCtsEncryptDecrypt(void);
int test_wc_AesCtsEncryptDecrypt_InPlace(void);
int test_wc_AesCtsEncryptDecrypt_UnalignedBuffers(void);
int test_wc_AesCtrSetKey(void);
int test_wc_AesCtrEncryptDecrypt(void);
int test_wc_AesCtrEncryptDecrypt_UnalignedBuffers(void);
int test_wc_AesCtr_CrossCipher(void);
int test_wc_AesCtrCounterOverflow(void);
int test_wc_AesGcmSetKey(void);
int test_wc_AesGcmEncryptDecrypt_Sizes(void);
int test_wc_AesGcmEncryptDecrypt(void);
int test_wc_AesGcmEncryptDecrypt_InPlace(void);
int test_wc_AesGcmEncryptDecrypt_UnalignedBuffers(void);
int test_wc_AesGcm_CrossCipher(void);
int test_wc_AesGcmMixedEncDecLongIV(void);
int test_wc_AesGcmNonStdNonce(void);
int test_wc_AesGcmStream(void);
int test_wc_AesGcmStream_MidStreamState(void);
int test_wc_AesGcmStream_ReinitAfterFinal(void);
int test_wc_AesCcmSetKey(void);
int test_wc_AesCcmEncryptDecrypt(void);
int test_wc_AesCcmEncryptDecrypt_InPlace(void);
int test_wc_AesCcmEncryptDecrypt_UnalignedBuffers(void);
int test_wc_AesCcmAeadEdgeCases(void);
int test_wc_AesXtsSetKey(void);
int test_wc_AesXtsEncryptDecrypt_Sizes(void);
int test_wc_AesXtsEncryptDecrypt(void);
int test_wc_AesXtsEncryptDecrypt_InPlace(void);
int test_wc_AesXtsEncryptDecrypt_UnalignedBuffers(void);
int test_wc_AesXtsEncryptDecryptSector(void);
int test_wc_AesXtsStream(void);
int test_wc_AesXtsStream_MidStreamState(void);
int test_wc_AesXtsStream_ReinitAfterFinal(void);
#if defined(WOLFSSL_AES_EAX) && defined(WOLFSSL_AES_256) && \
(!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 3)) && !defined(HAVE_SELFTEST)
int test_wc_AesEaxVectors(void);
@@ -83,22 +107,46 @@ int test_wc_CryptoCb_AesGcm_EncryptDecrypt(void);
TEST_DECL_GROUP("aes", test_wc_AesSetIV), \
TEST_DECL_GROUP("aes", test_wc_AesEncryptDecryptDirect), \
TEST_DECL_GROUP("aes", test_wc_AesEcbEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesCbcEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesCfbEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesCbcEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesCbcEncryptDecrypt_UnalignedBuffers), \
TEST_DECL_GROUP("aes", test_wc_AesCbc_CrossCipher), \
TEST_DECL_GROUP("aes", test_wc_AesCfbEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesCfb_CrossCipher), \
TEST_DECL_GROUP("aes", test_wc_AesOfbEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesCtsEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesCtrSetKey), \
TEST_DECL_GROUP("aes", test_wc_AesCtrEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesOfb_CrossCipher), \
TEST_DECL_GROUP("aes", test_wc_AesCtsEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesCtsEncryptDecrypt_InPlace), \
TEST_DECL_GROUP("aes", test_wc_AesCtsEncryptDecrypt_UnalignedBuffers), \
TEST_DECL_GROUP("aes", test_wc_AesCtrSetKey), \
TEST_DECL_GROUP("aes", test_wc_AesCtrEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesCtrEncryptDecrypt_UnalignedBuffers), \
TEST_DECL_GROUP("aes", test_wc_AesCtr_CrossCipher), \
TEST_DECL_GROUP("aes", test_wc_AesCtrCounterOverflow), \
TEST_DECL_GROUP("aes", test_wc_AesGcmSetKey), \
TEST_DECL_GROUP("aes", test_wc_AesGcmEncryptDecrypt_Sizes), \
TEST_DECL_GROUP("aes", test_wc_AesGcmEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesGcmMixedEncDecLongIV), \
TEST_DECL_GROUP("aes", test_wc_AesGcmEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesGcmEncryptDecrypt_InPlace), \
TEST_DECL_GROUP("aes", test_wc_AesGcmEncryptDecrypt_UnalignedBuffers), \
TEST_DECL_GROUP("aes", test_wc_AesGcm_CrossCipher), \
TEST_DECL_GROUP("aes", test_wc_AesGcmMixedEncDecLongIV), \
TEST_DECL_GROUP("aes", test_wc_AesGcmNonStdNonce), \
TEST_DECL_GROUP("aes", test_wc_AesGcmStream), \
TEST_DECL_GROUP("aes", test_wc_AesGcmStream_MidStreamState), \
TEST_DECL_GROUP("aes", test_wc_AesGcmStream_ReinitAfterFinal), \
TEST_DECL_GROUP("aes", test_wc_AesCcmSetKey), \
TEST_DECL_GROUP("aes", test_wc_AesCcmEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesXtsSetKey), \
TEST_DECL_GROUP("aes", test_wc_AesXtsEncryptDecrypt_Sizes), \
TEST_DECL_GROUP("aes", test_wc_AesXtsEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesCcmEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesCcmEncryptDecrypt_InPlace), \
TEST_DECL_GROUP("aes", test_wc_AesCcmEncryptDecrypt_UnalignedBuffers), \
TEST_DECL_GROUP("aes", test_wc_AesCcmAeadEdgeCases), \
TEST_DECL_GROUP("aes", test_wc_AesXtsSetKey), \
TEST_DECL_GROUP("aes", test_wc_AesXtsEncryptDecrypt_Sizes), \
TEST_DECL_GROUP("aes", test_wc_AesXtsEncryptDecrypt), \
TEST_DECL_GROUP("aes", test_wc_AesXtsEncryptDecrypt_InPlace), \
TEST_DECL_GROUP("aes", test_wc_AesXtsEncryptDecrypt_UnalignedBuffers), \
TEST_DECL_GROUP("aes", test_wc_AesXtsEncryptDecryptSector), \
TEST_DECL_GROUP("aes", test_wc_AesXtsStream), \
TEST_DECL_GROUP("aes", test_wc_AesXtsStream_MidStreamState), \
TEST_DECL_GROUP("aes", test_wc_AesXtsStream_ReinitAfterFinal), \
TEST_DECL_GROUP("aes", test_wc_AesCbc_MonteCarlo), \
TEST_DECL_GROUP("aes", test_wc_AesCtr_MonteCarlo), \
TEST_DECL_GROUP("aes", test_wc_AesGcm_MonteCarlo), \
+160
View File
@@ -184,3 +184,163 @@ int test_ascon_aead128(void)
#endif
return EXPECT_RESULT();
}
/*
* Ascon-AEAD128 AEAD edge cases:
* - invalid auth tag rejection (DecryptFinal with wrong tag -> ASCON_AUTH_E)
* - empty plaintext with empty AAD (KAT[0])
* - empty plaintext with non-empty AAD (KAT[1])
*
* KAT vectors are from the Ascon reference implementation:
* https://github.com/ascon/ascon-c
*/
int test_ascon_aead128_edge_cases(void)
{
EXPECT_DECLS;
#ifdef HAVE_ASCON
/* Shared key and nonce for all sub-tests (same as KAT[0..N]) */
static const byte key[ASCON_AEAD128_KEY_SZ] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
};
static const byte nonce[ASCON_AEAD128_NONCE_SZ] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
};
/* KAT[0]: PT="", AD="" -> CT = tag only */
static const byte expTag0[ASCON_AEAD128_TAG_SZ] = {
0x44, 0x27, 0xD6, 0x4B, 0x8E, 0x1E, 0x14, 0x51,
0xFC, 0x44, 0x59, 0x60, 0xF0, 0x83, 0x9B, 0xB0
};
/* KAT[1]: PT="", AD="00" -> CT = tag only */
static const byte ad1[1] = { 0x00 };
static const byte expTag1[ASCON_AEAD128_TAG_SZ] = {
0x10, 0x3A, 0xB7, 0x9D, 0x91, 0x3A, 0x03, 0x21,
0x28, 0x77, 0x15, 0xA9, 0x79, 0xBB, 0x85, 0x85
};
wc_AsconAEAD128* asconAEAD = NULL;
byte tagBuf[ASCON_AEAD128_TAG_SZ];
byte badTag[ASCON_AEAD128_TAG_SZ];
byte dummy[1]; /* non-NULL placeholder for 0-length pt/ct args */
ExpectNotNull(asconAEAD = wc_AsconAEAD128_New());
/* ------------------------------------------------------------------ */
/* 1. Empty plaintext + empty AAD (KAT[0]) */
/* ------------------------------------------------------------------ */
/* Encrypt and verify tag against KAT */
ExpectIntEQ(wc_AsconAEAD128_Init(asconAEAD), 0);
ExpectIntEQ(wc_AsconAEAD128_SetKey(asconAEAD, key), 0);
ExpectIntEQ(wc_AsconAEAD128_SetNonce(asconAEAD, nonce), 0);
ExpectIntEQ(wc_AsconAEAD128_SetAD(asconAEAD, dummy, 0), 0);
ExpectIntEQ(wc_AsconAEAD128_EncryptUpdate(asconAEAD, dummy, dummy, 0), 0);
XMEMSET(tagBuf, 0, sizeof(tagBuf));
ExpectIntEQ(wc_AsconAEAD128_EncryptFinal(asconAEAD, tagBuf), 0);
ExpectBufEQ(tagBuf, expTag0, ASCON_AEAD128_TAG_SZ);
wc_AsconAEAD128_Clear(asconAEAD);
/* Decrypt with correct tag -> success */
ExpectIntEQ(wc_AsconAEAD128_Init(asconAEAD), 0);
ExpectIntEQ(wc_AsconAEAD128_SetKey(asconAEAD, key), 0);
ExpectIntEQ(wc_AsconAEAD128_SetNonce(asconAEAD, nonce), 0);
ExpectIntEQ(wc_AsconAEAD128_SetAD(asconAEAD, dummy, 0), 0);
ExpectIntEQ(wc_AsconAEAD128_DecryptUpdate(asconAEAD, dummy, dummy, 0), 0);
ExpectIntEQ(wc_AsconAEAD128_DecryptFinal(asconAEAD, expTag0), 0);
wc_AsconAEAD128_Clear(asconAEAD);
/* Decrypt with wrong tag -> ASCON_AUTH_E */
XMEMCPY(badTag, expTag0, ASCON_AEAD128_TAG_SZ);
badTag[0] ^= 0xff;
ExpectIntEQ(wc_AsconAEAD128_Init(asconAEAD), 0);
ExpectIntEQ(wc_AsconAEAD128_SetKey(asconAEAD, key), 0);
ExpectIntEQ(wc_AsconAEAD128_SetNonce(asconAEAD, nonce), 0);
ExpectIntEQ(wc_AsconAEAD128_SetAD(asconAEAD, dummy, 0), 0);
ExpectIntEQ(wc_AsconAEAD128_DecryptUpdate(asconAEAD, dummy, dummy, 0), 0);
ExpectIntEQ(wc_AsconAEAD128_DecryptFinal(asconAEAD, badTag),
WC_NO_ERR_TRACE(ASCON_AUTH_E));
wc_AsconAEAD128_Clear(asconAEAD);
/* ------------------------------------------------------------------ */
/* 2. Empty plaintext + non-empty AAD (KAT[1], AD = {0x00}) */
/* ------------------------------------------------------------------ */
/* Encrypt and verify tag against KAT */
ExpectIntEQ(wc_AsconAEAD128_Init(asconAEAD), 0);
ExpectIntEQ(wc_AsconAEAD128_SetKey(asconAEAD, key), 0);
ExpectIntEQ(wc_AsconAEAD128_SetNonce(asconAEAD, nonce), 0);
ExpectIntEQ(wc_AsconAEAD128_SetAD(asconAEAD, ad1, sizeof(ad1)), 0);
ExpectIntEQ(wc_AsconAEAD128_EncryptUpdate(asconAEAD, dummy, dummy, 0), 0);
XMEMSET(tagBuf, 0, sizeof(tagBuf));
ExpectIntEQ(wc_AsconAEAD128_EncryptFinal(asconAEAD, tagBuf), 0);
ExpectBufEQ(tagBuf, expTag1, ASCON_AEAD128_TAG_SZ);
wc_AsconAEAD128_Clear(asconAEAD);
/* Decrypt with correct tag -> success */
ExpectIntEQ(wc_AsconAEAD128_Init(asconAEAD), 0);
ExpectIntEQ(wc_AsconAEAD128_SetKey(asconAEAD, key), 0);
ExpectIntEQ(wc_AsconAEAD128_SetNonce(asconAEAD, nonce), 0);
ExpectIntEQ(wc_AsconAEAD128_SetAD(asconAEAD, ad1, sizeof(ad1)), 0);
ExpectIntEQ(wc_AsconAEAD128_DecryptUpdate(asconAEAD, dummy, dummy, 0), 0);
ExpectIntEQ(wc_AsconAEAD128_DecryptFinal(asconAEAD, expTag1), 0);
wc_AsconAEAD128_Clear(asconAEAD);
/* Decrypt with wrong tag -> ASCON_AUTH_E */
XMEMCPY(badTag, expTag1, ASCON_AEAD128_TAG_SZ);
badTag[0] ^= 0xff;
ExpectIntEQ(wc_AsconAEAD128_Init(asconAEAD), 0);
ExpectIntEQ(wc_AsconAEAD128_SetKey(asconAEAD, key), 0);
ExpectIntEQ(wc_AsconAEAD128_SetNonce(asconAEAD, nonce), 0);
ExpectIntEQ(wc_AsconAEAD128_SetAD(asconAEAD, ad1, sizeof(ad1)), 0);
ExpectIntEQ(wc_AsconAEAD128_DecryptUpdate(asconAEAD, dummy, dummy, 0), 0);
ExpectIntEQ(wc_AsconAEAD128_DecryptFinal(asconAEAD, badTag),
WC_NO_ERR_TRACE(ASCON_AUTH_E));
wc_AsconAEAD128_Clear(asconAEAD);
/* ------------------------------------------------------------------ */
/* 3. Non-empty plaintext: invalid tag rejection */
/* ------------------------------------------------------------------ */
{
static const byte pt[] = { 0x00 };
byte ct[sizeof(pt)];
byte encTag[ASCON_AEAD128_TAG_SZ];
/* Encrypt one byte */
XMEMSET(ct, 0, sizeof(ct));
XMEMSET(encTag, 0, sizeof(encTag));
ExpectIntEQ(wc_AsconAEAD128_Init(asconAEAD), 0);
ExpectIntEQ(wc_AsconAEAD128_SetKey(asconAEAD, key), 0);
ExpectIntEQ(wc_AsconAEAD128_SetNonce(asconAEAD, nonce), 0);
ExpectIntEQ(wc_AsconAEAD128_SetAD(asconAEAD, dummy, 0), 0);
ExpectIntEQ(wc_AsconAEAD128_EncryptUpdate(asconAEAD, ct, pt,
sizeof(pt)), 0);
ExpectIntEQ(wc_AsconAEAD128_EncryptFinal(asconAEAD, encTag), 0);
wc_AsconAEAD128_Clear(asconAEAD);
/* Decrypt with correct tag -> success */
ExpectIntEQ(wc_AsconAEAD128_Init(asconAEAD), 0);
ExpectIntEQ(wc_AsconAEAD128_SetKey(asconAEAD, key), 0);
ExpectIntEQ(wc_AsconAEAD128_SetNonce(asconAEAD, nonce), 0);
ExpectIntEQ(wc_AsconAEAD128_SetAD(asconAEAD, dummy, 0), 0);
ExpectIntEQ(wc_AsconAEAD128_DecryptUpdate(asconAEAD, dummy, ct,
sizeof(ct)), 0);
ExpectIntEQ(wc_AsconAEAD128_DecryptFinal(asconAEAD, encTag), 0);
wc_AsconAEAD128_Clear(asconAEAD);
/* Decrypt with tampered tag -> ASCON_AUTH_E */
encTag[ASCON_AEAD128_TAG_SZ - 1] ^= 0xff;
ExpectIntEQ(wc_AsconAEAD128_Init(asconAEAD), 0);
ExpectIntEQ(wc_AsconAEAD128_SetKey(asconAEAD, key), 0);
ExpectIntEQ(wc_AsconAEAD128_SetNonce(asconAEAD, nonce), 0);
ExpectIntEQ(wc_AsconAEAD128_SetAD(asconAEAD, dummy, 0), 0);
ExpectIntEQ(wc_AsconAEAD128_DecryptUpdate(asconAEAD, dummy, ct,
sizeof(ct)), 0);
ExpectIntEQ(wc_AsconAEAD128_DecryptFinal(asconAEAD, encTag),
WC_NO_ERR_TRACE(ASCON_AUTH_E));
wc_AsconAEAD128_Clear(asconAEAD);
}
wc_AsconAEAD128_Free(asconAEAD);
#endif /* HAVE_ASCON */
return EXPECT_RESULT();
} /* END test_ascon_aead128_edge_cases */
+5 -3
View File
@@ -26,9 +26,11 @@
int test_ascon_hash256(void);
int test_ascon_aead128(void);
int test_ascon_aead128_edge_cases(void);
#define TEST_ASCON_DECLS \
TEST_DECL_GROUP("ascon", test_ascon_hash256), \
TEST_DECL_GROUP("ascon", test_ascon_aead128)
#define TEST_ASCON_DECLS \
TEST_DECL_GROUP("ascon", test_ascon_hash256), \
TEST_DECL_GROUP("ascon", test_ascon_aead128), \
TEST_DECL_GROUP("ascon", test_ascon_aead128_edge_cases)
#endif /* TESTS_API_TEST_ASCON_H */
+184
View File
@@ -433,3 +433,187 @@ int test_wc_Chacha_MonteCarlo(void)
#endif
return EXPECT_RESULT();
}
/*******************************************************************************
* ChaCha20 counter overflow
******************************************************************************/
/*
* Verify that the ChaCha20 block counter (X[12], a 32-bit value) wraps
* correctly from 0xFFFFFFFF back to 0x00000000.
*
* We set the counter to 0xFFFFFFFF and encrypt 65 bytes in a single call,
* which requires two 64-byte key-stream blocks. We then re-encrypt the same
* data as two separate calls - 64 bytes at counter=0xFFFFFFFF and 1 byte at
* counter=0x00000000 - and confirm the outputs match.
*/
int test_wc_Chacha_CounterOverflow(void)
{
EXPECT_DECLS;
#ifdef HAVE_CHACHA
ChaCha enc;
static const byte key[CHACHA_MAX_KEY_SZ] = {
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
};
static const byte nonce[CHACHA_IV_BYTES] = {
0x00,0x00,0x00,0x09, 0x00,0x00,0x00,0x4a, 0x00,0x00,0x00,0x00
};
/* 65 bytes of zeroed plaintext - easy to verify, no KAT needed. */
static const byte plain[65] = { 0 };
/* combined: single call spanning the 0xFFFFFFFF->0x00000000 boundary */
byte cipher_combined[65];
/* per-block: block at counter=0xFFFFFFFF (64 bytes) */
byte cipher_b0[64];
/* per-block: first byte of block at counter=0x00000000 (1 byte) */
byte cipher_b1[1];
XMEMSET(&enc, 0, sizeof(enc));
/* Encrypt 65 bytes in one shot, starting at counter 0xFFFFFFFF. */
ExpectIntEQ(wc_Chacha_SetKey(&enc, key, sizeof(key)), 0);
ExpectIntEQ(wc_Chacha_SetIV(&enc, nonce, 0xFFFFFFFFUL), 0);
ExpectIntEQ(wc_Chacha_Process(&enc, cipher_combined, plain, 65), 0);
/* First 64 bytes: key-stream block at counter 0xFFFFFFFF. */
ExpectIntEQ(wc_Chacha_SetKey(&enc, key, sizeof(key)), 0);
ExpectIntEQ(wc_Chacha_SetIV(&enc, nonce, 0xFFFFFFFFUL), 0);
ExpectIntEQ(wc_Chacha_Process(&enc, cipher_b0, plain, 64), 0);
/* Byte 65: first byte of key-stream block at counter 0x00000000. */
ExpectIntEQ(wc_Chacha_SetKey(&enc, key, sizeof(key)), 0);
ExpectIntEQ(wc_Chacha_SetIV(&enc, nonce, 0x00000000UL), 0);
ExpectIntEQ(wc_Chacha_Process(&enc, cipher_b1, plain + 64, 1), 0);
/* Combined output must match per-block results. */
ExpectBufEQ(cipher_combined, cipher_b0, 64);
ExpectBufEQ(cipher_combined + 64, cipher_b1, 1);
#endif
return EXPECT_RESULT();
}
/*
* Verify that wc_Chacha_Process works correctly when the output buffer is the
* same as the input buffer (in-place operation). ChaCha20 XORs the keystream
* onto the input byte-by-byte, so in == out is always safe.
*/
int test_wc_Chacha_InPlace(void)
{
EXPECT_DECLS;
#ifdef HAVE_CHACHA
ChaCha enc;
static const byte key[CHACHA_MAX_KEY_SZ] = {
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x01
};
static const byte nonce[CHACHA_IV_BYTES] = {
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x02
};
/* 67 bytes: spans one full block (64) plus a partial block tail */
static const byte plain[67] = {
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00
};
byte ref_ct[sizeof(plain)];
byte buf[sizeof(plain)];
XMEMSET(&enc, 0, sizeof(enc));
/* Reference ciphertext with separate in/out buffers */
ExpectIntEQ(wc_Chacha_SetKey(&enc, key, sizeof(key)), 0);
ExpectIntEQ(wc_Chacha_SetIV(&enc, nonce, 1), 0);
ExpectIntEQ(wc_Chacha_Process(&enc, ref_ct, plain, sizeof(plain)), 0);
/* Encrypt in-place (out == in) - must produce the same ciphertext */
XMEMCPY(buf, plain, sizeof(buf));
ExpectIntEQ(wc_Chacha_SetKey(&enc, key, sizeof(key)), 0);
ExpectIntEQ(wc_Chacha_SetIV(&enc, nonce, 1), 0);
ExpectIntEQ(wc_Chacha_Process(&enc, buf, buf, sizeof(buf)), 0);
ExpectBufEQ(buf, ref_ct, sizeof(buf));
/* Decrypt in-place (ChaCha20 is symmetric - apply keystream again) */
ExpectIntEQ(wc_Chacha_SetKey(&enc, key, sizeof(key)), 0);
ExpectIntEQ(wc_Chacha_SetIV(&enc, nonce, 1), 0);
ExpectIntEQ(wc_Chacha_Process(&enc, buf, buf, sizeof(buf)), 0);
ExpectBufEQ(buf, plain, sizeof(buf));
#endif
return EXPECT_RESULT();
} /* END test_wc_Chacha_InPlace */
/*
* Verify that wc_Chacha_Process produces correct results when both the input
* and output buffers are byte-offset (unaligned). Tests offsets 1, 2, and 3.
* A 67-byte plaintext is used (same as InPlace) to exercise both full-block
* and partial-block tail paths.
*/
int test_wc_Chacha_UnalignedBuffers(void)
{
EXPECT_DECLS;
#ifdef HAVE_CHACHA
ChaCha enc;
static const byte key[CHACHA_MAX_KEY_SZ] = {
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x01
};
static const byte nonce[CHACHA_IV_BYTES] = {
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x02
};
static const byte plain[67] = {
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00
};
byte ref_ct[sizeof(plain)];
byte in_buf[sizeof(plain) + 3], out_buf[sizeof(plain) + 3];
int off;
XMEMSET(&enc, 0, sizeof(enc));
/* Reference ciphertext with naturally-aligned buffers */
ExpectIntEQ(wc_Chacha_SetKey(&enc, key, sizeof(key)), 0);
ExpectIntEQ(wc_Chacha_SetIV(&enc, nonce, 1), 0);
ExpectIntEQ(wc_Chacha_Process(&enc, ref_ct, plain, sizeof(plain)), 0);
/* Encrypt with byte offsets 1, 2, 3 on both in and out */
for (off = 1; off <= 3 && EXPECT_SUCCESS(); off++) {
XMEMCPY(in_buf + off, plain, sizeof(plain));
XMEMSET(out_buf, 0, sizeof(out_buf));
ExpectIntEQ(wc_Chacha_SetKey(&enc, key, sizeof(key)), 0);
ExpectIntEQ(wc_Chacha_SetIV(&enc, nonce, 1), 0);
ExpectIntEQ(wc_Chacha_Process(&enc, out_buf + off, in_buf + off,
sizeof(plain)), 0);
ExpectBufEQ(out_buf + off, ref_ct, sizeof(plain));
}
/* Decrypt (ChaCha20 is symmetric) */
for (off = 1; off <= 3 && EXPECT_SUCCESS(); off++) {
XMEMCPY(in_buf + off, ref_ct, sizeof(plain));
XMEMSET(out_buf, 0, sizeof(out_buf));
ExpectIntEQ(wc_Chacha_SetKey(&enc, key, sizeof(key)), 0);
ExpectIntEQ(wc_Chacha_SetIV(&enc, nonce, 1), 0);
ExpectIntEQ(wc_Chacha_Process(&enc, out_buf + off, in_buf + off,
sizeof(plain)), 0);
ExpectBufEQ(out_buf + off, plain, sizeof(plain));
}
#endif
return EXPECT_RESULT();
} /* END test_wc_Chacha_UnalignedBuffers */
+11 -5
View File
@@ -28,11 +28,17 @@ int test_wc_Chacha_SetKey(void);
int test_wc_Chacha_Process(void);
int test_wc_Chacha_Process_Chunking(void);
int test_wc_Chacha_MonteCarlo(void);
int test_wc_Chacha_CounterOverflow(void);
int test_wc_Chacha_InPlace(void);
int test_wc_Chacha_UnalignedBuffers(void);
#define TEST_CHACHA_DECLS \
TEST_DECL_GROUP("chacha", test_wc_Chacha_SetKey), \
TEST_DECL_GROUP("chacha", test_wc_Chacha_Process), \
TEST_DECL_GROUP("chacha", test_wc_Chacha_Process_Chunking), \
TEST_DECL_GROUP("chacha", test_wc_Chacha_MonteCarlo)
#define TEST_CHACHA_DECLS \
TEST_DECL_GROUP("chacha", test_wc_Chacha_SetKey), \
TEST_DECL_GROUP("chacha", test_wc_Chacha_Process), \
TEST_DECL_GROUP("chacha", test_wc_Chacha_Process_Chunking), \
TEST_DECL_GROUP("chacha", test_wc_Chacha_MonteCarlo), \
TEST_DECL_GROUP("chacha", test_wc_Chacha_CounterOverflow), \
TEST_DECL_GROUP("chacha", test_wc_Chacha_InPlace), \
TEST_DECL_GROUP("chacha", test_wc_Chacha_UnalignedBuffers)
#endif /* WOLFCRYPT_TEST_CHACHA_H */
+606
View File
@@ -340,3 +340,609 @@ int test_wc_ChaCha20Poly1305_MonteCarlo(void)
#endif
return EXPECT_RESULT();
}
/*
* Testing wc_ChaCha20Poly1305_Init(), wc_ChaCha20Poly1305_UpdateAad(),
* wc_ChaCha20Poly1305_UpdateData(), and wc_ChaCha20Poly1305_Final()
* streaming API using the RFC 8439 Section 2.8.2 test vector.
*/
int test_wc_ChaCha20Poly1305_Stream(void)
{
EXPECT_DECLS;
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
/* RFC 8439 Section 2.8.2 test vector */
static const byte key[] = {
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
};
static const byte iv[] = {
0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43,
0x44, 0x45, 0x46, 0x47
};
static const byte aad[] = {
0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
0xc4, 0xc5, 0xc6, 0xc7
};
static const byte plaintext[] = {
0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
0x74, 0x2e
};
static const byte expCipher[] = {
0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb,
0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12,
0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29,
0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36,
0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58,
0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94,
0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,
0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b,
0x61, 0x16
};
static const byte expAuthTag[] = {
0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a,
0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91
};
ChaChaPoly_Aead aead;
byte outCipher[sizeof(plaintext)];
byte outPlain[sizeof(plaintext)];
byte outTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
/* --- Streaming encrypt: AAD in two chunks, plaintext in three chunks --- */
ExpectIntEQ(wc_ChaCha20Poly1305_Init(&aead, key, iv,
CHACHA20_POLY1305_AEAD_ENCRYPT), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateAad(&aead, aad, 6), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateAad(&aead, aad + 6,
(word32)(sizeof(aad) - 6)), 0);
XMEMSET(outCipher, 0, sizeof(outCipher));
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateData(&aead, plaintext,
outCipher, 38), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateData(&aead, plaintext + 38,
outCipher + 38, 38), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateData(&aead, plaintext + 76,
outCipher + 76, (word32)(sizeof(plaintext) - 76)), 0);
XMEMSET(outTag, 0, sizeof(outTag));
ExpectIntEQ(wc_ChaCha20Poly1305_Final(&aead, outTag), 0);
ExpectBufEQ(outCipher, expCipher, sizeof(expCipher));
ExpectBufEQ(outTag, expAuthTag, sizeof(expAuthTag));
/* --- Streaming decrypt: single AAD chunk, ciphertext in three chunks --- */
ExpectIntEQ(wc_ChaCha20Poly1305_Init(&aead, key, iv,
CHACHA20_POLY1305_AEAD_DECRYPT), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateAad(&aead, aad,
(word32)sizeof(aad)), 0);
XMEMSET(outPlain, 0, sizeof(outPlain));
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateData(&aead, expCipher,
outPlain, 38), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateData(&aead, expCipher + 38,
outPlain + 38, 38), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateData(&aead, expCipher + 76,
outPlain + 76, (word32)(sizeof(expCipher) - 76)), 0);
XMEMSET(outTag, 0, sizeof(outTag));
ExpectIntEQ(wc_ChaCha20Poly1305_Final(&aead, outTag), 0);
ExpectBufEQ(outPlain, plaintext, sizeof(plaintext));
ExpectIntEQ(wc_ChaCha20Poly1305_CheckTag(outTag, expAuthTag), 0);
/* --- Bad args --- */
/* wc_ChaCha20Poly1305_Init: NULL aead */
ExpectIntEQ(wc_ChaCha20Poly1305_Init(NULL, key, iv,
CHACHA20_POLY1305_AEAD_ENCRYPT),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* wc_ChaCha20Poly1305_Init: NULL key */
ExpectIntEQ(wc_ChaCha20Poly1305_Init(&aead, NULL, iv,
CHACHA20_POLY1305_AEAD_ENCRYPT),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* wc_ChaCha20Poly1305_Init: NULL iv */
ExpectIntEQ(wc_ChaCha20Poly1305_Init(&aead, key, NULL,
CHACHA20_POLY1305_AEAD_ENCRYPT),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* wc_ChaCha20Poly1305_UpdateAad: NULL aead */
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateAad(NULL, aad, (word32)sizeof(aad)),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* wc_ChaCha20Poly1305_UpdateData: NULL aead */
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateData(NULL, plaintext, outCipher,
(word32)sizeof(plaintext)),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* wc_ChaCha20Poly1305_Final: NULL aead */
ExpectIntEQ(wc_ChaCha20Poly1305_Final(NULL, outTag),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* wc_ChaCha20Poly1305_Final: wrong state (INIT, not AAD/DATA) */
ExpectIntEQ(wc_ChaCha20Poly1305_Init(&aead, key, iv,
CHACHA20_POLY1305_AEAD_ENCRYPT), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_Final(&aead, outTag),
WC_NO_ERR_TRACE(BAD_STATE_E));
#endif
return EXPECT_RESULT();
} /* END test_wc_ChaCha20Poly1305_Stream */
/*
* ChaCha20-Poly1305 AEAD edge cases:
* - invalid auth tag rejection (one-shot API)
* - empty plaintext with non-empty AAD (streaming API)
*/
int test_wc_ChaCha20Poly1305_AeadEdgeCases(void)
{
EXPECT_DECLS;
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
/* RFC 8439 Section 2.8.2 key/iv/aad */
static const byte key[] = {
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
};
static const byte iv[] = {
0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43,
0x44, 0x45, 0x46, 0x47
};
static const byte aad[] = {
0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
0xc4, 0xc5, 0xc6, 0xc7
};
static const byte plaintext[] = {
0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
0x74, 0x2e
};
ChaChaPoly_Aead aead;
byte cipherOut[sizeof(plaintext)];
byte plainOut[sizeof(plaintext)];
byte authTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
byte authTagDecrypt[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
/* --- Invalid tag rejection (one-shot API) ---
* Encrypt with correct key/iv/aad/pt, then flip a tag byte and
* verify that Decrypt returns MAC_CMP_FAILED_E. */
XMEMSET(cipherOut, 0, sizeof(cipherOut));
XMEMSET(authTag, 0, sizeof(authTag));
ExpectIntEQ(wc_ChaCha20Poly1305_Encrypt(key, iv, aad, sizeof(aad),
plaintext, sizeof(plaintext), cipherOut, authTag), 0);
authTag[0] ^= 0xff;
XMEMSET(plainOut, 0, sizeof(plainOut));
ExpectIntEQ(wc_ChaCha20Poly1305_Decrypt(key, iv, aad, sizeof(aad),
cipherOut, sizeof(cipherOut), authTag, plainOut),
WC_NO_ERR_TRACE(MAC_CMP_FAILED_E));
/* --- Empty plaintext with non-empty AAD (streaming API) ---
* Init + UpdateAad + Final, no UpdateData call.
* Correct computed tag must verify; tampered tag must fail. */
XMEMSET(authTag, 0, sizeof(authTag));
XMEMSET(authTagDecrypt, 0, sizeof(authTagDecrypt));
ExpectIntEQ(wc_ChaCha20Poly1305_Init(&aead, key, iv,
CHACHA20_POLY1305_AEAD_ENCRYPT), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateAad(&aead, aad, sizeof(aad)), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_Final(&aead, authTag), 0);
/* Decrypt with same AAD and no data; verify tag matches */
ExpectIntEQ(wc_ChaCha20Poly1305_Init(&aead, key, iv,
CHACHA20_POLY1305_AEAD_DECRYPT), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateAad(&aead, aad, sizeof(aad)), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_Final(&aead, authTagDecrypt), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_CheckTag(authTagDecrypt, authTag), 0);
/* Tamper and verify CheckTag rejects it */
authTagDecrypt[0] ^= 0xff;
ExpectIntEQ(wc_ChaCha20Poly1305_CheckTag(authTagDecrypt, authTag),
WC_NO_ERR_TRACE(MAC_CMP_FAILED_E));
#endif
return EXPECT_RESULT();
} /* END test_wc_ChaCha20Poly1305_AeadEdgeCases */
/*******************************************************************************
* ChaCha20-Poly1305 mid-stream state corruption
******************************************************************************/
/*
* Verify that the ChaCha20-Poly1305 streaming state machine rejects operations
* called in the wrong order, and handles post-Final reuse gracefully.
*
* State transitions: INIT(0) -> READY(1) -> AAD(2) -> DATA(3)
* UpdateAad: READY or AAD only
* UpdateData: READY, AAD, or DATA
* Final: AAD or DATA only
* After Final, ForceZero resets the struct to all-zeros (state == INIT).
*/
int test_wc_ChaCha20Poly1305_MidStreamState(void)
{
EXPECT_DECLS;
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
static const byte key[CHACHA20_POLY1305_AEAD_KEYSIZE] = {
0x80,0x81,0x82,0x83, 0x84,0x85,0x86,0x87,
0x88,0x89,0x8a,0x8b, 0x8c,0x8d,0x8e,0x8f,
0x90,0x91,0x92,0x93, 0x94,0x95,0x96,0x97,
0x98,0x99,0x9a,0x9b, 0x9c,0x9d,0x9e,0x9f
};
static const byte iv[CHACHA20_POLY1305_AEAD_IV_SIZE] = {
0x07,0x00,0x00,0x00, 0x40,0x41,0x42,0x43, 0x44,0x45,0x46,0x47
};
static const byte aad[8] = { 0x50,0x51,0x52,0x53, 0xc0,0xc1,0xc2,0xc3 };
static const byte plain[8] = { 0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07 };
ChaChaPoly_Aead aead;
byte ct[8];
byte tag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
/* ------------------------------------------------------------------
* Test 1: UpdateAad after UpdateData (DATA state) -> BAD_STATE_E
* Once UpdateData has been called the state advances to DATA and any
* further UpdateAad calls must be rejected.
* ------------------------------------------------------------------ */
ExpectIntEQ(wc_ChaCha20Poly1305_Init(&aead, key, iv,
CHACHA20_POLY1305_AEAD_ENCRYPT), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateAad(&aead, aad, sizeof(aad)), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateData(&aead, plain, ct,
sizeof(plain)), 0);
/* State is now DATA - UpdateAad must fail. */
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateAad(&aead, aad, sizeof(aad)),
WC_NO_ERR_TRACE(BAD_STATE_E));
/* Clean up the aead object so the next test starts fresh. */
XMEMSET(&aead, 0, sizeof(aead));
/* ------------------------------------------------------------------
* Test 2: UpdateData in INIT state (no Init called) -> BAD_STATE_E
* state == INIT(0): UpdateData requires READY(1), AAD(2), or DATA(3).
* ------------------------------------------------------------------ */
/* aead was zeroed above so state == INIT. */
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateData(&aead, plain, ct, sizeof(plain)),
WC_NO_ERR_TRACE(BAD_STATE_E));
/* ------------------------------------------------------------------
* Test 3: Reuse after Final - state reset to INIT by ForceZero
* wc_ChaCha20Poly1305_Final calls ForceZero on the whole struct, which
* sets state back to INIT(0). Any subsequent streaming call must fail.
* ------------------------------------------------------------------ */
ExpectIntEQ(wc_ChaCha20Poly1305_Init(&aead, key, iv,
CHACHA20_POLY1305_AEAD_ENCRYPT), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateAad(&aead, aad, sizeof(aad)), 0);
/* First Final succeeds (state == AAD). */
ExpectIntEQ(wc_ChaCha20Poly1305_Final(&aead, tag), 0);
/* State is now INIT (all zeros after ForceZero). */
/* Second Final must fail. */
ExpectIntEQ(wc_ChaCha20Poly1305_Final(&aead, tag),
WC_NO_ERR_TRACE(BAD_STATE_E));
/* UpdateAad after Final must also fail. */
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateAad(&aead, aad, sizeof(aad)),
WC_NO_ERR_TRACE(BAD_STATE_E));
/* UpdateData after Final must also fail. */
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateData(&aead, plain, ct, sizeof(plain)),
WC_NO_ERR_TRACE(BAD_STATE_E));
/* ------------------------------------------------------------------
* Test 4: Direct state field corruption to an invalid value
* Forcing state to a value outside the defined enum range makes all
* state-checking calls return BAD_STATE_E.
* ------------------------------------------------------------------ */
ExpectIntEQ(wc_ChaCha20Poly1305_Init(&aead, key, iv,
CHACHA20_POLY1305_AEAD_ENCRYPT), 0);
/* Corrupt state: 99 is not a valid CHACHA20_POLY1305_STATE_* value. */
aead.state = 99;
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateAad(&aead, aad, sizeof(aad)),
WC_NO_ERR_TRACE(BAD_STATE_E));
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateData(&aead, plain, ct, sizeof(plain)),
WC_NO_ERR_TRACE(BAD_STATE_E));
ExpectIntEQ(wc_ChaCha20Poly1305_Final(&aead, tag),
WC_NO_ERR_TRACE(BAD_STATE_E));
#endif
return EXPECT_RESULT();
} /* END test_wc_ChaCha20Poly1305_MidStreamState */
/*******************************************************************************
* ChaCha20-Poly1305 re-initialization after Final
******************************************************************************/
/*
* Verify that a ChaCha20-Poly1305 AEAD context can be re-initialized and
* reused after wc_ChaCha20Poly1305_Final has been called.
*
* wc_ChaCha20Poly1305_Final calls ForceZero on the whole ChaChaPoly_Aead
* struct, so a fresh wc_ChaCha20Poly1305_Init is needed before the next
* session. These tests confirm:
*
* 1. Re-init with the same key and IV produces identical ciphertext and tag.
* 2. Re-init with a different IV produces different ciphertext and tag.
* 3. Re-init after an *abandoned* session (Init but no Final) also works.
*/
int test_wc_ChaCha20Poly1305_ReinitAfterFinal(void)
{
EXPECT_DECLS;
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
static const byte key[CHACHA20_POLY1305_AEAD_KEYSIZE] = {
0x80,0x81,0x82,0x83, 0x84,0x85,0x86,0x87,
0x88,0x89,0x8a,0x8b, 0x8c,0x8d,0x8e,0x8f,
0x90,0x91,0x92,0x93, 0x94,0x95,0x96,0x97,
0x98,0x99,0x9a,0x9b, 0x9c,0x9d,0x9e,0x9f
};
static const byte iv1[CHACHA20_POLY1305_AEAD_IV_SIZE] = {
0x07,0x00,0x00,0x00, 0x40,0x41,0x42,0x43, 0x44,0x45,0x46,0x47
};
/* Distinct IV - same length, one byte different. */
static const byte iv2[CHACHA20_POLY1305_AEAD_IV_SIZE] = {
0x07,0x00,0x00,0x00, 0x40,0x41,0x42,0x43, 0x44,0x45,0x46,0x48
};
static const byte aad[] = {
0x50,0x51,0x52,0x53, 0xc0,0xc1,0xc2,0xc3,
0xc4,0xc5,0xc6,0xc7
};
static const byte plain[] = {
0x4c,0x61,0x64,0x69, 0x65,0x73,0x20,0x61,
0x6e,0x64,0x20,0x47, 0x65,0x6e,0x74,0x6c
};
ChaChaPoly_Aead aead;
byte ct1[sizeof(plain)];
byte ct2[sizeof(plain)];
byte ct3[sizeof(plain)];
byte tag1[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
byte tag2[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
byte tag3[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
/* ---- Session 1: establish baseline ciphertext and tag ---- */
ExpectIntEQ(wc_ChaCha20Poly1305_Init(&aead, key, iv1,
CHACHA20_POLY1305_AEAD_ENCRYPT), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateAad(&aead, aad, sizeof(aad)), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateData(&aead, plain, ct1,
sizeof(plain)), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_Final(&aead, tag1), 0);
/* ---- Session 2: re-init with the same key and IV ---- */
/* aead was ForceZero'd by Final; Init must succeed. */
ExpectIntEQ(wc_ChaCha20Poly1305_Init(&aead, key, iv1,
CHACHA20_POLY1305_AEAD_ENCRYPT), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateAad(&aead, aad, sizeof(aad)), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateData(&aead, plain, ct2,
sizeof(plain)), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_Final(&aead, tag2), 0);
/* Same key + IV must produce identical output. */
ExpectBufEQ(ct2, ct1, sizeof(ct1));
ExpectBufEQ(tag2, tag1, sizeof(tag1));
/* ---- Session 3: re-init with a different IV ---- */
ExpectIntEQ(wc_ChaCha20Poly1305_Init(&aead, key, iv2,
CHACHA20_POLY1305_AEAD_ENCRYPT), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateAad(&aead, aad, sizeof(aad)), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateData(&aead, plain, ct3,
sizeof(plain)), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_Final(&aead, tag3), 0);
/* Different IV must produce different ciphertext and tag. */
ExpectIntNE(XMEMCMP(ct3, ct1, sizeof(ct1)), 0);
ExpectIntNE(XMEMCMP(tag3, tag1, sizeof(tag1)), 0);
/* ---- Session 4: re-init after an abandoned session ----
* Start a session (Init + UpdateAad) but never call Final.
* Then re-init and complete normally - must match session 1. */
ExpectIntEQ(wc_ChaCha20Poly1305_Init(&aead, key, iv2,
CHACHA20_POLY1305_AEAD_ENCRYPT), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateAad(&aead, aad, sizeof(aad)), 0);
/* Abandon this session - manually reset before re-init. */
XMEMSET(&aead, 0, sizeof(aead));
/* Now re-init with iv1 and verify we get session-1 output again. */
ExpectIntEQ(wc_ChaCha20Poly1305_Init(&aead, key, iv1,
CHACHA20_POLY1305_AEAD_ENCRYPT), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateAad(&aead, aad, sizeof(aad)), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_UpdateData(&aead, plain, ct2,
sizeof(plain)), 0);
ExpectIntEQ(wc_ChaCha20Poly1305_Final(&aead, tag2), 0);
ExpectBufEQ(ct2, ct1, sizeof(ct1));
ExpectBufEQ(tag2, tag1, sizeof(tag1));
#endif
return EXPECT_RESULT();
} /* END test_wc_ChaCha20Poly1305_ReinitAfterFinal */
/*
* Verify that wc_ChaCha20Poly1305_Encrypt and wc_ChaCha20Poly1305_Decrypt work
* correctly when the plaintext/ciphertext pointer is the same buffer (in-place
* operation). The cipher uses a ChaCha20 keystream XOR, so in == out is safe.
* The Poly1305 tag is always a separate output buffer.
*
* RFC 8439 2.8.2 key, IV, and AAD are used with a 64-byte counter-pattern
* plaintext (self-consistency: reference ciphertext computed at test time).
*/
int test_wc_ChaCha20Poly1305_InPlace(void)
{
EXPECT_DECLS;
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
static const byte key[CHACHA20_POLY1305_AEAD_KEYSIZE] = {
0x80,0x81,0x82,0x83, 0x84,0x85,0x86,0x87,
0x88,0x89,0x8a,0x8b, 0x8c,0x8d,0x8e,0x8f,
0x90,0x91,0x92,0x93, 0x94,0x95,0x96,0x97,
0x98,0x99,0x9a,0x9b, 0x9c,0x9d,0x9e,0x9f
};
static const byte iv[CHACHA20_POLY1305_AEAD_IV_SIZE] = {
0x07,0x00,0x00,0x00, 0x40,0x41,0x42,0x43, 0x44,0x45,0x46,0x47
};
static const byte aad[12] = {
0x50,0x51,0x52,0x53, 0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7
};
/* 67-byte counter pattern: spans one full ChaCha20 block (64 B) plus
* a 3-byte partial tail, exercising both full-block and leftover paths. */
static const byte plain[67] = {
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,
0x20,0x21,0x22,0x23, 0x24,0x25,0x26,0x27,
0x28,0x29,0x2a,0x2b, 0x2c,0x2d,0x2e,0x2f,
0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
0x38,0x39,0x3a,0x3b, 0x3c,0x3d,0x3e,0x3f,
0x40,0x41,0x42
};
byte ref_ct[sizeof(plain)], ref_tag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
byte buf[sizeof(plain)], tag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
/* Reference ciphertext with separate in/out buffers */
ExpectIntEQ(wc_ChaCha20Poly1305_Encrypt(key, iv,
aad, sizeof(aad), plain, sizeof(plain), ref_ct, ref_tag), 0);
/* Encrypt in-place (outCiphertext == inPlaintext) */
XMEMCPY(buf, plain, sizeof(buf));
XMEMSET(tag, 0, sizeof(tag));
ExpectIntEQ(wc_ChaCha20Poly1305_Encrypt(key, iv,
aad, sizeof(aad), buf, sizeof(buf), buf, tag), 0);
ExpectBufEQ(buf, ref_ct, sizeof(buf));
ExpectBufEQ(tag, ref_tag, sizeof(tag));
/* Decrypt in-place (outPlaintext == inCiphertext) */
ExpectIntEQ(wc_ChaCha20Poly1305_Decrypt(key, iv,
aad, sizeof(aad), buf, sizeof(buf), tag, buf), 0);
ExpectBufEQ(buf, plain, sizeof(buf));
#endif
return EXPECT_RESULT();
} /* END test_wc_ChaCha20Poly1305_InPlace */
/*
* Verify that wc_ChaCha20Poly1305_Encrypt and wc_ChaCha20Poly1305_Decrypt
* produce correct results when plaintext, ciphertext, and AAD buffers are
* byte-offset (unaligned). Tests offsets 1, 2, and 3.
*/
int test_wc_ChaCha20Poly1305_UnalignedBuffers(void)
{
EXPECT_DECLS;
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
/* Same key / IV / AAD as InPlace test */
static const byte key[CHACHA20_POLY1305_AEAD_KEYSIZE] = {
0x80,0x81,0x82,0x83, 0x84,0x85,0x86,0x87,
0x88,0x89,0x8a,0x8b, 0x8c,0x8d,0x8e,0x8f,
0x90,0x91,0x92,0x93, 0x94,0x95,0x96,0x97,
0x98,0x99,0x9a,0x9b, 0x9c,0x9d,0x9e,0x9f
};
static const byte iv[CHACHA20_POLY1305_AEAD_IV_SIZE] = {
0x07,0x00,0x00,0x00, 0x40,0x41,0x42,0x43, 0x44,0x45,0x46,0x47
};
static const byte aad[12] = {
0x50,0x51,0x52,0x53, 0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7
};
/* 67-byte counter pattern - same as InPlace test */
static const byte plain[67] = {
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,
0x20,0x21,0x22,0x23, 0x24,0x25,0x26,0x27,
0x28,0x29,0x2a,0x2b, 0x2c,0x2d,0x2e,0x2f,
0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
0x38,0x39,0x3a,0x3b, 0x3c,0x3d,0x3e,0x3f,
0x40,0x41,0x42
};
byte ref_ct[sizeof(plain)], ref_tag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
byte in_buf[sizeof(plain) + 3], out_buf[sizeof(plain) + 3];
byte aad_buf[sizeof(aad) + 3];
byte tag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
int off;
/* Reference ciphertext/tag with naturally-aligned buffers */
ExpectIntEQ(wc_ChaCha20Poly1305_Encrypt(key, iv,
aad, sizeof(aad), plain, sizeof(plain), ref_ct, ref_tag), 0);
/* Encrypt with byte offsets 1, 2, 3 on plaintext, ciphertext, and AAD */
for (off = 1; off <= 3 && EXPECT_SUCCESS(); off++) {
XMEMCPY(in_buf + off, plain, sizeof(plain));
XMEMCPY(aad_buf + off, aad, sizeof(aad));
XMEMSET(out_buf, 0, sizeof(out_buf));
XMEMSET(tag, 0, sizeof(tag));
ExpectIntEQ(wc_ChaCha20Poly1305_Encrypt(key, iv,
aad_buf + off, sizeof(aad), in_buf + off, sizeof(plain),
out_buf + off, tag), 0);
ExpectBufEQ(out_buf + off, ref_ct, sizeof(plain));
ExpectBufEQ(tag, ref_tag, sizeof(tag));
}
/* Decrypt with byte offsets 1, 2, 3 */
for (off = 1; off <= 3 && EXPECT_SUCCESS(); off++) {
XMEMCPY(in_buf + off, ref_ct, sizeof(plain));
XMEMCPY(aad_buf + off, aad, sizeof(aad));
XMEMSET(out_buf, 0, sizeof(out_buf));
ExpectIntEQ(wc_ChaCha20Poly1305_Decrypt(key, iv,
aad_buf + off, sizeof(aad), in_buf + off, sizeof(plain),
ref_tag, out_buf + off), 0);
ExpectBufEQ(out_buf + off, plain, sizeof(plain));
}
#endif
return EXPECT_RESULT();
} /* END test_wc_ChaCha20Poly1305_UnalignedBuffers */
/*
* Cross-cipher test: ChaCha20-Poly1305 encrypts plaintext using ChaCha20 with
* the block counter starting at 1. Counter 0 is reserved for generating the
* 32-byte Poly1305 one-time key; plaintext encryption begins at counter 1.
*
* This test verifies that the ciphertext produced by
* wc_ChaCha20Poly1305_Encrypt equals the output of wc_Chacha_Process when
* the counter is initialised to 1 via wc_Chacha_SetIV(ctx, iv, 1).
*/
int test_wc_ChaCha20Poly1305_CrossCipher(void)
{
EXPECT_DECLS;
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
ChaCha ctx;
/* Same key / IV / plain as the InPlace and UnalignedBuffers tests */
static const byte key[CHACHA20_POLY1305_AEAD_KEYSIZE] = {
0x80,0x81,0x82,0x83, 0x84,0x85,0x86,0x87,
0x88,0x89,0x8a,0x8b, 0x8c,0x8d,0x8e,0x8f,
0x90,0x91,0x92,0x93, 0x94,0x95,0x96,0x97,
0x98,0x99,0x9a,0x9b, 0x9c,0x9d,0x9e,0x9f
};
static const byte iv[CHACHA20_POLY1305_AEAD_IV_SIZE] = {
0x07,0x00,0x00,0x00, 0x40,0x41,0x42,0x43, 0x44,0x45,0x46,0x47
};
static const byte aad[12] = {
0x50,0x51,0x52,0x53, 0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7
};
static const byte plain[67] = {
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,
0x20,0x21,0x22,0x23, 0x24,0x25,0x26,0x27,
0x28,0x29,0x2a,0x2b, 0x2c,0x2d,0x2e,0x2f,
0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
0x38,0x39,0x3a,0x3b, 0x3c,0x3d,0x3e,0x3f,
0x40,0x41,0x42
};
byte aead_ct[sizeof(plain)], aead_tag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
byte chacha_ct[sizeof(plain)];
/* ChaCha20-Poly1305 ciphertext */
ExpectIntEQ(wc_ChaCha20Poly1305_Encrypt(key, iv,
aad, sizeof(aad), plain, sizeof(plain), aead_ct, aead_tag), 0);
/* ChaCha20 ciphertext with counter=1 (counter 0 is the Poly1305 key block) */
ExpectIntEQ(wc_Chacha_SetKey(&ctx, key, sizeof(key)), 0);
ExpectIntEQ(wc_Chacha_SetIV(&ctx, iv, 1), 0);
ExpectIntEQ(wc_Chacha_Process(&ctx, chacha_ct, plain, sizeof(plain)), 0);
/* ChaCha20-Poly1305 ciphertext must equal ChaCha20(counter=1) ciphertext */
ExpectBufEQ(aead_ct, chacha_ct, sizeof(plain));
#endif
return EXPECT_RESULT();
} /* END test_wc_ChaCha20Poly1305_CrossCipher */
+18 -4
View File
@@ -27,10 +27,24 @@
int test_wc_ChaCha20Poly1305_aead(void);
int test_wc_XChaCha20Poly1305_aead(void);
int test_wc_ChaCha20Poly1305_MonteCarlo(void);
int test_wc_ChaCha20Poly1305_Stream(void);
int test_wc_ChaCha20Poly1305_AeadEdgeCases(void);
int test_wc_ChaCha20Poly1305_MidStreamState(void);
int test_wc_ChaCha20Poly1305_ReinitAfterFinal(void);
int test_wc_ChaCha20Poly1305_InPlace(void);
int test_wc_ChaCha20Poly1305_UnalignedBuffers(void);
int test_wc_ChaCha20Poly1305_CrossCipher(void);
#define TEST_CHACHA20_POLY1305_DECLS \
TEST_DECL_GROUP("chacha20-poly1305", test_wc_ChaCha20Poly1305_aead), \
TEST_DECL_GROUP("xchacha20-poly1305", test_wc_XChaCha20Poly1305_aead), \
TEST_DECL_GROUP("chacha20-poly1305", test_wc_ChaCha20Poly1305_MonteCarlo)
#define TEST_CHACHA20_POLY1305_DECLS \
TEST_DECL_GROUP("chacha20-poly1305", test_wc_ChaCha20Poly1305_aead), \
TEST_DECL_GROUP("xchacha20-poly1305", test_wc_XChaCha20Poly1305_aead), \
TEST_DECL_GROUP("chacha20-poly1305", test_wc_ChaCha20Poly1305_MonteCarlo), \
TEST_DECL_GROUP("chacha20-poly1305", test_wc_ChaCha20Poly1305_Stream), \
TEST_DECL_GROUP("chacha20-poly1305", test_wc_ChaCha20Poly1305_AeadEdgeCases), \
TEST_DECL_GROUP("chacha20-poly1305", test_wc_ChaCha20Poly1305_MidStreamState), \
TEST_DECL_GROUP("chacha20-poly1305", test_wc_ChaCha20Poly1305_ReinitAfterFinal), \
TEST_DECL_GROUP("chacha20-poly1305", test_wc_ChaCha20Poly1305_InPlace), \
TEST_DECL_GROUP("chacha20-poly1305", test_wc_ChaCha20Poly1305_UnalignedBuffers), \
TEST_DECL_GROUP("chacha20-poly1305", test_wc_ChaCha20Poly1305_CrossCipher)
#endif /* WOLFCRYPT_TEST_CHACHA20_POLY1305_H */