| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2019-04-10 02:39:42 +08:00
										 |  |  |  * MinIO Cloud Storage, (C) 2017, 2018 MinIO, Inc. | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  * you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  * You may obtain a copy of the License at | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  * See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  * limitations under the License. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2019-01-06 06:16:43 +08:00
										 |  |  | 	"encoding/base64" | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 10:22:09 +08:00
										 |  |  | 	humanize "github.com/dustin/go-humanize" | 
					
						
							| 
									
										
										
										
											2019-05-30 07:35:12 +08:00
										 |  |  | 	"github.com/minio/minio-go/v6/pkg/encrypt" | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 	"github.com/minio/minio/cmd/crypto" | 
					
						
							| 
									
										
										
										
											2018-09-21 10:22:09 +08:00
										 |  |  | 	"github.com/minio/sio" | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var encryptRequestTests = []struct { | 
					
						
							|  |  |  | 	header   map[string]string | 
					
						
							|  |  |  | 	metadata map[string]string | 
					
						
							|  |  |  | }{ | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		header: map[string]string{ | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 			crypto.SSECAlgorithm: "AES256", | 
					
						
							|  |  |  | 			crypto.SSECKey:       "XAm0dRrJsEsyPb1UuFNezv1bl9hxuYsgUVC/MUctE2k=", | 
					
						
							|  |  |  | 			crypto.SSECKeyMD5:    "bY4wkxQejw9mUJfo72k53A==", | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		metadata: map[string]string{}, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		header: map[string]string{ | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 			crypto.SSECAlgorithm: "AES256", | 
					
						
							|  |  |  | 			crypto.SSECKey:       "XAm0dRrJsEsyPb1UuFNezv1bl9hxuYsgUVC/MUctE2k=", | 
					
						
							|  |  |  | 			crypto.SSECKeyMD5:    "bY4wkxQejw9mUJfo72k53A==", | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		metadata: map[string]string{ | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 			crypto.SSECKey: "XAm0dRrJsEsyPb1UuFNezv1bl9hxuYsgUVC/MUctE2k=", | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestEncryptRequest(t *testing.T) { | 
					
						
							|  |  |  | 	defer func(flag bool) { globalIsSSL = flag }(globalIsSSL) | 
					
						
							|  |  |  | 	globalIsSSL = true | 
					
						
							|  |  |  | 	for i, test := range encryptRequestTests { | 
					
						
							|  |  |  | 		content := bytes.NewReader(make([]byte, 64)) | 
					
						
							|  |  |  | 		req := &http.Request{Header: http.Header{}} | 
					
						
							|  |  |  | 		for k, v := range test.header { | 
					
						
							|  |  |  | 			req.Header.Set(k, v) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-11-15 09:36:41 +08:00
										 |  |  | 		_, _, err := EncryptRequest(content, req, "bucket", "object", test.metadata) | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d: Failed to encrypt request: %v", i, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 		if kdf, ok := test.metadata[crypto.SSESealAlgorithm]; !ok { | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 			t.Errorf("Test %d: ServerSideEncryptionKDF must be part of metadata: %v", i, kdf) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 		if iv, ok := test.metadata[crypto.SSEIV]; !ok { | 
					
						
							|  |  |  | 			t.Errorf("Test %d: crypto.SSEIV must be part of metadata: %v", i, iv) | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 		if mac, ok := test.metadata[crypto.SSECSealedKey]; !ok { | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 			t.Errorf("Test %d: ServerSideEncryptionKeyMAC must be part of metadata: %v", i, mac) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var decryptRequestTests = []struct { | 
					
						
							| 
									
										
										
										
											2018-07-10 08:18:28 +08:00
										 |  |  | 	bucket, object string | 
					
						
							|  |  |  | 	header         map[string]string | 
					
						
							|  |  |  | 	metadata       map[string]string | 
					
						
							|  |  |  | 	shouldFail     bool | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | }{ | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-07-10 08:18:28 +08:00
										 |  |  | 		bucket: "bucket", | 
					
						
							|  |  |  | 		object: "object", | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		header: map[string]string{ | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 			crypto.SSECAlgorithm: "AES256", | 
					
						
							|  |  |  | 			crypto.SSECKey:       "MzJieXRlc2xvbmdzZWNyZXRrZXltdXN0cHJvdmlkZWQ=", | 
					
						
							|  |  |  | 			crypto.SSECKeyMD5:    "7PpPLAK26ONlVUGOWlusfg==", | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		metadata: map[string]string{ | 
					
						
							| 
									
										
										
										
											2019-09-20 17:21:07 +08:00
										 |  |  | 			crypto.SSESealAlgorithm: crypto.InsecureSealAlgorithm, | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 			crypto.SSEIV:            "7nQqotA8xgrPx6QK7Ap3GCfjKitqJSrGP7xzgErSJlw=", | 
					
						
							|  |  |  | 			crypto.SSECSealedKey:    "EAAfAAAAAAD7v1hQq3PFRUHsItalxmrJqrOq6FwnbXNarxOOpb8jTWONPPKyM3Gfjkjyj6NCf+aB/VpHCLCTBA==", | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		shouldFail: false, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-07-10 08:18:28 +08:00
										 |  |  | 		bucket: "bucket", | 
					
						
							|  |  |  | 		object: "object", | 
					
						
							|  |  |  | 		header: map[string]string{ | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 			crypto.SSECAlgorithm: "AES256", | 
					
						
							|  |  |  | 			crypto.SSECKey:       "MzJieXRlc2xvbmdzZWNyZXRrZXltdXN0cHJvdmlkZWQ=", | 
					
						
							|  |  |  | 			crypto.SSECKeyMD5:    "7PpPLAK26ONlVUGOWlusfg==", | 
					
						
							| 
									
										
										
										
											2018-07-10 08:18:28 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		metadata: map[string]string{ | 
					
						
							| 
									
										
										
										
											2019-09-20 17:21:07 +08:00
										 |  |  | 			crypto.SSESealAlgorithm: crypto.SealAlgorithm, | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 			crypto.SSEIV:            "qEqmsONcorqlcZXJxaw32H04eyXyXwUgjHzlhkaIYrU=", | 
					
						
							|  |  |  | 			crypto.SSECSealedKey:    "IAAfAIM14ugTGcM/dIrn4iQMrkl1sjKyeBQ8FBEvRebYj8vWvxG+0cJRpC6NXRU1wJN50JaUOATjO7kz0wZ2mA==", | 
					
						
							| 
									
										
										
										
											2018-07-10 08:18:28 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		shouldFail: false, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		bucket: "bucket", | 
					
						
							|  |  |  | 		object: "object", | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		header: map[string]string{ | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 			crypto.SSECAlgorithm: "AES256", | 
					
						
							|  |  |  | 			crypto.SSECKey:       "XAm0dRrJsEsyPb1UuFNezv1bl9hxuYsgUVC/MUctE2k=", | 
					
						
							|  |  |  | 			crypto.SSECKeyMD5:    "bY4wkxQejw9mUJfo72k53A==", | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		metadata: map[string]string{ | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 			crypto.SSESealAlgorithm: "HMAC-SHA3", | 
					
						
							|  |  |  | 			crypto.SSEIV:            "XAm0dRrJsEsyPb1UuFNezv1bl9hxuYsgUVC/MUctE2k=", | 
					
						
							|  |  |  | 			crypto.SSECSealedKey:    "SY5E9AvI2tI7/nUrUAssIGE32Hcs4rR9z/CUuPqu5N4=", | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		shouldFail: true, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-07-10 08:18:28 +08:00
										 |  |  | 		bucket: "bucket", | 
					
						
							|  |  |  | 		object: "object", | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		header: map[string]string{ | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 			crypto.SSECAlgorithm: "AES256", | 
					
						
							|  |  |  | 			crypto.SSECKey:       "XAm0dRrJsEsyPb1UuFNezv1bl9hxuYsgUVC/MUctE2k=", | 
					
						
							|  |  |  | 			crypto.SSECKeyMD5:    "bY4wkxQejw9mUJfo72k53A==", | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		metadata: map[string]string{ | 
					
						
							| 
									
										
										
										
											2019-09-20 17:21:07 +08:00
										 |  |  | 			crypto.SSESealAlgorithm: crypto.InsecureSealAlgorithm, | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 			crypto.SSEIV:            "RrJsEsyPb1UuFNezv1bl9hxuYsgUVC/MUctE2k=", | 
					
						
							|  |  |  | 			crypto.SSECSealedKey:    "SY5E9AvI2tI7/nUrUAssIGE32Hcs4rR9z/CUuPqu5N4=", | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		shouldFail: true, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-07-10 08:18:28 +08:00
										 |  |  | 		bucket: "bucket", | 
					
						
							|  |  |  | 		object: "object", | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		header: map[string]string{ | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 			crypto.SSECAlgorithm: "AES256", | 
					
						
							|  |  |  | 			crypto.SSECKey:       "XAm0dRrJsEsyPb1UuFNezv1bl9hxuYsgUVC/MUctE2k=", | 
					
						
							|  |  |  | 			crypto.SSECKeyMD5:    "bY4wkxQejw9mUJfo72k53A==", | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		metadata: map[string]string{ | 
					
						
							| 
									
										
										
										
											2019-09-20 17:21:07 +08:00
										 |  |  | 			crypto.SSESealAlgorithm: crypto.InsecureSealAlgorithm, | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 			crypto.SSEIV:            "XAm0dRrJsEsyPb1UuFNezv1bl9ehxuYsgUVC/MUctE2k=", | 
					
						
							|  |  |  | 			crypto.SSECSealedKey:    "SY5E9AvI2tI7/nUrUAssIGE32Hds4rR9z/CUuPqu5N4=", | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		shouldFail: true, | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2018-07-10 08:18:28 +08:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		bucket: "bucket", | 
					
						
							|  |  |  | 		object: "object-2", | 
					
						
							|  |  |  | 		header: map[string]string{ | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 			crypto.SSECAlgorithm: "AES256", | 
					
						
							|  |  |  | 			crypto.SSECKey:       "MzJieXRlc2xvbmdzZWNyZXRrZXltdXN0cHJvdmlkZWQ=", | 
					
						
							|  |  |  | 			crypto.SSECKeyMD5:    "7PpPLAK26ONlVUGOWlusfg==", | 
					
						
							| 
									
										
										
										
											2018-07-10 08:18:28 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		metadata: map[string]string{ | 
					
						
							| 
									
										
										
										
											2019-09-20 17:21:07 +08:00
										 |  |  | 			crypto.SSESealAlgorithm: crypto.SealAlgorithm, | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 			crypto.SSEIV:            "qEqmsONcorqlcZXJxaw32H04eyXyXwUgjHzlhkaIYrU=", | 
					
						
							|  |  |  | 			crypto.SSECSealedKey:    "IAAfAIM14ugTGcM/dIrn4iQMrkl1sjKyeBQ8FBEvRebYj8vWvxG+0cJRpC6NXRU1wJN50JaUOATjO7kz0wZ2mA==", | 
					
						
							| 
									
										
										
										
											2018-07-10 08:18:28 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		shouldFail: true, | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestDecryptRequest(t *testing.T) { | 
					
						
							|  |  |  | 	defer func(flag bool) { globalIsSSL = flag }(globalIsSSL) | 
					
						
							|  |  |  | 	globalIsSSL = true | 
					
						
							| 
									
										
										
										
											2018-07-10 08:18:28 +08:00
										 |  |  | 	for i, test := range decryptRequestTests[1:] { | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		client := bytes.NewBuffer(nil) | 
					
						
							|  |  |  | 		req := &http.Request{Header: http.Header{}} | 
					
						
							|  |  |  | 		for k, v := range test.header { | 
					
						
							|  |  |  | 			req.Header.Set(k, v) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-07-10 08:18:28 +08:00
										 |  |  | 		_, err := DecryptRequest(client, req, test.bucket, test.object, test.metadata) | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		if err != nil && !test.shouldFail { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d: Failed to encrypt request: %v", i, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-07-10 08:18:28 +08:00
										 |  |  | 		if err == nil && test.shouldFail { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d: should fail but passed", i) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 		if key, ok := test.metadata[crypto.SSECKey]; ok { | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 			t.Errorf("Test %d: Client provided key survived in metadata - key: %s", i, key) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 		if kdf, ok := test.metadata[crypto.SSESealAlgorithm]; ok && !test.shouldFail { | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 			t.Errorf("Test %d: ServerSideEncryptionKDF should not be part of metadata: %v", i, kdf) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 		if iv, ok := test.metadata[crypto.SSEIV]; ok && !test.shouldFail { | 
					
						
							|  |  |  | 			t.Errorf("Test %d: crypto.SSEIV should not be part of metadata: %v", i, iv) | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 		if mac, ok := test.metadata[crypto.SSECSealedKey]; ok && !test.shouldFail { | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 			t.Errorf("Test %d: ServerSideEncryptionKeyMAC should not be part of metadata: %v", i, mac) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var decryptObjectInfoTests = []struct { | 
					
						
							|  |  |  | 	info    ObjectInfo | 
					
						
							|  |  |  | 	headers http.Header | 
					
						
							| 
									
										
										
										
											2018-08-24 22:56:24 +08:00
										 |  |  | 	expErr  error | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | }{ | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		info:    ObjectInfo{Size: 100}, | 
					
						
							|  |  |  | 		headers: http.Header{}, | 
					
						
							| 
									
										
										
										
											2018-08-24 22:56:24 +08:00
										 |  |  | 		expErr:  nil, | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2019-09-20 17:21:07 +08:00
										 |  |  | 		info:    ObjectInfo{Size: 100, UserDefined: map[string]string{crypto.SSESealAlgorithm: crypto.InsecureSealAlgorithm}}, | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 		headers: http.Header{crypto.SSECAlgorithm: []string{crypto.SSEAlgorithmAES256}}, | 
					
						
							| 
									
										
										
										
											2018-08-24 22:56:24 +08:00
										 |  |  | 		expErr:  nil, | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2019-09-20 17:21:07 +08:00
										 |  |  | 		info:    ObjectInfo{Size: 0, UserDefined: map[string]string{crypto.SSESealAlgorithm: crypto.InsecureSealAlgorithm}}, | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 		headers: http.Header{crypto.SSECAlgorithm: []string{crypto.SSEAlgorithmAES256}}, | 
					
						
							| 
									
										
										
										
											2018-08-24 22:56:24 +08:00
										 |  |  | 		expErr:  nil, | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 		info:    ObjectInfo{Size: 100, UserDefined: map[string]string{crypto.SSECSealedKey: "EAAfAAAAAAD7v1hQq3PFRUHsItalxmrJqrOq6FwnbXNarxOOpb8jTWONPPKyM3Gfjkjyj6NCf+aB/VpHCLCTBA=="}}, | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 		headers: http.Header{}, | 
					
						
							| 
									
										
										
										
											2018-08-24 22:56:24 +08:00
										 |  |  | 		expErr:  errEncryptedObject, | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		info:    ObjectInfo{Size: 100, UserDefined: map[string]string{}}, | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 		headers: http.Header{crypto.SSECAlgorithm: []string{crypto.SSEAlgorithmAES256}}, | 
					
						
							| 
									
										
										
										
											2018-08-24 22:56:24 +08:00
										 |  |  | 		expErr:  errInvalidEncryptionParameters, | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2019-09-20 17:21:07 +08:00
										 |  |  | 		info:    ObjectInfo{Size: 31, UserDefined: map[string]string{crypto.SSESealAlgorithm: crypto.InsecureSealAlgorithm}}, | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 		headers: http.Header{crypto.SSECAlgorithm: []string{crypto.SSEAlgorithmAES256}}, | 
					
						
							| 
									
										
										
										
											2018-08-24 22:56:24 +08:00
										 |  |  | 		expErr:  errObjectTampered, | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 	}, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestDecryptObjectInfo(t *testing.T) { | 
					
						
							|  |  |  | 	for i, test := range decryptObjectInfoTests { | 
					
						
							| 
									
										
										
										
											2018-11-15 09:36:41 +08:00
										 |  |  | 		if encrypted, err := DecryptObjectInfo(&test.info, test.headers); err != test.expErr { | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 			t.Errorf("Test %d: Decryption returned wrong error code: got %d , want %d", i, err, test.expErr) | 
					
						
							| 
									
										
										
										
											2018-08-18 03:52:14 +08:00
										 |  |  | 		} else if enc := crypto.IsEncrypted(test.info.UserDefined); encrypted && enc != encrypted { | 
					
						
							| 
									
										
										
										
											2017-11-08 07:18:59 +08:00
										 |  |  | 			t.Errorf("Test %d: Decryption thinks object is encrypted but it is not", i) | 
					
						
							|  |  |  | 		} else if !encrypted && enc != encrypted { | 
					
						
							|  |  |  | 			t.Errorf("Test %d: Decryption thinks object is not encrypted but it is", i) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-09-21 10:22:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-10 08:01:45 +08:00
										 |  |  | var decryptETagTests = []struct { | 
					
						
							|  |  |  | 	ObjectKey  crypto.ObjectKey | 
					
						
							|  |  |  | 	ObjectInfo ObjectInfo | 
					
						
							|  |  |  | 	ShouldFail bool | 
					
						
							|  |  |  | 	ETag       string | 
					
						
							|  |  |  | }{ | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		ObjectKey:  [32]byte{}, | 
					
						
							|  |  |  | 		ObjectInfo: ObjectInfo{ETag: "20000f00f27834c9a2654927546df57f9e998187496394d4ee80f3d9978f85f3c7d81f72600cdbe03d80dc5a13d69354"}, | 
					
						
							|  |  |  | 		ETag:       "8ad3fe6b84bf38489e95c701c84355b6", | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		ObjectKey:  [32]byte{}, | 
					
						
							|  |  |  | 		ObjectInfo: ObjectInfo{ETag: "20000f00f27834c9a2654927546df57f9e998187496394d4ee80f3d9978f85f3c7d81f72600cdbe03d80dc5a13d6935"}, | 
					
						
							|  |  |  | 		ETag:       "", | 
					
						
							|  |  |  | 		ShouldFail: true, // ETag is not a valid hex value
 | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		ObjectKey:  [32]byte{}, | 
					
						
							|  |  |  | 		ObjectInfo: ObjectInfo{ETag: "00000f00f27834c9a2654927546df57f9e998187496394d4ee80f3d9978f85f3c7d81f72600cdbe03d80dc5a13d69354"}, | 
					
						
							|  |  |  | 		ETag:       "", | 
					
						
							|  |  |  | 		ShouldFail: true, // modified ETag
 | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Special tests for ETags that end with a '-x'
 | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		ObjectKey:  [32]byte{}, | 
					
						
							|  |  |  | 		ObjectInfo: ObjectInfo{ETag: "916516b396f0f4d4f2a0e7177557bec4-1"}, | 
					
						
							|  |  |  | 		ETag:       "916516b396f0f4d4f2a0e7177557bec4-1", | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		ObjectKey:  [32]byte{}, | 
					
						
							|  |  |  | 		ObjectInfo: ObjectInfo{ETag: "916516b396f0f4d4f2a0e7177557bec4-738"}, | 
					
						
							|  |  |  | 		ETag:       "916516b396f0f4d4f2a0e7177557bec4-738", | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		ObjectKey:  [32]byte{}, | 
					
						
							|  |  |  | 		ObjectInfo: ObjectInfo{ETag: "916516b396f0f4d4f2a0e7177557bec4-Q"}, | 
					
						
							|  |  |  | 		ETag:       "", | 
					
						
							|  |  |  | 		ShouldFail: true, // Q is not a number
 | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		ObjectKey:  [32]byte{}, | 
					
						
							|  |  |  | 		ObjectInfo: ObjectInfo{ETag: "16516b396f0f4d4f2a0e7177557bec4-1"}, | 
					
						
							|  |  |  | 		ETag:       "", | 
					
						
							|  |  |  | 		ShouldFail: true, // ETag prefix is not a valid hex value
 | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		ObjectKey:  [32]byte{}, | 
					
						
							|  |  |  | 		ObjectInfo: ObjectInfo{ETag: "16516b396f0f4d4f2a0e7177557bec4-1-2"}, | 
					
						
							|  |  |  | 		ETag:       "", | 
					
						
							|  |  |  | 		ShouldFail: true, // ETag contains multiple: -
 | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestDecryptETag(t *testing.T) { | 
					
						
							|  |  |  | 	for i, test := range decryptETagTests { | 
					
						
							|  |  |  | 		etag, err := DecryptETag(test.ObjectKey, test.ObjectInfo) | 
					
						
							|  |  |  | 		if err != nil && !test.ShouldFail { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d: should succeed but failed: %v", i, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err == nil && test.ShouldFail { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d: should fail but succeeded", i) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err == nil { | 
					
						
							|  |  |  | 			if etag != test.ETag { | 
					
						
							|  |  |  | 				t.Fatalf("Test %d: ETag mismatch: got %s - want %s", i, etag, test.ETag) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-09 02:27:21 +08:00
										 |  |  | // Tests for issue reproduced when getting the right encrypted
 | 
					
						
							|  |  |  | // offset of the object.
 | 
					
						
							|  |  |  | func TestGetDecryptedRange_Issue50(t *testing.T) { | 
					
						
							|  |  |  | 	rs, err := parseRequestRangeSpec("bytes=594870256-594870263") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	objInfo := ObjectInfo{ | 
					
						
							|  |  |  | 		Bucket: "bucket", | 
					
						
							|  |  |  | 		Name:   "object", | 
					
						
							|  |  |  | 		Size:   595160760, | 
					
						
							|  |  |  | 		UserDefined: map[string]string{ | 
					
						
							|  |  |  | 			crypto.SSEMultipart:                    "", | 
					
						
							|  |  |  | 			crypto.SSEIV:                           "HTexa=", | 
					
						
							|  |  |  | 			crypto.SSESealAlgorithm:                "DAREv2-HMAC-SHA256", | 
					
						
							|  |  |  | 			crypto.SSECSealedKey:                   "IAA8PGAA==", | 
					
						
							|  |  |  | 			ReservedMetadataPrefix + "actual-size": "594870264", | 
					
						
							|  |  |  | 			"content-type":                         "application/octet-stream", | 
					
						
							|  |  |  | 			"etag":                                 "166b1545b4c1535294ee0686678bea8c-2", | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2019-01-06 06:16:43 +08:00
										 |  |  | 		Parts: []ObjectPartInfo{ | 
					
						
							| 
									
										
										
										
											2018-11-09 02:27:21 +08:00
										 |  |  | 			{ | 
					
						
							|  |  |  | 				Number:     1, | 
					
						
							|  |  |  | 				Size:       297580380, | 
					
						
							|  |  |  | 				ActualSize: 297435132, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				Number:     2, | 
					
						
							|  |  |  | 				Size:       297580380, | 
					
						
							|  |  |  | 				ActualSize: 297435132, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	encOff, encLength, skipLen, seqNumber, partStart, err := objInfo.GetDecryptedRange(rs) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Test: failed %s", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if encOff != 595127964 { | 
					
						
							|  |  |  | 		t.Fatalf("Test: expected %d, got %d", 595127964, encOff) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if encLength != 32796 { | 
					
						
							|  |  |  | 		t.Fatalf("Test: expected %d, got %d", 32796, encLength) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if skipLen != 32756 { | 
					
						
							|  |  |  | 		t.Fatalf("Test: expected %d, got %d", 32756, skipLen) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if seqNumber != 4538 { | 
					
						
							|  |  |  | 		t.Fatalf("Test: expected %d, got %d", 4538, seqNumber) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if partStart != 1 { | 
					
						
							|  |  |  | 		t.Fatalf("Test: expected %d, got %d", 1, partStart) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 10:22:09 +08:00
										 |  |  | func TestGetDecryptedRange(t *testing.T) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		pkgSz     = int64(64) * humanize.KiByte | 
					
						
							|  |  |  | 		minPartSz = int64(5) * humanize.MiByte | 
					
						
							|  |  |  | 		maxPartSz = int64(5) * humanize.GiByte | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		getEncSize = func(s int64) int64 { | 
					
						
							|  |  |  | 			v, _ := sio.EncryptedSize(uint64(s)) | 
					
						
							|  |  |  | 			return int64(v) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		udMap = func(isMulti bool) map[string]string { | 
					
						
							|  |  |  | 			m := map[string]string{ | 
					
						
							| 
									
										
										
										
											2019-09-20 17:21:07 +08:00
										 |  |  | 				crypto.SSESealAlgorithm: crypto.InsecureSealAlgorithm, | 
					
						
							| 
									
										
										
										
											2018-09-21 10:22:09 +08:00
										 |  |  | 				crypto.SSEMultipart:     "1", | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if !isMulti { | 
					
						
							|  |  |  | 				delete(m, crypto.SSEMultipart) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return m | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Single part object tests
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		mkSPObj = func(s int64) ObjectInfo { | 
					
						
							|  |  |  | 			return ObjectInfo{ | 
					
						
							|  |  |  | 				Size:        getEncSize(s), | 
					
						
							|  |  |  | 				UserDefined: udMap(false), | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	testSP := []struct { | 
					
						
							|  |  |  | 		decSz int64 | 
					
						
							|  |  |  | 		oi    ObjectInfo | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{0, mkSPObj(0)}, | 
					
						
							|  |  |  | 		{1, mkSPObj(1)}, | 
					
						
							|  |  |  | 		{pkgSz - 1, mkSPObj(pkgSz - 1)}, | 
					
						
							|  |  |  | 		{pkgSz, mkSPObj(pkgSz)}, | 
					
						
							|  |  |  | 		{2*pkgSz - 1, mkSPObj(2*pkgSz - 1)}, | 
					
						
							|  |  |  | 		{minPartSz, mkSPObj(minPartSz)}, | 
					
						
							|  |  |  | 		{maxPartSz, mkSPObj(maxPartSz)}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, test := range testSP { | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			// nil range
 | 
					
						
							|  |  |  | 			o, l, skip, sn, ps, err := test.oi.GetDecryptedRange(nil) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Errorf("Case %d: unexpected err: %v", i, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if skip != 0 || sn != 0 || ps != 0 || o != 0 || l != getEncSize(test.decSz) { | 
					
						
							|  |  |  | 				t.Errorf("Case %d: test failed: %d %d %d %d %d", i, o, l, skip, sn, ps) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if test.decSz >= 10 { | 
					
						
							|  |  |  | 			// first 10 bytes
 | 
					
						
							|  |  |  | 			o, l, skip, sn, ps, err := test.oi.GetDecryptedRange(&HTTPRangeSpec{false, 0, 9}) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Errorf("Case %d: unexpected err: %v", i, err) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-09-24 01:24:10 +08:00
										 |  |  | 			var rLen = pkgSz + 32 | 
					
						
							| 
									
										
										
										
											2018-09-21 10:22:09 +08:00
										 |  |  | 			if test.decSz < pkgSz { | 
					
						
							|  |  |  | 				rLen = test.decSz + 32 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if skip != 0 || sn != 0 || ps != 0 || o != 0 || l != rLen { | 
					
						
							|  |  |  | 				t.Errorf("Case %d: test failed: %d %d %d %d %d", i, o, l, skip, sn, ps) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		kb32 := int64(32) * humanize.KiByte | 
					
						
							|  |  |  | 		if test.decSz >= (64+32)*humanize.KiByte { | 
					
						
							|  |  |  | 			// Skip the first 32Kib, and read the next 64Kib
 | 
					
						
							|  |  |  | 			o, l, skip, sn, ps, err := test.oi.GetDecryptedRange(&HTTPRangeSpec{false, kb32, 3*kb32 - 1}) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Errorf("Case %d: unexpected err: %v", i, err) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-09-24 01:24:10 +08:00
										 |  |  | 			var rLen = (pkgSz + 32) * 2 | 
					
						
							| 
									
										
										
										
											2018-09-21 10:22:09 +08:00
										 |  |  | 			if test.decSz < 2*pkgSz { | 
					
						
							|  |  |  | 				rLen = (pkgSz + 32) + (test.decSz - pkgSz + 32) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if skip != kb32 || sn != 0 || ps != 0 || o != 0 || l != rLen { | 
					
						
							|  |  |  | 				t.Errorf("Case %d: test failed: %d %d %d %d %d", i, o, l, skip, sn, ps) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if test.decSz >= (64*2+32)*humanize.KiByte { | 
					
						
							|  |  |  | 			// Skip the first 96Kib and read the next 64Kib
 | 
					
						
							|  |  |  | 			o, l, skip, sn, ps, err := test.oi.GetDecryptedRange(&HTTPRangeSpec{false, 3 * kb32, 5*kb32 - 1}) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Errorf("Case %d: unexpected err: %v", i, err) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-09-24 01:24:10 +08:00
										 |  |  | 			var rLen = (pkgSz + 32) * 2 | 
					
						
							| 
									
										
										
										
											2018-09-21 10:22:09 +08:00
										 |  |  | 			if test.decSz-pkgSz < 2*pkgSz { | 
					
						
							|  |  |  | 				rLen = (pkgSz + 32) + (test.decSz - pkgSz + 32*2) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if skip != kb32 || sn != 1 || ps != 0 || o != pkgSz+32 || l != rLen { | 
					
						
							|  |  |  | 				t.Errorf("Case %d: test failed: %d %d %d %d %d", i, o, l, skip, sn, ps) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Multipart object tests
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		// make a multipart object-info given part sizes
 | 
					
						
							|  |  |  | 		mkMPObj = func(sizes []int64) ObjectInfo { | 
					
						
							| 
									
										
										
										
											2019-01-06 06:16:43 +08:00
										 |  |  | 			r := make([]ObjectPartInfo, len(sizes)) | 
					
						
							| 
									
										
										
										
											2018-09-21 10:22:09 +08:00
										 |  |  | 			sum := int64(0) | 
					
						
							|  |  |  | 			for i, s := range sizes { | 
					
						
							|  |  |  | 				r[i].Number = i | 
					
						
							|  |  |  | 				r[i].Size = int64(getEncSize(s)) | 
					
						
							|  |  |  | 				sum += r[i].Size | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return ObjectInfo{ | 
					
						
							|  |  |  | 				Size:        sum, | 
					
						
							|  |  |  | 				UserDefined: udMap(true), | 
					
						
							|  |  |  | 				Parts:       r, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Simple useful utilities
 | 
					
						
							|  |  |  | 		repeat = func(k int64, n int) []int64 { | 
					
						
							|  |  |  | 			a := []int64{} | 
					
						
							|  |  |  | 			for i := 0; i < n; i++ { | 
					
						
							|  |  |  | 				a = append(a, k) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return a | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		lsum = func(s []int64) int64 { | 
					
						
							|  |  |  | 			sum := int64(0) | 
					
						
							|  |  |  | 			for _, i := range s { | 
					
						
							|  |  |  | 				if i < 0 { | 
					
						
							|  |  |  | 					return -1 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				sum += i | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return sum | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		esum = func(oi ObjectInfo) int64 { | 
					
						
							|  |  |  | 			sum := int64(0) | 
					
						
							|  |  |  | 			for _, i := range oi.Parts { | 
					
						
							|  |  |  | 				sum += i.Size | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return sum | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s1 := []int64{5487701, 5487799, 3} | 
					
						
							|  |  |  | 	s2 := repeat(5487701, 5) | 
					
						
							|  |  |  | 	s3 := repeat(maxPartSz, 10000) | 
					
						
							|  |  |  | 	testMPs := []struct { | 
					
						
							|  |  |  | 		decSizes []int64 | 
					
						
							|  |  |  | 		oi       ObjectInfo | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{s1, mkMPObj(s1)}, | 
					
						
							|  |  |  | 		{s2, mkMPObj(s2)}, | 
					
						
							|  |  |  | 		{s3, mkMPObj(s3)}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// This function is a reference (re-)implementation of
 | 
					
						
							|  |  |  | 	// decrypted range computation, written solely for the purpose
 | 
					
						
							|  |  |  | 	// of the unit tests.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// `s` gives the decrypted part sizes, and the other
 | 
					
						
							|  |  |  | 	// parameters describe the desired read segment. When
 | 
					
						
							|  |  |  | 	// `isFromEnd` is true, `skipLen` argument is ignored.
 | 
					
						
							|  |  |  | 	decryptedRangeRef := func(s []int64, skipLen, readLen int64, isFromEnd bool) (o, l, skip int64, sn uint32, ps int) { | 
					
						
							|  |  |  | 		oSize := lsum(s) | 
					
						
							|  |  |  | 		if isFromEnd { | 
					
						
							|  |  |  | 			skipLen = oSize - readLen | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if skipLen < 0 || readLen < 0 || oSize < 0 || skipLen+readLen > oSize { | 
					
						
							|  |  |  | 			t.Fatalf("Impossible read specified: %d %d %d", skipLen, readLen, oSize) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var cumulativeSum, cumulativeEncSum int64 | 
					
						
							|  |  |  | 		toRead := readLen | 
					
						
							|  |  |  | 		readStart := false | 
					
						
							|  |  |  | 		for i, v := range s { | 
					
						
							|  |  |  | 			partOffset := int64(0) | 
					
						
							|  |  |  | 			partDarePkgOffset := int64(0) | 
					
						
							|  |  |  | 			if !readStart && cumulativeSum+v > skipLen { | 
					
						
							|  |  |  | 				// Read starts at the current part
 | 
					
						
							|  |  |  | 				readStart = true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				partOffset = skipLen - cumulativeSum | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// All return values except `l` are
 | 
					
						
							|  |  |  | 				// calculated here.
 | 
					
						
							|  |  |  | 				sn = uint32(partOffset / pkgSz) | 
					
						
							|  |  |  | 				skip = partOffset % pkgSz | 
					
						
							|  |  |  | 				ps = i | 
					
						
							|  |  |  | 				o = cumulativeEncSum + int64(sn)*(pkgSz+32) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				partDarePkgOffset = partOffset - skip | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if readStart { | 
					
						
							|  |  |  | 				currentPartBytes := v - partOffset | 
					
						
							|  |  |  | 				currentPartDareBytes := v - partDarePkgOffset | 
					
						
							|  |  |  | 				if currentPartBytes < toRead { | 
					
						
							|  |  |  | 					toRead -= currentPartBytes | 
					
						
							|  |  |  | 					l += getEncSize(currentPartDareBytes) | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					// current part has the last
 | 
					
						
							|  |  |  | 					// byte required
 | 
					
						
							|  |  |  | 					lbPartOffset := partOffset + toRead - 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// round up the lbPartOffset
 | 
					
						
							|  |  |  | 					// to the end of the
 | 
					
						
							|  |  |  | 					// corresponding DARE package
 | 
					
						
							|  |  |  | 					lbPkgEndOffset := lbPartOffset - (lbPartOffset % pkgSz) + pkgSz | 
					
						
							|  |  |  | 					if lbPkgEndOffset > v { | 
					
						
							|  |  |  | 						lbPkgEndOffset = v | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					bytesToDrop := v - lbPkgEndOffset | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// Last segment to update `l`
 | 
					
						
							|  |  |  | 					l += getEncSize(currentPartDareBytes - bytesToDrop) | 
					
						
							|  |  |  | 					break | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			cumulativeSum += v | 
					
						
							|  |  |  | 			cumulativeEncSum += getEncSize(v) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, test := range testMPs { | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			// nil range
 | 
					
						
							|  |  |  | 			o, l, skip, sn, ps, err := test.oi.GetDecryptedRange(nil) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Errorf("Case %d: unexpected err: %v", i, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if o != 0 || l != esum(test.oi) || skip != 0 || sn != 0 || ps != 0 { | 
					
						
							|  |  |  | 				t.Errorf("Case %d: test failed: %d %d %d %d %d", i, o, l, skip, sn, ps) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Skip 1Mib and read 1Mib (in the decrypted object)
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// The check below ensures the object is large enough
 | 
					
						
							|  |  |  | 		// for the read.
 | 
					
						
							|  |  |  | 		if lsum(test.decSizes) >= 2*humanize.MiByte { | 
					
						
							|  |  |  | 			skipLen, readLen := int64(1)*humanize.MiByte, int64(1)*humanize.MiByte | 
					
						
							|  |  |  | 			o, l, skip, sn, ps, err := test.oi.GetDecryptedRange(&HTTPRangeSpec{false, skipLen, skipLen + readLen - 1}) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Errorf("Case %d: unexpected err: %v", i, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			oRef, lRef, skipRef, snRef, psRef := decryptedRangeRef(test.decSizes, skipLen, readLen, false) | 
					
						
							|  |  |  | 			if o != oRef || l != lRef || skip != skipRef || sn != snRef || ps != psRef { | 
					
						
							|  |  |  | 				t.Errorf("Case %d: test failed: %d %d %d %d %d (Ref: %d %d %d %d %d)", | 
					
						
							|  |  |  | 					i, o, l, skip, sn, ps, oRef, lRef, skipRef, snRef, psRef) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Read the last 6Mib+1 bytes of the (decrypted)
 | 
					
						
							|  |  |  | 		// object
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// The check below ensures the object is large enough
 | 
					
						
							|  |  |  | 		// for the read.
 | 
					
						
							|  |  |  | 		readLen := int64(6)*humanize.MiByte + 1 | 
					
						
							|  |  |  | 		if lsum(test.decSizes) >= readLen { | 
					
						
							|  |  |  | 			o, l, skip, sn, ps, err := test.oi.GetDecryptedRange(&HTTPRangeSpec{true, -readLen, -1}) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Errorf("Case %d: unexpected err: %v", i, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			oRef, lRef, skipRef, snRef, psRef := decryptedRangeRef(test.decSizes, 0, readLen, true) | 
					
						
							|  |  |  | 			if o != oRef || l != lRef || skip != skipRef || sn != snRef || ps != psRef { | 
					
						
							|  |  |  | 				t.Errorf("Case %d: test failed: %d %d %d %d %d (Ref: %d %d %d %d %d)", | 
					
						
							|  |  |  | 					i, o, l, skip, sn, ps, oRef, lRef, skipRef, snRef, psRef) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-01-06 06:16:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-09 13:31:06 +08:00
										 |  |  | var getDefaultOptsTests = []struct { | 
					
						
							| 
									
										
										
										
											2019-01-06 06:16:43 +08:00
										 |  |  | 	headers        http.Header | 
					
						
							|  |  |  | 	copySource     bool | 
					
						
							|  |  |  | 	metadata       map[string]string | 
					
						
							|  |  |  | 	encryptionType encrypt.Type | 
					
						
							|  |  |  | 	err            error | 
					
						
							|  |  |  | }{ | 
					
						
							|  |  |  | 	{headers: http.Header{crypto.SSECAlgorithm: []string{"AES256"}, | 
					
						
							|  |  |  | 		crypto.SSECKey:    []string{"MzJieXRlc2xvbmdzZWNyZXRrZXltdXN0cHJvdmlkZWQ="}, | 
					
						
							|  |  |  | 		crypto.SSECKeyMD5: []string{"7PpPLAK26ONlVUGOWlusfg=="}}, | 
					
						
							|  |  |  | 		copySource:     false, | 
					
						
							|  |  |  | 		metadata:       nil, | 
					
						
							|  |  |  | 		encryptionType: encrypt.SSEC, | 
					
						
							|  |  |  | 		err:            nil}, // 0
 | 
					
						
							|  |  |  | 	{headers: http.Header{crypto.SSECAlgorithm: []string{"AES256"}, | 
					
						
							|  |  |  | 		crypto.SSECKey:    []string{"MzJieXRlc2xvbmdzZWNyZXRrZXltdXN0cHJvdmlkZWQ="}, | 
					
						
							|  |  |  | 		crypto.SSECKeyMD5: []string{"7PpPLAK26ONlVUGOWlusfg=="}}, | 
					
						
							|  |  |  | 		copySource:     true, | 
					
						
							|  |  |  | 		metadata:       nil, | 
					
						
							|  |  |  | 		encryptionType: "", | 
					
						
							|  |  |  | 		err:            nil}, // 1
 | 
					
						
							|  |  |  | 	{headers: http.Header{crypto.SSECAlgorithm: []string{"AES256"}, | 
					
						
							|  |  |  | 		crypto.SSECKey:    []string{"Mz"}, | 
					
						
							|  |  |  | 		crypto.SSECKeyMD5: []string{"7PpPLAK26ONlVUGOWlusfg=="}}, | 
					
						
							|  |  |  | 		copySource:     false, | 
					
						
							|  |  |  | 		metadata:       nil, | 
					
						
							|  |  |  | 		encryptionType: "", | 
					
						
							|  |  |  | 		err:            crypto.ErrInvalidCustomerKey}, // 2
 | 
					
						
							|  |  |  | 	{headers: http.Header{crypto.SSEHeader: []string{"AES256"}}, | 
					
						
							|  |  |  | 		copySource:     false, | 
					
						
							|  |  |  | 		metadata:       nil, | 
					
						
							|  |  |  | 		encryptionType: encrypt.S3, | 
					
						
							|  |  |  | 		err:            nil}, // 3
 | 
					
						
							|  |  |  | 	{headers: http.Header{}, | 
					
						
							|  |  |  | 		copySource: false, | 
					
						
							|  |  |  | 		metadata: map[string]string{crypto.S3SealedKey: base64.StdEncoding.EncodeToString(make([]byte, 64)), | 
					
						
							|  |  |  | 			crypto.S3KMSKeyID:     "kms-key", | 
					
						
							|  |  |  | 			crypto.S3KMSSealedKey: "m-key"}, | 
					
						
							|  |  |  | 		encryptionType: encrypt.S3, | 
					
						
							|  |  |  | 		err:            nil}, // 4
 | 
					
						
							|  |  |  | 	{headers: http.Header{}, | 
					
						
							|  |  |  | 		copySource: true, | 
					
						
							|  |  |  | 		metadata: map[string]string{crypto.S3SealedKey: base64.StdEncoding.EncodeToString(make([]byte, 64)), | 
					
						
							|  |  |  | 			crypto.S3KMSKeyID:     "kms-key", | 
					
						
							|  |  |  | 			crypto.S3KMSSealedKey: "m-key"}, | 
					
						
							|  |  |  | 		encryptionType: "", | 
					
						
							|  |  |  | 		err:            nil}, // 5
 | 
					
						
							|  |  |  | 	{headers: http.Header{crypto.SSECopyAlgorithm: []string{"AES256"}, | 
					
						
							|  |  |  | 		crypto.SSECopyKey:    []string{"MzJieXRlc2xvbmdzZWNyZXRrZXltdXN0cHJvdmlkZWQ="}, | 
					
						
							|  |  |  | 		crypto.SSECopyKeyMD5: []string{"7PpPLAK26ONlVUGOWlusfg=="}}, | 
					
						
							|  |  |  | 		copySource:     true, | 
					
						
							|  |  |  | 		metadata:       nil, | 
					
						
							|  |  |  | 		encryptionType: encrypt.SSEC, | 
					
						
							|  |  |  | 		err:            nil}, // 6
 | 
					
						
							|  |  |  | 	{headers: http.Header{crypto.SSECopyAlgorithm: []string{"AES256"}, | 
					
						
							|  |  |  | 		crypto.SSECopyKey:    []string{"MzJieXRlc2xvbmdzZWNyZXRrZXltdXN0cHJvdmlkZWQ="}, | 
					
						
							|  |  |  | 		crypto.SSECopyKeyMD5: []string{"7PpPLAK26ONlVUGOWlusfg=="}}, | 
					
						
							|  |  |  | 		copySource:     false, | 
					
						
							|  |  |  | 		metadata:       nil, | 
					
						
							|  |  |  | 		encryptionType: "", | 
					
						
							|  |  |  | 		err:            nil}, // 7
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-09 13:31:06 +08:00
										 |  |  | func TestGetDefaultOpts(t *testing.T) { | 
					
						
							|  |  |  | 	for i, test := range getDefaultOptsTests { | 
					
						
							|  |  |  | 		opts, err := getDefaultOpts(test.headers, test.copySource, test.metadata) | 
					
						
							| 
									
										
										
										
											2019-01-06 06:16:43 +08:00
										 |  |  | 		if test.err != err { | 
					
						
							|  |  |  | 			t.Errorf("Case %d: expected err: %v , actual err: %v", i, test.err, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err == nil { | 
					
						
							|  |  |  | 			if opts.ServerSideEncryption == nil && test.encryptionType != "" { | 
					
						
							|  |  |  | 				t.Errorf("Case %d: expected opts to be of %v encryption type", i, test.encryptionType) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if opts.ServerSideEncryption != nil && test.encryptionType != opts.ServerSideEncryption.Type() { | 
					
						
							|  |  |  | 				t.Errorf("Case %d: expected opts to have encryption type %v but was %v ", i, test.encryptionType, opts.ServerSideEncryption.Type()) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |