-
Notifications
You must be signed in to change notification settings - Fork 2
/
balloon.py
89 lines (75 loc) · 2.55 KB
/
balloon.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import hashlib
hash_function = hashlib.sha256
"""
Concatenate all arguments and hash them together
"""
def hash_func(*args):
# Convert everything to bytes first
byte_args = b''
for arg in args:
if not isinstance(arg, bytes):
str_rep = str(arg)
byte_args += str.encode(str_rep)
else:
byte_args += arg
return hash_function(byte_args).digest()
"""
First step of the algorithm. Fill up a buffer with
pseudorandom bytes derived from the password and salt
by computing repeatedly the hash function on a combination
of the password and the previous hash.
"""
def expand(buf, cnt, space_cost):
for s in range(1, space_cost):
buf.append(hash_func(cnt, buf[s - 1]))
cnt += 1
"""
Mixing step of the balloon hash.
- cnt: security parameter from paper
- delta: number of random blocks to mix with
- salt: string representation of salt
- space_cost: size of the buffer
- time_cost: number of mixing rounds
Returns nothing, updates buffer in place.
"""
def mix(buf, cnt, delta, salt, space_cost, time_cost):
for t in range(time_cost):
for s in range(space_cost):
buf[s] = hash_func(cnt, buf[s - 1], buf[s])
cnt += 1
for i in range(delta):
other = int.from_bytes(hash_func(cnt, salt, t, s, i), byteorder='little') % space_cost
cnt += 1
buf[s] = hash_func(cnt, buf[s], buf[other])
cnt += 1
"""
Returns last value in the buffer. Returns a string.
"""
def extract(buf):
return buf[-1]
"""
Implementation of the balloon function from https://eprint.iacr.org/2016/027.pdf
Does the following steps to hash a value with a specific time cost and space cost.
* expand
* mix
* extract
Takes in password and salt (the naming convention of the paper) as strings, takes in
ints for space and time costs. Delta is an int for number of mixing blocks.
"""
def balloon(pw, salt, space, time, delta=3):
buf = [hash_func(0, pw, salt)]
cnt = 1
expand(buf, cnt, space)
mix(buf, cnt, delta, salt, space, time)
return extract(buf)
"""
Takes in two strings, password and the salt, and computes the balloon
hash with some space cost and time cost. Will return a string.
"""
def balloon_hash(password, salt, space=30, time=30, delta=5):
pw = password.encode('utf-8')
slt = salt.encode('utf-8')
return balloon(pw, slt, space, time, delta=delta)
if __name__ == '__main__':
print("Raymond.")
print(balloon_hash("HEH", "NOTHING PERSONNEL"))