mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 10:50:53 +02:00
Add SHE (Secure Hardware Extension) support to wolfCrypt
This commit is contained in:
@@ -42,6 +42,8 @@ jobs:
|
||||
'--enable-dtls --enable-dtlscid --enable-dtls13 --enable-secure-renegotiation
|
||||
--enable-psk --enable-aesccm --enable-nullcipher
|
||||
CPPFLAGS=-DWOLFSSL_STATIC_RSA',
|
||||
'--enable-she --enable-cmac',
|
||||
'--enable-she --enable-cmac --enable-cryptocb --enable-cryptocbutils',
|
||||
'--enable-all CPPFLAGS=''-DNO_AES_192 -DNO_AES_256'' ',
|
||||
'--enable-sniffer --enable-curve25519 --enable-curve448 --enable-enckeys
|
||||
CPPFLAGS=-DWOLFSSL_DH_EXTRA',
|
||||
|
||||
@@ -888,6 +888,8 @@ WOLFSSL_SE050_NO_TRNG
|
||||
WOLFSSL_SECURE_RENEGOTIATION_ON_BY_DEFAULT
|
||||
WOLFSSL_SERVER_EXAMPLE
|
||||
WOLFSSL_SETTINGS_FILE
|
||||
WOLFSSL_SHE
|
||||
WOLFSSL_SH224
|
||||
WOLFSSL_SHA256_ALT_CH_MAJ
|
||||
WOLFSSL_SHA512_HASHTYPE
|
||||
WOLFSSL_SHUTDOWNONCE
|
||||
|
||||
@@ -1640,6 +1640,20 @@ if(WOLFSSL_CMAC)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# SHE (Secure Hardware Extension) key update message generation
|
||||
add_option("WOLFSSL_SHE"
|
||||
"Enable SHE key update support (default: disabled)"
|
||||
"no" "yes;no")
|
||||
|
||||
if(WOLFSSL_SHE)
|
||||
if (NOT WOLFSSL_AES)
|
||||
message(FATAL_ERROR "Cannot use SHE without AES.")
|
||||
else()
|
||||
list(APPEND WOLFSSL_DEFINITIONS
|
||||
"-DWOLFSSL_SHE")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# TODO: - RC2
|
||||
# - FIPS, again (there's more logic for FIPS in configure.ac)
|
||||
# - Selftest
|
||||
@@ -2816,6 +2830,7 @@ if(WOLFSSL_EXAMPLES)
|
||||
tests/api/test_hash.c
|
||||
tests/api/test_hmac.c
|
||||
tests/api/test_cmac.c
|
||||
tests/api/test_she.c
|
||||
tests/api/test_des3.c
|
||||
tests/api/test_chacha.c
|
||||
tests/api/test_poly1305.c
|
||||
|
||||
@@ -5945,6 +5945,15 @@ fi
|
||||
AS_IF([test "x$ENABLED_CMAC" = "xyes"],
|
||||
[AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CMAC -DWOLFSSL_AES_DIRECT"])
|
||||
|
||||
# SHE (Secure Hardware Extension) key update message generation
|
||||
AC_ARG_ENABLE([she],
|
||||
[AS_HELP_STRING([--enable-she],[Enable SHE key update support (default: disabled)])],
|
||||
[ ENABLED_SHE=$enableval ],
|
||||
[ ENABLED_SHE=no ]
|
||||
)
|
||||
|
||||
AS_IF([test "x$ENABLED_SHE" = "xyes"],
|
||||
[AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHE"])
|
||||
|
||||
# AES-XTS
|
||||
AC_ARG_ENABLE([aesxts],
|
||||
@@ -11555,6 +11564,7 @@ AM_CONDITIONAL([BUILD_FIPS_V6],[test $HAVE_FIPS_VERSION = 6])
|
||||
AM_CONDITIONAL([BUILD_FIPS_V6_PLUS],[test $HAVE_FIPS_VERSION -ge 6])
|
||||
AM_CONDITIONAL([BUILD_SIPHASH],[test "x$ENABLED_SIPHASH" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
|
||||
AM_CONDITIONAL([BUILD_CMAC],[test "x$ENABLED_CMAC" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
|
||||
AM_CONDITIONAL([BUILD_SHE],[test "x$ENABLED_SHE" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
|
||||
AM_CONDITIONAL([BUILD_SELFTEST],[test "x$ENABLED_SELFTEST" = "xyes"])
|
||||
AM_CONDITIONAL([BUILD_SHA224],[test "x$ENABLED_SHA224" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
|
||||
AM_CONDITIONAL([BUILD_SHA3],[test "x$ENABLED_SHA3" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"])
|
||||
|
||||
@@ -159,6 +159,10 @@ if BUILD_CMAC
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/cmac.c
|
||||
endif
|
||||
|
||||
if BUILD_SHE
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/she.c
|
||||
endif
|
||||
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/fips.c \
|
||||
wolfcrypt/src/fips_test.c
|
||||
|
||||
@@ -424,6 +428,10 @@ if BUILD_CMAC
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/cmac.c
|
||||
endif
|
||||
|
||||
if BUILD_SHE
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/she.c
|
||||
endif
|
||||
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/fips.c \
|
||||
wolfcrypt/src/fips_test.c
|
||||
|
||||
@@ -677,6 +685,10 @@ if BUILD_CMAC
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/cmac.c
|
||||
endif
|
||||
|
||||
if BUILD_SHE
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/she.c
|
||||
endif
|
||||
|
||||
if BUILD_CURVE448
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/curve448.c
|
||||
endif
|
||||
@@ -1009,6 +1021,10 @@ if !BUILD_FIPS_V2_PLUS
|
||||
if BUILD_CMAC
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/cmac.c
|
||||
endif
|
||||
|
||||
if BUILD_SHE
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/she.c
|
||||
endif
|
||||
endif !BUILD_FIPS_V2_PLUS
|
||||
|
||||
if !BUILD_FIPS_V2
|
||||
|
||||
@@ -202,6 +202,7 @@
|
||||
#include <tests/api/test_hash.h>
|
||||
#include <tests/api/test_hmac.h>
|
||||
#include <tests/api/test_cmac.h>
|
||||
#include <tests/api/test_she.h>
|
||||
#include <tests/api/test_des3.h>
|
||||
#include <tests/api/test_chacha.h>
|
||||
#include <tests/api/test_poly1305.h>
|
||||
@@ -35635,6 +35636,11 @@ TEST_CASE testCases[] = {
|
||||
TEST_HMAC_DECLS,
|
||||
/* CMAC */
|
||||
TEST_CMAC_DECLS,
|
||||
/* SHE */
|
||||
TEST_SHE_DECLS,
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
TEST_SHE_CB_DECLS,
|
||||
#endif
|
||||
|
||||
/* Cipher */
|
||||
/* Triple-DES */
|
||||
|
||||
@@ -18,6 +18,8 @@ tests_unit_test_SOURCES += tests/api/test_hash.c
|
||||
# MAC
|
||||
tests_unit_test_SOURCES += tests/api/test_hmac.c
|
||||
tests_unit_test_SOURCES += tests/api/test_cmac.c
|
||||
# SHE
|
||||
tests_unit_test_SOURCES += tests/api/test_she.c
|
||||
# Cipher
|
||||
tests_unit_test_SOURCES += tests/api/test_des3.c
|
||||
tests_unit_test_SOURCES += tests/api/test_chacha.c
|
||||
@@ -124,6 +126,7 @@ EXTRA_DIST += tests/api/test_digest.h
|
||||
EXTRA_DIST += tests/api/test_hash.h
|
||||
EXTRA_DIST += tests/api/test_hmac.h
|
||||
EXTRA_DIST += tests/api/test_cmac.h
|
||||
EXTRA_DIST += tests/api/test_she.h
|
||||
EXTRA_DIST += tests/api/test_des3.h
|
||||
EXTRA_DIST += tests/api/test_chacha.h
|
||||
EXTRA_DIST += tests/api/test_poly1305.h
|
||||
|
||||
@@ -0,0 +1,875 @@
|
||||
/* test_she.c
|
||||
*
|
||||
* Copyright (C) 2006-2026 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 3 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
|
||||
*/
|
||||
|
||||
#include <tests/unit.h>
|
||||
|
||||
#ifdef NO_INLINE
|
||||
#include <wolfssl/wolfcrypt/misc.h>
|
||||
#else
|
||||
#define WOLFSSL_MISC_INCLUDED
|
||||
#include <wolfcrypt/src/misc.c>
|
||||
#endif
|
||||
|
||||
#include <wolfssl/wolfcrypt/she.h>
|
||||
#include <wolfssl/wolfcrypt/types.h>
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
#include <wolfssl/wolfcrypt/cryptocb.h>
|
||||
#endif
|
||||
#include <tests/api/api.h>
|
||||
#include <tests/api/test_she.h>
|
||||
|
||||
/*
|
||||
* Testing wc_SHE_Init()
|
||||
*/
|
||||
int test_wc_SHE_Init(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_SHE) && !defined(NO_AES)
|
||||
wc_SHE she;
|
||||
|
||||
/* Valid init with default heap/devId */
|
||||
ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0);
|
||||
|
||||
/* Verify heap and devId are stored correctly */
|
||||
ExpectTrue(she.heap == NULL);
|
||||
ExpectIntEQ(she.devId, INVALID_DEVID);
|
||||
|
||||
/* Verify state flags are zeroed */
|
||||
ExpectIntEQ(she.generated, 0);
|
||||
ExpectIntEQ(she.verified, 0);
|
||||
|
||||
/* Verify key material is zeroed */
|
||||
{
|
||||
byte zeros[WC_SHE_KEY_SZ] = {0};
|
||||
ExpectIntEQ(XMEMCMP(she.authKey, zeros, WC_SHE_KEY_SZ), 0);
|
||||
ExpectIntEQ(XMEMCMP(she.newKey, zeros, WC_SHE_KEY_SZ), 0);
|
||||
}
|
||||
|
||||
wc_SHE_Free(&she);
|
||||
|
||||
/* Test bad args: NULL pointer */
|
||||
ExpectIntEQ(wc_SHE_Init(NULL, NULL, INVALID_DEVID),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_SHE_Init */
|
||||
|
||||
/*
|
||||
* Testing wc_SHE_Free()
|
||||
*/
|
||||
int test_wc_SHE_Free(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_SHE) && !defined(NO_AES)
|
||||
wc_SHE she;
|
||||
|
||||
/* Init, then free — should scrub key material */
|
||||
ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0);
|
||||
wc_SHE_Free(&she);
|
||||
|
||||
/* After free, context should be zeroed */
|
||||
ExpectIntEQ(she.devId, 0);
|
||||
ExpectIntEQ(she.generated, 0);
|
||||
ExpectIntEQ(she.verified, 0);
|
||||
|
||||
/* Free with NULL should not crash */
|
||||
wc_SHE_Free(NULL);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_SHE_Free */
|
||||
|
||||
/*
|
||||
* Testing wc_SHE_Init_Id()
|
||||
*/
|
||||
int test_wc_SHE_Init_Id(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_SHE) && !defined(NO_AES) && defined(WOLF_PRIVATE_KEY_ID)
|
||||
wc_SHE she;
|
||||
unsigned char testId[] = {0x01, 0x02, 0x03, 0x04};
|
||||
|
||||
/* Valid init with a 4-byte key ID */
|
||||
ExpectIntEQ(wc_SHE_Init_Id(&she, testId, (int)sizeof(testId),
|
||||
NULL, INVALID_DEVID), 0);
|
||||
|
||||
/* Verify the ID was copied and length is set */
|
||||
ExpectIntEQ(she.idLen, (int)sizeof(testId));
|
||||
ExpectIntEQ(XMEMCMP(she.id, testId, sizeof(testId)), 0);
|
||||
|
||||
/* Verify label length is cleared */
|
||||
ExpectIntEQ(she.labelLen, 0);
|
||||
|
||||
/* Verify heap and devId are stored */
|
||||
ExpectTrue(she.heap == NULL);
|
||||
ExpectIntEQ(she.devId, INVALID_DEVID);
|
||||
|
||||
wc_SHE_Free(&she);
|
||||
|
||||
/* Test bad args: NULL she pointer */
|
||||
ExpectIntEQ(wc_SHE_Init_Id(NULL, testId, (int)sizeof(testId),
|
||||
NULL, INVALID_DEVID),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* Test bad args: ID length too large */
|
||||
ExpectIntEQ(wc_SHE_Init_Id(&she, testId, WC_SHE_MAX_ID_LEN + 1,
|
||||
NULL, INVALID_DEVID),
|
||||
WC_NO_ERR_TRACE(BUFFER_E));
|
||||
|
||||
/* Test bad args: negative ID length */
|
||||
ExpectIntEQ(wc_SHE_Init_Id(&she, testId, -1, NULL, INVALID_DEVID),
|
||||
WC_NO_ERR_TRACE(BUFFER_E));
|
||||
|
||||
/* Test zero-length ID is valid */
|
||||
ExpectIntEQ(wc_SHE_Init_Id(&she, testId, 0, NULL, INVALID_DEVID), 0);
|
||||
ExpectIntEQ(she.idLen, 0);
|
||||
wc_SHE_Free(&she);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_SHE_Init_Id */
|
||||
|
||||
/*
|
||||
* Testing wc_SHE_Init_Label()
|
||||
*/
|
||||
int test_wc_SHE_Init_Label(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_SHE) && !defined(NO_AES) && defined(WOLF_PRIVATE_KEY_ID)
|
||||
wc_SHE she;
|
||||
const char* testLabel = "my_she_key";
|
||||
|
||||
/* Valid init with a label string */
|
||||
ExpectIntEQ(wc_SHE_Init_Label(&she, testLabel, NULL, INVALID_DEVID), 0);
|
||||
|
||||
/* Verify the label was copied and length is set */
|
||||
ExpectIntEQ(she.labelLen, (int)XSTRLEN(testLabel));
|
||||
ExpectIntEQ(XMEMCMP(she.label, testLabel, XSTRLEN(testLabel)), 0);
|
||||
|
||||
/* Verify ID length is cleared */
|
||||
ExpectIntEQ(she.idLen, 0);
|
||||
|
||||
/* Verify heap and devId are stored */
|
||||
ExpectTrue(she.heap == NULL);
|
||||
ExpectIntEQ(she.devId, INVALID_DEVID);
|
||||
|
||||
wc_SHE_Free(&she);
|
||||
|
||||
/* Test bad args: NULL she pointer */
|
||||
ExpectIntEQ(wc_SHE_Init_Label(NULL, testLabel, NULL, INVALID_DEVID),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* Test bad args: NULL label */
|
||||
ExpectIntEQ(wc_SHE_Init_Label(&she, NULL, NULL, INVALID_DEVID),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* Test bad args: empty label */
|
||||
ExpectIntEQ(wc_SHE_Init_Label(&she, "", NULL, INVALID_DEVID),
|
||||
WC_NO_ERR_TRACE(BUFFER_E));
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_SHE_Init_Label */
|
||||
|
||||
/*
|
||||
* Testing wc_SHE_SetUID()
|
||||
*/
|
||||
int test_wc_SHE_SetUID(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_SHE) && !defined(NO_AES)
|
||||
wc_SHE she;
|
||||
byte uid[WC_SHE_UID_SZ] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
|
||||
};
|
||||
|
||||
ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0);
|
||||
|
||||
/* Valid UID */
|
||||
ExpectIntEQ(wc_SHE_SetUID(&she, uid, WC_SHE_UID_SZ, NULL), 0);
|
||||
ExpectIntEQ(XMEMCMP(she.uid, uid, WC_SHE_UID_SZ), 0);
|
||||
|
||||
/* Bad args */
|
||||
ExpectIntEQ(wc_SHE_SetUID(NULL, uid, WC_SHE_UID_SZ, NULL),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SHE_SetUID(&she, NULL, WC_SHE_UID_SZ, NULL),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SHE_SetUID(&she, uid, WC_SHE_UID_SZ - 1, NULL),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SHE_SetUID(&she, uid, WC_SHE_UID_SZ + 1, NULL),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
wc_SHE_Free(&she);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_SHE_SetUID */
|
||||
|
||||
/*
|
||||
* Testing wc_SHE_SetAuthKey()
|
||||
*/
|
||||
int test_wc_SHE_SetAuthKey(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_SHE) && !defined(NO_AES)
|
||||
wc_SHE she;
|
||||
byte key[WC_SHE_KEY_SZ] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
|
||||
};
|
||||
|
||||
ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0);
|
||||
|
||||
/* Valid auth key */
|
||||
ExpectIntEQ(wc_SHE_SetAuthKey(&she, WC_SHE_MASTER_ECU_KEY_ID,
|
||||
key, WC_SHE_KEY_SZ), 0);
|
||||
ExpectIntEQ(she.authKeyId, WC_SHE_MASTER_ECU_KEY_ID);
|
||||
ExpectIntEQ(XMEMCMP(she.authKey, key, WC_SHE_KEY_SZ), 0);
|
||||
|
||||
/* Bad args */
|
||||
ExpectIntEQ(wc_SHE_SetAuthKey(NULL, 0, key, WC_SHE_KEY_SZ),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SHE_SetAuthKey(&she, 0, NULL, WC_SHE_KEY_SZ),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SHE_SetAuthKey(&she, 0, key, WC_SHE_KEY_SZ - 1),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
wc_SHE_Free(&she);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_SHE_SetAuthKey */
|
||||
|
||||
/*
|
||||
* Testing wc_SHE_SetNewKey()
|
||||
*/
|
||||
int test_wc_SHE_SetNewKey(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_SHE) && !defined(NO_AES)
|
||||
wc_SHE she;
|
||||
byte key[WC_SHE_KEY_SZ] = {
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
|
||||
};
|
||||
|
||||
ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0);
|
||||
|
||||
/* Valid new key */
|
||||
ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, key, WC_SHE_KEY_SZ), 0);
|
||||
ExpectIntEQ(she.targetKeyId, 4);
|
||||
ExpectIntEQ(XMEMCMP(she.newKey, key, WC_SHE_KEY_SZ), 0);
|
||||
|
||||
/* Bad args */
|
||||
ExpectIntEQ(wc_SHE_SetNewKey(NULL, 4, key, WC_SHE_KEY_SZ),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, NULL, WC_SHE_KEY_SZ),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, key, 0),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
wc_SHE_Free(&she);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_SHE_SetNewKey */
|
||||
|
||||
/*
|
||||
* Testing wc_SHE_SetCounter()
|
||||
*/
|
||||
int test_wc_SHE_SetCounter(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_SHE) && !defined(NO_AES)
|
||||
wc_SHE she;
|
||||
|
||||
ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0);
|
||||
|
||||
ExpectIntEQ(wc_SHE_SetCounter(&she, 1), 0);
|
||||
ExpectIntEQ(she.counter, 1);
|
||||
|
||||
ExpectIntEQ(wc_SHE_SetCounter(&she, 0x0FFFFFFF), 0);
|
||||
ExpectIntEQ(she.counter, 0x0FFFFFFF);
|
||||
|
||||
/* Bad args */
|
||||
ExpectIntEQ(wc_SHE_SetCounter(NULL, 1),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
wc_SHE_Free(&she);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_SHE_SetCounter */
|
||||
|
||||
/*
|
||||
* Testing wc_SHE_SetFlags()
|
||||
*/
|
||||
int test_wc_SHE_SetFlags(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_SHE) && !defined(NO_AES)
|
||||
wc_SHE she;
|
||||
|
||||
ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0);
|
||||
|
||||
ExpectIntEQ(wc_SHE_SetFlags(&she, 0), 0);
|
||||
ExpectIntEQ(she.flags, 0);
|
||||
|
||||
ExpectIntEQ(wc_SHE_SetFlags(&she, WC_SHE_FLAG_WRITE_PROTECT |
|
||||
WC_SHE_FLAG_BOOT_PROTECT), 0);
|
||||
ExpectIntEQ(she.flags, WC_SHE_FLAG_WRITE_PROTECT |
|
||||
WC_SHE_FLAG_BOOT_PROTECT);
|
||||
|
||||
/* Bad args */
|
||||
ExpectIntEQ(wc_SHE_SetFlags(NULL, 0),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
wc_SHE_Free(&she);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_SHE_SetFlags */
|
||||
|
||||
/*
|
||||
* Testing wc_SHE_SetKdfConstants()
|
||||
*/
|
||||
int test_wc_SHE_SetKdfConstants(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_SHE) && !defined(NO_AES)
|
||||
wc_SHE she;
|
||||
const byte defEncC[] = WC_SHE_KEY_UPDATE_ENC_C;
|
||||
const byte defMacC[] = WC_SHE_KEY_UPDATE_MAC_C;
|
||||
byte customEncC[WC_SHE_KEY_SZ];
|
||||
byte customMacC[WC_SHE_KEY_SZ];
|
||||
|
||||
ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0);
|
||||
|
||||
/* Init should set defaults */
|
||||
ExpectIntEQ(XMEMCMP(she.kdfEncC, defEncC, WC_SHE_KEY_SZ), 0);
|
||||
ExpectIntEQ(XMEMCMP(she.kdfMacC, defMacC, WC_SHE_KEY_SZ), 0);
|
||||
|
||||
/* Override both */
|
||||
XMEMCPY(customEncC, defEncC, WC_SHE_KEY_SZ);
|
||||
XMEMCPY(customMacC, defMacC, WC_SHE_KEY_SZ);
|
||||
customEncC[1] += 0x80;
|
||||
customMacC[1] += 0x80;
|
||||
ExpectIntEQ(wc_SHE_SetKdfConstants(&she,
|
||||
customEncC, WC_SHE_KEY_SZ,
|
||||
customMacC, WC_SHE_KEY_SZ), 0);
|
||||
ExpectIntEQ(XMEMCMP(she.kdfEncC, customEncC, WC_SHE_KEY_SZ), 0);
|
||||
ExpectIntEQ(XMEMCMP(she.kdfMacC, customMacC, WC_SHE_KEY_SZ), 0);
|
||||
|
||||
/* Override only encC, leave macC unchanged */
|
||||
ExpectIntEQ(wc_SHE_SetKdfConstants(&she,
|
||||
defEncC, WC_SHE_KEY_SZ, NULL, 0), 0);
|
||||
ExpectIntEQ(XMEMCMP(she.kdfEncC, defEncC, WC_SHE_KEY_SZ), 0);
|
||||
ExpectIntEQ(XMEMCMP(she.kdfMacC, customMacC, WC_SHE_KEY_SZ), 0);
|
||||
|
||||
/* Bad args: NULL she */
|
||||
ExpectIntEQ(wc_SHE_SetKdfConstants(NULL,
|
||||
defEncC, WC_SHE_KEY_SZ, defMacC, WC_SHE_KEY_SZ),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* Bad args: wrong size */
|
||||
ExpectIntEQ(wc_SHE_SetKdfConstants(&she,
|
||||
defEncC, WC_SHE_KEY_SZ - 1, NULL, 0),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
wc_SHE_Free(&she);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_SHE_SetKdfConstants */
|
||||
|
||||
/*
|
||||
* Testing wc_SHE_SetM2Header() and wc_SHE_SetM4Header()
|
||||
*/
|
||||
int test_wc_SHE_SetM2M4Header(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_SHE) && !defined(NO_AES)
|
||||
wc_SHE she, sheOvr;
|
||||
byte uid[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
|
||||
};
|
||||
byte authKey[] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
|
||||
};
|
||||
byte newKey[] = {
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
|
||||
};
|
||||
byte customHeader[WC_SHE_KEY_SZ] = {0};
|
||||
byte m1Def[WC_SHE_M1_SZ], m2Def[WC_SHE_M2_SZ], m3Def[WC_SHE_M3_SZ];
|
||||
byte m1Ovr[WC_SHE_M1_SZ], m2Ovr[WC_SHE_M2_SZ], m3Ovr[WC_SHE_M3_SZ];
|
||||
|
||||
/* --- SetM2Header bad args --- */
|
||||
ExpectIntEQ(wc_SHE_SetM2Header(NULL, customHeader, WC_SHE_KEY_SZ),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SHE_SetM4Header(NULL, customHeader, WC_SHE_KEY_SZ),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0);
|
||||
|
||||
/* NULL header */
|
||||
ExpectIntEQ(wc_SHE_SetM2Header(&she, NULL, WC_SHE_KEY_SZ),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* Wrong size */
|
||||
ExpectIntEQ(wc_SHE_SetM2Header(&she, customHeader, WC_SHE_KEY_SZ - 1),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_SHE_SetM4Header(&she, customHeader, WC_SHE_KEY_SZ + 1),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* Valid set */
|
||||
XMEMSET(customHeader, 0xAA, WC_SHE_KEY_SZ);
|
||||
ExpectIntEQ(wc_SHE_SetM2Header(&she, customHeader, WC_SHE_KEY_SZ), 0);
|
||||
ExpectIntEQ(XMEMCMP(she.m2pHeader, customHeader, WC_SHE_KEY_SZ), 0);
|
||||
ExpectIntEQ(she.m2pOverride, 1);
|
||||
|
||||
ExpectIntEQ(wc_SHE_SetM4Header(&she, customHeader, WC_SHE_KEY_SZ), 0);
|
||||
ExpectIntEQ(XMEMCMP(she.m4pHeader, customHeader, WC_SHE_KEY_SZ), 0);
|
||||
ExpectIntEQ(she.m4pOverride, 1);
|
||||
|
||||
wc_SHE_Free(&she);
|
||||
|
||||
/* --- Override produces different M2 than default --- */
|
||||
/* Default path: counter=1, flags=0, auto-built headers */
|
||||
ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0);
|
||||
ExpectIntEQ(wc_SHE_SetUID(&she, uid, sizeof(uid), NULL), 0);
|
||||
ExpectIntEQ(wc_SHE_SetAuthKey(&she, 1, authKey, sizeof(authKey)), 0);
|
||||
ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, newKey, sizeof(newKey)), 0);
|
||||
ExpectIntEQ(wc_SHE_SetCounter(&she, 1), 0);
|
||||
ExpectIntEQ(wc_SHE_SetFlags(&she, 0), 0);
|
||||
ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she), 0);
|
||||
ExpectIntEQ(wc_SHE_ExportKey(&she,
|
||||
m1Def, WC_SHE_M1_SZ, m2Def, WC_SHE_M2_SZ,
|
||||
m3Def, WC_SHE_M3_SZ, NULL, 0, NULL, 0, NULL), 0);
|
||||
wc_SHE_Free(&she);
|
||||
|
||||
/* Override path: same inputs but custom m2pHeader */
|
||||
ExpectIntEQ(wc_SHE_Init(&sheOvr, NULL, INVALID_DEVID), 0);
|
||||
ExpectIntEQ(wc_SHE_SetUID(&sheOvr, uid, sizeof(uid), NULL), 0);
|
||||
ExpectIntEQ(wc_SHE_SetAuthKey(&sheOvr, 1, authKey, sizeof(authKey)), 0);
|
||||
ExpectIntEQ(wc_SHE_SetNewKey(&sheOvr, 4, newKey, sizeof(newKey)), 0);
|
||||
ExpectIntEQ(wc_SHE_SetCounter(&sheOvr, 1), 0);
|
||||
ExpectIntEQ(wc_SHE_SetFlags(&sheOvr, 0), 0);
|
||||
/* Set a different header ΓÇö should produce different M2/M3 */
|
||||
XMEMSET(customHeader, 0, WC_SHE_KEY_SZ);
|
||||
customHeader[0] = 0xFF; /* different from auto-built */
|
||||
ExpectIntEQ(wc_SHE_SetM2Header(&sheOvr, customHeader, WC_SHE_KEY_SZ), 0);
|
||||
ExpectIntEQ(wc_SHE_GenerateM1M2M3(&sheOvr), 0);
|
||||
ExpectIntEQ(wc_SHE_ExportKey(&sheOvr,
|
||||
m1Ovr, WC_SHE_M1_SZ, m2Ovr, WC_SHE_M2_SZ,
|
||||
m3Ovr, WC_SHE_M3_SZ, NULL, 0, NULL, 0, NULL), 0);
|
||||
|
||||
/* M1 should be same (UID|IDs unchanged), M2 should differ */
|
||||
ExpectIntEQ(XMEMCMP(m1Def, m1Ovr, WC_SHE_M1_SZ), 0);
|
||||
ExpectIntNE(XMEMCMP(m2Def, m2Ovr, WC_SHE_M2_SZ), 0);
|
||||
|
||||
wc_SHE_Free(&sheOvr);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_SHE_SetM2M4Header */
|
||||
|
||||
/*
|
||||
* Testing wc_SHE_GenerateM1M2M3()
|
||||
*/
|
||||
int test_wc_SHE_GenerateM1M2M3(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_SHE) && !defined(NO_AES)
|
||||
wc_SHE she;
|
||||
byte uid[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
|
||||
};
|
||||
byte authKey[] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
|
||||
};
|
||||
byte newKey[] = {
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
|
||||
};
|
||||
|
||||
ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0);
|
||||
ExpectIntEQ(wc_SHE_SetUID(&she, uid, sizeof(uid), NULL), 0);
|
||||
ExpectIntEQ(wc_SHE_SetAuthKey(&she, WC_SHE_MASTER_ECU_KEY_ID,
|
||||
authKey, sizeof(authKey)), 0);
|
||||
ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, newKey, sizeof(newKey)), 0);
|
||||
ExpectIntEQ(wc_SHE_SetCounter(&she, 1), 0);
|
||||
ExpectIntEQ(wc_SHE_SetFlags(&she, 0), 0);
|
||||
|
||||
/* Generate should succeed and set generated flag */
|
||||
ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she), 0);
|
||||
ExpectIntEQ(she.generated, 1);
|
||||
|
||||
/* Bad args */
|
||||
ExpectIntEQ(wc_SHE_GenerateM1M2M3(NULL),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
wc_SHE_Free(&she);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_SHE_GenerateM1M2M3 */
|
||||
|
||||
/*
|
||||
* Testing wc_She_AesMp16() — Miyaguchi-Preneel compression
|
||||
*/
|
||||
int test_wc_She_AesMp16(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_SHE) && !defined(NO_AES)
|
||||
Aes aes;
|
||||
byte out[WC_SHE_KEY_SZ];
|
||||
byte input[WC_SHE_KEY_SZ * 2] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x01, 0x01, 0x53, 0x48, 0x45, 0x00, 0x80, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0
|
||||
};
|
||||
/* 17 bytes — not block-aligned, triggers zero-padding path */
|
||||
byte shortInput[17] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0xAA
|
||||
};
|
||||
|
||||
ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);
|
||||
|
||||
/* Valid block-aligned input */
|
||||
ExpectIntEQ(wc_She_AesMp16(&aes, input, sizeof(input), out), 0);
|
||||
|
||||
/* Non-block-aligned input — exercises zero-padding */
|
||||
ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);
|
||||
ExpectIntEQ(wc_She_AesMp16(&aes, shortInput, sizeof(shortInput), out), 0);
|
||||
|
||||
/* Bad args: NULL aes */
|
||||
ExpectIntEQ(wc_She_AesMp16(NULL, input, sizeof(input), out),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* Bad args: NULL input */
|
||||
ExpectIntEQ(wc_She_AesMp16(&aes, NULL, sizeof(input), out),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* Bad args: zero size */
|
||||
ExpectIntEQ(wc_She_AesMp16(&aes, input, 0, out),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* Bad args: NULL output */
|
||||
ExpectIntEQ(wc_She_AesMp16(&aes, input, sizeof(input), NULL),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
wc_AesFree(&aes);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_She_AesMp16 */
|
||||
|
||||
/*
|
||||
* Testing wc_SHE_ExportKey()
|
||||
*/
|
||||
int test_wc_SHE_ExportKey(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_SHE) && !defined(NO_AES)
|
||||
wc_SHE she;
|
||||
byte m1[WC_SHE_M1_SZ];
|
||||
byte m2[WC_SHE_M2_SZ];
|
||||
byte m3[WC_SHE_M3_SZ];
|
||||
byte m4[WC_SHE_M4_SZ];
|
||||
byte m5[WC_SHE_M5_SZ];
|
||||
byte uid[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
|
||||
};
|
||||
byte authKey[] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
|
||||
};
|
||||
byte newKey[] = {
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
|
||||
};
|
||||
|
||||
ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0);
|
||||
|
||||
/* Export before generate should return BAD_STATE_E */
|
||||
ExpectIntEQ(wc_SHE_ExportKey(&she,
|
||||
m1, WC_SHE_M1_SZ, NULL, 0, NULL, 0,
|
||||
NULL, 0, NULL, 0, NULL),
|
||||
WC_NO_ERR_TRACE(BAD_STATE_E));
|
||||
|
||||
/* NULL she should return BAD_FUNC_ARG */
|
||||
ExpectIntEQ(wc_SHE_ExportKey(NULL,
|
||||
m1, WC_SHE_M1_SZ, NULL, 0, NULL, 0,
|
||||
NULL, 0, NULL, 0, NULL),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* Set up, generate, and compute verification */
|
||||
ExpectIntEQ(wc_SHE_SetUID(&she, uid, sizeof(uid), NULL), 0);
|
||||
ExpectIntEQ(wc_SHE_SetAuthKey(&she, WC_SHE_MASTER_ECU_KEY_ID,
|
||||
authKey, sizeof(authKey)), 0);
|
||||
ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, newKey, sizeof(newKey)), 0);
|
||||
ExpectIntEQ(wc_SHE_SetCounter(&she, 1), 0);
|
||||
ExpectIntEQ(wc_SHE_SetFlags(&she, 0), 0);
|
||||
ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she), 0);
|
||||
ExpectIntEQ(wc_SHE_GenerateM4M5(&she), 0);
|
||||
|
||||
/* Export only M1/M2/M3 */
|
||||
ExpectIntEQ(wc_SHE_ExportKey(&she,
|
||||
m1, WC_SHE_M1_SZ,
|
||||
m2, WC_SHE_M2_SZ,
|
||||
m3, WC_SHE_M3_SZ,
|
||||
NULL, 0, NULL, 0, NULL), 0);
|
||||
|
||||
/* Export only M4/M5 */
|
||||
ExpectIntEQ(wc_SHE_ExportKey(&she,
|
||||
NULL, 0, NULL, 0, NULL, 0,
|
||||
m4, WC_SHE_M4_SZ,
|
||||
m5, WC_SHE_M5_SZ, NULL), 0);
|
||||
|
||||
/* Export all M1-M5 */
|
||||
ExpectIntEQ(wc_SHE_ExportKey(&she,
|
||||
m1, WC_SHE_M1_SZ,
|
||||
m2, WC_SHE_M2_SZ,
|
||||
m3, WC_SHE_M3_SZ,
|
||||
m4, WC_SHE_M4_SZ,
|
||||
m5, WC_SHE_M5_SZ, NULL), 0);
|
||||
|
||||
/* Buffer too small */
|
||||
ExpectIntEQ(wc_SHE_ExportKey(&she,
|
||||
m1, 1, NULL, 0, NULL, 0,
|
||||
NULL, 0, NULL, 0, NULL),
|
||||
WC_NO_ERR_TRACE(BUFFER_E));
|
||||
|
||||
/* Export M4/M5 when generated but not verified — BAD_STATE_E */
|
||||
{
|
||||
wc_SHE badShe;
|
||||
ExpectIntEQ(wc_SHE_Init(&badShe, NULL, INVALID_DEVID), 0);
|
||||
badShe.generated = 1; /* fake generated state */
|
||||
badShe.verified = 0; /* but not verified */
|
||||
ExpectIntEQ(wc_SHE_ExportKey(&badShe,
|
||||
NULL, 0, NULL, 0, NULL, 0,
|
||||
m4, WC_SHE_M4_SZ,
|
||||
NULL, 0, NULL),
|
||||
WC_NO_ERR_TRACE(BAD_STATE_E));
|
||||
wc_SHE_Free(&badShe);
|
||||
}
|
||||
|
||||
wc_SHE_Free(&she);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_SHE_ExportKey */
|
||||
|
||||
/*
|
||||
* Testing wc_SHE_GenerateM4M5()
|
||||
*/
|
||||
int test_wc_SHE_GenerateM4M5(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_SHE) && !defined(NO_AES)
|
||||
wc_SHE she;
|
||||
byte uid[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
|
||||
};
|
||||
byte authKey[] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
|
||||
};
|
||||
byte newKey[] = {
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
|
||||
};
|
||||
|
||||
ExpectIntEQ(wc_SHE_Init(&she, NULL, INVALID_DEVID), 0);
|
||||
|
||||
/* GenerateM4M5 before GenerateM1M2M3 should return BAD_STATE_E */
|
||||
ExpectIntEQ(wc_SHE_GenerateM4M5(&she),
|
||||
WC_NO_ERR_TRACE(BAD_STATE_E));
|
||||
|
||||
/* Set up and generate M1/M2/M3 */
|
||||
ExpectIntEQ(wc_SHE_SetUID(&she, uid, sizeof(uid), NULL), 0);
|
||||
ExpectIntEQ(wc_SHE_SetAuthKey(&she, WC_SHE_MASTER_ECU_KEY_ID,
|
||||
authKey, sizeof(authKey)), 0);
|
||||
ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, newKey, sizeof(newKey)), 0);
|
||||
ExpectIntEQ(wc_SHE_SetCounter(&she, 1), 0);
|
||||
ExpectIntEQ(wc_SHE_SetFlags(&she, 0), 0);
|
||||
ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she), 0);
|
||||
|
||||
/* Now compute M4/M5 */
|
||||
ExpectIntEQ(wc_SHE_GenerateM4M5(&she), 0);
|
||||
ExpectIntEQ(she.verified, 1);
|
||||
|
||||
/* Bad args */
|
||||
ExpectIntEQ(wc_SHE_GenerateM4M5(NULL),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
wc_SHE_Free(&she);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_SHE_GenerateM4M5 */
|
||||
|
||||
#if defined(WOLF_CRYPTO_CB) && defined(WOLFSSL_SHE) && !defined(NO_AES)
|
||||
|
||||
/* Simple SHE callback that falls back to software by resetting devId */
|
||||
static int test_she_crypto_cb(int devIdArg, wc_CryptoInfo* info, void* ctx)
|
||||
{
|
||||
int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
|
||||
wc_SHE* she;
|
||||
int savedDevId;
|
||||
|
||||
(void)ctx;
|
||||
(void)devIdArg;
|
||||
|
||||
if (info == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
#ifdef WOLF_CRYPTO_CB_FREE
|
||||
/* Handle free callback */
|
||||
if (info->algo_type == WC_ALGO_TYPE_FREE) {
|
||||
if (info->free.algo == WC_ALGO_TYPE_SHE) {
|
||||
she = (wc_SHE*)info->free.obj;
|
||||
she->devId = INVALID_DEVID;
|
||||
wc_SHE_Free(she);
|
||||
return 0;
|
||||
}
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (info->algo_type != WC_ALGO_TYPE_SHE) {
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
|
||||
she = (wc_SHE*)info->she.she;
|
||||
if (she == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
savedDevId = she->devId;
|
||||
she->devId = INVALID_DEVID;
|
||||
|
||||
switch (info->she.type) {
|
||||
case WC_SHE_SET_UID:
|
||||
ret = wc_SHE_SetUID(she, info->she.op.setUid.uid,
|
||||
info->she.op.setUid.uidSz,
|
||||
info->she.ctx);
|
||||
break;
|
||||
case WC_SHE_GENERATE_M4M5:
|
||||
ret = wc_SHE_GenerateM4M5(she);
|
||||
break;
|
||||
case WC_SHE_EXPORT_KEY:
|
||||
ret = wc_SHE_ExportKey(she,
|
||||
info->she.op.exportKey.m1,
|
||||
info->she.op.exportKey.m1Sz,
|
||||
info->she.op.exportKey.m2,
|
||||
info->she.op.exportKey.m2Sz,
|
||||
info->she.op.exportKey.m3,
|
||||
info->she.op.exportKey.m3Sz,
|
||||
info->she.op.exportKey.m4,
|
||||
info->she.op.exportKey.m4Sz,
|
||||
info->she.op.exportKey.m5,
|
||||
info->she.op.exportKey.m5Sz,
|
||||
info->she.ctx);
|
||||
break;
|
||||
default:
|
||||
ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
|
||||
break;
|
||||
}
|
||||
|
||||
she->devId = savedDevId;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing SHE callback path for SetUID and GenerateM4M5
|
||||
*/
|
||||
int test_wc_SHE_CryptoCb(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_SHE) && !defined(NO_AES)
|
||||
wc_SHE she;
|
||||
int sheTestDevId = 54321;
|
||||
byte m4[WC_SHE_M4_SZ];
|
||||
byte m5[WC_SHE_M5_SZ];
|
||||
byte uid[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
|
||||
};
|
||||
byte authKey[] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
|
||||
};
|
||||
byte newKey[] = {
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
|
||||
};
|
||||
|
||||
/* Register our test callback with a non-INVALID devId */
|
||||
ExpectIntEQ(wc_CryptoCb_RegisterDevice(sheTestDevId,
|
||||
test_she_crypto_cb, NULL), 0);
|
||||
|
||||
/* Init with the test devId so callback path is used */
|
||||
ExpectIntEQ(wc_SHE_Init(&she, NULL, sheTestDevId), 0);
|
||||
|
||||
/* SetUID via callback — passes uid through to software */
|
||||
ExpectIntEQ(wc_SHE_SetUID(&she, uid, sizeof(uid), NULL), 0);
|
||||
ExpectIntEQ(XMEMCMP(she.uid, uid, WC_SHE_UID_SZ), 0);
|
||||
|
||||
/* Set remaining inputs (software only) */
|
||||
ExpectIntEQ(wc_SHE_SetAuthKey(&she, WC_SHE_MASTER_ECU_KEY_ID,
|
||||
authKey, sizeof(authKey)), 0);
|
||||
ExpectIntEQ(wc_SHE_SetNewKey(&she, 4, newKey, sizeof(newKey)), 0);
|
||||
ExpectIntEQ(wc_SHE_SetCounter(&she, 1), 0);
|
||||
ExpectIntEQ(wc_SHE_SetFlags(&she, 0), 0);
|
||||
|
||||
/* GenerateLoadKey — software, callback not involved */
|
||||
ExpectIntEQ(wc_SHE_GenerateM1M2M3(&she), 0);
|
||||
|
||||
/* GenerateM4M5 via callback — falls back to software */
|
||||
ExpectIntEQ(wc_SHE_GenerateM4M5(&she), 0);
|
||||
ExpectIntEQ(she.verified, 1);
|
||||
|
||||
/* ExportKey via callback path */
|
||||
ExpectIntEQ(wc_SHE_ExportKey(&she,
|
||||
NULL, 0, NULL, 0, NULL, 0,
|
||||
m4, WC_SHE_M4_SZ,
|
||||
m5, WC_SHE_M5_SZ, NULL), 0);
|
||||
|
||||
/* Export all M1-M5 via callback */
|
||||
{
|
||||
byte cm1[WC_SHE_M1_SZ];
|
||||
byte cm2[WC_SHE_M2_SZ];
|
||||
byte cm3[WC_SHE_M3_SZ];
|
||||
ExpectIntEQ(wc_SHE_ExportKey(&she,
|
||||
cm1, WC_SHE_M1_SZ,
|
||||
cm2, WC_SHE_M2_SZ,
|
||||
cm3, WC_SHE_M3_SZ,
|
||||
m4, WC_SHE_M4_SZ,
|
||||
m5, WC_SHE_M5_SZ, NULL), 0);
|
||||
}
|
||||
|
||||
wc_SHE_Free(&she);
|
||||
wc_CryptoCb_UnRegisterDevice(sheTestDevId);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_SHE_CryptoCb */
|
||||
|
||||
#endif /* WOLF_CRYPTO_CB && WOLFSSL_SHE && !NO_AES */
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/* test_she.h
|
||||
*
|
||||
* Copyright (C) 2006-2026 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 3 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_SHE_H
|
||||
#define WOLFCRYPT_TEST_SHE_H
|
||||
|
||||
#include <tests/api/api_decl.h>
|
||||
|
||||
int test_wc_SHE_Init(void);
|
||||
int test_wc_SHE_Init_Id(void);
|
||||
int test_wc_SHE_Init_Label(void);
|
||||
int test_wc_SHE_Free(void);
|
||||
int test_wc_SHE_SetUID(void);
|
||||
int test_wc_SHE_SetAuthKey(void);
|
||||
int test_wc_SHE_SetNewKey(void);
|
||||
int test_wc_SHE_SetCounter(void);
|
||||
int test_wc_SHE_SetFlags(void);
|
||||
int test_wc_SHE_SetKdfConstants(void);
|
||||
int test_wc_SHE_SetM2M4Header(void);
|
||||
int test_wc_SHE_GenerateM1M2M3(void);
|
||||
int test_wc_She_AesMp16(void);
|
||||
int test_wc_SHE_GenerateM4M5(void);
|
||||
int test_wc_SHE_ExportKey(void);
|
||||
#if defined(WOLF_CRYPTO_CB) && defined(WOLFSSL_SHE)
|
||||
int test_wc_SHE_CryptoCb(void);
|
||||
#endif
|
||||
|
||||
#define TEST_SHE_DECLS \
|
||||
TEST_DECL_GROUP("she", test_wc_SHE_Init), \
|
||||
TEST_DECL_GROUP("she", test_wc_SHE_Init_Id), \
|
||||
TEST_DECL_GROUP("she", test_wc_SHE_Init_Label), \
|
||||
TEST_DECL_GROUP("she", test_wc_SHE_Free), \
|
||||
TEST_DECL_GROUP("she", test_wc_SHE_SetUID), \
|
||||
TEST_DECL_GROUP("she", test_wc_SHE_SetAuthKey), \
|
||||
TEST_DECL_GROUP("she", test_wc_SHE_SetNewKey), \
|
||||
TEST_DECL_GROUP("she", test_wc_SHE_SetCounter), \
|
||||
TEST_DECL_GROUP("she", test_wc_SHE_SetFlags), \
|
||||
TEST_DECL_GROUP("she", test_wc_SHE_SetKdfConstants), \
|
||||
TEST_DECL_GROUP("she", test_wc_SHE_SetM2M4Header), \
|
||||
TEST_DECL_GROUP("she", test_wc_SHE_GenerateM1M2M3), \
|
||||
TEST_DECL_GROUP("she", test_wc_She_AesMp16), \
|
||||
TEST_DECL_GROUP("she", test_wc_SHE_GenerateM4M5), \
|
||||
TEST_DECL_GROUP("she", test_wc_SHE_ExportKey)
|
||||
|
||||
#if defined(WOLF_CRYPTO_CB) && defined(WOLFSSL_SHE)
|
||||
#define TEST_SHE_CB_DECLS \
|
||||
TEST_DECL_GROUP("she", test_wc_SHE_CryptoCb)
|
||||
#else
|
||||
#define TEST_SHE_CB_DECLS
|
||||
#endif
|
||||
|
||||
#endif /* WOLFCRYPT_TEST_SHE_H */
|
||||
@@ -2120,6 +2120,124 @@ int wc_CryptoCb_Cmac(Cmac* cmac, const byte* key, word32 keySz,
|
||||
}
|
||||
#endif /* WOLFSSL_CMAC */
|
||||
|
||||
#ifdef WOLFSSL_SHE
|
||||
int wc_CryptoCb_SheSetUid(wc_SHE* she, const byte* uid, word32 uidSz,
|
||||
const void* ctx)
|
||||
{
|
||||
int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
|
||||
CryptoCb* dev;
|
||||
|
||||
if (she == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
/* locate registered callback */
|
||||
dev = wc_CryptoCb_FindDevice(she->devId, WC_ALGO_TYPE_SHE);
|
||||
if (dev && dev->cb) {
|
||||
wc_CryptoInfo cryptoInfo;
|
||||
XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo));
|
||||
cryptoInfo.algo_type = WC_ALGO_TYPE_SHE;
|
||||
cryptoInfo.she.she = she;
|
||||
cryptoInfo.she.type = WC_SHE_SET_UID;
|
||||
cryptoInfo.she.ctx = ctx;
|
||||
cryptoInfo.she.op.setUid.uid = uid;
|
||||
cryptoInfo.she.op.setUid.uidSz = uidSz;
|
||||
|
||||
ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx);
|
||||
}
|
||||
|
||||
return wc_CryptoCb_TranslateErrorCode(ret);
|
||||
}
|
||||
|
||||
int wc_CryptoCb_SheGenerateM1M2M3(wc_SHE* she, const void* ctx)
|
||||
{
|
||||
int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
|
||||
CryptoCb* dev;
|
||||
|
||||
if (she == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
dev = wc_CryptoCb_FindDevice(she->devId, WC_ALGO_TYPE_SHE);
|
||||
if (dev && dev->cb) {
|
||||
wc_CryptoInfo cryptoInfo;
|
||||
XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo));
|
||||
cryptoInfo.algo_type = WC_ALGO_TYPE_SHE;
|
||||
cryptoInfo.she.she = she;
|
||||
cryptoInfo.she.type = WC_SHE_GENERATE_M1M2M3;
|
||||
cryptoInfo.she.ctx = ctx;
|
||||
|
||||
ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx);
|
||||
}
|
||||
|
||||
return wc_CryptoCb_TranslateErrorCode(ret);
|
||||
}
|
||||
|
||||
int wc_CryptoCb_SheGenerateM4M5(wc_SHE* she, const void* ctx)
|
||||
{
|
||||
int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
|
||||
CryptoCb* dev;
|
||||
|
||||
if (she == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
dev = wc_CryptoCb_FindDevice(she->devId, WC_ALGO_TYPE_SHE);
|
||||
if (dev && dev->cb) {
|
||||
wc_CryptoInfo cryptoInfo;
|
||||
XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo));
|
||||
cryptoInfo.algo_type = WC_ALGO_TYPE_SHE;
|
||||
cryptoInfo.she.she = she;
|
||||
cryptoInfo.she.type = WC_SHE_GENERATE_M4M5;
|
||||
cryptoInfo.she.ctx = ctx;
|
||||
|
||||
ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx);
|
||||
}
|
||||
|
||||
return wc_CryptoCb_TranslateErrorCode(ret);
|
||||
}
|
||||
|
||||
int wc_CryptoCb_SheExportKey(wc_SHE* she,
|
||||
byte* m1, word32 m1Sz,
|
||||
byte* m2, word32 m2Sz,
|
||||
byte* m3, word32 m3Sz,
|
||||
byte* m4, word32 m4Sz,
|
||||
byte* m5, word32 m5Sz,
|
||||
const void* ctx)
|
||||
{
|
||||
int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
|
||||
CryptoCb* dev;
|
||||
|
||||
if (she == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
dev = wc_CryptoCb_FindDevice(she->devId, WC_ALGO_TYPE_SHE);
|
||||
if (dev && dev->cb) {
|
||||
wc_CryptoInfo cryptoInfo;
|
||||
XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo));
|
||||
cryptoInfo.algo_type = WC_ALGO_TYPE_SHE;
|
||||
cryptoInfo.she.she = she;
|
||||
cryptoInfo.she.type = WC_SHE_EXPORT_KEY;
|
||||
cryptoInfo.she.ctx = ctx;
|
||||
cryptoInfo.she.op.exportKey.m1 = m1;
|
||||
cryptoInfo.she.op.exportKey.m1Sz = m1Sz;
|
||||
cryptoInfo.she.op.exportKey.m2 = m2;
|
||||
cryptoInfo.she.op.exportKey.m2Sz = m2Sz;
|
||||
cryptoInfo.she.op.exportKey.m3 = m3;
|
||||
cryptoInfo.she.op.exportKey.m3Sz = m3Sz;
|
||||
cryptoInfo.she.op.exportKey.m4 = m4;
|
||||
cryptoInfo.she.op.exportKey.m4Sz = m4Sz;
|
||||
cryptoInfo.she.op.exportKey.m5 = m5;
|
||||
cryptoInfo.she.op.exportKey.m5Sz = m5Sz;
|
||||
|
||||
ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx);
|
||||
}
|
||||
|
||||
return wc_CryptoCb_TranslateErrorCode(ret);
|
||||
}
|
||||
#endif /* WOLFSSL_SHE */
|
||||
|
||||
/* returns the default dev id for the current build */
|
||||
int wc_CryptoCb_DefaultDevID(void)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,702 @@
|
||||
/* she.c
|
||||
*
|
||||
* Copyright (C) 2006-2026 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* SHE (Secure Hardware Extension) key update message generation.
|
||||
*
|
||||
* Software-only computation of M1/M2/M3 for CMD_LOAD_KEY and optional
|
||||
* M4/M5 verification. Ported from the wolfHSM reference implementation
|
||||
* (src/wh_she_crypto.c) and adapted to wolfSSL conventions.
|
||||
*/
|
||||
|
||||
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
|
||||
|
||||
#ifdef WOLFSSL_SHE
|
||||
|
||||
#ifdef NO_INLINE
|
||||
#include <wolfssl/wolfcrypt/misc.h>
|
||||
#else
|
||||
#define WOLFSSL_MISC_INCLUDED
|
||||
#include <wolfcrypt/src/misc.c>
|
||||
#endif
|
||||
|
||||
#include <wolfssl/wolfcrypt/aes.h>
|
||||
#include <wolfssl/wolfcrypt/cmac.h>
|
||||
#include <wolfssl/wolfcrypt/she.h>
|
||||
#include <wolfssl/wolfcrypt/error-crypt.h>
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
#include <wolfssl/wolfcrypt/cryptocb.h>
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Miyaguchi-Preneel AES-128 compression (internal) */
|
||||
/* */
|
||||
/* H_0 = 0 */
|
||||
/* H_i = E_{H_{i-1}}(M_i) XOR M_i XOR H_{i-1} */
|
||||
/* */
|
||||
/* Only valid for AES-128 where key size == block size. */
|
||||
/* */
|
||||
/* Ported from wolfHSM wh_She_AesMp16_ex() in src/wh_she_crypto.c. */
|
||||
/* The caller (GenerateM1M2M3 / GenerateM4M5) owns the Aes object. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
int wc_She_AesMp16(Aes* aes, const byte* in, word32 inSz, byte* out)
|
||||
{
|
||||
int ret;
|
||||
int i = 0;
|
||||
int j;
|
||||
byte paddedInput[AES_BLOCK_SIZE];
|
||||
byte prev[WC_SHE_KEY_SZ] = {0};
|
||||
|
||||
if (aes == NULL || in == NULL || inSz == 0 || out == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
/* Set initial key = H_0 = all zeros */
|
||||
ret = wc_AesSetKeyDirect(aes, prev, AES_BLOCK_SIZE, NULL,
|
||||
AES_ENCRYPTION);
|
||||
|
||||
while (ret == 0 && i < (int)inSz) {
|
||||
/* Copy next input block, zero-padding if short */
|
||||
if ((int)inSz - i < (int)AES_BLOCK_SIZE) {
|
||||
XMEMCPY(paddedInput, in + i, inSz - i);
|
||||
XMEMSET(paddedInput + (inSz - i), 0,
|
||||
AES_BLOCK_SIZE - (inSz - i));
|
||||
}
|
||||
else {
|
||||
XMEMCPY(paddedInput, in + i, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
/* E_{H_{i-1}}(M_i) */
|
||||
ret = wc_AesEncryptDirect(aes, out, paddedInput);
|
||||
|
||||
if (ret == 0) {
|
||||
/* H_i = E_{H_{i-1}}(M_i) XOR M_i XOR H_{i-1} */
|
||||
for (j = 0; j < (int)AES_BLOCK_SIZE; j++) {
|
||||
out[j] ^= paddedInput[j];
|
||||
out[j] ^= prev[j];
|
||||
}
|
||||
|
||||
/* Save H_i as the previous output */
|
||||
XMEMCPY(prev, out, AES_BLOCK_SIZE);
|
||||
|
||||
/* Set key = H_i for next block */
|
||||
ret = wc_AesSetKeyDirect(aes, out, AES_BLOCK_SIZE,
|
||||
NULL, AES_ENCRYPTION);
|
||||
|
||||
i += AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Context init */
|
||||
/* */
|
||||
/* Zero-initialize the SHE context and store the heap hint and device ID */
|
||||
/* for use by subsequent crypto operations. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
int wc_SHE_Init(wc_SHE* she, void* heap, int devId)
|
||||
{
|
||||
const byte encC[] = WC_SHE_KEY_UPDATE_ENC_C;
|
||||
const byte macC[] = WC_SHE_KEY_UPDATE_MAC_C;
|
||||
|
||||
if (she == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
XMEMSET(she, 0, sizeof(wc_SHE));
|
||||
she->heap = heap;
|
||||
she->devId = devId;
|
||||
XMEMCPY(she->kdfEncC, encC, WC_SHE_KEY_SZ);
|
||||
XMEMCPY(she->kdfMacC, macC, WC_SHE_KEY_SZ);
|
||||
/* m2pHeader/m4pHeader are zero from XMEMSET ΓÇö correct for counter=0 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WOLF_PRIVATE_KEY_ID
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Context init with opaque hardware key identifier */
|
||||
/* */
|
||||
/* Like wc_SHE_Init but also stores an opaque byte-string key ID that */
|
||||
/* crypto callback backends can use to look up the authorizing key in */
|
||||
/* hardware (e.g. an HSM slot reference or PKCS#11 object handle). */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
int wc_SHE_Init_Id(wc_SHE* she, unsigned char* id, int len,
|
||||
void* heap, int devId)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (she == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
ret = wc_SHE_Init(she, heap, devId);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (len < 0 || len > WC_SHE_MAX_ID_LEN) {
|
||||
return BUFFER_E;
|
||||
}
|
||||
|
||||
XMEMCPY(she->id, id, (size_t)len);
|
||||
she->idLen = len;
|
||||
she->labelLen = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Context init with human-readable key label */
|
||||
/* */
|
||||
/* Like wc_SHE_Init but also stores a NUL-terminated string label that */
|
||||
/* crypto callback backends can use for string-based key lookup. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
int wc_SHE_Init_Label(wc_SHE* she, const char* label,
|
||||
void* heap, int devId)
|
||||
{
|
||||
int ret;
|
||||
size_t labelLen;
|
||||
|
||||
if (she == NULL || label == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
ret = wc_SHE_Init(she, heap, devId);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
labelLen = XSTRLEN(label);
|
||||
if (labelLen == 0 || labelLen > WC_SHE_MAX_LABEL_LEN) {
|
||||
return BUFFER_E;
|
||||
}
|
||||
|
||||
XMEMCPY(she->label, label, labelLen);
|
||||
she->labelLen = (int)labelLen;
|
||||
she->idLen = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* WOLF_PRIVATE_KEY_ID */
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Context free */
|
||||
/* */
|
||||
/* Scrub all key material and reset the SHE context to zero. */
|
||||
/* Safe to call on a NULL or already-freed context. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
void wc_SHE_Free(wc_SHE* she)
|
||||
{
|
||||
if (she == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE)
|
||||
if (she->devId != INVALID_DEVID) {
|
||||
int ret = wc_CryptoCb_Free(she->devId, WC_ALGO_TYPE_SHE,
|
||||
0, 0, she);
|
||||
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
|
||||
return;
|
||||
}
|
||||
/* fall-through when unavailable */
|
||||
}
|
||||
#endif /* WOLF_CRYPTO_CB && WOLF_CRYPTO_CB_FREE */
|
||||
|
||||
ForceZero(she, sizeof(wc_SHE));
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Setter functions */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int wc_SHE_SetUID(wc_SHE* she, const byte* uid, word32 uidSz,
|
||||
const void* ctx)
|
||||
{
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
int ret;
|
||||
#endif
|
||||
|
||||
if (she == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
/* Try callback first if a device is registered */
|
||||
if (she->devId != INVALID_DEVID) {
|
||||
ret = wc_CryptoCb_SheSetUid(she, uid, uidSz, ctx);
|
||||
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
|
||||
return ret;
|
||||
}
|
||||
/* fall-through to software path */
|
||||
}
|
||||
#else
|
||||
(void)ctx;
|
||||
#endif
|
||||
|
||||
/* Software path: copy caller-provided UID */
|
||||
if (uid == NULL || uidSz != WC_SHE_UID_SZ) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
XMEMCPY(she->uid, uid, WC_SHE_UID_SZ);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wc_SHE_SetAuthKey(wc_SHE* she, byte authKeyId,
|
||||
const byte* authKey, word32 keySz)
|
||||
{
|
||||
if (she == NULL || authKey == NULL || keySz != WC_SHE_KEY_SZ) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
she->authKeyId = authKeyId;
|
||||
XMEMCPY(she->authKey, authKey, WC_SHE_KEY_SZ);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wc_SHE_SetNewKey(wc_SHE* she, byte targetKeyId,
|
||||
const byte* newKey, word32 keySz)
|
||||
{
|
||||
if (she == NULL || newKey == NULL || keySz != WC_SHE_KEY_SZ) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
she->targetKeyId = targetKeyId;
|
||||
XMEMCPY(she->newKey, newKey, WC_SHE_KEY_SZ);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wc_SHE_SetCounter(wc_SHE* she, word32 counter)
|
||||
{
|
||||
if (she == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
she->counter = counter;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wc_SHE_SetFlags(wc_SHE* she, byte flags)
|
||||
{
|
||||
if (she == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
she->flags = flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wc_SHE_SetKdfConstants(wc_SHE* she,
|
||||
const byte* encC, word32 encCSz,
|
||||
const byte* macC, word32 macCSz)
|
||||
{
|
||||
if (she == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
if (encC != NULL) {
|
||||
if (encCSz != WC_SHE_KEY_SZ) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
XMEMCPY(she->kdfEncC, encC, WC_SHE_KEY_SZ);
|
||||
}
|
||||
|
||||
if (macC != NULL) {
|
||||
if (macCSz != WC_SHE_KEY_SZ) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
XMEMCPY(she->kdfMacC, macC, WC_SHE_KEY_SZ);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Portable big-endian 32-bit store */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
static WC_INLINE void she_store_be32(byte* dst, word32 val)
|
||||
{
|
||||
dst[0] = (byte)(val >> 24);
|
||||
dst[1] = (byte)(val >> 16);
|
||||
dst[2] = (byte)(val >> 8);
|
||||
dst[3] = (byte)(val);
|
||||
}
|
||||
|
||||
/* Build M2P/M4P headers from counter and flags using standard SHE packing.
|
||||
* M2P header: counter(28b) | flags(4b) | zeros(96b) = 16 bytes
|
||||
* M4P header: counter(28b) | 1(1b) | zeros(99b) = 16 bytes
|
||||
* Called internally by GenerateM1M2M3/GenerateM4M5 unless overridden. */
|
||||
static void she_build_headers(wc_SHE* she)
|
||||
{
|
||||
word32 field;
|
||||
|
||||
if (!she->m2pOverride) {
|
||||
XMEMSET(she->m2pHeader, 0, WC_SHE_KEY_SZ);
|
||||
field = (she->counter << WC_SHE_M2_COUNT_SHIFT) |
|
||||
(she->flags << WC_SHE_M2_FLAGS_SHIFT);
|
||||
she_store_be32(she->m2pHeader, field);
|
||||
}
|
||||
|
||||
if (!she->m4pOverride) {
|
||||
XMEMSET(she->m4pHeader, 0, WC_SHE_KEY_SZ);
|
||||
field = (she->counter << WC_SHE_M4_COUNT_SHIFT) | WC_SHE_M4_COUNT_PAD;
|
||||
she_store_be32(she->m4pHeader, field);
|
||||
}
|
||||
}
|
||||
|
||||
int wc_SHE_SetM2Header(wc_SHE* she, const byte* header, word32 headerSz)
|
||||
{
|
||||
if (she == NULL || header == NULL || headerSz != WC_SHE_KEY_SZ) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
XMEMCPY(she->m2pHeader, header, WC_SHE_KEY_SZ);
|
||||
she->m2pOverride = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wc_SHE_SetM4Header(wc_SHE* she, const byte* header, word32 headerSz)
|
||||
{
|
||||
if (she == NULL || header == NULL || headerSz != WC_SHE_KEY_SZ) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
XMEMCPY(she->m4pHeader, header, WC_SHE_KEY_SZ);
|
||||
she->m4pOverride = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* M1/M2/M3 generation */
|
||||
/* */
|
||||
/* Derives K1 and K2 from AuthKey via Miyaguchi-Preneel, then builds: */
|
||||
/* M1 = UID | TargetKeyID | AuthKeyID */
|
||||
/* M2 = AES-CBC(K1, IV=0, counter|flags|pad|newkey) */
|
||||
/* M3 = AES-CMAC(K2, M1 | M2) */
|
||||
/* */
|
||||
/* Ported from wolfHSM wh_She_GenerateLoadableKey() in wh_she_crypto.c. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
int wc_SHE_GenerateM1M2M3(wc_SHE* she)
|
||||
{
|
||||
int ret = 0;
|
||||
byte k1[WC_SHE_KEY_SZ];
|
||||
byte k2[WC_SHE_KEY_SZ];
|
||||
byte kdfInput[WC_SHE_KEY_SZ * 2];
|
||||
word32 cmacSz = AES_BLOCK_SIZE;
|
||||
WC_DECLARE_VAR(aes, Aes, 1, 0);
|
||||
WC_DECLARE_VAR(cmac, Cmac, 1, 0);
|
||||
|
||||
if (she == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
/* Build M2P/M4P headers from counter/flags (skipped if overridden) */
|
||||
she_build_headers(she);
|
||||
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
/* Try callback first ΓÇö hardware may generate M1/M2/M3 directly */
|
||||
if (she->devId != INVALID_DEVID) {
|
||||
ret = wc_CryptoCb_SheGenerateM1M2M3(she, NULL);
|
||||
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
|
||||
if (ret == 0) {
|
||||
she->generated = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/* fall-through to software path */
|
||||
ret = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
WC_ALLOC_VAR(aes, Aes, 1, she->heap);
|
||||
if (!WC_VAR_OK(aes)) {
|
||||
return MEMORY_E;
|
||||
}
|
||||
|
||||
WC_ALLOC_VAR(cmac, Cmac, 1, she->heap);
|
||||
if (!WC_VAR_OK(cmac)) {
|
||||
WC_FREE_VAR(aes, she->heap);
|
||||
return MEMORY_E;
|
||||
}
|
||||
|
||||
/* Init AES once — used by both MP16 and CBC */
|
||||
ret = wc_AesInit(aes, she->heap, she->devId);
|
||||
if (ret != 0) {
|
||||
WC_FREE_VAR(aes, she->heap);
|
||||
WC_FREE_VAR(cmac, she->heap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ---- Derive K1 = AES-MP(AuthKey || CENC) ---- */
|
||||
XMEMCPY(kdfInput, she->authKey, WC_SHE_KEY_SZ);
|
||||
XMEMCPY(kdfInput + WC_SHE_KEY_SZ, she->kdfEncC, WC_SHE_KEY_SZ);
|
||||
ret = wc_She_AesMp16(aes, kdfInput, WC_SHE_KEY_SZ * 2, k1);
|
||||
|
||||
/* ---- Build M1: UID(15B) | TargetKeyID(4b) | AuthKeyID(4b) ---- */
|
||||
if (ret == 0) {
|
||||
XMEMCPY(she->m1, she->uid, WC_SHE_UID_SZ);
|
||||
she->m1[WC_SHE_M1_KID_OFFSET] =
|
||||
(byte)((she->targetKeyId << WC_SHE_M1_KID_SHIFT) |
|
||||
(she->authKeyId << WC_SHE_M1_AID_SHIFT));
|
||||
}
|
||||
|
||||
/* ---- Build cleartext M2 and encrypt with K1 ---- */
|
||||
if (ret == 0) {
|
||||
/* M2P = m2pHeader(16B) | newKey(16B) */
|
||||
XMEMCPY(she->m2, she->m2pHeader, WC_SHE_KEY_SZ);
|
||||
XMEMCPY(she->m2 + WC_SHE_M2_KEY_OFFSET, she->newKey, WC_SHE_KEY_SZ);
|
||||
|
||||
/* Encrypt M2 in-place with AES-128-CBC, IV = 0 */
|
||||
ret = wc_AesSetKey(aes, k1, WC_SHE_KEY_SZ, NULL, AES_ENCRYPTION);
|
||||
if (ret == 0) {
|
||||
ret = wc_AesCbcEncrypt(aes, she->m2, she->m2, WC_SHE_M2_SZ);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Derive K2 = AES-MP(AuthKey || CMAC) ---- */
|
||||
if (ret == 0) {
|
||||
XMEMCPY(kdfInput + WC_SHE_KEY_SZ, she->kdfMacC, WC_SHE_KEY_SZ);
|
||||
ret = wc_She_AesMp16(aes, kdfInput, WC_SHE_KEY_SZ * 2, k2);
|
||||
}
|
||||
|
||||
/* ---- Build M3 = AES-CMAC(K2, M1 || M2) ---- */
|
||||
if (ret == 0) {
|
||||
ret = wc_InitCmac_ex(cmac, k2, WC_SHE_KEY_SZ, WC_CMAC_AES,
|
||||
NULL, she->heap, she->devId);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_CmacUpdate(cmac, she->m1, WC_SHE_M1_SZ);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_CmacUpdate(cmac, she->m2, WC_SHE_M2_SZ);
|
||||
}
|
||||
if (ret == 0) {
|
||||
cmacSz = AES_BLOCK_SIZE;
|
||||
ret = wc_CmacFinal(cmac, she->m3, &cmacSz);
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
she->generated = 1;
|
||||
}
|
||||
|
||||
/* Scrub temporary key material */
|
||||
ForceZero(k1, sizeof(k1));
|
||||
ForceZero(k2, sizeof(k2));
|
||||
ForceZero(kdfInput, sizeof(kdfInput));
|
||||
|
||||
wc_AesFree(aes);
|
||||
WC_FREE_VAR(aes, she->heap);
|
||||
WC_FREE_VAR(cmac, she->heap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* M4/M5 verification computation */
|
||||
/* */
|
||||
/* Derives K3 and K4 from NewKey via Miyaguchi-Preneel, then builds: */
|
||||
/* M4 = UID | KeyID | AuthID | AES-ECB(K3, counter|pad) */
|
||||
/* M5 = AES-CMAC(K4, M4) */
|
||||
/* */
|
||||
/* These are the expected proof messages that SHE hardware should return. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
int wc_SHE_GenerateM4M5(wc_SHE* she)
|
||||
{
|
||||
int ret = 0;
|
||||
byte k3[WC_SHE_KEY_SZ];
|
||||
byte k4[WC_SHE_KEY_SZ];
|
||||
byte kdfInput[WC_SHE_KEY_SZ * 2];
|
||||
word32 cmacSz;
|
||||
WC_DECLARE_VAR(aes, Aes, 1, 0);
|
||||
WC_DECLARE_VAR(cmac, Cmac, 1, 0);
|
||||
|
||||
if (she == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
if (!she->generated) {
|
||||
return BAD_STATE_E;
|
||||
}
|
||||
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
/* Try callback first — sends M1/M2/M3 to HW, receives M4/M5 */
|
||||
if (she->devId != INVALID_DEVID) {
|
||||
ret = wc_CryptoCb_SheGenerateM4M5(she, NULL);
|
||||
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
|
||||
if (ret == 0) {
|
||||
she->verified = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/* fall-through to software path */
|
||||
}
|
||||
#endif
|
||||
|
||||
WC_ALLOC_VAR(aes, Aes, 1, she->heap);
|
||||
if (!WC_VAR_OK(aes)) {
|
||||
return MEMORY_E;
|
||||
}
|
||||
|
||||
WC_ALLOC_VAR(cmac, Cmac, 1, she->heap);
|
||||
if (!WC_VAR_OK(cmac)) {
|
||||
WC_FREE_VAR(aes, she->heap);
|
||||
return MEMORY_E;
|
||||
}
|
||||
|
||||
/* Init AES once — used by both MP16 and ECB */
|
||||
ret = wc_AesInit(aes, she->heap, she->devId);
|
||||
if (ret != 0) {
|
||||
WC_FREE_VAR(aes, she->heap);
|
||||
WC_FREE_VAR(cmac, she->heap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ---- Derive K3 = AES-MP(NewKey || CENC) ---- */
|
||||
XMEMCPY(kdfInput, she->newKey, WC_SHE_KEY_SZ);
|
||||
XMEMCPY(kdfInput + WC_SHE_KEY_SZ, she->kdfEncC, WC_SHE_KEY_SZ);
|
||||
ret = wc_She_AesMp16(aes, kdfInput, WC_SHE_KEY_SZ * 2, k3);
|
||||
|
||||
/* ---- Build M4: UID|IDs header + AES-ECB(K3, m4pHeader) ---- */
|
||||
if (ret == 0) {
|
||||
XMEMSET(she->m4, 0, WC_SHE_M4_SZ);
|
||||
|
||||
XMEMCPY(she->m4, she->uid, WC_SHE_UID_SZ);
|
||||
she->m4[WC_SHE_M4_KID_OFFSET] =
|
||||
(byte)((she->targetKeyId << WC_SHE_M4_KID_SHIFT) |
|
||||
(she->authKeyId << WC_SHE_M4_AID_SHIFT));
|
||||
|
||||
/* Copy pre-built M4P header (counter|pad) into M4 counter block */
|
||||
XMEMCPY(she->m4 + WC_SHE_M4_COUNT_OFFSET, she->m4pHeader,
|
||||
WC_SHE_KEY_SZ);
|
||||
|
||||
/* Encrypt the 16-byte counter block in-place with AES-ECB */
|
||||
ret = wc_AesSetKey(aes, k3, WC_SHE_KEY_SZ, NULL, AES_ENCRYPTION);
|
||||
if (ret == 0) {
|
||||
ret = wc_AesEncryptDirect(aes,
|
||||
she->m4 + WC_SHE_M4_COUNT_OFFSET,
|
||||
she->m4 + WC_SHE_M4_COUNT_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Derive K4 = AES-MP(NewKey || CMAC) ---- */
|
||||
if (ret == 0) {
|
||||
XMEMCPY(kdfInput + WC_SHE_KEY_SZ, she->kdfMacC, WC_SHE_KEY_SZ);
|
||||
ret = wc_She_AesMp16(aes, kdfInput, WC_SHE_KEY_SZ * 2, k4);
|
||||
}
|
||||
|
||||
/* ---- Build M5 = AES-CMAC(K4, M4) ---- */
|
||||
if (ret == 0) {
|
||||
cmacSz = AES_BLOCK_SIZE;
|
||||
ret = wc_AesCmacGenerate_ex(cmac, she->m5, &cmacSz,
|
||||
she->m4, WC_SHE_M4_SZ, k4, WC_SHE_KEY_SZ,
|
||||
she->heap, she->devId);
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
she->verified = 1;
|
||||
}
|
||||
|
||||
ForceZero(k3, sizeof(k3));
|
||||
ForceZero(k4, sizeof(k4));
|
||||
ForceZero(kdfInput, sizeof(kdfInput));
|
||||
|
||||
wc_AesFree(aes);
|
||||
WC_FREE_VAR(aes, she->heap);
|
||||
WC_FREE_VAR(cmac, she->heap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Export Key (callback optional) */
|
||||
/* */
|
||||
/* Software: copies computed messages from context into caller buffers. */
|
||||
/* Any pointer may be NULL to skip that message. */
|
||||
/* M1/M2/M3 require generated state, M4/M5 require verified state. */
|
||||
/* Callback: asks hardware to export the key as M1-M5. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
int wc_SHE_ExportKey(wc_SHE* she,
|
||||
byte* m1, word32 m1Sz,
|
||||
byte* m2, word32 m2Sz,
|
||||
byte* m3, word32 m3Sz,
|
||||
byte* m4, word32 m4Sz,
|
||||
byte* m5, word32 m5Sz,
|
||||
const void* ctx)
|
||||
{
|
||||
if (she == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
/* Verify buffer sizes for any non-NULL pointers */
|
||||
if ((m1 != NULL && m1Sz < WC_SHE_M1_SZ) ||
|
||||
(m2 != NULL && m2Sz < WC_SHE_M2_SZ) ||
|
||||
(m3 != NULL && m3Sz < WC_SHE_M3_SZ) ||
|
||||
(m4 != NULL && m4Sz < WC_SHE_M4_SZ) ||
|
||||
(m5 != NULL && m5Sz < WC_SHE_M5_SZ)) {
|
||||
return BUFFER_E;
|
||||
}
|
||||
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
if (she->devId != INVALID_DEVID) {
|
||||
int ret = wc_CryptoCb_SheExportKey(she,
|
||||
m1, m1Sz, m2, m2Sz, m3, m3Sz,
|
||||
m4, m4Sz, m5, m5Sz, ctx);
|
||||
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
|
||||
return ret;
|
||||
}
|
||||
/* fall-through to software path */
|
||||
}
|
||||
#endif
|
||||
(void)ctx;
|
||||
|
||||
/* Export M1/M2/M3 if requested */
|
||||
if (m1 != NULL || m2 != NULL || m3 != NULL) {
|
||||
if (!she->generated) {
|
||||
return BAD_STATE_E;
|
||||
}
|
||||
if (m1 != NULL) {
|
||||
XMEMCPY(m1, she->m1, WC_SHE_M1_SZ);
|
||||
}
|
||||
if (m2 != NULL) {
|
||||
XMEMCPY(m2, she->m2, WC_SHE_M2_SZ);
|
||||
}
|
||||
if (m3 != NULL) {
|
||||
XMEMCPY(m3, she->m3, WC_SHE_M3_SZ);
|
||||
}
|
||||
}
|
||||
|
||||
/* Export M4/M5 if requested */
|
||||
if (m4 != NULL || m5 != NULL) {
|
||||
if (!she->verified) {
|
||||
return BAD_STATE_E;
|
||||
}
|
||||
if (m4 != NULL) {
|
||||
XMEMCPY(m4, she->m4, WC_SHE_M4_SZ);
|
||||
}
|
||||
if (m5 != NULL) {
|
||||
XMEMCPY(m5, she->m5, WC_SHE_M5_SZ);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* WOLFSSL_SHE */
|
||||
@@ -348,6 +348,9 @@ static const byte const_byte_array[] = "A+Gd\0\0\0";
|
||||
#include <wolfssl/wolfcrypt/aes.h>
|
||||
#include <wolfssl/wolfcrypt/wc_encrypt.h>
|
||||
#include <wolfssl/wolfcrypt/cmac.h>
|
||||
#ifdef WOLFSSL_SHE
|
||||
#include <wolfssl/wolfcrypt/she.h>
|
||||
#endif
|
||||
#include <wolfssl/wolfcrypt/siphash.h>
|
||||
#include <wolfssl/wolfcrypt/poly1305.h>
|
||||
#include <wolfssl/wolfcrypt/camellia.h>
|
||||
@@ -866,6 +869,9 @@ 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);
|
||||
#ifdef WOLFSSL_SHE
|
||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t she_test(void);
|
||||
#endif
|
||||
#ifdef HAVE_ASCON
|
||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ascon_hash256_test(void);
|
||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ascon_aead128_test(void);
|
||||
@@ -3183,6 +3189,13 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\
|
||||
TEST_PASS("CMAC test passed!\n");
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_SHE) && !defined(NO_AES)
|
||||
if ( (ret = she_test()) != 0)
|
||||
TEST_FAIL("SHE test failed!\n", ret);
|
||||
else
|
||||
TEST_PASS("SHE test passed!\n");
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_SIPHASH)
|
||||
if ( (ret = siphash_test()) != 0)
|
||||
TEST_FAIL("SipHash test failed!\n", ret);
|
||||
@@ -56601,6 +56614,171 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cmac_test(void)
|
||||
|
||||
#endif /* !NO_AES && WOLFSSL_CMAC */
|
||||
|
||||
#if defined(WOLFSSL_SHE) && !defined(NO_AES)
|
||||
|
||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t she_test(void)
|
||||
{
|
||||
wc_test_ret_t ret = 0;
|
||||
byte m1[WC_SHE_M1_SZ];
|
||||
byte m2[WC_SHE_M2_SZ];
|
||||
byte m3[WC_SHE_M3_SZ];
|
||||
byte m4[WC_SHE_M4_SZ];
|
||||
byte m5[WC_SHE_M5_SZ];
|
||||
WC_DECLARE_VAR(she, wc_SHE, 1, HEAP_HINT);
|
||||
|
||||
/* SHE specification test vector (from wolfHSM wh_test_she.c) */
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte sheUid[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
|
||||
};
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte vectorAuthKey[] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
|
||||
};
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte vectorNewKey[] = {
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
|
||||
};
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte expM1[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x41
|
||||
};
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte expM2[] = {
|
||||
0x2b, 0x11, 0x1e, 0x2d, 0x93, 0xf4, 0x86, 0x56,
|
||||
0x6b, 0xcb, 0xba, 0x1d, 0x7f, 0x7a, 0x97, 0x97,
|
||||
0xc9, 0x46, 0x43, 0xb0, 0x50, 0xfc, 0x5d, 0x4d,
|
||||
0x7d, 0xe1, 0x4c, 0xff, 0x68, 0x22, 0x03, 0xc3
|
||||
};
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte expM3[] = {
|
||||
0xb9, 0xd7, 0x45, 0xe5, 0xac, 0xe7, 0xd4, 0x18,
|
||||
0x60, 0xbc, 0x63, 0xc2, 0xb9, 0xf5, 0xbb, 0x46
|
||||
};
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte expM4[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x41,
|
||||
0xb4, 0x72, 0xe8, 0xd8, 0x72, 0x7d, 0x70, 0xd5,
|
||||
0x72, 0x95, 0xe7, 0x48, 0x49, 0xa2, 0x79, 0x17
|
||||
};
|
||||
WOLFSSL_SMALL_STACK_STATIC const byte expM5[] = {
|
||||
0x82, 0x0d, 0x8d, 0x95, 0xdc, 0x11, 0xb4, 0x66,
|
||||
0x88, 0x78, 0x16, 0x0c, 0xb2, 0xa4, 0xe2, 0x3e
|
||||
};
|
||||
|
||||
WOLFSSL_ENTER("she_test");
|
||||
|
||||
WC_ALLOC_VAR(she, wc_SHE, 1, HEAP_HINT);
|
||||
if (!WC_VAR_OK(she)) {
|
||||
return WC_TEST_RET_ENC_EC(MEMORY_E);
|
||||
}
|
||||
|
||||
/* ---- Init ---- */
|
||||
ret = wc_SHE_Init(she, HEAP_HINT, devId);
|
||||
if (ret != 0) {
|
||||
WC_FREE_VAR(she, HEAP_HINT);
|
||||
return WC_TEST_RET_ENC_EC(ret);
|
||||
}
|
||||
|
||||
/* ---- Set inputs from test vector ---- */
|
||||
ret = wc_SHE_SetUID(she, sheUid, sizeof(sheUid), NULL);
|
||||
if (ret != 0) {
|
||||
goto exit_SHE_Test;
|
||||
}
|
||||
|
||||
ret = wc_SHE_SetAuthKey(she, WC_SHE_MASTER_ECU_KEY_ID,
|
||||
vectorAuthKey, sizeof(vectorAuthKey));
|
||||
if (ret != 0) {
|
||||
goto exit_SHE_Test;
|
||||
}
|
||||
|
||||
ret = wc_SHE_SetNewKey(she, 4, vectorNewKey, sizeof(vectorNewKey));
|
||||
if (ret != 0) {
|
||||
goto exit_SHE_Test;
|
||||
}
|
||||
|
||||
ret = wc_SHE_SetCounter(she, 1);
|
||||
if (ret != 0) {
|
||||
goto exit_SHE_Test;
|
||||
}
|
||||
|
||||
ret = wc_SHE_SetFlags(she, 0);
|
||||
if (ret != 0) {
|
||||
goto exit_SHE_Test;
|
||||
}
|
||||
|
||||
/* ---- Generate M1/M2/M3 ---- */
|
||||
ret = wc_SHE_GenerateM1M2M3(she);
|
||||
if (ret != 0) {
|
||||
goto exit_SHE_Test;
|
||||
}
|
||||
|
||||
/* ---- Export M1/M2/M3 ---- */
|
||||
ret = wc_SHE_ExportKey(she,
|
||||
m1, WC_SHE_M1_SZ,
|
||||
m2, WC_SHE_M2_SZ,
|
||||
m3, WC_SHE_M3_SZ,
|
||||
NULL, 0,
|
||||
NULL, 0,
|
||||
NULL);
|
||||
if (ret != 0) {
|
||||
goto exit_SHE_Test;
|
||||
}
|
||||
|
||||
/* ---- Check M1 ---- */
|
||||
if (XMEMCMP(m1, expM1, WC_SHE_M1_SZ) != 0) {
|
||||
ret = WC_TEST_RET_ENC_NC;
|
||||
goto exit_SHE_Test;
|
||||
}
|
||||
|
||||
/* ---- Check M2 ---- */
|
||||
if (XMEMCMP(m2, expM2, WC_SHE_M2_SZ) != 0) {
|
||||
ret = WC_TEST_RET_ENC_NC;
|
||||
goto exit_SHE_Test;
|
||||
}
|
||||
|
||||
/* ---- Check M3 ---- */
|
||||
if (XMEMCMP(m3, expM3, WC_SHE_M3_SZ) != 0) {
|
||||
ret = WC_TEST_RET_ENC_NC;
|
||||
goto exit_SHE_Test;
|
||||
}
|
||||
|
||||
/* ---- Compute M4/M5 ---- */
|
||||
ret = wc_SHE_GenerateM4M5(she);
|
||||
if (ret != 0) {
|
||||
goto exit_SHE_Test;
|
||||
}
|
||||
|
||||
/* ---- Export M4/M5 ---- */
|
||||
ret = wc_SHE_ExportKey(she,
|
||||
NULL, 0,
|
||||
NULL, 0,
|
||||
NULL, 0,
|
||||
m4, WC_SHE_M4_SZ,
|
||||
m5, WC_SHE_M5_SZ,
|
||||
NULL);
|
||||
if (ret != 0) {
|
||||
goto exit_SHE_Test;
|
||||
}
|
||||
|
||||
/* ---- Check M4 ---- */
|
||||
if (XMEMCMP(m4, expM4, WC_SHE_M4_SZ) != 0) {
|
||||
ret = WC_TEST_RET_ENC_NC;
|
||||
goto exit_SHE_Test;
|
||||
}
|
||||
|
||||
/* ---- Check M5 ---- */
|
||||
if (XMEMCMP(m5, expM5, WC_SHE_M5_SZ) != 0) {
|
||||
ret = WC_TEST_RET_ENC_NC;
|
||||
goto exit_SHE_Test;
|
||||
}
|
||||
|
||||
exit_SHE_Test:
|
||||
wc_SHE_Free(she);
|
||||
WC_FREE_VAR(she, HEAP_HINT);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* WOLFSSL_SHE && !NO_AES */
|
||||
|
||||
#if defined(WOLFSSL_SIPHASH)
|
||||
|
||||
#if WOLFSSL_SIPHASH_CROUNDS == 2 && WOLFSSL_SIPHASH_DROUNDS == 4
|
||||
@@ -66714,6 +66892,16 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (info->free.algo == WC_ALGO_TYPE_SHE) {
|
||||
#if defined(WOLFSSL_SHE) && !defined(NO_AES)
|
||||
wc_SHE* she = (wc_SHE*)info->free.obj;
|
||||
she->devId = INVALID_DEVID;
|
||||
wc_SHE_Free(she);
|
||||
ret = 0;
|
||||
#else
|
||||
ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN);
|
||||
}
|
||||
@@ -67153,7 +67341,53 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
|
||||
}
|
||||
#endif /* HAVE_CMAC_KDF */
|
||||
}
|
||||
#if defined(WOLFSSL_SHE) && !defined(NO_AES)
|
||||
else if (info->algo_type == WC_ALGO_TYPE_SHE) {
|
||||
wc_SHE* she = (wc_SHE*)info->she.she;
|
||||
int savedDevId;
|
||||
|
||||
if (she == NULL) {
|
||||
return NOT_COMPILED_IN;
|
||||
}
|
||||
|
||||
/* Save and override devId so re-call uses software path */
|
||||
savedDevId = she->devId;
|
||||
she->devId = INVALID_DEVID;
|
||||
|
||||
switch (info->she.type) {
|
||||
case WC_SHE_SET_UID:
|
||||
ret = wc_SHE_SetUID(she, info->she.op.setUid.uid,
|
||||
info->she.op.setUid.uidSz,
|
||||
info->she.ctx);
|
||||
break;
|
||||
case WC_SHE_GENERATE_M4M5:
|
||||
/* Re-call with software devId — fills she->m4/m5 */
|
||||
ret = wc_SHE_GenerateM4M5(she);
|
||||
break;
|
||||
case WC_SHE_EXPORT_KEY:
|
||||
/* Fall back to software export */
|
||||
ret = wc_SHE_ExportKey(she,
|
||||
info->she.op.exportKey.m1,
|
||||
info->she.op.exportKey.m1Sz,
|
||||
info->she.op.exportKey.m2,
|
||||
info->she.op.exportKey.m2Sz,
|
||||
info->she.op.exportKey.m3,
|
||||
info->she.op.exportKey.m3Sz,
|
||||
info->she.op.exportKey.m4,
|
||||
info->she.op.exportKey.m4Sz,
|
||||
info->she.op.exportKey.m5,
|
||||
info->she.op.exportKey.m5Sz,
|
||||
info->she.ctx);
|
||||
break;
|
||||
default:
|
||||
ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Restore devId */
|
||||
she->devId = savedDevId;
|
||||
}
|
||||
#endif /* WOLFSSL_SHE && !NO_AES */
|
||||
|
||||
(void)devIdArg;
|
||||
(void)myCtx;
|
||||
|
||||
@@ -65,6 +65,9 @@
|
||||
#ifdef WOLFSSL_CMAC
|
||||
#include <wolfssl/wolfcrypt/cmac.h>
|
||||
#endif
|
||||
#ifdef WOLFSSL_SHE
|
||||
#include <wolfssl/wolfcrypt/she.h>
|
||||
#endif
|
||||
#ifdef HAVE_ED25519
|
||||
#include <wolfssl/wolfcrypt/ed25519.h>
|
||||
#endif
|
||||
@@ -478,6 +481,31 @@ typedef struct wc_CryptoInfo {
|
||||
int type;
|
||||
} cmac;
|
||||
#endif
|
||||
#ifdef WOLFSSL_SHE
|
||||
struct {
|
||||
void* she; /* wc_SHE* context */
|
||||
int type; /* enum wc_SheType - discriminator */
|
||||
const void* ctx; /* read-only caller context */
|
||||
union {
|
||||
struct {
|
||||
const byte* uid; /* caller-provided UID (may be NULL) */
|
||||
word32 uidSz; /* size of uid buffer */
|
||||
} setUid;
|
||||
struct {
|
||||
byte* m1; /* output: M1 */
|
||||
word32 m1Sz;
|
||||
byte* m2; /* output: M2 */
|
||||
word32 m2Sz;
|
||||
byte* m3; /* output: M3 */
|
||||
word32 m3Sz;
|
||||
byte* m4; /* output: M4 */
|
||||
word32 m4Sz;
|
||||
byte* m5; /* output: M5 */
|
||||
word32 m5Sz;
|
||||
} exportKey;
|
||||
} op;
|
||||
} she;
|
||||
#endif
|
||||
#ifndef NO_CERTS
|
||||
struct {
|
||||
const byte *id;
|
||||
@@ -799,6 +827,22 @@ WOLFSSL_LOCAL int wc_CryptoCb_Cmac(Cmac* cmac, const byte* key, word32 keySz,
|
||||
void* ctx);
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_SHE
|
||||
WOLFSSL_LOCAL int wc_CryptoCb_SheSetUid(wc_SHE* she, const byte* uid,
|
||||
word32 uidSz, const void* ctx);
|
||||
WOLFSSL_LOCAL int wc_CryptoCb_SheGenerateM1M2M3(wc_SHE* she,
|
||||
const void* ctx);
|
||||
WOLFSSL_LOCAL int wc_CryptoCb_SheGenerateM4M5(wc_SHE* she,
|
||||
const void* ctx);
|
||||
WOLFSSL_LOCAL int wc_CryptoCb_SheExportKey(wc_SHE* she,
|
||||
byte* m1, word32 m1Sz,
|
||||
byte* m2, word32 m2Sz,
|
||||
byte* m3, word32 m3Sz,
|
||||
byte* m4, word32 m4Sz,
|
||||
byte* m5, word32 m5Sz,
|
||||
const void* ctx);
|
||||
#endif
|
||||
|
||||
#ifndef NO_CERTS
|
||||
WOLFSSL_LOCAL int wc_CryptoCb_GetCert(int devId, const char *label,
|
||||
word32 labelLen, const byte *id, word32 idLen, byte** out,
|
||||
|
||||
@@ -10,6 +10,7 @@ nobase_include_HEADERS+= \
|
||||
wolfssl/wolfcrypt/poly1305.h \
|
||||
wolfssl/wolfcrypt/camellia.h \
|
||||
wolfssl/wolfcrypt/cmac.h \
|
||||
wolfssl/wolfcrypt/she.h \
|
||||
wolfssl/wolfcrypt/coding.h \
|
||||
wolfssl/wolfcrypt/compress.h \
|
||||
wolfssl/wolfcrypt/des3.h \
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/* she.h
|
||||
*
|
||||
* Copyright (C) 2006-2026 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_SHE_H
|
||||
#define WOLF_CRYPT_SHE_H
|
||||
|
||||
#include <wolfssl/wolfcrypt/settings.h>
|
||||
|
||||
#ifdef WOLFSSL_SHE
|
||||
|
||||
#include <wolfssl/wolfcrypt/types.h>
|
||||
#include <wolfssl/wolfcrypt/aes.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define WC_SHE_KEY_SZ 16
|
||||
#define WC_SHE_UID_SZ 15
|
||||
|
||||
#define WC_SHE_M1_SZ 16
|
||||
#define WC_SHE_M2_SZ 32
|
||||
#define WC_SHE_M3_SZ 16
|
||||
#define WC_SHE_M4_SZ 32
|
||||
#define WC_SHE_M5_SZ 16
|
||||
|
||||
/* crypto callback sub-types for WC_ALGO_TYPE_SHE */
|
||||
enum wc_SheType {
|
||||
WC_SHE_SET_UID = 1,
|
||||
WC_SHE_GENERATE_M1M2M3 = 2,
|
||||
WC_SHE_GENERATE_M4M5 = 3,
|
||||
WC_SHE_EXPORT_KEY = 4
|
||||
};
|
||||
|
||||
/* test flags (only used for KATs) */
|
||||
#define WC_SHE_MASTER_ECU_KEY_ID 1
|
||||
#define WC_SHE_FLAG_WRITE_PROTECT 0x01
|
||||
#define WC_SHE_FLAG_BOOT_PROTECT 0x02
|
||||
|
||||
/* internal field offsets and shifts for message construction */
|
||||
#define WC_SHE_M1_KID_OFFSET 15
|
||||
#define WC_SHE_M1_KID_SHIFT 4
|
||||
#define WC_SHE_M1_AID_SHIFT 0
|
||||
|
||||
#define WC_SHE_M2_COUNT_SHIFT 4
|
||||
#define WC_SHE_M2_FLAGS_SHIFT 0
|
||||
#define WC_SHE_M2_KEY_OFFSET 16
|
||||
|
||||
#define WC_SHE_M4_KID_OFFSET 15
|
||||
#define WC_SHE_M4_KID_SHIFT 4
|
||||
#define WC_SHE_M4_AID_SHIFT 0
|
||||
#define WC_SHE_M4_COUNT_OFFSET 16
|
||||
#define WC_SHE_M4_COUNT_SHIFT 4
|
||||
#define WC_SHE_M4_COUNT_PAD 0x8
|
||||
|
||||
/* SHE KDF constants (Miyaguchi-Preneel input) */
|
||||
#define WC_SHE_KEY_UPDATE_ENC_C { \
|
||||
0x01, 0x01, 0x53, 0x48, \
|
||||
0x45, 0x00, 0x80, 0x00, \
|
||||
0x00, 0x00, 0x00, 0x00, \
|
||||
0x00, 0x00, 0x00, 0xB0 \
|
||||
}
|
||||
|
||||
#define WC_SHE_KEY_UPDATE_MAC_C { \
|
||||
0x01, 0x02, 0x53, 0x48, \
|
||||
0x45, 0x00, 0x80, 0x00, \
|
||||
0x00, 0x00, 0x00, 0x00, \
|
||||
0x00, 0x00, 0x00, 0xB0 \
|
||||
}
|
||||
|
||||
enum {
|
||||
WC_SHE_MAX_ID_LEN = 32,
|
||||
WC_SHE_MAX_LABEL_LEN = 32
|
||||
};
|
||||
|
||||
typedef struct wc_SHE {
|
||||
byte uid[WC_SHE_UID_SZ];
|
||||
byte authKeyId;
|
||||
byte targetKeyId;
|
||||
byte authKey[WC_SHE_KEY_SZ];
|
||||
byte newKey[WC_SHE_KEY_SZ];
|
||||
word32 counter;
|
||||
byte flags;
|
||||
|
||||
byte kdfEncC[WC_SHE_KEY_SZ]; /* KDF encryption constant (CENC) */
|
||||
byte kdfMacC[WC_SHE_KEY_SZ]; /* KDF authentication constant (CMAC) */
|
||||
byte m2pHeader[WC_SHE_KEY_SZ]; /* M2P cleartext header (counter|flags|pad) */
|
||||
byte m4pHeader[WC_SHE_KEY_SZ]; /* M4P cleartext header (counter|pad) */
|
||||
byte m2pOverride; /* set by SetM2Header to skip auto-build */
|
||||
byte m4pOverride; /* set by SetM4Header to skip auto-build */
|
||||
|
||||
byte m1[WC_SHE_M1_SZ];
|
||||
byte m2[WC_SHE_M2_SZ];
|
||||
byte m3[WC_SHE_M3_SZ];
|
||||
byte m4[WC_SHE_M4_SZ];
|
||||
byte m5[WC_SHE_M5_SZ];
|
||||
|
||||
byte generated;
|
||||
byte verified;
|
||||
|
||||
void* heap;
|
||||
int devId;
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
void* devCtx;
|
||||
#endif
|
||||
#ifdef WOLF_PRIVATE_KEY_ID
|
||||
byte id[WC_SHE_MAX_ID_LEN];
|
||||
int idLen;
|
||||
char label[WC_SHE_MAX_LABEL_LEN];
|
||||
int labelLen;
|
||||
#endif
|
||||
} wc_SHE;
|
||||
|
||||
|
||||
/* Initialize SHE context, store heap hint and device ID */
|
||||
WOLFSSL_API int wc_SHE_Init(wc_SHE* she, void* heap, int devId);
|
||||
|
||||
#ifdef WOLF_PRIVATE_KEY_ID
|
||||
/* Initialize with opaque hardware key identifier */
|
||||
WOLFSSL_API int wc_SHE_Init_Id(wc_SHE* she, unsigned char* id, int len,
|
||||
void* heap, int devId);
|
||||
/* Initialize with human-readable key label */
|
||||
WOLFSSL_API int wc_SHE_Init_Label(wc_SHE* she, const char* label,
|
||||
void* heap, int devId);
|
||||
#endif
|
||||
|
||||
/* Scrub key material and zero the context */
|
||||
WOLFSSL_API void wc_SHE_Free(wc_SHE* she);
|
||||
|
||||
/* Set UID; callback optional (WC_SHE_SET_UID) */
|
||||
WOLFSSL_API int wc_SHE_SetUID(wc_SHE* she, const byte* uid, word32 uidSz,
|
||||
const void* ctx);
|
||||
|
||||
/* Set authorizing key slot ID and value */
|
||||
WOLFSSL_API int wc_SHE_SetAuthKey(wc_SHE* she, byte authKeyId,
|
||||
const byte* authKey, word32 keySz);
|
||||
|
||||
/* Set target key slot ID and new key value */
|
||||
WOLFSSL_API int wc_SHE_SetNewKey(wc_SHE* she, byte targetKeyId,
|
||||
const byte* newKey, word32 keySz);
|
||||
|
||||
/* Set monotonic counter value for M2 */
|
||||
WOLFSSL_API int wc_SHE_SetCounter(wc_SHE* she, word32 counter);
|
||||
|
||||
/* Set flag byte for M2 */
|
||||
WOLFSSL_API int wc_SHE_SetFlags(wc_SHE* she, byte flags);
|
||||
|
||||
/* Set KDF constants (CENC/CMAC) used for key derivation.
|
||||
* Defaults are set by Init. Either pointer may be NULL to skip. */
|
||||
WOLFSSL_API int wc_SHE_SetKdfConstants(wc_SHE* she,
|
||||
const byte* encC, word32 encCSz,
|
||||
const byte* macC, word32 macCSz);
|
||||
|
||||
/* Override M2P cleartext header (first 16 bytes before KID').
|
||||
* Skips auto-build from counter/flags in GenerateM1M2M3. */
|
||||
WOLFSSL_API int wc_SHE_SetM2Header(wc_SHE* she,
|
||||
const byte* header, word32 headerSz);
|
||||
|
||||
/* Override M4P cleartext header (16-byte counter block).
|
||||
* Skips auto-build from counter in GenerateM4M5. */
|
||||
WOLFSSL_API int wc_SHE_SetM4Header(wc_SHE* she,
|
||||
const byte* header, word32 headerSz);
|
||||
|
||||
/* Generate M1/M2/M3 from the current context */
|
||||
WOLFSSL_API int wc_SHE_GenerateM1M2M3(wc_SHE* she);
|
||||
|
||||
/* Miyaguchi-Preneel AES-128 compression (internal, exposed for testing) */
|
||||
WOLFSSL_TEST_VIS int wc_She_AesMp16(Aes* aes, const byte* in, word32 inSz,
|
||||
byte* out);
|
||||
|
||||
/* Generate M4/M5 verification messages; callback optional (WC_SHE_GENERATE_M4M5) */
|
||||
WOLFSSL_API int wc_SHE_GenerateM4M5(wc_SHE* she);
|
||||
|
||||
/* Export M1-M5 into caller buffers; NULL to skip; callback optional (WC_SHE_EXPORT_KEY) */
|
||||
WOLFSSL_API int wc_SHE_ExportKey(wc_SHE* she,
|
||||
byte* m1, word32 m1Sz,
|
||||
byte* m2, word32 m2Sz,
|
||||
byte* m3, word32 m3Sz,
|
||||
byte* m4, word32 m4Sz,
|
||||
byte* m5, word32 m5Sz,
|
||||
const void* ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* WOLFSSL_SHE */
|
||||
#endif /* WOLF_CRYPT_SHE_H */
|
||||
@@ -1426,7 +1426,8 @@ enum wc_AlgoType {
|
||||
WC_ALGO_TYPE_FREE = 11,
|
||||
WC_ALGO_TYPE_SETKEY = 12,
|
||||
WC_ALGO_TYPE_EXPORT_KEY = 13,
|
||||
WC_ALGO_TYPE_MAX = WC_ALGO_TYPE_EXPORT_KEY
|
||||
WC_ALGO_TYPE_SHE = 14,
|
||||
WC_ALGO_TYPE_MAX = WC_ALGO_TYPE_SHE
|
||||
};
|
||||
|
||||
/* KDF types */
|
||||
|
||||
Reference in New Issue
Block a user