Hashing, HMAC & Utilities

Hashing

const digest = await enc.hash('my-token', 'sha256', 'hex');
hash(input: string | Uint8Array, algorithm?: 'sha256' | 'sha384' | 'sha512', encoding?: 'hex' | 'base64' | 'base64url'): Promise<string>

HMAC

When no key is passed, the client signs with its raw master key (intentional default for signing your own data). Verification decodes the signature and compares bytes in constant time (Node’s native crypto.timingSafeEqual where available, a constant-time JS loop in browsers/edge).

const sig   = await enc.hmac(webhookBody);
const valid = await enc.verifyHmac(webhookBody, sig); // constant-time

Key encoding. A key is either raw bytes (Uint8Array) or a string decoded per keyEncoding:

keyEncoding String key is…
'hex' (default) hex-decoded — same as 1.0.0. Non-hex or odd-length strings throw INVALID_KEY.
'utf8' used as UTF-8 bytes — equivalent to Node’s createHmac(alg, secret). Use for Shopify, WooCommerce, EKM, Etsy webhook secrets.
'base64' / 'base64url' base64-decoded.

Passing keyEncoding without a key throws instead of falling back to the master key.

// Shopify: X-Shopify-Hmac-Sha256 = base64(HMAC-SHA256(rawBody, secret))
const ok = await verifyHmac(rawBody, secret, header, { keyEncoding: 'utf8', encoding: 'base64' });
type HmacKey = string | Uint8Array;
interface HmacOptions {
  algorithm?: HashAlgorithm;                       // default 'sha256' (client: its hashAlgorithm)
  encoding?: 'hex' | 'base64' | 'base64url';        // output / signature encoding, default 'hex'
  keyEncoding?: 'hex' | 'utf8' | 'base64' | 'base64url'; // default 'hex'
}

// Standalone
hmac(message: string | Uint8Array, key: HmacKey, algorithm?: HashAlgorithm, encoding?: HmacOutputEncoding): Promise<string>
hmac(message: string | Uint8Array, key: HmacKey, options?: HmacOptions): Promise<string>
verifyHmac(message: string | Uint8Array, key: HmacKey, signature: string, algorithm?: HashAlgorithm, encoding?: HmacOutputEncoding): Promise<boolean>
verifyHmac(message: string | Uint8Array, key: HmacKey, signature: string, options?: HmacOptions): Promise<boolean>

// EncryptixClient (key optional → master key)
enc.hmac(message, key?, algorithm?, encoding?) / enc.hmac(message, key | undefined, options)
enc.verifyHmac(message, signature, key?, algorithm?, encoding?) / enc.verifyHmac(message, signature, key | undefined, options)

Random tokens & IDs

const token  = enc.generateToken(32, 'hex'); // 64-char hex
const apiKey = enc.generateApiKey('sk');      // 'sk_4xG9cN7m...'
const uuid   = enc.generateUUID();            // UUID v4

Secure randomness

Standalone, cryptographically secure random helpers (all bias-free).

import {
  secureRandomBytes, secureRandomInt, secureRandomString,
  secureRandomChoice, secureRandomSample, secureRandomShuffle,
  securePassphrase, CHARSETS,
} from '@scriptixlabs/encryptix';

secureRandomBytes(32);                       // Uint8Array(32)
secureRandomInt(1, 100);                     // unbiased integer in [1, 100]
secureRandomString(16, 'alphanumeric');      // or a CHARSETS key / custom charset
secureRandomChoice(['a', 'b', 'c']);         // one element
secureRandomSample(items, 3);                // 3 distinct elements
secureRandomShuffle(items);                  // Fisher–Yates shuffle
securePassphrase(wordList, 5, '-');          // 'stone-river-proud-flame-oak'
Function Returns
secureRandomBytes(n) Uint8Array of n random bytes
secureRandomInt(min, max) Unbiased integer in [min, max]
secureRandomFloat() Float in [0, 1)
secureRandomString(length, charset?) Random string
secureRandomChoice(array) One random element
secureRandomSample(array, n) n distinct random elements
secureRandomShuffle(array) Shuffled copy
securePassphrase(wordList, count?, sep?) Word-based passphrase
CHARSETS Named charsets for secureRandomString

Encoding

import { base32Encode, hexEncode, base64urlEncode, convertEncoding, safeCompare } from '@scriptixlabs/encryptix';

base32Encode/Decode, hexEncode/Decode, base64Encode/Decode, base64urlEncode, and convertEncoding(value, from, to) convert between encodings. safeCompare(a, b) is a constant-time equality check for secrets.

Payload inspection

Decode metadata from a payload/token without the key — handy for debugging and routing.

import { inspectPayload, inspectStreamHeader, inspectToken } from '@scriptixlabs/encryptix';

enc.inspectPayload(payload);   // → { version, algorithm, keyVersion, ... }
inspectStreamHeader(header);   // stream magic/version/algo/chunk size
inspectToken(token);           // signed-token header + claims (unverified)
ℹ️

Inspection never decrypts or verifies — it only parses public header fields. Never trust inspected claims for authorization; use verify() instead.