Add mbedtls_ecp_read_key

The private keys used in ECDH differ in the case of Weierstrass and
Montgomery curves. They have different constraints, the former is based
on big endian, the latter little endian byte order. The fundamental
approach is different too:
- Weierstrass keys have to be in the right interval, otherwise they are
  rejected.
- Any byte array of the right size is a valid Montgomery key and it
  needs to be masked before interpreting it as a number.

Historically it was sufficient to use mbedtls_mpi_read_binary() to read
private keys, but as a preparation to improve support for Montgomery
curves we add mbedtls_ecp_read_key() to enable uniform treatment of EC
keys.

For the masking the `mbedtls_mpi_set_bit()` function is used. This is
suboptimal but seems to provide the best trade-off at this time.
Alternatives considered:
- Making a copy of the input buffer (less efficient)
- removing the `const` constraint from the input buffer (breaks the api
and makes it less user friendly)
- applying the mask directly to the limbs (violates the api between the
modules and creates and unwanted dependency)
This commit is contained in:
Janos Follath 2019-02-15 16:17:45 +00:00
parent 59b813c7be
commit 171a7efd02
6 changed files with 160 additions and 4 deletions

View file

@ -2830,6 +2830,63 @@ int mbedtls_ecp_gen_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key,
return( mbedtls_ecp_gen_keypair( &key->grp, &key->d, &key->Q, f_rng, p_rng ) );
}
#define ECP_CURVE255_KEY_SIZE 32
/*
* Read a private key.
*/
int mbedtls_ecp_read_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key,
const unsigned char *buf, size_t buflen )
{
int ret = 0;
if( ( ret = mbedtls_ecp_group_load( &key->grp, grp_id ) ) != 0 )
return( ret );
#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED)
/*
* If it is Curve25519 curve then mask the key as mandated by RFC7748
*/
if( grp_id == MBEDTLS_ECP_DP_CURVE25519 )
{
if( buflen != ECP_CURVE255_KEY_SIZE )
return MBEDTLS_ERR_ECP_INVALID_KEY;
MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary_le( &key->d, buf, buflen ) );
/* Set the three least significant bits to 0 */
MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &key->d, 0, 0 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &key->d, 1, 0 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &key->d, 2, 0 ) );
/* Set the most significant bit to 0 */
MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &key->d,
ECP_CURVE255_KEY_SIZE * 8 - 1,
0 ) );
/* Set the second most significant bit to 1 */
MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &key->d,
ECP_CURVE255_KEY_SIZE * 8 - 2,
1 ) );
}
#endif
#if defined(ECP_SHORTWEIERSTRASS)
if( ecp_get_type( &key->grp ) != ECP_TYPE_MONTGOMERY )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &key->d, buf, buflen ) );
MBEDTLS_MPI_CHK( mbedtls_ecp_check_privkey( &key->grp, &key->d ) );
}
#endif
cleanup:
if( ret != 0 )
mbedtls_mpi_free( &key->d );
return( ret );
}
/*
* Check a public-private key pair
*/