2 releases

0.1.1 Sep 24, 2020
0.1.0 Sep 23, 2020

#483 in Authentication

GPL-3.0-or-later

24KB
120 lines

bronco

cargo-downloads-badge api-docs-badge crates-io license-badge

Bronco provides authenticated and encrypted API tokens.

Based on the Branca specification (with slight alterations) this module provides authenticated and encrypted API tokens. Crypto primitives are provided by libsodium via the sodiumoxide library.

IETF XChaCha20-Poly1305 AEAD symmetric encryption is used to create the tokens. The encrypted token is base64-encoded, using the url-safe Base64 variant (without padding). Branca uses Base62 to ensure url safety, but since the url-safe variant of Base64 encoding is more common, we use that instead.

Security Guarantees

I provide absolutely no security guarantees whatsoever.

I am not a cryptographer. This is not an audited implementation. This does not follow the Branca specification 100%.

This a library I wrote to better understand AEAD primitives and authenticated/encrypted API tokens. I do use it in my own project, pasta6 knowing full well that I probably made some trivial mistakes.

Example

Add bronco and sodiumoxide to your dependencies:

bronco = "0.1.1"
sodiumoxide = "0.2.6"

Encoding

use bronco::encode;
use sodiumoxide::crypto::aead::xchacha20poly1305_ietf::gen_key;

sodiumoxide::init();

let key = gen_key();
let message: &str = "hello, world!";
let token: String = encode(message, key.as_ref()).unwrap();

Decoding

use bronco::decode;

// let token: &str = ...;
// let key: &[u8] = ...;
let ttl: u32 = 60; // token is valid for 1 minute
let message = decode(token, key, ttl).unwrap();
assert_eq!(message, "hello, world!");

Token Format

Tokens have a header, ciphertext, and authentication tag. The header has a version, timestamp, and nonce. Overall the token structure is:

Version (1B) || Timestamp (4B) || Nonce (24B) || Ciphertext (*B) || Tag (16B)

The ciphertext can be arbitrarily long, and will be exactly the length of the plaintext message.

The string representation of the binary token uses Base64 (URL-safe variant) encoding, with the following character set:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_

More details can be found in the Branca specification.

Keys

Keys must be 32 bytes in length. Any 32 byte slice can be used as a key, but it is highly recommended you use sodiumoxide's sodiumoxide::crypto::aead::xchacha20poly1305_ietf::gen_key function to generate truly random keys.

Implementation Details

This module has several significant changes from the Branca specification.

First, the binary token is encoded as a string using Base64 (URL-safe variant), not Base62.

Second, token payloads are assumed to be valid UTF-8. This module only allows encoding of valid UTF-8 strings, so this should never be a problem. A custom implementation could allow the encoding of arbitrary bytes into a token, so to handle non UTF-8 payloads we do a lossy UTF-8 conversion when parsing the payload. Invalid characters are replaced with the UTF-8 replacement character.

TTL is enforced for tokens, unless set to 0 at decoding time. When a token's timestamp is more than ttl seconds in the past, it is treated as a decoding error. It is not possible to specify an infinite TTL, but you can set arbitrarily large u32 values.

NOTE: TTLs which result in an integer overflow when added to the UNIX epoch timestamp are treated as invalid.

License: GPL-3.0-or-later

Dependencies

~18MB
~81K SLoC