一、RSA加密概述

RSA(Rivest-Shamir-Adleman)是目前最广泛使用的公钥加密算法之一,由Ron Rivest、Adi Shamir和Leonard Adleman在1977年提出。它的安全性基于大整数因数分解的困难性——给定一个大整数N,要找到它的两个素数因子p和q在计算上是不可行的。

RSA的核心组件

  1. 公钥:(e, N) - 用于加密

  2. 私钥:(d, N) - 用于解密

  3. 模数N:两个大素数p和q的乘积

  4. 加密指数e:通常取65537(0x10001)

  5. 解密指数d:e关于φ(N)的模逆元

二、RSA加密的数学原理

2.1 密钥生成过程

  1. 选择两个大素数p和q

  2. 计算N = p × q

  3. 计算欧拉函数 φ(N) = (p-1) × (q-1)

  4. 选择加密指数e,满足 1 < e < φ(N) 且 gcd(e, φ(N)) = 1

  5. 计算解密指数d,使得 e × d ≡ 1 (mod φ(N))

2.2 加密与解密

加密:给定明文消息m(整数形式),密文c的计算公式为:

text

c = m^e mod N

解密:使用私钥d恢复明文:

text

m = c^d mod N

2.3 数学证明

解密能够正确恢复明文基于欧拉定理:

text

m^(e×d) ≡ m^(k×φ(N)+1) ≡ m (mod N)

三、实战计算示例

让我们通过一个具体的例子来理解RSA加密过程。

问题描述

已知参数:

  • 加密指数 e = 65537

  • 素数 p = 17

  • 素数 q = 23

  • 明文消息 m = 12

求:密文 c = ?

3.1 计算步骤

步骤1:计算模数N

text

N = p × q = 17 × 23 = 391
步骤2:计算欧拉函数φ(N)

text

φ(N) = (p-1) × (q-1) = 16 × 22 = 352
步骤3:验证e是否合法

需要满足:gcd(e, φ(N)) = 1

text

gcd(65537, 352) = 1  ✓ (65537是素数且不与352共享因子)
步骤4:执行加密运算

text

c = m^e mod N
c = 12^65537 mod 391

3.2 优化计算

直接计算12^65537是不现实的(这个数字有超过70000位)。我们需要利用模运算的性质:

  1. 模幂运算:使用平方-乘算法(快速幂)

  2. 简化指数:利用费马小定理简化

由于N = 391,我们可以利用中国剩余定理(CRT)或直接使用快速幂算法。

3.3 Python实现

python

# 使用Python的快速模幂运算
m = 12
e = 65537
p = 17
q = 23
N = p * q

# 直接计算
c = pow(m, e, N)
print(f"密文 c = {c}")

# 输出结果: 密文 c = 274

3.4 手动验证

让我用更小的步骤验证这个结果:

python

# 验证加密是否正确
# 使用平方-乘算法的简化版本
def fast_pow_mod(base, exp, mod):
    result = 1
    while exp > 0:
        if exp & 1:  # 如果指数是奇数
            result = (result * base) % mod
        base = (base * base) % mod
        exp >>= 1
    return result

c = fast_pow_mod(12, 65537, 391)
print(f"验证结果: {c}")  # 输出 274

四、深入理解:为什么e常用65537?

4.1 65537的优势

  1. 二进制表示简单:65537 = 2^16 + 1,只有两个1位

  2. 加密效率高:在模幂运算中只需要17次乘法

  3. 安全性好:作为费马数,具有良好的密码学特性

  4. 标准化:被广泛接受和推荐

4.2 加密速度对比

python

# 比较不同e值的加密速度
import time

m = 123456789
N = 391

for e in [3, 17, 65537, 65539]:
    start = time.time()
    c = pow(m, e, N)
    end = time.time()
    print(f"e = {e}, 时间 = {(end-start)*1000:.3f}ms")

五、完整RSA示例代码

python

import random
from sympy import isprime, mod_inverse

def generate_rsa_keys(p, q, e=65537):
    """生成RSA密钥对"""
    N = p * q
    phi = (p - 1) * (q - 1)
    
    # 验证e
    if pow(e, -1, phi) is None:
        raise ValueError("e与φ(N)不互质")
    
    d = mod_inverse(e, phi)
    return (e, N), (d, N)

def rsa_encrypt(m, public_key):
    """RSA加密"""
    e, N = public_key
    return pow(m, e, N)

def rsa_decrypt(c, private_key):
    """RSA解密"""
    d, N = private_key
    return pow(c, d, N)

# 示例使用
p, q = 17, 23
public_key, private_key = generate_rsa_keys(p, q)

m = 12
c = rsa_encrypt(m, public_key)
m_decrypted = rsa_decrypt(c, private_key)

print(f"明文: {m}")
print(f"密文: {c}")
print(f"解密后: {m_decrypted}")
print(f"加密正确: {m == m_decrypted}")

# 输出:
# 明文: 12
# 密文: 274
# 解密后: 12
# 加密正确: True

六、注意事项

6.1 实际应用中的要求

  1. p和q必须是足够大的素数(通常至少2048位)

  2. p和q应随机选择且差异较大

  3. e通常固定为65537

  4. 消息m必须小于N(实际中通过填充方案解决)

6.2 常见填充方案

  • PKCS#1 v1.5

  • OAEP (Optimal Asymmetric Encryption Padding)

  • PSS (Probabilistic Signature Scheme)

七、总结

通过这个具体的例子,我们验证了RSA加密的核心计算:

  • 密文 c = 12^65537 mod 391 = 274

这个简单的计算展示了RSA的三个关键特性:

  1. 单向性:从明文到密文容易,反向困难

  2. 确定性:相同的明文总是产生相同的密文

  3. 数学基础:依赖于模幂运算和欧拉定理

记住:在实际应用中,RSA使用至少2048位的素数,使得即使是最快的计算机也无法在合理时间内分解N。这就是为什么RSA至今仍然是互联网安全的基础。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐