package paymentconfig import ( "crypto/aes" "crypto/cipher" "crypto/rand" "encoding/base64" "errors" "io" ) // Encryptor 密钥加密器接口 type Encryptor interface { Encrypt(plaintext string) (string, error) Decrypt(ciphertext string) (string, error) } // AESEncryptor AES 加密器 type AESEncryptor struct { key []byte } // NewAESEncryptor 创建 AES 加密器 // key 必须是 16、24 或 32 字节(对应 AES-128、AES-192、AES-256) func NewAESEncryptor(key string) (*AESEncryptor, error) { keyBytes := []byte(key) if len(keyBytes) != 16 && len(keyBytes) != 24 && len(keyBytes) != 32 { return nil, errors.New("invalid key length: must be 16, 24, or 32 bytes") } return &AESEncryptor{key: keyBytes}, nil } // Encrypt 加密明文(使用 AES-GCM) func (e *AESEncryptor) Encrypt(plaintext string) (string, error) { if plaintext == "" { return "", nil } block, err := aes.NewCipher(e.key) if err != nil { return "", err } gcm, err := cipher.NewGCM(block) if err != nil { return "", err } nonce := make([]byte, gcm.NonceSize()) if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return "", err } ciphertext := gcm.Seal(nonce, nonce, []byte(plaintext), nil) return base64.StdEncoding.EncodeToString(ciphertext), nil } // Decrypt 解密密文(使用 AES-GCM) func (e *AESEncryptor) Decrypt(ciphertext string) (string, error) { if ciphertext == "" { return "", nil } ciphertextBytes, err := base64.StdEncoding.DecodeString(ciphertext) if err != nil { return "", err } block, err := aes.NewCipher(e.key) if err != nil { return "", err } gcm, err := cipher.NewGCM(block) if err != nil { return "", err } nonceSize := gcm.NonceSize() if len(ciphertextBytes) < nonceSize { return "", errors.New("ciphertext too short") } nonce, ciphertextBytes := ciphertextBytes[:nonceSize], ciphertextBytes[nonceSize:] plaintext, err := gcm.Open(nil, nonce, ciphertextBytes, nil) if err != nil { return "", err } return string(plaintext), nil } // MockEncryptor 模拟加密器(用于测试) type MockEncryptor struct{} func (e *MockEncryptor) Encrypt(plaintext string) (string, error) { return plaintext, nil } func (e *MockEncryptor) Decrypt(ciphertext string) (string, error) { return ciphertext, nil }