summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorDavid Sommerseth <dazo@users.sourceforge.net>2009-03-28 19:16:29 +0100
committerDavid Sommerseth <dazo@users.sourceforge.net>2009-03-28 19:16:29 +0100
commitadd06f4a6033f517b6147a12be703b049ae7338a (patch)
tree94792134b7838273bf0fcf47b474ab57106d6150 /common
parentb1d3a7b2621374d23ef8be5cb79d06fb3a18e3dc (diff)
downloadeurephia-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')
-rw-r--r--common/passwd.c46
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);
}