blind_index 0.3.0 → 0.3.2
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 +10 -0
- data/LICENSE.txt +1 -1
- data/README.md +26 -7
- data/Rakefile +42 -14
- data/lib/blind_index.rb +15 -6
- data/lib/blind_index/extensions.rb +10 -0
- data/lib/blind_index/model.rb +18 -7
- data/lib/blind_index/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: fe8410b6e972d6fe7aa37648396462b1e2a70358813e97db153d62ed5ac3fbad
|
4
|
+
data.tar.gz: 37d9baa7fb293ee2aa6e0a9fb5d253f8d0c7a83807dade72a8ac532825dc0220
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c647598d872e02b829377d5436442f0d929575722ee3330396c773d4dea556aabf74083e4868923fb597478df5648487fbfa26361eb6a341b1709dea3bb2e137
|
7
|
+
data.tar.gz: 1a9c501115e25cecf73e59ccb7ee5b23c96ccb01c81e4a62e48c1858546cf67a9c83f4f482cbf212ca2f38de559bbb668c39bf90a131ede9732eb4e390f45d3b
|
data/CHANGELOG.md
CHANGED
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -42,7 +42,7 @@ class User < ApplicationRecord
|
|
42
42
|
end
|
43
43
|
```
|
44
44
|
|
45
|
-
We use environment variables to store the keys ([dotenv](https://github.com/bkeepers/dotenv) is great for this). *Do not commit them to source control.* Generate one key for encryption and one key for hashing. You can generate keys in the Rails console with:
|
45
|
+
We use environment variables to store the keys as hex-encoded strings ([dotenv](https://github.com/bkeepers/dotenv) is great for this). *Do not commit them to source control.* Generate one key for encryption and one key for hashing. You can generate keys in the Rails console with:
|
46
46
|
|
47
47
|
```ruby
|
48
48
|
SecureRandom.hex(32)
|
@@ -143,11 +143,8 @@ end
|
|
143
143
|
|
144
144
|
The default is `10000`. Changing this value requires you to recompute the blind index.
|
145
145
|
|
146
|
-
|
147
146
|
### scrypt
|
148
147
|
|
149
|
-
:warning: *Not production ready yet*
|
150
|
-
|
151
148
|
Add [scrypt](https://github.com/pbhogan/scrypt) to your Gemfile and use:
|
152
149
|
|
153
150
|
```ruby
|
@@ -156,9 +153,15 @@ class User < ApplicationRecord
|
|
156
153
|
end
|
157
154
|
```
|
158
155
|
|
159
|
-
|
156
|
+
Set the cost parameters with:
|
160
157
|
|
161
|
-
|
158
|
+
```ruby
|
159
|
+
class User < ApplicationRecord
|
160
|
+
blind_index :email, algorithm: :scrypt, cost: {n: 4096, r: 8, p: 1}, ...
|
161
|
+
end
|
162
|
+
```
|
163
|
+
|
164
|
+
### Argon2
|
162
165
|
|
163
166
|
Add [argon2](https://github.com/technion/ruby-argon2) to your Gemfile and use:
|
164
167
|
|
@@ -168,6 +171,14 @@ class User < ApplicationRecord
|
|
168
171
|
end
|
169
172
|
```
|
170
173
|
|
174
|
+
Set the cost parameters with:
|
175
|
+
|
176
|
+
```ruby
|
177
|
+
class User < ApplicationRecord
|
178
|
+
blind_index :email, algorithm: :argon2, cost: {t: 3, m: 12}, ...
|
179
|
+
end
|
180
|
+
```
|
181
|
+
|
171
182
|
## Reference
|
172
183
|
|
173
184
|
By default, blind indexes are encoded in Base64. Set a different encoding with:
|
@@ -194,7 +205,15 @@ We recommend rotating your key if it doesn’t meet this criteria. You can gener
|
|
194
205
|
SecureRandom.hex(32)
|
195
206
|
```
|
196
207
|
|
197
|
-
|
208
|
+
Update your model to convert the hex key to binary.
|
209
|
+
|
210
|
+
```ruby
|
211
|
+
class User < ApplicationRecord
|
212
|
+
blind_index :email, key: [ENV["EMAIL_BLIND_INDEX_KEY"]].pack("H*")
|
213
|
+
end
|
214
|
+
```
|
215
|
+
|
216
|
+
And recompute the blind index.
|
198
217
|
|
199
218
|
```ruby
|
200
219
|
User.find_each do |user|
|
data/Rakefile
CHANGED
@@ -10,19 +10,47 @@ end
|
|
10
10
|
|
11
11
|
task default: :test
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
13
|
+
namespace :benchmark do
|
14
|
+
task :algorithms do
|
15
|
+
require "securerandom"
|
16
|
+
require "benchmark/ips"
|
17
|
+
require "blind_index"
|
18
|
+
require "scrypt"
|
19
|
+
require "argon2"
|
20
|
+
|
21
|
+
key = SecureRandom.random_bytes(32)
|
22
|
+
value = "secret"
|
23
|
+
|
24
|
+
Benchmark.ips do |x|
|
25
|
+
x.report("pbkdf2_hmac") { BlindIndex.generate_bidx(value, key: key, algorithm: :pbkdf2_hmac) }
|
26
|
+
x.report("scrypt") { BlindIndex.generate_bidx(value, key: key, algorithm: :scrypt) }
|
27
|
+
x.report("argon2") { BlindIndex.generate_bidx(value, key: key, algorithm: :argon2) }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
task :queries do
|
32
|
+
require "benchmark/ips"
|
33
|
+
require "active_record"
|
34
|
+
require "blind_index"
|
35
|
+
|
36
|
+
ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
|
37
|
+
|
38
|
+
ActiveRecord::Migration.create_table :users do
|
39
|
+
end
|
40
|
+
|
41
|
+
ActiveRecord::Migration.create_table :cities do
|
42
|
+
end
|
43
|
+
|
44
|
+
class User < ActiveRecord::Base
|
45
|
+
blind_index :email
|
46
|
+
end
|
47
|
+
|
48
|
+
class City < ActiveRecord::Base
|
49
|
+
end
|
50
|
+
|
51
|
+
Benchmark.ips do |x|
|
52
|
+
x.report("no index") { City.where(id: 1).first }
|
53
|
+
x.report("index") { User.where(id: 1).first }
|
54
|
+
end
|
27
55
|
end
|
28
56
|
end
|
data/lib/blind_index.rb
CHANGED
@@ -15,7 +15,8 @@ module BlindIndex
|
|
15
15
|
iterations: 10000,
|
16
16
|
algorithm: :pbkdf2_hmac,
|
17
17
|
insecure_key: false,
|
18
|
-
encode: true
|
18
|
+
encode: true,
|
19
|
+
cost: {}
|
19
20
|
}
|
20
21
|
|
21
22
|
def self.generate_bidx(value, key:, **options)
|
@@ -39,16 +40,22 @@ module BlindIndex
|
|
39
40
|
|
40
41
|
# gist to compare algorithm results
|
41
42
|
# https://gist.github.com/ankane/fe3ac63fbf1c4550ee12554c664d2b8c
|
43
|
+
cost_options = options[:cost]
|
44
|
+
|
42
45
|
value =
|
43
46
|
case algorithm
|
44
47
|
when :scrypt
|
45
|
-
|
46
|
-
|
48
|
+
n = cost_options[:n] || 4096
|
49
|
+
r = cost_options[:r] || 8
|
50
|
+
cp = cost_options[:p] || 1
|
51
|
+
SCrypt::Engine.scrypt(value.to_s, key, n, r, cp, 32)
|
47
52
|
when :argon2
|
48
|
-
|
49
|
-
[
|
53
|
+
t = cost_options[:t] || 3
|
54
|
+
m = cost_options[:m] || 12
|
55
|
+
[Argon2::Engine.hash_argon2i(value.to_s, key, t, m)].pack("H*")
|
50
56
|
when :pbkdf2_hmac
|
51
|
-
|
57
|
+
iterations = cost_options[:iterations] || options[:iterations]
|
58
|
+
OpenSSL::PKCS5.pbkdf2_hmac(value.to_s, key, iterations, 32, "sha256")
|
52
59
|
else
|
53
60
|
raise BlindIndex::Error, "Unknown algorithm"
|
54
61
|
end
|
@@ -77,6 +84,8 @@ ActiveSupport.on_load(:active_record) do
|
|
77
84
|
ActiveRecord::PredicateBuilder.singleton_class.prepend(BlindIndex::Extensions::PredicateBuilder)
|
78
85
|
end
|
79
86
|
|
87
|
+
ActiveRecord::DynamicMatchers::Method.prepend(BlindIndex::Extensions::DynamicMatchers)
|
88
|
+
|
80
89
|
unless ActiveRecord::VERSION::STRING.start_with?("5.1.")
|
81
90
|
ActiveRecord::Validations::UniquenessValidator.prepend(BlindIndex::Extensions::UniquenessValidator)
|
82
91
|
end
|
@@ -67,5 +67,15 @@ module BlindIndex
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
end
|
70
|
+
|
71
|
+
module DynamicMatchers
|
72
|
+
def valid?
|
73
|
+
attribute_names.all? { |name| model.columns_hash[name] || model.reflect_on_aggregation(name.to_sym) || blind_index?(name.to_sym) }
|
74
|
+
end
|
75
|
+
|
76
|
+
def blind_index?(name)
|
77
|
+
model.respond_to?(:blind_indexes) && model.blind_indexes[name]
|
78
|
+
end
|
79
|
+
end
|
70
80
|
end
|
71
81
|
end
|
data/lib/blind_index/model.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module BlindIndex
|
2
2
|
module Model
|
3
|
-
def blind_index(name, key: nil, iterations: nil, attribute: nil, expression: nil, bidx_attribute: nil, callback: true, algorithm: nil, insecure_key: nil, encode: nil)
|
3
|
+
def blind_index(name, key: nil, iterations: nil, attribute: nil, expression: nil, bidx_attribute: nil, callback: true, algorithm: nil, insecure_key: nil, encode: nil, cost: nil)
|
4
4
|
iterations ||= 10000
|
5
5
|
attribute ||= name
|
6
6
|
bidx_attribute ||= :"encrypted_#{name}_bidx"
|
@@ -10,15 +10,24 @@ module BlindIndex
|
|
10
10
|
method_name = :"compute_#{name}_bidx"
|
11
11
|
|
12
12
|
class_eval do
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
@blind_indexes ||= {}
|
14
|
+
|
15
|
+
unless respond_to?(:blind_indexes)
|
16
|
+
def self.blind_indexes
|
17
|
+
parent_indexes =
|
18
|
+
if superclass.respond_to?(:blind_indexes)
|
19
|
+
superclass.blind_indexes
|
20
|
+
else
|
21
|
+
{}
|
22
|
+
end
|
23
|
+
|
24
|
+
parent_indexes.merge(@blind_indexes || {})
|
25
|
+
end
|
17
26
|
end
|
18
27
|
|
19
28
|
raise BlindIndex::Error, "Duplicate blind index: #{name}" if blind_indexes[name]
|
20
29
|
|
21
|
-
blind_indexes[name] = {
|
30
|
+
@blind_indexes[name] = {
|
22
31
|
key: key,
|
23
32
|
iterations: iterations,
|
24
33
|
attribute: attribute,
|
@@ -26,9 +35,11 @@ module BlindIndex
|
|
26
35
|
bidx_attribute: bidx_attribute,
|
27
36
|
algorithm: algorithm,
|
28
37
|
insecure_key: insecure_key,
|
29
|
-
encode: encode
|
38
|
+
encode: encode,
|
39
|
+
cost: cost
|
30
40
|
}.reject { |_, v| v.nil? }
|
31
41
|
|
42
|
+
# should have been named generate_#{name}_bidx
|
32
43
|
define_singleton_method method_name do |value|
|
33
44
|
BlindIndex.generate_bidx(value, blind_indexes[name])
|
34
45
|
end
|
data/lib/blind_index/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blind_index
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-06-
|
11
|
+
date: 2018-06-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|