节后一直很忙抽空写个wp。
lastRSA
csharp
from Crypto.Util.number import *
from secret import flag
def encrypt(P,k,leak0):
round=40
t=114514
x= leak0+2*t if k==1 else 2*t*leak0
enc=2024
while(round):
enc+=pow(x,round,P)
round-=1
return enc
m=bytes_to_long(flag)
p=getStrongPrime(512)
q=getStrongPrime(512)
assert len(bin(p)[2:])==512 and len(bin(q)[2:])==512
e=0x10001
leak0=p^(q>>13)
n=p*q
enc1=encrypt(n,1,leak0)
enc2=encrypt(n,0,leak0)
c=pow(m,e,n)
print(f"enc1={enc1}")
print(f"enc2={enc2}")
print(f"c={c}")
print(f"n={n}")
"""
enc1=2481998981478152169164378674194911111475668734496914731682204172873045273889232856266140236518231314247189371709204253066552650323964534117750428068488816244218804456399611481184330258906749484831445348350172666468738790766815099309565494384945826796034182837505953580660530809234341340618365003203562639721024
enc2=2892413486487317168909532087203213279451225676278514499452279887449096190436834627119161155437012153025493797437822039637248773941097619806471091066094500182219982742574131816371999183859939231601667171386686480639682179794271743863617494759526428080527698539121555583797116049103918578087014860597240690299394
c=87077759878060225287052106938097622158896106278756852778571684429767457761148474369973882278847307769690207029595557915248044823659812747567906459417733553420521047767697402135115530660537769991893832879721828034794560921646691417429690920199537846426396918932533649132260605985848584545112232670451169040592
n=136159501395608246592433283541763642196295827652290287729738751327141687762873360488671062583851846628664067117347340297084457474032286451582225574885517757497232577841944028986878525656103449482492190400477852995620473233002547925192690737520592206832895895025277841872025718478827192193010765543046480481871
"""
思路:
enc1,enc2都是关于leak0的多项式,我用的是多项式求根的方法求出来的leak0,但是我发现小鸡块师傅的更棒。
csharp
from Crypto.Util.number import *
e=0x10001
enc1=2481998981478152169164378674194911111475668734496914731682204172873045273889232856266140236518231314247189371709204253066552650323964534117750428068488816244218804456399611481184330258906749484831445348350172666468738790766815099309565494384945826796034182837505953580660530809234341340618365003203562639721024
enc2=2892413486487317168909532087203213279451225676278514499452279887449096190436834627119161155437012153025493797437822039637248773941097619806471091066094500182219982742574131816371999183859939231601667171386686480639682179794271743863617494759526428080527698539121555583797116049103918578087014860597240690299394
c=87077759878060225287052106938097622158896106278756852778571684429767457761148474369973882278847307769690207029595557915248044823659812747567906459417733553420521047767697402135115530660537769991893832879721828034794560921646691417429690920199537846426396918932533649132260605985848584545112232670451169040592
n=136159501395608246592433283541763642196295827652290287729738751327141687762873360488671062583851846628664067117347340297084457474032286451582225574885517757497232577841944028986878525656103449482492190400477852995620473233002547925192690737520592206832895895025277841872025718478827192193010765543046480481871
#part1 get leak0
PR.<x> = PolynomialRing(Zmod(n))
f1 = -enc1+2024
for i in range(1,41):
f1 += (x+2*114514)^i
f2 = -enc2+2024
for i in range(1,41):
f2 += (2*114514*x)^i
def gcd(g1, g2):
while g2:
g1, g2 = g2, g1 % g2
return g1.monic()
leak0 = int(-gcd(f1, f2)[0])
求出leak0后就是leak0的剪枝求解。
csharp
from Crypto.Util.number import *
#计算p高位以及补0
gift=13168452015078389807681744077701012683188749953280204324570483361963541298704796389757190180549802771265899020301416729606658667351017116721327316272373584
N=136159501395608246592433283541763642196295827652290287729738751327141687762873360488671062583851846628664067117347340297084457474032286451582225574885517757497232577841944028986878525656103449482492190400477852995620473233002547925192690737520592206832895895025277841872025718478827192193010765543046480481871
leakbit=13
ph = bin(gift)[2:][:leakbit] + '0'*(512-leakbit)
ph = int(ph,2)
#因为已知q的第一位为1 所有未知位从leakbit+1位开始计算
print(bin(gift)[2:])
x = bin(gift)[2:][(leakbit+1):]
def fac(x,tp,tq):
l=len(x)
if len(x) == 0:
return
if tp*tq>N:
return
if N%(tp+1)==0:
print("p=",tp+1)
return
#得到x的第一位 15 16 17
v = x[0]
#得到x的后几位 16 17 18...
r = x[1:]
#计算r去掉第一位后的长度 ,后续值位移的时候需要位移的长度
l = len(r)
if (tp+(1<<(l+1)))*(tq+(1<<(l+leakbit+1)))<N:
# print(bin(tp)[:50])
# print(bin(tq)[:50])
# print(l)
return
#判断第15 16,...
if v == '0':
#此时p,q的第15位同为0 1
#同为0
fac(r, tp, tq)
#同为1 需要加上1位移l位
fac(r, tp+(1<<l), tq+(1<<(l+leakbit)))
else:
fac(r, tp+(1<<l), tq)
fac(r, tp, tq+(1<<(l+leakbit)))
tq = 1<<511
if x[0]=='1':
#因为已知leak0的下一位中p的bit为1
tp = ph
else:
#该位补1
tp = ph+ (1<<(512-leakbit-1))
fac(x,tp,tq)
求出来p之后getflag
csharp
import gmpy2
from Crypto.Util.number import *
p = 13167244882304693277785720567493996610066918256369682594482416913362069704726831109204371100970154866396462315730687841430922916219416627940866383413192931
q = 10340773837858169661474323029012384377394391882332560606952494899463284596209932089793576041492039641919331765221984085549386070977506894068717765568920741
e = 65537
phi = (p - 1) * (q - 1)
d = gmpy2.invert(e, phi)
m = pow(c, d, n)
print(long_to_bytes(m))
transformation
csharp
#!/usr/bin/env python
# coding: utf-8
from Crypto.Util.number import *
from secret import Curve,gx,gy
# flag = "hgame{" + hex(gx+gy)[2:] + "}"
def ison(C, P):
c, d, p = C
u, v = P
return (u**2 + v**2 - c**2 * (1 + d * u**2*v**2)) % p == 0
def add(C, P, Q):
c, d, p = C
u1, v1 = P
u2, v2 = Q
assert ison(C, P) and ison(C, Q)
u3 = (u1 * v2 + v1 * u2) * inverse(c * (1 + d * u1 * u2 * v1 * v2), p) % p
v3 = (v1 * v2 - u1 * u2) * inverse(c * (1 - d * u1 * u2 * v1 * v2), p) % p
return (int(u3), int(v3))
def mul(C, P, m):
assert ison(C, P)
c, d, p = C
B = bin(m)[2:]
l = len(B)
u, v = P
PP = (-u, v)
O = add(C, P, PP)
Q = O
if m == 0:
return O
elif m == 1:
return P
else:
for _ in range(l-1):
P = add(C, P, P)
m = m - 2**(l-1)
Q, P = P, (u, v)
return add(C, Q, mul(C, P, m))
c, d, p = Curve
G = (gx, gy)
P = (423323064726997230640834352892499067628999846, 44150133418579337991209313731867512059107422186218072084511769232282794765835)
Q = (1033433758780986378718784935633168786654735170, 2890573833121495534597689071280547153773878148499187840022524010636852499684)
S = (875772166783241503962848015336037891993605823, 51964088188556618695192753554835667051669568193048726314346516461990381874317)
T = (612403241107575741587390996773145537915088133, 64560350111660175566171189050923672010957086249856725096266944042789987443125)
assert ison(Curve, P) and ison(Curve, Q) and ison(Curve, G)
e = 0x10001
print(f"eG = {mul(Curve, G, e)}")
# eG = (40198712137747628410430624618331426343875490261805137714686326678112749070113, 65008030741966083441937593781739493959677657609550411222052299176801418887407)
思路:
最近看到这个题目有点多,这是一道典型的板子题目。
题目给出了一道曲线
和我在sictf Round3中做的题目进阶]2024_New_Setback差不多,不过
这题的flag在G的x,y坐标上,所以解题的思路如下:
1.通过给出的四个节点求出p,c,d的值,还原出爱德华曲线。
2.将爱德华曲线分别转换成蒙哥马利曲线再到椭圆曲线。
3.然后求该曲线的阶,从而求解出远原点G,并且重新逆变换回Edcurve,得到的横坐标和纵坐标即为flag。
step1:如何通过给出的四个节点求解出爱德华曲线的参数。
我们的目标是恢复(c,d,p)。
首先,我们有曲线
如果我们知道曲线上的多个点,就可以通过下列公式隔离参数c,d
目标是使用两个点来写出p的倍数,并执行此操作两次。然后我们可以从一对点的gcd恢复p
此时,令
有
同样对另一点也如此然后作差会得到p的倍数:
去分母得到:
最后,我们可以采取另一种组合以及使用最大公约数得到p:
这里需要注意,我们得到的不是精确的p,而是p的倍数,但是我们可以通过分解来得到精确的p。
有了p我们再回到上面的表达式从而计算c2d:
至此我们得到了扭曲爱德华曲线上的所有参数。
此时我们需要通过e,eG以及已知的扭曲爱德华曲线求出G。
这里参考了之前小鸡块师傅的做法
EdRSA
不过需要将扭曲爱德华曲线变换成标准爱德华曲线 参考lazzzaro佬
Edwards Curves
csharp
p = 67943764351073247630101943221474884302015437788242536572067548198498727238923
cc = 12908728488299650872377430201970332178171657588185291326485782119189255844928
d = 8779982120820562807260290996171144226614358666469579196351820160975526615300
F = GF(p)
c = F(cc).sqrt()
print(c)
csharp
p = 67943764351073247630101943221474884302015437788242536572067548198498727238923
cc = 12908728488299650872377430201970332178171657588185291326485782119189255844928
d = 8779982120820562807260290996171144226614358666469579196351820160975526615300
c=7143899698109428282870539364581968579753042129945786627292343174759297201080
e = 0x10001
import gmpy2
def add(P, Q):
(x1, y1) = P
(x2, y2) = Q
x3 = (x1*y2 + y1*x2) * gmpy2.invert(1 + d*x1*x2*y1*y2, p) % p
y3 = (y1*y2 - a*x1*x2) * gmpy2.invert(1 - d*x1*x2*y1*y2, p) % p
return (x3, y3)
def mul(x, P):
Q = (0, 1)
while x > 0:
if x % 2 == 1:
Q = add(Q, P)
P = add(P, P)
x = x >> 1
return Q
PR.<z> = PolynomialRing(Zmod(p))
aa = 1
dd = (d*c^4)%p
J = (2*(aa+dd)*gmpy2.invert(aa-dd,p))%p
K = (4*gmpy2.invert(aa-dd,p))%p
A = ((3-J^2)*gmpy2.invert(3*K^2,p))%p
B = ((2*J^3-9*J)*gmpy2.invert(27*K^3,p))%p
for i in PR(z^3+A*z+B).roots():
alpha = int(i[0])
for j in PR(z^2-(3*alpha^2+A)).roots():
s = int(j[0])
s = gmpy2.invert(s, p)
if J==alpha*3*s%p:
Alpha = alpha
S = s
def twist_to_weier(x,y):
#x,y转换成标准爱德华曲线值
v = x*gmpy2.invert(c,p)%p
w = y*gmpy2.invert(c,p)%p
assert (aa*v^2+w^2)%p==(1+dd*v^2*w^2)%p
#转换成蒙哥马利曲线方程上的值
s = (1+w)*gmpy2.invert(1-w,p)%p
t = s*gmpy2.invert(v,p)%p
assert (K*t^2)%p==(s^3+J*s^2+s)%p
#转换成椭圆曲线上的方程的值
xW = (3*s+J) * gmpy2.invert(3*K, p) % p
yW = t * gmpy2.invert(K, p) % p
assert yW^2 % p == (xW^3+A*xW+B) % p
return (xW,yW)
a=1
def weier_to_twist(x,y):
#椭圆曲线转回
xM=S*(x-Alpha)%p
yM=S*y%p
assert (K*yM^2)%p==(xM^3+J*xM^2+xM)%p
xe = xM*gmpy2.invert(yM,p)%p
ye = (xM-1)*gmpy2.invert(xM+1,p)%p
assert (aa*xe^2+ye^2)%p==(1+dd*xe^2*ye^2)%p
xq = xe*c%p
yq = ye*c%p
assert (a*xq^2+yq^2)%p==c^2*(1+d*xq^2*yq^2)%p
return (xq,yq)
E = EllipticCurve(GF(p), [A, B])
order = E.order()
print(order)
eG = (40198712137747628410430624618331426343875490261805137714686326678112749070113, 65008030741966083441937593781739493959677657609550411222052299176801418887407)
eG = twist_to_weier(40198712137747628410430624618331426343875490261805137714686326678112749070113, 65008030741966083441937593781739493959677657609550411222052299176801418887407)
print(eG)
eG = E(eG)
print(gmpy2.gcd(e,order))
t = gmpy2.invert(e,order)
G = t*eG
print(G)
G = weier_to_twist(35733349967727579207362409511868045188603684677107507326049720528422212540295,6262749945313057631927156406870959025196549376410411046740120315141730009195)
print(G)
gx,gy=G
flag = "hgame{" + hex(gx+gy)[2:] + "}"
print(flag)