diff mbox

[V2] crypto: implement DH primitives under akcipher API

Message ID 1457007345-3412-1-git-send-email-salvatore.benedetto@intel.com (mailing list archive)
State Changes Requested
Delegated to: Herbert Xu
Headers show

Commit Message

Salvatore Benedetto March 3, 2016, 12:15 p.m. UTC
Implement Diffie-Hellman primitives required by the scheme under the
akcipher API. Here is how it works.
1) Call set_pub_key() by passing DH parameters (p,g) in PKCS3 format
2) Call set_priv_key() to set your own private key (xa) in raw format
3) Call decrypt() without passing any data as input to get back the
   public part which will be computed as g^xa mod p
4) Call encrypt() by passing the counter part public key (yb) in raw format
   as input to get back the shared secret calculated as zz = yb^xa mod p

A test is included in the patch. Test vector has been generated with
openssl

Signed-off-by: Salvatore Benedetto <salvatore.benedetto@intel.com>
---

Changes in V2:
 * Use dh_get_params where required
 * Use key lengths defined in RFC3526
 * Set fips_allowed=1 for the test

 crypto/Kconfig    |   8 ++
 crypto/Makefile   |   7 ++
 crypto/dh.c       | 264 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 crypto/pkcs3.asn1 |   5 ++
 crypto/tcrypt.c   |   4 +
 crypto/testmgr.c  | 141 +++++++++++++++++++++++++++--
 crypto/testmgr.h  | 208 +++++++++++++++++++++++++++++++++++++++++-
 7 files changed, 628 insertions(+), 9 deletions(-)
 create mode 100644 crypto/dh.c
 create mode 100644 crypto/pkcs3.asn1

Comments

Marcel Holtmann March 3, 2016, 4:23 p.m. UTC | #1
Hi Salvatore,

> Implement Diffie-Hellman primitives required by the scheme under the
> akcipher API. Here is how it works.
> 1) Call set_pub_key() by passing DH parameters (p,g) in PKCS3 format
> 2) Call set_priv_key() to set your own private key (xa) in raw format
> 3) Call decrypt() without passing any data as input to get back the
>   public part which will be computed as g^xa mod p
> 4) Call encrypt() by passing the counter part public key (yb) in raw format
>   as input to get back the shared secret calculated as zz = yb^xa mod p

I am still not convinced that akcipher is good match for key exchange methods. I think we should try to introduce a new abstraction here.

Overloading set_pub_key() with DH params and using decrypt() for private/public key pair generation seems not a good fit. It does not really match.

And as I said before, we know for certain that ECDH has to happen as well. So we need to forward look into making that fit as well.

Regards

Marcel

--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Herbert Xu April 5, 2016, 11:08 a.m. UTC | #2
On Thu, Mar 03, 2016 at 08:23:48AM -0800, Marcel Holtmann wrote:
> Hi Salvatore,
> 
> > Implement Diffie-Hellman primitives required by the scheme under the
> > akcipher API. Here is how it works.
> > 1) Call set_pub_key() by passing DH parameters (p,g) in PKCS3 format
> > 2) Call set_priv_key() to set your own private key (xa) in raw format
> > 3) Call decrypt() without passing any data as input to get back the
> >   public part which will be computed as g^xa mod p
> > 4) Call encrypt() by passing the counter part public key (yb) in raw format
> >   as input to get back the shared secret calculated as zz = yb^xa mod p
> 
> I am still not convinced that akcipher is good match for key exchange methods. I think we should try to introduce a new abstraction here.
> 
> Overloading set_pub_key() with DH params and using decrypt() for private/public key pair generation seems not a good fit. It does not really match.
> 
> And as I said before, we know for certain that ECDH has to happen as well. So we need to forward look into making that fit as well.

I agree that akcipher is poor choice for this.  If we are going
to add DH to the crypto API then it should be of its own type.

But before we even go there what does the hardware acceleration
actually look like?

Cheers,
Salvatore Benedetto April 8, 2016, 6:38 a.m. UTC | #3
Hi Herbert,

> -----Original Message-----
> From: Herbert Xu [mailto:herbert@gondor.apana.org.au]
> Sent: Tuesday, April 5, 2016 12:09 PM
> To: Marcel Holtmann <marcel@holtmann.org>
> Cc: Benedetto, Salvatore <salvatore.benedetto@intel.com>; linux-
> crypto@vger.kernel.org
> Subject: Re: [PATCH V2] crypto: implement DH primitives under akcipher API
> 
> On Thu, Mar 03, 2016 at 08:23:48AM -0800, Marcel Holtmann wrote:
> > Hi Salvatore,
> >
> > > Implement Diffie-Hellman primitives required by the scheme under the
> > > akcipher API. Here is how it works.
> > > 1) Call set_pub_key() by passing DH parameters (p,g) in PKCS3 format
> > > 2) Call set_priv_key() to set your own private key (xa) in raw
> > > format
> > > 3) Call decrypt() without passing any data as input to get back the
> > >   public part which will be computed as g^xa mod p
> > > 4) Call encrypt() by passing the counter part public key (yb) in raw format
> > >   as input to get back the shared secret calculated as zz = yb^xa
> > > mod p
> >
> > I am still not convinced that akcipher is good match for key exchange
> methods. I think we should try to introduce a new abstraction here.
> >
> > Overloading set_pub_key() with DH params and using decrypt() for
> private/public key pair generation seems not a good fit. It does not really
> match.
> >
> > And as I said before, we know for certain that ECDH has to happen as well.
> So we need to forward look into making that fit as well.
> 
> I agree that akcipher is poor choice for this.  If we are going to add DH to the
> crypto API then it should be of its own type.
> 
> But before we even go there what does the hardware acceleration actually
> look like?
>

I'm not sure what you mean by that, but in the case of DH, the hardware will
receive as input 3 buffers containing base, exponent and module, compute the
value and return it into the given output buffer. That's it. More or less the same
will be for ECDH.

Thanks,
Salvatore
--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/crypto/Kconfig b/crypto/Kconfig
index f6bfdda..fd5b78d 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -101,6 +101,14 @@  config CRYPTO_RSA
 	help
 	  Generic implementation of the RSA public key algorithm.
 
+config CRYPTO_DH
+	tristate "Diffie-Hellman algorithm"
+	select CRYPTO_AKCIPHER
+	select MPILIB
+	select ASN1
+	help
+	  Generic implementation of the Diffie-Hellman algorithm.
+
 config CRYPTO_MANAGER
 	tristate "Cryptographic algorithm manager"
 	select CRYPTO_MANAGER2
diff --git a/crypto/Makefile b/crypto/Makefile
index 4f4ef7e..ee73489 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -31,6 +31,13 @@  obj-$(CONFIG_CRYPTO_HASH2) += crypto_hash.o
 
 obj-$(CONFIG_CRYPTO_AKCIPHER2) += akcipher.o
 
+$(obj)/pkcs3-asn1.o: $(obj)/pkcs3-asn1.c $(obj)/pkcs3-asn1.h
+clean-files += pkcs3-asn1.c pkcs3-asn1.h
+
+dh_generic-y := pkcs3-asn1.o
+dh_generic-y += dh.o
+obj-$(CONFIG_CRYPTO_DH) += dh_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
 clean-files += rsapubkey-asn1.c rsapubkey-asn1.h
diff --git a/crypto/dh.c b/crypto/dh.c
new file mode 100644
index 0000000..29243ee
--- /dev/null
+++ b/crypto/dh.c
@@ -0,0 +1,264 @@ 
+/*  Diffie-Hellman Key Agreement Method [RFC2631]
+ *
+ * Copyright (c) 2016, Intel Corporation
+ * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <crypto/internal/akcipher.h>
+#include <crypto/akcipher.h>
+#include <crypto/algapi.h>
+#include <linux/mpi.h>
+#include "pkcs3-asn1.h"
+
+struct dh_params {
+	MPI p;
+	MPI g;
+	MPI xa;
+};
+
+int dh_get_g(void *context, size_t hdrlen, unsigned char tag, const void *value,
+	     size_t vlen)
+{
+	struct dh_params *params = context;
+
+	params->g = mpi_read_raw_data(value, vlen);
+
+	if (!params->g)
+		return -ENOMEM;
+
+	return 0;
+}
+
+int dh_get_p(void *context, size_t hdrlen, unsigned char tag, const void *value,
+	     size_t vlen)
+{
+	struct dh_params *params = context;
+
+	params->p = mpi_read_raw_data(value, vlen);
+
+	if (!params->p)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int dh_parse_params(struct dh_params *params, const void *key,
+			   unsigned int keylen)
+{
+	int ret;
+
+	mpi_free(params->p);
+	mpi_free(params->g);
+
+	ret = asn1_ber_decoder(&pkcs3_decoder, params, key, keylen);
+
+	return ret;
+}
+
+static void dh_free_params(struct dh_params *params)
+{
+	mpi_free(params->p);
+	mpi_free(params->g);
+	mpi_free(params->xa);
+	params->p = NULL;
+	params->g = NULL;
+	params->xa = NULL;
+}
+
+/*
+ * Public key generation function [RFC2631 sec 2.1.1]
+ * ya = g^xa mod p;
+ */
+static int _generate_public_key(const struct dh_params *params, MPI ya)
+{
+	/* ya = g^xa mod p */
+	return mpi_powm(ya, params->g, params->xa, params->p);
+}
+
+/*
+ * ZZ generation function [RFC2631 sec 2.1.1]
+ * ZZ = yb^xa mod p;
+ */
+static int _compute_shared_secret(const struct dh_params *params, MPI yb,
+				  MPI zz)
+{
+	/* ZZ = yb^xa mod p */
+	return mpi_powm(zz, yb, params->xa, params->p);
+}
+
+static inline struct dh_params *dh_get_params(struct crypto_akcipher *tfm)
+{
+	return akcipher_tfm_ctx(tfm);
+}
+
+static int dh_generate_public_key(struct akcipher_request *req)
+{
+	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+	const struct dh_params *params = dh_get_params(tfm);
+	MPI ya = mpi_alloc(0);
+	int ret = 0;
+	int sign;
+
+	if (!ya)
+		return -ENOMEM;
+
+	if (unlikely(!params->p || !params->g || !params->xa)) {
+		ret = -EINVAL;
+		goto err_free_ya;
+	}
+	ret = _generate_public_key(params, ya);
+	if (ret)
+		goto err_free_ya;
+
+	ret = mpi_write_to_sgl(ya, req->dst, &req->dst_len, &sign);
+	if (ret)
+		goto err_free_ya;
+
+	if (sign < 0)
+		ret = -EBADMSG;
+
+err_free_ya:
+	mpi_free(ya);
+	return ret;
+}
+
+static int dh_compute_shared_secret(struct akcipher_request *req)
+{
+	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+	struct dh_params *params = dh_get_params(tfm);
+	MPI yb, zz = mpi_alloc(0);
+	int ret = 0;
+	int sign;
+
+	if (!zz)
+		return -ENOMEM;
+
+	if (unlikely(!params->p || !params->xa)) {
+		ret = -EINVAL;
+		goto err_free_zz;
+	}
+
+	yb = mpi_read_raw_from_sgl(req->src, req->src_len);
+	if (!yb) {
+		ret = EINVAL;
+		goto err_free_zz;
+	}
+
+	ret = _compute_shared_secret(params, yb, zz);
+	if (ret)
+		goto err_free_yb;
+
+	ret = mpi_write_to_sgl(zz, req->dst, &req->dst_len, &sign);
+	if (ret)
+		goto err_free_yb;
+
+	if (sign < 0)
+		ret = -EBADMSG;
+
+err_free_yb:
+	mpi_free(yb);
+err_free_zz:
+	mpi_free(zz);
+	return ret;
+}
+
+static int dh_check_params_length(unsigned int p_len)
+{
+	switch (p_len) {
+	case 1536:
+	case 2048:
+	case 3072:
+	case 4096:
+	case 6144:
+	case 8192:
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int dh_no_op(struct akcipher_request *req)
+{
+	return -ENOPROTOOPT;
+}
+
+static int dh_set_priv_key(struct crypto_akcipher *tfm, const void *key,
+			   unsigned int keylen)
+{
+	struct dh_params *params = dh_get_params(tfm);
+
+	params->xa = mpi_read_raw_data(key, keylen);
+
+	if (!params->xa)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int dh_set_pub_key(struct crypto_akcipher *tfm, const void *key,
+			  unsigned int keylen)
+{
+	struct dh_params *params = dh_get_params(tfm);
+	int ret = 0;
+
+	ret = dh_parse_params(params, key, keylen);
+	if (ret)
+		return ret;
+	if (dh_check_params_length(mpi_get_size(params->p) << 3))
+		ret = -EINVAL;
+
+	return ret;
+}
+
+static int dh_max_size(struct crypto_akcipher *tfm)
+{
+	struct dh_params *params = dh_get_params(tfm);
+
+	return params->p ? mpi_get_size(params->p) : -EINVAL;
+}
+
+static void dh_exit_tfm(struct crypto_akcipher *tfm)
+{
+	struct dh_params *params = dh_get_params(tfm);
+
+	dh_free_params(params);
+}
+
+static struct akcipher_alg dh = {
+	.encrypt = dh_compute_shared_secret,
+	.decrypt = dh_generate_public_key,
+	.sign = dh_no_op,
+	.verify = dh_no_op,
+	.set_priv_key = dh_set_priv_key,
+	.set_pub_key = dh_set_pub_key,
+	.max_size = dh_max_size,
+	.exit = dh_exit_tfm,
+	.base = {
+		.cra_name = "dh",
+		.cra_driver_name = "dh-generic",
+		.cra_priority = 100,
+		.cra_module = THIS_MODULE,
+		.cra_ctxsize = sizeof(struct dh_params),
+	},
+};
+
+static int dh_init(void)
+{
+	return crypto_register_akcipher(&dh);
+}
+
+static void dh_exit(void)
+{
+	crypto_unregister_akcipher(&dh);
+}
+
+module_init(dh_init);
+module_exit(dh_exit);
+MODULE_ALIAS_CRYPTO("dh");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DH generic algorithm");
diff --git a/crypto/pkcs3.asn1 b/crypto/pkcs3.asn1
new file mode 100644
index 0000000..3d4ba5c
--- /dev/null
+++ b/crypto/pkcs3.asn1
@@ -0,0 +1,5 @@ 
+DHParameter ::= SEQUENCE {
+    prime               INTEGER ({ dh_get_p }),
+    base                INTEGER ({ dh_get_g }),
+    private_len         INTEGER OPTIONAL
+}
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index 579dce0..53c45f7 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -1981,6 +1981,10 @@  static int do_test(const char *alg, u32 type, u32 mask, int m)
 				   speed_template_8_32);
 		break;
 
+	case 600:
+		ret += tcrypt_test("dh");
+		break;
+
 	case 1000:
 		test_available();
 		break;
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index b86883a..2e0dc93 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -112,7 +112,7 @@  struct drbg_test_suite {
 };
 
 struct akcipher_test_suite {
-	struct akcipher_testvec *vecs;
+	struct akcipher_testvec vecs;
 	unsigned int count;
 };
 
@@ -1773,8 +1773,113 @@  static int alg_test_drbg(const struct alg_test_desc *desc, const char *driver,
 
 }
 
+static int do_test_dh(struct crypto_akcipher *tfm,
+		      struct akcipher_testvec_dh *vec)
+{
+	struct akcipher_request *req;
+	void *input_buf = NULL;
+	void *output_buf = NULL;
+	struct tcrypt_result result;
+	unsigned int out_len_max;
+	int err = -ENOMEM;
+	struct scatterlist src, dst;
+
+	req = akcipher_request_alloc(tfm, GFP_KERNEL);
+	if (!req)
+		return err;
+
+	init_completion(&result.completion);
+
+	/* Set p,g */
+	err = crypto_akcipher_set_pub_key(tfm, vec->pkcs3, vec->pkcs3_size);
+	if (err)
+		goto free_req;
+
+	/* Set A private Key */
+	err = crypto_akcipher_set_priv_key(tfm, vec->priv_key_A, vec->key_len);
+	if (err)
+		goto free_req;
+
+	out_len_max = crypto_akcipher_maxsize(tfm);
+	output_buf = kzalloc(out_len_max, GFP_KERNEL);
+	if (!output_buf) {
+		err = -ENOMEM;
+		goto free_req;
+	}
+
+	sg_init_one(&dst, output_buf, out_len_max);
+	akcipher_request_set_crypt(req, NULL, &dst, 0, out_len_max);
+	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				      tcrypt_complete, &result);
+
+	/* Compute A public key = g^xa mod p */
+	err = wait_async_op(&result, crypto_akcipher_decrypt(req));
+	if (err) {
+		pr_err("alg: dh: decrypt test failed. err %d\n", err);
+		goto free_output;
+	}
+	/* Verify calculated public key */
+	if (memcmp(vec->expected_pub_key_A, sg_virt(req->dst), vec->key_len)) {
+		pr_err("alg: dh: decrypt test failed. Invalid output\n");
+		err = -EINVAL;
+		goto free_output;
+	}
+
+	/* Calculate shared secret key by using counter part public key. */
+	input_buf = kzalloc(vec->key_len, GFP_KERNEL);
+	if (!input_buf) {
+		err = -ENOMEM;
+		goto free_output;
+	}
+
+	memcpy(input_buf, vec->pub_key_B, vec->key_len);
+	sg_init_one(&src, input_buf, vec->key_len);
+	sg_init_one(&dst, output_buf, out_len_max);
+	akcipher_request_set_crypt(req, &src, &dst, vec->key_len, out_len_max);
+	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				      tcrypt_complete, &result);
+	err = wait_async_op(&result, crypto_akcipher_encrypt(req));
+	if (err) {
+		pr_err("alg: dh: encrypt test failed. err %d\n", err);
+		goto free_all;
+	}
+	/*
+	 * verify shared secret from which the user will derive
+	 * secret key by executing whatever hash it has chosen
+	 */
+	if (memcmp(vec->expected_shared_secret, sg_virt(req->dst),
+		   vec->key_len)) {
+		pr_err("alg: dh: encrypt test failed. Invalid output\n");
+		err = -EINVAL;
+	}
+
+free_all:
+	kfree(input_buf);
+free_output:
+	kfree(output_buf);
+free_req:
+	akcipher_request_free(req);
+	return err;
+}
+
+static int test_dh(struct crypto_akcipher *tfm,
+		   struct akcipher_testvec_dh *vecs, unsigned int tcount)
+{
+	int ret, i;
+
+	for (i = 0; i < tcount; i++) {
+		ret = do_test_dh(tfm, vecs++);
+		if (ret) {
+			pr_err("alg: dh: test failed on vector %d, err=%d\n",
+			       i + 1, ret);
+			return ret;
+		}
+	}
+	return 0;
+}
+
 static int do_test_rsa(struct crypto_akcipher *tfm,
-		       struct akcipher_testvec *vecs)
+		       struct akcipher_testvec_rsa *vecs)
 {
 	struct akcipher_request *req;
 	void *outbuf_enc = NULL;
@@ -1870,7 +1975,8 @@  free_req:
 	return err;
 }
 
-static int test_rsa(struct crypto_akcipher *tfm, struct akcipher_testvec *vecs,
+static int test_rsa(struct crypto_akcipher *tfm,
+		    struct akcipher_testvec_rsa *vecs,
 		    unsigned int tcount)
 {
 	int ret, i;
@@ -1890,7 +1996,9 @@  static int test_akcipher(struct crypto_akcipher *tfm, const char *alg,
 			 struct akcipher_testvec *vecs, unsigned int tcount)
 {
 	if (strncmp(alg, "rsa", 3) == 0)
-		return test_rsa(tfm, vecs, tcount);
+		return test_rsa(tfm, vecs->a.rsa, tcount);
+	else if (strncmp(alg, "dh", 3) == 0)
+		return test_dh(tfm, vecs->a.dh, tcount);
 
 	return 0;
 }
@@ -1907,8 +2015,9 @@  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,
+	if (desc->suite.akcipher.vecs.a.rsa)
+		err = test_akcipher(tfm, desc->alg,
+				    &desc->suite.akcipher.vecs,
 				    desc->suite.akcipher.count);
 
 	crypto_free_akcipher(tfm);
@@ -2708,6 +2817,20 @@  static const struct alg_test_desc alg_test_descs[] = {
 			}
 		}
 	}, {
+		.alg = "dh",
+		.test = alg_test_akcipher,
+		.fips_allowed = 1,
+		.suite = {
+			.akcipher = {
+				.vecs = {
+					.a = {
+						.dh = dh_tv_template
+					},
+				},
+				.count = DH_TEST_VECTORS
+			}
+		}
+	}, {
 		.alg = "digest_null",
 		.test = alg_test_null,
 	}, {
@@ -3592,7 +3715,11 @@  static const struct alg_test_desc alg_test_descs[] = {
 		.fips_allowed = 1,
 		.suite = {
 			.akcipher = {
-				.vecs = rsa_tv_template,
+				.vecs = {
+					.a = {
+						.rsa = rsa_tv_template
+					},
+				},
 				.count = RSA_TEST_VECTORS
 			}
 		}
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 487ec88..ba08ed6 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -123,7 +123,7 @@  struct drbg_testvec {
 	size_t expectedlen;
 };
 
-struct akcipher_testvec {
+struct akcipher_testvec_rsa {
 	unsigned char *key;
 	unsigned char *m;
 	unsigned char *c;
@@ -133,6 +133,23 @@  struct akcipher_testvec {
 	bool public_key_vec;
 };
 
+struct akcipher_testvec_dh {
+	unsigned char *pkcs3;
+	unsigned pkcs3_size;
+	unsigned char *priv_key_A;
+	unsigned char *pub_key_B;
+	unsigned char *expected_pub_key_A;
+	unsigned char *expected_shared_secret;
+	unsigned key_len;
+};
+
+struct akcipher_testvec {
+	union {
+		struct akcipher_testvec_rsa *rsa;
+		struct akcipher_testvec_dh *dh;
+	} a;
+};
+
 static char zeroed_string[48];
 
 /*
@@ -143,7 +160,7 @@  static char zeroed_string[48];
 #else
 #define RSA_TEST_VECTORS	4
 #endif
-static struct akcipher_testvec rsa_tv_template[] = {
+static struct akcipher_testvec_rsa rsa_tv_template[] = {
 	{
 #ifndef CONFIG_CRYPTO_FIPS
 	.key =
@@ -330,6 +347,193 @@  static struct akcipher_testvec rsa_tv_template[] = {
 	}
 };
 
+#define DH_TEST_VECTORS 2
+
+struct akcipher_testvec_dh dh_tv_template[] = {
+	{
+	/* p, g */
+	.pkcs3 =
+	"\x30\x82\x01\x08\x02\x82\x01\x01\x00\x9f\xab\x7c\xc2\x50\xa7\xdc"
+	"\x3c\x17\x2a\x5b\x9f\x76\x17\x8e\x92\xa6\xb0\x13\x1e\x6e\x7b\x9a"
+	"\x6b\x8d\x06\xcf\x9f\x90\xb8\x21\x6a\x30\x04\xe8\xda\xc0\x13\x27"
+	"\xc8\x40\xbf\x6c\x84\x1e\xe2\x9e\xf9\xd2\x48\x11\xc7\x06\xd3\x06"
+	"\xb8\xaa\xbe\x69\x3f\xf2\x60\x06\xa0\xd1\x55\x03\x63\xa1\xfd\x33"
+	"\x2c\x04\xe4\xf0\xe6\x02\x8a\x97\x1e\x22\x4f\x2b\x73\x15\x23\xa5"
+	"\x26\x97\xd6\x91\x11\xd8\x80\x35\xe7\x7f\x19\x29\x6c\x59\x64\x24"
+	"\x68\xc0\x40\x66\x5d\xa8\xcb\xda\x84\xce\xbc\xf7\x1b\x68\x81\xac"
+	"\xec\xe9\x84\xc1\x46\xef\xac\xe2\xb2\x85\xf2\x92\x06\x82\xbe\xe7"
+	"\x12\x53\x21\xfc\xc5\x82\xe5\xe3\x7f\x26\xe5\x53\x02\x58\xb1\xa9"
+	"\x26\x32\x5f\xb9\xa6\x23\x1d\xd8\x26\xda\x7a\x67\xab\x8a\x84\x97"
+	"\x2e\x78\xc1\x6d\xec\x67\x50\x27\x2d\x52\xf7\x67\xec\x5b\x2c\x9f"
+	"\x17\xb7\x81\xec\x47\x60\x65\xf5\x86\x20\x4f\x82\x84\xd9\xee\x62"
+	"\x6f\x49\x7d\x80\x9e\xaa\x8a\x7a\x82\x45\x65\x36\x0b\xf1\xfe\x01"
+	"\x06\x52\x3c\xa1\xdf\xc8\x84\x89\xb0\xee\xb6\xfa\x95\x12\x42\xb9"
+	"\x87\x53\x77\x1c\xe0\x56\x25\xf6\x96\x31\xec\x62\x82\x77\xb7\x52"
+	"\xac\x25\x71\x49\x97\x13\x83\x23\x63\x02\x01\x02",
+	.pkcs3_size = 268,
+	.priv_key_A =
+	"\x48\xed\x07\x3d\x49\x20\xf8\xa5\xcf\x90\xcd\xf9\x97\x63\xd2\x51"
+	"\x3d\xac\xbd\x2d\x49\x4a\xb8\x87\x06\x62\xd2\x0c\x13\x55\x73\x77"
+	"\x97\x15\xd3\x23\x8a\x3b\x3e\xb9\x14\xa6\xfb\x20\x7b\xd1\xea\x68"
+	"\x85\x9a\xc6\x8f\x66\x9a\x78\xf0\x26\xce\x8c\xe0\x66\x4e\x51\xc9"
+	"\xf5\xf9\x89\xc6\x0a\xc5\x4b\x99\xdc\xb0\x36\x3e\xf2\xc7\x7f\x52"
+	"\x60\x99\x12\xbd\x8f\x85\x7b\x0a\x99\xa9\x85\x21\xc6\x50\x66\xf6"
+	"\xde\x62\xc4\x08\x3f\x8c\x97\x91\xb0\x19\x72\x2a\x56\xc6\x85\x12"
+	"\x8e\x89\x65\xa7\x13\x34\x51\x53\x2e\xe0\x07\x6c\x01\xaa\xb1\x23"
+	"\x42\x54\xa5\x49\xfd\x01\x2a\xd8\xa7\xc3\xd6\x6a\x6f\x3c\x76\xc4"
+	"\x4b\x37\x55\x30\xb7\xbe\xb7\x87\x4e\x43\x68\x37\xd8\xa0\x6f\x53"
+	"\x59\xb6\x25\xd4\x44\xc9\x43\xcd\xb1\x20\x8c\xf9\x3a\xd5\xbc\x97"
+	"\x70\x8e\xad\x1a\x8b\x69\xbd\xae\xf9\xd0\x48\x70\x40\x4d\x3f\xdc"
+	"\xea\x10\xef\x61\x49\x1b\x87\x10\xff\x96\x36\x73\x4f\x75\xf5\x75"
+	"\x23\xbb\x5e\x48\xe8\x96\x57\xcf\x33\x76\x78\x2e\x86\x90\x5c\x2c"
+	"\x17\xe6\x70\x8a\x6c\x0c\x0d\xa8\x3e\x79\xa6\x9e\xe1\xbf\x18\x40"
+	"\xeb\x2c\x1a\xb9\x14\xf5\x02\xeb\x37\x66\x06\x1c\xe8\xb5\x75\x0d",
+	.pub_key_B =
+	"\x18\xd9\x78\xdd\x6a\xc9\x19\x4e\xe6\xa0\x83\xcc\x12\x00\x3b\x6c"
+	"\x4c\x8c\x11\x38\x94\x90\xd7\xc4\x1f\xa6\x64\x04\x35\x4a\xda\x48"
+	"\x5a\xeb\x38\xe7\xae\x44\x16\x4a\x94\xfe\x7c\xa9\x00\xff\x67\x20"
+	"\x4c\xef\x34\x45\xfe\x2d\xf5\xa9\xfb\xa8\xc0\x45\x09\xcd\xcd\xc0"
+	"\x4c\x20\xc0\x1e\x42\x41\x4b\x37\x6c\x90\xba\xef\xd6\x65\xab\xb1"
+	"\xec\x51\x30\xfa\x08\xfc\x22\xc6\x42\xce\x6a\x90\xb7\x27\xe4\x52"
+	"\x76\x28\x78\x17\x56\x71\x73\xeb\xaf\x6e\xbb\x61\x7a\x6b\x4b\xdb"
+	"\x8e\x2f\xaa\xfa\x9e\x40\xee\x84\xf6\x63\x9b\xb7\xe2\x22\x72\x6b"
+	"\x94\x58\x3f\x08\xa5\xbe\xd6\x87\x63\xe7\xbb\x5a\xfb\x52\x92\xd2"
+	"\xe6\x5e\x7e\x55\x78\x4b\xc0\x0e\x1a\xe5\xe6\x0f\x0e\x41\xd5\x05"
+	"\xb7\x71\x42\x78\x35\x74\xad\x33\x9f\x24\xc0\x3b\x09\xd5\xcf\x4d"
+	"\x6e\x20\x3a\xee\x04\x9f\x05\x2d\x8d\x77\x06\x2d\x9b\x67\xba\x39"
+	"\x2f\x6c\x1d\x7b\x75\x57\xed\x2f\xe2\xf1\xbc\x0b\x3a\x77\xf2\xba"
+	"\xb2\xb1\x98\x52\x34\x40\x53\x7b\x0e\xb6\x13\x6a\x5b\x91\xe4\x59"
+	"\x67\x2c\x45\x3a\x07\x1a\xa2\x3b\xdb\xa1\xa6\x08\xf0\x80\xe8\x61"
+	"\xca\xac\x95\xb3\x3e\xd6\x97\x98\x08\x7e\x50\x48\xc0\x25\x45\xd0",
+	.expected_pub_key_A =
+	"\x91\x9e\x52\xa3\xb8\x20\x25\x12\x17\xcc\x37\x82\x81\x22\x14\x7a"
+	"\x81\x88\xce\x9f\xf2\x46\xb1\x17\xaf\x41\x23\xc9\xb8\x93\x40\xfd"
+	"\xa9\x96\x05\x5a\x1a\xcc\xa6\x51\xe2\x9e\xca\x63\x2a\x67\x72\x4a"
+	"\xe1\x2b\xa7\xbe\xf9\xeb\x69\xc8\x2d\x29\xb6\x6b\x5f\xc0\xf2\x90"
+	"\xa9\x36\x49\xdb\xcc\x6b\x5e\xed\x76\x47\x9f\xc9\x2e\x91\x68\x75"
+	"\xa3\x39\x6c\x50\xa6\xaf\x81\xac\x23\x58\xa9\xc9\x71\xf3\x87\x97"
+	"\xef\x0c\x80\x19\xac\xb7\xf0\xa0\x83\x44\x4b\x1c\x08\xf1\x4f\x23"
+	"\xfb\xf1\x61\x39\x00\x59\xef\x83\xa5\xaf\x2f\x3f\xc0\x19\x2a\x5b"
+	"\x22\x53\xdb\x8b\x24\xbc\xe4\xaa\x9a\x19\x6b\xfd\x20\xbf\x1a\xe2"
+	"\xb5\xaf\x82\x3e\xb8\xea\xe7\x28\xcd\xad\xfe\x00\xee\x70\x52\x46"
+	"\x3d\x2c\x55\x81\x44\xed\x15\x21\xc8\x48\x75\x4d\x6f\xf0\xba\xe9"
+	"\xab\x4c\x65\xf3\x54\x2e\x74\xd9\xe7\xe2\xb7\xad\xec\x6d\xb2\x6e"
+	"\xc1\xe3\x2d\x0e\xb1\x18\x36\xd7\xb9\x42\x6b\x2f\xc9\x51\x2e\xff"
+	"\x5d\xd0\xca\x8c\x0d\x0d\x95\xd3\x16\xf3\xdb\xc1\x2b\xed\x00\x32"
+	"\xd7\x77\xb8\x0e\x86\x7a\x57\x48\x74\x23\x30\xae\xe0\x3c\x38\xa6"
+	"\xed\xf9\x0c\x16\xf2\xf2\xa0\xe0\x51\x80\x67\x92\xe4\xc7\x9a\x5e",
+	.expected_shared_secret =
+	"\x1d\x7d\x2e\x47\x06\xbe\x46\xd3\x69\xf6\xe7\x0e\x88\xdc\xe8\xe1"
+	"\xe6\x6a\xfc\x3c\xbc\xc1\x85\xe9\x24\xf0\x7b\x75\x0f\xa4\x04\xd6"
+	"\x9b\xef\x7b\x30\x55\xde\xbf\xd4\xb2\xcb\xce\x74\x53\xae\x72\x34"
+	"\x19\x36\x9e\xe9\x45\xb8\xda\x59\x22\x41\x9e\xa3\x8f\x02\xaa\x60"
+	"\xb1\x8b\xf9\x84\xd4\x8a\xeb\xea\xd1\xd9\x1a\x53\xe9\x5f\x01\xd1"
+	"\x40\xb4\x73\x63\xc5\x1a\x79\xf1\x08\xb6\xc0\x0c\x85\x9e\x3e\x70"
+	"\xea\x79\xd9\xc2\x5b\x17\xa7\x1e\xeb\x58\x3e\x1b\xca\x7a\x4d\xab"
+	"\x61\x5b\xdf\xa2\x6f\x1e\xd4\x36\xeb\xe3\xe9\x04\x10\x8e\x0b\xc9"
+	"\x18\x8c\x0d\x6e\x4f\x2e\xc5\xfc\x5b\x6a\xb5\x9f\xdf\x71\x50\x04"
+	"\x54\x62\x49\x57\xf3\xc6\x9e\x39\xc6\x56\xf1\x2d\x31\x59\x58\xdb"
+	"\x67\x94\x25\xbd\x47\xe2\xdd\x95\x0c\x39\xb1\xfa\x22\xc6\x94\xc4"
+	"\x75\xab\xff\xe2\xce\x52\xa2\xeb\x78\x26\x10\x0f\x2d\x8c\xf2\xad"
+	"\xd2\xc7\xaf\x85\xd9\x5c\x71\xfe\x9e\xe9\xeb\xbf\x20\x36\x1e\x9a"
+	"\x74\x43\xe6\x06\x00\x8a\x4d\x64\x41\x2a\x15\x6d\x60\x44\x3f\x2c"
+	"\xcd\x05\x16\x54\x6a\x48\x7c\x71\x0a\xe9\x33\x95\x16\xc7\xf4\x23"
+	"\xc2\x8d\xed\x8a\x24\x5d\x99\xc7\x8c\x8b\x07\x47\x8c\xe9\x0c\x10",
+	.key_len = 256
+	},
+	{
+	/* p, g */
+	.pkcs3 =
+	"\x30\x82\x01\x08\x02\x82\x01\x01\x00\x9f\xab\x7c\xc2\x50\xa7\xdc"
+	"\x3c\x17\x2a\x5b\x9f\x76\x17\x8e\x92\xa6\xb0\x13\x1e\x6e\x7b\x9a"
+	"\x6b\x8d\x06\xcf\x9f\x90\xb8\x21\x6a\x30\x04\xe8\xda\xc0\x13\x27"
+	"\xc8\x40\xbf\x6c\x84\x1e\xe2\x9e\xf9\xd2\x48\x11\xc7\x06\xd3\x06"
+	"\xb8\xaa\xbe\x69\x3f\xf2\x60\x06\xa0\xd1\x55\x03\x63\xa1\xfd\x33"
+	"\x2c\x04\xe4\xf0\xe6\x02\x8a\x97\x1e\x22\x4f\x2b\x73\x15\x23\xa5"
+	"\x26\x97\xd6\x91\x11\xd8\x80\x35\xe7\x7f\x19\x29\x6c\x59\x64\x24"
+	"\x68\xc0\x40\x66\x5d\xa8\xcb\xda\x84\xce\xbc\xf7\x1b\x68\x81\xac"
+	"\xec\xe9\x84\xc1\x46\xef\xac\xe2\xb2\x85\xf2\x92\x06\x82\xbe\xe7"
+	"\x12\x53\x21\xfc\xc5\x82\xe5\xe3\x7f\x26\xe5\x53\x02\x58\xb1\xa9"
+	"\x26\x32\x5f\xb9\xa6\x23\x1d\xd8\x26\xda\x7a\x67\xab\x8a\x84\x97"
+	"\x2e\x78\xc1\x6d\xec\x67\x50\x27\x2d\x52\xf7\x67\xec\x5b\x2c\x9f"
+	"\x17\xb7\x81\xec\x47\x60\x65\xf5\x86\x20\x4f\x82\x84\xd9\xee\x62"
+	"\x6f\x49\x7d\x80\x9e\xaa\x8a\x7a\x82\x45\x65\x36\x0b\xf1\xfe\x01"
+	"\x06\x52\x3c\xa1\xdf\xc8\x84\x89\xb0\xee\xb6\xfa\x95\x12\x42\xb9"
+	"\x87\x53\x77\x1c\xe0\x56\x25\xf6\x96\x31\xec\x62\x82\x77\xb7\x52"
+	"\xac\x25\x71\x49\x97\x13\x83\x23\x63\x02\x01\x02",
+	.pkcs3_size = 268,
+	.priv_key_A =
+	"\x7d\xfb\xa2\x51\x24\xa4\xfa\x65\x35\x1c\x3b\xef\x3f\x6b\x10\x27"
+	"\xde\x30\xcb\x2c\xa7\x5b\xfe\x1a\xec\x5f\x2b\x1c\x7b\xd8\xa7\xfd"
+	"\x37\x15\xec\x62\xbd\x64\x71\x57\x31\x48\xcc\x8c\xd9\x6f\xe9\x24"
+	"\x9d\x63\xff\x1f\xb6\x7d\xf7\x30\x23\x13\xdc\x0f\x27\xd9\x6e\x11"
+	"\x8b\x54\x80\xe4\x35\x52\x98\x5c\xac\x87\x56\xdf\x5e\xe2\xbe\x08"
+	"\x63\xfd\xb2\xe4\x06\x2b\x04\x68\xf6\x3a\x45\x3b\xb0\xf1\x81\x32"
+	"\x36\xa3\xde\xe4\xe7\xec\x8b\x87\x32\x09\x45\x87\x1c\x1c\x0e\x84"
+	"\xf7\x30\x09\x7d\x7f\x98\xf5\xbe\x92\x50\xbd\xa8\xc2\x35\x11\xe3"
+	"\x0a\xf2\x90\x1a\x18\xcb\x5a\xe5\x4e\x4a\x93\x3d\x6d\x26\xa6\x36"
+	"\x79\x45\x75\x12\xb4\x27\x95\xcd\x9e\x6b\x37\x57\x4d\x69\x21\xa9"
+	"\xff\x5d\xe2\xf2\xf8\x4f\xeb\x50\x79\xa4\xa7\x87\x59\x78\x23\xfa"
+	"\x67\xb5\xdc\x6e\xa6\x59\x81\xba\x65\x8e\x65\xfc\x7f\x51\xc8\xad"
+	"\x1d\x28\x50\x60\x92\x2a\xcc\x9c\x47\xc7\x13\xd2\xf4\xb8\xa2\xab"
+	"\x2c\x50\x4c\xf1\xcd\xef\xb7\x94\x1c\xe7\xd3\x2a\x55\x37\xff\xfa"
+	"\x6d\xe8\x43\x01\xb0\x9b\x24\x5d\xd4\x57\x7d\xb5\x30\xaa\x60\x97"
+	"\x33\xfe\xe7\x31\x39\x96\xe6\xb3\xf4\x11\xde\x3c\x57\x4b\xcb\xad",
+	.pub_key_B =
+	"\x91\x9e\x52\xa3\xb8\x20\x25\x12\x17\xcc\x37\x82\x81\x22\x14\x7a"
+	"\x81\x88\xce\x9f\xf2\x46\xb1\x17\xaf\x41\x23\xc9\xb8\x93\x40\xfd"
+	"\xa9\x96\x05\x5a\x1a\xcc\xa6\x51\xe2\x9e\xca\x63\x2a\x67\x72\x4a"
+	"\xe1\x2b\xa7\xbe\xf9\xeb\x69\xc8\x2d\x29\xb6\x6b\x5f\xc0\xf2\x90"
+	"\xa9\x36\x49\xdb\xcc\x6b\x5e\xed\x76\x47\x9f\xc9\x2e\x91\x68\x75"
+	"\xa3\x39\x6c\x50\xa6\xaf\x81\xac\x23\x58\xa9\xc9\x71\xf3\x87\x97"
+	"\xef\x0c\x80\x19\xac\xb7\xf0\xa0\x83\x44\x4b\x1c\x08\xf1\x4f\x23"
+	"\xfb\xf1\x61\x39\x00\x59\xef\x83\xa5\xaf\x2f\x3f\xc0\x19\x2a\x5b"
+	"\x22\x53\xdb\x8b\x24\xbc\xe4\xaa\x9a\x19\x6b\xfd\x20\xbf\x1a\xe2"
+	"\xb5\xaf\x82\x3e\xb8\xea\xe7\x28\xcd\xad\xfe\x00\xee\x70\x52\x46"
+	"\x3d\x2c\x55\x81\x44\xed\x15\x21\xc8\x48\x75\x4d\x6f\xf0\xba\xe9"
+	"\xab\x4c\x65\xf3\x54\x2e\x74\xd9\xe7\xe2\xb7\xad\xec\x6d\xb2\x6e"
+	"\xc1\xe3\x2d\x0e\xb1\x18\x36\xd7\xb9\x42\x6b\x2f\xc9\x51\x2e\xff"
+	"\x5d\xd0\xca\x8c\x0d\x0d\x95\xd3\x16\xf3\xdb\xc1\x2b\xed\x00\x32"
+	"\xd7\x77\xb8\x0e\x86\x7a\x57\x48\x74\x23\x30\xae\xe0\x3c\x38\xa6"
+	"\xed\xf9\x0c\x16\xf2\xf2\xa0\xe0\x51\x80\x67\x92\xe4\xc7\x9a\x5e",
+	.expected_pub_key_A =
+	"\x18\xd9\x78\xdd\x6a\xc9\x19\x4e\xe6\xa0\x83\xcc\x12\x00\x3b\x6c"
+	"\x4c\x8c\x11\x38\x94\x90\xd7\xc4\x1f\xa6\x64\x04\x35\x4a\xda\x48"
+	"\x5a\xeb\x38\xe7\xae\x44\x16\x4a\x94\xfe\x7c\xa9\x00\xff\x67\x20"
+	"\x4c\xef\x34\x45\xfe\x2d\xf5\xa9\xfb\xa8\xc0\x45\x09\xcd\xcd\xc0"
+	"\x4c\x20\xc0\x1e\x42\x41\x4b\x37\x6c\x90\xba\xef\xd6\x65\xab\xb1"
+	"\xec\x51\x30\xfa\x08\xfc\x22\xc6\x42\xce\x6a\x90\xb7\x27\xe4\x52"
+	"\x76\x28\x78\x17\x56\x71\x73\xeb\xaf\x6e\xbb\x61\x7a\x6b\x4b\xdb"
+	"\x8e\x2f\xaa\xfa\x9e\x40\xee\x84\xf6\x63\x9b\xb7\xe2\x22\x72\x6b"
+	"\x94\x58\x3f\x08\xa5\xbe\xd6\x87\x63\xe7\xbb\x5a\xfb\x52\x92\xd2"
+	"\xe6\x5e\x7e\x55\x78\x4b\xc0\x0e\x1a\xe5\xe6\x0f\x0e\x41\xd5\x05"
+	"\xb7\x71\x42\x78\x35\x74\xad\x33\x9f\x24\xc0\x3b\x09\xd5\xcf\x4d"
+	"\x6e\x20\x3a\xee\x04\x9f\x05\x2d\x8d\x77\x06\x2d\x9b\x67\xba\x39"
+	"\x2f\x6c\x1d\x7b\x75\x57\xed\x2f\xe2\xf1\xbc\x0b\x3a\x77\xf2\xba"
+	"\xb2\xb1\x98\x52\x34\x40\x53\x7b\x0e\xb6\x13\x6a\x5b\x91\xe4\x59"
+	"\x67\x2c\x45\x3a\x07\x1a\xa2\x3b\xdb\xa1\xa6\x08\xf0\x80\xe8\x61"
+	"\xca\xac\x95\xb3\x3e\xd6\x97\x98\x08\x7e\x50\x48\xc0\x25\x45\xd0",
+	.expected_shared_secret =
+	"\x1d\x7d\x2e\x47\x06\xbe\x46\xd3\x69\xf6\xe7\x0e\x88\xdc\xe8\xe1"
+	"\xe6\x6a\xfc\x3c\xbc\xc1\x85\xe9\x24\xf0\x7b\x75\x0f\xa4\x04\xd6"
+	"\x9b\xef\x7b\x30\x55\xde\xbf\xd4\xb2\xcb\xce\x74\x53\xae\x72\x34"
+	"\x19\x36\x9e\xe9\x45\xb8\xda\x59\x22\x41\x9e\xa3\x8f\x02\xaa\x60"
+	"\xb1\x8b\xf9\x84\xd4\x8a\xeb\xea\xd1\xd9\x1a\x53\xe9\x5f\x01\xd1"
+	"\x40\xb4\x73\x63\xc5\x1a\x79\xf1\x08\xb6\xc0\x0c\x85\x9e\x3e\x70"
+	"\xea\x79\xd9\xc2\x5b\x17\xa7\x1e\xeb\x58\x3e\x1b\xca\x7a\x4d\xab"
+	"\x61\x5b\xdf\xa2\x6f\x1e\xd4\x36\xeb\xe3\xe9\x04\x10\x8e\x0b\xc9"
+	"\x18\x8c\x0d\x6e\x4f\x2e\xc5\xfc\x5b\x6a\xb5\x9f\xdf\x71\x50\x04"
+	"\x54\x62\x49\x57\xf3\xc6\x9e\x39\xc6\x56\xf1\x2d\x31\x59\x58\xdb"
+	"\x67\x94\x25\xbd\x47\xe2\xdd\x95\x0c\x39\xb1\xfa\x22\xc6\x94\xc4"
+	"\x75\xab\xff\xe2\xce\x52\xa2\xeb\x78\x26\x10\x0f\x2d\x8c\xf2\xad"
+	"\xd2\xc7\xaf\x85\xd9\x5c\x71\xfe\x9e\xe9\xeb\xbf\x20\x36\x1e\x9a"
+	"\x74\x43\xe6\x06\x00\x8a\x4d\x64\x41\x2a\x15\x6d\x60\x44\x3f\x2c"
+	"\xcd\x05\x16\x54\x6a\x48\x7c\x71\x0a\xe9\x33\x95\x16\xc7\xf4\x23"
+	"\xc2\x8d\xed\x8a\x24\x5d\x99\xc7\x8c\x8b\x07\x47\x8c\xe9\x0c\x10",
+	.key_len = 256
+	}
+};
+
 /*
  * MD4 test vectors from RFC1320
  */