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 }