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 raw_nthash(secret, hex=False): """encode password using md4-based NTHASH algorithm :returns: returns string of raw bytes if ``hex=False``, returns digest as hexidecimal unicode if ``hex=True``. """ secret = to_unicode(secret, "utf-8") hash = md4(secret.encode("utf-16le")) if hex: return to_unicode(hash.hexdigest(), 'ascii') else: return hash.digest()
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 passlib.crypto.digest import pbkdf2_hmac 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_hmac("sha1", tmp, user, 10240, 16)
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 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 _yhsmfrom_string(base, cls, hash): if not hash: raise ValueError('No hash specified') hash = to_unicode(hash, 'ascii', 'hash') if not hash.startswith(cls.ident): raise ValueError('invalid %s hash' % (cls.name)) hash = hash[len(cls.ident):] if hash.startswith(_UKH): part, hash = hash.split(_UDOLLAR, 1) key_handle = part[len(_UKH):] else: key_handle = _UDEFAULT_KH inner_config, chk = hash.rsplit('$', 1) inner = base.from_string('%s%s' % (base.ident, inner_config)) params = {} for kwd in inner.setting_kwds: try: params[kwd] = inner.__getattribute__(kwd) except AttributeError: pass params['key_handle'] = key_handle params['checksum'] = b64decode(chk.encode('ascii')) return cls(**params)
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 __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 encode(value): "encode according to guess at how oracle encodes strings (see note above)" #we can't trust what original encoding was. #user should have passed us unicode in the first place. #but try decoding as utf-8 just to work for most common case. value = to_unicode(value, "utf-8") return value.upper().encode("utf-16-be")
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 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 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") ident, data = hash[0:3], hash[3:] if ident != cls.ident: raise exc.InvalidHashError() rounds, salt, chk = data[0], data[1:9], data[9:] return cls( rounds=h64.decode_int6(rounds.encode("ascii")), salt=salt, checksum=chk or None, )
def genhash(cls, secret, config, user): if config is not None and not cls.identify(config): raise ValueError("not a postgres-md5 hash") if not user: raise ValueError("user keyword must be specified for this algorithm") if isinstance(secret, unicode): secret = secret.encode("utf-8") if isinstance(user, unicode): user = user.encode("utf-8") hash = u"md5" + to_unicode(md5(secret + user).hexdigest()) return to_hash_str(hash)
def genhash(cls, secret, config, user): if config is not None and not cls.identify(config): raise ValueError("not a postgres-md5 hash") if not user: raise ValueError( "user keyword must be specified for this algorithm") if isinstance(secret, unicode): secret = secret.encode("utf-8") if isinstance(user, unicode): user = user.encode("utf-8") hash = u"md5" + to_unicode(md5(secret + user).hexdigest()) return to_hash_str(hash)
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 test_90_decode(self): """test cisco_type7.decode()""" from passlib.utils import to_unicode, to_bytes handler = self.handler for secret, hash in self.known_correct_hashes: usecret = to_unicode(secret) bsecret = to_bytes(secret) self.assertEqual(handler.decode(hash), usecret) self.assertEqual(handler.decode(hash, None), bsecret) self.assertRaises(UnicodeDecodeError, handler.decode, '0958EDC8A9F495F6F8A5FD', 'ascii')
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 _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 __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 from_string(cls, hash, **context): # default from_string() which strips optional prefix, # and passes rest unchanged as checksum value. hash = to_unicode(hash, "ascii", "hash") hash = cls._norm_hash(hash) # could enable this for extra strictness ##pat = cls._hash_regex ##if pat and pat.match(hash) is None: ## raise ValueError("not a valid %s hash" % (cls.name,)) prefix = cls._hash_prefix if prefix: if hash.startswith(prefix): hash = hash[len(prefix):] else: raise exc.InvalidHashError(cls) # Decode the base64 stored actual hash hash = unicode(base64.b64decode(hash)) return cls(checksum=hash, **context)
def test_to_unicode(self): "test 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', None), u'\x00\xff') 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')) self.assertRaises(TypeError, to_unicode, b('\x00\xff'), None) #check other self.assertRaises(TypeError, to_unicode, None)
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 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 calc_checksum(self, secret): if isinstance(secret, unicode): secret = secret.encode("utf-8") return to_unicode(sha1(self.salt.encode("ascii") + secret).hexdigest(), "ascii")
def calc_checksum(self, secret): if isinstance(secret, unicode): secret = secret.encode("utf-8") data = self.salt.encode("ascii") + secret + self.salt.encode("ascii") return to_unicode(hashlib.sha1(data).hexdigest(), "latin-1")
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") 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 calc_checksum(self, secret): if isinstance(secret, unicode): secret = secret.encode("utf-8") return to_unicode( sha1(self.salt.encode("ascii") + secret).hexdigest(), "ascii")
def calc_checksum(self, secret): if isinstance(secret, unicode): secret = secret.encode("utf-8") chk = sha1(secret + unhexlify(self.salt.encode("ascii"))).hexdigest() return to_unicode(chk, 'ascii').upper()
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") # # 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, )