mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 13:40:49 +02:00
Merge pull request #10226 from SparkiDev/api_test_cipher_algs_3
API tests: more cipher tests
This commit is contained in:
+2302
-7
File diff suppressed because it is too large
Load Diff
+59
-11
@@ -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), \
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user