Documentation ¶
Overview ¶
Package crypto implements AWS S3 related cryptographic building blocks for implementing Server-Side-Encryption (SSE-S3) and Server-Side-Encryption with customer provided keys (SSE-C).
All objects are encrypted with an unique and randomly generated 'ObjectKey'. The ObjectKey itself is never stored in plaintext. Instead it is only stored in a sealed from. The sealed 'ObjectKey' is created by encrypting the 'ObjectKey' with an unique key-encryption-key. Given the correct key-encryption-key the sealed 'ObjectKey' can be unsealed and the object can be decrypted.
## SSE-C
SSE-C computes the key-encryption-key from the client-provided key, an initialization vector (IV) and the bucket/object path.
- Encrypt: Input: ClientKey, bucket, object, metadata, object_data - IV := Random({0,1}²⁵⁶) - ObjectKey := SHA256(ClientKey || Random({0,1}²⁵⁶)) - KeyEncKey := HMAC-SHA256(ClientKey, IV || 'SSE-C' || 'DAREv2-HMAC-SHA256' || bucket || '/' || object) - SealedKey := DAREv2_Enc(KeyEncKey, ObjectKey) - enc_object_data := DAREv2_Enc(ObjectKey, object_data) - metadata <- IV - metadata <- SealedKey Output: enc_object_data, metadata
- Decrypt: Input: ClientKey, bucket, object, metadata, enc_object_data - IV <- metadata - SealedKey <- metadata - KeyEncKey := HMAC-SHA256(ClientKey, IV || 'SSE-C' || 'DAREv2-HMAC-SHA256' || bucket || '/' || object) - ObjectKey := DAREv2_Dec(KeyEncKey, SealedKey) - object_data := DAREv2_Dec(ObjectKey, enc_object_data) Output: object_data
## SSE-S3
SSE-S3 can use either a master key or a KMS as root-of-trust. The en/decryption slightly depens upon which root-of-trust is used.
### SSE-S3 and single master key
The master key is used to derive unique object- and key-encryption-keys. SSE-S3 with a single master key works as SSE-C where the master key is used as the client-provided key.
- Encrypt: Input: MasterKey, bucket, object, metadata, object_data - IV := Random({0,1}²⁵⁶) - ObjectKey := SHA256(MasterKey || Random({0,1}²⁵⁶)) - KeyEncKey := HMAC-SHA256(MasterKey, IV || 'SSE-S3' || 'DAREv2-HMAC-SHA256' || bucket || '/' || object) - SealedKey := DAREv2_Enc(KeyEncKey, ObjectKey) - enc_object_data := DAREv2_Enc(ObjectKey, object_data) - metadata <- IV - metadata <- SealedKey Output: enc_object_data, metadata
- Decrypt: Input: MasterKey, bucket, object, metadata, enc_object_data - IV <- metadata - SealedKey <- metadata - KeyEncKey := HMAC-SHA256(MasterKey, IV || 'SSE-S3' || 'DAREv2-HMAC-SHA256' || bucket || '/' || object) - ObjectKey := DAREv2_Dec(KeyEncKey, SealedKey) - object_data := DAREv2_Dec(ObjectKey, enc_object_data) Output: object_data
### SSE-S3 and KMS
SSE-S3 requires that the KMS provides two functions:
- Generate(KeyID) -> (Key, EncKey)
- Unseal(KeyID, EncKey) -> Key
- Encrypt: Input: KeyID, bucket, object, metadata, object_data - Key, EncKey := Generate(KeyID) - IV := Random({0,1}²⁵⁶) - ObjectKey := SHA256(Key, Random({0,1}²⁵⁶)) - KeyEncKey := HMAC-SHA256(Key, IV || 'SSE-S3' || 'DAREv2-HMAC-SHA256' || bucket || '/' || object) - SealedKey := DAREv2_Enc(KeyEncKey, ObjectKey) - enc_object_data := DAREv2_Enc(ObjectKey, object_data) - metadata <- IV - metadata <- KeyID - metadata <- EncKey - metadata <- SealedKey Output: enc_object_data, metadata
- Decrypt: Input: bucket, object, metadata, enc_object_data - KeyID <- metadata - EncKey <- metadata - IV <- metadata - SealedKey <- metadata - Key := Unseal(KeyID, EncKey) - KeyEncKey := HMAC-SHA256(Key, IV || 'SSE-S3' || 'DAREv2-HMAC-SHA256' || bucket || '/' || object) - ObjectKey := DAREv2_Dec(KeyEncKey, SealedKey) - object_data := DAREv2_Dec(ObjectKey, enc_object_data) Output: object_data
Index ¶
- Constants
- Variables
- func CreateMultipartMetadata(metadata map[string]string) map[string]string
- func DecryptSinglePart(w io.Writer, offset, length int64, key ObjectKey) io.WriteCloser
- func EncryptMultiPart(r io.Reader, partID int, key ObjectKey) io.Reader
- func EncryptSinglePart(r io.Reader, key ObjectKey) io.Reader
- func Errorf(format string, a ...interface{}) error
- func GenerateIV(random io.Reader) (iv [32]byte)
- func IsETagSealed(etag []byte) bool
- func IsMultiPart(metadata map[string]string) bool
- func IsSourceEncrypted(metadata map[string]string) bool
- func LookupAutoEncryption() bool
- func RemoveInternalEntries(metadata map[string]string)
- func RemoveSSEHeaders(metadata map[string]string)
- func RemoveSensitiveEntries(metadata map[string]string)
- func RemoveSensitiveHeaders(h http.Header)
- type Error
- type ObjectKey
- func (key ObjectKey) DerivePartKey(id uint32) (partKey [32]byte)
- func (key ObjectKey) Seal(extKey []byte, iv [32]byte, domain, bucket, object string) SealedKey
- func (key ObjectKey) SealETag(etag []byte) []byte
- func (key *ObjectKey) Unseal(extKey []byte, sealedKey SealedKey, domain, bucket, object string) error
- func (key ObjectKey) UnsealETag(etag []byte) ([]byte, error)
- type SealedKey
- type Type
Constants ¶
const ( // MetaMultipart indicates that the object has been uploaded // in multiple parts - via the S3 multipart API. MetaMultipart = "X-Minio-Internal-Encrypted-Multipart" // MetaIV is the random initialization vector (IV) used for // the MinIO-internal key derivation. MetaIV = "X-Minio-Internal-Server-Side-Encryption-Iv" // MetaAlgorithm is the algorithm used to derive internal keys // and encrypt the objects. MetaAlgorithm = "X-Minio-Internal-Server-Side-Encryption-Seal-Algorithm" // MetaSealedKeySSEC is the sealed object encryption key in case of SSE-C. MetaSealedKeySSEC = "X-Minio-Internal-Server-Side-Encryption-Sealed-Key" // MetaSealedKeyS3 is the sealed object encryption key in case of SSE-S3 MetaSealedKeyS3 = "X-Minio-Internal-Server-Side-Encryption-S3-Sealed-Key" // MetaSealedKeyKMS is the sealed object encryption key in case of SSE-KMS MetaSealedKeyKMS = "X-Minio-Internal-Server-Side-Encryption-Kms-Sealed-Key" // MetaKeyID is the KMS master key ID used to generate/encrypt the data // encryption key (DEK). MetaKeyID = "X-Minio-Internal-Server-Side-Encryption-S3-Kms-Key-Id" // MetaDataEncryptionKey is the sealed data encryption key (DEK) received from // the KMS. MetaDataEncryptionKey = "X-Minio-Internal-Server-Side-Encryption-S3-Kms-Sealed-Key" // MetaContext is the KMS context provided by a client when encrypting an // object with SSE-KMS. A client may not send a context in which case the // MetaContext will not be present. // MetaContext only contains the bucket/object name if the client explicitly // added it. However, when decrypting an object the bucket/object name must // be part of the object. Therefore, the bucket/object name must be added // to the context, if not present, whenever a decryption is performed. MetaContext = "X-Minio-Internal-Server-Side-Encryption-Context" )
const ( // SealAlgorithm is the encryption/sealing algorithm used to derive & seal // the key-encryption-key and to en/decrypt the object data. SealAlgorithm = "DAREv2-HMAC-SHA256" // InsecureSealAlgorithm is the legacy encryption/sealing algorithm used // to derive & seal the key-encryption-key and to en/decrypt the object data. // This algorithm should not be used for new objects because its key derivation // is not optimal. See: https://github.com/memoio/minio/pull/6121 InsecureSealAlgorithm = "DARE-SHA256" )
const ( // EnvKMSAutoEncryption is the environment variable used to en/disable // SSE-S3 auto-encryption. SSE-S3 auto-encryption, if enabled, // requires a valid KMS configuration and turns any non-SSE-C // request into an SSE-S3 request. // If present EnvAutoEncryption must be either "on" or "off". EnvKMSAutoEncryption = "MINIO_KMS_AUTO_ENCRYPTION" )
Variables ¶
var ( // ErrInvalidEncryptionMethod indicates that the specified SSE encryption method // is not supported. ErrInvalidEncryptionMethod = Errorf("The encryption method is not supported") // ErrInvalidCustomerAlgorithm indicates that the specified SSE-C algorithm // is not supported. ErrInvalidCustomerAlgorithm = Errorf("The SSE-C algorithm is not supported") // ErrMissingCustomerKey indicates that the HTTP headers contains no SSE-C client key. ErrMissingCustomerKey = Errorf("The SSE-C request is missing the customer key") // ErrMissingCustomerKeyMD5 indicates that the HTTP headers contains no SSE-C client key // MD5 checksum. ErrMissingCustomerKeyMD5 = Errorf("The SSE-C request is missing the customer key MD5") // ErrInvalidCustomerKey indicates that the SSE-C client key is not valid - e.g. not a // base64-encoded string or not 256 bits long. ErrInvalidCustomerKey = Errorf("The SSE-C client key is invalid") // ErrSecretKeyMismatch indicates that the provided secret key (SSE-C client key / SSE-S3 KMS key) // does not match the secret key used during encrypting the object. ErrSecretKeyMismatch = Errorf("The secret key does not match the secret key used during upload") // ErrCustomerKeyMD5Mismatch indicates that the SSE-C key MD5 does not match the // computed MD5 sum. This means that the client provided either the wrong key for // a certain MD5 checksum or the wrong MD5 for a certain key. ErrCustomerKeyMD5Mismatch = Errorf("The provided SSE-C key MD5 does not match the computed MD5 of the SSE-C key") // ErrIncompatibleEncryptionMethod indicates that both SSE-C headers and SSE-S3 headers were specified, and are incompatible // The client needs to remove the SSE-S3 header or the SSE-C headers ErrIncompatibleEncryptionMethod = Errorf("Server side encryption specified with both SSE-C and SSE-S3 headers") )
var ( // S3 represents AWS SSE-S3. It provides functionality to handle // SSE-S3 requests. S3 = sses3{} )
var ( // S3KMS represents AWS SSE-KMS. It provides functionality to // handle SSE-KMS requests. S3KMS = ssekms{} )
var ( // SSEC represents AWS SSE-C. It provides functionality to handle // SSE-C requests. SSEC = ssec{} )
var SSECopy = ssecCopy{}
SSECopy represents AWS SSE-C for copy requests. It provides functionality to handle SSE-C copy requests.
Functions ¶
func CreateMultipartMetadata ¶
CreateMultipartMetadata adds the multipart flag entry to metadata and returns modifed metadata. It allocates a new metadata map if metadata is nil.
func DecryptSinglePart ¶
DecryptSinglePart decrypts an io.Writer which must an object uploaded with the single-part PUT API. The offset and length specify the requested range.
func EncryptMultiPart ¶
EncryptMultiPart encrypts an io.Reader which must be the body of multi-part PUT request. It derives an unique encryption key from the partID and the object key.
func EncryptSinglePart ¶
EncryptSinglePart encrypts an io.Reader which must be the the body of a single-part PUT request.
func Errorf ¶
Errorf - formats according to a format specifier and returns the string as a value that satisfies error of type crypto.Error
func GenerateIV ¶
GenerateIV generates a new random 256 bit IV from the provided source of randomness. If random is nil the default PRNG of the system (crypto/rand) is used.
func IsETagSealed ¶
IsETagSealed returns true if the etag seems to be encrypted.
func IsMultiPart ¶
IsMultiPart returns true if the object metadata indicates that it was uploaded using some form of server-side-encryption and the S3 multipart API.
func IsSourceEncrypted ¶
IsSourceEncrypted returns true if the source is encrypted
func LookupAutoEncryption ¶
func LookupAutoEncryption() bool
LookupAutoEncryption returns true if and only if the MINIO_KMS_AUTO_ENCRYPTION env. variable is set to "on".
func RemoveInternalEntries ¶
RemoveInternalEntries removes all crypto-specific internal metadata entries from the metadata map.
func RemoveSSEHeaders ¶
RemoveSSEHeaders removes all crypto-specific SSE header entries from the metadata map.
func RemoveSensitiveEntries ¶
RemoveSensitiveEntries removes confidential encryption information - e.g. the SSE-C key - from the metadata map. It has the same semantics as RemoveSensitiveHeaders.
func RemoveSensitiveHeaders ¶
RemoveSensitiveHeaders removes confidential encryption information - e.g. the SSE-C key - from the HTTP headers. It has the same semantics as RemoveSensitiveEntires.
Types ¶
type Error ¶
type Error struct {
// contains filtered or unexported fields
}
Error is the generic type for any error happening during decrypting an object. It indicates that the object itself or its metadata was modified accidentally or maliciously.
type ObjectKey ¶
type ObjectKey [32]byte
ObjectKey is a 256 bit secret key used to encrypt the object. It must never be stored in plaintext.
func GenerateKey ¶
GenerateKey generates a unique ObjectKey from a 256 bit external key and a source of randomness. If random is nil the default PRNG of the system (crypto/rand) is used.
func (ObjectKey) DerivePartKey ¶
DerivePartKey derives an unique 256 bit key from an ObjectKey and the part index.
func (ObjectKey) Seal ¶
Seal encrypts the ObjectKey using the 256 bit external key and IV. The sealed key is also cryptographically bound to the object's path (bucket/object) and the domain (SSE-C or SSE-S3).
func (ObjectKey) SealETag ¶
SealETag seals the etag using the object key. It does not encrypt empty ETags because such ETags indicate that the S3 client hasn't sent an ETag = MD5(object) and the backend can pick an ETag value.
func (*ObjectKey) Unseal ¶
func (key *ObjectKey) Unseal(extKey []byte, sealedKey SealedKey, domain, bucket, object string) error
Unseal decrypts a sealed key using the 256 bit external key. Since the sealed key may be cryptographically bound to the object's path the same bucket/object as during sealing must be provided. On success the ObjectKey contains the decrypted sealed key.
func (ObjectKey) UnsealETag ¶
UnsealETag unseals the etag using the provided object key. It does not try to decrypt the ETag if len(etag) == 16 because such ETags indicate that the S3 client hasn't sent an ETag = MD5(object) and the backend has picked an ETag value.
type SealedKey ¶
type SealedKey struct { Key [64]byte // The encrypted and authenticted object-key. IV [32]byte // The random IV used to encrypt the object-key. Algorithm string // The sealing algorithm used to encrypt the object key. }
SealedKey represents a sealed object key. It can be stored at an untrusted location.
type Type ¶
type Type interface { fmt.Stringer IsRequested(http.Header) bool IsEncrypted(map[string]string) bool }
Type represents an AWS SSE type:
- SSE-C
- SSE-S3
- SSE-KMS
func IsEncrypted ¶
IsEncrypted returns true if the object metadata indicates that it was uploaded using some form of server-side-encryption.
IsEncrypted only checks whether the metadata contains at least one entry indicating SSE-C or SSE-S3.