naby

导航

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

\[e*d_p=1\mod (p-1)=1+k(p-1)\\ 因为p是素数,可以选取任意数a,我这里取2就可以了\\ 根据费马小定理有:a^{p-1}=1\mod p\\ 扩展为:a^p=a\mod p\\ 我们可以得到:a^p-a=kp\\ 之后跟n求gcd就是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^{p-1}=1\mod p\\ 欧拉定理:a^{\phi(n)}=1\mod n\\ 再推一下就是:a^{k*\phi(n)}=(a^{\phi(n)})^k=1^k=1\mod n\\ 所以只要指数是模数n的欧拉函数的倍数,在模n下就等于1\\ \]

具体:

\[p=p_1p_2...p_s+1,q=q_1q_2...q_t+1\\ \phi(p)=p_1p_2...p_s,\phi(q)=q_1q_2...q_t\\ n=p*q,\phi(n)=p_1p_2...p_s*q_1q_2...q_t\\ 所以只要遍历get\_primes()得到的素数表,利用数a计算指数\\ 得,a^{k*\phi(p)}=1\mod p,之后的思想跟上题一样。\\ \]

补充:在计算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的情况下就可以求出来了。

\[x_1^3+ax_1+b=y_1^2\mod p\\ x_2^3+ax_2+b=y_2^2\mod p\\ y_1^2-y_2^2=x_1^3-x_2^3+a(x_1-x_2)\mod p\\ a=((y_1^2-y_2^2)-(x_1^3-x_2^3))*(x_1-x_2)^{-1}\mod p\\ b=y_1^2-(x_1^3+ax_1)\mod 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}'

posted on 2024-10-16 08:44  Naby  阅读(238)  评论(0编辑  收藏  举报