Browse Source

add support for checking sha256crypt passwords

they will be converted to the configured password hashing algorithm after
the first user login

Fixes #1000

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
Nicola Murino 2 years ago
parent
commit
1e21aa9453

+ 1 - 1
docs/account.md

@@ -14,7 +14,7 @@ the dump is a JSON with all SFTPGo data including users, folders, admins.
 
 These properties are stored inside the configured data provider.
 
-SFTPGo supports checking passwords stored with bcrypt, pbkdf2, md5crypt and sha512crypt too. For pbkdf2 the supported format is `$<algo>$<iterations>$<salt>$<hashed pwd base64 encoded>`, where algo is `pbkdf2-sha1` or `pbkdf2-sha256` or `pbkdf2-sha512` or `$pbkdf2-b64salt-sha256$`. For example the pbkdf2-sha256 of the word password using 150000 iterations and E86a9YMX3zC7 as salt must be stored as `$pbkdf2-sha256$150000$E86a9YMX3zC7$R5J62hsSq+pYw00hLLPKBbcGXmq7fj5+/M0IFoYtZbo=`. In pbkdf2 variant with b64salt the salt is base64 encoded. For bcrypt the format must be the one supported by golang's crypto/bcrypt package, for example the password secret with cost 14 must be stored as `$2a$14$ajq8Q7fbtFRQvXpdCq7Jcuy.Rx1h/L4J60Otx.gyNLbAYctGMJ9tK`. For md5crypt and sha512crypt we support the format used in `/etc/shadow` with the `$1$` and `$6$` prefix, this is useful if you are migrating from Unix system user accounts. We support Apache md5crypt (`$apr1$` prefix) too. Using the REST API you can send a password hashed as bcrypt, pbkdf2, md5crypt or sha512crypt and it will be stored as is.
+SFTPGo supports checking passwords stored with argon2id, bcrypt, pbkdf2, md5cryptm sha256crypt and sha512crypt too. For pbkdf2 the supported format is `$<algo>$<iterations>$<salt>$<hashed pwd base64 encoded>`, where algo is `pbkdf2-sha1` or `pbkdf2-sha256` or `pbkdf2-sha512` or `$pbkdf2-b64salt-sha256$`. For example the pbkdf2-sha256 of the word password using 150000 iterations and E86a9YMX3zC7 as salt must be stored as `$pbkdf2-sha256$150000$E86a9YMX3zC7$R5J62hsSq+pYw00hLLPKBbcGXmq7fj5+/M0IFoYtZbo=`. In pbkdf2 variant with b64salt the salt is base64 encoded. For bcrypt the format must be the one supported by golang's crypto/bcrypt package, for example the password secret with cost 14 must be stored as `$2a$14$ajq8Q7fbtFRQvXpdCq7Jcuy.Rx1h/L4J60Otx.gyNLbAYctGMJ9tK`. For md5crypt, sha256crypt and sha512crypt we support the format used in `/etc/shadow` with the `$1$`, `$5$` and `$6$` prefix, this is useful if you are migrating from Unix system user accounts. We support Apache md5crypt (`$apr1$` prefix) too. Using the REST API you can send a password hashed as argon2id, bcrypt, pbkdf2, md5crypt, sha256crypt  or sha512crypt and it will be stored as is.
 
 If you want to use your existing accounts, you have these options:
 

+ 1 - 0
docs/full-configuration.md

@@ -502,6 +502,7 @@ Supported hash algorithms:
 - PBKDF2 sha256 with base64 salt, prefix `$pbkdf2-b64salt-sha256$`
 - MD5 crypt, prefix `$1$`
 - MD5 crypt APR1, prefix `$apr1$`
+- SHA256 crypt, prefix `$5$`
 - SHA512 crypt, prefix `$6$`
 - LDAP MD5, prefix `{MD5}`
 

+ 6 - 2
internal/dataprovider/dataprovider.go

@@ -51,6 +51,7 @@ import (
 	"github.com/GehirnInc/crypt"
 	"github.com/GehirnInc/crypt/apr1_crypt"
 	"github.com/GehirnInc/crypt/md5_crypt"
+	"github.com/GehirnInc/crypt/sha256_crypt"
 	"github.com/GehirnInc/crypt/sha512_crypt"
 	"github.com/alexedwards/argon2id"
 	"github.com/go-chi/render"
@@ -96,6 +97,7 @@ const (
 	pbkdf2SHA256B64SaltPrefix = "$pbkdf2-b64salt-sha256$"
 	md5cryptPwdPrefix         = "$1$"
 	md5cryptApr1PwdPrefix     = "$apr1$"
+	sha256cryptPwdPrefix      = "$5$"
 	sha512cryptPwdPrefix      = "$6$"
 	md5LDAPPwdPrefix          = "{MD5}"
 	trackQuotaDisabledError   = "please enable track_quota in your configuration to use this method"
@@ -163,10 +165,10 @@ var (
 	internalHashPwdPrefixes  = []string{argonPwdPrefix, bcryptPwdPrefix}
 	hashPwdPrefixes          = []string{argonPwdPrefix, bcryptPwdPrefix, pbkdf2SHA1Prefix, pbkdf2SHA256Prefix,
 		pbkdf2SHA512Prefix, pbkdf2SHA256B64SaltPrefix, md5cryptPwdPrefix, md5cryptApr1PwdPrefix, md5LDAPPwdPrefix,
-		sha512cryptPwdPrefix}
+		sha256cryptPwdPrefix, sha512cryptPwdPrefix}
 	pbkdfPwdPrefixes             = []string{pbkdf2SHA1Prefix, pbkdf2SHA256Prefix, pbkdf2SHA512Prefix, pbkdf2SHA256B64SaltPrefix}
 	pbkdfPwdB64SaltPrefixes      = []string{pbkdf2SHA256B64SaltPrefix}
-	unixPwdPrefixes              = []string{md5cryptPwdPrefix, md5cryptApr1PwdPrefix, sha512cryptPwdPrefix}
+	unixPwdPrefixes              = []string{md5cryptPwdPrefix, md5cryptApr1PwdPrefix, sha256cryptPwdPrefix, sha512cryptPwdPrefix}
 	sharedProviders              = []string{PGSQLDataProviderName, MySQLDataProviderName, CockroachDataProviderName}
 	logSender                    = "dataprovider"
 	sqlTableUsers                string
@@ -3067,6 +3069,8 @@ func compareUnixPasswordAndHash(user *User, password string) (bool, error) {
 	var crypter crypt.Crypter
 	if strings.HasPrefix(user.Password, sha512cryptPwdPrefix) {
 		crypter = sha512_crypt.New()
+	} else if strings.HasPrefix(user.Password, sha256cryptPwdPrefix) {
+		crypter = sha256_crypt.New()
 	} else if strings.HasPrefix(user.Password, md5cryptPwdPrefix) {
 		crypter = md5_crypt.New()
 	} else if strings.HasPrefix(user.Password, md5cryptApr1PwdPrefix) {

+ 1 - 0
internal/sftpd/sftpd_test.go

@@ -7231,6 +7231,7 @@ func TestHashedPasswords(t *testing.T) {
 	pwdMapping["$1$b5caebda$VODr/nyhGWgZaY8sJ4x05."] = plainPwd
 	pwdMapping["$2a$14$ajq8Q7fbtFRQvXpdCq7Jcuy.Rx1h/L4J60Otx.gyNLbAYctGMJ9tK"] = "secret"
 	pwdMapping["$6$459ead56b72e44bc$uog86fUxscjt28BZxqFBE2pp2QD8P/1e98MNF75Z9xJfQvOckZnQ/1YJqiq1XeytPuDieHZvDAMoP7352ELkO1"] = "secret"
+	pwdMapping["$5$h4Aalt0fJdGX8sgv$Rd2ew0fvgzUN.DzAVlKa9QL4q/DZWo4SsKpB9.3AyZ/"] = plainPwd
 	pwdMapping["$apr1$OBWLeSme$WoJbB736e7kKxMBIAqilb1"] = plainPwd
 	pwdMapping["{MD5}5f4dcc3b5aa765d61d8327deb882cf99"] = plainPwd