From 3aeb5a7192b8e5259b517ae0a7f6272abfe83fb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Sat, 26 Jan 2013 18:05:50 +0100 Subject: [PATCH] Add ECDSA signature primitive. --- include/polarssl/ecdsa.h | 18 +++++++++ library/ecdsa.c | 84 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 99 insertions(+), 3 deletions(-) diff --git a/include/polarssl/ecdsa.h b/include/polarssl/ecdsa.h index 39a062666..2ad986d64 100644 --- a/include/polarssl/ecdsa.h +++ b/include/polarssl/ecdsa.h @@ -52,6 +52,24 @@ int ecdsa_sign( const ecp_group *grp, mpi *r, mpi *s, const mpi *d, const unsigned char *buf, size_t blen, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); +/** + * \brief Verify ECDSA signature of a previously hashed message + * + * \param grp ECP group + * \param buf Message hash + * \param blen Length of buf + * \param Q Public key to use for verification + * \param r First integer of the signature + * \param s Second integer of the signature + * + * \return 0 if successful, + * POLARSSL_ERR_ECP_BAD_INPUT_DATA if signature is invalid + * or a POLARSSL_ERR_ECP_XXX or POLARSSL_MPI_XXX error code + */ +int ecdsa_verify( const ecp_group *grp, + const unsigned char *buf, size_t blen, + const ecp_point *Q, const mpi *r, const mpi *s); + /** * \brief Checkup routine * diff --git a/library/ecdsa.c b/library/ecdsa.c index a8f29c134..d6834574d 100644 --- a/library/ecdsa.c +++ b/library/ecdsa.c @@ -35,6 +35,17 @@ #include "polarssl/ecdsa.h" +/* + * Derive a suitable integer for group grp from a buffer of length len + * SEC1 4.1.3 step 5 aka SEC1 4.1.4 step 3 + */ +static int derive_mpi( const ecp_group *grp, mpi *x, + const unsigned char *buf, size_t blen ) +{ + size_t n_size = (grp->nbits + 7) / 8; + return( mpi_read_binary( x, buf, blen > n_size ? n_size : blen ) ); +} + /* * Compute ECDSA signature of a hashed message (SEC1 4.1.3) * Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message) @@ -44,7 +55,6 @@ int ecdsa_sign( const ecp_group *grp, mpi *r, mpi *s, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret, key_tries, sign_tries; - size_t n_size; ecp_point R; mpi k, e; @@ -72,8 +82,7 @@ int ecdsa_sign( const ecp_group *grp, mpi *r, mpi *s, /* * Step 5: derive MPI from hashed message */ - n_size = (grp->nbits + 7) / 8; - MPI_CHK( mpi_read_binary( &e, buf, blen > n_size ? n_size : blen ) ); + MPI_CHK( derive_mpi( grp, &e, buf, blen ) ); /* * Step 6: compute s = (e + r * d) / k mod n @@ -97,6 +106,75 @@ cleanup: return( ret ); } +/* + * Verify ECDSA signature of hashed message (SEC1 4.1.4) + * Obviously, compared to SEC1 4.1.3, we skip step 2 (hash message) + */ +int ecdsa_verify( const ecp_group *grp, + const unsigned char *buf, size_t blen, + const ecp_point *Q, const mpi *r, const mpi *s) +{ + int ret; + mpi e, s_inv, u1, u2; + ecp_point R, P; + + ecp_point_init( &R ); ecp_point_init( &P ); + mpi_init( &e ); mpi_init( &s_inv ); mpi_init( &u1 ); mpi_init( &u2 ); + + /* + * Step 1: make sure r and s are in range 1..n-1 + */ + if( mpi_cmp_int( r, 1 ) < 0 || mpi_cmp_mpi( r, &grp->N ) >= 0 || + mpi_cmp_int( s, 1 ) < 0 || mpi_cmp_mpi( s, &grp->N ) >= 0 ) + { + return( POLARSSL_ERR_ECP_BAD_INPUT_DATA ); + } + + /* + * Additional precaution: make sure Q is valid + */ + MPI_CHK( ecp_check_pubkey( grp, Q ) ); + + /* + * Step 3: derive MPI from hashed message + */ + MPI_CHK( derive_mpi( grp, &e, buf, blen ) ); + + /* + * Step 4: u1 = e / s mod n, u2 = r / s mod n + */ + MPI_CHK( mpi_inv_mod( &s_inv, s, &grp->N ) ); + + MPI_CHK( mpi_mul_mpi( &u1, &e, &s_inv ) ); + MPI_CHK( mpi_mod_mpi( &u1, &u1, &grp->N ) ); + + MPI_CHK( mpi_mul_mpi( &u2, r, &s_inv ) ); + MPI_CHK( mpi_mod_mpi( &u2, &u2, &grp->N ) ); + + /* + * Step 5: R = u1 G + u2 Q + */ + MPI_CHK( ecp_mul( grp, &R, &u1, &grp->G ) ); + MPI_CHK( ecp_mul( grp, &P, &u2, Q ) ); + MPI_CHK( ecp_add( grp, &R, &R, &P ) ); + + if( ecp_is_zero( &R ) ) + return( POLARSSL_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Step 6: check that xR == r + */ + if( mpi_cmp_mpi( &R.X, r ) != 0 ) + return( POLARSSL_ERR_ECP_BAD_INPUT_DATA ); + +cleanup: + ecp_point_free( &R ); ecp_point_free( &P ); + mpi_free( &e ); mpi_free( &s_inv ); mpi_free( &u1 ); mpi_free( &u2 ); + + return( ret ); +} + + #if defined(POLARSSL_SELF_TEST) /*