aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorFacundo Tuesca <facundo.tuesca@trailofbits.com>2024-02-26 20:13:47 +0100
committerGitHub <noreply@github.com>2024-02-26 19:13:47 +0000
commit0a1098fcf09dfb7aef75ec87d29fb133deb0d70d (patch)
tree205c490ac6fb7ddff924e764ef3089c63b3d2f65 /tests
parent4bfd3216380c7925609c46759f9c6c48d78a4697 (diff)
downloadpyca-cryptography-0a1098fcf09dfb7aef75ec87d29fb133deb0d70d.zip
pyca-cryptography-0a1098fcf09dfb7aef75ec87d29fb133deb0d70d.tar.gz
pyca-cryptography-0a1098fcf09dfb7aef75ec87d29fb133deb0d70d.tar.bz2
Support for ECDSA deterministic signing (RFC 6979) (#10369)
* Add support for deterministic ECDSA (RFC 6979)
Diffstat (limited to 'tests')
-rw-r--r--tests/hazmat/primitives/test_ec.py67
-rw-r--r--tests/utils.py51
2 files changed, 118 insertions, 0 deletions
diff --git a/tests/hazmat/primitives/test_ec.py b/tests/hazmat/primitives/test_ec.py
index a558af3..33b4c6d 100644
--- a/tests/hazmat/primitives/test_ec.py
+++ b/tests/hazmat/primitives/test_ec.py
@@ -16,6 +16,10 @@ from cryptography import exceptions, utils, x509
from cryptography.hazmat.bindings._rust import openssl as rust_openssl
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec
+from cryptography.hazmat.primitives.asymmetric.ec import (
+ EllipticCurvePrivateKey,
+ EllipticCurvePublicKey,
+)
from cryptography.hazmat.primitives.asymmetric.utils import (
Prehashed,
encode_dss_signature,
@@ -27,6 +31,7 @@ from ...utils import (
load_fips_ecdsa_signing_vectors,
load_kasvs_ecdh_vectors,
load_nist_vectors,
+ load_rfc6979_vectors,
load_vectors_from_file,
raises_unsupported_algorithm,
)
@@ -508,6 +513,68 @@ class TestECDSAVectors:
signature, vector["message"], ec.ECDSA(hash_type())
)
+ def test_unsupported_deterministic_nonce(self, backend):
+ if backend.ecdsa_deterministic_supported():
+ pytest.skip(
+ f"ECDSA deterministic signing is supported by this"
+ f" backend {backend}"
+ )
+ with pytest.raises(exceptions.UnsupportedAlgorithm):
+ ec.ECDSA(hashes.SHA256(), deterministic_signing=True)
+
+ def test_deterministic_nonce(self, backend, subtests):
+ if not backend.ecdsa_deterministic_supported():
+ pytest.skip(
+ f"ECDSA deterministic signing is not supported by this"
+ f" backend {backend}"
+ )
+
+ supported_hash_algorithms = {
+ "SHA1": hashes.SHA1(),
+ "SHA224": hashes.SHA224(),
+ "SHA256": hashes.SHA256(),
+ "SHA384": hashes.SHA384(),
+ "SHA512": hashes.SHA512(),
+ }
+ vectors = load_vectors_from_file(
+ os.path.join(
+ "asymmetric", "ECDSA", "RFC6979", "evppkey_ecdsa_rfc6979.txt"
+ ),
+ load_rfc6979_vectors,
+ )
+
+ for vector in vectors:
+ with subtests.test():
+ input = bytes(vector["input"], "utf-8")
+ output = bytes.fromhex(vector["output"])
+ key = bytes("\n".join(vector["key"]), "utf-8")
+ if "digest_sign" in vector:
+ algorithm = vector["digest_sign"]
+ hash_algorithm = supported_hash_algorithms[algorithm]
+ algorithm = ec.ECDSA(
+ hash_algorithm,
+ deterministic_signing=vector["deterministic_nonce"],
+ )
+ private_key = serialization.load_pem_private_key(
+ key, password=None
+ )
+ assert isinstance(private_key, EllipticCurvePrivateKey)
+ signature = private_key.sign(input, algorithm)
+ assert signature == output
+ else:
+ assert "digest_verify" in vector
+ algorithm = vector["digest_verify"]
+ assert algorithm in supported_hash_algorithms
+ hash_algorithm = supported_hash_algorithms[algorithm]
+ algorithm = ec.ECDSA(hash_algorithm)
+ public_key = serialization.load_pem_public_key(key)
+ assert isinstance(public_key, EllipticCurvePublicKey)
+ if vector["verify_error"]:
+ with pytest.raises(exceptions.InvalidSignature):
+ public_key.verify(output, input, algorithm)
+ else:
+ public_key.verify(output, input, algorithm)
+
def test_sign(self, backend):
_skip_curve_unsupported(backend, ec.SECP256R1())
message = b"one little message"
diff --git a/tests/utils.py b/tests/utils.py
index 595e8dc..c1aa34e 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -701,6 +701,57 @@ def load_kasvs_ecdh_vectors(vector_data):
return vectors
+def load_rfc6979_vectors(vector_data):
+ """
+ Loads data out of the ECDSA and DSA RFC6979 vector files.
+ """
+ vectors = []
+ keys: typing.Dict[str, typing.List[str]] = dict()
+ reading_key = False
+ current_key_name = None
+
+ data: typing.Dict[str, object] = dict()
+ for line in vector_data:
+ line = line.strip()
+
+ if reading_key and current_key_name:
+ keys[current_key_name].append(line)
+ if line.startswith("-----END"):
+ reading_key = False
+ current_key_name = None
+
+ if line.startswith("PrivateKey=") or line.startswith("PublicKey="):
+ reading_key = True
+ current_key_name = line.split("=")[1].strip()
+ keys[current_key_name] = []
+ elif line.startswith("DigestSign = "):
+ data["digest_sign"] = line.split("=")[1].strip()
+ data["deterministic_nonce"] = False
+ elif line.startswith("DigestVerify = "):
+ data["digest_verify"] = line.split("=")[1].strip()
+ data["verify_error"] = False
+ elif line.startswith("Key = "):
+ key_name = line.split("=")[1].strip()
+ assert key_name in keys
+ data["key"] = keys[key_name]
+ elif line.startswith("NonceType = "):
+ nonce_type = line.split("=")[1].strip()
+ data["deterministic_nonce"] = nonce_type == "deterministic"
+ elif line.startswith("Input = "):
+ data["input"] = line.split("=")[1].strip(' "')
+ elif line.startswith("Output = "):
+ data["output"] = line.split("=")[1].strip()
+ elif line.startswith("Result = "):
+ data["verify_error"] = line.split("=")[1].strip() == "VERIFY_ERROR"
+
+ elif not line:
+ if data:
+ vectors.append(data)
+ data = {}
+
+ return vectors
+
+
def load_x963_vectors(vector_data):
"""
Loads data out of the X9.63 vector data