branca_erl

An Erlang implementation of the Branca specification for authenticated and encrypted tokens


License
Other

Documentation

branca-erl

Build Status

An Erlang implementation of the Branca specification for authenticated and encrypted tokens.

These are symmetrically encrypted, tamper-proof strings of arbitrary contents that can be safely exposed.

Installation

Add this to your rebar.config file to install the library through hex.pm:

{deps, [
    {branca_erl, "0.1.1"}
]}.

Basic Usage

1> Secret = soda:rand(32). % the spec mandates that secret keys must be exactly 32 bytes long.
<<238,191,60,162,227,35,20,3,135,35,6,69,45,10,213,250,3,
  106,71,133,119,70,131,43,173,147,60,182,122,...>>

2> Message = erlang:term_to_binary({foo, bar, baz, [1,2,3]}).
<<131,104,4,100,0,3,102,111,111,100,0,3,98,97,114,100,0,3,
  98,97,122,107,0,3,1,2,3>>

3> Token = branca:encode(Message, Secret).
<<"9GBoip8wFIboItLRutv335YmhKpa4vRX5qXKFoyABy0f8LOw9hk3Zi4I14H2AL9VKk0i6GRentlKXc9qr">>

4> {ok, Message} = branca:decode(Token, Secret).
{ok,<<131,104,4,100,0,3,102,111,111,100,0,3,98,97,114,
      100,0,3,98,97,122,107,0,3,1,2,3>>}

API

branca:encode/2

Uses Secret to turn PlainText into a Branca token using the current Unix time as the timestamp. Returns the token as an Erlang binary.

branca:encode/3

Same as above, but using a custom timestamp. If used, it must be greater than 0 and less than 2^32 (4 bytes long).

branca:decode/2

Uses Secret to turn a Branca token into the original PlainText. Returns a two-valued tuple for each possible outcome:

  • {ok, PlainText} -> successful token decryption.
  • {error, bad_encoding} -> CipherText contains at least one non-base62 character.
  • {error, invalid_token} -> CipherText is base62, but it does not have the layout of a valid Branca token.
  • {error, invalid_sig} -> the Secret used to decrypt the token is incorrect, or the token has been tampered.

branca:decode/3

Same as above, but using a TTL to determine if the token has to be considered stale. Might return any of the above tuples, plus:

  • {expired, PlainText} -> the token was successfully decrypted, but it expired (i.e. it was minted more than TTL seconds ago).

Testing

The library includes EUnit and PropEr test suites.

These can be run with the usual rebar3 commands (rebar3 eunit and rebar3 proper).

Caveats

  • The base62 encoding and decoding is based on an O(n^2) algorithm involving arithmetic division and is dog slow. On my development laptop encoding 1KB of random data takes about 100ms, and 5KB jumps to 2.5s. Future releases might try to mitigate this problem by implementing branca_transcoder as a NIF, or replace the base62 algorithm altogether (though that would make the tokens incompatible with the Branca spec and the ones produced by other implementations).

TODO

  • Travis CI build
  • Timestamp expiration
  • Spec annotations for Dialyzer
  • Improve all modules documentation