Unlocking Secure Password Storage with Salt Hashing

What is Hashing?

Hashing is a crucial concept in cryptography that involves mapping data of any size to a fixed-length string using an algorithm. This one-way function is primarily used for authentication purposes.

The Power of Salt Hashing

Salt hashing is a method that adds an extra layer of security to password storage. It involves combining a user-entered password with a random string of characters (salt) and then hashing the combined string using a suitable crypto hashing algorithm. The resulting hash is stored in the database, ensuring that plaintext passwords are never stored.

Getting Started

To follow along with this tutorial, you’ll need:

  • A basic understanding of Node.js
  • A code editor, such as VS Code, installed
  • POSTMAN installed
  • MongoDB set up

Crafting the Hashing Functions

We’ll create three functions to perform the following tasks:

  1. Generate a random salt
  2. Hash the data
  3. Compare the hashes

Setting Up the Node.js Application

Create a package.json file to document dependencies and an index.js file, which will serve as the root of our application.

const crypto = require('crypto');

const log = (message) => console.log(message);

Generating the Salt

Our first function will generate a random salt. This function takes in a number as a parameter to define the length of the salt. We’ll add a simple validator to ensure the number is greater than 15.

const generateSalt = (length) => {
  if (length <= 15) {
    throw new Error('Salt length must be greater than 15');
  }
  return crypto.randomBytes(length).toString('hex');
};

Hashing the Data

Next, we’ll define our hashing algorithm using the crypto.createHmac() method. We’ll use the sha512 algorithm and pass in our salt as the key.

const hashData = (password, salt) => {
  const hmac = crypto.createHmac('sha512', salt);
  hmac.update(password);
  return hmac.digest('hex');
};

Comparing the Hashes

Our compare password function will use the same algorithm to hash the inputted password and then test whether the new hash matches the stored hash. We’ll write some validation to check whether the password or hash is provided and whether the type of password is a string and type of hash is an object.

const compareHashes = (inputPassword, storedHash, salt) => {
  if (!inputPassword ||!storedHash ||!salt) {
    throw new Error('Password, hash, and salt are required');
  }
  if (typeof inputPassword!== 'tring' || typeof storedHash!== 'object') {
    throw new Error('Invalid password or hash type');
  }
  const hashedInputPassword = hashData(inputPassword, salt);
  return hashedInputPassword === storedHash.hash;
};

Putting it All Together

Now that we have our hashing functions, let’s create a test.js file to test our hasher module. We’ll set up a simple express server, connect to MongoDB, and create the necessary routes.

// Import dependencies and create an express app
const express = require('express');
const app = express();
const mongoose = require('mongoose');

// Connect to MongoDB
mongoose.connect('mongodb://localhost:27017/password-hash-db', { useNewUrlParser: true, useUnifiedTopology: true });

// Define the User model
const userSchema = new mongoose.Schema({
  username: String,
  password: String,
  salt: String,
});

const User = mongoose.model('User', userSchema);

// Register route
app.post('/register', (req, res) => {
  const { username, password } = req.body;
  const salt = generateSalt(16);
  const hashedPassword = hashData(password, salt);
  const user = new User({ username, password: hashedPassword, salt });
  user.save((err) => {
    if (err) {
      res.status(500).send(err);
    } else {
      res.send(`User created successfully`);
    }
  });
});

// Login route
app.post('/login', (req, res) => {
  const { username, password } = req.body;
  User.findOne({ username }, (err, user) => {
    if (err) {
      res.status(500).send(err);
    } else if (!user) {
      res.status(404).send('User not found');
    } else {
      const isValid = compareHashes(password, user.password, user.salt);
      if (isValid) {
        res.send(`Login successful`);
      } else {
        res.status(401).send('Invalid password');
      }
    }
  });
});

// Start the server
const port = 3000;
app.listen(port, () => {
  console.log(`Server started on port ${port}`);
});

Testing the Password Hasher

Open POSTMAN and make a post request to /register following the defined schema. Then, implement the login route and test it using POSTMAN. Our password hasher is working perfectly!

Note: While this guide demonstrates how salting works in Node.js crypto, it’s essential to note that this implementation has some flaws and shouldn’t be used in production. Better tools, such as Bcrypt, are more suitable for production applications. The source code is available on GitHub.

Leave a Reply