cloak_ecto v1.0.0-alpha.0 Cloak.Ecto.HMAC behaviour View Source
A custom Ecto.Type
for hashing fields using :crypto.hmac/3
.
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 HMAC 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.
Security
HMAC is more secure than Cloak.Ecto.SHA256
, because it uses a
secret to obfuscate the hash. This makes it harder to guess the value of
the field.
Configuration
Create an HMAC
field in your project:
defmodule MyApp.Hashed.HMAC do
use Cloak.Ecto.HMAC, otp_app: :my_app
end
Then, configure it with a :secret
and :algorithm
, either using
mix configuration:
config :my_app, MyApp.Hashed.HMAC,
algorithm: :sha512,
secret: "secret"
Or using the init/1
callback to fetch configuration at runtime:
defmodule MyApp.Hashed.HMAC do
use Cloak.Ecto.HMAC, otp_app: :my_app
@impl Cloak.Ecto.HMAC
def init(config) do
config = Keyword.merge(config, [
algorithm: :sha512,
secret: System.get_env("HMAC_SECRET")
])
{:ok, config}
end
end
Usage
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.HMAC
end
Ensure 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))
end
Query 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
HMAC algorithms supported by Cloak.Field.HMAC
Callbacks
Configures the HMAC
field using runtime information
Link to this section Types
algorithms() :: :md5 | :ripemd160 | :sha | :sha224 | :sha256 | :sha384 | :sha512
HMAC algorithms supported by Cloak.Field.HMAC
Link to this section Callbacks
Configures the HMAC
field using runtime information.
Example
@impl Cloak.Fields.HMAC
def init(config) do
config = Keyword.merge(config, [
algorithm: :sha512,
secret: System.get_env("HMAC_SECRET")
])
{:ok, config}
end