linux-crypto.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/6] Add support for ECDSA algorithm
@ 2017-01-20 11:35 Nitin Kumbhar
  2017-01-20 11:35 ` [PATCH 1/6] crypto: ecc: separate out ecc and ecdh Nitin Kumbhar
                   ` (6 more replies)
  0 siblings, 7 replies; 20+ messages in thread
From: Nitin Kumbhar @ 2017-01-20 11:35 UTC (permalink / raw)
  To: herbert, davem; +Cc: linux-crypto, Nitin Kumbhar

Hello,

This patch series adds support for Elliptic Curve Digital Signature
Algorithm (ECDSA). To reuse existing ECC functionality, which is
added as part of ECDH, it separates out ECC and ECDH so that
only ECC functionality is available for ECDSA even when ECDH is in
a disabled state.

Patch #1 restructures ECC and ECDH code such that ECC is not
dependent on ECDH config.

Patches #2 & #3 add vli and ecc functions which are required
for other Elliptic curve algorithms like ECDSA and ECIES.

Patch #4 adds support for ECDSA. This has been validated for P192
and P256 elliptic curves.

Patches #5 and #6 add ECDSA tests to validate ECDSA functionality
and measure ECDSA performance.

Nitin Kumbhar (6):
  crypto: ecc: separate out ecc and ecdh
  crypto: ecc: add vli and ecc ops
  crypto: ecc: export vli and ecc ops
  crypto: ecdsa: add ECDSA SW implementation
  crypto: testmgr: add ECDSA tests
  crypto: tcrypt: add ECDSA test modes

 crypto/Kconfig            |   14 ++
 crypto/Makefile           |    8 +-
 crypto/ecc.c              |  415 ++++++++++++++++++++++++++++-------------
 crypto/ecc.h              |   98 ++++++----
 crypto/ecc_curve_defs.h   |   51 +----
 crypto/ecc_ecdh.h         |   54 ++++++
 crypto/ecdh.c             |    4 +-
 crypto/ecdh_helper.c      |   94 ++++++++++
 crypto/ecdsa.c            |  331 +++++++++++++++++++++++++++++++++
 crypto/ecdsa_helper.c     |  116 ++++++++++++
 crypto/tcrypt.c           |  250 ++++++++++++++++++++++++-
 crypto/tcrypt.h           |  122 ++++++++++++
 crypto/testmgr.c          |  452 ++++++++++++++++++++++++++++++++++++++++++++-
 crypto/testmgr.h          |  140 ++++++++++++++
 include/crypto/akcipher.h |    5 +-
 include/crypto/ecc.h      |   24 +++
 include/crypto/ecdh.h     |   10 +-
 include/crypto/ecdsa.h    |   29 +++
 18 files changed, 1984 insertions(+), 233 deletions(-)
 create mode 100644 crypto/ecc_ecdh.h
 create mode 100644 crypto/ecdsa.c
 create mode 100644 crypto/ecdsa_helper.c
 create mode 100644 include/crypto/ecc.h
 create mode 100644 include/crypto/ecdsa.h

-- 
1.7.6.3

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 1/6] crypto: ecc: separate out ecc and ecdh
  2017-01-20 11:35 [PATCH 0/6] Add support for ECDSA algorithm Nitin Kumbhar
@ 2017-01-20 11:35 ` Nitin Kumbhar
  2017-01-20 11:35 ` [PATCH 2/6] crypto: ecc: add vli and ecc ops Nitin Kumbhar
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 20+ messages in thread
From: Nitin Kumbhar @ 2017-01-20 11:35 UTC (permalink / raw)
  To: herbert, davem; +Cc: linux-crypto, Nitin Kumbhar

Add ECC operations i.e. vli and ecc point ops as a separate
module under CRYPTO_ECC kconfig. This allows other ECC
algorithms like ECDSA & ECIES to reuse these ops even when ECDH
is disabled with CRYPTO_ECDH kconfig.

With these changes, ECDH specific functions are consolidated
as ECDH helper routines and ECC curves are moved to ECC specific
files.

Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
---
 crypto/Kconfig          |    7 +++
 crypto/Makefile         |    5 +-
 crypto/ecc.c            |  133 ++++++++++++++--------------------------------
 crypto/ecc.h            |   45 ++--------------
 crypto/ecc_curve_defs.h |   51 ++++--------------
 crypto/ecc_ecdh.h       |   54 +++++++++++++++++++
 crypto/ecdh.c           |    4 +-
 crypto/ecdh_helper.c    |   94 +++++++++++++++++++++++++++++++++
 include/crypto/ecc.h    |   24 +++++++++
 include/crypto/ecdh.h   |   10 +---
 10 files changed, 243 insertions(+), 184 deletions(-)
 create mode 100644 crypto/ecc_ecdh.h
 create mode 100644 include/crypto/ecc.h

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 160f08e721cc..e240075d6f46 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -127,9 +127,16 @@ config CRYPTO_DH
 	help
 	  Generic implementation of the Diffie-Hellman algorithm.
 
+config CRYPTO_ECC
+	tristate "ECC functions"
+	help
+	  Implementation of ECC functions
+
+
 config CRYPTO_ECDH
 	tristate "ECDH algorithm"
 	select CRYTPO_KPP
+	select CRYPTO_ECC
 	help
 	  Generic implementation of the ECDH algorithm
 
diff --git a/crypto/Makefile b/crypto/Makefile
index b8f0e3eb0791..827740a47a37 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -33,8 +33,9 @@ obj-$(CONFIG_CRYPTO_KPP2) += kpp.o
 dh_generic-y := dh.o
 dh_generic-y += dh_helper.o
 obj-$(CONFIG_CRYPTO_DH) += dh_generic.o
-ecdh_generic-y := ecc.o
-ecdh_generic-y += ecdh.o
+
+obj-$(CONFIG_CRYPTO_ECC) += ecc.o
+ecdh_generic-y := ecdh.o
 ecdh_generic-y += ecdh_helper.o
 obj-$(CONFIG_CRYPTO_ECDH) += ecdh_generic.o
 
diff --git a/crypto/ecc.c b/crypto/ecc.c
index 414c78a9c214..a8c10e725138 100644
--- a/crypto/ecc.c
+++ b/crypto/ecc.c
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2013, Kenneth MacKay
  * All rights reserved.
+ * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -28,16 +29,54 @@
 #include <linux/slab.h>
 #include <linux/swab.h>
 #include <linux/fips.h>
-#include <crypto/ecdh.h>
 
 #include "ecc.h"
-#include "ecc_curve_defs.h"
 
 typedef struct {
 	u64 m_low;
 	u64 m_high;
 } uint128_t;
 
+/* NIST P-192 */
+static u64 nist_p192_g_x[] = { 0xF4FF0AFD82FF1012ull, 0x7CBF20EB43A18800ull,
+				0x188DA80EB03090F6ull };
+static u64 nist_p192_g_y[] = { 0x73F977A11E794811ull, 0x631011ED6B24CDD5ull,
+				0x07192B95FFC8DA78ull };
+static u64 nist_p192_p[] = { 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFEull,
+				0xFFFFFFFFFFFFFFFFull };
+static u64 nist_p192_n[] = { 0x146BC9B1B4D22831ull, 0xFFFFFFFF99DEF836ull,
+				0xFFFFFFFFFFFFFFFFull };
+static struct ecc_curve nist_p192 = {
+	.name = "nist_192",
+	.g = {
+		.x = nist_p192_g_x,
+		.y = nist_p192_g_y,
+		.ndigits = 3,
+	},
+	.p = nist_p192_p,
+	.n = nist_p192_n
+};
+
+/* NIST P-256 */
+static u64 nist_p256_g_x[] = { 0xF4A13945D898C296ull, 0x77037D812DEB33A0ull,
+				0xF8BCE6E563A440F2ull, 0x6B17D1F2E12C4247ull };
+static u64 nist_p256_g_y[] = { 0xCBB6406837BF51F5ull, 0x2BCE33576B315ECEull,
+				0x8EE7EB4A7C0F9E16ull, 0x4FE342E2FE1A7F9Bull };
+static u64 nist_p256_p[] = { 0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull,
+				0x0000000000000000ull, 0xFFFFFFFF00000001ull };
+static u64 nist_p256_n[] = { 0xF3B9CAC2FC632551ull, 0xBCE6FAADA7179E84ull,
+				0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00000000ull };
+static struct ecc_curve nist_p256 = {
+	.name = "nist_256",
+	.g = {
+		.x = nist_p256_g_x,
+		.y = nist_p256_g_y,
+		.ndigits = 4,
+	},
+	.p = nist_p256_p,
+	.n = nist_p256_n
+};
+
 static inline const struct ecc_curve *ecc_get_curve(unsigned int curve_id)
 {
 	switch (curve_id) {
@@ -926,93 +965,3 @@ int ecc_is_key_valid(unsigned int curve_id, unsigned int ndigits,
 
 	return 0;
 }
-
-int ecdh_make_pub_key(unsigned int curve_id, unsigned int ndigits,
-		      const u8 *private_key, unsigned int private_key_len,
-		      u8 *public_key, unsigned int public_key_len)
-{
-	int ret = 0;
-	struct ecc_point *pk;
-	u64 priv[ndigits];
-	unsigned int nbytes;
-	const struct ecc_curve *curve = ecc_get_curve(curve_id);
-
-	if (!private_key || !curve) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	ecc_swap_digits((const u64 *)private_key, priv, ndigits);
-
-	pk = ecc_alloc_point(ndigits);
-	if (!pk) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	ecc_point_mult(pk, &curve->g, priv, NULL, curve->p, ndigits);
-	if (ecc_point_is_zero(pk)) {
-		ret = -EAGAIN;
-		goto err_free_point;
-	}
-
-	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
-	ecc_swap_digits(pk->x, (u64 *)public_key, ndigits);
-	ecc_swap_digits(pk->y, (u64 *)&public_key[nbytes], ndigits);
-
-err_free_point:
-	ecc_free_point(pk);
-out:
-	return ret;
-}
-
-int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits,
-		       const u8 *private_key, unsigned int private_key_len,
-		       const u8 *public_key, unsigned int public_key_len,
-		       u8 *secret, unsigned int secret_len)
-{
-	int ret = 0;
-	struct ecc_point *product, *pk;
-	u64 priv[ndigits];
-	u64 rand_z[ndigits];
-	unsigned int nbytes;
-	const struct ecc_curve *curve = ecc_get_curve(curve_id);
-
-	if (!private_key || !public_key || !curve) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
-
-	get_random_bytes(rand_z, nbytes);
-
-	pk = ecc_alloc_point(ndigits);
-	if (!pk) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	product = ecc_alloc_point(ndigits);
-	if (!product) {
-		ret = -ENOMEM;
-		goto err_alloc_product;
-	}
-
-	ecc_swap_digits((const u64 *)public_key, pk->x, ndigits);
-	ecc_swap_digits((const u64 *)&public_key[nbytes], pk->y, ndigits);
-	ecc_swap_digits((const u64 *)private_key, priv, ndigits);
-
-	ecc_point_mult(product, pk, priv, rand_z, curve->p, ndigits);
-
-	ecc_swap_digits(product->x, (u64 *)secret, ndigits);
-
-	if (ecc_point_is_zero(product))
-		ret = -EFAULT;
-
-	ecc_free_point(product);
-err_alloc_product:
-	ecc_free_point(pk);
-out:
-	return ret;
-}
diff --git a/crypto/ecc.h b/crypto/ecc.h
index 663d598c7406..5db82223d485 100644
--- a/crypto/ecc.h
+++ b/crypto/ecc.h
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2013, Kenneth MacKay
  * All rights reserved.
+ * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -26,9 +27,9 @@
 #ifndef _CRYPTO_ECC_H
 #define _CRYPTO_ECC_H
 
-#define ECC_MAX_DIGITS	4 /* 256 */
+#include <crypto/ecc.h>
 
-#define ECC_DIGITS_TO_BYTES_SHIFT 3
+#include "ecc_curve_defs.h"
 
 /**
  * ecc_is_key_valid() - Validate a given ECDH private key
@@ -42,42 +43,4 @@
  */
 int ecc_is_key_valid(unsigned int curve_id, unsigned int ndigits,
 		     const u8 *private_key, unsigned int private_key_len);
-
-/**
- * ecdh_make_pub_key() - Compute an ECC public key
- *
- * @curve_id:		id representing the curve to use
- * @private_key:	pregenerated private key for the given curve
- * @private_key_len:	length of private_key
- * @public_key:		buffer for storing the public key generated
- * @public_key_len:	length of the public_key buffer
- *
- * Returns 0 if the public key was generated successfully, a negative value
- * if an error occurred.
- */
-int ecdh_make_pub_key(const unsigned int curve_id, unsigned int ndigits,
-		      const u8 *private_key, unsigned int private_key_len,
-		      u8 *public_key, unsigned int public_key_len);
-
-/**
- * crypto_ecdh_shared_secret() - Compute a shared secret
- *
- * @curve_id:		id representing the curve to use
- * @private_key:	private key of part A
- * @private_key_len:	length of private_key
- * @public_key:		public key of counterpart B
- * @public_key_len:	length of public_key
- * @secret:		buffer for storing the calculated shared secret
- * @secret_len:		length of the secret buffer
- *
- * Note: It is recommended that you hash the result of crypto_ecdh_shared_secret
- * before using it for symmetric encryption or HMAC.
- *
- * Returns 0 if the shared secret was generated successfully, a negative value
- * if an error occurred.
- */
-int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits,
-		       const u8 *private_key, unsigned int private_key_len,
-		       const u8 *public_key, unsigned int public_key_len,
-		       u8 *secret, unsigned int secret_len);
-#endif
+#endif /* _CRYPTO_ECC_H */
diff --git a/crypto/ecc_curve_defs.h b/crypto/ecc_curve_defs.h
index 03ae5f714028..baacf32bca16 100644
--- a/crypto/ecc_curve_defs.h
+++ b/crypto/ecc_curve_defs.h
@@ -1,3 +1,12 @@
+/*
+ * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
 #ifndef _CRYTO_ECC_CURVE_DEFS_H
 #define _CRYTO_ECC_CURVE_DEFS_H
 
@@ -14,44 +23,4 @@ struct ecc_curve {
 	u64 *n;
 };
 
-/* NIST P-192 */
-static u64 nist_p192_g_x[] = { 0xF4FF0AFD82FF1012ull, 0x7CBF20EB43A18800ull,
-				0x188DA80EB03090F6ull };
-static u64 nist_p192_g_y[] = { 0x73F977A11E794811ull, 0x631011ED6B24CDD5ull,
-				0x07192B95FFC8DA78ull };
-static u64 nist_p192_p[] = { 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFEull,
-				0xFFFFFFFFFFFFFFFFull };
-static u64 nist_p192_n[] = { 0x146BC9B1B4D22831ull, 0xFFFFFFFF99DEF836ull,
-				0xFFFFFFFFFFFFFFFFull };
-static struct ecc_curve nist_p192 = {
-	.name = "nist_192",
-	.g = {
-		.x = nist_p192_g_x,
-		.y = nist_p192_g_y,
-		.ndigits = 3,
-	},
-	.p = nist_p192_p,
-	.n = nist_p192_n
-};
-
-/* NIST P-256 */
-static u64 nist_p256_g_x[] = { 0xF4A13945D898C296ull, 0x77037D812DEB33A0ull,
-				0xF8BCE6E563A440F2ull, 0x6B17D1F2E12C4247ull };
-static u64 nist_p256_g_y[] = { 0xCBB6406837BF51F5ull, 0x2BCE33576B315ECEull,
-				0x8EE7EB4A7C0F9E16ull, 0x4FE342E2FE1A7F9Bull };
-static u64 nist_p256_p[] = { 0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull,
-				0x0000000000000000ull, 0xFFFFFFFF00000001ull };
-static u64 nist_p256_n[] = { 0xF3B9CAC2FC632551ull, 0xBCE6FAADA7179E84ull,
-				0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00000000ull };
-static struct ecc_curve nist_p256 = {
-	.name = "nist_256",
-	.g = {
-		.x = nist_p256_g_x,
-		.y = nist_p256_g_y,
-		.ndigits = 4,
-	},
-	.p = nist_p256_p,
-	.n = nist_p256_n
-};
-
-#endif
+#endif /* _CRYTO_ECC_CURVE_DEFS_H */
diff --git a/crypto/ecc_ecdh.h b/crypto/ecc_ecdh.h
new file mode 100644
index 000000000000..f77b1fe094c9
--- /dev/null
+++ b/crypto/ecc_ecdh.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013, Kenneth MacKay. All rights reserved.
+ * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#ifndef _CRYPTO_ECC_ECDH_H
+#define _CRYPTO_ECC_ECDH_H
+
+#include "ecc.h"
+
+/**
+ * ecdh_make_pub_key() - Compute an ECC public key
+ *
+ * @curve_id:		id representing the curve to use
+ * @private_key:	pregenerated private key for the given curve
+ * @private_key_len:	length of private_key
+ * @public_key:		buffer for storing the public key generated
+ * @public_key_len:	length of the public_key buffer
+ *
+ * Returns 0 if the public key was generated successfully, a negative value
+ * if an error occurred.
+ */
+int ecdh_make_pub_key(const unsigned int curve_id, unsigned int ndigits,
+		      const u8 *private_key, unsigned int private_key_len,
+		      u8 *public_key, unsigned int public_key_len);
+
+/**
+ * crypto_ecdh_shared_secret() - Compute a shared secret
+ *
+ * @curve_id:		id representing the curve to use
+ * @private_key:	private key of part A
+ * @private_key_len:	length of private_key
+ * @public_key:		public key of counterpart B
+ * @public_key_len:	length of public_key
+ * @secret:		buffer for storing the calculated shared secret
+ * @secret_len:		length of the secret buffer
+ *
+ * Note: It is recommended that you hash the result of crypto_ecdh_shared_secret
+ * before using it for symmetric encryption or HMAC.
+ *
+ * Returns 0 if the shared secret was generated successfully, a negative value
+ * if an error occurred.
+ */
+int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits,
+		       const u8 *private_key, unsigned int private_key_len,
+		       const u8 *public_key, unsigned int public_key_len,
+		       u8 *secret, unsigned int secret_len);
+
+#endif /* _CRYPTO_ECC_ECDH_H */
diff --git a/crypto/ecdh.c b/crypto/ecdh.c
index 3de289806d67..2b83ff3a4b9a 100644
--- a/crypto/ecdh.c
+++ b/crypto/ecdh.c
@@ -2,6 +2,7 @@
  *
  * Copyright (c) 2016, Intel Corporation
  * Authors: Salvator Benedetto <salvatore.benedetto@intel.com>
+ * Copyright (c) 2017, NVIDIA Corporation.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public Licence
@@ -14,7 +15,8 @@
 #include <crypto/kpp.h>
 #include <crypto/ecdh.h>
 #include <linux/scatterlist.h>
-#include "ecc.h"
+
+#include "ecc_ecdh.h"
 
 struct ecdh_ctx {
 	unsigned int curve_id;
diff --git a/crypto/ecdh_helper.c b/crypto/ecdh_helper.c
index 3cd8a2414e60..b3857f3bfcee 100644
--- a/crypto/ecdh_helper.c
+++ b/crypto/ecdh_helper.c
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2016, Intel Corporation
  * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com>
+ * Copyright (c) 2017, NVIDIA Corporation.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public Licence
@@ -11,9 +12,12 @@
 #include <linux/export.h>
 #include <linux/err.h>
 #include <linux/string.h>
+#include <linux/random.h>
 #include <crypto/ecdh.h>
 #include <crypto/kpp.h>
 
+#include "ecc_ecdh.h"
+
 #define ECDH_KPP_SECRET_MIN_SIZE (sizeof(struct kpp_secret) + 2 * sizeof(short))
 
 static inline u8 *ecdh_pack_data(void *dst, const void *src, size_t sz)
@@ -28,6 +32,96 @@
 	return src + sz;
 }
 
+int ecdh_make_pub_key(unsigned int curve_id, unsigned int ndigits,
+		      const u8 *private_key, unsigned int private_key_len,
+		      u8 *public_key, unsigned int public_key_len)
+{
+	int ret = 0;
+	struct ecc_point *pk;
+	u64 priv[ndigits];
+	unsigned int nbytes;
+	const struct ecc_curve *curve = ecc_get_curve(curve_id);
+
+	if (!private_key || !curve) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ecc_swap_digits((const u64 *)private_key, priv, ndigits);
+
+	pk = ecc_alloc_point(ndigits);
+	if (!pk) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ecc_point_mult(pk, &curve->g, priv, NULL, curve->p, ndigits);
+	if (ecc_point_is_zero(pk)) {
+		ret = -EAGAIN;
+		goto err_free_point;
+	}
+
+	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+	ecc_swap_digits(pk->x, (u64 *)public_key, ndigits);
+	ecc_swap_digits(pk->y, (u64 *)&public_key[nbytes], ndigits);
+
+err_free_point:
+	ecc_free_point(pk);
+out:
+	return ret;
+}
+
+int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits,
+		       const u8 *private_key, unsigned int private_key_len,
+		       const u8 *public_key, unsigned int public_key_len,
+		       u8 *secret, unsigned int secret_len)
+{
+	int ret = 0;
+	struct ecc_point *product, *pk;
+	u64 priv[ndigits];
+	u64 rand_z[ndigits];
+	unsigned int nbytes;
+	const struct ecc_curve *curve = ecc_get_curve(curve_id);
+
+	if (!private_key || !public_key || !curve) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+
+	get_random_bytes(rand_z, nbytes);
+
+	pk = ecc_alloc_point(ndigits);
+	if (!pk) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	product = ecc_alloc_point(ndigits);
+	if (!product) {
+		ret = -ENOMEM;
+		goto err_alloc_product;
+	}
+
+	ecc_swap_digits((const u64 *)public_key, pk->x, ndigits);
+	ecc_swap_digits((const u64 *)&public_key[nbytes], pk->y, ndigits);
+	ecc_swap_digits((const u64 *)private_key, priv, ndigits);
+
+	ecc_point_mult(product, pk, priv, rand_z, curve->p, ndigits);
+
+	ecc_swap_digits(product->x, (u64 *)secret, ndigits);
+
+	if (ecc_point_is_zero(product))
+		ret = -EFAULT;
+
+	ecc_free_point(product);
+err_alloc_product:
+	ecc_free_point(pk);
+out:
+	return ret;
+}
+
 int crypto_ecdh_key_len(const struct ecdh *params)
 {
 	return ECDH_KPP_SECRET_MIN_SIZE + params->key_size;
diff --git a/include/crypto/ecc.h b/include/crypto/ecc.h
new file mode 100644
index 000000000000..27957f805fd6
--- /dev/null
+++ b/include/crypto/ecc.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#ifndef _CRYPTO_ECC_
+#define _CRYPTO_ECC_
+
+/* Curves IDs */
+#define ECC_CURVE_NIST_P192	0x0001
+#define ECC_CURVE_NIST_P256	0x0002
+
+#define ECC_MAX_DIGITS	4 /* 256 */
+
+#define ECC_DIGITS_TO_BYTES_SHIFT 3
+
+#define ECC_MAX_DIGIT_BYTES (ECC_MAX_DIGITS << ECC_DIGITS_TO_BYTES_SHIFT)
+
+#endif /* _CRYPTO_ECC_ */
diff --git a/include/crypto/ecdh.h b/include/crypto/ecdh.h
index 03a64f62ba7a..c8556305acad 100644
--- a/include/crypto/ecdh.h
+++ b/include/crypto/ecdh.h
@@ -3,6 +3,7 @@
  *
  * Copyright (c) 2016, Intel Corporation
  * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com>
+ * Copyright (c) 2017, NVIDIA Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -13,24 +14,19 @@
 #ifndef _CRYPTO_ECDH_
 #define _CRYPTO_ECDH_
 
+#include <crypto/ecc.h>
+
 /**
  * DOC: ECDH Helper Functions
  *
  * To use ECDH with the KPP cipher API, the following data structure and
  * functions should be used.
  *
- * The ECC curves known to the ECDH implementation are specified in this
- * header file.
- *
  * To use ECDH with KPP, the following functions should be used to operate on
  * an ECDH private key. The packet private key that can be set with
  * the KPP API function call of crypto_kpp_set_secret.
  */
 
-/* Curves IDs */
-#define ECC_CURVE_NIST_P192	0x0001
-#define ECC_CURVE_NIST_P256	0x0002
-
 /**
  * struct ecdh - define an ECDH private key
  *
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 2/6] crypto: ecc: add vli and ecc ops
  2017-01-20 11:35 [PATCH 0/6] Add support for ECDSA algorithm Nitin Kumbhar
  2017-01-20 11:35 ` [PATCH 1/6] crypto: ecc: separate out ecc and ecdh Nitin Kumbhar
@ 2017-01-20 11:35 ` Nitin Kumbhar
  2017-01-20 11:35 ` [PATCH 3/6] crypto: ecc: export " Nitin Kumbhar
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 20+ messages in thread
From: Nitin Kumbhar @ 2017-01-20 11:35 UTC (permalink / raw)
  To: herbert, davem; +Cc: linux-crypto, Nitin Kumbhar

Add functions to copy vli from buffers, to print vli in
big endian format, for vli mod and mod multiplication ops
and ecc point addition.

Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
---
 crypto/ecc.c |  168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 168 insertions(+), 0 deletions(-)

diff --git a/crypto/ecc.c b/crypto/ecc.c
index a8c10e725138..6ad785c4c12a 100644
--- a/crypto/ecc.c
+++ b/crypto/ecc.c
@@ -208,6 +208,42 @@ static void vli_set(u64 *dest, const u64 *src, unsigned int ndigits)
 		dest[i] = src[i];
 }
 
+/* Copy from vli to buf.
+ * For buffers smaller than vli: copy only LSB nbytes from vli.
+ * For buffers larger than vli : fill up remaining buf with zeroes.
+ */
+void vli_copy_to_buf(u8 *dst_buf, unsigned int buf_len,
+		     const u64 *src_vli, unsigned int ndigits)
+{
+	unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+	u8 *vli = (u8 *)src_vli;
+	int i;
+
+	for (i = 0; i < buf_len && i < nbytes; i++)
+		dst_buf[i] = vli[i];
+
+	for (; i < buf_len; i++)
+		dst_buf[i] = 0;
+}
+
+/* Copy from buffer to vli.
+ * For buffers smaller than vli: fill up remaining vli with zeroes.
+ * For buffers larger than vli : copy only LSB nbytes to vli.
+ */
+void vli_copy_from_buf(u64 *dst_vli, unsigned int ndigits,
+		       const u8 *src_buf, unsigned int buf_len)
+{
+	unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+	u8 *vli = (u8 *)dst_vli;
+	int i;
+
+	for (i = 0; i < buf_len && i < nbytes; i++)
+		vli[i] = src_buf[i];
+
+	for (; i < nbytes; i++)
+		vli[i] = 0;
+}
+
 /* Returns sign of left - right. */
 static int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits)
 {
@@ -440,6 +476,83 @@ static void vli_mod_sub(u64 *result, const u64 *left, const u64 *right,
 		vli_add(result, result, mod, ndigits);
 }
 
+/* Computes result = input % mod.
+ * Assumes that input < mod, result != mod.
+ */
+void vli_mod(u64 *result, const u64 *input, const u64 *mod,
+	     unsigned int ndigits)
+{
+	if (vli_cmp(input, mod, ndigits) >= 0)
+		vli_sub(result, input, mod, ndigits);
+	else
+		vli_set(result, input, ndigits);
+}
+
+/* Print vli in big-endian format.
+ * The bytes are printed in hex.
+ */
+void vli_print(char *vli_name, const u64 *vli, unsigned int ndigits)
+{
+	int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+	int buf_size = 2 * ECC_MAX_DIGIT_BYTES + 1;
+	unsigned char *c, buf[buf_size];
+	int i, j;
+
+	c = (unsigned char *)vli;
+
+	for (i = nbytes - 1, j = 0; i >= 0 && j < buf_size; i--, j += 2)
+		snprintf(&buf[j], 3, "%02x", *(c + i));
+
+	buf[j] = '\0';
+
+	pr_info("%20s(BigEnd)=%s\n", vli_name, buf);
+}
+
+/* Computes result = (left * right) % mod.
+ * Assumes that left < mod and right < mod, result != mod.
+ * Uses:
+ *	(a * b) % m = ((a % m) * (b % m)) % m
+ *	(a * b) % m = (a + a + ... + a) % m = b modular additions of (a % m)
+ */
+void vli_mod_mult(u64 *result, const u64 *left, const u64 *right,
+		  const u64 *mod, unsigned int ndigits)
+{
+	u64 t1[ndigits], mm[ndigits];
+	u64 aa[ndigits], bb[ndigits];
+
+	vli_clear(result, ndigits);
+	vli_set(aa, left, ndigits);
+	vli_set(bb, right, ndigits);
+	vli_set(mm, mod, ndigits);
+
+	/* aa = aa % mm */
+	vli_mod(aa, aa, mm, ndigits);
+
+	/* bb = bb % mm */
+	vli_mod(bb, bb, mm, ndigits);
+
+	while (!vli_is_zero(bb, ndigits)) {
+
+		/* if bb is odd i.e. 0th bit set then add
+		 * aa i.e. result = (result + aa) % mm
+		 */
+		if (vli_test_bit(bb, 0))
+			vli_mod_add(result, result, aa, mm, ndigits);
+
+		/* bb = bb / 2 = bb >> 1 */
+		vli_rshift1(bb, ndigits);
+
+		/* aa = (aa * 2) % mm */
+		vli_sub(t1, mm, aa, ndigits);
+		if (vli_cmp(aa, t1, ndigits) == -1)
+			/* if aa < t1 then aa = aa * 2 = aa << 1*/
+			vli_lshift(aa, aa, 1, ndigits);
+		else
+			/* if aa >= t1 then aa = aa - t1 */
+			vli_sub(aa, aa, t1, ndigits);
+	}
+}
+
 /* Computes p_result = p_product % curve_p.
  * See algorithm 5 and 6 from
  * http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf
@@ -878,6 +991,61 @@ static void xycz_add_c(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime,
 	vli_set(x1, t7, ndigits);
 }
 
+/* Point addition.
+ * Add 2 distinct points on elliptic curve to get a new point.
+ *
+ * P = (x1,y1)and Q = (x2, y2) then P + Q = (x3,y3) where
+ * x3 = ((y2-y1)/(x2-x1))^2 - x1 - x2
+ * y3 = ((y2-y1)/(x2-x1))(x1-x3) - y1
+ *
+ * Q => P + Q
+ */
+void ecc_point_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime,
+		   unsigned int ndigits)
+{
+	/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
+	u64 t5[ndigits];
+	u64 t6[ndigits];
+	u64 t7[ndigits];
+
+	/* t6 = x2 - x1 */
+	vli_mod_sub(t6, x2, x1, curve_prime, ndigits);
+	/* t6 = (x2 - x1)^2 = A */
+	vli_mod_square_fast(t6, t6, curve_prime, ndigits);
+	vli_mod_inv(t7, t6, curve_prime, ndigits);
+	/* t5 = x2 - x1 */
+	vli_mod_sub(t5, x2, x1, curve_prime, ndigits);
+	/* t5 = (x2 - x1)^2 = A */
+	vli_mod_square_fast(t5, t5, curve_prime, ndigits);
+	/* t1 = x1*A = B = x1*(x2-x1)^2*/
+	vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits);
+	/* t3 = x2*A = C = x2*(x2-x1)^2*/
+	vli_mod_mult_fast(x2, x2, t5, curve_prime, ndigits);
+	/* t4 = y2 - y1 */
+	vli_mod_sub(y2, y2, y1, curve_prime, ndigits);
+	/* t5 = (y2 - y1)^2 = D */
+	vli_mod_square_fast(t5, y2, curve_prime, ndigits);
+
+	/* t5 = D - B = (y2 - y1)^2 - x1*(x2-x1)^2 */
+	vli_mod_sub(t5, t5, x1, curve_prime, ndigits);
+	/* t5 = D - B - C = x3 = (y2 - y1)^2 - x1*(x2-x1)^2 - x2*(x2-x1)^2*/
+	vli_mod_sub(t5, t5, x2, curve_prime, ndigits);
+
+	/* t3 = C - B = x2*(x2-x1)^2 - x1*(x2-x1)^2 */
+	vli_mod_sub(x2, x2, x1, curve_prime, ndigits);
+	/* t2 = y1*(C - B) = y1*(x2*(x2-x1)^2 - x1*(x2-x1)^2)*/
+	vli_mod_mult_fast(y1, y1, x2, curve_prime, ndigits);
+	/* t3 = B - x3 = x1*(x2-x1)^2 - x3*/
+	vli_mod_sub(x2, x1, t5, curve_prime, ndigits);
+	/* t4 = (y2 - y1)*(B - x3)  = (y2 - y1)*(x1*(x2-x1)^2 - x3)*/
+	vli_mod_mult_fast(y2, y2, x2, curve_prime, ndigits);
+	/* t4 = y3 = ((y2 - y1)*(x1*(x2-x1)^2 - x3)) - y1*/
+	vli_mod_sub(y2, y2, y1, curve_prime, ndigits);
+
+	vli_mod_mult_fast(t5, t5, t7,  curve_prime, ndigits);
+	vli_set(x2, t5, ndigits);
+}
+
 static void ecc_point_mult(struct ecc_point *result,
 			   const struct ecc_point *point, const u64 *scalar,
 			   u64 *initial_z, u64 *curve_prime,
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 3/6] crypto: ecc: export vli and ecc ops
  2017-01-20 11:35 [PATCH 0/6] Add support for ECDSA algorithm Nitin Kumbhar
  2017-01-20 11:35 ` [PATCH 1/6] crypto: ecc: separate out ecc and ecdh Nitin Kumbhar
  2017-01-20 11:35 ` [PATCH 2/6] crypto: ecc: add vli and ecc ops Nitin Kumbhar
@ 2017-01-20 11:35 ` Nitin Kumbhar
  2017-01-20 11:35 ` [PATCH 4/6] crypto: ecdsa: add ECDSA SW implementation Nitin Kumbhar
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 20+ messages in thread
From: Nitin Kumbhar @ 2017-01-20 11:35 UTC (permalink / raw)
  To: herbert, davem; +Cc: linux-crypto, Nitin Kumbhar

Export vli and ECC related functions so that these can
be used by all ECC algorithm modules like ECDH, ECDSA and ECIES.

Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
---
 crypto/ecc.c |  114 +++++++++++++++++++++++++++++++++++++---------------------
 crypto/ecc.h |   53 +++++++++++++++++++++++++++
 2 files changed, 126 insertions(+), 41 deletions(-)

diff --git a/crypto/ecc.c b/crypto/ecc.c
index 6ad785c4c12a..c6fe1b7b998d 100644
--- a/crypto/ecc.c
+++ b/crypto/ecc.c
@@ -77,7 +77,7 @@
 	.n = nist_p256_n
 };
 
-static inline const struct ecc_curve *ecc_get_curve(unsigned int curve_id)
+const struct ecc_curve *ecc_get_curve(unsigned int curve_id)
 {
 	switch (curve_id) {
 	/* In FIPS mode only allow P256 and higher */
@@ -89,6 +89,7 @@
 		return NULL;
 	}
 }
+EXPORT_SYMBOL_GPL(ecc_get_curve);
 
 static u64 *ecc_alloc_digits_space(unsigned int ndigits)
 {
@@ -105,7 +106,7 @@ static void ecc_free_digits_space(u64 *space)
 	kzfree(space);
 }
 
-static struct ecc_point *ecc_alloc_point(unsigned int ndigits)
+struct ecc_point *ecc_alloc_point(unsigned int ndigits)
 {
 	struct ecc_point *p = kmalloc(sizeof(*p), GFP_KERNEL);
 
@@ -130,8 +131,9 @@ static void ecc_free_digits_space(u64 *space)
 	kfree(p);
 	return NULL;
 }
+EXPORT_SYMBOL_GPL(ecc_alloc_point);
 
-static void ecc_free_point(struct ecc_point *p)
+void ecc_free_point(struct ecc_point *p)
 {
 	if (!p)
 		return;
@@ -140,17 +142,19 @@ static void ecc_free_point(struct ecc_point *p)
 	kzfree(p->y);
 	kzfree(p);
 }
+EXPORT_SYMBOL_GPL(ecc_free_point);
 
-static void vli_clear(u64 *vli, unsigned int ndigits)
+void vli_clear(u64 *vli, unsigned int ndigits)
 {
 	int i;
 
 	for (i = 0; i < ndigits; i++)
 		vli[i] = 0;
 }
+EXPORT_SYMBOL_GPL(vli_clear);
 
 /* Returns true if vli == 0, false otherwise. */
-static bool vli_is_zero(const u64 *vli, unsigned int ndigits)
+bool vli_is_zero(const u64 *vli, unsigned int ndigits)
 {
 	int i;
 
@@ -161,15 +165,17 @@ static bool vli_is_zero(const u64 *vli, unsigned int ndigits)
 
 	return true;
 }
+EXPORT_SYMBOL_GPL(vli_is_zero);
 
 /* Returns nonzero if bit bit of vli is set. */
-static u64 vli_test_bit(const u64 *vli, unsigned int bit)
+u64 vli_test_bit(const u64 *vli, unsigned int bit)
 {
 	return (vli[bit / 64] & ((u64)1 << (bit % 64)));
 }
+EXPORT_SYMBOL_GPL(vli_test_bit);
 
 /* Counts the number of 64-bit "digits" in vli. */
-static unsigned int vli_num_digits(const u64 *vli, unsigned int ndigits)
+unsigned int vli_num_digits(const u64 *vli, unsigned int ndigits)
 {
 	int i;
 
@@ -181,9 +187,10 @@ static unsigned int vli_num_digits(const u64 *vli, unsigned int ndigits)
 
 	return (i + 1);
 }
+EXPORT_SYMBOL_GPL(vli_num_digits);
 
 /* Counts the number of bits required for vli. */
-static unsigned int vli_num_bits(const u64 *vli, unsigned int ndigits)
+unsigned int vli_num_bits(const u64 *vli, unsigned int ndigits)
 {
 	unsigned int i, num_digits;
 	u64 digit;
@@ -198,15 +205,17 @@ static unsigned int vli_num_bits(const u64 *vli, unsigned int ndigits)
 
 	return ((num_digits - 1) * 64 + i);
 }
+EXPORT_SYMBOL_GPL(vli_num_bits);
 
 /* Sets dest = src. */
-static void vli_set(u64 *dest, const u64 *src, unsigned int ndigits)
+void vli_set(u64 *dest, const u64 *src, unsigned int ndigits)
 {
 	int i;
 
 	for (i = 0; i < ndigits; i++)
 		dest[i] = src[i];
 }
+EXPORT_SYMBOL_GPL(vli_set);
 
 /* Copy from vli to buf.
  * For buffers smaller than vli: copy only LSB nbytes from vli.
@@ -225,6 +234,7 @@ void vli_copy_to_buf(u8 *dst_buf, unsigned int buf_len,
 	for (; i < buf_len; i++)
 		dst_buf[i] = 0;
 }
+EXPORT_SYMBOL_GPL(vli_copy_to_buf);
 
 /* Copy from buffer to vli.
  * For buffers smaller than vli: fill up remaining vli with zeroes.
@@ -243,9 +253,10 @@ void vli_copy_from_buf(u64 *dst_vli, unsigned int ndigits,
 	for (; i < nbytes; i++)
 		vli[i] = 0;
 }
+EXPORT_SYMBOL_GPL(vli_copy_from_buf);
 
 /* Returns sign of left - right. */
-static int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits)
+int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits)
 {
 	int i;
 
@@ -258,12 +269,13 @@ static int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(vli_cmp);
 
 /* Computes result = in << c, returning carry. Can modify in place
  * (if result == in). 0 < shift < 64.
  */
-static u64 vli_lshift(u64 *result, const u64 *in, unsigned int shift,
-		      unsigned int ndigits)
+u64 vli_lshift(u64 *result, const u64 *in, unsigned int shift,
+	       unsigned int ndigits)
 {
 	u64 carry = 0;
 	int i;
@@ -277,9 +289,10 @@ static u64 vli_lshift(u64 *result, const u64 *in, unsigned int shift,
 
 	return carry;
 }
+EXPORT_SYMBOL_GPL(vli_lshift);
 
 /* Computes vli = vli >> 1. */
-static void vli_rshift1(u64 *vli, unsigned int ndigits)
+void vli_rshift1(u64 *vli, unsigned int ndigits)
 {
 	u64 *end = vli;
 	u64 carry = 0;
@@ -292,10 +305,11 @@ static void vli_rshift1(u64 *vli, unsigned int ndigits)
 		carry = temp << 63;
 	}
 }
+EXPORT_SYMBOL_GPL(vli_rshift1);
 
 /* Computes result = left + right, returning carry. Can modify in place. */
-static u64 vli_add(u64 *result, const u64 *left, const u64 *right,
-		   unsigned int ndigits)
+u64 vli_add(u64 *result, const u64 *left, const u64 *right,
+	    unsigned int ndigits)
 {
 	u64 carry = 0;
 	int i;
@@ -312,10 +326,11 @@ static u64 vli_add(u64 *result, const u64 *left, const u64 *right,
 
 	return carry;
 }
+EXPORT_SYMBOL_GPL(vli_add);
 
 /* Computes result = left - right, returning borrow. Can modify in place. */
-static u64 vli_sub(u64 *result, const u64 *left, const u64 *right,
-		   unsigned int ndigits)
+u64 vli_sub(u64 *result, const u64 *left, const u64 *right,
+	    unsigned int ndigits)
 {
 	u64 borrow = 0;
 	int i;
@@ -332,6 +347,7 @@ static u64 vli_sub(u64 *result, const u64 *left, const u64 *right,
 
 	return borrow;
 }
+EXPORT_SYMBOL_GPL(vli_sub);
 
 static uint128_t mul_64_64(u64 left, u64 right)
 {
@@ -368,8 +384,8 @@ static uint128_t add_128_128(uint128_t a, uint128_t b)
 	return result;
 }
 
-static void vli_mult(u64 *result, const u64 *left, const u64 *right,
-		     unsigned int ndigits)
+void vli_mult(u64 *result, const u64 *left, const u64 *right,
+	      unsigned int ndigits)
 {
 	uint128_t r01 = { 0, 0 };
 	u64 r2 = 0;
@@ -403,8 +419,9 @@ static void vli_mult(u64 *result, const u64 *left, const u64 *right,
 
 	result[ndigits * 2 - 1] = r01.m_low;
 }
+EXPORT_SYMBOL_GPL(vli_mult);
 
-static void vli_square(u64 *result, const u64 *left, unsigned int ndigits)
+void vli_square(u64 *result, const u64 *left, unsigned int ndigits)
 {
 	uint128_t r01 = { 0, 0 };
 	u64 r2 = 0;
@@ -442,12 +459,13 @@ static void vli_square(u64 *result, const u64 *left, unsigned int ndigits)
 
 	result[ndigits * 2 - 1] = r01.m_low;
 }
+EXPORT_SYMBOL_GPL(vli_square);
 
 /* Computes result = (left + right) % mod.
  * Assumes that left < mod and right < mod, result != mod.
  */
-static void vli_mod_add(u64 *result, const u64 *left, const u64 *right,
-			const u64 *mod, unsigned int ndigits)
+void vli_mod_add(u64 *result, const u64 *left, const u64 *right,
+		 const u64 *mod, unsigned int ndigits)
 {
 	u64 carry;
 
@@ -459,12 +477,13 @@ static void vli_mod_add(u64 *result, const u64 *left, const u64 *right,
 	if (carry || vli_cmp(result, mod, ndigits) >= 0)
 		vli_sub(result, result, mod, ndigits);
 }
+EXPORT_SYMBOL_GPL(vli_mod_add);
 
 /* Computes result = (left - right) % mod.
  * Assumes that left < mod and right < mod, result != mod.
  */
-static void vli_mod_sub(u64 *result, const u64 *left, const u64 *right,
-			const u64 *mod, unsigned int ndigits)
+void vli_mod_sub(u64 *result, const u64 *left, const u64 *right,
+		 const u64 *mod, unsigned int ndigits)
 {
 	u64 borrow = vli_sub(result, left, right, ndigits);
 
@@ -475,6 +494,7 @@ static void vli_mod_sub(u64 *result, const u64 *left, const u64 *right,
 	if (borrow)
 		vli_add(result, result, mod, ndigits);
 }
+EXPORT_SYMBOL_GPL(vli_mod_sub);
 
 /* Computes result = input % mod.
  * Assumes that input < mod, result != mod.
@@ -487,6 +507,7 @@ void vli_mod(u64 *result, const u64 *input, const u64 *mod,
 	else
 		vli_set(result, input, ndigits);
 }
+EXPORT_SYMBOL_GPL(vli_mod);
 
 /* Print vli in big-endian format.
  * The bytes are printed in hex.
@@ -507,6 +528,7 @@ void vli_print(char *vli_name, const u64 *vli, unsigned int ndigits)
 
 	pr_info("%20s(BigEnd)=%s\n", vli_name, buf);
 }
+EXPORT_SYMBOL_GPL(vli_print);
 
 /* Computes result = (left * right) % mod.
  * Assumes that left < mod and right < mod, result != mod.
@@ -552,6 +574,7 @@ void vli_mod_mult(u64 *result, const u64 *left, const u64 *right,
 			vli_sub(aa, aa, t1, ndigits);
 	}
 }
+EXPORT_SYMBOL_GPL(vli_mod_mult);
 
 /* Computes p_result = p_product % curve_p.
  * See algorithm 5 and 6 from
@@ -663,8 +686,8 @@ static void vli_mmod_fast_256(u64 *result, const u64 *product,
 /* Computes result = product % curve_prime
  *  from http://www.nsa.gov/ia/_files/nist-routines.pdf
 */
-static bool vli_mmod_fast(u64 *result, u64 *product,
-			  const u64 *curve_prime, unsigned int ndigits)
+bool vli_mmod_fast(u64 *result, u64 *product,
+		   const u64 *curve_prime, unsigned int ndigits)
 {
 	u64 tmp[2 * ndigits];
 
@@ -682,34 +705,37 @@ static bool vli_mmod_fast(u64 *result, u64 *product,
 
 	return true;
 }
+EXPORT_SYMBOL_GPL(vli_mmod_fast);
 
 /* Computes result = (left * right) % curve_prime. */
-static void vli_mod_mult_fast(u64 *result, const u64 *left, const u64 *right,
-			      const u64 *curve_prime, unsigned int ndigits)
+void vli_mod_mult_fast(u64 *result, const u64 *left, const u64 *right,
+		       const u64 *curve_prime, unsigned int ndigits)
 {
 	u64 product[2 * ndigits];
 
 	vli_mult(product, left, right, ndigits);
 	vli_mmod_fast(result, product, curve_prime, ndigits);
 }
+EXPORT_SYMBOL_GPL(vli_mod_mult_fast);
 
 /* Computes result = left^2 % curve_prime. */
-static void vli_mod_square_fast(u64 *result, const u64 *left,
-				const u64 *curve_prime, unsigned int ndigits)
+void vli_mod_square_fast(u64 *result, const u64 *left,
+			 const u64 *curve_prime, unsigned int ndigits)
 {
 	u64 product[2 * ndigits];
 
 	vli_square(product, left, ndigits);
 	vli_mmod_fast(result, product, curve_prime, ndigits);
 }
+EXPORT_SYMBOL_GPL(vli_mod_square_fast);
 
 #define EVEN(vli) (!(vli[0] & 1))
 /* Computes result = (1 / p_input) % mod. All VLIs are the same size.
  * See "From Euclid's GCD to Montgomery Multiplication to the Great Divide"
  * https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf
  */
-static void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod,
-			unsigned int ndigits)
+void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod,
+		 unsigned int ndigits)
 {
 	u64 a[ndigits], b[ndigits];
 	u64 u[ndigits], v[ndigits];
@@ -781,23 +807,25 @@ static void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod,
 
 	vli_set(result, u, ndigits);
 }
+EXPORT_SYMBOL_GPL(vli_mod_inv);
 
 /* ------ Point operations ------ */
 
 /* Returns true if p_point is the point at infinity, false otherwise. */
-static bool ecc_point_is_zero(const struct ecc_point *point)
+bool ecc_point_is_zero(const struct ecc_point *point)
 {
 	return (vli_is_zero(point->x, point->ndigits) &&
 		vli_is_zero(point->y, point->ndigits));
 }
+EXPORT_SYMBOL_GPL(ecc_point_is_zero);
 
 /* Point multiplication algorithm using Montgomery's ladder with co-Z
  * coordinates. From http://eprint.iacr.org/2011/338.pdf
  */
 
 /* Double in place */
-static void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1,
-				      u64 *curve_prime, unsigned int ndigits)
+void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1,
+			       u64 *curve_prime, unsigned int ndigits)
 {
 	/* t1 = x, t2 = y, t3 = z */
 	u64 t4[ndigits];
@@ -857,6 +885,7 @@ static void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1,
 	vli_set(z1, y1, ndigits);
 	vli_set(y1, t4, ndigits);
 }
+EXPORT_SYMBOL_GPL(ecc_point_double_jacobian);
 
 /* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */
 static void apply_z(u64 *x1, u64 *y1, u64 *z, u64 *curve_prime,
@@ -1045,11 +1074,12 @@ void ecc_point_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime,
 	vli_mod_mult_fast(t5, t5, t7,  curve_prime, ndigits);
 	vli_set(x2, t5, ndigits);
 }
+EXPORT_SYMBOL_GPL(ecc_point_add);
 
-static void ecc_point_mult(struct ecc_point *result,
-			   const struct ecc_point *point, const u64 *scalar,
-			   u64 *initial_z, u64 *curve_prime,
-			   unsigned int ndigits)
+void ecc_point_mult(struct ecc_point *result,
+		    const struct ecc_point *point, const u64 *scalar,
+		    u64 *initial_z, u64 *curve_prime,
+		    unsigned int ndigits)
 {
 	/* R0 and R1 */
 	u64 rx[2][ndigits];
@@ -1100,15 +1130,16 @@ static void ecc_point_mult(struct ecc_point *result,
 	vli_set(result->x, rx[0], ndigits);
 	vli_set(result->y, ry[0], ndigits);
 }
+EXPORT_SYMBOL_GPL(ecc_point_mult);
 
-static inline void ecc_swap_digits(const u64 *in, u64 *out,
-				   unsigned int ndigits)
+void ecc_swap_digits(const u64 *in, u64 *out, unsigned int ndigits)
 {
 	int i;
 
 	for (i = 0; i < ndigits; i++)
 		out[i] = __swab64(in[ndigits - 1 - i]);
 }
+EXPORT_SYMBOL_GPL(ecc_swap_digits);
 
 int ecc_is_key_valid(unsigned int curve_id, unsigned int ndigits,
 		     const u8 *private_key, unsigned int private_key_len)
@@ -1133,3 +1164,4 @@ int ecc_is_key_valid(unsigned int curve_id, unsigned int ndigits,
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(ecc_is_key_valid);
diff --git a/crypto/ecc.h b/crypto/ecc.h
index 5db82223d485..0f907a860d0b 100644
--- a/crypto/ecc.h
+++ b/crypto/ecc.h
@@ -31,6 +31,59 @@
 
 #include "ecc_curve_defs.h"
 
+const struct ecc_curve *ecc_get_curve(unsigned int curve_id);
+struct ecc_point *ecc_alloc_point(unsigned int ndigits);
+void ecc_free_point(struct ecc_point *p);
+
+void vli_clear(u64 *vli, unsigned int ndigits);
+bool vli_is_zero(const u64 *vli, unsigned int ndigits);
+unsigned int vli_num_digits(const u64 *vli, unsigned int ndigits);
+unsigned int vli_num_bits(const u64 *vli, unsigned int ndigits);
+void vli_set(u64 *dest, const u64 *src, unsigned int ndigits);
+void vli_copy_to_buf(u8 *dst_buf, unsigned int buf_len,
+		     const u64 *src_vli, unsigned int ndigits);
+void vli_copy_from_buf(u64 *dst_vli, unsigned int ndigits,
+		       const u8 *src_buf, unsigned int buf_len);
+int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits);
+u64 vli_lshift(u64 *result, const u64 *in, unsigned int shift,
+	       unsigned int ndigits);
+void vli_rshift1(u64 *vli, unsigned int ndigits);
+u64 vli_add(u64 *result, const u64 *left, const u64 *right,
+	    unsigned int ndigits);
+u64 vli_sub(u64 *result, const u64 *left, const u64 *right,
+	    unsigned int ndigits);
+void vli_mult(u64 *result, const u64 *left, const u64 *right,
+	      unsigned int ndigits);
+void vli_square(u64 *result, const u64 *left, unsigned int ndigits);
+void vli_mod_add(u64 *result, const u64 *left, const u64 *right,
+		 const u64 *mod, unsigned int ndigits);
+void vli_mod_sub(u64 *result, const u64 *left, const u64 *right,
+		 const u64 *mod, unsigned int ndigits);
+void vli_mod(u64 *result, const u64 *input, const u64 *mod,
+	     unsigned int ndigits);
+void vli_print(char *vli_name, const u64 *vli, unsigned int ndigits);
+void vli_mod_mult(u64 *result, const u64 *left, const u64 *right,
+		  const u64 *mod, unsigned int ndigits);
+bool vli_mmod_fast(u64 *result, u64 *product,
+		   const u64 *curve_prime, unsigned int ndigits);
+void vli_mod_mult_fast(u64 *result, const u64 *left, const u64 *right,
+		       const u64 *curve_prime, unsigned int ndigits);
+void vli_mod_square_fast(u64 *result, const u64 *left,
+			 const u64 *curve_prime, unsigned int ndigits);
+void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod,
+		 unsigned int ndigits);
+
+bool ecc_point_is_zero(const struct ecc_point *point);
+void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1,
+			       u64 *curve_prime, unsigned int ndigits);
+void ecc_point_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime,
+		   unsigned int ndigits);
+void ecc_point_mult(struct ecc_point *result,
+		    const struct ecc_point *point, const u64 *scalar,
+		    u64 *initial_z, u64 *curve_prime,
+		    unsigned int ndigits);
+void ecc_swap_digits(const u64 *in, u64 *out, unsigned int ndigits);
+
 /**
  * ecc_is_key_valid() - Validate a given ECDH private key
  *
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 4/6] crypto: ecdsa: add ECDSA SW implementation
  2017-01-20 11:35 [PATCH 0/6] Add support for ECDSA algorithm Nitin Kumbhar
                   ` (2 preceding siblings ...)
  2017-01-20 11:35 ` [PATCH 3/6] crypto: ecc: export " Nitin Kumbhar
@ 2017-01-20 11:35 ` Nitin Kumbhar
  2017-01-20 13:06   ` Stephan Müller
  2017-01-20 11:36 ` [PATCH 5/6] crypto: testmgr: add ECDSA tests Nitin Kumbhar
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 20+ messages in thread
From: Nitin Kumbhar @ 2017-01-20 11:35 UTC (permalink / raw)
  To: herbert, davem; +Cc: linux-crypto, Nitin Kumbhar

This adds support for ECDSA algorithm. This implementation supports
sign and verify functions for ECDSA algorithm using akcipher. As ECDSA
is a signing algorithm dummy functions are added for encrypt() and
decrypt().

Helper routines for parsing public and private ECC keys for ECDSA are
added as well.

Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
---
 crypto/Kconfig            |    7 +
 crypto/Makefile           |    3 +
 crypto/ecdsa.c            |  331 +++++++++++++++++++++++++++++++++++++++++++++
 crypto/ecdsa_helper.c     |  116 ++++++++++++++++
 include/crypto/akcipher.h |    5 +-
 include/crypto/ecdsa.h    |   29 ++++
 6 files changed, 490 insertions(+), 1 deletions(-)
 create mode 100644 crypto/ecdsa.c
 create mode 100644 crypto/ecdsa_helper.c
 create mode 100644 include/crypto/ecdsa.h

diff --git a/crypto/Kconfig b/crypto/Kconfig
index e240075d6f46..1c5c236b3bbc 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -140,6 +140,13 @@ config CRYPTO_ECDH
 	help
 	  Generic implementation of the ECDH algorithm
 
+config CRYPTO_ECDSA
+	tristate "ECDSA algorithm"
+	select CRYPTO_AKCIPHER
+	select CRYPTO_ECC
+	help
+	  Generic implementation of the ECDSA algorithm
+
 config CRYPTO_MANAGER
 	tristate "Cryptographic algorithm manager"
 	select CRYPTO_MANAGER2
diff --git a/crypto/Makefile b/crypto/Makefile
index 827740a47a37..9c13eb2ade6a 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -38,6 +38,9 @@ obj-$(CONFIG_CRYPTO_ECC) += ecc.o
 ecdh_generic-y := ecdh.o
 ecdh_generic-y += ecdh_helper.o
 obj-$(CONFIG_CRYPTO_ECDH) += ecdh_generic.o
+ecdsa_generic-y := ecdsa.o
+ecdsa_generic-y += ecdsa_helper.o
+obj-$(CONFIG_CRYPTO_ECDSA) += ecdsa_generic.o
 
 $(obj)/rsapubkey-asn1.o: $(obj)/rsapubkey-asn1.c $(obj)/rsapubkey-asn1.h
 $(obj)/rsaprivkey-asn1.o: $(obj)/rsaprivkey-asn1.c $(obj)/rsaprivkey-asn1.h
diff --git a/crypto/ecdsa.c b/crypto/ecdsa.c
new file mode 100644
index 000000000000..d415900af3bd
--- /dev/null
+++ b/crypto/ecdsa.c
@@ -0,0 +1,331 @@
+/*
+ * ECDSA generic algorithm
+ *
+ * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <linux/random.h>
+#include <crypto/internal/akcipher.h>
+#include <crypto/akcipher.h>
+#include <crypto/ecdsa.h>
+
+#include "ecc.h"
+
+struct ecdsa_ctx {
+	unsigned int curve_id;
+	unsigned int ndigits;
+	u64 private_key[ECC_MAX_DIGITS];
+	u64 public_key[2 * ECC_MAX_DIGITS];
+};
+
+static inline struct ecdsa_ctx *ecdsa_get_ctx(struct crypto_akcipher *tfm)
+{
+	return akcipher_tfm_ctx(tfm);
+}
+
+static void ecdsa_parse_msg_hash(struct akcipher_request *req, u64 *msg,
+				 unsigned int ndigits)
+{
+	unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+	unsigned int hash_len, hash_off;
+	unsigned char *hash, *msg_ptr;
+	int i;
+
+	/*
+	 * If hash_len == nbytes:
+	 *	copy nbytes from req
+	 * If hash_len > nbytes:
+	 *	copy left most nbytes from hash ignoring LSBs
+	 * If hash_len < nbytes:
+	 *	copy hash_len from req and zero remaining bytes
+	 *	(nbytes - hash_len)
+	 */
+	hash_len = req->src[0].length;
+	hash_off = hash_len <= nbytes ? 0 : hash_len - nbytes;
+
+	msg_ptr = (unsigned char *)msg;
+	hash = sg_virt(&req->src[0]);
+
+	for (i = hash_off; i < hash_len; i++)
+		*msg_ptr++ = hash[i];
+	for (; i < nbytes; i++)
+		*msg_ptr++ = 0;
+}
+
+int ecdsa_sign(struct akcipher_request *req)
+{
+	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
+	unsigned int ndigits = ctx->ndigits;
+	unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+	unsigned int curve_id = ctx->curve_id;
+	const struct ecc_curve *curve = ecc_get_curve(curve_id);
+	struct ecc_point *x1y1 = NULL;
+	u64 z[ndigits], d[ndigits];
+	u64 k[ndigits], k_inv[ndigits];
+	u64 r[ndigits], s[ndigits];
+	u64 dr[ndigits], zdr[ndigits];
+	u8 *r_ptr, *s_ptr;
+
+	if (req->dst_len < 2 * nbytes) {
+		req->dst_len = 2 * nbytes;
+		return -EINVAL;
+	}
+
+	ecdsa_parse_msg_hash(req, z, ndigits);
+
+	/* d */
+	vli_set(d, (const u64 *)ctx->private_key, ndigits);
+
+	/* k */
+#if defined(CONFIG_CRYPTO_MANAGER2)
+	if (req->info) {
+		vli_copy_from_buf(k, ndigits, req->info, nbytes);
+	} else
+#endif
+		get_random_bytes(k, nbytes);
+
+	x1y1 = ecc_alloc_point(ndigits);
+	if (!x1y1)
+		return -ENOMEM;
+
+	/* (x1, y1) = k x G */
+	ecc_point_mult(x1y1, &curve->g, k, NULL, curve->p, ndigits);
+
+	/* r = x1 mod n */
+	vli_mod(r, x1y1->x, curve->n, ndigits);
+
+	/* k^-1 */
+	vli_mod_inv(k_inv, k, curve->n, ndigits);
+
+	/* d . r mod n */
+	vli_mod_mult(dr, d, r, curve->n, ndigits);
+
+	/* z + dr mod n */
+	vli_mod_add(zdr, z, dr, curve->n, ndigits);
+
+	/* k^-1 . ( z + dr) mod n */
+	vli_mod_mult(s, k_inv, zdr, curve->n, ndigits);
+
+	/* write signature (r,s) in dst */
+	r_ptr = sg_virt(req->dst);
+	s_ptr = (u8 *)sg_virt(req->dst) + nbytes;
+
+	vli_copy_to_buf(r_ptr, nbytes, r, ndigits);
+	vli_copy_to_buf(s_ptr, nbytes, s, ndigits);
+
+	req->dst_len = 2 * nbytes;
+
+	ecc_free_point(x1y1);
+	return 0;
+}
+
+int ecdsa_verify(struct akcipher_request *req)
+{
+	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
+	unsigned int ndigits = ctx->ndigits;
+	unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+	unsigned int curve_id = ctx->curve_id;
+	const struct ecc_curve *curve = ecc_get_curve(curve_id);
+	struct ecc_point *x1y1 = NULL, *x2y2 = NULL, *Q = NULL;
+	u64 r[ndigits], s[ndigits], v[ndigits];
+	u64 z[ndigits], w[ndigits];
+	u64 u1[ndigits], u2[ndigits];
+	u64 x1[ndigits], x2[ndigits];
+	u64 y1[ndigits], y2[ndigits];
+	u64 *ctx_qx, *ctx_qy;
+	int ret;
+
+	x1y1 = ecc_alloc_point(ndigits);
+	x2y2 = ecc_alloc_point(ndigits);
+	Q = ecc_alloc_point(ndigits);
+	if (!x1y1 || !x2y2 || !Q) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	ecdsa_parse_msg_hash(req, z, ndigits);
+
+	/* Signature r,s */
+	vli_copy_from_buf(r, ndigits, sg_virt(&req->src[1]), nbytes);
+	vli_copy_from_buf(s, ndigits, sg_virt(&req->src[2]), nbytes);
+
+	/* w = s^-1 mod n */
+	vli_mod_inv(w, s, curve->n, ndigits);
+
+	/* u1 = zw mod n */
+	vli_mod_mult(u1, z, w, curve->n, ndigits);
+
+	/* u2 = rw mod n */
+	vli_mod_mult(u2, r, w, curve->n, ndigits);
+
+	/* u1 . G */
+	ecc_point_mult(x1y1, &curve->g, u1, NULL, curve->p, ndigits);
+
+	/* Q=(Qx,Qy) */
+	ctx_qx = ctx->public_key;
+	ctx_qy = ctx_qx + ECC_MAX_DIGITS;
+	vli_set(Q->x, ctx_qx, ndigits);
+	vli_set(Q->y, ctx_qy, ndigits);
+
+	/* u2 x Q */
+	ecc_point_mult(x2y2, Q, u2, NULL, curve->p, ndigits);
+
+	vli_set(x1, x1y1->x, ndigits);
+	vli_set(y1, x1y1->y, ndigits);
+	vli_set(x2, x2y2->x, ndigits);
+	vli_set(y2, x2y2->y, ndigits);
+
+	/* x1y1 + x2y2 => P + Q; P + Q in x2 y2 */
+	ecc_point_add(x1, y1, x2, y2, curve->p, ndigits);
+
+	/* v = x mod n */
+	vli_mod(v, x2, curve->n, ndigits);
+
+	/* validate signature */
+	ret = vli_cmp(v, r, ndigits) == 0 ? 0 : -EBADMSG;
+ exit:
+	ecc_free_point(x1y1);
+	ecc_free_point(x2y2);
+	ecc_free_point(Q);
+	return ret;
+}
+
+int ecdsa_dummy_enc(struct akcipher_request *req)
+{
+	return -EINVAL;
+}
+
+int ecdsa_dummy_dec(struct akcipher_request *req)
+{
+	return -EINVAL;
+}
+
+int ecdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key,
+		      unsigned int keylen)
+{
+	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
+	struct ecdsa params;
+	unsigned int ndigits;
+	unsigned int nbytes;
+	u8 *params_qx, *params_qy;
+	u64 *ctx_qx, *ctx_qy;
+	int ret = 0;
+
+	if (crypto_ecdsa_parse_pub_key(key, keylen, &params))
+		return -EINVAL;
+
+	ndigits = ecdsa_supported_curve(params.curve_id);
+
+	ctx->curve_id = params.curve_id;
+	ctx->ndigits = ndigits;
+	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+
+	params_qx = params.key;
+	params_qy = params_qx + ECC_MAX_DIGIT_BYTES;
+
+	ctx_qx = ctx->public_key;
+	ctx_qy = ctx_qx + ECC_MAX_DIGITS;
+
+	vli_copy_from_buf(ctx_qx, ndigits, params_qx, nbytes);
+	vli_copy_from_buf(ctx_qy, ndigits, params_qy, nbytes);
+
+	memset(&params, 0, sizeof(params));
+	return ret;
+}
+
+int ecdsa_set_priv_key(struct crypto_akcipher *tfm, const void *key,
+		       unsigned int keylen)
+{
+	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
+	struct ecdsa params;
+	unsigned int ndigits;
+	unsigned int nbytes;
+
+	if (crypto_ecdsa_parse_priv_key(key, keylen, &params))
+		return -EINVAL;
+
+	ndigits = ecdsa_supported_curve(params.curve_id);
+
+	ctx->curve_id = params.curve_id;
+	ctx->ndigits = ndigits;
+	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+
+	if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits,
+			     (const u8 *)params.key, params.key_size) < 0)
+		return -EINVAL;
+
+	vli_copy_from_buf(ctx->private_key, ndigits, params.key, nbytes);
+
+	memset(&params, 0, sizeof(params));
+	return 0;
+}
+
+int ecdsa_max_size(struct crypto_akcipher *tfm)
+{
+	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
+	int nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+
+	/* For r,s */
+	return 2 * nbytes;
+}
+
+int ecdsa_init_tfm(struct crypto_akcipher *tfm)
+{
+	return 0;
+}
+
+void ecdsa_exit_tfm(struct crypto_akcipher *tfm)
+{
+}
+
+static struct akcipher_alg ecdsa_alg = {
+	.sign		= ecdsa_sign,
+	.verify		= ecdsa_verify,
+	.encrypt	= ecdsa_dummy_enc,
+	.decrypt	= ecdsa_dummy_dec,
+	.set_priv_key	= ecdsa_set_priv_key,
+	.set_pub_key	= ecdsa_set_pub_key,
+	.max_size	= ecdsa_max_size,
+	.init		= ecdsa_init_tfm,
+	.exit		= ecdsa_exit_tfm,
+	.base = {
+		.cra_name	= "ecdsa",
+		.cra_driver_name = "ecdsa-generic",
+		.cra_priority	= 100,
+		.cra_module	= THIS_MODULE,
+		.cra_ctxsize	= sizeof(struct ecdsa_ctx),
+	},
+};
+
+static int ecdsa_init(void)
+{
+	int ret;
+
+	ret = crypto_register_akcipher(&ecdsa_alg);
+	if (ret)
+		pr_err("ecdsa alg register failed. err:%d\n", ret);
+	return ret;
+}
+
+static void ecdsa_exit(void)
+{
+	crypto_unregister_akcipher(&ecdsa_alg);
+}
+
+module_init(ecdsa_init);
+module_exit(ecdsa_exit);
+
+MODULE_ALIAS_CRYPTO("ecdsa");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ECDSA Generic Algorithm");
+MODULE_AUTHOR("NVIDIA Corporation");
diff --git a/crypto/ecdsa_helper.c b/crypto/ecdsa_helper.c
new file mode 100644
index 000000000000..d31eb54431a9
--- /dev/null
+++ b/crypto/ecdsa_helper.c
@@ -0,0 +1,116 @@
+/*
+ * ECDSA helper routines
+ *
+ * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <crypto/ecdsa.h>
+
+#include "ecc.h"
+
+#define ECDSA_KEY_MIN_SIZE	(1 + 1 + 24) /* ver + cid + n (P-192) */
+
+unsigned int ecdsa_supported_curve(unsigned int curve_id)
+{
+	switch (curve_id) {
+	case ECC_CURVE_NIST_P192: return 3;
+	case ECC_CURVE_NIST_P256: return 4;
+	default: return 0;
+	}
+}
+
+static inline u8 *ecdsa_pack_data(void *dst, const void *src, size_t sz)
+{
+	memcpy(dst, src, sz);
+	return dst + sz;
+}
+
+static inline const u8 *ecdsa_unpack_data(void *dst, const void *src, size_t sz)
+{
+	memcpy(dst, src, sz);
+	return src + sz;
+}
+
+int crypto_ecdsa_parse_pub_key(const char *buf, unsigned int len,
+			       struct ecdsa *params)
+{
+	unsigned char version;
+	unsigned int ndigits;
+	unsigned int nbytes;
+	const u8 *ptr = buf;
+	u8 *qx, *qy;
+
+	if (unlikely(!buf) || len < ECDSA_KEY_MIN_SIZE)
+		return -EINVAL;
+
+	ptr = ecdsa_unpack_data(&version, ptr, sizeof(version));
+	if (version != 1)
+		return -EINVAL;
+
+	ptr = ecdsa_unpack_data(&params->curve_id, ptr,
+				sizeof(params->curve_id));
+
+	ndigits = ecdsa_supported_curve(params->curve_id);
+	if (!ndigits)
+		return -EINVAL;
+
+	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+
+	/* skip private key */
+	ptr = ecdsa_unpack_data(&params->key, ptr, nbytes);
+
+	/* copy public key */
+	qx = params->key;
+	qy = qx + ECC_MAX_DIGIT_BYTES;
+
+	ptr = ecdsa_unpack_data(qx, ptr, nbytes);
+	ptr = ecdsa_unpack_data(qy, ptr, nbytes);
+
+	params->key_size = 2 * nbytes;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_ecdsa_parse_pub_key);
+
+int crypto_ecdsa_parse_priv_key(const char *buf, unsigned int len,
+				struct ecdsa *params)
+{
+	unsigned char version;
+	unsigned int ndigits;
+	unsigned int nbytes;
+	const u8 *ptr = buf;
+
+	if (unlikely(!buf) || len < ECDSA_KEY_MIN_SIZE)
+		return -EINVAL;
+
+	ptr = ecdsa_unpack_data(&version, ptr, sizeof(version));
+	if (version != 1)
+		return -EINVAL;
+
+	ptr = ecdsa_unpack_data(&params->curve_id, ptr,
+				sizeof(params->curve_id));
+
+	ndigits = ecdsa_supported_curve(params->curve_id);
+	if (!ndigits)
+		return -EINVAL;
+
+	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+
+	params->key_size = nbytes;
+
+	/* copy private key */
+	ptr = ecdsa_unpack_data(&params->key, ptr, nbytes);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_ecdsa_parse_priv_key);
diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
index c37cc59e9bf2..6b34e9043a6f 100644
--- a/include/crypto/akcipher.h
+++ b/include/crypto/akcipher.h
@@ -3,6 +3,7 @@
  *
  * Copyright (c) 2015, Intel Corporation
  * Authors: Tadeusz Struk <tadeusz.struk@intel.com>
+ * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -27,6 +28,7 @@
  *		result.
  *		In case of error where the dst sgl size was insufficient,
  *		it will be updated to the size required for the operation.
+ * @info:	Any request specific data needed to process the request.
  * @__ctx:	Start of private context data
  */
 struct akcipher_request {
@@ -35,6 +37,7 @@ struct akcipher_request {
 	struct scatterlist *dst;
 	unsigned int src_len;
 	unsigned int dst_len;
+	void *info;
 	void *__ctx[] CRYPTO_MINALIGN_ATTR;
 };
 
@@ -193,7 +196,7 @@ static inline void crypto_free_akcipher(struct crypto_akcipher *tfm)
 {
 	struct akcipher_request *req;
 
-	req = kmalloc(sizeof(*req) + crypto_akcipher_reqsize(tfm), gfp);
+	req = kzalloc(sizeof(*req) + crypto_akcipher_reqsize(tfm), gfp);
 	if (likely(req))
 		akcipher_request_set_tfm(req, tfm);
 
diff --git a/include/crypto/ecdsa.h b/include/crypto/ecdsa.h
new file mode 100644
index 000000000000..c71d21e654b9
--- /dev/null
+++ b/include/crypto/ecdsa.h
@@ -0,0 +1,29 @@
+/*
+ * ECC parameters for ECDSA
+ *
+ * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#ifndef _CRYPTO_ECDSA_
+#define _CRYPTO_ECDSA_
+
+#include <crypto/ecc.h>
+
+struct ecdsa {
+	unsigned char curve_id;
+	unsigned char key[2 * ECC_MAX_DIGIT_BYTES];
+	unsigned short key_size;
+};
+
+unsigned int ecdsa_supported_curve(unsigned int curve_id);
+int crypto_ecdsa_parse_pub_key(const char *buf, unsigned int len,
+			       struct ecdsa *params);
+int crypto_ecdsa_parse_priv_key(const char *buf, unsigned int len,
+				struct ecdsa *params);
+#endif /* _CRYPTO_ECDSA_ */
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 5/6] crypto: testmgr: add ECDSA tests
  2017-01-20 11:35 [PATCH 0/6] Add support for ECDSA algorithm Nitin Kumbhar
                   ` (3 preceding siblings ...)
  2017-01-20 11:35 ` [PATCH 4/6] crypto: ecdsa: add ECDSA SW implementation Nitin Kumbhar
@ 2017-01-20 11:36 ` Nitin Kumbhar
  2017-01-20 13:19   ` Stephan Müller
  2017-01-20 11:36 ` [PATCH 6/6] crypto: tcrypt: add ECDSA test modes Nitin Kumbhar
  2017-01-23 14:24 ` [PATCH 0/6] Add support for ECDSA algorithm Herbert Xu
  6 siblings, 1 reply; 20+ messages in thread
From: Nitin Kumbhar @ 2017-01-20 11:36 UTC (permalink / raw)
  To: herbert, davem; +Cc: linux-crypto, Nitin Kumbhar

Update crypto test manager to include NIST ECDSA
test vectors and various ECDSA tests. These include
tests for ECDSA signing, ECDSA sign-verification,
ECDSA signing and verifying generated signatures and
invalidation of incorrect signatures.

Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
---
 crypto/testmgr.c |  452 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 crypto/testmgr.h |  140 +++++++++++++++++
 2 files changed, 589 insertions(+), 3 deletions(-)

diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 98eb09782db8..a1db28cbc32d 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -5,6 +5,7 @@
  * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org>
  * Copyright (c) 2007 Nokia Siemens Networks
  * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
+ * Copyright (c) 2017 NVIDIA Corporation
  *
  * Updated RFC4106 AES-GCM testing.
  *    Authors: Aidan O'Mahony (aidan.o.mahony@intel.com)
@@ -2085,6 +2086,436 @@ static int alg_test_kpp(const struct alg_test_desc *desc, const char *driver,
 	return err;
 }
 
+static int do_test_ecdsa_verify(struct crypto_akcipher *tfm,
+			      struct akcipher_testvec *vec)
+{
+	struct akcipher_request *req = NULL;
+	u8 *r_str = NULL, *s_str = NULL;
+	u8 *m_str = NULL;
+	struct scatterlist src_tab[3], dst;
+	struct tcrypt_result result;
+	unsigned int outbuf_maxlen;
+	u8 *outbuf = NULL;
+	unsigned int nbytes;
+	int err;
+
+	/* Alloc akcipher request */
+	req = akcipher_request_alloc(tfm, GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	/* Set private key */
+	err = crypto_akcipher_set_pub_key(tfm, vec->key, vec->key_len);
+	if (err)
+		goto error;
+
+	/*
+	 * vec->c always contains k, R and S in that order. All are
+	 * of same size and are equal to n i.e. the order of
+	 * an elliptic curve.
+	 */
+	nbytes = vec->c_size / 3;
+
+	r_str = kzalloc(nbytes, GFP_KERNEL);
+	s_str = kzalloc(nbytes, GFP_KERNEL);
+	m_str = kzalloc(vec->m_size, GFP_KERNEL);
+	if (!r_str || !s_str || !m_str) {
+		err = -ENOMEM;
+		goto error;
+	}
+	memcpy(r_str, (u8 *)vec->c + nbytes, nbytes);
+	memcpy(s_str, (u8 *)vec->c + 2 * nbytes, nbytes);
+	memcpy(m_str, vec->m, vec->m_size);
+
+	outbuf_maxlen = crypto_akcipher_maxsize(tfm);
+	if (outbuf_maxlen < 0) {
+		err = outbuf_maxlen;
+		goto error;
+	}
+	outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL);
+	if (!outbuf) {
+		err = -ENOMEM;
+		goto error;
+	}
+
+	/* Set src and dst buffers */
+	sg_init_table(src_tab, 3);
+	sg_set_buf(&src_tab[0], m_str, vec->m_size);
+	sg_set_buf(&src_tab[1], r_str, nbytes);
+	sg_set_buf(&src_tab[2], s_str, nbytes);
+	sg_init_one(&dst, outbuf, outbuf_maxlen);
+
+	akcipher_request_set_crypt(req, src_tab, &dst,
+				   vec->m_size + 2 * nbytes, outbuf_maxlen);
+
+	/* Set up result callback */
+	init_completion(&result.completion);
+	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				      tcrypt_complete, &result);
+
+	/* Run ecdsa verify operation on sig (r,s) */
+	err = wait_async_op(&result, crypto_akcipher_verify(req));
+	if (err) {
+		pr_err("alg: ecdsa: verify(rs) test failed. err %d\n", err);
+		goto error;
+	}
+error:
+	akcipher_request_free(req);
+	kfree(r_str);
+	kfree(s_str);
+	kfree(m_str);
+	kfree(outbuf);
+	return err;
+}
+
+static int do_test_ecdsa_invalid_verify(struct crypto_akcipher *tfm,
+					struct akcipher_testvec *vec)
+{
+	struct akcipher_request *req = NULL;
+	u8 *r_str = NULL, *s_str = NULL;
+	u8 *m_str = NULL;
+	struct scatterlist src_tab[3], dst;
+	struct tcrypt_result result;
+	unsigned int outbuf_maxlen;
+	u8 *outbuf = NULL;
+	unsigned int nbytes;
+	int err;
+
+	/* Alloc akcipher request */
+	req = akcipher_request_alloc(tfm, GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	/* Set private key */
+	err = crypto_akcipher_set_pub_key(tfm, vec->key, vec->key_len);
+	if (err)
+		goto error;
+
+	/*
+	 * vec->c always contains k, R and S in that order. All are
+	 * of same size and are equal to n i.e. the order of
+	 * an elliptic curve.
+	 */
+	nbytes = vec->c_size / 3;
+
+	r_str = kzalloc(nbytes, GFP_KERNEL);
+	s_str = kzalloc(nbytes, GFP_KERNEL);
+	m_str = kzalloc(vec->m_size, GFP_KERNEL);
+	if (!r_str || !s_str || !m_str) {
+		err = -ENOMEM;
+		goto error;
+	}
+	memcpy(r_str, (u8 *)vec->c + 1 * nbytes, nbytes);
+	memcpy(s_str, (u8 *)vec->c + 2 * nbytes, nbytes);
+	memcpy(m_str, vec->m, vec->m_size);
+
+	outbuf_maxlen = crypto_akcipher_maxsize(tfm);
+	if (outbuf_maxlen < 0) {
+		err = outbuf_maxlen;
+		goto error;
+	}
+	outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL);
+	if (!outbuf) {
+		err = -ENOMEM;
+		goto error;
+	}
+
+	/* Set src and dst buffers */
+	sg_init_table(src_tab, 3);
+	/* Intentionally set m_size to 8 to have invalid hash */
+	sg_set_buf(&src_tab[0], m_str, 8);
+	sg_set_buf(&src_tab[1], r_str, nbytes);
+	sg_set_buf(&src_tab[2], s_str, nbytes);
+	sg_init_one(&dst, outbuf, outbuf_maxlen);
+
+	akcipher_request_set_crypt(req, src_tab, &dst,
+				   vec->m_size + 2 * nbytes, outbuf_maxlen);
+
+	/* Set up result callback */
+	init_completion(&result.completion);
+	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				      tcrypt_complete, &result);
+
+	/* Run ecdsa verify operation on sig (r,s) */
+	err = wait_async_op(&result, crypto_akcipher_verify(req));
+	if (err != -EBADMSG) {
+		pr_err("alg: ecdsa: invalid verify test failed. err %d\n", err);
+		goto error;
+	}
+	err = 0;
+error:
+	akcipher_request_free(req);
+	kfree(r_str);
+	kfree(s_str);
+	kfree(m_str);
+	kfree(outbuf);
+	return err;
+}
+
+static int do_test_ecdsa_sign_verify(struct crypto_akcipher *tfm,
+				     struct akcipher_testvec *vec)
+{
+	struct akcipher_request *req = NULL;
+	u8 *r_str = NULL, *s_str = NULL;
+	u8 *m_str = NULL;
+	struct scatterlist src_tab[3];
+	struct scatterlist src, dst;
+	struct tcrypt_result result;
+	unsigned int outbuf_maxlen;
+	void *outbuf = NULL;
+	unsigned int nbytes;
+	int err;
+
+	/* Alloc akcipher request */
+	req = akcipher_request_alloc(tfm, GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	/* Set private key */
+	err = crypto_akcipher_set_priv_key(tfm, vec->key, vec->key_len);
+	if (err)
+		goto error;
+
+	/* Set private key */
+	err = crypto_akcipher_set_pub_key(tfm, vec->key, vec->key_len);
+	if (err)
+		goto error;
+
+	/*
+	 * vec->c always contains k, R and S in that order. All are
+	 * of same size and are equal to n i.e. the order of
+	 * an elliptic curve.
+	 */
+	nbytes = vec->c_size / 3;
+
+	m_str = kzalloc(vec->m_size, GFP_KERNEL);
+	if (!m_str) {
+		err = -ENOMEM;
+		goto error;
+	}
+	memcpy(m_str, vec->m, vec->m_size);
+
+	outbuf_maxlen = crypto_akcipher_maxsize(tfm);
+	if (outbuf_maxlen < 0) {
+		err = outbuf_maxlen;
+		goto error;
+	}
+	outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL);
+	if (!outbuf) {
+		err = -ENOMEM;
+		goto error;
+	}
+
+	sg_init_one(&src, m_str, vec->m_size);
+	sg_init_one(&dst, outbuf, outbuf_maxlen);
+
+	akcipher_request_set_crypt(req, &src, &dst,
+				   vec->m_size, outbuf_maxlen);
+
+	/* Set up result callback */
+	init_completion(&result.completion);
+	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				      tcrypt_complete, &result);
+
+	/* Run ecdsa sign operation on message digest */
+	err = wait_async_op(&result, crypto_akcipher_sign(req));
+	if (err) {
+		pr_err("alg: ecdsa: sign test failed. err %d\n", err);
+		goto error;
+	}
+
+	/* verify that signature (r,s) is valid */
+	if (req->dst_len != 2 * nbytes) {
+		pr_err("alg: ecdsa: sign test failed. Invalid sig len\n");
+		err = -EINVAL;
+		goto error;
+	}
+
+	/* output contains r and s */
+	r_str = outbuf;
+	s_str = (u8 *)outbuf + nbytes;
+
+	/* Set src and dst buffers */
+	sg_init_table(src_tab, 3);
+	sg_set_buf(&src_tab[0], m_str, vec->m_size);
+	sg_set_buf(&src_tab[1], r_str, nbytes);
+	sg_set_buf(&src_tab[2], s_str, nbytes);
+	sg_init_one(&dst, outbuf, outbuf_maxlen);
+
+	akcipher_request_set_crypt(req, src_tab, &dst,
+				   vec->m_size + 2 * nbytes, outbuf_maxlen);
+
+	/* Set up result callback */
+	init_completion(&result.completion);
+	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				      tcrypt_complete, &result);
+
+	/* Run ecdsa verify operation on sig (r,s) */
+	err = wait_async_op(&result, crypto_akcipher_verify(req));
+	if (err) {
+		pr_err("alg: ecdsa: verify test failed. err %d\n", err);
+		goto error;
+	}
+error:
+	akcipher_request_free(req);
+	kfree(m_str);
+	kfree(outbuf);
+	return err;
+}
+
+static int do_test_ecdsa_sign(struct crypto_akcipher *tfm,
+			      struct akcipher_testvec *vec)
+{
+	struct akcipher_request *req = NULL;
+	u8 *r_str = NULL, *s_str = NULL;
+	u8 *k_str = NULL, *m_str = NULL;
+	struct scatterlist src, dst;
+	struct tcrypt_result result;
+	unsigned int outbuf_maxlen;
+	void *outbuf = NULL;
+	unsigned int nbytes;
+	int err;
+
+	/* Alloc akcipher request */
+	req = akcipher_request_alloc(tfm, GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	/* Set private key */
+	err = crypto_akcipher_set_priv_key(tfm, vec->key, vec->key_len);
+	if (err)
+		goto error;
+
+	/*
+	 * vec->c always contains k, R and S in that order. All are
+	 * of same size and are equal to n i.e. the order of
+	 * an elliptic curve.
+	 */
+	nbytes = vec->c_size / 3;
+
+	k_str = kzalloc(nbytes, GFP_KERNEL);
+	r_str = kzalloc(nbytes, GFP_KERNEL);
+	s_str = kzalloc(nbytes, GFP_KERNEL);
+	m_str = kzalloc(vec->m_size, GFP_KERNEL);
+	if (!k_str || !r_str || !s_str || !m_str) {
+		err = -ENOMEM;
+		goto error;
+	}
+	memcpy(k_str, (u8 *)vec->c + 0 * nbytes, nbytes);
+	memcpy(r_str, (u8 *)vec->c + 1 * nbytes, nbytes);
+	memcpy(s_str, (u8 *)vec->c + 2 * nbytes, nbytes);
+	memcpy(m_str, vec->m, vec->m_size);
+
+	outbuf_maxlen = crypto_akcipher_maxsize(tfm);
+	if (outbuf_maxlen < 0) {
+		err = outbuf_maxlen;
+		goto error;
+	}
+	outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL);
+	if (!outbuf) {
+		err = -ENOMEM;
+		goto error;
+	}
+
+	/* Set src and dst buffers */
+	sg_init_one(&src, m_str, vec->m_size);
+	sg_init_one(&dst, outbuf, outbuf_maxlen);
+
+	akcipher_request_set_crypt(req, &src, &dst,
+				   vec->m_size, outbuf_maxlen);
+
+	/* Set up result callback */
+	init_completion(&result.completion);
+	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				      tcrypt_complete, &result);
+
+	/* Set K in request for signing */
+	req->info = k_str;
+
+	/* Run ecdsa sign operation on message digest */
+	err = wait_async_op(&result, crypto_akcipher_sign(req));
+	if (err) {
+		pr_err("alg: ecdsa: sign(k) test failed. err %d\n", err);
+		goto error;
+	}
+
+	/* verify that signature (r,s) is valid */
+	if (req->dst_len != 2 * nbytes) {
+		pr_err("alg: ecdsa: sign(k) test failed. Invalid sig len\n");
+		err = -EINVAL;
+		goto error;
+	}
+
+	if (memcmp(r_str, sg_virt(req->dst), nbytes)) {
+		pr_err("alg: ecdsa: sign(k) test failed. Invalid sig(r)\n");
+		err = -EINVAL;
+		goto error;
+	}
+
+	if (memcmp(s_str, (u8 *)sg_virt(req->dst) + nbytes, nbytes)) {
+		pr_err("alg: ecdsa: sign(k) test failed. Invalid sig(s)\n");
+		err = -EINVAL;
+		goto error;
+	}
+error:
+	akcipher_request_free(req);
+	kfree(k_str);
+	kfree(r_str);
+	kfree(s_str);
+	kfree(m_str);
+	kfree(outbuf);
+	return err;
+}
+
+static int test_ecdsa_akcipher(struct crypto_akcipher *tfm, const char *alg,
+		       struct akcipher_testvec *vecs, unsigned int tcount)
+{
+	int i, err = 0;
+
+	for (i = 0; i < tcount; i++) {
+		err = do_test_ecdsa_verify(tfm, &vecs[i]);
+		if (!err)
+			continue;
+
+		pr_err("ecdsa: verify failed on vec %d, err=%d\n",
+		       i + 1, err);
+		goto exit;
+	}
+
+	for (i = 0; i < tcount; i++) {
+		err = do_test_ecdsa_invalid_verify(tfm, &vecs[i]);
+		if (!err)
+			continue;
+
+		pr_err("ecdsa: verify(invl) failed on vec %d, err=%d\n",
+		       i + 1, err);
+		goto exit;
+	}
+
+	for (i = 0; i < tcount; i++) {
+		err = do_test_ecdsa_sign_verify(tfm, &vecs[i]);
+		if (!err)
+			continue;
+
+		pr_err("ecdsa: sign/verify failed on vec %d, err=%d\n",
+		       i + 1, err);
+		goto exit;
+	}
+
+	for (i = 0; i < tcount; i++) {
+		err = do_test_ecdsa_sign(tfm, &vecs[i]);
+		if (!err)
+			continue;
+
+		pr_err("ecdsa: sign failed on vec %d, err=%d\n",
+		       i + 1, err);
+		goto exit;
+	}
+ exit:
+	pr_info("test_ecdsa: %s\n", err ? "FAILED" : "PASSED");
+	return err;
+}
+
 static int test_akcipher_one(struct crypto_akcipher *tfm,
 			     struct akcipher_testvec *vecs)
 {
@@ -2236,9 +2667,17 @@ static int alg_test_akcipher(const struct alg_test_desc *desc,
 		       driver, PTR_ERR(tfm));
 		return PTR_ERR(tfm);
 	}
-	if (desc->suite.akcipher.vecs)
-		err = test_akcipher(tfm, desc->alg, desc->suite.akcipher.vecs,
-				    desc->suite.akcipher.count);
+
+	if (desc->suite.akcipher.vecs) {
+		if (strncmp(desc->alg, "ecdsa", 5) == 0)
+			err = test_ecdsa_akcipher(tfm, desc->alg,
+						  desc->suite.akcipher.vecs,
+						  desc->suite.akcipher.count);
+		else
+			err = test_akcipher(tfm, desc->alg,
+					    desc->suite.akcipher.vecs,
+					    desc->suite.akcipher.count);
+	}
 
 	crypto_free_akcipher(tfm);
 	return err;
@@ -2982,6 +3421,13 @@ static int alg_test_null(const struct alg_test_desc *desc,
 			.kpp = __VECS(ecdh_tv_template)
 		}
 	}, {
+		.alg = "ecdsa",
+		.test = alg_test_akcipher,
+		.fips_allowed = 1,
+		.suite = {
+			.akcipher = __VECS(ecdsa_tv_template)
+		}
+	}, {
 		.alg = "gcm(aes)",
 		.test = alg_test_aead,
 		.fips_allowed = 1,
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 64595f067d72..00bb57f4707a 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -5,6 +5,7 @@
  * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org>
  * Copyright (c) 2007 Nokia Siemens Networks
  * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
+ * Copyright (c) 2017 NVIDIA Corporation
  *
  * Updated RFC4106 AES-GCM testing. Some test vectors were taken from
  * http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/
@@ -755,6 +756,145 @@ struct kpp_testvec dh_tv_template[] = {
 	}
 };
 
+/*
+ * ECDSA NIST test vectors from SigGenComponent.txt file from
+ * 186-3ecdsasiggencomponenttestvectors.zip for P-192 and P-256
+ * elliptic curves.
+ */
+static struct akcipher_testvec ecdsa_tv_template[] = {
+	{
+#ifndef CONFIG_CRYPTO_FIPS
+		/* [P-192,SHA-1] */
+		.m =
+		/* Msg / Hash */
+		"\x92\x5b\xd6\xf4\x1c\x55\xbe\x3e"
+		"\x49\xb7\x16\xe6\x1d\x42\x12\x3f"
+		"\x42\x79\x80\x60",
+		.m_size = 20,
+		.key =
+		/* version */
+		"\x01"
+		/* curve_id */
+		"\x01"
+		/* d */
+		"\xf3\xd7\x60\xd6\x75\xf2\xcc\xeb"
+		"\xf0\xd2\xfd\xb3\xb9\x41\x3f\xb0"
+		"\xf8\x4f\x37\xd1\xb3\x37\x4f\xe1"
+		/* Qx */
+		"\xe6\x98\xcf\x5b\x2d\x2d\x98\x94"
+		"\x4c\x49\xa2\x80\x6e\x09\x32\x64"
+		"\xe7\xdb\x08\x0b\xa4\x8e\x00\x07"
+		/* Qy */
+		"\x77\x54\xd6\xe4\xf2\xd7\x1b\xc4"
+		"\x98\x6d\xe2\x5d\x21\xba\x36\xa6"
+		"\x4e\x41\x0b\xd0\x81\xb6\xfa\x76",
+		.key_len = 74,
+		.c =
+		/* k */
+		"\x25\x5f\x68\x89\xa2\x31\xbc\x57"
+		"\x4d\x15\xc4\x12\xfb\x56\x45\x68"
+		"\x83\x07\xa1\x43\x70\xbc\x0a\xcb"
+		/* R */
+		"\x3e\xa6\x58\x62\xb4\x98\x96\x1a"
+		"\xf9\xf2\x5b\xec\x55\xf8\xdd\xff"
+		"\x93\xd7\xd0\xbd\x62\xd9\x94\x69"
+		/* S */
+		"\x41\x9f\x1a\x0e\xc0\x5f\xcf\x73"
+		"\x5b\x40\x21\x85\xbc\x02\xab\x44"
+		"\x37\x90\x34\xa2\x65\x64\xba\x02",
+		.c_size = 72,
+	}, {
+		/* [P-192,SHA-256] */
+		.m =
+		/* Msg / Hash */
+		"\xd0\xd8\xc0\x99\xe0\xe2\xf7\xf8"
+		"\x87\xe1\x6d\x11\xe1\xcc\x20\x43"
+		"\xaf\xc0\x80\xdb\x47\x72\xfa\xe3"
+		"\x95\xe5\xd1\x34\x7d\x31\xe8\x5a",
+		.m_size = 32,
+		.key =
+		/* version */
+		"\x01"
+		/* curve_id */
+		"\x01"
+		/* d */
+		"\x47\x7a\xf2\x5c\x86\xef\x09\x08"
+		"\xa4\x9a\x47\x53\x06\xfc\x61\xbc"
+		"\xa5\x6f\xdd\x7d\x2f\xd2\xed\x24"
+		/* Qx */
+		"\xdc\x14\xd4\xd8\x2e\x1e\x25\x2f"
+		"\x66\x28\xaa\x80\xbc\x38\x6a\x07"
+		"\x8a\x70\xb7\x74\x71\x2d\xf1\x9b"
+		/* Qy */
+		"\x98\x34\x57\x11\xb0\xdc\x3d\xff"
+		"\xfc\xdc\xfe\xa2\x1c\x47\x9e\x4e"
+		"\x82\x08\xfc\x7d\xd0\xc8\x54\x48",
+		.key_len = 74,
+		.c =
+		/* k */
+		"\x3e\x70\xc7\x86\xaf\xaa\x71\x7c"
+		"\x68\x96\xc5\xc3\xec\xb8\x29\xa3"
+		"\xfa\xf7\xa5\x36\xa2\x17\xc8\xa5"
+		/* R */
+		"\xf8\xef\x13\xa8\x86\xe6\x73\x85"
+		"\xdf\x2e\x88\x99\x91\x9b\xc2\x90"
+		"\xea\x1f\x36\xf4\xec\xba\x4a\x35"
+		/* S */
+		"\xc1\x82\x9e\x94\xb7\x58\x2c\x63"
+		"\x8e\xd7\x15\x5a\x38\x47\x30\x9b"
+		"\x1c\x11\x86\xac\x00\x00\xf5\x80",
+		.c_size = 72,
+	}, {
+#endif
+		/* [P-256,SHA-256] */
+		.m =
+		/* Msg / Hash */
+		"\x56\xec\x33\xa1\xa6\xe7\xc4\xdb"
+		"\x77\x03\x90\x1a\xfb\x2e\x1e\x4e"
+		"\x50\x09\xfe\x04\x72\x89\xc5\xc2"
+		"\x42\x13\x6c\xe3\xb7\xf6\xac\x44",
+		.m_size = 32,
+		.key =
+		/* version */
+		"\x01"
+		/* curve_id */
+		"\x02"
+		/* d */
+		"\x64\xb4\x72\xda\x6d\xa5\x54\xca"
+		"\xac\x3e\x4e\x0b\x13\xc8\x44\x5b"
+		"\x1a\x77\xf4\x59\xee\xa8\x4f\x1f"
+		"\x58\x8b\x5f\x71\x3d\x42\x9b\x51"
+		/* Qx */
+		"\x83\xbf\x71\xc2\x46\xff\x59\x3c"
+		"\x2f\xb1\xbf\x4b\xe9\x5d\x56\xd3"
+		"\xcc\x8f\xdb\x48\xa2\xbf\x33\xf0"
+		"\xf4\xc7\x5f\x07\x1c\xe9\xcb\x1c"
+		/* Qy */
+		"\xa9\x4c\x9a\xa8\x5c\xcd\x7c\xdc"
+		"\x78\x4e\x40\xb7\x93\xca\xb7\x6d"
+		"\xe0\x13\x61\x0e\x2c\xdb\x1f\x1a"
+		"\xa2\xf9\x11\x88\xc6\x14\x40\xce",
+		.key_len = 98,
+		.c =
+		/* k */
+		"\xde\x68\x2a\x64\x87\x07\x67\xb9"
+		"\x33\x5d\x4f\x82\x47\x62\x4a\x3b"
+		"\x7f\x3c\xe9\xf9\x45\xf2\x80\xa2"
+		"\x61\x6a\x90\x4b\xb1\xbb\xa1\x94"
+		/* R */
+		"\xac\xc2\xc8\x79\x6f\x5e\xbb\xca"
+		"\x7a\x5a\x55\x6a\x1f\x6b\xfd\x2a"
+		"\xed\x27\x95\x62\xd6\xe3\x43\x88"
+		"\x5b\x79\x14\xb5\x61\x80\xac\xf3"
+		/* S */
+		"\x03\x89\x05\xcc\x2a\xda\xcd\x3c"
+		"\x5a\x17\x6f\xe9\x18\xb2\x97\xef"
+		"\x1c\x37\xf7\x2b\x26\x76\x6c\x78"
+		"\xb2\xa6\x05\xca\x19\x78\xf7\x8b",
+		.c_size = 96,
+	},
+};
+
 struct kpp_testvec ecdh_tv_template[] = {
 	{
 #ifndef CONFIG_CRYPTO_FIPS
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 6/6] crypto: tcrypt: add ECDSA test modes
  2017-01-20 11:35 [PATCH 0/6] Add support for ECDSA algorithm Nitin Kumbhar
                   ` (4 preceding siblings ...)
  2017-01-20 11:36 ` [PATCH 5/6] crypto: testmgr: add ECDSA tests Nitin Kumbhar
@ 2017-01-20 11:36 ` Nitin Kumbhar
  2017-01-23 14:24 ` [PATCH 0/6] Add support for ECDSA algorithm Herbert Xu
  6 siblings, 0 replies; 20+ messages in thread
From: Nitin Kumbhar @ 2017-01-20 11:36 UTC (permalink / raw)
  To: herbert, davem; +Cc: linux-crypto, Nitin Kumbhar

Update tcrypt module to include a new ECDSA test
modes. It includes:

tcrypt.ko mode=560 for ECDSA sign/verify validation.
tcrypt.ko mode=561 for ECDSA sign/verify op perf in cycles.
tcrypt.ko mode=561 sec=<seconds> for number of ECDSA sign
  verify ops in given time.

Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
---
 crypto/tcrypt.c |  250 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 crypto/tcrypt.h |  122 +++++++++++++++++++++++++++
 2 files changed, 368 insertions(+), 4 deletions(-)

diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index ae22f05d5936..0e4547fe23a8 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -7,6 +7,7 @@
  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
  * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org>
  * Copyright (c) 2007 Nokia Siemens Networks
+ * Copyright (c) 2017 NVIDIA Corporation
  *
  * Updated RFC4106 AES-GCM testing.
  *    Authors: Aidan O'Mahony (aidan.o.mahony@intel.com)
@@ -25,6 +26,7 @@
 #include <crypto/aead.h>
 #include <crypto/hash.h>
 #include <crypto/skcipher.h>
+#include <crypto/akcipher.h>
 #include <linux/err.h>
 #include <linux/fips.h>
 #include <linux/init.h>
@@ -44,10 +46,12 @@
 #define TVMEMSIZE	4
 
 /*
-* Used by test_cipher_speed()
-*/
-#define ENCRYPT 1
-#define DECRYPT 0
+ * Used by test_cipher_speed()
+ */
+#define DECRYPT		0
+#define ENCRYPT		1
+#define SIGN		2
+#define VERIFY		3
 
 #define MAX_DIGEST_SIZE		64
 
@@ -994,6 +998,223 @@ static void test_cipher_speed(const char *algo, int enc, unsigned int secs,
 				   false);
 }
 
+static inline int do_one_akcipher_op(struct akcipher_request *r, int ret)
+{
+	if (ret == -EINPROGRESS || ret == -EBUSY) {
+		struct tcrypt_result *tr = r->base.data;
+
+		wait_for_completion(&tr->completion);
+		reinit_completion(&tr->completion);
+		ret = tr->err;
+	}
+	return ret;
+}
+
+static int test_akcipher_jiffies(struct akcipher_request *r, int op, int secs)
+{
+	unsigned long start, end;
+	int count, ret;
+
+	for (start = jiffies, end = start + secs * HZ, count = 0;
+	     time_before(jiffies, end); count++) {
+
+		switch (op) {
+		case SIGN:
+			ret = do_one_akcipher_op(r, crypto_akcipher_sign(r));
+			break;
+		case VERIFY:
+			ret = do_one_akcipher_op(r, crypto_akcipher_verify(r));
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+		if (ret)
+			return ret;
+	}
+
+	pr_info("%d operations in %d seconds\n", count, secs);
+	return 0;
+}
+
+static int test_akcipher_cycles(struct akcipher_request *r, int op)
+{
+	unsigned long cycles = 0;
+	int ret = 0;
+	int i;
+
+	/* Warm-up run. */
+	for (i = 0; i < 4; i++) {
+		switch (op) {
+		case SIGN:
+			ret = do_one_akcipher_op(r, crypto_akcipher_sign(r));
+			break;
+		case VERIFY:
+			ret = do_one_akcipher_op(r, crypto_akcipher_verify(r));
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+		if (ret)
+			goto out;
+	}
+
+	/* The real thing. */
+	for (i = 0; i < 8; i++) {
+		cycles_t start, end;
+
+		start = get_cycles();
+		switch (op) {
+		case SIGN:
+			ret = do_one_akcipher_op(r, crypto_akcipher_sign(r));
+			break;
+		case VERIFY:
+			ret = do_one_akcipher_op(r, crypto_akcipher_verify(r));
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+		end = get_cycles();
+
+		if (ret)
+			goto out;
+
+		cycles += end - start;
+	}
+out:
+	if (ret == 0)
+		pr_info("1 operation in %lu cycles\n", (cycles + 4) / 8);
+
+	return ret;
+}
+
+static void test_akcipher_speed(const char *algo, int op, unsigned int secs,
+				struct akcipher_speed_template *template,
+				unsigned int tcount, u8 *keysize)
+{
+	unsigned int ret, i, j;
+	struct tcrypt_result tresult;
+	const char *key;
+	struct akcipher_request *req;
+	struct crypto_akcipher *tfm;
+	unsigned int m_size = 0;
+	unsigned int nbytes = 0;
+	const char *o;
+
+	if (op == SIGN)
+		o = "sign";
+	else if (op == VERIFY)
+		o = "verify";
+	else
+		return;
+
+	tfm = crypto_alloc_akcipher(algo, 0, 0);
+	if (IS_ERR(tfm)) {
+		pr_err("failed to load transform for %s: %ld\n", algo,
+		       PTR_ERR(tfm));
+		return;
+	}
+
+	req = akcipher_request_alloc(tfm, GFP_KERNEL);
+	if (!req) {
+		pr_err("tcrypt: akcipher: Failed to allocate request for %s\n",
+		       algo);
+		goto out;
+	}
+
+	init_completion(&tresult.completion);
+	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				      tcrypt_complete, &tresult);
+
+	i = 0;
+	do {
+		struct scatterlist sg[TVMEMSIZE];
+
+		memset(tvmem[0], 0xff, PAGE_SIZE);
+
+		/* set key */
+		key = tvmem[0];
+		for (j = 0; j < tcount; j++) {
+			if (template[j].key_len == *keysize) {
+				key = template[j].key;
+				break;
+			}
+		}
+
+		ret = crypto_akcipher_set_pub_key(tfm, key, *keysize);
+		if (ret) {
+			pr_err("set_pub_key() failed\n");
+			goto out_free_req;
+		}
+
+		ret = crypto_akcipher_set_priv_key(tfm, key, *keysize);
+		if (ret) {
+			pr_err("set_priv_key() failed\n");
+			goto out_free_req;
+		}
+
+		/* set up src/dst buffs */
+		sg_init_table(sg, TVMEMSIZE);
+		if (op == SIGN) {
+			m_size = template[j].m_size;
+			nbytes = template[j].c_size / 3;
+
+			memcpy(tvmem[0], template[j].m, m_size);
+
+			sg_set_buf(&sg[0], tvmem[0], m_size);
+			akcipher_request_set_crypt(req, sg, sg,
+						   m_size, PAGE_SIZE);
+		} else if (op == VERIFY) {
+			m_size = template[j].m_size;
+			nbytes = template[j].c_size / 3;
+
+			memcpy(tvmem[0], template[j].m, m_size);
+			memcpy(tvmem[1], (u8 *)(template[j].c) + nbytes,
+			       nbytes);
+			memcpy(tvmem[2], (u8 *)(template[j].c) + 2 * nbytes,
+			       nbytes);
+
+			sg_set_buf(&sg[0], tvmem[0], m_size);
+			sg_set_buf(&sg[1], tvmem[1], nbytes);
+			sg_set_buf(&sg[2], tvmem[2], nbytes);
+
+			akcipher_request_set_crypt(req, sg, sg,
+						   m_size + 2 * nbytes,
+						   PAGE_SIZE);
+		} else {
+			pr_err("invalid op\n");
+			ret = -EINVAL;
+			goto out_free_req;
+		}
+
+
+		pr_info("\ntesting speed of %s (%s) %s with keysize %d\n",
+			algo, get_driver_name(crypto_akcipher, tfm), o,
+			nbytes * 8);
+
+		if (secs)
+			ret = test_akcipher_jiffies(req, op, secs);
+		else
+			ret = test_akcipher_cycles(req, op);
+
+		if (ret) {
+			pr_err("%s() failed\n", o);
+			break;
+		}
+
+		i++;
+		keysize++;
+
+	} while (*keysize);
+
+out_free_req:
+	akcipher_request_free(req);
+out:
+	crypto_free_akcipher(tfm);
+}
+
 static void test_available(void)
 {
 	char **name = check;
@@ -2035,6 +2256,27 @@ static int do_test(const char *alg, u32 type, u32 mask, int m)
 				   speed_template_8_32);
 		break;
 
+	case 560:
+		ret += tcrypt_test("ecdsa");
+		break;
+
+	case 561:
+#ifndef CONFIG_CRYPTO_FIPS
+		test_akcipher_speed("ecdsa", SIGN, sec,
+				    ecdsa_speed_template, ECDSA_SPEED_VECTORS,
+				    akc_speed_template_P192);
+		test_akcipher_speed("ecdsa", VERIFY, sec,
+				    ecdsa_speed_template, ECDSA_SPEED_VECTORS,
+				    akc_speed_template_P192);
+#endif
+		test_akcipher_speed("ecdsa", SIGN, sec,
+				    ecdsa_speed_template, ECDSA_SPEED_VECTORS,
+				    akc_speed_template_P256);
+		test_akcipher_speed("ecdsa", VERIFY, sec,
+				    ecdsa_speed_template, ECDSA_SPEED_VECTORS,
+				    akc_speed_template_P256);
+		break;
+
 	case 1000:
 		test_available();
 		break;
diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h
index f0bfee1bb293..bd6a4b1cbcbe 100644
--- a/crypto/tcrypt.h
+++ b/crypto/tcrypt.h
@@ -7,6 +7,7 @@
  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
  * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org>
  * Copyright (c) 2007 Nokia Siemens Networks
+ * Copyright (c) 2017 NVIDIA Corporation
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -17,6 +18,16 @@
 #ifndef _CRYPTO_TCRYPT_H
 #define _CRYPTO_TCRYPT_H
 
+struct akcipher_speed_template {
+	unsigned char *key;
+	unsigned char *m;
+	unsigned char *c;
+	unsigned int key_len;
+	unsigned int m_size;
+	unsigned int c_size;
+	bool public_key_vec;
+};
+
 struct cipher_speed_template {
 	const char *key;
 	unsigned int klen;
@@ -48,6 +59,117 @@ struct hash_speed {
 };
 
 /*
+ * ECDSA test vectors.
+ */
+#ifdef CONFIG_CRYPTO_FIPS
+#define ECDSA_SPEED_VECTORS	1
+#else
+#define ECDSA_SPEED_VECTORS	2
+#endif
+
+static struct akcipher_speed_template ecdsa_speed_template[] = {
+	{
+#ifndef CONFIG_CRYPTO_FIPS
+		/* [P-192,SHA-256] */
+		.m =
+		/* Msg / Hash */
+		"\xd0\xd8\xc0\x99\xe0\xe2\xf7\xf8"
+		"\x87\xe1\x6d\x11\xe1\xcc\x20\x43"
+		"\xaf\xc0\x80\xdb\x47\x72\xfa\xe3"
+		"\x95\xe5\xd1\x34\x7d\x31\xe8\x5a",
+		.m_size = 32,
+		.key =
+		/* version */
+		"\x01"
+		/* curve_id */
+		"\x01"
+		/* d */
+		"\x47\x7a\xf2\x5c\x86\xef\x09\x08"
+		"\xa4\x9a\x47\x53\x06\xfc\x61\xbc"
+		"\xa5\x6f\xdd\x7d\x2f\xd2\xed\x24"
+		/* Qx */
+		"\xdc\x14\xd4\xd8\x2e\x1e\x25\x2f"
+		"\x66\x28\xaa\x80\xbc\x38\x6a\x07"
+		"\x8a\x70\xb7\x74\x71\x2d\xf1\x9b"
+		/* Qy */
+		"\x98\x34\x57\x11\xb0\xdc\x3d\xff"
+		"\xfc\xdc\xfe\xa2\x1c\x47\x9e\x4e"
+		"\x82\x08\xfc\x7d\xd0\xc8\x54\x48",
+		.key_len = 74,
+		.c =
+		/* k */
+		"\x3e\x70\xc7\x86\xaf\xaa\x71\x7c"
+		"\x68\x96\xc5\xc3\xec\xb8\x29\xa3"
+		"\xfa\xf7\xa5\x36\xa2\x17\xc8\xa5"
+		/* R */
+		"\xf8\xef\x13\xa8\x86\xe6\x73\x85"
+		"\xdf\x2e\x88\x99\x91\x9b\xc2\x90"
+		"\xea\x1f\x36\xf4\xec\xba\x4a\x35"
+		/* S */
+		"\xc1\x82\x9e\x94\xb7\x58\x2c\x63"
+		"\x8e\xd7\x15\x5a\x38\x47\x30\x9b"
+		"\x1c\x11\x86\xac\x00\x00\xf5\x80",
+		.c_size = 72,
+	}, {
+#endif
+		/* [P-256,SHA-256] */
+		.m =
+		/* Msg / Hash */
+		"\x56\xec\x33\xa1\xa6\xe7\xc4\xdb"
+		"\x77\x03\x90\x1a\xfb\x2e\x1e\x4e"
+		"\x50\x09\xfe\x04\x72\x89\xc5\xc2"
+		"\x42\x13\x6c\xe3\xb7\xf6\xac\x44",
+		.m_size = 32,
+		.key =
+		/* version */
+		"\x01"
+		/* curve_id */
+		"\x02"
+		/* d */
+		"\x64\xb4\x72\xda\x6d\xa5\x54\xca"
+		"\xac\x3e\x4e\x0b\x13\xc8\x44\x5b"
+		"\x1a\x77\xf4\x59\xee\xa8\x4f\x1f"
+		"\x58\x8b\x5f\x71\x3d\x42\x9b\x51"
+		/* Qx */
+		"\x83\xbf\x71\xc2\x46\xff\x59\x3c"
+		"\x2f\xb1\xbf\x4b\xe9\x5d\x56\xd3"
+		"\xcc\x8f\xdb\x48\xa2\xbf\x33\xf0"
+		"\xf4\xc7\x5f\x07\x1c\xe9\xcb\x1c"
+		/* Qy */
+		"\xa9\x4c\x9a\xa8\x5c\xcd\x7c\xdc"
+		"\x78\x4e\x40\xb7\x93\xca\xb7\x6d"
+		"\xe0\x13\x61\x0e\x2c\xdb\x1f\x1a"
+		"\xa2\xf9\x11\x88\xc6\x14\x40\xce",
+		.key_len = 98,
+		.c =
+		/* k */
+		"\xde\x68\x2a\x64\x87\x07\x67\xb9"
+		"\x33\x5d\x4f\x82\x47\x62\x4a\x3b"
+		"\x7f\x3c\xe9\xf9\x45\xf2\x80\xa2"
+		"\x61\x6a\x90\x4b\xb1\xbb\xa1\x94"
+		/* R */
+		"\xac\xc2\xc8\x79\x6f\x5e\xbb\xca"
+		"\x7a\x5a\x55\x6a\x1f\x6b\xfd\x2a"
+		"\xed\x27\x95\x62\xd6\xe3\x43\x88"
+		"\x5b\x79\x14\xb5\x61\x80\xac\xf3"
+		/* S */
+		"\x03\x89\x05\xcc\x2a\xda\xcd\x3c"
+		"\x5a\x17\x6f\xe9\x18\xb2\x97\xef"
+		"\x1c\x37\xf7\x2b\x26\x76\x6c\x78"
+		"\xb2\xa6\x05\xca\x19\x78\xf7\x8b",
+		.c_size = 96,
+	},
+};
+
+/*
+ * AKCipher speed tests
+ */
+#ifndef CONFIG_CRYPTO_FIPS
+static u8 akc_speed_template_P192[] = {74, 0};
+#endif
+static u8 akc_speed_template_P256[] = {98, 0};
+
+/*
  * Cipher speed tests
  */
 static u8 speed_template_8[] = {8, 0};
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH 4/6] crypto: ecdsa: add ECDSA SW implementation
  2017-01-20 11:35 ` [PATCH 4/6] crypto: ecdsa: add ECDSA SW implementation Nitin Kumbhar
@ 2017-01-20 13:06   ` Stephan Müller
  2017-01-26  5:52     ` Nitin Kumbhar
  0 siblings, 1 reply; 20+ messages in thread
From: Stephan Müller @ 2017-01-20 13:06 UTC (permalink / raw)
  To: Nitin Kumbhar; +Cc: herbert, davem, linux-crypto

Am Freitag, 20. Januar 2017, 17:05:59 CET schrieb Nitin Kumbhar:

Hi Nitin,

> This adds support for ECDSA algorithm. This implementation supports
> sign and verify functions for ECDSA algorithm using akcipher. As ECDSA
> is a signing algorithm dummy functions are added for encrypt() and
> decrypt().
> 
> Helper routines for parsing public and private ECC keys for ECDSA are
> added as well.
> 
> Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
> ---
>  crypto/Kconfig            |    7 +
>  crypto/Makefile           |    3 +
>  crypto/ecdsa.c            |  331
> +++++++++++++++++++++++++++++++++++++++++++++ crypto/ecdsa_helper.c     | 
> 116 ++++++++++++++++
>  include/crypto/akcipher.h |    5 +-
>  include/crypto/ecdsa.h    |   29 ++++
>  6 files changed, 490 insertions(+), 1 deletions(-)
>  create mode 100644 crypto/ecdsa.c
>  create mode 100644 crypto/ecdsa_helper.c
>  create mode 100644 include/crypto/ecdsa.h
> 
> diff --git a/crypto/Kconfig b/crypto/Kconfig
> index e240075d6f46..1c5c236b3bbc 100644
> --- a/crypto/Kconfig
> +++ b/crypto/Kconfig
> @@ -140,6 +140,13 @@ config CRYPTO_ECDH
>  	help
>  	  Generic implementation of the ECDH algorithm
> 
> +config CRYPTO_ECDSA
> +	tristate "ECDSA algorithm"
> +	select CRYPTO_AKCIPHER
> +	select CRYPTO_ECC
> +	help
> +	  Generic implementation of the ECDSA algorithm
> +
>  config CRYPTO_MANAGER
>  	tristate "Cryptographic algorithm manager"
>  	select CRYPTO_MANAGER2
> diff --git a/crypto/Makefile b/crypto/Makefile
> index 827740a47a37..9c13eb2ade6a 100644
> --- a/crypto/Makefile
> +++ b/crypto/Makefile
> @@ -38,6 +38,9 @@ obj-$(CONFIG_CRYPTO_ECC) += ecc.o
>  ecdh_generic-y := ecdh.o
>  ecdh_generic-y += ecdh_helper.o
>  obj-$(CONFIG_CRYPTO_ECDH) += ecdh_generic.o
> +ecdsa_generic-y := ecdsa.o
> +ecdsa_generic-y += ecdsa_helper.o
> +obj-$(CONFIG_CRYPTO_ECDSA) += ecdsa_generic.o
> 
>  $(obj)/rsapubkey-asn1.o: $(obj)/rsapubkey-asn1.c $(obj)/rsapubkey-asn1.h
>  $(obj)/rsaprivkey-asn1.o: $(obj)/rsaprivkey-asn1.c $(obj)/rsaprivkey-asn1.h
> diff --git a/crypto/ecdsa.c b/crypto/ecdsa.c
> new file mode 100644
> index 000000000000..d415900af3bd
> --- /dev/null
> +++ b/crypto/ecdsa.c
> @@ -0,0 +1,331 @@
> +/*
> + * ECDSA generic algorithm
> + *
> + * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> Free + * Software Foundation; either version 2 of the License, or (at your
> option) + * any later version.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/scatterlist.h>
> +#include <linux/random.h>
> +#include <crypto/internal/akcipher.h>
> +#include <crypto/akcipher.h>
> +#include <crypto/ecdsa.h>
> +
> +#include "ecc.h"
> +
> +struct ecdsa_ctx {
> +	unsigned int curve_id;
> +	unsigned int ndigits;
> +	u64 private_key[ECC_MAX_DIGITS];
> +	u64 public_key[2 * ECC_MAX_DIGITS];
> +};
> +
> +static inline struct ecdsa_ctx *ecdsa_get_ctx(struct crypto_akcipher *tfm)
> +{
> +	return akcipher_tfm_ctx(tfm);
> +}
> +
> +static void ecdsa_parse_msg_hash(struct akcipher_request *req, u64 *msg,
> +				 unsigned int ndigits)
> +{
> +	unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +	unsigned int hash_len, hash_off;
> +	unsigned char *hash, *msg_ptr;
> +	int i;
> +
> +	/*
> +	 * If hash_len == nbytes:
> +	 *	copy nbytes from req
> +	 * If hash_len > nbytes:
> +	 *	copy left most nbytes from hash ignoring LSBs
> +	 * If hash_len < nbytes:
> +	 *	copy hash_len from req and zero remaining bytes
> +	 *	(nbytes - hash_len)
> +	 */
> +	hash_len = req->src[0].length;
> +	hash_off = hash_len <= nbytes ? 0 : hash_len - nbytes;
> +
> +	msg_ptr = (unsigned char *)msg;
> +	hash = sg_virt(&req->src[0]);
> +
> +	for (i = hash_off; i < hash_len; i++)
> +		*msg_ptr++ = hash[i];
> +	for (; i < nbytes; i++)
> +		*msg_ptr++ = 0;
> +}
> +
> +int ecdsa_sign(struct akcipher_request *req)
> +{
> +	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
> +	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
> +	unsigned int ndigits = ctx->ndigits;
> +	unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +	unsigned int curve_id = ctx->curve_id;
> +	const struct ecc_curve *curve = ecc_get_curve(curve_id);
> +	struct ecc_point *x1y1 = NULL;
> +	u64 z[ndigits], d[ndigits];
> +	u64 k[ndigits], k_inv[ndigits];
> +	u64 r[ndigits], s[ndigits];
> +	u64 dr[ndigits], zdr[ndigits];
> +	u8 *r_ptr, *s_ptr;
> +
> +	if (req->dst_len < 2 * nbytes) {
> +		req->dst_len = 2 * nbytes;
> +		return -EINVAL;
> +	}
> +
> +	ecdsa_parse_msg_hash(req, z, ndigits);
> +
> +	/* d */
> +	vli_set(d, (const u64 *)ctx->private_key, ndigits);
> +
> +	/* k */
> +#if defined(CONFIG_CRYPTO_MANAGER2)
> +	if (req->info) {
> +		vli_copy_from_buf(k, ndigits, req->info, nbytes);
> +	} else
> +#endif
> +		get_random_bytes(k, nbytes);

Please use crypto_get_default_rng /crypto_rng_get_bytes / 
crypto_put_default_rng here.

> +
> +	x1y1 = ecc_alloc_point(ndigits);
> +	if (!x1y1)
> +		return -ENOMEM;
> +
> +	/* (x1, y1) = k x G */
> +	ecc_point_mult(x1y1, &curve->g, k, NULL, curve->p, ndigits);
> +
> +	/* r = x1 mod n */
> +	vli_mod(r, x1y1->x, curve->n, ndigits);
> +
> +	/* k^-1 */
> +	vli_mod_inv(k_inv, k, curve->n, ndigits);
> +
> +	/* d . r mod n */
> +	vli_mod_mult(dr, d, r, curve->n, ndigits);
> +
> +	/* z + dr mod n */
> +	vli_mod_add(zdr, z, dr, curve->n, ndigits);
> +
> +	/* k^-1 . ( z + dr) mod n */
> +	vli_mod_mult(s, k_inv, zdr, curve->n, ndigits);
> +
> +	/* write signature (r,s) in dst */
> +	r_ptr = sg_virt(req->dst);
> +	s_ptr = (u8 *)sg_virt(req->dst) + nbytes;
> +
> +	vli_copy_to_buf(r_ptr, nbytes, r, ndigits);
> +	vli_copy_to_buf(s_ptr, nbytes, s, ndigits);
> +
> +	req->dst_len = 2 * nbytes;
> +
> +	ecc_free_point(x1y1);
> +	return 0;
> +}
> +
> +int ecdsa_verify(struct akcipher_request *req)
> +{
> +	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
> +	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
> +	unsigned int ndigits = ctx->ndigits;
> +	unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +	unsigned int curve_id = ctx->curve_id;
> +	const struct ecc_curve *curve = ecc_get_curve(curve_id);
> +	struct ecc_point *x1y1 = NULL, *x2y2 = NULL, *Q = NULL;
> +	u64 r[ndigits], s[ndigits], v[ndigits];
> +	u64 z[ndigits], w[ndigits];
> +	u64 u1[ndigits], u2[ndigits];
> +	u64 x1[ndigits], x2[ndigits];
> +	u64 y1[ndigits], y2[ndigits];
> +	u64 *ctx_qx, *ctx_qy;
> +	int ret;
> +
> +	x1y1 = ecc_alloc_point(ndigits);
> +	x2y2 = ecc_alloc_point(ndigits);
> +	Q = ecc_alloc_point(ndigits);
> +	if (!x1y1 || !x2y2 || !Q) {
> +		ret = -ENOMEM;
> +		goto exit;
> +	}
> +
> +	ecdsa_parse_msg_hash(req, z, ndigits);
> +
> +	/* Signature r,s */
> +	vli_copy_from_buf(r, ndigits, sg_virt(&req->src[1]), nbytes);
> +	vli_copy_from_buf(s, ndigits, sg_virt(&req->src[2]), nbytes);
> +
> +	/* w = s^-1 mod n */
> +	vli_mod_inv(w, s, curve->n, ndigits);
> +
> +	/* u1 = zw mod n */
> +	vli_mod_mult(u1, z, w, curve->n, ndigits);
> +
> +	/* u2 = rw mod n */
> +	vli_mod_mult(u2, r, w, curve->n, ndigits);
> +
> +	/* u1 . G */
> +	ecc_point_mult(x1y1, &curve->g, u1, NULL, curve->p, ndigits);
> +
> +	/* Q=(Qx,Qy) */
> +	ctx_qx = ctx->public_key;
> +	ctx_qy = ctx_qx + ECC_MAX_DIGITS;
> +	vli_set(Q->x, ctx_qx, ndigits);
> +	vli_set(Q->y, ctx_qy, ndigits);
> +
> +	/* u2 x Q */
> +	ecc_point_mult(x2y2, Q, u2, NULL, curve->p, ndigits);
> +
> +	vli_set(x1, x1y1->x, ndigits);
> +	vli_set(y1, x1y1->y, ndigits);
> +	vli_set(x2, x2y2->x, ndigits);
> +	vli_set(y2, x2y2->y, ndigits);
> +
> +	/* x1y1 + x2y2 => P + Q; P + Q in x2 y2 */
> +	ecc_point_add(x1, y1, x2, y2, curve->p, ndigits);
> +
> +	/* v = x mod n */
> +	vli_mod(v, x2, curve->n, ndigits);
> +
> +	/* validate signature */
> +	ret = vli_cmp(v, r, ndigits) == 0 ? 0 : -EBADMSG;
> + exit:
> +	ecc_free_point(x1y1);
> +	ecc_free_point(x2y2);
> +	ecc_free_point(Q);
> +	return ret;
> +}
> +
> +int ecdsa_dummy_enc(struct akcipher_request *req)
> +{
> +	return -EINVAL;
> +}
> +
> +int ecdsa_dummy_dec(struct akcipher_request *req)
> +{
> +	return -EINVAL;
> +}
> +
> +int ecdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key,
> +		      unsigned int keylen)
> +{
> +	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
> +	struct ecdsa params;
> +	unsigned int ndigits;
> +	unsigned int nbytes;
> +	u8 *params_qx, *params_qy;
> +	u64 *ctx_qx, *ctx_qy;
> +	int ret = 0;
> +
> +	if (crypto_ecdsa_parse_pub_key(key, keylen, &params))
> +		return -EINVAL;
> +
> +	ndigits = ecdsa_supported_curve(params.curve_id);
> +
> +	ctx->curve_id = params.curve_id;
> +	ctx->ndigits = ndigits;
> +	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +
> +	params_qx = params.key;
> +	params_qy = params_qx + ECC_MAX_DIGIT_BYTES;
> +
> +	ctx_qx = ctx->public_key;
> +	ctx_qy = ctx_qx + ECC_MAX_DIGITS;
> +
> +	vli_copy_from_buf(ctx_qx, ndigits, params_qx, nbytes);
> +	vli_copy_from_buf(ctx_qy, ndigits, params_qy, nbytes);
> +
> +	memset(&params, 0, sizeof(params));
> +	return ret;

Shouldn't there be a check that the point is on the curve? As I think the same 
issue is applicable to ECDH, I guess a common service function should be used 
that we can also invoke from ECDH.

> +}
> +
> +int ecdsa_set_priv_key(struct crypto_akcipher *tfm, const void *key,
> +		       unsigned int keylen)
> +{
> +	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
> +	struct ecdsa params;
> +	unsigned int ndigits;
> +	unsigned int nbytes;
> +
> +	if (crypto_ecdsa_parse_priv_key(key, keylen, &params))
> +		return -EINVAL;
> +
> +	ndigits = ecdsa_supported_curve(params.curve_id);
> +
> +	ctx->curve_id = params.curve_id;
> +	ctx->ndigits = ndigits;
> +	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +
> +	if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits,
> +			     (const u8 *)params.key, params.key_size) < 0)
> +		return -EINVAL;
> +
> +	vli_copy_from_buf(ctx->private_key, ndigits, params.key, nbytes);
> +
> +	memset(&params, 0, sizeof(params));
> +	return 0;
> +}
> +
> +int ecdsa_max_size(struct crypto_akcipher *tfm)
> +{
> +	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
> +	int nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +
> +	/* For r,s */
> +	return 2 * nbytes;
> +}
> +
> +int ecdsa_init_tfm(struct crypto_akcipher *tfm)
> +{
> +	return 0;
> +}
> +
> +void ecdsa_exit_tfm(struct crypto_akcipher *tfm)
> +{
> +}
> +
> +static struct akcipher_alg ecdsa_alg = {
> +	.sign		= ecdsa_sign,
> +	.verify		= ecdsa_verify,
> +	.encrypt	= ecdsa_dummy_enc,
> +	.decrypt	= ecdsa_dummy_dec,
> +	.set_priv_key	= ecdsa_set_priv_key,
> +	.set_pub_key	= ecdsa_set_pub_key,
> +	.max_size	= ecdsa_max_size,
> +	.init		= ecdsa_init_tfm,
> +	.exit		= ecdsa_exit_tfm,
> +	.base = {
> +		.cra_name	= "ecdsa",
> +		.cra_driver_name = "ecdsa-generic",
> +		.cra_priority	= 100,
> +		.cra_module	= THIS_MODULE,
> +		.cra_ctxsize	= sizeof(struct ecdsa_ctx),
> +	},
> +};
> +
> +static int ecdsa_init(void)
> +{
> +	int ret;
> +
> +	ret = crypto_register_akcipher(&ecdsa_alg);
> +	if (ret)
> +		pr_err("ecdsa alg register failed. err:%d\n", ret);
> +	return ret;
> +}
> +
> +static void ecdsa_exit(void)
> +{
> +	crypto_unregister_akcipher(&ecdsa_alg);
> +}
> +
> +module_init(ecdsa_init);
> +module_exit(ecdsa_exit);
> +
> +MODULE_ALIAS_CRYPTO("ecdsa");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("ECDSA Generic Algorithm");
> +MODULE_AUTHOR("NVIDIA Corporation");
> diff --git a/crypto/ecdsa_helper.c b/crypto/ecdsa_helper.c
> new file mode 100644
> index 000000000000..d31eb54431a9
> --- /dev/null
> +++ b/crypto/ecdsa_helper.c
> @@ -0,0 +1,116 @@
> +/*
> + * ECDSA helper routines
> + *
> + * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> Free + * Software Foundation; either version 2 of the License, or (at your
> option) + * any later version.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/export.h>
> +#include <linux/err.h>
> +#include <linux/string.h>
> +#include <crypto/ecdsa.h>
> +
> +#include "ecc.h"
> +
> +#define ECDSA_KEY_MIN_SIZE	(1 + 1 + 24) /* ver + cid + n (P-192) */
> +
> +unsigned int ecdsa_supported_curve(unsigned int curve_id)
> +{
> +	switch (curve_id) {
> +	case ECC_CURVE_NIST_P192: return 3;
> +	case ECC_CURVE_NIST_P256: return 4;
> +	default: return 0;
> +	}
> +}

Wouldn't it be better to have a common function with ECDH as this has almost 
the same code in ecdh_supported_curve?

> +
> +static inline u8 *ecdsa_pack_data(void *dst, const void *src, size_t sz)
> +{
> +	memcpy(dst, src, sz);
> +	return dst + sz;
> +}
> +
> +static inline const u8 *ecdsa_unpack_data(void *dst, const void *src,
> size_t sz) +{
> +	memcpy(dst, src, sz);
> +	return src + sz;
> +}
> +
> +int crypto_ecdsa_parse_pub_key(const char *buf, unsigned int len,
> +			       struct ecdsa *params)
> +{
> +	unsigned char version;
> +	unsigned int ndigits;
> +	unsigned int nbytes;
> +	const u8 *ptr = buf;
> +	u8 *qx, *qy;
> +
> +	if (unlikely(!buf) || len < ECDSA_KEY_MIN_SIZE)
> +		return -EINVAL;
> +
> +	ptr = ecdsa_unpack_data(&version, ptr, sizeof(version));
> +	if (version != 1)
> +		return -EINVAL;
> +
> +	ptr = ecdsa_unpack_data(&params->curve_id, ptr,
> +				sizeof(params->curve_id));
> +
> +	ndigits = ecdsa_supported_curve(params->curve_id);
> +	if (!ndigits)
> +		return -EINVAL;
> +
> +	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +
> +	/* skip private key */
> +	ptr = ecdsa_unpack_data(&params->key, ptr, nbytes);
> +
> +	/* copy public key */
> +	qx = params->key;
> +	qy = qx + ECC_MAX_DIGIT_BYTES;
> +
> +	ptr = ecdsa_unpack_data(qx, ptr, nbytes);
> +	ptr = ecdsa_unpack_data(qy, ptr, nbytes);
> +
> +	params->key_size = 2 * nbytes;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(crypto_ecdsa_parse_pub_key);
> +
> +int crypto_ecdsa_parse_priv_key(const char *buf, unsigned int len,
> +				struct ecdsa *params)
> +{
> +	unsigned char version;
> +	unsigned int ndigits;
> +	unsigned int nbytes;
> +	const u8 *ptr = buf;
> +
> +	if (unlikely(!buf) || len < ECDSA_KEY_MIN_SIZE)
> +		return -EINVAL;
> +
> +	ptr = ecdsa_unpack_data(&version, ptr, sizeof(version));
> +	if (version != 1)
> +		return -EINVAL;
> +
> +	ptr = ecdsa_unpack_data(&params->curve_id, ptr,
> +				sizeof(params->curve_id));
> +
> +	ndigits = ecdsa_supported_curve(params->curve_id);
> +	if (!ndigits)
> +		return -EINVAL;
> +
> +	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +
> +	params->key_size = nbytes;
> +
> +	/* copy private key */
> +	ptr = ecdsa_unpack_data(&params->key, ptr, nbytes);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(crypto_ecdsa_parse_priv_key);
> diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
> index c37cc59e9bf2..6b34e9043a6f 100644
> --- a/include/crypto/akcipher.h
> +++ b/include/crypto/akcipher.h
> @@ -3,6 +3,7 @@
>   *
>   * Copyright (c) 2015, Intel Corporation
>   * Authors: Tadeusz Struk <tadeusz.struk@intel.com>
> + * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
>   *
>   * This program is free software; you can redistribute it and/or modify it
>   * under the terms of the GNU General Public License as published by the
> Free @@ -27,6 +28,7 @@
>   *		result.
>   *		In case of error where the dst sgl size was insufficient,
>   *		it will be updated to the size required for the operation.
> + * @info:	Any request specific data needed to process the request.
>   * @__ctx:	Start of private context data
>   */
>  struct akcipher_request {
> @@ -35,6 +37,7 @@ struct akcipher_request {
>  	struct scatterlist *dst;
>  	unsigned int src_len;
>  	unsigned int dst_len;
> +	void *info;
>  	void *__ctx[] CRYPTO_MINALIGN_ATTR;
>  };
> 
> @@ -193,7 +196,7 @@ static inline void crypto_free_akcipher(struct
> crypto_akcipher *tfm) {
>  	struct akcipher_request *req;
> 
> -	req = kmalloc(sizeof(*req) + crypto_akcipher_reqsize(tfm), gfp);
> +	req = kzalloc(sizeof(*req) + crypto_akcipher_reqsize(tfm), gfp);
>  	if (likely(req))
>  		akcipher_request_set_tfm(req, tfm);
> 
> diff --git a/include/crypto/ecdsa.h b/include/crypto/ecdsa.h
> new file mode 100644
> index 000000000000..c71d21e654b9
> --- /dev/null
> +++ b/include/crypto/ecdsa.h
> @@ -0,0 +1,29 @@
> +/*
> + * ECC parameters for ECDSA
> + *
> + * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> Free + * Software Foundation; either version 2 of the License, or (at your
> option) + * any later version.
> + *
> + */
> +
> +#ifndef _CRYPTO_ECDSA_
> +#define _CRYPTO_ECDSA_
> +
> +#include <crypto/ecc.h>
> +
> +struct ecdsa {
> +	unsigned char curve_id;
> +	unsigned char key[2 * ECC_MAX_DIGIT_BYTES];
> +	unsigned short key_size;
> +};
> +
> +unsigned int ecdsa_supported_curve(unsigned int curve_id);
> +int crypto_ecdsa_parse_pub_key(const char *buf, unsigned int len,
> +			       struct ecdsa *params);
> +int crypto_ecdsa_parse_priv_key(const char *buf, unsigned int len,
> +				struct ecdsa *params);
> +#endif /* _CRYPTO_ECDSA_ */

I would like to see soem documentation here similar to the ecdh.h. Especially, 
can you please add documentation which type of point representation you expect 
as input (e.g. affine representation)?

Ciao
Stephan

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 5/6] crypto: testmgr: add ECDSA tests
  2017-01-20 11:36 ` [PATCH 5/6] crypto: testmgr: add ECDSA tests Nitin Kumbhar
@ 2017-01-20 13:19   ` Stephan Müller
  2017-01-26  5:58     ` Nitin Kumbhar
  0 siblings, 1 reply; 20+ messages in thread
From: Stephan Müller @ 2017-01-20 13:19 UTC (permalink / raw)
  To: Nitin Kumbhar; +Cc: herbert, davem, linux-crypto

Am Freitag, 20. Januar 2017, 17:06:00 CET schrieb Nitin Kumbhar:

Hi Nitin,

> Update crypto test manager to include NIST ECDSA
> test vectors and various ECDSA tests. These include
> tests for ECDSA signing, ECDSA sign-verification,
> ECDSA signing and verifying generated signatures and
> invalidation of incorrect signatures.
> 
> Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
> ---
>  crypto/testmgr.c |  452
> +++++++++++++++++++++++++++++++++++++++++++++++++++++- crypto/testmgr.h | 
> 140 +++++++++++++++++
>  2 files changed, 589 insertions(+), 3 deletions(-)
> 
> diff --git a/crypto/testmgr.c b/crypto/testmgr.c
> index 98eb09782db8..a1db28cbc32d 100644
> --- a/crypto/testmgr.c
> +++ b/crypto/testmgr.c
> @@ -5,6 +5,7 @@
>   * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org>
>   * Copyright (c) 2007 Nokia Siemens Networks
>   * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
> + * Copyright (c) 2017 NVIDIA Corporation
>   *
>   * Updated RFC4106 AES-GCM testing.
>   *    Authors: Aidan O'Mahony (aidan.o.mahony@intel.com)
> @@ -2085,6 +2086,436 @@ static int alg_test_kpp(const struct alg_test_desc
> *desc, const char *driver, return err;
>  }
> 
> +static int do_test_ecdsa_verify(struct crypto_akcipher *tfm,
> +			      struct akcipher_testvec *vec)
> +{
> +	struct akcipher_request *req = NULL;
> +	u8 *r_str = NULL, *s_str = NULL;
> +	u8 *m_str = NULL;
> +	struct scatterlist src_tab[3], dst;
> +	struct tcrypt_result result;
> +	unsigned int outbuf_maxlen;
> +	u8 *outbuf = NULL;
> +	unsigned int nbytes;
> +	int err;
> +
> +	/* Alloc akcipher request */
> +	req = akcipher_request_alloc(tfm, GFP_KERNEL);
> +	if (!req)
> +		return -ENOMEM;
> +
> +	/* Set private key */
> +	err = crypto_akcipher_set_pub_key(tfm, vec->key, vec->key_len);
> +	if (err)
> +		goto error;
> +
> +	/*
> +	 * vec->c always contains k, R and S in that order. All are
> +	 * of same size and are equal to n i.e. the order of
> +	 * an elliptic curve.
> +	 */
> +	nbytes = vec->c_size / 3;
> +
> +	r_str = kzalloc(nbytes, GFP_KERNEL);
> +	s_str = kzalloc(nbytes, GFP_KERNEL);
> +	m_str = kzalloc(vec->m_size, GFP_KERNEL);
> +	if (!r_str || !s_str || !m_str) {
> +		err = -ENOMEM;
> +		goto error;
> +	}
> +	memcpy(r_str, (u8 *)vec->c + nbytes, nbytes);
> +	memcpy(s_str, (u8 *)vec->c + 2 * nbytes, nbytes);
> +	memcpy(m_str, vec->m, vec->m_size);
> +
> +	outbuf_maxlen = crypto_akcipher_maxsize(tfm);
> +	if (outbuf_maxlen < 0) {
> +		err = outbuf_maxlen;
> +		goto error;
> +	}
> +	outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL);
> +	if (!outbuf) {
> +		err = -ENOMEM;
> +		goto error;
> +	}
> +
> +	/* Set src and dst buffers */
> +	sg_init_table(src_tab, 3);
> +	sg_set_buf(&src_tab[0], m_str, vec->m_size);
> +	sg_set_buf(&src_tab[1], r_str, nbytes);
> +	sg_set_buf(&src_tab[2], s_str, nbytes);
> +	sg_init_one(&dst, outbuf, outbuf_maxlen);
> +
> +	akcipher_request_set_crypt(req, src_tab, &dst,
> +				   vec->m_size + 2 * nbytes, outbuf_maxlen);
> +
> +	/* Set up result callback */
> +	init_completion(&result.completion);
> +	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> +				      tcrypt_complete, &result);
> +
> +	/* Run ecdsa verify operation on sig (r,s) */
> +	err = wait_async_op(&result, crypto_akcipher_verify(req));
> +	if (err) {
> +		pr_err("alg: ecdsa: verify(rs) test failed. err %d\n", err);
> +		goto error;
> +	}
> +error:
> +	akcipher_request_free(req);
> +	kfree(r_str);
> +	kfree(s_str);
> +	kfree(m_str);
> +	kfree(outbuf);
> +	return err;
> +}
> +
> +static int do_test_ecdsa_invalid_verify(struct crypto_akcipher *tfm,
> +					struct akcipher_testvec *vec)
> +{
> +	struct akcipher_request *req = NULL;
> +	u8 *r_str = NULL, *s_str = NULL;
> +	u8 *m_str = NULL;
> +	struct scatterlist src_tab[3], dst;
> +	struct tcrypt_result result;
> +	unsigned int outbuf_maxlen;
> +	u8 *outbuf = NULL;
> +	unsigned int nbytes;
> +	int err;
> +
> +	/* Alloc akcipher request */
> +	req = akcipher_request_alloc(tfm, GFP_KERNEL);
> +	if (!req)
> +		return -ENOMEM;
> +
> +	/* Set private key */
> +	err = crypto_akcipher_set_pub_key(tfm, vec->key, vec->key_len);
> +	if (err)
> +		goto error;
> +
> +	/*
> +	 * vec->c always contains k, R and S in that order. All are
> +	 * of same size and are equal to n i.e. the order of
> +	 * an elliptic curve.
> +	 */
> +	nbytes = vec->c_size / 3;
> +
> +	r_str = kzalloc(nbytes, GFP_KERNEL);
> +	s_str = kzalloc(nbytes, GFP_KERNEL);
> +	m_str = kzalloc(vec->m_size, GFP_KERNEL);
> +	if (!r_str || !s_str || !m_str) {
> +		err = -ENOMEM;
> +		goto error;
> +	}
> +	memcpy(r_str, (u8 *)vec->c + 1 * nbytes, nbytes);
> +	memcpy(s_str, (u8 *)vec->c + 2 * nbytes, nbytes);
> +	memcpy(m_str, vec->m, vec->m_size);
> +
> +	outbuf_maxlen = crypto_akcipher_maxsize(tfm);
> +	if (outbuf_maxlen < 0) {
> +		err = outbuf_maxlen;
> +		goto error;
> +	}
> +	outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL);
> +	if (!outbuf) {
> +		err = -ENOMEM;
> +		goto error;
> +	}
> +
> +	/* Set src and dst buffers */
> +	sg_init_table(src_tab, 3);
> +	/* Intentionally set m_size to 8 to have invalid hash */
> +	sg_set_buf(&src_tab[0], m_str, 8);
> +	sg_set_buf(&src_tab[1], r_str, nbytes);
> +	sg_set_buf(&src_tab[2], s_str, nbytes);
> +	sg_init_one(&dst, outbuf, outbuf_maxlen);
> +
> +	akcipher_request_set_crypt(req, src_tab, &dst,
> +				   vec->m_size + 2 * nbytes, outbuf_maxlen);
> +
> +	/* Set up result callback */
> +	init_completion(&result.completion);
> +	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> +				      tcrypt_complete, &result);
> +
> +	/* Run ecdsa verify operation on sig (r,s) */
> +	err = wait_async_op(&result, crypto_akcipher_verify(req));
> +	if (err != -EBADMSG) {
> +		pr_err("alg: ecdsa: invalid verify test failed. err %d\n", err);
> +		goto error;
> +	}
> +	err = 0;
> +error:
> +	akcipher_request_free(req);
> +	kfree(r_str);
> +	kfree(s_str);
> +	kfree(m_str);
> +	kfree(outbuf);
> +	return err;
> +}

There seems to be a lot of code duplication between 
do_test_ecdsa_invalid_verify and do_test_ecdsa_verify -- can this be 
eliminated?
> +
> +static int do_test_ecdsa_sign_verify(struct crypto_akcipher *tfm,
> +				     struct akcipher_testvec *vec)
> +{
> +	struct akcipher_request *req = NULL;
> +	u8 *r_str = NULL, *s_str = NULL;
> +	u8 *m_str = NULL;
> +	struct scatterlist src_tab[3];
> +	struct scatterlist src, dst;
> +	struct tcrypt_result result;
> +	unsigned int outbuf_maxlen;
> +	void *outbuf = NULL;
> +	unsigned int nbytes;
> +	int err;
> +
> +	/* Alloc akcipher request */
> +	req = akcipher_request_alloc(tfm, GFP_KERNEL);
> +	if (!req)
> +		return -ENOMEM;
> +
> +	/* Set private key */
> +	err = crypto_akcipher_set_priv_key(tfm, vec->key, vec->key_len);
> +	if (err)
> +		goto error;
> +
> +	/* Set private key */
> +	err = crypto_akcipher_set_pub_key(tfm, vec->key, vec->key_len);
> +	if (err)
> +		goto error;
> +
> +	/*
> +	 * vec->c always contains k, R and S in that order. All are
> +	 * of same size and are equal to n i.e. the order of
> +	 * an elliptic curve.
> +	 */
> +	nbytes = vec->c_size / 3;
> +
> +	m_str = kzalloc(vec->m_size, GFP_KERNEL);
> +	if (!m_str) {
> +		err = -ENOMEM;
> +		goto error;
> +	}
> +	memcpy(m_str, vec->m, vec->m_size);
> +
> +	outbuf_maxlen = crypto_akcipher_maxsize(tfm);
> +	if (outbuf_maxlen < 0) {
> +		err = outbuf_maxlen;
> +		goto error;
> +	}
> +	outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL);
> +	if (!outbuf) {
> +		err = -ENOMEM;
> +		goto error;
> +	}
> +
> +	sg_init_one(&src, m_str, vec->m_size);
> +	sg_init_one(&dst, outbuf, outbuf_maxlen);
> +
> +	akcipher_request_set_crypt(req, &src, &dst,
> +				   vec->m_size, outbuf_maxlen);
> +
> +	/* Set up result callback */
> +	init_completion(&result.completion);
> +	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> +				      tcrypt_complete, &result);
> +
> +	/* Run ecdsa sign operation on message digest */
> +	err = wait_async_op(&result, crypto_akcipher_sign(req));
> +	if (err) {
> +		pr_err("alg: ecdsa: sign test failed. err %d\n", err);
> +		goto error;
> +	}
> +
> +	/* verify that signature (r,s) is valid */
> +	if (req->dst_len != 2 * nbytes) {
> +		pr_err("alg: ecdsa: sign test failed. Invalid sig len\n");
> +		err = -EINVAL;
> +		goto error;
> +	}
> +
> +	/* output contains r and s */
> +	r_str = outbuf;
> +	s_str = (u8 *)outbuf + nbytes;
> +
> +	/* Set src and dst buffers */
> +	sg_init_table(src_tab, 3);
> +	sg_set_buf(&src_tab[0], m_str, vec->m_size);
> +	sg_set_buf(&src_tab[1], r_str, nbytes);
> +	sg_set_buf(&src_tab[2], s_str, nbytes);
> +	sg_init_one(&dst, outbuf, outbuf_maxlen);
> +
> +	akcipher_request_set_crypt(req, src_tab, &dst,
> +				   vec->m_size + 2 * nbytes, outbuf_maxlen);
> +
> +	/* Set up result callback */
> +	init_completion(&result.completion);
> +	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> +				      tcrypt_complete, &result);
> +
> +	/* Run ecdsa verify operation on sig (r,s) */
> +	err = wait_async_op(&result, crypto_akcipher_verify(req));
> +	if (err) {
> +		pr_err("alg: ecdsa: verify test failed. err %d\n", err);
> +		goto error;
> +	}
> +error:
> +	akcipher_request_free(req);
> +	kfree(m_str);
> +	kfree(outbuf);
> +	return err;
> +}
> +
> +static int do_test_ecdsa_sign(struct crypto_akcipher *tfm,
> +			      struct akcipher_testvec *vec)
> +{
> +	struct akcipher_request *req = NULL;
> +	u8 *r_str = NULL, *s_str = NULL;
> +	u8 *k_str = NULL, *m_str = NULL;
> +	struct scatterlist src, dst;
> +	struct tcrypt_result result;
> +	unsigned int outbuf_maxlen;
> +	void *outbuf = NULL;
> +	unsigned int nbytes;
> +	int err;
> +
> +	/* Alloc akcipher request */
> +	req = akcipher_request_alloc(tfm, GFP_KERNEL);
> +	if (!req)
> +		return -ENOMEM;
> +
> +	/* Set private key */
> +	err = crypto_akcipher_set_priv_key(tfm, vec->key, vec->key_len);
> +	if (err)
> +		goto error;
> +
> +	/*
> +	 * vec->c always contains k, R and S in that order. All are
> +	 * of same size and are equal to n i.e. the order of
> +	 * an elliptic curve.
> +	 */
> +	nbytes = vec->c_size / 3;
> +
> +	k_str = kzalloc(nbytes, GFP_KERNEL);
> +	r_str = kzalloc(nbytes, GFP_KERNEL);
> +	s_str = kzalloc(nbytes, GFP_KERNEL);
> +	m_str = kzalloc(vec->m_size, GFP_KERNEL);
> +	if (!k_str || !r_str || !s_str || !m_str) {
> +		err = -ENOMEM;
> +		goto error;
> +	}
> +	memcpy(k_str, (u8 *)vec->c + 0 * nbytes, nbytes);
> +	memcpy(r_str, (u8 *)vec->c + 1 * nbytes, nbytes);
> +	memcpy(s_str, (u8 *)vec->c + 2 * nbytes, nbytes);
> +	memcpy(m_str, vec->m, vec->m_size);
> +
> +	outbuf_maxlen = crypto_akcipher_maxsize(tfm);
> +	if (outbuf_maxlen < 0) {
> +		err = outbuf_maxlen;
> +		goto error;
> +	}
> +	outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL);
> +	if (!outbuf) {
> +		err = -ENOMEM;
> +		goto error;
> +	}
> +
> +	/* Set src and dst buffers */
> +	sg_init_one(&src, m_str, vec->m_size);
> +	sg_init_one(&dst, outbuf, outbuf_maxlen);
> +
> +	akcipher_request_set_crypt(req, &src, &dst,
> +				   vec->m_size, outbuf_maxlen);
> +
> +	/* Set up result callback */
> +	init_completion(&result.completion);
> +	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> +				      tcrypt_complete, &result);
> +
> +	/* Set K in request for signing */
> +	req->info = k_str;
> +
> +	/* Run ecdsa sign operation on message digest */
> +	err = wait_async_op(&result, crypto_akcipher_sign(req));
> +	if (err) {
> +		pr_err("alg: ecdsa: sign(k) test failed. err %d\n", err);
> +		goto error;
> +	}
> +
> +	/* verify that signature (r,s) is valid */
> +	if (req->dst_len != 2 * nbytes) {
> +		pr_err("alg: ecdsa: sign(k) test failed. Invalid sig len\n");
> +		err = -EINVAL;
> +		goto error;
> +	}
> +
> +	if (memcmp(r_str, sg_virt(req->dst), nbytes)) {
> +		pr_err("alg: ecdsa: sign(k) test failed. Invalid sig(r)\n");
> +		err = -EINVAL;
> +		goto error;
> +	}
> +
> +	if (memcmp(s_str, (u8 *)sg_virt(req->dst) + nbytes, nbytes)) {
> +		pr_err("alg: ecdsa: sign(k) test failed. Invalid sig(s)\n");
> +		err = -EINVAL;
> +		goto error;
> +	}
> +error:
> +	akcipher_request_free(req);
> +	kfree(k_str);
> +	kfree(r_str);
> +	kfree(s_str);
> +	kfree(m_str);
> +	kfree(outbuf);
> +	return err;
> +}

Same here -- there seem to be a lot of code duplication -- can this be 
reduced?
> +
> +static int test_ecdsa_akcipher(struct crypto_akcipher *tfm, const char
> *alg, +		       struct akcipher_testvec *vecs, unsigned int tcount)
> +{
> +	int i, err = 0;
> +
> +	for (i = 0; i < tcount; i++) {
> +		err = do_test_ecdsa_verify(tfm, &vecs[i]);
> +		if (!err)
> +			continue;
> +
> +		pr_err("ecdsa: verify failed on vec %d, err=%d\n",
> +		       i + 1, err);

All of these pr_err logs here and below should be removed as these errors seem 
to be already logged.

> +		goto exit;
> +	}
> +
> +	for (i = 0; i < tcount; i++) {
> +		err = do_test_ecdsa_invalid_verify(tfm, &vecs[i]);
> +		if (!err)
> +			continue;
> +
> +		pr_err("ecdsa: verify(invl) failed on vec %d, err=%d\n",
> +		       i + 1, err);
> +		goto exit;
> +	}
> +
> +	for (i = 0; i < tcount; i++) {
> +		err = do_test_ecdsa_sign_verify(tfm, &vecs[i]);
> +		if (!err)
> +			continue;
> +
> +		pr_err("ecdsa: sign/verify failed on vec %d, err=%d\n",
> +		       i + 1, err);
> +		goto exit;
> +	}
> +
> +	for (i = 0; i < tcount; i++) {
> +		err = do_test_ecdsa_sign(tfm, &vecs[i]);
> +		if (!err)
> +			continue;
> +
> +		pr_err("ecdsa: sign failed on vec %d, err=%d\n",
> +		       i + 1, err);
> +		goto exit;
> +	}
> + exit:
> +	pr_info("test_ecdsa: %s\n", err ? "FAILED" : "PASSED");

This log message should go away.

> +	return err;
> +}
> +
>  static int test_akcipher_one(struct crypto_akcipher *tfm,
>  			     struct akcipher_testvec *vecs)
>  {
> @@ -2236,9 +2667,17 @@ static int alg_test_akcipher(const struct
> alg_test_desc *desc, driver, PTR_ERR(tfm));
>  		return PTR_ERR(tfm);
>  	}
> -	if (desc->suite.akcipher.vecs)
> -		err = test_akcipher(tfm, desc->alg, desc->suite.akcipher.vecs,
> -				    desc->suite.akcipher.count);
> +
> +	if (desc->suite.akcipher.vecs) {
> +		if (strncmp(desc->alg, "ecdsa", 5) == 0)
> +			err = test_ecdsa_akcipher(tfm, desc->alg,
> +						  desc->suite.akcipher.vecs,
> +						  desc->suite.akcipher.count);
> +		else
> +			err = test_akcipher(tfm, desc->alg,
> +					    desc->suite.akcipher.vecs,
> +					    desc->suite.akcipher.count);
> +	}
> 
>  	crypto_free_akcipher(tfm);
>  	return err;
> @@ -2982,6 +3421,13 @@ static int alg_test_null(const struct alg_test_desc
> *desc, .kpp = __VECS(ecdh_tv_template)
>  		}
>  	}, {
> +		.alg = "ecdsa",
> +		.test = alg_test_akcipher,
> +		.fips_allowed = 1,
> +		.suite = {
> +			.akcipher = __VECS(ecdsa_tv_template)
> +		}
> +	}, {



Ciao
Stephan

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 0/6] Add support for ECDSA algorithm
  2017-01-20 11:35 [PATCH 0/6] Add support for ECDSA algorithm Nitin Kumbhar
                   ` (5 preceding siblings ...)
  2017-01-20 11:36 ` [PATCH 6/6] crypto: tcrypt: add ECDSA test modes Nitin Kumbhar
@ 2017-01-23 14:24 ` Herbert Xu
  2017-01-26  6:00   ` Nitin Kumbhar
  6 siblings, 1 reply; 20+ messages in thread
From: Herbert Xu @ 2017-01-23 14:24 UTC (permalink / raw)
  To: Nitin Kumbhar; +Cc: davem, linux-crypto

On Fri, Jan 20, 2017 at 05:05:55PM +0530, Nitin Kumbhar wrote:
> Hello,
> 
> This patch series adds support for Elliptic Curve Digital Signature
> Algorithm (ECDSA). To reuse existing ECC functionality, which is
> added as part of ECDH, it separates out ECC and ECDH so that
> only ECC functionality is available for ECDSA even when ECDH is in
> a disabled state.
> 
> Patch #1 restructures ECC and ECDH code such that ECC is not
> dependent on ECDH config.
> 
> Patches #2 & #3 add vli and ecc functions which are required
> for other Elliptic curve algorithms like ECDSA and ECIES.
> 
> Patch #4 adds support for ECDSA. This has been validated for P192
> and P256 elliptic curves.
> 
> Patches #5 and #6 add ECDSA tests to validate ECDSA functionality
> and measure ECDSA performance.

Who is going to use this in the kernel?

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 4/6] crypto: ecdsa: add ECDSA SW implementation
  2017-01-20 13:06   ` Stephan Müller
@ 2017-01-26  5:52     ` Nitin Kumbhar
  0 siblings, 0 replies; 20+ messages in thread
From: Nitin Kumbhar @ 2017-01-26  5:52 UTC (permalink / raw)
  To: Stephan Müller; +Cc: herbert, davem, linux-crypto

Hello Stephan,

On 1/20/2017 6:36 PM, Stephan Müller wrote:
> Am Freitag, 20. Januar 2017, 17:05:59 CET schrieb Nitin Kumbhar:
>
> Hi Nitin,
>
>> This adds support for ECDSA algorithm. This implementation supports
>> sign and verify functions for ECDSA algorithm using akcipher. As ECDSA
>> is a signing algorithm dummy functions are added for encrypt() and
>> decrypt().
>>
>> Helper routines for parsing public and private ECC keys for ECDSA are
>> added as well.
>>
>> Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
>> ---
>>  crypto/Kconfig            |    7 +
>>  crypto/Makefile           |    3 +
>>  crypto/ecdsa.c            |  331
>> +++++++++++++++++++++++++++++++++++++++++++++ crypto/ecdsa_helper.c     |
>> 116 ++++++++++++++++
>>  include/crypto/akcipher.h |    5 +-
>>  include/crypto/ecdsa.h    |   29 ++++
>>  6 files changed, 490 insertions(+), 1 deletions(-)
>>  create mode 100644 crypto/ecdsa.c
>>  create mode 100644 crypto/ecdsa_helper.c
>>  create mode 100644 include/crypto/ecdsa.h
>>
>> diff --git a/crypto/Kconfig b/crypto/Kconfig
>> index e240075d6f46..1c5c236b3bbc 100644
>> --- a/crypto/Kconfig
>> +++ b/crypto/Kconfig
>> @@ -140,6 +140,13 @@ config CRYPTO_ECDH
>>  	help
>>  	  Generic implementation of the ECDH algorithm
>>
>> +config CRYPTO_ECDSA
>> +	tristate "ECDSA algorithm"
>> +	select CRYPTO_AKCIPHER
>> +	select CRYPTO_ECC
>> +	help
>> +	  Generic implementation of the ECDSA algorithm
>> +
>>  config CRYPTO_MANAGER
>>  	tristate "Cryptographic algorithm manager"
>>  	select CRYPTO_MANAGER2
>> diff --git a/crypto/Makefile b/crypto/Makefile
>> index 827740a47a37..9c13eb2ade6a 100644
>> --- a/crypto/Makefile
>> +++ b/crypto/Makefile
>> @@ -38,6 +38,9 @@ obj-$(CONFIG_CRYPTO_ECC) += ecc.o
>>  ecdh_generic-y := ecdh.o
>>  ecdh_generic-y += ecdh_helper.o
>>  obj-$(CONFIG_CRYPTO_ECDH) += ecdh_generic.o
>> +ecdsa_generic-y := ecdsa.o
>> +ecdsa_generic-y += ecdsa_helper.o
>> +obj-$(CONFIG_CRYPTO_ECDSA) += ecdsa_generic.o
>>
>>  $(obj)/rsapubkey-asn1.o: $(obj)/rsapubkey-asn1.c $(obj)/rsapubkey-asn1.h
>>  $(obj)/rsaprivkey-asn1.o: $(obj)/rsaprivkey-asn1.c $(obj)/rsaprivkey-asn1.h
>> diff --git a/crypto/ecdsa.c b/crypto/ecdsa.c
>> new file mode 100644
>> index 000000000000..d415900af3bd
>> --- /dev/null
>> +++ b/crypto/ecdsa.c
>> @@ -0,0 +1,331 @@
>> +/*
>> + * ECDSA generic algorithm
>> + *
>> + * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License as published by the
>> Free + * Software Foundation; either version 2 of the License, or (at your
>> option) + * any later version.
>> + *
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/scatterlist.h>
>> +#include <linux/random.h>
>> +#include <crypto/internal/akcipher.h>
>> +#include <crypto/akcipher.h>
>> +#include <crypto/ecdsa.h>
>> +
>> +#include "ecc.h"
>> +
>> +struct ecdsa_ctx {
>> +	unsigned int curve_id;
>> +	unsigned int ndigits;
>> +	u64 private_key[ECC_MAX_DIGITS];
>> +	u64 public_key[2 * ECC_MAX_DIGITS];
>> +};
>> +
>> +static inline struct ecdsa_ctx *ecdsa_get_ctx(struct crypto_akcipher *tfm)
>> +{
>> +	return akcipher_tfm_ctx(tfm);
>> +}
>> +
>> +static void ecdsa_parse_msg_hash(struct akcipher_request *req, u64 *msg,
>> +				 unsigned int ndigits)
>> +{
>> +	unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
>> +	unsigned int hash_len, hash_off;
>> +	unsigned char *hash, *msg_ptr;
>> +	int i;
>> +
>> +	/*
>> +	 * If hash_len == nbytes:
>> +	 *	copy nbytes from req
>> +	 * If hash_len > nbytes:
>> +	 *	copy left most nbytes from hash ignoring LSBs
>> +	 * If hash_len < nbytes:
>> +	 *	copy hash_len from req and zero remaining bytes
>> +	 *	(nbytes - hash_len)
>> +	 */
>> +	hash_len = req->src[0].length;
>> +	hash_off = hash_len <= nbytes ? 0 : hash_len - nbytes;
>> +
>> +	msg_ptr = (unsigned char *)msg;
>> +	hash = sg_virt(&req->src[0]);
>> +
>> +	for (i = hash_off; i < hash_len; i++)
>> +		*msg_ptr++ = hash[i];
>> +	for (; i < nbytes; i++)
>> +		*msg_ptr++ = 0;
>> +}
>> +
>> +int ecdsa_sign(struct akcipher_request *req)
>> +{
>> +	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
>> +	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
>> +	unsigned int ndigits = ctx->ndigits;
>> +	unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
>> +	unsigned int curve_id = ctx->curve_id;
>> +	const struct ecc_curve *curve = ecc_get_curve(curve_id);
>> +	struct ecc_point *x1y1 = NULL;
>> +	u64 z[ndigits], d[ndigits];
>> +	u64 k[ndigits], k_inv[ndigits];
>> +	u64 r[ndigits], s[ndigits];
>> +	u64 dr[ndigits], zdr[ndigits];
>> +	u8 *r_ptr, *s_ptr;
>> +
>> +	if (req->dst_len < 2 * nbytes) {
>> +		req->dst_len = 2 * nbytes;
>> +		return -EINVAL;
>> +	}
>> +
>> +	ecdsa_parse_msg_hash(req, z, ndigits);
>> +
>> +	/* d */
>> +	vli_set(d, (const u64 *)ctx->private_key, ndigits);
>> +
>> +	/* k */
>> +#if defined(CONFIG_CRYPTO_MANAGER2)
>> +	if (req->info) {
>> +		vli_copy_from_buf(k, ndigits, req->info, nbytes);
>> +	} else
>> +#endif
>> +		get_random_bytes(k, nbytes);
>
> Please use crypto_get_default_rng /crypto_rng_get_bytes /
> crypto_put_default_rng here.

Sure. I will update that in next version of the patch.

>> +
>> +	x1y1 = ecc_alloc_point(ndigits);
>> +	if (!x1y1)
>> +		return -ENOMEM;
>> +
>> +	/* (x1, y1) = k x G */
>> +	ecc_point_mult(x1y1, &curve->g, k, NULL, curve->p, ndigits);
>> +
>> +	/* r = x1 mod n */
>> +	vli_mod(r, x1y1->x, curve->n, ndigits);
>> +
>> +	/* k^-1 */
>> +	vli_mod_inv(k_inv, k, curve->n, ndigits);
>> +
>> +	/* d . r mod n */
>> +	vli_mod_mult(dr, d, r, curve->n, ndigits);
>> +
>> +	/* z + dr mod n */
>> +	vli_mod_add(zdr, z, dr, curve->n, ndigits);
>> +
>> +	/* k^-1 . ( z + dr) mod n */
>> +	vli_mod_mult(s, k_inv, zdr, curve->n, ndigits);
>> +
>> +	/* write signature (r,s) in dst */
>> +	r_ptr = sg_virt(req->dst);
>> +	s_ptr = (u8 *)sg_virt(req->dst) + nbytes;
>> +
>> +	vli_copy_to_buf(r_ptr, nbytes, r, ndigits);
>> +	vli_copy_to_buf(s_ptr, nbytes, s, ndigits);
>> +
>> +	req->dst_len = 2 * nbytes;
>> +
>> +	ecc_free_point(x1y1);
>> +	return 0;
>> +}
>> +
>> +int ecdsa_verify(struct akcipher_request *req)
>> +{
>> +	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
>> +	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
>> +	unsigned int ndigits = ctx->ndigits;
>> +	unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
>> +	unsigned int curve_id = ctx->curve_id;
>> +	const struct ecc_curve *curve = ecc_get_curve(curve_id);
>> +	struct ecc_point *x1y1 = NULL, *x2y2 = NULL, *Q = NULL;
>> +	u64 r[ndigits], s[ndigits], v[ndigits];
>> +	u64 z[ndigits], w[ndigits];
>> +	u64 u1[ndigits], u2[ndigits];
>> +	u64 x1[ndigits], x2[ndigits];
>> +	u64 y1[ndigits], y2[ndigits];
>> +	u64 *ctx_qx, *ctx_qy;
>> +	int ret;
>> +
>> +	x1y1 = ecc_alloc_point(ndigits);
>> +	x2y2 = ecc_alloc_point(ndigits);
>> +	Q = ecc_alloc_point(ndigits);
>> +	if (!x1y1 || !x2y2 || !Q) {
>> +		ret = -ENOMEM;
>> +		goto exit;
>> +	}
>> +
>> +	ecdsa_parse_msg_hash(req, z, ndigits);
>> +
>> +	/* Signature r,s */
>> +	vli_copy_from_buf(r, ndigits, sg_virt(&req->src[1]), nbytes);
>> +	vli_copy_from_buf(s, ndigits, sg_virt(&req->src[2]), nbytes);
>> +
>> +	/* w = s^-1 mod n */
>> +	vli_mod_inv(w, s, curve->n, ndigits);
>> +
>> +	/* u1 = zw mod n */
>> +	vli_mod_mult(u1, z, w, curve->n, ndigits);
>> +
>> +	/* u2 = rw mod n */
>> +	vli_mod_mult(u2, r, w, curve->n, ndigits);
>> +
>> +	/* u1 . G */
>> +	ecc_point_mult(x1y1, &curve->g, u1, NULL, curve->p, ndigits);
>> +
>> +	/* Q=(Qx,Qy) */
>> +	ctx_qx = ctx->public_key;
>> +	ctx_qy = ctx_qx + ECC_MAX_DIGITS;
>> +	vli_set(Q->x, ctx_qx, ndigits);
>> +	vli_set(Q->y, ctx_qy, ndigits);
>> +
>> +	/* u2 x Q */
>> +	ecc_point_mult(x2y2, Q, u2, NULL, curve->p, ndigits);
>> +
>> +	vli_set(x1, x1y1->x, ndigits);
>> +	vli_set(y1, x1y1->y, ndigits);
>> +	vli_set(x2, x2y2->x, ndigits);
>> +	vli_set(y2, x2y2->y, ndigits);
>> +
>> +	/* x1y1 + x2y2 => P + Q; P + Q in x2 y2 */
>> +	ecc_point_add(x1, y1, x2, y2, curve->p, ndigits);
>> +
>> +	/* v = x mod n */
>> +	vli_mod(v, x2, curve->n, ndigits);
>> +
>> +	/* validate signature */
>> +	ret = vli_cmp(v, r, ndigits) == 0 ? 0 : -EBADMSG;
>> + exit:
>> +	ecc_free_point(x1y1);
>> +	ecc_free_point(x2y2);
>> +	ecc_free_point(Q);
>> +	return ret;
>> +}
>> +
>> +int ecdsa_dummy_enc(struct akcipher_request *req)
>> +{
>> +	return -EINVAL;
>> +}
>> +
>> +int ecdsa_dummy_dec(struct akcipher_request *req)
>> +{
>> +	return -EINVAL;
>> +}
>> +
>> +int ecdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key,
>> +		      unsigned int keylen)
>> +{
>> +	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
>> +	struct ecdsa params;
>> +	unsigned int ndigits;
>> +	unsigned int nbytes;
>> +	u8 *params_qx, *params_qy;
>> +	u64 *ctx_qx, *ctx_qy;
>> +	int ret = 0;
>> +
>> +	if (crypto_ecdsa_parse_pub_key(key, keylen, &params))
>> +		return -EINVAL;
>> +
>> +	ndigits = ecdsa_supported_curve(params.curve_id);
>> +
>> +	ctx->curve_id = params.curve_id;
>> +	ctx->ndigits = ndigits;
>> +	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
>> +
>> +	params_qx = params.key;
>> +	params_qy = params_qx + ECC_MAX_DIGIT_BYTES;
>> +
>> +	ctx_qx = ctx->public_key;
>> +	ctx_qy = ctx_qx + ECC_MAX_DIGITS;
>> +
>> +	vli_copy_from_buf(ctx_qx, ndigits, params_qx, nbytes);
>> +	vli_copy_from_buf(ctx_qy, ndigits, params_qy, nbytes);
>> +
>> +	memset(&params, 0, sizeof(params));
>> +	return ret;
>
> Shouldn't there be a check that the point is on the curve? As I think the same
> issue is applicable to ECDH, I guess a common service function should be used
> that we can also invoke from ECDH.

Yes. I'll add checks for public key.

>> +}
>> +
>> +int ecdsa_set_priv_key(struct crypto_akcipher *tfm, const void *key,
>> +		       unsigned int keylen)
>> +{
>> +	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
>> +	struct ecdsa params;
>> +	unsigned int ndigits;
>> +	unsigned int nbytes;
>> +
>> +	if (crypto_ecdsa_parse_priv_key(key, keylen, &params))
>> +		return -EINVAL;
>> +
>> +	ndigits = ecdsa_supported_curve(params.curve_id);
>> +
>> +	ctx->curve_id = params.curve_id;
>> +	ctx->ndigits = ndigits;
>> +	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
>> +
>> +	if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits,
>> +			     (const u8 *)params.key, params.key_size) < 0)
>> +		return -EINVAL;
>> +
>> +	vli_copy_from_buf(ctx->private_key, ndigits, params.key, nbytes);
>> +
>> +	memset(&params, 0, sizeof(params));
>> +	return 0;
>> +}
>> +
>> +int ecdsa_max_size(struct crypto_akcipher *tfm)
>> +{
>> +	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
>> +	int nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
>> +
>> +	/* For r,s */
>> +	return 2 * nbytes;
>> +}
>> +
>> +int ecdsa_init_tfm(struct crypto_akcipher *tfm)
>> +{
>> +	return 0;
>> +}
>> +
>> +void ecdsa_exit_tfm(struct crypto_akcipher *tfm)
>> +{
>> +}
>> +
>> +static struct akcipher_alg ecdsa_alg = {
>> +	.sign		= ecdsa_sign,
>> +	.verify		= ecdsa_verify,
>> +	.encrypt	= ecdsa_dummy_enc,
>> +	.decrypt	= ecdsa_dummy_dec,
>> +	.set_priv_key	= ecdsa_set_priv_key,
>> +	.set_pub_key	= ecdsa_set_pub_key,
>> +	.max_size	= ecdsa_max_size,
>> +	.init		= ecdsa_init_tfm,
>> +	.exit		= ecdsa_exit_tfm,
>> +	.base = {
>> +		.cra_name	= "ecdsa",
>> +		.cra_driver_name = "ecdsa-generic",
>> +		.cra_priority	= 100,
>> +		.cra_module	= THIS_MODULE,
>> +		.cra_ctxsize	= sizeof(struct ecdsa_ctx),
>> +	},
>> +};
>> +
>> +static int ecdsa_init(void)
>> +{
>> +	int ret;
>> +
>> +	ret = crypto_register_akcipher(&ecdsa_alg);
>> +	if (ret)
>> +		pr_err("ecdsa alg register failed. err:%d\n", ret);
>> +	return ret;
>> +}
>> +
>> +static void ecdsa_exit(void)
>> +{
>> +	crypto_unregister_akcipher(&ecdsa_alg);
>> +}
>> +
>> +module_init(ecdsa_init);
>> +module_exit(ecdsa_exit);
>> +
>> +MODULE_ALIAS_CRYPTO("ecdsa");
>> +MODULE_LICENSE("GPL");
>> +MODULE_DESCRIPTION("ECDSA Generic Algorithm");
>> +MODULE_AUTHOR("NVIDIA Corporation");
>> diff --git a/crypto/ecdsa_helper.c b/crypto/ecdsa_helper.c
>> new file mode 100644
>> index 000000000000..d31eb54431a9
>> --- /dev/null
>> +++ b/crypto/ecdsa_helper.c
>> @@ -0,0 +1,116 @@
>> +/*
>> + * ECDSA helper routines
>> + *
>> + * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License as published by the
>> Free + * Software Foundation; either version 2 of the License, or (at your
>> option) + * any later version.
>> + *
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/export.h>
>> +#include <linux/err.h>
>> +#include <linux/string.h>
>> +#include <crypto/ecdsa.h>
>> +
>> +#include "ecc.h"
>> +
>> +#define ECDSA_KEY_MIN_SIZE	(1 + 1 + 24) /* ver + cid + n (P-192) */
>> +
>> +unsigned int ecdsa_supported_curve(unsigned int curve_id)
>> +{
>> +	switch (curve_id) {
>> +	case ECC_CURVE_NIST_P192: return 3;
>> +	case ECC_CURVE_NIST_P256: return 4;
>> +	default: return 0;
>> +	}
>> +}
>
> Wouldn't it be better to have a common function with ECDH as this has almost
> the same code in ecdh_supported_curve?

A separate function is added as ECDH and ECDSA may not support all 
elliptic curves. This allows to handle the differences.

>> +
>> +static inline u8 *ecdsa_pack_data(void *dst, const void *src, size_t sz)
>> +{
>> +	memcpy(dst, src, sz);
>> +	return dst + sz;
>> +}
>> +
>> +static inline const u8 *ecdsa_unpack_data(void *dst, const void *src,
>> size_t sz) +{
>> +	memcpy(dst, src, sz);
>> +	return src + sz;
>> +}
>> +
>> +int crypto_ecdsa_parse_pub_key(const char *buf, unsigned int len,
>> +			       struct ecdsa *params)
>> +{
>> +	unsigned char version;
>> +	unsigned int ndigits;
>> +	unsigned int nbytes;
>> +	const u8 *ptr = buf;
>> +	u8 *qx, *qy;
>> +
>> +	if (unlikely(!buf) || len < ECDSA_KEY_MIN_SIZE)
>> +		return -EINVAL;
>> +
>> +	ptr = ecdsa_unpack_data(&version, ptr, sizeof(version));
>> +	if (version != 1)
>> +		return -EINVAL;
>> +
>> +	ptr = ecdsa_unpack_data(&params->curve_id, ptr,
>> +				sizeof(params->curve_id));
>> +
>> +	ndigits = ecdsa_supported_curve(params->curve_id);
>> +	if (!ndigits)
>> +		return -EINVAL;
>> +
>> +	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
>> +
>> +	/* skip private key */
>> +	ptr = ecdsa_unpack_data(&params->key, ptr, nbytes);
>> +
>> +	/* copy public key */
>> +	qx = params->key;
>> +	qy = qx + ECC_MAX_DIGIT_BYTES;
>> +
>> +	ptr = ecdsa_unpack_data(qx, ptr, nbytes);
>> +	ptr = ecdsa_unpack_data(qy, ptr, nbytes);
>> +
>> +	params->key_size = 2 * nbytes;
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(crypto_ecdsa_parse_pub_key);
>> +
>> +int crypto_ecdsa_parse_priv_key(const char *buf, unsigned int len,
>> +				struct ecdsa *params)
>> +{
>> +	unsigned char version;
>> +	unsigned int ndigits;
>> +	unsigned int nbytes;
>> +	const u8 *ptr = buf;
>> +
>> +	if (unlikely(!buf) || len < ECDSA_KEY_MIN_SIZE)
>> +		return -EINVAL;
>> +
>> +	ptr = ecdsa_unpack_data(&version, ptr, sizeof(version));
>> +	if (version != 1)
>> +		return -EINVAL;
>> +
>> +	ptr = ecdsa_unpack_data(&params->curve_id, ptr,
>> +				sizeof(params->curve_id));
>> +
>> +	ndigits = ecdsa_supported_curve(params->curve_id);
>> +	if (!ndigits)
>> +		return -EINVAL;
>> +
>> +	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
>> +
>> +	params->key_size = nbytes;
>> +
>> +	/* copy private key */
>> +	ptr = ecdsa_unpack_data(&params->key, ptr, nbytes);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(crypto_ecdsa_parse_priv_key);
>> diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
>> index c37cc59e9bf2..6b34e9043a6f 100644
>> --- a/include/crypto/akcipher.h
>> +++ b/include/crypto/akcipher.h
>> @@ -3,6 +3,7 @@
>>   *
>>   * Copyright (c) 2015, Intel Corporation
>>   * Authors: Tadeusz Struk <tadeusz.struk@intel.com>
>> + * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
>>   *
>>   * This program is free software; you can redistribute it and/or modify it
>>   * under the terms of the GNU General Public License as published by the
>> Free @@ -27,6 +28,7 @@
>>   *		result.
>>   *		In case of error where the dst sgl size was insufficient,
>>   *		it will be updated to the size required for the operation.
>> + * @info:	Any request specific data needed to process the request.
>>   * @__ctx:	Start of private context data
>>   */
>>  struct akcipher_request {
>> @@ -35,6 +37,7 @@ struct akcipher_request {
>>  	struct scatterlist *dst;
>>  	unsigned int src_len;
>>  	unsigned int dst_len;
>> +	void *info;
>>  	void *__ctx[] CRYPTO_MINALIGN_ATTR;
>>  };
>>
>> @@ -193,7 +196,7 @@ static inline void crypto_free_akcipher(struct
>> crypto_akcipher *tfm) {
>>  	struct akcipher_request *req;
>>
>> -	req = kmalloc(sizeof(*req) + crypto_akcipher_reqsize(tfm), gfp);
>> +	req = kzalloc(sizeof(*req) + crypto_akcipher_reqsize(tfm), gfp);
>>  	if (likely(req))
>>  		akcipher_request_set_tfm(req, tfm);
>>
>> diff --git a/include/crypto/ecdsa.h b/include/crypto/ecdsa.h
>> new file mode 100644
>> index 000000000000..c71d21e654b9
>> --- /dev/null
>> +++ b/include/crypto/ecdsa.h
>> @@ -0,0 +1,29 @@
>> +/*
>> + * ECC parameters for ECDSA
>> + *
>> + * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License as published by the
>> Free + * Software Foundation; either version 2 of the License, or (at your
>> option) + * any later version.
>> + *
>> + */
>> +
>> +#ifndef _CRYPTO_ECDSA_
>> +#define _CRYPTO_ECDSA_
>> +
>> +#include <crypto/ecc.h>
>> +
>> +struct ecdsa {
>> +	unsigned char curve_id;
>> +	unsigned char key[2 * ECC_MAX_DIGIT_BYTES];
>> +	unsigned short key_size;
>> +};
>> +
>> +unsigned int ecdsa_supported_curve(unsigned int curve_id);
>> +int crypto_ecdsa_parse_pub_key(const char *buf, unsigned int len,
>> +			       struct ecdsa *params);
>> +int crypto_ecdsa_parse_priv_key(const char *buf, unsigned int len,
>> +				struct ecdsa *params);
>> +#endif /* _CRYPTO_ECDSA_ */
>
> I would like to see soem documentation here similar to the ecdh.h. Especially,
> can you please add documentation which type of point representation you expect
> as input (e.g. affine representation)?

I'll include documentation on the lines of ecdh.h for these functions in 
next patch series.

> Ciao
> Stephan
>

Regards,
- Nitin
-----------------------------------------------------------------------------------
This email message is for the sole use of the intended recipient(s) and may contain
confidential information.  Any unauthorized review, use, disclosure or distribution
is prohibited.  If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.
-----------------------------------------------------------------------------------

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 5/6] crypto: testmgr: add ECDSA tests
  2017-01-20 13:19   ` Stephan Müller
@ 2017-01-26  5:58     ` Nitin Kumbhar
  0 siblings, 0 replies; 20+ messages in thread
From: Nitin Kumbhar @ 2017-01-26  5:58 UTC (permalink / raw)
  To: Stephan Müller; +Cc: herbert, davem, linux-crypto

Hello Stephan,

On 1/20/2017 6:49 PM, Stephan Müller wrote:
> Am Freitag, 20. Januar 2017, 17:06:00 CET schrieb Nitin Kumbhar:
>
> Hi Nitin,
>
>> Update crypto test manager to include NIST ECDSA
>> test vectors and various ECDSA tests. These include
>> tests for ECDSA signing, ECDSA sign-verification,
>> ECDSA signing and verifying generated signatures and
>> invalidation of incorrect signatures.
>>
>> Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
>> ---
>>  crypto/testmgr.c |  452
>> +++++++++++++++++++++++++++++++++++++++++++++++++++++- crypto/testmgr.h |
>> 140 +++++++++++++++++
>>  2 files changed, 589 insertions(+), 3 deletions(-)
>>
>> diff --git a/crypto/testmgr.c b/crypto/testmgr.c
>> index 98eb09782db8..a1db28cbc32d 100644
>> --- a/crypto/testmgr.c
>> +++ b/crypto/testmgr.c
>> @@ -5,6 +5,7 @@
>>   * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org>
>>   * Copyright (c) 2007 Nokia Siemens Networks
>>   * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
>> + * Copyright (c) 2017 NVIDIA Corporation
>>   *
>>   * Updated RFC4106 AES-GCM testing.
>>   *    Authors: Aidan O'Mahony (aidan.o.mahony@intel.com)
>> @@ -2085,6 +2086,436 @@ static int alg_test_kpp(const struct alg_test_desc
>> *desc, const char *driver, return err;
>>  }
>>
>> +static int do_test_ecdsa_verify(struct crypto_akcipher *tfm,
>> +			      struct akcipher_testvec *vec)
>> +{
>> +	struct akcipher_request *req = NULL;
>> +	u8 *r_str = NULL, *s_str = NULL;
>> +	u8 *m_str = NULL;
>> +	struct scatterlist src_tab[3], dst;
>> +	struct tcrypt_result result;
>> +	unsigned int outbuf_maxlen;
>> +	u8 *outbuf = NULL;
>> +	unsigned int nbytes;
>> +	int err;
>> +
>> +	/* Alloc akcipher request */
>> +	req = akcipher_request_alloc(tfm, GFP_KERNEL);
>> +	if (!req)
>> +		return -ENOMEM;
>> +
>> +	/* Set private key */
>> +	err = crypto_akcipher_set_pub_key(tfm, vec->key, vec->key_len);
>> +	if (err)
>> +		goto error;
>> +
>> +	/*
>> +	 * vec->c always contains k, R and S in that order. All are
>> +	 * of same size and are equal to n i.e. the order of
>> +	 * an elliptic curve.
>> +	 */
>> +	nbytes = vec->c_size / 3;
>> +
>> +	r_str = kzalloc(nbytes, GFP_KERNEL);
>> +	s_str = kzalloc(nbytes, GFP_KERNEL);
>> +	m_str = kzalloc(vec->m_size, GFP_KERNEL);
>> +	if (!r_str || !s_str || !m_str) {
>> +		err = -ENOMEM;
>> +		goto error;
>> +	}
>> +	memcpy(r_str, (u8 *)vec->c + nbytes, nbytes);
>> +	memcpy(s_str, (u8 *)vec->c + 2 * nbytes, nbytes);
>> +	memcpy(m_str, vec->m, vec->m_size);
>> +
>> +	outbuf_maxlen = crypto_akcipher_maxsize(tfm);
>> +	if (outbuf_maxlen < 0) {
>> +		err = outbuf_maxlen;
>> +		goto error;
>> +	}
>> +	outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL);
>> +	if (!outbuf) {
>> +		err = -ENOMEM;
>> +		goto error;
>> +	}
>> +
>> +	/* Set src and dst buffers */
>> +	sg_init_table(src_tab, 3);
>> +	sg_set_buf(&src_tab[0], m_str, vec->m_size);
>> +	sg_set_buf(&src_tab[1], r_str, nbytes);
>> +	sg_set_buf(&src_tab[2], s_str, nbytes);
>> +	sg_init_one(&dst, outbuf, outbuf_maxlen);
>> +
>> +	akcipher_request_set_crypt(req, src_tab, &dst,
>> +				   vec->m_size + 2 * nbytes, outbuf_maxlen);
>> +
>> +	/* Set up result callback */
>> +	init_completion(&result.completion);
>> +	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
>> +				      tcrypt_complete, &result);
>> +
>> +	/* Run ecdsa verify operation on sig (r,s) */
>> +	err = wait_async_op(&result, crypto_akcipher_verify(req));
>> +	if (err) {
>> +		pr_err("alg: ecdsa: verify(rs) test failed. err %d\n", err);
>> +		goto error;
>> +	}
>> +error:
>> +	akcipher_request_free(req);
>> +	kfree(r_str);
>> +	kfree(s_str);
>> +	kfree(m_str);
>> +	kfree(outbuf);
>> +	return err;
>> +}
>> +
>> +static int do_test_ecdsa_invalid_verify(struct crypto_akcipher *tfm,
>> +					struct akcipher_testvec *vec)
>> +{
>> +	struct akcipher_request *req = NULL;
>> +	u8 *r_str = NULL, *s_str = NULL;
>> +	u8 *m_str = NULL;
>> +	struct scatterlist src_tab[3], dst;
>> +	struct tcrypt_result result;
>> +	unsigned int outbuf_maxlen;
>> +	u8 *outbuf = NULL;
>> +	unsigned int nbytes;
>> +	int err;
>> +
>> +	/* Alloc akcipher request */
>> +	req = akcipher_request_alloc(tfm, GFP_KERNEL);
>> +	if (!req)
>> +		return -ENOMEM;
>> +
>> +	/* Set private key */
>> +	err = crypto_akcipher_set_pub_key(tfm, vec->key, vec->key_len);
>> +	if (err)
>> +		goto error;
>> +
>> +	/*
>> +	 * vec->c always contains k, R and S in that order. All are
>> +	 * of same size and are equal to n i.e. the order of
>> +	 * an elliptic curve.
>> +	 */
>> +	nbytes = vec->c_size / 3;
>> +
>> +	r_str = kzalloc(nbytes, GFP_KERNEL);
>> +	s_str = kzalloc(nbytes, GFP_KERNEL);
>> +	m_str = kzalloc(vec->m_size, GFP_KERNEL);
>> +	if (!r_str || !s_str || !m_str) {
>> +		err = -ENOMEM;
>> +		goto error;
>> +	}
>> +	memcpy(r_str, (u8 *)vec->c + 1 * nbytes, nbytes);
>> +	memcpy(s_str, (u8 *)vec->c + 2 * nbytes, nbytes);
>> +	memcpy(m_str, vec->m, vec->m_size);
>> +
>> +	outbuf_maxlen = crypto_akcipher_maxsize(tfm);
>> +	if (outbuf_maxlen < 0) {
>> +		err = outbuf_maxlen;
>> +		goto error;
>> +	}
>> +	outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL);
>> +	if (!outbuf) {
>> +		err = -ENOMEM;
>> +		goto error;
>> +	}
>> +
>> +	/* Set src and dst buffers */
>> +	sg_init_table(src_tab, 3);
>> +	/* Intentionally set m_size to 8 to have invalid hash */
>> +	sg_set_buf(&src_tab[0], m_str, 8);
>> +	sg_set_buf(&src_tab[1], r_str, nbytes);
>> +	sg_set_buf(&src_tab[2], s_str, nbytes);
>> +	sg_init_one(&dst, outbuf, outbuf_maxlen);
>> +
>> +	akcipher_request_set_crypt(req, src_tab, &dst,
>> +				   vec->m_size + 2 * nbytes, outbuf_maxlen);
>> +
>> +	/* Set up result callback */
>> +	init_completion(&result.completion);
>> +	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
>> +				      tcrypt_complete, &result);
>> +
>> +	/* Run ecdsa verify operation on sig (r,s) */
>> +	err = wait_async_op(&result, crypto_akcipher_verify(req));
>> +	if (err != -EBADMSG) {
>> +		pr_err("alg: ecdsa: invalid verify test failed. err %d\n", err);
>> +		goto error;
>> +	}
>> +	err = 0;
>> +error:
>> +	akcipher_request_free(req);
>> +	kfree(r_str);
>> +	kfree(s_str);
>> +	kfree(m_str);
>> +	kfree(outbuf);
>> +	return err;
>> +}
>
> There seems to be a lot of code duplication between
> do_test_ecdsa_invalid_verify and do_test_ecdsa_verify -- can this be
> eliminated?

I will reorg the code to reuse test subroutines.

>> +
>> +static int do_test_ecdsa_sign_verify(struct crypto_akcipher *tfm,
>> +				     struct akcipher_testvec *vec)
>> +{
>> +	struct akcipher_request *req = NULL;
>> +	u8 *r_str = NULL, *s_str = NULL;
>> +	u8 *m_str = NULL;
>> +	struct scatterlist src_tab[3];
>> +	struct scatterlist src, dst;
>> +	struct tcrypt_result result;
>> +	unsigned int outbuf_maxlen;
>> +	void *outbuf = NULL;
>> +	unsigned int nbytes;
>> +	int err;
>> +
>> +	/* Alloc akcipher request */
>> +	req = akcipher_request_alloc(tfm, GFP_KERNEL);
>> +	if (!req)
>> +		return -ENOMEM;
>> +
>> +	/* Set private key */
>> +	err = crypto_akcipher_set_priv_key(tfm, vec->key, vec->key_len);
>> +	if (err)
>> +		goto error;
>> +
>> +	/* Set private key */
>> +	err = crypto_akcipher_set_pub_key(tfm, vec->key, vec->key_len);
>> +	if (err)
>> +		goto error;
>> +
>> +	/*
>> +	 * vec->c always contains k, R and S in that order. All are
>> +	 * of same size and are equal to n i.e. the order of
>> +	 * an elliptic curve.
>> +	 */
>> +	nbytes = vec->c_size / 3;
>> +
>> +	m_str = kzalloc(vec->m_size, GFP_KERNEL);
>> +	if (!m_str) {
>> +		err = -ENOMEM;
>> +		goto error;
>> +	}
>> +	memcpy(m_str, vec->m, vec->m_size);
>> +
>> +	outbuf_maxlen = crypto_akcipher_maxsize(tfm);
>> +	if (outbuf_maxlen < 0) {
>> +		err = outbuf_maxlen;
>> +		goto error;
>> +	}
>> +	outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL);
>> +	if (!outbuf) {
>> +		err = -ENOMEM;
>> +		goto error;
>> +	}
>> +
>> +	sg_init_one(&src, m_str, vec->m_size);
>> +	sg_init_one(&dst, outbuf, outbuf_maxlen);
>> +
>> +	akcipher_request_set_crypt(req, &src, &dst,
>> +				   vec->m_size, outbuf_maxlen);
>> +
>> +	/* Set up result callback */
>> +	init_completion(&result.completion);
>> +	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
>> +				      tcrypt_complete, &result);
>> +
>> +	/* Run ecdsa sign operation on message digest */
>> +	err = wait_async_op(&result, crypto_akcipher_sign(req));
>> +	if (err) {
>> +		pr_err("alg: ecdsa: sign test failed. err %d\n", err);
>> +		goto error;
>> +	}
>> +
>> +	/* verify that signature (r,s) is valid */
>> +	if (req->dst_len != 2 * nbytes) {
>> +		pr_err("alg: ecdsa: sign test failed. Invalid sig len\n");
>> +		err = -EINVAL;
>> +		goto error;
>> +	}
>> +
>> +	/* output contains r and s */
>> +	r_str = outbuf;
>> +	s_str = (u8 *)outbuf + nbytes;
>> +
>> +	/* Set src and dst buffers */
>> +	sg_init_table(src_tab, 3);
>> +	sg_set_buf(&src_tab[0], m_str, vec->m_size);
>> +	sg_set_buf(&src_tab[1], r_str, nbytes);
>> +	sg_set_buf(&src_tab[2], s_str, nbytes);
>> +	sg_init_one(&dst, outbuf, outbuf_maxlen);
>> +
>> +	akcipher_request_set_crypt(req, src_tab, &dst,
>> +				   vec->m_size + 2 * nbytes, outbuf_maxlen);
>> +
>> +	/* Set up result callback */
>> +	init_completion(&result.completion);
>> +	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
>> +				      tcrypt_complete, &result);
>> +
>> +	/* Run ecdsa verify operation on sig (r,s) */
>> +	err = wait_async_op(&result, crypto_akcipher_verify(req));
>> +	if (err) {
>> +		pr_err("alg: ecdsa: verify test failed. err %d\n", err);
>> +		goto error;
>> +	}
>> +error:
>> +	akcipher_request_free(req);
>> +	kfree(m_str);
>> +	kfree(outbuf);
>> +	return err;
>> +}
>> +
>> +static int do_test_ecdsa_sign(struct crypto_akcipher *tfm,
>> +			      struct akcipher_testvec *vec)
>> +{
>> +	struct akcipher_request *req = NULL;
>> +	u8 *r_str = NULL, *s_str = NULL;
>> +	u8 *k_str = NULL, *m_str = NULL;
>> +	struct scatterlist src, dst;
>> +	struct tcrypt_result result;
>> +	unsigned int outbuf_maxlen;
>> +	void *outbuf = NULL;
>> +	unsigned int nbytes;
>> +	int err;
>> +
>> +	/* Alloc akcipher request */
>> +	req = akcipher_request_alloc(tfm, GFP_KERNEL);
>> +	if (!req)
>> +		return -ENOMEM;
>> +
>> +	/* Set private key */
>> +	err = crypto_akcipher_set_priv_key(tfm, vec->key, vec->key_len);
>> +	if (err)
>> +		goto error;
>> +
>> +	/*
>> +	 * vec->c always contains k, R and S in that order. All are
>> +	 * of same size and are equal to n i.e. the order of
>> +	 * an elliptic curve.
>> +	 */
>> +	nbytes = vec->c_size / 3;
>> +
>> +	k_str = kzalloc(nbytes, GFP_KERNEL);
>> +	r_str = kzalloc(nbytes, GFP_KERNEL);
>> +	s_str = kzalloc(nbytes, GFP_KERNEL);
>> +	m_str = kzalloc(vec->m_size, GFP_KERNEL);
>> +	if (!k_str || !r_str || !s_str || !m_str) {
>> +		err = -ENOMEM;
>> +		goto error;
>> +	}
>> +	memcpy(k_str, (u8 *)vec->c + 0 * nbytes, nbytes);
>> +	memcpy(r_str, (u8 *)vec->c + 1 * nbytes, nbytes);
>> +	memcpy(s_str, (u8 *)vec->c + 2 * nbytes, nbytes);
>> +	memcpy(m_str, vec->m, vec->m_size);
>> +
>> +	outbuf_maxlen = crypto_akcipher_maxsize(tfm);
>> +	if (outbuf_maxlen < 0) {
>> +		err = outbuf_maxlen;
>> +		goto error;
>> +	}
>> +	outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL);
>> +	if (!outbuf) {
>> +		err = -ENOMEM;
>> +		goto error;
>> +	}
>> +
>> +	/* Set src and dst buffers */
>> +	sg_init_one(&src, m_str, vec->m_size);
>> +	sg_init_one(&dst, outbuf, outbuf_maxlen);
>> +
>> +	akcipher_request_set_crypt(req, &src, &dst,
>> +				   vec->m_size, outbuf_maxlen);
>> +
>> +	/* Set up result callback */
>> +	init_completion(&result.completion);
>> +	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
>> +				      tcrypt_complete, &result);
>> +
>> +	/* Set K in request for signing */
>> +	req->info = k_str;
>> +
>> +	/* Run ecdsa sign operation on message digest */
>> +	err = wait_async_op(&result, crypto_akcipher_sign(req));
>> +	if (err) {
>> +		pr_err("alg: ecdsa: sign(k) test failed. err %d\n", err);
>> +		goto error;
>> +	}
>> +
>> +	/* verify that signature (r,s) is valid */
>> +	if (req->dst_len != 2 * nbytes) {
>> +		pr_err("alg: ecdsa: sign(k) test failed. Invalid sig len\n");
>> +		err = -EINVAL;
>> +		goto error;
>> +	}
>> +
>> +	if (memcmp(r_str, sg_virt(req->dst), nbytes)) {
>> +		pr_err("alg: ecdsa: sign(k) test failed. Invalid sig(r)\n");
>> +		err = -EINVAL;
>> +		goto error;
>> +	}
>> +
>> +	if (memcmp(s_str, (u8 *)sg_virt(req->dst) + nbytes, nbytes)) {
>> +		pr_err("alg: ecdsa: sign(k) test failed. Invalid sig(s)\n");
>> +		err = -EINVAL;
>> +		goto error;
>> +	}
>> +error:
>> +	akcipher_request_free(req);
>> +	kfree(k_str);
>> +	kfree(r_str);
>> +	kfree(s_str);
>> +	kfree(m_str);
>> +	kfree(outbuf);
>> +	return err;
>> +}
>
> Same here -- there seem to be a lot of code duplication -- can this be
> reduced?

Yes. I will update.

>> +
>> +static int test_ecdsa_akcipher(struct crypto_akcipher *tfm, const char
>> *alg, +		       struct akcipher_testvec *vecs, unsigned int tcount)
>> +{
>> +	int i, err = 0;
>> +
>> +	for (i = 0; i < tcount; i++) {
>> +		err = do_test_ecdsa_verify(tfm, &vecs[i]);
>> +		if (!err)
>> +			continue;
>> +
>> +		pr_err("ecdsa: verify failed on vec %d, err=%d\n",
>> +		       i + 1, err);
>
> All of these pr_err logs here and below should be removed as these errors seem
> to be already logged.

Sure. I will remove these error logs.

>
>> +		goto exit;
>> +	}
>> +
>> +	for (i = 0; i < tcount; i++) {
>> +		err = do_test_ecdsa_invalid_verify(tfm, &vecs[i]);
>> +		if (!err)
>> +			continue;
>> +
>> +		pr_err("ecdsa: verify(invl) failed on vec %d, err=%d\n",
>> +		       i + 1, err);
>> +		goto exit;
>> +	}
>> +
>> +	for (i = 0; i < tcount; i++) {
>> +		err = do_test_ecdsa_sign_verify(tfm, &vecs[i]);
>> +		if (!err)
>> +			continue;
>> +
>> +		pr_err("ecdsa: sign/verify failed on vec %d, err=%d\n",
>> +		       i + 1, err);
>> +		goto exit;
>> +	}
>> +
>> +	for (i = 0; i < tcount; i++) {
>> +		err = do_test_ecdsa_sign(tfm, &vecs[i]);
>> +		if (!err)
>> +			continue;
>> +
>> +		pr_err("ecdsa: sign failed on vec %d, err=%d\n",
>> +		       i + 1, err);
>> +		goto exit;
>> +	}
>> + exit:
>> +	pr_info("test_ecdsa: %s\n", err ? "FAILED" : "PASSED");
>
> This log message should go away.

Okay.

>
>> +	return err;
>> +}
>> +
>>  static int test_akcipher_one(struct crypto_akcipher *tfm,
>>  			     struct akcipher_testvec *vecs)
>>  {
>> @@ -2236,9 +2667,17 @@ static int alg_test_akcipher(const struct
>> alg_test_desc *desc, driver, PTR_ERR(tfm));
>>  		return PTR_ERR(tfm);
>>  	}
>> -	if (desc->suite.akcipher.vecs)
>> -		err = test_akcipher(tfm, desc->alg, desc->suite.akcipher.vecs,
>> -				    desc->suite.akcipher.count);
>> +
>> +	if (desc->suite.akcipher.vecs) {
>> +		if (strncmp(desc->alg, "ecdsa", 5) == 0)
>> +			err = test_ecdsa_akcipher(tfm, desc->alg,
>> +						  desc->suite.akcipher.vecs,
>> +						  desc->suite.akcipher.count);
>> +		else
>> +			err = test_akcipher(tfm, desc->alg,
>> +					    desc->suite.akcipher.vecs,
>> +					    desc->suite.akcipher.count);
>> +	}
>>
>>  	crypto_free_akcipher(tfm);
>>  	return err;
>> @@ -2982,6 +3421,13 @@ static int alg_test_null(const struct alg_test_desc
>> *desc, .kpp = __VECS(ecdh_tv_template)
>>  		}
>>  	}, {
>> +		.alg = "ecdsa",
>> +		.test = alg_test_akcipher,
>> +		.fips_allowed = 1,
>> +		.suite = {
>> +			.akcipher = __VECS(ecdsa_tv_template)
>> +		}
>> +	}, {
>
>
>
> Ciao
> Stephan
>

Thanks,
- Nitin
-----------------------------------------------------------------------------------
This email message is for the sole use of the intended recipient(s) and may contain
confidential information.  Any unauthorized review, use, disclosure or distribution
is prohibited.  If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.
-----------------------------------------------------------------------------------

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 0/6] Add support for ECDSA algorithm
  2017-01-23 14:24 ` [PATCH 0/6] Add support for ECDSA algorithm Herbert Xu
@ 2017-01-26  6:00   ` Nitin Kumbhar
  2017-01-26  7:44     ` Stephan Müller
  2017-02-02 13:57     ` Herbert Xu
  0 siblings, 2 replies; 20+ messages in thread
From: Nitin Kumbhar @ 2017-01-26  6:00 UTC (permalink / raw)
  To: Herbert Xu; +Cc: davem, linux-crypto

Hello Herbert,

On 1/23/2017 7:54 PM, Herbert Xu wrote:
> On Fri, Jan 20, 2017 at 05:05:55PM +0530, Nitin Kumbhar wrote:
>> Hello,
>>
>> This patch series adds support for Elliptic Curve Digital Signature
>> Algorithm (ECDSA). To reuse existing ECC functionality, which is
>> added as part of ECDH, it separates out ECC and ECDH so that
>> only ECC functionality is available for ECDSA even when ECDH is in
>> a disabled state.
>>
>> Patch #1 restructures ECC and ECDH code such that ECC is not
>> dependent on ECDH config.
>>
>> Patches #2 & #3 add vli and ecc functions which are required
>> for other Elliptic curve algorithms like ECDSA and ECIES.
>>
>> Patch #4 adds support for ECDSA. This has been validated for P192
>> and P256 elliptic curves.
>>
>> Patches #5 and #6 add ECDSA tests to validate ECDSA functionality
>> and measure ECDSA performance.
>
> Who is going to use this in the kernel?

This ECDSA implementation is analogous to the RSA kernel implementation 
for signature generation / verification. It extends ECC family of 
algorithms like ECDH to support signature verification using akcipher. 
This will be used in a way similar to RSA.

>
> Thanks,
>

Regards,
- Nitin

-----------------------------------------------------------------------------------
This email message is for the sole use of the intended recipient(s) and may contain
confidential information.  Any unauthorized review, use, disclosure or distribution
is prohibited.  If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.
-----------------------------------------------------------------------------------

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 0/6] Add support for ECDSA algorithm
  2017-01-26  6:00   ` Nitin Kumbhar
@ 2017-01-26  7:44     ` Stephan Müller
  2017-02-02 13:57     ` Herbert Xu
  1 sibling, 0 replies; 20+ messages in thread
From: Stephan Müller @ 2017-01-26  7:44 UTC (permalink / raw)
  To: Nitin Kumbhar; +Cc: Herbert Xu, davem, linux-crypto

Am Donnerstag, 26. Januar 2017, 11:30:04 CET schrieb Nitin Kumbhar:

Hi Nitin,

> > Who is going to use this in the kernel?
> 
> This ECDSA implementation is analogous to the RSA kernel implementation
> for signature generation / verification. It extends ECC family of
> algorithms like ECDH to support signature verification using akcipher.
> This will be used in a way similar to RSA.

So, I guess that I should dust off algif_akcipher now.

Ciao
Stephan

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 0/6] Add support for ECDSA algorithm
  2017-01-26  6:00   ` Nitin Kumbhar
  2017-01-26  7:44     ` Stephan Müller
@ 2017-02-02 13:57     ` Herbert Xu
  2017-02-03 11:16       ` Nitin Kumbhar
                         ` (2 more replies)
  1 sibling, 3 replies; 20+ messages in thread
From: Herbert Xu @ 2017-02-02 13:57 UTC (permalink / raw)
  To: Nitin Kumbhar; +Cc: davem, linux-crypto

On Thu, Jan 26, 2017 at 11:30:04AM +0530, Nitin Kumbhar wrote:
> 
> This ECDSA implementation is analogous to the RSA kernel implementation for
> signature generation / verification. It extends ECC family of algorithms
> like ECDH to support signature verification using akcipher. This will be
> used in a way similar to RSA.

Yes but RSA had an in-kernel user in the form of module signature
verification.  We don't add algorithms to the kernel without
actual users.  So this patch-set needs to come with an actual
in-kernel user of ECDSA.

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 0/6] Add support for ECDSA algorithm
  2017-02-02 13:57     ` Herbert Xu
@ 2017-02-03 11:16       ` Nitin Kumbhar
  2017-02-06 14:47       ` Stephan Müller
  2017-08-22 16:14       ` Tudor Ambarus
  2 siblings, 0 replies; 20+ messages in thread
From: Nitin Kumbhar @ 2017-02-03 11:16 UTC (permalink / raw)
  To: Herbert Xu; +Cc: nkumbhar, davem, linux-crypto

Hello Herbert,

On 2/2/2017 7:27 PM, Herbert Xu wrote:
> On Thu, Jan 26, 2017 at 11:30:04AM +0530, Nitin Kumbhar wrote:
>>
>> This ECDSA implementation is analogous to the RSA kernel implementation for
>> signature generation / verification. It extends ECC family of algorithms
>> like ECDH to support signature verification using akcipher. This will be
>> used in a way similar to RSA.
>
> Yes but RSA had an in-kernel user in the form of module signature
> verification.  We don't add algorithms to the kernel without
> actual users.  So this patch-set needs to come with an actual
> in-kernel user of ECDSA.

If this is about ECC in kernel then ECDSA extends ECDH which is from ECC 
and already part of kernel.

If none of the above are sufficient for now then let these patches come 
along with a consumer or let kernel add ECDSA based on akcipher as part 
of a crypto engine.

Nonetheless, how about rest of the vli and ECC patches?

> Thanks,
>

Regards,
- Nitin

-----------------------------------------------------------------------------------
This email message is for the sole use of the intended recipient(s) and may contain
confidential information.  Any unauthorized review, use, disclosure or distribution
is prohibited.  If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.
-----------------------------------------------------------------------------------

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 0/6] Add support for ECDSA algorithm
  2017-02-02 13:57     ` Herbert Xu
  2017-02-03 11:16       ` Nitin Kumbhar
@ 2017-02-06 14:47       ` Stephan Müller
  2017-08-22 16:14       ` Tudor Ambarus
  2 siblings, 0 replies; 20+ messages in thread
From: Stephan Müller @ 2017-02-06 14:47 UTC (permalink / raw)
  To: Herbert Xu; +Cc: Nitin Kumbhar, davem, linux-crypto

Am Donnerstag, 2. Februar 2017, 21:57:21 CET schrieb Herbert Xu:

Hi Herbert,

> On Thu, Jan 26, 2017 at 11:30:04AM +0530, Nitin Kumbhar wrote:
> > This ECDSA implementation is analogous to the RSA kernel implementation
> > for
> > signature generation / verification. It extends ECC family of algorithms
> > like ECDH to support signature verification using akcipher. This will be
> > used in a way similar to RSA.
> 
> Yes but RSA had an in-kernel user in the form of module signature
> verification.  We don't add algorithms to the kernel without
> actual users.  So this patch-set needs to come with an actual
> in-kernel user of ECDSA.

If I understood correctly, the crypto API should also provide device drivers 
for cryptographic accelerators to user space. This would be of special 
importance for asymmetric ciphers considering their resource intense 
operation.

As for each HW implementation there should be a SW fallback, shouldn't ECDSA 
therefore be added?

Please note that I am currently updating algif_akcipher to be en-par with 
algif_skcipher and algif_aead, including an AIO operation.

Ciao
Stephan

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Re: [PATCH 0/6] Add support for ECDSA algorithm
  2017-02-02 13:57     ` Herbert Xu
  2017-02-03 11:16       ` Nitin Kumbhar
  2017-02-06 14:47       ` Stephan Müller
@ 2017-08-22 16:14       ` Tudor Ambarus
  2017-08-22 17:22         ` Sandy Harris
  2 siblings, 1 reply; 20+ messages in thread
From: Tudor Ambarus @ 2017-08-22 16:14 UTC (permalink / raw)
  To: Herbert Xu, Nitin Kumbhar; +Cc: davem, linux-crypto

Hi, Herbert,

On 02/02/2017 03:57 PM, Herbert Xu wrote:
> Yes but RSA had an in-kernel user in the form of module signature
> verification.  We don't add algorithms to the kernel without
> actual users.  So this patch-set needs to come with an actual
> in-kernel user of ECDSA.

ECDSA can be used by the kernel module signing facility too. Is there
any interest in using ECDSA by the kernel module signing facility?

Thanks,
ta

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Re: [PATCH 0/6] Add support for ECDSA algorithm
  2017-08-22 16:14       ` Tudor Ambarus
@ 2017-08-22 17:22         ` Sandy Harris
  2017-08-23 13:40           ` Tudor Ambarus
  0 siblings, 1 reply; 20+ messages in thread
From: Sandy Harris @ 2017-08-22 17:22 UTC (permalink / raw)
  To: Tudor Ambarus
  Cc: Herbert Xu, Nitin Kumbhar, David S. Miller, Linux Crypto Mailing List

On Tue, Aug 22, 2017 at 12:14 PM, Tudor Ambarus
<tudor.ambarus@microchip.com> wrote:
> Hi, Herbert,
>
> On 02/02/2017 03:57 PM, Herbert Xu wrote:
>>
>> Yes but RSA had an in-kernel user in the form of module signature
>> verification.  We don't add algorithms to the kernel without
>> actual users.  So this patch-set needs to come with an actual
>> in-kernel user of ECDSA.
>
>
> ECDSA can be used by the kernel module signing facility too. Is there
> any interest in using ECDSA by the kernel module signing facility?

I'd say keep it simple wherever possible; adding an algorithm should
need "is required by" not just "can be used by".

Even then, there is room for questions. In particular, whether such a
fragile algorithm should be trusted at all, let alone for signatures
on infrastructure modules that the whole OS will trust.
https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Security

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 0/6] Add support for ECDSA algorithm
  2017-08-22 17:22         ` Sandy Harris
@ 2017-08-23 13:40           ` Tudor Ambarus
  0 siblings, 0 replies; 20+ messages in thread
From: Tudor Ambarus @ 2017-08-23 13:40 UTC (permalink / raw)
  To: Sandy Harris
  Cc: Herbert Xu, Nitin Kumbhar, David S. Miller, Linux Crypto Mailing List

Hi, Sandy,

On 08/22/2017 08:22 PM, Sandy Harris wrote:
> On Tue, Aug 22, 2017 at 12:14 PM, Tudor Ambarus
> <tudor.ambarus@microchip.com> wrote:
>> Hi, Herbert,
>>
>> On 02/02/2017 03:57 PM, Herbert Xu wrote:
>>>
>>> Yes but RSA had an in-kernel user in the form of module signature
>>> verification.  We don't add algorithms to the kernel without
>>> actual users.  So this patch-set needs to come with an actual
>>> in-kernel user of ECDSA.
>>
>>
>> ECDSA can be used by the kernel module signing facility too. Is there
>> any interest in using ECDSA by the kernel module signing facility?
> 
> I'd say keep it simple wherever possible; adding an algorithm should
> need "is required by" not just "can be used by".
> 
> Even then, there is room for questions. In particular, whether such a
> fragile algorithm should be trusted at all, let alone for signatures
> on infrastructure modules that the whole OS will trust.
> https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Security
> 

ECDSA is a better alternative to RSA for digital signatures assuming
that you don't have implementation bugs.

ECDSA requires a much smaller key length in order to provide the same
security strength as RSA (see [1]):

security strength | RSA key length (bits) | ECDSA key lengths (bits)
        112                   2048                    224-255
        128                   3072                    256-383

When comparing to RSA, ECDSA promises better computational efficiency,
signature size and bandwith (see [2]).

Cheers,
ta

[1] NIST.SP.800-57pt1r4, section 5.6.1,  table 2
[2] rfc4754, rfc6979

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2017-08-23 13:41 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-20 11:35 [PATCH 0/6] Add support for ECDSA algorithm Nitin Kumbhar
2017-01-20 11:35 ` [PATCH 1/6] crypto: ecc: separate out ecc and ecdh Nitin Kumbhar
2017-01-20 11:35 ` [PATCH 2/6] crypto: ecc: add vli and ecc ops Nitin Kumbhar
2017-01-20 11:35 ` [PATCH 3/6] crypto: ecc: export " Nitin Kumbhar
2017-01-20 11:35 ` [PATCH 4/6] crypto: ecdsa: add ECDSA SW implementation Nitin Kumbhar
2017-01-20 13:06   ` Stephan Müller
2017-01-26  5:52     ` Nitin Kumbhar
2017-01-20 11:36 ` [PATCH 5/6] crypto: testmgr: add ECDSA tests Nitin Kumbhar
2017-01-20 13:19   ` Stephan Müller
2017-01-26  5:58     ` Nitin Kumbhar
2017-01-20 11:36 ` [PATCH 6/6] crypto: tcrypt: add ECDSA test modes Nitin Kumbhar
2017-01-23 14:24 ` [PATCH 0/6] Add support for ECDSA algorithm Herbert Xu
2017-01-26  6:00   ` Nitin Kumbhar
2017-01-26  7:44     ` Stephan Müller
2017-02-02 13:57     ` Herbert Xu
2017-02-03 11:16       ` Nitin Kumbhar
2017-02-06 14:47       ` Stephan Müller
2017-08-22 16:14       ` Tudor Ambarus
2017-08-22 17:22         ` Sandy Harris
2017-08-23 13:40           ` Tudor Ambarus

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).