Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

equivalent salt and hash in golang

Tags:

go

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?

like image 522
Calvin Cheng Avatar asked Apr 13 '14 05:04

Calvin Cheng


People also ask

What is salt in SHA256?

What is a Salt? A salt is a random character string that is added to the beginning or the end of a password. This salt is unique to each user, and is stored in the database along with the username and salted-hashed password. An example username-password database using the SHA256 hashing function with a salt.

Is bcrypt better than SHA256?

Bcrypt was not designed for encrypting large amounts of data. It is best implemented for passwords, however SHA-256 is better for large amounts of data because it is less costly and faster.

What is salt in hash value?

According to OWASP Guidelines, a salt is a value generated by a cryptographically secure function that is added to the input of hash functions to create unique hashes for every input, regardless of the input not being unique.

What is salt in SHA512?

The Salted SHA512 Password Storage Scheme provides a mechanism for encoding user passwords using a salted form of the 512-bit SHA-2 message digest algorithm.


4 Answers

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:

  1. The salt is automatically (and randomly) generated upon hashing a password, so that you don't have to worry about salt generation.
  2. When storing hashed passwords in a database, you no longer have to worry about storing the salt for each password hash as well.
  3. The syntax is simplified for hashing and checking passwords.
  4. The hash produced by bcrypt includes the bcrypt version, cost, salt and cipher, not only the cipher.

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
}
like image 111
Iron John Bonney Avatar answered Oct 08 '22 23:10

Iron John Bonney


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\n", hash)
}
like image 28
Stephen Weinberg Avatar answered Oct 09 '22 00:10

Stephen Weinberg


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)
}
like image 6
Salvador Dali Avatar answered Oct 09 '22 00:10

Salvador Dali


Here's a complete hashing utilities funcs I wrote based on RFC 2898 / PKCS #5 v2.0.

Hash can be used to hash passwords, straight forward something like Hash("hello")

while Verify can be used to raw password against a hash, basically what it does is to hashes the raw string and compares it with the actual hash.

package common

import (
    "crypto/rand"
    "crypto/sha1"
    "encoding/base64"
    "errors"
    "fmt"
    "golang.org/x/crypto/pbkdf2"
    "io"
    "strconv"
    "strings"
)

const (
    SALT_BYTE_SIZE    = 24
    HASH_BYTE_SIZE    = 24
    PBKDF2_ITERATIONS = 1000
)

func Hash(password string) (string, error) {
    salt := make([]byte, SALT_BYTE_SIZE)
    if _, err := io.ReadFull(rand.Reader, salt); err != nil {
        fmt.Print("Err generating random salt")
        return "", errors.New("Err generating random salt")
    }

    //todo: enhance: randomize itrs as well
    hbts := pbkdf2.Key([]byte(password), salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE, sha1.New)
    //hbtstr := fmt.Sprintf("%x", hbts)

    return fmt.Sprintf("%v:%v:%v",
        PBKDF2_ITERATIONS,
        base64.StdEncoding.EncodeToString(salt),
        base64.StdEncoding.EncodeToString(hbts)), nil
}

func Verify(raw, hash string) (bool, error) {
    hparts := strings.Split(hash, ":")

    itr, err := strconv.Atoi(hparts[0])
    if err != nil {
        fmt.Printf("wrong hash %v", hash)
        return false, errors.New("wrong hash, iteration is invalid")
    }
    salt, err := base64.StdEncoding.DecodeString(hparts[1])
    if err != nil {
        fmt.Print("wrong hash, salt error:", err)
        return false, errors.New("wrong hash, salt error:" + err.Error())
    }

    hsh, err := base64.StdEncoding.DecodeString(hparts[2])
    if err != nil {
        fmt.Print("wrong hash, hash error:", err)
        return false, errors.New("wrong hash, hash error:" + err.Error())
    }

    rhash := pbkdf2.Key([]byte(raw), salt, itr, len(hsh), sha1.New)
    return equal(rhash, hsh), nil
}

//bytes comparisons
func equal(h1, h2 []byte) bool {
    diff := uint32(len(h1)) ^ uint32(len(h2))
    for i := 0; i < len(h1) && i < len(h2); i++ {
        diff |= uint32(h1[i] ^ h2[i])
    }

    return diff == 0
}

Here's unit test that would help you figuring out how to call such funcs

package common

import (

    "github.com/stretchr/testify/assert"
    "testing"
)

func TestHash(t *testing.T) {
    hash, err := Hash("hello")
    assert.Nil(t, err)
    assert.NotEmpty(t, hash)

}

func TestVerify(t *testing.T) {
    hash, err := Hash("hello")
    assert.Nil(t, err)
    assert.NotEmpty(t, hash)

    ok, err := Verify("hello", hash)
    assert.Nil(t, err)
    assert.True(t, ok)
}
like image 2
Muhammad Soliman Avatar answered Oct 08 '22 22:10

Muhammad Soliman