首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java AES 加密實戰指南:基於 SHA1PRNG 的密鑰派生與 Base64 編碼最佳實踐

     編輯:Java 綜合教學

Java AES 加密實戰指南:基於 SHA1PRNG 的密鑰派生與 Base64 編碼最佳實踐

AES(Advanced Encryption Standard)是目前廣泛採用的對稱加密算法。本文提供一個生產級工具類,涵蓋 AES 加解密、Base64 編解碼、MD5 摘要,並重點解決「跨平台密鑰派生不一致」的經典坑,代碼開箱即用。

1. 核心工具類設計

public class AesUtils {
    // Base64 編解碼(JDK 8+ 建議用 java.util.Base64,此處兼容舊版本用 sun.misc)
    public static String base64Encode(byte[] bytes) { return new BASE64Encoder().encode(bytes); }
    public static byte[] base64Decode(String str) throws Exception {
        return str == null ? null : new BASE64Decoder().decodeBuffer(str);
    }

    // MD5 摘要
    public static byte[] md5(byte[] data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(data);
        return md.digest();
    }
    public static String md5Encrypt(String msg) throws Exception {
        return msg == null ? null : base64Encode(md5(msg.getBytes()));
    }

    // AES 加密核心:關鍵在於 SecureRandom 實例化方式
    public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        // 必須顯式指定 SHA1PRNG 並 setSeed,否則不同 JDK 實現(Windows/Linux)派生密鑰不同
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
        random.setSeed(encryptKey.getBytes());
        kgen.init(128, random); // 128 位密鑰

        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(kgen.generateKey().getEncoded(), "AES"));
        return cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
    }

    public static String aesEncrypt(String content, String key) throws Exception {
        return base64Encode(aesEncryptToBytes(content, key));
    }

    public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
        if (encryptStr == null) return null;
        byte[] decryptBytes = aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
        return new String(decryptBytes, StandardCharsets.UTF_8);
    }

    private static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
        random.setSeed(decryptKey.getBytes());
        kgen.init(128, random);

        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(kgen.generateKey().getEncoded(), "AES"));
        byte[] decrypted = cipher.doFinal(encryptBytes);
        return new String(decrypted, StandardCharsets.UTF_8);
    }
}

2. 關鍵坑點深度解析

為什麼要用 SecureRandom.getInstance("SHA1PRNG") + setSeed()?

早期寫法 new SecureRandom(key.getBytes()) 在 Windows(SunJCE)與 Linux(OpenJDK)上行為不同:Windows 使用種子作為唯一熵源,Linux 則混合系統熵池。導致相同密鑰字符串派生出不同的 AES Key,造成跨平台解密失敗。顯式指定 SHA1PRNG 並 setSeed 可強制統一行為,確保跨平台一致性。

為什麼要 Base64 包裝密文?

AES 輸出為二進制字節數組,可能包含不可見控制字符,直接存儲傳輸易損壞。Base64 編碼為可打印 ASCII 字符串,安全用於 JSON、URL、數據庫文本字段。

3. 使用示例

public static void main(String[] args) throws Exception {
    String content = "敏感業務數據:訂單號 20240101001,金額 ¥999.99";
    String key = "MySecretKey123"; // 生產環境建議從密管系統獲取,長度≥16 字符

    String encrypted = AesUtils.aesEncrypt(content, key);
    System.out.println("密文: " + encrypted);

    String decrypted = AesUtils.aesDecrypt(encrypted, key);
    System.out.println("解密: " + decrypted);
    // 輸出: 解密: 敏感業務數據:訂單號 20240101001,金額 ¥999.99
}

4. 安全加固建議

  • 密鑰管理: 禁用硬編碼密鑰,接入 Vault、KMS 或環境變量注入;定期輪換。
  • 模式升級: 生產環境建議使用 AES/GCM/NoPadding(需 12 字節 IV),提供認證加密(AEAD),防止密文篡改。ECB 模式不安全,CBC 模式需防填充預言機攻擊。
  • 密鑰派生: 高安全場景改用 PBKDF2/Argon2/scrypt 派生密鑰,增加暴力破解成本。
  • 異常處理: 捕獲 BadPaddingException、IllegalBlockSizeException 區分密鑰錯誤與數據損壞,避免信息洩露。
  • 依賴升級: JDK 9+ 移除 sun.misc.BASE64Encoder,遷移至 java.util.Base64。

5. 完整依賴說明

無第三方依賴,僅使用 JDK 標準庫(javax.crypto、java.security、java.math.BigInteger)。兼容 JDK 1.7+,JDK 9+ 需替換 Base64 實現。

掌握 AES 正確姿勢,不僅能保護數據機密性,更能避開跨平台兼容性坑,構建可信的安全基礎設施。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved