storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/crypto/key_test.go (about)

     1  // MinIO Cloud Storage, (C) 2015, 2016, 2017, 2018 MinIO, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package crypto
    16  
    17  import (
    18  	"bytes"
    19  	"crypto/rand"
    20  	"encoding/hex"
    21  	"io"
    22  	"testing"
    23  
    24  	"storj.io/minio/cmd/logger"
    25  )
    26  
    27  var shortRandom = func(limit int64) io.Reader { return io.LimitReader(rand.Reader, limit) }
    28  
    29  func recoverTest(i int, shouldPass bool, t *testing.T) {
    30  	if err := recover(); err == nil && !shouldPass {
    31  		t.Errorf("Test %d should fail but passed successfully", i)
    32  	} else if err != nil && shouldPass {
    33  		t.Errorf("Test %d should pass but failed: %v", i, err)
    34  	}
    35  }
    36  
    37  var generateKeyTests = []struct {
    38  	ExtKey     [32]byte
    39  	Random     io.Reader
    40  	ShouldPass bool
    41  }{
    42  	{ExtKey: [32]byte{}, Random: nil, ShouldPass: true},              // 0
    43  	{ExtKey: [32]byte{}, Random: rand.Reader, ShouldPass: true},      // 1
    44  	{ExtKey: [32]byte{}, Random: shortRandom(32), ShouldPass: true},  // 2
    45  	{ExtKey: [32]byte{}, Random: shortRandom(31), ShouldPass: false}, // 3
    46  }
    47  
    48  func TestGenerateKey(t *testing.T) {
    49  	defer func(disableLog bool) { logger.Disable = disableLog }(logger.Disable)
    50  	logger.Disable = true
    51  
    52  	for i, test := range generateKeyTests {
    53  		i, test := i, test
    54  		func() {
    55  			defer recoverTest(i, test.ShouldPass, t)
    56  			key := GenerateKey(test.ExtKey[:], test.Random)
    57  			if [32]byte(key) == [32]byte{} {
    58  				t.Errorf("Test %d: generated key is zero key", i) // check that we generate random and unique key
    59  			}
    60  		}()
    61  	}
    62  }
    63  
    64  var generateIVTests = []struct {
    65  	Random     io.Reader
    66  	ShouldPass bool
    67  }{
    68  	{Random: nil, ShouldPass: true},              // 0
    69  	{Random: rand.Reader, ShouldPass: true},      // 1
    70  	{Random: shortRandom(32), ShouldPass: true},  // 2
    71  	{Random: shortRandom(31), ShouldPass: false}, // 3
    72  }
    73  
    74  func TestGenerateIV(t *testing.T) {
    75  	defer func(disableLog bool) { logger.Disable = disableLog }(logger.Disable)
    76  	logger.Disable = true
    77  
    78  	for i, test := range generateIVTests {
    79  		i, test := i, test
    80  		func() {
    81  			defer recoverTest(i, test.ShouldPass, t)
    82  			iv := GenerateIV(test.Random)
    83  			if iv == [32]byte{} {
    84  				t.Errorf("Test %d: generated IV is zero IV", i) // check that we generate random and unique IV
    85  			}
    86  		}()
    87  	}
    88  }
    89  
    90  var sealUnsealKeyTests = []struct {
    91  	SealExtKey, SealIV                 [32]byte
    92  	SealDomain, SealBucket, SealObject string
    93  
    94  	UnsealExtKey                             [32]byte
    95  	UnsealDomain, UnsealBucket, UnsealObject string
    96  
    97  	ShouldPass bool
    98  }{
    99  	{
   100  		SealExtKey: [32]byte{}, SealIV: [32]byte{}, SealDomain: "SSE-C", SealBucket: "bucket", SealObject: "object",
   101  		UnsealExtKey: [32]byte{}, UnsealDomain: "SSE-C", UnsealBucket: "bucket", UnsealObject: "object",
   102  		ShouldPass: true,
   103  	}, // 0
   104  	{
   105  		SealExtKey: [32]byte{}, SealIV: [32]byte{}, SealDomain: "SSE-C", SealBucket: "bucket", SealObject: "object",
   106  		UnsealExtKey: [32]byte{1}, UnsealDomain: "SSE-C", UnsealBucket: "bucket", UnsealObject: "object", // different ext-key
   107  		ShouldPass: false,
   108  	}, // 1
   109  	{
   110  		SealExtKey: [32]byte{}, SealIV: [32]byte{}, SealDomain: "SSE-S3", SealBucket: "bucket", SealObject: "object",
   111  		UnsealExtKey: [32]byte{}, UnsealDomain: "SSE-C", UnsealBucket: "bucket", UnsealObject: "object", // different domain
   112  		ShouldPass: false,
   113  	}, // 2
   114  	{
   115  		SealExtKey: [32]byte{}, SealIV: [32]byte{}, SealDomain: "SSE-C", SealBucket: "bucket", SealObject: "object",
   116  		UnsealExtKey: [32]byte{}, UnsealDomain: "SSE-C", UnsealBucket: "Bucket", UnsealObject: "object", // different bucket
   117  		ShouldPass: false,
   118  	}, // 3
   119  	{
   120  		SealExtKey: [32]byte{}, SealIV: [32]byte{}, SealDomain: "SSE-C", SealBucket: "bucket", SealObject: "object",
   121  		UnsealExtKey: [32]byte{}, UnsealDomain: "SSE-C", UnsealBucket: "bucket", UnsealObject: "Object", // different object
   122  		ShouldPass: false,
   123  	}, // 4
   124  }
   125  
   126  func TestSealUnsealKey(t *testing.T) {
   127  	for i, test := range sealUnsealKeyTests {
   128  		key := GenerateKey(test.SealExtKey[:], rand.Reader)
   129  		sealedKey := key.Seal(test.SealExtKey[:], test.SealIV, test.SealDomain, test.SealBucket, test.SealObject)
   130  		if err := key.Unseal(test.UnsealExtKey[:], sealedKey, test.UnsealDomain, test.UnsealBucket, test.UnsealObject); err == nil && !test.ShouldPass {
   131  			t.Errorf("Test %d should fail but passed successfully", i)
   132  		} else if err != nil && test.ShouldPass {
   133  			t.Errorf("Test %d should pass put failed: %v", i, err)
   134  		}
   135  	}
   136  
   137  	// Test legacy InsecureSealAlgorithm
   138  	var extKey, iv [32]byte
   139  	key := GenerateKey(extKey[:], rand.Reader)
   140  	sealedKey := key.Seal(extKey[:], iv, "SSE-S3", "bucket", "object")
   141  	sealedKey.Algorithm = InsecureSealAlgorithm
   142  	if err := key.Unseal(extKey[:], sealedKey, "SSE-S3", "bucket", "object"); err == nil {
   143  		t.Errorf("'%s' test succeeded but it should fail because the legacy algorithm was used", sealedKey.Algorithm)
   144  	}
   145  }
   146  
   147  var derivePartKeyTest = []struct {
   148  	PartID  uint32
   149  	PartKey string
   150  }{
   151  	{PartID: 0, PartKey: "aa7855e13839dd767cd5da7c1ff5036540c9264b7a803029315e55375287b4af"},
   152  	{PartID: 1, PartKey: "a3e7181c6eed030fd52f79537c56c4d07da92e56d374ff1dd2043350785b37d8"},
   153  	{PartID: 10000, PartKey: "f86e65c396ed52d204ee44bd1a0bbd86eb8b01b7354e67a3b3ae0e34dd5bd115"},
   154  }
   155  
   156  func TestDerivePartKey(t *testing.T) {
   157  	var key ObjectKey
   158  	for i, test := range derivePartKeyTest {
   159  		expectedPartKey, err := hex.DecodeString(test.PartKey)
   160  		if err != nil {
   161  			t.Fatalf("Test %d failed to decode expected part-key: %v", i, err)
   162  		}
   163  		partKey := key.DerivePartKey(test.PartID)
   164  		if !bytes.Equal(partKey[:], expectedPartKey[:]) {
   165  			t.Errorf("Test %d derives wrong part-key: got '%s' want: '%s'", i, hex.EncodeToString(partKey[:]), test.PartKey)
   166  		}
   167  	}
   168  }
   169  
   170  var sealUnsealETagTests = []string{
   171  	"",
   172  	"90682b8e8cc7609c",
   173  	"90682b8e8cc7609c4671e1d64c73fc30",
   174  	"90682b8e8cc7609c4671e1d64c73fc307fb3104f",
   175  }
   176  
   177  func TestSealETag(t *testing.T) {
   178  	var key ObjectKey
   179  	for i := range key {
   180  		key[i] = byte(i)
   181  	}
   182  	for i, etag := range sealUnsealETagTests {
   183  		tag, err := hex.DecodeString(etag)
   184  		if err != nil {
   185  			t.Errorf("Test %d: failed to decode etag: %s", i, err)
   186  		}
   187  		sealedETag := key.SealETag(tag)
   188  		unsealedETag, err := key.UnsealETag(sealedETag)
   189  		if err != nil {
   190  			t.Errorf("Test %d: failed to decrypt etag: %s", i, err)
   191  		}
   192  		if !bytes.Equal(unsealedETag, tag) {
   193  			t.Errorf("Test %d: unsealed etag does not match: got %s - want %s", i, hex.EncodeToString(unsealedETag), etag)
   194  		}
   195  	}
   196  }