Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
jvdsn
GitHub Repository: jvdsn/crypto-attacks
Path: blob/master/attacks/rsa/desmedt_odlyzko.py
2589 views
1
import logging
2
3
from sage.all import GF
4
from sage.all import ZZ
5
from sage.all import factor
6
from sage.all import matrix
7
from sage.all import next_prime
8
from sage.all import vector
9
10
11
def attack(hash_oracle, sign_oracle, N, e, target_m):
12
"""
13
Performs a selective forgery attack using the Desmedt-Odlyzko attack.
14
Note that this selective forgery attack is much slower than the existential forgery attack. However, it is also more applicable to real world scenarios.
15
More information: Coron J. et al., "Practical Cryptanalysis of ISO 9796-2 and EMV Signatures (Section 3)"
16
:param hash_oracle: the oracle taking integer messages, returns an integer representation of the hashed message
17
:param sign_oracle: the oracle taking integer messages, returns an integer representation of the signature
18
:param N: the modulus
19
:param e: the public exponent
20
:param target_m: the target message to sign (integer)
21
:return: the signature of the target message (integer)
22
"""
23
target_factors = factor(hash_oracle(target_m))
24
B, _ = target_factors[-1]
25
26
logging.info(f"Computing all primes <= {B}...")
27
primes = {}
28
p = 2
29
i = 0
30
while p <= B:
31
primes[p] = i
32
p = next_prime(p)
33
i += 1
34
35
l = len(primes)
36
37
Vt = vector(GF(e), l, sparse=True)
38
for p, v in target_factors:
39
Vt[primes[p]] = v
40
41
logging.info(f"Generating initial {l}x{l} matrix...")
42
M = matrix(GF(e), l, sparse=True)
43
m = []
44
mi = 0
45
i = 0
46
while i < l:
47
factors = factor(hash_oracle(mi))
48
if all(p <= B for p, _ in factors):
49
for p, v in factors:
50
M[i, primes[p]] = v
51
m.append(mi)
52
i += 1
53
mi += 1
54
55
rank = M.rank()
56
logging.info(f"Extending initial matrix with rank {rank} (required = {l})...")
57
while rank < l:
58
Vi = vector(GF(e), l, sparse=True)
59
factors = factor(hash_oracle(mi))
60
if all(p <= B for p, _ in factors):
61
for p, v in factors:
62
Vi[primes[p]] = v
63
M_ = M.stack(Vi)
64
rank_ = M_.rank()
65
if rank_ > rank:
66
M = M_
67
rank = rank_
68
m.append(mi)
69
logging.debug(f"New rank: {rank}...")
70
mi += 1
71
72
logging.info(f"Found {M.nrows()}x{M.ncols()} basis matrix")
73
74
b = M.solve_left(Vt)
75
76
logging.info(f"Found linear combination of target vector")
77
78
Vt = Vt.change_ring(ZZ)
79
M = M.change_ring(ZZ)
80
b = b.change_ring(ZZ)
81
G = (Vt - b * M) / e
82
delta = 1
83
for pj, gj in zip(primes.keys(), G):
84
delta = delta * pow(int(pj), int(gj), N) % N
85
86
st = delta
87
for bi, mi in zip(b, m):
88
if bi > 0:
89
si = sign_oracle(mi)
90
st = st * pow(int(si), int(bi), N) % N
91
92
return st
93
94