diff options
author | Salvatore Benedetto <salvatore.benedetto@intel.com> | 2016-06-22 12:49:15 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2016-06-23 06:29:57 -0400 |
commit | 3c4b23901a0c766879dff680cd6bdab47bcdbbd2 (patch) | |
tree | 3bcc903dce759f69193f4b9fa638f1383d7323d3 /crypto/ecdh.c | |
parent | 802c7f1c84e4b5a6ac78635878041023fc5831b1 (diff) |
crypto: ecdh - Add ECDH software support
* Implement ECDH under kpp API
* Provide ECC software support for curve P-192 and
P-256.
* Add kpp test for ECDH with data generated by OpenSSL
Signed-off-by: Salvatore Benedetto <salvatore.benedetto@intel.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/ecdh.c')
-rw-r--r-- | crypto/ecdh.c | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/crypto/ecdh.c b/crypto/ecdh.c new file mode 100644 index 000000000000..d3a9eeca4b32 --- /dev/null +++ b/crypto/ecdh.c | |||
@@ -0,0 +1,151 @@ | |||
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 = 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"); | ||