kurenaif_2000_subscribers_challenge writeup
まえがき
2000人本当にありがとうございます 😆😆😆😆
最近は暗号以外にも様々な知識に触れる機会が増えてとても楽しい日々を送らせていただいております!
今後は暗号系の動画はちょっと少なくして、いろんな人と知識を共有しながらいろんな知識の習得過程を動画の形で残していければと思っています。そのためにはたくさん友だちが欲しいので、もっとチャンネル登録者数を増やして色んな人と技術交流をしてみたいです!
今後もよろしくおねがいします!
問題
フラグの長さは383bitです。(サンプルの文字列と同じ)
この問題には以下の特徴があります。
- pとqが20bit(とてもちいさい)
- n = p*q にはフラグに入り切らない
- e が 20000 (2の倍数)
from Crypto.Util.number import *
flag = bytes_to_long(b"kurenaifCTF{DUMMYDUMMYDUMMYDUMMYDUMMYDUMMYDUMMY}")
print("# bit_length = ", flag.bit_length())
e = 20000
ns = []
cs = []
for i in range(2*200):
p = getPrime(20)
q = getPrime(20)
n = p * q
ns.append(n)
cs.append(pow(flag, e, n))
print("e=", e)
print("ns=", ns)
print("cs=", cs)
解答
n が小さすぎるので容易に素因数分解可能
程度です。
e と \phi が互いに素ではない
残念ながら、この問題は
であるから、
ここで、 以下の式を考え、ユークリッドの互除法で
より、
となります。もし、
m^4 の情報が足りない
ここで、4となるものの個数によって復元できるかどうかが異なります。筆者手元の環境では10回連続では成功してくれたので、概ね問題なしと思い問題にしました。
m^4 から m へ
あとがき
1問で典型的なRSA暗号問をいくつか重ね合わせてみました。が、ぶっちゃけ
ソースコード
sagemathでときました
from Crypto.Util.number import *
import gmpy2
from params import *
ms = []
cnt = 0
ans_ns = []
ans_ms = []
nn = 1
memo = {}
for i in range(len(ns)):
n = ns[i]
c = cs[i]
p = factor(n)[0][0]
q = factor(n)[1][0]
phi = (p-1) * (q-1)
g, d, _ = xgcd(e, phi)
if g not in memo:
memo[g] = 0
memo[g] += 1
print(g)
if g == 4:
cnt += 1
ans_ms.append(int(pow(c,d,n)))
ans_ns.append(n)
nn *= n
print(memo)
print(int(cnt))
print(int(nn).bit_length())
print(long_to_bytes(crt(ans_ms, ans_ns).nth_root(4)))
Discussion