
题目:
python
from Crypto.Util.number import *
from libnum import *
flag = b'NSSCTF{******}' + b'1010101010101010101010101010101010101010100010101010101010101010101101'
p = getPrime(512)
q = getPrime(512)
n = p*q
e = 65537
d = inverse(e, (p-1)*(q-1))
dp = d % (p-1)
m = s2n(flag)
c = pow(m, e, n)
print(f'n = {n}')
print(f'c = {c}')
print(f'dp = {dp}')
'''
n = 62950660589752377241535942010457460675378335694404721223426371627802159493655570041534480026979837056215567303530448462076388942749116962945931432723672826148999814815864738069663127706046027850586024555861960247057288826014343547293035737544457656904257388300461848219257240252715837662741274235378360898441
c = 26392919777656338278184497106215581599692023606797351841011065350738534402079717897589592521000832026751736045905247050532819571969784687491977953157313304550096179520376626220816081159472339787295872214912587497324709488986746768994907107727184468228540635002062232484115731701648311946527233449512543132274
dp = 7088497034630351463006975624795947102639056977565074157092915907376477955247769847204254053775159112398217033648894620506901638351932922911273150932128973
'''
题目分析
题目提供了以下参数:
-
n: RSA 模数 -
c: 密文 -
dp: 私钥指数 d 对 (p-1) 取模的结果,即 dp = d mod (p-1) -
e: 公钥指数,值为 65537
这是一个典型的 dp 泄露攻击,当我们知道 dp 时,可以恢复出私钥并解密密文。
数学原理
根据 RSA 定义:
-
d * e ≡ 1 mod φ(n),其中 φ(n) = (p-1)(q-1) -
dp = d mod (p-1) -
由 (2) 可得:
d = dp + k*(p-1),其中 k 是一个整数 -
将 (3) 代入 (1):
e * (dp + k*(p-1)) ≡ 1 mod (p-1) -
化简得:
e * dp ≡ 1 mod (p-1),即e * dp - 1 ≡ 0 mod (p-1)
这意味着 e*dp - 1 是 (p-1) 的倍数。我们可以通过遍历 k 来寻找 p 的值。
解题步骤
步骤 1:寻找 p
根据上述推导,我们有:
python
e * dp = 1 + k * (p-1)
其中 k 是 1 到 e 之间的整数(因为 dp < p-1)。
我们可以遍历所有可能的 k,检查 (e*dp - 1) 是否能被 k 整除,从而得到候选的 p:
python
p = (e*dp - 1)/k + 1
步骤 2:验证并计算 q
找到候选的 p 后,检查:
-
p 是否为整数
-
n 是否能被 p 整除
-
p 是否为素数(这里简化检查:n % p == 0)
如果满足条件,则:
python
q = n // p
步骤 3:计算私钥 d
使用公式:
python
φ(n) = (p-1) * (q-1)
d = e^(-1) mod φ(n) # 即 e 关于 φ(n) 的模逆元
步骤 4:解密密文
使用 RSA 解密公式:
python
m = c^d mod n
完整代码
python
from Crypto.Util.number import *
# 题目给出的参数
n = 62950660589752377241535942010457460675378335694404721223426371627802159493655570041534480026979837056215567303530448462076388942749116962945931432723672826148999814815864738069663127706046027850586024555861960247057288826014343547293035737544457656904257388300461848219257240252715837662741274235378360898441
c = 26392919777656338278184497106215581599692023606797351841011065350738534402079717897589592521000832026751736045905247050532819571969784687491977953157313304550096179520376626220816081159472339787295872214912587497324709488986746768994907107727184468228540635002062232484115731701648311946527233449512543132274
dp = 7088497034630351463006975624795947102639056977565074157092915907376477955247769847204254053775159112398217033648894620506901638351932922911273150932128973
e = 65537
# 步骤1:遍历 k 寻找 p
print("开始寻找素数 p...")
for k in range(2, e): # k 从 2 开始,因为 k=1 时 p 可能太大
# 检查 (e*dp - 1) 是否能被 k 整除
if (e * dp - 1) % k == 0:
# 计算候选的 p
p = (e * dp - 1) // k + 1
# 步骤2:验证 p
# 检查1: p 是否能整除 n
if n % p == 0:
print(f"找到可能的 k = {k}")
print(f"p = {p}")
# 计算 q
q = n // p
print(f"q = {q}")
# 验证 p 和 q 的乘积是否等于 n
if p * q == n:
print("验证成功: p * q == n")
# 步骤3:计算私钥 d
phi = (p - 1) * (q - 1)
d = inverse(e, phi) # 计算 e 关于 φ(n) 的模逆元
print(f"d = {d}")
# 步骤4:解密密文
m = pow(c, d, n)
print(f"解密得到的整数 m = {m}")
# 转换为字节串
flag = long_to_bytes(m)
print(f"解密得到的 flag = {flag}")
# 由于我们可能找到多个解,这里只取第一个有效的解
break
else:
print("验证失败: p * q != n")
else:
continue # 继续尝试下一个 k
print("\n解密完成!")
最后flag为
NSSCTF{CTFCTFNSSNSS}
总结
-
漏洞点:dp 泄露是 RSA 中常见的侧信道攻击,当攻击者知道 dp = d mod (p-1) 时,可以恢复私钥。
-
关键步骤 :利用关系式
e*dp ≡ 1 mod (p-1),通过遍历 k 来找到 p。 -
防御措施:在实际应用中,需要保护所有私钥参数,包括 d、dp、dq 等,避免信息泄露。