Merge pull request #335 from exarkun/pyopenssl-test_crypto-with-optionals
Pyopenssl test crypto with optionals
diff --git a/cryptography/exceptions.py b/cryptography/exceptions.py
index e9d8819..44363c2 100644
--- a/cryptography/exceptions.py
+++ b/cryptography/exceptions.py
@@ -30,3 +30,7 @@
class InvalidTag(Exception):
pass
+
+
+class InvalidSignature(Exception):
+ pass
diff --git a/cryptography/hazmat/primitives/hmac.py b/cryptography/hazmat/primitives/hmac.py
index 618bccc..76d658a 100644
--- a/cryptography/hazmat/primitives/hmac.py
+++ b/cryptography/hazmat/primitives/hmac.py
@@ -16,8 +16,8 @@
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 @@
digest = self._ctx.finalize()
self._ctx = None
return digest
+
+ def verify(self, signature):
+ if isinstance(signature, six.text_type):
+ raise TypeError("Unicode-objects must be encoded before verifying")
+ digest = self.finalize()
+ if not constant_time.bytes_eq(digest, signature):
+ raise InvalidSignature("Signature did not match digest.")
diff --git a/docs/exceptions.rst b/docs/exceptions.rst
index 087066b..1fbd326 100644
--- a/docs/exceptions.rst
+++ b/docs/exceptions.rst
@@ -8,6 +8,12 @@
This is raised when a context is used after being finalized.
+.. class:: InvalidSignature
+
+ This is raised when the verify method of a hash context does not
+ compare equal.
+
+
.. class:: NotYetFinalized
This is raised when the AEAD tag property is accessed on a context
diff --git a/docs/hazmat/primitives/hmac.rst b/docs/hazmat/primitives/hmac.rst
index 0547b7d..b8f94fd 100644
--- a/docs/hazmat/primitives/hmac.rst
+++ b/docs/hazmat/primitives/hmac.rst
@@ -71,3 +71,11 @@
:return bytes: The message digest as bytes.
:raises cryptography.exceptions.AlreadyFinalized:
+
+ .. method:: verify(signature)
+
+ Finalize the current context and securely compare digest to ``signature``.
+
+ :param bytes signature: The bytes of the HMAC signature recieved.
+ :raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`
+ :raises cryptography.exceptions.InvalidSignature: If signature does not match digest
diff --git a/tests/hazmat/primitives/test_hmac.py b/tests/hazmat/primitives/test_hmac.py
index 6d8cc27..7acb78b 100644
--- a/tests/hazmat/primitives/test_hmac.py
+++ b/tests/hazmat/primitives/test_hmac.py
@@ -20,7 +20,9 @@
import six
from cryptography import utils
-from cryptography.exceptions import AlreadyFinalized, UnsupportedAlgorithm
+from cryptography.exceptions import (
+ AlreadyFinalized, UnsupportedAlgorithm, InvalidSignature
+)
from cryptography.hazmat.primitives import hashes, hmac, interfaces
from .utils import generate_base_hmac_test
@@ -71,6 +73,29 @@
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(''))
+
def test_unsupported_hash(self, backend):
with pytest.raises(UnsupportedAlgorithm):
hmac.HMAC(b"key", UnsupportedDummyHash(), backend)