package provider import ( "context" "crypto/aes" "crypto/cipher" "crypto/rand" "io" "github.com/grafana/grafana/pkg/services/encryption" "github.com/grafana/grafana/pkg/util" ) type aesCfbCipher struct{} func (c aesCfbCipher) Encrypt(_ context.Context, payload []byte, secret string) ([]byte, error) { salt, err := util.GetRandomString(encryption.SaltLength) if err != nil { return nil, err } key, err := encryption.KeyToBytes(secret, salt) if err != nil { return nil, err } block, err := aes.NewCipher(key) if err != nil { return nil, err } // The IV needs to be unique, but not secure. Therefore, it's common to // include it at the beginning of the ciphertext. ciphertext := make([]byte, encryption.SaltLength+aes.BlockSize+len(payload)) copy(ciphertext[:encryption.SaltLength], salt) iv := ciphertext[encryption.SaltLength : encryption.SaltLength+aes.BlockSize] if _, err := io.ReadFull(rand.Reader, iv); err != nil { return nil, err } //nolint:staticcheck stream := cipher.NewCFBEncrypter(block, iv) stream.XORKeyStream(ciphertext[encryption.SaltLength+aes.BlockSize:], payload) return ciphertext, nil }