前言
首先,这篇文章RSA的基础知识就不介绍了,有兴趣的同学可以自行百度。
群友发了一道RSA,趁着有时间看了一下,分明可以很快就做出来的。但是,工具所在操作系统不统一耽误了很多时间(linux安装虚拟机迫不及待了)。还有,yafu永远滴神。
题目
from flag import flag,e,n,hint
from Crypto.Util.number import *
import sympy
import gmpy2
p1 = getPrime(1024)
q1 = getPrime(1024)
e1 = 65537
n1 = p1*q1
assert(n1==15407468934696168945264941371249627512485392136974126598864628856925116979363556866600135159969362640364802588000019524432394335524684826940831824306176814133539517786207961684101309117876531510947731474486452423332666973424028236568978713721272696289578931811888717036997558222398494314972431669206271790498970715500900264135119925860973490478100517862203305350401450340461065734676693349949156509885063766622284428107803228247305641260197128116324287237159269445241346706939628322442653423784680505594491670305409475396892234263140080944815341606020833976202613516503619770434532072430523496943880084782822882395561)
ce1 = 9358375874172613158834229877024317683584630006974717983646788533181744400179880375212071675133499846143400535192432317412046977443024162408488313516096642763509202430705635589848015361375982727481783583991155495804651044648088887150808240286937965973316666393115851696990488898075583952094868953037743356967968067736835363829651634349330238825747281131155593702157704874959369044558058902334950446838748187360229080799752695727828434200272526099122679051401887589765557218579565833612721706890321866568589538614582998047621904069239300554658361941559470229373193717457381777328942065533883675298360731732194947279795
phlN = 15407468934696168945264941371249627512485392136974126598864628856925116979363556866600135159969362640364802588000019524432394335524684826940831824306176814133539517786207961684101309117876531510947731474486452423332666973424028236568978713721272696289578931811888717036997558222398494314972431669206271790498464018927614244801324207858508082114013427427386533621381297845359492925630738083331982774623929178622496692967582554648054155539962669050232428740867170751875251878513979382763298349143928654646317668203902613536978578902751252553370198639565945596821655915911942217028443162254984509372791709751729154520665
assert(ce1==pow(e,e1,p1*q1))
assert(phlN == (p1-2)*(q1-2))
hint = bytes_to_long(hint)
p2 = getPrime(1024)
q2 = getPrime(1024)
n2 = p2*q2
assert(n2 == 28893510257620697683460496256535205565442761626884074461131328944537733369480542664329234494261134185519412984326351909339548274687685691178747333730200925184695096506043395247789946931930900534309611780406525586273555148267536989042393112377604035854352378641775810498846875701100032728530563047886310136220238869676172030690830702619998332297151991527168384713693755329052216065438455447751805497385008986122998650713085776028533074822347020809417940650453855645728580672594332642519955944572392961417012121591521684352756472219420799866941938445371061369712705596457590318004690868178809894190759298728516706735477)
e2 = 65551
ch = 13266387070878490570670697639270043033807853939037054598645717808876488930890591147631231150108846932320316500419631285253214106524742656890177777928436598320329627076713149425907459299846239893536694829460222481646942970935622765176761418873226630783318106970080392754530212411073362101463326073490621773461386168128782019895669575426736890586316867024125853363074012735577040424244158585111790969799174247996196949924855399697726336051726918778395347583029861129072802767845942653153837702017342939334820310884001319636176711523262216793772356694982490804785506659839451490438758836533696668087217149563093683986895
cn = 3145678648559702656736616546413476167536617037352966784505564254222854589577402748568787126609555164203391574882088441604768127490324440934911902296179714620132860851113484004838638108927241254636059307081584011702465766580428858614809022726237572187076605529219576713228993700190573788098115236767177357986521815537165762005303789794802413116079077948360469285796268343661309249716521567885906426439262622248113920076344035106506814979913107243169704621489526294999382288697954496636121611809182111470448770267583258782543154655048464943630754253914017286158633422408256951821187246928084946961470498806046371082593
d = 28724655802447761369427730489621050451056009445626210956262120726496658070328749816923370679754794035786377673387538829990828513496215474053742218622419565733610392873563809359209396255596470595425613713484089415872975756141158505639075344368073200666104259853613396359947347901635282853879187402871426074053912807997704133108727205194769898143830893607666310677680537924487544860100788828324845348251106410546107041689818386615840163864729254319067470710571583621001206018545494809941049687225537877195097462509088418020592061785787020300957323731964298904197864530825344966599183162868525718018915199518292271140825
assert(ch == pow(hint,e1,p2*q2))
assert(cn == pow(n,e2,p2*q2))
assert(hint == pow(ch,d,p2*q2))
flag = bytes_to_long(flag)
ccf = 6345095924537176892939102509084851834144996961449154569289370302204022667119946513913495896182344236671297118430731743822126772210352305554958792139511668352828006579439841379272533312061206820455321448889387797401794308175847204707739877304983482880539604531698066565660805838304117646372920395496202558162741038409798451023450508947201370523715733273269604044419796231091427374594619876862071565242272286577860132515579217851037380265724915500165310393910168400054800698496882400513490249747719051361162741600189260207452204596203420802235988770580036309786997219186772210017149969143771864717829565656459180539188L
assert(ccf == pow(flag,e,n))
分析
审计代码时间看来有些进步了,就基本套路已经可以看出来了,用了差不多五分钟就开始上手破题了。
题目也很容易读懂,主要做题分成前期思路和后期思路(理论知识就慢慢在其中穿插吧,打公式也挺累的):
前期思路
审计代码后先从主体开始,我们可以看出,求flag的e,n都被RSA加密了,一环扣一环的。那么解出e,n就是前期的关键。
求解e
已知 ce1 = pow(e,e1,n1) , e1 和 n1 都是已知的,除此之外还知道一个近似 phi 函数的 phl
(1)\(phl=(p-2)(q-2)\)
且知
(2)\(n=p*q\)
而我们的目标是求解
(3)\(\phi(n)=(p-1)(q-1)\)
有点数学功底的人可以将(1),(2)推出(3),这里直接给出结论:
\(\phi(n)=n1-\frac{(n1-phl+4)}{2}+1\)
得知phi(n)我们其实就拿到了私钥,d1=invert(e,phi)
,进一步可得到e=pow(ce1,d1,n1)
,e即解出
求解n
一开始我们注意到有个hint被加密了,而且对应私钥被明目张胆给了出来,不解白不解,发现解出来是haha,nohint
大概这个意思吧
其实给的这个hint的提示不在解出的内容之中,而在它已经给出的e,d之中
(4)\(ed = 1 mod(\phi(n))\)
(5)\(ed-1=k*\phi(n)\)
由(4)(5)我们就可以解出phi(n),也就是我们可以拿到e2对应的私钥,具体实现和理论有些差别,具体请看python的getpq()函数
d2=invert(e2,phi(n2))
,n=pow(cn,d2,n2)
,n即解出
后期思路
我们现在拿到了n,c,e,而且e是一个偶数170,那肯定和phi函数是不互素的,一开始想用低加密指数去直接去解发现一直都没办法去处理这个不互素的问题。
然后突然看了自己的笔记,当n比较大时可以分解n,然后试了一下,分解出来了(我还能说什么,yafu永远滴神)
得到p,q,那phi就拿到了,但是我们还是绕不过e和phi不互素的情况,上算法
1,若e和phi不互素,则选取\(e'=\frac{e}{gcd(e,phi)}\) (gcd指的是最大公因子,并且最后得到值是2)
2,加密指数选择 d=invert(\(e'\),phi)
3,由上,基本解密过程可以写为\(c^d=m^{gcd(e,phi)} mod(n)\)
4,由于知道gcd等于2,所以解出的\(m^{gcd(e,phi)}\)直接开方就好了(注:开平方一定要自己写函数,用内置函数给出的是特垃圾的小数)
解题脚本
#-- coding:utf-8 --
from Crypto.Util.number import *
import sympy
import random
import gmpy2
n1= 15407468934696168945264941371249627512485392136974126598864628856925116979363556866600135159969362640364802588000019524432394335524684826940831824306176814133539517786207961684101309117876531510947731474486452423332666973424028236568978713721272696289578931811888717036997558222398494314972431669206271790498970715500900264135119925860973490478100517862203305350401450340461065734676693349949156509885063766622284428107803228247305641260197128116324287237159269445241346706939628322442653423784680505594491670305409475396892234263140080944815341606020833976202613516503619770434532072430523496943880084782822882395561
e1 = 65537
ce1 = 9358375874172613158834229877024317683584630006974717983646788533181744400179880375212071675133499846143400535192432317412046977443024162408488313516096642763509202430705635589848015361375982727481783583991155495804651044648088887150808240286937965973316666393115851696990488898075583952094868953037743356967968067736835363829651634349330238825747281131155593702157704874959369044558058902334950446838748187360229080799752695727828434200272526099122679051401887589765557218579565833612721706890321866568589538614582998047621904069239300554658361941559470229373193717457381777328942065533883675298360731732194947279795
phlN = 15407468934696168945264941371249627512485392136974126598864628856925116979363556866600135159969362640364802588000019524432394335524684826940831824306176814133539517786207961684101309117876531510947731474486452423332666973424028236568978713721272696289578931811888717036997558222398494314972431669206271790498464018927614244801324207858508082114013427427386533621381297845359492925630738083331982774623929178622496692967582554648054155539962669050232428740867170751875251878513979382763298349143928654646317668203902613536978578902751252553370198639565945596821655915911942217028443162254984509372791709751729154520665
n2 = 28893510257620697683460496256535205565442761626884074461131328944537733369480542664329234494261134185519412984326351909339548274687685691178747333730200925184695096506043395247789946931930900534309611780406525586273555148267536989042393112377604035854352378641775810498846875701100032728530563047886310136220238869676172030690830702619998332297151991527168384713693755329052216065438455447751805497385008986122998650713085776028533074822347020809417940650453855645728580672594332642519955944572392961417012121591521684352756472219420799866941938445371061369712705596457590318004690868178809894190759298728516706735477
e2 = 65551
ch = 13266387070878490570670697639270043033807853939037054598645717808876488930890591147631231150108846932320316500419631285253214106524742656890177777928436598320329627076713149425907459299846239893536694829460222481646942970935622765176761418873226630783318106970080392754530212411073362101463326073490621773461386168128782019895669575426736890586316867024125853363074012735577040424244158585111790969799174247996196949924855399697726336051726918778395347583029861129072802767845942653153837702017342939334820310884001319636176711523262216793772356694982490804785506659839451490438758836533696668087217149563093683986895
cn = 3145678648559702656736616546413476167536617037352966784505564254222854589577402748568787126609555164203391574882088441604768127490324440934911902296179714620132860851113484004838638108927241254636059307081584011702465766580428858614809022726237572187076605529219576713228993700190573788098115236767177357986521815537165762005303789794802413116079077948360469285796268343661309249716521567885906426439262622248113920076344035106506814979913107243169704621489526294999382288697954496636121611809182111470448770267583258782543154655048464943630754253914017286158633422408256951821187246928084946961470498806046371082593
d = 28724655802447761369427730489621050451056009445626210956262120726496658070328749816923370679754794035786377673387538829990828513496215474053742218622419565733610392873563809359209396255596470595425613713484089415872975756141158505639075344368073200666104259853613396359947347901635282853879187402871426074053912807997704133108727205194769898143830893607666310677680537924487544860100788828324845348251106410546107041689818386615840163864729254319067470710571583621001206018545494809941049687225537877195097462509088418020592061785787020300957323731964298904197864530825344966599183162868525718018915199518292271140825
c = 6345095924537176892939102509084851834144996961449154569289370302204022667119946513913495896182344236671297118430731743822126772210352305554958792139511668352828006579439841379272533312061206820455321448889387797401794308175847204707739877304983482880539604531698066565660805838304117646372920395496202558162741038409798451023450508947201370523715733273269604044419796231091427374594619876862071565242272286577860132515579217851037380265724915500165310393910168400054800698496882400513490249747719051361162741600189260207452204596203420802235988770580036309786997219186772210017149969143771864717829565656459180539188
def gcd(a, b):
if a < b:
a, b = b, a
while b != 0:
temp = a % b
a = b
b = temp
return a
def getpq(n,e,d):
while True:
k = e * d - 1
g = random.randint(0, n)
while k%2==0:
k=k//2
temp=gmpy2.powmod(g,k,n)-1
if gmpy2.gcd(temp,n)>1 and temp!=0:
return gmpy2.gcd(temp,n)
def isqrt(n):
x = n
y = (x + 1) // 2
while y < x:
x = y
y = (x + n // x) // 2
return x
#解出n
pq2=getpq(n2,e1,d)
p2=pq2
q2=n2//pq2
if p2*q2 == n2 :
print("true")
phin2=(p2-1)*(q2-1)
d2=gmpy2.invert(e2,phin2)
n=pow(cn,d2,n2)
print(n)
#解出e
phin1=n1-(n1-phlN+4)//2+1
d1=gmpy2.invert(e1,phin1)
e=pow(ce1,d1,n1)
print(e)
#yafu分解n
p = 110008692064444333114552396120412188326432697682750049489560365146770147579249803762425525918027991556641987279328964584183654715362902671307163603939776287305519794751748445600023976792537215842609803380681680355205053311348980154705501711802410590939817347286808595438717476065347389083064487349999646302977
q = 110008692064444333114552396120412188326432697682750049489560365146770147579249803762425525918027991556641987279328964584183654715362902671307163603939776287305519794751748445600023976792537215842609803380681680355205053311348980154705501711802410590939817347286808595438717476065347389083064487349999646247583
phin=(p-1)*(q-1)
can=gcd(e,phin)
print(can)
real_e=e//can
d=gmpy2.invert(real_e,phin)
fake_m=pow(c,d,n)
#因为gcd为2
m=isqrt(fake_m)
flag=long_to_bytes(m)
print(flag)
b'flag{b085ade6def8ad9efbed3a75fc6fc76f}'
总结
当思路进行不下去的时候,为什么不从头开始呢?笑