voucher/internal/pkg/cmb/sm2.go

150 lines
3.2 KiB
Go

package cmb
import (
"crypto/rand"
"encoding/base64"
"encoding/hex"
"fmt"
"github.com/ZZMarquis/gm/sm4"
"github.com/tjfoc/gmsm/sm2"
"strings"
sm22 "voucher/internal/pkg/cmb/sm2"
"voucher/internal/pkg/cmb/sm2/model"
"voucher/internal/pkg/cmb/sm2/sdk"
)
// GenerateSm2Key 生成密钥对
func GenerateSm2Key() (string, string) {
pri, _ := sm2.GenerateKey(rand.Reader)
hexPri := pri.D.Text(16)
// 获取公钥
publicKeyHex := publicKeyToString(&pri.PublicKey)
return hexPri, publicKeyHex
}
// publicKeyToString 公钥sm2.PublicKey转字符串(与java中org.bouncycastle.crypto生成的公私钥完全互通使用)
func publicKeyToString(publicKey *sm2.PublicKey) string {
xBytes := publicKey.X.Bytes()
yBytes := publicKey.Y.Bytes()
// 确保坐标字节切片长度相同
byteLen := len(xBytes)
if len(yBytes) > byteLen {
byteLen = len(yBytes)
}
// 为坐标补齐前导零
xBytes = append(make([]byte, byteLen-len(xBytes)), xBytes...)
yBytes = append(make([]byte, byteLen-len(yBytes)), yBytes...)
// 添加 "04" 前缀
publicKeyBytes := append([]byte{0x04}, append(xBytes, yBytes...)...)
return hex.EncodeToString(publicKeyBytes)
}
func Encrypt(sopPublicKey, input string) (string, error) {
sm4Key := GenerateSM4Key()
iv := GetSM4IV()
encryptedBody, err := sm4.CBCEncrypt(sm4Key, iv, Padding([]byte(input), 1))
keyAndIv := AssemblingByteArray(sm4Key, iv)
kvTmp, err := sm22.NewSm2().
SetHexPublicKey(sopPublicKey).
SetData([]byte(base64.StdEncoding.EncodeToString(keyAndIv))).
SetSdk(sdk.NewCmbLifeSdk()).
SetCipherType(model.C1C3C2).
Encrypt().
ToString()
if err != nil {
return "", err
}
return fmt.Sprintf("%s|%s", base64.StdEncoding.EncodeToString([]byte(kvTmp)), base64.StdEncoding.EncodeToString(encryptedBody)), nil
}
func Decrypt(privateKey, input string) (string, error) {
tmpDataArr := strings.Split(input, "|")
if len(tmpDataArr) != 2 {
return "", fmt.Errorf("数据格式错误")
}
keyAndIvStr := tmpDataArr[0]
encryptedBody := tmpDataArr[1]
kvBase64Tmp, err := sm22.NewSm2().
SetHexPrivateKey(privateKey).
SetBase64StringData(keyAndIvStr).
SetSdk(sdk.NewCmbLifeSdk()).
SetCipherType(model.C1C3C2).
Decrypt().
ToString()
if err != nil {
return "", err
}
kvTmp, err := base64.StdEncoding.DecodeString(kvBase64Tmp)
if err != nil {
return "", err
}
if len(kvTmp) != 33 {
return "", fmt.Errorf("iv长度不等于33")
}
plainKey := kvTmp[0:16]
plainIv := kvTmp[17:33]
data2, err := base64.StdEncoding.DecodeString(encryptedBody)
if err != nil {
return "", err
}
plainText, err := sm4.CBCDecrypt(plainKey, plainIv, data2)
if err != nil {
return "", err
}
return string(Padding(plainText, 0)), nil
}
func Sign(privateKey, input string) (string, error) {
signData, err := sm22.NewSm2().
SetHexPrivateKey(privateKey).
SetData([]byte(input)).
Sign().
ToString()
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString([]byte(signData)), nil
}
func Verify(publicKey, input, sign string) (bool, error) {
ok, err := sm22.NewSm2().
SetHexPublicKey(publicKey).
SetData([]byte(input)).
SetBase64Signature(sign).
Verify().
ToBool()
if err != nil {
return false, err
}
if !ok {
return false, nil
}
return true, nil
}