# SecureBuffer _(no submodules)_ ## Purpose `SecureBuffer` is the canonical envelope for sensitive cryptographic material in `@suaveplan/crypto-vault`. It owns a private `Uint8Array`, exposes an opt-in `bytes` accessor, and overwrites the backing storage with zero bytes the moment `close()` is called. A module-level registry of `WeakRef` lets `zeroizeAll()` sweep every live buffer in one call — useful on lock, on a security event, or as a final process-shutdown hook. Strings and JSON serializations are masked so the buffer can never leak through accidental logging. ## Features - Eager zeroization via `Uint8Array#fill(0)` on `close()`. - Idempotent close (`close()` after `close()` is a no-op). - Clone isolation — `clone()` allocates a fresh independent backing store. - Slice copy semantics — `slice()` returns a fresh `Uint8Array`; the caller cannot mutate the buffer through the result. - Random fill via `fillRandom(rng?)` (uses `crypto.getRandomValues` by default; honours an injected `Rng` with `nextBytes`). - `toString` and `toJSON` print only `length` and `closed` flags. - Global `zeroizeAll()` sweeps every reachable `SecureBuffer` and closes it. ## Usage: Basic Example ```ts import { SecureBuffer } from "@suaveplan/crypto-vault/secure/secure-buffer"; const buf = new SecureBuffer(32); buf.fillRandom(); // ... use buf.bytes ... buf.close(); ``` ## Usage: Advanced Example ```ts import { SecureBuffer, zeroizeAll, } from "@suaveplan/crypto-vault/secure/secure-buffer"; // Initialise from existing key material — copied, never shared. const seed = new Uint8Array(32).fill(7); const masterBuf = new SecureBuffer(seed); // Clone for an isolated branch derivation. const branch = masterBuf.clone(); branch.bytes[0] = 1; console.log(masterBuf.bytes[0]); // 7 — clone is fully isolated // Lock everything in one shot. zeroizeAll(); console.log(masterBuf.isClosed); // true console.log(branch.isClosed); // true ``` ## API Reference ### `class SecureBuffer` #### `new SecureBuffer(lengthOrSource, options?)` - `lengthOrSource: number | Uint8Array`. A `number` allocates a fresh zero-filled buffer of that length. A `Uint8Array` is **copied** into the internal store — the buffer never aliases caller storage. - `options?: SecureBufferOptions = { clock?, rng? }`. Reserved for future allocation telemetry; `fillRandom` reads `rng` directly. Throws `CryptoVaultError(CRYPTOVAULT.SECURE.INVALID_LENGTH)` when the numeric length is negative or non-integer. #### `bytes: Uint8Array` Mutable view of the live bytes. Throws `CryptoVaultError(CRYPTOVAULT.SECURE.ZEROIZED)` once the buffer has been closed. #### `length: number`, `isClosed: boolean` Length of the backing store and the closed flag. #### `close(): void` Overwrite the bytes with zeros and mark closed. Idempotent. #### `clone(): SecureBuffer` Allocate a fresh `SecureBuffer` with a copy of the current bytes. #### `slice(start?, end?): Uint8Array` Copy a range out into a new `Uint8Array`. The result is not registered. #### `fillRandom(rng?): void` Fill the bytes with CSPRNG output. Honours `rng?.nextBytes(n)` when provided; otherwise falls back to `crypto.getRandomValues`. #### `toString()`, `toJSON()` Return `[SecureBuffer length= closed=]` and a structurally equivalent JSON object — never the raw bytes. ### `zeroizeAll(): void` Walk every live `WeakRef` in the module-level registry, call `close()` on each non-closed instance, and prune the registry. ### `liveSecureBufferCount(): number` Test helper — prune dead refs and return the number of live entries. ## Implementation Notes - The registry stores `WeakRef`s so registered buffers can still be garbage-collected normally. - JavaScript cannot guarantee the GC has not relocated memory before `close()`, so eager zeroization is best-effort. Combine with aggressive scoping: allocate inside a function, close, return nothing sensitive. - Memory-locking (`mlock`) is intentionally out of scope. A future native binding will plug in via the `SecureBufferOptions` bag without breaking callers.