DEV Community

Cover image for A Simple Password Hash implementation
Chinedu Orie
Chinedu Orie

Posted on

A Simple Password Hash implementation

Passwords are not stored as plain text for obvious security reasons. There are several npm packages already in place for password encryption such as bcrypt.js, password-hash etc.

This article does not aim to provide a better solution to the ones already provided by the existing libraries, rather it tends to shed some light on how the implementation works under the hood.

Getting Started

I assume that you already created a project. Now go ahead and create a file named custom-bcrypt.js.

Copy the snippet below into the custom-bcrypt.js file:

const md5 = require("md5");

module.exports = {
  /**
   *
   *
   * @param { string } rawPass - the password to be hashed
   * @param { object } [options={}] - object containing salt and rounds
   * @returns {string} 
   */
  hash(rawPassword, options = {}) {
    /**
     * salt is optional, if not provided it will be set to current timestamp
     */
    const salt = options.salt ? options.salt : new Date().getTime();

    /**
     * rounds is optional, if not provided it will be set to 10
     */
    const rounds = options.rounds ? options.rounds : 10;

    let hashed = md5(rawPassword + salt);
    for (let i = 0; i <= rounds; i++) {
      hashed = md5(hashed);
    }
    return `${salt}$${rounds}$${hashed}`;
  },
  /**
   *
   *
   * @param {string} rawPassword - the raw password
   * @param { string } hashedPassword - the hashed password
   * @returns
   */
  compare(rawPassword, hashedPassword) {
    try {
      const [ salt, rounds ] = hashedPassword.split('$');
      const hashedRawPassword = this.hash(rawPassword, { salt, rounds });
      return hashedPassword === hashedRawPassword;
    } catch (error) {
      throw Error(error.message);
    }
  }
};

Enter fullscreen mode Exit fullscreen mode

Let's us explain what's going on in the code snippet above.

First, notice that we required md5 library which forms the base for the hashing. Now, install md5 in the project.

npm add md5 or yarn add md5
Enter fullscreen mode Exit fullscreen mode

Salt

In cryptography, a salt is random data that is used as an additional input to a one-way function that "hashes" data, a password or passphrase. Salts are used to safeguard passwords in storage. Salts defend against a pre-computed hash attack. - wikipedia

Rounds

The rounds specify the number of iterations used in the hashing. The higher the rounds the more difficult it is for hackers to guess the password using rainbow table.

Notice that in the custom-bcrypt module above, we have two functions hash and compare.

hash function

The hash function takes two arguments, the password to be hashed and the options object which is set to an empty object by default. The options object has two optional properties the salt and the rounds which are set to the current timestamp and 10 respectively. This function uses md5 to encrypt the password plus the salt as many times as the rounds. The returned value is a string consisting of the salt, rounds and the hashed value all concatenated together.

compare function

The compare function takes two arguments, the raw password to be verified and the previously hashed password. It extracts the salt and rounds from the previously hashed password and then uses it to hash the current raw password and returns a corresponding Boolean value for whether the password matches or not.

Now, let's test our custom bcrypt module. Create a file named sample.js.
Copy the code below into the sample.js

const bcrypt = require('./custom-bcrypt')

const rawPassword = 'password'

console.log(bcrypt.hash(rawPassword))
//1563995248971$10$58e0867f3acc11de363e03389bb27167

console.log(bcrypt.compare('password','1563995248971$10$58e0867f3acc11de363e03389bb27167'));
//true

console.log(bcrypt.hash(rawPassword, {salt: 'someRandomString', rounds: 20}))
//someRandomString$20$199d9de71859a87cdd22e52d93f4522a

console.log(bcrypt.compare('password', 'someRandomString$20$199d9de71859a87cdd22e52d93f4522a'));
//true
Enter fullscreen mode Exit fullscreen mode

You can test it how ever you want, for the sake of this article, I tested it on the terminal using node sample.js.

Disclaimer: This article does not guarantee the security of encryption implemented herein.

Conclusion

In this article, we tried to shed some light on how password encryption works. Feel free to reach out to me if you have any question or contribution to this article. ✌️

This article was originally published on my blog

Top comments (2)

Collapse
 
elmuerte profile image
Michiel Hendriks

Violation of rule #1 of cryptography:

Never ever invent your own crypto algorithm.

Crypto is difficult, really difficult.

Hashcat can do 25Giga-hashes per second for MD5. Only 13000 hashes per second for bcrypt with the cost parameter set to 5 (at this point 12 is advised, which is 2^7 more slower). So even if you would do a million rounds in the above algorithm you do not come close to bcrypt's security. Also, I have no idea if doing multiple rounds of md5 makes it more secure.

Just use bcrypt, it is battle tested and still secure.

Collapse
 
nedsoft profile image
Chinedu Orie

Thanks for your feedback. However, if you read through the article, you would have observed that I stated clearly the intent.

This article does not aim to provide a better solution to the ones already provided by the existing libraries, rather it tends to shed some light on how the implementation works under the hood.

Also, before the Conclusion, there's a disclaimer

Disclaimer: This article does not guarantee the security of encryption implemented herein.

I hope this helps explain better.