2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								/ *  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Minio  Cloud  Storage ,  ( C )  2017  Minio ,  Inc . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Licensed  under  the  Apache  License ,  Version  2.0  ( the  "License" ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  you  may  not  use  this  file  except  in  compliance  with  the  License . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  You  may  obtain  a  copy  of  the  License  at 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *      http : //www.apache.org/licenses/LICENSE-2.0
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Unless  required  by  applicable  law  or  agreed  to  in  writing ,  software 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  distributed  under  the  License  is  distributed  on  an  "AS IS"  BASIS , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  WITHOUT  WARRANTIES  OR  CONDITIONS  OF  ANY  KIND ,  either  express  or  implied . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  See  the  License  for  the  specific  language  governing  permissions  and 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  limitations  under  the  License . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * / 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								package  cmd  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"bytes" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"crypto/md5" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"crypto/rand" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"encoding/base64" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"errors" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"io" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"net/http" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sha256  "github.com/minio/sha256-simd" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"github.com/minio/sio" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								var  (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// AWS errors for invalid SSE-C requests.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									errInsecureSSERequest   =  errors . New ( "Requests specifying Server Side Encryption with Customer provided keys must be made over a secure connection" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									errEncryptedObject      =  errors . New ( "The object was stored using a form of Server Side Encryption. The correct parameters must be provided to retrieve the object" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									errInvalidSSEAlgorithm  =  errors . New ( "Requests specifying Server Side Encryption with Customer provided keys must provide a valid encryption algorithm" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									errMissingSSEKey        =  errors . New ( "Requests specifying Server Side Encryption with Customer provided keys must provide an appropriate secret key" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									errInvalidSSEKey        =  errors . New ( "The secret key was invalid for the specified algorithm" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									errMissingSSEKeyMD5     =  errors . New ( "Requests specifying Server Side Encryption with Customer provided keys must provide the client calculated MD5 of the secret key" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									errSSEKeyMD5Mismatch    =  errors . New ( "The calculated MD5 hash of the key did not match the hash that was provided" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									errSSEKeyMismatch       =  errors . New ( "The client provided key does not match the key provided when the object was encrypted" )  // this msg is not shown to the client
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Additional Minio errors for SSE-C requests.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									errObjectTampered  =  errors . New ( "The requested object was modified and may be compromised" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// SSECustomerAlgorithm is the AWS SSE-C algorithm HTTP header key.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SSECustomerAlgorithm  =  "X-Amz-Server-Side-Encryption-Customer-Algorithm" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// SSECustomerKey is the AWS SSE-C encryption key HTTP header key.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SSECustomerKey  =  "X-Amz-Server-Side-Encryption-Customer-Key" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// SSECustomerKeyMD5 is the AWS SSE-C encryption key MD5 HTTP header key.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SSECustomerKeyMD5  =  "X-Amz-Server-Side-Encryption-Customer-Key-MD5" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// SSECustomerKeySize is the size of valid client provided encryption keys in bytes.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Currently AWS supports only AES256. So the SSE-C key size is fixed to 32 bytes.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SSECustomerKeySize  =  32 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// SSECustomerAlgorithmAES256 the only valid S3 SSE-C encryption algorithm identifier.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SSECustomerAlgorithmAES256  =  "AES256" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// SSE-C key derivation, key verification and key update:
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// H: Hash function [32 = |H(m)|]
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// AE: authenticated encryption scheme, AD: authenticated decryption scheme [m = AD(k, AE(k, m))]
  
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								//
  
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Key derivation:
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// 	 Input:
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// 		key     := 32 bytes              # client provided key
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// 		Re, Rm  := 32 bytes, 32 bytes    # uniformly random
  
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								//
  
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								//   Seal:
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// 		k       := H(key || Re)          # object encryption key
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// 		r       := H(Rm)                 # save as object metadata [ServerSideEncryptionIV]
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//		KeK     := H(key || r)           # key encryption key
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// 		K       := AE(KeK, k)            # save as object metadata [ServerSideEncryptionSealedKey]
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// ------------------------------------------------------------------------------------------------
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Key verification:
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// 	 Input:
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// 		key     := 32 bytes              # client provided key
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// 		r       := 32 bytes              # object metadata [ServerSideEncryptionIV]
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// 		K       := 32 bytes              # object metadata [ServerSideEncryptionSealedKey]
  
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								//
  
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								//   Open:
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//		KeK     := H(key || r)           # key encryption key
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//		k       := AD(Kek, K)            # object encryption key
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// -------------------------------------------------------------------------------------------------
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Key update:
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// 	 Input:
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// 		key     := 32 bytes              # old client provided key
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// 		key'    := 32 bytes              # new client provided key
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// 		Rm      := 32 bytes              # uniformly random
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// 		r       := 32 bytes              # object metadata [ServerSideEncryptionIV]
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// 		K       := 32 bytes              # object metadata [ServerSideEncryptionSealedKey]
  
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								//
  
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								//   Update:
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//      1. open:
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//			KeK     := H(key || r)       # key encryption key
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//			k       := AD(Kek, K)        # object encryption key
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//      2. seal:
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//			r'      := H(Rm)			 # save as object metadata [ServerSideEncryptionIV]
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//			KeK'    := H(key' || r')	 # new key encryption key
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// 			K'      := AE(KeK', k)       # save as object metadata [ServerSideEncryptionSealedKey]
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								const  (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// ServerSideEncryptionIV is a 32 byte randomly generated IV used to derive an
 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// unique key encryption key from the client provided key. The combination of this value
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// and the client-provided key MUST be unique.
 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									ServerSideEncryptionIV  =  ReservedMetadataPrefix  +  "Server-Side-Encryption-Iv" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// ServerSideEncryptionSealAlgorithm identifies a combination of a cryptographic hash function and
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// an authenticated en/decryption scheme to seal the object encryption key.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ServerSideEncryptionSealAlgorithm  =  ReservedMetadataPrefix  +  "Server-Side-Encryption-Seal-Algorithm" 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// ServerSideEncryptionSealedKey is the sealed object encryption key. The sealed key can be decrypted
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// by the key encryption key derived from the client provided key and the server-side-encryption IV.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ServerSideEncryptionSealedKey  =  ReservedMetadataPrefix  +  "Server-Side-Encryption-Sealed-Key" 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// SSESealAlgorithmDareSha256 specifies DARE as authenticated en/decryption scheme and SHA256 as cryptographic
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// hash function.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  SSESealAlgorithmDareSha256  =  "DARE-SHA256"  
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// IsSSECustomerRequest returns true if the given HTTP header
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// contains server-side-encryption with customer provided key fields.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  IsSSECustomerRequest ( header  http . Header )  bool  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  header . Get ( SSECustomerAlgorithm )  !=  ""  ||  header . Get ( SSECustomerKey )  !=  ""  ||  header . Get ( SSECustomerKeyMD5 )  !=  "" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// ParseSSECustomerRequest parses the SSE-C header fields of the provided request.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// It returns the client provided key on success.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ParseSSECustomerRequest ( r  * http . Request )  ( key  [ ] byte ,  err  error )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! globalIsSSL  {  // minio only supports HTTP or HTTPS requests not both at the same time
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// we cannot use r.TLS == nil here because Go's http implementation reflects on
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// the net.Conn and sets the TLS field of http.Request only if it's an tls.Conn.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Minio uses a BufConn (wrapping a tls.Conn) so the type check within the http package
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// will always fail -> r.TLS is always nil even for TLS requests.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  errInsecureSSERequest 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									header  :=  r . Header 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  algorithm  :=  header . Get ( SSECustomerAlgorithm ) ;  algorithm  !=  SSECustomerAlgorithmAES256  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  errInvalidSSEAlgorithm 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  header . Get ( SSECustomerKey )  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  errMissingSSEKey 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  header . Get ( SSECustomerKeyMD5 )  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  errMissingSSEKeyMD5 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									key ,  err  =  base64 . StdEncoding . DecodeString ( header . Get ( SSECustomerKey ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  errInvalidSSEKey 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									header . Del ( SSECustomerKey )  // make sure we do not save the key by accident
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  len ( key )  !=  SSECustomerKeySize  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  errInvalidSSEKey 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									keyMD5 ,  err  :=  base64 . StdEncoding . DecodeString ( header . Get ( SSECustomerKeyMD5 ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  errSSEKeyMD5Mismatch 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  md5Sum  :=  md5 . Sum ( key ) ;  ! bytes . Equal ( md5Sum [ : ] ,  keyMD5 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  errSSEKeyMD5Mismatch 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  key ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// EncryptRequest takes the client provided content and encrypts the data
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// with the client provided key. It also marks the object as client-side-encrypted
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// and sets the correct headers.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  EncryptRequest ( content  io . Reader ,  r  * http . Request ,  metadata  map [ string ] string )  ( io . Reader ,  error )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									key ,  err  :=  ParseSSECustomerRequest ( r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									delete ( metadata ,  SSECustomerKey )  // make sure we do not save the key by accident
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// security notice:
 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									//  - If the first 32 bytes of the random value are ever repeated under the same client-provided
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//    key the encrypted object will not be tamper-proof. [ P(coll) ~= 1 / 2^(256 / 2)]
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//  - If the last 32 bytes of the random value are ever repeated under the same client-provided
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//    key an adversary may be able to extract the object encryption key. This depends on the
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//    authenticated en/decryption scheme. The DARE format will generate an 8 byte nonce which must
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//    be repeated in addition to reveal the object encryption key.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//    [ P(coll) ~= 1 / 2^((256 + 64) / 2) ]
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									nonce  :=  make ( [ ] byte ,  64 )  // generate random values for key derivation
 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  _ ,  err  =  io . ReadFull ( rand . Reader ,  nonce ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									sha  :=  sha256 . New ( )  // derive object encryption key
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sha . Write ( key ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sha . Write ( nonce [ : 32 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									objectEncryptionKey  :=  sha . Sum ( nil ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									iv  :=  sha256 . Sum256 ( nonce [ 32 : ] )  // derive key encryption key
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sha  =  sha256 . New ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sha . Write ( key ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sha . Write ( iv [ : ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									keyEncryptionKey  :=  sha . Sum ( nil ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									sealedKey  :=  bytes . NewBuffer ( nil )  // sealedKey := 16 byte header + 32 byte payload + 16 byte tag
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									n ,  err  :=  sio . Encrypt ( sealedKey ,  bytes . NewReader ( objectEncryptionKey ) ,  sio . Config { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Key :  keyEncryptionKey , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  n  !=  64  ||  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  errors . New ( "failed to seal object encryption key" )  // if this happens there's a bug in the code (may panic ?)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									reader ,  err  :=  sio . EncryptReader ( content ,  sio . Config { Key :  objectEncryptionKey } ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  errInvalidSSEKey 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									metadata [ ServerSideEncryptionIV ]  =  base64 . StdEncoding . EncodeToString ( iv [ : ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									metadata [ ServerSideEncryptionSealAlgorithm ]  =  SSESealAlgorithmDareSha256 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									metadata [ ServerSideEncryptionSealedKey ]  =  base64 . StdEncoding . EncodeToString ( sealedKey . Bytes ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									return  reader ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// DecryptRequest decrypts the object with the client provided key. It also removes
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// the client-side-encryption metadata from the object and sets the correct headers.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  DecryptRequest ( client  io . Writer ,  r  * http . Request ,  metadata  map [ string ] string )  ( io . WriteCloser ,  error )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									key ,  err  :=  ParseSSECustomerRequest ( r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									delete ( metadata ,  SSECustomerKey )  // make sure we do not save the key by accident
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  metadata [ ServerSideEncryptionSealAlgorithm ]  !=  SSESealAlgorithmDareSha256  {  // currently DARE-SHA256 is the only option
 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return  nil ,  errObjectTampered 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									iv ,  err  :=  base64 . StdEncoding . DecodeString ( metadata [ ServerSideEncryptionIV ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  ||  len ( iv )  !=  32  { 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return  nil ,  errObjectTampered 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									sealedKey ,  err  :=  base64 . StdEncoding . DecodeString ( metadata [ ServerSideEncryptionSealedKey ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  ||  len ( sealedKey )  !=  64  { 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return  nil ,  errObjectTampered 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									sha  :=  sha256 . New ( )  // derive key encryption key
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sha . Write ( key ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sha . Write ( iv ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									keyEncryptionKey  :=  sha . Sum ( nil ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									objectEncryptionKey  :=  bytes . NewBuffer ( nil )  // decrypt object encryption key
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									n ,  err  :=  sio . Decrypt ( objectEncryptionKey ,  bytes . NewReader ( sealedKey ) ,  sio . Config { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Key :  keyEncryptionKey , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  n  !=  32  ||  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-21 06:04:10 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// Either the provided key does not match or the object was tampered.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// To provide strict AWS S3 compatibility we return: access denied.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  errSSEKeyMismatch 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									writer ,  err  :=  sio . DecryptWriter ( client ,  sio . Config { Key :  objectEncryptionKey . Bytes ( ) } ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  errInvalidSSEKey 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									delete ( metadata ,  ServerSideEncryptionIV ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									delete ( metadata ,  ServerSideEncryptionSealAlgorithm ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									delete ( metadata ,  ServerSideEncryptionSealedKey ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									return  writer ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// IsEncrypted returns true if the object is marked as encrypted.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( o  * ObjectInfo )  IsEncrypted ( )  bool  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  _ ,  ok  :=  o . UserDefined [ ServerSideEncryptionIV ] ;  ok  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  _ ,  ok  :=  o . UserDefined [ ServerSideEncryptionSealAlgorithm ] ;  ok  { 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-11 09:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  _ ,  ok  :=  o . UserDefined [ ServerSideEncryptionSealedKey ] ;  ok  { 
							 
						 
					
						
							
								
									
										
										
										
											2017-11-08 07:18:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// DecryptedSize returns the size of the object after decryption in bytes.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// It returns an error if the object is not encrypted or marked as encrypted
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// but has an invalid size.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// DecryptedSize panics if the referred object is not encrypted.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( o  * ObjectInfo )  DecryptedSize ( )  ( int64 ,  error )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! o . IsEncrypted ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										panic ( "cannot compute decrypted size of an object which is not encrypted" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  o . Size  ==  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  o . Size ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									size  :=  ( o . Size  /  ( 32  +  64 * 1024 ) )  *  ( 64  *  1024 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  mod  :=  o . Size  %  ( 32  +  64 * 1024 ) ;  mod  >  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  mod  <  33  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  - 1 ,  errObjectTampered  // object is not 0 size but smaller than the smallest valid encrypted object
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										size  +=  mod  -  32 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  size ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// EncryptedSize returns the size of the object after encryption.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// An encrypted object is always larger than a plain object
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// except for zero size objects.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( o  * ObjectInfo )  EncryptedSize ( )  int64  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									size  :=  ( o . Size  /  ( 64  *  1024 ) )  *  ( 32  +  64 * 1024 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  mod  :=  o . Size  %  ( 64  *  1024 ) ;  mod  >  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										size  +=  mod  +  32 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  size 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// DecryptObjectInfo tries to decrypt the provided object if it is encrypted.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// It fails if the object is encrypted and the HTTP headers don't contain
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// SSE-C headers or the object is not encrypted but SSE-C headers are provided. (AWS behavior)
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// DecryptObjectInfo returns 'ErrNone' if the object is not encrypted or the
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// decryption succeeded.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// DecryptObjectInfo also returns whether the object is encrypted or not.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  DecryptObjectInfo ( info  * ObjectInfo ,  headers  http . Header )  ( apiErr  APIErrorCode ,  encrypted  bool )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  apiErr ,  encrypted  =  ErrNone ,  info . IsEncrypted ( ) ;  ! encrypted  &&  IsSSECustomerRequest ( headers )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										apiErr  =  ErrInvalidEncryptionParameters 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  if  encrypted  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ! IsSSECustomerRequest ( headers )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											apiErr  =  ErrSSEEncryptedObject 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										var  err  error 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  info . Size ,  err  =  info . DecryptedSize ( ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											apiErr  =  toAPIErrorCode ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}