跳到主要内容
加密解密2026-06-236 分钟阅读

在线 RSA 加解密工具:非对称加密和数字签名

什么是 RSA 加密

RSA 是最广泛使用的非对称加密算法,由 Rivest、Shamir、Adleman 三人于 1977 年提出。它使用一对密钥:公钥加密,私钥解密。

RSA 工作原理

密钥对生成:
  选择两个大质数 p, q
  计算 n = p × q
  计算 φ(n) = (p-1)(q-1)
  选择 e 使得 gcd(e, φ(n)) = 1
  计算 d 使得 e×d ≡ 1 (mod φ(n))

公钥: (e, n)   ← 可以公开
私钥: (d, n)   ← 必须保密

加密: C = M^e mod n
解密: M = C^d mod n

RSA vs AES

特性RSA(非对称)AES(对称)
密钥数量一对(公钥+私钥)一个共享密钥
加密速度慢(1000x)快
数据大小有限制(< 密钥长度)无限制
典型用途密钥交换、数字签名数据加密
密钥长度2048-4096 位128-256 位

为什么需要 RSA 加密

  1. 安全通信:HTTPS/TLS 握手中的密钥交换
  2. 数字签名:验证数据完整性和来源
  3. API 认证:JWT RS256 签名验证
  4. 密钥交换:安全传输 AES 会话密钥
  5. 代码签名:验证软件发布者身份

如何使用在线工具

使用 ToolVault 工具匣 的 RSA 加解密工具:

  1. 生成 RSA 密钥对(2048/4096 位)
  2. 使用公钥加密数据
  3. 使用私钥解密数据
  4. 创建和验证数字签名
  5. 支持 PEM 格式导入/导出

代码中的 RSA

JavaScript:Web Crypto API

// 生成 RSA 密钥对
async function generateRSAKeyPair() {
  const keyPair = await crypto.subtle.generateKey(
    {
      name: 'RSA-OAEP',
      modulusLength: 2048,
      publicExponent: new Uint8Array([1, 0, 1]),
      hash: 'SHA-256',
    },
    true,
    ['encrypt', 'decrypt']
  );
  return keyPair;
}

// 加密
async function rsaEncrypt(publicKey, data) {
  const encoder = new TextEncoder();
  const encrypted = await crypto.subtle.encrypt(
    { name: 'RSA-OAEP' },
    publicKey,
    encoder.encode(data)
  );
  return new Uint8Array(encrypted);
}

// 解密
async function rsaDecrypt(privateKey, encryptedData) {
  const decrypted = await crypto.subtle.decrypt(
    { name: 'RSA-OAEP' },
    privateKey,
    encryptedData
  );
  return new TextDecoder().decode(decrypted);
}

Python:使用 cryptography 库

from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes, serialization

# 生成密钥对
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
)
public_key = private_key.public_key()

# 加密
ciphertext = public_key.encrypt(
    b"Hello, RSA!",
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

# 解密
plaintext = private_key.decrypt(
    ciphertext,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

填充模式不是细节,是安全本身

教科书 RSA(对消息做幂运算)在确定性地不安全:同一明文永远得同一密文,短消息直接被开根号提取。所有真实部署都用填充方案,而选择是兼容性雷区:PKCS#1 v1.5 是到处可用的遗留默认,但在解密方泄露失败细节时暴露于 Bleichenbacher 填充预言攻击;OAEP 是现代答案——但 Java 默认 OAEP 参数与 OpenSSL 的 MGF1 摘要不同,产出彼此打不开的密文。规则:一方加密、另一方解不开时,先比对 OAEP 参数字节再怪密钥。

密钥尺寸:2048 的由来与 4096 的误用

分解记录一路推高门槛:512 位 1999 年破、768 位 2009 年破、1024 位在国家力量预算内。2048 位约 112 bit 安全强度,满足当前所有 CA 与标准。跳到 4096 位让解密成本翻四倍只换约 20 bit——正确动作是换算法:新混合设计用 EC(P-256)或 SM2,以零头密钥尺寸拿 128 bit。4096 只留给被对方标准冻结在 RSA 里的场景。

混合信封的现实

RSA 一次最多加密一个块(2048 位下按填充 190-245 字节)——没人直接用 RSA 加密文档。真实系统全是信封结构:随机 AES/SM4 会话密钥加密数据本体,RSA 只加密会话密钥。TLS、PGP、我们的混合工具都是这个形状。调试「RSA payload too long」报错,八成是有人跳过了信封这步。

PEM 格式与导入导出:SPKI 与 PKCS#8

工具的「生成密钥」页签输出的是 PEM 文本块,但 PEM 只是外壳——外壳里面装哪种 DER 结构才决定能不能被别的程序打开:

外观内部结构用途兼容性
BEGIN PUBLIC KEYSPKI(X.509 SubjectPublicKeyInfo)公钥所有现代栈通用
BEGIN RSA PUBLIC KEYPKCS#1 RSAPublicKey公钥遗留格式,Web Crypto 不支持
BEGIN PRIVATE KEYPKCS#8 PrivateKeyInfo私钥所有现代栈通用
BEGIN RSA PRIVATE KEYPKCS#1 RSAPrivateKey私钥遗留格式,Web Crypto 不支持
BEGIN ENCRYPTED PRIVATE KEYPKCS#8 + 密码包裹加密私钥需先解密

换算只在 OpenSSL 一侧:openssl rsa -in rsa.pem -pubout 就能把 PKCS#1 私钥换成 PKCS#8(-in 读进来,-pubout 对应导出公钥;私钥格式转换用 openssl pkcs8 -topk8 -nocrypt)。反过来,Java/Python 导出的 BEGIN PUBLIC KEY / BEGIN PRIVATE KEY 可以直接粘进工具的输入框——粘贴时带有的换行、CRLF 空白会被自动剥掉。

常见报错排查清单

「DataError」/ 解密失败(浏览器):密文不是这把私钥对应的公钥加密的,或密文被截断/改写。Base64 密文丢一个字符都会触发——先检查复制是否完整。

明文太长(payload too long):OAEP/SHA-256 下单块上限是 密钥字节数 - 66。2048 位只能装 190 字节 UTF-8(约 63 个汉字),4096 位 446 字节。工具加密页签现在会实时显示字节数/上限,超限会禁用加密按钮——这是提示你走混合加密,不是 bug。

「BEGIN RSA PRIVATE KEY」导入失败:这是 PKCS#1 私钥,Web Crypto 只吃 PKCS#8(BEGIN PRIVATE KEY)。用 openssl pkcs8 -topk8 -nocrypt -in rsa.pem -out pkcs8.pem 转换后再导入。

跨语言对不上(Java 加密、浏览器解不开):九成是 OAEP 参数不一致。Java 写 RSA/ECB/OAEPWithSHA-256AndMGF1Padding 时 MGF1 默认还是 SHA-1,而 Web Crypto 的 hash: 'SHA-256' 会把 MGF1 也锁成 SHA-256。Java 侧必须显式 new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT)。

FAQ

RSA 密钥长度如何选择?

  • 2048 位:当前标准,足够安全
  • 3072 位:更高安全要求
  • 4096 位:最高安全级别(性能较低) NIST 建议至少 2048 位,2030 年后建议 3072 位以上。

RSA 和 ECC 哪个更好?

ECC(椭圆曲线)在相同安全级别下密钥更短(256 位 ECC ≈ 3072 位 RSA),性能也更好。但 RSA 更成熟、兼容性更好。新项目推荐 ECC,现有系统保持 RSA。

为什么 RSA 不能直接加密大文件?

RSA 加密有长度限制(密钥长度 - 填充开销),且速度慢。实际使用中,RSA 用于加密 AES 密钥,再用 AES 加密文件(混合加密)。对称的 AES 部分可以用我们的 AES 加解密工具来完成。

PEM 公钥能直接贴进工具吗?换行会弄坏密钥吗?

不会。PEM 按 64 字符换行只是排版约定,工具导入前会把所有空白剥掉再按 base64 解码。但要确认头行:公钥必须是 BEGIN PUBLIC KEY,私钥必须是 BEGIN PRIVATE KEY——带 RSA 字样的是 PKCS#1 遗留格式,浏览器 Web Crypto 不支持。

2048 位 RSA 一次能加密多少汉字?

OAEP/SHA-256 上限 190 字节,UTF-8 下约 63 个汉字。工具加密页签会实时显示「字节数/上限」,超限自动禁用按钮。需要加密更长内容时,正确姿势是混合加密而不是换更大的 RSA 密钥。

排查注记

报错清单按互操作场景排:跨语言对不上单列并断言「九成是 OAEP 参数不一致」,依据是 Java 的 OAEPWithSHA-256AndMGF1Padding 里 MGF1 默认还是 SHA-1、而 Web Crypto 会把 MGF1 也锁成 SHA-256——两边摘要参数差一个字段,密文就互相打不开。PEM 那张表按头行区分 SPKI/PKCS#8 与 PKCS#1 遗留格式,因为带 RSA 字样的头 Web Crypto 不吃,是导入失败里最好认的一类。「payload too long」的注解也是同一逻辑:八成是有人跳过了信封这步,正确姿势是混合加密而不是换更大的密钥。


这篇实战笔记来自 ToolVault 工具匣。其他在线工具可在 首页 找到。