Java Cryptography Architecture (JCA) 與 Extension (JCE) 提供完整的加密工具箱。本文系統整理消息摘要、對稱加密、非對稱加密、數字簽名、Diffie-Hellman 密鑰協商五大核心場景的標準 API 用法、參數選型與工程化落地要點。
| 類別 | 代表算法 | 核心類 | 典型用途 |
|---|---|---|---|
| 消息摘要 | MD5 (128bit), SHA-1 (160bit), SHA-256 | MessageDigest | 文件完整性校驗、密碼存儲 (需加鹽)、區塊鏈 |
| 對稱加密 | DES, 3DES (DESede), AES, Blowfish | Cipher, KeyGenerator | 大數據加密、數據庫字段加密、會話加密 |
| 非對稱加密 | RSA (加密/簽名), DSA (僅簽名), EC | KeyPairGenerator, Cipher | 密鑰交換、數字簽名、身份認證 |
| 密鑰協商 | Diffie-Hellman (DH), ECDH | KeyAgreement, KeyPairGenerator | 雙方協商會話密鑰 (TLS/SSL 核心) |
| 數字簽名 | SHA1withDSA, SHA256withRSA, ECDSA | Signature | 防篡改、防抵賴、代碼簽名、電子合同 |
public static String digest(String input, String algorithm) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance(algorithm); // "SHA-256"
byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
return Hex.encodeHexString(hash); // Apache Commons Codec
}
// 驗證
boolean verified = MessageDigest.isEqual(expectedHash, actualHash); // 定時比較防側信道
工程提示:密碼存儲**禁止**直接使用 MD5/SHA,必須使用 PBKDF2、BCrypt、Argon2 等慢速雜湊 (Spring Security BCryptPasswordEncoder)。
public static byte[] encrypt(byte[] plaintext, SecretKey key, byte[] iv) throws Exception {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec spec = new GCMParameterSpec(128, iv); // 128bit 認證標籤
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
return cipher.doFinal(plaintext); // 輸出: 密文 || 認證標籤
}
public static byte[] decrypt(byte[] ciphertext, SecretKey key, byte[] iv) throws Exception {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec spec = new GCMParameterSpec(128, iv);
cipher.init(Cipher.DECRYPT_MODE, key, spec);
return cipher.doFinal(ciphertext);
}
// 密鑰生成
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(256); // AES-256
SecretKey key = kg.generateKey();
// IV 生成 (每次加密唯一)
SecureRandom sr = new SecureRandom();
byte[] iv = new byte[12]; // GCM 推薦 96bit IV
sr.nextBytes(iv);
避坑:
// 密鑰對生成 (2048bit 以上)
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp = kpg.generateKeyPair();
PrivateKey priv = kp.getPrivate();
PublicKey pub = kp.getPublic();
// 加密 (僅適用短數據,長數據用混合加密)
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pub);
byte[] encrypted = cipher.doFinal(plaintext);
// 簽名 (SHA256withRSA)
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initSign(priv);
sig.update(data);
byte[] signature = sig.sign();
// 驗證
Signature verify = Signature.getInstance("SHA256withRSA");
verify.initVerify(pub);
verify.update(data);
boolean valid = verify.verify(signature);
// Alice 端
KeyPairGenerator aliceKpg = KeyPairGenerator.getInstance("DH");
aliceKpg.initialize(2048);
KeyPair aliceKp = aliceKpg.generateKeyPair();
// 發送 aliceKp.getPublic().getEncoded() 給 Bob
// Bob 端
KeyFactory kf = KeyFactory.getInstance("DH");
X509EncodedKeySpec spec = new X509EncodedKeySpec(alicePubEncoded);
PublicKey alicePub = kf.generatePublic(spec);
// 從 Alice 公鑰提取參數,生成自己的 DH 密鑰對
DHParameterSpec dhSpec = ((DHPublicKey) alicePub).getParams();
KeyPairGenerator bobKpg = KeyPairGenerator.getInstance("DH");
bobKpg.initialize(dhSpec);
KeyPair bobKp = bobKpg.generateKeyPair();
// 發送 bobKp.getPublic().getEncoded() 給 Alice
// 雙方各自生成共享密鑰
KeyAgreement aliceKa = KeyAgreement.getInstance("DH");
aliceKa.init(aliceKp.getPrivate());
aliceKa.doPhase(bobPub, true);
SecretKey aliceShared = aliceKa.generateSecret("AES"); // 直接導出 AES 密鑰
KeyAgreement bobKa = KeyAgreement.getInstance("DH");
bobKa.init(bobKp.getPrivate());
bobKa.doPhase(alicePub, true);
SecretKey bobShared = bobKa.generateSecret("AES");
// aliceShared.equals(bobShared) == true
| 密鑰類型 | 編碼格式 | 規格類 | 還原代碼 |
|---|---|---|---|
| PublicKey | X.509 | X509EncodedKeySpec | KeyFactory.getInstance("RSA").generatePublic(spec) |
| PrivateKey | PKCS#8 | PKCS8EncodedKeySpec | KeyFactory.getInstance("RSA").generatePrivate(spec) |
| SecretKey | Raw bytes | SecretKeySpec | new SecretKeySpec(bytes, "AES") |
Security.insertProviderAt(new BouncyCastleProvider(), 1) 確保優先使用 BC 實現 (支援更多算法、常數時間實現)SecureRandom (默認強隨機),避免 new Random()GeneralSecurityException 父類,區分 InvalidKeyException、BadPaddingException、IllegalBlockSizeExceptionSunPKCS11 接入硬件模塊| 誤區 | 正確認知 |
|---|---|
| 「RSA 可以加密任意長度數據」 | RSA 明文長度 < KeySize/8 - Padding開銷 (2048bit ≈ 245 bytes)。長數據必須用混合加密:AES 加密數據 + RSA 加密 AES Key |
| 「Base64 是加密」 | Base64 僅編碼,無任何機密性 |
| 「雙重加密更安全」 | 雙重 DES (2DES) 遭遇中間相遇攻擊,安全性等同單 DES。3DES (EDE) 才有效提升 |
| 「保存 PrivateKey 到文件即可」 | 必須加密存儲 (PKCS#12 / JCEKS / 加密文件),生產環境上 HSM/KMS |