xref: /optee_os/lib/libmbedtls/mbedtls/library/ecdh.c (revision c6672fdcd95b9a895eb5b4191f8ba3483a34a442)
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