#include "pw.h" #include #include #include #include bool pw_set(sqlite3 *db, char *user, char *pass) { static const char *q = "INSERT INTO login (user, pass) VALUES (?1, ?2) " "ON CONFLICT (user) DO UPDATE SET pass = ?2"; static sqlite3_stmt *s; if (!s && sqlite3_prepare_v2(db, q, -1, &s, NULL) != SQLITE_OK) return false; if (sqlite3_bind_text(s, 1, user, -1, SQLITE_TRANSIENT) != SQLITE_OK) return false; char hash[_PASSWORD_LEN]; // note that alternatives to bcrypt are emerging // https://isopenbsdsecu.re/mitigations/password_hashing/ if (crypt_newhash(pass, "bcrypt,a", hash, sizeof hash) != 0) { // TODO: free s return false; } if (sqlite3_bind_text(s, 2, hash, sizeof hash, SQLITE_TRANSIENT) != SQLITE_OK) return false; if (sqlite3_step(s) != SQLITE_DONE) { fprintf(stderr, "Can't set pw: %s\n", sqlite3_errmsg(db)); return false; } bool good = sqlite3_changes(db) > 0; sqlite3_reset(s); return good; } bool pw_check(sqlite3 *db, char *user, char *pass) { static const char *q = "SELECT pass FROM login WHERE user = ?"; static sqlite3_stmt *s; if (!s && sqlite3_prepare_v2(db, q, -1, &s, NULL) != SQLITE_OK) return false; if (sqlite3_bind_text(s, 1, user, -1, SQLITE_TRANSIENT) != SQLITE_OK) { fprintf(stderr, "Can't bind: %s\n", sqlite3_errmsg(db)); return false; } if (sqlite3_step(s) != SQLITE_ROW) return false; const unsigned char *dbhash = sqlite3_column_text(s, 0); bool good = 0 == crypt_checkpass(pass, dbhash); sqlite3_reset(s); return good; } int main(int argc, char **argv){ sqlite3 *db = NULL; int rc, fk_enabled; if (argc !=2) { fprintf(stderr, "Usage: %s DATABASE\n", argv[0]); goto fail; } rc = sqlite3_open(argv[1], &db); if( rc ){ fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db)); goto fail; } rc = sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_FKEY, 1, &fk_enabled ); if (rc != SQLITE_OK || !fk_enabled) { fputs("Could not enable foreign keys in sqlite\n", stderr); return EXIT_FAILURE; } char *u1 = "foo@example.com", *p1 = "password123", *u1c = "FOO@EXAMPLE.COM"; pw_set(db, u1, p1); printf("Checking pass: %d\n", pw_check(db, u1, p1)); printf("Checking mixed case: %d\n", pw_check(db, u1c, p1)); printf("Checking wrong pass: %d\n", pw_check(db, u1, "wrong")); sqlite3_close(db); return 0; fail: sqlite3_close(db); return EXIT_FAILURE; }