0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <asm/hwcap.h>
0011 #include <asm/neon.h>
0012 #include <asm/simd.h>
0013 #include <crypto/internal/kpp.h>
0014 #include <crypto/internal/simd.h>
0015 #include <linux/types.h>
0016 #include <linux/module.h>
0017 #include <linux/init.h>
0018 #include <linux/jump_label.h>
0019 #include <linux/scatterlist.h>
0020 #include <crypto/curve25519.h>
0021
0022 asmlinkage void curve25519_neon(u8 mypublic[CURVE25519_KEY_SIZE],
0023 const u8 secret[CURVE25519_KEY_SIZE],
0024 const u8 basepoint[CURVE25519_KEY_SIZE]);
0025
0026 static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon);
0027
0028 void curve25519_arch(u8 out[CURVE25519_KEY_SIZE],
0029 const u8 scalar[CURVE25519_KEY_SIZE],
0030 const u8 point[CURVE25519_KEY_SIZE])
0031 {
0032 if (static_branch_likely(&have_neon) && crypto_simd_usable()) {
0033 kernel_neon_begin();
0034 curve25519_neon(out, scalar, point);
0035 kernel_neon_end();
0036 } else {
0037 curve25519_generic(out, scalar, point);
0038 }
0039 }
0040 EXPORT_SYMBOL(curve25519_arch);
0041
0042 void curve25519_base_arch(u8 pub[CURVE25519_KEY_SIZE],
0043 const u8 secret[CURVE25519_KEY_SIZE])
0044 {
0045 return curve25519_arch(pub, secret, curve25519_base_point);
0046 }
0047 EXPORT_SYMBOL(curve25519_base_arch);
0048
0049 static int curve25519_set_secret(struct crypto_kpp *tfm, const void *buf,
0050 unsigned int len)
0051 {
0052 u8 *secret = kpp_tfm_ctx(tfm);
0053
0054 if (!len)
0055 curve25519_generate_secret(secret);
0056 else if (len == CURVE25519_KEY_SIZE &&
0057 crypto_memneq(buf, curve25519_null_point, CURVE25519_KEY_SIZE))
0058 memcpy(secret, buf, CURVE25519_KEY_SIZE);
0059 else
0060 return -EINVAL;
0061 return 0;
0062 }
0063
0064 static int curve25519_compute_value(struct kpp_request *req)
0065 {
0066 struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
0067 const u8 *secret = kpp_tfm_ctx(tfm);
0068 u8 public_key[CURVE25519_KEY_SIZE];
0069 u8 buf[CURVE25519_KEY_SIZE];
0070 int copied, nbytes;
0071 u8 const *bp;
0072
0073 if (req->src) {
0074 copied = sg_copy_to_buffer(req->src,
0075 sg_nents_for_len(req->src,
0076 CURVE25519_KEY_SIZE),
0077 public_key, CURVE25519_KEY_SIZE);
0078 if (copied != CURVE25519_KEY_SIZE)
0079 return -EINVAL;
0080 bp = public_key;
0081 } else {
0082 bp = curve25519_base_point;
0083 }
0084
0085 curve25519_arch(buf, secret, bp);
0086
0087
0088 nbytes = min_t(size_t, CURVE25519_KEY_SIZE, req->dst_len);
0089 copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst,
0090 nbytes),
0091 buf, nbytes);
0092 if (copied != nbytes)
0093 return -EINVAL;
0094 return 0;
0095 }
0096
0097 static unsigned int curve25519_max_size(struct crypto_kpp *tfm)
0098 {
0099 return CURVE25519_KEY_SIZE;
0100 }
0101
0102 static struct kpp_alg curve25519_alg = {
0103 .base.cra_name = "curve25519",
0104 .base.cra_driver_name = "curve25519-neon",
0105 .base.cra_priority = 200,
0106 .base.cra_module = THIS_MODULE,
0107 .base.cra_ctxsize = CURVE25519_KEY_SIZE,
0108
0109 .set_secret = curve25519_set_secret,
0110 .generate_public_key = curve25519_compute_value,
0111 .compute_shared_secret = curve25519_compute_value,
0112 .max_size = curve25519_max_size,
0113 };
0114
0115 static int __init arm_curve25519_init(void)
0116 {
0117 if (elf_hwcap & HWCAP_NEON) {
0118 static_branch_enable(&have_neon);
0119 return IS_REACHABLE(CONFIG_CRYPTO_KPP) ?
0120 crypto_register_kpp(&curve25519_alg) : 0;
0121 }
0122 return 0;
0123 }
0124
0125 static void __exit arm_curve25519_exit(void)
0126 {
0127 if (IS_REACHABLE(CONFIG_CRYPTO_KPP) && elf_hwcap & HWCAP_NEON)
0128 crypto_unregister_kpp(&curve25519_alg);
0129 }
0130
0131 module_init(arm_curve25519_init);
0132 module_exit(arm_curve25519_exit);
0133
0134 MODULE_ALIAS_CRYPTO("curve25519");
0135 MODULE_ALIAS_CRYPTO("curve25519-neon");
0136 MODULE_LICENSE("GPL v2");