github.com/zntrio/harp/v2@v2.0.9/pkg/container/seal/v2/seal_test.go (about)

     1  // Licensed to Elasticsearch B.V. under one or more contributor
     2  // license agreements. See the NOTICE file distributed with
     3  // this work for additional information regarding copyright
     4  // ownership. Elasticsearch B.V. licenses this file to you under
     5  // the Apache License, Version 2.0 (the "License"); you may
     6  // not use this file except in compliance with the License.
     7  // You may obtain a copy of the License at
     8  //
     9  //	http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing,
    12  // software distributed under the License is distributed on an
    13  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    14  // KIND, either express or implied.  See the License for the
    15  // specific language governing permissions and limitations
    16  // under the License.
    17  package v2
    18  
    19  import (
    20  	"crypto/rand"
    21  	"testing"
    22  
    23  	"github.com/awnumar/memguard"
    24  	"github.com/google/go-cmp/cmp"
    25  	"github.com/google/go-cmp/cmp/cmpopts"
    26  	fuzz "github.com/google/gofuzz"
    27  	"github.com/stretchr/testify/assert"
    28  
    29  	containerv1 "github.com/zntrio/harp/v2/api/gen/go/harp/container/v1"
    30  )
    31  
    32  var (
    33  	opt = cmp.FilterPath(
    34  		func(p cmp.Path) bool {
    35  			// Remove ignoring of the fields below once go-cmp is able to ignore generated fields.
    36  			// See https://github.com/google/go-cmp/issues/153
    37  			ignoreXXXCache :=
    38  				p.String() == "XXX_sizecache" ||
    39  					p.String() == "Headers.XXX_sizecache"
    40  			return ignoreXXXCache
    41  		}, cmp.Ignore())
    42  
    43  	ignoreOpts = []cmp.Option{
    44  		cmpopts.IgnoreUnexported(containerv1.Container{}),
    45  		cmpopts.IgnoreUnexported(containerv1.Header{}),
    46  		opt,
    47  	}
    48  )
    49  
    50  // -----------------------------------------------------------------------------
    51  
    52  func TestSeal(t *testing.T) {
    53  	type args struct {
    54  		container      *containerv1.Container
    55  		peersPublicKey []string
    56  	}
    57  	tests := []struct {
    58  		name    string
    59  		args    args
    60  		want    *containerv1.Container
    61  		wantErr bool
    62  	}{
    63  		{
    64  			name:    "nil",
    65  			wantErr: true,
    66  		},
    67  		{
    68  			name: "empty container",
    69  			args: args{
    70  				container: &containerv1.Container{},
    71  			},
    72  			wantErr: true,
    73  		},
    74  		{
    75  			name: "empty container headers",
    76  			args: args{
    77  				container: &containerv1.Container{
    78  					Headers: &containerv1.Header{},
    79  				},
    80  			},
    81  			wantErr: true,
    82  		},
    83  		// ---------------------------------------------------------------------
    84  		{
    85  			name: "valid",
    86  			args: args{
    87  				container: &containerv1.Container{
    88  					Headers: &containerv1.Header{},
    89  					Raw:     []byte{0x01, 0x02, 0x03, 0x04},
    90  				},
    91  				peersPublicKey: []string{
    92  					"v2.sk.AuSjVpMZben6n9fXiaDj8bMjSvhcZ9n7c82VOt7v9_UBzZJaMLamkQUFAVp_9frpAg",
    93  					"v2.sk.A0V1xCxGNtVAE9EVhaKi-pIADhd1in8xV_FI5Y0oHSHLAkew9gDAqiALSd6VgvBCbQ",
    94  				},
    95  			},
    96  			wantErr: false,
    97  		},
    98  	}
    99  	for _, tt := range tests {
   100  		t.Run(tt.name, func(t *testing.T) {
   101  			adapter := New()
   102  			_, err := adapter.Seal(rand.Reader, tt.args.container, tt.args.peersPublicKey...)
   103  			if (err != nil) != tt.wantErr {
   104  				t.Errorf("Seal() error = %v, wantErr %v", err, tt.wantErr)
   105  				return
   106  			}
   107  		})
   108  	}
   109  }
   110  
   111  func TestSealWithPSK(t *testing.T) {
   112  	psk := memguard.NewBufferRandom(64)
   113  
   114  	type args struct {
   115  		container      *containerv1.Container
   116  		peersPublicKey []string
   117  	}
   118  	tests := []struct {
   119  		name    string
   120  		args    args
   121  		want    *containerv1.Container
   122  		wantErr bool
   123  	}{
   124  		{
   125  			name:    "nil",
   126  			wantErr: true,
   127  		},
   128  		{
   129  			name: "empty container",
   130  			args: args{
   131  				container: &containerv1.Container{},
   132  			},
   133  			wantErr: true,
   134  		},
   135  		{
   136  			name: "empty container headers",
   137  			args: args{
   138  				container: &containerv1.Container{
   139  					Headers: &containerv1.Header{},
   140  				},
   141  			},
   142  			wantErr: true,
   143  		},
   144  		// ---------------------------------------------------------------------
   145  		{
   146  			name: "valid",
   147  			args: args{
   148  				container: &containerv1.Container{
   149  					Headers: &containerv1.Header{},
   150  					Raw:     []byte{0x01, 0x02, 0x03, 0x04},
   151  				},
   152  				peersPublicKey: []string{
   153  					"v2.sk.AuSjVpMZben6n9fXiaDj8bMjSvhcZ9n7c82VOt7v9_UBzZJaMLamkQUFAVp_9frpAg",
   154  					"v2.sk.A0V1xCxGNtVAE9EVhaKi-pIADhd1in8xV_FI5Y0oHSHLAkew9gDAqiALSd6VgvBCbQ",
   155  				},
   156  			},
   157  			wantErr: false,
   158  		},
   159  	}
   160  	for _, tt := range tests {
   161  		t.Run(tt.name, func(t *testing.T) {
   162  			adapter := New()
   163  			_, err := adapter.SealWithPSK(rand.Reader, tt.args.container, psk, tt.args.peersPublicKey...)
   164  			if (err != nil) != tt.wantErr {
   165  				t.Errorf("Seal() error = %v, wantErr %v", err, tt.wantErr)
   166  				return
   167  			}
   168  		})
   169  	}
   170  }
   171  
   172  // -----------------------------------------------------------------------------
   173  
   174  func Test_Seal_Unseal(t *testing.T) {
   175  	adapter := New()
   176  
   177  	pubKey, privKey, err := adapter.GenerateKey()
   178  	assert.NoError(t, err)
   179  
   180  	input := &containerv1.Container{
   181  		Headers: &containerv1.Header{
   182  			ContentEncoding: "gzip",
   183  			ContentType:     "application/vnd.harp.v1.Bundle",
   184  		},
   185  		Raw: []byte{0x00, 0x00},
   186  	}
   187  
   188  	sealed, err := adapter.Seal(rand.Reader, input, pubKey)
   189  	if err != nil {
   190  		t.Fatalf("unable to seal container: %v", err)
   191  	}
   192  
   193  	unsealed, err := adapter.Unseal(sealed, memguard.NewBufferFromBytes([]byte(privKey)))
   194  	if err != nil {
   195  		t.Fatalf("unable to unseal container: %v", err)
   196  	}
   197  
   198  	if diff := cmp.Diff(unsealed, input, ignoreOpts...); diff != "" {
   199  		t.Errorf("Seal/Unseal()\n-got/+want\ndiff %s", diff)
   200  	}
   201  }
   202  
   203  func Test_Seal_Unseal_WithPSK(t *testing.T) {
   204  	psk := memguard.NewBufferRandom(64)
   205  	adapter := New()
   206  
   207  	pubKey, privKey, err := adapter.GenerateKey()
   208  	assert.NoError(t, err)
   209  
   210  	input := &containerv1.Container{
   211  		Headers: &containerv1.Header{
   212  			ContentEncoding: "gzip",
   213  			ContentType:     "application/vnd.harp.v1.Bundle",
   214  		},
   215  		Raw: []byte{0x00, 0x00},
   216  	}
   217  
   218  	sealed, err := adapter.SealWithPSK(rand.Reader, input, psk, pubKey)
   219  	if err != nil {
   220  		t.Fatalf("unable to seal container: %v", err)
   221  	}
   222  
   223  	unsealed, err := adapter.UnsealWithPSK(sealed, memguard.NewBufferFromBytes([]byte(privKey)), psk)
   224  	if err != nil {
   225  		t.Fatalf("unable to unseal container: %v", err)
   226  	}
   227  
   228  	if diff := cmp.Diff(unsealed, input, ignoreOpts...); diff != "" {
   229  		t.Errorf("Seal/Unseal()\n-got/+want\ndiff %s", diff)
   230  	}
   231  }
   232  
   233  func Test_Seal_Fuzz(t *testing.T) {
   234  	adapter := New()
   235  
   236  	// Making sure the function never panics
   237  	for i := 0; i < 500; i++ {
   238  		f := fuzz.New()
   239  
   240  		// Prepare arguments
   241  		var (
   242  			publicKey string
   243  		)
   244  		input := containerv1.Container{
   245  			Headers: &containerv1.Header{},
   246  			Raw:     []byte{0x00, 0x00},
   247  		}
   248  
   249  		f.Fuzz(&input.Headers)
   250  		f.Fuzz(&input.Raw)
   251  		f.Fuzz(&publicKey)
   252  
   253  		// Execute
   254  		adapter.Seal(rand.Reader, &input, publicKey)
   255  	}
   256  }
   257  
   258  // -----------------------------------------------------------------------------.
   259  func benchmarkSeal(container *containerv1.Container, peersPublicKeys []string, b *testing.B) {
   260  	adapter := New()
   261  	for n := 0; n < b.N; n++ {
   262  		_, err := adapter.Seal(rand.Reader, container, peersPublicKeys...)
   263  		if err != nil {
   264  			b.Fatal(err)
   265  		}
   266  	}
   267  }
   268  
   269  func Benchmark_Seal(b *testing.B) {
   270  	publicKey, _, err := New().GenerateKey()
   271  	assert.NoError(b, err)
   272  
   273  	input := &containerv1.Container{
   274  		Headers: &containerv1.Header{
   275  			ContentEncoding: "gzip",
   276  			ContentType:     "application/vnd.harp.v1.Bundle",
   277  		},
   278  		Raw: make([]byte, 1024),
   279  	}
   280  
   281  	benchmarkSeal(input, []string{publicKey}, b)
   282  }