mirror of https://github.com/mindoc-org/mindoc.git
147 lines
3.0 KiB
Go
147 lines
3.0 KiB
Go
package utils
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"crypto/sha512"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"io"
|
|
mt "math/rand"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
saltSize = 16
|
|
delmiter = "$"
|
|
stretching_password = 500
|
|
salt_local_secret = "ahfw*&TGdsfnbi*^Wt"
|
|
)
|
|
|
|
//加密密码
|
|
func PasswordHash(pass string) (string, error) {
|
|
|
|
saltSecret, err := salt_secret()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
salt, err := salt(salt_local_secret + saltSecret)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
interation := randInt(1, 20)
|
|
|
|
hash, err := hash(pass, saltSecret, salt, int64(interation))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
interationString := strconv.Itoa(interation)
|
|
password := saltSecret + delmiter + interationString + delmiter + hash + delmiter + salt
|
|
|
|
return password, nil
|
|
|
|
}
|
|
|
|
//校验密码是否有效
|
|
func PasswordVerify(hashing string, pass string) (bool, error) {
|
|
data := trimSaltHash(hashing)
|
|
|
|
interation, _ := strconv.ParseInt(data["interation_string"], 10, 64)
|
|
|
|
has, err := hash(pass, data["salt_secret"], data["salt"], int64(interation))
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
if (data["salt_secret"] + delmiter + data["interation_string"] + delmiter + has + delmiter + data["salt"]) == hashing {
|
|
return true, nil
|
|
} else {
|
|
return false, nil
|
|
}
|
|
|
|
}
|
|
|
|
func hash(pass string, salt_secret string, salt string, interation int64) (string, error) {
|
|
var passSalt = salt_secret + pass + salt + salt_secret + pass + salt + pass + pass + salt
|
|
var i int
|
|
|
|
hashPass := salt_local_secret
|
|
hashStart := sha512.New()
|
|
hashCenter := sha256.New()
|
|
hashOutput := sha256.New224()
|
|
|
|
i = 0
|
|
for i <= stretching_password {
|
|
i = i + 1
|
|
_, err := hashStart.Write([]byte(passSalt + hashPass))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
hashPass = hex.EncodeToString(hashStart.Sum(nil))
|
|
}
|
|
|
|
i = 0
|
|
for int64(i) <= interation {
|
|
i = i + 1
|
|
hashPass = hashPass + hashPass
|
|
}
|
|
|
|
i = 0
|
|
for i <= stretching_password {
|
|
i = i + 1
|
|
_, err := hashCenter.Write([]byte(hashPass + salt_secret))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
hashPass = hex.EncodeToString(hashCenter.Sum(nil))
|
|
}
|
|
if _,err := hashOutput.Write([]byte(hashPass + salt_local_secret)); err != nil {
|
|
return "", err
|
|
}
|
|
hashPass = hex.EncodeToString(hashOutput.Sum(nil))
|
|
|
|
return hashPass, nil
|
|
}
|
|
|
|
func trimSaltHash(hash string) map[string]string {
|
|
str := strings.Split(hash, delmiter)
|
|
|
|
return map[string]string{
|
|
"salt_secret": str[0],
|
|
"interation_string": str[1],
|
|
"hash": str[2],
|
|
"salt": str[3],
|
|
}
|
|
}
|
|
func salt(secret string) (string, error) {
|
|
|
|
buf := make([]byte, saltSize, saltSize+md5.Size)
|
|
_, err := io.ReadFull(rand.Reader, buf)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
hash := md5.New()
|
|
hash.Write(buf)
|
|
hash.Write([]byte(secret))
|
|
return hex.EncodeToString(hash.Sum(buf)), nil
|
|
}
|
|
|
|
func salt_secret() (string, error) {
|
|
rb := make([]byte, randInt(10, 100))
|
|
_, err := rand.Read(rb)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return base64.URLEncoding.EncodeToString(rb), nil
|
|
}
|
|
|
|
func randInt(min int, max int) int {
|
|
return min + mt.Intn(max-min)
|
|
}
|