voucher/internal/pkg/cmb/sm4.go

112 lines
2.4 KiB
Go

package cmb
import (
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"fmt"
"github.com/tjfoc/gmsm/sm4"
)
func generateSm4Key() (string, error) {
keyBytes, err := generateKey()
if err != nil {
return "", err
}
return ByteArrayToHexString(keyBytes)
}
func generateKey() ([]byte, error) {
key := make([]byte, sm4.BlockSize)
_, err := rand.Read(key)
if err != nil {
return nil, err
}
return key, nil
}
// ByteArrayToHexString 将字节数组转换为十六进制字符串
func ByteArrayToHexString(byteArray []byte) (string, error) {
if byteArray == nil {
return "", fmt.Errorf("byteArray is nil")
}
result := make([]byte, 0, len(byteArray)*2)
for _, b := range byteArray {
// 处理高 4 位
result = append(result, byteToHexChar(b>>4))
// 处理低 4 位
result = append(result, byteToHexChar(b&0x0F))
}
return string(result), nil
}
// byteToHexChar 将一个 4 位字节转换为对应的十六进制字符
func byteToHexChar(n byte) byte {
if n < 10 {
return '0' + n
}
return 'a' + n - 10
}
func SM4Encrypt(contentBytes []byte, encryptKey string) (string, error) {
d, err := base64.StdEncoding.DecodeString(encryptKey)
if err != nil {
return "", err
}
cipherBlock, err := sm4.NewCipher(d)
if err != nil {
return "", err
}
blockSize := cipherBlock.BlockSize()
iv := make([]byte, blockSize)
for i := 0; i < blockSize; i++ {
iv[i] = 0
}
blockMode := cipher.NewCBCEncrypter(cipherBlock, iv)
padding := blockSize - len(contentBytes)%blockSize
for i := 0; i < padding; i++ {
contentBytes = append(contentBytes, byte(padding))
}
cipherText := make([]byte, len(contentBytes))
blockMode.CryptBlocks(cipherText, contentBytes)
return base64.StdEncoding.EncodeToString(cipherText), nil
}
func SM4Decrypt(encrypted, encryptKey string) (string, error) {
d, err := base64.StdEncoding.DecodeString(encryptKey)
if err != nil {
return "", err
}
cipherBlock, err := sm4.NewCipher(d)
if err != nil {
return "", err
}
blockSize := cipherBlock.BlockSize()
iv := make([]byte, blockSize)
for i := 0; i < blockSize; i++ {
iv[i] = 0
}
cipherText, err := base64.StdEncoding.DecodeString(encrypted)
if err != nil {
return "", err
}
plainText := make([]byte, len(cipherText))
blockMode := cipher.NewCBCDecrypter(cipherBlock, iv)
blockMode.CryptBlocks(plainText, cipherText)
plainTextLen := len(plainText)
padding := int(plainText[plainTextLen-1])
buff := plainText[:plainTextLen-padding]
return string(buff), nil
}