@wrnexus/encryption
Hashing, HMAC, authenticated encryption, and key derivation.
Private registry access required
This package is not available from the public npm registry. After WorkRoot approves access and supplies private registry instructions, install the release-aligned package:
bun add @wrnexus/encryption@0.2.57Request preview access. Never put registry tokens in source control.
Dependency-free crypto helpers for WRNexusJS: authenticated symmetric encryption (AES-256-GCM), hashing, and HMAC signing.
Part of the WRNexusJS framework — an SSR-first, Bun-native full-stack web framework.
Overview
This package provides small, focused cryptographic primitives for server-side use: encrypting secrets/tokens/database fields at rest with AES-256-GCM, deriving keys from passwords via PBKDF2, computing SHA-256 digests, and signing/verifying payloads with HMAC-SHA256. It is built entirely on the standard Web Crypto API (crypto.subtle) plus btoa/atob and TextEncoder/TextDecoder — no third-party dependencies. Reach for it whenever you need to protect sensitive values or verify webhook signatures. All functions are async (Web Crypto is promise-based).
bun add @wrnexus/encryption
Private package — the machine must be authenticated to the wrnexus npm org
(a read token in ~/.npmrc). Requires Bun (Node is not supported).
API
All keys are exchanged as base64 strings and all digests/signatures as hex strings.
| Export | Signature | Description |
|---|---|---|
generateKey | () => Promise<string> | Generate a random 256-bit AES key, base64-encoded. Store it as a secret. |
deriveKey | (password: string, salt: string) => Promise<string> | Derive a base64 AES-256 key from a password + salt using PBKDF2 (100,000 iterations, SHA-256). |
encrypt | (plaintext: string, key: string) => Promise<string> | AES-256-GCM encrypt a string. Returns base64 of iv(12 bytes) ‖ ciphertext+tag. A fresh random IV is used each call. |
decrypt | (payload: string, key: string) => Promise<string> | Decrypt a value produced by encrypt. Throws if the key is wrong or the data was tampered with. |
sha256 | (data: string) => Promise<string> | SHA-256 hex digest of a string (e.g. content hashing, dedup keys). |
hmacSign | (data: string, secret: string) => Promise<string> | HMAC-SHA256 hex signature of data with secret (e.g. signing webhooks). |
hmacVerify | (data: string, secret: string, signature: string) => Promise<boolean> | Constant-time verify of an HMAC-SHA256 hex signature. |
Notes:
generateKeyproduces a 32-byte (256-bit) key viacrypto.getRandomValues.encrypt/decryptrequire a base64-encoded 256-bit key; anything else throws"Encryption key must be a base64 256-bit key".decryptthrows"Invalid ciphertext"if the payload is shorter than the 12-byte IV, and the underlying Web Crypto call throws on any authentication (tag) mismatch.hmacVerifycompares in constant time (length check plus XOR accumulation) to avoid timing leaks.
Usage
Symmetric encryption of a secret at rest:
import { generateKey, encrypt, decrypt } from "@wrnexus/encryption";
const key = await generateKey(); // store this safely (env/secret manager)
const box = await encrypt("card #1234", key); // opaque base64 string, safe to persist
const plain = await decrypt(box, key); // "card #1234"
Deriving a key from a user password instead of a random key:
import { deriveKey, encrypt } from "@wrnexus/encryption";
const key = await deriveKey("correct horse battery staple", "per-user-salt");
const box = await encrypt("secret note", key);
Hashing and webhook signature verification:
import { sha256, hmacSign, hmacVerify } from "@wrnexus/encryption";
const digest = await sha256("some content"); // 64-char hex string
const signature = await hmacSign(rawBody, webhookSecret);
const ok = await hmacVerify(rawBody, webhookSecret, incomingSignatureHeader);
if (!ok) throw new Error("Invalid webhook signature");
Requirements / Notes
- Bun-only. Relies on the Web Crypto API (
crypto.subtle,crypto.getRandomValues) and the globalbtoa/atob,TextEncoder/TextDecoder— all available in Bun's runtime. - No dependencies. The package has an empty dependency set; nothing is bundled beyond standard runtime APIs.
- Algorithms: AES-256-GCM (encryption), PBKDF2 with 100k SHA-256 iterations (key derivation), SHA-256 (digest), HMAC-SHA256 (signing).
- Keep generated/derived keys and HMAC secrets out of source control; treat them as first-class secrets.
Complete TypeScript API
This declaration comes from the exact installed package and lists its exported functions, classes, interfaces, and types.
/**
* @wrnexus/encryption — authenticated symmetric encryption (AES-256-GCM) via
* WebCrypto, dependency-free. Use it to encrypt secrets, tokens, or database
* fields at rest.
*
* const key = await generateKey(); // store this safely
* const box = await encrypt("card #1234", key); // opaque base64 string
* const plain = await decrypt(box, key); // "card #1234"
*
* A key derived from a password (PBKDF2) is also supported via `deriveKey`.
*/
/** SHA-256 hex digest of a string (e.g. content hashing, dedup keys). */
declare function sha256(data: string): Promise<string>;
/** HMAC-SHA256 hex signature of `data` with `secret` (e.g. signing webhooks). */
declare function hmacSign(data: string, secret: string): Promise<string>;
/** Constant-time verify of an HMAC-SHA256 signature. */
declare function hmacVerify(data: string, secret: string, signature: string): Promise<boolean>;
/** Generate a random 256-bit key, base64-encoded. Store it as a secret. */
declare function generateKey(): Promise<string>;
/**
* Encrypt a string. Output is base64 of `iv(12) || ciphertext+tag`, safe to
* store or transmit. Each call uses a fresh random IV.
*/
declare function encrypt(plaintext: string, key: string): Promise<string>;
/** Decrypt a value produced by `encrypt`. Throws if the key is wrong or data tampered. */
declare function decrypt(payload: string, key: string): Promise<string>;
/** Derive a base64 AES key from a password + salt (PBKDF2, 100k iterations). */
declare function deriveKey(password: string, salt: string): Promise<string>;
export { decrypt, deriveKey, encrypt, generateKey, hmacSign, hmacVerify, sha256 };
Examples
Examples are taken from this package's installed documentation and must be evaluated with its requirements and stability notes.
Symmetric encryption of a secret at rest
import { generateKey, encrypt, decrypt } from "@wrnexus/encryption";
const key = await generateKey(); // store this safely (env/secret manager)
const box = await encrypt("card #1234", key); // opaque base64 string, safe to persist
const plain = await decrypt(box, key); // "card #1234"Deriving a key from a user password instead of a random key
import { deriveKey, encrypt } from "@wrnexus/encryption";
const key = await deriveKey("correct horse battery staple", "per-user-salt");
const box = await encrypt("secret note", key);Hashing and webhook signature verification
import { sha256, hmacSign, hmacVerify } from "@wrnexus/encryption";
const digest = await sha256("some content"); // 64-char hex string
const signature = await hmacSign(rawBody, webhookSecret);
const ok = await hmacVerify(rawBody, webhookSecret, incomingSignatureHeader);
if (!ok) throw new Error("Invalid webhook signature");