1*c6672fdcSEdison Ai // SPDX-License-Identifier: Apache-2.0 2817466cbSJens Wiklander /* 3817466cbSJens Wiklander * Elliptic curve Diffie-Hellman 4817466cbSJens Wiklander * 5817466cbSJens Wiklander * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 6817466cbSJens Wiklander * 7817466cbSJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 8817466cbSJens Wiklander * not use this file except in compliance with the License. 9817466cbSJens Wiklander * You may obtain a copy of the License at 10817466cbSJens Wiklander * 11817466cbSJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 12817466cbSJens Wiklander * 13817466cbSJens Wiklander * Unless required by applicable law or agreed to in writing, software 14817466cbSJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15817466cbSJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16817466cbSJens Wiklander * See the License for the specific language governing permissions and 17817466cbSJens Wiklander * limitations under the License. 18817466cbSJens Wiklander * 19817466cbSJens Wiklander * This file is part of mbed TLS (https://tls.mbed.org) 20817466cbSJens Wiklander */ 21817466cbSJens Wiklander 22817466cbSJens Wiklander /* 23817466cbSJens Wiklander * References: 24817466cbSJens Wiklander * 25817466cbSJens Wiklander * SEC1 http://www.secg.org/index.php?action=secg,docs_secg 26817466cbSJens Wiklander * RFC 4492 27817466cbSJens Wiklander */ 28817466cbSJens Wiklander 29817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE) 30817466cbSJens Wiklander #include "mbedtls/config.h" 31817466cbSJens Wiklander #else 32817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE 33817466cbSJens Wiklander #endif 34817466cbSJens Wiklander 35817466cbSJens Wiklander #if defined(MBEDTLS_ECDH_C) 36817466cbSJens Wiklander 37817466cbSJens Wiklander #include "mbedtls/ecdh.h" 38817466cbSJens Wiklander 39817466cbSJens Wiklander #include <string.h> 40817466cbSJens Wiklander 41817466cbSJens Wiklander /* 42817466cbSJens Wiklander * Generate public key: simple wrapper around mbedtls_ecp_gen_keypair 43817466cbSJens Wiklander */ 44817466cbSJens Wiklander int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, 45817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 46817466cbSJens Wiklander void *p_rng ) 47817466cbSJens Wiklander { 48817466cbSJens Wiklander return mbedtls_ecp_gen_keypair( grp, d, Q, f_rng, p_rng ); 49817466cbSJens Wiklander } 50817466cbSJens Wiklander 51817466cbSJens Wiklander /* 52817466cbSJens Wiklander * Compute shared secret (SEC1 3.3.1) 53817466cbSJens Wiklander */ 54817466cbSJens Wiklander int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, 55817466cbSJens Wiklander const mbedtls_ecp_point *Q, const mbedtls_mpi *d, 56817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 57817466cbSJens Wiklander void *p_rng ) 58817466cbSJens Wiklander { 59817466cbSJens Wiklander int ret; 60817466cbSJens Wiklander mbedtls_ecp_point P; 61817466cbSJens Wiklander 62817466cbSJens Wiklander mbedtls_ecp_point_init( &P ); 63817466cbSJens Wiklander 64817466cbSJens Wiklander /* 65817466cbSJens Wiklander * Make sure Q is a valid pubkey before using it 66817466cbSJens Wiklander */ 67817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) ); 68817466cbSJens Wiklander 69817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, &P, d, Q, f_rng, p_rng ) ); 70817466cbSJens Wiklander 71817466cbSJens Wiklander if( mbedtls_ecp_is_zero( &P ) ) 72817466cbSJens Wiklander { 73817466cbSJens Wiklander ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 74817466cbSJens Wiklander goto cleanup; 75817466cbSJens Wiklander } 76817466cbSJens Wiklander 77817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_copy( z, &P.X ) ); 78817466cbSJens Wiklander 79817466cbSJens Wiklander cleanup: 80817466cbSJens Wiklander mbedtls_ecp_point_free( &P ); 81817466cbSJens Wiklander 82817466cbSJens Wiklander return( ret ); 83817466cbSJens Wiklander } 84817466cbSJens Wiklander 85817466cbSJens Wiklander /* 86817466cbSJens Wiklander * Initialize context 87817466cbSJens Wiklander */ 88817466cbSJens Wiklander void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx ) 89817466cbSJens Wiklander { 90817466cbSJens Wiklander memset( ctx, 0, sizeof( mbedtls_ecdh_context ) ); 91817466cbSJens Wiklander } 92817466cbSJens Wiklander 93817466cbSJens Wiklander /* 94817466cbSJens Wiklander * Free context 95817466cbSJens Wiklander */ 96817466cbSJens Wiklander void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ) 97817466cbSJens Wiklander { 98817466cbSJens Wiklander if( ctx == NULL ) 99817466cbSJens Wiklander return; 100817466cbSJens Wiklander 101817466cbSJens Wiklander mbedtls_ecp_group_free( &ctx->grp ); 102817466cbSJens Wiklander mbedtls_ecp_point_free( &ctx->Q ); 103817466cbSJens Wiklander mbedtls_ecp_point_free( &ctx->Qp ); 104817466cbSJens Wiklander mbedtls_ecp_point_free( &ctx->Vi ); 105817466cbSJens Wiklander mbedtls_ecp_point_free( &ctx->Vf ); 106817466cbSJens Wiklander mbedtls_mpi_free( &ctx->d ); 107817466cbSJens Wiklander mbedtls_mpi_free( &ctx->z ); 108817466cbSJens Wiklander mbedtls_mpi_free( &ctx->_d ); 109817466cbSJens Wiklander } 110817466cbSJens Wiklander 111817466cbSJens Wiklander /* 112817466cbSJens Wiklander * Setup and write the ServerKeyExhange parameters (RFC 4492) 113817466cbSJens Wiklander * struct { 114817466cbSJens Wiklander * ECParameters curve_params; 115817466cbSJens Wiklander * ECPoint public; 116817466cbSJens Wiklander * } ServerECDHParams; 117817466cbSJens Wiklander */ 118817466cbSJens Wiklander int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, 119817466cbSJens Wiklander unsigned char *buf, size_t blen, 120817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 121817466cbSJens Wiklander void *p_rng ) 122817466cbSJens Wiklander { 123817466cbSJens Wiklander int ret; 124817466cbSJens Wiklander size_t grp_len, pt_len; 125817466cbSJens Wiklander 126817466cbSJens Wiklander if( ctx == NULL || ctx->grp.pbits == 0 ) 127817466cbSJens Wiklander return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 128817466cbSJens Wiklander 129817466cbSJens Wiklander if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ) 130817466cbSJens Wiklander != 0 ) 131817466cbSJens Wiklander return( ret ); 132817466cbSJens Wiklander 133817466cbSJens Wiklander if( ( ret = mbedtls_ecp_tls_write_group( &ctx->grp, &grp_len, buf, blen ) ) 134817466cbSJens Wiklander != 0 ) 135817466cbSJens Wiklander return( ret ); 136817466cbSJens Wiklander 137817466cbSJens Wiklander buf += grp_len; 138817466cbSJens Wiklander blen -= grp_len; 139817466cbSJens Wiklander 140817466cbSJens Wiklander if( ( ret = mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, ctx->point_format, 141817466cbSJens Wiklander &pt_len, buf, blen ) ) != 0 ) 142817466cbSJens Wiklander return( ret ); 143817466cbSJens Wiklander 144817466cbSJens Wiklander *olen = grp_len + pt_len; 145817466cbSJens Wiklander return( 0 ); 146817466cbSJens Wiklander } 147817466cbSJens Wiklander 148817466cbSJens Wiklander /* 149817466cbSJens Wiklander * Read the ServerKeyExhange parameters (RFC 4492) 150817466cbSJens Wiklander * struct { 151817466cbSJens Wiklander * ECParameters curve_params; 152817466cbSJens Wiklander * ECPoint public; 153817466cbSJens Wiklander * } ServerECDHParams; 154817466cbSJens Wiklander */ 155817466cbSJens Wiklander int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx, 156817466cbSJens Wiklander const unsigned char **buf, const unsigned char *end ) 157817466cbSJens Wiklander { 158817466cbSJens Wiklander int ret; 159817466cbSJens Wiklander 160817466cbSJens Wiklander if( ( ret = mbedtls_ecp_tls_read_group( &ctx->grp, buf, end - *buf ) ) != 0 ) 161817466cbSJens Wiklander return( ret ); 162817466cbSJens Wiklander 163817466cbSJens Wiklander if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, buf, end - *buf ) ) 164817466cbSJens Wiklander != 0 ) 165817466cbSJens Wiklander return( ret ); 166817466cbSJens Wiklander 167817466cbSJens Wiklander return( 0 ); 168817466cbSJens Wiklander } 169817466cbSJens Wiklander 170817466cbSJens Wiklander /* 171817466cbSJens Wiklander * Get parameters from a keypair 172817466cbSJens Wiklander */ 173817466cbSJens Wiklander int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, const mbedtls_ecp_keypair *key, 174817466cbSJens Wiklander mbedtls_ecdh_side side ) 175817466cbSJens Wiklander { 176817466cbSJens Wiklander int ret; 177817466cbSJens Wiklander 178817466cbSJens Wiklander if( ( ret = mbedtls_ecp_group_copy( &ctx->grp, &key->grp ) ) != 0 ) 179817466cbSJens Wiklander return( ret ); 180817466cbSJens Wiklander 181817466cbSJens Wiklander /* If it's not our key, just import the public part as Qp */ 182817466cbSJens Wiklander if( side == MBEDTLS_ECDH_THEIRS ) 183817466cbSJens Wiklander return( mbedtls_ecp_copy( &ctx->Qp, &key->Q ) ); 184817466cbSJens Wiklander 185817466cbSJens Wiklander /* Our key: import public (as Q) and private parts */ 186817466cbSJens Wiklander if( side != MBEDTLS_ECDH_OURS ) 187817466cbSJens Wiklander return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 188817466cbSJens Wiklander 189817466cbSJens Wiklander if( ( ret = mbedtls_ecp_copy( &ctx->Q, &key->Q ) ) != 0 || 190817466cbSJens Wiklander ( ret = mbedtls_mpi_copy( &ctx->d, &key->d ) ) != 0 ) 191817466cbSJens Wiklander return( ret ); 192817466cbSJens Wiklander 193817466cbSJens Wiklander return( 0 ); 194817466cbSJens Wiklander } 195817466cbSJens Wiklander 196817466cbSJens Wiklander /* 197817466cbSJens Wiklander * Setup and export the client public value 198817466cbSJens Wiklander */ 199817466cbSJens Wiklander int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen, 200817466cbSJens Wiklander unsigned char *buf, size_t blen, 201817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 202817466cbSJens Wiklander void *p_rng ) 203817466cbSJens Wiklander { 204817466cbSJens Wiklander int ret; 205817466cbSJens Wiklander 206817466cbSJens Wiklander if( ctx == NULL || ctx->grp.pbits == 0 ) 207817466cbSJens Wiklander return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 208817466cbSJens Wiklander 209817466cbSJens Wiklander if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ) 210817466cbSJens Wiklander != 0 ) 211817466cbSJens Wiklander return( ret ); 212817466cbSJens Wiklander 213817466cbSJens Wiklander return mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, ctx->point_format, 214817466cbSJens Wiklander olen, buf, blen ); 215817466cbSJens Wiklander } 216817466cbSJens Wiklander 217817466cbSJens Wiklander /* 218817466cbSJens Wiklander * Parse and import the client's public value 219817466cbSJens Wiklander */ 220817466cbSJens Wiklander int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, 221817466cbSJens Wiklander const unsigned char *buf, size_t blen ) 222817466cbSJens Wiklander { 223817466cbSJens Wiklander int ret; 224817466cbSJens Wiklander const unsigned char *p = buf; 225817466cbSJens Wiklander 226817466cbSJens Wiklander if( ctx == NULL ) 227817466cbSJens Wiklander return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 228817466cbSJens Wiklander 229817466cbSJens Wiklander if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, &p, blen ) ) != 0 ) 230817466cbSJens Wiklander return( ret ); 231817466cbSJens Wiklander 232817466cbSJens Wiklander if( (size_t)( p - buf ) != blen ) 233817466cbSJens Wiklander return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 234817466cbSJens Wiklander 235817466cbSJens Wiklander return( 0 ); 236817466cbSJens Wiklander } 237817466cbSJens Wiklander 238817466cbSJens Wiklander /* 239817466cbSJens Wiklander * Derive and export the shared secret 240817466cbSJens Wiklander */ 241817466cbSJens Wiklander int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen, 242817466cbSJens Wiklander unsigned char *buf, size_t blen, 243817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 244817466cbSJens Wiklander void *p_rng ) 245817466cbSJens Wiklander { 246817466cbSJens Wiklander int ret; 247817466cbSJens Wiklander 248817466cbSJens Wiklander if( ctx == NULL ) 249817466cbSJens Wiklander return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 250817466cbSJens Wiklander 251817466cbSJens Wiklander if( ( ret = mbedtls_ecdh_compute_shared( &ctx->grp, &ctx->z, &ctx->Qp, &ctx->d, 252817466cbSJens Wiklander f_rng, p_rng ) ) != 0 ) 253817466cbSJens Wiklander { 254817466cbSJens Wiklander return( ret ); 255817466cbSJens Wiklander } 256817466cbSJens Wiklander 257817466cbSJens Wiklander if( mbedtls_mpi_size( &ctx->z ) > blen ) 258817466cbSJens Wiklander return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 259817466cbSJens Wiklander 260817466cbSJens Wiklander *olen = ctx->grp.pbits / 8 + ( ( ctx->grp.pbits % 8 ) != 0 ); 261817466cbSJens Wiklander return mbedtls_mpi_write_binary( &ctx->z, buf, *olen ); 262817466cbSJens Wiklander } 263817466cbSJens Wiklander 264817466cbSJens Wiklander #endif /* MBEDTLS_ECDH_C */ 265