/* * ECDH with curve-optimized implementation multiplexing * * Copyright 2016-2018 INRIA and Microsoft Corporation * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * This file is part of mbed TLS (https://tls.mbed.org) */ #if !defined(MBEDTLS_CONFIG_FILE) #include "mbedtls/config.h" #else #include MBEDTLS_CONFIG_FILE #endif #if defined(MBEDTLS_ECDH_C) #include #include #include #include "x25519.h" #include /* * Initialize context */ void mbedtls_x25519_init( mbedtls_x25519_context *ctx ) { mbedtls_platform_zeroize( ctx, sizeof( mbedtls_x25519_context ) ); } /* * Free context */ void mbedtls_x25519_free( mbedtls_x25519_context *ctx ) { if( ctx == NULL ) return; mbedtls_platform_zeroize( ctx->our_secret, MBEDTLS_X25519_KEY_SIZE_BYTES ); mbedtls_platform_zeroize( ctx->peer_point, MBEDTLS_X25519_KEY_SIZE_BYTES ); } int mbedtls_x25519_make_params( mbedtls_x25519_context *ctx, size_t *olen, unsigned char *buf, size_t blen, int( *f_rng )(void *, unsigned char *, size_t), void *p_rng ) { int ret = 0; uint8_t base[MBEDTLS_X25519_KEY_SIZE_BYTES] = {0}; if( ( ret = f_rng( p_rng, ctx->our_secret, MBEDTLS_X25519_KEY_SIZE_BYTES ) ) != 0 ) return ret; *olen = MBEDTLS_X25519_KEY_SIZE_BYTES + 4; if( blen < *olen ) return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); *buf++ = MBEDTLS_ECP_TLS_NAMED_CURVE; *buf++ = MBEDTLS_ECP_TLS_CURVE25519 >> 8; *buf++ = MBEDTLS_ECP_TLS_CURVE25519 & 0xFF; *buf++ = MBEDTLS_X25519_KEY_SIZE_BYTES; base[0] = 9; Hacl_Curve25519_crypto_scalarmult( buf, ctx->our_secret, base ); base[0] = 0; if( memcmp( buf, base, MBEDTLS_X25519_KEY_SIZE_BYTES) == 0 ) return MBEDTLS_ERR_ECP_RANDOM_FAILED; return( 0 ); } int mbedtls_x25519_read_params( mbedtls_x25519_context *ctx, const unsigned char **buf, const unsigned char *end ) { if( end - *buf < MBEDTLS_X25519_KEY_SIZE_BYTES + 1 ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); if( ( *(*buf)++ != MBEDTLS_X25519_KEY_SIZE_BYTES ) ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); memcpy( ctx->peer_point, *buf, MBEDTLS_X25519_KEY_SIZE_BYTES ); *buf += MBEDTLS_X25519_KEY_SIZE_BYTES; return( 0 ); } int mbedtls_x25519_get_params( mbedtls_x25519_context *ctx, const mbedtls_ecp_keypair *key, mbedtls_x25519_ecdh_side side ) { size_t olen = 0; switch( side ) { case MBEDTLS_X25519_ECDH_THEIRS: mbedtls_ecp_point_write_binary( &key->grp, &key->Q, MBEDTLS_ECP_PF_COMPRESSED, &olen, ctx->peer_point, MBEDTLS_X25519_KEY_SIZE_BYTES ); /* untested; defensively throw an error for now. */ return(MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE); case MBEDTLS_X25519_ECDH_OURS: mbedtls_mpi_write_binary( &key->d, ctx->our_secret, MBEDTLS_X25519_KEY_SIZE_BYTES ); /* CMW: key->Q = key->d * base; do we need to set up ctx.peer_point here? */ /* untested; defensively throw an error for now. */ return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); default: return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); } } int mbedtls_x25519_calc_secret( mbedtls_x25519_context *ctx, size_t *olen, unsigned char *buf, size_t blen, int( *f_rng )(void *, unsigned char *, size_t), void *p_rng ) { /* f_rng and p_rng are not used here because this implementation does not need blinding since it has constant trace. */ (( void )f_rng); (( void )p_rng); *olen = MBEDTLS_X25519_KEY_SIZE_BYTES; if( blen < *olen ) return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); Hacl_Curve25519_crypto_scalarmult( buf, ctx->our_secret, ctx->peer_point); /* Wipe the DH secret and don't let the peer chose a small subgroup point */ mbedtls_platform_zeroize( ctx->our_secret, MBEDTLS_X25519_KEY_SIZE_BYTES ); if( memcmp( buf, ctx->our_secret, MBEDTLS_X25519_KEY_SIZE_BYTES) == 0 ) return MBEDTLS_ERR_ECP_RANDOM_FAILED; return( 0 ); } int mbedtls_x25519_make_public( mbedtls_x25519_context *ctx, size_t *olen, unsigned char *buf, size_t blen, int( *f_rng )(void *, unsigned char *, size_t), void *p_rng ) { int ret = 0; unsigned char base[MBEDTLS_X25519_KEY_SIZE_BYTES] = { 0 }; if( ctx == NULL ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); if( ( ret = f_rng( p_rng, ctx->our_secret, MBEDTLS_X25519_KEY_SIZE_BYTES ) ) != 0 ) return ret; *olen = MBEDTLS_X25519_KEY_SIZE_BYTES + 1; if( blen < *olen ) return(MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL); *buf++ = MBEDTLS_X25519_KEY_SIZE_BYTES; base[0] = 9; Hacl_Curve25519_crypto_scalarmult( buf, ctx->our_secret, base ); base[0] = 0; if( memcmp( buf, base, MBEDTLS_X25519_KEY_SIZE_BYTES ) == 0 ) return MBEDTLS_ERR_ECP_RANDOM_FAILED; return( ret ); } int mbedtls_x25519_read_public( mbedtls_x25519_context *ctx, const unsigned char *buf, size_t blen ) { if( blen < MBEDTLS_X25519_KEY_SIZE_BYTES + 1 ) return(MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL); if( (*buf++ != MBEDTLS_X25519_KEY_SIZE_BYTES) ) return(MBEDTLS_ERR_ECP_BAD_INPUT_DATA); memcpy( ctx->peer_point, buf, MBEDTLS_X25519_KEY_SIZE_BYTES ); return( 0 ); } #endif /* MBEDTLS_ECDH_C */