summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2020-07-23 20:38:00 -0400
committerGitHub <noreply@github.com>2020-07-23 19:38:00 -0500
commit09c5fd1a20865731d76c607948fab5bd9c018824 (patch)
tree0439f58a34e7c97353ca90247ac56c38347170b9
parentcd8ba16d8e83987a5d905ad2a8d05c7da97b994d (diff)
downloadpy-bcrypt-git-09c5fd1a20865731d76c607948fab5bd9c018824.tar.gz
Paint it Black by the Rolling Stones (#208)
-rw-r--r--.travis.yml2
-rw-r--r--pyproject.toml4
-rw-r--r--release.py60
-rw-r--r--setup.py132
-rw-r--r--src/bcrypt/__about__.py10
-rw-r--r--src/bcrypt/__init__.py47
-rw-r--r--src/build_bcrypt.py6
-rw-r--r--tests/test_bcrypt.py295
-rw-r--r--tox.ini4
9 files changed, 312 insertions, 248 deletions
diff --git a/.travis.yml b/.travis.yml
index ddaea21..e766564 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -41,7 +41,7 @@ matrix:
- python: 2.7
env: TOXENV=pep8
- env: TOXENV=packaging
- - python: 3.5
+ - python: 3.8
env: TOXENV=py3pep8
- python: 2.7
arch: arm64
diff --git a/pyproject.toml b/pyproject.toml
index f821a2e..caa1f72 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -8,3 +8,7 @@ requires = [
# Point to the setuptools' PEP517 build backend explicitly to
# disable Pip's fallback guessing
build-backend = "setuptools.build_meta"
+
+[tool.black]
+line-length = 79
+target-version = ["py27"]
diff --git a/release.py b/release.py
index dbedaac..9e492af 100644
--- a/release.py
+++ b/release.py
@@ -25,10 +25,13 @@ def run(*args, **kwargs):
def wait_for_build_complete_github_actions(session, token, run_url):
while True:
- response = session.get(run_url, headers={
- "Content-Type": "application/json",
- "Authorization": "token {}".format(token),
- })
+ response = session.get(
+ run_url,
+ headers={
+ "Content-Type": "application/json",
+ "Authorization": "token {}".format(token),
+ },
+ )
response.raise_for_status()
if response.json()["conclusion"] is not None:
break
@@ -36,32 +39,39 @@ def wait_for_build_complete_github_actions(session, token, run_url):
def download_artifacts_github_actions(session, token, run_url):
- response = session.get(run_url, headers={
- "Content-Type": "application/json",
- "Authorization": "token {}".format(token),
- })
+ response = session.get(
+ run_url,
+ headers={
+ "Content-Type": "application/json",
+ "Authorization": "token {}".format(token),
+ },
+ )
response.raise_for_status()
- response = session.get(response.json()["artifacts_url"], headers={
- "Content-Type": "application/json",
- "Authorization": "token {}".format(token),
- })
+ response = session.get(
+ response.json()["artifacts_url"],
+ headers={
+ "Content-Type": "application/json",
+ "Authorization": "token {}".format(token),
+ },
+ )
response.raise_for_status()
paths = []
for artifact in response.json()["artifacts"]:
- response = session.get(artifact["archive_download_url"], headers={
- "Content-Type": "application/json",
- "Authorization": "token {}".format(token),
- })
+ response = session.get(
+ artifact["archive_download_url"],
+ headers={
+ "Content-Type": "application/json",
+ "Authorization": "token {}".format(token),
+ },
+ )
with zipfile.ZipFile(io.BytesIO(response.content)) as z:
for name in z.namelist():
if not name.endswith(".whl"):
continue
p = z.open(name)
out_path = os.path.join(
- os.path.dirname(__file__),
- "dist",
- os.path.basename(name),
+ os.path.dirname(__file__), "dist", os.path.basename(name),
)
with open(out_path, "wb") as f:
f.write(p.read())
@@ -79,12 +89,12 @@ def build_github_actions_wheels(token, version):
"Accept": "application/vnd.github.everest-preview+json",
"Authorization": "token {}".format(token),
},
- data=json.dumps({
- "event_type": "wheel-builder",
- "client_payload": {
- "BUILD_VERSION": version,
- },
- }),
+ data=json.dumps(
+ {
+ "event_type": "wheel-builder",
+ "client_payload": {"BUILD_VERSION": version},
+ }
+ ),
)
response.raise_for_status()
diff --git a/setup.py b/setup.py
index 6de648f..1db9191 100644
--- a/setup.py
+++ b/setup.py
@@ -21,7 +21,7 @@ CFFI_MODULES = [
# Manually extract the __about__
__about__ = {}
with open("src/bcrypt/__about__.py") as fp:
- exec(fp.read(), __about__)
+ exec (fp.read(), __about__)
if platform.python_implementation() == "PyPy":
@@ -40,6 +40,7 @@ class PyTest(test):
def run_tests(self):
import pytest
+
errno = pytest.main(self.test_args)
sys.exit(errno)
@@ -70,47 +71,52 @@ def keywords_with_side_effects(argv):
.. _setup.py script: https://github.com/scipy/scipy/blob/master/setup.py
"""
no_setup_requires_arguments = (
- '-h', '--help',
- '-n', '--dry-run',
- '-q', '--quiet',
- '-v', '--verbose',
- '-V', '--version',
- '--author',
- '--author-email',
- '--classifiers',
- '--contact',
- '--contact-email',
- '--description',
- '--egg-base',
- '--fullname',
- '--help-commands',
- '--keywords',
- '--licence',
- '--license',
- '--long-description',
- '--maintainer',
- '--maintainer-email',
- '--name',
- '--no-user-cfg',
- '--obsoletes',
- '--platforms',
- '--provides',
- '--requires',
- '--url',
- 'clean',
- 'egg_info',
- 'register',
- 'sdist',
- 'upload',
+ "-h",
+ "--help",
+ "-n",
+ "--dry-run",
+ "-q",
+ "--quiet",
+ "-v",
+ "--verbose",
+ "-V",
+ "--version",
+ "--author",
+ "--author-email",
+ "--classifiers",
+ "--contact",
+ "--contact-email",
+ "--description",
+ "--egg-base",
+ "--fullname",
+ "--help-commands",
+ "--keywords",
+ "--licence",
+ "--license",
+ "--long-description",
+ "--maintainer",
+ "--maintainer-email",
+ "--name",
+ "--no-user-cfg",
+ "--obsoletes",
+ "--platforms",
+ "--provides",
+ "--requires",
+ "--url",
+ "clean",
+ "egg_info",
+ "register",
+ "sdist",
+ "upload",
)
def is_short_option(argument):
"""Check whether a command line argument is a short option."""
- return len(argument) >= 2 and argument[0] == '-' and argument[1] != '-'
+ return len(argument) >= 2 and argument[0] == "-" and argument[1] != "-"
def expand_short_options(argument):
"""Expand combined short options into canonical short options."""
- return ('-' + char for char in argument[1:])
+ return ("-" + char for char in argument[1:])
def argument_without_setup_requirements(argv, i):
"""Check whether a command line argument needs setup requirements."""
@@ -118,21 +124,24 @@ def keywords_with_side_effects(argv):
# Simple case: An argument which is either an option or a command
# which doesn't need setup requirements.
return True
- elif (is_short_option(argv[i]) and
- all(option in no_setup_requires_arguments
- for option in expand_short_options(argv[i]))):
+ elif is_short_option(argv[i]) and all(
+ option in no_setup_requires_arguments
+ for option in expand_short_options(argv[i])
+ ):
# Not so simple case: Combined short options none of which need
# setup requirements.
return True
- elif argv[i - 1:i] == ['--egg-base']:
+ elif argv[i - 1 : i] == ["--egg-base"]:
# Tricky case: --egg-info takes an argument which should not make
# us use setup_requires (defeating the purpose of this code).
return True
else:
return False
- if all(argument_without_setup_requirements(argv, i)
- for i in range(1, len(argv))):
+ if all(
+ argument_without_setup_requirements(argv, i)
+ for i in range(1, len(argv))
+ ):
return {
"cmdclass": {
"build": DummyCFFIBuild,
@@ -143,16 +152,16 @@ def keywords_with_side_effects(argv):
else:
return {
"setup_requires": [CFFI_DEPENDENCY],
- "cmdclass": {
- "test": PyTest,
- },
+ "cmdclass": {"test": PyTest},
"cffi_modules": CFFI_MODULES,
}
-setup_requires_error = ("Requested setup command that needs 'setup_requires' "
- "while command line arguments implied a side effect "
- "free command or option.")
+setup_requires_error = (
+ "Requested setup command that needs 'setup_requires' "
+ "while command line arguments implied a side effect "
+ "free command or option."
+)
class DummyCFFIBuild(build):
@@ -191,36 +200,19 @@ class DummyPyTest(test):
setup(
name=__about__["__title__"],
version=__about__["__version__"],
-
description=__about__["__summary__"],
- long_description=io.open("README.rst", encoding='utf-8').read(),
+ long_description=io.open("README.rst", encoding="utf-8").read(),
url=__about__["__uri__"],
license=__about__["__license__"],
-
author=__about__["__author__"],
author_email=__about__["__email__"],
-
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
- install_requires=[
- CFFI_DEPENDENCY,
- SIX_DEPENDENCY,
- ],
- extras_require={
- "tests": [
- "pytest>=3.2.1,!=3.3.0",
- ],
- },
- tests_require=[
- "pytest>=3.2.1,!=3.3.0",
- ],
-
+ install_requires=[CFFI_DEPENDENCY, SIX_DEPENDENCY],
+ extras_require={"tests": ["pytest>=3.2.1,!=3.3.0"]},
+ tests_require=["pytest>=3.2.1,!=3.3.0"],
package_dir={"": "src"},
- packages=[
- "bcrypt",
- ],
-
+ packages=["bcrypt"],
zip_safe=False,
-
classifiers=[
"Development Status :: 5 - Production/Stable",
"License :: OSI Approved :: Apache Software License",
@@ -234,8 +226,6 @@ setup(
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
],
-
ext_package="bcrypt",
-
**keywords_with_side_effects(sys.argv)
)
diff --git a/src/bcrypt/__about__.py b/src/bcrypt/__about__.py
index bf81dc6..0b80173 100644
--- a/src/bcrypt/__about__.py
+++ b/src/bcrypt/__about__.py
@@ -18,8 +18,14 @@ from __future__ import division
from __future__ import unicode_literals
__all__ = [
- "__title__", "__summary__", "__uri__", "__version__", "__author__",
- "__email__", "__license__", "__copyright__",
+ "__title__",
+ "__summary__",
+ "__uri__",
+ "__version__",
+ "__author__",
+ "__email__",
+ "__license__",
+ "__copyright__",
]
__title__ = "bcrypt"
diff --git a/src/bcrypt/__init__.py b/src/bcrypt/__init__.py
index 073c788..9679a42 100644
--- a/src/bcrypt/__init__.py
+++ b/src/bcrypt/__init__.py
@@ -24,15 +24,30 @@ import six
from . import _bcrypt
from .__about__ import (
- __author__, __copyright__, __email__, __license__, __summary__, __title__,
- __uri__, __version__,
+ __author__,
+ __copyright__,
+ __email__,
+ __license__,
+ __summary__,
+ __title__,
+ __uri__,
+ __version__,
)
__all__ = [
- "__title__", "__summary__", "__uri__", "__version__", "__author__",
- "__email__", "__license__", "__copyright__",
- "gensalt", "hashpw", "kdf", "checkpw",
+ "__title__",
+ "__summary__",
+ "__uri__",
+ "__version__",
+ "__author__",
+ "__email__",
+ "__license__",
+ "__copyright__",
+ "gensalt",
+ "hashpw",
+ "kdf",
+ "checkpw",
]
@@ -51,8 +66,12 @@ def gensalt(rounds=12, prefix=b"2b"):
_bcrypt.lib.encode_base64(output, salt, len(salt))
return (
- b"$" + prefix + b"$" + ("%2.2u" % rounds).encode("ascii") + b"$" +
- _bcrypt.ffi.string(output)
+ b"$"
+ + prefix
+ + b"$"
+ + ("%2.2u" % rounds).encode("ascii")
+ + b"$"
+ + _bcrypt.ffi.string(output)
)
@@ -95,8 +114,9 @@ def hashpw(password, salt):
def checkpw(password, hashed_password):
- if (isinstance(password, six.text_type) or
- isinstance(hashed_password, six.text_type)):
+ if isinstance(password, six.text_type) or isinstance(
+ hashed_password, six.text_type
+ ):
raise TypeError("Unicode-objects must be encoded before checking")
if b"\x00" in password or b"\x00" in hashed_password:
@@ -129,10 +149,11 @@ def kdf(password, salt, desired_key_bytes, rounds, ignore_few_rounds=False):
# They probably think bcrypt.kdf()'s rounds parameter is logarithmic,
# expecting this value to be slow enough (it probably would be if this
# were bcrypt). Emit a warning.
- warnings.warn((
- "Warning: bcrypt.kdf() called with only {0} round(s). "
- "This few is not secure: the parameter is linear, like PBKDF2.")
- .format(rounds),
+ warnings.warn(
+ (
+ "Warning: bcrypt.kdf() called with only {0} round(s). "
+ "This few is not secure: the parameter is linear, like PBKDF2."
+ ).format(rounds),
UserWarning,
stacklevel=2,
)
diff --git a/src/build_bcrypt.py b/src/build_bcrypt.py
index 3eec35c..f401706 100644
--- a/src/build_bcrypt.py
+++ b/src/build_bcrypt.py
@@ -20,13 +20,15 @@ BLOWFISH_DIR = os.path.join(os.path.dirname(__file__), "_csrc")
ffi = FFI()
-ffi.cdef("""
+ffi.cdef(
+ """
int bcrypt_hashpass(const char *, const char *, char *, size_t);
int encode_base64(char *, const uint8_t *, size_t);
int bcrypt_pbkdf(const char *, size_t, const uint8_t *, size_t,
uint8_t *, size_t, unsigned int);
int timingsafe_bcmp(const void *, const void *, size_t);
-""")
+"""
+)
ffi.set_source(
"_bcrypt",
diff --git a/tests/test_bcrypt.py b/tests/test_bcrypt.py
index 3f00875..37baa54 100644
--- a/tests/test_bcrypt.py
+++ b/tests/test_bcrypt.py
@@ -139,12 +139,12 @@ _test_vectors = [
b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
b"chars after 72 are ignored as usual",
b"$2a$05$/OK.fbVrR/bpIqNJ5ianF.",
- b"$2a$05$/OK.fbVrR/bpIqNJ5ianF.swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6"
+ b"$2a$05$/OK.fbVrR/bpIqNJ5ianF.swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6",
),
(
b"\xa3",
b"$2a$05$/OK.fbVrR/bpIqNJ5ianF.",
- b"$2a$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq"
+ b"$2a$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
),
]
@@ -167,29 +167,32 @@ def test_gensalt_basic(monkeypatch):
assert bcrypt.gensalt() == b"$2b$12$KB.uKB.uKB.uKB.uKB.uK."
-@pytest.mark.parametrize(("rounds", "expected"), [
- (4, b"$2b$04$KB.uKB.uKB.uKB.uKB.uK."),
- (5, b"$2b$05$KB.uKB.uKB.uKB.uKB.uK."),
- (6, b"$2b$06$KB.uKB.uKB.uKB.uKB.uK."),
- (7, b"$2b$07$KB.uKB.uKB.uKB.uKB.uK."),
- (8, b"$2b$08$KB.uKB.uKB.uKB.uKB.uK."),
- (9, b"$2b$09$KB.uKB.uKB.uKB.uKB.uK."),
- (10, b"$2b$10$KB.uKB.uKB.uKB.uKB.uK."),
- (11, b"$2b$11$KB.uKB.uKB.uKB.uKB.uK."),
- (12, b"$2b$12$KB.uKB.uKB.uKB.uKB.uK."),
- (13, b"$2b$13$KB.uKB.uKB.uKB.uKB.uK."),
- (14, b"$2b$14$KB.uKB.uKB.uKB.uKB.uK."),
- (15, b"$2b$15$KB.uKB.uKB.uKB.uKB.uK."),
- (16, b"$2b$16$KB.uKB.uKB.uKB.uKB.uK."),
- (17, b"$2b$17$KB.uKB.uKB.uKB.uKB.uK."),
- (18, b"$2b$18$KB.uKB.uKB.uKB.uKB.uK."),
- (19, b"$2b$19$KB.uKB.uKB.uKB.uKB.uK."),
- (20, b"$2b$20$KB.uKB.uKB.uKB.uKB.uK."),
- (21, b"$2b$21$KB.uKB.uKB.uKB.uKB.uK."),
- (22, b"$2b$22$KB.uKB.uKB.uKB.uKB.uK."),
- (23, b"$2b$23$KB.uKB.uKB.uKB.uKB.uK."),
- (24, b"$2b$24$KB.uKB.uKB.uKB.uKB.uK."),
-])
+@pytest.mark.parametrize(
+ ("rounds", "expected"),
+ [
+ (4, b"$2b$04$KB.uKB.uKB.uKB.uKB.uK."),
+ (5, b"$2b$05$KB.uKB.uKB.uKB.uKB.uK."),
+ (6, b"$2b$06$KB.uKB.uKB.uKB.uKB.uK."),
+ (7, b"$2b$07$KB.uKB.uKB.uKB.uKB.uK."),
+ (8, b"$2b$08$KB.uKB.uKB.uKB.uKB.uK."),
+ (9, b"$2b$09$KB.uKB.uKB.uKB.uKB.uK."),
+ (10, b"$2b$10$KB.uKB.uKB.uKB.uKB.uK."),
+ (11, b"$2b$11$KB.uKB.uKB.uKB.uKB.uK."),
+ (12, b"$2b$12$KB.uKB.uKB.uKB.uKB.uK."),
+ (13, b"$2b$13$KB.uKB.uKB.uKB.uKB.uK."),
+ (14, b"$2b$14$KB.uKB.uKB.uKB.uKB.uK."),
+ (15, b"$2b$15$KB.uKB.uKB.uKB.uKB.uK."),
+ (16, b"$2b$16$KB.uKB.uKB.uKB.uKB.uK."),
+ (17, b"$2b$17$KB.uKB.uKB.uKB.uKB.uK."),
+ (18, b"$2b$18$KB.uKB.uKB.uKB.uKB.uK."),
+ (19, b"$2b$19$KB.uKB.uKB.uKB.uKB.uK."),
+ (20, b"$2b$20$KB.uKB.uKB.uKB.uKB.uK."),
+ (21, b"$2b$21$KB.uKB.uKB.uKB.uKB.uK."),
+ (22, b"$2b$22$KB.uKB.uKB.uKB.uKB.uK."),
+ (23, b"$2b$23$KB.uKB.uKB.uKB.uKB.uK."),
+ (24, b"$2b$24$KB.uKB.uKB.uKB.uKB.uK."),
+ ],
+)
def test_gensalt_rounds_valid(rounds, expected, monkeypatch):
monkeypatch.setattr(os, "urandom", lambda n: b"0000000000000000")
assert bcrypt.gensalt(rounds) == expected
@@ -242,49 +245,48 @@ def test_hashpw_invalid():
def test_checkpw_wrong_password():
- assert bcrypt.checkpw(
- b"badpass",
- b"$2b$04$2Siw3Nv3Q/gTOIPetAyPr.GNj3aO0lb1E5E9UumYGKjP9BYqlNWJe"
- ) is False
+ assert (
+ bcrypt.checkpw(
+ b"badpass",
+ b"$2b$04$2Siw3Nv3Q/gTOIPetAyPr.GNj3aO0lb1E5E9UumYGKjP9BYqlNWJe",
+ )
+ is False
+ )
def test_checkpw_bad_salt():
with pytest.raises(ValueError):
bcrypt.checkpw(
b"badpass",
- b"$2b$04$?Siw3Nv3Q/gTOIPetAyPr.GNj3aO0lb1E5E9UumYGKjP9BYqlNWJe"
+ b"$2b$04$?Siw3Nv3Q/gTOIPetAyPr.GNj3aO0lb1E5E9UumYGKjP9BYqlNWJe",
)
def test_checkpw_str_password():
with pytest.raises(TypeError):
bcrypt.checkpw(
- six.text_type("password"),
- b"$2b$04$cVWp4XaNU8a4v1uMRum2SO",
+ six.text_type("password"), b"$2b$04$cVWp4XaNU8a4v1uMRum2SO",
)
def test_checkpw_str_salt():
with pytest.raises(TypeError):
bcrypt.checkpw(
- b"password",
- six.text_type("$2b$04$cVWp4XaNU8a4v1uMRum2SO"),
+ b"password", six.text_type("$2b$04$cVWp4XaNU8a4v1uMRum2SO"),
)
def test_hashpw_str_password():
with pytest.raises(TypeError):
bcrypt.hashpw(
- six.text_type("password"),
- b"$2b$04$cVWp4XaNU8a4v1uMRum2SO",
+ six.text_type("password"), b"$2b$04$cVWp4XaNU8a4v1uMRum2SO",
)
def test_hashpw_str_salt():
with pytest.raises(TypeError):
bcrypt.hashpw(
- b"password",
- six.text_type("$2b$04$cVWp4XaNU8a4v1uMRum2SO"),
+ b"password", six.text_type("$2b$04$cVWp4XaNU8a4v1uMRum2SO"),
)
@@ -292,13 +294,13 @@ def test_checkpw_nul_byte():
with pytest.raises(ValueError):
bcrypt.checkpw(
b"abc\0def",
- b"$2b$04$2Siw3Nv3Q/gTOIPetAyPr.GNj3aO0lb1E5E9UumYGKjP9BYqlNWJe"
+ b"$2b$04$2Siw3Nv3Q/gTOIPetAyPr.GNj3aO0lb1E5E9UumYGKjP9BYqlNWJe",
)
with pytest.raises(ValueError):
bcrypt.checkpw(
b"abcdef",
- b"$2b$04$2S\0w3Nv3Q/gTOIPetAyPr.GNj3aO0lb1E5E9UumYGKjP9BYqlNWJe"
+ b"$2b$04$2S\0w3Nv3Q/gTOIPetAyPr.GNj3aO0lb1E5E9UumYGKjP9BYqlNWJe",
)
@@ -319,86 +321,116 @@ def test_checkpw_extra_data():
@pytest.mark.parametrize(
("rounds", "password", "salt", "expected"),
- [[
- 4, b"password", b"salt",
- b"\x5b\xbf\x0c\xc2\x93\x58\x7f\x1c\x36\x35\x55\x5c\x27\x79\x65\x98"
- b"\xd4\x7e\x57\x90\x71\xbf\x42\x7e\x9d\x8f\xbe\x84\x2a\xba\x34\xd9"
- ], [
- 4, b"password", b"\x00",
- b"\xc1\x2b\x56\x62\x35\xee\xe0\x4c\x21\x25\x98\x97\x0a\x57\x9a\x67"
- ], [
- 4, b"\x00", b"salt",
- b"\x60\x51\xbe\x18\xc2\xf4\xf8\x2c\xbf\x0e\xfe\xe5\x47\x1b\x4b\xb9"
- ], [
- # nul bytes in password and string
- 4, b"password\x00", b"salt\x00",
- b"\x74\x10\xe4\x4c\xf4\xfa\x07\xbf\xaa\xc8\xa9\x28\xb1\x72\x7f\xac"
- b"\x00\x13\x75\xe7\xbf\x73\x84\x37\x0f\x48\xef\xd1\x21\x74\x30\x50"
- ], [
- 4, b"pass\x00wor", b"sa\0l",
- b"\xc2\xbf\xfd\x9d\xb3\x8f\x65\x69\xef\xef\x43\x72\xf4\xde\x83\xc0"
- ], [
- 4, b"pass\x00word", b"sa\0lt",
- b"\x4b\xa4\xac\x39\x25\xc0\xe8\xd7\xf0\xcd\xb6\xbb\x16\x84\xa5\x6f"
- ], [
- # bigger key
- 8, b"password", b"salt",
- b"\xe1\x36\x7e\xc5\x15\x1a\x33\xfa\xac\x4c\xc1\xc1\x44\xcd\x23\xfa"
- b"\x15\xd5\x54\x84\x93\xec\xc9\x9b\x9b\x5d\x9c\x0d\x3b\x27\xbe\xc7"
- b"\x62\x27\xea\x66\x08\x8b\x84\x9b\x20\xab\x7a\xa4\x78\x01\x02\x46"
- b"\xe7\x4b\xba\x51\x72\x3f\xef\xa9\xf9\x47\x4d\x65\x08\x84\x5e\x8d"
- ], [
- # more rounds
- 42, b"password", b"salt",
- b"\x83\x3c\xf0\xdc\xf5\x6d\xb6\x56\x08\xe8\xf0\xdc\x0c\xe8\x82\xbd"
- ], [
- # longer password
- 8,
- b"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
- b"eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
- b"enim ad minim veniam, quis nostrud exercitation ullamco laboris "
- b"nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor "
- b"in reprehenderit in voluptate velit esse cillum dolore eu fugiat "
- b"nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
- b"sunt in culpa qui officia deserunt mollit anim id est laborum.",
- b"salis\x00",
- b"\x10\x97\x8b\x07\x25\x3d\xf5\x7f\x71\xa1\x62\xeb\x0e\x8a\xd3\x0a"
- ], [
- # "unicode"
- 8,
- b"\x0d\xb3\xac\x94\xb3\xee\x53\x28\x4f\x4a\x22\x89\x3b\x3c\x24\xae",
- b"\x3a\x62\xf0\xf0\xdb\xce\xf8\x23\xcf\xcc\x85\x48\x56\xea\x10\x28",
- b"\x20\x44\x38\x17\x5e\xee\x7c\xe1\x36\xc9\x1b\x49\xa6\x79\x23\xff"
- ], [
- # very large key
- 8,
- b"\x0d\xb3\xac\x94\xb3\xee\x53\x28\x4f\x4a\x22\x89\x3b\x3c\x24\xae",
- b"\x3a\x62\xf0\xf0\xdb\xce\xf8\x23\xcf\xcc\x85\x48\x56\xea\x10\x28",
- b"\x20\x54\xb9\xff\xf3\x4e\x37\x21\x44\x03\x34\x74\x68\x28\xe9\xed"
- b"\x38\xde\x4b\x72\xe0\xa6\x9a\xdc\x17\x0a\x13\xb5\xe8\xd6\x46\x38"
- b"\x5e\xa4\x03\x4a\xe6\xd2\x66\x00\xee\x23\x32\xc5\xed\x40\xad\x55"
- b"\x7c\x86\xe3\x40\x3f\xbb\x30\xe4\xe1\xdc\x1a\xe0\x6b\x99\xa0\x71"
- b"\x36\x8f\x51\x8d\x2c\x42\x66\x51\xc9\xe7\xe4\x37\xfd\x6c\x91\x5b"
- b"\x1b\xbf\xc3\xa4\xce\xa7\x14\x91\x49\x0e\xa7\xaf\xb7\xdd\x02\x90"
- b"\xa6\x78\xa4\xf4\x41\x12\x8d\xb1\x79\x2e\xab\x27\x76\xb2\x1e\xb4"
- b"\x23\x8e\x07\x15\xad\xd4\x12\x7d\xff\x44\xe4\xb3\xe4\xcc\x4c\x4f"
- b"\x99\x70\x08\x3f\x3f\x74\xbd\x69\x88\x73\xfd\xf6\x48\x84\x4f\x75"
- b"\xc9\xbf\x7f\x9e\x0c\x4d\x9e\x5d\x89\xa7\x78\x39\x97\x49\x29\x66"
- b"\x61\x67\x07\x61\x1c\xb9\x01\xde\x31\xa1\x97\x26\xb6\xe0\x8c\x3a"
- b"\x80\x01\x66\x1f\x2d\x5c\x9d\xcc\x33\xb4\xaa\x07\x2f\x90\xdd\x0b"
- b"\x3f\x54\x8d\x5e\xeb\xa4\x21\x13\x97\xe2\xfb\x06\x2e\x52\x6e\x1d"
- b"\x68\xf4\x6a\x4c\xe2\x56\x18\x5b\x4b\xad\xc2\x68\x5f\xbe\x78\xe1"
- b"\xc7\x65\x7b\x59\xf8\x3a\xb9\xab\x80\xcf\x93\x18\xd6\xad\xd1\xf5"
- b"\x93\x3f\x12\xd6\xf3\x61\x82\xc8\xe8\x11\x5f\x68\x03\x0a\x12\x44"
- ], [
- # UTF-8 Greek characters "odysseus" / "telemachos"
- 8,
- b"\xe1\xbd\x88\xce\xb4\xcf\x85\xcf\x83\xcf\x83\xce\xb5\xcf\x8d\xcf"
- b"\x82",
- b"\xce\xa4\xce\xb7\xce\xbb\xce\xad\xce\xbc\xce\xb1\xcf\x87\xce\xbf"
- b"\xcf\x82",
- b"\x43\x66\x6c\x9b\x09\xef\x33\xed\x8c\x27\xe8\xe8\xf3\xe2\xd8\xe6"
- ]])
+ [
+ [
+ 4,
+ b"password",
+ b"salt",
+ b"\x5b\xbf\x0c\xc2\x93\x58\x7f\x1c\x36\x35\x55\x5c\x27\x79\x65\x98"
+ b"\xd4\x7e\x57\x90\x71\xbf\x42\x7e\x9d\x8f\xbe\x84\x2a\xba\x34\xd9",
+ ],
+ [
+ 4,
+ b"password",
+ b"\x00",
+ b"\xc1\x2b\x56\x62\x35\xee\xe0\x4c\x21\x25\x98\x97\x0a\x57\x9a\x67",
+ ],
+ [
+ 4,
+ b"\x00",
+ b"salt",
+ b"\x60\x51\xbe\x18\xc2\xf4\xf8\x2c\xbf\x0e\xfe\xe5\x47\x1b\x4b\xb9",
+ ],
+ [
+ # nul bytes in password and string
+ 4,
+ b"password\x00",
+ b"salt\x00",
+ b"\x74\x10\xe4\x4c\xf4\xfa\x07\xbf\xaa\xc8\xa9\x28\xb1\x72\x7f\xac"
+ b"\x00\x13\x75\xe7\xbf\x73\x84\x37\x0f\x48\xef\xd1\x21\x74\x30\x50",
+ ],
+ [
+ 4,
+ b"pass\x00wor",
+ b"sa\0l",
+ b"\xc2\xbf\xfd\x9d\xb3\x8f\x65\x69\xef\xef\x43\x72\xf4\xde\x83\xc0",
+ ],
+ [
+ 4,
+ b"pass\x00word",
+ b"sa\0lt",
+ b"\x4b\xa4\xac\x39\x25\xc0\xe8\xd7\xf0\xcd\xb6\xbb\x16\x84\xa5\x6f",
+ ],
+ [
+ # bigger key
+ 8,
+ b"password",
+ b"salt",
+ b"\xe1\x36\x7e\xc5\x15\x1a\x33\xfa\xac\x4c\xc1\xc1\x44\xcd\x23\xfa"
+ b"\x15\xd5\x54\x84\x93\xec\xc9\x9b\x9b\x5d\x9c\x0d\x3b\x27\xbe\xc7"
+ b"\x62\x27\xea\x66\x08\x8b\x84\x9b\x20\xab\x7a\xa4\x78\x01\x02\x46"
+ b"\xe7\x4b\xba\x51\x72\x3f\xef\xa9\xf9\x47\x4d\x65\x08\x84\x5e\x8d",
+ ],
+ [
+ # more rounds
+ 42,
+ b"password",
+ b"salt",
+ b"\x83\x3c\xf0\xdc\xf5\x6d\xb6\x56\x08\xe8\xf0\xdc\x0c\xe8\x82\xbd",
+ ],
+ [
+ # longer password
+ 8,
+ b"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
+ b"eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
+ b"enim ad minim veniam, quis nostrud exercitation ullamco laboris "
+ b"nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor "
+ b"in reprehenderit in voluptate velit esse cillum dolore eu fugiat "
+ b"nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
+ b"sunt in culpa qui officia deserunt mollit anim id est laborum.",
+ b"salis\x00",
+ b"\x10\x97\x8b\x07\x25\x3d\xf5\x7f\x71\xa1\x62\xeb\x0e\x8a\xd3\x0a",
+ ],
+ [
+ # "unicode"
+ 8,
+ b"\x0d\xb3\xac\x94\xb3\xee\x53\x28\x4f\x4a\x22\x89\x3b\x3c\x24\xae",
+ b"\x3a\x62\xf0\xf0\xdb\xce\xf8\x23\xcf\xcc\x85\x48\x56\xea\x10\x28",
+ b"\x20\x44\x38\x17\x5e\xee\x7c\xe1\x36\xc9\x1b\x49\xa6\x79\x23\xff",
+ ],
+ [
+ # very large key
+ 8,
+ b"\x0d\xb3\xac\x94\xb3\xee\x53\x28\x4f\x4a\x22\x89\x3b\x3c\x24\xae",
+ b"\x3a\x62\xf0\xf0\xdb\xce\xf8\x23\xcf\xcc\x85\x48\x56\xea\x10\x28",
+ b"\x20\x54\xb9\xff\xf3\x4e\x37\x21\x44\x03\x34\x74\x68\x28\xe9\xed"
+ b"\x38\xde\x4b\x72\xe0\xa6\x9a\xdc\x17\x0a\x13\xb5\xe8\xd6\x46\x38"
+ b"\x5e\xa4\x03\x4a\xe6\xd2\x66\x00\xee\x23\x32\xc5\xed\x40\xad\x55"
+ b"\x7c\x86\xe3\x40\x3f\xbb\x30\xe4\xe1\xdc\x1a\xe0\x6b\x99\xa0\x71"
+ b"\x36\x8f\x51\x8d\x2c\x42\x66\x51\xc9\xe7\xe4\x37\xfd\x6c\x91\x5b"
+ b"\x1b\xbf\xc3\xa4\xce\xa7\x14\x91\x49\x0e\xa7\xaf\xb7\xdd\x02\x90"
+ b"\xa6\x78\xa4\xf4\x41\x12\x8d\xb1\x79\x2e\xab\x27\x76\xb2\x1e\xb4"
+ b"\x23\x8e\x07\x15\xad\xd4\x12\x7d\xff\x44\xe4\xb3\xe4\xcc\x4c\x4f"
+ b"\x99\x70\x08\x3f\x3f\x74\xbd\x69\x88\x73\xfd\xf6\x48\x84\x4f\x75"
+ b"\xc9\xbf\x7f\x9e\x0c\x4d\x9e\x5d\x89\xa7\x78\x39\x97\x49\x29\x66"
+ b"\x61\x67\x07\x61\x1c\xb9\x01\xde\x31\xa1\x97\x26\xb6\xe0\x8c\x3a"
+ b"\x80\x01\x66\x1f\x2d\x5c\x9d\xcc\x33\xb4\xaa\x07\x2f\x90\xdd\x0b"
+ b"\x3f\x54\x8d\x5e\xeb\xa4\x21\x13\x97\xe2\xfb\x06\x2e\x52\x6e\x1d"
+ b"\x68\xf4\x6a\x4c\xe2\x56\x18\x5b\x4b\xad\xc2\x68\x5f\xbe\x78\xe1"
+ b"\xc7\x65\x7b\x59\xf8\x3a\xb9\xab\x80\xcf\x93\x18\xd6\xad\xd1\xf5"
+ b"\x93\x3f\x12\xd6\xf3\x61\x82\xc8\xe8\x11\x5f\x68\x03\x0a\x12\x44",
+ ],
+ [
+ # UTF-8 Greek characters "odysseus" / "telemachos"
+ 8,
+ b"\xe1\xbd\x88\xce\xb4\xcf\x85\xcf\x83\xcf\x83\xce\xb5\xcf\x8d\xcf"
+ b"\x82",
+ b"\xce\xa4\xce\xb7\xce\xbb\xce\xad\xce\xbc\xce\xb1\xcf\x87\xce\xbf"
+ b"\xcf\x82",
+ b"\x43\x66\x6c\x9b\x09\xef\x33\xed\x8c\x27\xe8\xe8\xf3\xe2\xd8\xe6",
+ ],
+ ],
+)
def test_kdf(rounds, password, salt, expected):
derived = bcrypt.kdf(
password, salt, len(expected), rounds, ignore_few_rounds=True
@@ -415,22 +447,16 @@ def test_kdf_str_password():
def test_kdf_str_salt():
with pytest.raises(TypeError):
- bcrypt.kdf(
- b"password", six.text_type("salt"), 10, 10
- )
+ bcrypt.kdf(b"password", six.text_type("salt"), 10, 10)
def test_kdf_no_warn_rounds():
- bcrypt.kdf(
- b"password", b"salt", 10, 10, True
- )
+ bcrypt.kdf(b"password", b"salt", 10, 10, True)
def test_kdf_warn_rounds():
with pytest.warns(UserWarning):
- bcrypt.kdf(
- b"password", b"salt", 10, 10
- )
+ bcrypt.kdf(b"password", b"salt", 10, 10)
@pytest.mark.parametrize(
@@ -444,7 +470,7 @@ def test_kdf_warn_rounds():
(b"password", b"$2b$04$cVWp4XaNU8a4v1uMRum2SO", -3, 10, ValueError),
(b"password", b"$2b$04$cVWp4XaNU8a4v1uMRum2SO", 513, 10, ValueError),
(b"password", b"$2b$04$cVWp4XaNU8a4v1uMRum2SO", 20, 0, ValueError),
- ]
+ ],
)
def test_invalid_params(password, salt, desired_key_bytes, rounds, error):
with pytest.raises(error):
@@ -457,6 +483,9 @@ def test_bcrypt_assert():
def test_2a_wraparound_bug():
- assert bcrypt.hashpw(
- (b"0123456789" * 26)[:255], b"$2a$04$R1lJ2gkNaoPGdafE.H.16."
- ) == b"$2a$04$R1lJ2gkNaoPGdafE.H.16.1MKHPvmKwryeulRe225LKProWYwt9Oi"
+ assert (
+ bcrypt.hashpw(
+ (b"0123456789" * 26)[:255], b"$2a$04$R1lJ2gkNaoPGdafE.H.16."
+ )
+ == b"$2a$04$R1lJ2gkNaoPGdafE.H.16.1MKHPvmKwryeulRe225LKProWYwt9Oi"
+ )
diff --git a/tox.ini b/tox.ini
index 0850d43..49ec7b6 100644
--- a/tox.ini
+++ b/tox.ini
@@ -22,11 +22,13 @@ commands =
[testenv:py3pep8]
basepython = python3
deps =
+ black
flake8
flake8-import-order
pep8-naming
commands =
flake8 .
+ black --check .
[testenv:packaging]
deps =
@@ -38,7 +40,7 @@ commands =
[flake8]
-ignore = W504
+ignore = E203,E211,E501,W503,W504
exclude = .tox,*.egg
select = E,W,F,N,I
application-import-names = bcrypt,tests