Here's an example of salting and hashing a given password in python.
import scrypt
import os
# Length of salt
PW_SALT_BYTES = 32
# Length of scrypt hash of passwords
PW_HASH_BYTES = 64
# test password
password = "hello"
salt = os.urandom(PW_SALT_BYTES).encode('hex')
# hash(password, salt, N=1 << 14, r=8, p=1, buflen=64)
hashed_password = scrypt.hash(str(password), salt.decode('hex'), buflen=PW_HASH_BYTES).encode('hex')
print(hashed_password)
Which would give us a hashed and salted string in return:-
4d1da45b401961fccb10e094ecd70ec79510f05483ca293d300bbd0024e35866ca39fe09fbc15f83a359431021a1ed9644f7d2b871b357e37a186300877edb18
How would I implement this in golang?
Go doesn't have scrypt in the standard library but there is an "official" implementation in the go.crypto repo.
import (
"crypto/rand"
"fmt"
"io"
"log"
"code.google.com/p/go.crypto/scrypt"
)
const (
PW_SALT_BYTES = 32
PW_HASH_BYTES = 64
password = "hello"
)
func main() {
salt := make([]byte, PW_SALT_BYTES)
_, err := io.ReadFull(rand.Reader, salt)
if err != nil {
log.Fatal(err)
}
hash, err := scrypt.Key([]byte(password), salt, 1<<14, 8, 1, PW_HASH_BYTES)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%x
", hash)
}
It looks like now Go has scrypt in official library. Its subrepository x/crypto among many other crypto functions has an scrypt.
Here is an example of how you can use it:
package main
import (
"golang.org/x/crypto/scrypt"
"fmt"
)
func main(){
salt := []byte("asdfasdf")
dk, err := scrypt.Key([]byte("some password"), salt, 16384, 8, 1, 32)
fmt.Println(dk)
fmt.Println(err)
}
Rather than using scrypt
, a great library for securely hashing passwords with random salts in Golang is golang.org/x/crypto/bcrypt, as mentioned in the following answer:
Bcrypt password hashing in Golang (compatible with Node.js)?
A couple benefits of using bcrypt
instead of scrypt
:
Here's an example of using bcrypt taken from the above answer:
package main
import (
"golang.org/x/crypto/bcrypt"
"fmt"
)
func main() {
password := []byte("MyDarkSecret")
// Hashing the password with the default cost of 10
hashedPassword, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost)
if err != nil {
panic(err)
}
fmt.Println(string(hashedPassword))
// Comparing the password with the hash
err = bcrypt.CompareHashAndPassword(hashedPassword, password)
fmt.Println(err) // nil means it is a match
}