教科书式RSA方案面临的攻击及防御措施

教科书式RSA方案面临的攻击及防御措施

感谢橘子杀手学长写的博客,这是本篇文章主要的参考,感谢所有写博客分享自己技术的人
https://www.tr0y.wang/2017/11/06/CTFRSA/index.html

欢迎关注本人的博客
www.xuanworld.top

关于RSA的介绍

RSA的加密过程:

  1. 选择一对不相等且足够大的质数,列如:选z1和z2为较大的两个质数
  2. 计算z1和z2的乘积,n=z1*z2
  3. 计算n的欧拉函数 ϕ ( n ) = ( z 1 − 1 ) ∗ ( z 2 − 1 ) \phi(n)=(z1-1)*(z2-1) ϕ(n)=(z11)(z21)
  4. 选一个与 ϕ ( n ) \phi(n) ϕ(n)互质的整数e,且 e < ϕ ( n ) e<\phi(n) e<ϕ(n)
  5. 算出e对于 ϕ ( n ) \phi(n) ϕ(n)的模反元素d
  6. 公钥:KU=(e,n),e和n是成对的,共同组成公钥
  7. 私钥:KR=(d,n),同上

RSA的使用方法:

明文M加密: M e   m o d   n = C M^e \ mod \ n=C Me mod n=C

密文C解密: C d   m o d   n = M C^d \ mod \ n=M Cd mod n=M

攻击方法一:直接分解攻击

介绍

这种方式其实有点类似于暴力攻击了,因为我们知道RSA的安全性就是来自大素数乘积分解的困难性,如果n比较小的话,我们可以通过暴力穷举的方式进行攻击,也就是把小于n的这些素数都试一遍,但如果n比较大的话这种方法就十分困难了,有时需要用服务器运行上好几天也不一定能得到结果。在此我们推荐一个网站可以在线分解

http://factordb.com/

这个就相当于我们破解md5的方式是一样的,其实就是我们把之前破解好的一些密码给储存起来放到一个数据库中,然后我们逆向时直接查询就好。

举例

n=1062789633774349417938788353001516763303743389381120380522262327123099728631034935663418832664265833959487018276693680850987382421521055508477988016246558095545925414048663082368488342633334571240563

然后我们通过网站进行分解后就可以得到结果
在这里插入图片描述

防御的方法

这种情况下其实只需要把n给弄的特别大就可以了,一般来说2048bit的n就会被认为是特别安全的,现在一般公钥都是用4096bit的这种情况发下其实很难进行分解

攻击方法二:利用公约数分解n

介绍

如果我们得到了n1和n2,而且n1和n2拥有两个相同的因子的话,我们就可以使用这种攻击方式来进行一个计算。

计算方法很简单,我们可以使用欧几里得gcd算法来直接计算n1和n2的最大公约数。欧几里得算法的复杂度是log n,复杂度是比较低的,因而计算较快,所以这是一种比较高效的计算方法。

举例

我们给出一个欧几里得gcd的算法

n1 = 9051013965404084482870087864821455535159008696042953021965631089095795348830954383127323853272528967729311045179605407693592665683311660581204886571146327720288455874927281128121117323579691204792399913106627543274457036172455814805715668293705603675386878220947722186914112990452722174363713630297685159669328951520891938403452797650685849523658191947411429068829734053745180460758604283051344339641429819373112365211739216160420494167071996438506850526168389386850499796102003625404245645796271690310748804327
n2 = 13225948396179603816062046418717214792668512413625091569997524364243995991961018894150059207824093837420451375240550310050209398964506318518991620142575926623780411532257230701985821629425722030608722035570690474171259238153947095310303522831971664666067542649034461621725656234869005501293423975184701929729170077280251436216167293058560030089006140224375425679571181787206982712477261432579537981278055755344573767076951793312062480275004564657590263719816033564139497109942073701755011873153205366238585665743

结果

1564859779720039565508870182569324208117555667917997801104862601098933699462849007879184203051278194180664616470669559575370868384820368930104560074538872199213236203822337186927275879139590248731148622362880471439310489228147093224418374555428793546002109

代码

def Euclidean_gcd(a: int, b: int):
    param_big = a
    param_small = b
    if b > a:
        param_big = b
        param_small = a
    c = param_small
    while param_small:
        c = param_big % param_small
        param_big = param_small
        param_small = c
    return param_big

把两个n丢进去就可以了

防御方法

这种情况其实是比较罕见的,我们一般很少会出现拥有公约数的情况,事实上避免这种攻击的方法也十分的简单,我们选的n较大

然后使用程序自动生成一个n,这种情况下出现又有公约数的概率微乎其微。

攻击方法三:共模攻击

介绍

如果我们使用了相同的模数对一段相同的密文进行了加密,我们就能通过共模攻击还原出明文m的值,当然这种情况是不需要分解m的。我们先讲解一下基本的原理。

首先我们通过相同的n对相同的m进行加密

c 1 ≡ m e 1   m o d   n c_1 \equiv m^{e_1} \ mod \ n c1me1 mod n

c 2 ≡ m e 2   m o d   n c_2 \equiv m^{e_2} \ mod\ n c2me2 mod n

首先,两个加密的指数是互质的,那么就是 g c d ( e 1 , e 2 ) = 1 gcd(e_1,e_2)=1 gcd(e1,e2)=1

根据欧几里得算法我们可以得到一组一正一负的解 ( s 1 , s 2 ) (s_1,s_2) (s1,s2)

使得 e 1 s 1 + e 2 s 2 = 1 e_1s_1+e_2s_2=1 e1s1+e2s2=1,

然后我们带入化简就可以得到

c 1 s 1 c 2 s 2 ≡ m   m o d   n c_1^{s_1}c_2{s_2}\equiv m\ mod\ n c1s1c2s2m mod n

举例

import gmpy2
import libnum

n = 0x00b0bee5e3e9e5a7e8d00b493355c618fc8c7d7d03b82e409951c182f398dee3104580e7ba70d383ae5311475656e8a964d380cb157f48c951adfa65db0b122ca40e42fa709189b719a4f0d746e2f6069baf11cebd650f14b93c977352fd13b1eea6d6e1da775502abff89d3a8b3615fd0db49b88a976bc20568489284e181f6f11e270891c8ef80017bad238e363039a458470f1749101bc29949d3a4f4038d463938851579c7525a69984f15b5667f34209b70eb261136947fa123e549dfff00601883afd936fe411e006e4e93d1a00b0fea541bbfc8c5186cb6220503a94b2413110d640c77ea54ba3220fc8f4cc6ce77151e29b3e06578c478bd1bebe04589ef9a197f6f806db8b3ecd826cad24f5324ccdec6e8fead2c2150068602c8dcdc59402ccac9424b790048ccdd9327068095efa010b7f196c74ba8c37b128f9e1411751633f78b7b9e56f71f77a1b4daad3fc54b5e7ef935d9a72fb176759765522b4bbc02e314d5c06b64d5054b7b096c601236e6ccf45b5e611c805d335dbab0c35d226cc208d8ce4736ba39a0354426fae006c7fe52d5267dcfb9c3884f51fddfdf4a9794bcfe0e1557113749e6c8ef421dba263aff68739ce00ed80fd0022ef92d3488f76deb62bdef7bea6026f22a1d25aa2a92d124414a8021fe0c174b9803e6bb5fad75e186a946a17280770f1243f4387446ccceb2222a965cc30b3929
e1 = 17
c1 = 0xe2656d98064060e2d223768e65ddaf83b031c12b1764c02a200ea358d621a1df50dce5aa4058aaffc9471bb8cafd609f4093adc71167775ecaf53e77b08fee395855e833f6da9060d10dd7534937e7136323588bc76905a284f1bbef30fc8723ef804eeafaf40d42227b0aaf213dcdb1a84aafb8aa0f96a132c648cb2eace527c2510e3c17e071543229f69ede7ec97e511d15b90b6e908440b07c19bd5f8db4fa225cc1e790331
n2 = n
e2 = 65537
c2 = 0xafd609e652925da44893025767bb57f11fd49ee7f1d6b63d21a9aab22e70ea91e404386cf57fc79f00629512592cf827c21147297f773f0c12912274d747ed81b4e8dfef01f6f71259dd5c9c2b9ffbfe7450fa2eaf9a3e932c0c877f374471d8651d75f5bb5769fcbfbb837636385dadd70db774fafecb6f2812c1fc2e06cd73404ae9859e5d30fe2dcf906067325ef6407b01de7093c3d11685b31b8b924cac7ee5e0444deeff2190875edcc4e4f9d4e991a083dd946b5ad53ecc53f963b5211c57e9a78aa717763c45a4ba1c1bfac7687bc0e6e5c1b452faf9232f30356214746fbb625d20a693d32bf665232daeb82f8460d5b38355ca2a0226e89f12f0d12bf09bd581274c5ed47ab1d1caf1e25a37f974c1f0808ae0984108ff69047abbca7f45430b260036d93a318625dfab0e8c3172db0a58496c0f47ac8af3cc425686f4233d085e88f81680a78a9213405be118f83017ad6c8a5908d1cb584ec8334c125305d32e17fd2cdf07cb0f06c8b16940b6e171ddfdffd55cee5d72002b66d4102243dab3dcfa21b5d12b384820ac1a1ba4f83ce8b6c8f3e8cedd8af42ed085bac111763d416a61b22eed6c5aa52af01851607de198ea1297e4aa9343afefa475f63b5d8502b9952d8008227f24fa2331254851dd5e9415ca7ad5a255fc5d74ead231f9e360040ff5ee5968d696a264bf6fdf09e7ad28584690f5cc311494
s = gmpy2.gcdext(e1, e2)
s1 = s[1]
s2 = s[2]
if s1 < 0:
    s1 = - s1
    c1 = gmpy2.invert(c1, n)
elif s2 < 0:
    s2 = - s2
    c2 = gmpy2.invert(c2, n)
    m = (pow(c1, s1, n) * pow(c2, s2, n)) % n
print(libnum.n2s(int(m)).decode())

这样就可以直接运行出最终的结果

防御方法

我们只要避免多个人使用同一个模数就可以了,这样攻击者是无法推导明文的。

攻击方法四:低指数攻击

介绍

在RSA中e也被称为加密指数,e是可以随便选取的,一般来说选小一点的e可以事加密更加迅速,但是如果太小的话就可能造成比较严重的安全问题。

我们可以举一个简单的例子:

$ c\equiv m^e \ mod\ n$

如果e=3, m e < n m^e<n me<n那么

c = m e , e = 3 c=m^e,e=3 c=me,e=3

m = c 3 m=\sqrt[3]{c} m=3c

当然,我们还有可能会遇到明文的3次方比n大的情况,那么我们可以设一个k

c = m k + k n c=m^k+kn c=mk+kn

这种情况下我们只需要对n进行一个爆破就可以了

举例

c=492941893985125689056004628436103502490218489301029929996937359251178626967153356288856008811449446717819949872113981057598960730650811603515919692403032638486529321

e=3

这个c一看就很小,所以我们一猜就知道e肯定不会大了

然后我们用代码运行一下试试

import gmpy2
import libnum

e = 3
# 读入 n, 密文
c= 492941893985125689056004628436103502490218489301029929996937359251178626967153356288856008811449446717819949872113981057598960730650811603515919692403032638486529321
a,b=gmpy2.iroot(c,3)
print(libnum.n2s(int(a)).decode())

最终的输出的结果是

Rytter_is_beautiful_boy

(没错,我是个漂亮男孩)

防御方法

我们把指数设置的大一点,比如一个5位数或者4位数,这种情况下黑客使用逆运算是十分困难的。

攻击方法五:Hastad广播攻击

介绍

如果使用的是一个比较小的指数进行加密,并且还把加密的消息mod不同的n后发给了其他的多个人,这种情况下我们就可以通过地加密指数广播攻击来进行攻击。

假设e比较小,而且n1,n2,n3是互素的,我们可以使用中国剩余定理来求得 m e m^e me

举例

import gmpy2
import libnum
from functools import reduce


def CRT(items):
    N = reduce(lambda x, y: x * y, (i[1] for i in items))
    result = 0
    for a, n in items:
        m = N // n
        d, r, s = gmpy2.gcdext(n, m)
        if d != 1: raise Exception("Input not pairwise co-prime")
        result += a * s * m

    return result % N, N


# 读入 e, n, c
e = 9
n = [
    142782424368849674771976671955176187834932417027468006479038058385550042422280158726561712259205616626939123504489410624745195777853423961104590708231562726165590769610040722589287393102301338152085670464005026301781192671834390892019478189768725018303217559795377795540494239283891894830166363576205812991157,
    153610425077816156109768509904751446801233412970601397035720458311275245730833227428213917577405780162151444202393431444812010569489900435979730559895340377469612234558042643742219128033827948585534761030527275423811282367831985007507137144308704413007806012914286105842311420933479771294576841956749281552971,
    152540067782701001222493009941492423063369171831039847414320547494725020441901272486665728360741395415762864872737675660423920609681185809510355937534756399208661762715484879562585724584849261266873624875852300611683382543315580370484972470694466195837255994159609193239840228218925381488410059939975556977947,
    125842716702134814646356078531900645012495638692517778270527426844383063904041812273637776798591687732598509470005151551320457132061693618473039437320011446697406190781306264437609046721508738109650829547010385875425097336266103994639126319889016342284747700714199556143378526590058467791687837422897022829661,
    116144389285266462769913139639175922392318396923181100785008570884082681963637784423143843845816350379438789947802939701820129805341796427821894273985551331666719808355412080909245720551238149511778060242720419584504473490216670437024863860559347959698828131475160058721701582089480924088773887932997353631767,
    127833907448946785858374094953899556339175475846831397383049660262333005992005484987913355932559627279178940862787593749842796469355336182379062826441222705075178971785791223706944120681105575965622931327112817747065200324610697178273898956820957640413744954233327851461318200323486469677469950386824833536523,
    130561613227079478921314550968562766645507834694262831586725464124109153306162445639759476845681271537955934718244296904503168256991962908095007040044300188572466395275317838178325500238288302672390013747102961340256309124310478931896245221622317302428447389760864327859640573452084295225059466376349115703119,
    115953389401040751013569404909249958538962411171147823610874077094621794755967854844224923689925397631692572916641171075740839099217316101334941033937183815345038898177087515909675028366437302462022970987947264115373697445950951595479758872029099661065186221250394358255523574834723958546450323357472451930993,
    143437107845384843564651522639125300763388830136500260725097766445883003928355325003575359566631064630487365774344508496878731109174874449170057678821440711511966073934025028100604234445470976333825866939923998344367645612128590820812489407412175198698290167077116185959180877334222693344630253253476594907313]
c = [
    126614023705610247090019294113407412715821263359477677588459244887555174903568133490570864775225451701706868913802374938942213937947762067695504692087674602851265919322316265003763338305790803677433818501570168307268815851850921805174813849523354940888857999606213109014097036939449661195437237541769645107004,
    70908643806892802618509105733186365688654461225936556673646944217302528561640901157174222986127546495878308605692365408260258545773134243291808668084533381732010678166291795651007903447008982159052151644824777541752574686984267862855125980350905596422771415460786516060723198104435439293665628808858945853129,
    109599829675514201441261430014488564303964453266364523917524457648527909292717574323189769408116896296205364262106006916485184241547651784913092255959472834868833047764144251354819545064578607443924221124393790947311620107117314621960954674545046617962662509618502212353080162020845471617023190370952880694956,
    107910386698710736927353579013027406305954448336078410683411620715842500616371408940516318256722350949835968491578728633692534256555906176020636948971953813759729461548007608497364287548995623373370577988013088249513593832849805442641259759567490924075209438682821591975600592390716845883578451424705261218219,
    44624612665064662357908333024211729819983085003935551649561188186735945339830932837613692877691197632058523958408671611832421900123816907400252218606057899719039264815501475227568572430683147904460271312484901444488326921081390645226666185437693762485926070791643619293039814426818237785573790623528121910530,
    40620848081518407992180639680162190017941444910670465889487810690623033209063022558974849246382077229017852985083425134754101122046623878436036547241821832170972280434336497125946368641882730912395654303785081350920319344488728261778113890272549887390539878610482004675846054416784748597891948269281468234078,
    86566251278233538955590219125173670865000608556023318614050704736152785880235946188528626303912192346173384823042684887161982861552626002027336405125850584761789310327414669746178808537843999387861591027028563951959393828472778282627116959245237062060501114221629951373610045939934010193093971748920887749903,
    97684809101700730389097924089994412812403815300510622315708392919974916930136878948480030136702962983037106913717478489237964607960954266552285295969037994510716108491804445001248561078153474640621937479849235013420198946023472330608275018552462790304785795771073934718236988199734471991873661060955494473697,
    13385339950843680230623339128042508380079021516859076477016647932057813387177848487508066465470701299541995818896938439713570488931434491700516948788512899822563477877354360575798826347434062508189243414435093871418815288387263128470602107533632112227579653334192069543887918445462644884079992672844526231878,

]
data = list(zip(c, n))

x, n = CRT(data)
a,b = gmpy2.iroot(gmpy2.mpz(x), e)
print(libnum.n2s(int(a)).decode())

防御方法

我们将e的取值范围设的更广一点, 这样黑客很难猜到e

攻击方法六:Fermat攻击

介绍

针对大整数的分解有很多种算法,性能上各有优异,其中一种就是Fermat 方法,Fermat 适用于 p q 相差不大的时候

举例

from gmpy2 import *

def Fermat(n):
    a = isqrt_rem(n)[0] + 1
    b = a ** 2 - n

    while 1:
        q = isqrt_rem(b)
        if q[1] == 0:
            return a - q[0]

        a += 1
        b = a ** 2 - n

n = 2181271*2908361
print(Fermat(n))

输出的结果是

2181271

防御方法

我们可以将p,q的大小不要太接近,这样可以使分解n的难度加大

攻击方法七:Pollard rho 方法攻击

介绍

针对大整数的分解有很多种算法,还有一种就是Pollard rho 方法,Pollard rho 适用于p,q相差比较大的时候。

举例

from gmpy2 import *


def PollardRho_p_1( N):
    a = i = 2
    while 1:
        a = pow(a, i, N)
        d = gcd(a - 1, N)
        if d != 1:
            return d
        i += 1

n = 911*21788233
print(PollardRho_p_1(n))

输出的结果是

911

防御方法

我们可以将p,q的大小差别不要太大,这样可以使分解n花费的时间更长

攻击方法八:已知明文格式的暴力破解

介绍

这个其实不是一个教科书的攻击方法,是我在平时的一个小挑战中发现的,如果我们知道加密的方法,并且知道加密的格式,我们可以通过构造明文,然后对明文进行加密的方法来进行对比,如果发现我们加密后的结果跟对比的密文一样,我们就可以判定当前的我们猜测的明文是正确的

举例

我们已经知道明文的格式和加密的方法,然后我们就可以暴力破解这一个结果

import gmpy2 as gm

with open("prime_numbers.txt", 'r') as f:
    # prime_numbwer.txt是我在网上找的素数表
    line = f.readline()
    linestr = line.split()
for line_str in linestr:
    prime_number = int(line_str)
    text = "prime:" + str(prime_number)
    temp = 0
    for i in text:
        d = ord(i)
        temp = temp * 256 + d
    M = gm.mpz(temp)
    e = 65537
    n = 721059527572145959497866070657244746540818298735241721382435892767279354577831824618770455583435147844630635953460258329387406192598509097375098935299515255208445013180388186216473913754107215551156731413550416051385656895153798495423962750773689964815342291306243827028882267935999927349370340823239030087548468521168519725061290069094595524921012137038227208900579645041589141405674545883465785472925889948455146449614776287566375730215127615312001651111977914327170496695481547965108836595145998046638495232893568434202438172004892803105333017726958632541897741726563336871452837359564555756166187509015523771005760534037559648199915268764998183410394036820824721644946933656264441126738697663216138624571035323231711566263476403936148535644088575960271071967700560360448191493328793704136810376879662623765917690163480410089565377528947433177653458111431603202302962218312038109342064899388130688144810901340648989107010954279327738671710906115976561154622625847780945535284376248111949506936128229494332806622251145622565895781480383025403043645862516504771643210000415216199272423542871886181906457361118669629044165861299560814450960273479900717138570739601887771447529543568822851100841225147694940195217298482866496536787241

    C = pow(M, e, n)

    c = 717348655627038616073288354387606286229980677413304369915862527771281016852135054963900603046847179121609227174165679532130716705305425549067650613906848637494474096907092492560671684935826812101674760813486843819489114781692851259623358504486939604307275251199873481633460815189996292969692596011265992876003974419953548879377924749253797859118881953484341596717704679730718910535006470210670208589833003641625708472071775592625379615502058915163185965355709795021350078363827528602826373934927290670399178428782728342716330421109221332903266281664583709697681266008823069020574040305198446737103343701826287828186916725963214757346800273536268742826517052307802199170787956054354547373002365129277234200348567463205094639558600522531787165414661355476744878250693304548629419435228784187058488847537216525666369533617265094969848698840010240871326319967181036417250016781160463225626134456687737978765164453500082048261302710166124116718102883998948965833964620946728635781816970367930728010217145644644322367043290818334229925848346663430689435771412320072479164926194376343790391298595539977628049052505552553062470292175217795639777381605730709286986337496306136510796700220019530855839494563567560194768782151996589381705077908

    if c==C:
        print("find the number!!!")
        print("the number is:" + str(prime_number))

这样我们就可以通过暴力破解的方式来进行攻击了

防御方法

这种的防御方法也很简单,我们只要不暴露我们的格式,或者在明文的最后加上一些没有意义的符号,这样攻击者就很难通用这种方式进行攻击了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值