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..614c4f1
--- /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 768:
+	case 1024:
+	case 1536:
+	case 2048:
+	case 3072:
+	case 4096:
+		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 = akcipher_tfm_ctx(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 = akcipher_tfm_ctx(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 = akcipher_tfm_ctx(tfm);
+
+	return params->p ? mpi_get_size(params->p) : -EINVAL;
+}
+
+static void dh_exit_tfm(struct crypto_akcipher *tfm)
+{
+	struct dh_params *params = akcipher_tfm_ctx(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 93f3527..adf6815 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);
@@ -2676,6 +2785,19 @@ static const struct alg_test_desc alg_test_descs[] = {
 			}
 		}
 	}, {
+		.alg = "dh",
+		.test = alg_test_akcipher,
+		.suite = {
+			.akcipher = {
+				.vecs = {
+					.a = {
+						.dh = dh_tv_template
+					},
+				},
+				.count = DH_TEST_VECTORS
+			}
+		}
+	}, {
 		.alg = "digest_null",
 		.test = alg_test_null,
 	}, {
@@ -3560,7 +3682,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
  */
