How To Upgrade From 0.6.x to 0.7.x
Cloak 0.7 introduced a number of important changes.
- Encryption is now performed through
Cloak.Vault
modules - Ciphertext no longer contains a
module_tag
- Ecto types are now local to your project
- You no longer need an
:encryption_version
field
Install Cloak 0.7
Update your cloak
dependency to 0.7
or later.
{:cloak, "~> 0.7.0"}
Create a Vault
Create a vault module for your project. (Or more than one, if you want!)
defmodule MyApp.Vault do
use Cloak.Vault, otp_app: :my_app
end
You will need to move your existing configuration to the vault. For example, if you had this configuration:
config :cloak, Cloak.AES.CTR,
tag: "AES",
default: true,
keys: [
%{tag: <<1>>, key: :base64.decode("..."), default: true}
]
You would convert it to the following:
config :my_app, MyApp.Vault,
ciphers: [
default: {Cloak.Ciphers.AES.CTR, tag: "AES.V2", key: Base.decode64("...")},
retired: {Cloak.Ciphers.Deprecated.AES.CTR, module_tag: "AES", tag: <<1>>, key: Base.decode64("...")}
]
Notice that the tag: "AES"
became module_tag: "AES"
in the :retired
cipher configuration.
Alternatively, if your keys are stored in environment variables, you could
configure the vault using the Cloak.Vault.init/1
callback:
defmodule MyApp.Vault do
use Cloak.Vault, otp_app: :my_app
@impl Cloak.Vault
def init(config) do
config =
Keyword.put(config, :ciphers, [
default: {Cloak.Ciphers.AES.CTR, tag: "AES.V2", key: decode_env("CLOAK_KEY")},
retired: {Cloak.Ciphers.Deprecated.AES.CTR, module_tag: "AES", tag: <<1>>, key: decode_env("CLOAK_KEY")}
])
{:ok, config}
end
defp decode_env(var) do
var
|> System.get_env(var)
|> Base.decode64!()
end
end
Create Project-Specific Ecto Types
For each type of encrypted field you have, define a local type. For example, if you had the following schema:
defmodule MyApp.Accounts.User do
use Ecto.Schema
import Ecto.Changeset
schema "users" do
field :name, Cloak.EncryptedBinaryField,
field :encryption_version
end
@doc false
def changeset(struct, attrs \\ %{}) do
struct
|> cast(attrs, [:name])
|> put_change(:encryption_version, Cloak.version())
end
end
You would define a project-specific field:
defmodule MyApp.Encrypted.Binary do
use Cloak.Fields.Binary, vault: MyApp.Vault
end
And then replace Cloak.EncryptedBinaryField
in your schema:
schema "users" do
field :name, MyApp.Encrypted.Binary,
field :encryption_version
end
Finally, you’d remove the :encryption_version
field as it is no longer
needed.
# In migration...
alter table(:users) do
remove :encryption_version
end
# In your changeset...
@doc false
def changeset(struct, attrs \\ %{}) do
struct
|> cast(attrs, [:name])
end
Migrate Existing Data
To convert ciphertext en masse from the old v0.6
format to the new v0.7
format, you’ll need to run mix cloak.migrate
as shown in its documentation.
mix cloak.migrate -r MyApp.Repo -s MyApp.Schema
Remove :retired
Cipher
Now that the data has been migrated to the new v0.7
format, you can remove the
:retired
cipher from your configuration.
config :my_app, MyApp.Vault,
ciphers: [
default: {Cloak.Ciphers.AES.CTR, tag: "AES.V2", key: Base.decode64("...")}
]