From c0c6d19be257daaeaf37c7b4bf783453b89937e6 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 12 Feb 2016 07:14:12 +0100 Subject: [PATCH] bcrypt hashes implementation, not activated yet. --- crypto | 2 +- src/kernel/faction.test.c | 10 ++-- src/util/password.c | 96 +++++++++++++++++++++++++-------------- src/util/password.test.c | 25 ++++++---- 4 files changed, 83 insertions(+), 50 deletions(-) diff --git a/crypto b/crypto index e0f9891a9..7101b264c 160000 --- a/crypto +++ b/crypto @@ -1 +1 @@ -Subproject commit e0f9891a91d69c042f82c1e13e48ab4c7160381d +Subproject commit 7101b264c8150c513d454421b1b263345ff90f66 diff --git a/src/kernel/faction.test.c b/src/kernel/faction.test.c index 678aaa068..c5a1236b3 100644 --- a/src/kernel/faction.test.c +++ b/src/kernel/faction.test.c @@ -108,12 +108,12 @@ static void test_addfaction(CuTest *tc) { CuAssertPtrEquals(tc, NULL, (void *)f->ursprung); CuAssertPtrEquals(tc, (void *)factions, (void *)f); CuAssertStrEquals(tc, "test@eressea.de", f->email); - CuAssertIntEquals(tc, true, checkpasswd(f, "hurrdurr")); + CuAssertTrue(tc, checkpasswd(f, "hurrdurr")); CuAssertPtrEquals(tc, (void *)lang, (void *)f->locale); CuAssertIntEquals(tc, 1234, f->subscription); CuAssertIntEquals(tc, 0, f->flags); CuAssertIntEquals(tc, 0, f->age); - CuAssertIntEquals(tc, true, faction_alive(f)); + CuAssertTrue(tc, faction_alive(f)); CuAssertIntEquals(tc, M_GRAY, f->magiegebiet); CuAssertIntEquals(tc, turn, f->lastorders); CuAssertPtrEquals(tc, f, findfaction(f->no)); @@ -125,9 +125,9 @@ static void test_check_passwd(CuTest *tc) { f = test_create_faction(0); faction_setpassword(f, password_hash("password", 0, PASSWORD_DEFAULT)); - CuAssertIntEquals(tc, true, checkpasswd(f, "password")); - CuAssertIntEquals(tc, false, checkpasswd(f, "assword")); - CuAssertIntEquals(tc, false, checkpasswd(f, "PASSWORD")); + CuAssertTrue(tc, checkpasswd(f, "password")); + CuAssertTrue(tc, !checkpasswd(f, "assword")); + CuAssertTrue(tc, !checkpasswd(f, "PASSWORD")); } static void test_get_monsters(CuTest *tc) { diff --git a/src/util/password.c b/src/util/password.c index 271cedf6d..1b6a52cdf 100644 --- a/src/util/password.c +++ b/src/util/password.c @@ -2,6 +2,8 @@ #include "password.h" #include +#include +#include #include #include @@ -25,37 +27,68 @@ } while (0) -char *password_gensalt(void) { - static char salt[SALTLEN + 1]; +char *password_gensalt(char *salt, size_t salt_len) { + size_t buflen = salt_len-1; char *cp = salt; - int buflen = SALTLEN; while (buflen) { unsigned long ul = genrand_int32() & (unsigned long)time(0); b64_from_24bit((char)(ul & 0xFF), (char)((ul>>8)&0xff), (char)((ul>>16)&0xFF), 4); } - salt[SALTLEN] = 0; + salt[salt_len-1] = 0; return salt; } -static const char * password_hash_i(const char * passwd, const char *salt, int algo, char *result, size_t len) { - assert(passwd); - if (!salt) { - salt = password_gensalt(); - } - if (algo==PASSWORD_PLAIN) { - _snprintf(result, len, "$0$%s$%s", salt, passwd); - } - else if (algo == PASSWORD_MD5) { - return md5_crypt_r(passwd, salt, result, len); - } - else if (algo == PASSWORD_APACHE_MD5) { - apr_md5_encode(passwd, salt, result, len); +static bool password_is_implemented(int algo) { + return algo == PASSWORD_BCRYPT || algo == PASSWORD_PLAIN || algo == PASSWORD_MD5 || algo == PASSWORD_APACHE_MD5; +} + +static const char * password_hash_i(const char * passwd, const char *input, int algo, char *result, size_t len) { + if (algo == PASSWORD_BCRYPT) { + char salt[MAXSALTLEN]; + char setting[40]; + if (!input) { + input = password_gensalt(salt, MAXSALTLEN); + } + if (_crypt_gensalt_blowfish_rn("$2y$", 5, input, strlen(input), setting, sizeof(setting)) == NULL) { + return NULL; + } + if (_crypt_blowfish_rn(passwd, setting, result, len) == NULL) { + return NULL; + } return result; } - else { - return NULL; + else if (algo == PASSWORD_PLAIN) { + _snprintf(result, len, "$0$%s", passwd); + return result; } - return result; + else if (password_is_implemented(algo)) { + char salt[MAXSALTLEN]; + assert(passwd); + if (input) { + const char * dol = strchr(input, '$'); + size_t salt_len; + if (dol) { + assert(dol > input && dol[0] == '$'); + salt_len = dol - input; + } + else { + salt_len = strlen(input); + } + assert(salt_len < MAXSALTLEN); + stpncpy(salt, input, salt_len); + salt[salt_len] = 0; + } else { + input = password_gensalt(salt, sizeof(salt)); + } + if (algo == PASSWORD_MD5) { + return md5_crypt_r(passwd, input, result, len); + } + else if (algo == PASSWORD_APACHE_MD5) { + apr_md5_encode(passwd, input, result, len); + return result; + } + } + return NULL; } const char * password_hash(const char * passwd, const char * salt, int algo) { @@ -64,31 +97,24 @@ const char * password_hash(const char * passwd, const char * salt, int algo) { return password_hash_i(passwd, salt, algo, result, sizeof(result)); } -static bool password_is_implemented(int algo) { - return algo==PASSWORD_PLAIN || algo==PASSWORD_MD5 || algo==PASSWORD_APACHE_MD5; -} - int password_verify(const char * pwhash, const char * passwd) { - char salt[MAXSALTLEN+1]; char hash[64]; - size_t len; int algo; char *pos; - const char *dol, *result; + const char *result; assert(passwd); assert(pwhash); assert(pwhash[0] == '$'); algo = pwhash[1]; + if (algo == PASSWORD_BCRYPT) { + char sample[200]; + _crypt_blowfish_rn(passwd, pwhash, sample, sizeof(sample)); + return (strcmp(sample, pwhash) == 0) ? VERIFY_OK : VERIFY_FAIL; + } pos = strchr(pwhash+2, '$'); assert(pos && pos[0] == '$'); - ++pos; - dol = strchr(pos, '$'); - assert(dol>pos && dol[0] == '$'); - len = dol - pos; - assert(len <= MAXSALTLEN); - strncpy(salt, pos, len); - salt[len] = 0; - result = password_hash_i(passwd, salt, algo, hash, sizeof(hash)); + pos = strchr(pos, '$')+1; + result = password_hash_i(passwd, pos, algo, hash, sizeof(hash)); if (!password_is_implemented(algo)) { return VERIFY_UNKNOWN; } diff --git a/src/util/password.test.c b/src/util/password.test.c index b4f4005da..cb3838774 100644 --- a/src/util/password.test.c +++ b/src/util/password.test.c @@ -3,24 +3,31 @@ #include "password.h" static void test_passwords(CuTest *tc) { - const char *hash; + const char *hash, *expect; + CuAssertIntEquals(tc, VERIFY_UNKNOWN, password_verify("$9$password", "password")); + + expect = "$apr1$FqQLkl8g$.icQqaDJpim4BVy.Ho5660"; + CuAssertIntEquals(tc, VERIFY_OK, password_verify(expect, "Hodor")); hash = password_hash("Hodor", "FqQLkl8g", PASSWORD_APACHE_MD5); CuAssertPtrNotNull(tc, hash); - CuAssertStrEquals(tc, "$apr1$FqQLkl8g$.icQqaDJpim4BVy.Ho5660", hash); - CuAssertIntEquals(tc, VERIFY_OK, password_verify(hash, "Hodor")); + CuAssertStrEquals(tc, expect, hash); + expect = "$1$ZouUn04i$yNnT1Oy8azJ5V.UM9ppP5/"; + CuAssertIntEquals(tc, VERIFY_OK, password_verify(expect, "jollygood")); hash = password_hash("jollygood", "ZouUn04i", PASSWORD_MD5); CuAssertPtrNotNull(tc, hash); - CuAssertStrEquals(tc, "$1$ZouUn04i$yNnT1Oy8azJ5V.UM9ppP5/", hash); - CuAssertIntEquals(tc, VERIFY_OK, password_verify(hash, "jollygood")); + CuAssertStrEquals(tc, expect, hash); + expect = "$0$password"; + CuAssertIntEquals(tc, VERIFY_OK, password_verify(expect, "password")); + CuAssertIntEquals(tc, VERIFY_FAIL, password_verify(expect, "arseword")); hash = password_hash("password", "hodor", PASSWORD_PLAIN); CuAssertPtrNotNull(tc, hash); - CuAssertStrEquals(tc, "$0$hodor$password", hash); - CuAssertIntEquals(tc, VERIFY_OK, password_verify(hash, "password")); - CuAssertIntEquals(tc, VERIFY_FAIL, password_verify(hash, "arseword")); - CuAssertIntEquals(tc, VERIFY_UNKNOWN, password_verify("$9$saltyfish$password", "password")); + CuAssertStrEquals(tc, expect, hash); + + expect = "$2y$05$RJ8qAhu.foXyJLdc2eHTLOaK4MDYn3/v4HtOVCq0Plv2yxcrEB7Wm"; + CuAssertIntEquals(tc, VERIFY_OK, password_verify(expect, "Hodor")); } CuSuite *get_password_suite(void) {