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 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.0"
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).encrypt plaintext
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
-
@@ -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
- return nil if ciphertext.nil?
68
- return "" if ciphertext.empty?
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)
@@ -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.0
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: 2013-02-14 00:00:00.000000000 Z
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: 1.8.24
137
+ rubygems_version: 2.4.5
150
138
  signing_key:
151
- specification_version: 3
139
+ specification_version: 4
152
140
  summary: Secures ActiveRecord fields with public key encryption.
153
141
  test_files:
154
142
  - test/database.yml