README.md in blind_index-2.3.1 vs README.md in blind_index-2.3.2

- old
+ new

@@ -222,24 +222,34 @@ Finally, drop the old column. ## Key Separation -The master key is used to generate unique keys for each blind index. This technique comes from [CipherSweet](https://ciphersweet.paragonie.com/internals/key-hierarchy). The table name and blind index column name are both used in this process. If you need to rename a table with blind indexes, or a blind index column itself, get the key: +The master key is used to generate unique keys for each blind index. This technique comes from [CipherSweet](https://ciphersweet.paragonie.com/internals/key-hierarchy). The table name and blind index column name are both used in this process. +You can get an individual key with: + ```ruby BlindIndex.index_key(table: "users", bidx_attribute: "email_bidx") ``` -And set it directly before renaming: +To rename a table with blind indexes, use: ```ruby class User < ApplicationRecord - blind_index :email, key: ENV["USER_EMAIL_BLIND_INDEX_KEY"] + blind_index :email, key_table: "original_table" end ``` +To rename a blind index column, use: + +```ruby +class User < ApplicationRecord + blind_index :email, key_attribute: "original_column" +end +``` + ## Algorithm Argon2id is used for best security. The default cost parameters are 3 iterations and 4 MB of memory. For `slow: true`, the cost parameters are 4 iterations and 32 MB of memory. A number of other algorithms are [also supported](docs/Other-Algorithms.md). Unless you have specific reasons to use them, go with Argon2id. @@ -344,10 +354,32 @@ class User < ApplicationRecord blind_index :email, key: ENV["USER_EMAIL_BLIND_INDEX_KEY"] end ``` +## Compatibility + +You can generate blind indexes from other languages as well. For Python, you can use [argon2-cffi](https://github.com/hynek/argon2-cffi). + +```python +from argon2.low_level import Type, hash_secret_raw +from base64 import b64encode + +key = '289737bab72fa97b1f4b081cef00d7b7d75034bcf3183c363feaf3e6441777bc' +value = 'test@example.org' + +bidx = b64encode(hash_secret_raw( + secret=value.encode(), + salt=bytes.fromhex(key), + time_cost=3, + memory_cost=2**12, + parallelism=1, + hash_len=32, + type=Type.ID +)) +``` + ## 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. We recommend blind indexing over deterministic encryption because: 1. You can keep encryption consistent for all fields (both searchable and non-searchable) @@ -360,108 +392,9 @@ 2.0.0 brings a number of improvements. - Blind indexes are updated immediately instead of in a `before_validation` callback - Better Lockbox integration - no need to generate a separate key - There’s a new gem for Argon2 that has no dependencies and (officially) supports Windows - -### 1.0.0 - -1.0.0 brings a number of improvements. Here are a few to be aware of: - -- Argon2id is the default algorithm for stronger security -- You can use a master key instead of individual keys for each column -- Columns no longer have an `encrypted_` prefix - -For existing fields, add: - -```ruby -class User < ApplicationRecord - blind_index :email, legacy: true -end -``` - -#### Optional - -To rotate to new fields that use Argon2id and a master key, generate a master key: - -```ruby -BlindIndex.generate_key -``` - -And set `ENV["BLIND_INDEX_MASTER_KEY"]` or `BlindIndex.master_key`. - -Add a new column without the `encrypted_` prefix: - -```ruby -add_column :users, :email_bidx, :string -add_index :users, :email_bidx # unique: true if needed -``` - -And add to your model - -```ruby -class User < ApplicationRecord - blind_index :email, key: ENV["USER_EMAIL_BLIND_INDEX_KEY"], legacy: true, rotate: {} -end -``` - -> For more sensitive fields, use `rotate: {slow: true}` - -This will keep the new column synced going forward. Next, backfill the data: - -```ruby -User.unscoped.where(email_bidx: nil).find_each do |user| - user.compute_rotated_email_bidx - user.save(validate: false) -end -``` - -Then update your model - -```ruby -class User < ApplicationRecord - blind_index :email -end -``` - -> For more sensitive fields, add `slow: true` - -Finally, drop the old column. - -### 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) -``` - -Update your model to convert the hex key to binary. - -```ruby -class User < ApplicationRecord - blind_index :email, key: [ENV["USER_EMAIL_BLIND_INDEX_KEY"]].pack("H*") -end -``` - -And recompute the blind index. - -```ruby -User.unscoped.find_each do |user| - user.compute_email_bidx - user.save(validate: false) -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)