305 lines
8.0 KiB
Go
305 lines
8.0 KiB
Go
// aes.go
|
||
package crypt
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
|
||
"github.com/sashabaranov/go-openai"
|
||
"github.com/sashabaranov/go-openai/jsonschema"
|
||
)
|
||
|
||
// ========== AES-CBC 加密工具 ==========
|
||
type AESCBCEncryptTool struct{}
|
||
|
||
func (t *AESCBCEncryptTool) Name() string { return "aes_cbc_encrypt" }
|
||
|
||
func (t *AESCBCEncryptTool) Description() string {
|
||
return "AES-CBC模式加密实现指南。当文档要求使用AES-CBC模式对请求体或敏感字段进行加密时使用,包含PKCS7填充、IV生成和处理"
|
||
}
|
||
|
||
func (t *AESCBCEncryptTool) GetFunctionDefinition() openai.FunctionDefinition {
|
||
return openai.FunctionDefinition{
|
||
Name: t.Name(),
|
||
Description: t.Description(),
|
||
Parameters: jsonschema.Definition{
|
||
Type: jsonschema.Object,
|
||
Properties: map[string]jsonschema.Definition{
|
||
"key_length": {
|
||
Type: jsonschema.Integer,
|
||
Description: "密钥长度,可选 16(AES-128), 24(AES-192), 32(AES-256),默认 32",
|
||
Enum: []string{"16", "24", "32"},
|
||
},
|
||
"encoding": {
|
||
Type: jsonschema.String,
|
||
Description: "输出编码方式,base64 或 hex,默认 base64",
|
||
Enum: []string{"base64", "hex"},
|
||
},
|
||
},
|
||
Required: []string{},
|
||
},
|
||
}
|
||
}
|
||
|
||
func (t *AESCBCEncryptTool) GetDetail(ctx context.Context, params map[string]string) (string, error) {
|
||
keyLength := "32"
|
||
if v, ok := params["key_length"]; ok && v != "" {
|
||
keyLength = v
|
||
}
|
||
encoding := "base64"
|
||
if v, ok := params["encoding"]; ok && v != "" {
|
||
encoding = v
|
||
}
|
||
|
||
aesType := "256"
|
||
if keyLength == "16" {
|
||
aesType = "128"
|
||
} else if keyLength == "24" {
|
||
aesType = "192"
|
||
}
|
||
|
||
return fmt.Sprintf(`
|
||
### AES-CBC 加密完整实现指南
|
||
|
||
**适用场景**:文档要求使用 AES-CBC 模式进行对称加密
|
||
|
||
**配置参数**:
|
||
- 密钥长度: %s 字节 (AES-%s)
|
||
- 编码方式: %s
|
||
|
||
**完整代码模板**:
|
||
|
||
`+"```go"+`
|
||
package crypto
|
||
|
||
import (
|
||
"crypto/aes"
|
||
"crypto/cipher"
|
||
"crypto/rand"
|
||
"encoding/base64"
|
||
"encoding/hex"
|
||
"fmt"
|
||
"io"
|
||
"bytes"
|
||
)
|
||
|
||
// AESCBCEncrypt AES-CBC模式加密
|
||
func AESCBCEncrypt(plaintext []byte, key []byte) (string, error) {
|
||
block, err := aes.NewCipher(key)
|
||
if err != nil {
|
||
return "", fmt.Errorf("创建AES cipher失败: %%v", err)
|
||
}
|
||
|
||
padded := pkcs7Padding(plaintext, aes.BlockSize)
|
||
|
||
iv := make([]byte, aes.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...)
|
||
if "%s" == "hex" {
|
||
return hex.EncodeToString(result), nil
|
||
}
|
||
return base64.StdEncoding.EncodeToString(result), nil
|
||
}
|
||
|
||
// AESCBCDecrypt AES-CBC模式解密
|
||
func AESCBCDecrypt(encryptedData string, key []byte) ([]byte, error) {
|
||
var data []byte
|
||
var err error
|
||
|
||
if "%s" == "hex" {
|
||
data, err = hex.DecodeString(encryptedData)
|
||
} else {
|
||
data, err = base64.StdEncoding.DecodeString(encryptedData)
|
||
}
|
||
if err != nil {
|
||
return nil, fmt.Errorf("解码失败: %%v", err)
|
||
}
|
||
|
||
if len(data) < aes.BlockSize {
|
||
return nil, fmt.Errorf("数据长度不足")
|
||
}
|
||
iv := data[:aes.BlockSize]
|
||
ciphertext := data[aes.BlockSize:]
|
||
|
||
block, err := aes.NewCipher(key)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("创建AES cipher失败: %%v", err)
|
||
}
|
||
|
||
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 {
|
||
return nil, fmt.Errorf("填充数据无效")
|
||
}
|
||
return data[:length-padding], nil
|
||
}
|
||
`+"```"+`
|
||
|
||
**注意事项**:
|
||
- 密钥长度必须是 16/24/32 字节
|
||
- IV 必须随机生成且每次不同
|
||
- IV 随密文一起传输
|
||
`, keyLength, aesType, encoding, encoding, encoding), nil
|
||
}
|
||
|
||
func (t *AESCBCEncryptTool) Execute(ctx context.Context, params map[string]string) (string, error) {
|
||
return t.GetDetail(ctx, params)
|
||
}
|
||
|
||
// ========== AES-ECB 加密工具 ==========
|
||
type AESECBEncryptTool struct{}
|
||
|
||
func (t *AESECBEncryptTool) Name() string { return "aes_ecb_encrypt" }
|
||
|
||
func (t *AESECBEncryptTool) Description() string {
|
||
return "AES-ECB模式加密实现指南。⚠️注意ECB模式不安全,仅用于兼容老旧系统"
|
||
}
|
||
|
||
func (t *AESECBEncryptTool) GetFunctionDefinition() openai.FunctionDefinition {
|
||
return openai.FunctionDefinition{
|
||
Name: t.Name(),
|
||
Description: t.Description(),
|
||
Parameters: jsonschema.Definition{
|
||
Type: jsonschema.Object,
|
||
Properties: map[string]jsonschema.Definition{
|
||
"key_length": {
|
||
Type: jsonschema.Integer,
|
||
Description: "密钥长度,可选 16(AES-128), 24(AES-192), 32(AES-256),默认 32",
|
||
Enum: []string{"16", "24", "32"},
|
||
},
|
||
"encoding": {
|
||
Type: jsonschema.String,
|
||
Description: "输出编码方式,base64 或 hex,默认 base64",
|
||
Enum: []string{"base64", "hex"},
|
||
},
|
||
},
|
||
Required: []string{},
|
||
},
|
||
}
|
||
}
|
||
|
||
func (t *AESECBEncryptTool) GetDetail(ctx context.Context, params map[string]string) (string, error) {
|
||
keyLength := "32"
|
||
if v, ok := params["key_length"]; ok && v != "" {
|
||
keyLength = v
|
||
}
|
||
encoding := "base64"
|
||
if v, ok := params["encoding"]; ok && v != "" {
|
||
encoding = v
|
||
}
|
||
|
||
return fmt.Sprintf(`
|
||
### AES-ECB 加密完整实现指南
|
||
|
||
**配置参数**:
|
||
- 密钥长度: %s 字节
|
||
- 编码方式: %s
|
||
|
||
**完整代码模板**:
|
||
|
||
`+"```go"+`
|
||
package crypto
|
||
|
||
import (
|
||
"crypto/aes"
|
||
"encoding/base64"
|
||
"encoding/hex"
|
||
"fmt"
|
||
"bytes"
|
||
)
|
||
|
||
// AESECBEncrypt AES-ECB模式加密
|
||
func AESECBEncrypt(plaintext []byte, key []byte, encoding string) (string, error) {
|
||
block, err := aes.NewCipher(key)
|
||
if err != nil {
|
||
return "", fmt.Errorf("创建AES cipher失败: %%v", err)
|
||
}
|
||
|
||
padded := pkcs7Padding(plaintext, aes.BlockSize)
|
||
|
||
ciphertext := make([]byte, len(padded))
|
||
for i := 0; i < len(padded); i += aes.BlockSize {
|
||
block.Encrypt(ciphertext[i:i+aes.BlockSize], padded[i:i+aes.BlockSize])
|
||
}
|
||
|
||
if encoding == "hex" {
|
||
return hex.EncodeToString(ciphertext), nil
|
||
}
|
||
return base64.StdEncoding.EncodeToString(ciphertext), nil
|
||
}
|
||
|
||
// AESECBDecrypt AES-ECB模式解密
|
||
func AESECBDecrypt(encryptedData string, key []byte, encoding string) ([]byte, error) {
|
||
var ciphertext []byte
|
||
var err error
|
||
|
||
if encoding == "hex" {
|
||
ciphertext, err = hex.DecodeString(encryptedData)
|
||
} else {
|
||
ciphertext, err = base64.StdEncoding.DecodeString(encryptedData)
|
||
}
|
||
if err != nil {
|
||
return nil, fmt.Errorf("解码失败: %%v", err)
|
||
}
|
||
|
||
block, err := aes.NewCipher(key)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("创建AES cipher失败: %%v", err)
|
||
}
|
||
|
||
if len(ciphertext)%%aes.BlockSize != 0 {
|
||
return nil, fmt.Errorf("密文长度不是块大小的整数倍")
|
||
}
|
||
|
||
plaintext := make([]byte, len(ciphertext))
|
||
for i := 0; i < len(ciphertext); i += aes.BlockSize {
|
||
block.Decrypt(plaintext[i:i+aes.BlockSize], ciphertext[i:i+aes.BlockSize])
|
||
}
|
||
|
||
plaintext, err = pkcs7UnPadding(plaintext)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("去除填充失败: %%v", err)
|
||
}
|
||
|
||
return plaintext, nil
|
||
}
|
||
`+"```"+`
|
||
|
||
`, keyLength, encoding, keyLength), nil
|
||
}
|
||
|
||
func (t *AESECBEncryptTool) Execute(ctx context.Context, params map[string]string) (string, error) {
|
||
return t.GetDetail(ctx, params)
|
||
}
|