感觉越来越难了这比赛,只作了一个一看就简单的小题,其它看都看不懂。
from Crypto.Util.number import bytes_to_long, getStrongPrime
from secret import flag
assert len(flag) == 255
e = 3
p = getStrongPrime(1024, e=e)
q = getStrongPrime(1024, e=e)
n = p * q
phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
enc_d = pow(d, e, n)
enc_phi = pow(phi, e, n) #(pq-p-q+1) (p+q+1)**3
enc_flag = pow(bytes_to_long(flag), e, n)
print(f"{n = }")
print(f"{enc_d = }")
print(f"{enc_phi = }")
print(f"{enc_flag = }")
e=3非常小,给了pow(d,e,n),pow(phi,e,n),pow(flag,e,n)
由于所以
enc_d*e^e = (k* +1 )^e%n
k^e * enc_phi = (k*)^e%n
所以明显这是关联信息攻击,可以原来的程序,计算出来都是-1(n-1)
def related_message_attack(c1,c2, di, e,n):
from Crypto.Util.number import GCD
#展开(x+a)^e的系数,杨辉三角
def poly_coef(a, e):
assert e >= 0
if e == 0:
return 1
elif e == 1:
return [1,1]
else:
res = [1]
coe_prev = poly_coef(a, e-1)
for i in range(len(coe_prev)-1):
res.append(sum(coe_prev[i:i+2]))
res.append(1)
return res
def poly_extend(a, e, n,c):
coef = poly_coef(a, e)
res = [a**i * coef[i] for i in range(len(coef))]
res[-1] = res[-1] + c
res = [x%n for x in res]
return res
#化首1
def poly_monic(pl,n):
from gmpy2 import invert
for p in pl:
if p!=0:
inv = invert(p,n)
break
return [int((x*inv)%n) for x in pl]
#模运算,这部分写的不是很好,待优化
def poly_mod(pl1,pl2,n):
from functools import reduce
assert len(pl1) == len(pl2)
pl1 = poly_monic(pl1,n)
pl2 = poly_monic(pl2,n)
for i in range(len(pl1)):
if pl1[i] > pl2[i]:
break
elif pl1[i] < pl2[i]:
return poly_mod(pl2,pl1,n)
else:
return 0
idx = -1
for i in range(len(pl1)):
if pl1[i] == 1:
idx = i
break
for i in range(idx,len(pl2)):
if pl2[i] == 1:
pl2 = pl2[:idx] + pl2[i:]
pl2 += [0]*(len(pl1)-len(pl2))
break
res = []
for i in range(len(pl1)):
if pl2[i] == 0:
res.append(pl1[i])
else:
res.append(pl1[i]-pl2[i])
res = [int(x%n) for x in res]
g = int(reduce(GCD,res))
if g > 1:
res = [x//g for x in res]
return res
#最大公因式
def poly_gcd(pl1,pl2,n):
while pl2 != 0:
pl1,pl2 = pl2, poly_mod(pl1,pl2,n)
pl1 = poly_monic(pl1,n)
return pl1
#x^e-c1
#(x+di)^e-c2
pl1 = poly_extend(0,e,n,-c1)
pl2 = poly_extend(di,e,n,-c2)
pl_d = poly_gcd(pl1,pl2,n)
#求得(x-m),所以取负数即为m
m = n - pl_d[-1]
return m
可能是什么不清楚,后来又从网上搜到一个简单点的。
from gmpy2 import invert
#这个函数原来是解出phi,但经过测试解出的是-(p+q-1)*2 phi=(p-1)(q-1)=n-(p+q)+1 所以解是p+q-1
def getM2(a,b,c1,c2,n,e):
a3 = pow(a,e,n)
b3 = pow(b,e,n)
first = c1-a3*c2+2*b3
first = first % n
second = e*b*(a3*c2-b3)
second = second % n
third = second * invert(first,n)
third = third % n
fourth = (third+b) * invert(a,n)
return fourth % n
这里还有个问题,phi虽然比n小,但k=2时也是比n大的,所以得到的是模n后的,phi=(p-1)(q-1)可以简单看成k(pq-p-q-1) = 2(1-p-q)这样就直接求出p+q然后就很容易得到p,q。
from output import *
e = 3
for k in range(1,3):
print(k)
c1 = enc_d * e**e %n #ed = k*phi + 1 => c1 = enc_d * e^e = (e*d)^e = (k*phi + 1)^e
c2 = enc_phi * k**e %n # c2 = enc_phi * k^e = (k*phi)^e
diff = 1
vv = getM2(1,diff,c1,c2,n,e)
#print(vv)
print('p+q:',(n-vv+2)//2)
'''
1
p+q: 8820468529041372002324038698966107072889102452877058887634498287453998997040072501409717546020769209164013911226723405860610209969068954054326071267363333989522789410364093976052951960389244009241995951348719565502276229384027370949790352653647809018302591167162614297744664920674123301610093287714014050868144462711682841900909838516794872905539836775052216863500628808277736583508580182374764197142389283888665469794215298689234712901544771897071199702872440965930331079753495886332933281500351422898210408413640120586805111875614402614790809233447071017020608120170440189652479953915574544657443320286438960533983
2
p+q: 312923382871248014067014925984412146067094621402549185870032327453115760507056850415403142556065116353933188609216161363804133557007400032321485662200928476199152365342526984153017631756765310979024793123971318866032039849942965865364222773233591801819504804711487822035015274359026776976437482432378059626872
'''
现用z3解出来p,q回到rsa的开头。也可以直接用p+q求phi再求d,反正都简单了
q = 154492600502310358961290595218855606637686112564658215263043082517847747558415354021955483686653624865913299541093297750308537763576451319637002115896403014960496288119726132921253645065026096509274270374571068515713750554820699528648387417681352310503451804260205255524204258933646537556120166683375680596359
p = 158430782368937655105724330765556539429408508837890970606989244935268012948641496393447658869411491488019889068122863613495595793430948712684483546304525461238656077222800851231763986691739214469750522749400250350318289295122266336715835355552239491316053000451282566510811015425380239420317315749002379030513
phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
m = pow(enc_flag,e,n)
print(bytes.fromhex(hex(m)[2:]))
#b"HackTM{Have you warmed up? If not, I suggest you consider the case where e=65537, although I don't know if it's solvable. Why did I say that? Because I have to make this flag much longer to avoid solving it just by calculating the cubic root of enc_flag.}"