Skip to content

Instantly share code, notes, and snippets.

@0xpizza
Last active April 16, 2019 19:57
Show Gist options
  • Save 0xpizza/96a44d810d156eedc17911b7fc34d12c to your computer and use it in GitHub Desktop.
Save 0xpizza/96a44d810d156eedc17911b7fc34d12c to your computer and use it in GitHub Desktop.
import os
import base64
import hashlib
class Scrypt():
@staticmethod
def _make_bytes(pw, encoding):
if isinstance(pw, str):
try:
pw = pw.encode(encoding)
except UnicodeEncodeError as e:
e.args = ('Invalid string. Hashes must be ASCII and passwords should be UTF-8',)
raise e
if not isinstance(pw, bytes):
raise ValueError(
'Value must be {} or {}, not {}'\
.format(repr(bytes), repr(str), type(pw))
)
return pw
@staticmethod
def _const_time_comparison(a, b):
if len(a) != len(b):
return False
result = 0
for j,k in zip(a,b):
result ^= j ^ k
if result == 0:
return True
else:
return False
@staticmethod
def hash(password, salt=None, n=17, p=1, r=8, dklen=18, encoding='UTF-8'):
maxmem = 0x7fffffff
password = Scrypt._make_bytes(password, encoding)
_n = 2**n
salt = os.urandom(18) if salt is None else salt
hash = hashlib.scrypt(password, salt=salt, n=_n, p=p, r=r, maxmem=maxmem, dklen=dklen)
salt = base64.b64encode(salt).decode()
hash = base64.b64encode(hash).decode()
PHC = f'$scrypt$n={n}$p={p}$r={r}${salt}${hash}'
return PHC
@staticmethod
def verify(param_string, password):
params = param_string.split('$')[1:]
salt = params[-2]
try:
params = {k:int(v) for k,v in map(lambda s: s.split('='), params[1:-2])}
except ValueError:
raise ValueError(
'invalid parameter string'
)
salt = base64.b64decode(salt)
return Scrypt._const_time_comparison(
Scrypt._make_bytes(Scrypt.hash(password, salt=salt, **params), 'ascii')
,Scrypt._make_bytes(param_string, 'ascii'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment