End to end user credentials protection

End to end user credentials protection

Advance user authentication

Introduction

# First check if you have been pwned. # Second understand what a hash function is.

Argon2

Nowadays password hashing is the most common way to protect user access to internet services, but password hashing can’t fulfill the needs of modern applications because of Rainbow tables, Hash online search services, GPU password crackers, Password crackers. With Blockchain raising GPU hash cracking rises too, so that Password Hashing Competition (PHC) emerges to accomplish this problem. The idea is to create a password hash functions that can be recognized as a recommended standard and avoid previous password breaches involving weak or no hashing passwords.

What is the difference between hash function and password hash function? Hash function is a unique string that identifies a piece of data aka fingerprint, and a password hash function is a hash function resistant against GPU cracking attacks, side-channel attacks, time–memory trade-off.

Argon2 is the PHC winner and its code is open source. On Argon2 website , we can read: “Argon2 has one primary variant: Argon2id, and two supplementary variants: Argon2d and Argon2i. Argon2d uses data-depending memory access, which makes it suitable for cryptocurrencies and proof-of-work applications with no threats from side-channel timing attacks. Argon2i uses data-independent memory access, which is preferred for password hashing and password-based key derivation. Argon2id works as Argon2i for the first half of the first iteration over the memory, and as Argon2d for the rest, thus providing both side-channel attack protection and brute-force cost savings due to time-memory tradeoffs. Argon2i makes more passes over the memory to protect from tradeoff attacks.” Specs

HMAC

It is a hash-based MAC (message authentication code) algorithm, commonly used for authenticated encryption, it combines a hash function with a secret key and a message. In this case it will help us to store username into DB.

So, the password will be store in the DB as Argon2(password) and username will be store as HMAC(username+key) with SHA3_512. If an attacker stole all your DB, he won’t be able to read it, it is useless data. Password and username will be protected.

How to use Argon2 and HMAC with Node.js?

There are 2 ways to implement Argon2 and HMAC:

Here we are exploring the second way to implement Argon2, we are using a cryptoserver called Coherence.

Why to use Coherence?

There is a couple of good reasons to use Coherence:

  • Offload, you have an specialized software dedicated entirely for cryptographic operations. Cryptographic operations like encrypting and decrypting is a very CPU-intensive task for webapps, so offload alleviates CPU-intensive encryption and decryption tasks from your webapp, boosting application performance.

  • Interoperability, it doesn’t depend on a language programming, it depends on standards tcp and json, so you can integrate with homogeneous and heterogeneous systems.

  • Flexibility, it gives you a complete cryptographic toolkitto implement stream ciphers, block ciphers, RSA, Elliptic curves, Post quantum cryptography. So it gives you all that you need to create your own cryptographic protocol.

  • Open source, you can inspect, modify, and enhance.

  • Free of charges, you don’t have to pay.

Pre-requiste

Before moving to argon2, we must have the following programs installed on your machines.

  • Node.js

  • Sqlite3

Setup Coherence

For Centos 7 dependencies:

yum install glibc-static libstdc++-static autoconf automake gcc gcc-c++ make libtool git wget

For Debian 9 dependencies:

apt-get install autoconf automake gcc g++ make libtool git wget

Compile:

wget https://raw.githubusercontent.com/liesware/coherence/master/install.sh
sh install.sh
cd coherence_git/coherence/coherence02/bin/
./coherence 127.0.0.1 6613

Test Coherence, in other terminal run:

cd your_dir/coherence/coherence02/
python argon2.py
node mac.js

Project Structure

  • auth.db -> sqlite database to store username and password

  • index.js -> main program

  • package.js -> dependencies

  • public/form.html -> html to add user

  • public/login.html -> html to login user

Note: This PoC use bulma for CSS, and CSS is loaded by CDN.

index.js

This program makes 2 things:

  • Secure and store user credentials.

  • Verify user credentials.

Action

  • Clone github repo
  • Generate a X.509 certificate for https
  • Install dependencies
  • Start it
git clone https://github.com/liesware/coherence-poc.git 
cd coherence-poc/auth/
openssl ecparam -genkey -name prime256v1 -out key.pem
openssl req -new -sha256 -key key.pem -out csr.csr
openssl req -x509 -sha256 -days 365 -key key.pem -in csr.csr -out certificate.pem
npm install 
npm start
Open in your browser http://127.0.0.1:6845/

Remember Coherence is up and running.

Code


/_
This PoC is about Secure login, password hashing and user storage
using Argon2 with Coherenc, Node.js and Sqlite3 by Liesware.com

https://coherence.liesware.com/
https://github.com/liesware/coherence/

An anonymous system empowers individuals to reveal their
identity when desired and only when desired;
this is the essence of privacy ” by Eric Hughes.

_/

//https://expressjs.com/en/guide/routing.html
var express =   require("express"); //module to create http server
var https = require('https'); //module for https
var fs = require('fs'); //module to read files
var bodyParser = require('body-parser'); //module to parse http request
//http://www.sqlitetutorial.net/sqlite-nodejs/
var sqlite3 = require('sqlite3').verbose(); //module to connect sqlite3
//https://nodejs.org/api/net.html
var net = require('net'); //module to connect to Coherence

//Coherence json
// these json are based on https://github.com/liesware/coherence/wiki/User-guide-by-example_
//json to generate Argon2 (argon2i is recommended for passwords)
//you can modify the parameters according to https://github.com/P-H-C/phc-winner-argon2
_
argon2_gen='{"algorithm": "ARGON2", "family": "argon2i", "plaintext": "", "hashlen": 32, "t_cost": 10, "version": 1, "parallelism": 4, "m_cost": 16, "salt": "ABABABABABABABABABABABABABABABAB", "operation": "hash"}'
//json to verify Argon2
argon2_very='{"algorithm": "ARGON2", "family": "argon2i", "plaintext": "", "pwd": "", "version": 1, "operation": "verify"}'
//json to generate HMAC with sha3_512
sha3_gen='{"version":1,"algorithm":"HMAC","type":"string","plaintext":"","key":"","family":"sha3_512"}'
//key for HMAC json_sha3 in hex, maybe you want to change it
mac_key_hex='0123456789ABCDEF'

//preparing express to start the server and receive the data
var app =   express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

//preparing queries for sqlite
let db = new sqlite3.Database('auth.db');
//this table helps us to create users
db.run('CREATE TABLE IF NOT EXISTS auth(name text PRIMARY KEY , password text)');
//this query helps us to login users
let sql_q='SELECT password FROM auth where name=? limit 1;'

//Static files
app.use(express.static('public'));

//Default page
app.get('/',function(req,res){
  res.sendFile(__dirname + "/public/form.html");
});

//Post request to add user
app.post('/add_user',function(req,res){
  //getting user data
  password = req.body.password_poc
  email = req.body.email_poc
  console.log('Body: '+JSON.stringify(req.body))

  //parsing Coherence's json
  var json_argon2 = JSON.parse(argon2_gen);
  var json_sha3 = JSON.parse(sha3_gen);
  var hash, mac;

  //putting varibles inside json
  json_argon2['plaintext'] = password
  json_sha3['plaintext'] = email
  json_sha3['key']=mac_key_hex

  //this socket requests for Argon2 password generation from password input
  var client = new net.Socket();
  client.connect(6613, '127.0.0.1', function() {
    client.write(JSON.stringify(json_argon2));
      client.on('data', function(data) {
        json_argon2_r = JSON.parse(data);
        hash=json_argon2_r['hash']

        //this socket requests for HMAC generation from email input
        var client_1 = new net.Socket();
        client_1.connect(6613, '127.0.0.1', function() {
          client_1.write(JSON.stringify(json_sha3));
            client_1.on('data', function(data) {
              json_sha3_r = JSON.parse(data);
              mac=json_sha3_r['mac']
              console.log('Argon2: '+hash);
              console.log('Username: '+mac+'\n');

              //inserting hmac(email) and argon2(password) into auth table
              var sql_insert = db.prepare("INSERT INTO auth VALUES (?,?)");
              sql_insert.run(mac, hash, function(err) {
                if (err) {
                  res.end("User not added")
                }
                res.end("User added")
              });
              sql_insert.finalize();
              client_1.destroy();
            });});
        client.destroy();
      });});
});

//Post reuest to login user
app.post('/login_user',function(req,res){
  password = req.body.password_poc
  email = req.body.email_poc
  console.log('Body: '+JSON.stringify(req.body))

  //parsing Coherence's json
  var json_argon2 = JSON.parse(argon2_very);
  var json_sha3 = JSON.parse(sha3_gen);
  var hash, mac;

  //putting varibles inside json
  json_argon2['plaintext'] = password
  json_sha3['plaintext'] = email
  json_sha3['key']=mac_key_hex

  //this socket requests for HMAC generation from email input
  var client = new net.Socket();
  client.connect(6613, '127.0.0.1', function() {
    client.write(JSON.stringify(json_sha3));
    client.on('data', function(data) {
      json_sha3_r = JSON.parse(data);
      mac = json_sha3_r['mac']
      //getting password from table auth based on hmac(email)
      db.get(sql_q, [mac], (err, row) => {
        if (err) {
          return res.end(err.message);
        }
        if (row) {
          json_argon2['pwd'] = row.password
          //Verify Argon2 password, it needs password from table and password from post request
          var client_1 = new net.Socket();
          client_1.connect(6613, '127.0.0.1', function() {
            client_1.write(JSON.stringify(json_argon2));
            client_1.on('data', function(data) {
              json_argon2_r = JSON.parse(data);
              hash = json_argon2_r['verify']
              hash == 'ARGON2_OK' ? res.end("Good Password") : res.end("Bad password")
              client_1.destroy();
            });});
        }
        else {res.end("Bad username")}
      });
      client.destroy();
    });});
});

https.createServer({
  key: fs.readFileSync('key.pem'),
  cert: fs.readFileSync('certificate.pem')
}, app)
.listen(6845,'0.0.0.0',function(){
    console.log("Working on port 6845\n");
});

Final words

With this PoC we see how to implement end to end user credentials protection (both username and password). If you suffer a data breach the data will be useless for the attacker, and your user never will be impacted.

Some points:

  • To implement end to end user credentials protection, you need to standardize and sanitize all your data inputs for your own needsYsjsjsjajshd .

  • Implement error handling for your own needs.

Like this article? Follow @liesware on Twitter