本文目录导读:

在Java中实现对称加密通常使用javax.crypto包下的类,以下是几种常见对称加密算法的实现方法。
AES加密实现(推荐使用)
AES是目前最常用的对称加密算法,安全性高、性能好。
基础AES加密
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;
public class AESEncryption {
// AES加密,使用ECB模式(不推荐生产使用)
public static String encryptECB(String plainText, String secretKey) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "AES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encrypted);
}
// AES解密,使用ECB模式
public static String decryptECB(String encryptedText, String secretKey) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "AES");
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
return new String(decrypted, StandardCharsets.UTF_8);
}
// 推荐:AES加密,使用CBC模式(更安全)
public static String encryptCBC(String plainText, String secretKey, String iv) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encrypted);
}
// 推荐:AES解密,使用CBC模式
public static String decryptCBC(String encryptedText, String secretKey, String iv) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
return new String(decrypted, StandardCharsets.UTF_8);
}
public static void main(String[] args) {
try {
// 使用固定密钥(16字节即128位)
String key = "1234567890123456"; // 必须是16、24或32位
String iv = "1234567890123456"; // IV必须16位
String originalText = "Hello, World! 这是敏感数据";
// ECB模式(简单但不安全,不适合块数据)
String encryptedECB = encryptECB(originalText, key);
String decryptedECB = decryptECB(encryptedECB, key);
System.out.println("ECB模式:");
System.out.println("原文: " + originalText);
System.out.println("密文: " + encryptedECB);
System.out.println("解密: " + decryptedECB);
// CBC模式(推荐)
String encryptedCBC = encryptCBC(originalText, key, iv);
String decryptedCBC = decryptCBC(encryptedCBC, key, iv);
System.out.println("\nCBC模式:");
System.out.println("原文: " + originalText);
System.out.println("密文: " + encryptedCBC);
System.out.println("解密: " + decryptedCBC);
} catch (Exception e) {
e.printStackTrace();
}
}
}
自动生成密钥和IV(推荐生产使用)
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.util.Base64;
public class AESGCMEncryption {
private static final int AES_KEY_SIZE = 256; // 密钥位数
private static final int GCM_NONCE_LENGTH = 12; // IV长度(推荐12字节)
private static final int GCM_TAG_LENGTH = 128; // 认证标签长度
// 生成随机密钥
public static SecretKey generateKey() throws Exception {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(AES_KEY_SIZE);
return keyGen.generateKey();
}
// AES-GCM加密(最安全的方式)
public static String encrypt(String plainText, SecretKey key) throws Exception {
byte[] nonce = new byte[GCM_NONCE_LENGTH];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(nonce);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, nonce);
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
byte[] cipherText = cipher.doFinal(plainText.getBytes());
// 将nonce和密文拼接
byte[] combined = new byte[nonce.length + cipherText.length];
System.arraycopy(nonce, 0, combined, 0, nonce.length);
System.arraycopy(cipherText, 0, combined, nonce.length, cipherText.length);
return Base64.getEncoder().encodeToString(combined);
}
// AES-GCM解密
public static String decrypt(String encryptedData, SecretKey key) throws Exception {
byte[] combined = Base64.getDecoder().decode(encryptedData);
byte[] nonce = new byte[GCM_NONCE_LENGTH];
System.arraycopy(combined, 0, nonce, 0, nonce.length);
byte[] cipherText = new byte[combined.length - nonce.length];
System.arraycopy(combined, nonce.length, cipherText, 0, cipherText.length);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, nonce);
cipher.init(Cipher.DECRYPT_MODE, key, spec);
byte[] plainText = cipher.doFinal(cipherText);
return new String(plainText);
}
public static void main(String[] args) {
try {
// 生成密钥
SecretKey key = generateKey();
String keyStr = Base64.getEncoder().encodeToString(key.getEncoded());
System.out.println("密钥(Base64): " + keyStr);
String originalText = "Hello, World! 这是使用AES-GCM加密的敏感数据";
// 加密
String encrypted = encrypt(originalText, key);
System.out.println("原文: " + originalText);
System.out.println("密文: " + encrypted);
// 解密
String decrypted = decrypt(encrypted, key);
System.out.println("解密: " + decrypted);
} catch (Exception e) {
e.printStackTrace();
}
}
}
3DES加密(遗留系统兼容)
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.util.Base64;
public class TripleDESEncryption {
public static String encrypt(String plainText, String secretKey) throws Exception {
byte[] keyBytes = secretKey.getBytes();
DESedeKeySpec spec = new DESedeKeySpec(keyBytes);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
javax.crypto.SecretKey key = keyFactory.generateSecret(spec);
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
IvParameterSpec ivSpec = new IvParameterSpec(new byte[8]); // 8字节IV
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
byte[] encrypted = cipher.doFinal(plainText.getBytes());
return Base64.getEncoder().encodeToString(encrypted);
}
public static String decrypt(String encryptedText, String secretKey) throws Exception {
byte[] keyBytes = secretKey.getBytes();
DESedeKeySpec spec = new DESedeKeySpec(keyBytes);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
javax.crypto.SecretKey key = keyFactory.generateSecret(spec);
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
IvParameterSpec ivSpec = new IvParameterSpec(new byte[8]);
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
return new String(decrypted);
}
}
使用工具类封装
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;
public class CryptoUtils {
// 从密码生成固定长度的密钥
public static SecretKeySpec generateKey(String password) throws Exception {
MessageDigest sha = MessageDigest.getInstance("SHA-256");
byte[] key = sha.digest(password.getBytes(StandardCharsets.UTF_8));
return new SecretKeySpec(key, "AES");
}
// 简单的AES加密封装
public static String encrypt(String plainText, String password) {
try {
SecretKeySpec keySpec = generateKey(password);
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] encrypted = cipher.doFinal(plainText.getBytes());
return Base64.getEncoder().encodeToString(encrypted);
} catch (Exception e) {
throw new RuntimeException("加密失败", e);
}
}
// 简单的AES解密封装
public static String decrypt(String encryptedText, String password) {
try {
SecretKeySpec keySpec = generateKey(password);
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
return new String(decrypted);
} catch (Exception e) {
throw new RuntimeException("解密失败", e);
}
}
public static void main(String[] args) {
String password = "mySecretPassword123!";
String data = "Hello, World!";
String encrypted = encrypt(data, password);
String decrypted = decrypt(encrypted, password);
System.out.println("原文: " + data);
System.out.println("密文: " + encrypted);
System.out.println("解密: " + decrypted);
}
}
最佳实践建议
// 推荐的生产环境配置
public class EncryptionConfig {
// 常量配置
public static final String ALGORITHM = "AES/GCM/NoPadding"; // 使用GCM模式
public static final int KEY_SIZE = 256; // 256位密钥
public static final int IV_SIZE = 12; // 12字节IV
public static final int TAG_SIZE = 128; // 128位认证标签
// 密钥管理(生产环境应使用密钥管理服务)
// 1. 不要硬编码密钥
// 2. 使用密钥存储服务(KMS)
// 3. 定期轮换密钥
// 4. 密钥要有过期时间
}
注意事项
-
密钥管理:
- 不要硬编码密钥在代码中
- 使用密钥管理服务(如AWS KMS、Azure Key Vault)
- 密钥定期轮换
-
模式选择:
- ECB模式:不适合加密块数据,相同明文生成相同密文
- CBC模式:需要IV,每个块依赖于前一个块
- GCM模式:推荐,提供认证和加密
-
IV管理:
- IV必须是随机且唯一的
- IV不需要加密,但最好与密文一起存储
- 同一个密钥下,IV不能重复使用
-
编码处理:
- 密文通常使用Base64编码传输
- 注意字符编码统一使用UTF-8
-
异常处理:
- 密码学操作应使用try-catch处理异常
- 解密失败时不要泄露具体原因(防止padding oracle攻击)
推荐使用AES-GCM模式进行生产环境的对称加密,它提供了加密和认证双重保障。