README.md in blind_index-0.2.1 vs README.md in blind_index-0.3.0
- old
+ new
@@ -2,15 +2,17 @@
Securely search encrypted database fields
Designed for use with [attr_encrypted](https://github.com/attr-encrypted/attr_encrypted)
+Here’s a [full example](https://shorts.dokkuapp.com/securing-user-emails-in-rails/) of how to use it with Devise
+
[![Build Status](https://travis-ci.org/ankane/blind_index.svg?branch=master)](https://travis-ci.org/ankane/blind_index)
## How It Works
-We use [this approach](https://www.sitepoint.com/how-to-search-on-securely-encrypted-database-fields/) 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-HMAC-SHA256) 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.
+We use [this approach](https://www.sitepoint.com/how-to-search-on-securely-encrypted-database-fields/) 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-HMAC-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.
## Getting Started
Add these lines to your application’s Gemfile:
@@ -33,20 +35,26 @@
And add to your model
```ruby
class User < ApplicationRecord
- attr_encrypted :email, key: ENV["EMAIL_ENCRYPTION_KEY"]
- blind_index :email, key: ENV["EMAIL_BLIND_INDEX_KEY"]
+ attr_encrypted :email, key: [ENV["EMAIL_ENCRYPTION_KEY"]].pack("H*")
+ blind_index :email, key: [ENV["EMAIL_BLIND_INDEX_KEY"]].pack("H*")
end
```
-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. For development, you can use these:
+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:
+```ruby
+SecureRandom.hex(32)
+```
+
+For development, you can use these:
+
```sh
-EMAIL_ENCRYPTION_KEY=00000000000000000000000000000000
-EMAIL_BLIND_INDEX_KEY=99999999999999999999999999999999
+EMAIL_ENCRYPTION_KEY=0000000000000000000000000000000000000000000000000000000000000000
+EMAIL_BLIND_INDEX_KEY=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
```
And query away
```ruby
@@ -97,39 +105,111 @@
```ruby
User.where(email_ci: "test@example.org")
```
-## Key Stretching
+## Index Only
-Key stretching increases the amount of time required to compute hashes, which slows down brute-force attacks. You can set the number of iterations with:
+If you don’t need to store the original value (for instance, when just checking duplicates), use a virtual attribute:
```ruby
class User < ApplicationRecord
+ attribute :email
+ blind_index :email, ...
+end
+```
+
+## Fixtures
+
+You can use blind indexes in fixtures with:
+
+```yml
+test_user:
+ encrypted_email_bidx: <%= User.compute_email_bidx("test@example.org").inspect %>
+```
+
+Be sure to include the `inspect` at the end, or it won’t be encoded properly in YAML.
+
+## Algorithms
+
+### PBKDF2-HMAC-SHA256
+
+The default hashing algorithm. [Key stretching](https://en.wikipedia.org/wiki/Key_stretching) increases the amount of time required to compute hashes, which slows down brute-force attacks. You can set the number of iterations with:
+
+```ruby
+class User < ApplicationRecord
blind_index :email, iterations: 1000000, ...
end
```
The default is `10000`. Changing this value requires you to recompute the blind index.
-## Index Only
-If you don’t need to store the original value (for instance, when just checking duplicates), use a virtual attribute:
+### scrypt
+:warning: *Not production ready yet*
+
+Add [scrypt](https://github.com/pbhogan/scrypt) to your Gemfile and use:
+
```ruby
class User < ApplicationRecord
- attribute :email
- blind_index :email, ...
+ blind_index :email, algorithm: :scrypt, ...
end
```
-## Fixtures
+### Argon2
-You can use blind indexes in fixtures with:
+:warning: *Not production ready yet*
-```yml
-test_user:
- encrypted_email_bidx: <%= User.compute_email_bidx("test@example.org").inspect %>
+Add [argon2](https://github.com/technion/ruby-argon2) to your Gemfile and use:
+
+```ruby
+class User < ApplicationRecord
+ blind_index :email, algorithm: :argon2, ...
+end
+```
+
+## Reference
+
+By default, blind indexes are encoded in Base64. Set a different encoding with:
+
+```ruby
+class User < ApplicationRecord
+ blind_index :email, encode: ->(v) { [v].pack("H*") }
+end
+```
+
+## Alternatives
+
+One alternative to blind indexing is to use a deterministic encryption scheme, like [AES-SIV](https://github.com/miscreant/miscreant). In this approach, the encrypted data will be the same for matches.
+
+## Upgrading
+
+### 0.3.0
+
+This version introduces a breaking change to enforce secure key generation. An error is thrown if your blind index key isn’t both binary and 32 bytes.
+
+We recommend rotating your key if it doesn’t meet this criteria. You can generate a new key in the Rails console with:
+
+```ruby
+SecureRandom.hex(32)
+```
+
+Set the new key and recompute the blind index.
+
+```ruby
+User.find_each do |user|
+ user.compute_email_bidx
+ user.save!
+end
+```
+
+To continue without rotating, set:
+
+```ruby
+class User < ApplicationRecord
+ blind_index :email, insecure_key: true, ...
+end
```
## History
View the [changelog](https://github.com/ankane/blind_index/blob/master/CHANGELOG.md)