How to Hash Passwords Using Node.js Crypto Module

This article explains the purpose of the built-in crypto module in Node.js and demonstrates how to use it for secure password hashing. You will learn the importance of cryptographic functions in application security, how to securely hash a password using a salt, and how to verify user credentials during authentication.

Purpose of the Node.js Crypto Module

The crypto module is a built-in Node.js library that provides cryptographic functionality, wrapping OpenSSL’s cryptographic functions. It allows developers to secure application data without relying on third-party libraries. The module provides tools for:

For password storage, the crypto module is primarily used to perform one-way hashing. One-way hashing ensures that even if a database is compromised, the actual plain-text passwords of users remain unreadable.

Why Hashing Passwords Requires a Salt

Simply hashing a password is not secure enough. Attackers can use precomputed tables of hashes (known as rainbow tables) to easily crack simple hashed passwords.

To prevent this, you must use a salt. A salt is a unique, random string generated for each user that is combined with the password before hashing. This ensures that two users with the exact same password will have entirely different hashes in the database.

How to Hash a Password using crypto.scrypt

Node.js offers the scrypt algorithm within the crypto module, which is specifically designed to be slow and resource-intensive to prevent brute-force attacks.

Here is how to generate a secure salt and hash a password:

const crypto = require('crypto');

function hashPassword(password) {
    // Generate a random 16-byte salt
    const salt = crypto.randomBytes(16).toString('hex');

    // Hash the password using scrypt with the generated salt
    const derivedKey = crypto.scryptSync(password, salt, 64);

    // Combine the salt and hash to store in the database
    const hashedPassword = `${salt}:${derivedKey.toString('hex')}`;
    
    return hashedPassword;
}

const secureStorage = hashPassword("mySuperSecretPassword123");
console.log("Stored Value:", secureStorage);

In this example, the resulting string contains both the salt and the generated hash, separated by a colon. You should store this combined string in your database.

How to Verify a Password During Login

To verify a user’s password during login, you must retrieve the stored salt and hash from the database, hash the incoming password attempt using that same salt, and compare the results.

Here is how to verify the password:

function verifyPassword(passwordAttempt, storedValue) {
    // Split the salt and the hash from the stored database string
    const [salt, originalHash] = storedValue.split(':');

    // Hash the login attempt using the same salt
    const hashToVerify = crypto.scryptSync(passwordAttempt, salt, 64).toString('hex');

    // Compare the original hash with the new hash
    return hashToVerify === originalHash;
}

// Example usage
const isMatch = verifyPassword("mySuperSecretPassword123", secureStorage);
console.log("Password match status:", isMatch); // Outputs: true

By utilizing crypto.scryptSync alongside random salts, you can easily implement robust, secure password hashing in your Node.js applications without external dependencies.