Skip to main content

README.md

# barrel_crypto

Encryption primitives and key providers for Barrel's encryption at rest.
Provides an AES-256-GCM envelope with HKDF-SHA256 key derivation,
offset-addressable AES-256-CTR for sector-encrypted flat files, key-check
tokens for fail-closed wrong-key detection, and the `barrel_keyprovider`
behaviour that maps a database keyspace to its 256-bit key.

[Documentation](https://barrel-db.eu/docs/lib/crypto/) |
[HexDocs](https://hexdocs.pm/barrel_crypto) |
[Repository](https://github.com/barrel-db/barrel)

Encryption is off by default. Databases opt in with an encryption spec at
open: `default` resolves keys through `barrel_keyprovider_env`
(`BARREL_ENCRYPTION_KEY` as 32 raw bytes, 64 hex chars, or a passphrase;
per-database keys are derived from it with the keyspace as HKDF info), and
`#{provider => Mod}` plugs in a custom provider (KMS, token-derived).

## Use

```erlang
{ok, Key} = barrel_keyprovider:key_for_db(default, <<"mydb">>),

%% GCM envelope for whole values
Enc = barrel_crypto:encrypt(<<"secret">>, Key),
true = barrel_crypto:is_encrypted(Enc),
<<"secret">> = barrel_crypto:decrypt(Enc, Key),

%% offset-addressable CTR for flat files
Nonce = barrel_crypto:new_nonce(8),
Ct = barrel_crypto:ctr_crypt(Key, Nonce, 0, <<"some file bytes">>),
<<"file">> = barrel_crypto:ctr_crypt(Key, Nonce, 5, binary:part(Ct, 5, 4)),

%% wrong-key detection without key material on disk
Token = barrel_crypto:key_check_new(Key),
true = barrel_crypto:key_check_verify(Key, Token).
```

`barrel_crypto:decrypt/2` returns unencrypted input unchanged, so it is safe
to call on values written before encryption was enabled.

## Custom provider

```erlang
-module(my_kms_provider).
-behaviour(barrel_keyprovider).
-export([key_for_db/1]).

key_for_db(Keyspace) ->
    {ok, my_kms:fetch_data_key(Keyspace)}.  %% must be exactly 32 bytes
```