Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
jvdsn
GitHub Repository: jvdsn/crypto-attacks
Path: blob/master/attacks/rsa/non_coprime_exponent.py
2589 views
1
import logging
2
import os
3
import sys
4
from math import gcd
5
6
from sage.all import GF
7
from sage.all import crt
8
from sage.all import is_prime
9
10
path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(os.path.abspath(__file__)))))
11
if sys.path[1] != path:
12
sys.path.insert(1, path)
13
14
from attacks.factorization import known_phi
15
from shared import rth_roots
16
17
18
def attack(N, e, phi, c):
19
"""
20
Computes possible plaintexts when e is not coprime with Euler's totient.
21
More information: Shumow D., "Incorrectly Generated RSA Keys: How To Recover Lost Plaintexts"
22
:param N: the modulus
23
:param e: the public exponent
24
:param phi: Euler's totient for the modulus
25
:param c: the ciphertext
26
:return: a generator generating possible plaintexts for c
27
"""
28
assert phi % e == 0, "Public exponent must divide Euler's totient"
29
if gcd(phi // e, e) == 1:
30
assert is_prime(e), "Public exponent must be prime"
31
phi //= e
32
# Finding multiplicative generator of subgroup with order e elements (Algorithm 1).
33
g = 1
34
gE = 1
35
while gE == 1:
36
g += 1
37
gE = pow(g, phi, N)
38
39
# Finding possible plaintexts (Algorithm 2).
40
d = pow(e, -1, phi)
41
a = pow(c, d, N)
42
l = gE
43
for i in range(e):
44
x = a * l % N
45
l = l * gE % N
46
yield x
47
else:
48
# Fall back to more generic root finding using Adleman-Manders-Miller and CRT.
49
p, q = known_phi.factorize(N, phi)
50
tp = 0
51
while (p - 1) % (e ** (tp + 1)) == 0:
52
tp += 1
53
tq = 0
54
while (q - 1) % (e ** (tq + 1)) == 0:
55
tq += 1
56
57
assert tp > 0 or tq > 0
58
cp = c % p
59
cq = c % q
60
logging.info(f"Computing {e}-th roots mod {p}...")
61
mps = [pow(cp, pow(e, -1, p - 1), p)] if tp == 0 else list(rth_roots(GF(p), cp, e))
62
logging.info(f"Computing {e}-th roots mod {q}...")
63
mqs = [pow(cq, pow(e, -1, q - 1), q)] if tq == 0 else list(rth_roots(GF(q), cq, e))
64
logging.info(f"Computing {len(mps) * len(mqs)} roots using CRT...")
65
for mp in mps:
66
for mq in mqs:
67
yield int(crt([mp, mq], [p, q]))
68
69