diff options
-rw-r--r-- | cryptography/exceptions.py | 4 | ||||
-rw-r--r-- | cryptography/hazmat/primitives/hashes.py | 11 | ||||
-rw-r--r-- | cryptography/hazmat/primitives/hmac.py | 11 | ||||
-rw-r--r-- | cryptography/hazmat/primitives/interfaces.py | 6 | ||||
-rw-r--r-- | docs/hazmat/primitives/cryptographic-hashes.rst | 7 | ||||
-rw-r--r-- | docs/hazmat/primitives/hmac.rst | 7 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_hashes.py | 25 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_hmac.py | 25 |
8 files changed, 90 insertions, 6 deletions
diff --git a/cryptography/exceptions.py b/cryptography/exceptions.py index e9d88199..44363c24 100644 --- a/cryptography/exceptions.py +++ b/cryptography/exceptions.py @@ -30,3 +30,7 @@ class NotYetFinalized(Exception): class InvalidTag(Exception): pass + + +class InvalidSignature(Exception): + pass diff --git a/cryptography/hazmat/primitives/hashes.py b/cryptography/hazmat/primitives/hashes.py index bee188b3..b3c626d4 100644 --- a/cryptography/hazmat/primitives/hashes.py +++ b/cryptography/hazmat/primitives/hashes.py @@ -16,8 +16,8 @@ from __future__ import absolute_import, division, print_function import six from cryptography import utils -from cryptography.exceptions import AlreadyFinalized -from cryptography.hazmat.primitives import interfaces +from cryptography.exceptions import AlreadyFinalized, InvalidSignature +from cryptography.hazmat.primitives import constant_time, interfaces @utils.register_interface(interfaces.HashContext) @@ -55,6 +55,13 @@ class Hash(object): self._ctx = None return digest + def verify(self, sig): + if isinstance(sig, six.text_type): + raise TypeError("Unicode-objects must be encoded before verifying") + digest = self.finalize() + if not constant_time.bytes_eq(digest, sig): + raise InvalidSignature("Signature did not match digest.") + @utils.register_interface(interfaces.HashAlgorithm) class SHA1(object): diff --git a/cryptography/hazmat/primitives/hmac.py b/cryptography/hazmat/primitives/hmac.py index 618bccc5..8ade84aa 100644 --- a/cryptography/hazmat/primitives/hmac.py +++ b/cryptography/hazmat/primitives/hmac.py @@ -16,8 +16,8 @@ from __future__ import absolute_import, division, print_function import six from cryptography import utils -from cryptography.exceptions import AlreadyFinalized -from cryptography.hazmat.primitives import interfaces +from cryptography.exceptions import AlreadyFinalized, InvalidSignature +from cryptography.hazmat.primitives import constant_time, interfaces @utils.register_interface(interfaces.HashContext) @@ -57,3 +57,10 @@ class HMAC(object): digest = self._ctx.finalize() self._ctx = None return digest + + def verify(self, sig): + if isinstance(sig, six.text_type): + raise TypeError("Unicode-objects must be encoded before verifying") + digest = self.finalize() + if not constant_time.bytes_eq(digest, sig): + raise InvalidSignature("Signature did not match digest.") diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py index e3f4f586..76dc9339 100644 --- a/cryptography/hazmat/primitives/interfaces.py +++ b/cryptography/hazmat/primitives/interfaces.py @@ -152,3 +152,9 @@ class HashContext(six.with_metaclass(abc.ABCMeta)): """ return a HashContext that is a copy of the current context. """ + + @abc.abstractmethod + def verify(self, sig): + """ + compare digest to sig and raise exception if not equal. + """ diff --git a/docs/hazmat/primitives/cryptographic-hashes.rst b/docs/hazmat/primitives/cryptographic-hashes.rst index 90ca198a..02c7b5e1 100644 --- a/docs/hazmat/primitives/cryptographic-hashes.rst +++ b/docs/hazmat/primitives/cryptographic-hashes.rst @@ -67,6 +67,13 @@ Message Digests :return bytes: The message digest as bytes. + .. method:: verify(sig) + + Finalize the current context and securely compare digest to sig. + + :raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize` + :raises cryptography.exceptions.InvalidSignature: If sig does not match digest + .. _cryptographic-hash-algorithms: diff --git a/docs/hazmat/primitives/hmac.rst b/docs/hazmat/primitives/hmac.rst index 0c0d0220..b556bd6a 100644 --- a/docs/hazmat/primitives/hmac.rst +++ b/docs/hazmat/primitives/hmac.rst @@ -69,3 +69,10 @@ message. :return bytes: The message digest as bytes. :raises cryptography.exceptions.AlreadyFinalized: + + .. method:: verify(sig) + + Finalize the current context and securely compare digest to sig. + + :raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize` + :raises cryptography.exceptions.InvalidSignature: If sig does not match digest diff --git a/tests/hazmat/primitives/test_hashes.py b/tests/hazmat/primitives/test_hashes.py index ff42e8f4..cd58b065 100644 --- a/tests/hazmat/primitives/test_hashes.py +++ b/tests/hazmat/primitives/test_hashes.py @@ -19,7 +19,7 @@ import pytest import six -from cryptography.exceptions import AlreadyFinalized +from cryptography.exceptions import AlreadyFinalized, InvalidSignature from cryptography.hazmat.primitives import hashes from .utils import generate_base_hash_test @@ -57,6 +57,29 @@ class TestHashContext(object): with pytest.raises(AlreadyFinalized): h.finalize() + def test_verify(self, backend): + h = hashes.Hash(hashes.SHA1(), backend=backend) + digest = h.finalize() + + h = hashes.Hash(hashes.SHA1(), backend=backend) + h.verify(digest) + + with pytest.raises(AlreadyFinalized): + h.verify(b'') + + def test_invalid_verify(self, backend): + h = hashes.Hash(hashes.SHA1(), backend=backend) + with pytest.raises(InvalidSignature): + h.verify(b'') + + with pytest.raises(AlreadyFinalized): + h.verify(b'') + + def test_verify_reject_unicode(self, backend): + h = hashes.Hash(hashes.SHA1(), backend=backend) + with pytest.raises(TypeError): + h.verify(six.u('')) + class TestSHA1(object): test_SHA1 = generate_base_hash_test( diff --git a/tests/hazmat/primitives/test_hmac.py b/tests/hazmat/primitives/test_hmac.py index 992bcb1a..48360185 100644 --- a/tests/hazmat/primitives/test_hmac.py +++ b/tests/hazmat/primitives/test_hmac.py @@ -19,7 +19,7 @@ import pytest import six -from cryptography.exceptions import AlreadyFinalized +from cryptography.exceptions import AlreadyFinalized, InvalidSignature from cryptography.hazmat.primitives import hashes, hmac from .utils import generate_base_hmac_test @@ -63,3 +63,26 @@ class TestHMAC(object): with pytest.raises(AlreadyFinalized): h.finalize() + + def test_verify(self, backend): + h = hmac.HMAC(b'', hashes.SHA1(), backend=backend) + digest = h.finalize() + + h = hmac.HMAC(b'', hashes.SHA1(), backend=backend) + h.verify(digest) + + with pytest.raises(AlreadyFinalized): + h.verify(b'') + + def test_invalid_verify(self, backend): + h = hmac.HMAC(b'', hashes.SHA1(), backend=backend) + with pytest.raises(InvalidSignature): + h.verify(b'') + + with pytest.raises(AlreadyFinalized): + h.verify(b'') + + def test_verify_reject_unicode(self, backend): + h = hmac.HMAC(b'', hashes.SHA1(), backend=backend) + with pytest.raises(TypeError): + h.verify(six.u('')) |