2. 密码学基础复习:对称加密、非对称加密、哈希与数字签名

这一章,咱们把密码学里最核心的几个算法拉出来遛一遛。你可能会想:“都搞PKCS11了,这些基础还用复习?”

没错,我个人习惯是每碰一个新项目,先快速过一遍密码学基础。因为后面你会看到, 里的所有操作——加密、签名、密钥生成——都绕不开它们。

我见过很多开发者在接口里乱填AES模式,或者把RSA私钥当公钥传。嗯,别笑,我也犯过。所以这一章我们聊透,避坑指南也一并送上。

核心观点: 密码学不是黑魔法,记住“保密、完整、认证、不可否认”四个目标,你就抓住了主线。

2.1 对称加密与AES

对称加密,说白了就是 一把钥匙开一把锁。加密和解密用同一个密钥。AES 是目前最主流的对称算法。

我在做金融加密机项目时遇到过一个问题:客户要求每笔交易用AES-256-CBC加密,但初始化向量(IV)必须固定。结果?密文模式严重,安全审计直接打回。后来我改成AES-256-GCM,用随机IV + 附加认证数据,问题才解决。

AES 关键参数

  • 密钥长度:128 / 192 / 256 位,长度越长越安全。
  • 工作模式:CBC(需要IV,不能并行)、GCM(支持认证,推荐)、CTR(可并行,无填充)。
  • 填充方式:PKCS7(CBC默认)、NoPadding(GCM/CTR不用填充)。
经验之谈: 新项目一律用 AES-256-GCM。它同时提供加密和完整性校验,避免单独算MAC的麻烦。
特性AES-128AES-192AES-256
密钥长度128 bit192 bit256 bit
轮数101214
安全强度高(非敏感场景)更高最高(推荐)
性能最快中等稍慢(但软硬件均支持)
避坑: 不要用ECB模式。我见过有人把ECB当默认模式,结果相同明文块产生相同密文块,信息泄露严重。GCM和CTR是现代推荐选择。

2.2 非对称加密:RSA与ECC

非对称加密,就是一对密钥:公钥加密,私钥解密(或反过来签名)。PKCS11里,私钥永远待在内,你只能操作句柄。

RSA

RSA基于大整数分解难题。密钥长度通常2048或4096位。我最早做CA系统时用RSA 1024,后来被安全规范禁止——现在最少2048。

RSA的签名和加密是两套模式:RSA_PKCS1_PADDING 和 RSA_PKCS1_OAEP_PADDING。OAEP更安全,我建议优先选它。

ECC(椭圆曲线密码学)

ECC用更短的密钥提供同等安全强度。比如256位ECC ≈ 3072位RSA。PKCS11常用的曲线有 P-256、P-384、P-521(对应secp256r1等)。

我在移动支付项目中推广过ECC,最大的痛点不是算法,而是曲线参数协商。不同厂商的支持的曲线可能不一样,接口里必须显式指定CKA_EC_PARAMS。

对比项RSA-2048ECC P-256
密钥长度2048 bit256 bit
签名速度慢快
验签速度较快较慢(但整体优于RSA)
推荐场景兼容性优先性能与带宽敏感
选型建议: 如果支持ECC,优先用P-256签名。我曾在旧设备上被迫用RSA,原因是固件不支持ECC。所以务必先查C_GetMechanismList。

2.3 哈希函数(SHA)

哈希就是把任意长数据变成固定长度的摘要,不可逆。SHA家族目前主力是 SHA-256、SHA-3-256。

我之前有个项目用了SHA-1做文件完整性校验,结果被攻击者在两个不同文件里碰撞出相同哈希。嗯,从那以后我见SHA-1就直接标红。

警示: SHA-1已经在实战中被破解碰撞。PKCS11接口里应禁用CKM_SHA_1机制,改用CKM_SHA256或以上。

常用哈希算法

  • SHA-256:输出32字节,安全可靠,签名前摘要的首选。
  • SHA-384:48字节,适合搭配P-384曲线。
  • SHA-512:64字节,更安全但慢,可配合SHA-3使用。
  • SHA-3:新一代标准,固件兼容性不如SHA-2,但更抗量子(当前)。
一个实用习惯: 我会在项目初始化时做一次哈希速度测试。有些低端做SHA-512很慢,换SHA-256能省一半时间。

2.4 数字签名原理

数字签名 = 哈希 + 私钥加密。你想想看,签名并不是直接加密整份文件,而是先取文件摘要,再用私钥对摘要加密,形成签名值。

验证时,接收方用同样的哈希算法计算文件摘要,然后用公钥解密签名,对比两个摘要。如果一致,就说明数据未被篡改,且签名者确实持有私钥。

我在做电子合同系统时,签名流程是典型三步:

  1. 调用的C_DigestInit + C_DigestUpdate 计算文件哈希。
  2. 用C_SignInit + C_Sign 对哈希摘要签名。
  3. 验签时用C_VerifyInit + C_Verify。
关键点: PKCS11标准里,签名操作直接在内部完成哈希计算(某些机制会组合哈希)。例如CKM_RSA_PKCS_PSS会自己管理盐和哈希。你不需要手工拼接。

我曾经踩过一个坑:在调用C_Sign之前,忘了调用C_SignUpdate传入数据。结果返回CKR_DATA_LEN_RANGE。嗯,细节决定成败。

数字签名完整流程 发送方 原始数据 (文件/消息) 哈希运算 SHA-256 私钥签名 (内操作) 传输 (数据 + 签名) 接收方 收到数据 (文件/消息) 哈希运算 SHA-256 公钥验签 解密签名→比较摘要 摘要一致 → 签名有效 摘要不一致 → 数据被篡改或签名伪造 做签名
一个容易被忽略的点: 签名之前,哈希运算也可以在内部完成。比如CKM_ECDSA_SHA256这种组合机制,会自己算SHA-256然后再签名。你只需要传入原始数据,不用手动哈希。

小结

这一章我们把AES、RSA/ECC、SHA和数字签名捋了一遍。你会发现,PKCS11接口就是把这些算法包装成标准函数调用。理解算法本身,才能理解为什么接口需要CKA_EC_PARAMS、为什么签名需要CKM_RSA_PKCS_PSS。