Skip to content

Commit 09d0839

Browse files
committed
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.
1 parent c807903 commit 09d0839

File tree

4 files changed

+72
-20
lines changed

4 files changed

+72
-20
lines changed

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2726,7 +2726,7 @@ AC_ARG_ENABLE([faultharden],
27262726

27272727
if test "$ENABLED_FAULTHARDEN" = "yes"
27282728
then
2729-
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CHECK_SIG_FAULTS -DWOLFSSL_CHECK_VER_FAULTS -DWC_SHA3_HARDEN"
2729+
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CHECK_SIG_FAULTS -DWOLFSSL_CHECK_VER_FAULTS -DWC_SHA3_FAULT_HARDEN -DWC_MLKEM_FAULT_HARDEN -DWC_MLDSA_FAULT_HARDEN"
27302730
fi
27312731

27322732
AC_ARG_ENABLE([compileharden],

wolfcrypt/src/dilithium.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8138,6 +8138,9 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key,
81388138
sword32* ct0 = NULL;
81398139
byte priv_rand_seed[DILITHIUM_Y_SEED_SZ];
81408140
byte* h = sig + params->lambda / 4 + params->zEncSz;
8141+
#ifdef WC_MLDSA_FAULT_HARDEN
8142+
sword32* y_check;
8143+
#endif
81418144

81428145
/* Check the signature buffer isn't too small. */
81438146
if (*sigLen < params->sigSz) {
@@ -8202,6 +8205,9 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key,
82028205
ret = MEMORY_E;
82038206
}
82048207
else {
8208+
#ifdef WC_MLDSA_FAULT_HARDEN
8209+
y_check = y;
8210+
#endif
82058211
w0 = y + params->s1Sz / sizeof(*y);
82068212
w1 = w0 + params->s2Sz / sizeof(*w0);
82078213
c = w1 + params->s2Sz / sizeof(*w1);
@@ -8270,6 +8276,12 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key,
82708276
{
82718277
/* Step 13: NTT-1(A o NTT(y)) */
82728278
XMEMCPY(y_ntt, y, params->s1Sz);
8279+
#ifdef WC_MLDSA_FAULT_HARDEN
8280+
if (y_check != y) {
8281+
valid = 0;
8282+
ret = BAD_COND_E;
8283+
}
8284+
#endif
82738285
dilithium_vec_ntt_full(y_ntt, params->l);
82748286
dilithium_matrix_mul(w, a, y_ntt, params->k, params->l);
82758287
dilithium_vec_invntt_full(w, params->k);
@@ -8411,6 +8423,9 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key,
84118423
byte maxK = (byte)min(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A,
84128424
params->k);
84138425
#endif
8426+
#ifdef WC_MLDSA_FAULT_HARDEN
8427+
sword32* y_check;
8428+
#endif
84148429

84158430
/* Check the signature buffer isn't too small. */
84168431
if ((ret == 0) && (*sigLen < params->sigSz)) {
@@ -8442,6 +8457,9 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key,
84428457
ret = MEMORY_E;
84438458
}
84448459
else {
8460+
#ifdef WC_MLDSA_FAULT_HARDEN
8461+
y_check = y;
8462+
#endif
84458463
w0 = y + params->s1Sz / sizeof(*y_ntt);
84468464
w1 = w0 + params->s2Sz / sizeof(*w0);
84478465
blocks = (byte*)(w1 + params->s2Sz / sizeof(*w1));
@@ -8557,6 +8575,16 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key,
85578575
#else
85588576
sword32* y_ntt_t = y_ntt;
85598577
#endif
8578+
#ifdef WC_MLDSA_FAULT_HARDEN
8579+
sword32* yt_check = yt;
8580+
#endif
8581+
#ifdef WC_MLDSA_FAULT_HARDEN
8582+
if (y_check != y) {
8583+
valid = 0;
8584+
ret = BAD_COND_E;
8585+
break;
8586+
}
8587+
#endif
85608588

85618589
/* Put r/i into buffer to be hashed. */
85628590
aseed[DILITHIUM_PUB_SEED_SZ + 1] = r;
@@ -8571,6 +8599,12 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key,
85718599
break;
85728600
}
85738601
XMEMCPY(y_ntt_t, yt, DILITHIUM_POLY_SIZE);
8602+
#ifdef WC_MLDSA_FAULT_HARDEN
8603+
if (yt_check + s * DILITHIUM_N != yt) {
8604+
ret = BAD_COND_E;
8605+
break;
8606+
}
8607+
#endif
85748608
dilithium_ntt_full(y_ntt_t);
85758609
/* Matrix multiply. */
85768610
#ifndef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
@@ -8669,6 +8703,9 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key,
86698703
/* Next polynomial. */
86708704
yt += DILITHIUM_N;
86718705
}
8706+
if (ret != 0) {
8707+
break;
8708+
}
86728709
#ifdef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
86738710
for (e = 0; e < DILITHIUM_N; e++) {
86748711
wt[e] = dilithium_mont_red(t64[e]);

wolfcrypt/src/sha3.c

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ static word64 Load64BitLittleEndian(const byte* a)
595595

596596
return n;
597597
}
598-
#elif defined(WC_SHA3_HARDEN)
598+
#elif defined(WC_SHA3_FAULT_HARDEN)
599599
static WC_INLINE word64 Load64Unaligned(const unsigned char *a)
600600
{
601601
#ifdef WC_64BIT_CPU
@@ -712,9 +712,9 @@ static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p)
712712
{
713713
word32 i;
714714
word32 blocks;
715-
#ifdef WC_SHA3_HARDEN
716-
byte check = 0;
717-
byte total_check = 0;
715+
#ifdef WC_SHA3_FAULT_HARDEN
716+
word32 check = 0;
717+
word32 total_check = 0;
718718
#endif
719719

720720
#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)
732732
t = &sha3->t[sha3->i];
733733
for (i = 0; i < l; i++) {
734734
t[i] = data[i];
735-
#ifdef WC_SHA3_HARDEN
735+
#ifdef WC_SHA3_FAULT_HARDEN
736736
check++;
737737
#endif
738738
}
739-
#ifdef WC_SHA3_HARDEN
739+
#ifdef WC_SHA3_FAULT_HARDEN
740740
if (check != l) {
741741
return BAD_COND_E;
742742
}
@@ -747,16 +747,16 @@ static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p)
747747
sha3->i = (byte)(sha3->i + i);
748748

749749
if (sha3->i == p * 8) {
750-
#if !defined(BIG_ENDIAN_ORDER) && !defined(WC_SHA3_HARDEN)
750+
#if !defined(BIG_ENDIAN_ORDER) && !defined(WC_SHA3_FAULT_HARDEN)
751751
xorbuf(sha3->s, sha3->t, (word32)(p * 8));
752752
#else
753753
for (i = 0; i < p; i++) {
754754
sha3->s[i] ^= Load64BitLittleEndian(sha3->t + 8 * i);
755-
#ifdef WC_SHA3_HARDEN
755+
#ifdef WC_SHA3_FAULT_HARDEN
756756
check++;
757757
#endif
758758
}
759-
#ifdef WC_SHA3_HARDEN
759+
#ifdef WC_SHA3_FAULT_HARDEN
760760
if (check != p + l) {
761761
return BAD_COND_E;
762762
}
@@ -780,20 +780,20 @@ static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p)
780780
blocks = 0;
781781
}
782782
#endif
783-
#ifdef WC_SHA3_HARDEN
783+
#ifdef WC_SHA3_FAULT_HARDEN
784784
total_check += blocks * p;
785785
#endif
786786
for (; blocks > 0; blocks--) {
787-
#if !defined(BIG_ENDIAN_ORDER) && !defined(WC_SHA3_HARDEN)
787+
#if !defined(BIG_ENDIAN_ORDER) && !defined(WC_SHA3_FAULT_HARDEN)
788788
xorbuf(sha3->s, data, (word32)(p * 8));
789789
#else
790790
for (i = 0; i < p; i++) {
791791
sha3->s[i] ^= Load64Unaligned(data + 8 * i);
792-
#ifdef WC_SHA3_HARDEN
792+
#ifdef WC_SHA3_FAULT_HARDEN
793793
check++;
794794
#endif
795795
}
796-
#ifdef WC_SHA3_HARDEN
796+
#ifdef WC_SHA3_FAULT_HARDEN
797797
if (check != total_check - ((blocks - 1) * p)) {
798798
return BAD_COND_E;
799799
}
@@ -807,7 +807,7 @@ static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p)
807807
len -= p * 8U;
808808
data += p * 8U;
809809
}
810-
#ifdef WC_SHA3_HARDEN
810+
#ifdef WC_SHA3_FAULT_HARDEN
811811
if (check != total_check) {
812812
return BAD_COND_E;
813813
}
@@ -837,14 +837,14 @@ static int Sha3Final(wc_Sha3* sha3, byte padChar, byte* hash, byte p, word32 l)
837837
{
838838
word32 rate = p * 8U;
839839
word32 j;
840-
#if defined(BIG_ENDIAN_ORDER) || defined(WC_SHA3_HARDEN)
840+
#if defined(BIG_ENDIAN_ORDER) || defined(WC_SHA3_FAULT_HARDEN)
841841
word32 i;
842842
#endif
843-
#ifdef WC_SHA3_HARDEN
843+
#ifdef WC_SHA3_FAULT_HARDEN
844844
int check = 0;
845845
#endif
846846

847-
#if !defined(BIG_ENDIAN_ORDER) && !defined(WC_SHA3_HARDEN)
847+
#if !defined(BIG_ENDIAN_ORDER) && !defined(WC_SHA3_FAULT_HARDEN)
848848
xorbuf(sha3->s, sha3->t, sha3->i);
849849
#ifdef WOLFSSL_HASH_FLAGS
850850
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)
867867
}
868868
for (i = 0; i < p; i++) {
869869
sha3->s[i] ^= Load64BitLittleEndian(sha3->t + 8 * i);
870-
#ifdef WC_SHA3_HARDEN
870+
#ifdef WC_SHA3_FAULT_HARDEN
871871
check++;
872872
#endif
873873
}
874-
#ifdef WC_SHA3_HARDEN
874+
#ifdef WC_SHA3_FAULT_HARDEN
875875
if (check != p) {
876876
return BAD_COND_E;
877877
}

wolfcrypt/src/wc_mlkem.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,11 @@ int wc_MlKemKey_MakeKeyWithRandom(MlKemKey* key, const unsigned char* rand,
434434
{
435435
byte buf[2 * WC_ML_KEM_SYM_SZ + 1];
436436
byte* rho = buf;
437+
#ifndef WC_MLKEM_FAULT_HARDEN
437438
byte* sigma = buf + WC_ML_KEM_SYM_SZ;
439+
#else
440+
byte sigma[WC_ML_KEM_SYM_SZ + 1];
441+
#endif
438442
#ifndef WOLFSSL_NO_MALLOC
439443
sword16* e = NULL;
440444
#else
@@ -565,6 +569,17 @@ int wc_MlKemKey_MakeKeyWithRandom(MlKemKey* key, const unsigned char* rand,
565569
}
566570
#endif
567571
}
572+
#ifdef WC_MLKEM_FAULT_HARDEN
573+
if (ret == 0) {
574+
XMEMCPY(sigma, buf + WC_ML_KEM_SYM_SZ, WC_ML_KEM_SYM_SZ);
575+
if (XMEMCMP(sigma, rho, WC_ML_KEM_SYM_SZ) == 0) {
576+
ret = BAD_COND_E;
577+
}
578+
if (XMEMCMP(sigma, rho + WC_ML_KEM_SYM_SZ, WC_ML_KEM_SYM_SZ) != 0) {
579+
ret = BAD_COND_E;
580+
}
581+
}
582+
#endif
568583
if (ret == 0) {
569584
const byte* z = rand + WC_ML_KEM_SYM_SZ;
570585
s = key->priv;

0 commit comments

Comments
 (0)