View Source Cloak.Vault behaviour (cloak v1.1.2)
Encrypts and decrypts data, using a configured cipher.
create-your-vault
Create Your Vault
Define a module in your application that uses Cloak.Vault
.
defmodule MyApp.Vault do
use Cloak.Vault, otp_app: :my_app
end
configuration
Configuration
The :otp_app
option should point to an OTP application that has the vault
configuration.
For example, the vault:
defmodule MyApp.Vault do
use Cloak.Vault, otp_app: :my_app
end
Could be configured with Mix configuration like so:
config :my_app, MyApp.Vault,
json_library: Jason,
ciphers: [
default: {Cloak.Ciphers.AES.GCM, tag: "AES.GCM.V1", key: <<...>>}
]
The configuration options are:
:json_library
: Used to convert data types like lists and maps into binary so that they can be encrypted. (Default:Jason
):ciphers: a list of
Cloak.Cipher
modules the following format:{:label, {CipherModule, opts}}
The first configured cipher in the list is the default for encrypting all new data, regardless of its label. This behaviour can be overridden on a field-by-field basis.
The
opts
are specific to each cipher module. Check their codumentation for what each cipher requires.
runtime-configuration
Runtime Configuration
Because Vaults are GenServers, they can be configured at runtime using the
init/1
callback. This allows you to easily fetch values like environment
variables in a reliable way.
The configuration from the :otp_app
is passed as the first argument to the
callback, allowing you to append to or change it at will.
defmodule MyApp.Vault do
use Cloak.Vault, otp_app: :my_app
@impl GenServer
def init(config) do
config =
Keyword.put(config, :ciphers, [
default: {Cloak.Ciphers.AES.GCM, tag: "AES.GCM.V1", key: decode_env!("CLOAK_KEY")}
])
{:ok, config}
end
defp decode_env!(var) do
var
|> System.get_env()
|> Base.decode64!()
end
end
You can also pass configuration to vaults via start_link/1
:
MyApp.Vault.start_link(ciphers: [
default: {Cloak.Ciphers.AES.GCM, tag: "AES.GCM.V1", key: key}
])
supervision
Supervision
Because Vaults are GenServer
s, you'll need to add your vault to your
supervision tree in application.ex
or whichever supervisor you prefer.
children = [
MyApp.Vault
]
If you want to pass in configuration values at runtime, you can do so:
children = [
{MyApp.Vault, ciphers: [...]}
]
usage
Usage
You can use the vault directly by calling its functions.
MyApp.Vault.encrypt("plaintext")
# => {:ok, <<...>>}
MyApp.Vault.decrypt(ciphertext)
# => {:ok, "plaintext"}
See the documented callbacks below for the functions you can call.
performance-notes
Performance Notes
Vaults are not bottlenecks. They simply store configuration in an ETS table
named after the Vault, e.g. MyApp.Vault.Config
. All encryption and
decryption is performed in your local process, reading configuration from
the vault's ETS table.
Link to this section Summary
Callbacks
Decrypts a binary with the configured cipher that generated the binary. Automatically detects which cipher to use, based on the ciphertext.
Like decrypt/1
, but raises any errors.
Encrypts a binary using the first configured cipher in the vault's
configured :ciphers
list.
Encrypts a binary using the vault's configured cipher with the corresponding label.
Like encrypt/1
, but raises any errors.
Like encrypt/2
, but raises any errors.
The JSON library the vault uses to convert maps and lists into JSON binaries before encryption.
Link to this section Types
Link to this section Callbacks
@callback decrypt(ciphertext()) :: {:ok, plaintext()} | {:error, Exception.t()}
Decrypts a binary with the configured cipher that generated the binary. Automatically detects which cipher to use, based on the ciphertext.
@callback decrypt!(ciphertext()) :: plaintext() | no_return()
Like decrypt/1
, but raises any errors.
@callback encrypt(plaintext()) :: {:ok, ciphertext()} | {:error, Exception.t()}
Encrypts a binary using the first configured cipher in the vault's
configured :ciphers
list.
@callback encrypt(plaintext(), label()) :: {:ok, ciphertext()} | {:error, Exception.t()}
Encrypts a binary using the vault's configured cipher with the corresponding label.
@callback encrypt!(plaintext()) :: ciphertext() | no_return()
Like encrypt/1
, but raises any errors.
@callback encrypt!(plaintext(), label()) :: ciphertext() | no_return()
Like encrypt/2
, but raises any errors.
@callback json_library() :: module()
The JSON library the vault uses to convert maps and lists into JSON binaries before encryption.