diff --git a/include/polarssl/bignum.h b/include/polarssl/bignum.h index 6e2afac72..f225fc394 100644 --- a/include/polarssl/bignum.h +++ b/include/polarssl/bignum.h @@ -246,7 +246,8 @@ void mpi_swap( mpi *X, mpi *Y ); * if( assign ) mpi_copy( X, Y ); * except that it avoids leaking any information about whether * the assignment was done or not (the above code may leak - * information through branch prediction analysis). + * information through branch prediction and/or memory access + * patterns analysis). */ int mpi_safe_cond_assign( mpi *X, mpi *Y, unsigned char assign ); diff --git a/include/polarssl/ecp.h b/include/polarssl/ecp.h index 81b789edb..33c09fcf2 100644 --- a/include/polarssl/ecp.h +++ b/include/polarssl/ecp.h @@ -463,15 +463,15 @@ int ecp_sub( const ecp_group *grp, ecp_point *R, * or P is not a valid pubkey, * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed * - * \note In order to prevent simple timing attacks, this function - * executes a constant number of operations (that is, point - * doubling and addition of distinct points) for random m in - * the allowed range. + * \note In order to prevent timing attacks, this function + * executes the exact same sequence of (base field) + * operations for any valid m. It avoids any if-branch or + * array index depending on the value of m. * * \note If f_rng is not NULL, it is used to randomize intermediate - * results in order to prevent potential attacks targetting - * these results. It is recommended to always provide a - * non-NULL f_rng (the overhead is negligible). + * results in order to prevent potential timing attacks + * targetting these results. It is recommended to always + * provide a non-NULL f_rng (the overhead is negligible). */ int ecp_mul( ecp_group *grp, ecp_point *R, const mpi *m, const ecp_point *P, diff --git a/library/ecp.c b/library/ecp.c index 9f1d3cef1..756beba15 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -1385,14 +1385,23 @@ cleanup: * Select precomputed point: R = sign(i) * T[ abs(i) / 2 ] */ static int ecp_select_comb( const ecp_group *grp, ecp_point *R, - const ecp_point T[], unsigned char i ) + ecp_point T[], unsigned char t_len, + unsigned char i ) { int ret; + unsigned char ii, j; - /* Ignore the "sign" bit */ - MPI_CHK( ecp_copy( R, &T[ ( i & 0x7Fu ) >> 1 ] ) ); + /* Ignore the "sign" bit and scale down */ + ii = ( i & 0x7Fu ) >> 1; - /* Restore the Z coordinate */ + /* Read the whole table to thwart cache-based timing attacks */ + for( j = 0; j < t_len; j++ ) + { + MPI_CHK( mpi_safe_cond_assign( &R->X, &T[j].X, j == ii ) ); + MPI_CHK( mpi_safe_cond_assign( &R->Y, &T[j].Y, j == ii ) ); + } + + /* The Z coordinate is always 1 */ MPI_CHK( mpi_lset( &R->Z, 1 ) ); /* Safely invert result if i is "negative" */ @@ -1409,7 +1418,7 @@ cleanup: * Cost: d A + d D + 1 R */ static int ecp_mul_comb_core( const ecp_group *grp, ecp_point *R, - const ecp_point T[], + ecp_point T[], unsigned char t_len, const unsigned char x[], size_t d, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) @@ -1422,14 +1431,14 @@ static int ecp_mul_comb_core( const ecp_group *grp, ecp_point *R, /* Start with a non-zero point and randomize its coordinates */ i = d; - MPI_CHK( ecp_select_comb( grp, R, T, x[i] ) ); + MPI_CHK( ecp_select_comb( grp, R, T, t_len, x[i] ) ); if( f_rng != 0 ) MPI_CHK( ecp_randomize_coordinates( grp, R, f_rng, p_rng ) ); while( i-- != 0 ) { MPI_CHK( ecp_double_jac( grp, R, R ) ); - MPI_CHK( ecp_select_comb( grp, &Txi, T, x[i] ) ); + MPI_CHK( ecp_select_comb( grp, &Txi, T, t_len, x[i] ) ); MPI_CHK( ecp_add_mixed( grp, R, R, &Txi ) ); } @@ -1447,8 +1456,8 @@ int ecp_mul( ecp_group *grp, ecp_point *R, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret; - unsigned char w, m_is_odd, p_eq_g; - size_t pre_len, d, i; + unsigned char w, m_is_odd, p_eq_g, pre_len, i; + size_t d; unsigned char k[COMB_MAX_D + 1]; ecp_point *T; mpi M, mm; @@ -1542,7 +1551,7 @@ int ecp_mul( ecp_group *grp, ecp_point *R, * Go for comb multiplication, R = M * P */ ecp_comb_fixed( k, d, w, &M ); - ecp_mul_comb_core( grp, R, T, k, d, f_rng, p_rng ); + MPI_CHK( ecp_mul_comb_core( grp, R, T, pre_len, k, d, f_rng, p_rng ) ); /* * Now get m * P from M * P and normalize it