1. 从CTF赛场看RSA算法的攻防本质
第一次在CTF比赛中遇到RSA密码题时,我盯着那串十六进制密文发了半小时呆。作为非科班出身的选手,当时连模数N和公钥e的关系都理不清。直到后来系统研究了数论基础,才发现RSA看似简单的算法背后,藏着无数精妙的数学陷阱。今天我们就来拆解CTF中RSA题型的九种致命攻击姿势,从最基础的因数分解到Coppersmith高阶攻击,手把手带你看透出题人的套路。
RSA作为目前最广泛使用的非对称加密算法,其安全性建立在"大整数分解难题"之上。但在CTF竞赛中,出题人往往会故意设置特殊条件来降低难度——比如使用相近的素数、过小的加密指数,或者泄露部分私钥信息。这些"不完美"的RSA实现,正是密码学爱好者最好的练兵场。
2. RSA算法核心原理速成课
2.1 密钥生成背后的数学魔法
RSA的密钥生成过程就像在构造一个数学谜题:
- 随机选择两个大素数p和q(CTF中通常为512bit或1024bit)
- 计算模数N = p × q(这个乘积将成为破解的关键)
- 计算欧拉函数φ(N) = (p-1)(q-1)
- 选取公钥e,满足1 < e < φ(N)且与φ(N)互质
- 计算私钥d ≡ e⁻¹ mod φ(N)
举个具体例子:当p=61, q=53时:
- N = 61×53 = 3233
- φ(N) = 60×52 = 3120
- 选择e=17(与3120互质)
- 计算d ≡ 17⁻¹ mod 3120 = 2753
2.2 加解密过程的数论实现
加密过程:对明文m,计算密文c ≡ mᵉ mod N
解密过程:对密文c,计算明文m ≡ cᵈ mod N
这里的关键在于欧拉定理——当m与N互质时,m^φ(N) ≡ 1 mod N。因此解密时:
cᵈ ≡ (mᵉ)ᵈ ≡ m^(e×d) ≡ m^(kφ(N)+1) ≡ m mod N
实战提示:在CTF中,明文m通常被转换为ASCII码或十六进制表示的整数。当m超过N时(即未进行分组加密),会导致直接解密失败。
3. CTF常见RSA攻击手法全图谱
3.1 基础篇——模数分解的艺术
3.1.1 小素数爆破
当N较小时(如小于512bit),可以用工具直接分解:
bash复制# 使用factordb在线分解
curl http://factordb.com/api?query=12345678901234567890
# 本地用yafu分解
yafu "factor(12345678901234567890)"
3.1.2 相近素数攻击
当p和q过于接近时,存在:
|p-q| < N^(1/4)
此时可以用费马分解法:
python复制from gmpy2 import isqrt
N = 0x1234...
a = isqrt(N) + 1
b2 = a*a - N
while not is_square(b2):
a += 1
b2 = a*a - N
p = a - isqrt(b2)
q = a + isqrt(b2)
3.2 进阶篇——数学漏洞的精准打击
3.2.1 低加密指数攻击
当e=3且明文很短时,可能满足mᵉ < N,此时直接开方:
python复制from gmpy2 import iroot
c = 0x123... # 密文
m = iroot(c, 3)[0]
3.2.2 共模攻击
当相同的明文用两个不同的公钥(e₁,e₂)加密,且gcd(e₁,e₂)=1时:
python复制def common_modulus_attack(c1, c2, e1, e2, N):
_, u, v = gcdext(e1, e2)
m = (pow(c1,u,N) * pow(c2,v,N)) % N
return m
3.3 高阶篇——Coppersmith的降维打击
3.3.1 已知高位攻击
当知道p或q的高位比特时(通常泄露50%以上):
python复制load('coppersmith.sage')
p_high = 0x12340000... # 已知p的高位
kbits = 128 # 未知的比特数
p = p_high << kbits
PR.<x> = PolynomialRing(Zmod(N))
f = x + p
roots = f.small_roots(X=2^kbits, beta=0.4)
3.3.2 Boneh-Durfee攻击
当私钥d满足d < N^0.292时,即使e很大也能破解:
python复制# 需要专门的Boneh-Durfee实现
# 通常使用SageMath的现成脚本
4. 实战演练:三道经典CTF题详解
4.1 [例题1] 基础因数分解
题目给出:
code复制N = 1522605027922533360535618378132637429718068114961380688657908494580122963258952897654000350692006139
e = 65537
c = 110644875422336073350488613774418819991169603750711465190260581119043921549811353108399064284589038384
解题步骤:
- 用factordb分解N得到:
p = 37975227936943673922808872755445627854565536638199
q = 40094690950920881030683735292761468389214899724061 - 计算φ(N) = (p-1)(q-1)
- 求d ≡ e⁻¹ mod φ(N)
- 解密m ≡ cᵈ mod N
4.2 [例题2] Wiener攻击实战
题目特征:e特别大(接近N的大小)
python复制def wiener_attack(e, n):
# 连分数展开
def cf_expansion(n, d):
...
# 渐进分数计算
def convergents(cf):
...
# 攻击主逻辑
for k, d in convergents(cf_expansion(e, n)):
if k == 0: continue
phi = (e*d -1)//k
# 解方程x² - (n-phi+1)x + n = 0
b = n - phi + 1
disc = b*b - 4*n
if disc >= 0:
t = isqrt(disc)
if t*t == disc and (b+t)%2==0:
return d
4.3 [例题3] LSB Oracle攻击
当服务器能返回解密结果的奇偶性时:
python复制def lsb_oracle_attack(c, n, e, oracle):
multiplier = pow(2, e, n)
low = 0
high = n
for i in range(n.bit_length()):
c = (c * multiplier) % n
if oracle(c) == 'odd':
low = (low + high) // 2
else:
high = (low + high) // 2
return high
5. 防御之道:如何写出安全的RSA实现
5.1 参数选择黄金法则
- 素数长度:至少2048bit(CTF中常用512/1024bit降低难度)
- 素数生成:使用强素数(p-1和p+1都有大素因子)
- 加密指数:e=65537是理想选择(平衡安全与效率)
- 私钥保护:d > N^0.5(防止Wiener攻击)
5.2 常见错误检查清单
- 检查|p-q|是否足够大(应大于2^(N.bit_length()//2 - 100))
- 验证gcd(e,φ(N))=1
- 避免使用固定明文或短明文(需OAEP填充)
- 不同用户绝对不要共享模数N
5.3 侧信道防御技巧
- 实现恒定时间解密算法
- 屏蔽幂运算的分支预测
- 添加随机延迟对抗时序分析
6. 工具链与学习资源
6.1 必备工具包
bash复制# 因数分解
yafu "factor(123456)"
# 计算模逆元
python -c "print(pow(3, -1, 7))"
# RSA综合工具
rsactftool -n 123456 -e 65537 --uncipher 0x1234
6.2 推荐学习路径
- 《应用密码学》Bruce Schneier(理论基础)
- Cryptopals挑战赛(实战编程)
- CTFtime.org的RSA题目归档(最新题型)
记得第一次成功分解1024bit RSA时,我在凌晨三点的实验室里差点喊出声来。那种用数学武器击碎加密屏障的快感,正是密码学最迷人的地方。下次遇到RSA题目时,不妨先问问自己:出题人这次又埋了什么彩蛋?