45 lines
1.0 KiB
Go
45 lines
1.0 KiB
Go
package password
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"errors"
|
|
"strings"
|
|
"unicode/utf8"
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
const prefix = "bcrypt:v1:"
|
|
const minLength = 6
|
|
|
|
var ErrInvalidEncoding = errors.New("password hash encoding is invalid")
|
|
|
|
func Encode(value string) (string, error) {
|
|
length := utf8.RuneCountInString(value)
|
|
if !utf8.ValidString(value) || length < minLength || length > 1024 {
|
|
return "", ErrInvalidEncoding
|
|
}
|
|
hash, err := bcrypt.GenerateFromPassword(bcryptInput(value), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return prefix + string(hash), nil
|
|
}
|
|
|
|
func Verify(encoded, value string) bool {
|
|
if !strings.HasPrefix(encoded, prefix) || !utf8.ValidString(value) || utf8.RuneCountInString(value) > 1024 {
|
|
return false
|
|
}
|
|
return bcrypt.CompareHashAndPassword([]byte(strings.TrimPrefix(encoded, prefix)), bcryptInput(value)) == nil
|
|
}
|
|
|
|
func bcryptInput(value string) []byte {
|
|
raw := []byte(value)
|
|
if len(raw) <= 72 {
|
|
return raw
|
|
}
|
|
digest := sha256.Sum256(raw)
|
|
return []byte("sha256:" + hex.EncodeToString(digest[:]))
|
|
}
|