引言
无
[GKCTF 2021]Random
加密代码如下:
import random
from hashlib import md5
def get_mask():
file = open("random.txt","w")
for i in range(104):
file.write(str(random.getrandbits(32))+"\n")
file.write(str(random.getrandbits(64))+"\n")
file.write(str(random.getrandbits(96))+"\n")
file.close()
get_mask()
flag = md5(str(random.getrandbits(32)).encode()).hexdigest()
print(flag)
显然,考的是伪随机数,因为random.getrandbits(k)
用的其实是MersenneTwister算法,常见的版本是MT19937,能做生成1≤k≤623个32位均匀分布的随机数,是一种伪随机数生成算法,以前做过,但是不知道这个k
是怎么回事,而且每次生成的位数也不一样,于是找wp
得知random.getrandbits(64)
其实就是从低到高位生成两组32位随机数,random.getrandbits(96)
类似
这样算我们就有
104
+
104
∗
(
64
/
32
)
+
104
∗
(
96
/
32
)
=
624
104 + 104 ∗ ( 64 / 32 ) + 104 ∗ ( 96 / 32 ) = 624
104+104∗(64/32)+104∗(96/32)=624个随机数
wp中用randcrack库可以方便破解(使用MersenneTwister算法生成的)伪随机数,可以借鉴
解密代码如下:
from hashlib import md5
from randcrack import RandCrack
with open(r'random.txt', 'r') as f:
l = f.readlines()
l = [int(i.strip()) for i in l]
t = []
for i in range(len(l)):
if i % 3 == 0:
t.append(l[i])
elif i % 3 == 1:
t.append(l[i] & (2 ** 32 - 1))
t.append(l[i] >> 32)
else:
t.append(l[i] & (2 ** 32 - 1))
t.append(l[i] & (2 ** 64 - 1) >> 32)
t.append(l[i] >> 64)
rc = RandCrack()
for i in t:
rc.submit(i)
flag = rc.predict_getrandbits(32)
print(md5(str(flag).encode()).hexdigest())
结果为:
[GUET-CTF2019]Uncle Sam
加密代码如下:
from Crypto.Util.number import *
def generkey(k):
p, q = getPrime(k), getPrime(k)
pubkey = p**2 * q
n = pubkey
l = (p-1)*(q-1) / gcd(p-1, q-1)
privkey = inverse(n, l)
return pubkey, privkey
def encrypt(m, pubkey):
return pow(bytes_to_long(m), pubkey, pubkey)
# pubkey = 2188967977749378274223515689363599801320698247938997135947965550196681836543275429767581633044354412195352229175764784503562989045268075431206876726265968368605210824232207290410773979606662689866265612797103853982014198455433380266671856355564273196151136025319624636805659505233975208570409914054916955097594873702395812044506205943671404203774360656553350987491558491176962018842708476009578127303566834534914605109859995649555122751891647040448980718882755855420324482466559223748065037520788159654436293431470164057490350841209872489538460060216015196875136927502162027562546316560342464968237957692873588796640619530455268367136243313422579857823529592167101260779382665832380054690727358197646512896661216090677033395209196007249594394515130315041760988292009930675192749010228592156047159029095406021812884258810889225617544404799863903982758961208187042972047819358256866346758337277473016068375206319837317222523597
# privkey = 1430375790065574721602196196929651174572674429040725535698217207301881161695296519567051246290199551982286327831985649037584885137134580625982555634409225551121712376849579015320947279716204424716566222721338735256648873164510429206991141648646869378141312253135997851908862030990576004173514556541317395106924370019574216894560447817319669690140544728277302043783163888037836675290468320723215759693903569878293475447370766682477726453262771004872749335257953507469109966448126634101604029506006038527612917418016783711729800719387298398848370079742790126047329182349899824258355003200173612567191747851669220766603
# enc = 1491421391364871767357931639710394622399451019824572362288458431186299231664459957755422474433520889084351841298056066100216440853409346006657723086501921816381226292526490195810903459483318275931326433052468863850690793659405367902593999395060606972100169925074005992478583035226026829214443008941631771292291305226470216430735050944285543542354459162474346521327649934512511202470099020668235115245819634762067338432916012664452035696422865651002305445711778476072004708256200872226475346448360491248823843688268126341094612981308791499434770936360676087490303951728563482686307164877000300082742316368597958297217061375140696272398140310043942637287763946305961019518639745426370821124559939597559475362769382796386720030343305889701616194279058139516811941262747298761646317383112470923295543635754747288259324745583689440061956478083777663996487389553238481759103908588004219390662578446313004404784835263543083088327198
有点像昨天写的塔卡基体系,但是没有dp,dq,显然不行
先尝试爆破n
:
啊这
那我直接m = pow(enc, privkey, p*q)
,但是不行,找wp
这种加密其实有个名字叫Schmidt-Samoa密码系统,对于小于pq的密文m,计算
c
≡
n
m
o
d
n
c\equiv n\space mod \space n
c≡n mod n作为密文,计算
d
=
i
n
v
(
n
,
φ
(
n
)
)
d=inv(n, \varphi(n))
d=inv(n,φ(n))作为私钥
但是对于这道题,发现私钥其实是
i
n
v
(
p
,
φ
(
p
)
)
inv(p, \varphi(p))
inv(p,φ(p)),应该是出题人的锅,或者可能是出题人故意为了防止爆破设置的
假设我们没有爆破,首先要做的是获取pq
由欧拉定理,
∀
a
∈
Z
\forall a\in \mathbb{Z}
∀a∈Z满足
g
c
d
(
a
,
p
q
)
=
1
gcd(a, pq)=1
gcd(a,pq)=1,则
a
φ
(
p
q
)
=
a
(
p
−
1
)
(
q
−
1
)
≡
1
m
o
d
p
q
a^{\varphi(pq)}=a^{(p-1)(q-1)}\equiv 1\space mod \space pq
aφ(pq)=a(p−1)(q−1)≡1 mod pq
于是
∃
k
1
∈
Z
\exists k_1\in \mathbb{Z}
∃k1∈Z,
s
.
t
.
a
N
d
=
a
1
+
k
1
(
p
−
1
)
(
q
−
1
)
s.t.a^{Nd}=a^{1+k_1(p-1)(q-1)}
s.t.aNd=a1+k1(p−1)(q−1)
再由欧拉定理,
a
(
p
−
1
)
(
q
−
1
)
≡
1
m
o
d
p
q
a^{(p-1)(q-1)}\equiv 1\space mod \space pq
a(p−1)(q−1)≡1 mod pq可得
a
N
d
=
a
1
+
k
1
(
p
−
1
)
(
q
−
1
)
≡
a
m
o
d
p
q
a^{Nd}=a^{1+k_1(p-1)(q-1)}\equiv a\space mod \space pq
aNd=a1+k1(p−1)(q−1)≡a mod pq
所以于是
∃
k
2
∈
Z
\exists k_2\in \mathbb{Z}
∃k2∈Z,
s
.
t
.
s.t.
s.t.
a
N
d
−
a
=
k
2
p
q
a^{Nd}-a=k_2pq
aNd−a=k2pq
又
n
=
p
2
q
n=p^2q
n=p2q,于是
p
q
=
g
c
d
(
a
N
d
−
a
,
n
)
pq=gcd(a^{Nd}-a,n)
pq=gcd(aNd−a,n)
进而可以求得私钥
d
=
i
n
v
(
n
,
φ
(
p
q
)
)
d=inv(n, \varphi(pq))
d=inv(n,φ(pq))
上述解法对于本题依然有效,取
a
=
2
a=2
a=2,解密代码如下:
from Crypto.Util.number import *
n = 2188967977749378274223515689363599801320698247938997135947965550196681836543275429767581633044354412195352229175764784503562989045268075431206876726265968368605210824232207290410773979606662689866265612797103853982014198455433380266671856355564273196151136025319624636805659505233975208570409914054916955097594873702395812044506205943671404203774360656553350987491558491176962018842708476009578127303566834534914605109859995649555122751891647040448980718882755855420324482466559223748065037520788159654436293431470164057490350841209872489538460060216015196875136927502162027562546316560342464968237957692873588796640619530455268367136243313422579857823529592167101260779382665832380054690727358197646512896661216090677033395209196007249594394515130315041760988292009930675192749010228592156047159029095406021812884258810889225617544404799863903982758961208187042972047819358256866346758337277473016068375206319837317222523597
c = 1491421391364871767357931639710394622399451019824572362288458431186299231664459957755422474433520889084351841298056066100216440853409346006657723086501921816381226292526490195810903459483318275931326433052468863850690793659405367902593999395060606972100169925074005992478583035226026829214443008941631771292291305226470216430735050944285543542354459162474346521327649934512511202470099020668235115245819634762067338432916012664452035696422865651002305445711778476072004708256200872226475346448360491248823843688268126341094612981308791499434770936360676087490303951728563482686307164877000300082742316368597958297217061375140696272398140310043942637287763946305961019518639745426370821124559939597559475362769382796386720030343305889701616194279058139516811941262747298761646317383112470923295543635754747288259324745583689440061956478083777663996487389553238481759103908588004219390662578446313004404784835263543083088327198
d = 1430375790065574721602196196929651174572674429040725535698217207301881161695296519567051246290199551982286327831985649037584885137134580625982555634409225551121712376849579015320947279716204424716566222721338735256648873164510429206991141648646869378141312253135997851908862030990576004173514556541317395106924370019574216894560447817319669690140544728277302043783163888037836675290468320723215759693903569878293475447370766682477726453262771004872749335257953507469109966448126634101604029506006038527612917418016783711729800719387298398848370079742790126047329182349899824258355003200173612567191747851669220766603
pq = GCD(pow(2, d * n, n) - 2, n)
m = pow(c, d, pq)
print(long_to_bytes(m))
结果为
但事实上,求出了pq就等于分解了n,但对于本题,就会发现,我们按照上述方法求出的pq
其实等于p
用p直接代替pq
也可求得m,解密代码如下:
from Crypto.Util.number import *
p = 128194403049680759730417456073484146647356572995921713843464320871713147845377732806963342042934962454134027743097600387979308508723555742581738982465486376489529245549008462953454385367577100489297368340937113649234808638010260771764118502798523641102975042512421309736174582209335248607849222488552635035711
q = 133199096697970395010360601752123884484750642911271667153329616708900276095359262125870755605084831227824337829042027891279415798701328111263867626754073487492338827458300240653837593442381578663683707324178792275270673229517518047914128590838435632554611499345291692417044388509949314333019317417383181850957
n = 2188967977749378274223515689363599801320698247938997135947965550196681836543275429767581633044354412195352229175764784503562989045268075431206876726265968368605210824232207290410773979606662689866265612797103853982014198455433380266671856355564273196151136025319624636805659505233975208570409914054916955097594873702395812044506205943671404203774360656553350987491558491176962018842708476009578127303566834534914605109859995649555122751891647040448980718882755855420324482466559223748065037520788159654436293431470164057490350841209872489538460060216015196875136927502162027562546316560342464968237957692873588796640619530455268367136243313422579857823529592167101260779382665832380054690727358197646512896661216090677033395209196007249594394515130315041760988292009930675192749010228592156047159029095406021812884258810889225617544404799863903982758961208187042972047819358256866346758337277473016068375206319837317222523597
c = 1491421391364871767357931639710394622399451019824572362288458431186299231664459957755422474433520889084351841298056066100216440853409346006657723086501921816381226292526490195810903459483318275931326433052468863850690793659405367902593999395060606972100169925074005992478583035226026829214443008941631771292291305226470216430735050944285543542354459162474346521327649934512511202470099020668235115245819634762067338432916012664452035696422865651002305445711778476072004708256200872226475346448360491248823843688268126341094612981308791499434770936360676087490303951728563482686307164877000300082742316368597958297217061375140696272398140310043942637287763946305961019518639745426370821124559939597559475362769382796386720030343305889701616194279058139516811941262747298761646317383112470923295543635754747288259324745583689440061956478083777663996487389553238481759103908588004219390662578446313004404784835263543083088327198
d = 1430375790065574721602196196929651174572674429040725535698217207301881161695296519567051246290199551982286327831985649037584885137134580625982555634409225551121712376849579015320947279716204424716566222721338735256648873164510429206991141648646869378141312253135997851908862030990576004173514556541317395106924370019574216894560447817319669690140544728277302043783163888037836675290468320723215759693903569878293475447370766682477726453262771004872749335257953507469109966448126634101604029506006038527612917418016783711729800719387298398848370079742790126047329182349899824258355003200173612567191747851669220766603
m = pow(c, d, p)
print(long_to_bytes(m))
结果相同
结语
无