symmetric-encryption 2.0.2 → 2.2.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.
- 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
|