158771c1cSSalvatore Benedetto /*
258771c1cSSalvatore Benedetto * ECDH helper functions - KPP wrappings
358771c1cSSalvatore Benedetto *
458771c1cSSalvatore Benedetto * Copyright (C) 2017 Intel Corporation
558771c1cSSalvatore Benedetto *
658771c1cSSalvatore Benedetto * This program is free software; you can redistribute it and/or modify
758771c1cSSalvatore Benedetto * it under the terms of the GNU General Public License version 2 as
858771c1cSSalvatore Benedetto * published by the Free Software Foundation;
958771c1cSSalvatore Benedetto *
1058771c1cSSalvatore Benedetto * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1158771c1cSSalvatore Benedetto * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1258771c1cSSalvatore Benedetto * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
1358771c1cSSalvatore Benedetto * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
1458771c1cSSalvatore Benedetto * CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
1558771c1cSSalvatore Benedetto * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1658771c1cSSalvatore Benedetto * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1758771c1cSSalvatore Benedetto * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1858771c1cSSalvatore Benedetto *
1958771c1cSSalvatore Benedetto * ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
2058771c1cSSalvatore Benedetto * COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
2158771c1cSSalvatore Benedetto * SOFTWARE IS DISCLAIMED.
2258771c1cSSalvatore Benedetto */
2358771c1cSSalvatore Benedetto #include "ecdh_helper.h"
2458771c1cSSalvatore Benedetto
2558771c1cSSalvatore Benedetto #include <linux/scatterlist.h>
2658771c1cSSalvatore Benedetto #include <crypto/ecdh.h>
2758771c1cSSalvatore Benedetto
swap_digits(u64 * in,u64 * out,unsigned int ndigits)2858771c1cSSalvatore Benedetto static inline void swap_digits(u64 *in, u64 *out, unsigned int ndigits)
2958771c1cSSalvatore Benedetto {
3058771c1cSSalvatore Benedetto int i;
3158771c1cSSalvatore Benedetto
3258771c1cSSalvatore Benedetto for (i = 0; i < ndigits; i++)
3358771c1cSSalvatore Benedetto out[i] = __swab64(in[ndigits - 1 - i]);
3458771c1cSSalvatore Benedetto }
3558771c1cSSalvatore Benedetto
36c0153b0bSTudor Ambarus /* compute_ecdh_secret() - function assumes that the private key was
37c0153b0bSTudor Ambarus * already set.
38c0153b0bSTudor Ambarus * @tfm: KPP tfm handle allocated with crypto_alloc_kpp().
39c0153b0bSTudor Ambarus * @public_key: pair's ecc public key.
40c0153b0bSTudor Ambarus * secret: memory where the ecdh computed shared secret will be saved.
41c0153b0bSTudor Ambarus *
42c0153b0bSTudor Ambarus * Return: zero on success; error code in case of error.
43c0153b0bSTudor Ambarus */
compute_ecdh_secret(struct crypto_kpp * tfm,const u8 public_key[64],u8 secret[32])44a2976416STudor Ambarus int compute_ecdh_secret(struct crypto_kpp *tfm, const u8 public_key[64],
45c0153b0bSTudor Ambarus u8 secret[32])
4658771c1cSSalvatore Benedetto {
47*fe93d841SHerbert Xu DECLARE_CRYPTO_WAIT(result);
4858771c1cSSalvatore Benedetto struct kpp_request *req;
49c0153b0bSTudor Ambarus u8 *tmp;
5058771c1cSSalvatore Benedetto struct scatterlist src, dst;
51a2976416STudor Ambarus int err;
5258771c1cSSalvatore Benedetto
53763d9a30SSalvatore Benedetto tmp = kmalloc(64, GFP_KERNEL);
54763d9a30SSalvatore Benedetto if (!tmp)
55a2976416STudor Ambarus return -ENOMEM;
56763d9a30SSalvatore Benedetto
5758771c1cSSalvatore Benedetto req = kpp_request_alloc(tfm, GFP_KERNEL);
58a2976416STudor Ambarus if (!req) {
59a2976416STudor Ambarus err = -ENOMEM;
6047eb2ac8STudor Ambarus goto free_tmp;
61a2976416STudor Ambarus }
6258771c1cSSalvatore Benedetto
6358771c1cSSalvatore Benedetto swap_digits((u64 *)public_key, (u64 *)tmp, 4); /* x */
6458771c1cSSalvatore Benedetto swap_digits((u64 *)&public_key[32], (u64 *)&tmp[32], 4); /* y */
6558771c1cSSalvatore Benedetto
6658771c1cSSalvatore Benedetto sg_init_one(&src, tmp, 64);
6758771c1cSSalvatore Benedetto sg_init_one(&dst, secret, 32);
6858771c1cSSalvatore Benedetto kpp_request_set_input(req, &src, 64);
6958771c1cSSalvatore Benedetto kpp_request_set_output(req, &dst, 32);
7058771c1cSSalvatore Benedetto kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
71*fe93d841SHerbert Xu crypto_req_done, &result);
7258771c1cSSalvatore Benedetto err = crypto_kpp_compute_shared_secret(req);
73*fe93d841SHerbert Xu err = crypto_wait_req(err, &result);
7458771c1cSSalvatore Benedetto if (err < 0) {
7558771c1cSSalvatore Benedetto pr_err("alg: ecdh: compute shared secret failed. err %d\n",
7658771c1cSSalvatore Benedetto err);
7758771c1cSSalvatore Benedetto goto free_all;
7858771c1cSSalvatore Benedetto }
7958771c1cSSalvatore Benedetto
8058771c1cSSalvatore Benedetto swap_digits((u64 *)secret, (u64 *)tmp, 4);
8158771c1cSSalvatore Benedetto memcpy(secret, tmp, 32);
8258771c1cSSalvatore Benedetto
8358771c1cSSalvatore Benedetto free_all:
8458771c1cSSalvatore Benedetto kpp_request_free(req);
85763d9a30SSalvatore Benedetto free_tmp:
86453431a5SWaiman Long kfree_sensitive(tmp);
87a2976416STudor Ambarus return err;
8858771c1cSSalvatore Benedetto }
8958771c1cSSalvatore Benedetto
90c0153b0bSTudor Ambarus /* set_ecdh_privkey() - set or generate ecc private key.
91c0153b0bSTudor Ambarus *
92c0153b0bSTudor Ambarus * Function generates an ecc private key in the crypto subsystem when receiving
93c0153b0bSTudor Ambarus * a NULL private key or sets the received key when not NULL.
94c0153b0bSTudor Ambarus *
95c0153b0bSTudor Ambarus * @tfm: KPP tfm handle allocated with crypto_alloc_kpp().
96c0153b0bSTudor Ambarus * @private_key: user's ecc private key. When not NULL, the key is expected
97c0153b0bSTudor Ambarus * in little endian format.
98c0153b0bSTudor Ambarus *
99c0153b0bSTudor Ambarus * Return: zero on success; error code in case of error.
100c0153b0bSTudor Ambarus */
set_ecdh_privkey(struct crypto_kpp * tfm,const u8 private_key[32])101c0153b0bSTudor Ambarus int set_ecdh_privkey(struct crypto_kpp *tfm, const u8 private_key[32])
10258771c1cSSalvatore Benedetto {
103c0153b0bSTudor Ambarus u8 *buf, *tmp = NULL;
10458771c1cSSalvatore Benedetto unsigned int buf_len;
105a2976416STudor Ambarus int err;
106c0153b0bSTudor Ambarus struct ecdh p = {0};
107c0153b0bSTudor Ambarus
108c0153b0bSTudor Ambarus if (private_key) {
109c0153b0bSTudor Ambarus tmp = kmalloc(32, GFP_KERNEL);
110c0153b0bSTudor Ambarus if (!tmp)
111c0153b0bSTudor Ambarus return -ENOMEM;
112c0153b0bSTudor Ambarus swap_digits((u64 *)private_key, (u64 *)tmp, 4);
113c0153b0bSTudor Ambarus p.key = tmp;
114c0153b0bSTudor Ambarus p.key_size = 32;
115c0153b0bSTudor Ambarus }
116c0153b0bSTudor Ambarus
117c0153b0bSTudor Ambarus buf_len = crypto_ecdh_key_len(&p);
118c0153b0bSTudor Ambarus buf = kmalloc(buf_len, GFP_KERNEL);
119c0153b0bSTudor Ambarus if (!buf) {
120c0153b0bSTudor Ambarus err = -ENOMEM;
121c0153b0bSTudor Ambarus goto free_tmp;
122c0153b0bSTudor Ambarus }
123c0153b0bSTudor Ambarus
124c0153b0bSTudor Ambarus err = crypto_ecdh_encode_key(buf, buf_len, &p);
125c0153b0bSTudor Ambarus if (err)
126c0153b0bSTudor Ambarus goto free_all;
127c0153b0bSTudor Ambarus
128c0153b0bSTudor Ambarus err = crypto_kpp_set_secret(tfm, buf, buf_len);
129c0153b0bSTudor Ambarus /* fall through */
130c0153b0bSTudor Ambarus free_all:
131453431a5SWaiman Long kfree_sensitive(buf);
132c0153b0bSTudor Ambarus free_tmp:
133453431a5SWaiman Long kfree_sensitive(tmp);
134c0153b0bSTudor Ambarus return err;
135c0153b0bSTudor Ambarus }
136c0153b0bSTudor Ambarus
137c0153b0bSTudor Ambarus /* generate_ecdh_public_key() - function assumes that the private key was
138c0153b0bSTudor Ambarus * already set.
139c0153b0bSTudor Ambarus *
140c0153b0bSTudor Ambarus * @tfm: KPP tfm handle allocated with crypto_alloc_kpp().
141c0153b0bSTudor Ambarus * @public_key: memory where the computed ecc public key will be saved.
142c0153b0bSTudor Ambarus *
143c0153b0bSTudor Ambarus * Return: zero on success; error code in case of error.
144c0153b0bSTudor Ambarus */
generate_ecdh_public_key(struct crypto_kpp * tfm,u8 public_key[64])145c0153b0bSTudor Ambarus int generate_ecdh_public_key(struct crypto_kpp *tfm, u8 public_key[64])
146c0153b0bSTudor Ambarus {
147*fe93d841SHerbert Xu DECLARE_CRYPTO_WAIT(result);
148c0153b0bSTudor Ambarus struct kpp_request *req;
149c0153b0bSTudor Ambarus u8 *tmp;
150c0153b0bSTudor Ambarus struct scatterlist dst;
151c0153b0bSTudor Ambarus int err;
15258771c1cSSalvatore Benedetto
153763d9a30SSalvatore Benedetto tmp = kmalloc(64, GFP_KERNEL);
154763d9a30SSalvatore Benedetto if (!tmp)
155a2976416STudor Ambarus return -ENOMEM;
156763d9a30SSalvatore Benedetto
15758771c1cSSalvatore Benedetto req = kpp_request_alloc(tfm, GFP_KERNEL);
158a2976416STudor Ambarus if (!req) {
159a2976416STudor Ambarus err = -ENOMEM;
16047eb2ac8STudor Ambarus goto free_tmp;
161a2976416STudor Ambarus }
16258771c1cSSalvatore Benedetto
16358771c1cSSalvatore Benedetto sg_init_one(&dst, tmp, 64);
164f9583153SMarcel Holtmann kpp_request_set_input(req, NULL, 0);
16558771c1cSSalvatore Benedetto kpp_request_set_output(req, &dst, 64);
16658771c1cSSalvatore Benedetto kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
167*fe93d841SHerbert Xu crypto_req_done, &result);
16858771c1cSSalvatore Benedetto
16958771c1cSSalvatore Benedetto err = crypto_kpp_generate_public_key(req);
170*fe93d841SHerbert Xu err = crypto_wait_req(err, &result);
17158771c1cSSalvatore Benedetto if (err < 0)
17258771c1cSSalvatore Benedetto goto free_all;
17358771c1cSSalvatore Benedetto
174c0153b0bSTudor Ambarus /* The public key is handed back in little endian as expected by
175c0153b0bSTudor Ambarus * the Security Manager Protocol.
17658771c1cSSalvatore Benedetto */
17758771c1cSSalvatore Benedetto swap_digits((u64 *)tmp, (u64 *)public_key, 4); /* x */
17858771c1cSSalvatore Benedetto swap_digits((u64 *)&tmp[32], (u64 *)&public_key[32], 4); /* y */
17958771c1cSSalvatore Benedetto
18058771c1cSSalvatore Benedetto free_all:
18158771c1cSSalvatore Benedetto kpp_request_free(req);
182763d9a30SSalvatore Benedetto free_tmp:
183763d9a30SSalvatore Benedetto kfree(tmp);
184a2976416STudor Ambarus return err;
18558771c1cSSalvatore Benedetto }
186c0153b0bSTudor Ambarus
187c0153b0bSTudor Ambarus /* generate_ecdh_keys() - generate ecc key pair.
188c0153b0bSTudor Ambarus *
189c0153b0bSTudor Ambarus * @tfm: KPP tfm handle allocated with crypto_alloc_kpp().
190c0153b0bSTudor Ambarus * @public_key: memory where the computed ecc public key will be saved.
191c0153b0bSTudor Ambarus *
192c0153b0bSTudor Ambarus * Return: zero on success; error code in case of error.
193c0153b0bSTudor Ambarus */
generate_ecdh_keys(struct crypto_kpp * tfm,u8 public_key[64])194c0153b0bSTudor Ambarus int generate_ecdh_keys(struct crypto_kpp *tfm, u8 public_key[64])
195c0153b0bSTudor Ambarus {
196c0153b0bSTudor Ambarus int err;
197c0153b0bSTudor Ambarus
198c0153b0bSTudor Ambarus err = set_ecdh_privkey(tfm, NULL);
199c0153b0bSTudor Ambarus if (err)
200c0153b0bSTudor Ambarus return err;
201c0153b0bSTudor Ambarus
202c0153b0bSTudor Ambarus return generate_ecdh_public_key(tfm, public_key);
203c0153b0bSTudor Ambarus }
204