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

Java JCE 3DES 加密解密標準實作:SunJCE Provider 完整範例

     編輯:關於JSP

JDK 內建安全提供者 SunJCE 實現 3DES 加密的標準用法

Java Cryptography Extension (JCE) 內建 `SunJCE` 提供者,支援 DES、3DES (DESede)、AES、Blowfish 等對稱加密算法。本文展示零第三方依賴、純 JDK API 的 3DES 加解密標準實作,含金鑰生成、模式選擇、IV 處理、十六進位顯示與完整測試代碼。

環境需求

  • JDK 1.4+ (內建 JCE)
  • **無限制權限政策檔** (Unlimited Strength Jurisdiction Policy Files) - 針對舊版 JDK (≤8u161) 需手動替換 `$JAVA_HOME/jre/lib/security/` 下的 `local_policy.jar`、`US_export_policy.jar`,JDK 8u161+ 預設開啟

核心實作代碼

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.*;
import java.util.Arrays;

public class Standard3DES {

    // 算法常數
    private static final String ALGORITHM = "DESede";           // 3DES
    private static final String TRANSFORMATION_ECB = "DESede/ECB/PKCS5Padding";
    private static final String TRANSFORMATION_CBC = "DESede/CBC/PKCS5Padding";
    private static final int KEY_SIZE = 24;                     // 3DES 金鑰 24 bytes

    /**
     * 3DES 加密 (ECB 模式,無 IV)
     * @param keyBytes 24 位元組金鑰
     * @param plainData 明文資料
     * @return 密文位元組陣列
     */
    public static byte[] encryptECB(byte[] keyBytes, byte[] plainData) {
        return crypt(TRANSFORMATION_ECB, Cipher.ENCRYPT_MODE, keyBytes, null, plainData);
    }

    /**
     * 3DES 解密 (ECB 模式)
     */
    public static byte[] decryptECB(byte[] keyBytes, byte[] cipherData) {
        return crypt(TRANSFORMATION_ECB, Cipher.DECRYPT_MODE, keyBytes, null, cipherData);
    }

    /**
     * 3DES 加密 (CBC 模式,需 IV) - 推薦生產環境
     * @param keyBytes 24 位元組金鑰
     * @param iv 8 位元組初始化向量
     * @param plainData 明文資料
     */
    public static byte[] encryptCBC(byte[] keyBytes, byte[] iv, byte[] plainData) {
        return crypt(TRANSFORMATION_CBC, Cipher.ENCRYPT_MODE, keyBytes, iv, plainData);
    }

    /**
     * 3DES 解密 (CBC 模式)
     */
    public static byte[] decryptCBC(byte[] keyBytes, byte[] iv, byte[] cipherData) {
        return crypt(TRANSFORMATION_CBC, Cipher.DECRYPT_MODE, keyBytes, iv, cipherData);
    }

    /**
     * 核心加解密邏輯
     */
    private static byte[] crypt(String transformation, int mode, byte[] keyBytes, byte[] iv, byte[] data) {
        try {
            // 1. 驗證金鑰長度
            if (keyBytes == null || keyBytes.length != KEY_SIZE) {
                throw new IllegalArgumentException("3DES 金鑰必須為 24 位元組,實際: " + 
                    (keyBytes == null ? "null" : keyBytes.length));
            }
            
            // 2. 建立 SecretKey
            SecretKeySpec keySpec = new SecretKeySpec(keyBytes, ALGORITHM);
            
            // 3. 取得 Cipher 實例
            Cipher cipher = Cipher.getInstance(transformation);
            
            // 4. 初始化
            if (iv != null) {
                if (iv.length != 8) throw new IllegalArgumentException("3DES IV 必須為 8 位元組");
                cipher.init(mode, keySpec, new IvParameterSpec(iv));
            } else {
                cipher.init(mode, keySpec);
            }
            
            // 5. 執行
            return cipher.doFinal(data);
            
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | 
                 InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            throw new CryptoException("3DES 操作失敗: " + transformation, e);
        }
    }

    /**
     * 位元組陣列轉十六進位字串 (含分隔符,便於閱讀)
     */
    public static String bytesToHex(byte[] bytes) {
        if (bytes == null) return "null";
        StringBuilder sb = new StringBuilder(bytes.length * 3);
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() == 1) sb.append('0');
            sb.append(hex);
            if (i < bytes.length - 1) sb.append(':');
        }
        return sb.toUpperCase();
    }

    // 自定義異常
    public static class CryptoException extends RuntimeException {
        public CryptoException(String msg, Throwable cause) { super(msg, cause); }
    }

    // ========== 測試主程式 ==========
    public static void main(String[] args) {
        System.out.println("=== JDK SunJCE 3DES 標準測試 ===\n");
        
        // 1. 準備 24 位元組金鑰 (實際應從安全隨機生成或 KDF 派生)
        byte[] key = new byte[] {
            0x11, 0x22, 0x4F, 0x58, (byte)0x88, 0x10, 0x40, 0x38,
            0x28, 0x25, 0x79, 0x51, (byte)0xCB, (byte)0xDD, 0x55, 0x66,
            0x77, 0x29, 0x74, (byte)0x98, 0x30, 0x40, 0x36, (byte)0xE2
        };
        
        // 2. CBC 模式需 8 位元組 IV
        byte[] iv = new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
        
        // 3. 測試資料 (含中文)
        String plainText = "This is a 3DES test. 測試中文數據";
        byte[] plainBytes = plainText.getBytes(StandardCharsets.UTF_8);
        
        System.out.println("原文: " + plainText);
        System.out.println("原文 Hex: " + bytesToHex(plainBytes));
        System.out.println("金鑰: " + bytesToHex(key));
        System.out.println("IV:   " + bytesToHex(iv));
        System.out.println();
        
        // 4. ECB 模式測試
        System.out.println("--- ECB 模式 ---");
        byte[] ecbEncrypted = encryptECB(key, plainBytes);
        System.out.println("ECB 密文: " + bytesToHex(ecbEncrypted));
        
        byte[] ecbDecrypted = decryptECB(key, ecbEncrypted);
        System.out.println("ECB 解密: " + new String(ecbDecrypted, StandardCharsets.UTF_8));
        System.out.println("ECB 驗證: " + (Arrays.equals(plainBytes, ecbDecrypted) ? "✅ 通過" : "❌ 失敗"));
        System.out.println();
        
        // 5. CBC 模式測試 (推薦)
        System.out.println("--- CBC 模式 (推薦) ---");
        byte[] cbcEncrypted = encryptCBC(key, iv, plainBytes);
        System.out.println("CBC 密文: " + bytesToHex(cbcEncrypted));
        
        byte[] cbcDecrypted = decryptCBC(key, iv, cbcEncrypted);
        System.out.println("CBC 解密: " + new String(cbcDecrypted, StandardCharsets.UTF_8));
        System.out.println("CBC 驗證: " + (Arrays.equals(plainBytes, cbcDecrypted) ? "✅ 通過" : "❌ 失敗"));
    }
}

關鍵技術點深度解析

1. ECB vs CBC 模式選擇

特性ECB (Electronic Codebook)CBC (Cipher Block Chaining)
IV 需求不需要需要 8 bytes (3DES 區塊大小)
相同明文塊產生相同密文塊 ❌ 洩漏模式產生不同密文塊 ✅
並行計算可並行加密串行,解密可並行
錯誤傳播單塊影響當前塊及下一塊
安全性低 (不推薦)標準推薦
適用場景極短資料、測試、舊系統相容**生產環境標準**

2. PKCS5Padding 填充機制

  • 3DES 區塊大小 = 8 bytes (64-bit)
  • 資料長度非 8 倍數時,補齊 N 個值為 N 的位元組 (1~8)
  • 資料長度恰為 8 倍數時,**額外增加一整塊** (8 個 0x08)
  • 解密時自動移除填充,`BadPaddingException` 通常表示金鑰錯誤或資料損壞

3. 金鑰生成最佳實務


// ❌ 硬編碼金鑰 (僅測試用)
// ✅ 生產環境:從密碼派生 (PBKDF2) 或安全隨機生成

// 方案一:PBKDF2 派生 (密碼基礎)
public static byte[] deriveKeyPBKDF2(String password, byte[] salt, int iterations) {
    try {
        PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, 192); // 192 bits = 24 bytes
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        return factory.generateSecret(spec).getEncoded();
    } catch (Exception e) {
        throw new CryptoException("PBKDF2 失敗", e);
    }
}

// 方案二:安全隨機生成 (密鑰交換場景)
public static byte[] generateRandomKey() {
    byte[] key = new byte[24];
    new SecureRandom().nextBytes(key);
    // 修正奇偶校驗位 (DESedeKeySpec 會自動處理,但手動生成時需注意)
    return key;
}

4. 常見異常排查

異常常見原因解決
InvalidKeyException: Wrong key size金鑰非 24 bytes檢查金鑰生成/派生邏輯,確保 24 bytes
InvalidAlgorithmParameterException: Wrong IV lengthIV 非 8 bytesCBC 模式固定 8 bytes IV
BadPaddingException金鑰錯誤、資料截斷、填充損壞驗證金鑰一致性、資料完整傳輸
NoSuchAlgorithmException: DESedeJCE 提供者未載入確認 `Security.getProviders()` 含 SunJCE,或手動 `Security.addProvider(new SunJCE())`

遷移建議:從 3DES 到 AES


// 僅需變更常數,代碼結構完全相容
private static final String ALGORITHM = "AES";
private static final String TRANSFORMATION_CBC = "AES/CBC/PKCS5Padding";
private static final int KEY_SIZE = 16; // 或 24, 32 (AES-128/192/256)
private static final int IV_SIZE = 16;  // AES 區塊大小 128-bit = 16 bytes

// 金鑰生成
byte[] aesKey = new byte[16]; // 128-bit
new SecureRandom().nextBytes(aesKey);
// 或 PBKDF2 派生 128/192/256 bits

JDK 內建 `SunJCE` 提供完整、標準、零依賴的加密能力。掌握標準 API、正確選擇模式/填充、妥善管理金鑰/IV、處理編碼邊界,是 Java 後端安全開發的核心基本功。

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