2016-09-03 10:18:46 +02:00
|
|
|
package password
|
2016-05-12 19:16:39 +02:00
|
|
|
|
|
|
|
import "golang.org/x/crypto/pbkdf2"
|
|
|
|
import "hash"
|
|
|
|
import "strconv"
|
|
|
|
import "encoding/base64"
|
|
|
|
import "crypto/sha1"
|
|
|
|
import "crypto/sha256"
|
|
|
|
import "crypto/sha512"
|
|
|
|
import "crypto/rand"
|
|
|
|
import "fmt"
|
|
|
|
import "strings"
|
|
|
|
|
|
|
|
const (
|
2016-09-03 10:18:46 +02:00
|
|
|
saltLength = 8
|
|
|
|
hashLength = 20
|
2016-08-24 23:02:25 +02:00
|
|
|
interations = 10000
|
|
|
|
hashfunc string = "sha256"
|
2016-05-12 19:16:39 +02:00
|
|
|
)
|
|
|
|
|
2016-08-24 23:02:25 +02:00
|
|
|
var hashlib = map[string]func() hash.Hash{
|
|
|
|
"sha1": sha1.New,
|
|
|
|
"sha256": sha256.New,
|
|
|
|
"sha512": sha512.New,
|
|
|
|
}
|
|
|
|
|
2016-09-03 10:18:46 +02:00
|
|
|
// Validate a password and a hash
|
2016-08-24 23:02:25 +02:00
|
|
|
func Validate(hash, password string) (output, replace bool) {
|
|
|
|
parts := strings.Split(hash, "$")
|
2016-05-12 19:16:39 +02:00
|
|
|
if len(parts) == 3 {
|
2016-08-24 23:02:25 +02:00
|
|
|
return false, false
|
2016-05-12 19:16:39 +02:00
|
|
|
}
|
2016-09-03 10:18:46 +02:00
|
|
|
curIter, err := strconv.Atoi(parts[1])
|
2016-05-12 19:16:39 +02:00
|
|
|
if err != nil {
|
2016-08-24 23:02:25 +02:00
|
|
|
return false, false
|
2016-05-12 19:16:39 +02:00
|
|
|
}
|
2016-09-03 10:18:46 +02:00
|
|
|
hashfuncC := strings.Split(parts[0], "_")[1]
|
|
|
|
replace = (hashfuncC != hashfunc)
|
2016-05-12 19:16:39 +02:00
|
|
|
|
2016-09-03 10:18:46 +02:00
|
|
|
dk := pbkdf2.Key([]byte(password), []byte(parts[2]), curIter, len(parts[3])-8, hashlib[hashfuncC])
|
|
|
|
x := fmt.Sprintf("pbkdf2_%s$%s$%s$%s", hashfuncC, parts[1], parts[2], base64.StdEncoding.EncodeToString(dk))
|
2016-08-24 23:02:25 +02:00
|
|
|
output = (x == hash)
|
2016-05-12 19:16:39 +02:00
|
|
|
return
|
|
|
|
}
|
2016-09-03 10:18:46 +02:00
|
|
|
|
|
|
|
// GenerateRandomString by length for key
|
2016-05-12 19:16:39 +02:00
|
|
|
func GenerateRandomString(n int) (string, error) {
|
|
|
|
b := make([]byte, n)
|
|
|
|
_, err := rand.Read(b)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return base64.URLEncoding.EncodeToString(b), nil
|
|
|
|
}
|
2016-09-03 10:18:46 +02:00
|
|
|
|
|
|
|
// NewHash of given password
|
2016-08-24 23:02:25 +02:00
|
|
|
func NewHash(password string) string {
|
2016-09-03 10:18:46 +02:00
|
|
|
salt, _ := GenerateRandomString(saltLength)
|
|
|
|
dk := pbkdf2.Key([]byte(password), []byte(salt), interations, hashLength, hashlib[hashfunc])
|
2016-08-24 23:02:25 +02:00
|
|
|
return fmt.Sprintf("pbkdf2_%s$%d$%s$%s", hashfunc, interations, salt, base64.StdEncoding.EncodeToString(dk))
|
2016-05-12 19:16:39 +02:00
|
|
|
}
|