A TypeScript library for encrypting and decrypting text using AES-256-CTR encryption with PBKDF2 key derivation.
This library uses Node.js native crypto module for secure encryption operations.
scrypt (OWASP-recommended, memory-hard)npm install @vvlad1973/crypto
import Crypto, { CryptoOptions, isCrypto } from '@vvlad1973/crypto';
import Crypto from '@vvlad1973/crypto';
const password = 'your-password';
const salt = 'your-salt';
// Create an instance using separate parameters
const crypto = new Crypto(password, salt);
// Encrypt a text
const plainText = 'Hello, World!';
const encryptedText = crypto.encrypt(plainText);
console.log('Encrypted:', encryptedText);
// Decrypt the text
const decryptedText = crypto.decrypt(encryptedText);
console.log('Decrypted:', decryptedText);
import Crypto, { CryptoOptions } from '@vvlad1973/crypto';
const options: CryptoOptions = {
password: 'your-password',
salt: 'your-salt',
algorithm: 'SHA512',
iterations: 1000,
keyLength: 32,
iv: 5
};
const crypto = new Crypto(options);
const encrypted = crypto.encrypt('Secret message');
const decrypted = crypto.decrypt(encrypted);
import Crypto from '@vvlad1973/crypto';
import { randomBytes } from 'crypto';
// Generate a random 16-byte initialization vector
const ivBuffer = randomBytes(16);
const crypto = new Crypto({
password: 'your-password',
salt: 'your-salt',
iv: ivBuffer
});
const encrypted = crypto.encrypt('Secret message');
import Crypto from '@vvlad1973/crypto';
// Generate a UUID v4
const uuid = Crypto.getUUID();
console.log(uuid); // e.g., '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'
import Crypto, { isCrypto } from '@vvlad1973/crypto';
const crypto = new Crypto('password', 'salt');
if (isCrypto(crypto)) {
// TypeScript knows crypto has encrypt/decrypt methods
const encrypted = crypto.encrypt('text');
}
The Crypto class encrypts recoverable data. For passwords, which must never be
recoverable, use the standalone hashPassword / verifyPassword functions. They are
built on Node.js native scrypt (a memory-hard, OWASP-recommended KDF), generate a
fresh per-record salt on every call, and compare in constant time.
import { hashPassword, verifyPassword } from '@vvlad1973/crypto';
// On registration / password change — store the returned string as-is:
const stored = await hashPassword('correct horse battery staple');
// e.g. 'scrypt$1$N=131072,r=8,p=1$<saltHex>$<hashHex>'
// On login:
const ok = await verifyPassword('correct horse battery staple', stored); // true
const no = await verifyPassword('wrong password', stored); // false
The stored value is a single self-describing string that carries the algorithm, a
format version, the scrypt parameters and the salt — so the cost profile can change
over time without any storage migration, and the value is distinguishable from other
schemes (legacy bcrypt $2a$…, a future argon2id$…, etc.).
To trade strength for speed (for example in a test suite), lower the cost parameters:
const cheap = await hashPassword('pw', { params: { N: 16384 } });
The reversible
encrypt/decryptcipher and thehashPassword/verifyPasswordfunctions are not interchangeable: use the cipher for data you must read back, and the password functions for secrets that must stay one-way.
new Crypto(
password: string,
salt: string,
algorithm?: string,
iterations?: number,
keyLength?: number,
iv?: number | Buffer
)
new Crypto(options: CryptoOptions)
CryptoOptions interface:
interface CryptoOptions {
password: string; // Password for key derivation
salt: string; // Salt for key derivation
algorithm?: string; // Hash algorithm (default: 'SHA512')
iterations?: number; // PBKDF2 iterations (default: 1000)
keyLength?: number; // Key length in bytes (default: 32)
iv?: number | Buffer; // Initialization vector (default: random 16 bytes)
}
Parameters:
password - The password used for PBKDF2 key derivationsalt - The salt used for PBKDF2 key derivationalgorithm - Hash algorithm for PBKDF2 (default: 'SHA512')iterations - Number of PBKDF2 iterations (default: 1000)keyLength - Derived key length in bytes (default: 32 for AES-256)iv - Initialization vector: either a number (converted to 16-byte Buffer) or a Buffer directly (default: random 16 bytes)Encrypts the given text using AES-256-CTR encryption.
text - The plain text to encryptDecrypts the given encrypted text using AES-256-CTR decryption.
text - The encrypted text as a hexadecimal stringGenerates a random UUID v4 string using Node.js native crypto.
'9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d')Type guard function to check if an object is an instance of Crypto.
object - The object to checktrue if the object is a Crypto instance, false otherwiseHashes a plaintext password with scrypt for storage. A fresh 16-byte salt is
generated per call.
plain - The plaintext password to hashoptions.params - Optional scrypt parameter overrides (N, r, p, keyLength);
omitted fields fall back to DEFAULT_SCRYPT_PARAMSscrypt$1$<params>$<saltHex>$<hashHex>Verifies a candidate password against a value produced by hashPassword, comparing in
constant time. A structurally invalid or non-scrypt stored value yields false
rather than throwing.
plain - The candidate plaintext passwordstored - The stored hash stringtrue when the password matches, false otherwiseThe default OWASP scrypt profile: { N: 131072, r: 8, p: 1, keyLength: 32 }
(about 128 MiB and 100-250 ms per hash on a modern CPU).
This library uses Vitest for testing with comprehensive coverage requirements.
npm test
npm run test:watch
npm run test:ui
npm run test:coverage
Current coverage: 100% across all metrics
To build the TypeScript project:
npm run build
This will compile TypeScript files to the dist directory with type definitions.
To generate TypeDoc documentation:
npm run doc
Documentation will be generated in the docs directory.
This project is licensed under the MIT License with Commercial Use - see the LICENSE file for details.
Vladislav Vnukovskiy vvlad1973@gmail.com