From ba17d46f15cf8c2089efb2a68cb78f6805f4f93d Mon Sep 17 00:00:00 2001 From: Andreas Auernhammer Date: Thu, 31 Mar 2022 00:23:25 +0200 Subject: [PATCH] ListObjectParts: simplify ETag decryption and size adjustment (#14653) This commit simplifies the ETag decryption and size adjustment when listing object parts. When listing object parts, MinIO has to decrypt the ETag of all parts if and only if the object resp. the parts is encrypted using SSE-S3. In case of SSE-KMS and SSE-C, MinIO returns a pseudo-random ETag. This is inline with AWS S3 behavior. Further, MinIO has to adjust the size of all encrypted parts due to the encryption overhead. The ListObjectParts does specifically not use the KMS bulk decryption API (4d2fc530d0a953e9957b8cc670ccdbdb568b3894) since the ETags of all parts are encrypted using the same object encryption key. Therefore, MinIO only has to connect to the KMS once, even if there are multiple parts resp. ETags. It can simply reuse the same object encryption key. Signed-off-by: Andreas Auernhammer --- cmd/object-handlers.go | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/cmd/object-handlers.go b/cmd/object-handlers.go index ecf82fe30..f861ac8f5 100644 --- a/cmd/object-handlers.go +++ b/cmd/object-handlers.go @@ -3025,34 +3025,29 @@ func (api objectAPIHandlers) ListObjectPartsHandler(w http.ResponseWriter, r *ht return } - var ssec bool - if _, ok := crypto.IsEncrypted(listPartsInfo.UserDefined); ok && objectAPI.IsEncryptionSupported() { - var key []byte - if crypto.SSEC.IsEncrypted(listPartsInfo.UserDefined) { - ssec = true - } + // We have to adjust the size of encrypted parts since encrypted parts + // are slightly larger due to encryption overhead. + // Further, we have to adjust the ETags of parts when using SSE-S3. + // Due to AWS S3, SSE-S3 encrypted parts return the plaintext ETag + // being the content MD5 of that particular part. This is not the + // case for SSE-C and SSE-KMS objects. + if kind, ok := crypto.IsEncrypted(listPartsInfo.UserDefined); ok && objectAPI.IsEncryptionSupported() { var objectEncryptionKey []byte - if crypto.S3.IsEncrypted(listPartsInfo.UserDefined) { - // Calculating object encryption key - objectEncryptionKey, err = decryptObjectInfo(key, bucket, object, listPartsInfo.UserDefined) + if kind == crypto.S3 { + objectEncryptionKey, err = decryptObjectInfo(nil, bucket, object, listPartsInfo.UserDefined) if err != nil { writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL) return } } - for i := range listPartsInfo.Parts { - curp := listPartsInfo.Parts[i] - curp.ETag = tryDecryptETag(objectEncryptionKey, curp.ETag, ssec) - if !ssec { - var partSize uint64 - partSize, err = sio.DecryptedSize(uint64(curp.Size)) - if err != nil { - writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL) - return - } - curp.Size = int64(partSize) + for i, p := range listPartsInfo.Parts { + listPartsInfo.Parts[i].ETag = tryDecryptETag(objectEncryptionKey, p.ETag, kind != crypto.S3) + size, err := sio.DecryptedSize(uint64(p.Size)) + if err != nil { + writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL) + return } - listPartsInfo.Parts[i] = curp + listPartsInfo.Parts[i].Size = int64(size) } }