Skip to content

Commit

Permalink
Switch to Jason, update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
danielberkompas committed Dec 31, 2018
1 parent dfab4f5 commit ead16b1
Show file tree
Hide file tree
Showing 12 changed files with 225 additions and 455 deletions.
109 changes: 62 additions & 47 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,72 +6,87 @@ Cloak
[![Inline docs](http://inch-ci.org/github/danielberkompas/cloak.svg?branch=master)](http://inch-ci.org/github/danielberkompas/cloak)
[![Coverage Status](https://coveralls.io/repos/github/danielberkompas/cloak/badge.svg?branch=migrate)](https://coveralls.io/github/danielberkompas/cloak?branch=migrate)

Cloak makes it easy to encrypt fields in your [Ecto](https://github.com/elixir-ecto/ecto) schemas.
Cloak is an Elixir encryption library that implements several best practices
and conveniences for Elixir developers:

- [Hex Documentation](https://hexdocs.pm/cloak)
- [How to upgrade from Cloak 0.6.x to 0.7.x](https://hexdocs.pm/cloak/0.7.0/0.6.x_to_0.7.x.html)
- Random IVs
- Tagged ciphertexts
- Elixir-native configuration

## Example
## Documentation

Fields are encrypted with custom `Ecto.Type` modules which Cloak helps you
create.
- [Hex Documentation](https://hexdocs.pm/cloak) (Includes installation guide)
- [How to upgrade from Cloak 0.9.x to 1.0.x](https://hexdocs.pm/cloak/0.9.x_to_1.0.x.html)

```elixir
defmodule MyApp.EctoSchema do
use Ecto.Schema
## Examples

schema "table_name" do
field :encrypted_field, MyApp.Encrypted.Binary
### Encrypt / Decrypt

# ...
end
end
```elixir
{:ok, ciphertext} = MyApp.Vault.encrypt("plaintext")
# => {:ok, <<1, 10, 65, 69, 83, 46, 71, 67, 77, 46, 86, 49, 45, 1, 250, 221,
# => 189, 64, 26, 214, 26, 147, 171, 101, 181, 158, 224, 117, 10, 254, 140, 207,
# => 215, 98, 208, 208, 174, 162, 33, 197, 179, 56, 236, 71, 81, 67, 85, 229,
# => ...>>}

MyApp.Vault.decrypt(ciphertext)
# => {:ok, "plaintext"}
```

When Ecto writes these fields to the database, it encrypts the values into
a binary blob, using a configured encryption algorithm chosen by you.
### Reencrypt With New Algorithm/Key

```console
iex> Repo.insert!(%MyApp.EctoSchema{encrypted_field: "plaintext"})
08:46:08.862 [debug] QUERY OK db=3.4ms
INSERT INTO "table_name" ("encrypted_field") VALUES ($1) RETURNING "id", "encrypted_field" [<<1,10, 65, 69, 83, 46, 67, 84, 82, 46, 86, 49, 69, 92, 173, 219, 203, 238, 26, 58, 236, 5, 104, 23, 12, 10, 182, 31, 221, 89, 22, 58, 34, 79, 109, 30, 70, 254, 56, 93, 102, 84>>]
```elixir
"plaintext"
|> MyApp.Vault.encrypt!(:aes_gcm)
|> MyApp.Vault.decrypt!()
|> MyApp.Vault.encrypt!(:aes_ctr)
|> MyApp.Vault.decrypt!()
# => "plaintext"
```

Likewise, when Ecto reads the field out of the database, it will automatically
decrypt the value.
### Configuration

```elixir
iex> Repo.get(MyApp.EctoSchema, 1)
%MyApp.EctoSchema{encrypted_field: "plaintext"}
config :my_app, MyApp.Vault,
ciphers: [
aes_gcm: {Cloak.Ciphers.AES.GCM, tag: "AES.GCM.V1", key: <<...>>},
aes_ctr: {Cloak.Ciphers.AES.CTR, tag: "AES.CTR.V1", key: <<...>>}
]
```

## Notable Features
## Features

- Transparent, easy to use encryption for database fields
- Fully compatible with umbrella projects (as of 0.7.0)
- Bring your own encryption algorithm, if you want
- Mix task for key rotation: `mix cloak.migrate`
### Random Initialization Vectors (IV)

## Security Notes
Every strong encryption algorithm recommends unique initialization vectors.
Cloak automatically generates unique vectors using
`:crypto.strong_rand_bytes`, and includes the IV in the ciphertext.
This greatly simplifies storage and is not a security risk.

### Tagged Ciphertext

- **Supported Algorithms**: Cloak's built-in encryption modules rely on Erlang's
`:crypto` module. Cloak supports the following algorithms out of the box:

- AES.GCM
- AES.CTR
Each ciphertext contains metadata about the algorithm and key which was used
to encrypt it. This allows Cloak to automatically select the correct key and
algorithm to use for decryption for any given ciphertext.

- **Encrypted Data Not Searchable**: Cloak uses random IVs for each ciphertext. This
means that the same value will not encrypt to the same value twice. As a result,
encrypted columns are not queryable. However, Cloak does provide easy ways to
create hashed, searchable columns.
This makes key rotation much easier, because you can easily tell whether any
given ciphertext is using the old key or the new key.

- **Runtime Data is not Encrypted**: Cloak encrypts data _at rest_ in the database.
The data in your Ecto structs at runtime is not encrypted.
### Elixir-Native Configuration

- **No Support for User-specific Encryption Keys**: Cloak's `Ecto.Type` modules do not
support user-specific encryption keys, due to limitations on the `Ecto.Type`
behaviour. However, you can still use Cloak's ciphers to implement these in your
application logic.
Cloak works through `Vault` modules which you define in your app, and add
to your supervision tree.

You can have as many vaults as you wish running simultaneously in your
project. (This works well with umbrella apps, or any runtime environment
where you have multiple OTP apps using Cloak)

### Ecto Support

You can use Cloak to transparently encrypt Ecto fields, using
[`cloak_ecto`](https://hex.pm/packages/cloak_ecto).

## Security Notes

## Migrating from 0.6.x
Updating to Cloak versions `0.7.0` and higher will require changes to your configuration and Ecto models. Please see the [0.6.x to 0.7.x Migration Guide](https://hexdocs.pm/cloak/0.6.x_to_0.7.x.html) for a full summary of changes and upgrade instructions.
- Cloak is built on Erlang's `crypto` library, and therefore inherits its security.
- You can implement your own cipher modules to use with Cloak, which may use any other encryption algorithms of your choice.
2 changes: 1 addition & 1 deletion config/test.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use Mix.Config

config :cloak, Cloak.TestVault,
json_library: Poison,
json_library: Jason,
ciphers: [
default:
{Cloak.Ciphers.AES.GCM,
Expand Down
106 changes: 0 additions & 106 deletions guides/how_to/encrypt_existing_data.md

This file was deleted.

83 changes: 18 additions & 65 deletions guides/how_to/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This guide will walk you through installing Cloak in your project.

First, add `:cloak` to your dependencies in `mix.exs`:

{:cloak, "~> 0.9.2"}
{:cloak, "1.0.0-alpha.0"}

Run `mix deps.get` to fetch the dependency.

Expand Down Expand Up @@ -73,75 +73,28 @@ Finally, add your vault to your supervision tree.
MyApp.Vault
]

### Create Local Ecto Types

For each type of data you want to encrypt, define a local Ecto type like so.

defmodule MyApp.Encrypted.Binary do
use Cloak.Fields.Binary, vault: MyApp.Vault
end

You can find a complete list of available types in the "MODULES" documentation.

### Create Your Schema

If you want to encrypt an existing schema, see the guide on [Encrypting
Existing Data](encrypt_existing_data.html).

If you're starting from scratch with a new `Ecto.Schema`, it's enough to
generate the migration with the correct fields, for example:

create table(:users) do
add :email, :binary
add :email_hash, :binary # will be used for searching
# ...

timestamps()
end

The schema module should look like this:

defmodule MyApp.Accounts.User do
use Ecto.Schema

import Ecto.Changeset

schema "users" do
field :email, MyApp.Encrypted.Binary
field :email_hash, Cloak.Fields.SHA256
# ... other fields

timestamps()
end

@doc false
def changeset(struct, attrs \\ %{}) do
struct
|> cast(attrs, [:email])
|> put_hashed_fields()
end
## Usage

defp put_hashed_fields(changeset) do
changeset
|> put_change(:email_hash, get_field(changeset, :email))
end
end
You can now encrypt and decrypt values using your Vault.

This example also shows how you would make a given field queryable by
creating a mirrored `_hash` field. See `Cloak.Fields.SHA256` or
`Cloak.Fields.HMAC` for more details.
{:ok, ciphertext} = MyApp.Vault.encrypt("plaintext")
# => {:ok, <<1, 10, 65, 69, 83, 46, 71, 67, 77, 46, 86, 49, 93, 140, 255, 234,
1, 195, 125, 112, 121, 186, 169, 185, 129, 122, 237, 161, 160, 24, 166,
48, 224, 230, 53, 194, 251, 175, 215, 10, 186, 130, 61, 230, 176, 102,
213, 209, ...>>}

## Usage
MyApp.Vault.decrypt(ciphertext)
{:ok, "plaintext"}

Your encrypted fields will be transparently encrypted and decrypted as
data are loaded from the database.
By default, the first configured key will be used. You can use a specific key
to use by referencing its label:

Repo.get(Accounts.User, 1)
# => %Accounts.User{email: "[email protected]", email_hash: <<115, 6, 45, 135, 41, ...>>}
MyApp.Vault.encrypt("plaintext", :default)

You can query by the mirrored `_hash` fields:
Decryption will use the metadata embedded in the ciphertext to decide which
configured key to use.

Repo.get_by(Accounts.User, email_hash: "[email protected]")
# => %Accounts.User{email: "[email protected]", ...}
## Usage with Ecto

And you're done! Cloak is successfully installed.
If you want to use Cloak to automatically encrypt and decrypt fields in your
`Ecto` schemas, see [`cloak_ecto`](https://hex.pm/packages/cloak_ecto).
Loading

0 comments on commit ead16b1

Please sign in to comment.