338 lines
9.3 KiB
Go
338 lines
9.3 KiB
Go
// sm4.go
|
||
package crypt
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
|
||
"github.com/sashabaranov/go-openai"
|
||
"github.com/sashabaranov/go-openai/jsonschema"
|
||
)
|
||
|
||
// ========== SM4-CBC 加密工具 ==========
|
||
type SM4CBCEncryptTool struct{}
|
||
|
||
func (t *SM4CBCEncryptTool) Name() string { return "sm4_cbc_encrypt" }
|
||
|
||
func (t *SM4CBCEncryptTool) Description() string {
|
||
return "SM4国密对称加密(CBC模式)实现指南。当文档要求使用国密SM4算法进行对称加密时使用。⚠️ 必须使用 github.com/tjfoc/gmsm 库,不要自己实现!"
|
||
}
|
||
|
||
func (t *SM4CBCEncryptTool) GetFunctionDefinition() openai.FunctionDefinition {
|
||
return openai.FunctionDefinition{
|
||
Name: t.Name(),
|
||
Description: t.Description(),
|
||
Parameters: jsonschema.Definition{
|
||
Type: jsonschema.Object,
|
||
Properties: map[string]jsonschema.Definition{
|
||
"encoding": {
|
||
Type: jsonschema.String,
|
||
Description: "输出编码方式,base64 或 hex,默认 base64",
|
||
Enum: []string{"base64", "hex"},
|
||
},
|
||
},
|
||
Required: []string{},
|
||
},
|
||
}
|
||
}
|
||
|
||
func (t *SM4CBCEncryptTool) GetDetail(ctx context.Context, params map[string]string) (string, error) {
|
||
encoding := "base64"
|
||
if v, ok := params["encoding"]; ok && v != "" {
|
||
encoding = v
|
||
}
|
||
|
||
return fmt.Sprintf(`
|
||
### SM4-CBC 国密对称加密完整实现指南
|
||
|
||
**⚠️ 重要:必须使用第三方库,不要自己实现 SM4 算法!**
|
||
**推荐使用:github.com/tjfoc/gmsm**
|
||
|
||
**前置要求**:
|
||
`+"```bash"+`
|
||
go get github.com/tjfoc/gmsm
|
||
`+"```"+`
|
||
|
||
**配置参数**:
|
||
- 编码方式: %s
|
||
|
||
**完整代码模板(请直接复制使用)**:
|
||
|
||
`+"```go"+`
|
||
package crypto
|
||
|
||
import (
|
||
"crypto/cipher"
|
||
"crypto/rand"
|
||
"encoding/base64"
|
||
"encoding/hex"
|
||
"fmt"
|
||
"io"
|
||
"bytes"
|
||
|
||
"github.com/tjfoc/gmsm/sm4" // ⚠️ 必须使用此库,不要自己实现SM4
|
||
)
|
||
|
||
// SM4CBCEncrypt SM4-CBC模式加密
|
||
// 使用 github.com/tjfoc/gmsm/sm4 实现
|
||
func SM4CBCEncrypt(plaintext []byte, key []byte) (string, error) {
|
||
if len(key) != 16 {
|
||
return "", fmt.Errorf("SM4密钥长度必须为16字节")
|
||
}
|
||
|
||
// 使用 gmsm 库创建 SM4 cipher
|
||
block, err := sm4.NewCipher(key)
|
||
if err != nil {
|
||
return "", fmt.Errorf("创建SM4 cipher失败: %%v", err)
|
||
}
|
||
|
||
padded := pkcs7Padding(plaintext, block.BlockSize())
|
||
|
||
iv := make([]byte, block.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
|
||
}
|
||
|
||
// SM4CBCDecrypt SM4-CBC模式解密
|
||
// 使用 github.com/tjfoc/gmsm/sm4 实现
|
||
func SM4CBCDecrypt(encryptedData string, key []byte) ([]byte, error) {
|
||
if len(key) != 16 {
|
||
return nil, fmt.Errorf("SM4密钥长度必须为16字节")
|
||
}
|
||
|
||
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)
|
||
}
|
||
|
||
block, err := sm4.NewCipher(key)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("创建SM4 cipher失败: %%v", err)
|
||
}
|
||
|
||
blockSize := block.BlockSize()
|
||
if len(data) < blockSize {
|
||
return nil, fmt.Errorf("数据长度不足")
|
||
}
|
||
iv := data[:blockSize]
|
||
ciphertext := data[blockSize:]
|
||
|
||
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 || padding == 0 {
|
||
return nil, fmt.Errorf("无效的填充")
|
||
}
|
||
for i := length - padding; i < length; i++ {
|
||
if data[i] != byte(padding) {
|
||
return nil, fmt.Errorf("无效的填充")
|
||
}
|
||
}
|
||
return data[:length-padding], nil
|
||
}
|
||
`+"```"+`
|
||
|
||
**⚠️ 重要提醒**:
|
||
1. **不要自己实现 SM4 算法**,请直接使用 github.com/tjfoc/gmsm
|
||
2. 这个库是国密官方推荐的 Go 实现,安全可靠
|
||
3. 在 go.mod 中添加依赖:`+"`require github.com/tjfoc/gmsm v1.4.1`"+`
|
||
|
||
**注意事项**:
|
||
- SM4 密钥固定为 16 字节
|
||
- IV 必须随机生成且每次不同
|
||
- CBC 模式需要 IV,ECB 模式不需要
|
||
`, encoding, encoding, encoding), nil
|
||
}
|
||
|
||
func (t *SM4CBCEncryptTool) Execute(ctx context.Context, params map[string]string) (string, error) {
|
||
return t.GetDetail(ctx, params)
|
||
}
|
||
|
||
// ========== SM4-ECB 加密工具 ==========
|
||
type SM4ECBEncryptTool struct{}
|
||
|
||
func (t *SM4ECBEncryptTool) Name() string { return "sm4_ecb_encrypt" }
|
||
|
||
func (t *SM4ECBEncryptTool) Description() string {
|
||
return "SM4国密对称加密(ECB模式)实现指南。⚠️ ECB模式不安全,仅用于兼容老旧系统。必须使用 github.com/tjfoc/gmsm 库,不要自己实现!"
|
||
}
|
||
|
||
func (t *SM4ECBEncryptTool) GetFunctionDefinition() openai.FunctionDefinition {
|
||
return openai.FunctionDefinition{
|
||
Name: t.Name(),
|
||
Description: t.Description(),
|
||
Parameters: jsonschema.Definition{
|
||
Type: jsonschema.Object,
|
||
Properties: map[string]jsonschema.Definition{
|
||
"encoding": {
|
||
Type: jsonschema.String,
|
||
Description: "输出编码方式,base64 或 hex,默认 base64",
|
||
Enum: []string{"base64", "hex"},
|
||
},
|
||
},
|
||
Required: []string{},
|
||
},
|
||
}
|
||
}
|
||
|
||
func (t *SM4ECBEncryptTool) GetDetail(ctx context.Context, params map[string]string) (string, error) {
|
||
encoding := "base64"
|
||
if v, ok := params["encoding"]; ok && v != "" {
|
||
encoding = v
|
||
}
|
||
|
||
return fmt.Sprintf(`
|
||
### SM4-ECB 国密对称加密完整实现指南
|
||
|
||
**⚠️ 重要提示**:ECB模式不安全,仅用于兼容老旧系统。
|
||
|
||
**⚠️ 重要:必须使用第三方库,不要自己实现 SM4 算法!**
|
||
**推荐使用:github.com/tjfoc/gmsm**
|
||
|
||
**前置要求**:
|
||
`+"```bash"+`
|
||
go get github.com/tjfoc/gmsm
|
||
`+"```"+`
|
||
|
||
**配置参数**:
|
||
- 编码方式: %s
|
||
|
||
**完整代码模板(请直接复制使用)**:
|
||
|
||
`+"```go"+`
|
||
package crypto
|
||
|
||
import (
|
||
"encoding/base64"
|
||
"encoding/hex"
|
||
"fmt"
|
||
"bytes"
|
||
|
||
"github.com/tjfoc/gmsm/sm4" // ⚠️ 必须使用此库,不要自己实现SM4
|
||
)
|
||
|
||
// SM4ECBEncrypt SM4-ECB模式加密
|
||
// 使用 github.com/tjfoc/gmsm/sm4 实现
|
||
func SM4ECBEncrypt(plaintext []byte, key []byte) (string, error) {
|
||
if len(key) != 16 {
|
||
return "", fmt.Errorf("SM4密钥长度必须为16字节")
|
||
}
|
||
|
||
block, err := sm4.NewCipher(key)
|
||
if err != nil {
|
||
return "", fmt.Errorf("创建SM4 cipher失败: %%v", err)
|
||
}
|
||
|
||
padded := pkcs7Padding(plaintext, block.BlockSize())
|
||
|
||
ciphertext := make([]byte, len(padded))
|
||
for i := 0; i < len(padded); i += block.BlockSize() {
|
||
block.Encrypt(ciphertext[i:i+block.BlockSize()], padded[i:i+block.BlockSize()])
|
||
}
|
||
|
||
if "%s" == "hex" {
|
||
return hex.EncodeToString(ciphertext), nil
|
||
}
|
||
return base64.StdEncoding.EncodeToString(ciphertext), nil
|
||
}
|
||
|
||
// SM4ECBDecrypt SM4-ECB模式解密
|
||
// 使用 github.com/tjfoc/gmsm/sm4 实现
|
||
func SM4ECBDecrypt(encryptedData string, key []byte) ([]byte, error) {
|
||
if len(key) != 16 {
|
||
return nil, fmt.Errorf("SM4密钥长度必须为16字节")
|
||
}
|
||
|
||
var ciphertext []byte
|
||
var err error
|
||
if "%s" == "hex" {
|
||
ciphertext, err = hex.DecodeString(encryptedData)
|
||
} else {
|
||
ciphertext, err = base64.StdEncoding.DecodeString(encryptedData)
|
||
}
|
||
if err != nil {
|
||
return nil, fmt.Errorf("解码失败: %%v", err)
|
||
}
|
||
|
||
block, err := sm4.NewCipher(key)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("创建SM4 cipher失败: %%v", err)
|
||
}
|
||
|
||
blockSize := block.BlockSize()
|
||
if len(ciphertext)%%blockSize != 0 {
|
||
return nil, fmt.Errorf("密文长度不是块大小的整数倍")
|
||
}
|
||
|
||
plaintext := make([]byte, len(ciphertext))
|
||
for i := 0; i < len(ciphertext); i += blockSize {
|
||
block.Decrypt(plaintext[i:i+blockSize], ciphertext[i:i+blockSize])
|
||
}
|
||
|
||
plaintext, err = pkcs7UnPadding(plaintext)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("去除填充失败: %%v", err)
|
||
}
|
||
|
||
return plaintext, nil
|
||
}
|
||
|
||
// pkcs7Padding 和 pkcs7UnPadding 函数请参考 CBC 模式实现
|
||
`+"```"+`
|
||
|
||
**⚠️ 重要提醒**:
|
||
1. **不要自己实现 SM4 算法**,请直接使用 github.com/tjfoc/gmsm
|
||
2. 这个库是国密官方推荐的 Go 实现,安全可靠
|
||
3. 在 go.mod 中添加依赖:`+"`require github.com/tjfoc/gmsm v1.4.1`"+`
|
||
|
||
**⚠️ 安全警告**:
|
||
- ECB模式不应在新系统中使用
|
||
- 仅用于兼容老旧的国密系统
|
||
- 推荐使用 SM4-CBC 模式
|
||
`, encoding, encoding, encoding), nil
|
||
}
|
||
|
||
func (t *SM4ECBEncryptTool) Execute(ctx context.Context, params map[string]string) (string, error) {
|
||
return t.GetDetail(ctx, params)
|
||
}
|