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 | |
| parent | f45959b53b8322a852554aa8dd7f8c9f4f99b5b4 (diff) | |
server: User password hashing (libsodium Argon2id(3,64MB))
| -rw-r--r-- | command.c | 4 | ||||
| -rw-r--r-- | db.c | 84 | ||||
| -rw-r--r-- | db.h | 2 | ||||
| -rw-r--r-- | schema.sql | 2 | 
4 files changed, 75 insertions, 17 deletions
| @@ -50,9 +50,7 @@ static struct cmd_retval cmd_login(struct conn_data *data,const char *tag,const  			data->userid=-1;  		}  	} else { -		char *pass=db_get_pass(userid); -		bool success=strcmp(args[1],pass)==0; -		free(pass); +		bool success = db_check_pass(userid, args[1]);  		if(data->userid!=-1){  			userdata_unregister(data->userid,data->fd);  			broadcast_online_change(data->userid); @@ -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){ @@ -52,7 +52,7 @@ i64 db_create_user(const char *name,const char *pass);  bool db_set_username(i64 userid,const char *name);  bool db_set_pass(i64 userid,const char *pass);  char* db_get_username(i64 userid); -char* db_get_pass(i64 userid); +bool db_check_pass(i64 userid,const char *pass);  bool db_delete_user(i64 userid);  i64 db_find_user(const char *name);  // -1 if not found  struct db_strings_list db_user_tokens(i64 userid); @@ -21,7 +21,7 @@ create table Members (  create table Users (  	id integer primary key not null,  	name text not null, -	pass text not null +	passhash text not null  );  create unique index users_name_index on Users(name); | 
