mirror of https://github.com/minio/minio.git
fix size computation for en/decrypted objects (#6147)
This PR fixes the size calculation for encrypted multipart objects.
This commit is contained in:
parent
b11a8eb3f4
commit
adf7340394
|
@ -640,15 +640,12 @@ func DecryptAllBlocksCopyRequest(client io.Writer, r *http.Request, bucket, obje
|
|||
// DecryptBlocksRequest - setup a struct which can decrypt many concatenated encrypted data
|
||||
// parts information helps to know the boundaries of each encrypted data block.
|
||||
func DecryptBlocksRequest(client io.Writer, r *http.Request, bucket, object string, startOffset, length int64, objInfo ObjectInfo, copySource bool) (io.WriteCloser, int64, int64, error) {
|
||||
seqNumber, encStartOffset, encLength := getEncryptedStartOffset(startOffset, length)
|
||||
|
||||
// Encryption length cannot be bigger than the file size, if it is
|
||||
// which is allowed in AWS S3, we simply default to EncryptedSize().
|
||||
if encLength+encStartOffset > objInfo.EncryptedSize() {
|
||||
encLength = objInfo.EncryptedSize() - encStartOffset
|
||||
}
|
||||
var seqNumber uint32
|
||||
var encStartOffset, encLength int64
|
||||
|
||||
if len(objInfo.Parts) == 0 || !objInfo.IsEncryptedMultipart() {
|
||||
seqNumber, encStartOffset, encLength = getEncryptedSinglePartOffsetLength(startOffset, length, objInfo)
|
||||
|
||||
var writer io.WriteCloser
|
||||
var err error
|
||||
if copySource {
|
||||
|
@ -662,6 +659,7 @@ func DecryptBlocksRequest(client io.Writer, r *http.Request, bucket, object stri
|
|||
return writer, encStartOffset, encLength, nil
|
||||
}
|
||||
|
||||
seqNumber, encStartOffset, encLength = getEncryptedMultipartsOffsetLength(startOffset, length, objInfo)
|
||||
var partStartIndex int
|
||||
var partStartOffset = startOffset
|
||||
// Skip parts until final offset maps to a particular part offset.
|
||||
|
@ -716,15 +714,62 @@ func DecryptBlocksRequest(client io.Writer, r *http.Request, bucket, object stri
|
|||
w.customerKeyHeader = r.Header.Get(SSECopyCustomerKey)
|
||||
}
|
||||
|
||||
if err := w.buildDecrypter(partStartIndex + 1); err != nil {
|
||||
if err := w.buildDecrypter(w.parts[w.partIndex].Number); err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
return w, encStartOffset, encLength, nil
|
||||
}
|
||||
|
||||
// getEncryptedStartOffset - fetch sequence number, encrypted start offset and encrypted length.
|
||||
func getEncryptedStartOffset(offset, length int64) (seqNumber uint32, encOffset int64, encLength int64) {
|
||||
// getEncryptedMultipartsOffsetLength - fetch sequence number, encrypted start offset and encrypted length.
|
||||
func getEncryptedMultipartsOffsetLength(offset, length int64, obj ObjectInfo) (uint32, int64, int64) {
|
||||
|
||||
// Calculate encrypted offset of a multipart object
|
||||
computeEncOffset := func(off int64, obj ObjectInfo) (seqNumber uint32, encryptedOffset int64, err error) {
|
||||
var curPartEndOffset uint64
|
||||
var prevPartsEncSize int64
|
||||
for _, p := range obj.Parts {
|
||||
size, decErr := sio.DecryptedSize(uint64(p.Size))
|
||||
if decErr != nil {
|
||||
err = errObjectTampered // assign correct error type
|
||||
return
|
||||
}
|
||||
if off < int64(curPartEndOffset+size) {
|
||||
seqNumber, encryptedOffset, _ = getEncryptedSinglePartOffsetLength(off-int64(curPartEndOffset), 1, obj)
|
||||
encryptedOffset += int64(prevPartsEncSize)
|
||||
break
|
||||
}
|
||||
curPartEndOffset += size
|
||||
prevPartsEncSize += p.Size
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Calculate the encrypted start offset corresponding to the plain offset
|
||||
seqNumber, encStartOffset, _ := computeEncOffset(offset, obj)
|
||||
// Calculate also the encrypted end offset corresponding to plain offset + plain length
|
||||
_, encEndOffset, _ := computeEncOffset(offset+length-1, obj)
|
||||
|
||||
// encLength is the diff between encrypted end offset and encrypted start offset + one package size
|
||||
// to ensure all encrypted data are covered
|
||||
encLength := encEndOffset - encStartOffset + (64*1024 + 32)
|
||||
|
||||
// Calculate total size of all parts
|
||||
var totalPartsLength int64
|
||||
for _, p := range obj.Parts {
|
||||
totalPartsLength += p.Size
|
||||
}
|
||||
|
||||
// Set encLength to maximum possible value if it exceeded total parts size
|
||||
if encLength+encStartOffset > totalPartsLength {
|
||||
encLength = totalPartsLength - encStartOffset
|
||||
}
|
||||
|
||||
return seqNumber, encStartOffset, encLength
|
||||
}
|
||||
|
||||
// getEncryptedSinglePartOffsetLength - fetch sequence number, encrypted start offset and encrypted length.
|
||||
func getEncryptedSinglePartOffsetLength(offset, length int64, objInfo ObjectInfo) (seqNumber uint32, encOffset int64, encLength int64) {
|
||||
onePkgSize := int64(sseDAREPackageBlockSize + sseDAREPackageMetaSize)
|
||||
|
||||
seqNumber = uint32(offset / sseDAREPackageBlockSize)
|
||||
|
@ -742,6 +787,9 @@ func getEncryptedStartOffset(offset, length int64) (seqNumber uint32, encOffset
|
|||
encLength += onePkgSize
|
||||
}
|
||||
|
||||
if encLength+encOffset > objInfo.EncryptedSize() {
|
||||
encLength = objInfo.EncryptedSize() - encOffset
|
||||
}
|
||||
return seqNumber, encOffset, encLength
|
||||
}
|
||||
|
||||
|
@ -786,7 +834,7 @@ func (o *ObjectInfo) DecryptedSize() (int64, error) {
|
|||
if !o.IsEncrypted() {
|
||||
return 0, errors.New("Cannot compute decrypted size of an unencrypted object")
|
||||
}
|
||||
if len(o.Parts) == 0 {
|
||||
if len(o.Parts) == 0 || !o.IsEncryptedMultipart() {
|
||||
size, err := sio.DecryptedSize(uint64(o.Size))
|
||||
if err != nil {
|
||||
err = errObjectTampered // assign correct error type
|
||||
|
|
|
@ -1038,6 +1038,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
|
|||
|
||||
var writer io.WriteCloser = pipeWriter
|
||||
var reader io.Reader = pipeReader
|
||||
var getLength = length
|
||||
srcInfo.Reader, err = hash.NewReader(reader, length, "", "")
|
||||
if err != nil {
|
||||
pipeWriter.CloseWithError(err)
|
||||
|
@ -1057,7 +1058,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
|
|||
// Response writer should be limited early on for decryption upto required length,
|
||||
// additionally also skipping mod(offset)64KiB boundaries.
|
||||
writer = ioutil.LimitedWriter(writer, startOffset%(64*1024), length)
|
||||
writer, startOffset, length, err = DecryptBlocksRequest(writer, r, srcBucket, srcObject, startOffset, length, srcInfo, true)
|
||||
writer, startOffset, getLength, err = DecryptBlocksRequest(writer, r, srcBucket, srcObject, startOffset, length, srcInfo, true)
|
||||
if err != nil {
|
||||
pipeWriter.CloseWithError(err)
|
||||
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||
|
@ -1098,12 +1099,8 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
|
|||
return
|
||||
}
|
||||
|
||||
size := length
|
||||
if !sseCopyC {
|
||||
info := ObjectInfo{Size: length}
|
||||
size = info.EncryptedSize()
|
||||
}
|
||||
|
||||
info := ObjectInfo{Size: length}
|
||||
size := info.EncryptedSize()
|
||||
srcInfo.Reader, err = hash.NewReader(reader, size, "", "")
|
||||
if err != nil {
|
||||
pipeWriter.CloseWithError(err)
|
||||
|
@ -1117,7 +1114,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
|
|||
// Copy source object to destination, if source and destination
|
||||
// object is same then only metadata is updated.
|
||||
partInfo, err := objectAPI.CopyObjectPart(ctx, srcBucket, srcObject, dstBucket,
|
||||
dstObject, uploadID, partID, startOffset, length, srcInfo)
|
||||
dstObject, uploadID, partID, startOffset, getLength, srcInfo)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||
return
|
||||
|
|
Loading…
Reference in New Issue