symmetric-encryption 4.3.0 → 4.4.0

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -7
  3. data/Rakefile +9 -9
  4. data/bin/symmetric-encryption +1 -1
  5. data/lib/symmetric-encryption.rb +1 -1
  6. data/lib/symmetric_encryption/cipher.rb +17 -11
  7. data/lib/symmetric_encryption/cli.rb +72 -54
  8. data/lib/symmetric_encryption/coerce.rb +3 -3
  9. data/lib/symmetric_encryption/config.rb +28 -27
  10. data/lib/symmetric_encryption/core.rb +23 -22
  11. data/lib/symmetric_encryption/encoder.rb +26 -8
  12. data/lib/symmetric_encryption/generator.rb +7 -3
  13. data/lib/symmetric_encryption/header.rb +24 -24
  14. data/lib/symmetric_encryption/key.rb +1 -1
  15. data/lib/symmetric_encryption/keystore/aws.rb +10 -13
  16. data/lib/symmetric_encryption/keystore/environment.rb +5 -5
  17. data/lib/symmetric_encryption/keystore/file.rb +27 -9
  18. data/lib/symmetric_encryption/keystore/gcp.rb +21 -18
  19. data/lib/symmetric_encryption/keystore/heroku.rb +1 -1
  20. data/lib/symmetric_encryption/keystore/memory.rb +3 -3
  21. data/lib/symmetric_encryption/keystore.rb +23 -23
  22. data/lib/symmetric_encryption/railtie.rb +9 -8
  23. data/lib/symmetric_encryption/railties/mongoid_encrypted.rb +5 -4
  24. data/lib/symmetric_encryption/railties/symmetric_encryption_validator.rb +1 -1
  25. data/lib/symmetric_encryption/reader.rb +13 -13
  26. data/lib/symmetric_encryption/rsa_key.rb +1 -1
  27. data/lib/symmetric_encryption/symmetric_encryption.rb +24 -18
  28. data/lib/symmetric_encryption/utils/aws.rb +8 -10
  29. data/lib/symmetric_encryption/utils/files.rb +3 -3
  30. data/lib/symmetric_encryption/utils/re_encrypt_files.rb +11 -11
  31. data/lib/symmetric_encryption/version.rb +1 -1
  32. data/lib/symmetric_encryption/writer.rb +20 -13
  33. data/lib/symmetric_encryption.rb +9 -9
  34. metadata +8 -9
@@ -15,7 +15,7 @@ module SymmetricEncryption
15
15
  puts "\n\n********************************************************************************"
16
16
  puts "Add the environment key to Heroku:\n\n"
17
17
  puts " heroku config:add #{key_env_var}=#{encoder.encode(encrypted_key)}"
18
- puts '********************************************************************************'
18
+ puts "********************************************************************************"
19
19
  end
20
20
  end
21
21
  end
@@ -12,10 +12,10 @@ module SymmetricEncryption
12
12
  # Notes:
13
13
  # * For development and testing purposes only!!
14
14
  # * Never store the encrypted encryption key in the source code / config file.
15
- def self.generate_data_key(cipher_name:, app_name:, environment:, version: 0, dek: nil, **args)
15
+ def self.generate_data_key(cipher_name:, app_name:, environment:, version: 0, dek: nil, **_args)
16
16
  version >= 255 ? (version = 1) : (version += 1)
17
17
 
18
- kek = SymmetricEncryption::Key.new(cipher_name: cipher_name)
18
+ kek = SymmetricEncryption::Key.new(cipher_name: cipher_name)
19
19
  dek ||= SymmetricEncryption::Key.new(cipher_name: cipher_name)
20
20
 
21
21
  encrypted_key = new(key_encrypting_key: kek).write(dek.key)
@@ -35,7 +35,7 @@ module SymmetricEncryption
35
35
 
36
36
  # Stores the Encryption key in a string.
37
37
  # Secures the Encryption key by encrypting it with a key encryption key.
38
- def initialize(encrypted_key: nil, key_encrypting_key:)
38
+ def initialize(key_encrypting_key:, encrypted_key: nil)
39
39
  @encrypted_key = encrypted_key
40
40
  @key_encrypting_key = key_encrypting_key
41
41
  end
@@ -2,12 +2,12 @@ module SymmetricEncryption
2
2
  # Encryption keys are secured in Keystores
3
3
  module Keystore
4
4
  # @formatter:off
5
- autoload :Aws, 'symmetric_encryption/keystore/aws'
6
- autoload :Environment, 'symmetric_encryption/keystore/environment'
7
- autoload :Gcp, 'symmetric_encryption/keystore/gcp'
8
- autoload :File, 'symmetric_encryption/keystore/file'
9
- autoload :Heroku, 'symmetric_encryption/keystore/heroku'
10
- autoload :Memory, 'symmetric_encryption/keystore/memory'
5
+ autoload :Aws, "symmetric_encryption/keystore/aws"
6
+ autoload :Environment, "symmetric_encryption/keystore/environment"
7
+ autoload :Gcp, "symmetric_encryption/keystore/gcp"
8
+ autoload :File, "symmetric_encryption/keystore/file"
9
+ autoload :Heroku, "symmetric_encryption/keystore/heroku"
10
+ autoload :Memory, "symmetric_encryption/keystore/memory"
11
11
  # @formatter:on
12
12
 
13
13
  # Returns [Hash] a new keystore configuration after generating data keys for each environment.
@@ -56,7 +56,7 @@ module SymmetricEncryption
56
56
  # Notes:
57
57
  # * iv_filename is no longer supported and is removed when creating a new random cipher.
58
58
  # * `iv` does not need to be encrypted and is included in the clear.
59
- def self.rotate_keys!(full_config, environments: [], app_name:, rolling_deploy: false, keystore: nil)
59
+ def self.rotate_keys!(full_config, app_name:, environments: [], rolling_deploy: false, keystore: nil)
60
60
  full_config.each_pair do |environment, cfg|
61
61
  # Only rotate keys for specified environments. Default, all
62
62
  next if !environments.empty? && !environments.include?(environment.to_sym)
@@ -69,7 +69,7 @@ module SymmetricEncryption
69
69
  # Only generate new keys for keystore's that have a key encrypting key
70
70
  next unless config[:key_encrypting_key] || config[:private_rsa_key]
71
71
 
72
- cipher_name = config[:cipher_name] || 'aes-256-cbc'
72
+ cipher_name = config[:cipher_name] || "aes-256-cbc"
73
73
 
74
74
  keystore_class = keystore ? constantize_symbol(keystore) : keystore_for(config)
75
75
 
@@ -80,7 +80,7 @@ module SymmetricEncryption
80
80
  environment: environment
81
81
  }
82
82
  args[:key_path] = ::File.dirname(config[:key_filename]) if config.key?(:key_filename)
83
- new_data_key = keystore_class.generate_data_key(args)
83
+ new_data_key = keystore_class.generate_data_key(**args)
84
84
 
85
85
  # Add as second key so that key can be published now and only used in a later deploy.
86
86
  if rolling_deploy
@@ -95,7 +95,7 @@ module SymmetricEncryption
95
95
  # Rotates just the key encrypting keys for the current cipher version.
96
96
  # The existing data encryption key is not changed, it is secured using the
97
97
  # new key encrypting keys.
98
- def self.rotate_key_encrypting_keys!(full_config, environments: [], app_name:)
98
+ def self.rotate_key_encrypting_keys!(full_config, app_name:, environments: [])
99
99
  full_config.each_pair do |environment, cfg|
100
100
  # Only rotate keys for specified environments. Default, all
101
101
  next if !environments.empty? && !environments.include?(environment.to_sym)
@@ -105,7 +105,7 @@ module SymmetricEncryption
105
105
  # Only generate new keys for keystore's that have a key encrypting key
106
106
  next unless config[:key_encrypting_key]
107
107
 
108
- version = config.delete(:version) || 1
108
+ version = config.delete(:version) || 1
109
109
  version -= 1
110
110
 
111
111
  always_add_header = config.delete(:always_add_header)
@@ -144,9 +144,9 @@ module SymmetricEncryption
144
144
  ciphers:
145
145
  [
146
146
  {
147
- key: '1234567890ABCDEF',
148
- iv: '1234567890ABCDEF',
149
- cipher_name: 'aes-128-cbc',
147
+ key: "1234567890ABCDEF",
148
+ iv: "1234567890ABCDEF",
149
+ cipher_name: "aes-128-cbc",
150
150
  version: 1
151
151
  }
152
152
  ]
@@ -156,7 +156,7 @@ module SymmetricEncryption
156
156
  # Returns [Key] by recursively navigating the config tree.
157
157
  #
158
158
  # Supports N level deep key encrypting keys.
159
- def self.read_key(key: nil, iv:, key_encrypting_key: nil, cipher_name: 'aes-256-cbc', keystore: nil, version: 0, **args)
159
+ def self.read_key(iv:, key: nil, key_encrypting_key: nil, cipher_name: "aes-256-cbc", keystore: nil, version: 0, **args)
160
160
  if key_encrypting_key.is_a?(Hash)
161
161
  # Recurse up the chain returning the parent key_encrypting_key
162
162
  key_encrypting_key = read_key(cipher_name: cipher_name, **key_encrypting_key)
@@ -185,11 +185,11 @@ module SymmetricEncryption
185
185
  elsif config[:key_env_var]
186
186
  Keystore::Environment
187
187
  else
188
- raise(ArgumentError, 'Unknown keystore supplied in config')
188
+ raise(ArgumentError, "Unknown keystore supplied in config")
189
189
  end
190
190
  end
191
191
 
192
- def self.constantize_symbol(symbol, namespace = 'SymmetricEncryption::Keystore')
192
+ def self.constantize_symbol(symbol, namespace = "SymmetricEncryption::Keystore")
193
193
  klass = "#{namespace}::#{camelize(symbol.to_s)}"
194
194
  begin
195
195
  Object.const_get(klass)
@@ -202,8 +202,8 @@ module SymmetricEncryption
202
202
  def self.camelize(term)
203
203
  string = term.to_s
204
204
  string = string.sub(/^[a-z\d]*/, &:capitalize)
205
- string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{Regexp.last_match(1)}#{Regexp.last_match(2).capitalize}" }
206
- string.gsub!('/'.freeze, '::'.freeze)
205
+ string.gsub!(%r{(?:_|(/))([a-z\d]*)}i) { "#{Regexp.last_match(1)}#{Regexp.last_match(2).capitalize}" }
206
+ string.gsub!("/".freeze, "::".freeze)
207
207
  string
208
208
  end
209
209
 
@@ -220,12 +220,12 @@ module SymmetricEncryption
220
220
 
221
221
  # Migrate old encrypted_iv
222
222
  if (encrypted_iv = config.delete(:encrypted_iv)) && private_rsa_key
223
- encrypted_iv = RSAKey.new(private_rsa_key).decrypt(encrypted_iv)
224
- config[:iv] = ::Base64.decode64(encrypted_iv)
223
+ encrypted_iv = RSAKey.new(private_rsa_key).decrypt(encrypted_iv)
224
+ config[:iv] = ::Base64.decode64(encrypted_iv)
225
225
  end
226
226
 
227
227
  # Migrate old iv_filename
228
- if (file_name = config.delete(:iv_filename)) && private_rsa_key
228
+ if (file_name = config.delete(:iv_filename)) && private_rsa_key
229
229
  encrypted_iv = ::File.read(file_name)
230
230
  config[:iv] = RSAKey.new(private_rsa_key).decrypt(encrypted_iv)
231
231
  end
@@ -234,7 +234,7 @@ module SymmetricEncryption
234
234
  config[:key_encrypting_key] = RSAKey.new(private_rsa_key) if private_rsa_key
235
235
 
236
236
  # Migrate old encrypted_key to new binary format
237
- if (encrypted_key = config[:encrypted_key]) && private_rsa_key
237
+ if (encrypted_key = config[:encrypted_key]) && private_rsa_key
238
238
  config[:encrypted_key] = ::Base64.decode64(encrypted_key)
239
239
  end
240
240
  end
@@ -29,23 +29,24 @@ module SymmetricEncryption #:nodoc:
29
29
  config.before_configuration do
30
30
  # Check if already configured
31
31
  unless ::SymmetricEncryption.cipher?
32
- app_name = Rails::Application.subclasses.first.parent.to_s.underscore
33
- env_var = ENV['SYMMETRIC_ENCRYPTION_CONFIG']
34
- config_file =
32
+ parent_method = Module.method_defined?(:module_parent) ? "module_parent" : "parent"
33
+ app_name = Rails::Application.subclasses.first.send(parent_method).to_s.underscore
34
+ env_var = ENV["SYMMETRIC_ENCRYPTION_CONFIG"]
35
+ config_file =
35
36
  if env_var
36
37
  Pathname.new(File.expand_path(env_var))
37
38
  else
38
- Rails.root.join('config', 'symmetric-encryption.yml')
39
+ Rails.root.join("config", "symmetric-encryption.yml")
39
40
  end
40
41
 
41
42
  if config_file.file?
42
43
  begin
43
- ::SymmetricEncryption::Config.load!(file_name: config_file, env: ENV['SYMMETRIC_ENCRYPTION_ENV'] || Rails.env)
44
- rescue ArgumentError => exc
44
+ ::SymmetricEncryption::Config.load!(file_name: config_file, env: ENV["SYMMETRIC_ENCRYPTION_ENV"] || Rails.env)
45
+ rescue ArgumentError => e
45
46
  puts "\nSymmetric Encryption not able to read keys."
46
- puts "#{exc.class.name} #{exc.message}"
47
+ puts "#{e.class.name} #{e.message}"
47
48
  puts "To generate a new config file and key files: symmetric-encryption --generate --app-name #{app_name}\n\n"
48
- raise(exc)
49
+ raise(e)
49
50
  end
50
51
  end
51
52
 
@@ -1,4 +1,4 @@
1
- require 'mongoid'
1
+ require "mongoid"
2
2
  # Add :encrypted option for Mongoid models
3
3
  #
4
4
  # Example:
@@ -95,12 +95,13 @@ Mongoid::Fields.option :encrypted do |model, field, options|
95
95
 
96
96
  # Support overriding the name of the decrypted attribute
97
97
  decrypted_field_name = options.delete(:decrypt_as)
98
- if decrypted_field_name.nil? && encrypted_field_name.to_s.start_with?('encrypted_')
99
- decrypted_field_name = encrypted_field_name.to_s['encrypted_'.length..-1]
98
+ if decrypted_field_name.nil? && encrypted_field_name.to_s.start_with?("encrypted_")
99
+ decrypted_field_name = encrypted_field_name.to_s["encrypted_".length..-1]
100
100
  end
101
101
 
102
102
  if decrypted_field_name.nil?
103
- raise(ArgumentError, "SymmetricEncryption for Mongoid. Encryption enabled for field #{encrypted_field_name}. It must either start with 'encrypted_' or the option :decrypt_as must be supplied")
103
+ raise(ArgumentError,
104
+ "SymmetricEncryption for Mongoid. Encryption enabled for field #{encrypted_field_name}. It must either start with 'encrypted_' or the option :decrypt_as must be supplied")
104
105
  end
105
106
 
106
107
  SymmetricEncryption::Generator.generate_decrypted_accessors(model, decrypted_field_name, encrypted_field_name, options)
@@ -15,6 +15,6 @@ class SymmetricEncryptionValidator < ActiveModel::EachValidator
15
15
  def validate_each(record, attribute, value)
16
16
  return if value.blank? || SymmetricEncryption.encrypted?(value)
17
17
 
18
- record.errors.add(attribute, 'must be a value encrypted using SymmetricEncryption.encrypt')
18
+ record.errors.add(attribute, "must be a value encrypted using SymmetricEncryption.encrypt")
19
19
  end
20
20
  end
@@ -1,4 +1,4 @@
1
- require 'openssl'
1
+ require "openssl"
2
2
 
3
3
  module SymmetricEncryption
4
4
  # Read from encrypted files and other IO streams
@@ -60,7 +60,7 @@ module SymmetricEncryption
60
60
  # csv.close if csv
61
61
  # end
62
62
  def self.open(file_name_or_stream, buffer_size: 16_384, **args, &block)
63
- ios = file_name_or_stream.is_a?(String) ? ::File.open(file_name_or_stream, 'rb') : file_name_or_stream
63
+ ios = file_name_or_stream.is_a?(String) ? ::File.open(file_name_or_stream, "rb") : file_name_or_stream
64
64
 
65
65
  begin
66
66
  file = new(ios, buffer_size: buffer_size, **args)
@@ -104,7 +104,7 @@ module SymmetricEncryption
104
104
 
105
105
  # Returns [true|false] whether the file contains the encryption header
106
106
  def self.header_present?(file_name)
107
- ::File.open(file_name, 'rb') { |file| new(file).header_present? }
107
+ ::File.open(file_name, "rb") { |file| new(file).header_present? }
108
108
  end
109
109
 
110
110
  # After opening a file Returns [true|false] whether the file being
@@ -120,9 +120,9 @@ module SymmetricEncryption
120
120
  @version = version
121
121
  @header_present = false
122
122
  @closed = false
123
- @read_buffer = ''.b
123
+ @read_buffer = "".b
124
124
 
125
- raise(ArgumentError, 'Buffer size cannot be smaller than 128') unless @buffer_size >= 128
125
+ raise(ArgumentError, "Buffer size cannot be smaller than 128") unless @buffer_size >= 128
126
126
 
127
127
  read_header
128
128
  end
@@ -185,10 +185,10 @@ module SymmetricEncryption
185
185
  # At end of file, it returns nil if no more data is available, or the last
186
186
  # remaining bytes
187
187
  def read(length = nil, outbuf = nil)
188
- data = outbuf.to_s.clear
188
+ data = outbuf.nil? ? "" : outbuf.clear
189
189
  remaining_length = length
190
190
 
191
- until remaining_length == 0 || eof?
191
+ until remaining_length&.zero? || eof?
192
192
  read_block(remaining_length) if @read_buffer.empty?
193
193
 
194
194
  if remaining_length && remaining_length < @read_buffer.length
@@ -209,7 +209,7 @@ module SymmetricEncryption
209
209
  # Raises EOFError on eof
210
210
  # The stream must be opened for reading or an IOError will be raised.
211
211
  def readline(sep_string = "\n")
212
- gets(sep_string) || raise(EOFError, 'End of file reached when trying to read a line')
212
+ gets(sep_string) || raise(EOFError, "End of file reached when trying to read a line")
213
213
  end
214
214
 
215
215
  # Reads a single decrypted line from the file up to and including the optional sep_string.
@@ -226,8 +226,8 @@ module SymmetricEncryption
226
226
  read_block
227
227
  end
228
228
  index ||= -1
229
- data = @read_buffer.slice!(0..index)
230
- @pos += data.length
229
+ data = @read_buffer.slice!(0..index)
230
+ @pos += data.length
231
231
  return nil if data.empty? && eof?
232
232
 
233
233
  data
@@ -310,7 +310,7 @@ module SymmetricEncryption
310
310
  @pos = 0
311
311
 
312
312
  # Read first block and check for the header
313
- buf = @ios.read(@buffer_size, @output_buffer ||= ''.b)
313
+ buf = @ios.read(@buffer_size, @output_buffer ||= "".b)
314
314
 
315
315
  # Use cipher specified in header, or global cipher if it has no header
316
316
  iv, key, cipher_name, cipher = nil
@@ -340,7 +340,7 @@ module SymmetricEncryption
340
340
 
341
341
  # Read a block of data and append the decrypted data in the read buffer
342
342
  def read_block(length = nil)
343
- buf = @ios.read(length || @buffer_size, @output_buffer ||= ''.b)
343
+ buf = @ios.read(length || @buffer_size, @output_buffer ||= "".b)
344
344
  decrypt(buf)
345
345
  end
346
346
 
@@ -356,7 +356,7 @@ module SymmetricEncryption
356
356
  def decrypt(buf)
357
357
  return if buf.nil? || buf.empty?
358
358
 
359
- @read_buffer << @stream_cipher.update(buf, @cipher_buffer ||= ''.b)
359
+ @read_buffer << @stream_cipher.update(buf, @cipher_buffer ||= "".b)
360
360
  @read_buffer << @stream_cipher.final if @ios.eof?
361
361
  end
362
362
  end
@@ -1,4 +1,4 @@
1
- require 'openssl'
1
+ require "openssl"
2
2
  module SymmetricEncryption
3
3
  # DEPRECATED - Internal use only
4
4
  class RSAKey
@@ -1,8 +1,8 @@
1
- require 'base64'
2
- require 'openssl'
3
- require 'zlib'
4
- require 'yaml'
5
- require 'erb'
1
+ require "base64"
2
+ require "openssl"
3
+ require "zlib"
4
+ require "yaml"
5
+ require "erb"
6
6
 
7
7
  # Encrypt using 256 Bit AES CBC symmetric key and initialization vector
8
8
  # The symmetric key is protected using the private key below and must
@@ -32,7 +32,9 @@ module SymmetricEncryption
32
32
  # cipher: 'aes-128-cbc'
33
33
  # )
34
34
  def self.cipher=(cipher)
35
- raise(ArgumentError, 'Cipher must respond to :encrypt and :decrypt') unless cipher.nil? || (cipher.respond_to?(:encrypt) && cipher.respond_to?(:decrypt))
35
+ unless cipher.nil? || (cipher.respond_to?(:encrypt) && cipher.respond_to?(:decrypt))
36
+ raise(ArgumentError, "Cipher must respond to :encrypt and :decrypt")
37
+ end
36
38
 
37
39
  @cipher = cipher
38
40
  end
@@ -45,7 +47,7 @@ module SymmetricEncryption
45
47
  unless cipher?
46
48
  raise(
47
49
  SymmetricEncryption::ConfigError,
48
- 'Call SymmetricEncryption.load! or SymmetricEncryption.cipher= prior to encrypting or decrypting data'
50
+ "Call SymmetricEncryption.load! or SymmetricEncryption.cipher= prior to encrypting or decrypting data"
49
51
  )
50
52
  end
51
53
 
@@ -61,10 +63,12 @@ module SymmetricEncryption
61
63
 
62
64
  # Set the Secondary Symmetric Ciphers Array to be used
63
65
  def self.secondary_ciphers=(secondary_ciphers)
64
- raise(ArgumentError, 'secondary_ciphers must be a collection') unless secondary_ciphers.respond_to? :each
66
+ raise(ArgumentError, "secondary_ciphers must be a collection") unless secondary_ciphers.respond_to? :each
65
67
 
66
68
  secondary_ciphers.each do |cipher|
67
- raise(ArgumentError, 'secondary_ciphers can only consist of SymmetricEncryption::Ciphers') unless cipher.respond_to?(:encrypt) && cipher.respond_to?(:decrypt)
69
+ unless cipher.respond_to?(:encrypt) && cipher.respond_to?(:decrypt)
70
+ raise(ArgumentError, "secondary_ciphers can only consist of SymmetricEncryption::Ciphers")
71
+ end
68
72
  end
69
73
  @secondary_ciphers = secondary_ciphers
70
74
  end
@@ -121,7 +125,7 @@ module SymmetricEncryption
121
125
  # the incorrect key. Clearly the data returned is garbage, but it still
122
126
  # successfully returns a string of data
123
127
  def self.decrypt(encrypted_and_encoded_string, version: nil, type: :string)
124
- return encrypted_and_encoded_string if encrypted_and_encoded_string.nil? || (encrypted_and_encoded_string == '')
128
+ return encrypted_and_encoded_string if encrypted_and_encoded_string.nil? || (encrypted_and_encoded_string == "")
125
129
 
126
130
  str = encrypted_and_encoded_string.to_s
127
131
 
@@ -150,14 +154,16 @@ module SymmetricEncryption
150
154
  end
151
155
 
152
156
  # Try to force result to UTF-8 encoding, but if it is not valid, force it back to Binary
153
- decrypted.force_encoding(SymmetricEncryption::BINARY_ENCODING) unless decrypted.force_encoding(SymmetricEncryption::UTF8_ENCODING).valid_encoding?
157
+ unless decrypted.force_encoding(SymmetricEncryption::UTF8_ENCODING).valid_encoding?
158
+ decrypted.force_encoding(SymmetricEncryption::BINARY_ENCODING)
159
+ end
154
160
  Coerce.coerce_from_string(decrypted, type)
155
161
  end
156
162
 
157
163
  # Returns the header for the encrypted string
158
164
  # Returns [nil] if no header is present
159
165
  def self.header(encrypted_and_encoded_string)
160
- return if encrypted_and_encoded_string.nil? || (encrypted_and_encoded_string == '')
166
+ return if encrypted_and_encoded_string.nil? || (encrypted_and_encoded_string == "")
161
167
 
162
168
  # Decode before decrypting supplied string
163
169
  decoded = cipher.encoder.decode(encrypted_and_encoded_string.to_s)
@@ -212,7 +218,7 @@ module SymmetricEncryption
212
218
  # the coercible gem is available in the path.
213
219
  # Default: :string
214
220
  def self.encrypt(str, random_iv: SymmetricEncryption.randomize_iv?, compress: false, type: :string, header: cipher.always_add_header)
215
- return str if str.nil? || (str == '')
221
+ return str if str.nil? || (str == "")
216
222
 
217
223
  # Encrypt and then encode the supplied string
218
224
  cipher.encrypt(Coerce.coerce_to_string(str, type), random_iv: random_iv, compress: compress, header: header)
@@ -241,7 +247,7 @@ module SymmetricEncryption
241
247
  # * This method only works reliably when the encrypted data includes the symmetric encryption header.
242
248
  # * nil and '' are considered "encrypted" so that validations do not blow up on empty values.
243
249
  def self.encrypted?(encrypted_data)
244
- return false if encrypted_data.nil? || (encrypted_data == '')
250
+ return false if encrypted_data.nil? || (encrypted_data == "")
245
251
 
246
252
  @header ||= SymmetricEncryption.cipher.encoded_magic_header
247
253
  encrypted_data.to_s.start_with?(@header)
@@ -290,16 +296,16 @@ module SymmetricEncryption
290
296
 
291
297
  # Generate a Random password
292
298
  def self.random_password(size = 22)
293
- require 'securerandom' unless defined?(SecureRandom)
299
+ require "securerandom" unless defined?(SecureRandom)
294
300
  SecureRandom.urlsafe_base64(size)
295
301
  end
296
302
 
297
- BINARY_ENCODING = Encoding.find('binary')
298
- UTF8_ENCODING = Encoding.find('UTF-8')
303
+ BINARY_ENCODING = Encoding.find("binary")
304
+ UTF8_ENCODING = Encoding.find("UTF-8")
299
305
 
300
306
  # Defaults
301
307
  @cipher = nil
302
308
  @secondary_ciphers = []
303
309
  @select_cipher = nil
304
- @random_iv = false
310
+ @randomize_iv = false
305
311
  end
@@ -1,5 +1,5 @@
1
- require 'base64'
2
- require 'aws-sdk-kms'
1
+ require "base64"
2
+ require "aws-sdk-kms"
3
3
  module SymmetricEncryption
4
4
  module Utils
5
5
  # Wrap the AWS KMS client so that it automatically creates the Customer Master Key,
@@ -13,8 +13,8 @@ module SymmetricEncryption
13
13
 
14
14
  # TODO: Map to OpenSSL ciphers
15
15
  AWS_KEY_SPEC_MAP = {
16
- 'aes-256-cbc' => 'AES_256',
17
- 'aes-128-cbc' => 'AES_128'
16
+ "aes-256-cbc" => "AES_256",
17
+ "aes-128-cbc" => "AES_128"
18
18
  }.freeze
19
19
 
20
20
  # TODO: Move to Keystore::Aws
@@ -98,12 +98,10 @@ module SymmetricEncryption
98
98
 
99
99
  private
100
100
 
101
- attr_reader :client
102
-
103
101
  def whoami
104
102
  @whoami ||= `whoami`.strip
105
103
  rescue StandardError
106
- @whoami = 'unknown'
104
+ @whoami = "unknown"
107
105
  end
108
106
 
109
107
  # Creates a new Customer Master Key for Symmetric Encryption use.
@@ -111,10 +109,10 @@ module SymmetricEncryption
111
109
  # TODO: Add error handling and retry
112
110
 
113
111
  resp = client.create_key(
114
- description: 'Symmetric Encryption for Ruby Customer Masker Key',
112
+ description: "Symmetric Encryption for Ruby Customer Masker Key",
115
113
  tags: [
116
- {tag_key: 'CreatedAt', tag_value: Time.now.to_s},
117
- {tag_key: 'CreatedBy', tag_value: whoami}
114
+ {tag_key: "CreatedAt", tag_value: Time.now.to_s},
115
+ {tag_key: "CreatedBy", tag_value: whoami}
118
116
  ]
119
117
  )
120
118
  resp.key_metadata.key_id
@@ -6,7 +6,7 @@ module SymmetricEncryption
6
6
  attr_reader :file_name
7
7
 
8
8
  def read_file_and_decode(file_name)
9
- raise(SymmetricEncryption::ConfigError, 'file_name is mandatory for each key_file entry') unless file_name
9
+ raise(SymmetricEncryption::ConfigError, "file_name is mandatory for each key_file entry") unless file_name
10
10
 
11
11
  raise(SymmetricEncryption::ConfigError, "File #{file_name} could not be found") unless ::File.exist?(file_name)
12
12
 
@@ -31,12 +31,12 @@ module SymmetricEncryption
31
31
  key_path = ::File.dirname(file_name)
32
32
  ::FileUtils.mkdir_p(key_path) unless ::File.directory?(key_path)
33
33
  ::File.rename(file_name, "#{file_name}.#{Time.now.to_i}") if ::File.exist?(file_name)
34
- ::File.open(file_name, 'wb', 0600) { |file| file.write(data) }
34
+ ::File.open(file_name, "wb", 0o600) { |file| file.write(data) }
35
35
  end
36
36
 
37
37
  # Read from the file, raising an exception if it is not found
38
38
  def read_from_file(file_name)
39
- ::File.open(file_name, 'rb', &:read)
39
+ ::File.open(file_name, "rb", &:read)
40
40
  rescue Errno::ENOENT
41
41
  raise(SymmetricEncryption::ConfigError, "Symmetric Encryption key file: '#{file_name}' not found or readable")
42
42
  end
@@ -55,26 +55,26 @@ module SymmetricEncryption
55
55
  lines = File.read(file_name)
56
56
  hits, output_lines = re_encrypt_lines(lines)
57
57
 
58
- File.open(file_name, 'wb') { |file| file.write(output_lines) } if hits.positive?
58
+ File.open(file_name, "wb") { |file| file.write(output_lines) } if hits.positive?
59
59
  hits
60
60
  end
61
61
 
62
62
  # Replaces instances of encrypted data within lines of text with re-encrypted values
63
63
  def re_encrypt_lines(lines)
64
64
  hits = 0
65
- output_lines = ''
65
+ output_lines = ""
66
66
  r = regexp
67
67
  lines.each_line do |line|
68
68
  line.force_encoding(SymmetricEncryption::UTF8_ENCODING)
69
69
  output_lines <<
70
70
  if line.valid_encoding? && (result = line.match(r))
71
- encrypted = result[0]
72
- new_value = re_encrypt(encrypted)
73
- if new_value != encrypted
71
+ encrypted = result[0]
72
+ new_value = re_encrypt(encrypted)
73
+ if new_value == encrypted
74
+ line
75
+ else
74
76
  hits += 1
75
77
  line.gsub(encrypted, new_value)
76
- else
77
- line
78
78
  end
79
79
  else
80
80
  line
@@ -117,8 +117,8 @@ module SymmetricEncryption
117
117
  begin
118
118
  count = re_encrypt_contents(file_name)
119
119
  puts "Re-encrypted #{count} encrypted value(s) in: #{file_name}" if count.positive?
120
- rescue StandardError => exc
121
- puts "Failed re-encrypting the file contents of: #{file_name}. #{exc.class.name}: #{exc.message}"
120
+ rescue StandardError => e
121
+ puts "Failed re-encrypting the file contents of: #{file_name}. #{e.class.name}: #{e.message}"
122
122
  end
123
123
  end
124
124
  end
@@ -127,13 +127,13 @@ module SymmetricEncryption
127
127
  private
128
128
 
129
129
  def regexp
130
- @regexp ||= /#{SymmetricEncryption.cipher.encoded_magic_header}([A-Za-z0-9+\/]+[=\\n]*)/
130
+ @regexp ||= %r{#{SymmetricEncryption.cipher.encoded_magic_header}([A-Za-z0-9+/]+[=\\n]*)}
131
131
  end
132
132
 
133
133
  # Returns [Integer] encrypted file key version.
134
134
  # Returns [nil] if the file is not encrypted or does not have a header.
135
135
  def encrypted_file_version(file_name)
136
- ::File.open(file_name, 'rb') do |file|
136
+ ::File.open(file_name, "rb") do |file|
137
137
  reader = SymmetricEncryption::Reader.new(file)
138
138
  reader.version if reader.header_present?
139
139
  end
@@ -1,3 +1,3 @@
1
1
  module SymmetricEncryption
2
- VERSION = '4.3.0'.freeze
2
+ VERSION = "4.4.0".freeze
3
3
  end
@@ -1,4 +1,4 @@
1
- require 'openssl'
1
+ require "openssl"
2
2
 
3
3
  module SymmetricEncryption
4
4
  # Write to encrypted files and other IO streams.
@@ -49,10 +49,10 @@ module SymmetricEncryption
49
49
  # end
50
50
  def self.open(file_name_or_stream, compress: nil, **args)
51
51
  if file_name_or_stream.is_a?(String)
52
- file_name_or_stream = ::File.open(file_name_or_stream, 'wb')
52
+ file_name_or_stream = ::File.open(file_name_or_stream, "wb")
53
53
  compress = !(/\.(zip|gz|gzip|xls.|)\z/i === file_name_or_stream) if compress.nil?
54
- else
55
- compress = true if compress.nil?
54
+ elsif compress.nil?
55
+ compress = true
56
56
  end
57
57
 
58
58
  begin
@@ -97,15 +97,22 @@ module SymmetricEncryption
97
97
  def initialize(ios, version: nil, cipher_name: nil, header: true, random_key: true, random_iv: true, compress: false)
98
98
  # Compress is only used at this point for setting the flag in the header
99
99
  @ios = ios
100
- raise(ArgumentError, 'When :random_key is true, :random_iv must also be true') if random_key && !random_iv
101
- raise(ArgumentError, 'Cannot supply a :cipher_name unless both :random_key and :random_iv are true') if cipher_name && !random_key && !random_iv
100
+ raise(ArgumentError, "When :random_key is true, :random_iv must also be true") if random_key && !random_iv
101
+ if cipher_name && !random_key && !random_iv
102
+ raise(ArgumentError, "Cannot supply a :cipher_name unless both :random_key and :random_iv are true")
103
+ end
102
104
 
103
105
  # Cipher to encrypt the random_key, or the entire file
104
106
  cipher = SymmetricEncryption.cipher(version)
105
- raise(SymmetricEncryption::CipherError, "Cipher with version:#{version} not found in any of the configured SymmetricEncryption ciphers") unless cipher
107
+ unless cipher
108
+ raise(SymmetricEncryption::CipherError,
109
+ "Cipher with version:#{version} not found in any of the configured SymmetricEncryption ciphers")
110
+ end
106
111
 
107
112
  # Force header if compressed or using random iv, key
108
- header = Header.new(version: cipher.version, compress: compress, cipher_name: cipher_name) if (header == true) || compress || random_key || random_iv
113
+ if (header == true) || compress || random_key || random_iv
114
+ header = Header.new(version: cipher.version, compress: compress, cipher_name: cipher_name)
115
+ end
109
116
 
110
117
  @stream_cipher = ::OpenSSL::Cipher.new(cipher_name || cipher.cipher_name)
111
118
  @stream_cipher.encrypt
@@ -158,8 +165,8 @@ module SymmetricEncryption
158
165
  def write(data)
159
166
  return unless data
160
167
 
161
- bytes = data.to_s
162
- @size += bytes.size
168
+ bytes = data.to_s
169
+ @size += bytes.size
163
170
  partial = @stream_cipher.update(bytes)
164
171
  @ios.write(partial) unless partial.empty?
165
172
  data.length
@@ -168,9 +175,9 @@ module SymmetricEncryption
168
175
  def write(data)
169
176
  return unless data
170
177
 
171
- bytes = data.to_s
172
- @size += bytes.size
173
- partial = @stream_cipher.update(bytes, @cipher_buffer ||= ''.b)
178
+ bytes = data.to_s
179
+ @size += bytes.size
180
+ partial = @stream_cipher.update(bytes, @cipher_buffer ||= "".b)
174
181
  @ios.write(partial) unless partial.empty?
175
182
  data.length
176
183
  end