package secrets import ( "crypto/aes" "crypto/cipher" "crypto/rand" "encoding/base64" "io" "log/slog" ) type Secrets struct { Logger *slog.Logger EncryptionKey []byte } func New(logger *slog.Logger, key []byte) *Secrets { return &Secrets{ Logger: logger, EncryptionKey: key, } } // Encrypt function that encrypts data using AES256-GCM and returns base64 encoded ciphertext func (s *Secrets) Encrypt(plainText []byte) (string, error) { block, err := aes.NewCipher(s.EncryptionKey) if err != nil { return "", err } // Create a new GCM cipher gcm, err := cipher.NewGCM(block) if err != nil { return "", err } // Create a nonce nonce := make([]byte, gcm.NonceSize()) if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return "", err } // Encrypt the plaintext using AES256-GCM cipherText := gcm.Seal(nonce, nonce, plainText, nil) // Return the base64 encoded ciphertext return base64.StdEncoding.EncodeToString(cipherText), nil } // Decrypt function that decrypts base64 encoded AES256-GCM ciphertext func (s *Secrets) Decrypt(base64CipherText string) ([]byte, error) { // Decode the base64 ciphertext cipherText, err := base64.StdEncoding.DecodeString(base64CipherText) if err != nil { return nil, err } block, err := aes.NewCipher(s.EncryptionKey) if err != nil { return nil, err } // Create a new GCM cipher gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } // Extract the nonce from the ciphertext nonceSize := gcm.NonceSize() nonce, cipherText := cipherText[:nonceSize], cipherText[nonceSize:] // Decrypt the ciphertext plainText, err := gcm.Open(nil, nonce, cipherText, nil) if err != nil { return nil, err } return plainText, nil }