Hashing and salting passwords is an industry standard for protecting passwords for any respectable service. One option is using SHA-512 that computes quickly. The downside is attackers can take advantage of this with computational power and crack your passwords 😬.
Using Bcrypt is a better option
Algorithms like SHA are fast and efficient, allowing attackers to quickly brute force a password match. Not a very good choice for security, luckily there is another hashing algorithm called Bcrypt which is designed for hashing passwords slowly.
This frustrates attackers because passwords can't be brute forced and an increase in computational power will do little to help. Learn more on my article on hashing passwords with Bcrypt.
Hashing Steps
Convert password string to a byte slice
Generate random salt of 16 bytes (SHA2-crypt methods in Linus, BSD Unixes, and Solaris use 16 bytes)
Append salt to password slice
Hash the resulting concatenation
Implementation
package main
import (
"crypto/rand"
"crypto/sha512"
"encoding/hex"
"fmt"
)
// Define salt size
const saltSize = 16
// Generate 16 bytes randomly and securely using the
// Cryptographically secure pseudorandom number generator (CSPRNG)
// in the crypto.rand package
func generateRandomSalt(saltSize int) []byte {
var salt = make([]byte, saltSize)
_, err := rand.Read(salt[:])
if err != nil {
panic(err)
}
return salt
}
// Combine password and salt then hash them using the SHA-512
// hashing algorithm and then return the hashed password
// as a hex string
func hashPassword(password string, salt []byte) string {
// Convert password string to byte slice
var passwordBytes = []byte(password)
// Create sha-512 hasher
var sha512Hasher = sha512.New()
// Append salt to password
passwordBytes = append(passwordBytes, salt...)
// Write password bytes to the hasher
sha512Hasher.Write(passwordBytes)
// Get the SHA-512 hashed password
var hashedPasswordBytes = sha512Hasher.Sum(nil)
// Convert the hashed password to a hex string
var hashedPasswordHex = hex.EncodeToString(hashedPasswordBytes)
return hashedPasswordHex
}
// Check if two passwords match
func doPasswordsMatch(hashedPassword, currPassword string,
salt []byte) bool {
var currPasswordHash = hashPassword(currPassword, salt)
return hashedPassword == currPasswordHash
}
func main() {
// Generate random 16 byte salt
var salt = generateRandomSalt(saltSize)
// Hash password using the salt
var hashedPassword = hashPassword("hello", salt)
fmt.Println("Password Hash:", hashedPassword)
fmt.Println("Salt:", salt)
// Check if passed password matches the original password by hashing it
// with the original password's salt and check if the hashes match
fmt.Println("Password Match:",
doPasswordsMatch(hashedPassword, "hello", salt))
}
Password Hash: c7b714330211d3eddd0b047cde89b6ce618f321532eeb6ebbd0974c0d92097a66a2264a9b42012eb3387fe91f217e2109f2eefa26ee24a9c33e5417365bf07ec
Salt: [192 42 57 120 177 235 67 200 75 110 215 162 5 44 205 20]
Password Match: true
About the Author
Follow me on Twitter at @GregoryAGaines and consider signing up for my newsletter.
Top comments (0)