RSA基础
RSA密钥生成步骤
(1)随机选择两个不相等的质数p和q
比如选择61和53
在实际应用中,这两个指数越大就越难破解
(2)计算p和q的乘积n
n=61*53=3233
3233写成二进制是110010100001,共12位,故该密钥是12位的
目前主流可选值:1024、2048、3072、4096等,低于1024bit的密钥已经不建议使用
(3)计算n的欧拉函数$\phi(n)$
欧拉函数是小于x的整数中与x互质的数的个数,一般用$\phi(x)$表示
互质是指两个数的公约数只有1,比如15和31
$\phi(8)$就等于4,因为8以内的与8互质的数只有1、3、5、7这四个数
欧拉函数的性质:
如果$n=p*q$且p、q互质,则$\phi(n)=\phi(pq)=\phi(p)\phi(q)$
如果n是质数,则$\phi(n)=n-1$
根据这两个性质可得:
$\phi(p)=p-1,\phi(q)=q-1$,所以$\phi(n)=(p-1)*(q-1)$
所以可得例子中的$\phi(n)=60*52=3120$
(4)找出公钥e
公钥e是按照条件随机选择的一个整数,选择e的条件是$1<e<\phi(n)$,且e与$\phi(n)$互质
本例中选取e=17,但实际应用中e常常取65537
(5)计算私钥d
私钥d是根据公钥e计算出来的,计算规则:e*d除以$\phi(n)$余数为1,可表示为:$ed \equiv 1(mod\phi(n))$
$\equiv$是恒等号(也叫同余号),比如两个整数a、b,他们除以整数m所得的余数相等,就可以表示为$a\equiv b$(mod m),比如说5除以3余数为2,11除以3余数为2,于是可写成$11 \equiv $ 5(mod 3)
d其实就是e相对于$\phi(n)$的乘法逆元
(6)得到密钥对
公钥就是(n,e),这里对应着(3233,17)。
私钥就是(n,d),这里对应着(3233,2753)
简单RSA加解密过程
(1)公钥加密
假设需要加密的数据是字母“A”
首选需要转ASCII码,所以m=65,并且m必须要小于n
加密公式:$c=m^{e}modn$,即m的e次方再模n,即为c(密文)
(2)私钥解密
拿到密文c=2790
解密公式:$m=c^{d}modn$,即c的d次方再模n,即为m(明文)
解密必须知道私钥d,在已知n和e的情况下,可以推到出d
因为$ed\equiv1(mod\phi(n))$,所以只有知道e和$\phi(n)$才能算出d。
$\phi(n)$=(p-1)*(q-1),所以知道p和q就行,而p和q又是由n因式分解出来的,所以只要能因式分解n,那么就可以算出d,拿到私钥
具体RSA加解密过程
(1)公钥加密
明文"hello"
转换顺序:字符串->十六进制->十进制
m=448378203247
p = 999671,q=999727,n=999398089817,$\phi(n)$=999396090420,e=65537
c = m**e%n = 511394555284
(2)私钥解密
转换顺序:十进制->十六进制->字符串
c = m**e%n = 511394555284
d = 529762121873
m = c**d%n = 448378203247
当需要求的d(私钥,即公钥的乘法逆元)数值过大时,需要利用python中的libnum库进行计算
利用pow函数可以很好的实现次方模运算
利用bytes.fromhex('68656c6c6f')
可以将十六进制字符串转化为明文字符串
更好的办法是利用libnum 库中的n2s方法,直接将十进制转化为字符串
同时之前的字符串转十进制数也可以通过内置的方法s2n直接转换
利用openssl提取公钥信息
1 openssl rsa -pubin -in pub.key -text -modulus
分解大整数
利用symbol求解方程组
1 2 3 import sympyx,y = sympy.symbols('x y' ) s = sympy.solve([c1 - x -y,c2 - x**3 -y**3 ],[x,y])
求n的公约数
当题目中有多个n的时候,使用同一e对同一个明文加密时,这些n之前可能存在公约数。利用
找出存在的公约数
利用迭代器
1 2 3 4 5 6 7 import itertoolsls = [n0,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n13,n14,n15,n16,n17,n18,n19] for i in itertools.product(ls,ls): if i[0 ] != i[1 ] & libnum.gcd(i[0 ],i[1 ]) != 1 : print (ls.index(i[0 ]),ls.index(i[1 ]))
低加密指数分解攻击
RSA中e也称为加密指数,d称为解密指数,n称为模数
e太小就会造成安全问题,也成为低加密指数分解攻击
解题思路
共模攻击
当n相同时,e不同,并且e在互质的前提下可以使用共模攻击
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import libnumimport gmpy2c1=22322035275663237041646893770451933509324701913484303338076210603542612758956262869640822486470121149424485571361007421293675516338822195280313794991136048140918842471219840263536338886250492682739436410013436651161720725855484866690084788721349555662019879081501113222996123305533009325964377798892703161521852805956811219563883312896330156298621674684353919547558127920925706842808914762199011054955816534977675267395009575347820387073483928425066536361482774892370969520740304287456555508933372782327506569010772537497541764311429052216291198932092617792645253901478910801592878203564861118912045464959832566051361 n=22708078815885011462462049064339185898712439277226831073457888403129378547350292420267016551819052430779004755846649044001024141485283286483130702616057274698473611149508798869706347501931583117632710700787228016480127677393649929530416598686027354216422565934459015161927613607902831542857977859612596282353679327773303727004407262197231586324599181983572622404590354084541788062262164510140605868122410388090174420147752408554129789760902300898046273909007852818474030770699647647363015102118956737673941354217692696044969695308506436573142565573487583507037356944848039864382339216266670673567488871508925311154801 e1=11187289 c2=18702010045187015556548691642394982835669262147230212731309938675226458555210425972429418449273410535387985931036711854265623905066805665751803269106880746769003478900791099590239513925449748814075904017471585572848473556490565450062664706449128415834787961947266259789785962922238701134079720414228414066193071495304612341052987455615930023536823801499269773357186087452747500840640419365011554421183037505653461286732740983702740822671148045619497667184586123657285604061875653909567822328914065337797733444640351518775487649819978262363617265797982843179630888729407238496650987720428708217115257989007867331698397 e2=9647291 s1 = int (gmpy2.gcdext(e1,e2)[1 ]) s2 = int (gmpy2.gcdext(e1,e2)[2 ]) print (s1,s2)m = pow (c1,s1,n)*pow (c2,s2,n)%n print (libnum.n2s(m))
低解密指数攻击
1 2 3 4 5 6 7 8 9 10 import RSAwienerHacker as rsa_dimport hashlibN = 101991809777553253470276751399264740131157682329252673501792154507006158434432009141995367241962525705950046253400188884658262496534706438791515071885860897552736656899566915731297225817250639873643376310103992170646906557242832893914902053581087502512787303322747780420210884852166586717636559058152544979471 e = 46731919563265721307105180410302518676676135509737992912625092976849075262192092549323082367518264378630543338219025744820916471913696072050291990620486581719410354385121760761374229374847695148230596005409978383369740305816082770283909611956355972181848077519920922059268376958811713365106925235218265173085 d = rsa_d.hack_RSA(e,N) print (d)print (hashlib.md5(hex (d).encode()).hexdigest())
低加密指数广播攻击(中国剩余定理)
这种攻击方式特点与之前介绍的低加密指数分解攻击以及求n的公约数非常相似,都是对同一个明文采用不同的公钥加密,这些公钥中的e是相同的,并且非常小,但是n不同,而且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 29 30 31 32 33 34 35 36 import libnumimport gmpy2import RSAwienerHacker as rsa_dfrom functools import reduces=[{"c" : 7366067574741171461722065133242916080495505913663250330082747465383676893970411476550748394841437418105312353971095003424322679616940371123028982189502042 , "e" : 10 , "n" : 25162507052339714421839688873734596177751124036723831003300959761137811490715205742941738406548150240861779301784133652165908227917415483137585388986274803 }, {"c" : 21962825323300469151795920289886886562790942771546858500842179806566435767103803978885148772139305484319688249368999503784441507383476095946258011317951461 , "e" : 10 , "n" : 23976859589904419798320812097681858652325473791891232710431997202897819580634937070900625213218095330766877190212418023297341732808839488308551126409983193 }, {"c" : 6569689420274066957835983390583585286570087619048110141187700584193792695235405077811544355169290382357149374107076406086154103351897890793598997687053983 , "e" : 10 , "n" : 18503782836858540043974558035601654610948915505645219820150251062305120148745545906567548650191832090823482852604346478335353784501076761922605361848703623 }, {"c" : 4508246168044513518452493882713536390636741541551805821790338973797615971271867248584379813114125478195284692695928668946553625483179633266057122967547052 , "e" : 10 , "n" : 23383087478545512218713157932934746110721706819077423418060220083657713428503582801909807142802647367994289775015595100541168367083097506193809451365010723 }, {"c" : 22966105670291282335588843018244161552764486373117942865966904076191122337435542553276743938817686729554714315494818922753880198945897222422137268427611672 , "e" : 10 , "n" : 31775649089861428671057909076144152870796722528112580479442073365053916012507273433028451755436987054722496057749731758475958301164082755003195632005308493 }, {"c" : 17963313063405045742968136916219838352135561785389534381262979264585397896844470879023686508540355160998533122970239261072020689217153126649390825646712087 , "e" : 10 , "n" : 22246342022943432820696190444155665289928378653841172632283227888174495402248633061010615572642126584591103750338919213945646074833823905521643025879053949 }, {"c" : 1652417534709029450380570653973705320986117679597563873022683140800507482560482948310131540948227797045505390333146191586749269249548168247316404074014639 , "e" : 10 , "n" : 25395461142670631268156106136028325744393358436617528677967249347353524924655001151849544022201772500033280822372661344352607434738696051779095736547813043 }, {"c" : 15585771734488351039456631394040497759568679429510619219766191780807675361741859290490732451112648776648126779759368428205194684721516497026290981786239352 , "e" : 10 , "n" : 32056508892744184901289413287728039891303832311548608141088227876326753674154124775132776928481935378184756756785107540781632570295330486738268173167809047 }, {"c" : 8965123421637694050044216844523379163347478029124815032832813225050732558524239660648746284884140746788823681886010577342254841014594570067467905682359797 , "e" : 10 , "n" : 52849766269541827474228189428820648574162539595985395992261649809907435742263020551050064268890333392877173572811691599841253150460219986817964461970736553 }, {"c" : 13560945756543023008529388108446940847137853038437095244573035888531288577370829065666320069397898394848484847030321018915638381833935580958342719988978247 , "e" : 10 , "n" : 30415984800307578932946399987559088968355638354344823359397204419191241802721772499486615661699080998502439901585573950889047918537906687840725005496238621 }] n = [s[i]['n' ] for i in range (len (s))] print (n)c = [s[i]['c' ] for i in range (len (s))] print (c)e = 10 N = reduce(lambda x,y:x*y,n) print (N)M = 0 for i in range (10 ): M += libnum.invmod(N//n[i],n[i])*(N//n[i])*c[i] print (M)k = 0 while 1 : result = gmpy2.iroot(M%N+k*N,e) if result[1 ]: print (libnum.n2s(int (result[0 ]))) break k += 1