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#椭圆曲线