56 lines
1.3 KiB
Go
56 lines
1.3 KiB
Go
package passwordutil
|
||
|
||
import (
|
||
"crypto/rand"
|
||
"crypto/sha256"
|
||
"encoding/hex"
|
||
"errors"
|
||
"strings"
|
||
)
|
||
|
||
const (
|
||
saltBytes = 16
|
||
separator = "$"
|
||
hashLength = 64 // sha256 hex length
|
||
)
|
||
|
||
// Hash 生成 salt+hash 的存储串,格式:salt$hash(均为 hex)
|
||
func Hash(plain string) (string, error) {
|
||
plain = strings.TrimSpace(plain)
|
||
if plain == "" {
|
||
return "", errors.New("password 不能为空")
|
||
}
|
||
salt := make([]byte, saltBytes)
|
||
if _, err := rand.Read(salt); err != nil {
|
||
return "", err
|
||
}
|
||
saltHex := hex.EncodeToString(salt)
|
||
hashHex := hashHex(saltHex, plain)
|
||
return saltHex + separator + hashHex, nil
|
||
}
|
||
|
||
// Verify 校验存储串(salt$hash)是否匹配输入明文密码。
|
||
func Verify(stored, plain string) bool {
|
||
stored = strings.TrimSpace(stored)
|
||
plain = strings.TrimSpace(plain)
|
||
if stored == "" || plain == "" {
|
||
return false
|
||
}
|
||
parts := strings.Split(stored, separator)
|
||
if len(parts) != 2 {
|
||
return false
|
||
}
|
||
saltHex := strings.TrimSpace(parts[0])
|
||
hashHexStored := strings.TrimSpace(parts[1])
|
||
if saltHex == "" || len(hashHexStored) != hashLength {
|
||
return false
|
||
}
|
||
return hashHex(saltHex, plain) == strings.ToLower(hashHexStored)
|
||
}
|
||
|
||
func hashHex(saltHex, plain string) string {
|
||
sum := sha256.Sum256([]byte(saltHex + plain))
|
||
return hex.EncodeToString(sum[:])
|
||
}
|
||
|