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

Java 加密與數位簽名程式設計快速入門指南

     編輯:Java 相關知識

前言

密碼學是現代資訊安全的基石,而 Java 平台透過 java.security 與 javax.crypto 套件提供了完整的加密、雜湊、數位簽名與憑證管理功能。本文將透過實際程式碼範例,帶領讀者快速掌握 Java 中常見的密碼學操作,包含訊息摘要、對稱加密、非對稱加密、數位簽名與數位憑證等核心概念。文中範例基於 JDK 1.5 環境,但核心 API 至今仍廣泛適用於現代 Java 版本。

一、密碼學核心概念與 Java 實作

1. 訊息摘要—— 確保資料完整性

訊息摘要演算法將任意長度的輸入資料轉換為固定長度的雜湊值,具有單向不可逆、極難碰撞的特性,常用於密碼儲存、檔案完整性驗證等場景。Java 透過 java.security.MessageDigest 類別提供標準化介面,支援 MD5、SHA-1、SHA-256 等演算法。

程式碼範例:SHA-1 訊息摘要

import java.security.MessageDigest;

public class MessageDigestExample {
    public static void main(String[] args) throws Exception {
        if (args.length != 1) {
            System.err.println("用法: java MessageDigestExample <文字>");
            System.exit(1);
        }
        byte[] plainText = args[0].getBytes("UTF-8");
        
        // 取得 SHA-1 摘要演算法實例
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        System.out.println("\n提供者資訊: " + md.getProvider().getInfo());
        
        // 計算摘要
        md.update(plainText);
        byte[] digest = md.digest();
        
        // 以十六進位格式輸出(實務上建議用 Hex 編碼,避免中文亂碼)
        StringBuilder sb = new StringBuilder();
        for (byte b : digest) {
            sb.append(String.format("%02x", b));
        }
        System.out.println("\n摘要值 (Hex): " + sb.toString());
    }
}

補充說明:若需攜帶金鑰的完整性驗證,可使用 javax.crypto.Mac 實作 HMAC(如 HmacSHA256),此處不再贅述。

2. 私鑰加密(對稱加密)—— 高效保障機密性

對稱加密使用相同金鑰進行加解密,速度快、適合大量資料加密。常見演算法包含 AES(建議優先使用)、DESede(3DES)、DES(已淘汰)。Java 透過 KeyGenerator 產生金鑰,再配合 Cipher 完成加解密流程。

程式碼範例:AES-128 ECB 模式加解密

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import java.security.Key;

public class SymmetricEncryptionExample {
    public static void main(String[] args) throws Exception {
        if (args.length != 1) {
            System.err.println("用法: java SymmetricEncryptionExample <文字>");
            System.exit(1);
        }
        byte[] plainText = args[0].getBytes("UTF-8");
        
        // 1. 產生 AES 金鑰
        System.out.println("\n開始產生 AES 金鑰...");
        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(128); // 金鑰長度 128/192/256 bits
        Key secretKey = keyGen.generateKey();
        System.out.println("金鑰產生完成");
        
        // 2. 建立 Cipher 實例(演算法/模式/填充)
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        System.out.println("\n提供者資訊: " + cipher.getProvider().getInfo());
        
        // 3. 加密
        System.out.println("\n開始加密...");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] cipherText = cipher.doFinal(plainText);
        System.out.println("加密完成,密文長度: " + cipherText.length + " bytes");
        
        // 4. 解密
        System.out.println("\n開始解密...");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] decryptedText = cipher.doFinal(cipherText);
        System.out.println("解密完成: " + new String(decryptedText, "UTF-8"));
    }
}

最佳實務提醒:

  • 生產環境建議使用 GCM 或 CBC 模式搭配隨機 IV,避免使用 ECB 模式。
  • 金鑰管理至關重要,切勿硬編碼於程式碼中,建議使用金鑰管理系統(KMS)或硬體安全模組(HSM)。

3. 公鑰加密(非對稱加密)—— 解決金鑰分發難題

非對稱加密使用金鑰對:公鑰加密、私鑰解密(機密性);私鑰簽名、公鑰驗證(不可否認性)。RSA 是最經典的演算法,JDK 1.5 起原生支援。雖然速度較對稱加密慢 100~1000 倍,但適合用於金鑰交換、數位簽名等場景。

程式碼範例:RSA 加解密示範

import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import javax.crypto.Cipher;

public class AsymmetricEncryptionExample {
    public static void main(String[] args) throws Exception {
        if (args.length != 1) {
            System.err.println("用法: java AsymmetricEncryptionExample <文字>");
            System.exit(1);
        }
        byte[] plainText = args[0].getBytes("UTF-8");
        
        // 1. 產生 RSA 金鑰對(建議 2048 bits 以上)
        System.out.println("\n開始產生 RSA 金鑰對...");
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(2048);
        KeyPair keyPair = keyGen.generateKeyPair();
        System.out.println("金鑰對產生完成");
        
        // 2. 公鑰加密
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        System.out.println("\n提供者資訊: " + cipher.getProvider().getInfo());
        
        System.out.println("\n開始公鑰加密...");
        cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
        byte[] cipherText = cipher.doFinal(plainText);
        System.out.println("加密完成");
        
        // 3. 私鑰解密
        System.out.println("\n開始私鑰解密...");
        cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
        byte[] decryptedText = cipher.doFinal(cipherText);
        System.out.println("解密完成: " + new String(decryptedText, "UTF-8"));
    }
}

4. 數位簽名—— 實現身分驗證與不可否認性

數位簽名結合雜湊函數與非對稱加密:發送方用私鑰對訊息摘要簽名,接收方用對應公鑰驗證。Java 透過 java.security.Signature 類別支援多種簽名演算法(如 SHA256withRSA、SHA1withDSA、SHA256withECDSA)。

程式碼範例:RSA 數位簽名與驗證

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Signature;

public class DigitalSignatureExample {
    public static void main(String[] args) throws Exception {
        if (args.length != 1) {
            System.err.println("用法: java DigitalSignatureExample <文字>");
            System.exit(1);
        }
        byte[] plainText = args[0].getBytes("UTF-8");
        
        // 1. 產生金鑰對
        System.out.println("\n開始產生 RSA 金鑰對...");
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(2048);
        KeyPair keyPair = keyGen.generateKeyPair();
        System.out.println("金鑰對產生完成");
        
        // 2. 簽名(私鑰)
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(keyPair.getPrivate());
        signature.update(plainText);
        byte[] digitalSignature = signature.sign();
        System.out.println("\n簽名完成,長度: " + digitalSignature.length + " bytes");
        System.out.println("提供者資訊: " + signature.getProvider().getInfo());
        
        // 3. 驗證(公鑰)
        System.out.println("\n開始驗證簽名...");
        signature.initVerify(keyPair.getPublic());
        signature.update(plainText);
        boolean verified = signature.verify(digitalSignature);
        System.out.println(verified ? "✓ 簽名驗證通過" : "✗ 簽名驗證失敗");
    }
}

5. 數位憑證與金鑰庫—— 信任鏈的建立

為防止中間人攻擊(攻擊者冒充公鑰),需要可信任的第三方機構(CA)對公鑰進行簽名,形成數位憑證(X.509 標準)。Java 提供 keytool 工具管理金鑰庫(Keystore),支援 JKS、PKCS12 等格式。

常用 keytool 指令

# 產生自簽憑證與金鑰對
keytool -genkeypair -alias myKey -keyalg RSA -keysize 2048 -keystore mykeystore.p12 -storetype PKCS12 -validity 365

# 列出金鑰庫內容
keytool -list -keystore mykeystore.p12 -storetype PKCS12 -v

# 匯出憑證
keytool -exportcert -alias myKey -keystore mykeystore.p12 -storetype PKCS12 -file mycert.cer

# 匯入受信任憑證
keytool -importcert -alias trustedCA -file ca.cer -keystore truststore.p12 -storetype PKCS12

二、JAR 檔案簽名

對 JAR 檔進行數位簽名可確保程式碼來源真實性與完整性。接收方可根據簽名者身分決定是否授予權限(如透過 Policy 檔案配置)。

jarsigner 實務操作

# 對 JAR 簽名
jarsigner -keystore mykeystore.p12 -storetype PKCS12 MyApp.jar myKey

# 驗證簽名
jarsigner -verify -verbose -certs MyApp.jar

在 Applet 或 Java Web Start 部署中,瀏覽器會提示使用者檢視憑證並決定是否信任執行。

三、SSL/TLS 安全通訊協定

SSL/TLS 為網路通訊提供加密、身分驗證與完整性保護。Java 透過 javax.net.ssl 套件支援 SSL/TLS 客戶端與伺服端開發。

SSL 交握流程簡述

  1. 客戶端發起 HTTPS 請求,伺服端回傳 X.509 憑證(含公鑰)。
  2. 客戶端驗證憑證信任鏈、主機名稱匹配。
  3. 客戶端產生預主密鑰,用伺服端公鑰加密傳送。
  4. 雙方從預主密鑰導出會話金鑰,改用對稱加密(如 AES-GCM)進行後續通訊。

簡易 SSL 伺服器範例架構

import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLServerSocket;
import java.io.*;

public class SimpleSSLServer {
    public static void main(String[] args) throws Exception {
        // 需設定系統屬性:javax.net.ssl.keyStore、javax.net.ssl.keyStorePassword
        SSLServerSocketFactory factory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
        SSLServerSocket serverSocket = (SSLServerSocket) factory.createServerSocket(8443);
        
        System.out.println("SSL 伺服器啟動於 port 8443...");
        while (true) {
            try (var socket = serverSocket.accept();
                 var in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                 var out = new PrintWriter(socket.getOutputStream(), true)) {
                String request = in.readLine();
                System.out.println("收到請求: " + request);
                out.println("HTTP/1.1 200 OK");
                out.println("Content-Type: text/plain");
                out.println();
                out.println("Hello, Secure World!");
            }
        }
    }
}

啟動參數:

java -Djavax.net.ssl.keyStore=keystore.p12 \
     -Djavax.net.ssl.keyStorePassword=changeit \
     -Djavax.net.ssl.keyStoreType=PKCS12 \
     SimpleSSLServer

總結

Java 提供了完整且標準化的密碼學 API,涵蓋雜湊、對稱/非對稱加密、數位簽名、憑證管理與 SSL/TLS 通訊。實務開發時應注意:

  • 選用強健演算法(AES-GCM、RSA-2048+、SHA-256+、ECDSA P-256)。
  • 妥善管理金鑰生命週期(產生、輪換、撤銷、銷毀)。
  • 使用成熟的高層庫(如 Bouncy Castle、Google Tink)降低誤用風險。
  • 定期更新 JDK 與安全性提供者,修補已知漏洞。

建議進一步閱讀 Bruce Schneier 著作《Applied Cryptography》與 NIST SP 800 系列文件,深化密碼學工程實務能力。

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