前言
首先,這篇文章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}'
總結
當思路進行不下去的時候,為什么不從頭開始呢?笑