| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- package crypto
-
- import (
- "crypto/aes"
- "crypto/cipher"
- "crypto/rand"
- "encoding/base64"
- "errors"
- "fmt"
- "io"
- "strings"
- )
-
- // CryptoService 加密服务结构体
- type CryptoService struct {
- key []byte
- prefix string // 加密文本前缀,用于识别是否已加密
- }
-
- // NewCryptoService 创建加密服务
- func NewCryptoService(key string) (*CryptoService, error) {
- keyBytes := []byte(key)
-
- // 如果密钥长度不足,使用PBKDF2派生密钥
- if len(keyBytes) < 32 {
- derivedKey, err := deriveKey(keyBytes, 32)
- if err != nil {
- return nil, err
- }
- keyBytes = derivedKey
- } else if len(keyBytes) > 32 {
- keyBytes = keyBytes[:32] // 截取前32字节
- }
-
- return &CryptoService{
- key: keyBytes,
- prefix: "ENC::", // 加密文本前缀
- }, nil
- }
-
- // deriveKey 使用PBKDF2派生密钥
- func deriveKey(password []byte, keyLen int) ([]byte, error) {
- // 这里简化实现,实际应该使用crypto/sha256和更复杂的盐
- // 为了简单示例,使用固定盐(生产环境应该使用随机盐)
- salt := []byte("fixed-salt-for-demo")
-
- hash := make([]byte, keyLen)
- for i := 0; i < keyLen; i++ {
- if i < len(password) {
- hash[i] = password[i] ^ salt[i%len(salt)]
- } else {
- hash[i] = salt[i%len(salt)]
- }
- }
- return hash, nil
- }
-
- // Encrypt 加密文本
- func (cs *CryptoService) Encrypt(plaintext string) (string, error) {
- // 如果已经是加密文本,直接返回
- if cs.IsEncrypted(plaintext) {
- return plaintext, nil
- }
-
- block, err := aes.NewCipher(cs.key)
- if err != nil {
- return "", fmt.Errorf("创建密码块失败: %w", err)
- }
-
- gcm, err := cipher.NewGCM(block)
- if err != nil {
- return "", fmt.Errorf("创建GCM模式失败: %w", err)
- }
-
- nonce := make([]byte, gcm.NonceSize())
- if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
- return "", fmt.Errorf("生成随机数失败: %w", err)
- }
-
- ciphertext := gcm.Seal(nonce, nonce, []byte(plaintext), nil)
- encoded := base64.StdEncoding.EncodeToString(ciphertext)
-
- // 添加前缀标识
- return cs.prefix + encoded, nil
- }
-
- // Decrypt 解密文本
- func (cs *CryptoService) Decrypt(input string) (string, error) {
- // 如果不是加密文本,直接返回原文本
- if !cs.IsEncrypted(input) {
- return input, nil
- }
-
- // 移除前缀
- encoded := strings.TrimPrefix(input, cs.prefix)
-
- ciphertext, err := base64.StdEncoding.DecodeString(encoded)
- if err != nil {
- // 如果不是有效的Base64,返回原文本
- return input, nil
- }
-
- block, err := aes.NewCipher(cs.key)
- if err != nil {
- return "", fmt.Errorf("创建密码块失败: %w", err)
- }
-
- gcm, err := cipher.NewGCM(block)
- if err != nil {
- return "", fmt.Errorf("创建GCM模式失败: %w", err)
- }
-
- if len(ciphertext) < gcm.NonceSize() {
- return "", errors.New("密文太短")
- }
-
- nonce, ciphertext := ciphertext[:gcm.NonceSize()], ciphertext[gcm.NonceSize():]
-
- plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
- if err != nil {
- // 如果解密失败,返回原文本(可能是格式相似但不是真正的加密文本)
- return input, nil
- }
-
- return string(plaintext), nil
- }
-
- // IsEncrypted 检查文本是否已加密
- func (cs *CryptoService) IsEncrypted(text string) bool {
- return strings.HasPrefix(text, cs.prefix)
- }
-
- // EncryptOrDecrypt 智能加密或解密
- // 如果输入是明文则加密,如果已是密文则解密
- func (cs *CryptoService) EncryptOrDecrypt(input string) (string, error) {
- if cs.IsEncrypted(input) {
- return cs.Decrypt(input)
- }
- return cs.Encrypt(input)
- }
-
- // EncryptIfNeeded 如果需要则加密
- func (cs *CryptoService) EncryptIfNeeded(input string) (string, error) {
- if cs.IsEncrypted(input) {
- return input, nil
- }
- return cs.Encrypt(input)
- }
-
- // DecryptIfNeeded 如果需要则解密
- func (cs *CryptoService) DecryptIfNeeded(input string) (string, error) {
- if cs.IsEncrypted(input) {
- return cs.Decrypt(input)
- }
- return input, nil
- }
|