You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							517 lines
						
					
					
						
							15 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							517 lines
						
					
					
						
							15 KiB
						
					
					
				
								package s3api
							 | 
						|
								
							 | 
						|
								import (
							 | 
						|
									"bytes"
							 | 
						|
									"fmt"
							 | 
						|
									"io"
							 | 
						|
									"strings"
							 | 
						|
									"testing"
							 | 
						|
									
							 | 
						|
									"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
							 | 
						|
								)
							 | 
						|
								
							 | 
						|
								// TestSSECMultipartUpload tests SSE-C with multipart uploads
							 | 
						|
								func TestSSECMultipartUpload(t *testing.T) {
							 | 
						|
									keyPair := GenerateTestSSECKey(1)
							 | 
						|
									customerKey := &SSECustomerKey{
							 | 
						|
										Algorithm: "AES256",
							 | 
						|
										Key:       keyPair.Key,
							 | 
						|
										KeyMD5:    keyPair.KeyMD5,
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Test data larger than typical part size
							 | 
						|
									testData := strings.Repeat("Hello, SSE-C multipart world! ", 1000) // ~30KB
							 | 
						|
								
							 | 
						|
									t.Run("Single part encryption/decryption", func(t *testing.T) {
							 | 
						|
										// Encrypt the data
							 | 
						|
										encryptedReader, iv, err := CreateSSECEncryptedReader(strings.NewReader(testData), customerKey)
							 | 
						|
										if err != nil {
							 | 
						|
											t.Fatalf("Failed to create encrypted reader: %v", err)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										encryptedData, err := io.ReadAll(encryptedReader)
							 | 
						|
										if err != nil {
							 | 
						|
											t.Fatalf("Failed to read encrypted data: %v", err)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Decrypt the data
							 | 
						|
										decryptedReader, err := CreateSSECDecryptedReader(bytes.NewReader(encryptedData), customerKey, iv)
							 | 
						|
										if err != nil {
							 | 
						|
											t.Fatalf("Failed to create decrypted reader: %v", err)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										decryptedData, err := io.ReadAll(decryptedReader)
							 | 
						|
										if err != nil {
							 | 
						|
											t.Fatalf("Failed to read decrypted data: %v", err)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										if string(decryptedData) != testData {
							 | 
						|
											t.Error("Decrypted data doesn't match original")
							 | 
						|
										}
							 | 
						|
									})
							 | 
						|
								
							 | 
						|
									t.Run("Simulated multipart upload parts", func(t *testing.T) {
							 | 
						|
										// Simulate multiple parts (each part gets encrypted separately)
							 | 
						|
										partSize := 5 * 1024 // 5KB parts
							 | 
						|
										var encryptedParts [][]byte
							 | 
						|
										var partIVs [][]byte
							 | 
						|
								
							 | 
						|
										for i := 0; i < len(testData); i += partSize {
							 | 
						|
											end := i + partSize
							 | 
						|
											if end > len(testData) {
							 | 
						|
												end = len(testData)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											partData := testData[i:end]
							 | 
						|
								
							 | 
						|
											// Each part is encrypted separately in multipart uploads
							 | 
						|
											encryptedReader, iv, err := CreateSSECEncryptedReader(strings.NewReader(partData), customerKey)
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to create encrypted reader for part %d: %v", i/partSize, err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											encryptedPart, err := io.ReadAll(encryptedReader)
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to read encrypted part %d: %v", i/partSize, err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											encryptedParts = append(encryptedParts, encryptedPart)
							 | 
						|
											partIVs = append(partIVs, iv)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Simulate reading back the multipart object
							 | 
						|
										var reconstructedData strings.Builder
							 | 
						|
								
							 | 
						|
										for i, encryptedPart := range encryptedParts {
							 | 
						|
											decryptedReader, err := CreateSSECDecryptedReader(bytes.NewReader(encryptedPart), customerKey, partIVs[i])
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to create decrypted reader for part %d: %v", i, err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											decryptedPart, err := io.ReadAll(decryptedReader)
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to read decrypted part %d: %v", i, err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											reconstructedData.Write(decryptedPart)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										if reconstructedData.String() != testData {
							 | 
						|
											t.Error("Reconstructed multipart data doesn't match original")
							 | 
						|
										}
							 | 
						|
									})
							 | 
						|
								
							 | 
						|
									t.Run("Multipart with different part sizes", func(t *testing.T) {
							 | 
						|
										partSizes := []int{1024, 2048, 4096, 8192} // Various part sizes
							 | 
						|
								
							 | 
						|
										for _, partSize := range partSizes {
							 | 
						|
											t.Run(fmt.Sprintf("PartSize_%d", partSize), func(t *testing.T) {
							 | 
						|
												var encryptedParts [][]byte
							 | 
						|
												var partIVs [][]byte
							 | 
						|
								
							 | 
						|
												for i := 0; i < len(testData); i += partSize {
							 | 
						|
													end := i + partSize
							 | 
						|
													if end > len(testData) {
							 | 
						|
														end = len(testData)
							 | 
						|
													}
							 | 
						|
								
							 | 
						|
													partData := testData[i:end]
							 | 
						|
								
							 | 
						|
													encryptedReader, iv, err := CreateSSECEncryptedReader(strings.NewReader(partData), customerKey)
							 | 
						|
													if err != nil {
							 | 
						|
														t.Fatalf("Failed to create encrypted reader: %v", err)
							 | 
						|
													}
							 | 
						|
								
							 | 
						|
													encryptedPart, err := io.ReadAll(encryptedReader)
							 | 
						|
													if err != nil {
							 | 
						|
														t.Fatalf("Failed to read encrypted part: %v", err)
							 | 
						|
													}
							 | 
						|
								
							 | 
						|
													encryptedParts = append(encryptedParts, encryptedPart)
							 | 
						|
													partIVs = append(partIVs, iv)
							 | 
						|
												}
							 | 
						|
								
							 | 
						|
												// Verify reconstruction
							 | 
						|
												var reconstructedData strings.Builder
							 | 
						|
								
							 | 
						|
												for j, encryptedPart := range encryptedParts {
							 | 
						|
													decryptedReader, err := CreateSSECDecryptedReader(bytes.NewReader(encryptedPart), customerKey, partIVs[j])
							 | 
						|
													if err != nil {
							 | 
						|
														t.Fatalf("Failed to create decrypted reader: %v", err)
							 | 
						|
													}
							 | 
						|
								
							 | 
						|
													decryptedPart, err := io.ReadAll(decryptedReader)
							 | 
						|
													if err != nil {
							 | 
						|
														t.Fatalf("Failed to read decrypted part: %v", err)
							 | 
						|
													}
							 | 
						|
								
							 | 
						|
													reconstructedData.Write(decryptedPart)
							 | 
						|
												}
							 | 
						|
								
							 | 
						|
												if reconstructedData.String() != testData {
							 | 
						|
													t.Errorf("Reconstructed data doesn't match original for part size %d", partSize)
							 | 
						|
												}
							 | 
						|
											})
							 | 
						|
										}
							 | 
						|
									})
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// TestSSEKMSMultipartUpload tests SSE-KMS with multipart uploads
							 | 
						|
								func TestSSEKMSMultipartUpload(t *testing.T) {
							 | 
						|
									kmsKey := SetupTestKMS(t)
							 | 
						|
									defer kmsKey.Cleanup()
							 | 
						|
								
							 | 
						|
									// Test data larger than typical part size
							 | 
						|
									testData := strings.Repeat("Hello, SSE-KMS multipart world! ", 1000) // ~30KB
							 | 
						|
									encryptionContext := BuildEncryptionContext("test-bucket", "test-object", false)
							 | 
						|
								
							 | 
						|
									t.Run("Single part encryption/decryption", func(t *testing.T) {
							 | 
						|
										// Encrypt the data
							 | 
						|
										encryptedReader, sseKey, err := CreateSSEKMSEncryptedReader(strings.NewReader(testData), kmsKey.KeyID, encryptionContext)
							 | 
						|
										if err != nil {
							 | 
						|
											t.Fatalf("Failed to create encrypted reader: %v", err)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										encryptedData, err := io.ReadAll(encryptedReader)
							 | 
						|
										if err != nil {
							 | 
						|
											t.Fatalf("Failed to read encrypted data: %v", err)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Decrypt the data
							 | 
						|
										decryptedReader, err := CreateSSEKMSDecryptedReader(bytes.NewReader(encryptedData), sseKey)
							 | 
						|
										if err != nil {
							 | 
						|
											t.Fatalf("Failed to create decrypted reader: %v", err)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										decryptedData, err := io.ReadAll(decryptedReader)
							 | 
						|
										if err != nil {
							 | 
						|
											t.Fatalf("Failed to read decrypted data: %v", err)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										if string(decryptedData) != testData {
							 | 
						|
											t.Error("Decrypted data doesn't match original")
							 | 
						|
										}
							 | 
						|
									})
							 | 
						|
								
							 | 
						|
									t.Run("Simulated multipart upload parts", func(t *testing.T) {
							 | 
						|
										// Simulate multiple parts (each part might use the same or different KMS operations)
							 | 
						|
										partSize := 5 * 1024 // 5KB parts
							 | 
						|
										var encryptedParts [][]byte
							 | 
						|
										var sseKeys []*SSEKMSKey
							 | 
						|
								
							 | 
						|
										for i := 0; i < len(testData); i += partSize {
							 | 
						|
											end := i + partSize
							 | 
						|
											if end > len(testData) {
							 | 
						|
												end = len(testData)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											partData := testData[i:end]
							 | 
						|
								
							 | 
						|
											// Each part might get its own data key in KMS multipart uploads
							 | 
						|
											encryptedReader, sseKey, err := CreateSSEKMSEncryptedReader(strings.NewReader(partData), kmsKey.KeyID, encryptionContext)
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to create encrypted reader for part %d: %v", i/partSize, err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											encryptedPart, err := io.ReadAll(encryptedReader)
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to read encrypted part %d: %v", i/partSize, err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											encryptedParts = append(encryptedParts, encryptedPart)
							 | 
						|
											sseKeys = append(sseKeys, sseKey)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Simulate reading back the multipart object
							 | 
						|
										var reconstructedData strings.Builder
							 | 
						|
								
							 | 
						|
										for i, encryptedPart := range encryptedParts {
							 | 
						|
											decryptedReader, err := CreateSSEKMSDecryptedReader(bytes.NewReader(encryptedPart), sseKeys[i])
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to create decrypted reader for part %d: %v", i, err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											decryptedPart, err := io.ReadAll(decryptedReader)
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to read decrypted part %d: %v", i, err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											reconstructedData.Write(decryptedPart)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										if reconstructedData.String() != testData {
							 | 
						|
											t.Error("Reconstructed multipart data doesn't match original")
							 | 
						|
										}
							 | 
						|
									})
							 | 
						|
								
							 | 
						|
									t.Run("Multipart consistency checks", func(t *testing.T) {
							 | 
						|
										// Test that all parts use the same KMS key ID but different data keys
							 | 
						|
										partSize := 5 * 1024
							 | 
						|
										var sseKeys []*SSEKMSKey
							 | 
						|
								
							 | 
						|
										for i := 0; i < len(testData); i += partSize {
							 | 
						|
											end := i + partSize
							 | 
						|
											if end > len(testData) {
							 | 
						|
												end = len(testData)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											partData := testData[i:end]
							 | 
						|
								
							 | 
						|
											_, sseKey, err := CreateSSEKMSEncryptedReader(strings.NewReader(partData), kmsKey.KeyID, encryptionContext)
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to create encrypted reader: %v", err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											sseKeys = append(sseKeys, sseKey)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Verify all parts use the same KMS key ID
							 | 
						|
										for i, sseKey := range sseKeys {
							 | 
						|
											if sseKey.KeyID != kmsKey.KeyID {
							 | 
						|
												t.Errorf("Part %d has wrong KMS key ID: expected %s, got %s", i, kmsKey.KeyID, sseKey.KeyID)
							 | 
						|
											}
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Verify each part has different encrypted data keys (they should be unique)
							 | 
						|
										for i := 0; i < len(sseKeys); i++ {
							 | 
						|
											for j := i + 1; j < len(sseKeys); j++ {
							 | 
						|
												if bytes.Equal(sseKeys[i].EncryptedDataKey, sseKeys[j].EncryptedDataKey) {
							 | 
						|
													t.Errorf("Parts %d and %d have identical encrypted data keys (should be unique)", i, j)
							 | 
						|
												}
							 | 
						|
											}
							 | 
						|
										}
							 | 
						|
									})
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// TestMultipartSSEMixedScenarios tests edge cases with multipart and SSE
							 | 
						|
								func TestMultipartSSEMixedScenarios(t *testing.T) {
							 | 
						|
									t.Run("Empty parts handling", func(t *testing.T) {
							 | 
						|
										keyPair := GenerateTestSSECKey(1)
							 | 
						|
										customerKey := &SSECustomerKey{
							 | 
						|
											Algorithm: "AES256",
							 | 
						|
											Key:       keyPair.Key,
							 | 
						|
											KeyMD5:    keyPair.KeyMD5,
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Test empty part
							 | 
						|
										encryptedReader, iv, err := CreateSSECEncryptedReader(strings.NewReader(""), customerKey)
							 | 
						|
										if err != nil {
							 | 
						|
											t.Fatalf("Failed to create encrypted reader for empty data: %v", err)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										encryptedData, err := io.ReadAll(encryptedReader)
							 | 
						|
										if err != nil {
							 | 
						|
											t.Fatalf("Failed to read encrypted empty data: %v", err)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Empty part should produce empty encrypted data, but still have a valid IV
							 | 
						|
										if len(encryptedData) != 0 {
							 | 
						|
											t.Errorf("Expected empty encrypted data for empty part, got %d bytes", len(encryptedData))
							 | 
						|
										}
							 | 
						|
										if len(iv) != s3_constants.AESBlockSize {
							 | 
						|
											t.Errorf("Expected IV of size %d, got %d", s3_constants.AESBlockSize, len(iv))
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Decrypt and verify
							 | 
						|
										decryptedReader, err := CreateSSECDecryptedReader(bytes.NewReader(encryptedData), customerKey, iv)
							 | 
						|
										if err != nil {
							 | 
						|
											t.Fatalf("Failed to create decrypted reader for empty data: %v", err)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										decryptedData, err := io.ReadAll(decryptedReader)
							 | 
						|
										if err != nil {
							 | 
						|
											t.Fatalf("Failed to read decrypted empty data: %v", err)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										if len(decryptedData) != 0 {
							 | 
						|
											t.Errorf("Expected empty decrypted data, got %d bytes", len(decryptedData))
							 | 
						|
										}
							 | 
						|
									})
							 | 
						|
								
							 | 
						|
									t.Run("Single byte parts", func(t *testing.T) {
							 | 
						|
										keyPair := GenerateTestSSECKey(1)
							 | 
						|
										customerKey := &SSECustomerKey{
							 | 
						|
											Algorithm: "AES256",
							 | 
						|
											Key:       keyPair.Key,
							 | 
						|
											KeyMD5:    keyPair.KeyMD5,
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										testData := "ABCDEFGHIJ"
							 | 
						|
										var encryptedParts [][]byte
							 | 
						|
										var partIVs [][]byte
							 | 
						|
								
							 | 
						|
										// Encrypt each byte as a separate part
							 | 
						|
										for i, b := range []byte(testData) {
							 | 
						|
											partData := string(b)
							 | 
						|
								
							 | 
						|
											encryptedReader, iv, err := CreateSSECEncryptedReader(strings.NewReader(partData), customerKey)
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to create encrypted reader for byte %d: %v", i, err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											encryptedPart, err := io.ReadAll(encryptedReader)
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to read encrypted byte %d: %v", i, err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											encryptedParts = append(encryptedParts, encryptedPart)
							 | 
						|
											partIVs = append(partIVs, iv)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Reconstruct
							 | 
						|
										var reconstructedData strings.Builder
							 | 
						|
								
							 | 
						|
										for i, encryptedPart := range encryptedParts {
							 | 
						|
											decryptedReader, err := CreateSSECDecryptedReader(bytes.NewReader(encryptedPart), customerKey, partIVs[i])
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to create decrypted reader for byte %d: %v", i, err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											decryptedPart, err := io.ReadAll(decryptedReader)
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to read decrypted byte %d: %v", i, err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											reconstructedData.Write(decryptedPart)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										if reconstructedData.String() != testData {
							 | 
						|
											t.Errorf("Expected %s, got %s", testData, reconstructedData.String())
							 | 
						|
										}
							 | 
						|
									})
							 | 
						|
								
							 | 
						|
									t.Run("Very large parts", func(t *testing.T) {
							 | 
						|
										keyPair := GenerateTestSSECKey(1)
							 | 
						|
										customerKey := &SSECustomerKey{
							 | 
						|
											Algorithm: "AES256",
							 | 
						|
											Key:       keyPair.Key,
							 | 
						|
											KeyMD5:    keyPair.KeyMD5,
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Create a large part (1MB)
							 | 
						|
										largeData := make([]byte, 1024*1024)
							 | 
						|
										for i := range largeData {
							 | 
						|
											largeData[i] = byte(i % 256)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Encrypt
							 | 
						|
										encryptedReader, iv, err := CreateSSECEncryptedReader(bytes.NewReader(largeData), customerKey)
							 | 
						|
										if err != nil {
							 | 
						|
											t.Fatalf("Failed to create encrypted reader for large data: %v", err)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										encryptedData, err := io.ReadAll(encryptedReader)
							 | 
						|
										if err != nil {
							 | 
						|
											t.Fatalf("Failed to read encrypted large data: %v", err)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Decrypt
							 | 
						|
										decryptedReader, err := CreateSSECDecryptedReader(bytes.NewReader(encryptedData), customerKey, iv)
							 | 
						|
										if err != nil {
							 | 
						|
											t.Fatalf("Failed to create decrypted reader for large data: %v", err)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										decryptedData, err := io.ReadAll(decryptedReader)
							 | 
						|
										if err != nil {
							 | 
						|
											t.Fatalf("Failed to read decrypted large data: %v", err)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										if !bytes.Equal(decryptedData, largeData) {
							 | 
						|
											t.Error("Large data doesn't match after encryption/decryption")
							 | 
						|
										}
							 | 
						|
									})
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// TestMultipartSSEPerformance tests performance characteristics of SSE with multipart
							 | 
						|
								func TestMultipartSSEPerformance(t *testing.T) {
							 | 
						|
									if testing.Short() {
							 | 
						|
										t.Skip("Skipping performance test in short mode")
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									t.Run("SSE-C performance with multiple parts", func(t *testing.T) {
							 | 
						|
										keyPair := GenerateTestSSECKey(1)
							 | 
						|
										customerKey := &SSECustomerKey{
							 | 
						|
											Algorithm: "AES256",
							 | 
						|
											Key:       keyPair.Key,
							 | 
						|
											KeyMD5:    keyPair.KeyMD5,
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										partSize := 64 * 1024 // 64KB parts
							 | 
						|
										numParts := 10
							 | 
						|
								
							 | 
						|
										for partNum := 0; partNum < numParts; partNum++ {
							 | 
						|
											partData := make([]byte, partSize)
							 | 
						|
											for i := range partData {
							 | 
						|
												partData[i] = byte((partNum + i) % 256)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											// Encrypt
							 | 
						|
											encryptedReader, iv, err := CreateSSECEncryptedReader(bytes.NewReader(partData), customerKey)
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to create encrypted reader for part %d: %v", partNum, err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											encryptedData, err := io.ReadAll(encryptedReader)
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to read encrypted data for part %d: %v", partNum, err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											// Decrypt
							 | 
						|
											decryptedReader, err := CreateSSECDecryptedReader(bytes.NewReader(encryptedData), customerKey, iv)
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to create decrypted reader for part %d: %v", partNum, err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											decryptedData, err := io.ReadAll(decryptedReader)
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to read decrypted data for part %d: %v", partNum, err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											if !bytes.Equal(decryptedData, partData) {
							 | 
						|
												t.Errorf("Data mismatch for part %d", partNum)
							 | 
						|
											}
							 | 
						|
										}
							 | 
						|
									})
							 | 
						|
								
							 | 
						|
									t.Run("SSE-KMS performance with multiple parts", func(t *testing.T) {
							 | 
						|
										kmsKey := SetupTestKMS(t)
							 | 
						|
										defer kmsKey.Cleanup()
							 | 
						|
								
							 | 
						|
										partSize := 64 * 1024 // 64KB parts
							 | 
						|
										numParts := 5         // Fewer parts for KMS due to overhead
							 | 
						|
										encryptionContext := BuildEncryptionContext("test-bucket", "test-object", false)
							 | 
						|
								
							 | 
						|
										for partNum := 0; partNum < numParts; partNum++ {
							 | 
						|
											partData := make([]byte, partSize)
							 | 
						|
											for i := range partData {
							 | 
						|
												partData[i] = byte((partNum + i) % 256)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											// Encrypt
							 | 
						|
											encryptedReader, sseKey, err := CreateSSEKMSEncryptedReader(bytes.NewReader(partData), kmsKey.KeyID, encryptionContext)
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to create encrypted reader for part %d: %v", partNum, err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											encryptedData, err := io.ReadAll(encryptedReader)
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to read encrypted data for part %d: %v", partNum, err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											// Decrypt
							 | 
						|
											decryptedReader, err := CreateSSEKMSDecryptedReader(bytes.NewReader(encryptedData), sseKey)
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to create decrypted reader for part %d: %v", partNum, err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											decryptedData, err := io.ReadAll(decryptedReader)
							 | 
						|
											if err != nil {
							 | 
						|
												t.Fatalf("Failed to read decrypted data for part %d: %v", partNum, err)
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											if !bytes.Equal(decryptedData, partData) {
							 | 
						|
												t.Errorf("Data mismatch for part %d", partNum)
							 | 
						|
											}
							 | 
						|
										}
							 | 
						|
									})
							 | 
						|
								}
							 |