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}" }