-
Notifications
You must be signed in to change notification settings - Fork 14
/
blinding.sage
50 lines (36 loc) · 1.46 KB
/
blinding.sage
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
import random
def generate_private_params(e=65537, bits=1024):
while 1:
p = random_prime(2^bits, proof=False)
q = random_prime(2^bits, proof=False)
N = p * q
phi = (p - 1) * (q - 1)
if gcd(phi, e) != 1:
continue
d = inverse_mod(e, phi)
return N, d
def sign_message(m, N, d, deny=range(0, 10000)):
# deny is the range of messages that the signer refuses to sign.
if m in deny:
raise ValueError("Wait that's illegal")
s = pow(m, d, N)
return s
def test():
m = 10001
m2 = 10002
e = 65537
target_m = 2
N, d = generate_private_params()
s1 = sign_message(m, N, d)
s2 = sign_message(m2, N, d)
r = random.randint(0, N)
# Let's say the attacker wants to obtain a signature of m = 2. Obviously he can't do this directly since the sender won't allows a signature for 2.
# However, this does little to stop the attacker, who can pick an `r` in Z_n and request a signature $s$ for $r^e * m$.
# The signer doesn't know the attacker's intentions and assumes that because the message is not in a list of banned ones
# It is safe to sign. The attacker can then calculate the desired signature of $m$ by simply taking ((r^-1 mod N) * s) mod N.
s_r = inverse_mod(r, N) * sign_message(pow(r, e, N) * target_m, N, d)
sig_of_2 = sign_message(2, N, d, deny=[])
assert sig_of_2 == s_r
return s_r
if __name__ == "__main__":
test()