Bozhin Zafirov 7 роки тому
батько
коміт
8e3d5b88aa
2 змінених файлів з 77 додано та 1 видалено
  1. 1 1
      LICENSE
  2. 76 0
      crypt.go

+ 1 - 1
LICENSE

@@ -1,4 +1,4 @@
-Copyright (c) <year> <owner> All rights reserved.
+Copyright (c) 2018 Bozhin Zafirov. All rights reserved.
 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 
 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

+ 76 - 0
crypt.go

@@ -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())
+}