diff options
Diffstat (limited to 'src/auth.c')
| -rw-r--r-- | src/auth.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/src/auth.c b/src/auth.c new file mode 100644 index 0000000..62dcd04 --- /dev/null +++ b/src/auth.c @@ -0,0 +1,92 @@ +#include "auth.h" + +#include <argon2.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "util.h" + +#define ARGON2_T_COST 3 +#define ARGON2_M_COST (64 * 1024) +#define ARGON2_PARALLELISM 1 +#define ARGON2_SALT_LEN 16 +#define ARGON2_HASH_LEN 32 + +int auth_hash_password(const char *pw, char **out_phc) +{ + if (!pw) + return -1; + unsigned char salt[ARGON2_SALT_LEN]; + if (util_random(salt, sizeof salt) != 0) + return -1; + char encoded[256]; + int rc = argon2id_hash_encoded(ARGON2_T_COST, ARGON2_M_COST, + ARGON2_PARALLELISM, pw, strlen(pw), salt, + sizeof salt, ARGON2_HASH_LEN, encoded, + sizeof encoded); + if (rc != ARGON2_OK) + return -1; + *out_phc = xstrdup(encoded); + return 0; +} + +int auth_verify_password(const char *phc, const char *pw) +{ + if (!phc || !pw) + return -1; + return argon2id_verify(phc, pw, strlen(pw)) == ARGON2_OK ? 0 : -1; +} + +void auth_hash_token(const char *token, unsigned char out[32]) +{ + util_sha256(token, strlen(token), out); +} + +char *auth_generate_token(void) +{ + unsigned char raw[32]; + if (util_random(raw, sizeof raw) != 0) { + fprintf(stderr, "fatal: no entropy source\n"); + exit(1); + } + char *body = util_b64url(raw, sizeof raw); + size_t n = strlen(body) + sizeof AUTH_TOKEN_PREFIX + 1; + char *token = xmalloc(n); + snprintf(token, n, "%s%s", AUTH_TOKEN_PREFIX, body); + free(body); + return token; +} + +int64_t auth_user_lookup(sqlite3 *db, const char *username, char **out_pwhash, + char **out_display, int *out_is_admin, + int *out_disabled) +{ + sqlite3_stmt *st = NULL; + int rc = sqlite3_prepare_v2( + db, + "SELECT id, pw_hash, display_name, is_admin, disabled_at FROM users" + " WHERE username = ?1", + -1, &st, NULL); + if (rc != SQLITE_OK) + return -2; + sqlite3_bind_text(st, 1, username, -1, SQLITE_TRANSIENT); + int64_t id = -1; + if (sqlite3_step(st) == SQLITE_ROW) { + id = sqlite3_column_int64(st, 0); + if (out_pwhash) { + const unsigned char *p = sqlite3_column_text(st, 1); + *out_pwhash = p ? xstrdup((const char *)p) : NULL; + } + if (out_display) { + const unsigned char *p = sqlite3_column_text(st, 2); + *out_display = p ? xstrdup((const char *)p) : NULL; + } + if (out_is_admin) + *out_is_admin = sqlite3_column_int(st, 3); + if (out_disabled) + *out_disabled = sqlite3_column_type(st, 4) != SQLITE_NULL; + } + sqlite3_finalize(st); + return id; +} |
