diff options
-rw-r--r-- | .travis.yml | 8 | ||||
-rwxr-xr-x | .travis/install.sh | 12 | ||||
-rw-r--r-- | CHANGELOG.rst | 7 | ||||
-rw-r--r-- | cryptography/hazmat/backends/openssl/backend.py | 49 | ||||
-rw-r--r-- | cryptography/hazmat/bindings/utils.py | 38 | ||||
-rw-r--r-- | cryptography/hazmat/primitives/interfaces.py | 6 | ||||
-rw-r--r-- | docs/hazmat/primitives/interfaces.rst | 8 | ||||
-rw-r--r-- | setup.py | 1 | ||||
-rw-r--r-- | tests/hazmat/bindings/test_utils.py | 25 | ||||
-rw-r--r-- | tox.ini | 2 |
10 files changed, 131 insertions, 25 deletions
diff --git a/.travis.yml b/.travis.yml index b7fa090e..7d5663d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,11 +16,13 @@ env: - TOX_ENV=py27 - TOX_ENV=py32 - TOX_ENV=py33 + - TOX_ENV=py34 - TOX_ENV=pypy - TOX_ENV=py26 OPENSSL=0.9.8 - TOX_ENV=py27 OPENSSL=0.9.8 - TOX_ENV=py32 OPENSSL=0.9.8 - TOX_ENV=py33 OPENSSL=0.9.8 + - TOX_ENV=py34 OPENSSL=0.9.8 - TOX_ENV=pypy OPENSSL=0.9.8 - TOX_ENV=docs - TOX_ENV=pep8 @@ -60,6 +62,9 @@ matrix: env: TOX_ENV=py33 compiler: gcc - os: osx + env: TOX_ENV=py34 + compiler: gcc + - os: osx env: TOX_ENV=pypy compiler: gcc - os: osx @@ -75,6 +80,9 @@ matrix: env: TOX_ENV=py33 OPENSSL=0.9.8 compiler: gcc - os: osx + env: TOX_ENV=py34 OPENSSL=0.9.8 + compiler: gcc + - os: osx env: TOX_ENV=pypy OPENSSL=0.9.8 compiler: gcc - os: osx diff --git a/.travis/install.sh b/.travis/install.sh index 7e77fc87..58d7404d 100755 --- a/.travis/install.sh +++ b/.travis/install.sh @@ -52,8 +52,13 @@ if [[ "$(uname -s)" == "Darwin" ]]; then pip install virtualenv ;; py33) - pyenv install 3.3.2 - pyenv global 3.3.2 + pyenv install 3.3.5 + pyenv global 3.3.5 + pip install virtualenv + ;; + py34) + pyenv install 3.4.0 + pyenv global 3.4.0 pip install virtualenv ;; docs) @@ -78,6 +83,9 @@ else py33) sudo apt-get install python3.3 python3.3-dev ;; + py34) + sudo apt-get install python3.4 python3.4-dev + ;; py3pep8) sudo apt-get install python3.3 python3.3-dev ;; diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 391427d7..abbea9fa 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,8 +1,10 @@ Changelog ========= -0.3 - 2014-XX-XX -~~~~~~~~~~~~~~~~ +0.3 - `master`_ +~~~~~~~~~~~~~~~ + +.. note:: This version is not yet released and is under active development. * Added :class:`~cryptography.hazmat.primitives.twofactor.hotp.HOTP`. * Added :class:`~cryptography.hazmat.primitives.twofactor.totp.TOTP`. @@ -40,3 +42,4 @@ Changelog * Initial release. +.. _`master`: https://github.com/pyca/cryptography/ diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index 9b8e8f0f..7c058f58 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -16,6 +16,8 @@ from __future__ import absolute_import, division, print_function import collections import itertools +import six + from cryptography import utils from cryptography.exceptions import ( InvalidTag, InternalError, AlreadyFinalized, UnsupportedCipher, @@ -262,11 +264,24 @@ class Backend(object): ) def _bn_to_int(self, bn): - hex_cdata = self._lib.BN_bn2hex(bn) - assert hex_cdata != self._ffi.NULL - hex_str = self._ffi.string(hex_cdata) - self._lib.OPENSSL_free(hex_cdata) - return int(hex_str, 16) + if six.PY3: + # Python 3 has constant time from_bytes, so use that. + + bn_num_bytes = (self._lib.BN_num_bits(bn) + 7) // 8 + bin_ptr = self._ffi.new("unsigned char[]", bn_num_bytes) + bin_len = self._lib.BN_bn2bin(bn, bin_ptr) + assert bin_len > 0 + assert bin_ptr != self._ffi.NULL + return int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big") + + else: + # Under Python 2 the best we can do is hex() + + hex_cdata = self._lib.BN_bn2hex(bn) + assert hex_cdata != self._ffi.NULL + hex_str = self._ffi.string(hex_cdata) + self._lib.OPENSSL_free(hex_cdata) + return int(hex_str, 16) def _int_to_bn(self, num): """ @@ -275,12 +290,24 @@ class Backend(object): ownership of the object). Be sure to register it for GC if it will be discarded after use. """ - hex_num = hex(num).rstrip("L").lstrip("0x").encode("ascii") or b"0" - bn_ptr = self._ffi.new("BIGNUM **") - res = self._lib.BN_hex2bn(bn_ptr, hex_num) - assert res != 0 - assert bn_ptr[0] != self._ffi.NULL - return bn_ptr[0] + + if six.PY3: + # Python 3 has constant time to_bytes, so use that. + + binary = num.to_bytes(int(num.bit_length() / 8.0 + 1), "big") + bn_ptr = self._lib.BN_bin2bn(binary, len(binary), self._ffi.NULL) + assert bn_ptr != self._ffi.NULL + return bn_ptr + + else: + # Under Python 2 the best we can do is hex() + + hex_num = hex(num).rstrip("L").lstrip("0x").encode("ascii") or b"0" + bn_ptr = self._ffi.new("BIGNUM **") + res = self._lib.BN_hex2bn(bn_ptr, hex_num) + assert res != 0 + assert bn_ptr[0] != self._ffi.NULL + return bn_ptr[0] def generate_rsa_private_key(self, public_exponent, key_size): if public_exponent < 3: diff --git a/cryptography/hazmat/bindings/utils.py b/cryptography/hazmat/bindings/utils.py index b8253483..318b82bb 100644 --- a/cryptography/hazmat/bindings/utils.py +++ b/cryptography/hazmat/bindings/utils.py @@ -13,6 +13,8 @@ from __future__ import absolute_import, division, print_function +import binascii + import sys import cffi @@ -50,7 +52,8 @@ def build_ffi(module_prefix, modules, pre_include, post_include, libraries): includes.append(module.INCLUDES) customizations.append(module.CUSTOMIZATIONS) - ffi.cdef("\n".join(types + functions + macros)) + cdef_sources = types + functions + macros + ffi.cdef("\n".join(cdef_sources)) # We include functions here so that if we got any of their definitions # wrong, the underlying C compiler will explode. In C you are allowed @@ -60,14 +63,16 @@ def build_ffi(module_prefix, modules, pre_include, post_include, libraries): # is legal, but the following will fail to compile: # int foo(int); # int foo(short); + source = "\n".join( + [pre_include] + + includes + + [post_include] + + functions + + customizations + ) lib = ffi.verify( - source="\n".join( - [pre_include] + - includes + - [post_include] + - functions + - customizations - ), + source=source, + modulename=_create_modulename(cdef_sources, source, sys.version), libraries=libraries, ext_package="cryptography", ) @@ -81,3 +86,20 @@ def build_ffi(module_prefix, modules, pre_include, post_include, libraries): delattr(lib, name) return ffi, lib + + +def _create_modulename(cdef_sources, source, sys_version): + """ + cffi creates a modulename internally that incorporates the cffi version. + This will cause cryptography's wheels to break when the version of cffi + the user has does not match what was used when building the wheel. To + resolve this we build our own modulename that uses most of the same code + from cffi but elides the version key. + """ + key = '\x00'.join([sys_version[:3], source] + cdef_sources) + key = key.encode('utf-8') + k1 = hex(binascii.crc32(key[0::2]) & 0xffffffff) + k1 = k1.lstrip('0x').rstrip('L') + k2 = hex(binascii.crc32(key[1::2]) & 0xffffffff) + k2 = k2.lstrip('0').rstrip('L') + return '_Cryptography_cffi_{0}{1}'.format(k1, k2) diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py index 3824bcde..eab48b4d 100644 --- a/cryptography/hazmat/primitives/interfaces.py +++ b/cryptography/hazmat/primitives/interfaces.py @@ -367,6 +367,12 @@ class DSAPrivateKey(six.with_metaclass(abc.ABCMeta)): class DSAPublicKey(six.with_metaclass(abc.ABCMeta)): @abc.abstractproperty + def key_size(self): + """ + The bit length of the prime modulus. + """ + + @abc.abstractproperty def y(self): """ The public key. diff --git a/docs/hazmat/primitives/interfaces.rst b/docs/hazmat/primitives/interfaces.rst index cc2a3000..cefd81ac 100644 --- a/docs/hazmat/primitives/interfaces.rst +++ b/docs/hazmat/primitives/interfaces.rst @@ -323,7 +323,13 @@ Asymmetric Interfaces .. versionadded:: 0.3 - A `DSA`_ private key. + A `DSA`_ public key. + + .. attribute:: key_size + + :type: int + + The bit length of the modulus. .. method:: parameters() @@ -119,6 +119,7 @@ setup( "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Security :: Cryptography", diff --git a/tests/hazmat/bindings/test_utils.py b/tests/hazmat/bindings/test_utils.py new file mode 100644 index 00000000..0d5b34de --- /dev/null +++ b/tests/hazmat/bindings/test_utils.py @@ -0,0 +1,25 @@ +# 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 cryptography.hazmat.bindings import utils + + +def test_create_modulename(): + cdef_sources = ["cdef sources go here"] + source = "source code" + name = utils._create_modulename(cdef_sources, source, "2.7") + assert name == "_Cryptography_cffi_bcba7f4bx4a14b588" + name = utils._create_modulename(cdef_sources, source, "3.2") + assert name == "_Cryptography_cffi_a7462526x4a14b588" @@ -1,5 +1,5 @@ [tox] -envlist = py26,py27,pypy,py32,py33,docs,pep8,py3pep8 +envlist = py26,py27,pypy,py32,py33,py34,docs,pep8,py3pep8 [testenv] deps = |