summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDonald Stufft <donald@stufft.io>2016-06-30 13:05:04 -0400
committerPaul Kehrer <paul.l.kehrer@gmail.com>2016-06-30 12:05:04 -0500
commitc95966955b60a446e9d23af0b9500fbc5e43c0cc (patch)
tree317f85080dedac1a4d06ccf9bd2a8f8eea633599
parentc9c76210fad230995a6155287e8b92c49180eae4 (diff)
downloadpy-bcrypt-git-c95966955b60a446e9d23af0b9500fbc5e43c0cc.tar.gz
Inputing a 2y salt should output a 2y hash (#84)
-rw-r--r--README.rst1
-rw-r--r--src/bcrypt/__init__.py23
-rw-r--r--tests/test_bcrypt.py4
3 files changed, 17 insertions, 11 deletions
diff --git a/README.rst b/README.rst
index 0883286..b8c75a9 100644
--- a/README.rst
+++ b/README.rst
@@ -40,6 +40,7 @@ Changelog
3.1.0
-----
* Added support for ``checkpw`` as another method of verifying a password.
+* Ensure that you get a ``$2y$`` hash when you input a ``$2y$`` salt.
3.0.0
-----
diff --git a/src/bcrypt/__init__.py b/src/bcrypt/__init__.py
index d6acb84..abc9d75 100644
--- a/src/bcrypt/__init__.py
+++ b/src/bcrypt/__init__.py
@@ -39,10 +39,6 @@ __all__ = [
_normalize_re = re.compile(b"^\$2y\$")
-def _normalize_prefix(salt):
- return _normalize_re.sub(b"$2b$", salt)
-
-
def gensalt(rounds=12, prefix=b"2b"):
if prefix not in (b"2a", b"2b"):
raise ValueError("Supported prefixes are b'2a' or b'2b'")
@@ -75,7 +71,13 @@ def hashpw(password, salt):
# on $2a$, so we do it here to preserve compatibility with 2.0.0
password = password[:72]
- salt = _normalize_prefix(salt)
+ # When the original 8bit bug was found the original library we supported
+ # added a new prefix, $2y$, that fixes it. This prefix is exactly the same
+ # as the $2b$ prefix added by OpenBSD other than the name. Since the
+ # OpenBSD library does not support the $2y$ prefix, if the salt given to us
+ # is for the $2y$ prefix, we'll just mugne it so that it's a $2b$ prior to
+ # passing it into the C library.
+ original_salt, salt = salt, _normalize_re.sub(b"$2b$", salt)
hashed = _bcrypt.ffi.new("unsigned char[]", 128)
retval = _bcrypt.lib.bcrypt_hashpass(password, salt, hashed, len(hashed))
@@ -83,7 +85,13 @@ def hashpw(password, salt):
if retval != 0:
raise ValueError("Invalid salt")
- return _bcrypt.ffi.string(hashed)
+ # Now that we've gotten our hashed password, we want to ensure that the
+ # prefix we return is the one that was passed in, so we'll use the prefix
+ # from the original salt and concatenate that with the return value (minus
+ # the return value's prefix). This will ensure that if someone passed in a
+ # salt with a $2y$ prefix, that they get back a hash with a $2y$ prefix
+ # even though we munged it to $2b$.
+ return original_salt[:4] + _bcrypt.ffi.string(hashed)[4:]
def checkpw(password, hashed_password):
@@ -96,9 +104,6 @@ def checkpw(password, hashed_password):
"password and hashed_password may not contain NUL bytes"
)
- # If the user supplies a $2y$ prefix we normalize to $2b$
- hashed_password = _normalize_prefix(hashed_password)
-
ret = hashpw(password, hashed_password)
return _bcrypt.lib.timingsafe_bcmp(ret, hashed_password, len(ret)) == 0
diff --git a/tests/test_bcrypt.py b/tests/test_bcrypt.py
index 47f315a..d9bde72 100644
--- a/tests/test_bcrypt.py
+++ b/tests/test_bcrypt.py
@@ -152,12 +152,12 @@ _2y_test_vectors = [
(
b"\xa3",
b"$2y$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
- b"$2b$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
+ b"$2y$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
),
(
b"\xff\xff\xa3",
b"$2y$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
- b"$2b$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
+ b"$2y$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
),
]