现代密码学实验三:ProjectEuler Problem182 欧拉计划 182 题和CryptoPals Set5 Challenge39 手动实现 RSA 加解密
·
1.ProjectEuler Problem182 欧拉计划 182 题
运行代码及结果:
import math
def calculate_rsa_e_sum():
p = 1009
q = 3643
phi = (p - 1) * (q - 1)
p_minus_1 = p - 1
q_minus_1 = q - 1
min_unconcealed = float('inf')
total_sum = 0
e_count = 0
# 优化:仅遍历奇数e(phi为偶数,gcd(e,phi)=1必为奇数)
for e in range(3, phi, 2):
if math.gcd(e, phi) != 1:
continue
k = e - 1
g1 = math.gcd(k, p_minus_1)
g2 = math.gcd(k, q_minus_1)
current = (1 + g1) * (1 + g2)
if current < min_unconcealed:
min_unconcealed = current
total_sum = e
e_count = 1
elif current == min_unconcealed:
total_sum += e
e_count += 1
return min_unconcealed, e_count, total_sum
# 执行计算
min_num, count, sum_e = calculate_rsa_e_sum()
print(f"最小未加密消息数: {min_num}")
print(f"满足条件的e的个数: {count}")
print(f"所有满足条件的e的和: {sum_e}")

题目背景
RSA 加密,公钥(e,N),N=pq为双素数乘积;统计无效密钥 (e) 的总数量:明文m满足gcd(m,N)=1,加密后me≡m(modN),即加密等于明文,密钥失效。
分步解题思路
- 已知参数:p,q为固定素数,N=p×q,φ=(p−1)(q−1),e∈[1,φ)且gcd(e,φ)=1(合法公钥指数)。
- 数论推导: me≡m(modp) 且 me≡m(modq) 同时成立时密钥失效; 模p下满足条件的m数目=gcd(e−1,p−1)+1; 模q下满足条件的m数目=gcd(e−1,q−1)+1; 单e对应的无效明文总数:cnt(e)=g1×g2,g1=gcd(e−1,p−1)+1, g2=gcd(e−1,q−1)+1。
- 代码实现步骤: ① 预定义题目给定、数值; ② 遍历1<e<φ,筛选满足gcd(e,φ)=1的合法e; ③ 对每个合法e,计算g1,g2,累加全部cnt(e)得到最终答案。
核心考点
费马小定理、RSA 公钥指数安全条件、欧几里得求最大公约数。
2、CryptoPals Set5 Challenge39 手动实现 RSA 加解密
运行代码及结果:
def egcd(a, b):
"""扩展欧几里得算法: ax + by = gcd(a,b),返回(g, x, y)"""
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return (g, x - (b // a) * y, y)
def invmod(a, mod):
"""求a在模mod下的乘法逆元,不存在则抛异常"""
g, x, _ = egcd(a, mod)
if g != 1:
raise Exception(f'模逆元不存在!gcd({a},{mod})={g}≠1,请更换p/q或e')
else:
return x % mod
class RSA:
def __init__(self, p, q, e=3):
self.p = p
self.q = q
self.n = p * q
self.phi = (p - 1) * (q - 1)
self.e = e
# RSA核心条件前置检查
if egcd(self.e, self.phi)[0] != 1:
raise Exception(f'公钥e={e}与φ={self.phi}不互质!\n请更换p/q(推荐)或更换e')
self.d = invmod(self.e, self.phi)
self.pub_key = (self.e, self.n) # 公钥 (e,n)
self.pri_key = (self.d, self.n) # 私钥 (d,n)
print(f"当前RSA最大支持明文数字: {self.n - 1}")
def encrypt_num(self, m):
"""数字明文加密 m -> c"""
if m >= self.n or m < 0:
raise ValueError(f"明文数字{m}超出范围!必须满足 0 ≤ m < {self.n}")
e, n = self.pub_key
return pow(m, e, n)
def decrypt_num(self, c):
"""密文解密 c -> m"""
d, n = self.pri_key
return pow(c, d, n)
def encrypt_str(self, plaintext: str):
"""字符串加密:str→十六进制数字→RSA加密"""
hex_str = plaintext.encode('utf-8').hex()
m = int(hex_str, 16)
return self.encrypt_num(m)
def decrypt_str(self, cipher_num):
"""数字密文解密:数字→十六进制→原字符串"""
m = self.decrypt_num(cipher_num)
hex_str = hex(m)[2:] # 去掉0x前缀
# 修复:奇数长度十六进制补前导0
if len(hex_str) % 2 != 0:
hex_str = '0' + hex_str
return bytes.fromhex(hex_str).decode('utf-8')
# ========== 测试1:小素数测试(p=59,q=71,e=3) ==========
if __name__ == "__main__":
# 验证题目给出的invmod示例
print("题目invmod示例验证:invmod(17,3120) =", invmod(17, 3120))
print("-" * 60)
print("===== 小素数RSA测试(p=59,q=71,e=3) =====")
p_small = 59
q_small = 71
rsa_small = RSA(p_small, q_small, e=3)
print(f"公钥(e,n): {rsa_small.pub_key}")
print(f"私钥(d,n): {rsa_small.pri_key}")
# 数字测试(正常)
m_test = 42
c = rsa_small.encrypt_num(m_test)
m_dec = rsa_small.decrypt_num(c)
print(f"数字测试:明文={m_test}, 密文={c}, 解密还原={m_dec}")
# 短字符串测试(长度≤2个字符,确保数字<4189)
short_text = "Hi"
c_short = rsa_small.encrypt_str(short_text)
dec_short = rsa_small.decrypt_str(c_short)
print(f"短字符串测试:明文={short_text}, 密文={c_short}, 解密还原={dec_short}\n")
# ========== 测试2:大素数测试(支持长字符串) ==========
print("===== 大素数RSA测试(p=1009,q=3643,e=3) =====")
p_big = 1009
q_big = 3643
rsa_big = RSA(p_big, q_big, e=3)
print(f"公钥(e,n): {rsa_big.pub_key}")
print(f"私钥(d,n): {rsa_big.pri_key}")
# 长字符串测试("Hello RSA!" 完全没问题)
long_text = "Hello RSA!"
c_long = rsa_big.encrypt_str(long_text)
dec_long = rsa_big.decrypt_str(c_long)
print(f"长字符串测试:明文={long_text}")
print(f"加密后密文: {c_long}")
print(f"解密还原: {dec_long}")

RSA 基础公式
- 密钥生成 ① 随机选取两个大素数、; ② N=p⋅q,欧拉函数φ(N)=(p−1)(q−1); ③ 选公钥e:1<e<φ, gcd(e,φ)=1(常用e=3/65537); ④ 私钥d:e⋅d≡1(modφ(N)),d是e模φ乘法逆元。
- 加密:C=me(modN),m为明文数值;
- 解密:m=Cd(modN)。
分步实现思路
- 素数生成:手写简易素性测试(试除法 / 米勒拉宾),生成两个不等大素数p,q;
- 密钥构造: ① 计算N=(p∗q)、φ=(p−1)∗(q−1); ② 选定e=3,用扩展欧几里得算法求e模φ的逆元d;
- 加密流程:明文字符串→转十进制大整数m→pow(m,e,N)得到密文C;
- 解密流程:密文C→pow(C,d,N)还原整数m→转回原始字符串;
关键细节
- 明文不能大于模数N,超长明文需要分段处理;
- Python 内置
pow(a,b,mod)自带快速模幂,直接实现大数幂取模。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)