Path: blob/master/attacks/rsa/non_coprime_exponent.py
2589 views
import logging1import os2import sys3from math import gcd45from sage.all import GF6from sage.all import crt7from sage.all import is_prime89path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(os.path.abspath(__file__)))))10if sys.path[1] != path:11sys.path.insert(1, path)1213from attacks.factorization import known_phi14from shared import rth_roots151617def attack(N, e, phi, c):18"""19Computes possible plaintexts when e is not coprime with Euler's totient.20More information: Shumow D., "Incorrectly Generated RSA Keys: How To Recover Lost Plaintexts"21:param N: the modulus22:param e: the public exponent23:param phi: Euler's totient for the modulus24:param c: the ciphertext25:return: a generator generating possible plaintexts for c26"""27assert phi % e == 0, "Public exponent must divide Euler's totient"28if gcd(phi // e, e) == 1:29assert is_prime(e), "Public exponent must be prime"30phi //= e31# Finding multiplicative generator of subgroup with order e elements (Algorithm 1).32g = 133gE = 134while gE == 1:35g += 136gE = pow(g, phi, N)3738# Finding possible plaintexts (Algorithm 2).39d = pow(e, -1, phi)40a = pow(c, d, N)41l = gE42for i in range(e):43x = a * l % N44l = l * gE % N45yield x46else:47# Fall back to more generic root finding using Adleman-Manders-Miller and CRT.48p, q = known_phi.factorize(N, phi)49tp = 050while (p - 1) % (e ** (tp + 1)) == 0:51tp += 152tq = 053while (q - 1) % (e ** (tq + 1)) == 0:54tq += 15556assert tp > 0 or tq > 057cp = c % p58cq = c % q59logging.info(f"Computing {e}-th roots mod {p}...")60mps = [pow(cp, pow(e, -1, p - 1), p)] if tp == 0 else list(rth_roots(GF(p), cp, e))61logging.info(f"Computing {e}-th roots mod {q}...")62mqs = [pow(cq, pow(e, -1, q - 1), q)] if tq == 0 else list(rth_roots(GF(q), cq, e))63logging.info(f"Computing {len(mps) * len(mqs)} roots using CRT...")64for mp in mps:65for mq in mqs:66yield int(crt([mp, mq], [p, q]))676869