symmetric-encryption 3.8.3 → 3.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/Rakefile +16 -16
  4. data/examples/symmetric-encryption.yml +33 -38
  5. data/lib/rails/generators/symmetric_encryption/config/templates/symmetric-encryption.yml +10 -14
  6. data/lib/rails/generators/symmetric_encryption/heroku_config/templates/symmetric-encryption.yml +28 -25
  7. data/lib/symmetric_encryption.rb +14 -6
  8. data/lib/symmetric_encryption/cipher.rb +151 -130
  9. data/lib/symmetric_encryption/config.rb +0 -1
  10. data/lib/symmetric_encryption/encoder.rb +79 -0
  11. data/lib/symmetric_encryption/extensions/active_record/base.rb +94 -134
  12. data/lib/symmetric_encryption/extensions/mongo_mapper/plugins/encrypted_key.rb +3 -89
  13. data/lib/symmetric_encryption/key_encryption_key.rb +32 -0
  14. data/lib/symmetric_encryption/railtie.rb +3 -3
  15. data/lib/symmetric_encryption/symmetric_encryption.rb +41 -8
  16. data/lib/symmetric_encryption/utils/re_encrypt_config_files.rb +82 -0
  17. data/lib/symmetric_encryption/version.rb +1 -1
  18. data/test/active_record_test.rb +149 -140
  19. data/test/cipher_test.rb +98 -6
  20. data/test/config/{mongoid_v5.yml → mongoid.yml} +0 -0
  21. data/test/config/symmetric-encryption.yml +4 -10
  22. data/test/config/test_new.key +2 -2
  23. data/test/encoder_test.rb +61 -0
  24. data/test/mongoid_test.rb +12 -22
  25. data/test/reader_test.rb +16 -11
  26. data/test/symmetric_encryption_test.rb +23 -3
  27. data/test/test_db.sqlite3 +0 -0
  28. data/test/test_helper.rb +2 -16
  29. data/test/writer_test.rb +1 -5
  30. metadata +11 -12
  31. data/test/config/mongoid_v2.yml +0 -6
  32. data/test/config/mongoid_v3.yml +0 -9
  33. data/test/mongo_mapper_test.rb +0 -599
data/test/cipher_test.rb CHANGED
@@ -8,7 +8,7 @@ class CipherTest < Minitest::Test
8
8
  it 'allow setting the cipher_name' do
9
9
  cipher = SymmetricEncryption::Cipher.new(
10
10
  cipher_name: 'aes-128-cbc',
11
- key: '1234567890ABCDEF1234567890ABCDEF',
11
+ key: '1234567890ABCDEF',
12
12
  iv: '1234567890ABCDEF',
13
13
  encoding: :none
14
14
  )
@@ -32,7 +32,7 @@ class CipherTest < Minitest::Test
32
32
  it 'throw an exception on bad data' do
33
33
  cipher = SymmetricEncryption::Cipher.new(
34
34
  cipher_name: 'aes-128-cbc',
35
- key: '1234567890ABCDEF1234567890ABCDEF',
35
+ key: '1234567890ABCDEF',
36
36
  iv: '1234567890ABCDEF',
37
37
  encoding: :none
38
38
  )
@@ -44,7 +44,7 @@ class CipherTest < Minitest::Test
44
44
  end
45
45
 
46
46
  [false, true].each do |always_add_header|
47
- SymmetricEncryption::Cipher::ENCODINGS.each do |encoding|
47
+ [:none, :base64, :base64strict, :base16].each do |encoding|
48
48
  describe "encoding: #{encoding} with#{'out' unless always_add_header} header" do
49
49
  before do
50
50
  @social_security_number = '987654321'
@@ -65,7 +65,7 @@ class CipherTest < Minitest::Test
65
65
  @social_security_number_encrypted_with_secondary_1 = "D1UCu38pqJ3jc0GvwJHiow==\n"
66
66
  @non_utf8 = "\xc2".force_encoding('binary')
67
67
  @cipher = SymmetricEncryption::Cipher.new(
68
- key: 'ABCDEF1234567890ABCDEF1234567890',
68
+ key: 'ABCDEF1234567890',
69
69
  iv: 'ABCDEF1234567890',
70
70
  cipher_name: 'aes-128-cbc',
71
71
  encoding: encoding,
@@ -94,7 +94,7 @@ class CipherTest < Minitest::Test
94
94
  end
95
95
 
96
96
  it 'return nil when encrypting nil' do
97
- assert_equal nil, @cipher.encrypt(nil)
97
+ assert_nil @cipher.encrypt(nil)
98
98
  end
99
99
 
100
100
  it "return '' when encrypting ''" do
@@ -102,7 +102,7 @@ class CipherTest < Minitest::Test
102
102
  end
103
103
 
104
104
  it 'return nil when decrypting nil' do
105
- assert_equal nil, @cipher.decrypt(nil)
105
+ assert_nil @cipher.decrypt(nil)
106
106
  end
107
107
 
108
108
  it "return '' when decrypting ''" do
@@ -172,4 +172,96 @@ class CipherTest < Minitest::Test
172
172
  end
173
173
 
174
174
  end
175
+
176
+ describe '.generate_random_keys' do
177
+ describe 'with wrong params' do
178
+ it 'raises ArgumentError' do
179
+ error = assert_raises ArgumentError do
180
+ SymmetricEncryption::Cipher.generate_random_keys(wrong_params: '')
181
+ end
182
+
183
+ assert_equal "SymmetricEncryption::Cipher Invalid options {:wrong_params=>\"\"}", error.message
184
+ end
185
+ end
186
+
187
+ describe 'without keys' do
188
+ it 'creates new keys' do
189
+ h = SymmetricEncryption::Cipher.generate_random_keys
190
+ assert_equal 'aes-256-cbc', h[:cipher_name]
191
+ assert_equal :base64strict, h[:encoding]
192
+ assert h.has_key?(:key), h
193
+ assert h.has_key?(:iv), h
194
+ end
195
+ end
196
+
197
+ describe 'with keys' do
198
+ it 'creates new keys' do
199
+ h = SymmetricEncryption::Cipher.generate_random_keys(key: '', iv: '')
200
+ assert_equal 'aes-256-cbc', h[:cipher_name]
201
+ assert_equal :base64strict, h[:encoding]
202
+ assert h.has_key?(:key), h
203
+ assert h.has_key?(:iv), h
204
+ end
205
+ end
206
+
207
+ describe 'with encrypted keys' do
208
+ it 'creates new encrypted keys' do
209
+ key_encryption_key = SymmetricEncryption::KeyEncryptionKey.generate
210
+ h = SymmetricEncryption::Cipher.generate_random_keys(
211
+ encrypted_key: '',
212
+ encrypted_iv: '',
213
+ private_rsa_key: key_encryption_key
214
+ )
215
+ assert_equal 'aes-256-cbc', h[:cipher_name]
216
+ assert_equal :base64strict, h[:encoding]
217
+ assert h.has_key?(:encrypted_key), h
218
+ assert h.has_key?(:encrypted_iv), h
219
+ end
220
+
221
+ it 'exception on missing rsa key' do
222
+ assert_raises SymmetricEncryption::ConfigError do
223
+ SymmetricEncryption::Cipher.generate_random_keys(
224
+ encrypted_key: '',
225
+ encrypted_iv: ''
226
+ )
227
+ end
228
+ end
229
+ end
230
+
231
+ describe 'with files' do
232
+ before do
233
+ @key_filename = 'blah.key'
234
+ @iv_filename = 'blah.iv'
235
+ end
236
+
237
+ after do
238
+ File.delete(@key_filename) if File.exist?(@key_filename)
239
+ File.delete(@iv_filename) if File.exist?(@iv_filename)
240
+ end
241
+
242
+ it 'creates new files' do
243
+ key_encryption_key = SymmetricEncryption::KeyEncryptionKey.generate
244
+ h = SymmetricEncryption::Cipher.generate_random_keys(
245
+ key_filename: @key_filename,
246
+ iv_filename: @iv_filename,
247
+ private_rsa_key: key_encryption_key
248
+ )
249
+ assert_equal 'aes-256-cbc', h[:cipher_name]
250
+ assert_equal :base64strict, h[:encoding]
251
+ assert h.has_key?(:key_filename), h
252
+ assert h.has_key?(:iv_filename), h
253
+ assert File.exist?(@key_filename)
254
+ assert File.exist?(@iv_filename)
255
+ end
256
+
257
+ it 'exception on missing rsa key' do
258
+ assert_raises SymmetricEncryption::ConfigError do
259
+ SymmetricEncryption::Cipher.generate_random_keys(
260
+ key_filename: @key_filename,
261
+ iv_filename: @iv_filename
262
+ )
263
+ end
264
+ end
265
+ end
266
+ end
175
267
  end
File without changes
@@ -3,8 +3,8 @@
3
3
  #
4
4
  ---
5
5
  test:
6
- # Test RSA Key, DO NOT use this RSA key, generate a new one using
7
- # openssl genrsa 2048
6
+ # Test Key encryption key, DO NOT use this key, generate a new one using
7
+ # SymmetricEncryption::KeyEncryptionKey.generate
8
8
  # Or use the rails generator to create a new config file as described in the readme
9
9
  private_rsa_key: |
10
10
  -----BEGIN RSA PRIVATE KEY-----
@@ -37,10 +37,6 @@ test:
37
37
 
38
38
  ciphers:
39
39
  # Current / Newest Symmetric Encryption Key
40
- #
41
- # To manually generate new keys once this file has been generated:
42
- # require 'symmetric_encryption'
43
- # SymmetricEncryption.generate_symmetric_key_files('this_file_name.yml', 'production')
44
40
  -
45
41
  key_filename: test/config/test_new.key
46
42
  iv_filename: test/config/test_new.iv
@@ -52,9 +48,7 @@ test:
52
48
 
53
49
  # Prior Symmetric Encryption Key specified in environment variable
54
50
  -
55
- # Base64 encoded and RSA encrypted, encryption key
56
- # encrypted_key can be used for retrieving the encrypted key from a source
57
- # other than a local file.
51
+ # Encryption Key
58
52
  #
59
53
  # Example:
60
54
  # # An environment variable:
@@ -63,7 +57,7 @@ test:
63
57
  # NOTE: Do not put the encrypted key directly in this file. It is only here
64
58
  # for testing purposes
65
59
  encrypted_key: <%= 'xFAsZ73PThktyo76PoNQGYnjCJUAd4+Yaz71bO5FajshXsbjkfZjjvbK9hxzWLr+C7X67hcrTypVHB1Rw0De8lRDqexlc87sTx1wtlz70lOvTBXt9Lv4sbJNLxacuqk545LIJpgK02Dq7FGzACV3jb3Yk+QQngiscETYM6PyiuFpReFB0qFOgCSLeBJsXAdNdqkEZggl8PL+lGDueDGeKUng+Ic/AFWPhJGYkk3xV++AGwUFXdDQeuHllxmV9WlzriHnDwzbfugkfGaRjWn808VXrv9Jgf2yRy++gOYUvRnjZ1ltOgXUEEmBVF2Uvhu+zs6C/D4cb1mkR7911M5naA==' %>
66
- # For testing purposes only, the above RSA encrypted key is just:
60
+ # For testing purposes only, the above key is just:
67
61
  # key: ABCDEF1234567890
68
62
  iv: 1234567890ABCDEF
69
63
  cipher_name: aes-128-cbc
@@ -1,2 +1,2 @@
1
- e@ ���D/�t4��k��"z��Qmg
2
- m��r��Ն��۪�ӃqE-�}��]��=���8�WzVܮ+�R�nt���R2����.��Iu�l
1
+ ��|A|1M[g� �C��� 8w���D$K/�o
2
+ -�VLӠ�~$���d����+�<����э|�zORbA�*b�Έ�'L_nj�� ˎ�|��껰������Ptq<���a�|�lo���&ݯI
@@ -0,0 +1,61 @@
1
+ # encoding: utf-8
2
+ require_relative 'test_helper'
3
+
4
+ # Unit Test for SymmetricEncryption
5
+ #
6
+ class EncoderTest < Minitest::Test
7
+ describe SymmetricEncryption::Encoder do
8
+ [:none, :base64, :base64strict, :base16].each do |encoding|
9
+ describe "encoding: #{encoding}" do
10
+ before do
11
+ @data = '987654321'
12
+ @data_encoded =
13
+ case encoding
14
+ when :base64
15
+ "OTg3NjU0MzIx\n"
16
+ when :base64strict
17
+ 'OTg3NjU0MzIx'
18
+ when :base16
19
+ '393837363534333231'
20
+ when :none
21
+ @data
22
+ end
23
+ @encoder = SymmetricEncryption::Encoder[encoding]
24
+ @non_utf8 = "\xc2".force_encoding('binary')
25
+ end
26
+
27
+ it 'correctly encodes' do
28
+ assert_equal @data_encoded, @encoder.encode(@data)
29
+ assert_equal Encoding.find('UTF-8'), @data_encoded.encoding
30
+ end
31
+
32
+ it 'return BINARY encoding for non-UTF-8 data' do
33
+ assert_equal Encoding.find('binary'), @non_utf8.encoding
34
+ assert @non_utf8.valid_encoding?
35
+ assert encoded = @encoder.encode(@non_utf8)
36
+ assert decoded = @encoder.decode(encoded)
37
+ assert decoded.valid_encoding?
38
+ assert_equal Encoding.find('binary'), decoded.encoding, decoded
39
+ assert_equal @non_utf8, decoded
40
+ end
41
+
42
+ it 'return nil when encoding nil' do
43
+ assert_nil @encoder.encode(nil)
44
+ end
45
+
46
+ it "return '' when encoding ''" do
47
+ assert_equal '', @encoder.encode('')
48
+ end
49
+
50
+ it 'return nil when decoding nil' do
51
+ assert_nil @encoder.decode(nil)
52
+ end
53
+
54
+ it "return '' when decoding ''" do
55
+ assert_equal '', @encoder.decode('')
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ end
data/test/mongoid_test.rb CHANGED
@@ -4,27 +4,17 @@ begin
4
4
  require_relative '../lib/symmetric_encryption/extensions/mongoid/encrypted'
5
5
  ENV['RACK_ENV'] = 'test'
6
6
 
7
- Mongoid.logger = SemanticLogger[Mongoid]
8
- filename =
9
- case Mongoid::VERSION.to_i
10
- when 3, 4
11
- 'test/config/mongoid_v3.yml'
12
- when 1, 2
13
- 'test/config/mongoid_v2.yml'
14
- else
15
- 'test/config/mongoid_v5.yml'
16
- end
17
- Mongoid.load!(filename)
7
+ Mongoid.load!('test/config/mongoid.yml')
18
8
 
19
9
  #@formatter:off
20
10
  class MongoidUser
21
11
  include Mongoid::Document
22
12
 
23
13
  field :name, type: String
24
- field :encrypted_bank_account_number, type: String, encrypted: true
25
- field :encrypted_social_security_number, type: String, encrypted: true
26
- field :encrypted_string, type: String, encrypted: {random_iv: true}
27
- field :encrypted_long_string, type: String, encrypted: {random_iv: true, compress: true}
14
+ field :encrypted_bank_account_number, type: String, encrypted: true
15
+ field :encrypted_social_security_number, type: String, encrypted: true
16
+ field :encrypted_string, type: String, encrypted: {random_iv: true}
17
+ field :encrypted_long_string, type: String, encrypted: {random_iv: true, compress: true}
28
18
 
29
19
  field :encrypted_integer_value, type: String, encrypted: {type: :integer}
30
20
  field :aiv, type: String, encrypted: {type: :integer, decrypt_as: :aliased_integer_value}
@@ -194,14 +184,14 @@ begin
194
184
 
195
185
  it "all paths it lead to the same result, check uninitialized" do
196
186
  user = MongoidUser.new
197
- assert_equal nil, user.social_security_number
187
+ assert_nil user.social_security_number
198
188
  assert_equal @bank_account_number, (user.social_security_number = @bank_account_number)
199
189
  assert_equal @bank_account_number, user.social_security_number
200
190
  assert_equal @bank_account_number_encrypted, user.encrypted_social_security_number
201
191
 
202
- assert_equal nil, (user.social_security_number = nil)
203
- assert_equal nil, user.social_security_number
204
- assert_equal nil, user.encrypted_social_security_number
192
+ assert_nil (user.social_security_number = nil)
193
+ assert_nil user.social_security_number
194
+ assert_nil user.encrypted_social_security_number
205
195
  end
206
196
 
207
197
  it 'allow unencrypted values to be passed to the constructor' do
@@ -385,14 +375,14 @@ begin
385
375
 
386
376
  describe 'time values' do
387
377
  it 'return correct data type' do
388
- assert_equal @time_value, @user_clone.time_value
378
+ assert_equal @time_value, @user_clone.time_value.dup
389
379
  assert @user.clone.time_value.kind_of?(Time)
390
380
  end
391
381
 
392
382
  it 'coerce data type before save' do
393
383
  now = Time.now
394
384
  u = MongoidUser.new(time_value: now)
395
- assert_equal now, u.time_value
385
+ assert_equal now, u.time_value.dup
396
386
  assert u.time_value.kind_of?(Time)
397
387
  end
398
388
 
@@ -411,7 +401,7 @@ begin
411
401
  @user_clone.save!
412
402
 
413
403
  @user.reload
414
- assert_equal new_time_value, @user.time_value
404
+ assert_equal new_time_value, @user.time_value.dup
415
405
  end
416
406
  end
417
407
 
data/test/reader_test.rb CHANGED
@@ -140,14 +140,14 @@ class ReaderTest < Minitest::Test
140
140
  File.delete(@filename) if File.exist?(@filename) && !@filename.end_with?('empty.csv')
141
141
  end
142
142
 
143
- it ".empty?" do
143
+ it '.empty?' do
144
144
  assert_equal (@data_size==0), SymmetricEncryption::Reader.empty?(@filename)
145
145
  assert_raises Errno::ENOENT do
146
146
  SymmetricEncryption::Reader.empty?('missing_file')
147
147
  end
148
148
  end
149
149
 
150
- it ".header_present?" do
150
+ it '.header_present?' do
151
151
  assert_equal @header, SymmetricEncryption::Reader.header_present?(@filename)
152
152
  assert_raises Errno::ENOENT do
153
153
  SymmetricEncryption::Reader.header_present?('missing_file')
@@ -160,7 +160,7 @@ class ReaderTest < Minitest::Test
160
160
  file.close
161
161
  end
162
162
 
163
- it "#read()" do
163
+ it '#read' do
164
164
  data = nil
165
165
  eof = nil
166
166
  result = SymmetricEncryption::Reader.open(@filename) do |file|
@@ -172,17 +172,22 @@ class ReaderTest < Minitest::Test
172
172
  assert_equal @data_str, result
173
173
  end
174
174
 
175
- it "#read(size)" do
175
+ it '#read(size)' do
176
176
  file = SymmetricEncryption::Reader.open(@filename)
177
177
  eof = file.eof?
178
178
  data = file.read(4096)
179
179
  file.close
180
180
 
181
181
  assert_equal @eof, eof
182
- assert_equal (@data_size > 0 ? @data_str : nil), data
182
+ if @data_size > 0
183
+ assert_equal @data_str, data
184
+ else
185
+ assert_nil data
186
+ end
187
+
183
188
  end
184
189
 
185
- it "#each_line" do
190
+ it '#each_line' do
186
191
  SymmetricEncryption::Reader.open(@filename) do |file|
187
192
  i = 0
188
193
  file.each_line do |line|
@@ -192,7 +197,7 @@ class ReaderTest < Minitest::Test
192
197
  end
193
198
  end
194
199
 
195
- it "#rewind" do
200
+ it '#rewind' do
196
201
  decrypted = SymmetricEncryption::Reader.open(@filename) do |file|
197
202
  file.read
198
203
  file.rewind
@@ -201,7 +206,7 @@ class ReaderTest < Minitest::Test
201
206
  assert_equal @data_str, decrypted
202
207
  end
203
208
 
204
- it "#gets(nil,size)" do
209
+ it '#gets(nil,size)' do
205
210
  file = SymmetricEncryption::Reader.open(@filename)
206
211
  eof = file.eof?
207
212
  data = file.gets(nil, 4096)
@@ -216,12 +221,12 @@ class ReaderTest < Minitest::Test
216
221
  if defined?(JRuby) && options[:compress] && (usecase == :empty)
217
222
  assert_equal '', data
218
223
  else
219
- assert_equal nil, data
224
+ assert_nil data
220
225
  end
221
226
  end
222
227
  end
223
228
 
224
- it "#gets(delim)" do
229
+ it '#gets(delim)' do
225
230
  SymmetricEncryption::Reader.open(@filename) do |file|
226
231
  i = 0
227
232
  while line = file.gets("\n")
@@ -232,7 +237,7 @@ class ReaderTest < Minitest::Test
232
237
  end
233
238
  end
234
239
 
235
- it "#gets(delim,size)" do
240
+ it '#gets(delim,size)' do
236
241
  SymmetricEncryption::Reader.open(@filename) do |file|
237
242
  i = 0
238
243
  while file.gets("\n", 128)
@@ -41,7 +41,7 @@ class SymmetricEncryptionTest < Minitest::Test
41
41
  end
42
42
  end
43
43
 
44
- SymmetricEncryption::Cipher::ENCODINGS.each do |encoding|
44
+ [:none, :base64, :base64strict, :base16].each do |encoding|
45
45
  describe "encoding: #{encoding}" do
46
46
  before do
47
47
  @social_security_number = '987654321'
@@ -89,7 +89,7 @@ class SymmetricEncryptionTest < Minitest::Test
89
89
  end
90
90
 
91
91
  it 'return nil when encrypting nil' do
92
- assert_equal nil, SymmetricEncryption.encrypt(nil)
92
+ assert_nil SymmetricEncryption.encrypt(nil)
93
93
  end
94
94
 
95
95
  it "return '' when encrypting ''" do
@@ -97,7 +97,7 @@ class SymmetricEncryptionTest < Minitest::Test
97
97
  end
98
98
 
99
99
  it 'return nil when decrypting nil' do
100
- assert_equal nil, SymmetricEncryption.decrypt(nil)
100
+ assert_nil SymmetricEncryption.decrypt(nil)
101
101
  end
102
102
 
103
103
  it "return '' when decrypting ''" do
@@ -293,6 +293,26 @@ class SymmetricEncryptionTest < Minitest::Test
293
293
  end
294
294
  end
295
295
 
296
+ describe '.generate_symmetric_key_files' do
297
+ let(:params) { {private_rsa_key: 'rsa_key', key: 'key', iv: 'iv'} }
298
+ let(:file_path) { File.join(File.dirname(__FILE__), 'config', 'symmetric-encryption.yml') }
299
+ let(:cipher_config) { {encrypted_key: 'encrypted_key', encrypted_iv: 'encrypted_iv'} }
300
+
301
+ let(:config) do
302
+ {
303
+ private_rsa_key: 'rsa_key',
304
+ ciphers: [{version: 1, always_add_header: true, key: 'key', iv: 'iv'}]
305
+ }
306
+ end
307
+
308
+ it 'removes unused config keys before generate the random keys' do
309
+ SymmetricEncryption::Config.stub(:read_config, config) do
310
+ SymmetricEncryption::Cipher.stub(:generate_random_keys, cipher_config) do
311
+ SymmetricEncryption.generate_symmetric_key_files(file_path, 'test')
312
+ end
313
+ end
314
+ end
315
+ end
296
316
  end
297
317
 
298
318
  end