diff mbox series

[v4,4/5] crypto: hisilicon/hpre - add 'ECDH' algorithm

Message ID 1607668234-46130-5-git-send-email-yumeng18@huawei.com (mailing list archive)
State Superseded
Delegated to: Herbert Xu
Headers show
Series add ECDH and CURVE25519 algorithms support for Kunpeng 930 | expand

Commit Message

Meng Yu Dec. 11, 2020, 6:30 a.m. UTC
1. Add some new 'ECDH' curve parameter definitions to
   'include/crypto/ecc_curve_defs.h', and reorder ECC 'Curves IDs'
   in 'include/crypto/ecdh.h';
2. Enable 'ECDH' algorithm in Kunpeng 930.

Signed-off-by: Meng Yu <yumeng18@huawei.com>
Reviewed-by: Zaibo Xu <xuzaibo@huawei.com>
---
 crypto/ecc.c                                |   4 +-
 crypto/testmgr.h                            |  12 +-
 drivers/crypto/hisilicon/hpre/hpre.h        |   2 +-
 drivers/crypto/hisilicon/hpre/hpre_crypto.c | 510 +++++++++++++++++++++++++++-
 drivers/crypto/hisilicon/hpre/hpre_main.c   |   1 +
 include/crypto/ecc_curve_defs.h             | 198 +++++++++--
 include/crypto/ecdh.h                       |   9 +-
 7 files changed, 698 insertions(+), 38 deletions(-)

Comments

Stephan Mueller Dec. 11, 2020, 2:08 p.m. UTC | #1
Am Freitag, den 11.12.2020, 14:30 +0800 schrieb Meng Yu:
> 
> +/* size in bytes of the n prime */
> +#define HPRE_ECC_NIST_P128_N_SIZE      16

Do we truly need P-128? Besides, I do not see that curve being defined in
contemporary cipher specs.

> +#define HPRE_ECC_NIST_P192_N_SIZE      24
> +#define HPRE_ECC_NIST_P224_N_SIZE      28
> +#define HPRE_ECC_NIST_P256_N_SIZE      32
> +#define HPRE_ECC_NIST_P320_N_SIZE      40

Do we truly need P-320? Besides, I do not see that curve being defined in
contemporary cipher specs.

> +#define HPRE_ECC_NIST_P384_N_SIZE      48
> +#define HPRE_ECC_NIST_P521_N_SIZE      66
> +
> +/* size in bytes */
> +#define HPRE_ECC_HW256_KSZ_B   32
> +#define HPRE_ECC_HW384_KSZ_B   48
> +#define HPRE_ECC_HW576_KSZ_B   72
> +
> +#define HPRE_ECDH_MAX_SZ       HPRE_ECC_HW576_KSZ_B]

Ciao
Stephan
Meng Yu Dec. 16, 2020, 2:39 a.m. UTC | #2
> Am Freitag, den 11.12.2020, 14:30 +0800 schrieb Meng Yu:
>> 
>> +/* size in bytes of the n prime */
>> +#define HPRE_ECC_NIST_P128_N_SIZE      16
> 
> Do we truly need P-128? Besides, I do not see that curve being defined in
> contemporary cipher specs.
> 
>> +#define HPRE_ECC_NIST_P192_N_SIZE      24
>> +#define HPRE_ECC_NIST_P224_N_SIZE      28
>> +#define HPRE_ECC_NIST_P256_N_SIZE      32
>> +#define HPRE_ECC_NIST_P320_N_SIZE      40
> 
> Do we truly need P-320? Besides, I do not see that curve being defined in
> contemporary cipher specs.

Yes, in rfc 5903, only P-256, P-384 and P-521 is defined, but in
'rfc5639' and  "SEC 2: Recommended Elliptic Curve Domain Parameters",
other curves like P-128, P-192, P-224, and P-320 curve parameters are
found, and they are used in 'openssl';
How about your idea?

Thanks,


>> +#define HPRE_ECC_NIST_P384_N_SIZE      48
>> +#define HPRE_ECC_NIST_P521_N_SIZE      66
>> +
>> +/* size in bytes */
>> +#define HPRE_ECC_HW256_KSZ_B   32
>> +#define HPRE_ECC_HW384_KSZ_B   48
>> +#define HPRE_ECC_HW576_KSZ_B   72
>> +
>> +#define HPRE_ECDH_MAX_SZ       HPRE_ECC_HW576_KSZ_B]
> 
> Ciao
> Stephan
> 
> .
>
Stephan Mueller Dec. 16, 2020, 8:10 p.m. UTC | #3
Am Mittwoch, dem 16.12.2020 um 10:39 +0800 schrieb yumeng:
> 
> 
> 
> > Am Freitag, den 11.12.2020, 14:30 +0800 schrieb Meng Yu:
> > > 
> > > +/* size in bytes of the n prime */
> > > +#define HPRE_ECC_NIST_P128_N_SIZE      16
> > 
> > Do we truly need P-128? Besides, I do not see that curve being defined in
> > contemporary cipher specs.
> > 
> > > +#define HPRE_ECC_NIST_P192_N_SIZE      24
> > > +#define HPRE_ECC_NIST_P224_N_SIZE      28
> > > +#define HPRE_ECC_NIST_P256_N_SIZE      32
> > > +#define HPRE_ECC_NIST_P320_N_SIZE      40
> > 
> > Do we truly need P-320? Besides, I do not see that curve being defined in
> > contemporary cipher specs.
> 
> Yes, in rfc 5903, only P-256, P-384 and P-521 is defined, but in
> 'rfc5639' and  "SEC 2: Recommended Elliptic Curve Domain Parameters",
> other curves like P-128, P-192, P-224, and P-320 curve parameters are
> found, and they are used in 'openssl';
> How about your idea?

Who is going to use that curve considering that common protocols that are
implemented in the kernel do not use it?

Thanks
Stephan
Meng Yu Dec. 17, 2020, 3:07 a.m. UTC | #4
在 2020/12/17 4:10, Stephan Mueller 写道:
> Am Mittwoch, dem 16.12.2020 um 10:39 +0800 schrieb yumeng:
>>
>>
>>
>>> Am Freitag, den 11.12.2020, 14:30 +0800 schrieb Meng Yu:
>>>>
>>>> +/* size in bytes of the n prime */
>>>> +#define HPRE_ECC_NIST_P128_N_SIZE      16
>>>
>>> Do we truly need P-128? Besides, I do not see that curve being defined in
>>> contemporary cipher specs.
>>>
>>>> +#define HPRE_ECC_NIST_P192_N_SIZE      24
>>>> +#define HPRE_ECC_NIST_P224_N_SIZE      28
>>>> +#define HPRE_ECC_NIST_P256_N_SIZE      32
>>>> +#define HPRE_ECC_NIST_P320_N_SIZE      40
>>>
>>> Do we truly need P-320? Besides, I do not see that curve being defined in
>>> contemporary cipher specs.
>>
>> Yes, in rfc 5903, only P-256, P-384 and P-521 is defined, but in
>> 'rfc5639' and  "SEC 2: Recommended Elliptic Curve Domain Parameters",
>> other curves like P-128, P-192, P-224, and P-320 curve parameters are
>> found, and they are used in 'openssl';
>> How about your idea?
> 
> Who is going to use that curve considering that common protocols that are
> implemented in the kernel do not use it?
> 
> Thanks
> Stephan
> 

I see in "SEC 2: Recommended Elliptic Curve Domain ParametersVersion2.0"
that 'Recommend Elliptic Curve Domain Parameters over Fp' are secp192,
secp224, secp256, secp384, and secp521, secp128 and secp320 are not
recommended.
So you mean it's better not to include secp128 and secp320, right?

Thanks,
Stephan Mueller Dec. 19, 2020, 9:25 p.m. UTC | #5
Am Donnerstag, 17. Dezember 2020, 04:07:30 CET schrieb yumeng:

Hi yumeng,

> 
> I see in "SEC 2: Recommended Elliptic Curve Domain ParametersVersion2.0"
> that 'Recommend Elliptic Curve Domain Parameters over Fp' are secp192,
> secp224, secp256, secp384, and secp521, secp128 and secp320 are not
> recommended.
> So you mean it's better not to include secp128 and secp320, right?

Precisely because I do not see the use case in the kernel.
> 
> Thanks,


Ciao
Stephan
diff mbox series

Patch

diff --git a/crypto/ecc.c b/crypto/ecc.c
index f23efdd..6adcae2 100644
--- a/crypto/ecc.c
+++ b/crypto/ecc.c
@@ -46,9 +46,9 @@  static inline const struct ecc_curve *ecc_get_curve(unsigned int curve_id)
 	switch (curve_id) {
 	/* In FIPS mode only allow P256 and higher */
 	case ECC_CURVE_NIST_P192:
-		return fips_enabled ? NULL : &nist_p192;
+		return fips_enabled ? NULL : &ecc_curve_list[ECC_CURVE_NIST_P192 - 1];
 	case ECC_CURVE_NIST_P256:
-		return &nist_p256;
+		return &ecc_curve_list[ECC_CURVE_NIST_P256 - 1];
 	default:
 		return NULL;
 	}
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 8c83811..371692e 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -2268,12 +2268,12 @@  static const struct kpp_testvec ecdh_tv_template[] = {
 #ifdef __LITTLE_ENDIAN
 	"\x02\x00" /* type */
 	"\x20\x00" /* len */
-	"\x01\x00" /* curve_id */
+	"\x02\x00" /* curve_id */
 	"\x18\x00" /* key_size */
 #else
 	"\x00\x02" /* type */
 	"\x00\x20" /* len */
-	"\x00\x01" /* curve_id */
+	"\x00\x02" /* curve_id */
 	"\x00\x18" /* key_size */
 #endif
 	"\xb5\x05\xb1\x71\x1e\xbf\x8c\xda"
@@ -2307,12 +2307,12 @@  static const struct kpp_testvec ecdh_tv_template[] = {
 #ifdef __LITTLE_ENDIAN
 	"\x02\x00" /* type */
 	"\x28\x00" /* len */
-	"\x02\x00" /* curve_id */
+	"\x04\x00" /* curve_id */
 	"\x20\x00" /* key_size */
 #else
 	"\x00\x02" /* type */
 	"\x00\x28" /* len */
-	"\x00\x02" /* curve_id */
+	"\x00\x04" /* curve_id */
 	"\x00\x20" /* key_size */
 #endif
 	"\x24\xd1\x21\xeb\xe5\xcf\x2d\x83"
@@ -2351,12 +2351,12 @@  static const struct kpp_testvec ecdh_tv_template[] = {
 #ifdef __LITTLE_ENDIAN
 	"\x02\x00" /* type */
 	"\x08\x00" /* len */
-	"\x02\x00" /* curve_id */
+	"\x04\x00" /* curve_id */
 	"\x00\x00", /* key_size */
 #else
 	"\x00\x02" /* type */
 	"\x00\x08" /* len */
-	"\x00\x02" /* curve_id */
+	"\x00\x04" /* curve_id */
 	"\x00\x00", /* key_size */
 #endif
 	.b_secret =
diff --git a/drivers/crypto/hisilicon/hpre/hpre.h b/drivers/crypto/hisilicon/hpre/hpre.h
index 02193e1..50e6b2e 100644
--- a/drivers/crypto/hisilicon/hpre/hpre.h
+++ b/drivers/crypto/hisilicon/hpre/hpre.h
@@ -83,6 +83,7 @@  enum hpre_alg_type {
 	HPRE_ALG_KG_CRT = 0x3,
 	HPRE_ALG_DH_G2 = 0x4,
 	HPRE_ALG_DH = 0x5,
+	HPRE_ALG_ECC_MUL = 0xD,
 };
 
 struct hpre_sqe {
@@ -104,5 +105,4 @@  struct hisi_qp *hpre_create_qp(u8 type);
 int hpre_algs_register(struct hisi_qm *qm);
 void hpre_algs_unregister(struct hisi_qm *qm);
 
-
 #endif
diff --git a/drivers/crypto/hisilicon/hpre/hpre_crypto.c b/drivers/crypto/hisilicon/hpre/hpre_crypto.c
index 712bea9..58f847b 100644
--- a/drivers/crypto/hisilicon/hpre/hpre_crypto.c
+++ b/drivers/crypto/hisilicon/hpre/hpre_crypto.c
@@ -2,6 +2,8 @@ 
 /* Copyright (c) 2019 HiSilicon Limited. */
 #include <crypto/akcipher.h>
 #include <crypto/dh.h>
+#include <crypto/ecc_curve_defs.h>
+#include <crypto/ecdh.h>
 #include <crypto/internal/akcipher.h>
 #include <crypto/internal/kpp.h>
 #include <crypto/internal/rsa.h>
@@ -36,6 +38,22 @@  struct hpre_ctx;
 #define HPRE_DFX_SEC_TO_US	1000000
 #define HPRE_DFX_US_TO_NS	1000
 
+/* size in bytes of the n prime */
+#define HPRE_ECC_NIST_P128_N_SIZE	16
+#define HPRE_ECC_NIST_P192_N_SIZE	24
+#define HPRE_ECC_NIST_P224_N_SIZE	28
+#define HPRE_ECC_NIST_P256_N_SIZE	32
+#define HPRE_ECC_NIST_P320_N_SIZE	40
+#define HPRE_ECC_NIST_P384_N_SIZE	48
+#define HPRE_ECC_NIST_P521_N_SIZE	66
+
+/* size in bytes */
+#define HPRE_ECC_HW256_KSZ_B	32
+#define HPRE_ECC_HW384_KSZ_B	48
+#define HPRE_ECC_HW576_KSZ_B	72
+
+#define HPRE_ECDH_MAX_SZ	HPRE_ECC_HW576_KSZ_B
+
 typedef void (*hpre_cb)(struct hpre_ctx *ctx, void *sqe);
 
 struct hpre_rsa_ctx {
@@ -61,14 +79,25 @@  struct hpre_dh_ctx {
 	 * else if base if the counterpart public key we
 	 * compute the shared secret
 	 *	ZZ = yb^xa mod p; [RFC2631 sec 2.1.1]
+	 * low address: d--->n, please refer to Hisilicon HPRE UM
 	 */
-	char *xa_p; /* low address: d--->n, please refer to Hisilicon HPRE UM */
+	char *xa_p;
 	dma_addr_t dma_xa_p;
 
 	char *g; /* m */
 	dma_addr_t dma_g;
 };
 
+struct hpre_ecdh_ctx {
+	/* low address: p->a->k->b */
+	unsigned char *p;
+	dma_addr_t dma_p;
+
+	/* low address: x->y */
+	unsigned char *g;
+	dma_addr_t dma_g;
+};
+
 struct hpre_ctx {
 	struct hisi_qp *qp;
 	struct hpre_asym_request **req_list;
@@ -80,7 +109,10 @@  struct hpre_ctx {
 	union {
 		struct hpre_rsa_ctx rsa;
 		struct hpre_dh_ctx dh;
+		struct hpre_ecdh_ctx ecdh;
 	};
+	/* for ecc algorithms */
+	unsigned int curve_id;
 };
 
 struct hpre_asym_request {
@@ -91,6 +123,7 @@  struct hpre_asym_request {
 	union {
 		struct akcipher_request *rsa;
 		struct kpp_request *dh;
+		struct kpp_request *ecdh;
 	} areq;
 	int err;
 	int req_id;
@@ -1115,6 +1148,443 @@  static void hpre_rsa_exit_tfm(struct crypto_akcipher *tfm)
 	crypto_free_akcipher(ctx->rsa.soft_tfm);
 }
 
+static void hpre_key_to_big_end(u8 *data, int len)
+{
+	int i, j;
+	u8 tmp;
+
+	for (i = 0; i < len / 2; i++) {
+		j = len - i - 1;
+		tmp = data[j];
+		data[j] = data[i];
+		data[i] = tmp;
+	}
+}
+
+static void hpre_ecc_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all,
+			       bool is_ecdh)
+{
+	struct device *dev = HPRE_DEV(ctx);
+	unsigned int sz = ctx->key_sz;
+	unsigned int shift = sz << 1;
+
+	if (is_clear_all)
+		hisi_qm_stop_qp(ctx->qp);
+
+	if (is_ecdh && ctx->ecdh.p) {
+		/* ecdh: p->a->k->b */
+		memzero_explicit(ctx->ecdh.p + shift, sz);
+		dma_free_coherent(dev, sz << 3, ctx->ecdh.p, ctx->ecdh.dma_p);
+		ctx->ecdh.p = NULL;
+	}
+
+	ctx->curve_id = 0;
+	hpre_ctx_clear(ctx, is_clear_all);
+}
+
+/*
+ * only the bits of 128/192/224/256/320/384/521 are supported by HPRE,
+ * and convert the bits like:
+ * bits<=256, bits=256; 256<bits<=384, bits=384; 384<bits<=576, bits=576;
+ * If the parameter bit width is insufficient, then we fill in the
+ * high-order zeros by soft, so TASK_LENGTH1 is 0x3/0x5/0x8;
+ */
+static unsigned int hpre_ecdh_supported_curve(unsigned int curve_id)
+{
+	switch (curve_id) {
+	case ECC_CURVE_NIST_P192:
+	case ECC_CURVE_NIST_P256:
+	case ECC_CURVE_NIST_P128:
+	case ECC_CURVE_NIST_P224:
+		return HPRE_ECC_HW256_KSZ_B;
+	case ECC_CURVE_NIST_P320:
+	case ECC_CURVE_NIST_P384:
+		return HPRE_ECC_HW384_KSZ_B;
+	case ECC_CURVE_NIST_P521:
+		return HPRE_ECC_HW576_KSZ_B;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+void fill_curve_param(void *addr, u64 *param, unsigned int cur_sz, u8 ndigits)
+{
+	unsigned int sz = cur_sz - (ndigits - 1) * sizeof(u64);
+	u8 i = 0;
+
+	while (i < ndigits - 1) {
+		memcpy(addr + sizeof(u64) * i, &param[i], sizeof(u64));
+		i++;
+	}
+
+	memcpy(addr + sizeof(u64) * i, &param[ndigits - 1], sz);
+	hpre_key_to_big_end((u8 *)addr, cur_sz);
+}
+
+static const struct ecc_curve *ecdh_get_curve_param(__u32 curve_id)
+{
+	if (curve_id >= ECC_CURVE_NIST_P128 &&
+	    curve_id <= ECC_CURVE_NIST_P521)
+		return &ecc_curve_list[curve_id - 1];
+
+	return NULL;
+}
+
+static int hpre_ecdh_fill_curve(struct hpre_ctx *ctx, struct ecdh *params,
+				unsigned int cur_sz)
+{
+	unsigned int shifta = ctx->key_sz << 1;
+	unsigned int shiftb = ctx->key_sz << 2;
+	void *p = ctx->ecdh.p + ctx->key_sz - cur_sz;
+	void *a = ctx->ecdh.p + shifta - cur_sz;
+	void *b = ctx->ecdh.p + shiftb - cur_sz;
+	void *x = ctx->ecdh.g + ctx->key_sz - cur_sz;
+	void *y = ctx->ecdh.g + shifta - cur_sz;
+	const struct ecc_curve *curve;
+	char *n;
+
+	n = kzalloc(ctx->key_sz, GFP_KERNEL);
+	if (!n)
+		return -ENOMEM;
+
+	curve = ecdh_get_curve_param(params->curve_id);
+	if (!curve)
+		goto free;
+
+	fill_curve_param(p, curve->p, cur_sz, curve->g.ndigits);
+	fill_curve_param(a, curve->a, cur_sz, curve->g.ndigits);
+	fill_curve_param(b, curve->b, cur_sz, curve->g.ndigits);
+	fill_curve_param(x, curve->g.x, cur_sz, curve->g.ndigits);
+	fill_curve_param(y, curve->g.y, cur_sz, curve->g.ndigits);
+	fill_curve_param(n, curve->n, cur_sz, curve->g.ndigits);
+
+	if (params->key_size == cur_sz && strcmp(params->key, n) >= 0)
+		goto free;
+
+	kfree(n);
+	return 0;
+
+free:
+	kfree(n);
+	return -EINVAL;
+}
+
+static unsigned int hpre_ecdh_get_curvesz(unsigned short id)
+{
+	switch (id) {
+	case ECC_CURVE_NIST_P192:
+		return HPRE_ECC_NIST_P192_N_SIZE;
+	case ECC_CURVE_NIST_P256:
+		return HPRE_ECC_NIST_P256_N_SIZE;
+	case ECC_CURVE_NIST_P128:
+		return HPRE_ECC_NIST_P128_N_SIZE;
+	case ECC_CURVE_NIST_P224:
+		return HPRE_ECC_NIST_P224_N_SIZE;
+	case ECC_CURVE_NIST_P320:
+		return HPRE_ECC_NIST_P320_N_SIZE;
+	case ECC_CURVE_NIST_P384:
+		return HPRE_ECC_NIST_P384_N_SIZE;
+	case ECC_CURVE_NIST_P521:
+		return HPRE_ECC_NIST_P521_N_SIZE;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int hpre_ecdh_set_param(struct hpre_ctx *ctx, struct ecdh *params)
+{
+	struct device *dev = HPRE_DEV(ctx);
+	unsigned int sz, shift, curve_sz;
+	int ret;
+
+	ctx->key_sz = hpre_ecdh_supported_curve(params->curve_id);
+	if (!ctx->key_sz)
+		return -EINVAL;
+
+	curve_sz = hpre_ecdh_get_curvesz(params->curve_id);
+	if (!curve_sz || params->key_size > curve_sz)
+		return -EINVAL;
+
+	sz = ctx->key_sz;
+	ctx->curve_id = params->curve_id;
+
+	if (!ctx->ecdh.p) {
+		ctx->ecdh.p = dma_alloc_coherent(dev, sz << 3, &ctx->ecdh.dma_p,
+						 GFP_KERNEL);
+		if (!ctx->ecdh.p)
+			return -ENOMEM;
+	}
+
+	shift = sz << 2;
+	ctx->ecdh.g = ctx->ecdh.p + shift;
+	ctx->ecdh.dma_g = ctx->ecdh.dma_p + shift;
+
+	ret = hpre_ecdh_fill_curve(ctx, params, curve_sz);
+	if (ret) {
+		dev_err(dev, "failed to fill curve_param, ret = %d!\n", ret);
+		dma_free_coherent(dev, sz << 3, ctx->ecdh.p, ctx->ecdh.dma_p);
+		ctx->ecdh.p = NULL;
+		return ret;
+	}
+
+	return 0;
+}
+
+static bool hpre_key_is_valid(char *key, unsigned short key_sz)
+{
+	int i;
+
+	for (i = 0; i < key_sz; i++)
+		if (key[i])
+			return true;
+
+	return false;
+}
+
+static int hpre_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
+				unsigned int len)
+{
+	struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
+	struct device *dev = HPRE_DEV(ctx);
+	unsigned int sz, sz_shift;
+	struct ecdh params;
+	int ret;
+
+	if (crypto_ecdh_decode_key(buf, len, &params) < 0) {
+		dev_err(dev, "failed to decode ecdh key!\n");
+		return -EINVAL;
+	}
+
+	if (!hpre_key_is_valid(params.key, params.key_size)) {
+		dev_err(dev, "Invalid hpre key!\n");
+		return -EINVAL;
+	}
+
+	hpre_ecc_clear_ctx(ctx, false, true);
+
+	ret = hpre_ecdh_set_param(ctx, &params);
+	if (ret < 0) {
+		dev_err(dev, "failed to set hpre param, ret = %d!\n", ret);
+		return ret;
+	}
+
+	sz = ctx->key_sz;
+	sz_shift = (sz << 1) + sz - params.key_size;
+	memcpy(ctx->ecdh.p + sz_shift, params.key, params.key_size);
+
+	return 0;
+}
+
+static void hpre_ecdh_hw_data_clr_all(struct hpre_ctx *ctx,
+				      struct hpre_asym_request *req,
+				      struct scatterlist *dst,
+				      struct scatterlist *src)
+{
+	struct device *dev = HPRE_DEV(ctx);
+	struct hpre_sqe *sqe = &req->req;
+	dma_addr_t dma;
+
+	dma = le64_to_cpu(sqe->in);
+	if (unlikely(!dma))
+		return;
+
+	if (src && req->src)
+		dma_free_coherent(dev, ctx->key_sz << 2, req->src, dma);
+
+	dma = le64_to_cpu(sqe->out);
+	if (unlikely(!dma))
+		return;
+
+	if (req->dst)
+		dma_free_coherent(dev, ctx->key_sz << 1, req->dst, dma);
+	if (dst)
+		dma_unmap_single(dev, dma, ctx->key_sz << 1, DMA_FROM_DEVICE);
+}
+
+static void hpre_ecdh_cb(struct hpre_ctx *ctx, void *resp)
+{
+	unsigned int curve_sz = hpre_ecdh_get_curvesz(ctx->curve_id);
+	struct hpre_dfx *dfx = ctx->hpre->debug.dfx;
+	struct hpre_asym_request *req = NULL;
+	struct kpp_request *areq;
+	u64 overtime_thrhld;
+	char *p;
+	int ret;
+
+	ret = hpre_alg_res_post_hf(ctx, resp, (void **)&req);
+	areq = req->areq.ecdh;
+	areq->dst_len = ctx->key_sz << 1;
+
+	overtime_thrhld = atomic64_read(&dfx[HPRE_OVERTIME_THRHLD].value);
+	if (overtime_thrhld && hpre_is_bd_timeout(req, overtime_thrhld))
+		atomic64_inc(&dfx[HPRE_OVER_THRHLD_CNT].value);
+
+	p = sg_virt(areq->dst);
+	memmove(p, p + ctx->key_sz - curve_sz, curve_sz);
+	memmove(p + curve_sz, p + areq->dst_len - curve_sz, curve_sz);
+
+	hpre_ecdh_hw_data_clr_all(ctx, req, areq->dst, areq->src);
+	kpp_request_complete(areq, ret);
+
+	atomic64_inc(&dfx[HPRE_RECV_CNT].value);
+}
+
+static int hpre_ecdh_msg_request_set(struct hpre_ctx *ctx,
+				     struct kpp_request *req)
+{
+	struct hpre_asym_request *h_req;
+	struct hpre_sqe *msg;
+	int req_id;
+	void *tmp;
+
+	if (req->dst_len < ctx->key_sz << 1) {
+		req->dst_len = ctx->key_sz << 1;
+		return -EINVAL;
+	}
+
+	tmp = kpp_request_ctx(req);
+	h_req = PTR_ALIGN(tmp, HPRE_ALIGN_SZ);
+	h_req->cb = hpre_ecdh_cb;
+	h_req->areq.ecdh = req;
+	msg = &h_req->req;
+	memset(msg, 0, sizeof(*msg));
+	msg->key = cpu_to_le64(ctx->ecdh.dma_p);
+
+	msg->dw0 |= cpu_to_le32(0x1U << HPRE_SQE_DONE_SHIFT);
+	msg->task_len1 = (ctx->key_sz >> HPRE_BITS_2_BYTES_SHIFT) - 1;
+	h_req->ctx = ctx;
+
+	req_id = hpre_add_req_to_ctx(h_req);
+	if (req_id < 0)
+		return -EBUSY;
+
+	msg->tag = cpu_to_le16((u16)req_id);
+	return 0;
+}
+
+static int hpre_ecdh_src_data_init(struct hpre_asym_request *hpre_req,
+				   struct scatterlist *data, unsigned int len)
+{
+	struct hpre_sqe *msg = &hpre_req->req;
+	struct hpre_ctx *ctx = hpre_req->ctx;
+	struct device *dev = HPRE_DEV(ctx);
+	unsigned int tmpshift;
+	dma_addr_t dma = 0;
+	void *ptr;
+	int shift;
+
+	/* Src_data include gx and gy. */
+	shift = ctx->key_sz - (len >> 1);
+	if (unlikely(shift < 0))
+		return -EINVAL;
+
+	ptr = dma_alloc_coherent(dev, ctx->key_sz << 2, &dma, GFP_KERNEL);
+	if (unlikely(!ptr))
+		return -ENOMEM;
+
+	tmpshift = ctx->key_sz << 1;
+	scatterwalk_map_and_copy(ptr + tmpshift, data, 0, len, 0);
+	memcpy(ptr + shift, ptr + tmpshift, len >> 1);
+	memcpy(ptr + ctx->key_sz + shift, ptr + tmpshift + (len >> 1), len >> 1);
+
+	hpre_req->src = ptr;
+	msg->in = cpu_to_le64(dma);
+	return 0;
+}
+
+static int hpre_ecdh_dst_data_init(struct hpre_asym_request *hpre_req,
+				   struct scatterlist *data, unsigned int len)
+{
+	struct hpre_sqe *msg = &hpre_req->req;
+	struct hpre_ctx *ctx = hpre_req->ctx;
+	struct device *dev = HPRE_DEV(ctx);
+	dma_addr_t dma = 0;
+
+	if (unlikely(!data || !sg_is_last(data) || len != ctx->key_sz << 1)) {
+		dev_err(dev, "data or data length is illegal!\n");
+		return -EINVAL;
+	}
+
+	hpre_req->dst = NULL;
+	dma = dma_map_single(dev, sg_virt(data), len, DMA_FROM_DEVICE);
+	if (unlikely(dma_mapping_error(dev, dma))) {
+		dev_err(dev, "dma map data err!\n");
+		return -ENOMEM;
+	}
+
+	msg->out = cpu_to_le64(dma);
+	return 0;
+}
+
+static int hpre_ecdh_compute_value(struct kpp_request *req)
+{
+	struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
+	struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
+	struct device *dev = HPRE_DEV(ctx);
+	void *tmp = kpp_request_ctx(req);
+	struct hpre_asym_request *hpre_req = PTR_ALIGN(tmp, HPRE_ALIGN_SZ);
+	struct hpre_sqe *msg = &hpre_req->req;
+	int ret;
+
+	ret = hpre_ecdh_msg_request_set(ctx, req);
+	if (unlikely(ret)) {
+		dev_err(dev, "failed to set ecdh request, ret = %d!\n", ret);
+		return ret;
+	}
+
+	if (req->src) {
+		ret = hpre_ecdh_src_data_init(hpre_req, req->src, req->src_len);
+		if (unlikely(ret)) {
+			dev_err(dev, "failed to init src data, ret = %d!\n", ret);
+			goto clear_all;
+		}
+	} else {
+		msg->in = cpu_to_le64(ctx->ecdh.dma_g);
+	}
+
+	ret = hpre_ecdh_dst_data_init(hpre_req, req->dst, req->dst_len);
+	if (unlikely(ret)) {
+		dev_err(dev, "failed to init dst data, ret = %d!\n", ret);
+		goto clear_all;
+	}
+
+	msg->dw0 = cpu_to_le32(le32_to_cpu(msg->dw0) | HPRE_ALG_ECC_MUL);
+	ret = hpre_send(ctx, msg);
+	if (likely(!ret))
+		return -EINPROGRESS;
+
+clear_all:
+	hpre_rm_req_from_ctx(hpre_req);
+	hpre_ecdh_hw_data_clr_all(ctx, hpre_req, req->dst, req->src);
+	return ret;
+}
+
+static unsigned int hpre_ecdh_max_size(struct crypto_kpp *tfm)
+{
+	struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
+
+	/* max size is the pub_key_size, include x and y */
+	return ctx->key_sz << 1;
+}
+
+static int hpre_ecdh_init_tfm(struct crypto_kpp *tfm)
+{
+	struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
+
+	return hpre_ctx_init(ctx, HPRE_V3_ECC_ALG_TYPE);
+}
+
+static void hpre_ecdh_exit_tfm(struct crypto_kpp *tfm)
+{
+	struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
+
+	hpre_ecc_clear_ctx(ctx, true, true);
+}
+
 static struct akcipher_alg rsa = {
 	.sign = hpre_rsa_dec,
 	.verify = hpre_rsa_enc,
@@ -1154,6 +1624,22 @@  static struct kpp_alg dh = {
 };
 #endif
 
+static struct kpp_alg ecdh = {
+	.set_secret = hpre_ecdh_set_secret,
+	.generate_public_key = hpre_ecdh_compute_value,
+	.compute_shared_secret = hpre_ecdh_compute_value,
+	.max_size = hpre_ecdh_max_size,
+	.init = hpre_ecdh_init_tfm,
+	.exit = hpre_ecdh_exit_tfm,
+	.reqsize = sizeof(struct hpre_asym_request) + HPRE_ALIGN_SZ,
+	.base = {
+		.cra_ctxsize = sizeof(struct hpre_ctx),
+		.cra_priority = HPRE_CRYPTO_ALG_PRI,
+		.cra_name = "ecdh",
+		.cra_driver_name = "hpre-ecdh",
+		.cra_module = THIS_MODULE,
+	},
+};
 int hpre_algs_register(struct hisi_qm *qm)
 {
 	int ret;
@@ -1164,17 +1650,33 @@  int hpre_algs_register(struct hisi_qm *qm)
 		return ret;
 #ifdef CONFIG_CRYPTO_DH
 	ret = crypto_register_kpp(&dh);
-	if (ret)
+	if (ret) {
 		crypto_unregister_akcipher(&rsa);
+		return ret;
+	}
 #endif
 
-	return ret;
+	if (qm->ver >= QM_HW_V3) {
+		ret = crypto_register_kpp(&ecdh);
+		if (ret) {
+#ifdef CONFIG_CRYPTO_DH
+			crypto_unregister_kpp(&dh);
+#endif
+			crypto_unregister_akcipher(&rsa);
+			return ret;
+		}
+	}
+
+	return 0;
 }
 
 void hpre_algs_unregister(struct hisi_qm *qm)
 {
-	crypto_unregister_akcipher(&rsa);
+	if (qm->ver >= QM_HW_V3)
+		crypto_unregister_kpp(&ecdh);
+
 #ifdef CONFIG_CRYPTO_DH
 	crypto_unregister_kpp(&dh);
 #endif
+	crypto_unregister_akcipher(&rsa);
 }
diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c
index 1ae8fa1..2ccc3dc 100644
--- a/drivers/crypto/hisilicon/hpre/hpre_main.c
+++ b/drivers/crypto/hisilicon/hpre/hpre_main.c
@@ -1020,4 +1020,5 @@  module_exit(hpre_exit);
 
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Zaibo Xu <xuzaibo@huawei.com>");
+MODULE_AUTHOR("Meng Yu <yumeng18@huawei.com>");
 MODULE_DESCRIPTION("Driver for HiSilicon HPRE accelerator");
diff --git a/include/crypto/ecc_curve_defs.h b/include/crypto/ecc_curve_defs.h
index 1080766..bf30338 100644
--- a/include/crypto/ecc_curve_defs.h
+++ b/include/crypto/ecc_curve_defs.h
@@ -37,6 +37,14 @@  struct ecc_curve {
 	u64 *b;
 };
 
+/* NIST P-128: a = p - 3 */
+static u64 nist_p128_g_x[] = { 0x0C28607CA52C5B86ull, 0x161FF7528B899B2Dull };
+static u64 nist_p128_g_y[] = { 0xc02da292dded7a83ull, 0xcf5ac8395bafeb13ull };
+static u64 nist_p128_p[] = { 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFDFFFFFFFFull };
+static u64 nist_p128_n[] = { 0x75A30D1B9038A115ull, 0xFFFFFFFE00000000ull };
+static u64 nist_p128_a[] = { 0xFFFFFFFFFFFFFFFCull, 0xFFFFFFFDFFFFFFFFull };
+static u64 nist_p128_b[] = { 0xD824993C2CEE5ED3ull, 0xE87579C11079F43Dull };
+
 /* NIST P-192: a = p - 3 */
 static u64 nist_p192_g_x[] = { 0xF4FF0AFD82FF1012ull, 0x7CBF20EB43A18800ull,
 				0x188DA80EB03090F6ull };
@@ -50,18 +58,20 @@  static u64 nist_p192_a[] = { 0xFFFFFFFFFFFFFFFCull, 0xFFFFFFFFFFFFFFFEull,
 				0xFFFFFFFFFFFFFFFFull };
 static u64 nist_p192_b[] = { 0xFEB8DEECC146B9B1ull, 0x0FA7E9AB72243049ull,
 				0x64210519E59C80E7ull };
-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,
-	.a = nist_p192_a,
-	.b = nist_p192_b
-};
+
+/* NIST P-224 */
+static u64 nist_p224_g_x[] = { 0x343280D6115C1D21ull, 0x4A03C1D356C21122ull,
+				0x6BB4BF7F321390B9ull, 0xB70E0CBDull };
+static u64 nist_p224_g_y[] = { 0x44d5819985007e34ull, 0xcd4375a05a074764ull,
+				0xb5f723fb4c22dfe6ull, 0xbd376388ull };
+static u64 nist_p224_p[] = { 0x0000000000000001ull, 0xFFFFFFFF00000000ull,
+				0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFull };
+static u64 nist_p224_n[] = { 0x13DD29455C5C2A3Dull, 0xFFFF16A2E0B8F03Eull,
+				0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFull };
+static u64 nist_p224_a[] = { 0xFFFFFFFFFFFFFFFEull, 0xFFFFFFFEFFFFFFFFull,
+				0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFull };
+static u64 nist_p224_b[] = { 0x270B39432355FFB4ull, 0x5044B0B7D7BFD8BAull,
+				0x0C04B3ABF5413256ull, 0xB4050A85ull };
 
 /* NIST P-256: a = p - 3 */
 static u64 nist_p256_g_x[] = { 0xF4A13945D898C296ull, 0x77037D812DEB33A0ull,
@@ -76,17 +86,159 @@  static u64 nist_p256_a[] = { 0xFFFFFFFFFFFFFFFCull, 0x00000000FFFFFFFFull,
 				0x0000000000000000ull, 0xFFFFFFFF00000001ull };
 static u64 nist_p256_b[] = { 0x3BCE3C3E27D2604Bull, 0x651D06B0CC53B0F6ull,
 				0xB3EBBD55769886BCull, 0x5AC635D8AA3A93E7ull };
-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,
-	.a = nist_p256_a,
-	.b = nist_p256_b
+
+/* NIST P-320 */
+static u64 nist_p320_g_x[] = { 0x10AF8D0D39E20611ull, 0xE7871E2A10A599C7ull,
+				0xF20137D10A087EB6ull, 0x5289BCC48EE5BFE6ull,
+				0x43BD7E9AFB53D8B8ull };
+static u64 nist_p320_g_y[] = { 0xD35245D1692E8EE1ull, 0xA9C77877AAAC6AC7ull,
+				0x0743FFED117182EAull, 0xAB4093247F77275Eull,
+				0x14FDD05545EC1CC8ull };
+static u64 nist_p320_p[] = { 0xFCD412B1F1B32E27ull, 0x4F92B9EC7893EC28ull,
+				0xF98FCFA6F6F40DEFull, 0xE13C785ED201E065ull,
+				0xD35E472036BC4FB7ull };
+static u64 nist_p320_n[] = { 0x8691555B44C59311ull, 0x2D482EC7EE8658E9ull,
+				0xF98FCFA5B68F12A3ull, 0xE13C785ED201E065ull,
+				0xD35E472036BC4FB7ull };
+static u64 nist_p320_a[] = { 0x92F375A97D860EB4ull, 0x66190EB085FFA9F4ull,
+				0xA2A73513F5EB79DAull, 0x83CCEBD46D3F3BB8ull,
+				0x3EE30B568FBAB0F8ull };
+static u64 nist_p320_b[] = { 0x6F5EB4AC8FB1F1A6ull, 0xCC31DCCD88453981ull,
+				0xE13F41349554B49Aull, 0xD3AD198640688A6Full,
+				0x520883949DFDBC42ull };
+
+/* NIST P-384 */
+static u64 nist_p384_g_x[] = { 0xEF87B2E247D4AF1Eull, 0xE826E03436D646AAull,
+				0xDB7FCAFE0CBD10E8ull, 0x8847A3E77EF14FE3ull,
+				0xA2A63A81B7C13F6Bull, 0x1D1C64F068CF45FFull };
+static u64 nist_p384_g_y[] = { 0x42820341263C5315ull, 0x0E46462177918111ull,
+				0xE19C054FF9912928ull, 0x62B70B29FEEC5864ull,
+				0x5CB1EB8E95CFD552ull, 0x8ABE1D7520F9C2A4ull };
+static u64 nist_p384_p[] = { 0x874700133107EC53ull, 0xACD3A729901D1A71ull,
+				0x12B1DA197FB71123ull, 0x152F7109ED5456B4ull,
+				0x0F5D6F7E50E641DFull, 0x8CB91E82A3386D28ull };
+static u64 nist_p384_n[] = { 0x3B883202E9046565ull, 0xCF3AB6AF6B7FC310ull,
+				0x1F166E6CAC0425A7ull, 0x152F7109ED5456B3ull,
+				0x0F5D6F7E50E641DFull, 0x8CB91E82A3386D28ull };
+static u64 nist_p384_a[] = { 0x04A8C7DD22CE2826ull, 0x8AA5814A503AD4EBull,
+				0x139165EFBA91F90Full, 0xC2BEA28E4FB22787ull,
+				0x3C72080ACE05AFA0ull, 0x7BC382C63D8C150Cull };
+static u64 nist_p384_b[] = { 0x3AB78696FA504C11ull, 0x7CB4390295DBC994ull,
+				0x2E880EA53EEB62D5ull, 0x2FB77DE107DCD2A6ull,
+				0x8B39B55416F0447Cull, 0x04A8C7DD22CE2826ull };
+
+/* NIST P-521: a = p - 3 */
+static u64 nist_p521_g_x[] = { 0xF97E7E31C2E5BD66ull, 0x3348B3C1856A429Bull,
+				0xFE1DC127A2FFA8DEull, 0xA14B5E77EFE75928ull,
+				0xF828AF606B4D3DBAull, 0x9C648139053FB521ull,
+				0x9E3ECB662395B442ull, 0x858E06B70404E9CDull,
+				0x00C6ull };
+static u64 nist_p521_g_y[] = { 0x88be94769fd16650ull, 0x353c7086a272c240ull,
+				0xc550b9013fad0761ull, 0x97ee72995ef42640ull,
+				0x17afbd17273e662cull, 0x98f54449579b4468ull,
+				0x5c8a5fb42c7d1bd9ull, 0x39296a789a3bc004ull,
+				0x0118ull };
+static u64 nist_p521_p[] = {0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
+				0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
+				0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
+				0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
+				0x01FFull };
+static u64 nist_p521_n[] = { 0xBB6FB71E91386409ull, 0x3BB5C9B8899C47AEull,
+				0x7FCC0148F709A5D0ull, 0x51868783BF2F966Bull,
+				0xFFFFFFFFFFFFFFFAull, 0xFFFFFFFFFFFFFFFFull,
+				0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
+				0x01FFull };
+static u64 nist_p521_a[] = { 0xFFFFFFFFFFFFFFFCull, 0xFFFFFFFFFFFFFFFFull,
+				0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
+				0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
+				0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
+				0x01FFull };
+static u64 nist_p521_b[] = { 0xEF451FD46B503F00ull, 0x3573DF883D2C34F1ull,
+				0x1652C0BD3BB1BF07ull, 0x56193951EC7E937Bull,
+				0xB8B489918EF109E1ull, 0xA2DA725B99B315F3ull,
+				0x929A21A0B68540EEull, 0x953EB9618E1C9A1Full,
+				0x0051ull };
+
+
+static const struct ecc_curve ecc_curve_list[] = {
+	{
+		.name = "nist_128",
+		.g = {
+			.x = nist_p128_g_x,
+			.y = nist_p128_g_y,
+			.ndigits = 2,
+		},
+		.p = nist_p128_p,
+		.n = nist_p128_n,
+		.a = nist_p128_a,
+		.b = nist_p128_b,
+	}, {
+		.name = "nist_192",
+		.g = {
+			.x = nist_p192_g_x,
+			.y = nist_p192_g_y,
+			.ndigits = 3,
+		},
+		.p = nist_p192_p,
+		.n = nist_p192_n,
+		.a = nist_p192_a,
+		.b = nist_p192_b,
+	}, {
+		.name = "nist_224",
+		.g = {
+			.x = nist_p224_g_x,
+			.y = nist_p224_g_y,
+			.ndigits = 4,
+		},
+		.p = nist_p224_p,
+		.n = nist_p224_n,
+		.a = nist_p224_a,
+		.b = nist_p224_b,
+	}, {
+		.name = "nist_256",
+		.g = {
+			.x = nist_p256_g_x,
+			.y = nist_p256_g_y,
+			.ndigits = 4,
+		},
+		.p = nist_p256_p,
+		.n = nist_p256_n,
+		.a = nist_p256_a,
+		.b = nist_p256_b,
+	}, {
+		.name = "nist_320",
+		.g = {
+			.x = nist_p320_g_x,
+			.y = nist_p320_g_y,
+			.ndigits = 5,
+		},
+		.p = nist_p320_p,
+		.n = nist_p320_n,
+		.a = nist_p320_a,
+		.b = nist_p320_b,
+	}, {
+		.name = "nist_384",
+		.g = {
+			.x = nist_p384_g_x,
+			.y = nist_p384_g_y,
+			.ndigits = 6,
+		},
+		.p = nist_p384_p,
+		.n = nist_p384_n,
+		.a = nist_p384_a,
+		.b = nist_p384_b,
+	}, {
+		.name = "nist_521",
+		.g = {
+			.x = nist_p521_g_x,
+			.y = nist_p521_g_y,
+			.ndigits = 9,
+		},
+		.p = nist_p521_p,
+		.n = nist_p521_n,
+		.a = nist_p521_a,
+		.b = nist_p521_b,
+	}
 };
 
 #endif
diff --git a/include/crypto/ecdh.h b/include/crypto/ecdh.h
index a5b805b..7d4fd3a 100644
--- a/include/crypto/ecdh.h
+++ b/include/crypto/ecdh.h
@@ -23,8 +23,13 @@ 
  */
 
 /* Curves IDs */
-#define ECC_CURVE_NIST_P192	0x0001
-#define ECC_CURVE_NIST_P256	0x0002
+#define ECC_CURVE_NIST_P128	0x0001
+#define ECC_CURVE_NIST_P192	0x0002
+#define ECC_CURVE_NIST_P224	0x0003
+#define ECC_CURVE_NIST_P256	0x0004
+#define ECC_CURVE_NIST_P320	0x0005
+#define ECC_CURVE_NIST_P384	0x0006
+#define ECC_CURVE_NIST_P521	0x0007
 
 /**
  * struct ecdh - define an ECDH private key