java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : DER input, Integer tag error
在調用支付寶 SDK 簽名/驗簽環節拋出上述異常,導致支付請求構建失敗。
經對比支付寶官方文檔與生成的私鑰文件,發現 OpenSSL 生成 PKCS#8 格式私鑰的命令參數順序錯誤,導致輸出的私鑰格式不符合 Java 安全提供者預期的 DER 編碼結構。
# 錯誤:-outform 參數位置錯誤,導致輸出格式非預期
openssl pkcs8 -topk8 -nocrypt -inform PEM -in rsa_private_key.pem -outform PEM outform
# 1. 生成 2048 位 RSA 私鑰(建議 2048 位以上)
openssl genrsa -out rsa_private_key.pem 2048
# 2. 導出公鑰
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
# 3. 轉換為 PKCS#8 格式(Java 偏好格式),注意 -outform PEM 緊跟 -out 文件路徑
openssl pkcs8 -topk8 -nocrypt -inform PEM -in rsa_private_key.pem -outform PEM -out rsa_private_key_pkcs8.pem
| 參數 | 含義 | 注意事項 |
|---|---|---|
-topk8 | 輸出 PKCS#8 格式 | Java 偏好 PKCS#8,而非傳統 PKCS#1 |
-nocrypt | 不加密私鑰 | 生產環境建議加密,運行時解密載入 |
-inform PEM | 輸入格式為 PEM | 對應步驟 1 生成的格式 |
-outform PEM | 輸出格式為 PEM | 必須在 -out 之前 |
-out file | 輸出文件路徑 | 文件名建議帶 _pkcs8 後綴區分 |
# 查看私鑰結構,應包含 BEGIN PRIVATE KEY(PKCS#8)而非 BEGIN RSA PRIVATE KEY(PKCS#1)
head -n 5 rsa_private_key_pkcs8.pem
# -----BEGIN PRIVATE KEY-----
# MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQD...
# -----END PRIVATE KEY-----
public static PrivateKey loadPrivateKey(String path) throws Exception {
String pem = new String(Files.readAllBytes(Paths.get(path)));
pem = pem.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s", "");
byte[] encoded = Base64.getDecoder().decode(pem);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(encoded);
return KeyFactory.getInstance("RSA").generatePrivate(spec);
}
-outform 必須緊跟 -out。