diff --git a/ChangeLog b/ChangeLog index 27a6eab78..84115d495 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,7 @@ Features * EC key generation support in gen_key app * Support for adhering to client ciphersuite order preference (POLARSSL_SSL_SRV_RESPECT_CLIENT_PREFERENCE) + * Support for Curve25519 Changes * gen_prime() speedup @@ -15,6 +16,7 @@ Changes * Split off curves from ecp.c into ecp_curves.c Bugfix + * Fixed bug in mpi_set_bit() on platforms where t_uint is wider than int * Fixed X.509 hostname comparison (with non-regular characters) * SSL now gracefully handles missing RNG * Missing defines / cases for RSA_PSK key exchange diff --git a/include/polarssl/bignum.h b/include/polarssl/bignum.h index d98dce9c4..df17b129b 100644 --- a/include/polarssl/bignum.h +++ b/include/polarssl/bignum.h @@ -236,11 +236,10 @@ void mpi_swap( mpi *X, mpi *Y ); * * \param X MPI to conditionally assign to * \param Y Value to be assigned - * \param assign 1: perform the assignment, 0: leave X untouched + * \param assign 1: perform the assignment, 0: keep X's original value * * \return 0 if successful, * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, - * POLARSSL_ERR_MPI_BAD_INPUT_DATA if assing is not 0 or 1 * * \note This function is equivalent to * if( assign ) mpi_copy( X, Y ); @@ -251,6 +250,25 @@ void mpi_swap( mpi *X, mpi *Y ); */ int mpi_safe_cond_assign( mpi *X, const mpi *Y, unsigned char assign ); +/** + * \brief Safe conditional swap X <-> Y if swap is 1 + * + * \param X First mpi value + * \param Y Second mpi value + * \param assign 1: perform the swap, 0: keep X and Y's original values + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * + * \note This function is equivalent to + * if( assign ) mpi_swap( 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 and/or memory access + * patterns analysis). + */ +int mpi_safe_cond_swap( mpi *X, mpi *Y, unsigned char assign ); + /** * \brief Set value from integer * diff --git a/include/polarssl/config.h b/include/polarssl/config.h index bdd40af15..0b76f0853 100644 --- a/include/polarssl/config.h +++ b/include/polarssl/config.h @@ -248,6 +248,10 @@ #define POLARSSL_ECP_DP_BP256R1_ENABLED #define POLARSSL_ECP_DP_BP384R1_ENABLED #define POLARSSL_ECP_DP_BP512R1_ENABLED +//#define POLARSSL_ECP_DP_M221_ENABLED // Not implemented yet! +#define POLARSSL_ECP_DP_M255_ENABLED +//#define POLARSSL_ECP_DP_M383_ENABLED // Not implemented yet! +//#define POLARSSL_ECP_DP_M511_ENABLED // Not implemented yet! /** * \def POLARSSL_ECP_NIST_OPTIM diff --git a/include/polarssl/ecp.h b/include/polarssl/ecp.h index c0f50791d..a1a37af24 100644 --- a/include/polarssl/ecp.h +++ b/include/polarssl/ecp.h @@ -64,10 +64,16 @@ typedef enum POLARSSL_ECP_DP_BP256R1, /*!< 256-bits Brainpool curve */ POLARSSL_ECP_DP_BP384R1, /*!< 384-bits Brainpool curve */ POLARSSL_ECP_DP_BP512R1, /*!< 512-bits Brainpool curve */ + POLARSSL_ECP_DP_M221, /*!< (not implemented yet) */ + POLARSSL_ECP_DP_M255, /*!< Curve25519 */ + POLARSSL_ECP_DP_M383, /*!< (not implemented yet) */ + POLARSSL_ECP_DP_M511, /*!< (not implemented yet) */ } ecp_group_id; /** - * Number of supported curves (plus one for NONE) + * Number of supported curves (plus one for NONE). + * + * (Montgomery curves excluded for now.) */ #define POLARSSL_ECP_DP_MAX 9 @@ -102,10 +108,16 @@ ecp_point; /** * \brief ECP group structure * - * The curves we consider are defined by y^2 = x^3 + A x + B mod P, - * and a generator for a large subgroup of order N is fixed. + * We consider two types of curves equations: + * 1. Short Weierstrass y^2 = x^3 + A x + B mod P (SEC1 + RFC 4492) + * 2. Montgomery, y^2 = x^3 + A x^2 + x mod P (M255 + draft) + * In both cases, a generator G for a prime-order subgroup is fixed. In the + * short weierstrass, this subgroup is actually the whole curve, and its + * cardinal is denoted by N. * - * pbits and nbits must be the size of P and N in bits. + * In the case of Montgomery curves, we don't store A but (A + 2) / 4 which is + * the quantity actualy used in the formulas. Also, nbits is not the size of N + * but the required size for private keys. * * If modp is NULL, reduction modulo P is done using a generic algorithm. * Otherwise, it must point to a function that takes an mpi in the range @@ -118,18 +130,18 @@ typedef struct { ecp_group_id id; /*!< internal group identifier */ mpi P; /*!< prime modulus of the base field */ - mpi A; /*!< linear term in the equation */ - mpi B; /*!< constant term in the equation */ - ecp_point G; /*!< generator of the subgroup used */ - mpi N; /*!< the order of G */ + mpi A; /*!< 1. A in the equation, or 2. (A + 2) / 4 */ + mpi B; /*!< 1. B in the equation, or 2. unused */ + ecp_point G; /*!< generator of the (sub)group used */ + mpi N; /*!< 1. the order of G, or 2. unused */ size_t pbits; /*!< number of bits in P */ - size_t nbits; /*!< number of bits in N */ - unsigned int h; /*!< cofactor (unused now: assume 1) */ + size_t nbits; /*!< number of bits in 1. P, or 2. private keys */ + unsigned int h; /*!< unused */ int (*modp)(mpi *); /*!< function for fast reduction mod P */ - int (*t_pre)(ecp_point *, void *); /*!< currently unused */ - int (*t_post)(ecp_point *, void *); /*!< currently unused */ - void *t_data; /*!< currently unused */ - ecp_point *T; /*!< pre-computed points for ecp_mul() */ + int (*t_pre)(ecp_point *, void *); /*!< unused */ + int (*t_post)(ecp_point *, void *); /*!< unused */ + void *t_data; /*!< unused */ + ecp_point *T; /*!< pre-computed points for ecp_mul_comb() */ size_t T_size; /*!< number for pre-computed points */ } ecp_group; @@ -438,6 +450,9 @@ int ecp_tls_write_group( const ecp_group *grp, size_t *olen, * * \return 0 if successful, * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + * + * \note This function does not support Montgomery curves, such as + * Curve25519. */ int ecp_add( const ecp_group *grp, ecp_point *R, const ecp_point *P, const ecp_point *Q ); @@ -452,6 +467,9 @@ int ecp_add( const ecp_group *grp, ecp_point *R, * * \return 0 if successful, * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + * + * \note This function does not support Montgomery curves, such as + * Curve25519. */ int ecp_sub( const ecp_group *grp, ecp_point *R, const ecp_point *P, const ecp_point *Q ); diff --git a/library/bignum.c b/library/bignum.c index 945da17b8..dd5c0bfdd 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -214,16 +214,16 @@ int mpi_safe_cond_assign( mpi *X, const mpi *Y, unsigned char assign ) int ret = 0; size_t i; - if( assign * ( 1 - assign ) != 0 ) - return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + /* make sure assign is 0 or 1 */ + assign = ( assign != 0 ); - if( Y->n > X->n ) - MPI_CHK( mpi_grow( X, Y->n ) ); + MPI_CHK( mpi_grow( X, Y->n ) ); - /* Do the conditional assign safely */ X->s = X->s * (1 - assign) + Y->s * assign; + for( i = 0; i < Y->n; i++ ) X->p[i] = X->p[i] * (1 - assign) + Y->p[i] * assign; + for( ; i < X->n; i++ ) X->p[i] *= (1 - assign); @@ -231,6 +231,43 @@ cleanup: return( ret ); } +/* + * Conditionally swap X and Y, without leaking information + * about whether the swap was made or not. + * Here it is not ok to simply swap the pointers, which whould lead to + * different memory access patterns when X and Y are used afterwards. + */ +int mpi_safe_cond_swap( mpi *X, mpi *Y, unsigned char swap ) +{ + int ret, s; + size_t i; + t_uint tmp; + + if( X == Y ) + return( 0 ); + + /* make sure swap is 0 or 1 */ + swap = ( swap != 0 ); + + MPI_CHK( mpi_grow( X, Y->n ) ); + MPI_CHK( mpi_grow( Y, X->n ) ); + + s = X->s; + X->s = X->s * (1 - swap) + Y->s * swap; + Y->s = Y->s * (1 - swap) + s * swap; + + + for( i = 0; i < X->n; i++ ) + { + tmp = X->p[i]; + X->p[i] = X->p[i] * (1 - swap) + Y->p[i] * swap; + Y->p[i] = Y->p[i] * (1 - swap) + tmp * swap; + } + +cleanup: + return( ret ); +} + /* * Set value from integer */ @@ -280,7 +317,8 @@ int mpi_set_bit( mpi *X, size_t pos, unsigned char val ) MPI_CHK( mpi_grow( X, off + 1 ) ); } - X->p[off] = ( X->p[off] & ~( 0x01 << idx ) ) | ( val << idx ); + X->p[off] &= ~( (t_uint) 0x01 << idx ); + X->p[off] |= (t_uint) val << idx; cleanup: diff --git a/library/ecdsa.c b/library/ecdsa.c index 13f394bc8..2072d5559 100644 --- a/library/ecdsa.c +++ b/library/ecdsa.c @@ -59,6 +59,10 @@ int ecdsa_sign( ecp_group *grp, mpi *r, mpi *s, ecp_point R; mpi k, e; + /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ + if( grp->N.p == NULL ) + return( POLARSSL_ERR_ECP_BAD_INPUT_DATA ); + ecp_point_init( &R ); mpi_init( &k ); mpi_init( &e ); @@ -129,6 +133,10 @@ int ecdsa_verify( ecp_group *grp, ecp_point_init( &R ); ecp_point_init( &P ); mpi_init( &e ); mpi_init( &s_inv ); mpi_init( &u1 ); mpi_init( &u2 ); + /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ + if( grp->N.p == NULL ) + return( POLARSSL_ERR_ECP_BAD_INPUT_DATA ); + /* * Step 1: make sure r and s are in range 1..n-1 */ diff --git a/library/ecp.c b/library/ecp.c index 8338b2c6a..02f1b61d7 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -31,6 +31,8 @@ * FIPS 186-3 http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf * RFC 4492 for the related TLS structures and constants * + * [M255] http://cr.yp.to/ecdh/curve25519-20060209.pdf + * * [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. @@ -78,6 +80,34 @@ static unsigned long add_count, dbl_count, mul_count; #endif +#if defined(POLARSSL_ECP_DP_SECP192R1_ENABLED) || \ + defined(POLARSSL_ECP_DP_SECP224R1_ENABLED) || \ + defined(POLARSSL_ECP_DP_SECP256R1_ENABLED) || \ + defined(POLARSSL_ECP_DP_SECP384R1_ENABLED) || \ + defined(POLARSSL_ECP_DP_SECP521R1_ENABLED) || \ + defined(POLARSSL_ECP_DP_BP256R1_ENABLED) || \ + defined(POLARSSL_ECP_DP_BP384R1_ENABLED) || \ + defined(POLARSSL_ECP_DP_BP512R1_ENABLED) +#define POLARSSL_ECP_SHORT_WEIERSTRASS +#endif + +#if defined(POLARSSL_ECP_DP_M221_ENABLED) || \ + defined(POLARSSL_ECP_DP_M255_ENABLED) || \ + defined(POLARSSL_ECP_DP_M383_ENABLED) || \ + defined(POLARSSL_ECP_DP_M511_ENABLED) +#define POLARSSL_ECP_MONTGOMERY +#endif + +/* + * Curve types: internal for now, might be exposed later + */ +typedef enum +{ + POLARSSL_ECP_TYPE_NONE = 0, + POLARSSL_ECP_TYPE_SHORT_WEIERSTRASS, /* y^2 = x^3 + a x + b */ + POLARSSL_ECP_TYPE_MONTGOMERY, /* y^2 = x^3 + a x^2 + x */ +} ecp_curve_type; + /* * List of supported curves: * - internal ID @@ -176,6 +206,20 @@ const ecp_curve_info *ecp_curve_info_from_name( const char *name ) return( NULL ); } +/* + * Get the type of a curve + */ +static inline ecp_curve_type ecp_get_type( const ecp_group *grp ) +{ + if( grp->G.X.p == NULL ) + return( POLARSSL_ECP_TYPE_NONE ); + + if( grp->G.Y.p == NULL ) + return( POLARSSL_ECP_TYPE_MONTGOMERY ); + else + return( POLARSSL_ECP_TYPE_SHORT_WEIERSTRASS ); +} + /* * Initialize (the components of) a point */ @@ -632,11 +676,20 @@ cleanup: while( mpi_cmp_mpi( &N, &grp->P ) >= 0 ) \ MPI_CHK( mpi_sub_abs( &N, &N, &grp->P ) ) +#if defined(POLARSSL_ECP_SHORT_WEIERSTRASS) +/* + * For curves in short Weierstrass form, we do all the internal operations in + * Jacobian coordinates. + * + * For multiplication, we'll use a comb method with coutermeasueres against + * SPA, hence timing attacks. + */ + /* * Normalize jacobian coordinates so that Z == 0 || Z == 1 (GECC 3.2.1) * Cost: 1N := 1I + 3M + 1S */ -static int ecp_normalize( const ecp_group *grp, ecp_point *pt ) +static int ecp_normalize_jac( const ecp_group *grp, ecp_point *pt ) { int ret; mpi Zi, ZZi; @@ -678,19 +731,19 @@ cleanup: * Theory", Algorithm 10.3.4.) * * Warning: fails (returning an error) if one of the points is zero! - * This should never happen, see choice of w in ecp_mul(). + * This should never happen, see choice of w in ecp_mul_comb(). * * Cost: 1N(t) := 1I + (6t - 3)M + 1S */ -static int ecp_normalize_many( const ecp_group *grp, - ecp_point *T[], size_t t_len ) +static int ecp_normalize_jac_many( const ecp_group *grp, + ecp_point *T[], size_t t_len ) { int ret; size_t i; mpi *c, u, Zi, ZZi; if( t_len < 2 ) - return( ecp_normalize( grp, *T ) ); + return( ecp_normalize_jac( grp, *T ) ); if( ( c = (mpi *) polarssl_malloc( t_len * sizeof( mpi ) ) ) == NULL ) return( POLARSSL_ERR_ECP_MALLOC_FAILED ); @@ -756,7 +809,7 @@ cleanup: * Conditional point inversion: Q -> -Q = (Q.X, -Q.Y, Q.Z) without leak. * "inv" must be 0 (don't invert) or 1 (invert) or the result will be invalid */ -static int ecp_safe_invert( const ecp_group *grp, +static int ecp_safe_invert_jac( const ecp_group *grp, ecp_point *Q, unsigned char inv ) { @@ -843,7 +896,7 @@ cleanup: * but those of P don't need to. R is not normalized. * * Special cases: (1) P or Q is zero, (2) R is zero, (3) P == Q. - * None of these cases can happen as intermediate step in ecp_mul(): + * None of these cases can happen as intermediate step in ecp_mul_comb(): * - at each step, P, Q and R are multiples of the base point, the factor * being less than its order, so none of them is zero; * - Q is an odd multiple of the base point, P an even multiple, @@ -929,15 +982,17 @@ cleanup: /* * Addition: R = P + Q, result's coordinates normalized - * Cost: 1A + 1N = 1I + 11M + 4S */ int ecp_add( const ecp_group *grp, ecp_point *R, const ecp_point *P, const ecp_point *Q ) { int ret; + if( ecp_get_type( grp ) != POLARSSL_ECP_TYPE_SHORT_WEIERSTRASS ) + return( POLARSSL_ERR_ECP_FEATURE_UNAVAILABLE ); + MPI_CHK( ecp_add_mixed( grp, R, P, Q ) ); - MPI_CHK( ecp_normalize( grp, R ) ); + MPI_CHK( ecp_normalize_jac( grp, R ) ); cleanup: return( ret ); @@ -945,7 +1000,6 @@ cleanup: /* * Subtraction: R = P - Q, result's coordinates normalized - * Cost: 1A + 1N = 1I + 11M + 4S */ int ecp_sub( const ecp_group *grp, ecp_point *R, const ecp_point *P, const ecp_point *Q ) @@ -955,13 +1009,16 @@ int ecp_sub( const ecp_group *grp, ecp_point *R, ecp_point_init( &mQ ); + if( ecp_get_type( grp ) != POLARSSL_ECP_TYPE_SHORT_WEIERSTRASS ) + return( POLARSSL_ERR_ECP_FEATURE_UNAVAILABLE ); + /* mQ = - Q */ ecp_copy( &mQ, Q ); if( mpi_cmp_int( &mQ.Y, 0 ) != 0 ) MPI_CHK( mpi_sub_mpi( &mQ.Y, &grp->P, &mQ.Y ) ); MPI_CHK( ecp_add_mixed( grp, R, P, &mQ ) ); - MPI_CHK( ecp_normalize( grp, R ) ); + MPI_CHK( ecp_normalize_jac( grp, R ) ); cleanup: ecp_point_free( &mQ ); @@ -972,11 +1029,11 @@ cleanup: /* * 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(). + * This is sort of the reverse operation of ecp_normalize_jac(). * * This countermeasure was first suggested in [2]. */ -static int ecp_randomize_coordinates( const ecp_group *grp, ecp_point *pt, +static int ecp_randomize_jac( const ecp_group *grp, ecp_point *pt, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret; @@ -1115,7 +1172,7 @@ static int ecp_precompute_comb( const ecp_group *grp, TT[k++] = cur; } - ecp_normalize_many( grp, TT, k ); + ecp_normalize_jac_many( grp, TT, k ); /* * Compute the remaining ones using the minimal number of additions @@ -1132,7 +1189,7 @@ static int ecp_precompute_comb( const ecp_group *grp, } } - ecp_normalize_many( grp, TT, k ); + ecp_normalize_jac_many( grp, TT, k ); /* * Post-precessing: reclaim some memory by @@ -1175,7 +1232,7 @@ static int ecp_select_comb( const ecp_group *grp, ecp_point *R, MPI_CHK( mpi_lset( &R->Z, 1 ) ); /* Safely invert result if i is "negative" */ - MPI_CHK( ecp_safe_invert( grp, R, i >> 7 ) ); + MPI_CHK( ecp_safe_invert_jac( grp, R, i >> 7 ) ); cleanup: return( ret ); @@ -1203,7 +1260,7 @@ static int ecp_mul_comb_core( const ecp_group *grp, ecp_point *R, i = d; 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 ) ); + MPI_CHK( ecp_randomize_jac( grp, R, f_rng, p_rng ) ); while( i-- != 0 ) { @@ -1219,11 +1276,13 @@ cleanup: } /* - * Multiplication using the comb method + * Multiplication using the comb method, + * for curves in short Weierstrass form */ -int ecp_mul( ecp_group *grp, ecp_point *R, - const mpi *m, const ecp_point *P, - int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +static int ecp_mul_comb( ecp_group *grp, ecp_point *R, + 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, p_eq_g, pre_len, i; @@ -1232,28 +1291,13 @@ int ecp_mul( ecp_group *grp, ecp_point *R, ecp_point *T; mpi M, mm; - /* - * Sanity checks (before we even initialize anything) - */ - if( mpi_cmp_int( &P->Z, 1 ) != 0 || - mpi_get_bit( &grp->N, 0 ) != 1 ) - { - return( POLARSSL_ERR_ECP_BAD_INPUT_DATA ); - } - - if( ( ret = ecp_check_privkey( grp, m ) ) != 0 ) - return( ret ); - - /* We'll need this later, but do it now to possibly avoid checking P */ - p_eq_g = ( mpi_cmp_mpi( &P->Y, &grp->G.Y ) == 0 && - mpi_cmp_mpi( &P->X, &grp->G.X ) == 0 ); - - if( ! p_eq_g && ( ret = ecp_check_pubkey( grp, P ) ) != 0 ) - return( ret ); - mpi_init( &M ); mpi_init( &mm ); + /* we need N to be odd to trnaform m in an odd number, check now */ + if( mpi_get_bit( &grp->N, 0 ) != 1 ) + return( POLARSSL_ERR_ECP_BAD_INPUT_DATA ); + /* * Minimize the number of multiplications, that is minimize * 10 * d * w + 18 * 2^(w-1) + 11 * d + 7 * w, with d = ceil( nbits / w ) @@ -1265,6 +1309,8 @@ int ecp_mul( ecp_group *grp, ecp_point *R, * If P == G, pre-compute a bit more, since this may be re-used later. * Just adding one ups the cost of the first mul by at most 3%. */ + p_eq_g = ( mpi_cmp_mpi( &P->Y, &grp->G.Y ) == 0 && + mpi_cmp_mpi( &P->X, &grp->G.X ) == 0 ); if( p_eq_g ) w++; @@ -1326,8 +1372,8 @@ int ecp_mul( ecp_group *grp, ecp_point *R, /* * Now get m * P from M * P and normalize it */ - MPI_CHK( ecp_safe_invert( grp, R, ! m_is_odd ) ); - MPI_CHK( ecp_normalize( grp, R ) ); + MPI_CHK( ecp_safe_invert_jac( grp, R, ! m_is_odd ) ); + MPI_CHK( ecp_normalize_jac( grp, R ) ); cleanup: @@ -1347,23 +1393,228 @@ cleanup: return( ret ); } +#endif /* POLARSSL_ECP_SHORT_WEIERSTRASS */ + +#if defined(POLARSSL_ECP_MONTGOMERY) /* - * Check that a point is valid as a public key (SEC1 3.2.3.1) + * For Montgomery curves, we do all the internal arithmetic in projective + * coordinates. Import/export of points uses only the x coordinates, which is + * internaly represented as X / Z. + * + * For scalar multiplication, we'll use a Montgomery ladder. */ -int ecp_check_pubkey( const ecp_group *grp, const ecp_point *pt ) + +/* + * Normalize Montgomery x/z coordinates: X = X/Z, Z = 1 + * Cost: 1M + 1I + */ +static int ecp_normalize_mxz( const ecp_group *grp, ecp_point *P ) +{ + int ret; + + MPI_CHK( mpi_inv_mod( &P->Z, &P->Z, &grp->P ) ); + MPI_CHK( mpi_mul_mpi( &P->X, &P->X, &P->Z ) ); MOD_MUL( P->X ); + MPI_CHK( mpi_lset( &P->Z, 1 ) ); + +cleanup: + return( ret ); +} + +/* + * Randomize projective x/z coordinates: + * (X, Z) -> (l X, l Z) for random l + * This is sort of the reverse operation of ecp_normalize_mxz(). + * + * This countermeasure was first suggested in [2]. + * Cost: 2M + */ +static int ecp_randomize_mxz( const ecp_group *grp, ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + mpi l; + size_t p_size = (grp->pbits + 7) / 8; + int count = 0; + + mpi_init( &l ); + + /* 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_RANDOM_FAILED ); + } + while( mpi_cmp_int( &l, 1 ) <= 0 ); + + MPI_CHK( mpi_mul_mpi( &P->X, &P->X, &l ) ); MOD_MUL( P->X ); + MPI_CHK( mpi_mul_mpi( &P->Z, &P->Z, &l ) ); MOD_MUL( P->Z ); + +cleanup: + mpi_free( &l ); + + return( ret ); +} + +/* + * Double-and-add: R = 2P, S = P + Q, with d = X(P - Q), + * for Montgomery curves in x/z coordinates. + * + * http://www.hyperelliptic.org/EFD/g1p/auto-code/montgom/xz/ladder/mladd-1987-m.op3 + * with + * d = X1 + * P = (X2, Z2) + * Q = (X3, Z3) + * R = (X4, Z4) + * S = (X5, Z5) + * and eliminating temporary variables tO, ..., t4. + * + * Cost: 5M + 4S + */ +static int ecp_double_add_mxz( const ecp_group *grp, + ecp_point *R, ecp_point *S, + const ecp_point *P, const ecp_point *Q, + const mpi *d ) +{ + int ret; + mpi A, AA, B, BB, E, C, D, DA, CB; + + mpi_init( &A ); mpi_init( &AA ); mpi_init( &B ); + mpi_init( &BB ); mpi_init( &E ); mpi_init( &C ); + mpi_init( &D ); mpi_init( &DA ); mpi_init( &CB ); + + MPI_CHK( mpi_add_mpi( &A, &P->X, &P->Z ) ); MOD_ADD( A ); + MPI_CHK( mpi_mul_mpi( &AA, &A, &A ) ); MOD_MUL( AA ); + MPI_CHK( mpi_sub_mpi( &B, &P->X, &P->Z ) ); MOD_SUB( B ); + MPI_CHK( mpi_mul_mpi( &BB, &B, &B ) ); MOD_MUL( BB ); + MPI_CHK( mpi_sub_mpi( &E, &AA, &BB ) ); MOD_SUB( E ); + MPI_CHK( mpi_add_mpi( &C, &Q->X, &Q->Z ) ); MOD_ADD( C ); + MPI_CHK( mpi_sub_mpi( &D, &Q->X, &Q->Z ) ); MOD_SUB( D ); + MPI_CHK( mpi_mul_mpi( &DA, &D, &A ) ); MOD_MUL( DA ); + MPI_CHK( mpi_mul_mpi( &CB, &C, &B ) ); MOD_MUL( CB ); + MPI_CHK( mpi_add_mpi( &S->X, &DA, &CB ) ); MOD_MUL( S->X ); + MPI_CHK( mpi_mul_mpi( &S->X, &S->X, &S->X ) ); MOD_MUL( S->X ); + MPI_CHK( mpi_sub_mpi( &S->Z, &DA, &CB ) ); MOD_SUB( S->Z ); + MPI_CHK( mpi_mul_mpi( &S->Z, &S->Z, &S->Z ) ); MOD_MUL( S->Z ); + MPI_CHK( mpi_mul_mpi( &S->Z, d, &S->Z ) ); MOD_MUL( S->Z ); + MPI_CHK( mpi_mul_mpi( &R->X, &AA, &BB ) ); MOD_MUL( R->X ); + MPI_CHK( mpi_mul_mpi( &R->Z, &grp->A, &E ) ); MOD_MUL( R->Z ); + MPI_CHK( mpi_add_mpi( &R->Z, &BB, &R->Z ) ); MOD_ADD( R->Z ); + MPI_CHK( mpi_mul_mpi( &R->Z, &E, &R->Z ) ); MOD_MUL( R->Z ); + +cleanup: + mpi_free( &A ); mpi_free( &AA ); mpi_free( &B ); + mpi_free( &BB ); mpi_free( &E ); mpi_free( &C ); + mpi_free( &D ); mpi_free( &DA ); mpi_free( &CB ); + + return( ret ); +} + +/* + * Multiplication with Montgomery ladder in x/z coordinates, + * for curves in Montgomery form + */ +static int ecp_mul_mxz( ecp_group *grp, ecp_point *R, + const mpi *m, const ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t i; + unsigned char b; + ecp_point RP; + mpi PX; + + ecp_point_init( &RP ); mpi_init( &PX ); + + /* Save PX and read from P before writing to R, in case P == R */ + mpi_copy( &PX, &P->X ); + MPI_CHK( ecp_copy( &RP, P ) ); + + /* Set R to zero in modified x/z coordinates */ + MPI_CHK( mpi_lset( &R->X, 1 ) ); + MPI_CHK( mpi_lset( &R->Z, 0 ) ); + mpi_free( &R->Y ); + + /* RP.X might be sligtly larger than P, so reduce it */ + MOD_ADD( RP.X ); + + /* Randomize coordinates of the starting point */ + if( f_rng != NULL ) + MPI_CHK( ecp_randomize_mxz( grp, &RP, f_rng, p_rng ) ); + + /* Loop invariant: R = result so far, RP = R + P */ + i = mpi_msb( m ); /* one past the (zero-based) most significant bit */ + while( i-- > 0 ) + { + b = mpi_get_bit( m, i ); + /* + * if (b) R = 2R + P else R = 2R, + * which is: + * if (b) double_add( RP, R, RP, R ) + * else double_add( R, RP, R, RP ) + * but using safe conditional swaps to avoid leaks + */ + MPI_CHK( mpi_safe_cond_swap( &R->X, &RP.X, b ) ); + MPI_CHK( mpi_safe_cond_swap( &R->Z, &RP.Z, b ) ); + MPI_CHK( ecp_double_add_mxz( grp, R, &RP, R, &RP, &PX ) ); + MPI_CHK( mpi_safe_cond_swap( &R->X, &RP.X, b ) ); + MPI_CHK( mpi_safe_cond_swap( &R->Z, &RP.Z, b ) ); + } + + MPI_CHK( ecp_normalize_mxz( grp, R ) ); + +cleanup: + ecp_point_free( &RP ); mpi_free( &PX ); + + return( ret ); +} + +#endif /* POLARSSL_ECP_MONTGOMERY */ + +/* + * Multiplication R = m * P + */ +int ecp_mul( ecp_group *grp, ecp_point *R, + const mpi *m, const ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + + /* Common sanity checks */ + if( mpi_cmp_int( &P->Z, 1 ) != 0 ) + return( POLARSSL_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = ecp_check_privkey( grp, m ) ) != 0 || + ( ret = ecp_check_pubkey( grp, P ) ) != 0 ) + return( ret ); + +#if defined(POLARSSL_ECP_MONTGOMERY) + if( ecp_get_type( grp ) == POLARSSL_ECP_TYPE_MONTGOMERY ) + return( ecp_mul_mxz( grp, R, m, P, f_rng, p_rng ) ); +#endif +#if defined(POLARSSL_ECP_SHORT_WEIERSTRASS) + if( ecp_get_type( grp ) == POLARSSL_ECP_TYPE_SHORT_WEIERSTRASS ) + return( ecp_mul_comb( grp, R, m, P, f_rng, p_rng ) ); +#endif + return( POLARSSL_ERR_ECP_BAD_INPUT_DATA ); +} + +#if defined(POLARSSL_ECP_SHORT_WEIERSTRASS) +/* + * Check that an affine point is valid as a public key, + * short weierstrass curves (SEC1 3.2.3.1) + */ +static int ecp_check_pubkey_sw( const ecp_group *grp, const ecp_point *pt ) { int ret; mpi YY, RHS; - if( mpi_cmp_int( &pt->Z, 0 ) == 0 ) - return( POLARSSL_ERR_ECP_INVALID_KEY ); - - /* - * pt coordinates must be normalized for our checks - */ - if( mpi_cmp_int( &pt->Z, 1 ) != 0 ) - return( POLARSSL_ERR_ECP_INVALID_KEY ); - + /* pt coordinates must be normalized for our checks */ if( mpi_cmp_int( &pt->X, 0 ) < 0 || mpi_cmp_int( &pt->Y, 0 ) < 0 || mpi_cmp_mpi( &pt->X, &grp->P ) >= 0 || @@ -1391,43 +1642,127 @@ cleanup: return( ret ); } +#endif /* POLARSSL_ECP_SHORT_WEIERSTRASS */ + +#if defined(POLARSSL_ECP_MONTGOMERY) /* - * Check that an mpi is valid as a private key (SEC1 3.2) + * Check validity of a public key for Montgomery curves with x-only schemes */ -int ecp_check_privkey( const ecp_group *grp, const mpi *d ) +static int ecp_check_pubkey_mx( const ecp_group *grp, const ecp_point *pt ) { - /* We want 1 <= d <= N-1 */ - if ( mpi_cmp_int( d, 1 ) < 0 || mpi_cmp_mpi( d, &grp->N ) >= 0 ) + /* [M255 p. 5] Just check X is the correct number of bytes */ + if( mpi_size( &pt->X ) > ( grp->nbits + 7 ) / 8 ) return( POLARSSL_ERR_ECP_INVALID_KEY ); return( 0 ); } +#endif /* POLARSSL_ECP_MONTGOMERY */ /* - * Generate a keypair (SEC1 3.2.1) + * Check that a point is valid as a public key + */ +int ecp_check_pubkey( const ecp_group *grp, const ecp_point *pt ) +{ + /* Must use affine coordinates */ + if( mpi_cmp_int( &pt->Z, 1 ) != 0 ) + return( POLARSSL_ERR_ECP_INVALID_KEY ); + +#if defined(POLARSSL_ECP_MONTGOMERY) + if( ecp_get_type( grp ) == POLARSSL_ECP_TYPE_MONTGOMERY ) + return( ecp_check_pubkey_mx( grp, pt ) ); +#endif +#if defined(POLARSSL_ECP_SHORT_WEIERSTRASS) + if( ecp_get_type( grp ) == POLARSSL_ECP_TYPE_SHORT_WEIERSTRASS ) + return( ecp_check_pubkey_sw( grp, pt ) ); +#endif + return( POLARSSL_ERR_ECP_BAD_INPUT_DATA ); +} + +/* + * Check that an mpi is valid as a private key + */ +int ecp_check_privkey( const ecp_group *grp, const mpi *d ) +{ +#if defined(POLARSSL_ECP_MONTGOMERY) + if( ecp_get_type( grp ) == POLARSSL_ECP_TYPE_MONTGOMERY ) + { + /* see [M255] page 5 */ + if( mpi_get_bit( d, 0 ) != 0 || + mpi_get_bit( d, 1 ) != 0 || + mpi_get_bit( d, 2 ) != 0 || + mpi_msb( d ) - 1 != grp->nbits ) /* mpi_msb is one-based! */ + return( POLARSSL_ERR_ECP_INVALID_KEY ); + else + return( 0 ); + } +#endif +#if defined(POLARSSL_ECP_SHORT_WEIERSTRASS) + if( ecp_get_type( grp ) == POLARSSL_ECP_TYPE_SHORT_WEIERSTRASS ) + { + /* see SEC1 3.2 */ + if( mpi_cmp_int( d, 1 ) < 0 || + mpi_cmp_mpi( d, &grp->N ) >= 0 ) + return( POLARSSL_ERR_ECP_INVALID_KEY ); + else + return( 0 ); + } +#endif + + return( POLARSSL_ERR_ECP_BAD_INPUT_DATA ); +} + +/* + * Generate a keypair */ int ecp_gen_keypair( ecp_group *grp, mpi *d, ecp_point *Q, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { - int count = 0; size_t n_size = (grp->nbits + 7) / 8; - /* - * Generate d such that 1 <= n < N - */ - do +#if defined(POLARSSL_ECP_MONTGOMERY) + if( ecp_get_type( grp ) == POLARSSL_ECP_TYPE_MONTGOMERY ) { + /* [M225] page 5 */ + size_t b; + mpi_fill_random( d, n_size, f_rng, p_rng ); - while( mpi_cmp_mpi( d, &grp->N ) >= 0 ) - mpi_shift_r( d, 1 ); + /* Make sure the most significant bit is nbits */ + b = mpi_msb( d ) - 1; /* mpi_msb is one-based */ + if( b > grp->nbits ) + mpi_shift_r( d, b - grp->nbits ); + else + mpi_set_bit( d, grp->nbits, 1 ); - if( count++ > 10 ) - return( POLARSSL_ERR_ECP_RANDOM_FAILED ); + /* Make sure the last three bits are unset */ + mpi_set_bit( d, 0, 0 ); + mpi_set_bit( d, 1, 0 ); + mpi_set_bit( d, 2, 0 ); } - while( mpi_cmp_int( d, 1 ) < 0 ); + else +#endif +#if defined(POLARSSL_ECP_SHORT_WEIERSTRASS) + if( ecp_get_type( grp ) == POLARSSL_ECP_TYPE_SHORT_WEIERSTRASS ) + { + /* SEC1 3.2.1: Generate d such that 1 <= n < N */ + int count = 0; + do + { + mpi_fill_random( d, n_size, f_rng, p_rng ); + + while( mpi_cmp_mpi( d, &grp->N ) >= 0 ) + mpi_shift_r( d, 1 ); + + if( count++ > 10 ) + return( POLARSSL_ERR_ECP_RANDOM_FAILED ); + } + while( mpi_cmp_int( d, 1 ) < 0 ); + } + else +#endif + return( POLARSSL_ERR_ECP_BAD_INPUT_DATA ); return( ecp_mul( grp, Q, d, &grp->G, f_rng, p_rng ) ); } diff --git a/library/ecp_curves.c b/library/ecp_curves.c index d3b1b4de8..26d9e1efd 100644 --- a/library/ecp_curves.c +++ b/library/ecp_curves.c @@ -322,16 +322,29 @@ cleanup: #if defined(POLARSSL_ECP_NIST_OPTIM) /* Forward declarations */ +#if defined(POLARSSL_ECP_DP_SECP192R1_ENABLED) static int ecp_mod_p192( mpi * ); +#endif +#if defined(POLARSSL_ECP_DP_SECP224R1_ENABLED) static int ecp_mod_p224( mpi * ); +#endif +#if defined(POLARSSL_ECP_DP_SECP256R1_ENABLED) static int ecp_mod_p256( mpi * ); +#endif +#if defined(POLARSSL_ECP_DP_SECP384R1_ENABLED) static int ecp_mod_p384( mpi * ); +#endif +#if defined(POLARSSL_ECP_DP_SECP521R1_ENABLED) static int ecp_mod_p521( mpi * ); +#endif +#if defined(POLARSSL_ECP_DP_M255_ENABLED) +static int ecp_mod_p255( mpi * ); +#endif #define NIST_MODP( P ) grp->modp = ecp_mod_ ## P; #else #define NIST_MODP( P ) -#endif +#endif /* POLARSSL_ECP_NIST_OPTIM */ #define LOAD_GROUP( G ) ecp_group_read_binary( grp, \ G ## _p, sizeof( G ## _p ), \ @@ -341,11 +354,45 @@ static int ecp_mod_p521( mpi * ); G ## _gy, sizeof( G ## _gy ), \ G ## _n, sizeof( G ## _n ) ) +/* + * Specialized function for creating the Curve25519 group + */ +static int ecp_use_curve25519( ecp_group *grp ) +{ + int ret; + + /* Actually ( A + 2 ) / 4 */ + MPI_CHK( mpi_read_string( &grp->A, 16, "01DB42" ) ); + + /* P = 2^255 - 19 */ + MPI_CHK( mpi_lset( &grp->P, 1 ) ); + MPI_CHK( mpi_shift_l( &grp->P, 255 ) ); + MPI_CHK( mpi_sub_int( &grp->P, &grp->P, 19 ) ); + grp->pbits = mpi_msb( &grp->P ); + + /* Y intentionaly not set, since we use x/z coordinates. + * This is used as a marker to identify Montgomery curves! */ + MPI_CHK( mpi_lset( &grp->G.X, 9 ) ); + MPI_CHK( mpi_lset( &grp->G.Z, 1 ) ); + mpi_free( &grp->G.Y ); + + /* Actually, the required msb for private keys */ + grp->nbits = 254; + +cleanup: + if( ret != 0 ) + ecp_group_free( grp ); + + return( ret ); +} + /* * Set a group using well-known domain parameters */ int ecp_use_known_dp( ecp_group *grp, ecp_group_id id ) { + ecp_group_free( grp ); + grp->id = id; switch( id ) @@ -395,6 +442,12 @@ int ecp_use_known_dp( ecp_group *grp, ecp_group_id id ) return( LOAD_GROUP( brainpoolP512r1 ) ); #endif /* POLARSSL_ECP_DP_BP512R1_ENABLED */ +#if defined(POLARSSL_ECP_DP_M255_ENABLED) + case POLARSSL_ECP_DP_M255: + grp->modp = ecp_mod_p255; + return( ecp_use_curve25519( grp ) ); +#endif /* POLARSSL_ECP_DP_M255_ENABLED */ + default: ecp_group_free( grp ); return( POLARSSL_ERR_ECP_FEATURE_UNAVAILABLE ); @@ -804,4 +857,48 @@ cleanup: #endif /* POLARSSL_ECP_NIST_OPTIM */ +#if defined(POLARSSL_ECP_DP_M255_ENABLED) + +/* Size of p255 in terms of t_uint */ +#define P255_WIDTH ( 255 / 8 / sizeof( t_uint ) + 1 ) + +/* + * Fast quasi-reduction modulo p255 = 2^255 - 19 + * Write N as A1 + 2^255 A1, return A0 + 19 * A1 + */ +static int ecp_mod_p255( mpi *N ) +{ + int ret; + size_t i; + mpi M; + t_uint Mp[P255_WIDTH + 2]; + + if( N->n < P255_WIDTH ) + return( 0 ); + + /* M = A1 */ + M.s = 1; + M.n = N->n - ( P255_WIDTH - 1 ); + if( M.n > P255_WIDTH + 1 ) + M.n = P255_WIDTH + 1; + M.p = Mp; + memset( Mp, 0, sizeof Mp ); + memcpy( Mp, N->p + P255_WIDTH - 1, M.n * sizeof( t_uint ) ); + MPI_CHK( mpi_shift_r( &M, 255 % ( 8 * sizeof( t_uint ) ) ) ); + M.n++; /* Make room for multiplication by 19 */ + + /* N = A0 */ + mpi_set_bit( N, 255, 0 ); + for( i = P255_WIDTH; i < N->n; i++ ) + N->p[i] = 0; + + /* N = A0 + 19 * A1 */ + MPI_CHK( mpi_mul_int( &M, &M, 19 ) ); + MPI_CHK( mpi_add_abs( N, N, &M ) ); + +cleanup: + return( ret ); +} +#endif /* POLARSSL_ECP_DP_M255_ENABLED */ + #endif diff --git a/tests/suites/test_suite_ecp.data b/tests/suites/test_suite_ecp.data index 17ad8aa10..dcf8ed6ec 100644 --- a/tests/suites/test_suite_ecp.data +++ b/tests/suites/test_suite_ecp.data @@ -159,6 +159,12 @@ ecp_small_check_pub:0:2:1:0 ECP small check pubkey #10 ecp_small_check_pub:10:25:1:POLARSSL_ERR_ECP_INVALID_KEY +ECP check pubkey Montgomery #1 (too big) +ecp_check_pub_mx:POLARSSL_ECP_DP_M255:"010000000000000000000000000000000000000000000000000000000000000000":POLARSSL_ERR_ECP_INVALID_KEY + +ECP check pubkey Montgomery #2 (biggest) +ecp_check_pub_mx:POLARSSL_ECP_DP_M255:"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF":0 + ECP write binary #0 (zero, bad format) depends_on:POLARSSL_ECP_DP_SECP192R1_ENABLED ecp_write_binary:POLARSSL_ECP_DP_SECP192R1:"01":"01":"00":POLARSSL_ECP_PF_UNKNOWN:"00":1:POLARSSL_ERR_ECP_BAD_INPUT_DATA @@ -271,14 +277,58 @@ ECP tls write-read group #2 depends_on:POLARSSL_ECP_DP_SECP521R1_ENABLED ecp_tls_write_read_group:POLARSSL_ECP_DP_SECP521R1 -ECP check privkey +ECP check privkey #1 (short weierstrass, too small) depends_on:POLARSSL_ECP_DP_SECP192R1_ENABLED -ecp_check_privkey:POLARSSL_ECP_DP_SECP192R1 +ecp_check_privkey:POLARSSL_ECP_DP_SECP192R1:"00":POLARSSL_ERR_ECP_INVALID_KEY + +ECP check privkey #2 (short weierstrass, smallest) +depends_on:POLARSSL_ECP_DP_SECP192R1_ENABLED +ecp_check_privkey:POLARSSL_ECP_DP_SECP192R1:"01":0 + +ECP check privkey #3 (short weierstrass, biggest) +depends_on:POLARSSL_ECP_DP_SECP192R1_ENABLED +ecp_check_privkey:POLARSSL_ECP_DP_SECP192R1:"FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22830":0 + +ECP check privkey #4 (short weierstrass, too big) +depends_on:POLARSSL_ECP_DP_SECP192R1_ENABLED +ecp_check_privkey:POLARSSL_ECP_DP_SECP192R1:"FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831":POLARSSL_ERR_ECP_INVALID_KEY + +ECP check privkey #5 (montgomery, too big) +depends_on:POLARSSL_ECP_DP_M255_ENABLED +ecp_check_privkey:POLARSSL_ECP_DP_M255:"C000000000000000000000000000000000000000000000000000000000000000":POLARSSL_ERR_ECP_INVALID_KEY + +ECP check privkey #6 (montgomery, not big enough) +depends_on:POLARSSL_ECP_DP_M255_ENABLED +ecp_check_privkey:POLARSSL_ECP_DP_M255:"3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0":POLARSSL_ERR_ECP_INVALID_KEY + +ECP check privkey #7 (montgomery, msb OK) +depends_on:POLARSSL_ECP_DP_M255_ENABLED +ecp_check_privkey:POLARSSL_ECP_DP_M255:"4000000000000000000000000000000000000000000000000000000000000000":0 + +ECP check privkey #8 (montgomery, bit 0 set) +depends_on:POLARSSL_ECP_DP_M255_ENABLED +ecp_check_privkey:POLARSSL_ECP_DP_M255:"4000000000000000000000000000000000000000000000000000000000000001":POLARSSL_ERR_ECP_INVALID_KEY + +ECP check privkey #9 (montgomery, bit 1 set) +depends_on:POLARSSL_ECP_DP_M255_ENABLED +ecp_check_privkey:POLARSSL_ECP_DP_M255:"4000000000000000000000000000000000000000000000000000000000000002":POLARSSL_ERR_ECP_INVALID_KEY + +ECP check privkey #10 (montgomery, bit 2 set) +depends_on:POLARSSL_ECP_DP_M255_ENABLED +ecp_check_privkey:POLARSSL_ECP_DP_M255:"4000000000000000000000000000000000000000000000000000000000000004":POLARSSL_ERR_ECP_INVALID_KEY + +ECP check privkey #11 (montgomery, OK) +depends_on:POLARSSL_ECP_DP_M255_ENABLED +ecp_check_privkey:POLARSSL_ECP_DP_M255:"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8":0 ECP gen keypair depends_on:POLARSSL_ECP_DP_SECP192R1_ENABLED ecp_gen_keypair:POLARSSL_ECP_DP_SECP192R1 +ECP gen keypair +depends_on:POLARSSL_ECP_DP_M255_ENABLED +ecp_gen_keypair:POLARSSL_ECP_DP_M255 + ECP gen keypair wrapper depends_on:POLARSSL_ECP_DP_SECP192R1_ENABLED ecp_gen_key:POLARSSL_ECP_DP_SECP192R1 @@ -367,5 +417,9 @@ ECP test vectors brainpoolP512r1 rfc 7027 depends_on:POLARSSL_ECP_DP_BP512R1_ENABLED ecp_test_vect:POLARSSL_ECP_DP_BP512R1:"16302FF0DBBB5A8D733DAB7141C1B45ACBC8715939677F6A56850A38BD87BD59B09E80279609FF333EB9D4C061231FB26F92EEB04982A5F1D1764CAD57665422":"0A420517E406AAC0ACDCE90FCD71487718D3B953EFD7FBEC5F7F27E28C6149999397E91E029E06457DB2D3E640668B392C2A7E737A7F0BF04436D11640FD09FD":"72E6882E8DB28AAD36237CD25D580DB23783961C8DC52DFA2EC138AD472A0FCEF3887CF62B623B2A87DE5C588301EA3E5FC269B373B60724F5E82A6AD147FDE7":"230E18E1BCC88A362FA54E4EA3902009292F7F8033624FD471B5D8ACE49D12CFABBC19963DAB8E2F1EBA00BFFB29E4D72D13F2224562F405CB80503666B25429":"9D45F66DE5D67E2E6DB6E93A59CE0BB48106097FF78A081DE781CDB31FCE8CCBAAEA8DD4320C4119F1E9CD437A2EAB3731FA9668AB268D871DEDA55A5473199F":"2FDC313095BCDD5FB3A91636F07A959C8E86B5636A1E930E8396049CB481961D365CC11453A06C719835475B12CB52FC3C383BCE35E27EF194512B71876285FA":"A7927098655F1F9976FA50A9D566865DC530331846381C87256BAF3226244B76D36403C024D7BBF0AA0803EAFF405D3D24F11A9B5C0BEF679FE1454B21C4CD1F":"7DB71C3DEF63212841C463E881BDCF055523BD368240E6C3143BD8DEF8B3B3223B95E0F53082FF5E412F4222537A43DF1C6D25729DDB51620A832BE6A26680A2" +ECP test vectors M255 aka Curve25519 +depends_on:POLARSSL_ECP_DP_M255_ENABLED +ecp_test_vec_x:POLARSSL_ECP_DP_M255:"5AC99F33632E5A768DE7E81BF854C27C46E3FBF2ABBACD29EC4AFF517369C660":"057E23EA9F1CBE8A27168F6E696A791DE61DD3AF7ACD4EEACC6E7BA514FDA863":"47DC3D214174820E1154B49BC6CDB2ABD45EE95817055D255AA35831B70D3260":"6EB89DA91989AE37C7EAC7618D9E5C4951DBA1D73C285AE1CD26A855020EEF04":"61450CD98E36016B58776A897A9F0AEF738B99F09468B8D6B8511184D53494AB" + ECP selftest ecp_selftest: diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function index cb93e850a..1f04d678c 100644 --- a/tests/suites/test_suite_ecp.function +++ b/tests/suites/test_suite_ecp.function @@ -188,6 +188,27 @@ void ecp_small_check_pub( int x, int y, int z, int ret ) } /* END_CASE */ +/* BEGIN_CASE */ +void ecp_check_pub_mx( int grp_id, char *key_hex, int ret ) +{ + ecp_group grp; + ecp_point P; + + ecp_group_init( &grp ); + ecp_point_init( &P ); + + TEST_ASSERT( ecp_use_known_dp( &grp, grp_id ) == 0 ); + + TEST_ASSERT( mpi_read_string( &P.X, 16, key_hex ) == 0 ); + TEST_ASSERT( mpi_lset( &P.Z, 1 ) == 0 ); + + TEST_ASSERT( ecp_check_pubkey( &grp, &P ) == ret ); + + ecp_group_free( &grp ); + ecp_point_free( &P ); +} +/* END_CASE */ + /* BEGIN_CASE */ void ecp_test_vect( int id, char *dA_str, char *xA_str, char *yA_str, char *dB_str, char *xB_str, char *yB_str, char *xZ_str, @@ -242,6 +263,56 @@ void ecp_test_vect( int id, char *dA_str, char *xA_str, char *yA_str, } /* END_CASE */ +/* BEGIN_CASE */ +void ecp_test_vec_x( int id, char *dA_hex, char *xA_hex, + char *dB_hex, char *xB_hex, char *xS_hex ) +{ + ecp_group grp; + ecp_point R; + mpi dA, xA, dB, xB, xS; + rnd_pseudo_info rnd_info; + + ecp_group_init( &grp ); ecp_point_init( &R ); + mpi_init( &dA ); mpi_init( &xA ); + mpi_init( &dB ); mpi_init( &xB ); + mpi_init( &xS ); + memset( &rnd_info, 0x00, sizeof( rnd_pseudo_info ) ); + + TEST_ASSERT( ecp_use_known_dp( &grp, id ) == 0 ); + + TEST_ASSERT( ecp_check_pubkey( &grp, &grp.G ) == 0 ); + + TEST_ASSERT( mpi_read_string( &dA, 16, dA_hex ) == 0 ); + TEST_ASSERT( mpi_read_string( &dB, 16, dB_hex ) == 0 ); + TEST_ASSERT( mpi_read_string( &xA, 16, xA_hex ) == 0 ); + TEST_ASSERT( mpi_read_string( &xB, 16, xB_hex ) == 0 ); + TEST_ASSERT( mpi_read_string( &xS, 16, xS_hex ) == 0 ); + + TEST_ASSERT( ecp_mul( &grp, &R, &dA, &grp.G, + &rnd_pseudo_rand, &rnd_info ) == 0 ); + TEST_ASSERT( ecp_check_pubkey( &grp, &R ) == 0 ); + TEST_ASSERT( mpi_cmp_mpi( &R.X, &xA ) == 0 ); + + TEST_ASSERT( ecp_mul( &grp, &R, &dB, &R, + &rnd_pseudo_rand, &rnd_info ) == 0 ); + TEST_ASSERT( ecp_check_pubkey( &grp, &R ) == 0 ); + TEST_ASSERT( mpi_cmp_mpi( &R.X, &xS ) == 0 ); + + TEST_ASSERT( ecp_mul( &grp, &R, &dB, &grp.G, NULL, NULL ) == 0 ); + TEST_ASSERT( ecp_check_pubkey( &grp, &R ) == 0 ); + TEST_ASSERT( mpi_cmp_mpi( &R.X, &xB ) == 0 ); + + TEST_ASSERT( ecp_mul( &grp, &R, &dA, &R, NULL, NULL ) == 0 ); + TEST_ASSERT( ecp_check_pubkey( &grp, &R ) == 0 ); + TEST_ASSERT( mpi_cmp_mpi( &R.X, &xS ) == 0 ); + + ecp_group_free( &grp ); ecp_point_free( &R ); + mpi_free( &dA ); mpi_free( &xA ); + mpi_free( &dB ); mpi_free( &xB ); + mpi_free( &xS ); +} +/* END_CASE */ + /* BEGIN_CASE */ void ecp_fast_mod( int id, char *N_str ) { @@ -490,7 +561,7 @@ void ecp_tls_write_read_group( int id ) /* END_CASE */ /* BEGIN_CASE */ -void ecp_check_privkey( int id ) +void ecp_check_privkey( int id, char *key_hex, int ret ) { ecp_group grp; mpi d; @@ -499,12 +570,9 @@ void ecp_check_privkey( int id ) mpi_init( &d ); TEST_ASSERT( ecp_use_known_dp( &grp, id ) == 0 ); + TEST_ASSERT( mpi_read_string( &d, 16, key_hex ) == 0 ); - TEST_ASSERT( mpi_lset( &d, 0 ) == 0 ); - TEST_ASSERT( ecp_check_privkey( &grp, &d ) == POLARSSL_ERR_ECP_INVALID_KEY ); - - TEST_ASSERT( mpi_copy( &d, &grp.N ) == 0 ); - TEST_ASSERT( ecp_check_privkey( &grp, &d ) == POLARSSL_ERR_ECP_INVALID_KEY ); + TEST_ASSERT( ecp_check_privkey( &grp, &d ) == ret ); ecp_group_free( &grp ); mpi_free( &d ); diff --git a/tests/suites/test_suite_mpi.data b/tests/suites/test_suite_mpi.data index b9e00f1d7..fdbef02cc 100644 --- a/tests/suites/test_suite_mpi.data +++ b/tests/suites/test_suite_mpi.data @@ -223,6 +223,24 @@ mpi_safe_cond_assign:-1:"01":+1:"02" Test mpi_safe_cond_assign #6 mpi_safe_cond_assign:-1:"01":-1:"02" +Test mpi_safe_cond_swap #1 +mpi_safe_cond_swap:+1:"01":+1:"02" + +Test mpi_safe_cond_swap #2 +mpi_safe_cond_swap:+1:"FF000000000000000001":+1:"02" + +Test mpi_safe_cond_swap #3 +mpi_safe_cond_swap:+1:"01":+1:"FF000000000000000002" + +Test mpi_safe_cond_swap #4 +mpi_safe_cond_swap:+1:"01":-1:"02" + +Test mpi_safe_cond_swap #5 +mpi_safe_cond_swap:-1:"01":+1:"02" + +Test mpi_safe_cond_swap #6 +mpi_safe_cond_swap:-1:"01":-1:"02" + Base test mpi_add_abs #1 mpi_add_abs:10:"12345678":10:"642531":10:"12988209" @@ -665,6 +683,12 @@ mpi_set_bit:10:"49979687":80:0:10:"49979687" Test bit set (Add above existing limbs with a 1) mpi_set_bit:10:"49979687":80:1:10:"1208925819614629224685863" +Test bit set (Bit index larger than 31 with a 0) +mpi_set_bit:16:"FFFFFFFFFFFFFFFF":32:0:16:"FFFFFFFEFFFFFFFF" + +Test bit set (Bit index larger than 31 with a 1) +mpi_set_bit:16:"00":32:1:16:"0100000000" + MPI Selftest depends_on:POLARSSL_SELF_TEST mpi_selftest: diff --git a/tests/suites/test_suite_mpi.function b/tests/suites/test_suite_mpi.function index 394cd339b..620c36851 100644 --- a/tests/suites/test_suite_mpi.function +++ b/tests/suites/test_suite_mpi.function @@ -331,6 +331,36 @@ void mpi_safe_cond_assign( int x_sign, char *x_str, } /* END_CASE */ +/* BEGIN_CASE */ +void mpi_safe_cond_swap( int x_sign, char *x_str, + int y_sign, char *y_str ) +{ + mpi X, Y, XX, YY; + + mpi_init( &X ); mpi_init( &Y ); + mpi_init( &XX ); mpi_init( &YY ); + + TEST_ASSERT( mpi_read_string( &X, 16, x_str ) == 0 ); + X.s = x_sign; + TEST_ASSERT( mpi_read_string( &Y, 16, y_str ) == 0 ); + Y.s = y_sign; + + TEST_ASSERT( mpi_copy( &XX, &X ) == 0 ); + TEST_ASSERT( mpi_copy( &YY, &Y ) == 0 ); + + TEST_ASSERT( mpi_safe_cond_swap( &X, &Y, 0 ) == 0 ); + TEST_ASSERT( mpi_cmp_mpi( &X, &XX ) == 0 ); + TEST_ASSERT( mpi_cmp_mpi( &Y, &YY ) == 0 ); + + TEST_ASSERT( mpi_safe_cond_swap( &X, &Y, 1 ) == 0 ); + TEST_ASSERT( mpi_cmp_mpi( &Y, &XX ) == 0 ); + TEST_ASSERT( mpi_cmp_mpi( &X, &YY ) == 0 ); + + mpi_free( &X ); mpi_free( &Y ); + mpi_free( &XX ); mpi_free( &YY ); +} +/* END_CASE */ + /* BEGIN_CASE */ void mpi_swap( int input_X, int input_Y ) {