def _pseudorandom(x, mac=mac): h = mac.copy() h.update(ensureBytes(x)) if not IS_PYTHON3: return list(map(ord, h.digest())) else: return list(h.digest())
def shadow(password): """Generate a random salt and return a new hash for the password.""" if isinstance(password, str): password = password.encode('utf-8') salt = b64encode(urandom(SALT_LENGTH)) p = b64encode(ensureBytes(pbkdf2_bin(password, salt, COST_FACTOR, KEY_LENGTH, getattr(hashlib, HASH_FUNCTION)))) return 'PBKDF2${}${}${}${}'.format( HASH_FUNCTION, COST_FACTOR, ensureString(salt, "ascii"), ensureString(p, "ascii"), )
def verify(password, shadow): """Check a password against an existing hash.""" password = ensureString(password) algorithm, hash_function, cost_factor, salt, hash_a = shadow.split('$') assert algorithm == 'PBKDF2' salt = ensureBytes(salt) hash_a = b64decode(hash_a) hash_b = pbkdf2_bin(password, salt, int(cost_factor), len(hash_a), getattr(hashlib, hash_function)) assert len(hash_a) == len(hash_b) # we requested this from pbkdf2_bin() # Same as "return hash_a == hash_b" but takes a constant time. # See http://carlos.bueno.org/2011/10/timing.html diff = 0 for char_a, char_b in zip(hash_a, hash_b): if IS_PYTHON3: diff |= char_a ^ ord(char_b) else: diff |= ord(char_a) ^ ord(char_b) return diff == 0