mirror of
https://github.com/rjNemo/auth
synced 2026-06-06 00:16:40 +00:00
Relocated internal/auth to internal/service/auth for improved project structure and separation of concerns. Updated all imports to reflect new paths. Split UserStore interface and error definitions into a dedicated store.go file. Moved generateUserID to user.go for better encapsulation.
50 lines
1.2 KiB
Go
50 lines
1.2 KiB
Go
package auth
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"crypto/subtle"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"log"
|
|
)
|
|
|
|
const saltLen = 32
|
|
|
|
// HashPassword returns a base64-encoded salt and hash for the provided plaintext.
|
|
func HashPassword(plain string) (salt string, hash string, err error) {
|
|
if plain == "" {
|
|
return "", "", fmt.Errorf("password cannot be empty")
|
|
}
|
|
|
|
rawSalt := make([]byte, saltLen)
|
|
if _, err = rand.Read(rawSalt); err != nil {
|
|
return "", "", fmt.Errorf("generate salt: %w", err)
|
|
}
|
|
|
|
salt = base64.StdEncoding.EncodeToString(rawSalt)
|
|
hash = encodeHash(rawSalt, plain)
|
|
|
|
return salt, hash, nil
|
|
}
|
|
|
|
// VerifyPassword reports whether the supplied plaintext matches the salt+hash pair.
|
|
func VerifyPassword(plain, salt, expectedHash string) bool {
|
|
if plain == "" || salt == "" || expectedHash == "" {
|
|
return false
|
|
}
|
|
|
|
rawSalt, err := base64.StdEncoding.DecodeString(salt)
|
|
if err != nil {
|
|
log.Printf("auth: invalid salt encoding: %v", err)
|
|
return false
|
|
}
|
|
|
|
calculated := encodeHash(rawSalt, plain)
|
|
return subtle.ConstantTimeCompare([]byte(calculated), []byte(expectedHash)) == 1
|
|
}
|
|
|
|
func encodeHash(salt []byte, plain string) string {
|
|
digest := sha256.Sum256(append(salt, plain...))
|
|
return base64.StdEncoding.EncodeToString(digest[:])
|
|
}
|