Go中使用RSA/ECB/PKCS1Padding加密对接银联失败,如何解决?
解决Go与Java RSA/ECB/PKCS1Padding加密结果不一致问题
导致Go和Java加密结果无法对接银联的核心是字符串编码、证书解析格式两个关键细节差异,逐一修正即可:
1. 字符串编码不匹配
Java中plantext.getBytes()默认采用系统平台编码(Windows下为GBK,Linux/macOS下为UTF-8),而Go中[]byte(plantext)固定使用UTF-8编码。银联接口通常要求统一使用GBK编码,这是最常见的不匹配原因。
修正方案:
引入GBK编码库,将明文转为GBK字节数组再加密:
import ( "golang.org/x/text/encoding/simplifiedchinese" "golang.org/x/text/transform" "io" ) // 字符串转GBK字节数组 func strToGBK(s string) ([]byte, error) { encoder := simplifiedchinese.GBK.NewEncoder() result, _, err := transform.String(encoder, s) if err != nil { return nil, err } return []byte(result), nil }
加密时替换原字节转换逻辑:
gbkPlaintext, err := strToGBK("6122005564598") if err != nil { // 处理编码错误 } encrypted, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, gbkPlaintext)
2. 证书解析格式差异
Java代码直接解码纯Base64格式的DER证书(无PEM头尾标记),而Go的pem.Decode仅支持带-----BEGIN CERTIFICATE-----/-----END CERTIFICATE-----的PEM格式证书。如果你的证书源和Java端一致(纯Base64),需跳过PEM解码,直接解析DER格式:
// 假设certBase64是纯Base64的证书字符串(无PEM头尾) derBytes, err := base64.StdEncoding.DecodeString(certBase64) if err != nil { // 处理解码错误 } cert, err := x509.ParseCertificate(derBytes) if err != nil { // 处理证书解析错误 } pubKey := cert.PublicKey.(*rsa.PublicKey)
3. Base64编码一致性验证
Java的Base64.encodeBase64String和Go的base64.StdEncoding.EncodeToString均为标准Base64编码(无换行),这部分通常无需调整。若Java端使用URL安全Base64,需替换为Go的base64.URLEncoding。
完整可运行Go代码示例
package main import ( "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/base64" "errors" "log" "golang.org/x/text/encoding/simplifiedchinese" "golang.org/x/text/transform" "io" ) func strToGBK(s string) ([]byte, error) { encoder := simplifiedchinese.GBK.NewEncoder() result, _, err := transform.String(encoder, s) if err != nil { return nil, err } return []byte(result), nil } func encryptWithUnionPayCert(certBase64, plaintext string) (string, error) { // 解析DER格式证书 derBytes, err := base64.StdEncoding.DecodeString(certBase64) if err != nil { return "", err } cert, err := x509.ParseCertificate(derBytes) if err != nil { return "", err } pubKey, ok := cert.PublicKey.(*rsa.PublicKey) if !ok { return "", errors.New("not RSA public key") } // 转换明文为GBK编码 gbkData, err := strToGBK(plaintext) if err != nil { return "", err } // RSA PKCS#1 v1.5加密 encrypted, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, gbkData) if err != nil { return "", err } return base64.StdEncoding.EncodeToString(encrypted), nil } func main() { // 替换为你的银联公钥证书纯Base64字符串 unionPayCert := "你的证书Base64内容" plaintext := "6122005564598" encryptedStr, err := encryptWithUnionPayCert(unionPayCert, plaintext) if err != nil { log.Fatalf("加密失败: %v", err) } log.Println("加密结果:", encryptedStr) }
验证方法
- 用Java代码加密示例明文,记录基准结果。
- 运行修正后的Go代码,对比加密后的Base64字符串是否与Java结果一致。
- 若仍不一致,确认两端使用的是同一银联公钥证书。
内容的提问来源于stack exchange,提问作者Temuujin Oyuntsetseg
相关产品推荐
相关产品推荐

