|
@@ -0,0 +1,76 @@
|
|
|
+package crypt
|
|
|
+
|
|
|
+import (
|
|
|
+ "errors"
|
|
|
+ "math/rand"
|
|
|
+ "strings"
|
|
|
+ "time"
|
|
|
+ "unsafe"
|
|
|
+)
|
|
|
+
|
|
|
+// #cgo LDFLAGS: -lcrypt
|
|
|
+// #define _GNU_SOURCE
|
|
|
+// #include <crypt.h>
|
|
|
+// #include <stdlib.h>
|
|
|
+// #include <errno.h>
|
|
|
+import "C"
|
|
|
+
|
|
|
+// EPasswordIncorrect is a password verification failure error
|
|
|
+var EPasswordIncorrect = errors.New("passwords do not match")
|
|
|
+
|
|
|
+// Crypt wraps C library crypt_r
|
|
|
+func Crypt(Password, Salt string) (*string, error) {
|
|
|
+ data := C.struct_crypt_data{}
|
|
|
+ ckey := C.CString(Password)
|
|
|
+ csalt := C.CString(Salt)
|
|
|
+ cpass, err := C.crypt_r(ckey, csalt, &data)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ out := C.GoString(cpass)
|
|
|
+ C.free(unsafe.Pointer(ckey))
|
|
|
+ C.free(unsafe.Pointer(csalt))
|
|
|
+ return &out, nil
|
|
|
+}
|
|
|
+
|
|
|
+// MakeSaltSHA512 generates a random salt for SHA512
|
|
|
+// encrypted password hash.
|
|
|
+func MakeSaltSHA512() string {
|
|
|
+ var LetterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./")
|
|
|
+ salt := make([]rune, 8)
|
|
|
+
|
|
|
+ for i := range salt {
|
|
|
+ salt[i] = LetterRunes[rand.Intn(len(LetterRunes))]
|
|
|
+ }
|
|
|
+
|
|
|
+ return "$6$" + string(salt) + "$"
|
|
|
+}
|
|
|
+
|
|
|
+// Verify checks key against previously crypted hash
|
|
|
+func CompareHashAndPassword(Hash, Password string) error {
|
|
|
+ // ignore empty hashes
|
|
|
+ if len(Hash) == 0 {
|
|
|
+ return EPasswordIncorrect
|
|
|
+ }
|
|
|
+ // Split salt from password
|
|
|
+ HashItems := strings.SplitN(Hash, "$", 4)
|
|
|
+ Salt := "$" + HashItems[1] + "$" + HashItems[2] + "$"
|
|
|
+
|
|
|
+ hash, err := Crypt(Password, Salt)
|
|
|
+ if err != nil {
|
|
|
+ // Crypt error
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ if *hash == Hash {
|
|
|
+ // Passwords match
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ return EPasswordIncorrect
|
|
|
+}
|
|
|
+
|
|
|
+func init() {
|
|
|
+ // Initialize RNG seed
|
|
|
+ rand.Seed(time.Now().UnixNano())
|
|
|
+}
|