attr_encrypted 1.4.0 → 3.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8be516fee846217b6cc95a706bc87bbc267f7d71
4
- data.tar.gz: f72d166a492c0efc4a7fd2a84b863fb3b4ea8d5a
3
+ metadata.gz: 5c1a2bcf5e2b7fc8937e96cb0fcd99926bd98d1e
4
+ data.tar.gz: 40112aef07bda5ba8145b2fb634a9bdbfea34d7a
5
5
  SHA512:
6
- metadata.gz: ed046ac7c9e40406f871e00e3e95821002605b62022d556b8ac5dcc5a7ce9f06e38925b6a1849e1dfb3ee7a4666ce2a2e15e1130f20f53eb246017fcb362dbd3
7
- data.tar.gz: c27e6b6c8b4644a8daf02c4fc50f607878dac6a3a86e71181e28f3a78c71da5b7abed88094b61ac6fa9a558a08934d572b5a7169830c93592deabfd79c285512
6
+ metadata.gz: cbb4fb1d4fa7e22f791139ab1b9a96324cbb8e07f7e8472561a3dd0ce1fcb0a7c048c0ba413b5bccb876dade09f9528ccc7d23caa4378de3da8ef2c540ba76ad
7
+ data.tar.gz: ef6b487235f2f92ccdf73de3c806b3b3f9161c2ebcd78b2102e1975edc3150cda28a7b458136a051100e939a271b2e92ca690cd38360ec5c43c9c33db22dc1f4
checksums.yaml.gz.sig ADDED
Binary file
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ .bundle
2
+ .DS_Store
3
+ .ruby-version
4
+ pkg
5
+ Gemfile.lock
6
+ coverage
data/.travis.yml ADDED
@@ -0,0 +1,31 @@
1
+ sudo: false
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.0
6
+ - 2.1
7
+ - 2.2.2
8
+ - 2.3.0
9
+ - rbx
10
+ env:
11
+ - ACTIVERECORD=3.0.0
12
+ - ACTIVERECORD=3.1.0
13
+ - ACTIVERECORD=3.2.0
14
+ - ACTIVERECORD=4.0.0
15
+ - ACTIVERECORD=4.1.0
16
+ - ACTIVERECORD=4.2.0
17
+ - ACTIVERECORD=5.0.0
18
+ matrix:
19
+ exclude:
20
+ - rvm: 2.0
21
+ env: ACTIVERECORD=5.0.0
22
+ - rvm: 2.1
23
+ env: ACTIVERECORD=5.0.0
24
+ - rvm: rbx
25
+ env: ACTIVERECORD=5.0.0
26
+ allow_failures:
27
+ - rvm: rbx
28
+ fast_finish: true
29
+ addons:
30
+ code_climate:
31
+ repo_token: a90435ed4954dd6e9f3697a20c5bc3754f67d94703f870e8fc7b00f69f5b2d06
data/CHANGELOG.md ADDED
@@ -0,0 +1,87 @@
1
+ # attr_encrypted #
2
+
3
+ ## 3.0.3 ##
4
+ * Fixed: attr_was would decrypt the attribute upon every call. This is inefficient and introduces problems when the options change between decrypting an old value and encrypting a new value; for example, when rotating the encryption key. As such, the new approach caches the decrypted value of the old encrypted value such that the old options are no longer needed. (@johnny-lai) (@saghaulor)
5
+
6
+ ## 3.0.2 ##
7
+ * Changed: Removed alias_method_chain for compatibility with Rails v5.x (@grosser)
8
+ * Changed: Updated Travis build matrix to include Rails 5. (@saghaulor) (@connorshea)
9
+ * Changed: Removed `.silence_stream` from tests as it has been removed from Rails 5. (@sblackstone)
10
+
11
+ ## 3.0.1 ##
12
+ * Fixed: attr_was method no longer calls undefined methods. (@saghaulor)
13
+
14
+ ## 3.0.0 ##
15
+ * Changed: Updated gemspec to use Encryptor v3.0.0. (@saghaulor)
16
+ * Changed: Updated README with instructions related to moving from v2.0.0 to v3.0.0. (@saghaulor)
17
+ * Fixed: ActiveModel::Dirty methods in the ActiveRecord adapter. (@saghaulor)
18
+
19
+ ## 2.0.0 ##
20
+ * Added: Now using Encryptor v2.0.0 (@saghaulor)
21
+ * Added: Options are copied to the instance. (@saghaulor)
22
+ * Added: Operation option is set during encryption/decryption to allow options to be evaluated in the context of the current operation. (@saghaulor)
23
+ * Added: IV and salt can be conditionally encoded. (@saghaulor)
24
+ * Added: Changelog! (@saghaulor)
25
+ * Changed: attr_encrypted no longer extends object, to use with PORO extend your class, all supported ORMs are already extended. (@saghaulor)
26
+ * Changed: Salt is now generated with more entropy. (@saghaulor)
27
+ * Changed: The default algorithm is now `aes-256-gcm`. (@saghaulor)
28
+ * Changed: The default mode is now `:per_attribute_iv`' (@saghaulor)
29
+ * Changed: Extracted class level default options hash to a private method. (@saghaulor)
30
+ * Changed: Dynamic finders only work with `:single_iv_and_salt` mode. (@saghaulor)
31
+ * Changed: Updated documentation to include v2.0.0 changes and 'things to consider' section. (@saghaulor)
32
+ * Fixed: All options are evaluated correctly. (@saghaulor)
33
+ * Fixed: IV is generated for every encryption operation. (@saghaulor)
34
+ * Deprecated: `:single_iv_and_salt` and `:per_attribute_iv_and_salt` modes are deprecated and will be removed in the next major release. (@saghaulor)
35
+ * Deprecated: Dynamic finders via `method_missing` is deprecated and will be removed in the next major release. (@saghaulor)
36
+ * Removed: Support for Ruby < 2.x (@saghaulor)
37
+ * Removed: Support for Rails < 3.x (@saghaulor)
38
+ * Removed: Unnecessary use of `alias_method` from ActiveRecord adapter. (@saghaulor)
39
+
40
+ ## 1.4.0 ##
41
+ * Added: ActiveModel::Dirty#attribute_was (@saghaulor)
42
+ * Added: ActiveModel::Dirty#attribute_changed? (@mwean)
43
+
44
+ ## 1.3.5 ##
45
+ * Changed: Fixed gemspec to explicitly depend on Encryptor v1.3.0 (@saghaulor)
46
+ * Fixed: Evaluate `:mode` option as a symbol or proc. (@cheynewallace)
47
+
48
+ ## 1.3.4 ##
49
+ * Added: ActiveRecord::Base.reload support. (@rcook)
50
+ * Fixed: ActiveRecord adapter no longer forces attribute hashes to be string-keyed. (@tamird)
51
+ * Fixed: Mass assignment protection in ActiveRecord 4. (@tamird)
52
+ * Changed: Now using rubygems over https. (@tamird)
53
+ * Changed: Let ActiveRecord define attribute methods. (@saghaulor)
54
+
55
+ ## 1.3.3 ##
56
+ * Added: Alias attr_encryptor and attr_encrpted. (@Billy Monk)
57
+
58
+ ## 1.3.2 ##
59
+ * Fixed: Bug regarding strong parameters. (@S. Brent Faulkner)
60
+ * Fixed: Bug regarding loading per instance IV and salt. (@S. Brent Faulkner)
61
+ * Fixed: Bug regarding assigning nil. (@S. Brent Faulkner)
62
+ * Added: Support for protected attributes. (@S. Brent Faulkner)
63
+ * Added: Support for ActiveRecord 4. (@S. Brent Faulkner)
64
+
65
+ ## 1.3.1 ##
66
+ * Added: Support for Rails 2.3.x and 3.1.x. (@S. Brent Faulkner)
67
+
68
+ ## 1.3.0 ##
69
+ * Fixed: Serialization bug. (@Billy Monk)
70
+ * Added: Support for :per_attribute_iv_and_salt mode. (@rcook)
71
+ * Fixed: Added dependencies to gemspec. (@jmazzi)
72
+
73
+ ## 1.2.1 ##
74
+ * Added: Force encoding when not marshaling. (@mosaicxm)
75
+ * Fixed: Issue specifying multiple attributes on the same line. (@austintaylor)
76
+ * Added: Typecasting to String before encryption (@shuber)
77
+ * Added: `"#{attribute}?"` method. (@shuber)
78
+
79
+ ## 1.2.0 ##
80
+ * Changed: General code refactoring (@shuber)
81
+
82
+ ## 1.1.2 ##
83
+ * No significant changes
84
+
85
+ ## 1.1.1 ##
86
+ * Changled: Updated README. (@shuber)
87
+ * Added: `before_type_cast` alias to ActiveRecord adapter. (@shuber)
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,444 @@
1
+ # attr_encrypted
2
+ [![Build Status](https://secure.travis-ci.org/attr-encrypted/attr_encrypted.svg)](https://travis-ci.org/attr-encrypted/attr_encrypted) [![Test Coverage](https://codeclimate.com/github/attr-encrypted/attr_encrypted/badges/coverage.svg)](https://codeclimate.com/github/attr-encrypted/attr_encrypted/coverage) [![Code Climate](https://codeclimate.com/github/attr-encrypted/attr_encrypted/badges/gpa.svg)](https://codeclimate.com/github/attr-encrypted/attr_encrypted) [![Gem Version](https://badge.fury.io/rb/attr_encrypted.svg)](https://badge.fury.io/rb/attr_encrypted) [![security](https://hakiri.io/github/attr-encrypted/attr_encrypted/master.svg)](https://hakiri.io/github/attr-encrypted/attr_encrypted/master)
3
+
4
+ Generates attr_accessors that transparently encrypt and decrypt attributes.
5
+
6
+ It works with ANY class, however, you get a few extra features when you're using it with `ActiveRecord`, `DataMapper`, or `Sequel`.
7
+
8
+
9
+ ## Installation
10
+
11
+ Add attr_encrypted to your gemfile:
12
+
13
+ ```ruby
14
+ gem "attr_encrypted", "~> 3.0.0"
15
+ ```
16
+
17
+ Then install the gem:
18
+
19
+ ```bash
20
+ bundle install
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ If you're using an ORM like `ActiveRecord`, `DataMapper`, or `Sequel`, using attr_encrypted is easy:
26
+
27
+ ```ruby
28
+ class User
29
+ attr_encrypted :ssn, key: 'This is a key that is 256 bits!!'
30
+ end
31
+ ```
32
+
33
+ If you're using a PORO, you have to do a little bit more work by extending the class:
34
+
35
+ ```ruby
36
+ class User
37
+ extend AttrEncrypted
38
+ attr_accessor :name
39
+ attr_encrypted :ssn, key: 'This is a key that is 256 bits!!'
40
+
41
+ def load
42
+ # loads the stored data
43
+ end
44
+
45
+ def save
46
+ # saves the :name and :encrypted_ssn attributes somewhere (e.g. filesystem, database, etc)
47
+ end
48
+ end
49
+
50
+ user = User.new
51
+ user.ssn = '123-45-6789'
52
+ user.ssn # returns the unencrypted object ie. '123-45-6789'
53
+ user.encrypted_ssn # returns the encrypted version of :ssn
54
+ user.save
55
+
56
+ user = User.load
57
+ user.ssn # decrypts :encrypted_ssn and returns '123-45-6789'
58
+ ```
59
+
60
+ ### Encrypt/decrypt attribute class methods
61
+
62
+ Two class methods are available for each attribute: `User.encrypt_email` and `User.decrypt_email`. They accept as arguments the same options that the `attr_encrypted` class method accepts. For example:
63
+
64
+ ```ruby
65
+ key = SecureRandom.random_bytes(32)
66
+ iv = SecureRandom.random_bytes(12)
67
+ encrypted_email = User.encrypt_email('test@test.com', iv: iv, key: key)
68
+ email = User.decrypt_email(encrypted_email, iv: iv, key: key)
69
+ ```
70
+
71
+ The `attr_encrypted` class method is also aliased as `attr_encryptor` to conform to Ruby's `attr_` naming conventions. I should have called this project `attr_encryptor` but it was too late when I realized it ='(.
72
+
73
+ ### attr_encrypted with database persistence
74
+
75
+ By default, `attr_encrypted` uses the `:per_attribute_iv` encryption mode. This mode requires a column to store your cipher text and a column to store your IV.
76
+
77
+ Create or modify the table that your model uses to add a column with the `encrypted_` prefix (which can be modified, see below), e.g. `encrypted_ssn` via a migration like the following:
78
+
79
+ ```ruby
80
+ create_table :users do |t|
81
+ t.string :name
82
+ t.string :encrypted_ssn
83
+ t.string :encrypted_ssn_iv
84
+ t.timestamps
85
+ end
86
+ ```
87
+
88
+ You can use a string or binary column type. (See the encode option section below for more info)
89
+
90
+ ### Specifying the encrypted attribute name
91
+
92
+ By default, the encrypted attribute name is `encrypted_#{attribute}` (e.g. `attr_encrypted :email` would create an attribute named `encrypted_email`). So, if you're storing the encrypted attribute in the database, you need to make sure the `encrypted_#{attribute}` field exists in your table. You have a couple of options if you want to name your attribute or db column something else, see below for more details.
93
+
94
+
95
+ ## attr_encrypted options
96
+
97
+ #### Options are evaluated
98
+ All options will be evaluated at the instance level. If you pass in a symbol it will be passed as a message to the instance of your class. If you pass a proc or any object that responds to `:call` it will be called. You can pass in the instance of your class as an argument to the proc. Anything else will be returned. For example:
99
+
100
+ ##### Symbols representing instance methods
101
+
102
+ Here is an example class that uses an instance method to determines the encryption key to use.
103
+
104
+ ```ruby
105
+ class User
106
+ attr_encrypted :email, key: :encryption_key
107
+
108
+ def encryption_key
109
+ # does some fancy logic and returns an encryption key
110
+ end
111
+ end
112
+ ```
113
+
114
+
115
+ ##### Procs
116
+
117
+ Here is an example of passing a proc/lambda object as the `:key` option as well:
118
+
119
+ ```ruby
120
+ class User
121
+ attr_encrypted :email, key: proc { |user| user.key }
122
+ end
123
+ ```
124
+
125
+
126
+ ### Default options
127
+
128
+ The following are the default options used by `attr_encrypted`:
129
+
130
+ ```ruby
131
+ prefix: 'encrypted_',
132
+ suffix: '',
133
+ if: true,
134
+ unless: false,
135
+ encode: false,
136
+ encode_iv: true,
137
+ encode_salt: true,
138
+ default_encoding: 'm',
139
+ marshal: false,
140
+ marshaler: Marshal,
141
+ dump_method: 'dump',
142
+ load_method: 'load',
143
+ encryptor: Encryptor,
144
+ encrypt_method: 'encrypt',
145
+ decrypt_method: 'decrypt',
146
+ mode: :per_attribute_iv,
147
+ algorithm: 'aes-256-gcm',
148
+ ```
149
+
150
+ All of the aforementioned options are explained in depth below.
151
+
152
+ Additionally, you can specify default options for all encrypted attributes in your class. Instead of having to define your class like this:
153
+
154
+ ```ruby
155
+ class User
156
+ attr_encrypted :email, key: 'This is a key that is 256 bits!!', prefix: '', suffix: '_crypted'
157
+ attr_encrypted :ssn, key: 'a different secret key', prefix: '', suffix: '_crypted'
158
+ attr_encrypted :credit_card, key: 'another secret key', prefix: '', suffix: '_crypted'
159
+ end
160
+ ```
161
+
162
+ You can simply define some default options like so:
163
+
164
+ ```ruby
165
+ class User
166
+ attr_encrypted_options.merge!(prefix: '', :suffix => '_crypted')
167
+ attr_encrypted :email, key: 'This is a key that is 256 bits!!'
168
+ attr_encrypted :ssn, key: 'a different secret key'
169
+ attr_encrypted :credit_card, key: 'another secret key'
170
+ end
171
+ ```
172
+
173
+ This should help keep your classes clean and DRY.
174
+
175
+ ### The `:attribute` option
176
+
177
+ You can simply pass the name of the encrypted attribute as the `:attribute` option:
178
+
179
+ ```ruby
180
+ class User
181
+ attr_encrypted :email, key: 'This is a key that is 256 bits!!', attribute: 'email_encrypted'
182
+ end
183
+ ```
184
+
185
+ This would generate an attribute named `email_encrypted`
186
+
187
+
188
+ ### The `:prefix` and `:suffix` options
189
+
190
+ If you don't like the `encrypted_#{attribute}` naming convention then you can specify your own:
191
+
192
+ ```ruby
193
+ class User
194
+ attr_encrypted :email, key: 'This is a key that is 256 bits!!', prefix: 'secret_', suffix: '_crypted'
195
+ end
196
+ ```
197
+
198
+ This would generate the following attributes: `secret_email_crypted`, `secret_credit_card_crypted`, and `secret_ssn_crypted`.
199
+
200
+
201
+ ### The `:key` option
202
+
203
+ The `:key` option is used to pass in a data encryption key to be used with whatever encryption class you use. If you're using `Encryptor`, the key must meet minimum length requirements respective to the algorithm that you use; aes-256 requires a 256 bit key, etc. The `:key` option is not required (see custom encryptor below).
204
+
205
+
206
+ ##### Unique keys for each attribute
207
+
208
+ You can specify unique keys for each attribute if you'd like:
209
+
210
+ ```ruby
211
+ class User
212
+ attr_encrypted :email, key: 'This is a key that is 256 bits!!'
213
+ attr_encrypted :ssn, key: 'a different secret key'
214
+ end
215
+ ```
216
+
217
+ It is recommended to use a symbol or a proc for the key and to store information regarding what key was used to encrypt your data. (See below for more details.)
218
+
219
+
220
+ ### The `:if` and `:unless` options
221
+
222
+ There may be times that you want to only encrypt when certain conditions are met. For example maybe you're using rails and you don't want to encrypt attributes when you're in development mode. You can specify conditions like this:
223
+
224
+ ```ruby
225
+ class User < ActiveRecord::Base
226
+ attr_encrypted :email, key: 'This is a key that is 256 bits!!', unless: Rails.env.development?
227
+ attr_encrypted :ssn, key: 'This is a key that is 256 bits!!', if: Rails.env.development?
228
+ end
229
+ ```
230
+
231
+ You can specify both `:if` and `:unless` options.
232
+
233
+
234
+ ### The `:encryptor`, `:encrypt_method`, and `:decrypt_method` options
235
+
236
+ The `Encryptor` class is used by default. You may use your own custom encryptor by specifying the `:encryptor`, `:encrypt_method`, and `:decrypt_method` options.
237
+
238
+ Lets suppose you'd like to use this custom encryptor class:
239
+
240
+ ```ruby
241
+ class SillyEncryptor
242
+ def self.silly_encrypt(options)
243
+ (options[:value] + options[:secret_key]).reverse
244
+ end
245
+
246
+ def self.silly_decrypt(options)
247
+ options[:value].reverse.gsub(/#{options[:secret_key]}$/, '')
248
+ end
249
+ end
250
+ ```
251
+
252
+ Simply set up your class like so:
253
+
254
+ ```ruby
255
+ class User
256
+ attr_encrypted :email, secret_key: 'This is a key that is 256 bits!!', encryptor: SillyEncryptor, encrypt_method: :silly_encrypt, decrypt_method: :silly_decrypt
257
+ end
258
+ ```
259
+
260
+ Any options that you pass to `attr_encrypted` will be passed to the encryptor class along with the `:value` option which contains the string to encrypt/decrypt. Notice that the above example uses `:secret_key` instead of `:key`. See [encryptor](https://github.com/attr-encrypted/encryptor) for more info regarding the default encryptor class.
261
+
262
+
263
+ ### The `:mode` option
264
+
265
+ The mode options allows you to specify in what mode your data will be encrypted. There are currently three modes: `:per_attribute_iv`, `:per_attribute_iv_and_salt`, and `:single_iv_and_salt`.
266
+
267
+ __NOTE: `:per_attribute_iv_and_salt` and `:single_iv_and_salt` modes are deprecated and will be removed in the next major release.__
268
+
269
+
270
+ ### The `:algorithm` option
271
+
272
+ The default `Encryptor` class uses the standard ruby OpenSSL library. Its default algorithm is `aes-256-gcm`. You can modify this by passing the `:algorithm` option to the `attr_encrypted` call like so:
273
+
274
+ ```ruby
275
+ class User
276
+ attr_encrypted :email, key: 'This is a key that is 256 bits!!', algorithm: 'aes-256-cbc'
277
+ end
278
+ ```
279
+
280
+ To view a list of all cipher algorithms that are supported on your platform, run the following code in your favorite Ruby REPL:
281
+
282
+ ```ruby
283
+ require 'openssl'
284
+ puts OpenSSL::Cipher.ciphers
285
+ ```
286
+ See [Encryptor](https://github.com/attr-encrypted/encryptor#algorithms) for more information.
287
+
288
+
289
+ ### The `:encode`, `:encode_iv`, `:encode_salt`, and `:default_encoding` options
290
+
291
+ You're probably going to be storing your encrypted attributes somehow (e.g. filesystem, database, etc). You can simply pass the `:encode` option to automatically encode/decode when encrypting/decrypting. The default behavior assumes that you're using a string column type and will base64 encode your cipher text. If you choose to use the binary column type then encoding is not required, but be sure to pass in `false` with the `:encode` option.
292
+
293
+ ```ruby
294
+ class User
295
+ attr_encrypted :email, key: 'some secret key', encode: true, encode_iv: true, encode_salt: true
296
+ end
297
+ ```
298
+
299
+ The default encoding is `m` (base64). You can change this by setting `encode: 'some encoding'`. See [`Arrary#pack`](http://ruby-doc.org/core-2.3.0/Array.html#method-i-pack) for more encoding options.
300
+
301
+
302
+ ### The `:marshal`, `:dump_method`, and `:load_method` options
303
+
304
+ You may want to encrypt objects other than strings (e.g. hashes, arrays, etc). If this is the case, simply pass the `:marshal` option to automatically marshal when encrypting/decrypting.
305
+
306
+ ```ruby
307
+ class User
308
+ attr_encrypted :credentials, key: 'some secret key', marshal: true
309
+ end
310
+ ```
311
+
312
+ You may also optionally specify `:marshaler`, `:dump_method`, and `:load_method` if you want to use something other than the default `Marshal` object.
313
+
314
+
315
+ ## ORMs
316
+
317
+ ### ActiveRecord
318
+
319
+ If you're using this gem with `ActiveRecord`, you get a few extra features:
320
+
321
+ #### Default options
322
+
323
+ The `:encode` option is set to true by default.
324
+
325
+ #### Dynamic `find_by_` and `scoped_by_` methods
326
+
327
+ Let's say you'd like to encrypt your user's email addresses, but you also need a way for them to login. Simply set up your class like so:
328
+
329
+ ```ruby
330
+ class User < ActiveRecord::Base
331
+ attr_encrypted :email, key: 'This is a key that is 256 bits!!'
332
+ attr_encrypted :password, key: 'some other secret key'
333
+ end
334
+ ```
335
+
336
+ You can now lookup and login users like so:
337
+
338
+ ```ruby
339
+ User.find_by_email_and_password('test@example.com', 'testing')
340
+ ```
341
+
342
+ The call to `find_by_email_and_password` is intercepted and modified to `find_by_encrypted_email_and_encrypted_password('ENCRYPTED EMAIL', 'ENCRYPTED PASSWORD')`. The dynamic scope methods like `scoped_by_email_and_password` work the same way.
343
+
344
+ NOTE: This only works if all records are encrypted with the same encryption key (per attribute).
345
+
346
+ __NOTE: This feature is deprecated and will be removed in the next major release.__
347
+
348
+
349
+ ### DataMapper and Sequel
350
+
351
+ #### Default options
352
+
353
+ The `:encode` option is set to true by default.
354
+
355
+
356
+ ## Deprecations
357
+
358
+ attr_encrypted v2.0.0 now depends on encryptor v2.0.0. As part of both major releases many insecure defaults and behaviors have been deprecated. The new default behavior is as follows:
359
+
360
+ * Default `:mode` is now `:per_attribute_iv`, the default `:mode` in attr_encrypted v1.x was `:single_iv_and_salt`.
361
+ * Default `:algorithm` is now 'aes-256-gcm', the default `:algorithm` in attr_encrypted v1.x was 'aes-256-cbc'.
362
+ * The encryption key provided must be of appropriate length respective to the algorithm used. Previously, encryptor did not verify minimum key length.
363
+ * The dynamic finders available in ActiveRecord will only work with `:single_iv_and_salt` mode. It is strongly advised that you do not use this mode. If you can search the encrypted data, it wasn't encrypted securely. This functionality will be deprecated in the next major release.
364
+ * `:per_attribute_iv_and_salt` and `:single_iv_and_salt` modes are deprecated and will be removed in the next major release.
365
+
366
+ Backwards compatibility is supported by providing a special option that is passed to encryptor, namely, `:insecure_mode`:
367
+
368
+ ```ruby
369
+ class User
370
+ attr_encrypted :email, key: 'a secret key', algorithm: 'aes-256-cbc', mode: :single_iv_and_salt, insecure_mode: true
371
+ end
372
+ ```
373
+
374
+ The `:insecure_mode` option will allow encryptor to ignore the new security requirements. It is strongly advised that if you use this older insecure behavior that you migrate to the newer more secure behavior.
375
+
376
+
377
+ ## Upgrading from attr_encrypted v1.x to v3.x
378
+
379
+ Modify your gemfile to include the new version of attr_encrypted:
380
+
381
+ ```ruby
382
+ gem attr_encrypted, "~> 3.0.0"
383
+ ```
384
+
385
+ The update attr_encrypted:
386
+
387
+ ```bash
388
+ bundle update attr_encrypted
389
+ ```
390
+
391
+ Then modify your models using attr\_encrypted to account for the changes in default options. Specifically, pass in the `:mode` and `:algorithm` options that you were using if you had not previously done so. If your key is insufficient length relative to the algorithm that you use, you should also pass in `insecure_mode: true`; this will prevent Encryptor from raising an exception regarding insufficient key length. Please see the Deprecations sections for more details including an example of how to specify your model with default options from attr_encrypted v1.x.
392
+
393
+ ## Upgrading from attr_encrypted v2.x to v3.x
394
+
395
+ A bug was discovered in Encryptor v2.0.0 that inccorectly set the IV when using an AES-\*-GCM algorithm. Unfornately fixing this major security issue results in the inability to decrypt records encrypted using an AES-*-GCM algorithm from Encryptor v2.0.0. Please see [Upgrading to Encryptor v3.0.0](https://github.com/attr-encrypted/encryptor#upgrading-from-v200-to-v300) for more info.
396
+
397
+ It is strongly advised that you re-encrypt your data encrypted with Encryptor v2.0.0. However, you'll have to take special care to re-encrypt. To decrypt data encrypted with Encryptor v2.0.0 using an AES-\*-GCM algorithm you can use the `:v2_gcm_iv` option.
398
+
399
+ It is recommended that you implement a strategy to insure that you do not mix the encryption implementations of Encryptor. One way to do this is to re-encrypt everything while your application is offline.Another way is to add a column that keeps track of what implementation was used. The path that you choose will depend on your situtation. Below is an example of how you might go about re-encrypting your data.
400
+
401
+ ```ruby
402
+ class User
403
+ attr_encrypted :ssn, key: :encryption_key, v2_gcm_iv: :is_decrypting?(:ssn)
404
+
405
+ def is_decrypting?(attribute)
406
+ encrypted_attributes[attribute][:operation] == :decrypting
407
+ end
408
+ end
409
+
410
+ User.all.each do |user|
411
+ old_ssn = user.ssn
412
+ user.ssn= old_ssn
413
+ user.save
414
+ end
415
+ ```
416
+
417
+ ## Things to consider before using attr_encrypted
418
+
419
+ #### Searching, joining, etc
420
+ While choosing to encrypt at the attribute level is the most secure solution, it is not without drawbacks. Namely, you cannot search the encrypted data, and because you can't search it, you can't index it either. You also can't use joins on the encrypted data. Data that is securely encrypted is effectively noise. So any operations that rely on the data not being noise will not work. If you need to do any of the aforementioned operations, please consider using database and file system encryption along with transport encryption as it moves through your stack.
421
+
422
+ #### Data leaks
423
+ Please also consider where your data leaks. If you're using attr_encrypted with Rails, it's highly likely that this data will enter your app as a request parameter. You'll want to be sure that you're filtering your request params from you logs or else your data is sitting in the clear in your logs. [Parameter Filtering in Rails](http://apidock.com/rails/ActionDispatch/Http/FilterParameters) Please also consider other possible leak points.
424
+
425
+ #### Storage requirements
426
+ When storing your encrypted data, please consider the length requirements of the db column that you're storing the cipher text in. Older versions of Mysql attempt to 'help' you by truncating strings that are too large for the column. When this happens, you will not be able to decrypt your data. [MySQL Strict Trans](http://www.davidpashley.com/2009/02/15/silently-truncated/)
427
+
428
+ #### Metadata regarding your crypto implementation
429
+ It is advisable to also store metadata regarding the circumstances of your encrypted data. Namely, you should store information about the key used to encrypt your data, as well as the algorithm. Having this metadata with every record will make key rotation and migrating to a new algorithm signficantly easier. It will allow you to continue to decrypt old data using the information provided in the metadata and new data can be encrypted using your new key and algorithm of choice.
430
+
431
+ #### Enforcing the IV as a nonce
432
+ On a related note, most alorithms require that your IV be unique for every record and key combination. You can enforce this using composite unique indexes on your IV and encryption key name/id column. [RFC 5084](https://tools.ietf.org/html/rfc5084#section-1.5)
433
+
434
+ #### Unique key per record
435
+ Lastly, while the `:per_attribute_iv_and_salt` mode is more secure than `:per_attribute_iv` mode because it uses a unique key per record, it uses a PBKDF function which introduces a huge performance hit (175x slower by my benchmarks). There are other ways of deriving a unique key per record that would be much faster.
436
+
437
+ ## Note on Patches/Pull Requests
438
+
439
+ * Fork the project.
440
+ * Make your feature addition or bug fix.
441
+ * Add tests for it. This is important so I don't break it in a
442
+ future version unintentionally.
443
+ * Commit, do not mess with rakefile, version, changelog, or history.
444
+ * Send me a pull request. Bonus points for topic branches.
data/Rakefile CHANGED
@@ -1,6 +1,5 @@
1
- require 'rake'
2
1
  require 'rake/testtask'
3
- require 'rake/rdoctask'
2
+ require 'rdoc/task'
4
3
  require "bundler/gem_tasks"
5
4
 
6
5
  desc 'Test the attr_encrypted gem.'
@@ -19,16 +18,5 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
19
18
  rdoc.rdoc_files.include('lib/**/*.rb')
20
19
  end
21
20
 
22
- if RUBY_VERSION < '1.9.3'
23
- require 'rcov/rcovtask'
24
-
25
- task :rcov do
26
- sh "rcov -o coverage/rcov --exclude '^(?!lib)' " + FileList[ 'test/**/*_test.rb' ].join(' ')
27
- end
28
-
29
- desc 'Default: run unit tests under rcov.'
30
- task :default => :rcov
31
- else
32
- desc 'Default: run unit tests.'
33
- task :default => :test
34
- end
21
+ desc 'Default: run unit tests.'
22
+ task :default => :test
@@ -0,0 +1,63 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ lib = File.expand_path('../lib/', __FILE__)
4
+ $:.unshift lib unless $:.include?(lib)
5
+
6
+ require 'attr_encrypted/version'
7
+ require 'date'
8
+
9
+ Gem::Specification.new do |s|
10
+ s.name = 'attr_encrypted'
11
+ s.version = AttrEncrypted::Version.string
12
+ s.date = Date.today
13
+
14
+ s.summary = 'Encrypt and decrypt attributes'
15
+ s.description = 'Generates attr_accessors that encrypt and decrypt attributes transparently'
16
+
17
+ s.authors = ['Sean Huber', 'S. Brent Faulkner', 'William Monk', 'Stephen Aghaulor']
18
+ s.email = ['seah@shuber.io', 'sbfaulkner@gmail.com', 'billy.monk@gmail.com', 'saghaulor@gmail.com']
19
+ s.homepage = 'http://github.com/attr-encrypted/attr_encrypted'
20
+
21
+ s.has_rdoc = false
22
+ s.rdoc_options = ['--line-numbers', '--inline-source', '--main', 'README.rdoc']
23
+
24
+ s.require_paths = ['lib']
25
+
26
+ s.files = `git ls-files`.split("\n")
27
+ s.test_files = `git ls-files -- test/*`.split("\n")
28
+
29
+ s.required_ruby_version = '>= 2.0.0'
30
+
31
+ s.add_dependency('encryptor', ['~> 3.0.0'])
32
+ # support for testing with specific active record version
33
+ activerecord_version = if ENV.key?('ACTIVERECORD')
34
+ "~> #{ENV['ACTIVERECORD']}"
35
+ else
36
+ '>= 2.0.0'
37
+ end
38
+ s.add_development_dependency('activerecord', activerecord_version)
39
+ s.add_development_dependency('actionpack', activerecord_version)
40
+ s.add_development_dependency('datamapper')
41
+ s.add_development_dependency('rake')
42
+ s.add_development_dependency('minitest')
43
+ s.add_development_dependency('sequel')
44
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE.to_sym == :jruby
45
+ s.add_development_dependency('activerecord-jdbcsqlite3-adapter')
46
+ s.add_development_dependency('jdbc-sqlite3', '< 3.8.7') # 3.8.7 is nice and broke
47
+ else
48
+ s.add_development_dependency('sqlite3')
49
+ end
50
+ s.add_development_dependency('dm-sqlite-adapter')
51
+ s.add_development_dependency('simplecov')
52
+ s.add_development_dependency('simplecov-rcov')
53
+ s.add_development_dependency("codeclimate-test-reporter")
54
+
55
+ s.cert_chain = ['certs/saghaulor.pem']
56
+ s.signing_key = File.expand_path("~/.ssh/gem-private_key.pem") if $0 =~ /gem\z/
57
+
58
+ s.post_install_message = "\n\n\nWARNING: Several insecure default options and features were deprecated in attr_encrypted v2.0.0.\n
59
+ Additionally, there was a bug in Encryptor v2.0.0 that insecurely encrypted data when using an AES-*-GCM algorithm.\n
60
+ This bug was fixed but introduced breaking changes between v2.x and v3.x.\n
61
+ Please see the README for more information regarding upgrading to attr_encrypted v3.0.0.\n\n\n"
62
+
63
+ end