RSA 算法 - 非对称加密的基石
·37 分钟阅读·7379 字··作者:xinglei.wang
什么是 RSA
RSA 是由 Ron Rivest、Adi Shamir 和 Leonard Adleman 于 1977 年发明的非对称加密算法,以三位发明者姓氏首字母命名。它是第一个同时支持加密和数字签名的公钥密码系统,至今仍广泛应用于安全通信、数字证书和身份认证等领域。
核心特性
| 特性 | 说明 |
|---|---|
| 非对称性 | 使用一对密钥:公钥加密,私钥解密 |
| 双向性 | 既可用于加密,也可用于数字签名 |
| 数学基础 | 基于大整数分解的困难性 |
| 密钥长度 | 常用 2048、3072、4096 位 |
对称加密 vs 非对称加密
对称加密 (AES):
发送方 ──[共享密钥]──▶ 加密 ──▶ 密文 ──▶ 解密 ──[共享密钥]──▶ 接收方
问题: 如何安全地传递共享密钥?
非对称加密 (RSA):
发送方 ──[接收方公钥]──▶ 加密 ──▶ 密文 ──▶ 解密 ──[接收方私钥]──▶ 接收方
优势: 公钥可以公开,只有私钥持有者能解密
应用场景
mindmap
root((RSA 应用))
数据加密
密钥交换
小数据加密
混合加密
数字签名
代码签名
文档签名
交易签名
身份认证
SSL/TLS 证书
SSH 登录
数字身份
密钥管理
密钥封装
密钥协商
证书链
数学基础
1. 模运算
模运算是 RSA 的核心数学工具:
# 模运算基础
"""
a mod n = a 除以 n 的余数
例如:
17 mod 5 = 2 (17 = 3 × 5 + 2)
-3 mod 7 = 4 (在 Python 中)
模运算性质:
(a + b) mod n = ((a mod n) + (b mod n)) mod n
(a × b) mod n = ((a mod n) × (b mod n)) mod n
(a^b) mod n = ((a mod n)^b) mod n
"""
def mod_exp(base: int, exp: int, mod: int) -> int:
"""
模幂运算 (快速幂算法)
计算 base^exp mod mod
时间复杂度: O(log exp)
"""
result = 1
base = base % mod
while exp > 0:
# 如果 exp 是奇数,乘以 base
if exp % 2 == 1:
result = (result * base) % mod
# exp 除以 2
exp = exp >> 1
# base 平方
base = (base * base) % mod
return result
# Python 内置函数
print(pow(7, 13, 11)) # 等价于 7^13 mod 11
2. 欧拉函数
欧拉函数 φ(n) 表示小于 n 且与 n 互质的正整数个数:
"""
欧拉函数定义:
φ(n) = |{k : 1 ≤ k ≤ n, gcd(k, n) = 1}|
重要性质:
1. φ(p) = p - 1,其中 p 是素数
2. φ(p × q) = (p - 1) × (q - 1),其中 p, q 是不同的素数
3. φ(p^k) = p^(k-1) × (p - 1)
RSA 中使用:
n = p × q (两个大素数的乘积)
φ(n) = (p - 1) × (q - 1)
"""
def euler_phi(n: int) -> int:
"""计算欧拉函数 (朴素算法,仅用于教学)"""
from math import gcd
count = 0
for i in range(1, n + 1):
if gcd(i, n) == 1:
count += 1
return count
# 验证性质
p, q = 11, 13
n = p * q # 143
print(f"φ({n}) = {euler_phi(n)}") # 120
print(f"(p-1)(q-1) = {(p-1) * (q-1)}") # 120
3. 欧拉定理与费马小定理
"""
欧拉定理:
若 gcd(a, n) = 1,则 a^φ(n) ≡ 1 (mod n)
费马小定理 (欧拉定理的特例):
若 p 是素数且 gcd(a, p) = 1,则 a^(p-1) ≡ 1 (mod p)
RSA 的数学基础:
由欧拉定理推导:
a^φ(n) ≡ 1 (mod n)
a^(k·φ(n)) ≡ 1 (mod n)
a^(k·φ(n)+1) ≡ a (mod n)
如果找到 e 和 d 使得 e·d ≡ 1 (mod φ(n)),即 e·d = k·φ(n) + 1
那么: (a^e)^d = a^(e·d) = a^(k·φ(n)+1) ≡ a (mod n)
这就是 RSA 加密和解密的数学原理!
"""
# 验证欧拉定理
a = 7
n = 143 # 11 × 13
phi_n = 120 # (11-1) × (13-1)
result = pow(a, phi_n, n)
print(f"{a}^{phi_n} mod {n} = {result}") # 应该等于 1
4. 模逆元
"""
模逆元定义:
若 a·b ≡ 1 (mod n),则 b 是 a 在模 n 下的逆元,记作 a^(-1) mod n
存在条件:
a 的模 n 逆元存在,当且仅当 gcd(a, n) = 1
计算方法:
1. 扩展欧几里得算法
2. 费马小定理 (当 n 是素数时): a^(-1) ≡ a^(n-2) (mod n)
"""
def extended_gcd(a: int, b: int) -> tuple:
"""
扩展欧几里得算法
返回 (gcd, x, y) 使得 a*x + b*y = gcd(a, b)
"""
if a == 0:
return b, 0, 1
gcd, x1, y1 = extended_gcd(b % a, a)
x = y1 - (b // a) * x1
y = x1
return gcd, x, y
def mod_inverse(a: int, n: int) -> int:
"""
计算 a 在模 n 下的逆元
"""
gcd, x, _ = extended_gcd(a % n, n)
if gcd != 1:
raise ValueError(f"{a} 在模 {n} 下没有逆元")
return (x % n + n) % n
# 示例: RSA 中计算私钥 d
e = 17 # 公钥指数
phi_n = 120 # φ(n) = (p-1)(q-1)
d = mod_inverse(e, phi_n)
print(f"d = {d}") # d = 113
print(f"验证: e·d mod φ(n) = {(e * d) % phi_n}") # 应该等于 1
RSA 密钥生成
生成流程
flowchart TD
classDef prime fill:#2b2d42,stroke:#8d99ae,stroke-width:2px,color:#edf2f4
classDef compute fill:#ffffff,stroke:#2b2d42,stroke-width:2px,color:#2b2d42
classDef key fill:#7209b7,stroke:#3a0ca3,stroke-width:2px,color:#ffffff
classDef output fill:#2ec4b6,stroke:#011627,stroke-width:2px,color:#ffffff
P["生成大素数 p"]:::prime
Q["生成大素数 q"]:::prime
N["计算 n = p × q"]:::compute
PHI["计算 φ(n) = (p-1)(q-1)"]:::compute
E["选择公钥指数 e<br/>1 < e < φ(n), gcd(e, φ(n)) = 1"]:::key
D["计算私钥指数 d<br/>d ≡ e^(-1) (mod φ(n))"]:::key
PUB["公钥 (n, e)"]:::output
PRI["私钥 (n, d)"]:::output
P --> N
Q --> N
N --> PHI
PHI --> E
E --> D
N --> PUB
E --> PUB
N --> PRI
D --> PRI
linkStyle default stroke:#8d99ae,stroke-width:2px,fill:none
Python 实现
import random
from typing import Tuple
def is_prime_miller_rabin(n: int, k: int = 40) -> bool:
"""
Miller-Rabin 素性测试
k: 测试轮数,k=40 时错误概率 < 2^(-80)
"""
if n < 2:
return False
if n == 2 or n == 3:
return True
if n % 2 == 0:
return False
# 将 n-1 写成 2^r × d 的形式
r, d = 0, n - 1
while d % 2 == 0:
r += 1
d //= 2
# 进行 k 轮测试
for _ in range(k):
a = random.randrange(2, n - 1)
x = pow(a, d, n)
if x == 1 or x == n - 1:
continue
for _ in range(r - 1):
x = pow(x, 2, n)
if x == n - 1:
break
else:
return False
return True
def generate_prime(bits: int) -> int:
"""生成指定位数的素数"""
while True:
# 生成随机奇数
candidate = random.getrandbits(bits)
candidate |= (1 << bits - 1) | 1 # 确保最高位和最低位为 1
if is_prime_miller_rabin(candidate):
return candidate
def generate_rsa_keypair(bits: int = 2048) -> Tuple[Tuple[int, int], Tuple[int, int]]:
"""
生成 RSA 密钥对
返回: ((n, e), (n, d)) = (公钥, 私钥)
"""
# 1. 生成两个大素数
p = generate_prime(bits // 2)
q = generate_prime(bits // 2)
# 确保 p ≠ q
while p == q:
q = generate_prime(bits // 2)
# 2. 计算 n 和 φ(n)
n = p * q
phi_n = (p - 1) * (q - 1)
# 3. 选择公钥指数 e
# 常用值: 65537 (0x10001),因为二进制只有两个 1,计算效率高
e = 65537
# 确保 gcd(e, φ(n)) = 1
from math import gcd
if gcd(e, phi_n) != 1:
# 如果不互质,选择其他值
e = 3
while gcd(e, phi_n) != 1:
e += 2
# 4. 计算私钥指数 d
d = mod_inverse(e, phi_n)
# 5. 清除敏感数据
p = q = phi_n = 0
return (n, e), (n, d)
# 生成密钥对
public_key, private_key = generate_rsa_keypair(2048)
print(f"公钥 n 位数: {public_key[0].bit_length()}")
print(f"公钥 e: {public_key[1]}")
print(f"私钥 d 位数: {private_key[1].bit_length()}")
Rust 实现
use num_bigint::{BigUint, RandBigInt, ToBigUint};
use num_traits::{One, Zero};
use rand::thread_rng;
/// RSA 密钥对
pub struct RsaKeyPair {
pub public_key: RsaPublicKey,
pub private_key: RsaPrivateKey,
}
pub struct RsaPublicKey {
pub n: BigUint,
pub e: BigUint,
}
pub struct RsaPrivateKey {
pub n: BigUint,
pub d: BigUint,
}
/// Miller-Rabin 素性测试
fn is_prime_miller_rabin(n: &BigUint, k: u32) -> bool {
let zero = BigUint::zero();
let one = BigUint::one();
let two = 2u32.to_biguint().unwrap();
if *n < two {
return false;
}
if *n == two || *n == 3u32.to_biguint().unwrap() {
return true;
}
if n % &two == zero {
return false;
}
// n-1 = 2^r × d
let mut r = 0u32;
let mut d = n - &one;
while &d % &two == zero {
r += 1;
d /= &two;
}
let mut rng = thread_rng();
let n_minus_one = n - &one;
let n_minus_two = n - &two;
'outer: for _ in 0..k {
let a = rng.gen_biguint_range(&two, &n_minus_two);
let mut x = a.modpow(&d, n);
if x == one || x == n_minus_one {
continue;
}
for _ in 0..r - 1 {
x = x.modpow(&two, n);
if x == n_minus_one {
continue 'outer;
}
}
return false;
}
true
}
/// 生成指定位数的素数
fn generate_prime(bits: u64) -> BigUint {
let mut rng = thread_rng();
let one = BigUint::one();
loop {
let mut candidate = rng.gen_biguint(bits);
// 设置最高位和最低位
candidate |= &one << (bits - 1);
candidate |= &one;
if is_prime_miller_rabin(&candidate, 40) {
return candidate;
}
}
}
/// 扩展欧几里得算法
fn extended_gcd(a: &BigUint, b: &BigUint) -> (BigUint, BigInt, BigInt) {
// 简化实现,实际使用 num-bigint-dig 库
unimplemented!("使用 num-bigint-dig 库的 mod_inverse")
}
/// 计算模逆元
fn mod_inverse(a: &BigUint, n: &BigUint) -> Option<BigUint> {
use num_integer::Integer;
let one = BigUint::one();
if a.gcd(n) != one {
return None;
}
// 使用扩展欧几里得算法
// 实际实现中使用 num-bigint-dig 库
Some(a.modpow(&(n - 2u32), n)) // 费马小定理方法 (仅当 n 为素数时有效)
}
/// 生成 RSA 密钥对
pub fn generate_rsa_keypair(bits: u64) -> RsaKeyPair {
// 1. 生成两个大素数
let p = generate_prime(bits / 2);
let q = generate_prime(bits / 2);
// 2. 计算 n 和 φ(n)
let n = &p * &q;
let one = BigUint::one();
let phi_n = (&p - &one) * (&q - &one);
// 3. 选择公钥指数 e = 65537
let e = 65537u32.to_biguint().unwrap();
// 4. 计算私钥指数 d
let d = mod_inverse(&e, &phi_n).expect("e 和 φ(n) 必须互质");
RsaKeyPair {
public_key: RsaPublicKey { n: n.clone(), e },
private_key: RsaPrivateKey { n, d },
}
}
使用密码学库 (推荐)
# 使用 cryptography 库 (推荐用于生产环境)
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
def generate_rsa_key_pair_crypto(key_size: int = 2048):
"""使用 cryptography 库生成 RSA 密钥对"""
# 生成私钥
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=key_size,
)
# 获取公钥
public_key = private_key.public_key()
return private_key, public_key
def serialize_keys(private_key, public_key):
"""序列化密钥为 PEM 格式"""
# 私钥 PEM
private_pem = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)
# 公钥 PEM
public_pem = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
return private_pem, public_pem
# 使用示例
private_key, public_key = generate_rsa_key_pair_crypto(2048)
private_pem, public_pem = serialize_keys(private_key, public_key)
print("私钥 (PEM):")
print(private_pem.decode())
print("\n公钥 (PEM):")
print(public_pem.decode())
加密与解密
基本原理
加密: C = M^e mod n
解密: M = C^d mod n
其中:
- M: 明文 (必须小于 n)
- C: 密文
- (n, e): 公钥
- (n, d): 私钥
数学证明:
C^d mod n = (M^e)^d mod n = M^(e·d) mod n
因为 e·d ≡ 1 (mod φ(n)),即 e·d = k·φ(n) + 1
所以 M^(e·d) = M^(k·φ(n)+1) = M · (M^φ(n))^k ≡ M · 1^k ≡ M (mod n)
教学实现 (不安全)
def rsa_encrypt_raw(message: int, public_key: tuple) -> int:
"""
原始 RSA 加密 (仅用于教学)
警告: 这是教科书式 RSA,不安全,不要用于生产!
"""
n, e = public_key
if message >= n:
raise ValueError("消息必须小于 n")
return pow(message, e, n)
def rsa_decrypt_raw(ciphertext: int, private_key: tuple) -> int:
"""
原始 RSA 解密 (仅用于教学)
"""
n, d = private_key
return pow(ciphertext, d, n)
# 示例
p, q = 61, 53
n = p * q # 3233
phi_n = (p - 1) * (q - 1) # 3120
e = 17
d = mod_inverse(e, phi_n) # 2753
public_key = (n, e)
private_key = (n, d)
# 加密
message = 65 # 'A' 的 ASCII 码
ciphertext = rsa_encrypt_raw(message, public_key)
print(f"明文: {message}")
print(f"密文: {ciphertext}")
# 解密
decrypted = rsa_decrypt_raw(ciphertext, private_key)
print(f"解密: {decrypted}")
安全实现 (PKCS#1 v1.5 / OAEP)
教科书式 RSA 存在多种攻击,实际使用必须添加填充方案:
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes
def rsa_encrypt_oaep(public_key, plaintext: bytes) -> bytes:
"""
使用 OAEP 填充的 RSA 加密 (推荐)
OAEP (Optimal Asymmetric Encryption Padding):
- 添加随机性,使相同明文产生不同密文
- 提供 IND-CCA2 安全性
"""
ciphertext = public_key.encrypt(
plaintext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return ciphertext
def rsa_decrypt_oaep(private_key, ciphertext: bytes) -> bytes:
"""使用 OAEP 填充的 RSA 解密"""
plaintext = private_key.decrypt(
ciphertext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return plaintext
# 使用示例
private_key, public_key = generate_rsa_key_pair_crypto(2048)
message = b"Hello, RSA with OAEP!"
ciphertext = rsa_encrypt_oaep(public_key, message)
print(f"密文长度: {len(ciphertext)} bytes")
decrypted = rsa_decrypt_oaep(private_key, ciphertext)
print(f"解密结果: {decrypted.decode()}")
PKCS#1 v1.5 填充 (已不推荐)
def rsa_encrypt_pkcs1v15(public_key, plaintext: bytes) -> bytes:
"""
使用 PKCS#1 v1.5 填充的 RSA 加密
警告: PKCS#1 v1.5 存在 Bleichenbacher 攻击,
新系统应使用 OAEP
"""
ciphertext = public_key.encrypt(
plaintext,
padding.PKCS1v15()
)
return ciphertext
def rsa_decrypt_pkcs1v15(private_key, ciphertext: bytes) -> bytes:
"""使用 PKCS#1 v1.5 填充的 RSA 解密"""
plaintext = private_key.decrypt(
ciphertext,
padding.PKCS1v15()
)
return plaintext
填充方案对比
| 方案 | 安全性 | 推荐度 | 说明 |
|---|---|---|---|
| 无填充 (教科书式) | 不安全 | 禁止使用 | 易受多种攻击 |
| PKCS#1 v1.5 | 较弱 | 仅兼容 | Bleichenbacher 攻击 |
| OAEP | 强 | 推荐 | IND-CCA2 安全 |
混合加密
RSA 加密的数据量受限于密钥长度,实际应用通常采用混合加密:
import os
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
class HybridEncryption:
"""
混合加密: RSA + AES
流程:
1. 生成随机 AES 密钥
2. 使用 AES 加密数据
3. 使用 RSA 加密 AES 密钥
"""
def __init__(self, rsa_public_key=None, rsa_private_key=None):
self.public_key = rsa_public_key
self.private_key = rsa_private_key
def encrypt(self, plaintext: bytes) -> dict:
"""加密数据"""
# 1. 生成随机 AES 密钥和 IV
aes_key = os.urandom(32) # 256-bit key
iv = os.urandom(16) # 128-bit IV
# 2. 使用 AES-GCM 加密数据
cipher = Cipher(algorithms.AES(aes_key), modes.GCM(iv))
encryptor = cipher.encryptor()
ciphertext = encryptor.update(plaintext) + encryptor.finalize()
tag = encryptor.tag
# 3. 使用 RSA-OAEP 加密 AES 密钥
encrypted_key = rsa_encrypt_oaep(self.public_key, aes_key)
return {
'encrypted_key': encrypted_key,
'iv': iv,
'ciphertext': ciphertext,
'tag': tag
}
def decrypt(self, encrypted_data: dict) -> bytes:
"""解密数据"""
# 1. 使用 RSA 解密 AES 密钥
aes_key = rsa_decrypt_oaep(self.private_key, encrypted_data['encrypted_key'])
# 2. 使用 AES-GCM 解密数据
cipher = Cipher(
algorithms.AES(aes_key),
modes.GCM(encrypted_data['iv'], encrypted_data['tag'])
)
decryptor = cipher.decryptor()
plaintext = decryptor.update(encrypted_data['ciphertext']) + decryptor.finalize()
return plaintext
# 使用示例
private_key, public_key = generate_rsa_key_pair_crypto(2048)
hybrid = HybridEncryption(public_key, private_key)
# 可以加密大量数据
large_data = b"This is a very long message..." * 1000
encrypted = hybrid.encrypt(large_data)
decrypted = hybrid.decrypt(encrypted)
print(f"原始大小: {len(large_data)} bytes")
print(f"解密成功: {decrypted == large_data}")
数字签名
签名原理
签名: S = H(M)^d mod n
验证: H(M) == S^e mod n
其中:
- M: 消息
- H: 哈希函数 (如 SHA-256)
- S: 签名
- (n, e): 公钥
- (n, d): 私钥
为什么要对哈希值签名:
1. 消息可能很长,直接签名效率低
2. RSA 只能加密小于 n 的数据
3. 哈希保证唯一性和固定长度
签名流程
flowchart LR
classDef msg fill:#2b2d42,stroke:#8d99ae,stroke-width:2px,color:#edf2f4
classDef process fill:#ffffff,stroke:#2b2d42,stroke-width:2px,color:#2b2d42
classDef key fill:#7209b7,stroke:#3a0ca3,stroke-width:2px,color:#ffffff
classDef output fill:#2ec4b6,stroke:#011627,stroke-width:2px,color:#ffffff
subgraph 签名过程
M1["消息 M"]:::msg
H1["哈希 H(M)"]:::process
PRIV["私钥 d"]:::key
S["签名 S"]:::output
M1 --> H1
H1 --> |"S = H(M)^d mod n"| PRIV
PRIV --> S
end
subgraph 验证过程
M2["消息 M"]:::msg
H2["哈希 H(M)"]:::process
S2["签名 S"]:::output
PUB["公钥 e"]:::key
CMP{"比较"}:::process
RES["结果"]:::output
M2 --> H2
S2 --> |"S^e mod n"| PUB
PUB --> CMP
H2 --> CMP
CMP --> RES
end
linkStyle default stroke:#8d99ae,stroke-width:2px,fill:none
Python 实现
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes
def rsa_sign(private_key, message: bytes) -> bytes:
"""
使用 RSA-PSS 签名 (推荐)
PSS (Probabilistic Signature Scheme):
- 添加随机性
- 提供可证明安全性
"""
signature = private_key.sign(
message,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
return signature
def rsa_verify(public_key, message: bytes, signature: bytes) -> bool:
"""验证 RSA-PSS 签名"""
try:
public_key.verify(
signature,
message,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
return True
except Exception:
return False
# 使用示例
private_key, public_key = generate_rsa_key_pair_crypto(2048)
message = b"This message needs to be signed."
signature = rsa_sign(private_key, message)
print(f"签名长度: {len(signature)} bytes")
# 验证签名
is_valid = rsa_verify(public_key, message, signature)
print(f"签名有效: {is_valid}")
# 篡改消息后验证
tampered_message = b"This message has been modified."
is_valid_tampered = rsa_verify(public_key, tampered_message, signature)
print(f"篡改后验证: {is_valid_tampered}") # False
PKCS#1 v1.5 签名
def rsa_sign_pkcs1v15(private_key, message: bytes) -> bytes:
"""使用 PKCS#1 v1.5 签名 (兼容性需要时使用)"""
signature = private_key.sign(
message,
padding.PKCS1v15(),
hashes.SHA256()
)
return signature
def rsa_verify_pkcs1v15(public_key, message: bytes, signature: bytes) -> bool:
"""验证 PKCS#1 v1.5 签名"""
try:
public_key.verify(
signature,
message,
padding.PKCS1v15(),
hashes.SHA256()
)
return True
except Exception:
return False
Rust 实现
use rsa::{RsaPrivateKey, RsaPublicKey, Pkcs1v15Sign, signature::{Signer, Verifier}};
use sha2::Sha256;
/// RSA-PKCS1v15 签名
pub fn rsa_sign(private_key: &RsaPrivateKey, message: &[u8]) -> Vec<u8> {
use rsa::signature::SignatureEncoding;
let signing_key = rsa::pkcs1v15::SigningKey::<Sha256>::new(private_key.clone());
let signature = signing_key.sign(message);
signature.to_bytes().to_vec()
}
/// 验证签名
pub fn rsa_verify(public_key: &RsaPublicKey, message: &[u8], signature: &[u8]) -> bool {
use rsa::pkcs1v15::{VerifyingKey, Signature};
let verifying_key = VerifyingKey::<Sha256>::new(public_key.clone());
match Signature::try_from(signature) {
Ok(sig) => verifying_key.verify(message, &sig).is_ok(),
Err(_) => false,
}
}
签名方案对比
| 方案 | 安全性 | 确定性 | 推荐度 |
|---|---|---|---|
| PKCS#1 v1.5 | 较弱 | 是 | 仅兼容 |
| PSS | 强 | 否 (随机) | 推荐 |
实际应用
1. SSL/TLS 证书
"""
SSL/TLS 中的 RSA 应用:
1. 证书中包含服务器的 RSA 公钥
2. 客户端验证证书签名 (CA 使用 RSA 签名)
3. 密钥交换 (RSA 或 ECDHE)
4. 握手完成后使用对称加密
"""
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes
import datetime
def create_self_signed_certificate(private_key, public_key):
"""创建自签名证书"""
subject = issuer = x509.Name([
x509.NameAttribute(NameOID.COUNTRY_NAME, "CN"),
x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Beijing"),
x509.NameAttribute(NameOID.LOCALITY_NAME, "Beijing"),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Example Inc"),
x509.NameAttribute(NameOID.COMMON_NAME, "example.com"),
])
cert = (
x509.CertificateBuilder()
.subject_name(subject)
.issuer_name(issuer)
.public_key(public_key)
.serial_number(x509.random_serial_number())
.not_valid_before(datetime.datetime.utcnow())
.not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=365))
.add_extension(
x509.SubjectAlternativeName([
x509.DNSName("localhost"),
x509.DNSName("example.com"),
]),
critical=False,
)
.sign(private_key, hashes.SHA256())
)
return cert
# 生成证书
private_key, public_key = generate_rsa_key_pair_crypto(2048)
certificate = create_self_signed_certificate(private_key, public_key)
# 导出 PEM 格式
cert_pem = certificate.public_bytes(serialization.Encoding.PEM)
print(cert_pem.decode())
2. SSH 密钥认证
"""
SSH RSA 密钥认证流程:
1. 用户生成 RSA 密钥对
2. 将公钥添加到服务器 ~/.ssh/authorized_keys
3. 连接时,服务器发送随机挑战
4. 客户端用私钥签名挑战
5. 服务器用公钥验证签名
"""
from cryptography.hazmat.primitives.serialization import (
Encoding, PublicFormat, PrivateFormat, NoEncryption
)
def generate_ssh_keypair():
"""生成 SSH 兼容的 RSA 密钥对"""
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=4096, # SSH 推荐 4096 位
)
public_key = private_key.public_key()
# OpenSSH 格式
private_openssh = private_key.private_bytes(
encoding=Encoding.PEM,
format=PrivateFormat.OpenSSH,
encryption_algorithm=NoEncryption()
)
public_openssh = public_key.public_bytes(
encoding=Encoding.OpenSSH,
format=PublicFormat.OpenSSH
)
return private_openssh, public_openssh
private_ssh, public_ssh = generate_ssh_keypair()
print("私钥 (OpenSSH):")
print(private_ssh.decode())
print("\n公钥 (authorized_keys 格式):")
print(public_ssh.decode())
3. JWT RS256 签名
import json
import base64
class JWTRS256:
"""使用 RS256 (RSA + SHA-256) 的 JWT 实现"""
def __init__(self, private_key=None, public_key=None):
self.private_key = private_key
self.public_key = public_key
def _base64url_encode(self, data: bytes) -> str:
return base64.urlsafe_b64encode(data).rstrip(b'=').decode()
def _base64url_decode(self, data: str) -> bytes:
padding = 4 - len(data) % 4
if padding != 4:
data += '=' * padding
return base64.urlsafe_b64decode(data)
def create_token(self, payload: dict) -> str:
"""创建 JWT Token"""
header = {'alg': 'RS256', 'typ': 'JWT'}
header_b64 = self._base64url_encode(json.dumps(header).encode())
payload_b64 = self._base64url_encode(json.dumps(payload).encode())
message = f"{header_b64}.{payload_b64}".encode()
# 使用 RSA-PKCS1v15 签名 (JWT RS256 标准)
signature = self.private_key.sign(
message,
padding.PKCS1v15(),
hashes.SHA256()
)
signature_b64 = self._base64url_encode(signature)
return f"{header_b64}.{payload_b64}.{signature_b64}"
def verify_token(self, token: str) -> dict:
"""验证并解析 JWT Token"""
parts = token.split('.')
if len(parts) != 3:
raise ValueError("Invalid token format")
header_b64, payload_b64, signature_b64 = parts
message = f"{header_b64}.{payload_b64}".encode()
signature = self._base64url_decode(signature_b64)
# 验证签名
try:
self.public_key.verify(
signature,
message,
padding.PKCS1v15(),
hashes.SHA256()
)
except Exception:
raise ValueError("Invalid signature")
return json.loads(self._base64url_decode(payload_b64))
# 使用示例
private_key, public_key = generate_rsa_key_pair_crypto(2048)
jwt_handler = JWTRS256(private_key, public_key)
token = jwt_handler.create_token({
"sub": "user123",
"name": "Alice",
"iat": 1516239022
})
print(f"Token: {token[:50]}...")
payload = jwt_handler.verify_token(token)
print(f"Payload: {payload}")
4. 代码签名
import hashlib
import json
class CodeSigner:
"""代码/软件包签名器"""
def __init__(self, private_key, public_key):
self.private_key = private_key
self.public_key = public_key
def sign_file(self, file_path: str) -> dict:
"""签名文件"""
with open(file_path, 'rb') as f:
content = f.read()
# 计算文件哈希
file_hash = hashlib.sha256(content).digest()
# 签名哈希值
signature = self.private_key.sign(
file_hash,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
return {
'file': file_path,
'sha256': file_hash.hex(),
'signature': base64.b64encode(signature).decode(),
'algorithm': 'RSA-PSS-SHA256'
}
def verify_signature(self, file_path: str, signature_info: dict) -> bool:
"""验证文件签名"""
with open(file_path, 'rb') as f:
content = f.read()
file_hash = hashlib.sha256(content).digest()
# 检查哈希是否匹配
if file_hash.hex() != signature_info['sha256']:
return False
signature = base64.b64decode(signature_info['signature'])
try:
self.public_key.verify(
signature,
file_hash,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
return True
except Exception:
return False
安全性分析
已知攻击
1. 因数分解攻击
"""
RSA 安全性基于大整数分解的困难性
如果攻击者能分解 n = p × q,就能计算:
φ(n) = (p-1)(q-1)
d = e^(-1) mod φ(n)
当前分解记录:
- RSA-250 (829 位): 2020 年被分解
- RSA-260 (862 位): 尚未被分解
安全建议:
- 2030 年前: 至少 2048 位
- 2030 年后: 至少 3072 位
- 长期安全: 4096 位
"""
# 密钥长度与安全等级
KEY_SECURITY_LEVELS = {
1024: "不安全,已可被分解",
2048: "短期安全,2030 年前",
3072: "中期安全,对应 128 位对称密钥",
4096: "长期安全,对应 140+ 位对称密钥",
7680: "对应 192 位对称密钥",
15360: "对应 256 位对称密钥",
}
2. 小公钥指数攻击
"""
Coppersmith 攻击:
如果 e = 3 且消息 m 较小,可能直接开立方根
防御:
- 使用 e = 65537
- 使用适当的填充方案
"""
# 不安全示例
# e = 3, m^3 < n 时,直接开立方根得到 m
3. 共模攻击
"""
如果使用相同的 n 但不同的 e 加密同一消息:
c1 = m^e1 mod n
c2 = m^e2 mod n
如果 gcd(e1, e2) = 1,可以恢复 m
防御:
- 每个用户使用不同的 n
"""
4. Bleichenbacher 攻击 (针对 PKCS#1 v1.5)
"""
Bleichenbacher (1998):
利用填充错误的侧信道信息,逐步恢复明文
攻击步骤:
1. 发送大量特制密文
2. 观察服务器是否报填充错误
3. 通过二分搜索逐步缩小明文范围
防御:
- 使用 OAEP 而非 PKCS#1 v1.5
- 不返回详细的错误信息
"""
5. 时序攻击
"""
通过测量解密时间来推断私钥
防御:
- 使用恒定时间算法
- 使用蒙哥马利乘法
- RSA 盲化
"""
def rsa_decrypt_with_blinding(private_key, ciphertext: int, n: int, d: int) -> int:
"""RSA 盲化解密,防止时序攻击"""
import random
# 生成随机盲化因子
r = random.randint(2, n - 1)
while gcd(r, n) != 1:
r = random.randint(2, n - 1)
# 盲化
e = 65537 # 假设公钥指数
blinded = (ciphertext * pow(r, e, n)) % n
# 解密盲化后的密文
blinded_result = pow(blinded, d, n)
# 去盲化
r_inv = mod_inverse(r, n)
result = (blinded_result * r_inv) % n
return result
安全建议
| 方面 | 建议 |
|---|---|
| 密钥长度 | 至少 2048 位,推荐 3072 或 4096 位 |
| 公钥指数 | 使用 65537 (0x10001) |
| 填充方案 | 加密用 OAEP,签名用 PSS |
| 素数生成 | 使用密码学安全的随机数生成器 |
| 私钥保护 | 使用 HSM 或加密存储 |
| 密钥轮换 | 定期更换密钥 |
性能考虑
RSA vs 对称加密性能
import time
def benchmark_rsa_vs_aes():
"""RSA 与 AES 性能对比"""
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
# 生成密钥
rsa_private, rsa_public = generate_rsa_key_pair_crypto(2048)
aes_key = os.urandom(32)
iv = os.urandom(16)
# 测试数据
small_data = os.urandom(190) # RSA-2048 OAEP 最大明文约 190 字节
large_data = os.urandom(1024 * 1024) # 1 MB
# RSA 加密性能 (小数据)
start = time.time()
for _ in range(100):
rsa_encrypt_oaep(rsa_public, small_data)
rsa_encrypt_time = (time.time() - start) / 100
# AES 加密性能 (大数据)
start = time.time()
for _ in range(100):
cipher = Cipher(algorithms.AES(aes_key), modes.GCM(iv))
encryptor = cipher.encryptor()
encryptor.update(large_data) + encryptor.finalize()
aes_encrypt_time = (time.time() - start) / 100
print(f"RSA-2048 加密 (190B): {rsa_encrypt_time * 1000:.2f} ms")
print(f"AES-256-GCM 加密 (1MB): {aes_encrypt_time * 1000:.2f} ms")
# benchmark_rsa_vs_aes()
"""
典型结果:
RSA-2048 加密 (190B): 0.5-1 ms
AES-256-GCM 加密 (1MB): 1-2 ms
RSA 比 AES 慢约 1000 倍
因此大数据应使用混合加密
"""
优化技术
"""
RSA 性能优化技术:
1. 中国剩余定理 (CRT) 加速解密
- 将模 n 运算分解为模 p 和模 q
- 解密速度提升 4 倍
2. 预计算
- 预计算 dp = d mod (p-1)
- 预计算 dq = d mod (q-1)
- 预计算 qinv = q^(-1) mod p
3. 蒙哥马利乘法
- 避免除法运算
- 硬件友好
"""
def rsa_decrypt_crt(ciphertext: int, p: int, q: int, dp: int, dq: int, qinv: int) -> int:
"""
使用 CRT 加速 RSA 解密
参数:
- dp = d mod (p-1)
- dq = d mod (q-1)
- qinv = q^(-1) mod p
"""
# 分别计算
m1 = pow(ciphertext, dp, p)
m2 = pow(ciphertext, dq, q)
# 使用 CRT 合并
h = (qinv * (m1 - m2)) % p
m = m2 + h * q
return m
多语言实现
Node.js
const crypto = require('crypto');
// 生成密钥对
function generateKeyPair() {
return crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem'
}
});
}
// RSA-OAEP 加密
function encrypt(publicKey, plaintext) {
return crypto.publicEncrypt(
{
key: publicKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: 'sha256'
},
Buffer.from(plaintext)
);
}
// RSA-OAEP 解密
function decrypt(privateKey, ciphertext) {
return crypto.privateDecrypt(
{
key: privateKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: 'sha256'
},
ciphertext
).toString();
}
// RSA-PSS 签名
function sign(privateKey, message) {
return crypto.sign('sha256', Buffer.from(message), {
key: privateKey,
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
saltLength: crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN
});
}
// 验证签名
function verify(publicKey, message, signature) {
return crypto.verify('sha256', Buffer.from(message), {
key: publicKey,
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
saltLength: crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN
}, signature);
}
// 使用示例
const { publicKey, privateKey } = generateKeyPair();
const message = 'Hello, RSA!';
const encrypted = encrypt(publicKey, message);
const decrypted = decrypt(privateKey, encrypted);
console.log('Decrypted:', decrypted);
const signature = sign(privateKey, message);
const isValid = verify(publicKey, message, signature);
console.log('Signature valid:', isValid);
Go
package main
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/pem"
"fmt"
)
// 生成密钥对
func generateKeyPair(bits int) (*rsa.PrivateKey, *rsa.PublicKey, error) {
privateKey, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return nil, nil, err
}
return privateKey, &privateKey.PublicKey, nil
}
// RSA-OAEP 加密
func encrypt(publicKey *rsa.PublicKey, plaintext []byte) ([]byte, error) {
return rsa.EncryptOAEP(sha256.New(), rand.Reader, publicKey, plaintext, nil)
}
// RSA-OAEP 解密
func decrypt(privateKey *rsa.PrivateKey, ciphertext []byte) ([]byte, error) {
return rsa.DecryptOAEP(sha256.New(), rand.Reader, privateKey, ciphertext, nil)
}
// RSA-PSS 签名
func sign(privateKey *rsa.PrivateKey, message []byte) ([]byte, error) {
hash := sha256.Sum256(message)
return rsa.SignPSS(rand.Reader, privateKey, crypto.SHA256, hash[:], nil)
}
// 验证签名
func verify(publicKey *rsa.PublicKey, message, signature []byte) error {
hash := sha256.Sum256(message)
return rsa.VerifyPSS(publicKey, crypto.SHA256, hash[:], signature, nil)
}
// 导出 PEM 格式
func exportPrivateKeyPEM(privateKey *rsa.PrivateKey) []byte {
der := x509.MarshalPKCS1PrivateKey(privateKey)
return pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: der,
})
}
func main() {
privateKey, publicKey, _ := generateKeyPair(2048)
message := []byte("Hello, RSA!")
// 加密解密
ciphertext, _ := encrypt(publicKey, message)
plaintext, _ := decrypt(privateKey, ciphertext)
fmt.Printf("Decrypted: %s\n", plaintext)
// 签名验证
signature, _ := sign(privateKey, message)
err := verify(publicKey, message, signature)
fmt.Printf("Signature valid: %v\n", err == nil)
}
Java
import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.PSSParameterSpec;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
import java.util.Base64;
public class RSAExample {
// 生成密钥对
public static KeyPair generateKeyPair() throws Exception {
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048);
return generator.generateKeyPair();
}
// RSA-OAEP 加密
public static byte[] encrypt(PublicKey publicKey, byte[] plaintext) throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
OAEPParameterSpec oaepParams = new OAEPParameterSpec(
"SHA-256",
"MGF1",
MGF1ParameterSpec.SHA256,
PSource.PSpecified.DEFAULT
);
cipher.init(Cipher.ENCRYPT_MODE, publicKey, oaepParams);
return cipher.doFinal(plaintext);
}
// RSA-OAEP 解密
public static byte[] decrypt(PrivateKey privateKey, byte[] ciphertext) throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
OAEPParameterSpec oaepParams = new OAEPParameterSpec(
"SHA-256",
"MGF1",
MGF1ParameterSpec.SHA256,
PSource.PSpecified.DEFAULT
);
cipher.init(Cipher.DECRYPT_MODE, privateKey, oaepParams);
return cipher.doFinal(ciphertext);
}
// RSA-PSS 签名
public static byte[] sign(PrivateKey privateKey, byte[] message) throws Exception {
Signature signature = Signature.getInstance("RSASSA-PSS");
PSSParameterSpec pssParams = new PSSParameterSpec(
"SHA-256",
"MGF1",
MGF1ParameterSpec.SHA256,
32,
1
);
signature.setParameter(pssParams);
signature.initSign(privateKey);
signature.update(message);
return signature.sign();
}
// 验证签名
public static boolean verify(PublicKey publicKey, byte[] message, byte[] sig) throws Exception {
Signature signature = Signature.getInstance("RSASSA-PSS");
PSSParameterSpec pssParams = new PSSParameterSpec(
"SHA-256",
"MGF1",
MGF1ParameterSpec.SHA256,
32,
1
);
signature.setParameter(pssParams);
signature.initVerify(publicKey);
signature.update(message);
return signature.verify(sig);
}
public static void main(String[] args) throws Exception {
KeyPair keyPair = generateKeyPair();
byte[] message = "Hello, RSA!".getBytes();
// 加密解密
byte[] ciphertext = encrypt(keyPair.getPublic(), message);
byte[] plaintext = decrypt(keyPair.getPrivate(), ciphertext);
System.out.println("Decrypted: " + new String(plaintext));
// 签名验证
byte[] sig = sign(keyPair.getPrivate(), message);
boolean valid = verify(keyPair.getPublic(), message, sig);
System.out.println("Signature valid: " + valid);
}
}
最佳实践
1. 密钥管理
"""
RSA 密钥管理最佳实践:
1. 密钥生成
- 使用密码学安全的随机数生成器
- 验证素数质量
- 使用足够的密钥长度
2. 密钥存储
- 私钥加密存储 (PKCS#8 + AES)
- 使用硬件安全模块 (HSM)
- 严格的访问控制
3. 密钥使用
- 区分加密密钥和签名密钥
- 实现密钥轮换机制
- 记录密钥使用日志
4. 密钥销毁
- 安全擦除内存
- 多次覆写存储
- 保留审计记录
"""
from cryptography.hazmat.primitives.serialization import (
Encoding, PrivateFormat, BestAvailableEncryption
)
def save_encrypted_private_key(private_key, password: bytes, file_path: str):
"""加密保存私钥"""
encrypted_pem = private_key.private_bytes(
encoding=Encoding.PEM,
format=PrivateFormat.PKCS8,
encryption_algorithm=BestAvailableEncryption(password)
)
with open(file_path, 'wb') as f:
f.write(encrypted_pem)
def load_encrypted_private_key(file_path: str, password: bytes):
"""加载加密的私钥"""
from cryptography.hazmat.primitives.serialization import load_pem_private_key
with open(file_path, 'rb') as f:
private_key = load_pem_private_key(f.read(), password=password)
return private_key
2. 错误处理
from cryptography.exceptions import InvalidSignature
def safe_rsa_decrypt(private_key, ciphertext: bytes) -> bytes:
"""安全的 RSA 解密,统一错误处理"""
try:
return rsa_decrypt_oaep(private_key, ciphertext)
except ValueError:
# 解密失败,不泄露具体原因
raise DecryptionError("Decryption failed")
except Exception:
raise DecryptionError("Decryption failed")
def safe_rsa_verify(public_key, message: bytes, signature: bytes) -> bool:
"""安全的签名验证"""
try:
public_key.verify(
signature,
message,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
return True
except InvalidSignature:
return False
except Exception:
return False
class DecryptionError(Exception):
"""解密错误"""
pass
3. 测试向量
"""
使用已知测试向量验证实现正确性
来源: NIST CAVP (Cryptographic Algorithm Validation Program)
"""
def test_rsa_encrypt_decrypt():
"""测试加密解密"""
private_key, public_key = generate_rsa_key_pair_crypto(2048)
test_cases = [
b"", # 空消息
b"A", # 单字节
b"Hello, World!", # 普通消息
os.urandom(190), # 最大长度 (2048-bit OAEP)
]
for msg in test_cases:
ciphertext = rsa_encrypt_oaep(public_key, msg)
decrypted = rsa_decrypt_oaep(private_key, ciphertext)
assert decrypted == msg, f"Failed for message length {len(msg)}"
print("All encryption/decryption tests passed!")
def test_rsa_sign_verify():
"""测试签名验证"""
private_key, public_key = generate_rsa_key_pair_crypto(2048)
message = b"Test message for signing"
signature = rsa_sign(private_key, message)
# 正确验证
assert rsa_verify(public_key, message, signature) == True
# 篡改消息
tampered = b"Modified message"
assert rsa_verify(public_key, tampered, signature) == False
# 篡改签名
bad_sig = bytes([s ^ 0xFF for s in signature])
assert rsa_verify(public_key, message, bad_sig) == False
print("All signature tests passed!")
常见问题
1. RSA 能加密多大的数据?
"""
RSA 加密数据长度限制:
1. 无填充: 明文 < n (密钥长度 / 8 字节)
- 2048 位密钥: < 256 字节
- 不推荐使用
2. PKCS#1 v1.5: 明文 < n - 11 字节
- 2048 位密钥: < 245 字节
3. OAEP (SHA-256): 明文 < n - 2*hash_len - 2 字节
- 2048 位密钥: < 256 - 66 = 190 字节
大数据解决方案:
使用混合加密 (RSA + AES)
"""
def max_plaintext_length(key_bits: int, padding: str) -> int:
"""计算最大明文长度"""
key_bytes = key_bits // 8
if padding == 'none':
return key_bytes - 1
elif padding == 'pkcs1v15':
return key_bytes - 11
elif padding == 'oaep_sha256':
return key_bytes - 2 * 32 - 2
else:
raise ValueError(f"Unknown padding: {padding}")
print(f"RSA-2048 OAEP 最大明文: {max_plaintext_length(2048, 'oaep_sha256')} bytes")
2. RSA 公钥指数为什么选 65537?
"""
e = 65537 = 0x10001 = 2^16 + 1
优点:
1. 是素数,容易满足 gcd(e, φ(n)) = 1
2. 二进制只有两个 1,计算效率高
3. 足够大,避免某些攻击
4. 足够小,加密速度快
其他常见值:
- e = 3: 最快,但有安全风险
- e = 17: 较快
- e = 65537: 标准推荐
"""
3. RSA 和 ECC 如何选择?
| 特性 | RSA-2048 | ECDSA P-256 |
|---|---|---|
| 密钥长度 | 2048 位 | 256 位 |
| 等效安全性 | 112 位 | 128 位 |
| 签名速度 | 较慢 | 较快 |
| 验证速度 | 较快 | 较慢 |
| 密钥生成 | 较慢 | 较快 |
| 兼容性 | 极佳 | 良好 |
| 推荐场景 | 兼容优先 | 移动端/IoT |
4. 量子计算对 RSA 的威胁?
"""
Shor 算法可以在多项式时间内分解大整数
影响:
- 所有基于大整数分解的密码系统将失效
- 包括 RSA、DSA、Diffie-Hellman
时间线预估:
- 2030-2040: 可能出现足够强的量子计算机
应对措施:
1. 迁移到后量子密码学 (NIST PQC 标准)
- CRYSTALS-Kyber (密钥封装)
- CRYSTALS-Dilithium (数字签名)
- SPHINCS+ (哈希签名)
2. 过渡期策略:
- 混合模式: RSA + 后量子算法
- 增加密钥长度 (短期缓解)
"""
总结
RSA 是公钥密码学的基石,理解其原理对于安全系统设计至关重要:
核心要点
| 方面 | 要点 |
|---|---|
| 数学基础 | 大整数分解困难性 + 欧拉定理 |
| 密钥长度 | 至少 2048 位,推荐 3072+ |
| 填充方案 | 加密用 OAEP,签名用 PSS |
| 性能 | 比对称加密慢,大数据用混合加密 |
| 应用 | SSL/TLS、SSH、数字签名、JWT |
安全检查清单
- 密钥长度至少 2048 位
- 使用 e = 65537
- 使用 OAEP/PSS 填充
- 私钥加密存储
- 实现密钥轮换
- 不返回详细错误信息
- 使用恒定时间比较
- 定期安全审计
参考资料:
- RFC 8017: PKCS #1: RSA Cryptography Specifications Version 2.2
- NIST SP 800-56B: Recommendation for Pair-Wise Key-Establishment Using Integer Factorization Cryptography
- FIPS 186-5: Digital Signature Standard (DSS)
相关推荐
HMAC - 基于哈希的消息认证码
深入解析 HMAC 的工作原理、安全特性、应用场景和多语言实现,理解为什么 HMAC 比简单的哈希更安全
·31 分钟·
#HMAC#加密算法
Ed25519 - 现代高性能数字签名算法
深入解析 Ed25519 椭圆曲线签名算法的数学原理、性能优势、安全特性,以及在区块链和 SSH 中的应用实践
·32 分钟·
#Ed25519#椭圆曲线
撮合引擎 - 数字资产交易的核心技术
深入解析撮合引擎的工作原理、核心算法、订单类型和技术架构,理解交易所如何实现高效的买卖订单匹配
·45 分钟·
#撮合引擎#交易所