in v3/client/encrypt_middleware.go [52:147]
func (m *encryptMiddleware) HandleSerialize(
ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler,
) (
out middleware.SerializeOutput, metadata middleware.Metadata, err error,
) {
req, ok := in.Request.(*smithyhttp.Request)
if !ok {
return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)}
}
input, ok := in.Parameters.(*s3.PutObjectInput)
if !ok {
return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)}
}
// TODO - customize errors?
reqCopy, err := req.SetStream(input.Body)
if err != nil {
return out, metadata, &smithy.SerializationError{Err: err}
}
n, ok, err := reqCopy.StreamLength()
if !ok || err != nil {
return out, metadata, err
}
dst, err := internal.GetWriterStore(m.ec.Options.TempFolderPath, n >= m.ec.Options.MinFileSize)
if err != nil {
return out, metadata, err
}
ec := ctx.Value(EncryptionContext)
if ec == nil {
ec = map[string]string{}
}
var matDesc materials.MaterialDescription = ec.(map[string]string)
cmm := m.ec.Options.CryptographicMaterialsManager
cryptoMaterials, err := cmm.GetEncryptionMaterials(ctx, matDesc)
if err != nil {
return out, metadata, err
}
cipher, err := internal.NewAESGCMContentCipher(*cryptoMaterials)
if err != nil {
return out, metadata, err
}
stream := reqCopy.GetStream()
lengthReader := internal.NewContentLengthReader(stream)
reader, err := cipher.EncryptContents(lengthReader)
if err != nil {
return out, metadata, err
}
_, err = io.Copy(dst, reader)
if err != nil {
return out, metadata, err
}
data := cipher.GetCipherData()
envelope, err := internal.EncodeMeta(lengthReader, data)
if err != nil {
return out, metadata, err
}
// rewind
if _, err := dst.Seek(0, io.SeekStart); err != nil {
return out, metadata, err
}
// update the request body to encrypted contents
input.Body = dst
// save the metadata
saveReq := &internal.SaveStrategyRequest{
Envelope: &envelope,
HTTPRequest: req.Request,
Input: input,
}
// this saves the required crypto params (IV, tag length, etc.)
strat := internal.ObjectMetadataSaveStrategy{}
if err = strat.Save(ctx, saveReq); err != nil {
return out, metadata, err
}
// update the middleware input's parameter which is what the generated serialize step will use
in.Parameters = input
out, metadata, err = next.HandleSerialize(ctx, in)
// cleanup any temp files after the request is made
dst.Cleanup()
return out, metadata, err
}