Merge branch 'master' into common-crypto-backend
* master: (24 commits)
Expose the innards of DH and DSA
More bindings for asymmetric stuff
Tell cffi these opaque types are pointers.
rename variable to be less confusing and terrible
Document when the common crypto bindings were added
Expose a name needed for ECDHE -- the NIDs are always available
Expose the nids for the various eliptical curve things. I don't understand what these mean.
Specify the epub theme to fix the epub build on RTD.
Added forgotten decl
reversed
Allow these to not be defined because lololol fedora/centos
add conditional ERR_remove_thread_state. PyOpenSSL uses this
Don't require sphinx spelling to be installed, for readthedocs benefit
This is also a requirement
oops
Start binding some stuff for ECDHE in pyOpenSSL.
check if openssl is installed via homebrew on osx. install if not
Verify the tag len for GCM
remove comment that's no longer needed
Make just one call to ffi.cdef for most of the definitions
...
diff --git a/cryptography/hazmat/backends/__init__.py b/cryptography/hazmat/backends/__init__.py
index 215aa4d..cb1fee9 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 0000000..64a1c01
--- /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 0000000..efbd6ba
--- /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 0000000..edd45b6
--- /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 0695128..22354f6 100644
--- a/docs/hazmat/backends/index.rst
+++ b/docs/hazmat/backends/index.rst
@@ -31,4 +31,5 @@
:maxdepth: 1
openssl
+ common-crypto
interfaces
diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt
index 97356c2..b17bcde 100644
--- a/docs/spelling_wordlist.txt
+++ b/docs/spelling_wordlist.txt
@@ -26,3 +26,4 @@
Docstrings
Fernet
Schneier
+iOS