From 23bdeca64d85ccb0c2d602643d814a291b262916 Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Fri, 22 Jul 2022 18:24:06 +0100 Subject: [PATCH] Add core constant time comparison Unfortunately reusing the new function from the signed constant time comparison is not trivial. One option would be to do temporary conditional swaps which would prevent qualifying input to const. Another way would be to add an additional flag for the sign and make it an integral part of the computation, which would defeat the purpose of having an unsigned core comparison. Going with two separate function for now and the signed version can be retired/compiled out with the legacy API eventually. The new function in theory could be placed into either `library/constant_time.c` or `library/bignum_new.c`. Going with the first as the other functions in the second are not constant time yet and this distinction seems more valuable for new (as opposed to belonging to the `_core` functions. Signed-off-by: Janos Follath --- library/constant_time.c | 44 +++++++++++++++++++++ library/constant_time_internal.h | 16 ++++++++ tests/suites/test_suite_mpi.data | 57 ++++++++++++++++++++++++++++ tests/suites/test_suite_mpi.function | 38 +++++++++++++++++++ 4 files changed, 155 insertions(+) diff --git a/library/constant_time.c b/library/constant_time.c index 47e9b02d6b..cd3ec10647 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -741,6 +741,50 @@ cleanup: return( ret ); } +/* + * Compare unsigned values in constant time + */ +unsigned mbedtls_mpi_core_lt_ct( const mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *Y, + size_t len ) +{ + size_t i; + /* The value of any of these variables is either 0 or 1 at all times. */ + unsigned ret, cond, done; + + ret = cond = done = 0; + + for( i = len; i > 0; i-- ) + { + /* + * If Y[i - 1] < X[i - 1] then X < Y is false and the result must + * remain 0. + * + * Again even if we can make a decision, we just mark the result and + * the fact that we are done and continue looping. + */ + cond = mbedtls_ct_mpi_uint_lt( Y[i - 1], X[i - 1] ); + done |= cond; + + /* + * If X[i - 1] < Y[i - 1] then X < Y is true. + * + * Again even if we can make a decision, we just mark the result and + * the fact that we are done and continue looping. + */ + cond = mbedtls_ct_mpi_uint_lt( X[i - 1], Y[i - 1] ); + ret |= cond & ( 1 - done ); + done |= cond; + } + + /* + * If all the limbs were equal, then the numbers are equal, X < Y is false + * and leaving the result 0 is correct. + */ + + return( ret ); +} + /* * Compare signed values in constant time */ diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index 9466bc3789..7255b2a857 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -129,6 +129,22 @@ unsigned mbedtls_ct_size_bool_eq( size_t x, unsigned mbedtls_ct_mpi_uint_lt( const mbedtls_mpi_uint x, const mbedtls_mpi_uint y ); +/** + * \brief Check if an MPI is less than the other in constant time. + * + * \param X The left-hand MPI. This must point to an array of limbs + * with the same allocated length as Y. + * \param Y The right-hand MPI. This must point to an array of limbs + * with the same allocated length as X. + * \param len The number of limbs in X and Y. + * + * \return The result of the comparison: + * \c 1 if \p X is less than \p Y. + * \c 0 if \p X is greater than or equal to \p Y. + */ +unsigned mbedtls_mpi_core_lt_ct( const mbedtls_mpi_uint *X, + const mbedtls_mpi_uint *Y, + size_t len ); #endif /* MBEDTLS_BIGNUM_C */ /** Choose between two integer values without branches. diff --git a/tests/suites/test_suite_mpi.data b/tests/suites/test_suite_mpi.data index 1974e3fc38..e52953c7ff 100644 --- a/tests/suites/test_suite_mpi.data +++ b/tests/suites/test_suite_mpi.data @@ -409,6 +409,63 @@ mbedtls_mpi_cmp_mpi:"-1230000000000000000":"":-1 Test mbedtls_mpi_cmp_mpi: large negative < 0 (1 limb) mbedtls_mpi_cmp_mpi:"-1230000000000000000":"0":-1 +Base test mbedtls_mpi_core_lt_ct #1 +mbedtls_mpi_core_lt_ct:"02B5":"02B5":0 + +Base test mbedtls_mpi_core_lt_ct #2 +mbedtls_mpi_core_lt_ct:"02B5":"02B4":0 + +Base test mbedtls_mpi_core_lt_ct #3 +mbedtls_mpi_core_lt_ct:"02B5":"02B6":1 + +Base test mbedtls_mpi_core_lt_ct (length=0) +mbedtls_mpi_core_lt_ct:"":"":0 + +Base test mbedtls_mpi_core_lt_ct (corner case - 64 bit) #1 +mbedtls_mpi_core_lt_ct:"7FFFFFFFFFFFFFFF":"FF":0 + +Base test mbedtls_mpi_core_lt_ct (corner case - 64 bit) #2 +mbedtls_mpi_core_lt_ct:"8000000000000000":"7FFFFFFFFFFFFFFF":0 + +Base test mbedtls_mpi_core_lt_ct (corner case - 64 bit) #3 +mbedtls_mpi_core_lt_ct:"8000000000000000":"01":0 + +Base test mbedtls_mpi_core_lt_ct (corner case - 64 bit) #4 +mbedtls_mpi_core_lt_ct:"8000000000000000":"00":0 + +Base test mbedtls_mpi_core_lt_ct (corner case - 64 bit) #5 +mbedtls_mpi_core_lt_ct:"FFFFFFFFFFFFFFFF":"FF":0 + +Base test mbedtls_mpi_core_lt_ct (corner case - 32 bit) #1 +mbedtls_mpi_core_lt_ct:"7FFFFFFF":"FF":0 + +Base test mbedtls_mpi_core_lt_ct (corner case - 32 bit) #2 +mbedtls_mpi_core_lt_ct:"80000000":"7FFFFFFF":0 + +Base test mbedtls_mpi_core_lt_ct (corner case - 32 bit) #3 +mbedtls_mpi_core_lt_ct:"80000000":"01":0 + +Base test mbedtls_mpi_core_lt_ct (corner case - 32 bit) #4 +mbedtls_mpi_core_lt_ct:"80000000":"00":0 + +Base test mbedtls_mpi_core_lt_ct (corner case - 32 bit) #5 +mbedtls_mpi_core_lt_ct:"FFFFFFFF":"FF":0 + +Multi-limb mbedtls_mpi_core_lt_ct (XY, equal MS limbs) +mbedtls_mpi_core_lt_ct:"EEFFFFFFFFFFFFFFFF":"EEFFFFFFFFFFFFFFF1":0 + +Multi-limb mbedtls_mpi_core_lt_ct (X=Y) +mbedtls_mpi_core_lt_ct:"EEFFFFFFFFFFFFFFFF":"EEFFFFFFFFFFFFFFFF":0 + +Multi-limb mbedtls_mpi_core_lt_ct (Alternating limbs) #1 +mbedtls_mpi_core_lt_ct:"11FFFFFFFFFFFFFFFF":"FF1111111111111111":1 + +Multi-limb mbedtls_mpi_core_lt_ct (Alternating limbs) #2 +mbedtls_mpi_core_lt_ct:"FF1111111111111111":"11FFFFFFFFFFFFFFFF":0 + Base test mbedtls_mpi_lt_mpi_ct #1 mbedtls_mpi_lt_mpi_ct:1:"2B5":1:"2B5":0:0 diff --git a/tests/suites/test_suite_mpi.function b/tests/suites/test_suite_mpi.function index b0d947c9db..ff87ea44ac 100644 --- a/tests/suites/test_suite_mpi.function +++ b/tests/suites/test_suite_mpi.function @@ -2,6 +2,8 @@ #include "mbedtls/bignum.h" #include "mbedtls/entropy.h" #include "bignum_core.h" +#include "constant_time_internal.h" +#include "test/constant_flow.h" #if MBEDTLS_MPI_MAX_BITS > 792 #define MPI_MAX_BITS_LARGER_THAN_792 @@ -607,6 +609,42 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void mbedtls_mpi_core_lt_ct( data_t * input_X, data_t * input_Y, int input_ret ) +{ + #define MAX_LEN 64 + mbedtls_mpi_uint X[MAX_LEN]; + mbedtls_mpi_uint Y[MAX_LEN]; + unsigned exp_ret = input_ret; + unsigned ret; + size_t len = CHARS_TO_LIMBS( + input_X->len > input_Y->len ? input_X->len : input_Y->len ); + + TEST_ASSERT( len <= MAX_LEN ); + + TEST_ASSERT( mbedtls_mpi_core_read_be( X, len, input_X->x, input_X->len ) + == 0 ); + TEST_ASSERT( mbedtls_mpi_core_read_be( Y, len, input_Y->x, input_Y->len ) + == 0 ); + + TEST_CF_SECRET( X, len * sizeof( mbedtls_mpi_uint ) ); + TEST_CF_SECRET( Y, len * sizeof( mbedtls_mpi_uint ) ); + + ret = mbedtls_mpi_core_lt_ct( X, Y, len ); + + TEST_CF_PUBLIC( X, len * sizeof( mbedtls_mpi_uint ) ); + TEST_CF_PUBLIC( Y, len * sizeof( mbedtls_mpi_uint ) ); + TEST_CF_PUBLIC( &ret, sizeof( ret ) ); + + TEST_ASSERT( ret == exp_ret ); + +exit: + ; + + #undef MAX_LEN +} +/* END_CASE */ + /* BEGIN_CASE */ void mbedtls_mpi_lt_mpi_ct( int size_X, char * input_X, int size_Y, char * input_Y,