blind_index 0.3.4 → 0.3.5

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: 0a5e0cf17996a671847cd6b7d9c89820c4dfa319c1f6e8c60bff430d5fdbb222
4
- data.tar.gz: 82d7b94d12cd4391d48d845613a75740c0edbcb38d9d8272054b3bea58574c81
3
+ metadata.gz: 8f5aab7dbd2a784f6bcc2b464c14f76621c94886ec4764bc5e51f97ac74ae0d9
4
+ data.tar.gz: 104135feff81321860030ca46946cd5021cfb97fcc5a3953742ac61cee842cfd
5
5
  SHA512:
6
- metadata.gz: ff9d3d7b14c867a1972faa2600bfec2918fee21b2c2108bfa5a358990d1fc661c2aab84cc39c1610a0064cfd6a9b0ad461c1269b4bfdc8b85414f944235d864b
7
- data.tar.gz: 87f28352c529b0cb61a0b4cf050a3619234da3e21fb06b5ba36d3d605119910678947994d381bb3a1bad81716300fe184d0adf8aa73cb78a95bd93ce93a23206
6
+ metadata.gz: b79e2f7597a572b4732f326bde1ce82de7941ffd3e97dc609834931cacb86a59c2ae6f5cc981cda0f6827956823bd01d910b56c5092409547a539a5db010e1b8
7
+ data.tar.gz: ba72cc3e13bb0fdd12e3502d1657e20074af745b41bb8fcb34df495e14fbddb36c3535e450950aa3ccb935a92c9cbbdcc70c7f1eaacccaba8c3fa358a3955470
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.3.5
2
+
3
+ - Added support for hex keys
4
+ - Added `generate_key` method
5
+ - Fixed querying with array values
6
+
1
7
  ## 0.3.4
2
8
 
3
9
  - Added `size` option
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2017-2018 Andrew Kane
1
+ Copyright (c) 2017-2019 Andrew Kane
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -6,11 +6,19 @@ Designed for use with [attr_encrypted](https://github.com/attr-encrypted/attr_en
6
6
 
7
7
  Here’s a [full example](https://ankane.org/securing-user-emails-in-rails) of how to use it
8
8
 
9
+ Check out [this post](https://ankane.org/sensitive-data-rails) for more info on securing sensitive data with Rails
10
+
9
11
  [![Build Status](https://travis-ci.org/ankane/blind_index.svg?branch=master)](https://travis-ci.org/ankane/blind_index)
10
12
 
11
13
  ## How It Works
12
14
 
13
- We use [this approach](https://paragonie.com/blog/2017/05/building-searchable-encrypted-databases-with-php-and-sql) by Scott Arciszewski. To summarize, we compute a keyed hash of the sensitive data and store it in a column. To query, we apply the keyed hash function (PBKDF2-SHA256 by default) to the value we’re searching and then perform a database search. This results in performant queries for equality operations, while keeping the data secure from those without the key.
15
+ We use [this approach](https://paragonie.com/blog/2017/05/building-searchable-encrypted-databases-with-php-and-sql) by Scott Arciszewski. To summarize, we compute a keyed hash of the sensitive data and store it in a column. To query, we apply the keyed hash function to the value we’re searching and then perform a database search. This results in performant queries for exact matches. `LIKE` queries are not possible, but you can index expressions.
16
+
17
+ ## Leakage
18
+
19
+ An important consideration in searchable encryption is leakage, which is information an attacker can gain. Blind indexing leaks that rows have the same value. If you use this for a field like last name, an attacker can use frequency analysis to predict the values. In an active attack where an attacker can control the input values, they can learn which other values in the database match.
20
+
21
+ Here’s a [great article](https://blog.cryptographyengineering.com/2019/02/11/attack-of-the-week-searchable-encryption-and-the-ever-expanding-leakage-function/) on leakage in searchable encryption. Blind indexing has the same leakage as deterministic encryption.
14
22
 
15
23
  ## Installation
16
24
 
@@ -31,26 +39,28 @@ add_column :users, :encrypted_email_bidx, :string
31
39
  add_index :users, :encrypted_email_bidx
32
40
  ```
33
41
 
34
- And add to your model
42
+ Next, generate a key
35
43
 
36
44
  ```ruby
37
- class User < ApplicationRecord
38
- blind_index :email, key: [ENV["EMAIL_BLIND_INDEX_KEY"]].pack("H*")
39
- end
45
+ BlindIndex.generate_key
40
46
  ```
41
47
 
42
- We use an environment variable to store the key as a hex-encoded string ([dotenv](https://github.com/bkeepers/dotenv) is great for this). [Here’s an explanation](https://ankane.org/encryption-keys) of why `pack` is used. *Do not commit it to source control.* This should be different than the key you use for encryption. You can generate a key in the Rails console with:
43
-
44
- ```ruby
45
- SecureRandom.hex(32)
46
- ```
48
+ Store the key with your other secrets. This is typically Rails credentials or an environment variable ([dotenv](https://github.com/bkeepers/dotenv) is great for this). Be sure to use different keys in development and production, and be sure this is different than the key you use for encryption. Keys don’t need to be hex-encoded, but it’s often easier to store them this way.
47
49
 
48
- For development, you can use this:
50
+ Here’s a key you can use in development
49
51
 
50
52
  ```sh
51
53
  EMAIL_BLIND_INDEX_KEY=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
52
54
  ```
53
55
 
56
+ Add to your model
57
+
58
+ ```ruby
59
+ class User < ApplicationRecord
60
+ blind_index :email, key: ENV["EMAIL_BLIND_INDEX_KEY"]
61
+ end
62
+ ```
63
+
54
64
  Backfill existing records
55
65
 
56
66
  ```ruby
@@ -212,8 +222,8 @@ And add to your model
212
222
 
213
223
  ```ruby
214
224
  class User < ApplicationRecord
215
- blind_index :email, key: [ENV["EMAIL_BLIND_INDEX_KEY"]].pack("H*")
216
- blind_index :email_v2, attribute: :email, key: [ENV["EMAIL_V2_BLIND_INDEX_KEY"]].pack("H*")
225
+ blind_index :email, key: ENV["EMAIL_BLIND_INDEX_KEY"]
226
+ blind_index :email_v2, attribute: :email, key: ENV["EMAIL_V2_BLIND_INDEX_KEY"]
217
227
  end
218
228
  ```
219
229
 
@@ -230,7 +240,7 @@ Then update your model
230
240
 
231
241
  ```ruby
232
242
  class User < ApplicationRecord
233
- blind_index :email, bidx_attribute: :encrypted_email_v2_bidx, key: [ENV["EMAIL_V2_BLIND_INDEX_KEY"]].pack("H*")
243
+ blind_index :email, bidx_attribute: :encrypted_email_v2_bidx, key: ENV["EMAIL_V2_BLIND_INDEX_KEY"]
234
244
 
235
245
  # remove this line after dropping column
236
246
  self.ignored_columns = ["encrypted_email_bidx"]
@@ -254,6 +264,12 @@ Be sure to include the `inspect` at the end, or it won’t be encoded properly i
254
264
 
255
265
  ## Reference
256
266
 
267
+ Set default options in an initializer with:
268
+
269
+ ```ruby
270
+ BlindIndex.default_options[:algorithm] = :argon2
271
+ ```
272
+
257
273
  By default, blind indexes are encoded in Base64. Set a different encoding with:
258
274
 
259
275
  ```ruby
data/lib/blind_index.rb CHANGED
@@ -11,16 +11,16 @@ module BlindIndex
11
11
  class << self
12
12
  attr_accessor :default_options
13
13
  end
14
- self.default_options = {
15
- iterations: 10000,
16
- algorithm: :pbkdf2_sha256,
17
- insecure_key: false,
18
- encode: true,
19
- cost: {}
20
- }
14
+ self.default_options = {}
21
15
 
22
16
  def self.generate_bidx(value, key:, **options)
23
- options = default_options.merge(options)
17
+ options = {
18
+ iterations: 10000,
19
+ algorithm: :pbkdf2_sha256,
20
+ insecure_key: false,
21
+ encode: true,
22
+ cost: {}
23
+ }.merge(default_options).merge(options)
24
24
 
25
25
  # apply expression
26
26
  value = options[:expression].call(value) if options[:expression]
@@ -35,6 +35,11 @@ module BlindIndex
35
35
 
36
36
  key = key.to_s
37
37
  unless options[:insecure_key] && algorithm == :pbkdf2_sha256
38
+ # decode hex key
39
+ if key.encoding != Encoding::BINARY && key =~ /\A[0-9a-f]{64}\z/i
40
+ key = [key].pack("H*")
41
+ end
42
+
38
43
  raise BlindIndex::Error, "Key must use binary encoding" if key.encoding != Encoding::BINARY
39
44
  raise BlindIndex::Error, "Key must be 32 bytes" if key.bytesize != 32
40
45
  end
@@ -90,6 +95,11 @@ module BlindIndex
90
95
  end
91
96
  end
92
97
  end
98
+
99
+ def self.generate_key
100
+ require "securerandom"
101
+ SecureRandom.hex(32)
102
+ end
93
103
  end
94
104
 
95
105
  ActiveSupport.on_load(:active_record) do
@@ -7,7 +7,13 @@ module BlindIndex
7
7
  if has_blind_indexes?
8
8
  hash.each do |key, _|
9
9
  if key.respond_to?(:to_sym) && (bi = klass.blind_indexes[key.to_sym]) && !new_hash[key].is_a?(ActiveRecord::StatementCache::Substitute)
10
- new_hash[bi[:bidx_attribute]] = BlindIndex.generate_bidx(new_hash.delete(key), bi)
10
+ value = new_hash.delete(key)
11
+ new_hash[bi[:bidx_attribute]] =
12
+ if value.is_a?(Array)
13
+ value.map { |v| BlindIndex.generate_bidx(v, bi) }
14
+ else
15
+ BlindIndex.generate_bidx(value, bi)
16
+ end
11
17
  end
12
18
  end
13
19
  end
@@ -30,7 +36,13 @@ module BlindIndex
30
36
  if has_blind_indexes?(klass)
31
37
  hash.each do |key, _|
32
38
  if key.respond_to?(:to_sym) && (bi = klass.blind_indexes[key.to_sym]) && !new_hash[key].is_a?(ActiveRecord::StatementCache::Substitute)
33
- new_hash[bi[:bidx_attribute]] = BlindIndex.generate_bidx(new_hash.delete(key), bi)
39
+ value = new_hash.delete(key)
40
+ new_hash[bi[:bidx_attribute]] =
41
+ if value.is_a?(Array)
42
+ value.map { |v| BlindIndex.generate_bidx(v, bi) }
43
+ else
44
+ BlindIndex.generate_bidx(value, bi)
45
+ end
34
46
  end
35
47
  end
36
48
  end
@@ -1,3 +1,3 @@
1
1
  module BlindIndex
2
- VERSION = "0.3.4"
2
+ VERSION = "0.3.5"
3
3
  end
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
4
+ version: 0.3.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-16 00:00:00.000000000 Z
11
+ date: 2019-05-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -98,16 +98,16 @@ dependencies:
98
98
  name: sqlite3
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ">="
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '0'
103
+ version: 1.3.0
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ">="
108
+ - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '0'
110
+ version: 1.3.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: scrypt
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -182,8 +182,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
182
182
  - !ruby/object:Gem::Version
183
183
  version: '0'
184
184
  requirements: []
185
- rubyforge_project:
186
- rubygems_version: 2.7.6
185
+ rubygems_version: 3.0.3
187
186
  signing_key:
188
187
  specification_version: 4
189
188
  summary: Securely search encrypted database fields