package service import ( "crypto/aes" "crypto/cipher" "crypto/rand" "crypto/sha256" "encoding/base64" "errors" "io" ) // SecretCodec 使用应用主密钥加密落库的第三方密钥,避免明文存储。 type SecretCodec struct { gcm cipher.AEAD } func NewSecretCodec(masterKey string) (*SecretCodec, error) { if masterKey == "" { return nil, errors.New("数据加密主密钥不能为空") } sum := sha256.Sum256([]byte(masterKey)) block, err := aes.NewCipher(sum[:]) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } return &SecretCodec{gcm: gcm}, nil } func (c *SecretCodec) Encrypt(plain string) (string, error) { nonce := make([]byte, c.gcm.NonceSize()) if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return "", err } sealed := c.gcm.Seal(nil, nonce, []byte(plain), nil) return base64.RawURLEncoding.EncodeToString(append(nonce, sealed...)), nil } func (c *SecretCodec) Decrypt(ciphertext string) (string, error) { raw, err := base64.RawURLEncoding.DecodeString(ciphertext) if err != nil { return "", errors.New("密钥密文格式错误") } if len(raw) < c.gcm.NonceSize() { return "", errors.New("密钥密文长度错误") } plain, err := c.gcm.Open(nil, raw[:c.gcm.NonceSize()], raw[c.gcm.NonceSize():], nil) if err != nil { return "", errors.New("密钥解密失败") } return string(plain), nil }