SHCTF2024-week2-Crypto
Week2
Crypto
worde很大
import gmpy2
from Crypto.Util.number import *
from enc import flag
m = bytes_to_long(flag)
p = getPrime(512)
q = getPrime(512)
n = p*q
e = getPrime(200)
d = gmpy2.invert(e,(p-1)*(q-1))
dp = d % (p-1)
c = pow(m,e,n)
print(f"n = {n}")
print(f"c = {c}")
print(f"e = {e}")
print(f"dp = {dp}")
dp泄露,但是e很大,利用费马小定理就可以求出p
from Crypto.Util.number import *
from gmpy2 import *
n = 137936518212795016631995520838472302149141790253254063746644690789087238703518209864090400488867329204081462188070717686809252787882402936392955629363437184771842206953074183149138159637950191923912242531961311599662318655990865727657664205013000939289803471731705713740024391474024499546638888872254845182913
c = 121609905093326965529278560764503008737291822872196092526081697008572697757921850313770648096987000708617211869169540739201090558646483774562605091601996034685597344346173308271051378164676552111608917552372843867408949249508989974751671092015244566198448302722139817527780990490118285683385534014911565099055
e = 1475558511269133981422224090204112278405693168473364430129339
dp = 8218282983473677655187341896314032453994259573173123901161646379674688283023199060920450160589079068624519308615175274441217089076660114575658298351670291
p=gcd(pow(2,dp*e,n)-2,n)
print(long_to_bytes(pow(c,dp,p)))
#b'SHCTF{w0Rd_E_yoU_dlAN_DA_512AdE}'
魔鬼的步伐
from Crypto.Util.number import *
from random import choice
from enc import flag
m = bytes_to_long(flag)
def get_primes(limit):
primes = []
is_prime = [True] * (limit + 1)
for num in range(2, limit + 1):
if is_prime[num]:
primes.append(num)
for multiple in range(num * num, limit + 1, num):
is_prime[multiple] = False
return primes
def get_Prime(bits):
while True:
n = 2
while n.bit_length() < bits:
n *= choice(primes)
if isPrime(n + 1):
return n + 1
e = 65537
primes = get_primes(e)
p = get_Prime(512)
q = get_Prime(512)
n = p*q
c = pow(m,e,n)
print(f"n = {n}")
print(f"e = {e}")
print(f"c = {c}")
get_primes()生成的是2到65537之间的素数,可以调用这个函数得到素数列表。
之后是p-1光滑,套个模板就能出。
具体思想跟上一题很像,主要就是费马小定理的扩展,欧拉定理
具体:
补充:在计算a的指数时,可以利用模n计算,方便计算,证明如下
\(a^x=1\mod n=1+tpq=1+p=1+k_1p,k_1=tp\)
from Crypto.Util.number import *
from gmpy2 import *
n = 5110762360558841991200479861489285925524844631514508212466019395958785445022185836485590756596293862508459375211702740100625097146848518119269962030650395678777168527665231570301027424646066036855170246766085695197931470813222582532845205613779493177474912032708374450766979494491424493131759491942131030498257869
e = 65537
c = 3746692163606775986360277721955428653734462000451018476851908568984798654670765770329944346664679639250612313758119651138943404505224652681391417810641828118284271179416659949753583777829851912344964918202005601845806729432840819639932359587333302076619119507737168646424442796029179363464347377060864938789305152
def get_primes(limit):
primes = []
is_prime = [True] * (limit + 1)
for num in range(2, limit + 1):
if is_prime[num]:
primes.append(num)
for multiple in range(num * num, limit + 1, num):
is_prime[multiple] = False
return primes
primes = get_primes(e)
def pollard(N):
a = 2
for p in primes: #注意primes是什么,如果一次无法求解,则改成for p in primes+primes
a = pow(a, p, N)
p = gcd(a-1, N)
if p != 1 and p != N:
return p
p=pollard(n)
q=n//p
print(long_to_bytes(pow(c,inverse(0x10001,(p-1)*(q-1)),n)))
#b'SHCTF{fRIC7I0n_15_7hE_d3vils_sT3P_c4}'
pading
from Crypto.Util.number import *
import gmpy2
flag = b'SHCTF{********}'
assert len(flag) == 39
p = getPrime(512)
q = getPrime(512)
n = p * q
e = 0x3
pad = b'a_easy_problem'
c = pow(bytes_to_long(flag + pad),e,n)
print(f'n = {n}')
print(f'c = {c}')
方法一
知道前后缀,利用coppersmith求解
但是未知的位数有点多,实测中间未知31字节应该就可以出,所以这里多爆破一位
(原理我也不懂,这里就不说了)
from Crypto.Util.number import *
n = 77181376028870767428506413273794792813827015423912051082788843012528976994995131246668984940391210475066597668329315822594645257086873735167077745300534961199777709548474369179406260920824820997996539563126878553761334790678733817244005887911626210406449309019240173369781910452082054174678810877799182859993
c = 74528016275557253012735040006933867353003516025896832221477819880425483528903078818518341999308485483023581596498066751077631605539209065848529211627206825051132116372877873018154355697802663441819723056933012730127555814325771869129620407718638077085507303921975621542388852572081358396973201178454310073668
e=3
pre=b'SHCTF{'
for i in range(33,127):
tmp1=pre+int.to_bytes(i,1,'big')
suf=b'}a_easy_problem'
flag_length=39
pre_bits=(flag_length+len(suf)-1-len(tmp1))*8
suf_bits=len(suf)*8
unknown_bits=(flag_length-len(tmp1)-1)*8
PR.<x> = PolynomialRing(Zmod(n))
f=(bytes_to_long(tmp1)*2^pre_bits+x*2^suf_bits+bytes_to_long(suf))^e-c
f=f.monic()
m=f.small_roots(X=2^unknown_bits,beta=0.4)
if m:
x=m[0]
flag=tmp1+long_to_bytes(int(x))+suf
print(flag)
#b'SHCTF{ARE_yOu_PAdddlN9_ME_boY_do44d667}a_easy_problem'
方法二
后面又了解了一个不懂原理的写法(跟shin师傅讨论了一下,受益良多):
使用small_roots时,多设一个参数epsilon,让里面构造的格大一点,就可以不用爆破直接出结果了
具体可以看源码,这里贴一小部分,最后造格的时候跟m,g和t等一下参数有关,到最后会发现跟epsilon有关,epsilon越小,造出来的格越大。
在不设置的情况下默认为beta/8,这里就是0.4*8=0.05,这样跑不出来结果,就可以尝试缩小epsilon的值,这里实测,epsilon=0.026就可以出结果。
当epslion过小时,格过大,LLL算法会非常耗时,这里测试epsilon=0.01就需要一点时间了。
所以一般取0.01左右出不来,就得考虑方法问题了。
if epsilon is None:
epsilon = beta/8
verbose("epsilon = %f"%epsilon, level=2)
m = max(beta**2/(delta * epsilon), 7*beta/delta).ceil()
verbose("m = %d"%m, level=2)
t = int( ( delta*m*(1/beta -1) ).floor() )
verbose("t = %d"%t, level=2)
if X is None:
X = (0.5 * N**(beta**2/delta - epsilon)).ceil()
verbose("X = %s"%X, level=2)
# we could do this much faster, but this is a cheap step
# compared to LLL
g = [x**j * N**(m-i) * f**i for i in range(m) for j in range(delta) ]
g.extend([x**i * f**m for i in range(t)]) # h
B = Matrix(ZZ, len(g), delta*m + max(delta,t) )
for i in range(B.nrows()):
for j in range( g[i].degree()+1 ):
B[i,j] = g[i][j]*X**j
from Crypto.Util.number import *
n = 77181376028870767428506413273794792813827015423912051082788843012528976994995131246668984940391210475066597668329315822594645257086873735167077745300534961199777709548474369179406260920824820997996539563126878553761334790678733817244005887911626210406449309019240173369781910452082054174678810877799182859993
c = 74528016275557253012735040006933867353003516025896832221477819880425483528903078818518341999308485483023581596498066751077631605539209065848529211627206825051132116372877873018154355697802663441819723056933012730127555814325771869129620407718638077085507303921975621542388852572081358396973201178454310073668
e=3
pre=b'SHCTF{'
suf=b'}a_easy_problem'
flag_length=39
pre_bits=(flag_length+len(suf)-1-len(pre))*8
suf_bits=len(suf)*8
unknown_bits=(flag_length-len(pre)-1)*8
PR.<x> = PolynomialRing(Zmod(n))
f=(bytes_to_long(pre)*2^pre_bits+x*2^suf_bits+bytes_to_long(suf))^e-c
f=f.monic()
m=f.small_roots(X=2^unknown_bits,beta=0.4,epsilon=0.026)
if m:
x=m[0]
flag=pre+long_to_bytes(int(x))+suf
print(flag)
#b'SHCTF{ARE_yOu_PAdddlN9_ME_boY_do44d667}a_easy_problem'
ezECC
from Crypto.Util.number import *
from flag import flag
assert flag.startswith(b'SHCTF{')
m = next_prime(bytes_to_long(flag))
p = getPrime(512)
a,b = getPrime(128),getPrime(128)
E = EllipticCurve(Zmod(p),[a,b])
k = getPrime(256)
A1 = E.random_point()
A2 = A1*k
M = E.lift_x(m)
C = M+A2
print('p = ',p)
print('k = ',k)
print('A1 = ',A1)
print('C = ',C)
知道模数p,知道私钥k,需要求出椭圆曲线的参数a,b,之后问题就迎刃而解了。
在知道线上两点的和模数p的情况下就可以求出来了。
求出来之后直接利用私钥解出\(m_x\),然后小小爆破一下就可以了
fromCrypto.Util.number import *
p = 9799485259524549113003780400336995829253375211044694607315372450399356814285244762186468904824132005209991983177601498069896166228214442123763065076327679
k = 73771953838487511457389800773038323262861649769228176071578897500004883270121
A1_x=5945412329827707694132352090606154232045921322662767755331097180167148601629747751274580872108985870208681845078153424348847330421799769770041805208089791
A1_y=4113102573821904570542216004200810877456931033522276527318388416329888348077285857968081007666714313806776668203284797556825595791189566621228705928598709
C_x=2336301464307188733995312208152021176388718095735565422234047912672553316288080052957448196669174030921526180747767251838308335308474037066343018337141276
C_y=6868888273736103386336636953449998615833854869329393895956720058438723636197866928342387693671211918574357564701700555086194574821628053750572619551290025
a=(((A1_y^2-C_y^2)-(A1_x^3-C_x^3))*inverse_mod(A1_x-C_x,p))%p
b=(A1_y^2-(A1_x^3+a*A1_x))%p
E=EllipticCurve(Zmod(p),[a,b])
A1=E(A1_x,A1_y)
C=E(C_x,C_y)
M=C-A1*k
M_x,M_y=M.xy()
M_x=int(M_x)
k=0
while True:
flag=long_to_bytes(int(M_x-k))
if flag[-1]==b'}'[0]:
print(flag)
break
k=k+1
#b'SHCTF{fo1und_adm1n_1st111}'
E&R
#sage
from Crypto.Util.number import *
from secret import flag
flag = flag[6:-1]
l = len(flag)
m1 = bytes_to_long(flag[:l//2])
m2 = bytes_to_long(flag[l//2:])
#RSA
p = getPrime(256)
q = getPrime(256)
n = p * q
e = 65537
r_q = int(bin(q)[2:][::-1] , 2)
leak = p ^^ r_q
c = pow(m2,e,n)
#ECC
E = EllipticCurve(Zmod(n),[114514,1919810])
G = E.lift_x(Integer(m1))
P = G * e
print(f'leak = {leak}')
print(f'n = {n}')
print(f'c = {c}')
print(f'P = {P}')
参考文献:(两位神,膜拜)
RSA:Crypto趣题-剪枝 | 糖醋小鸡块的blog (tangcuxiaojikuai.xyz)
(剪枝说起来有点麻烦,我觉得关键就是要同时找到p和q高位或低位,要是只找p高位和q低位,爆破条件无法判断,这就是为什么这题需要同时用到pxorq的两端)
ECC:https://dexterjie.github.io/2023/07/25/非对称加密/ECC/?highlight=e.lift_x#HGAME-2023-week4-ECRSA
(ECC部分直接给了C点,也就是P的x和y,所以不用那么麻烦了,直接跳到最后求逆元就好了)
from Crypto.Util.number import *
import gmpy2
n = 7120275986401660066259983193598830554385933355254283093021239164350142898387660104515624591378875067038235085428170557400012848874756868985306042421950909
c = 6803450117490196163076010186755045681029929816618361161925865477601994608941714788803007124967390157378525581080320415602012078322064392991884070073083436
e=65537
#RSA
p=0
q=0
# https://tangcuxiaojikuai.xyz/post/342113ee.html
pxorq = 5599968251197363876087002284371721787318931284225671549507477934076746561842
pxorq = str(bin(pxorq)[2:]).zfill(256)
def find(ph,qh,pl,ql):
l = len(ph)
tmp0 = ph + (256-2*l)*"0" + pl
tmp1 = ph + (256-2*l)*"1" + pl
tmq0 = qh + (256-2*l)*"0" + ql
tmq1 = qh + (256-2*l)*"1" + ql
if(int(tmp0,2)*int(tmq0,2) > n):
return
if(int(tmp1,2)*int(tmq1,2) < n):
return
if(int(pl,2)*int(ql,2) % (2**(l-1)) != n % (2**(l-1))):
return
if(l == 128):
pp0 = int(tmp0,2)
if(n % pp0 == 0):
global p,q
p=pp0
q=n//p
return
else:
if(pxorq[l] == "1" and pxorq[255-l] == "1"):
find(ph+"1",qh+"0","1"+pl,"0"+ql)
find(ph+"0",qh+"0","1"+pl,"1"+ql)
find(ph+"1",qh+"1","0"+pl,"0"+ql)
find(ph+"0",qh+"1","0"+pl,"1"+ql)
elif(pxorq[l] == "1" and pxorq[255-l] == "0"):
find(ph+"1",qh+"0","0"+pl,"0"+ql)
find(ph+"0",qh+"0","0"+pl,"1"+ql)
find(ph+"1",qh+"1","1"+pl,"0"+ql)
find(ph+"0",qh+"1","1"+pl,"1"+ql)
elif(pxorq[l] == "0" and pxorq[255-l] == "1"):
find(ph+"0",qh+"0","1"+pl,"0"+ql)
find(ph+"0",qh+"1","0"+pl,"0"+ql)
find(ph+"1",qh+"0","1"+pl,"1"+ql)
find(ph+"1",qh+"1","0"+pl,"1"+ql)
elif(pxorq[l] == "0" and pxorq[255-l] == "0"):
find(ph+"0",qh+"0","0"+pl,"0"+ql)
find(ph+"1",qh+"0","0"+pl,"1"+ql)
find(ph+"0",qh+"1","1"+pl,"0"+ql)
find(ph+"1",qh+"1","1"+pl,"1"+ql)
find("1","1","1","1")
phi = (p-1)*(q-1)
d = inverse(e,phi)
m2 = long_to_bytes(int(pow(c,d,n)))
#ECC
# https://dexterjie.github.io/2023/07/25/%E9%9D%9E%E5%AF%B9%E7%A7%B0%E5%8A%A0%E5%AF%86/ECC/?highlight=e.lift_x#HGAME-2023-week4-ECRSA
a = 114514
b = 1919810
E = EllipticCurve(Zmod(n), [a, b])
cx=4143131125485719352848137000299706175276016714942734255688381872061184989156686585992844083387698688432978380177564346382756951426943827434190895490233627
cy=3879946878859691332371384275396678851932267609535096278038417524609690721322205780110680003522999409696718745532857001461869452116434787256032366267905519
E1 = EllipticCurve(Zmod(p), [a, b])
E2 = EllipticCurve(Zmod(q), [a, b])
order1 = E1.order()
order2 = E2.order()
d = gmpy2.invert(e,order1*order2)
Ct = E(cx,cy)
mx,my = (int(d) * Ct).xy()
print(b'SHCTF{'+long_to_bytes(int(mx))+m2+b'}')
#b'SHCTF{a67b2a9b-0542-4646-908f-7c002c687387}'