@@ -0,0 +1,71 @@
|
||||
package customer
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var rawURL = base64.RawURLEncoding
|
||||
|
||||
func RandomToken(n int) string {
|
||||
if n < 16 {
|
||||
n = 16
|
||||
}
|
||||
b := make([]byte, n)
|
||||
_, _ = rand.Read(b)
|
||||
return rawURL.EncodeToString(b)
|
||||
}
|
||||
|
||||
func NewPasswordHash(password string) (salt string, hash string, err error) {
|
||||
if len(strings.TrimSpace(password)) < 12 {
|
||||
return "", "", errors.New("password must be at least 12 characters")
|
||||
}
|
||||
s := make([]byte, 16)
|
||||
if _, err := rand.Read(s); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
h := pbkdf2SHA256([]byte(password), s, 310000, 32)
|
||||
return rawURL.EncodeToString(s), rawURL.EncodeToString(h), nil
|
||||
}
|
||||
func VerifyPassword(password, salt, hash string) bool {
|
||||
s, err := rawURL.DecodeString(salt)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
want, err := rawURL.DecodeString(hash)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
got := pbkdf2SHA256([]byte(password), s, 310000, len(want))
|
||||
return len(got) == len(want) && subtle.ConstantTimeCompare(got, want) == 1
|
||||
}
|
||||
func pbkdf2SHA256(password, salt []byte, iterations, keyLen int) []byte {
|
||||
hLen := sha256.Size
|
||||
blocks := (keyLen + hLen - 1) / hLen
|
||||
out := make([]byte, 0, blocks*hLen)
|
||||
for block := 1; block <= blocks; block++ {
|
||||
mac := hmac.New(sha256.New, password)
|
||||
mac.Write(salt)
|
||||
var n [4]byte
|
||||
binary.BigEndian.PutUint32(n[:], uint32(block))
|
||||
mac.Write(n[:])
|
||||
u := mac.Sum(nil)
|
||||
t := append([]byte(nil), u...)
|
||||
for i := 1; i < iterations; i++ {
|
||||
mac = hmac.New(sha256.New, password)
|
||||
mac.Write(u)
|
||||
u = mac.Sum(nil)
|
||||
for j := range t {
|
||||
t[j] ^= u[j]
|
||||
}
|
||||
}
|
||||
out = append(out, t...)
|
||||
}
|
||||
return out[:keyLen]
|
||||
}
|
||||
Reference in New Issue
Block a user