npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

secure-hash-vault

v1.2.0

Published

Enterprise-minded, dependency-free Node.js security toolkit for scrypt password hashing, AES-256-GCM encryption, atomic file protection, key rotation, AAD, and TypeScript.

Readme

Secure Hash Vault v1.2.0

npm version npm downloads license Node.js TypeScript BSG Technologies

Secure Hash Vault is a custom-owned, zero-runtime-dependency Node.js and TypeScript security library for password hashing, authenticated encryption, failure-safe file protection, key rotation, and security-aware migrations.

🎓 Learn Here: Start Without Crypto Confusion

New developer? You are in the right place. This page explains which function to choose, what every parameter means, what the function returns, what output looks like, which errors to catch, and where to use it in a real application.

✅ Beginner-friendly lessons | ✅ Copy-ready examples | ✅ Output previews | ✅ Error handling | ✅ Enterprise-oriented workflows

| Project signature | Details | | --- | --- | | 👨‍💻 Author | Pradeep Kumar Sheoran (Stack Developer) | | 🏢 Company | BSG Technologies | | 📞 Contact / WhatsApp | +91-8595147850 | | 🌐 Official website | Visit BSG Technologies to meet, learn, contribute, discuss new topics, and accept a coffee invitation |

Security note: this library uses Node.js cryptographic primitives and does not invent a custom cipher. “Enterprise-oriented” describes the included controls and workflows; it is not a claim of independent security certification.

📚 Table Of Contents

⚡ Quick Start

Install

npm install secure-hash-vault

Hash and verify a password

import { hashPassword, verifyPassword } from "secure-hash-vault";

const saved = await hashPassword("MyPassword@123");
console.log(saved.hash);

const login = await verifyPassword("MyPassword@123", saved.hash);
console.log(login.valid);

Output:

$cv$v1$scrypt$N=32768,r=8,p=3,keyLen=64$...
true

Encrypt and decrypt application data

import { decryptJson, encryptJson } from "secure-hash-vault";

const encrypted = await encryptJson(
  { customerId: 42, plan: "enterprise" },
  process.env.VAULT_SECRET!,
  { keyId: "prod-2026-07", aad: "tenant:acme" }
);

const data = await decryptJson(encrypted, process.env.VAULT_SECRET!, {
  aad: "tenant:acme"
});

console.log(data);

Output:

{ customerId: 42, plan: 'enterprise' }

🧭 How It Works

Password flow:

🧑 User password → 🧂 Random salt → 🛡️ scrypt → 🗄️ Store one-way hash → ✅ Verify during login

Encryption flow:

📄 Plain data → 🔑 Secret + random salt → 🔒 AES-256-GCM → 📦 Authenticated v2 envelope → ✅ Verify before use

Failure-safe file flow:

📁 Encrypted file → 🧪 Temporary private output → 🏷️ Verify GCM tag → ✅ Commit final file

Security-control coverage:

| Control | Visual status | Result | | --- | --- | --- | | Password hashing | 🟩🟩🟩🟩🟩 | scrypt + unique salt + optional pepper | | Data integrity | 🟩🟩🟩🟩🟩 | AES-GCM authentication tag | | File failure safety | 🟩🟩🟩🟩🟩 | Temporary output + verified commit | | Key rotation | 🟩🟩🟩🟩🟩 | Keyring, inspection, single/bulk rotation | | Resource limits | 🟩🟩🟩🟩🟩 | Bounded untrusted KDF settings | | Package compatibility | 🟩🟩🟩🟩🟩 | ESM + CommonJS + TypeScript declarations |

🆕 What Is New In v1.2

| New capability | Why it matters | Status | | --- | --- | --- | | Authenticated envelope v2 | Protects keyId, metadata, KDF header and AAD marker from silent modification | ✅ Added | | Compact v2 payload | Keeps keyId, metadata and AAD requirement in compact output | ✅ Added | | Legacy v1 reading | Existing v1 payloads and files remain decryptable | ✅ Preserved | | Atomic-style file commit | Failed authentication never replaces the requested final output | ✅ Added | | Temporary plaintext cleanup | Wrong keys, tampering and cancellation remove temporary output | ✅ Added | | Same-path protection | Prevents accidental source-file truncation | ✅ Added | | KDF resource policy | Rejects attacker-controlled memory/CPU settings before derivation | ✅ Added | | Security profiles | legacy, balanced, strong, and owasp presets | ✅ Added | | Strict payload decoder | Canonical Base64URL and exact salt/IV/tag lengths | ✅ Added | | Cancellation | AbortSignal support | ✅ Added | | Progress events | Bytes, percentage and elapsed time callbacks | ✅ Added | | Secret input types | String, Buffer and secret KeyObject | ✅ Added | | Password migration | verifyAndRehash() upgrades valid older hashes | ✅ Added | | Keyring decryption | Selects the correct secret using keyId | ✅ Added | | Payload inspection | Reads safe envelope information without decryption | ✅ Added | | Single/bulk rotation | Rotates one payload, many payloads, or encrypted files | ✅ Added | | Best-effort key clearing | Temporary derived-key Buffers are cleared after use | ✅ Added | | Package signature API | Author, company, contact and website available through code | ✅ Added | | Expanded verification | 19 security/runtime tests plus ESM/CJS package checks | ✅ Added |

✅ Complete Feature Matrix

| Category | Feature | v1.0 | v1.1 | v1.2 | | --- | --- | :---: | :---: | :---: | | Password | Async scrypt hashing | ✅ | ✅ | ✅ | | Password | Unique random salts | ✅ | ✅ | ✅ | | Password | Optional secret pepper | ✅ | ✅ | ✅ | | Password | Timing-safe verification | ✅ | ✅ | ✅ | | Password | Rehash detection | ✅ | ✅ | ✅ | | Password | Verify and automatic migration response | ❌ | ❌ | ✅ | | Password | Named security profiles | ❌ | ❌ | ✅ | | Encryption | AES-256-GCM text encryption | ✅ | ✅ | ✅ | | Encryption | JSON encryption | ✅ | ✅ | ✅ | | Encryption | Buffer encryption | ✅ | ✅ | ✅ | | Encryption | Empty Buffer support | ❌ | ❌ | ✅ | | Encryption | Object payload | ✅ | ✅ | ✅ | | Encryption | Compact payload | ✅ | ✅ | ✅ v2 | | Encryption | AAD context binding | ✅ | ✅ | ✅ | | Encryption | Authenticated envelope metadata | ❌ | ❌ | ✅ | | Files | Streaming encryption | ✅ | ✅ | ✅ | | Files | Streaming decryption | ❌ | ✅ | ✅ | | Files | Failure-safe final output | ❌ | ❌ | ✅ | | Files | Same input/output guard | ❌ | ❌ | ✅ | | Files | Progress callback | ❌ | ❌ | ✅ | | Files | Abort support | ❌ | ❌ | ✅ | | Rotation | keyId metadata | ❌ | ✅ | ✅ protected | | Rotation | Keyring resolver | ❌ | ❌ | ✅ | | Rotation | Single payload rotation | ❌ | ❌ | ✅ | | Rotation | Bulk payload rotation | ❌ | ❌ | ✅ | | Rotation | Encrypted file rotation | ❌ | ❌ | ✅ | | Validation | Typed custom errors | ✅ | ✅ | ✅ | | Validation | Strict canonical Base64URL | ❌ | ❌ | ✅ | | Validation | Bounded KDF policy | ❌ | ❌ | ✅ | | Package | Zero runtime dependencies | ✅ | ✅ | ✅ | | Package | ESM + CommonJS | ✅ | ✅ | ✅ | | Package | TypeScript declarations | ✅ | ✅ | ✅ | | Package | Author signature export | ❌ | ❌ | ✅ |

🎯 Which Function Should I Use

| I want to... | Use this function | | --- | --- | | Store a login password | hashPassword() | | Check a login password | verifyPassword() | | Check and upgrade an old password hash | verifyAndRehash() | | Know whether stored settings are old | needsRehash() | | Protect normal text | encryptText() | | Read protected text | decryptText() | | Protect an object or array | encryptJson() | | Read a protected object or array | decryptJson() | | Protect bytes, an image, or binary data in memory | encryptBuffer() | | Read protected bytes | decryptBuffer() | | Protect a file without loading it all into memory | encryptFile() | | Recover and authenticate a file | decryptFile() | | See a payload key id before decrypting | inspectEncryptedPayload() | | See an encrypted file key id | inspectEncryptedFile() | | Let key id select the secret | decryptWithKeyring() | | Change one payload to a new secret | rotateEncryptedPayload() | | Change many payloads to a new secret | rotateEncryptedPayloads() | | Change an encrypted file to a new secret | rotateEncryptedFile() | | Configure defaults once | createSecureHashVault() |

🎓 Learn Here: Password Functions

hashPassword(password, options?)

Description: Creates a one-way scrypt hash. It does not create decryptable data.

Syntax:

const result = await hashPassword(password, options);

| Parameter | Type | Required | Meaning | | --- | --- | :---: | --- | | password | string | ✅ | Password entered by the user | | options.pepper | string | ❌ | Extra secret stored outside the database | | options.profile | profile name | ❌ | Security preset | | options.params | scrypt settings | ❌ | Advanced parameter override | | options.salt | Base64URL string | ❌ | Controlled salt, mainly for migration/testing |

Returns: PasswordHashResult with hash, salt, params, algorithm, version and creation time.

const result = await hashPassword("FreshPassword@123", { profile: "balanced" });
console.log(result.algorithm, result.hash.startsWith("$cv$"));

Output: scrypt true

Errors: InvalidConfigError, InvalidPayloadError, or a native scrypt error as the cause.
Use cases: Registration, password reset, successful-login migration.

verifyPassword(password, storedHash, options?)

Description: Checks a plain login password against a stored one-way hash using a timing-safe comparison.

Syntax: await verifyPassword(password, storedHash, options)

| Parameter | Type | Required | Meaning | | --- | --- | :---: | --- | | password | string | ✅ | Login password | | storedHash | string | ✅ | Full $cv$... value from the database | | options.pepper | string | ❌ | Same pepper used while hashing | | options.currentOptions | hash options | ❌ | Settings used to calculate needsRehash | | options.policy | KdfPolicy | ❌ | Maximum accepted resource settings |

Returns: { valid, needsRehash, algorithm, version }.

const result = await verifyPassword("FreshPassword@123", storedHash);
console.log(result);

Output: { valid: true, needsRehash: false, algorithm: 'scrypt', version: 'v1' }

Errors: PasswordVerificationError for malformed hashes or derivation failures.
Use cases: Login, step-up authentication, confirming a password before a sensitive action.

verifyAndRehash(password, storedHash, options?)

Description: Verifies first. When login succeeds and settings are old, it also returns a stronger replacement hash.

Syntax: await verifyAndRehash(password, storedHash, { hashOptions })

| Parameter | Type | Required | Meaning | | --- | --- | :---: | --- | | password | string | ✅ | Login password | | storedHash | string | ✅ | Existing database hash | | hashOptions | HashPasswordOptions | ❌ | New settings for the upgraded hash |

Returns: Verification fields plus optional upgradedHash.

const checked = await verifyAndRehash(password, storedHash, {
  hashOptions: { profile: "owasp" }
});
if (checked.upgradedHash) await users.updateHash(checked.upgradedHash.hash);

Output: { valid: true, needsRehash: true, upgradedHash: { hash: '$cv$...' } }

Errors: Same verification and hashing errors as the two underlying operations.
Use cases: Gradual password-security upgrades without forcing every user to reset a password.

needsRehash(storedHash, currentOptions?)

Description: Compares encoded hash settings with the settings your application wants today.

Syntax: needsRehash(storedHash, { profile: "owasp" })

| Parameter | Type | Required | Meaning | | --- | --- | :---: | --- | | storedHash | string | ✅ | Existing password hash | | currentOptions | hash options | ❌ | Desired current profile or params |

Returns: boolean. Example output: true.
Errors: Invalid configuration errors; malformed stored hashes return true.
Use cases: Migration reports and post-login upgrades.

🎓 Learn Here: Encryption Functions

Shared encryption options:

| Option | Meaning | | --- | --- | | aad | Context that must match during decryption, such as tenant or record id | | keyId | Public key label used for rotation; never put the secret here | | metadata | Authenticated application metadata, maximum 16 KiB | | output | "object" or compact v2 string | | profile / params | scrypt work settings | | policy | Maximum resource settings accepted by the operation | | signal | Cancels with AbortController | | onProgress | Receives progress information |

encryptText(plainText, secret, options?)

Description: Encrypts a UTF-8 string with AES-256-GCM.

Syntax: await encryptText(plainText, secret, options)

| Parameter | Type | Required | Meaning | | --- | --- | :---: | --- | | plainText | string | ✅ | Text to protect | | secret | string, Buffer, secret KeyObject | ✅ | Secret used to derive the encryption key | | options | EncryptOptions | ❌ | AAD, key id, metadata, format and controls |

Returns: EncryptedPayload or compact string.

const payload = await encryptText("private note", secret, {
  keyId: "key-2026-07",
  aad: "note:42"
});
console.log(payload.format);

Output: cv.enc.v2

Errors: InvalidConfigError or EncryptionError; cancellation returns AbortError.
Use cases: API tokens, private notes, recovery codes and database fields.

decryptText(payload, secret, options?)

Description: Authenticates and decrypts text. Wrong secret, changed header, changed ciphertext or wrong AAD fails.

Syntax: await decryptText(payload, secret, { aad })

| Parameter | Type | Required | Meaning | | --- | --- | :---: | --- | | payload | object or compact string | ✅ | Secure Hash Vault encrypted value | | secret | string, Buffer, secret KeyObject | ✅ | Matching secret | | options.aad | string | When marked | Matching business context |

Returns: Plain string. Example output: private note.
Errors: DecryptionError; cancellation returns AbortError.
Use cases: Reading protected text after authorization.

encryptJson(data, secret, options?)

Description: Serializes JSON-compatible data and encrypts it.

Syntax: await encryptJson(data, secret, options)

| Parameter | Type | Required | Meaning | | --- | --- | :---: | --- | | data | JSON-compatible value | ✅ | Object, array, number, boolean or null | | secret | supported secret | ✅ | Encryption secret | | options | EncryptOptions | ❌ | Shared encryption options |

Returns: EncryptedPayload or compact string.

const payload = await encryptJson({ userId: 7, roles: ["admin"] }, secret);

Output: { format: 'cv.enc.v2', algorithm: 'aes-256-gcm', ... }

Errors: InvalidPayloadError for values JSON cannot serialize, or EncryptionError.
Use cases: Profiles, settings, private API responses and structured records.

decryptJson<T>(payload, secret, options?)

Description: Decrypts and parses JSON, with TypeScript generic support.

Syntax: await decryptJson<UserRecord>(payload, secret, options)

| Parameter | Type | Required | Meaning | | --- | --- | :---: | --- | | payload | encrypted object/string | ✅ | Protected JSON payload | | secret | supported secret | ✅ | Matching secret | | options | DecryptOptions | ❌ | AAD, policy, signal and progress |

Returns: Parsed value of type T. Example output: { userId: 7, roles: ['admin'] }.
Errors: DecryptionError or InvalidPayloadError when decrypted text is not JSON.
Use cases: Typed service records and encrypted configuration.

encryptBuffer(buffer, secret, options?)

Description: Encrypts binary bytes, including an empty Buffer.

Syntax: await encryptBuffer(buffer, secret, options)

| Parameter | Type | Required | Meaning | | --- | --- | :---: | --- | | buffer | Buffer | ✅ | Binary bytes | | secret | supported secret | ✅ | Encryption secret | | options | EncryptOptions | ❌ | Shared encryption options |

Returns: Encrypted object or compact string.

const payload = await encryptBuffer(Buffer.from([1, 2, 3]), secret);

Output: { cipherText: '...', tag: '...', format: 'cv.enc.v2' }

Errors: EncryptionError when input is not a Buffer or encryption fails.
Use cases: Small images, compressed data, protocol packets and binary database columns.

decryptBuffer(payload, secret, options?)

Description: Authenticates and returns the original bytes.

Syntax: await decryptBuffer(payload, secret, options)

| Parameter | Type | Required | Meaning | | --- | --- | :---: | --- | | payload | encrypted object/string | ✅ | Protected binary payload | | secret | supported secret | ✅ | Matching secret | | options | DecryptOptions | ❌ | AAD, policy, signal and progress |

Returns: Buffer. Example output: <Buffer 01 02 03>.
Errors: DecryptionError.
Use cases: Recovering binary values kept in memory.

🎓 Learn Here: File Functions

encryptFile(inputPath, outputPath, secret, options?)

Description: Streams a source file into authenticated Secure Hash Vault file format v2.

Syntax: await encryptFile(inputPath, outputPath, secret, options)

| Parameter | Type | Required | Meaning | | --- | --- | :---: | --- | | inputPath | string | ✅ | Existing source file | | outputPath | string | ✅ | New encrypted file path | | secret | supported secret | ✅ | Encryption secret | | options.overwrite | boolean | ❌ | Replace existing output after success; default true | | options.onProgress | function | ❌ | Receives bytes and percentage | | Other options | shared options | ❌ | AAD, key id, metadata, profile, policy, signal |

Returns: Paths, bytes read/written, algorithm, key id and creation time.

await encryptFile("invoice.pdf", "invoice.pdf.shv", secret, {
  keyId: "files-2026-07",
  aad: "invoice:845",
  onProgress: ({ percent }) => console.log(percent)
});

Output: 100 and { algorithm: 'aes-256-gcm', bytesRead: ... }

Errors: EncryptionError, InvalidConfigError, or AbortError.
Use cases: Documents, exports, backups and large files.

decryptFile(inputPath, outputPath, secret, options?)

Description: Streams decryption into a temporary file, verifies the GCM tag, then commits the requested output. A failure leaves existing output untouched.

Syntax: await decryptFile(inputPath, outputPath, secret, options)

| Parameter | Type | Required | Meaning | | --- | --- | :---: | --- | | inputPath | string | ✅ | .shv encrypted file | | outputPath | string | ✅ | Final recovered file path | | secret | supported secret | ✅ | Matching secret | | options.aad | string | When marked | Matching context | | options.overwrite | boolean | ❌ | Controls successful replacement |

Returns: FileCryptoResult. Example output: { bytesWritten: 2048, keyId: 'files-2026-07' }.
Errors: DecryptionError or AbortError.
Use cases: Safe document recovery where unauthenticated plaintext must not become the final file.

inspectEncryptedFile(inputPath, policy?)

Description: Reads and validates only the public encrypted-file header. It does not decrypt content.

Syntax: await inspectEncryptedFile("invoice.pdf.shv")

| Parameter | Type | Required | Meaning | | --- | --- | :---: | --- | | inputPath | string | ✅ | Encrypted file | | policy | KdfPolicy | ❌ | Accepted maximum KDF settings |

Returns: Format, algorithm, params, key id, AAD requirement, metadata and header size.

Output: { format: 'cv.file.v2', keyId: 'files-2026-07', requiresAad: true }

Errors: InvalidPayloadError for unsupported or malformed headers.
Use cases: Key selection, migration reports and file inventories.

🎓 Learn Here: Key Rotation Functions

inspectEncryptedPayload(payload, policy?)

Description: Reads validated public envelope information without decrypting ciphertext.

Syntax: inspectEncryptedPayload(payload)

| Parameter | Type | Required | Meaning | | --- | --- | :---: | --- | | payload | object/string | ✅ | Encrypted payload | | policy | KdfPolicy | ❌ | Resource acceptance limits |

Returns: Format, algorithm, KDF settings, key id, AAD requirement and metadata.
Example output: { format: 'cv.enc.v2', keyId: 'prod-1', requiresAad: true }
Errors: InvalidPayloadError or InvalidConfigError.
Use cases: Routing a payload to a key vault without exposing plaintext.

decryptWithKeyring<T>(payload, keyring, options?)

Description: Reads keyId, selects the matching secret, then decrypts as text, JSON or Buffer.

Syntax: await decryptWithKeyring(payload, keyring, { as, aad })

| Parameter | Type | Required | Meaning | | --- | --- | :---: | --- | | payload | encrypted payload | ✅ | Value containing keyId | | keyring | object, Map or resolver | ✅ | Maps key ids to secrets | | options.as | text/json/buffer | ❌ | Desired result; default text |

const keys = { "prod-1": process.env.OLD_KEY!, "prod-2": process.env.NEW_KEY! };
const value = await decryptWithKeyring(payload, keys, { as: "json", aad: "tenant:acme" });

Output: { customerId: 42 }

Errors: InvalidPayloadError when key id is absent; InvalidConfigError when key is missing; DecryptionError on authentication failure.
Use cases: Zero-downtime key rotation and multi-key archives.

rotateEncryptedPayload(payload, keyring, newSecret, options)

Description: Decrypts one payload with its old key id and creates a protected v2 payload with a new key id.

Syntax: await rotateEncryptedPayload(payload, keyring, newSecret, options)

| Parameter | Type | Required | Meaning | | --- | --- | :---: | --- | | payload | encrypted value | ✅ | Old payload | | keyring | Keyring | ✅ | Contains old secret | | newSecret | supported secret | ✅ | New encryption secret | | options.keyId | string | ✅ | New public key label | | currentAad / newAad | string | As needed | Old and new context |

Returns: New encrypted payload/string. Example output key id: prod-2.
Errors: Keyring, decryption or encryption errors.
Use cases: Rotating a database record after a key change.

rotateEncryptedPayloads(payloads, keyring, newSecret, options)

Description: Runs the same rotation safely over a list in order.

Syntax: await rotateEncryptedPayloads(payloads, keyring, newSecret, options)

| Parameter | Type | Required | Meaning | | --- | --- | :---: | --- | | payloads | array | ✅ | Encrypted values to rotate | | Other parameters | same as single rotation | ✅ | Keyring, new secret and options |

Returns: Array of rotated payloads. Example output: [payloadV2, payloadV2].
Errors: Stops and rejects on the first failed item.
Use cases: Controlled maintenance jobs and migration batches.

rotateEncryptedFile(inputPath, outputPath, keyring, newSecret, options)

Description: Resolves the old file key id, verifies the old file and writes a new encrypted file under a new key id.

Syntax: await rotateEncryptedFile(input, output, keyring, newSecret, options)

| Parameter | Type | Required | Meaning | | --- | --- | :---: | --- | | inputPath / outputPath | string | ✅ | Old and new encrypted paths | | keyring | Keyring | ✅ | Old secrets | | newSecret | supported secret | ✅ | New secret | | options.keyId | string | ✅ | New key id |

Returns: FileCryptoResult for the new file.
Errors: Inspection, keyring, decryption, encryption or cancellation errors.
Use cases: File-vault rotation and protected backup migration.

🎓 Learn Here: Utility Functions

| Function | Syntax | Returns | Example output | Main errors | Best use | | --- | --- | --- | --- | --- | --- | | generateSalt(size?) | generateSalt(16) | Base64URL string | x7...Q | InvalidConfigError | Password salts | | generatePepper(size?) | generatePepper(32) | Base64URL secret | m2...A | InvalidConfigError | Secret-manager pepper | | randomBuffer(size?) | randomBuffer(32) | Secure Buffer | <Buffer ...> | InvalidConfigError | Keys, nonces and tokens | | getSecurityProfile(name, keyLen) | getSecurityProfile("owasp", 64) | ScryptParams | { N: 131072, r: 8, p: 1, keyLen: 64 } | InvalidConfigError | Visible policy configuration | | toBase64Url(input) | toBase64Url("hello") | string | aGVsbG8 | none for supported input | URL-safe storage | | fromBase64Url(value) | fromBase64Url("aGVsbG8") | Buffer | <Buffer 68 65 6c 6c 6f> | InvalidPayloadError | Canonical decoding | | decodeBase64Url(value, field, rules) | decodeBase64Url(value, "iv", { exactBytes: 12 }) | validated Buffer | <Buffer ...> | InvalidPayloadError | Protocol validation | | toHex(input) | toHex("Hi") | hex string | 4869 | none for supported input | Debug/storage encoding | | fromHex(value) | fromHex("4869") | Buffer | <Buffer 48 69> | InvalidPayloadError | Strict hex decoding | | detectPayload(value) | detectPayload(payload) | category string | encrypted-payload | none | Input routing | | getPackageInfo() | getPackageInfo() | frozen signature object | { author: 'Pradeep...', company: 'BSG Technologies' } | none | About/support screens |

Utility parameter notes:

  • Random sizes must be integers between 8 and 1024 bytes; password salts use at least 16 bytes.
  • fromBase64Url() accepts canonical URL-safe Base64 without = padding.
  • decodeBase64Url() adds exact/minimum decoded-byte rules.
  • detectPayload() can return password-hash, encrypted-payload, plain-text, json, buffer, or unknown.

🧰 Configured Client

createSecureHashVault(options?)

Description: Creates one client with reusable password and encryption defaults.

Syntax: const vault = createSecureHashVault(options)

| Parameter | Type | Required | Meaning | | --- | --- | :---: | --- | | options.password | HashPasswordOptions | ❌ | Default password profile, pepper or params | | options.encryption | EncryptOptions | ❌ | Default AAD, key id, profile, metadata or policy |

import { createSecureHashVault } from "secure-hash-vault";

const vault = createSecureHashVault({
  password: { profile: "owasp", pepper: process.env.PASSWORD_PEPPER },
  encryption: { profile: "balanced", keyId: "prod-2026-07" }
});

const passwordHash = await vault.password.hash("Password@123");
const encrypted = await vault.crypto.encryptText("private", process.env.VAULT_SECRET!);

Returns: SecureHashVaultClient.
Errors: Individual methods return their documented typed errors.
Use cases: Dependency injection, services and applications that want one shared policy.

Client shortcuts:

| API | Purpose | | --- | --- | | vault.hash() / vault.verify() / vault.verifyAndRehash() | Password operations | | vault.encrypt() | Automatically chooses text, JSON or Buffer encryption | | vault.decrypt({ as }) | Decrypts as text, JSON or Buffer | | vault.password.* | Namespaced password functions | | vault.crypto.* | Namespaced crypto and file functions | | vault.decryptWithKeyring() | Key-id-based decryption | | vault.rotateEncryptedPayload() | Single rotation | | vault.rotateEncryptedPayloads() | Bulk rotation | | vault.rotateEncryptedFile() | File rotation |

Compatibility aliases createCipherVault(), createCipherForge(), CipherForge, cipherForge, cipherVault, and secureVault remain available. New projects should use createSecureHashVault().

🚨 Errors

| Error | Meaning | Developer action | | --- | --- | --- | | InvalidConfigError | Option, path, key id, profile or resource policy is invalid | Fix application configuration | | InvalidPasswordHashError | Password hash format is invalid | Treat stored value as damaged/unsupported | | PasswordVerificationError | Password verification could not be completed | Reject login and log a redacted reason | | InvalidPayloadError | Envelope/header/encoding/JSON is malformed | Reject input before use | | EncryptionError | Encryption operation failed | Do not store the incomplete result | | DecryptionError | Secret, tag, AAD, metadata or ciphertext authentication failed | Never use partial plaintext | | AbortError | Caller cancelled through AbortSignal | Report cancellation, not a security failure |

import { DecryptionError, decryptText } from "secure-hash-vault";

try {
  const value = await decryptText(payload, secret, { aad: "tenant:acme" });
  console.log(value);
} catch (error) {
  if (error instanceof DecryptionError) {
    console.error("Protected data could not be authenticated.");
  }
}

Never log passwords, peppers, encryption secrets, full payloads, or decrypted private data.

🛡️ Security Profiles

| Profile | N | r | p | Typical purpose | | --- | ---: | ---: | ---: | --- | | legacy | 16,384 | 8 | 1 | Compatibility and controlled migrations | | balanced | 32,768 | 8 | 3 | Default security/performance balance | | strong | 65,536 | 8 | 2 | Higher memory setting | | owasp | 131,072 | 8 | 1 | OWASP scrypt minimum profile |

Always benchmark on your own production hardware. The default KDF policy limits accepted untrusted work settings to reduce resource-exhaustion attacks. Raise policy limits deliberately, not from payload data.

❓ Questionnaire With Answers

Before v1.2, a partial output file could remain. In v1.2, plaintext goes to a temporary path and reaches the final output only after authentication succeeds.

Compact v1 did not keep keyId, metadata, or the AAD-required marker. Compact v2 preserves and authenticates those fields.

v1.2 validates untrusted parameters against KdfPolicy before key derivation. Applications can set stricter limits.

Yes. v1 object, compact, and encrypted-file formats remain readable. New encryption writes authenticated v2 formats.

Add old and new secrets to a keyring, inspect keyId, then use rotateEncryptedPayload(), rotateEncryptedPayloads(), or rotateEncryptedFile().

Yes. Pass signal from AbortController and an onProgress callback.

No. Login passwords must use hashPassword() and verifyPassword(). Reversible encryption is for data that must later be recovered.

No. Runtime code directly uses audited primitives exposed by Node.js node:crypto: scrypt, random bytes, AES-256-GCM, and timing-safe equality.

No package can honestly guarantee ranking. Clear naming, accurate keywords, useful documentation, releases, adoption, quality and trust improve discoverability without misleading keyword stuffing.

📋 Production Checklist

  • ✅ Store password hashes, never plain passwords.
  • ✅ Keep peppers and encryption secrets in a secret manager.
  • ✅ Use keyId; never put the actual secret inside metadata.
  • ✅ Bind tenant, user, record or file context with AAD.
  • ✅ Keep default KDF limits or configure stricter limits for public inputs.
  • ✅ Use verifyAndRehash() after successful login to upgrade older hashes.
  • ✅ Handle DecryptionError without exposing sensitive details.
  • ✅ Test secret backups and rotation before deleting an old key.
  • ✅ Keep Node.js patched and run npm run verify before release.
  • ✅ Obtain independent security review for high-risk or regulated deployments.

✍️ Author Signature

import { getPackageInfo, PACKAGE_INFO } from "secure-hash-vault";

console.log(getPackageInfo());
console.log(PACKAGE_INFO.website);

| Signature | Value | | --- | --- | | Library | Secure Hash Vault | | Author | Pradeep Kumar Sheoran (Stack Developer) | | Company | BSG Technologies | | Contact / WhatsApp | +91-8595147850 | | Official website | https://bsgtechnologies.com | | Invitation | Visit to meet, learn, contribute, discuss new topics, and accept a coffee invitation. |

🔍 Search Keywords

secure hash vault · password hashing · scrypt · AES-256-GCM · Node.js encryption · TypeScript crypto · file encryption · key rotation · keyring · AAD · password migration · verify and rehash · authenticated encryption · atomic file decryption · zero dependency security · BSG Technologies · Pradeep Kumar Sheoran


Secure Hash Vault

Secure Hash Vault is a production-minded TypeScript crypto toolkit for password hashing, password verification, authenticated data encryption, and file protection using Node.js node:crypto.

Created by Pradeep Kumar Sheoran (Stack Developer) at BSG Technologies. Contact: +91-8595147850 (also WhatsApp).

Donation support: UPI on mobile number +91-8595147850.

Hashtags: #SecureHashVault #NodeCrypto #TypeScript #PasswordHashing #AES256GCM #Scrypt #BSGTechnologies

Installation

npm install secure-hash-vault

Features

  • One-way password hashing with async Node.js crypto.scrypt.
  • Password verification with timing-safe comparison.
  • Random salt generation and optional secret pepper support.
  • Metadata-safe password hash format.
  • Hash upgrade detection with needsRehash().
  • AES-256-GCM authenticated encryption for text, JSON, buffers, and files.
  • Authenticated data support with AAD for tenant, user, file, or context binding.
  • Optional keyId metadata for secret rotation and audit trails.
  • Streaming file decryption for large encrypted files.
  • JSON-safe encrypted payload object and compact string format.
  • Base64URL and hex helpers.
  • Developer-friendly custom errors.
  • TypeScript-first API with ESM and CJS builds.
  • No third-party crypto dependency and no custom cryptographic algorithm.

Important Security Rule

Passwords are not decrypted. A password should be stored as a one-way hash, then checked during login with verifyPassword(). Reversible encryption/decryption is only for general data such as tokens, secrets, files, JSON payloads, and private text.

Password Hashing

import { hashPassword, verifyPassword } from "secure-hash-vault";

const result = await hashPassword("MyStrongPassword@123", {
  pepper: process.env.CIPHER_FORGE_PEPPER
});

// Store only result.hash in your database.
console.log(result.hash);

const verified = await verifyPassword("MyStrongPassword@123", result.hash, {
  pepper: process.env.CIPHER_FORGE_PEPPER
});

if (verified.valid) {
  console.log("Login success");
}

Password hash format:

$cv$v1$scrypt$N=16384,r=8,p=1,keyLen=64$saltBase64Url$hashBase64Url

Example response:

{
  "algorithm": "scrypt",
  "version": "v1",
  "hash": "$cv$v1$scrypt$N=16384,r=8,p=1,keyLen=64$abcSalt$xyzHash",
  "salt": "abcSalt",
  "params": {
    "N": 16384,
    "r": 8,
    "p": 1,
    "keyLen": 64
  },
  "createdAt": "2026-07-02T10:00:00.000Z"
}

Salt And Pepper

A salt is random public data generated per password hash. It prevents two equal passwords from producing the same stored hash.

A pepper is a secret value added during hashing and verification. Keep it in an environment variable or a secret manager. Never store the pepper in the database.

import { generatePepper, generateSalt } from "secure-hash-vault";

console.log(generateSalt());
console.log(generatePepper());

Hash Upgrade Detection

import { needsRehash } from "secure-hash-vault";

const shouldUpgrade = needsRehash(storedHash, {
  params: { N: 32768, r: 8, p: 1, keyLen: 64 }
});

Data Encryption

Secure Hash Vault uses AES-256-GCM for reversible encryption. AES-GCM provides confidentiality and integrity verification.

import { decryptText, encryptText } from "secure-hash-vault";

const encrypted = await encryptText("secret data", "master-secret", {
  aad: "tenant:acme",
  keyId: "prod-key-2026-07"
});

const decrypted = await decryptText(encrypted, "master-secret", {
  aad: "tenant:acme"
});

When aad is used during encryption, the same authenticated data must be supplied during decryption. keyId is stored as metadata so your app can select the right secret during rotation.

Encrypted payload format:

{
  "format": "cv.enc.v1",
  "algorithm": "aes-256-gcm",
  "kdf": "scrypt",
  "params": {
    "N": 16384,
    "r": 8,
    "p": 1,
    "keyLen": 32
  },
  "iv": "base64url-iv",
  "salt": "base64url-salt",
  "tag": "base64url-auth-tag",
  "cipherText": "base64url-ciphertext",
  "keyId": "prod-key-2026-07",
  "aad": true,
  "metadata": {
    "createdAt": "2026-07-02T10:00:00.000Z"
  }
}

Compact format:

$cvenc$v1$aes-256-gcm$scrypt$params$salt$iv$tag$cipherText

JSON Encryption

import { decryptJson, encryptJson } from "secure-hash-vault";

const encrypted = await encryptJson({ userId: 1, role: "admin" }, "master-secret");
const decrypted = await decryptJson<{ userId: number; role: string }>(encrypted, "master-secret");

Buffer Encryption

import { decryptBuffer, encryptBuffer } from "secure-hash-vault";

const encrypted = await encryptBuffer(Buffer.from("binary secret"), "master-secret");
const decrypted = await decryptBuffer(encrypted, "master-secret");

File Encryption

import { decryptFile, encryptFile } from "secure-hash-vault";

await encryptFile("private.txt", "private.txt.shv", "master-secret", {
  aad: "file:private.txt",
  keyId: "file-key-1"
});

await decryptFile("private.txt.shv", "private.decrypted.txt", "master-secret", {
  aad: "file:private.txt"
});

Client API

import { createCipherForge } from "secure-hash-vault";

const vault = createCipherForge({
  password: {
    algorithm: "scrypt",
    params: {
      N: 16384,
      r: 8,
      p: 1,
      keyLen: 64
    }
  },
  encryption: {
    algorithm: "aes-256-gcm"
  }
});

const passwordHash = await vault.password.hash("MyPassword@123");
const isValid = await vault.password.verify("MyPassword@123", passwordHash.hash);

const encrypted = await vault.crypto.encryptText("secret data", "master-key");
const decrypted = await vault.crypto.decryptText(encrypted, "master-key");

Primary factory: createSecureHashVault(). Compatibility aliases such as createCipherForge(), createCipherVault(), CipherForge, and cipherVault remain available for existing users.

Universal Converter

import { CipherForge } from "secure-hash-vault";

const encryptedText = await CipherForge.encrypt("hello", "master-secret");
const decryptedText = await CipherForge.decrypt(encryptedText, "master-secret");

const encryptedJson = await CipherForge.encrypt({ userId: 1, role: "admin" }, "master-secret");
const decryptedJson = await CipherForge.decrypt(encryptedJson, "master-secret", { as: "json" });

Error Classes

import {
  DecryptionError,
  EncryptionError,
  InvalidConfigError,
  InvalidPasswordHashError,
  InvalidPayloadError,
  PasswordVerificationError,
  SecureHashVaultError
} from "secure-hash-vault";

Common Mistakes

  • Do not decrypt passwords. Use verifyPassword().
  • Do not store plain passwords.
  • Do not use SHA-256 alone for password storage.
  • Do not reuse IVs for encryption. CipherForge generates a random IV every time.
  • Do not store pepper beside password hashes.
  • Do not lose encryption keys; encrypted data cannot be recovered without the correct secret.
  • Use keyId during secret rotation.
  • Use aad to bind encrypted data to tenant, user, file, or business context.
  • Do not invent a custom cryptographic algorithm.
  • Do not ignore AES-GCM authentication failures.

Production Checklist

  • Store only password hashes in the database.
  • Use HTTPS.
  • Keep pepper in environment variables or a secret manager.
  • Never store pepper in the database.
  • Rotate encryption secrets carefully.
  • Back up encryption keys safely.
  • Use timing-safe comparison.
  • Use random salt and IV.
  • Audit code before production use.
  • Keep Node.js updated.

Implementation Guide

CipherForge is a wrapper around trusted Node.js primitives:

  • Password hashing: crypto.scrypt.
  • Random bytes: crypto.randomBytes.
  • Authenticated encryption: crypto.createCipheriv("aes-256-gcm").
  • Authenticated decryption: crypto.createDecipheriv("aes-256-gcm").
  • Constant-time checks: crypto.timingSafeEqual.

Build commands:

npm run typecheck
npm run test
npm run build
npm run pack:dry
npm run verify

More Docs

Package Author

  • Developer: Pradeep Kumar Sheoran (Stack Developer)
  • Company: BSG Technologies
  • Contact: +91-8595147850 (also WhatsApp)
  • Donation: UPI on mobile number +91-8595147850