Files
537yaha 109e927152 v1.0.0
2025-12-02 20:03:39 +08:00

119 lines
3.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
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.
package utils
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"errors"
"fmt"
"io"
"os"
)
// 获取加密密钥(优先从环境变量读取,否则使用默认值)
// 重要说明:
// 1. 这个密钥是固定的,用于加密/解密所有 API Key
// 2. API Key 的长度可以不同,但都用同一个加密密钥加密
// 3. 如果改变这个密钥,之前加密的 API Key 将无法解密
// 4. 生产环境必须从环境变量 ENCRYPTION_KEY 读取
// AES-256 需要 32 字节的密钥
func getEncryptionKey() []byte {
key := os.Getenv("ENCRYPTION_KEY")
if key != "" && len(key) == 32 {
return []byte(key)
}
// 默认密钥(仅用于开发环境,生产环境必须设置 ENCRYPTION_KEY
return []byte("abcdefghijklmnopqrstuvwxyz123456") // 32 bytes for AES-256
}
// EncryptAPIKey 加密 API Key
// 参数:
// - plaintext: 用户输入的 API Key(长度可变,不同服务商不同)
//
// 返回:
// - 加密后的字符串(base64 编码)
//
// 说明:
// - 无论 API Key 多长,都用同一个固定的 encryptionKey 加密
// - 加密密钥(encryptionKey)是固定的,不会因为 API Key 长度变化而改变
func EncryptAPIKey(plaintext string) (string, error) {
// 验证输入
if plaintext == "" {
return "", errors.New("API Key 不能为空")
}
// 获取加密密钥(优先从环境变量读取)
key := getEncryptionKey()
if len(key) != 32 {
return "", errors.New("加密密钥长度必须为 32 字节")
}
// 创建 AES cipher
block, err := aes.NewCipher(key)
if err != nil {
return "", fmt.Errorf("创建加密器失败: %v", err)
}
// 创建 GCMGalois/Counter Mode
gcm, err := cipher.NewGCM(block)
if err != nil {
return "", fmt.Errorf("创建 GCM 失败: %v", err)
}
// 生成随机 nonce
nonce := make([]byte, gcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return "", fmt.Errorf("生成随机数失败: %v", err)
}
// 加密数据
ciphertext := gcm.Seal(nonce, nonce, []byte(plaintext), nil)
// 返回 base64 编码的密文
return base64.StdEncoding.EncodeToString(ciphertext), nil
}
// DecryptAPIKey 解密 API Key
func DecryptAPIKey(ciphertext string) (string, error) {
// 获取加密密钥(优先从环境变量读取)
key := getEncryptionKey()
if len(key) != 32 {
return "", errors.New("加密密钥长度必须为 32 字节")
}
// 解码 base64
data, err := base64.StdEncoding.DecodeString(ciphertext)
if err != nil {
return "", err
}
// 创建 AES cipher
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
// 创建 GCM
gcm, err := cipher.NewGCM(block)
if err != nil {
return "", err
}
// 检查数据长度
if len(data) < gcm.NonceSize() {
return "", errors.New("ciphertext too short")
}
// 提取 nonce 和密文
nonce, ciphertextBytes := data[:gcm.NonceSize()], data[gcm.NonceSize():]
// 解密数据
plaintext, err := gcm.Open(nil, nonce, ciphertextBytes, nil)
if err != nil {
return "", err
}
return string(plaintext), nil
}