Browse Source

Add salt for every single user

Unknown 11 years ago
parent
commit
e7c8a3cb8d
8 changed files with 64 additions and 30 deletions
  1. 0 1
      .gopmfile
  2. 2 2
      README.md
  3. 1 1
      README_ZH.md
  4. 1 1
      gogs.go
  5. 16 15
      models/user.go
  6. 40 0
      modules/base/tool.go
  7. 2 5
      routers/user/setting.go
  8. 2 5
      routers/user/user.go

+ 0 - 1
.gopmfile

@@ -7,7 +7,6 @@ github.com/go-martini/martini =
 github.com/Unknwon/com = 
 github.com/Unknwon/cae = 
 github.com/Unknwon/goconfig = 
-github.com/dchest/scrypt = 
 github.com/nfnt/resize = 
 github.com/lunny/xorm = 
 github.com/go-sql-driver/mysql = 

+ 2 - 2
README.md

@@ -5,9 +5,9 @@ Gogs(Go Git Service) is a Self Hosted Git Service in the Go Programming Language
 
 ![Demo](http://gowalker.org/public/gogs_demo.gif)
 
-##### Current version: 0.2.1 Alpha
+##### Current version: 0.2.2 Alpha
 
-#### Due to testing purpose, data of [try.gogits.org](http://try.gogits.org) has been reset in March 29, 2014 and will reset multiple times after. Please do NOT put your important data on the site.
+#### Due to testing purpose, data of [try.gogits.org](http://try.gogits.org) has been reset in April 6, 2014 and will reset multiple times after. Please do NOT put your important data on the site.
 
 #### Other language version
 

+ 1 - 1
README_ZH.md

@@ -5,7 +5,7 @@ Gogs(Go Git Service) 是一个由 Go 语言编写的自助 Git 托管服务。
 
 ![Demo](http://gowalker.org/public/gogs_demo.gif)
 
-##### 当前版本:0.2.1 Alpha
+##### 当前版本:0.2.2 Alpha
 
 ## 开发目的
 

+ 1 - 1
gogs.go

@@ -19,7 +19,7 @@ import (
 // Test that go1.2 tag above is included in builds. main.go refers to this definition.
 const go12tag = true
 
-const APP_VER = "0.2.1.0406 Alpha"
+const APP_VER = "0.2.2.0406 Alpha"
 
 func init() {
 	base.AppVer = APP_VER

+ 16 - 15
models/user.go

@@ -5,6 +5,7 @@
 package models
 
 import (
+	"crypto/sha256"
 	"encoding/hex"
 	"errors"
 	"fmt"
@@ -13,8 +14,6 @@ import (
 	"strings"
 	"time"
 
-	"github.com/dchest/scrypt"
-
 	"github.com/gogits/git"
 
 	"github.com/gogits/gogs/modules/base"
@@ -62,6 +61,7 @@ type User struct {
 	IsActive      bool
 	IsAdmin       bool
 	Rands         string    `xorm:"VARCHAR(10)"`
+	Salt          string    `xorm:"VARCHAR(10)"`
 	Created       time.Time `xorm:"created"`
 	Updated       time.Time `xorm:"updated"`
 }
@@ -89,10 +89,9 @@ func (user *User) NewGitSig() *git.Signature {
 }
 
 // EncodePasswd encodes password to safe format.
-func (user *User) EncodePasswd() error {
-	newPasswd, err := scrypt.Key([]byte(user.Passwd), []byte(base.SecretKey), 16384, 8, 1, 64)
+func (user *User) EncodePasswd() {
+	newPasswd := base.PBKDF2([]byte(user.Passwd), []byte(user.Salt), 10000, 50, sha256.New)
 	user.Passwd = fmt.Sprintf("%x", newPasswd)
-	return err
 }
 
 // Member represents user is member of organization.
@@ -148,9 +147,9 @@ func RegisterUser(user *User) (*User, error) {
 	user.Avatar = base.EncodeMd5(user.Email)
 	user.AvatarEmail = user.Email
 	user.Rands = GetUserSalt()
-	if err = user.EncodePasswd(); err != nil {
-		return nil, err
-	} else if _, err = orm.Insert(user); err != nil {
+	user.Salt = GetUserSalt()
+	user.EncodePasswd()
+	if _, err = orm.Insert(user); err != nil {
 		return nil, err
 	} else if err = os.MkdirAll(UserPath(user.Name), os.ModePerm); err != nil {
 		if _, err := orm.Id(user.Id).Delete(&User{}); err != nil {
@@ -384,18 +383,20 @@ func GetUserByEmail(email string) (*User, error) {
 
 // LoginUserPlain validates user by raw user name and password.
 func LoginUserPlain(name, passwd string) (*User, error) {
-	user := User{LowerName: strings.ToLower(name), Passwd: passwd}
-	if err := user.EncodePasswd(); err != nil {
-		return nil, err
-	}
-
+	user := User{LowerName: strings.ToLower(name)}
 	has, err := orm.Get(&user)
 	if err != nil {
 		return nil, err
 	} else if !has {
-		err = ErrUserNotExist
+		return nil, ErrUserNotExist
+	}
+
+	newUser := &User{Passwd: passwd, Salt: user.Salt}
+	newUser.EncodePasswd()
+	if user.Passwd != newUser.Passwd {
+		return nil, ErrUserNotExist
 	}
-	return &user, err
+	return &user, nil
 }
 
 // Follow is connection request for receiving user notifycation.

+ 40 - 0
modules/base/tool.go

@@ -6,12 +6,14 @@ package base
 
 import (
 	"bytes"
+	"crypto/hmac"
 	"crypto/md5"
 	"crypto/rand"
 	"crypto/sha1"
 	"encoding/hex"
 	"encoding/json"
 	"fmt"
+	"hash"
 	"math"
 	"strconv"
 	"strings"
@@ -40,6 +42,44 @@ func GetRandomString(n int, alphabets ...byte) string {
 	return string(bytes)
 }
 
+// http://code.google.com/p/go/source/browse/pbkdf2/pbkdf2.go?repo=crypto
+func PBKDF2(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
+	prf := hmac.New(h, password)
+	hashLen := prf.Size()
+	numBlocks := (keyLen + hashLen - 1) / hashLen
+
+	var buf [4]byte
+	dk := make([]byte, 0, numBlocks*hashLen)
+	U := make([]byte, hashLen)
+	for block := 1; block <= numBlocks; block++ {
+		// N.B.: || means concatenation, ^ means XOR
+		// for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
+		// U_1 = PRF(password, salt || uint(i))
+		prf.Reset()
+		prf.Write(salt)
+		buf[0] = byte(block >> 24)
+		buf[1] = byte(block >> 16)
+		buf[2] = byte(block >> 8)
+		buf[3] = byte(block)
+		prf.Write(buf[:4])
+		dk = prf.Sum(dk)
+		T := dk[len(dk)-hashLen:]
+		copy(U, T)
+
+		// U_n = PRF(password, U_(n-1))
+		for n := 2; n <= iter; n++ {
+			prf.Reset()
+			prf.Write(U)
+			U = U[:0]
+			U = prf.Sum(U)
+			for x := range U {
+				T[x] ^= U[x]
+			}
+		}
+	}
+	return dk[:keyLen]
+}
+
 // verify time limit code
 func VerifyTimeLimitCode(data string, minutes int, code string) bool {
 	if len(code) <= 18 {

+ 2 - 5
routers/user/setting.go

@@ -73,11 +73,7 @@ func SettingPassword(ctx *middleware.Context, form auth.UpdatePasswdForm) {
 
 	user := ctx.User
 	newUser := &models.User{Passwd: form.NewPasswd}
-	if err := newUser.EncodePasswd(); err != nil {
-		ctx.Handle(200, "setting.SettingPassword", err)
-		return
-	}
-
+	newUser.EncodePasswd()
 	if user.Passwd != newUser.Passwd {
 		ctx.Data["HasError"] = true
 		ctx.Data["ErrorMsg"] = "Old password is not correct"
@@ -85,6 +81,7 @@ func SettingPassword(ctx *middleware.Context, form auth.UpdatePasswdForm) {
 		ctx.Data["HasError"] = true
 		ctx.Data["ErrorMsg"] = "New password and re-type password are not same"
 	} else {
+		newUser.Salt = models.GetUserSalt()
 		user.Passwd = newUser.Passwd
 		if err := models.UpdateUser(user); err != nil {
 			ctx.Handle(200, "setting.SettingPassword", err)

+ 2 - 5
routers/user/user.go

@@ -477,12 +477,9 @@ func ResetPasswd(ctx *middleware.Context) {
 		}
 
 		u.Passwd = passwd
-		if err := u.EncodePasswd(); err != nil {
-			ctx.Handle(404, "user.ResetPasswd(EncodePasswd)", err)
-			return
-		}
-
 		u.Rands = models.GetUserSalt()
+		u.Salt = models.GetUserSalt()
+		u.EncodePasswd()
 		if err := models.UpdateUser(u); err != nil {
 			ctx.Handle(404, "user.ResetPasswd(UpdateUser)", err)
 			return