diff options
author | Donald Stufft <donald@stufft.io> | 2015-06-11 09:23:01 -0400 |
---|---|---|
committer | Donald Stufft <donald@stufft.io> | 2015-06-11 09:23:01 -0400 |
commit | 51ebadb34d22d25c10c5e54d4dada46b88c3829b (patch) | |
tree | b14a815d477d7f24eebbad6be2b038b21693da7e | |
parent | f3280bda0a560fbf4d401bd8edf89b974a97b39c (diff) | |
download | py-bcrypt-git-51ebadb34d22d25c10c5e54d4dada46b88c3829b.tar.gz |
Migrate to using CFFI 1.0
* Move everything under src/ to ensure we test against the installed
library.
* Create a build_bcrypt.py script which will build _bcrypt.so.
* Refactor to utilize the new _bcrypt.so instead of implicit compile.
-rw-r--r-- | MANIFEST.in | 3 | ||||
-rw-r--r-- | bcrypt/__init__.py | 150 | ||||
-rw-r--r-- | setup.py | 55 | ||||
-rw-r--r-- | src/bcrypt/__about__.py (renamed from bcrypt/__about__.py) | 0 | ||||
-rw-r--r-- | src/bcrypt/__init__.py | 65 | ||||
-rw-r--r-- | src/build_bcrypt.py | 47 | ||||
-rw-r--r-- | src/crypt_blowfish-1.3/LINKS (renamed from bcrypt/crypt_blowfish-1.3/LINKS) | 0 | ||||
-rw-r--r-- | src/crypt_blowfish-1.3/Makefile (renamed from bcrypt/crypt_blowfish-1.3/Makefile) | 0 | ||||
-rw-r--r-- | src/crypt_blowfish-1.3/PERFORMANCE (renamed from bcrypt/crypt_blowfish-1.3/PERFORMANCE) | 0 | ||||
-rw-r--r-- | src/crypt_blowfish-1.3/README (renamed from bcrypt/crypt_blowfish-1.3/README) | 0 | ||||
-rw-r--r-- | src/crypt_blowfish-1.3/crypt.3 (renamed from bcrypt/crypt_blowfish-1.3/crypt.3) | 0 | ||||
-rw-r--r-- | src/crypt_blowfish-1.3/crypt.h (renamed from bcrypt/crypt_blowfish-1.3/crypt.h) | 0 | ||||
-rw-r--r-- | src/crypt_blowfish-1.3/crypt_blowfish.c (renamed from bcrypt/crypt_blowfish-1.3/crypt_blowfish.c) | 0 | ||||
-rw-r--r-- | src/crypt_blowfish-1.3/crypt_blowfish.h (renamed from bcrypt/crypt_blowfish-1.3/crypt_blowfish.h) | 0 | ||||
-rw-r--r-- | src/crypt_blowfish-1.3/crypt_gensalt.c (renamed from bcrypt/crypt_blowfish-1.3/crypt_gensalt.c) | 0 | ||||
-rw-r--r-- | src/crypt_blowfish-1.3/crypt_gensalt.h (renamed from bcrypt/crypt_blowfish-1.3/crypt_gensalt.h) | 0 | ||||
-rw-r--r-- | src/crypt_blowfish-1.3/glibc-2.1.3-crypt.diff (renamed from bcrypt/crypt_blowfish-1.3/glibc-2.1.3-crypt.diff) | 0 | ||||
-rw-r--r-- | src/crypt_blowfish-1.3/glibc-2.14-crypt.diff (renamed from bcrypt/crypt_blowfish-1.3/glibc-2.14-crypt.diff) | 0 | ||||
-rw-r--r-- | src/crypt_blowfish-1.3/glibc-2.3.6-crypt.diff (renamed from bcrypt/crypt_blowfish-1.3/glibc-2.3.6-crypt.diff) | 0 | ||||
-rw-r--r-- | src/crypt_blowfish-1.3/ow-crypt.h (renamed from bcrypt/crypt_blowfish-1.3/ow-crypt.h) | 0 | ||||
-rw-r--r-- | src/crypt_blowfish-1.3/wrapper.c (renamed from bcrypt/crypt_blowfish-1.3/wrapper.c) | 0 | ||||
-rw-r--r-- | src/crypt_blowfish-1.3/x86.S (renamed from bcrypt/crypt_blowfish-1.3/x86.S) | 0 | ||||
-rw-r--r-- | tests/test_bcrypt.py | 5 |
23 files changed, 127 insertions, 198 deletions
diff --git a/MANIFEST.in b/MANIFEST.in index 521c312..ea1c0a0 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,3 @@ include LICENSE README.rst -recursive-include bcrypt/crypt_blowfish-1.3 * +include src/build_bcrypt.py +recursive-include src/crypt_blowfish-1.3 * diff --git a/bcrypt/__init__.py b/bcrypt/__init__.py deleted file mode 100644 index 29a4701..0000000 --- a/bcrypt/__init__.py +++ /dev/null @@ -1,150 +0,0 @@ -# Author:: Donald Stufft (<donald@stufft.io>) -# Copyright:: Copyright (c) 2013 Donald Stufft -# License:: Apache License, Version 2.0 -# -# 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 -from __future__ import division - -import binascii -import os -import sys -import threading - -from cffi import FFI -from cffi.verifier import Verifier - -import six - -from .__about__ import ( - __author__, __copyright__, __email__, __license__, __summary__, __title__, - __uri__, __version__, -) - - -__all__ = [ - "__title__", "__summary__", "__uri__", "__version__", "__author__", - "__email__", "__license__", "__copyright__", - "gensalt", "hashpw", -] - - -def _create_modulename(cdef_sources, source, sys_version): - """ - This is the same as CFFI's create modulename except we don't include the - CFFI version. - """ - 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 '_bcrypt_cffi_{0}{1}'.format(k1, k2) - - -def _compile_module(*args, **kwargs): - raise RuntimeError( - "Attempted implicit compile of a cffi module. All cffi modules should " - "be pre-compiled at installation time." - ) - - -class LazyLibrary(object): - def __init__(self, ffi): - self._ffi = ffi - self._lib = None - self._lock = threading.Lock() - - def __getattr__(self, name): - if self._lib is None: - with self._lock: - # We no cover this because this guard is here just to protect - # against concurrent loads of this library. This is pretty - # hard to test and the logic is simple and should hold fine - # without testing (famous last words). - if self._lib is None: # pragma: no cover - self._lib = self._ffi.verifier.load_library() - - return getattr(self._lib, name) - - -_crypt_blowfish_dir = "crypt_blowfish-1.3" -_bundled_dir = os.path.join(os.path.dirname(__file__), _crypt_blowfish_dir) - - -CDEF = """ - char *crypt_gensalt_rn(const char *prefix, unsigned long count, - const char *input, int size, char *output, int output_size); - - char *crypt_rn(const char *key, const char *setting, void *data, int size); -""" - -SOURCE = """ - #include "ow-crypt.h" -""" - -_ffi = FFI() -_ffi.cdef(CDEF) -_ffi.verifier = Verifier( - _ffi, - SOURCE, - sources=[ - str(os.path.join(_bundled_dir, "crypt_blowfish.c")), - str(os.path.join(_bundled_dir, "crypt_gensalt.c")), - str(os.path.join(_bundled_dir, "wrapper.c")), - # How can we get distutils to work with a .S file? - # Set bcrypt/crypt_blowfish-1.3/crypt_blowfish.c#57 back to 1 if we - # get ASM loaded. - # str(os.path.join(_bundled_dir, "x86.S")), - ], - include_dirs=[str(_bundled_dir)], - modulename=_create_modulename(CDEF, SOURCE, sys.version), -) - -# Patch the Verifier() instance to prevent CFFI from compiling the module -_ffi.verifier.compile_module = _compile_module -_ffi.verifier._compile_module = _compile_module - - -_bcrypt_lib = LazyLibrary(_ffi) - - -def gensalt(rounds=12): - salt = os.urandom(16) - output = _ffi.new("unsigned char[]", 30) - - retval = _bcrypt_lib.crypt_gensalt_rn( - b"$2a$", rounds, salt, len(salt), output, len(output), - ) - - if not retval: - raise ValueError("Invalid rounds") - - return _ffi.string(output) - - -def hashpw(password, salt): - if isinstance(password, six.text_type) or isinstance(salt, six.text_type): - raise TypeError("Unicode-objects must be encoded before hashing") - - if b"\x00" in password: - raise ValueError("password may not contain NUL bytes") - - hashed = _ffi.new("unsigned char[]", 128) - retval = _bcrypt_lib.crypt_rn(password, salt, hashed, len(hashed)) - - if not retval: - raise ValueError("Invalid salt") - - return _ffi.string(hashed) @@ -7,48 +7,21 @@ from setuptools.command.install import install from setuptools.command.test import test -CFFI_DEPENDENCY = "cffi>=0.8" +CFFI_DEPENDENCY = "cffi>=1.1" SIX_DEPENDENCY = "six>=1.4.1" +CFFI_MODULES = [ + "src/build_bcrypt.py:ffi", +] + + # Manually extract the __about__ __about__ = {} -with open("bcrypt/__about__.py") as fp: +with open("src/bcrypt/__about__.py") as fp: exec(fp.read(), __about__) -def get_ext_modules(): - from bcrypt import _ffi - return [_ffi.verifier.get_extension()] - - -class CFFIBuild(build): - """ - This class exists, instead of just providing ``ext_modules=[...]`` directly - in ``setup()`` because importing cryptography requires we have several - packages installed first. - - By doing the imports here we ensure that packages listed in - ``setup_requires`` are already installed. - """ - - def finalize_options(self): - self.distribution.ext_modules = get_ext_modules() - build.finalize_options(self) - - -class CFFIInstall(install): - """ - As a consequence of CFFIBuild and it's late addition of ext_modules, we - need the equivalent for the ``install`` command to install into platlib - install-dir rather than purelib. - """ - - def finalize_options(self): - self.distribution.ext_modules = get_ext_modules() - install.finalize_options(self) - - class PyTest(test): def finalize_options(self): test.finalize_options(self) @@ -159,12 +132,11 @@ def keywords_with_side_effects(argv): } else: return { - "setup_requires": [CFFI_DEPENDENCY, SIX_DEPENDENCY], + "setup_requires": [CFFI_DEPENDENCY], "cmdclass": { - "build": CFFIBuild, - "install": CFFIInstall, "test": PyTest, - } + }, + "cffi_modules": CFFI_MODULES, } @@ -231,14 +203,11 @@ setup( "pytest", ], + package_dir={"": "src"}, packages=[ "bcrypt", ], - package_data={ - "bcrypt": ["crypt_blowfish-1.3/*"], - }, - zip_safe=False, classifiers=[ @@ -252,5 +221,7 @@ setup( "Programming Language :: Python :: 3.3", ], + ext_package="bcrypt", + **keywords_with_side_effects(sys.argv) ) diff --git a/bcrypt/__about__.py b/src/bcrypt/__about__.py index d526fe7..d526fe7 100644 --- a/bcrypt/__about__.py +++ b/src/bcrypt/__about__.py diff --git a/src/bcrypt/__init__.py b/src/bcrypt/__init__.py new file mode 100644 index 0000000..10f860b --- /dev/null +++ b/src/bcrypt/__init__.py @@ -0,0 +1,65 @@ +# Author:: Donald Stufft (<donald@stufft.io>) +# Copyright:: Copyright (c) 2013 Donald Stufft +# License:: Apache License, Version 2.0 +# +# 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 +from __future__ import division + +import os + +import six + +from bcrypt import _bcrypt + +from .__about__ import ( + __author__, __copyright__, __email__, __license__, __summary__, __title__, + __uri__, __version__, +) + + +__all__ = [ + "__title__", "__summary__", "__uri__", "__version__", "__author__", + "__email__", "__license__", "__copyright__", + "gensalt", "hashpw", +] + + +def gensalt(rounds=12): + salt = os.urandom(16) + output = _bcrypt.ffi.new("unsigned char[]", 30) + + retval = _bcrypt.lib.crypt_gensalt_rn( + b"$2a$", rounds, salt, len(salt), output, len(output), + ) + + if not retval: + raise ValueError("Invalid rounds") + + return _bcrypt.ffi.string(output) + + +def hashpw(password, salt): + if isinstance(password, six.text_type) or isinstance(salt, six.text_type): + raise TypeError("Unicode-objects must be encoded before hashing") + + if b"\x00" in password: + raise ValueError("password may not contain NUL bytes") + + hashed = _bcrypt.ffi.new("unsigned char[]", 128) + retval = _bcrypt.lib.crypt_rn(password, salt, hashed, len(hashed)) + + if not retval: + raise ValueError("Invalid salt") + + return _bcrypt.ffi.string(hashed) diff --git a/src/build_bcrypt.py b/src/build_bcrypt.py new file mode 100644 index 0000000..b468c08 --- /dev/null +++ b/src/build_bcrypt.py @@ -0,0 +1,47 @@ +# 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. + +import os.path + +from cffi import FFI + + +BLOWFISH_DIR = os.path.join(os.path.dirname(__file__), "crypt_blowfish-1.3") + + +ffi = FFI() + +ffi.cdef( + """ + char *crypt_gensalt_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size); + + char *crypt_rn(const char *key, const char *setting, void *data, int size); + """ +) + +ffi.set_source( + "_bcrypt", + """ + #include "ow-crypt.h" + """, + sources=[ + os.path.join(BLOWFISH_DIR, "crypt_blowfish.c"), + os.path.join(BLOWFISH_DIR, "crypt_gensalt.c"), + os.path.join(BLOWFISH_DIR, "wrapper.c"), + # How can we get distutils to work with a .S file? + # Set bcrypt/crypt_blowfish-1.3/crypt_blowfish.c#57 back to 1 if we + # get ASM loaded. + # os.path.join(BLOWFISH_DIR, "x86.S"), + ], + include_dirs=[BLOWFISH_DIR], +) diff --git a/bcrypt/crypt_blowfish-1.3/LINKS b/src/crypt_blowfish-1.3/LINKS index a6cb7e1..a6cb7e1 100644 --- a/bcrypt/crypt_blowfish-1.3/LINKS +++ b/src/crypt_blowfish-1.3/LINKS diff --git a/bcrypt/crypt_blowfish-1.3/Makefile b/src/crypt_blowfish-1.3/Makefile index c162adc..c162adc 100644 --- a/bcrypt/crypt_blowfish-1.3/Makefile +++ b/src/crypt_blowfish-1.3/Makefile diff --git a/bcrypt/crypt_blowfish-1.3/PERFORMANCE b/src/crypt_blowfish-1.3/PERFORMANCE index 9d6fe4e..9d6fe4e 100644 --- a/bcrypt/crypt_blowfish-1.3/PERFORMANCE +++ b/src/crypt_blowfish-1.3/PERFORMANCE diff --git a/bcrypt/crypt_blowfish-1.3/README b/src/crypt_blowfish-1.3/README index e95da23..e95da23 100644 --- a/bcrypt/crypt_blowfish-1.3/README +++ b/src/crypt_blowfish-1.3/README diff --git a/bcrypt/crypt_blowfish-1.3/crypt.3 b/src/crypt_blowfish-1.3/crypt.3 index b4c0895..b4c0895 100644 --- a/bcrypt/crypt_blowfish-1.3/crypt.3 +++ b/src/crypt_blowfish-1.3/crypt.3 diff --git a/bcrypt/crypt_blowfish-1.3/crypt.h b/src/crypt_blowfish-1.3/crypt.h index 12e6705..12e6705 100644 --- a/bcrypt/crypt_blowfish-1.3/crypt.h +++ b/src/crypt_blowfish-1.3/crypt.h diff --git a/bcrypt/crypt_blowfish-1.3/crypt_blowfish.c b/src/crypt_blowfish-1.3/crypt_blowfish.c index 488a920..488a920 100644 --- a/bcrypt/crypt_blowfish-1.3/crypt_blowfish.c +++ b/src/crypt_blowfish-1.3/crypt_blowfish.c diff --git a/bcrypt/crypt_blowfish-1.3/crypt_blowfish.h b/src/crypt_blowfish-1.3/crypt_blowfish.h index 2ee0d8c..2ee0d8c 100644 --- a/bcrypt/crypt_blowfish-1.3/crypt_blowfish.h +++ b/src/crypt_blowfish-1.3/crypt_blowfish.h diff --git a/bcrypt/crypt_blowfish-1.3/crypt_gensalt.c b/src/crypt_blowfish-1.3/crypt_gensalt.c index 73c15a1..73c15a1 100644 --- a/bcrypt/crypt_blowfish-1.3/crypt_gensalt.c +++ b/src/crypt_blowfish-1.3/crypt_gensalt.c diff --git a/bcrypt/crypt_blowfish-1.3/crypt_gensalt.h b/src/crypt_blowfish-1.3/crypt_gensalt.h index 457bbfe..457bbfe 100644 --- a/bcrypt/crypt_blowfish-1.3/crypt_gensalt.h +++ b/src/crypt_blowfish-1.3/crypt_gensalt.h diff --git a/bcrypt/crypt_blowfish-1.3/glibc-2.1.3-crypt.diff b/src/crypt_blowfish-1.3/glibc-2.1.3-crypt.diff index 415e5b4..415e5b4 100644 --- a/bcrypt/crypt_blowfish-1.3/glibc-2.1.3-crypt.diff +++ b/src/crypt_blowfish-1.3/glibc-2.1.3-crypt.diff diff --git a/bcrypt/crypt_blowfish-1.3/glibc-2.14-crypt.diff b/src/crypt_blowfish-1.3/glibc-2.14-crypt.diff index bacd12e..bacd12e 100644 --- a/bcrypt/crypt_blowfish-1.3/glibc-2.14-crypt.diff +++ b/src/crypt_blowfish-1.3/glibc-2.14-crypt.diff diff --git a/bcrypt/crypt_blowfish-1.3/glibc-2.3.6-crypt.diff b/src/crypt_blowfish-1.3/glibc-2.3.6-crypt.diff index 4471054..4471054 100644 --- a/bcrypt/crypt_blowfish-1.3/glibc-2.3.6-crypt.diff +++ b/src/crypt_blowfish-1.3/glibc-2.3.6-crypt.diff diff --git a/bcrypt/crypt_blowfish-1.3/ow-crypt.h b/src/crypt_blowfish-1.3/ow-crypt.h index 2e48794..2e48794 100644 --- a/bcrypt/crypt_blowfish-1.3/ow-crypt.h +++ b/src/crypt_blowfish-1.3/ow-crypt.h diff --git a/bcrypt/crypt_blowfish-1.3/wrapper.c b/src/crypt_blowfish-1.3/wrapper.c index 1e49c90..1e49c90 100644 --- a/bcrypt/crypt_blowfish-1.3/wrapper.c +++ b/src/crypt_blowfish-1.3/wrapper.c diff --git a/bcrypt/crypt_blowfish-1.3/x86.S b/src/crypt_blowfish-1.3/x86.S index b0f1cd2..b0f1cd2 100644 --- a/bcrypt/crypt_blowfish-1.3/x86.S +++ b/src/crypt_blowfish-1.3/x86.S diff --git a/tests/test_bcrypt.py b/tests/test_bcrypt.py index 5793811..c91a62e 100644 --- a/tests/test_bcrypt.py +++ b/tests/test_bcrypt.py @@ -7,11 +7,6 @@ import six import bcrypt -def test_raise_implicit_compile(): - with pytest.raises(RuntimeError): - bcrypt._compile_module() - - def test_gensalt_basic(monkeypatch): monkeypatch.setattr(os, "urandom", lambda n: b"0000000000000000") assert bcrypt.gensalt() == b"$2a$12$KB.uKB.uKB.uKB.uKB.uK." |