aws-sdk-s3 1.61.2 → 1.83.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. checksums.yaml +5 -5
  2. data/lib/aws-sdk-s3.rb +5 -2
  3. data/lib/aws-sdk-s3/arn/access_point_arn.rb +62 -0
  4. data/lib/aws-sdk-s3/arn/outpost_access_point_arn.rb +71 -0
  5. data/lib/aws-sdk-s3/bucket.rb +61 -10
  6. data/lib/aws-sdk-s3/bucket_acl.rb +7 -0
  7. data/lib/aws-sdk-s3/bucket_cors.rb +15 -2
  8. data/lib/aws-sdk-s3/bucket_lifecycle.rb +14 -1
  9. data/lib/aws-sdk-s3/bucket_lifecycle_configuration.rb +14 -1
  10. data/lib/aws-sdk-s3/bucket_logging.rb +7 -0
  11. data/lib/aws-sdk-s3/bucket_notification.rb +7 -0
  12. data/lib/aws-sdk-s3/bucket_policy.rb +14 -1
  13. data/lib/aws-sdk-s3/bucket_region_cache.rb +2 -0
  14. data/lib/aws-sdk-s3/bucket_request_payment.rb +7 -0
  15. data/lib/aws-sdk-s3/bucket_tagging.rb +14 -1
  16. data/lib/aws-sdk-s3/bucket_versioning.rb +17 -0
  17. data/lib/aws-sdk-s3/bucket_website.rb +18 -3
  18. data/lib/aws-sdk-s3/client.rb +2521 -1187
  19. data/lib/aws-sdk-s3/client_api.rb +188 -18
  20. data/lib/aws-sdk-s3/customizations.rb +3 -0
  21. data/lib/aws-sdk-s3/customizations/bucket.rb +11 -4
  22. data/lib/aws-sdk-s3/customizations/multipart_upload.rb +2 -0
  23. data/lib/aws-sdk-s3/customizations/object.rb +23 -5
  24. data/lib/aws-sdk-s3/customizations/object_summary.rb +5 -0
  25. data/lib/aws-sdk-s3/customizations/types/list_object_versions_output.rb +2 -0
  26. data/lib/aws-sdk-s3/encryption.rb +4 -0
  27. data/lib/aws-sdk-s3/encryption/client.rb +18 -5
  28. data/lib/aws-sdk-s3/encryption/decrypt_handler.rb +72 -26
  29. data/lib/aws-sdk-s3/encryption/default_cipher_provider.rb +43 -5
  30. data/lib/aws-sdk-s3/encryption/default_key_provider.rb +2 -0
  31. data/lib/aws-sdk-s3/encryption/encrypt_handler.rb +13 -2
  32. data/lib/aws-sdk-s3/encryption/errors.rb +2 -0
  33. data/lib/aws-sdk-s3/encryption/io_auth_decrypter.rb +2 -0
  34. data/lib/aws-sdk-s3/encryption/io_decrypter.rb +11 -3
  35. data/lib/aws-sdk-s3/encryption/io_encrypter.rb +2 -0
  36. data/lib/aws-sdk-s3/encryption/key_provider.rb +2 -0
  37. data/lib/aws-sdk-s3/encryption/kms_cipher_provider.rb +34 -3
  38. data/lib/aws-sdk-s3/encryption/materials.rb +8 -6
  39. data/lib/aws-sdk-s3/encryption/utils.rb +25 -0
  40. data/lib/aws-sdk-s3/encryptionV2/client.rb +566 -0
  41. data/lib/aws-sdk-s3/encryptionV2/decrypt_handler.rb +226 -0
  42. data/lib/aws-sdk-s3/encryptionV2/default_cipher_provider.rb +170 -0
  43. data/lib/aws-sdk-s3/encryptionV2/default_key_provider.rb +40 -0
  44. data/lib/aws-sdk-s3/encryptionV2/encrypt_handler.rb +69 -0
  45. data/lib/aws-sdk-s3/encryptionV2/errors.rb +37 -0
  46. data/lib/aws-sdk-s3/encryptionV2/io_auth_decrypter.rb +58 -0
  47. data/lib/aws-sdk-s3/encryptionV2/io_decrypter.rb +37 -0
  48. data/lib/aws-sdk-s3/encryptionV2/io_encrypter.rb +73 -0
  49. data/lib/aws-sdk-s3/encryptionV2/key_provider.rb +31 -0
  50. data/lib/aws-sdk-s3/encryptionV2/kms_cipher_provider.rb +169 -0
  51. data/lib/aws-sdk-s3/encryptionV2/materials.rb +60 -0
  52. data/lib/aws-sdk-s3/encryptionV2/utils.rb +103 -0
  53. data/lib/aws-sdk-s3/encryption_v2.rb +23 -0
  54. data/lib/aws-sdk-s3/errors.rb +2 -0
  55. data/lib/aws-sdk-s3/event_streams.rb +7 -0
  56. data/lib/aws-sdk-s3/file_downloader.rb +10 -8
  57. data/lib/aws-sdk-s3/file_part.rb +2 -0
  58. data/lib/aws-sdk-s3/file_uploader.rb +14 -1
  59. data/lib/aws-sdk-s3/legacy_signer.rb +2 -0
  60. data/lib/aws-sdk-s3/multipart_file_uploader.rb +39 -2
  61. data/lib/aws-sdk-s3/multipart_stream_uploader.rb +3 -1
  62. data/lib/aws-sdk-s3/multipart_upload.rb +18 -1
  63. data/lib/aws-sdk-s3/multipart_upload_error.rb +2 -0
  64. data/lib/aws-sdk-s3/multipart_upload_part.rb +66 -7
  65. data/lib/aws-sdk-s3/object.rb +174 -23
  66. data/lib/aws-sdk-s3/object_acl.rb +15 -0
  67. data/lib/aws-sdk-s3/object_copier.rb +2 -0
  68. data/lib/aws-sdk-s3/object_multipart_copier.rb +2 -0
  69. data/lib/aws-sdk-s3/object_summary.rb +185 -20
  70. data/lib/aws-sdk-s3/object_version.rb +44 -4
  71. data/lib/aws-sdk-s3/plugins/accelerate.rb +29 -38
  72. data/lib/aws-sdk-s3/plugins/arn.rb +187 -0
  73. data/lib/aws-sdk-s3/plugins/bucket_dns.rb +2 -2
  74. data/lib/aws-sdk-s3/plugins/bucket_name_restrictions.rb +3 -1
  75. data/lib/aws-sdk-s3/plugins/dualstack.rb +5 -1
  76. data/lib/aws-sdk-s3/plugins/expect_100_continue.rb +3 -4
  77. data/lib/aws-sdk-s3/plugins/get_bucket_location_fix.rb +2 -0
  78. data/lib/aws-sdk-s3/plugins/http_200_errors.rb +11 -3
  79. data/lib/aws-sdk-s3/plugins/iad_regional_endpoint.rb +3 -1
  80. data/lib/aws-sdk-s3/plugins/location_constraint.rb +2 -0
  81. data/lib/aws-sdk-s3/plugins/md5s.rb +26 -25
  82. data/lib/aws-sdk-s3/plugins/redirects.rb +2 -0
  83. data/lib/aws-sdk-s3/plugins/s3_host_id.rb +2 -0
  84. data/lib/aws-sdk-s3/plugins/s3_signer.rb +31 -7
  85. data/lib/aws-sdk-s3/plugins/sse_cpk.rb +3 -1
  86. data/lib/aws-sdk-s3/plugins/streaming_retry.rb +118 -0
  87. data/lib/aws-sdk-s3/plugins/url_encoded_keys.rb +2 -0
  88. data/lib/aws-sdk-s3/presigned_post.rb +68 -32
  89. data/lib/aws-sdk-s3/presigner.rb +102 -34
  90. data/lib/aws-sdk-s3/resource.rb +4 -2
  91. data/lib/aws-sdk-s3/types.rb +2016 -256
  92. data/lib/aws-sdk-s3/waiters.rb +2 -0
  93. metadata +23 -6
  94. data/lib/aws-sdk-s3/plugins/bucket_arn.rb +0 -211
@@ -0,0 +1,226 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+
5
+ module Aws
6
+ module S3
7
+ module EncryptionV2
8
+ # @api private
9
+ class DecryptHandler < Seahorse::Client::Handler
10
+ @@warned_response_target_proc = false
11
+
12
+ V1_ENVELOPE_KEYS = %w(
13
+ x-amz-key
14
+ x-amz-iv
15
+ x-amz-matdesc
16
+ )
17
+
18
+ V2_ENVELOPE_KEYS = %w(
19
+ x-amz-key-v2
20
+ x-amz-iv
21
+ x-amz-cek-alg
22
+ x-amz-wrap-alg
23
+ x-amz-matdesc
24
+ )
25
+
26
+ V2_OPTIONAL_KEYS = %w(x-amz-tag-len)
27
+
28
+ POSSIBLE_ENVELOPE_KEYS = (V1_ENVELOPE_KEYS +
29
+ V2_ENVELOPE_KEYS + V2_OPTIONAL_KEYS).uniq
30
+
31
+ POSSIBLE_WRAPPING_FORMATS = %w(
32
+ AES/GCM
33
+ kms
34
+ kms+context
35
+ RSA-OAEP-SHA1
36
+ )
37
+
38
+ POSSIBLE_ENCRYPTION_FORMATS = %w(
39
+ AES/GCM/NoPadding
40
+ AES/CBC/PKCS5Padding
41
+ AES/CBC/PKCS7Padding
42
+ )
43
+
44
+ AUTH_REQUIRED_CEK_ALGS = %w(AES/GCM/NoPadding)
45
+
46
+ def call(context)
47
+ attach_http_event_listeners(context)
48
+ apply_cse_user_agent(context)
49
+
50
+ if context[:response_target].is_a?(Proc) && !@@warned_response_target_proc
51
+ @@warned_response_target_proc = true
52
+ warn(':response_target is a Proc, or a block was provided. ' \
53
+ 'Read the entire object to the ' \
54
+ 'end before you start using the decrypted data. This is to ' \
55
+ 'verify that the object has not been modified since it ' \
56
+ 'was encrypted.')
57
+
58
+ end
59
+
60
+ @handler.call(context)
61
+ end
62
+
63
+ private
64
+
65
+ def attach_http_event_listeners(context)
66
+
67
+ context.http_response.on_headers(200) do
68
+ cipher, envelope = decryption_cipher(context)
69
+ decrypter = body_contains_auth_tag?(envelope) ?
70
+ authenticated_decrypter(context, cipher, envelope) :
71
+ IODecrypter.new(cipher, context.http_response.body)
72
+ context.http_response.body = decrypter
73
+ end
74
+
75
+ context.http_response.on_success(200) do
76
+ decrypter = context.http_response.body
77
+ decrypter.finalize
78
+ decrypter.io.rewind if decrypter.io.respond_to?(:rewind)
79
+ context.http_response.body = decrypter.io
80
+ end
81
+
82
+ context.http_response.on_error do
83
+ if context.http_response.body.respond_to?(:io)
84
+ context.http_response.body = context.http_response.body.io
85
+ end
86
+ end
87
+ end
88
+
89
+ def decryption_cipher(context)
90
+ if (envelope = get_encryption_envelope(context))
91
+ cipher = context[:encryption][:cipher_provider]
92
+ .decryption_cipher(
93
+ envelope,
94
+ context[:encryption]
95
+ )
96
+ [cipher, envelope]
97
+ else
98
+ raise Errors::DecryptionError, "unable to locate encryption envelope"
99
+ end
100
+ end
101
+
102
+ def get_encryption_envelope(context)
103
+ if context[:encryption][:envelope_location] == :metadata
104
+ envelope_from_metadata(context) || envelope_from_instr_file(context)
105
+ else
106
+ envelope_from_instr_file(context) || envelope_from_metadata(context)
107
+ end
108
+ end
109
+
110
+ def envelope_from_metadata(context)
111
+ possible_envelope = {}
112
+ POSSIBLE_ENVELOPE_KEYS.each do |suffix|
113
+ if value = context.http_response.headers["x-amz-meta-#{suffix}"]
114
+ possible_envelope[suffix] = value
115
+ end
116
+ end
117
+ extract_envelope(possible_envelope)
118
+ end
119
+
120
+ def envelope_from_instr_file(context)
121
+ suffix = context[:encryption][:instruction_file_suffix]
122
+ possible_envelope = Json.load(context.client.get_object(
123
+ bucket: context.params[:bucket],
124
+ key: context.params[:key] + suffix
125
+ ).body.read)
126
+ extract_envelope(possible_envelope)
127
+ rescue S3::Errors::ServiceError, Json::ParseError
128
+ nil
129
+ end
130
+
131
+ def extract_envelope(hash)
132
+ return nil unless hash
133
+ return v1_envelope(hash) if hash.key?('x-amz-key')
134
+ return v2_envelope(hash) if hash.key?('x-amz-key-v2')
135
+ if hash.keys.any? { |key| key.match(/^x-amz-key-(.+)$/) }
136
+ msg = "unsupported envelope encryption version #{$1}"
137
+ raise Errors::DecryptionError, msg
138
+ end
139
+ end
140
+
141
+ def v1_envelope(envelope)
142
+ envelope
143
+ end
144
+
145
+ def v2_envelope(envelope)
146
+ unless POSSIBLE_ENCRYPTION_FORMATS.include? envelope['x-amz-cek-alg']
147
+ alg = envelope['x-amz-cek-alg'].inspect
148
+ msg = "unsupported content encrypting key (cek) format: #{alg}"
149
+ raise Errors::DecryptionError, msg
150
+ end
151
+ unless POSSIBLE_WRAPPING_FORMATS.include? envelope['x-amz-wrap-alg']
152
+ alg = envelope['x-amz-wrap-alg'].inspect
153
+ msg = "unsupported key wrapping algorithm: #{alg}"
154
+ raise Errors::DecryptionError, msg
155
+ end
156
+ unless (missing_keys = V2_ENVELOPE_KEYS - envelope.keys).empty?
157
+ msg = "incomplete v2 encryption envelope:\n"
158
+ msg += " missing: #{missing_keys.join(',')}\n"
159
+ raise Errors::DecryptionError, msg
160
+ end
161
+ envelope
162
+ end
163
+
164
+ # This method fetches the tag from the end of the object by
165
+ # making a GET Object w/range request. This auth tag is used
166
+ # to initialize the cipher, and the decrypter truncates the
167
+ # auth tag from the body when writing the final bytes.
168
+ def authenticated_decrypter(context, cipher, envelope)
169
+ if RUBY_VERSION.match(/1.9/)
170
+ raise "authenticated decryption not supported by OpenSSL in Ruby version ~> 1.9"
171
+ raise Aws::Errors::NonSupportedRubyVersionError, msg
172
+ end
173
+ http_resp = context.http_response
174
+ content_length = http_resp.headers['content-length'].to_i
175
+ auth_tag_length = auth_tag_length(envelope)
176
+
177
+ auth_tag = context.client.get_object(
178
+ bucket: context.params[:bucket],
179
+ key: context.params[:key],
180
+ range: "bytes=-#{auth_tag_length}"
181
+ ).body.read
182
+
183
+ cipher.auth_tag = auth_tag
184
+ cipher.auth_data = ''
185
+
186
+ # The encrypted object contains both the cipher text
187
+ # plus a trailing auth tag.
188
+ IOAuthDecrypter.new(
189
+ io: http_resp.body,
190
+ encrypted_content_length: content_length - auth_tag_length,
191
+ cipher: cipher)
192
+ end
193
+
194
+ def body_contains_auth_tag?(envelope)
195
+ AUTH_REQUIRED_CEK_ALGS.include?(envelope['x-amz-cek-alg'])
196
+ end
197
+
198
+ # Determine the auth tag length from the algorithm
199
+ # Validate it against the value provided in the x-amz-tag-len
200
+ # Return the tag length in bytes
201
+ def auth_tag_length(envelope)
202
+ tag_length =
203
+ case envelope['x-amz-cek-alg']
204
+ when 'AES/GCM/NoPadding' then AES_GCM_TAG_LEN_BYTES
205
+ else
206
+ raise ArgumentError, 'Unsupported cek-alg: ' \
207
+ "#{envelope['x-amz-cek-alg']}"
208
+ end
209
+ if (tag_length * 8) != envelope['x-amz-tag-len'].to_i
210
+ raise Errors::DecryptionError, 'x-amz-tag-len does not match expected'
211
+ end
212
+ tag_length
213
+ end
214
+
215
+ def apply_cse_user_agent(context)
216
+ if context.config.user_agent_suffix.nil?
217
+ context.config.user_agent_suffix = EC_USER_AGENT
218
+ elsif !context.config.user_agent_suffix.include? EC_USER_AGENT
219
+ context.config.user_agent_suffix += " #{EC_USER_AGENT}"
220
+ end
221
+ end
222
+
223
+ end
224
+ end
225
+ end
226
+ end
@@ -0,0 +1,170 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+
5
+ module Aws
6
+ module S3
7
+ module EncryptionV2
8
+ # @api private
9
+ class DefaultCipherProvider
10
+
11
+ def initialize(options = {})
12
+ @key_provider = options[:key_provider]
13
+ @key_wrap_schema = validate_key_wrap(
14
+ options[:key_wrap_schema],
15
+ @key_provider.encryption_materials.key
16
+ )
17
+ @content_encryption_schema = validate_cek(
18
+ options[:content_encryption_schema]
19
+ )
20
+ end
21
+
22
+ # @return [Array<Hash,Cipher>] Creates an returns a new encryption
23
+ # envelope and encryption cipher.
24
+ def encryption_cipher(options = {})
25
+ validate_options(options)
26
+ cipher = Utils.aes_encryption_cipher(:GCM)
27
+ if @key_provider.encryption_materials.key.is_a? OpenSSL::PKey::RSA
28
+ enc_key = encode64(
29
+ encrypt_rsa(envelope_key(cipher), @content_encryption_schema)
30
+ )
31
+ else
32
+ enc_key = encode64(
33
+ encrypt_aes_gcm(envelope_key(cipher), @content_encryption_schema)
34
+ )
35
+ end
36
+ envelope = {
37
+ 'x-amz-key-v2' => enc_key,
38
+ 'x-amz-cek-alg' => @content_encryption_schema,
39
+ 'x-amz-tag-len' => (AES_GCM_TAG_LEN_BYTES * 8).to_s,
40
+ 'x-amz-wrap-alg' => @key_wrap_schema,
41
+ 'x-amz-iv' => encode64(envelope_iv(cipher)),
42
+ 'x-amz-matdesc' => materials_description
43
+ }
44
+ cipher.auth_data = '' # auth_data must be set after key and iv
45
+ [envelope, cipher]
46
+ end
47
+
48
+ # @return [Cipher] Given an encryption envelope, returns a
49
+ # decryption cipher.
50
+ def decryption_cipher(envelope, options = {})
51
+ validate_options(options)
52
+ master_key = @key_provider.key_for(envelope['x-amz-matdesc'])
53
+ if envelope.key? 'x-amz-key'
54
+ unless options[:security_profile] == :v2_and_legacy
55
+ raise Errors::LegacyDecryptionError
56
+ end
57
+ # Support for decryption of legacy objects
58
+ key = Utils.decrypt(master_key, decode64(envelope['x-amz-key']))
59
+ iv = decode64(envelope['x-amz-iv'])
60
+ Utils.aes_decryption_cipher(:CBC, key, iv)
61
+ else
62
+ if envelope['x-amz-cek-alg'] != 'AES/GCM/NoPadding'
63
+ raise ArgumentError, 'Unsupported cek-alg: ' \
64
+ "#{envelope['x-amz-cek-alg']}"
65
+ end
66
+ key =
67
+ case envelope['x-amz-wrap-alg']
68
+ when 'AES/GCM'
69
+ if master_key.is_a? OpenSSL::PKey::RSA
70
+ raise ArgumentError, 'Key mismatch - Client is configured' \
71
+ ' with an RSA key and the x-amz-wrap-alg is AES/GCM.'
72
+ end
73
+ Utils.decrypt_aes_gcm(master_key,
74
+ decode64(envelope['x-amz-key-v2']),
75
+ envelope['x-amz-cek-alg'])
76
+ when 'RSA-OAEP-SHA1'
77
+ unless master_key.is_a? OpenSSL::PKey::RSA
78
+ raise ArgumentError, 'Key mismatch - Client is configured' \
79
+ ' with an AES key and the x-amz-wrap-alg is RSA-OAEP-SHA1.'
80
+ end
81
+ key, cek_alg = Utils.decrypt_rsa(master_key, decode64(envelope['x-amz-key-v2']))
82
+ raise Errors::CEKAlgMismatchError unless cek_alg == envelope['x-amz-cek-alg']
83
+ key
84
+ when 'kms+context'
85
+ raise ArgumentError, 'Key mismatch - Client is configured' \
86
+ ' with a user provided key and the x-amz-wrap-alg is' \
87
+ ' kms+context. Please configure the client with the' \
88
+ ' required kms_key_id'
89
+ else
90
+ raise ArgumentError, 'Unsupported wrap-alg: ' \
91
+ "#{envelope['x-amz-wrap-alg']}"
92
+ end
93
+ iv = decode64(envelope['x-amz-iv'])
94
+ Utils.aes_decryption_cipher(:GCM, key, iv)
95
+ end
96
+ end
97
+
98
+ private
99
+
100
+ # Validate that the key_wrap_schema
101
+ # is valid, supported and matches the provided key.
102
+ # Returns the string version for the x-amz-key-wrap-alg
103
+ def validate_key_wrap(key_wrap_schema, key)
104
+ if key.is_a? OpenSSL::PKey::RSA
105
+ unless key_wrap_schema == :rsa_oaep_sha1
106
+ raise ArgumentError, ':key_wrap_schema must be set to :rsa_oaep_sha1 for RSA keys.'
107
+ end
108
+ else
109
+ unless key_wrap_schema == :aes_gcm
110
+ raise ArgumentError, ':key_wrap_schema must be set to :aes_gcm for AES keys.'
111
+ end
112
+ end
113
+
114
+ case key_wrap_schema
115
+ when :rsa_oaep_sha1 then 'RSA-OAEP-SHA1'
116
+ when :aes_gcm then 'AES/GCM'
117
+ when :kms_context
118
+ raise ArgumentError, 'A kms_key_id is required when using :kms_context.'
119
+ else
120
+ raise ArgumentError, "Unsupported key_wrap_schema: #{key_wrap_schema}"
121
+ end
122
+ end
123
+
124
+ def validate_cek(content_encryption_schema)
125
+ case content_encryption_schema
126
+ when :aes_gcm_no_padding
127
+ "AES/GCM/NoPadding"
128
+ else
129
+ raise ArgumentError, "Unsupported content_encryption_schema: #{content_encryption_schema}"
130
+ end
131
+ end
132
+
133
+ def envelope_key(cipher)
134
+ cipher.key = cipher.random_key
135
+ end
136
+
137
+ def envelope_iv(cipher)
138
+ cipher.iv = cipher.random_iv
139
+ end
140
+
141
+ def encrypt_aes_gcm(data, auth_data)
142
+ Utils.encrypt_aes_gcm(@key_provider.encryption_materials.key, data, auth_data)
143
+ end
144
+
145
+ def encrypt_rsa(data, auth_data)
146
+ Utils.encrypt_rsa(@key_provider.encryption_materials.key, data, auth_data)
147
+ end
148
+
149
+ def materials_description
150
+ @key_provider.encryption_materials.description
151
+ end
152
+
153
+ def encode64(str)
154
+ Base64.encode64(str).split("\n") * ''
155
+ end
156
+
157
+ def decode64(str)
158
+ Base64.decode64(str)
159
+ end
160
+
161
+ def validate_options(options)
162
+ if !options[:kms_encryption_context].nil?
163
+ raise ArgumentError, 'Cannot provide :kms_encryption_context ' \
164
+ 'with non KMS client.'
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module S3
5
+ module EncryptionV2
6
+
7
+ # The default key provider is constructed with a single key
8
+ # that is used for both encryption and decryption, ignoring
9
+ # the possible per-object envelope encryption materials description.
10
+ # @api private
11
+ class DefaultKeyProvider
12
+
13
+ include KeyProvider
14
+
15
+ # @option options [required, OpenSSL::PKey::RSA, String] :encryption_key
16
+ # The master key to use for encrypting objects.
17
+ # @option options [String<JSON>] :materials_description ('{}')
18
+ # A description of the encryption key.
19
+ def initialize(options = {})
20
+ @encryption_materials = Materials.new(
21
+ key: options[:encryption_key],
22
+ description: options[:materials_description] || '{}'
23
+ )
24
+ end
25
+
26
+ # @return [Materials]
27
+ def encryption_materials
28
+ @encryption_materials
29
+ end
30
+
31
+ # @param [String<JSON>] materials_description
32
+ # @return Returns the key given in the constructor.
33
+ def key_for(materials_description)
34
+ @encryption_materials.key
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+
5
+ module Aws
6
+ module S3
7
+ module EncryptionV2
8
+ # @api private
9
+ class EncryptHandler < Seahorse::Client::Handler
10
+
11
+ def call(context)
12
+ if RUBY_VERSION.match(/1.9/)
13
+ raise "authenticated encryption not supported by OpenSSL in Ruby version ~> 1.9"
14
+ raise Aws::Errors::NonSupportedRubyVersionError, msg
15
+ end
16
+ envelope, cipher = context[:encryption][:cipher_provider]
17
+ .encryption_cipher(
18
+ kms_encryption_context: context[:encryption][:kms_encryption_context]
19
+ )
20
+ context[:encryption][:cipher] = cipher
21
+ apply_encryption_envelope(context, envelope)
22
+ apply_encryption_cipher(context, cipher)
23
+ apply_cse_user_agent(context)
24
+ @handler.call(context)
25
+ end
26
+
27
+ private
28
+
29
+ def apply_encryption_envelope(context, envelope)
30
+ if context[:encryption][:envelope_location] == :instruction_file
31
+ suffix = context[:encryption][:instruction_file_suffix]
32
+ context.client.put_object(
33
+ bucket: context.params[:bucket],
34
+ key: context.params[:key] + suffix,
35
+ body: Json.dump(envelope)
36
+ )
37
+ else # :metadata
38
+ context.params[:metadata] ||= {}
39
+ context.params[:metadata].update(envelope)
40
+ end
41
+ end
42
+
43
+ def apply_encryption_cipher(context, cipher)
44
+ io = context.params[:body] || ''
45
+ io = StringIO.new(io) if io.is_a? String
46
+ context.params[:body] = IOEncrypter.new(cipher, io)
47
+ context.params[:metadata] ||= {}
48
+ context.params[:metadata]['x-amz-unencrypted-content-length'] = io.size
49
+ if context.params.delete(:content_md5)
50
+ raise ArgumentError, 'Setting content_md5 on client side '\
51
+ 'encrypted objects is deprecated.'
52
+ end
53
+ context.http_response.on_headers do
54
+ context.params[:body].close
55
+ end
56
+ end
57
+
58
+ def apply_cse_user_agent(context)
59
+ if context.config.user_agent_suffix.nil?
60
+ context.config.user_agent_suffix = EC_USER_AGENT
61
+ elsif !context.config.user_agent_suffix.include? EC_USER_AGENT
62
+ context.config.user_agent_suffix += " #{EC_USER_AGENT}"
63
+ end
64
+ end
65
+
66
+ end
67
+ end
68
+ end
69
+ end