3.20 ECC与哈希机制:现代密码学的“双子星“
ECC机制概览
ECC(椭圆曲线密码学)提供比RSA更高效的非对称加密:
ECC机制列表:
密钥生成:
CKM_EC_KEY_PAIR_GEN EC密钥对生成(通用,通过曲线参数区分ECDSA/ECDH)
签名机制:
CKM_ECDSA ECDSA签名
CKM_ECDSA_SHA1 ECDSA + SHA1哈希
CKM_ECDSA_SHA256 ECDSA + SHA256哈希
CKM_ECDSA_SHA384 ECDSA + SHA384哈希
CKM_ECDSA_SHA512 ECDSA + SHA512哈希
密钥协商:
CKM_ECDH1_DERIVE ECDH密钥派生
CKM_ECDH1_COFACTOR_DERIVE ECDH cofactor密钥派生
CKM_ECMQV_DERIVE ECMQV密钥派生
国密ECC(厂商扩展,非PKCS#11 v3.1标准):
CKM_SM2_KEY_PAIR_GEN SM2密钥对生成
CKM_SM2 SM2签名/加密
CKM_SM2_SM3 SM2 + SM3签名
注意:SM2、SM3等国密机制是厂商对PKCS#11的扩展,并非OASIS PKCS#11 v3.1标准规范的一部分。具体实现和机制值由各厂商定义。
ECC密钥生成
EC密钥对需要指定曲线参数:
常用椭圆曲线:
NIST曲线:
P-192 (192位,已不推荐)
P-224 (224位,过渡期)
P-256 (256位,最常用)
P-384 (384位,高安全)
P-521 (521位,最高安全)
其他曲线:
Curve25519 (255位,现代推荐)
Brainpool曲线(欧洲推荐)
SM2曲线 (中国标准)
OID编码示例:
P-256:1.2.840.10045.3.1.7
Curve25519:1.3.101.110
/* EC密钥对生成(P-256) */
CK_MECHANISM mechanism = {CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0};
// P-256曲线OID
CK_BYTE ecParams[] = {
0x06, 0x08, // OID标签和长度
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07 // P-256 OID
};
CK_ATTRIBUTE publicKeyTemplate[] = {
{CKA_EC_PARAMS, ecParams, sizeof(ecParams)},
{CKA_VERIFY, &true, sizeof(true)}
};
CK_ATTRIBUTE privateKeyTemplate[] = {
{CKA_SENSITIVE, &true, sizeof(true)},
{CKA_SIGN, &true, sizeof(true)},
{CKA_DERIVE, &true, sizeof(true)} // 支持密钥派生
};
CK_OBJECT_HANDLE hPublicKey, hPrivateKey;
rv = C_GenerateKeyPair(hSession, &mechanism,
publicKeyTemplate, 2,
privateKeyTemplate, 3,
&hPublicKey, &hPrivateKey);
ECC与RSA的安全对比
ECC vs RSA:等效安全强度
RSA密钥长度 ECC密钥长度 安全级别
───────────────────────────────────────
1024位 160位 已不安全
2048位 224-256位 当前标准
3072位 256-384位 高安全
7680位 384-512位 极高安全
15360位 512+位 最高安全
ECC优势:
- 更短的密钥长度
- 更快的计算速度
- 更低的资源消耗
- 更适合嵌入式系统
车载推荐:
- P-256:一般安全场景
- P-384:高安全场景
- Curve25519:现代新系统
ECDSA签名
ECDSA是椭圆曲线数字签名算法:
/* ECDSA-SHA256签名 */
CK_MECHANISM mechanism = {CKM_ECDSA_SHA256, NULL_PTR, 0};
rv = C_SignInit(hSession, &mechanism, hPrivateKey);
CK_BYTE data[] = "Data to sign";
CK_BYTE signature[64]; // P-256签名 = 32+32字节(r+s)
CK_ULONG sigLen = 64;
rv = C_Sign(hSession, data, sizeof(data)-1, signature, &sigLen);
签名结构:
ECDSA签名格式:
P-256签名(64字节):
┌──────────────────────────────┐
│ r(32字节) │ 签名第一部分
├──────────────────────────────┤
│ s(32字节) │ 签名第二部分
└──────────────────────────────┘
特点:
- 签名长度 = 2 * 曲线字段长度
- P-256签名 = 64字节
- P-384签名 = 96字节
ECDSA验证
/* ECDSA-SHA256验证 */
CK_MECHANISM mechanism = {CKM_ECDSA_SHA256, NULL_PTR, 0};
rv = C_VerifyInit(hSession, &mechanism, hPublicKey);
CK_BYTE data[] = "Data to sign";
CK_BYTE signature[64];
CK_ULONG sigLen = 64;
rv = C_Verify(hSession, data, sizeof(data)-1, signature, sigLen);
if (rv == CKR_OK) {
printf("ECDSA签名验证成功\n");
} else if (rv == CKR_SIGNATURE_INVALID) {
printf("ECDSA签名验证失败\n");
}
ECDH密钥协商
ECDH用于安全协商共享密钥:
ECDH密钥协商流程:
Alice Bob
────────────────────────────────────────
生成EC密钥对 生成EC密钥对
├─ 私钥A ├─ 私钥B
└─ 公钥A └─ 公钥B
交换公钥:
←──────── 公钥B ────────→
←──────── 公钥A ────────→
派生共享密钥:
C_DeriveKey(私钥A, 公钥B) C_DeriveKey(私钥B, 公钥A)
↓ ↓
共享密钥K ←───相同───→ 共享密钥K
/* ECDH密钥派生 */
CK_ECDH1_DERIVE_PARAMS ecdhParams = {
.kdf = CKD_NULL, // 密钥派生函数(可选)
.ulSharedDataLen = 0,
.pSharedData = NULL_PTR,
.ulPublicDataLen = sizeof(bobPublicKey), // Bob公钥长度
.pPublicData = bobPublicKey // Bob的公钥数据
};
CK_MECHANISM mechanism = {
CKM_ECDH1_DERIVE,
&ecdhParams,
sizeof(ecdhParams)
};
CK_ULONG keyLen = 32; // 派生32字节AES密钥
CK_ATTRIBUTE keyTemplate[] = {
{CKA_KEY_TYPE, &(CK_KEY_TYPE){CKK_AES}, sizeof(CK_KEY_TYPE)},
{CKA_VALUE_LEN, &keyLen, sizeof(keyLen)},
{CKA_SENSITIVE, &true, sizeof(true)}
};
CK_OBJECT_HANDLE hSharedKey;
rv = C_DeriveKey(hSession, &mechanism, hPrivateKeyA,
keyTemplate, 3, &hSharedKey);
if (rv == CKR_OK) {
printf("共享密钥派生成功\n");
// Alice和Bob派生的密钥相同
}
Curve25519:现代椭圆曲线
Curve25519是现代推荐的椭圆曲线:
Curve25519特点:
安全性:
- 255位,等效于RSA-3072
- 设计安全,避免弱点
- 现代密码学推荐
性能:
- 极快计算速度
- 抗侧信道攻击设计
- 适合嵌入式系统
用途:
- X25519:密钥协商
- Ed25519:签名算法
PKCS#11支持:
CKM_EC_MONTGOMERY_KEY_PAIR_GEN X25519/X448密钥生成
CKM_ECDH1_DERIVE 密钥协商(通过曲线参数指定)
CKM_EC_EDWARDS_KEY_PAIR_GEN Ed25519/Ed448密钥生成
CKM_EDDSA EdDSA签名
哈希机制概览
哈希机制用于计算数据摘要:
哈希机制列表:
SHA系列:
CKM_SHA_1 SHA-1(160位,已不推荐)
CKM_SHA224 SHA-224(224位)
CKM_SHA256 SHA-256(256位)★最常用
CKM_SHA384 SHA-384(384位)
CKM_SHA512 SHA-512(512位)
SHA-3系列:
CKM_SHA3_224 SHA3-224
CKM_SHA3_256 SHA3-256
CKM_SHA3_384 SHA3-384
CKM_SHA3_512 SHA3-512
其他:
CKM_MD5 MD5(128位,已不安全)
CKM_RIPEMD160 RIPEMD-160
国密:
CKM_SM3 SM3(256位)
SHA-256哈希计算
/* SHA-256哈希 */
CK_MECHANISM mechanism = {CKM_SHA256, NULL_PTR, 0};
rv = C_DigestInit(hSession, &mechanism);
CK_BYTE data[] = "Data to hash";
CK_BYTE digest[32]; // SHA-256输出32字节
CK_ULONG digestLen = 32;
rv = C_Digest(hSession, data, sizeof(data)-1, digest, &digestLen);
if (rv == CKR_OK) {
printf("SHA-256哈希值:");
for (int i = 0; i < 32; i++) {
printf("%02x", digest[i]);
}
printf("\n");
}
HMAC机制
HMAC使用密钥进行哈希运算:
HMAC机制列表:
CKM_SHA_1_HMAC HMAC-SHA1(已不推荐)
CKM_SHA224_HMAC HMAC-SHA224
CKM_SHA256_HMAC HMAC-SHA256 ★最常用
CKM_SHA384_HMAC HMAC-SHA384
CKM_SHA512_HMAC HMAC-SHA512
CKM_MD5_HMAC HMAC-MD5(已不安全)
国密:
CKM_SM3_HMAC HMAC-SM3
/* HMAC-SHA256计算 */
CK_MECHANISM mechanism = {CKM_SHA256_HMAC, NULL_PTR, 0};
rv = C_SignInit(hSession, &mechanism, hHmacKey);
CK_BYTE message[] = "Message to authenticate";
CK_BYTE mac[32]; // HMAC输出=哈希长度
CK_ULONG macLen = 32;
rv = C_Sign(hSession, message, sizeof(message)-1, mac, &macLen);
if (rv == CKR_OK) {
printf("HMAC-SHA256值:");
for (int i = 0; i < 32; i++) {
printf("%02x", mac[i]);
}
printf("\n");
}
HMAC验证
/* HMAC验证 */
CK_MECHANISM mechanism = {CKM_SHA256_HMAC, NULL_PTR, 0};
rv = C_VerifyInit(hSession, &mechanism, hHmacKey);
CK_BYTE message[] = "Message to authenticate";
CK_BYTE receivedMac[32];
CK_ULONG macLen = 32;
rv = C_Verify(hSession, message, sizeof(message)-1, receivedMac, macLen);
if (rv == CKR_OK) {
printf("HMAC验证成功,消息真实\n");
} else if (rv == CKR_SIGNATURE_INVALID) {
printf("HMAC验证失败,消息可能被篡改\n");
}
HKDF:密钥派生函数
HKDF用于从基密钥派生多个子密钥:
HKDF用途:
密钥分层管理:
┌─────────────────────────────────────┐
│ 主密钥(Master Key) │
│ │
│ HKDF派生: │
│ ├─ 加密密钥(encryption key) │
│ ├─ HMAC密钥(authentication key) │
│ ├─ 会话密钥(session key) │
│ └─ IV生成密钥(IV derivation key) │
└─────────────────────────────────────┘
/* HKDF密钥派生 */
CK_HKDF_PARAMS hkdfParams = {
TRUE, /* bExtract */
TRUE, /* bExpand */
CKM_SHA256, /* prfHashMechanism */
CKZ_SALT_SPECIFIED, /* ulSaltType */
salt, sizeof(salt), /* pSalt, ulSaltLen */
CK_INVALID_HANDLE, /* hSaltKey */
info, sizeof(info) /* pInfo, ulInfoLen */
};
CK_MECHANISM mechanism = {
CKM_HKDF_DERIVE,
&hkdfParams,
sizeof(hkdfParams)
};
CK_ULONG keyLen = 32; // 派生32字节密钥
CK_ATTRIBUTE keyTemplate[] = {
{CKA_KEY_TYPE, &(CK_KEY_TYPE){CKK_AES}, sizeof(CK_KEY_TYPE)},
{CKA_VALUE_LEN, &keyLen, sizeof(CK_ULONG)}
};
CK_OBJECT_HANDLE hDerivedKey;
rv = C_DeriveKey(hSession, &mechanism, hMasterKey,
keyTemplate, 2, &hDerivedKey);
ECC在车载中的应用
车载ECC应用场景:
V2X安全通信:
┌─────────────────────────────────────┐
│ 发送方 │
│ │
│ message = {位置,速度,...} │
│ signature = ECDSA-SHA256(message) │
│ │
│ 发送:{message, signature} │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ 接收方 │
│ │
│ ECDSA-SHA256验证签名 │
│ → 消息真实可信 │
└─────────────────────────────────────┘
TLS密钥协商:
┌─────────────────────────────────────┐
│ TLS 1.3握手 │
│ │
│ 使用ECDHE密钥协商 │
│ ├─ X25519/P-256 │
│ ├─ 派生会话密钥 │
│ └─ 加密通信通道 │
└─────────────────────────────────────┘
固件签名验证:
┌─────────────────────────────────────┐
│ 安全启动 │
│ │
│ 固件签名 = ECDSA-SHA256 │
│ Boot ROM验证签名 │
│ → 固件可信 │
│ │
│ ECC比RSA更快 │
│ 车载启动时间敏感 │
└─────────────────────────────────────┘
哈希算法选择
哈希算法安全对比:
算法 输出长度 安全性 推荐度
───────────────────────────────────────
MD5 128位 已破解 ❌不推荐
SHA-1 160位 已破解 ❌不推荐
SHA-224 224位 安全 ⚠️可用
SHA-256 256位 安全 ✓推荐
SHA-384 384位 安全 ✓高安全
SHA-512 512位 安全 ✓高安全
SHA3-256 256位 安全 ✓现代
SM3 256位 安全 ✓中国标准
车载推荐:
SHA-256:一般场景,平衡性能和安全
SHA-384:高安全场景
SM3:中国合规要求
小结:ECC与哈希机制要点
核心要点回顾:
1. ECC密钥长度优势
- P-256等效RSA-2048
- P-384等效RSA-3072
- 更短密钥,更快计算
2. ECDSA签名特点
- 签名长度 = 2 * 曲线字段长度
- P-256签名 = 64字节
- 比RSA签名更短
3. ECDH密钥协商
- 双方交换公钥
- 派生相同共享密钥
- TLS/V2X常用
4. HMAC认证机制
- 使用密钥的哈希
- 验证消息真实性
- 比签名更高效
5. HKDF密钥派生
- 从主密钥派生子密钥
- 密钥分层管理
- 灵活且安全
6. 哈希算法选择
- 避免MD5、SHA-1
- 推荐SHA-256
- 高安全选SHA-384
ECC和哈希机制是现代密码学的核心,为车载安全提供高效、可靠的密码服务。 下一节,我们将综合实践——看安全属性的合理组合。
【下集预告】
最高安全密钥怎么配置?
可备份密钥怎么配置?
密钥包装怎么实现?
下一节,安全属性组合实战。