引言
摸鱼中。。。
[i春秋云上巅峰赛2021]crtrsa
题面:
加密的sage代码如下:
from secret import flagn,p,q
#p and q are two primes generated by getPrime
import random
def key_gen():
while True:
dp = random.randint(1,1<<20)
dq = random.randint(1,q-1)
if gcd(dp, p - 1) == 1 and gcd(dq, q - 1) == 1:
d = crt([dp,dq],[p-1,q-1])
phi = (p-1)*(q-1)
R = Integers(phi)
e = R(d)^-1
return p*q,e
n,e = key_gen()
print e
print n
print pow(flagn,int(e),n)
看代码的时候,数学关系很容易找,而且很多,感觉好像能行
最核心的是d = crt([dp,dq],[p-1,q-1])
,翻译成数学语言就是:
{
d
≡
d
p
m
o
d
d
q
d
≡
(
p
−
1
)
m
o
d
(
q
−
1
)
\begin{cases} d \equiv dp \space mod \space dq\\ d \equiv (p-1) \space mod \space (q-1) \end{cases}
{d≡dp mod dqd≡(p−1) mod (q−1)
还有一条隐藏的或者说是约定俗成的数学关系就是:
{
d
p
≡
d
m
o
d
(
p
−
1
)
d
q
≡
d
m
o
d
(
q
−
1
)
\begin{cases} dp \equiv d\space mod\space (p-1)\\ dq \equiv d\space mod\space (q-1) \end{cases}
{dp≡d mod (p−1)dq≡d mod (q−1)
(虽然当时不确定,鬼知道出题人会出什么幺蛾子,后来发现是我想多了)
其他的都是常规的RSA
看起来线索很多,但又无从下手
后来badm0nkey前辈提醒我,从dp下手爆破
因为dp = random.randint(1,1<<20)
,也就是说
1
≤
d
p
≤
1048576
1\leq dp \leq 1048576
1≤dp≤1048576,是容易遍历的
但是即使容易遍历,但是出了dp,其他相关的未知量也是未知的,遍历过程中怎么判断这个dp就是我们想要的呢?
比赛结束后,前辈给了我答案,推导过程如下:
首先,根据RSA加密算法,有
e
⋅
d
≡
1
m
o
d
(
p
−
1
)
(
q
−
1
)
e·d \equiv 1 \space mod \space (p-1)(q-1)
e⋅d≡1 mod (p−1)(q−1)
那么有
e
⋅
d
≡
1
m
o
d
(
p
−
1
)
e·d \equiv 1 \space mod \space (p-1)
e⋅d≡1 mod (p−1)
又
d
q
≡
d
m
o
d
(
q
−
1
)
dq \equiv d\space mod\space (q-1)
dq≡d mod (q−1)
故
e
⋅
d
q
≡
e
d
m
o
d
(
q
−
1
)
≡
1
m
o
d
(
q
−
1
)
e·dq \equiv ed\space mod\space (q-1) \equiv 1\space mod\space (q-1)
e⋅dq≡ed mod (q−1)≡1 mod (q−1)
故
∃
k
∈
Z
\exist k\in \mathbb{Z}
∃k∈Z,
s
.
t
.
s.t.
s.t.
e
⋅
d
p
=
1
+
k
(
p
−
1
)
e·dp=1+k(p-1)
e⋅dp=1+k(p−1)
移项得
e
⋅
d
p
−
1
=
k
(
p
−
1
)
e·dp-1=k(p-1)
e⋅dp−1=k(p−1)
由费马小定理,假如
a
a
a是一个整数,
p
p
p是一个质数,那么
a
p
−
a
a^{p} - a
ap−a是p的倍数,可以表示为
a
p
≡
a
m
o
d
p
a^p \equiv a \space mod\space p
ap≡a mod p
如果
a
a
a不是
p
p
p的倍数,这个定理也可以写成
a
p
−
1
≡
1
m
o
d
p
a^{p-1} \equiv 1 \space mod\space p
ap−1≡1 mod p
可以推出
a
k
(
p
−
1
)
≡
1
m
o
d
p
a^{k(p-1)} \equiv 1 \space mod\space p
ak(p−1)≡1 mod p
那么又
∃
t
∈
Z
\exist t\in \mathbb{Z}
∃t∈Z,
s
.
t
.
s.t.
s.t.
a
k
(
p
−
1
)
=
1
+
t
p
a^{k(p-1)} = 1+tp
ak(p−1)=1+tp
移项得
a
k
(
p
−
1
)
−
1
=
t
p
a^{k(p-1)} - 1=tp
ak(p−1)−1=tp
在模N的情况下也成立,也就是有
e
⋅
d
p
−
1
≡
k
(
p
−
1
)
m
o
d
N
e·dp-1\equiv k(p-1) \space mod \space N
e⋅dp−1≡k(p−1) mod N,则
a
e
⋅
d
p
−
1
−
1
≡
a
k
(
p
−
1
)
−
1
m
o
d
N
≡
t
p
m
o
d
N
a^{e·dp-1} - 1\equiv a^{k(p-1)} - 1 \space mod \space N \equiv tp \space mod \space N
ae⋅dp−1−1≡ak(p−1)−1 mod N≡tp mod N
所以,只要
g
c
d
(
a
e
⋅
d
p
−
1
,
N
)
≠
1
gcd(a^{e·dp-1}, N) \neq 1
gcd(ae⋅dp−1,N)=1,则这个dp就是我们想要的,并且
g
c
d
(
a
e
⋅
d
p
−
1
,
N
)
=
p
gcd(a^{e·dp-1}, N) =p
gcd(ae⋅dp−1,N)=p
解密代码如下:
from Crypto.Util.number import *
from tqdm import tqdm
e = 2953544268002866703872076551930953722572317122777861299293407053391808199220655289235983088986372630141821049118015752017412642148934113723174855236142887
N = 6006128121276172470274143101473619963750725942458450119252491144009018469845917986523007748831362674341219814935241703026024431390531323127620970750816983
c = 4082777468662493175049853412968913980472986215497247773911290709560282223053863513029985115855416847643274608394467813391117463817805000754191093158289399
for dp in tqdm(range(3, 1<<20, 2)):
tmp = e*dp-1
t = pow(3, tmp, N)
p = GCD(N, t-1)
if p != 1:
print("find p!")
q = N//p
phi = (p-1)*(q-1)
d = inverse(e, phi)
m = pow(c, d, N)
print(long_to_bytes(m))
break
结果为:
结语
以后可能要两日一更了,太多事情没干
希望继续坚持