diff --git a/tests/api.c b/tests/api.c index b941ea01ee..05ad49af07 100644 --- a/tests/api.c +++ b/tests/api.c @@ -286,7 +286,8 @@ #define WOLFSSL_MISC_INCLUDED #include - +/* Gather test declarations to include them in the testCases array */ +#include #if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \ !defined(NO_RSA) && !defined(SINGLE_THREADED) && \ @@ -101723,6 +101724,10 @@ TEST_CASE testCases[] = { TEST_DECL(test_wc_dilithium_sig_kats), TEST_DECL(test_wc_dilithium_verify_kats), + /* Ascon */ + TEST_DECL(test_ascon_hash256), + TEST_DECL(test_ascon_aead128), + /* Signature API */ TEST_DECL(test_wc_SignatureGetSize_ecc), TEST_DECL(test_wc_SignatureGetSize_rsa), diff --git a/wolfcrypt/test/ascon-kat.h b/tests/api/ascon.c similarity index 98% rename from wolfcrypt/test/ascon-kat.h rename to tests/api/ascon.c index 8690b76e81..46adbd18b7 100644 --- a/wolfcrypt/test/ascon-kat.h +++ b/tests/api/ascon.c @@ -1,4 +1,4 @@ -/* ascon-kat.h +/* ascon.c * * Copyright (C) 2006-2025 wolfSSL Inc. * @@ -19,11 +19,28 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ -#ifndef WOLFCRYPT_TEST_ASCON_KAT_H -#define WOLFCRYPT_TEST_ASCON_KAT_H +#ifdef HAVE_CONFIG_H + #include +#endif +#if !defined(WOLFSSL_USER_SETTINGS) && !defined(WOLFSSL_NO_OPTIONS_H) + #include +#endif +#include + +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +#include #include +#include +#include +#ifdef HAVE_ASCON /* KATs taken from https://github.com/ascon/ascon-c */ /* crypto_hash/asconhash256/LWC_HASH_KAT_256.txt @@ -6505,5 +6522,153 @@ static const char *ascon_aead128_kat[][5] = { /* AD = */ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", /* CT = */ "4C086D27A3B51A2333CFC7F22172A9BCAD88B8D4D77E50622D788345FA7BEE4468915D3F9422289F2349D6A3B4160397", }, }; +#endif + +int test_ascon_hash256(void) +{ + EXPECT_DECLS; +#ifdef HAVE_ASCON + byte msg[1024]; + byte mdOut[ASCON_HASH256_SZ]; + const size_t test_rounds = sizeof(msg) + 1; /* +1 to test 0-len msg */ + wc_AsconHash256* asconHash = NULL; + word32 i; + + ExpectIntEQ(XELEM_CNT(ascon_hash256_output), test_rounds); + + /* init msg buffer */ + for (i = 0; i < sizeof(msg); i++) + msg[i] = (byte)i; + + ExpectNotNull(asconHash = wc_AsconHash256_New()); + + for (i = 0; i < test_rounds && EXPECT_SUCCESS(); i++) { + XMEMSET(mdOut, 0, sizeof(mdOut)); + ExpectIntEQ(wc_AsconHash256_Init(asconHash), 0); + ExpectIntEQ(wc_AsconHash256_Update(asconHash, msg, i), 0); + ExpectIntEQ(wc_AsconHash256_Final(asconHash, mdOut), 0); + ExpectBufEQ(mdOut, ascon_hash256_output[i], ASCON_HASH256_SZ); + wc_AsconHash256_Clear(asconHash); + } + + /* Test separated update */ + for (i = 0; i < test_rounds && EXPECT_SUCCESS(); i++) { + word32 half_i = i / 2; + XMEMSET(mdOut, 0, sizeof(mdOut)); + ExpectIntEQ(wc_AsconHash256_Init(asconHash), 0); + ExpectIntEQ(wc_AsconHash256_Update(asconHash, msg, half_i), 0); + ExpectIntEQ(wc_AsconHash256_Update(asconHash, msg + half_i, + i - half_i), 0); + ExpectIntEQ(wc_AsconHash256_Final(asconHash, mdOut), 0); + ExpectBufEQ(mdOut, ascon_hash256_output[i], ASCON_HASH256_SZ); + wc_AsconHash256_Clear(asconHash); + } + + wc_AsconHash256_Free(asconHash); +#endif + return EXPECT_RESULT(); +} + +int test_ascon_aead128(void) +{ + EXPECT_DECLS; +#ifdef HAVE_ASCON + word32 i; + wc_AsconAEAD128* asconAEAD = NULL; + + ExpectNotNull(asconAEAD = wc_AsconAEAD128_New()); + + for (i = 0; i < XELEM_CNT(ascon_aead128_kat); i++) { + byte key[ASCON_AEAD128_KEY_SZ]; + byte nonce[ASCON_AEAD128_NONCE_SZ]; + byte pt[32]; /* longest plaintext we test is 32 bytes */ + word32 ptSz; + byte ad[32]; /* longest AD we test is 32 bytes */ + word32 adSz; + byte ct[48]; /* longest ciphertext we test is 32 bytes + 16 bytes tag */ + word32 ctSz; + word32 j; + byte tag[ASCON_AEAD128_TAG_SZ]; + byte buf[32]; /* longest buffer we test is 32 bytes */ + + XMEMSET(key, 0, sizeof(key)); + XMEMSET(nonce, 0, sizeof(nonce)); + XMEMSET(pt, 0, sizeof(pt)); + XMEMSET(ad, 0, sizeof(ad)); + XMEMSET(ct, 0, sizeof(ct)); + XMEMSET(tag, 0, sizeof(tag)); + + /* Convert HEX strings to byte stream */ + for (j = 0; ascon_aead128_kat[i][0][j] != '\0'; j += 2) { + key[j/2] = HexCharToByte(ascon_aead128_kat[i][0][j]) << 4 | + HexCharToByte(ascon_aead128_kat[i][0][j+1]); + } + for (j = 0; ascon_aead128_kat[i][1][j] != '\0'; j += 2) { + nonce[j/2] = HexCharToByte(ascon_aead128_kat[i][1][j]) << 4 | + HexCharToByte(ascon_aead128_kat[i][1][j+1]); + } + for (j = 0; ascon_aead128_kat[i][2][j] != '\0'; j += 2) { + pt[j/2] = HexCharToByte(ascon_aead128_kat[i][2][j]) << 4 | + HexCharToByte(ascon_aead128_kat[i][2][j+1]); + } + ptSz = j/2; + for (j = 0; ascon_aead128_kat[i][3][j] != '\0'; j += 2) { + ad[j/2] = HexCharToByte(ascon_aead128_kat[i][3][j]) << 4 | + HexCharToByte(ascon_aead128_kat[i][3][j+1]); + } + adSz = j/2; + for (j = 0; ascon_aead128_kat[i][4][j] != '\0'; j += 2) { + ct[j/2] = HexCharToByte(ascon_aead128_kat[i][4][j]) << 4 | + HexCharToByte(ascon_aead128_kat[i][4][j+1]); + } + ctSz = j/2 - ASCON_AEAD128_TAG_SZ; + + for (j = 0; j < 4; j++) { + 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, ad, adSz), 0); + if (j == 0) { + /* Encryption test */ + ExpectIntEQ(wc_AsconAEAD128_EncryptUpdate(asconAEAD, buf, pt, + ptSz), 0); + ExpectBufEQ(buf, ct, ptSz); + ExpectIntEQ(wc_AsconAEAD128_EncryptFinal(asconAEAD, tag), 0); + ExpectBufEQ(tag, ct + ptSz, ASCON_AEAD128_TAG_SZ); + } + else if (j == 1) { + /* Decryption test */ + ExpectIntEQ(wc_AsconAEAD128_DecryptUpdate(asconAEAD, buf, ct, + ctSz), 0); + ExpectBufEQ(buf, pt, ctSz); + ExpectIntEQ(wc_AsconAEAD128_DecryptFinal(asconAEAD, ct + ctSz), + 0); + } + else if (j == 2) { + /* Split encryption test */ + ExpectIntEQ(wc_AsconAEAD128_EncryptUpdate(asconAEAD, buf, pt, + ptSz / 2), 0); + ExpectIntEQ(wc_AsconAEAD128_EncryptUpdate(asconAEAD, + buf + (ptSz/2), pt + (ptSz/2), ptSz - (ptSz/2)), 0); + ExpectBufEQ(buf, ct, ptSz); + ExpectIntEQ(wc_AsconAEAD128_EncryptFinal(asconAEAD, tag), 0); + ExpectBufEQ(tag, ct + ptSz, ASCON_AEAD128_TAG_SZ); + } + else if (j == 3) { + /* Split decryption test */ + ExpectIntEQ(wc_AsconAEAD128_DecryptUpdate(asconAEAD, buf, ct, + ctSz / 2), 0); + ExpectIntEQ(wc_AsconAEAD128_DecryptUpdate(asconAEAD, + buf + (ctSz/2), ct + (ctSz/2), ctSz - (ctSz/2)), 0); + ExpectBufEQ(buf, pt, ctSz); + ExpectIntEQ(wc_AsconAEAD128_DecryptFinal(asconAEAD, ct + ctSz), + 0); + } + wc_AsconAEAD128_Clear(asconAEAD); + } + } -#endif /* WOLFCRYPT_TEST_ASCON_KAT_H */ + wc_AsconAEAD128_Free(asconAEAD); +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/ascon.h b/tests/api/ascon.h new file mode 100644 index 0000000000..09d56c8be4 --- /dev/null +++ b/tests/api/ascon.h @@ -0,0 +1,28 @@ +/* ascon.h + * + * Copyright (C) 2006-2025 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#ifndef WOLFCRYPT_TEST_ASCON_H +#define WOLFCRYPT_TEST_ASCON_H + +int test_ascon_hash256(void); +int test_ascon_aead128(void); + +#endif /* WOLFCRYPT_TEST_ASCON_H */ diff --git a/tests/api/include.am b/tests/api/include.am new file mode 100644 index 0000000000..c0df6b8d19 --- /dev/null +++ b/tests/api/include.am @@ -0,0 +1,4 @@ +if BUILD_TESTS +tests_unit_test_SOURCES += tests/api/ascon.c +endif +EXTRA_DIST += tests/api/ascon.h diff --git a/tests/include.am b/tests/include.am index 5ed4fe40dc..65ba734adf 100644 --- a/tests/include.am +++ b/tests/include.am @@ -18,6 +18,7 @@ tests_unit_test_SOURCES = \ tests_unit_test_CFLAGS = -DNO_MAIN_DRIVER $(AM_CFLAGS) $(WOLFSENTRY_INCLUDE) tests_unit_test_LDADD = src/libwolfssl@LIBSUFFIX@.la $(LIB_STATIC_ADD) $(WOLFSENTRY_LIB) tests_unit_test_DEPENDENCIES = src/libwolfssl@LIBSUFFIX@.la +include tests/api/include.am endif EXTRA_DIST += tests/unit.h \ tests/test.conf \ diff --git a/wolfcrypt/test/include.am b/wolfcrypt/test/include.am index 5179dfb308..4e059dfa62 100644 --- a/wolfcrypt/test/include.am +++ b/wolfcrypt/test/include.am @@ -13,7 +13,6 @@ wolfcrypt_test_testwolfcrypt_SOURCES = wolfcrypt/test/test.c wolfcrypt_test_testwolfcrypt_LDADD = src/libwolfssl@LIBSUFFIX@.la $(LIB_STATIC_ADD) wolfcrypt_test_testwolfcrypt_DEPENDENCIES = src/libwolfssl@LIBSUFFIX@.la noinst_HEADERS += wolfcrypt/test/test.h wolfcrypt/test/test_paths.h.in -noinst_HEADERS += wolfcrypt/test/ascon-kat.h endif endif diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 9bdba6206d..f50905e5b3 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -8807,25 +8807,33 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t chacha20_poly1305_aead_test(void) #endif /* HAVE_CHACHA && HAVE_POLY1305 */ #ifdef HAVE_ASCON -#include WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ascon_hash256_test(void) { WOLFSSL_SMALL_STACK_STATIC byte msg[1024]; byte mdOut[ASCON_HASH256_SZ]; - const size_t test_rounds = sizeof(msg) + 1; /* +1 to test 0-len msg */ + + /* KATs taken from https://github.com/ascon/ascon-c. + * Testing only a subset of KATs here. The rest are tested in + * tests/api/ascon.c. */ + /* crypto_hash/asconhash256/LWC_HASH_KAT_256.txt + * The message is just the byte stream 00 01 02 03 ... */ + WOLFSSL_SMALL_STACK_STATIC const byte hash_output[][32] = { + { 0x0B, 0x3B, 0xE5, 0x85, 0x0F, 0x2F, 0x6B, 0x98, 0xCA, 0xF2, 0x9F, 0x8F, 0xDE, 0xA8, 0x9B, 0x64, 0xA1, 0xFA, 0x70, 0xAA, 0x24, 0x9B, 0x8F, 0x83, 0x9B, 0xD5, 0x3B, 0xAA, 0x30, 0x4D, 0x92, 0xB2 }, + { 0x07, 0x28, 0x62, 0x10, 0x35, 0xAF, 0x3E, 0xD2, 0xBC, 0xA0, 0x3B, 0xF6, 0xFD, 0xE9, 0x00, 0xF9, 0x45, 0x6F, 0x53, 0x30, 0xE4, 0xB5, 0xEE, 0x23, 0xE7, 0xF6, 0xA1, 0xE7, 0x02, 0x91, 0xBC, 0x80 }, + { 0x61, 0x15, 0xE7, 0xC9, 0xC4, 0x08, 0x1C, 0x27, 0x97, 0xFC, 0x8F, 0xE1, 0xBC, 0x57, 0xA8, 0x36, 0xAF, 0xA1, 0xC5, 0x38, 0x1E, 0x55, 0x6D, 0xD5, 0x83, 0x86, 0x0C, 0xA2, 0xDF, 0xB4, 0x8D, 0xD2 }, + { 0x26, 0x5A, 0xB8, 0x9A, 0x60, 0x9F, 0x5A, 0x05, 0xDC, 0xA5, 0x7E, 0x83, 0xFB, 0xBA, 0x70, 0x0F, 0x9A, 0x2D, 0x2C, 0x42, 0x11, 0xBA, 0x4C, 0xC9, 0xF0, 0xA1, 0xA3, 0x69, 0xE1, 0x7B, 0x91, 0x5C }, + { 0xD7, 0xE4, 0xC7, 0xED, 0x9B, 0x8A, 0x32, 0x5C, 0xD0, 0x8B, 0x9E, 0xF2, 0x59, 0xF8, 0x87, 0x70, 0x54, 0xEC, 0xD8, 0x30, 0x4F, 0xE1, 0xB2, 0xD7, 0xFD, 0x84, 0x71, 0x37, 0xDF, 0x67, 0x27, 0xEE }, + }; wc_AsconHash256 asconHash; int err; word32 i; - if (XELEM_CNT(ascon_hash256_output) != test_rounds) - return WC_TEST_RET_ENC_EC(BAD_FUNC_ARG); - /* init msg buffer */ for (i = 0; i < sizeof(msg); i++) msg[i] = (byte)i; - for (i = 0; i < test_rounds; i++) { + for (i = 0; i < XELEM_CNT(hash_output); i++) { XMEMSET(mdOut, 0, sizeof(mdOut)); err = wc_AsconHash256_Init(&asconHash); if (err != 0) @@ -8836,13 +8844,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ascon_hash256_test(void) err = wc_AsconHash256_Final(&asconHash, mdOut); if (err != 0) return WC_TEST_RET_ENC_EC(err); - if (XMEMCMP(mdOut, ascon_hash256_output[i], ASCON_HASH256_SZ) != 0) + if (XMEMCMP(mdOut, hash_output[i], ASCON_HASH256_SZ) != 0) return WC_TEST_RET_ENC_NC; wc_AsconHash256_Clear(&asconHash); } /* Test separated update */ - for (i = 0; i < test_rounds; i++) { + for (i = 0; i < XELEM_CNT(hash_output); i++) { word32 half_i = i / 2; XMEMSET(mdOut, 0, sizeof(mdOut)); err = wc_AsconHash256_Init(&asconHash); @@ -8857,7 +8865,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ascon_hash256_test(void) err = wc_AsconHash256_Final(&asconHash, mdOut); if (err != 0) return WC_TEST_RET_ENC_EC(err); - if (XMEMCMP(mdOut, ascon_hash256_output[i], ASCON_HASH256_SZ) != 0) + if (XMEMCMP(mdOut, hash_output[i], ASCON_HASH256_SZ) != 0) return WC_TEST_RET_ENC_NC; wc_AsconHash256_Clear(&asconHash); } @@ -8871,7 +8879,39 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ascon_aead128_test(void) wc_AsconAEAD128 asconAEAD; int err; - for (i = 0; i < XELEM_CNT(ascon_aead128_kat); i++) { + /* KATs taken from https://github.com/ascon/ascon-c. + * Testing only a subset of KATs here. The rest are tested in + * tests/api/ascon.c. */ + /* crypto_hash/asconaead128/LWC_AEAD_KAT_128_128.txt */ + static const char *aead_kat[][5] = { + { /* Key = */ "000102030405060708090A0B0C0D0E0F", + /* Nonce = */ "000102030405060708090A0B0C0D0E0F", + /* PT = */ "", + /* AD = */ "", + /* CT = */ "4427D64B8E1E1451FC445960F0839BB0", }, + { /* Key = */ "000102030405060708090A0B0C0D0E0F", + /* Nonce = */ "000102030405060708090A0B0C0D0E0F", + /* PT = */ "", + /* AD = */ "00", + /* CT = */ "103AB79D913A0321287715A979BB8585", }, + { /* Key = */ "000102030405060708090A0B0C0D0E0F", + /* Nonce = */ "000102030405060708090A0B0C0D0E0F", + /* PT = */ "", + /* AD = */ "0001", + /* CT = */ "A50E88E30F923B90A9C810181230DF10", }, + { /* Key = */ "000102030405060708090A0B0C0D0E0F", + /* Nonce = */ "000102030405060708090A0B0C0D0E0F", + /* PT = */ "", + /* AD = */ "000102", + /* CT = */ "AE214C9F66630658ED8DC7D31131174C", }, + { /* Key = */ "000102030405060708090A0B0C0D0E0F", + /* Nonce = */ "000102030405060708090A0B0C0D0E0F", + /* PT = */ "", + /* AD = */ "00010203", + /* CT = */ "C6FF3CF70575B144B955820D9BC7685E", }, + }; + + for (i = 0; i < XELEM_CNT(aead_kat); i++) { byte key[ASCON_AEAD128_KEY_SZ]; byte nonce[ASCON_AEAD128_NONCE_SZ]; byte pt[32]; /* longest plaintext we test is 32 bytes */ @@ -8892,27 +8932,27 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ascon_aead128_test(void) XMEMSET(tag, 0, sizeof(tag)); /* Convert HEX strings to byte stream */ - for (j = 0; ascon_aead128_kat[i][0][j] != '\0'; j += 2) { - key[j/2] = HexCharToByte(ascon_aead128_kat[i][0][j]) << 4 | - HexCharToByte(ascon_aead128_kat[i][0][j+1]); + for (j = 0; aead_kat[i][0][j] != '\0'; j += 2) { + key[j/2] = HexCharToByte(aead_kat[i][0][j]) << 4 | + HexCharToByte(aead_kat[i][0][j+1]); } - for (j = 0; ascon_aead128_kat[i][1][j] != '\0'; j += 2) { - nonce[j/2] = HexCharToByte(ascon_aead128_kat[i][1][j]) << 4 | - HexCharToByte(ascon_aead128_kat[i][1][j+1]); + for (j = 0; aead_kat[i][1][j] != '\0'; j += 2) { + nonce[j/2] = HexCharToByte(aead_kat[i][1][j]) << 4 | + HexCharToByte(aead_kat[i][1][j+1]); } - for (j = 0; ascon_aead128_kat[i][2][j] != '\0'; j += 2) { - pt[j/2] = HexCharToByte(ascon_aead128_kat[i][2][j]) << 4 | - HexCharToByte(ascon_aead128_kat[i][2][j+1]); + for (j = 0; aead_kat[i][2][j] != '\0'; j += 2) { + pt[j/2] = HexCharToByte(aead_kat[i][2][j]) << 4 | + HexCharToByte(aead_kat[i][2][j+1]); } ptSz = j/2; - for (j = 0; ascon_aead128_kat[i][3][j] != '\0'; j += 2) { - ad[j/2] = HexCharToByte(ascon_aead128_kat[i][3][j]) << 4 | - HexCharToByte(ascon_aead128_kat[i][3][j+1]); + for (j = 0; aead_kat[i][3][j] != '\0'; j += 2) { + ad[j/2] = HexCharToByte(aead_kat[i][3][j]) << 4 | + HexCharToByte(aead_kat[i][3][j+1]); } adSz = j/2; - for (j = 0; ascon_aead128_kat[i][4][j] != '\0'; j += 2) { - ct[j/2] = HexCharToByte(ascon_aead128_kat[i][4][j]) << 4 | - HexCharToByte(ascon_aead128_kat[i][4][j+1]); + for (j = 0; aead_kat[i][4][j] != '\0'; j += 2) { + ct[j/2] = HexCharToByte(aead_kat[i][4][j]) << 4 | + HexCharToByte(aead_kat[i][4][j+1]); } ctSz = j/2 - ASCON_AEAD128_TAG_SZ;