如何使用Java AES 256 GCM解密此前已加密存储的文本内容
Java AES GCM持久化加解密调整方案
当前示例代码仅支持单次运行时的加解密测试,核心问题是每次运行都会动态生成随机AES密钥和GCM初始化向量(IV),而AES GCM解密要求密钥、IV必须和加密时完全一致,未持久化存储这两个参数就无法实现跨时间的解密需求。
调整思路
- 密钥仅生成一次,Base64编码后存储在安全可控的独立区域(如密钥管理服务、权限严格管控的单独配置文件),禁止与加密后的密文存放在同一配置文件,避免同时泄露。
- GCM的IV无需保密,仅需保证每次加密时唯一即可,加密后将12字节的IV和密文拼接后统一做Base64编码存储,解密时直接拆分前12字节即可得到对应IV。
调整后完整代码
package com.javainterviewpoint; import java.security.SecureRandom; import java.util.Base64; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; public class AES_GCM_Example { // 替换为你自己生成后存储的AES密钥Base64值 public static final String STORED_AES_KEY = "你生成的Base64编码的AES密钥"; public static final int AES_KEY_SIZE = 256; public static final int GCM_IV_LENGTH = 12; public static final int GCM_TAG_LENGTH = 16; // 首次使用时调用一次该方法生成AES密钥,记录返回的Base64值作为STORED_AES_KEY public static String generateAesKey() throws Exception { KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); keyGenerator.init(AES_KEY_SIZE); SecretKey key = keyGenerator.generateKey(); return Base64.getEncoder().encodeToString(key.getEncoded()); } // 加密方法,直接返回可存储的Base64字符串 public static String encryptToBase64(String plainText) throws Exception { // 读取固定存储的密钥 byte[] keyBytes = Base64.getDecoder().decode(STORED_AES_KEY); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); // 每次加密生成新的随机IV byte[] IV = new byte[GCM_IV_LENGTH]; SecureRandom random = new SecureRandom(); random.nextBytes(IV); // 加密逻辑 Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, IV); cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmParameterSpec); byte[] cipherText = cipher.doFinal(plainText.getBytes()); // 拼接IV和密文后转Base64 byte[] result = new byte[GCM_IV_LENGTH + cipherText.length]; System.arraycopy(IV, 0, result, 0, GCM_IV_LENGTH); System.arraycopy(cipherText, 0, result, GCM_IV_LENGTH, cipherText.length); return Base64.getEncoder().encodeToString(result); } // 解密方法,传入存储的Base64加密字符串直接返回明文 public static String decryptFromBase64(String encryptedBase64) throws Exception { // 读取固定存储的密钥 byte[] keyBytes = Base64.getDecoder().decode(STORED_AES_KEY); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); // 拆分IV和密文 byte[] encryptedBytes = Base64.getDecoder().decode(encryptedBase64); byte[] IV = new byte[GCM_IV_LENGTH]; System.arraycopy(encryptedBytes, 0, IV, 0, GCM_IV_LENGTH); byte[] cipherText = new byte[encryptedBytes.length - GCM_IV_LENGTH]; System.arraycopy(encryptedBytes, GCM_IV_LENGTH, cipherText, 0, cipherText.length); // 解密逻辑 Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, IV); cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec); byte[] decryptedText = cipher.doFinal(cipherText); return new String(decryptedText); } public static void main(String[] args) throws Exception { // 首次运行先执行这行生成密钥,记录后替换STORED_AES_KEY再注释掉 // System.out.println("生成的AES密钥:" + generateAesKey()); String plainText = "需要加密存储的密码"; String encryptedStr = encryptToBase64(plainText); System.out.println("可存储的加密字符串:" + encryptedStr); String decryptedText = decryptFromBase64(encryptedStr); System.out.println("解密后的明文:" + decryptedText); } }
使用说明
- 首次运行代码先执行
generateAesKey()方法,将输出的Base64密钥值替换STORED_AES_KEY常量,之后就不需要再调用密钥生成方法。 - 加密密码时调用
encryptToBase64()方法,得到的字符串直接存入配置文件即可。 - 后续解密时直接读取配置文件中的加密字符串,传入
decryptFromBase64()方法即可得到原始明文密码,可多次解密不受时间限制。
内容的提问来源于stack exchange,提问作者Shaan
相关产品推荐
相关产品推荐

