加密算法基础95 条

RSA 公钥算法

1977 年提出的公钥算法,基于大整数分解难题,可同时用于加密与签名;RFC 8017(PKCS#1 v2.2)是其主流实现规范,新系统推荐 3072 位密钥。

加密与证书速查安全更新于 2026-10-13

RSA 是什么

RSA 是 1977 年提出的公钥算法,安全性建立在大整数分解难题上,同一对密钥既能做签名也能做加密。工程上它运算慢、密文长,所以几乎不直接加密业务数据,而是用于签名,或用「RSA 加密对称密钥、对称算法加密正文」的混合加密。当前实现规范是 RFC 8017(PKCS #1 v2.2):加密推荐 OAEP 填充,签名推荐 PSS 填充。

基本信息

标准RFC 8017 / FIPS 186-5
数学基础大整数分解难题,运算为模幂
常用密钥长度2048(约 112 位强度)/ 3072(约 128 位)/ 4096 位
加密填充RSAES-OAEP(推荐);PKCS#1 v1.5 属遗留
签名填充RSASSA-PSS(推荐);RSASSA-PKCS1-v1.5 仍广泛兼容
典型用途证书签名、代码签名、JWT RS256/PS256、密钥封装

典型使用场景

  • TLS 证书签名:CA 用 RSA 私钥签服务器证书,握手时客户端验签
  • SSH 登录密钥:rsa 2048/4096 密钥对仍是存量环境的主流形式
  • 代码与固件签名:发布物签名后由安装端用公钥验签
  • JWT 与开放平台接口:RS256/PS256 用于第三方校验令牌来源
  • 接口字段加密:RSA 加密一次性对称密钥,正文交给 AES-GCM 处理
  • 邮件与文档签名:S/MIME、PDF 签章的底层签名算法之一

生成与签名验签

生成与签名验签
# 生成 3072 位密钥(新系统推荐,2048 位用于兼容存量)
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:3072 -out rsa.key
# 导出公钥,交付对方验签用;私钥始终留在本机并 chmod 600
openssl rsa -in rsa.key -pubout -out rsa.pub
# 确认密钥长度与格式:BEGIN PRIVATE KEY 是 PKCS#8,BEGIN RSA PRIVATE KEY 是 PKCS#1
openssl rsa -in rsa.key -noout -text | head -2
# 私钥签名、公钥验签(先哈希再签名,SHA-256)
openssl dgst -sha256 -sign rsa.key -out sig.bin data.bin
openssl dgst -sha256 -verify rsa.pub -signature sig.bin data.bin

填充方案对照

方案用途最小消息/上限评价
RSAES-OAEP加密明文上限 k-2hLen-2 字节新系统首选,可抵御 Bleichenbacher 类攻击
RSAES-PKCS1-v1.5加密明文上限 k-11 字节遗留兼容,解密端错误分类必须统一
RSASSA-PSS签名随哈希与盐长度固定推荐,具备可证明安全性
RSASSA-PKCS1-v1.5签名同上兼容性最好,新系统若可用优先 PSS
RSA 加密有严格长度上限:2048 位密钥配 SHA-256 的 OAEP 只能加密约 190 字节。超过上限必须走混合加密,不要试图分段裸加密(分段会带来顺序与重排问题)。
签名与加密应使用不同的密钥对,并在证书里通过 KeyUsage 标明用途。同一对密钥兼作两种用途会扩大暴露面,也让密钥轮换更困难。2048 位目前仍可用,但新签发材料建议直接上 3072 位;后量子迁移需要提前清点算法与数据留存周期。

混合加密流程(示意)

混合加密流程(示意)
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from cryptography.hazmat.primitives.asymmetric import padding   # OAEP
import os

# 发送方:随机生成数据密钥,用接收方 RSA 公钥只封装这把密钥
key = AESGCM.generate_key(bit_length=256)
nonce = os.urandom(12)
wrapped = peer_public.encrypt(key, padding.OAEP(mgf=padding.MGF1(hashes.SHA256()),
                                              algorithm=hashes.SHA256(), label=None))
body = AESGCM(key).encrypt(nonce, payload, None)   # 正文走 AEAD,快且防篡改
# 接收方:先用自己私钥解出数据密钥(失败统一报错),再解正文与校验标签

密钥与格式常见组合

形式典型文件用途与注意点
PKCS#8 私钥BEGIN PRIVATE KEY新工具链默认格式,OpenSSL 1.0 起推荐
PKCS#1 私钥BEGIN RSA PRIVATE KEY老系统与部分 Java 库要求,需要时显式转换
X.509 公钥BEGIN PUBLIC KEY交付对方验签或加密,不含任何私密信息
SSH 公钥ssh-rsa AAAA...仅用于 SSH 登录,与 TLS 证书格式不能直接混用
证书内公钥openssl x509 -pubkey以证书为信任载体的场景,验签方只需信任证书
跨系统对接签名时,先对齐三件事:填充方案(PSS 还是 v1.5)、哈希算法、以及签名字节的编码方式。这三项任一处不一致都会表现为验签失败,而报错信息往往只写「签名无效」,排错成本很高。

易错点

  • 误用 PKCS#1 v1.5 加密:解密端一旦对「填充错误」与「内容错误」给出不同响应或不同耗时,就会形成 Bleichenbacher 类填充预言,密文可被逐字节解出
  • 用 RSA 直接加密大文件:超过填充上限会直接报错,强行分段又引入重排与丢失保护问题,应改为 RSA 封装对称密钥的混合加密
  • 私钥权限过宽(644 或属主错误)或随代码仓库提交:私钥泄漏后所有历史签名与已加密数据都要作废重建
  • 把密钥长度当成唯一安全指标:2048 位配 v1.5 填充的加密方案,风险往往高于 3072 位配 OAEP 的同类方案
  • 只导出公钥时用错命令:openssl rsa -in key 在处理 PKCS#8 私钥时行为与预期不同,跨工具链对接前先确认输出格式

数据来源与参考

  • RFC 8017(PKCS #1 v2.2)
  • FIPS 186-5(数字签名标准)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌