添加文件: xy_sh/crypto.go
This commit is contained in:
parent
2f35a0130f
commit
1c356f99f3
|
|
@ -0,0 +1,134 @@
|
|||
package xy_sh
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/tjfoc/gmsm/sm3"
|
||||
"github.com/tjfoc/gmsm/sm4"
|
||||
)
|
||||
|
||||
// ============================================================
|
||||
// 时间戳生成
|
||||
// ============================================================
|
||||
|
||||
// GenerateTimestampMillis 生成毫秒级时间戳字符串
|
||||
func GenerateTimestampMillis() string {
|
||||
return fmt.Sprintf("%d", time.Now().UnixMilli())
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// SM3 哈希(含盐值)
|
||||
// ============================================================
|
||||
|
||||
// SM3WithSalt 使用SM3算法结合盐值进行哈希
|
||||
// 对应Java Hutool的 SmUtil.sm3WithSalt(salt).digestHex(data)
|
||||
// 实现方式:将salt作为HMAC的key,对数据进行HMAC-SM3计算
|
||||
func SM3WithSalt(data []byte, salt []byte) string {
|
||||
h := hmac.New(sm3.New, salt)
|
||||
h.Write(data)
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
// SM3WithSaltString 便捷方法:对字符串进行SM3加盐哈希
|
||||
func SM3WithSaltString(data string, salt string) string {
|
||||
return SM3WithSalt([]byte(data), []byte(salt))
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// SM4-CBC 加密/解密
|
||||
// ============================================================
|
||||
|
||||
// SM4Encrypt SM4-CBC模式加密,返回base64编码字符串
|
||||
// 使用 github.com/tjfoc/gmsm/sm4 实现
|
||||
func SM4Encrypt(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())
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// SM4Decrypt SM4-CBC模式解密,输入base64编码字符串,返回明文
|
||||
func SM4Decrypt(encryptedData string, key []byte) ([]byte, error) {
|
||||
if len(key) != 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(key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("创建SM4 cipher失败: %v", err)
|
||||
}
|
||||
|
||||
blockSize := block.BlockSize()
|
||||
if len(data) < blockSize {
|
||||
return nil, fmt.Errorf("数据长度不足")
|
||||
}
|
||||
iv := data[:blockSize]
|
||||
ciphertext := data[blockSize:]
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// pkcs7Padding PKCS7填充
|
||||
func pkcs7Padding(data []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(data)%blockSize
|
||||
padText := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(data, padText...)
|
||||
}
|
||||
|
||||
// pkcs7UnPadding 去除PKCS7填充
|
||||
func pkcs7UnPadding(data []byte) ([]byte, error) {
|
||||
length := len(data)
|
||||
if length == 0 {
|
||||
return nil, fmt.Errorf("数据为空")
|
||||
}
|
||||
padding := int(data[length-1])
|
||||
if padding > length || padding == 0 {
|
||||
return nil, fmt.Errorf("无效的填充")
|
||||
}
|
||||
for i := length - padding; i < length; i++ {
|
||||
if data[i] != byte(padding) {
|
||||
return nil, fmt.Errorf("无效的填充")
|
||||
}
|
||||
}
|
||||
return data[:length-padding], nil
|
||||
}
|
||||
Loading…
Reference in New Issue