github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ccl/storageccl/encryption_test.go (about)

     1  // Copyright 2020 The Cockroach Authors.
     2  //
     3  // Licensed as a CockroachDB Enterprise file under the Cockroach Community
     4  // License (the "License"); you may not use this file except in compliance with
     5  // the License. You may obtain a copy of the License at
     6  //
     7  //     https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt
     8  
     9  package storageccl
    10  
    11  import (
    12  	"bytes"
    13  	"testing"
    14  
    15  	"github.com/cockroachdb/cockroach/pkg/util/humanizeutil"
    16  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  func TestEncryptDecrypt(t *testing.T) {
    21  	defer leaktest.AfterTest(t)()
    22  
    23  	plaintext := bytes.Repeat([]byte("hello world\n"), 3)
    24  	passphrase := []byte("this is a a key")
    25  	salt, err := GenerateSalt()
    26  	if err != nil {
    27  		t.Fatal(err)
    28  	}
    29  	key := GenerateKey(passphrase, salt)
    30  
    31  	t.Run("EncryptFile+DecryptFile", func(t *testing.T) {
    32  		ciphertext, err := EncryptFile(plaintext, key)
    33  		require.NoError(t, err)
    34  		require.True(t, AppearsEncrypted(ciphertext), "cipher text should appear encrypted")
    35  
    36  		decrypted, err := DecryptFile(ciphertext, key)
    37  		require.NoError(t, err)
    38  		require.Equal(t, plaintext, decrypted)
    39  	})
    40  
    41  	t.Run("helpful error on bad input", func(t *testing.T) {
    42  
    43  		_, err := DecryptFile([]byte("a"), key)
    44  		require.EqualError(t, err, "file does not appear to be encrypted")
    45  	})
    46  }
    47  
    48  func BenchmarkEncryption(b *testing.B) {
    49  	plaintext1KB := bytes.Repeat([]byte("0123456789abcdef"), 64)
    50  	plaintext100KB := bytes.Repeat(plaintext1KB, 100)
    51  	plaintext1MB := bytes.Repeat(plaintext1KB, 1024)
    52  
    53  	passphrase := []byte("this is a a key")
    54  	salt, err := GenerateSalt()
    55  	require.NoError(b, err)
    56  	key := GenerateKey(passphrase, salt)
    57  
    58  	ciphertext1KB, err := EncryptFile(plaintext1KB, key)
    59  	require.NoError(b, err)
    60  	ciphertext100KB, err := EncryptFile(plaintext100KB, key)
    61  	require.NoError(b, err)
    62  	ciphertext1MB, err := EncryptFile(plaintext1MB, key)
    63  	require.NoError(b, err)
    64  
    65  	b.ResetTimer()
    66  
    67  	b.Run("EncryptFile", func(b *testing.B) {
    68  		for _, plaintext := range [][]byte{plaintext1KB, plaintext100KB, plaintext1MB} {
    69  			b.Run(humanizeutil.IBytes(int64(len(plaintext))), func(b *testing.B) {
    70  				for i := 0; i < b.N; i++ {
    71  					_, err := EncryptFile(plaintext, key)
    72  					if err != nil {
    73  						b.Fatal(err)
    74  					}
    75  				}
    76  				b.SetBytes(int64(len(plaintext)))
    77  			})
    78  		}
    79  	})
    80  
    81  	b.Run("DecryptFile", func(b *testing.B) {
    82  		for _, ciphertextOriginal := range [][]byte{ciphertext1KB, ciphertext100KB, ciphertext1MB} {
    83  			// Decrypt reuses/clobbers the original ciphertext slice.
    84  			ciphertext := make([]byte, len(ciphertextOriginal))
    85  			b.Run(humanizeutil.IBytes(int64(len(ciphertext))), func(b *testing.B) {
    86  				for i := 0; i < b.N; i++ {
    87  					copy(ciphertext, ciphertextOriginal)
    88  					_, err := DecryptFile(ciphertext, key)
    89  					if err != nil {
    90  						b.Fatal(err)
    91  					}
    92  				}
    93  				b.SetBytes(int64(len(ciphertext)))
    94  			})
    95  		}
    96  	})
    97  
    98  	// If each file written or read also requires key derivation it is much more
    99  	// expensive.
   100  	b.Run("DeriveAndEncrypt", func(b *testing.B) {
   101  		for _, plaintext := range [][]byte{plaintext1KB, plaintext100KB, plaintext1MB} {
   102  			b.Run(humanizeutil.IBytes(int64(len(plaintext))), func(b *testing.B) {
   103  				for i := 0; i < b.N; i++ {
   104  					derived := GenerateKey(passphrase, salt)
   105  					_, err := EncryptFile(plaintext, derived)
   106  					if err != nil {
   107  						b.Fatal(err)
   108  					}
   109  				}
   110  				b.SetBytes(int64(len(plaintext)))
   111  			})
   112  		}
   113  	})
   114  
   115  	b.Run("DeriveAndDecrypt", func(b *testing.B) {
   116  		for _, ciphertextOriginal := range [][]byte{ciphertext1KB, ciphertext100KB, ciphertext1MB} {
   117  			// Decrypt reuses/clobbers the original ciphertext slice.
   118  			ciphertext := make([]byte, len(ciphertextOriginal))
   119  			b.Run(humanizeutil.IBytes(int64(len(ciphertext))), func(b *testing.B) {
   120  				for i := 0; i < b.N; i++ {
   121  					copy(ciphertext, ciphertextOriginal)
   122  					derived := GenerateKey(passphrase, salt)
   123  					_, err := DecryptFile(ciphertext, derived)
   124  					if err != nil {
   125  						b.Fatal(err)
   126  					}
   127  				}
   128  				b.SetBytes(int64(len(ciphertext)))
   129  			})
   130  		}
   131  	})
   132  }