敏感信息加解密
为了保证通信过程中敏感信息字段(如用户的住址、银行卡号、手机号码等)的机密性,微信支付API V3要求商户对上送的敏感信息字段进行加密。与之相对应,微信支付会对下行的敏感信息字段进行加密,商户需解密后方能得到原文。下面详细介绍加解密的方式,以及如何进行相应的计算。
为了保证通信过程中敏感信息字段(如用户的住址、银行卡号、手机号码等)的机密性,微信支付API V3要求商户对上送的敏感信息字段进行加密。与之相对应,微信支付会对下行的敏感信息字段进行加密,商户需解密后方能得到原文。下面详细介绍加解密的方式,以及如何进行相应的计算。
敏感信息加密使用的RSA公钥加密算法。加密算法使用的填充方案,我们使用了相对更安全的RSAES-OAEP(Optimal Asymmetric Encryption Padding)。
RSAES-OAEP在各个编程语言中的模式值为:
• OpenSSL,padding设置为RSA_PKCS1_OAEP_PADDING
• Java,使用Cipher.getinstance(RSA/ECB/OAEPWithSHA-1AndMGF1Padding)
• PHP,padding设置为OPENSSL_PKCS1_OAEP_PADDING
• .NET,fOAEP设置为true
• Node.js,padding设置为crypto.constants.RSA_PKCS1_OAEP_PADDING
• Go,使用EncryptOAEP
开发者应当使用微信支付平台证书中的公钥,对上送的敏感信息进行加密。这样只有拥有私钥的微信支付才能对密文进行解密,从而保证了信息的机密性。
另一方面,微信支付使用 商户证书中的公钥对下行的敏感信息进行加密。开发者应使用商户私钥对下行的敏感信息的密文进行解密。
开发者应当使用 微信支付平台证书中的公钥,对上送的敏感信息进行加密。
大部分编程语言支持RSA公钥加密。你可以参考示例,了解如何使用您的编程语言实现敏感信息加密。
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("当前Java环境不支持RSA v1.5/OAEP", e);
} catch (InvalidKeyException e) {
throw new IllegalArgumentException("无效的证书", e);
} catch (IllegalBlockSizeException | BadPaddingException e) {
throw new IllegalBlockSizeException("加密原串的长度不能超过214字节");
}
}
}
某些情况下,微信支付会更新平台证书。这时,商户有多个微信支付平台证书可以用于加密。为了保证解密顺利,商户发起请求的HTTP头部中应包括RSA公钥加密算法,以声明加密所用的密钥对和证书。
• 商户上送敏感信息时使用微信支付平台公钥加密,证书序列号包含在请求HTTP头部的Wechatpay-Serial
微信支付使用商户证书中的公钥对下行的敏感信息进行加密。开发者应使用商户私钥对下行的敏感信息的密文进行解密。
同样的,大部分编程语言支持RSA私钥解密。你可以参考示例,了解如何使用您的编程语言实现敏感信息解密。
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("当前Java环境不支持RSA v1.5/OAEP", e);
} catch (InvalidKeyException e) {
throw new IllegalArgumentException("无效的私钥", 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证