obcrypt 0.2.0

Bytes-in/bytes-out cryptographic core of the oboron protocol (a-tier + u-tier schemes, no encoding).
Documentation

obcrypt

Crates.io Documentation License: MIT

The bytes-in / bytes-out cryptographic core of the oboron protocol.

obcrypt implements oboron's a-tier (authenticated) and u-tier (unauthenticated) encryption schemes operating on raw byte slices. It does not perform any text encoding (no base64, no base32, no hex) and does not validate UTF-8 — plaintext bytes pass through unchanged.

For the full string-in / string-out oboron protocol (with obtext encoding, format strings, and the z-tier obfuscation schemes), use the oboron crate, which depends on this crate.

Keys do have a canonical text form: hex (128 lowercase characters). Key::from_hex / Key::to_hex handle that. obcrypt intentionally does not support other key encodings (base64, base32, …) — in cryptography clarity beats compactness, and the size saving of base64 over hex (86 vs 128 chars for a 64-byte key) isn't enough to justify the visual noise.

When to use which

obcrypt oboron
Input / output &[u8] / Vec<u8> &str / String
Encoding none base64 / base32 / hex
UTF-8 validation no yes
Schemes a-tier, u-tier a-tier, u-tier, z-tier
Intended use binary contexts, embedded, low-level integration text contexts, identifiers, URLs

Quick start

use obcrypt::{encrypt, decrypt, Key, Scheme};

let key = Key::random();
let payload = encrypt(b"secret data", Scheme::Aasv, &key)?;
let plaintext = decrypt(&payload, &key)?;
assert_eq!(plaintext, b"secret data");
# Ok::<(), obcrypt::Error>(())

Schemes

Each scheme is a 4-letter identifier of the form <tier><props><alg>. Pick by what you need first; the table below ranks the schemes within each row by recommended preference.

Tier Properties Algorithm Schemes (preferred → fallback)
a (authenticated) deterministic SIV / GCM-SIV aasvaags
a (authenticated) probabilistic SIV / GCM-SIV apsvapgs
u (unauthenticated, secure) probabilistic CBC upbc

Scheme decision matrix:

  • Need authentication? Use an a-tier scheme (aasv / apsv / aags / apgs). u-tier upbc provides confidentiality only — pair with an outer authenticator if you use it.
  • Need same-plaintext-same-ciphertext? (e.g. for stable IDs or encrypted lookups.) Use a deterministic variant (aasv, aags).
  • Need different-ciphertext-each-call? Use a probabilistic variant (apsv, apgs, upbc).
  • Want broad nonce-misuse resistance? Prefer SIV variants (aasv, apsv) — they degrade gracefully under accidental nonce reuse.
  • Want smallest footprint / fastest on AES-NI hardware? Prefer GCM-SIV variants (aags, apgs).

Plus testing-only schemes behind the mock feature flag — mock1 (identity) and mock2 (reverse). They perform no encryption and exist solely for round-tripping unit tests, layering benchmarks, and as inert fallbacks. Never enable mock in a production build.

See SECURITY.md for the full threat model and algorithm justification.

Framed payload format

For every scheme, the framed payload returned by encrypt is:

[ scheme ciphertext bytes ][ marker[0] ^ ct[0] ][ marker[1] ^ ct[0] ]
  • scheme ciphertext bytes — whatever the per-scheme primitive produces (for AEAD schemes that's nonce || ct || tag for the probabilistic ones, or ct || tag for the deterministic ones).
  • marker — the 2-byte Scheme identifier.
  • The XOR with ct[0] mixes entropy into the marker so it doesn't appear as a constant trailer on short payloads.

decrypt reverses this, dispatching on the recovered marker; decrypt_as additionally checks that the marker matches the caller-supplied scheme.

API

Two parallel forms are provided for every operation:

  • Owned: returns a fresh Vec<u8>. Convenient.
  • _into: appends to a caller-provided &mut Vec<u8>. Lets integrators (notably oboron) avoid an intermediate buffer allocation when piping output to a downstream encoder.
pub fn encrypt(plaintext: &[u8], scheme: Scheme, key: &Key) -> Result<Vec<u8>, Error>;
pub fn encrypt_into(plaintext: &[u8], scheme: Scheme, key: &Key, out: &mut Vec<u8>) -> Result<(), Error>;

pub fn decrypt(payload: &[u8], key: &Key) -> Result<Vec<u8>, Error>;
pub fn decrypt_into(payload: &[u8], key: &Key, out: &mut Vec<u8>) -> Result<(), Error>;

pub fn decrypt_as(payload: &[u8], scheme: Scheme, key: &Key) -> Result<Vec<u8>, Error>;
pub fn decrypt_as_into(payload: &[u8], scheme: Scheme, key: &Key, out: &mut Vec<u8>) -> Result<(), Error>;

decrypt auto-dispatches on the trailing marker; decrypt_as additionally verifies the marker matches an expected scheme.

Raw per-scheme primitives (without framing) live under obcrypt::schemes::{aasv, aags, apsv, apgs, upbc, ...} for callers that want to manage the marker themselves — e.g. integrators that already track the scheme in a separate field, or hot-path consumers that want to skip the dispatch. Each scheme module exposes the same four functions: encrypt, encrypt_into, decrypt, decrypt_into.

Performance

obcrypt is designed for low-overhead embedding in performance- sensitive paths (the oboron crate uses it on every enc / dec call). Notable choices:

  • The owned encrypt / decrypt calls the underlying AEAD's exact-capacity allocator, avoiding intermediate buffers.
  • The _into form writes ciphertext directly into the caller's buffer via aead::encrypt_in_place, with a private TailBuffer adapter to scope the in-place region — zero extra allocations.
  • All public functions are #[inline]. Combined with workspace- level LTO (which the parent workspace Cargo.toml enables), the cross-crate boundary collapses on the hot path.

Cargo features

See FEATURES.md for the full matrix. By default every production scheme (aags, apgs, aasv, apsv, upbc) is enabled; schemes are individually gated so binary size scales with what you actually use.

Versioning

Pre-1.0; the Rust API may evolve across 0.x minor releases. See CHANGELOG.md for release notes. The framed payload format and the Scheme::marker byte assignments are bound to the oboron protocol spec and are stable across the 0.x series — a payload produced by any obcrypt 0.x build decrypts under any other 0.x build with the matching scheme feature enabled.

License

MIT — see LICENSE.