From 73aa146b8470727f036f732d2c9c267048ee455b Mon Sep 17 00:00:00 2001 From: Andrew Pamment Date: Thu, 4 Aug 2016 21:41:37 +1000 Subject: [PATCH] EXPERIMENTAL Password Hashing --- Makefile.freebsd | 8 +- Makefile.linux | 8 +- Makefile.minix | 8 +- bbs.h | 1 + users.c | 165 ++++++++++++++++++++++---------- utils/mgpost/mgpost.c | 46 ++++----- utils/update_pass/Makefile | 15 +++ utils/update_pass/update_pass.c | 126 ++++++++++++++++++++++++ 8 files changed, 290 insertions(+), 87 deletions(-) create mode 100644 utils/update_pass/Makefile create mode 100644 utils/update_pass/update_pass.c diff --git a/Makefile.freebsd b/Makefile.freebsd index fea6795..2e7cb11 100644 --- a/Makefile.freebsd +++ b/Makefile.freebsd @@ -9,10 +9,10 @@ OBJ = inih/ini.o bbs.o main.o users.o main_menu.o mail_menu.o doors.o bbs_list.o %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) -magicka: $(OBJ) - $(CC) -o magicka -o $@ $^ $(CFLAGS) -L/usr/local/lib -lsqlite3 $(JAMLIB) $(ZMODEM) $(LUA) -lutil -lm - +magicka: $(OBJ) + $(CC) -o magicka -o $@ $^ $(CFLAGS) -L/usr/local/lib -lsqlite3 $(JAMLIB) $(ZMODEM) $(LUA) -lutil -lm -lssl -lcrypto + .PHONY: clean clean: - rm -f $(OBJ) magicka + rm -f $(OBJ) magicka diff --git a/Makefile.linux b/Makefile.linux index 0d808cf..ef09a42 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -9,10 +9,10 @@ OBJ = inih/ini.o bbs.o main.o users.o main_menu.o mail_menu.o doors.o bbs_list.o %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) -magicka: $(OBJ) - $(CC) -o magicka -o $@ $^ $(CFLAGS) -L/usr/local/lib -lsqlite3 $(JAMLIB) $(ZMODEM) $(LUA) -lutil -lm -ldl - +magicka: $(OBJ) + $(CC) -o magicka -o $@ $^ $(CFLAGS) -L/usr/local/lib -lsqlite3 $(JAMLIB) $(ZMODEM) $(LUA) -lutil -lm -ldl -lssl -lcrypto + .PHONY: clean clean: - rm -f $(OBJ) magicka + rm -f $(OBJ) magicka diff --git a/Makefile.minix b/Makefile.minix index 1cf8b03..f8459dc 100644 --- a/Makefile.minix +++ b/Makefile.minix @@ -9,10 +9,10 @@ OBJ = inih/ini.o bbs.o main.o users.o main_menu.o mail_menu.o doors.o bbs_list.o %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) -magicka: $(OBJ) - $(CC) -o magicka -o $@ $^ $(CFLAGS) -L/usr/pkg/lib -lsqlite3 $(JAMLIB) $(ZMODEM) $(LUA) -lutil -lm - +magicka: $(OBJ) + $(CC) -o magicka -o $@ $^ $(CFLAGS) -L/usr/pkg/lib -lsqlite3 $(JAMLIB) $(ZMODEM) $(LUA) -lutil -lm -lssl -lcrypto + .PHONY: clean clean: - rm -f $(OBJ) magicka + rm -f $(OBJ) magicka diff --git a/bbs.h b/bbs.h index 4cb7b28..8895ac9 100644 --- a/bbs.h +++ b/bbs.h @@ -120,6 +120,7 @@ struct user_record { int id; char *loginname; char *password; + char *salt; char *firstname; char *lastname; char *email; diff --git a/users.c b/users.c index 3e5c903..6f08d4c 100644 --- a/users.c +++ b/users.c @@ -3,11 +3,64 @@ #include #include #include +#include #include "bbs.h" #include "inih/ini.h" extern struct bbs_config conf; +char *hash_sha256(char *pass, char *salt) { + char *buffer = (char *)malloc(strlen(pass) + strlen(salt) + 1); + char *shash = (char *)malloc(66); + unsigned char hash[SHA256_DIGEST_LENGTH]; + + if (!buffer) { + dolog("Out of memory!"); + exit(-1); + } + + sprintf(buffer, "%s%s", pass, salt); + + + SHA256_CTX sha256; + SHA256_Init(&sha256); + SHA256_Update(&sha256, buffer, strlen(buffer)); + SHA256_Final(hash, &sha256); + int i = 0; + for(i = 0; i < SHA256_DIGEST_LENGTH; i++) { + sprintf(shash + (i * 2), "%02x", hash[i]); + } + shash[64] = 0; + + free(buffer); + return shash; +} + +void gen_salt(char **s) { + FILE *fptr; + int i; + char c; + *s = (char *)malloc(11); + + char *salt = *s; + + if (!salt) { + dolog("Out of memory.."); + exit(-1); + } + fptr = fopen("/dev/urandom", "rb"); + if (!fptr) { + dolog("Unable to open /dev/urandom!"); + exit(-1); + } + for (i=0;i<10;i++) { + fread(&c, 1, 1, fptr); + salt[i] = (char)((abs(c) % 93) + 33); + } + fclose(fptr); + salt[10] = '\0'; +} + static int secLevel(void* user, const char* section, const char* name, const char* value) { @@ -27,7 +80,7 @@ int save_user(struct user_record *user) { sqlite3_stmt *res; int rc; - char *update_sql = "UPDATE users SET password=?, firstname=?," + char *update_sql = "UPDATE users SET password=?, salt=?, firstname=?," "lastname=?, email=?, location=?, sec_level=?, last_on=?, time_left=?, cur_mail_conf=?, cur_mail_area=?, cur_file_dir=?, cur_file_sub=?, times_on=? where loginname LIKE ?"; char *err_msg = 0; @@ -46,19 +99,20 @@ int save_user(struct user_record *user) { if (rc == SQLITE_OK) { sqlite3_bind_text(res, 1, user->password, -1, 0); - sqlite3_bind_text(res, 2, user->firstname, -1, 0); - sqlite3_bind_text(res, 3, user->lastname, -1, 0); - sqlite3_bind_text(res, 4, user->email, -1, 0); - sqlite3_bind_text(res, 5, user->location, -1, 0); - sqlite3_bind_int(res, 6, user->sec_level); - sqlite3_bind_int(res, 7, user->laston); - sqlite3_bind_int(res, 8, user->timeleft); - sqlite3_bind_int(res, 9, user->cur_mail_conf); - sqlite3_bind_int(res, 10, user->cur_mail_area); - sqlite3_bind_int(res, 11, user->cur_file_dir); - sqlite3_bind_int(res, 12, user->cur_file_sub); - sqlite3_bind_int(res, 13, user->timeson); - sqlite3_bind_text(res, 14, user->loginname, -1, 0); + sqlite3_bind_text(res, 2, user->salt, -1, 0); + sqlite3_bind_text(res, 3, user->firstname, -1, 0); + sqlite3_bind_text(res, 4, user->lastname, -1, 0); + sqlite3_bind_text(res, 5, user->email, -1, 0); + sqlite3_bind_text(res, 6, user->location, -1, 0); + sqlite3_bind_int(res, 7, user->sec_level); + sqlite3_bind_int(res, 8, user->laston); + sqlite3_bind_int(res, 9, user->timeleft); + sqlite3_bind_int(res, 10, user->cur_mail_conf); + sqlite3_bind_int(res, 11, user->cur_mail_area); + sqlite3_bind_int(res, 12, user->cur_file_dir); + sqlite3_bind_int(res, 13, user->cur_file_sub); + sqlite3_bind_int(res, 14, user->timeson); + sqlite3_bind_text(res, 15, user->loginname, -1, 0); } else { dolog("Failed to execute statement: %s", sqlite3_errmsg(db)); } @@ -86,6 +140,7 @@ int inst_user(struct user_record *user) { "Id INTEGER PRIMARY KEY," "loginname TEXT COLLATE NOCASE," "password TEXT," + "salt TEXT," "firstname TEXT," "lastname TEXT," "email TEXT," @@ -99,8 +154,8 @@ int inst_user(struct user_record *user) { "cur_file_dir INTEGER," "times_on INTEGER);"; - char *insert_sql = "INSERT INTO users (loginname, password, firstname," - "lastname, email, location, sec_level, last_on, time_left, cur_mail_conf, cur_mail_area, cur_file_dir, cur_file_sub, times_on) VALUES(?,?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + char *insert_sql = "INSERT INTO users (loginname, password, salt, firstname," + "lastname, email, location, sec_level, last_on, time_left, cur_mail_conf, cur_mail_area, cur_file_dir, cur_file_sub, times_on) VALUES(?,?, ?,?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; char *err_msg = 0; sprintf(buffer, "%s/users.sq3", conf.bbs_path); @@ -130,18 +185,19 @@ int inst_user(struct user_record *user) { if (rc == SQLITE_OK) { sqlite3_bind_text(res, 1, user->loginname, -1, 0); sqlite3_bind_text(res, 2, user->password, -1, 0); - sqlite3_bind_text(res, 3, user->firstname, -1, 0); - sqlite3_bind_text(res, 4, user->lastname, -1, 0); - sqlite3_bind_text(res, 5, user->email, -1, 0); - sqlite3_bind_text(res, 6, user->location, -1, 0); - sqlite3_bind_int(res, 7, user->sec_level); - sqlite3_bind_int(res, 8, user->laston); - sqlite3_bind_int(res, 9, user->timeleft); - sqlite3_bind_int(res, 10, user->cur_mail_conf); - sqlite3_bind_int(res, 11, user->cur_mail_area); - sqlite3_bind_int(res, 12, user->cur_file_dir); - sqlite3_bind_int(res, 13, user->cur_file_sub); - sqlite3_bind_int(res, 14, user->timeson); + sqlite3_bind_text(res, 3, user->salt, -1, 0); + sqlite3_bind_text(res, 4, user->firstname, -1, 0); + sqlite3_bind_text(res, 5, user->lastname, -1, 0); + sqlite3_bind_text(res, 6, user->email, -1, 0); + sqlite3_bind_text(res, 7, user->location, -1, 0); + sqlite3_bind_int(res, 8, user->sec_level); + sqlite3_bind_int(res, 9, user->laston); + sqlite3_bind_int(res, 10, user->timeleft); + sqlite3_bind_int(res, 11, user->cur_mail_conf); + sqlite3_bind_int(res, 12, user->cur_mail_area); + sqlite3_bind_int(res, 13, user->cur_file_dir); + sqlite3_bind_int(res, 14, user->cur_file_sub); + sqlite3_bind_int(res, 15, user->timeson); } else { dolog("Failed to execute statement: %s", sqlite3_errmsg(db)); @@ -151,10 +207,9 @@ int inst_user(struct user_record *user) { rc = sqlite3_step(res); if (rc != SQLITE_DONE) { - dolog("execution failed: %s", sqlite3_errmsg(db)); - sqlite3_close(db); - exit(1); + sqlite3_close(db); + exit(1); } user->id = sqlite3_last_insert_rowid(db); @@ -168,9 +223,10 @@ struct user_record *check_user_pass(int socket, char *loginname, char *password) struct user_record *user; char buffer[256]; sqlite3 *db; - sqlite3_stmt *res; - int rc; - char *sql = "SELECT * FROM users WHERE loginname LIKE ?"; + sqlite3_stmt *res; + int rc; + char *sql = "SELECT * FROM users WHERE loginname LIKE ?"; + char *pass_hash; sprintf(buffer, "%s/users.sq3", conf.bbs_path); @@ -199,31 +255,37 @@ struct user_record *check_user_pass(int socket, char *loginname, char *password) user->id = sqlite3_column_int(res, 0); user->loginname = strdup((char *)sqlite3_column_text(res, 1)); user->password = strdup((char *)sqlite3_column_text(res, 2)); - user->firstname = strdup((char *)sqlite3_column_text(res, 3)); - user->lastname = strdup((char *)sqlite3_column_text(res, 4)); - user->email = strdup((char *)sqlite3_column_text(res, 5)); - user->location = strdup((char *)sqlite3_column_text(res, 6)); - user->sec_level = sqlite3_column_int(res, 7); - user->laston = (time_t)sqlite3_column_int(res, 8); - user->timeleft = sqlite3_column_int(res, 9); - user->cur_mail_conf = sqlite3_column_int(res, 10); - user->cur_mail_area = sqlite3_column_int(res, 11); - user->cur_file_dir = sqlite3_column_int(res, 13); - user->cur_file_sub = sqlite3_column_int(res, 12); - user->timeson = sqlite3_column_int(res, 14); + user->salt = strdup((char *)sqlite3_column_text(res, 3)); + user->firstname = strdup((char *)sqlite3_column_text(res, 4)); + user->lastname = strdup((char *)sqlite3_column_text(res, 5)); + user->email = strdup((char *)sqlite3_column_text(res, 6)); + user->location = strdup((char *)sqlite3_column_text(res, 7)); + user->sec_level = sqlite3_column_int(res, 8); + user->laston = (time_t)sqlite3_column_int(res, 9); + user->timeleft = sqlite3_column_int(res, 10); + user->cur_mail_conf = sqlite3_column_int(res, 11); + user->cur_mail_area = sqlite3_column_int(res, 12); + user->cur_file_dir = sqlite3_column_int(res, 14); + user->cur_file_sub = sqlite3_column_int(res, 13); + user->timeson = sqlite3_column_int(res, 15); - if (strcmp(password, user->password) != 0) { + pass_hash = hash_sha256(password, user->salt); + + if (strcmp(pass_hash, user->password) != 0) { free(user->loginname); free(user->firstname); free(user->lastname); free(user->email); free(user->location); + free(user->salt); free(user); - sqlite3_finalize(res); + free(pass_hash); + sqlite3_finalize(res); sqlite3_close(db); return NULL; } - } else { + free(pass_hash); + } else { sqlite3_finalize(res); sqlite3_close(db); return NULL; @@ -437,7 +499,8 @@ struct user_record *new_user(int socket) { s_putstring(socket, "Password too short!\r\n"); } } while (!passok); - user->password = strdup(buffer); + gen_salt(&user->salt); + user->password = hash_sha256(buffer, salt); s_putstring(socket, "You Entered:\r\n"); s_putstring(socket, "-------------------------------------\r\n"); @@ -451,8 +514,6 @@ struct user_record *new_user(int socket) { s_putstring(socket, user->email); s_putstring(socket, "\r\nLocation: "); s_putstring(socket, user->location); - s_putstring(socket, "\r\nPassword: "); - s_putstring(socket, user->password); s_putstring(socket, "\r\n-------------------------------------\r\n"); s_putstring(socket, "Is this Correct? (Y/N)"); c = s_getchar(socket); diff --git a/utils/mgpost/mgpost.c b/utils/mgpost/mgpost.c index 05b1445..a12618a 100644 --- a/utils/mgpost/mgpost.c +++ b/utils/mgpost/mgpost.c @@ -8,9 +8,9 @@ s_JamBase *open_jam_base(char *path) { int ret; s_JamBase *jb; - + ret = JAM_OpenMB((char *)path, &jb); - + if (ret != 0) { if (ret == JAM_IO_ERROR) { free(jb); @@ -35,12 +35,12 @@ int main(int argc, char **argv) { time_t thetime; int z; int i; - + s_JamBase *jb; s_JamMsgHeader jmh; s_JamSubPacket* jsp; s_JamSubfield jsf; - + if (argc < 6) { printf("Usage:\n"); printf("%s [l|e] filename jambase from subject laddress\n", argv[0]); @@ -50,29 +50,29 @@ int main(int argc, char **argv) { } if (tolower(argv[1][0]) != 'l' && tolower(argv[1][0]) != 'e') { printf("Usage:\n"); - printf("%s [l|e] filename jambase from subject\n", argv[0]); + printf("%s [l|e] filename jambase from subject laddress\n", argv[0]); printf(" l = Local Message, e = Echomail Message\n"); printf(" laddress is your network address, and only required on echomail.\n"); exit(1); } - + if (tolower(argv[1][0]) == 'e' && argc < 7) { printf("Usage:\n"); - printf("%s [l|e] filename jambase from subject\n", argv[0]); + printf("%s [l|e] filename jambase from subject laddress\n", argv[0]); printf(" l = Local Message, e = Echomail Message\n"); printf(" laddress is your network address, and only required on echomail.\n"); exit(1); } - + fptr = fopen(argv[2], "r"); - + if (!fptr) { printf("Unable to open %s\n", argv[2]); exit(1); } body = NULL; totlen = 0; - + len = fread(buffer, 1, 256, fptr); while (len > 0) { totlen += len; @@ -85,33 +85,33 @@ int main(int argc, char **argv) { body[totlen] = '\0'; len = fread(buffer, 1, 256, fptr); } - + fclose(fptr); - + for (i=0;i +#include +#include +#include +#include +#include + +char *hash_sha256(char *pass, char *salt) { + char *buffer = (char *)malloc(strlen(pass) + strlen(salt) + 1); + char *shash = (char *)malloc(66); + unsigned char hash[SHA256_DIGEST_LENGTH]; + + if (!buffer) { + printf("Out of memory!"); + exit(-1); + } + + sprintf(buffer, "%s%s", pass, salt); + + + SHA256_CTX sha256; + SHA256_Init(&sha256); + SHA256_Update(&sha256, buffer, strlen(buffer)); + SHA256_Final(hash, &sha256); + int i = 0; + for(i = 0; i < SHA256_DIGEST_LENGTH; i++) { + sprintf(shash + (i * 2), "%02x", hash[i]); + } + shash[64] = 0; + + free(buffer); + return shash; +} + +void gen_salt(char **s) { + FILE *fptr; + int i; + char c; + *s = (char *)malloc(11); + char *salt = *s; + + if (!salt) { + printf("Out of memory.."); + exit(-1); + } + fptr = fopen("/dev/urandom", "rb"); + if (!fptr) { + printf("Unable to open /dev/urandom!"); + exit(-1); + } + for (i=0;i<10;i++) { + fread(&c, 1, 1, fptr); + salt[i] = (char)((abs(c) % 93) + 33); + } + fclose(fptr); + salt[10] = '\0'; +} + +int main(int argc, char **argv) { + sqlite3 *db; + sqlite3_stmt *res; + sqlite3_stmt *res2; + + char *alter_table_sql = "ALTER TABLE users ADD COLUMN salt TEXT"; + char *select_sql = "SELECT Id,password FROM users"; + char *update_sql = "UPDATE users SET password=?, salt=? WHERE Id=?"; + char *err_msg = 0; + int id; + int rc; + char *password; + char *hash; + char *salt; + + rc = sqlite3_open(argv[1], &db); + + if (rc != SQLITE_OK) { + printf("Error opening database\n"); + return -1; + } + + rc = sqlite3_exec(db, alter_table_sql, 0, 0, &err_msg); + if (rc != SQLITE_OK ) { + + printf("SQL error: %s\n", err_msg); + + sqlite3_free(err_msg); + sqlite3_close(db); + + return 1; + } + rc = sqlite3_prepare_v2(db, select_sql, -1, &res, 0); + if (rc != SQLITE_OK) { + printf("Cannot prepare statement: %s\n", sqlite3_errmsg(db)); + sqlite3_close(db); + exit(1); + } + while (sqlite3_step(res) == SQLITE_ROW) { + id = sqlite3_column_int(res, 0); + password = strdup(sqlite3_column_text(res, 1)); + + gen_salt(&salt); + hash = hash_sha256(password, salt); + + rc = sqlite3_prepare_v2(db, update_sql, -1, &res2, 0); + if (rc != SQLITE_OK) { + printf("Cannot prepare statement: %s\n", sqlite3_errmsg(db)); + sqlite3_close(db); + exit(1); + } + sqlite3_bind_text(res2, 1, hash, -1, 0); + sqlite3_bind_text(res2, 2, salt, -1, 0); + sqlite3_bind_int(res2, 3, id); + + rc = sqlite3_step(res2); + + if (rc != SQLITE_DONE) { + printf("Error: %s\n", sqlite3_errmsg(db)); + exit(1); + } + sqlite3_finalize(res2); + } + + printf("Converted!\n"); + sqlite3_finalize(res); + sqlite3_close(db); +}