為了保證通信過程中敏感信息字段(如用戶的住址、銀行卡號、手機號碼等)的機密性,微信支付API v3要求商戶對上送的敏感信息字段進行加密。與之相對應,微信支付會對下行的敏感信息字段進行加密,商戶需解密后方能得到原文。下面詳細介紹加解密的方式,以及如何進行相應的計算。
敏感信息加密使用的RSA公鑰加密算法。加密算法使用的填充方案,我們使用了相對更安全的RSAES-OAEP(Optimal Asymmetric Encryption Padding)。
RSAES-OAEP在各個編程語言中的模式值為:
RSA_PKCS1_OAEP_PADDING
Cipher.getinstance(RSA/ECB/OAEPWithSHA-1AndMGF1Padding)
OPENSSL_PKCS1_OAEP_PADDING
true
crypto.constants.RSA_PKCS1_OAEP_PADDING
使用EncryptOAEP
開發(fā)者應當使用微信支付平臺證書中的公鑰,對上送的敏感信息進行加密。這樣只有擁有私鑰的微信支付才能對密文進行解密,從而保證了信息的機密性。
另一方面,微信支付使用 商戶證書中的公鑰對下行的敏感信息進行加密。開發(fā)者應使用商戶私鑰對下行的敏感信息的密文進行解密。
開發(fā)者應當使用 微信支付平臺證書中的公鑰,對上送的敏感信息進行加密。
大部分編程語言支持RSA公鑰加密。你可以參考示例,了解如何使用您的編程語言實現(xiàn)敏感信息加密。
public static String rsaEncryptOAEP(String message, X509Certificate certificate)
throws IllegalBlockSizeException, IOException {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, certificate.getPublicKey());
byte[] data = message.getBytes("utf-8");
byte[] cipherdata = cipher.doFinal(data);
return Base64.getEncoder().encodeToString(cipherdata);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new RuntimeException("當前Java環(huán)境不支持RSA v1.5/OAEP", e);
} catch (InvalidKeyException e) {
throw new IllegalArgumentException("無效的證書", e);
} catch (IllegalBlockSizeException | BadPaddingException e) {
throw new IllegalBlockSizeException("加密原串的長度不能超過214字節(jié)");
}
}
某些情況下,微信支付會更新平臺證書。這時,商戶有多個微信支付平臺證書可以用于加密。為了保證解密順利,商戶發(fā)起請求的HTTP頭部中應包括RSA公鑰加密算法,以聲明加密所用的密鑰對和證書。
Wechatpay-Serial
微信支付使用商戶證書中的公鑰對下行的敏感信息進行加密。開發(fā)者應使用商戶私鑰對下行的敏感信息的密文進行解密。
同樣的,大部分編程語言支持RSA私鑰解密。你可以參考示例,了解如何使用您的編程語言實現(xiàn)敏感信息解密。
public static String rsaDecryptOAEP(String ciphertext, PrivateKey privateKey)
throws BadPaddingException, IOException {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] data = Base64.getDecoder().decode(ciphertext);
return new String(cipher.doFinal(data), "utf-8");
} catch (NoSuchPaddingException | NoSuchAlgorithmException e) {
throw new RuntimeException("當前Java環(huán)境不支持RSA v1.5/OAEP", e);
} catch (InvalidKeyException e) {
throw new IllegalArgumentException("無效的私鑰", e);
} catch (BadPaddingException | IllegalBlockSizeException e) {
throw new BadPaddingException("解密失敗");
}
}