Browse Source

offset

pull/7481/head
chrislu 1 month ago
parent
commit
7fc43d964b
  1. 44
      weed/s3api/s3api_object_handlers.go
  2. 13
      weed/s3api/s3api_object_handlers_put.go

44
weed/s3api/s3api_object_handlers.go

@ -1224,12 +1224,21 @@ func (s3a *S3ApiServer) decryptSSECChunkView(ctx context.Context, fileChunk *fil
// Decrypt with CTR IV offset adjustment // Decrypt with CTR IV offset adjustment
// CTR mode: IV for block N = base_IV + (N / 16) // CTR mode: IV for block N = base_IV + (N / 16)
// For multipart objects, each part is encrypted independently with offset=0
// So we need to adjust IV based on position WITHIN THE PART, not absolute file position
offsetWithinPart := chunkView.ViewOffset - ssecMetadata.PartOffset
glog.V(3).Infof("decryptSSECChunkView: chunk=%s, fileChunk.Offset=%d, chunkView.OffsetInChunk=%d, chunkView.ViewOffset=%d, chunkView.ViewSize=%d, metadata.PartOffset=%d, offsetWithinPart=%d",
chunkView.FileId, fileChunk.Offset, chunkView.OffsetInChunk, chunkView.ViewOffset, chunkView.ViewSize, ssecMetadata.PartOffset, offsetWithinPart)
adjustedIV := adjustCTRIV(chunkIV, offsetWithinPart)
// PartOffset in metadata distinguishes single-part vs multipart:
// - Single-part: PartOffset = 0 for all chunks (one encrypted stream starting at 0)
// - Multipart: PartOffset = chunk position within part during upload
var ivOffset int64
if ssecMetadata.PartOffset == 0 {
// Single-part upload: use absolute file position
ivOffset = chunkView.ViewOffset
} else {
// Multipart upload: use position within the part's encrypted stream
// After assembly, chunk.Offset is in final file, so we calculate position within part
ivOffset = chunkView.ViewOffset - fileChunk.Offset
}
glog.V(3).Infof("decryptSSECChunkView: chunk=%s, fileChunk.Offset=%d, chunkView.ViewOffset=%d, chunkView.ViewSize=%d, metadata.PartOffset=%d, ivOffset=%d",
chunkView.FileId, fileChunk.Offset, chunkView.ViewOffset, chunkView.ViewSize, ssecMetadata.PartOffset, ivOffset)
adjustedIV := adjustCTRIV(chunkIV, ivOffset)
return CreateSSECDecryptedReader(encryptedReader, customerKey, adjustedIV) return CreateSSECDecryptedReader(encryptedReader, customerKey, adjustedIV)
} }
@ -1257,21 +1266,28 @@ func (s3a *S3ApiServer) decryptSSEKMSChunkView(ctx context.Context, fileChunk *f
} }
// Decrypt with CTR IV offset adjustment // Decrypt with CTR IV offset adjustment
// For multipart objects, each part is encrypted independently with offset=0
// So we need to adjust IV based on position WITHIN THE PART, not absolute file position
// sseKMSKey.ChunkOffset contains the part offset (where this part starts in the file)
offsetWithinPart := chunkView.ViewOffset - sseKMSKey.ChunkOffset
adjustedIV := adjustCTRIV(sseKMSKey.IV, offsetWithinPart)
// ChunkOffset in KMS metadata distinguishes single-part vs multipart (same logic as SSE-C)
// - Single-part: ChunkOffset = 0 for all chunks (one encrypted stream starting at 0)
// - Multipart: ChunkOffset = chunk position within part during upload
var ivOffset int64
if sseKMSKey.ChunkOffset == 0 {
// Single-part upload: use absolute file position
ivOffset = chunkView.ViewOffset
} else {
// Multipart upload: use position within the part's encrypted stream
ivOffset = chunkView.ViewOffset - fileChunk.Offset
}
adjustedIV := adjustCTRIV(sseKMSKey.IV, ivOffset)
adjustedKey := &SSEKMSKey{ adjustedKey := &SSEKMSKey{
KeyID: sseKMSKey.KeyID, KeyID: sseKMSKey.KeyID,
EncryptedDataKey: sseKMSKey.EncryptedDataKey, EncryptedDataKey: sseKMSKey.EncryptedDataKey,
EncryptionContext: sseKMSKey.EncryptionContext, EncryptionContext: sseKMSKey.EncryptionContext,
BucketKeyEnabled: sseKMSKey.BucketKeyEnabled, BucketKeyEnabled: sseKMSKey.BucketKeyEnabled,
IV: adjustedIV, IV: adjustedIV,
ChunkOffset: offsetWithinPart,
ChunkOffset: ivOffset,
} }
glog.V(3).Infof("decryptSSEKMSChunkView: chunk=%s, ViewOffset=%d, PartOffset=%d, offsetWithinPart=%d",
chunkView.FileId, chunkView.ViewOffset, sseKMSKey.ChunkOffset, offsetWithinPart)
glog.V(3).Infof("decryptSSEKMSChunkView: chunk=%s, fileChunk.Offset=%d, ViewOffset=%d, metadata.ChunkOffset=%d, ivOffset=%d",
chunkView.FileId, fileChunk.Offset, chunkView.ViewOffset, sseKMSKey.ChunkOffset, ivOffset)
return CreateSSEKMSDecryptedReader(encryptedReader, adjustedKey) return CreateSSEKMSDecryptedReader(encryptedReader, adjustedKey)
} }

13
weed/s3api/s3api_object_handlers_put.go

@ -390,6 +390,17 @@ func (s3a *S3ApiServer) putToFiler(r *http.Request, uploadUrl string, dataReader
for _, chunk := range chunkResult.FileChunks { for _, chunk := range chunkResult.FileChunks {
chunk.SseType = filer_pb.SSEType_SSE_C chunk.SseType = filer_pb.SSEType_SSE_C
if len(sseIV) > 0 { if len(sseIV) > 0 {
// For single-part uploads (partNumber == 0), all chunks belong to one encrypted stream starting at 0
// For multipart uploads (partNumber > 0), each part is encrypted independently starting at 0
var partOffset int64
if partNumber == 0 {
// Single-part: use 0 since the entire object is one encrypted stream starting at position 0
partOffset = 0
} else {
// Multipart: use chunk.Offset which represents position within this part's encrypted stream
partOffset = chunk.Offset
}
ssecMetadataStruct := struct { ssecMetadataStruct := struct {
Algorithm string `json:"algorithm"` Algorithm string `json:"algorithm"`
IV string `json:"iv"` IV string `json:"iv"`
@ -399,7 +410,7 @@ func (s3a *S3ApiServer) putToFiler(r *http.Request, uploadUrl string, dataReader
Algorithm: "AES256", Algorithm: "AES256",
IV: base64.StdEncoding.EncodeToString(sseIV), IV: base64.StdEncoding.EncodeToString(sseIV),
KeyMD5: customerKey.KeyMD5, KeyMD5: customerKey.KeyMD5,
PartOffset: chunk.Offset, // Use actual chunk offset
PartOffset: partOffset,
} }
if ssecMetadata, serErr := json.Marshal(ssecMetadataStruct); serErr == nil { if ssecMetadata, serErr := json.Marshal(ssecMetadataStruct); serErr == nil {
chunk.SseMetadata = ssecMetadata chunk.SseMetadata = ssecMetadata

Loading…
Cancel
Save