def raw(cls, secret, user): """encode password using mscash v1 algorithm :arg secret: secret as unicode or utf-8 encoded bytes :arg user: username to use as salt :returns: returns string of raw bytes """ secret = to_unicode(secret, "utf-8", param="secret").encode("utf-16-le") user = to_unicode(user, "utf-8", param="user").lower().encode("utf-16-le") return md4(md4(secret).digest() + user).digest()
def __init__(self, wordset=None, words=None, sep=None, **kwds): # load wordset if words is not None: if wordset is not None: raise TypeError("`words` and `wordset` are mutually exclusive") else: if wordset is None: wordset = self.wordset assert wordset words = default_wordsets[wordset] self.wordset = wordset # init words if not isinstance(words, _sequence_types): words = tuple(words) _ensure_unique(words, param="words") self.words = words # init separator if sep is None: sep = self.sep sep = to_unicode(sep, param="sep") self.sep = sep # hand off to parent super(PhraseGenerator, self).__init__(**kwds)
def from_string(cls, hash): hash = to_unicode(hash, "ascii", "hash") m = cls._hash_regex.match(hash) if not m: raise uh.exc.InvalidHashError(cls) salt, chk = m.group("salt", "chk") return cls(salt=salt, checksum=chk.upper())
def test_02_from_string(self): """test CryptPolicy.from_string() constructor""" # test "\n" linesep policy = CryptPolicy.from_string(self.sample_config_1s) self.assertEqual(policy.to_dict(), self.sample_config_1pd) # test "\r\n" linesep policy = CryptPolicy.from_string( self.sample_config_1s.replace("\n", "\r\n")) self.assertEqual(policy.to_dict(), self.sample_config_1pd) # test with unicode data = to_unicode(self.sample_config_1s) policy = CryptPolicy.from_string(data) self.assertEqual(policy.to_dict(), self.sample_config_1pd) # test with non-ascii-compatible encoding uc2 = to_bytes(self.sample_config_1s, "utf-16", source_encoding="utf-8") policy = CryptPolicy.from_string(uc2, encoding="utf-16") self.assertEqual(policy.to_dict(), self.sample_config_1pd) # test category specific options policy = CryptPolicy.from_string(self.sample_config_4s) self.assertEqual(policy.to_dict(), self.sample_config_4pd)
def from_string(cls, hash): hash = to_unicode(hash, "ascii", "hash") m = cls._hash_regex.match(hash) if not m: raise uh.exc.InvalidHashError(cls) salt, chk = m.group("salt", "chk") return cls(salt=salt, checksum=chk)
def raw(cls, secret, user): """encode password using msdcc v2 algorithm :type secret: unicode or utf-8 bytes :arg secret: secret :type user: str :arg user: username to use as salt :returns: returns string of raw bytes """ from lib.passlib.utils.pbkdf2 import pbkdf2 secret = to_unicode(secret, "utf-8", param="secret").encode("utf-16-le") user = to_unicode(user, "utf-8", param="user").lower().encode("utf-16-le") tmp = md4(md4(secret).digest() + user).digest() return pbkdf2(tmp, user, 10240, 16, 'hmac-sha1')
def from_string(cls, hash): hash = to_unicode(hash, "ascii", "hash") if not hash.startswith(cls.django_prefix): raise uh.exc.InvalidHashError(cls) bhash = hash[len(cls.django_prefix):] if not bhash.startswith("$2"): raise uh.exc.MalformedHashError(cls) return super(django_bcrypt_sha256, cls).from_string(bhash)
def from_string(cls, hash): hash = to_unicode(hash, "ascii", "hash") ident = cls.ident if not hash.startswith(ident): raise uh.exc.InvalidHashError(cls) data = b64decode(hash[len(ident):].encode("ascii")) salt, chk = data[:16], data[16:] return cls(salt=salt, checksum=chk)
def from_string(cls, hash): hash = to_unicode(hash, "ascii", "hash") ident = cls.ident if not hash.startswith(ident): raise uh.exc.InvalidHashError(cls) data = b64decode(hash[len(ident):].encode("ascii")) salt, chk = data[:16], data[16:] return cls(salt=salt, checksum=chk)
def raw(cls, secret): """encode password using MD4-based NTHASH algorithm :arg secret: secret as unicode or utf-8 encoded bytes :returns: returns string of raw bytes """ secret = to_unicode(secret, "utf-8", param="secret") # XXX: found refs that say only first 128 chars are used. return md4(secret.encode("utf-16-le")).digest()
def from_string(cls, hash): hash = to_unicode(hash, "ascii", "hash") m = cls._hash_regex.match(hash) if not m: raise uh.exc.InvalidHashError(cls) rounds, salt, chk = m.group("rounds", "salt", "chk") return cls( rounds=h64.decode_int24(rounds.encode("ascii")), salt=salt, checksum=chk, )
def from_string(cls, hash): hash = to_unicode(hash, "ascii", "hash") m = cls._hash_regex.match(hash) if not m: raise uh.exc.InvalidHashError(cls) rounds, salt, chk = m.group("rounds", "salt", "chk") return cls( rounds=h64.decode_int24(rounds.encode("ascii")), salt=salt, checksum=chk, )
def from_string(cls, hash): hash = to_unicode(hash, "ascii", "hash") m = cls._hash_regex.match(hash) if not m: raise uh.exc.InvalidHashError(cls) try: data = b64decode(m.group("tmp").encode("ascii")) except TypeError: raise uh.exc.MalformedHashError(cls) cs = cls.checksum_size assert cs return cls(checksum=data[:cs], salt=data[cs:])
def from_string(cls, hash): hash = to_unicode(hash, "ascii", "hash") if not hash.startswith(cls.prefix): raise uh.exc.InvalidHashError(cls) m = cls._hash_re.match(hash) if not m: raise uh.exc.MalformedHashError(cls) rounds = m.group("rounds") if rounds.startswith(uh._UZERO) and rounds != uh._UZERO: raise uh.exc.ZeroPaddedRoundsError(cls) return cls(ident=m.group("variant"), rounds=int(rounds), salt=m.group("salt"), checksum=m.group("digest"), )
def from_string(cls, hash): hash = to_unicode(hash, "ascii", "hash") m = cls._hash_regex.match(hash) if not m: raise uh.exc.InvalidHashError(cls) variant, salt_size, rounds, data = m.group(1,2,3,4) variant = int(variant) salt_size = int(salt_size) rounds = int(rounds) try: data = b64decode(data.encode("ascii")) except TypeError: raise uh.exc.MalformedHashError(cls) salt = data[:salt_size] chk = data[salt_size:] return cls(salt=salt, checksum=chk, rounds=rounds, variant=variant)
def from_string(cls, hash): # basic format this parses - # $5$[rounds=<rounds>$]<salt>[$<checksum>] # TODO: this *could* use uh.parse_mc3(), except that the rounds # portion has a slightly different grammar. # convert to unicode, check for ident prefix, split on dollar signs. hash = to_unicode(hash, "ascii", "hash") ident = cls.ident if not hash.startswith(ident): raise uh.exc.InvalidHashError(cls) assert len(ident) == 3 parts = hash[3:].split(_UDOLLAR) # extract rounds value if parts[0].startswith(_UROUNDS): assert len(_UROUNDS) == 7 rounds = parts.pop(0)[7:] if rounds.startswith(_UZERO) and rounds != _UZERO: raise uh.exc.ZeroPaddedRoundsError(cls) rounds = int(rounds) implicit_rounds = False else: rounds = 5000 implicit_rounds = True # rest should be salt and checksum if len(parts) == 2: salt, chk = parts elif len(parts) == 1: salt = parts[0] chk = None else: raise uh.exc.MalformedHashError(cls) # return new object return cls( rounds=rounds, salt=salt, checksum=chk or None, implicit_rounds=implicit_rounds, relaxed=not chk, # NOTE: relaxing parsing for config strings # so that out-of-range rounds are clipped, # since SHA2-Crypt spec treats them this way. )
def from_string(cls, hash): # basic format this parses - # $5$[rounds=<rounds>$]<salt>[$<checksum>] # TODO: this *could* use uh.parse_mc3(), except that the rounds # portion has a slightly different grammar. # convert to unicode, check for ident prefix, split on dollar signs. hash = to_unicode(hash, "ascii", "hash") ident = cls.ident if not hash.startswith(ident): raise uh.exc.InvalidHashError(cls) assert len(ident) == 3 parts = hash[3:].split(_UDOLLAR) # extract rounds value if parts[0].startswith(_UROUNDS): assert len(_UROUNDS) == 7 rounds = parts.pop(0)[7:] if rounds.startswith(_UZERO) and rounds != _UZERO: raise uh.exc.ZeroPaddedRoundsError(cls) rounds = int(rounds) implicit_rounds = False else: rounds = 5000 implicit_rounds = True # rest should be salt and checksum if len(parts) == 2: salt, chk = parts elif len(parts) == 1: salt = parts[0] chk = None else: raise uh.exc.MalformedHashError(cls) # return new object return cls( rounds=rounds, salt=salt, checksum=chk or None, implicit_rounds=implicit_rounds, relaxed=not chk, # NOTE: relaxing parsing for config strings # so that out-of-range rounds are clipped, # since SHA2-Crypt spec treats them this way. )
def __init__(self, chars=None, charset=None, **kwds): # init chars and charset if chars: if charset: raise TypeError("`chars` and `charset` are mutually exclusive") else: if not charset: charset = self.charset assert charset chars = default_charsets[charset] self.charset = charset chars = to_unicode(chars, param="chars") _ensure_unique(chars, param="chars") self.chars = chars # hand off to parent super(WordGenerator, self).__init__(**kwds)
def _calc_checksum(self, secret): # FIXME: not sure how oracle handles unicode. # online docs about 10g hash indicate it puts ascii chars # in a 2-byte encoding w/ the high byte set to null. # they don't say how it handles other chars, or what encoding. # # so for now, encoding secret & user to utf-16-be, # since that fits, and if secret/user is bytes, # we assume utf-8, and decode first. # # this whole mess really needs someone w/ an oracle system, # and some answers :) if isinstance(secret, bytes): secret = secret.decode("utf-8") user = to_unicode(self.user, "utf-8", param="user") input = (user + secret).upper().encode("utf-16-be") hash = des_cbc_encrypt(ORACLE10_MAGIC, input) hash = des_cbc_encrypt(hash, input) return hexlify(hash).decode("ascii").upper()
def test_02_from_string(self): """test CryptPolicy.from_string() constructor""" # test "\n" linesep policy = CryptPolicy.from_string(self.sample_config_1s) self.assertEqual(policy.to_dict(), self.sample_config_1pd) # test "\r\n" linesep policy = CryptPolicy.from_string( self.sample_config_1s.replace("\n","\r\n")) self.assertEqual(policy.to_dict(), self.sample_config_1pd) # test with unicode data = to_unicode(self.sample_config_1s) policy = CryptPolicy.from_string(data) self.assertEqual(policy.to_dict(), self.sample_config_1pd) # test with non-ascii-compatible encoding uc2 = to_bytes(self.sample_config_1s, "utf-16", source_encoding="utf-8") policy = CryptPolicy.from_string(uc2, encoding="utf-16") self.assertEqual(policy.to_dict(), self.sample_config_1pd) # test category specific options policy = CryptPolicy.from_string(self.sample_config_4s) self.assertEqual(policy.to_dict(), self.sample_config_4pd)
def test_to_unicode(self): """test to_unicode()""" from lib.passlib.utils import to_unicode # check unicode inputs self.assertEqual(to_unicode(u('abc')), u('abc')) self.assertEqual(to_unicode(u('\x00\xff')), u('\x00\xff')) # check unicode input ignores encoding self.assertEqual(to_unicode(u('\x00\xff'), "ascii"), u('\x00\xff')) # check bytes input self.assertEqual(to_unicode(b('abc')), u('abc')) self.assertEqual(to_unicode(b('\x00\xc3\xbf')), u('\x00\xff')) self.assertEqual(to_unicode(b('\x00\xff'), 'latin-1'), u('\x00\xff')) self.assertRaises(ValueError, to_unicode, b('\x00\xff')) # check other self.assertRaises(AssertionError, to_unicode, 'abc', None) self.assertRaises(TypeError, to_unicode, None)
def from_string(cls, hash): hash = to_unicode(hash, "ascii", "hash") # # detect if hash specifies rounds value. # if so, parse and validate it. # by end, set 'rounds' to int value, and 'tail' containing salt+chk # if hash.startswith(u("$md5$")): rounds = 0 salt_idx = 5 elif hash.startswith(u("$md5,rounds=")): idx = hash.find(u("$"), 12) if idx == -1: raise uh.exc.MalformedHashError(cls, "unexpected end of rounds") rstr = hash[12:idx] try: rounds = int(rstr) except ValueError: raise uh.exc.MalformedHashError(cls, "bad rounds") if rstr != unicode(rounds): raise uh.exc.ZeroPaddedRoundsError(cls) if rounds == 0: # NOTE: not sure if this is forbidden by spec or not; # but allowing it would complicate things, # and it should never occur anyways. raise uh.exc.MalformedHashError(cls, "explicit zero rounds") salt_idx = idx+1 else: raise uh.exc.InvalidHashError(cls) # # salt/checksum separation is kinda weird, # to deal cleanly with some backward-compatible workarounds # implemented by original implementation. # chk_idx = hash.rfind(u("$"), salt_idx) if chk_idx == -1: # ''-config for $-hash salt = hash[salt_idx:] chk = None bare_salt = True elif chk_idx == len(hash)-1: if chk_idx > salt_idx and hash[-2] == u("$"): raise uh.exc.MalformedHashError(cls, "too many '$' separators") # $-config for $$-hash salt = hash[salt_idx:-1] chk = None bare_salt = False elif chk_idx > 0 and hash[chk_idx-1] == u("$"): # $$-hash salt = hash[salt_idx:chk_idx-1] chk = hash[chk_idx+1:] bare_salt = False else: # $-hash salt = hash[salt_idx:chk_idx] chk = hash[chk_idx+1:] bare_salt = True return cls( rounds=rounds, salt=salt, checksum=chk, bare_salt=bare_salt, )
def from_string(cls, hash): hash = to_unicode(hash, "ascii", "hash") if len(hash) < 2: raise uh.exc.InvalidHashError(cls) salt = int(hash[:2]) # may throw ValueError return cls(salt=salt, checksum=hash[2:].upper())
def from_string(cls, hash): hash = to_unicode(hash, "ascii", "hash") salt, chk = hash[:2], hash[2:] return cls(salt=salt, checksum=chk or None)
def from_string(cls, hash): hash = to_unicode(hash, "ascii", "hash") salt, chk = hash[:2], hash[2:] return cls(salt=salt, checksum=chk or None)
def from_string(cls, hash): hash = to_unicode(hash, "ascii", "hash") # # detect if hash specifies rounds value. # if so, parse and validate it. # by end, set 'rounds' to int value, and 'tail' containing salt+chk # if hash.startswith(u("$md5$")): rounds = 0 salt_idx = 5 elif hash.startswith(u("$md5,rounds=")): idx = hash.find(u("$"), 12) if idx == -1: raise uh.exc.MalformedHashError(cls, "unexpected end of rounds") rstr = hash[12:idx] try: rounds = int(rstr) except ValueError: raise uh.exc.MalformedHashError(cls, "bad rounds") if rstr != unicode(rounds): raise uh.exc.ZeroPaddedRoundsError(cls) if rounds == 0: # NOTE: not sure if this is forbidden by spec or not; # but allowing it would complicate things, # and it should never occur anyways. raise uh.exc.MalformedHashError(cls, "explicit zero rounds") salt_idx = idx + 1 else: raise uh.exc.InvalidHashError(cls) # # salt/checksum separation is kinda weird, # to deal cleanly with some backward-compatible workarounds # implemented by original implementation. # chk_idx = hash.rfind(u("$"), salt_idx) if chk_idx == -1: # ''-config for $-hash salt = hash[salt_idx:] chk = None bare_salt = True elif chk_idx == len(hash) - 1: if chk_idx > salt_idx and hash[-2] == u("$"): raise uh.exc.MalformedHashError(cls, "too many '$' separators") # $-config for $$-hash salt = hash[salt_idx:-1] chk = None bare_salt = False elif chk_idx > 0 and hash[chk_idx - 1] == u("$"): # $$-hash salt = hash[salt_idx:chk_idx - 1] chk = hash[chk_idx + 1:] bare_salt = False else: # $-hash salt = hash[salt_idx:chk_idx] chk = hash[chk_idx + 1:] bare_salt = True return cls( rounds=rounds, salt=salt, checksum=chk, bare_salt=bare_salt, )