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 { ID uint64 `json:"id"` Username string `json:"username"` Salt string `json:"salt"` Passwd string `json:"passwd"` Email string `json:"email"` } func NewUser(name, passwd string) (*User, error) { log.WithFields(log.Fields{"name": name}).Debugf("starting") defer log.WithFields(log.Fields{"name": name}).Debugf("done") userID := uint64(0) for _, v := range cfg.Admin.Users { userID = max(v.ID+1, userID) if v.Username == name { err := errors.New("user already exists") log.WithFields(log.Fields{"name": name, "error": err}).Errorf("") return nil, err } } u := &User{ ID: userID, 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 } }