package passwd import ( "bytes" "crypto/sha256" "crypto/sha512" "encoding/hex" "fmt" "math/rand" "strings" "time" ) var rnd *rand.Rand const ( sha256Prefix = "sha256pwd" sha512Prefix = "sha512pwd" saltSize = 12 ) func init() { src := rand.NewSource(time.Now().UnixNano()) rnd = rand.New(src) } func MakeSHA256Hash(passwd []byte) string { var res string salt := hex.EncodeToString(randomBytes(saltSize)) passwdString := hex.EncodeToString(passwd) passwdString = fmt.Sprintf("%s%s", passwdString, salt) hasher := sha256.New() hasher.Write([]byte(passwdString)) checksum := hex.EncodeToString(hasher.Sum(nil)) res = fmt.Sprintf("%s:%s:%s", sha256Prefix, salt, checksum) return res } func MakeSHA512Hash(passwd []byte) string { var res string salt := hex.EncodeToString(randomBytes(saltSize)) passwdString := hex.EncodeToString(passwd) passwdString = fmt.Sprintf("%s%s", passwdString, salt) hasher := sha512.New() hasher.Write([]byte(passwdString)) checksum := hex.EncodeToString(hasher.Sum(nil)) res = fmt.Sprintf("%s:%s:%s", sha512Prefix, salt, checksum) return res } func PasswordMatchCompat(passwd []byte, hash string) bool { if strings.HasPrefix(hash, sha256Prefix) || strings.HasPrefix(hash, sha512Prefix) { return PasswordMatch(passwd, hash) } if bytes.Equal(passwd, []byte(hash)) { return true } return false } func PasswordMatch(passwd []byte, hash string) bool { hashComponents := strings.Split(hash, ":") if len(hashComponents) != 3 { return false } method := hashComponents[0] salt := hashComponents[1] controlChecksum := hashComponents[2] switch method { case sha256Prefix: passwdString := hex.EncodeToString(passwd) passwdString = fmt.Sprintf("%s%s", passwdString, salt) hasher := sha256.New() hasher.Write([]byte(passwdString)) checksum := hex.EncodeToString(hasher.Sum(nil)) if checksum != controlChecksum { return false } case sha512Prefix: passwdString := hex.EncodeToString(passwd) passwdString = fmt.Sprintf("%s%s", passwdString, salt) hasher := sha512.New() hasher.Write([]byte(passwdString)) checksum := hex.EncodeToString(hasher.Sum(nil)) if checksum != controlChecksum { return false } default: return false } return true } func randomString(n int) string { const letters = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" arr := make([]byte, n) lettersArrayLen := len(letters) for i := range arr { arr[i] = letters[rnd.Intn(lettersArrayLen)] } return string(arr) } func randomBytes(n int) []byte { arr := make([]byte, n) for i := range arr { arr[i] = byte(rnd.Intn(256) & 0xFF) } return arr }