「RSA 一次能加密多少字节」这个问题,网上给出的答案往往是一个具体数字。但只要你换一个填充方案或换一个摘要算法,那个数字就不对了。
上限由三个变量共同决定:密钥长度、填充方案、摘要算法。
完整对照表
| 密钥长度 | PKCS#1 v1.5 | OAEP-SHA-1 | OAEP-SHA-256 | OAEP-SHA-384 | OAEP-SHA-512 |
|---|---|---|---|---|---|
| RSA-1024 | 117 字节 | 86 字节 | 62 字节 | 30 字节 | 放不下 |
| RSA-2048 | 245 字节 | 214 字节 | 190 字节 | 158 字节 | 126 字节 |
| RSA-3072 | 373 字节 | 342 字节 | 318 字节 | 286 字节 | 254 字节 |
| RSA-4096 | 501 字节 | 470 字节 | 446 字节 | 414 字节 | 382 字节 |
有几件事值得单独指出:
- 摘要越强,能加密的越少。 同样是 RSA-2048,SHA-256 能加 190 字节,SHA-512 只剩 126 字节
- RSA-1024 配 OAEP-SHA-512 是负数,一个字节也放不下,算式本身就不成立
- 这里说的是字节不是字符。 一个汉字按 UTF-8 占 3 字节,190 字节只够装 63 个汉字
上限是怎么算出来的
RSA 的数学运算是对一个不超过模数的整数做幂模运算。明文必须先被填充成正好 k 字节的一个数据块(k 是模数的字节数,RSA-2048 就是 256)。填充自己要占位置,剩下的才留给明文。
PKCS#1 v1.5:固定开销 11 字节
块结构是:
0x00 || 0x02 || PS || 0x00 || M
1 1 ≥8 1 明文
- 开头
0x00保证这个整数小于模数 0x02标记这是加密块(签名块是0x01)PS是随机非零填充串,标准要求至少 8 字节0x00分隔符,标记明文从哪开始
固定开销 1 + 1 + 8 + 1 = 11 字节,所以上限是 k - 11。
OAEP:固定开销 2×hLen + 2
OAEP 要放的东西更多:一个 hLen 字节的标签哈希、一个 hLen 字节的随机种子、一个前导零字节、一个分隔符字节。加起来是 2×hLen + 2。
SHA-256 的 hLen 是 32,开销就是 66 字节;SHA-512 的 hLen 是 64,开销 130 字节。
明明更费空间,为什么还要用 OAEP
因为 v1.5 的填充结构是确定的,历史上被 Bleichenbacher 攻击利用过——1998 年提出,只要攻击者能观察到「填充是否合法」这一位信息,就能通过大量请求逐步把密文解出来,不需要私钥。这类攻击后来在 TLS 实现上反复复发。
OAEP 是 PKCS#1 v2.0 引入的,有可证明安全的形式化证明。新代码一律用 OAEP,v1.5 只在对接老系统时保留。
报错 data too large for key size 之后
先确认三件事:
- 明文实际有多少字节(中文按 UTF-8 一个字 3 字节)
- 密钥是多少位——PEM 文本里看不出来,得解析
- 当前选的填充方案和摘要
然后按推荐程度排,有三条路:
① 改用混合加密(推荐)—— 见下一节,没有长度限制
② 降低摘要强度 —— OAEP-SHA-512 换 SHA-256 能多出 64 字节。这只是把天花板抬高一点,治标不治本
③ 换更长的密钥 —— RSA-4096 配 OAEP-SHA-256 能加 446 字节。代价是运算慢一个量级,而且仍然装不下任何有实际体量的数据
还有第四条路,分段加密,不推荐。
为什么不该分段加密
看起来很自然:数据长就切片,每片单独 RSA 加密,接收方逐片解密再拼起来。但这条路有三个问题。
慢。 RSA 的运算比 AES 慢三到四个数量级。加密 1 MB 数据,用 RSA-2048 配 OAEP-SHA-256 要切成约 5500 段,每段做一次模幂运算。同样的数据用 AES-GCM 是毫秒级。
不安全。 每段独立加密,段与段之间没有任何绑定。攻击者可以删掉中间某一段、复制某一段、调换顺序——解密方完全察觉不到。这和 ECB 模式的分组重排问题是同一类。
难维护。 切分长度依赖填充方案和摘要算法,改任何一个参数,所有历史密文都要重算。
正确做法:混合加密
RSA 从设计上就不是用来直接加密数据的,它是用来传密钥的。TLS、PGP、JWE、S/MIME 全都是这个结构。
发送方:
- 生成一把一次性的随机 AES 密钥(32 字节,来自密码学安全随机源)
- 用 AES-GCM 加密真实数据,nonce 也随机生成
- 用对方的 RSA 公钥加密那把 AES 密钥——只有 32 字节,任何密钥长度配任何填充都放得下
- 把四段一起发出去:
RSA 加密后的 AES 密钥 (256 字节,RSA-2048)
nonce (12 字节)
AES-GCM 密文 (和明文等长)
认证标签 (16 字节)
接收方: 用 RSA 私钥解出 AES 密钥,再用它解密数据。
为什么这是安全的:RSA 保护的是那 32 字节的一次性随机密钥——没有任何结构可供攻击者利用;数据本身由 AES-GCM 保护,既保密又能检测篡改。两边各自做自己擅长的事。
密钥长度怎么选
| 长度 | 安全强度 | 运算相对成本 | 建议 |
|---|---|---|---|
| RSA-1024 | 约 80 位 | 基准 | ❌ 只用来解历史数据 |
| RSA-2048 | 约 112 位 | 约 6 倍 | ✅ 当前主流 |
| RSA-3072 | 约 128 位 | 约 20 倍 | 长期保密的数据 |
| RSA-4096 | 约 140 位 | 约 40 倍 | 保守场景,注意并发代价 |
RSA-1024 从 2010 年起就不再被 NIST 推荐,各大 CA 早已停止签发。本站工具保留它只是为了让你能解出历史数据。
一个实际的取舍:如果只是保护短期数据且并发量大,RSA-2048 完全够用。如果数据要保密十年以上,考虑 RSA-3072,或者干脆换椭圆曲线——EC P-256 的安全强度接近 RSA-3072,密钥只有 32 字节,运算快一个量级。
动手验证
RSA 加解密会在加密前先算出当前组合的上限,超了就明确告诉你「明文多少字节、上限多少字节」,而不是抛一个 data too large for key size 让你自己猜。
工具支持 PKCS#1 v1.5 和 OAEP 两种填充,OAEP 可选 SHA-1 / SHA-256 / SHA-384 / SHA-512,能直接对照出摘要强度对上限的影响。密钥对生成、加解密、签名验签全在浏览器本地完成,私钥不会离开你的设备。
如果你手上的密钥 PEM 贴进去解析不了,那多半是格式问题不是长度问题,见 RSA 密钥格式认不出来:PKCS#1、PKCS#8、SPKI 到底差在哪。