asciigoat's .htaccess and .htpasswd parser https://asciigoat.org/httools
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

72 lines
1.4 KiB

package htpasswd
import (
"bytes"
"crypto/rand"
"crypto/sha1"
"encoding/base64"
"fmt"
)
// Ssha facilitates ssha style hashing
type Ssha struct{}
// Hash returns the hashed variant of the password or an error
func (ss *Ssha) Hash(passwd string) (string, error) {
s := sha1.New()
_, err := s.Write([]byte(passwd))
if err != nil {
return "", err
}
salt := make([]byte, 4)
_, err = rand.Read(salt)
if err != nil {
return "", err
}
_, err = s.Write([]byte(salt))
if err != nil {
return "", err
}
passwordSum := []byte(s.Sum(nil))
ret := append(passwordSum, salt...)
return ss.Prefix() + base64.StdEncoding.EncodeToString(ret), nil
}
// Match verifier the hashed password using the original
func (*Ssha) Match(password, hashedPassword string) error {
eppS := hashedPassword[6:]
hash, err := base64.StdEncoding.DecodeString(eppS)
if err != nil {
return fmt.Errorf("cannot base64 decode")
}
salt := hash[len(hash)-4:]
sha := sha1.New()
_, err = sha.Write([]byte(password))
if err != nil {
return err
}
_, err = sha.Write(salt)
if err != nil {
return err
}
sum := sha.Sum(nil)
if !bytes.Equal(sum, hash[:len(hash)-4]) {
return fmt.Errorf("wrong password")
}
return nil
}
// Name returns the name of the hasher
func (*Ssha) Name() string { return "ssha" }
// Prefix returns the hasher's prefix
func (*Ssha) Prefix() string { return "{SSHA}" }