12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 |
- 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())
- }
|