From e5ccdb44491e05aaa8e4c86f9324a00640276bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Michaud?= Date: Sun, 3 May 2020 06:06:09 +0200 Subject: [PATCH] [MISC] Introduce CryptAlgo type. (#960) * [MISC] Introduce CryptAlgo type. It helps distinguish between the configuration representation of an algorithm and the crypt representation (6 and argon2id vs sha512 vs argon2id). * Add a description to CryptAlgo. * use const Co-authored-by: James Elliott --- internal/authentication/const.go | 7 +++++-- internal/authentication/file_user_provider.go | 8 ++++---- internal/authentication/password_hash.go | 9 +++++---- internal/commands/hash.go | 2 +- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/internal/authentication/const.go b/internal/authentication/const.go index 6133ddd3..a939ab25 100644 --- a/internal/authentication/const.go +++ b/internal/authentication/const.go @@ -24,11 +24,14 @@ const ( // PossibleMethods is the set of all possible 2FA methods. var PossibleMethods = []string{TOTP, U2F, Push} +// CryptAlgo the crypt representation of an algorithm used in the prefix of the hash. +type CryptAlgo string + const ( // HashingAlgorithmArgon2id Argon2id hash identifier. - HashingAlgorithmArgon2id = "argon2id" + HashingAlgorithmArgon2id CryptAlgo = "argon2id" // HashingAlgorithmSHA512 SHA512 hash identifier. - HashingAlgorithmSHA512 = "6" + HashingAlgorithmSHA512 CryptAlgo = "6" ) // These are the default values from the upstream crypt module we use them to for GetInt diff --git a/internal/authentication/file_user_provider.go b/internal/authentication/file_user_provider.go index 5d442ee5..180854c8 100644 --- a/internal/authentication/file_user_provider.go +++ b/internal/authentication/file_user_provider.go @@ -51,14 +51,14 @@ func NewFileUserProvider(configuration *schema.FileAuthenticationBackendConfigur panic(err.Error()) } + var cryptAlgo CryptAlgo = HashingAlgorithmArgon2id // TODO: Remove this. This is only here to temporarily fix the username enumeration security flaw in #949. // This generates a hash that should be usable to do a fake CheckUserPassword - algorithm := configuration.Password.Algorithm if configuration.Password.Algorithm == sha512 { - algorithm = HashingAlgorithmSHA512 + cryptAlgo = HashingAlgorithmSHA512 } settings := getCryptSettings(utils.RandomString(configuration.Password.SaltLength, HashingPossibleSaltCharacters), - algorithm, configuration.Password.Iterations, configuration.Password.Memory*1024, configuration.Password.Parallelism, + cryptAlgo, configuration.Password.Iterations, configuration.Password.Memory*1024, configuration.Password.Parallelism, configuration.Password.KeyLength) data := crypt.Base64Encoding.EncodeToString([]byte(utils.RandomString(configuration.Password.KeyLength, HashingPossibleSaltCharacters))) fakeHash := fmt.Sprintf("%s$%s", settings, data) @@ -140,7 +140,7 @@ func (p *FileUserProvider) UpdatePassword(username string, newPassword string) e return fmt.Errorf("User '%s' does not exist in database", username) } - var algorithm string + var algorithm CryptAlgo if p.configuration.Password.Algorithm == "argon2id" { algorithm = HashingAlgorithmArgon2id } else if p.configuration.Password.Algorithm == sha512 { diff --git a/internal/authentication/password_hash.go b/internal/authentication/password_hash.go index 91f221fd..9586147f 100644 --- a/internal/authentication/password_hash.go +++ b/internal/authentication/password_hash.go @@ -14,7 +14,7 @@ import ( // PasswordHash represents all characteristics of a password hash. // Authelia only supports salted SHA512 or salted argon2id method, i.e., $6$ mode or $argon2id$ mode. type PasswordHash struct { - Algorithm string + Algorithm CryptAlgo Iterations int Salt string Key string @@ -28,7 +28,8 @@ func ParseHash(hash string) (passwordHash *PasswordHash, err error) { parts := strings.Split(hash, "$") // This error can be ignored as it's always nil. - code, parameters, salt, key, _ := crypt.DecodeSettings(hash) + c, parameters, salt, key, _ := crypt.DecodeSettings(hash) + code := CryptAlgo(c) h := &PasswordHash{} h.Salt = salt @@ -83,7 +84,7 @@ func ParseHash(hash string) (passwordHash *PasswordHash, err error) { // HashPassword generate a salt and hash the password with the salt and a constant number of rounds. //nolint:gocyclo // TODO: Consider refactoring/simplifying, time permitting. -func HashPassword(password, salt, algorithm string, iterations, memory, parallelism, keyLength, saltLength int) (hash string, err error) { +func HashPassword(password, salt string, algorithm CryptAlgo, iterations, memory, parallelism, keyLength, saltLength int) (hash string, err error) { var settings string if algorithm != HashingAlgorithmArgon2id && algorithm != HashingAlgorithmSHA512 { @@ -147,7 +148,7 @@ func CheckPassword(password, hash string) (ok bool, err error) { return hash == expectedHash, nil } -func getCryptSettings(salt, algorithm string, iterations, memory, parallelism, keyLength int) (settings string) { +func getCryptSettings(salt string, algorithm CryptAlgo, iterations, memory, parallelism, keyLength int) (settings string) { if algorithm == HashingAlgorithmArgon2id { settings, _ = crypt.Argon2idSettings(memory, iterations, parallelism, keyLength, salt) } else if algorithm == HashingAlgorithmSHA512 { diff --git a/internal/commands/hash.go b/internal/commands/hash.go index 0488f43e..a8bfab76 100644 --- a/internal/commands/hash.go +++ b/internal/commands/hash.go @@ -34,7 +34,7 @@ var HashPasswordCmd = &cobra.Command{ var err error var hash string - var algorithm string + var algorithm authentication.CryptAlgo if sha512 { if iterations == schema.DefaultPasswordConfiguration.Iterations {