CodexaCodexa

Crypto & Passwords

ID and random value generation, constant-time comparison, and PBKDF2 password hashing, all on the Web Crypto API.

@codexa/core/crypto covers the cryptographic primitives a typical backend needs, IDs, random values, and password hashing, without adding a native dependency, everything runs on the standard Web Crypto API.

IDs and random values

import { generateId, randomBytes, generateOtp } from '@codexa/core/crypto';

generateId();        // a UUID v4 string
randomBytes(16);      // 16 random bytes as a 32-character hex string
generateOtp(6);        // a 6-digit numeric code, e.g. "042817"

randomBytesRaw(length) returns the same random bytes as a Uint8Array instead of a hex string, useful when you need the raw bytes for something like a salt.

Password hashing

import { hashPassword, verifyPassword } from '@codexa/core/crypto';

const stored = await hashPassword('user-supplied-password');
// "pbkdf2$310000$<saltHex>$<hashHex>"

const ok = await verifyPassword('user-supplied-password', stored);

hashPassword uses PBKDF2-SHA256 with 310,000 iterations by default, matching current OWASP guidance, and returns a single self-describing string with the iteration count and salt embedded. verifyPassword reads the iteration count back out of that string, so hashes created with a different iteration count in the past still verify correctly even after you raise the default later.

verifyPassword compares hashes with a constant-time comparison, not ===, specifically to avoid a timing attack that could otherwise leak how many leading bytes of a guessed hash were correct.

Constant-time comparison

import { timingSafeEqual } from '@codexa/core/crypto';

timingSafeEqual(providedToken, expectedToken);

Use this whenever comparing a secret, a token, an API key, a webhook signature, against a known value. A plain === short-circuits on the first mismatched character, which measurably leaks information through response timing. timingSafeEqual always takes the same time regardless of where the strings first differ.

Encoding helpers

import { base32Encode, base32Decode, toBase64Url, fromBase64Url } from '@codexa/core/crypto';

base32Encode(bytes);   // RFC 4648 Base32, no padding, the format TOTP secrets use
toBase64Url(bytes);    // base64url, no padding, safe to put directly in a URL

Integrity digests

import { blake2bDigest } from '@codexa/core/crypto';

blake2bDigest(`${walletId}:${currency}:${balance}`); // a hex digest, 32 bytes by default

A fast, non-cryptographic-strength-dependent digest for detecting whether a piece of data changed, not a password hash. Pass a second argument to change the output length in bytes.

On this page