s3_sse_metadata.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. package s3api
  2. import (
  3. "encoding/base64"
  4. "encoding/json"
  5. "fmt"
  6. )
  7. // SSE metadata keys for storing encryption information in entry metadata
  8. const (
  9. // MetaSSEIV is the initialization vector used for encryption
  10. MetaSSEIV = "X-SeaweedFS-Server-Side-Encryption-Iv"
  11. // MetaSSEAlgorithm is the encryption algorithm used
  12. MetaSSEAlgorithm = "X-SeaweedFS-Server-Side-Encryption-Algorithm"
  13. // MetaSSECKeyMD5 is the MD5 hash of the SSE-C customer key
  14. MetaSSECKeyMD5 = "X-SeaweedFS-Server-Side-Encryption-Customer-Key-MD5"
  15. // MetaSSEKMSKeyID is the KMS key ID used for encryption
  16. MetaSSEKMSKeyID = "X-SeaweedFS-Server-Side-Encryption-KMS-Key-Id"
  17. // MetaSSEKMSEncryptedKey is the encrypted data key from KMS
  18. MetaSSEKMSEncryptedKey = "X-SeaweedFS-Server-Side-Encryption-KMS-Encrypted-Key"
  19. // MetaSSEKMSContext is the encryption context for KMS
  20. MetaSSEKMSContext = "X-SeaweedFS-Server-Side-Encryption-KMS-Context"
  21. // MetaSSES3KeyID is the key ID for SSE-S3 encryption
  22. MetaSSES3KeyID = "X-SeaweedFS-Server-Side-Encryption-S3-Key-Id"
  23. )
  24. // StoreIVInMetadata stores the IV in entry metadata as base64 encoded string
  25. func StoreIVInMetadata(metadata map[string][]byte, iv []byte) {
  26. if len(iv) > 0 {
  27. metadata[MetaSSEIV] = []byte(base64.StdEncoding.EncodeToString(iv))
  28. }
  29. }
  30. // GetIVFromMetadata retrieves the IV from entry metadata
  31. func GetIVFromMetadata(metadata map[string][]byte) ([]byte, error) {
  32. if ivBase64, exists := metadata[MetaSSEIV]; exists {
  33. iv, err := base64.StdEncoding.DecodeString(string(ivBase64))
  34. if err != nil {
  35. return nil, fmt.Errorf("failed to decode IV from metadata: %w", err)
  36. }
  37. return iv, nil
  38. }
  39. return nil, fmt.Errorf("IV not found in metadata")
  40. }
  41. // StoreSSECMetadata stores SSE-C related metadata
  42. func StoreSSECMetadata(metadata map[string][]byte, iv []byte, keyMD5 string) {
  43. StoreIVInMetadata(metadata, iv)
  44. metadata[MetaSSEAlgorithm] = []byte("AES256")
  45. if keyMD5 != "" {
  46. metadata[MetaSSECKeyMD5] = []byte(keyMD5)
  47. }
  48. }
  49. // StoreSSEKMSMetadata stores SSE-KMS related metadata
  50. func StoreSSEKMSMetadata(metadata map[string][]byte, iv []byte, keyID string, encryptedKey []byte, context map[string]string) {
  51. StoreIVInMetadata(metadata, iv)
  52. metadata[MetaSSEAlgorithm] = []byte("aws:kms")
  53. if keyID != "" {
  54. metadata[MetaSSEKMSKeyID] = []byte(keyID)
  55. }
  56. if len(encryptedKey) > 0 {
  57. metadata[MetaSSEKMSEncryptedKey] = []byte(base64.StdEncoding.EncodeToString(encryptedKey))
  58. }
  59. if len(context) > 0 {
  60. // Marshal context to JSON to handle special characters correctly
  61. contextBytes, err := json.Marshal(context)
  62. if err == nil {
  63. metadata[MetaSSEKMSContext] = contextBytes
  64. }
  65. // Note: json.Marshal for map[string]string should never fail, but we handle it gracefully
  66. }
  67. }
  68. // StoreSSES3Metadata stores SSE-S3 related metadata
  69. func StoreSSES3Metadata(metadata map[string][]byte, iv []byte, keyID string) {
  70. StoreIVInMetadata(metadata, iv)
  71. metadata[MetaSSEAlgorithm] = []byte("AES256")
  72. if keyID != "" {
  73. metadata[MetaSSES3KeyID] = []byte(keyID)
  74. }
  75. }
  76. // GetSSECMetadata retrieves SSE-C metadata
  77. func GetSSECMetadata(metadata map[string][]byte) (iv []byte, keyMD5 string, err error) {
  78. iv, err = GetIVFromMetadata(metadata)
  79. if err != nil {
  80. return nil, "", err
  81. }
  82. if keyMD5Bytes, exists := metadata[MetaSSECKeyMD5]; exists {
  83. keyMD5 = string(keyMD5Bytes)
  84. }
  85. return iv, keyMD5, nil
  86. }
  87. // GetSSEKMSMetadata retrieves SSE-KMS metadata
  88. func GetSSEKMSMetadata(metadata map[string][]byte) (iv []byte, keyID string, encryptedKey []byte, context map[string]string, err error) {
  89. iv, err = GetIVFromMetadata(metadata)
  90. if err != nil {
  91. return nil, "", nil, nil, err
  92. }
  93. if keyIDBytes, exists := metadata[MetaSSEKMSKeyID]; exists {
  94. keyID = string(keyIDBytes)
  95. }
  96. if encKeyBase64, exists := metadata[MetaSSEKMSEncryptedKey]; exists {
  97. encryptedKey, err = base64.StdEncoding.DecodeString(string(encKeyBase64))
  98. if err != nil {
  99. return nil, "", nil, nil, fmt.Errorf("failed to decode encrypted key: %w", err)
  100. }
  101. }
  102. // Parse context from JSON
  103. if contextBytes, exists := metadata[MetaSSEKMSContext]; exists {
  104. context = make(map[string]string)
  105. if err := json.Unmarshal(contextBytes, &context); err != nil {
  106. return nil, "", nil, nil, fmt.Errorf("failed to parse KMS context JSON: %w", err)
  107. }
  108. }
  109. return iv, keyID, encryptedKey, context, nil
  110. }
  111. // GetSSES3Metadata retrieves SSE-S3 metadata
  112. func GetSSES3Metadata(metadata map[string][]byte) (iv []byte, keyID string, err error) {
  113. iv, err = GetIVFromMetadata(metadata)
  114. if err != nil {
  115. return nil, "", err
  116. }
  117. if keyIDBytes, exists := metadata[MetaSSES3KeyID]; exists {
  118. keyID = string(keyIDBytes)
  119. }
  120. return iv, keyID, nil
  121. }
  122. // IsSSEEncrypted checks if the metadata indicates any form of SSE encryption
  123. func IsSSEEncrypted(metadata map[string][]byte) bool {
  124. _, exists := metadata[MetaSSEIV]
  125. return exists
  126. }
  127. // GetSSEAlgorithm returns the SSE algorithm from metadata
  128. func GetSSEAlgorithm(metadata map[string][]byte) string {
  129. if alg, exists := metadata[MetaSSEAlgorithm]; exists {
  130. return string(alg)
  131. }
  132. return ""
  133. }