From e09d2f8261723acfecaf22d6fcde723913ee8ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Mon, 2 Sep 2013 14:29:09 +0200 Subject: [PATCH 01/13] Change ecp_mul() prototype to allow randomization (Also improve an error code while at it.) --- include/polarssl/ecdh.h | 16 ++++++++++++-- include/polarssl/ecp.h | 22 +++++++++++++++----- library/ecdh.c | 16 +++++++++----- library/ecdsa.c | 7 +++++-- library/ecp.c | 20 +++++++++++------- library/ssl_cli.c | 3 ++- library/ssl_srv.c | 3 ++- tests/suites/test_suite_ecdh.function | 15 ++++++++------ tests/suites/test_suite_ecp.data | 4 ++-- tests/suites/test_suite_ecp.function | 30 ++++++++++++++++++++++----- 10 files changed, 99 insertions(+), 37 deletions(-) diff --git a/include/polarssl/ecdh.h b/include/polarssl/ecdh.h index 2184ab95f..d91aea58d 100644 --- a/include/polarssl/ecdh.h +++ b/include/polarssl/ecdh.h @@ -70,12 +70,20 @@ int ecdh_gen_public( const ecp_group *grp, mpi *d, ecp_point *Q, * \param z Destination MPI (shared secret) * \param Q Public key from other party * \param d Our secret exponent + * \param f_rng RNG function (see notes) + * \param p_rng RNG parameter * * \return 0 if successful, * or a POLARSSL_ERR_ECP_XXX or POLARSSL_MPI_XXX error code + * + * \note If f_rng is not NULL, it is used to implement + * countermeasures against potential elaborate timing + * attacks, see \c ecp_mul() for details. */ int ecdh_compute_shared( const ecp_group *grp, mpi *z, - const ecp_point *Q, const mpi *d ); + const ecp_point *Q, const mpi *d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); /** * \brief Initialize context @@ -156,11 +164,15 @@ int ecdh_read_public( ecdh_context *ctx, * \param olen number of bytes written * \param buf destination buffer * \param blen buffer length + * \param f_rng RNG function, see notes for \c ecdh_compute_shared() + * \param p_rng RNG parameter * * \return 0 if successful, or an POLARSSL_ERR_ECP_XXX error code */ int ecdh_calc_secret( ecdh_context *ctx, size_t *olen, - unsigned char *buf, size_t blen ); + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); /** * \brief Checkup routine diff --git a/include/polarssl/ecp.h b/include/polarssl/ecp.h index ad31bff66..594223133 100644 --- a/include/polarssl/ecp.h +++ b/include/polarssl/ecp.h @@ -411,17 +411,29 @@ int ecp_sub( const ecp_group *grp, ecp_point *R, * \param R Destination point * \param m Integer by which to multiply * \param P Point to multiply + * \param f_rng RNG function (see notes) + * \param p_rng RNG parameter * * \return 0 if successful, * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed - * POLARSSL_ERR_ECP_GENERIC if m < 0 of m has greater bit - * length than N, the number of points in the group. + * POLARSSL_ERR_ECP_BAD_INPUT_DATA if m < 0 of m has greater + * bit length than N, the number of points in the group. * - * \note This function executes a constant number of operations - * for random m in the allowed range. + * \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 If f_rng is not NULL, it is used to randomize projective + * coordinates of indermediate results, in order to prevent + * more elaborate timing attacks relying on intermediate + * operations. (This is a prophylactic measure since so such + * attack has been published yet.) */ int ecp_mul( const ecp_group *grp, ecp_point *R, - const mpi *m, const ecp_point *P ); + const mpi *m, const ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + /** * \brief Check that a point is a valid public key on this curve diff --git a/library/ecdh.c b/library/ecdh.c index d76596eb2..8ef02f54b 100644 --- a/library/ecdh.c +++ b/library/ecdh.c @@ -50,7 +50,9 @@ int ecdh_gen_public( const ecp_group *grp, mpi *d, ecp_point *Q, * Compute shared secret (SEC1 3.3.1) */ int ecdh_compute_shared( const ecp_group *grp, mpi *z, - const ecp_point *Q, const mpi *d ) + const ecp_point *Q, const mpi *d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) { int ret; ecp_point P; @@ -62,7 +64,7 @@ int ecdh_compute_shared( const ecp_group *grp, mpi *z, */ MPI_CHK( ecp_check_pubkey( grp, Q ) ); - MPI_CHK( ecp_mul( grp, &P, d, Q ) ); + MPI_CHK( ecp_mul( grp, &P, d, Q, f_rng, p_rng ) ); if( ecp_is_zero( &P ) ) { @@ -202,16 +204,20 @@ int ecdh_read_public( ecdh_context *ctx, * Derive and export the shared secret */ int ecdh_calc_secret( ecdh_context *ctx, size_t *olen, - unsigned char *buf, size_t blen ) + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) { int ret; if( ctx == NULL ) return( POLARSSL_ERR_ECP_BAD_INPUT_DATA ); - if( ( ret = ecdh_compute_shared( &ctx->grp, &ctx->z, &ctx->Qp, &ctx->d ) ) - != 0 ) + if( ( ret = ecdh_compute_shared( &ctx->grp, &ctx->z, &ctx->Qp, &ctx->d, + f_rng, p_rng ) ) != 0 ) + { return( ret ); + } if( mpi_size( &ctx->z ) > blen ) return( POLARSSL_ERR_ECP_BAD_INPUT_DATA ); diff --git a/library/ecdsa.c b/library/ecdsa.c index 67774c9d0..bbdb5d57b 100644 --- a/library/ecdsa.c +++ b/library/ecdsa.c @@ -161,9 +161,12 @@ int ecdsa_verify( const ecp_group *grp, /* * Step 5: R = u1 G + u2 Q + * + * Since we're not using any secret data, no need to pass a RNG to + * ecp_mul() for countermesures. */ - MPI_CHK( ecp_mul( grp, &R, &u1, &grp->G ) ); - MPI_CHK( ecp_mul( grp, &P, &u2, Q ) ); + MPI_CHK( ecp_mul( grp, &R, &u1, &grp->G, NULL, NULL ) ); + MPI_CHK( ecp_mul( grp, &P, &u2, Q, NULL, NULL ) ); MPI_CHK( ecp_add( grp, &R, &R, &P ) ); if( ecp_is_zero( &R ) ) diff --git a/library/ecp.c b/library/ecp.c index 09a021bf8..b4ee042d2 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -1166,7 +1166,8 @@ cleanup: * random m in the range 0 .. 2^nbits - 1. */ int ecp_mul( const ecp_group *grp, ecp_point *R, - const mpi *m, const ecp_point *P ) + const mpi *m, const ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret; unsigned char w, m_is_odd; @@ -1175,18 +1176,21 @@ int ecp_mul( const ecp_group *grp, ecp_point *R, ecp_point Q, T[ MAX_PRE_LEN ]; mpi M; + ((void) f_rng); + ((void) p_rng); + if( mpi_cmp_int( m, 0 ) < 0 || mpi_msb( m ) > grp->nbits ) - return( POLARSSL_ERR_ECP_GENERIC ); + return( POLARSSL_ERR_ECP_BAD_INPUT_DATA ); w = grp->nbits >= 521 ? 6 : grp->nbits >= 224 ? 5 : - 4; + 4; /* * Make sure w is within the limits. * The last test ensures that none of the precomputed points is zero, * which wouldn't be handled correctly by ecp_normalize_many(). - * It is only useful for small curves, as used in the test suite. + * It is only useful for very small curves, as used in the test suite. */ if( w > POLARSSL_ECP_WINDOW_SIZE ) w = POLARSSL_ECP_WINDOW_SIZE; @@ -1348,7 +1352,7 @@ int ecp_gen_keypair( const ecp_group *grp, mpi *d, ecp_point *Q, } while( mpi_cmp_int( d, 1 ) < 0 ); - return( ecp_mul( grp, Q, d, &grp->G ) ); + return( ecp_mul( grp, Q, d, &grp->G, f_rng, p_rng ) ); } #if defined(POLARSSL_SELF_TEST) @@ -1402,12 +1406,12 @@ int ecp_self_test( int verbose ) #endif /* POLARSSL_ECP_DP_SECP192R1_ENABLED */ if( verbose != 0 ) - printf( " ECP test #1 (SPA resistance): " ); + printf( " ECP test #1 (resistance to simple timing attacks): " ); add_count = 0; dbl_count = 0; MPI_CHK( mpi_read_string( &m, 16, exponents[0] ) ); - MPI_CHK( ecp_mul( &grp, &R, &m, &grp.G ) ); + MPI_CHK( ecp_mul( &grp, &R, &m, &grp.G, NULL, NULL ) ); for( i = 1; i < sizeof( exponents ) / sizeof( exponents[0] ); i++ ) { @@ -1417,7 +1421,7 @@ int ecp_self_test( int verbose ) dbl_count = 0; MPI_CHK( mpi_read_string( &m, 16, exponents[i] ) ); - MPI_CHK( ecp_mul( &grp, &R, &m, &grp.G ) ); + MPI_CHK( ecp_mul( &grp, &R, &m, &grp.G, NULL, NULL ) ); if( add_count != add_c_prev || dbl_count != dbl_c_prev ) { diff --git a/library/ssl_cli.c b/library/ssl_cli.c index 0fccf3443..3b9d14246 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -1748,7 +1748,8 @@ static int ssl_write_client_key_exchange( ssl_context *ssl ) if( ( ret = ecdh_calc_secret( &ssl->handshake->ecdh_ctx, &ssl->handshake->pmslen, ssl->handshake->premaster, - POLARSSL_MPI_MAX_SIZE ) ) != 0 ) + POLARSSL_MPI_MAX_SIZE, + ssl->f_rng, ssl->p_rng ) ) != 0 ) { SSL_DEBUG_RET( 1, "ecdh_calc_secret", ret ); return( ret ); diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 5bedcadce..adf5a623f 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2410,7 +2410,8 @@ static int ssl_parse_client_key_exchange( ssl_context *ssl ) if( ( ret = ecdh_calc_secret( &ssl->handshake->ecdh_ctx, &ssl->handshake->pmslen, ssl->handshake->premaster, - POLARSSL_MPI_MAX_SIZE ) ) != 0 ) + POLARSSL_MPI_MAX_SIZE, + ssl->f_rng, ssl->p_rng ) ) != 0 ) { SSL_DEBUG_RET( 1, "ecdh_calc_secret", ret ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS ); diff --git a/tests/suites/test_suite_ecdh.function b/tests/suites/test_suite_ecdh.function index 5bfd63db7..ba35c76a7 100644 --- a/tests/suites/test_suite_ecdh.function +++ b/tests/suites/test_suite_ecdh.function @@ -27,8 +27,10 @@ void ecdh_primitive_random( int id ) == 0 ); TEST_ASSERT( ecdh_gen_public( &grp, &dB, &qB, &rnd_pseudo_rand, &rnd_info ) == 0 ); - TEST_ASSERT( ecdh_compute_shared( &grp, &zA, &qB, &dA ) == 0 ); - TEST_ASSERT( ecdh_compute_shared( &grp, &zB, &qA, &dB ) == 0 ); + TEST_ASSERT( ecdh_compute_shared( &grp, &zA, &qB, &dA, + &rnd_pseudo_rand, &rnd_info ) == 0 ); + TEST_ASSERT( ecdh_compute_shared( &grp, &zB, &qA, &dB, + NULL, NULL ) == 0 ); TEST_ASSERT( mpi_cmp_mpi( &zA, &zB ) == 0 ); @@ -70,9 +72,9 @@ void ecdh_primitive_testvec( int id, char *dA_str, char *xA_str, char *yA_str, TEST_ASSERT( mpi_cmp_mpi( &qB.Y, &check ) == 0 ); TEST_ASSERT( mpi_read_string( &check, 16, z_str ) == 0 ); - TEST_ASSERT( ecdh_compute_shared( &grp, &zA, &qB, &dA ) == 0 ); + TEST_ASSERT( ecdh_compute_shared( &grp, &zA, &qB, &dA, NULL, NULL ) == 0 ); TEST_ASSERT( mpi_cmp_mpi( &zA, &check ) == 0 ); - TEST_ASSERT( ecdh_compute_shared( &grp, &zB, &qA, &dB ) == 0 ); + TEST_ASSERT( ecdh_compute_shared( &grp, &zB, &qA, &dB, NULL, NULL ) == 0 ); TEST_ASSERT( mpi_cmp_mpi( &zB, &check ) == 0 ); ecp_group_free( &grp ); @@ -107,8 +109,9 @@ void ecdh_exchange( int id ) &rnd_pseudo_rand, &rnd_info ) == 0 ); TEST_ASSERT( ecdh_read_public( &srv, buf, len ) == 0 ); - TEST_ASSERT( ecdh_calc_secret( &srv, &len, buf, 1000 ) == 0 ); - TEST_ASSERT( ecdh_calc_secret( &cli, &len, buf, 1000 ) == 0 ); + TEST_ASSERT( ecdh_calc_secret( &srv, &len, buf, 1000, + &rnd_pseudo_rand, &rnd_info ) == 0 ); + TEST_ASSERT( ecdh_calc_secret( &cli, &len, buf, 1000, NULL, NULL ) == 0 ); TEST_ASSERT( mpi_cmp_mpi( &srv.z, &cli.z ) == 0 ); ecdh_free( &srv ); diff --git a/tests/suites/test_suite_ecp.data b/tests/suites/test_suite_ecp.data index ce9263364..55a34539f 100644 --- a/tests/suites/test_suite_ecp.data +++ b/tests/suites/test_suite_ecp.data @@ -50,7 +50,7 @@ ECP small subtraction #9 ecp_small_sub:0:"14":"11":0:"14":"36":0:27:30 ECP small multiplication negative -ecp_small_mul:-1:0:0:0:POLARSSL_ERR_ECP_GENERIC +ecp_small_mul:-1:0:0:0:POLARSSL_ERR_ECP_BAD_INPUT_DATA ECP small multiplication #0 ecp_small_mul:0:1:0:0:0 @@ -101,7 +101,7 @@ ECP small multiplication #15 ecp_small_mul:2:0:20:01:0 ECP small multiplication too big -ecp_small_mul:-1:0:0:0:POLARSSL_ERR_ECP_GENERIC +ecp_small_mul:-1:0:0:0:POLARSSL_ERR_ECP_BAD_INPUT_DATA ECP small check pubkey #1 ecp_small_check_pub:1:1:0:POLARSSL_ERR_ECP_GENERIC diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function index 62c5de2d4..5b1ab601d 100644 --- a/tests/suites/test_suite_ecp.function +++ b/tests/suites/test_suite_ecp.function @@ -101,17 +101,33 @@ void ecp_small_mul( int m_str, int r_zero, int x_r, int y_r, int ret ) ecp_group grp; ecp_point R; mpi m; + rnd_pseudo_info rnd_info; ecp_group_init( &grp ); ecp_point_init( &R ); mpi_init( &m ); + memset( &rnd_info, 0x00, sizeof( rnd_pseudo_info ) ); TEST_ASSERT( ecp_group_read_string( &grp, 10, "47", "4", "17", "42", "13" ) == 0 ); TEST_ASSERT( mpi_lset( &m, m_str ) == 0 ); - TEST_ASSERT( ecp_mul( &grp, &R, &m, &grp.G ) == ret ); + TEST_ASSERT( ecp_mul( &grp, &R, &m, &grp.G, NULL, NULL ) == ret ); + + if( r_zero ) + TEST_ASSERT( mpi_cmp_int( &R.Z, 0 ) == 0 ); + else + { + TEST_ASSERT( mpi_cmp_int( &R.X, x_r ) == 0 ); + TEST_ASSERT( mpi_cmp_int( &R.Y, y_r ) == 0 ); + } + + /* try again with randomization */ + ecp_point_free( &R ); + + TEST_ASSERT( ecp_mul( &grp, &R, &m, &grp.G, + &rnd_pseudo_rand, &rnd_info ) == ret ); if( r_zero ) TEST_ASSERT( mpi_cmp_int( &R.Z, 0 ) == 0 ); @@ -158,10 +174,12 @@ void ecp_test_vect( int id, char *dA_str, char *xA_str, char *yA_str, ecp_group grp; ecp_point R; mpi dA, xA, yA, dB, xB, yB, xZ, yZ; + rnd_pseudo_info rnd_info; ecp_group_init( &grp ); ecp_point_init( &R ); mpi_init( &dA ); mpi_init( &xA ); mpi_init( &yA ); mpi_init( &dB ); mpi_init( &xB ); mpi_init( &yB ); mpi_init( &xZ ); mpi_init( &yZ ); + memset( &rnd_info, 0x00, sizeof( rnd_pseudo_info ) ); TEST_ASSERT( ecp_use_known_dp( &grp, id ) == 0 ); @@ -176,20 +194,22 @@ void ecp_test_vect( int id, char *dA_str, char *xA_str, char *yA_str, TEST_ASSERT( mpi_read_string( &xZ, 16, xZ_str ) == 0 ); TEST_ASSERT( mpi_read_string( &yZ, 16, yZ_str ) == 0 ); - TEST_ASSERT( ecp_mul( &grp, &R, &dA, &grp.G ) == 0 ); + TEST_ASSERT( ecp_mul( &grp, &R, &dA, &grp.G, + &rnd_pseudo_rand, &rnd_info ) == 0 ); TEST_ASSERT( mpi_cmp_mpi( &R.X, &xA ) == 0 ); TEST_ASSERT( mpi_cmp_mpi( &R.Y, &yA ) == 0 ); TEST_ASSERT( ecp_check_pubkey( &grp, &R ) == 0 ); - TEST_ASSERT( ecp_mul( &grp, &R, &dB, &R ) == 0 ); + TEST_ASSERT( ecp_mul( &grp, &R, &dB, &R, NULL, NULL ) == 0 ); TEST_ASSERT( mpi_cmp_mpi( &R.X, &xZ ) == 0 ); TEST_ASSERT( mpi_cmp_mpi( &R.Y, &yZ ) == 0 ); TEST_ASSERT( ecp_check_pubkey( &grp, &R ) == 0 ); - TEST_ASSERT( ecp_mul( &grp, &R, &dB, &grp.G ) == 0 ); + TEST_ASSERT( ecp_mul( &grp, &R, &dB, &grp.G, NULL, NULL ) == 0 ); TEST_ASSERT( mpi_cmp_mpi( &R.X, &xB ) == 0 ); TEST_ASSERT( mpi_cmp_mpi( &R.Y, &yB ) == 0 ); TEST_ASSERT( ecp_check_pubkey( &grp, &R ) == 0 ); - TEST_ASSERT( ecp_mul( &grp, &R, &dA, &R ) == 0 ); + TEST_ASSERT( ecp_mul( &grp, &R, &dA, &R, + &rnd_pseudo_rand, &rnd_info ) == 0 ); TEST_ASSERT( mpi_cmp_mpi( &R.X, &xZ ) == 0 ); TEST_ASSERT( mpi_cmp_mpi( &R.Y, &yZ ) == 0 ); TEST_ASSERT( ecp_check_pubkey( &grp, &R ) == 0 ); From c75c56fef73745975a8a82271d6f2e8bde526ca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Mon, 2 Sep 2013 16:25:37 +0200 Subject: [PATCH 02/13] Fix off-by-one error in ecdsa_write_signature() Made some signature fail with 521-bit curve --- library/ecdsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/ecdsa.c b/library/ecdsa.c index bbdb5d57b..dc169cefc 100644 --- a/library/ecdsa.c +++ b/library/ecdsa.c @@ -220,8 +220,8 @@ int ecdsa_write_signature( ecdsa_context *ctx, void *p_rng ) { int ret; - unsigned char buf[MAX_SIG_LEN]; - unsigned char *p = buf + MAX_SIG_LEN - 1; + unsigned char buf[MAX_SIG_LEN + 3]; + unsigned char *p = buf + MAX_SIG_LEN; size_t len = 0; if( ( ret = ecdsa_sign( &ctx->grp, &ctx->r, &ctx->s, &ctx->d, From 07de4b1d084ab68587066b68d29befb91ccc88c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Mon, 2 Sep 2013 16:26:04 +0200 Subject: [PATCH 03/13] Implement randomized coordinates in ecp_mul() --- library/ecp.c | 84 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 12 deletions(-) diff --git a/library/ecp.c b/library/ecp.c index b4ee042d2..a80ddac63 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -30,6 +30,17 @@ * GECC = Guide to Elliptic Curve Cryptography - Hankerson, Menezes, Vanstone * FIPS 186-3 http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf * RFC 4492 for the related TLS structures and constants + * + * [1] OKEYA, Katsuyuki and TAKAGI, Tsuyoshi. The width-w NAF method provides + * small memory and fast elliptic scalar multiplications secure against + * side channel attacks. In : Topics in Cryptology—CT-RSA 2003. Springer + * Berlin Heidelberg, 2003. p. 328-343. + * . + * + * [2] CORON, Jean-Sébastien. Resistance against differential power analysis + * for elliptic curve cryptosystems. In : Cryptographic Hardware and + * Embedded Systems. Springer Berlin Heidelberg, 1999. p. 292-302. + * */ #include "polarssl/config.h" @@ -51,7 +62,7 @@ #if defined(POLARSSL_SELF_TEST) /* * Counts of point addition and doubling operations. - * Used to test resistance of point multiplication to SPA/timing attacks. + * Used to test resistance of point multiplication to simple timing attacks. */ unsigned long add_count, dbl_count; #endif @@ -777,7 +788,7 @@ cleanup: * (See for example Cohen's "A Course in Computational Algebraic Number * Theory", Algorithm 10.3.4.) * - * Warning: fails if one of the points is zero! + * Warning: fails (returning an error) if one of the points is zero! * This should never happen, see choice of w in ecp_mul(). */ static int ecp_normalize_many( const ecp_group *grp, @@ -1049,11 +1060,10 @@ cleanup: /* * Compute a modified width-w non-adjacent form (NAF) of a number, - * with a fixed pattern for resistance to SPA/timing attacks, - * see . - * (The resulting multiplication algorithm can also been seen as a - * modification of 2^w-ary multiplication, with signed coefficients, - * all of them odd.) + * with a fixed pattern for resistance to simple timing attacks (even SPA), + * see [1]. (The resulting multiplication algorithm can also been seen as a + * modification of 2^w-ary multiplication, with signed coefficients, all of + * them odd.) * * Input: * m must be an odd positive mpi less than w * k bits long @@ -1144,6 +1154,51 @@ cleanup: return( ret ); } +/* + * Randomize jacobian coordinates: + * (X, Y, Z) -> (l^2 X, l^3 Y, l Z) for random l + * This is sort of the reverse operation of ecp_normalize(). + */ +static int ecp_randomize_coordinates( const ecp_group *grp, ecp_point *pt, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + mpi l, ll; + size_t p_size = (grp->pbits + 7) / 8; + int count = 0; + + mpi_init( &l ); mpi_init( &ll ); + + /* Generate l such that 1 < l < p */ + do + { + mpi_fill_random( &l, p_size, f_rng, p_rng ); + + while( mpi_cmp_mpi( &l, &grp->P ) >= 0 ) + mpi_shift_r( &l, 1 ); + + if( count++ > 10 ) + return( POLARSSL_ERR_ECP_GENERIC ); + } + while( mpi_cmp_int( &l, 1 ) <= 0 ); + + /* Z = l * Z */ + MPI_CHK( mpi_mul_mpi( &pt->Z, &pt->Z, &l ) ); MOD_MUL( pt->Z ); + + /* X = l^2 * X */ + MPI_CHK( mpi_mul_mpi( &ll, &l, &l ) ); MOD_MUL( ll ); + MPI_CHK( mpi_mul_mpi( &pt->X, &pt->X, &ll ) ); MOD_MUL( pt->X ); + + /* Y = l^3 * Y */ + MPI_CHK( mpi_mul_mpi( &ll, &ll, &l ) ); MOD_MUL( ll ); + MPI_CHK( mpi_mul_mpi( &pt->Y, &pt->Y, &ll ) ); MOD_MUL( pt->Y ); + +cleanup: + mpi_free( &l ); mpi_free( &ll ); + + return( ret ); +} + /* * Maximum length of the precomputed table */ @@ -1159,11 +1214,15 @@ cleanup: /* * Integer multiplication: R = m * P * - * Based on fixed-pattern width-w NAF, see comments of ecp_w_naf_fixed() - * and . + * Based on fixed-pattern width-w NAF, see comments of ecp_w_naf_fixed(). * * This function executes a fixed number of operations for * random m in the range 0 .. 2^nbits - 1. + * + * As an additional countermeasure against potential elaborate timing attacks, + * we randomize coordinates after each addition. This was suggested as a + * countermeasure against DPA in 5.3 of [2] (with the obvious adaptation that + * we use jacobian coordinates, not standard projective coordinates). */ int ecp_mul( const ecp_group *grp, ecp_point *R, const mpi *m, const ecp_point *P, @@ -1176,9 +1235,6 @@ int ecp_mul( const ecp_group *grp, ecp_point *R, ecp_point Q, T[ MAX_PRE_LEN ]; mpi M; - ((void) f_rng); - ((void) p_rng); - if( mpi_cmp_int( m, 0 ) < 0 || mpi_msb( m ) > grp->nbits ) return( POLARSSL_ERR_ECP_BAD_INPUT_DATA ); @@ -1241,6 +1297,10 @@ int ecp_mul( const ecp_group *grp, ecp_point *R, MPI_CHK( ecp_add_mixed( grp, &Q, &Q, &T[ naf[i] ], +1 ) ); } + /* Countermeasure (see comments above) */ + if( f_rng != NULL ) + ecp_randomize_coordinates( grp, &Q, f_rng, p_rng ); + if( i == 0 ) break; i--; From 2d627649bfaef83cbba70752b3e169012620724c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 4 Sep 2013 14:22:07 +0200 Subject: [PATCH 04/13] Change dhm_calc_secret() prototype --- include/polarssl/dhm.h | 6 +++++- library/dhm.c | 7 ++++++- library/ssl_cli.c | 5 +++-- library/ssl_srv.c | 5 +++-- programs/pkey/dh_client.c | 2 +- programs/pkey/dh_server.c | 2 +- tests/suites/test_suite_dhm.function | 4 ++-- 7 files changed, 21 insertions(+), 10 deletions(-) diff --git a/include/polarssl/dhm.h b/include/polarssl/dhm.h index da787c346..4d7bd8a7a 100644 --- a/include/polarssl/dhm.h +++ b/include/polarssl/dhm.h @@ -219,11 +219,15 @@ int dhm_make_public( dhm_context *ctx, int x_size, * \param ctx DHM context * \param output destination buffer * \param olen number of chars written + * \param f_rng RNG function, for blinding purposes + * \param p_rng RNG parameter * * \return 0 if successful, or an POLARSSL_ERR_DHM_XXX error code */ int dhm_calc_secret( dhm_context *ctx, - unsigned char *output, size_t *olen ); + unsigned char *output, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); /** * \brief Free the components of a DHM key diff --git a/library/dhm.c b/library/dhm.c index 0c65dfec3..a5c3e9095 100644 --- a/library/dhm.c +++ b/library/dhm.c @@ -249,10 +249,15 @@ cleanup: * Derive and export the shared secret (G^Y)^X mod P */ int dhm_calc_secret( dhm_context *ctx, - unsigned char *output, size_t *olen ) + unsigned char *output, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) { int ret; + (void) f_rng; + (void) p_rng; + if( ctx == NULL || *olen < ctx->len ) return( POLARSSL_ERR_DHM_BAD_INPUT_DATA ); diff --git a/library/ssl_cli.c b/library/ssl_cli.c index 3b9d14246..e7512986c 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -1713,7 +1713,8 @@ static int ssl_write_client_key_exchange( ssl_context *ssl ) if( ( ret = dhm_calc_secret( &ssl->handshake->dhm_ctx, ssl->handshake->premaster, - &ssl->handshake->pmslen ) ) != 0 ) + &ssl->handshake->pmslen, + ssl->f_rng, ssl->p_rng ) ) != 0 ) { SSL_DEBUG_RET( 1, "dhm_calc_secret", ret ); return( ret ); @@ -1842,7 +1843,7 @@ static int ssl_write_client_key_exchange( ssl_context *ssl ) *(p++) = (unsigned char)( ssl->handshake->dhm_ctx.len >> 8 ); *(p++) = (unsigned char)( ssl->handshake->dhm_ctx.len ); if( ( ret = dhm_calc_secret( &ssl->handshake->dhm_ctx, - p, &n ) ) != 0 ) + p, &n, ssl->f_rng, ssl->p_rng ) ) != 0 ) { SSL_DEBUG_RET( 1, "dhm_calc_secret", ret ); return( ret ); diff --git a/library/ssl_srv.c b/library/ssl_srv.c index adf5a623f..f0936b403 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2386,7 +2386,8 @@ static int ssl_parse_client_key_exchange( ssl_context *ssl ) if( ( ret = dhm_calc_secret( &ssl->handshake->dhm_ctx, ssl->handshake->premaster, - &ssl->handshake->pmslen ) ) != 0 ) + &ssl->handshake->pmslen, + ssl->f_rng, ssl->p_rng ) ) != 0 ) { SSL_DEBUG_RET( 1, "dhm_calc_secret", ret ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS ); @@ -2472,7 +2473,7 @@ static int ssl_parse_client_key_exchange( ssl_context *ssl ) n = ssl->handshake->dhm_ctx.len; if( ( ret = dhm_calc_secret( &ssl->handshake->dhm_ctx, - p, &n ) ) != 0 ) + p, &n, ssl->f_rng, ssl->p_rng ) ) != 0 ) { SSL_DEBUG_RET( 1, "dhm_calc_secret", ret ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS ); diff --git a/programs/pkey/dh_client.c b/programs/pkey/dh_client.c index f06b9069b..c5c6f7584 100644 --- a/programs/pkey/dh_client.c +++ b/programs/pkey/dh_client.c @@ -239,7 +239,7 @@ int main( int argc, char *argv[] ) fflush( stdout ); n = dhm.len; - if( ( ret = dhm_calc_secret( &dhm, buf, &n ) ) != 0 ) + if( ( ret = dhm_calc_secret( &dhm, buf, &n, NULL, NULL ) ) != 0 ) { printf( " failed\n ! dhm_calc_secret returned %d\n\n", ret ); goto exit; diff --git a/programs/pkey/dh_server.c b/programs/pkey/dh_server.c index 1eba8061e..33823077d 100644 --- a/programs/pkey/dh_server.c +++ b/programs/pkey/dh_server.c @@ -242,7 +242,7 @@ int main( int argc, char *argv[] ) printf( "\n . Shared secret: " ); fflush( stdout ); - if( ( ret = dhm_calc_secret( &dhm, buf, &n ) ) != 0 ) + if( ( ret = dhm_calc_secret( &dhm, buf, &n, NULL, NULL ) ) != 0 ) { printf( " failed\n ! dhm_calc_secret returned %d\n\n", ret ); goto exit; diff --git a/tests/suites/test_suite_dhm.function b/tests/suites/test_suite_dhm.function index e6524cc14..e6fadfb2f 100644 --- a/tests/suites/test_suite_dhm.function +++ b/tests/suites/test_suite_dhm.function @@ -49,8 +49,8 @@ void dhm_do_dhm( int NOTUSED, int radix_P, char *input_P, TEST_ASSERT( dhm_read_public( &ctx_srv, pub_cli, pub_cli_len ) == 0 ); - TEST_ASSERT( dhm_calc_secret( &ctx_srv, sec_srv, &sec_srv_len ) == 0 ); - TEST_ASSERT( dhm_calc_secret( &ctx_cli, sec_cli, &sec_cli_len ) == 0 ); + TEST_ASSERT( dhm_calc_secret( &ctx_srv, sec_srv, &sec_srv_len, &rnd_pseudo_rand, &rnd_info ) == 0 ); + TEST_ASSERT( dhm_calc_secret( &ctx_cli, sec_cli, &sec_cli_len, NULL, NULL ) == 0 ); TEST_ASSERT( sec_srv_len == sec_cli_len ); TEST_ASSERT( sec_srv_len != 0 ); From 143b5028a5a0a2ff545bc1de40d92b675e8da886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 4 Sep 2013 16:29:59 +0200 Subject: [PATCH 05/13] Implement DH blinding --- include/polarssl/dhm.h | 6 ++ library/dhm.c | 86 ++++++++++++++++++++++++++-- tests/suites/test_suite_dhm.data | 2 +- tests/suites/test_suite_dhm.function | 39 ++++++++++++- 4 files changed, 124 insertions(+), 9 deletions(-) diff --git a/include/polarssl/dhm.h b/include/polarssl/dhm.h index 4d7bd8a7a..4874bc8df 100644 --- a/include/polarssl/dhm.h +++ b/include/polarssl/dhm.h @@ -147,6 +147,9 @@ typedef struct mpi GY; /*!< peer = G^Y mod P */ mpi K; /*!< key = GY^X mod P */ mpi RP; /*!< cached R^2 mod P */ + mpi Vi; /*!< blinding value */ + mpi Vf; /*!< un-blinding value */ + mpi _X; /*!< previous X */ } dhm_context; @@ -223,6 +226,9 @@ int dhm_make_public( dhm_context *ctx, int x_size, * \param p_rng RNG parameter * * \return 0 if successful, or an POLARSSL_ERR_DHM_XXX error code + * + * \note If f_rng is not NULL, it is used to blind the input as + * countermeasure against timing attacks. */ int dhm_calc_secret( dhm_context *ctx, unsigned char *output, size_t *olen, diff --git a/library/dhm.c b/library/dhm.c index a5c3e9095..11eee2a7a 100644 --- a/library/dhm.c +++ b/library/dhm.c @@ -245,6 +245,60 @@ cleanup: return( 0 ); } +/* + * Use the blinding method and optimisation suggested in section 10 of: + * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA, + * DSS, and other systems. In : Advances in Cryptology—CRYPTO’96. Springer + * Berlin Heidelberg, 1996. p. 104-113. + */ +static int dhm_update_blinding( dhm_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret, count; + + /* + * We can just update the previous values (by squaring them) if: + * - the values are initialized, and + * - our secret exponent did not change. + */ + if( ctx->Vi.p != NULL && + mpi_cmp_mpi( &ctx->X, &ctx->_X ) == 0 ) + { + MPI_CHK( mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) ); + MPI_CHK( mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) ); + + return( 0 ); + } + + /* + * Otherwise, we need to generate new values from scratch for this secret + */ + + /* Vi = random( 2, P-1 ) */ + count = 0; + do + { + mpi_fill_random( &ctx->Vi, mpi_size( &ctx->P ), f_rng, p_rng ); + + while( mpi_cmp_mpi( &ctx->Vi, &ctx->P ) >= 0 ) + mpi_shift_r( &ctx->Vi, 1 ); + + if( count++ > 10 ) + return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); + } + while( mpi_cmp_int( &ctx->Vi, 1 ) <= 0 ); + + /* Vf = Vi^-X mod P */ + MPI_CHK( mpi_inv_mod( &ctx->Vf, &ctx->Vi, &ctx->P ) ); + MPI_CHK( mpi_exp_mod( &ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP ) ); + + /* Remember secret associated with Vi and Vf */ + MPI_CHK( mpi_copy( &ctx->_X, &ctx->X ) );; + +cleanup: + return( ret ); +} + /* * Derive and export the shared secret (G^Y)^X mod P */ @@ -254,24 +308,43 @@ int dhm_calc_secret( dhm_context *ctx, void *p_rng ) { int ret; - - (void) f_rng; - (void) p_rng; + mpi GYb; if( ctx == NULL || *olen < ctx->len ) return( POLARSSL_ERR_DHM_BAD_INPUT_DATA ); - MPI_CHK( mpi_exp_mod( &ctx->K, &ctx->GY, &ctx->X, - &ctx->P, &ctx->RP ) ); - if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 ) return( ret ); + mpi_init( &GYb ); + + /* Blind peer's value */ + if( f_rng != 0 ) + { + MPI_CHK( dhm_update_blinding( ctx, f_rng, p_rng ) ); + MPI_CHK( mpi_mul_mpi( &GYb, &ctx->GY, &ctx->Vi ) ); + MPI_CHK( mpi_mod_mpi( &GYb, &GYb, &ctx->P ) ); + } + else + MPI_CHK( mpi_copy( &GYb, &ctx->GY ) ); + + /* Do modular exponentiation */ + MPI_CHK( mpi_exp_mod( &ctx->K, &GYb, &ctx->X, + &ctx->P, &ctx->RP ) ); + + /* Unblind secret value */ + if( f_rng != 0 ) + { + MPI_CHK( mpi_mul_mpi( &ctx->K, &ctx->K, &ctx->Vf ) ); + MPI_CHK( mpi_mod_mpi( &ctx->K, &ctx->K, &ctx->P ) ); + } + *olen = mpi_size( &ctx->K ); MPI_CHK( mpi_write_binary( &ctx->K, output, *olen ) ); cleanup: + mpi_free( &GYb ); if( ret != 0 ) return( POLARSSL_ERR_DHM_CALC_SECRET_FAILED + ret ); @@ -284,6 +357,7 @@ cleanup: */ void dhm_free( dhm_context *ctx ) { + mpi_free( &ctx->Vi ); mpi_free( &ctx->Vf ); mpi_free( &ctx->RP ); mpi_free( &ctx->K ); mpi_free( &ctx->GY ); mpi_free( &ctx->GX ); mpi_free( &ctx->X ); mpi_free( &ctx->G ); mpi_free( &ctx->P ); diff --git a/tests/suites/test_suite_dhm.data b/tests/suites/test_suite_dhm.data index 99f44826d..0c0dce867 100644 --- a/tests/suites/test_suite_dhm.data +++ b/tests/suites/test_suite_dhm.data @@ -4,5 +4,5 @@ dhm_do_dhm:1024:10:"23":10:"5" Diffie-Hellman full exchange #2 dhm_do_dhm:1024:10:"93450983094850938450983409623":10:"9345098304850938450983409622" -Diffie-Hellman full exchange #2 +Diffie-Hellman full exchange #3 dhm_do_dhm:1024:10:"93450983094850938450983409623982317398171298719873918739182739712938719287391879381271":10:"9345098309485093845098340962223981329819812792137312973297123912791271" diff --git a/tests/suites/test_suite_dhm.function b/tests/suites/test_suite_dhm.function index e6fadfb2f..31a9004c3 100644 --- a/tests/suites/test_suite_dhm.function +++ b/tests/suites/test_suite_dhm.function @@ -35,18 +35,53 @@ void dhm_do_dhm( int NOTUSED, int radix_P, char *input_P, memset( sec_cli, 0x00, 1000 ); memset( &rnd_info, 0x00, sizeof( rnd_pseudo_info ) ); + /* + * Set params + */ TEST_ASSERT( mpi_read_string( &ctx_srv.P, radix_P, input_P ) == 0 ); TEST_ASSERT( mpi_read_string( &ctx_srv.G, radix_G, input_G ) == 0 ); x_size = mpi_size( &ctx_srv.P ); + pub_cli_len = x_size; + + /* + * First key exchange + */ + TEST_ASSERT( dhm_make_params( &ctx_srv, x_size, ske, &ske_len, &rnd_pseudo_rand, &rnd_info ) == 0 ); + ske[ske_len++] = 0; + ske[ske_len++] = 0; + TEST_ASSERT( dhm_read_params( &ctx_cli, &p, ske + ske_len ) == 0 ); + + TEST_ASSERT( dhm_make_public( &ctx_cli, x_size, pub_cli, pub_cli_len, &rnd_pseudo_rand, &rnd_info ) == 0 ); + TEST_ASSERT( dhm_read_public( &ctx_srv, pub_cli, pub_cli_len ) == 0 ); + + TEST_ASSERT( dhm_calc_secret( &ctx_srv, sec_srv, &sec_srv_len, &rnd_pseudo_rand, &rnd_info ) == 0 ); + TEST_ASSERT( dhm_calc_secret( &ctx_cli, sec_cli, &sec_cli_len, NULL, NULL ) == 0 ); + + TEST_ASSERT( sec_srv_len == sec_cli_len ); + TEST_ASSERT( sec_srv_len != 0 ); + TEST_ASSERT( memcmp( sec_srv, sec_cli, sec_srv_len ) == 0 ); + + /* Re-do calc_secret on server to test update of blinding values */ + sec_srv_len = 1000; + TEST_ASSERT( dhm_calc_secret( &ctx_srv, sec_srv, &sec_srv_len, &rnd_pseudo_rand, &rnd_info ) == 0 ); + + TEST_ASSERT( sec_srv_len == sec_cli_len ); + TEST_ASSERT( sec_srv_len != 0 ); + TEST_ASSERT( memcmp( sec_srv, sec_cli, sec_srv_len ) == 0 ); + + /* + * Second key exchange to test change of blinding values on server + */ + sec_cli_len = 1000; + sec_srv_len = 1000; + p = ske; TEST_ASSERT( dhm_make_params( &ctx_srv, x_size, ske, &ske_len, &rnd_pseudo_rand, &rnd_info ) == 0 ); ske[ske_len++] = 0; ske[ske_len++] = 0; TEST_ASSERT( dhm_read_params( &ctx_cli, &p, ske + ske_len ) == 0 ); - pub_cli_len = x_size; TEST_ASSERT( dhm_make_public( &ctx_cli, x_size, pub_cli, pub_cli_len, &rnd_pseudo_rand, &rnd_info ) == 0 ); - TEST_ASSERT( dhm_read_public( &ctx_srv, pub_cli, pub_cli_len ) == 0 ); TEST_ASSERT( dhm_calc_secret( &ctx_srv, sec_srv, &sec_srv_len, &rnd_pseudo_rand, &rnd_info ) == 0 ); From ed8a02bfaef6ad630726a80ac88a01568e04ca8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 4 Sep 2013 16:39:03 +0200 Subject: [PATCH 06/13] Simplify DH blinding a bit --- library/dhm.c | 55 ++++++++++++++++------------ tests/suites/test_suite_dhm.data | 6 +-- tests/suites/test_suite_dhm.function | 4 +- 3 files changed, 35 insertions(+), 30 deletions(-) diff --git a/library/dhm.c b/library/dhm.c index 11eee2a7a..b95f89958 100644 --- a/library/dhm.c +++ b/library/dhm.c @@ -257,37 +257,44 @@ static int dhm_update_blinding( dhm_context *ctx, int ret, count; /* - * We can just update the previous values (by squaring them) if: - * - the values are initialized, and - * - our secret exponent did not change. + * If Vi is initialized, update it by squaring it */ - if( ctx->Vi.p != NULL && - mpi_cmp_mpi( &ctx->X, &ctx->_X ) == 0 ) + if( ctx->Vi.p != NULL ) + { + MPI_CHK( mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) ); + MPI_CHK( mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->P ) ); + } + else + { + /* Vi = random( 2, P-1 ) */ + count = 0; + do + { + mpi_fill_random( &ctx->Vi, mpi_size( &ctx->P ), f_rng, p_rng ); + + while( mpi_cmp_mpi( &ctx->Vi, &ctx->P ) >= 0 ) + mpi_shift_r( &ctx->Vi, 1 ); + + if( count++ > 10 ) + return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); + } + while( mpi_cmp_int( &ctx->Vi, 1 ) <= 0 ); + } + + /* + * If X did not change, update Vf by squaring it too + */ + if( mpi_cmp_mpi( &ctx->X, &ctx->_X ) == 0 ) { MPI_CHK( mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) ); - MPI_CHK( mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) ); - + MPI_CHK( mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) ); return( 0 ); } /* - * Otherwise, we need to generate new values from scratch for this secret + * Otherwise, compute Vf from scratch */ - /* Vi = random( 2, P-1 ) */ - count = 0; - do - { - mpi_fill_random( &ctx->Vi, mpi_size( &ctx->P ), f_rng, p_rng ); - - while( mpi_cmp_mpi( &ctx->Vi, &ctx->P ) >= 0 ) - mpi_shift_r( &ctx->Vi, 1 ); - - if( count++ > 10 ) - return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); - } - while( mpi_cmp_int( &ctx->Vi, 1 ) <= 0 ); - /* Vf = Vi^-X mod P */ MPI_CHK( mpi_inv_mod( &ctx->Vf, &ctx->Vi, &ctx->P ) ); MPI_CHK( mpi_exp_mod( &ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP ) ); @@ -319,7 +326,7 @@ int dhm_calc_secret( dhm_context *ctx, mpi_init( &GYb ); /* Blind peer's value */ - if( f_rng != 0 ) + if( f_rng != NULL ) { MPI_CHK( dhm_update_blinding( ctx, f_rng, p_rng ) ); MPI_CHK( mpi_mul_mpi( &GYb, &ctx->GY, &ctx->Vi ) ); @@ -333,7 +340,7 @@ int dhm_calc_secret( dhm_context *ctx, &ctx->P, &ctx->RP ) ); /* Unblind secret value */ - if( f_rng != 0 ) + if( f_rng != NULL ) { MPI_CHK( mpi_mul_mpi( &ctx->K, &ctx->K, &ctx->Vf ) ); MPI_CHK( mpi_mod_mpi( &ctx->K, &ctx->K, &ctx->P ) ); diff --git a/tests/suites/test_suite_dhm.data b/tests/suites/test_suite_dhm.data index 0c0dce867..168c77c1b 100644 --- a/tests/suites/test_suite_dhm.data +++ b/tests/suites/test_suite_dhm.data @@ -1,8 +1,8 @@ Diffie-Hellman full exchange #1 -dhm_do_dhm:1024:10:"23":10:"5" +dhm_do_dhm:10:"23":10:"5" Diffie-Hellman full exchange #2 -dhm_do_dhm:1024:10:"93450983094850938450983409623":10:"9345098304850938450983409622" +dhm_do_dhm:10:"93450983094850938450983409623":10:"9345098304850938450983409622" Diffie-Hellman full exchange #3 -dhm_do_dhm:1024:10:"93450983094850938450983409623982317398171298719873918739182739712938719287391879381271":10:"9345098309485093845098340962223981329819812792137312973297123912791271" +dhm_do_dhm:10:"93450983094850938450983409623982317398171298719873918739182739712938719287391879381271":10:"9345098309485093845098340962223981329819812792137312973297123912791271" diff --git a/tests/suites/test_suite_dhm.function b/tests/suites/test_suite_dhm.function index 31a9004c3..e8d9cea84 100644 --- a/tests/suites/test_suite_dhm.function +++ b/tests/suites/test_suite_dhm.function @@ -8,7 +8,7 @@ */ /* BEGIN_CASE */ -void dhm_do_dhm( int NOTUSED, int radix_P, char *input_P, +void dhm_do_dhm( int radix_P, char *input_P, int radix_G, char *input_G ) { dhm_context ctx_srv; @@ -25,8 +25,6 @@ void dhm_do_dhm( int NOTUSED, int radix_P, char *input_P, int x_size; rnd_pseudo_info rnd_info; - ((void)NOTUSED); - memset( &ctx_srv, 0x00, sizeof( dhm_context ) ); memset( &ctx_cli, 0x00, sizeof( dhm_context ) ); memset( ske, 0x00, 1000 ); From cac5f7d7372fbe27284f2ac2144125b987b69649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 4 Sep 2013 17:19:18 +0200 Subject: [PATCH 07/13] Update benchmarks for new prototypes --- programs/test/benchmark.c | 13 ++++++------- programs/test/ecp-bench.c | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/programs/test/benchmark.c b/programs/test/benchmark.c index c33f5b5bc..bf8b7bbdd 100644 --- a/programs/test/benchmark.c +++ b/programs/test/benchmark.c @@ -446,7 +446,7 @@ int main( int argc, char *argv[] ) for( i = 1; ! alarmed; i++ ) { buf[0] = 0; - rsa_private( &rsa, buf, buf ); + rsa_private( &rsa, myrand, NULL, buf, buf ); } printf( "%9lu private/s\n", i / 3 ); @@ -475,7 +475,7 @@ int main( int argc, char *argv[] ) for( i = 1; ! alarmed; i++ ) { buf[0] = 0; - rsa_private( &rsa, buf, buf ); + rsa_private( &rsa, myrand, NULL, buf, buf ); } printf( "%9lu private/s\n", i / 3 ); @@ -504,7 +504,7 @@ int main( int argc, char *argv[] ) for( i = 1; ! alarmed; i++ ) { buf[0] = 0; - rsa_private( &rsa, buf, buf ); + rsa_private( &rsa, myrand, NULL, buf, buf ); } printf( "%9lu private/s\n", i / 3 ); @@ -528,7 +528,7 @@ int main( int argc, char *argv[] ) for( i = 1; ! alarmed; i++ ) { dhm_make_public( &dhm, dhm.len, buf, dhm.len, myrand, NULL ); - dhm_calc_secret( &dhm, buf, &olen ); + dhm_calc_secret( &dhm, buf, &olen, NULL, NULL ); } printf( "%9lu handshake/s\n", i / 3 ); @@ -550,13 +550,12 @@ int main( int argc, char *argv[] ) for( i = 1; ! alarmed; i++ ) { dhm_make_public( &dhm, dhm.len, buf, dhm.len, myrand, NULL ); - dhm_calc_secret( &dhm, buf, &olen ); + dhm_calc_secret( &dhm, buf, &olen, NULL, NULL ); } printf( "%9lu handshake/s\n", i / 3 ); dhm_free( &dhm ); - memset( &dhm, 0, sizeof( dhm_context ) ); mpi_read_string( &dhm.P, 16, POLARSSL_DHM_RFC3526_MODP_3072_P ); @@ -572,7 +571,7 @@ int main( int argc, char *argv[] ) for( i = 1; ! alarmed; i++ ) { dhm_make_public( &dhm, dhm.len, buf, dhm.len, myrand, NULL ); - dhm_calc_secret( &dhm, buf, &olen ); + dhm_calc_secret( &dhm, buf, &olen, NULL, NULL ); } printf( "%9lu handshake/s\n", i / 3 ); diff --git a/programs/test/ecp-bench.c b/programs/test/ecp-bench.c index 0a0e015b4..e200c4267 100644 --- a/programs/test/ecp-bench.c +++ b/programs/test/ecp-bench.c @@ -161,7 +161,7 @@ static void ecp_bench_case( size_t dp, const char *s, const char *m ) set_alarm( 3 ); for( i = 1; ! alarmed; i++ ) - ecp_mul( &grp, &R, &M, &grp.G ); + ecp_mul( &grp, &R, &M, &grp.G, NULL, NULL ); printf( "%9lu mul/s\n", i / 3 ); From 337b29c3345201e7556d6f3718b189e65a4298fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Sat, 7 Sep 2013 11:52:27 +0200 Subject: [PATCH 08/13] Test and document EC blinding overhead --- include/polarssl/ecp.h | 6 ++++-- programs/test/ecp-bench.c | 25 ++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/include/polarssl/ecp.h b/include/polarssl/ecp.h index 594223133..31f9e6ddb 100644 --- a/include/polarssl/ecp.h +++ b/include/polarssl/ecp.h @@ -427,8 +427,10 @@ int ecp_sub( const ecp_group *grp, ecp_point *R, * \note If f_rng is not NULL, it is used to randomize projective * coordinates of indermediate results, in order to prevent * more elaborate timing attacks relying on intermediate - * operations. (This is a prophylactic measure since so such - * attack has been published yet.) + * operations. (This is a prophylactic measure since no such + * attack has been published yet.) Since this contermeasure + * has very low overhead, it is recommended to always provide + * a non-NULL f_rng parameter when using secret inputs. */ int ecp_mul( const ecp_group *grp, ecp_point *R, const mpi *m, const ecp_point *P, diff --git a/programs/test/ecp-bench.c b/programs/test/ecp-bench.c index e200c4267..923111876 100644 --- a/programs/test/ecp-bench.c +++ b/programs/test/ecp-bench.c @@ -28,6 +28,29 @@ int main( int argc, char *argv[] ) #else +static int myrand( void *rng_state, unsigned char *output, size_t len ) +{ + size_t use_len; + int rnd; + + if( rng_state != NULL ) + rng_state = NULL; + + while( len > 0 ) + { + use_len = len; + if( use_len > sizeof(int) ) + use_len = sizeof(int); + + rnd = rand(); + memcpy( output, &rnd, use_len ); + output += use_len; + len -= use_len; + } + + return( 0 ); +} + static void dhm_bench_case( const char *s, const char *p, const char *g, const char *x ) { @@ -161,7 +184,7 @@ static void ecp_bench_case( size_t dp, const char *s, const char *m ) set_alarm( 3 ); for( i = 1; ! alarmed; i++ ) - ecp_mul( &grp, &R, &M, &grp.G, NULL, NULL ); + ecp_mul( &grp, &R, &M, &grp.G, myrand, NULL ); printf( "%9lu mul/s\n", i / 3 ); From 1a2012459b09f082db52b4c22b1214c9acdc102a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Sat, 7 Sep 2013 12:27:35 +0200 Subject: [PATCH 09/13] Fix undetected errors in benchmark dhm_calc_secret() was exiting early, leading to wrong results --- programs/test/benchmark.c | 101 ++++++++++++++++++++++++++------------ 1 file changed, 70 insertions(+), 31 deletions(-) diff --git a/programs/test/benchmark.c b/programs/test/benchmark.c index bf8b7bbdd..401c83727 100644 --- a/programs/test/benchmark.c +++ b/programs/test/benchmark.c @@ -92,7 +92,7 @@ int main( int argc, char *argv[] ) #else int main( int argc, char *argv[] ) { - int keysize; + int ret, keysize; unsigned long i, j, tsc; unsigned char tmp[64]; #if defined(POLARSSL_ARC4_C) @@ -431,25 +431,33 @@ int main( int argc, char *argv[] ) fflush( stdout ); set_alarm( 3 ); - for( i = 1; ! alarmed; i++ ) + ret = 0; + for( i = 1; ! alarmed && ! ret ; i++ ) { buf[0] = 0; - rsa_public( &rsa, buf, buf ); + ret = rsa_public( &rsa, buf, buf ); } - printf( "%9lu public/s\n", i / 3 ); + if( ret != 0 ) + printf( "FAILED\n" ); + else + printf( "%9lu public/s\n", i / 3 ); printf( HEADER_FORMAT, "RSA-1024" ); fflush( stdout ); set_alarm( 3 ); - for( i = 1; ! alarmed; i++ ) + ret = 0; + for( i = 1; ! alarmed && ! ret ; i++ ) { buf[0] = 0; - rsa_private( &rsa, myrand, NULL, buf, buf ); + ret = rsa_private( &rsa, myrand, NULL, buf, buf ); } - printf( "%9lu private/s\n", i / 3 ); + if( ret != 0 ) + printf( "FAILED\n" ); + else + printf( "%9lu private/s\n", i / 3 ); rsa_free( &rsa ); @@ -460,25 +468,33 @@ int main( int argc, char *argv[] ) fflush( stdout ); set_alarm( 3 ); - for( i = 1; ! alarmed; i++ ) + ret = 0; + for( i = 1; ! alarmed && ! ret ; i++ ) { buf[0] = 0; - rsa_public( &rsa, buf, buf ); + ret = rsa_public( &rsa, buf, buf ); } - printf( "%9lu public/s\n", i / 3 ); + if( ret != 0 ) + printf( "FAILED\n" ); + else + printf( "%9lu public/s\n", i / 3 ); printf( HEADER_FORMAT, "RSA-2048" ); fflush( stdout ); set_alarm( 3 ); - for( i = 1; ! alarmed; i++ ) + ret = 0; + for( i = 1; ! alarmed && ! ret ; i++ ) { buf[0] = 0; - rsa_private( &rsa, myrand, NULL, buf, buf ); + ret = rsa_private( &rsa, myrand, NULL, buf, buf ); } - printf( "%9lu private/s\n", i / 3 ); + if( ret != 0 ) + printf( "FAILED\n" ); + else + printf( "%9lu private/s\n", i / 3 ); rsa_free( &rsa ); @@ -489,25 +505,33 @@ int main( int argc, char *argv[] ) fflush( stdout ); set_alarm( 3 ); - for( i = 1; ! alarmed; i++ ) + ret = 0; + for( i = 1; ! alarmed && ! ret ; i++ ) { buf[0] = 0; - rsa_public( &rsa, buf, buf ); + ret = rsa_public( &rsa, buf, buf ); } - printf( "%9lu public/s\n", i / 3 ); + if( ret != 0 ) + printf( "FAILED\n" ); + else + printf( "%9lu public/s\n", i / 3 ); printf( HEADER_FORMAT, "RSA-4096" ); fflush( stdout ); set_alarm( 3 ); - for( i = 1; ! alarmed; i++ ) + ret = 0; + for( i = 1; ! alarmed && ! ret ; i++ ) { buf[0] = 0; - rsa_private( &rsa, myrand, NULL, buf, buf ); + ret = rsa_private( &rsa, myrand, NULL, buf, buf ); } - printf( "%9lu private/s\n", i / 3 ); + if( ret != 0 ) + printf( "FAILED\n" ); + else + printf( "%9lu private/s\n", i / 3 ); rsa_free( &rsa ); #endif @@ -525,13 +549,18 @@ int main( int argc, char *argv[] ) fflush( stdout ); set_alarm( 3 ); - for( i = 1; ! alarmed; i++ ) + ret = 0; + for( i = 1; ! alarmed && ! ret ; i++ ) { - dhm_make_public( &dhm, dhm.len, buf, dhm.len, myrand, NULL ); - dhm_calc_secret( &dhm, buf, &olen, NULL, NULL ); + olen = sizeof( buf ); + ret |= dhm_make_public( &dhm, dhm.len, buf, dhm.len, myrand, NULL ); + ret |= dhm_calc_secret( &dhm, buf, &olen, NULL, NULL ); } - printf( "%9lu handshake/s\n", i / 3 ); + if( ret != 0 ) + printf( "FAILED\n" ); + else + printf( "%9lu handshake/s\n", i / 3 ); dhm_free( &dhm ); @@ -547,13 +576,18 @@ int main( int argc, char *argv[] ) fflush( stdout ); set_alarm( 3 ); - for( i = 1; ! alarmed; i++ ) + ret = 0; + for( i = 1; ! alarmed && ! ret ; i++ ) { - dhm_make_public( &dhm, dhm.len, buf, dhm.len, myrand, NULL ); - dhm_calc_secret( &dhm, buf, &olen, NULL, NULL ); + olen = sizeof( buf ); + ret |= dhm_make_public( &dhm, dhm.len, buf, dhm.len, myrand, NULL ); + ret |= dhm_calc_secret( &dhm, buf, &olen, NULL, NULL ); } - printf( "%9lu handshake/s\n", i / 3 ); + if( ret != 0 ) + printf( "FAILED\n" ); + else + printf( "%9lu handshake/s\n", i / 3 ); dhm_free( &dhm ); memset( &dhm, 0, sizeof( dhm_context ) ); @@ -568,13 +602,18 @@ int main( int argc, char *argv[] ) fflush( stdout ); set_alarm( 3 ); - for( i = 1; ! alarmed; i++ ) + ret = 0; + for( i = 1; ! alarmed && ! ret ; i++ ) { - dhm_make_public( &dhm, dhm.len, buf, dhm.len, myrand, NULL ); - dhm_calc_secret( &dhm, buf, &olen, NULL, NULL ); + olen = sizeof( buf ); + ret |= dhm_make_public( &dhm, dhm.len, buf, dhm.len, myrand, NULL ); + ret |= dhm_calc_secret( &dhm, buf, &olen, NULL, NULL ); } - printf( "%9lu handshake/s\n", i / 3 ); + if( ret != 0 ) + printf( "FAILED\n" ); + else + printf( "%9lu handshake/s\n", i / 3 ); dhm_free( &dhm ); #endif From ce6352a791f5e4ce04fbaca60fc99514aab79cf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Sat, 7 Sep 2013 13:05:52 +0200 Subject: [PATCH 10/13] Add benchmark for fixed-DHM with blinding --- programs/test/benchmark.c | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/programs/test/benchmark.c b/programs/test/benchmark.c index 401c83727..e0d65d33d 100644 --- a/programs/test/benchmark.c +++ b/programs/test/benchmark.c @@ -557,6 +557,22 @@ int main( int argc, char *argv[] ) ret |= dhm_calc_secret( &dhm, buf, &olen, NULL, NULL ); } + if( ret != 0 ) + printf( "FAILED\n" ); + else + printf( "%9lu handshake/s\n", i / 3 ); + + printf( HEADER_FORMAT, "fixed-DHM-1024" ); + fflush( stdout ); + set_alarm( 3 ); + + ret = 0; + for( i = 1; ! alarmed && ! ret ; i++ ) + { + olen = sizeof( buf ); + ret |= dhm_calc_secret( &dhm, buf, &olen, myrand, NULL ); + } + if( ret != 0 ) printf( "FAILED\n" ); else @@ -581,6 +597,22 @@ int main( int argc, char *argv[] ) { olen = sizeof( buf ); ret |= dhm_make_public( &dhm, dhm.len, buf, dhm.len, myrand, NULL ); + ret |= dhm_calc_secret( &dhm, buf, &olen, myrand, NULL ); + } + + if( ret != 0 ) + printf( "FAILED\n" ); + else + printf( "%9lu handshake/s\n", i / 3 ); + + printf( HEADER_FORMAT, "fixed-DHM-2048" ); + fflush( stdout ); + set_alarm( 3 ); + + ret = 0; + for( i = 1; ! alarmed && ! ret ; i++ ) + { + olen = sizeof( buf ); ret |= dhm_calc_secret( &dhm, buf, &olen, NULL, NULL ); } @@ -610,6 +642,22 @@ int main( int argc, char *argv[] ) ret |= dhm_calc_secret( &dhm, buf, &olen, NULL, NULL ); } + if( ret != 0 ) + printf( "FAILED\n" ); + else + printf( "%9lu handshake/s\n", i / 3 ); + + printf( HEADER_FORMAT, "fixed-DHM-3072" ); + fflush( stdout ); + set_alarm( 3 ); + + ret = 0; + for( i = 1; ! alarmed && ! ret ; i++ ) + { + olen = sizeof( buf ); + ret |= dhm_calc_secret( &dhm, buf, &olen, myrand, NULL ); + } + if( ret != 0 ) printf( "FAILED\n" ); else From 032c34e206730f7c7cede6909724c8f73db83637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Sat, 7 Sep 2013 13:06:27 +0200 Subject: [PATCH 11/13] Don't use DH blinding for ephemeral DH --- include/polarssl/dhm.h | 7 ++++++- library/ssl_cli.c | 6 ++++-- library/ssl_srv.c | 6 ++++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/include/polarssl/dhm.h b/include/polarssl/dhm.h index 4874bc8df..09de70b0e 100644 --- a/include/polarssl/dhm.h +++ b/include/polarssl/dhm.h @@ -228,7 +228,12 @@ int dhm_make_public( dhm_context *ctx, int x_size, * \return 0 if successful, or an POLARSSL_ERR_DHM_XXX error code * * \note If f_rng is not NULL, it is used to blind the input as - * countermeasure against timing attacks. + * countermeasure against timing attacks. This is only useful + * when this function is called repeatedly with the same + * secret value (X field), eg when using DH key exchange as + * opposed to DHE. It is recommended to use a non-NULL f_rng + * only when needed, since otherwise this countermeasure has + * high overhead. */ int dhm_calc_secret( dhm_context *ctx, unsigned char *output, size_t *olen, diff --git a/library/ssl_cli.c b/library/ssl_cli.c index e7512986c..19f0cb683 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -1711,10 +1711,11 @@ static int ssl_write_client_key_exchange( ssl_context *ssl ) ssl->handshake->pmslen = ssl->handshake->dhm_ctx.len; + /* No blinding needed for DHE, but will be needed for fixed DH! */ if( ( ret = dhm_calc_secret( &ssl->handshake->dhm_ctx, ssl->handshake->premaster, &ssl->handshake->pmslen, - ssl->f_rng, ssl->p_rng ) ) != 0 ) + NULL, NULL ) ) != 0 ) { SSL_DEBUG_RET( 1, "dhm_calc_secret", ret ); return( ret ); @@ -1842,8 +1843,9 @@ static int ssl_write_client_key_exchange( ssl_context *ssl ) *(p++) = (unsigned char)( ssl->handshake->dhm_ctx.len >> 8 ); *(p++) = (unsigned char)( ssl->handshake->dhm_ctx.len ); + /* No blinding needed since this is ephemeral DHM */ if( ( ret = dhm_calc_secret( &ssl->handshake->dhm_ctx, - p, &n, ssl->f_rng, ssl->p_rng ) ) != 0 ) + p, &n, NULL, NULL ) ) != 0 ) { SSL_DEBUG_RET( 1, "dhm_calc_secret", ret ); return( ret ); diff --git a/library/ssl_srv.c b/library/ssl_srv.c index f0936b403..21ceaf1f8 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2384,10 +2384,11 @@ static int ssl_parse_client_key_exchange( ssl_context *ssl ) ssl->handshake->pmslen = ssl->handshake->dhm_ctx.len; + /* No blinding needed for DHE, but will be needed for fixed DH! */ if( ( ret = dhm_calc_secret( &ssl->handshake->dhm_ctx, ssl->handshake->premaster, &ssl->handshake->pmslen, - ssl->f_rng, ssl->p_rng ) ) != 0 ) + NULL, NULL ) ) != 0 ) { SSL_DEBUG_RET( 1, "dhm_calc_secret", ret ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS ); @@ -2472,8 +2473,9 @@ static int ssl_parse_client_key_exchange( ssl_context *ssl ) n = ssl->handshake->dhm_ctx.len; + /* No blinding needed since this is ephemeral DHM */ if( ( ret = dhm_calc_secret( &ssl->handshake->dhm_ctx, - p, &n, ssl->f_rng, ssl->p_rng ) ) != 0 ) + p, &n, NULL, NULL ) ) != 0 ) { SSL_DEBUG_RET( 1, "dhm_calc_secret", ret ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS ); From ea53a55c0f39a0f5f6b4edf4d733188e88f094a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 10 Sep 2013 13:29:30 +0200 Subject: [PATCH 12/13] Refactor to prepare for RSA blinding optimisation --- include/polarssl/rsa.h | 5 +++++ library/rsa.c | 46 +++++++++++++++++++++++++++++------------- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/include/polarssl/rsa.h b/include/polarssl/rsa.h index 4e85ca6cc..71fbff2d8 100644 --- a/include/polarssl/rsa.h +++ b/include/polarssl/rsa.h @@ -89,6 +89,11 @@ typedef struct mpi RP; /*!< cached R^2 mod P */ mpi RQ; /*!< cached R^2 mod Q */ +#if !defined(POLARSSL_RSA_NO_CRT) + mpi Vi; /*!< cached blinding value */ + mpi Vf; /*!< cached un-blinding value */ +#endif + int padding; /*!< RSA_PKCS_V15 for 1.5 padding and RSA_PKCS_v21 for OAEP/PSS */ int hash_id; /*!< Hash identifier of md_type_t as diff --git a/library/rsa.c b/library/rsa.c index c39a338a3..0a943c234 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -253,6 +253,27 @@ cleanup: return( 0 ); } +#if !defined(POLARSSL_RSA_NO_CRT) +/* + * Generate blinding values + */ +static int rsa_prepare_blinding( rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + + /* Unblinding value: Vf = random number */ + MPI_CHK( mpi_fill_random( &ctx->Vf, ctx->len - 1, f_rng, p_rng ) ); + + /* Blinding value: Vi = Vf^(-e) mod N */ + MPI_CHK( mpi_inv_mod( &ctx->Vi, &ctx->Vf, &ctx->N ) ); + MPI_CHK( mpi_exp_mod( &ctx->Vi, &ctx->Vi, &ctx->E, &ctx->N, &ctx->RN ) ); + +cleanup: + return( ret ); +} +#endif + /* * Do an RSA private key operation */ @@ -265,11 +286,8 @@ int rsa_private( rsa_context *ctx, int ret; size_t olen; mpi T, T1, T2; - mpi A, X; - mpi_init( &T ); mpi_init( &T1 ); mpi_init( &T2 ); - mpi_init( &A ); mpi_init( &X ); MPI_CHK( mpi_read_binary( &T, input, ctx->len ) ); if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) @@ -284,14 +302,12 @@ int rsa_private( rsa_context *ctx, if( f_rng != NULL ) { /* - * RSA Blinding - * A = rnd MPI - * T = A^E * T mod N + * Blinding + * T = T * Vi mod N */ - MPI_CHK( mpi_fill_random( &A, ctx->len - 1, f_rng, p_rng ) ); - MPI_CHK( mpi_exp_mod( &X, &A, &ctx->E, &ctx->N, NULL ) ); - MPI_CHK( mpi_mul_mpi( &X, &X, &T ) ); - MPI_CHK( mpi_mod_mpi( &T, &X, &ctx->N ) ); + MPI_CHK( rsa_prepare_blinding( ctx, f_rng, p_rng ) ); + MPI_CHK( mpi_mul_mpi( &T, &T, &ctx->Vi ) ); + MPI_CHK( mpi_mod_mpi( &T, &T, &ctx->N ) ); } /* @@ -320,10 +336,9 @@ int rsa_private( rsa_context *ctx, { /* * Unblind - * T = T / A mod N + * T = T * Vf mod N */ - MPI_CHK( mpi_inv_mod( &A, &A, &ctx->N ) ); - MPI_CHK( mpi_mul_mpi( &T, &T, &A ) ); + MPI_CHK( mpi_mul_mpi( &T, &T, &ctx->Vf ) ); MPI_CHK( mpi_mod_mpi( &T, &T, &ctx->N ) ); } #endif @@ -334,7 +349,6 @@ int rsa_private( rsa_context *ctx, cleanup: mpi_free( &T ); mpi_free( &T1 ); mpi_free( &T2 ); - mpi_free( &A ); mpi_free( &X ); if( ret != 0 ) return( POLARSSL_ERR_RSA_PRIVATE_FAILED + ret ); @@ -1280,6 +1294,9 @@ int rsa_copy( rsa_context *dst, const rsa_context *src ) MPI_CHK( mpi_copy( &dst->RP, &src->RP ) ); MPI_CHK( mpi_copy( &dst->RQ, &src->RQ ) ); + MPI_CHK( mpi_copy( &dst->Vi, &src->Vi ) ); + MPI_CHK( mpi_copy( &dst->Vf, &src->Vf ) ); + dst->padding = src->padding; dst->hash_id = src->padding; @@ -1295,6 +1312,7 @@ cleanup: */ void rsa_free( rsa_context *ctx ) { + mpi_free( &ctx->Vi ); mpi_free( &ctx->Vf ); mpi_free( &ctx->RQ ); mpi_free( &ctx->RP ); mpi_free( &ctx->RN ); mpi_free( &ctx->QP ); mpi_free( &ctx->DQ ); mpi_free( &ctx->DP ); mpi_free( &ctx->Q ); mpi_free( &ctx->P ); mpi_free( &ctx->D ); From 8a109f106daa46bc6bd38656e0ed504052a5bd9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 10 Sep 2013 13:37:26 +0200 Subject: [PATCH 13/13] Optimize RSA blinding by caching-updating values --- library/rsa.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/library/rsa.c b/library/rsa.c index 0a943c234..c82ffaa8a 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -255,13 +255,27 @@ cleanup: #if !defined(POLARSSL_RSA_NO_CRT) /* - * Generate blinding values + * Generate or update blinding values, see section 10 of: + * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA, + * DSS, and other systems. In : Advances in Cryptology—CRYPTO’96. Springer + * Berlin Heidelberg, 1996. p. 104-113. */ static int rsa_prepare_blinding( rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret; + if( ctx->Vf.p != NULL ) + { + /* We already have blinding values, just update them by squaring */ + MPI_CHK( mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) ); + MPI_CHK( mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->P ) ); + MPI_CHK( mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) ); + MPI_CHK( mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) ); + + return( 0 ); + } + /* Unblinding value: Vf = random number */ MPI_CHK( mpi_fill_random( &ctx->Vf, ctx->len - 1, f_rng, p_rng ) );