strongbox 0.7.0 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/README.md +2 -0
- data/lib/strongbox.rb +13 -8
- data/lib/strongbox/lock.rb +21 -3
- data/test/method_key_test.rb +68 -0
- metadata +5 -17
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MGZhNGI2ODYzOWFjYTk3MTYyNDdjNjIzMDJmMzc4NDc2ZGMyMGEzOQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
Yzk0MDNlNWNjYzlmMjkyMDYwYjE2YjUwNjYzNWJhOGIxNzNkMWU4MQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
OTZlY2M1NmMwZjkzMjMyYTlmY2IzODc3MzM4NzIzMmYxYjllMjMxNTczZWYz
|
10
|
+
ZTc2ZDc0ZjQyNTVmZDQwYzE0NmIxOWE4Y2FmOTFlY2I4OTlmOWZhN2MyMjE5
|
11
|
+
ZGE2YTlhYTI0NGRmZDI3NzM3YjU0NTg0YWY1OGQyNTJlNzBmMjM=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ODZhNGYzZmJiMWNhNmVhMDU3MzdhNDVjNDI4MDgwMzE0OGI4YzRjZjEyYjQy
|
14
|
+
Njc5NzkwMjliZDNhY2JjY2NkYzQ4Yzc5MjA1ODcwZTM2Y2U2NDA4YWE4M2M5
|
15
|
+
ZjY0YzVjZDNiNzE2NzIyYjE2YzAyYzQwNGVmMmY5Yzg3ZmM0OWE=
|
data/README.md
CHANGED
@@ -126,6 +126,8 @@ Options to `encrypt_with_public_key` are:
|
|
126
126
|
|
127
127
|
* `:ensure_required_columns` - Make sure the required database column(s) exist. Defaults to `true`, set to `false` if you want to encrypt/decrypt data stored outside of the database.
|
128
128
|
|
129
|
+
* `:deferred_encryption` - Defer the encryption to happen before saving the object, instead of on the assignment of the encrypted attribute. Solves issues when using [dynamic keys](http://stuff-things.net/2012/04/18/dynamic-keys-for-strongbox/). Defaults to `false`.
|
130
|
+
|
129
131
|
For example, encrypting a small attribute, providing only the public
|
130
132
|
key for extra security, and Base64 encoding the encrypted data:
|
131
133
|
|
data/lib/strongbox.rb
CHANGED
@@ -5,7 +5,7 @@ require 'strongbox/lock'
|
|
5
5
|
|
6
6
|
module Strongbox
|
7
7
|
|
8
|
-
VERSION = "0.7.
|
8
|
+
VERSION = "0.7.1"
|
9
9
|
|
10
10
|
RSA_PKCS1_PADDING = OpenSSL::PKey::RSA::PKCS1_PADDING
|
11
11
|
RSA_SSLV23_PADDING = OpenSSL::PKey::RSA::SSLV23_PADDING
|
@@ -20,7 +20,8 @@ module Strongbox
|
|
20
20
|
:symmetric => :always,
|
21
21
|
:padding => RSA_PKCS1_PADDING,
|
22
22
|
:symmetric_cipher => 'aes-256-cbc',
|
23
|
-
:ensure_required_columns => true
|
23
|
+
:ensure_required_columns => true,
|
24
|
+
:deferred_encryption => false
|
24
25
|
}
|
25
26
|
end
|
26
27
|
|
@@ -50,20 +51,20 @@ module Strongbox
|
|
50
51
|
# Argument 0..-2 contains columns to be encrypted
|
51
52
|
def encrypt_with_public_key(*args)
|
52
53
|
include InstanceMethods
|
53
|
-
|
54
|
+
|
54
55
|
options = args.delete_at(-1) || {}
|
55
|
-
|
56
|
+
|
56
57
|
unless options.is_a?(Hash)
|
57
58
|
args.push(options)
|
58
59
|
options = {}
|
59
60
|
end
|
60
|
-
|
61
|
+
|
61
62
|
if args.one?
|
62
63
|
name = args.first
|
63
64
|
else
|
64
65
|
return args.each { |name| encrypt_with_public_key(name, options) }
|
65
66
|
end
|
66
|
-
|
67
|
+
|
67
68
|
if respond_to?(:class_attribute)
|
68
69
|
self.lock_options = {} if lock_options.nil?
|
69
70
|
else
|
@@ -77,9 +78,14 @@ module Strongbox
|
|
77
78
|
end
|
78
79
|
|
79
80
|
define_method "#{name}=" do | plaintext |
|
80
|
-
lock_for(name).
|
81
|
+
lock_for(name).content plaintext
|
81
82
|
end
|
82
83
|
|
84
|
+
if lock_options[name][:deferred_encryption]
|
85
|
+
before_save do
|
86
|
+
lock_for(name).encrypt!
|
87
|
+
end
|
88
|
+
end
|
83
89
|
end
|
84
90
|
end
|
85
91
|
|
@@ -94,4 +100,3 @@ end
|
|
94
100
|
if Object.const_defined?("ActiveRecord")
|
95
101
|
ActiveRecord::Base.send(:include, Strongbox)
|
96
102
|
end
|
97
|
-
|
data/lib/strongbox/lock.rb
CHANGED
@@ -21,6 +21,20 @@ module Strongbox
|
|
21
21
|
@symmetric_key = options[:symmetric_key] || "#{name}_key"
|
22
22
|
@symmetric_iv = options[:symmetric_iv] || "#{name}_iv"
|
23
23
|
@ensure_required_columns = options[:ensure_required_columns]
|
24
|
+
@deferred_encryption = options[:deferred_encryption]
|
25
|
+
end
|
26
|
+
|
27
|
+
def content plaintext
|
28
|
+
if @deferred_encryption
|
29
|
+
@raw_content = plaintext
|
30
|
+
else
|
31
|
+
encrypt plaintext
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def encrypt!
|
36
|
+
encrypt @raw_content
|
37
|
+
@raw_content = nil
|
24
38
|
end
|
25
39
|
|
26
40
|
def encrypt plaintext
|
@@ -61,11 +75,15 @@ module Strongbox
|
|
61
75
|
# OpenSSL::PKey::RSAError if the password is wrong.
|
62
76
|
|
63
77
|
def decrypt password = nil, ciphertext = nil
|
78
|
+
return @raw_content if @deferred_encryption && @raw_content
|
79
|
+
|
64
80
|
# Given a private key and a nil password OpenSSL::PKey::RSA.new() will
|
65
81
|
# *prompt* for a password, we default to an empty string to avoid that.
|
66
82
|
ciphertext ||= @instance[@name]
|
67
|
-
|
68
|
-
|
83
|
+
unless @deferred_encryption
|
84
|
+
return nil if ciphertext.nil?
|
85
|
+
return "" if ciphertext.empty?
|
86
|
+
end
|
69
87
|
|
70
88
|
return "*encrypted*" if password.nil?
|
71
89
|
unless @private_key
|
@@ -97,7 +115,7 @@ module Strongbox
|
|
97
115
|
end
|
98
116
|
|
99
117
|
def to_s
|
100
|
-
decrypt
|
118
|
+
@raw_content || decrypt
|
101
119
|
end
|
102
120
|
|
103
121
|
def to_json(options = nil)
|
data/test/method_key_test.rb
CHANGED
@@ -74,4 +74,72 @@ class MethodKeyTest < Test::Unit::TestCase
|
|
74
74
|
|
75
75
|
should_encypted_and_decrypt
|
76
76
|
end
|
77
|
+
|
78
|
+
context "With dynamic keys" do
|
79
|
+
setup do
|
80
|
+
ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
|
81
|
+
table.string :in_the_clear
|
82
|
+
table.binary :secret
|
83
|
+
table.binary :secret_key
|
84
|
+
table.binary :secret_iv
|
85
|
+
table.binary :segreto
|
86
|
+
|
87
|
+
table.string :key_pair
|
88
|
+
end
|
89
|
+
rebuild_class :public_key => :key_pair,
|
90
|
+
:private_key => :key_pair,
|
91
|
+
:deferred_encryption => true
|
92
|
+
|
93
|
+
Dummy.class_eval do
|
94
|
+
attr_accessor :password
|
95
|
+
|
96
|
+
def key_pair
|
97
|
+
unless self['key_pair']
|
98
|
+
raise if self.password.blank?
|
99
|
+
self['key_pair'] = generate_key_pair(self.password)
|
100
|
+
end
|
101
|
+
self['key_pair']
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
@password = 'letmein'
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'When just initialized' do
|
109
|
+
setup do
|
110
|
+
@dummy = Dummy.new
|
111
|
+
@dummy.secret = 'Shhhh'
|
112
|
+
@dummy.password = @password
|
113
|
+
end
|
114
|
+
|
115
|
+
should 'return secret when not yet locked' do
|
116
|
+
assert_equal 'Shhhh', @dummy.secret.decrypt
|
117
|
+
end
|
118
|
+
|
119
|
+
should 'return secret when unlocked' do
|
120
|
+
assert_equal 'Shhhh', @dummy.secret.decrypt(@password)
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'Then locked' do
|
124
|
+
setup do
|
125
|
+
@dummy.secret.encrypt!
|
126
|
+
end
|
127
|
+
should_encypted_and_decrypt
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'After saving the model, and then loading it from the database' do
|
132
|
+
setup do
|
133
|
+
Dummy.create!(:secret => 'Shhhh', :password => @password)
|
134
|
+
@dummy = Dummy.first
|
135
|
+
p 'XXXXXXXXXXXX'
|
136
|
+
end
|
137
|
+
|
138
|
+
should_encypted_and_decrypt
|
139
|
+
end
|
140
|
+
|
141
|
+
teardown do
|
142
|
+
rebuild_model
|
143
|
+
end
|
144
|
+
end
|
77
145
|
end
|
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: strongbox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
5
|
-
prerelease:
|
4
|
+
version: 0.7.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Spike Ilacqua
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2015-01-19 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: activerecord
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ! '>='
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ! '>='
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,7 +27,6 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: thoughtbot-shoulda
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ! '>='
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,7 +34,6 @@ dependencies:
|
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ! '>='
|
44
39
|
- !ruby/object:Gem::Version
|
@@ -46,7 +41,6 @@ dependencies:
|
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: sqlite3
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
45
|
- - ~>
|
52
46
|
- !ruby/object:Gem::Version
|
@@ -54,7 +48,6 @@ dependencies:
|
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
52
|
- - ~>
|
60
53
|
- !ruby/object:Gem::Version
|
@@ -62,7 +55,6 @@ dependencies:
|
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: rake
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
59
|
- - ! '>='
|
68
60
|
- !ruby/object:Gem::Version
|
@@ -70,7 +62,6 @@ dependencies:
|
|
70
62
|
type: :development
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
66
|
- - ! '>='
|
76
67
|
- !ruby/object:Gem::Version
|
@@ -78,7 +69,6 @@ dependencies:
|
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: rdoc
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
73
|
- - ! '>='
|
84
74
|
- !ruby/object:Gem::Version
|
@@ -86,7 +76,6 @@ dependencies:
|
|
86
76
|
type: :development
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
80
|
- - ! '>='
|
92
81
|
- !ruby/object:Gem::Version
|
@@ -128,27 +117,26 @@ files:
|
|
128
117
|
- test/validations_test.rb
|
129
118
|
homepage: http://stuff-things.net/strongbox
|
130
119
|
licenses: []
|
120
|
+
metadata: {}
|
131
121
|
post_install_message:
|
132
122
|
rdoc_options: []
|
133
123
|
require_paths:
|
134
124
|
- lib
|
135
125
|
required_ruby_version: !ruby/object:Gem::Requirement
|
136
|
-
none: false
|
137
126
|
requirements:
|
138
127
|
- - ! '>='
|
139
128
|
- !ruby/object:Gem::Version
|
140
129
|
version: '0'
|
141
130
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
|
-
none: false
|
143
131
|
requirements:
|
144
132
|
- - ! '>='
|
145
133
|
- !ruby/object:Gem::Version
|
146
134
|
version: '0'
|
147
135
|
requirements: []
|
148
136
|
rubyforge_project:
|
149
|
-
rubygems_version:
|
137
|
+
rubygems_version: 2.4.5
|
150
138
|
signing_key:
|
151
|
-
specification_version:
|
139
|
+
specification_version: 4
|
152
140
|
summary: Secures ActiveRecord fields with public key encryption.
|
153
141
|
test_files:
|
154
142
|
- test/database.yml
|