add utils to pkg
This commit is contained in:
@@ -0,0 +1,303 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user