如何加解密敏感信息

更新时间:2024.12.23

为了保证通信过程中敏感信息字段(如用户的住址、银行卡号、手机号码等)的机密性,微信支付API v3要求商户对上送的敏感信息字段进行加密。与之相对应,微信支付会对下行的敏感信息字段进行加密,商户需解密后方能得到原文。下面详细介绍加解密的方式,以及如何进行相应的计算。

我们提供了微信支付API v3官方SDK(目前包含Java (opens new window)PHP (opens new window)Go (opens new window)三种语言版本),使用官方 SDK 调用微信支付接口,无需关心签名生成和验证,接入更方便。

# 1. 加密算法

敏感信息加密使用的RSA公钥加密算法 (opens new window)。加密算法使用的填充方案,我们使用了相对更安全的RSAES-OAEP(Optimal Asymmetric Encryption Padding)。

RSAES-OAEP在各个编程语言中的模式值为:

开发者应当使用微信支付平台证书中的公钥,对上送的敏感信息进行加密。这样只有拥有私钥的微信支付才能对密文进行解密,从而保证了信息的机密性。

另一方面,微信支付使用 商户证书中的公钥对下行的敏感信息进行加密。开发者应使用商户私钥对下行的敏感信息的密文进行解密。

# 2. 加密示例

开发者应当使用微信支付平台证书中的公钥,对上送的敏感信息进行加密。

大部分编程语言支持RSA公钥加密。你可以参考示例,了解如何使用您的编程语言实现敏感信息加密。

示例代码
1public static String rsaEncryptOAEP(String message, X509Certificate certificate)
2throws IllegalBlockSizeException, IOException {
3 try {
4 Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
5 cipher.init(Cipher.ENCRYPT_MODE, certificate.getPublicKey());
6
7 byte[] data = message.getBytes("utf-8");
8 byte[] cipherdata = cipher.doFinal(data);
9 return Base64.getEncoder().encodeToString(cipherdata);
10 } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
11 throw new RuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
12 } catch (InvalidKeyException e) {
13 throw new IllegalArgumentException("无效的证书", e);
14 } catch (IllegalBlockSizeException | BadPaddingException e) {
15 throw new IllegalBlockSizeException("加密原串的长度不能超过214字节");
16 }
17}
1secretMessage := []byte("send reinforcements, we're going to advance")
2rng := rand.Reader
3
4cipherdata, err := EncryptOAEP(sha1.New(), rng, rsaPublicKey, secretMessage, nil)
5if err != nil {
6 fmt.Fprintf(os.Stderr, "Error from encryption: %s\n", err)
7 return
8}
9
10ciphertext := base64.StdEncoding.EncodeToString(cipherdata)
11fmt.Printf("Ciphertext: %s\n", ciphertext)
1private
2function getEncrypt($str) {
3 //$str是待加密字符串
4 $public_key_path = '平台证书路径';
5 $public_key = file_get_contents($public_key_path);
6 $encrypted = '';
7 if (openssl_public_encrypt($str, $encrypted, $public_key, OPENSSL_PKCS1_OAEP_PADDING)) {
8 //base64编码
9 $sign = base64_encode($encrypted);
10 } else {
11 throw new Exception('encrypt failed');
12 }
13 return $sign;
14}
1///
2
3/// 最终提交请求时,需对敏感信息加密,如身份证、银行卡号。
4/// 加密算法是RSA,使用从接口下载到的公钥进行加密,非后台下载到的私钥。
5/// 感谢ISV(https://github.com/ndma-isv)提供示例
6///
7///
8
9/// 要加密的明文
10/// -----BEGIN CERTIFICATE----- 开头的string,转为bytes
11///
12public static string RSAEncrypt(string text, byte[] publicKey)
13{
14 using (var x509 = new X509Certificate2(publicKey))
15 {
16 using (var rsa = (RSACryptoServiceProvider)x509.PublicKey.Key)
17 {
18 var buff = rsa.Encrypt(Encoding.UTF8.GetBytes(text), true);
19
20 return Convert.ToBase64String(buff);
21 }
22 }
23}

# 3. 声明加密使用的平台证书

某些情况下,微信支付会更新平台证书。这时,商户有多个微信支付平台证书可以用于加密。为了保证解密顺利,商户发起请求的HTTP头部中应包括声明加密所用的平台证书。

  • 商户上送敏感信息时使用微信支付平台公钥加密,证书序列号包含在请求HTTP头部的Wechatpay-Serial

# 4. 解密示例

微信支付使用商户API证书中的公钥对下行的敏感信息进行加密。开发者应使用商户私钥对下行的敏感信息的密文进行解密。

同样的,大部分编程语言支持RSA私钥解密。你可以参考示例,了解如何使用您的编程语言实现敏感信息解密。

示例代码
1public static String rsaDecryptOAEP(String ciphertext, PrivateKey privateKey)
2throws BadPaddingException, IOException {
3 try {
4 Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
5 cipher.init(Cipher.DECRYPT_MODE, privateKey);
6
7 byte[] data = Base64.getDecoder().decode(ciphertext);
8 return new String(cipher.doFinal(data), "utf-8");
9 } catch (NoSuchPaddingException | NoSuchAlgorithmException e) {
10 throw new RuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
11 } catch (InvalidKeyException e) {
12 throw new IllegalArgumentException("无效的私钥", e);
13 } catch (BadPaddingException | IllegalBlockSizeException e) {
14 throw new BadPaddingException("解密失败");
15 }
16}
1cipherdata, _ := base64.StdEncoding.DecodeString(ciphertext)
2rng := rand.Reader
3
4plaintext, err := DecryptOAEP(sha1.New(), rng, rsaPrivateKey, cipherdata, nil)
5if err != nil {
6 fmt.Fprintf(os.Stderr, "Error from decryption: %s\n", err)
7 return
8}
9
10fmt.Printf("Plaintext: %s\n", string(plaintext))
反馈
咨询
目录

微信支付文档中心已升级,你当前所查看的是旧文档中心的内容,旧文档中心将于 2025年 3 月 31日 下线,请移步 [新文档中心] 查看相应的内容