The crypto Module: Hashing and Random Values
Objectives
By the end of this lesson, you should be able to:
- Hash a value with
crypto.createHash - Generate secure random values with
crypto.randomBytesandcrypto.randomUUID - Hash and verify a password with a salt using
crypto.scryptSync
💡 Why this matters: Storing a user’s password in plain text is a serious security failure. Node’s built-in
cryptomodule provides everything needed to hash values and generate secure random data, no external package required, and this exact pattern reappears once user authentication is built in a later course.
⚠️ A note on verification: every snippet and output in this lesson was actually run with Node.js.
Hashing a Value
const crypto = require('crypto');
const hash = crypto.createHash('sha256').update('hello world').digest('hex');
console.log('sha256 hash:', hash);
sha256 hash: b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
createHash('sha256') creates a hash object using the SHA-256 algorithm, .update(value) feeds it the data to hash, and .digest('hex') produces the final result as a hex string. Hashing is one-way, there’s no way to recover 'hello world' from the hash, and hashing the exact same input always produces the exact same output, this determinism is why hashing alone isn’t enough for passwords, covered next.
Random Values
const crypto = require('crypto');
const uuid = crypto.randomUUID();
console.log('uuid:', uuid);
const randomHex = crypto.randomBytes(8).toString('hex');
console.log('random bytes (hex):', randomHex);
uuid: c846c8a0-0b95-414b-b411-b6e7f61188e9
random bytes (hex): fda70a0cc96e108c
crypto.randomUUID() generates a standard-format unique identifier, useful anywhere a unique ID is needed (a database record, a session token) without relying on a database to assign one. crypto.randomBytes(n) generates n cryptographically secure random bytes, .toString('hex') renders them as a readable hex string. Both use a source of true randomness suitable for security purposes, unlike Math.random(), which is not secure enough for anything sensitive.
Hashing Passwords Correctly
Hashing a password directly with createHash is not safe, identical passwords produce identical hashes, and fast hash algorithms like SHA-256 can be brute-forced quickly. The standard fix is a salt, random data mixed into each password before hashing, combined with a deliberately slow algorithm:
const crypto = require('crypto');
function hashPassword(password) {
const salt = crypto.randomBytes(16).toString('hex');
const hash = crypto.scryptSync(password, salt, 64).toString('hex');
return `${salt}:${hash}`;
}
function verifyPassword(password, stored) {
const [salt, originalHash] = stored.split(':');
const hash = crypto.scryptSync(password, salt, 64).toString('hex');
return hash === originalHash;
}
const stored = hashPassword('correct horse battery staple');
console.log('correct password:', verifyPassword('correct horse battery staple', stored));
console.log('wrong password:', verifyPassword('wrong guess', stored));
correct password: true
wrong password: false
scryptSync(password, salt, keylen) is deliberately slow and memory-intensive, making brute-force guessing impractical. Storing salt:hash together (the salt itself isn’t secret) lets verifyPassword re-hash a login attempt with the same salt, and compare the result, this is exactly how real authentication systems check a password without ever storing it directly.
Try It
- Hash the strings
'apple'and'Apple'withcreateHash('sha256'), and confirm the hashes are completely different despite the tiny input difference. - Generate five UUIDs in a loop with
crypto.randomUUID(), and confirm every one is different. - Write the
hashPassword/verifyPasswordpair yourself from scratch, then test it with a correct password, an incorrect password, and an empty string. - Explain, in your own words, why a salt is necessary even though
scryptSyncis already a strong hashing algorithm.
Recap
createHash(algorithm).update(value).digest('hex')produces a one-way hash of a value.randomUUID()andrandomBytes(n)generate cryptographically secure random values.- Passwords should be hashed with a per-password salt and a slow algorithm like
scryptSync, never with a fast hash alone.
Next lesson: events, Node’s event emitter pattern.