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 ""
|
|
}
|