3.19 RSA机制详解:非对称加密的“门面担当“
一个场景:你需要生成签名
假设你正在开发一个电子合同系统。
合同签署需要数字签名。你查了一下,发现RSA是最常用的签名算法。
但打开PKCS#11规范,搜索“RSA“——
发现15种RSA机制。
CKM_RSA_PKCS、CKM_RSA_PKCS_PSS、CKM_RSA_X_509、CKM_RSA_PKCS_OAEP…
你可能会困惑:
- PKCS和PSS有什么区别?
- 哪个签名机制更安全?
- OAEP是什么,为什么加密用OAEP?
更深层的问题是:
为什么RSA有签名和加密两种用途,机制还不同?
“门面担当“的设计意图
RSA是密码学的“门面担当“——最早、最著名、最广泛使用的非对称算法:
门面担当类比:
RSA(门面担当)
│
├── 为什么是"门面"?
│ ├── 1977年发明(最早的实用非对称算法)
│ ├── 历史最悠久
│ ├── 使用最广泛
│ ├── 几乎所有密码库都支持
│ └── 开发者最熟悉的非对称算法
│
├── 为什么有多种"面孔"?
│ ├── 签名面孔(PKCS#1 v1.5、PSS)
│ ├── 加密面孔(PKCS#1 v1.5、OAEP)
│ ├── 原始面孔(X.509,不推荐)
│ └── 密钥生成面孔
│ └── 每种用途需要不同的机制
│
├── 为什么需要PSS和OAEP?
│ ├── PKCS#1 v1.5有安全漏洞
│ ├── PSS解决了签名安全问题
│ ├── OAEP解决了加密安全问题
│ └── 新机制更安全,但旧机制仍兼容
│
└── 现代选择:
├── 签名:PSS(推荐)
├── 加密:OAEP(推荐)
└── 密钥长度:2048位以上
RSA机制概览
RSA是最经典的非对称加密算法,PKCS#11支持多种RSA机制:
RSA机制列表:
密钥生成:
CKM_RSA_PKCS_KEY_PAIR_GEN RSA密钥对生成(PKCS#1)
签名机制:
CKM_RSA_PKCS PKCS#1 v1.5签名
CKM_RSA_PKCS_PSS PSS签名(更安全)
CKM_RSA_X_509 原始RSA签名(不推荐)
加密机制:
CKM_RSA_PKCS PKCS#1 v1.5加密
CKM_RSA_PKCS_OAEP OAEP加密(更安全)
CKM_RSA_X_509 原始RSA加密(不推荐)
密钥包装:
CKM_RSA_PKCS PKCS#1 v1.5包装
CKM_RSA_PKCS_OAEP OAEP包装
带哈希的签名:
CKM_SHA256_RSA_PKCS SHA-256 + PKCS签名
CKM_SHA256_RSA_PKCS_PSS SHA-256 + PSS签名
CKM_SHA384_RSA_PKCS SHA-384 + PKCS签名
CKM_SHA512_RSA_PKCS SHA-512 + PKCS签名
RSA密钥生成
RSA密钥对通过C_GenerateKeyPair生成:
/* RSA密钥对生成 */
CK_MECHANISM mechanism = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0};
CK_ULONG modulusBits = 2048; // 密钥长度
CK_BYTE publicExponent[] = {0x01, 0x00, 0x01}; // 65537(推荐)
CK_BBOOL bTrue = CK_TRUE;
CK_BBOOL bFalse = CK_FALSE;
CK_ATTRIBUTE publicKeyTemplate[] = {
{CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits)},
{CKA_PUBLIC_EXPONENT, publicExponent, sizeof(publicExponent)},
{CKA_ENCRYPT, &bTrue, sizeof(bTrue)},
{CKA_VERIFY, &bTrue, sizeof(bTrue)}
};
CK_ATTRIBUTE privateKeyTemplate[] = {
{CKA_SENSITIVE, &bTrue, sizeof(bTrue)}, // 私钥不可读取
{CKA_EXTRACTABLE, &bFalse, sizeof(bFalse)}, // 私钥不可导出
{CKA_DECRYPT, &bTrue, sizeof(bTrue)},
{CKA_SIGN, &bTrue, sizeof(bTrue)}
};
CK_OBJECT_HANDLE hPublicKey, hPrivateKey;
rv = C_GenerateKeyPair(hSession, &mechanism,
publicKeyTemplate, 4,
privateKeyTemplate, 4,
&hPublicKey, &hPrivateKey);
密钥参数选择:
RSA密钥参数选择:
密钥长度:
├── 1024位:已不安全,禁用
├── 2048位:推荐(2030年前安全)
├── 3072位:等效128位安全强度
└── 4096位:等效约140位安全强度
公钥指数:
├── 3:不推荐(安全风险)
├── 17:可用
├── 65537:推荐(标准选择)
└── 固定值,便于快速运算
安全属性:
├── CKA_SENSITIVE = TRUE:私钥值不可读取
├── CKA_EXTRACTABLE = FALSE:私钥不可导出
└── 这些属性设置后不可更改
PKCS#1 v1.5签名:经典但有问题
PKCS#1 v1.5是最早的RSA签名标准:
/* PKCS#1 v1.5签名示例 */
CK_MECHANISM mechanism = {CKM_RSA_PKCS, NULL_PTR, 0};
rv = C_SignInit(hSession, &mechanism, hPrivateKey);
rv = C_Sign(hSession, data, dataLen, signature, &sigLen);
PKCS#1 v1.5签名结构:
PKCS#1 v1.5签名结构:
签名 = RSA私钥运算(填充后的数据)
填充格式:
├── 0x00 0x01 [0xFF...0xFF] 0x00 [DigestInfo]
├── DigestInfo = AlgorithmID + Hash值
└── 填充使签名长度等于模数长度
安全问题:
├── Bleichenbacher攻击(1998年)
├── 选择密文攻击
└── 可能伪造签名
建议:
├── 仅用于兼容旧系统
├── 新系统使用PSS
└── 生产环境不推荐
PSS签名:现代安全标准
PSS(Probabilistic Signature Scheme)是现代推荐:
/* PSS签名示例 */
CK_RSA_PKCS_PSS_PARAMS pssParams = {
.hashAlg = CKM_SHA256, // Hash算法
.mgf = CKG_MGF1_SHA256, // MGF函数
.sLen = 32 // Salt长度
};
CK_MECHANISM mechanism = {CKM_RSA_PKCS_PSS, &pssParams, sizeof(pssParams)};
rv = C_SignInit(hSession, &mechanism, hPrivateKey);
rv = C_Sign(hSession, data, dataLen, signature, &sigLen);
PSS特点:
PSS签名特点:
优点:
├── 随机Salt,每次签名不同
├── 抗选择密文攻击
├── 安全性可证明
└── 现代推荐标准
参数选择:
├── hashAlg:推荐SHA-256或SHA-384
├── mgf:使用MGF1,与Hash相同
└── sLen:推荐等于Hash长度
安全建议:
├── 新系统使用PSS
├── Salt长度等于Hash长度
└── 避免sLen = 0(固定签名)
带Hash的签名机制
PKCS#11提供组合机制,自动处理Hash:
/* SHA-256 + PSS签名示例 */
CK_RSA_PKCS_PSS_PARAMS pssParams = {
.hashAlg = CKM_SHA256,
.mgf = CKG_MGF1_SHA256,
.sLen = 32
};
CK_MECHANISM mechanism = {CKM_SHA256_RSA_PKCS_PSS, &pssParams, sizeof(pssParams)};
rv = C_SignInit(hSession, &mechanism, hPrivateKey);
rv = C_Sign(hSession, data, dataLen, signature, &sigLen);
// 注意:传入原始数据,不是Hash值
// HSM内部自动计算SHA-256
组合机制的好处:
组合机制(带Hash的签名):
使用组合机制:
├── CKM_SHA256_RSA_PKCS_PSS
├── 输入原始数据(不是Hash)
├── HSM内部自动Hash
└── 更安全(Hash在HSM内完成)
不使用组合机制:
├── 先在外部计算Hash
├── 再调用CKM_RSA_PKCS_PSS
├── 输入Hash值
└── Hash值可能在Host暴露
推荐:使用组合机制
├── Hash在HSM内完成
├── 避免Host暴露Hash值
└── 更安全
OAEP加密:现代加密标准
OAEP(Optimal Asymmetric Encryption Padding)是推荐:
/* OAEP加密示例 */
CK_RSA_PKCS_OAEP_PARAMS oaepParams = {
.hashAlg = CKM_SHA256, // Hash算法
.mgf = CKG_MGF1_SHA256, // MGF函数
.source = CKZ_DATA_SPECIFIED,// 源数据类型
.pSourceData = label, // 可选Label
.ulSourceDataLen = labelLen // Label长度
};
CK_MECHANISM mechanism = {CKM_RSA_PKCS_OAEP, &oaepParams, sizeof(oaepParams)};
rv = C_EncryptInit(hSession, &mechanism, hPublicKey);
rv = C_Encrypt(hSession, data, dataLen, encrypted, &encLen);
OAEP特点:
OAEP加密特点:
优点:
├── 随机填充,每次加密不同
├── 抗选择密文攻击
├── 安全性可证明
└── 现代推荐标准
参数选择:
├── hashAlg:推荐SHA-256
├── mgf:使用MGF1
└── source:可设为CKZ_DATA_SPECIFIED
Label(可选):
├── 可以添加标签数据
├── 用于区分不同加密
└── 增强安全性
加密长度限制:
├── 最大明文长度 = 模数长度 - 2*Hash长度 - 2
├── 如:2048位RSA,SHA-256
├── 最大明文 = 256 - 64 - 2 = 190字节
└── 大数据需要分段或用对称加密
X.509原始RSA:不推荐
X.509是“裸RSA“,没有填充:
/* X.509原始RSA(不推荐) */
CK_MECHANISM mechanism = {CKM_RSA_X_509, NULL_PTR, 0};
rv = C_SignInit(hSession, &mechanism, hPrivateKey);
rv = C_Sign(hSession, hashValue, hashLen, signature, &sigLen);
为什么不推荐:
X.509原始RSA问题:
问题:
├── 没有填充保护
├── 相同输入产生相同输出
├── 可被数学攻击
└── 不安全
使用场景:
├── 仅用于特殊协议
├── 需要明确知道风险
└── 一般应用禁用
替代:
├── 签名用PSS
├── 加密用OAEP
└── 不要用X.509
签名vs加密:机制选择
RSA有两种用途,机制不同:
签名vs加密机制选择:
用途 推荐机制 原因
──────────────────────────────────────────
签名 PSS 安全,随机Salt
签名(兼容) PKCS#1 v1.5 旧系统兼容
加密 OAEP 安全,随机填充
加密(兼容) PKCS#1 v1.5 旧系统兼容
密钥包装 OAEP 安全
──────────────────────────────────────────
重要区别:
├── 签名用私钥(hPrivateKey)
├── 验证用公钥(hPublicKey)
├── 加密用公钥(hPublicKey)
├── 解密用私钥(hPrivateKey)
└── 密钥不同,机制选择也不同
一个类比:门面担当的多种“面孔“
门面担当的多种面孔类比:
RSA算法(名人)
│
├── 签名面孔(盖章)
│ │
│ ├── PKCS#1 v1.5签名
│ │ ├── 像传统印章
│ │ ├── 固定格式
│ │ ├── 有安全问题
│ │ └── 仅用于兼容
│ │
│ └── PSS签名
│ │ ├── 像防伪印章
│ │ ├── 加随机Salt
│ │ ├── 每次不同
│ │ ├── 防伪造
│ │ └── 推荐使用
│ │
│ └── 组合签名(带Hash)
│ │ ├── 像全自动盖章机
│ │ ├── 自动盖Hash + 章印
│ │ └── 最推荐
│
├── 加密面孔(密封)
│ │
│ ├── PKCS#1 v1.5加密
│ │ ├── 像普通信封
│ │ ├── 有安全问题
│ │ └── 仅用于兼容
│ │
│ └── OAEP加密
│ │ ├── 像防拆信封
│ │ ├── 随机填充
│ │ ├── 防篡改
│ │ └── 推荐使用
│
└── X.509原始RSA
├── 像没有任何保护的裸操作
├── 不安全
└── 禁用
关键:
├── 根据用途选择机制
├── 签名用PSS
├── 加密用OAEP
└── 避免X.509
本篇小结
RSA是非对称加密的“门面担当“:
机制数量:
- 约15种RSA机制
- 密钥生成、签名、加密、包装
密钥生成:
- CKM_RSA_PKCS_KEY_PAIR_GEN
- 推荐2048位以上
签名机制:
- PKCS#1 v1.5:经典,有问题
- PSS:现代,推荐
- 组合机制:带Hash,更安全
加密机制:
- PKCS#1 v1.5:经典,有问题
- OAEP:现代,推荐
安全建议:
- 签名:PSS(或组合机制)
- 加密:OAEP
- 密钥:2048位以上
- 禁用:X.509
下一节,我们将分析ECDSA与ECDH机制——椭圆曲线密码学的“新生代“。
【下集预告】
ECDSA如何签名?
ECDH如何密钥交换?
椭圆曲线如何选择?
EC与RSA哪个更安全?
下一节,ECDSA与ECDH机制。