RSA-OAEP 是什么
OAEP(Optimal Asymmetric Encryption Padding)是 RFC 8017 定义的 RSA 加密填充方案:用哈希与掩码生成函数把随机性引入填充结构,使同一明文每次加密得到不同密文,并显著提升对选择密文攻击的抵抗能力。它是新系统做 RSA 加密时的推荐填充,与老式的 PKCS#1 v1.5 相比更安全。
基本信息
| 标准 | RFC 8017 §7.1(RSAES-OAEP) |
|---|---|
| 结构 | lHash 加填充串加 0x01 加消息,配合 MGF1 掩码生成 |
| 推荐哈希 | SHA-256,且 MGF1 使用同一哈希 |
| 明文上限 | 密钥长度减去两倍哈希长度再减 2(2048 位配 SHA-256 约 190 字节) |
| 对比 v1.5 | 抗 Bleichenbacher 类攻击能力更强 |
| 典型用途 | 密钥封装、接口敏感字段加密、混合加密的密钥传递 |
典型使用场景
- 混合加密:用 OAEP 只封装一次性对称密钥,正文交给 AES-GCM
- 接口加密:客户端用服务端公钥加密敏感字段后提交
- 密钥分发:把数据密钥通过 RSA 公钥安全传递
- 跨系统对接:对方只支持 RSA 时的默认填充选择
- 合规整改:把遗留的 PKCS#1 v1.5 加密方案升级为 OAEP
Python 示例(cryptography)
Python 示例(cryptography)
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
# OAEP 的哈希与 MGF1 哈希需保持一致,并与对端约定
ct = public_key.encrypt(
message,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None, # label 默认为空,双方必须一致
),
)
# 解密失败时对外统一报错,不要区分填充与内容错误命令行生成密钥并检查长度
命令行生成密钥并检查长度
# 生成 3072 位密钥,OAEP 下可加密的明文上限随密钥长度增加
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:3072 -out rsa.key
# 查看密钥长度,估算明文上限(k - 2h - 2,h 为哈希长度)
openssl rsa -in rsa.key -noout -text | head -2
# 导出公钥用于对端加密
openssl rsa -in rsa.key -pubout -out rsa.pub与填充方案对照
| 填充 | 用途 | 明文上限 | 评价 |
|---|---|---|---|
| RSAES-OAEP | 加密 | 密钥长度减两倍哈希长度再减 2 | 新系统首选,抗选择密文攻击 |
| RSAES-PKCS1-v1.5 | 加密 | 密钥长度减 11 字节 | 遗留兼容,解密端错误分类必须统一 |
| RSASSA-PSS | 签名 | 按哈希与盐长度确定 | 推荐签名方案 |
| RSASSA-PKCS1-v1.5 | 签名 | 同上 | 兼容性最好,新系统优先 PSS |
解密失败时对外必须统一响应:错误码、响应体与处理耗时都不应有差异。只要攻击者能区分「填充错误」与「内容错误」,就可能重演针对 RSA 填充的密文选择攻击,OAEP 的结构优势也会被这种侧信道抵消。
OAEP 的哈希算法与 MGF1 哈希不一致时部分库会拒绝解密,跨系统对接务必显式约定;label 参数若一方传空、另一方传固定值,也会导致解密失败,而错误信息通常只写「解密失败」。