敏感信息加解密
為了保證通信過(guò)程中敏感信息字段(如用戶(hù)的住址、銀行卡號(hào)、手機(jī)號(hào)碼等)的機(jī)密性,微信支付API V3要求商戶(hù)對(duì)上送的敏感信息字段進(jìn)行加密。與之相對(duì)應(yīng),微信支付會(huì)對(duì)下行的敏感信息字段進(jìn)行加密,商戶(hù)需解密后方能得到原文。下面詳細(xì)介紹加解密的方式,以及如何進(jìn)行相應(yīng)的計(jì)算。
為了保證通信過(guò)程中敏感信息字段(如用戶(hù)的住址、銀行卡號(hào)、手機(jī)號(hào)碼等)的機(jī)密性,微信支付API V3要求商戶(hù)對(duì)上送的敏感信息字段進(jìn)行加密。與之相對(duì)應(yīng),微信支付會(huì)對(duì)下行的敏感信息字段進(jìn)行加密,商戶(hù)需解密后方能得到原文。下面詳細(xì)介紹加解密的方式,以及如何進(jìn)行相應(yīng)的計(jì)算。
敏感信息加密使用的RSA公鑰加密算法。加密算法使用的填充方案,我們使用了相對(duì)更安全的RSAES-OAEP(Optimal Asymmetric Encryption Padding)。
RSAES-OAEP在各個(gè)編程語(yǔ)言中的模式值為:
? OpenSSL,padding設(shè)置為RSA_PKCS1_OAEP_PADDING
? Java,使用Cipher.getinstance(RSA/ECB/OAEPWithSHA-1AndMGF1Padding)
? PHP,padding設(shè)置為OPENSSL_PKCS1_OAEP_PADDING
? .NET,fOAEP設(shè)置為true
? Node.js,padding設(shè)置為crypto.constants.RSA_PKCS1_OAEP_PADDING
? Go,使用EncryptOAEP
開(kāi)發(fā)者應(yīng)當(dāng)使用微信支付平臺(tái)證書(shū)中的公鑰,對(duì)上送的敏感信息進(jìn)行加密。這樣只有擁有私鑰的微信支付才能對(duì)密文進(jìn)行解密,從而保證了信息的機(jī)密性。
另一方面,微信支付使用 商戶(hù)證書(shū)中的公鑰對(duì)下行的敏感信息進(jìn)行加密。開(kāi)發(fā)者應(yīng)使用商戶(hù)私鑰對(duì)下行的敏感信息的密文進(jìn)行解密。
開(kāi)發(fā)者應(yīng)當(dāng)使用 微信支付平臺(tái)證書(shū)中的公鑰,對(duì)上送的敏感信息進(jìn)行加密。
大部分編程語(yǔ)言支持RSA公鑰加密。你可以參考示例,了解如何使用您的編程語(yǔ)言實(shí)現(xiàn)敏感信息加密。
package com.wechat.v3;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.Base64;
public class EncryptionUtil {
private static final String TRANSFORMATION = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding";
public static String encryptOAEP(String message, X509Certificate certificate) throws IllegalBlockSizeException {
return encrypt(message, certificate, TRANSFORMATION);
}
public static String encrypt(String message, X509Certificate certificate, String transformation) throws IllegalBlockSizeException {
try {
Cipher cipher = Cipher.getInstance(transformation);
cipher.init(Cipher.ENCRYPT_MODE, certificate.getPublicKey());
byte[] data = message.getBytes(StandardCharsets.UTF_8);
byte[] ciphertext = cipher.doFinal(data);
return Base64.getEncoder().encodeToString(ciphertext);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new RuntimeException("當(dāng)前Java環(huán)境不支持RSA v1.5/OAEP", e);
} catch (InvalidKeyException e) {
throw new IllegalArgumentException("無(wú)效的證書(shū)", e);
} catch (IllegalBlockSizeException | BadPaddingException e) {
throw new IllegalBlockSizeException("加密原串的長(zhǎng)度不能超過(guò)214字節(jié)");
}
}
}
某些情況下,微信支付會(huì)更新平臺(tái)證書(shū)。這時(shí),商戶(hù)有多個(gè)微信支付平臺(tái)證書(shū)可以用于加密。為了保證解密順利,商戶(hù)發(fā)起請(qǐng)求的HTTP頭部中應(yīng)包括RSA公鑰加密算法,以聲明加密所用的密鑰對(duì)和證書(shū)。
? 商戶(hù)上送敏感信息時(shí)使用微信支付平臺(tái)公鑰加密,證書(shū)序列號(hào)包含在請(qǐng)求HTTP頭部的Wechatpay-Serial
微信支付使用商戶(hù)證書(shū)中的公鑰對(duì)下行的敏感信息進(jìn)行加密。開(kāi)發(fā)者應(yīng)使用商戶(hù)私鑰對(duì)下行的敏感信息的密文進(jìn)行解密。
同樣的,大部分編程語(yǔ)言支持RSA私鑰解密。你可以參考示例,了解如何使用您的編程語(yǔ)言實(shí)現(xiàn)敏感信息解密。
package com.wechat.v3;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.util.Base64;
public class DecryptionUtil {
private static final String TRANSFORMATION = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding";
public static String decryptOAEP(String ciphertext, PrivateKey privateKey) throws BadPaddingException {
return decrypt(ciphertext, privateKey, TRANSFORMATION);
}
public static String decrypt(String ciphertext, PrivateKey privateKey, String transformation) throws BadPaddingException {
try {
Cipher cipher = Cipher.getInstance(transformation);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] data = Base64.getDecoder().decode(ciphertext);
return new String(cipher.doFinal(data), StandardCharsets.UTF_8);
} catch (NoSuchPaddingException | NoSuchAlgorithmException e) {
throw new RuntimeException("當(dāng)前Java環(huán)境不支持RSA v1.5/OAEP", e);
} catch (InvalidKeyException e) {
throw new IllegalArgumentException("無(wú)效的私鑰", e);
} catch (BadPaddingException | IllegalBlockSizeException e) {
throw new BadPaddingException("解密失敗");
}
}
}
Customer Service Tel
Business Development
9:00-18:00
Monday-Friday GMT+8
Technical Support
WeChat Pay Global
ICP證