xref: /openbmc/linux/arch/arm/crypto/curve25519-glue.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
1d8f1308aSJason A. Donenfeld // SPDX-License-Identifier: GPL-2.0 OR MIT
2d8f1308aSJason A. Donenfeld /*
3d8f1308aSJason A. Donenfeld  * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
4d8f1308aSJason A. Donenfeld  *
5d8f1308aSJason A. Donenfeld  * Based on public domain code from Daniel J. Bernstein and Peter Schwabe. This
6d8f1308aSJason A. Donenfeld  * began from SUPERCOP's curve25519/neon2/scalarmult.s, but has subsequently been
7d8f1308aSJason A. Donenfeld  * manually reworked for use in kernel space.
8d8f1308aSJason A. Donenfeld  */
9d8f1308aSJason A. Donenfeld 
10d8f1308aSJason A. Donenfeld #include <asm/hwcap.h>
11d8f1308aSJason A. Donenfeld #include <asm/neon.h>
12d8f1308aSJason A. Donenfeld #include <asm/simd.h>
13d8f1308aSJason A. Donenfeld #include <crypto/internal/kpp.h>
14d8f1308aSJason A. Donenfeld #include <crypto/internal/simd.h>
15d8f1308aSJason A. Donenfeld #include <linux/types.h>
16d8f1308aSJason A. Donenfeld #include <linux/module.h>
17d8f1308aSJason A. Donenfeld #include <linux/init.h>
18d8f1308aSJason A. Donenfeld #include <linux/jump_label.h>
196779d0e6SFabio Estevam #include <linux/scatterlist.h>
20d8f1308aSJason A. Donenfeld #include <crypto/curve25519.h>
21d8f1308aSJason A. Donenfeld 
22d8f1308aSJason A. Donenfeld asmlinkage void curve25519_neon(u8 mypublic[CURVE25519_KEY_SIZE],
23d8f1308aSJason A. Donenfeld 				const u8 secret[CURVE25519_KEY_SIZE],
24d8f1308aSJason A. Donenfeld 				const u8 basepoint[CURVE25519_KEY_SIZE]);
25d8f1308aSJason A. Donenfeld 
26d8f1308aSJason A. Donenfeld static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon);
27d8f1308aSJason A. Donenfeld 
curve25519_arch(u8 out[CURVE25519_KEY_SIZE],const u8 scalar[CURVE25519_KEY_SIZE],const u8 point[CURVE25519_KEY_SIZE])28d8f1308aSJason A. Donenfeld void curve25519_arch(u8 out[CURVE25519_KEY_SIZE],
29d8f1308aSJason A. Donenfeld 		     const u8 scalar[CURVE25519_KEY_SIZE],
30d8f1308aSJason A. Donenfeld 		     const u8 point[CURVE25519_KEY_SIZE])
31d8f1308aSJason A. Donenfeld {
32d8f1308aSJason A. Donenfeld 	if (static_branch_likely(&have_neon) && crypto_simd_usable()) {
33d8f1308aSJason A. Donenfeld 		kernel_neon_begin();
34d8f1308aSJason A. Donenfeld 		curve25519_neon(out, scalar, point);
35d8f1308aSJason A. Donenfeld 		kernel_neon_end();
36d8f1308aSJason A. Donenfeld 	} else {
37d8f1308aSJason A. Donenfeld 		curve25519_generic(out, scalar, point);
38d8f1308aSJason A. Donenfeld 	}
39d8f1308aSJason A. Donenfeld }
40d8f1308aSJason A. Donenfeld EXPORT_SYMBOL(curve25519_arch);
41d8f1308aSJason A. Donenfeld 
curve25519_base_arch(u8 pub[CURVE25519_KEY_SIZE],const u8 secret[CURVE25519_KEY_SIZE])4284faa307SJason A. Donenfeld void curve25519_base_arch(u8 pub[CURVE25519_KEY_SIZE],
4384faa307SJason A. Donenfeld 			  const u8 secret[CURVE25519_KEY_SIZE])
4484faa307SJason A. Donenfeld {
4584faa307SJason A. Donenfeld 	return curve25519_arch(pub, secret, curve25519_base_point);
4684faa307SJason A. Donenfeld }
4784faa307SJason A. Donenfeld EXPORT_SYMBOL(curve25519_base_arch);
4884faa307SJason A. Donenfeld 
curve25519_set_secret(struct crypto_kpp * tfm,const void * buf,unsigned int len)49d8f1308aSJason A. Donenfeld static int curve25519_set_secret(struct crypto_kpp *tfm, const void *buf,
50d8f1308aSJason A. Donenfeld 				 unsigned int len)
51d8f1308aSJason A. Donenfeld {
52d8f1308aSJason A. Donenfeld 	u8 *secret = kpp_tfm_ctx(tfm);
53d8f1308aSJason A. Donenfeld 
54d8f1308aSJason A. Donenfeld 	if (!len)
55d8f1308aSJason A. Donenfeld 		curve25519_generate_secret(secret);
56d8f1308aSJason A. Donenfeld 	else if (len == CURVE25519_KEY_SIZE &&
57d8f1308aSJason A. Donenfeld 		 crypto_memneq(buf, curve25519_null_point, CURVE25519_KEY_SIZE))
58d8f1308aSJason A. Donenfeld 		memcpy(secret, buf, CURVE25519_KEY_SIZE);
59d8f1308aSJason A. Donenfeld 	else
60d8f1308aSJason A. Donenfeld 		return -EINVAL;
61d8f1308aSJason A. Donenfeld 	return 0;
62d8f1308aSJason A. Donenfeld }
63d8f1308aSJason A. Donenfeld 
curve25519_compute_value(struct kpp_request * req)64d8f1308aSJason A. Donenfeld static int curve25519_compute_value(struct kpp_request *req)
65d8f1308aSJason A. Donenfeld {
66d8f1308aSJason A. Donenfeld 	struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
67d8f1308aSJason A. Donenfeld 	const u8 *secret = kpp_tfm_ctx(tfm);
68d8f1308aSJason A. Donenfeld 	u8 public_key[CURVE25519_KEY_SIZE];
69d8f1308aSJason A. Donenfeld 	u8 buf[CURVE25519_KEY_SIZE];
70d8f1308aSJason A. Donenfeld 	int copied, nbytes;
71d8f1308aSJason A. Donenfeld 	u8 const *bp;
72d8f1308aSJason A. Donenfeld 
73d8f1308aSJason A. Donenfeld 	if (req->src) {
74d8f1308aSJason A. Donenfeld 		copied = sg_copy_to_buffer(req->src,
75d8f1308aSJason A. Donenfeld 					   sg_nents_for_len(req->src,
76d8f1308aSJason A. Donenfeld 							    CURVE25519_KEY_SIZE),
77d8f1308aSJason A. Donenfeld 					   public_key, CURVE25519_KEY_SIZE);
78d8f1308aSJason A. Donenfeld 		if (copied != CURVE25519_KEY_SIZE)
79d8f1308aSJason A. Donenfeld 			return -EINVAL;
80d8f1308aSJason A. Donenfeld 		bp = public_key;
81d8f1308aSJason A. Donenfeld 	} else {
82d8f1308aSJason A. Donenfeld 		bp = curve25519_base_point;
83d8f1308aSJason A. Donenfeld 	}
84d8f1308aSJason A. Donenfeld 
85d8f1308aSJason A. Donenfeld 	curve25519_arch(buf, secret, bp);
86d8f1308aSJason A. Donenfeld 
87d8f1308aSJason A. Donenfeld 	/* might want less than we've got */
88d8f1308aSJason A. Donenfeld 	nbytes = min_t(size_t, CURVE25519_KEY_SIZE, req->dst_len);
89d8f1308aSJason A. Donenfeld 	copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst,
90d8f1308aSJason A. Donenfeld 								nbytes),
91d8f1308aSJason A. Donenfeld 				     buf, nbytes);
92d8f1308aSJason A. Donenfeld 	if (copied != nbytes)
93d8f1308aSJason A. Donenfeld 		return -EINVAL;
94d8f1308aSJason A. Donenfeld 	return 0;
95d8f1308aSJason A. Donenfeld }
96d8f1308aSJason A. Donenfeld 
curve25519_max_size(struct crypto_kpp * tfm)97d8f1308aSJason A. Donenfeld static unsigned int curve25519_max_size(struct crypto_kpp *tfm)
98d8f1308aSJason A. Donenfeld {
99d8f1308aSJason A. Donenfeld 	return CURVE25519_KEY_SIZE;
100d8f1308aSJason A. Donenfeld }
101d8f1308aSJason A. Donenfeld 
102d8f1308aSJason A. Donenfeld static struct kpp_alg curve25519_alg = {
103d8f1308aSJason A. Donenfeld 	.base.cra_name		= "curve25519",
104d8f1308aSJason A. Donenfeld 	.base.cra_driver_name	= "curve25519-neon",
105d8f1308aSJason A. Donenfeld 	.base.cra_priority	= 200,
106d8f1308aSJason A. Donenfeld 	.base.cra_module	= THIS_MODULE,
107d8f1308aSJason A. Donenfeld 	.base.cra_ctxsize	= CURVE25519_KEY_SIZE,
108d8f1308aSJason A. Donenfeld 
109d8f1308aSJason A. Donenfeld 	.set_secret		= curve25519_set_secret,
110d8f1308aSJason A. Donenfeld 	.generate_public_key	= curve25519_compute_value,
111d8f1308aSJason A. Donenfeld 	.compute_shared_secret	= curve25519_compute_value,
112d8f1308aSJason A. Donenfeld 	.max_size		= curve25519_max_size,
113d8f1308aSJason A. Donenfeld };
114d8f1308aSJason A. Donenfeld 
arm_curve25519_init(void)115*cb5f09e8SRandy Dunlap static int __init arm_curve25519_init(void)
116d8f1308aSJason A. Donenfeld {
117d8f1308aSJason A. Donenfeld 	if (elf_hwcap & HWCAP_NEON) {
118d8f1308aSJason A. Donenfeld 		static_branch_enable(&have_neon);
1198394bfecSJason A. Donenfeld 		return IS_REACHABLE(CONFIG_CRYPTO_KPP) ?
1208394bfecSJason A. Donenfeld 			crypto_register_kpp(&curve25519_alg) : 0;
121d8f1308aSJason A. Donenfeld 	}
122d8f1308aSJason A. Donenfeld 	return 0;
123d8f1308aSJason A. Donenfeld }
124d8f1308aSJason A. Donenfeld 
arm_curve25519_exit(void)125*cb5f09e8SRandy Dunlap static void __exit arm_curve25519_exit(void)
126d8f1308aSJason A. Donenfeld {
1278394bfecSJason A. Donenfeld 	if (IS_REACHABLE(CONFIG_CRYPTO_KPP) && elf_hwcap & HWCAP_NEON)
128d8f1308aSJason A. Donenfeld 		crypto_unregister_kpp(&curve25519_alg);
129d8f1308aSJason A. Donenfeld }
130d8f1308aSJason A. Donenfeld 
131*cb5f09e8SRandy Dunlap module_init(arm_curve25519_init);
132*cb5f09e8SRandy Dunlap module_exit(arm_curve25519_exit);
133d8f1308aSJason A. Donenfeld 
134d8f1308aSJason A. Donenfeld MODULE_ALIAS_CRYPTO("curve25519");
135d8f1308aSJason A. Donenfeld MODULE_ALIAS_CRYPTO("curve25519-neon");
136d8f1308aSJason A. Donenfeld MODULE_LICENSE("GPL v2");
137