304 lines
7.4 KiB
Go
304 lines
7.4 KiB
Go
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
|
||
}
|