Files
lone-services/utils/crypto.go
T
2026-08-05 17:37:32 +08:00

304 lines
7.4 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 utils
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/binary"
"fmt"
)
type Crypto struct {
}
// DecryptKey 解密处理函数
func (c Crypto) DecryptKey(data, iv, key string) (string, Error) {
info, err := c.aesCBCDecryptKey(data, iv, key)
if err != nil {
return "", err
}
return info, nil
}
func (c Crypto) aesCBCDecryptKey(data, iv, key string) (string, Error) {
cipherByte, err := base64.StdEncoding.DecodeString(data)
if err != nil {
Logger.Error(err)
return "", ErrorEncryptBase64Error
}
k := []byte(key)
// 分组密钥
block, err := aes.NewCipher(k)
if err != nil {
Logger.Error(err)
return "", ErrorEncryptBase64Error
}
if len(iv) < 16 {
return "", ErrorEncryptBase64Error
}
// 加密模式
blockMode := cipher.NewCBCDecrypter(block, []byte(iv))
// 创建数组
origData := make([]byte, len(cipherByte))
// 解密
blockMode.CryptBlocks(origData, cipherByte)
// 去补码
origData = c.pKCS7UnPadding(origData)
return string(origData), nil
}
// Decrypt 解密处理函数
func (c Crypto) Decrypt(data, iv string) (string, Error) {
info, err := c.aesCBCDecrypt(data, iv)
if err != nil {
return "", err
}
return info, nil
}
func (c Crypto) aesCBCDecrypt(data, iv string) (string, Error) {
key := c.GetKey()
cipherByte, err := base64.StdEncoding.DecodeString(data)
if err != nil {
Logger.Error(err)
return "", ErrorEncryptBase64Error
}
k := []byte(key)
// 分组密钥
block, err := aes.NewCipher(k)
if err != nil {
Logger.Error(err)
return "", ErrorEncryptBase64Error
}
if len(iv) < 16 {
return "", ErrorEncryptBase64Error
}
// 加密模式
blockMode := cipher.NewCBCDecrypter(block, []byte(iv))
// 创建数组
origData := make([]byte, len(cipherByte))
// 解密
blockMode.CryptBlocks(origData, cipherByte)
// 去补码
origData = c.pKCS7UnPadding(origData)
return string(origData), nil
}
func (c Crypto) GetKey() string {
return GetConfigString("encrypt.encrypt_key")
}
// PKCS7UnPadding 去码
func (c Crypto) pKCS7UnPadding(origData []byte) []byte {
length := len(origData)
if length == 0 {
return nil
}
unPadding := int(origData[length-1])
if length < unPadding {
return nil
}
return origData[:(length - unPadding)]
}
func (c Crypto) pKCS7Padding(ciphertext []byte, blockSize int) []byte {
// 判断缺少几位长度,最少为 1,最多为 blockSize
padding := blockSize - len(ciphertext)%blockSize
// 补足位数,把切片 []byte{byte(padding)} 复制 padding 个
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
// Encrypt 加密
func (c Crypto) Encrypt(data []byte) (map[string]string, Error) {
info, err := c.aesCBCEncrypt(data)
if err != nil {
return nil, err
}
return info, nil
}
func (c Crypto) aesCBCEncrypt(data []byte) (map[string]string, Error) {
key := c.GetKey()
k := []byte(key)
iv := GetRandString(NumberSixteen)
// 分组密钥
block, err := aes.NewCipher(k)
if err != nil {
return nil, ErrorEncryptAesKeyError
}
// 获取密钥块的长度
blockSize := block.BlockSize()
// 补充码
data = c.pKCS7Padding(data, blockSize)
// 加密模式
blockMode := cipher.NewCBCEncrypter(block, []byte(iv))
// 创建数组
crypted := make([]byte, len(data))
// 加密
blockMode.CryptBlocks(crypted, data)
return map[string]string{
"data": base64.StdEncoding.EncodeToString(crypted),
"iv": iv,
}, nil
}
// Encrypt 加密
func (c Crypto) EncryptKey(data []byte, key string) (map[string]string, Error) {
info, err := c.aesCBCEncryptKey(data, key)
if err != nil {
return nil, err
}
return info, nil
}
func (c Crypto) aesCBCEncryptKey(data []byte, key string) (map[string]string, Error) {
k := []byte(key)
iv := GetRandString(NumberSixteen)
// 分组密钥
block, err := aes.NewCipher(k)
if err != nil {
return nil, ErrorEncryptAesKeyError
}
// 获取密钥块的长度
blockSize := block.BlockSize()
// 补充码
data = c.pKCS7Padding(data, blockSize)
// 加密模式
blockMode := cipher.NewCBCEncrypter(block, []byte(iv))
// 创建数组
crypted := make([]byte, len(data))
// 加密
blockMode.CryptBlocks(crypted, data)
return map[string]string{
"data": base64.StdEncoding.EncodeToString(crypted),
"iv": iv,
}, nil
}
// AESEncryptECB 不使用IV的AES-ECB加密
// key长度必须为16、24或32字节,对应AES-128、AES-192、AES-256
func (c Crypto) AESEncryptECB(data string) (string, Error) {
key := GetConfigString("encrypt.data_key")
block, err := aes.NewCipher([]byte(key))
if err != nil {
return "", ErrorEncryptMissingKey
}
// 检查密钥长度
keyLen := len(key)
if keyLen != 16 && keyLen != 24 && keyLen != 32 {
return "", ErrorEncryptMissingKey
}
dataByte := []byte(data)
// 填充数据以适应块大小
dataByte = c.pKCS7Padding(dataByte, block.BlockSize())
// ECB模式加密
crypted := make([]byte, len(dataByte))
bs := block.BlockSize()
for i := 0; i < len(dataByte); i += bs {
block.Encrypt(crypted[i:i+bs], dataByte[i:i+bs])
}
return base64.StdEncoding.EncodeToString(crypted), nil
}
// AESDecryptECB 不使用IV的AES-ECB解密
// key长度必须为16、24或32字节,对应AES-128、AES-192、AES-256
func (c Crypto) AESDecryptECB(data string) (string, Error) {
if len([]byte(data)) < 16 {
return "", ErrorEncryptMissingKey
}
key := GetConfigString("encrypt.data_key")
block, err := aes.NewCipher([]byte(key))
if err != nil {
return "", ErrorEncryptMissingKey
}
// 检查密钥长度
keyLen := len(key)
if keyLen != 16 && keyLen != 24 && keyLen != 32 {
return "", ErrorEncryptMissingKey
}
dataByte, err := base64.StdEncoding.DecodeString(data)
if err != nil {
Logger.Error(err)
return "", ErrorEncryptBase64Error
}
// ECB模式解密
decrypted := make([]byte, len(dataByte))
bs := block.BlockSize()
// 修复:正确 ECB 循环
for i := 0; i < len(dataByte); i += bs {
block.Decrypt(decrypted[i:i+bs], dataByte[i:i+bs])
}
// 移除填充
return string(c.pKCS7UnPadding(decrypted)), nil
}
func (c Crypto) DecryptWechatMsg(msgEncrypt string, encodingAESKey string) (msg []byte, receiveId string, err error) {
aesKey, err := base64.StdEncoding.DecodeString(encodingAESKey + "=")
if err != nil {
return nil, "", fmt.Errorf("AESKey解码失败: %v", err)
}
// 1. Base64 解码密文
aesMsg, err := base64.StdEncoding.DecodeString(msgEncrypt)
if err != nil {
return nil, "", fmt.Errorf("base64解码失败: %v", err)
}
// 2. AES 解密(ECB + PKCS7
randMsg, err := c.aesDecrypt(aesMsg, aesKey)
if err != nil {
return nil, "", fmt.Errorf("aes解密失败: %v", err)
}
// 3. 去掉前16随机字节
content := randMsg[16:]
if len(content) < 4 {
return nil, "", fmt.Errorf("数据格式非法")
}
// 4. 读取4字节消息长度
msgLen := binary.BigEndian.Uint32(content[:4])
end := 4 + msgLen
if uint32(len(content)) < end {
return nil, "", fmt.Errorf("消息长度非法")
}
// 5. 截取消息体
msg = content[4:end]
// 6. 剩余为 receiveid
receiveId = string(content[end:])
return msg, receiveId, nil
}
// aesDecrypt AES-ECB-PKCS7 解密(微信加密标准)
func (c Crypto) aesDecrypt(cipherText, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
// ECB 模式
mode := cipher.NewCBCDecrypter(block, make([]byte, aes.BlockSize))
plainText := make([]byte, len(cipherText))
mode.CryptBlocks(plainText, cipherText)
// PKCS7 去填充
return c.pKCS7UnPadding(plainText), nil
}