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