The crypto module provides cryptographic functionality including hashing, encryption, and secure random generation. Here's how to use it.
Hashing#
1import crypto from 'node:crypto';
2
3// Simple hash
4function hash(data, algorithm = 'sha256') {
5 return crypto.createHash(algorithm).update(data).digest('hex');
6}
7
8console.log(hash('Hello, World!')); // SHA-256 hash
9console.log(hash('Hello, World!', 'md5')); // MD5 hash
10console.log(hash('Hello, World!', 'sha512')); // SHA-512 hash
11
12// Hash with different encodings
13const hashBuffer = crypto.createHash('sha256')
14 .update('Hello')
15 .digest(); // Buffer
16
17const hashBase64 = crypto.createHash('sha256')
18 .update('Hello')
19 .digest('base64'); // Base64 string
20
21// Incremental hashing
22const hasher = crypto.createHash('sha256');
23hasher.update('Hello');
24hasher.update(', ');
25hasher.update('World!');
26console.log(hasher.digest('hex'));HMAC (Hash-based Message Authentication)#
1import crypto from 'node:crypto';
2
3// Create HMAC
4function createHmac(data, secret, algorithm = 'sha256') {
5 return crypto.createHmac(algorithm, secret)
6 .update(data)
7 .digest('hex');
8}
9
10const secret = 'my-secret-key';
11const hmac = createHmac('message to authenticate', secret);
12console.log(hmac);
13
14// Verify HMAC
15function verifyHmac(data, secret, providedHmac) {
16 const calculated = createHmac(data, secret);
17 return crypto.timingSafeEqual(
18 Buffer.from(calculated),
19 Buffer.from(providedHmac)
20 );
21}Password Hashing#
1import crypto from 'node:crypto';
2
3// Hash password with salt (using scrypt)
4async function hashPassword(password) {
5 return new Promise((resolve, reject) => {
6 const salt = crypto.randomBytes(16).toString('hex');
7
8 crypto.scrypt(password, salt, 64, (err, derivedKey) => {
9 if (err) reject(err);
10 resolve(`${salt}:${derivedKey.toString('hex')}`);
11 });
12 });
13}
14
15// Verify password
16async function verifyPassword(password, stored) {
17 return new Promise((resolve, reject) => {
18 const [salt, hash] = stored.split(':');
19
20 crypto.scrypt(password, salt, 64, (err, derivedKey) => {
21 if (err) reject(err);
22 resolve(crypto.timingSafeEqual(
23 Buffer.from(hash, 'hex'),
24 derivedKey
25 ));
26 });
27 });
28}
29
30// Usage
31const hashed = await hashPassword('myPassword123');
32console.log('Hashed:', hashed);
33
34const isValid = await verifyPassword('myPassword123', hashed);
35console.log('Valid:', isValid); // trueRandom Bytes#
1import crypto from 'node:crypto';
2
3// Synchronous
4const randomSync = crypto.randomBytes(32);
5console.log(randomSync.toString('hex'));
6
7// Asynchronous
8crypto.randomBytes(32, (err, buffer) => {
9 if (err) throw err;
10 console.log(buffer.toString('hex'));
11});
12
13// Promise wrapper
14function randomBytesAsync(size) {
15 return new Promise((resolve, reject) => {
16 crypto.randomBytes(size, (err, buffer) => {
17 if (err) reject(err);
18 else resolve(buffer);
19 });
20 });
21}
22
23// Generate random string
24function randomString(length) {
25 return crypto.randomBytes(Math.ceil(length / 2))
26 .toString('hex')
27 .slice(0, length);
28}
29
30// Random integer in range
31function randomInt(min, max) {
32 return crypto.randomInt(min, max);
33}
34
35console.log(randomInt(1, 100)); // Random number 1-99UUID Generation#
1import crypto from 'node:crypto';
2
3// Generate UUID v4
4const uuid = crypto.randomUUID();
5console.log(uuid); // e.g., '1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed'
6
7// Batch generation
8function generateUUIDs(count) {
9 return Array.from({ length: count }, () => crypto.randomUUID());
10}Symmetric Encryption (AES)#
1import crypto from 'node:crypto';
2
3const algorithm = 'aes-256-gcm';
4
5// Encrypt
6function encrypt(text, key) {
7 const iv = crypto.randomBytes(16);
8 const cipher = crypto.createCipheriv(algorithm, key, iv);
9
10 let encrypted = cipher.update(text, 'utf8', 'hex');
11 encrypted += cipher.final('hex');
12
13 const authTag = cipher.getAuthTag();
14
15 return {
16 iv: iv.toString('hex'),
17 encrypted,
18 authTag: authTag.toString('hex'),
19 };
20}
21
22// Decrypt
23function decrypt(encrypted, key) {
24 const decipher = crypto.createDecipheriv(
25 algorithm,
26 key,
27 Buffer.from(encrypted.iv, 'hex')
28 );
29
30 decipher.setAuthTag(Buffer.from(encrypted.authTag, 'hex'));
31
32 let decrypted = decipher.update(encrypted.encrypted, 'hex', 'utf8');
33 decrypted += decipher.final('utf8');
34
35 return decrypted;
36}
37
38// Usage
39const key = crypto.randomBytes(32); // 256 bits
40const message = 'Secret message';
41
42const encrypted = encrypt(message, key);
43console.log('Encrypted:', encrypted);
44
45const decrypted = decrypt(encrypted, key);
46console.log('Decrypted:', decrypted);Asymmetric Encryption (RSA)#
1import crypto from 'node:crypto';
2
3// Generate key pair
4function generateKeyPair() {
5 return crypto.generateKeyPairSync('rsa', {
6 modulusLength: 2048,
7 publicKeyEncoding: {
8 type: 'spki',
9 format: 'pem',
10 },
11 privateKeyEncoding: {
12 type: 'pkcs8',
13 format: 'pem',
14 },
15 });
16}
17
18const { publicKey, privateKey } = generateKeyPair();
19
20// Encrypt with public key
21function rsaEncrypt(data, publicKey) {
22 return crypto.publicEncrypt(
23 {
24 key: publicKey,
25 padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
26 oaepHash: 'sha256',
27 },
28 Buffer.from(data)
29 );
30}
31
32// Decrypt with private key
33function rsaDecrypt(encrypted, privateKey) {
34 return crypto.privateDecrypt(
35 {
36 key: privateKey,
37 padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
38 oaepHash: 'sha256',
39 },
40 encrypted
41 ).toString();
42}
43
44// Usage
45const encrypted = rsaEncrypt('Secret', publicKey);
46const decrypted = rsaDecrypt(encrypted, privateKey);Digital Signatures#
1import crypto from 'node:crypto';
2
3// Sign data
4function sign(data, privateKey) {
5 const signer = crypto.createSign('RSA-SHA256');
6 signer.update(data);
7 return signer.sign(privateKey, 'hex');
8}
9
10// Verify signature
11function verify(data, signature, publicKey) {
12 const verifier = crypto.createVerify('RSA-SHA256');
13 verifier.update(data);
14 return verifier.verify(publicKey, signature, 'hex');
15}
16
17// Usage
18const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
19 modulusLength: 2048,
20});
21
22const data = 'Data to sign';
23const signature = sign(data, privateKey);
24const isValid = verify(data, signature, publicKey);
25console.log('Signature valid:', isValid); // trueKey Derivation#
1import crypto from 'node:crypto';
2
3// PBKDF2
4function deriveKeyPbkdf2(password, salt, iterations = 100000) {
5 return new Promise((resolve, reject) => {
6 crypto.pbkdf2(
7 password,
8 salt,
9 iterations,
10 64, // key length
11 'sha512',
12 (err, derivedKey) => {
13 if (err) reject(err);
14 else resolve(derivedKey);
15 }
16 );
17 });
18}
19
20// Scrypt (more secure)
21function deriveKeyScrypt(password, salt) {
22 return new Promise((resolve, reject) => {
23 crypto.scrypt(password, salt, 64, (err, derivedKey) => {
24 if (err) reject(err);
25 else resolve(derivedKey);
26 });
27 });
28}
29
30// Usage
31const salt = crypto.randomBytes(16);
32const key = await deriveKeyPbkdf2('password', salt);
33console.log('Derived key:', key.toString('hex'));Secure Token Generation#
1import crypto from 'node:crypto';
2
3// API token
4function generateApiToken() {
5 return crypto.randomBytes(32).toString('base64url');
6}
7
8// Session token
9function generateSessionToken() {
10 return crypto.randomBytes(48).toString('hex');
11}
12
13// Reset token with expiry
14function generateResetToken() {
15 const token = crypto.randomBytes(32).toString('hex');
16 const expires = Date.now() + 3600000; // 1 hour
17 const hash = crypto.createHash('sha256').update(token).digest('hex');
18
19 return {
20 token, // Send to user
21 hash, // Store in database
22 expires,
23 };
24}
25
26// Verify reset token
27function verifyResetToken(token, storedHash, expiry) {
28 if (Date.now() > expiry) return false;
29 const hash = crypto.createHash('sha256').update(token).digest('hex');
30 return crypto.timingSafeEqual(
31 Buffer.from(hash),
32 Buffer.from(storedHash)
33 );
34}File Hashing#
1import crypto from 'node:crypto';
2import fs from 'node:fs';
3
4// Hash file using streams
5function hashFile(filePath, algorithm = 'sha256') {
6 return new Promise((resolve, reject) => {
7 const hash = crypto.createHash(algorithm);
8 const stream = fs.createReadStream(filePath);
9
10 stream.on('data', (data) => hash.update(data));
11 stream.on('end', () => resolve(hash.digest('hex')));
12 stream.on('error', reject);
13 });
14}
15
16// Verify file integrity
17async function verifyFileIntegrity(filePath, expectedHash) {
18 const actualHash = await hashFile(filePath);
19 return crypto.timingSafeEqual(
20 Buffer.from(actualHash),
21 Buffer.from(expectedHash)
22 );
23}Best Practices#
Hashing:
✓ Use SHA-256 or SHA-512
✓ Use bcrypt/scrypt for passwords
✓ Always use salt
✓ Use timingSafeEqual for comparison
Encryption:
✓ Use AES-256-GCM for symmetric
✓ Use RSA-OAEP for asymmetric
✓ Generate random IVs
✓ Store keys securely
Random:
✓ Use crypto.randomBytes
✓ Use crypto.randomUUID for UUIDs
✓ Use crypto.randomInt for numbers
✓ Never use Math.random for security
Avoid:
✗ MD5 or SHA-1 for security
✗ Hardcoded keys/secrets
✗ ECB mode encryption
✗ Custom crypto implementations
Conclusion#
The Node.js crypto module provides comprehensive cryptographic functionality. Use modern algorithms like SHA-256 for hashing, AES-256-GCM for encryption, and scrypt for password hashing. Always use cryptographically secure random number generation and never roll your own crypto. Store keys securely and use appropriate key lengths for your security requirements.