diff options
-rw-r--r-- | cryptography/hazmat/backends/__init__.py | 13 | ||||
-rw-r--r-- | cryptography/hazmat/backends/commoncrypto/__init__.py | 17 | ||||
-rw-r--r-- | cryptography/hazmat/backends/commoncrypto/backend.py | 128 |
3 files changed, 155 insertions, 3 deletions
diff --git a/cryptography/hazmat/backends/__init__.py b/cryptography/hazmat/backends/__init__.py index 215aa4d3..54a227b7 100644 --- a/cryptography/hazmat/backends/__init__.py +++ b/cryptography/hazmat/backends/__init__.py @@ -13,10 +13,17 @@ from cryptography.hazmat.backends import openssl +_POTENTIAL_BACKENDS = ["openssl", "commoncrypto"] -_ALL_BACKENDS = [ - openssl.backend -] +_ALL_BACKENDS = [] + +for b in _POTENTIAL_BACKENDS: + binding = __import__("cryptography.hazmat.bindings.{0}.binding".format(b), + fromlist=["binding"]) + if binding.Binding.is_available(): + backend = __import__("cryptography.hazmat.backends.{0}".format(b), + fromlist=["backend"]) + _ALL_BACKENDS.append(backend.backend) def default_backend(): diff --git a/cryptography/hazmat/backends/commoncrypto/__init__.py b/cryptography/hazmat/backends/commoncrypto/__init__.py new file mode 100644 index 00000000..64a1c01c --- /dev/null +++ b/cryptography/hazmat/backends/commoncrypto/__init__.py @@ -0,0 +1,17 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from cryptography.hazmat.backends.commoncrypto.backend import backend + + +__all__ = ["backend"] diff --git a/cryptography/hazmat/backends/commoncrypto/backend.py b/cryptography/hazmat/backends/commoncrypto/backend.py new file mode 100644 index 00000000..efbd6bab --- /dev/null +++ b/cryptography/hazmat/backends/commoncrypto/backend.py @@ -0,0 +1,128 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import absolute_import, division, print_function + +from collections import namedtuple + +from cryptography import utils +from cryptography.exceptions import UnsupportedAlgorithm +from cryptography.hazmat.backends.interfaces import ( + HashBackend, +) +from cryptography.hazmat.bindings.commoncrypto.binding import Binding +from cryptography.hazmat.primitives import interfaces + + +@utils.register_interface(HashBackend) +class Backend(object): + """ + CommonCrypto API wrapper. + """ + hashtuple = namedtuple("HashClass", ["struct", "init", "update", "final"]) + + def __init__(self): + self._binding = Binding() + self._ffi = self._binding.ffi + self._lib = self._binding.lib + + self.hash_methods = { + b"md5": self.hashtuple( + "CC_MD5_CTX *", self._lib.CC_MD5_Init, + self._lib.CC_MD5_Update, self._lib.CC_MD5_Final + ), + b"sha1": self.hashtuple( + "CC_SHA1_CTX *", self._lib.CC_SHA1_Init, + self._lib.CC_SHA1_Update, self._lib.CC_SHA1_Final + ), + b"sha224": self.hashtuple( + "CC_SHA256_CTX *", self._lib.CC_SHA224_Init, + self._lib.CC_SHA224_Update, self._lib.CC_SHA224_Final + ), + b"sha256": self.hashtuple( + "CC_SHA256_CTX *", self._lib.CC_SHA256_Init, + self._lib.CC_SHA256_Update, self._lib.CC_SHA256_Final + ), + b"sha384": self.hashtuple( + "CC_SHA512_CTX *", self._lib.CC_SHA384_Init, + self._lib.CC_SHA384_Update, self._lib.CC_SHA384_Final + ), + b"sha512": self.hashtuple( + "CC_SHA512_CTX *", self._lib.CC_SHA512_Init, + self._lib.CC_SHA512_Update, self._lib.CC_SHA512_Final + ), + } + + def hash_supported(self, algorithm): + try: + self.hash_methods[algorithm.name.encode("ascii")] + return True + except KeyError: + return False + + def create_hash_ctx(self, algorithm): + return _HashContext(self, algorithm) + + +@utils.register_interface(interfaces.HashContext) +class _HashContext(object): + def __init__(self, backend, algorithm, ctx=None): + self.algorithm = algorithm + self._backend = backend + + if ctx is None: + try: + methods = self._backend.hash_methods[ + self.algorithm.name.encode("ascii") + ] + except KeyError: + raise UnsupportedAlgorithm( + "{0} is not a supported hash on this backend".format( + algorithm.name) + ) + ctx = self._backend._ffi.new(methods.struct) + res = methods.init(ctx) + assert res == 1 + + self._ctx = ctx + + def copy(self): + methods = self._backend.hash_methods[ + self.algorithm.name.encode("ascii") + ] + new_ctx = self._backend._ffi.new(methods.struct) + # CommonCrypto has no APIs for copying hashes, so we have to copy the + # underlying struct. + new_ctx[0] = self._ctx[0] + + return _HashContext(self._backend, self.algorithm, ctx=new_ctx) + + def update(self, data): + methods = self._backend.hash_methods[ + self.algorithm.name.encode("ascii") + ] + res = methods.update(self._ctx, data, len(data)) + assert res == 1 + + def finalize(self): + methods = self._backend.hash_methods[ + self.algorithm.name.encode("ascii") + ] + buf = self._backend._ffi.new("unsigned char[]", + self.algorithm.digest_size) + res = methods.final(buf, self._ctx) + assert res == 1 + return self._backend._ffi.buffer(buf)[:] + + +backend = Backend() |