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

Java 實現 DES 與 MD5 加密解密工具類完整指南

     編輯:Java 相關知識

前言

資料加密是資訊安全基石。本文提供生產級可用的 Java 加密工具類,涵蓋對稱加密(DES/AES)與單向雜湊(MD5/SHA),包含金鑰管理、向量處理、Base64 編碼與異常處理完整實作。

核心依賴

Java 8+ 內建 javax.crypto,無需額外引入。建議優先使用 AES 取代不安全的 DES。

加密工具類完整實作

package com.example.util;

import javax.crypto.*;
import javax.crypto.spec.*;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;

public final class CryptoUtils {
    private CryptoUtils() {}

    // ==================== AES 對稱加密 (推薦) ====================
    private static final String AES_ALGO = "AES";
    private static final String AES_CBC_PKCS5 = "AES/CBC/PKCS5Padding";
    private static final int KEY_SIZE = 256; // 128/192/256

    /** 從密碼派生金鑰 (PBKDF2) */
    public static SecretKey deriveKey(String password, byte[] salt) throws Exception {
        PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, KEY_SIZE);
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        return new SecretKeySpec(factory.generateSecret(spec).getEncoded(), AES_ALGO);
    }

    /** AES-CBC 加密 → Base64(salt + iv + ciphertext) */
    public static String encryptAES(String plaintext, String password) throws Exception {
        byte[] salt = SecureRandom.getInstanceStrong().generateSeed(16);
        byte[] iv = SecureRandom.getInstanceStrong().generateSeed(16);
        SecretKey key = deriveKey(password, salt);

        Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5);
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
        byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));

        // 組合:salt(16) + iv(16) + ciphertext
        byte[] combined = new byte[salt.length + iv.length + ciphertext.length];
        System.arraycopy(salt, 0, combined, 0, salt.length);
        System.arraycopy(iv, 0, combined, salt.length, iv.length);
        System.arraycopy(ciphertext, 0, combined, salt.length + iv.length, ciphertext.length);

        return Base64.getEncoder().encodeToString(combined);
    }

    /** AES-CBC 解密 */
    public static String decryptAES(String encryptedBase64, String password) throws Exception {
        byte[] combined = Base64.getDecoder().decode(encryptedBase64);
        if (combined.length < 32) throw new IllegalArgumentException("無效密文長度");

        byte[] salt = new byte[16];
        byte[] iv = new byte[16];
        byte[] ciphertext = new byte[combined.length - 32];
        System.arraycopy(combined, 0, salt, 0, 16);
        System.arraycopy(combined, 16, iv, 0, 16);
        System.arraycopy(combined, 32, ciphertext, 0, ciphertext.length);

        SecretKey key = deriveKey(password, salt);
        Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5);
        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
        byte[] plain = cipher.doFinal(ciphertext);
        return new String(plain, StandardCharsets.UTF_8);
    }

    // ==================== MD5 / SHA 雜湊 (單向) ====================
    /** MD5 雜湊 (不建議用於密碼儲存,僅校驗完整性) */
    public static String md5(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
            return bytesToHex(hash);
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException("MD5 不可用", e);
        }
    }

    /** SHA-256 雜湊 */
    public static String sha256(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
            return bytesToHex(hash);
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException("SHA-256 不可用", e);
        }
    }

    /** 帶鹽 SHA-256 (密碼儲存推薦) */
    public static String hashPassword(String password) {
        byte[] salt = SecureRandom.getInstanceStrong().generateSeed(16);
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(salt);
            byte[] hash = md.digest(password.getBytes(StandardCharsets.UTF_8));
            byte[] combined = new byte[salt.length + hash.length];
            System.arraycopy(salt, 0, combined, 0, salt.length);
            System.arraycopy(hash, 0, combined, salt.length, hash.length);
            return Base64.getEncoder().encodeToString(combined);
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException("SHA-256 不可用", e);
        }
    }

    /** 驗證帶鹽密碼 */
    public static boolean verifyPassword(String password, String storedBase64) {
        byte[] combined = Base64.getDecoder().decode(storedBase64);
        if (combined.length < 16) return false;
        byte[] salt = new byte[16];
        byte[] hash = new byte[combined.length - 16];
        System.arraycopy(combined, 0, salt, 0, 16);
        System.arraycopy(combined, 16, hash, 0, hash.length);
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(salt);
            byte[] calc = md.digest(password.getBytes(StandardCharsets.UTF_8));
            return MessageDigest.isEqual(hash, calc);
        } catch (NoSuchAlgorithmException e) {
            return false;
        }
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) sb.append(String.format("%02x", b));
        return sb.toString();
    }

    // ==================== 測試主程式 ====================
    public static void main(String[] args) throws Exception {
        String pwd = "MySecret@2024";
        String data = "敏感業務資料:訂單號 ORD-20240115-001";

        // AES 加解密
        String enc = encryptAES(data, pwd);
        System.out.println("AES加密: " + enc);
        System.out.println("AES解密: " + decryptAES(enc, pwd));

        // 密碼雜湊儲存與驗證
        String hashed = hashPassword(pwd);
        System.out.println("密碼雜湊: " + hashed);
        System.out.println("驗證成功: " + verifyPassword(pwd, hashed));
        System.out.println("驗證失敗: " + verifyPassword("WrongPwd", hashed));

        // 簡單完整性校驗
        System.out.println("MD5: " + md5(data));
        System.out.println("SHA-256: " + sha256(data));
    }
}

關鍵安全原則

場景推薦算法禁用/避免
資料加密傳輸/儲存AES-256-CBC / GCMDES, 3DES, ECB 模式
密碼儲存PBKDF2 / bcrypt / Argon2MD5, SHA-1, 純 SHA-256 無鹽
檔案完整性校驗SHA-256 / SHA-3MD5 (碰撞風險)
API 簽名HMAC-SHA256自定義拼接簽名

進階建議

  • 金鑰輪換:定期更換加密金鑰,舊資料重新加密
  • 硬體加密:高安全場景使用 HSM 或云 KMS 管理金鑰
  • Java 9+:優先使用 SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256") 替代舊版 PBKDF2WithHmacSHA1
  • 副通道攻擊防護:使用 MessageDigest.isEqual() 恆時間比對防時序攻擊
  • 依賴更新:定期檢查 Bouncy Castle 等提供者版本

總結

本工具類提供開箱即用的 AES 加解密與密碼雜湊功能,採用 PBKDF2 派生金鑰、隨機 Salt/IV、Base64 封裝,符合現代密碼學最佳實踐。生產環境請配合金鑰管理系統、審計日誌與合規審查使用。

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