storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/crypto/sse.go (about) 1 // MinIO Cloud Storage, (C) 2015, 2016, 2017, 2018 MinIO, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package crypto 16 17 import ( 18 "context" 19 "errors" 20 "fmt" 21 "io" 22 "net/http" 23 24 "github.com/minio/sio" 25 26 "storj.io/minio/cmd/logger" 27 "storj.io/minio/pkg/fips" 28 "storj.io/minio/pkg/ioutil" 29 ) 30 31 const ( 32 // SealAlgorithm is the encryption/sealing algorithm used to derive & seal 33 // the key-encryption-key and to en/decrypt the object data. 34 SealAlgorithm = "DAREv2-HMAC-SHA256" 35 36 // InsecureSealAlgorithm is the legacy encryption/sealing algorithm used 37 // to derive & seal the key-encryption-key and to en/decrypt the object data. 38 // This algorithm should not be used for new objects because its key derivation 39 // is not optimal. See: https://github.com/minio/minio/pull/6121 40 InsecureSealAlgorithm = "DARE-SHA256" 41 ) 42 43 // Type represents an AWS SSE type: 44 // • SSE-C 45 // • SSE-S3 46 // • SSE-KMS 47 type Type interface { 48 fmt.Stringer 49 50 IsRequested(http.Header) bool 51 52 IsEncrypted(map[string]string) bool 53 } 54 55 // IsRequested returns true and the SSE Type if the HTTP headers 56 // indicate that some form server-side encryption is requested. 57 // 58 // If no SSE headers are present then IsRequested returns false 59 // and no Type. 60 func IsRequested(h http.Header) (Type, bool) { 61 switch { 62 case S3.IsRequested(h): 63 return S3, true 64 case S3KMS.IsRequested(h): 65 return S3KMS, true 66 case SSEC.IsRequested(h): 67 return SSEC, true 68 default: 69 return nil, false 70 } 71 } 72 73 // UnsealObjectKey extracts and decrypts the sealed object key 74 // from the metadata using the SSE-Copy client key of the HTTP headers 75 // and returns the decrypted object key. 76 func (sse ssecCopy) UnsealObjectKey(h http.Header, metadata map[string]string, bucket, object string) (key ObjectKey, err error) { 77 clientKey, err := sse.ParseHTTP(h) 78 if err != nil { 79 return 80 } 81 return unsealObjectKey(clientKey[:], metadata, bucket, object) 82 } 83 84 // unsealObjectKey decrypts and returns the sealed object key 85 // from the metadata using the SSE-C client key. 86 func unsealObjectKey(clientKey []byte, metadata map[string]string, bucket, object string) (key ObjectKey, err error) { 87 sealedKey, err := SSEC.ParseMetadata(metadata) 88 if err != nil { 89 return 90 } 91 err = key.Unseal(clientKey, sealedKey, SSEC.String(), bucket, object) 92 return 93 } 94 95 // EncryptSinglePart encrypts an io.Reader which must be the 96 // the body of a single-part PUT request. 97 func EncryptSinglePart(r io.Reader, key ObjectKey) io.Reader { 98 r, err := sio.EncryptReader(r, sio.Config{MinVersion: sio.Version20, Key: key[:], CipherSuites: fips.CipherSuitesDARE()}) 99 if err != nil { 100 logger.CriticalIf(context.Background(), errors.New("Unable to encrypt io.Reader using object key")) 101 } 102 return r 103 } 104 105 // EncryptMultiPart encrypts an io.Reader which must be the body of 106 // multi-part PUT request. It derives an unique encryption key from 107 // the partID and the object key. 108 func EncryptMultiPart(r io.Reader, partID int, key ObjectKey) io.Reader { 109 partKey := key.DerivePartKey(uint32(partID)) 110 return EncryptSinglePart(r, ObjectKey(partKey)) 111 } 112 113 // DecryptSinglePart decrypts an io.Writer which must an object 114 // uploaded with the single-part PUT API. The offset and length 115 // specify the requested range. 116 func DecryptSinglePart(w io.Writer, offset, length int64, key ObjectKey) io.WriteCloser { 117 const PayloadSize = 1 << 16 // DARE 2.0 118 w = ioutil.LimitedWriter(w, offset%PayloadSize, length) 119 120 decWriter, err := sio.DecryptWriter(w, sio.Config{Key: key[:], CipherSuites: fips.CipherSuitesDARE()}) 121 if err != nil { 122 logger.CriticalIf(context.Background(), errors.New("Unable to decrypt io.Writer using object key")) 123 } 124 return decWriter 125 }