s3_sse_s3.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. package s3api
  2. import (
  3. "crypto/aes"
  4. "crypto/cipher"
  5. "crypto/rand"
  6. "encoding/base64"
  7. "encoding/json"
  8. "fmt"
  9. "io"
  10. mathrand "math/rand"
  11. "net/http"
  12. "github.com/seaweedfs/seaweedfs/weed/glog"
  13. "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
  14. )
  15. // SSE-S3 uses AES-256 encryption with server-managed keys
  16. const (
  17. SSES3Algorithm = s3_constants.SSEAlgorithmAES256
  18. SSES3KeySize = 32 // 256 bits
  19. )
  20. // SSES3Key represents a server-managed encryption key for SSE-S3
  21. type SSES3Key struct {
  22. Key []byte
  23. KeyID string
  24. Algorithm string
  25. IV []byte // Initialization Vector for this key
  26. }
  27. // IsSSES3RequestInternal checks if the request specifies SSE-S3 encryption
  28. func IsSSES3RequestInternal(r *http.Request) bool {
  29. sseHeader := r.Header.Get(s3_constants.AmzServerSideEncryption)
  30. result := sseHeader == SSES3Algorithm
  31. // Debug: log header detection for SSE-S3 requests
  32. if result {
  33. glog.V(4).Infof("SSE-S3 detection: method=%s, header=%q, expected=%q, result=%t, copySource=%q", r.Method, sseHeader, SSES3Algorithm, result, r.Header.Get("X-Amz-Copy-Source"))
  34. }
  35. return result
  36. }
  37. // IsSSES3EncryptedInternal checks if the object metadata indicates SSE-S3 encryption
  38. func IsSSES3EncryptedInternal(metadata map[string][]byte) bool {
  39. if sseAlgorithm, exists := metadata[s3_constants.AmzServerSideEncryption]; exists {
  40. return string(sseAlgorithm) == SSES3Algorithm
  41. }
  42. return false
  43. }
  44. // GenerateSSES3Key generates a new SSE-S3 encryption key
  45. func GenerateSSES3Key() (*SSES3Key, error) {
  46. key := make([]byte, SSES3KeySize)
  47. if _, err := io.ReadFull(rand.Reader, key); err != nil {
  48. return nil, fmt.Errorf("failed to generate SSE-S3 key: %w", err)
  49. }
  50. // Generate a key ID for tracking
  51. keyID := fmt.Sprintf("sse-s3-key-%d", mathrand.Int63())
  52. return &SSES3Key{
  53. Key: key,
  54. KeyID: keyID,
  55. Algorithm: SSES3Algorithm,
  56. }, nil
  57. }
  58. // CreateSSES3EncryptedReader creates an encrypted reader for SSE-S3
  59. // Returns the encrypted reader and the IV for metadata storage
  60. func CreateSSES3EncryptedReader(reader io.Reader, key *SSES3Key) (io.Reader, []byte, error) {
  61. // Create AES cipher
  62. block, err := aes.NewCipher(key.Key)
  63. if err != nil {
  64. return nil, nil, fmt.Errorf("create AES cipher: %w", err)
  65. }
  66. // Generate random IV
  67. iv := make([]byte, aes.BlockSize)
  68. if _, err := io.ReadFull(rand.Reader, iv); err != nil {
  69. return nil, nil, fmt.Errorf("generate IV: %w", err)
  70. }
  71. // Create CTR mode cipher
  72. stream := cipher.NewCTR(block, iv)
  73. // Return encrypted reader and IV separately for metadata storage
  74. encryptedReader := &cipher.StreamReader{S: stream, R: reader}
  75. return encryptedReader, iv, nil
  76. }
  77. // CreateSSES3DecryptedReader creates a decrypted reader for SSE-S3 using IV from metadata
  78. func CreateSSES3DecryptedReader(reader io.Reader, key *SSES3Key, iv []byte) (io.Reader, error) {
  79. // Create AES cipher
  80. block, err := aes.NewCipher(key.Key)
  81. if err != nil {
  82. return nil, fmt.Errorf("create AES cipher: %w", err)
  83. }
  84. // Create CTR mode cipher with the provided IV
  85. stream := cipher.NewCTR(block, iv)
  86. return &cipher.StreamReader{S: stream, R: reader}, nil
  87. }
  88. // GetSSES3Headers returns the headers for SSE-S3 encrypted objects
  89. func GetSSES3Headers() map[string]string {
  90. return map[string]string{
  91. s3_constants.AmzServerSideEncryption: SSES3Algorithm,
  92. }
  93. }
  94. // SerializeSSES3Metadata serializes SSE-S3 metadata for storage
  95. func SerializeSSES3Metadata(key *SSES3Key) ([]byte, error) {
  96. if err := ValidateSSES3Key(key); err != nil {
  97. return nil, err
  98. }
  99. // For SSE-S3, we typically don't store the actual key in metadata
  100. // Instead, we store a key ID or reference that can be used to retrieve the key
  101. // from a secure key management system
  102. metadata := map[string]string{
  103. "algorithm": key.Algorithm,
  104. "keyId": key.KeyID,
  105. }
  106. // Include IV if present (needed for chunk-level decryption)
  107. if key.IV != nil {
  108. metadata["iv"] = base64.StdEncoding.EncodeToString(key.IV)
  109. }
  110. // Use JSON for proper serialization
  111. data, err := json.Marshal(metadata)
  112. if err != nil {
  113. return nil, fmt.Errorf("marshal SSE-S3 metadata: %w", err)
  114. }
  115. return data, nil
  116. }
  117. // DeserializeSSES3Metadata deserializes SSE-S3 metadata from storage and retrieves the actual key
  118. func DeserializeSSES3Metadata(data []byte, keyManager *SSES3KeyManager) (*SSES3Key, error) {
  119. if len(data) == 0 {
  120. return nil, fmt.Errorf("empty SSE-S3 metadata")
  121. }
  122. // Parse the JSON metadata to extract keyId
  123. var metadata map[string]string
  124. if err := json.Unmarshal(data, &metadata); err != nil {
  125. return nil, fmt.Errorf("failed to parse SSE-S3 metadata: %w", err)
  126. }
  127. keyID, exists := metadata["keyId"]
  128. if !exists {
  129. return nil, fmt.Errorf("keyId not found in SSE-S3 metadata")
  130. }
  131. algorithm, exists := metadata["algorithm"]
  132. if !exists {
  133. algorithm = s3_constants.SSEAlgorithmAES256 // Default algorithm
  134. }
  135. // Retrieve the actual key using the keyId
  136. if keyManager == nil {
  137. return nil, fmt.Errorf("key manager is required for SSE-S3 key retrieval")
  138. }
  139. key, err := keyManager.GetOrCreateKey(keyID)
  140. if err != nil {
  141. return nil, fmt.Errorf("failed to retrieve SSE-S3 key with ID %s: %w", keyID, err)
  142. }
  143. // Verify the algorithm matches
  144. if key.Algorithm != algorithm {
  145. return nil, fmt.Errorf("algorithm mismatch: expected %s, got %s", algorithm, key.Algorithm)
  146. }
  147. // Restore IV if present in metadata (for chunk-level decryption)
  148. if ivStr, exists := metadata["iv"]; exists {
  149. iv, err := base64.StdEncoding.DecodeString(ivStr)
  150. if err != nil {
  151. return nil, fmt.Errorf("failed to decode IV: %w", err)
  152. }
  153. key.IV = iv
  154. }
  155. return key, nil
  156. }
  157. // SSES3KeyManager manages SSE-S3 encryption keys
  158. type SSES3KeyManager struct {
  159. // In a production system, this would interface with a secure key management system
  160. keys map[string]*SSES3Key
  161. }
  162. // NewSSES3KeyManager creates a new SSE-S3 key manager
  163. func NewSSES3KeyManager() *SSES3KeyManager {
  164. return &SSES3KeyManager{
  165. keys: make(map[string]*SSES3Key),
  166. }
  167. }
  168. // GetOrCreateKey gets an existing key or creates a new one
  169. func (km *SSES3KeyManager) GetOrCreateKey(keyID string) (*SSES3Key, error) {
  170. if keyID == "" {
  171. // Generate new key
  172. return GenerateSSES3Key()
  173. }
  174. // Check if key exists
  175. if key, exists := km.keys[keyID]; exists {
  176. return key, nil
  177. }
  178. // Create new key
  179. key, err := GenerateSSES3Key()
  180. if err != nil {
  181. return nil, err
  182. }
  183. key.KeyID = keyID
  184. km.keys[keyID] = key
  185. return key, nil
  186. }
  187. // StoreKey stores a key in the manager
  188. func (km *SSES3KeyManager) StoreKey(key *SSES3Key) {
  189. km.keys[key.KeyID] = key
  190. }
  191. // GetKey retrieves a key by ID
  192. func (km *SSES3KeyManager) GetKey(keyID string) (*SSES3Key, bool) {
  193. key, exists := km.keys[keyID]
  194. return key, exists
  195. }
  196. // Global SSE-S3 key manager instance
  197. var globalSSES3KeyManager = NewSSES3KeyManager()
  198. // GetSSES3KeyManager returns the global SSE-S3 key manager
  199. func GetSSES3KeyManager() *SSES3KeyManager {
  200. return globalSSES3KeyManager
  201. }
  202. // ProcessSSES3Request processes an SSE-S3 request and returns encryption metadata
  203. func ProcessSSES3Request(r *http.Request) (map[string][]byte, error) {
  204. if !IsSSES3RequestInternal(r) {
  205. return nil, nil
  206. }
  207. // Generate or retrieve encryption key
  208. keyManager := GetSSES3KeyManager()
  209. key, err := keyManager.GetOrCreateKey("")
  210. if err != nil {
  211. return nil, fmt.Errorf("get SSE-S3 key: %w", err)
  212. }
  213. // Serialize key metadata
  214. keyData, err := SerializeSSES3Metadata(key)
  215. if err != nil {
  216. return nil, fmt.Errorf("serialize SSE-S3 metadata: %w", err)
  217. }
  218. // Store key in manager
  219. keyManager.StoreKey(key)
  220. // Return metadata
  221. metadata := map[string][]byte{
  222. s3_constants.AmzServerSideEncryption: []byte(SSES3Algorithm),
  223. s3_constants.SeaweedFSSSES3Key: keyData,
  224. }
  225. return metadata, nil
  226. }
  227. // GetSSES3KeyFromMetadata extracts SSE-S3 key from object metadata
  228. func GetSSES3KeyFromMetadata(metadata map[string][]byte, keyManager *SSES3KeyManager) (*SSES3Key, error) {
  229. keyData, exists := metadata[s3_constants.SeaweedFSSSES3Key]
  230. if !exists {
  231. return nil, fmt.Errorf("SSE-S3 key not found in metadata")
  232. }
  233. return DeserializeSSES3Metadata(keyData, keyManager)
  234. }
  235. // CreateSSES3EncryptedReaderWithBaseIV creates an encrypted reader using a base IV for multipart upload consistency.
  236. // The returned IV is the offset-derived IV, calculated from the input baseIV and offset.
  237. func CreateSSES3EncryptedReaderWithBaseIV(reader io.Reader, key *SSES3Key, baseIV []byte, offset int64) (io.Reader, []byte /* derivedIV */, error) {
  238. // Validate key to prevent panics and security issues
  239. if key == nil {
  240. return nil, nil, fmt.Errorf("SSES3Key is nil")
  241. }
  242. if key.Key == nil || len(key.Key) != SSES3KeySize {
  243. return nil, nil, fmt.Errorf("invalid SSES3Key: must be %d bytes, got %d", SSES3KeySize, len(key.Key))
  244. }
  245. if err := ValidateSSES3Key(key); err != nil {
  246. return nil, nil, err
  247. }
  248. block, err := aes.NewCipher(key.Key)
  249. if err != nil {
  250. return nil, nil, fmt.Errorf("create AES cipher: %w", err)
  251. }
  252. // Calculate the proper IV with offset to ensure unique IV per chunk/part
  253. // This prevents the severe security vulnerability of IV reuse in CTR mode
  254. iv := calculateIVWithOffset(baseIV, offset)
  255. stream := cipher.NewCTR(block, iv)
  256. encryptedReader := &cipher.StreamReader{S: stream, R: reader}
  257. return encryptedReader, iv, nil
  258. }