How to Hash and Salt Passwords in Golang Using SHA-512 and Why You Shouldn’t 😤
Tags: go, webdev, programming, tutorial
Published: 2022-04-08 17:25:54

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 <a href="https://dev.to/gregorygaines/how-to-properly-hash-and-salt-passwords-in-golang-using-bcrypt-io4">hashing passwords with Bcrypt</a>.

## Hashing Steps

1. Convert password string to a byte slice

2. Generate random salt of 16 bytes (SHA2-crypt methods in Linus, BSD Unixes, and Solaris use 16 bytes)

3. Append salt to password slice

4. Hash the resulting concatenation

## Implementation

```go
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))
}
```

```markdown
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 <a href="https://twitter.com/GregoryAGaines">@GregoryAGaines</a> and consider signing up for my <a href="https://gregorygaines.substack.com/subscribe">newsletter</a>.