March 4, 2019

Golang: storing passwords securely

There has been an active movement to go password-less and build a system based on alternative security measures like biometric authentication. No matter what’s your opinion about the passwords, they are not gonna go away anytime soon, simply because there are no alternatives available currently which offer the same level of ease of use (I know it’s a bit opiniated argument). Chances are you will have to keep supporting password based authentication for a forseable future.

With the above point made, how would you go about storing the passwords? It turns out, there is more to it than simply storing the passwords like any other piece of data.

You should absolutely not store passwords in cleartext, in fact storing the passwords in the encrypted form is also very dangerous and NOT a good idea. The reason for the later is, if you ever lose the encryition key, you will end up exposing passwords of your users to the whoever has access to the key, it’s really no better than storing the passwords in the clear text, and more importantly it’s a really big onus which you should not/do not need to carry.

Hashing the passwords

Hashing the passwords before storing them in the database is the correct way to go about it. There are numerous algorithms for hashing and NOT all of them are suitable for passwords.

As of the time of writting this post OWASP lists following algorithms in the order of preference, while selecting one for password hasing.

  1. Argon2
  2. pbkdf2
  3. scrypt
  4. bcrypt

Cool we will be hashing the passwords using one of the above algorithms, so we should be good, but hold on, there is more to it. Some really smart people recommend that hashing alone is not enough, we should at the very least be adding a dash of salt to it.

Adding the salt

In order to avoid security attacks based on precalculated hashes (rainbow tables) it’s important that we give it enough degree of randomness before storing.

Password salts are the random numbers (pretty big ones), which are used along with the passwords to generate the hash.

Sample

If you are starting a new application, and if you have choice then, probably you should pick Argon2, for the sake of the sample code however I will be using the pbkdf2.

Let’s see how we can achieve this in golang, we will be using following package which implements the pbkdf2 “golang.org/x/crypto/pbkdf2”.

package main

import (
	"crypto/rand"
	"crypto/sha512"
	"encoding/hex"
	"fmt"

	"github.com/nishch/cryptography-golang/security"
	"golang.org/x/crypto/pbkdf2"
)

const (
	// no of iteration which tells pbkdf2, how many time it should repeat the calculation
	// it basically makes the whole computation time taking, hence puts resistance for the attacker
	ITER = 10000

	// the size of final out put hash
	KEYLEN = 512
)

// generates the random number which can be used as the salt
func generateSalt(size int) (res []byte) {
	res = make([]byte, size)
	_, err := rand.Read(res)
	if err != nil {
		panic("failed to generate salt, error: " + err.Error())
	}
	return res
}

// generates the hashed password and the salt used
func HashPassword(password string) (hashedPassword, salt string) {

	s := generateSalt(256)
	h := pbkdf2.Key([]byte(password), s, ITER, KEYLEN, sha512.New)

	salt = hex.EncodeToString(s)
	hashedPassword = hex.EncodeToString(h)
	return hashedPassword, salt
}

func main() {
	samplePassword := "AVeryStrongPassword*123"
	pass, salt := security.HashPassword(samplePassword)
	fmt.Println("hashed password:", pass)
	fmt.Println("salt:", salt)
}

That’s it, above sample is definitely not feature complete, but it’s a good start. One last thing, you have to store salt along with the hashed password, and implement the verification function which does essentially what HashPassword function does and additionally also compares the computed hash with the one stored in the db.

Thanks for reading. Copyright © notabot.in