RSA4(p1-p11)

P1

本题为Schemidt-Samoa密码,原理点我

代码如下:

from Crypto.Util.number import *
n = 539403894871945779827202174061302970341082455928364137444962844359039924160163196863639732747261316352083923762760392277536591121706270680734175544093484423564223679628430671167864783270170316881238613070741410367403388936640139281272357761773388084534717028640788227350254140821128908338938211038299089224967666902522698905762169859839320277939509727532793553875254243396522340305880944219886874086251872580220405893975158782585205038779055706441633392356197489
e = n
d = 58169755386408729394668831947856757060407423126014928705447058468355548861569452522734305188388017764321018770435192767746145932739423507387500606563617116764196418533748380893094448060562081543927295828007016873588530479985728135015510171217414380395169021607415979109815455365309760152218352878885075237009
c = 192900246089028524753714085947506209686933390275949638288635203069117504901164350538204619142802436833736532680210208373707687461486601253665313637541968852691434282584934523173439632554783111037594035333325446559685553119339191110056283203940511701992217372405369575376549738295022767068810511670144120539082403063406787770958515441813335548550876818218065412869322721395317537328975187612606437225577060414403223288106406471061759010085578263501971809720648827
pq = GCD(pow(2, e*d-1, n)-1, n)
m = pow(c, d, pq)
print(long_to_bytes(m))

运行得flag:NSSCTF{864098e7-7ef1-4c7e-90d6-d103d8c272e0}

P2

 本题需要我们解一个同余意义下的一元三次方程,可以使用Coppersmith攻击,但直接写代码的话就太复杂了,所以这里可以安装sage,sage里有现成的small_roots方法来实现Coppersmith攻击。安装完sage后,我们打开SageMath Notebook:

 之后sage会在浏览器创建一个Jupyte坏境:

我们点击右上角的 New ,然后选择 sagemath,就可以写sage代码了,sage的语法与python一样,但sage多了一些东西我会在注释里说明。对于本题的sage代码如下:

from Crypto.Util.number import *
from gmpy2 import *
p = 133497915779382863191750985139274661777547262395290628161924420897772911005538338729076080701700641387222690295548776566406640902391412661622674862629221960258683570655393881212072865809598640669325347893228617784548982886334708010706482958773921901369314425694414231562752232070402056445403762485870067804611
a = 9956367951694116871507184264812038680047685394446603010101493156120195118634053526664122377707243776744926630820373051608195739431033785355316509320690639
b = 10372715760267086803036635068149481902075294943354407472550232447612611381527989796797133302495652064200149218004252582942179771677307157495328484190016267
c = 6954444546090251351899752282258945069765577103755637726562318645879810909547057855773433206441550954298878711294660493586907360045986061150306446126101573
d = 12708905621484064085174866220764918657140490021181156214236692898034114314742314389460399916798129560082685314351680895409634875081403212130502800572290391
y = 89881957270704175663646084308402351944545222001266778194637035700540903495792268004845278611707036762628657152963392762363015748904045511650663013086598899685992255568758440781657480520250399778976982455784259655683731183717562593121780657623767804362641533930566522430
h = 584447473604416360596641349947186936435346265446590336271443321812736224750414727189483734666053582372219773206703655293254283559436185831581631

PR.<x>=PolynomialRing(GF(p))    '''建立一个多项式环,你可以简单的理解为一个多项式声明,其中x为自变量,GF(p)表示多项式是在模p意义下的多项式'''
f = a*x^3 + b*x^2 + c*x + d - y '''创建了一个一元三次多项式f'''
f = f.monic()                   '''用monic方法将f的最高次系数化为一,这样才能用small_roots方法求根'''
                                '''我们自己也可以将f化为首一多项式,只需要给每个系数乘上a模p的逆元即可'''
re = f.small_roots()            '''用coppersmith求根'''
m = h // int(re[0])             '''由于re是模p意义下的根,所以要先转换为整数'''
print(long_to_bytes(m))

运行得flag:NSSCTF{fdf4236b-50a9-4d4b-96fb-fe9ba9d7dff7}

P3

此题给了我们如下两个式子,但他们都是m的幂为3,但我们可以做如下操作得到一个m的幂为1的式子,从而解出m:

已知:

                                        \begin{cases} m^{3} \equiv c_{1} \mod (n)\ \ \ \ \ \ \ \ \ \ \ \ (1) \\ (am+b)^{3} \equiv c_{2} \mod (n) \ \ \ (2) \end{cases}

将(2)式展开整理得:

                        ​​​​​​​        ​​​​​​​   3b(a^{2}m^{2} + amb + b^{2}) \equiv c_{2} - a^{3}c_{1} +2b^{3} \mod(n)

两边同时乘以(am-b)得:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        3b(a^{3}m^{3}-b^{3}) \equiv (c_{2} - a^{3}c_{1} +2b^{3})(am-b) \mod(n)

所以:

        ​​​​​​​        ​​​​​​​        m - a^{-1}(3b(a^{3}m^{3}-b^{3})(c_{2} - a^{3}c_{1} +2b^{3})^{-1}+b) \equiv \mod(n)

具体代码如下:

from Crypto.Util.number import *
n = 100458074154921630841467009716211081004496986067171453439200150708921645946139163766441611050743248698408002732330100522747315912617782265320913313460939731072047224701193946357341685422329349168512101723657005099845122860786073559690394636750367940135874243034107367507957642817011696553619030089913082650051
a = 235598638113466821523819951671842238817
b = 183046284622289531351267591814278208143
c1 = 59213026759461784288811267183372841532509333531605324857784387344377914885661521950844577998650904368265218037805476510488318417561718106578315758637105422183211905379616339980270327392640886739452625323181466064322246845738001714864060399808732460864513032069624364554351131806580712989439398464697132652674
c2 = 3451970836023636992808694960720139231990590529637727188690993996140273782744393239397467373679391223914185297028545706156586953463105320180151843119949047044046733716896796505869700601788410522957973779842899158545218190431782013633486273807312128458720848868027747769057989052968304813931468091592761421857
m1 = (inverse(a,n)*(3*b*(a*a*a*c1-b*b*b)*inverse(c2-a*a*a*c1+2*b*b*b, n)+b))%n
print(long_to_bytes(m1))

运行得flag:NSSCTF{76f8044e-7bf9-43cd-885f-22f611628b8b}

P4

本题大致与P3一样,但是把e提高到了5,这样就不好再去展开一个5次多项式了,回顾P3的方法,其实我们就是在从题目中关于m的两个高次多项式中求出了他们的一个公因式,这个公因式是一次的,可以直接解出m。所以本题我们也想求出关于m的一个一次多项式,而对两个多项式而言,求他们的公因式的方法形式上与求两个整数的最大公因数一样,在sage里,我们直接把多项式当作一个数看待即可,然后对他们使用辗转相除法就可以求出一个关于m的一次多项式,然后求出m即可,具体代码如下:

from Crypto.Util.number import *
from gmpy2 import *
n = 13919443827889434443507983317773657992305936401066686387374260636490833628767777134968864107882874635776776741295578533278845576747348959144023000046017344598661215911149680972293657114227644912150926936884507570232880546597335636361816325245444237275023999522533527764240730547185826755972838574195391038131656239536920948158465916528880835693552792260356361022462682037427718404037021825844211741628768123221090717527493
a = 285426137705625850725555147387995674019
b = 277985464990476154618471183198080357743
c1 = 9426395562512809581013620472326672750327318596813074726353079091173842802365552984264585030513998874440683981314827988473250779276622812642078592270162488257445750556180090334901558598065090257832879692296066144186335139137620672058976438826755846843815726564085636220609216862492337842110335421544935056753632826033207088809042045528566533513130910178132026694855125856386336197708244017301467175024440126022121500756597
c2 = 7817626870900560837063304883188246502988767588941344995287074193857215881437472677956793645281329763767094907997432409446021978284194802133451654430505222891535367029301384789198710394554265321474931034378249847884399129098152817955822667403789421376159327548545340231962148603594715994813791837670639630747654837874296940404313828931665262517234613625655607389345122624044747819855804429899373080756267420097146009333048
PR.<x> = PolynomialRing(Zmod(n))
f1 = x^5 - c1
f2 = (a*x + b)^5 -c2
while f2:
        f2, f1 = f1%f2, f2
m = int(f1.monic().small_roots()[0])
print(long_to_bytes(m))

运行得flag:NSSCTF{ca5e5ba4-57f1-4902-9448-d78b2cb05618}

P5

此题给出了以下信息:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        (a_{i}m_{i}+b_{i})^e \equiv c_{i} \mod(n_{i})

我们可以通过sage内置的CRT函数将这些式子转化为一个式子,然后用coppersmith求出小根就可以得出m,具体代码如下:

from Crypto.Util.number import *
from gmpy2 import *
Cs = [3883550483902420926234302242195949363902226654053022494278088796963093148922544154652393440710324453957805003804862341179812753736616349557399185135880313324078548975985811806182903172952051652658588498612963004980264760087430598878125976827727487812798234711111712162020259061748840871764150680864715622600474900724019717, 44236067230701013362887598977513235723198800481322709348886355202907732899445854511587419035591039483362973933824325371001141984765195796979842132811747908218486539899605454036424269293612496645594202012384509417494958938609654993954815298870367636552785788956298375017694826184378792550191638399421497826339423606821604157, 6357650953899476167368901224389387403906446759598372329485772462484633677698135444868033121301336092469156582681179266678600618088894651608959308419170191169045155695737438290373562868522834196889856654007109891894017495798358315308038562408520108440771857096111507359080036538511243240503551392124933753089110476128205879, 22113876206623661433094377745740418662890776774627724662206682745097788065566600734855556673140969239465263787646309908630165398806037735405429975451284487302914604239730662891329034924321076102542709261476260968369261179396546360622009680551846353241542278987410340410787241742872482813920394082039159494900989803139848, 3482139402999788223900773097355269284333433274039980036209713091774078099956379218113295375979469580323031564990774054948555715060182912479470463142901382767332589017162687376944227096536463901792518843690268101660074429034365722795293704792196728134808253362549344588424246863639211005569740713503298812433885633339928000]
Ns = [16475947720089128737086499038994656469812989231809435921247088488421456071533054401942524421620331649062071397844226728071767213827034006847771426419523100773295773164564476217357610574522713490589578290280800714302496527429690267342283298617108512673396866659851168908725556917773195601048972304412711680140760801040935590195586074637385222382292803661244860123231496798860777536415139625565081790463543592610972293444445484103576151223863074744798386995109810985102707212603792744509634887671301358727199987659311189567616661188675145831286196163294361139604739930788248190209148634033965292667427275010588011907449, 20577756967813119473983751142406348831049793754920537415005815223703461130310397180758312537008616509869607815711902558904863798387297921980544196445945053155779852988514975874071063143079007922739179751830691324912287324521191080786349595537328978318940405478035852622078260078106150355838894304903666410802941404171580632337325226810035755441751019274785623857299274197733366157959314887828355684391955406242669453470960096408521602483306976326328443227588146790803825249363494429478920856868334932355802422905860734038456902208606699044555491079703407805059303577939602439962034474867810455961978123428573930309579, 25378900199358568547963276996842869295995268651191814514603221510827400166103120330924988917554751086130358554721062101701515825946297524373525439060420148179742729309006073061967296139229954269726231365437710075337125457376990188019604789882474361937774315087501386157518068677103700336670450539759041322742305750381808526633011613014316600728378154635620303486714630541107978228937765593165029293600696974317531575469630789089360595175501977260250968161370460576429760743419177492425307438895058834861598683601140950473599184767494278677563047031229859204765208419798131798581975676005652781036214330956450007099403, 9926930930542540303568927026135349869339912234415090245441062010278559018661286180235901235221302260175325531516014675014545716516533078219977130807590578846757066721033900594646767488495122383467444918251577083210413483316448060657426105745966157951221212755678202988755054192555411944547922101946719460879213184073264876177559979901796761414990531875287201475974601204234252323254624416703924391519239658714195344209537776288504410483034555245167972866281710032749023882686703242857598745646748066876170805806058616787854614797120972981188197354785585317082619741063413472652781873599900240100437586392949061248911, 20830107058752240343833750223075661528901765032886427653372256688107333986271844745610709207164953960695218903201021174901973495649232416991828815735226979007977454196096030222267886398005100472650709789400722193947140354500257454594031250139843254349174343293378469322212240525155348525032929797789787100019790044104691478313003888625343348575779856701393153928092199647854293030744711864943595605801812851745568294572509414459253058726953902809163955547592002726224051451969415362170516701646937298176613945563863745599843208814303891064544739910893746169725919856235296428308161065429422882694228900677440053029677]
A = [56, 126, 66, 10, 54]
B = [261, 191, 877, 352, 62]
Fs = []
for i in range(5):
    PR.<x> = PolynomialRing(ZZ)
    f = ((A[i]*x + B[i])^3 -Cs[i])
    Fs.append(f)
f = crt(Fs, Ns)
N = reduce(lambda x, y :x*y, Ns)
f = f.change_ring(Zmod(N))
re = f.monic().small_roots()[0]
print(long_to_bytes(int(re)))

运行得flag:NSSCTF{35036d92-a21e-4a72-b95b-9dbbe753ecc3}

P6

本题与P5的区别是多项式的指数有些为3,有些为5,这个时候需要为指数为3的多项式乘以x^{2},使所有多项式同次幂,然后再使用CRT提升模数,最后用coppersmith求出小根,具体代码如下:

from Crypto.Util.number import *
from gmpy2 import *
Cs = [1638372860396333830858192139299197565315535797114047251934794618479536350353064186140459367290707128364710894701037380862116232991456320452033817724729745999551370161110364719775843718524874686887258953369568831680913879476181277785920985528366522169515587323204831502022101524013959969707030218702665635534427846097310528, 24875103245287518333798583341170669610612985353699595724009027288108265538326708679930645795919635882205442133007431151523157879281206220723880745758565471501438254496442690083695181899335274484890789079296262809116356375268279845048678237286447923982167817217922153443176926762232059077533241044053964988769850924306985288, 64688172933628370164101081823612690628987450046625542396917972565171355353907472697857255273381548322579305723285123851525656566580337341114653428214836087595329638898225145943365511037774869374134885003316128253926961420282704740956759510282270641913416144450959604091354160410240665076557553695082195679797827535998182932257141208537699109343258070255441327703937342812407754987740672481360192201134257594522722416452532574980648175817255926752015634178759148371873886725487426882416560377719144628014480729074137290874113394638649, 2331510898077623659120984694249257439156322301842388986730933314009350853947089766519871253176646702446795943582256729119033154456495699173945031006143311061427619102940335615125087858864022720270624007893746341836293909702537610528426633085355155950799091717823412938027363876570661223166297511428235178239172777386054157082903814899961457013918859628205065752880604381763832163537338551244398891801443773401629786720308176486501031559320335954176695196225203579812567823068688019940197116285653102121974647104338589625423162979123200000, 43352520643859740433225512983905414415548381386134203892101097918185149451843972944152506360707251233402378401486868477947209998018140026240239412053179633750634829740693522063308924633469091372871162080586416600131760956876088974352867618081110555761392159757815560347289247112408714776983781605234434193615594699312985986139327998952524143416350988540093792251368427565860264534170095799987780694458909019564914374157162696794037736526763479508220179034487041180476942175322953798097172419873588374189541978291235559914015746424832]
Ns = [18851715582267592911067637781505654688524006829609246212518637897179276424340538881817812202528554956234031661903911094094631063183133761100477455043312123459298106634164727720627011192110779310094771478538283788677548037922530846281891688189750395295091964623923749350256625089576542690752106832774515171043826627323369467260229924116376613509392517052062075900227272040203183759436637270279153088519018200373369193287900910393638164679806105636141482865492140475543667203300150180799017010647191076802371803957049729665372388660643393619274625881752621206735741181918995753694012667166942840946695127545765890742063, 10267889563711456032579409966472790716819993551437295130252040883990243681903448974535591113545723576913765740482844093394217174748720819947126768257873382519317182097620449979975383634794725676148262423293825784384533131631434500141020335993500562261013949796155168237990517113432978329233691874362416933639983930536969236091719851430961549012395926775041931819868164629850848771931505977967078205269399517880792473005512550209988476927697762292764104113892623269364458825553466135026856101503576301198196565099526473547248865742864274841493027912793979121030411574680325683879250124843231524231297963898683611241527, 13319929603701741793046504861847275881318265379528541599237187836042138080675688093798835275556697353969650992398737328710351200421781106774355347739070892841366306344713730729129300977800957626288502163079067715579382767916393807593767445074588824226624616133919776732577297061788596743900830022053036147505073981250694269494874718657327986653908553022998256475699594299485467200757418076210359679356806790879777840686012933726208975488043576064467651494231751296178499718963576152784658938960177680763100892103245100085259616393419229979173756419121148473713407084223326468838444608241533523272737548699784114288903, 15549454451010517732114866346347857621738418424726590607108866905866201671458396332585415677794254468988000522332928496951404966782246273839731570675805037547434885303486571417761150107287375265185136666085669367768385334732360327965658288195932251712038801089064036484182689420567148777802229959025706026709147490355638461816828297349827923064039389517458474972494803430895794622409100453812936135163906960476019328052200697229957383357240180993014685003281514802948810450239516985749998285384120569891328984748185007801287194757011610585773959113119657356194098917480068595559585415503075706079451596444873538025303, 10893748607240110955496798243605432030914497581057961213501578142738832043376333318606333861002076584473798177824249978795107994620002676260061434742704861691017695197358462123116073867166385116309506188722505093349759974669126863738760846667781081937653476878088812043691664173859578763022307064317030903235196823302973152319271598841684324885625237030423977448610068847582315745648803893547950848775977888604054275196982524051414526965045483738781651554877828535198984557716599475979572917851219474771059404496356672662467552795811246938928548202179363916774439119111218984949582826015360298300266708147597580287967]
A = [42, 104, 13, 106, 12]
B = [338, 554, 768, 638, 548]
e = [3, 3, 5, 5, 5]
fs = []
for i in range(5):
    PR.<x> = PolynomialRing(Zmod(Ns[i]))
    f = (A[i]*x+B[i])^e[i]-Cs[i]
    if e[i] <= 3 :
        f = f*x^2
    f = f.monic().change_ring(ZZ)
    fs.append(f)
M = reduce(lambda x,y:x*y, Ns)
re = CRT(fs, Ns).change_ring(Zmod(M)).small_roots()
print(long_to_bytes(int(re[0])))

运行得flag:NSSCTF{62e90a0e-c982-4a00-8ae9-eb493786a7d6}

P7

本题为短填充攻击,两组密文满足m_{2} = m_{1} +r,这是P4中a为1的特殊情况情况,所以套用P5的代码即可:

from Crypto.Util.number import *
from gmpy2 import *
c1 = 135074766579407676786282087896424573055829820741326911395660008092908906818293714163243721440579480398437184153110701014575949020137195005556115765711856362529093323957313305701439430406396620730435232669024347062255561124227077117736226705746520202121773331267896121082546807985584499775544186860738299210902
c2 = 52198561898892210533988782934627447441579509170862004216826284305082884787397969852570583444422705227177306845788090962326207704949679636373972262848806083888114511515323970306654941921527306928423850775839578728701294521014874290792581635297504014585143468088934951952990888189000603302912352199468290961647
r = 7226418134082605571805056000800553195029496658257912353583130240746954757224748488491991266548553899116384605868480860827154816241193159482670000874841821
n = 144690523587663809780722437199578577582544144694543134253077982812595463236242062416509866333774784681011350541203308061301675822157859373788530465702809816586981803008466959154241234879285863437666243631170277595720205934928759253610014553402523757331771549475265418644503305010214366648156173843801360148229
e = 9
PR.<x> = PolynomialRing(Zmod(n))
f1 = x^e - c1
f2 = (x + r)^e-c2
while f2 :
    f1, f2 = f2, f1%f2
    m = f1
m = m.monic().small_roots()
print(long_to_bytes(int(m[0])))

运行得flag:NSSCTF{539b7c07-fbe9-41e9-baca-0591020ca683}

P8

本题为已知明文高位攻击,那么我们可以得到一个关于明文低位的多项式:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        f(x) = ((m_{h}<<100)+x)^3 - c

由于明文地位只有100位,小于n^{\frac{1}{e}},所以可以用coppersmith求小根,求出f(x)的一个小根后就可以恢复明文,具体代码如下:

from Crypto.Util.number import *
n = 1527542955109141740955682973826193262775892499957309448026045241470857728195657663426381459817190647872750820593934305392986732687654051540838628636529717414135863605586498459487983117670942529496973140251670874510207985224170313618738268651184582186637089407746738836054395760157095709388670653150429457223183161697730087281761369404956762102465246289770300941300936135728738323821631682286737786472020790680432476428922187234364341215016265407571963282147129157
m = 2214226572250613833249705195927505959981823363137633354626532745196588970707
c = 22113876206623661468496987580282614626160320529328454393375952035910523390370709980915981609422504775420007441257006956611997263223244837790238493516238723139514158563675396731542096229586616735753203254810465452822757959264870210654015436735165961713016222816604825816304606749448517022584926571828009062411578367333

m_h = m<<100
PR.<x> = PolynomialRing(Zmod(n))
f = (x+m_h)^3 - c
m_l = f.small_roots()[0]
m_l = int(m_l)
m = m_l + m_h
print(long_to_bytes(m))

运行得flag:NSSCTF{688404a6-c408-4196-bc43-7f18317a9170} 

P9

本题为已知p高位攻击,此时我们要利用coppersmith的第二个作用,可以求解模数的因数的根。我们由多项式:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        p(x) \equiv x \mod(n)

而我们又知道p的高位,所以:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        p(x) \equiv p_{h} + x \mod (n)

这样我们就减小了多项式根的大小,这样就可以用coppersmith求解小根,即p的低位。要注意这种方法要求我们已知的信息要大于n^{\frac{9}{32}},对于此题我们已知的p高位满足这个条件,所以代码如下:

from Crypto.Util.number import *
n = 64335017257291288694879798080666629573501118113377179370850991421806469826103134483305987256497147128148330360834028920504233940886960965527818740354522230977284177508093687651712761343376265176857120577153061490788347779327206437787594150381508592990273475278503352979893670354730287704989079247190299342871
e = 65537
p = 7550547038897825994210519739007596111285476244196123253081036462313916767780871742001683690783926938603422562506786339392389
c = 63156227746402147833665215816432368072100003179308515827461336094419526246728847463629131014545663919689064970828884371592840335299717484415279040662500514230579275586231051576688620810169339105201465431624989678170362157914366609856305650090630980489686792938272599406165204410721499875713189193728688835223
p = p<<100
PR.<x> = PolynomialRing(Zmod(n))
f = p + x
p_low = f.small_roots(X=2^100, beta=0.4)[0]
p = int(p + p_low)
q = n//p
d = inverse(e, (p-1)*(q-1))
m = pow(c, d, n)
m = int(m)
print(long_to_bytes(m))

运行得flag:NSSCTF{36a5ae48-f281-4576-8d1f-acab0666bff2}

P10

此题为已知部分私钥攻击,我们知道:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ed \equiv 1 \mod (\phi(n))

即:

                ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​   ed = 1 + k\phi(p-1)(q-1)

我们假设已知d的低位d_{l}\alpha位,那么:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​ ed_{l} \equiv 1 + k(p-1)(q-1) \mod (2^{\alpha})

我们将q用\frac{n}{p}代替得:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ped_{l} \equiv p + k(p-1)(n-p) \mod (2^{\alpha})

由于k小于e,所以可以遍历k,然后求解上式关于p的解,这样我们就可以得到p的地位,然后按照P9的方法求出p的高位即可,具体代码如下:

from Crypto.Util.number import *
def find_p(p_low, bit, n):
    PR.<x> = PolynomialRing(Zmod(n))
    f = (2<<bit)*x + p_low
    f = f.monic()
    root = f.small_roots(X=2^(512-bit), beta=0.3)
    if root :
        return (2<<bit)*root[0] + p_low
n = 156739515226635581524592797610847324418529702729659760727202454324501479907596255649349406182566636617352761983459648380669151952249526892078378572831346100444943020314226860094300911303589453661009834514243241261318188779118227457185670049393331570167726982038500849886842419000632840251465852441285715712609
d = 1865327042408619801352057511348007441275330638921397637214779955824487081626289235627502761209800783644652914147540081431451
c = 72260884070910873253619893714557327479300651539617744913822595501549980223259020597000998829262506949824325397279990912888752157554696212466966682483623575703479116305560808218806054242135099446883072418808228726774129042552815016924170283352225826854235696829480360844745488070927932843928843556296485306121
bit = 410
e = 7
for k in range(1, e+1):
    X = var('X')
    re = solve_mod([e*d*X == X + k*(X-1)*(n-X)], 2<<bit)
    for x in re:
        p_low = int(x[0])
        p = find_p(p_low, bit, n)
        if p:
            break
p = int(p)
q = n//p
d = inverse(e, (p-1)*(q-1))
m = pow(c, d, n)
print(long_to_bytes(int(m)))

运行得flag:NSSCTF{e5430ded-500c-4cc0-9bdb-b4e40a9be3a0}

P11

本题与维纳攻击十分相似,但维纳攻击要求d<\frac{1}{3}n^{0.25},但此题的d为n^{0.27}不满足维纳攻击的条件,所以这里我们采取一种新的攻击方式:Boneh and Durfee Attack

我们有:

        ​​​​​​​        ​​​​​​​        ​​​​​​        ​​​​​​​           ed = 1 + k(p-1)(q-1)

两边同时模e得:

                            ​​​​​​​           1 + k(n - p - q + 1)\equiv 0 \mod (e)            

即:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​1 + 2k (\frac{n+1}{2} - \frac{p+q}{2}) \equiv 0\mod(e)

令x = k,y = -(p+q)/2 得二元多项式f(x, y):

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​    f(x, y) \equiv 1+2x(\frac{n+1}{2}+y) \mod(e)

而Boneh和Durfee给出了对这个方程存在解的上界的证明,当d < n^{0.272}时就可以找到解,具体代码如下:

from Crypto.Util.number import *

"""
Setting debug to true will display more informations
about the lattice, the bounds, the vectors...
"""
debug = False

"""
Setting strict to true will stop the algorithm (and
return (-1, -1)) if we don't have a correct
upperbound on the determinant. Note that this
doesn't necesseraly mean that no solutions
will be found since the theoretical upperbound is
usualy far away from actual results. That is why
you should probably use `strict = False`
"""
strict = False

"""
This is experimental, but has provided remarkable results
so far. It tries to reduce the lattice as much as it can
while keeping its efficiency. I see no reason not to use
this option, but if things don't work, you should try
disabling it
"""
helpful_only = True
dimension_min = 7  # stop removing if lattice reaches that dimension


############################################
# Functions
##########################################

# display stats on helpful vectors
def helpful_vectors(BB, modulus):
    nothelpful = 0
    for ii in range(BB.dimensions()[0]):
        if BB[ii, ii] >= modulus:
            nothelpful += 1

    print(nothelpful, "/", BB.dimensions()[0], " vectors are not helpful")


# display matrix picture with 0 and X
def matrix_overview(BB, bound):
    for ii in range(BB.dimensions()[0]):
        a = ('%02d ' % ii)
        for jj in range(BB.dimensions()[1]):
            a += '0' if BB[ii, jj] == 0 else 'X'
            if BB.dimensions()[0] < 60:
                a += ' '
        if BB[ii, ii] >= bound:
            a += '~'
        print(a)


# tries to remove unhelpful vectors
# we start at current = n-1 (last vector)
def remove_unhelpful(BB, monomials, bound, current):
    # end of our recursive function
    if current == -1 or BB.dimensions()[0] <= dimension_min:
        return BB

    # we start by checking from the end
    for ii in range(current, -1, -1):
        # if it is unhelpful:
        if BB[ii, ii] >= bound:
            affected_vectors = 0
            affected_vector_index = 0
            # let's check if it affects other vectors
            for jj in range(ii + 1, BB.dimensions()[0]):
                # if another vector is affected:
                # we increase the count
                if BB[jj, ii] != 0:
                    affected_vectors += 1
                    affected_vector_index = jj

            # level:0
            # if no other vectors end up affected
            # we remove it
            if affected_vectors == 0:
                # print("* removing unhelpful vector", ii)
                BB = BB.delete_columns([ii])
                BB = BB.delete_rows([ii])
                monomials.pop(ii)
                BB = remove_unhelpful(BB, monomials, bound, ii - 1)
                return BB

            # level:1
            # if just one was affected we check
            # if it is affecting someone else
            elif affected_vectors == 1:
                affected_deeper = True
                for kk in range(affected_vector_index + 1, BB.dimensions()[0]):
                    # if it is affecting even one vector
                    # we give up on this one
                    if BB[kk, affected_vector_index] != 0:
                        affected_deeper = False
                # remove both it if no other vector was affected and
                # this helpful vector is not helpful enough
                # compared to our unhelpful one
                if affected_deeper and abs(bound - BB[affected_vector_index, affected_vector_index]) < abs(
                        bound - BB[ii, ii]):
                    # print("* removing unhelpful vectors", ii, "and", affected_vector_index)
                    BB = BB.delete_columns([affected_vector_index, ii])
                    BB = BB.delete_rows([affected_vector_index, ii])
                    monomials.pop(affected_vector_index)
                    monomials.pop(ii)
                    BB = remove_unhelpful(BB, monomials, bound, ii - 1)
                    return BB
    # nothing happened
    return BB


""" 
Returns:
* 0,0   if it fails
* -1,-1 if `strict=true`, and determinant doesn't bound
* x0,y0 the solutions of `pol`
"""


def boneh_durfee(pol, modulus, mm, tt, XX, YY):
    """
    Boneh and Durfee revisited by Herrmann and May

    finds a solution if:
    * d < N^delta
    * |x| < e^delta
    * |y| < e^0.5
    whenever delta < 1 - sqrt(2)/2 ~ 0.292
    """

    # substitution (Herrman and May)
    PR.<u,x,y> = PolynomialRing(ZZ)
    Q = PR.quotient(x * y + 1 - u)  # u = xy + 1
    polZ = Q(pol).lift()

    UU = XX * YY + 1

    # x-shifts
    gg = []
    for kk in range(mm + 1):
        for ii in range(mm - kk + 1):
            xshift = x ^ ii * modulus ^ (mm - kk) * polZ(u, x, y) ^ kk
            gg.append(xshift)
    gg.sort()

    # x-shifts list of monomials
    monomials = []
    for polynomial in gg:
        for monomial in polynomial.monomials():
            if monomial not in monomials:
                monomials.append(monomial)
    monomials.sort()

    # y-shifts (selected by Herrman and May)
    for jj in range(1, tt + 1):
        for kk in range(floor(mm / tt) * jj, mm + 1):
            yshift = y ^ jj * polZ(u, x, y) ^ kk * modulus ^ (mm - kk)
            yshift = Q(yshift).lift()
            gg.append(yshift)  # substitution

    # y-shifts list of monomials
    for jj in range(1, tt + 1):
        for kk in range(floor(mm / tt) * jj, mm + 1):
            monomials.append(u ^ kk * y ^ jj)

    # construct lattice B
    nn = len(monomials)
    BB = Matrix(ZZ, nn)
    for ii in range(nn):
        BB[ii, 0] = gg[ii](0, 0, 0)
        for jj in range(1, ii + 1):
            if monomials[jj] in gg[ii].monomials():
                BB[ii, jj] = gg[ii].monomial_coefficient(monomials[jj]) * monomials[jj](UU, XX, YY)

    # Prototype to reduce the lattice
    if helpful_only:
        # automatically remove
        BB = remove_unhelpful(BB, monomials, modulus ^ mm, nn - 1)
        # reset dimension
        nn = BB.dimensions()[0]
        if nn == 0:
            print("failure")
            return 0, 0

    # check if vectors are helpful
    if debug:
        helpful_vectors(BB, modulus ^ mm)

    # check if determinant is correctly bounded
    det = BB.det()
    bound = modulus ^ (mm * nn)
    if det >= bound:
        # print("We do not have det < bound. Solutions might not be found.")
        # print("Try with highers m and t.")
        if debug:
            diff = (log(det) - log(bound)) / log(2)
            # print("size det(L) - size e^(m*n) = ", floor(diff))
        if strict:
            return -1, -1
    else:
        print("det(L) < e^(m*n) (good! If a solution exists < N^delta, it will be found)")

    # display the lattice basis
    if debug:
        matrix_overview(BB, modulus ^ mm)

    # LLL
    if debug:
        print("optimizing basis of the lattice via LLL, this can take a long time")

    BB = BB.LLL()

    if debug:
        print("LLL is done!")

    # transform vector i & j -> polynomials 1 & 2
    if debug:
        print("looking for independent vectors in the lattice")
    found_polynomials = False

    for pol1_idx in range(nn - 1):
        for pol2_idx in range(pol1_idx + 1, nn):
            # for i and j, create the two polynomials
            PR.<w,z> = PolynomialRing(ZZ)
            pol1 = pol2 = 0
            for jj in range(nn):
                pol1 += monomials[jj](w * z + 1, w, z) * BB[pol1_idx, jj] / monomials[jj](UU, XX, YY)
                pol2 += monomials[jj](w * z + 1, w, z) * BB[pol2_idx, jj] / monomials[jj](UU, XX, YY)

            # resultant
            PR.<q> = PolynomialRing(ZZ)
            rr = pol1.resultant(pol2)

            # are these good polynomials?
            if rr.is_zero() or rr.monomials() == [1]:
                continue
            else:
                # print("found them, using vectors", pol1_idx, "and", pol2_idx)
                found_polynomials = True
                break
        if found_polynomials:
            break

    if not found_polynomials:
        # print("no independant vectors could be found. This should very rarely happen...")
        return 0, 0

    rr = rr(q, q)

    # solutions
    soly = rr.roots()

    if len(soly) == 0:
        # print("Your prediction (delta) is too small")
        return 0, 0

    soly = soly[0][0]
    ss = pol1(q, soly)
    solx = ss.roots()[0][0]

    #
    return solx, soly
def attack(N, e, factor_bit_length, factors, delta=0.25, m=1):
    x, y = ZZ["x", "y"].gens()
    A = N + 1
    f = x * (A + y) + 1
    X = int(RR(e) ** delta)
    Y = int(2 ** ((factors - 1) * factor_bit_length + 1))
    t = int((1 - 2 * delta) * m)
    x0, y0 = boneh_durfee(f, e, m, t, X, Y)
    return f(x0, y0)//e

N = 160114502501162084436964583573537478796032975208003641998245321466054315024090626426576990670846673676284220472762005347545857048805279326218401844652650972020279579076862422448095751869541093396088035262462766840652498826036642824370917665518133929602675230369722990871966227199496065637730328810028624771799
e = 45345940569506069958442629331605385637541863502889625766318025882612322508079296362452308633027956256763871699363730475762179734871820426435674201573024637206928394192742633431788159554008858191365192772486379417021387095234660386008405855409257903024187126197769938866986740500855322639995703897171982472409
c = 54804574756729863920967159846060185937697266820658443964397350756668642051647933464063713653569896152539760694973280490768379727191709149635944250514794939902138783777815040318178431874892245462786377699958110644049375757179588739287406833915772871299296750059138805811112990483420256564588150314150915692126

d = attack(N, e, 512, 2, .271, 6)
m = pow(c, d, N)
print(long_to_bytes(int(m)))

这里m表示格的大小,尝试后发现,m为6最好,如果小了就无法解出,大了就要耗费更多时间。

运行得flag:NSSCTF{012ca572-455d-4d85-a362-d3f4bb2a7f15}

  • 39
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值