xy_sh-20260727101126/xy_sh/pkg/crypto/crypto.go

144 lines
3.3 KiB
Go

package crypto
import (
"bytes"
"crypto/cipher"
"crypto/hmac"
"crypto/rand"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"io"
"github.com/tjfoc/gmsm/sm3"
"github.com/tjfoc/gmsm/sm4"
)
var (
sm3Salt []byte
sm4Key []byte
)
func InitCrypto(salt, key string) {
sm3Salt = []byte(salt)
keyBytes := []byte(key)
if len(keyBytes) < 16 {
padded := make([]byte, 16)
copy(padded, keyBytes)
sm4Key = padded
} else if len(keyBytes) > 16 {
sm4Key = keyBytes[:16]
} else {
sm4Key = keyBytes
}
}
func SM3Hash(data []byte) string {
h := sm3.New()
h.Write(data)
hashBytes := h.Sum(nil)
return hex.EncodeToString(hashBytes)
}
func SM3HashWithSalt(data string) string {
h := hmac.New(sm3.New, sm3Salt)
h.Write([]byte(data))
return hex.EncodeToString(h.Sum(nil))
}
func GenerateSign(timestamp, encryptedData string) string {
signStr := timestamp + encryptedData
return SM3HashWithSalt(signStr)
}
func VerifySign(timestamp, encryptedData, sign string) bool {
expectedSign := GenerateSign(timestamp, encryptedData)
return hmac.Equal([]byte(expectedSign), []byte(sign))
}
func SM4CBCEncrypt(plaintext []byte) (string, error) {
if len(sm4Key) != 16 {
return "", fmt.Errorf("SM4密钥长度必须为16字节")
}
block, err := sm4.NewCipher(sm4Key)
if err != nil {
return "", fmt.Errorf("创建SM4 cipher失败: %v", err)
}
padded := pkcs7Padding(plaintext, block.BlockSize())
iv := make([]byte, block.BlockSize())
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return "", fmt.Errorf("生成IV失败: %v", err)
}
mode := cipher.NewCBCEncrypter(block, iv)
ciphertext := make([]byte, len(padded))
mode.CryptBlocks(ciphertext, padded)
result := append(iv, ciphertext...)
return base64.StdEncoding.EncodeToString(result), nil
}
func SM4CBCDecrypt(encryptedData string) ([]byte, error) {
if len(sm4Key) != 16 {
return nil, fmt.Errorf("SM4密钥长度必须为16字节")
}
data, err := base64.StdEncoding.DecodeString(encryptedData)
if err != nil {
return nil, fmt.Errorf("base64解码失败: %v", err)
}
block, err := sm4.NewCipher(sm4Key)
if err != nil {
return nil, fmt.Errorf("创建SM4 cipher失败: %v", err)
}
blockSize := block.BlockSize()
if len(data) < blockSize {
return nil, errors.New("数据长度不足")
}
iv := data[:blockSize]
ciphertext := data[blockSize:]
if len(ciphertext)%blockSize != 0 {
return nil, errors.New("密文长度不是块大小的整数倍")
}
mode := cipher.NewCBCDecrypter(block, iv)
plaintext := make([]byte, len(ciphertext))
mode.CryptBlocks(plaintext, ciphertext)
plaintext, err = pkcs7UnPadding(plaintext)
if err != nil {
return nil, fmt.Errorf("去除填充失败: %v", err)
}
return plaintext, nil
}
func pkcs7Padding(data []byte, blockSize int) []byte {
padding := blockSize - len(data)%blockSize
padText := bytes.Repeat([]byte{byte(padding)}, padding)
return append(data, padText...)
}
func pkcs7UnPadding(data []byte) ([]byte, error) {
length := len(data)
if length == 0 {
return nil, errors.New("数据为空")
}
padding := int(data[length-1])
if padding > length || padding == 0 {
return nil, errors.New("无效的填充")
}
for i := length - padding; i < length; i++ {
if data[i] != byte(padding) {
return nil, errors.New("无效的填充")
}
}
return data[:length-padding], nil
}