Current section
Files
Jump to
Current section
Files
lib/cloak.ex
defmodule Cloak do
@moduledoc """
This 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
### Options
:qa
:q
Both of these options are required for every cipher:
- `:default` - Boolean. Determines whether this module will be the default module for
encryption or decryption.
- `:tag` - Binary. Used to tag any ciphertext that the cipher module
generates. This allows Cloak to send a ciphertext to the correct decryption
cipher when you have multiple ciphers in use at the same time.
If your cipher module requires additional config options, you can also add
those keys to this configuration.
## Provided Ciphers
- `Cloak.AES.CTR` - AES encryption in CTR stream mode.
If you don't see what you need here, you can implement your own cipher module
if you adhere to the `Cloak.Cipher` behaviour. (And [open a PR](https://github.com/danielberkompas/cloak), please!)
## Ecto Integration
Once Cloak is configured with a Cipher module, you can use it seamlessly with
[Ecto](http://hex.pm/ecto) with these `Ecto.Type`s:
- `Cloak.EncryptedBinaryField`
- `Cloak.EncryptedFloatField`
- `Cloak.EncryptedIntegerField`
- `Cloak.EncryptedMapField`
- `Cloak.SHA256Field`
## Examples
iex> Cloak.encrypt("Hello") != "Hello"
true
iex> Cloak.encrypt("Hello") |> Cloak.decrypt
"Hello"
iex> Cloak.version
<<"AES", 1>>
"""
{cipher, config} = Cloak.Config.default_cipher
@cipher cipher
@tag config[:tag]
@doc """
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", ...>>
"""
def encrypt(plaintext) do
@tag <> @cipher.encrypt(plaintext)
end
@doc """
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 by `encrypt/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!"
"""
for {cipher, config} <- Cloak.Config.all do
def decrypt(unquote(config[:tag]) <> ciphertext) do
unquote(cipher).decrypt(ciphertext)
end
end
def decrypt(invalid) do
raise ArgumentError, "No cipher found to decrypt #{inspect invalid}."
end
@doc """
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.
"""
def version do
@tag <> @cipher.version
end
end