Use scrypt to store passwords
This commit is contained in:
parent
fdb7544999
commit
07a133e49a
4 changed files with 60 additions and 31 deletions
3
README
3
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 \
|
# 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/gorilla/securecookie github.com/gorilla/mux \
|
||||||
github.com/nfnt/resize github.com/cihub/seelog \
|
github.com/nfnt/resize github.com/cihub/seelog \
|
||||||
gopkgs.com/unidecode.v1
|
gopkgs.com/unidecode.v1 \
|
||||||
|
code.google.com/p/go.crypto/scrypt
|
||||||
|
|
||||||
== Installation ==
|
== Installation ==
|
||||||
=== For admins ("for developers" below) ===
|
=== For admins ("for developers" below) ===
|
||||||
|
|
|
@ -9,7 +9,6 @@ const (
|
||||||
FS_BOOKS = "fs_books"
|
FS_BOOKS = "fs_books"
|
||||||
FS_IMGS = "fs_imgs"
|
FS_IMGS = "fs_imgs"
|
||||||
|
|
||||||
PASS_SALT = "ImperialLibSalt"
|
|
||||||
MINUTES_UPDATE_TAGS = 11
|
MINUTES_UPDATE_TAGS = 11
|
||||||
MINUTES_UPDATE_VISITED = 41
|
MINUTES_UPDATE_VISITED = 41
|
||||||
MINUTES_UPDATE_DOWNLOADED = 47
|
MINUTES_UPDATE_DOWNLOADED = 47
|
||||||
|
|
|
@ -4,7 +4,8 @@ import log "github.com/cihub/seelog"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/md5"
|
"code.google.com/p/go.crypto/scrypt"
|
||||||
|
"crypto/rand"
|
||||||
"errors"
|
"errors"
|
||||||
"labix.org/v2/mgo"
|
"labix.org/v2/mgo"
|
||||||
"labix.org/v2/mgo/bson"
|
"labix.org/v2/mgo/bson"
|
||||||
|
@ -24,6 +25,7 @@ type User struct {
|
||||||
type db_user struct {
|
type db_user struct {
|
||||||
User string
|
User string
|
||||||
Pass []byte
|
Pass []byte
|
||||||
|
Salt []byte
|
||||||
Role string
|
Role string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +60,11 @@ func addUser(coll *mgo.Collection, name string, pass string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
var user db_user
|
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.User = name
|
||||||
user.Role = ""
|
user.Role = ""
|
||||||
return coll.Insert(user)
|
return coll.Insert(user)
|
||||||
|
@ -72,8 +78,7 @@ func (u User) Valid(pass string) bool {
|
||||||
if u.err != nil {
|
if u.err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
hash := md5Pass(pass)
|
return validatePass(pass, u.user)
|
||||||
return bytes.Compare(u.user.Pass, hash) == 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u User) Role() string {
|
func (u User) Role() string {
|
||||||
|
@ -84,13 +89,48 @@ func (u *User) SetPassword(pass string) error {
|
||||||
if u.err != nil {
|
if u.err != nil {
|
||||||
return u.err
|
return u.err
|
||||||
}
|
}
|
||||||
hash := md5Pass(pass)
|
hash, salt, err := hashPass(pass)
|
||||||
return u.coll.Update(bson.M{"user": u.user.User}, bson.M{"$set": bson.M{"pass": hash}})
|
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 hashPass(pass string) (hash []byte, salt []byte, err error) {
|
||||||
func md5Pass(pass string) []byte {
|
salt, err = genSalt()
|
||||||
h := md5.New()
|
if err != nil {
|
||||||
hash := h.Sum(([]byte)(pass_salt + pass))
|
return
|
||||||
return hash
|
}
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,37 +2,26 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.google.com/p/gopass"
|
"code.google.com/p/gopass"
|
||||||
"crypto/md5"
|
"git.gitorious.org/trantor/trantor.git/database"
|
||||||
"fmt"
|
|
||||||
"labix.org/v2/mgo"
|
|
||||||
"labix.org/v2/mgo/bson"
|
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
IP = "127.0.0.1"
|
DB_IP = "127.0.0.1"
|
||||||
DB_NAME = "trantor"
|
DB_NAME = "trantor"
|
||||||
USERS_COLL = "users"
|
|
||||||
PASS_SALT = "ImperialLibSalt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
session, err := mgo.Dial(IP)
|
db := database.Init(DB_IP, DB_NAME)
|
||||||
if err != nil {
|
defer db.Close()
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer session.Close()
|
|
||||||
coll := session.DB(DB_NAME).C(USERS_COLL)
|
|
||||||
|
|
||||||
user := os.Args[1]
|
user := os.Args[1]
|
||||||
pass, err := gopass.GetPass("Password: ")
|
pass, err := gopass.GetPass("Password: ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
h := md5.New()
|
|
||||||
hash := h.Sum(([]byte)(PASS_SALT + pass))
|
err = db.AddUser(user, pass)
|
||||||
fmt.Println(user, " - ", hash)
|
|
||||||
err = coll.Insert(bson.M{"user": user, "pass": hash, "role": "admin"})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue