Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR MIT
0002 /*
0003  * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
0004  *
0005  * Based on public domain code from Daniel J. Bernstein and Peter Schwabe. This
0006  * began from SUPERCOP's curve25519/neon2/scalarmult.s, but has subsequently been
0007  * manually reworked for use in kernel space.
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     /* might want less than we've got */
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");