Merge pull request #8307 from julek-wolfssl/ascon

Initial ASCON hash256 and AEAD128 support based on NIST SP 800-232 ipd
This commit is contained in:
Sean Parkinson
2025-01-30 08:39:59 +10:00
committed by GitHub
20 changed files with 8259 additions and 4 deletions

View File

@ -40,6 +40,8 @@ jobs:
--enable-dtls-mtu',
'--enable-dtls --enable-dtlscid --enable-dtls13 --enable-secure-renegotiation
--enable-psk --enable-aesccm --enable-nullcipher CPPFLAGS=-DWOLFSSL_STATIC_RSA',
'--enable-ascon --enable-experimental',
'--enable-ascon CPPFLAGS=-DWOLFSSL_ASCON_UNROLL --enable-experimental',
]
name: make check
if: github.repository_owner == 'wolfssl'

View File

@ -564,6 +564,7 @@ WOLFSSL_ALLOW_TLS_SHA1
WOLFSSL_ALTERNATIVE_DOWNGRADE
WOLFSSL_ALT_NAMES_NO_REV
WOLFSSL_ARM_ARCH_NEON_64BIT
WOLFSSL_ASCON_UNROLL
WOLFSSL_ASNC_CRYPT
WOLFSSL_ASN_EXTRA
WOLFSSL_ASN_INT_LEAD_0_ANY

View File

@ -6055,6 +6055,17 @@ then
AM_CFLAGS="$AM_CFLAGS -DHAVE_XCHACHA"
fi
# ASCON
AC_ARG_ENABLE([ascon],
[AS_HELP_STRING([--enable-ascon],[Enable ASCON (default: disabled).])],
[ ENABLED_ASCON=$enableval ],
[ ENABLED_ASCON=no]
)
if test "$ENABLED_ASCON" = "yes"
then
AM_CFLAGS="$AM_CFLAGS -DHAVE_ASCON"
fi
# Hash DRBG
AC_ARG_ENABLE([hashdrbg],
@ -10073,6 +10084,7 @@ AM_CONDITIONAL([BUILD_SHA3],[test "x$ENABLED_SHA3" != "xno" || test "x$ENABLED_U
AM_CONDITIONAL([BUILD_POLY1305],[test "x$ENABLED_POLY1305" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_CHACHA],[test "x$ENABLED_CHACHA" = "xyes" || test "x$ENABLED_CHACHA" = "xnoasm" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_XCHACHA],[test "x$ENABLED_XCHACHA" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_ASCON],[test "x$ENABLED_ASCON" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_SM2],[test "x$ENABLED_SM2" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_SM3],[test "x$ENABLED_SM3" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_SM4],[test "x$ENABLED_SM4" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"])
@ -10473,6 +10485,7 @@ echo " * AES-EAX: $ENABLED_AESEAX"
echo " * AES Bitspliced: $ENABLED_AESBS"
echo " * AES Key Wrap: $ENABLED_AESKEYWRAP"
echo " * ARIA: $ENABLED_ARIA"
echo " * ASCON: $ENABLED_ASCON"
echo " * DES3: $ENABLED_DES3"
echo " * DES3 TLS Suites: $ENABLED_DES3_TLS_SUITES"
echo " * Camellia: $ENABLED_CAMELLIA"

View File

@ -0,0 +1,469 @@
/*!
\ingroup ASCON
\brief This function initializes the ASCON context for hashing.
\return 0 on success.
\return BAD_FUNC_ARG if the context pointer is NULL.
\param a pointer to the ASCON context to initialize.
_Example_
\code
wc_AsconHash256 a;
byte data[] = {0x01, 0x02, 0x03};
byte hash[ASCON_HASH256_SZ];
if (wc_AsconHash256_Init(&a) != 0)
// handle error
if (wc_AsconHash256_Update(&ctx, data, sizeof(data)) != 0)
// handle error
if (wc_AsconHash256_Final(&ctx, hash, sizeof(hash)) != 0)
// handle error
// hash contains the final hash
\endcode
\sa wc_AsconHash256_Update
\sa wc_AsconHash256_Final
*/
int wc_AsconHash256_Init(wc_AsconHash256* a);
/*!
\ingroup ASCON
\brief This function updates the ASCON hash with the input data.
\return 0 on success.
\return BAD_FUNC_ARG if the context or input pointer is NULL.
\param ctx pointer to the ASCON context.
\param in pointer to the input data.
\param inSz size of the input data.
_Example_
\code
wc_AsconHash256 a;
byte data[] = {0x01, 0x02, 0x03};
byte hash[ASCON_HASH256_SZ];
if (wc_AsconHash256_Init(&a) != 0)
// handle error
if (wc_AsconHash256_Update(&ctx, data, sizeof(data)) != 0)
// handle error
if (wc_AsconHash256_Final(&ctx, hash, sizeof(hash)) != 0)
// handle error
// hash contains the final hash
\endcode
\sa wc_AsconHash256_Init
\sa wc_AsconHash256_Final
*/
int wc_AsconHash256_Update(wc_AsconHash256* a, const byte* data, word32 dataSz);
/*!
\ingroup ASCON
\brief This function finalizes the ASCON hash and produces the output.
\return 0 on success.
\return BAD_FUNC_ARG if the context or output pointer is NULL.
\param ctx pointer to the ASCON context.
\param out pointer to the output buffer.
\param outSz size of the output buffer, should be at least ASCON_HASH256_SZ.
_Example_
\code
wc_AsconHash256 a;
byte data[] = {0x01, 0x02, 0x03};
byte hash[ASCON_HASH256_SZ];
if (wc_AsconHash256_Init(&a) != 0)
// handle error
if (wc_AsconHash256_Update(&ctx, data, sizeof(data)) != 0)
// handle error
if (wc_AsconHash256_Final(&ctx, hash, sizeof(hash)) != 0)
// handle error
// hash contains the final hash
\endcode
\sa wc_AsconHash256_Init
\sa wc_AsconHash256_Update
*/
int wc_AsconHash256_Final(wc_AsconHash256* a, byte* hash);
/*!
\ingroup ASCON
\brief This function allocates and initializes a new Ascon AEAD context.
\return pointer to the newly allocated Ascon AEAD context
\return NULL on failure.
_Example_
\code
wc_AsconAEAD128* a = wc_AsconAEAD128_New();
if (a == NULL) {
// handle allocation error
}
wc_AsconAEAD128_Free(a);
\endcode
\sa wc_AsconAEAD128_Free
*/
wc_AsconAEAD128* wc_AsconAEAD128_New(void);
/*!
\ingroup ASCON
\brief This function frees the resources associated with the Ascon AEAD
context.
\param a pointer to the Ascon AEAD context to free.
_Example_
\code
wc_AsconAEAD128* a = wc_AsconAEAD128_New();
if (a == NULL) {
// handle allocation error
}
// Use the context
wc_AsconAEAD128_Free(a);
\endcode
\sa wc_AsconAEAD128_New
*/
void wc_AsconAEAD128_Free(wc_AsconAEAD128 *a);
/*!
\ingroup ASCON
\brief This function initializes an Ascon AEAD context.
\return 0 on success.
\return BAD_FUNC_ARG if the context or output pointer is NULL.
\param a pointer to the Ascon AEAD context to initialize.
_Example_
\code
AsconAead a;
if (wc_AsconAEAD128_Init(&a) != 0)
// handle error
\endcode
\sa wc_AsconAeadEncrypt
\sa wc_AsconAeadDecrypt
*/
int wc_AsconAEAD128_Init(wc_AsconAEAD128* a);
/*!
\ingroup ASCON
\brief This function deinitializes an Ascon AEAD context. It does not
free the context.
\param a pointer to the Ascon AEAD context to deinitialize.
_Example_
\code
AsconAead a;
if (wc_AsconAEAD128_Init(&a) != 0)
// handle error
wc_AsconAEAD128_Clear(&a);
\endcode
\sa wc_AsconAeadEncrypt
\sa wc_AsconAeadDecrypt
*/
void wc_AsconAEAD128_Clear(wc_AsconAEAD128 *a);
/*!
\ingroup ASCON
\brief This function sets the key for the Ascon AEAD context.
\return 0 on success.
\return BAD_FUNC_ARG if the context or key pointer is NULL.
\return BAD_STATE_E if the key has already been set.
\param a pointer to the initialized Ascon AEAD context.
\param key pointer to the key buffer of length ASCON_AEAD128_KEY_SZ.
_Example_
\code
wc_AsconAEAD128 a;
byte key[ASCON_AEAD128_KEY_SZ] = { ... };
if (wc_AsconAEAD128_Init(&a) != 0)
// handle error
if (wc_AsconAEAD128_SetKey(&a, key) != 0)
// handle error
\endcode
\sa wc_AsconAEAD128_Init
\sa wc_AsconAEAD128_SetNonce
\sa wc_AsconAEAD128_SetAD
*/
int wc_AsconAEAD128_SetKey(wc_AsconAEAD128* a, const byte* key);
/*!
\ingroup ASCON
\brief This function sets the nonce for the Ascon AEAD context.
\return 0 on success.
\return BAD_FUNC_ARG if the context or nonce pointer is NULL.
\return BAD_STATE_E if the nonce has already been set.
\param a pointer to the initialized Ascon AEAD context.
\param nonce pointer to the nonce buffer of length ASCON_AEAD128_NONCE_SZ.
_Example_
\code
wc_AsconAEAD128 a;
byte nonce[ASCON_AEAD128_NONCE_SZ] = { ... };
if (wc_AsconAEAD128_Init(&a) != 0)
// handle error
if (wc_AsconAEAD128_SetNonce(&a, nonce) != 0)
// handle error
\endcode
\sa wc_AsconAEAD128_Init
\sa wc_AsconAEAD128_SetKey
\sa wc_AsconAEAD128_SetAD
*/
int wc_AsconAEAD128_SetNonce(wc_AsconAEAD128* a, const byte* nonce);
/*!
\ingroup ASCON
\brief This function sets the associated data for the Ascon AEAD context.
\return 0 on success.
\return BAD_FUNC_ARG if the context or associated data pointer is NULL.
\return BAD_STATE_E if the key or nonce has not been set.
\param a pointer to the initialized Ascon AEAD context.
\param ad pointer to the associated data buffer.
\param adSz size of the associated data buffer.
_Example_
\code
wc_AsconAEAD128 a;
byte key[ASCON_AEAD128_KEY_SZ] = { ... };
byte nonce[ASCON_AEAD128_NONCE_SZ] = { ... };
byte ad[] = { ... };
if (wc_AsconAEAD128_Init(&a) != 0)
// handle error
if (wc_AsconAEAD128_SetKey(&a, key) != 0)
// handle error
if (wc_AsconAEAD128_SetNonce(&a, nonce) != 0)
// handle error
if (wc_AsconAEAD128_SetAD(&a, ad, sizeof(ad)) != 0)
// handle error
\endcode
\sa wc_AsconAEAD128_Init
\sa wc_AsconAEAD128_SetKey
\sa wc_AsconAEAD128_SetNonce
*/
int wc_AsconAEAD128_SetAD(wc_AsconAEAD128* a, const byte* ad, word32 adSz);
/*!
\ingroup ASCON
\brief This function encrypts a plaintext message using Ascon AEAD. The
output is stored in the out buffer. The length of the output is
equal to the length of the input.
\return 0 on success.
\return BAD_FUNC_ARG if the context or output pointer is NULL or the input
is NULL while the input size is greater than 0.
\return BAD_STATE_E if the key, nonce, or additional data has not been set
or the context was previously used for decryption.
\param a pointer to the initialized Ascon AEAD context.
\param out pointer to the output buffer to store the ciphertext.
\param in pointer to the input buffer containing the plaintext message.
\param inSz length of the input buffer.
_Example_
\code
wc_AsconAEAD128 a;
byte key[ASCON_AEAD128_KEY_SZ] = { ... };
byte nonce[ASCON_AEAD128_NONCE_SZ] = { ... };
byte plaintext[PLAIN_TEXT_SIZE] = { ... };
byte ciphertext[CIPHER_TEXT_SIZE];
byte tag[ASCON_AEAD128_TAG_SZ] = { ... };
if (wc_AsconAeadInit(&a) != 0)
// handle error
if (wc_AsconAEAD128_SetKey(&a, key) != 0)
// handle error
if (wc_AsconAEAD128_SetNonce(&a, nonce) != 0)
// handle error
if (wc_AsconAEAD128_SetAD(&a, ad, sizeof(ad)) != 0)
// handle error
if (wc_AsconAEAD128_EncryptUpdate(&a, ciphertext, plaintext,
sizeof(plaintext)) != 0)
// handle error
if (wc_AsconAEAD128_EncryptFinal(&a, tag) != 0)
// handle error
\endcode
\sa wc_AsconAeadInit
\sa wc_AsconAEAD128_Clear
\sa wc_AsconAEAD128_SetKey
\sa wc_AsconAEAD128_SetNonce
\sa wc_AsconAEAD128_SetAD
\sa wc_AsconAEAD128_EncryptFinal
\sa wc_AsconAEAD128_DecryptUpdate
\sa wc_AsconAEAD128_DecryptFinal
*/
int wc_AsconAEAD128_EncryptUpdate(wc_AsconAEAD128* a, byte* out, const byte* in,
word32 inSz);
/*!
\ingroup ASCON
\brief This function finalizes the encryption process using Ascon AEAD and
produces the authentication tag.
\return 0 on success.
\return BAD_FUNC_ARG if the context or output pointer is NULL or the input
is NULL while the input size is greater than 0.
\return BAD_STATE_E if the key, nonce, or additional data has not been set
or the context was previously used for decryption.
\param a pointer to the initialized Ascon AEAD context.
\param tag pointer to the output buffer to store the authentication tag.
_Example_
\code
wc_AsconAEAD128 a;
byte key[ASCON_AEAD128_KEY_SZ] = { ... };
byte nonce[ASCON_AEAD128_NONCE_SZ] = { ... };
byte plaintext[PLAIN_TEXT_SIZE] = { ... };
byte ciphertext[CIPHER_TEXT_SIZE];
byte tag[ASCON_AEAD128_TAG_SZ] = { ... };
if (wc_AsconAeadInit(&a) != 0)
// handle error
if (wc_AsconAEAD128_SetKey(&a, key) != 0)
// handle error
if (wc_AsconAEAD128_SetNonce(&a, nonce) != 0)
// handle error
if (wc_AsconAEAD128_SetAD(&a, ad, sizeof(ad)) != 0)
// handle error
if (wc_AsconAEAD128_EncryptUpdate(&a, ciphertext, plaintext,
sizeof(plaintext)) != 0)
// handle error
if (wc_AsconAEAD128_EncryptFinal(&a, tag) != 0)
// handle error
\endcode
\sa wc_AsconAEAD128_Init
\sa wc_AsconAEAD128_SetKey
\sa wc_AsconAEAD128_SetNonce
\sa wc_AsconAEAD128_SetAD
\sa wc_AsconAEAD128_EncryptUpdate
\sa wc_AsconAEAD128_DecryptUpdate
\sa wc_AsconAEAD128_DecryptFinal
*/
int wc_AsconAEAD128_EncryptFinal(wc_AsconAEAD128* a, byte* tag);
/*!
\ingroup ASCON
\brief This function updates the decryption process using Ascon AEAD. The
output is stored in the out buffer. The length of the output is
equal to the length of the input.
\return 0 on success.
\return BAD_FUNC_ARG if the context or output pointer is NULL or the input
is NULL while the input size is greater than 0.
\return BAD_STATE_E if the key, nonce, or additional data has not been set
or the context was previously used for encryption.
\param a pointer to the initialized Ascon AEAD context.
\param out pointer to the output buffer to store the plaintext.
\param in pointer to the input buffer containing the ciphertext message.
\param inSz length of the input buffer.
_Example_
\code
wc_AsconAEAD128 a;
byte key[ASCON_AEAD128_KEY_SZ] = { ... };
byte nonce[ASCON_AEAD128_NONCE_SZ] = { ... };
byte ciphertext[CIPHER_TEXT_SIZE] = { ... };
byte plaintext[PLAIN_TEXT_SIZE];
byte tag[ASCON_AEAD128_TAG_SZ] = { ... };
if (wc_AsconAeadInit(&a) != 0)
// handle error
if (wc_AsconAEAD128_SetKey(&a, key) != 0)
// handle error
if (wc_AsconAEAD128_SetNonce(&a, nonce) != 0)
// handle error
if (wc_AsconAEAD128_SetAD(&a, ad, sizeof(ad)) != 0)
// handle error
if (wc_AsconAEAD128_DecryptUpdate(&a, plaintext, ciphertext,
sizeof(ciphertext)) != 0)
// handle error
if (wc_AsconAEAD128_DecryptFinal(&a, tag) != 0)
// handle error
\endcode
\sa wc_AsconAEAD128_Init
\sa wc_AsconAEAD128_SetKey
\sa wc_AsconAEAD128_SetNonce
\sa wc_AsconAEAD128_SetAD
\sa wc_AsconAEAD128_EncryptUpdate
\sa wc_AsconAEAD128_EncryptFinal
\sa wc_AsconAEAD128_DecryptFinal
*/
int wc_AsconAEAD128_DecryptUpdate(wc_AsconAEAD128* a, byte* out, const byte* in,
word32 inSz);
/*!
\ingroup ASCON
\brief This function finalizes the decryption process using Ascon AEAD and
verifies the authentication tag.
\return 0 on success.
\return BAD_FUNC_ARG if the context or tag pointer is NULL.
\return BAD_STATE_E if the key, nonce, or additional data has not been set
or the context was previously used for encryption.
\return ASCON_AUTH_E if the authentication tag does not match.
\param a pointer to the initialized Ascon AEAD context.
\param tag pointer to the buffer containing the authentication tag to verify
_Example_
\code
wc_AsconAEAD128 a;
byte key[ASCON_AEAD128_KEY_SZ] = { ... };
byte nonce[ASCON_AEAD128_NONCE_SZ] = { ... };
byte ciphertext[CIPHER_TEXT_SIZE] = { ... };
byte plaintext[PLAIN_TEXT_SIZE];
byte tag[ASCON_AEAD128_TAG_SZ] = { ... };
if (wc_AsconAeadInit(&a) != 0)
// handle error
if (wc_AsconAEAD128_SetKey(&a, key) != 0)
// handle error
if (wc_AsconAEAD128_SetNonce(&a, nonce) != 0)
// handle error
if (wc_AsconAEAD128_SetAD(&a, ad, sizeof(ad)) != 0)
// handle error
if (wc_AsconAEAD128_DecryptUpdate(&a, plaintext, ciphertext,
sizeof(ciphertext)) != 0)
// handle error
if (wc_AsconAEAD128_DecryptFinal(&a, tag) != 0)
// handle error
\endcode
\sa wc_AsconAEAD128_Init
\sa wc_AsconAEAD128_SetKey
\sa wc_AsconAEAD128_SetNonce
\sa wc_AsconAEAD128_SetAD
\sa wc_AsconAEAD128_DecryptUpdate
\sa wc_AsconAEAD128_EncryptUpdate
\sa wc_AsconAEAD128_EncryptFinal
*/
int wc_AsconAEAD128_DecryptFinal(wc_AsconAEAD128* a, const byte* tag);

View File

@ -1164,6 +1164,10 @@ src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/chacha20_poly1305.c
endif BUILD_POLY1305
endif BUILD_CHACHA
if BUILD_ASCON
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/ascon.c
endif
if !BUILD_INLINE
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/misc.c
endif

View File

@ -286,7 +286,8 @@
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
/* Gather test declarations to include them in the testCases array */
#include <tests/api/ascon.h>
#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),

6674
tests/api/ascon.c Normal file

File diff suppressed because it is too large Load Diff

28
tests/api/ascon.h Normal file
View File

@ -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 */

4
tests/api/include.am Normal file
View File

@ -0,0 +1,4 @@
if BUILD_TESTS
tests_unit_test_SOURCES += tests/api/ascon.c
endif
EXTRA_DIST += tests/api/ascon.h

View File

@ -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 \

View File

@ -553,6 +553,10 @@
#endif
#endif
#ifdef HAVE_ASCON
#include <wolfssl/wolfcrypt/ascon.h>
#endif
#ifdef HAVE_FIPS
#include <wolfssl/wolfcrypt/fips_test.h>
@ -669,6 +673,8 @@
#define BENCH_BLAKE2B 0x00008000
#define BENCH_BLAKE2S 0x00010000
#define BENCH_SM3 0x00020000
#define BENCH_ASCON_HASH256 0x00040000
#define BENCH_ASCON_AEAD128 0x00080000
/* MAC algorithms. */
#define BENCH_CMAC 0x00000001
@ -882,6 +888,9 @@ static const bench_alg bench_cipher_opt[] = {
#endif
#ifndef NO_DES3
{ "-des", BENCH_DES },
#endif
#ifdef HAVE_ASCON
{ "-ascon-aead", BENCH_ASCON_AEAD128 },
#endif
{ NULL, 0 }
};
@ -949,6 +958,9 @@ static const bench_alg bench_digest_opt[] = {
#endif
#ifdef HAVE_BLAKE2S
{ "-blake2s", BENCH_BLAKE2S },
#endif
#ifdef HAVE_ASCON
{ "-ascon-hash", BENCH_ASCON_HASH256 },
#endif
{ NULL, 0 }
};
@ -3342,6 +3354,10 @@ static void* benchmarks_do(void* args)
#endif
}
#endif
#ifdef HAVE_ASCON
if (bench_all || (bench_cipher_algs & BENCH_ASCON_AEAD128))
bench_ascon_aead();
#endif
#ifndef NO_MD5
if (bench_all || (bench_digest_algs & BENCH_MD5)) {
#ifndef NO_SW_BENCH
@ -3515,6 +3531,10 @@ static void* benchmarks_do(void* args)
if (bench_all || (bench_digest_algs & BENCH_BLAKE2S))
bench_blake2s();
#endif
#ifdef HAVE_ASCON
if (bench_all || (bench_digest_algs & BENCH_ASCON_HASH256))
bench_ascon_hash();
#endif
#ifdef WOLFSSL_CMAC
if (bench_all || (bench_mac_algs & BENCH_CMAC)) {
bench_cmac(0);
@ -6103,6 +6123,67 @@ exit:
}
#endif /* HAVE_CHACHA && HAVE_POLY1305 */
#ifdef HAVE_ASCON
void bench_ascon_aead(void)
{
#define ASCON_AD (byte*)"ADADADADAD"
#define ASCON_AD_SZ XSTR_SIZEOF(ASCON_AD)
double start;
int ret = 0, i, count;
WC_DECLARE_VAR(authTag, byte, ASCON_AEAD128_TAG_SZ, HEAP_HINT);
WC_DECLARE_VAR(enc, wc_AsconAEAD128, 1, HEAP_HINT);
DECLARE_MULTI_VALUE_STATS_VARS()
WC_ALLOC_VAR(authTag, byte, ASCON_AEAD128_TAG_SZ, HEAP_HINT);
XMEMSET(authTag, 0, ASCON_AEAD128_TAG_SZ);
WC_ALLOC_VAR(enc, wc_AsconAEAD128, 1, HEAP_HINT);
XMEMSET(enc, 0, sizeof(wc_AsconAEAD128));
bench_stats_start(&count, &start);
do {
for (i = 0; i < numBlocks; i++) {
ret = wc_AsconAEAD128_Init(enc);
if (ret == 0)
ret = wc_AsconAEAD128_SetKey(enc, bench_key);
if (ret == 0)
ret = wc_AsconAEAD128_SetNonce(enc, bench_iv);
if (ret == 0)
ret = wc_AsconAEAD128_SetAD(enc, ASCON_AD, ASCON_AD_SZ);
if (ret == 0) {
ret = wc_AsconAEAD128_EncryptUpdate(enc, bench_cipher,
bench_plain, bench_size);
}
if (ret == 0)
ret = wc_AsconAEAD128_EncryptFinal(enc, authTag);
wc_AsconAEAD128_Clear(enc);
if (ret != 0) {
printf("ASCON-AEAD error: %d\n", ret);
goto exit;
}
RECORD_MULTI_VALUE_STATS();
}
count += i;
} while (bench_stats_check(start)
#ifdef MULTI_VALUE_STATISTICS
|| runs < minimum_runs
#endif
);
bench_stats_sym_finish("ASCON-AEAD", 0, count, bench_size, start, ret);
#ifdef MULTI_VALUE_STATISTICS
bench_multi_value_stats(max, min, sum, squareSum, runs);
#endif
exit:
WC_FREE_VAR(authTag, HEAP_HINT);
WC_FREE_VAR(enc, HEAP_HINT);
}
#endif /* HAVE_ASCON */
#ifndef NO_MD5
void bench_md5(int useDeviceID)
@ -7996,6 +8077,64 @@ void bench_blake2s(void)
}
#endif
#ifdef HAVE_ASCON
void bench_ascon_hash(void)
{
wc_AsconHash256 ascon;
byte digest[ASCON_HASH256_SZ];
double start;
int ret = 0, i, count;
if (digest_stream) {
ret = wc_AsconHash256_Init(&ascon);
if (ret != 0) {
printf("wc_AsconHash256_Init failed, ret = %d\n", ret);
return;
}
bench_stats_start(&count, &start);
do {
for (i = 0; i < numBlocks; i++) {
ret = wc_AsconHash256_Update(&ascon, bench_plain, bench_size);
if (ret != 0) {
printf("wc_AsconHash256_Update failed, ret = %d\n", ret);
return;
}
}
ret = wc_AsconHash256_Final(&ascon, digest);
if (ret != 0) {
printf("wc_AsconHash256_Final failed, ret = %d\n", ret);
return;
}
count += i;
} while (bench_stats_check(start));
}
else {
bench_stats_start(&count, &start);
do {
for (i = 0; i < numBlocks; i++) {
ret = wc_AsconHash256_Init(&ascon);
if (ret != 0) {
printf("wc_AsconHash256_Init failed, ret = %d\n", ret);
return;
}
ret = wc_AsconHash256_Update(&ascon, bench_plain, bench_size);
if (ret != 0) {
printf("wc_AsconHash256_Update failed, ret = %d\n", ret);
return;
}
ret = wc_AsconHash256_Final(&ascon, digest);
if (ret != 0) {
printf("wc_AsconHash256_Final failed, ret = %d\n", ret);
return;
}
}
count += i;
} while (bench_stats_check(start));
}
bench_stats_sym_finish("ASCON hash", 0, count, bench_size, start, ret);
}
#endif
#ifdef WOLFSSL_CMAC

View File

@ -64,6 +64,7 @@ void bench_camellia(void);
void bench_sm4_cbc(void);
void bench_sm4_gcm(void);
void bench_sm4_ccm(void);
void bench_ascon_aead(void);
void bench_md5(int useDeviceID);
void bench_sha(int useDeviceID);
void bench_sha224(int useDeviceID);
@ -128,6 +129,7 @@ void bench_sakke(void);
void bench_rng(void);
void bench_blake2b(void);
void bench_blake2s(void);
void bench_ascon_hash(void);
void bench_pbkdf2(void);
void bench_falconKeySign(byte level);
void bench_dilithiumKeySign(byte level);

527
wolfcrypt/src/ascon.c Normal file
View File

@ -0,0 +1,527 @@
/* ascon.c
*
* 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
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#ifdef HAVE_ASCON
#include <wolfssl/wolfcrypt/ascon.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/logging.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
/*
* Implementation of the ASCON AEAD and HASH algorithms. Based on the NIST
* Initial Public Draft "NIST SP 800-232 ipd" and reference implementation found
* at https://github.com/ascon/ascon-c.
*/
/*
* TODO
* - Add support for big-endian systems
* - Add support for 32-bit and smaller systems */
#ifndef WORD64_AVAILABLE
#error "Ascon implementation requires a 64-bit word"
#endif
/* Data block size in bytes */
#define ASCON_HASH256_RATE 8
#define ASCON_HASH256_ROUNDS 12
#define ASCON_HASH256_IV 0x0000080100CC0002ULL
#define ASCON_AEAD128_ROUNDS_PA 12
#define ASCON_AEAD128_ROUNDS_PB 8
#define ASCON_AEAD128_IV 0x00001000808C0001ULL
#define ASCON_AEAD128_RATE 16
#define MAX_ROUNDS 12
#ifndef WOLFSSL_ASCON_UNROLL
/* Table 5 */
static const byte round_constants[MAX_ROUNDS] = {
0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, 0x78, 0x69, 0x5a, 0x4b
};
static byte start_index(byte rounds)
{
switch (rounds) {
case 8:
return 4;
case 12:
return 0;
default:
WOLFSSL_MSG("Something went wrong in wolfCrypt logic. Wrong ASCON "
"rounds value.");
return MAX_ROUNDS;
}
}
static WC_INLINE void ascon_round(AsconState* a, byte round)
{
word64 tmp0, tmp1, tmp2, tmp3, tmp4;
/* 3.2 Constant-Addition Layer */
a->s64[2] ^= round_constants[round];
/* 3.3 Substitution Layer */
a->s64[0] ^= a->s64[4];
a->s64[4] ^= a->s64[3];
a->s64[2] ^= a->s64[1];
tmp0 = a->s64[0] ^ (~a->s64[1] & a->s64[2]);
tmp2 = a->s64[2] ^ (~a->s64[3] & a->s64[4]);
tmp4 = a->s64[4] ^ (~a->s64[0] & a->s64[1]);
tmp1 = a->s64[1] ^ (~a->s64[2] & a->s64[3]);
tmp3 = a->s64[3] ^ (~a->s64[4] & a->s64[0]);
tmp1 ^= tmp0;
tmp3 ^= tmp2;
tmp0 ^= tmp4;
tmp2 = ~tmp2;
/* 3.4 Linear Diffusion Layer */
a->s64[4] = tmp4 ^ rotrFixed64(tmp4, 7) ^ rotrFixed64(tmp4, 41);
a->s64[1] = tmp1 ^ rotrFixed64(tmp1, 61) ^ rotrFixed64(tmp1, 39);
a->s64[3] = tmp3 ^ rotrFixed64(tmp3, 10) ^ rotrFixed64(tmp3, 17);
a->s64[0] = tmp0 ^ rotrFixed64(tmp0, 19) ^ rotrFixed64(tmp0, 28);
a->s64[2] = tmp2 ^ rotrFixed64(tmp2, 1) ^ rotrFixed64(tmp2, 6);
}
static void permutation(AsconState* a, byte rounds)
{
byte i = start_index(rounds);
for (; i < MAX_ROUNDS; i++) {
ascon_round(a, i);
}
}
#else
#define p(a, c) do { \
word64 tmp0, tmp1, tmp2, tmp3, tmp4; \
/* 3.2 Constant-Addition Layer */ \
(a)->s64[2] ^= c; \
/* 3.3 Substitution Layer */ \
(a)->s64[0] ^= (a)->s64[4]; \
(a)->s64[4] ^= (a)->s64[3]; \
(a)->s64[2] ^= (a)->s64[1]; \
tmp0 = (a)->s64[0] ^ (~(a)->s64[1] & (a)->s64[2]); \
tmp2 = (a)->s64[2] ^ (~(a)->s64[3] & (a)->s64[4]); \
tmp4 = (a)->s64[4] ^ (~(a)->s64[0] & (a)->s64[1]); \
tmp1 = (a)->s64[1] ^ (~(a)->s64[2] & (a)->s64[3]); \
tmp3 = (a)->s64[3] ^ (~(a)->s64[4] & (a)->s64[0]); \
tmp1 ^= tmp0; \
tmp3 ^= tmp2; \
tmp0 ^= tmp4; \
tmp2 = ~tmp2; \
/* 3.4 Linear Diffusion Layer */ \
(a)->s64[4] = tmp4 ^ rotrFixed64(tmp4, 7) ^ rotrFixed64(tmp4, 41); \
(a)->s64[1] = tmp1 ^ rotrFixed64(tmp1, 61) ^ rotrFixed64(tmp1, 39); \
(a)->s64[3] = tmp3 ^ rotrFixed64(tmp3, 10) ^ rotrFixed64(tmp3, 17); \
(a)->s64[0] = tmp0 ^ rotrFixed64(tmp0, 19) ^ rotrFixed64(tmp0, 28); \
(a)->s64[2] = tmp2 ^ rotrFixed64(tmp2, 1) ^ rotrFixed64(tmp2, 6); \
} while (0)
#define p8(a) \
p(a, 0xb4); \
p(a, 0xa5); \
p(a, 0x96); \
p(a, 0x87); \
p(a, 0x78); \
p(a, 0x69); \
p(a, 0x5a); \
p(a, 0x4b)
#define p12(a) \
p(a, 0xf0); \
p(a, 0xe1); \
p(a, 0xd2); \
p(a, 0xc3); \
p8(a)
/* Needed layer to evaluate the macro values */
#define _permutation(a, rounds) \
p ## rounds(a)
#define permutation(a, rounds) \
_permutation(a, rounds)
#endif
/* AsconHash API */
wc_AsconHash256* wc_AsconHash256_New(void)
{
wc_AsconHash256* ret = (wc_AsconHash256*)XMALLOC(sizeof(wc_AsconHash256),
NULL, DYNAMIC_TYPE_ASCON);
if (ret != NULL) {
if (wc_AsconHash256_Init(ret) != 0) {
wc_AsconHash256_Free(ret);
ret = NULL;
}
}
return ret;
}
void wc_AsconHash256_Free(wc_AsconHash256* a)
{
if (a != NULL) {
wc_AsconHash256_Clear(a);
XFREE(a, NULL, DYNAMIC_TYPE_ASCON);
}
}
int wc_AsconHash256_Init(wc_AsconHash256* a)
{
if (a == NULL)
return BAD_FUNC_ARG;
XMEMSET(a, 0, sizeof(*a));
a->state.s64[0] = ASCON_HASH256_IV;
permutation(&a->state, ASCON_HASH256_ROUNDS);
return 0;
}
void wc_AsconHash256_Clear(wc_AsconHash256* a)
{
if (a != NULL) {
ForceZero(a, sizeof(*a));
}
}
int wc_AsconHash256_Update(wc_AsconHash256* a, const byte* data, word32 dataSz)
{
if (a == NULL || (data == NULL && dataSz != 0))
return BAD_FUNC_ARG;
if (dataSz == 0)
return 0;
/* Process leftover block */
if (a->lastBlkSz != 0) {
word32 toProcess = min(ASCON_HASH256_RATE - a->lastBlkSz, dataSz);
xorbuf(a->state.s8 + a->lastBlkSz, data, toProcess);
data += toProcess;
dataSz -= toProcess;
a->lastBlkSz += toProcess;
if (a->lastBlkSz < ASCON_HASH256_RATE)
return 0;
permutation(&a->state, ASCON_HASH256_ROUNDS);
/* Reset the counter */
a->lastBlkSz = 0;
}
while (dataSz >= ASCON_HASH256_RATE) {
/* Read in input as little endian numbers */
xorbuf(a->state.s64, data, ASCON_HASH256_RATE);
permutation(&a->state, ASCON_HASH256_ROUNDS);
data += ASCON_HASH256_RATE;
dataSz -= ASCON_HASH256_RATE;
}
xorbuf(a->state.s64, data, dataSz);
a->lastBlkSz = dataSz;
return 0;
}
int wc_AsconHash256_Final(wc_AsconHash256* a, byte* hash)
{
byte i;
if (a == NULL || hash == NULL)
return BAD_FUNC_ARG;
/* Process last block */
a->state.s8[a->lastBlkSz] ^= 1;
for (i = 0; i < ASCON_HASH256_SZ; i += ASCON_HASH256_RATE) {
permutation(&a->state, ASCON_HASH256_ROUNDS);
XMEMCPY(hash, a->state.s64, ASCON_HASH256_RATE);
hash += ASCON_HASH256_RATE;
}
/* Clear state as soon as possible */
wc_AsconHash256_Clear(a);
return 0;
}
/* AsconAEAD API */
wc_AsconAEAD128* wc_AsconAEAD128_New(void)
{
wc_AsconAEAD128 *ret = (wc_AsconAEAD128*) XMALLOC(sizeof(wc_AsconAEAD128),
NULL, DYNAMIC_TYPE_ASCON);
if (ret != NULL) {
if (wc_AsconAEAD128_Init(ret) != 0) {
wc_AsconAEAD128_Free(ret);
ret = NULL;
}
}
return ret;
}
void wc_AsconAEAD128_Free(wc_AsconAEAD128 *a)
{
if (a != NULL) {
wc_AsconAEAD128_Clear(a);
XFREE(a, NULL, DYNAMIC_TYPE_ASCON);
}
}
int wc_AsconAEAD128_Init(wc_AsconAEAD128 *a)
{
if (a == NULL)
return BAD_FUNC_ARG;
XMEMSET(a, 0, sizeof(*a));
a->state.s64[0] = ASCON_AEAD128_IV;
return 0;
}
void wc_AsconAEAD128_Clear(wc_AsconAEAD128 *a)
{
if (a != NULL) {
ForceZero(a, sizeof(*a));
}
}
int wc_AsconAEAD128_SetKey(wc_AsconAEAD128* a, const byte* key)
{
if (a == NULL || key == NULL)
return BAD_FUNC_ARG;
if (a->keySet)
return BAD_STATE_E;
XMEMCPY(a->key, key, ASCON_AEAD128_KEY_SZ);
a->state.s64[1] = a->key[0];
a->state.s64[2] = a->key[1];
a->keySet = 1;
return 0;
}
int wc_AsconAEAD128_SetNonce(wc_AsconAEAD128* a, const byte* nonce)
{
if (a == NULL || nonce == NULL)
return BAD_FUNC_ARG;
if (a->nonceSet)
return BAD_STATE_E;
XMEMCPY(&a->state.s64[3], nonce, ASCON_AEAD128_NONCE_SZ);
a->nonceSet = 1;
return 0;
}
int wc_AsconAEAD128_SetAD(wc_AsconAEAD128* a, const byte* ad,
word32 adSz)
{
if (a == NULL || (ad == NULL && adSz > 0))
return BAD_FUNC_ARG;
if (!a->keySet || !a->nonceSet) /* key and nonce must be set before */
return BAD_STATE_E;
permutation(&a->state, ASCON_AEAD128_ROUNDS_PA);
a->state.s64[3] ^= a->key[0];
a->state.s64[4] ^= a->key[1];
if (adSz > 0) {
while (adSz >= ASCON_AEAD128_RATE) {
xorbuf(a->state.s64, ad, ASCON_AEAD128_RATE);
permutation(&a->state, ASCON_AEAD128_ROUNDS_PB);
ad += ASCON_AEAD128_RATE;
adSz -= ASCON_AEAD128_RATE;
}
xorbuf(a->state.s64, ad, adSz);
/* Pad the last block */
a->state.s8[adSz] ^= 1;
permutation(&a->state, ASCON_AEAD128_ROUNDS_PB);
}
a->state.s64[4] ^= 1ULL << 63;
a->adSet = 1;
return 0;
}
int wc_AsconAEAD128_EncryptUpdate(wc_AsconAEAD128* a, byte* out,
const byte* in, word32 inSz)
{
if (a == NULL || (in == NULL && inSz > 0))
return BAD_FUNC_ARG;
if (!a->keySet || !a->nonceSet || !a->adSet)
return BAD_STATE_E;
if (a->op == ASCON_AEAD128_NOTSET)
a->op = ASCON_AEAD128_ENCRYPT;
else if (a->op != ASCON_AEAD128_ENCRYPT)
return BAD_STATE_E;
/* Process leftover from last block */
if (a->lastBlkSz != 0) {
word32 toProcess = min(ASCON_AEAD128_RATE - a->lastBlkSz, inSz);
xorbuf(&a->state.s8[a->lastBlkSz], in, toProcess);
XMEMCPY(out, &a->state.s8[a->lastBlkSz], toProcess);
a->lastBlkSz += toProcess;
in += toProcess;
out += toProcess;
inSz -= toProcess;
if (a->lastBlkSz < ASCON_AEAD128_RATE)
return 0;
permutation(&a->state, ASCON_AEAD128_ROUNDS_PB);
a->lastBlkSz = 0;
}
while (inSz >= ASCON_AEAD128_RATE) {
xorbuf(a->state.s64, in, ASCON_AEAD128_RATE);
XMEMCPY(out, a->state.s64, ASCON_AEAD128_RATE);
permutation(&a->state, ASCON_AEAD128_ROUNDS_PB);
in += ASCON_AEAD128_RATE;
out += ASCON_AEAD128_RATE;
inSz -= ASCON_AEAD128_RATE;
}
/* Store leftover */
xorbuf(a->state.s64, in, inSz);
XMEMCPY(out, a->state.s64, inSz);
a->lastBlkSz = inSz;
return 0;
}
int wc_AsconAEAD128_EncryptFinal(wc_AsconAEAD128* a, byte* tag)
{
if (a == NULL || tag == NULL)
return BAD_FUNC_ARG;
if (!a->keySet || !a->nonceSet || !a->adSet)
return BAD_STATE_E;
if (a->op != ASCON_AEAD128_ENCRYPT)
return BAD_STATE_E;
/* Process leftover from last block */
a->state.s8[a->lastBlkSz] ^= 1;
a->state.s64[2] ^= a->key[0];
a->state.s64[3] ^= a->key[1];
permutation(&a->state, ASCON_AEAD128_ROUNDS_PA);
a->state.s64[3] ^= a->key[0];
a->state.s64[4] ^= a->key[1];
XMEMCPY(tag, &a->state.s64[3], ASCON_AEAD128_TAG_SZ);
/* Clear state as soon as possible */
wc_AsconAEAD128_Clear(a);
return 0;
}
int wc_AsconAEAD128_DecryptUpdate(wc_AsconAEAD128* a, byte* out,
const byte* in, word32 inSz)
{
if (a == NULL || (in == NULL && inSz > 0))
return BAD_FUNC_ARG;
if (!a->keySet || !a->nonceSet || !a->adSet)
return BAD_STATE_E;
if (a->op == ASCON_AEAD128_NOTSET)
a->op = ASCON_AEAD128_DECRYPT;
else if (a->op != ASCON_AEAD128_DECRYPT)
return BAD_STATE_E;
/* Process leftover block */
if (a->lastBlkSz != 0) {
word32 toProcess = min(ASCON_AEAD128_RATE - a->lastBlkSz, inSz);
xorbufout(out, a->state.s8 + a->lastBlkSz, in, toProcess);
XMEMCPY(a->state.s8 + a->lastBlkSz, in, toProcess);
in += toProcess;
out += toProcess;
inSz -= toProcess;
a->lastBlkSz += toProcess;
if (a->lastBlkSz < ASCON_AEAD128_RATE)
return 0;
permutation(&a->state, ASCON_AEAD128_ROUNDS_PB);
a->lastBlkSz = 0;
}
while (inSz >= ASCON_AEAD128_RATE) {
xorbufout(out, a->state.s64, in, ASCON_AEAD128_RATE);
XMEMCPY(a->state.s64, in, ASCON_AEAD128_RATE);
permutation(&a->state, ASCON_AEAD128_ROUNDS_PB);
in += ASCON_AEAD128_RATE;
out += ASCON_AEAD128_RATE;
inSz -= ASCON_AEAD128_RATE;
}
/* Store leftover */
xorbufout(out, a->state.s64, in, inSz);
XMEMCPY(a->state.s64, in, inSz);
a->lastBlkSz = inSz;
return 0;
}
int wc_AsconAEAD128_DecryptFinal(wc_AsconAEAD128* a, const byte* tag)
{
if (a == NULL || tag == NULL)
return BAD_FUNC_ARG;
if (!a->keySet || !a->nonceSet || !a->adSet)
return BAD_STATE_E;
if (a->op != ASCON_AEAD128_DECRYPT)
return BAD_STATE_E;
/* Pad last block */
a->state.s8[a->lastBlkSz] ^= 1;
a->state.s64[2] ^= a->key[0];
a->state.s64[3] ^= a->key[1];
permutation(&a->state, ASCON_AEAD128_ROUNDS_PA);
a->state.s64[3] ^= a->key[0];
a->state.s64[4] ^= a->key[1];
if (ConstantCompare(tag, (const byte*)&a->state.s64[3],
ASCON_AEAD128_TAG_SZ) != 0)
return ASCON_AUTH_E;
/* Clear state as soon as possible */
wc_AsconAEAD128_Clear(a);
return 0;
}
#endif /* HAVE_ASCON */

View File

@ -651,6 +651,9 @@ const char* wc_GetErrorString(int error)
case DEADLOCK_AVERTED_E:
return "Deadlock averted -- retry the call";
case ASCON_AUTH_E:
return "ASCON Authentication check fail";
case MAX_CODE_E:
case WC_SPAN1_MIN_CODE_E:
case MIN_CODE_E:

View File

@ -48,6 +48,13 @@
#include <wolfssl/wolfcrypt/wc_port.h>
#include <wolfssl/wolfcrypt/mem_track.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
#if defined(HAVE_WOLFCRYPT_TEST_OPTIONS)
#include <wolfssl/ssl.h>
#define err_sys err_sys_remap /* remap err_sys */
@ -285,6 +292,7 @@ const byte const_byte_array[] = "A+Gd\0\0\0";
#include <wolfssl/wolfcrypt/srp.h>
#include <wolfssl/wolfcrypt/chacha.h>
#include <wolfssl/wolfcrypt/chacha20_poly1305.h>
#include <wolfssl/wolfcrypt/ascon.h>
#include <wolfssl/wolfcrypt/pwdbased.h>
#include <wolfssl/wolfcrypt/ripemd.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
@ -590,6 +598,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes192_test(void);
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes256_test(void);
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aesofb_test(void);
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cmac_test(void);
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ascon_hash256_test(void);
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ascon_aead128_test(void);
#if defined(WOLFSSL_SIPHASH)
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t siphash_test(void);
#endif
@ -1947,6 +1957,18 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\
TEST_PASS("ChaCha20-Poly1305 AEAD test passed!\n");
#endif
#ifdef HAVE_ASCON
if ( (ret = ascon_hash256_test()) != 0)
return err_sys("ASCON Hash test failed!\n", ret);
else
TEST_PASS("ASCON Hash test passed!\n");
if ( (ret = ascon_aead128_test()) != 0)
return err_sys("ASCON AEAD test failed!\n", ret);
else
TEST_PASS("ASCON AEAD test passed!\n");
#endif
#if defined(HAVE_XCHACHA) && defined(HAVE_POLY1305)
if ( (ret = XChaCha20Poly1305_test()) != 0)
TEST_FAIL("XChaCha20-Poly1305 AEAD test failed!\n", ret);
@ -8784,6 +8806,254 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t chacha20_poly1305_aead_test(void)
}
#endif /* HAVE_CHACHA && HAVE_POLY1305 */
#ifdef HAVE_ASCON
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ascon_hash256_test(void)
{
WOLFSSL_SMALL_STACK_STATIC byte msg[1024];
byte mdOut[ASCON_HASH256_SZ];
/* 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;
/* init msg buffer */
for (i = 0; i < sizeof(msg); i++)
msg[i] = (byte)i;
for (i = 0; i < XELEM_CNT(hash_output); i++) {
XMEMSET(mdOut, 0, sizeof(mdOut));
err = wc_AsconHash256_Init(&asconHash);
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
err = wc_AsconHash256_Update(&asconHash, msg, i);
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
err = wc_AsconHash256_Final(&asconHash, mdOut);
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
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 < XELEM_CNT(hash_output); i++) {
word32 half_i = i / 2;
XMEMSET(mdOut, 0, sizeof(mdOut));
err = wc_AsconHash256_Init(&asconHash);
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
err = wc_AsconHash256_Update(&asconHash, msg, half_i);
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
err = wc_AsconHash256_Update(&asconHash, msg + half_i, i - half_i);
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
err = wc_AsconHash256_Final(&asconHash, mdOut);
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
if (XMEMCMP(mdOut, hash_output[i], ASCON_HASH256_SZ) != 0)
return WC_TEST_RET_ENC_NC;
wc_AsconHash256_Clear(&asconHash);
}
return 0;
}
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ascon_aead128_test(void)
{
word32 i;
wc_AsconAEAD128 asconAEAD;
int err;
/* 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 */
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; 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; 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; 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; 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; 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;
for (j = 0; j < 4; j++) {
err = wc_AsconAEAD128_Init(&asconAEAD);
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
err = wc_AsconAEAD128_SetKey(&asconAEAD, key);
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
err = wc_AsconAEAD128_SetNonce(&asconAEAD, nonce);
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
err = wc_AsconAEAD128_SetAD(&asconAEAD, ad, adSz);
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
if (j == 0) {
/* Encryption test */
err = wc_AsconAEAD128_EncryptUpdate(&asconAEAD, buf, pt, ptSz);
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
if (XMEMCMP(buf, ct, ptSz) != 0)
return WC_TEST_RET_ENC_NC;
err = wc_AsconAEAD128_EncryptFinal(&asconAEAD, tag);
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
if (XMEMCMP(tag, ct + ptSz, ASCON_AEAD128_TAG_SZ) != 0)
return WC_TEST_RET_ENC_NC;
}
else if (j == 1) {
/* Decryption test */
err = wc_AsconAEAD128_DecryptUpdate(&asconAEAD, buf, ct, ctSz);
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
if (XMEMCMP(buf, pt, ctSz) != 0)
return WC_TEST_RET_ENC_NC;
err = wc_AsconAEAD128_DecryptFinal(&asconAEAD, ct + ctSz);
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
}
else if (j == 2) {
/* Split encryption test */
err = wc_AsconAEAD128_EncryptUpdate(&asconAEAD, buf, pt,
ptSz/2);
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
err = wc_AsconAEAD128_EncryptUpdate(&asconAEAD, buf + (ptSz/2),
pt + (ptSz/2), ptSz - (ptSz/2));
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
if (XMEMCMP(buf, ct, ptSz) != 0)
return WC_TEST_RET_ENC_NC;
err = wc_AsconAEAD128_EncryptFinal(&asconAEAD, tag);
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
if (XMEMCMP(tag, ct + ptSz, ASCON_AEAD128_TAG_SZ) != 0)
return WC_TEST_RET_ENC_NC;
}
else if (j == 3) {
/* Split decryption test */
err = wc_AsconAEAD128_DecryptUpdate(&asconAEAD, buf, ct,
ctSz/2);
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
err = wc_AsconAEAD128_DecryptUpdate(&asconAEAD, buf + (ctSz/2),
ct + (ctSz/2), ctSz - (ctSz/2));
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
if (XMEMCMP(buf, pt, ctSz) != 0)
return WC_TEST_RET_ENC_NC;
err = wc_AsconAEAD128_DecryptFinal(&asconAEAD, ct + ctSz);
if (err != 0)
return WC_TEST_RET_ENC_EC(err);
}
wc_AsconAEAD128_Clear(&asconAEAD);
}
}
return 0;
}
#endif /* HAVE_ASCON */
#ifndef NO_DES3
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t des_test(void)

109
wolfssl/wolfcrypt/ascon.h Normal file
View File

@ -0,0 +1,109 @@
/* 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 WOLF_CRYPT_ASCON_H
#define WOLF_CRYPT_ASCON_H
#ifdef HAVE_ASCON
#include <wolfssl/wolfcrypt/types.h>
#ifdef __cplusplus
extern "C" {
#endif
#define ASCON_HASH256_SZ 32
#define ASCON_AEAD128_KEY_SZ 16
#define ASCON_AEAD128_NONCE_SZ 16
#define ASCON_AEAD128_TAG_SZ 16
typedef union AsconState {
#ifdef WORD64_AVAILABLE
word64 s64[5];
#endif
word32 s32[10];
word16 s16[20];
byte s8[40];
} AsconState;
typedef struct wc_AsconHash256 {
AsconState state;
byte lastBlkSz;
} wc_AsconHash256;
enum {
ASCON_AEAD128_NOTSET = 0,
ASCON_AEAD128_ENCRYPT = 1,
ASCON_AEAD128_DECRYPT = 2
};
typedef struct wc_AsconAEAD128 {
/* needed throughout both encrypt and decrypt */
#ifdef WORD64_AVAILABLE
word64 key[ASCON_AEAD128_KEY_SZ/sizeof(word64)];
#endif
AsconState state;
byte lastBlkSz;
byte keySet:1; /* has the key been processed */
byte nonceSet:1; /* has the nonce been processed */
byte adSet:1; /* has the associated data been processed */
byte op:2; /* 0 for not set, 1 for encrypt, 2 for decrypt */
} wc_AsconAEAD128;
/* AsconHash API */
WOLFSSL_API wc_AsconHash256* wc_AsconHash256_New(void);
WOLFSSL_API void wc_AsconHash256_Free(wc_AsconHash256* a);
WOLFSSL_API int wc_AsconHash256_Init(wc_AsconHash256* a);
WOLFSSL_API void wc_AsconHash256_Clear(wc_AsconHash256* a);
WOLFSSL_API int wc_AsconHash256_Update(wc_AsconHash256* a, const byte* data,
word32 dataSz);
WOLFSSL_API int wc_AsconHash256_Final(wc_AsconHash256* a, byte* hash);
WOLFSSL_API wc_AsconAEAD128* wc_AsconAEAD128_New(void);
WOLFSSL_API void wc_AsconAEAD128_Free(wc_AsconAEAD128* a);
WOLFSSL_API int wc_AsconAEAD128_Init(wc_AsconAEAD128* a);
WOLFSSL_API void wc_AsconAEAD128_Clear(wc_AsconAEAD128* a);
/* AsconAEAD API */
WOLFSSL_API int wc_AsconAEAD128_SetKey(wc_AsconAEAD128* a, const byte* key);
WOLFSSL_API int wc_AsconAEAD128_SetNonce(wc_AsconAEAD128* a, const byte* nonce);
WOLFSSL_API int wc_AsconAEAD128_SetAD(wc_AsconAEAD128* a, const byte* ad,
word32 adSz);
WOLFSSL_API int wc_AsconAEAD128_EncryptUpdate(wc_AsconAEAD128* a, byte* out,
const byte* in, word32 inSz);
WOLFSSL_API int wc_AsconAEAD128_EncryptFinal(wc_AsconAEAD128* a, byte* tag);
WOLFSSL_API int wc_AsconAEAD128_DecryptUpdate(wc_AsconAEAD128* a, byte* out,
const byte* in, word32 inSz);
WOLFSSL_API int wc_AsconAEAD128_DecryptFinal(wc_AsconAEAD128* a,
const byte* tag);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* HAVE_ASCON */
#endif /* WOLF_CRYPT_ASCON_H */

View File

@ -303,11 +303,12 @@ enum wolfCrypt_ErrorCodes {
WC_SPAN2_FIRST_E = -1000,
DEADLOCK_AVERTED_E = -1000, /* Deadlock averted -- retry the call */
ASCON_AUTH_E = -1001, /* ASCON Authentication check failure */
WC_SPAN2_LAST_E = -1000, /* Update to indicate last used error code */
WC_SPAN2_LAST_E = -1001, /* Update to indicate last used error code */
WC_SPAN2_MIN_CODE_E = -1999, /* Last usable code in span 2 */
WC_LAST_E = -1000, /* the last code used either here or in
WC_LAST_E = -1001, /* the last code used either here or in
* error-ssl.h
*/

View File

@ -4,6 +4,7 @@
nobase_include_HEADERS+= \
wolfssl/wolfcrypt/aes.h \
wolfssl/wolfcrypt/arc4.h \
wolfssl/wolfcrypt/ascon.h \
wolfssl/wolfcrypt/asn.h \
wolfssl/wolfcrypt/asn_public.h \
wolfssl/wolfcrypt/poly1305.h \

View File

@ -4103,7 +4103,8 @@ extern void uITRON4_free(void *p) ;
#if (defined(HAVE_LIBOQS) || \
defined(HAVE_LIBXMSS) || \
defined(HAVE_LIBLMS) || \
defined(WOLFSSL_DUAL_ALG_CERTS)) && \
defined(WOLFSSL_DUAL_ALG_CERTS) || \
defined(HAVE_ASCON)) && \
!defined(WOLFSSL_EXPERIMENTAL_SETTINGS)
#error Experimental settings without WOLFSSL_EXPERIMENTAL_SETTINGS
#endif

View File

@ -1110,6 +1110,7 @@ typedef struct w64wrapper {
DYNAMIC_TYPE_BIO = 102,
DYNAMIC_TYPE_X509_ACERT = 103,
DYNAMIC_TYPE_OS_BUF = 104,
DYNAMIC_TYPE_ASCON = 105,
DYNAMIC_TYPE_SNIFFER_SERVER = 1000,
DYNAMIC_TYPE_SNIFFER_SESSION = 1001,
DYNAMIC_TYPE_SNIFFER_PB = 1002,