xy_sh-20260723184208/xy_sh/pkg/crypto/crypto.go

113 lines
3.0 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 crypto
import (
"encoding/base64"
"encoding/hex"
"fmt"
"time"
"github.com/tjfoc/gmsm/sm3"
"github.com/tjfoc/gmsm/sm4"
)
// ==================== SM3 with Salt ====================
// SM3WithSalt 使用SM3加盐哈希
// 对应Java hutool的 SmUtil.sm3WithSalt(salt).digestHex(data)
// hutool实现为SM3(salt + data)
func SM3WithSalt(salt string, data string) string {
h := sm3.New()
h.Write([]byte(salt))
h.Write([]byte(data))
return hex.EncodeToString(h.Sum(nil))
}
// ==================== SM4-ECB 加密/解密 ====================
// SM4ECBEncrypt SM4-ECB模式加密返回base64编码字符串
func SM4ECBEncrypt(plaintext []byte, key []byte) (string, error) {
if len(key) != 16 {
return "", fmt.Errorf("SM4密钥长度必须为16字节")
}
block, err := sm4.NewCipher(key)
if err != nil {
return "", fmt.Errorf("创建SM4 cipher失败: %v", err)
}
padded := pkcs7Padding(plaintext, block.BlockSize())
ciphertext := make([]byte, len(padded))
for i := 0; i < len(padded); i += block.BlockSize() {
block.Encrypt(ciphertext[i:i+block.BlockSize()], padded[i:i+block.BlockSize()])
}
return base64.StdEncoding.EncodeToString(ciphertext), nil
}
// SM4ECBDecrypt SM4-ECB模式解密输入base64编码字符串返回明文
func SM4ECBDecrypt(encryptedData string, key []byte) ([]byte, error) {
if len(key) != 16 {
return nil, fmt.Errorf("SM4密钥长度必须为16字节")
}
ciphertext, err := base64.StdEncoding.DecodeString(encryptedData)
if err != nil {
return nil, fmt.Errorf("base64解码失败: %v", err)
}
block, err := sm4.NewCipher(key)
if err != nil {
return nil, fmt.Errorf("创建SM4 cipher失败: %v", err)
}
blockSize := block.BlockSize()
if len(ciphertext)%blockSize != 0 {
return nil, fmt.Errorf("密文长度不是块大小的整数倍")
}
plaintext := make([]byte, len(ciphertext))
for i := 0; i < len(ciphertext); i += blockSize {
block.Decrypt(plaintext[i:i+blockSize], ciphertext[i:i+blockSize])
}
plaintext, err = pkcs7UnPadding(plaintext)
if err != nil {
return nil, fmt.Errorf("去除填充失败: %v", err)
}
return plaintext, nil
}
// ==================== PKCS7 填充 ====================
func pkcs7Padding(data []byte, blockSize int) []byte {
padding := blockSize - len(data)%blockSize
padText := make([]byte, padding)
for i := range padText {
padText[i] = byte(padding)
}
return append(data, padText...)
}
func pkcs7UnPadding(data []byte) ([]byte, error) {
if len(data) == 0 {
return nil, fmt.Errorf("数据为空")
}
padding := int(data[len(data)-1])
if padding > len(data) || padding == 0 {
return nil, fmt.Errorf("无效的填充")
}
for i := len(data) - padding; i < len(data); i++ {
if int(data[i]) != padding {
return nil, fmt.Errorf("无效的填充")
}
}
return data[:len(data)-padding], nil
}
// ==================== 时间戳工具 ====================
// GenerateTimestampMillis 生成毫秒级时间戳
func GenerateTimestampMillis() string {
return fmt.Sprintf("%d", time.Now().UnixMilli())
}