Files
neural-hunt/internal/customer/security.go
jbergner bcfbef390f
Some checks failed
release-tag / release-image (push) Failing after 2m44s
RC-7
2026-08-11 16:58:07 +02:00

72 lines
1.7 KiB
Go

package customer
import (
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"crypto/subtle"
"encoding/base64"
"encoding/binary"
"errors"
"strings"
)
var rawURL = base64.RawURLEncoding
func RandomToken(n int) string {
if n < 16 {
n = 16
}
b := make([]byte, n)
_, _ = rand.Read(b)
return rawURL.EncodeToString(b)
}
func NewPasswordHash(password string) (salt string, hash string, err error) {
if len(strings.TrimSpace(password)) < 12 {
return "", "", errors.New("password must be at least 12 characters")
}
s := make([]byte, 16)
if _, err := rand.Read(s); err != nil {
return "", "", err
}
h := pbkdf2SHA256([]byte(password), s, 310000, 32)
return rawURL.EncodeToString(s), rawURL.EncodeToString(h), nil
}
func VerifyPassword(password, salt, hash string) bool {
s, err := rawURL.DecodeString(salt)
if err != nil {
return false
}
want, err := rawURL.DecodeString(hash)
if err != nil {
return false
}
got := pbkdf2SHA256([]byte(password), s, 310000, len(want))
return len(got) == len(want) && subtle.ConstantTimeCompare(got, want) == 1
}
func pbkdf2SHA256(password, salt []byte, iterations, keyLen int) []byte {
hLen := sha256.Size
blocks := (keyLen + hLen - 1) / hLen
out := make([]byte, 0, blocks*hLen)
for block := 1; block <= blocks; block++ {
mac := hmac.New(sha256.New, password)
mac.Write(salt)
var n [4]byte
binary.BigEndian.PutUint32(n[:], uint32(block))
mac.Write(n[:])
u := mac.Sum(nil)
t := append([]byte(nil), u...)
for i := 1; i < iterations; i++ {
mac = hmac.New(sha256.New, password)
mac.Write(u)
u = mac.Sum(nil)
for j := range t {
t[j] ^= u[j]
}
}
out = append(out, t...)
}
return out[:keyLen]
}