lockbox 0.4.8 → 0.4.9
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +10 -10
- data/lib/lockbox/aes_gcm.rb +8 -4
- data/lib/lockbox/model.rb +13 -3
- data/lib/lockbox/utils.rb +11 -1
- data/lib/lockbox/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5ad5a754772ecb9d5f0a480cab88a63de9ed2fcfd973eef25f286fcf13da7694
|
4
|
+
data.tar.gz: d38646c9d1aedee2bf12419a24064fa5b01e4ef4cb619e8cb48903c343ec67b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5f6e78e05cb6788ad8188314694846f70c438e3e43f48bdf1e8e6356ac94e64226a3790ebaab6369121d1083d551a7203281979731443cfdb1c611d52a617493
|
7
|
+
data.tar.gz: 30fc406d323dda8abdc0d5138880dc32b862abdd479e623180cf99c2531b466ef5a3be10620c975d0f2aee4b10e17b413cdc1cf21e03aa49ef5c6f0a7757cd82
|
data/CHANGELOG.md
CHANGED
@@ -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.
|
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
|
-
|
825
|
-
|
826
|
-
|
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.
|
data/lib/lockbox/aes_gcm.rb
CHANGED
@@ -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 =
|
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
|
-
|
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
|
data/lib/lockbox/model.rb
CHANGED
@@ -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
|
-
#
|
37
|
-
|
38
|
+
# per attribute options
|
39
|
+
# TODO use a different name
|
40
|
+
options = original_options.dup
|
38
41
|
|
39
|
-
|
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
|
data/lib/lockbox/utils.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/lockbox/version.rb
CHANGED
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.
|
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-
|
11
|
+
date: 2020-10-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|