pkgconfig: Fix libgcrypt.pc.
[libgcrypt.git] / cipher / ecc-ecdh.c
1 /* ecc-ecdh.c  -  Elliptic Curve Diffie-Hellman key agreement
2  * Copyright (C) 2019 g10 Code GmbH
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, see <https://www.gnu.org/licenses/>.
18  * SPDX-License-Identifier: LGPL-2.1+
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26
27 #include "g10lib.h"
28 #include "mpi.h"
29 #include "cipher.h"
30 #include "context.h"
31 #include "ec-context.h"
32 #include "ecc-common.h"
33
34 #define ECC_CURVE25519_BITS 256
35 #define ECC_CURVE448_BITS   448
36
37 static mpi_ec_t
38 prepare_ec (const char *curve_name, elliptic_curve_t *E)
39 {
40   mpi_ec_t ec;
41
42   memset (E, 0, sizeof *E);
43   if (_gcry_ecc_fill_in_curve (0, curve_name, E, NULL))
44     return NULL;
45
46   ec = _gcry_mpi_ec_p_internal_new (E->model, E->dialect,
47                                     PUBKEY_FLAG_DJB_TWEAK, E->p, E->a, E->b);
48   return ec;
49 }
50
51 unsigned int
52 _gcry_ecc_get_algo_keylen (int algo)
53 {
54   unsigned int len = 0;
55
56   if (algo == GCRY_ECC_CURVE25519)
57     len = ECC_CURVE25519_BITS/8;
58   else if (algo == GCRY_ECC_CURVE448)
59     len = ECC_CURVE448_BITS/8;
60
61   return len;
62 }
63
64 gpg_error_t
65 _gcry_ecc_mul_point (int algo, unsigned char *result,
66                      const unsigned char *scalar, const unsigned char *point)
67 {
68   unsigned int nbits;
69   unsigned int nbytes;
70   const char *curve;
71   gpg_err_code_t err;
72   elliptic_curve_t E;
73   unsigned char buffer[ECC_CURVE448_BITS/8];
74   gcry_mpi_t mpi_k;
75   mpi_ec_t ec;
76   gcry_mpi_t mpi_u;
77   mpi_point_t Q;
78   gcry_mpi_t x;
79   unsigned int len;
80   int i;
81   unsigned char *buf;
82
83   if (algo == GCRY_ECC_CURVE25519)
84     {
85       nbits = ECC_CURVE25519_BITS;
86       curve = "Curve25519";
87     }
88   else if (algo == GCRY_ECC_CURVE448)
89     {
90       nbits = ECC_CURVE448_BITS;
91       curve = "X448";
92       return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
93     }
94   else
95     return gpg_error (GPG_ERR_UNKNOWN_ALGORITHM);
96
97   nbytes = nbits / 8;
98
99   mpi_k = mpi_new (nbits);
100   ec = prepare_ec (curve, &E);
101   mpi_u = mpi_new (nbits);
102   Q = mpi_point_new (nbits);
103   x = mpi_new (nbits);
104
105   memcpy (buffer, scalar, nbytes);
106   reverse_buffer (buffer, nbytes);
107   _gcry_mpi_set_buffer (mpi_k, buffer, nbytes, 0);
108
109   for (i = 0; i < mpi_get_nbits (E.h) - 1; i++)
110     mpi_clear_bit (mpi_k, i);
111   mpi_set_highbit (mpi_k, mpi_get_nbits (E.p) - 1);
112
113   if (point)
114     {
115       mpi_point_t P = mpi_point_new (nbits);
116
117       _gcry_mpi_set_buffer (mpi_u, point, nbytes, 0);
118
119       err = _gcry_ecc_mont_decodepoint (mpi_u, ec, P);
120       _gcry_mpi_release (mpi_u);
121       if (err)
122         goto leave;
123       _gcry_mpi_ec_mul_point (Q, mpi_k, P, ec);
124       _gcry_mpi_point_release (P);
125     }
126   else
127     _gcry_mpi_ec_mul_point (Q, mpi_k, &E.G, ec);
128
129   _gcry_mpi_ec_get_affine (x, NULL, Q, ec);
130
131   buf = _gcry_mpi_get_buffer (x, nbytes, &len, NULL);
132   if (!buf)
133     err = gpg_error_from_syserror ();
134   memcpy (result, buf, nbytes);
135   xfree (buf);
136
137  leave:
138   _gcry_mpi_release (x);
139   _gcry_mpi_point_release (Q);
140   _gcry_mpi_release (mpi_k);
141   return err;
142 }