diff options
-rw-r--r-- | cryptography/hazmat/backends/__init__.py | 10 | ||||
-rw-r--r-- | cryptography/hazmat/backends/commoncrypto/__init__.py | 17 | ||||
-rw-r--r-- | cryptography/hazmat/backends/commoncrypto/backend.py | 128 | ||||
-rw-r--r-- | docs/hazmat/backends/common-crypto.rst | 28 | ||||
-rw-r--r-- | docs/hazmat/backends/index.rst | 1 | ||||
-rw-r--r-- | docs/spelling_wordlist.txt | 1 |
6 files changed, 182 insertions, 3 deletions
diff --git a/cryptography/hazmat/backends/__init__.py b/cryptography/hazmat/backends/__init__.py index 215aa4d3..cb1fee90 100644 --- a/cryptography/hazmat/backends/__init__.py +++ b/cryptography/hazmat/backends/__init__.py @@ -12,11 +12,15 @@ # limitations under the License. from cryptography.hazmat.backends import openssl +from cryptography.hazmat.bindings.commoncrypto.binding import ( + Binding as CCBinding +) +_ALL_BACKENDS = [openssl.backend] -_ALL_BACKENDS = [ - openssl.backend -] +if CCBinding.is_available(): + from cryptography.hazmat.backends import commoncrypto + _ALL_BACKENDS.append(commoncrypto.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() diff --git a/docs/hazmat/backends/common-crypto.rst b/docs/hazmat/backends/common-crypto.rst new file mode 100644 index 00000000..edd45b6b --- /dev/null +++ b/docs/hazmat/backends/common-crypto.rst @@ -0,0 +1,28 @@ +.. hazmat:: + +CommonCrypto Backend +==================== + +These are `CFFI`_ bindings to the `CommonCrypto`_ C library provided by Apple +on OS X and iOS. + +.. currentmodule:: cryptography.hazmat.backends.commoncrypto.backend + +.. data:: cryptography.hazmat.backends.commoncrypto.backend + + This is the exposed API for the CommonCrypto bindings. It has two public + attributes: + + .. attribute:: ffi + + This is a :class:`cffi.FFI` instance. It can be used to allocate and + otherwise manipulate CommonCrypto structures. + + .. attribute:: lib + + This is a ``cffi`` library. It can be used to call CommonCrypto + functions, and access constants. + + +.. _`CFFI`: https://cffi.readthedocs.org/ +.. _`CommonCrypto`: https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/Common%20Crypto.3cc.html diff --git a/docs/hazmat/backends/index.rst b/docs/hazmat/backends/index.rst index 06951281..22354f69 100644 --- a/docs/hazmat/backends/index.rst +++ b/docs/hazmat/backends/index.rst @@ -31,4 +31,5 @@ Individual Backends :maxdepth: 1 openssl + common-crypto interfaces diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index 97356c24..b17bcde0 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -26,3 +26,4 @@ Changelog Docstrings Fernet Schneier +iOS |