rjharmon-strongbox 0.3.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.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2009 Joseph A. Ilacqua, Jr
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,271 @@
1
+ h1. Strongbox
2
+
3
+ Strongbox provides Public Key Encryption for ActiveRecord. By using a public key
4
+ sensitive information can be encrypted and stored automatically. Once stored, the
5
+ private key and password are required to access the information.
6
+
7
+ Because the largest amount of data that can practically be encrypted with a 2048-bit
8
+ public key is 245 bytes, by default Strongbox uses a two layer approach. First it
9
+ encrypts the attribute using symmetric encryption with a randomly generated key and
10
+ initialization vector (IV) (which can just be thought of as a second key), then it
11
+ encrypts those with the public key.
12
+
13
+ Strongbox stores the encrypted attribute in a database column by the same name, i.e.
14
+ if you tell Strongbox to encrypt "secret" then it will be store in "secret" in the
15
+ database, just as the unencrypted attribute would have been. If symmetric encryption
16
+ is used (the default) two additional columns "secret_key" and "secret_iv" are needed
17
+ as well.
18
+
19
+ The attribute is automatically and immediately encrypted simply by setting it:
20
+
21
+ user.secret = "Shhhhhhh..."
22
+
23
+ and decrypted by calling the "decrypt" method with the private key password.
24
+
25
+ plain_text = user.secret.decrypt 'letmein'
26
+
27
+ The password for the private key can be empty if you are protecting the key through a
28
+ different method. In that case, provide the empty string '' to decrypt() in order to
29
+ decrypt the data.
30
+
31
+ This fork of Strongbox is also able to perform symmetric-only encryption. If you
32
+ do this, be sure that you're protecting the symmetric key. One application of this is
33
+ for encrypting data to a private password known by the user. See below for more options.
34
+
35
+ h2. Quick Start
36
+
37
+ In your model:
38
+
39
+ bc. class User < ActiveRecord::Base
40
+ encrypt_with_public_key :secret,
41
+ :key_pair => File.join(RAILS_ROOT,'config','keypair.pem')
42
+ end
43
+
44
+ In your migrations:
45
+
46
+ bc. class AddSecretColumnsToUser < ActiveRecord::Migration
47
+ def self.up
48
+ add_column :users, :secret, :binary
49
+ add_column :users, :secret_key, :binary
50
+ add_column :users, :secret_iv, :binary
51
+ end
52
+ def self.down
53
+ remove_column :users, :secret
54
+ remove_column :users, :secret_key
55
+ remove_column :users, :secret_iv
56
+ end
57
+ end
58
+
59
+ Generate a key pair:
60
+
61
+ (Choose a strong password.)
62
+
63
+ bc. openssl genrsa -des3 -out config/private.pem 2048
64
+ openssl rsa -in config/private.pem -out config/public.pem -outform PEM -pubout
65
+ cat config/private.pem config/public.pem >> config/keypair.pem
66
+
67
+ In your views and forms you don't need to do anything special to encrypt data. To
68
+ decrypt call:
69
+
70
+ bc. user.secret.decrypt 'password'
71
+
72
+ h2. Gem installation (Rails 2.1+)
73
+
74
+ In config/environment.rb:
75
+
76
+ bc. config.gem "strongbox"
77
+
78
+ h2. Usage
79
+
80
+ _encrypt_with_public_key_ sets up the attribute it's called on for automatic
81
+ encryption. It's simplest form is:
82
+
83
+ bc. class User < ActiveRecord::Base
84
+ encrypt_with_public_key :secret,
85
+ :key_pair => File.join(RAILS_ROOT,'config','keypair.pem')
86
+ end
87
+
88
+ Which will encrypt the attribute "secret". The attribute will be encrypted using
89
+ symmetric encryption with an automatically generated key and IV encrypted using the
90
+ public key. This requires three columns in the database "secret", "secret_key", and
91
+ "secret_iv" (see below).
92
+
93
+ Options to encrypt_with_public_key are:
94
+
95
+ :public_key - Path to the public key file. Overrides :keypair.
96
+
97
+ :private_key - Path to the private key file. Overrides :keypair.
98
+
99
+ :keypair - Path to a file containing both the public and private keys.
100
+
101
+ :symmetric :always/:never - Encrypt the date using symmetric encryption. The public
102
+ key is used to encrypt an automatically generated key and IV. This allows for large
103
+ amounts of data to be encrypted. The size of data that can be encrypted directly with
104
+ the public is limit to key size (in bytes) - 11. So a 2048 key can encrypt *245 bytes*. Defaults to :always
105
+
106
+ :symmetric_cipher - Cipher to use for symmetric encryption. Defaults to *'aes-256-cbc'*. Other ciphers support by OpenSSL may be used.
107
+
108
+ :base64 true/false - Use Base64 encoding to convert encrypted data to text. Use when
109
+ binary save data storage is not available. Defaults to *false*
110
+
111
+ :padding - Method used to pad data encrypted with the public key. Defaults to
112
+ RSA_PKCS1_PADDING. The default should be fine unless you are dealing with legacy
113
+ data.
114
+
115
+ :encrypt_iv true/false - Default is true for backward compatibility, but it is not
116
+ necessary to encrypt the initialization vector to maintain security. For first-time
117
+ installations, you might choose to set this to false, which cuts the encryption and
118
+ decryption overhead approximately in half. There is currently no method for
119
+ migrating encrypted iv's to clear-text iv's, but you could add a second set of columns
120
+ with a different configuration and write a script that decrypts values from one encrypted
121
+ column and stores them into to the second decrypted column.
122
+
123
+
124
+ For example, encrypting a small attribute, providing only the public key for extra
125
+ security, and Base64 encoding the encrypted data:
126
+
127
+ bc. class User < ActiveRecord::Base
128
+ validates_length_of :pin_code, :is => 4
129
+ encrypt_with_public_key :pin_code,
130
+ :symmetric => :never,
131
+ :base64 => true,
132
+ :public_key => File.join(RAILS_ROOT,'config','public.pem')
133
+ end
134
+
135
+ h2. Key Generation
136
+
137
+ Generate a key pair:
138
+
139
+ bc. openssl genrsa -des3 -out config/private.pem 2048
140
+ Generating RSA private key, 2048 bit long modulus
141
+ ......+++
142
+ .+++
143
+ e is 65537 (0x10001)
144
+ Enter pass phrase for config/private.pem:
145
+ Verifying - Enter pass phrase for config/private.pem:
146
+
147
+ and extract the the public key:
148
+
149
+ bc. openssl rsa -in config/private.pem -out config/public.pem -outform PEM -pubout
150
+ Enter pass phrase for config/private.pem:
151
+ writing RSA key
152
+
153
+ If you are going to leave the private key installed it's easiest to create a single
154
+ key pair file:
155
+
156
+ bc. cat config/private.pem config/public.pem >> config/keypair.pem
157
+
158
+ Or, for added security, store the private key file else where, leaving only the public key.
159
+
160
+ h2. Table Creation
161
+
162
+ In it's default configuration Strongbox requires three columns, one the encrypted
163
+ data, one for the encrypted symmetric key, and one for the encrypted symmetric IV. If
164
+ symmetric encryption is disabled then only the columns for the data being encrypted
165
+ is needed.
166
+
167
+ If your underlying database allows, use the *binary* column type. If you must store
168
+ your data in text format be sure to enable Base64 encoding and to use the *text*
169
+ column type. If you use a _string_ column and encrypt anything greater than 186
170
+ bytes (245 bytes if you don't enable Base64 encoding) *your data will be lost*.
171
+
172
+ h2. Validation
173
+
174
+ Because Strongbox immediately encrypts the data as you assign it into the model,
175
+ the amount of validation that can be done is minimal, being limited to
176
+ validates_size_of and validates_presence_of.
177
+
178
+ If you require additional validation for your encrypted columns, this should be done
179
+ before assigning into encrypted attributes. That, or you might want to contribute a
180
+ patch that delays the encryption step until right before save.
181
+
182
+ h2. Symmetric Encryption
183
+
184
+ h3. Background
185
+
186
+ Asymmetric encryption is generally far preferred over symmetric-only encryption.
187
+ Being able to physically separate and protect the private decryption key from the
188
+ public encryption key creates a level of potential security unmatchable with
189
+ symmetric encryption, which is reversible using the single encryption key.
190
+
191
+ However, symmetric keys can be useful in certain circumstances - for example the
192
+ combined symmetric/asymmetric encryption provided by default with
193
+ _encrypt_with_public_key_. Other advanced examples include:
194
+
195
+ * Encrypt data to a PIN code known only to the user (retrieve it only when they re-type their PIN)
196
+
197
+ * Encrypt a PIN code with public key, then use the PIN to symmetrically encrypt other data, so
198
+ that it can be retrieved directly by the user but not by an attacker. Combined with pubkey
199
+ encryption for the same data, much flexibility is gained with a minimum of risk exposure - though
200
+ it comes with a tradeoff: increased code complexity.
201
+
202
+ h3. Implementing Symmetric Encryption
203
+
204
+ If you don't understand the caveats above, please re-read them. Then, if you are
205
+ prepared to do symmetric encryption, use _encrypt_with_symmetric_key_:
206
+
207
+ bc. class User < ActiveRecord::Base
208
+ validates_length_of :pin_code, :is => 4
209
+ encrypt_with_symmetric_key :some_data, :encrypt_iv => false, :key_proc => :pin_key
210
+ attr_accessor :pin_key
211
+ end
212
+
213
+ All options are the same as for pubkey encryption, except that no keys may be specified.
214
+ Additionally, :encrypt_iv must be set to false, and the :key_proc must be specified as a
215
+ symbol referring to a function which will return the symmetric key.
216
+
217
+ h3. Implementing the symmetric-key function
218
+
219
+ Two examples should demonstrate the use of a function that returns symmetric keys. They
220
+ correspond to the two use cases mentioned above.
221
+
222
+ Encrypting with a key not stored on the server: This is easily implemented by creating
223
+ an attr_accessor on the model having the encrypted field.
224
+
225
+ bc. class User < ActiveRecord::Base
226
+ encrypt_with_symmetric_key :some_data, :encrypt_iv => false, :key_proc => :pin_key
227
+ attr_accessor :pin_key
228
+ end
229
+
230
+ In your controller, put the key into the model prior to storing or retrieving encrypted data.
231
+
232
+ In the second example, we store the user's PIN, encrypted asymmetrically. To encrypt
233
+ data to the PIN code, we go inside the security perimeter where we have the private key;
234
+ decrypt the PIN, then set it, possibly using the attr_accessor method, prior to encrypting
235
+ the symmetric data.
236
+
237
+ Decryption for user-facing content is done the same way as in the first example.
238
+
239
+ Another method of implementing the :key_proc is as follows:
240
+
241
+ bc. attr_writer :pin_key
242
+ def pin_key
243
+ @pin_key || self.pin.decrypt('password')
244
+ end
245
+
246
+ h2. Security Caveats
247
+
248
+ If you don't encrypt your data, then an attacker only needs to steal that data to get
249
+ your secrets.
250
+
251
+ If encrypt your data using symmetric encrypts and a stored key, then the attacker
252
+ needs the data and the key stored on the server.
253
+
254
+ If you use public key encryption, the attacker needs the data, the private key, and
255
+ the password. This means the attacker has to sniff the password somehow, so that's
256
+ what you need to protect against.
257
+
258
+ h2. Authors
259
+
260
+ Spike Ilacqua
261
+
262
+ h2. Contributors
263
+
264
+ Randy Harmon
265
+
266
+ h2. Thanks
267
+
268
+ Strongbox's implementation drew inspiration from Thoughtbot's Paperclip gem
269
+ http://www.thoughtbot.com/projects/paperclip
270
+
271
+
data/Rakefile ADDED
@@ -0,0 +1,43 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ $LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
6
+ require 'strongbox'
7
+
8
+ desc 'Default: run tests.'
9
+ task :default => :test
10
+
11
+ desc 'Test the strongbox gem.'
12
+ Rake::TestTask.new(:test) do |t|
13
+ t.libs << 'lib' << 'profile'
14
+ t.pattern = 'test/**/*_test.rb'
15
+ t.verbose = true
16
+ end
17
+
18
+ desc 'Generate documentation for the strongbox gem.'
19
+ Rake::RDocTask.new(:rdoc) do |rdoc|
20
+ rdoc.rdoc_dir = 'doc'
21
+ rdoc.title = 'Strongbox'
22
+ rdoc.options << '--line-numbers' << '--inline-source'
23
+ rdoc.rdoc_files.include('README*')
24
+ rdoc.rdoc_files.include('lib/**/*.rb')
25
+ end
26
+
27
+ spec = Gem::Specification.new do |s|
28
+ s.name = "strongbox"
29
+ s.version = Strongbox::VERSION
30
+ s.summary = "Secures ActiveRecord fields with public key encryption."
31
+ s.authors = ["Spike Ilacqua"]
32
+ s.email = "spike@stuff-things.net"
33
+ s.homepage = "http://stuff-things.net/strongbox"
34
+ s.files = FileList["[A-Z]*", "init.rb", "{lib,rails}/**/*"]
35
+ s.add_development_dependency 'thoughtbot-shoulda'
36
+ end
37
+
38
+ desc "Generate a gemspec file for GitHub"
39
+ task :gemspec do
40
+ File.open("#{spec.name}.gemspec", 'w') do |f|
41
+ f.write spec.to_yaml
42
+ end
43
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'strongbox'
@@ -0,0 +1,190 @@
1
+ module Strongbox
2
+ # The Lock class encrypts and decrypts the protected attribute. It
3
+ # automatically encrypts the data when set and decrypts it when the private
4
+ # key password is provided.
5
+ class Lock
6
+
7
+ def initialize name, instance, options = {}
8
+ @name = name
9
+ @instance = instance
10
+
11
+ @size = nil
12
+
13
+ options = Strongbox.options.merge(options)
14
+
15
+ @is_empty = true if @instance[@name].blank?
16
+
17
+ @base64 = options[:base64]
18
+ @public_key = options[:public_key] || options[:key_pair]
19
+ @private_key = options[:private_key] || options[:key_pair]
20
+ @padding = options[:padding]
21
+ @symmetric = options[:symmetric]
22
+ @symmetric_cipher = options[:symmetric_cipher]
23
+ @symmetric_key = options[:symmetric_key] || "#{name}_key"
24
+ @symmetric_iv = options[:symmetric_iv] || "#{name}_iv"
25
+ @key_proc = options[:key_proc]
26
+ @encrypt_iv = options[:encrypt_iv]
27
+ if @symmetric == :only
28
+ if @encrypt_iv
29
+ raise ArgumentError, ":encrypt_iv should be set to false for :symmetric => :only encryption, since encrypting the iv requires a pubkey"
30
+ end
31
+ if @public_key
32
+ raise ArgumentError, ":public_key, :private_key and :key_pair are not used with :symmetric => :only"
33
+ end
34
+ unless @key_proc
35
+ raise ArgumentError, ":key_proc option is required. This option specifies a proc or a symbol of a method on the instance, which will return a key used for the symmetric cypher."
36
+ end
37
+ else
38
+ if @key_proc
39
+ raise ArgumentError, ":key_proc is valid only when :symmetric => :only is specified, or when using encrypt_with_symmetric_key()"
40
+ end
41
+ end
42
+ end
43
+
44
+ def encrypt plaintext
45
+
46
+ unless @public_key or @symmetric == :only
47
+ raise StrongboxError.new("#{@instance.class} model does not have public key_file")
48
+ end
49
+ if !plaintext.blank?
50
+ @is_empty = false
51
+ @size = plaintext.size # For validations
52
+ # Using a blank password in OpenSSL::PKey::RSA.new prevents reading
53
+ # the private key if the file is a key pair
54
+ public_key = get_rsa_key(@public_key,"")
55
+ if @symmetric == :always or @symmetric == :only
56
+ cipher = OpenSSL::Cipher::Cipher.new(@symmetric_cipher)
57
+ cipher.encrypt
58
+
59
+ cipher.key = symmetric_key = case @key_proc
60
+ when Proc
61
+ @key_proc.call( @instance )
62
+ when Symbol
63
+ @instance.send( @key_proc )
64
+ else
65
+ cipher.random_key
66
+ end
67
+ cipher.iv = symmetric_iv = cipher.random_iv
68
+
69
+ ciphertext = cipher.update(plaintext)
70
+ ciphertext << cipher.final
71
+ unless @symmetric == :only
72
+ encrypted_key = public_key.public_encrypt(symmetric_key,@padding)
73
+ end
74
+ if @encrypt_iv
75
+ encrypted_iv = public_key.public_encrypt(symmetric_iv,@padding)
76
+ end
77
+ if @base64
78
+ unless @symmetric == :only
79
+ encrypted_key = Base64.encode64(encrypted_key)
80
+ end
81
+ encrypted_iv = Base64.encode64(encrypted_iv)
82
+ end
83
+ unless @symmetric == :only
84
+ @instance[@symmetric_key] = encrypted_key
85
+ end
86
+ if @encrypt_iv
87
+ @instance[@symmetric_iv] = encrypted_iv
88
+ else
89
+ @instance[@symmetric_iv] = symmetric_iv
90
+ end
91
+ else
92
+ ciphertext = public_key.public_encrypt(plaintext,@padding)
93
+ end
94
+ ciphertext = Base64.encode64(ciphertext) if @base64
95
+ @instance[@name] = ciphertext
96
+ else
97
+ @size = 0
98
+ @instance[@name] = ""
99
+ @is_empty = true
100
+ end
101
+ end
102
+
103
+ # Given the private key password decrypts the attribute. Will raise
104
+ # OpenSSL::PKey::RSAError if the password is wrong.
105
+
106
+ def decrypt password = nil
107
+ return "" if @is_empty
108
+ # Given a private key and a nil password OpenSSL::PKey::RSA.new() will
109
+ # *prompt* for a password, we default to an empty string to avoid that.
110
+ ciphertext = @instance[@name]
111
+ return nil if ciphertext.nil?
112
+ return "" if ciphertext.empty?
113
+
114
+ return "*encrypted*" if password.nil? and ! @key_proc
115
+ unless @private_key or @symmetric == :only
116
+ raise StrongboxError.new("#{@instance.class} model does not have private key_file")
117
+ end
118
+
119
+ if ciphertext
120
+ ciphertext = Base64.decode64(ciphertext) if @base64
121
+ private_key = get_rsa_key(@private_key,password)
122
+
123
+ if @symmetric == :always || @symmetric == :only
124
+ symmetric_key = case @key_proc
125
+ when Proc
126
+ @key_proc.call( @instance )
127
+ when Symbol
128
+ @instance.send( @key_proc )
129
+ else
130
+ @instance[@symmetric_key]
131
+ end
132
+ symmetric_iv = @instance[@symmetric_iv]
133
+
134
+ if @base64
135
+ if @symmetric == :always
136
+ symmetric_key = Base64.decode64(symmetric_key)
137
+ end
138
+ symmetric_iv = Base64.decode64(symmetric_iv)
139
+ end
140
+ cipher = OpenSSL::Cipher::Cipher.new(@symmetric_cipher)
141
+ cipher.decrypt
142
+ cipher.key = if @symmetric == :only
143
+ symmetric_key
144
+ else
145
+ private_key.private_decrypt(symmetric_key,@padding)
146
+ end
147
+ if @encrypt_iv
148
+ cipher.iv = private_key.private_decrypt(symmetric_iv,@padding)
149
+ else
150
+ cipher.iv = symmetric_iv
151
+ end
152
+
153
+ plaintext = cipher.update(ciphertext)
154
+ plaintext << cipher.final
155
+ else
156
+ plaintext = private_key.private_decrypt(ciphertext,@padding)
157
+ end
158
+ else
159
+ nil
160
+ end
161
+ end
162
+
163
+ def to_s
164
+ decrypt
165
+ end
166
+
167
+ # Needed for validations
168
+ def blank?
169
+ @instance[@name].blank?
170
+ end
171
+
172
+ def nil?
173
+ @instance[@name].nil?
174
+ end
175
+
176
+ def size
177
+ @size
178
+ end
179
+
180
+ private
181
+ def get_rsa_key(key,password = '')
182
+ return nil unless key
183
+ return key if key.is_a?(OpenSSL::PKey::RSA)
184
+ if key !~ /^-----BEGIN RSA/
185
+ key = File.read(key)
186
+ end
187
+ return OpenSSL::PKey::RSA.new(key,password)
188
+ end
189
+ end
190
+ end
data/lib/strongbox.rb ADDED
@@ -0,0 +1,85 @@
1
+ require 'openssl'
2
+ require 'base64'
3
+
4
+ require 'strongbox/lock'
5
+
6
+ module Strongbox
7
+
8
+ VERSION = "0.3.0"
9
+
10
+ RSA_PKCS1_PADDING = OpenSSL::PKey::RSA::PKCS1_PADDING
11
+ RSA_SSLV23_PADDING = OpenSSL::PKey::RSA::SSLV23_PADDING
12
+ RSA_NO_PADDING = OpenSSL::PKey::RSA::NO_PADDING
13
+ RSA_PKCS1_OAEP_PADDING = OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING
14
+
15
+ class << self
16
+ # Provides for setting the default options for Strongbox
17
+ def options
18
+ @options ||= {
19
+ :base64 => false,
20
+ :symmetric => :always,
21
+ :padding => RSA_PKCS1_PADDING,
22
+ :encrypt_iv => true,
23
+ :symmetric_cipher => 'aes-256-cbc'
24
+ }
25
+ end
26
+
27
+ def included base #:nodoc:
28
+ base.extend ClassMethods
29
+ end
30
+ end
31
+
32
+ class StrongboxError < StandardError #:nodoc:
33
+ end
34
+
35
+ module ClassMethods
36
+ # +encrypt_with_public_key+ gives the class it is called on an attribute that
37
+ # when assigned is automatically encrypted using a public key. This allows the
38
+ # unattended encryption of data, without exposing the information need to decrypt
39
+ # it (as would be the case when using symmetric key encryption alone). Small
40
+ # amounts of data may be encrypted directly with the public key. Larger data is
41
+ # encrypted using symmetric encryption. The encrypted data is stored in the
42
+ # database column of the same name as the attibute. If symmetric encryption is
43
+ # used (the default) additional column are need to store the generated password
44
+ # and IV.
45
+ def encrypt_with_public_key(name, options = {})
46
+ strongbox_encryption( name, options )
47
+ end
48
+
49
+ def encrypt_with_symmetric_key( name, options = {})
50
+ options.merge!( :symmetric => :only )
51
+ strongbox_encryption( name, options )
52
+ end
53
+
54
+ def strongbox_encryption( name, options )
55
+ include InstanceMethods
56
+
57
+ class_inheritable_reader :lock_options
58
+ write_inheritable_attribute(:lock_options, {}) if lock_options.nil?
59
+
60
+
61
+ lock_options[name] = options.symbolize_keys.reverse_merge Strongbox.options
62
+
63
+ define_method name do
64
+ lock_for(name)
65
+ end
66
+
67
+ define_method "#{name}=" do | plaintext |
68
+ lock_for(name).encrypt plaintext
69
+ end
70
+
71
+ end
72
+ end
73
+
74
+ module InstanceMethods
75
+ def lock_for name
76
+ @_locks ||= {}
77
+ @_locks[name] ||= Lock.new(name, self, self.class.lock_options[name])
78
+ end
79
+ end
80
+ end
81
+
82
+ if Object.const_defined?("ActiveRecord")
83
+ ActiveRecord::Base.send(:include, Strongbox)
84
+ end
85
+
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__),'../init.rb')
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rjharmon-strongbox
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Spike Ilacqua
8
+ - Randy Harmon
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2009-12-13 23:00:00 -08:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: thoughtbot-shoulda
18
+ type: :development
19
+ version_requirement:
20
+ version_requirements: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: "0"
25
+ version:
26
+ description:
27
+ email: r_j_h_box-sf@yahoo.com
28
+ executables: []
29
+
30
+ extensions: []
31
+
32
+ extra_rdoc_files: []
33
+
34
+ files:
35
+ - LICENSE
36
+ - Rakefile
37
+ - README.textile
38
+ - init.rb
39
+ - lib/strongbox/lock.rb
40
+ - lib/strongbox.rb
41
+ - rails/init.rb
42
+ has_rdoc: true
43
+ homepage: http://stuff-things.net/strongbox
44
+ licenses: []
45
+
46
+ post_install_message:
47
+ rdoc_options: []
48
+
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.3.5
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: Secures ActiveRecord fields with public key encryption.
70
+ test_files: []
71
+