2.4 KiB
zeroize
(no submodules)
Purpose
Best-effort overwrite of a Uint8Array with zero bytes. Secret material — private keys, AEAD keys, plaintext buffers, intermediate KDF state — should be zeroized as soon as it is no longer needed so that its remnants become unreadable if the process is later snapshotted, dumped, or forked into an attacker-controlled context.
JavaScript does not let us pin memory or guarantee the garbage collector has not already copied the underlying ArrayBuffer into a new region. zeroize is therefore a mitigation, not a guarantee. Use it in combination with narrow scoping (allocate the buffer inside a function, zeroize, return nothing sensitive) to minimise the residency window.
Features
- In-place; no allocation.
- Backed by
Uint8Array#fill(0), which is inlined to a tight memset on every modern engine. - Zero dependencies.
Usage: Basic Example
import { zeroize } from "@suaveplan/crypto-utils/zeroize";
const key = new Uint8Array(32);
// …use the key…
zeroize(key);
Usage: Advanced Example
import { zeroize } from "@suaveplan/crypto-utils/zeroize";
import { concatBytes } from "@suaveplan/crypto-utils/bytes";
function withScopedSecret<T>(
secretBuilder: () => Uint8Array,
fn: (secret: Uint8Array) => T
): T {
const secret = secretBuilder();
try {
return fn(secret);
} finally {
zeroize(secret);
}
}
withScopedSecret(
() => concatBytes(new Uint8Array(16).fill(0xaa), new Uint8Array(16).fill(0xbb)),
(key) => {
// key is live inside this block only
return key.length;
}
);
API Reference
zeroize(buf: Uint8Array): void— fillsbufwith0in place. Returns nothing. Never throws.
Implementation Notes
Uint8Array#fill(0) is the minimum the runtime can do without dropping into node:buffer or platform-specific APIs. Some environments (OpenSSL-linked node:crypto) expose sodium_memzero-equivalents that are marked volatile to prevent compiler dead-store elimination; we do not rely on those here because they are not available in browsers or edge runtimes, and cross-runtime consistency is more valuable than the marginal hardening on Node. Engines do not currently eliminate Uint8Array#fill as dead, but a future JIT optimisation could; revisit this helper if dudect-style analysis reports leakage.