The One Hash Function You Need, BCrypt
Tags: javascript, security, beginners, webdev
Published: 2022-02-18 14:23:38

Whether you are building authentication for your app or designing a communication scheme, one thing is sure, you need hashes. And we got you the best kind. The scalable kind with a pinch of salt!.

> **bcrypt** is a password-hashing function designed by *Niels Provos* and *David Mazières*, based on the **_Blowfish_** cipher and presented at USENIX in 1999.

Technicalities aside, this algorithm has two very important properties. 

One, it employs a _salt_-mechanism to mitigate [Rainbow Table attacks](https://en.wikipedia.org/wiki/Rainbow_table). And two, it introduces control over computation-time cost to scale with processing power and keep [Dictionary attacks](https://en.wikipedia.org/wiki/Dictionary_attack) within practically-infeasable range.

This exposition targets _JS_ users. But keep in mind that there is a _Python_ implementation. 

To get you started, you can install the package by typing,

```javascript
npm install bcrypt
```
From there you can import the library using,

```javascript
// ES5 syntax
const bcrypt = require('bcrypt')
// ES6 syntax
import bcrypt from 'bcrypt'
```
The package is relatively small and has only essential features. Exposed to us in two flavor, both *synchronous* and *asynchronous*, these are,

### 1. Salt Generation

```javascript
// Sync
const salt = bcrypt.genSaltSync(rounds)

// Async
bcrypt.genSalt(rounds).then(function(salt){
		// Use the salt
})

```

### 2. Hashing

```javascript
// Sync
const hash = bcrypt.hashSync(plainMessage, salt)
/* Hash with auto-generated salt */
const hash = bcrypt.hashSync(plainMessage, saltRounds)

// Async
bcrypt.hash(plainMessage, saltRounds).then(function(hash) {
    // Use the hash
})
```

### 3. Verification

```javascript
// Sync
bcrypt.compareSync(testMessage, hash)

// Async
bcrypt.compare(testMessage, hash).then(function(result) {
    // result == true or false
})
```

It might be surprising but this is all there is to **_Bcrypt.js_**. Pretty simple, huh!

---

Now to help you better see this in action. Here is a quick example of how a simple authentication scheme using **_Express.js_** and **_Mongoose.js_** would look like.


We will make a simple _**Node.JS**_ backend. **Express** will handle the requests while, **Mongoose** will be used to store the user data. And before any of that, make sure you created a *npm* project and have _[both packages installed](https://dev.to/franciscomendes10866/setup-mongodb-with-mongoose-and-express-4c58)_ along with *Bcrypt*(as shown above).

From here, it is a 3+0-step work.

## Step ZERO

We lay the structure of our app, by setting up an _Express_ server with two POST routes to handle both register and login actions.

```javascript
/* filename: ./index.js */

const Express = require("express");
const bcrypt = require("bcrypt");

// Import our User Model
const User = require("./model");

// Connection to Mongo DB
const Connect = require("./Connectdb");

const app = Express();

// CONSTANTS (these can be put in a .env file)
const SALT_ROUNDS = 10
const PORT = 3000

// Middleware for sending JSON type messages
app.use(express.json());

// Handling Registration for New Users
app.post('/register',(req, res)=>{
  // CODE for handling Registration will go here ...
})

// Handling Login 
app.post('/login',(req, res)=>{
  // CODE for handling Login will go here ...
})

// Server Launch
app.listen(PORT, () => {
  console.log(`Sever online and accessible via localhost:${PORT}.`);
});
```

_**Note**: for more information on how to use the .env utility, [see this article](https://dev.to/vyasriday/using-dotenv-to-manage-environment-variables-in-nodejs-3ja1)._

## Step ONE

For this step we need to make two things. One, is to write the code that will enable the connection to our Mongo DB.

```javascript
const mongoose = require("mongoose");

const ConnectDb = (url) => {
  return mongoose.connect(url, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
  });
};

module.exports = ConnectDb;
```

Two, we create a user [model](https://mongoosejs.com/docs/models.html). We keep it simple; our model will only have **email**, **password**, and **username** fields.

```javascript
const mongoose = require("mongoose");

const UserSchema = new mongoose.Schema({
  username: String,
  password: String,
  email: String,
});

module.exports = mongoose.model("User", UserSchema);
```

## Step TWO

Now that everything is ready, it is time to hash password and add the salt!


To make the register controller, we need to:  

1. - Verify if the user already exists.
2. - Generate a salt then, hash the password.
4. - Save the user with the hashed password.
5. - Return the `User` object.

```javascript
//Register Route
app.post("/register", async (req, res) => {

  // deconstruct the body sent via request
  const { username, password, email } = req.body;

  // check if all the information is filled properly
  if (!username || !password || !email) {
    res.status(400).json({ msg: "Please provide valid information." });
  }

  // Generate the salt
  const salt = await bcrypt.genSalt(SALT_ROUNDS);

  // Hash The password
  const passwordHash = await bcrypt.hash(password, salt);

  // Check if the user already exits in our Database
  const IsExist = await User.findOne({ email });
  if (IsExist) {
    res.status(400).json({ msg: "User already exists." });
  }

  try {
    const savedUser = await User.create({
      username,
      email,
      password: passwordHash,
    });

    res.status(200).json({ msg: "Successfully added user:", savedUser });
  } catch (error) {
    res.status(500).json({ error });
  }
});
```

To test this route, we can use _VS Code'_s extension, **Thunder Client**. We make an API request to our server with email and username and password in the body like so,

![a post request to an the register/login route with bcrypt as a hashing algorithm for our passwords and safely stored in db](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ks0k53723i1x3zg0l7ic.png)
 
and as you can see, the response contains the hash of our password. It is important to note that the returned hash embeds information about its computation.

```
$2b$10$nOUIs5kJ7naTuTFkBy1veuK0kSxUFXfuaOKdOKf9xYT0KKIGSJwFa
 |  |  |                     |
 |  |  |                     hash-value = K0kSxUFXfuaOKdOKf9xYT0KKIGSJwFa
 |  |  |
 |  |  salt = nOUIs5kJ7naTuTFkBy1veu
 |  |
 |  cost-factor => 10 = 2^10 rounds
 |
 hash-algorithm identifier => 2b = BCrypt
```
_[Taken from the package's official npm page.](https://www.npmjs.com/package/bcrypt)_

## Step THREE

The elaboration of the login controller is much more concise than the registration process. All we need to do is, 

1. - Check if the user is actually registered.
2. - Verify the password.
3. - Return the `User` object.

```javascript
// Login Route
app.post("/login", async (req, res) => {

  // deconstruct the request body
  const { email, password } = req.body;

  // check if all the information is filled properly
  if (!password || !email) {
    res.status(400).json({ msg: "Please provide valid information." });
  }

  // check if user already exists
  const userExists = await User.findOne({ email });
  console.log(userExists);

  if (!userExists) {
    res.status(400).json({ msg: "Please Register." });
  }

  // verify the given password 
  const isPassword = await bcrypt.compare(password, userExists.password);

  // if incorrect
  if (!isPassword) {
    res.status(400).json({ msg: "Email or password incorect." });
  }

  //if correct
  res.status(200).json({ userExists });
});

```

We again use **_Thunder_** to test the route.

![thunder request to login route using bcrypt to compare the passwords](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r1l7e2pgg1l8fqedjsxm.png)

The response object do contain the user in our _database_  and since the password is correct, the hash will match and the user can be logged safely without the need of storing sensitive data.

> Please acknowledge that this is not a production-ready application. We wrote this article with the aim of showcasing the use of **_Bcrypt.js_** in authentication. 

---

If you are a developer who doesn’t want to the headaches of cryptographic technicalities and just wants a default go-to utility. Bcrypt.js is what you need for all your hash matters. Don’t get me wrong, I am saying it is perfect in all regards but at least it mitigates the most obvious attacks. 

To back up this claim. We share with you a benchmark test done with our potato PC. It shows computation-time cost per number of rounds.

![Salt Rounds vs. Time](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vth92rsvo7ggbq4rge81.png)
 
As you can see, the number of rounds controls how much time is needed for computation. And for data transmission, any choice under 10 rounds wouldn’t put too much strain on the speed of your communications. The implementation wouldn't be too far from the register/login example. 

Overall **_Bcrypt.js_** is simple and versatile. Let us know in the comment what do you think! 

Find the code at [CoddingAddicts/BcryptDoc](https://github.com/CoddingAddicts/BcryptDoc)

This was the <u>_Codding Addicts_</u> and until next time.