1. 为什么需要AES加密在日常开发中我们经常需要处理敏感数据的存储和传输问题。比如用户的密码、身份证号、银行卡信息等如果直接以明文形式存储或传输一旦被黑客截获就会造成严重的安全问题。这时候就需要使用加密技术来保护这些数据。你可能听说过MD5这种哈希算法但它只能做单向加密无法解密。而很多业务场景下我们需要能够还原原始数据比如加密存储的用户手机号在需要显示时还得能解密出来。这时候对称加密就派上用场了。对称加密最大的特点就是加密和解密使用同一个密钥就像我们日常生活中用的钥匙和锁的关系。只有用同一把钥匙才能锁上和打开同一把锁。AESAdvanced Encryption Standard就是目前最主流的对称加密算法它已经取代了早期的DES和3DES算法成为事实上的行业标准。2. AES加密的核心概念2.1 分组密码体制AES采用分组密码的工作方式它会先把明文数据切分成固定大小的块block每个块128位16字节。如果最后一块不足16字节就需要进行填充Padding。然后对每个块分别进行加密最后把所有加密后的块拼接起来形成最终的密文。这种分组处理的方式有几个关键优势可以并行处理多个数据块提高加密效率固定大小的块便于硬件优化实现安全性更高单个块的破解不会影响其他块2.2 填充模式Padding由于明文数据长度不一定是16字节的整数倍所以需要对最后一个块进行填充。AES支持几种常见的填充模式PKCS5/PKCS7缺少几个字节就填充几个字节的填充值。比如缺5个字节就填充5个0x05NoPadding不填充要求明文长度必须是16字节的倍数实际开发中最常用的是PKCS7填充模式。这里有个细节需要注意如果最后一个块正好是16字节且内容全是0x1016解密时就无法区分这是有效数据还是填充数据。因此PKCS7在这种情况下会自动再追加一个完整的填充块。2.3 加密模式AES支持多种加密模式不同的模式安全性差异很大ECB模式电子密码本最简单的模式相同的明文块会加密成相同的密文块安全性较差CBC模式密码块链接引入初始化向量IV使相同明文加密出不同密文安全性高GCM模式除了加密还提供认证功能性能优异ECB模式因为安全性问题基本不再使用CBC是最常用的模式而GCM适合对性能要求高的场景。2.4 密钥和初始化向量密钥AES支持128位、192位和256位三种密钥长度。密钥越长安全性越高但加密速度会变慢。一般128位就足够安全了。初始化向量IVCBC模式需要的一个随机数长度也是128位。它的作用是让相同的明文每次加密出不同的密文提高安全性。3. Java实现AES加密解密3.1 解决Invalid key size问题在Java中使用AES-256时可能会遇到Illegal key size错误。这是因为Java默认的加密策略文件限制了密钥长度。解决方法是从Oracle官网下载对应的JCE策略文件根据JDK版本下载对应的策略文件包解压后得到local_policy.jar和US_export_policy.jar替换JDK和JRE的security目录下的这两个文件3.2 完整工具类实现下面是一个完整的AES工具类实现支持CBC模式和PKCS7填充import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.security.Security; import java.util.Base64; public class AESUtil { static { Security.addProvider(new BouncyCastleProvider()); } /** * AES加密 * param data 明文 * param key 密钥16/24/32字节 * param iv 初始化向量16字节 * return 密文Base64编码 */ public static String encrypt(String data, String key, String iv) throws Exception { byte[] raw key.getBytes(UTF-8); SecretKeySpec keySpec new SecretKeySpec(raw, AES); Cipher cipher Cipher.getInstance(AES/CBC/PKCS7Padding, BC); IvParameterSpec ivSpec new IvParameterSpec(iv.getBytes(UTF-8)); cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); byte[] encrypted cipher.doFinal(data.getBytes(UTF-8)); return Base64.getEncoder().encodeToString(encrypted); } /** * AES解密 * param data 密文Base64编码 * param key 密钥16/24/32字节 * param iv 初始化向量16字节 * return 明文 */ public static String decrypt(String data, String key, String iv) throws Exception { byte[] raw key.getBytes(UTF-8); SecretKeySpec keySpec new SecretKeySpec(raw, AES); Cipher cipher Cipher.getInstance(AES/CBC/PKCS7Padding, BC); IvParameterSpec ivSpec new IvParameterSpec(iv.getBytes(UTF-8)); cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); byte[] encrypted Base64.getDecoder().decode(data); byte[] original cipher.doFinal(encrypted); return new String(original, UTF-8); } }3.3 使用示例public static void main(String[] args) throws Exception { // 16字节的密钥和初始化向量 String key 1234567890abcdef; String iv abcdef1234567890; String plainText 这是一段需要加密的敏感数据; // 加密 String encrypted AESUtil.encrypt(plainText, key, iv); System.out.println(加密结果: encrypted); // 解密 String decrypted AESUtil.decrypt(encrypted, key, iv); System.out.println(解密结果: decrypted); }4. 实际应用中的注意事项4.1 密钥管理密钥的安全性直接决定了加密系统的安全性。在实际项目中不要硬编码密钥在代码中密钥应该定期更换可以使用密钥管理系统KMS来管理密钥对于密码等场景建议使用PBKDF2等算法从口令派生密钥4.2 初始化向量IVIV不需要保密但必须随机生成且不可预测同一个密钥下不要重复使用相同的IVIV可以随密文一起存储和传输4.3 性能优化对于大量数据可以考虑分块处理现代CPU都支持AES-NI指令集可以显著提升加解密速度根据安全需求选择合适的密钥长度不必盲目使用256位4.4 常见问题排查密钥长度不匹配确保密钥长度是16/24/32字节IV长度错误CBC模式需要16字节的IV填充异常加密解密要使用相同的填充模式字符编码问题确保加密解密使用相同的字符编码推荐UTF-85. AES与其他加密算法的对比5.1 AES vs DES/3DES密钥长度DES只有56位3DES是112/168位而AES支持128/192/256位安全性DES已被证明不安全3DES逐渐被淘汰AES是目前最安全的选择性能AES的软件和硬件实现效率都高于3DES5.2 AES vs RSA加密类型AES是对称加密RSA是非对称加密速度AES比RSA快很多适合加密大量数据用途通常配合使用 - RSA加密AES密钥AES加密实际数据在实际项目中我遇到过一个典型问题使用ECB模式加密的用户数据当数据中有大量重复内容时密文也呈现出明显的模式这给安全分析带来了风险。后来我们全部迁移到CBC模式配合随机IV生成彻底解决了这个问题。这也让我深刻理解了加密模式选择的重要性。