// bcrypt_tool.c - CLI tool for bcrypt password hashing and verification // Compile: ( cd tools/ && rm bcrypt_tool; mk bcrypt_tool ) // Usage: // ./bcrypt_tool hash [cost] // ./bcrypt_tool verify #define _XOPEN_SOURCE #include #include #include #include #include #include #include #include #include typedef unsigned char byte; #include "util/defs.h" #include "util/arenastr.c" #include "util/strmanip.c" #include "util/passwordhash.c" static void print_usage(const char *prog) { fprintf(stderr, "Usage: %s [arguments]\n" "\n" "Commands:\n" " hash [cost] Hash a password (cost default: %d, range: %d-%d)\n" " verify Verify a password against a hash\n" "\n" "Examples:\n" " %s hash mysecretpassword\n" " %s hash mysecretpassword 12\n" " %s verify mysecretpassword '$2b$10$...'\n", prog, BCRYPT_DEFAULT_COST, BCRYPT_MIN_COST, BCRYPT_MAX_COST, prog, prog, prog); } int main(int argc, char **argv) { if (argc < 2) { print_usage(argv[0]); return 1; } // Arena for temporary allocations (4KB is plenty) uint8_t buf[4096]; arena tmp; arena_init(&tmp, buf, sizeof(buf)); if (strcmp(argv[1], "hash") == 0) { if (argc < 3) { fprintf(stderr, "Error: password required\n"); print_usage(argv[0]); return 1; } str password = str_from_cstr(argv[2]); int cost = BCRYPT_DEFAULT_COST; if (argc >= 4) { cost = atoi(argv[3]); } str hash = create_password_hash(&tmp, password, cost); if (hash.len == 0) { fprintf(stderr, "Error: failed to create password hash\n"); return 1; } printf("%.*s\n", (int)hash.len, hash.data); return 0; } else if (strcmp(argv[1], "verify") == 0) { if (argc < 4) { fprintf(stderr, "Error: password and hash required\n"); print_usage(argv[0]); return 1; } str password = str_from_cstr(argv[2]); str hash = str_from_cstr(argv[3]); if (verify_password(password, hash)) { printf("MATCH\n"); return 0; } else { printf("FAIL\n"); return 1; } } else { fprintf(stderr, "Error: unknown command '%s'\n", argv[1]); print_usage(argv[0]); return 1; } }