todo/internal/auth/hashing.go
Michael Thomson e55d419d44
All checks were successful
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/lint Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
auth services, middleware, and other stuff
2025-05-22 13:55:43 -04:00

71 lines
1.2 KiB
Go

package auth
import (
"bytes"
"crypto/rand"
"errors"
"golang.org/x/crypto/argon2"
)
type HashSalt struct {
Hash, Salt []byte
}
type Argon2IdHash struct {
time uint32
memory uint32
threads uint8
keyLen uint32
saltLen uint32
}
var (
ErrNoMatch error = errors.New("hash doesn't match")
)
func NewArgon2IdHash(time, saltLen uint32, memory uint32, threads uint8, keyLen uint32) *Argon2IdHash {
return &Argon2IdHash{
time: time,
saltLen: saltLen,
memory: memory,
threads: threads,
keyLen: keyLen,
}
}
func (a *Argon2IdHash) GenerateHash(password, salt []byte) (*HashSalt, error) {
var err error
if len(salt) == 0 {
salt, err = randomSecret(a.saltLen)
}
if err != nil {
return nil, err
}
hash := argon2.IDKey(password, salt, a.time, a.memory, a.threads, a.keyLen)
return &HashSalt{Hash: hash, Salt: salt}, nil
}
func (a *Argon2IdHash) Compare(hash, salt, password []byte) error {
hashSalt, err := a.GenerateHash(password, salt)
if err != nil {
return err
}
if !bytes.Equal(hash, hashSalt.Hash) {
return ErrNoMatch
}
return nil
}
func randomSecret(length uint32) ([]byte, error) {
secret := make([]byte, length)
_, err := rand.Read(secret)
if err != nil {
return nil, err
}
return secret, nil
}