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

     1  /*
     2   * MinIO Cloud Storage, (C) 2017, 2018 MinIO, Inc.
     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 cmd
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/base64"
    22  	"net/http"
    23  	"testing"
    24  
    25  	humanize "github.com/dustin/go-humanize"
    26  	"github.com/minio/minio-go/v7/pkg/encrypt"
    27  	"github.com/minio/sio"
    28  
    29  	"storj.io/minio/cmd/crypto"
    30  	xhttp "storj.io/minio/cmd/http"
    31  )
    32  
    33  var encryptRequestTests = []struct {
    34  	header   map[string]string
    35  	metadata map[string]string
    36  }{
    37  	{
    38  		header: map[string]string{
    39  			xhttp.AmzServerSideEncryptionCustomerAlgorithm: "AES256",
    40  			xhttp.AmzServerSideEncryptionCustomerKey:       "XAm0dRrJsEsyPb1UuFNezv1bl9hxuYsgUVC/MUctE2k=",
    41  			xhttp.AmzServerSideEncryptionCustomerKeyMD5:    "bY4wkxQejw9mUJfo72k53A==",
    42  		},
    43  		metadata: map[string]string{},
    44  	},
    45  	{
    46  		header: map[string]string{
    47  			xhttp.AmzServerSideEncryptionCustomerAlgorithm: "AES256",
    48  			xhttp.AmzServerSideEncryptionCustomerKey:       "XAm0dRrJsEsyPb1UuFNezv1bl9hxuYsgUVC/MUctE2k=",
    49  			xhttp.AmzServerSideEncryptionCustomerKeyMD5:    "bY4wkxQejw9mUJfo72k53A==",
    50  		},
    51  		metadata: map[string]string{
    52  			xhttp.AmzServerSideEncryptionCustomerKey: "XAm0dRrJsEsyPb1UuFNezv1bl9hxuYsgUVC/MUctE2k=",
    53  		},
    54  	},
    55  }
    56  
    57  func TestEncryptRequest(t *testing.T) {
    58  	defer func(flag bool) { GlobalIsTLS = flag }(GlobalIsTLS)
    59  	GlobalIsTLS = true
    60  	for i, test := range encryptRequestTests {
    61  		content := bytes.NewReader(make([]byte, 64))
    62  		req := &http.Request{Header: http.Header{}}
    63  		for k, v := range test.header {
    64  			req.Header.Set(k, v)
    65  		}
    66  		_, _, err := EncryptRequest(content, req, "bucket", "object", test.metadata)
    67  
    68  		if err != nil {
    69  			t.Fatalf("Test %d: Failed to encrypt request: %v", i, err)
    70  		}
    71  		if kdf, ok := test.metadata[crypto.MetaAlgorithm]; !ok {
    72  			t.Errorf("Test %d: ServerSideEncryptionKDF must be part of metadata: %v", i, kdf)
    73  		}
    74  		if iv, ok := test.metadata[crypto.MetaIV]; !ok {
    75  			t.Errorf("Test %d: crypto.SSEIV must be part of metadata: %v", i, iv)
    76  		}
    77  		if mac, ok := test.metadata[crypto.MetaSealedKeySSEC]; !ok {
    78  			t.Errorf("Test %d: ServerSideEncryptionKeyMAC must be part of metadata: %v", i, mac)
    79  		}
    80  	}
    81  }
    82  
    83  var decryptObjectInfoTests = []struct {
    84  	info    ObjectInfo
    85  	request *http.Request
    86  	expErr  error
    87  }{
    88  	{
    89  		info:    ObjectInfo{Size: 100},
    90  		request: &http.Request{Header: http.Header{}},
    91  		expErr:  nil,
    92  	},
    93  	{
    94  		info:    ObjectInfo{Size: 100, UserDefined: map[string]string{crypto.MetaAlgorithm: crypto.InsecureSealAlgorithm}},
    95  		request: &http.Request{Header: http.Header{xhttp.AmzServerSideEncryption: []string{xhttp.AmzEncryptionAES}}},
    96  		expErr:  nil,
    97  	},
    98  	{
    99  		info:    ObjectInfo{Size: 0, UserDefined: map[string]string{crypto.MetaAlgorithm: crypto.InsecureSealAlgorithm}},
   100  		request: &http.Request{Header: http.Header{xhttp.AmzServerSideEncryption: []string{xhttp.AmzEncryptionAES}}},
   101  		expErr:  nil,
   102  	},
   103  	{
   104  		info:    ObjectInfo{Size: 100, UserDefined: map[string]string{crypto.MetaSealedKeySSEC: "EAAfAAAAAAD7v1hQq3PFRUHsItalxmrJqrOq6FwnbXNarxOOpb8jTWONPPKyM3Gfjkjyj6NCf+aB/VpHCLCTBA=="}},
   105  		request: &http.Request{Header: http.Header{}},
   106  		expErr:  errEncryptedObject,
   107  	},
   108  	{
   109  		info:    ObjectInfo{Size: 100, UserDefined: map[string]string{}},
   110  		request: &http.Request{Method: http.MethodGet, Header: http.Header{xhttp.AmzServerSideEncryptionCustomerAlgorithm: []string{xhttp.AmzEncryptionAES}}},
   111  		expErr:  errInvalidEncryptionParameters,
   112  	},
   113  	{
   114  		info:    ObjectInfo{Size: 100, UserDefined: map[string]string{}},
   115  		request: &http.Request{Method: http.MethodHead, Header: http.Header{xhttp.AmzServerSideEncryptionCustomerAlgorithm: []string{xhttp.AmzEncryptionAES}}},
   116  		expErr:  errInvalidEncryptionParameters,
   117  	},
   118  	{
   119  		info:    ObjectInfo{Size: 31, UserDefined: map[string]string{crypto.MetaAlgorithm: crypto.InsecureSealAlgorithm}},
   120  		request: &http.Request{Header: http.Header{xhttp.AmzServerSideEncryptionCustomerAlgorithm: []string{xhttp.AmzEncryptionAES}}},
   121  		expErr:  errObjectTampered,
   122  	},
   123  }
   124  
   125  func TestDecryptObjectInfo(t *testing.T) {
   126  	for i, test := range decryptObjectInfoTests {
   127  		if encrypted, err := DecryptObjectInfo(&test.info, test.request); err != test.expErr {
   128  			t.Errorf("Test %d: Decryption returned wrong error code: got %d , want %d", i, err, test.expErr)
   129  		} else if _, enc := crypto.IsEncrypted(test.info.UserDefined); encrypted && enc != encrypted {
   130  			t.Errorf("Test %d: Decryption thinks object is encrypted but it is not", i)
   131  		} else if !encrypted && enc != encrypted {
   132  			t.Errorf("Test %d: Decryption thinks object is not encrypted but it is", i)
   133  		}
   134  	}
   135  }
   136  
   137  var decryptETagTests = []struct {
   138  	ObjectKey  crypto.ObjectKey
   139  	ObjectInfo ObjectInfo
   140  	ShouldFail bool
   141  	ETag       string
   142  }{
   143  	{
   144  		ObjectKey:  [32]byte{},
   145  		ObjectInfo: ObjectInfo{ETag: "20000f00f27834c9a2654927546df57f9e998187496394d4ee80f3d9978f85f3c7d81f72600cdbe03d80dc5a13d69354"},
   146  		ETag:       "8ad3fe6b84bf38489e95c701c84355b6",
   147  	},
   148  	{
   149  		ObjectKey:  [32]byte{},
   150  		ObjectInfo: ObjectInfo{ETag: "20000f00f27834c9a2654927546df57f9e998187496394d4ee80f3d9978f85f3c7d81f72600cdbe03d80dc5a13d6935"},
   151  		ETag:       "",
   152  		ShouldFail: true, // ETag is not a valid hex value
   153  	},
   154  	{
   155  		ObjectKey:  [32]byte{},
   156  		ObjectInfo: ObjectInfo{ETag: "00000f00f27834c9a2654927546df57f9e998187496394d4ee80f3d9978f85f3c7d81f72600cdbe03d80dc5a13d69354"},
   157  		ETag:       "",
   158  		ShouldFail: true, // modified ETag
   159  	},
   160  
   161  	// Special tests for ETags that end with a '-x'
   162  	{
   163  		ObjectKey:  [32]byte{},
   164  		ObjectInfo: ObjectInfo{ETag: "916516b396f0f4d4f2a0e7177557bec4-1"},
   165  		ETag:       "916516b396f0f4d4f2a0e7177557bec4-1",
   166  	},
   167  	{
   168  		ObjectKey:  [32]byte{},
   169  		ObjectInfo: ObjectInfo{ETag: "916516b396f0f4d4f2a0e7177557bec4-738"},
   170  		ETag:       "916516b396f0f4d4f2a0e7177557bec4-738",
   171  	},
   172  	{
   173  		ObjectKey:  [32]byte{},
   174  		ObjectInfo: ObjectInfo{ETag: "916516b396f0f4d4f2a0e7177557bec4-Q"},
   175  		ETag:       "",
   176  		ShouldFail: true, // Q is not a number
   177  	},
   178  	{
   179  		ObjectKey:  [32]byte{},
   180  		ObjectInfo: ObjectInfo{ETag: "16516b396f0f4d4f2a0e7177557bec4-1"},
   181  		ETag:       "",
   182  		ShouldFail: true, // ETag prefix is not a valid hex value
   183  	},
   184  	{
   185  		ObjectKey:  [32]byte{},
   186  		ObjectInfo: ObjectInfo{ETag: "16516b396f0f4d4f2a0e7177557bec4-1-2"},
   187  		ETag:       "",
   188  		ShouldFail: true, // ETag contains multiple: -
   189  	},
   190  }
   191  
   192  func TestDecryptETag(t *testing.T) {
   193  	for i, test := range decryptETagTests {
   194  		etag, err := DecryptETag(test.ObjectKey, test.ObjectInfo)
   195  		if err != nil && !test.ShouldFail {
   196  			t.Fatalf("Test %d: should succeed but failed: %v", i, err)
   197  		}
   198  		if err == nil && test.ShouldFail {
   199  			t.Fatalf("Test %d: should fail but succeeded", i)
   200  		}
   201  		if err == nil {
   202  			if etag != test.ETag {
   203  				t.Fatalf("Test %d: ETag mismatch: got %s - want %s", i, etag, test.ETag)
   204  			}
   205  		}
   206  	}
   207  }
   208  
   209  // Tests for issue reproduced when getting the right encrypted
   210  // offset of the object.
   211  func TestGetDecryptedRange_Issue50(t *testing.T) {
   212  	rs, err := parseRequestRangeSpec("bytes=594870256-594870263")
   213  	if err != nil {
   214  		t.Fatal(err)
   215  	}
   216  
   217  	objInfo := ObjectInfo{
   218  		Bucket: "bucket",
   219  		Name:   "object",
   220  		Size:   595160760,
   221  		UserDefined: map[string]string{
   222  			crypto.MetaMultipart:                   "",
   223  			crypto.MetaIV:                          "HTexa=",
   224  			crypto.MetaAlgorithm:                   "DAREv2-HMAC-SHA256",
   225  			crypto.MetaSealedKeySSEC:               "IAA8PGAA==",
   226  			ReservedMetadataPrefix + "actual-size": "594870264",
   227  			"content-type":                         "application/octet-stream",
   228  			"etag":                                 "166b1545b4c1535294ee0686678bea8c-2",
   229  		},
   230  		Parts: []ObjectPartInfo{
   231  			{
   232  				Number:     1,
   233  				Size:       297580380,
   234  				ActualSize: 297435132,
   235  			},
   236  			{
   237  				Number:     2,
   238  				Size:       297580380,
   239  				ActualSize: 297435132,
   240  			},
   241  		},
   242  	}
   243  
   244  	encOff, encLength, skipLen, seqNumber, partStart, err := objInfo.GetDecryptedRange(rs)
   245  	if err != nil {
   246  		t.Fatalf("Test: failed %s", err)
   247  	}
   248  	if encOff != 595127964 {
   249  		t.Fatalf("Test: expected %d, got %d", 595127964, encOff)
   250  	}
   251  	if encLength != 32796 {
   252  		t.Fatalf("Test: expected %d, got %d", 32796, encLength)
   253  	}
   254  	if skipLen != 32756 {
   255  		t.Fatalf("Test: expected %d, got %d", 32756, skipLen)
   256  	}
   257  	if seqNumber != 4538 {
   258  		t.Fatalf("Test: expected %d, got %d", 4538, seqNumber)
   259  	}
   260  	if partStart != 1 {
   261  		t.Fatalf("Test: expected %d, got %d", 1, partStart)
   262  	}
   263  }
   264  
   265  func TestGetDecryptedRange(t *testing.T) {
   266  	var (
   267  		pkgSz     = int64(64) * humanize.KiByte
   268  		minPartSz = int64(5) * humanize.MiByte
   269  		maxPartSz = int64(5) * humanize.GiByte
   270  
   271  		getEncSize = func(s int64) int64 {
   272  			v, _ := sio.EncryptedSize(uint64(s))
   273  			return int64(v)
   274  		}
   275  		udMap = func(isMulti bool) map[string]string {
   276  			m := map[string]string{
   277  				crypto.MetaAlgorithm: crypto.InsecureSealAlgorithm,
   278  				crypto.MetaMultipart: "1",
   279  			}
   280  			if !isMulti {
   281  				delete(m, crypto.MetaMultipart)
   282  			}
   283  			return m
   284  		}
   285  	)
   286  
   287  	// Single part object tests
   288  	var (
   289  		mkSPObj = func(s int64) ObjectInfo {
   290  			return ObjectInfo{
   291  				Size:        getEncSize(s),
   292  				UserDefined: udMap(false),
   293  			}
   294  		}
   295  	)
   296  
   297  	testSP := []struct {
   298  		decSz int64
   299  		oi    ObjectInfo
   300  	}{
   301  		{0, mkSPObj(0)},
   302  		{1, mkSPObj(1)},
   303  		{pkgSz - 1, mkSPObj(pkgSz - 1)},
   304  		{pkgSz, mkSPObj(pkgSz)},
   305  		{2*pkgSz - 1, mkSPObj(2*pkgSz - 1)},
   306  		{minPartSz, mkSPObj(minPartSz)},
   307  		{maxPartSz, mkSPObj(maxPartSz)},
   308  	}
   309  
   310  	for i, test := range testSP {
   311  		{
   312  			// nil range
   313  			o, l, skip, sn, ps, err := test.oi.GetDecryptedRange(nil)
   314  			if err != nil {
   315  				t.Errorf("Case %d: unexpected err: %v", i, err)
   316  			}
   317  			if skip != 0 || sn != 0 || ps != 0 || o != 0 || l != getEncSize(test.decSz) {
   318  				t.Errorf("Case %d: test failed: %d %d %d %d %d", i, o, l, skip, sn, ps)
   319  			}
   320  		}
   321  
   322  		if test.decSz >= 10 {
   323  			// first 10 bytes
   324  			o, l, skip, sn, ps, err := test.oi.GetDecryptedRange(&HTTPRangeSpec{false, 0, 9})
   325  			if err != nil {
   326  				t.Errorf("Case %d: unexpected err: %v", i, err)
   327  			}
   328  			var rLen = pkgSz + 32
   329  			if test.decSz < pkgSz {
   330  				rLen = test.decSz + 32
   331  			}
   332  			if skip != 0 || sn != 0 || ps != 0 || o != 0 || l != rLen {
   333  				t.Errorf("Case %d: test failed: %d %d %d %d %d", i, o, l, skip, sn, ps)
   334  			}
   335  		}
   336  
   337  		kb32 := int64(32) * humanize.KiByte
   338  		if test.decSz >= (64+32)*humanize.KiByte {
   339  			// Skip the first 32Kib, and read the next 64Kib
   340  			o, l, skip, sn, ps, err := test.oi.GetDecryptedRange(&HTTPRangeSpec{false, kb32, 3*kb32 - 1})
   341  			if err != nil {
   342  				t.Errorf("Case %d: unexpected err: %v", i, err)
   343  			}
   344  			var rLen = (pkgSz + 32) * 2
   345  			if test.decSz < 2*pkgSz {
   346  				rLen = (pkgSz + 32) + (test.decSz - pkgSz + 32)
   347  			}
   348  			if skip != kb32 || sn != 0 || ps != 0 || o != 0 || l != rLen {
   349  				t.Errorf("Case %d: test failed: %d %d %d %d %d", i, o, l, skip, sn, ps)
   350  			}
   351  		}
   352  
   353  		if test.decSz >= (64*2+32)*humanize.KiByte {
   354  			// Skip the first 96Kib and read the next 64Kib
   355  			o, l, skip, sn, ps, err := test.oi.GetDecryptedRange(&HTTPRangeSpec{false, 3 * kb32, 5*kb32 - 1})
   356  			if err != nil {
   357  				t.Errorf("Case %d: unexpected err: %v", i, err)
   358  			}
   359  			var rLen = (pkgSz + 32) * 2
   360  			if test.decSz-pkgSz < 2*pkgSz {
   361  				rLen = (pkgSz + 32) + (test.decSz - pkgSz + 32*2)
   362  			}
   363  			if skip != kb32 || sn != 1 || ps != 0 || o != pkgSz+32 || l != rLen {
   364  				t.Errorf("Case %d: test failed: %d %d %d %d %d", i, o, l, skip, sn, ps)
   365  			}
   366  		}
   367  
   368  	}
   369  
   370  	// Multipart object tests
   371  	var (
   372  		// make a multipart object-info given part sizes
   373  		mkMPObj = func(sizes []int64) ObjectInfo {
   374  			r := make([]ObjectPartInfo, len(sizes))
   375  			sum := int64(0)
   376  			for i, s := range sizes {
   377  				r[i].Number = i
   378  				r[i].Size = getEncSize(s)
   379  				sum += r[i].Size
   380  			}
   381  			return ObjectInfo{
   382  				Size:        sum,
   383  				UserDefined: udMap(true),
   384  				Parts:       r,
   385  			}
   386  		}
   387  		// Simple useful utilities
   388  		repeat = func(k int64, n int) []int64 {
   389  			a := []int64{}
   390  			for i := 0; i < n; i++ {
   391  				a = append(a, k)
   392  			}
   393  			return a
   394  		}
   395  		lsum = func(s []int64) int64 {
   396  			sum := int64(0)
   397  			for _, i := range s {
   398  				if i < 0 {
   399  					return -1
   400  				}
   401  				sum += i
   402  			}
   403  			return sum
   404  		}
   405  		esum = func(oi ObjectInfo) int64 {
   406  			sum := int64(0)
   407  			for _, i := range oi.Parts {
   408  				sum += i.Size
   409  			}
   410  			return sum
   411  		}
   412  	)
   413  
   414  	s1 := []int64{5487701, 5487799, 3}
   415  	s2 := repeat(5487701, 5)
   416  	s3 := repeat(maxPartSz, 10000)
   417  	testMPs := []struct {
   418  		decSizes []int64
   419  		oi       ObjectInfo
   420  	}{
   421  		{s1, mkMPObj(s1)},
   422  		{s2, mkMPObj(s2)},
   423  		{s3, mkMPObj(s3)},
   424  	}
   425  
   426  	// This function is a reference (re-)implementation of
   427  	// decrypted range computation, written solely for the purpose
   428  	// of the unit tests.
   429  	//
   430  	// `s` gives the decrypted part sizes, and the other
   431  	// parameters describe the desired read segment. When
   432  	// `isFromEnd` is true, `skipLen` argument is ignored.
   433  	decryptedRangeRef := func(s []int64, skipLen, readLen int64, isFromEnd bool) (o, l, skip int64, sn uint32, ps int) {
   434  		oSize := lsum(s)
   435  		if isFromEnd {
   436  			skipLen = oSize - readLen
   437  		}
   438  		if skipLen < 0 || readLen < 0 || oSize < 0 || skipLen+readLen > oSize {
   439  			t.Fatalf("Impossible read specified: %d %d %d", skipLen, readLen, oSize)
   440  		}
   441  
   442  		var cumulativeSum, cumulativeEncSum int64
   443  		toRead := readLen
   444  		readStart := false
   445  		for i, v := range s {
   446  			partOffset := int64(0)
   447  			partDarePkgOffset := int64(0)
   448  			if !readStart && cumulativeSum+v > skipLen {
   449  				// Read starts at the current part
   450  				readStart = true
   451  
   452  				partOffset = skipLen - cumulativeSum
   453  
   454  				// All return values except `l` are
   455  				// calculated here.
   456  				sn = uint32(partOffset / pkgSz)
   457  				skip = partOffset % pkgSz
   458  				ps = i
   459  				o = cumulativeEncSum + int64(sn)*(pkgSz+32)
   460  
   461  				partDarePkgOffset = partOffset - skip
   462  			}
   463  			if readStart {
   464  				currentPartBytes := v - partOffset
   465  				currentPartDareBytes := v - partDarePkgOffset
   466  				if currentPartBytes < toRead {
   467  					toRead -= currentPartBytes
   468  					l += getEncSize(currentPartDareBytes)
   469  				} else {
   470  					// current part has the last
   471  					// byte required
   472  					lbPartOffset := partOffset + toRead - 1
   473  
   474  					// round up the lbPartOffset
   475  					// to the end of the
   476  					// corresponding DARE package
   477  					lbPkgEndOffset := lbPartOffset - (lbPartOffset % pkgSz) + pkgSz
   478  					if lbPkgEndOffset > v {
   479  						lbPkgEndOffset = v
   480  					}
   481  					bytesToDrop := v - lbPkgEndOffset
   482  
   483  					// Last segment to update `l`
   484  					l += getEncSize(currentPartDareBytes - bytesToDrop)
   485  					break
   486  				}
   487  			}
   488  
   489  			cumulativeSum += v
   490  			cumulativeEncSum += getEncSize(v)
   491  		}
   492  		return
   493  	}
   494  
   495  	for i, test := range testMPs {
   496  		{
   497  			// nil range
   498  			o, l, skip, sn, ps, err := test.oi.GetDecryptedRange(nil)
   499  			if err != nil {
   500  				t.Errorf("Case %d: unexpected err: %v", i, err)
   501  			}
   502  			if o != 0 || l != esum(test.oi) || skip != 0 || sn != 0 || ps != 0 {
   503  				t.Errorf("Case %d: test failed: %d %d %d %d %d", i, o, l, skip, sn, ps)
   504  			}
   505  		}
   506  
   507  		// Skip 1Mib and read 1Mib (in the decrypted object)
   508  		//
   509  		// The check below ensures the object is large enough
   510  		// for the read.
   511  		if lsum(test.decSizes) >= 2*humanize.MiByte {
   512  			skipLen, readLen := int64(1)*humanize.MiByte, int64(1)*humanize.MiByte
   513  			o, l, skip, sn, ps, err := test.oi.GetDecryptedRange(&HTTPRangeSpec{false, skipLen, skipLen + readLen - 1})
   514  			if err != nil {
   515  				t.Errorf("Case %d: unexpected err: %v", i, err)
   516  			}
   517  
   518  			oRef, lRef, skipRef, snRef, psRef := decryptedRangeRef(test.decSizes, skipLen, readLen, false)
   519  			if o != oRef || l != lRef || skip != skipRef || sn != snRef || ps != psRef {
   520  				t.Errorf("Case %d: test failed: %d %d %d %d %d (Ref: %d %d %d %d %d)",
   521  					i, o, l, skip, sn, ps, oRef, lRef, skipRef, snRef, psRef)
   522  			}
   523  		}
   524  
   525  		// Read the last 6Mib+1 bytes of the (decrypted)
   526  		// object
   527  		//
   528  		// The check below ensures the object is large enough
   529  		// for the read.
   530  		readLen := int64(6)*humanize.MiByte + 1
   531  		if lsum(test.decSizes) >= readLen {
   532  			o, l, skip, sn, ps, err := test.oi.GetDecryptedRange(&HTTPRangeSpec{true, -readLen, -1})
   533  			if err != nil {
   534  				t.Errorf("Case %d: unexpected err: %v", i, err)
   535  			}
   536  
   537  			oRef, lRef, skipRef, snRef, psRef := decryptedRangeRef(test.decSizes, 0, readLen, true)
   538  			if o != oRef || l != lRef || skip != skipRef || sn != snRef || ps != psRef {
   539  				t.Errorf("Case %d: test failed: %d %d %d %d %d (Ref: %d %d %d %d %d)",
   540  					i, o, l, skip, sn, ps, oRef, lRef, skipRef, snRef, psRef)
   541  			}
   542  		}
   543  
   544  	}
   545  }
   546  
   547  var getDefaultOptsTests = []struct {
   548  	headers        http.Header
   549  	copySource     bool
   550  	metadata       map[string]string
   551  	encryptionType encrypt.Type
   552  	err            error
   553  }{
   554  	{headers: http.Header{xhttp.AmzServerSideEncryptionCustomerAlgorithm: []string{"AES256"},
   555  		xhttp.AmzServerSideEncryptionCustomerKey:    []string{"MzJieXRlc2xvbmdzZWNyZXRrZXltdXN0cHJvdmlkZWQ="},
   556  		xhttp.AmzServerSideEncryptionCustomerKeyMD5: []string{"7PpPLAK26ONlVUGOWlusfg=="}},
   557  		copySource:     false,
   558  		metadata:       nil,
   559  		encryptionType: encrypt.SSEC,
   560  		err:            nil}, // 0
   561  	{headers: http.Header{xhttp.AmzServerSideEncryptionCustomerAlgorithm: []string{"AES256"},
   562  		xhttp.AmzServerSideEncryptionCustomerKey:    []string{"MzJieXRlc2xvbmdzZWNyZXRrZXltdXN0cHJvdmlkZWQ="},
   563  		xhttp.AmzServerSideEncryptionCustomerKeyMD5: []string{"7PpPLAK26ONlVUGOWlusfg=="}},
   564  		copySource:     true,
   565  		metadata:       nil,
   566  		encryptionType: "",
   567  		err:            nil}, // 1
   568  	{headers: http.Header{xhttp.AmzServerSideEncryptionCustomerAlgorithm: []string{"AES256"},
   569  		xhttp.AmzServerSideEncryptionCustomerKey:    []string{"Mz"},
   570  		xhttp.AmzServerSideEncryptionCustomerKeyMD5: []string{"7PpPLAK26ONlVUGOWlusfg=="}},
   571  		copySource:     false,
   572  		metadata:       nil,
   573  		encryptionType: "",
   574  		err:            crypto.ErrInvalidCustomerKey}, // 2
   575  	{headers: http.Header{xhttp.AmzServerSideEncryption: []string{"AES256"}},
   576  		copySource:     false,
   577  		metadata:       nil,
   578  		encryptionType: encrypt.S3,
   579  		err:            nil}, // 3
   580  	{headers: http.Header{},
   581  		copySource: false,
   582  		metadata: map[string]string{crypto.MetaSealedKeyS3: base64.StdEncoding.EncodeToString(make([]byte, 64)),
   583  			crypto.MetaKeyID:             "kms-key",
   584  			crypto.MetaDataEncryptionKey: "m-key"},
   585  		encryptionType: encrypt.S3,
   586  		err:            nil}, // 4
   587  	{headers: http.Header{},
   588  		copySource: true,
   589  		metadata: map[string]string{crypto.MetaSealedKeyS3: base64.StdEncoding.EncodeToString(make([]byte, 64)),
   590  			crypto.MetaKeyID:             "kms-key",
   591  			crypto.MetaDataEncryptionKey: "m-key"},
   592  		encryptionType: "",
   593  		err:            nil}, // 5
   594  	{headers: http.Header{xhttp.AmzServerSideEncryptionCopyCustomerAlgorithm: []string{"AES256"},
   595  		xhttp.AmzServerSideEncryptionCopyCustomerKey:    []string{"MzJieXRlc2xvbmdzZWNyZXRrZXltdXN0cHJvdmlkZWQ="},
   596  		xhttp.AmzServerSideEncryptionCopyCustomerKeyMD5: []string{"7PpPLAK26ONlVUGOWlusfg=="}},
   597  		copySource:     true,
   598  		metadata:       nil,
   599  		encryptionType: encrypt.SSEC,
   600  		err:            nil}, // 6
   601  	{headers: http.Header{xhttp.AmzServerSideEncryptionCopyCustomerAlgorithm: []string{"AES256"},
   602  		xhttp.AmzServerSideEncryptionCopyCustomerKey:    []string{"MzJieXRlc2xvbmdzZWNyZXRrZXltdXN0cHJvdmlkZWQ="},
   603  		xhttp.AmzServerSideEncryptionCopyCustomerKeyMD5: []string{"7PpPLAK26ONlVUGOWlusfg=="}},
   604  		copySource:     false,
   605  		metadata:       nil,
   606  		encryptionType: "",
   607  		err:            nil}, // 7
   608  }
   609  
   610  func TestGetDefaultOpts(t *testing.T) {
   611  	for i, test := range getDefaultOptsTests {
   612  		opts, err := getDefaultOpts(test.headers, test.copySource, test.metadata)
   613  		if test.err != err {
   614  			t.Errorf("Case %d: expected err: %v , actual err: %v", i, test.err, err)
   615  		}
   616  		if err == nil {
   617  			if opts.ServerSideEncryption == nil && test.encryptionType != "" {
   618  				t.Errorf("Case %d: expected opts to be of %v encryption type", i, test.encryptionType)
   619  			}
   620  			if opts.ServerSideEncryption != nil && test.encryptionType != opts.ServerSideEncryption.Type() {
   621  				t.Errorf("Case %d: expected opts to have encryption type %v but was %v ", i, test.encryptionType, opts.ServerSideEncryption.Type())
   622  			}
   623  		}
   624  	}
   625  }