voucher/internal/pkg/cmb/sign.go

137 lines
4.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package cmb
import (
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"fmt"
"github.com/ZZMarquis/gm/util"
tsm2 "github.com/tjfoc/gmsm/sm2"
"github.com/tjfoc/gmsm/sm4"
"github.com/tjfoc/gmsm/x509"
"strings"
"voucher/internal/pkg/cmb/encrypt"
)
const messageSeparator = byte(0x7C)
type Decrypts struct {
EncryptBody string
PrivateKey string
}
type Encrypts struct {
JsonParam string
SoaPubKey string
}
func EncryptBody(encrypts *Encrypts) (string, error) {
paddedPlaintext := util.PKCS5Padding([]byte(encrypts.JsonParam), sm4.BlockSize)
//随机生成对称密钥RandomKey和偏移向量RandomIV
randomKey := make([]byte, sm4.BlockSize)
randomIV := make([]byte, sm4.BlockSize)
if _, err := rand.Read(randomKey); err != nil {
return "", fmt.Errorf("生成randomKey失败:%v", err)
}
if _, err := rand.Read(randomIV); err != nil {
return "", fmt.Errorf("生成randomIV失败: %v", err)
}
// 使用对称密钥对报文进行加密并对结果进行Base64编码
//对称加密算法为SM4/CBC/PKCS5Padding密钥长度为16字节明文长度不做要求IV长度为16字节。
block, err := sm4.NewCipher(randomKey)
if err != nil {
return "", fmt.Errorf("IV加密失败: %v", err)
}
ciphertext := make([]byte, len(paddedPlaintext))
if len(paddedPlaintext)%sm4.BlockSize != 0 {
return "", fmt.Errorf("加密格式错误:%v", err)
}
mode := cipher.NewCBCEncrypter(block, randomIV)
mode.CryptBlocks(ciphertext, paddedPlaintext)
//ciphertext, err := sm4.Sm4Cbc(randomKey, randomIV, util.PKCS5Padding([]byte(encrypts.JsonParam), sm4.BlockSize))
ciphertextBase64 := base64.StdEncoding.EncodeToString(ciphertext)
//使用掌上生活的SM2算法公钥对“RandomKey|RandomIV”进行base64之后加密并对结果进行Base64编码
//非对称加密算法为SM2公钥长度为65字节私钥长度为32字节。
keyAndIV := AssemblingByteArray(randomKey, randomIV)
keyAndIVBase64 := base64.StdEncoding.EncodeToString(keyAndIV)
pubk, err := x509.ReadPublicKeyFromHex(encrypts.SoaPubKey)
if err != nil {
return "", fmt.Errorf("解析公钥失败: %v", err)
}
sm2EncryptKeyAndIV, err := tsm2.Encrypt(pubk, []byte(keyAndIVBase64), rand.Reader, tsm2.C1C3C2)
if err != nil {
return "", fmt.Errorf("RandomKey|RandomIV加密失败: %v", err)
}
sm2EncryptKeyAndIVBase64 := base64.StdEncoding.EncodeToString(sm2EncryptKeyAndIV)
//将加密后的对称密钥以及加密后的报文进行拼接,使用“ | ”进行分割。
encryptedBody := fmt.Sprintf("%s|%s", sm2EncryptKeyAndIVBase64, ciphertextBase64)
return encryptedBody, nil
}
func DecryptBody(decrypts *Decrypts) ([]byte, error) {
var (
EncryptSlice []string
)
EncryptSlice = strings.Split(decrypts.EncryptBody, "|")
if len(EncryptSlice) != 2 {
return nil, fmt.Errorf("解密失败: 格式错误")
}
sm2EncryptKeyAndIV, err := base64.StdEncoding.DecodeString(EncryptSlice[0])
if err != nil {
return nil, fmt.Errorf("解密失败:向量格式错误: %v", err)
}
ciphertext, err := base64.StdEncoding.DecodeString(EncryptSlice[1])
if err != nil {
return nil, fmt.Errorf("解密失败:内容格式错误: %v", err)
}
prik, err := x509.ReadPrivateKeyFromHex(decrypts.PrivateKey)
if err != nil {
return nil, fmt.Errorf("解密失败:密钥错误: %v", err)
}
keyAndIv, err := tsm2.Decrypt(prik, sm2EncryptKeyAndIV, tsm2.C1C3C2)
if err != nil {
return nil, fmt.Errorf("解密失败: %v", err)
}
key, iv, err := Base64DecodeAndSplit(string(keyAndIv))
if err != nil {
return nil, fmt.Errorf("解密失败:解密后向量格式错误: %v", err)
}
block, err := sm4.NewCipher(key)
if err != nil {
return nil, fmt.Errorf("IV加密失败: %v", err)
}
paddedPlaintext := make([]byte, len(ciphertext))
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(paddedPlaintext, ciphertext)
res := util.PKCS5UnPadding(paddedPlaintext)
return res, err
}
func VerifyBody(crypt string, signDataBase64 string, pubKey string) (bool, error) {
signByte, _ := base64.StdEncoding.DecodeString(signDataBase64)
return encrypt.Sm2Sm3VerySign(crypt, string(signByte), pubKey)
}
func SignBody(sign string, privateKey string) (string, error) {
//签名
signData, err := encrypt.SM3WithSM2Sign(privateKey, sign)
return base64.StdEncoding.EncodeToString(signData), err
}
func Base64DecodeAndSplit(encoded string) ([]byte, []byte, error) {
// 解码 Base64 字符串
decodedBytes, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, nil, err
}
// 拆分字节切片
firstParam := decodedBytes[:sm4.BlockSize]
secondParam := decodedBytes[sm4.BlockSize+1:] // +1 以跳过分隔符本身
return firstParam, secondParam, nil
}