151 lines
3.5 KiB
Go
151 lines
3.5 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, inputJson string) (string, error) {
|
|
data, _ := base64.StdEncoding.DecodeString(inputJson)
|
|
|
|
sm4Key := GenerateSM4Key()
|
|
iv := GetSM4IV()
|
|
encryptedBody, err := sm4.CBCEncrypt(sm4Key, iv, Padding(data, 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, inputJson string) (string, error) {
|
|
data, err := base64.StdEncoding.DecodeString(inputJson)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
tmpDataArr := strings.Split(string(data), "|")
|
|
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
|
|
}
|
|
|
|
kvArr := strings.Split(string(kvTmp), "|")
|
|
if len(tmpDataArr) != 2 {
|
|
return "", fmt.Errorf("数据格式错误!")
|
|
}
|
|
plainKey := []byte(kvArr[0])
|
|
plainIv := []byte(kvArr[1])
|
|
|
|
data2, err := base64.StdEncoding.DecodeString(encryptedBody)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
plainText, err := sm4.CBCDecrypt(plainKey, plainIv, data2)
|
|
|
|
return string(Padding(plainText, 0)), nil
|
|
}
|
|
|
|
func sign(privateKey, inputJson string) (string, error) {
|
|
data, _ := base64.StdEncoding.DecodeString(inputJson)
|
|
|
|
signData, err := sm22.NewSm2().
|
|
SetHexPrivateKey(privateKey).
|
|
SetData(data).
|
|
Sign().
|
|
ToString()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return base64.StdEncoding.EncodeToString([]byte(signData)), nil
|
|
}
|
|
|
|
func verify(publicKey, inputJson, sign string) (bool, error) {
|
|
data, _ := base64.StdEncoding.DecodeString(inputJson)
|
|
|
|
ok, err := sm22.NewSm2().
|
|
SetHexPublicKey(publicKey).
|
|
SetData(data).
|
|
SetBase64Signature(sign).
|
|
Verify().
|
|
ToBool()
|
|
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
if !ok {
|
|
return false, nil
|
|
}
|
|
|
|
return true, nil
|
|
}
|