receipt_indexer/backend/internal/lcrypto/lcrypto.go
Ethan Wellenreiter 829349c2aa A package to provide hashing and different algorithms.
Designed to be extensible to other algorithms which use salting.

Signed-off-by: Ethan Wellenreiter <ewellenreiter@gmail.com>
2025-04-30 21:01:19 -04:00

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
}