几乎所有开发者都知道 RSA 是非对称加密的代表,但真正用过的人常常会撞上同一个墙:“为什么加密一段稍长的文本就报错了?” 这篇文章解释这个限制的来源,以及实际系统是怎么绕过它的。
RSA 是最经典的非对称加密算法,1977 年由 Rivest、Shamir、Adleman 三人提出(名字就是三人姓氏首字母)。它有一对密钥:
| 密钥 | 要不要保密 | 用途 |
|---|---|---|
| 公钥 | 公开,可以随便发 | 加密、验证签名 |
| 私钥 | 绝对保密 | 解密、生成签名 |
它的安全性建立在一个数学难题上:把两个大质数相乘很容易,但把乘积分解回两个质数极难。2048 位的 RSA 密钥,就是两个约 1024 位的大质数的乘积。
这是 RSA 最反直觉的限制。原因是:**RSA 一次只能加密一个“数学块”,而这个块的大小受密钥长度限制。**
具体数字(2048 位密钥):
密钥长度 2048 位 = 256 字节
减去填充开销 约 11 字节(PKCS#1 v1.5)
────────────────────────────────
实际可加密 最多 245 字节
245 字节,大约 80 个汉字。超过就报错。
为什么不能像 AES 那样分段加密?技术上可以,但会有两个致命问题:
既然 RSA 只能加密短数据、AES 又快又能加密任意长度,那就组合起来用。这就是 **TLS/HTTPS 的实际工作方式**:
RSA 只负责安全地传递那把小小的对称密钥,真正的大流量交给 AES。这个模式叫**数字信封**。
这是另一个高频混淆点。两者都用 RSA,但目的和方向完全不同:
| 加密 | 签名 | |
|---|---|---|
| 目的 | 保密(别人看不到) | 认证(确认是谁发的、有没有被改) |
| 用哪把钥匙操作 | 公钥加密 | 私钥签名 |
| 用哪把钥匙还原 | 私钥解密 | 公钥验证 |
| 数据是否可见 | 不可见 | 可见(签名是附加的) |
记忆方法:**加密是“锁上给别人”,签名是“盖章证明是我”。**
签名的实际做法不是对原文直接签,而是先算原文的哈希,再对哈希签名。因为哈希值固定很短,正好符合 RSA 的长度限制。
RSA 不能直接加密裸数据,必须先填充。常见的有两种:
| 方案 | 安全性 | 说明 |
|---|---|---|
| PKCS#1 v1.5 | ⚠️ 有已知攻击 | 老系统常见,新项目不建议 |
| OAEP | ✅ 推荐 | 带随机性,当前标准做法 |
OAEP 会引入随机数,所以**同一段明文加密两次会得到不同密文**——这是正确行为。如果你需要密文稳定,那应该用哈希而不是加密。
| 长度 | 状态 |
|---|---|
| 1024 位 | ❌ 已不推荐,理论上可被资源充足者分解 |
| 2048 位 | ✅ 当前主流,够用到 2030 年前后 |
| 4096 位 | ✅ 更安全,但加解密慢约 6 倍 |
一般选 2048 位。只有在密钥生命周期很长(比如代码签名证书)时才需要 4096 位。
所有运算在浏览器本地完成。私钥不会离开你的电脑。
-----BEGIN ...----- 包裹。常见的有三种:BEGIN PUBLIC KEY(公钥)、BEGIN RSA PRIVATE KEY(PKCS#1 格式私钥)、BEGIN PRIVATE KEY(PKCS#8 格式私钥)。选错格式会导致解析失败。