密码学基础:Hash、对称加密、非对称加密
作者:林 | 系列:密码学 | 适合读者:后端开发 / 对密码学感兴趣的工程师
一、为什么要懂密码学
作为开发者,你可能每天都在用密码学而不自知:
- HTTPS 连接 → TLS 握手(非对称 + 对称加密)
- 用户密码存储 → BCrypt/Argon2(散列函数)
- JWT Token → HMAC-SHA256(消息认证码)
- 支付接口签名 → RSA/SM2(数字签名)
- 数据库敏感字段 → AES/SM4(对称加密)
密码学并非安全团队的专属,重点是每个后端工程师的基本功。本文用下限的篇幅把三大支柱讲清楚,后续每篇深入一个方向。
二、三大分类总览
| 能力 | 散列函数 | 对称密码 | 公钥密码 |
|---|---|---|---|
| 主要用途 | 完整性、派生、消息认证的组成部分 | 数据机密性与认证加密 | 密钥协商、签名,部分算法支持加密 |
| 是否可逆 | 不可逆 | 持有密钥可解密 | 取决于具体算法与用途 |
| 密钥 | 普通散列无密钥,HMAC 有密钥 | 双方共享密钥 | 公钥与私钥成对 |
| 常见算法 | SHA-2、SHA-3、SM3 | AES、SM4、ChaCha20 | RSA、ECC、SM2 |
核心区别一句话:
- Hash:单向压缩,不能解密,用于验证完整性
- 对称加密:一把钥匙,能加能解,用于加密数据
- 非对称加密:两把钥匙,公私配对,用于密钥交换和签名
三、散列函数(Hash)
3.1 特征
| 特征 | 说明 |
|---|---|
| 单向性 | 从哈希值无法反推出原文 |
| 固定长度 | 无论输入多长,输出长度固定 |
| 雪崩效应 | 输入改一个 bit,输出变化超过 50% |
| 抗碰撞 | 找到两个不同输入产生相同输出,计算上不可行 |
3.2 常见算法
| 算法 | 输出长度 | 状态 | 用途 |
|---|---|---|---|
| MD5 | 128 bit | ❌ 已破解 | 仅用于文件校验(非安全场景) |
| SHA-1 | 160 bit | ❌ 已破解 | 不应再使用 |
| SHA-256 | 256 bit | ✅ 安全 | 数字签名、证书、区块链 |
| SHA-3 | 可变 | ✅ 安全 | SHA-2 的备选方案 |
| SM3 | 256 bit | ✅ 安全 | 国密体系,对标 SHA-256 |
3.3 代码示例
import java.security.MessageDigest;
// SHA-256
byte[] hash = MessageDigest.getInstance("SHA-256")
.digest("hello".getBytes());
// SM3(需要 BouncyCastle)
byte[] sm3Hash = MessageDigest.getInstance("SM3")
.digest("hello".getBytes());3.4 典型应用
| 场景 | 做法 |
|---|---|
| 密码存储 | BCrypt/Argon2(带盐的慢哈希) |
| 文件完整性校验 | SHA-256 摘要比对 |
| 消息认证(HMAC) | HMAC-SHA256(key, message) |
| 数字签名 | 先 Hash 再用私钥签 Hash 值 |
| 区块链 | SHA-256 链式哈希 |
四、对称加密(Symmetric Encryption)
4.1 原理
加密和解密使用同一把密钥:
明文 + 密钥 → 加密算法 → 密文
密文 + 密钥 → 解密算法 → 明文4.2 常见算法
| 算法 | 密钥长度 | 分组长度 | 状态 |
|---|---|---|---|
| DES | 56 bit | 64 bit | ❌ 已淘汰 |
| 3DES | 168 bit | 64 bit | ⚠️ 遗留系统 |
| AES-128 | 128 bit | 128 bit | ✅ 主流 |
| AES-256 | 256 bit | 128 bit | ✅ 高安全场景 |
| SM4 | 128 bit | 128 bit | ✅ 国密,对标 AES-128 |
| ChaCha20 | 256 bit | 流密码 | ✅ 移动端/TLS |
4.3 加密模式(关键)
算法本身只处理一个分组(16 字节),多个分组怎么处理由模式决定:
| 模式 | 特点 | 是否推荐 |
|---|---|---|
| ECB | 每块独立加密,相同明文块→相同密文块 | ❌ 不安全 |
| CBC | 前一块密文参与下一块加密,需要 IV | ⚠️ 可用但有 padding oracle 风险 |
| CTR | 计数器模式,可并行 | ✅ 推荐 |
| GCM | CTR + 认证标签(AEAD) | ✅ 首选 |
// AES-GCM 加密示例
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec spec = new GCMParameterSpec(128, nonce); // 12字节 nonce
cipher.init(Cipher.ENCRYPT_MODE, secretKey, spec);
byte[] ciphertext = cipher.doFinal(plaintext);4.4 核心问题:密钥怎么给对方?
对称加密速度快,但有一个核心问题:通信双方怎么安全地共享同一把密钥?
- 线下交换?不现实
- 明文传输?等于没加密
- 解决方案 → 非对称加密(密钥交换)或预共享密钥
这就引出了非对称加密。
五、非对称加密(Asymmetric Encryption)
5.1 原理
使用一对密钥:公钥(public key)和私钥(private key)。
加密场景:
明文 + 对方公钥 → 加密 → 密文
密文 + 自己私钥 → 解密 → 明文
签名场景:
消息 + 自己私钥 → 签名 → 签名值
消息 + 对方公钥 → 验签 → 通过/不通过5.2 常见算法
| 算法 | 密钥长度 | 安全强度 | 性能 | 状态 |
|---|---|---|---|---|
| RSA-2048 | 2048 bit | 112 bit | 慢(密钥生成特别慢) | ✅ 广泛使用 |
| RSA-4096 | 4096 bit | 128 bit | 更慢 | ✅ 高安全场景 |
| ECDSA P-256 | 256 bit | 128 bit | 快 | ✅ 主流趋势 |
| Ed25519 | 256 bit | 128 bit | 很快 | ✅ 现代首选 |
| SM2 | 256 bit | 128 bit | 快 | ✅ 国密,对标 ECC |
5.3 RSA vs ECC 直观对比
在约 128 位经典安全强度下,常见比较会使用 RSA-3072 与 256 位素数域椭圆曲线。RSA 签名长度等于模数长度,ECDSA 的原始 r || s 长度由曲线参数决定,DER 编码还会变化。性能受算法方向、实现、硬件加速和提供者影响,需要在目标密码库中分别测量签名与验签,不能用一组固定毫秒数概括。
5.4 代码示例
// SM2 签名(Hutool)
SM2 sm2 = SmUtil.sm2(privateKeyHex, publicKeyHex);
byte[] sign = sm2.sign("hello".getBytes());
boolean valid = sm2.verify("hello".getBytes(), sign);
// RSA 签名
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initSign(privateKey);
sig.update("hello".getBytes());
byte[] signature = sig.sign();5.5 典型应用
| 场景 | 用法 |
|---|---|
| HTTPS/TLS | 密钥交换(ECDHE)+ 证书验证(签名) |
| 数字信封 | 非对称加密对称密钥,对称密钥加密数据 |
| 数字签名 | 接口防篡改、电子合同、代码签名 |
| SSH 登录 | 公钥认证 |
| 区块链 | 交易签名(ECDSA/Ed25519) |
六、三者的协作关系
实际系统中,三种密码学原语几乎不会单独使用,而是组合协作:
以 TLS 1.3 常见握手为例:客户端和服务端协商参数,服务端发送证书并证明持有对应私钥,双方通过 (EC)DHE 计算共享秘密,再由 HKDF 派生握手与应用流量密钥。应用数据通常由 AES-GCM 或 ChaCha20-Poly1305 这类 AEAD 套件同时提供机密性和完整性,不再额外给每条应用记录附加 HMAC。
支付接口签名流程:
1. 将请求参数按字典序拼接成字符串
2. 对字符串做 SHA-256 哈希(Hash)
3. 用私钥对 Hash 值做 SM2/RSA 签名(非对称)
4. 对方用公钥验签
5. 请求体用 AES/SM4 加密传输(对称)七、国密算法体系
中国国家密码管理局发布的商用密码算法,在政府、金融、央企项目中逐步替代国际算法:
| 国密算法 | 类型 | 对标国际算法 | 标准编号 |
|---|---|---|---|
| SM2 | 非对称(椭圆曲线) | ECDSA/ECIES | GM/T 0003 |
| SM3 | 散列函数 | SHA-256 | GM/T 0004 |
| SM4 | 对称加密(分组密码) | AES-128 | GM/T 0002 |
| SM9 | 标识密码 | IBE | GM/T 0044 |
| ZUC | 流密码 | — | 3GPP 标准 |
- 政府/央企/军工项目:强制要求
- 金融行业:逐步推进,2025 年后新系统基本强制
- 等保三级以上系统:建议使用
- 普通互联网项目:不强制,AES/RSA 仍然是主流选择
八、选型速查表
| 我要做什么 | 推荐方案 | 国密方案 |
|---|---|---|
| 存储用户密码 | BCrypt / Argon2 | — |
| 校验文件完整性 | SHA-256 | SM3 |
| 接口签名验签 | ECDSA / Ed25519 | SM2 |
| 加密数据库字段 | AES-256-GCM | SM4-GCM |
| 加密传输数据 | TLS 1.3 (ECDHE + AES-GCM) | TLCP (SM2 + SM4) |
| 密钥交换 | ECDH / X25519 | SM2 密钥交换 |
| 数字信封 | RSA/ECDH + AES | SM2 + SM4 |
| JWT 签名 | HMAC-SHA256 / ES256 | SM2 签名 |
九、常见误区
误区 1:加密 = 安全
加密只是安全的一环。密钥管理、传输安全、访问控制同样重要。密钥硬编码在代码里,加密等于白做。
误区 2:Hash 可以解密
Hash 是单向函数,不存在"解密"。所谓的"MD5 解密网站"是彩虹表反查,不是解密。
误区 3:RSA 比 AES 更安全
RSA 和 AES 解决的是不同问题。RSA 解决密钥分发,AES 解决数据加密。两者配合使用,不是二选一。
误区 4:密钥越长越好
AES-128 在可预见的未来都足够安全(暴力破解需要 2^128 次运算)。盲目加长密钥只会降低性能,没有实际安全收益。
误区 5:自己实现加密算法
永远不要自己发明加密算法或自己实现已有算法。使用成熟的库(BouncyCastle、OpenSSL、libsodium),它们经过了大量审计和攻击测试。
十、系列导航
本系列共 7 篇,由浅入深:
- 密码学基础:Hash、对称加密、非对称加密(本文)
- 散列函数:MD5、SHA、SM3 与 HMAC
- 对称加密:AES 与 SM4 模式选择指南
- 非对称加密与签名:RSA、ECC、SM2
- 数字信封与密钥协商:SM2+SM4、ECDH、TLS
- 可搜索加密:加密数据的模糊检索方案
- 格式保留加密、同态加密与零知识证明