1 /* 2 * ECDH helper functions - KPP wrappings 3 * 4 * Copyright (C) 2017 Intel Corporation 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation; 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 11 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 12 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. 13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY 14 * CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 * 19 * ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 20 * COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 21 * SOFTWARE IS DISCLAIMED. 22 */ 23 #include "ecdh_helper.h" 24 25 #include <linux/scatterlist.h> 26 #include <crypto/ecdh.h> 27 28 static inline void swap_digits(u64 *in, u64 *out, unsigned int ndigits) 29 { 30 int i; 31 32 for (i = 0; i < ndigits; i++) 33 out[i] = __swab64(in[ndigits - 1 - i]); 34 } 35 36 /* compute_ecdh_secret() - function assumes that the private key was 37 * already set. 38 * @tfm: KPP tfm handle allocated with crypto_alloc_kpp(). 39 * @public_key: pair's ecc public key. 40 * secret: memory where the ecdh computed shared secret will be saved. 41 * 42 * Return: zero on success; error code in case of error. 43 */ 44 int compute_ecdh_secret(struct crypto_kpp *tfm, const u8 public_key[64], 45 u8 secret[32]) 46 { 47 DECLARE_CRYPTO_WAIT(result); 48 struct kpp_request *req; 49 u8 *tmp; 50 struct scatterlist src, dst; 51 int err; 52 53 tmp = kmalloc(64, GFP_KERNEL); 54 if (!tmp) 55 return -ENOMEM; 56 57 req = kpp_request_alloc(tfm, GFP_KERNEL); 58 if (!req) { 59 err = -ENOMEM; 60 goto free_tmp; 61 } 62 63 swap_digits((u64 *)public_key, (u64 *)tmp, 4); /* x */ 64 swap_digits((u64 *)&public_key[32], (u64 *)&tmp[32], 4); /* y */ 65 66 sg_init_one(&src, tmp, 64); 67 sg_init_one(&dst, secret, 32); 68 kpp_request_set_input(req, &src, 64); 69 kpp_request_set_output(req, &dst, 32); 70 kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, 71 crypto_req_done, &result); 72 err = crypto_kpp_compute_shared_secret(req); 73 err = crypto_wait_req(err, &result); 74 if (err < 0) { 75 pr_err("alg: ecdh: compute shared secret failed. err %d\n", 76 err); 77 goto free_all; 78 } 79 80 swap_digits((u64 *)secret, (u64 *)tmp, 4); 81 memcpy(secret, tmp, 32); 82 83 free_all: 84 kpp_request_free(req); 85 free_tmp: 86 kfree_sensitive(tmp); 87 return err; 88 } 89 90 /* set_ecdh_privkey() - set or generate ecc private key. 91 * 92 * Function generates an ecc private key in the crypto subsystem when receiving 93 * a NULL private key or sets the received key when not NULL. 94 * 95 * @tfm: KPP tfm handle allocated with crypto_alloc_kpp(). 96 * @private_key: user's ecc private key. When not NULL, the key is expected 97 * in little endian format. 98 * 99 * Return: zero on success; error code in case of error. 100 */ 101 int set_ecdh_privkey(struct crypto_kpp *tfm, const u8 private_key[32]) 102 { 103 u8 *buf, *tmp = NULL; 104 unsigned int buf_len; 105 int err; 106 struct ecdh p = {0}; 107 108 if (private_key) { 109 tmp = kmalloc(32, GFP_KERNEL); 110 if (!tmp) 111 return -ENOMEM; 112 swap_digits((u64 *)private_key, (u64 *)tmp, 4); 113 p.key = tmp; 114 p.key_size = 32; 115 } 116 117 buf_len = crypto_ecdh_key_len(&p); 118 buf = kmalloc(buf_len, GFP_KERNEL); 119 if (!buf) { 120 err = -ENOMEM; 121 goto free_tmp; 122 } 123 124 err = crypto_ecdh_encode_key(buf, buf_len, &p); 125 if (err) 126 goto free_all; 127 128 err = crypto_kpp_set_secret(tfm, buf, buf_len); 129 /* fall through */ 130 free_all: 131 kfree_sensitive(buf); 132 free_tmp: 133 kfree_sensitive(tmp); 134 return err; 135 } 136 137 /* generate_ecdh_public_key() - function assumes that the private key was 138 * already set. 139 * 140 * @tfm: KPP tfm handle allocated with crypto_alloc_kpp(). 141 * @public_key: memory where the computed ecc public key will be saved. 142 * 143 * Return: zero on success; error code in case of error. 144 */ 145 int generate_ecdh_public_key(struct crypto_kpp *tfm, u8 public_key[64]) 146 { 147 DECLARE_CRYPTO_WAIT(result); 148 struct kpp_request *req; 149 u8 *tmp; 150 struct scatterlist dst; 151 int err; 152 153 tmp = kmalloc(64, GFP_KERNEL); 154 if (!tmp) 155 return -ENOMEM; 156 157 req = kpp_request_alloc(tfm, GFP_KERNEL); 158 if (!req) { 159 err = -ENOMEM; 160 goto free_tmp; 161 } 162 163 sg_init_one(&dst, tmp, 64); 164 kpp_request_set_input(req, NULL, 0); 165 kpp_request_set_output(req, &dst, 64); 166 kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, 167 crypto_req_done, &result); 168 169 err = crypto_kpp_generate_public_key(req); 170 err = crypto_wait_req(err, &result); 171 if (err < 0) 172 goto free_all; 173 174 /* The public key is handed back in little endian as expected by 175 * the Security Manager Protocol. 176 */ 177 swap_digits((u64 *)tmp, (u64 *)public_key, 4); /* x */ 178 swap_digits((u64 *)&tmp[32], (u64 *)&public_key[32], 4); /* y */ 179 180 free_all: 181 kpp_request_free(req); 182 free_tmp: 183 kfree(tmp); 184 return err; 185 } 186 187 /* generate_ecdh_keys() - generate ecc key pair. 188 * 189 * @tfm: KPP tfm handle allocated with crypto_alloc_kpp(). 190 * @public_key: memory where the computed ecc public key will be saved. 191 * 192 * Return: zero on success; error code in case of error. 193 */ 194 int generate_ecdh_keys(struct crypto_kpp *tfm, u8 public_key[64]) 195 { 196 int err; 197 198 err = set_ecdh_privkey(tfm, NULL); 199 if (err) 200 return err; 201 202 return generate_ecdh_public_key(tfm, public_key); 203 } 204
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.