Java 加密基础
cryptography;JCA/JCE 直觉。
30 分钟
Java 加密基础
日志里不能打密码,数据库里不应存明文。JCA/JCE(Java Cryptography Architecture / Extension)提供哈希、对称加密、非对称加密与签名 API——本课建立安全直觉,供 spring-boot-essentials 的 Spring Security 与 HTTPS 配置理解底层,并遵循 java-core-essentials 的「不可变、显式异常」风格。
学习目标
- 用
MessageDigest做 SHA-256 哈希,理解盐(salt)的作用 - 用
Cipher做 AES-GCM 加解密,选对模式与 IV - 区分「哈希存密码」与「加密可还原字段」的适用场景
密码哈希(不可逆)
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Base64;
public final class PasswordHasher {
private static final SecureRandom RNG = new SecureRandom();
public static String hash(char[] password) throws Exception {
byte[] salt = new byte[16];
RNG.nextBytes(salt);
byte[] hash = sha256(concat(salt, new String(password).getBytes()));
return Base64.getEncoder().encodeToString(salt)
+ "$" + Base64.getEncoder().encodeToString(hash);
}
private static byte[] sha256(byte[] input) throws Exception {
return MessageDigest.getInstance("SHA-256").digest(input);
}
}
生产环境请用 BCrypt / Argon2(Spring Security 的 PasswordEncoder),上述代码仅说明 JCA 用法。SHA-256 单次哈希对密码仍不够慢,易被彩虹表攻击。
AES-GCM 对称加密(可还原)
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public final class AesGcm {
private static final int TAG_BITS = 128;
public static byte[] encrypt(byte[] key, byte[] plain) throws Exception {
byte[] iv = new byte[12];
new SecureRandom().nextBytes(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"),
new GCMParameterSpec(TAG_BITS, iv));
byte[] cipherText = cipher.doFinal(plain);
return concat(iv, cipherText); // 存储时 IV 与密文一起
}
}
禁止 AES-ECB;GCM 同时提供机密性与完整性。密钥长度 128/256 位,从 KMS 或环境变量读取,不要硬编码进 Git。
场景选型
| 需求 | 方案 | Java API / 库 |
|---|---|---|
| 存用户密码 | 慢哈希 + 盐 | BCryptPasswordEncoder |