Path: blob/main/components/gitpod-db/go/encryption_test.go
2497 views
// Copyright (c) 2022 Gitpod GmbH. All rights reserved.1// Licensed under the GNU Affero General Public License (AGPL).2// See License.AGPL.txt in the project root for license information.34package db_test56import (7"crypto/rand"8"encoding/base64"9"fmt"10db "github.com/gitpod-io/gitpod/components/gitpod-db/go"11"github.com/gitpod-io/gitpod/components/gitpod-db/go/dbtest"12"github.com/stretchr/testify/require"13"testing"14)1516func TestAES256CBCCipher_Encrypt_Decrypt(t *testing.T) {17secret := "testtesttesttesttesttesttesttest"1819metadata := db.CipherMetadata{20Name: "general",21Version: 1,22}2324cipher, err := db.NewAES256CBCCipher(secret, metadata)25require.NoError(t, err)2627data := []byte(`{ "foo": "bar", "another": "one" }`)2829encrypted, err := cipher.Encrypt(data)30require.NoError(t, err)3132iv, err := base64.StdEncoding.DecodeString(encrypted.Params.InitializationVector)33require.NoError(t, err, "initialization vector must be stored as base64")34require.NotEmpty(t, iv, "initialization vector must not be empty")3536decodedCipherText, err := base64.StdEncoding.DecodeString(encrypted.EncodedData)37require.NoError(t, err, "encrypted data must be base64 encoded")38require.NotEmpty(t, decodedCipherText, "decoded cipher text must not be emtpy")3940require.Equal(t, metadata, encrypted.Metadata)41require.NotEmpty(t, encrypted.Params.InitializationVector)4243decrypted, err := cipher.Decrypt(encrypted)44require.NoError(t, err)45require.Equal(t, data, decrypted)46}4748func TestAES256CBCCipher_EncryptedByServer(t *testing.T) {49cipher, metadata := dbtest.GetTestCipher(t)50encrypted := db.EncryptedData{51EncodedData: "YpgOY8ZNV64oG1DXiuCUXKy0thVySbN7uXTQxtC2j2A=",52Params: db.KeyParams{53InitializationVector: "vpTOAFN5v4kOPsAHBKk+eg==",54},55Metadata: metadata,56}5758decrypted, err := cipher.Decrypt(encrypted)59fmt.Println(err)60require.NoError(t, err)61require.Equal(t, "12345678901234567890", string(decrypted))62}6364func TestCipherSet(t *testing.T) {65t.Run("errors when no config specified", func(t *testing.T) {66_, err := db.NewCipherSet(nil)67require.Error(t, err)68})6970t.Run("errors when no primary configs", func(t *testing.T) {71_, err := db.NewCipherSet([]db.CipherConfig{72{73Name: "first",74Version: 0,75Primary: false,76Material: "something",77},78{79Name: "second",80Version: 0,81Primary: false,82Material: "something else",83},84})85require.Error(t, err)86})8788t.Run("errors when multiple primary configs", func(t *testing.T) {89_, err := db.NewCipherSet([]db.CipherConfig{90{91Name: "first",92Version: 0,93Primary: true,94Material: "something",95},96{97Name: "second",98Version: 0,99Primary: true,100Material: "something else",101},102})103require.Error(t, err)104})105106t.Run("uses primary to encrypt", func(t *testing.T) {107cipherset, err := db.NewCipherSet([]db.CipherConfig{108{109Name: "first",110Version: 1,111Primary: true,112Material: base64.StdEncoding.EncodeToString(generateSecret(t, 32)),113},114{115Name: "second",116Version: 0,117Primary: false,118Material: base64.StdEncoding.EncodeToString(generateSecret(t, 32)),119},120})121require.NoError(t, err)122123data := []byte(`random`)124encrypted, err := cipherset.Encrypt(data)125require.NoError(t, err)126require.Equal(t, "first", encrypted.Metadata.Name)127require.Equal(t, 1, encrypted.Metadata.Version)128})129130t.Run("uses all to decrypt", func(t *testing.T) {131data := []byte(`random`)132133// Construct a cipher, and encrypt some data. This serves as an "old" encrypted piece134secret := generateSecret(t, 32)135metadata := db.CipherMetadata{136Name: "second",137Version: 0,138}139oldCipher, err := db.NewAES256CBCCipher(string(secret), metadata)140require.NoError(t, err)141142encrypted, err := oldCipher.Encrypt(data)143require.NoError(t, err)144145cipherset, err := db.NewCipherSet([]db.CipherConfig{146{147Name: "first",148Version: 0,149Primary: true,150Material: base64.StdEncoding.EncodeToString(generateSecret(t, 32)),151},152{153Name: metadata.Name,154Version: metadata.Version,155Primary: false,156Material: base64.StdEncoding.EncodeToString(secret),157},158})159require.NoError(t, err)160161decrypted, err := cipherset.Decrypt(encrypted)162require.NoError(t, err)163require.Equal(t, string(data), string(decrypted))164})165166t.Run("no matching metadata returns an error when decrypting", func(t *testing.T) {167encrypted := db.EncryptedData{168EncodedData: "foobar",169Params: db.KeyParams{},170Metadata: db.CipherMetadata{171Name: "non-existent",172Version: 0,173},174}175176cipherset := dbtest.CipherSet(t)177_, err := cipherset.Decrypt(encrypted)178require.Error(t, err)179})180181}182183func generateSecret(t *testing.T, size int) []byte {184t.Helper()185186b := make([]byte, size)187_, err := rand.Read(b)188require.NoError(t, err)189190return b191}192193194