package main import ( "crypto/hmac" "crypto/rand" "crypto/sha256" "encoding/hex" "errors" log "github.com/sirupsen/logrus" "golang.org/x/crypto/scrypt" ) type User struct { Username string `json:"username"` Salt string `json:"salt"` Passwd string `json:"passwd"` } func NewUser(name, passwd string) (*User, error) { log.WithFields(log.Fields{"name": name}).Debugf("starting") defer log.WithFields(log.Fields{"name": name}).Debugf("done") for _, v := range cfg.Admin.Users { if v.Username == name { err := errors.New("user already exists") log.WithFields(log.Fields{"name": name, "error": err}).Errorf("") return nil, err } } u := &User{ Username: name, } salt := make([]byte, 32) if _, err := rand.Read(salt); err != nil { log.WithFields(log.Fields{"name": name, "call": "rand.Read", "error": err}).Errorf("") return nil, err } u.Salt = hex.EncodeToString(salt) if pass, err := u.HashPassword(passwd); err != nil { log.WithFields(log.Fields{"name": name, "call": "HashPassword", "error": err}).Errorf("") return nil, err } else { u.Passwd = hex.EncodeToString(pass) } return u, nil } func (u *User) HashPassword(passwd string) ([]byte, error) { log.WithFields(log.Fields{}).Debugf("starting") defer log.WithFields(log.Fields{}).Debugf("done") //peppering the pass hash := hmac.New(sha256.New, []byte(cfg.Admin.Secrets.PasswordPepper)) hash.Write([]byte(passwd)) hashPass := hash.Sum(nil) //salting the hash salt := make([]byte, 32) if _, err := hex.Decode(salt, []byte(u.Salt)); err != nil { log.WithFields(log.Fields{"call": "hex.Decode", "error": err}).Errorf("") return nil, err } if h, err := scrypt.Key(hashPass, salt, cfg.Admin.Secrets.ScryptN, cfg.Admin.Secrets.ScryptR, cfg.Admin.Secrets.ScryptP, 32); err != nil { log.WithFields(log.Fields{"call": "scrypt.Key", "error": err}).Errorf("") return h, err } else { return h, nil } }