Password Hash & Salt Using Golang

The following is an example of how to hash & salt your passwords using the bcrypt package in Go.

For this example I’m going to make a console application for the purposes of demonstrating how to take a password entered by a user and generate a salted hash with it. Once we’ve done this, I’ll go through comparing a password with its hashed version to verify whether or not the password is correct.

Step One — Get The Users Password

We’ll start by creating the following function which can be used to read user input from the console.

func getPwd() []byte {
    // Prompt the user to enter a password
fmt.Println("Enter a password")
    // Variable to store the users input
var pwd string
    // Read the users input
_, err := fmt.Scan(&pwd)
if err != nil {
log.Println(err)
}
    // Return the users input as a byte slice which will save us
// from having to do this conversion later on
return []byte(pwd)
}

Step Two — Hash & Salt The User Password

Now that we have the users password we can hash & salt it using the GenerateFromPassword(password []byte, cost int)([]byte, error) function in Go’s bcrypt package.

GenerateFromPassword returns the bcrypt hash of the password at the given cost. If the cost given is less than MinCost, the cost will be set to DefaultCost, instead.

One advantage of using GenerateFromPassword is that it generates a salt for us which saves us from having to write our own function to generate a salt.

The below function uses GenerateFromPassword to generate a salted hash which is returned as a byte slice. We then return the byte slice as a string so that we can store the salted hash in our database as the users password.

func hashAndSalt(pwd []byte) string {

// Use GenerateFromPassword to hash & salt pwd.
// MinCost is just an integer constant provided by the bcrypt
// package along with DefaultCost & MaxCost.
// The cost can be any value you want provided it isn't lower
// than the MinCost (4)
hash, err := bcrypt.GenerateFromPassword(pwd, bcrypt.MinCost)
if err != nil {
log.Println(err)
}
    // GenerateFromPassword returns a byte slice so we need to
// convert the bytes to a string and return it
return string(hash)
}

Step Three — What We’ve Done So Far

So far we’ve created a function that accepts user input from the console and returns it as a byte slice. We then created a function that will take this user input and return a salted hash.

So, putting it altogether it should look something like this.

package main
import (
"fmt"
"log"
"golang.org/x/crypto/bcrypt"
)
func main() {
   for {

// Enter a password and generate a salted hash
pwd := getPwd()
hash := hashAndSalt(pwd)
        fmt.Println("Salted Hash", pwd)
     }
}

If you run the above code you‘re output should be similar to this.

Note, I called my functions inside an infinite for loop so as my program continues to run until I force it to stop. For those unfamiliar with Go it’s just like doing this while (true) { }. You don’t have to do this but I found it easier as it meant I could try out different passwords and see the results without having to run the program each time.

Step Four — Verify Password

The last thing we need to do is verify a password matches its hash which is what we would need to do if we were building a login system. We can do this using the

CompareHashAndPassword(hashedPassword, password []byte) error

function provided by the bcrypt package.

CompareHashAndPassword compares a bcrypt hashed password with its possible plaintext equivalent. Returns nil on success, or an error on failure.

Using CompareHashAndPassword we can create a function that returns a boolean to let us know whether or not the passwords match.

func comparePasswords(hashedPwd string, plainPwd []byte) bool {
    // Since we'll be getting the hashed password from the DB it
// will be a string so we'll need to convert it to a byte slice
byteHash := []byte(hashedPwd)
    err := bcrypt.CompareHashAndPassword(byteHash, plainPwd)
if err != nil {
log.Println(err)
return false
}

return true
}

Step Five — Update Our Main Function

We can now update our main function so that we will be able to enter a password, get its salted hash and then enter the password again and find out if our second password matches the first password we entered.

func main() {
    for {

// Enter a password and generate a salted hash
pwd := getPwd()
hash := hashAndSalt(pwd)

// Enter the same password again and compare it with the
// first password entered
pwd2 := getPwd()
pwdMatch := comparePasswords(hash, pwd2)
        fmt.Println("Passwords Match?", pwd)
    }
}

If you run the above code and enter the same password twice you should get the following result.

However, if you enter two passwords that don’t match then you should get the following result.

Final Code Review

Altogether your code should look like this.

package main
import (
"fmt"
"log"
    "golang.org/x/crypto/bcrypt"
)
func main() {
    for {

// Enter a password and generate a salted hash
pwd := getPwd()
hash := hashAndSalt(pwd)

// Enter the same password again and compare it with the
// first password entered
pwd2 := getPwd()
pwdMatch := comparePasswords(hash, pwd2)
        fmt.Println("Passwords Match?", pwd)
    }
}
func getPwd() []byte {
    // Prompt the user to enter a password
fmt.Println("Enter a password")
    // We will use this to store the users input
var pwd string
    // Read the users input
_, err := fmt.Scan(&pwd)
if err != nil {
log.Println(err)
}
    // Return the users input as a byte slice which will save us
// from having to do this conversion later on
return []byte(pwd)
}

func hashAndSalt(pwd []byte) string {

// Use GenerateFromPassword to hash & salt pwd
// MinCost is just an integer constant provided by the bcrypt
// package along with DefaultCost & MaxCost.
// The cost can be any value you want provided it isn't lower
// than the MinCost (4)
hash, err := bcrypt.GenerateFromPassword(pwd, bcrypt.MinCost)
if err != nil {
log.Println(err)
}
    // GenerateFromPassword returns a byte slice so we need to
// convert the bytes to a string and return it
return string(hash)
}

func comparePasswords(hashedPwd string, plainPwd []byte) bool {
    // Since we'll be getting the hashed password from the DB it
// will be a string so we'll need to convert it to a byte slice
byteHash := []byte(hashedPwd)
    err := bcrypt.CompareHashAndPassword(byteHash, plainPwd)
if err != nil {
log.Println(err)
return false
}

return true
}

If you made it this far thanks for taking the time to read this tutorial and I welcome any improvements or alternative methods for storing passwords.