简单理解
案例一
p=3, q=5 (实际要用几百位的大数!)
n = 15
φ(n) = (3-1)×(5-1) = 8
选 e=3(因为与8互质)
计算d:3×d ≡ 1 (mod 8)
3×3=9,9÷8=1余1 ✅
所以 d=3
加密:m=2(明文)
c = 2³ mod 15 = 8 mod 15 = 8
解密:
m' = 8³ mod 15 = 512 mod 15 = 2 ✓
案例二
设定pqe
p = 13
q = 17
n = p × q = 13 × 17 = 221
φ(n) = (p-1) × (q-1)
= (13-1) × (17-1)
= 12 × 16 = 192
选择 e = 5(满足:1 < e < 192,且与192互质)
检查:gcd(5, 192) = 1 ✅
得出公钥 (e, n)
公钥 = (e, n) = (5, 221)
寻找私钥d
e × d ≡ 1 (mod φ(n))
5 × d ≡ 1 (mod 192)
找 d 使得 5×d ÷ 192 余 1
试一试:
5×1 = 5 → 5 mod 192 = 5 ❌ 不是1
5×2 = 10 → 10 mod 192 = 10 ❌
...
5×77 = 385 → 385÷192 = 2 余 1 ✅
所以 d = 77
得出私钥 (d, n)
私钥 = (d, n) = (77, 221)
公钥加密
明文 m = 7
密文 c = mᵉ mod n
= 7⁵ mod 221
计算:
7² = 49
7⁴ = (7²)² = 49² = 2401
7⁵ = 7⁴ × 7 = 2401 × 7 = 16807
现在算 16807 mod 221:
221 × 76 = 16796
16807 - 16796 = 11
所以 c = 11
密文 c = 11
私钥解密
解密 m' = cᵈ mod n
= 11⁷⁷ mod 221
11¹ mod 221 = 11
11² = 121
11⁴ = (11²)² = 121² = 14641 mod 221
= 14641 ÷ 221 = 66 余 55
= 55
11⁸ = (11⁴)² = 55² = 3025 mod 221
= 3025 ÷ 221 = 13 余 152
= 152
...(一直算到11⁷⁷)
11⁷⁷ mod 221 = 7 ✅
计算私钥
代码
python
# 定义两个大素数
p = 473398607161 # 第一个大素数
q = 2147483647 # 第二个大素数
e = 17 # 公钥指数
# 计算模数 n = p * q
n = p * q
# 计算欧拉函数 φ(n) = (p-1) * (q-1)
phi_n = (p-1) * (q-1)
# 扩展欧几里得算法,用于求解ax + by = gcd(a,b),如gcd(30, 12) = 6,其实就是求余
# gcd(Greatest Common Divisor,最大公约数)是指两个或多个整数共有约数(因数)中最大的一个。
def extended_gcd(a, b):
if b == 0:
# 当b为0时,返回(1, 0, a)
return (1, 0, a)
else:
# 递归计算
x0, y0, g = extended_gcd(b, a % b)
# 根据递归结果计算当前系数
x = y0
y = x0 - (a // b) * y0
return (x, y, g)
# 计算模逆元,即求解 a*x ≡ 1 (mod m),如3 × 4 = 12 ≡ 1 (mod 11),返回值为4%12的值
def mod_inverse(a, m):
# 使用扩展欧几里得算法求解
x, y, g = extended_gcd(a, m)
if g != 1:
# 如果最大公约数不为1,则模逆不存在
raise ValueError("模逆不存在")
else:
# 返回模逆元,确保结果为正数
return x % m
# 计算私钥指数d,即e关于φ(n)的模逆元
d = mod_inverse(e, phi_n)
print("d =", d) # 输出私钥指数d
运行结果
powershell
d = 837212984518464651473
解释p、q、e
对于RSA加密算法来说,p、q、e的选择不是可以随便写的,需要满足特定的数学条件:
1. p和q必须是素数(这是基础要求,如果不是的话,就很容易被破解)
- 代码中:473398607161 和 2147483647 都必须是真正的素数
2. p和q应该足够大且长度相近
- 现代RSA通常要求2048位以上(约600位十进制数)
- 案例中的p是12位,q只有7位,大小差异太大,安全性低
3. e的选择限制
- e必须是整数,且 1 < e < φ(n)
- e与φ(n)必须互质(gcd(e, φ(n)) = 1)
- 常用e值:3, 17, 65537(这些是费马素数,计算效率高)
4. 安全性要求
- p和q应该是随机生成的大素数
- p-1和q-1都应该有大素因子(防止Pollard's p-1攻击)
- p和q不应该太接近(防止费马分解法)
归纳
不可以随便写,必须满足:
- p、q都是大素数(真正测试过的)
- p ≠ q
- e与φ(n)互质
- 满足安全要求(足够大、随机等)
解释模逆元:mod_inverse
模逆元 是指:对于给定的整数 a 和模数 m,找到一个整数 x,使得:
a × x ≡ 1 (mod m)
等价于:a × x mod m = 1
例子1:求 3 在模 11 下的逆元
3 × 4 = 12
12 ÷ 11 = 1 余 1
所以 12 ≡ 1 (mod 11)
因此 3 的模逆元是 4(在模 11 下)
记作:3⁻¹ ≡ 4 (mod 11)
例子2:求 7 在模 15 下的逆元
目标 :找到 x 使得 7 × x ≡ 1 (mod 15)
方法1:穷举尝试(小模数时)
7 × 1 = 7 → 7 mod 15 = 7 ❌ 不是1
7 × 2 = 14 → 14 mod 15 = 14 ❌
7 × 3 = 21 → 21 mod 15 = 6 ❌
7 × 4 = 28 → 28 mod 15 = 13 ❌
7 × 5 = 35 → 35 mod 15 = 5 ❌
7 × 6 = 42 → 42 mod 15 = 12 ❌
7 × 7 = 49 → 49 mod 15 = 4 ❌
7 × 8 = 56 → 56 mod 15 = 11 ❌
7 × 9 = 63 → 63 mod 15 = 3 ❌
7 × 10 = 70 → 70 mod 15 = 10 ❌
7 × 11 = 77 → 77 mod 15 = 2 ❌
7 × 12 = 84 → 84 mod 15 = 9 ❌
7 × 13 = 91 → 91 mod 15 = 1 ✅ 找到了!
结果 :7 × 13 = 91 ≡ 1 (mod 15)
所以 7⁻¹ ≡ 13 (mod 15)
方法2:扩展欧几里得算法(标准方法)
求 extended_gcd(7, 15):
15 = 7×2 + 1 → 1 = 15 - 7×2
→ 1 = 7×(-2) + 15×1
得到:x = -2, y = 1, gcd = 1
模逆元:(-2) mod 15 = 13
例子3:求 5 在模 26 下的逆元
目标 :找到 x 使得 5 × x ≡ 1 (mod 26)
方法1:穷举验证:
5 × 1 = 5 → 5 mod 26 = 5 ❌
5 × 2 = 10 → 10 mod 26 = 10 ❌
5 × 3 = 15 → 15 mod 26 = 15 ❌
5 × 4 = 20 → 20 mod 26 = 20 ❌
5 × 5 = 25 → 25 mod 26 = 25 ❌
5 × 6 = 30 → 30 mod 26 = 4 ❌
5 × 7 = 35 → 35 mod 26 = 9 ❌
5 × 8 = 40 → 40 mod 26 = 14 ❌
5 × 9 = 45 → 45 mod 26 = 19 ❌
5 × 10 = 50 → 50 mod 26 = 24 ❌
5 × 11 = 55 → 55 mod 26 = 3 ❌
5 × 12 = 60 → 60 mod 26 = 8 ❌
5 × 13 = 65 → 65 mod 26 = 13 ❌
5 × 14 = 70 → 70 mod 26 = 18 ❌
5 × 15 = 75 → 75 mod 26 = 23 ❌
5 × 16 = 80 → 80 mod 26 = 2 ❌
5 × 17 = 85 → 85 mod 26 = 7 ❌
5 × 18 = 90 → 90 mod 26 = 12 ❌
5 × 19 = 95 → 95 mod 26 = 17 ❌
5 × 20 = 100 → 100 mod 26 = 22 ❌
5 × 21 = 105 → 105 mod 26 = 1 ✅ 找到了!
结果 :5 × 21 = 105 ≡ 1 (mod 26)
所以 5⁻¹ ≡ 21 (mod 26)
方法2:扩展欧几里得算法验证:
26 = 5×5 + 1 → 1 = 26 - 5×5
→ 1 = 5×(-5) + 26×1
得到:x = -5, y = 1, gcd = 1
模逆元:(-5) mod 26 = 21
为什么需要模逆元?
1. RSA解密的核心
在RSA中:
- 加密:
c ≡ mᵉ (mod n) - 解密:
m ≡ cᵈ (mod n)
其中d必须满足:e×d ≡ 1 (mod φ(n))
所以d就是e在模φ(n)下的逆元
2. 数学基础
因为欧拉定理:m^φ(n) ≡ 1 (mod n)
解密过程:c^d ≡ (m^e)^d ≡ m^(ed) (mod n)
由于 ed ≡ 1 (mod φ(n)),即 ed = kφ(n) + 1
所以 m^(ed) ≡ m^(kφ(n)+1) ≡ (m^φ(n))^k × m ≡ 1^k × m ≡ m (mod n)
不存在逆元的情况
如果 gcd(a, m) ≠ 1,则 a 在模 m 下没有逆元。
示例:
求 2 在模 4 下的逆元:
假设存在 x 使得 2x ≡ 1 (mod 4)
2x 在模 4 下只能是 0 或 2,不可能为 1
因为 gcd(2, 4) = 2 ≠ 1
其他替代用法
用invert效果与mod_inverse效果相同
python
from gmpy2 import invert
int(invert(3, 11))
归纳
模逆元:
- 是模运算中的"倒数"
- 存在条件:
gcd(a, m) = 1 - 在RSA中用于计算私钥
d - 可通过扩展欧几里得算法高效计算
代码中的 mod_inverse 函数正是利用扩展欧几里得算法求解 ax + my = 1 中的 x,然后取模得到正数解。
公钥加密
代码
python
# RSA参数
p = 473398607161 # 第一个大素数
q = 2147483647 # 第二个大素数
e = 17 # 公钥指数
m = 123123 # 要加密的明文
# 计算模数 n = p * q
n = p * q
# 计算密文 c = m^e mod n
c = pow(m, e, n)
# 输出结果
print("模数 n =", n)
print("密文 c =", c)
运行结果
powershell
模数 n = 1016615767390824596167
密文 c = 856820935524006748078
私钥解密
代码
powershell
ciphertext = 856820935524006748078 # 密文
# 解密函数:m = c^d mod n
def rsa_decrypt(ciphertext, d, n):
"""
RSA解密函数
ciphertext: 密文(整数)
d: 私钥指数
n: 模数
返回解密后的明文
"""
return pow(ciphertext, d, n)
decrypted_text = rsa_decrypt(ciphertext, d, n)
print(f"解密结果 m' = c^d mod n = {decrypted_text}")
print(f"\n公钥: (e, n) = ({e}, {n})")
print(f"私钥: (d, n) = ({d}, {n})")
运行结果
powershell
解密结果 m' = c^d mod n = 123123
公钥: (e, n) = (17, 1016615767390824596167)
私钥: (d, n) = (837212984518464651473, 1016615767390824596167)