sdk_generate/internal/prompts/tools/crypt/sm4.go

338 lines
9.3 KiB
Go
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

// 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 模式需要 IVECB 模式不需要
`, 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)
}