DASCTF-CBCTF 2023
0rays的师傅出的题,学习了。
EzRSA
看到雅可比符号基本上就猜测是老套路了,然后还有个rsa的相关攻击。
from Crypto.Util.number import *
from gmpy2 import *
n1 = 65634094430927080732256164808833233563732628654160389042977689628512527168256899310662239009610512772020503283842588142453533499954947692968978190310627721338357432052800695091789711809256924541784954080619073213358228083200846540676931341013554634493581962527475555869292091755676130810562421465063412235309
n2 = 103670293685965841863872863719573676572683187403862749665555450164387906552249974071743238931253290278574192713467491802940810851806104430306195931179902098180199167945649526235613636163362672777298968943319216325949503045377100235181706964846408396946496139224344270391027205106691880999410424150216806861393
(e1, noise1, c1) = (1743, 44560588075773853612820227436439937514195680734214431948441190347878274184937952381785302837541202705212687700521129385632776241537669208088777729355349833215443048466316517110778502508209433792603420158786772339233397583637570006255153020675167597396958251208681121668808253767520416175569161674463861719776, 65643009354198075182587766550521107063140340983433852821580802983736094225036497335607400197479623208915379722646955329855681601551282788854644359967909570360251550766970054185510197999091645907461580987639650262519866292285164258262387411847857812391136042309550813795587776534035784065962779853621152905983)
(e2, noise2, c2) = (1325, 35282006599813744140721262875292395887558561517759721467291789696459426702600397172655624765281531167221787036009507833425145071265739486735993631460189629709591456017092661028839951392247601628468621576100035700437892164435424035004463142959219067199451575338270613300215815894328788753564798153516122567683, 50327632090778183759544755226710110702046850880299488259739672542025916422119065179822210884622225945376465802069464782311211031263046593145733701591371950349735709553105217501410716570601397725812709771348772095131473415552527749452347866778401205442409443726952960806789526845194216490544108773715759733714)
c = 124349762993424531697403299350944207725577290992189948388824124986066269514204313888980321088629462472088631052329128042837153718129149149661961926557818023704330462282009415874674794190206220980118413541269327644472633791532767765585035518183177197863522573410860341245613331398610013697803459403446614221369
def attack():
PR.<x>=PolynomialRing(Zmod(n2))
g1 = (x+noise1) ^ e1 - c1
g2 = (x+noise2) ^ e2 - c2
def gcd(g1, g2):
while g2:
g1, g2 = g2, g1 % g2
return g1.monic()
return -gcd(g1, g2)[0]
q = attack()
print(q)
enc = []
enc = [int(i) for i in enc]
p = ''
for i in enc:
if kronecker(i,n1) == 1:
p = '1' + p
else:
p = '0' + p
p = int(p,2)
print(p)
q = 13189337905641321257372188436353844418280745284875462357019668708167547026960641869513283218672677712590326347601424108528959315675307896082223561007980457
p = 9473204278465588641589315677772678997836862033858760337441231265335880892205102590571357305720744128962068300763212493598006400853597404586755248901932203
phi = (p-1)*(q-1)
d = inverse(65537,phi)
print(long_to_bytes(ZZ(pow(c,d,p*q))))
CB backpack
出题人的本意是考察New Time-Memory Trade-Offs for Subset Sum –
Improving ISD in Theory and Practice这个paper的内容,但因为数据给的不够大可以用爆破加背包格来做。
具体来说,总的未知比特是48,参考jvdsn可计算密度大致是1.几,尝试爆16位,再测一下密度,发现只有0.6几,妥妥够了:
from math import *
n = 32
a = [65651991706497, 247831871690373, 120247087605020, 236854536567393, 38795708921144, 256334857906663, 120089773523233, 165349388120302, 123968326805899, 79638234559694, 259559389823590, 256776519514651, 107733244474073, 216508566448440, 39327578905012, 118682486932022, 263357223061004, 132872609024098, 44605761726563, 24908360451602, 237906955893793, 204469770496199, 7055254513808, 221802659519968, 169686619990988, 23128789035141, 208847144870760, 272339624469135, 269511404473473, 112830627321371, 73203551744776, 42843503010671, 118193938825623, 49625220390324, 230439888723036, 241486656550572, 107149406378865, 233503862264755, 269502011971514, 181805192674559, 152612003195556, 184127512098087, 165959151027513, 188723045133473, 241615906682300, 216101484550038, 81190147709444, 124498742419309]
a = a[16:]
d = n / log2(max(a))
N = ceil(1 / 2 * sqrt(n))
assert d < 0.9408, f"Density should be less than 0.9408 but was {d}."
print(d)
然后就是经典背包格,在ln3师傅的主机上跑三四分钟就出了:
from tqdm import tqdm
a=[65651991706497, 247831871690373, 120247087605020, 236854536567393, 38795708921144, 256334857906663, 120089773523233, 165349388120302, 123968326805899, 79638234559694, 259559389823590, 256776519514651, 107733244474073, 216508566448440, 39327578905012, 118682486932022, 263357223061004, 132872609024098, 44605761726563, 24908360451602, 237906955893793, 204469770496199, 7055254513808, 221802659519968, 169686619990988, 23128789035141, 208847144870760, 272339624469135, 269511404473473, 112830627321371, 73203551744776, 42843503010671, 118193938825623, 49625220390324, 230439888723036, 241486656550572, 107149406378865, 233503862264755, 269502011971514, 181805192674559, 152612003195556, 184127512098087, 165959151027513, 188723045133473, 241615906682300, 216101484550038, 81190147709444, 124498742419309]
re=4051501228761632
A = a[16:]
bits=32
def ju(j):
for i in j:
if abs(i)!=1:
return 0
return 1
for i in tqdm(range(2^16)):
temp=[int(j) for j in bin(i)[2:].zfill(16)]
t1,t2=temp[:6],temp[6:12]
if sum(t1)!=3 or sum(t2)!=3:
continue
rr = sum([i*j for i,j in zip(temp,a[:16])])
new_re = re - rr
M=Matrix(ZZ,bits+1)
for i in range(bits):
M[i,i]=2
M[i,-1]=A[i]
for i in range(bits):
M[-1,i]=1
M[-1,-1]=new_re
res=M.LLL()
# j = [abs(j) for j in res[0][:-1]]
if ju(res[0][:-1]):
print('find')
print(temp)
print(res[0])
break
CB curve
给了曲线的点加和数乘运算,但主要用到的是加法,用公式直观表示:
由于出现了\(\small x_1+x_2\)在分子上,因此\(\small (x,y)+(-x,-y)=(0,0)\),进一步测试\(\small kG+(-kG)=(0,0)\):
G = (586066762126624229327260483658353973556531595840920560414263113786807168248797, 66727759687879628160487324122999265926655929132333860726404158613654375336028)
G_ = (-586066762126624229327260483658353973556531595840920560414263113786807168248797, -66727759687879628160487324122999265926655929132333860726404158613654375336028)
Q = (460843895959181097343292934009653542386784127282375019764638432240505304648101, 739422832583403823403837831802136107593509589942947902014204968923412689379907)
# test
test = (ecc.add(G,G_))
print(test)
q1 = ecc.mul(5,G)
q2 = ecc.mul(5,G_)
print(ecc.add(q1,q2))
再结合def negG(self,G): return self.mul(570870969979422295249173442435007561272085504844186092739816337605942962972880-1,G)
可以知道order是570870969979422295249173442435007561272085504844186092739816337605942962972880
接下来要做的是把P点求出来然后想办法求dlp,这里利用点加法比较特殊的性质结合gb基会比较简单:
不难发现如果计算\(\small (ph-e)(pl-e)\)就可以利用平方差简化式子得到\(\small \frac{xp^2-x^2}{1-b^2xp^2x^2}\),而题目是给了这样的十对数据,利用groebner_basis()就很容易简化计算了。
后边再做一个映射利用order较光滑选几个小因子求dlp即可。
给出我的垃圾代码:
from Crypto.Util.number import *
from random import randint
from sage.all import *
class CB_curve:
def __init__(self):
self.p = 1141741939958844590498346884870015122543626602665954681008204697160652371664923
self.a = 727131475903635498678013730344448225340496007388151739960305539398192321065043
self.b = 840714623434321649308065401328602364673881568379142278640950034404861312007307
def add(self, P, Q):
if P == -1:
return Q
(x1, y1) = P
(x2, y2) = Q
x3 = (x1+x2)*(1+self.a*y1*y2)*inverse((1+self.b*x1*x2)*(1-self.a*y1*y2),self.p)% self.p
y3 = (y1+y2)*(1+self.b*x1*x2)*inverse((1-self.b*x1*x2)*(1+self.a*y1*y2),self.p)% self.p
return (x3, y3)
def mul(self, x, P):
Q = -1
x = x % self.p
while x > 0:
if x & 1:
Q = self.add(Q, P)
P = self.add(P, P)
x = x >> 1
return Q
def negG(self,G):
return self.mul(570870969979422295249173442435007561272085504844186092739816337605942962972880-1,G)
ecc = CB_curve()
G = (586066762126624229327260483658353973556531595840920560414263113786807168248797, 66727759687879628160487324122999265926655929132333860726404158613654375336028)
G_ = (-586066762126624229327260483658353973556531595840920560414263113786807168248797, -66727759687879628160487324122999265926655929132333860726404158613654375336028)
Q = (460843895959181097343292934009653542386784127282375019764638432240505304648101, 739422832583403823403837831802136107593509589942947902014204968923412689379907)
# test
test = (ecc.add(G,G_))
print(test)
q1 = ecc.mul(5,G)
q2 = ecc.mul(5,G_)
print(ecc.add(q1,q2))
# attack
order = 570870969979422295249173442435007561272085504844186092739816337605942962972880
pl = [908996880816674413953945844149350915331956247471480600840221415119794882139724, 971918808384910355828135603762747020183688585728289421786279444571287619529246, 1285550352531583269956802123237391199017403081800977678246201935580429758051904, 1551774945769448705387900437472951015954157193946719575845523359198154668857591, 676185408751480221545400062950292727848016906516506232986883519673765317932582, 1250300209784131850574858927023046353058343552115735540789593580037130054384362, 1298409778422699298367007023890818793557023853717180295526932023194697263501748, 1332552452292482549702793642987623159617988974910321945878093492007278710993114, 1030239404875082841481045525469865919289388171602293245905162820968158543176773, 1154148024180033719999293176590867264297899817449945744942661351655533433871621]
ph = [584297112520340495757457954416165393828472756298945167299482077258411155766756, 886432149227960827335266910774569034430464592640209168563805700117347063152246, 613528590036968449893421430816319461615130635882647544978722093413694101540550, 576162106332135829961234799085370038425761945928004579456101802617485243023987, 627570890346195626159365118862437334953500165050236216404858019114288681512171, 1015503424232985454098149884321288932492551183126601131968495641510550575005042, 1532737675157046782602115678180407262847166210963507805526455422934164759886583, 1540047002602145805476906585925538790245968214992837106009502002588479779602195, 505097517314409449404205152068185149808364887623922221197462411159844816865696, 873498218680784138428154510303205366133389839886911286745954821800632158315951]
a = ecc.a
b = ecc.b
p = ecc.p
R.<xp,e>=PolynomialRing(Zmod(p))
F = []
for i in range(10):
f = (pl[i] - e) * (ph[i] - e) * (1-b^2*xp^2 * ecc.mul(10-i,Q)[0] ^2) - (xp^2 - ecc.mul(10-i,Q)[0] ^2)
F.append(f)
res=Ideal(F).groebner_basis()
print(res)
c = -219493165434454878473973957507132663767650700404392831423708684433961924200902
xp = Zmod(p)(c).nth_root(2,all=True)[1]
RR.<yp> = PolynomialRing(Zmod(p))
f = xp*(a*yp^2-1) - yp*(b*xp^2-1)
yp = f.roots()[1][0]
P = (int(xp),int(yp))
E = EllipticCurve(GF(p),[0,a+b,0,a*b,0])
print(E)
g = ((b*G[0] - a*G[1]) * inverse_mod(G[1]-G[0],p)%p,(b-a)*inverse_mod(G[1]-G[0],p)%p)
q = ((b*P[0] - a*P[1]) * inverse_mod(P[1]-P[0],p)%p,(b-a)*inverse_mod(P[1]-P[0],p)%p)
g = E(g)
q = E(q)
# 做映射之后的阶是不会变的
primes = [3 , 5 , 16, 37 , 271 , 4297 , 6983 , 9679 , 52631 , 139571 , 84666937 , 558977989]
logs=[]
for fac in primes:
t=int(order)//int(fac)
print('ok')
log=discrete_log(t*q,t*g,operation='+')
logs+=[log]
m = crt(logs,primes)
from Crypto.Util.number import *
print(long_to_bytes(m))
# DASCTF{goodathuff}