1
0
mirror of https://github.com/Mbed-TLS/mbedtls.git synced 2025-08-08 17:42:09 +03:00

Merged blinding additions for EC, RSA and DHM into development

This commit is contained in:
Paul Bakker
2013-09-10 14:44:27 +02:00
20 changed files with 527 additions and 117 deletions

View File

@@ -245,28 +245,113 @@ 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—CRYPTO96. 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;
/*
* If Vi is initialized, update it by squaring it
*/
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_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) );
return( 0 );
}
/*
* Otherwise, compute Vf from scratch
*/
/* 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
*/
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;
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 != NULL )
{
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 != NULL )
{
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 );
@@ -279,6 +364,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 );

View File

@@ -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 );

View File

@@ -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 ) )
@@ -217,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,

View File

@@ -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.
* <http://rd.springer.com/chapter/10.1007/3-540-36563-X_23>.
*
* [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.
* <http://link.springer.com/chapter/10.1007/3-540-48059-5_25>
*/
#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 <http://rd.springer.com/chapter/10.1007/3-540-36563-X_23>.
* (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,14 +1214,19 @@ cleanup:
/*
* Integer multiplication: R = m * P
*
* Based on fixed-pattern width-w NAF, see comments of ecp_w_naf_fixed()
* and <http://rd.springer.com/chapter/10.1007/3-540-36563-X_23>.
* 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 )
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;
@@ -1176,17 +1236,17 @@ int ecp_mul( const ecp_group *grp, ecp_point *R,
mpi M;
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;
@@ -1237,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--;
@@ -1348,7 +1412,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 +1466,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 +1481,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 )
{

View File

@@ -253,6 +253,41 @@ cleanup:
return( 0 );
}
#if !defined(POLARSSL_RSA_NO_CRT)
/*
* 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—CRYPTO96. 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 ) );
/* 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 +300,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 +316,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 +350,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 +363,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 +1308,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 +1326,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 );

View File

@@ -1711,9 +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 ) ) != 0 )
&ssl->handshake->pmslen,
NULL, NULL ) ) != 0 )
{
SSL_DEBUG_RET( 1, "dhm_calc_secret", ret );
return( ret );
@@ -1748,7 +1750,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 );
@@ -1840,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 ) ) != 0 )
p, &n, NULL, NULL ) ) != 0 )
{
SSL_DEBUG_RET( 1, "dhm_calc_secret", ret );
return( ret );

View File

@@ -2384,9 +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 ) ) != 0 )
&ssl->handshake->pmslen,
NULL, NULL ) ) != 0 )
{
SSL_DEBUG_RET( 1, "dhm_calc_secret", ret );
return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS );
@@ -2410,7 +2412,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 );
@@ -2470,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 ) ) != 0 )
p, &n, NULL, NULL ) ) != 0 )
{
SSL_DEBUG_RET( 1, "dhm_calc_secret", ret );
return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS );