iT邦幫忙

2026 iThome 鐵人賽

DAY 19
0
Software Development

我是Java工程師,關於密碼學我想懂的不多系列 第 19 篇

Day18 - 對稱金鑰加密系統:AES加密演算法

  • 分享至 

  • xImage
  •  

前言

AES(Advanced Encryption Standard,進階加密標準) 原名 Rijndael,由比利時密碼學家 Joan Daemen 與 Vincent Rijmen 設計,並於 2001 年獲美國 NIST 正式採納為官方標準,用以全面取代安全性不足且效率低落的 DES 與 3DES。

作為當今全球資安領域應用最廣、極度可靠的對稱式區塊加密演算法,AES 被廣泛應用於 TLS 1.3、Wi-Fi WPA3、Signal 隱私通訊、BitLocker 磁碟加密以及各國政府與金融體系的資料保密防線中。

一、 AES 核心規格與參數

與 DES/3DES 所採用的 Feistel 網路結構不同,AES 採用了 代換置換網路(Substitution-Permutation Network, SPN) 架構。在 SPN 中,每一輪運算都會同時對整個 128-bit 區塊的所有位元進行並行處理,而非像DES演算法僅處理一半的區塊。

參數項目 AES-128 AES-192 AES-256
區塊大小 (Block Size) 128 bits (16 Bytes) 128 bits (16 Bytes) 128 bits (16 Bytes)
金鑰長度 (Key Length) 128 bits (16 Bytes) 192 bits (24 Bytes) 256 bits (32 Bytes)
迭代輪數 (Rounds) 10 輪 12 輪 14 輪
子金鑰數量與長度 11 組 128-bit 子金鑰 13 組 128-bit 子金鑰 15 組 128-bit 子金鑰
安全強度 抵禦當前所有已知攻擊 高安全性需求的標準 抗量子演算預期標準

註:AES 將 128-bit(16 位元組)的資料區塊表示為一個 4 X 4 的矩陣,稱為 狀態矩陣(State Matrix)。

二、 運算流程

https://ithelp.ithome.com.tw/upload/images/20261003/20128084iYFchu9pjJ.png

  1. SubBytes(位元組代換)—— 非線性混淆(Confusion)
  2. ShiftRows(列移位)—— 跨列擴散(Diffusion)
  3. MixColumns(行混合)—— 跨行強擴散(Diffusion)
    特別注意:最終輪(第 10/12/14 輪)會跳過 MixColumns,這是為了讓加密與解密的電路結構更為對稱,並提高硬體實作效率。
  4. AddRoundKey(輪金鑰加法)—— 金鑰導入

三、 Java JCA 實作與現代安全建議

在 Java 中,推薦使用 AES/GCM/NoPadding(具有認證防篡改功能的 AEAD 模式)作為對稱加密的首選方案。以下提供包含完整加密與解密的程式碼範例:

1. 完整 AES-GCM 加密與解密程式碼範例

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

public class AESGCMExample {
    private static final int AES_KEY_SIZE = 256;   // 首選 256 bits 安全強度
    private static final int GCM_IV_LENGTH = 12;   // GCM 模式標準 IV (Nonce) 長度為 12 位元組
    private static final int GCM_TAG_LENGTH = 128; // 認證標籤長度 128 bits

    public static void main(String[] args) throws Exception {
        String originalText = "Hello, Modern Cryptography!";

        // ==================== 1. 金鑰與 IV 生成 ====================
        // 生成 AES-256 秘密金鑰
        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(AES_KEY_SIZE);
        SecretKey key = keyGen.generateKey();

        // 生成強隨機 IV (Nonce)
        byte[] iv = new byte[GCM_IV_LENGTH];
        new SecureRandom().nextBytes(iv);

        // ==================== 2. 加密流程 (Encryption) ====================
        Cipher cipherEncrypt = Cipher.getInstance("AES/GCM/NoPadding");
        GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
        cipherEncrypt.init(Cipher.ENCRYPT_MODE, key, spec);

        byte[] ciphertext = cipherEncrypt.doFinal(originalText.getBytes(StandardCharsets.UTF_8));
        System.out.println("加密結果 (Base64): " + Base64.getEncoder().encodeToString(ciphertext));

        // ==================== 3. 解密流程 (Decryption) ====================
        Cipher cipherDecrypt = Cipher.getInstance("AES/GCM/NoPadding");
        // 解密時必須使用與加密時相同的金鑰、IV 以及 Tag 長度規格
        cipherDecrypt.init(Cipher.DECRYPT_MODE, key, spec);

        // doFinal 會自動進行 1. 密文解密 2. GCM Auth Tag 認證標籤驗證
        byte[] decryptedBytes = cipherDecrypt.doFinal(ciphertext);
        String decryptedText = new String(decryptedBytes, StandardCharsets.UTF_8);

        System.out.println("解密後的原文: " + decryptedText);
    }
}

2. GCM 解密流程核心注意事項

  1. 認證標籤(Auth Tag)自動驗證機制:
  • 在 GCM 模式下呼叫 doFinal() 進行解密時,JCA 會自動校驗密文末尾的 128-bit Auth Tag。
  • 若密文或傳輸內容遭受攻擊者篡改,解密端呼叫 doFinal() 時會自動拋出 javax.crypto.AEADBadTagException 異常並拒絕解密,徹底防止資料被篡改(Integrity Protection)。
  1. IV (Nonce) 的保存與傳輸:
  • 解密端必須擁有與加密端完全相同的 IV 才能成功解密。
  • 由於 IV 本身不需要保密(只需保證不重複),工程實務上通常會將 12 位元組的 IV 拼接到密文最前方(即 IV || Ciphertext)一同傳送給接收方,解密前再由前 12 位元組拆解出 IV。
  • IV (Nonce) 絕不重複:尤其在 GCM 或 CTR 模式下,相同金鑰搭配重複 IV 會導致金鑰流洩漏,造成致命的安全破口。

上一篇
Day17 - 對稱金鑰加密系統:3DES 加密演算法
下一篇
Day19 - 訊息鑑別碼 (Message Authention Code,MAC)
系列文
我是Java工程師,關於密碼學我想懂的不多 共 22 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言