symmetric-encryption 4.2.1 → 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 (36) 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/{railties → active_record}/attr_encrypted.rb +16 -5
  7. data/lib/symmetric_encryption/active_record/encrypted_attribute.rb +37 -0
  8. data/lib/symmetric_encryption/cipher.rb +20 -14
  9. data/lib/symmetric_encryption/cli.rb +72 -54
  10. data/lib/symmetric_encryption/coerce.rb +3 -3
  11. data/lib/symmetric_encryption/config.rb +28 -27
  12. data/lib/symmetric_encryption/core.rb +25 -20
  13. data/lib/symmetric_encryption/encoder.rb +26 -8
  14. data/lib/symmetric_encryption/generator.rb +7 -3
  15. data/lib/symmetric_encryption/header.rb +24 -24
  16. data/lib/symmetric_encryption/key.rb +1 -1
  17. data/lib/symmetric_encryption/keystore/aws.rb +10 -13
  18. data/lib/symmetric_encryption/keystore/environment.rb +5 -5
  19. data/lib/symmetric_encryption/keystore/file.rb +27 -9
  20. data/lib/symmetric_encryption/keystore/gcp.rb +21 -18
  21. data/lib/symmetric_encryption/keystore/heroku.rb +1 -1
  22. data/lib/symmetric_encryption/keystore/memory.rb +3 -3
  23. data/lib/symmetric_encryption/keystore.rb +23 -23
  24. data/lib/symmetric_encryption/railtie.rb +12 -11
  25. data/lib/symmetric_encryption/railties/mongoid_encrypted.rb +5 -4
  26. data/lib/symmetric_encryption/railties/symmetric_encryption_validator.rb +1 -1
  27. data/lib/symmetric_encryption/reader.rb +13 -13
  28. data/lib/symmetric_encryption/rsa_key.rb +1 -1
  29. data/lib/symmetric_encryption/symmetric_encryption.rb +56 -36
  30. data/lib/symmetric_encryption/utils/aws.rb +8 -10
  31. data/lib/symmetric_encryption/utils/files.rb +3 -3
  32. data/lib/symmetric_encryption/utils/re_encrypt_files.rb +11 -11
  33. data/lib/symmetric_encryption/version.rb +1 -1
  34. data/lib/symmetric_encryption/writer.rb +20 -13
  35. data/lib/symmetric_encryption.rb +13 -9
  36. metadata +10 -10
@@ -1,5 +1,5 @@
1
- require 'erb'
2
- require 'yaml'
1
+ require "erb"
2
+ require "yaml"
3
3
  module SymmetricEncryption
4
4
  class Config
5
5
  attr_reader :file_name, :env
@@ -38,12 +38,12 @@ module SymmetricEncryption
38
38
  config = deep_stringify_keys(config)
39
39
 
40
40
  FileUtils.mkdir_p(File.dirname(file_name))
41
- File.open(file_name, 'w') do |f|
42
- f.puts '# This file was auto generated by symmetric-encryption.'
43
- f.puts '# Recommend using symmetric-encryption to make changes.'
44
- f.puts '# For more info, run:'
45
- f.puts '# symmetric-encryption --help'
46
- f.puts '#'
41
+ File.open(file_name, "w") do |f|
42
+ f.puts "# This file was auto generated by symmetric-encryption."
43
+ f.puts "# Recommend using symmetric-encryption to make changes."
44
+ f.puts "# For more info, run:"
45
+ f.puts "# symmetric-encryption --help"
46
+ f.puts "#"
47
47
  f.write(config.to_yaml)
48
48
  end
49
49
  end
@@ -52,15 +52,15 @@ module SymmetricEncryption
52
52
  #
53
53
  # See: `.load!` for parameters.
54
54
  def initialize(file_name: nil, env: nil)
55
- env ||= defined?(Rails) ? Rails.env : ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
55
+ env ||= defined?(Rails) ? Rails.env : ENV["RACK_ENV"] || ENV["RAILS_ENV"] || "development"
56
56
 
57
57
  unless file_name
58
- root = defined?(Rails) ? Rails.root : '.'
59
- file_name =
60
- if (env_var = ENV['SYMMETRIC_ENCRYPTION_CONFIG'])
58
+ root = defined?(Rails) ? Rails.root : "."
59
+ file_name =
60
+ if (env_var = ENV["SYMMETRIC_ENCRYPTION_CONFIG"])
61
61
  File.expand_path(env_var)
62
62
  else
63
- File.join(root, 'config', 'symmetric-encryption.yml')
63
+ File.join(root, "config", "symmetric-encryption.yml")
64
64
  end
65
65
  raise(ConfigError, "Cannot find config file: #{file_name}") unless File.exist?(file_name)
66
66
  end
@@ -71,20 +71,21 @@ module SymmetricEncryption
71
71
 
72
72
  # Returns [Hash] the configuration for the supplied environment.
73
73
  def config
74
- @config ||= begin
75
- raise(ConfigError, "Cannot find config file: #{file_name}") unless File.exist?(file_name)
74
+ @config ||=
75
+ begin
76
+ raise(ConfigError, "Cannot find config file: #{file_name}") unless File.exist?(file_name)
76
77
 
77
- env_config = YAML.load(ERB.new(File.new(file_name).read).result)[env]
78
- raise(ConfigError, "Cannot find environment: #{env} in config file: #{file_name}") unless env_config
78
+ env_config = YAML.load(ERB.new(File.new(file_name).read).result)[env]
79
+ raise(ConfigError, "Cannot find environment: #{env} in config file: #{file_name}") unless env_config
79
80
 
80
- env_config = self.class.send(:deep_symbolize_keys, env_config)
81
- self.class.send(:migrate_old_formats!, env_config)
82
- end
81
+ env_config = self.class.send(:deep_symbolize_keys, env_config)
82
+ self.class.send(:migrate_old_formats!, env_config)
83
+ end
83
84
  end
84
85
 
85
- # Returns [Array(SymmetricEncrytion::Cipher)] ciphers specified in the configuration file.
86
+ # Returns [Array(SymmetricEncryption::Cipher)] ciphers specified in the configuration file.
86
87
  def ciphers
87
- @ciphers ||= config[:ciphers].collect { |cipher_config| Cipher.from_config(cipher_config) }
88
+ @ciphers ||= config[:ciphers].collect { |cipher_config| Cipher.from_config(**cipher_config) }
88
89
  end
89
90
 
90
91
  # Iterate through the Hash symbolizing all keys.
@@ -129,22 +130,22 @@ module SymmetricEncryption
129
130
  def self.migrate_old_formats!(config)
130
131
  # Inline single cipher before :ciphers
131
132
  unless config.key?(:ciphers)
132
- inline_cipher = {}
133
+ inline_cipher = {}
133
134
  config.keys.each { |key| inline_cipher[key] = config.delete(key) }
134
- config[:ciphers] = [inline_cipher]
135
+ config[:ciphers] = [inline_cipher]
135
136
  end
136
137
 
137
138
  # Copy Old :private_rsa_key into each ciphers config
138
139
  # Cipher.from_config replaces it with the RSA Kek
139
140
  if config[:private_rsa_key]
140
- private_rsa_key = config.delete(:private_rsa_key)
141
+ private_rsa_key = config.delete(:private_rsa_key)
141
142
  config[:ciphers].each { |cipher| cipher[:private_rsa_key] = private_rsa_key }
142
143
  end
143
144
 
144
145
  # Old :cipher_name
145
146
  config[:ciphers].each do |cipher|
146
147
  if (old_key_name_cipher = cipher.delete(:cipher))
147
- cipher[:cipher_name] = old_key_name_cipher
148
+ cipher[:cipher_name] = old_key_name_cipher
148
149
  end
149
150
 
150
151
  # Only temporarily used during v4 Beta process
@@ -155,7 +156,7 @@ module SymmetricEncryption
155
156
  # encrypted_key: <%= ENV['VAR'] %>
156
157
  if cipher.key?(:encrypted_key) && cipher[:encrypted_key].nil?
157
158
  cipher[:key_env_var] = :placeholder
158
- puts 'WARNING: :encrypted_key resolved to nil. Please see the migrated config file for the new option :key_env_var.'
159
+ puts "WARNING: :encrypted_key resolved to nil. Please see the migrated config file for the new option :key_env_var."
159
160
  end
160
161
  end
161
162
  config
@@ -1,30 +1,35 @@
1
1
  # Used for compression
2
- require 'zlib'
2
+ require "zlib"
3
3
  # Used to coerce data types between string and their actual types
4
- require 'coercible'
4
+ require "coercible"
5
5
 
6
- require 'symmetric_encryption/version'
7
- require 'symmetric_encryption/cipher'
8
- require 'symmetric_encryption/symmetric_encryption'
9
- require 'symmetric_encryption/exception'
6
+ require "symmetric_encryption/version"
7
+ require "symmetric_encryption/cipher"
8
+ require "symmetric_encryption/symmetric_encryption"
9
+ require "symmetric_encryption/exception"
10
10
 
11
11
  # @formatter:off
12
12
  module SymmetricEncryption
13
- autoload :Coerce, 'symmetric_encryption/coerce'
14
- autoload :Config, 'symmetric_encryption/config'
15
- autoload :Encoder, 'symmetric_encryption/encoder'
16
- autoload :Generator, 'symmetric_encryption/generator'
17
- autoload :Header, 'symmetric_encryption/header'
18
- autoload :Key, 'symmetric_encryption/key'
19
- autoload :Reader, 'symmetric_encryption/reader'
20
- autoload :RSAKey, 'symmetric_encryption/rsa_key'
21
- autoload :Writer, 'symmetric_encryption/writer'
22
- autoload :CLI, 'symmetric_encryption/cli'
23
- autoload :Keystore, 'symmetric_encryption/keystore'
13
+ autoload :Coerce, "symmetric_encryption/coerce"
14
+ autoload :Config, "symmetric_encryption/config"
15
+ autoload :Encoder, "symmetric_encryption/encoder"
16
+ autoload :EncryptedStringType, "symmetric_encryption/types/encrypted_string_type"
17
+ autoload :Generator, "symmetric_encryption/generator"
18
+ autoload :Header, "symmetric_encryption/header"
19
+ autoload :Key, "symmetric_encryption/key"
20
+ autoload :Reader, "symmetric_encryption/reader"
21
+ autoload :RSAKey, "symmetric_encryption/rsa_key"
22
+ autoload :Writer, "symmetric_encryption/writer"
23
+ autoload :CLI, "symmetric_encryption/cli"
24
+ autoload :Keystore, "symmetric_encryption/keystore"
25
+ module ActiveRecord
26
+ autoload :EncryptedAttribute, "symmetric_encryption/active_record/encrypted_attribute"
27
+ end
28
+
24
29
  module Utils
25
- autoload :Aws, 'symmetric_encryption/utils/aws'
26
- autoload :Files, 'symmetric_encryption/utils/files'
27
- autoload :ReEncryptFiles, 'symmetric_encryption/utils/re_encrypt_files'
30
+ autoload :Aws, "symmetric_encryption/utils/aws"
31
+ autoload :Files, "symmetric_encryption/utils/files"
32
+ autoload :ReEncryptFiles, "symmetric_encryption/utils/re_encrypt_files"
28
33
  end
29
34
  end
30
35
  # @formatter:on
@@ -6,6 +6,8 @@ module SymmetricEncryption
6
6
  Base64.new
7
7
  when :base64strict
8
8
  Base64Strict.new
9
+ when :base64urlsafe
10
+ Base64UrlSafe.new
9
11
  when :base16
10
12
  Base16.new
11
13
  when :none
@@ -35,14 +37,14 @@ module SymmetricEncryption
35
37
 
36
38
  class Base64
37
39
  def encode(binary_string)
38
- return binary_string if binary_string.nil? || (binary_string == '')
40
+ return binary_string if binary_string.nil? || (binary_string == "")
39
41
 
40
42
  encoded_string = ::Base64.encode64(binary_string)
41
43
  encoded_string.force_encoding(SymmetricEncryption::UTF8_ENCODING)
42
44
  end
43
45
 
44
46
  def decode(encoded_string)
45
- return encoded_string if encoded_string.nil? || (encoded_string == '')
47
+ return encoded_string if encoded_string.nil? || (encoded_string == "")
46
48
 
47
49
  decoded_string = ::Base64.decode64(encoded_string)
48
50
  decoded_string.force_encoding(SymmetricEncryption::BINARY_ENCODING)
@@ -51,32 +53,48 @@ module SymmetricEncryption
51
53
 
52
54
  class Base64Strict
53
55
  def encode(binary_string)
54
- return binary_string if binary_string.nil? || (binary_string == '')
56
+ return binary_string if binary_string.nil? || (binary_string == "")
55
57
 
56
58
  encoded_string = ::Base64.strict_encode64(binary_string)
57
59
  encoded_string.force_encoding(SymmetricEncryption::UTF8_ENCODING)
58
60
  end
59
61
 
60
62
  def decode(encoded_string)
61
- return encoded_string if encoded_string.nil? || (encoded_string == '')
63
+ return encoded_string if encoded_string.nil? || (encoded_string == "")
62
64
 
63
65
  decoded_string = ::Base64.decode64(encoded_string)
64
66
  decoded_string.force_encoding(SymmetricEncryption::BINARY_ENCODING)
65
67
  end
66
68
  end
67
69
 
70
+ class Base64UrlSafe
71
+ def encode(binary_string)
72
+ return binary_string if binary_string.nil? || (binary_string == "")
73
+
74
+ encoded_string = ::Base64.urlsafe_encode64(binary_string)
75
+ encoded_string.force_encoding(SymmetricEncryption::UTF8_ENCODING)
76
+ end
77
+
78
+ def decode(encoded_string)
79
+ return encoded_string if encoded_string.nil? || (encoded_string == "")
80
+
81
+ decoded_string = ::Base64.urlsafe_decode64(encoded_string)
82
+ decoded_string.force_encoding(SymmetricEncryption::BINARY_ENCODING)
83
+ end
84
+ end
85
+
68
86
  class Base16
69
87
  def encode(binary_string)
70
- return binary_string if binary_string.nil? || (binary_string == '')
88
+ return binary_string if binary_string.nil? || (binary_string == "")
71
89
 
72
- encoded_string = binary_string.to_s.unpack('H*').first
90
+ encoded_string = binary_string.to_s.unpack("H*").first
73
91
  encoded_string.force_encoding(SymmetricEncryption::UTF8_ENCODING)
74
92
  end
75
93
 
76
94
  def decode(encoded_string)
77
- return encoded_string if encoded_string.nil? || (encoded_string == '')
95
+ return encoded_string if encoded_string.nil? || (encoded_string == "")
78
96
 
79
- decoded_string = [encoded_string].pack('H*')
97
+ decoded_string = [encoded_string].pack("H*")
80
98
  decoded_string.force_encoding(SymmetricEncryption::BINARY_ENCODING)
81
99
  end
82
100
  end
@@ -8,11 +8,15 @@ module SymmetricEncryption
8
8
  compress = options.delete(:compress) || false
9
9
  type = options.delete(:type) || :string
10
10
 
11
- raise(ArgumentError, "SymmetricEncryption Invalid options #{options.inspect} when encrypting '#{decrypted_name}'") unless options.empty?
12
- raise(ArgumentError, "Invalid type: #{type.inspect}. Valid types: #{SymmetricEncryption::COERCION_TYPES.inspect}") unless SymmetricEncryption::COERCION_TYPES.include?(type)
11
+ unless options.empty?
12
+ raise(ArgumentError, "SymmetricEncryption Invalid options #{options.inspect} when encrypting '#{decrypted_name}'")
13
+ end
14
+ unless SymmetricEncryption::COERCION_TYPES.include?(type)
15
+ raise(ArgumentError, "Invalid type: #{type.inspect}. Valid types: #{SymmetricEncryption::COERCION_TYPES.inspect}")
16
+ end
13
17
 
14
18
  if model.const_defined?(:EncryptedAttributes, _search_ancestors = false)
15
- mod = model.const_get(:EncryptedAttributes)
19
+ mod = model.const_get(:EncryptedAttributes)
16
20
  else
17
21
  mod = model.const_set(:EncryptedAttributes, Module.new)
18
22
  model.send(:include, mod)
@@ -8,7 +8,7 @@ module SymmetricEncryption
8
8
  class Header
9
9
  # Encrypted data includes this header prior to encoding when
10
10
  # `always_add_header` is true.
11
- MAGIC_HEADER = '@EnC'.force_encoding(SymmetricEncryption::BINARY_ENCODING)
11
+ MAGIC_HEADER = "@EnC".force_encoding(SymmetricEncryption::BINARY_ENCODING)
12
12
  MAGIC_HEADER_SIZE = MAGIC_HEADER.size
13
13
 
14
14
  # [true|false] Whether to compress the data before encryption.
@@ -37,7 +37,7 @@ module SymmetricEncryption
37
37
  # Returns whether the supplied buffer starts with a symmetric_encryption header
38
38
  # Note: The encoding of the supplied buffer is forced to binary if not already binary
39
39
  def self.present?(buffer)
40
- return false if buffer.nil? || (buffer == '')
40
+ return false if buffer.nil? || (buffer == "")
41
41
 
42
42
  buffer.force_encoding(SymmetricEncryption::BINARY_ENCODING)
43
43
  buffer.start_with?(MAGIC_HEADER)
@@ -122,7 +122,7 @@ module SymmetricEncryption
122
122
  #
123
123
  # Returns 0 if no header is present
124
124
  def parse(buffer, offset = 0)
125
- return 0 if buffer.nil? || (buffer == '') || (buffer.length <= MAGIC_HEADER_SIZE + 2)
125
+ return 0 if buffer.nil? || (buffer == "") || (buffer.length <= MAGIC_HEADER_SIZE + 2)
126
126
 
127
127
  # Symmetric Encryption Header
128
128
  #
@@ -153,7 +153,7 @@ module SymmetricEncryption
153
153
 
154
154
  # Remove header and extract flags
155
155
  self.version = buffer.getbyte(offset)
156
- offset += 1
156
+ offset += 1
157
157
 
158
158
  unless cipher
159
159
  raise(
@@ -162,34 +162,34 @@ module SymmetricEncryption
162
162
  )
163
163
  end
164
164
 
165
- flags = buffer.getbyte(offset)
165
+ flags = buffer.getbyte(offset)
166
166
  offset += 1
167
167
 
168
168
  self.compress = (flags & FLAG_COMPRESSED) != 0
169
169
 
170
- if (flags & FLAG_IV) != 0
171
- self.iv, offset = read_string(buffer, offset)
172
- else
170
+ if (flags & FLAG_IV).zero?
173
171
  self.iv = nil
172
+ else
173
+ self.iv, offset = read_string(buffer, offset)
174
174
  end
175
175
 
176
- if (flags & FLAG_KEY) != 0
176
+ if (flags & FLAG_KEY).zero?
177
+ self.key = nil
178
+ else
177
179
  encrypted_key, offset = read_string(buffer, offset)
178
180
  self.key = cipher.binary_decrypt(encrypted_key)
179
- else
180
- self.key = nil
181
181
  end
182
182
 
183
- if (flags & FLAG_CIPHER_NAME) != 0
184
- self.cipher_name, offset = read_string(buffer, offset)
185
- else
183
+ if (flags & FLAG_CIPHER_NAME).zero?
186
184
  self.cipher_name = nil
185
+ else
186
+ self.cipher_name, offset = read_string(buffer, offset)
187
187
  end
188
188
 
189
- if (flags & FLAG_AUTH_TAG) != 0
190
- self.auth_tag, offset = read_string(buffer, offset)
191
- else
189
+ if (flags & FLAG_AUTH_TAG).zero?
192
190
  self.auth_tag = nil
191
+ else
192
+ self.auth_tag, offset = read_string(buffer, offset)
193
193
  end
194
194
 
195
195
  offset
@@ -197,7 +197,7 @@ module SymmetricEncryption
197
197
 
198
198
  # Returns [String] this header as a string
199
199
  def to_s
200
- flags = 0
200
+ flags = 0
201
201
  flags |= FLAG_COMPRESSED if compressed?
202
202
  flags |= FLAG_IV if iv
203
203
  flags |= FLAG_KEY if key
@@ -207,23 +207,23 @@ module SymmetricEncryption
207
207
  header = "#{MAGIC_HEADER}#{version.chr(SymmetricEncryption::BINARY_ENCODING)}#{flags.chr(SymmetricEncryption::BINARY_ENCODING)}"
208
208
 
209
209
  if iv
210
- header << [iv.length].pack('v')
210
+ header << [iv.length].pack("v")
211
211
  header << iv
212
212
  end
213
213
 
214
214
  if key
215
215
  encrypted = cipher.binary_encrypt(key, header: false)
216
- header << [encrypted.length].pack('v')
216
+ header << [encrypted.length].pack("v")
217
217
  header << encrypted
218
218
  end
219
219
 
220
220
  if cipher_name
221
- header << [cipher_name.length].pack('v')
221
+ header << [cipher_name.length].pack("v")
222
222
  header << cipher_name
223
223
  end
224
224
 
225
225
  if auth_tag
226
- header << [auth_tag.length].pack('v')
226
+ header << [auth_tag.length].pack("v")
227
227
  header << auth_tag
228
228
  end
229
229
 
@@ -258,9 +258,9 @@ module SymmetricEncryption
258
258
  # Exception when
259
259
  # - offset exceeds length of buffer
260
260
  # byteslice truncates when too long, but returns nil when start is beyond end of buffer
261
- len = buffer.byteslice(offset, 2).unpack('v').first
261
+ len = buffer.byteslice(offset, 2).unpack("v").first
262
262
  offset += 2
263
- out = buffer.byteslice(offset, len)
263
+ out = buffer.byteslice(offset, len)
264
264
  [out, offset + len]
265
265
  end
266
266
  end
@@ -3,7 +3,7 @@ module SymmetricEncryption
3
3
  class Key
4
4
  attr_reader :key, :iv, :cipher_name
5
5
 
6
- def initialize(key: :random, iv: :random, cipher_name: 'aes-256-cbc')
6
+ def initialize(key: :random, iv: :random, cipher_name: "aes-256-cbc")
7
7
  @key = key == :random ? ::OpenSSL::Cipher.new(cipher_name).random_key : key
8
8
  @iv = iv == :random ? ::OpenSSL::Cipher.new(cipher_name).random_iv : iv
9
9
  @cipher_name = cipher_name
@@ -1,4 +1,4 @@
1
- require 'aws-sdk-kms'
1
+ require "aws-sdk-kms"
2
2
  module SymmetricEncryption
3
3
  module Keystore
4
4
  # Support AWS Key Management Service (KMS)
@@ -70,24 +70,20 @@ module SymmetricEncryption
70
70
  # ],
71
71
  # iv: 'T80pYzD0E6e/bJCdjZ6TiQ=='
72
72
  # }
73
- def self.generate_data_key(version: 0,
73
+ def self.generate_data_key(cipher_name:, app_name:, environment:, key_path:, version: 0,
74
74
  regions: Utils::Aws::AWS_US_REGIONS,
75
75
  dek: nil,
76
- cipher_name:,
77
- app_name:,
78
- environment:,
79
- key_path:,
80
- **args)
76
+ **_args)
81
77
 
82
78
  # TODO: Also support generating environment variables instead of files.
83
79
 
84
80
  version >= 255 ? (version = 1) : (version += 1)
85
- regions = Array(regions).dup
81
+ regions = Array(regions).dup
86
82
 
87
83
  master_key_alias = master_key_alias(app_name, environment)
88
84
 
89
85
  # File per region for holding the encrypted data key
90
- key_files = regions.collect do |region|
86
+ key_files = regions.collect do |region|
91
87
  file_name = "#{app_name}_#{environment}_#{region}_v#{version}.encrypted_key"
92
88
  {region: region, file_name: ::File.join(key_path, file_name)}
93
89
  end
@@ -116,12 +112,13 @@ module SymmetricEncryption
116
112
 
117
113
  # Stores the Encryption key in a file.
118
114
  # Secures the Encryption key by encrypting it with a key encryption key.
119
- def initialize(region: nil, key_files:, master_key_alias:, key_encrypting_key: nil)
115
+ def initialize(key_files:, master_key_alias:, region: nil, key_encrypting_key: nil)
120
116
  @key_files = key_files
121
117
  @master_key_alias = master_key_alias
122
- @region = region || ENV['AWS_REGION'] || ENV['AWS_DEFAULT_REGION'] || ::Aws.config[:region]
118
+ @region = region || ENV["AWS_REGION"] || ENV["AWS_DEFAULT_REGION"] || ::Aws.config[:region]
123
119
  if key_encrypting_key
124
- raise(SymmetricEncryption::ConfigError, 'AWS KMS keystore encrypts the key itself, so does not support supplying a key_encrypting_key')
120
+ raise(SymmetricEncryption::ConfigError,
121
+ "AWS KMS keystore encrypts the key itself, so does not support supplying a key_encrypting_key")
125
122
  end
126
123
  end
127
124
 
@@ -143,7 +140,7 @@ module SymmetricEncryption
143
140
  region = key_file[:region]
144
141
  file_name = key_file[:file_name]
145
142
 
146
- raise(ArgumentError, 'region and file_name are mandatory for each key_file entry') unless region && file_name
143
+ raise(ArgumentError, "region and file_name are mandatory for each key_file entry") unless region && file_name
147
144
 
148
145
  encrypted_data_key = aws(region).encrypt(data_key)
149
146
  write_encoded_to_file(file_name, encrypted_data_key)
@@ -7,13 +7,13 @@ module SymmetricEncryption
7
7
  # Returns [Hash] a new keystore configuration after generating the data key.
8
8
  #
9
9
  # Increments the supplied version number by 1.
10
- def self.generate_data_key(cipher_name:, app_name:, environment:, version: 0, dek: nil, **args)
10
+ def self.generate_data_key(cipher_name:, app_name:, environment:, version: 0, dek: nil, **_args)
11
11
  version >= 255 ? (version = 1) : (version += 1)
12
12
 
13
- kek = SymmetricEncryption::Key.new(cipher_name: cipher_name)
13
+ kek = SymmetricEncryption::Key.new(cipher_name: cipher_name)
14
14
  dek ||= SymmetricEncryption::Key.new(cipher_name: cipher_name)
15
15
 
16
- key_env_var = "#{app_name}_#{environment}_v#{version}".upcase.tr('-', '_')
16
+ key_env_var = "#{app_name}_#{environment}_v#{version}".upcase.tr("-", "_")
17
17
  new(key_env_var: key_env_var, key_encrypting_key: kek).write(dek.key)
18
18
 
19
19
  {
@@ -50,9 +50,9 @@ module SymmetricEncryption
50
50
  def write(key)
51
51
  encrypted_key = key_encrypting_key.encrypt(key)
52
52
  puts "\n\n********************************************************************************"
53
- puts 'Set the environment variable as follows:'
53
+ puts "Set the environment variable as follows:"
54
54
  puts " export #{key_env_var}=\"#{encoder.encode(encrypted_key)}\""
55
- puts '********************************************************************************'
55
+ puts "********************************************************************************"
56
56
  end
57
57
 
58
58
  private
@@ -2,17 +2,18 @@ module SymmetricEncryption
2
2
  module Keystore
3
3
  class File
4
4
  include Utils::Files
5
+ ALLOWED_PERMISSIONS = %w[100600 100400].freeze
5
6
 
6
7
  attr_accessor :file_name, :key_encrypting_key
7
8
 
8
9
  # Returns [Hash] a new keystore configuration after generating the data key.
9
10
  #
10
11
  # Increments the supplied version number by 1.
11
- def self.generate_data_key(key_path:, cipher_name:, app_name:, environment:, version: 0, dek: nil, **args)
12
+ def self.generate_data_key(key_path:, cipher_name:, app_name:, environment:, version: 0, dek: nil, **_args)
12
13
  version >= 255 ? (version = 1) : (version += 1)
13
14
 
14
15
  dek ||= SymmetricEncryption::Key.new(cipher_name: cipher_name)
15
- kek = SymmetricEncryption::Key.new(cipher_name: cipher_name)
16
+ kek = SymmetricEncryption::Key.new(cipher_name: cipher_name)
16
17
  kekek = SymmetricEncryption::Key.new(cipher_name: cipher_name)
17
18
 
18
19
  dek_file_name = ::File.join(key_path, "#{app_name}_#{environment}_v#{version}.encrypted_key")
@@ -47,11 +48,22 @@ module SymmetricEncryption
47
48
 
48
49
  # Returns the Encryption key in the clear.
49
50
  def read
50
- raise(SymmetricEncryption::ConfigError,
51
- "Symmetric Encryption key file: '#{file_name}' not found") unless ::File.exists?(file_name)
52
- raise(SymmetricEncryption::ConfigError,
53
- "Symmetric Encryption key file '#{file_name}' has the wrong "\
54
- "permissions: #{::File.stat(file_name).mode.to_s(8)}. Expected 100600 or 100400.") unless correct_permissions?
51
+ unless ::File.exist?(file_name)
52
+ raise(SymmetricEncryption::ConfigError,
53
+ "Symmetric Encryption key file: '#{file_name}' not found")
54
+ end
55
+ unless correct_permissions?
56
+ raise(SymmetricEncryption::ConfigError,
57
+ "Symmetric Encryption key file '#{file_name}' has the wrong "\
58
+ "permissions: #{::File.stat(file_name).mode.to_s(8)}. Expected 100600 or 100400.")
59
+ end
60
+ unless owned?
61
+ raise(SymmetricEncryption::ConfigError,
62
+ "Symmetric Encryption key file '#{file_name}' has the wrong "\
63
+ "owner (#{stat.uid}) or group (#{stat.gid}). "\
64
+ "Expected it to be owned by current user "\
65
+ "#{ENV['USER'] || ENV['USERNAME']}.")
66
+ end
55
67
 
56
68
  data = read_from_file(file_name)
57
69
  key_encrypting_key ? key_encrypting_key.decrypt(data) : data
@@ -69,9 +81,15 @@ module SymmetricEncryption
69
81
  # has the correct mode - readable and writable by its owner and no one
70
82
  # else, much like the keys one has in ~/.ssh
71
83
  def correct_permissions?
72
- stat = ::File.stat(file_name)
84
+ ALLOWED_PERMISSIONS.include?(stat.mode.to_s(8))
85
+ end
86
+
87
+ def owned?
88
+ stat.owned?
89
+ end
73
90
 
74
- stat.owned? && %w(100600 100400).include?(stat.mode.to_s(8))
91
+ def stat
92
+ ::File.stat(file_name)
75
93
  end
76
94
  end
77
95
  end
@@ -5,12 +5,12 @@ module SymmetricEncryption
5
5
  class Gcp
6
6
  include Utils::Files
7
7
 
8
- def self.generate_data_key(version: 0, cipher_name:, app_name:, environment:, key_path:)
8
+ def self.generate_data_key(cipher_name:, app_name:, environment:, key_path:, version: 0)
9
9
  version >= 255 ? (version = 1) : (version += 1)
10
10
 
11
- dek = SymmetricEncryption::Key.new(cipher_name: cipher_name)
11
+ dek = SymmetricEncryption::Key.new(cipher_name: cipher_name)
12
12
  file_name = "#{key_path}/#{app_name}_#{environment}_v#{version}.encrypted_key"
13
- keystore = new(
13
+ keystore = new(
14
14
  key_file: file_name,
15
15
  app_name: app_name,
16
16
  environment: environment
@@ -18,21 +18,21 @@ module SymmetricEncryption
18
18
  keystore.write(dek.key)
19
19
 
20
20
  {
21
- keystore: :gcp,
22
- cipher_name: dek.cipher_name,
23
- version: version,
24
- key_file: file_name,
25
- iv: dek.iv,
26
- crypto_key: keystore.crypto_key
21
+ keystore: :gcp,
22
+ cipher_name: dek.cipher_name,
23
+ version: version,
24
+ key_file: file_name,
25
+ iv: dek.iv,
26
+ crypto_key: keystore.crypto_key
27
27
  }
28
28
  end
29
29
 
30
30
  def initialize(key_file:, app_name: nil, environment: nil, key_encrypting_key: nil, crypto_key: nil, project_id: nil, credentials: nil, location_id: nil)
31
- @crypto_key = crypto_key
32
- @app_name = app_name
31
+ @crypto_key = crypto_key
32
+ @app_name = app_name
33
33
  @environment = environment
34
- @file_name = key_file
35
- @project_id = project_id
34
+ @file_name = key_file
35
+ @project_id = project_id
36
36
  @credentials = credentials
37
37
  @location_id = location_id
38
38
  end
@@ -46,7 +46,8 @@ module SymmetricEncryption
46
46
  end
47
47
 
48
48
  def crypto_key
49
- @crypto_key ||= self.class::KMS::KeyManagementServiceClient.crypto_key_path(project_id, location_id, app_name, environment.to_s)
49
+ @crypto_key ||= self.class::KMS::KeyManagementServiceClient.crypto_key_path(project_id, location_id, app_name,
50
+ environment.to_s)
50
51
  end
51
52
 
52
53
  private
@@ -69,18 +70,20 @@ module SymmetricEncryption
69
70
 
70
71
  def project_id
71
72
  @project_id ||= ENV["GOOGLE_CLOUD_PROJECT"]
72
- raise 'GOOGLE_CLOUD_PROJECT must be set' if @project_id.nil?
73
+ raise "GOOGLE_CLOUD_PROJECT must be set" if @project_id.nil?
74
+
73
75
  @project_id
74
76
  end
75
77
 
76
78
  def credentials
77
- @credentials ||= ENV['GOOGLE_CLOUD_KEYFILE']
78
- raise 'GOOGLE_CLOUD_KEYFILE must be set' if @credentials.nil?
79
+ @credentials ||= ENV["GOOGLE_CLOUD_KEYFILE"]
80
+ raise "GOOGLE_CLOUD_KEYFILE must be set" if @credentials.nil?
81
+
79
82
  @credentials
80
83
  end
81
84
 
82
85
  def location_id
83
- @location_id ||= ENV["GOOGLE_CLOUD_LOCATION"] || 'global'
86
+ @location_id ||= ENV["GOOGLE_CLOUD_LOCATION"] || "global"
84
87
  end
85
88
  end
86
89
  end