github.com/aavshr/aws-sdk-go@v1.41.3/service/s3/s3crypto/shared_client.go (about) 1 package s3crypto 2 3 import ( 4 "encoding/base64" 5 "encoding/hex" 6 "io" 7 "strings" 8 9 "github.com/aavshr/aws-sdk-go/aws" 10 "github.com/aavshr/aws-sdk-go/aws/awserr" 11 "github.com/aavshr/aws-sdk-go/aws/request" 12 "github.com/aavshr/aws-sdk-go/internal/sdkio" 13 "github.com/aavshr/aws-sdk-go/service/s3" 14 ) 15 16 // clientConstructionErrorCode is used for operations that can't be completed due to invalid client construction 17 const clientConstructionErrorCode = "ClientConstructionError" 18 19 // mismatchWrapError is an error returned if a wrapping handler receives an unexpected envelope 20 var mismatchWrapError = awserr.New(clientConstructionErrorCode, "wrap algorithm provided did not match handler", nil) 21 22 func putObjectRequest(c EncryptionClientOptions, input *s3.PutObjectInput) (*request.Request, *s3.PutObjectOutput) { 23 req, out := c.S3Client.PutObjectRequest(input) 24 25 // Get Size of file 26 n, err := aws.SeekerLen(input.Body) 27 if err != nil { 28 req.Error = err 29 return req, out 30 } 31 32 dst, err := getWriterStore(req, c.TempFolderPath, n >= c.MinFileSize) 33 if err != nil { 34 req.Error = err 35 return req, out 36 } 37 38 req.Handlers.Build.PushFront(func(r *request.Request) { 39 if err != nil { 40 r.Error = err 41 return 42 } 43 var encryptor ContentCipher 44 if v, ok := c.ContentCipherBuilder.(ContentCipherBuilderWithContext); ok { 45 encryptor, err = v.ContentCipherWithContext(r.Context()) 46 } else { 47 encryptor, err = c.ContentCipherBuilder.ContentCipher() 48 } 49 if err != nil { 50 r.Error = err 51 return 52 } 53 54 lengthReader := newContentLengthReader(input.Body) 55 sha := newSHA256Writer(dst) 56 reader, err := encryptor.EncryptContents(lengthReader) 57 if err != nil { 58 r.Error = err 59 return 60 } 61 62 _, err = io.Copy(sha, reader) 63 if err != nil { 64 r.Error = err 65 return 66 } 67 68 data := encryptor.GetCipherData() 69 env, err := encodeMeta(lengthReader, data) 70 if err != nil { 71 r.Error = err 72 return 73 } 74 75 shaHex := hex.EncodeToString(sha.GetValue()) 76 req.HTTPRequest.Header.Set("X-Amz-Content-Sha256", shaHex) 77 78 dst.Seek(0, sdkio.SeekStart) 79 input.Body = dst 80 81 err = c.SaveStrategy.Save(env, r) 82 r.Error = err 83 }) 84 85 return req, out 86 } 87 88 func putObject(options EncryptionClientOptions, input *s3.PutObjectInput) (*s3.PutObjectOutput, error) { 89 req, out := putObjectRequest(options, input) 90 return out, req.Send() 91 } 92 93 func putObjectWithContext(options EncryptionClientOptions, ctx aws.Context, input *s3.PutObjectInput, opts ...request.Option) (*s3.PutObjectOutput, error) { 94 req, out := putObjectRequest(options, input) 95 req.SetContext(ctx) 96 req.ApplyOptions(opts...) 97 return out, req.Send() 98 } 99 100 func getObjectRequest(options DecryptionClientOptions, input *s3.GetObjectInput) (*request.Request, *s3.GetObjectOutput) { 101 req, out := options.S3Client.GetObjectRequest(input) 102 req.Handlers.Unmarshal.PushBack(func(r *request.Request) { 103 env, err := options.LoadStrategy.Load(r) 104 if err != nil { 105 r.Error = err 106 out.Body.Close() 107 return 108 } 109 110 // If KMS should return the correct cek algorithm with the proper 111 // KMS key provider 112 cipher, err := contentCipherFromEnvelope(options, r.Context(), env) 113 if err != nil { 114 r.Error = err 115 out.Body.Close() 116 return 117 } 118 119 reader, err := cipher.DecryptContents(out.Body) 120 if err != nil { 121 r.Error = err 122 out.Body.Close() 123 return 124 } 125 out.Body = reader 126 }) 127 return req, out 128 } 129 130 func getObject(options DecryptionClientOptions, input *s3.GetObjectInput) (*s3.GetObjectOutput, error) { 131 req, out := getObjectRequest(options, input) 132 return out, req.Send() 133 } 134 135 func getObjectWithContext(options DecryptionClientOptions, ctx aws.Context, input *s3.GetObjectInput, opts ...request.Option) (*s3.GetObjectOutput, error) { 136 req, out := getObjectRequest(options, input) 137 req.SetContext(ctx) 138 req.ApplyOptions(opts...) 139 return out, req.Send() 140 } 141 142 func contentCipherFromEnvelope(options DecryptionClientOptions, ctx aws.Context, env Envelope) (ContentCipher, error) { 143 wrap, err := wrapFromEnvelope(options, env) 144 if err != nil { 145 return nil, err 146 } 147 148 return cekFromEnvelope(options, ctx, env, wrap) 149 } 150 151 func wrapFromEnvelope(options DecryptionClientOptions, env Envelope) (CipherDataDecrypter, error) { 152 f, ok := options.CryptoRegistry.GetWrap(env.WrapAlg) 153 if !ok || f == nil { 154 155 return nil, awserr.New( 156 "InvalidWrapAlgorithmError", 157 "wrap algorithm isn't supported, "+env.WrapAlg, 158 nil, 159 ) 160 } 161 return f(env) 162 } 163 164 func cekFromEnvelope(options DecryptionClientOptions, ctx aws.Context, env Envelope, decrypter CipherDataDecrypter) (ContentCipher, error) { 165 f, ok := options.CryptoRegistry.GetCEK(env.CEKAlg) 166 if !ok || f == nil { 167 return nil, awserr.New( 168 "InvalidCEKAlgorithmError", 169 "cek algorithm isn't supported, "+env.CEKAlg, 170 nil, 171 ) 172 } 173 174 key, err := base64.StdEncoding.DecodeString(env.CipherKey) 175 if err != nil { 176 return nil, err 177 } 178 179 iv, err := base64.StdEncoding.DecodeString(env.IV) 180 if err != nil { 181 return nil, err 182 } 183 184 if d, ok := decrypter.(CipherDataDecrypterWithContext); ok { 185 key, err = d.DecryptKeyWithContext(ctx, key) 186 } else { 187 key, err = decrypter.DecryptKey(key) 188 } 189 190 if err != nil { 191 return nil, err 192 } 193 194 cd := CipherData{ 195 Key: key, 196 IV: iv, 197 CEKAlgorithm: env.CEKAlg, 198 Padder: getPadder(options, env.CEKAlg), 199 } 200 return f(cd) 201 } 202 203 // getPadder will return an unpadder with checking the cek algorithm specific padder. 204 // If there wasn't a cek algorithm specific padder, we check the padder itself. 205 // We return a no unpadder, if no unpadder was found. This means any customization 206 // either contained padding within the cipher implementation, and to maintain 207 // backwards compatibility we will simply not unpad anything. 208 func getPadder(options DecryptionClientOptions, cekAlg string) Padder { 209 padder, ok := options.CryptoRegistry.GetPadder(cekAlg) 210 if !ok { 211 padder, ok = options.CryptoRegistry.GetPadder(cekAlg[strings.LastIndex(cekAlg, "/")+1:]) 212 if !ok { 213 return NoPadder 214 } 215 } 216 return padder 217 }