aws-sdk-s3 1.68.1 → 1.72.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/lib/aws-sdk-s3.rb +3 -1
  3. data/lib/aws-sdk-s3/bucket.rb +2 -0
  4. data/lib/aws-sdk-s3/bucket_acl.rb +2 -0
  5. data/lib/aws-sdk-s3/bucket_cors.rb +2 -0
  6. data/lib/aws-sdk-s3/bucket_lifecycle.rb +2 -0
  7. data/lib/aws-sdk-s3/bucket_lifecycle_configuration.rb +2 -0
  8. data/lib/aws-sdk-s3/bucket_logging.rb +2 -0
  9. data/lib/aws-sdk-s3/bucket_notification.rb +2 -0
  10. data/lib/aws-sdk-s3/bucket_policy.rb +2 -0
  11. data/lib/aws-sdk-s3/bucket_region_cache.rb +2 -0
  12. data/lib/aws-sdk-s3/bucket_request_payment.rb +2 -0
  13. data/lib/aws-sdk-s3/bucket_tagging.rb +2 -0
  14. data/lib/aws-sdk-s3/bucket_versioning.rb +2 -0
  15. data/lib/aws-sdk-s3/bucket_website.rb +2 -0
  16. data/lib/aws-sdk-s3/client.rb +5 -1
  17. data/lib/aws-sdk-s3/client_api.rb +2 -0
  18. data/lib/aws-sdk-s3/customizations.rb +3 -0
  19. data/lib/aws-sdk-s3/customizations/bucket.rb +2 -0
  20. data/lib/aws-sdk-s3/customizations/multipart_upload.rb +2 -0
  21. data/lib/aws-sdk-s3/customizations/object.rb +2 -0
  22. data/lib/aws-sdk-s3/customizations/object_summary.rb +2 -0
  23. data/lib/aws-sdk-s3/customizations/types/list_object_versions_output.rb +2 -0
  24. data/lib/aws-sdk-s3/encryption.rb +2 -0
  25. data/lib/aws-sdk-s3/encryption/client.rb +2 -0
  26. data/lib/aws-sdk-s3/encryption/decrypt_handler.rb +11 -0
  27. data/lib/aws-sdk-s3/encryption/default_cipher_provider.rb +2 -0
  28. data/lib/aws-sdk-s3/encryption/default_key_provider.rb +2 -0
  29. data/lib/aws-sdk-s3/encryption/encrypt_handler.rb +11 -0
  30. data/lib/aws-sdk-s3/encryption/errors.rb +2 -0
  31. data/lib/aws-sdk-s3/encryption/io_auth_decrypter.rb +2 -0
  32. data/lib/aws-sdk-s3/encryption/io_decrypter.rb +8 -1
  33. data/lib/aws-sdk-s3/encryption/io_encrypter.rb +2 -0
  34. data/lib/aws-sdk-s3/encryption/key_provider.rb +2 -0
  35. data/lib/aws-sdk-s3/encryption/kms_cipher_provider.rb +2 -0
  36. data/lib/aws-sdk-s3/encryption/materials.rb +2 -0
  37. data/lib/aws-sdk-s3/encryption/utils.rb +2 -0
  38. data/lib/aws-sdk-s3/encryptionV2/client.rb +388 -0
  39. data/lib/aws-sdk-s3/encryptionV2/decrypt_handler.rb +198 -0
  40. data/lib/aws-sdk-s3/encryptionV2/default_cipher_provider.rb +103 -0
  41. data/lib/aws-sdk-s3/encryptionV2/default_key_provider.rb +38 -0
  42. data/lib/aws-sdk-s3/encryptionV2/encrypt_handler.rb +66 -0
  43. data/lib/aws-sdk-s3/encryptionV2/errors.rb +13 -0
  44. data/lib/aws-sdk-s3/encryptionV2/io_auth_decrypter.rb +56 -0
  45. data/lib/aws-sdk-s3/encryptionV2/io_decrypter.rb +35 -0
  46. data/lib/aws-sdk-s3/encryptionV2/io_encrypter.rb +71 -0
  47. data/lib/aws-sdk-s3/encryptionV2/key_provider.rb +29 -0
  48. data/lib/aws-sdk-s3/encryptionV2/kms_cipher_provider.rb +99 -0
  49. data/lib/aws-sdk-s3/encryptionV2/materials.rb +58 -0
  50. data/lib/aws-sdk-s3/encryptionV2/utils.rb +116 -0
  51. data/lib/aws-sdk-s3/encryption_v2.rb +20 -0
  52. data/lib/aws-sdk-s3/errors.rb +2 -0
  53. data/lib/aws-sdk-s3/event_streams.rb +2 -0
  54. data/lib/aws-sdk-s3/file_downloader.rb +2 -0
  55. data/lib/aws-sdk-s3/file_part.rb +2 -0
  56. data/lib/aws-sdk-s3/file_uploader.rb +2 -0
  57. data/lib/aws-sdk-s3/legacy_signer.rb +2 -0
  58. data/lib/aws-sdk-s3/multipart_file_uploader.rb +2 -0
  59. data/lib/aws-sdk-s3/multipart_stream_uploader.rb +2 -0
  60. data/lib/aws-sdk-s3/multipart_upload.rb +2 -0
  61. data/lib/aws-sdk-s3/multipart_upload_error.rb +2 -0
  62. data/lib/aws-sdk-s3/multipart_upload_part.rb +2 -0
  63. data/lib/aws-sdk-s3/object.rb +2 -0
  64. data/lib/aws-sdk-s3/object_acl.rb +2 -0
  65. data/lib/aws-sdk-s3/object_copier.rb +2 -0
  66. data/lib/aws-sdk-s3/object_multipart_copier.rb +2 -0
  67. data/lib/aws-sdk-s3/object_summary.rb +2 -0
  68. data/lib/aws-sdk-s3/object_version.rb +2 -0
  69. data/lib/aws-sdk-s3/plugins/accelerate.rb +2 -0
  70. data/lib/aws-sdk-s3/plugins/bucket_arn.rb +2 -0
  71. data/lib/aws-sdk-s3/plugins/bucket_dns.rb +2 -0
  72. data/lib/aws-sdk-s3/plugins/bucket_name_restrictions.rb +2 -0
  73. data/lib/aws-sdk-s3/plugins/dualstack.rb +2 -0
  74. data/lib/aws-sdk-s3/plugins/expect_100_continue.rb +2 -0
  75. data/lib/aws-sdk-s3/plugins/get_bucket_location_fix.rb +2 -0
  76. data/lib/aws-sdk-s3/plugins/http_200_errors.rb +4 -1
  77. data/lib/aws-sdk-s3/plugins/iad_regional_endpoint.rb +2 -0
  78. data/lib/aws-sdk-s3/plugins/location_constraint.rb +2 -0
  79. data/lib/aws-sdk-s3/plugins/md5s.rb +2 -0
  80. data/lib/aws-sdk-s3/plugins/redirects.rb +2 -0
  81. data/lib/aws-sdk-s3/plugins/s3_host_id.rb +2 -0
  82. data/lib/aws-sdk-s3/plugins/s3_signer.rb +2 -0
  83. data/lib/aws-sdk-s3/plugins/sse_cpk.rb +2 -0
  84. data/lib/aws-sdk-s3/plugins/streaming_retry.rb +118 -0
  85. data/lib/aws-sdk-s3/plugins/url_encoded_keys.rb +2 -0
  86. data/lib/aws-sdk-s3/presigned_post.rb +2 -0
  87. data/lib/aws-sdk-s3/presigner.rb +2 -0
  88. data/lib/aws-sdk-s3/resource.rb +2 -0
  89. data/lib/aws-sdk-s3/types.rb +265 -0
  90. data/lib/aws-sdk-s3/waiters.rb +2 -0
  91. metadata +19 -4
@@ -0,0 +1,35 @@
1
+ module Aws
2
+ module S3
3
+ module EncryptionV2
4
+ # @api private
5
+ class IODecrypter
6
+
7
+ # @param [OpenSSL::Cipher] cipher
8
+ # @param [IO#write] io An IO-like object that responds to `#write`.
9
+ def initialize(cipher, io)
10
+ @cipher = cipher
11
+ # Ensure that IO is reset between retries
12
+ @io = io.tap { |io| io.truncate(0) if io.respond_to?(:truncate) }
13
+ @cipher_buffer = String.new
14
+ end
15
+
16
+ # @return [#write]
17
+ attr_reader :io
18
+
19
+ def write(chunk)
20
+ # decrypt and write
21
+ if @cipher.method(:update).arity == 1
22
+ @io.write(@cipher.update(chunk))
23
+ else
24
+ @io.write(@cipher.update(chunk, @cipher_buffer))
25
+ end
26
+ end
27
+
28
+ def finalize
29
+ @io.write(@cipher.final)
30
+ end
31
+
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,71 @@
1
+ require 'stringio'
2
+ require 'tempfile'
3
+
4
+ module Aws
5
+ module S3
6
+ module EncryptionV2
7
+
8
+ # Provides an IO wrapper encrypting a stream of data.
9
+ # @api private
10
+ class IOEncrypter
11
+
12
+ # @api private
13
+ ONE_MEGABYTE = 1024 * 1024
14
+
15
+ def initialize(cipher, io)
16
+ @encrypted = io.size <= ONE_MEGABYTE ?
17
+ encrypt_to_stringio(cipher, io.read) :
18
+ encrypt_to_tempfile(cipher, io)
19
+ @size = @encrypted.size
20
+ end
21
+
22
+ # @return [Integer]
23
+ attr_reader :size
24
+
25
+ def read(bytes = nil, output_buffer = nil)
26
+ if @encrypted.is_a?(Tempfile) && @encrypted.closed?
27
+ @encrypted.open
28
+ @encrypted.binmode
29
+ end
30
+ @encrypted.read(bytes, output_buffer)
31
+ end
32
+
33
+ def rewind
34
+ @encrypted.rewind
35
+ end
36
+
37
+ # @api private
38
+ def close
39
+ @encrypted.close if @encrypted.is_a?(Tempfile)
40
+ end
41
+
42
+ private
43
+
44
+ def encrypt_to_stringio(cipher, plain_text)
45
+ if plain_text.empty?
46
+ StringIO.new(cipher.final + cipher.auth_tag)
47
+ else
48
+ StringIO.new(cipher.update(plain_text) + cipher.final + cipher.auth_tag)
49
+ end
50
+ end
51
+
52
+ def encrypt_to_tempfile(cipher, io)
53
+ encrypted = Tempfile.new(self.object_id.to_s)
54
+ encrypted.binmode
55
+ while chunk = io.read(ONE_MEGABYTE, read_buffer ||= String.new)
56
+ if cipher.method(:update).arity == 1
57
+ encrypted.write(cipher.update(chunk))
58
+ else
59
+ encrypted.write(cipher.update(chunk, cipher_buffer ||= String.new))
60
+ end
61
+ end
62
+ encrypted.write(cipher.final)
63
+ encrypted.write(cipher.auth_tag)
64
+ encrypted.rewind
65
+ encrypted
66
+ end
67
+
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,29 @@
1
+ module Aws
2
+ module S3
3
+ module EncryptionV2
4
+
5
+ # This module defines the interface required for a {Client#key_provider}.
6
+ # A key provider is any object that:
7
+ #
8
+ # * Responds to {#encryption_materials} with an {Materials} object.
9
+ #
10
+ # * Responds to {#key_for}, receiving a JSON document String,
11
+ # returning an encryption key. The returned encryption key
12
+ # must be one of:
13
+ #
14
+ # * `OpenSSL::PKey::RSA` - for asymmetric encryption
15
+ # * `String` - 32, 24, or 16 bytes long, for symmetric encryption
16
+ #
17
+ module KeyProvider
18
+
19
+ # @return [Materials]
20
+ def encryption_materials; end
21
+
22
+ # @param [String<JSON>] materials_description
23
+ # @return [OpenSSL::PKey::RSA, String] encryption_key
24
+ def key_for(materials_description); end
25
+
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,99 @@
1
+ require 'base64'
2
+
3
+ module Aws
4
+ module S3
5
+ module EncryptionV2
6
+ # @api private
7
+ class KmsCipherProvider
8
+
9
+ def initialize(options = {})
10
+ @kms_key_id = options[:kms_key_id]
11
+ @kms_client = options[:kms_client]
12
+ end
13
+
14
+ # @return [Array<Hash,Cipher>] Creates and returns a new encryption
15
+ # envelope and encryption cipher.
16
+ def encryption_cipher(options = {})
17
+ cek_alg = 'AES/GCM/NoPadding'
18
+ encryption_context = build_encryption_context(cek_alg, options)
19
+ key_data = @kms_client.generate_data_key(
20
+ key_id: @kms_key_id,
21
+ encryption_context: encryption_context,
22
+ key_spec: 'AES_256'
23
+ )
24
+ cipher = Utils.aes_encryption_cipher(:GCM)
25
+ cipher.key = key_data.plaintext
26
+ envelope = {
27
+ 'x-amz-key-v2' => encode64(key_data.ciphertext_blob),
28
+ 'x-amz-iv' => encode64(cipher.iv = cipher.random_iv),
29
+ 'x-amz-cek-alg' => cek_alg,
30
+ 'x-amz-tag-len' => 16 * 8,
31
+ 'x-amz-wrap-alg' => 'kms+context',
32
+ 'x-amz-matdesc' => Json.dump(encryption_context)
33
+ }
34
+ cipher.auth_data = '' # auth_data must be set after key and iv
35
+ [envelope, cipher]
36
+ end
37
+
38
+ # @return [Cipher] Given an encryption envelope, returns a
39
+ # decryption cipher.
40
+ def decryption_cipher(envelope, options={})
41
+ encryption_context = Json.load(envelope['x-amz-matdesc'])
42
+ cek_alg = envelope['x-amz-wrap-alg'] == 'kms+context' ?
43
+ encryption_context['aws:x-amz-cek-alg'] : envelope['x-amz-cek-alg']
44
+ if cek_alg != envelope['x-amz-cek-alg']
45
+ raise Errors::DecryptionError, 'Value of cek-alg from envelope'\
46
+ ' does not match the value in the encryption context'
47
+ end
48
+
49
+ if envelope['x-amz-wrap-alg'] == 'kms+context' &&
50
+ encryption_context != build_encryption_context(cek_alg, options)
51
+ raise Errors::DecryptionError, 'Value of encryption context from'\
52
+ ' envelope does not match the provided encryption context'
53
+ end
54
+
55
+ key = @kms_client.decrypt(
56
+ ciphertext_blob: decode64(envelope['x-amz-key-v2']),
57
+ encryption_context: encryption_context
58
+ ).plaintext
59
+
60
+
61
+ iv = decode64(envelope['x-amz-iv'])
62
+ block_mode =
63
+ case cek_alg
64
+ when 'AES/CBC/PKCS5Padding'
65
+ :CBC
66
+ when 'AES/CBC/PKCS7Padding'
67
+ :CBC
68
+ when 'AES/GCM/NoPadding'
69
+ :GCM
70
+ else
71
+ type = envelope['x-amz-cek-alg'].inspect
72
+ msg = "unsupported content encrypting key (cek) format: #{type}"
73
+ raise Errors::DecryptionError, msg
74
+ end
75
+ Utils.aes_decryption_cipher(block_mode, key, iv)
76
+ end
77
+
78
+ private
79
+
80
+ def build_encryption_context(cek_alg, options = {})
81
+ kms_context = (options[:kms_encryption_context] || {})
82
+ .each_with_object({}) { |(k, v), h| h[k.to_s] = v }
83
+ {
84
+ 'aws:x-amz-cek-alg' => cek_alg
85
+ }.merge(kms_context)
86
+ end
87
+
88
+ def encode64(str)
89
+ Base64.encode64(str).split("\n") * ""
90
+ end
91
+
92
+ def decode64(str)
93
+ Base64.decode64(str)
94
+ end
95
+
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,58 @@
1
+ require 'base64'
2
+
3
+ module Aws
4
+ module S3
5
+ module EncryptionV2
6
+ class Materials
7
+
8
+ # @option options [required, OpenSSL::PKey::RSA, String] :key
9
+ # The master key to use for encrypting/decrypting all objects.
10
+ #
11
+ # @option options [String<JSON>] :description ('{}')
12
+ # The encryption materials description. This is must be
13
+ # a JSON document string.
14
+ #
15
+ def initialize(options = {})
16
+ @key = validate_key(options[:key])
17
+ @description = validate_desc(options[:description])
18
+ end
19
+
20
+ # @return [OpenSSL::PKey::RSA, String]
21
+ attr_reader :key
22
+
23
+ # @return [String<JSON>]
24
+ attr_reader :description
25
+
26
+ private
27
+
28
+ def validate_key(key)
29
+ case key
30
+ when OpenSSL::PKey::RSA then key
31
+ when String
32
+ if [32, 24, 16].include?(key.bytesize)
33
+ key
34
+ else
35
+ msg = 'invalid key, symmetric key required to be 16, 24, or '\
36
+ '32 bytes in length, saw length ' + key.bytesize.to_s
37
+ raise ArgumentError, msg
38
+ end
39
+ else
40
+ msg = 'invalid encryption key, expected an OpenSSL::PKey::RSA key '\
41
+ '(for asymmetric encryption) or a String (for symmetric '\
42
+ 'encryption).'
43
+ raise ArgumentError, msg
44
+ end
45
+ end
46
+
47
+ def validate_desc(description)
48
+ Json.load(description)
49
+ description
50
+ rescue Json::ParseError, EncodingError
51
+ msg = 'expected description to be a valid JSON document string'
52
+ raise ArgumentError, msg
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,116 @@
1
+ require 'openssl'
2
+
3
+ module Aws
4
+ module S3
5
+ module EncryptionV2
6
+ # @api private
7
+ module Utils
8
+
9
+ UNSAFE_MSG = "unsafe encryption, data is longer than key length"
10
+
11
+ class << self
12
+
13
+ def encrypt(key, data)
14
+ case key
15
+ when OpenSSL::PKey::RSA # asymmetric encryption
16
+ warn(UNSAFE_MSG) if key.public_key.n.num_bits < cipher_size(data)
17
+ key.public_encrypt(data)
18
+ when String # symmetric encryption
19
+ warn(UNSAFE_MSG) if cipher_size(key) < cipher_size(data)
20
+ cipher = aes_encryption_cipher(:ECB, key)
21
+ cipher.update(data) + cipher.final
22
+ end
23
+ end
24
+
25
+ def encrypt_aes_gcm(key, data, auth_data)
26
+ warn(UNSAFE_MSG) if cipher_size(key) < cipher_size(data)
27
+ cipher = aes_encryption_cipher(:GCM, key)
28
+ cipher.iv = (iv = cipher.random_iv)
29
+ cipher.auth_data = auth_data
30
+
31
+ iv + cipher.update(data) + cipher.final + cipher.auth_tag
32
+ end
33
+
34
+ def encrypt_rsa(key, data, auth_data)
35
+ # Plaintext must be KeyLengthInBytes (1 Byte) + DataKey + AuthData
36
+ buf = [data.bytesize] + data.unpack('C*') + auth_data.unpack('C*')
37
+ key.public_encrypt(buf.pack('C*'), OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
38
+ end
39
+
40
+ def decrypt(key, data)
41
+ begin
42
+ case key
43
+ when OpenSSL::PKey::RSA # asymmetric decryption
44
+ key.private_decrypt(data)
45
+ when String # symmetric Decryption
46
+ cipher = aes_cipher(:decrypt, :ECB, key, nil)
47
+ cipher.update(data) + cipher.final
48
+ end
49
+ rescue OpenSSL::Cipher::CipherError
50
+ msg = 'decryption failed, possible incorrect key'
51
+ raise Errors::DecryptionError, msg
52
+ end
53
+ end
54
+
55
+ def decrypt_aes_gcm(key, data, auth_data)
56
+ # data is iv (12B) + key + tag (16B)
57
+ buf = data.unpack('C*')
58
+ iv = buf[0,12].pack('C*') # iv will always be 12 bytes
59
+ tag = buf[-16, 16].pack('C*') # tag is 16 bytes
60
+ enc_key = buf[12, buf.size - (12+16)].pack('C*')
61
+ cipher = aes_cipher(:decrypt, :GCM, key, iv)
62
+ cipher.auth_tag = tag
63
+ cipher.auth_data = auth_data
64
+ cipher.update(enc_key) + cipher.final
65
+ end
66
+
67
+ # returns the decrypted data + auth_data
68
+ def decrypt_rsa(key, enc_data)
69
+ # Plaintext must be KeyLengthInBytes (1 Byte) + DataKey + AuthData
70
+ buf = key.private_decrypt(enc_data, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING).unpack('C*')
71
+ key_length = buf[0]
72
+ data = buf[1, key_length].pack('C*')
73
+ auth_data = buf[key_length+1, buf.length - key_length].pack('C*')
74
+ [data, auth_data]
75
+ end
76
+
77
+ # @param [String] block_mode "CBC" or "ECB"
78
+ # @param [OpenSSL::PKey::RSA, String, nil] key
79
+ # @param [String, nil] iv The initialization vector
80
+ def aes_encryption_cipher(block_mode, key = nil, iv = nil)
81
+ aes_cipher(:encrypt, block_mode, key, iv)
82
+ end
83
+
84
+ # @param [String] block_mode "CBC" or "ECB"
85
+ # @param [OpenSSL::PKey::RSA, String, nil] key
86
+ # @param [String, nil] iv The initialization vector
87
+ def aes_decryption_cipher(block_mode, key = nil, iv = nil)
88
+ aes_cipher(:decrypt, block_mode, key, iv)
89
+ end
90
+
91
+ # @param [String] mode "encrypt" or "decrypt"
92
+ # @param [String] block_mode "CBC" or "ECB"
93
+ # @param [OpenSSL::PKey::RSA, String, nil] key
94
+ # @param [String, nil] iv The initialization vector
95
+ def aes_cipher(mode, block_mode, key, iv)
96
+ cipher = key ?
97
+ OpenSSL::Cipher.new("aes-#{cipher_size(key)}-#{block_mode.downcase}") :
98
+ OpenSSL::Cipher.new("aes-256-#{block_mode.downcase}")
99
+ cipher.send(mode) # encrypt or decrypt
100
+ cipher.key = key if key
101
+ cipher.iv = iv if iv
102
+ cipher
103
+ end
104
+
105
+ # @param [String] key
106
+ # @return [Integer]
107
+ # @raise ArgumentError
108
+ def cipher_size(key)
109
+ key.bytesize * 8
110
+ end
111
+
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,20 @@
1
+ require 'aws-sdk-s3/encryptionV2/client'
2
+ require 'aws-sdk-s3/encryptionV2/decrypt_handler'
3
+ require 'aws-sdk-s3/encryptionV2/default_cipher_provider'
4
+ require 'aws-sdk-s3/encryptionV2/encrypt_handler'
5
+ require 'aws-sdk-s3/encryptionV2/errors'
6
+ require 'aws-sdk-s3/encryptionV2/io_encrypter'
7
+ require 'aws-sdk-s3/encryptionV2/io_decrypter'
8
+ require 'aws-sdk-s3/encryptionV2/io_auth_decrypter'
9
+ require 'aws-sdk-s3/encryptionV2/key_provider'
10
+ require 'aws-sdk-s3/encryptionV2/kms_cipher_provider'
11
+ require 'aws-sdk-s3/encryptionV2/materials'
12
+ require 'aws-sdk-s3/encryptionV2/utils'
13
+ require 'aws-sdk-s3/encryptionV2/default_key_provider'
14
+
15
+ module Aws
16
+ module S3
17
+ module EncryptionV2; end
18
+ end
19
+ end
20
+
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # WARNING ABOUT GENERATED CODE
2
4
  #
3
5
  # This file is generated. See the contributing guide for more information:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # WARNING ABOUT GENERATED CODE
2
4
  #
3
5
  # This file is generated. See the contributing guide for more information: