密码学基础回顾:对称加密、非对称加密、哈希函数、数字签名

做安全架构,密码学是绕不开的基石。我见过不少团队在密钥边界划分上出问题,追根溯源,往往是对这四种基本原语理解不够透。今天咱们就把对称加密、非对称加密、哈希函数、数字签名这四兄弟理清楚。

别小看这些基础。我记得有一次评审一个支付系统,他们用同一个对称密钥做全链路加密,连签名都省了。结果泄露一个点,整个系统裸奔。为什么?边界没划清,本质上是没搞清楚每种原语该管什么事。

密码学基础四原语关系 密码学原语 对称加密 非对称加密 哈希函数 数字签名 快,批量加密 密钥分发困难 慢,安全密钥交换 公钥公开,私钥保密 不可逆,固定长度 完整性校验 防抵赖 + 完整性 私钥签名,公钥验签

对称加密:密钥就是命根子

对称加密,说白了就是加密和解密用同一个密钥。你想想看,两个人通信,得先商量好一把“钥匙”。速度快是它最大的优点,AES-256在硬件加速下搞Gbps级吞吐没问题。

但密钥分发是个大坑。我在一个物联网项目里遇到过,设备出厂时预置了对称密钥,结果固件被逆向,所有设备密钥泄漏——厂家连夜召回。为什么?密钥存在设备本地,没有硬件安全隔离。

核心原则:对称加密只解决“机密性”,不解决身份认证和完整性。密钥一旦泄漏,所有密文等于明文。

常用的有 AES(高级加密标准)、SM4(国密)。工作模式也得注意,ECB 模式有模式重复问题,我建议默认用 GCM 或 CTR 模式。

# Python 示例:AES-GCM 加密/解密
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes

key = get_random_bytes(32)  # 256位密钥
nonce = get_random_bytes(12)  # 96位随机数
cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
ciphertext, tag = cipher.encrypt_and_digest(b"敏感数据")
# decrypt
cipher2 = AES.new(key, AES.MODE_GCM, nonce=nonce)
plain = cipher2.decrypt_and_verify(ciphertext, tag)

我曾经排查过一个线上故障:系统重启后随机数种子被重置,导致每次生成的 nonce 相同,GCM 模式被攻破。记住,nonce 不允许重复使用。

非对称加密:公私钥的哲学

非对称加密解决了密钥分发难题。公钥随便给人,私钥自己藏着。常见的 RSA、ECC(椭圆曲线)以及国密 SM2。RSA 现在推荐至少 3072 位,ECC 用 256 位就能达到同等强度。

速度慢是它的硬伤。你想想看,用 RSA 加密 1KB 数据就要几毫秒,而 AES 加密 1MB 数据也就几微秒。所以实际项目中,我们通常用非对称加密来保护“会话密钥”——也就是混合加密方案。

我个人习惯:TLS 握手时用 ECDHE 交换临时密钥,再用对称加密传输业务数据。这样既安全又高效。

密钥边界划分时,非对称密钥的私钥必须放在 HSM(硬件安全模块)或 TEE(可信执行环境)里,不能出现在应用日志或数据库里。我曾经审计过一个项目,私钥居然写在配置文件的注释里——真事。

对比项 对称加密 非对称加密
密钥数量 一个密钥 一对密钥(公/私)
速度 快(硬件加速后可到 Gbps) 慢(RSA 4096 签名约 1ms)
典型算法 AES, SM4, ChaCha20 RSA, ECDSA, SM2
主要用途 大量数据加密 密钥交换、数字签名

哈希函数:数据的指纹

哈希函数把任意长度的数据映射成固定长度的摘要,而且不可逆。你想想看,就算只改了一个 bit,摘要都会面目全非。这就是“雪崩效应”。

常见的哈希算法有 SHA-256、SHA-3,国密用 SM3。MD5 和 SHA-1 已经不安全了,千万别用。我去年还碰到一个老旧系统用 MD5 存密码哈希——直接判了安全漏洞。

注意:哈希不提供机密性,只提供完整性校验。比如下载文件,网站给一个 SHA-256 值,你本地算了比对,就知道文件有没有被篡改。

但哈希有致命弱点:彩虹表攻击和碰撞攻击。所以存储密码时,不能只用哈希,一定要加盐(salt)和拉伸(例如 bcrypt、Argon2)。

# 安全密码哈希(Python 示例)
import hashlib, os

salt = os.urandom(16)
password = b"my_secret_pass"
hash_obj = hashlib.pbkdf2_hmac('sha256', password, salt, 100000)
print(hash_obj.hex())

我曾经帮一个客户做过渗透测试,他们用 SHA-256 直接哈希用户密码,连盐都没加。结果数据库泄露后,超过一半的密码被彩虹表秒破。加盐不是选项,是强制要求。

数字签名:防抵赖的终极武器

数字签名 = 哈希 + 非对称加密。签名方先用哈希对消息生成摘要,再用自己的私钥对摘要加密(签名)。验签方用公钥解密摘要,再和自己算的哈希比对。

为什么需要哈希?因为非对称加密太慢,签名大文件不现实。先哈希,再签名,相当于给文件盖一个“电子公章”。

常见的签名算法有 RSA-PSS、ECDSA、Ed25519。Ed25519 效率高且实现安全,我最近几年用的越来越多。

我建议:在安全架构中,签名和加密的密钥一定要分开。用同一把私钥既做签名又做解密,会破坏不可否认性——签名方可以说“这是解密操作,不是我的签名”。

数字签名通常是 CA 体系的核心,证书的本质就是 CA 对你公钥的签名。密钥边界划分时,签名私钥所在的系统必须严格隔离,通常放在离线签名机里,只在可信环境接触网络。

# Ed25519 签名与验证(Python + ed25519)
import ed25519

sk, vk = ed25519.create_keypair()
message = b"重要合约内容"
signature = sk.sign(message)
try:
    vk.verify(signature, message)
    print("签名验证通过")
except ed25519.BadSignatureError:
    print("签名无效")

关键理解:数字签名提供的“不可否认性”依赖于私钥的保密。如果私钥落入他人之手,签名就不再可信。密钥边界划分的核心,就是围绕私钥的生命周期做隔离。

好了,这四种原语我们回顾完了。总结一下:对称加密管机密性,哈希管完整性,非对称加密配合哈希做数字签名管身份认证和不可否认性。实际系统往往是混合使用,比如 TLS 就把它们全用上了。搞清楚了各自边界,密钥管理系统才不会设计成一锅粥。