summaryrefslogtreecommitdiff
path: root/passlib
diff options
context:
space:
mode:
authorEli Collins <elic@astllc.org>2011-03-25 12:11:17 -0400
committerEli Collins <elic@astllc.org>2011-03-25 12:11:17 -0400
commit32773d53f07bd9e94d4966a28f48c56cdecd51c3 (patch)
tree59f64c35fb6c4b3255882a417b9a4462c40cac8f /passlib
parent771a8d2c0f909c6e8a59ff39ee4a1e939d799ce9 (diff)
downloadpasslib-32773d53f07bd9e94d4966a28f48c56cdecd51c3.tar.gz
misc bugfixes & tweaks for win32 compat
Diffstat (limited to 'passlib')
-rw-r--r--passlib/apps.py6
-rw-r--r--passlib/handlers/bcrypt.py2
-rw-r--r--passlib/handlers/des_crypt.py2
-rw-r--r--passlib/handlers/md5_crypt.py2
-rw-r--r--passlib/handlers/sha2_crypt.py4
-rw-r--r--passlib/tests/test_context.py7
-rw-r--r--passlib/tests/test_drivers.py4
-rw-r--r--passlib/tests/test_utils.py7
-rw-r--r--passlib/tests/test_utils_handlers.py18
-rw-r--r--passlib/utils/__init__.py5
-rw-r--r--passlib/utils/pbkdf2.py12
11 files changed, 45 insertions, 24 deletions
diff --git a/passlib/apps.py b/passlib/apps.py
index 5b84963..ed91f2f 100644
--- a/passlib/apps.py
+++ b/passlib/apps.py
@@ -3,12 +3,12 @@
#imports
#=========================================================
#core
-import platform
import logging; log = logging.getLogger(__name__)
#site
#libs
from passlib import hash
from passlib.context import CryptContext
+from passlib.utils import sys_bits
#pkg
#local
__all__ = [
@@ -23,8 +23,6 @@ __all__ = [
#=========================================================
#for quickly bootstrapping new custom applications
#=========================================================
-_is32 = platform.architecture()[0] == '32bit'
-
custom_app_context = CryptContext(
#choose some reasonbly strong schemes
schemes=["sha512_crypt", "sha256_crypt"],
@@ -32,7 +30,7 @@ custom_app_context = CryptContext(
#set some useful global options
min_verify_time = .125,
all__vary_rounds = "10%",
- default="sha256_crypt" if _is32 else "sha512_crypt",
+ default="sha256_crypt" if sys_bits < 64 else "sha512_crypt",
#set a good starting point for rounds selection
sha512_crypt__default_rounds = 40000,
diff --git a/passlib/handlers/bcrypt.py b/passlib/handlers/bcrypt.py
index 45a3077..ff386b1 100644
--- a/passlib/handlers/bcrypt.py
+++ b/passlib/handlers/bcrypt.py
@@ -140,7 +140,7 @@ class bcrypt(MultiBackendHandler):
@classproperty
def _has_backend_os_crypt(cls):
return (
- os_crypt
+ os_crypt is not None
and
os_crypt("test", "$2a$04$......................") ==
'$2a$04$......................qiOQjkB8hxU8OzRhS.GhRMa4VUnkPty'
diff --git a/passlib/handlers/des_crypt.py b/passlib/handlers/des_crypt.py
index ac9da21..e358208 100644
--- a/passlib/handlers/des_crypt.py
+++ b/passlib/handlers/des_crypt.py
@@ -200,7 +200,7 @@ class des_crypt(MultiBackendHandler):
@classproperty
def _has_backend_os_crypt(cls):
- return os_crypt and os_crypt("test", "ab") == 'abgOeLfPimXQo'
+ return os_crypt is not None and os_crypt("test", "ab") == 'abgOeLfPimXQo'
def _calc_checksum_builtin(self, secret):
#forbidding nul chars because linux crypt (and most C implementations) won't accept it either.
diff --git a/passlib/handlers/md5_crypt.py b/passlib/handlers/md5_crypt.py
index 07081a0..c7ce561 100644
--- a/passlib/handlers/md5_crypt.py
+++ b/passlib/handlers/md5_crypt.py
@@ -195,7 +195,7 @@ class md5_crypt(MultiBackendHandler):
@classproperty
def _has_backend_os_crypt(cls):
- return os_crypt and os_crypt("test", "$1$test") == '$1$test$pi/xDtU5WFVRqYS6BMU8X/'
+ return os_crypt is not None and os_crypt("test", "$1$test") == '$1$test$pi/xDtU5WFVRqYS6BMU8X/'
def _calc_checksum_builtin(self, secret):
#FIXME: can't find definitive policy on how md5-crypt handles non-ascii.
diff --git a/passlib/handlers/sha2_crypt.py b/passlib/handlers/sha2_crypt.py
index e15203c..c430d09 100644
--- a/passlib/handlers/sha2_crypt.py
+++ b/passlib/handlers/sha2_crypt.py
@@ -321,7 +321,7 @@ class sha256_crypt(MultiBackendHandler):
@classproperty
def _has_backend_os_crypt(cls):
return bool(
- os_crypt and
+ os_crypt is not None and
os_crypt("test", "$5$rounds=1000$test") ==
"$5$rounds=1000$test$QmQADEXMG8POI5WDsaeho0P36yK3Tcrgboabng6bkb/"
)
@@ -468,7 +468,7 @@ class sha512_crypt(MultiBackendHandler):
@classproperty
def _has_backend_os_crypt(cls):
return bool(
- os_crypt and
+ os_crypt is not None and
os_crypt("test", "$6$rounds=1000$test") ==
"$6$rounds=1000$test$2M/Lx6MtobqjLjobw0Wmo4Q5OFx5nVLJvmgseatA6oMnyWeBdRDx4DU.1H3eGmse6pgsOgDisWBGI5c7TZauS0"
)
diff --git a/passlib/tests/test_context.py b/passlib/tests/test_context.py
index df9b78d..2543709 100644
--- a/passlib/tests/test_context.py
+++ b/passlib/tests/test_context.py
@@ -674,16 +674,19 @@ class CryptContextTest(TestCase):
def test_24_min_verify_time(self):
cc = CryptContext(["plaintext", "bsdi_crypt"], min_verify_time=.1)
+ #plaintext should (in reality) take <.01,
+ #so this test checks mvt makes it take 0.09 - .5
s = time.time()
cc.verify("password", "password")
d = time.time()-s
self.assertTrue(d>=.09,d)
self.assertTrue(d<.5)
-
+
+ #this may take longer, so we just check min
s = time.time()
cc.verify("password", '_2b..iHVSUNMkJT.GcFU')
d = time.time()-s
- self.assertTrue(d>=.1)
+ self.assertTrue(d>=.09, "mvt=.1, delta=%r" % (d,))
#=========================================================
#eoc
diff --git a/passlib/tests/test_drivers.py b/passlib/tests/test_drivers.py
index 32e3823..3c9ce67 100644
--- a/passlib/tests/test_drivers.py
+++ b/passlib/tests/test_drivers.py
@@ -246,7 +246,9 @@ class LdapSaltedSha1Test(HandlerCase):
class LdapPlaintextTest(HandlerCase):
handler = ldap_digests.ldap_plaintext
known_correct_hashes = [ ("password", 'password') ]
- known_unidentified_hashes = [ "{MD5}fooey" ]
+ known_unidentified_hashes = [ "{FOO}bar" ]
+
+ known_other_hashes = [ ("ldap_md5", "{MD5}/F4DjTilcDIIVEHn/nAQsA==")]
# helloworld -> '{CRYPT}dQ58WW.1980Ig'
diff --git a/passlib/tests/test_utils.py b/passlib/tests/test_utils.py
index 40a64f4..4f31ebb 100644
--- a/passlib/tests/test_utils.py
+++ b/passlib/tests/test_utils.py
@@ -11,7 +11,7 @@ import random
#module
from passlib import utils
from passlib.context import CryptContext
-from passlib.utils import h64, des, Undef
+from passlib.utils import h64, des, Undef, sys_bits
from passlib.utils.md4 import md4
from passlib.tests.utils import TestCase, Params as ak, enable_option
@@ -412,6 +412,9 @@ class _Pbkdf2BackendTest(TestCase):
if not self.enable_m2crypto:
self._orig_EVP = pbkdf2._EVP
pbkdf2._EVP = None
+ else:
+ #set flag so tests can check for m2crypto presence quickly
+ self.enable_m2crypto = bool(pbkdf2._EVP)
def tearDown(self):
if not self.enable_m2crypto:
@@ -473,7 +476,7 @@ class _Pbkdf2BackendTest(TestCase):
self.assertRaises(TypeError, pbkdf2.pbkdf2, 'password', 'salt', 'x', 16)
#invalid keylen
- self.assertRaises(ValueError, pbkdf2.pbkdf2, 'password', 'salt', 1, 20*(2**32))
+ self.assertRaises(ValueError, pbkdf2.pbkdf2, 'password', 'salt', 1, 20*(2**32-1)+1)
#invalid salt type
self.assertRaises(TypeError, pbkdf2.pbkdf2, 'password', 5, 1, 10)
diff --git a/passlib/tests/test_utils_handlers.py b/passlib/tests/test_utils_handlers.py
index d9e05c6..1750113 100644
--- a/passlib/tests/test_utils_handlers.py
+++ b/passlib/tests/test_utils_handlers.py
@@ -139,7 +139,7 @@ class SkeletonTest(TestCase):
#check small & large rounds
with catch_warnings():
- warnings.filterwarnings("ignore", ".* does not allow (less|greater) than 1 rounds: .*", UserWarning)
+ warnings.filterwarnings("ignore", ".* does not allow (less|more) than \d rounds: .*", UserWarning)
self.assertEqual(d1.norm_rounds(0), 1)
self.assertEqual(d1.norm_rounds(4), 3)
self.assertRaises(ValueError, d1.norm_rounds, 0, strict=True)
@@ -167,7 +167,7 @@ class SkeletonTest(TestCase):
backends = ("a", "b")
_has_backend_a = False
- _has_backend_b = True
+ _has_backend_b = False
def _calc_checksum_a(self, secret):
return 'a'
@@ -175,6 +175,13 @@ class SkeletonTest(TestCase):
def _calc_checksum_b(self, secret):
return 'b'
+ #test no backends
+ self.assertRaises(EnvironmentError, d1.set_backend, 'default')
+ self.assertFalse(d1.has_backend())
+
+ #enable 'b' backend
+ d1._has_backend_b = True
+
#test lazy load
obj = d1()
self.assertEquals(obj.calc_checksum('s'), 'b')
@@ -187,13 +194,10 @@ class SkeletonTest(TestCase):
#test unavailable
self.assertRaises(ValueError, d1.set_backend, 'a')
- #test all unavailable
- d1._has_backend_b = False
- self.assertRaises(EnvironmentError, d1.set_backend, 'default')
- self.assertFalse(d1.has_backend())
+ #enable 'a' backend also
+ d1._has_backend_a = True
#test explicit
- d1._has_backend_a = d1._has_backend_b = True
self.assertTrue(d1.has_backend())
d1.set_backend('a')
self.assertEquals(obj.calc_checksum('s'), 'a')
diff --git a/passlib/utils/__init__.py b/passlib/utils/__init__.py
index 00f27da..8b7fff2 100644
--- a/passlib/utils/__init__.py
+++ b/passlib/utils/__init__.py
@@ -7,6 +7,7 @@ from cStringIO import StringIO
from functools import update_wrapper
from hashlib import sha256
import logging; log = logging.getLogger(__name__)
+from math import log as logb
import os
import sys
import random
@@ -40,6 +41,10 @@ __all__ = [
'getrandstr',
]
+#quick check of system's arch
+sys_bits = int(logb(sys.maxsize,2)+1.5)
+assert sys_bits in (32,64), "unexpected sys_bits value: %r" % (sys_bits,)
+
#=================================================================================
#os crypt helpers
#=================================================================================
diff --git a/passlib/utils/pbkdf2.py b/passlib/utils/pbkdf2.py
index ad6f087..460925c 100644
--- a/passlib/utils/pbkdf2.py
+++ b/passlib/utils/pbkdf2.py
@@ -48,6 +48,7 @@ if _EVP:
#backend
#=================================================================================
MAX_BLOCKS = 0xffffffffL #2**32-1
+MAX_HMAC_SHA1_KEYLEN = MAX_BLOCKS*20
def _resolve_prf(prf):
"resolve prf string or callable -> func & digest_size"
@@ -134,10 +135,15 @@ def pbkdf2(secret, salt, rounds, keylen, prf="hmac-sha1"):
#special case for m2crypto + hmac-sha1
if prf == "hmac-sha1" and _EVP:
- try:
- return _EVP.pbkdf2(secret, salt, rounds, keylen)
- except OverflowError:
+ #NOTE: doing check here, because M2crypto won't take longs (which this is, under 32bit)
+ if keylen > MAX_HMAC_SHA1_KEYLEN:
raise ValueError, "key length too long"
+
+ #NOTE: M2crypto reliably segfaults for me if given keylengths
+ # larger than 40 (crashes at 41 on one system, 61 on another).
+ # so just avoiding it for longer calls.
+ if keylen < 41:
+ return _EVP.pbkdf2(secret, salt, rounds, keylen)
#resolve prf
encode_block, digest_size = _resolve_prf(prf)