RSA3(p1-p12)

P1

这题将flag分为了m1,m2,然后给出了m1和m2的一个线性组合的值为1,m1与m2前的系数已知,这里记为a,b,则有:

                        ​​​​                        am_{1}+bm_{2} = 1 \ \ \ \ \ \ (1)

这里的a和b是互素的,我们对两边模b可得:

                                                am_{1} \equiv 1 \mod(b)

所以m1就是a模b的逆元,但我们求出的这个逆元是模b意义下的m1,所以真实的m1可能还需要加上k倍的b,得出真实的m1后,在代入(1)中就可以求出m2,代码如下:

from Crypto.Util.number import *
a = 18608629446895353521310408885845687520013234781800558
b = 14258810472138345414555137649316815272478951117940067
m1 = inverse(a, b)
for k in range(100000):
    m2 = (a*m1 - 1)//b 
    flag = long_to_bytes(m1) + long_to_bytes(m2)
    if b'NSSCTF' in flag:
        print(flag)
        break
    m1 += b

运行得flag:NSSCTF{4cdc3370-b5db-4f88-bd95-a43d232a9af9}

P2

这里是e为4的rabin攻击,需要我们在在模p的意义下开4次根,我们可以把m^{2}看作一个整体,所以就只需要开2次根即可,然后将开出来的两个根在进行开2次根,最后得出4个根,具体的开根方法可以以看我之前发的博客。这里稍微提一下,虽然开4次根会得到4个解,但其实去掉重复的只会留下两个不同的解,同样推广到e为2^{k}时,最后解出来也就只有两个解互不相同。具体代码如下:

from Crypto.Util.number import *
from gmpy2 import *

def rabin (c:int ,p:int):   #开二次方根
    assert p%4 == 3
    return [pow(c,(p+1)//4,p), p-pow(c,(p+1)//4,p)]

def CRT (b:list[int], m:list[int], sum:int):
    n = 1
    re = 0
    for i in range(sum):
        n *= m[i]
    for k in range(sum):
        re = (re+(b[k]*(n//m[k])*inverse(n//m[k],m[k])))%n
    return re

def attack(c:int, p:int, e:int):
    if e==2:
        return rabin(c,p)
    e //= 2
    return attack(rabin(c,p)[1],p,e)

p = 59146104467364373868799971411233588834178779836823785905639649355194168174467
q = 78458230412463183024731868185916348923227701568297699614451375213784918571587
e = 4
c = 1203393285445255679455330581174083350744414151272999693874069337386260499408999133487149585390696161509841251500970131235102423165932460197848215104528310
plst = attack(c,p,e)
qlst = attack(c,q,e)
m = []
for i in qlst:
    for j in plst:
        m.append(long_to_bytes(CRT([i,j],[q,p],2)))
for k in m:
    if b"NSSCTF" in k:
        print(k)

运行得flag:NSSCTF{9c66047c-72da-49b6-9856-00fd46969fc7}     

P3

这题生成的p1,p2非常接近,而且都远大于q1,q2,所以我们可以得到:

                                                \frac{n_{1}}{n_{2}} = \frac{p_{1}^{2}q_{1}}{p_{2}^{2}q_{2}} \approx \frac{q_{1}}{q_{2}}

所以用\frac{n_{1}}{n_{2}}的连分数可以精确覆盖\frac{q_{1}}{q_{2}},求出q1,q2后就可以分解n1,n2,代码如下:

from Crypto.Util.number import *
from gmpy2 import iroot
def Fraction_to_ConFrac(numerator, denominator):
    lst = []
    if numerator > denominator:
        lst.append(0)
        numerator, denominator = denominator, numerator
    while numerator > 0:
        lst.append(denominator//numerator)
        denominator, numerator = numerator, denominator%numerator
    return lst
def ConFrac_to_Fraction(lst:list[int]):
    numerator, denominator = 0, 1
    for i in lst[::-1]:
        numerator, denominator = denominator, i*denominator+numerator
    return numerator, denominator
def ConFractionCover(lst:list[int]):
    re = []
    for i in range(len(lst)):
        q1 ,q2 = ConFrac_to_Fraction(lst[:i+1])
        re.append((q1,q2))
    return re
n1 = 45965238261145848306223556876775641787109249067253988455950651872774381183888979035386577960806305813634216583223483001245996467366520071511779063266315692543617195166613592991812117446772937889819643718423377609566597230873623011099295202599905646652692946273375405832062164263711151844949794774229886016858313299259387152937467743637367261734624060321171598033647661809876890249035267180368762739600552966699295210431508056693524383116052539072065535970720901196322942269916455391238409489616842687658335666652878840458263998780783865062993401055465701207886230787204008073260653659510197069116237460322442433331870944968133645513020531983926180514313028320422449103156746225574626841023639595418255472716267486241462968101152032898749
e1 = 279586443815379026299414729432860797623
c1 = 11515318475856179010858377918435934663304239594599788732135470038988222237790835017056954077794506499559722814863240838882673078330335616745578747265404229105473136943188301293198548838105990504750972653445744347121859396823995101611868191609259910876207038154174100742978387355304521374228562928260479446249263909934393657537918407756957032700052269827171045167752168509783885071211516601218892308228572735545579606908430615218499620619028799140945676768341492724044499209913045110359935325510223652935426973411960865908064824205626343685369866932545651037748553442488682593143020861196339307665638704485958986411837014559504992818255506454051842453553265179370878637153602580071152915165775491633322055360737581203750897698007951117808
n2 = 25459365600568360055376316722846535809281537088824978187355135247184417413329012865221456308642116409716822227032113740366024809533942721286337697830775221199570509665320400376959076685728357107457862901087218522281771857981155239522807950207375964963527837592797198372303427082343684305143238075402697262610809363109748984974325271762535573995993132076293275456692621516174749076897962348000698039074721998780555541905706268579496243099763776676950336105074846695227221690550755501320117554250942600626927600558489780841103863110357615957088709321079080707735028039675102383525496673233697130053936053431067133520717494376952763684807635780416860233261892013531534059267366382617635000415723745274490604551078385404286689447761642713963
e2 = 249615977162294580923494787210301891647
c2 = 24544357952213952357056140974408354173440635791397720610932999473703241918398814255275362994811954064820912468224131892551724930677715676493892869921426790840199600798807085779112854131346378899855545138289836687048918660685766286852276199524789699567994154833159365800848535248059731927121269157841084905465048764152977389352561685340108834453730139893330210765986258703154334901509553990091592209268471594519326651914685843021165854654380119091009831071244459145750976193183411590207529489774630266528538380011000213950174694472355034075543687572037516433204151217601537869823709241020510051494619335852686100897182065588340025334679570763716458250649152257797833022586793526594784648938165537701256313728194521212887453997160504204832
for q1, q2 in ConFractionCover(Fraction_to_ConFrac(n1, n2)):
    if n1 % q1 == 0 and 1 < q1 < n1:
        break
p1 = iroot(n1//q1,2)[0]
p2 = iroot(n2//q2,2)[0]
d1 = inverse(e1, p1*(p1-1)*(q1-1))
d2 = inverse(e2, p2*(p2-1)*(q2-1))
m1 = pow(c1,d1,n1)
m2 = pow(c2,d2,n2)
flag = long_to_bytes(m1) + long_to_bytes(m2)
print(flag)

运行得flag:NSSCTF{ee5cb1a5-257a-48b0-9d62-9ef56ff0651a}

P4

a,p已知,且有下面的同余式:

                                        ​​​​​​​        ar \equiv m \mod (p)

所以:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ar = m +kp

由于r相对p非常小,所以类似于wiene攻击,我们可以在等式两边同时除以p,r可得:

                                                 \frac{a}{p} = \frac{m}{pr} + \frac{k}{r}

这里m应该不会太大,可以满足:

                                                \begin{vmatrix} \frac{a}{p} - \frac{k}{r} \end{vmatrix} = \frac{m}{pr} <\frac{1}{2r^{2}}

然后用\frac{a}{p}的连分数覆盖\frac{k}{r}即可求出r,代码如下:

from Crypto.Util.number import *
from gmpy2 import *
def Fraction_to_ConFrac(numerator, denominator):
    lst = []
    if numerator > denominator:
        lst.append(0)
        numerator, denominator = denominator, numerator
    while numerator > 0:
        lst.append(denominator//numerator)
        denominator, numerator = numerator, denominator%numerator
    return lst
def ConFrac_to_Fraction(lst:list[int]):
    numerator, denominator = 0, 1
    for i in lst[::-1]:
        numerator, denominator = denominator, i*denominator+numerator
    return numerator, denominator
def ConFractionCover(lst:list[int]):
    re = []
    for i in range(len(lst)):
        q1 ,q2 = ConFrac_to_Fraction(lst[:i+1])
        re.append((q1,q2))
    return re
a = 79047880584807269054505204752966875903807058486141783766561521134845058071995038638934174701175782152417081883728635655442964823110171015637136681101856684888576194849310180873104729087883030291173114003115983405311162152717385429179852150760696213217464522070759438318396222163013306629318041233934326478247
p = 90596199661954314748094754376367411728681431234103196427120607507149461190520498120433570647077910673128371876546100672985278698226714483847201363857703757534255187784953078548908192496602029047268538065300238964884068500561488409356401505220814317044301436585177722826939067622852763442884505234084274439591
for k, r in ConFractionCover(Fraction_to_ConFrac(a,p)):
    m = (a*r)%p
    m = long_to_bytes(m)
    if b'NSSCTF' in m:
        print(m)
        break

运行得flag:NSSCTF{e572546b-abb5-4358-8970-471abc12b7ef}

P5

这题也是用CRT把模数提高,然后直接开根,不过这里给的模数存在不互素的情况,所以要用到拓展的CRT算法,这个算法的主要思路就是把两个同余式等价转化为一个同余式,然后重复这个步骤,直到最后只剩一个同余式就完成了模数的提升。这里给出把两个同余式等价转化为一个同余式的方法:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        \left\{\begin{matrix} & x \equiv c_{1} \mod(n_{1})\ \ \ \ \ \ \ \ (1)\\ & x \equiv c_{2} \mod(n_{2})\ \ \ \ \ \ \ \ (2) \end{matrix}\right.

这里先写出满足(1)的x的表达式:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        x = c_{1} + k_{1}n_{1} \ \ \ \ \ \ \ \ (3)

将他带入(2)中得:

                                        k_{1}n_{1} \equiv c_{2} - c_{1} \mod(n_{2})\ \ \ \ \ \ \ \ (4)

要想这里的k_{1}有解,则需要满足以下条件:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        (n_{1}, n_{2}) \mid (c_{2} - c_{1})

(n_{1},n_{2}) = d,对(4)式两边除以d得:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        k_{1}\frac{n_{1}}{d} \equiv \frac{c_{2}-c_{1}}{d}\mod(\frac{n_1}{d})

所以:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        k_{1} \equiv \frac{c_{2}-c_{1}}{d}(\frac{n_{1}}{d})^{-1} \mod (\frac{n_{2}}{d})

所以:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        k_{1} = \frac{c_{2}-c_{1}}{d}(\frac{n_{1}}{d})^{-1} +k_{2}\frac{n_2}{d}\ \ \ \ \ \ \ (5)

将(5)带入(3)中得:

                 ​​​​​​​        ​​​​​​​        x = c_{1} + n_{1}\frac{c_{2}-c_{1}}{d}(\frac{n_{1}}{d})^{-1} + k_{2} \begin{bmatrix} n_{1},n_{2} \end{bmatrix}

所以:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        x \equiv c_{1} + n_{1}\frac{c_{2}-c_{1}}{d}(\frac{n_{1}}{d})^{-1} \mod (\begin{bmatrix} n_{1},n_{2} \end{bmatrix})

这样就把两个同余式转化为一个同余式了,具体代码如下:

from Crypto.Util.number import *
from gmpy2 import iroot
def exCRT (b:list[int], m:list[int], sum:int):
    n = 1
    re = 0
    for i in range(sum):
        assert (b[i] - re) % (GCD(m[i], n)) == 0
        re = ( m[i] * (inverse(m[i]//GCD(m[i], n), n//GCD(m[i], n))) * ((re-b[i])//GCD(m[i],n)) + b[i] ) % (m[i]*n//GCD(m[i], n))
        n = m[i]*n//GCD(m[i], n)
    return re, n
nl = [48900330639594979739701067783234903348599405413588466525574910520196852415104874636276388006189258357683981763, 52184798260918956005878710130354843122927544013692595240956998112200987084814453592388074200951779840156511, 57591305346419909943538345276263585821186563609432856462492112562586368230163591993342956384688555395772999, 1391052858660682537388264601016075339528373211889618359237336378385137832855656756800539626220549334300176727, 8401669052993451281764489325068020625937224410830694438332016050030698435746929661939302694116817188225591, 66809775375777747860816961274643428927028556487820183599747024350362932190079439298182707730302976119988715497, 41209230281867957743385705727577318625405890894626062454495908709761427062490881938652489884059847194603237277, 31140089821370202352241944402736292072447365626312703496944186462246895695650729682254970622208848300946861]
cl = [26617913696414745819584063604277199673357890677059949687794606743781436349829925794253672010780125661705587071, 6332739614121961923948917957498597962902897015582697635859365080803944882904908423983706426654363433337197, 46154051334276357655176765655327305918368830821288083739892570534253190653909520953027859629573215723954424, 2800905135165447908315158053695706832127646195243072751493365013371469263897970241141686022109978485359114, 3597083928897756955519089479028751799504001377334447013725903377254761160933418420625119547713455139382114, 17032086144873551648611964054579542303630306316746409528107026138674853298939194425805809444921339677455174485, 36111201824253386572496248461433786832561483450731317363761227351689971628309683994429845284904292821369745345, 28548175317543234723297895187238113463350377151401226415566179373530461612253257137535830491771909906093171]
c = exCRT(cl, nl, len(nl))[0]
m = iroot(c,7)[0]
print(long_to_bytes(m))

运行得flag:NSSCTF{6ff0651a-48b0-257a-9d62-9ef5ee5cb1a5}

P6

本题为p-1光滑,只不过组成p-1的小素数不是在base_sieve中选的,而是从一个名为primes的列表中选的,所以我们只需要更换素数表即可,代码如下:

primes = [...]
from Crypto.Util.number import *
n = 210488679270475701976181947365152313699517734264122394812492020724654505220623065289117447808270300405893088216711827935540458944042230307295703758023289811232234667671779565383964487868833609515040373751117785890923111021052281871560758159098018301948230396406718130378740957192704249130990473406094468375190967933383609736557
c = 136071043914570532351840574748667342595827512223368889758030473691165475344493240895540489846178990095609930878050872170334417124306746585253763197947342333489768575699470163018093386136808345465103492262428343569799463896437045282842447134475696863670001725029430508792000363373891006638520238615750531296612676072986388618657
e = 65537

sum = 1
a = 2

for i in range(len(primes)):
    sum *= primes[i]
p = GCD(pow(a,sum,n)-1,n)
q = n // p
d = inverse(e,(p-1)*(q-1))
print(long_to_bytes(pow(c,d,n)))

运行得flag:NSSCTF{e9991e0b-ade8-498e-86a9-bf4af9770399}

P7

本题为p+1光滑,只不过组成p+1的小素数不是在base_sieve中选的,而是从一个名为primes的列表中选的,所以我们只需要更换素数表即可,代码如下:

primes = [...] 
from Crypto.Util.number import *
from gmpy2 import iroot
def mlucas(v, a, n):
    """ Helper function for williams_pp1().  Multiplies along a Lucas sequence modulo n. """
    v1, v2 = v, (v**2 - 2) % n
    for bit in bin(a)[3:]: v1, v2 = ((v1**2 - 2) % n, (v1*v2 - v) % n) if bit == "0" else ((v1*v2 - v) % n, (v2**2 - 2) % n)
    return v1
def ilog(x, b):  # greatest integer l such that b**l <= x.
    l = 0
    while x >= b:
        x /= b
        l += 1
    return l
def attack(n):
    v = 1
    while True:
        for p in primes:
            e = ilog(iroot(n,2)[0], p)
            if e == 0: break
            for _ in range(e): v = mlucas(v, p, n)
            g = GCD(v-2, n)
            if 1 < g < n: 
              return g ,n//g
            if g == n: break
        v += 1
n = 345799778173748173773868120733939877012606206055022173086869626920649670201345540822551954372166638650313660302429331346299033954403991966160361903811355684857744142271007451931591141051285664283723609717718163872529480367508508005122335725499745970420634995317589843507796161899995004285340611933981932785753209168028330041659
c = 246232608531423461212845855125527519175008303736088113629990791124779986502745272419907699490375796645611551466345965328844415806242069890639077695943105766009969737068824735226917926112338655266209848386322013506145057902662138167248624945138207215690482597144303445656882230801297916736896978224496017358461492736283036138486
e = 65537
p, q = attack(n)
d = inverse(e,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(m))

运行得flag:NSSCTF{e9991e0b-498e-ade8-86a9-bf4af9770399}

P8

代码审计可以发现,这题的e与p-1是不互素的,甚至e可以整除p-1,这种情况我们就没办法求出逆元d,而是要采用有限域开根的算法(AMM算法)直接对m^{e} \equiv c \mod(p)开根,在得到一个根后,将它与一个e阶循环群相乘就可以得到e个解。这个算法原理较长,就不过多介绍了,具体原理可以看这篇论文,讲的比较详细,不过还是需要一些n次剩余和循环群的前置知识。具体代码如下:

from Crypto.Util.number import *
from gmpy2 import *
from random import randint
def AMM(c, r, p):
    s = p-1
    t = 0
    while s%r == 0:
        t += 1
        s //= r
    while True:
        non_residue = randint(1,p-1)        #找一个r次非剩余
        if pow(non_residue, (p-1)//r, p) != 1:
            break
    K = []                                  #r阶循环群     
    e = pow(non_residue, s*(r**(t-1)), p)   #生成元
    for i in range(r):
        K.append(pow(e, i, p))
    K.append(1)
    d = GCD(r, s)
    alpha = inverse(r//d, s//d)
    k = []
    for n in range(t-1):
        tmp = pow(c, (r*alpha-d)*(r**(t-n-2)),p)
        for i in range(n):
            tmp = (pow(non_residue, (s*k[i])*(r**(t-n-1+i)), p) * tmp)%p
        k.append(r - K.index(tmp))
    root = pow(c, alpha, p)
    for i in range(t-1):
        root = (pow(non_residue, (s*k[i])*(r**i), p) * root)%p
    return (root, d)    # root**r == c**d 
def ALL_Solution(root, r, p):
    s = p-1
    t = 0
    while s%r == 0:
        t += 1
        s //= r
    while True:
        non_residue = randint(1,p-1)        #找一个r次非剩余
        if pow(non_residue, (p-1)//r, p) != 1:
            break
    K = set()                               #r阶循环群     
    e = pow(non_residue, s*(r**(t-1)), p)   #生成元
    for i in range(r):
        K.add(pow(e, i, p))
    K = list(K)
    for i in range(len(K)):
        K[i] = (root*K[i])%p
    return K
n = 38041020633815871156456469733983765765506895617311762629687651104582466286930269704125415948922860928755218376007606985275046819516740493733602776653724917044661666016759231716059415706703608364873041098478331738686843910748962386378250780017056206432910543374411668835255040201640020726710967482627384460424737495938659004753604600674521079949545966815918391090355556787926276553281009472950401599151788863393804355849499551329
c = 2252456587771662978440183865248648532442503596913181525329434089345680311102588580009450289493044848004270703980243056178363045412903946651952904162045861994915982599488021388197891419171012611795147125799759947942753772847866647801312816514803861011346523945623870123406891646751226481676463538137263366023714001998348605629756519894600802504515051642140147685496526829541501501664072723281466792594858474882239889529245732945
p = 5220649501756432310453173296020153841505609640978826669340282938895377093244978215488158231209243571089268416199675077647719021740691293187913372884975853901554910056350739745148711689601574920977808625399309470283   
q = 7286645200183879820325990521698389973072307061827784645416472106180161656047009812712987400850001340478084529480635891468153462119149259083604029658605921695587836792877281924620444742434168448594010024363257554563
e = 1009
pl = ALL_Solution(AMM(c, e, p)[0], e, p)
ql = ALL_Solution(AMM(c, e, q)[0], e, q)
cnt = 0
p_inv = inverse(p, q)
q_inv = inverse(q, p)
found = 0
for i in pl:
    if found :
        break
    for j in ql:
        m = (i*q*q_inv + j*p*p_inv)%n       #CRT
        if b'NSSCTF' in long_to_bytes(m):
            print(long_to_bytes(m))
            found = 1
            break

运行得flag:NSSCTF{ee5cb1a5-9d62-257a-9ef5-48b06ff0651a}

P10

本题仍然是使用AMM算法,但是可以发现e并不整除q-1且e与q-1存在公因子,这个时候就不能直接套用AMM算法,而是要先做以下处理:

记 (e, q-1) = d,则根据贝祖定理,存在整数a, b满足:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​   ae + b(q-1) = d

求出我们通过两边同时除以d,然后求出\frac{e}{d}\frac{p-1}{d}的逆元即为a,得到a后,我们做如下操作:

因为:

                ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        m^{e} \equiv c \mod(q)

所以:

                                m^{d} \equiv m^{ae+b(q-1)} \equiv m^{ae} \equiv c^a \mod(q)

这样得到了新的加密直数d,d能整除q-1,所以此时就可以套用AMM算法,具体代码如下:

from Crypto.Util.number import *
from gmpy2 import *
from random import randint
def AMM(c, r, p):
    s = p-1
    t = 0
    while s%r == 0:
        t += 1
        s //= r
    while True:
        non_residue = randint(1,p-1)        #找一个r次非剩余
        if pow(non_residue, (p-1)//r, p) != 1:
            break
    K = []                                  #r阶循环群     
    e = pow(non_residue, s*(r**(t-1)), p)   #生成元
    for i in range(r):
        K.append(pow(e, i, p))
    K.append(1)
    d = GCD(r, s)
    alpha = inverse(r//d, s//d)
    k = []
    for n in range(t-1):
        tmp = pow(c, (r*alpha-d)*(r**(t-n-2)),p)
        for i in range(n):
            tmp = (pow(non_residue, (s*k[i])*(r**(t-n-1+i)), p) * tmp)%p
        k.append(r - K.index(tmp))
    root = pow(c, alpha, p)
    for i in range(t-1):
        root = (pow(non_residue, (s*k[i])*(r**i), p) * root)%p
    return (root, d)    # root**r == c**d 
def ALL_Solution(root, r, p):
    s = p-1
    t = 0
    while s%r == 0:
        t += 1
        s //= r
    while True:
        non_residue = randint(1,p-1)        #找一个r次非剩余
        if pow(non_residue, (p-1)//r, p) != 1:
            break
    K = set()                               #r阶循环群     
    e = pow(non_residue, s*(r**(t-1)), p)   #生成元
    for i in range(r):
        K.add(pow(e, i, p))
    K = list(K)
    for i in range(len(K)):
        K[i] = (root*K[i])%p
    return K

n = 98950849420612859614279452190318782153029931966597217314273823358984928689736597943774367572478091193816498014404387458350141854427041188032441028722132300155987022405432547244436252627801235200799719531840755071562539171489733346246951714886747673950900290905148318965065773167290984966067642777528454814019184856012497536781760044965489668142694134954466581148235162435617572891367282110999553789319439912296241889469226304877
c = 22561646796929363815984273658718096881828574147472740106912668949512978818367595303883956088667384207835022579136977262135029404640598574466248596921339941958216824486529066880854722372158998556902335323841170236300423638675072077074005797219260622119718558697081430219981494670569821476853158740209737420919480047033900157150865588466910802691118334480300332681763467974691587834295938999022060676767513865584039532912503921584
p = 33918986475509072603988274492338254523919682179700323084167169617716245684540055969194500298976880885466534900490327133434356902533524212744941101469238500990334546197257933040365697281122571898438913033813040027859  
q = 2917270228344219924472221188897798789902618263281810355113281879157575741497356945522168552316357276417700368971563177551494320723579146612010452353273237547587402941227901795977981691403950826343318848831462080703
e = 1009*7
pl = ALL_Solution(AMM(c, e, p)[0], e, p)
a = inverse(7, q-1)
ql = ALL_Solution(AMM(pow(c, a, q), 1009, q)[0], 1009, q)
p_inv = inverse(p, q)
q_inv = inverse(q, p)
found = 0
for i in pl:
    if found :
        break
    for j in ql:
        m = (i*q*q_inv + j*p*p_inv)%n       #CRT
        if b'NSSCTF' in long_to_bytes(m):
            print(long_to_bytes(m))
            found = 1
            break

运行得flag:NSSCTF{827152d9-4ac6-4dd2-8f33-c6a28a1433d2}

P11

本题将rsa密钥以pem格式存储,我们可以使用openssl工具解析pem文件,在安装完openssl后,使用以下命令用文本格式输出密钥:

openssl rsa -in key.pem -inform pem -text

 打印如下:

可以发现私钥与模数均存在,所以直接解密即可。

除了用openssl解析外,我们还可以使用Crypto库中的PublicKey模块,具体代码如下:

from Crypto.Util.number import *
from gmpy2 import *
from Crypto.PublicKey import RSA

rsa = RSA.importKey(open('key.pem', 'rb').read())
c = bytes_to_long(open('enc', 'rb').read())
m = pow(c, rsa.d, rsa.n)
print(long_to_bytes(m))

运行得flag:NSSCTF{4f85c39b-6d7a-4e29-a215-7379e30d2939}

P12

此题给的.pem只有半截,需要我们自己解析。先用base64解码得到:

3a1d7b10ba7f9f652b9ea83f81a15b2961e00cd63374f346a8d78f81dad1b697f3abe8eced002260d89f2d12bc9395c233012b6f744a380d1d0aed78c9fb52a28d95f858c630bd3b164e857b406f541311426d64d5f0b6e0d102818100befff9907f75bb7ad561131b5c76ae137bd67ae0e32b90f92b997b044277cab3dfeb84f255138127e1a4e53751a68db743a00ed8acc58f33107fe35db6b4813bc048db48bd530bcb35fba434dbb70e27d78aede2de0d4745df35a245417b8c74a31a7b55a77db45ebd6ed1dc4b3dcaa435a79dbf7240d96775372e64b58b080302818077a554614c111b51dea903a8e8222be795b45948805fc6f5ea67e60ad493f117b3033ea2ee84d87c0a29a87ea38908a93e313e08fe83dc91ba8695ba969d40f243addff620ee40bda8562ff5389661efd8b9d5976bacf2bc9a1cfc54d7704c7098441b1e7253760fc7dbcef7a417082e7492e8e0808f34d830c772e800714f410281801c1005fdea0c454075eb6e603dc49e2cf4abfd9fdf20be8b2d91be5650e1c2e18ccbd0dbbe0e4092b87f7ec212f812a8538247cc240e5eccd4e6c564367cece3f78b7cd482249a7dffef7a1fde0c56431a532a4283f7957a39a26ab61c39e7d81742c3ce40eea23aad40840b06ef0c3ff6362b623e8a32a715bcc6cf3b31333b028181008488efbea72e9abac7f71085b86e9071bece170f8c92a387aebdcc89f8915c33739609a73cacd5559b3a56fd59082ed311bab49f42ea0ba6be5e253453db0fc8b5b6aab458163b8a013121fd5c554dcc51d81c57e60f59d9d7f8f4d45fab24365da039ed8fb5401cfaff0c8aae2191ae8bd742351d11034ff0f0c32fb0586810

然后找到这段字节串中第一个02,根据02后面的一个字节大小,往后偏移相应的字节,如果尾部的后一个字节不是02,则说明我们找到的第一个02不是数据的头部,而是上一个数据的信息,这需要我们找到第二个02,然后重复上述步骤,最终可以得出4个数据,那么这4个数据就分别是:(q, dp, dq, inv(p, q)),这里我们没有n,但是有dq,所以可以求出m在模q意义下的值,如果m<q,那么就可以求出m的精确值,具体代码如下:

from Crypto.Util.number import *
enc = 2329206064672111950904450292941421573350591294207157652026787098178545948258554492347649016030892000747909819064473414536692222493030122267884839986067073054508582403564557167583565364976046083954888777809177108315052118912603290095925912298584322873410379937455462434313487981715516761071523410121549134193124709612876311518391130974466069686830456036397449773159386026998482557500868323733155606973727191287617806211911722356975478414165867941665666556476756617951672736466672410799762479373101996896644454778482896784598378016390592459460753042458284030795009957030383305268628413551730442224404807955926606496353
q = 0x00befff9907f75bb7ad561131b5c76ae137bd67ae0e32b90f92b997b044277cab3dfeb84f255138127e1a4e53751a68db743a00ed8acc58f33107fe35db6b4813bc048db48bd530bcb35fba434dbb70e27d78aede2de0d4745df35a245417b8c74a31a7b55a77db45ebd6ed1dc4b3dcaa435a79dbf7240d96775372e64b58b0803
dp = 0x77a554614c111b51dea903a8e8222be795b45948805fc6f5ea67e60ad493f117b3033ea2ee84d87c0a29a87ea38908a93e313e08fe83dc91ba8695ba969d40f243addff620ee40bda8562ff5389661efd8b9d5976bacf2bc9a1cfc54d7704c7098441b1e7253760fc7dbcef7a417082e7492e8e0808f34d830c772e800714f41
dq = 0x1c1005fdea0c454075eb6e603dc49e2cf4abfd9fdf20be8b2d91be5650e1c2e18ccbd0dbbe0e4092b87f7ec212f812a8538247cc240e5eccd4e6c564367cece3f78b7cd482249a7dffef7a1fde0c56431a532a4283f7957a39a26ab61c39e7d81742c3ce40eea23aad40840b06ef0c3ff6362b623e8a32a715bcc6cf3b31333b
inv = 0x008488efbea72e9abac7f71085b86e9071bece170f8c92a387aebdcc89f8915c33739609a73cacd5559b3a56fd59082ed311bab49f42ea0ba6be5e253453db0fc8b5b6aab458163b8a013121fd5c554dcc51d81c57e60f59d9d7f8f4d45fab24365da039ed8fb5401cfaff0c8aae2191ae8bd742351d11034ff0f0c32fb0586810
m = pow(enc, dq, q)
print(long_to_bytes(m))

运行得flag:NSSCTF{301815bd-67ca-4866-9934-61144503d6b5}

  • 30
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ECDHE_RSA和P-256都是TLS协议中的加密算法和密钥交换算法。其中,ECDHE_RSA是一种基于椭圆曲线的密钥交换算法,P-256是一种椭圆曲线加密算法,它们通常一起使用以提供更高的安全性。 具体来说,ECDHE_RSA是一种基于椭圆曲线的密钥交换算法,它使用ECDH算法来协商一个临时密钥,然后使用RSA算法对该密钥进行签名,以确保密钥的机密性和完整性。而P-256是一种椭圆曲线加密算法,它使用基于椭圆曲线的数学问题来保护数据的机密性。 如果您想在Java中使用ECDHE_RSA和P-256,可以使用Java Cryptography Extension (JCE)提供的相应算法。具体来说,您可以使用SunJCE提供的ECDHE_RSA和P-256算法,如下所示: ```java import javax.crypto.Cipher; import javax.crypto.KeyAgreement; import javax.crypto.SecretKey; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.security.*; import java.security.spec.ECGenParameterSpec; import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; import java.util.Arrays; public class ECDHE_RSA_P256 { public static void main(String[] args) throws Exception { // Generate ECDH key pair KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC"); ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1"); kpg.initialize(ecSpec); KeyPair kp = kpg.generateKeyPair(); // Generate RSA key pair KeyPairGenerator kpg2 = KeyPairGenerator.getInstance("RSA"); kpg2.initialize(2048); KeyPair kp2 = kpg2.generateKeyPair(); // Generate shared secret using ECDH KeyAgreement ka = KeyAgreement.getInstance("ECDH"); ka.init(kp.getPrivate()); ka.doPhase(kp2.getPublic(), true); byte[] sharedSecret = ka.generateSecret(); // Sign shared secret using RSA Signature sig = Signature.getInstance("SHA256withRSA"); sig.initSign(kp2.getPrivate()); sig.update(sharedSecret); byte[] signature = sig.sign(); // Verify signature using RSA sig.initVerify(kp2.getPublic()); sig.update(sharedSecret); boolean verified = sig.verify(signature); System.out.println("Signature verified: " + verified); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值