mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-09 09:20:52 +02:00
Merge pull request #10807 from SparkiDev/aes_gcm_siv_asm
AES-GCM-SIV: Add implementation in C and assembly
This commit is contained in:
@@ -0,0 +1,207 @@
|
||||
name: AES-GCM-SIV (RFC 8452) tests
|
||||
|
||||
# START OF COMMON SECTION
|
||||
on:
|
||||
push:
|
||||
branches: [ 'release/**' ]
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
branches: [ '*' ]
|
||||
# Weekday-morning cron (10:00 UTC) seeds the master-scoped ccache that PR runs
|
||||
# restore (cross job only); re-runs --build-only on the default branch.
|
||||
schedule:
|
||||
- cron: '40 10 * * 1-5'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
# END OF COMMON SECTION
|
||||
|
||||
jobs:
|
||||
# Native x86_64 'make check'. These are --enable-cryptonly (WOLFCRYPT_ONLY)
|
||||
# builds, so check runs testwolfcrypt - which includes aesgcm_siv_test (the
|
||||
# RFC 8452 KATs) - but not the TLS-only tests/unit.test (the tests/api group,
|
||||
# test_wc_AesGcmSivEncryptDecrypt, needs a non-cryptonly build). One runner
|
||||
# per config:
|
||||
# - siv-c-only : no asm, software word64-table POLYVAL + C CTR.
|
||||
# - siv-word32 : GCM_WORD32 forces the word32-table software POLYVAL multiply.
|
||||
# - siv-small : GCM_SMALL forces the table-free software POLYVAL multiply.
|
||||
# - siv-intelasm : PCLMUL/AVX/VAES/AVX512 POLYVAL + pipelined CTR, whichever
|
||||
# the runner CPU selects at runtime.
|
||||
# - siv-all : SIV alongside --enable-all to catch integration regressions.
|
||||
# - siv-smallstack : SIV's key schedules / derived keys live on the stack.
|
||||
make_check:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
config:
|
||||
- '--enable-cryptonly --enable-aesgcm-siv'
|
||||
- '--enable-cryptonly --enable-aesgcm-siv CPPFLAGS=-DGCM_WORD32'
|
||||
- '--enable-cryptonly --enable-aesgcm-siv CPPFLAGS=-DGCM_SMALL'
|
||||
- '--enable-cryptonly --enable-intelasm --enable-sp-asm --enable-aesgcm-siv'
|
||||
- '--enable-cryptonly --enable-all-crypto --enable-intelasm --enable-sp-asm --enable-aesgcm-siv'
|
||||
- '--enable-cryptonly --enable-aesgcm-siv --enable-smallstack'
|
||||
name: make check (${{ matrix.config }})
|
||||
if: ${{ (github.repository_owner == 'wolfssl') && (github.event_name != 'pull_request' || github.event.pull_request.draft == false) }}
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 12
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
name: Checkout wolfSSL
|
||||
|
||||
- name: Build and test AES-GCM-SIV
|
||||
run: |
|
||||
./autogen.sh
|
||||
./configure ${{ matrix.config }}
|
||||
make -j 4
|
||||
make check
|
||||
|
||||
- name: Print errors
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
for file in scripts/*.log test-suite.log
|
||||
do
|
||||
if [ -f "$file" ]; then
|
||||
echo "${file}:"
|
||||
cat "$file"
|
||||
echo "========================================================================"
|
||||
fi
|
||||
done
|
||||
|
||||
# Cross-compiled AES-GCM-SIV asm paths, built out-of-tree in parallel and run
|
||||
# under qemu-user (binfmt). Covers:
|
||||
# - arm64-pmull : AArch64 PMULL POLYVAL (gcm_siv_arm64_crypto).
|
||||
# - arm64-no-hw-crypto : AArch64 NEON 8-bit-pmul + table POLYVAL
|
||||
# (gcm_siv_arm64_neon / _base) via WOLFSSL_ARMASM_NO_HW_CRYPTO.
|
||||
# - armhf-crypto : ARMv8-A 32-bit vmull.p64 POLYVAL (gcm_siv_arm32_crypto);
|
||||
# QEMU_CPU=max enables the crypto extensions.
|
||||
# - armhf-base : AArch32 software-table POLYVAL/CTR (gcm_siv_arm32_base)
|
||||
# via NO_HW_CRYPTO, run under the default (non-crypto) CPU.
|
||||
# Known gaps (a defect here would not be caught): the AArch64 base variant
|
||||
# (AES_GCMSIV_polyval_base) is compiled in every aarch64 armasm build but only
|
||||
# selected at runtime with NEON+HW-crypto both disabled, a config unsupported
|
||||
# upstream on aarch64 (no base SHA/ChaCha armasm); and Thumb-2 (gcm_siv_thumb2,
|
||||
# armv7-m) which qemu-user cannot run. Both are noted for release notes.
|
||||
cross_check:
|
||||
name: Cross-arch test
|
||||
if: ${{ (github.repository_owner == 'wolfssl') && (github.event_name != 'pull_request' || github.event.pull_request.draft == false) }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 25
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
name: Checkout wolfSSL
|
||||
|
||||
- name: Install dependencies
|
||||
uses: ./.github/actions/install-apt-deps
|
||||
with:
|
||||
packages: autoconf automake libtool build-essential crossbuild-essential-arm64 crossbuild-essential-armhf qemu-user
|
||||
ghcr-debs-tag: ubuntu-22.04-minimal
|
||||
|
||||
- name: Set up ccache
|
||||
uses: ./.github/actions/ccache-setup
|
||||
with:
|
||||
workflow-id: aesgcm-siv
|
||||
read-only: ${{ github.event_name == 'pull_request' }}
|
||||
max-size: 300M
|
||||
|
||||
- name: Build all configs (parallel, out-of-tree)
|
||||
run: |
|
||||
cat > "$RUNNER_TEMP/aesgcm-siv-configs.json" <<'EOF'
|
||||
[
|
||||
{"name": "arm64-pmull", "minutes": 6,
|
||||
"cc": "ccache aarch64-linux-gnu-gcc",
|
||||
"configure": ["--host=aarch64-linux-gnu", "--enable-cryptonly",
|
||||
"--enable-all-crypto", "--disable-examples", "--enable-armasm",
|
||||
"--enable-aesgcm-siv", "CFLAGS=-O2"],
|
||||
"check": false,
|
||||
"run": [["env", "QEMU_LD_PREFIX=/usr/aarch64-linux-gnu", "QEMU_CPU=max",
|
||||
"./wolfcrypt/test/testwolfcrypt"]]},
|
||||
{"name": "arm64-no-hw-crypto", "minutes": 6,
|
||||
"cc": "ccache aarch64-linux-gnu-gcc",
|
||||
"configure": ["--host=aarch64-linux-gnu", "--enable-cryptonly",
|
||||
"--enable-all-crypto", "--disable-examples", "--enable-armasm",
|
||||
"--enable-aesgcm-siv", "CPPFLAGS=-DWOLFSSL_ARMASM_NO_HW_CRYPTO",
|
||||
"CFLAGS=-O2"],
|
||||
"check": false,
|
||||
"run": [["env", "QEMU_LD_PREFIX=/usr/aarch64-linux-gnu", "QEMU_CPU=max",
|
||||
"./wolfcrypt/test/testwolfcrypt"]]},
|
||||
{"name": "armhf-crypto", "minutes": 6,
|
||||
"cc": "ccache arm-linux-gnueabihf-gcc",
|
||||
"comment": "--disable-aesgcm-stream: WOLFSSL_AESGCM_STREAM's software GHASH only defines its macros for __aarch64__ armasm, not 32-bit __arm__ armasm, so all-crypto + armasm otherwise fails to build aes.c (pre-existing, unrelated to SIV).",
|
||||
"configure": ["--host=arm-linux-gnueabihf", "--enable-cryptonly",
|
||||
"--enable-all-crypto", "--disable-examples", "--enable-armasm",
|
||||
"--enable-aesgcm-siv", "--disable-aesgcm-stream", "CFLAGS=-O2"],
|
||||
"check": false,
|
||||
"run": [["env", "QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf", "QEMU_CPU=max",
|
||||
"./wolfcrypt/test/testwolfcrypt"]]},
|
||||
{"name": "armhf-base", "minutes": 6,
|
||||
"cc": "ccache arm-linux-gnueabihf-gcc",
|
||||
"comment": "WOLFSSL_ARMASM_NO_HW_CRYPTO selects the AArch32 software-table POLYVAL/CTR (AES_GCMSIV_polyval_base/ctr_base). Run under the DEFAULT qemu CPU (no QEMU_CPU=max) so the crypto path is not taken - this is the only job exercising the base variant at runtime.",
|
||||
"configure": ["--host=arm-linux-gnueabihf", "--enable-cryptonly",
|
||||
"--enable-all-crypto", "--disable-examples", "--enable-armasm",
|
||||
"--enable-aesgcm-siv", "--disable-aesgcm-stream",
|
||||
"CPPFLAGS=-DWOLFSSL_ARMASM_NO_HW_CRYPTO", "CFLAGS=-O2"],
|
||||
"check": false,
|
||||
"run": [["env", "QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf",
|
||||
"./wolfcrypt/test/testwolfcrypt"]]}
|
||||
]
|
||||
EOF
|
||||
.github/scripts/parallel-make-check.py \
|
||||
${{ github.event_name == 'schedule' && '--build-only' || '' }} \
|
||||
"$RUNNER_TEMP/aesgcm-siv-configs.json"
|
||||
|
||||
- name: ccache stats
|
||||
if: always()
|
||||
run: ccache -s || true
|
||||
|
||||
- name: Upload logs on failure
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
retention-days: 7
|
||||
name: aesgcm-siv-cross-logs
|
||||
path: |
|
||||
build-*/make-check.log
|
||||
build-*/test-suite.log
|
||||
build-*/config.log
|
||||
if-no-files-found: ignore
|
||||
|
||||
# Windows MSVC/MASM: build wolfssl64.sln (AES-NI on by default => the MASM
|
||||
# aes_gcm_asm.asm POLYVAL/CTR is assembled with ml64) with WOLFSSL_AESGCM_SIV
|
||||
# enabled, and run testsuite.exe - which calls wolfcrypt_test() -> the RFC 8452
|
||||
# KATs incl. the 128-byte multi-block vector. This is the ONLY job that
|
||||
# exercises the Windows MASM SIV path; its absence let a High-severity
|
||||
# AES_GCMSIV_ctr register-clobber (wrong ciphertext + a 16-byte wild write)
|
||||
# ship undetected. x64 only: the AES-NI .asm is x86_64.
|
||||
windows_masm:
|
||||
name: Windows MASM AES-GCM-SIV (x64)
|
||||
if: ${{ (github.repository_owner == 'wolfssl') && (github.event_name != 'pull_request' || github.event.pull_request.draft == false) }}
|
||||
runs-on: windows-latest
|
||||
timeout-minutes: 12
|
||||
env:
|
||||
SOLUTION_FILE_PATH: wolfssl64.sln
|
||||
BUILD_CONFIGURATION: Release
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
name: Checkout wolfSSL
|
||||
|
||||
- name: Enable AES-GCM-SIV in user_settings.h
|
||||
shell: bash
|
||||
run: |
|
||||
# Add the define once, right after the first HAVE_AESGCM (AES-NI is
|
||||
# already enabled for x64 in this header).
|
||||
sed -i '0,/#define HAVE_AESGCM/s//#define HAVE_AESGCM\n#define WOLFSSL_AESGCM_SIV/' \
|
||||
IDE/WIN/user_settings.h
|
||||
grep -n 'WOLFSSL_AESGCM_SIV' IDE/WIN/user_settings.h
|
||||
|
||||
- name: Add MSBuild to PATH
|
||||
uses: microsoft/setup-msbuild@v3
|
||||
|
||||
- name: Restore NuGet packages
|
||||
run: nuget restore ${{ env.SOLUTION_FILE_PATH }}
|
||||
|
||||
- name: Build (x64, MASM)
|
||||
run: msbuild /m /p:PlatformToolset=v142 /p:Platform=x64 /p:Configuration=${{ env.BUILD_CONFIGURATION }} ${{ env.SOLUTION_FILE_PATH }}
|
||||
|
||||
- name: Run wolfCrypt KATs (incl. AES-GCM-SIV)
|
||||
run: Release/x64/testsuite.exe
|
||||
@@ -929,6 +929,7 @@ WOLFSSL_SE050_NO_TRNG
|
||||
WOLFSSL_SECURE_RENEGOTIATION_ON_BY_DEFAULT
|
||||
WOLFSSL_SERVER_EXAMPLE
|
||||
WOLFSSL_SETTINGS_FILE
|
||||
WOLFSSL_SGX_CPUID_AVX512_VAES
|
||||
WOLFSSL_SHA256_ALT_CH_MAJ
|
||||
WOLFSSL_SHA3_PPC64_BLOCKS_N
|
||||
WOLFSSL_SHA512_HASHTYPE
|
||||
|
||||
@@ -1213,6 +1213,18 @@ if(WOLFSSL_AESSIV)
|
||||
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_AES_SIV")
|
||||
endif()
|
||||
|
||||
# AES-GCM-SIV
|
||||
add_option("WOLFSSL_AESGCMSIV"
|
||||
"Enable AES-GCM-SIV (RFC 8452) support (default: disabled)"
|
||||
"no" "yes;no")
|
||||
|
||||
if(WOLFSSL_AESGCMSIV)
|
||||
if(NOT WOLFSSL_AESGCM)
|
||||
message(FATAL_ERROR "AES-GCM-SIV requires AES-GCM. Please enable WOLFSSL_AESGCM.")
|
||||
endif()
|
||||
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_AESGCM_SIV")
|
||||
endif()
|
||||
|
||||
# AES-CTR
|
||||
add_option("WOLFSSL_AESCTR"
|
||||
"Enable wolfSSL AES-CTR support (default: disabled)"
|
||||
|
||||
@@ -3536,6 +3536,25 @@ then
|
||||
ENABLED_AESSIV=yes
|
||||
fi
|
||||
|
||||
# AES-GCM-SIV (RFC 8452)
|
||||
AC_ARG_ENABLE([aesgcm-siv],
|
||||
[AS_HELP_STRING([--enable-aesgcm-siv],[Enable AES-GCM-SIV (RFC 8452) (default: disabled)])],
|
||||
[ ENABLED_AESGCMSIV=$enableval ],
|
||||
[ ENABLED_AESGCMSIV=no ]
|
||||
)
|
||||
|
||||
if test "$ENABLED_AESGCMSIV" = "yes"
|
||||
then
|
||||
if test "$ENABLED_AESGCM" = "no"
|
||||
then
|
||||
AC_MSG_ERROR([AES-GCM-SIV requires AES-GCM. Please enable it (--enable-aesgcm).])
|
||||
fi
|
||||
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AESGCM_SIV"
|
||||
# The generated AES-GCM-SIV assembly (aes_gcm_asm.S) is guarded by
|
||||
# WOLFSSL_AESGCM_SIV, so the assembler needs the define too.
|
||||
AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_AESGCM_SIV"
|
||||
fi
|
||||
|
||||
# AES-CTR
|
||||
AC_ARG_ENABLE([aesctr],
|
||||
[AS_HELP_STRING([--enable-aesctr],[Enable wolfSSL AES-CTR support (default: disabled)])],
|
||||
@@ -13013,6 +13032,7 @@ echo " * AES-OFB: $ENABLED_AESOFB"
|
||||
echo " * AES-XTS: $ENABLED_AESXTS"
|
||||
echo " * AES-XTS streaming: $ENABLED_AESXTS_STREAM"
|
||||
echo " * AES-SIV: $ENABLED_AESSIV"
|
||||
echo " * AES-GCM-SIV: $ENABLED_AESGCMSIV"
|
||||
echo " * AES-EAX: $ENABLED_AESEAX"
|
||||
echo " * AES Bitspliced: $ENABLED_AESBS"
|
||||
echo " * AES Key Wrap: $ENABLED_AESKEYWRAP"
|
||||
|
||||
@@ -3705,6 +3705,243 @@ int test_wc_AesGcmMixedEncDecLongIV(void)
|
||||
* AES-GCM non-standard nonce lengths
|
||||
******************************************************************************/
|
||||
|
||||
#if defined(WOLFSSL_AESGCM_SIV) && !defined(NO_AES) && defined(HAVE_AESGCM) && \
|
||||
defined(WOLFSSL_AES_128)
|
||||
/* Decode a hex string into 'out' (spaces ignored, NULL -> length 0).
|
||||
* Returns the byte length, or -1 on a malformed string / overflow. */
|
||||
static int gcmsiv_hex(const char* hex, byte* out, word32 max)
|
||||
{
|
||||
word32 n = 0;
|
||||
int hi, lo;
|
||||
|
||||
if (hex == NULL)
|
||||
return 0;
|
||||
while (*hex != '\0') {
|
||||
if (*hex == ' ') { hex++; continue; }
|
||||
if (hex[1] == '\0') return -1;
|
||||
hi = (*hex >= '0' && *hex <= '9') ? *hex - '0' :
|
||||
(*hex >= 'a' && *hex <= 'f') ? *hex - 'a' + 10 :
|
||||
(*hex >= 'A' && *hex <= 'F') ? *hex - 'A' + 10 : -1;
|
||||
hex++;
|
||||
lo = (*hex >= '0' && *hex <= '9') ? *hex - '0' :
|
||||
(*hex >= 'a' && *hex <= 'f') ? *hex - 'a' + 10 :
|
||||
(*hex >= 'A' && *hex <= 'F') ? *hex - 'A' + 10 : -1;
|
||||
hex++;
|
||||
if (hi < 0 || lo < 0 || n >= max) return -1;
|
||||
out[n++] = (byte)((hi << 4) | lo);
|
||||
}
|
||||
return (int)n;
|
||||
}
|
||||
|
||||
/* Run one RFC 8452 known-answer vector (expH = ciphertext || 16-byte tag):
|
||||
* encrypt and check ciphertext+tag, then decrypt and check the recovered
|
||||
* plaintext and that authentication succeeds. Returns 0 on a full match,
|
||||
* or a negative step code on the first failure. */
|
||||
static int gcmsiv_kat(const char* keyH, const char* nonceH, const char* aadH,
|
||||
const char* ptH, const char* expH)
|
||||
{
|
||||
byte key[32], nonce[12], aad[64], pt[64], exp[96], ct[80], tag[16], dec[64];
|
||||
int keySz, nonceSz, aadSz, ptSz, expSz;
|
||||
|
||||
keySz = gcmsiv_hex(keyH, key, (word32)sizeof(key));
|
||||
nonceSz = gcmsiv_hex(nonceH, nonce, (word32)sizeof(nonce));
|
||||
aadSz = gcmsiv_hex(aadH, aad, (word32)sizeof(aad));
|
||||
ptSz = gcmsiv_hex(ptH, pt, (word32)sizeof(pt));
|
||||
expSz = gcmsiv_hex(expH, exp, (word32)sizeof(exp));
|
||||
if (keySz < 0 || nonceSz < 0 || aadSz < 0 || ptSz < 0 || expSz < 0)
|
||||
return -1;
|
||||
if (expSz != ptSz + 16)
|
||||
return -2;
|
||||
|
||||
if (wc_AesGcmSivEncrypt(key, (word32)keySz, nonce, (word32)nonceSz,
|
||||
aad, (word32)aadSz, pt, (word32)ptSz, ct, tag, 16) != 0)
|
||||
return -3;
|
||||
if (ptSz > 0 && XMEMCMP(ct, exp, (size_t)ptSz) != 0)
|
||||
return -4;
|
||||
if (XMEMCMP(tag, exp + ptSz, 16) != 0)
|
||||
return -5;
|
||||
|
||||
if (wc_AesGcmSivDecrypt(key, (word32)keySz, nonce, (word32)nonceSz,
|
||||
aad, (word32)aadSz, ct, (word32)ptSz, dec, tag, 16) != 0)
|
||||
return -6;
|
||||
if (ptSz > 0 && XMEMCMP(dec, pt, (size_t)ptSz) != 0)
|
||||
return -7;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* WOLFSSL_AESGCM_SIV ... */
|
||||
|
||||
/*
|
||||
* AES-GCM-SIV (RFC 8452): RFC 8452 Appendix C known-answer vectors (encrypt and
|
||||
* decrypt), a full encrypt/decrypt round trip, authentication-failure handling
|
||||
* (corrupted tag / AAD / ciphertext), edge cases (empty plaintext, empty AAD,
|
||||
* AES-128 and AES-256), and an exhaustive invalid-parameter matrix.
|
||||
*/
|
||||
int test_wc_AesGcmSivEncryptDecrypt(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_AESGCM_SIV) && !defined(NO_AES) && defined(HAVE_AESGCM) && \
|
||||
defined(WOLFSSL_AES_128)
|
||||
byte key[32];
|
||||
byte nonce[12];
|
||||
byte aad[20];
|
||||
byte pt[32];
|
||||
byte ct[32];
|
||||
byte tag[16];
|
||||
byte dec[32];
|
||||
word32 i;
|
||||
|
||||
/* --- RFC 8452 Appendix C.1 known-answer vectors (AES-128) --- */
|
||||
ExpectIntEQ(gcmsiv_kat("01000000000000000000000000000000",
|
||||
"030000000000000000000000", NULL, NULL,
|
||||
"dc20e2d83f25705bb49e439eca56de25"), 0);
|
||||
ExpectIntEQ(gcmsiv_kat("01000000000000000000000000000000",
|
||||
"030000000000000000000000", NULL, "0100000000000000",
|
||||
"b5d839330ac7b786578782fff6013b815b287c22493a364c"), 0);
|
||||
ExpectIntEQ(gcmsiv_kat("01000000000000000000000000000000",
|
||||
"030000000000000000000000", NULL, "010000000000000000000000",
|
||||
"7323ea61d05932260047d942a4978db357391a0bc4fdec8b0d106639"), 0);
|
||||
ExpectIntEQ(gcmsiv_kat("01000000000000000000000000000000",
|
||||
"030000000000000000000000", "01", "0200000000000000",
|
||||
"1e6daba35669f4273b0a1a2560969cdf790d99759abd1508"), 0);
|
||||
ExpectIntEQ(gcmsiv_kat("01000000000000000000000000000000",
|
||||
"030000000000000000000000", "01",
|
||||
"02000000000000000000000000000000",
|
||||
"e2b0c5da79a901c1745f700525cb335b8f8936ec039e4e4bb97ebd8c4457441f"), 0);
|
||||
/* Non-block-aligned AAD (18 B) and plaintext (20 B). */
|
||||
ExpectIntEQ(gcmsiv_kat("01000000000000000000000000000000",
|
||||
"030000000000000000000000",
|
||||
"010000000000000000000000000000000200",
|
||||
"030000000000000000000000000000000400 0000",
|
||||
"6bb0fecf5ded9b77f902c7d5da236a4391dd029724afc9805e976f451e6d87f6"
|
||||
"fe106514"), 0);
|
||||
/* Non-block-aligned AAD (20 B) and plaintext (18 B). */
|
||||
ExpectIntEQ(gcmsiv_kat("01000000000000000000000000000000",
|
||||
"030000000000000000000000",
|
||||
"0100000000000000000000000000000002000000",
|
||||
"030000000000000000000000000000000400",
|
||||
"44d0aaf6fb2f1f34add5e8064e83e12a2adabff9b2ef00fb47920cc72a0c0f13"
|
||||
"b9fd"), 0);
|
||||
|
||||
#ifdef WOLFSSL_AES_256
|
||||
/* --- RFC 8452 Appendix C.2 known-answer vectors (AES-256) --- */
|
||||
ExpectIntEQ(gcmsiv_kat(
|
||||
"0100000000000000000000000000000000000000000000000000000000000000",
|
||||
"030000000000000000000000", NULL, NULL,
|
||||
"07f5f4169bbf55a8400cd47ea6fd400f"), 0);
|
||||
ExpectIntEQ(gcmsiv_kat(
|
||||
"0100000000000000000000000000000000000000000000000000000000000000",
|
||||
"030000000000000000000000", NULL, "0100000000000000",
|
||||
"c2ef328e5c71c83b843122130f7364b761e0b97427e3df28"), 0);
|
||||
ExpectIntEQ(gcmsiv_kat(
|
||||
"0100000000000000000000000000000000000000000000000000000000000000",
|
||||
"030000000000000000000000", NULL, "010000000000000000000000",
|
||||
"9aab2aeb3faa0a34aea8e2b18ca50da9ae6559e48fd10f6e5c9ca17e"), 0);
|
||||
#endif /* WOLFSSL_AES_256 */
|
||||
|
||||
/* --- Round trip + authentication-failure handling (AES-128) --- */
|
||||
for (i = 0; i < (word32)sizeof(key); i++) key[i] = (byte)i;
|
||||
for (i = 0; i < (word32)sizeof(nonce); i++) nonce[i] = (byte)(i + 1);
|
||||
for (i = 0; i < (word32)sizeof(aad); i++) aad[i] = (byte)(i + 2);
|
||||
for (i = 0; i < (word32)sizeof(pt); i++) pt[i] = (byte)(i + 3);
|
||||
|
||||
ExpectIntEQ(wc_AesGcmSivEncrypt(key, 16, nonce, 12, aad, sizeof(aad),
|
||||
pt, sizeof(pt), ct, tag, 16), 0);
|
||||
ExpectIntEQ(wc_AesGcmSivDecrypt(key, 16, nonce, 12, aad, sizeof(aad),
|
||||
ct, sizeof(pt), dec, tag, 16), 0);
|
||||
ExpectIntEQ(XMEMCMP(pt, dec, sizeof(pt)), 0);
|
||||
|
||||
/* Corrupted tag -> authentication failure. */
|
||||
tag[0] ^= 0xff;
|
||||
ExpectIntEQ(wc_AesGcmSivDecrypt(key, 16, nonce, 12, aad, sizeof(aad),
|
||||
ct, sizeof(pt), dec, tag, 16), WC_NO_ERR_TRACE(AES_GCM_AUTH_E));
|
||||
tag[0] ^= 0xff;
|
||||
/* Corrupted AAD -> authentication failure. */
|
||||
aad[0] ^= 0xff;
|
||||
ExpectIntEQ(wc_AesGcmSivDecrypt(key, 16, nonce, 12, aad, sizeof(aad),
|
||||
ct, sizeof(pt), dec, tag, 16), WC_NO_ERR_TRACE(AES_GCM_AUTH_E));
|
||||
aad[0] ^= 0xff;
|
||||
/* Corrupted ciphertext -> authentication failure. */
|
||||
ct[0] ^= 0xff;
|
||||
ExpectIntEQ(wc_AesGcmSivDecrypt(key, 16, nonce, 12, aad, sizeof(aad),
|
||||
ct, sizeof(pt), dec, tag, 16), WC_NO_ERR_TRACE(AES_GCM_AUTH_E));
|
||||
ct[0] ^= 0xff;
|
||||
|
||||
/* Edge cases: empty plaintext (tag only) and empty AAD. */
|
||||
ExpectIntEQ(wc_AesGcmSivEncrypt(key, 16, nonce, 12, NULL, 0, NULL, 0,
|
||||
NULL, tag, 16), 0);
|
||||
ExpectIntEQ(wc_AesGcmSivDecrypt(key, 16, nonce, 12, NULL, 0, NULL, 0,
|
||||
NULL, tag, 16), 0);
|
||||
|
||||
#ifdef WOLFSSL_AES_256
|
||||
/* AES-256 round trip. */
|
||||
ExpectIntEQ(wc_AesGcmSivEncrypt(key, 32, nonce, 12, aad, sizeof(aad),
|
||||
pt, sizeof(pt), ct, tag, 16), 0);
|
||||
ExpectIntEQ(wc_AesGcmSivDecrypt(key, 32, nonce, 12, aad, sizeof(aad),
|
||||
ct, sizeof(pt), dec, tag, 16), 0);
|
||||
ExpectIntEQ(XMEMCMP(pt, dec, sizeof(pt)), 0);
|
||||
#endif
|
||||
|
||||
/* --- Invalid parameters: encrypt --- */
|
||||
ExpectIntEQ(wc_AesGcmSivEncrypt(NULL, 16, nonce, 12, aad, sizeof(aad),
|
||||
pt, sizeof(pt), ct, tag, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_AesGcmSivEncrypt(key, 16, NULL, 12, aad, sizeof(aad),
|
||||
pt, sizeof(pt), ct, tag, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_AesGcmSivEncrypt(key, 16, nonce, 12, aad, sizeof(aad),
|
||||
pt, sizeof(pt), ct, NULL, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
/* in/out NULL while inSz != 0 */
|
||||
ExpectIntEQ(wc_AesGcmSivEncrypt(key, 16, nonce, 12, aad, sizeof(aad),
|
||||
NULL, sizeof(pt), ct, tag, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_AesGcmSivEncrypt(key, 16, nonce, 12, aad, sizeof(aad),
|
||||
pt, sizeof(pt), NULL, tag, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
/* aad NULL while aadSz != 0 */
|
||||
ExpectIntEQ(wc_AesGcmSivEncrypt(key, 16, nonce, 12, NULL, sizeof(aad),
|
||||
pt, sizeof(pt), ct, tag, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
/* invalid key sizes (only 16 and 32 allowed; 24/AES-192 is rejected) */
|
||||
ExpectIntEQ(wc_AesGcmSivEncrypt(key, 0, nonce, 12, aad, sizeof(aad),
|
||||
pt, sizeof(pt), ct, tag, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_AesGcmSivEncrypt(key, 15, nonce, 12, aad, sizeof(aad),
|
||||
pt, sizeof(pt), ct, tag, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_AesGcmSivEncrypt(key, 24, nonce, 12, aad, sizeof(aad),
|
||||
pt, sizeof(pt), ct, tag, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_AesGcmSivEncrypt(key, 33, nonce, 12, aad, sizeof(aad),
|
||||
pt, sizeof(pt), ct, tag, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
/* invalid nonce sizes (must be exactly 12) */
|
||||
ExpectIntEQ(wc_AesGcmSivEncrypt(key, 16, nonce, 0, aad, sizeof(aad),
|
||||
pt, sizeof(pt), ct, tag, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_AesGcmSivEncrypt(key, 16, nonce, 11, aad, sizeof(aad),
|
||||
pt, sizeof(pt), ct, tag, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_AesGcmSivEncrypt(key, 16, nonce, 13, aad, sizeof(aad),
|
||||
pt, sizeof(pt), ct, tag, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
/* invalid tag sizes (must be exactly 16) */
|
||||
ExpectIntEQ(wc_AesGcmSivEncrypt(key, 16, nonce, 12, aad, sizeof(aad),
|
||||
pt, sizeof(pt), ct, tag, 15), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_AesGcmSivEncrypt(key, 16, nonce, 12, aad, sizeof(aad),
|
||||
pt, sizeof(pt), ct, tag, 17), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* --- Invalid parameters: decrypt --- */
|
||||
ExpectIntEQ(wc_AesGcmSivDecrypt(NULL, 16, nonce, 12, aad, sizeof(aad),
|
||||
ct, sizeof(pt), dec, tag, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_AesGcmSivDecrypt(key, 16, NULL, 12, aad, sizeof(aad),
|
||||
ct, sizeof(pt), dec, tag, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_AesGcmSivDecrypt(key, 16, nonce, 12, aad, sizeof(aad),
|
||||
ct, sizeof(pt), dec, NULL, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_AesGcmSivDecrypt(key, 16, nonce, 12, aad, sizeof(aad),
|
||||
NULL, sizeof(pt), dec, tag, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_AesGcmSivDecrypt(key, 16, nonce, 12, aad, sizeof(aad),
|
||||
ct, sizeof(pt), NULL, tag, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_AesGcmSivDecrypt(key, 16, NULL, 12, NULL, sizeof(aad),
|
||||
ct, sizeof(pt), dec, tag, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_AesGcmSivDecrypt(key, 24, nonce, 12, aad, sizeof(aad),
|
||||
ct, sizeof(pt), dec, tag, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_AesGcmSivDecrypt(key, 16, nonce, 13, aad, sizeof(aad),
|
||||
ct, sizeof(pt), dec, tag, 16), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_AesGcmSivDecrypt(key, 16, nonce, 12, aad, sizeof(aad),
|
||||
ct, sizeof(pt), dec, tag, 17), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
#endif /* WOLFSSL_AESGCM_SIV && !NO_AES && HAVE_AESGCM && WOLFSSL_AES_128 */
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* Non-standard (non-96-bit) nonce tests for AES-GCM.
|
||||
*
|
||||
|
||||
@@ -51,6 +51,7 @@ int test_wc_AesGcmEncryptDecrypt_UnalignedBuffers(void);
|
||||
int test_wc_AesGcm_CrossCipher(void);
|
||||
int test_wc_AesGcmMixedEncDecLongIV(void);
|
||||
int test_wc_AesGcmNonStdNonce(void);
|
||||
int test_wc_AesGcmSivEncryptDecrypt(void);
|
||||
int test_wc_AesGcmStream(void);
|
||||
int test_wc_AesGcmStream_MidStreamState(void);
|
||||
int test_wc_AesGcmStream_ReinitAfterFinal(void);
|
||||
@@ -173,6 +174,7 @@ int test_wc_CryptoCb_Tls13_Key_No_Zero_Without_Offload(void);
|
||||
TEST_DECL_GROUP("aes", test_wc_AesGcm_CrossCipher), \
|
||||
TEST_DECL_GROUP("aes", test_wc_AesGcmMixedEncDecLongIV), \
|
||||
TEST_DECL_GROUP("aes", test_wc_AesGcmNonStdNonce), \
|
||||
TEST_DECL_GROUP("aes", test_wc_AesGcmSivEncryptDecrypt), \
|
||||
TEST_DECL_GROUP("aes", test_wc_AesGcmStream), \
|
||||
TEST_DECL_GROUP("aes", test_wc_AesGcmStream_MidStreamState), \
|
||||
TEST_DECL_GROUP("aes", test_wc_AesGcmStream_ReinitAfterFinal), \
|
||||
|
||||
@@ -829,6 +829,7 @@ static WC_INLINE void bench_append_memory_info(char* buffer, size_t size,
|
||||
#define BENCH_SM4_GCM 0x00100000
|
||||
#define BENCH_SM4_CCM 0x00200000
|
||||
#define BENCH_SM4 (BENCH_SM4_CBC | BENCH_SM4_GCM | BENCH_SM4_CCM)
|
||||
#define BENCH_AESGCM_SIV 0x00800000
|
||||
/* Digest algorithms. */
|
||||
#define BENCH_MD5 0x00000001
|
||||
#define BENCH_POLY1305 0x00000002
|
||||
@@ -1066,6 +1067,9 @@ static const bench_alg bench_cipher_opt[] = {
|
||||
#ifdef WOLFSSL_AES_SIV
|
||||
{ "-aes-siv", BENCH_AES_SIV },
|
||||
#endif
|
||||
#ifdef WOLFSSL_AESGCM_SIV
|
||||
{ "-aesgcm-siv", BENCH_AESGCM_SIV },
|
||||
#endif
|
||||
#ifdef HAVE_CAMELLIA
|
||||
{ "-camellia", BENCH_CAMELLIA },
|
||||
#endif
|
||||
@@ -4033,6 +4037,10 @@ static void* benchmarks_do(void* args)
|
||||
if (bench_all || (bench_cipher_algs & BENCH_AES_SIV))
|
||||
bench_aessiv();
|
||||
#endif
|
||||
#ifdef WOLFSSL_AESGCM_SIV
|
||||
if (bench_all || (bench_cipher_algs & BENCH_AESGCM_SIV))
|
||||
bench_aesgcmsiv();
|
||||
#endif
|
||||
#endif /* !NO_AES */
|
||||
|
||||
#ifdef HAVE_CAMELLIA
|
||||
@@ -6913,6 +6921,86 @@ void bench_aessiv(void)
|
||||
bench_aessiv_internal(bench_key, 64, "AES-512-SIV-enc", "AES-512-SIV-dec");
|
||||
}
|
||||
#endif /* WOLFSSL_AES_SIV */
|
||||
|
||||
#ifdef WOLFSSL_AESGCM_SIV
|
||||
static void bench_aesgcmsiv_internal(const byte* key, word32 keySz, const char*
|
||||
encLabel, const char* decLabel)
|
||||
{
|
||||
int i;
|
||||
int ret = 0;
|
||||
byte nonce[12];
|
||||
byte additional[AES_AUTH_ADD_SZ];
|
||||
byte tag[WC_AES_BLOCK_SIZE];
|
||||
int count = 0;
|
||||
double start;
|
||||
DECLARE_MULTI_VALUE_STATS_VARS()
|
||||
|
||||
XMEMSET(nonce, 0, sizeof(nonce));
|
||||
XMEMSET(additional, 0, sizeof(additional));
|
||||
|
||||
bench_stats_prepare();
|
||||
|
||||
bench_stats_start(&count, &start);
|
||||
do {
|
||||
for (i = 0; i < numBlocks; i++) {
|
||||
ret = wc_AesGcmSivEncrypt(key, keySz, nonce, sizeof(nonce),
|
||||
additional, aesAuthAddSz,
|
||||
bench_plain, bench_size, bench_cipher,
|
||||
tag, sizeof(tag));
|
||||
if (ret != 0) {
|
||||
printf("wc_AesGcmSivEncrypt failed (%d)\n", ret);
|
||||
return;
|
||||
}
|
||||
RECORD_MULTI_VALUE_STATS();
|
||||
}
|
||||
count += i;
|
||||
} while (bench_stats_check(start)
|
||||
#ifdef MULTI_VALUE_STATISTICS
|
||||
|| runs < minimum_runs
|
||||
#endif
|
||||
);
|
||||
|
||||
bench_stats_sym_finish(encLabel, 0, count, bench_size, start, ret);
|
||||
#ifdef MULTI_VALUE_STATISTICS
|
||||
bench_multi_value_stats(max, min, sum, squareSum, runs);
|
||||
#endif
|
||||
|
||||
RESET_MULTI_VALUE_STATS_VARS();
|
||||
|
||||
bench_stats_start(&count, &start);
|
||||
do {
|
||||
for (i = 0; i < numBlocks; i++) {
|
||||
ret = wc_AesGcmSivDecrypt(key, keySz, nonce, sizeof(nonce),
|
||||
additional, aesAuthAddSz,
|
||||
bench_cipher, bench_size, bench_plain,
|
||||
tag, sizeof(tag));
|
||||
if (ret != 0) {
|
||||
printf("wc_AesGcmSivDecrypt failed (%d)\n", ret);
|
||||
return;
|
||||
}
|
||||
RECORD_MULTI_VALUE_STATS();
|
||||
}
|
||||
count += i;
|
||||
} while (bench_stats_check(start)
|
||||
#ifdef MULTI_VALUE_STATISTICS
|
||||
|| runs < minimum_runs
|
||||
#endif
|
||||
);
|
||||
|
||||
bench_stats_sym_finish(decLabel, 0, count, bench_size, start, ret);
|
||||
#ifdef MULTI_VALUE_STATISTICS
|
||||
bench_multi_value_stats(max, min, sum, squareSum, runs);
|
||||
#endif
|
||||
}
|
||||
|
||||
void bench_aesgcmsiv(void)
|
||||
{
|
||||
bench_aesgcmsiv_internal(bench_key, 16, "AES-128-GCM-SIV-enc",
|
||||
"AES-128-GCM-SIV-dec");
|
||||
bench_aesgcmsiv_internal(bench_key, 32, "AES-256-GCM-SIV-enc",
|
||||
"AES-256-GCM-SIV-dec");
|
||||
}
|
||||
#endif /* WOLFSSL_AESGCM_SIV */
|
||||
#endif /* !NO_AES */
|
||||
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ void bench_aesctr(int useDeviceID);
|
||||
void bench_aescfb(void);
|
||||
void bench_aesofb(void);
|
||||
void bench_aessiv(void);
|
||||
void bench_aesgcmsiv(void);
|
||||
void bench_poly1305(void);
|
||||
void bench_camellia(void);
|
||||
void bench_sm4_cbc(void);
|
||||
|
||||
+1143
-6
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -53,6 +53,14 @@
|
||||
new_cpuid_flags |= CPUID_ADX;
|
||||
new_cpuid_flags |= CPUID_MOVBE;
|
||||
new_cpuid_flags |= CPUID_BMI1;
|
||||
#ifdef WOLFSSL_SGX_CPUID_AVX512_VAES
|
||||
/* CPUID is unavailable inside an SGX enclave, so the integrator
|
||||
* defines this macro to assert the target CPU implements VAES and
|
||||
* AVX512. This enables ALL VAES/AVX512-gated code (AES-GCM and the
|
||||
* rest), not just AES-GCM-SIV - only set it when that is true. */
|
||||
new_cpuid_flags |= CPUID_VAES;
|
||||
new_cpuid_flags |= CPUID_AVX512;
|
||||
#endif
|
||||
|
||||
(void)wolfSSL_Atomic_Uint_CompareExchange
|
||||
(&cpuid_flags, &old_cpuid_flags, new_cpuid_flags);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -877,6 +877,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t siphash_test(void);
|
||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t poly1305_test(void);
|
||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aesgcm_test(void);
|
||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aesgcm_default_test(void);
|
||||
#ifdef WOLFSSL_AESGCM_SIV
|
||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aesgcm_siv_test(void);
|
||||
#endif
|
||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t gmac_test(void);
|
||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aesccm_test(void);
|
||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aeskeywrap_test(void);
|
||||
@@ -2863,6 +2866,12 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\
|
||||
if (ret == 0) {
|
||||
TEST_PASS("AES-GCM test passed!\n");
|
||||
}
|
||||
#ifdef WOLFSSL_AESGCM_SIV
|
||||
if ((ret = aesgcm_siv_test()) != 0)
|
||||
TEST_FAIL("AES-GCM-SIV test failed!\n", ret);
|
||||
else
|
||||
TEST_PASS("AES-GCM-SIV test passed!\n");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_AESCCM) && defined(WOLFSSL_AES_128)
|
||||
@@ -20314,6 +20323,251 @@ static wc_test_ret_t aesgcm_aes256_large_test(Aes* enc, Aes* dec)
|
||||
}
|
||||
#endif /* WOLFSSL_AES_256 */
|
||||
|
||||
#ifdef WOLFSSL_AESGCM_SIV
|
||||
/* AES-GCM-SIV (RFC 8452) self test: known-answer vectors from RFC 8452
|
||||
* Appendix C (AES-128 C.1-2 and AES-256 C.2-2), an encrypt/decrypt round trip,
|
||||
* authentication-failure handling and invalid-parameter spot checks. The
|
||||
* exhaustive coverage lives in tests/api/test_aes.c. */
|
||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aesgcm_siv_test(void)
|
||||
{
|
||||
wc_test_ret_t ret = 0;
|
||||
#ifdef WOLFSSL_AES_128
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte key128[16] = {
|
||||
0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
||||
};
|
||||
#endif
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte nonce[12] = {
|
||||
0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
||||
};
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte pt8[8] = {
|
||||
0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
||||
};
|
||||
#ifdef WOLFSSL_AES_128
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte exp128[8] = {
|
||||
0xb5,0xd8,0x39,0x33,0x0a,0xc7,0xb7,0x86
|
||||
};
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte tag128[16] = {
|
||||
0x57,0x87,0x82,0xff,0xf6,0x01,0x3b,0x81,
|
||||
0x5b,0x28,0x7c,0x22,0x49,0x3a,0x36,0x4c
|
||||
};
|
||||
#endif
|
||||
#ifdef WOLFSSL_AES_256
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte key256[32] = {
|
||||
0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
||||
};
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte exp256[8] = {
|
||||
0xc2,0xef,0x32,0x8e,0x5c,0x71,0xc8,0x3b
|
||||
};
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte tag256[16] = {
|
||||
0x84,0x31,0x22,0x13,0x0f,0x73,0x64,0xb7,
|
||||
0x61,0xe0,0xb9,0x74,0x27,0xe3,0xdf,0x28
|
||||
};
|
||||
#endif
|
||||
/* Multi-block (128-byte) known-answer vectors: exercise the 64-byte CTR
|
||||
* loop and its tail past the first block. Self-generated with the
|
||||
* software reference (which passes the Wycheproof suite) and independent
|
||||
* of any one asm backend; <=1-block vectors cannot catch CTR round-count
|
||||
* or counter-pointer bugs (e.g. the Windows MASM AES_GCMSIV_ctr defect). */
|
||||
#ifdef WOLFSSL_AES_128
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte keyBig128[16] = {
|
||||
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
|
||||
0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10
|
||||
};
|
||||
#endif
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte nonceBig[12] = {
|
||||
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
|
||||
0x18,0x19,0x1a,0x1b
|
||||
};
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte aadBig[20] = {
|
||||
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,
|
||||
0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
|
||||
0xb0,0xb1,0xb2,0xb3
|
||||
};
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte ptBig[128] = {
|
||||
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
|
||||
0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
|
||||
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
|
||||
0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
|
||||
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
|
||||
0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
|
||||
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
|
||||
0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
|
||||
0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
|
||||
0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
|
||||
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
|
||||
0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
|
||||
0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
|
||||
0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
|
||||
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
|
||||
0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f
|
||||
};
|
||||
#ifdef WOLFSSL_AES_128
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte ctBig128Exp[128] = {
|
||||
0x4f,0x98,0x96,0x18,0x0d,0xc1,0x37,0x1f,
|
||||
0xf4,0xf1,0x7b,0x4b,0xff,0x28,0xd4,0x29,
|
||||
0x54,0x80,0x33,0xd0,0x7f,0xed,0xe0,0x23,
|
||||
0xd8,0x76,0x5d,0x28,0xad,0x2a,0x5e,0x37,
|
||||
0xeb,0xb7,0x64,0x87,0xb7,0x03,0x37,0xdd,
|
||||
0x72,0x5f,0xd1,0x1f,0xba,0xc2,0xdb,0x53,
|
||||
0x46,0x38,0xb9,0x30,0x5f,0x67,0x22,0x6b,
|
||||
0x96,0x10,0x06,0x36,0xe7,0xf5,0x88,0x53,
|
||||
0x5c,0x88,0x80,0xaf,0x83,0xc3,0x73,0x78,
|
||||
0xc4,0x59,0xb0,0x52,0x79,0x77,0xd3,0xdd,
|
||||
0x3f,0xfd,0x1f,0xed,0x34,0xaf,0xd2,0x53,
|
||||
0x4e,0xc2,0xb5,0x94,0x96,0xcd,0x03,0x11,
|
||||
0x52,0xcb,0x31,0x09,0x84,0x0f,0x8d,0xa4,
|
||||
0x4a,0x82,0x66,0xd9,0xb3,0xfe,0x22,0xa1,
|
||||
0xbc,0x04,0xb5,0x43,0x50,0x83,0xb9,0xd6,
|
||||
0x42,0xea,0xc5,0x75,0xe1,0x7f,0x42,0x04
|
||||
};
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte tagBig128Exp[16] = {
|
||||
0x6c,0x53,0xec,0xcc,0xd2,0x1b,0xdc,0x5a,
|
||||
0x45,0x7f,0x97,0xa4,0x79,0xb1,0x0c,0x52
|
||||
};
|
||||
#endif
|
||||
#ifdef WOLFSSL_AES_256
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte keyBig256[32] = {
|
||||
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
|
||||
0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,
|
||||
0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
|
||||
0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20
|
||||
};
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte ctBig256Exp[128] = {
|
||||
0x1a,0x16,0xea,0x46,0x31,0x0f,0x8e,0xe6,
|
||||
0x51,0x3a,0x56,0x0b,0x90,0xf6,0x3a,0x4e,
|
||||
0x09,0x25,0xf0,0x0a,0xfb,0xa5,0x58,0x36,
|
||||
0x9e,0xd7,0x96,0x59,0x24,0x8f,0xb6,0xdd,
|
||||
0xf1,0xc6,0xb6,0x75,0xf9,0x11,0x39,0x04,
|
||||
0x8d,0xa2,0xcb,0x0d,0x17,0x52,0x81,0x1b,
|
||||
0xf8,0x94,0xc4,0xd0,0x04,0xcc,0xcc,0xda,
|
||||
0xb6,0x85,0x26,0x66,0x40,0xaa,0xef,0x40,
|
||||
0xdb,0xbb,0xe1,0xbb,0x5e,0x57,0x0b,0x65,
|
||||
0x26,0x1c,0xde,0x3b,0x61,0xcd,0x96,0xb1,
|
||||
0xd9,0xe4,0x0b,0x13,0x2f,0xd3,0x48,0x41,
|
||||
0x58,0xa5,0xc7,0x33,0x45,0x03,0x3c,0xbf,
|
||||
0xe9,0x23,0x5e,0x6b,0x01,0xd0,0xe0,0x3a,
|
||||
0x90,0x81,0xd2,0x95,0x84,0x12,0x70,0x8e,
|
||||
0x79,0xdf,0xf4,0x95,0xbf,0x30,0x0c,0xad,
|
||||
0xe0,0x9a,0xa1,0x56,0xcd,0x70,0xd6,0x3b
|
||||
};
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte tagBig256Exp[16] = {
|
||||
0xeb,0x69,0x16,0x9f,0x11,0xd4,0x59,0x7c,
|
||||
0xc0,0x81,0xe7,0xf6,0x79,0x5c,0x7c,0xbb
|
||||
};
|
||||
#endif
|
||||
byte ctBig[128];
|
||||
byte tagBig[16];
|
||||
byte decBig[128];
|
||||
|
||||
byte ct[8];
|
||||
byte tag[16];
|
||||
byte dec[8];
|
||||
|
||||
#ifdef WOLFSSL_AES_128
|
||||
/* AES-128 known-answer (encrypt). */
|
||||
ret = wc_AesGcmSivEncrypt(key128, sizeof(key128), nonce, sizeof(nonce),
|
||||
NULL, 0, pt8, sizeof(pt8), ct, tag, sizeof(tag));
|
||||
if (ret != 0)
|
||||
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
|
||||
if (XMEMCMP(ct, exp128, sizeof(exp128)) != 0)
|
||||
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
|
||||
if (XMEMCMP(tag, tag128, sizeof(tag128)) != 0)
|
||||
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
|
||||
/* Decrypt round trip. */
|
||||
ret = wc_AesGcmSivDecrypt(key128, sizeof(key128), nonce, sizeof(nonce),
|
||||
NULL, 0, ct, sizeof(ct), dec, tag, sizeof(tag));
|
||||
if (ret != 0)
|
||||
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
|
||||
if (XMEMCMP(dec, pt8, sizeof(pt8)) != 0)
|
||||
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
|
||||
/* Tampered tag must fail authentication. */
|
||||
tag[0] ^= 0xff;
|
||||
if (wc_AesGcmSivDecrypt(key128, sizeof(key128), nonce, sizeof(nonce),
|
||||
NULL, 0, ct, sizeof(ct), dec, tag, sizeof(tag)) !=
|
||||
WC_NO_ERR_TRACE(AES_GCM_AUTH_E))
|
||||
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
|
||||
tag[0] ^= 0xff;
|
||||
#endif /* WOLFSSL_AES_128 */
|
||||
|
||||
#ifdef WOLFSSL_AES_256
|
||||
/* AES-256 known-answer + round trip. */
|
||||
ret = wc_AesGcmSivEncrypt(key256, sizeof(key256), nonce, sizeof(nonce),
|
||||
NULL, 0, pt8, sizeof(pt8), ct, tag, sizeof(tag));
|
||||
if (ret != 0)
|
||||
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
|
||||
if (XMEMCMP(ct, exp256, sizeof(exp256)) != 0)
|
||||
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
|
||||
if (XMEMCMP(tag, tag256, sizeof(tag256)) != 0)
|
||||
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
|
||||
ret = wc_AesGcmSivDecrypt(key256, sizeof(key256), nonce, sizeof(nonce),
|
||||
NULL, 0, ct, sizeof(ct), dec, tag, sizeof(tag));
|
||||
if (ret != 0)
|
||||
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
|
||||
if (XMEMCMP(dec, pt8, sizeof(pt8)) != 0)
|
||||
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
|
||||
#endif /* WOLFSSL_AES_256 */
|
||||
|
||||
#ifdef WOLFSSL_AES_128
|
||||
/* AES-128 multi-block known-answer + round trip (128-byte plaintext). */
|
||||
ret = wc_AesGcmSivEncrypt(keyBig128, sizeof(keyBig128), nonceBig,
|
||||
sizeof(nonceBig), aadBig, sizeof(aadBig), ptBig, sizeof(ptBig),
|
||||
ctBig, tagBig, sizeof(tagBig));
|
||||
if (ret != 0)
|
||||
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
|
||||
if (XMEMCMP(ctBig, ctBig128Exp, sizeof(ctBig128Exp)) != 0)
|
||||
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
|
||||
if (XMEMCMP(tagBig, tagBig128Exp, sizeof(tagBig128Exp)) != 0)
|
||||
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
|
||||
ret = wc_AesGcmSivDecrypt(keyBig128, sizeof(keyBig128), nonceBig,
|
||||
sizeof(nonceBig), aadBig, sizeof(aadBig), ctBig, sizeof(ptBig),
|
||||
decBig, tagBig, sizeof(tagBig));
|
||||
if (ret != 0)
|
||||
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
|
||||
if (XMEMCMP(decBig, ptBig, sizeof(ptBig)) != 0)
|
||||
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
|
||||
#endif /* WOLFSSL_AES_128 */
|
||||
#ifdef WOLFSSL_AES_256
|
||||
ret = wc_AesGcmSivEncrypt(keyBig256, sizeof(keyBig256), nonceBig,
|
||||
sizeof(nonceBig), aadBig, sizeof(aadBig), ptBig, sizeof(ptBig),
|
||||
ctBig, tagBig, sizeof(tagBig));
|
||||
if (ret != 0)
|
||||
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
|
||||
if (XMEMCMP(ctBig, ctBig256Exp, sizeof(ctBig256Exp)) != 0)
|
||||
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
|
||||
if (XMEMCMP(tagBig, tagBig256Exp, sizeof(tagBig256Exp)) != 0)
|
||||
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
|
||||
ret = wc_AesGcmSivDecrypt(keyBig256, sizeof(keyBig256), nonceBig,
|
||||
sizeof(nonceBig), aadBig, sizeof(aadBig), ctBig, sizeof(ptBig),
|
||||
decBig, tagBig, sizeof(tagBig));
|
||||
if (ret != 0)
|
||||
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
|
||||
if (XMEMCMP(decBig, ptBig, sizeof(ptBig)) != 0)
|
||||
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
|
||||
#endif /* WOLFSSL_AES_256 */
|
||||
|
||||
/* Invalid-parameter spot checks (NULL key; AES-192 key size rejected).
|
||||
* Key-size-agnostic (no key128) so these run in AES-256-only builds too;
|
||||
* both are rejected before the key bytes are read, so ptBig is just a
|
||||
* non-NULL pointer. */
|
||||
if (wc_AesGcmSivEncrypt(NULL, 16, nonce, sizeof(nonce),
|
||||
NULL, 0, pt8, sizeof(pt8), ct, tag, sizeof(tag)) !=
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG))
|
||||
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
|
||||
if (wc_AesGcmSivEncrypt(ptBig, 24, nonce, sizeof(nonce),
|
||||
NULL, 0, pt8, sizeof(pt8), ct, tag, sizeof(tag)) !=
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG))
|
||||
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
#endif /* WOLFSSL_AESGCM_SIV */
|
||||
|
||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aesgcm_test(void)
|
||||
{
|
||||
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
|
||||
|
||||
@@ -824,6 +824,30 @@ int wc_AesSivDecrypt_ex(const byte* key, word32 keySz, const AesSivAssoc* assoc,
|
||||
const byte* in, word32 inSz, byte* siv, byte* out);
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_AESGCM_SIV
|
||||
/* AES-GCM-SIV (RFC 8452): nonce-misuse resistant AEAD.
|
||||
* key : key-generating-key, 16 (AES-128) or 32 (AES-256) bytes.
|
||||
* nonce : 12 bytes.
|
||||
* tag : 16 bytes (the RFC 8452 authentication tag).
|
||||
* The encrypted output is the same length as the plaintext; the tag is
|
||||
* returned separately.
|
||||
*
|
||||
* The POLYVAL hash is constant-time wherever the CPU provides carry-less
|
||||
* multiply (x86 PCLMUL, Arm PMULL/VMULL) - the runtime default on such CPUs.
|
||||
* Software-only builds fall back to a key-dependent 4-bit table (a cache-timing
|
||||
* trade-off matching GCM_TABLE GHASH); GCM_SMALL avoids the table entirely. */
|
||||
WOLFSSL_API WARN_UNUSED_RESULT
|
||||
int wc_AesGcmSivEncrypt(const byte* key, word32 keySz, const byte* nonce,
|
||||
word32 nonceSz, const byte* aad, word32 aadSz,
|
||||
const byte* in, word32 inSz, byte* out,
|
||||
byte* tag, word32 tagSz);
|
||||
WOLFSSL_API WARN_UNUSED_RESULT
|
||||
int wc_AesGcmSivDecrypt(const byte* key, word32 keySz, const byte* nonce,
|
||||
word32 nonceSz, const byte* aad, word32 aadSz,
|
||||
const byte* in, word32 inSz, byte* out,
|
||||
const byte* tag, word32 tagSz);
|
||||
#endif /* WOLFSSL_AESGCM_SIV */
|
||||
|
||||
#ifdef WOLFSSL_CMAC
|
||||
/* forward declaration, in case aes.h is being included by cmac.h */
|
||||
struct Cmac;
|
||||
|
||||
Reference in New Issue
Block a user