mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 20:50:49 +02:00
ML-KEM/ML-DSA: harden against fault attacks
ML-DSA: check pointer to the y parameter has not be faulted. ML-KEM: to harden against faultiong, use a different buffer for private seed, sigma, and add a check that the buffer was copied correctly. SHA-3: fix size of check variables.
This commit is contained in:
+1
-1
@@ -2726,7 +2726,7 @@ AC_ARG_ENABLE([faultharden],
|
||||
|
||||
if test "$ENABLED_FAULTHARDEN" = "yes"
|
||||
then
|
||||
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CHECK_SIG_FAULTS -DWOLFSSL_CHECK_VER_FAULTS -DWC_SHA3_HARDEN"
|
||||
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CHECK_SIG_FAULTS -DWOLFSSL_CHECK_VER_FAULTS -DWC_SHA3_FAULT_HARDEN -DWC_MLKEM_FAULT_HARDEN -DWC_MLDSA_FAULT_HARDEN"
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE([compileharden],
|
||||
|
||||
@@ -8138,6 +8138,9 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key,
|
||||
sword32* ct0 = NULL;
|
||||
byte priv_rand_seed[DILITHIUM_Y_SEED_SZ];
|
||||
byte* h = sig + params->lambda / 4 + params->zEncSz;
|
||||
#ifdef WC_MLDSA_FAULT_HARDEN
|
||||
sword32* y_check;
|
||||
#endif
|
||||
|
||||
/* Check the signature buffer isn't too small. */
|
||||
if (*sigLen < params->sigSz) {
|
||||
@@ -8202,6 +8205,9 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key,
|
||||
ret = MEMORY_E;
|
||||
}
|
||||
else {
|
||||
#ifdef WC_MLDSA_FAULT_HARDEN
|
||||
y_check = y;
|
||||
#endif
|
||||
w0 = y + params->s1Sz / sizeof(*y);
|
||||
w1 = w0 + params->s2Sz / sizeof(*w0);
|
||||
c = w1 + params->s2Sz / sizeof(*w1);
|
||||
@@ -8270,6 +8276,14 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key,
|
||||
{
|
||||
/* Step 13: NTT-1(A o NTT(y)) */
|
||||
XMEMCPY(y_ntt, y, params->s1Sz);
|
||||
#ifdef WC_MLDSA_FAULT_HARDEN
|
||||
if (y_check != y) {
|
||||
valid = 0;
|
||||
ret = BAD_COND_E;
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
#endif
|
||||
dilithium_vec_ntt_full(y_ntt, params->l);
|
||||
dilithium_matrix_mul(w, a, y_ntt, params->k, params->l);
|
||||
dilithium_vec_invntt_full(w, params->k);
|
||||
@@ -8411,6 +8425,9 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key,
|
||||
byte maxK = (byte)min(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A,
|
||||
params->k);
|
||||
#endif
|
||||
#ifdef WC_MLDSA_FAULT_HARDEN
|
||||
sword32* y_check;
|
||||
#endif
|
||||
|
||||
/* Check the signature buffer isn't too small. */
|
||||
if ((ret == 0) && (*sigLen < params->sigSz)) {
|
||||
@@ -8442,6 +8459,9 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key,
|
||||
ret = MEMORY_E;
|
||||
}
|
||||
else {
|
||||
#ifdef WC_MLDSA_FAULT_HARDEN
|
||||
y_check = y;
|
||||
#endif
|
||||
w0 = y + params->s1Sz / sizeof(*y_ntt);
|
||||
w1 = w0 + params->s2Sz / sizeof(*w0);
|
||||
blocks = (byte*)(w1 + params->s2Sz / sizeof(*w1));
|
||||
@@ -8557,6 +8577,16 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key,
|
||||
#else
|
||||
sword32* y_ntt_t = y_ntt;
|
||||
#endif
|
||||
#ifdef WC_MLDSA_FAULT_HARDEN
|
||||
sword32* yt_check = yt;
|
||||
#endif
|
||||
#ifdef WC_MLDSA_FAULT_HARDEN
|
||||
if (y_check != y) {
|
||||
valid = 0;
|
||||
ret = BAD_COND_E;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Put r/i into buffer to be hashed. */
|
||||
aseed[DILITHIUM_PUB_SEED_SZ + 1] = r;
|
||||
@@ -8571,6 +8601,12 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key,
|
||||
break;
|
||||
}
|
||||
XMEMCPY(y_ntt_t, yt, DILITHIUM_POLY_SIZE);
|
||||
#ifdef WC_MLDSA_FAULT_HARDEN
|
||||
if (yt_check + s * DILITHIUM_N != yt) {
|
||||
ret = BAD_COND_E;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
dilithium_ntt_full(y_ntt_t);
|
||||
/* Matrix multiply. */
|
||||
#ifndef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
||||
@@ -8669,6 +8705,9 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key,
|
||||
/* Next polynomial. */
|
||||
yt += DILITHIUM_N;
|
||||
}
|
||||
if (ret != 0) {
|
||||
break;
|
||||
}
|
||||
#ifdef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
||||
for (e = 0; e < DILITHIUM_N; e++) {
|
||||
wt[e] = dilithium_mont_red(t64[e]);
|
||||
|
||||
+23
-23
@@ -595,18 +595,18 @@ static word64 Load64BitLittleEndian(const byte* a)
|
||||
|
||||
return n;
|
||||
}
|
||||
#elif defined(WC_SHA3_HARDEN)
|
||||
#elif defined(WC_SHA3_FAULT_HARDEN)
|
||||
static WC_INLINE word64 Load64Unaligned(const unsigned char *a)
|
||||
{
|
||||
#ifdef WC_64BIT_CPU
|
||||
return *(word64*)a;
|
||||
#elif defined(WC_32BIT_CPU)
|
||||
return (((word64)((word32*)a)[1]) << 32) ||
|
||||
return (((word64)((word32*)a)[1]) << 32) |
|
||||
((word32*)a)[0];
|
||||
#else
|
||||
return (((word64)((word16*)a)[3]) << 48) ||
|
||||
(((word64)((word16*)a)[2]) << 32) ||
|
||||
(((word64)((word16*)a)[1]) << 16) ||
|
||||
return (((word64)((word16*)a)[3]) << 48) |
|
||||
(((word64)((word16*)a)[2]) << 32) |
|
||||
(((word64)((word16*)a)[1]) << 16) |
|
||||
((word16*)a)[0];
|
||||
#endif
|
||||
}
|
||||
@@ -712,9 +712,9 @@ static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p)
|
||||
{
|
||||
word32 i;
|
||||
word32 blocks;
|
||||
#ifdef WC_SHA3_HARDEN
|
||||
byte check = 0;
|
||||
byte total_check = 0;
|
||||
#ifdef WC_SHA3_FAULT_HARDEN
|
||||
word32 check = 0;
|
||||
word32 total_check = 0;
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) && defined(USE_INTEL_SPEEDUP)
|
||||
@@ -732,11 +732,11 @@ static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p)
|
||||
t = &sha3->t[sha3->i];
|
||||
for (i = 0; i < l; i++) {
|
||||
t[i] = data[i];
|
||||
#ifdef WC_SHA3_HARDEN
|
||||
#ifdef WC_SHA3_FAULT_HARDEN
|
||||
check++;
|
||||
#endif
|
||||
}
|
||||
#ifdef WC_SHA3_HARDEN
|
||||
#ifdef WC_SHA3_FAULT_HARDEN
|
||||
if (check != l) {
|
||||
return BAD_COND_E;
|
||||
}
|
||||
@@ -747,16 +747,16 @@ static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p)
|
||||
sha3->i = (byte)(sha3->i + i);
|
||||
|
||||
if (sha3->i == p * 8) {
|
||||
#if !defined(BIG_ENDIAN_ORDER) && !defined(WC_SHA3_HARDEN)
|
||||
#if !defined(BIG_ENDIAN_ORDER) && !defined(WC_SHA3_FAULT_HARDEN)
|
||||
xorbuf(sha3->s, sha3->t, (word32)(p * 8));
|
||||
#else
|
||||
for (i = 0; i < p; i++) {
|
||||
sha3->s[i] ^= Load64BitLittleEndian(sha3->t + 8 * i);
|
||||
#ifdef WC_SHA3_HARDEN
|
||||
#ifdef WC_SHA3_FAULT_HARDEN
|
||||
check++;
|
||||
#endif
|
||||
}
|
||||
#ifdef WC_SHA3_HARDEN
|
||||
#ifdef WC_SHA3_FAULT_HARDEN
|
||||
if (check != p + l) {
|
||||
return BAD_COND_E;
|
||||
}
|
||||
@@ -780,20 +780,20 @@ static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p)
|
||||
blocks = 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef WC_SHA3_HARDEN
|
||||
#ifdef WC_SHA3_FAULT_HARDEN
|
||||
total_check += blocks * p;
|
||||
#endif
|
||||
for (; blocks > 0; blocks--) {
|
||||
#if !defined(BIG_ENDIAN_ORDER) && !defined(WC_SHA3_HARDEN)
|
||||
#if !defined(BIG_ENDIAN_ORDER) && !defined(WC_SHA3_FAULT_HARDEN)
|
||||
xorbuf(sha3->s, data, (word32)(p * 8));
|
||||
#else
|
||||
for (i = 0; i < p; i++) {
|
||||
sha3->s[i] ^= Load64Unaligned(data + 8 * i);
|
||||
#ifdef WC_SHA3_HARDEN
|
||||
#ifdef WC_SHA3_FAULT_HARDEN
|
||||
check++;
|
||||
#endif
|
||||
}
|
||||
#ifdef WC_SHA3_HARDEN
|
||||
#ifdef WC_SHA3_FAULT_HARDEN
|
||||
if (check != total_check - ((blocks - 1) * p)) {
|
||||
return BAD_COND_E;
|
||||
}
|
||||
@@ -807,7 +807,7 @@ static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p)
|
||||
len -= p * 8U;
|
||||
data += p * 8U;
|
||||
}
|
||||
#ifdef WC_SHA3_HARDEN
|
||||
#ifdef WC_SHA3_FAULT_HARDEN
|
||||
if (check != total_check) {
|
||||
return BAD_COND_E;
|
||||
}
|
||||
@@ -837,14 +837,14 @@ static int Sha3Final(wc_Sha3* sha3, byte padChar, byte* hash, byte p, word32 l)
|
||||
{
|
||||
word32 rate = p * 8U;
|
||||
word32 j;
|
||||
#if defined(BIG_ENDIAN_ORDER) || defined(WC_SHA3_HARDEN)
|
||||
#if defined(BIG_ENDIAN_ORDER) || defined(WC_SHA3_FAULT_HARDEN)
|
||||
word32 i;
|
||||
#endif
|
||||
#ifdef WC_SHA3_HARDEN
|
||||
#ifdef WC_SHA3_FAULT_HARDEN
|
||||
int check = 0;
|
||||
#endif
|
||||
|
||||
#if !defined(BIG_ENDIAN_ORDER) && !defined(WC_SHA3_HARDEN)
|
||||
#if !defined(BIG_ENDIAN_ORDER) && !defined(WC_SHA3_FAULT_HARDEN)
|
||||
xorbuf(sha3->s, sha3->t, sha3->i);
|
||||
#ifdef WOLFSSL_HASH_FLAGS
|
||||
if ((p == WC_SHA3_256_COUNT) && (sha3->flags & WC_HASH_SHA3_KECCAK256)) {
|
||||
@@ -867,11 +867,11 @@ static int Sha3Final(wc_Sha3* sha3, byte padChar, byte* hash, byte p, word32 l)
|
||||
}
|
||||
for (i = 0; i < p; i++) {
|
||||
sha3->s[i] ^= Load64BitLittleEndian(sha3->t + 8 * i);
|
||||
#ifdef WC_SHA3_HARDEN
|
||||
#ifdef WC_SHA3_FAULT_HARDEN
|
||||
check++;
|
||||
#endif
|
||||
}
|
||||
#ifdef WC_SHA3_HARDEN
|
||||
#ifdef WC_SHA3_FAULT_HARDEN
|
||||
if (check != p) {
|
||||
return BAD_COND_E;
|
||||
}
|
||||
|
||||
@@ -434,7 +434,11 @@ int wc_MlKemKey_MakeKeyWithRandom(MlKemKey* key, const unsigned char* rand,
|
||||
{
|
||||
byte buf[2 * WC_ML_KEM_SYM_SZ + 1];
|
||||
byte* rho = buf;
|
||||
#ifndef WC_MLKEM_FAULT_HARDEN
|
||||
byte* sigma = buf + WC_ML_KEM_SYM_SZ;
|
||||
#else
|
||||
byte sigma[WC_ML_KEM_SYM_SZ + 1];
|
||||
#endif
|
||||
#ifndef WOLFSSL_NO_MALLOC
|
||||
sword16* e = NULL;
|
||||
#else
|
||||
@@ -565,6 +569,17 @@ int wc_MlKemKey_MakeKeyWithRandom(MlKemKey* key, const unsigned char* rand,
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef WC_MLKEM_FAULT_HARDEN
|
||||
if (ret == 0) {
|
||||
XMEMCPY(sigma, buf + WC_ML_KEM_SYM_SZ, WC_ML_KEM_SYM_SZ);
|
||||
if (XMEMCMP(sigma, rho, WC_ML_KEM_SYM_SZ) == 0) {
|
||||
ret = BAD_COND_E;
|
||||
}
|
||||
if (XMEMCMP(sigma, rho + WC_ML_KEM_SYM_SZ, WC_ML_KEM_SYM_SZ) != 0) {
|
||||
ret = BAD_COND_E;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (ret == 0) {
|
||||
const byte* z = rand + WC_ML_KEM_SYM_SZ;
|
||||
s = key->priv;
|
||||
|
||||
Reference in New Issue
Block a user