1
1
mirror of https://github.com/go-gitea/gitea synced 2025-07-22 18:28:37 +00:00

Add additional password hash algorithms (closes #5859) (#6023)

This commit is contained in:
EpicCoder
2019-07-07 08:01:01 +02:00
committed by techknowlogick
parent 1b85b248e4
commit 8d9d6aa903
23 changed files with 2895 additions and 20 deletions

View File

@@ -33,7 +33,10 @@ import (
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
"golang.org/x/crypto/argon2"
"golang.org/x/crypto/bcrypt"
"golang.org/x/crypto/pbkdf2"
"golang.org/x/crypto/scrypt"
"golang.org/x/crypto/ssh"
"xorm.io/builder"
"xorm.io/core"
@@ -50,6 +53,13 @@ const (
UserTypeOrganization
)
const (
algoBcrypt = "bcrypt"
algoScrypt = "scrypt"
algoArgon2 = "argon2"
algoPbkdf2 = "pbkdf2"
)
const syncExternalUsers = "sync_external_users"
var (
@@ -82,6 +92,7 @@ type User struct {
Email string `xorm:"NOT NULL"`
KeepEmailPrivate bool
Passwd string `xorm:"NOT NULL"`
PasswdHashAlgo string `xorm:"NOT NULL DEFAULT 'pbkdf2'"`
// MustChangePassword is an attribute that determines if a user
// is to change his/her password after registration.
@@ -430,25 +441,48 @@ func (u *User) NewGitSig() *git.Signature {
}
}
func hashPassword(passwd, salt string) string {
tempPasswd := pbkdf2.Key([]byte(passwd), []byte(salt), 10000, 50, sha256.New)
func hashPassword(passwd, salt, algo string) string {
var tempPasswd []byte
switch algo {
case algoBcrypt:
tempPasswd, _ = bcrypt.GenerateFromPassword([]byte(passwd), bcrypt.DefaultCost)
return string(tempPasswd)
case algoScrypt:
tempPasswd, _ = scrypt.Key([]byte(passwd), []byte(salt), 65536, 16, 2, 50)
case algoArgon2:
tempPasswd = argon2.IDKey([]byte(passwd), []byte(salt), 2, 65536, 8, 50)
case algoPbkdf2:
fallthrough
default:
tempPasswd = pbkdf2.Key([]byte(passwd), []byte(salt), 10000, 50, sha256.New)
}
return fmt.Sprintf("%x", tempPasswd)
}
// HashPassword hashes a password using PBKDF.
// HashPassword hashes a password using the algorithm defined in the config value of PASSWORD_HASH_ALGO.
func (u *User) HashPassword(passwd string) {
u.Passwd = hashPassword(passwd, u.Salt)
u.PasswdHashAlgo = setting.PasswordHashAlgo
u.Passwd = hashPassword(passwd, u.Salt, setting.PasswordHashAlgo)
}
// ValidatePassword checks if given password matches the one belongs to the user.
func (u *User) ValidatePassword(passwd string) bool {
tempHash := hashPassword(passwd, u.Salt)
return subtle.ConstantTimeCompare([]byte(u.Passwd), []byte(tempHash)) == 1
tempHash := hashPassword(passwd, u.Salt, u.PasswdHashAlgo)
if u.PasswdHashAlgo != algoBcrypt && subtle.ConstantTimeCompare([]byte(u.Passwd), []byte(tempHash)) == 1 {
return true
}
if u.PasswdHashAlgo == algoBcrypt && bcrypt.CompareHashAndPassword([]byte(u.Passwd), []byte(passwd)) == nil {
return true
}
return false
}
// IsPasswordSet checks if the password is set or left empty
func (u *User) IsPasswordSet() bool {
return !u.ValidatePassword("")
return len(u.Passwd) > 0
}
// UploadAvatar saves custom avatar for user.