Add a safer deterministic ECDSA function
`mbedtls_ecdsa_sign_det` reuses the internal HMAC-DRBG instance to
implement blinding. The advantage of this is that the algorithm is
deterministic too, not just the resulting signature. The drawback is
that the blinding is always the same for the same key and message.
This diminishes the efficiency of blinding and leaks information about
the private key.
A function that takes external randomness fixes this weakness.
diff --git a/library/ecdsa.c b/library/ecdsa.c
index 17a88bd..b3e5161 100644
--- a/library/ecdsa.c
+++ b/library/ecdsa.c
@@ -70,9 +70,14 @@
* Compute ECDSA signature of a hashed message (SEC1 4.1.3)
* Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message)
*/
-int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
- const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
- int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+static int ecdsa_sign_internal( mbedtls_ecp_group *grp, mbedtls_mpi *r,
+ mbedtls_mpi *s, const mbedtls_mpi *d,
+ const unsigned char *buf, size_t blen,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int (*f_rng_blind)(void *, unsigned char *,
+ size_t),
+ void *p_rng_blind )
{
int ret, key_tries, sign_tries, blind_tries;
mbedtls_ecp_point R;
@@ -99,7 +104,10 @@
key_tries = 0;
do
{
- MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair( grp, &k, &R, f_rng, p_rng ) );
+ MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, &k, f_rng, p_rng ) );
+
+ MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, &R, &k, &grp->G,
+ f_rng_blind, p_rng_blind ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( r, &R.X, &grp->N ) );
if( key_tries++ > 10 )
@@ -123,7 +131,8 @@
do
{
size_t n_size = ( grp->nbits + 7 ) / 8;
- MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &t, n_size, f_rng, p_rng ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &t, n_size, f_rng_blind,
+ p_rng_blind ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &t, 8 * n_size - grp->nbits ) );
/* See mbedtls_ecp_gen_keypair() */
@@ -158,15 +167,27 @@
return( ret );
}
+
+int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
+ const mbedtls_mpi *d, const unsigned char *buf,
+ size_t blen,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+ /* Use the same RNG for both blinding and ephemeral key generation */
+ return( ecdsa_sign_internal( grp, r, s, d, buf, blen, f_rng, p_rng,
+ f_rng, p_rng ) );
+}
#endif /* MBEDTLS_ECDSA_SIGN_ALT */
#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
-/*
- * Deterministic signature wrapper
- */
-int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
- const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
- mbedtls_md_type_t md_alg )
+static int ecdsa_sign_det_internal( mbedtls_ecp_group *grp, mbedtls_mpi *r,
+ mbedtls_mpi *s, const mbedtls_mpi *d,
+ const unsigned char *buf, size_t blen,
+ mbedtls_md_type_t md_alg,
+ int (*f_rng_blind)(void *, unsigned char *,
+ size_t),
+ void *p_rng_blind )
{
int ret;
mbedtls_hmac_drbg_context rng_ctx;
@@ -187,8 +208,20 @@
MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, data + grp_len, grp_len ) );
mbedtls_hmac_drbg_seed_buf( &rng_ctx, md_info, data, 2 * grp_len );
- ret = mbedtls_ecdsa_sign( grp, r, s, d, buf, blen,
- mbedtls_hmac_drbg_random, &rng_ctx );
+ if( f_rng_blind != NULL )
+ ret = ecdsa_sign_internal( grp, r, s, d, buf, blen,
+ mbedtls_hmac_drbg_random, &rng_ctx,
+ f_rng_blind, p_rng_blind );
+ else
+ /*
+ * Use the same RNG for both blinding and ephemeral key generation.
+ * Since the RNG output is always the same for the same key and message,
+ * this limits the efficiency of blinding and leaks information through
+ * side channels.
+ */
+ ret = ecdsa_sign_internal( grp, r, s, d, buf, blen,
+ mbedtls_hmac_drbg_random, &rng_ctx,
+ mbedtls_hmac_drbg_random, &rng_ctx );
cleanup:
mbedtls_hmac_drbg_free( &rng_ctx );
@@ -196,6 +229,30 @@
return( ret );
}
+
+/*
+ * Deterministic signature wrappers
+ */
+int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r,
+ mbedtls_mpi *s, const mbedtls_mpi *d,
+ const unsigned char *buf, size_t blen,
+ mbedtls_md_type_t md_alg )
+{
+ return( ecdsa_sign_det_internal( grp, r, s, d, buf, blen, md_alg,
+ NULL, NULL ) );
+}
+
+int mbedtls_ecdsa_sign_det_ext( mbedtls_ecp_group *grp, mbedtls_mpi *r,
+ mbedtls_mpi *s, const mbedtls_mpi *d,
+ const unsigned char *buf, size_t blen,
+ mbedtls_md_type_t md_alg,
+ int (*f_rng_blind)(void *, unsigned char *,
+ size_t),
+ void *p_rng_blind )
+{
+ return( ecdsa_sign_det_internal( grp, r, s, d, buf, blen, md_alg,
+ f_rng_blind, p_rng_blind ) );
+}
#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
#if !defined(MBEDTLS_ECDSA_VERIFY_ALT)
@@ -326,17 +383,15 @@
mbedtls_mpi_init( &s );
#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
- (void) f_rng;
- (void) p_rng;
-
- MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign_det( &ctx->grp, &r, &s, &ctx->d,
- hash, hlen, md_alg ) );
+ MBEDTLS_MPI_CHK( ecdsa_sign_det_internal( &ctx->grp, &r, &s, &ctx->d,
+ hash, hlen, md_alg,
+ f_rng, p_rng ) );
#else
(void) md_alg;
MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d,
hash, hlen, f_rng, p_rng ) );
-#endif
+#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
MBEDTLS_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen ) );