def generate_password_hash(password, salt, N=1 << 14, r=8, p=1, buflen=64): """ Generate password hash givin the password string and salt. Args: - ``password``: Password string. - ``salt`` : Random base64 encoded string. Optional args: - ``N`` : the CPU cost, must be a power of 2 greater than 1, defaults to 1 << 14. - ``r`` : the memory cost, defaults to 8. - ``p`` : the parallelization parameter, defaults to 1. The parameters r, p, and buflen must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The recommended parameters for interactive logins as of 2009 are N=16384, r=8, p=1. Remember to use a good random salt. Returns: - base64 encoded scrypt hash. """ if PYTHON2: password = password.encode('utf-8') salt = salt.encode('utf-8') pw_hash = scrypt_hash(password, salt, N, r, p, buflen) return enbase64(pw_hash)
def set_password(self, password): salt = base64.b64encode(urandom(64)) self.passsalt = salt self.passhash = base64.b64encode( scrypt_hash( password.encode('utf-8'), salt.encode('utf-8')))
def scrypt(password, salt): # Why did we choose the scrypt factors that we did? Well... we at least bothered to read the abstract of the scrypt # paper, which is apparently more than the creators of Litecoin (and all its clones) did. As such, we tried to tune # the parameters using the super-scientific method of timing it our our local development machines, aiming for # 100ms. N= 1 << 15 turned out to be the magic number, as guessed correctly by mr. Percival himself: # https://github.com/golang/go/issues/22082#issuecomment-332983728 # Having said that, remember that ancient truth of crypto-currency: everything you see is shoddily built, since you # can always paper over your mistakes with technobabble. Present coin included. # More (fun) reading: # https://bitcoin.stackexchange.com/questions/36642/why-did-litecoin-choose-the-scrypt-factors-that-they-did # buflen 32 was chosen... because scrypt's output is going to through sha256d anyway, so no sense in a greater # output space return scrypt_hash(password, salt, N=1 << 15, r=8, p=1, buflen=32)
def check_password(self, password): candidate_hash = base64.b64encode( scrypt_hash( password.encode('utf-8'), self.passsalt.encode('utf-8'))) return self.passhash.encode('utf-8') == candidate_hash