BUU第六届CTF校赛Crypto-RSA

一. Root_RSA

1.题目

这道题是Euler函数的应用。题目如下:

from Crypto.Util.number import *
p=getPrime(512)
q=getPrime(512)
print(p)
print(q)


from Crypto.Util.number import *
import gmpy2
from flag import flag

p=getPrime(512)
q=getPrime(512)
r=getPrime(512)
n=p*q*r
e=65537
m=bytes_to_long(flag)

def Euler(x):
    res=0
    for i in range(1,x):
        if gmpy2.gcd(i,x)==1:
            res+=1
    return res

P=p**3
Q=q**2
c=pow(m,e,n)

print(P)
print(Euler(Q))
print(c)
print(n)

#1686761823519516525084824311416810253107853832929411677237594989001281261421956188747941222367576127569696216513071075733130132251383529469095077597202999362675041210639065389821237728348981344440193122126487447235175127680730304754656661704596111547454161716607787386914764780833658069534913186485846587027674567133467341836048413431174183101579802349498153899249182793495245916757355079598668221097821452488627067390724198617676379698358212167618567704428433303
#54800501457630149544580145188029519076092032026436445384163914536965196942938808746487258773679836358732387355329080483568564046906919385574994390974732491368590525875801103056613954297623835159311237599961507385582029709732950222118171961946571285930711702624160354541459438994349318149872111029043942485620
#568846080701555049788706647255668980211679838950729382006912035332305772256748203239331545262283165739670330060735508231578298253855583985677482008855909565463834639005910652510802915373310537390293061001384655286359323437737989289787972131460392977341024828530868508329336263146882773903176326250063921456707975853839017504122823304303509269793133132036479219404842827556015566627129747816769486873563843578029479179692030808518925753268233301452280242586076493
#1069981867450019752454430625015273180922733107799929958042241890002915414684562764186875387471850290817321430141222917656674447229697676236077201897275059270515637506529666384968535578683380559782336910645306992981172862940944536463561840412558764760962107958365575095435157363812028759723055357681895134974760386884254380189603418912937553755099672511307377054933171384741715642510754214768859689909974996095149155241791151425031489280537907842378844226410097051

2.求解思路

其实细看代码并不是很难理解。我们的思路是解出p、q然后按常规的步骤去得到flag。

p我们很容易得到,对P直接开三次方即可;然而对于q则要动点脑筋。我在参赛的时候并没有学习过密码学,所以最初的思路时写一个脚本函数,功能是输入一个数n(即素数个数),输出是第n+1个素数。也就是说我们把Euler(Q)带入函数,输出即为Q。但是这种方法经过尝试发现并不可取,因为Euler(Q)太大,我们计算机的算力想要计算出来基本是不可能的。我编写的脚本编译通过后,可以运行,但是迟迟没有结果!

然后,对Euler进行了深入的了解,发现有一个扩展定理正好可以用到,原理如下:

#phi(n^a)=n^a-n^(a-1)

详情见:杨波,《现代密码学(第五版)》,北京,清华大学出版社,2022. P89-90.

3.编写脚本

有了Euler的扩展定理后,我们得到q只需要求解一个二元一次方程即可。

脚本如下:

#RSA变种pqr,n=pqr,phi=(p-1)(q-1)(r-1)
from Crypto.Util.number import *
import gmpy2

n=1069981867450019752454430625015273180922733107799929958042241890002915414684562764186875387471850290817321430141222917656674447229697676236077201897275059270515637506529666384968535578683380559782336910645306992981172862940944536463561840412558764760962107958365575095435157363812028759723055357681895134974760386884254380189603418912937553755099672511307377054933171384741715642510754214768859689909974996095149155241791151425031489280537907842378844226410097051
P=1686761823519516525084824311416810253107853832929411677237594989001281261421956188747941222367576127569696216513071075733130132251383529469095077597202999362675041210639065389821237728348981344440193122126487447235175127680730304754656661704596111547454161716607787386914764780833658069534913186485846587027674567133467341836048413431174183101579802349498153899249182793495245916757355079598668221097821452488627067390724198617676379698358212167618567704428433303
c=568846080701555049788706647255668980211679838950729382006912035332305772256748203239331545262283165739670330060735508231578298253855583985677482008855909565463834639005910652510802915373310537390293061001384655286359323437737989289787972131460392977341024828530868508329336263146882773903176326250063921456707975853839017504122823304303509269793133132036479219404842827556015566627129747816769486873563843578029479179692030808518925753268233301452280242586076493
Euler_Q=54800501457630149544580145188029519076092032026436445384163914536965196942938808746487258773679836358732387355329080483568564046906919385574994390974732491368590525875801103056613954297623835159311237599961507385582029709732950222118171961946571285930711702624160354541459438994349318149872111029043942485620

#求解p
p=gmpy2.iroot(P,3)[0] #为什么要加一个[0],是因为iroot函数返回是一个包含两个元素的元组
                      #比如如果P是27,那么gmpy2.iroot(P, 3)将返回(3, 0),前者是一个立方根,后者是一个布尔值
                      #所以添加[0]是使用第一个对我们有用的值,下同。
print(p)

#一元二次方程求解q
a=1
b=-1
c_q=-Euler_Q
delta=b**2-4*a*c_q
q =int((-b + gmpy2.iroot(delta,2)[0]) // (2 * a))
print(q)

#求解r
r=n//(p*q)
print(r)

#RSA的变种,Euler函数
phi=(p-1)*(q-1)*(r-1)

e=65537
d=gmpy2.invert(e,phi)

m=pow(c,d,n)
flag=long_to_bytes(m) #long_to_bytes在Crypto.Util.number库中
print(flag)

#11903771663059518341912645066042582267678745214691121272332269847512624178064427789028954264701292914161793272471217879550653909080475237446747964043276487
#7402736079155473279000574596031490410671021795687853893698348179857428763438305848933328416647633118223876785823588566614584124350907811192587130096357221
#12142261002625479270959358223863571062295429117378994112396394259314721874267081158944354513358164889564741712782226613341612447412750073385958464420872713
#b'flag{1ro0t_is_5o_Powerfu1_Go0d_Job!!!}'

二.  Wilson_RSA

1.题目

正如题干提示,这道题是wilson定理的应用,题目如下

from Crypto.Util.number import *
from libnum import s2n
from secret import flag
p = getPrime(1024)
q = getPrime(16)
n = p*q
m = s2n(flag)
for i in range(1,p-q):
    m = m*i%n
e = 1049
print(pow(2,e,n))
print(pow(m,e,n))
#4513855932190587780512692251070948513905472536079140708186519998265613363916408288602023081671609336332823271976169443708346965729874135535872958782973382975364993581165018591335971709648749814573285241290480406050308656233944927823668976933579733318618949138978777831374262042028072274386196484449175052332019377
#3303523331971096467930886326777599963627226774247658707743111351666869650815726173155008595010291772118253071226982001526457616278548388482820628617705073304972902604395335278436888382882457685710065067829657299760804647364231959804889954665450340608878490911738748836150745677968305248021749608323124958372559270

2.求解思路

这道赛题当场没有AK,赛后复盘发现确实有点难度。解题思路如下:

求解分为两大部分:求私钥和密文。求私钥可以根据C1(即密文一得到),求密文可以根据C2(因为由循环处可以得知,我们得到的密文二是被加密过的)。

求解私钥:根据所得密文一我们可以知道由如下关系:2^e=C1+kn,所以可以对k进行破解,这里需要对k的范围进行一个估计。这里我估计的范围是512~2048。

估计过程:2^e=C1+kn,将这个式子全部换成以2为底的指数,那么C1、kn的指数都将在1049附近,估计n的指数在1039~1040之间,那么k的指数范围就应该在9~11之间。

求解密文:根据循环结构我们可以看出,这个操作对m进行了混淆。

即有:m×(p-q-1)!≡M(mod n)

又因为:(p−1)!=(p−1)×(p−2)×…×(p−q)×(p−q−1)×…×3×2×1

即有:m×(p-1)!=(p−1)×(p−2)×…×(p−q)×M(mod n)        //约分后左边还是(p-q-1)!

由wilson定理可知:(p-1)!=-1(mod p)

即有:m*(-1)=(p−1)×(p−2)×…×(p−q)×M(mod p)        //mod p下-1直接带入,p是n的因子,故可替换

所以:m=-[(p−1)×(p−2)×…×(p−q)×M](mod p)

明文求出。

3.编写脚本

先来求解k和n:

c1=4513855932190587780512692251070948513905472536079140708186519998265613363916408288602023081671609336332823271976169443708346965729874135535872958782973382975364993581165018591335971709648749814573285241290480406050308656233944927823668976933579733318618949138978777831374262042028072274386196484449175052332019377
num=pow(2,1049)

for k in range(512,2049):
    if(num-c1)%k==0:
        print(k)
        print((num - c1) // k) #n

#1035
#5823713380800241798127161208605473167667967902620702068684472024119185247468416314089247879281733463161248890572390983305415645926810810670115987090805775496828975940219063783825457069902831333895859965086768216313079359826260701972093534555185595188238549423953860497190971290229918600826572984225793661171633741

有了n以后就可以分解n得到p、q:

import gmpy2
def fac(num):
    for a in range(gmpy2.bit_set(1,15),gmpy2.bit_set(1,16),2):
        if num%a==0 and gmpy2.is_prime(a):
            print(a)
            return a
n=5823713380800241798127161208605473167667967902620702068684472024119185247468416314089247879281733463161248890572390983305415645926810810670115987090805775496828975940219063783825457069902831333895859965086768216313079359826260701972093534555185595188238549423953860497190971290229918600826572984225793661171633741
q=fac(n)
p=n//q
print(p)
print(q)

#170229264879724117919007372149468684565431232721075153274808454126426741324966131188484635914814926870341378228417496808202497615585946352638507704855332363766887139815236730403246238633855524068161116748612090155595549964229654262432946553891601975628848891407847198187453488358420350203927771308228162321231
#34211

进而有p、q就可以得到欧拉函数phi和私钥d

import gmpy2
p=170229264879724117919007372149468684565431232721075153274808454126426741324966131188484635914814926870341378228417496808202497615585946352638507704855332363766887139815236730403246238633855524068161116748612090155595549964229654262432946553891601975628848891407847198187453488358420350203927771308228162321231
q=34211

phi=(p-1)*(q-1)
print(phi)

e=1049
d=gmpy2.invert(e,phi)
print(d)

#5823543151535362074009242201233323698983402471387980993531197215665058820727091347958059394645818648234378549194162565808607443429195224723763348583100920164465209053079248547095053823664197478371791803970019604222923764276296472317831101608631703586262920575062452649992783836741560180476369056454485433009278300
#3275396052817791824275932219950105798284277843773983590260635230926963493068621444514065817770288848863949803645906495545355950069804749844633341910419011341310270106117022538404272407971283615099482520822031998561987627190671991103451239226971120224876189837261055351282881280912793619143048373029691520948974449

求解明文

from Crypto.Util.number import *

p=170229264879724117919007372149468684565431232721075153274808454126426741324966131188484635914814926870341378228417496808202497615585946352638507704855332363766887139815236730403246238633855524068161116748612090155595549964229654262432946553891601975628848891407847198187453488358420350203927771308228162321231
q=34211
n=5823713380800241798127161208605473167667967902620702068684472024119185247468416314089247879281733463161248890572390983305415645926810810670115987090805775496828975940219063783825457069902831333895859965086768216313079359826260701972093534555185595188238549423953860497190971290229918600826572984225793661171633741
d=3275396052817791824275932219950105798284277843773983590260635230926963493068621444514065817770288848863949803645906495545355950069804749844633341910419011341310270106117022538404272407971283615099482520822031998561987627190671991103451239226971120224876189837261055351282881280912793619143048373029691520948974449
C2=3303523331971096467930886326777599963627226774247658707743111351666869650815726173155008595010291772118253071226982001526457616278548388482820628617705073304972902604395335278436888382882457685710065067829657299760804647364231959804889954665450340608878490911738748836150745677968305248021749608323124958372559270
M=pow(C2,d,n)

for i in range(1,q+1):
    M=M*(p-i)%p

m=(-M)%p
print(long_to_bytes(m))

#b"flag{7h3_73rr1b13_7h1ng_15_7h47_7h3_p457_c4n'7_b3_70rn_0u7_by_175_r0075}"

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值