Merge pull request #950 from Ayrx/cmac-multibackend
CMAC multibackend
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 9e89e56..106e0ab 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -11,6 +11,8 @@
to :class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS`. It will be
removed from ``MGF1`` in two releases per our :doc:`/api-stability` policy.
+* Added :class:`~cryptography.hazmat.primitives.cmac.CMAC`.
+
0.3 - 2014-03-27
~~~~~~~~~~~~~~~~
diff --git a/cryptography/hazmat/backends/multibackend.py b/cryptography/hazmat/backends/multibackend.py
index 86cded8..981a60b 100644
--- a/cryptography/hazmat/backends/multibackend.py
+++ b/cryptography/hazmat/backends/multibackend.py
@@ -16,11 +16,12 @@
from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.backends.interfaces import (
- CipherBackend, DSABackend, HMACBackend, HashBackend, PBKDF2HMACBackend,
- RSABackend
+ CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend,
+ PBKDF2HMACBackend, RSABackend
)
+@utils.register_interface(CMACBackend)
@utils.register_interface(CipherBackend)
@utils.register_interface(HashBackend)
@utils.register_interface(HMACBackend)
@@ -156,3 +157,18 @@
return b.generate_dsa_private_key(parameters)
raise UnsupportedAlgorithm("DSA is not supported by the backend",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def cmac_algorithm_supported(self, algorithm):
+ return any(
+ b.cmac_algorithm_supported(algorithm)
+ for b in self._filtered_backends(CMACBackend)
+ )
+
+ def create_cmac_ctx(self, algorithm):
+ for b in self._filtered_backends(CMACBackend):
+ try:
+ return b.create_cmac_ctx(algorithm)
+ except UnsupportedAlgorithm:
+ pass
+ raise UnsupportedAlgorithm("This backend does not support CMAC",
+ _Reasons.UNSUPPORTED_CIPHER)
diff --git a/docs/hazmat/primitives/mac/cmac.rst b/docs/hazmat/primitives/mac/cmac.rst
index 8b88a3c..a6b048b 100644
--- a/docs/hazmat/primitives/mac/cmac.rst
+++ b/docs/hazmat/primitives/mac/cmac.rst
@@ -19,10 +19,12 @@
.. class:: CMAC(algorithm, backend)
+ .. versionadded:: 0.4
+
CMAC objects take a
:class:`~cryptography.hazmat.primitives.interfaces.BlockCipherAlgorithm` provider.
- .. code-block:: pycon
+ .. doctest::
>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives import cmac
diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py
index f46009d..d8c09bd 100644
--- a/tests/hazmat/backends/test_multibackend.py
+++ b/tests/hazmat/backends/test_multibackend.py
@@ -18,11 +18,11 @@
UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import (
- CipherBackend, DSABackend, HMACBackend, HashBackend, PBKDF2HMACBackend,
- RSABackend
+ CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend,
+ PBKDF2HMACBackend, RSABackend
)
from cryptography.hazmat.backends.multibackend import MultiBackend
-from cryptography.hazmat.primitives import hashes, hmac
+from cryptography.hazmat.primitives import cmac, hashes, hmac
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
@@ -108,6 +108,19 @@
pass
+@utils.register_interface(CMACBackend)
+class DummyCMACBackend(object):
+ def __init__(self, supported_algorithms):
+ self._algorithms = supported_algorithms
+
+ def cmac_algorithm_supported(self, algorithm):
+ return type(algorithm) in self._algorithms
+
+ def create_cmac_ctx(self, algorithm):
+ if not self.cmac_algorithm_supported(algorithm):
+ raise UnsupportedAlgorithm("", _Reasons.UNSUPPORTED_CIPHER)
+
+
class TestMultiBackend(object):
def test_ciphers(self):
backend = MultiBackend([
@@ -224,3 +237,18 @@
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
):
backend.generate_dsa_private_key(parameters)
+
+ def test_cmac(self):
+ backend = MultiBackend([
+ DummyCMACBackend([algorithms.AES])
+ ])
+
+ fake_key = b"\x00" * 16
+
+ assert backend.cmac_algorithm_supported(
+ algorithms.AES(fake_key)) is True
+
+ cmac.CMAC(algorithms.AES(fake_key), backend)
+
+ with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER):
+ cmac.CMAC(algorithms.TripleDES(fake_key), backend)