cloak v0.8.0 Cloak.Fields.PBKDF2 behaviour View Source
A custom Ecto.Type for deriving a key for fields using
PBKDF2.
PBKDF2 is more secure than Cloak.Fields.HMAC and
Cloak.Fields.SHA256 because it uses key
stretching to increase the
amount of time to compute hashes. This slows down brute-force attacks.
Why
If you store a hash of a field’s value, you can then query on it as a proxy for an encrypted field. This works because PBKDF2 is deterministic and always results in the same value, while secure encryption does not. Be warned, however, that hashing will expose which fields have the same value, because they will contain the same hash.
Dependency
To use this field type, you must install the :pbkdf2 library in your
mix.exs file.
{:pbkdf2, "~> 2.0"}Configuration
Create a PBKDF2 field in your project:
defmodule MyApp.Hashed.PBKDF2 do
  use Cloak.Fields.PBKDF2, otp_app: :my_app
endThen, configure it with a :secret, an :algorithm, the maximum :size
of the stored key (in bytes), and a number of :iterations, either using
mix configuration:
config :my_app, MyApp.Hashed.PBKDF2,
  algorithm: :sha256,
  iterations: 10_000,
  secret: "secret"Or using the init/1 callback to fetch configuration at runtime:
defmodule MyApp.Hashed.PBKDF2 do
  use Cloak.Fields.PBKDF2, otp_app: :my_app
  @impl Cloak.Fields.PBKDF2
  def init(config) do
    config = Keyword.merge(config, [
      algorithm: :sha256,
      iterations: 10_000,
      secret: System.get_env("PBKDF2_SECRET")
    ])
    {:ok, config}
  end
endUsage
Create the hash field with the type :binary. Add it to your schema
definition like this:
schema "table" do
  field :field_name, MyApp.Encrypted.Binary
  field :field_name_hash, MyApp.Hashed.PBKDF2
endEnsure that the hash is updated whenever the target field changes with the
put_change/3 function:
def changeset(struct, attrs \\ %{}) do
  struct
  |> cast(attrs, [:field_name, :field_name_hash])
  |> put_hashed_fields()
end
defp put_hashed_fields(changeset) do
  changeset
  |> put_change(:field_name_hash, get_field(changeset, :field_name))
endQuery the Repo using the :field_name_hash in any place you would typically
query by :field_name.
user = Repo.get_by(User, email_hash: "user@email.com")Link to this section Summary
Types
Digest algorithms supported by Cloak.Field.PBKDF2
Callbacks
Configures the PBKDF2 field using runtime information
Link to this section Types
algorithms() :: :md4 | :md5 | :ripemd160 | :sha | :sha224 | :sha256 | :sha384 | :sha512
Digest algorithms supported by Cloak.Field.PBKDF2
Link to this section Callbacks
Configures the PBKDF2 field using runtime information.
Example
@impl Cloak.Fields.PBKDF2
def init(config) do
  config = Keyword.merge(config, [
    algorithm: :sha256,
    secret: System.get_env("PBKDF2_SECRET")
  ])
  {:ok, config}
end