df0ad8a0c0a738062133b1c84deb37dab0ab04a4
[openssl.git] / crypto / ec / ec_25519.c
1 /*
2  * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include <string.h>
11 #include <openssl/err.h>
12 #include <openssl/rand.h>
13 #include "ec_lcl.h"
14
15 /* Length of Curve 25519 keys */
16 #define EC_X25519_KEYLEN    32
17 /* Group degree and order bits */
18 #define EC_X25519_BITS      253
19
20 /* Copy Curve25519 public key buffer, allocating is necessary */
21 static int x25519_init_public(EC_POINT *pub, const void *src)
22 {
23     if (pub->custom_data == NULL) {
24         pub->custom_data = OPENSSL_malloc(EC_X25519_KEYLEN);
25         if (pub->custom_data == NULL)
26             return 0;
27     }
28     if (src != NULL)
29         memcpy(pub->custom_data, src, EC_X25519_KEYLEN);
30     return 1;
31 }
32
33 /* Copy Curve25519 private key buffer, allocating is necessary */
34 static int x25519_init_private(EC_KEY *dst, const void *src)
35 {
36     if (dst->custom_data == NULL) {
37         dst->custom_data = OPENSSL_secure_malloc(EC_X25519_KEYLEN);
38         if (dst->custom_data == NULL)
39             return 0;
40     }
41     if (src != NULL)
42         memcpy(dst->custom_data, src, EC_X25519_KEYLEN);
43     return 1;
44 }
45
46 static int x25519_group_init(EC_GROUP *grp)
47 {
48     return 1;
49 }
50
51 static int x25519_group_copy(EC_GROUP *dst, const EC_GROUP *src)
52 {
53     return 1;
54 }
55
56 static int x25519_group_get_degree(const EC_GROUP *src)
57 {
58     return EC_X25519_BITS;
59 }
60
61 static int x25519_group_order_bits(const EC_GROUP *src)
62 {
63     return EC_X25519_BITS;
64 }
65
66 static int x25519_set_private(EC_KEY *eckey, const BIGNUM *priv_key)
67 {
68     if (BN_num_bytes(priv_key) > EC_X25519_KEYLEN)
69         return 0;
70     if (x25519_init_private(eckey, NULL))
71         return 0;
72     /* Convert BIGNUM form private key to internal format */
73     if (BN_bn2lebinpad(priv_key, eckey->custom_data, EC_X25519_KEYLEN)
74         != EC_X25519_KEYLEN)
75         return 0;
76     return 1;
77 }
78
79 static int x25519_keycheck(const EC_KEY *eckey)
80 {
81     const char *pubkey;
82     if (eckey->pub_key == NULL)
83         return 0;
84     pubkey = eckey->pub_key->custom_data;
85     if (pubkey == NULL)
86         return 0;
87     if (eckey->custom_data != NULL) {
88         uint8_t tmp[EC_X25519_KEYLEN];
89         /* Check eckey->priv_key exists and matches eckey->custom_data */
90         if (eckey->priv_key == NULL)
91             return 0;
92         if (BN_bn2lebinpad(eckey->priv_key, tmp, EC_X25519_KEYLEN)
93             != EC_X25519_KEYLEN
94             || CRYPTO_memcmp(tmp, eckey->custom_data,
95                              EC_X25519_KEYLEN) != 0) {
96             OPENSSL_cleanse(tmp, EC_X25519_KEYLEN);
97             return 0;
98         }
99         X25519_public_from_private(tmp, eckey->custom_data);
100         if (CRYPTO_memcmp(pubkey, tmp, EC_X25519_KEYLEN) == 0)
101             return 1;
102         return 0;
103     } else {
104         return 1;
105     }
106 }
107
108 static int x25519_keygenpub(EC_KEY *eckey)
109 {
110     X25519_public_from_private(eckey->pub_key->custom_data,
111                                eckey->custom_data);
112     return 1;
113 }
114
115 static int x25519_keygen(EC_KEY *eckey)
116 {
117     unsigned char *key;
118     if (x25519_init_private(eckey, NULL) == 0)
119         return 0;
120     key = eckey->custom_data;
121     if (RAND_bytes(key, EC_X25519_KEYLEN) <= 0)
122         return 0;
123     key[0] &= 248;
124     key[31] &= 127;
125     key[31] |= 64;
126     /*
127      * Although the private key is kept as an array in eckey->custom_data
128      * Set eckey->priv_key too so existing code which uses
129      * EC_KEY_get0_private_key() still works.
130      */
131     if (eckey->priv_key == NULL)
132         eckey->priv_key = BN_secure_new();
133     if (eckey->priv_key == NULL)
134         return 0;
135     if (BN_lebin2bn(eckey->custom_data, EC_X25519_KEYLEN, eckey->priv_key) ==
136         NULL)
137         return 0;
138     if (eckey->pub_key == NULL)
139         eckey->pub_key = EC_POINT_new(eckey->group);
140     if (eckey->pub_key == NULL)
141         return 0;
142     return x25519_keygenpub(eckey);
143 }
144
145 static void x25519_keyfinish(EC_KEY *eckey)
146 {
147     OPENSSL_secure_free(eckey->custom_data);
148     eckey->custom_data = NULL;
149 }
150
151 static int x25519_keycopy(EC_KEY *dest, const EC_KEY *src)
152 {
153     if (src->custom_data == NULL)
154         return 0;
155     return x25519_init_private(dest, src->custom_data);
156 }
157
158 static int x25519_oct2priv(EC_KEY *eckey, const unsigned char *buf, size_t len)
159 {
160     if (len != EC_X25519_KEYLEN)
161         return 0;
162     if (x25519_init_private(eckey, buf) == 0)
163         return 0;
164     /*
165      * Although the private key is kept as an array in eckey->custom_data
166      * Set eckey->priv_key too so existing code which uses
167      * EC_KEY_get0_private_key() still works.
168      */
169     if (eckey->priv_key == NULL)
170         eckey->priv_key = BN_secure_new();
171     if (eckey->priv_key == NULL)
172         return 0;
173     if (BN_lebin2bn(buf, EC_X25519_KEYLEN, eckey->priv_key) == NULL)
174         return 0;
175     return 1;
176 }
177
178 static size_t x25519_priv2oct(const EC_KEY *eckey,
179                               unsigned char *buf, size_t len)
180 {
181     size_t keylen = EC_X25519_KEYLEN;
182     if (eckey->custom_data == NULL)
183         return 0;
184     if (buf != NULL) {
185         if (len < keylen)
186             return 0;
187         memcpy(buf, eckey->custom_data, keylen);
188     }
189     return keylen;
190 }
191
192 static int x25519_point_init(EC_POINT *pt)
193 {
194     return x25519_init_public(pt, NULL);
195 }
196
197 static void x25519_point_finish(EC_POINT *pt)
198 {
199     OPENSSL_free(pt->custom_data);
200     pt->custom_data = NULL;
201 }
202
203 static void x25519_point_clear_finish(EC_POINT *pt)
204 {
205     OPENSSL_clear_free(pt->custom_data, EC_X25519_KEYLEN);
206     pt->custom_data = NULL;
207 }
208
209 static int x25519_point_copy(EC_POINT *dst, const EC_POINT *src)
210 {
211     memcpy(dst->custom_data, src->custom_data, EC_X25519_KEYLEN);
212     return 1;
213 }
214
215 static size_t x25519_point2oct(const EC_GROUP *grp, const EC_POINT *pt,
216                                point_conversion_form_t form,
217                                unsigned char *buf, size_t len, BN_CTX *ctx)
218 {
219     if (buf != NULL) {
220         if (len < EC_X25519_KEYLEN)
221             return 0;
222         memcpy(buf, pt->custom_data, EC_X25519_KEYLEN);
223     }
224     return EC_X25519_KEYLEN;
225 }
226
227 static int x25519_oct2point(const EC_GROUP *grp, EC_POINT *pt,
228                             const unsigned char *buf, size_t len, BN_CTX *ctx)
229 {
230     unsigned char *pubkey = pt->custom_data;
231     if (len != EC_X25519_KEYLEN)
232         return 0;
233     memcpy(pubkey, buf, EC_X25519_KEYLEN);
234     /* Mask off MSB */
235     pubkey[EC_X25519_KEYLEN - 1] &= 0x7F;
236     return 1;
237 }
238
239 static int x25519_point_cmp(const EC_GROUP *group, const EC_POINT *a,
240                             const EC_POINT *b, BN_CTX *ctx)
241 {
242     /* Shouldn't happen as initialised to non-zero */
243     if (a->custom_data == NULL || b->custom_data == NULL)
244         return -1;
245
246     if (CRYPTO_memcmp(a->custom_data, b->custom_data, EC_X25519_KEYLEN) == 0)
247         return 0;
248
249     return 1;
250 }
251
252 static int x25519_compute_key(unsigned char **psec, size_t *pseclen,
253                               const EC_POINT *pub_key, const EC_KEY *ecdh)
254 {
255     unsigned char *key;
256     int ret = 0;
257     if (ecdh->custom_data == NULL)
258         return 0;
259     key = OPENSSL_malloc(EC_X25519_KEYLEN);
260     if (key == NULL)
261         return 0;
262     if (X25519(key, ecdh->custom_data, pub_key->custom_data) == 0)
263         goto err;
264     *psec = key;
265     *pseclen = EC_X25519_KEYLEN;
266     return 1;
267
268  err:
269     OPENSSL_clear_free(key, EC_X25519_KEYLEN);
270     return ret;
271 }
272
273 const EC_METHOD *ec_x25519_meth(void)
274 {
275     static const EC_METHOD ret = {
276         EC_FLAGS_CUSTOM_CURVE | EC_FLAGS_NO_SIGN,
277         NID_undef,
278         x25519_group_init,      /* group_init */
279         0,                      /* group_finish */
280         0,                      /* group_clear_finish */
281         x25519_group_copy,      /* group_copy */
282         0,                      /* group_set_curve */
283         0,                      /* group_get_curve */
284         x25519_group_get_degree,
285         x25519_group_order_bits,
286         0,                      /* group_check_discriminant */
287         x25519_point_init,
288         x25519_point_finish,
289         x25519_point_clear_finish,
290         x25519_point_copy,
291         0,                      /* point_set_to_infinity */
292         0,                      /* set_Jprojective_coordinates_GFp */
293         0,                      /* get_Jprojective_coordinates_GFp */
294         0,                      /* point_set_affine_coordinates */
295         0,                      /* point_get_affine_coordinates */
296         0,                      /* point_set_compressed_coordinates */
297         x25519_point2oct,
298         x25519_oct2point,
299         0,                      /* simple_add */
300         0,                      /* simple_dbl */
301         0,                      /* simple_invert */
302         0,                      /* simple_is_at_infinity */
303         0,                      /* simple_is_on_curve */
304         x25519_point_cmp,
305         0,                      /* simple_make_affine */
306         0,                      /* simple_points_make_affine */
307         0,                      /* points_mul */
308         0,                      /* precompute_mult */
309         0,                      /* have_precompute_mult */
310         0,                      /* field_mul */
311         0,                      /* field_sqr */
312         0,                      /* field_div */
313         0,                      /* field_encode */
314         0,                      /* field_decode */
315         0,                      /* field_set_to_one */
316         x25519_priv2oct,
317         x25519_oct2priv,
318         x25519_set_private,
319         x25519_keygen,
320         x25519_keycheck,
321         x25519_keygenpub,
322         x25519_keycopy,
323         x25519_keyfinish,
324         x25519_compute_key
325     };
326
327     return &ret;
328 }