Skip to main content
/aug 20, 2018

Zero to Hashing in under 10 Minutes: Argon2 in Nodejs

By Justin Boyer

View a screencast walkthrough of the material in this post.

Those who work with the Agile methodology expect change. The security field is no different. It’s hard for developers to keep up with all of the changes in application security practices. In fact, it’s sometimes difficult for security experts to keep up with the same changes.

A recent change (in security terms) occurred when a new hash algorithm called Argon2 was created. This algorithm won a contest called Password Hashing Competition, held between 2013 and 2015. Argon2 is now the recommended hashing algorithm by OWASP for all new applications.

Developers have the responsibility to keep up with these security changes. They are the ones that control the code and hold the security of users in their fingers. Let’s take a look at what Argon2 does, why it was necessary, then how to build a simple Node.js application that uses it in less than 10 minutes.

What Argon2 does

Hash functions are one-way functions that transform data from human-readable (‘password1’) to random gibberish (‘g9+nAKtU0hrPa0Unv’). Being a one-way function means that given the output, you can’t recover the input. The output of hash functions also changes drastically if even one character is changed in the input.

Hash functions are useful for passwords for two reasons. First, they don’t reveal the passwords if a data breach occurs. When a user enters a password, the password text is not saved in the database. Instead, the result of passing the password through the hash function is saved. If the database is breached, only the gibberish is lost and not the original values that generated it.

Major data breaches, and even minor ones, can lead to passwords being spread across the Internet. In December 2017, researchers found a massive store of plaintext passwords being sold and distributed online. Troy Hunt’s Have I Been Pwned website keeps track of data breaches that leak account information. Passwords which are hashed securely won’t be exposed even in the worst-case scenario of a data breach.

Second, the system doesn’t have to have access to the actual password in order to log a user in. When the user returns to log in, the password they enter is hashed and compared to the hash stored for the same user in the database. If the two values match, then the password is correct.

Argon2 is referred to as an “adaptive” one-way function. This means developers can control the “work factor” of the function. The function can be tuned so that it will take the most amount of time to complete without negatively affecting the user experience. Increasing this time will make it harder for attackers to figure out the passwords if the database gets breached and the password hashes are released.

Why Argon2 is needed

Hash functions have been around for quite a while. So why do we need to keep creating new ones?

To sum it up: it’s a game of cat and mouse. Security experts design a way to protect data with hash functions. Then computers get faster, attackers find new techniques to attack those functions, and then new ones have to be created to catch up. Security researchers are also constantly testing these functions and problems are found with existing hash functions. MD5 has been broken since the mid-2000’s. SHA-1 was proven to have problems more recently.

The Password Hashing Competition was created to provide security experts a chance to find a new, better algorithm for hashing passwords. Argon2 came out as the winner. It is now the recommended choice for new applications. Don’t worry if you’re not using Argon2 right now. If you use a Password-Based Key Derivation Function (PBKDF2), scrypt, or bcrypt, you’re still in pretty good shape. Consider using Argon2 for all new applications and migrating other apps over time.

Zero to hashing in under ten minutes

You don’t have to explore and learn on your own to know how to user Argon2 in your Node application. We’ll walk you through creating an app from scratch that uses Argon2 to hash a value passed in through a REST API. At the end of this post, you’ll know enough to begin implementing it in your applications.

As an added bonus, check out the video at the bottom of the post to watch us create it. Let’s get started.

Create app and install components

First up, we need to create the project. So we create a directory and use “npm init” to create a Node project and project.json file.

Create a project

Next up, we create the index.js file in the application directory. Now, it’s time to install the components we need.

Create the index

We’ll need ExpressJSbody-parser, Node’s built-in crypto library, and the argon2-ffi package.

Install argon2-ffi

 

There are some hangups you need to watch out for when using Argon2 with Node. The Argon2 implementation is written with C. Therefore, you need to build the Argon2 project when you install argon2-ffi using node-gyp. Keep in mind that node-gyp is not compatible with Python 3. You’ll need Python 2.x installed in order for the build to complete. You’ll also need a C/C++ compiler installed on your machine. I used Linux for this example to make that requirement much easier.

Once all of the required packages are installed using “npm install –save <package>”, we can start creating the REST service.

Initial code and Argon2 error message

We now create a simple server with express to give us a good baseline for the application.

Initial server

 

1
2
3
4
5
6
7
var express = require('express'),
argon2i = require('argon2-ffi').argon2i,
crypto = require('crypto'),
bodyParser = require('body-parser);
var app = express();
 
app.listen(3000);

However, when we run this code for the first time we run into an error.

argon2 error

Apparently, Node is looking for the compiled Argon2 binary in the wrong spot. After looking around, I found that the Node runtime is looking in the Releases folder of the argon2-ffi package in node_modules. The binary is actually in Release/lib.target. So, we simply copy the argon2.so file from the lib.target directory into the Release directory.

Move argon2

Once this is done, the server starts up successfully. Now, it’s time to use Argon2 to hash passwords.

Hashing with Argon2

You may have noticed the require statement accessing ‘argon2i’ instead of simply requiring ‘argon2-ffi’. This is because Argon2 has two modes, Argon2i and Argon2d. The technical details of what makes them different is out of scope for this introductory article. Developers should understand that Argon2i is preferred for password hashing as it has more defenses against password attacks. Argon2d is more suitable for cryptocurrencies. For those who want more detail, check out the IETF draft for Argon2.

Now, onto the code.

argon2 final code

Express is used to create a small REST API with a single POST operation to the ‘/signup’ URL. The URL accepts JSON passed in the body of the request. If there is no body, a ‘400 Bad Request’ error is returned to the user.

In order to hash the password, we use the crypto library to generate a 32-byte salt value. Once the value is created, we use Argon2i to hash the password passed in the request body. The argon2-ffi package uses promises since it works asynchronously by default. We call the hash function and pass in the password and the salt. It’s that simple. For demonstration purposes, we’ll log the hashed password to the console.

Here’s the code in full:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var express = require('express'),
argon2i = require('argon2-ffi').argon2i,
crypto = require('crypto'), bodyParser = require('body-parser');
 
var app = express();
var jsonParser = bodyParser.json();
 
app.post('/signup', jsonParser, function(req, res) {
  if(!req.body) return res.sendStatus(400);
 
  crypto.randomBytes(32, function(err, salt) {
    if(err) throw err;
 
    argon2i.hash(req.body.password, salt).then(hash => {
      console.log(hash); res.sendStatus(201);
    });
  });
});
 
app.listen(3000, function(){
  console.log("Listening on port 3000...");
});

Let’s send a request with Postman and see if it works.

Postman request

We have a request to ‘/signup’ and a simple username and password JSON body. We send the request off and see that we have a successful hash.

Successful hash

In a real application, we’d store the hash value in the database and use it to verify the user’s password the next time they log in. This can be done with the following snippet of code:

1
2
3
4
5
var argon2i = require('argon2-ffi').argon2i;
var encodedHash = "$argon2i$v=19$m=4096,t=3,p=1$c2FsdHlzYWx0$oG0js25z7kM30xSg9+nAKtU0hrPa0UnvRnqQRZXHCV8";
var password = new Buffer('password1');
 
argon2i.verify(encodedHash, password)  .then(correct => console.log(correct ? 'Correct password!' : 'Incorrect password'));

And there you have it. A simple demonstration of Argon2 in Node.

Take your hashing to the next level

This post is enough to get you started. Where you take it next is up to you. You now have the information you need to add Argon2 to existing applications or start using it for all new applications moving forward. Take your hashing to the next level, and protect your passwords.

Related Posts

By Justin Boyer

Justin Boyer is a certified content marketer who helps tech and security companies create engaging content to attract more leads and increase revenue.