这道来自HDCTF2019的"basic rsa"题目,是一个典型的RSA加密破解挑战。作为密码学领域最广为人知的非对称加密算法,RSA在CTF比赛中出现的频率极高。题目给出了加密所需的全部核心参数,包括两个大素数p和q、公钥指数e以及密文c,我们的目标是通过这些信息还原出原始明文flag。
RSA算法的基础数学原理建立在大数分解难题之上。其核心流程包含以下几个关键步骤:
密钥生成:
加密过程:
解密过程:
在实际应用中,RSA的安全性依赖于大数分解的困难性——当n足够大时(现代标准通常要求2048位以上),从n反推p和q在计算上是不可行的。但在这个题目中,p和q已经直接给出,大大简化了解密难度。
题目提供了以下关键参数:
python复制p = 262248800182277040650192055439906580479
q = 262854994239322828547925595487519915551
e = 65533
c = 27565231154623519221597938803435789010285480123476977081867877272451638645710
首先我们需要验证这些参数的有效性:
素数验证:
虽然题目声明p和q是素数,但在实际解题中最好进行验证。可以使用Miller-Rabin素性测试:
python复制from Crypto.Util.number import isPrime
print(isPrime(p)) # 应返回True
print(isPrime(q)) # 应返回True
模数计算:
n = p × q = 689627824760175039774843258898750439853
这个78位的数字在现代密码学标准中算是非常小的,普通计算机可以在毫秒级完成相关运算。
公钥指数分析:
e=65533与常见的RSA公钥指数65537非常接近。这两个数字都是素数,且二进制表示中只有两个1(65533=0xFFFD,65537=0x10001),这使得模幂运算可以通过快速算法高效完成。
欧拉函数φ(n)表示小于n且与n互质的正整数的个数。对于n=pq的情况:
φ(n) = (p-1)(q-1) = 689627824760175039249139554056130207800
计算过程:
python复制phi = (p - 1) * (q - 1)
私钥d是公钥e关于φ(n)的模逆元,即满足:
e × d ≡ 1 mod φ(n)
在Python 3.8+中,可以直接使用内置的pow函数计算模逆元:
python复制d = pow(e, -1, phi)
对于较早的Python版本,可以使用扩展欧几里得算法实现,或者借助gmpy2库:
python复制import gmpy2
d = gmpy2.invert(e, phi)
得到私钥d后,解密就是计算:
m ≡ cᵈ mod n
同样使用pow函数的三参数形式进行模幂运算:
python复制m = pow(c, d, n)
python复制from Crypto.Util.number import long_to_bytes
# 题目给定参数
p = 262248800182277040650192055439906580479
q = 262854994239322828547925595487519915551
e = 65533
c = 27565231154623519221597938803435789010285480123476977081867877272451638645710
# 计算中间参数
n = p * q
phi = (p - 1) * (q - 1)
# 计算私钥d
try:
d = pow(e, -1, phi) # Python 3.8+
except ValueError:
# 如果e和phi不互质,RSA无法正常工作
print("Error: e and phi are not coprime")
exit()
# 解密
m = pow(c, d, n)
# 转换为可读格式
flag = long_to_bytes(m)
print(f"Flag: {flag.decode()}")
推荐版本:Python 3.8+
版本检查:
bash复制python3 --version
如果使用较旧Python版本,需要安装额外库:
pycryptodome:
bash复制pip install pycryptodome
这个库提供了Crypto.Util.number模块,包含long_to_bytes等实用函数
gmpy2:
bash复制pip install gmpy2
提供高性能的大数运算支持,特别是模逆元计算
如果环境限制无法使用上述方法,可以考虑以下替代方案:
手动实现扩展欧几里得算法:
python复制def extended_gcd(a, b):
if b == 0:
return a, 1, 0
else:
g, x, y = extended_gcd(b, a % b)
return g, y, x - (a // b) * y
def modinv(a, m):
g, x, y = extended_gcd(a, m)
if g != 1:
return None # 无逆元
else:
return x % m
使用sympy库:
python复制from sympy import mod_inverse
d = mod_inverse(e, phi)
ValueError: base is not invertible for the given modulus
OverflowError: int too large to convert to float
AttributeError: module 'Crypto' has no attribute 'Util'
中间结果验证:
python复制print(f"n: {n}")
print(f"phi: {phi}")
print(f"d: {d}")
print(f"e*d mod phi: {(e*d) % phi}") # 应等于1
加密-解密闭环测试:
python复制test_m = 123456789
test_c = pow(test_m, e, n)
decrypted = pow(test_c, d, n)
assert test_m == decrypted
性能优化:
RSA算法的正确性基于欧拉定理:对于任何与n互质的整数a,有:
a^φ(n) ≡ 1 mod n
因此:
c^d ≡ (m^e)^d ≡ m^(ed) ≡ m^(kφ(n)+1) ≡ (m^φ(n))^k × m ≡ 1^k × m ≡ m mod n
大素数选择:
填充方案:
侧信道攻击防护:
密钥生成:
性能优化:
协议层面安全:
在解决这类基础RSA题目时,有几个关键点值得注意:
参数验证:即使题目给出了参数,也应该进行基本验证(如素数性检查、n=pq验证)
边界情况处理:编写脚本时要考虑各种可能的异常情况(如e和φ(n)不互质)
环境兼容性:确保代码在不同Python版本和环境中的可移植性
调试输出:添加适当的中间结果输出,便于验证各步骤的正确性
性能考量:虽然本题数据量小,但对于更大的数字,需要考虑算法效率
在实际CTF比赛中,RSA题目往往会设置各种"陷阱"或特殊条件,因此理解算法的数学基础比记住解题模板更为重要。建议深入学习数论知识,特别是模运算、欧拉定理、中国剩余定理等内容,这些不仅是理解RSA的基础,也是解决更复杂密码学问题的关键。