How to Properly Hash and Salt Passwords in Golang Using Bcrypt
The bcypt function is secure and brute force resistant allowing programmers to safely handle the passwords of their users.
Table of Contents
Prerequisites
- Download the golang bcrypt library using
go get golang.org/x/crypto/bcrypt
.
Hashing
1// Hash password using the bcrypt hashing algorithm 2func hashPassword(password string) (string, error) { 3 // Convert password string to byte slice 4 var passwordBytes = []byte(password) 5 6 // Hash password with bcrypt's min cost 7 hashedPasswordBytes, err := bcrypt. 8 GenerateFromPassword(passwordBytes, bcrypt.MinCost) 9 10 return string(hashedPasswordBytes), err 11} 12 13func main() { 14 // Hash password 15 var hashedPassword, err = hashPassword("password1") 16 17 if err != nil { 18 println(fmt.Println("Error hashing password")) 19 return 20 } 21 22 fmt.Println("Password Hash:", hashedPassword) 23}
No Need to Salt Passwords
Bcrypt uses a concept named cost
which represents the number of hash iterations that bcrypt undertakes. Hashing time is calculated as 2 ^ cost
and the higher the cost, the longer the hashing process takes.
This deters attackers because they can't quickly brute force a password match and increasing computational power will do little to help. Bcrypt uses a variable named bcrypt.MinCost
as a default cost and any cost lower defaults to bcrypt.DefaultCost
.
Passwords Matching
1package main 2 3import ( 4 "fmt" 5 "golang.org/x/crypto/bcrypt" 6) 7 8// Hash password 9func hashPassword(password string) (string, error) { 10 // Convert password string to byte slice 11 var passwordBytes = []byte(password) 12 13 // Hash password with Bcrypt's min cost 14 hashedPasswordBytes, err := bcrypt. 15 GenerateFromPassword(passwordBytes, bcrypt.MinCost) 16 17 return string(hashedPasswordBytes), err 18} 19 20// Check if two passwords match using Bcrypt's CompareHashAndPassword 21// which return nil on success and an error on failure. 22func doPasswordsMatch(hashedPassword, currPassword string) bool { 23 err := bcrypt.CompareHashAndPassword( 24 []byte(hashedPassword), []byte(currPassword)) 25 return err == nil 26} 27 28func main() { 29 // Hash password 30 var hashedPassword, err = hashPassword("password1") 31 32 if err != nil { 33 println(fmt.Println("Error hashing password")) 34 return 35 } 36 37 fmt.Println("Password Hash:", hashedPassword) 38 39 // Check if passed password matches the original password 40 fmt.Println("Password Match:", 41 doPasswordsMatch(hashedPassword, "password1")) 42}
1Password Hash: $2a$04$kcsOln10l5Gm0lSgQmlrhuS0T9u124J3HfrAr9tnHltr9u7.iUsJm 2Password Match: true
Consider signing up for my newsletter or supporting me if this was helpful. Thanks for reading!