// Package secret encrypts provider credentials at rest using an environment-owned key. package secret import ( "crypto/aes" "crypto/cipher" "crypto/rand" "encoding/base64" "fmt" "git.sundynix.cn/Blizzard/Veyra/internal/apperror" ) type Vault struct{ aead cipher.AEAD } func NewVault(encodedKey string) (*Vault, error) { if encodedKey == "" { return &Vault{}, nil } key, err := base64.StdEncoding.DecodeString(encodedKey) if err != nil || len(key) != 32 { return nil, fmt.Errorf("SECRET_ENCRYPTION_KEY must be base64 of 32 bytes") } block, err := aes.NewCipher(key) if err != nil { return nil, fmt.Errorf("initialize secret cipher") } aead, err := cipher.NewGCM(block) if err != nil { return nil, fmt.Errorf("initialize secret encryption") } return &Vault{aead: aead}, nil } func (v *Vault) Encrypt(value, binding string) ([]byte, error) { if v == nil || v.aead == nil { return nil, apperror.ErrUnavailable } nonce := make([]byte, v.aead.NonceSize()) if _, err := rand.Read(nonce); err != nil { return nil, apperror.ErrUnavailable } return v.aead.Seal(nonce, nonce, []byte(value), []byte(binding)), nil } func (v *Vault) Decrypt(encrypted []byte, binding string) (string, error) { if len(encrypted) == 0 { return "", nil } if v == nil || v.aead == nil || len(encrypted) < v.aead.NonceSize() { return "", apperror.ErrUnavailable } value, err := v.aead.Open(nil, encrypted[:v.aead.NonceSize()], encrypted[v.aead.NonceSize():], []byte(binding)) if err != nil { return "", apperror.ErrUnavailable } return string(value), nil }