Cloak
Cloak makes it easy to encrypt and decrypt database fields using Ecto.
This Cloak
module is Cloak's main entry point. It wraps the encryption and decryption process, ensuring that everything works smoothly without downtime even when there are multiple encryption ciphers and keys in play at the same time.
Configuration
The actual encryption work is delegated to the cipher module that you specify in Cloak's configuration. Cipher modules must adhere to the Cloak.Cipher
behaviour. You can configure a cipher module like so:
config :cloak, ModuleName,
default: true,
tag: "TAG",
# any other attributes required by the cipher
You can also have multiple ciphers configured at the same time, provided that they are not both set to default: true
.
config :cloak, CipherOne,
default: true,
tag: "one",
# ...
config :cloak, CipherTwo,
default: true,
tag: "two",
# ...
Options
Both of these options are required for every cipher:
:default
- Boolean. Determines whether this module will be the default module for encryption or decryption. The default module will be used to generate all new encrypted values.:tag
- Binary. Used to tag any ciphertext that the cipher module generates. This allows Cloak to decrypt a ciphertext with the correct module when you have multiple ciphers in use at the same time.
If your cipher module requires additional configuration options, you can also add those keys and values to this configuration.
# Example of custom settings for a cipher module
config :cloak, MyCustomCipher,
default: true,
tag: "tag",
custom_setting1: "...",
custom_setting2: "..."
It will be the responsibility of the cipher module to read these values from the :cloak
application configuration and use them.
Provided Ciphers
Cloak.AES.CTR
- AES encryption in CTR stream mode.
If you don't see what you need here, you can use your own cipher module, provided it adheres to the Cloak.Cipher
behaviour.
(And open a PR, please!)
Ecto Integration
Once Cloak is configured with a Cipher module, you can use it seamlessly with Ecto with these Ecto.Type
modules:
Cloak.EncryptedBinaryField
Cloak.EncryptedFloatField
Cloak.EncryptedIntegerField
Cloak.EncryptedMapField
Cloak.SHA256Field
For example, to encrypt a binary field, change your schema from this:
schema "users" do
field :name, :binary
end
To this:
schema "users" do
field :name, Cloak.EncryptedBinaryField
end
The name
field will then be encrypted whenever it is saved to the database, using your configured cipher module. It will also be transparently decrypted whenever the user is loaded from the database.
Examples
The Cloak
module can be called directly to generate ciphertext using the current default cipher module.
iex> Cloak.encrypt("Hello") != "Hello"
true
iex> Cloak.encrypt("Hello") |> Cloak.decrypt
"Hello"
iex> Cloak.version
<<"AES", 1>>
Summary
Decrypt a ciphertext with the cipher module it was encrypted with
Encrypt a value using the default cipher module
Functions
Decrypt a ciphertext with the cipher module it was encrypted with.
encrypt/1
includes the :tag
of the cipher module that generated the encryption in the ciphertext it outputs. decrypt/1
can then use this tag to find the right module on decryption.
Parameters
ciphertext
- A binary of ciphertext generated byencrypt/1
.
Example
If the cipher module responsible had the tag "AES", Cloak will find the module using that tag, strip it off, and hand the remaining ciphertext to the module for decryption.
iex> ciphertext = Cloak.encrypt("Hello world!")
...> <<"AES", _ :: bitstring>> = ciphertext
...> Cloak.decrypt(ciphertext)
"Hello world!"
Encrypt a value using the default cipher module.
The :tag
of the cipher will be prepended to the output. So, if the cipher was Cloak.AES.CTR
, and the tag was "AES", the output would be in this format:
+-------+---------------+
| "AES" | Cipher output |
+-------+---------------+
This tagging allows Cloak to delegate decryption of a ciphertext to the correct module when you have multiple ciphers in use at the same time. (For example, this can occur while you migrate your encrypted data to a new cipher.)
Parameters
plaintext
- The value to be encrypted.
Example
Cloak.encrypt("Hello, World!")
<<"AES", ...>>
Returns the default cipher module's tag combined with the result of that cipher's version/0
function.
It is used by Cloak.Model
to record which cipher was used to encrypt a row in a database table. This is very useful when migrating to a new cipher or new encryption key, because you'd be able to query your database to find records that need to be migrated.