from Crypto.Util.number import getPrime, long_to_bytes as ltb, bytes_to_long as btl DEBUG = True flag = b'AL3XEI_FAKE_FLAG'
p,q = [getPrime(512) for _ in"pq"] D = getPrime(250) phi = ( p - 1 ) * ( q - 1 ) n = p * q d = phi - D e = int(pow(d, -1, phi)) m = btl(flag) c = pow( m, e, n )
print(f"n = { n }") print(f"e = { e }") print(f"c = { c }")
from Crypto.Util.number import getPrime, long_to_bytes as ltb, bytes_to_long as btl from gmpy2 import invert, powmod
n = e = c =
for kD in continued_fraction(e / n).convergents(): k = kD.numer() D = kD.denom() try: if ( e * D + 1) % k == 0: phi = ( e * D + 1) // k d = phi - D if (e * d) % phi == 1: m = powmod(c, d, n) if ltb(m) == b'AL3XEI_FAKE_FLAG': print(ltb(m)) break
from Crypto.Util.number import getPrime, long_to_bytes as ltb, bytes_to_long as btl from gmpy2 import invert, powmod
DEBUG = True flag = b'flag{AL3XEI_FAKE_FLAG}'
p,q = [getPrime(1024) for _ in"pq"] D = getPrime(540) phi = ( p - 1 ) * ( q - 1 ) n = p * q d = phi - D e = invert( d , phi ) m = btl(flag) c = powmod( m, e, n )
print(f"n = { n }") print(f"e = { e }") print(f"c = { c }")
from Crypto.Util.number import long_to_bytes import itertools
defsmall_roots(f, bounds, m=1, d=None): ifnot d: d = f.degree()
R = f.base_ring() N = R.cardinality()
f /= f.coefficients().pop(0) f = f.change_ring(ZZ)
G = Sequence([], f.parent()) for i inrange(m + 1): base = N ^ (m - i) * f ^ i for shifts in itertools.product(range(d), repeat=f.nvariables()): g = base * prod(map(power, f.variables(), shifts)) G.append(g)
factors = [monomial(*bounds) for monomial in monomials] for i, factor inenumerate(factors): B.rescale_col(i, factor)
B = B.dense_matrix().LLL()
B = B.change_ring(QQ) for i, factor inenumerate(factors): B.rescale_col(i, 1 / factor)
H = Sequence([], f.parent().change_ring(QQ)) for h infilter(None, B * monomials): H.append(h) I = H.ideal() if I.dimension() == -1: H.pop() elif I.dimension() == 0: roots = [] for root in I.variety(ring=ZZ): root = tuple(R(root[var]) for var in f.variables()) roots.append(root) return roots
return []
n = e = c =
P = Zmod(ZZ(e))["k,s"] k, s = P.gens() f = 1 + k * (n - s) rs = small_roots(f, (2**540, 2**1025), m=4, d=5) print(rs) k, s = map(int, rs[0]) phi = n - s d = pow(e, -1, phi) m = pow(c, d, n) print(long_to_bytes(int(m))) # b'flag{AL3XEI_FAKE_FLAG}'
from Crypto.Util.number import long_to_bytes import itertools
defsmall_roots(f, bounds, m=1, d=None): ifnot d: d = f.degree()
R = f.base_ring() N = R.cardinality()
f /= f.coefficients().pop(0) f = f.change_ring(ZZ)
G = Sequence([], f.parent()) for i inrange(m + 1): base = N ^ (m - i) * f ^ i for shifts in itertools.product(range(d), repeat=f.nvariables()): g = base * prod(map(power, f.variables(), shifts)) G.append(g)
factors = [monomial(*bounds) for monomial in monomials] for i, factor inenumerate(factors): B.rescale_col(i, factor)
B = B.dense_matrix().LLL()
B = B.change_ring(QQ) for i, factor inenumerate(factors): B.rescale_col(i, 1 / factor)
H = Sequence([], f.parent().change_ring(QQ)) for h infilter(None, B * monomials): H.append(h) I = H.ideal() if I.dimension() == -1: H.pop() elif I.dimension() == 0: roots = [] for root in I.variety(ring=ZZ): root = tuple(R(root[var]) for var in f.variables()) roots.append(root) return roots
return []
n = e = c =
P = Zmod(ZZ(e))["k,s"] k, s = P.gens() f = 1 + k * (n - s) rs = small_roots(f, (2**490, 2**2050), m=4, d=5) print(rs) k, s = map(int, rs[0]) phi = n - s d = pow(e, -1, phi) m = pow(c, d, n) print(long_to_bytes(int(m)))
from Crypto.Util.number import long_to_bytes import itertools
defsmall_roots(f, bounds, m=1, d=None): ifnot d: d = f.degree()
R = f.base_ring() N = R.cardinality()
f /= f.coefficients().pop(0) f = f.change_ring(ZZ)
G = Sequence([], f.parent()) for i inrange(m + 1): base = N ^ (m - i) * f ^ i for shifts in itertools.product(range(d), repeat=f.nvariables()): g = base * prod(map(power, f.variables(), shifts)) G.append(g)
factors = [monomial(*bounds) for monomial in monomials] for i, factor inenumerate(factors): B.rescale_col(i, factor)
B = B.dense_matrix().LLL()
B = B.change_ring(QQ) for i, factor inenumerate(factors): B.rescale_col(i, 1 / factor)
H = Sequence([], f.parent().change_ring(QQ)) for h infilter(None, B * monomials): H.append(h) I = H.ideal() if I.dimension() == -1: H.pop() elif I.dimension() == 0: roots = [] for root in I.variety(ring=ZZ): root = tuple(R(root[var]) for var in f.variables()) roots.append(root) return roots
return [] a = c = p = high_v1 = high_v2 = PR = Zmod(ZZ(p))["l1, l2"] l1, l2 = PR.gens() f = a*(high_v1*(2^146)+l1)^2+c-(high_v2*(2^146)+l2) low_v1 = ZZ(small_roots(f, (2^146, 2^146), m=3, d=4)[0][0])
from Crypto.Util.number import long_to_bytes import itertools
defsmall_roots(f, bounds, m=1, d=None): ifnot d: d = f.degree()
R = f.base_ring() N = R.cardinality()
f /= f.coefficients().pop(0) f = f.change_ring(ZZ)
G = Sequence([], f.parent()) for i inrange(m + 1): base = N ^ (m - i) * f ^ i for shifts in itertools.product(range(d), repeat=f.nvariables()): g = base * prod(map(power, f.variables(), shifts)) G.append(g)
factors = [monomial(*bounds) for monomial in monomials] for i, factor inenumerate(factors): B.rescale_col(i, factor)
B = B.dense_matrix().LLL()
B = B.change_ring(QQ) for i, factor inenumerate(factors): B.rescale_col(i, 1 / factor)
H = Sequence([], f.parent().change_ring(QQ)) for h infilter(None, B * monomials): H.append(h) I = H.ideal() if I.dimension() == -1: H.pop() elif I.dimension() == 0: roots = [] for root in I.variety(ring=ZZ): root = tuple(R(root[var]) for var in f.variables()) roots.append(root) return roots
return []
UnKnownBits = 48 a = p = high_v0 = high_v1 = high_v2 =
from sage.allimport * import itertools from time import time from Crypto.Util.number import long_to_bytes
# display matrix picture with 0 and X # references: https://github.com/mimoo/RSA-and-LLL-attacks/blob/master/boneh_durfee.sage defmatrix_overview(BB): for ii inrange(BB.dimensions()[0]): a = ('%03d ' % ii) for jj inrange(BB.dimensions()[1]): a += '0'if BB[ii,jj] == 0else'X' if BB.dimensions()[0] < 60: a += ' ' print (a)
defsort_monomials(monomials): x, y, z = monomials[0].parent().gens() Mx = [] My = [] Mz = [] degx = max([monomial.degree(x) for monomial in monomials]) degy = max([monomial.degree(y) for monomial in monomials]) degz = max([monomial.degree(z) for monomial in monomials]) for i inrange(degx + 1): for j inrange(degy + 1): for k inrange(degz + 1): if k+j > i: break mono = x^i * y^j * z^k if mono in monomials: Mx += [mono] for j inrange(degy + 1): for k inrange(degz + 1): for i inrange(degx + 1): if k > j: break mono = x^i * y^j * z^k if mono in monomials and mono notin Mx: My += [mono] for k inrange(degz + 1): for j inrange(degy + 1): for i inrange(degx + 1): mono = x^i * y^j * z^k if mono in monomials and mono notin (Mx+My): Mz += [mono] return Mx + My + Mz
defjochemsz_may_trivariate(pol, XX, YY, ZZ, WW, tau, mm): ''' Implementation of Finding roots of trivariate polynomial [1]. Thanks @Bono_iPad References: [1] Ellen Jochemsz and Alexander May. "A Strategy for Finding Roots of Multivariate Polynomials with New Applications in Attacking RSA Variants" ''' tt = floor(mm * tau) cond = XX^(7 + 9*tau + 3*tau^2) * (YY*ZZ)^(5+9/2*tau) < WW^(3 + 3*tau) print ('[+] Bound check: X^{7+9tau+3tau^2} * (YZ)^{5+9/2tau} < W^{3+3tau}:', ) if cond: print( 'OK') else: print ('NG')
# Polynomial constant coefficient (a_0) must be 1 # XXX: can a_0 be zero? f_ = pol a0 = f_.constant_coefficient()
while gcd(a0, XX) != 1: XX += 1 while gcd(a0, YY) != 1: YY += 1 while gcd(a0, ZZ) != 1: ZZ += 1 while gcd(a0, WW) != 1: WW += 1
RR = WW * XX^(2*(mm-1)+tt) * (YY*ZZ)^(mm-1)
if a0 != 0: F = Zmod(RR) PK = PolynomialRing(F, 'xs, ys, zs') f_ = PR(PK(f_) * F(a0)^-1)
# Construct set `S` (cf.[1] p.8) S = set() for i2, i3 in itertools.product(range(0, mm), repeat=2): for i1 inrange(0, 2*(mm-1) - (i2 + i3) + tt + 1): S.add(x^i1 * y^i2 * z^i3) m_S = [] for k inrange(mm): for j inrange(mm): for i inrange(2*(mm-1) - (i2 + i3) + tt + 1): m_S += [x^i*y^j*z^k] S = m_S
# Construct set `M` (cf.[1] p.8) M = set() for i2, i3 in itertools.product(range(0, mm + 1), repeat=2): for i1 inrange(0, 2*mm - (i2 + i3) + tt + 1): M.add(x^i1 * y^i2 * z^i3) M_S = list(M - set(S))
m_M_S = [] deg_x = max([mono.degree(x) for mono in M_S]) deg_y = max([mono.degree(y) for mono in M_S]) deg_z = max([mono.degree(z) for mono in M_S]) for k inrange(deg_z + 1): for j inrange(deg_y + 1): for i inrange(deg_x + 1): mono = x^i*y^j*z^k if mono in M_S: m_M_S += [mono] M_S = m_M_S
# Construct polynomial `g`, `g'` for basis of lattice g = [] g_ = [] M_S = sort_monomials(M_S) S = sort_monomials(S) for monomial in S: i1 = monomial.degree(x) i2 = monomial.degree(y) i3 = monomial.degree(z) g += [monomial * f_ * XX^(2*(mm-1)+tt-i1) * YY^(mm-1-i2) * ZZ^(mm-1-i3)]
for monomial in M_S: g_ += [monomial * RR]
# Construct Lattice from `g`, `g'` monomials_G = [] monomials = [] G = g + g_ deg_x = deg_y = deg_z = 0 for g_poly in G: monomials_G += g_poly.monomials() deg_x = max(deg_x, g_poly.degree(x)) deg_y = max(deg_y, g_poly.degree(y)) deg_z = max(deg_z, g_poly.degree(z)) monomials_G = sorted(set(monomials_G))
for k inrange(deg_z + 1): for j inrange(deg_y + 1): for i inrange(deg_x + 1): mono = x^i*y^j*z^k if mono in monomials_G: monomials += [x^i*y^j*z^k] assertlen(monomials) == len(G) monomials = sort_monomials(monomials) dims = len(monomials) M = Matrix(IntegerRing(), dims) for i inrange(dims): M[i, 0] = G[i](0, 0, 0) for j inrange(dims): if monomials[j] in G[i].monomials(): M[i, j] = G[i].monomial_coefficient(monomials[j]) * monomials[j](XX, YY, ZZ) matrix_overview(M) print () print ('=' * 128) print ()
# Re-construct polynomial `H_i` from Reduced-lattice H = [(i, 0) for i inrange(dims)] H = dict(H) for i inrange(dims): for j inrange(dims): H[i] += PR((monomials[j] * B[i, j]) / monomials[j](XX, YY, ZZ))
from lbc_toolkit import hnp from Crypto.Util.number import *
N = _T = A = E = sol = hnp(N, _T, A, E, verbose=True) print(long_to_bytes(sol)) # [hnp] Lattice dimensions: (4, 4) # [hnp] Lattice reduction took 0.005s # b'AL3XEI_FAKE_FLAG'
对于
的情况也可以做拓展。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
from Crypto.Util.number import * from lbc_toolkit import hnp
m = b'AL3XEI_FAKE_FLAG' N, E, T = random_prime(2^360), 2^50, 2^50 print(T^6*E<N)
x = bytes_to_long(m) _T = [randrange(1, T) for _ inrange(5)] _E = [randrange(0, E) for _ inrange(5)] A = [(t * x + e) % N for t, e inzip(_T, _E)]
from lbc_toolkit import hnp from Crypto.Util.number import *
N = _T = A = E = sol = hnp(N, _T, A, E, verbose=True) print(long_to_bytes(sol)) # [hnp] Lattice dimensions: (7, 7) # [hnp] Lattice reduction took 0.013s # b'AL3XEI_FAKE_FLAG'
4.3 应用:对 MEGA 的攻击
MEGA 工作 (以及实施对 MEGA 攻击) 的环境中,服务器持有客户端 RSA
私钥的密文副本,加密方式是 AES-ECB mode,密钥由用户密码派生生成。