summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--passlib/handlers/scram.py15
-rw-r--r--passlib/tests/test_handlers.py27
2 files changed, 34 insertions, 8 deletions
diff --git a/passlib/handlers/scram.py b/passlib/handlers/scram.py
index 176f57c..a0c03f0 100644
--- a/passlib/handlers/scram.py
+++ b/passlib/handlers/scram.py
@@ -302,6 +302,8 @@ class scram(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
password = saslprep(password).encode("utf-8")
if not isinstance(salt, bytes):
raise TypeError("salt must be bytes")
+ if rounds < 1:
+ raise ValueError("rounds must be >= 1")
alg = iana_to_hashlib(norm_digest_name(alg))
return pbkdf2(password, salt, rounds, -1, "hmac-" + alg)
@@ -328,7 +330,10 @@ class scram(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
raise ValueError("invalid scram hash")
# decode salt
- salt = adapted_b64_decode(salt_str.encode("ascii"))
+ try:
+ salt = adapted_b64_decode(salt_str.encode("ascii"))
+ except TypeError:
+ raise ValueError("malformed scram hash")
# decode algs/digest list
if not chk_str:
@@ -340,7 +345,10 @@ class scram(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
chkmap = {}
for pair in chk_str.split(","):
alg, digest = pair.split("=")
- chkmap[alg] = adapted_b64_decode(digest.encode("ascii"))
+ try:
+ chkmap[alg] = adapted_b64_decode(digest.encode("ascii"))
+ except TypeError:
+ raise ValueError("malformed scram hash")
else:
# comma-separated list of alg names, no digests
algs = chk_str
@@ -449,7 +457,8 @@ class scram(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
self = cls.from_string(hash)
chkmap = self.checksum
if not chkmap:
- return False
+ raise ValueError("expected %s hash, got %s config string instead" %
+ (cls.name, cls.name))
# NOTE: to make the verify method efficient, we just calculate hash
# of shortest digest by default. apps can pass in "full_verify=True" to
diff --git a/passlib/tests/test_handlers.py b/passlib/tests/test_handlers.py
index 81e3958..5670339 100644
--- a/passlib/tests/test_handlers.py
+++ b/passlib/tests/test_handlers.py
@@ -1051,12 +1051,11 @@ class ScramTest(HandlerCase):
# non-digit in rounds
'$scram$409A$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30',
-# FIXME: bad chars raise TypeError
# bad char in salt
-# '$scram$4096$QSXCR.Q6sek8bf9-$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30',
+ '$scram$4096$QSXCR.Q6sek8bf9-$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30',
# bad char in digest
-# '$scram$4096$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX3-',
+ '$scram$4096$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX3-',
# too many chars in alg
'$scram$4096$QSXCR.Q6sek8bf92$shaxxx-190=HZbuOlKbWl.eR8AfIposuKbhX30',
@@ -1123,10 +1122,28 @@ class ScramTest(HandlerCase):
'edGQSu/kD1LwdX0SNV/KsPdHSwEl5qRTuZQ'),
["sha-1","sha-256","sha-512"])
- # TODO.
def test_103_derive_digest(self):
"test scram.derive_digest()"
- pass
+ # NOTE: this just does a light test, since derive_digest
+ # is used by encrypt / verify, and is tested pretty well via those.
+
+ hash = self.handler.derive_digest
+
+ # check various encodings of password work.
+ s1 = b('\x01\x02\x03')
+ d1 = b('\xb2\xfb\xab\x82[tNuPnI\x8aZZ\x19\x87\xcen\xe9\xd3')
+ self.assertEqual(hash(u("\u2168"), s1, 1000, 'sha-1'), d1)
+ self.assertEqual(hash(b("\xe2\x85\xa8"), s1, 1000, 'SHA-1'), d1)
+ self.assertEqual(hash(u("IX"), s1, 1000, 'sha1'), d1)
+ self.assertEqual(hash(b("IX"), s1, 1000, 'SHA1'), d1)
+
+ # check algs
+ self.assertEqual(hash("IX", s1, 1000, 'md5'),
+ b('3\x19\x18\xc0\x1c/\xa8\xbf\xe4\xa3\xc2\x8eM\xe8od'))
+ self.assertRaises(ValueError, hash, "IX", s1, 1000, 'sha-666')
+
+ # check rounds
+ self.assertRaises(ValueError, hash, "IX", s1, 0, 'sha-1')
def test_104_saslprep(self):
"test encrypt/verify use saslprep"