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 }