The crypto module provides cryptographic functionality for hashing, encryption, and secure operations.
Hashing#
1import { createHash } from 'crypto';
2
3// Basic hash
4const hash = createHash('sha256')
5 .update('Hello, World!')
6 .digest('hex');
7console.log(hash);
8
9// Supported algorithms
10createHash('md5');
11createHash('sha1');
12createHash('sha256');
13createHash('sha512');
14
15// Multiple updates
16const multiHash = createHash('sha256');
17multiHash.update('Hello, ');
18multiHash.update('World!');
19const result = multiHash.digest('hex');
20
21// Different output formats
22createHash('sha256').update('data').digest('hex'); // Hexadecimal
23createHash('sha256').update('data').digest('base64'); // Base64
24createHash('sha256').update('data').digest('binary'); // Binary string
25createHash('sha256').update('data').digest(); // Buffer
26
27// File hashing
28import { createReadStream } from 'fs';
29
30async function hashFile(path) {
31 return new Promise((resolve, reject) => {
32 const hash = createHash('sha256');
33 const stream = createReadStream(path);
34
35 stream.on('data', data => hash.update(data));
36 stream.on('end', () => resolve(hash.digest('hex')));
37 stream.on('error', reject);
38 });
39}HMAC#
1import { createHmac } from 'crypto';
2
3// HMAC for message authentication
4const secret = 'my-secret-key';
5const hmac = createHmac('sha256', secret)
6 .update('message to authenticate')
7 .digest('hex');
8
9console.log(hmac);
10
11// Verify HMAC
12function verifyHmac(message, receivedHmac, secret) {
13 const computed = createHmac('sha256', secret)
14 .update(message)
15 .digest('hex');
16
17 // Use timing-safe comparison
18 return timingSafeEqual(
19 Buffer.from(computed),
20 Buffer.from(receivedHmac)
21 );
22}
23
24// Webhook signature verification
25function verifyWebhook(payload, signature, secret) {
26 const expected = createHmac('sha256', secret)
27 .update(payload)
28 .digest('hex');
29
30 return `sha256=${expected}` === signature;
31}Password Hashing#
1import { scrypt, randomBytes, timingSafeEqual } from 'crypto';
2import { promisify } from 'util';
3
4const scryptAsync = promisify(scrypt);
5
6// Hash password
7async function hashPassword(password) {
8 const salt = randomBytes(16).toString('hex');
9 const derivedKey = await scryptAsync(password, salt, 64);
10 return `${salt}:${derivedKey.toString('hex')}`;
11}
12
13// Verify password
14async function verifyPassword(password, stored) {
15 const [salt, hash] = stored.split(':');
16 const derivedKey = await scryptAsync(password, salt, 64);
17 const hashBuffer = Buffer.from(hash, 'hex');
18 return timingSafeEqual(derivedKey, hashBuffer);
19}
20
21// Usage
22const hashed = await hashPassword('myPassword123');
23console.log('Hashed:', hashed);
24
25const isValid = await verifyPassword('myPassword123', hashed);
26console.log('Valid:', isValid); // true
27
28// PBKDF2 alternative
29import { pbkdf2 } from 'crypto';
30
31const pbkdf2Async = promisify(pbkdf2);
32
33async function hashWithPbkdf2(password) {
34 const salt = randomBytes(16);
35 const key = await pbkdf2Async(password, salt, 100000, 64, 'sha512');
36 return `${salt.toString('hex')}:${key.toString('hex')}`;
37}Symmetric Encryption#
1import {
2 createCipheriv,
3 createDecipheriv,
4 randomBytes,
5 scrypt
6} from 'crypto';
7import { promisify } from 'util';
8
9const scryptAsync = promisify(scrypt);
10
11// AES-256-GCM encryption (recommended)
12async function encrypt(text, password) {
13 const salt = randomBytes(16);
14 const key = await scryptAsync(password, salt, 32);
15 const iv = randomBytes(16);
16
17 const cipher = createCipheriv('aes-256-gcm', key, iv);
18 let encrypted = cipher.update(text, 'utf8', 'hex');
19 encrypted += cipher.final('hex');
20
21 const authTag = cipher.getAuthTag();
22
23 return {
24 encrypted,
25 iv: iv.toString('hex'),
26 salt: salt.toString('hex'),
27 authTag: authTag.toString('hex')
28 };
29}
30
31async function decrypt(encryptedData, password) {
32 const { encrypted, iv, salt, authTag } = encryptedData;
33 const key = await scryptAsync(password, Buffer.from(salt, 'hex'), 32);
34
35 const decipher = createDecipheriv(
36 'aes-256-gcm',
37 key,
38 Buffer.from(iv, 'hex')
39 );
40 decipher.setAuthTag(Buffer.from(authTag, 'hex'));
41
42 let decrypted = decipher.update(encrypted, 'hex', 'utf8');
43 decrypted += decipher.final('utf8');
44
45 return decrypted;
46}
47
48// Usage
49const encrypted = await encrypt('Secret message', 'password123');
50const decrypted = await decrypt(encrypted, 'password123');
51console.log(decrypted); // 'Secret message'Asymmetric Encryption#
1import {
2 generateKeyPairSync,
3 publicEncrypt,
4 privateDecrypt
5} from 'crypto';
6
7// Generate key pair
8const { publicKey, privateKey } = generateKeyPairSync('rsa', {
9 modulusLength: 2048,
10 publicKeyEncoding: { type: 'spki', format: 'pem' },
11 privateKeyEncoding: { type: 'pkcs8', format: 'pem' }
12});
13
14// Encrypt with public key
15const encrypted = publicEncrypt(
16 publicKey,
17 Buffer.from('Secret message')
18);
19
20console.log('Encrypted:', encrypted.toString('base64'));
21
22// Decrypt with private key
23const decrypted = privateDecrypt(privateKey, encrypted);
24console.log('Decrypted:', decrypted.toString());
25
26// Generate key pair async
27import { generateKeyPair } from 'crypto';
28
29generateKeyPair('rsa', {
30 modulusLength: 2048
31}, (err, publicKey, privateKey) => {
32 if (err) throw err;
33 // Use keys
34});Digital Signatures#
1import { createSign, createVerify, generateKeyPairSync } from 'crypto';
2
3// Generate keys for signing
4const { publicKey, privateKey } = generateKeyPairSync('rsa', {
5 modulusLength: 2048
6});
7
8// Sign data
9function sign(data, privateKey) {
10 const signer = createSign('SHA256');
11 signer.update(data);
12 signer.end();
13 return signer.sign(privateKey, 'hex');
14}
15
16// Verify signature
17function verify(data, signature, publicKey) {
18 const verifier = createVerify('SHA256');
19 verifier.update(data);
20 verifier.end();
21 return verifier.verify(publicKey, signature, 'hex');
22}
23
24// Usage
25const data = 'Data to sign';
26const signature = sign(data, privateKey);
27console.log('Signature:', signature);
28
29const isValid = verify(data, signature, publicKey);
30console.log('Valid signature:', isValid); // true
31
32// Ed25519 (faster, modern)
33const ed25519Keys = generateKeyPairSync('ed25519');
34const ed25519Signature = sign(data, ed25519Keys.privateKey);
35const ed25519Valid = verify(data, ed25519Signature, ed25519Keys.publicKey);Random Values#
1import { randomBytes, randomUUID, randomInt } from 'crypto';
2
3// Random bytes
4const bytes = randomBytes(32);
5console.log('Random bytes:', bytes.toString('hex'));
6
7// Random UUID
8const uuid = randomUUID();
9console.log('UUID:', uuid);
10
11// Random integer
12randomInt(100, (err, n) => {
13 console.log('Random 0-99:', n);
14});
15
16// Synchronous random int
17const randomNum = randomInt(1, 100); // 1-99
18
19// Secure token generation
20function generateToken(length = 32) {
21 return randomBytes(length).toString('hex');
22}
23
24// Generate random string
25function randomString(length, charset = 'alphanumeric') {
26 const charsets = {
27 alphanumeric: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
28 hex: '0123456789abcdef',
29 numeric: '0123456789'
30 };
31
32 const chars = charsets[charset] || charset;
33 const bytes = randomBytes(length);
34
35 return Array.from(bytes)
36 .map(byte => chars[byte % chars.length])
37 .join('');
38}
39
40console.log(randomString(16));Key Derivation#
1import { scrypt, pbkdf2, hkdf } from 'crypto';
2import { promisify } from 'util';
3
4// scrypt - memory-hard, good for passwords
5const scryptAsync = promisify(scrypt);
6
7async function deriveKeyScrypt(password, salt) {
8 const key = await scryptAsync(password, salt, 32, {
9 N: 16384, // CPU/memory cost
10 r: 8, // Block size
11 p: 1 // Parallelization
12 });
13 return key;
14}
15
16// PBKDF2 - widely supported
17const pbkdf2Async = promisify(pbkdf2);
18
19async function deriveKeyPbkdf2(password, salt) {
20 const key = await pbkdf2Async(
21 password,
22 salt,
23 100000, // Iterations
24 32, // Key length
25 'sha512' // Digest
26 );
27 return key;
28}
29
30// HKDF - for key expansion
31const hkdfAsync = promisify(hkdf);
32
33async function expandKey(key, salt, info, length = 32) {
34 const derived = await hkdfAsync('sha256', key, salt, info, length);
35 return derived;
36}Diffie-Hellman Key Exchange#
1import { createDiffieHellman, createECDH } from 'crypto';
2
3// Classic DH
4const alice = createDiffieHellman(2048);
5alice.generateKeys();
6
7const bob = createDiffieHellman(
8 alice.getPrime(),
9 alice.getGenerator()
10);
11bob.generateKeys();
12
13// Exchange public keys and compute shared secret
14const aliceSecret = alice.computeSecret(bob.getPublicKey());
15const bobSecret = bob.computeSecret(alice.getPublicKey());
16
17console.log('Secrets match:', aliceSecret.equals(bobSecret));
18
19// ECDH (more efficient)
20const aliceECDH = createECDH('secp256k1');
21aliceECDH.generateKeys();
22
23const bobECDH = createECDH('secp256k1');
24bobECDH.generateKeys();
25
26const aliceShared = aliceECDH.computeSecret(bobECDH.getPublicKey());
27const bobShared = bobECDH.computeSecret(aliceECDH.getPublicKey());
28
29console.log('ECDH secrets match:', aliceShared.equals(bobShared));Practical Examples#
1// API key generation
2function generateApiKey() {
3 const prefix = 'sk_live_';
4 const key = randomBytes(24).toString('base64url');
5 return prefix + key;
6}
7
8// Secure token for email verification
9function generateVerificationToken() {
10 return randomBytes(32).toString('hex');
11}
12
13// Hash sensitive data for storage
14function hashSensitiveData(data) {
15 return createHash('sha256')
16 .update(data)
17 .digest('hex');
18}
19
20// Checksum for file integrity
21async function calculateChecksum(filePath) {
22 return hashFile(filePath); // Using earlier hashFile function
23}
24
25// Secure cookie signing
26function signCookie(value, secret) {
27 const signature = createHmac('sha256', secret)
28 .update(value)
29 .digest('base64url');
30 return `${value}.${signature}`;
31}
32
33function verifyCookie(signedValue, secret) {
34 const [value, signature] = signedValue.split('.');
35 const expected = createHmac('sha256', secret)
36 .update(value)
37 .digest('base64url');
38
39 if (timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
40 return value;
41 }
42 return null;
43}Best Practices#
Algorithms:
✓ SHA-256 or SHA-512 for hashing
✓ AES-256-GCM for encryption
✓ scrypt or Argon2 for passwords
✓ Ed25519 for signatures
Security:
✓ Use timing-safe comparison
✓ Generate IVs/nonces randomly
✓ Store salts with hashes
✓ Use authenticated encryption
Key Management:
✓ Generate strong random keys
✓ Rotate keys periodically
✓ Secure key storage
✓ Use key derivation
Avoid:
✗ MD5 or SHA1 for security
✗ ECB mode encryption
✗ Hardcoded secrets
✗ Reusing IVs/nonces
Conclusion#
Node.js crypto module provides comprehensive cryptographic tools. Use appropriate algorithms for each task: SHA-256+ for hashing, AES-GCM for encryption, scrypt for passwords, and modern signature algorithms. Always use secure random generation, proper key derivation, and timing-safe comparisons. Keep security practices current as cryptographic recommendations evolve.