Initial ASCON hash256 and AEAD128 support based on NIST SP 800-232 ipd

Implemented based on the NIST Initial Public Draft "NIST SP 800-232 ipd". Testing based on KAT's available at https://github.com/ascon/ascon-c. Added configuration for testing in github action.
This commit is contained in:
Juliusz Sosinowicz
2023-03-06 13:41:01 +01:00
parent 45b385ade3
commit e3a612300b
15 changed files with 7415 additions and 2 deletions

View File

@@ -40,6 +40,7 @@ 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',
]
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"])

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

@@ -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,7 @@
#define BENCH_BLAKE2B 0x00008000
#define BENCH_BLAKE2S 0x00010000
#define BENCH_SM3 0x00020000
#define BENCH_ASCON_HASH256 0x00040000
/* MAC algorithms. */
#define BENCH_CMAC 0x00000001
@@ -949,6 +954,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 }
};
@@ -3515,6 +3523,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);
@@ -7996,6 +8008,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

@@ -128,6 +128,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);

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

@@ -0,0 +1,465 @@
/* 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 */
#define MAX_ROUNDS 12
/* Table 4 */
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 6:
return 6;
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)
{
AsconState tmp;
/* 2.6.1 Addition of Constants */
a->s64[2] ^= round_constants[round];
/* 2.6.2 Substitution Layer */
a->s64[0] ^= a->s64[4];
a->s64[4] ^= a->s64[3];
a->s64[2] ^= a->s64[1];
tmp.s64[0] = a->s64[0] ^ (~a->s64[1] & a->s64[2]);
tmp.s64[2] = a->s64[2] ^ (~a->s64[3] & a->s64[4]);
tmp.s64[4] = a->s64[4] ^ (~a->s64[0] & a->s64[1]);
tmp.s64[1] = a->s64[1] ^ (~a->s64[2] & a->s64[3]);
tmp.s64[3] = a->s64[3] ^ (~a->s64[4] & a->s64[0]);
tmp.s64[1] ^= tmp.s64[0];
tmp.s64[3] ^= tmp.s64[2];
tmp.s64[0] ^= tmp.s64[4];
tmp.s64[2] = ~tmp.s64[2];
/* 2.6.3 Linear Diffusion Layer */
a->s64[4] =
tmp.s64[4] ^ rotrFixed64(tmp.s64[4], 7) ^ rotrFixed64(tmp.s64[4], 41);
a->s64[1] =
tmp.s64[1] ^ rotrFixed64(tmp.s64[1], 61) ^ rotrFixed64(tmp.s64[1], 39);
a->s64[3] =
tmp.s64[3] ^ rotrFixed64(tmp.s64[3], 10) ^ rotrFixed64(tmp.s64[3], 17);
a->s64[0] =
tmp.s64[0] ^ rotrFixed64(tmp.s64[0], 19) ^ rotrFixed64(tmp.s64[0], 28);
a->s64[2] =
tmp.s64[2] ^ rotrFixed64(tmp.s64[2], 1) ^ rotrFixed64(tmp.s64[2], 6);
}
static void permutation(AsconState* a, byte rounds)
{
byte i = start_index(rounds);
for (; i < MAX_ROUNDS; i++) {
ascon_round(a, i);
}
}
/* 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_Deinit(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_Deinit(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_Deinit(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_Deinit(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_Deinit(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 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;
}
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;
/* 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];
XMEMCPY(tag, &a->state.s64[3], ASCON_AEAD128_TAG_SZ);
/* Clear state as soon as possible */
wc_AsconAEAD128_Deinit(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;
}
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_Deinit(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:

6509
wolfcrypt/test/ascon-kat.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -13,6 +13,7 @@ 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

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,214 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t chacha20_poly1305_aead_test(void)
}
#endif /* HAVE_CHACHA && HAVE_POLY1305 */
#ifdef HAVE_ASCON
#include <wolfcrypt/test/ascon-kat.h>
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 */
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++) {
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, ascon_hash256_output[i], ASCON_HASH256_SZ) != 0)
return WC_TEST_RET_ENC_NC;
wc_AsconHash256_Deinit(&asconHash);
}
/* Test separated update */
for (i = 0; i < test_rounds; 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, ascon_hash256_output[i], ASCON_HASH256_SZ) != 0)
return WC_TEST_RET_ENC_NC;
wc_AsconHash256_Deinit(&asconHash);
}
return 0;
}
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ascon_aead128_test(void)
{
word32 i;
wc_AsconAEAD128 asconAEAD;
int err;
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++) {
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_Deinit(&asconAEAD);
}
}
return 0;
}
#endif /* HAVE_ASCON */
#ifndef NO_DES3
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t des_test(void)

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

@@ -0,0 +1,113 @@
/* 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
/* 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_KEY_SZ 16
#define ASCON_AEAD128_NONCE_SZ 16
#define ASCON_AEAD128_TAG_SZ 16
#define ASCON_AEAD128_RATE 16
typedef union AsconState {
word64 s64[5];
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 {
AsconState state;
byte lastBlkSz;
/* needed throughout both encrypt and decrypt */
word64 key[ASCON_AEAD128_KEY_SZ/sizeof(word64)];
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_Deinit(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_Deinit(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

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