From fcf1406675431edec24550ced90aa2302afa657a Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Fri, 20 Oct 2023 10:13:50 +1000 Subject: [PATCH] RSA: convert to bin with length in constant time Add mp_to_unsigned_bin_len_ct() which puts a number into a buffer with padding in constant time. Call mp_to_unsigned_bin_len_ct() in RSA when encoding result of exponentiation. --- wolfcrypt/src/rsa.c | 2 +- wolfcrypt/src/sp_int.c | 67 +++++++++++++++++++++++++++++++++++++ wolfssl/wolfcrypt/integer.h | 1 + wolfssl/wolfcrypt/sp_int.h | 2 ++ wolfssl/wolfcrypt/tfm.h | 1 + 5 files changed, 72 insertions(+), 1 deletion(-) diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index 5d491f6bcf..0e9db2fd75 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -2693,7 +2693,7 @@ static int RsaFunctionSync(const byte* in, word32 inLen, byte* out, } if (ret == 0) { - if (mp_to_unsigned_bin_len(tmp, out, (int)*outLen) != MP_OKAY) + if (mp_to_unsigned_bin_len_ct(tmp, out, (int)*outLen) != MP_OKAY) ret = MP_TO_E; } #else diff --git a/wolfcrypt/src/sp_int.c b/wolfcrypt/src/sp_int.c index e9ffed4222..92ddc1509b 100644 --- a/wolfcrypt/src/sp_int.c +++ b/wolfcrypt/src/sp_int.c @@ -17774,6 +17774,73 @@ int sp_to_unsigned_bin_len(const sp_int* a, byte* out, int outSz) return err; } +/* Convert the multi-precision number to an array of bytes in big-endian format. + * + * Constant-time implementation. + * + * The array must be large enough for encoded number - use mp_unsigned_bin_size + * to calculate the number of bytes required. + * Front-pads the output array with zeros to make number the size of the array. + * + * @param [in] a SP integer. + * @param [out] out Array to put encoding into. + * @param [in] outSz Size of the array in bytes. + * + * @return MP_OKAY on success. + * @return MP_VAL when a or out is NULL. + */ +int sp_to_unsigned_bin_len_ct(const sp_int* a, byte* out, int outSz) +{ + int err = MP_OKAY; + + /* Validate parameters. */ + if ((a == NULL) || (out == NULL) || (outSz < 0)) { + err = MP_VAL; + } + +#if SP_WORD_SIZE > 8 + if (err == MP_OKAY) { + /* Start at the end of the buffer - least significant byte. */ + int j; + unsigned int i; + sp_digit mask = (sp_digit)-1; + sp_int_digit d; + + /* Put each digit in. */ + i = 0; + for (j = outSz - 1; j >= 0; ) { + int b; + d = a->dp[i]; + /* Place each byte of a digit into the buffer. */ + for (b = 0; (j >= 0) && (b < SP_WORD_SIZEOF); b++) { + out[j--] = (byte)(d & mask); + d >>= 8; + } + mask &= (sp_digit)0 - (i < a->used - 1); + i += (unsigned int)(1 & mask); + } + } +#else + if ((err == MP_OKAY) && ((unsigned int)outSz < a->used)) { + err = MP_VAL; + } + if (err == MP_OKAY) { + unsigned int i; + int j; + sp_digit mask = (sp_digit)-1; + + i = 0; + for (j = outSz - 1; j >= 0; j--) { + out[j] = a->dp[i] & mask; + mask &= (sp_digit)0 - (i < a->used - 1); + i += (unsigned int)(1 & mask); + } + } +#endif + + return err; +} + #if defined(WOLFSSL_SP_MATH_ALL) && !defined(NO_RSA) && \ !defined(WOLFSSL_RSA_VERIFY_ONLY) /* Store the number in big-endian format in array at an offset. diff --git a/wolfssl/wolfcrypt/integer.h b/wolfssl/wolfcrypt/integer.h index 677d0206b7..a4e742d774 100644 --- a/wolfssl/wolfcrypt/integer.h +++ b/wolfssl/wolfcrypt/integer.h @@ -313,6 +313,7 @@ MP_API int mp_unsigned_bin_size(const mp_int * a); MP_API int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c); MP_API int mp_to_unsigned_bin_at_pos(int x, mp_int *t, unsigned char *b); MP_API int mp_to_unsigned_bin (mp_int * a, unsigned char *b); +#define mp_to_unsigned_bin_len_ct mp_to_unsigned_bin_len MP_API int mp_to_unsigned_bin_len(mp_int * a, unsigned char *b, int c); MP_API int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y); MP_API int mp_exptmod_ex (mp_int * G, mp_int * X, int digits, mp_int * P, diff --git a/wolfssl/wolfcrypt/sp_int.h b/wolfssl/wolfcrypt/sp_int.h index 34fb82cd7e..833a6cab6e 100644 --- a/wolfssl/wolfcrypt/sp_int.h +++ b/wolfssl/wolfcrypt/sp_int.h @@ -1045,6 +1045,7 @@ MP_API int sp_unsigned_bin_size(const sp_int* a); MP_API int sp_read_unsigned_bin(sp_int* a, const byte* in, word32 inSz); MP_API int sp_to_unsigned_bin(const sp_int* a, byte* out); MP_API int sp_to_unsigned_bin_len(const sp_int* a, byte* out, int outSz); +MP_API int sp_to_unsigned_bin_len_ct(const sp_int* a, byte* out, int outSz); #ifdef WOLFSSL_SP_MATH_ALL MP_API int sp_to_unsigned_bin_at_pos(int o, const sp_int* a, unsigned char* out); @@ -1158,6 +1159,7 @@ WOLFSSL_LOCAL void sp_memzero_check(sp_int* sp); #define mp_read_unsigned_bin sp_read_unsigned_bin #define mp_to_unsigned_bin sp_to_unsigned_bin #define mp_to_unsigned_bin_len sp_to_unsigned_bin_len +#define mp_to_unsigned_bin_len_ct sp_to_unsigned_bin_len_ct #define mp_to_unsigned_bin_at_pos sp_to_unsigned_bin_at_pos #define mp_read_radix sp_read_radix #define mp_tohex sp_tohex diff --git a/wolfssl/wolfcrypt/tfm.h b/wolfssl/wolfcrypt/tfm.h index 6f3c40945c..221b4ce223 100644 --- a/wolfssl/wolfcrypt/tfm.h +++ b/wolfssl/wolfcrypt/tfm.h @@ -842,6 +842,7 @@ MP_API int mp_unsigned_bin_size(const mp_int * a); MP_API int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c); MP_API int mp_to_unsigned_bin_at_pos(int x, mp_int *t, unsigned char *b); MP_API int mp_to_unsigned_bin (mp_int * a, unsigned char *b); +#define mp_to_unsigned_bin_len_ct mp_to_unsigned_bin_len MP_API int mp_to_unsigned_bin_len(mp_int * a, unsigned char *b, int c); MP_API int mp_sub_d(fp_int *a, fp_digit b, fp_int *c);