how to salt and hash a password and verify in go

Here's an example of a function that salts and hashes a password in Go:

main.go
import (
    "crypto/rand"
    "crypto/sha256"
    "encoding/base64"
)

const saltLength = 16   // length of salt string in bytes
const iterations = 1000 // number of iterations for PBKDF2 function

func hashPassword(password string) (string, error) {
    // generate a random salt
    salt := make([]byte, saltLength)
    _, err := rand.Read(salt)
    if err != nil {
        return "", err
    }

    // hash the password with salt using PBKDF2
    dk := pbkdf2.Key([]byte(password), salt, iterations, sha256.Size, sha256.New)

    // encode the salt and hash as base64
    saltEnc := base64.StdEncoding.EncodeToString(salt)
    hashEnc := base64.StdEncoding.EncodeToString(dk)

    // combine salt and hash into single string
    return saltEnc + "$" + hashEnc, nil
}
771 chars
28 lines

To verify a password, you can use a similar function that checks if the provided password matches the stored hash:

main.go
func verifyPassword(password, storedHash string) (bool, error) {
    // separate stored hash into salt and hash components
    parts := strings.Split(storedHash, "$")
    if len(parts) != 2 {
        return false, errors.New("invalid stored hash format")
    }

    // decode salt and hash from base64
    salt, err := base64.StdEncoding.DecodeString(parts[0])
    if err != nil {
        return false, err
    }
    hash, err := base64.StdEncoding.DecodeString(parts[1])
    if err != nil {
        return false, err
    }

    // hash password with same salt and verify against stored hash
    dk := pbkdf2.Key([]byte(password), salt, iterations, sha256.Size, sha256.New)
    return bytes.Equal(hash, dk), nil
}
714 chars
22 lines

gistlibby LogSnag