Designed to be extensible to other algorithms which use salting. Signed-off-by: Ethan Wellenreiter <ewellenreiter@gmail.com>
104 lines
2.2 KiB
Go
104 lines
2.2 KiB
Go
package lcrypto
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/subtle"
|
|
)
|
|
|
|
type HashAlgo interface {
|
|
EncodeHashAndSalt(hash []byte, salt []byte) (string, error)
|
|
EncodeHash(hash []byte) (string, error)
|
|
DecodeHashAndSalt(encodedString string) (algo Argon2id, hash []byte, salt []byte, err error)
|
|
DecodeHash(encodedString string) (algo Argon2id, hash []byte, err error)
|
|
HashString(in string, salt []byte, keyLen uint) ([]byte, error)
|
|
}
|
|
|
|
type Hasher struct {
|
|
Algo HashAlgo
|
|
KeyLength uint
|
|
SaltLength uint
|
|
}
|
|
|
|
func (h *Hasher) CheckString(pass string, encoded string) (bool, error) {
|
|
algo, truehash, salt, err := h.Algo.DecodeHashAndSalt(encoded)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
newhash, err := algo.HashString(pass, salt, h.KeyLength)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
equal, err := CompareHash(truehash, newhash)
|
|
|
|
return equal, err
|
|
}
|
|
|
|
func (h *Hasher) CheckStringWithSalt(in string, salt []byte, encoded string) (bool, error) {
|
|
algo, truehash, err := h.Algo.DecodeHash(encoded)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
newhash, err := algo.HashString(in, salt, h.KeyLength)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
equal, err := CompareHash(truehash, newhash)
|
|
|
|
return equal, err
|
|
}
|
|
|
|
func (h *Hasher) HashString(in string) (string, error) {
|
|
|
|
salt, err := GenerateRandomBytes(h.SaltLength)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
hash, err := h.Algo.HashString(in, salt, h.KeyLength)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return h.Algo.EncodeHashAndSalt(hash, salt)
|
|
}
|
|
|
|
func (h *Hasher) HashStringWithSalt(in string, salt []byte) (string, error) {
|
|
hash, err := h.Algo.HashString(in, salt, h.KeyLength)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return h.Algo.EncodeHash(hash)
|
|
}
|
|
|
|
func (h *Hasher) Hash(in string) ([]byte, error) {
|
|
salt, err := GenerateRandomBytes(h.SaltLength)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return h.Algo.HashString(in, salt, h.KeyLength)
|
|
}
|
|
|
|
func CompareHash(h1 []byte, h2 []byte) (bool, error) {
|
|
if subtle.ConstantTimeCompare(h1, h2) == 1 {
|
|
return true, nil
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
func GenerateRandomBytes(saltLen uint) ([]byte, error) {
|
|
|
|
var bytes []byte = make([]byte, saltLen)
|
|
|
|
_, err := rand.Read(bytes)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return bytes, nil
|
|
}
|