aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/development/test-vectors.rst14
-rw-r--r--docs/hazmat/backends/interfaces.rst15
-rw-r--r--docs/hazmat/primitives/asymmetric/dh.rst12
-rw-r--r--src/cryptography/hazmat/backends/interfaces.py9
-rw-r--r--src/cryptography/hazmat/backends/multibackend.py13
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py66
-rw-r--r--src/cryptography/hazmat/backends/openssl/dh.py77
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/dh.py11
-rw-r--r--tests/hazmat/backends/test_multibackend.py7
-rw-r--r--tests/hazmat/backends/test_openssl.py83
-rw-r--r--tests/hazmat/primitives/test_dh.py165
-rw-r--r--tests/hazmat/primitives/test_serialization.py21
-rw-r--r--vectors/cryptography_vectors/asymmetric/DH/RFC5114.txt3
-rw-r--r--vectors/cryptography_vectors/asymmetric/DH/dhkey_rfc5114_2.derbin0 -> 609 bytes
-rw-r--r--vectors/cryptography_vectors/asymmetric/DH/dhkey_rfc5114_2.pem15
-rw-r--r--vectors/cryptography_vectors/asymmetric/DH/dhkey_rfc5114_2.txt7
-rw-r--r--vectors/cryptography_vectors/asymmetric/DH/dhp_rfc5114_2.derbin0 -> 526 bytes
-rw-r--r--vectors/cryptography_vectors/asymmetric/DH/dhp_rfc5114_2.pem14
-rw-r--r--vectors/cryptography_vectors/asymmetric/DH/dhpub_rfc5114_2.derbin0 -> 840 bytes
-rw-r--r--vectors/cryptography_vectors/asymmetric/DH/dhpub_rfc5114_2.pem20
20 files changed, 481 insertions, 71 deletions
diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst
index 15fe2d2e..f9f865e8 100644
--- a/docs/development/test-vectors.rst
+++ b/docs/development/test-vectors.rst
@@ -110,6 +110,20 @@ Key exchange
``vectors/cryptography_vectors/asymmetric/DH/dhpub.der`` contains
are the above parameters and keys in DER format.
+* ``vectors/cryptography_vectors/asymmetric/DH/dhp_rfc5114_2.pem``,
+ ``vectors/cryptography_vectors/asymmetric/DH/dhkey_rfc5114_2.pem`` and
+ ``vectors/cryptography_vectors/asymmetric/DH/dhpub_rfc5114_2.pem`` contains
+ Diffie-Hellman parameters and key respectively. The keys were
+ generated using OpenSSL following `DHKE`_ guide. When creating the
+ parameters we added the `-pkeyopt dh_rfc5114:2` option to use
+ RFC5114 2048 bit DH parameters with 224 bit subgroup.
+ ``vectors/cryptography_vectors/asymmetric/DH/dhkey_rfc5114_2.txt`` contains
+ all parameter in text.
+ ``vectors/cryptography_vectors/asymmetric/DH/dhp_rfc5114_2.der``,
+ ``vectors/cryptography_vectors/asymmetric/DH/dhkey_rfc5114_2.der`` and
+ ``vectors/cryptography_vectors/asymmetric/DH/dhpub_rfc5114_2.der`` contains
+ are the above parameters and keys in DER format.
+
X.509
~~~~~
diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst
index 87fc6ab7..4f15d5c6 100644
--- a/docs/hazmat/backends/interfaces.rst
+++ b/docs/hazmat/backends/interfaces.rst
@@ -666,14 +666,23 @@ A specific ``backend`` may provide one or more of these interfaces.
:raises cryptography.exceptions.UnsupportedAlgorithm: This is raised
when any backend specific criteria are not met.
- .. method:: dh_parameters_supported(p, g)
+ .. method:: dh_parameters_supported(p, g, q=None)
:param int p: The p value of the DH key.
:param int g: The g value of the DH key.
- :returns: ``True`` if the given values of ``p`` and ``g`` are supported
- by this backend, otherwise ``False``.
+ :param int q: The q value of the DH key.
+
+ :returns: ``True`` if the given values of ``p``, ``g`` and ``q``
+ are supported by this backend, otherwise ``False``.
+
+ .. versionadded:: 1.8
+
+ .. method:: dh_x942_serialization_supported()
+
+ :returns: True if serialization of DH objects with
+ subgroup order (q) is supported by this backend.
.. class:: ScryptBackend
diff --git a/docs/hazmat/primitives/asymmetric/dh.rst b/docs/hazmat/primitives/asymmetric/dh.rst
index 73e534e2..759b265b 100644
--- a/docs/hazmat/primitives/asymmetric/dh.rst
+++ b/docs/hazmat/primitives/asymmetric/dh.rst
@@ -223,7 +223,7 @@ Key interfaces
Numbers
~~~~~~~
-.. class:: DHParameterNumbers(p, g)
+.. class:: DHParameterNumbers(p, g, q=None)
.. versionadded:: 0.8
@@ -239,7 +239,15 @@ Numbers
:type: int
- The generator value. Must be 2 or 5.
+ The generator value. Must be 2 or 5 (Unless q is given).
+
+ .. attribute:: q
+
+ .. versionadded:: 1.8
+
+ :type: int
+
+ p subgroup order value.
.. class:: DHPrivateNumbers(x, public_numbers)
diff --git a/src/cryptography/hazmat/backends/interfaces.py b/src/cryptography/hazmat/backends/interfaces.py
index c5f2951c..9ed50cc4 100644
--- a/src/cryptography/hazmat/backends/interfaces.py
+++ b/src/cryptography/hazmat/backends/interfaces.py
@@ -361,11 +361,18 @@ class DHBackend(object):
"""
@abc.abstractmethod
- def dh_parameters_supported(self, p, g):
+ def dh_parameters_supported(self, p, g, q=None):
"""
Returns whether the backend supports DH with these parameter values.
"""
+ @abc.abstractmethod
+ def dh_x942_serialization_supported(self):
+ """
+ Returns True if the backend supports the serialization of DH objects
+ with subgroup order (q).
+ """
+
@six.add_metaclass(abc.ABCMeta)
class ScryptBackend(object):
diff --git a/src/cryptography/hazmat/backends/multibackend.py b/src/cryptography/hazmat/backends/multibackend.py
index 097b4908..bb30c661 100644
--- a/src/cryptography/hazmat/backends/multibackend.py
+++ b/src/cryptography/hazmat/backends/multibackend.py
@@ -481,9 +481,18 @@ class MultiBackend(object):
_Reasons.UNSUPPORTED_DIFFIE_HELLMAN
)
- def dh_parameters_supported(self, p, g):
+ def dh_parameters_supported(self, p, g, q=None):
for b in self._filtered_backends(DHBackend):
- return b.dh_parameters_supported(p, g)
+ return b.dh_parameters_supported(p, g, q)
+
+ raise UnsupportedAlgorithm(
+ "This backend does not support Diffie-Hellman",
+ _Reasons.UNSUPPORTED_DIFFIE_HELLMAN
+ )
+
+ def dh_x942_serialization_supported(self):
+ for b in self._filtered_backends(DHBackend):
+ return b.dh_x942_serialization_supported()
raise UnsupportedAlgorithm(
"This backend does not support Diffie-Hellman",
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index 77538162..446891d3 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -23,7 +23,8 @@ from cryptography.hazmat.backends.interfaces import (
from cryptography.hazmat.backends.openssl.ciphers import _CipherContext
from cryptography.hazmat.backends.openssl.cmac import _CMACContext
from cryptography.hazmat.backends.openssl.dh import (
- _DHParameters, _DHPrivateKey, _DHPublicKey
+ _DHParameters, _DHPrivateKey, _DHPublicKey,
+ _dh_params_dup
)
from cryptography.hazmat.backends.openssl.dsa import (
_DSAParameters, _DSAPrivateKey, _DSAPublicKey
@@ -99,6 +100,9 @@ class Backend(object):
self._cipher_registry = {}
self._register_default_ciphers()
self.activate_osrandom_engine()
+ self._dh_types = [self._lib.EVP_PKEY_DH]
+ if self._lib.Cryptography_HAS_EVP_PKEY_DHX:
+ self._dh_types.append(self._lib.EVP_PKEY_DHX)
def openssl_assert(self, ok):
return binding._openssl_assert(self._lib, ok)
@@ -480,7 +484,7 @@ class Backend(object):
self.openssl_assert(ec_cdata != self._ffi.NULL)
ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free)
return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey)
- elif key_type == self._lib.EVP_PKEY_DH:
+ elif key_type in self._dh_types:
dh_cdata = self._lib.EVP_PKEY_get1_DH(evp_pkey)
self.openssl_assert(dh_cdata != self._ffi.NULL)
dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
@@ -512,7 +516,7 @@ class Backend(object):
self.openssl_assert(ec_cdata != self._ffi.NULL)
ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free)
return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey)
- elif key_type == self._lib.EVP_PKEY_DH:
+ elif key_type in self._dh_types:
dh_cdata = self._lib.EVP_PKEY_get1_DH(evp_pkey)
self.openssl_assert(dh_cdata != self._ffi.NULL)
dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
@@ -1205,6 +1209,23 @@ class Backend(object):
_Reasons.UNSUPPORTED_CIPHER
)
+ elif errors[0][1:] in (
+ (
+ self._lib.ERR_LIB_ASN1,
+ self._lib.ASN1_F_ASN1_CHECK_TLEN,
+ self._lib.ASN1_R_WRONG_TAG
+ ),
+ (
+ self._lib.ERR_LIB_PEM,
+ self._lib.PEM_F_PEM_READ_BIO,
+ self._lib.PEM_R_NO_START_LINE
+ ),
+ ):
+ raise UnsupportedAlgorithm(
+ "Unsupported public key algorithm.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+ )
+
elif any(
error[1:] == (
self._lib.ERR_LIB_EVP,
@@ -1660,9 +1681,7 @@ class Backend(object):
return evp_pkey
def generate_dh_private_key(self, parameters):
- dh_key_cdata = self._lib.DHparams_dup(parameters._dh_cdata)
- self.openssl_assert(dh_key_cdata != self._ffi.NULL)
- dh_key_cdata = self._ffi.gc(dh_key_cdata, self._lib.DH_free)
+ dh_key_cdata = _dh_params_dup(parameters._dh_cdata, self)
res = self._lib.DH_generate_key(dh_key_cdata)
self.openssl_assert(res == 1)
@@ -1684,10 +1703,16 @@ class Backend(object):
p = self._int_to_bn(parameter_numbers.p)
g = self._int_to_bn(parameter_numbers.g)
+
+ if parameter_numbers.q is not None:
+ q = self._int_to_bn(parameter_numbers.q)
+ else:
+ q = self._ffi.NULL
+
pub_key = self._int_to_bn(numbers.public_numbers.y)
priv_key = self._int_to_bn(numbers.x)
- res = self._lib.DH_set0_pqg(dh_cdata, p, self._ffi.NULL, g)
+ res = self._lib.DH_set0_pqg(dh_cdata, p, q, g)
self.openssl_assert(res == 1)
res = self._lib.DH_set0_key(dh_cdata, pub_key, priv_key)
@@ -1713,9 +1738,15 @@ class Backend(object):
p = self._int_to_bn(parameter_numbers.p)
g = self._int_to_bn(parameter_numbers.g)
+
+ if parameter_numbers.q is not None:
+ q = self._int_to_bn(parameter_numbers.q)
+ else:
+ q = self._ffi.NULL
+
pub_key = self._int_to_bn(numbers.y)
- res = self._lib.DH_set0_pqg(dh_cdata, p, self._ffi.NULL, g)
+ res = self._lib.DH_set0_pqg(dh_cdata, p, q, g)
self.openssl_assert(res == 1)
res = self._lib.DH_set0_key(dh_cdata, pub_key, self._ffi.NULL)
@@ -1733,12 +1764,17 @@ class Backend(object):
p = self._int_to_bn(numbers.p)
g = self._int_to_bn(numbers.g)
- res = self._lib.DH_set0_pqg(dh_cdata, p, self._ffi.NULL, g)
+ if numbers.q is not None:
+ q = self._int_to_bn(numbers.q)
+ else:
+ q = self._ffi.NULL
+
+ res = self._lib.DH_set0_pqg(dh_cdata, p, q, g)
self.openssl_assert(res == 1)
return _DHParameters(self, dh_cdata)
- def dh_parameters_supported(self, p, g):
+ def dh_parameters_supported(self, p, g, q=None):
dh_cdata = self._lib.DH_new()
self.openssl_assert(dh_cdata != self._ffi.NULL)
dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
@@ -1746,7 +1782,12 @@ class Backend(object):
p = self._int_to_bn(p)
g = self._int_to_bn(g)
- res = self._lib.DH_set0_pqg(dh_cdata, p, self._ffi.NULL, g)
+ if q is not None:
+ q = self._int_to_bn(q)
+ else:
+ q = self._ffi.NULL
+
+ res = self._lib.DH_set0_pqg(dh_cdata, p, q, g)
self.openssl_assert(res == 1)
codes = self._ffi.new("int[]", 1)
@@ -1755,6 +1796,9 @@ class Backend(object):
return codes[0] == 0
+ def dh_x942_serialization_supported(self):
+ return self._lib.Cryptography_HAS_EVP_PKEY_DHX == 1
+
def x509_name_bytes(self, name):
x509_name = _encode_name_gc(self, name)
pp = self._ffi.new("unsigned char **")
diff --git a/src/cryptography/hazmat/backends/openssl/dh.py b/src/cryptography/hazmat/backends/openssl/dh.py
index b594d411..88c876fc 100644
--- a/src/cryptography/hazmat/backends/openssl/dh.py
+++ b/src/cryptography/hazmat/backends/openssl/dh.py
@@ -5,18 +5,31 @@
from __future__ import absolute_import, division, print_function
from cryptography import utils
+from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import dh
-def _dh_cdata_to_parameters(dh_cdata, backend):
+def _dh_params_dup(dh_cdata, backend):
lib = backend._lib
ffi = backend._ffi
param_cdata = lib.DHparams_dup(dh_cdata)
backend.openssl_assert(param_cdata != ffi.NULL)
param_cdata = ffi.gc(param_cdata, lib.DH_free)
+ if lib.OPENSSL_VERSION_NUMBER < 0x10002000 or lib.CRYPTOGRAPHY_IS_LIBRESSL:
+ # In OpenSSL versions < 1.0.2 or libressl DHparams_dup don't copy q
+ q = ffi.new("BIGNUM **")
+ lib.DH_get0_pqg(dh_cdata, ffi.NULL, q, ffi.NULL)
+ q_dup = lib.BN_dup(q[0])
+ res = lib.DH_set0_pqg(param_cdata, ffi.NULL, q_dup, ffi.NULL)
+ backend.openssl_assert(res == 1)
+
+ return param_cdata
+
+def _dh_cdata_to_parameters(dh_cdata, backend):
+ param_cdata = _dh_params_dup(dh_cdata, backend)
return _DHParameters(backend, param_cdata)
@@ -29,13 +42,18 @@ class _DHParameters(object):
def parameter_numbers(self):
p = self._backend._ffi.new("BIGNUM **")
g = self._backend._ffi.new("BIGNUM **")
- self._backend._lib.DH_get0_pqg(self._dh_cdata,
- p, self._backend._ffi.NULL, g)
+ q = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g)
self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
+ if q[0] == self._backend._ffi.NULL:
+ q_val = None
+ else:
+ q_val = self._backend._bn_to_int(q[0])
return dh.DHParameterNumbers(
p=self._backend._bn_to_int(p[0]),
- g=self._backend._bn_to_int(g[0])
+ g=self._backend._bn_to_int(g[0]),
+ q=q_val
)
def generate_private_key(self):
@@ -78,10 +96,14 @@ class _DHPrivateKey(object):
def private_numbers(self):
p = self._backend._ffi.new("BIGNUM **")
g = self._backend._ffi.new("BIGNUM **")
- self._backend._lib.DH_get0_pqg(self._dh_cdata,
- p, self._backend._ffi.NULL, g)
+ q = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g)
self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
+ if q[0] == self._backend._ffi.NULL:
+ q_val = None
+ else:
+ q_val = self._backend._bn_to_int(q[0])
pub_key = self._backend._ffi.new("BIGNUM **")
priv_key = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DH_get0_key(self._dh_cdata, pub_key, priv_key)
@@ -91,7 +113,8 @@ class _DHPrivateKey(object):
public_numbers=dh.DHPublicNumbers(
parameter_numbers=dh.DHParameterNumbers(
p=self._backend._bn_to_int(p[0]),
- g=self._backend._bn_to_int(g[0])
+ g=self._backend._bn_to_int(g[0]),
+ q=q_val
),
y=self._backend._bn_to_int(pub_key[0])
),
@@ -126,12 +149,7 @@ class _DHPrivateKey(object):
return key
def public_key(self):
- dh_cdata = self._backend._lib.DHparams_dup(self._dh_cdata)
- self._backend.openssl_assert(dh_cdata != self._backend._ffi.NULL)
- dh_cdata = self._backend._ffi.gc(
- dh_cdata, self._backend._lib.DH_free
- )
-
+ dh_cdata = _dh_params_dup(self._dh_cdata, self._backend)
pub_key = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DH_get0_key(self._dh_cdata,
pub_key, self._backend._ffi.NULL)
@@ -154,6 +172,17 @@ class _DHPrivateKey(object):
raise ValueError(
"DH private keys support only PKCS8 serialization"
)
+ if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX:
+ q = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DH_get0_pqg(self._dh_cdata,
+ self._backend._ffi.NULL,
+ q,
+ self._backend._ffi.NULL)
+ if q[0] != self._backend._ffi.NULL:
+ raise UnsupportedAlgorithm(
+ "DH X9.42 serialization is not supported",
+ _Reasons.UNSUPPORTED_SERIALIZATION)
+
return self._backend._private_key_bytes(
encoding,
format,
@@ -178,10 +207,14 @@ class _DHPublicKey(object):
def public_numbers(self):
p = self._backend._ffi.new("BIGNUM **")
g = self._backend._ffi.new("BIGNUM **")
- self._backend._lib.DH_get0_pqg(self._dh_cdata,
- p, self._backend._ffi.NULL, g)
+ q = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g)
self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
+ if q[0] == self._backend._ffi.NULL:
+ q_val = None
+ else:
+ q_val = self._backend._bn_to_int(q[0])
pub_key = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DH_get0_key(self._dh_cdata,
pub_key, self._backend._ffi.NULL)
@@ -189,7 +222,8 @@ class _DHPublicKey(object):
return dh.DHPublicNumbers(
parameter_numbers=dh.DHParameterNumbers(
p=self._backend._bn_to_int(p[0]),
- g=self._backend._bn_to_int(g[0])
+ g=self._backend._bn_to_int(g[0]),
+ q=q_val
),
y=self._backend._bn_to_int(pub_key[0])
)
@@ -204,6 +238,17 @@ class _DHPublicKey(object):
"SubjectPublicKeyInfo serialization"
)
+ if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX:
+ q = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DH_get0_pqg(self._dh_cdata,
+ self._backend._ffi.NULL,
+ q,
+ self._backend._ffi.NULL)
+ if q[0] != self._backend._ffi.NULL:
+ raise UnsupportedAlgorithm(
+ "DH X9.42 serialization is not supported",
+ _Reasons.UNSUPPORTED_SERIALIZATION)
+
return self._backend._public_key_bytes(
encoding,
format,
diff --git a/src/cryptography/hazmat/primitives/asymmetric/dh.py b/src/cryptography/hazmat/primitives/asymmetric/dh.py
index ec044ddd..aa60a2d8 100644
--- a/src/cryptography/hazmat/primitives/asymmetric/dh.py
+++ b/src/cryptography/hazmat/primitives/asymmetric/dh.py
@@ -78,18 +78,21 @@ class DHPublicNumbers(object):
class DHParameterNumbers(object):
- def __init__(self, p, g):
+ def __init__(self, p, g, q=None):
if (
not isinstance(p, six.integer_types) or
not isinstance(g, six.integer_types)
):
raise TypeError("p and g must be integers")
+ if q is not None and not isinstance(q, six.integer_types):
+ raise TypeError("q must be integer or None")
- if g not in (2, 5):
+ if q is None and g not in (2, 5):
raise ValueError("DH generator must be 2 or 5")
self._p = p
self._g = g
+ self._q = q
def __eq__(self, other):
if not isinstance(other, DHParameterNumbers):
@@ -97,7 +100,8 @@ class DHParameterNumbers(object):
return (
self._p == other._p and
- self._g == other._g
+ self._g == other._g and
+ self._q == other._q
)
def __ne__(self, other):
@@ -108,6 +112,7 @@ class DHParameterNumbers(object):
p = utils.read_only_property("_p")
g = utils.read_only_property("_g")
+ q = utils.read_only_property("_q")
@six.add_metaclass(abc.ABCMeta)
diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py
index bd806731..9370387c 100644
--- a/tests/hazmat/backends/test_multibackend.py
+++ b/tests/hazmat/backends/test_multibackend.py
@@ -265,7 +265,10 @@ class DummyDHBackend(object):
def generate_dh_private_key_and_parameters(self, generator, key_size):
pass
- def dh_parameters_supported(self, p, g):
+ def dh_parameters_supported(self, p, g, q=None):
+ pass
+
+ def dh_x942_serialization_supported(self):
pass
@@ -638,6 +641,8 @@ class TestMultiBackend(object):
backend.generate_dh_private_key_and_parameters(2, 512)
with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_DIFFIE_HELLMAN):
backend.dh_parameters_supported(2, 3)
+ with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_DIFFIE_HELLMAN):
+ backend.dh_x942_serialization_supported()
def test_scrypt(self):
backend = MultiBackend([DummyScryptBackend()])
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index ff8a42ef..f561c793 100644
--- a/tests/hazmat/backends/test_openssl.py
+++ b/tests/hazmat/backends/test_openssl.py
@@ -16,13 +16,13 @@ import pytest
from cryptography import utils, x509
from cryptography.exceptions import InternalError, _Reasons
-from cryptography.hazmat.backends.interfaces import RSABackend
+from cryptography.hazmat.backends.interfaces import DHBackend, RSABackend
from cryptography.hazmat.backends.openssl.backend import (
Backend, backend
)
from cryptography.hazmat.backends.openssl.ec import _sn_to_elliptic_curve
from cryptography.hazmat.primitives import hashes, serialization
-from cryptography.hazmat.primitives.asymmetric import dsa, ec, padding
+from cryptography.hazmat.primitives.asymmetric import dh, dsa, ec, padding
from cryptography.hazmat.primitives.ciphers import Cipher
from cryptography.hazmat.primitives.ciphers.algorithms import AES
from cryptography.hazmat.primitives.ciphers.modes import CBC
@@ -32,7 +32,9 @@ from ...doubles import (
DummyAsymmetricPadding, DummyCipherAlgorithm, DummyHashAlgorithm, DummyMode
)
from ...test_x509 import _load_cert
-from ...utils import load_vectors_from_file, raises_unsupported_algorithm
+from ...utils import (
+ load_nist_vectors, load_vectors_from_file, raises_unsupported_algorithm
+)
def skip_if_libre_ssl(openssl_version):
@@ -611,3 +613,78 @@ class TestGOSTCertificate(object):
assert cert.subject.get_attributes_for_oid(
x509.ObjectIdentifier("1.2.643.3.131.1.1")
)[0].value == "007710474375"
+
+
+@pytest.mark.skipif(
+ backend._lib.Cryptography_HAS_EVP_PKEY_DHX == 1,
+ reason="Requires OpenSSL without EVP_PKEY_DHX (1.0.2-)")
+@pytest.mark.requires_backend_interface(interface=DHBackend)
+class TestOpenSSLDHSerialization(object):
+
+ @pytest.mark.parametrize(
+ "vector",
+ load_vectors_from_file(
+ os.path.join("asymmetric", "DH", "RFC5114.txt"),
+ load_nist_vectors))
+ def test_dh_serialization_with_q_unsupported(self, backend, vector):
+ parameters = dh.DHParameterNumbers(int(vector["p"], 16),
+ int(vector["g"], 16),
+ int(vector["q"], 16))
+ public = dh.DHPublicNumbers(int(vector["ystatcavs"], 16), parameters)
+ private = dh.DHPrivateNumbers(int(vector["xstatcavs"], 16), public)
+ private_key = private.private_key(backend)
+ public_key = private_key.public_key()
+ with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION):
+ private_key.private_bytes(serialization.Encoding.PEM,
+ serialization.PrivateFormat.PKCS8,
+ serialization.NoEncryption())
+ with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION):
+ public_key.public_bytes(
+ serialization.Encoding.PEM,
+ serialization.PublicFormat.SubjectPublicKeyInfo)
+
+ @pytest.mark.parametrize(
+ ("key_path", "loader_func"),
+ [
+ (
+ os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.pem"),
+ serialization.load_pem_private_key,
+ ),
+ (
+ os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.der"),
+ serialization.load_der_private_key,
+ )
+ ]
+ )
+ def test_private_load_dhx_unsupported(self, key_path, loader_func,
+ backend):
+ key_bytes = load_vectors_from_file(
+ key_path,
+ lambda pemfile: pemfile.read(), mode="rb"
+ )
+ with raises_unsupported_algorithm(
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM):
+ loader_func(key_bytes, None, backend)
+
+ @pytest.mark.parametrize(
+ ("key_path", "loader_func"),
+ [
+ (
+ os.path.join("asymmetric", "DH", "dhpub_rfc5114_2.pem"),
+ serialization.load_pem_public_key,
+ ),
+ (
+ os.path.join("asymmetric", "DH", "dhpub_rfc5114_2.der"),
+ serialization.load_der_public_key,
+ )
+ ]
+ )
+ def test_public_load_dhx_unsupported(self, key_path, loader_func,
+ backend):
+ key_bytes = load_vectors_from_file(
+ key_path,
+ lambda pemfile: pemfile.read(), mode="rb"
+ )
+ with raises_unsupported_algorithm(
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM):
+ loader_func(key_bytes, backend)
diff --git a/tests/hazmat/primitives/test_dh.py b/tests/hazmat/primitives/test_dh.py
index 1086630d..5b35fe51 100644
--- a/tests/hazmat/primitives/test_dh.py
+++ b/tests/hazmat/primitives/test_dh.py
@@ -18,6 +18,13 @@ from ...doubles import DummyKeySerializationEncryption
from ...utils import load_nist_vectors, load_vectors_from_file
+def _skip_dhx_unsupported(backend):
+ if not backend.dh_x942_serialization_supported():
+ pytest.skip(
+ "DH x9.42 serialization is not supported"
+ )
+
+
def test_dh_parameternumbers():
params = dh.DHParameterNumbers(
65537, 2
@@ -46,6 +53,19 @@ def test_dh_parameternumbers():
65537, 7
)
+ params = dh.DHParameterNumbers(
+ 65537, 7, 1245
+ )
+
+ assert params.p == 65537
+ assert params.g == 7
+ assert params.q == 1245
+
+ with pytest.raises(TypeError):
+ dh.DHParameterNumbers(
+ 65537, 2, "hello"
+ )
+
def test_dh_numbers():
params = dh.DHParameterNumbers(
@@ -89,7 +109,11 @@ def test_dh_numbers():
def test_dh_parameter_numbers_equality():
assert dh.DHParameterNumbers(65537, 2) == dh.DHParameterNumbers(65537, 2)
+ assert dh.DHParameterNumbers(65537, 7, 12345) == dh.DHParameterNumbers(
+ 65537, 7, 12345)
assert dh.DHParameterNumbers(6, 2) != dh.DHParameterNumbers(65537, 2)
+ assert dh.DHParameterNumbers(65537, 2, 123) != dh.DHParameterNumbers(
+ 65537, 2, 456)
assert dh.DHParameterNumbers(65537, 5) != dh.DHParameterNumbers(65537, 2)
assert dh.DHParameterNumbers(65537, 2) != object()
@@ -132,15 +156,35 @@ class TestDH(object):
assert backend.dh_parameters_supported(23, 5)
assert not backend.dh_parameters_supported(23, 18)
- def test_convert_to_numbers(self, backend):
- parameters = backend.generate_dh_private_key_and_parameters(2, 512)
+ @pytest.mark.parametrize(
+ "vector",
+ load_vectors_from_file(
+ os.path.join("asymmetric", "DH", "RFC5114.txt"),
+ load_nist_vectors))
+ def test_dh_parameters_supported_with_q(self, backend, vector):
+ assert backend.dh_parameters_supported(int(vector["p"], 16),
+ int(vector["g"], 16),
+ int(vector["q"], 16))
+
+ @pytest.mark.parametrize("with_q", [False, True])
+ def test_convert_to_numbers(self, backend, with_q):
+ if with_q:
+ vector = load_vectors_from_file(
+ os.path.join("asymmetric", "DH", "RFC5114.txt"),
+ load_nist_vectors)[0]
+ p = int(vector["p"], 16)
+ g = int(vector["g"], 16)
+ q = int(vector["q"], 16)
+ else:
+ parameters = backend.generate_dh_private_key_and_parameters(2, 512)
- private = parameters.private_numbers()
+ private = parameters.private_numbers()
- p = private.public_numbers.parameter_numbers.p
- g = private.public_numbers.parameter_numbers.g
+ p = private.public_numbers.parameter_numbers.p
+ g = private.public_numbers.parameter_numbers.g
+ q = None
- params = dh.DHParameterNumbers(p, g)
+ params = dh.DHParameterNumbers(p, g, q)
public = dh.DHPublicNumbers(1, params)
private = dh.DHPrivateNumbers(2, public)
@@ -163,11 +207,22 @@ class TestDH(object):
with pytest.raises(ValueError):
private.private_key(backend)
- def test_generate_dh(self, backend):
- generator = 2
- key_size = 512
+ @pytest.mark.parametrize("with_q", [False, True])
+ def test_generate_dh(self, backend, with_q):
+ if with_q:
+ vector = load_vectors_from_file(
+ os.path.join("asymmetric", "DH", "RFC5114.txt"),
+ load_nist_vectors)[0]
+ p = int(vector["p"], 16)
+ g = int(vector["g"], 16)
+ q = int(vector["q"], 16)
+ parameters = dh.DHParameterNumbers(p, g, q).parameters(backend)
+ key_size = 1024
+ else:
+ generator = 2
+ key_size = 512
- parameters = dh.generate_parameters(generator, key_size, backend)
+ parameters = dh.generate_parameters(generator, key_size, backend)
assert isinstance(parameters, dh.DHParameters)
key = parameters.generate_private_key()
@@ -290,6 +345,27 @@ class TestDH(object):
assert int_from_bytes(symkey, 'big') == int(vector["k"], 16)
+ @pytest.mark.parametrize(
+ "vector",
+ load_vectors_from_file(
+ os.path.join("asymmetric", "DH", "RFC5114.txt"),
+ load_nist_vectors))
+ def test_dh_vectors_with_q(self, backend, vector):
+ parameters = dh.DHParameterNumbers(int(vector["p"], 16),
+ int(vector["g"], 16),
+ int(vector["q"], 16))
+ public1 = dh.DHPublicNumbers(int(vector["ystatcavs"], 16), parameters)
+ private1 = dh.DHPrivateNumbers(int(vector["xstatcavs"], 16), public1)
+ public2 = dh.DHPublicNumbers(int(vector["ystatiut"], 16), parameters)
+ private2 = dh.DHPrivateNumbers(int(vector["xstatiut"], 16), public2)
+ key1 = private1.private_key(backend)
+ key2 = private2.private_key(backend)
+ symkey1 = key1.exchange(public2.public_key(backend))
+ symkey2 = key2.exchange(public1.public_key(backend))
+
+ assert int_from_bytes(symkey1, 'big') == int(vector["z"], 16)
+ assert int_from_bytes(symkey2, 'big') == int(vector["z"], 16)
+
@pytest.mark.requires_backend_interface(interface=DHBackend)
@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend)
@@ -332,11 +408,20 @@ class TestDHPrivateKeySerialization(object):
os.path.join("asymmetric", "DH", "dhkey.der"),
serialization.load_der_private_key,
serialization.Encoding.DER,
+ ), (
+ os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.pem"),
+ serialization.load_pem_private_key,
+ serialization.Encoding.PEM,
+ ), (
+ os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.der"),
+ serialization.load_der_private_key,
+ serialization.Encoding.DER,
)
]
)
def test_private_bytes_match(self, key_path, loader_func,
encoding, backend):
+ _skip_dhx_unsupported(backend)
key_bytes = load_vectors_from_file(
key_path,
lambda pemfile: pemfile.read(), mode="rb"
@@ -349,34 +434,48 @@ class TestDHPrivateKeySerialization(object):
assert serialized == key_bytes
@pytest.mark.parametrize(
- ("key_path", "loader_func"),
+ ("key_path", "loader_func", "vec_path"),
[
(
os.path.join("asymmetric", "DH", "dhkey.pem"),
serialization.load_pem_private_key,
+ os.path.join("asymmetric", "DH", "dhkey.txt")
), (
os.path.join("asymmetric", "DH", "dhkey.der"),
serialization.load_der_private_key,
+ os.path.join("asymmetric", "DH", "dhkey.txt")
+ ), (
+ os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.pem"),
+ serialization.load_pem_private_key,
+ os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.txt")
+ ), (
+ os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.der"),
+ serialization.load_der_private_key,
+ os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.txt")
)
]
)
def test_private_bytes_values(self, key_path, loader_func,
- backend):
+ vec_path, backend):
+ _skip_dhx_unsupported(backend)
key_bytes = load_vectors_from_file(
key_path,
lambda pemfile: pemfile.read(), mode="rb"
)
- vec = load_vectors_from_file(
- os.path.join("asymmetric", "DH", "dhkey.txt"),
- load_nist_vectors)[0]
+ vec = load_vectors_from_file(vec_path, load_nist_vectors)[0]
key = loader_func(key_bytes, None, backend)
private_numbers = key.private_numbers()
assert private_numbers.x == int(vec["x"], 16)
assert private_numbers.public_numbers.y == int(vec["y"], 16)
assert private_numbers.public_numbers.parameter_numbers.g == int(
- vec["g"])
+ vec["g"], 16)
assert private_numbers.public_numbers.parameter_numbers.p == int(
vec["p"], 16)
+ if "q" in vec:
+ assert private_numbers.public_numbers.parameter_numbers.q == int(
+ vec["q"], 16)
+ else:
+ assert private_numbers.public_numbers.parameter_numbers.q is None
def test_private_bytes_traditional_openssl_invalid(self, backend):
parameters = dh.generate_parameters(2, 512, backend)
@@ -469,11 +568,20 @@ class TestDHPublicKeySerialization(object):
os.path.join("asymmetric", "DH", "dhpub.der"),
serialization.load_der_public_key,
serialization.Encoding.DER,
+ ), (
+ os.path.join("asymmetric", "DH", "dhpub_rfc5114_2.pem"),
+ serialization.load_pem_public_key,
+ serialization.Encoding.PEM,
+ ), (
+ os.path.join("asymmetric", "DH", "dhpub_rfc5114_2.der"),
+ serialization.load_der_public_key,
+ serialization.Encoding.DER,
)
]
)
def test_public_bytes_match(self, key_path, loader_func,
encoding, backend):
+ _skip_dhx_unsupported(backend)
key_bytes = load_vectors_from_file(
key_path,
lambda pemfile: pemfile.read(), mode="rb"
@@ -486,31 +594,44 @@ class TestDHPublicKeySerialization(object):
assert serialized == key_bytes
@pytest.mark.parametrize(
- ("key_path", "loader_func"),
+ ("key_path", "loader_func", "vec_path"),
[
(
os.path.join("asymmetric", "DH", "dhpub.pem"),
serialization.load_pem_public_key,
+ os.path.join("asymmetric", "DH", "dhkey.txt"),
), (
os.path.join("asymmetric", "DH", "dhpub.der"),
serialization.load_der_public_key,
+ os.path.join("asymmetric", "DH", "dhkey.txt"),
+ ), (
+ os.path.join("asymmetric", "DH", "dhpub_rfc5114_2.pem"),
+ serialization.load_pem_public_key,
+ os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.txt"),
+ ), (
+ os.path.join("asymmetric", "DH", "dhpub_rfc5114_2.der"),
+ serialization.load_der_public_key,
+ os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.txt"),
)
]
)
def test_public_bytes_values(self, key_path, loader_func,
- backend):
+ vec_path, backend):
+ _skip_dhx_unsupported(backend)
key_bytes = load_vectors_from_file(
key_path,
lambda pemfile: pemfile.read(), mode="rb"
)
- vec = load_vectors_from_file(
- os.path.join("asymmetric", "DH", "dhkey.txt"),
- load_nist_vectors)[0]
+ vec = load_vectors_from_file(vec_path, load_nist_vectors)[0]
pub_key = loader_func(key_bytes, backend)
public_numbers = pub_key.public_numbers()
assert public_numbers.y == int(vec["y"], 16)
- assert public_numbers.parameter_numbers.g == int(vec["g"])
+ assert public_numbers.parameter_numbers.g == int(vec["g"], 16)
assert public_numbers.parameter_numbers.p == int(vec["p"], 16)
+ if "q" in vec:
+ assert public_numbers.parameter_numbers.q == int(vec["q"], 16)
+ else:
+ assert public_numbers.parameter_numbers.q is None
def test_public_bytes_invalid_encoding(self, backend):
parameters = dh.generate_parameters(2, 512, backend)
diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py
index dad056c6..bc16b5f8 100644
--- a/tests/hazmat/primitives/test_serialization.py
+++ b/tests/hazmat/primitives/test_serialization.py
@@ -236,10 +236,12 @@ class TestDERSerialization(object):
""").encode()
bad_der = base64.b64decode(b"".join(key_data.splitlines()))
- with pytest.raises(ValueError):
+ with raises_unsupported_algorithm(
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM):
load_pem_private_key(bad_der, None, backend)
- with pytest.raises(ValueError):
+ with raises_unsupported_algorithm(
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM):
load_pem_private_key(
bad_der, b"this password will not be used", backend
)
@@ -575,12 +577,14 @@ class TestPEMSerialization(object):
def test_wrong_private_format(self, backend):
key_data = b"---- NOT A KEY ----\n"
- with pytest.raises(ValueError):
+ with raises_unsupported_algorithm(
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM):
load_pem_private_key(
key_data, None, backend
)
- with pytest.raises(ValueError):
+ with raises_unsupported_algorithm(
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM):
load_pem_private_key(
key_data, b"this password will not be used", backend
)
@@ -588,7 +592,8 @@ class TestPEMSerialization(object):
def test_wrong_public_format(self, backend):
key_data = b"---- NOT A KEY ----\n"
- with pytest.raises(ValueError):
+ with raises_unsupported_algorithm(
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM):
load_pem_public_key(key_data, backend)
def test_corrupt_traditional_format(self, backend):
@@ -720,12 +725,14 @@ class TestPEMSerialization(object):
password = b"this password is wrong"
- with pytest.raises(ValueError):
+ with raises_unsupported_algorithm(
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM):
load_pem_private_key(
key_data, None, backend
)
- with pytest.raises(ValueError):
+ with raises_unsupported_algorithm(
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM):
load_pem_private_key(
key_data, password, backend
)
diff --git a/vectors/cryptography_vectors/asymmetric/DH/RFC5114.txt b/vectors/cryptography_vectors/asymmetric/DH/RFC5114.txt
index bb8e238f..08e9c129 100644
--- a/vectors/cryptography_vectors/asymmetric/DH/RFC5114.txt
+++ b/vectors/cryptography_vectors/asymmetric/DH/RFC5114.txt
@@ -1,4 +1,5 @@
[A.1. 1024-bit MODP Group with 160-bit Prime Order Subgroup]
+COUNT=0
P = B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C69A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C013ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD7098488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708DF1FB2BC2E4A4371
Q = F518AA8781A8DF278ABA4E7D64B7CB9D49462353
G = A4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507FD6406CFF14266D31266FEA1E5C41564B777E690F5504F213160217B4B01B886A5E91547F9E2749F4D7FBD7D3B9A92EE1909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28AD662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24855E6EEB22B3B2E5
@@ -14,6 +15,7 @@ Z = 5C804F454D30D9C4DF85271F93528C91DF6B48AB5F80B3B59CAAC1B28F8ACBA9CD3E39F3CB61
Result = P (0 - Correct)
[A.2.2048-bitMODPGroupwith224-bitPrimeOrderSubgroup]
+COUNT=1
P = AD107E1E9123A9D0D660FAA79559C51FA20D64E5683B9FD1B54B1597B61D0A75E6FA141DF95A56DBAF9A3C407BA1DF15EB3D688A309C180E1DE6B85A1274A0A66D3F8152AD6AC2129037C9EDEFDA4DF8D91E8FEF55B7394B7AD5B7D0B6C12207C9F98D11ED34DBF6C6BA0B2C8BBC27BE6A00E0A0B9C49708B3BF8A317091883681286130BC8985DB1602E714415D9330278273C7DE31EFDC7310F7121FD5A07415987D9ADC0A486DCDF93ACC44328387315D75E198C641A480CD86A1B9E587E8BE60E69CC928B2B9C52172E413042E9B23F10B0E16E79763C9B53DCF4BA80A29E3FB73C16B8E75B97EF363E2FFA31F71CF9DE5384E71B81C0AC4DFFE0C10E64F
Q = 801C0D34C58D93FE997177101F80535A4738CEBCBF389A99B36371EB
G = AC4032EF4F2D9AE39DF30B5C8FFDAC506CDEBE7B89998CAF74866A08CFE4FFE3A6824A4E10B9A6F0DD921F01A70C4AFAAB739D7700C29F52C57DB17C620A8652BE5E9001A8D66AD7C17669101999024AF4D027275AC1348BB8A762D0521BC98AE247150422EA1ED409939D54DA7460CDB5F6C6B250717CBEF180EB34118E98D119529A45D6F834566E3025E316A330EFBB77A86F0C1AB15B051AE3D428C8F8ACB70A8137150B8EEB10E183EDD19963DDD9E263E4770589EF6AA21E7F5F2FF381B539CCE3409D13CD566AFBB48D6C019181E1BCFE94B30269EDFE72FE9B6AA4BD7B5A0F1C71CFFF4C19C418E1F6EC017981BC087F2A7065B384B890D3191F2BFA
@@ -29,6 +31,7 @@ Z = 34D9BDDC1B42176C313FEA034C21034D074A6313BB4ECDB3703FFF424567A46BDF75530EDE0A
Result = P (0 - Correct)
[A.3. 2048-bit MODP Group with 256-bit Prime Order Subgroup]
+COUNT=2
P = 87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597
Q = 8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3
G = 3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67EB6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659
diff --git a/vectors/cryptography_vectors/asymmetric/DH/dhkey_rfc5114_2.der b/vectors/cryptography_vectors/asymmetric/DH/dhkey_rfc5114_2.der
new file mode 100644
index 00000000..4db7c957
--- /dev/null
+++ b/vectors/cryptography_vectors/asymmetric/DH/dhkey_rfc5114_2.der
Binary files differ
diff --git a/vectors/cryptography_vectors/asymmetric/DH/dhkey_rfc5114_2.pem b/vectors/cryptography_vectors/asymmetric/DH/dhkey_rfc5114_2.pem
new file mode 100644
index 00000000..3356432b
--- /dev/null
+++ b/vectors/cryptography_vectors/asymmetric/DH/dhkey_rfc5114_2.pem
@@ -0,0 +1,15 @@
+-----BEGIN PRIVATE KEY-----
+MIICXQIBADCCAjYGByqGSM4+AgEwggIpAoIBAQCtEH4ekSOp0NZg+qeVWcUfog1k
+5Wg7n9G1SxWXth0Kdeb6FB35Wlbbr5o8QHuh3xXrPWiKMJwYDh3muFoSdKCmbT+B
+Uq1qwhKQN8nt79pN+Nkej+9VtzlLetW30LbBIgfJ+Y0R7TTb9sa6CyyLvCe+agDg
+oLnElwizv4oxcJGINoEoYTC8iYXbFgLnFEFdkzAngnPH3jHv3HMQ9xIf1aB0FZh9
+mtwKSG3N+TrMRDKDhzFddeGYxkGkgM2Gobnlh+i+YOacySiyucUhcuQTBC6bI/EL
+Dhbnl2PJtT3PS6gKKeP7c8FrjnW5fvNj4v+jH3HPneU4TnG4HArE3/4MEOZPAoIB
+AQCsQDLvTy2a453zC1yP/axQbN6+e4mZjK90hmoIz+T/46aCSk4Quabw3ZIfAacM
+Svqrc513AMKfUsV9sXxiCoZSvl6QAajWatfBdmkQGZkCSvTQJydawTSLuKdi0FIb
+yYriRxUEIuoe1AmTnVTadGDNtfbGslBxfL7xgOs0EY6Y0RlSmkXW+DRWbjAl4xaj
+MO+7d6hvDBqxWwUa49QoyPistwqBNxULjusQ4YPt0Zlj3dniY+R3BYnvaqIef18v
+84G1OczjQJ0TzVZq+7SNbAGRgeG8/pSzAmnt/nL+m2qkvXtaDxxxz/9MGcQY4fbs
+AXmBvAh/KnBls4S4kNMZHyv6Ah0AgBwNNMWNk/6ZcXcQH4BTWkc4zry/OJqZs2Nx
+6wQeAhxEYPzCd3Q1ssq2dHEOtoeo6KO1ZVs6WS2LFf3x
+-----END PRIVATE KEY-----
diff --git a/vectors/cryptography_vectors/asymmetric/DH/dhkey_rfc5114_2.txt b/vectors/cryptography_vectors/asymmetric/DH/dhkey_rfc5114_2.txt
new file mode 100644
index 00000000..e1999899
--- /dev/null
+++ b/vectors/cryptography_vectors/asymmetric/DH/dhkey_rfc5114_2.txt
@@ -0,0 +1,7 @@
+
+COUNT = 0
+P = AD107E1E9123A9D0D660FAA79559C51FA20D64E5683B9FD1B54B1597B61D0A75E6FA141DF95A56DBAF9A3C407BA1DF15EB3D688A309C180E1DE6B85A1274A0A66D3F8152AD6AC2129037C9EDEFDA4DF8D91E8FEF55B7394B7AD5B7D0B6C12207C9F98D11ED34DBF6C6BA0B2C8BBC27BE6A00E0A0B9C49708B3BF8A317091883681286130BC8985DB1602E714415D9330278273C7DE31EFDC7310F7121FD5A07415987D9ADC0A486DCDF93ACC44328387315D75E198C641A480CD86A1B9E587E8BE60E69CC928B2B9C52172E413042E9B23F10B0E16E79763C9B53DCF4BA80A29E3FB73C16B8E75B97EF363E2FFA31F71CF9DE5384E71B81C0AC4DFFE0C10E64F
+G = AC4032EF4F2D9AE39DF30B5C8FFDAC506CDEBE7B89998CAF74866A08CFE4FFE3A6824A4E10B9A6F0DD921F01A70C4AFAAB739D7700C29F52C57DB17C620A8652BE5E9001A8D66AD7C17669101999024AF4D027275AC1348BB8A762D0521BC98AE247150422EA1ED409939D54DA7460CDB5F6C6B250717CBEF180EB34118E98D119529A45D6F834566E3025E316A330EFBB77A86F0C1AB15B051AE3D428C8F8ACB70A8137150B8EEB10E183EDD19963DDD9E263E4770589EF6AA21E7F5F2FF381B539CCE3409D13CD566AFBB48D6C019181E1BCFE94B30269EDFE72FE9B6AA4BD7B5A0F1C71CFFF4C19C418E1F6EC017981BC087F2A7065B384B890D3191F2BFA
+Q = 801C0D34C58D93FE997177101F80535A4738CEBCBF389A99B36371EB
+Y = 0082c165bb576243ecf46d58c3d1501616955fca0320fa95ea11d2e6c1b9cf217676720dc1c08c85bf20c4d232b60a29a1e51c7b773bc645014587c525c86151b30d75486ec7b6c98efb5f74955b83116d01d0af1232af89213c2de574369d701aba9357300b920d3d8b98252d46c46952c16a5f33554b38317809c7b9add4701f5c158c1b7035e9fe39366ececb90d2896b78c523c4a577287ef5ba7a2663ed58aa20b5ec66e30f316610dfaa38583e495ab6af771c284387e660edbef4edb872e2e80e1d244ee95622e76d028e61c1e887c2aa792717362139f4dd26eafd49b2366eeb2350b01fe1b56022a2809e379559c37b375ba01c4eaacc14fd1b247837
+X = 4460fcc2777435b2cab674710eb687a8e8a3b5655b3a592d8b15fdf1
diff --git a/vectors/cryptography_vectors/asymmetric/DH/dhp_rfc5114_2.der b/vectors/cryptography_vectors/asymmetric/DH/dhp_rfc5114_2.der
new file mode 100644
index 00000000..666eb9a0
--- /dev/null
+++ b/vectors/cryptography_vectors/asymmetric/DH/dhp_rfc5114_2.der
Binary files differ
diff --git a/vectors/cryptography_vectors/asymmetric/DH/dhp_rfc5114_2.pem b/vectors/cryptography_vectors/asymmetric/DH/dhp_rfc5114_2.pem
new file mode 100644
index 00000000..8887cb17
--- /dev/null
+++ b/vectors/cryptography_vectors/asymmetric/DH/dhp_rfc5114_2.pem
@@ -0,0 +1,14 @@
+-----BEGIN X9.42 DH PARAMETERS-----
+MIICKQKCAQEArRB+HpEjqdDWYPqnlVnFH6INZOVoO5/RtUsVl7YdCnXm+hQd+VpW
+26+aPEB7od8V6z1oijCcGA4d5rhaEnSgpm0/gVKtasISkDfJ7e/aTfjZHo/vVbc5
+S3rVt9C2wSIHyfmNEe002/bGugssi7wnvmoA4KC5xJcIs7+KMXCRiDaBKGEwvImF
+2xYC5xRBXZMwJ4Jzx94x79xzEPcSH9WgdBWYfZrcCkhtzfk6zEQyg4cxXXXhmMZB
+pIDNhqG55YfovmDmnMkosrnFIXLkEwQumyPxCw4W55djybU9z0uoCinj+3PBa451
+uX7zY+L/ox9xz53lOE5xuBwKxN/+DBDmTwKCAQEArEAy708tmuOd8wtcj/2sUGze
+vnuJmYyvdIZqCM/k/+OmgkpOELmm8N2SHwGnDEr6q3OddwDCn1LFfbF8YgqGUr5e
+kAGo1mrXwXZpEBmZAkr00CcnWsE0i7inYtBSG8mK4kcVBCLqHtQJk51U2nRgzbX2
+xrJQcXy+8YDrNBGOmNEZUppF1vg0Vm4wJeMWozDvu3eobwwasVsFGuPUKMj4rLcK
+gTcVC47rEOGD7dGZY93Z4mPkdwWJ72qiHn9fL/OBtTnM40CdE81Wavu0jWwBkYHh
+vP6UswJp7f5y/ptqpL17Wg8ccc//TBnEGOH27AF5gbwIfypwZbOEuJDTGR8r+gId
+AIAcDTTFjZP+mXF3EB+AU1pHOM68vziambNjces=
+-----END X9.42 DH PARAMETERS-----
diff --git a/vectors/cryptography_vectors/asymmetric/DH/dhpub_rfc5114_2.der b/vectors/cryptography_vectors/asymmetric/DH/dhpub_rfc5114_2.der
new file mode 100644
index 00000000..ba8aec90
--- /dev/null
+++ b/vectors/cryptography_vectors/asymmetric/DH/dhpub_rfc5114_2.der
Binary files differ
diff --git a/vectors/cryptography_vectors/asymmetric/DH/dhpub_rfc5114_2.pem b/vectors/cryptography_vectors/asymmetric/DH/dhpub_rfc5114_2.pem
new file mode 100644
index 00000000..94a7170a
--- /dev/null
+++ b/vectors/cryptography_vectors/asymmetric/DH/dhpub_rfc5114_2.pem
@@ -0,0 +1,20 @@
+-----BEGIN PUBLIC KEY-----
+MIIDRDCCAjYGByqGSM4+AgEwggIpAoIBAQCtEH4ekSOp0NZg+qeVWcUfog1k5Wg7
+n9G1SxWXth0Kdeb6FB35Wlbbr5o8QHuh3xXrPWiKMJwYDh3muFoSdKCmbT+BUq1q
+whKQN8nt79pN+Nkej+9VtzlLetW30LbBIgfJ+Y0R7TTb9sa6CyyLvCe+agDgoLnE
+lwizv4oxcJGINoEoYTC8iYXbFgLnFEFdkzAngnPH3jHv3HMQ9xIf1aB0FZh9mtwK
+SG3N+TrMRDKDhzFddeGYxkGkgM2Gobnlh+i+YOacySiyucUhcuQTBC6bI/ELDhbn
+l2PJtT3PS6gKKeP7c8FrjnW5fvNj4v+jH3HPneU4TnG4HArE3/4MEOZPAoIBAQCs
+QDLvTy2a453zC1yP/axQbN6+e4mZjK90hmoIz+T/46aCSk4Quabw3ZIfAacMSvqr
+c513AMKfUsV9sXxiCoZSvl6QAajWatfBdmkQGZkCSvTQJydawTSLuKdi0FIbyYri
+RxUEIuoe1AmTnVTadGDNtfbGslBxfL7xgOs0EY6Y0RlSmkXW+DRWbjAl4xajMO+7
+d6hvDBqxWwUa49QoyPistwqBNxULjusQ4YPt0Zlj3dniY+R3BYnvaqIef18v84G1
+OczjQJ0TzVZq+7SNbAGRgeG8/pSzAmnt/nL+m2qkvXtaDxxxz/9MGcQY4fbsAXmB
+vAh/KnBls4S4kNMZHyv6Ah0AgBwNNMWNk/6ZcXcQH4BTWkc4zry/OJqZs2Nx6wOC
+AQYAAoIBAQCCwWW7V2JD7PRtWMPRUBYWlV/KAyD6leoR0ubBuc8hdnZyDcHAjIW/
+IMTSMrYKKaHlHHt3O8ZFAUWHxSXIYVGzDXVIbse2yY77X3SVW4MRbQHQrxIyr4kh
+PC3ldDadcBq6k1cwC5INPYuYJS1GxGlSwWpfM1VLODF4Cce5rdRwH1wVjBtwNen+
+OTZuzsuQ0olreMUjxKV3KH71unomY+1YqiC17GbjDzFmEN+qOFg+SVq2r3ccKEOH
+5mDtvvTtuHLi6A4dJE7pViLnbQKOYcHoh8KqeScXNiE59N0m6v1JsjZu6yNQsB/h
+tWAiooCeN5VZw3s3W6AcTqrMFP0bJHg3
+-----END PUBLIC KEY-----