crypto: curve25519 - implement generic KPP driver
authorArd Biesheuvel <ardb@kernel.org>
Fri, 8 Nov 2019 12:22:34 +0000 (13:22 +0100)
committerHerbert Xu <herbert@gondor.apana.org.au>
Sun, 17 Nov 2019 01:02:43 +0000 (09:02 +0800)
Expose the generic Curve25519 library via the crypto API KPP interface.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
crypto/Kconfig
crypto/Makefile
crypto/curve25519-generic.c [new file with mode: 0644]

index 64cc4a93b51ca4be494ba0766576899535b9805a..fab259d9d05661f20e242437981c8ddcd45ecb13 100644 (file)
@@ -264,6 +264,11 @@ config CRYPTO_ECRDSA
          standard algorithms (called GOST algorithms). Only signature verification
          is implemented.
 
+config CRYPTO_CURVE25519
+       tristate "Curve25519 algorithm"
+       select CRYPTO_KPP
+       select CRYPTO_LIB_CURVE25519_GENERIC
+
 comment "Authenticated Encryption with Associated Data"
 
 config CRYPTO_CCM
index 9995527c4be7eb6586aeb78d6526710ea3e68ce5..d627ec4e05224443dd7bd4955e51aa64688a7362 100644 (file)
@@ -168,6 +168,7 @@ obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o
 obj-$(CONFIG_CRYPTO_OFB) += ofb.o
 obj-$(CONFIG_CRYPTO_ECC) += ecc.o
 obj-$(CONFIG_CRYPTO_ESSIV) += essiv.o
+obj-$(CONFIG_CRYPTO_CURVE25519) += curve25519-generic.o
 
 ecdh_generic-y += ecdh.o
 ecdh_generic-y += ecdh_helper.o
diff --git a/crypto/curve25519-generic.c b/crypto/curve25519-generic.c
new file mode 100644 (file)
index 0000000..bd88fd5
--- /dev/null
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <crypto/curve25519.h>
+#include <crypto/internal/kpp.h>
+#include <crypto/kpp.h>
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+
+static int curve25519_set_secret(struct crypto_kpp *tfm, const void *buf,
+                                unsigned int len)
+{
+       u8 *secret = kpp_tfm_ctx(tfm);
+
+       if (!len)
+               curve25519_generate_secret(secret);
+       else if (len == CURVE25519_KEY_SIZE &&
+                crypto_memneq(buf, curve25519_null_point, CURVE25519_KEY_SIZE))
+               memcpy(secret, buf, CURVE25519_KEY_SIZE);
+       else
+               return -EINVAL;
+       return 0;
+}
+
+static int curve25519_compute_value(struct kpp_request *req)
+{
+       struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
+       const u8 *secret = kpp_tfm_ctx(tfm);
+       u8 public_key[CURVE25519_KEY_SIZE];
+       u8 buf[CURVE25519_KEY_SIZE];
+       int copied, nbytes;
+       u8 const *bp;
+
+       if (req->src) {
+               copied = sg_copy_to_buffer(req->src,
+                                          sg_nents_for_len(req->src,
+                                                           CURVE25519_KEY_SIZE),
+                                          public_key, CURVE25519_KEY_SIZE);
+               if (copied != CURVE25519_KEY_SIZE)
+                       return -EINVAL;
+               bp = public_key;
+       } else {
+               bp = curve25519_base_point;
+       }
+
+       curve25519_generic(buf, secret, bp);
+
+       /* might want less than we've got */
+       nbytes = min_t(size_t, CURVE25519_KEY_SIZE, req->dst_len);
+       copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst,
+                                                               nbytes),
+                                    buf, nbytes);
+       if (copied != nbytes)
+               return -EINVAL;
+       return 0;
+}
+
+static unsigned int curve25519_max_size(struct crypto_kpp *tfm)
+{
+       return CURVE25519_KEY_SIZE;
+}
+
+static struct kpp_alg curve25519_alg = {
+       .base.cra_name          = "curve25519",
+       .base.cra_driver_name   = "curve25519-generic",
+       .base.cra_priority      = 100,
+       .base.cra_module        = THIS_MODULE,
+       .base.cra_ctxsize       = CURVE25519_KEY_SIZE,
+
+       .set_secret             = curve25519_set_secret,
+       .generate_public_key    = curve25519_compute_value,
+       .compute_shared_secret  = curve25519_compute_value,
+       .max_size               = curve25519_max_size,
+};
+
+static int curve25519_init(void)
+{
+       return crypto_register_kpp(&curve25519_alg);
+}
+
+static void curve25519_exit(void)
+{
+       crypto_unregister_kpp(&curve25519_alg);
+}
+
+subsys_initcall(curve25519_init);
+module_exit(curve25519_exit);
+
+MODULE_ALIAS_CRYPTO("curve25519");
+MODULE_ALIAS_CRYPTO("curve25519-generic");
+MODULE_LICENSE("GPL");