环境配置
- Go 1.19+
- 系统级 GmSSL 库
- macOS:
brew install gmssl - Ubuntu/Debian:
sudo apt-get install libgmssl-dev - CentOS/RHEL:
sudo yum install gmssl-devel
- macOS:
项目文件
demo
├── go.mod
├── go.sum
├── main.go
└── public_key.pem # SM2公钥:联系商务获取
核心代码
package main
import (
"crypto/rand"
"encoding/base64"
"encoding/hex"
"fmt"
"io"
"log"
"net/http"
"net/url"
"strings"
gmssl "github.com/GmSSL/GmSSL-Go"
)
// sm4EncryptCBC 使用SM4-CBC加密数据并返回Base64编码结果
func sm4EncryptCBC(plaintext, key, iv string) (string, error) {
// 使用GmSSL-Go的SM4-CBC加密功能
sm4Cbc, err := gmssl.NewSm4Cbc([]byte(key), []byte(iv), true) // true表示加密
if err != nil {
return "", fmt.Errorf("创建SM4-CBC加密器失败: %v", err)
}
// 加密数据
ciphertext, err := sm4Cbc.Update([]byte(plaintext))
if err != nil {
return "", fmt.Errorf("SM4-CBC加密失败: %v", err)
}
// 完成加密(处理填充)
finalBlock, err := sm4Cbc.Finish()
if err != nil {
return "", fmt.Errorf("SM4-CBC完成加密失败: %v", err)
}
// 合并加密结果
fullCiphertext := append(ciphertext, finalBlock...)
// Base64编码
return base64.StdEncoding.EncodeToString(fullCiphertext), nil
}
// generateRandomSm4KeyAndIv 随机生成SM4密钥和IV(各16字节),返回十六进制字符串
func generateRandomSm4KeyAndIv() (string, string, error) {
// 生成16字节的随机密钥
keyBytes := make([]byte, 16)
if _, err := rand.Read(keyBytes); err != nil {
return "", "", fmt.Errorf("生成随机SM4密钥失败: %v", err)
}
// 生成16字节的随机IV
ivBytes := make([]byte, 16)
if _, err := rand.Read(ivBytes); err != nil {
return "", "", fmt.Errorf("生成随机SM4 IV失败: %v", err)
}
// 转换为十六进制字符串
keyHex := hex.EncodeToString(keyBytes)
ivHex := hex.EncodeToString(ivBytes)
return keyHex, ivHex, nil
}
func main() {
// 导入SM2公钥(用于加密SM4密钥和IV)
publicKey, err := gmssl.ImportSm2PublicKeyInfoPem("./public_key.pem")
if err != nil {
log.Fatalf("导入SM2公钥失败: %v", err)
}
// 基本参数配置
apiUrl := "http://v.juhe.cn/verifybankcard3/queryEncrySm"
apiKey := "12345678ba6e7a05938e6b4a12345678"
// 1. SM4密钥和IV,随机生成16字节
sm4KeyHex, sm4IvHex, err := generateRandomSm4KeyAndIv()
if err != nil {
log.Fatalf("生成随机SM4密钥和IV失败: %v", err)
}
sm4KeyBytes, _ := hex.DecodeString(sm4KeyHex)
sm4IvBytes, _ := hex.DecodeString(sm4IvHex)
// 2. 使用SM2公钥加密SM4密钥和IV,并Base64编码
sm4KeyEncrypted, err := publicKey.Encrypt(sm4KeyBytes)
if err != nil {
log.Fatalf("SM2加密SM4密钥失败: %v", err)
}
sm4IvEncrypted, err := publicKey.Encrypt(sm4IvBytes)
if err != nil {
log.Fatalf("SM2加密SM4 IV失败: %v", err)
}
sm4KeyBase64 := base64.StdEncoding.EncodeToString(sm4KeyEncrypted)
sm4IvBase64 := base64.StdEncoding.EncodeToString(sm4IvEncrypted)
// 原始数据
originalData := map[string]string{
"realname": "李洋",
"idcard": "370820199001151312",
"bankcard": "6225880212345678",
}
// 3. 使用SM4-CBC加密敏感数据
encryptedData := make(map[string]string)
for key, value := range originalData {
encrypted, err := sm4EncryptCBC(value, string(sm4KeyBytes), string(sm4IvBytes))
if err != nil {
log.Fatalf("SM4加密%s失败: %v", key, err)
}
encryptedData[key] = encrypted
}
// 接口请求入参配置
requestParams := url.Values{}
requestParams.Set("key", apiKey)
requestParams.Set("sm4Key", sm4KeyBase64)
requestParams.Set("sm4Iv", sm4IvBase64)
requestParams.Set("realname", encryptedData["realname"])
requestParams.Set("idcard", encryptedData["idcard"])
requestParams.Set("bankcard", encryptedData["bankcard"])
// 发起接口网络请求
resp, err := http.Post(apiUrl, "application/x-www-form-urlencoded", strings.NewReader(requestParams.Encode()))
if err != nil {
log.Fatalf("网络请求异常: %v", err)
}
defer resp.Body.Close()
// 读取原始响应body
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatalf("读取响应失败: %v", err)
}
fmt.Println(string(body))
}
编译运行
# 设置 GmSSL 头文件和库路径(macOS Homebrew 示例)
export CGO_CFLAGS="-I/opt/homebrew/Cellar/gmssl/3.1.1/include"
export CGO_LDFLAGS="-L/opt/homebrew/Cellar/gmssl/3.1.1/lib"
# 运行程序
go run main.go
正常情况下会输出类似信息:
{"reason":"成功","result":{"res":2,"message":"认证信息不匹配,银行卡无效","jobid":"JH2071260107144558876159mT"},"error_code":0}