lockbox 0.4.8 → 0.4.9

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
  SHA256:
3
- metadata.gz: a560c020c3adf21952f81767ffc9b5b4586784f62d748f484e7bacbd4076a64a
4
- data.tar.gz: 59d05b405b4cd46da679ef4f03a53fae03cc78d7cdfe89bab13cd6981b76a4da
3
+ metadata.gz: 5ad5a754772ecb9d5f0a480cab88a63de9ed2fcfd973eef25f286fcf13da7694
4
+ data.tar.gz: d38646c9d1aedee2bf12419a24064fa5b01e4ef4cb619e8cb48903c343ec67b1
5
5
  SHA512:
6
- metadata.gz: 8d6217f47cc9c38ad8cf3db11b2a3a2936950b97f91ea168c5f2e4f8a1d9a5916c832286f08156869fbecf89d05dfc9bd7c4ecade9b9b4384488c936a292a1a6
7
- data.tar.gz: 3ddf36244c68b6b0bebad62801366d9827e6bee520717f1d544cfc6a18e798c644a158b68ac295fa87cef45ce5b922f37e89c5e39a5882ccb9fe512e725e778b
6
+ metadata.gz: 5f6e78e05cb6788ad8188314694846f70c438e3e43f48bdf1e8e6356ac94e64226a3790ebaab6369121d1083d551a7203281979731443cfdb1c611d52a617493
7
+ data.tar.gz: 30fc406d323dda8abdc0d5138880dc32b862abdd479e623180cf99c2531b466ef5a3be10620c975d0f2aee4b10e17b413cdc1cf21e03aa49ef5c6f0a7757cd82
@@ -1,3 +1,10 @@
1
+ ## 0.4.9 (2020-10-01)
2
+
3
+ - Added `key_table` and `key_attribute` options to `previous_versions`
4
+ - Added `encrypted_attribute` option
5
+ - Added support for encrypting empty string
6
+ - Improved `inspect` for models with encrypted attributes
7
+
1
8
  ## 0.4.8 (2020-08-30)
2
9
 
3
10
  - Added `key_table` and `key_attribute` options
data/README.md CHANGED
@@ -773,7 +773,9 @@ Lockbox supports a few different ways to set keys for database fields and files.
773
773
 
774
774
  ### Master Key
775
775
 
776
- By default, the master key is used to generate unique keys for each field/uploader. This technique comes from [CipherSweet](https://ciphersweet.paragonie.com/internals/key-hierarchy). The table name and column/uploader name are both used in this process. You can get an individual key with:
776
+ By default, the master key is used to generate unique keys for each field/uploader. This technique comes from [CipherSweet](https://ciphersweet.paragonie.com/internals/key-hierarchy). The table name and column/uploader name are both used in this process.
777
+
778
+ You can get an individual key with:
777
779
 
778
780
  ```ruby
779
781
  Lockbox.attribute_key(table: "users", attribute: "email_ciphertext")
@@ -820,10 +822,14 @@ To use a different key for each record, use a symbol:
820
822
  ```ruby
821
823
  class User < ApplicationRecord
822
824
  encrypts :email, key: :some_method
825
+ end
826
+ ```
823
827
 
824
- def some_method
825
- # code to get key
826
- end
828
+ Or a proc:
829
+
830
+ ```ruby
831
+ class User < ApplicationRecord
832
+ encrypts :email, key: -> { some_method }
827
833
  end
828
834
  ```
829
835
 
@@ -938,12 +944,6 @@ class User < ApplicationRecord
938
944
  end
939
945
  ```
940
946
 
941
- or set it globally:
942
-
943
- ```ruby
944
- Lockbox.default_options = {encode: false}
945
- ```
946
-
947
947
  ## Compatibility
948
948
 
949
949
  It’s easy to read encrypted data in another language if needed.
@@ -18,9 +18,10 @@ module Lockbox
18
18
  # In encryption mode, it must be set after calling #encrypt and setting #key= and #iv=
19
19
  cipher.auth_data = associated_data || ""
20
20
 
21
- ciphertext = cipher.update(message) + cipher.final
21
+ ciphertext = String.new
22
+ ciphertext << cipher.update(message) unless message.empty?
23
+ ciphertext << cipher.final
22
24
  ciphertext << cipher.auth_tag
23
-
24
25
  ciphertext
25
26
  end
26
27
 
@@ -29,7 +30,6 @@ module Lockbox
29
30
 
30
31
  fail_decryption if nonce.to_s.bytesize != nonce_bytes
31
32
  fail_decryption if auth_tag.to_s.bytesize != auth_tag_bytes
32
- fail_decryption if ciphertext.to_s.bytesize == 0
33
33
 
34
34
  cipher = OpenSSL::Cipher.new("aes-256-gcm")
35
35
  # do not change order of operations
@@ -43,7 +43,11 @@ module Lockbox
43
43
  cipher.auth_data = associated_data || ""
44
44
 
45
45
  begin
46
- cipher.update(ciphertext) + cipher.final
46
+ if ciphertext.to_s.empty?
47
+ cipher.final
48
+ else
49
+ cipher.update(ciphertext) + cipher.final
50
+ end
47
51
  rescue OpenSSL::Cipher::CipherError
48
52
  fail_decryption
49
53
  end
@@ -32,11 +32,15 @@ module Lockbox
32
32
 
33
33
  raise ArgumentError, "Cannot use key_attribute with multiple attributes" if options[:key_attribute] && attributes.size > 1
34
34
 
35
+ original_options = options.dup
36
+
35
37
  attributes.each do |name|
36
- # add default options
37
- encrypted_attribute = "#{name}_ciphertext"
38
+ # per attribute options
39
+ # TODO use a different name
40
+ options = original_options.dup
38
41
 
39
- options = options.dup
42
+ # add default options
43
+ encrypted_attribute = options.delete(:encrypted_attribute) || "#{name}_ciphertext"
40
44
 
41
45
  # migrating
42
46
  original_name = name.to_sym
@@ -82,6 +86,11 @@ module Lockbox
82
86
  serializable_hash.map do |k,v|
83
87
  "#{k}: #{respond_to?(:attribute_for_inspect) ? attribute_for_inspect(k) : v.inspect}"
84
88
  end
89
+
90
+ self.class.lockbox_attributes.map do |_, lockbox_attribute|
91
+ inspection << "#{lockbox_attribute[:attribute]}: [FILTERED]" if has_attribute?(lockbox_attribute[:encrypted_attribute])
92
+ end
93
+
85
94
  "#<#{self.class} #{inspection.join(", ")}>"
86
95
  end
87
96
 
@@ -169,6 +178,7 @@ module Lockbox
169
178
  end
170
179
 
171
180
  raise "Duplicate encrypted attribute: #{original_name}" if lockbox_attributes[original_name]
181
+ raise "Multiple encrypted attributes use the same column: #{encrypted_attribute}" if lockbox_attributes.any? { |_, v| v[:encrypted_attribute] == encrypted_attribute }
172
182
  @lockbox_attributes[original_name] = options
173
183
 
174
184
  if activerecord
@@ -29,7 +29,17 @@ module Lockbox
29
29
  options[:previous_versions] = options[:previous_versions].dup
30
30
  options[:previous_versions].each_with_index do |version, i|
31
31
  if !(version[:key] || version[:encryption_key] || version[:decryption_key]) && version[:master_key]
32
- options[:previous_versions][i] = version.merge(key: Lockbox.attribute_key(table: table, attribute: attribute, master_key: version.delete(:master_key), encode: false))
32
+ # could also use key_table and key_attribute from options
33
+ # when specified, but keep simple for now
34
+ # also, this change isn't backward compatible
35
+ key =
36
+ Lockbox.attribute_key(
37
+ table: version.delete(:key_table) || table,
38
+ attribute: version.delete(:key_attribute) || attribute,
39
+ master_key: version.delete(:master_key),
40
+ encode: false
41
+ )
42
+ options[:previous_versions][i] = version.merge(key: key)
33
43
  end
34
44
  end
35
45
  end
@@ -1,3 +1,3 @@
1
1
  module Lockbox
2
- VERSION = "0.4.8"
2
+ VERSION = "0.4.9"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lockbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.8
4
+ version: 0.4.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-31 00:00:00.000000000 Z
11
+ date: 2020-10-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler