def pbkdf2(passwd, salt, hashtype=HashTypes.SHA2, iterations=10000, dklen=None): """ Derive a bytes-like key from a string password using the specified hash. salt is bytes-like. Greater iterations provide greater security. If dklen is specified, it must be an int. """ if isinstance(passwd, str): passwd = passwd.encode() check_hashtype(hashtype) if hashtype == HashTypes.SHA1: hash_name = 'sha1' elif hashtype == HashTypes.SHA2: hash_name = 'sha256' elif hashtype == HashTypes.SHA3: hash_name = 'sha3_256' elif hashtype == HashTypes.BLAKE2B: hash_name = 'blake2b' # blake2b gets "unsupported hash type" if sys.version_info >= (3, 6): # hash_name is str like 'sha1' or 'sha256' # LIMITATION: 'sha3', variations, and 'blake2b' are NOT SUPPORTED # passwd must be bytes-like return _pbkdf2(hash_name, passwd, salt, iterations, dklen) else: if not dklen: dklen = 32 # just playing around return PBKDF2(passwd, salt, iterations=iterations).read(dklen)
def scrypt(password, salt, N=SCRYPT_N, r=SCRYPT_r, p=SCRYPT_p, olen=64): """Returns a key derived using the scrypt key-derivarion function N must be a power of two larger than 1 but no larger than 2 ** 63 (insane) r and p must be positive numbers such that r * p < 2 ** 30 The default values are: N -- 2**14 (~16k) r -- 8 p -- 1 Memory usage is proportional to N*r. Defaults require about 16 MiB. Time taken is proportional to N*p. Defaults take <100ms of a recent x86. The last one differs from libscrypt defaults, but matches the 'interactive' work factor from the original paper. For long term storage where runtime of key derivation is not a problem, you could use 16 as in libscrypt or better yet increase N if memory is plentiful. """ check_args(password, salt, N, r, p, olen) # Everything is lists of 32-bit uints for all but pbkdf2 try: B = _pbkdf2('sha256', password, salt, 1, p * 128 * r) B = list(struct.unpack('<%dI' % (len(B) // 4), B)) XY = [0] * (64 * r) V = [0] * (32 * r * N) except (MemoryError, OverflowError): raise ValueError("scrypt parameters don't fit in memory") for i in xrange(p): smix(B, i * 32 * r, r, N, V, XY) B = struct.pack('<%dI' % len(B), *B) return _pbkdf2('sha256', password, B, 1, olen)
def scrypt(password, salt, N=SCRYPT_N, r=SCRYPT_r, p=SCRYPT_p, olen=64): """Returns a key derived using the scrypt key-derivarion function N must be a power of two larger than 1 but no larger than 2 ** 63 (insane) r and p must be positive numbers such that r * p < 2 ** 30 The default values are: N -- 2**14 (~16k) r -- 8 p -- 1 Memory usage is proportional to N*r. Defaults require about 16 MiB. Time taken is proportional to N*p. Defaults take <100ms of a recent x86. The last one differs from libscrypt defaults, but matches the 'interactive' work factor from the original paper. For long term storage where runtime of key derivation is not a problem, you could use 16 as in libscrypt or better yet increase N if memory is plentiful. """ def array_overwrite(source, s_start, dest, d_start, length): dest[d_start:d_start + length] = source[s_start:s_start + length] def blockxor(source, s_start, dest, d_start, length): for i in xrange(length): dest[d_start + i] ^= source[s_start + i] def integerify(B, r): """A bijection from ({0, 1} ** k) to {0, ..., (2 ** k) - 1""" Bi = (2 * r - 1) * 8 return B[Bi] & 0xffffffff def salsa20_8(B, x): """Salsa 20/8 using libsodium NaCL/libsodium includes crypto_core_salsa208, but unfortunately it expects the data in a different order, so we need to mix it up a bit. """ hi = 0xffffffff00000000 lo = 0x00000000ffffffff struct.pack_into('<9Q', x, 0, (B[0] & lo) + (B[2] & hi), (B[5] & lo) + (B[7] & hi), # c B[3], B[4], # in B[0], B[1], (B[2] & lo) + (B[5] & hi), # pad k pad B[6], B[7], ) c = ctypes.addressof(x) i = c + 4*4 k = c + 9*4 _libsodium_salsa20_8(c, i, k, c) B[:] = struct.unpack('<8Q8x', x) def blockmix_salsa8(BY, Yi, r): """Blockmix; Used by SMix""" start = (2 * r - 1) * 8 X = BY[start:start+8] # BlockMix - 1 x = ctypes.create_string_buffer(8*9) for i in xrange(2 * r): # BlockMix - 2 blockxor(BY, i * 8, X, 0, 8) # BlockMix - 3(inner) salsa20_8(X, x) # BlockMix - 3(outer) array_overwrite(X, 0, BY, Yi + (i * 8), 8) # BlockMix - 4 for i in xrange(r): # BlockMix - 6 array_overwrite(BY, Yi + (i * 2) * 8, BY, i * 8, 8) array_overwrite(BY, Yi + (i*2 + 1) * 8, BY, (i + r) * 8, 8) def smix(B, Bi, r, N, V, X): """SMix; a specific case of ROMix based on Salsa20/8""" array_overwrite(B, Bi, X, 0, 16 * r) # ROMix - 1 for i in xrange(N): # ROMix - 2 array_overwrite(X, 0, V, i * (16 * r), 16 * r) # ROMix - 3 blockmix_salsa8(X, 16 * r, r) # ROMix - 4 for i in xrange(N): # ROMix - 6 j = integerify(X, r) & (N - 1) # ROMix - 7 blockxor(V, j * (16 * r), X, 0, 16 * r) # ROMix - 8(inner) blockmix_salsa8(X, 16 * r, r) # ROMix - 9(outer) array_overwrite(X, 0, B, Bi, 16 * r) # ROMix - 10 check_args(password, salt, N, r, p, olen) # Everything is lists of 64-bit uints for all but pbkdf2 try: B = _pbkdf2('sha256', password, salt, 1, p * 128 * r) B = list(struct.unpack('<%dQ' % (len(B) // 8), B)) XY = [0] * (32 * r) V = [0] * (16 * r * N) except (MemoryError, OverflowError): raise ValueError("scrypt parameters don't fit in memory") for i in xrange(p): smix(B, i * 16 * r, r, N, V, XY) B = struct.pack('<%dQ' % len(B), *B) return _pbkdf2('sha256', password, B, 1, olen)