sealwd 0.5.0

Secure password and token management library for Rust, featuring hashing, encryption, and random generation.
Documentation

sealwd

sealwd provides small, focused primitives for handling secrets safely in Rust.

Designed specifically for server-side authentication systems, it enforces a strict separation between low-entropy user passwords and high-entropy machine-generated tokens. It handles memory zeroization, secure generation, policy validation, forward-compatible hashing, and optional encryption at rest.

Core Philosophy & Security Model

Passwords and tokens serve different purposes and require different cryptographic treatments:

  • Passwords are low-entropy secrets provided by users. They are hashed using Argon2id (slow, memory-hard) to resist brute-force attacks.
  • Tokens are high-entropy secrets generated by the system (e.g., session IDs, API keys, OAuth assertions). They are hashed using BLAKE3 (fast) with a server-side pepper. Using token hashing for passwords is mathematically insecure and intentionally unsupported by this crate.

Features

  • Explicit Secret Types: Distinct types for Password, stack-allocated fixed-size Token<LEN>, and heap-allocated dynamically-sized GenericToken.
  • Memory Safety: All secret containers automatically implement explicit memory zeroization on drop via the zeroize ecosystem.
  • Password Policies: Configurable rules for generation and validation (length, character classes).
  • Self-Describing Hashes: Binary serializable hashes (PasswordHash, TokenHash) with embedded algorithm versions for forward compatibility.
  • Encryption at Rest (Optional): AEAD encryption (XChaCha20-Poly1305 or AES-256-GCM-SIV) via the encryption feature, preserving domain types using compile-time marker validation (EncryptedToken<T>).
  • Framework Integrations (Optional): Direct BYTEA mappings for PostgreSQL via sqlx, and context-aware serde serialization (clean Base64 for human-readable formats, raw bytes for binary protocols).

Usage

Managing Passwords

use sealwd::{Password, PasswordPolicy};

// 1. Define a policy
let policy = PasswordPolicy::with_sane_defaults();

// 2. Generate a secure random password satisfying the policy
let password = Password::random(&policy).unwrap();

// 3. Hash the password for storage (uses Argon2id automatically)
let hash = password.to_default_hash().unwrap();

// 4. Verify a login attempt
assert!(hash.verify(&password).is_ok());

Managing High-Entropy Tokens

sealwd provides two token variants depending on your layout requirements:

  1. Token<const LEN: usize>: Optimized, stack-allocated fixed-size container utilizing constant generics.
  2. GenericToken: Heap-allocated dynamically-sized container ideal for runtime-determined lengths or external keys.

Both implement the TokenMaterial trait, sharing uniform hashing and encoding APIs.

Using Fixed-Size Stack Tokens (e.g., Session IDs, Refresh Tokens)

use sealwd::{Token, TokenMaterial};

// 1. Generate a 32-byte cryptographic token on the stack
let token = Token::<32>::random().unwrap();

// 2. Export to URL-safe Base64 string to send to the client
let encoded = token.to_base64();

// 3. Hash with a server-side pepper for database storage (uses BLAKE3)
let pepper = b"my-secret-server-pepper-value";
let token_hash = token.to_default_hash(pepper);

// 4. Verify an incoming client token directly
let client_token = Token::<32>::from_base64(&encoded).unwrap();
assert!(token_hash.verify(&client_token, pepper));

Using Dynamically-Sized Heap Tokens (e.g., OAuth Assertions, Ingested API Keys)

use sealwd::{GenericToken, TokenMaterial};

let pepper = b"my-secret-server-pepper-value";

// Instantiate from a runtime-received variable length slice
let external_key = b"some-arbitrary-length-incoming-api-key-payload";
let token = GenericToken::from_bytes(external_key);

// Or generate a secure random dynamic token of specific length
let dynamic_token = GenericToken::random(64).unwrap();

// Hash securely using uniform token pipelines
let token_hash = token.to_default_hash(pepper);

Encryption at Rest (Requires encryption feature)

When storing tokens that must be reversible (e.g., third-party external API keys), you can encrypt them before storage. The EncryptedToken<T> container uses PhantomData to enforce compile-time alignment back to your native domain model upon decryption.

use sealwd::{Token, TokenMaterial, crypto::CipherSuite};

let token = Token::<16>::random().unwrap();
let encryption_key = b"thisisa32bytekeyforrustcryptolib";

// Encrypt the token into a type-safe EncryptedToken<Token<16>> wrapper
let encrypted = token.encrypt(encryption_key, CipherSuite::XChaCha20Poly1305).unwrap();

// Decrypt back to your strictly-typed Token<16> directly
let decrypted: Token<16> = encrypted.decrypt(encryption_key).unwrap();

Feature Flags

  • encryption: Enables the crypto module, providing EncryptedPassword and EncryptedToken<T> wrappers backed by authenticated AEAD ciphers.
  • serde: Enables transparent serialization/deserialization for domain types. Intelligently routes through URL-safe Base64 for human-readable structures (JSON) and raw byte arrays for binary networks (Bincode/MessagePack).
  • sqlx: Implements sqlx::Type, Encode, and Decode allowing hashes and encrypted types to be used directly with database queries without manual container unpacking (maps to BYTEA in Postgres).

License

Apache-2.0