~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/crypto/ecdh.c

Version: ~ [ linux-5.17-rc1 ] ~ [ linux-5.16.2 ] ~ [ linux-5.15.16 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.93 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.173 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.225 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.262 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.297 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.299 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /* ECDH key-agreement protocol
  3  *
  4  * Copyright (c) 2016, Intel Corporation
  5  * Authors: Salvator Benedetto <salvatore.benedetto@intel.com>
  6  */
  7 
  8 #include <linux/module.h>
  9 #include <crypto/internal/ecc.h>
 10 #include <crypto/internal/kpp.h>
 11 #include <crypto/kpp.h>
 12 #include <crypto/ecdh.h>
 13 #include <linux/scatterlist.h>
 14 
 15 struct ecdh_ctx {
 16         unsigned int curve_id;
 17         unsigned int ndigits;
 18         u64 private_key[ECC_MAX_DIGITS];
 19 };
 20 
 21 static inline struct ecdh_ctx *ecdh_get_ctx(struct crypto_kpp *tfm)
 22 {
 23         return kpp_tfm_ctx(tfm);
 24 }
 25 
 26 static int ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
 27                            unsigned int len)
 28 {
 29         struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
 30         struct ecdh params;
 31 
 32         if (crypto_ecdh_decode_key(buf, len, &params) < 0 ||
 33             params.key_size > sizeof(u64) * ctx->ndigits)
 34                 return -EINVAL;
 35 
 36         if (!params.key || !params.key_size)
 37                 return ecc_gen_privkey(ctx->curve_id, ctx->ndigits,
 38                                        ctx->private_key);
 39 
 40         memcpy(ctx->private_key, params.key, params.key_size);
 41 
 42         if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits,
 43                              ctx->private_key, params.key_size) < 0) {
 44                 memzero_explicit(ctx->private_key, params.key_size);
 45                 return -EINVAL;
 46         }
 47         return 0;
 48 }
 49 
 50 static int ecdh_compute_value(struct kpp_request *req)
 51 {
 52         struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
 53         struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
 54         u64 *public_key;
 55         u64 *shared_secret = NULL;
 56         void *buf;
 57         size_t copied, nbytes, public_key_sz;
 58         int ret = -ENOMEM;
 59 
 60         nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
 61         /* Public part is a point thus it has both coordinates */
 62         public_key_sz = 2 * nbytes;
 63 
 64         public_key = kmalloc(public_key_sz, GFP_KERNEL);
 65         if (!public_key)
 66                 return -ENOMEM;
 67 
 68         if (req->src) {
 69                 shared_secret = kmalloc(nbytes, GFP_KERNEL);
 70                 if (!shared_secret)
 71                         goto free_pubkey;
 72 
 73                 /* from here on it's invalid parameters */
 74                 ret = -EINVAL;
 75 
 76                 /* must have exactly two points to be on the curve */
 77                 if (public_key_sz != req->src_len)
 78                         goto free_all;
 79 
 80                 copied = sg_copy_to_buffer(req->src,
 81                                            sg_nents_for_len(req->src,
 82                                                             public_key_sz),
 83                                            public_key, public_key_sz);
 84                 if (copied != public_key_sz)
 85                         goto free_all;
 86 
 87                 ret = crypto_ecdh_shared_secret(ctx->curve_id, ctx->ndigits,
 88                                                 ctx->private_key, public_key,
 89                                                 shared_secret);
 90 
 91                 buf = shared_secret;
 92         } else {
 93                 ret = ecc_make_pub_key(ctx->curve_id, ctx->ndigits,
 94                                        ctx->private_key, public_key);
 95                 buf = public_key;
 96                 nbytes = public_key_sz;
 97         }
 98 
 99         if (ret < 0)
100                 goto free_all;
101 
102         /* might want less than we've got */
103         nbytes = min_t(size_t, nbytes, req->dst_len);
104         copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst,
105                                                                 nbytes),
106                                      buf, nbytes);
107         if (copied != nbytes)
108                 ret = -EINVAL;
109 
110         /* fall through */
111 free_all:
112         kfree_sensitive(shared_secret);
113 free_pubkey:
114         kfree(public_key);
115         return ret;
116 }
117 
118 static unsigned int ecdh_max_size(struct crypto_kpp *tfm)
119 {
120         struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
121 
122         /* Public key is made of two coordinates, add one to the left shift */
123         return ctx->ndigits << (ECC_DIGITS_TO_BYTES_SHIFT + 1);
124 }
125 
126 static int ecdh_nist_p192_init_tfm(struct crypto_kpp *tfm)
127 {
128         struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
129 
130         ctx->curve_id = ECC_CURVE_NIST_P192;
131         ctx->ndigits = ECC_CURVE_NIST_P192_DIGITS;
132 
133         return 0;
134 }
135 
136 static struct kpp_alg ecdh_nist_p192 = {
137         .set_secret = ecdh_set_secret,
138         .generate_public_key = ecdh_compute_value,
139         .compute_shared_secret = ecdh_compute_value,
140         .max_size = ecdh_max_size,
141         .init = ecdh_nist_p192_init_tfm,
142         .base = {
143                 .cra_name = "ecdh-nist-p192",
144                 .cra_driver_name = "ecdh-nist-p192-generic",
145                 .cra_priority = 100,
146                 .cra_module = THIS_MODULE,
147                 .cra_ctxsize = sizeof(struct ecdh_ctx),
148         },
149 };
150 
151 static int ecdh_nist_p256_init_tfm(struct crypto_kpp *tfm)
152 {
153         struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
154 
155         ctx->curve_id = ECC_CURVE_NIST_P256;
156         ctx->ndigits = ECC_CURVE_NIST_P256_DIGITS;
157 
158         return 0;
159 }
160 
161 static struct kpp_alg ecdh_nist_p256 = {
162         .set_secret = ecdh_set_secret,
163         .generate_public_key = ecdh_compute_value,
164         .compute_shared_secret = ecdh_compute_value,
165         .max_size = ecdh_max_size,
166         .init = ecdh_nist_p256_init_tfm,
167         .base = {
168                 .cra_name = "ecdh-nist-p256",
169                 .cra_driver_name = "ecdh-nist-p256-generic",
170                 .cra_priority = 100,
171                 .cra_module = THIS_MODULE,
172                 .cra_ctxsize = sizeof(struct ecdh_ctx),
173         },
174 };
175 
176 static int ecdh_nist_p384_init_tfm(struct crypto_kpp *tfm)
177 {
178         struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
179 
180         ctx->curve_id = ECC_CURVE_NIST_P384;
181         ctx->ndigits = ECC_CURVE_NIST_P384_DIGITS;
182 
183         return 0;
184 }
185 
186 static struct kpp_alg ecdh_nist_p384 = {
187         .set_secret = ecdh_set_secret,
188         .generate_public_key = ecdh_compute_value,
189         .compute_shared_secret = ecdh_compute_value,
190         .max_size = ecdh_max_size,
191         .init = ecdh_nist_p384_init_tfm,
192         .base = {
193                 .cra_name = "ecdh-nist-p384",
194                 .cra_driver_name = "ecdh-nist-p384-generic",
195                 .cra_priority = 100,
196                 .cra_module = THIS_MODULE,
197                 .cra_ctxsize = sizeof(struct ecdh_ctx),
198         },
199 };
200 
201 static bool ecdh_nist_p192_registered;
202 
203 static int ecdh_init(void)
204 {
205         int ret;
206 
207         /* NIST p192 will fail to register in FIPS mode */
208         ret = crypto_register_kpp(&ecdh_nist_p192);
209         ecdh_nist_p192_registered = ret == 0;
210 
211         ret = crypto_register_kpp(&ecdh_nist_p256);
212         if (ret)
213                 goto nist_p256_error;
214 
215         ret = crypto_register_kpp(&ecdh_nist_p384);
216         if (ret)
217                 goto nist_p384_error;
218 
219         return 0;
220 
221 nist_p384_error:
222         crypto_unregister_kpp(&ecdh_nist_p256);
223 
224 nist_p256_error:
225         if (ecdh_nist_p192_registered)
226                 crypto_unregister_kpp(&ecdh_nist_p192);
227         return ret;
228 }
229 
230 static void ecdh_exit(void)
231 {
232         if (ecdh_nist_p192_registered)
233                 crypto_unregister_kpp(&ecdh_nist_p192);
234         crypto_unregister_kpp(&ecdh_nist_p256);
235         crypto_unregister_kpp(&ecdh_nist_p384);
236 }
237 
238 subsys_initcall(ecdh_init);
239 module_exit(ecdh_exit);
240 MODULE_ALIAS_CRYPTO("ecdh");
241 MODULE_LICENSE("GPL");
242 MODULE_DESCRIPTION("ECDH generic algorithm");
243 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp