【CrewCTF 2022】「The HUGE e」についてのメモ
前書き
CrewCTF 2022にて出題された問題「The HUGE e」に関する解法のメモです。
個人の備忘録としてまとめたものですが、誰かのお役に立てれば幸いです。
問題概要
以下のスクリプトと出力ファイルが与えられます。
from Crypto.Util.number import getPrime, bytes_to_long, inverse, isPrime
from secret import flag
m = bytes_to_long(flag)
def getSpecialPrime():
a = 2
for i in range(40):
a*=getPrime(20)
while True:
b = getPrime(20)
if isPrime(a*b+1):
return a*b+1
p = getSpecialPrime()
e1 = getPrime(128)
e2 = getPrime(128)
e3 = getPrime(128)
e = pow(e1,pow(e2,e3))
c = pow(m,e,p)
assert pow(c,inverse(e,p-1),p) == m
print(f'p = {p}')
print(f'e1 = {e1}')
print(f'e2 = {e2}')
print(f'e3 = {e3}')
print(f'c = {c}')
p = 127557933868274766492781168166651795645253551106939814103375361345423596703884421796150924794852741931334746816404778765897684777811408386179315837751682393250322682273488477810275794941270780027115435485813413822503016999058941190903932883823
e1 = 219560036291700924162367491740680392841
e2 = 325829142086458078752836113369745585569
e3 = 237262361171684477270779152881433264701
c = 962976093858853504877937799237367527464560456536071770645193845048591657714868645727169308285896910567283470660044952959089092802768837038911347652160892917850466319249036343642773207046774240176141525105555149800395040339351956120433647613
次のように暗号化をしていることが分かります。
ただし、
通常のRSA暗号と同様に考えると、
しかし、chall.pyで記載された方法(
ではどのようにして
解法
オイラーの定理を改めて確認します。
式
さらに、指数部は以下のように表せます(
ここで、
chall.pyのgetSpecialPrime関数を見てみると、
-
と素因数分解できる(各p - 1 = 2 \times a_{1} \times a_{2} \times \cdots \times a_{40} \times b とa_{i} はb bitの素数)20
また、
よって、オイラーの定理より、以下が成り立ちます。
先ほどと同様にして、式
式
なお、
from Crypto.Util.number import getPrime, isPrime
p = 127557933868274766492781168166651795645253551106939814103375361345423596703884421796150924794852741931334746816404778765897684777811408386179315837751682393250322682273488477810275794941270780027115435485813413822503016999058941190903932883823
phi = 1
q = (p - 1) // 2
while True:
if isPrime(q) == 1:
phi *= q - 1
break
a = getPrime(20)
if q % a == 0:
phi *= a - 1
q = q // a
print(phi)
数分時間はかかりますが、
phi = 63775594668498404422995279661693309334486076035802944116275814269950078792958445557761589097717204934857369990271713664698474867142217580223510594284968730411939236198524531363514002763605853593498040656788050786948899096447734618521600000000
あとは以下のとおりにフラグを求めていきます。
-
を計算する{e_{2}}^{e_{3}}\pmod {\phi(p - 1)} -
を計算するe = {e_{1}}^{(\rm{1.で求めた値})}\pmod{p - 1} - 法
の世界におけるp - 1 の逆元e を計算するd -
を計算するc^{d}\pmod p - 4.で得られた数値を変換する
from Crypto.Util.number import long_to_bytes
p = 127557933868274766492781168166651795645253551106939814103375361345423596703884421796150924794852741931334746816404778765897684777811408386179315837751682393250322682273488477810275794941270780027115435485813413822503016999058941190903932883823
e1 = 219560036291700924162367491740680392841
e2 = 325829142086458078752836113369745585569
e3 = 237262361171684477270779152881433264701
c = 962976093858853504877937799237367527464560456536071770645193845048591657714868645727169308285896910567283470660044952959089092802768837038911347652160892917850466319249036343642773207046774240176141525105555149800395040339351956120433647613
phi = 63775594668498404422995279661693309334486076035802944116275814269950078792958445557761589097717204934857369990271713664698474867142217580223510594284968730411939236198524531363514002763605853593498040656788050786948899096447734618521600000000
e2_e3 = pow(e2, e3, phi)
e = pow(e1, e2_e3, p - 1)
d = pow(e, -1, p - 1)
m = pow(c, d, p)
print(long_to_bytes(m))
フラグは次のとおりです。
b'crew{7hi5_1s_4_5ma11er_numb3r_7han_7h3_Gr4ham_numb3r}'
感想
大きな数や
Discussion