From 6012ccff0d709a80259f93a406eca5d133b40108 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 20 Nov 2016 23:45:06 +0800 Subject: support prehashed sign/verify in DSA (#3266) --- docs/hazmat/primitives/asymmetric/dsa.rst | 14 ++++++-- src/cryptography/hazmat/backends/openssl/dsa.py | 20 +++++++---- tests/hazmat/primitives/test_dsa.py | 47 ++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 10 deletions(-) diff --git a/docs/hazmat/primitives/asymmetric/dsa.rst b/docs/hazmat/primitives/asymmetric/dsa.rst index 126cdc28..d4c25256 100644 --- a/docs/hazmat/primitives/asymmetric/dsa.rst +++ b/docs/hazmat/primitives/asymmetric/dsa.rst @@ -301,6 +301,9 @@ Key interfaces .. method:: sign(data, algorithm) .. versionadded:: 1.5 + .. versionchanged:: 1.6 + :class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed` + can now be used as an ``algorithm``. Sign one block of data which can be verified later by others using the public key. @@ -308,7 +311,9 @@ Key interfaces :param bytes data: The message string to sign. :param algorithm: An instance of - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` or + :class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed` + if the ``data`` you want to sign has already been hashed. :return bytes: Signature. @@ -424,6 +429,9 @@ Key interfaces .. method:: verify(signature, data, algorithm) .. versionadded:: 1.5 + .. versionchanged:: 1.6 + :class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed` + can now be used as an ``algorithm``. Verify one block of data was signed by the private key associated with this public key. @@ -433,7 +441,9 @@ Key interfaces :param bytes data: The message string that was signed. :param algorithm: An instance of - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` or + :class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed` + if the ``data`` you want to sign has already been hashed. :raises cryptography.exceptions.InvalidSignature: If the signature does not validate. diff --git a/src/cryptography/hazmat/backends/openssl/dsa.py b/src/cryptography/hazmat/backends/openssl/dsa.py index 07d2c3bc..e82c043d 100644 --- a/src/cryptography/hazmat/backends/openssl/dsa.py +++ b/src/cryptography/hazmat/backends/openssl/dsa.py @@ -6,7 +6,9 @@ from __future__ import absolute_import, division, print_function from cryptography import utils from cryptography.exceptions import InvalidSignature -from cryptography.hazmat.backends.openssl.utils import _truncate_digest +from cryptography.hazmat.backends.openssl.utils import ( + _calculate_digest_and_algorithm, _truncate_digest +) from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ( AsymmetricSignatureContext, AsymmetricVerificationContext, dsa @@ -207,9 +209,11 @@ class _DSAPrivateKey(object): ) def sign(self, data, algorithm): - signer = self.signer(algorithm) - signer.update(data) - return signer.finalize() + data, algorithm = _calculate_digest_and_algorithm( + self._backend, data, algorithm + ) + data = _truncate_digest_for_dsa(self._dsa_cdata, data, self._backend) + return _dsa_sig_sign(self._backend, self, data) @utils.register_interface(dsa.DSAPublicKeyWithSerialization) @@ -279,6 +283,8 @@ class _DSAPublicKey(object): ) def verify(self, signature, data, algorithm): - verifier = self.verifier(signature, algorithm) - verifier.update(data) - verifier.verify() + data, algorithm = _calculate_digest_and_algorithm( + self._backend, data, algorithm + ) + data = _truncate_digest_for_dsa(self._dsa_cdata, data, self._backend) + return _dsa_sig_verify(self._backend, self, signature, data) diff --git a/tests/hazmat/primitives/test_dsa.py b/tests/hazmat/primitives/test_dsa.py index dde60607..8160ad99 100644 --- a/tests/hazmat/primitives/test_dsa.py +++ b/tests/hazmat/primitives/test_dsa.py @@ -16,7 +16,7 @@ from cryptography.hazmat.backends.interfaces import ( from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import dsa from cryptography.hazmat.primitives.asymmetric.utils import ( - encode_dss_signature + Prehashed, encode_dss_signature ) from cryptography.utils import bit_length @@ -616,6 +616,28 @@ class TestDSAVerification(object): public_key = private_key.public_key() public_key.verify(signature, message, algorithm) + def test_prehashed_verify(self, backend): + private_key = DSA_KEY_1024.private_key(backend) + message = b"one little message" + h = hashes.Hash(hashes.SHA1(), backend) + h.update(message) + digest = h.finalize() + prehashed_alg = Prehashed(hashes.SHA1()) + signature = private_key.sign(message, hashes.SHA1()) + public_key = private_key.public_key() + public_key.verify(signature, digest, prehashed_alg) + + def test_prehashed_digest_mismatch(self, backend): + private_key = DSA_KEY_1024.private_key(backend) + public_key = private_key.public_key() + message = b"one little message" + h = hashes.Hash(hashes.SHA1(), backend) + h.update(message) + digest = h.finalize() + prehashed_alg = Prehashed(hashes.SHA224()) + with pytest.raises(ValueError): + public_key.verify(b"\x00" * 128, digest, prehashed_alg) + @pytest.mark.requires_backend_interface(interface=DSABackend) class TestDSASignature(object): @@ -681,6 +703,29 @@ class TestDSASignature(object): verifier.update(message) verifier.verify() + def test_prehashed_sign(self, backend): + private_key = DSA_KEY_1024.private_key(backend) + message = b"one little message" + h = hashes.Hash(hashes.SHA1(), backend) + h.update(message) + digest = h.finalize() + prehashed_alg = Prehashed(hashes.SHA1()) + signature = private_key.sign(digest, prehashed_alg) + public_key = private_key.public_key() + verifier = public_key.verifier(signature, hashes.SHA1()) + verifier.update(message) + verifier.verify() + + def test_prehashed_digest_mismatch(self, backend): + private_key = DSA_KEY_1024.private_key(backend) + message = b"one little message" + h = hashes.Hash(hashes.SHA1(), backend) + h.update(message) + digest = h.finalize() + prehashed_alg = Prehashed(hashes.SHA224()) + with pytest.raises(ValueError): + private_key.sign(digest, prehashed_alg) + class TestDSANumbers(object): def test_dsa_parameter_numbers(self): -- cgit v1.2.3