symmetric-encryption 4.0.1 → 4.1.0.beta1

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.
@@ -0,0 +1,133 @@
1
+ require_relative '../test_helper'
2
+ require 'stringio'
3
+
4
+ module SymmetricEncryption
5
+ module Keystore
6
+ class AwsTest < Minitest::Test
7
+ describe SymmetricEncryption::Keystore::File do
8
+ before do
9
+ unless (ENV['AWS_ACCESS_KEY_ID'] && ENV['AWS_SECRET_ACCESS_KEY']) || ENV['AWS_CONFIG_FILE']
10
+ # For example: export AWS_CONFIG_FILE=~/.aws/credentials
11
+ skip 'Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, or AWS_CONFIG_FILE to run AWS KMS tests'
12
+ end
13
+ end
14
+
15
+ let :the_test_path do
16
+ path = "tmp/keystore/aws_test"
17
+ FileUtils.makedirs(path) unless ::File.exist?(path)
18
+ path
19
+ end
20
+
21
+ after do
22
+ # Cleanup generated encryption key files.
23
+ `rm #{the_test_path}/* 2> /dev/null`
24
+ end
25
+
26
+ let :regions do
27
+ %w[us-east-1 us-east-2]
28
+ end
29
+
30
+ let :version do
31
+ 10
32
+ end
33
+
34
+ let :key_config do
35
+ SymmetricEncryption::Keystore::Aws.generate_data_key(
36
+ regions: regions,
37
+ key_path: the_test_path,
38
+ cipher_name: 'aes-256-cbc',
39
+ app_name: 'tester',
40
+ environment: 'test',
41
+ version: version
42
+ )
43
+ end
44
+
45
+ let :master_key_alias do
46
+ 'alias/symmetric-encryption/test'
47
+ end
48
+
49
+ describe '.generate_data_key' do
50
+ it 'increments the version' do
51
+ assert_equal 11, key_config[:version]
52
+ end
53
+
54
+ describe 'with 255 version' do
55
+ let :version do
56
+ 255
57
+ end
58
+
59
+ it 'handles version wrap' do
60
+ assert_equal 1, key_config[:version]
61
+ end
62
+ end
63
+
64
+ describe 'with 0 version' do
65
+ let :version do
66
+ 0
67
+ end
68
+
69
+ it 'increments version' do
70
+ assert_equal 1, key_config[:version]
71
+ end
72
+ end
73
+
74
+ it 'creates encrypted key file for every region' do
75
+ assert key_files = key_config[:key_files]
76
+ common_data_key = nil
77
+ first_encrypted_data_key = nil
78
+
79
+ master_key_alias = "alias/symmetric-encryption/tester/test"
80
+
81
+ key_files.each do |key_file|
82
+ assert region = key_file[:region]
83
+ assert file_name = key_file[:file_name]
84
+ expected_file_name = "#{the_test_path}/tester_test_#{region}_v11.encrypted_key"
85
+
86
+ assert_equal expected_file_name, file_name
87
+ assert ::File.exist?(file_name)
88
+
89
+ assert encoded_data_key = ::File.read(file_name)
90
+ encrypted_data_key = Base64.strict_decode64(encoded_data_key)
91
+
92
+ aws = SymmetricEncryption::Utils::Aws.new(region: region, master_key_alias: master_key_alias)
93
+ assert data_key = aws.decrypt(encrypted_data_key)
94
+
95
+ # Verify that the dek is the same in every region, but encrypted with the CMK for that region.
96
+ if common_data_key
97
+ refute_equal encrypted_data_key, first_encrypted_data_key, 'Must be encrypted with region specific CMK'
98
+ assert_equal common_data_key, data_key, 'All regions must have the same data key'
99
+ else
100
+ first_encrypted_data_key = encrypted_data_key
101
+ common_data_key = data_key
102
+ end
103
+ end
104
+ end
105
+
106
+ it 'retains cipher_name' do
107
+ assert_equal 'aes-256-cbc', key_config[:cipher_name]
108
+ end
109
+
110
+ it 'is readable by Keystore.read_key' do
111
+ ENV['AWS_REGION'] = 'us-east-1'
112
+ assert SymmetricEncryption::Keystore.read_key(key_config)
113
+ end
114
+ end
115
+
116
+ describe '#write, #read' do
117
+ let :keystore do
118
+ SymmetricEncryption::Keystore::Aws.new(
119
+ region: 'us-east-1',
120
+ master_key_alias: master_key_alias,
121
+ key_files: [{region: 'us-east-1', file_name: "#{the_test_path}/file_1"}]
122
+ )
123
+ end
124
+
125
+ it 'stores the key' do
126
+ keystore.write('TEST')
127
+ assert_equal 'TEST', keystore.read
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
@@ -2,20 +2,15 @@ require_relative '../test_helper'
2
2
  require 'stringio'
3
3
 
4
4
  module SymmetricEncryption
5
- class FileTest < Minitest::Test
5
+ class EnvironmentTest < Minitest::Test
6
6
  describe SymmetricEncryption::Keystore::Environment do
7
- after do
8
- # Cleanup generated encryption key files.
9
- `rm tmp/tester* 2> /dev/null`
10
- end
11
-
12
- describe '.new_key_config' do
7
+ describe '.generate_data_key' do
13
8
  let :version do
14
9
  10
15
10
  end
16
11
 
17
12
  let :keystore_config do
18
- SymmetricEncryption::Keystore::Environment.new_key_config(
13
+ SymmetricEncryption::Keystore::Environment.generate_data_key(
19
14
  cipher_name: 'aes-256-cbc',
20
15
  app_name: 'tester',
21
16
  environment: 'test',
@@ -56,49 +51,6 @@ module SymmetricEncryption
56
51
  end
57
52
  end
58
53
 
59
- describe '.new_config' do
60
- let :environments do
61
- %i[development test acceptance preprod production]
62
- end
63
-
64
- let :config do
65
- SymmetricEncryption::Keystore::Environment.new_config(
66
- app_name: 'tester',
67
- environments: environments,
68
- cipher_name: 'aes-128-cbc'
69
- )
70
- end
71
-
72
- it 'creates keys for each environment' do
73
- assert_equal environments, config.keys, config
74
- end
75
-
76
- it 'use test config for development and test' do
77
- assert_equal SymmetricEncryption::Keystore.dev_config, config[:test]
78
- assert_equal SymmetricEncryption::Keystore.dev_config, config[:development]
79
- end
80
-
81
- it 'each non test environment has a key encryption key' do
82
- (environments - %i[development test]).each do |env|
83
- assert config[env][:ciphers].first[:key_encrypting_key], "Environment #{env} is missing the key encryption key"
84
- end
85
- end
86
-
87
- it 'every environment has ciphers' do
88
- environments.each do |env|
89
- assert ciphers = config[env][:ciphers], "Environment #{env} is missing ciphers: #{config[env].inspect}"
90
- assert_equal 1, ciphers.size
91
- end
92
- end
93
-
94
- it 'creates an encrypted key file for all non-test environments' do
95
- (environments - %i[development test]).each do |env|
96
- assert ciphers = config[env][:ciphers], "Environment #{env} is missing ciphers: #{config[env].inspect}"
97
- assert ciphers.first[:key_env_var], "Environment #{env} is missing key_env_var: #{ciphers.inspect}"
98
- end
99
- end
100
- end
101
-
102
54
  describe '#read' do
103
55
  let :key do
104
56
  SymmetricEncryption::Key.new
@@ -4,19 +4,25 @@ require 'stringio'
4
4
  module SymmetricEncryption
5
5
  class FileTest < Minitest::Test
6
6
  describe SymmetricEncryption::Keystore::File do
7
+ let :the_test_path do
8
+ path = "tmp/keystore/file_test"
9
+ FileUtils.makedirs(path) unless ::File.exist?(path)
10
+ path
11
+ end
12
+
7
13
  after do
8
14
  # Cleanup generated encryption key files.
9
- `rm tmp/tester* 2> /dev/null`
15
+ `rm #{the_test_path}/* 2> /dev/null`
10
16
  end
11
17
 
12
- describe '.new_key_config' do
18
+ describe '.generate_data_key' do
13
19
  let :version do
14
20
  10
15
21
  end
16
22
 
17
23
  let :key_config do
18
- SymmetricEncryption::Keystore::File.new_key_config(
19
- key_path: 'tmp',
24
+ SymmetricEncryption::Keystore::File.generate_data_key(
25
+ key_path: the_test_path,
20
26
  cipher_name: 'aes-256-cbc',
21
27
  app_name: 'tester',
22
28
  environment: 'test',
@@ -49,7 +55,7 @@ module SymmetricEncryption
49
55
  end
50
56
 
51
57
  it 'creates the encrypted key file' do
52
- file_name = 'tmp/tester_test_v11.encrypted_key'
58
+ file_name = "#{the_test_path}/tester_test_v11.encrypted_key"
53
59
  assert_equal file_name, key_config[:key_filename]
54
60
  assert File.exist?(file_name)
55
61
  end
@@ -60,58 +66,13 @@ module SymmetricEncryption
60
66
 
61
67
  it 'is readable by Key.from_config' do
62
68
  key_config.delete(:version)
63
- assert SymmetricEncryption::Key.from_config(key_config)
64
- end
65
- end
66
-
67
- describe '.new_config' do
68
- let :environments do
69
- %i[development test acceptance preprod production]
70
- end
71
-
72
- let :config do
73
- SymmetricEncryption::Keystore::File.new_config(
74
- key_path: 'tmp',
75
- app_name: 'tester',
76
- environments: environments,
77
- cipher_name: 'aes-128-cbc'
78
- )
79
- end
80
-
81
- it 'creates keys for each environment' do
82
- assert_equal environments, config.keys, config
83
- end
84
-
85
- it 'use test config for development and test' do
86
- assert_equal SymmetricEncryption::Keystore.dev_config, config[:test]
87
- assert_equal SymmetricEncryption::Keystore.dev_config, config[:development]
88
- end
89
-
90
- it 'each non test environment has a key encryption key' do
91
- (environments - %i[development test]).each do |env|
92
- assert config[env][:ciphers].first[:key_encrypting_key], "Environment #{env} is missing the key encryption key"
93
- end
94
- end
95
-
96
- it 'every environment has ciphers' do
97
- environments.each do |env|
98
- assert ciphers = config[env][:ciphers], "Environment #{env} is missing ciphers: #{config[env].inspect}"
99
- assert_equal 1, ciphers.size
100
- end
101
- end
102
-
103
- it 'creates an encrypted key file for all non-test environments' do
104
- (environments - %i[development test]).each do |env|
105
- assert ciphers = config[env][:ciphers], "Environment #{env} is missing ciphers: #{config[env].inspect}"
106
- assert file_name = ciphers.first[:key_filename], "Environment #{env} is missing key_filename: #{ciphers.inspect}"
107
- assert File.exist?(file_name)
108
- end
69
+ assert SymmetricEncryption::Keystore.read_key(key_config)
109
70
  end
110
71
  end
111
72
 
112
73
  describe '#write, #read' do
113
74
  let :keystore do
114
- SymmetricEncryption::Keystore::File.new(file_name: 'tmp/tester.key', key_encrypting_key: SymmetricEncryption::Key.new)
75
+ SymmetricEncryption::Keystore::File.new(key_filename: "#{the_test_path}/tester.key", key_encrypting_key: SymmetricEncryption::Key.new)
115
76
  end
116
77
 
117
78
  it 'stores the key' do
@@ -0,0 +1,70 @@
1
+ require_relative '../test_helper'
2
+ require 'stringio'
3
+
4
+ module SymmetricEncryption
5
+ class HerokuTest < Minitest::Test
6
+ describe SymmetricEncryption::Keystore::Heroku do
7
+ describe '.generate_data_key' do
8
+ let :version do
9
+ 10
10
+ end
11
+
12
+ let :keystore_config do
13
+ SymmetricEncryption::Keystore::Heroku.generate_data_key(
14
+ cipher_name: 'aes-256-cbc',
15
+ app_name: 'tester',
16
+ environment: 'test',
17
+ version: version
18
+ )
19
+ end
20
+
21
+ it 'increments the version' do
22
+ assert_equal 11, keystore_config[:version]
23
+ end
24
+
25
+ describe 'with 255 version' do
26
+ let :version do
27
+ 255
28
+ end
29
+
30
+ it 'handles version wrap' do
31
+ assert_equal 1, keystore_config[:version]
32
+ end
33
+ end
34
+
35
+ describe 'with 0 version' do
36
+ let :version do
37
+ 0
38
+ end
39
+
40
+ it 'increments version' do
41
+ assert_equal 1, keystore_config[:version]
42
+ end
43
+ end
44
+
45
+ it 'retains the env var name' do
46
+ assert_equal 'TESTER_TEST_V11', keystore_config[:key_env_var]
47
+ end
48
+
49
+ it 'retains cipher_name' do
50
+ assert_equal 'aes-256-cbc', keystore_config[:cipher_name]
51
+ end
52
+ end
53
+
54
+ describe '#read' do
55
+ let :key do
56
+ SymmetricEncryption::Key.new
57
+ end
58
+
59
+ let :keystore do
60
+ SymmetricEncryption::Keystore::Heroku.new(key_env_var: 'TESTER_ENV_VAR', key_encrypting_key: key)
61
+ end
62
+
63
+ it 'reads the key' do
64
+ ENV['TESTER_ENV_VAR'] = Base64.strict_encode64(key.encrypt('TEST'))
65
+ assert_equal 'TEST', keystore.read
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -7,9 +7,80 @@ module SymmetricEncryption
7
7
  SymmetricEncryption::Keystore::File.new(file_name: 'tmp/tester.key', key_encrypting_key: SymmetricEncryption::Key.new)
8
8
  end
9
9
 
10
+ let :the_test_path do
11
+ path = "tmp/keystore_test"
12
+ FileUtils.makedirs(path) unless ::File.exist?(path)
13
+ path
14
+ end
15
+
10
16
  after do
11
17
  # Cleanup generated encryption key files.
12
- `rm tmp/tester* 2>/dev/null`
18
+ `rm #{the_test_path}/* 2> /dev/null`
19
+ end
20
+
21
+ let :random_key do
22
+ SymmetricEncryption::Key.new
23
+ end
24
+
25
+ let :stored_key do
26
+ '1234567890ABCDEF1234567890ABCDEF'
27
+ end
28
+
29
+ let :stored_iv do
30
+ 'ABCDEF1234567890'
31
+ end
32
+
33
+ let :key do
34
+ SymmetricEncryption::Key.new(key: stored_key, iv: stored_iv)
35
+ end
36
+
37
+ let :stored_key2 do
38
+ 'ABCDEF1234567890ABCDEF1234567890'
39
+ end
40
+
41
+ let :stored_iv2 do
42
+ '1234567890ABCDEF'
43
+ end
44
+
45
+ let :key2 do
46
+ SymmetricEncryption::Key.new(key: stored_key2, iv: stored_iv2)
47
+ end
48
+
49
+ let :stored_key3 do
50
+ 'ABCDEF0123456789ABCDEF0123456789'
51
+ end
52
+
53
+ let :stored_iv3 do
54
+ '0123456789ABCDEF'
55
+ end
56
+
57
+ let :key3 do
58
+ SymmetricEncryption::Key.new(key: stored_key3, iv: stored_iv3)
59
+ end
60
+
61
+ describe '.generate_data_keys' do
62
+ let :environments do
63
+ %i[development test acceptance preprod production]
64
+ end
65
+
66
+ let :config do
67
+ SymmetricEncryption::Keystore.generate_data_keys(
68
+ keystore: :file,
69
+ key_path: the_test_path,
70
+ app_name: 'tester',
71
+ environments: environments,
72
+ cipher_name: 'aes-128-cbc'
73
+ )
74
+ end
75
+
76
+ it 'creates keys for each environment' do
77
+ assert_equal environments, config.keys, config
78
+ end
79
+
80
+ it 'use test config for development and test' do
81
+ assert_equal SymmetricEncryption::Keystore.dev_config, config[:test]
82
+ assert_equal SymmetricEncryption::Keystore.dev_config, config[:development]
83
+ end
13
84
  end
14
85
 
15
86
  describe '.rotate_keys' do
@@ -18,8 +89,9 @@ module SymmetricEncryption
18
89
  end
19
90
 
20
91
  let :config do
21
- SymmetricEncryption::Keystore::File.new_config(
22
- key_path: 'tmp',
92
+ SymmetricEncryption::Keystore.generate_data_keys(
93
+ keystore: :file,
94
+ key_path: the_test_path,
23
95
  app_name: 'tester',
24
96
  environments: environments,
25
97
  cipher_name: 'aes-128-cbc'
@@ -53,6 +125,130 @@ module SymmetricEncryption
53
125
  end
54
126
  end
55
127
  end
128
+
129
+ describe '.read_key' do
130
+ let :config do
131
+ {key: stored_key, iv: stored_iv}
132
+ end
133
+
134
+ let :config_key do
135
+ SymmetricEncryption::Keystore.read_key(config)
136
+ end
137
+
138
+ let :dek_file_name do
139
+ "#{the_test_path}/dek_tester_dek.encrypted_key"
140
+ end
141
+
142
+ describe 'key' do
143
+ it 'key' do
144
+ assert_equal stored_key, config_key.key
145
+ end
146
+
147
+ it 'iv' do
148
+ assert_equal stored_iv, config_key.iv
149
+ end
150
+
151
+ it 'cipher_name' do
152
+ assert_equal 'aes-256-cbc', config_key.cipher_name
153
+ end
154
+ end
155
+
156
+ describe 'encrypted_key' do
157
+ let :config do
158
+ {encrypted_key: key2.encrypt(stored_key), iv: stored_iv, key_encrypting_key: {key: stored_key2, iv: stored_iv2}}
159
+ end
160
+
161
+ it 'key' do
162
+ assert_equal stored_key, config_key.key
163
+ end
164
+
165
+ it 'iv' do
166
+ assert_equal stored_iv, config_key.iv
167
+ end
168
+
169
+ it 'cipher_name' do
170
+ assert_equal 'aes-256-cbc', config_key.cipher_name
171
+ end
172
+ end
173
+
174
+ describe 'key_filename' do
175
+ let :config do
176
+ File.open(dek_file_name, 'wb') { |f| f.write(key2.encrypt(stored_key)) }
177
+ {key_filename: dek_file_name, iv: stored_iv, key_encrypting_key: {key: stored_key2, iv: stored_iv2}}
178
+ end
179
+
180
+ it 'key' do
181
+ assert_equal stored_key, config_key.key
182
+ end
183
+
184
+ it 'iv' do
185
+ assert_equal stored_iv, config_key.iv
186
+ end
187
+
188
+ it 'cipher_name' do
189
+ assert_equal 'aes-256-cbc', config_key.cipher_name
190
+ end
191
+ end
192
+
193
+ describe 'key_env_var' do
194
+ let :env_var do
195
+ 'TEST_KEY'
196
+ end
197
+
198
+ let :config do
199
+ ENV[env_var] = ::Base64.strict_encode64(key2.encrypt(stored_key))
200
+ {key_env_var: env_var, iv: stored_iv, key_encrypting_key: {key: stored_key2, iv: stored_iv2}}
201
+ end
202
+
203
+ it 'key' do
204
+ assert_equal stored_key, config_key.key
205
+ end
206
+
207
+ it 'iv' do
208
+ assert_equal stored_iv, config_key.iv
209
+ end
210
+
211
+ it 'cipher_name' do
212
+ assert_equal 'aes-256-cbc', config_key.cipher_name
213
+ end
214
+ end
215
+
216
+ describe 'file store with kekek' do
217
+ let :kekek_file_name do
218
+ "#{the_test_path}/tester_kekek.key"
219
+ end
220
+
221
+ let :config do
222
+ File.open(dek_file_name, 'wb') { |f| f.write(key2.encrypt(stored_key)) }
223
+ encrypted_key = key3.encrypt(stored_key2)
224
+ File.open(kekek_file_name, 'wb') { |f| f.write(stored_key3) }
225
+ {
226
+ key_filename: dek_file_name,
227
+ iv: stored_iv,
228
+ key_encrypting_key: {
229
+ encrypted_key: encrypted_key,
230
+ iv: stored_iv2,
231
+ key_encrypting_key: {
232
+ key_filename: kekek_file_name,
233
+ iv: stored_iv3
234
+ }
235
+ }
236
+ }
237
+ end
238
+
239
+ it 'key' do
240
+ assert_equal stored_key, config_key.key
241
+ end
242
+
243
+ it 'iv' do
244
+ assert_equal stored_iv, config_key.iv
245
+ end
246
+
247
+ it 'cipher_name' do
248
+ assert_equal 'aes-256-cbc', config_key.cipher_name
249
+ end
250
+ end
251
+ end
56
252
  end
57
253
  end
58
254
  end