diff --git a/cmd/encryption-v1.go b/cmd/encryption-v1.go index fd9c6752d..8c7f06601 100644 --- a/cmd/encryption-v1.go +++ b/cmd/encryption-v1.go @@ -32,7 +32,6 @@ import ( "github.com/minio/minio-go/v6/pkg/encrypt" "github.com/minio/minio/cmd/crypto" "github.com/minio/minio/cmd/logger" - "github.com/minio/minio/pkg/ioutil" sha256 "github.com/minio/sha256-simd" "github.com/minio/sio" ) @@ -64,17 +63,6 @@ const ( ) -const ( - // SSESealAlgorithmDareSha256 specifies DARE as authenticated en/decryption scheme and SHA256 as cryptographic - // hash function. The key derivation of DARE-SHA256 is not optimal and does not include the object path. - // It is considered legacy and should not be used anymore. - SSESealAlgorithmDareSha256 = "DARE-SHA256" - - // SSESealAlgorithmDareV2HmacSha256 specifies DAREv2 as authenticated en/decryption scheme and SHA256 as cryptographic - // hash function for the HMAC PRF. - SSESealAlgorithmDareV2HmacSha256 = "DAREv2-HMAC-SHA256" -) - // hasServerSideEncryptionHeader returns true if the given HTTP header // contains server-side-encryption. func hasServerSideEncryptionHeader(header http.Header) bool { @@ -597,236 +585,6 @@ func (d *DecryptBlocksReader) Read(p []byte) (int, error) { return len(p), nil } -// DecryptBlocksWriter - decrypts multipart parts, while implementing -// a io.Writer compatible interface. -type DecryptBlocksWriter struct { - // Original writer where the plain data will be written - writer io.Writer - // Current decrypter for the current encrypted data block - decrypter io.WriteCloser - // Start sequence number - startSeqNum uint32 - // Current part index - partIndex int - // Parts information - parts []ObjectPartInfo - req *http.Request - bucket, object string - metadata map[string]string - - partEncRelOffset int64 - - copySource bool - // Customer Key - customerKeyHeader string -} - -func (w *DecryptBlocksWriter) buildDecrypter(partID int) error { - m := make(map[string]string) - for k, v := range w.metadata { - m[k] = v - } - // Initialize the first decrypter, new decrypters will be initialized in Write() operation as needed. - var key []byte - var err error - if w.copySource { - if crypto.SSEC.IsEncrypted(w.metadata) { - w.req.Header.Set(crypto.SSECopyKey, w.customerKeyHeader) - key, err = ParseSSECopyCustomerRequest(w.req.Header, w.metadata) - } - } else { - if crypto.SSEC.IsEncrypted(w.metadata) { - w.req.Header.Set(crypto.SSECKey, w.customerKeyHeader) - key, err = ParseSSECustomerRequest(w.req) - } - } - if err != nil { - return err - } - - objectEncryptionKey, err := decryptObjectInfo(key, w.bucket, w.object, m) - if err != nil { - return err - } - - var partIDbin [4]byte - binary.LittleEndian.PutUint32(partIDbin[:], uint32(partID)) // marshal part ID - - mac := hmac.New(sha256.New, objectEncryptionKey) // derive part encryption key from part ID and object key - mac.Write(partIDbin[:]) - partEncryptionKey := mac.Sum(nil) - - // make sure to provide a NopCloser such that a Close - // on sio.decryptWriter doesn't close the underlying writer's - // close which perhaps can close the stream prematurely. - decrypter, err := newDecryptWriterWithObjectKey(ioutil.NopCloser(w.writer), partEncryptionKey, w.startSeqNum, m) - if err != nil { - return err - } - - if w.decrypter != nil { - // Pro-actively close the writer such that any pending buffers - // are flushed already before we allocate a new decrypter. - err = w.decrypter.Close() - if err != nil { - return err - } - } - - w.decrypter = decrypter - return nil -} - -func (w *DecryptBlocksWriter) Write(p []byte) (int, error) { - var err error - var n1 int - if int64(len(p)) < w.parts[w.partIndex].Size-w.partEncRelOffset { - n1, err = w.decrypter.Write(p) - if err != nil { - return 0, err - } - w.partEncRelOffset += int64(n1) - } else { - n1, err = w.decrypter.Write(p[:w.parts[w.partIndex].Size-w.partEncRelOffset]) - if err != nil { - return 0, err - } - - // We should now proceed to next part, reset all values appropriately. - w.partEncRelOffset = 0 - w.startSeqNum = 0 - - w.partIndex++ - - err = w.buildDecrypter(w.partIndex + 1) - if err != nil { - return 0, err - } - - n1, err = w.decrypter.Write(p[n1:]) - if err != nil { - return 0, err - } - - w.partEncRelOffset += int64(n1) - } - - return len(p), nil -} - -// Close closes the LimitWriter. It behaves like io.Closer. -func (w *DecryptBlocksWriter) Close() error { - if w.decrypter != nil { - err := w.decrypter.Close() - if err != nil { - return err - } - } - - if closer, ok := w.writer.(io.Closer); ok { - return closer.Close() - } - return nil -} - -// DecryptAllBlocksCopyRequest - setup a struct which can decrypt many concatenated encrypted data -// parts information helps to know the boundaries of each encrypted data block, this function decrypts -// all parts starting from part-1. -func DecryptAllBlocksCopyRequest(client io.Writer, r *http.Request, bucket, object string, objInfo ObjectInfo) (io.WriteCloser, int64, error) { - w, _, size, err := DecryptBlocksRequest(client, r, bucket, object, 0, objInfo.Size, objInfo, true) - return w, size, err -} - -// 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) { - var seqNumber uint32 - var encStartOffset, encLength int64 - - if !isEncryptedMultipart(objInfo) { - seqNumber, encStartOffset, encLength = getEncryptedSinglePartOffsetLength(startOffset, length, objInfo) - - var writer io.WriteCloser - var err error - if copySource { - writer, err = DecryptCopyRequest(client, r, bucket, object, objInfo.UserDefined) - } else { - writer, err = DecryptRequestWithSequenceNumber(client, r, bucket, object, seqNumber, objInfo.UserDefined) - } - if err != nil { - return nil, 0, 0, err - } - return writer, encStartOffset, encLength, nil - } - - _, encStartOffset, encLength = getEncryptedMultipartsOffsetLength(startOffset, length, objInfo) - - var partStartIndex int - var partStartOffset = startOffset - // Skip parts until final offset maps to a particular part offset. - for i, part := range objInfo.Parts { - decryptedSize, err := sio.DecryptedSize(uint64(part.Size)) - if err != nil { - return nil, -1, -1, errObjectTampered - } - - partStartIndex = i - - // Offset is smaller than size we have reached the - // proper part offset, break out we start from - // this part index. - if partStartOffset < int64(decryptedSize) { - break - } - - // Continue to look for next part. - partStartOffset -= int64(decryptedSize) - } - - startSeqNum := partStartOffset / SSEDAREPackageBlockSize - partEncRelOffset := int64(startSeqNum) * (SSEDAREPackageBlockSize + SSEDAREPackageMetaSize) - - w := &DecryptBlocksWriter{ - writer: client, - startSeqNum: uint32(startSeqNum), - partEncRelOffset: partEncRelOffset, - parts: objInfo.Parts, - partIndex: partStartIndex, - req: r, - bucket: bucket, - object: object, - customerKeyHeader: r.Header.Get(crypto.SSECKey), - copySource: copySource, - } - - w.metadata = map[string]string{} - // Copy encryption metadata for internal use. - for k, v := range objInfo.UserDefined { - w.metadata[k] = v - } - - // Purge all the encryption headers. - delete(objInfo.UserDefined, crypto.SSEIV) - delete(objInfo.UserDefined, crypto.SSESealAlgorithm) - delete(objInfo.UserDefined, crypto.SSECSealedKey) - delete(objInfo.UserDefined, crypto.SSEMultipart) - - if crypto.S3.IsEncrypted(objInfo.UserDefined) { - delete(objInfo.UserDefined, crypto.S3SealedKey) - delete(objInfo.UserDefined, crypto.S3KMSKeyID) - delete(objInfo.UserDefined, crypto.S3KMSSealedKey) - } - if w.copySource { - w.customerKeyHeader = r.Header.Get(crypto.SSECopyKey) - } - - if err := w.buildDecrypter(w.parts[w.partIndex].Number); err != nil { - return nil, 0, 0, err - } - - return w, encStartOffset, encLength, nil -} - // 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 diff --git a/cmd/encryption-v1_test.go b/cmd/encryption-v1_test.go index 223eda5a7..1c280e707 100644 --- a/cmd/encryption-v1_test.go +++ b/cmd/encryption-v1_test.go @@ -173,7 +173,7 @@ var decryptRequestTests = []struct { crypto.SSECKeyMD5: "7PpPLAK26ONlVUGOWlusfg==", }, metadata: map[string]string{ - crypto.SSESealAlgorithm: SSESealAlgorithmDareSha256, + crypto.SSESealAlgorithm: crypto.InsecureSealAlgorithm, crypto.SSEIV: "7nQqotA8xgrPx6QK7Ap3GCfjKitqJSrGP7xzgErSJlw=", crypto.SSECSealedKey: "EAAfAAAAAAD7v1hQq3PFRUHsItalxmrJqrOq6FwnbXNarxOOpb8jTWONPPKyM3Gfjkjyj6NCf+aB/VpHCLCTBA==", }, @@ -188,7 +188,7 @@ var decryptRequestTests = []struct { crypto.SSECKeyMD5: "7PpPLAK26ONlVUGOWlusfg==", }, metadata: map[string]string{ - crypto.SSESealAlgorithm: SSESealAlgorithmDareV2HmacSha256, + crypto.SSESealAlgorithm: crypto.SealAlgorithm, crypto.SSEIV: "qEqmsONcorqlcZXJxaw32H04eyXyXwUgjHzlhkaIYrU=", crypto.SSECSealedKey: "IAAfAIM14ugTGcM/dIrn4iQMrkl1sjKyeBQ8FBEvRebYj8vWvxG+0cJRpC6NXRU1wJN50JaUOATjO7kz0wZ2mA==", }, @@ -218,7 +218,7 @@ var decryptRequestTests = []struct { crypto.SSECKeyMD5: "bY4wkxQejw9mUJfo72k53A==", }, metadata: map[string]string{ - crypto.SSESealAlgorithm: SSESealAlgorithmDareSha256, + crypto.SSESealAlgorithm: crypto.InsecureSealAlgorithm, crypto.SSEIV: "RrJsEsyPb1UuFNezv1bl9hxuYsgUVC/MUctE2k=", crypto.SSECSealedKey: "SY5E9AvI2tI7/nUrUAssIGE32Hcs4rR9z/CUuPqu5N4=", }, @@ -233,7 +233,7 @@ var decryptRequestTests = []struct { crypto.SSECKeyMD5: "bY4wkxQejw9mUJfo72k53A==", }, metadata: map[string]string{ - crypto.SSESealAlgorithm: SSESealAlgorithmDareSha256, + crypto.SSESealAlgorithm: crypto.InsecureSealAlgorithm, crypto.SSEIV: "XAm0dRrJsEsyPb1UuFNezv1bl9ehxuYsgUVC/MUctE2k=", crypto.SSECSealedKey: "SY5E9AvI2tI7/nUrUAssIGE32Hds4rR9z/CUuPqu5N4=", }, @@ -248,7 +248,7 @@ var decryptRequestTests = []struct { crypto.SSECKeyMD5: "7PpPLAK26ONlVUGOWlusfg==", }, metadata: map[string]string{ - crypto.SSESealAlgorithm: SSESealAlgorithmDareV2HmacSha256, + crypto.SSESealAlgorithm: crypto.SealAlgorithm, crypto.SSEIV: "qEqmsONcorqlcZXJxaw32H04eyXyXwUgjHzlhkaIYrU=", crypto.SSECSealedKey: "IAAfAIM14ugTGcM/dIrn4iQMrkl1sjKyeBQ8FBEvRebYj8vWvxG+0cJRpC6NXRU1wJN50JaUOATjO7kz0wZ2mA==", }, @@ -298,12 +298,12 @@ var decryptObjectInfoTests = []struct { expErr: nil, }, { - info: ObjectInfo{Size: 100, UserDefined: map[string]string{crypto.SSESealAlgorithm: SSESealAlgorithmDareSha256}}, + info: ObjectInfo{Size: 100, UserDefined: map[string]string{crypto.SSESealAlgorithm: crypto.InsecureSealAlgorithm}}, headers: http.Header{crypto.SSECAlgorithm: []string{crypto.SSEAlgorithmAES256}}, expErr: nil, }, { - info: ObjectInfo{Size: 0, UserDefined: map[string]string{crypto.SSESealAlgorithm: SSESealAlgorithmDareSha256}}, + info: ObjectInfo{Size: 0, UserDefined: map[string]string{crypto.SSESealAlgorithm: crypto.InsecureSealAlgorithm}}, headers: http.Header{crypto.SSECAlgorithm: []string{crypto.SSEAlgorithmAES256}}, expErr: nil, }, @@ -318,7 +318,7 @@ var decryptObjectInfoTests = []struct { expErr: errInvalidEncryptionParameters, }, { - info: ObjectInfo{Size: 31, UserDefined: map[string]string{crypto.SSESealAlgorithm: SSESealAlgorithmDareSha256}}, + info: ObjectInfo{Size: 31, UserDefined: map[string]string{crypto.SSESealAlgorithm: crypto.InsecureSealAlgorithm}}, headers: http.Header{crypto.SSECAlgorithm: []string{crypto.SSEAlgorithmAES256}}, expErr: errObjectTampered, }, @@ -408,7 +408,7 @@ func TestGetDecryptedRange(t *testing.T) { } udMap = func(isMulti bool) map[string]string { m := map[string]string{ - crypto.SSESealAlgorithm: SSESealAlgorithmDareSha256, + crypto.SSESealAlgorithm: crypto.InsecureSealAlgorithm, crypto.SSEMultipart: "1", } if !isMulti { diff --git a/cmd/generic-handlers_test.go b/cmd/generic-handlers_test.go index d31845f13..1850b234c 100644 --- a/cmd/generic-handlers_test.go +++ b/cmd/generic-handlers_test.go @@ -185,7 +185,7 @@ var containsReservedMetadataTests = []struct { shouldFail: true, }, { - header: http.Header{crypto.SSESealAlgorithm: []string{SSESealAlgorithmDareSha256}}, + header: http.Header{crypto.SSESealAlgorithm: []string{crypto.InsecureSealAlgorithm}}, shouldFail: true, }, {