143 lines
3.3 KiB
Go
143 lines
3.3 KiB
Go
|
package secret
|
|||
|
|
|||
|
import (
|
|||
|
"crypto/md5"
|
|||
|
"crypto/sha1"
|
|||
|
"crypto/sha256"
|
|||
|
"crypto/sha512"
|
|||
|
"fmt"
|
|||
|
"hash"
|
|||
|
|
|||
|
. "gitea.zaclys.com/bvaudour/gob/option"
|
|||
|
"gitea.zaclys.com/bvaudour/gob/random"
|
|||
|
)
|
|||
|
|
|||
|
func errAlgorithm(algorithm string) error {
|
|||
|
return fmt.Errorf("unknown algorithm: %s", algorithm)
|
|||
|
}
|
|||
|
|
|||
|
// Hasher est un utilitaire permettant de hasher une chaîne et de vérifier qu’une chaîne correspond bien à un hashage.
|
|||
|
type Hasher interface {
|
|||
|
Hash(data []byte) (hashed []byte)
|
|||
|
Compare(data []byte, hashed []byte) bool
|
|||
|
}
|
|||
|
|
|||
|
type hasher struct {
|
|||
|
h hash.Hash
|
|||
|
}
|
|||
|
|
|||
|
func (h hasher) Hash(data []byte) []byte {
|
|||
|
h.h.Write(data)
|
|||
|
return h.h.Sum(nil)
|
|||
|
}
|
|||
|
|
|||
|
func (h hasher) Compare(data []byte, hashed []byte) bool {
|
|||
|
return string(h.Hash(data)) == string(hashed)
|
|||
|
}
|
|||
|
|
|||
|
// HashResult est le résultat d’un hash.
|
|||
|
type HashResult[T ~[]byte | ~string] struct {
|
|||
|
Hash T
|
|||
|
Salt T
|
|||
|
}
|
|||
|
|
|||
|
func hashOf(data []byte, saltLen int, h Hasher) (result HashResult[[]byte]) {
|
|||
|
l := len(data)
|
|||
|
in := make([]byte, l+saltLen)
|
|||
|
|
|||
|
result.Salt = random.BytesKey(saltLen, random.All)
|
|||
|
copy(in[:l], data)
|
|||
|
copy(in[l:], result.Salt)
|
|||
|
result.Hash = h.Hash(in)
|
|||
|
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// HashOf génère le hash et un sel aléatoire à une chaîne donnée.
|
|||
|
func HashOf[T ~[]byte | ~string](data T, saltLen int, h Hasher) (result HashResult[T]) {
|
|||
|
rb := hashOf([]byte(data), saltLen, h)
|
|||
|
result.Hash, result.Salt = T(rb.Hash), T(rb.Salt)
|
|||
|
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
const (
|
|||
|
MD5 = "md5"
|
|||
|
SHA1 = "sha1"
|
|||
|
SHA256 = "sha256"
|
|||
|
SHA512 = "sha512"
|
|||
|
BCRYPT = "bcrypt"
|
|||
|
)
|
|||
|
|
|||
|
var (
|
|||
|
hashers = map[string]Hasher{
|
|||
|
MD5: hasher{md5.New()},
|
|||
|
SHA1: hasher{sha1.New()},
|
|||
|
SHA256: hasher{sha256.New()},
|
|||
|
SHA512: hasher{sha512.New()},
|
|||
|
BCRYPT: NewBcrypt(14),
|
|||
|
}
|
|||
|
)
|
|||
|
|
|||
|
// AvailableHashAlgorithms retourne la liste des noms des algorithmes de hachage supportés.
|
|||
|
func AvailableHashAlgorithms() (out []string) {
|
|||
|
for h := range hashers {
|
|||
|
out = append(out, h)
|
|||
|
}
|
|||
|
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// IsHashAlgorithmAvailable vérifie si le nom fournit en entrée fait partie des algorithmes de hachage supportés.
|
|||
|
func IsHashAlgorithmAvailable(name string) bool {
|
|||
|
_, exists := hashers[name]
|
|||
|
|
|||
|
return exists
|
|||
|
}
|
|||
|
|
|||
|
// AddHashAlgorithm ajoute un algorithme de hashage à disposition.
|
|||
|
func AddHashAlgorithm(name string, hasher Hasher) {
|
|||
|
hashers[name] = hasher
|
|||
|
}
|
|||
|
|
|||
|
// Hash chiffre la donnée d’entrée en utilisant l’algorithme demandé.
|
|||
|
// Si une longueur de sel est fournie, le hachage est créé à partir
|
|||
|
// d’un sel défini aléatoirement.
|
|||
|
// Les algorithmes supportés par défaut sont :
|
|||
|
// - md5
|
|||
|
// - sha1
|
|||
|
// - sha256
|
|||
|
// - sha512
|
|||
|
// - bcrypt
|
|||
|
func Hash[T ~[]byte | ~string](data T, algorithm string, saltLen ...int) (result Result[HashResult[T]]) {
|
|||
|
h, ok := hashers[algorithm]
|
|||
|
if !ok {
|
|||
|
return Err[HashResult[T]](errAlgorithm(algorithm))
|
|||
|
}
|
|||
|
|
|||
|
sl := 0
|
|||
|
if len(saltLen) > 0 && saltLen[0] > 0 {
|
|||
|
sl = saltLen[0]
|
|||
|
}
|
|||
|
r := HashOf(data, sl, h)
|
|||
|
|
|||
|
return Ok(r)
|
|||
|
}
|
|||
|
|
|||
|
// CheckHash vérifie le hash d’une donnée d’entrée avec un algorithme de hashage.
|
|||
|
// Si le hash a été généré avec du sel, la chaîne doit être la concaténation
|
|||
|
// de la chaîne d’origine et du sel.
|
|||
|
func CheckHash[T ~[]byte | ~string](data T, hash HashResult[T], algorithm string) bool {
|
|||
|
h, ok := hashers[algorithm]
|
|||
|
if !ok {
|
|||
|
return false
|
|||
|
}
|
|||
|
|
|||
|
ld, ls := len(data), len(hash.Salt)
|
|||
|
in := make([]byte, ld+ls)
|
|||
|
copy(in[:ld], []byte(data))
|
|||
|
copy(in[ld:], []byte(hash.Salt))
|
|||
|
|
|||
|
return h.Compare(in, []byte(hash.Hash))
|
|||
|
}
|