k8s.io/apiserver@v0.31.1/pkg/storage/value/encrypt/secretbox/secretbox_test.go (about)

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package secretbox
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"crypto/rand"
    23  	"encoding/hex"
    24  	"fmt"
    25  	"io"
    26  	"reflect"
    27  	"testing"
    28  
    29  	"k8s.io/apiserver/pkg/storage/value"
    30  )
    31  
    32  var (
    33  	key1 = [32]byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}
    34  	key2 = [32]byte{0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}
    35  )
    36  
    37  func TestSecretboxKeyRotation(t *testing.T) {
    38  	testErr := fmt.Errorf("test error")
    39  	ctx := context.Background()
    40  	dataCtx := value.DefaultContext([]byte("authenticated_data"))
    41  
    42  	p := value.NewPrefixTransformers(testErr,
    43  		value.PrefixTransformer{Prefix: []byte("first:"), Transformer: NewSecretboxTransformer(key1)},
    44  		value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewSecretboxTransformer(key2)},
    45  	)
    46  	out, err := p.TransformToStorage(ctx, []byte("firstvalue"), dataCtx)
    47  	if err != nil {
    48  		t.Fatal(err)
    49  	}
    50  	if !bytes.HasPrefix(out, []byte("first:")) {
    51  		t.Fatalf("unexpected prefix: %q", out)
    52  	}
    53  	from, stale, err := p.TransformFromStorage(ctx, out, dataCtx)
    54  	if err != nil {
    55  		t.Fatal(err)
    56  	}
    57  	if stale || !bytes.Equal([]byte("firstvalue"), from) {
    58  		t.Fatalf("unexpected data: %t %q", stale, from)
    59  	}
    60  
    61  	// verify changing the context does not fails storage
    62  	// Secretbox is not currently an authenticating store
    63  	_, _, err = p.TransformFromStorage(ctx, out, value.DefaultContext([]byte("incorrect_context")))
    64  	if err != nil {
    65  		t.Fatalf("secretbox is not authenticated")
    66  	}
    67  
    68  	// reverse the order, use the second key
    69  	p = value.NewPrefixTransformers(testErr,
    70  		value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewSecretboxTransformer(key2)},
    71  		value.PrefixTransformer{Prefix: []byte("first:"), Transformer: NewSecretboxTransformer(key1)},
    72  	)
    73  	from, stale, err = p.TransformFromStorage(ctx, out, dataCtx)
    74  	if err != nil {
    75  		t.Fatal(err)
    76  	}
    77  	if !stale || !bytes.Equal([]byte("firstvalue"), from) {
    78  		t.Fatalf("unexpected data: %t %q", stale, from)
    79  	}
    80  }
    81  
    82  func BenchmarkSecretboxRead(b *testing.B) {
    83  	tests := []struct {
    84  		keyLength   int
    85  		valueLength int
    86  		expectStale bool
    87  	}{
    88  		{keyLength: 32, valueLength: 1024, expectStale: false},
    89  		{keyLength: 32, valueLength: 16384, expectStale: false},
    90  		{keyLength: 32, valueLength: 16384, expectStale: true},
    91  	}
    92  	for _, t := range tests {
    93  		name := fmt.Sprintf("%vKeyLength/%vValueLength/%vExpectStale", t.keyLength, t.valueLength, t.expectStale)
    94  		b.Run(name, func(b *testing.B) {
    95  			benchmarkSecretboxRead(b, t.keyLength, t.valueLength, t.expectStale)
    96  		})
    97  	}
    98  }
    99  
   100  func BenchmarkSecretboxWrite(b *testing.B) {
   101  	tests := []struct {
   102  		keyLength   int
   103  		valueLength int
   104  	}{
   105  		{keyLength: 32, valueLength: 1024},
   106  		{keyLength: 32, valueLength: 16384},
   107  	}
   108  	for _, t := range tests {
   109  		name := fmt.Sprintf("%vKeyLength/%vValueLength", t.keyLength, t.valueLength)
   110  		b.Run(name, func(b *testing.B) {
   111  			benchmarkSecretboxWrite(b, t.keyLength, t.valueLength)
   112  		})
   113  	}
   114  }
   115  
   116  func benchmarkSecretboxRead(b *testing.B, keyLength int, valueLength int, expectStale bool) {
   117  	p := value.NewPrefixTransformers(nil,
   118  		value.PrefixTransformer{Prefix: []byte("first:"), Transformer: NewSecretboxTransformer(key1)},
   119  		value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewSecretboxTransformer(key2)},
   120  	)
   121  
   122  	ctx := context.Background()
   123  	dataCtx := value.DefaultContext([]byte("authenticated_data"))
   124  	v := bytes.Repeat([]byte("0123456789abcdef"), valueLength/16)
   125  
   126  	out, err := p.TransformToStorage(ctx, v, dataCtx)
   127  	if err != nil {
   128  		b.Fatal(err)
   129  	}
   130  	// reverse the key order if expecting stale
   131  	if expectStale {
   132  		p = value.NewPrefixTransformers(nil,
   133  			value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewSecretboxTransformer(key2)},
   134  			value.PrefixTransformer{Prefix: []byte("first:"), Transformer: NewSecretboxTransformer(key1)},
   135  		)
   136  	}
   137  
   138  	b.ResetTimer()
   139  	for i := 0; i < b.N; i++ {
   140  		from, stale, err := p.TransformFromStorage(ctx, out, dataCtx)
   141  		if err != nil {
   142  			b.Fatal(err)
   143  		}
   144  		if expectStale != stale {
   145  			b.Fatalf("unexpected data: %q, expect stale %t but got %t", from, expectStale, stale)
   146  		}
   147  	}
   148  	b.StopTimer()
   149  }
   150  
   151  func benchmarkSecretboxWrite(b *testing.B, keyLength int, valueLength int) {
   152  	p := value.NewPrefixTransformers(nil,
   153  		value.PrefixTransformer{Prefix: []byte("first:"), Transformer: NewSecretboxTransformer(key1)},
   154  		value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewSecretboxTransformer(key2)},
   155  	)
   156  
   157  	ctx := context.Background()
   158  	dataCtx := value.DefaultContext([]byte("authenticated_data"))
   159  	v := bytes.Repeat([]byte("0123456789abcdef"), valueLength/16)
   160  
   161  	b.ResetTimer()
   162  	for i := 0; i < b.N; i++ {
   163  		_, err := p.TransformToStorage(ctx, v, dataCtx)
   164  		if err != nil {
   165  			b.Fatal(err)
   166  		}
   167  	}
   168  	b.StopTimer()
   169  }
   170  
   171  func TestRoundTrip(t *testing.T) {
   172  	lengths := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 128, 1024}
   173  
   174  	ctx := context.Background()
   175  	tests := []struct {
   176  		name    string
   177  		dataCtx value.Context
   178  		t       value.Transformer
   179  	}{
   180  		{name: "Secretbox 32 byte key", t: NewSecretboxTransformer(key1)},
   181  	}
   182  	for _, tt := range tests {
   183  		t.Run(tt.name, func(t *testing.T) {
   184  			dataCtx := tt.dataCtx
   185  			if dataCtx == nil {
   186  				dataCtx = value.DefaultContext([]byte(""))
   187  			}
   188  			for _, l := range lengths {
   189  				data := make([]byte, l)
   190  				if _, err := io.ReadFull(rand.Reader, data); err != nil {
   191  					t.Fatalf("unable to read sufficient random bytes: %v", err)
   192  				}
   193  				original := append([]byte{}, data...)
   194  
   195  				ciphertext, err := tt.t.TransformToStorage(ctx, data, dataCtx)
   196  				if err != nil {
   197  					t.Errorf("TransformToStorage error = %v", err)
   198  					continue
   199  				}
   200  
   201  				result, stale, err := tt.t.TransformFromStorage(ctx, ciphertext, dataCtx)
   202  				if err != nil {
   203  					t.Errorf("TransformFromStorage error = %v", err)
   204  					continue
   205  				}
   206  				if stale {
   207  					t.Errorf("unexpected stale output")
   208  					continue
   209  				}
   210  
   211  				switch {
   212  				case l == 0:
   213  					if len(result) != 0 {
   214  						t.Errorf("Round trip failed len=%d\noriginal:\n%s\nresult:\n%s", l, hex.Dump(original), hex.Dump(result))
   215  					}
   216  				case !reflect.DeepEqual(original, result):
   217  					t.Errorf("Round trip failed len=%d\noriginal:\n%s\nresult:\n%s", l, hex.Dump(original), hex.Dump(result))
   218  				}
   219  			}
   220  		})
   221  	}
   222  }