server-side.go (6469B)
1 /* 2 * MinIO Go Library for Amazon S3 Compatible Cloud Storage 3 * Copyright 2018 MinIO, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package encrypt 19 20 import ( 21 "crypto/md5" 22 "encoding/base64" 23 "errors" 24 "net/http" 25 26 jsoniter "github.com/json-iterator/go" 27 "golang.org/x/crypto/argon2" 28 ) 29 30 const ( 31 // SseGenericHeader is the AWS SSE header used for SSE-S3 and SSE-KMS. 32 SseGenericHeader = "X-Amz-Server-Side-Encryption" 33 34 // SseKmsKeyID is the AWS SSE-KMS key id. 35 SseKmsKeyID = SseGenericHeader + "-Aws-Kms-Key-Id" 36 // SseEncryptionContext is the AWS SSE-KMS Encryption Context data. 37 SseEncryptionContext = SseGenericHeader + "-Context" 38 39 // SseCustomerAlgorithm is the AWS SSE-C algorithm HTTP header key. 40 SseCustomerAlgorithm = SseGenericHeader + "-Customer-Algorithm" 41 // SseCustomerKey is the AWS SSE-C encryption key HTTP header key. 42 SseCustomerKey = SseGenericHeader + "-Customer-Key" 43 // SseCustomerKeyMD5 is the AWS SSE-C encryption key MD5 HTTP header key. 44 SseCustomerKeyMD5 = SseGenericHeader + "-Customer-Key-MD5" 45 46 // SseCopyCustomerAlgorithm is the AWS SSE-C algorithm HTTP header key for CopyObject API. 47 SseCopyCustomerAlgorithm = "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Algorithm" 48 // SseCopyCustomerKey is the AWS SSE-C encryption key HTTP header key for CopyObject API. 49 SseCopyCustomerKey = "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key" 50 // SseCopyCustomerKeyMD5 is the AWS SSE-C encryption key MD5 HTTP header key for CopyObject API. 51 SseCopyCustomerKeyMD5 = "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key-MD5" 52 ) 53 54 // PBKDF creates a SSE-C key from the provided password and salt. 55 // PBKDF is a password-based key derivation function 56 // which can be used to derive a high-entropy cryptographic 57 // key from a low-entropy password and a salt. 58 type PBKDF func(password, salt []byte) ServerSide 59 60 // DefaultPBKDF is the default PBKDF. It uses Argon2id with the 61 // recommended parameters from the RFC draft (1 pass, 64 MB memory, 4 threads). 62 var DefaultPBKDF PBKDF = func(password, salt []byte) ServerSide { 63 sse := ssec{} 64 copy(sse[:], argon2.IDKey(password, salt, 1, 64*1024, 4, 32)) 65 return sse 66 } 67 68 // Type is the server-side-encryption method. It represents one of 69 // the following encryption methods: 70 // - SSE-C: server-side-encryption with customer provided keys 71 // - KMS: server-side-encryption with managed keys 72 // - S3: server-side-encryption using S3 storage encryption 73 type Type string 74 75 const ( 76 // SSEC represents server-side-encryption with customer provided keys 77 SSEC Type = "SSE-C" 78 // KMS represents server-side-encryption with managed keys 79 KMS Type = "KMS" 80 // S3 represents server-side-encryption using S3 storage encryption 81 S3 Type = "S3" 82 ) 83 84 // ServerSide is a form of S3 server-side-encryption. 85 type ServerSide interface { 86 // Type returns the server-side-encryption method. 87 Type() Type 88 89 // Marshal adds encryption headers to the provided HTTP headers. 90 // It marks an HTTP request as server-side-encryption request 91 // and inserts the required data into the headers. 92 Marshal(h http.Header) 93 } 94 95 // NewSSE returns a server-side-encryption using S3 storage encryption. 96 // Using SSE-S3 the server will encrypt the object with server-managed keys. 97 func NewSSE() ServerSide { return s3{} } 98 99 // NewSSEKMS returns a new server-side-encryption using SSE-KMS and the provided Key Id and context. 100 func NewSSEKMS(keyID string, context interface{}) (ServerSide, error) { 101 if context == nil { 102 return kms{key: keyID, hasContext: false}, nil 103 } 104 json := jsoniter.ConfigCompatibleWithStandardLibrary 105 serializedContext, err := json.Marshal(context) 106 if err != nil { 107 return nil, err 108 } 109 return kms{key: keyID, context: serializedContext, hasContext: true}, nil 110 } 111 112 // NewSSEC returns a new server-side-encryption using SSE-C and the provided key. 113 // The key must be 32 bytes long. 114 func NewSSEC(key []byte) (ServerSide, error) { 115 if len(key) != 32 { 116 return nil, errors.New("encrypt: SSE-C key must be 256 bit long") 117 } 118 sse := ssec{} 119 copy(sse[:], key) 120 return sse, nil 121 } 122 123 // SSE transforms a SSE-C copy encryption into a SSE-C encryption. 124 // It is the inverse of SSECopy(...). 125 // 126 // If the provided sse is no SSE-C copy encryption SSE returns 127 // sse unmodified. 128 func SSE(sse ServerSide) ServerSide { 129 if sse == nil || sse.Type() != SSEC { 130 return sse 131 } 132 if sse, ok := sse.(ssecCopy); ok { 133 return ssec(sse) 134 } 135 return sse 136 } 137 138 // SSECopy transforms a SSE-C encryption into a SSE-C copy 139 // encryption. This is required for SSE-C key rotation or a SSE-C 140 // copy where the source and the destination should be encrypted. 141 // 142 // If the provided sse is no SSE-C encryption SSECopy returns 143 // sse unmodified. 144 func SSECopy(sse ServerSide) ServerSide { 145 if sse == nil || sse.Type() != SSEC { 146 return sse 147 } 148 if sse, ok := sse.(ssec); ok { 149 return ssecCopy(sse) 150 } 151 return sse 152 } 153 154 type ssec [32]byte 155 156 func (s ssec) Type() Type { return SSEC } 157 158 func (s ssec) Marshal(h http.Header) { 159 keyMD5 := md5.Sum(s[:]) 160 h.Set(SseCustomerAlgorithm, "AES256") 161 h.Set(SseCustomerKey, base64.StdEncoding.EncodeToString(s[:])) 162 h.Set(SseCustomerKeyMD5, base64.StdEncoding.EncodeToString(keyMD5[:])) 163 } 164 165 type ssecCopy [32]byte 166 167 func (s ssecCopy) Type() Type { return SSEC } 168 169 func (s ssecCopy) Marshal(h http.Header) { 170 keyMD5 := md5.Sum(s[:]) 171 h.Set(SseCopyCustomerAlgorithm, "AES256") 172 h.Set(SseCopyCustomerKey, base64.StdEncoding.EncodeToString(s[:])) 173 h.Set(SseCopyCustomerKeyMD5, base64.StdEncoding.EncodeToString(keyMD5[:])) 174 } 175 176 type s3 struct{} 177 178 func (s s3) Type() Type { return S3 } 179 180 func (s s3) Marshal(h http.Header) { h.Set(SseGenericHeader, "AES256") } 181 182 type kms struct { 183 key string 184 context []byte 185 hasContext bool 186 } 187 188 func (s kms) Type() Type { return KMS } 189 190 func (s kms) Marshal(h http.Header) { 191 h.Set(SseGenericHeader, "aws:kms") 192 if s.key != "" { 193 h.Set(SseKmsKeyID, s.key) 194 } 195 if s.hasContext { 196 h.Set(SseEncryptionContext, base64.StdEncoding.EncodeToString(s.context)) 197 } 198 }