🛂 Crypto
11 Mar, 2020
👋 FYI, this note is over 6 months old. Some of the content may be out of date.
On this page
The crypto module provides cryptographic functionality including hashing, HMAC, encryption/decryption, signing, and random value generation. Available in both Node.js and modern browsers via the Web Crypto API.
Random Values Jump to heading
Generate UUID Jump to heading
// Works in Node.js and browsers
crypto.randomUUID();
// → "550e8400-e29b-41d4-a716-446655440000"
Random Bytes Jump to heading
import crypto from 'crypto';
// Generate random bytes (Node.js)
const buffer = crypto.randomBytes(32);
const hex = buffer.toString('hex');
// → "a3f2b8c9d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1"
// Generate random bytes (Browser)
const array = new Uint8Array(32);
crypto.getRandomValues(array);
Random Integer Jump to heading
import crypto from 'crypto';
// Generate random integer in range [min, max)
crypto.randomInt(100); // 0-99
crypto.randomInt(10, 100); // 10-99
// Async version
const num = await crypto.randomInt(1, 1000);
Hashing Jump to heading
Basic Hash (SHA-256) Jump to heading
import crypto from 'crypto';
const data = 'Hello, World!';
const hash = crypto.createHash('sha256').update(data).digest('hex');
// → "dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f"
Hash an Object Jump to heading
import crypto from 'crypto';
const body = {
uuid: '433d7a1b-e8e1-4b5a-b590-f468e5c18cc7',
name: 'Zander',
};
const hash = crypto.createHash('sha256');
hash.update(JSON.stringify(body));
const hashedResponse = hash.digest('hex');
// → "5a7430e6d96dafadc642289eba7e215d3b9cfd7a58f9593749891424e6d75a4f"
Available Hash Algorithms Jump to heading
// List all available hash algorithms
crypto.getHashes();
// → ['sha256', 'sha512', 'sha3-256', 'md5', 'blake2b512', ...]
| Algorithm | Output Size | Use Case |
|---|---|---|
sha256 |
256 bits | General purpose, signatures |
sha512 |
512 bits | Higher security needs |
sha3-256 |
256 bits | Modern alternative to SHA-2 |
md5 |
128 bits | Checksums only (not secure!) |
blake2b512 |
512 bits | Fast, secure alternative |
Hash a File Jump to heading
import crypto from 'crypto';
import fs from 'fs';
function hashFile(filepath) {
return new Promise((resolve, reject) => {
const hash = crypto.createHash('sha256');
const stream = fs.createReadStream(filepath);
stream.on('data', (chunk) => hash.update(chunk));
stream.on('end', () => resolve(hash.digest('hex')));
stream.on('error', reject);
});
}
const checksum = await hashFile('./large-file.zip');
HMAC (Hash-based Message Authentication Code) Jump to heading
Used for verifying data integrity and authenticity with a secret key.
import crypto from 'crypto';
const secret = 'my-secret-key';
const message = 'Important message';
const hmac = crypto.createHmac('sha256', secret)
.update(message)
.digest('hex');
// → "8b5a4e3f2c1d0e9f8a7b6c5d4e3f2a1b..."
Verify Webhook Signature Jump to heading
import crypto from 'crypto';
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
// Use timingSafeEqual to prevent timing attacks
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
Encryption & Decryption Jump to heading
AES-256-GCM (Recommended) Jump to heading
import crypto from 'crypto';
const algorithm = 'aes-256-gcm';
function encrypt(text, key) {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
const authTag = cipher.getAuthTag();
return {
iv: iv.toString('hex'),
encrypted,
authTag: authTag.toString('hex'),
};
}
function decrypt(encryptedData, key) {
const decipher = crypto.createDecipheriv(
algorithm,
key,
Buffer.from(encryptedData.iv, 'hex')
);
decipher.setAuthTag(Buffer.from(encryptedData.authTag, 'hex'));
let decrypted = decipher.update(encryptedData.encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
// Usage
const key = crypto.randomBytes(32); // 256-bit key
const encrypted = encrypt('Secret message', key);
const decrypted = decrypt(encrypted, key);
Generate Secure Key from Password Jump to heading
import crypto from 'crypto';
// Derive a key from a password using PBKDF2
function deriveKey(password, salt = crypto.randomBytes(16)) {
const key = crypto.pbkdf2Sync(
password,
salt,
100000, // iterations
32, // key length
'sha256'
);
return { key, salt };
}
// Async version
async function deriveKeyAsync(password, salt) {
return new Promise((resolve, reject) => {
crypto.pbkdf2(password, salt, 100000, 32, 'sha256', (err, key) => {
if (err) reject(err);
else resolve(key);
});
});
}
Password Hashing (with scrypt) Jump to heading
For storing passwords, use scrypt — designed to be slow and memory-hard.
import crypto from 'crypto';
async function hashPassword(password) {
const salt = crypto.randomBytes(16);
return new Promise((resolve, reject) => {
crypto.scrypt(password, salt, 64, (err, derivedKey) => {
if (err) reject(err);
resolve(salt.toString('hex') + ':' + derivedKey.toString('hex'));
});
});
}
async function verifyPassword(password, hash) {
const [salt, key] = hash.split(':');
return new Promise((resolve, reject) => {
crypto.scrypt(password, Buffer.from(salt, 'hex'), 64, (err, derivedKey) => {
if (err) reject(err);
resolve(crypto.timingSafeEqual(
Buffer.from(key, 'hex'),
derivedKey
));
});
});
}
// Usage
const hashed = await hashPassword('mySecretPassword');
const isValid = await verifyPassword('mySecretPassword', hashed); // true
Digital Signatures Jump to heading
Sign and Verify Data Jump to heading
import crypto from 'crypto';
// Generate key pair
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
});
// Sign data
const data = 'Data to sign';
const signature = crypto.sign('sha256', Buffer.from(data), privateKey);
// Verify signature
const isValid = crypto.verify(
'sha256',
Buffer.from(data),
publicKey,
signature
);
// → true
Generate Key Pair (Async) Jump to heading
import crypto from 'crypto';
const { publicKey, privateKey } = await crypto.generateKeyPair('ed25519');
// Export keys as PEM
const publicPem = publicKey.export({ type: 'spki', format: 'pem' });
const privatePem = privateKey.export({ type: 'pkcs8', format: 'pem' });
Web Crypto API (Browser) Jump to heading
The browser’s built-in crypto API for client-side cryptography.
Hash in Browser Jump to heading
async function sha256(message) {
const msgBuffer = new TextEncoder().encode(message);
const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}
await sha256('Hello, World!');
// → "dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f"
Encrypt in Browser Jump to heading
async function generateKey() {
return crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
}
async function encrypt(plaintext, key) {
const iv = crypto.getRandomValues(new Uint8Array(12));
const encoded = new TextEncoder().encode(plaintext);
const ciphertext = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
key,
encoded
);
return { iv, ciphertext };
}
async function decrypt({ iv, ciphertext }, key) {
const decrypted = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv },
key,
ciphertext
);
return new TextDecoder().decode(decrypted);
}
Quick Reference Jump to heading
| Task | Method |
|---|---|
| Generate UUID | crypto.randomUUID() |
| Random bytes | crypto.randomBytes(n) |
| Hash data | crypto.createHash('sha256').update(data).digest('hex') |
| HMAC | crypto.createHmac('sha256', secret).update(data).digest('hex') |
| Encrypt | crypto.createCipheriv(algorithm, key, iv) |
| Decrypt | crypto.createDecipheriv(algorithm, key, iv) |
| Password hash | crypto.scrypt(password, salt, keylen, callback) |
| Sign data | crypto.sign('sha256', data, privateKey) |
| Verify signature | crypto.verify('sha256', data, publicKey, signature) |
| Compare securely | crypto.timingSafeEqual(a, b) |
Security Best Practices Jump to heading
- Never use MD5 or SHA1 for security purposes — they’re broken
- Use
timingSafeEqualwhen comparing hashes to prevent timing attacks - Generate fresh IVs for each encryption operation
- Use authenticated encryption (AES-GCM) to detect tampering
- Store salts with hashes — they don’t need to be secret
- Use high iteration counts for password hashing (≥100,000 for PBKDF2)
- Prefer
scryptorargon2over PBKDF2 for password storage
← Back home