summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bcrypt/__init__.py8
-rw-r--r--tests/reference/Makefile4
-rw-r--r--tests/reference/bcrypt_reference.go35
-rw-r--r--tests/reference/go.mod5
-rw-r--r--tests/reference/go.sum2
-rw-r--r--tests/test_bcrypt.py32
-rw-r--r--tox.ini4
7 files changed, 75 insertions, 15 deletions
diff --git a/src/bcrypt/__init__.py b/src/bcrypt/__init__.py
index be79417..1f2886f 100644
--- a/src/bcrypt/__init__.py
+++ b/src/bcrypt/__init__.py
@@ -73,9 +73,6 @@ def hashpw(password: bytes, salt: bytes) -> bytes:
if isinstance(password, str) or isinstance(salt, str):
raise TypeError("Strings must be encoded before hashing")
- if b"\x00" in password:
- raise ValueError("password may not contain NUL bytes")
-
# bcrypt originally suffered from a wraparound bug:
# http://www.openwall.com/lists/oss-security/2012/01/02/4
# This bug was corrected in the OpenBSD source by truncating inputs to 72
@@ -91,11 +88,6 @@ def checkpw(password: bytes, hashed_password: bytes) -> bool:
if isinstance(password, str) or isinstance(hashed_password, str):
raise TypeError("Strings must be encoded before checking")
- if b"\x00" in password or b"\x00" in hashed_password:
- raise ValueError(
- "password and hashed_password may not contain NUL bytes"
- )
-
ret = hashpw(password, hashed_password)
return hmac.compare_digest(ret, hashed_password)
diff --git a/tests/reference/Makefile b/tests/reference/Makefile
new file mode 100644
index 0000000..faf967f
--- /dev/null
+++ b/tests/reference/Makefile
@@ -0,0 +1,4 @@
+.PHONY: all
+
+all:
+ go build -v ./bcrypt_reference.go
diff --git a/tests/reference/bcrypt_reference.go b/tests/reference/bcrypt_reference.go
new file mode 100644
index 0000000..81417c8
--- /dev/null
+++ b/tests/reference/bcrypt_reference.go
@@ -0,0 +1,35 @@
+package main
+
+import (
+ "io"
+ "os"
+ "strconv"
+
+ "golang.org/x/crypto/bcrypt"
+)
+
+// provides access to the golang implementation of bcrypt, for reference:
+// "password" to hash is provided on stdin, cost parameter is an optional
+// command-line parameter
+
+func main() {
+ cost := bcrypt.MinCost
+ if len(os.Args) > 1 {
+ if parsed, err := strconv.Atoi(os.Args[1]); err == nil {
+ cost = parsed
+ }
+ }
+
+ buf, err := io.ReadAll(os.Stdin)
+ if err != nil {
+ panic(err)
+ }
+
+ out, err := bcrypt.GenerateFromPassword(buf, cost)
+ if err != nil {
+ panic(err)
+ }
+
+ os.Stdout.Write(out)
+ os.Stdout.Write([]byte("\n"))
+}
diff --git a/tests/reference/go.mod b/tests/reference/go.mod
new file mode 100644
index 0000000..40d8c88
--- /dev/null
+++ b/tests/reference/go.mod
@@ -0,0 +1,5 @@
+module github.com/pyca/bcrypt
+
+go 1.17
+
+require golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
diff --git a/tests/reference/go.sum b/tests/reference/go.sum
new file mode 100644
index 0000000..8c260b8
--- /dev/null
+++ b/tests/reference/go.sum
@@ -0,0 +1,2 @@
+golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE=
+golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
diff --git a/tests/test_bcrypt.py b/tests/test_bcrypt.py
index d3bf6a1..c6deb85 100644
--- a/tests/test_bcrypt.py
+++ b/tests/test_bcrypt.py
@@ -144,6 +144,20 @@ _test_vectors = [
b"$2a$05$/OK.fbVrR/bpIqNJ5ianF.",
b"$2a$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
),
+ (
+ b"}>\xb3\xfe\xf1\x8b\xa0\xe6(\xa2Lzq\xc3P\x7f\xcc\xc8b{\xf9\x14\xf6"
+ b"\xf6`\x81G5\xec\x1d\x87\x10\xbf\xa7\xe1}I7 \x96\xdfc\xf2\xbf\xb3Vh"
+ b"\xdfM\x88q\xf7\xff\x1b\x82~z\x13\xdd\xe9\x84\x00\xdd4",
+ b"$2b$10$keO.ZZs22YtygVF6BLfhGO",
+ b"$2b$10$keO.ZZs22YtygVF6BLfhGOI/JjshJYPp8DZsUtym6mJV2Eha2Hdd.",
+ ),
+ (
+ b"g7\r\x01\xf3\xd4\xd0\xa9JB^\x18\x007P\xb2N\xc7\x1c\xee\x87&\x83C"
+ b"\x8b\xe8\x18\xc5>\x86\x14/\xd6\xcc\x1cJ\xde\xd7ix\xeb\xdeO\xef"
+ b"\xe1i\xac\xcb\x03\x96v1' \xd6@.m\xa5!\xa0\xef\xc0(",
+ b"$2a$04$tecY.9ylRInW/rAAzXCXPO",
+ b"$2a$04$tecY.9ylRInW/rAAzXCXPOOlyYeCNzmNTzPDNSIFztFMKbvs/s5XG",
+ ),
]
_2y_test_vectors = [
@@ -281,11 +295,10 @@ def test_hashpw_str_salt():
def test_checkpw_nul_byte():
- with pytest.raises(ValueError):
- bcrypt.checkpw(
- b"abc\0def",
- b"$2b$04$2Siw3Nv3Q/gTOIPetAyPr.GNj3aO0lb1E5E9UumYGKjP9BYqlNWJe",
- )
+ bcrypt.checkpw(
+ b"abc\0def",
+ b"$2b$04$2Siw3Nv3Q/gTOIPetAyPr.GNj3aO0lb1E5E9UumYGKjP9BYqlNWJe",
+ )
with pytest.raises(ValueError):
bcrypt.checkpw(
@@ -296,8 +309,13 @@ def test_checkpw_nul_byte():
def test_hashpw_nul_byte():
salt = bcrypt.gensalt(4)
- with pytest.raises(ValueError):
- bcrypt.hashpw(b"abc\0def", salt)
+ hashed = bcrypt.hashpw(b"abc\0def", salt)
+ assert bcrypt.checkpw(b"abc\0def", hashed)
+ # assert that we are sensitive to changes in the password after the first
+ # null byte:
+ assert not bcrypt.checkpw(b"abc\0deg", hashed)
+ assert not bcrypt.checkpw(b"abc\0def\0", hashed)
+ assert not bcrypt.checkpw(b"abc\0def\0\0", hashed)
def test_checkpw_extra_data():
diff --git a/tox.ini b/tox.ini
index 36ac09f..1980668 100644
--- a/tox.ini
+++ b/tox.ini
@@ -42,3 +42,7 @@ ignore = E203,E211,E501,W503,W504
exclude = .tox,*.egg
select = E,W,F,N,I
application-import-names = bcrypt,tests
+
+[check-manifest]
+ignore =
+ tests/reference/*