136 lines
4.6 KiB
Go
136 lines
4.6 KiB
Go
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"
|
||
)
|
||
|
||
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
|
||
}
|