From 07a133e49a054b5af0f6933987ef644222ed93cf Mon Sep 17 00:00:00 2001 From: Las Zenow Date: Mon, 30 Jun 2014 23:06:55 -0500 Subject: [PATCH] Use scrypt to store passwords --- README | 3 +- config.go | 1 - database/users.go | 62 +++++++++++++++++++++++++++++++++------- tools/adduser/adduser.go | 25 +++++----------- 4 files changed, 60 insertions(+), 31 deletions(-) diff --git a/README b/README index 9481fa1..1f9a33a 100644 --- a/README +++ b/README @@ -26,7 +26,8 @@ Yo also need to install go dependences: # go get labix.org/v2/mgo/bson labix.org/v2/mgo/ github.com/gorilla/sessions \ github.com/gorilla/securecookie github.com/gorilla/mux \ github.com/nfnt/resize github.com/cihub/seelog \ - gopkgs.com/unidecode.v1 + gopkgs.com/unidecode.v1 \ + code.google.com/p/go.crypto/scrypt == Installation == === For admins ("for developers" below) === diff --git a/config.go b/config.go index 902dcc4..bd27d3a 100644 --- a/config.go +++ b/config.go @@ -9,7 +9,6 @@ const ( FS_BOOKS = "fs_books" FS_IMGS = "fs_imgs" - PASS_SALT = "ImperialLibSalt" MINUTES_UPDATE_TAGS = 11 MINUTES_UPDATE_VISITED = 41 MINUTES_UPDATE_DOWNLOADED = 47 diff --git a/database/users.go b/database/users.go index e547a28..14eae3b 100644 --- a/database/users.go +++ b/database/users.go @@ -4,7 +4,8 @@ import log "github.com/cihub/seelog" import ( "bytes" - "crypto/md5" + "code.google.com/p/go.crypto/scrypt" + "crypto/rand" "errors" "labix.org/v2/mgo" "labix.org/v2/mgo/bson" @@ -24,6 +25,7 @@ type User struct { type db_user struct { User string Pass []byte + Salt []byte Role string } @@ -58,7 +60,11 @@ func addUser(coll *mgo.Collection, name string, pass string) error { } var user db_user - user.Pass = md5Pass(pass) + user.Pass, user.Salt, err = hashPass(pass) + if err != nil { + log.Error("Error hashing password: ", err) + return errors.New("An error happen storing the password") + } user.User = name user.Role = "" return coll.Insert(user) @@ -72,8 +78,7 @@ func (u User) Valid(pass string) bool { if u.err != nil { return false } - hash := md5Pass(pass) - return bytes.Compare(u.user.Pass, hash) == 0 + return validatePass(pass, u.user) } func (u User) Role() string { @@ -84,13 +89,48 @@ func (u *User) SetPassword(pass string) error { if u.err != nil { return u.err } - hash := md5Pass(pass) - return u.coll.Update(bson.M{"user": u.user.User}, bson.M{"$set": bson.M{"pass": hash}}) + hash, salt, err := hashPass(pass) + if err != nil { + return err + } + return u.coll.Update(bson.M{"user": u.user.User}, bson.M{"$set": bson.M{"pass": hash, "salt": salt}}) } -// FIXME: use a proper salting algorithm -func md5Pass(pass string) []byte { - h := md5.New() - hash := h.Sum(([]byte)(pass_salt + pass)) - return hash +func hashPass(pass string) (hash []byte, salt []byte, err error) { + salt, err = genSalt() + if err != nil { + return + } + hash, err = calculateHash(pass, salt) + return +} + +func genSalt() ([]byte, error) { + const ( + saltLen = 64 + ) + + b := make([]byte, saltLen) + _, err := rand.Read(b) + return b, err +} + +func validatePass(pass string, user db_user) bool { + hash, err := calculateHash(pass, user.Salt) + if err != nil { + return false + } + return bytes.Compare(user.Pass, hash) == 0 +} + +func calculateHash(pass string, salt []byte) ([]byte, error) { + const ( + N = 16384 + r = 8 + p = 1 + keyLen = 32 + ) + + bpass := []byte(pass) + return scrypt.Key(bpass, salt, N, r, p, keyLen) } diff --git a/tools/adduser/adduser.go b/tools/adduser/adduser.go index 458900f..f1b9d9d 100644 --- a/tools/adduser/adduser.go +++ b/tools/adduser/adduser.go @@ -2,37 +2,26 @@ package main import ( "code.google.com/p/gopass" - "crypto/md5" - "fmt" - "labix.org/v2/mgo" - "labix.org/v2/mgo/bson" + "git.gitorious.org/trantor/trantor.git/database" "os" ) const ( - IP = "127.0.0.1" - DB_NAME = "trantor" - USERS_COLL = "users" - PASS_SALT = "ImperialLibSalt" + DB_IP = "127.0.0.1" + DB_NAME = "trantor" ) func main() { - session, err := mgo.Dial(IP) - if err != nil { - panic(err) - } - defer session.Close() - coll := session.DB(DB_NAME).C(USERS_COLL) + db := database.Init(DB_IP, DB_NAME) + defer db.Close() user := os.Args[1] pass, err := gopass.GetPass("Password: ") if err != nil { panic(err) } - h := md5.New() - hash := h.Sum(([]byte)(PASS_SALT + pass)) - fmt.Println(user, " - ", hash) - err = coll.Insert(bson.M{"user": user, "pass": hash, "role": "admin"}) + + err = db.AddUser(user, pass) if err != nil { panic(err) }