接下来学习一下RSA加密中比较简单的一部分,就是低加密指数攻击(或者也叫做小加密指数攻击),小加密指数攻击还算是比较简单的,比小私钥指数攻击简单不少,接下来就是RSA加密低加密指数攻击的一些相关内容。下面图片就是低加密指数攻击的相关内容,其中消息相关攻击单开一部分。
下面三个攻击都是使用小私钥指数潜在的危险。所以这些攻击都假设攻击者对被加密的明文具有一定的先验知识,并且只能恢复明文。这些攻击都无法恢复私钥指数,也无法对模数进行因数分解,因此这类攻击是对RSA加密的部分攻击,而不是完全攻击。
使用非常小的公钥指数可以显著降低加密的计算成本,比如e = 3 e=3 e = 3 ,在每次加密时只需要进行两次模乘运算,相比之下,使用一个完整大小的公钥指数大约需要3 2 l o g 2 ( N ) \frac{3}{2}log_2(N) 2 3 l o g 2 ( N ) 次模乘。
在RSA中使用小指数的思想大概在20世纪80年代就已经为人所知,甚至可能更早。最早公开指数小指数可以显著减低基于模指数运算的算法成本的文献,通常认为是Rabin在1979年发表的一篇论文。
在实际应用中,大多数RSA实例都会使用一个固定的小公钥指数,例如:e = 2 16 + 1 e=2^{16}+1 e = 2 1 6 + 1 也就是65537或者e = 3 e=3 e = 3 。
刻板消息攻击
注意 :为了使得在实际中有用,公钥指数必须足够小。原因主要有两点:
一旦e > l o g 2 ( N ) e>log_2(N) e > l o g 2 ( N ) ,该攻击就需要已知明文的所有比特,都知道所有明文比特了还干嘛要攻击
随着公钥指数e e e 的增大,攻击的计算成本迅速上升,因为Coppersmith方法中所使用的格的维度是e e e 的多项式函数。因此在常用的公钥指数e = 2 16 + 1 e=2^{16}+1 e = 2 1 6 + 1 这种情况下,这种攻击并不适用。
当使用正确的随机填充方案时,只要明文至少有1 e \frac{1}{e} e 1 的比特是随机的,该攻击也将不再有效。
题型1 极端情况
极端情况 题目1
1 2 flag= 25166751653530941364839663846806543387720865339263370907985655775152187319464715737116599171477207047430065345882626259880756839094179627032623895330242655333 n= 134109481482703713214838023035418052567000870587160796935708584694132507394211363652420160931185332280406437290210512090663977634730864032370977407179731940068634536079284528020739988665713200815021342700369922518406968356455736393738946128013973643235228327971170711979683931964854563904980669850660628561419
只给了n n n 和c c c ,连e e e 都不知道,只能边爆破边界面看看,e e e 不会太大(自然就是低加密指数了)
1 2 3 4 5 6 7 import gmpy2from Crypto.Util.number import *flag = n = for e in range (1 ,10 ): print (long_to_bytes(int (gmpy2.iroot(flag,e)[0 ])))
极端情况 题目2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 from Crypto.Util.number import *from Crypto.Util.Padding import *FLAG = bytes_to_long(pad(b"flag{??????}" ,64 )) def init_key (): p, q = getPrime(512 ), getPrime(512 ) n = p*q e = 9 while (GCD((p-1 )*(q-1 ),e)!=1 ): p, q = getPrime(512 ), getPrime(512 ) n = p*q d = inverse(e,(p-1 )*(q-1 )) return n,e,d n_list=list () c_list=list () for i in range (9 ): N,e,d=init_key() n_list.append(N) c=pow (FLAG,e,N) c_list.append(pow (FLAG,e,N)) assert (pow (c,d,N)==FLAG) print ("n_list:" ,n_list)print ("c_list:" ,c_list)""" n_list: [71189786319102608575263218254922479901008514616376166401353025325668690465852130559783959409002115897148828732231478529655075366072137059589917001875303598680931962384468363842379833044123189276199264340224973914079447846845897807085694711541719515881377391200011269924562049643835131619086349617062034608799, 92503831027754984321994282254005318198418454777812045042619263533423066848097985191386666241913483806726751133691867010696758828674382946375162423033994046273252417389169779506788545647848951018539441971140081528915876529645525880324658212147388232683347292192795975558548712504744297104487514691170935149949, 100993952830138414466948640139083231443558390127247779484027818354177479632421980458019929149817002579508423291678953554090956334137167905685261724759487245658147039684536216616744746196651390112540237050493468689520465897258378216693418610879245129435268327315158194612110422630337395790254881602124839071919, 59138293747457431012165762343997972673625934330232909935732464725128776212729547237438509546925172847581735769773563840639187946741161318153031173864953372796950422229629824699580131369991913883136821374596762214064774480548532035315344368010507644630655604478651898097886873485265848973185431559958627423847, 66827868958054485359731420968595906328820823695638132426084478524423658597714990545142120448668257273436546456116147999073797943388584861050133103137697812149742551913704341990467090049650721713913812069904136198912314243175309387952328961054617877059134151915723594900209641163321839502908705301293546584147, 120940513339890268554625391482989102665030083707530690312336379356969219966820079510946652021721814016286307318930536030308296265425674637215009052078834615196224917417698019787514831973471113022781129000531459800329018133248426080717653298100515701379374786486337920294380753805825328119757649844054966712377, 72186594495190221129349814154999705524005203343018940547856004977368023856950836974465616291478257156860734574686154136925776069045232149725101769594505766718123155028300703627531567850035682448632166309129911061492630709698934310123778699316856399909549674138453085885820110724923723830686564968967391721281, 69105037583161467265649176715175579387938714721653281201847973223975467813529036844308693237404592381480367515044829190066606146105800243199497182114398931410844901178842049915914390117503986044951461783780327749665912369177733246873697481544777183820939967036346862056795919812693669387731294595126647751951, 76194219445824867986050004226602973283400885106636660263597964027139613163638212828932901192009131346530898961165310615466747046710743013409318156266326090650584190382130795884514074647833949281109675170830565650006906028402714868781834693473191228256626654011772428115359653448111208831188721505467497494581] c_list: [62580922178008480377006528793506649089253164524883696044759651305970802215270721223149734532870729533611357047595181907404222690394917605617029675103788705320032707977225447998111744887898039756375876685711148857676502670812333076878964148863713993853526715855758799502735753454247721711366497722251078739585, 46186240819076690248235492196228128599822002268014359444368898414937734806009161030424589993541799877081745454934484263188270879142125136786221625234555265815513136730416539407710862948861531339065039071959576035606192732936477944770308784472646015244527805057990939765708793705044236665364664490419874206900, 85756449024868529058704599481168414715291172247059370174556127800630896693021701121075838517372920466708826412897794900729896389468152213884232173410022054605870785910461728567377769960823103334874807744107855490558726013068890632637193410610478514663078901021307258078678427928255699031215654693270240640198, 14388767329946097216670270960679686032536707277732968784379505904021622612991917314721678940833050736745004078559116326396233622519356703639737886289595860359630019239654690312132039876082685046329079266785042428947147658321799501605837784127004536996628492065409017175037161261039765340032473048737319069656, 1143736792108232890306863524988028098730927600066491485326214420279375304665896453544100447027809433141790331191324806205845009336228331138326163746853197990596700523328423791764843694671580875538251166864957646807184041817863314204516355683663859246677105132100377322669627893863885482167305919925159944839, 2978800921927631161807562509445310353414810029862911925227583943849942080514132963605492727604495513988707849133045851539412276254555228149742924149242124724864770049898278052042163392380895275970574317984638058768854065506927848951716677514095183559625442889028813635385408810698294574175092159389388091981, 16200944263352278316040095503540249310705602580329203494665614035841657418101517016718103326928336623132935178377208651067093136976383774189554806135146237406248538919915426183225265103769259990252162411307338473817114996409705345401251435268136647166395894099897737607312110866874944619080871831772376466376, 31551601425575677138046998360378916515711528548963089502535903329268089950335615563205720969393649713416910860593823506545030969355111753902391336139384464585775439245735448030993755229554555004154084649002801255396359097917380427525820249562148313977941413268787799534165652742114031759562268691233834820996, 25288164985739570635307839193110091356864302148147148153228604718807817833935053919412276187989509493755136905193728864674684139319708358686431424793278248263545370628718355096523088238513079652226028236137381367215156975121794485995030822902933639803569133458328681148758392333073624280222354763268512333515]\ """
这题很显然就是一个CRT+极端情况的一类题型,首先我们之间使用CRT解出如下同余方程组,此时m 9 < n 1 . . . n i m^{9}< n_1...n_i m 9 < n 1 . . . n i ,直接对m 9 m^{9} m 9 开根即可。
{ m 9 ≡ c 1 m o d ( n 1 ) m 9 ≡ c 2 m o d ( n 2 ) . . . m 9 ≡ c i m o d ( n i ) ⇒ m 9 ≡ C m o d ( n 1 ∗ . . . ∗ n i ) \begin{cases}
m^{9}\equiv c_1~mod(~n_1)\\
m^{9}\equiv c_2~mod(~n_2)\\
...\\
m^{9}\equiv c_i~mod(~n_i)
\end{cases}\Rightarrow m^{9}\equiv C~mod(~n_1*...*n_i)
⎩ ⎪ ⎪ ⎪ ⎪ ⎨ ⎪ ⎪ ⎪ ⎪ ⎧ m 9 ≡ c 1 m o d ( n 1 ) m 9 ≡ c 2 m o d ( n 2 ) . . . m 9 ≡ c i m o d ( n i ) ⇒ m 9 ≡ C m o d ( n 1 ∗ . . . ∗ n i )
1 2 3 4 5 6 7 8 9 10 11 import gmpy2from Crypto.Util.number import *n_list= c_list= e = 9 x = CRT(c_list,n_list) print (x)m = gmpy2.iroot(x,9 )[0 ] flag = long_to_bytes(int (m)) print (flag)
题型2 刻板消息
刻板消息 题目1
刻板消息 题目2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 from Crypto.Util.number import *from secret import flagm = bytes_to_long(flag) assert m.bit_length()<200 p = getPrime(512 ) q = getPrime(512 ) n = p*q e = 3 c = pow (m, e, n) kbits = 103 m = (m >> kbits) << kbits Mod = getPrime(1024 ) hint1 = (2021 -2023 *m) % Mod hint2 = pow (2 , 2023 , Mod) print ('n =' ,n)print ('c =' ,c)print ('hint1 =' ,hint1)print ('hint2 =' ,hint2)''' n = 115383855234466224643769657979808398804254899116842846340552518876890834212233960206021018541117724144757264778086129841154749234706140951832603640953383528482125663673926452745186670807057426128028379664506531814550204605131476026038420737951652389070818761739123318769460392218629003518050621137961009397857 c = 5329266956476837379347536739209778690886367516092584944314921220156032648621405214333809779485753073093853063734538746101929825083615077 hint1 = 153580531261794088318480897414037573794615852052189508424770502825730438732573547598712417272036492121110446656514226232815820756435437665617271385368704576530324067841094570337328191161458300549179813432377043779779861066187597784486306748688798924645894867137996446960685210314180286437706545416961668988800 hint2 = 130939024886341321687705945538053996302793777331032277314813607352533647251650781154105954418698306293933779129141987945896277615656019480762879716136830059777341204876905094451068416223212748354774066124134473710638395595420261557771680485834288346221266495706392714094862310009374032975169649227238004805982 '''
h 1 ≡ ( 2021 − 2023 ∗ m ) m o d ( r ) h 2 ≡ 2 2023 m o d ( r ) \begin{array}{l}
h_1\equiv(2021-2023*m)~mod(~r)\\
h_2\equiv2^{2023}~mod(~r)
\end{array}
h 1 ≡ ( 2 0 2 1 − 2 0 2 3 ∗ m ) m o d ( r ) h 2 ≡ 2 2 0 2 3 m o d ( r )
使用模多项式的Coppersmith攻击的话需要两个必要的东西:其中一个就是方程,另一个是模数N N N ,这个模数要满足r ∣ N r|N r ∣ N 。根据h 2 h_2 h 2 ,我们可以得到模数N N N ,如下所示:
2 2023 − h 2 ≡ 0 m o d ( r ) 2^{2023}-h_2\equiv 0~mod(~r)
2 2 0 2 3 − h 2 ≡ 0 m o d ( r )
现在我们就需要通过h 1 h_1 h 1 去构造方程,所构造的方程就可以得到如下所示的方程:
2023 ∗ m + h 1 − 2021 ≡ 0 m o d ( r ) 2023*m+h_1-2021\equiv0~mod(~r)
2 0 2 3 ∗ m + h 1 − 2 0 2 1 ≡ 0 m o d ( r )
接下来我们就可以构造如下的方程使用Coppersmith攻击去求得m m m :
2023 ∗ m + h 1 − 2021 ≡ 0 m o d ( 2 2023 − h 2 ) 2023*m+h_1-2021\equiv0~mod(~2^{2023}-h_2)
2 0 2 3 ∗ m + h 1 − 2 0 2 1 ≡ 0 m o d ( 2 2 0 2 3 − h 2 )
接下来就是比较常见的刻板消息使用Coppersmith攻击求解明文m的低位,构造方程:
c − ( m + x ) 3 ≡ 0 m o d ( n ) c-(m+x)^{3}\equiv 0~mod(~n)
c − ( m + x ) 3 ≡ 0 m o d ( n )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 from Crypto.Util.number import *n = c = hint1 = hint2 = kp = pow (2 ,2023 ) - hint2 PR.<x> = PolynomialRing(Zmod(kp)) f = hint1 - 2021 + 2023 * x f = f.monic() result = f.small_roots(X=2 ^200 ,beta=0.5 ) print (result)m = 1746716778150027565782467891299010283212636160 print (long_to_bytes(m))P.<y> = PolynomialRing(Zmod(n)) g = c - (m+y)^3 g = g.monic() result2 = g.small_roots(X=2 ^200 ,beta=0.5 ) print (result2)flag = m+9770564320547953144707390074493 print (long_to_bytes(flag))""" [1746716778150027565782467891299010283212636160] b'NSSCTF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' [9770564320547953144707390074493] b'NSSCTF{Rea1_Si9n3n}' """
刻板消息 题目3
题目来源:XYCTF2025 Complex_signin
题目附件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 from Crypto.Util.number import *from Crypto.Cipher import ChaCha20import hashlibfrom secret import flagclass Complex : def __init__ (self, re, im ): self.re = re self.im = im def __mul__ (self, c ): re_ = self.re * c.re - self.im * c.im im_ = self.re * c.im + self.im * c.re return Complex(re_, im_) def __eq__ (self, c ): return self.re == c.re and self.im == c.im def __rshift__ (self, m ): return Complex(self.re >> m, self.im >> m) def __lshift__ (self, m ): return Complex(self.re << m, self.im << m) def __str__ (self ): if self.im == 0 : return str (self.re) elif self.re == 0 : if abs (self.im) == 1 : return f"{'-' if self.im < 0 else '' } i" else : return f"{self.im} i" else : return f"{self.re} {'+' if self.im > 0 else '-' } {abs (self.im)} i" def tolist (self ): return [self.re, self.im] def complex_pow (c, exp, n ): result = Complex(1 , 0 ) while exp > 0 : if exp & 1 : result = result * c result.re = result.re % n result.im = result.im % n c = c * c c.re = c.re % n c.im = c.im % n exp >>= 1 return result bits = 128 p = getPrime(1024 ) q = getPrime(1024 ) n = p * q m = Complex(getRandomRange(1 , n), getRandomRange(1 , n)) e = 3 c = complex_pow(m, e, n) print (f"n = {n} " )print (f"mh = {(m >> bits << bits).tolist()} " )print (f"C = {c.tolist()} " )print (f"enc = {ChaCha20.new(key=hashlib.sha256(str (m.re + m.im).encode()).digest(), nonce=b'Pr3d1ctmyxjj' ).encrypt(flag)} " )''' n = 24240993137357567658677097076762157882987659874601064738608971893024559525024581362454897599976003248892339463673241756118600994494150721789525924054960470762499808771760690211841936903839232109208099640507210141111314563007924046946402216384360405445595854947145800754365717704762310092558089455516189533635318084532202438477871458797287721022389909953190113597425964395222426700352859740293834121123138183367554858896124509695602915312917886769066254219381427385100688110915129283949340133524365403188753735534290512113201932620106585043122707355381551006014647469884010069878477179147719913280272028376706421104753 mh = [3960604425233637243960750976884707892473356737965752732899783806146911898367312949419828751012380013933993271701949681295313483782313836179989146607655230162315784541236731368582965456428944524621026385297377746108440938677401125816586119588080150103855075450874206012903009942468340296995700270449643148025957527925452034647677446705198250167222150181312718642480834399766134519333316989347221448685711220842032010517045985044813674426104295710015607450682205211098779229647334749706043180512861889295899050427257721209370423421046811102682648967375219936664246584194224745761842962418864084904820764122207293014016, 15053801146135239412812153100772352976861411085516247673065559201085791622602365389885455357620354025972053252939439247746724492130435830816513505615952791448705492885525709421224584364037704802923497222819113629874137050874966691886390837364018702981146413066712287361010611405028353728676772998972695270707666289161746024725705731676511793934556785324668045957177856807914741189938780850108643929261692799397326838812262009873072175627051209104209229233754715491428364039564130435227582042666464866336424773552304555244949976525797616679252470574006820212465924134763386213550360175810288209936288398862565142167552] C = [5300743174999795329371527870190100703154639960450575575101738225528814331152637733729613419201898994386548816504858409726318742419169717222702404409496156167283354163362729304279553214510160589336672463972767842604886866159600567533436626931810981418193227593758688610512556391129176234307448758534506432755113432411099690991453452199653214054901093242337700880661006486138424743085527911347931571730473582051987520447237586885119205422668971876488684708196255266536680083835972668749902212285032756286424244284136941767752754078598830317271949981378674176685159516777247305970365843616105513456452993199192823148760, 21112179095014976702043514329117175747825140730885731533311755299178008997398851800028751416090265195760178867626233456642594578588007570838933135396672730765007160135908314028300141127837769297682479678972455077606519053977383739500664851033908924293990399261838079993207621314584108891814038236135637105408310569002463379136544773406496600396931819980400197333039720344346032547489037834427091233045574086625061748398991041014394602237400713218611015436866842699640680804906008370869021545517947588322083793581852529192500912579560094015867120212711242523672548392160514345774299568940390940653232489808850407256752] enc = b'\x9c\xc4n\x8dF\xd9\x9e\xf4\x05\x82!\xde\xfe\x012$\xd0\x8c\xaf\xfb\rEb(\x04)\xa1\xa6\xbaI2J\xd2\xb2\x898\x11\xe6x\xa9\x19\x00pn\xf6rs- \xd2\xd1\xbe\xc7\xf51.\xd4\xd2 \xe7\xc6\xca\xe5\x19\xbe' '''
此题同样有两种做法,第一种就是二元Coppersmith攻击,第二种是使用结式消元将二元多项式转换成一元多项式然后打一元Coppersmith攻击。
附件中实现了复数域上的RSA加密。在附件的代码中,我们能看到一个复数类,这个类里面的属性有re(实部)、im(虚部),然后还有几个方法:
def __mul__即两个复数相乘运算,运算结果如下:
设x = a 1 + b 1 i x = a_1 + b_1i x = a 1 + b 1 i ,设y = a 2 + b 2 i y= a_2+b_2i y = a 2 + b 2 i
则两个复数相乘的结果为x ∗ y = a 1 ∗ a 2 − b 1 ∗ b 2 + ( a 1 ∗ b 2 + a 2 ∗ b 1 ) i x*y = a_1*a_2-b_1*b_2+(a_1*b_2+a_2*b_1)i x ∗ y = a 1 ∗ a 2 − b 1 ∗ b 2 + ( a 1 ∗ b 2 + a 2 ∗ b 1 ) i
def __eq__,这个方法定义了判断两个复数是否相等。
def __rshift__(self, m)、def __rshift__(self, m)这两个定义了复数域上的位移操作,左移或者右移m位就相当于将实部和虚部都左移或者右移m位。
def __str__,返回的就是这个复数的字符表达形式。
def tolist,获取这个复数类的实部和虚部。
程序中还有一个函数def complex_pow,实现的就是复数域上的模幂运算。
接下来我们查看加密过程,与正常RSA加密没差,先是生成n,然后这里m即明文是复数,并且实部和虚部都是随机生成的一个整数。
1 2 3 4 5 6 7 8 9 10 11 12 bits = 128 p = getPrime(1024 ) q = getPrime(1024 ) n = p * q m = Complex(getRandomRange(1 , n), getRandomRange(1 , n)) e = 3 c = complex_pow(m, e, n) print (f"n = {n} " )print (f"mh = {(m >> bits << bits).tolist()} " )print (f"C = {c.tolist()} " )print (f"enc = {ChaCha20.new(key=hashlib.sha256(str (m.re + m.im).encode()).digest(), nonce=b'Pr3d1ctmyxjj' ).encrypt(flag)} " )
然后我们对m进行rsa加密,加密过程c ≡ m 3 m o d ( n ) c \equiv m^3~mod~(n) c ≡ m 3 m o d ( n ) ,很显然是一个低指数加密,并且之后我们的m还泄露了高位。这时我们就会想到需要使用coppersmith攻击。但是这与我们之前做的一元coppersmith攻击不同。我们先将方程列好。
设m = a + b i m = a+bi m = a + b i ,则有如下式子:
c ≡ m 3 m o d ( n ) c ≡ ( a + b i ) 3 m o d ( n ) c ≡ a 3 − 3 a b 2 + ( 3 a 2 b − b 3 ) i m o d ( n ) \begin{array}{l}
c \equiv m^3~mod(n)
\\c \equiv (a+bi)^3~mod(n)
\\c \equiv a^3-3ab^2+(3a^2b-b^3)i~mod(n)
\end{array}
c ≡ m 3 m o d ( n ) c ≡ ( a + b i ) 3 m o d ( n ) c ≡ a 3 − 3 a b 2 + ( 3 a 2 b − b 3 ) i m o d ( n )
这时我们再设a = a h + x , b = b h + y a = a_h+x,~~~b=b_h+y a = a h + x , b = b h + y ,带入上面的式子就会得到:
c ≡ ( a h + x ) 3 − 3 ( a h + x ) ( b h + y ) 2 + [ 3 ( a h + x ) 2 ( b h + y ) − ( b h + y ) 3 m o d ( n ) c \equiv (a_h+x)^3-3(a_h+x)(b_h+y)^2+[3(a_h+x)^2(b_h+y)-(b_h+y)^3~mod(n)
c ≡ ( a h + x ) 3 − 3 ( a h + x ) ( b h + y ) 2 + [ 3 ( a h + x ) 2 ( b h + y ) − ( b h + y ) 3 m o d ( n )
0 ≡ ( a h + x ) 3 − 3 ( a h + x ) ( b h + y ) 2 − c 1 m o d ( n ) 0 ≡ 3 ( a h + x ) 2 ( b h + y ) − ( b h + y ) 3 − c 2 m o d ( n ) 记 f 1 = ( a h + x ) 3 − 3 ( a h + x ) ( b h + y ) 2 − c 1 m o d ( n ) 记 f 2 = 3 ( a h + x ) 2 ( b h + y ) − ( b h + y ) 3 − c 2 m o d ( n ) 0 \equiv (a_h+x)^3-3(a_h+x)(b_h+y)^2-c_1~mod(n)
\\0 \equiv 3(a_h+x)^2(b_h+y)-(b_h+y)^3-c_2~mod(n)
\\记f_1 = (a_h+x)^3-3(a_h+x)(b_h+y)^2-c_1~mod(n)
\\记f_2 = 3(a_h+x)^2(b_h+y)-(b_h+y)^3-c_2~mod(n)
0 ≡ ( a h + x ) 3 − 3 ( a h + x ) ( b h + y ) 2 − c 1 m o d ( n ) 0 ≡ 3 ( a h + x ) 2 ( b h + y ) − ( b h + y ) 3 − c 2 m o d ( n ) 记 f 1 = ( a h + x ) 3 − 3 ( a h + x ) ( b h + y ) 2 − c 1 m o d ( n ) 记 f 2 = 3 ( a h + x ) 2 ( b h + y ) − ( b h + y ) 3 − c 2 m o d ( n )
这时我们就列出了一个coppersmith求解形式的方程,但是这时我们会发现这里面有俩个未知数,所以显而易见,可以尝试使用二元coppersmith攻击。网上有现成的脚本可以使用。(不懂原理,只会当脚本小子)。这边有俩个方程式,经过尝试,我们可以通过f1这个方程式求出x和y,或者通过f1-f2这个方程式求出x和y,但是使用f2这个方程式并不能解出x和y
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 import itertoolsdef small_roots2 (f, bounds, m=1 , d=None ): if not d: d = f.degree() R = f.base_ring() N = R.cardinality() f /= f.coefficients().pop(0 ) f = f.change_ring(ZZ) G = Sequence ([], f.parent()) for i in range (m + 1 ): base = N ^ (m - i) * f ^ i for shifts in itertools.product(range (d), repeat=f.nvariables()): g = base * prod(map (power, f.variables(), shifts)) G.append(g) B, monomials = G.coefficient_matrix() monomials = vector(monomials) factors = [monomial(*bounds) for monomial in monomials] for i, factor in enumerate (factors): B.rescale_col(i, factor) B = B.dense_matrix().LLL() B = B.change_ring(QQ) for i, factor in enumerate (factors): B.rescale_col(i, 1 / factor) H = Sequence ([], f.parent().change_ring(QQ)) for h in filter (None , B * monomials): H.append(h) I = H.ideal() if I.dimension() == -1 : H.pop() elif I.dimension() == 0 : roots = [] for root in I.variety(ring=ZZ): root = tuple (R(root[var]) for var in f.variables()) roots.append(root) return roots return [] mh = n = C = PR.<x,y> = PolynomialRing(Zmod(n)) f1 = (mh[0 ]+x)^3 - 3 *(mh[0 ]+x)*(mh[1 ]+y)^2 - C[0 ] f2 = 3 *(mh[1 ]+y)*(mh[0 ]+x)^2 - (mh[1 ]+y)^3 - C[1 ] x,y = small_roots2(f1,[2 ^128 ,2 ^128 ],4 ,d=3 )[0 ] print (x)print (y)m1 = x + mh[0 ] m2 = y + mh[1 ] enc = b'\x9c\xc4n\x8dF\xd9\x9e\xf4\x05\x82!\xde\xfe\x012$\xd0\x8c\xaf\xfb\rEb(\x04)\xa1\xa6\xbaI2J\xd2\xb2\x898\x11\xe6x\xa9\x19\x00pn\xf6rs- \xd2\xd1\xbe\xc7\xf51.\xd4\xd2 \xe7\xc6\xca\xe5\x19\xbe' from Crypto.Cipher import ChaCha20import hashlibprint (ChaCha20.new(key=hashlib.sha256(str (m1 + m2).encode()).digest(), nonce=b'Pr3d1ctmyxjj' ).decrypt(enc))
接下来再提供一种结式消元的做法,其中结式这个概念在高等代数中会学习到。(等学到了再补充,先鸽一下)
随机填充攻击
泄露信息
当使用较小的公钥指数,私钥指数的某些信息可能会被泄露。Boneh、Durfee和Frankel观察到,如果已知密钥等式中的常数k,就会泄露关于私钥指数最高 有效位的信息
e d = 1 + k ϕ ( N ) ed=1+k\phi(N)
e d = 1 + k ϕ ( N )
该结论的定理如下,记该定理为定理4.6,定理内容如下:
设( e , N ) (e,N) ( e , N ) 是有效的RSA公钥,设( d , p , q ) (d,p,q) ( d , p , q ) 是相对应的私钥,则有密钥等式e d = 1 + k ϕ ( N ) ed=1+k\phi(N) e d = 1 + k ϕ ( N ) ,k k k 是正整数。
我们可以这样计算d 1 d_1 d 1 ,∣ d 1 − d ∣ < p + q |d_1-d|<p+q ∣ d 1 − d ∣ < p + q ,可以在关于l o g ( N ) log(N) l o g ( N ) 的多项式时间内计算出来
证明:
有公钥( e , N ) (e,N) ( e , N ) 和k k k ,我们计算出d 1 = ⌈ 1 + k N e ⌋ d_1=\lceil\frac{1+kN}{e}\rfloor d 1 = ⌈ e 1 + k N ⌋ 。
因此d 1 = 1 + ( k N ) e + α d_1=\frac{1+(kN)}{e}+\alpha d 1 = e 1 + ( k N ) + α ,其中∣ α ∣ < 1 |\alpha|<1 ∣ α ∣ < 1
重新回顾密钥等式,将其写成e d = 1 + k ( N − s ) ed=1+k(N-s) e d = 1 + k ( N − s )
这样就有$$|d_1-d|=|\frac{1+kN}{e}+\alpha-\frac{1+k(N-s)}{e}|=|\frac{ks}{e}+\alpha|<s+1=p+q$$
当k < e , s = p + q − 1 k<e,s=p+q-1 k < e , s = p + q − 1 ,计算出d 1 d_1 d 1 能在关于l o g ( N ) log(N) l o g ( N ) 的多项式时间内算出。
进而可以得出如下结论:
对于平衡素数RSA这种情况来说,素数之和满足p + q > 3 2 N 1 2 p+q>\frac{3}{2}N^{\frac{1}{2}} p + q > 2 3 N 2 1 。因此给定公钥和常数k k k 的情况下,我们可以计算出一个d 1 d_1 d 1 ,使得∣ d 1 − d ∣ < 3 2 N 1 2 |d_1-d|<\frac{3}{2}N^{\frac{1}{2}} ∣ d 1 − d ∣ < 2 3 N 2 1
也就是说,当k k k 已知时,我们实际上掌握了私钥指数d d d 的大约一半最高有效位。
反过来,也比较容易证明当已知私钥指数的最高有效位会泄露关于常数k k k 的信息,这一点会在部分私钥泄露攻击中被利用。
当公钥指数足够小时,由于k < e k<e k < e ,可以通过穷举法直接猜测k k k 。
一般来说还需要一种机制来验证猜测,从而确定k k k 的正确值。然而,在极端情况下,当e = 3 e=3 e = 3 时,可以证明k = 2 k=2 k = 2 。这一观察最早由Boneh提出,并在下面的4.7中被形式化表达。
接下来介绍一下定理4.7,定理内容如下:
设N = p q N=pq N = p q 是有效的RSA模数,其中p , q > 3 p,q>3 p , q > 3 ,并设( e , N ) (e,N) ( e , N ) 是有效的RSA公钥。如果e = 3 e=3 e = 3 ,密钥等式e d = 1 + k ϕ ( N ) ed=1+k\phi(N) e d = 1 + k ϕ ( N ) 的常数满足k = 2 k=2 k = 2
证明如下:
从密钥等式中我们知道0 < k < e 0<k<e 0 < k < e ,由于e = 3 e=3 e = 3 是一个有效的RSA公钥指数。
还已知g c d ( 3 , p − 1 ) = 1 gcd(3,p-1)=1 g c d ( 3 , p − 1 ) = 1 ,因此p − 1 ≢ 0 m o d ( 3 ) p-1\not\equiv 0~mod(~3) p − 1 ≡ 0 m o d ( 3 ) ,从而得到p > 3 p>3 p > 3
还知道g c d ( 3 , p ) = 1 gcd(3,p)=1 g c d ( 3 , p ) = 1 ,因此p − 1 ≢ 2 m o d ( 3 ) p-1\not\equiv 2~mod(~3) p − 1 ≡ 2 m o d ( 3 )
同理可以得到q − 1 ≡ m o d ( 3 ) q-1\equiv~mod(~3) q − 1 ≡ m o d ( 3 )
因此就有ϕ ( N ) = ( p − 1 ) ( q − 1 ) ≡ 1 m o d ( 3 ) \phi(N)=(p-1)(q-1)\equiv1~mod(~3) ϕ ( N ) = ( p − 1 ) ( q − 1 ) ≡ 1 m o d ( 3 )
那么就有3 d = 1 + k ϕ ( N ) m o d ( 3 ) 3d=1+k\phi(N)~mod (~3) 3 d = 1 + k ϕ ( N ) m o d ( 3 ) ,可以得到k ≡ − 1 ≡ 2 m o d ( 3 ) k\equiv -1 \equiv 2~mod(~3) k ≡ − 1 ≡ 2 m o d ( 3 ) ,又因为0 < k < 3 0<k<3 0 < k < 3
从而得到k = 2 k=2 k = 2
因此,当公钥指数e = 3 e=3 e = 3 时,私钥指数有大约一半的最高有效位总是会被泄露。尽管这似乎表明使用公钥指数e = 3 e=3 e = 3 的RSA可能是不安全的,但目前并不存在一种攻击,能够在没有额外信息的情况下,仅利用这一性质来攻破RSA。
此外,正如Boneh、Durfee和Frankel在论文所讲到的那样,如果存在一种算法,在公钥指数较小的情况下,能够在已知私钥指数最高有效位一半的前提下分解模数,那么该算法就可以被用作任意RSA模数的通用分解算法了。
设这样一种运算的运行时间为T T T 。对于任意RSA模数N N N ,令z z z 为不整除ϕ ( N ) \phi(N) ϕ ( N ) 的最小素数,则( z , N ) (z,N) ( z , N ) 构成模数N N N 的一个合法公钥。根据定理4.6,我们可以通过对所有满足k < z k<z k < z 的候选值进行尝试,计算出对应私钥指数最高有效位的大约一半。正确的候选值能够使我们得到私钥指数的一半最高有效位,从而进一步分解该模数。
由于z z z 是未知的,我们需要一次测试每一个奇素数,并对每个素数枚举其对应的所有k k k 候选值,知道找到k k k 为止。被测试的候选数量被z 2 z^2 z 2 所界定,因此该通用分解算法的总体运行时间最多为z 2 T z^{2}T z 2 T 。对于随机选取的RSA素数,通常认为z z z 不会很大,因此在高概率意义下,其运行时间将主要由T T T 所主导。