diff options
author | Tom Smeding <tom.smeding@gmail.com> | 2020-06-20 21:14:26 +0200 |
---|---|---|
committer | Tom Smeding <tom.smeding@gmail.com> | 2020-06-20 21:14:41 +0200 |
commit | 2675fac7fe07783d3266b59f6e1c0e0a337a84db (patch) | |
tree | 4e73285bc4972f0aeccb772ae512b2901f10bee1 /db.c | |
parent | f45959b53b8322a852554aa8dd7f8c9f4f99b5b4 (diff) |
server: User password hashing (libsodium Argon2id(3,64MB))
Diffstat (limited to 'db.c')
-rw-r--r-- | db.c | 84 |
1 files changed, 72 insertions, 12 deletions
@@ -3,6 +3,7 @@ #include <string.h> #include <assert.h> #include <sqlite3.h> +#include <sodium.h> #include "db.h" #include "schema.sql.h" @@ -10,6 +11,8 @@ #define SQLITE(func,...) do{if(sqlite3_##func(__VA_ARGS__)!=SQLITE_OK){die_sqlite("sqlite3_" #func);}}while(0) #define DATABASE_VERSION 1 +#define PASSHASH_OPSLIMIT 3 +#define PASSHASH_MEMLIMIT crypto_pwhash_MEMLIMIT_INTERACTIVE sqlite3 *database=NULL; @@ -19,6 +22,24 @@ static void die_sqlite(const char *func){ die("%s: %s",func,sqlite3_errmsg(database)); } +struct hashed_password { + char str[crypto_pwhash_STRBYTES + 1]; + int length; // -1 if hashing failed +}; + +static struct hashed_password hash_password(const char *pass) { + struct hashed_password result; + int ret = crypto_pwhash_str( + result.str, pass, strlen(pass), + PASSHASH_OPSLIMIT, PASSHASH_MEMLIMIT); + if (ret != 0) { + result.length = -1; + } else { + result.length = crypto_pwhash_STRBYTES; + } + return result; +} + void db_init(void){ SQLITE(config,SQLITE_CONFIG_SERIALIZED); @@ -210,10 +231,13 @@ struct db_room_list db_list_rooms(i64 userid){ i64 db_create_user(const char *name,const char *pass){ + struct hashed_password passhash = hash_password(pass); + if (passhash.length == -1) return -1; + sqlite3_stmt *stmt; - SQLITE(prepare_v2,database,"insert into Users (name, pass) values (?, ?)",-1,&stmt,NULL); + SQLITE(prepare_v2,database,"insert into Users (name, passhash) values (?, ?)",-1,&stmt,NULL); SQLITE(bind_text,stmt,1,name,-1,SQLITE_STATIC); - SQLITE(bind_text,stmt,2,pass,-1,SQLITE_STATIC); + SQLITE(bind_text,stmt,2,passhash.str,passhash.length,SQLITE_STATIC); bool success=sqlite3_step(stmt)==SQLITE_DONE; SQLITE(finalize,stmt); if(success){ @@ -223,6 +247,29 @@ i64 db_create_user(const char *name,const char *pass){ } } +bool db_set_username(i64 userid, const char *name) { + sqlite3_stmt *stmt; + SQLITE(prepare_v2, database, "update USERS set name = ? where id = ?", -1, &stmt, NULL); + SQLITE(bind_text, stmt, 1, name, -1, SQLITE_STATIC); + SQLITE(bind_int64, stmt, 2, userid); + bool success = sqlite3_step(stmt) == SQLITE_DONE; + SQLITE(finalize, stmt); + return success; +} + +bool db_set_pass(i64 userid, const char *pass) { + struct hashed_password passhash = hash_password(pass); + if (passhash.length == -1) return false; + + sqlite3_stmt *stmt; + SQLITE(prepare_v2, database, "update USERS set passhash = ? where id = ?", -1, &stmt, NULL); + SQLITE(bind_text, stmt, 1, passhash.str, passhash.length, SQLITE_STATIC); + SQLITE(bind_int64, stmt, 2, userid); + bool success = sqlite3_step(stmt) == SQLITE_DONE; + SQLITE(finalize, stmt); + return success; +} + char* db_get_username(i64 userid){ sqlite3_stmt *stmt; SQLITE(prepare_v2,database,"select name from Users where id = ?",-1,&stmt,NULL); @@ -237,18 +284,31 @@ char* db_get_username(i64 userid){ return name; } -char* db_get_pass(i64 userid){ +bool db_check_pass(i64 userid, const char *pass) { sqlite3_stmt *stmt; - SQLITE(prepare_v2,database,"select pass from Users where id = ?",-1,&stmt,NULL); - SQLITE(bind_int64,stmt,1,userid); - const unsigned char *pass_sq=NULL; - if(sqlite3_step(stmt)==SQLITE_ROW){ - pass_sq=sqlite3_column_text(stmt,0); + SQLITE(prepare_v2, database, "select passhash from Users where id = ?", -1, &stmt, NULL); + SQLITE(bind_int64, stmt, 1, userid); + + const unsigned char *passhash_sq = NULL; + if (sqlite3_step(stmt) == SQLITE_ROW) { + passhash_sq = sqlite3_column_text(stmt, 0); } - char *pass=NULL; - if(pass_sq)pass=strdup((const char*)pass_sq); - SQLITE(finalize,stmt); - return pass; + + int ret = crypto_pwhash_str_verify((const char*)passhash_sq, pass, strlen(pass)); + bool success = ret == 0; + bool rehash = success && + crypto_pwhash_str_needs_rehash( + (const char*)passhash_sq, PASSHASH_OPSLIMIT, PASSHASH_MEMLIMIT); + + SQLITE(finalize, stmt); + + if (rehash) { + fprintf(stderr, "Rehashing password for userid=%" PRIi64 "\n", userid); + // Ignore whether this succeeds; if it doesn't, we continue using the old hash + db_set_pass(userid, pass); + } + + return success; } i64 db_find_user(const char *name){ |