加密算法指南
常用加密算法介绍、使用场景和代码示例
算法对比总结
对称加密
什么是 AES?
AES(Advanced Encryption Standard)是目前最流行的对称加密算法,使用相同的密钥进行加密和解密。
特点
- 加密解密速度快
- 密钥长度:128/192/256 位
- 适合大数据量加密
- 需要安全传输密钥
使用场景
- 文件加密
- 数据库字段加密
- HTTPS 会话加密
- 敏感数据传输
Java 示例(Hutool)
// AES 加密
String content = "需要加密的内容";
String key = "1234567890123456"; // 16位密钥
// 加密
String encrypt = SecureUtil.aes(key.getBytes()).encryptBase64(content);
// 解密
String decrypt = SecureUtil.aes(key.getBytes()).decryptStr(encrypt);
其他对称加密算法
| 算法 | 密钥长度 | 安全性 | 说明 |
|---|---|---|---|
| DES | 56位 | 低 | 已淘汰,不建议使用 |
| 3DES | 168位 | 中 | DES 的改进版,速度较慢 |
| SM4 | 128位 | 高 | 国密算法,国内推荐使用 |
| ChaCha20 | 256位 | 高 | 新兴算法,移动端性能更好 |
非对称加密
什么是 RSA?
RSA 是最经典的非对称加密算法,使用公钥加密、私钥解密,解决了密钥传输的安全问题。
特点
- 公钥公开,私钥保密
- 密钥长度:1024/2048/4096 位
- 加密速度慢(比 AES 慢 100 倍)
- 适合小数据量加密
使用场景
- 密钥交换(交换 AES 密钥)
- 数字签名
- 身份认证
- 证书体系(SSL/TLS)
Java 示例(Hutool)
// 生成 RSA 密钥对
RSA rsa = SecureUtil.rsa();
String privateKey = rsa.getPrivateKeyBase64();
String publicKey = rsa.getPublicKeyBase64();
// 公钥加密
String encrypt = rsa.encryptBase64(content, CharsetUtil.CHARSET_UTF_8, KeyType.PublicKey);
// 私钥解密
String decrypt = rsa.decryptStr(encrypt, KeyType.PrivateKey);
国密 SM2
SM2 是国家密码管理局发布的椭圆曲线公钥密码算法,对标 RSA/ECDSA。
优势
- 密钥更短(256位 = RSA 3072位安全性)
- 速度更快
- 国密合规要求
Java 示例
// SM2 加密
SM2 sm2 = SmUtil.sm2();
String encrypt = sm2.encryptBcd(content, KeyType.PublicKey);
String decrypt = sm2.decryptStr(encrypt, KeyType.PrivateKey);
哈希算法(摘要)
什么是哈希?
哈希算法将任意长度数据转换为固定长度的摘要,具有不可逆特性,常用于数据完整性校验。
重要:哈希不是加密!哈希是单向的,无法从摘要还原原始数据。
| 算法 | 输出长度 | 安全性 | 用途 |
|---|---|---|---|
| MD5 | 128位 | 已破解 | 文件校验(不用于安全) |
| SHA-1 | 160位 | 不推荐 | 逐渐淘汰中 |
| SHA-256 | 256位 | 安全 | 目前最常用 |
| SHA-512 | 512位 | 更安全 | 高安全场景 |
| SM3 | 256位 | 安全 | 国密哈希算法 |
Java 示例(Hutool)
// SHA-256 哈希
String hash = SecureUtil.sha256(content);
// MD5(不推荐用于安全场景)
String md5 = SecureUtil.md5(content);
// SM3 国密哈希
String sm3 = SmUtil.sm3(content);
HMAC(带密钥的哈希)
HMAC 在哈希基础上增加了密钥,可以验证数据来源和完整性。
Java 示例
// HMAC-SHA256
String key = "secretKey";
String hmac = SecureUtil.hmac(HmacAlgorithm.HmacSHA256, key).digestBase64(content);
密码存储
为什么不能直接存密码?
绝对不要:明文存储密码、简单 MD5/SHA256 存储密码!
密码哈希 vs 普通哈希
| 特性 | 普通哈希(SHA-256/SM3) | 密码哈希(BCrypt/Argon2) |
|---|---|---|
| 设计目标 | 快速计算,验证数据完整性 | 故意慢速,防止暴力破解 |
| 计算速度 | 每秒数百万次 ⚡ | 每秒几百次 🐢 |
| 盐值 | 无(相同输入相同输出) | 自动随机盐值 |
| 适用场景 | 文件校验、数字签名 | 用户密码存储 |
| 安全性 | 易被彩虹表/暴力破解 | 抗彩虹表、抗 GPU 加速 |
简单理解:普通哈希追求"快"(效率),密码哈希追求"慢"(安全)。用 SHA-256 存密码,黑客每秒能试几十亿个密码;用 BCrypt,每秒只能试几百个。
正确做法:慢哈希 + 盐值
密码哈希需要慢(防暴力破解)+随机盐值(防彩虹表)。
| 算法 | 特点 | 推荐度 |
|---|---|---|
| BCrypt | 自适应成本,内置盐值,最流行 | ⭐⭐⭐ 首选 |
| SCrypt | 内存困难型,抗 GPU/ASIC | ⭐⭐⭐ 推荐 |
| Argon2 | 2015 密码哈希大赛冠军 | ⭐⭐⭐ 最新标准 |
| PBKDF2 | NIST 推荐,老牌标准 | ⭐⭐ 可用 |
Java 示例(BCrypt)
// 注册:生成密码哈希
String password = "userPassword";
String salt = BCrypt.gensalt(12); // cost = 12,约 300ms
String hashed = BCrypt.hashpw(password, salt);
// 存储 hashed 到数据库
// 登录:验证密码
boolean match = BCrypt.checkpw(inputPassword, storedHash);
Java 示例(双重哈希,更安全)
// 先 SHA-256 预处理,再 BCrypt
String sha256Pwd = DigestUtil.sha256Hex(password);
String salt = BCrypt.gensalt(10);
String passwordNew = BCrypt.hashpw(sha256Pwd, salt);
BCrypt 在线生成/验证
生成哈希
数值越大越慢越安全
验证密码
Argon2 在线生成/验证
生成哈希
内存困难型算法,抗 GPU/ASIC
验证密码
密码存储最佳实践
✅ 应该做的
- 使用 BCrypt/Argon2/SCrypt
- 每个密码独立盐值
- 定期升级 cost 参数
- 限制登录失败次数
- 使用 HTTPS 传输
❌ 不应该做的
- 明文存储密码
- 简单 MD5/SHA1
- 固定盐值
- 可逆加密(AES 等)
- 限制密码长度(如 16 位)
算法选择指南
国密算法(SM系列)
国密算法是中国国家密码管理局发布的密码算法标准,在国内金融、政务等领域有合规要求。
SM2 - 非对称加密/签名
基于椭圆曲线密码学(ECC)的公钥算法,对标 RSA/ECDSA,但性能更优。
优势
- 密钥更短:256位 SM2 ≈ 3072位 RSA 安全性
- 速度更快:加密/签名速度优于 RSA
- 存储更小:证书、签名数据更紧凑
- 国密合规:满足国内安全审查要求
Java 示例(Hutool)
// 生成 SM2 密钥对
SM2 sm2 = SmUtil.sm2();
String privateKey = sm2.getPrivateKeyBase64();
String publicKey = sm2.getPublicKeyBase64();
// SM2 加密
String encrypt = sm2.encryptBcd(content, KeyType.PublicKey);
// SM2 解密
String decrypt = sm2.decryptStr(encrypt, KeyType.PrivateKey);
// SM2 签名
String sign = sm2.signHex(content);
// SM2 验签
boolean verify = sm2.verifyHex(content, sign);
SM3 - 哈希算法
国密哈希算法,输出 256 位摘要,对标 SHA-256。
- 输出长度:256 位(32 字节)
- 安全性:与 SHA-256 相当
- 用途:数据完整性校验、数字签名
Java 示例
// SM3 哈希
String hash = SmUtil.sm3(content);
// SM3 HMAC
String hmac = SmUtil.sm3Hmac(key, content);
SM4 - 对称加密
国密对称加密算法,对标 AES,分组长度和密钥长度均为 128 位。
- 分组长度:128 位
- 密钥长度:128 位
- 工作模式:ECB、CBC、CTR、GCM 等
- 性能:与 AES 相当
Java 示例
// SM4 加密
String key = "1234567890123456"; // 16字节密钥
String iv = "1234567890123456"; // 16字节IV
// CBC 模式
SM4 sm4 = new SM4(Mode.CBC, Padding.PKCS5Padding,
key.getBytes(), iv.getBytes());
String encrypt = sm4.encryptBase64(content);
// 解密
String decrypt = sm4.decryptStr(encrypt);
SM9 - 标识加密
基于身份的密码算法(IBC),无需数字证书,直接使用用户标识(如邮箱)作为公钥。
适用场景:大规模用户系统、物联网设备、邮件加密等,省去证书管理开销。
编码方案(不是加密)
重要:编码不是加密!编码是可逆的、无密钥的,任何人都可以解码。
常用编码方案对比
| 编码 | 特点 | 用途 | 示例 |
|---|---|---|---|
| Base64 | 二进制转文本,体积增加 33% | 图片/文件传输、URL 参数 | SGVsbG8= |
| Base58 | 无 0/O/I/l 混淆,适合人工输入 | Bitcoin 地址 | 3J98t1WpEZ73CNm |
| Base32 | 全大写,适合二维码 | Google Authenticator | JBSWY3DPEHPK3PXP |
| Hex | 十六进制,体积增加 100% | 密钥显示、哈希值 | 48656c6c6f |
| URL Encode | 特殊字符转义 | URL 参数、表单提交 | Hello%20World |
Java 示例(Hutool)
// Base64
String base64 = Base64.encode(content);
String decoded = Base64.decodeStr(base64);
// Base58(Bitcoin)
String base58 = Base58.encode(bytes);
// Hex
String hex = HexUtil.encodeHexStr(content);
byte[] bytes = HexUtil.decodeHex(hex);
// URL Encode
String urlEncoded = URLUtil.encode(content);
String urlDecoded = URLUtil.decode(urlEncoded);