blob: 3de289806d6784d0affcdc356d16a2fee3d31d65
1 | /* ECDH key-agreement protocol |
2 | * |
3 | * Copyright (c) 2016, Intel Corporation |
4 | * Authors: Salvator Benedetto <salvatore.benedetto@intel.com> |
5 | * |
6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public Licence |
8 | * as published by the Free Software Foundation; either version |
9 | * 2 of the Licence, or (at your option) any later version. |
10 | */ |
11 | |
12 | #include <linux/module.h> |
13 | #include <crypto/internal/kpp.h> |
14 | #include <crypto/kpp.h> |
15 | #include <crypto/ecdh.h> |
16 | #include <linux/scatterlist.h> |
17 | #include "ecc.h" |
18 | |
19 | struct ecdh_ctx { |
20 | unsigned int curve_id; |
21 | unsigned int ndigits; |
22 | u64 private_key[ECC_MAX_DIGITS]; |
23 | u64 public_key[2 * ECC_MAX_DIGITS]; |
24 | u64 shared_secret[ECC_MAX_DIGITS]; |
25 | }; |
26 | |
27 | static inline struct ecdh_ctx *ecdh_get_ctx(struct crypto_kpp *tfm) |
28 | { |
29 | return kpp_tfm_ctx(tfm); |
30 | } |
31 | |
32 | static unsigned int ecdh_supported_curve(unsigned int curve_id) |
33 | { |
34 | switch (curve_id) { |
35 | case ECC_CURVE_NIST_P192: return 3; |
36 | case ECC_CURVE_NIST_P256: return 4; |
37 | default: return 0; |
38 | } |
39 | } |
40 | |
41 | static int ecdh_set_secret(struct crypto_kpp *tfm, void *buf, unsigned int len) |
42 | { |
43 | struct ecdh_ctx *ctx = ecdh_get_ctx(tfm); |
44 | struct ecdh params; |
45 | unsigned int ndigits; |
46 | |
47 | if (crypto_ecdh_decode_key(buf, len, ¶ms) < 0) |
48 | return -EINVAL; |
49 | |
50 | ndigits = ecdh_supported_curve(params.curve_id); |
51 | if (!ndigits) |
52 | return -EINVAL; |
53 | |
54 | ctx->curve_id = params.curve_id; |
55 | ctx->ndigits = ndigits; |
56 | |
57 | if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits, |
58 | (const u8 *)params.key, params.key_size) < 0) |
59 | return -EINVAL; |
60 | |
61 | memcpy(ctx->private_key, params.key, params.key_size); |
62 | |
63 | return 0; |
64 | } |
65 | |
66 | static int ecdh_compute_value(struct kpp_request *req) |
67 | { |
68 | int ret = 0; |
69 | struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); |
70 | struct ecdh_ctx *ctx = ecdh_get_ctx(tfm); |
71 | size_t copied, nbytes; |
72 | void *buf; |
73 | |
74 | nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT; |
75 | |
76 | if (req->src) { |
77 | copied = sg_copy_to_buffer(req->src, 1, ctx->public_key, |
78 | 2 * nbytes); |
79 | if (copied != 2 * nbytes) |
80 | return -EINVAL; |
81 | |
82 | ret = crypto_ecdh_shared_secret(ctx->curve_id, ctx->ndigits, |
83 | (const u8 *)ctx->private_key, nbytes, |
84 | (const u8 *)ctx->public_key, 2 * nbytes, |
85 | (u8 *)ctx->shared_secret, nbytes); |
86 | |
87 | buf = ctx->shared_secret; |
88 | } else { |
89 | ret = ecdh_make_pub_key(ctx->curve_id, ctx->ndigits, |
90 | (const u8 *)ctx->private_key, nbytes, |
91 | (u8 *)ctx->public_key, |
92 | sizeof(ctx->public_key)); |
93 | buf = ctx->public_key; |
94 | /* Public part is a point thus it has both coordinates */ |
95 | nbytes *= 2; |
96 | } |
97 | |
98 | if (ret < 0) |
99 | return ret; |
100 | |
101 | copied = sg_copy_from_buffer(req->dst, 1, buf, nbytes); |
102 | if (copied != nbytes) |
103 | return -EINVAL; |
104 | |
105 | return ret; |
106 | } |
107 | |
108 | static int ecdh_max_size(struct crypto_kpp *tfm) |
109 | { |
110 | struct ecdh_ctx *ctx = ecdh_get_ctx(tfm); |
111 | int nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT; |
112 | |
113 | /* Public key is made of two coordinates */ |
114 | return 2 * nbytes; |
115 | } |
116 | |
117 | static void no_exit_tfm(struct crypto_kpp *tfm) |
118 | { |
119 | return; |
120 | } |
121 | |
122 | static struct kpp_alg ecdh = { |
123 | .set_secret = ecdh_set_secret, |
124 | .generate_public_key = ecdh_compute_value, |
125 | .compute_shared_secret = ecdh_compute_value, |
126 | .max_size = ecdh_max_size, |
127 | .exit = no_exit_tfm, |
128 | .base = { |
129 | .cra_name = "ecdh", |
130 | .cra_driver_name = "ecdh-generic", |
131 | .cra_priority = 100, |
132 | .cra_module = THIS_MODULE, |
133 | .cra_ctxsize = sizeof(struct ecdh_ctx), |
134 | }, |
135 | }; |
136 | |
137 | static int ecdh_init(void) |
138 | { |
139 | return crypto_register_kpp(&ecdh); |
140 | } |
141 | |
142 | static void ecdh_exit(void) |
143 | { |
144 | crypto_unregister_kpp(&ecdh); |
145 | } |
146 | |
147 | module_init(ecdh_init); |
148 | module_exit(ecdh_exit); |
149 | MODULE_ALIAS_CRYPTO("ecdh"); |
150 | MODULE_LICENSE("GPL"); |
151 | MODULE_DESCRIPTION("ECDH generic algorithm"); |
152 |