symmetric-encryption 2.0.2 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +8 -6
- data/Gemfile.lock +38 -21
- data/README.md +2 -2
- data/lib/symmetric_encryption.rb +1 -1
- data/lib/symmetric_encryption/extensions/active_record/base.rb +2 -2
- data/lib/symmetric_encryption/mongoid.rb +118 -0
- data/lib/symmetric_encryption/version.rb +1 -1
- data/nbproject/private/config.properties +0 -0
- data/nbproject/private/private.properties +1 -0
- data/test/attr_encrypted_test.rb +56 -4
- data/test/field_encrypted_test.rb +24 -17
- data/test/test_db.sqlite3 +0 -0
- metadata +5 -3
- data/lib/symmetric_encryption/extensions/mongoid/fields.rb +0 -135
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 21f271484936806efc343704e1bfac1392239fa0
|
4
|
+
data.tar.gz: 53aff815835c31c9677eae87db94336cc72db0e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 89aab4b1b54a70e9e24023c074e03950b298376e6b97bc13a9a2597c5c6eaf1184ec7405ae6fe2ee898d31df7114589977a2d5e0cb2856ecd25641c186780f35
|
7
|
+
data.tar.gz: 08e333431de1b029ced0888c182efe67ad09d1e33e5164cb99a9c9103b990e3f532daa95358ad1bb257faf7fbd41e881a6cb2644631b749271500e71d7b01faa
|
data/Gemfile
CHANGED
@@ -1,11 +1,10 @@
|
|
1
|
-
source
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
|
3
3
|
group :test do
|
4
|
-
gem
|
4
|
+
gem 'rake'
|
5
|
+
gem 'shoulda'
|
5
6
|
|
6
|
-
|
7
|
-
# If Mongoid Appender is not used, Rails 4 should work fine
|
8
|
-
gem "activerecord", "~> 3.2.0"
|
7
|
+
gem 'activerecord'
|
9
8
|
gem 'sqlite3', :platform => :ruby
|
10
9
|
|
11
10
|
platforms :jruby do
|
@@ -13,5 +12,8 @@ group :test do
|
|
13
12
|
gem 'activerecord-jdbcsqlite3-adapter'
|
14
13
|
end
|
15
14
|
|
16
|
-
|
15
|
+
# Use Mongo as the database with Mongoid as the Object Document Mapper
|
16
|
+
# Edge has support for Rails 4
|
17
|
+
gem 'mongoid', git: 'https://github.com/mongoid/mongoid.git'
|
18
|
+
gem 'awesome_print'
|
17
19
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,28 +1,41 @@
|
|
1
|
-
|
2
|
-
remote:
|
1
|
+
GIT
|
2
|
+
remote: https://github.com/mongoid/mongoid.git
|
3
|
+
revision: cb541fa1fd7cf9ab0a725c757490d0ac435a79f7
|
3
4
|
specs:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
activerecord (3.2.13)
|
8
|
-
activemodel (= 3.2.13)
|
9
|
-
activesupport (= 3.2.13)
|
10
|
-
arel (~> 3.0.2)
|
11
|
-
tzinfo (~> 0.3.29)
|
12
|
-
activesupport (3.2.13)
|
13
|
-
i18n (= 0.6.1)
|
14
|
-
multi_json (~> 1.0)
|
15
|
-
arel (3.0.2)
|
16
|
-
builder (3.0.4)
|
17
|
-
i18n (0.6.1)
|
18
|
-
mongoid (3.1.4)
|
19
|
-
activemodel (~> 3.2)
|
20
|
-
moped (~> 1.4)
|
5
|
+
mongoid (4.0.0)
|
6
|
+
activemodel (~> 4.0.0)
|
7
|
+
moped (~> 1.5)
|
21
8
|
origin (~> 1.0)
|
22
9
|
tzinfo (~> 0.3.22)
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: https://rubygems.org/
|
13
|
+
specs:
|
14
|
+
activemodel (4.0.0)
|
15
|
+
activesupport (= 4.0.0)
|
16
|
+
builder (~> 3.1.0)
|
17
|
+
activerecord (4.0.0)
|
18
|
+
activemodel (= 4.0.0)
|
19
|
+
activerecord-deprecated_finders (~> 1.0.2)
|
20
|
+
activesupport (= 4.0.0)
|
21
|
+
arel (~> 4.0.0)
|
22
|
+
activerecord-deprecated_finders (1.0.3)
|
23
|
+
activesupport (4.0.0)
|
24
|
+
i18n (~> 0.6, >= 0.6.4)
|
25
|
+
minitest (~> 4.2)
|
26
|
+
multi_json (~> 1.3)
|
27
|
+
thread_safe (~> 0.1)
|
28
|
+
tzinfo (~> 0.3.37)
|
29
|
+
arel (4.0.0)
|
30
|
+
atomic (1.1.10)
|
31
|
+
awesome_print (1.1.0)
|
32
|
+
builder (3.1.4)
|
33
|
+
i18n (0.6.4)
|
34
|
+
minitest (4.7.5)
|
23
35
|
moped (1.5.0)
|
24
36
|
multi_json (1.7.7)
|
25
37
|
origin (1.1.0)
|
38
|
+
rake (10.1.0)
|
26
39
|
shoulda (3.5.0)
|
27
40
|
shoulda-context (~> 1.0, >= 1.0.1)
|
28
41
|
shoulda-matchers (>= 1.4.1, < 3.0)
|
@@ -30,15 +43,19 @@ GEM
|
|
30
43
|
shoulda-matchers (2.2.0)
|
31
44
|
activesupport (>= 3.0.0)
|
32
45
|
sqlite3 (1.3.7)
|
46
|
+
thread_safe (0.1.0)
|
47
|
+
atomic
|
33
48
|
tzinfo (0.3.37)
|
34
49
|
|
35
50
|
PLATFORMS
|
36
51
|
ruby
|
37
52
|
|
38
53
|
DEPENDENCIES
|
39
|
-
activerecord
|
54
|
+
activerecord
|
40
55
|
activerecord-jdbcsqlite3-adapter
|
56
|
+
awesome_print
|
41
57
|
jdbc-sqlite3
|
42
|
-
mongoid
|
58
|
+
mongoid!
|
59
|
+
rake
|
43
60
|
shoulda
|
44
61
|
sqlite3
|
data/README.md
CHANGED
@@ -79,7 +79,7 @@ option will result in different encrypted output every time it is encrypted.
|
|
79
79
|
* Encryption of passwords in configuration files
|
80
80
|
* Encryption of ActiveRecord model attributes by prefixing attributes / column
|
81
81
|
names with encrypted_
|
82
|
-
* Encryption of Mongoid model fields by adding :encrypted
|
82
|
+
* Encryption of Mongoid model fields by adding :encrypted option to field
|
83
83
|
definitions
|
84
84
|
* Externalization of symmetric encryption keys so that they are not in the
|
85
85
|
source code, or the source code control system
|
@@ -160,7 +160,7 @@ class User
|
|
160
160
|
field :name, :type => String
|
161
161
|
field :encrypted_bank_account_number, :type => String, :encrypted => true
|
162
162
|
field :encrypted_social_security_number, :type => String, :encrypted => true
|
163
|
-
field :encrypted_life_history, :type => String,
|
163
|
+
field :encrypted_life_history, :type => String, :encrypted => {:compress => true, :random_iv => true}
|
164
164
|
end
|
165
165
|
|
166
166
|
# Create a new user document
|
data/lib/symmetric_encryption.rb
CHANGED
@@ -54,7 +54,7 @@ module ActiveRecord #:nodoc:
|
|
54
54
|
# If this method is not called, then the encrypted value is never decrypted
|
55
55
|
def #{attribute}
|
56
56
|
if @stored_encrypted_#{attribute} != self.encrypted_#{attribute}
|
57
|
-
@#{attribute} = ::SymmetricEncryption.decrypt(self.encrypted_#{attribute})
|
57
|
+
@#{attribute} = ::SymmetricEncryption.decrypt(self.encrypted_#{attribute}).freeze
|
58
58
|
@stored_encrypted_#{attribute} = self.encrypted_#{attribute}
|
59
59
|
end
|
60
60
|
@#{attribute}
|
@@ -64,7 +64,7 @@ module ActiveRecord #:nodoc:
|
|
64
64
|
# Also updates the encrypted field with the encrypted value
|
65
65
|
def #{attribute}=(value)
|
66
66
|
self.encrypted_#{attribute} = @stored_encrypted_#{attribute} = ::SymmetricEncryption.encrypt(value#{".to_yaml" if marshal},#{random_iv},#{compress})
|
67
|
-
@#{attribute} = value
|
67
|
+
@#{attribute} = value.freeze
|
68
68
|
end
|
69
69
|
UNENCRYPTED
|
70
70
|
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# Add :encrypted option for Mongoid models
|
2
|
+
#
|
3
|
+
# Example:
|
4
|
+
#
|
5
|
+
# require 'mongoid'
|
6
|
+
# require 'symmetric-encryption'
|
7
|
+
#
|
8
|
+
# # Initialize Mongoid in a standalone environment. In a Rails app this is not required
|
9
|
+
# Mongoid.logger = Logger.new($stdout)
|
10
|
+
# Mongoid.load!('config/mongoid.yml')
|
11
|
+
#
|
12
|
+
# # Initialize SymmetricEncryption in a standalone environment. In a Rails app this is not required
|
13
|
+
# SymmetricEncryption.load!('config/symmetric-encryption.yml', 'test')
|
14
|
+
#
|
15
|
+
# class Person
|
16
|
+
# include Mongoid::Document
|
17
|
+
#
|
18
|
+
# field :name, :type => String
|
19
|
+
# field :encrypted_social_security_number, :type => String, :encrypted => true
|
20
|
+
# field :age, :type => Integer
|
21
|
+
# field :encrypted_life_history, :type => String, :encrypted => {:compress => true, :random_iv => true}
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# The above document results in the following document in the Mongo collection 'persons':
|
25
|
+
# {
|
26
|
+
# "name" : "Joe",
|
27
|
+
# "encrypted_social_security_number" : "...",
|
28
|
+
# "age" : 21
|
29
|
+
# "encrypted_life_history" : "...",
|
30
|
+
# }
|
31
|
+
#
|
32
|
+
# Symmetric Encryption creates the getters and setters to be able to work with the field
|
33
|
+
# in it's unencrypted form. For example
|
34
|
+
#
|
35
|
+
# Example:
|
36
|
+
# person = Person.where(:encrypted_social_security_number => '...').first
|
37
|
+
#
|
38
|
+
# puts "Decrypted Social Security Number is: #{person.social_security_number}"
|
39
|
+
#
|
40
|
+
# # Or is the same as
|
41
|
+
# puts "Decrypted Social Security Number is: #{SymmetricEncryption.decrypt(person.encrypted_social_security_number)}"
|
42
|
+
#
|
43
|
+
# # Sets the encrypted_social_security_number to encrypted version
|
44
|
+
# person.social_security_number = "123456789"
|
45
|
+
#
|
46
|
+
# # Or, is equivalent to:
|
47
|
+
# person.encrypted_social_security_number = SymmetricEncryption.encrypt("123456789")
|
48
|
+
#
|
49
|
+
# Note: Only "String" types are currently supported for encryption
|
50
|
+
#
|
51
|
+
# Note: Unlike attr_encrypted finders must use the encrypted field name
|
52
|
+
# Invalid Example, does not work:
|
53
|
+
# person = Person.where(:social_security_number => '123456789').first
|
54
|
+
#
|
55
|
+
# Valid Example:
|
56
|
+
# person = Person.where(:encrypted_social_security_number => SymmetricEncryption.encrypt('123456789')).first
|
57
|
+
#
|
58
|
+
# Defines all the fields that are accessible on the Document
|
59
|
+
# For each field that is defined, a getter and setter will be
|
60
|
+
# added as an instance method to the Document.
|
61
|
+
#
|
62
|
+
# @example Define a field.
|
63
|
+
# field :social_security_number, :type => String, :encrypted => {:compress => false, :random_iv => false}
|
64
|
+
# field :sensitive_text, :type => String, :encrypted => {:compress => true, :random_iv => true}
|
65
|
+
#
|
66
|
+
# @param [ Symbol ] name The name of the field.
|
67
|
+
# @param [ Hash ] options The options to pass to the field.
|
68
|
+
#
|
69
|
+
# @option options [ Boolean | Hash ] :encrypted If the field contains encrypted data.
|
70
|
+
# @option options [ Symbol ] :decrypt_as Name of the getters and setters to generate to access the decrypted value of this field.
|
71
|
+
# @option options [ Boolean ] :compress Whether to compress this encrypted field
|
72
|
+
# @option options [ Boolean ] :random_iv Whether the encrypted value should use a random IV every time the field is encrypted.
|
73
|
+
#
|
74
|
+
# @option options [ Class ] :type The type of the field.
|
75
|
+
# @option options [ String ] :label The label for the field.
|
76
|
+
# @option options [ Object, Proc ] :default The fields default
|
77
|
+
#
|
78
|
+
# @return [ Field ] The generated field
|
79
|
+
Mongoid::Fields.option :encrypted do |model, field, options|
|
80
|
+
if options != false
|
81
|
+
options = options.is_a?(Hash) ? options.dup : {}
|
82
|
+
field_name = field.name
|
83
|
+
|
84
|
+
decrypt_as = options.delete(:decrypt_as)
|
85
|
+
if decrypt_as.nil? && field_name.to_s.start_with?('encrypted_')
|
86
|
+
decrypt_as = field_name.to_s['encrypted_'.length..-1]
|
87
|
+
else
|
88
|
+
raise "SymmetricEncryption for Mongoid. Encryption enabled for field #{field_name}. It must either start with 'encrypted_' or the option :decrypt_as must be supplied"
|
89
|
+
end
|
90
|
+
|
91
|
+
random_iv = options.delete(:random_iv) || false
|
92
|
+
compress = options.delete(:compress) || false
|
93
|
+
|
94
|
+
# Generate getter and setter methods
|
95
|
+
model.class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
96
|
+
# Set the un-encrypted field
|
97
|
+
# Also updates the encrypted field with the encrypted value
|
98
|
+
def #{decrypt_as}=(value)
|
99
|
+
@stored_#{field_name} = ::SymmetricEncryption.encrypt(value,#{random_iv},#{compress})
|
100
|
+
self.#{field_name} = @stored_#{field_name}
|
101
|
+
@#{decrypt_as} = value.freeze
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns the decrypted value for the encrypted field
|
105
|
+
# The decrypted value is cached and is only decrypted if the encrypted value has changed
|
106
|
+
# If this method is not called, then the encrypted value is never decrypted
|
107
|
+
def #{decrypt_as}
|
108
|
+
if @stored_#{field_name} != self.#{field_name}
|
109
|
+
@#{decrypt_as} = ::SymmetricEncryption.decrypt(self.#{field_name}).freeze
|
110
|
+
@stored_#{field_name} = self.#{field_name}
|
111
|
+
end
|
112
|
+
@#{decrypt_as}
|
113
|
+
end
|
114
|
+
EOS
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
platform.active=Ruby_2
|
data/test/attr_encrypted_test.rb
CHANGED
@@ -5,11 +5,12 @@ require 'rubygems'
|
|
5
5
|
require 'logger'
|
6
6
|
require 'erb'
|
7
7
|
require 'test/unit'
|
8
|
-
require 'shoulda'
|
9
8
|
# Since we want both the AR and Mongoid extensions loaded we need to require them first
|
10
9
|
require 'active_record'
|
11
10
|
require 'mongoid'
|
12
11
|
require 'symmetric-encryption'
|
12
|
+
# Should redefines Proc#bind so must include after Rails
|
13
|
+
require 'shoulda'
|
13
14
|
|
14
15
|
ActiveRecord::Base.logger = Logger.new($stderr)
|
15
16
|
ActiveRecord::Base.configurations = YAML::load(ERB.new(IO.read('test/config/database.yml')).result)
|
@@ -63,11 +64,14 @@ class AttrEncryptedTest < Test::Unit::TestCase
|
|
63
64
|
@string = "A string containing some data to be encrypted with a random initialization vector"
|
64
65
|
@long_string = "A string containing some data to be encrypted with a random initialization vector and compressed since it takes up so much space in plain text form"
|
65
66
|
|
67
|
+
@name = 'Joe Bloggs'
|
68
|
+
|
66
69
|
@user = User.new(
|
67
70
|
# Encrypted Attribute
|
68
|
-
:bank_account_number
|
71
|
+
:bank_account_number => @bank_account_number,
|
69
72
|
# Encrypted Attribute
|
70
|
-
:social_security_number
|
73
|
+
:social_security_number => @social_security_number,
|
74
|
+
:name => @name
|
71
75
|
)
|
72
76
|
end
|
73
77
|
|
@@ -196,6 +200,54 @@ class AttrEncryptedTest < Test::Unit::TestCase
|
|
196
200
|
assert_equal true, @user.valid?
|
197
201
|
end
|
198
202
|
|
199
|
-
|
203
|
+
context "with saved user" do
|
204
|
+
setup do
|
205
|
+
@user.save!
|
206
|
+
end
|
207
|
+
|
208
|
+
teardown do
|
209
|
+
@user.destroy
|
210
|
+
end
|
211
|
+
|
212
|
+
should "handle gsub! for non-encrypted_field" do
|
213
|
+
@user.name.gsub!('a', 'v')
|
214
|
+
new_name = @name.gsub('a', 'v')
|
215
|
+
assert_equal new_name, @user.name
|
216
|
+
@user.reload
|
217
|
+
assert_equal new_name, @user.name
|
218
|
+
end
|
219
|
+
|
220
|
+
should "prevent gsub! on non-encrypted value of encrypted_field" do
|
221
|
+
# can't modify frozen String
|
222
|
+
assert_raises RuntimeError do
|
223
|
+
@user.bank_account_number.gsub!('5', '4')
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
should "revert changes on reload" do
|
228
|
+
new_bank_account_number = '444444444'
|
229
|
+
@user.bank_account_number = new_bank_account_number
|
230
|
+
assert_equal new_bank_account_number, @user.bank_account_number
|
231
|
+
|
232
|
+
# Reload User model from the database
|
233
|
+
@user.reload
|
234
|
+
assert_equal @bank_account_number_encrypted, @user.encrypted_bank_account_number
|
235
|
+
assert_equal @bank_account_number, @user.bank_account_number
|
236
|
+
end
|
237
|
+
|
238
|
+
should "revert changes to encrypted field on reload" do
|
239
|
+
new_bank_account_number = '111111111'
|
240
|
+
new_encrypted_bank_account_number = SymmetricEncryption.encrypt(new_bank_account_number)
|
241
|
+
@user.encrypted_bank_account_number = new_encrypted_bank_account_number
|
242
|
+
assert_equal new_encrypted_bank_account_number, @user.encrypted_bank_account_number
|
243
|
+
assert_equal new_bank_account_number, @user.bank_account_number
|
244
|
+
|
245
|
+
# Reload User model from the database
|
246
|
+
@user.reload
|
247
|
+
assert_equal @bank_account_number_encrypted, @user.encrypted_bank_account_number
|
248
|
+
assert_equal @bank_account_number, @user.bank_account_number
|
249
|
+
end
|
250
|
+
end
|
200
251
|
|
252
|
+
end
|
201
253
|
end
|
@@ -10,7 +10,6 @@ require 'shoulda'
|
|
10
10
|
require 'active_record'
|
11
11
|
require 'mongoid'
|
12
12
|
require 'symmetric-encryption'
|
13
|
-
require 'symmetric_encryption/extensions/mongoid/fields'
|
14
13
|
|
15
14
|
Mongoid.logger = Logger.new($stdout)
|
16
15
|
filename = defined?(Mongoid::VERSION) ? "test/config/mongoid_v3.yml" : "test/config/mongoid_v2.yml"
|
@@ -22,12 +21,8 @@ class MongoidUser
|
|
22
21
|
field :name, :type => String
|
23
22
|
field :encrypted_bank_account_number, :type => String, :encrypted => true
|
24
23
|
field :encrypted_social_security_number, :type => String, :encrypted => true
|
25
|
-
field :encrypted_string, :type => String, :encrypted =>
|
26
|
-
field :encrypted_long_string, :type => String, :encrypted =>
|
27
|
-
# field :encrypted_integer, :type => Integer, :encrypted => true
|
28
|
-
# field :encrypted_float, :type => Float, :encrypted => true
|
29
|
-
# field :encrypted_date, :type => Date, :encrypted => true
|
30
|
-
# etc...
|
24
|
+
field :encrypted_string, :type => String, :encrypted => {:random_iv => true}
|
25
|
+
field :encrypted_long_string, :type => String, :encrypted => {:random_iv => true, :compress => true}
|
31
26
|
|
32
27
|
# validates :encrypted_bank_account_number, :symmetric_encrypted => true
|
33
28
|
# validates :encrypted_social_security_number, :symmetric_encrypted => true
|
@@ -64,19 +59,36 @@ class FieldEncryptedTest < Test::Unit::TestCase
|
|
64
59
|
@user = MongoidUser.new(
|
65
60
|
:encrypted_bank_account_number => @bank_account_number_encrypted,
|
66
61
|
:encrypted_social_security_number => @social_security_number_encrypted,
|
67
|
-
:encrypted_integer => @integer_encrypted,
|
68
|
-
:encrypted_float => @float_encrypted,
|
69
|
-
:encrypted_date => @date_encrypted,
|
70
62
|
:name => "Joe Bloggs"
|
71
63
|
)
|
72
64
|
end
|
73
65
|
|
74
66
|
should "have encrypted methods" do
|
75
67
|
assert_equal true, @user.respond_to?(:encrypted_bank_account_number)
|
76
|
-
assert_equal true, @user.respond_to?(:bank_account_number)
|
77
68
|
assert_equal true, @user.respond_to?(:encrypted_social_security_number)
|
78
|
-
assert_equal true, @user.respond_to?(:
|
69
|
+
assert_equal true, @user.respond_to?(:encrypted_string)
|
70
|
+
assert_equal true, @user.respond_to?(:encrypted_long_string)
|
79
71
|
assert_equal false, @user.respond_to?(:encrypted_name)
|
72
|
+
|
73
|
+
assert_equal true, @user.respond_to?(:encrypted_bank_account_number=)
|
74
|
+
assert_equal true, @user.respond_to?(:encrypted_social_security_number=)
|
75
|
+
assert_equal true, @user.respond_to?(:encrypted_string=)
|
76
|
+
assert_equal true, @user.respond_to?(:encrypted_long_string=)
|
77
|
+
assert_equal false, @user.respond_to?(:encrypted_name=)
|
78
|
+
end
|
79
|
+
|
80
|
+
should "have unencrypted methods" do
|
81
|
+
assert_equal true, @user.respond_to?(:bank_account_number)
|
82
|
+
assert_equal true, @user.respond_to?(:social_security_number)
|
83
|
+
assert_equal true, @user.respond_to?(:string)
|
84
|
+
assert_equal true, @user.respond_to?(:long_string)
|
85
|
+
assert_equal true, @user.respond_to?(:name)
|
86
|
+
|
87
|
+
assert_equal true, @user.respond_to?(:bank_account_number=)
|
88
|
+
assert_equal true, @user.respond_to?(:social_security_number=)
|
89
|
+
assert_equal true, @user.respond_to?(:string=)
|
90
|
+
assert_equal true, @user.respond_to?(:long_string=)
|
91
|
+
assert_equal true, @user.respond_to?(:name=)
|
80
92
|
end
|
81
93
|
|
82
94
|
should "have unencrypted values" do
|
@@ -156,11 +168,6 @@ class FieldEncryptedTest < Test::Unit::TestCase
|
|
156
168
|
assert_equal @bank_account_number_encrypted, user.encrypted_bank_account_number
|
157
169
|
assert_equal @social_security_number_encrypted, user.encrypted_social_security_number
|
158
170
|
end
|
159
|
-
|
160
|
-
# should "support different data types" do
|
161
|
-
# assert_equal @integer, @user.integer
|
162
|
-
# assert_equal @integer_encrypted, @user.encrypted_integer
|
163
|
-
# end
|
164
171
|
end
|
165
172
|
|
166
173
|
end
|
data/test/test_db.sqlite3
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: symmetric-encryption
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Reid Morrison
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-07-16 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: SymmetricEncryption supports encrypting ActiveRecord data, Mongoid data,
|
14
14
|
passwords in configuration files, encrypting and decrypting of large files through
|
@@ -32,7 +32,7 @@ files:
|
|
32
32
|
- lib/symmetric_encryption.rb
|
33
33
|
- lib/symmetric_encryption/cipher.rb
|
34
34
|
- lib/symmetric_encryption/extensions/active_record/base.rb
|
35
|
-
- lib/symmetric_encryption/
|
35
|
+
- lib/symmetric_encryption/mongoid.rb
|
36
36
|
- lib/symmetric_encryption/railtie.rb
|
37
37
|
- lib/symmetric_encryption/railties/symmetric_encryption.rake
|
38
38
|
- lib/symmetric_encryption/railties/symmetric_encryption_validator.rb
|
@@ -40,6 +40,8 @@ files:
|
|
40
40
|
- lib/symmetric_encryption/symmetric_encryption.rb
|
41
41
|
- lib/symmetric_encryption/version.rb
|
42
42
|
- lib/symmetric_encryption/writer.rb
|
43
|
+
- nbproject/private/config.properties
|
44
|
+
- nbproject/private/private.properties
|
43
45
|
- nbproject/private/private.xml
|
44
46
|
- nbproject/private/rake-d.txt
|
45
47
|
- nbproject/project.properties
|
@@ -1,135 +0,0 @@
|
|
1
|
-
# Extensions to the mongoid Document model to support field encryption
|
2
|
-
# per the attr_encrypted model
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# #TODO initialize, create
|
6
|
-
#
|
7
|
-
module Mongoid
|
8
|
-
module Fields
|
9
|
-
module ClassMethods
|
10
|
-
# Example:
|
11
|
-
#
|
12
|
-
# require 'mongoid'
|
13
|
-
# require 'symmetric-encryption'
|
14
|
-
#
|
15
|
-
# # Initialize Mongoid in a standalone environment. In a Rails app this is not required
|
16
|
-
# Mongoid.logger = Logger.new($stdout)
|
17
|
-
# Mongoid.load!('config/mongoid.yml')
|
18
|
-
#
|
19
|
-
# # Initialize SymmetricEncryption in a standalone environment. In a Rails app this is not required
|
20
|
-
# SymmetricEncryption.load!('config/symmetric-encryption.yml', 'test')
|
21
|
-
#
|
22
|
-
# class Person
|
23
|
-
# include Mongoid::Document
|
24
|
-
#
|
25
|
-
# field :name, :type => String
|
26
|
-
# field :encrypted_social_security_number, :type => String, :encrypted => true
|
27
|
-
# field :age, :type => Integer
|
28
|
-
# field :encrypted_life_history, :type => String, :encrypted => true, :compress => true, :random_iv => true
|
29
|
-
# end
|
30
|
-
#
|
31
|
-
# The above document results in the following document in the Mongo collection 'persons':
|
32
|
-
# {
|
33
|
-
# "name" : "Joe",
|
34
|
-
# "encrypted_social_security_number" : "...",
|
35
|
-
# "age" : 21
|
36
|
-
# "encrypted_life_history" : "...",
|
37
|
-
# }
|
38
|
-
#
|
39
|
-
# Symmetric Encryption creates the getters and setters to be able to work with the field
|
40
|
-
# in it's unencrypted form. For example
|
41
|
-
#
|
42
|
-
# Example:
|
43
|
-
# person = Person.where(:encrypted_social_security_number => '...').first
|
44
|
-
#
|
45
|
-
# puts "Decrypted Social Security Number is: #{person.social_security_number}"
|
46
|
-
#
|
47
|
-
# # Or is the same as
|
48
|
-
# puts "Decrypted Social Security Number is: #{SymmetricEncryption.decrypt(person.encrypted_social_security_number)}"
|
49
|
-
#
|
50
|
-
# # Sets the encrypted_social_security_number to encrypted version
|
51
|
-
# person.social_security_number = "123456789"
|
52
|
-
#
|
53
|
-
# # Or, is equivalent to:
|
54
|
-
# person.encrypted_social_security_number = SymmetricEncryption.encrypt("123456789")
|
55
|
-
#
|
56
|
-
#
|
57
|
-
# Note: Unlike attr_encrypted finders must use the encrypted field name
|
58
|
-
# Invalid Example, does not work:
|
59
|
-
# person = Person.where(:social_security_number => '123456789').first
|
60
|
-
#
|
61
|
-
# Valid Example:
|
62
|
-
# person = Person.where(:encrypted_social_security_number => SymmetricEncryption.encrypt('123456789')).first
|
63
|
-
#
|
64
|
-
# Defines all the fields that are accessible on the Document
|
65
|
-
# For each field that is defined, a getter and setter will be
|
66
|
-
# added as an instance method to the Document.
|
67
|
-
#
|
68
|
-
# @example Define a field.
|
69
|
-
# field :social_security_number, :type => String, :encrypted => true, :compress => false, :random_iv => false
|
70
|
-
# field :sensitive_text, :type => String, :encrypted => true, :compress => true, :random_iv => true
|
71
|
-
#
|
72
|
-
# @param [ Symbol ] name The name of the field.
|
73
|
-
# @param [ Hash ] options The options to pass to the field.
|
74
|
-
#
|
75
|
-
# @option options [ Boolean ] :encrypted If the field contains encrypted data.
|
76
|
-
# @option options [ Symbol ] :decrypt_as Name of the getters and setters to generate to access the decrypted value of this field.
|
77
|
-
# @option options [ Boolean ] :compress Whether to compress this encrypted field
|
78
|
-
# @option options [ Boolean ] :random_iv Whether the encrypted value should use a random IV every time the field is encrypted.
|
79
|
-
#
|
80
|
-
# @option options [ Class ] :type The type of the field.
|
81
|
-
# @option options [ String ] :label The label for the field.
|
82
|
-
# @option options [ Object, Proc ] :default The fields default
|
83
|
-
#
|
84
|
-
# @return [ Field ] The generated field
|
85
|
-
def field_with_symmetric_encryption(field_name, options={})
|
86
|
-
if options.delete(:encrypted) == true
|
87
|
-
decrypt_as = options.delete(:decrypt_as)
|
88
|
-
unless decrypt_as
|
89
|
-
raise "SymmetricEncryption for Mongoid. When encryption is enabled for a field it must either start with 'encrypted_' or the option :decrypt must be supplied" unless field_name.to_s.start_with?('encrypted_')
|
90
|
-
decrypt_as = field_name.to_s['encrypted_'.length..-1]
|
91
|
-
end
|
92
|
-
|
93
|
-
random_iv = options.delete(:random_iv) || false
|
94
|
-
compress = options.delete(:compress) || false
|
95
|
-
|
96
|
-
# Store Intended data type for this field, but we store it as a String
|
97
|
-
underlying_type = options[:type]
|
98
|
-
options[:type] = String
|
99
|
-
|
100
|
-
raise "SymmetricEncryption for Mongoid currently only supports :type => String" unless underlying_type == String
|
101
|
-
|
102
|
-
# #TODO Need to do type conversions. Currently only supports String
|
103
|
-
|
104
|
-
# Generate getter and setter methods
|
105
|
-
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
106
|
-
# Set the un-encrypted field
|
107
|
-
# Also updates the encrypted field with the encrypted value
|
108
|
-
def #{decrypt_as}=(value)
|
109
|
-
@stored_#{field_name} = ::SymmetricEncryption.encrypt(value,#{random_iv},#{compress})
|
110
|
-
self.#{field_name} = @stored_#{field_name}
|
111
|
-
@#{decrypt_as} = value
|
112
|
-
end
|
113
|
-
|
114
|
-
# Returns the decrypted value for the encrypted field
|
115
|
-
# The decrypted value is cached and is only decrypted if the encrypted value has changed
|
116
|
-
# If this method is not called, then the encrypted value is never decrypted
|
117
|
-
def #{decrypt_as}
|
118
|
-
if @stored_#{field_name} != self.#{field_name}
|
119
|
-
@#{decrypt_as} = ::SymmetricEncryption.decrypt(self.#{field_name})
|
120
|
-
@stored_#{field_name} = self.#{field_name}
|
121
|
-
end
|
122
|
-
@#{decrypt_as}
|
123
|
-
end
|
124
|
-
EOS
|
125
|
-
end
|
126
|
-
|
127
|
-
# Pass on to the regular Mongoid field method
|
128
|
-
field_without_symmetric_encryption(field_name, options)
|
129
|
-
end
|
130
|
-
alias_method_chain :field, :symmetric_encryption
|
131
|
-
|
132
|
-
end
|
133
|
-
|
134
|
-
end
|
135
|
-
end
|