// Adapted from Sendico verification/hash.go; see backend/PROVENANCE.md. package credential import ( "crypto/rand" "crypto/sha256" "crypto/subtle" "encoding/base64" ) // New returns an opaque credential and its storage digest. Store only the digest. // This is for high-entropy tokens, never passwords or short numeric OTP codes. func New() (raw, digest string, err error) { bytes := make([]byte, 32) if _, err = rand.Read(bytes); err != nil { return "", "", err } raw = base64.RawURLEncoding.EncodeToString(bytes) return raw, Digest(raw), nil } func Digest(raw string) string { sum := sha256.Sum256([]byte(raw)) return base64.RawURLEncoding.EncodeToString(sum[:]) } func Matches(raw, digest string) bool { return raw != "" && subtle.ConstantTimeCompare([]byte(Digest(raw)), []byte(digest)) == 1 }