aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cryptography/hazmat/backends/__init__.py10
-rw-r--r--cryptography/hazmat/backends/commoncrypto/__init__.py17
-rw-r--r--cryptography/hazmat/backends/commoncrypto/backend.py128
-rw-r--r--docs/hazmat/backends/common-crypto.rst28
-rw-r--r--docs/hazmat/backends/index.rst1
-rw-r--r--docs/spelling_wordlist.txt1
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