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.
		
		
		
		
		
			
		
			
				
					
					
						
							159 lines
						
					
					
						
							4.9 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							159 lines
						
					
					
						
							4.9 KiB
						
					
					
				| package s3api | |
| 
 | |
| import ( | |
| 	"encoding/base64" | |
| 	"encoding/json" | |
| 	"fmt" | |
| ) | |
| 
 | |
| // SSE metadata keys for storing encryption information in entry metadata | |
| const ( | |
| 	// MetaSSEIV is the initialization vector used for encryption | |
| 	MetaSSEIV = "X-SeaweedFS-Server-Side-Encryption-Iv" | |
| 
 | |
| 	// MetaSSEAlgorithm is the encryption algorithm used | |
| 	MetaSSEAlgorithm = "X-SeaweedFS-Server-Side-Encryption-Algorithm" | |
| 
 | |
| 	// MetaSSECKeyMD5 is the MD5 hash of the SSE-C customer key | |
| 	MetaSSECKeyMD5 = "X-SeaweedFS-Server-Side-Encryption-Customer-Key-MD5" | |
| 
 | |
| 	// MetaSSEKMSKeyID is the KMS key ID used for encryption | |
| 	MetaSSEKMSKeyID = "X-SeaweedFS-Server-Side-Encryption-KMS-Key-Id" | |
| 
 | |
| 	// MetaSSEKMSEncryptedKey is the encrypted data key from KMS | |
| 	MetaSSEKMSEncryptedKey = "X-SeaweedFS-Server-Side-Encryption-KMS-Encrypted-Key" | |
| 
 | |
| 	// MetaSSEKMSContext is the encryption context for KMS | |
| 	MetaSSEKMSContext = "X-SeaweedFS-Server-Side-Encryption-KMS-Context" | |
| 
 | |
| 	// MetaSSES3KeyID is the key ID for SSE-S3 encryption | |
| 	MetaSSES3KeyID = "X-SeaweedFS-Server-Side-Encryption-S3-Key-Id" | |
| ) | |
| 
 | |
| // StoreIVInMetadata stores the IV in entry metadata as base64 encoded string | |
| func StoreIVInMetadata(metadata map[string][]byte, iv []byte) { | |
| 	if len(iv) > 0 { | |
| 		metadata[MetaSSEIV] = []byte(base64.StdEncoding.EncodeToString(iv)) | |
| 	} | |
| } | |
| 
 | |
| // GetIVFromMetadata retrieves the IV from entry metadata | |
| func GetIVFromMetadata(metadata map[string][]byte) ([]byte, error) { | |
| 	if ivBase64, exists := metadata[MetaSSEIV]; exists { | |
| 		iv, err := base64.StdEncoding.DecodeString(string(ivBase64)) | |
| 		if err != nil { | |
| 			return nil, fmt.Errorf("failed to decode IV from metadata: %w", err) | |
| 		} | |
| 		return iv, nil | |
| 	} | |
| 	return nil, fmt.Errorf("IV not found in metadata") | |
| } | |
| 
 | |
| // StoreSSECMetadata stores SSE-C related metadata | |
| func StoreSSECMetadata(metadata map[string][]byte, iv []byte, keyMD5 string) { | |
| 	StoreIVInMetadata(metadata, iv) | |
| 	metadata[MetaSSEAlgorithm] = []byte("AES256") | |
| 	if keyMD5 != "" { | |
| 		metadata[MetaSSECKeyMD5] = []byte(keyMD5) | |
| 	} | |
| } | |
| 
 | |
| // StoreSSEKMSMetadata stores SSE-KMS related metadata | |
| func StoreSSEKMSMetadata(metadata map[string][]byte, iv []byte, keyID string, encryptedKey []byte, context map[string]string) { | |
| 	StoreIVInMetadata(metadata, iv) | |
| 	metadata[MetaSSEAlgorithm] = []byte("aws:kms") | |
| 	if keyID != "" { | |
| 		metadata[MetaSSEKMSKeyID] = []byte(keyID) | |
| 	} | |
| 	if len(encryptedKey) > 0 { | |
| 		metadata[MetaSSEKMSEncryptedKey] = []byte(base64.StdEncoding.EncodeToString(encryptedKey)) | |
| 	} | |
| 	if len(context) > 0 { | |
| 		// Marshal context to JSON to handle special characters correctly | |
| 		contextBytes, err := json.Marshal(context) | |
| 		if err == nil { | |
| 			metadata[MetaSSEKMSContext] = contextBytes | |
| 		} | |
| 		// Note: json.Marshal for map[string]string should never fail, but we handle it gracefully | |
| 	} | |
| } | |
| 
 | |
| // StoreSSES3Metadata stores SSE-S3 related metadata | |
| func StoreSSES3Metadata(metadata map[string][]byte, iv []byte, keyID string) { | |
| 	StoreIVInMetadata(metadata, iv) | |
| 	metadata[MetaSSEAlgorithm] = []byte("AES256") | |
| 	if keyID != "" { | |
| 		metadata[MetaSSES3KeyID] = []byte(keyID) | |
| 	} | |
| } | |
| 
 | |
| // GetSSECMetadata retrieves SSE-C metadata | |
| func GetSSECMetadata(metadata map[string][]byte) (iv []byte, keyMD5 string, err error) { | |
| 	iv, err = GetIVFromMetadata(metadata) | |
| 	if err != nil { | |
| 		return nil, "", err | |
| 	} | |
| 
 | |
| 	if keyMD5Bytes, exists := metadata[MetaSSECKeyMD5]; exists { | |
| 		keyMD5 = string(keyMD5Bytes) | |
| 	} | |
| 
 | |
| 	return iv, keyMD5, nil | |
| } | |
| 
 | |
| // GetSSEKMSMetadata retrieves SSE-KMS metadata | |
| func GetSSEKMSMetadata(metadata map[string][]byte) (iv []byte, keyID string, encryptedKey []byte, context map[string]string, err error) { | |
| 	iv, err = GetIVFromMetadata(metadata) | |
| 	if err != nil { | |
| 		return nil, "", nil, nil, err | |
| 	} | |
| 
 | |
| 	if keyIDBytes, exists := metadata[MetaSSEKMSKeyID]; exists { | |
| 		keyID = string(keyIDBytes) | |
| 	} | |
| 
 | |
| 	if encKeyBase64, exists := metadata[MetaSSEKMSEncryptedKey]; exists { | |
| 		encryptedKey, err = base64.StdEncoding.DecodeString(string(encKeyBase64)) | |
| 		if err != nil { | |
| 			return nil, "", nil, nil, fmt.Errorf("failed to decode encrypted key: %w", err) | |
| 		} | |
| 	} | |
| 
 | |
| 	// Parse context from JSON | |
| 	if contextBytes, exists := metadata[MetaSSEKMSContext]; exists { | |
| 		context = make(map[string]string) | |
| 		if err := json.Unmarshal(contextBytes, &context); err != nil { | |
| 			return nil, "", nil, nil, fmt.Errorf("failed to parse KMS context JSON: %w", err) | |
| 		} | |
| 	} | |
| 
 | |
| 	return iv, keyID, encryptedKey, context, nil | |
| } | |
| 
 | |
| // GetSSES3Metadata retrieves SSE-S3 metadata | |
| func GetSSES3Metadata(metadata map[string][]byte) (iv []byte, keyID string, err error) { | |
| 	iv, err = GetIVFromMetadata(metadata) | |
| 	if err != nil { | |
| 		return nil, "", err | |
| 	} | |
| 
 | |
| 	if keyIDBytes, exists := metadata[MetaSSES3KeyID]; exists { | |
| 		keyID = string(keyIDBytes) | |
| 	} | |
| 
 | |
| 	return iv, keyID, nil | |
| } | |
| 
 | |
| // IsSSEEncrypted checks if the metadata indicates any form of SSE encryption | |
| func IsSSEEncrypted(metadata map[string][]byte) bool { | |
| 	_, exists := metadata[MetaSSEIV] | |
| 	return exists | |
| } | |
| 
 | |
| // GetSSEAlgorithm returns the SSE algorithm from metadata | |
| func GetSSEAlgorithm(metadata map[string][]byte) string { | |
| 	if alg, exists := metadata[MetaSSEAlgorithm]; exists { | |
| 		return string(alg) | |
| 	} | |
| 	return "" | |
| }
 |