在当今信息安全至关重要的时代,数据加密已成为每个Java开发者必须掌握的技能。AES(Advanced Encryption Standard)作为最流行的对称加密算法之一,被广泛应用于各种安全场景。本文将带你全面了解Java中AES的实现,从基础概念到高级应用,助你构建更安全的系统。
一、AES加密基础概念
AES(高级加密标准)是一种对称加密算法,由美国国家标准与技术研究院(NIST)于2001年确立。它取代了原先的DES算法,成为新一代加密标准。AES的主要特点包括:
- 对称加密:加密和解密使用相同的密钥
- 分组加密:将明文分成固定长度的块进行处理
- 三种密钥长度:支持128位、192位和256位密钥
- 高安全性:目前尚未有已知的有效攻击方法
二、Java中的AES实现核心类
Java通过JCE(Java Cryptography Extension)提供加密支持,主要涉及以下核心类:
javax.crypto.Cipher
:加密操作的核心类javax.crypto.KeyGenerator
:密钥生成器javax.crypto.SecretKey
:对称密钥接口javax.crypto.spec.IvParameterSpec
:初始化向量(IV)规范
三、AES加密模式与填充方式
3.1 加密模式
Java支持多种AES加密模式,常见的有:
- ECB(Electronic Codebook):最简单的模式,安全性较低
- CBC(Cipher Block Chaining):常用模式,需要IV
- GCM(Galois/Counter Mode):提供认证加密,推荐使用
3.2 填充方式
当数据长度不是块大小的整数倍时,需要填充。常用填充方式:
- PKCS5Padding/PKCS7Padding
- NoPadding(不推荐)
四、Java AES加密实战代码
4.1 基础AES加密实现
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;
public class AESUtil {
// 生成AES密钥
public static SecretKey generateKey(int keySize) throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(keySize);
return keyGenerator.generateKey();
}
// AES加密(CBC模式)
public static String encrypt(String plainText, SecretKey key) throws Exception {
byte[] iv = new byte[16]; // 初始化向量
new SecureRandom().nextBytes(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec);
byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
byte[] combined = new byte[iv.length + encrypted.length];
System.arraycopy(iv, 0, combined, 0, iv.length);
System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length);
return Base64.getEncoder().encodeToString(combined);
}
// AES解密(CBC模式)
public static String decrypt(String encryptedText, SecretKey key) throws Exception {
byte[] combined = Base64.getDecoder().decode(encryptedText);
byte[] iv = new byte[16];
System.arraycopy(combined, 0, iv, 0, iv.length);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
byte[] encrypted = new byte[combined.length - iv.length];
System.arraycopy(combined, iv.length, encrypted, 0, encrypted.length);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, ivParameterSpec);
byte[] decrypted = cipher.doFinal(encrypted);
return new String(decrypted, StandardCharsets.UTF_8);
}
}
4.2 更安全的GCM模式实现
// AES-GCM加密实现
public static String encryptGCM(String plainText, SecretKey key) throws Exception {
byte[] iv = new byte[12]; // GCM推荐12字节IV
new SecureRandom().nextBytes(iv);
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv); // 128位认证标签
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key, parameterSpec);
byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
byte[] combined = new byte[iv.length + encrypted.length];
System.arraycopy(iv, 0, combined, 0, iv.length);
System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length);
return Base64.getEncoder().encodeToString(combined);
}
// AES-GCM解密实现
public static String decryptGCM(String encryptedText, SecretKey key) throws Exception {
byte[] combined = Base64.getDecoder().decode(encryptedText);
byte[] iv = new byte[12];
System.arraycopy(combined, 0, iv, 0, iv.length);
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, key, parameterSpec);
byte[] encrypted = new byte[combined.length - iv.length];
System.arraycopy(combined, iv.length, encrypted, 0, encrypted.length);
byte[] decrypted = cipher.doFinal(encrypted);
return new String(decrypted, StandardCharsets.UTF_8);
}
五、AES最佳实践与常见问题
5.1 密钥管理
- 不要硬编码密钥在代码中
- 使用密钥管理系统(KMS)
- 定期轮换密钥
5.2 性能优化
- 重用Cipher实例(线程安全)
- 对于大文件,考虑分块加密
- 选择适当的密钥长度(128位通常足够)
5.3 常见问题
InvalidKeyException
:检查密钥长度和JCE策略文件BadPaddingException
:通常由密钥不匹配或数据损坏引起AEADBadTagException
(GCM模式):认证失败
六、Java AES与其他技术的整合
6.1 Spring Boot中的AES加密
@Configuration
public class CryptoConfig {
@Value("${aes.secret.key}")
private String base64Key;
@Bean
public SecretKey aesSecretKey() throws Exception {
byte[] decodedKey = Base64.getDecoder().decode(base64Key);
return new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
}
@Bean
public Cipher aesCipher() throws Exception {
return Cipher.getInstance("AES/GCM/NoPadding");
}
}
@Service
public class CryptoService {
@Autowired
private SecretKey secretKey;
@Autowired
private Cipher cipher;
public String encrypt(String data) throws Exception {
byte[] iv = new byte[12];
new SecureRandom().nextBytes(iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new GCMParameterSpec(128, iv));
byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
byte[] combined = new byte[iv.length + encrypted.length];
System.arraycopy(iv, 0, combined, 0, iv.length);
System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length);
return Base64.getEncoder().encodeToString(combined);
}
// 解密方法类似
}
6.2 Android中的AES实现
Android提供了AndroidKeyStore
来安全存储密钥:
// 生成存储在AndroidKeyStore中的AES密钥
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(
"my_key_alias",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setKeySize(256)
.build();
keyGenerator.init(keyGenParameterSpec);
SecretKey secretKey = keyGenerator.generateKey();
七、AES安全性进阶讨论
- 侧信道攻击防护:确保实现不受时序攻击影响
- 密钥派生:使用PBKDF2或Scrypt从密码派生密钥
- 认证加密:优先选择GCM等提供认证的加密模式
版权声明
本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。