diff options
author | David Sommerseth <dazo@users.sourceforge.net> | 2009-03-28 19:16:29 +0100 |
---|---|---|
committer | David Sommerseth <dazo@users.sourceforge.net> | 2009-03-28 19:16:29 +0100 |
commit | add06f4a6033f517b6147a12be703b049ae7338a (patch) | |
tree | 94792134b7838273bf0fcf47b474ab57106d6150 /common/passwd.c | |
parent | b1d3a7b2621374d23ef8be5cb79d06fb3a18e3dc (diff) | |
download | eurephia-add06f4a6033f517b6147a12be703b049ae7338a.tar.gz eurephia-add06f4a6033f517b6147a12be703b049ae7338a.tar.xz eurephia-add06f4a6033f517b6147a12be703b049ae7338a.zip |
Fixed a "hang" when wrong password was used
Due to the current implementation of SHA512 salts, it could be
experienced as if the application hung on wrong passwords. This is
because the rounds count for the passwords are scrambled, with values
based on the given password. When a wrong password is given, this will
also result in getting a wrong salt length and hash rounds for the
following hash calculation.
Due to this, the extracted rounds value from the salt string could
return some really high number of rounds on wrong
passwords (possibly the max value if integer). And this is why the
"hang" is experienced.
To avoid this, a check is added to make sure the rounds is not
unreasonably much higher than the configured max rounds values. If the
descrambled rounds number from the salt exceeds max rounds * 1.5, the
password (most probaly) is wrong. In this case we do a sleep() to slow
down bruteforce attacks and return NULL.
The drawback is if the maxrounds later on is changed to a value which
hits this scenario:
passwordsalt_rounds > maxrounds_cfg * 1.5
In this case these old passwords will be invalidated by that
configuration change. This is considered to be a feature and not a bug.
The reason for mulitiplying by 1.5, is to allow a little room for a
degrading the max rounds setting. By adjusting the max rounds up again,
these passwords will be valid again.
Added also a sleep() when wrong username is attempted.
Diffstat (limited to 'common/passwd.c')
-rw-r--r-- | common/passwd.c | 46 |
1 files changed, 36 insertions, 10 deletions
diff --git a/common/passwd.c b/common/passwd.c index 1fb14de..276a4a3 100644 --- a/common/passwd.c +++ b/common/passwd.c @@ -42,6 +42,7 @@ #include <sys/types.h> #include <assert.h> #include <time.h> +#include <unistd.h> #include "eurephia_nullsafe.h" #include "eurephia_context.h" @@ -125,7 +126,8 @@ int gen_randsaltstr(eurephiaCTX *ctx, char *saltstr, int len) { return 1; } -static char *sha512_crypt_r (const char *key, const char *salt, char *buffer, int buflen) { +static char *sha512_crypt_r(const char *key, const char *salt, size_t maxrounds_cfg, char *buffer, int buflen) +{ unsigned char alt_result[64] __attribute__ ((__aligned__ (__alignof__ (uint64_t)))); unsigned char temp_result[64] @@ -149,6 +151,25 @@ static char *sha512_crypt_r (const char *key, const char *salt, char *buffer, in rounds = MAX(ROUNDS_MIN, MIN(((saltinfo & 0xffffff00) >> 8), ROUNDS_MAX)); key_len = strlen (key); + // If the decoded rounds value from the salt is bigger than the + // the maximum configured rounds * 1.5, then the password is definitely wrong. + // + // The drawback is if the maxrounds later on is changed to a value which is: + // passwordsalt_rounds > maxrounds_cfg * 1.5 + // these passwords will be invalidated by that change. This is considered + // to be a feature and not a bug. The reason for mulitiplying by 1.5, is to + // allow a little room for a degrading max rounds. + // + // Without this fix, a wrong password might take several seconds or minutes to + // calculate. This behaviour is not wanted as that wastes CPU cycles on something + // we know is wrong. But to avoid quiting too quickly and to slow down + // bruteforce attacks directly on eurephia, we add 1 seconds sleep. + // + if( rounds > (maxrounds_cfg * 1.5) ) { + sleep(1); + return NULL; + } + //printf("%-8.8s == (%ld, %i) [%02x, %06x]\n", // salt, (long int)rounds, (int)salt_len, (int)rounds, (int)salt_len); @@ -362,6 +383,7 @@ char *eurephia_pwd_crypt(eurephiaCTX *ctx, const char *key, const char *salt) { int buflen = (MAX_SALT_LEN + 20 + 1 + 86 + 1); char saltinfo[20], saltstr[MAX_SALT_LEN+22]; // saltstr will also contain saltinfo int saltlen = 0; + static size_t maxrounds = 0; static int srand_init = 0; assert( (ctx != NULL) && (ctx->dbc != NULL) ); @@ -375,12 +397,18 @@ char *eurephia_pwd_crypt(eurephiaCTX *ctx, const char *key, const char *salt) { assert(buffer != NULL); memset(buffer, 0, buflen); + // Get default max rounds for hashing + if( maxrounds == 0 ) { + maxrounds = defaultIntValue(atoi_nullsafe(eGet_value(ctx->dbc->config, "passwordhash_rounds_max")), + ROUNDS_DEFAULT_MAX); + } + if( salt == NULL ) { // If we do not have salt, create salt info char tmp[saltlen+2]; memset(&saltstr, 0, MAX_SALT_LEN+22); memset(&tmp, 0, saltlen+2); - int min = 0, max = 0, rounds = ROUNDS_DEFAULT_MAX, loop = 0; + int minrounds = 0, rounds = ROUNDS_DEFAULT_MAX, loop = 0; if( saltlen == 0 ) { @@ -390,17 +418,15 @@ char *eurephia_pwd_crypt(eurephiaCTX *ctx, const char *key, const char *salt) { DEFAULT_SALT_LEN); } - // Get default min/max rounds for hashing - min = defaultIntValue(atoi_nullsafe(eGet_value(ctx->dbc->config, "passwordhash_rounds_min")), + // Get default min rounds for hashing + minrounds = defaultIntValue(atoi_nullsafe(eGet_value(ctx->dbc->config, "passwordhash_rounds_min")), ROUNDS_DEFAULT_MIN); - max = defaultIntValue(atoi_nullsafe(eGet_value(ctx->dbc->config, "passwordhash_rounds_max")), - ROUNDS_DEFAULT_MAX); // Loop until we have a random number we'd like to use as our hashing rounds value do { - rounds = rand() % max; + rounds = rand() % maxrounds; loop++; - } while( ((rounds < min) || (rounds > max)) && (loop < 1000)) ; + } while( ((rounds < minrounds) || (rounds > maxrounds)) && (loop < 1000)) ; if( loop > 10000 ) { eurephia_log(ctx, LOG_FATAL, 0, @@ -423,7 +449,7 @@ char *eurephia_pwd_crypt(eurephiaCTX *ctx, const char *key, const char *salt) { // If we have a salt, use it snprintf(saltstr, MAX_SALT_LEN+20, "%s%c", salt, 0); } - result = sha512_crypt_r(key, saltstr, buffer, buflen); + result = sha512_crypt_r(key, saltstr, maxrounds, buffer, buflen); return result; } @@ -507,7 +533,7 @@ void benchmark_hashing(int rounds) { assert( buffer != NULL ); memset(buffer, 0, 1024); - pwdhash = sha512_crypt_r("benchmarkpassword", pwdsalt, buffer, 1024); + pwdhash = sha512_crypt_r("benchmarkpassword", pwdsalt, ROUNDS_MAX, buffer, 1024); free_nullsafe(buffer); } |