在現代軟體開發中,資料傳輸的安全性至關重要。本文將透過詳細的說明、豐富的圖解與完整的原始碼範例,帶領讀者深入理解 Java 中如何實作安全通訊機制。內容涵蓋訊息摘要、訊息驗證碼(MAC)、數位憑證的產生與管理、程式碼簽署,以及如何利用簽署過的 Applet 突破沙箱限制,存取本地系統資源。
keytool 建立與維護金鑰庫訊息摘要演算法(如 MD5、SHA)將任意長度的輸入資料轉換為固定長度的雜湊值。這個值唯一對應原始資料,任何微小變動都會導致截然不同的摘要,因此可用於檢測資料是否被竄改。關鍵差異在於:加密可逆,摘要不可逆。
package com.messagedigest;
import java.security.*;
public class DigestPass {
public static void main(String[] args) throws Exception {
String str = "Hello,I sent to you 80 yuan.";
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(str.getBytes("UTF-8"));
byte[] re = md.digest();
StringBuilder result = new StringBuilder();
for (byte b : re) {
result.append(String.format("%02x", b));
}
System.out.println(result); // 輸出 32 位十六進位字串
}
}
使用 DigestInputStream 可邊讀取檔案邊計算摘要,並支援控制計算起始位置(如遇特定標記才開始)。
單純傳遞摘要無法防止「中間人」同時修改資料與摘要。MAC 引入雙方共享的密鑰,將摘要加密後傳遞,只有持有相同密鑰的接收方才能驗證。常見演算法為 HmacMD5、HmacSHA1。
package com.mac;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;
public class MyMac {
public static void main(String[] args) throws Exception {
String str = "TestString";
byte[] keyBytes = {11,105,-119,50,4,-105,16,38,-14,-111,21,-95,70,-15,76,-74,67,-88,59,-71,55,-125,104,42};
SecretKeySpec key = new SecretKeySpec(keyBytes, "HmacSHA1");
Mac mac = Mac.getInstance("HmacMD5");
mac.init(key);
mac.update(str.getBytes("UTF-8"));
byte[] result = mac.doFinal();
// 轉十六進位輸出...
}
}
MAC 要求雙方預先共享密鑰,不適合開放網路環境。非對稱加密解決此問題:發送方用私鑰加密摘要(簽名),接收方用對應公鑰解密驗證。但如何確認公鑰真屬於聲稱者?數位憑證由權威 CA(憑證授權機構)簽署,綁定主體身份與公鑰,形成信任鏈。
keytool -genkey -alias MissionCA -keyalg RSA -keysize 1024 \
-keystore abnerCALib -validity 3650 \
-dname "CN=美森系統軟體有限公司,OU=美森系統軟體有限公司,O=美森系統軟體有限公司,L=成都市,ST=四川省,C=CN" \
-keypass 200100 -storepass 100200
| 操作 | 指令範例 |
|---|---|
| 列出金鑰庫所有憑證 | keytool -list -keystore abnerCALib |
| 查看特定憑證詳細資訊 | keytool -list -v -alias MissionCA -keystore abnerCALib |
| 匯出憑證(二進位) | keytool -export -alias MissionCA -file MissionCA.cer -keystore abnerCALib |
| 匯出憑證(Base64 可列印) | keytool -export -alias MissionCA -file MissionCA.cer -keystore abnerCALib -rfc |
| 刪除憑證條目 | keytool -delete -alias MissionCA -keystore abnerCALib |
| 修改條目密碼 | keytool -keypasswd -alias MissionCA -keypass 200100 -new 123456 -storepass 100200 -keystore abnerCALib |
核心邏輯:讀取 CA 私鑰與使用者公開憑證,重建 X509CertInfo,設定簽發者、序號、有效期、演算法(MD5withRSA),最後以 CA 私鑰簽名並寫回金鑰庫。
// 關鍵步驟節錄
X509CertImpl caCert = new X509CertImpl(caCertEncoded);
X500Name issuer = (X500Name) caCert.getSubjectX500Principal();
X509CertImpl userCert = new X509CertImpl(userCertEncoded);
X509CertInfo info = (X509CertInfo) userCert.get(Certificate.INFO);
info.set(CertificateIssuerName.DN_NAME, issuer);
info.set(CertificateValidity.NAME, new CertificateValidity(start, end));
info.set(CertificateSerialNumber.NAME, new CertificateSerialNumber(serial));
info.set(CertificateAlgorithmId.NAME, new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid));
X509CertImpl signedCert = new X509CertImpl(info);
signedCert.sign(caPrivateKey, "MD5withRSA");
// 存入金鑰庫...
Mission_WaterMissionCA)簽署該憑證 → Mission_Water_Signedjar cvf myapplet.jar com/applet/*.classjarsigner 簽署 JAR:jarsigner -keystore abnerCALib myapplet.jar Mission_Water_Signedhtmlconverter 轉換為跨瀏覽器相容格式C:\WINNT\system.inipackage com.applet;
import java.applet.*;
import java.awt.*;
import java.io.*;
import javax.swing.*;
public class ShowFileApplet extends JApplet {
private TextArea ta = new TextArea(10, 80);
private String fileName = "C:\\WINNT\\system.ini";
public void init() {
try { jbInit(); myInit(); } catch (Exception e) { e.printStackTrace(); }
}
private void myInit() {
try (BufferedReader in = new BufferedReader(new FileReader(fileName))) {
String line, content = "檔案內容:\n";
while ((line = in.readLine()) != null) content += line + "\n";
ta.setText(content);
getContentPane().add(ta);
} catch (IOException ex) { ex.printStackTrace(); }
}
}
首次載入簽署 Applet 時,Java Plugin 會彈出對話框詢問用戶是否信任該憑證。選擇「總是信任」後,同憑證簽署的所有 Applet 將自動獲得權限,無需再次確認。信任記錄可在「控制台 → Java Plugin」中管理。
本文完整展示了從底層密碼學原理(摘要、MAC、非對稱加密)到工具操作(keytool、jarsigner),再到程式碼實作(CA 簽署邏輯、Applet 簽名部署)的完整鏈路。掌握這些技術,即可在 Java 應用中構建可信任的安全通訊與程式碼分發機制。