package main import ( "errors" "strings" "bytes" "crypto/rand" "crypto/sha1" "encoding/base64" "fmt" log "github.com/sirupsen/logrus" //"github.com/jsimonetti/pwscheme/ssha" "github.com/jsimonetti/pwscheme/ssha256" "github.com/jsimonetti/pwscheme/ssha512" ) const ( SSHA = "{SSHA}" SSHA256 = "{SSHA256}" SSHA512 = "{SSHA512}" ) // Encode encodes the string to ssha512 func SSHAEncode(rawPassPhrase string) (string, error) { return ssha512.Generate(rawPassPhrase, 16) } // Matches matches the encoded password and the raw password func SSHAMatches(encodedPassPhrase string, rawPassPhrase string) (bool, error) { hashType, err := determineHashType(encodedPassPhrase) if err != nil { return false, errors.New("invalid password hash stored") } var is_ok bool switch hashType { case SSHA: is_ok = LegacySSHAMatches(encodedPassPhrase, []byte(rawPassPhrase)) return is_ok, nil //return ssha.Validate(rawPassPhrase, encodedPassPhrase) case SSHA256: return ssha256.Validate(rawPassPhrase, encodedPassPhrase) case SSHA512: return ssha512.Validate(rawPassPhrase, encodedPassPhrase) } return false, errors.New("no matching hash type found") } func determineHashType(hash string) (string, error) { if len(hash) >= 7 && strings.ToUpper(string(hash[0:6])) == SSHA { return SSHA, nil } if len(hash) >= 10 && strings.ToUpper(string(hash[0:9])) == SSHA256 { return SSHA256, nil } if len(hash) >= 10 && strings.ToUpper(string(hash[0:9])) == SSHA512 { return SSHA512, nil } return "", errors.New("no valid hash found") } // --- legacy // Encode encodes the []byte of raw password func LegacySSHAEncode(rawPassPhrase []byte) string { hash := legacyMakeSSHAHash(rawPassPhrase, legacyMakeSalt()) b64 := base64.StdEncoding.EncodeToString(hash) return fmt.Sprintf("{ssha}%s", b64) } // Matches matches the encoded password and the raw password func LegacySSHAMatches(encodedPassPhrase string, rawPassPhrase []byte) bool { if !strings.EqualFold(encodedPassPhrase[:6], "{ssha}") { return false } bhash, err := base64.StdEncoding.DecodeString(encodedPassPhrase[6:]) if err != nil { return false } salt := bhash[20:] newssha := legacyMakeSSHAHash(rawPassPhrase, salt) if bytes.Compare(newssha, bhash) != 0 { return false } return true } // makeSalt make a 32 byte array containing random bytes. func legacyMakeSalt() []byte { sbytes := make([]byte, 32) _, err := rand.Read(sbytes) if err != nil { log.Panicf("Could not read random bytes: %s", err) } return sbytes } // makeSSHAHash make hasing using SHA-1 with salt. This is not the final output though. You need to append {SSHA} string with base64 of this hash. func legacyMakeSSHAHash(passphrase, salt []byte) []byte { sha := sha1.New() sha.Write(passphrase) sha.Write(salt) h := sha.Sum(nil) return append(h, salt...) }