2024-04-06 22:52:39 +00:00
|
|
|
// Package hasher contains methods to generate hashes for a given password
|
2017-10-06 20:54:45 +00:00
|
|
|
package hasher
|
|
|
|
|
|
|
|
import (
|
2024-04-06 22:52:39 +00:00
|
|
|
"crypto/sha256"
|
|
|
|
"crypto/sha512"
|
2017-10-06 20:54:45 +00:00
|
|
|
"fmt"
|
2024-04-06 22:52:39 +00:00
|
|
|
"hash"
|
2017-10-06 20:54:45 +00:00
|
|
|
|
2024-04-06 22:52:39 +00:00
|
|
|
"github.com/GehirnInc/crypt"
|
|
|
|
"github.com/GehirnInc/crypt/apr1_crypt"
|
|
|
|
"github.com/GehirnInc/crypt/sha256_crypt"
|
|
|
|
"github.com/GehirnInc/crypt/sha512_crypt"
|
2017-10-06 20:54:45 +00:00
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
|
|
)
|
|
|
|
|
|
|
|
type hasherFunc func(password string) (string, error)
|
|
|
|
|
2024-04-06 22:52:39 +00:00
|
|
|
var implementations = map[string]hasherFunc{
|
|
|
|
"htpasswd_apr1": implHTAPR1,
|
|
|
|
"htpasswd_bcrypt": implBcrypt,
|
|
|
|
"htpasswd_sha256": implHTSHA256,
|
|
|
|
"htpasswd_sha512": implHTSHA512,
|
|
|
|
"sha256": implSHA256,
|
|
|
|
"sha512": implSHA512,
|
|
|
|
}
|
2017-10-06 20:54:45 +00:00
|
|
|
|
2024-04-06 22:52:39 +00:00
|
|
|
// GetHashMap generates a map of hashes of the given password
|
2017-10-06 20:54:45 +00:00
|
|
|
func GetHashMap(password string) (map[string]string, error) {
|
|
|
|
result := map[string]string{}
|
|
|
|
|
|
|
|
for name, hf := range implementations {
|
|
|
|
h, err := hf(password)
|
|
|
|
if err != nil {
|
2024-04-06 22:52:39 +00:00
|
|
|
return nil, fmt.Errorf("hashing %s: %w", name, err)
|
2017-10-06 20:54:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
result[name] = h
|
|
|
|
}
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
2024-04-06 22:52:39 +00:00
|
|
|
func generic(h hash.Hash, password string) (_ string, err error) {
|
|
|
|
if _, err = h.Write([]byte(password)); err != nil {
|
|
|
|
return "", fmt.Errorf("writing password to hash: %w", err)
|
|
|
|
}
|
2017-10-06 20:54:45 +00:00
|
|
|
|
2024-04-06 22:52:39 +00:00
|
|
|
return fmt.Sprintf("%x", h.Sum(nil)), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func genericHT(c crypt.Crypter, password string) (string, error) {
|
|
|
|
h, err := c.Generate([]byte(password), nil) // Salt is auto-generated
|
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("generating hash: %w", err)
|
2017-10-06 20:54:45 +00:00
|
|
|
}
|
|
|
|
|
2024-04-06 22:52:39 +00:00
|
|
|
return h, nil
|
2017-10-06 20:54:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func implBcrypt(password string) (string, error) {
|
|
|
|
bc, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
|
|
|
if err != nil {
|
2024-04-06 22:52:39 +00:00
|
|
|
return "", fmt.Errorf("generating bcrypt hash: %w", err)
|
2017-10-06 20:54:45 +00:00
|
|
|
}
|
2024-04-06 22:52:39 +00:00
|
|
|
return string(bc), nil
|
2017-10-06 20:54:45 +00:00
|
|
|
}
|
|
|
|
|
2024-04-06 22:52:39 +00:00
|
|
|
func implHTAPR1(password string) (string, error) { return genericHT(apr1_crypt.New(), password) }
|
|
|
|
func implHTSHA256(password string) (string, error) { return genericHT(sha256_crypt.New(), password) }
|
|
|
|
func implHTSHA512(password string) (string, error) { return genericHT(sha512_crypt.New(), password) }
|
2017-10-06 20:54:45 +00:00
|
|
|
|
2024-04-06 22:52:39 +00:00
|
|
|
func implSHA256(password string) (string, error) { return generic(sha256.New(), password) }
|
|
|
|
func implSHA512(password string) (string, error) { return generic(sha512.New(), password) }
|