密码学基础:从对称到非对称,再到哈希与签名
对称加密:一把钥匙开一把锁
对称加密,说白了就是加密和解密用同一把密钥。我刚开始接触HSM时觉得这很简单,后来发现密钥管理的坑比想象中多得多。
金融行业最常用的是AES。密钥长度支持128、192、256位,实际项目中我几乎只用AES-256。为什么?监管要求加上一点安全冗余。
记得有一次,第三方厂商用AES-ECB模式加密卡片数据,结果明文模式暴露了数据规律。你想想看,ECB同样的明文块会产生同样的密文块,这在金融场景下非常危险。
下面是最简单的Python演示(使用cryptography库):
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import os
key = os.urandom(32) # AES-256
iv = os.urandom(12) # 96位IV,用于GCM
cipher = Cipher(algorithms.AES(key), modes.GCM(iv), backend=default_backend())
encryptor = cipher.encryptor()
plaintext = b"金融交易敏感数据"
ciphertext = encryptor.update(plaintext) + encryptor.finalize()
tag = encryptor.tag
GCM输出时要把ciphertext和tag一起传给接收方,接收方用相同密钥和IV进行解密+认证。如果tag校验失败,说明数据被改过。
| 特性 | AES-128 | AES-192 | AES-256 |
|---|---|---|---|
| 密钥长度 | 128 bit | 192 bit | 256 bit |
| 轮数 | 10 | 12 | 14 |
| 安全级别 | 可接受 | 良好 | 极高 |
| 金融推荐 | ❌ | ❌ | ✅ |
非对称加密:公钥与私钥的舞蹈
非对称加密有两个钥匙:公钥加密,私钥解密。RSA和ECC是金融HSM里最常见的两种。
RSA基于大整数分解困难,密钥长度越长越安全。目前RSA-2048是底线,RSA-4096也常见。但我个人更倾向于转向ECC——同等安全强度下,ECC密钥短很多,运算也快。
举个例子,256位ECC和3072位RSA的安全级别相当,但ECC的私钥只有32字节,签名速度也快十几倍。HSM硬件在处理大量交易签名时,这个差距很可观。
from cryptography.hazmat.primitives.asymmetric import rsa, ec
from cryptography.hazmat.primitives import serialization
# 生成RSA-2048密钥对
private_key_rsa = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)
# 生成ECC P-256密钥对
private_key_ecc = ec.generate_private_key(
ec.SECP256R1(), # prime256v1
backend=default_backend()
)
| 对比项 | RSA-2048 | ECC P-256 |
|---|---|---|
| 密钥长度 | 2048 bit | 256 bit |
| 签名速度 | 较慢 | 较快 |
| 量子安全 | 脆弱 | 同样脆弱 |
| HSM支持 | 非常成熟 | 逐渐普及 |
我在一个跨境支付项目里把RSA2154迁移到了ECC P-384,HSM硬件直接支持,签名性能提升了近3倍。嗯,迁移时一定要注意HSM固件版本是否兼容指定的椭圆曲线。
哈希函数:不可逆的指纹
哈希函数能把任意数据压缩成固定长度的“指纹”,而且无法逆向。金融行业用它做完整性校验、数字签名的摘要计算。
SHA-256是目前最稳妥的。虽然SHA-3已经发布,但硬件支持还不够普遍。我建议现阶段统一用SHA-256,除非HSM明确支持SHA-3加速。
有一个老掉牙的坑:MD5。几年前我审计一个合作方接口,发现他们竟然还在用MD5做报文完整性校验。你想想看,MD5碰撞攻击已经公开了十多年,金融数据用MD5等于裸奔。当场就被我驳回了。
from cryptography.hazmat.primitives import hashes
digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
digest.update(b"交易流水号: TX2025-00123")
hash_value = digest.finalize() # 32字节
另外,SHA-256的输出长度是256比特(32字节)。如果HSM内部签名算法要求更短的哈希(比如DSA要求160位),就要用SHA-1?不,千万别用SHA-1。选SHA-256截断也不行,最好直接用兼容的椭圆曲线配合SHA-256。
数字签名:谁签的?验一下
数字签名 = 哈希 + 非对称加密 + 签名算法。流程很简单:发送方对哈希值用私钥签名,接收方用公钥验签。
金融领域常用的有RSA-PSS、ECDSA(ECDSA是ECC上的签名算法)。我个人更推荐ECDSA,因为密钥短、签名快、证书链小——金融数据传输时少几个字节都有成本优势。
下面演示ECDSA签名与验签:
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import hashes
from cryptography.exceptions import InvalidSignature
# 假设已有私钥 private_key_ecc
message = b"转账指令: A给B 1000元"
signature = private_key_ecc.sign(
message,
ec.ECDSA(hashes.SHA256())
)
# 验签
public_key = private_key_ecc.public_key()
try:
public_key.verify(signature, message, ec.ECDSA(hashes.SHA256()))
print("签名验证通过")
except InvalidSignature:
print("签名无效,数据可能被篡改")