diff options
| author | Eli Collins <elic@assurancetechnologies.com> | 2012-01-19 00:13:49 -0500 |
|---|---|---|
| committer | Eli Collins <elic@assurancetechnologies.com> | 2012-01-19 00:13:49 -0500 |
| commit | bcf652e665ba2ffbf8e3f43b4e1108e7aa29dbb0 (patch) | |
| tree | 3a2aff7abc0d80d9c560846622f89439634f25ce /passlib/handlers | |
| parent | 6f816a3d7f1f3a394fedcc0aa410792a95b9ece6 (diff) | |
| download | passlib-bcf652e665ba2ffbf8e3f43b4e1108e7aa29dbb0.tar.gz | |
simplified crypt.crypt() wrappers
* safe_crypt() improved - accepts unicode/bytes for salt, checks for NULL, returns None on failure
* added test_crypt() wrapper to simplify backend checks.
* removed native=True from most to_string() implementations, unused now.
* updated UTs
Diffstat (limited to 'passlib/handlers')
| -rw-r--r-- | passlib/handlers/bcrypt.py | 38 | ||||
| -rw-r--r-- | passlib/handlers/des_crypt.py | 46 | ||||
| -rw-r--r-- | passlib/handlers/md5_crypt.py | 9 | ||||
| -rw-r--r-- | passlib/handlers/pbkdf2.py | 8 | ||||
| -rw-r--r-- | passlib/handlers/sha1_crypt.py | 14 | ||||
| -rw-r--r-- | passlib/handlers/sha2_crypt.py | 36 | ||||
| -rw-r--r-- | passlib/handlers/sun_md5_crypt.py | 8 |
7 files changed, 75 insertions, 84 deletions
diff --git a/passlib/handlers/bcrypt.py b/passlib/handlers/bcrypt.py index 9a1f595..7a698d4 100644 --- a/passlib/handlers/bcrypt.py +++ b/passlib/handlers/bcrypt.py @@ -27,8 +27,8 @@ except ImportError: #pragma: no cover - though should run whole suite w/o bcrypt bcryptor_engine = None #libs from passlib.exc import PasslibHandlerWarning -from passlib.utils import BCRYPT_CHARS as BCHARS, safe_os_crypt, \ - classproperty, rng, getrandstr +from passlib.utils import BCRYPT_CHARS as BCHARS, safe_crypt, \ + classproperty, rng, getrandstr, test_crypt from passlib.utils.compat import bytes, u, uascii_to_str, unicode import passlib.utils.handlers as uh @@ -144,9 +144,10 @@ class bcrypt(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.HasManyBackends, uh. strict=strict and bool(chk), ) - def to_string(self, native=True): - hash = u("%s%02d$%s%s") % (self.ident, self.rounds, self.salt, self.checksum or u('')) - return uascii_to_str(hash) if native else hash + def to_string(self): + hash = u("%s%02d$%s%s") % (self.ident, self.rounds, self.salt, + self.checksum or u('')) + return uascii_to_str(hash) #========================================================= # specialized salt generation - fixes passlib issue 25 @@ -228,18 +229,17 @@ class bcrypt(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.HasManyBackends, uh. @classproperty def _has_backend_os_crypt(cls): - h1 = u('$2$04$......................1O4gOrCYaqBG3o/4LnT2ykQUt1wbyju') - h2 = u('$2a$04$......................qiOQjkB8hxU8OzRhS.GhRMa4VUnkPty') - return bool(safe_os_crypt and safe_os_crypt(u("test"),h1)[1]==h1 and - safe_os_crypt(u("test"), h2)[1]==h2) + h1 = '$2$04$......................1O4gOrCYaqBG3o/4LnT2ykQUt1wbyju' + h2 = '$2a$04$......................qiOQjkB8hxU8OzRhS.GhRMa4VUnkPty' + return test_crypt("test",h1) and test_crypt("test", h2) @classmethod def _no_backends_msg(cls): return "no BCrypt backends available - please install pybcrypt or bcryptor for BCrypt support" def _calc_checksum_os_crypt(self, secret): - ok, hash = safe_os_crypt(secret, self.to_string(native=False)) - if ok: + hash = safe_crypt(secret, self.to_string()) + if hash: return hash[-31:] else: #NOTE: not checking backends since this is lowest priority, @@ -249,26 +249,22 @@ class bcrypt(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.HasManyBackends, uh. def _calc_checksum_pybcrypt(self, secret): #pybcrypt behavior: - # py2: unicode secret -> ascii bytes (we override this) - # unicode hash -> ascii bytes (we provide ascii bytes) - # returns ascii bytes + # py2: unicode secret/hash encoded as ascii bytes before use, + # bytes takes as-is; returns ascii bytes. # py3: can't get to install if isinstance(secret, unicode): secret = secret.encode("utf-8") - hash = pybcrypt_hashpw(secret, - self.to_string(native=False)) + hash = pybcrypt_hashpw(secret, self.to_string()) return hash[-31:].decode("ascii") def _calc_checksum_bcryptor(self, secret): #bcryptor behavior: - # py2: unicode secret -> ascii bytes (we have to override) - # unicode hash -> ascii bytes (we provide ascii bytes) - # returns ascii bytes + # py2: unicode secret/hash encoded as ascii bytes before use, + # bytes takes as-is; returns ascii bytes. # py3: can't get to install if isinstance(secret, unicode): secret = secret.encode("utf-8") - hash = bcryptor_engine(False).hash_key(secret, - self.to_string(native=False)) + hash = bcryptor_engine(False).hash_key(secret, self.to_string()) return hash[-31:].decode("ascii") def _calc_checksum_builtin(self, secret): diff --git a/passlib/handlers/des_crypt.py b/passlib/handlers/des_crypt.py index 976625a..b326e8e 100644 --- a/passlib/handlers/des_crypt.py +++ b/passlib/handlers/des_crypt.py @@ -58,7 +58,7 @@ import logging; log = logging.getLogger(__name__) from warnings import warn #site #libs -from passlib.utils import classproperty, h64, h64big, safe_os_crypt +from passlib.utils import classproperty, h64, h64big, safe_crypt, test_crypt from passlib.utils.compat import b, bytes, belem_ord, u, uascii_to_str, unicode from passlib.utils.des import mdes_encrypt_int_block import passlib.utils.handlers as uh @@ -193,9 +193,9 @@ class des_crypt(uh.HasManyBackends, uh.HasSalt, uh.GenericHandler): salt, chk = hash[:2], hash[2:] return cls(salt=salt, checksum=chk or None, strict=bool(chk)) - def to_string(self, native=True): + def to_string(self): hash = u("%s%s") % (self.salt, self.checksum or u('')) - return uascii_to_str(hash) if native else hash + return uascii_to_str(hash) #========================================================= #backend @@ -206,28 +206,23 @@ class des_crypt(uh.HasManyBackends, uh.HasSalt, uh.GenericHandler): @classproperty def _has_backend_os_crypt(cls): - h = u('abgOeLfPimXQo') - return bool(safe_os_crypt and safe_os_crypt(u("test"),h)[1]==h) + return test_crypt("test", 'abgOeLfPimXQo') def _calc_checksum_builtin(self, secret): - #gotta do something - no official policy since des-crypt predates unicode + # gotta do something - no official policy since des-crypt predates unicode if isinstance(secret, unicode): secret = secret.encode("utf-8") - #forbidding nul chars because linux crypt (and most C implementations) won't accept it either. + # forbidding nul chars because linux crypt (and most C implementations) + # won't accept it either. if b('\x00') in secret: raise ValueError("null char in secret") return raw_crypt(secret, self.salt.encode("ascii")).decode("ascii") def _calc_checksum_os_crypt(self, secret): - #os_crypt() would raise less useful error - null = u('\x00') if isinstance(secret, unicode) else b('\x00') - if null in secret: - raise ValueError("null char in secret") - - #NOTE: safe_os_crypt encodes unicode secret -> utf8 - #no official policy since des-crypt predates unicode - ok, hash = safe_os_crypt(secret, self.salt) - if ok: + # NOTE: safe_crypt encodes unicode secret -> utf8 + # no official policy since des-crypt predates unicode + hash = safe_crypt(secret, self.salt) + if hash: return hash[2:] else: return self._calc_checksum_builtin(secret) @@ -321,10 +316,10 @@ class bsdi_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler strict=bool(chk), ) - def to_string(self, native=True): + def to_string(self): hash = u("_%s%s%s") % (h64.encode_int24(self.rounds).decode("ascii"), self.salt, self.checksum or u('')) - return uascii_to_str(hash) if native else hash + return uascii_to_str(hash) #========================================================= #backend @@ -335,8 +330,7 @@ class bsdi_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler @classproperty def _has_backend_os_crypt(cls): - h = u('_/...lLDAxARksGCHin.') - return bool(safe_os_crypt and safe_os_crypt(u("test"),h)[1]==h) + return test_crypt("test", '_/...lLDAxARksGCHin.') def _calc_checksum_builtin(self, secret): if isinstance(secret, unicode): @@ -344,8 +338,8 @@ class bsdi_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler return raw_ext_crypt(secret, self.rounds, self.salt.encode("ascii")).decode("ascii") def _calc_checksum_os_crypt(self, secret): - ok, hash = safe_os_crypt(secret, self.to_string(native=False)) - if ok: + hash = safe_crypt(secret, self.to_string()) + if hash: return hash[9:] else: return self._calc_checksum_builtin(secret) @@ -414,9 +408,9 @@ class bigcrypt(uh.HasSalt, uh.GenericHandler): salt, chk = m.group("salt", "chk") return cls(salt=salt, checksum=chk, strict=bool(chk)) - def to_string(self, native=True): + def to_string(self): hash = u("%s%s") % (self.salt, self.checksum or u('')) - return uascii_to_str(hash) if native else hash + return uascii_to_str(hash) @classmethod def norm_checksum(cls, value, strict=False): @@ -499,9 +493,9 @@ class crypt16(uh.HasSalt, uh.GenericHandler): salt, chk = m.group("salt", "chk") return cls(salt=salt, checksum=chk, strict=bool(chk)) - def to_string(self, native=True): + def to_string(self): hash = u("%s%s") % (self.salt, self.checksum or u('')) - return uascii_to_str(hash) if native else hash + return uascii_to_str(hash) #========================================================= #backend diff --git a/passlib/handlers/md5_crypt.py b/passlib/handlers/md5_crypt.py index 2dd9e7e..e24e66e 100644 --- a/passlib/handlers/md5_crypt.py +++ b/passlib/handlers/md5_crypt.py @@ -9,7 +9,7 @@ import logging; log = logging.getLogger(__name__) from warnings import warn #site #libs -from passlib.utils import classproperty, h64, safe_os_crypt +from passlib.utils import classproperty, h64, safe_crypt, test_crypt from passlib.utils.compat import b, bytes, irange, unicode, u import passlib.utils.handlers as uh #pkg @@ -227,15 +227,14 @@ class md5_crypt(uh.HasManyBackends, _Md5Common): @classproperty def _has_backend_os_crypt(cls): - h = u('$1$test$pi/xDtU5WFVRqYS6BMU8X/') - return bool(safe_os_crypt and safe_os_crypt(u("test"),h)[1]==h) + return test_crypt("test", '$1$test$pi/xDtU5WFVRqYS6BMU8X/') def _calc_checksum_builtin(self, secret): return raw_md5_crypt(secret, self.salt) def _calc_checksum_os_crypt(self, secret): - ok, hash = safe_os_crypt(secret, self.ident + self.salt) - if ok: + hash = safe_crypt(secret, self.ident + self.salt) + if hash: return hash[-22:] else: return self._calc_checksum_builtin(secret) diff --git a/passlib/handlers/pbkdf2.py b/passlib/handlers/pbkdf2.py index 748d75d..8621f03 100644 --- a/passlib/handlers/pbkdf2.py +++ b/passlib/handlers/pbkdf2.py @@ -11,7 +11,7 @@ from warnings import warn #site #libs from passlib.utils import ab64_decode, ab64_encode -from passlib.utils.compat import b, bytes, u, uascii_to_str, unicode +from passlib.utils.compat import b, bytes, str_to_bascii, u, uascii_to_str, unicode from passlib.utils.pbkdf2 import pbkdf2 import passlib.utils.handlers as uh #pkg @@ -313,14 +313,14 @@ class dlitz_pbkdf2_sha1(uh.HasRounds, uh.HasSalt, uh.GenericHandler): strict=bool(chk), ) - def to_string(self, withchk=True, native=True): + def to_string(self, withchk=True): if self.rounds == 400: hash = u('$p5k2$$%s') % (self.salt,) else: hash = u('$p5k2$%x$%s') % (self.rounds, self.salt) if withchk and self.checksum: hash = u("%s$%s") % (hash,self.checksum) - return uascii_to_str(hash) if native else hash + return uascii_to_str(hash) #========================================================= #backend @@ -328,7 +328,7 @@ class dlitz_pbkdf2_sha1(uh.HasRounds, uh.HasSalt, uh.GenericHandler): def calc_checksum(self, secret): if isinstance(secret, unicode): secret = secret.encode("utf-8") - salt = self.to_string(withchk=False, native=False).encode("ascii") + salt = str_to_bascii(self.to_string(withchk=False)) result = pbkdf2(secret, salt, self.rounds, 24, "hmac-sha1") return ab64_encode(result).decode("ascii") diff --git a/passlib/handlers/sha1_crypt.py b/passlib/handlers/sha1_crypt.py index c2eb41d..2a12345 100644 --- a/passlib/handlers/sha1_crypt.py +++ b/passlib/handlers/sha1_crypt.py @@ -13,7 +13,7 @@ import logging; log = logging.getLogger(__name__) from warnings import warn #site #libs -from passlib.utils import classproperty, h64, safe_os_crypt +from passlib.utils import classproperty, h64, safe_crypt, test_crypt from passlib.utils.compat import b, bytes, u, uascii_to_str, unicode from passlib.utils.pbkdf2 import hmac_sha1 import passlib.utils.handlers as uh @@ -90,11 +90,11 @@ class sha1_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler strict=bool(chk), ) - def to_string(self, native=True): + def to_string(self): hash = u("$sha1$%d$%s") % (self.rounds, self.salt) if self.checksum: hash += u("$") + self.checksum - return uascii_to_str(hash) if native else hash + return uascii_to_str(hash) #========================================================= #backend @@ -105,8 +105,8 @@ class sha1_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler @classproperty def _has_backend_os_crypt(cls): - h = u('$sha1$1$Wq3GL2Vp$C8U25GvfHS8qGHimExLaiSFlGkAe') - return bool(safe_os_crypt and safe_os_crypt(u("test"),h)[1]==h) + return test_crypt("test", '$sha1$1$Wq3GL2Vp$C8U''25GvfHS8qGHim' + 'ExLaiSFlGkAe') def _calc_checksum_builtin(self, secret): if isinstance(secret, unicode): @@ -132,8 +132,8 @@ class sha1_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler ] def _calc_checksum_os_crypt(self, secret): - ok, hash = safe_os_crypt(secret, self.to_string(native=False)) - if ok: + hash = safe_crypt(secret, self.to_string()) + if hash: return hash[hash.rindex("$")+1:] else: return self._calc_checksum_builtin(secret) diff --git a/passlib/handlers/sha2_crypt.py b/passlib/handlers/sha2_crypt.py index 8da3f1a..58f32a6 100644 --- a/passlib/handlers/sha2_crypt.py +++ b/passlib/handlers/sha2_crypt.py @@ -9,7 +9,7 @@ import logging; log = logging.getLogger(__name__) from warnings import warn #site #libs -from passlib.utils import classproperty, h64, safe_os_crypt +from passlib.utils import classproperty, h64, safe_crypt, test_crypt from passlib.utils.compat import b, bytes, belem_ord, irange, u, \ uascii_to_str, unicode import passlib.utils.handlers as uh @@ -314,12 +314,12 @@ class sha256_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandl strict=bool(chk), ) - def to_string(self, native=True): + def to_string(self): if self.rounds == 5000 and self.implicit_rounds: hash = u("$5$%s$%s") % (self.salt, self.checksum or u('')) else: hash = u("$5$rounds=%d$%s$%s") % (self.rounds, self.salt, self.checksum or u('')) - return uascii_to_str(hash) if native else hash + return uascii_to_str(hash) #========================================================= #backend @@ -330,8 +330,8 @@ class sha256_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandl @classproperty def _has_backend_os_crypt(cls): - h = u("$5$rounds=1000$test$QmQADEXMG8POI5WDsaeho0P36yK3Tcrgboabng6bkb/") - return bool(safe_os_crypt and safe_os_crypt(u("test"),h)[1]==h) + return test_crypt("test", "$5$rounds=1000$test$QmQADEXMG8POI5W" + "Dsaeho0P36yK3Tcrgboabng6bkb/") def _calc_checksum_builtin(self, secret): if isinstance(secret, unicode): @@ -346,12 +346,12 @@ class sha256_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandl return checksum.decode("ascii") def _calc_checksum_os_crypt(self, secret): - ok, result = safe_os_crypt(secret, self.to_string(native=False)) - if ok: + hash = safe_crypt(secret, self.to_string()) + if hash: #NOTE: avoiding full parsing routine via from_string().checksum, # and just extracting the bit we need. - assert result.startswith(u("$5$")) - chk = result[-43:] + assert hash.startswith(u("$5$")) + chk = hash[-43:] assert u('$') not in chk return chk else: @@ -466,12 +466,12 @@ class sha512_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandl strict=bool(chk), ) - def to_string(self, native=True): + def to_string(self): if self.rounds == 5000 and self.implicit_rounds: hash = u("$6$%s$%s") % (self.salt, self.checksum or u('')) else: hash = u("$6$rounds=%d$%s$%s") % (self.rounds, self.salt, self.checksum or u('')) - return uascii_to_str(hash) if native else hash + return uascii_to_str(hash) #========================================================= #backend @@ -482,8 +482,10 @@ class sha512_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandl @classproperty def _has_backend_os_crypt(cls): - h = u("$6$rounds=1000$test$2M/Lx6MtobqjLjobw0Wmo4Q5OFx5nVLJvmgseatA6oMnyWeBdRDx4DU.1H3eGmse6pgsOgDisWBGI5c7TZauS0") - return bool(safe_os_crypt and safe_os_crypt(u("test"),h)[1]==h) + return test_crypt("test", "$6$rounds=1000$test$2M/Lx6Mtobqj" + "Ljobw0Wmo4Q5OFx5nVLJvmgseatA6oMn" + "yWeBdRDx4DU.1H3eGmse6pgsOgDisWBG" + "I5c7TZauS0") #NOTE: testing w/ HashTimer shows 64-bit linux's crypt to be ~2.6x faster than builtin (627253 vs 238152 rounds/sec) @@ -500,12 +502,12 @@ class sha512_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandl return checksum.decode("ascii") def _calc_checksum_os_crypt(self, secret): - ok, result = safe_os_crypt(secret, self.to_string(native=False)) - if ok: + hash = safe_crypt(secret, self.to_string()) + if hash: #NOTE: avoiding full parsing routine via from_string().checksum, # and just extracting the bit we need. - assert result.startswith(u("$6$")) - chk = result[-86:] + assert hash.startswith(u("$6$")) + chk = hash[-86:] assert u('$') not in chk return chk else: diff --git a/passlib/handlers/sun_md5_crypt.py b/passlib/handlers/sun_md5_crypt.py index c7b99bb..1a93c41 100644 --- a/passlib/handlers/sun_md5_crypt.py +++ b/passlib/handlers/sun_md5_crypt.py @@ -19,7 +19,7 @@ from warnings import warn #libs from passlib.utils import h64 from passlib.utils.compat import b, bytes, belem_ord, trange, u, \ - uascii_to_str, unicode + uascii_to_str, unicode, str_to_bascii import passlib.utils.handlers as uh #pkg #local @@ -307,7 +307,7 @@ class sun_md5_crypt(uh.HasRounds, uh.HasSalt, uh.GenericHandler): strict=bool(chk), ) - def to_string(self, withchk=True, native=True): + def to_string(self, withchk=True): ss = u('') if self.bare_salt else u('$') rounds = self.rounds if rounds > 0: @@ -318,7 +318,7 @@ class sun_md5_crypt(uh.HasRounds, uh.HasSalt, uh.GenericHandler): chk = self.checksum if chk: hash = u("%s$%s") % (hash, chk) - return uascii_to_str(hash) if native else hash + return uascii_to_str(hash) #========================================================= #primary interface @@ -334,7 +334,7 @@ class sun_md5_crypt(uh.HasRounds, uh.HasSalt, uh.GenericHandler): raise TypeError("no secret specified") if isinstance(secret, unicode): secret = secret.encode("utf-8") - config = self.to_string(withchk=False,native=False).encode("ascii") + config = str_to_bascii(self.to_string(withchk=False)) return raw_sun_md5_crypt(secret, self.rounds, config).decode("ascii") #========================================================= |
