diff --git a/.gitmodules b/.gitmodules index 2bba20905..e580c9aa7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "OpenCL-Headers"] path = deps/git/OpenCL-Headers url = https://github.com/KhronosGroup/OpenCL-Headers.git +[submodule "xxHash"] + path = deps/git/xxHash + url = https://github.com/Cyan4973/xxHash.git diff --git a/deps/git/xxHash b/deps/git/xxHash new file mode 160000 index 000000000..0f2dd4a1c --- /dev/null +++ b/deps/git/xxHash @@ -0,0 +1 @@ +Subproject commit 0f2dd4a1cb103e3fc8c55c855b821eb24c6d82c3 diff --git a/docs/changes.txt b/docs/changes.txt index 416a0865e..7eb7cae76 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -5,6 +5,13 @@ ## - Added new option --slow-candidates which allows hashcat to generate passwords on-host +- Added new option --brain-server to start a hashcat brain server +- Added new option --brain-client to start a hashcat brain client, automatically activates --slow-candidates +- Added new option --brain-host and --brain-port to specify ip and port of brain server, both listening and connecting +- Added new option --brain-session to override automatically calculated brain session ID +- Added new option --brain-session-whitelist to allow only explicit written session ID on brain server +- Added new option --brain-password to specify the brain server authentication password +- Added new option --brain-client-features which allows enable and disable certain features of the hashcat brain ## ## Algorithms diff --git a/docs/readme.txt b/docs/readme.txt index 4eedbf761..eac759b31 100644 --- a/docs/readme.txt +++ b/docs/readme.txt @@ -21,6 +21,7 @@ NVIDIA GPUs require "NVIDIA Driver" (367.x or later) - Multi-Hash (Cracking multiple hashes at the same time) - Multi-Devices (Utilizing multiple devices in same system) - Multi-Device-Types (Utilizing mixed device types in same system) +- Supports password candidate brain functionality - Supports distributed cracking networks (using overlay) - Supports interactive pause / resume - Supports sessions diff --git a/extra/tab_completion/hashcat.sh b/extra/tab_completion/hashcat.sh index 0a683d467..f65aab84c 100644 --- a/extra/tab_completion/hashcat.sh +++ b/extra/tab_completion/hashcat.sh @@ -189,8 +189,8 @@ _hashcat () local BUILD_IN_CHARSETS='?l ?u ?d ?a ?b ?s ?h ?H' local SHORT_OPTS="-m -a -V -v -h -b -t -o -p -c -d -w -n -u -j -k -r -g -1 -2 -3 -4 -i -I -s -l -O -S -z" - local LONG_OPTS="--hash-type --attack-mode --version --help --quiet --benchmark --benchmark-all --hex-salt --hex-wordlist --hex-charset --force --status --status-timer --machine-readable --loopback --markov-hcstat2 --markov-disable --markov-classic --markov-threshold --runtime --session --speed-only --progress-only --restore --restore-file-path --restore-disable --outfile --outfile-format --outfile-autohex-disable --outfile-check-timer --outfile-check-dir --wordlist-autohex-disable --separator --show --left --username --remove --remove-timer --potfile-disable --potfile-path --debug-mode --debug-file --induction-dir --segment-size --bitmap-min --bitmap-max --cpu-affinity --example-hashes --opencl-info --opencl-devices --opencl-platforms --opencl-device-types --opencl-vector-width --workload-profile --kernel-accel --kernel-loops --nvidia-spin-damp --gpu-temp-disable --gpu-temp-abort --skip --limit --keyspace --rule-left --rule-right --rules-file --generate-rules --generate-rules-func-min --generate-rules-func-max --generate-rules-seed --custom-charset1 --custom-charset2 --custom-charset3 --custom-charset4 --increment --increment-min --increment-max --logfile-disable --scrypt-tmto --truecrypt-keyfiles --veracrypt-keyfiles --veracrypt-pim --stdout --keep-guessing --hccapx-message-pair --nonce-error-corrections --encoding-from --encoding-to --optimized-kernel-enable --self-test-disable --slow-candidates" - local OPTIONS="-m -a -t -o -p -c -d -w -n -u -j -k -r -g -1 -2 -3 -4 -s -l --hash-type --attack-mode --status-timer --markov-hcstat2 --markov-threshold --runtime --session --timer --outfile --outfile-format --outfile-check-timer --outfile-check-dir --separator --remove-timer --potfile-path --restore-file-path --debug-mode --debug-file --induction-dir --segment-size --bitmap-min --bitmap-max --cpu-affinity --opencl-devices --opencl-platforms --opencl-device-types --opencl-vector-width --workload-profile --kernel-accel --kernel-loops --nvidia-spin-damp --gpu-temp-abort --skip --limit --rule-left --rule-right --rules-file --generate-rules --generate-rules-func-min --generate-rules-func-max --generate-rules-seed --custom-charset1 --custom-charset2 --custom-charset3 --custom-charset4 --increment-min --increment-max --scrypt-tmto --truecrypt-keyfiles --veracrypt-keyfiles --veracrypt-pim --hccapx-message-pair --nonce-error-corrections --encoding-from --encoding-to" + local LONG_OPTS="--hash-type --attack-mode --version --help --quiet --benchmark --benchmark-all --hex-salt --hex-wordlist --hex-charset --force --status --status-timer --machine-readable --loopback --markov-hcstat2 --markov-disable --markov-classic --markov-threshold --runtime --session --speed-only --progress-only --restore --restore-file-path --restore-disable --outfile --outfile-format --outfile-autohex-disable --outfile-check-timer --outfile-check-dir --wordlist-autohex-disable --separator --show --left --username --remove --remove-timer --potfile-disable --potfile-path --debug-mode --debug-file --induction-dir --segment-size --bitmap-min --bitmap-max --cpu-affinity --example-hashes --opencl-info --opencl-devices --opencl-platforms --opencl-device-types --opencl-vector-width --workload-profile --kernel-accel --kernel-loops --nvidia-spin-damp --gpu-temp-disable --gpu-temp-abort --skip --limit --keyspace --rule-left --rule-right --rules-file --generate-rules --generate-rules-func-min --generate-rules-func-max --generate-rules-seed --custom-charset1 --custom-charset2 --custom-charset3 --custom-charset4 --increment --increment-min --increment-max --logfile-disable --scrypt-tmto --truecrypt-keyfiles --veracrypt-keyfiles --veracrypt-pim --stdout --keep-guessing --hccapx-message-pair --nonce-error-corrections --encoding-from --encoding-to --optimized-kernel-enable --self-test-disable --slow-candidates --brain-server --brain-client --brain-client-features --brain-host --brain-port --brain-session --brain-session-whitelist --brain-password" + local OPTIONS="-m -a -t -o -p -c -d -w -n -u -j -k -r -g -1 -2 -3 -4 -s -l --hash-type --attack-mode --status-timer --markov-hcstat2 --markov-threshold --runtime --session --timer --outfile --outfile-format --outfile-check-timer --outfile-check-dir --separator --remove-timer --potfile-path --restore-file-path --debug-mode --debug-file --induction-dir --segment-size --bitmap-min --bitmap-max --cpu-affinity --opencl-devices --opencl-platforms --opencl-device-types --opencl-vector-width --workload-profile --kernel-accel --kernel-loops --nvidia-spin-damp --gpu-temp-abort --skip --limit --rule-left --rule-right --rules-file --generate-rules --generate-rules-func-min --generate-rules-func-max --generate-rules-seed --custom-charset1 --custom-charset2 --custom-charset3 --custom-charset4 --increment-min --increment-max --scrypt-tmto --truecrypt-keyfiles --veracrypt-keyfiles --veracrypt-pim --hccapx-message-pair --nonce-error-corrections --encoding-from --encoding-to --brain-host --brain-password --brain-port --brain-session --brain-whitelist-session" COMPREPLY=() local cur="${COMP_WORDS[COMP_CWORD]}" @@ -363,7 +363,51 @@ _hashcat () --status-timer|--markov-threshold|--runtime|--session|--separator|--segment-size|--rule-left|--rule-right| \ --nvidia-spin-damp|--gpu-temp-abort|--generate-rules|--generate-rules-func-min|--generate-rules-func-max| \ --increment-min|--increment-max|--remove-timer|--bitmap-min|--bitmap-max|--skip|--limit|--generate-rules-seed| \ - --outfile-check-timer|--outfile-check-dir|--induction-dir|--scrypt-tmto|--encoding-from|--encoding-to|--optimized-kernel-enable) + --outfile-check-timer|--outfile-check-dir|--induction-dir|--scrypt-tmto|--encoding-from|--encoding-to|--optimized-kernel-enable|--brain-host|--brain-port|--brain-password) + return 0 + ;; + + --brain-session) + local cur_session=$(echo "${cur}" | grep -Eo '^0x[0-9a-fA-F]*' | sed 's/^0x//') + + local session_var="0x${cur_session}" + + if [ "${#cur_session}" -lt 8 ] + then + session_var="${session_var}0 ${session_var}1 ${session_var}2 ${session_var}3 ${session_var}4 + ${session_var}5 ${session_var}6 ${session_var}7 ${session_var}8 ${session_var}9 + ${session_var}a ${session_var}b ${session_var}c ${session_var}d ${session_var}e + ${session_var}f" + fi + + COMPREPLY=($(compgen -W "${session_var}" -- ${cur})) + + return 0 + ;; + + --brain-session-whitelist) + local session_list=$(echo "${cur}" | grep -Eo '^0x[0-9a-fA-F,x]*' | sed 's/^0x//') + + local cur_session=$(echo "${session_list}" | sed 's/^.*0x//') + + local session_var="0x${session_list}" + + if [ "${#cur_session}" -eq 8 ] + then + cur_session="" + session_var="${session_var},0x" + fi + + if [ "${#cur_session}" -lt 8 ] + then + session_var="${session_var}0 ${session_var}1 ${session_var}2 ${session_var}3 ${session_var}4 + ${session_var}5 ${session_var}6 ${session_var}7 ${session_var}8 ${session_var}9 + ${session_var}a ${session_var}b ${session_var}c ${session_var}d ${session_var}e + ${session_var}f" + fi + + COMPREPLY=($(compgen -W "${session_var}" -- ${cur})) + return 0 ;; diff --git a/include/brain.h b/include/brain.h new file mode 100644 index 000000000..77af37081 --- /dev/null +++ b/include/brain.h @@ -0,0 +1,242 @@ +/** + * Author......: See docs/credits.txt + * License.....: MIT + */ + +#ifndef _BRAIN_H +#define _BRAIN_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined (_WIN) +#define _WINNT_WIN32 0x0601 +#include +#include +#include +#define SEND_FLAGS 0 +#else +#include +#include +#include +#include +#include +#include +#include +#define SEND_FLAGS MSG_NOSIGNAL +#endif + +#include "xxhash.h" + +static const int BRAIN_CLIENT_CONNECT_TIMEOUT = 5; +static const int BRAIN_SERVER_DUMP_EVERY = 5 * 60; +static const int BRAIN_SERVER_SESSIONS_MAX = 64; +static const int BRAIN_SERVER_ATTACKS_MAX = 64 * 1024; +static const int BRAIN_SERVER_CLIENTS_MAX = 256; +static const int BRAIN_SERVER_REALLOC_HASH_SIZE = 1024 * 1024; +static const int BRAIN_SERVER_REALLOC_ATTACK_SIZE = 1024; +static const int BRAIN_HASH_SIZE = 2 * sizeof (u32); +static const int BRAIN_LINK_VERSION_CUR = 1; +static const int BRAIN_LINK_VERSION_MIN = 1; +static const int BRAIN_LINK_CHUNK_SIZE = 4 * 1024; +static const int BRAIN_LINK_CANDIDATES_MAX = 128 * 1024 * 256; // units * threads * accel + +typedef enum brain_operation +{ + BRAIN_OPERATION_COMMIT = 1, + BRAIN_OPERATION_HASH_LOOKUP = 2, + BRAIN_OPERATION_ATTACK_RESERVE = 3, + +} brain_operation_t; + +typedef enum brain_client_feature +{ + BRAIN_CLIENT_FEATURE_HASHES = 1, + BRAIN_CLIENT_FEATURE_ATTACKS = 2, + +} brain_client_feature_t; + +typedef struct brain_server_attack_long +{ + u64 offset; + u64 length; + +} brain_server_attack_long_t; + +typedef struct brain_server_attack_short +{ + u64 offset; + u64 length; + + int client_fd; + +} brain_server_attack_short_t; + +typedef struct brain_server_hash_long +{ + u32 hash[2]; + +} brain_server_hash_long_t; + +typedef struct brain_server_hash_short +{ + u32 hash[2]; + +} brain_server_hash_short_t; + +typedef struct brain_server_hash_unique +{ + u32 hash[2]; + + i64 hash_idx; + +} brain_server_hash_unique_t; + +typedef struct brain_server_db_attack +{ + u32 brain_attack; + + brain_server_attack_short_t *short_buf; + + i64 short_alloc; + i64 short_cnt; + + brain_server_attack_long_t *long_buf; + + i64 long_alloc; + i64 long_cnt; + + int ab; + + hc_thread_mutex_t mux_ar; + hc_thread_mutex_t mux_ag; + + bool write_attacks; + +} brain_server_db_attack_t; + +typedef struct brain_server_db_hash +{ + u32 brain_session; + + brain_server_hash_long_t *long_buf; + + i64 long_alloc; + i64 long_cnt; + + int hb; + + hc_thread_mutex_t mux_hr; + hc_thread_mutex_t mux_hg; + + bool write_hashes; + +} brain_server_db_hash_t; + +typedef struct brain_server_db_short +{ + brain_server_hash_short_t *short_buf; + + i64 short_cnt; + +} brain_server_db_short_t; + +typedef struct brain_server_dbs +{ + // required for cyclic dump + + hc_thread_mutex_t mux_dbs; + + brain_server_db_hash_t *hash_buf; + brain_server_db_attack_t *attack_buf; + + int hash_cnt; + int attack_cnt; + +} brain_server_dbs_t; + +typedef struct brain_server_dumper_options +{ + brain_server_dbs_t *brain_server_dbs; + +} brain_server_dumper_options_t; + +typedef struct brain_server_client_options +{ + brain_server_dbs_t *brain_server_dbs; + + int client_fd; + + char *auth_password; + + u32 *session_whitelist_buf; + int session_whitelist_cnt; + +} brain_server_client_options_t; + +int brain_logging (FILE *stream, const int client_fd, const char *format, ...); + +u32 brain_compute_session (hashcat_ctx_t *hashcat_ctx); +u32 brain_compute_attack (hashcat_ctx_t *hashcat_ctx); +u64 brain_compute_attack_wordlist (const char *filename); + +u32 brain_auth_challenge (void); +u64 brain_auth_hash (const u32 challenge, const char *pw_buf, const int pw_len); + +int brain_connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen, const int timeout); +bool brain_recv (int sockfd, void *buf, size_t len, int flags, hc_device_param_t *device_param, const status_ctx_t *status_ctx); +bool brain_send (int sockfd, void *buf, size_t len, int flags, hc_device_param_t *device_param, const status_ctx_t *status_ctx); +bool brain_recv_all (int sockfd, void *buf, size_t len, int flags, hc_device_param_t *device_param, const status_ctx_t *status_ctx); +bool brain_send_all (int sockfd, void *buf, size_t len, int flags, hc_device_param_t *device_param, const status_ctx_t *status_ctx); + +bool brain_client_reserve (hc_device_param_t *device_param, const status_ctx_t *status_ctx, u64 words_off, u64 work, u64 *overlap); +bool brain_client_commit (hc_device_param_t *device_param, const status_ctx_t *status_ctx); +bool brain_client_lookup (hc_device_param_t *device_param, const status_ctx_t *status_ctx); +bool brain_client_connect (hc_device_param_t *device_param, const status_ctx_t *status_ctx, const char *host, const int port, const char *password, u32 brain_session, u32 brain_attack, i64 passwords_max, u64 *highest); +void brain_client_disconnect (hc_device_param_t *device_param); +void brain_client_generate_hash (u64 *hash, const char *line_buf, const size_t line_len); + +int brain_server (const char *listen_host, const int listen_port, const char *brain_password, const char *brain_session_whitelist); +bool brain_server_read_hash_dumps (brain_server_dbs_t *brain_server_dbs, const char *path); +bool brain_server_write_hash_dumps (brain_server_dbs_t *brain_server_dbs, const char *path); +bool brain_server_read_hash_dump (brain_server_db_hash_t *brain_server_db_hash, const char *file); +bool brain_server_write_hash_dump (brain_server_db_hash_t *brain_server_db_hash, const char *file); +bool brain_server_read_attack_dumps (brain_server_dbs_t *brain_server_dbs, const char *path); +bool brain_server_write_attack_dumps (brain_server_dbs_t *brain_server_dbs, const char *path); +bool brain_server_read_attack_dump (brain_server_db_attack_t *brain_server_db_attack, const char *file); +bool brain_server_write_attack_dump (brain_server_db_attack_t *brain_server_db_attack, const char *file); + +u64 brain_server_highest_attack (const brain_server_db_attack_t *buf); +u64 brain_server_highest_attack_long (const brain_server_attack_long_t *buf, const i64 cnt, const u64 start); +u64 brain_server_highest_attack_short (const brain_server_attack_short_t *buf, const i64 cnt, const u64 start); +u64 brain_server_find_attack_long (const brain_server_attack_long_t *buf, const i64 cnt, const u64 offset, const u64 length); +u64 brain_server_find_attack_short (const brain_server_attack_short_t *buf, const i64 cnt, const u64 offset, const u64 length); +i64 brain_server_find_hash_long (const u32 *search, const brain_server_hash_long_t *buf, const i64 cnt); +i64 brain_server_find_hash_short (const u32 *search, const brain_server_hash_short_t *buf, const i64 cnt); +int brain_server_sort_db_hash (const void *v1, const void *v2); +int brain_server_sort_db_attack (const void *v1, const void *v2); +int brain_server_sort_attack_long (const void *v1, const void *v2); +int brain_server_sort_attack_short (const void *v1, const void *v2); +int brain_server_sort_hash (const void *v1, const void *v2); +int brain_server_sort_hash_long (const void *v1, const void *v2); +int brain_server_sort_hash_short (const void *v1, const void *v2); +int brain_server_sort_hash_unique (const void *v1, const void *v2); +void brain_server_handle_signal (int signo); +void *brain_server_handle_client (void *p); +void *brain_server_handle_dumps (void *p); +void brain_server_db_hash_init (brain_server_db_hash_t *brain_server_db_hash, const u32 brain_session); +bool brain_server_db_hash_realloc (brain_server_db_hash_t *brain_server_db_hash, const i64 new_long_cnt); +void brain_server_db_hash_free (brain_server_db_hash_t *brain_server_db_hash); +void brain_server_db_attack_init (brain_server_db_attack_t *brain_server_db_attack, const u32 brain_attack); +bool brain_server_db_attack_realloc (brain_server_db_attack_t *brain_server_db_attack, const i64 new_long_cnt, const i64 new_short_cnt); +void brain_server_db_attack_free (brain_server_db_attack_t *brain_server_db_attack); + +#endif // _BRAIN_H diff --git a/include/dispatch.h b/include/dispatch.h index 459213cbb..e16a30650 100644 --- a/include/dispatch.h +++ b/include/dispatch.h @@ -6,6 +6,22 @@ #ifndef _DISPATCH_H #define _DISPATCH_H +#ifdef WITH_BRAIN +#if defined (_WIN) +#include +#define SEND_FLAGS 0 +#endif + +#if defined (__linux__) +#include +#include +#include +#include +#include +#define SEND_FLAGS MSG_NOSIGNAL +#endif +#endif + HC_API_CALL void *thread_calc_stdin (void *p); HC_API_CALL void *thread_calc (void *p); diff --git a/include/status.h b/include/status.h index 8427830f7..48653526d 100644 --- a/include/status.h +++ b/include/status.h @@ -85,6 +85,16 @@ int status_get_innerloop_pos_dev (const hashcat_ctx_t *hash int status_get_innerloop_left_dev (const hashcat_ctx_t *hashcat_ctx, const int device_id); int status_get_iteration_pos_dev (const hashcat_ctx_t *hashcat_ctx, const int device_id); int status_get_iteration_left_dev (const hashcat_ctx_t *hashcat_ctx, const int device_id); +#ifdef WITH_BRAIN +int status_get_brain_session (const hashcat_ctx_t *hashcat_ctx); +int status_get_brain_attack (const hashcat_ctx_t *hashcat_ctx); +int status_get_brain_link_client_id_dev (const hashcat_ctx_t *hashcat_ctx, const int device_id); +int status_get_brain_link_status_dev (const hashcat_ctx_t *hashcat_ctx, const int device_id); +char *status_get_brain_link_recv_bytes_dev (const hashcat_ctx_t *hashcat_ctx, const int device_id); +char *status_get_brain_link_send_bytes_dev (const hashcat_ctx_t *hashcat_ctx, const int device_id); +char *status_get_brain_link_recv_bytes_sec_dev (const hashcat_ctx_t *hashcat_ctx, const int device_id); +char *status_get_brain_link_send_bytes_sec_dev (const hashcat_ctx_t *hashcat_ctx, const int device_id); +#endif char *status_get_hwmon_dev (const hashcat_ctx_t *hashcat_ctx, const int device_id); int status_get_corespeed_dev (const hashcat_ctx_t *hashcat_ctx, const int device_id); int status_get_memoryspeed_dev (const hashcat_ctx_t *hashcat_ctx, const int device_id); diff --git a/include/types.h b/include/types.h index 404ba7561..ddda06907 100644 --- a/include/types.h +++ b/include/types.h @@ -536,6 +536,13 @@ typedef enum user_options_defaults BENCHMARK = false, BITMAP_MAX = 24, BITMAP_MIN = 16, + #ifdef WITH_BRAIN + BRAIN_CLIENT = false, + BRAIN_CLIENT_FEATURES = 3, + BRAIN_PORT = 6863, + BRAIN_SERVER = false, + BRAIN_SESSION = 0, + #endif DEBUG_MODE = 0, EXAMPLE_HASHES = false, FORCE = false, @@ -609,6 +616,16 @@ typedef enum user_options_map IDX_BENCHMARK = 'b', IDX_BITMAP_MAX = 0xff02, IDX_BITMAP_MIN = 0xff03, + #ifdef WITH_BRAIN + IDX_BRAIN_CLIENT = 'z', + IDX_BRAIN_CLIENT_FEATURES = 0xff04, + IDX_BRAIN_HOST = 0xff05, + IDX_BRAIN_PASSWORD = 0xff06, + IDX_BRAIN_PORT = 0xff07, + IDX_BRAIN_SERVER = 0xff08, + IDX_BRAIN_SESSION = 0xff09, + IDX_BRAIN_SESSION_WHITELIST = 0xff0a, + #endif IDX_CPU_AFFINITY = 0xff0b, IDX_CUSTOM_CHARSET_1 = '1', IDX_CUSTOM_CHARSET_2 = '2', @@ -712,6 +729,16 @@ typedef enum token_attr } token_attr_t; +#ifdef WITH_BRAIN +typedef enum brain_link_status +{ + BRAIN_LINK_STATUS_CONNECTED = 1 << 0, + BRAIN_LINK_STATUS_RECEIVING = 1 << 1, + BRAIN_LINK_STATUS_SENDING = 1 << 2, + +} brain_link_status_t; +#endif + /** * structs */ @@ -950,6 +977,16 @@ typedef struct plain } plain_t; +#define LINK_SPEED_COUNT 10000 + +typedef struct link_speed +{ + hc_timer_t timer[LINK_SPEED_COUNT]; + ssize_t bytes[LINK_SPEED_COUNT]; + int pos; + +} link_speed_t; + #include "ext_OpenCL.h" typedef struct hc_device_param @@ -1085,6 +1122,21 @@ typedef struct hc_device_param size_t size_st_salts; size_t size_st_esalts; + #ifdef WITH_BRAIN + size_t size_brain_link_in; + size_t size_brain_link_out; + + int brain_link_client_fd; + link_speed_t brain_link_recv_speed; + link_speed_t brain_link_send_speed; + bool brain_link_recv_active; + bool brain_link_send_active; + u64 brain_link_recv_bytes; + u64 brain_link_send_bytes; + u8 *brain_link_in_buf; + u32 *brain_link_out_buf; + #endif + char *scratch_buf; FILE *combs_fp; @@ -1618,6 +1670,11 @@ typedef struct user_options char **hc_argv; bool attack_mode_chgd; + #ifdef WITH_BRAIN + bool brain_host_chgd; + bool brain_port_chgd; + bool brain_password_chgd; + #endif bool hash_mode_chgd; bool hccapx_message_pair_chgd; bool increment_max_chgd; @@ -1639,6 +1696,10 @@ typedef struct user_options bool advice_disable; bool benchmark; bool benchmark_all; + #ifdef WITH_BRAIN + bool brain_client; + bool brain_server; + #endif bool example_hashes; bool force; bool gpu_temp_disable; @@ -1673,6 +1734,11 @@ typedef struct user_options bool username; bool version; bool wordlist_autohex_disable; + #ifdef WITH_BRAIN + char *brain_host; + char *brain_password; + char *brain_session_whitelist; + #endif char *cpu_affinity; char *custom_charset_4; char *debug_file; @@ -1700,6 +1766,12 @@ typedef struct user_options u32 attack_mode; u32 bitmap_max; u32 bitmap_min; + #ifdef WITH_BRAIN + u32 brain_client_features; + u32 brain_port; + u32 brain_session; + u32 brain_attack; + #endif u32 debug_mode; u32 gpu_temp_abort; u32 hash_mode; @@ -1893,6 +1965,16 @@ typedef struct device_info int innerloop_left_dev; int iteration_pos_dev; int iteration_left_dev; + #ifdef WITH_BRAIN + int brain_link_client_id_dev; + int brain_link_status_dev; + char *brain_link_recv_bytes_dev; + char *brain_link_send_bytes_dev; + char *brain_link_recv_bytes_sec_dev; + char *brain_link_send_bytes_sec_dev; + double brain_link_time_recv_dev; + double brain_link_time_send_dev; + #endif } device_info_t; @@ -1912,6 +1994,10 @@ typedef struct hashcat_status char *guess_charset; int guess_mask_length; char *session; + #ifdef WITH_BRAIN + int brain_session; + int brain_attack; + #endif const char *status_string; int status_number; char *time_estimated_absolute; diff --git a/src/Makefile b/src/Makefile index 4f6754653..355118747 100644 --- a/src/Makefile +++ b/src/Makefile @@ -7,6 +7,7 @@ SHARED := 0 DEBUG := 0 PRODUCTION := 0 PRODUCTION_VERSION := v4.2.1 +ENABLE_BRAIN := 1 ## ## Detect Operating System @@ -185,6 +186,12 @@ CFLAGS += $(LZMA_SDK_INCLUDE) LDFLAGS += -llzmasdk endif +# brain and xxHash +ifeq ($(ENABLE_BRAIN),1) +CFLAGS += -DWITH_BRAIN +CFLAGS += -Ideps/git/xxHash +endif + ## ## Native compilation target ## @@ -292,6 +299,10 @@ LFLAGS_CROSS_WIN64 += -lws2_32 OBJS_ALL := affinity autotune benchmark bitmap bitops combinator common convert cpt cpu_aes cpu_crc32 cpu_des cpu_md4 cpu_md5 cpu_sha1 cpu_sha256 debugfile dictstat dispatch dynloader event ext_ADL ext_nvapi ext_nvml ext_OpenCL ext_sysfs ext_lzma filehandling folder hashcat hashes hlfmt hwmon induct interface locking logfile loopback memory monitor mpsp opencl outfile_check outfile pidfile potfile restore rp rp_cpu rp_kernel_on_cpu rp_kernel_on_cpu_optimized selftest slow_candidates shared status stdout straight terminal thread timer tuningdb usage user_options wordlist +ifeq ($(ENABLE_BRAIN),1) +OBJS_ALL += brain +endif + NATIVE_STATIC_OBJS := $(foreach OBJ,$(OBJS_ALL),obj/$(OBJ).NATIVE.STATIC.o) NATIVE_SHARED_OBJS := $(foreach OBJ,$(OBJS_ALL),obj/$(OBJ).NATIVE.SHARED.o) @@ -301,6 +312,19 @@ LINUX_64_OBJS := $(foreach OBJ,$(OBJS_ALL),obj/$(OBJ).LINUX.64.o) WIN_32_OBJS := $(foreach OBJ,$(OBJS_ALL),obj/$(OBJ).WIN.32.o) WIN_64_OBJS := $(foreach OBJ,$(OBJS_ALL),obj/$(OBJ).WIN.64.o) +ifeq ($(ENABLE_BRAIN),1) +OBJS_XXHASH := xxhash + +NATIVE_STATIC_OBJS += $(foreach OBJ,$(OBJS_XXHASH),obj/$(OBJ).NATIVE.STATIC.o) +NATIVE_SHARED_OBJS += $(foreach OBJ,$(OBJS_XXHASH),obj/$(OBJ).NATIVE.SHARED.o) + +LINUX_32_OBJS += $(foreach OBJ,$(OBJS_XXHASH),obj/$(OBJ).LINUX.32.o) +LINUX_64_OBJS += $(foreach OBJ,$(OBJS_XXHASH),obj/$(OBJ).LINUX.64.o) + +WIN_32_OBJS += $(foreach OBJ,$(OBJS_XXHASH),obj/$(OBJ).WIN.32.o) +WIN_64_OBJS += $(foreach OBJ,$(OBJS_XXHASH),obj/$(OBJ).WIN.64.o) +endif + ifeq ($(SYSTEM_LZMA_SDK),0) OBJS_LZMA := Alloc Lzma2Dec LzmaDec @@ -449,6 +473,14 @@ obj/%.NATIVE.STATIC.o: src/%.c obj/%.NATIVE.SHARED.o: src/%.c $(CC) -c $(CFLAGS_NATIVE) $< -o $@ -fpic +ifeq ($(ENABLE_BRAIN),1) +obj/%.NATIVE.STATIC.o: deps/git/xxHash/%.c + $(CC) -c $(CFLAGS_NATIVE) $< -o $@ + +obj/%.NATIVE.SHARED.o: deps/git/xxHash/%.c + $(CC) -c $(CFLAGS_NATIVE) $< -o $@ -fpic +endif + ifeq ($(SYSTEM_LZMA_SDK),0) obj/%.NATIVE.STATIC.o: deps/lzma_sdk/%.c $(CC) -c $(CFLAGS_NATIVE) $< -o $@ @@ -489,6 +521,20 @@ obj/%.WIN.32.o: src/%.c obj/%.WIN.64.o: src/%.c $(CC_WIN_64) $(CFLAGS_CROSS_WIN64) -c -o $@ $< +ifeq ($(ENABLE_BRAIN),1) +obj/%.LINUX.32.o: deps/git/xxHash/%.c + $(CC_LINUX_32) $(CFLAGS_CROSS_LINUX32) -c -o $@ $< + +obj/%.LINUX.64.o: deps/git/xxHash/%.c + $(CC_LINUX_64) $(CFLAGS_CROSS_LINUX64) -c -o $@ $< + +obj/%.WIN.32.o: deps/git/xxHash/%.c + $(CC_WIN_32) $(CFLAGS_CROSS_WIN32) -c -o $@ $< + +obj/%.WIN.64.o: deps/git/xxHash/%.c + $(CC_WIN_64) $(CFLAGS_CROSS_WIN64) -c -o $@ $< +endif + ifeq ($(SYSTEM_LZMA_SDK),0) obj/%.LINUX.32.o: deps/lzma_sdk/%.c $(CC_LINUX_32) $(CFLAGS_CROSS_LINUX32) -c -o $@ $< diff --git a/src/brain.c b/src/brain.c new file mode 100644 index 000000000..eb179e03b --- /dev/null +++ b/src/brain.c @@ -0,0 +1,3209 @@ +/** + * Author......: See docs/credits.txt + * License.....: MIT + */ + +#include "common.h" +#include "types.h" +#include "timer.h" +#include "memory.h" +#include "thread.h" +#include "bitops.h" +#include "convert.h" +#include "shared.h" +#include "interface.h" +#include "hashes.h" +#include "shared.h" +#include "brain.h" + +static bool keep_running = true; + +static hc_timer_t timer_logging; + +static hc_thread_mutex_t mux_display; + +int brain_logging (FILE *stream, const int client_fd, const char *format, ...) +{ + const double ms = hc_timer_get (timer_logging); + + hc_timer_set (&timer_logging); + + hc_thread_mutex_lock (mux_display); + + struct timeval v; + + gettimeofday (&v, NULL); + + fprintf (stream, "%d.%06d | %6.2fs | %3d | ", (u32) v.tv_sec, (u32) v.tv_usec, ms / 1000, client_fd); + + va_list ap; + + va_start (ap, format); + + const int len = vfprintf (stream, format, ap); + + va_end (ap); + + hc_thread_mutex_unlock (mux_display); + + return len; +} + +u32 brain_compute_session (hashcat_ctx_t *hashcat_ctx) +{ + hashes_t *hashes = hashcat_ctx->hashes; + hashconfig_t *hashconfig = hashcat_ctx->hashconfig; + user_options_t *user_options = hashcat_ctx->user_options; + + if (user_options->brain_session != 0) return user_options->brain_session; + + const u64 seed = (const u64) hashconfig->hash_mode; + + XXH64_state_t *state = XXH64_createState (); + + XXH64_reset (state, seed); + + if (hashconfig->opts_type & OPTS_TYPE_BINARY_HASHFILE) + { + // digest + + u32 digests_cnt = hashes->digests_cnt; + u32 *digests_buf = hashes->digests_buf; + + XXH64_update (state, digests_buf, digests_cnt * hashconfig->dgst_size); + + // salt + + u32 salts_cnt = hashes->salts_cnt; + salt_t *salts_buf = hashes->salts_buf; + + for (u32 salts_idx = 0; salts_idx < salts_cnt; salts_idx++) + { + salt_t *salt = salts_buf + salts_idx; + + XXH64_update (state, &salt->salt_iter, sizeof (salt->salt_iter)); + XXH64_update (state, salt->salt_buf, sizeof (salt->salt_buf)); + } + + // esalt + + if (hashconfig->esalt_size > 0) + { + void *esalts_buf = hashes->esalts_buf; + + XXH64_update (state, esalts_buf, digests_cnt * hashconfig->esalt_size); + } + } + else + { + // using ascii_digest is an easy workaround for dealing with optimizations + // like OPTI_TYPE_PRECOMPUTE_MERKLE which cause diffrent hashes in digests_buf + // in case -O is used + + char **out_bufs = (char **) hccalloc (hashes->digests_cnt, sizeof (char *)); + + int out_idx = 0; + + u8 *out_buf = (u8 *) hcmalloc (HCBUFSIZ_LARGE); + + u32 salts_cnt = hashes->salts_cnt; + + for (u32 salts_idx = 0; salts_idx < salts_cnt; salts_idx++) + { + salt_t *salt_buf = &hashes->salts_buf[salts_idx]; + + for (u32 digest_idx = 0; digest_idx < salt_buf->digests_cnt; digest_idx++) + { + ascii_digest (hashcat_ctx, (char *) out_buf, HCBUFSIZ_LARGE, salts_idx, digest_idx); + + out_bufs[out_idx] = hcstrdup ((char *) out_buf); + } + } + + hcfree (out_buf); + + qsort (out_bufs, out_idx, sizeof (char *), sort_by_string); + + for (int i = 0; i < out_idx; i++) + { + const size_t out_len = strlen (out_bufs[out_idx]); + + XXH64_update (state, out_bufs[out_idx], out_len); + + hcfree (out_bufs[out_idx]); + } + + hcfree (out_bufs); + } + + const u32 session = (const u32) XXH64_digest (state); + + XXH64_freeState (state); + + return session; +} + +u32 brain_compute_attack (hashcat_ctx_t *hashcat_ctx) +{ + const combinator_ctx_t *combinator_ctx = hashcat_ctx->combinator_ctx; + const mask_ctx_t *mask_ctx = hashcat_ctx->mask_ctx; + const straight_ctx_t *straight_ctx = hashcat_ctx->straight_ctx; + const user_options_t *user_options = hashcat_ctx->user_options; + + XXH64_state_t *state = XXH64_createState (); + + XXH64_reset (state, user_options->brain_session); + + const int hash_mode = user_options->hash_mode; + const int attack_mode = user_options->attack_mode; + + XXH64_update (state, &hash_mode, sizeof (hash_mode)); + XXH64_update (state, &attack_mode, sizeof (attack_mode)); + + const int skip = user_options->skip; + const int limit = user_options->limit; + + XXH64_update (state, &skip, sizeof (skip)); + XXH64_update (state, &limit, sizeof (limit)); + + const int hex_salt = user_options->hex_salt; + + XXH64_update (state, &hex_salt, sizeof (hex_salt)); + + const int hccapx_message_pair = user_options->hccapx_message_pair; + + XXH64_update (state, &hccapx_message_pair, sizeof (hccapx_message_pair)); + + const int nonce_error_corrections = user_options->nonce_error_corrections; + + XXH64_update (state, &nonce_error_corrections, sizeof (nonce_error_corrections)); + + const int veracrypt_pim = user_options->veracrypt_pim; + + XXH64_update (state, &veracrypt_pim, sizeof (veracrypt_pim)); + + if (user_options->attack_mode == ATTACK_MODE_STRAIGHT) + { + if (straight_ctx->dict) + { + const u64 wordlist_hash = brain_compute_attack_wordlist (straight_ctx->dict); + + XXH64_update (state, &wordlist_hash, sizeof (wordlist_hash)); + } + + const int hex_wordlist = user_options->hex_wordlist; + + XXH64_update (state, &hex_wordlist, sizeof (hex_wordlist)); + + const int wordlist_autohex_disable = user_options->wordlist_autohex_disable; + + XXH64_update (state, &wordlist_autohex_disable, sizeof (wordlist_autohex_disable)); + + if (user_options->encoding_from) + { + const char *encoding_from = user_options->encoding_from; + + XXH64_update (state, encoding_from, strlen (encoding_from)); + } + + if (user_options->encoding_to) + { + const char *encoding_to = user_options->encoding_to; + + XXH64_update (state, encoding_to, strlen (encoding_to)); + } + + if (user_options->rule_buf_l) + { + const char *rule_buf_l = user_options->rule_buf_l; + + XXH64_update (state, rule_buf_l, strlen (rule_buf_l)); + } + + if (user_options->rule_buf_r) + { + const char *rule_buf_r = user_options->rule_buf_r; + + XXH64_update (state, rule_buf_r, strlen (rule_buf_r)); + } + + const int loopback = user_options->loopback; + + XXH64_update (state, &loopback, sizeof (loopback)); + + XXH64_update (state, straight_ctx->kernel_rules_buf, straight_ctx->kernel_rules_cnt * sizeof (kernel_rule_t)); + } + else if (user_options->attack_mode == ATTACK_MODE_COMBI) + { + const u64 wordlist1_hash = brain_compute_attack_wordlist (combinator_ctx->dict1); + const u64 wordlist2_hash = brain_compute_attack_wordlist (combinator_ctx->dict2); + + XXH64_update (state, &wordlist1_hash, sizeof (wordlist1_hash)); + XXH64_update (state, &wordlist2_hash, sizeof (wordlist2_hash)); + + const int hex_wordlist = user_options->hex_wordlist; + + XXH64_update (state, &hex_wordlist, sizeof (hex_wordlist)); + + const int wordlist_autohex_disable = user_options->wordlist_autohex_disable; + + XXH64_update (state, &wordlist_autohex_disable, sizeof (wordlist_autohex_disable)); + + if (user_options->encoding_from) + { + const char *encoding_from = user_options->encoding_from; + + XXH64_update (state, encoding_from, strlen (encoding_from)); + } + + if (user_options->encoding_to) + { + const char *encoding_to = user_options->encoding_to; + + XXH64_update (state, encoding_to, strlen (encoding_to)); + } + + if (user_options->rule_buf_l) + { + const char *rule_buf_l = user_options->rule_buf_l; + + XXH64_update (state, rule_buf_l, strlen (rule_buf_l)); + } + + if (user_options->rule_buf_r) + { + const char *rule_buf_r = user_options->rule_buf_r; + + XXH64_update (state, rule_buf_r, strlen (rule_buf_r)); + } + } + else if (user_options->attack_mode == ATTACK_MODE_BF) + { + const char *mask = mask_ctx->mask; + + XXH64_update (state, mask, strlen (mask)); + + const int hex_charset = user_options->hex_charset; + + XXH64_update (state, &hex_charset, sizeof (hex_charset)); + + const int markov_classic = user_options->markov_classic; + const int markov_disable = user_options->markov_disable; + const int markov_threshold = user_options->markov_threshold; + + XXH64_update (state, &markov_classic, sizeof (markov_classic)); + XXH64_update (state, &markov_disable, sizeof (markov_disable)); + XXH64_update (state, &markov_threshold, sizeof (markov_threshold)); + + if (user_options->markov_hcstat2) + { + const char *markov_hcstat2 = filename_from_filepath (user_options->markov_hcstat2); + + XXH64_update (state, markov_hcstat2, strlen (markov_hcstat2)); + } + + if (user_options->custom_charset_1) + { + const char *custom_charset_1 = user_options->custom_charset_1; + + XXH64_update (state, custom_charset_1, strlen (custom_charset_1)); + } + + if (user_options->custom_charset_2) + { + const char *custom_charset_2 = user_options->custom_charset_2; + + XXH64_update (state, custom_charset_2, strlen (custom_charset_2)); + } + + if (user_options->custom_charset_3) + { + const char *custom_charset_3 = user_options->custom_charset_3; + + XXH64_update (state, custom_charset_3, strlen (custom_charset_3)); + } + + if (user_options->custom_charset_4) + { + const char *custom_charset_4 = user_options->custom_charset_4; + + XXH64_update (state, custom_charset_4, strlen (custom_charset_4)); + } + } + else if (user_options->attack_mode == ATTACK_MODE_HYBRID1) + { + const u64 wordlist_hash = brain_compute_attack_wordlist (straight_ctx->dict); + + XXH64_update (state, &wordlist_hash, sizeof (wordlist_hash)); + + const char *mask = mask_ctx->mask; + + XXH64_update (state, mask, strlen (mask)); + + const int hex_charset = user_options->hex_charset; + + XXH64_update (state, &hex_charset, sizeof (hex_charset)); + + const int markov_classic = user_options->markov_classic; + const int markov_disable = user_options->markov_disable; + const int markov_threshold = user_options->markov_threshold; + + XXH64_update (state, &markov_classic, sizeof (markov_classic)); + XXH64_update (state, &markov_disable, sizeof (markov_disable)); + XXH64_update (state, &markov_threshold, sizeof (markov_threshold)); + + if (user_options->markov_hcstat2) + { + const char *markov_hcstat2 = filename_from_filepath (user_options->markov_hcstat2); + + XXH64_update (state, markov_hcstat2, strlen (markov_hcstat2)); + } + + if (user_options->custom_charset_1) + { + const char *custom_charset_1 = user_options->custom_charset_1; + + XXH64_update (state, custom_charset_1, strlen (custom_charset_1)); + } + + if (user_options->custom_charset_2) + { + const char *custom_charset_2 = user_options->custom_charset_2; + + XXH64_update (state, custom_charset_2, strlen (custom_charset_2)); + } + + if (user_options->custom_charset_3) + { + const char *custom_charset_3 = user_options->custom_charset_3; + + XXH64_update (state, custom_charset_3, strlen (custom_charset_3)); + } + + if (user_options->custom_charset_4) + { + const char *custom_charset_4 = user_options->custom_charset_4; + + XXH64_update (state, custom_charset_4, strlen (custom_charset_4)); + } + + const int hex_wordlist = user_options->hex_wordlist; + + XXH64_update (state, &hex_wordlist, sizeof (hex_wordlist)); + + const int wordlist_autohex_disable = user_options->wordlist_autohex_disable; + + XXH64_update (state, &wordlist_autohex_disable, sizeof (wordlist_autohex_disable)); + + if (user_options->encoding_from) + { + const char *encoding_from = user_options->encoding_from; + + XXH64_update (state, encoding_from, strlen (encoding_from)); + } + + if (user_options->encoding_to) + { + const char *encoding_to = user_options->encoding_to; + + XXH64_update (state, encoding_to, strlen (encoding_to)); + } + + if (user_options->rule_buf_l) + { + const char *rule_buf_l = user_options->rule_buf_l; + + XXH64_update (state, rule_buf_l, strlen (rule_buf_l)); + } + + if (user_options->rule_buf_r) + { + const char *rule_buf_r = user_options->rule_buf_r; + + XXH64_update (state, rule_buf_r, strlen (rule_buf_r)); + } + } + else if (user_options->attack_mode == ATTACK_MODE_HYBRID2) + { + const char *mask = mask_ctx->mask; + + XXH64_update (state, mask, strlen (mask)); + + const u64 wordlist_hash = brain_compute_attack_wordlist (straight_ctx->dict); + + XXH64_update (state, &wordlist_hash, sizeof (wordlist_hash)); + + const int hex_charset = user_options->hex_charset; + + XXH64_update (state, &hex_charset, sizeof (hex_charset)); + + const int markov_classic = user_options->markov_classic; + const int markov_disable = user_options->markov_disable; + const int markov_threshold = user_options->markov_threshold; + + XXH64_update (state, &markov_classic, sizeof (markov_classic)); + XXH64_update (state, &markov_disable, sizeof (markov_disable)); + XXH64_update (state, &markov_threshold, sizeof (markov_threshold)); + + if (user_options->markov_hcstat2) + { + const char *markov_hcstat2 = filename_from_filepath (user_options->markov_hcstat2); + + XXH64_update (state, markov_hcstat2, strlen (markov_hcstat2)); + } + + if (user_options->custom_charset_1) + { + const char *custom_charset_1 = user_options->custom_charset_1; + + XXH64_update (state, custom_charset_1, strlen (custom_charset_1)); + } + + if (user_options->custom_charset_2) + { + const char *custom_charset_2 = user_options->custom_charset_2; + + XXH64_update (state, custom_charset_2, strlen (custom_charset_2)); + } + + if (user_options->custom_charset_3) + { + const char *custom_charset_3 = user_options->custom_charset_3; + + XXH64_update (state, custom_charset_3, strlen (custom_charset_3)); + } + + if (user_options->custom_charset_4) + { + const char *custom_charset_4 = user_options->custom_charset_4; + + XXH64_update (state, custom_charset_4, strlen (custom_charset_4)); + } + + const int hex_wordlist = user_options->hex_wordlist; + + XXH64_update (state, &hex_wordlist, sizeof (hex_wordlist)); + + const int wordlist_autohex_disable = user_options->wordlist_autohex_disable; + + XXH64_update (state, &wordlist_autohex_disable, sizeof (wordlist_autohex_disable)); + + if (user_options->encoding_from) + { + const char *encoding_from = user_options->encoding_from; + + XXH64_update (state, encoding_from, strlen (encoding_from)); + } + + if (user_options->encoding_to) + { + const char *encoding_to = user_options->encoding_to; + + XXH64_update (state, encoding_to, strlen (encoding_to)); + } + + if (user_options->rule_buf_l) + { + const char *rule_buf_l = user_options->rule_buf_l; + + XXH64_update (state, rule_buf_l, strlen (rule_buf_l)); + } + + if (user_options->rule_buf_r) + { + const char *rule_buf_r = user_options->rule_buf_r; + + XXH64_update (state, rule_buf_r, strlen (rule_buf_r)); + } + } + + const u32 brain_attack = (const u32) XXH64_digest (state); + + XXH64_freeState (state); + + return brain_attack; +} + +u64 brain_compute_attack_wordlist (const char *filename) +{ + XXH64_state_t *state = XXH64_createState (); + + XXH64_reset (state, 0); + + #define FBUFSZ 8192 + + char buf[FBUFSZ]; + + FILE *fd = fopen (filename, "rb"); + + size_t nread = fread (buf, sizeof (u8), FBUFSZ, fd); + + XXH64_update (state, buf, nread); + + while (nread <= 0) + { + XXH64_update (state, buf, nread); + + nread = fread (buf, sizeof (u8), FBUFSZ, fd); + } + + fclose (fd); + + const u64 hash = XXH64_digest (state); + + XXH64_freeState (state); + + return hash; +} + +u64 brain_auth_hash (const u32 challenge, const char *pw_buf, const int pw_len) +{ + // nothing for production but good enough for testing + + u64 response = XXH64 (pw_buf, pw_len, challenge); + + for (int i = 0; i < 100000; i++) + { + response = XXH64 (&response, 8, 0); + } + + return response; +} + +u32 brain_auth_challenge (void) +{ + srand (time (NULL)); + + u32 val = rand (); // just a fallback value + + #if defined (_WIN) + + // from + + HCRYPTPROV hCryptProv; + + if (CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0) == true) + { + if (CryptGenRandom (hCryptProv, sizeof (val), (BYTE *) &val) == true) + { + // all good + } + else + { + brain_logging (stderr, 0, "CryptGenRandom: %d\n", (int) GetLastError ()); + + return val; + } + + CryptReleaseContext (hCryptProv, 0); + } + else + { + brain_logging (stderr, 0, "CryptAcquireContext: %d\n", (int) GetLastError ()); + + return val; + } + + #else + + static const char *urandom = "/dev/urandom"; + + FILE *fd = fopen (urandom, "rb"); + + if (fd == NULL) + { + brain_logging (stderr, 0, "%s: %s\n", urandom, strerror (errno)); + + return val; + } + + if (fread (&val, sizeof (val), 1, fd) != 1) + { + brain_logging (stderr, 0, "%s: %s\n", urandom, strerror (errno)); + + fclose (fd); + + return val; + } + + fclose (fd); + + #endif + + return val; +} + +int brain_connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen, const int timeout) +{ + #if defined (_WIN) + + if (timeout == 99999999) + { + // timeout not support on windows + } + + const int rc_connect = connect (sockfd, addr, addrlen); + + if (rc_connect == SOCKET_ERROR) + { + int err = WSAGetLastError (); + + char msg[256] = { 0 }; + + FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, // flags + NULL, // lpsource + err, // message id + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // languageid + msg, // output buffer + sizeof (msg), // size of msgbuf, bytes + NULL); // va_list of arguments + + brain_logging (stderr, 0, "connect: %s\n", msg); + + return -1; + } + + #else + + const int old_mode = fcntl (sockfd, F_GETFL, 0); + + if (fcntl (sockfd, F_SETFL, old_mode | O_NONBLOCK) == -1) + { + brain_logging (stderr, 0, "fcntl: %s\n", strerror (errno)); + + return -1; + } + + connect (sockfd, addr, addrlen); + + const int rc_select = select_write_timeout (sockfd, timeout); + + if (rc_select == -1) return -1; + + if (rc_select == 0) + { + brain_logging (stderr, 0, "connect: timeout\n"); + + return -1; + } + + int so_error; + + socklen_t len = sizeof (so_error); + + if (getsockopt (sockfd, SOL_SOCKET, SO_ERROR, &so_error, &len) == -1) + { + brain_logging (stderr, 0, "getsockopt: %s\n", strerror (errno)); + + return -1; + } + + if (fcntl (sockfd, F_SETFL, old_mode) == -1) + { + brain_logging (stderr, 0, "fcntl: %s\n", strerror (errno)); + + return -1; + } + + if (so_error != 0) + { + brain_logging (stderr, 0, "connect: %s\n", strerror (so_error)); + + return -1; + } + + #endif + + return 0; +} + +bool brain_send (int sockfd, void *buf, size_t len, int flags, hc_device_param_t *device_param, const status_ctx_t *status_ctx) +{ + char *ptr = (char *) buf; + + ssize_t s_pos; + ssize_t s_len = len; + + for (s_pos = 0; s_pos < s_len - BRAIN_LINK_CHUNK_SIZE; s_pos += BRAIN_LINK_CHUNK_SIZE) + { + if (brain_send_all (sockfd, ptr + s_pos, BRAIN_LINK_CHUNK_SIZE, flags, device_param, status_ctx) == false) return false; + + if (status_ctx) if (status_ctx->run_thread_level1 == false) return false; + } + + if (brain_send_all (sockfd, ptr + s_pos, s_len - s_pos, flags, device_param, status_ctx) == false) return false; + + if (status_ctx) if (status_ctx->run_thread_level1 == false) return false; + + return true; +} + +bool brain_recv (int sockfd, void *buf, size_t len, int flags, hc_device_param_t *device_param, const status_ctx_t *status_ctx) +{ + char *ptr = (char *) buf; + + ssize_t s_pos; + ssize_t s_len = len; + + for (s_pos = 0; s_pos < s_len - BRAIN_LINK_CHUNK_SIZE; s_pos += BRAIN_LINK_CHUNK_SIZE) + { + if (brain_recv_all (sockfd, ptr + s_pos, BRAIN_LINK_CHUNK_SIZE, flags, device_param, status_ctx) == false) return false; + + if (status_ctx) if (status_ctx->run_thread_level1 == false) return false; + } + + if (brain_recv_all (sockfd, ptr + s_pos, s_len - s_pos, flags, device_param, status_ctx) == false) return false; + + if (status_ctx) if (status_ctx->run_thread_level1 == false) return false; + + return true; +} + +bool brain_send_all (int sockfd, void *buf, size_t len, int flags, hc_device_param_t *device_param, const status_ctx_t *status_ctx) +{ + link_speed_t *link_speed = &device_param->brain_link_send_speed; + + if (device_param) + { + device_param->brain_link_send_active = true; + + hc_timer_set (&link_speed->timer[link_speed->pos]); + } + + ssize_t nsend = send (sockfd, buf, len, flags); + + if (device_param) + { + link_speed->bytes[link_speed->pos] = nsend; + + if (link_speed->pos++ == LINK_SPEED_COUNT) link_speed->pos = 0; + + device_param->brain_link_send_bytes += nsend; + } + + if (nsend <= 0) return false; + + if (status_ctx) if (status_ctx->run_thread_level1 == false) return false; + + while (nsend < (ssize_t) len) + { + char *buf_new = (char *) buf; + + if (device_param) + { + hc_timer_set (&link_speed->timer[link_speed->pos]); + } + + ssize_t nsend_new = send (sockfd, buf_new + nsend, len - nsend, flags); + + if (device_param) + { + link_speed->bytes[link_speed->pos] = nsend_new; + + if (link_speed->pos++ == LINK_SPEED_COUNT) link_speed->pos = 0; + + device_param->brain_link_send_bytes += nsend_new; + } + + if (nsend_new <= 0) return false; + + if (status_ctx) if (status_ctx->run_thread_level1 == false) break; + + nsend += nsend_new; + } + + if (device_param) + { + device_param->brain_link_send_active = false; + } + + return true; +} + +bool brain_recv_all (int sockfd, void *buf, size_t len, int flags, hc_device_param_t *device_param, const status_ctx_t *status_ctx) +{ + link_speed_t *link_speed = &device_param->brain_link_recv_speed; + + if (device_param) + { + device_param->brain_link_recv_active = true; + + hc_timer_set (&link_speed->timer[link_speed->pos]); + } + + ssize_t nrecv = recv (sockfd, buf, len, flags); + + if (device_param) + { + link_speed->bytes[link_speed->pos] = nrecv; + + if (link_speed->pos++ == LINK_SPEED_COUNT) link_speed->pos = 0; + + device_param->brain_link_recv_bytes += nrecv; + } + + if (nrecv <= 0) return false; + + if (status_ctx) if (status_ctx->run_thread_level1 == false) return false; + + while (nrecv < (ssize_t) len) + { + char *buf_new = (char *) buf; + + if (device_param) + { + hc_timer_set (&link_speed->timer[link_speed->pos]); + } + + ssize_t nrecv_new = recv (sockfd, buf_new + nrecv, len - nrecv, flags); + + if (device_param) + { + link_speed->bytes[link_speed->pos] = nrecv_new; + + if (link_speed->pos++ == LINK_SPEED_COUNT) link_speed->pos = 0; + + device_param->brain_link_recv_bytes += nrecv_new; + } + + if (nrecv_new <= 0) return false; + + if (status_ctx) if (status_ctx->run_thread_level1 == false) break; + + nrecv += nrecv_new; + } + + if (device_param) + { + device_param->brain_link_recv_active = false; + } + + return true; +} + +bool brain_client_connect (hc_device_param_t *device_param, const status_ctx_t *status_ctx, const char *host, const int port, const char *password, u32 brain_session, u32 brain_attack, i64 passwords_max, u64 *highest) +{ + device_param->brain_link_client_fd = -1; + device_param->brain_link_recv_bytes = 0; + device_param->brain_link_send_bytes = 0; + device_param->brain_link_recv_active = false; + device_param->brain_link_send_active = false; + + memset (&device_param->brain_link_recv_speed, 0, sizeof (link_speed_t)); + memset (&device_param->brain_link_send_speed, 0, sizeof (link_speed_t)); + + const int brain_link_client_fd = socket (AF_INET, SOCK_STREAM, 0); + + if (brain_link_client_fd == -1) + { + brain_logging (stderr, 0, "socket: %s\n", strerror (errno)); + + return false; + } + + #if defined (_WIN) + + #else + const int one = 1; + + if (setsockopt (brain_link_client_fd, SOL_TCP, TCP_NODELAY, &one, sizeof (one)) == -1) + { + brain_logging (stderr, 0, "setsockopt: %s\n", strerror (errno)); + + close (brain_link_client_fd); + + return false; + } + #endif + + struct addrinfo hints; + + memset (&hints, 0, sizeof (hints)); + + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + char port_str[8]; + + snprintf (port_str, sizeof (port_str) - 1, "%i", port); + + const char *host_real = (host == NULL) ? "127.0.0.1" : (const char *) host; + + bool connected = false; + + struct addrinfo *address_info; + + const int rc_getaddrinfo = getaddrinfo (host_real, port_str, &hints, &address_info); + + if (rc_getaddrinfo == 0) + { + struct addrinfo *address_info_ptr; + + for (address_info_ptr = address_info; address_info_ptr != NULL; address_info_ptr = address_info_ptr->ai_next) + { + if (brain_connect (brain_link_client_fd, address_info_ptr->ai_addr, address_info_ptr->ai_addrlen, BRAIN_CLIENT_CONNECT_TIMEOUT) == 0) + { + connected = true; + + break; + } + } + + freeaddrinfo (address_info); + } + else + { + brain_logging (stderr, 0, "%s: %s\n", host_real, gai_strerror (rc_getaddrinfo)); + + close (brain_link_client_fd); + + return false; + } + + if (connected == false) + { + close (brain_link_client_fd); + + return false; + } + + device_param->brain_link_client_fd = brain_link_client_fd; + + u32 brain_link_version = BRAIN_LINK_VERSION_CUR; + + if (brain_send (brain_link_client_fd, &brain_link_version, sizeof (brain_link_version), 0, NULL, NULL) == false) + { + brain_logging (stderr, 0, "brain_send: %s\n", strerror (errno)); + + close (brain_link_client_fd); + + return false; + } + + u32 brain_link_version_ok; + + if (brain_recv (brain_link_client_fd, &brain_link_version_ok, sizeof (brain_link_version_ok), 0, NULL, NULL) == false) + { + brain_logging (stderr, 0, "brain_recv: %s\n", strerror (errno)); + + close (brain_link_client_fd); + + return false; + } + + if (brain_link_version_ok == 0) + { + brain_logging (stderr, 0, "Invalid brain server version\n"); + + close (brain_link_client_fd); + + return false; + } + + u32 challenge; + + if (brain_recv (brain_link_client_fd, &challenge, sizeof (challenge), 0, NULL, NULL) == false) + { + brain_logging (stderr, 0, "brain_recv: %s\n", strerror (errno)); + + close (brain_link_client_fd); + + return false; + } + + u64 response = brain_auth_hash (challenge, password, strlen (password)); + + if (brain_send (brain_link_client_fd, &response, sizeof (response), 0, NULL, NULL) == false) + { + brain_logging (stderr, 0, "brain_send: %s\n", strerror (errno)); + + close (brain_link_client_fd); + + return false; + } + + u32 password_ok; + + if (brain_recv (brain_link_client_fd, &password_ok, sizeof (password_ok), 0, NULL, NULL) == false) + { + brain_logging (stderr, 0, "brain_recv: %s\n", strerror (errno)); + + close (brain_link_client_fd); + + return false; + } + + if (password_ok == 0) + { + brain_logging (stderr, 0, "Invalid brain server password\n"); + + close (brain_link_client_fd); + + return false; + } + + if (brain_send (brain_link_client_fd, &brain_session, sizeof (brain_session), SEND_FLAGS, device_param, status_ctx) == false) + { + brain_logging (stderr, 0, "brain_send: %s\n", strerror (errno)); + + close (brain_link_client_fd); + + return false; + } + + if (brain_send (brain_link_client_fd, &brain_attack, sizeof (brain_attack), SEND_FLAGS, device_param, status_ctx) == false) + { + brain_logging (stderr, 0, "brain_send: %s\n", strerror (errno)); + + close (brain_link_client_fd); + + return false; + } + + if (brain_send (brain_link_client_fd, &passwords_max, sizeof (passwords_max), SEND_FLAGS, device_param, status_ctx) == false) + { + brain_logging (stderr, 0, "brain_send: %s\n", strerror (errno)); + + close (brain_link_client_fd); + + return false; + } + + if (brain_recv (brain_link_client_fd, highest, sizeof (u64), 0, NULL, NULL) == false) + { + brain_logging (stderr, 0, "brain_recv: %s\n", strerror (errno)); + + close (brain_link_client_fd); + + return false; + } + + return true; +} + +void brain_client_disconnect (hc_device_param_t *device_param) +{ + if (device_param->brain_link_client_fd >= 3) + { + close (device_param->brain_link_client_fd); + } + + device_param->brain_link_client_fd = -1; +} + +bool brain_client_reserve (hc_device_param_t *device_param, const status_ctx_t *status_ctx, u64 words_off, u64 work, u64 *overlap) +{ + const int brain_link_client_fd = device_param->brain_link_client_fd; + + if (brain_link_client_fd == -1) return false; + + u8 operation = BRAIN_OPERATION_ATTACK_RESERVE; + + if (brain_send (brain_link_client_fd, &operation, sizeof (operation), SEND_FLAGS, device_param, status_ctx) == false) return false; + + if (brain_send (brain_link_client_fd, &words_off, sizeof (words_off), 0, device_param, status_ctx) == false) return false; + + if (brain_send (brain_link_client_fd, &work, sizeof (work), 0, device_param, status_ctx) == false) return false; + + if (brain_recv (brain_link_client_fd, overlap, sizeof (u64), 0, device_param, status_ctx) == false) return false; + + return true; +} + +bool brain_client_commit (hc_device_param_t *device_param, const status_ctx_t *status_ctx) +{ + if (device_param->pws_cnt == 0) return true; + + const int brain_link_client_fd = device_param->brain_link_client_fd; + + if (brain_link_client_fd == -1) return false; + + u8 operation = BRAIN_OPERATION_COMMIT; + + if (brain_send (brain_link_client_fd, &operation, sizeof (operation), SEND_FLAGS, device_param, status_ctx) == false) return false; + + return true; +} + +bool brain_client_lookup (hc_device_param_t *device_param, const status_ctx_t *status_ctx) +{ + if (device_param->pws_pre_cnt == 0) return true; + + const int brain_link_client_fd = device_param->brain_link_client_fd; + + if (brain_link_client_fd == -1) return false; + + char *recvbuf = (char *) device_param->brain_link_in_buf; + char *sendbuf = (char *) device_param->brain_link_out_buf; + + int out_size = device_param->pws_pre_cnt * BRAIN_HASH_SIZE; + + u8 operation = BRAIN_OPERATION_HASH_LOOKUP; + + if (brain_send (brain_link_client_fd, &operation, sizeof (operation), SEND_FLAGS, device_param, status_ctx) == false) return false; + + if (brain_send (brain_link_client_fd, &out_size, sizeof (out_size), SEND_FLAGS, device_param, status_ctx) == false) return false; + + if (brain_send (brain_link_client_fd, sendbuf, out_size, SEND_FLAGS, device_param, status_ctx) == false) return false; + + int in_size; + + if (brain_recv (brain_link_client_fd, &in_size, sizeof (in_size), 0, device_param, status_ctx) == false) return false; + + if (in_size > (int) device_param->size_brain_link_in) return false; + + if (brain_recv (brain_link_client_fd, recvbuf, (size_t) in_size, 0, device_param, status_ctx) == false) return false; + + return true; +} + +void brain_client_generate_hash (u64 *hash, const char *line_buf, const size_t line_len) +{ + const u64 seed = 0; + + hash[0] = XXH64 (line_buf, line_len, seed); +} + +void brain_server_db_hash_init (brain_server_db_hash_t *brain_server_db_hash, const u32 brain_session) +{ + brain_server_db_hash->brain_session = brain_session; + + brain_server_db_hash->long_alloc = 0; + brain_server_db_hash->long_cnt = 0; + brain_server_db_hash->long_buf = NULL; + + brain_server_db_hash->write_hashes = false; + + brain_server_db_hash->hb = 0; + + hc_thread_mutex_init (brain_server_db_hash->mux_hr); + hc_thread_mutex_init (brain_server_db_hash->mux_hg); +} + +bool brain_server_db_hash_realloc (brain_server_db_hash_t *brain_server_db_hash, const i64 new_long_cnt) +{ + if ((brain_server_db_hash->long_cnt + new_long_cnt) > brain_server_db_hash->long_alloc) + { + const i64 realloc_size_total = (i64) mydivc64 ((const u64) new_long_cnt, (const u64) BRAIN_SERVER_REALLOC_HASH_SIZE) * BRAIN_SERVER_REALLOC_HASH_SIZE; + + brain_server_hash_long_t *long_buf = (brain_server_hash_long_t *) hcrealloc (brain_server_db_hash->long_buf, brain_server_db_hash->long_alloc * sizeof (brain_server_hash_long_t), realloc_size_total * sizeof (brain_server_hash_long_t)); + + if (long_buf == NULL) return false; + + brain_server_db_hash->long_buf = long_buf; + + brain_server_db_hash->long_alloc += realloc_size_total; + } + + return true; +} + +void brain_server_db_hash_free (brain_server_db_hash_t *brain_server_db_hash) +{ + hc_thread_mutex_delete (brain_server_db_hash->mux_hg); + hc_thread_mutex_delete (brain_server_db_hash->mux_hr); + + brain_server_db_hash->hb = 0; + + hcfree (brain_server_db_hash->long_buf); + + brain_server_db_hash->long_alloc = 0; + brain_server_db_hash->long_cnt = 0; + brain_server_db_hash->long_buf = NULL; + + brain_server_db_hash->write_hashes = false; + + brain_server_db_hash->brain_session = 0; +} + +void brain_server_db_attack_init (brain_server_db_attack_t *brain_server_db_attack, const u32 brain_attack) +{ + brain_server_db_attack->brain_attack = brain_attack; + + brain_server_db_attack->short_alloc = 0; + brain_server_db_attack->short_cnt = 0; + brain_server_db_attack->short_buf = NULL; + + brain_server_db_attack->long_alloc = 0; + brain_server_db_attack->long_cnt = 0; + brain_server_db_attack->long_buf = NULL; + + brain_server_db_attack->write_attacks = false; + + brain_server_db_attack->ab = 0; + + hc_thread_mutex_init (brain_server_db_attack->mux_ar); + hc_thread_mutex_init (brain_server_db_attack->mux_ag); +} + +bool brain_server_db_attack_realloc (brain_server_db_attack_t *brain_server_db_attack, const i64 new_long_cnt, const i64 new_short_cnt) +{ + if ((brain_server_db_attack->long_cnt + new_long_cnt) > brain_server_db_attack->long_alloc) + { + const i64 realloc_size_total = (i64) mydivc64 ((const u64) new_long_cnt, (const u64) BRAIN_SERVER_REALLOC_ATTACK_SIZE) * BRAIN_SERVER_REALLOC_ATTACK_SIZE; + + brain_server_attack_long_t *long_buf = (brain_server_attack_long_t *) hcrealloc (brain_server_db_attack->long_buf, brain_server_db_attack->long_alloc * sizeof (brain_server_attack_long_t), realloc_size_total * sizeof (brain_server_attack_long_t)); + + if (long_buf == NULL) return false; + + brain_server_db_attack->long_buf = long_buf; + + brain_server_db_attack->long_alloc += realloc_size_total; + } + + if ((brain_server_db_attack->short_cnt + new_short_cnt) > brain_server_db_attack->short_alloc) + { + const i64 realloc_size_total = (i64) mydivc64 ((const u64) new_short_cnt, (const u64) BRAIN_SERVER_REALLOC_ATTACK_SIZE) * BRAIN_SERVER_REALLOC_ATTACK_SIZE; + + brain_server_attack_short_t *short_buf = (brain_server_attack_short_t *) hcrealloc (brain_server_db_attack->short_buf, brain_server_db_attack->short_alloc * sizeof (brain_server_attack_short_t), realloc_size_total * sizeof (brain_server_attack_short_t)); + + if (short_buf == NULL) return false; + + brain_server_db_attack->short_buf = short_buf; + + brain_server_db_attack->short_alloc += realloc_size_total; + } + + return true; +} + +void brain_server_db_attack_free (brain_server_db_attack_t *brain_server_db_attack) +{ + hc_thread_mutex_delete (brain_server_db_attack->mux_ag); + hc_thread_mutex_delete (brain_server_db_attack->mux_ar); + + brain_server_db_attack->ab = 0; + + hcfree (brain_server_db_attack->long_buf); + + brain_server_db_attack->long_alloc = 0; + brain_server_db_attack->long_cnt = 0; + brain_server_db_attack->long_buf = NULL; + + hcfree (brain_server_db_attack->short_buf); + + brain_server_db_attack->short_alloc = 0; + brain_server_db_attack->short_cnt = 0; + brain_server_db_attack->short_buf = NULL; + + brain_server_db_attack->write_attacks = false; + + brain_server_db_attack->brain_attack = 0; +} + +u64 brain_server_highest_attack (const brain_server_db_attack_t *buf) +{ + const brain_server_attack_long_t *long_buf = buf->long_buf; + const brain_server_attack_short_t *short_buf = buf->short_buf; + + const u64 long_cnt = buf->long_cnt; + const u64 short_cnt = buf->short_cnt; + + u64 highest_long = brain_server_highest_attack_long (long_buf, long_cnt, 0); + u64 highest_short = brain_server_highest_attack_short (short_buf, short_cnt, 0); + + u64 highest = MAX (highest_long, highest_short); + + highest_long = brain_server_highest_attack_long (long_buf, long_cnt, highest); + highest_short = brain_server_highest_attack_short (short_buf, short_cnt, highest); + + highest = MAX (highest_long, highest_short); + + return highest; +} + +u64 brain_server_highest_attack_long (const brain_server_attack_long_t *buf, const i64 cnt, const u64 start) +{ + u64 highest = start; + + for (i64 idx = 0; idx < cnt; idx++) + { + const u64 offset = buf[idx].offset; + const u64 length = buf[idx].length; + + if (offset > highest) break; + + const u64 next = offset + length; + + highest = MAX (highest, next); + } + + return highest; +} + +u64 brain_server_highest_attack_short (const brain_server_attack_short_t *buf, const i64 cnt, const u64 start) +{ + u64 highest = start; + + for (i64 idx = 0; idx < cnt; idx++) + { + const u64 offset = buf[idx].offset; + const u64 length = buf[idx].length; + + if (offset > highest) break; + + const u64 next = offset + length; + + highest = MAX (highest, next); + } + + return highest; +} + +u64 brain_server_find_attack_long (const brain_server_attack_long_t *buf, const i64 cnt, const u64 offset, const u64 length) +{ + const u64 end = offset + length; + + u64 overlap = 0; + + for (i64 idx = 0; idx < cnt; idx++) + { + const u64 element_length = buf[idx].length; + + if (element_length == 0) continue; + + const u64 element_start = buf[idx].offset; + const u64 element_end = element_start + element_length; + + const u64 start = offset + overlap; + + if (element_start > start) break; // we can't ever do it since this list is sorted + + if (element_end > start) + { + const u64 limited_end = MIN (end, element_end); + + overlap += limited_end - start; + + if (overlap == length) break; + } + } + + return overlap; +} + +u64 brain_server_find_attack_short (const brain_server_attack_short_t *buf, const i64 cnt, const u64 offset, const u64 length) +{ + const u64 end = offset + length; + + u64 overlap = 0; + + for (i64 idx = 0; idx < cnt; idx++) + { + const u64 element_length = buf[idx].length; + + if (element_length == 0) continue; + + const u64 element_start = buf[idx].offset; + const u64 element_end = element_start + element_length; + + const u64 start = offset + overlap; + + if (element_start > start) break; // we can't ever do it since this list is sorted + + if (element_end > start) + { + const u64 limited_end = MIN (end, element_end); + + overlap += limited_end - start; + + if (overlap == length) break; + } + } + + return overlap; +} + +int brain_server_sort_db_hash (const void *v1, const void *v2) +{ + const brain_server_db_hash_t *d1 = (const brain_server_db_hash_t *) v1; + const brain_server_db_hash_t *d2 = (const brain_server_db_hash_t *) v2; + + if (d1->brain_session > d2->brain_session) return 1; + if (d1->brain_session < d2->brain_session) return -1; + + return 0; +} + +int brain_server_sort_db_attack (const void *v1, const void *v2) +{ + const brain_server_db_attack_t *d1 = (const brain_server_db_attack_t *) v1; + const brain_server_db_attack_t *d2 = (const brain_server_db_attack_t *) v2; + + if (d1->brain_attack > d2->brain_attack) return 1; + if (d1->brain_attack < d2->brain_attack) return -1; + + return 0; +} + +int brain_server_sort_hash (const void *v1, const void *v2) +{ + const u32 *d1 = (const u32 *) v1; + const u32 *d2 = (const u32 *) v2; + + if (d1[1] > d2[1]) return 1; + if (d1[1] < d2[1]) return -1; + if (d1[0] > d2[0]) return 1; + if (d1[0] < d2[0]) return -1; + + return 0; +} + +int brain_server_sort_attack_long (const void *v1, const void *v2) +{ + const brain_server_attack_long_t *d1 = (const brain_server_attack_long_t *) v1; + const brain_server_attack_long_t *d2 = (const brain_server_attack_long_t *) v2; + + if (d1->offset > d2->offset) return 1; + if (d1->offset < d2->offset) return -1; + + return 0; +} + +int brain_server_sort_attack_short (const void *v1, const void *v2) +{ + const brain_server_attack_short_t *d1 = (const brain_server_attack_short_t *) v1; + const brain_server_attack_short_t *d2 = (const brain_server_attack_short_t *) v2; + + if (d1->offset > d2->offset) return 1; + if (d1->offset < d2->offset) return -1; + + return 0; +} + +int brain_server_sort_hash_long (const void *v1, const void *v2) +{ + const brain_server_hash_long_t *d1 = (const brain_server_hash_long_t *) v1; + const brain_server_hash_long_t *d2 = (const brain_server_hash_long_t *) v2; + + return brain_server_sort_hash (d1->hash, d2->hash); +} + +int brain_server_sort_hash_short (const void *v1, const void *v2) +{ + const brain_server_hash_short_t *d1 = (const brain_server_hash_short_t *) v1; + const brain_server_hash_short_t *d2 = (const brain_server_hash_short_t *) v2; + + return brain_server_sort_hash (d1->hash, d2->hash); +} + +int brain_server_sort_hash_unique (const void *v1, const void *v2) +{ + const brain_server_hash_unique_t *d1 = (const brain_server_hash_unique_t *) v1; + const brain_server_hash_unique_t *d2 = (const brain_server_hash_unique_t *) v2; + + return brain_server_sort_hash (d1->hash, d2->hash); +} + +bool brain_server_read_hash_dumps (brain_server_dbs_t *brain_server_dbs, const char *path) +{ + brain_server_dbs->hash_cnt = 0; + + if (chdir (path) == -1) + { + brain_logging (stderr, 0, "%s: %s\n", path, strerror (errno)); + + return false; + } + + DIR *dirp = opendir (path); + + if (dirp == NULL) + { + brain_logging (stderr, 0, "%s: %s\n", path, strerror (errno)); + + return false; + } + + struct dirent *entry; + + while ((entry = readdir (dirp)) != NULL) + { + char *file = entry->d_name; + + const size_t len = strlen (file); + + if (len != 19) continue; + + if (file[ 0] != 'b') continue; + if (file[ 1] != 'r') continue; + if (file[ 2] != 'a') continue; + if (file[ 3] != 'i') continue; + if (file[ 4] != 'n') continue; + if (file[ 5] != '.') continue; + + if (file[14] != '.') continue; + if (file[15] != 'l') continue; + if (file[16] != 'd') continue; + if (file[17] != 'm') continue; + if (file[18] != 'p') continue; + + const u32 brain_session = byte_swap_32 (hex_to_u32 ((const u8 *) file + 6)); + + brain_server_db_hash_t *brain_server_db_hash = &brain_server_dbs->hash_buf[brain_server_dbs->hash_cnt]; + + brain_server_db_hash_init (brain_server_db_hash, brain_session); + + if (brain_server_read_hash_dump (brain_server_db_hash, file) == false) + { + continue; + } + + brain_server_dbs->hash_cnt++; + } + + closedir (dirp); + + return true; +} + +bool brain_server_write_hash_dumps (brain_server_dbs_t *brain_server_dbs, const char *path) +{ + for (i64 idx = 0; idx < brain_server_dbs->hash_cnt; idx++) + { + brain_server_db_hash_t *brain_server_db_hash = &brain_server_dbs->hash_buf[idx]; + + hc_thread_mutex_lock (brain_server_db_hash->mux_hg); + + char file[100]; + + snprintf (file, sizeof (file) - 1, "%s/brain.%08x.ldmp", path, brain_server_db_hash->brain_session); + + brain_server_write_hash_dump (brain_server_db_hash, file); + + hc_thread_mutex_unlock (brain_server_db_hash->mux_hg); + } + + return true; +} + +bool brain_server_read_hash_dump (brain_server_db_hash_t *brain_server_db_hash, const char *file) +{ + hc_timer_t timer_dump; + + hc_timer_set (&timer_dump); + + // read from file + + struct stat sb; + + if (stat (file, &sb) == -1) + { + brain_logging (stderr, 0, "%s: %s\n", file, strerror (errno)); + + return false; + } + + FILE *fd = fopen (file, "rb"); + + if (fd == NULL) + { + brain_logging (stderr, 0, "%s: %s\n", file, strerror (errno)); + + return false; + } + else + { + i64 temp_cnt = (u64) sb.st_size / sizeof (brain_server_hash_long_t); + + if (brain_server_db_hash_realloc (brain_server_db_hash, temp_cnt) == false) + { + brain_logging (stderr, 0, "%s\n", MSG_ENOMEM); + + fclose (fd); + + return false; + } + + const size_t nread = fread (brain_server_db_hash->long_buf, sizeof (brain_server_hash_long_t), temp_cnt, fd); + + if (nread != (size_t) temp_cnt) + { + brain_logging (stderr, 0, "%s: only %" PRIu64 " bytes read\n", file, (u64) nread * sizeof (brain_server_hash_long_t)); + + fclose (fd); + + return false; + } + + brain_server_db_hash->long_cnt = temp_cnt; + + brain_server_db_hash->write_hashes = false; + + fclose (fd); + } + + const double ms = hc_timer_get (timer_dump); + + brain_logging (stdout, 0, "Read %" PRIu64 " bytes from session 0x%08x in %.2f ms\n", (u64) sb.st_size, brain_server_db_hash->brain_session, ms); + + return true; +} + +bool brain_server_write_hash_dump (brain_server_db_hash_t *brain_server_db_hash, const char *file) +{ + if (brain_server_db_hash->write_hashes == false) return true; + + hc_timer_t timer_dump; + + hc_timer_set (&timer_dump); + + // write to file + + FILE *fd = fopen (file, "wb"); + + if (fd == NULL) + { + brain_logging (stderr, 0, "%s: %s\n", file, strerror (errno)); + + return false; + } + else + { + const size_t nwrite = fwrite (brain_server_db_hash->long_buf, sizeof (brain_server_hash_long_t), brain_server_db_hash->long_cnt, fd); + + if (nwrite != (size_t) brain_server_db_hash->long_cnt) + { + brain_logging (stderr, 0, "%s: only %" PRIu64 " bytes written\n", file, (u64) nwrite * sizeof (brain_server_hash_long_t)); + + fclose (fd); + + return false; + } + + fclose (fd); + + brain_server_db_hash->write_hashes = false; + } + + // stats + + const double ms = hc_timer_get (timer_dump); + + struct stat sb; + + if (stat (file, &sb) == -1) + { + brain_logging (stderr, 0, "%s: %s\n", file, strerror (errno)); + + return false; + } + + brain_logging (stdout, 0, "Wrote %" PRIu64 " bytes from session 0x%08x in %.2f ms\n", (u64) sb.st_size, brain_server_db_hash->brain_session, ms); + + return true; +} + +bool brain_server_read_attack_dumps (brain_server_dbs_t *brain_server_dbs, const char *path) +{ + brain_server_dbs->attack_cnt = 0; + + if (chdir (path) == -1) + { + brain_logging (stderr, 0, "%s: %s\n", path, strerror (errno)); + + return false; + } + + DIR *dirp = opendir (path); + + if (dirp == NULL) + { + brain_logging (stderr, 0, "%s: %s\n", path, strerror (errno)); + + return false; + } + + struct dirent *entry; + + while ((entry = readdir (dirp)) != NULL) + { + char *file = entry->d_name; + + const size_t len = strlen (file); + + if (len != 19) continue; + + if (file[ 0] != 'b') continue; + if (file[ 1] != 'r') continue; + if (file[ 2] != 'a') continue; + if (file[ 3] != 'i') continue; + if (file[ 4] != 'n') continue; + if (file[ 5] != '.') continue; + + if (file[14] != '.') continue; + if (file[15] != 'a') continue; + if (file[16] != 'd') continue; + if (file[17] != 'm') continue; + if (file[18] != 'p') continue; + + const u32 brain_attack = byte_swap_32 (hex_to_u32 ((const u8 *) file + 6)); + + brain_server_db_attack_t *brain_server_db_attack = &brain_server_dbs->attack_buf[brain_server_dbs->attack_cnt]; + + brain_server_db_attack_init (brain_server_db_attack, brain_attack); + + if (brain_server_read_attack_dump (brain_server_db_attack, file) == false) + { + continue; + } + + brain_server_dbs->attack_cnt++; + } + + closedir (dirp); + + return true; +} + +bool brain_server_write_attack_dumps (brain_server_dbs_t *brain_server_dbs, const char *path) +{ + for (i64 idx = 0; idx < brain_server_dbs->attack_cnt; idx++) + { + brain_server_db_attack_t *brain_server_db_attack = &brain_server_dbs->attack_buf[idx]; + + hc_thread_mutex_lock (brain_server_db_attack->mux_ag); + + char file[100]; + + snprintf (file, sizeof (file) - 1, "%s/brain.%08x.admp", path, brain_server_db_attack->brain_attack); + + brain_server_write_attack_dump (brain_server_db_attack, file); + + hc_thread_mutex_unlock (brain_server_db_attack->mux_ag); + } + + return true; +} + +bool brain_server_read_attack_dump (brain_server_db_attack_t *brain_server_db_attack, const char *file) +{ + hc_timer_t timer_dump; + + hc_timer_set (&timer_dump); + + // read from file + + struct stat sb; + + if (stat (file, &sb) == -1) + { + brain_logging (stderr, 0, "%s: %s\n", file, strerror (errno)); + + return false; + } + + FILE *fd = fopen (file, "rb"); + + if (fd == NULL) + { + brain_logging (stderr, 0, "%s: %s\n", file, strerror (errno)); + + return false; + } + else + { + i64 temp_cnt = (u64) sb.st_size / sizeof (brain_server_attack_long_t); + + if (brain_server_db_attack_realloc (brain_server_db_attack, temp_cnt, 0) == false) + { + brain_logging (stderr, 0, "%s\n", MSG_ENOMEM); + + fclose (fd); + + return false; + } + + const size_t nread = fread (brain_server_db_attack->long_buf, sizeof (brain_server_attack_long_t), temp_cnt, fd); + + if (nread != (size_t) temp_cnt) + { + brain_logging (stderr, 0, "%s: only %" PRIu64 " bytes read\n", file, (u64) nread * sizeof (brain_server_attack_long_t)); + + fclose (fd); + + return false; + } + + brain_server_db_attack->long_cnt = temp_cnt; + + brain_server_db_attack->write_attacks = false; + + fclose (fd); + } + + const double ms = hc_timer_get (timer_dump); + + brain_logging (stdout, 0, "Read %" PRIu64 " bytes from attack 0x%08x in %.2f ms\n", (u64) sb.st_size, brain_server_db_attack->brain_attack, ms); + + return true; +} + +bool brain_server_write_attack_dump (brain_server_db_attack_t *brain_server_db_attack, const char *file) +{ + if (brain_server_db_attack->write_attacks == false) return true; + + hc_timer_t timer_dump; + + hc_timer_set (&timer_dump); + + // write to file + + FILE *fd = fopen (file, "wb"); + + if (fd == NULL) + { + brain_logging (stderr, 0, "%s: %s\n", file, strerror (errno)); + + return false; + } + else + { + // storing should not include reserved attacks only finished + + const size_t nwrite = fwrite (brain_server_db_attack->long_buf, sizeof (brain_server_attack_long_t), brain_server_db_attack->long_cnt, fd); + + if (nwrite != (size_t) brain_server_db_attack->long_cnt) + { + brain_logging (stderr, 0, "%s: only %" PRIu64 " bytes written\n", file, (u64) nwrite * sizeof (brain_server_attack_long_t)); + + fclose (fd); + + return false; + } + + fclose (fd); + + brain_server_db_attack->write_attacks = false; + } + + // stats + + const double ms = hc_timer_get (timer_dump); + + struct stat sb; + + if (stat (file, &sb) == -1) + { + brain_logging (stderr, 0, "%s: %s\n", file, strerror (errno)); + + return false; + } + + brain_logging (stdout, 0, "Wrote %" PRIu64 " bytes from attack 0x%08x in %.2f ms\n", (u64) sb.st_size, brain_server_db_attack->brain_attack, ms); + + return true; +} + +i64 brain_server_find_hash_long (const u32 *search, const brain_server_hash_long_t *buf, const i64 cnt) +{ + for (i64 l = 0, r = cnt; r; r >>= 1) + { + const i64 m = r >> 1; + + const i64 c = l + m; + + const int cmp = brain_server_sort_hash_long (search, buf + c); + + if (cmp > 0) + { + l += m + 1; + + r--; + } + + if (cmp == 0) return (c); + } + + return (-1); +} + +i64 brain_server_find_hash_short (const u32 *search, const brain_server_hash_short_t *buf, const i64 cnt) +{ + for (i64 l = 0, r = cnt; r; r >>= 1) + { + const i64 m = r >> 1; + + const i64 c = l + m; + + const int cmp = brain_server_sort_hash_short (search, buf + c); + + if (cmp > 0) + { + l += m + 1; + + r--; + } + + if (cmp == 0) return (c); + } + + return (-1); +} + +void brain_server_handle_signal (int signo) +{ + if (signo == SIGINT) + { + keep_running = false; + } +} + +void *brain_server_handle_dumps (void *p) +{ + brain_server_dumper_options_t *brain_server_dumper_options = (brain_server_dumper_options_t *) p; + + brain_server_dbs_t *brain_server_dbs = brain_server_dumper_options->brain_server_dbs; + + int i = 0; + + while (keep_running == true) + { + if (i == BRAIN_SERVER_DUMP_EVERY) + { + brain_server_write_hash_dumps (brain_server_dbs, "."); + brain_server_write_attack_dumps (brain_server_dbs, "."); + + i = 0; + } + else + { + i++; + } + + sleep (1); + } + + return NULL; +} + +void *brain_server_handle_client (void *p) +{ + brain_server_client_options_t *brain_server_client_options = (brain_server_client_options_t *) p; + + const int client_fd = brain_server_client_options->client_fd; + const char *auth_password = brain_server_client_options->auth_password; + const u32 *session_whitelist_buf = brain_server_client_options->session_whitelist_buf; + const int session_whitelist_cnt = brain_server_client_options->session_whitelist_cnt; + + brain_server_dbs_t *brain_server_dbs = brain_server_client_options->brain_server_dbs; + + // client configuration + + #if defined (_WIN) + + #else + const int one = 1; + + if (setsockopt (client_fd, SOL_TCP, TCP_NODELAY, &one, sizeof (one)) == -1) + { + brain_logging (stderr, client_fd, "setsockopt: %s\n", strerror (errno)); + + close (client_fd); + + return NULL; + } + #endif + + u32 brain_link_version; + + if (brain_recv (client_fd, &brain_link_version, sizeof (brain_link_version), 0, NULL, NULL) == false) + { + brain_logging (stderr, client_fd, "brain_recv: %s\n", strerror (errno)); + + close (client_fd); + + return NULL; + } + + u32 brain_link_version_ok = (brain_link_version >= (u32) BRAIN_LINK_VERSION_MIN) ? 1 : 0; + + if (brain_send (client_fd, &brain_link_version_ok, sizeof (brain_link_version_ok), 0, NULL, NULL) == false) + { + brain_logging (stderr, client_fd, "brain_send: %s\n", strerror (errno)); + + close (client_fd); + + return NULL; + } + + if (brain_link_version_ok == 0) + { + brain_logging (stderr, client_fd, "Invalid version\n"); + + close (client_fd); + + return NULL; + } + + u32 challenge = brain_auth_challenge (); + + if (brain_send (client_fd, &challenge, sizeof (challenge), 0, NULL, NULL) == false) + { + brain_logging (stderr, client_fd, "brain_send: %s\n", strerror (errno)); + + close (client_fd); + + return NULL; + } + + u64 response; + + if (brain_recv (client_fd, &response, sizeof (response), 0, NULL, NULL) == false) + { + brain_logging (stderr, client_fd, "brain_recv: %s\n", strerror (errno)); + + close (client_fd); + + return NULL; + } + + u64 auth_hash = brain_auth_hash (challenge, auth_password, strlen (auth_password)); + + u32 password_ok = (auth_hash == response) ? 1 : 0; + + if (brain_send (client_fd, &password_ok, sizeof (password_ok), 0, NULL, NULL) == false) + { + brain_logging (stderr, client_fd, "brain_send: %s\n", strerror (errno)); + + close (client_fd); + + return NULL; + } + + if (password_ok == 0) + { + brain_logging (stderr, client_fd, "Invalid password\n"); + + close (client_fd); + + return NULL; + } + + u32 brain_session; + + if (brain_recv (client_fd, &brain_session, sizeof (brain_session), 0, NULL, NULL) == false) + { + brain_logging (stderr, client_fd, "brain_recv: %s\n", strerror (errno)); + + close (client_fd); + + return NULL; + } + + if (session_whitelist_cnt > 0) + { + bool found = false; + + for (int idx = 0; idx < session_whitelist_cnt; idx++) + { + if (session_whitelist_buf[idx] == brain_session) + { + found = true; + + break; + } + } + + if (found == false) + { + brain_logging (stderr, client_fd, "Invalid brain session: 0x%08x\n", brain_session); + + close (client_fd); + + return NULL; + } + } + + u32 brain_attack; + + if (brain_recv (client_fd, &brain_attack, sizeof (brain_attack), 0, NULL, NULL) == false) + { + brain_logging (stderr, client_fd, "brain_recv: %s\n", strerror (errno)); + + close (client_fd); + + return NULL; + } + + i64 passwords_max; + + if (brain_recv (client_fd, &passwords_max, sizeof (passwords_max), 0, NULL, NULL) == false) + { + brain_logging (stderr, client_fd, "brain_recv: %s\n", strerror (errno)); + + close (client_fd); + + return NULL; + } + + if (passwords_max >= BRAIN_LINK_CANDIDATES_MAX) + { + brain_logging (stderr, client_fd, "Too large candidate allocation buffer size\n"); + + close (client_fd); + + return NULL; + } + + brain_logging (stdout, client_fd, "Session: 0x%08x, Attack: 0x%08x, Kernel-power: %" PRIu64 "\n", brain_session, brain_attack, passwords_max); + + // so far so good + + hc_thread_mutex_lock (brain_server_dbs->mux_dbs); + + // long term memory + + brain_server_db_hash_t key_hash; + + key_hash.brain_session = brain_session; + + #if defined (_WIN) + unsigned int find_hash_cnt = (unsigned int) brain_server_dbs->hash_cnt; + #else + size_t find_hash_cnt = (size_t) brain_server_dbs->hash_cnt; + #endif + + brain_server_db_hash_t *brain_server_db_hash = (brain_server_db_hash_t *) lfind (&key_hash, brain_server_dbs->hash_buf, &find_hash_cnt, sizeof (brain_server_db_hash_t), brain_server_sort_db_hash); + + if (brain_server_db_hash == NULL) + { + if (brain_server_dbs->hash_cnt >= BRAIN_SERVER_SESSIONS_MAX) + { + brain_logging (stderr, 0, "too many sessions\n"); + + close (client_fd); + + return NULL; + } + + brain_server_db_hash = &brain_server_dbs->hash_buf[brain_server_dbs->hash_cnt]; + + brain_server_db_hash_init (brain_server_db_hash, brain_session); + + brain_server_dbs->hash_cnt++; + } + + // attack memory + + brain_server_db_attack_t key_attack; + + key_attack.brain_attack = brain_attack; + + #if defined (_WIN) + unsigned int find_attack_cnt = (unsigned int) brain_server_dbs->attack_cnt; + #else + size_t find_attack_cnt = (size_t) brain_server_dbs->attack_cnt; + #endif + + brain_server_db_attack_t *brain_server_db_attack = (brain_server_db_attack_t *) lfind (&key_attack, brain_server_dbs->attack_buf, &find_attack_cnt, sizeof (brain_server_db_attack_t), brain_server_sort_db_attack); + + if (brain_server_db_attack == NULL) + { + if (brain_server_dbs->attack_cnt >= BRAIN_SERVER_ATTACKS_MAX) + { + brain_logging (stderr, 0, "too many attacks\n"); + + close (client_fd); + + return NULL; + } + + brain_server_db_attack = &brain_server_dbs->attack_buf[brain_server_dbs->attack_cnt]; + + brain_server_db_attack_init (brain_server_db_attack, brain_attack); + + brain_server_dbs->attack_cnt++; + } + + hc_thread_mutex_unlock (brain_server_dbs->mux_dbs); + + // higest position of that attack + + u64 highest = brain_server_highest_attack (brain_server_db_attack); + + if (brain_send (client_fd, &highest, sizeof (highest), 0, NULL, NULL) == false) + { + brain_logging (stderr, client_fd, "brain_send: %s\n", strerror (errno)); + + close (client_fd); + + return NULL; + } + + // recv + + const size_t recv_size = passwords_max * BRAIN_HASH_SIZE; + + u32 *recv_buf = (u32 *) hcmalloc (recv_size); + + if (recv_buf == NULL) + { + brain_logging (stderr, 0, "%s\n", MSG_ENOMEM); + + return NULL; + } + + // send + + const size_t send_size = passwords_max * sizeof (char); + + u8 *send_buf = (u8 *) hcmalloc (send_size); // we can reduce this to 1/8 if we use bits instead of bytes + + if (send_buf == NULL) + { + brain_logging (stderr, 0, "%s\n", MSG_ENOMEM); + + return NULL; + } + + // temp + + brain_server_hash_unique_t *temp_buf = (brain_server_hash_unique_t *) hccalloc (passwords_max, sizeof (brain_server_hash_unique_t)); + + if (temp_buf == NULL) + { + brain_logging (stderr, 0, "%s\n", MSG_ENOMEM); + + return NULL; + } + + // short global alloc + + brain_server_db_short_t *brain_server_db_short = hcmalloc (sizeof (brain_server_db_short_t)); + + brain_server_db_short->short_cnt = 0; + brain_server_db_short->short_buf = (brain_server_hash_short_t *) hccalloc (passwords_max, sizeof (brain_server_hash_short_t)); + + if (brain_server_db_short->short_buf == NULL) + { + brain_logging (stderr, 0, "%s\n", MSG_ENOMEM); + + return NULL; + } + + // main loop + + while (keep_running == true) + { + // wait for client to send data, but not too long + + const int rc_select = select_read_timeout (client_fd, 1); + + if (rc_select == -1) break; + + if (rc_select == 0) continue; + + // there's data + + u8 operation; + + if (brain_recv (client_fd, &operation, sizeof (operation), 0, NULL, NULL) == false) break; + + // U = update + // R = request + // C = commit + + /** + * L = lookup + * + * In this section the client sends a number of password hashes (max = passwords_max). + * The goal is to check them against the long-term memory + * to find out if the password is either reserved by any client (can be the same, too) + * or if it was already checked in the past and then to send a reject. + * This is a complicated process as we have to deal with lots of duplicate data + * and with lots of clients both at the same time. + * We also have to be very fast in looking up the information otherwise the clients + * lose too much performance. + * Once a client sends a commit message, all short-term data related to the client + * is moved to the long-term memory. + * To do that in the commit section, we're storing each hash in the short-term memory + * along with client_fd. + * The short-term memory itself is limited in size. That's possible because each client + * tells the server in the handshake the maximum number of passwords it will send + * before it will either disconnect or send a commit signal. + * The first procedure for each package of hashes sent by the client is to sort them. + * This is done in the client thread and without any mutex barriers, therefore the server + * is able to use multiple threads for this action. + * This is the only time in the entire process when data is being sorted because + * of a smart way of using the data in the following process up to + * and later even in the commit process. + * We need to make sure that a hash which is stored in the short-term memory is not + * already in both the short-term and the long-term memory otherwise we end up in a + * corrupted database. + * Therefor, as a first step after the data has been sorted, we need to remove all duplicates. + * Such duplicates can occur easily in hashcat, for example if hashcat uses a 's' rule. + * If such a 's' rule searches for a character which does not exist in the base word + * the password is not changed. + * If we have multiple of such rules we create lots of duplicates. + * As to this point there was no need to use any mutex. + * But from now on we need a mutex because we will access two shared memory regions + * which both can be written to from any other client. + * We'll check the both databases and remove any existing hashes before the go into + * the short-term memory but at the same time, update the send[] buffer in case we + * need to reject the hash. + * This is possible because along with the hash, we also keep track of its original position + * in the client stream. + * No we ne'll add the remaining hashes to the short-term memory. + * This process needs no additional sorting, but we need to update the hashes + * at the correct position because this is important for the binary tree search. + * So we can not simply append it to the end. + * We do not need to care about the short-term memory size because it was preallocated + * and it is safe the client does not send more hashes that max_passwords. + * The trick here is, since all data at this point is sorted, to merge them in a reverse order. + * Using the reverse order allows us to reuse the existing memory, we do not need to + * have two buffer allocated. This is more important to the long-term memory which is + * using the same technique but has an always growing size. + * Basically what we do is that we will use the hashes of the current one of the new hash array + * and the current one of the short-term memory as a representation of a pure number. + * We take the larger on (a comparison can always be only smaller or larger, not equal) + * and store it at the highest array index. We repeat this process till both buffers + * have iterate through all of their elements. + * It's like a broken zipper. + */ + + if (operation == BRAIN_OPERATION_ATTACK_RESERVE) + { + u64 offset = 0; + u64 length = 0; + + if (brain_recv (client_fd, &offset, sizeof (offset), 0, NULL, NULL) == false) break; + if (brain_recv (client_fd, &length, sizeof (length), 0, NULL, NULL) == false) break; + + // time the lookups for debugging + + hc_timer_t timer_reserved; + + hc_timer_set (&timer_reserved); + + hc_thread_mutex_lock (brain_server_db_attack->mux_ag); + + u64 overlap = 0; + + overlap += brain_server_find_attack_short (brain_server_db_attack->short_buf, brain_server_db_attack->short_cnt, offset, length); + overlap += brain_server_find_attack_long (brain_server_db_attack->long_buf, brain_server_db_attack->long_cnt, offset + overlap, length - overlap); + + if (overlap < length) + { + if (brain_server_db_attack_realloc (brain_server_db_attack, 0, 1) == true) + { + brain_server_db_attack->short_buf[brain_server_db_attack->short_cnt].offset = offset + overlap; + brain_server_db_attack->short_buf[brain_server_db_attack->short_cnt].length = length - overlap; + brain_server_db_attack->short_buf[brain_server_db_attack->short_cnt].client_fd = client_fd; + + brain_server_db_attack->short_cnt++; + + qsort (brain_server_db_attack->short_buf, brain_server_db_attack->short_cnt, sizeof (brain_server_attack_short_t), brain_server_sort_attack_short); + } + } + + hc_thread_mutex_unlock (brain_server_db_attack->mux_ag); + + if (brain_send (client_fd, &overlap, sizeof (overlap), SEND_FLAGS, NULL, NULL) == false) break; + + const double ms = hc_timer_get (timer_reserved); + + brain_logging (stdout, client_fd, "R | %8.2f ms | Offset: %" PRIu64 ", Length: %" PRIu64 ", Overlap: %" PRIu64 "\n", ms, offset, length, overlap); + } + else if (operation == BRAIN_OPERATION_COMMIT) + { + // time the lookups for debugging + + hc_timer_t timer_commit; + + hc_timer_set (&timer_commit); + + hc_thread_mutex_lock (brain_server_db_attack->mux_ag); + + i64 new_attacks = 0; + + for (i64 idx = 0; idx < brain_server_db_attack->short_cnt; idx++) + { + if (brain_server_db_attack->short_buf[idx].client_fd == client_fd) + { + if (brain_server_db_attack_realloc (brain_server_db_attack, 1, 0) == true) + { + brain_server_db_attack->long_buf[brain_server_db_attack->long_cnt].offset = brain_server_db_attack->short_buf[idx].offset; + brain_server_db_attack->long_buf[brain_server_db_attack->long_cnt].length = brain_server_db_attack->short_buf[idx].length; + + brain_server_db_attack->long_cnt++; + + qsort (brain_server_db_attack->long_buf, brain_server_db_attack->long_cnt, sizeof (brain_server_attack_long_t), brain_server_sort_attack_long); + } + else + { + brain_logging (stderr, 0, "%s\n", MSG_ENOMEM); + } + + brain_server_db_attack->short_buf[idx].offset = 0; + brain_server_db_attack->short_buf[idx].length = 0; + brain_server_db_attack->short_buf[idx].client_fd = 0; + + new_attacks++; + } + } + + brain_server_db_attack->write_attacks = true; + + hc_thread_mutex_unlock (brain_server_db_attack->mux_ag); + + if (new_attacks) + { + const double ms_attacks = hc_timer_get (timer_commit); + + brain_logging (stdout, client_fd, "C | %8.2f ms | Attacks: %" PRIi64 "\n", ms_attacks, new_attacks); + } + + // time the lookups for debugging + + hc_timer_set (&timer_commit); + + hc_thread_mutex_lock (brain_server_db_hash->mux_hg); + + // long-term memory merge + + if (brain_server_db_short->short_cnt) + { + if (brain_server_db_hash_realloc (brain_server_db_hash, brain_server_db_short->short_cnt) == true) + { + if (brain_server_db_hash->long_cnt == 0) + { + for (i64 idx = 0; idx < brain_server_db_short->short_cnt; idx++) + { + brain_server_db_hash->long_buf[idx].hash[0] = brain_server_db_short->short_buf[idx].hash[0]; + brain_server_db_hash->long_buf[idx].hash[1] = brain_server_db_short->short_buf[idx].hash[1]; + } + + brain_server_db_hash->long_cnt = brain_server_db_short->short_cnt; + } + else + { + const i64 cnt_total = brain_server_db_hash->long_cnt + brain_server_db_short->short_cnt; + + i64 long_left = brain_server_db_hash->long_cnt - 1; + i64 short_left = brain_server_db_short->short_cnt - 1; + + i64 long_dupes = 0; + + for (i64 idx = cnt_total - 1; idx >= long_dupes; idx--) + { + const brain_server_hash_long_t *long_entry = &brain_server_db_hash->long_buf[long_left]; + const brain_server_hash_short_t *short_entry = &brain_server_db_short->short_buf[short_left]; + + int rc = 0; + + if ((long_left >= 0) && (short_left >= 0)) + { + rc = brain_server_sort_hash (long_entry->hash, short_entry->hash); + } + else if (long_left >= 0) + { + rc = 1; + } + else if (short_left >= 0) + { + rc = -1; + } + else + { + brain_logging (stderr, client_fd, "unexpected remaining buffers in compare: %" PRIi64 " - %" PRIi64 "\n", long_left, short_left); + } + + brain_server_hash_long_t *next = &brain_server_db_hash->long_buf[idx]; + + if (rc == -1) + { + next->hash[0] = short_entry->hash[0]; + next->hash[1] = short_entry->hash[1]; + + short_left--; + } + else if (rc == 1) + { + next->hash[0] = long_entry->hash[0]; + next->hash[1] = long_entry->hash[1]; + + long_left--; + } + else + { + next->hash[0] = long_entry->hash[0]; + next->hash[1] = long_entry->hash[1]; + + short_left--; + long_left--; + + long_dupes++; + } + } + + if ((long_left != -1) || (short_left != -1)) + { + brain_logging (stderr, client_fd, "unexpected remaining buffers in commit: %" PRIi64 " - %" PRIi64 "\n", long_left, short_left); + } + + brain_server_db_hash->long_cnt = cnt_total - long_dupes; + + if (long_dupes) + { + for (i64 idx = 0; idx < brain_server_db_hash->long_cnt; idx++) + { + brain_server_db_hash->long_buf[idx].hash[0] = brain_server_db_hash->long_buf[long_dupes + idx].hash[0]; + brain_server_db_hash->long_buf[idx].hash[1] = brain_server_db_hash->long_buf[long_dupes + idx].hash[1]; + } + } + } + } + else + { + brain_logging (stderr, 0, "%s\n", MSG_ENOMEM); + } + + brain_server_db_hash->write_hashes = true; + } + + hc_thread_mutex_unlock (brain_server_db_hash->mux_hg); + + if (brain_server_db_short->short_cnt) + { + const double ms_hashes = hc_timer_get (timer_commit); + + brain_logging (stdout, client_fd, "C | %8.2f ms | Hashes: %" PRIi64 "\n", ms_hashes, brain_server_db_short->short_cnt); + } + + brain_server_db_short->short_cnt = 0; + } + else if (operation == BRAIN_OPERATION_HASH_LOOKUP) + { + int in_size = 0; + + if (brain_recv (client_fd, &in_size, sizeof (in_size), 0, NULL, NULL) == false) break; + + if (in_size == 0) + { + brain_logging (stderr, client_fd, "Zero in_size value\n"); + + break; + } + + if (in_size > (int) recv_size) break; + + if (brain_recv (client_fd, recv_buf, (size_t) in_size, 0, NULL, NULL) == false) break; + + const int hashes_cnt = in_size / BRAIN_HASH_SIZE; + + if (hashes_cnt == 0) + { + brain_logging (stderr, client_fd, "Zero passwords\n"); + + break; + } + + if (hashes_cnt > passwords_max) + { + brain_logging (stderr, client_fd, "Too many passwords\n"); + + break; + } + + // time the lookups for debugging + + hc_timer_t timer_lookup; + + hc_timer_set (&timer_lookup); + + // make it easier to work with + + for (int hash_idx = 0, recv_idx = 0; hash_idx < hashes_cnt; hash_idx += 1, recv_idx += 2) + { + temp_buf[hash_idx].hash[0] = recv_buf[recv_idx + 0]; + temp_buf[hash_idx].hash[1] = recv_buf[recv_idx + 1]; + + temp_buf[hash_idx].hash_idx = hash_idx; + + send_buf[hash_idx] = 0; + } + + // unique temp memory + + i64 temp_cnt = 0; + + qsort (temp_buf, hashes_cnt, sizeof (brain_server_hash_unique_t), brain_server_sort_hash_unique); + + brain_server_hash_unique_t *prev = temp_buf + temp_cnt; + + for (i64 temp_idx = 1; temp_idx < hashes_cnt; temp_idx++) + { + brain_server_hash_unique_t *cur = temp_buf + temp_idx; + + if ((cur->hash[0] == prev->hash[0]) && (cur->hash[1] == prev->hash[1])) + { + send_buf[cur->hash_idx] = 1; + } + else + { + temp_cnt++; + + prev = temp_buf + temp_cnt; + + prev->hash[0] = cur->hash[0]; + prev->hash[1] = cur->hash[1]; + + prev->hash_idx = cur->hash_idx; // we need this in a later stage + } + } + + temp_cnt++; + + // check if they are in long term memory + + hc_thread_mutex_lock (brain_server_db_hash->mux_hr); + + brain_server_db_hash->hb++; + + if (brain_server_db_hash->hb == 1) + { + hc_thread_mutex_lock (brain_server_db_hash->mux_hg); + } + + hc_thread_mutex_unlock (brain_server_db_hash->mux_hr); + + if (temp_cnt > 0) + { + i64 temp_idx_new = 0; + + for (i64 temp_idx = 0; temp_idx < temp_cnt; temp_idx++) + { + brain_server_hash_unique_t *cur = &temp_buf[temp_idx]; + + const i64 r = brain_server_find_hash_long (cur->hash, brain_server_db_hash->long_buf, brain_server_db_hash->long_cnt); + + if (r != -1) + { + send_buf[cur->hash_idx] = 1; + } + else + { + brain_server_hash_unique_t *save = temp_buf + temp_idx_new; + + temp_idx_new++; + + save->hash[0] = cur->hash[0]; + save->hash[1] = cur->hash[1]; + + save->hash_idx = cur->hash_idx; // we need this in a later stage + } + } + + temp_cnt = temp_idx_new; + } + + hc_thread_mutex_lock (brain_server_db_hash->mux_hr); + + brain_server_db_hash->hb--; + + if (brain_server_db_hash->hb == 0) + { + hc_thread_mutex_unlock (brain_server_db_hash->mux_hg); + } + + hc_thread_mutex_unlock (brain_server_db_hash->mux_hr); + + // check if they are in short term memory + + if (temp_cnt > 0) + { + i64 temp_idx_new = 0; + + for (i64 temp_idx = 0; temp_idx < temp_cnt; temp_idx++) + { + brain_server_hash_unique_t *cur = &temp_buf[temp_idx]; + + const i64 r = brain_server_find_hash_short (cur->hash, brain_server_db_short->short_buf, brain_server_db_short->short_cnt); + + if (r != -1) + { + send_buf[cur->hash_idx] = 1; + } + else + { + brain_server_hash_unique_t *save = temp_buf + temp_idx_new; + + temp_idx_new++; + + save->hash[0] = cur->hash[0]; + save->hash[1] = cur->hash[1]; + + save->hash_idx = cur->hash_idx; // we need this in a later stage + } + } + + temp_cnt = temp_idx_new; + } + + // update remaining + + if (temp_cnt > 0) + { + if (brain_server_db_short->short_cnt == 0) + { + for (i64 idx = 0; idx < temp_cnt; idx++) + { + brain_server_db_short->short_buf[idx].hash[0] = temp_buf[idx].hash[0]; + brain_server_db_short->short_buf[idx].hash[1] = temp_buf[idx].hash[1]; + } + + brain_server_db_short->short_cnt = temp_cnt; + } + else + { + const i64 cnt_total = brain_server_db_short->short_cnt + temp_cnt; + + i64 short_left = brain_server_db_short->short_cnt - 1; + i64 unique_left = temp_cnt - 1; + + for (i64 idx = cnt_total - 1; idx >= 0; idx--) + { + const brain_server_hash_short_t *short_entry = brain_server_db_short->short_buf + short_left; + const brain_server_hash_unique_t *unique_entry = temp_buf + unique_left; + + int rc = 0; + + if ((short_left >= 0) && (unique_left >= 0)) + { + rc = brain_server_sort_hash (short_entry->hash, unique_entry->hash); + } + else if (short_left >= 0) + { + rc = 1; + } + else if (unique_left >= 0) + { + rc = -1; + } + else + { + brain_logging (stderr, client_fd, "unexpected remaining buffers in compare: %" PRIi64 " - %" PRIi64 "\n", short_left, unique_left); + } + + brain_server_hash_short_t *next = brain_server_db_short->short_buf + idx; + + if (rc == -1) + { + next->hash[0] = unique_entry->hash[0]; + next->hash[1] = unique_entry->hash[1]; + + unique_left--; + } + else if (rc == 1) + { + next->hash[0] = short_entry->hash[0]; + next->hash[1] = short_entry->hash[1]; + + short_left--; + } + else + { + brain_logging (stderr, client_fd, "unexpected zero comparison in commit\n"); + } + } + + if ((short_left != -1) || (unique_left != -1)) + { + brain_logging (stderr, client_fd, "unexpected remaining buffers in commit: %" PRIi64 " - %" PRIi64 "\n", short_left, unique_left); + } + + brain_server_db_short->short_cnt = cnt_total; + } + } + + // opportunity to set counters for stats + + int local_lookup_new = 0; + + for (i64 hashes_idx = 0; hashes_idx < hashes_cnt; hashes_idx++) + { + if (send_buf[hashes_idx] == 0) + { + local_lookup_new++; + } + } + + // needs anti-flood fix + + const double ms = hc_timer_get (timer_lookup); + + brain_logging (stdout, client_fd, "L | %8.2f ms | Long: %" PRIi64 ", Inc: %d, New: %d\n", ms, brain_server_db_hash->long_cnt, hashes_cnt, local_lookup_new); + + // send + + int out_size = hashes_cnt; + + if (brain_send (client_fd, &out_size, sizeof (out_size), SEND_FLAGS, NULL, NULL) == false) break; + + if (brain_send (client_fd, send_buf, out_size, SEND_FLAGS, NULL, NULL) == false) break; + } + else + { + break; + } + } + + // client reservations + + hc_thread_mutex_lock (brain_server_db_attack->mux_ag); + + for (i64 idx = 0; idx < brain_server_db_attack->short_cnt; idx++) + { + if (brain_server_db_attack->short_buf[idx].client_fd == client_fd) + { + brain_server_db_attack->short_buf[idx].offset = 0; + brain_server_db_attack->short_buf[idx].length = 0; + brain_server_db_attack->short_buf[idx].client_fd = 0; + } + } + + hc_thread_mutex_unlock (brain_server_db_attack->mux_ag); + + // short free + + hcfree (brain_server_db_short->short_buf); + hcfree (brain_server_db_short); + + // free local memory + + hcfree (send_buf); + hcfree (temp_buf); + hcfree (recv_buf); + + brain_logging (stdout, client_fd, "Disconnected\n"); + + close (client_fd); + + return NULL; +} + +int brain_server (const char *listen_host, const int listen_port, const char *brain_password, const char *brain_session_whitelist) +{ + hc_timer_set (&timer_logging); + + hc_thread_mutex_init (mux_display); + + // generate random brain password if not specified by user + + char *auth_password = NULL; + + if (brain_password == NULL) + { + #define BRAIN_PASSWORD_SZ 20 + + auth_password = (char *) hcmalloc (BRAIN_PASSWORD_SZ); + + snprintf (auth_password, BRAIN_PASSWORD_SZ - 1, "%08x%08x", brain_auth_challenge (), brain_auth_challenge ()); + + brain_logging (stdout, 0, "Generated authentication password: %s\n", auth_password); + } + else + { + auth_password = (char *) brain_password; + } + + // socket stuff + + const int server_fd = socket (AF_INET, SOCK_STREAM, 0); + + if (server_fd == -1) + { + brain_logging (stderr, 0, "socket: %s\n", strerror (errno)); + + return -1; + } + + #if defined (_WIN) + + #else + const int one = 1; + + if (setsockopt (server_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof (one)) == -1) + { + brain_logging (stderr, 0, "setsockopt: %s\n", strerror (errno)); + + return -1; + } + + if (setsockopt (server_fd, SOL_TCP, TCP_NODELAY, &one, sizeof (one)) == -1) + { + brain_logging (stderr, 0, "setsockopt: %s\n", strerror (errno)); + + return -1; + } + #endif + + struct sockaddr_in sa; + + memset (&sa, 0, sizeof (sa)); + + size_t salen = sizeof (sa); + + sa.sin_family = AF_INET; + sa.sin_port = htons (listen_port); + sa.sin_addr.s_addr = INADDR_ANY; + + if (listen_host) + { + struct addrinfo hints; + + memset (&hints, 0, sizeof (hints)); + + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + struct addrinfo *address_info = NULL; + + const int rc_getaddrinfo = getaddrinfo (listen_host, NULL, &hints, &address_info); + + if (rc_getaddrinfo == 0) + { + struct sockaddr_in *tmp = (struct sockaddr_in *) address_info->ai_addr; + + sa.sin_addr.s_addr = tmp->sin_addr.s_addr; + + freeaddrinfo (address_info); + } + else + { + brain_logging (stderr, 0, "%s: %s\n", listen_host, gai_strerror (rc_getaddrinfo)); + + return -1; + } + } + + if (bind (server_fd, (struct sockaddr *) &sa, salen) == -1) + { + brain_logging (stderr, 0, "bind: %s\n", strerror (errno)); + + return -1; + } + + if (listen (server_fd, 5) == -1) + { + brain_logging (stderr, 0, "listen: %s\n", strerror (errno)); + + return -1; + } + + brain_server_dbs_t *brain_server_dbs = (brain_server_dbs_t *) hcmalloc (sizeof (brain_server_dbs_t)); + + if (brain_server_dbs == NULL) + { + brain_logging (stderr, 0, "%s\n", MSG_ENOMEM); + + return -1; + } + + hc_thread_mutex_init (brain_server_dbs->mux_dbs); + + brain_server_dbs->hash_buf = (brain_server_db_hash_t *) hccalloc (BRAIN_SERVER_SESSIONS_MAX, sizeof (brain_server_db_hash_t)); + brain_server_dbs->hash_cnt = 0; + + if (brain_server_dbs->hash_buf == NULL) + { + brain_logging (stderr, 0, "%s\n", MSG_ENOMEM); + + return -1; + } + + if (brain_server_read_hash_dumps (brain_server_dbs, ".") == false) + { + return -1; + } + + brain_server_dbs->attack_buf = (brain_server_db_attack_t *) hccalloc (BRAIN_SERVER_ATTACKS_MAX, sizeof (brain_server_db_attack_t)); + brain_server_dbs->attack_cnt = 0; + + if (brain_server_dbs->attack_buf == NULL) + { + brain_logging (stderr, 0, "%s\n", MSG_ENOMEM); + + return -1; + } + + if (brain_server_read_attack_dumps (brain_server_dbs, ".") == false) + { + return -1; + } + + // session whitelists + + u32 *session_whitelist_buf = (u32 *) hccalloc (BRAIN_SERVER_SESSIONS_MAX, sizeof (u32)); + int session_whitelist_cnt = 0; + + if (brain_session_whitelist != NULL) + { + char *sessions = hcstrdup (brain_session_whitelist); + + if (sessions == NULL) + { + brain_logging (stderr, 0, "%s\n", MSG_ENOMEM); + + return -1; + } + + char *saveptr = NULL; + + char *next = strtok_r (sessions, ",", &saveptr); + + do + { + const int session = (const int) hc_strtoul (next, NULL, 16); + + session_whitelist_buf[session_whitelist_cnt] = session; + + session_whitelist_cnt++; + + } while ((next = strtok_r ((char *) NULL, ",", &saveptr)) != NULL); + + hcfree (sessions); + } + + // client options + + brain_server_client_options_t *brain_server_client_options = (brain_server_client_options_t *) hccalloc (BRAIN_SERVER_CLIENTS_MAX, sizeof (brain_server_client_options_t)); + + if (brain_server_client_options == NULL) + { + brain_logging (stderr, 0, "%s\n", MSG_ENOMEM); + + return -1; + } + + for (int client_idx = 0; client_idx < BRAIN_SERVER_CLIENTS_MAX; client_idx++) + { + // none of these value change + + brain_server_client_options[client_idx].brain_server_dbs = brain_server_dbs; + brain_server_client_options[client_idx].client_fd = client_idx; + brain_server_client_options[client_idx].auth_password = auth_password; + brain_server_client_options[client_idx].session_whitelist_buf = session_whitelist_buf; + brain_server_client_options[client_idx].session_whitelist_cnt = session_whitelist_cnt; + } + + // ready to serve + + brain_logging (stdout, 0, "Brain server started\n"); + + if (signal (SIGINT, brain_server_handle_signal) == SIG_ERR) + { + brain_logging (stderr, 0, "signal: %s\n", strerror (errno)); + + return -1; + } + + brain_server_dumper_options_t brain_server_dumper_options; + + brain_server_dumper_options.brain_server_dbs = brain_server_dbs; + + hc_thread_t dump_thr; + + hc_thread_create (dump_thr, brain_server_handle_dumps, &brain_server_dumper_options); + + while (keep_running == true) + { + // wait for a client to connect, but not too long + + const int rc_select = select_read_timeout (server_fd, 1); + + if (rc_select == -1) + { + keep_running = false; + + break; + } + + if (rc_select == 0) continue; + + // there's a client! + + struct sockaddr_in ca; + + memset (&ca, 0, sizeof (ca)); + + size_t calen = sizeof (ca); + + const int client_fd = accept (server_fd, (struct sockaddr *) &ca, (socklen_t *) &calen); + + brain_logging (stdout, client_fd, "Connection from %s:%d\n", inet_ntoa (ca.sin_addr), ntohs (ca.sin_port)); + + if (client_fd <= 2) + { + brain_logging (stderr, client_fd, "Invalid client_fd\n"); + + keep_running = false; + + break; + } + + if (client_fd >= BRAIN_SERVER_CLIENTS_MAX) + { + brain_logging (stderr, client_fd, "Too many clients\n"); + + close (client_fd); + + continue; + } + + hc_thread_t client_thr; + + hc_thread_create (client_thr, brain_server_handle_client, &brain_server_client_options[client_fd]); + + if (client_thr == 0) + { + brain_logging (stderr, 0, "pthread_create: %s\n", strerror (errno)); + + close (client_fd); + + continue; + } + + hc_thread_detach (client_thr); + } + + brain_logging (stdout, 0, "Brain server stopping\n"); + + hc_thread_wait (1, &dump_thr); + + if (brain_server_write_hash_dumps (brain_server_dbs, ".") == false) + { + return -1; + } + + if (brain_server_write_attack_dumps (brain_server_dbs, ".") == false) + { + return -1; + } + + for (i64 idx = 0; idx < brain_server_dbs->hash_cnt; idx++) + { + brain_server_db_hash_t *brain_server_db_hash = &brain_server_dbs->hash_buf[idx]; + + brain_server_db_hash_free (brain_server_db_hash); + } + + for (i64 idx = 0; idx < brain_server_dbs->attack_cnt; idx++) + { + brain_server_db_attack_t *brain_server_db_attack = &brain_server_dbs->attack_buf[idx]; + + brain_server_db_attack_free (brain_server_db_attack); + } + + hcfree (brain_server_dbs->hash_buf); + hcfree (brain_server_dbs->attack_buf); + + hcfree (brain_server_dbs); + + hcfree (brain_server_client_options); + + close (server_fd); + + return 0; +} diff --git a/src/dispatch.c b/src/dispatch.c index 07b858e46..ce000cc35 100644 --- a/src/dispatch.c +++ b/src/dispatch.c @@ -19,6 +19,10 @@ #include "user_options.h" #include "dispatch.h" +#ifdef WITH_BRAIN +#include "brain.h" +#endif + static u64 get_highest_words_done (const hashcat_ctx_t *hashcat_ctx) { const opencl_ctx_t *opencl_ctx = hashcat_ctx->opencl_ctx; @@ -370,6 +374,39 @@ static int calc (hashcat_ctx_t *hashcat_ctx, hc_device_param_t *device_param) if (user_options->slow_candidates == true) { + #ifdef WITH_BRAIN + const u32 brain_session = user_options->brain_session; + const u32 brain_attack = user_options->brain_attack; + + u64 highest = 0; + + brain_client_disconnect (device_param); + + if (user_options->brain_client == true) + { + const i64 passwords_max = device_param->hardware_power * device_param->kernel_accel; + + if (brain_client_connect (device_param, status_ctx, user_options->brain_host, user_options->brain_port, user_options->brain_password, brain_session, brain_attack, passwords_max, &highest) == false) + { + brain_client_disconnect (device_param); + } + + hc_thread_mutex_lock (status_ctx->mux_dispatcher); + + if (status_ctx->words_off == 0) + { + status_ctx->words_off = highest; + + for (u32 salt_pos = 0; salt_pos < hashes->salts_cnt; salt_pos++) + { + status_ctx->words_progress_rejected[salt_pos] = status_ctx->words_off; + } + } + + hc_thread_mutex_unlock (status_ctx->mux_dispatcher); + } + #endif + // attack modes from here if (attack_mode == ATTACK_MODE_STRAIGHT) @@ -446,6 +483,39 @@ static int calc (hashcat_ctx_t *hashcat_ctx, hc_device_param_t *device_param) u64 words_off = device_param->words_off; + #ifdef WITH_BRAIN + if (user_options->brain_client == true) + { + if (device_param->brain_link_client_fd == -1) + { + const i64 passwords_max = device_param->hardware_power * device_param->kernel_accel; + + if (brain_client_connect (device_param, status_ctx, user_options->brain_host, user_options->brain_port, user_options->brain_password, user_options->brain_session, user_options->brain_attack, passwords_max, &highest) == false) + { + brain_client_disconnect (device_param); + } + } + + if (user_options->brain_client_features & BRAIN_CLIENT_FEATURE_ATTACKS) + { + u64 overlap = 0; + + if (brain_client_reserve (device_param, status_ctx, words_off, work, &overlap) == false) + { + brain_client_disconnect (device_param); + } + + words_extra = overlap; + + words_extra_total += overlap; + + words_off += overlap; + + work -= overlap; + } + } + #endif + words_fin = words_off + work; words_extra = 0; @@ -467,6 +537,20 @@ static int calc (hashcat_ctx_t *hashcat_ctx, hc_device_param_t *device_param) continue; } + #ifdef WITH_BRAIN + if (user_options->brain_client == true) + { + u32 hash[2]; + + brain_client_generate_hash ((u64 *) hash, (const char *) extra_info_straight.out_buf, extra_info_straight.out_len); + + u32 *ptr = (u32 *) device_param->brain_link_out_buf; + + ptr[(device_param->pws_pre_cnt * 2) + 0] = hash[0]; + ptr[(device_param->pws_pre_cnt * 2) + 1] = hash[1]; + } + #endif + pw_pre_add (device_param, extra_info_straight.out_buf, extra_info_straight.out_len, extra_info_straight.base_buf, extra_info_straight.base_len, extra_info_straight.rule_pos_prev); if (status_ctx->run_thread_level1 == false) break; @@ -479,6 +563,49 @@ static int calc (hashcat_ctx_t *hashcat_ctx, hc_device_param_t *device_param) if (status_ctx->run_thread_level1 == false) break; } + #ifdef WITH_BRAIN + if (user_options->brain_client == true) + { + if (user_options->brain_client_features & BRAIN_CLIENT_FEATURE_HASHES) + { + if (brain_client_lookup (device_param, status_ctx) == false) + { + brain_client_disconnect (device_param); + } + } + + u64 pws_pre_cnt = device_param->pws_pre_cnt; + + for (u64 pws_pre_idx = 0; pws_pre_idx < pws_pre_cnt; pws_pre_idx++) + { + if (device_param->brain_link_in_buf[pws_pre_idx] == 1) + { + pre_rejects++; + } + else + { + pw_pre_t *pw_pre = device_param->pws_pre_buf + pws_pre_idx; + + pw_base_add (device_param, pw_pre); + + pw_add (device_param, (const u8 *) pw_pre->pw_buf, (const int) pw_pre->pw_len); + } + } + } + else + { + u64 pws_pre_cnt = device_param->pws_pre_cnt; + + for (u64 pws_pre_idx = 0; pws_pre_idx < pws_pre_cnt; pws_pre_idx++) + { + pw_pre_t *pw_pre = device_param->pws_pre_buf + pws_pre_idx; + + pw_base_add (device_param, pw_pre); + + pw_add (device_param, (const u8 *) pw_pre->pw_buf, (const int) pw_pre->pw_len); + } + } + #else u64 pws_pre_cnt = device_param->pws_pre_cnt; for (u64 pws_pre_idx = 0; pws_pre_idx < pws_pre_cnt; pws_pre_idx++) @@ -489,6 +616,7 @@ static int calc (hashcat_ctx_t *hashcat_ctx, hc_device_param_t *device_param) pw_add (device_param, (const u8 *) pw_pre->pw_buf, (const int) pw_pre->pw_len); } + #endif words_extra_total += pre_rejects; @@ -543,6 +671,23 @@ static int calc (hashcat_ctx_t *hashcat_ctx, hc_device_param_t *device_param) return -1; } + #ifdef WITH_BRAIN + if (user_options->brain_client == true) + { + if ((status_ctx->devices_status != STATUS_ABORTED) + && (status_ctx->devices_status != STATUS_ABORTED_RUNTIME) + && (status_ctx->devices_status != STATUS_QUIT) + && (status_ctx->devices_status != STATUS_BYPASS) + && (status_ctx->devices_status != STATUS_ERROR)) + { + if (brain_client_commit (device_param, status_ctx) == false) + { + brain_client_disconnect (device_param); + } + } + } + #endif + device_param->pws_cnt = 0; device_param->pws_base_cnt = 0; @@ -673,6 +818,39 @@ static int calc (hashcat_ctx_t *hashcat_ctx, hc_device_param_t *device_param) u64 words_off = device_param->words_off; + #ifdef WITH_BRAIN + if (user_options->brain_client == true) + { + if (device_param->brain_link_client_fd == -1) + { + const i64 passwords_max = device_param->hardware_power * device_param->kernel_accel; + + if (brain_client_connect (device_param, status_ctx, user_options->brain_host, user_options->brain_port, user_options->brain_password, user_options->brain_session, user_options->brain_attack, passwords_max, &highest) == false) + { + brain_client_disconnect (device_param); + } + } + + if (user_options->brain_client_features & BRAIN_CLIENT_FEATURE_ATTACKS) + { + u64 overlap = 0; + + if (brain_client_reserve (device_param, status_ctx, words_off, work, &overlap) == false) + { + brain_client_disconnect (device_param); + } + + words_extra = overlap; + + words_extra_total += overlap; + + words_off += overlap; + + work -= overlap; + } + } + #endif + words_fin = words_off + work; slow_candidates_seek (hashcat_ctx_tmp, &extra_info_combi, words_cur, words_off); @@ -692,6 +870,20 @@ static int calc (hashcat_ctx_t *hashcat_ctx, hc_device_param_t *device_param) continue; } + #ifdef WITH_BRAIN + if (user_options->brain_client == true) + { + u32 hash[2]; + + brain_client_generate_hash ((u64 *) hash, (const char *) extra_info_combi.out_buf, extra_info_combi.out_len); + + u32 *ptr = (u32 *) device_param->brain_link_out_buf; + + ptr[(device_param->pws_pre_cnt * 2) + 0] = hash[0]; + ptr[(device_param->pws_pre_cnt * 2) + 1] = hash[1]; + } + #endif + pw_pre_add (device_param, extra_info_combi.out_buf, extra_info_combi.out_len, NULL, 0, 0); if (status_ctx->run_thread_level1 == false) break; @@ -704,6 +896,49 @@ static int calc (hashcat_ctx_t *hashcat_ctx, hc_device_param_t *device_param) if (status_ctx->run_thread_level1 == false) break; } + #ifdef WITH_BRAIN + if (user_options->brain_client == true) + { + if (user_options->brain_client_features & BRAIN_CLIENT_FEATURE_HASHES) + { + if (brain_client_lookup (device_param, status_ctx) == false) + { + brain_client_disconnect (device_param); + } + } + + u64 pws_pre_cnt = device_param->pws_pre_cnt; + + for (u64 pws_pre_idx = 0; pws_pre_idx < pws_pre_cnt; pws_pre_idx++) + { + if (device_param->brain_link_in_buf[pws_pre_idx] == 1) + { + pre_rejects++; + } + else + { + pw_pre_t *pw_pre = device_param->pws_pre_buf + pws_pre_idx; + + pw_base_add (device_param, pw_pre); + + pw_add (device_param, (const u8 *) pw_pre->pw_buf, (const int) pw_pre->pw_len); + } + } + } + else + { + u64 pws_pre_cnt = device_param->pws_pre_cnt; + + for (u64 pws_pre_idx = 0; pws_pre_idx < pws_pre_cnt; pws_pre_idx++) + { + pw_pre_t *pw_pre = device_param->pws_pre_buf + pws_pre_idx; + + pw_base_add (device_param, pw_pre); + + pw_add (device_param, (const u8 *) pw_pre->pw_buf, (const int) pw_pre->pw_len); + } + } + #else u64 pws_pre_cnt = device_param->pws_pre_cnt; for (u64 pws_pre_idx = 0; pws_pre_idx < pws_pre_cnt; pws_pre_idx++) @@ -714,6 +949,7 @@ static int calc (hashcat_ctx_t *hashcat_ctx, hc_device_param_t *device_param) pw_add (device_param, (const u8 *) pw_pre->pw_buf, (const int) pw_pre->pw_len); } + #endif words_extra_total += pre_rejects; @@ -772,6 +1008,23 @@ static int calc (hashcat_ctx_t *hashcat_ctx, hc_device_param_t *device_param) return -1; } + #ifdef WITH_BRAIN + if (user_options->brain_client == true) + { + if ((status_ctx->devices_status != STATUS_ABORTED) + && (status_ctx->devices_status != STATUS_ABORTED_RUNTIME) + && (status_ctx->devices_status != STATUS_QUIT) + && (status_ctx->devices_status != STATUS_BYPASS) + && (status_ctx->devices_status != STATUS_ERROR)) + { + if (brain_client_commit (device_param, status_ctx) == false) + { + brain_client_disconnect (device_param); + } + } + } + #endif + device_param->pws_cnt = 0; device_param->pws_base_cnt = 0; @@ -846,6 +1099,39 @@ static int calc (hashcat_ctx_t *hashcat_ctx, hc_device_param_t *device_param) u64 words_off = device_param->words_off; + #ifdef WITH_BRAIN + if (user_options->brain_client == true) + { + if (device_param->brain_link_client_fd == -1) + { + const i64 passwords_max = device_param->hardware_power * device_param->kernel_accel; + + if (brain_client_connect (device_param, status_ctx, user_options->brain_host, user_options->brain_port, user_options->brain_password, user_options->brain_session, user_options->brain_attack, passwords_max, &highest) == false) + { + brain_client_disconnect (device_param); + } + } + + if (user_options->brain_client_features & BRAIN_CLIENT_FEATURE_ATTACKS) + { + u64 overlap = 0; + + if (brain_client_reserve (device_param, status_ctx, words_off, work, &overlap) == false) + { + brain_client_disconnect (device_param); + } + + words_extra = overlap; + + words_extra_total += overlap; + + words_off += overlap; + + work -= overlap; + } + } + #endif + words_fin = words_off + work; words_cur = words_off; @@ -856,6 +1142,20 @@ static int calc (hashcat_ctx_t *hashcat_ctx, hc_device_param_t *device_param) slow_candidates_next (hashcat_ctx, &extra_info_mask); + #ifdef WITH_BRAIN + if (user_options->brain_client == true) + { + u32 hash[2]; + + brain_client_generate_hash ((u64 *) hash, (const char *) extra_info_mask.out_buf, extra_info_mask.out_len); + + u32 *ptr = (u32 *) device_param->brain_link_out_buf; + + ptr[(device_param->pws_pre_cnt * 2) + 0] = hash[0]; + ptr[(device_param->pws_pre_cnt * 2) + 1] = hash[1]; + } + #endif + pw_pre_add (device_param, extra_info_mask.out_buf, extra_info_mask.out_len, NULL, 0, 0); if (status_ctx->run_thread_level1 == false) break; @@ -868,6 +1168,45 @@ static int calc (hashcat_ctx_t *hashcat_ctx, hc_device_param_t *device_param) if (status_ctx->run_thread_level1 == false) break; } + #ifdef WITH_BRAIN + if (user_options->brain_client == true) + { + if (user_options->brain_client_features & BRAIN_CLIENT_FEATURE_HASHES) + { + if (brain_client_lookup (device_param, status_ctx) == false) + { + brain_client_disconnect (device_param); + } + } + + u64 pws_pre_cnt = device_param->pws_pre_cnt; + + for (u64 pws_pre_idx = 0; pws_pre_idx < pws_pre_cnt; pws_pre_idx++) + { + if (device_param->brain_link_in_buf[pws_pre_idx] == 1) + { + pre_rejects++; + } + else + { + pw_pre_t *pw_pre = device_param->pws_pre_buf + pws_pre_idx; + + pw_add (device_param, (const u8 *) pw_pre->pw_buf, (const int) pw_pre->pw_len); + } + } + } + else + { + u64 pws_pre_cnt = device_param->pws_pre_cnt; + + for (u64 pws_pre_idx = 0; pws_pre_idx < pws_pre_cnt; pws_pre_idx++) + { + pw_pre_t *pw_pre = device_param->pws_pre_buf + pws_pre_idx; + + pw_add (device_param, (const u8 *) pw_pre->pw_buf, (const int) pw_pre->pw_len); + } + } + #else u64 pws_pre_cnt = device_param->pws_pre_cnt; for (u64 pws_pre_idx = 0; pws_pre_idx < pws_pre_cnt; pws_pre_idx++) @@ -876,6 +1215,7 @@ static int calc (hashcat_ctx_t *hashcat_ctx, hc_device_param_t *device_param) pw_add (device_param, (const u8 *) pw_pre->pw_buf, (const int) pw_pre->pw_len); } + #endif words_extra_total += pre_rejects; @@ -918,6 +1258,23 @@ static int calc (hashcat_ctx_t *hashcat_ctx, hc_device_param_t *device_param) return -1; } + #ifdef WITH_BRAIN + if (user_options->brain_client == true) + { + if ((status_ctx->devices_status != STATUS_ABORTED) + && (status_ctx->devices_status != STATUS_ABORTED_RUNTIME) + && (status_ctx->devices_status != STATUS_QUIT) + && (status_ctx->devices_status != STATUS_BYPASS) + && (status_ctx->devices_status != STATUS_ERROR)) + { + if (brain_client_commit (device_param, status_ctx) == false) + { + brain_client_disconnect (device_param); + } + } + } + #endif + device_param->pws_cnt = 0; } @@ -935,6 +1292,13 @@ static int calc (hashcat_ctx_t *hashcat_ctx, hc_device_param_t *device_param) if (words_fin == 0) break; } } + + #ifdef WITH_BRAIN + if (user_options->brain_client == true) + { + brain_client_disconnect (device_param); + } + #endif } else { diff --git a/src/hashcat.c b/src/hashcat.c index 3ede374be..ea3eec594 100644 --- a/src/hashcat.c +++ b/src/hashcat.c @@ -51,6 +51,10 @@ #include "user_options.h" #include "wordlist.h" +#ifdef WITH_BRAIN +#include "brain.h" +#endif + // inner2_loop iterates through wordlists, then calls kernel execution static int inner2_loop (hashcat_ctx_t *hashcat_ctx) @@ -159,6 +163,10 @@ static int inner2_loop (hashcat_ctx_t *hashcat_ctx) status_ctx->words_progress_restored[i] = progress_restored; } + #ifdef WITH_BRAIN + user_options->brain_attack = brain_compute_attack (hashcat_ctx); + #endif + /** * limit kernel loops by the amplification count we have from: * - straight_ctx, combinator_ctx or mask_ctx for fast hashes @@ -1372,6 +1380,10 @@ int hashcat_get_status (hashcat_ctx_t *hashcat_ctx, hashcat_status_t *hashcat_st hashcat_status->salts_done = status_get_salts_done (hashcat_ctx); hashcat_status->salts_percent = status_get_salts_percent (hashcat_ctx); hashcat_status->session = status_get_session (hashcat_ctx); + #ifdef WITH_BRAIN + hashcat_status->brain_session = status_get_brain_session (hashcat_ctx); + hashcat_status->brain_attack = status_get_brain_attack (hashcat_ctx); + #endif hashcat_status->status_string = status_get_status_string (hashcat_ctx); hashcat_status->status_number = status_get_status_number (hashcat_ctx); hashcat_status->time_estimated_absolute = status_get_time_estimated_absolute (hashcat_ctx); @@ -1415,6 +1427,14 @@ int hashcat_get_status (hashcat_ctx_t *hashcat_ctx, hashcat_status_t *hashcat_st device_info->innerloop_left_dev = status_get_innerloop_left_dev (hashcat_ctx, device_id); device_info->iteration_pos_dev = status_get_iteration_pos_dev (hashcat_ctx, device_id); device_info->iteration_left_dev = status_get_iteration_left_dev (hashcat_ctx, device_id); + #ifdef WITH_BRAIN + device_info->brain_link_client_id_dev = status_get_brain_link_client_id_dev (hashcat_ctx, device_id); + device_info->brain_link_status_dev = status_get_brain_link_status_dev (hashcat_ctx, device_id); + device_info->brain_link_recv_bytes_dev = status_get_brain_link_recv_bytes_dev (hashcat_ctx, device_id); + device_info->brain_link_send_bytes_dev = status_get_brain_link_send_bytes_dev (hashcat_ctx, device_id); + device_info->brain_link_recv_bytes_sec_dev = status_get_brain_link_recv_bytes_sec_dev (hashcat_ctx, device_id); + device_info->brain_link_send_bytes_sec_dev = status_get_brain_link_send_bytes_sec_dev (hashcat_ctx, device_id); + #endif } hashcat_status->hashes_msec_all = status_get_hashes_msec_all (hashcat_ctx); diff --git a/src/hashes.c b/src/hashes.c index 0d2dd58b4..44048cbd5 100644 --- a/src/hashes.c +++ b/src/hashes.c @@ -27,6 +27,10 @@ #include "timer.h" #include "locking.h" +#ifdef WITH_BRAIN +#include "brain.h" +#endif + int sort_by_string (const void *p1, const void *p2) { const char *s1 = (const char *) p1; @@ -1664,6 +1668,14 @@ int hashes_init_stage4 (hashcat_ctx_t *hashcat_ctx) hashes->tmp_buf = tmp_buf; + // brain session + + #ifdef WITH_BRAIN + const u32 brain_session = brain_compute_session (hashcat_ctx); + + user_options->brain_session = brain_session; + #endif + return 0; } diff --git a/src/main.c b/src/main.c index b4ff127bd..c79e17a4e 100644 --- a/src/main.c +++ b/src/main.c @@ -21,6 +21,10 @@ #include "shared.h" #include "event.h" +#ifdef WITH_BRAIN +#include "brain.h" +#endif + #if defined (__MINGW64__) || defined (__MINGW32__) int _dowildcard = -1; #endif @@ -1042,6 +1046,15 @@ int main (int argc, char **argv) user_options_t *user_options = hashcat_ctx->user_options; + #ifdef WITH_BRAIN + if (user_options->brain_server == true) + { + const int rc = brain_server (user_options->brain_host, user_options->brain_port, user_options->brain_password, user_options->brain_session_whitelist); + + return rc; + } + #endif + if (user_options->version == true) { printf ("%s\n", VERSION_TAG); diff --git a/src/opencl.c b/src/opencl.c index 2964d1773..40081411a 100644 --- a/src/opencl.c +++ b/src/opencl.c @@ -6456,6 +6456,10 @@ int opencl_session_begin (hashcat_ctx_t *hashcat_ctx) size_t size_pws_base = 4; size_t size_tmps = 4; size_t size_hooks = 4; + #ifdef WITH_BRAIN + size_t size_brain_link_in = 4; + size_t size_brain_link_out = 4; + #endif // instead of a thread limit we can also use a memory limit. // this value should represent a reasonable amount of memory a host system has per GPU. @@ -6494,6 +6498,13 @@ int opencl_session_begin (hashcat_ctx_t *hashcat_ctx) size_hooks = (size_t) kernel_power_max * hashconfig->hook_size; + #ifdef WITH_BRAIN + // size_brains + + size_brain_link_in = (size_t) kernel_power_max * 1; + size_brain_link_out = (size_t) kernel_power_max * 8; + #endif + if (user_options->slow_candidates == true) { // size_pws_pre @@ -6558,6 +6569,10 @@ int opencl_session_begin (hashcat_ctx_t *hashcat_ctx) = size_pws_comp + size_pws_idx + size_hooks + #ifdef WITH_BRAIN + + size_brain_link_in + + size_brain_link_out + #endif + size_pws_pre + size_pws_base; @@ -6591,6 +6606,10 @@ int opencl_session_begin (hashcat_ctx_t *hashcat_ctx) device_param->size_pws_base = size_pws_base; device_param->size_tmps = size_tmps; device_param->size_hooks = size_hooks; + #ifdef WITH_BRAIN + device_param->size_brain_link_in = size_brain_link_in; + device_param->size_brain_link_out = size_brain_link_out; + #endif CL_rc = hc_clCreateBuffer (hashcat_ctx, device_param->context, CL_MEM_READ_WRITE, size_pws, NULL, &device_param->d_pws_buf); if (CL_rc == -1) return -1; CL_rc = hc_clCreateBuffer (hashcat_ctx, device_param->context, CL_MEM_READ_WRITE, size_pws_amp, NULL, &device_param->d_pws_amp_buf); if (CL_rc == -1) return -1; @@ -6630,6 +6649,16 @@ int opencl_session_begin (hashcat_ctx_t *hashcat_ctx) device_param->scratch_buf = scratch_buf; + #ifdef WITH_BRAIN + u8 *brain_link_in_buf = (u8 *) hcmalloc (size_brain_link_in); + + device_param->brain_link_in_buf = brain_link_in_buf; + + u32 *brain_link_out_buf = (u32 *) hcmalloc (size_brain_link_out); + + device_param->brain_link_out_buf = brain_link_out_buf; + #endif + pw_pre_t *pws_pre_buf = (pw_pre_t *) hcmalloc (size_pws_pre); device_param->pws_pre_buf = pws_pre_buf; @@ -6749,6 +6778,10 @@ void opencl_session_destroy (hashcat_ctx_t *hashcat_ctx) hcfree (device_param->combs_buf); hcfree (device_param->hooks_buf); hcfree (device_param->scratch_buf); + #ifdef WITH_BRAIN + hcfree (device_param->brain_link_in_buf); + hcfree (device_param->brain_link_out_buf); + #endif if (device_param->d_pws_buf) hc_clReleaseMemObject (hashcat_ctx, device_param->d_pws_buf); if (device_param->d_pws_amp_buf) hc_clReleaseMemObject (hashcat_ctx, device_param->d_pws_amp_buf); diff --git a/src/status.c b/src/status.c index 1a7493ea5..d2a350295 100644 --- a/src/status.c +++ b/src/status.c @@ -230,6 +230,22 @@ char *status_get_session (const hashcat_ctx_t *hashcat_ctx) return strdup (user_options->session); } +#ifdef WITH_BRAIN +int status_get_brain_session (const hashcat_ctx_t *hashcat_ctx) +{ + const user_options_t *user_options = hashcat_ctx->user_options; + + return user_options->brain_session; +} + +int status_get_brain_attack (const hashcat_ctx_t *hashcat_ctx) +{ + const user_options_t *user_options = hashcat_ctx->user_options; + + return user_options->brain_attack; +} +#endif + const char *status_get_status_string (const hashcat_ctx_t *hashcat_ctx) { const status_ctx_t *status_ctx = hashcat_ctx->status_ctx; @@ -1768,6 +1784,136 @@ int status_get_iteration_left_dev (const hashcat_ctx_t *hashcat_ctx, const int d return iteration_left; } +#ifdef WITH_BRAIN +int status_get_brain_link_client_id_dev (const hashcat_ctx_t *hashcat_ctx, const int device_id) +{ + const opencl_ctx_t *opencl_ctx = hashcat_ctx->opencl_ctx; + + hc_device_param_t *device_param = &opencl_ctx->devices_param[device_id]; + + int brain_client_id = -1; + + if (device_param->skipped == false) + { + brain_client_id = device_param->brain_link_client_fd; + } + + return brain_client_id; +} + +int status_get_brain_link_status_dev (const hashcat_ctx_t *hashcat_ctx, const int device_id) +{ + const opencl_ctx_t *opencl_ctx = hashcat_ctx->opencl_ctx; + + hc_device_param_t *device_param = &opencl_ctx->devices_param[device_id]; + + int brain_link_status_dev = 0; + + if (device_param->skipped == false) + { + if (device_param->brain_link_client_fd != -1) brain_link_status_dev = BRAIN_LINK_STATUS_CONNECTED; + if (device_param->brain_link_recv_active == true) brain_link_status_dev = BRAIN_LINK_STATUS_RECEIVING; + if (device_param->brain_link_send_active == true) brain_link_status_dev = BRAIN_LINK_STATUS_SENDING; + } + + return brain_link_status_dev; +} + +char *status_get_brain_link_recv_bytes_dev (const hashcat_ctx_t *hashcat_ctx, const int device_id) +{ + const opencl_ctx_t *opencl_ctx = hashcat_ctx->opencl_ctx; + + hc_device_param_t *device_param = &opencl_ctx->devices_param[device_id]; + + u64 brain_link_recv_bytes = 0; + + if (device_param->skipped == false) + { + brain_link_recv_bytes = device_param->brain_link_recv_bytes; + } + + char *display = (char *) hcmalloc (HCBUFSIZ_TINY); + + format_speed_display_1k (brain_link_recv_bytes, display, HCBUFSIZ_TINY); + + return display; +} + +char *status_get_brain_link_send_bytes_dev (const hashcat_ctx_t *hashcat_ctx, const int device_id) +{ + const opencl_ctx_t *opencl_ctx = hashcat_ctx->opencl_ctx; + + hc_device_param_t *device_param = &opencl_ctx->devices_param[device_id]; + + u64 brain_link_send_bytes = 0; + + if (device_param->skipped == false) + { + brain_link_send_bytes = device_param->brain_link_send_bytes; + } + + char *display = (char *) hcmalloc (HCBUFSIZ_TINY); + + format_speed_display_1k (brain_link_send_bytes, display, HCBUFSIZ_TINY); + + return display; +} + +char *status_get_brain_link_recv_bytes_sec_dev (const hashcat_ctx_t *hashcat_ctx, const int device_id) +{ + const opencl_ctx_t *opencl_ctx = hashcat_ctx->opencl_ctx; + + hc_device_param_t *device_param = &opencl_ctx->devices_param[device_id]; + + u64 brain_link_recv_bytes = 0; + + if (device_param->skipped == false) + { + for (int idx = 0; idx < LINK_SPEED_COUNT; idx++) + { + double ms = hc_timer_get (device_param->brain_link_recv_speed.timer[idx]); + + if (ms >= 1000) continue; + + brain_link_recv_bytes += device_param->brain_link_recv_speed.bytes[idx]; + } + } + + char *display = (char *) hcmalloc (HCBUFSIZ_TINY); + + snprintf (display, HCBUFSIZ_TINY - 1, "%.2f M", (double) (brain_link_recv_bytes * 8) / 1024 / 1024); + + return display; +} + +char *status_get_brain_link_send_bytes_sec_dev (const hashcat_ctx_t *hashcat_ctx, const int device_id) +{ + const opencl_ctx_t *opencl_ctx = hashcat_ctx->opencl_ctx; + + hc_device_param_t *device_param = &opencl_ctx->devices_param[device_id]; + + u64 brain_link_send_bytes = 0; + + if (device_param->skipped == false) + { + for (int idx = 0; idx < LINK_SPEED_COUNT; idx++) + { + double ms = hc_timer_get (device_param->brain_link_send_speed.timer[idx]); + + if (ms >= 1000) continue; + + brain_link_send_bytes += device_param->brain_link_send_speed.bytes[idx]; + } + } + + char *display = (char *) hcmalloc (HCBUFSIZ_TINY); + + snprintf (display, HCBUFSIZ_TINY - 1, "%.2f M", (double) (brain_link_send_bytes * 8) / 1024 / 1024); + + return display; +} +#endif + char *status_get_hwmon_dev (const hashcat_ctx_t *hashcat_ctx, const int device_id) { const opencl_ctx_t *opencl_ctx = hashcat_ctx->opencl_ctx; @@ -2060,9 +2206,21 @@ void status_status_destroy (hashcat_ctx_t *hashcat_ctx, hashcat_status_t *hashca hcfree (device_info->speed_sec_dev); hcfree (device_info->guess_candidates_dev); hcfree (device_info->hwmon_dev); + #ifdef WITH_BRAIN + hcfree (device_info->brain_link_recv_bytes_dev); + hcfree (device_info->brain_link_send_bytes_dev); + hcfree (device_info->brain_link_recv_bytes_sec_dev); + hcfree (device_info->brain_link_send_bytes_sec_dev); + #endif device_info->speed_sec_dev = NULL; device_info->guess_candidates_dev = NULL; device_info->hwmon_dev = NULL; + #ifdef WITH_BRAIN + device_info->brain_link_recv_bytes_dev = NULL; + device_info->brain_link_send_bytes_dev = NULL; + device_info->brain_link_recv_bytes_sec_dev = NULL; + device_info->brain_link_send_bytes_sec_dev = NULL; + #endif } } diff --git a/src/terminal.c b/src/terminal.c index 1ac4a4713..c14c349eb 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -898,9 +898,26 @@ void status_display (hashcat_ctx_t *hashcat_ctx) * show something */ + #ifdef WITH_BRAIN + if (user_options->brain_client == true) + { + event_log_info (hashcat_ctx, + "Session..........: %s (Brain Session/Attack:0x%08x/0x%08x)", + hashcat_status->session, + hashcat_status->brain_session, + hashcat_status->brain_attack); + } + else + { + event_log_info (hashcat_ctx, + "Session..........: %s", + hashcat_status->session); + } + #else event_log_info (hashcat_ctx, "Session..........: %s", hashcat_status->session); + #endif event_log_info (hashcat_ctx, "Status...........: %s", @@ -1279,6 +1296,63 @@ void status_display (hashcat_ctx_t *hashcat_ctx) break; } + #ifdef WITH_BRAIN + if (user_options->brain_client == true) + { + for (int device_id = 0; device_id < hashcat_status->device_info_cnt; device_id++) + { + const device_info_t *device_info = hashcat_status->device_info_buf + device_id; + + if (device_info->skipped_dev == true) continue; + + if (device_info->brain_link_status_dev == BRAIN_LINK_STATUS_CONNECTED) + { + event_log_info (hashcat_ctx, + "Brain.Link.#%d....: RX: %sB (%sbps), TX: %sB (%sbps), idle", device_id + 1, + device_info->brain_link_recv_bytes_dev, + device_info->brain_link_recv_bytes_sec_dev, + device_info->brain_link_send_bytes_dev, + device_info->brain_link_send_bytes_sec_dev); + } + else if (device_info->brain_link_status_dev == BRAIN_LINK_STATUS_RECEIVING) + { + event_log_info (hashcat_ctx, + "Brain.Link.#%d....: RX: %sB (%sbps), TX: %sB (%sbps), receiving", device_id + 1, + device_info->brain_link_recv_bytes_dev, + device_info->brain_link_recv_bytes_sec_dev, + device_info->brain_link_send_bytes_dev, + device_info->brain_link_send_bytes_sec_dev); + } + else if (device_info->brain_link_status_dev == BRAIN_LINK_STATUS_SENDING) + { + event_log_info (hashcat_ctx, + "Brain.Link.#%d....: RX: %sB (%sbps), TX: %sB (%sbps), sending", device_id + 1, + device_info->brain_link_recv_bytes_dev, + device_info->brain_link_recv_bytes_sec_dev, + device_info->brain_link_send_bytes_dev, + device_info->brain_link_send_bytes_sec_dev); + } + else + { + if ((device_info->brain_link_time_recv_dev > 0) && (device_info->brain_link_time_send_dev > 0)) + { + event_log_info (hashcat_ctx, + "Brain.Link.#%d....: RX: %sB (%sbps), TX: %sB (%sbps)", device_id + 1, + device_info->brain_link_recv_bytes_dev, + device_info->brain_link_recv_bytes_sec_dev, + device_info->brain_link_send_bytes_dev, + device_info->brain_link_send_bytes_sec_dev); + } + else + { + event_log_info (hashcat_ctx, + "Brain.Link.#%d....: N/A", device_id + 1); + } + } + } + } + #endif + switch (hashcat_status->progress_mode) { case PROGRESS_MODE_KEYSPACE_KNOWN: diff --git a/src/usage.c b/src/usage.c index 87181385e..fbb994164 100644 --- a/src/usage.c +++ b/src/usage.c @@ -116,6 +116,16 @@ static const char *const USAGE_BIG[] = " --increment-min | Num | Start mask incrementing at X | --increment-min=4", " --increment-max | Num | Stop mask incrementing at X | --increment-max=8", " -S, --slow-candidates | | Enable slower (but advanced) candidate generators |", + #ifdef WITH_BRAIN + " --brain-server | | Enable brain server |", + " -z, --brain-client | | Enable brain client, activates -S |", + " --brain-client-features | Num | Define brain client features, see below | --brain-client-features=3", + " --brain-host | Str | Brain server host (IP or domain) | --brain-host=127.0.0.1", + " --brain-port | Port | Brain server port | --brain-port=13743", + " --brain-password | Str | Brain server authentication password | --brain-password=bZfhCvGUSjRq", + " --brain-session | Hex | Overrides automatically calculated brain session | --brain-session=0x2ae611db", + " --brain-session-whitelist | Hex | Allow given sessions only, separated with commas | --brain-session-whitelist=0x2ae611db", + #endif "", "- [ Hash modes ] -", "", @@ -383,6 +393,16 @@ static const char *const USAGE_BIG[] = " 18100 | TOTP (HMAC-SHA1) | One-Time Passwords", " 99999 | Plaintext | Plaintext", "", + #ifdef WITH_BRAIN + "- [ Brain Client Features ] -", + "", + " # | Features", + " ===+========", + " 1 | Send hashed passwords", + " 2 | Send attack positions", + " 3 | Send hashed passwords and attack positions", + "", + #endif "- [ Outfile Formats ] -", "", " # | Format", diff --git a/src/user_options.c b/src/user_options.c index 2bd767073..f9ce42d78 100644 --- a/src/user_options.c +++ b/src/user_options.c @@ -14,7 +14,15 @@ #include "outfile.h" #include "user_options.h" +#ifdef WITH_BRAIN +#include "brain.h" +#endif + +#ifdef WITH_BRAIN +static const char *short_options = "hVvm:a:r:j:k:g:o:t:d:D:n:u:c:p:s:l:1:2:3:4:iIbw:OSz"; +#else static const char *short_options = "hVvm:a:r:j:k:g:o:t:d:D:n:u:c:p:s:l:1:2:3:4:iIbw:OS"; +#endif static const struct option long_options[] = { @@ -110,6 +118,16 @@ static const struct option long_options[] = {"version", no_argument, NULL, IDX_VERSION}, {"wordlist-autohex-disable", no_argument, NULL, IDX_WORDLIST_AUTOHEX_DISABLE}, {"workload-profile", required_argument, NULL, IDX_WORKLOAD_PROFILE}, + #ifdef WITH_BRAIN + {"brain-client", no_argument, NULL, IDX_BRAIN_CLIENT}, + {"brain-client-features", required_argument, NULL, IDX_BRAIN_CLIENT_FEATURES}, + {"brain-server", no_argument, NULL, IDX_BRAIN_SERVER}, + {"brain-host", required_argument, NULL, IDX_BRAIN_HOST}, + {"brain-port", required_argument, NULL, IDX_BRAIN_PORT}, + {"brain-password", required_argument, NULL, IDX_BRAIN_PASSWORD}, + {"brain-session", required_argument, NULL, IDX_BRAIN_SESSION}, + {"brain-session-whitelist", required_argument, NULL, IDX_BRAIN_SESSION_WHITELIST}, + #endif {NULL, 0, NULL, 0 } }; @@ -133,6 +151,15 @@ int user_options_init (hashcat_ctx_t *hashcat_ctx) user_options->benchmark = BENCHMARK; user_options->bitmap_max = BITMAP_MAX; user_options->bitmap_min = BITMAP_MIN; + #ifdef WITH_BRAIN + user_options->brain_client = BRAIN_CLIENT; + user_options->brain_client_features = BRAIN_CLIENT_FEATURES; + user_options->brain_host = NULL; + user_options->brain_port = BRAIN_PORT; + user_options->brain_server = BRAIN_SERVER; + user_options->brain_session = BRAIN_SESSION; + user_options->brain_session_whitelist = NULL; + #endif user_options->cpu_affinity = NULL; user_options->custom_charset_1 = NULL; user_options->custom_charset_2 = NULL; @@ -284,6 +311,9 @@ int user_options_getopt (hashcat_ctx_t *hashcat_ctx, int argc, char **argv) case IDX_BITMAP_MAX: case IDX_INCREMENT_MIN: case IDX_INCREMENT_MAX: + #ifdef WITH_BRAIN + case IDX_BRAIN_PORT: + #endif if (hc_string_is_digit (optarg) == false) { @@ -421,6 +451,19 @@ int user_options_getopt (hashcat_ctx_t *hashcat_ctx, int argc, char **argv) case IDX_CUSTOM_CHARSET_3: user_options->custom_charset_3 = optarg; break; case IDX_CUSTOM_CHARSET_4: user_options->custom_charset_4 = optarg; break; case IDX_SLOW_CANDIDATES: user_options->slow_candidates = true; break; + #ifdef WITH_BRAIN + case IDX_BRAIN_CLIENT: user_options->brain_client = true; break; + case IDX_BRAIN_CLIENT_FEATURES: user_options->brain_client_features = hc_strtoul (optarg, NULL, 10); break; + case IDX_BRAIN_SERVER: user_options->brain_server = true; break; + case IDX_BRAIN_PASSWORD: user_options->brain_password = optarg; + user_options->brain_password_chgd = true; break; + case IDX_BRAIN_HOST: user_options->brain_host = optarg; + user_options->brain_host_chgd = true; break; + case IDX_BRAIN_PORT: user_options->brain_port = hc_strtoul (optarg, NULL, 10); + user_options->brain_port_chgd = true; break; + case IDX_BRAIN_SESSION: user_options->brain_session = hc_strtoul (optarg, NULL, 16); break; + case IDX_BRAIN_SESSION_WHITELIST: user_options->brain_session_whitelist = optarg; break; + #endif } } @@ -450,6 +493,29 @@ int user_options_sanity (hashcat_ctx_t *hashcat_ctx) return -1; } + #ifdef WITH_BRAIN + if ((user_options->brain_client == true) && (user_options->brain_server == true)) + { + event_log_error (hashcat_ctx, "Can not have --brain-client and --brain-server at the same time"); + + return -1; + } + + if ((user_options->brain_client_features < 1) && (user_options->brain_client_features > 3)) + { + event_log_error (hashcat_ctx, "Invalid --brain-client-feature argument"); + + return -1; + } + + if ((user_options->brain_client == true) && (user_options->brain_password_chgd == false)) + { + event_log_error (hashcat_ctx, "Brain clients need to set --brain-password"); + + return -1; + } + #endif + if (user_options->slow_candidates == true) { if ((user_options->attack_mode != ATTACK_MODE_STRAIGHT) @@ -461,6 +527,19 @@ int user_options_sanity (hashcat_ctx_t *hashcat_ctx) return -1; } } + #ifdef WITH_BRAIN + else if (user_options->brain_client == true) + { + if ((user_options->attack_mode != ATTACK_MODE_STRAIGHT) + && (user_options->attack_mode != ATTACK_MODE_COMBI) + && (user_options->attack_mode != ATTACK_MODE_BF)) + { + event_log_error (hashcat_ctx, "Invalid attack mode (-a) value specified in brain-client mode."); + + return -1; + } + } + #endif else { if ((user_options->attack_mode != ATTACK_MODE_STRAIGHT) @@ -979,6 +1058,22 @@ int user_options_sanity (hashcat_ctx_t *hashcat_ctx) } } + #ifdef WITH_BRAIN + if ((user_options->brain_client == true) && (user_options->remove == true)) + { + event_log_error (hashcat_ctx, "Using --remove is not allowed if --brain-client is used."); + + return -1; + } + + if ((user_options->brain_client == true) && (user_options->potfile_disable == true)) + { + event_log_error (hashcat_ctx, "Using --potfile-disable is not allowed if --brain-client is used."); + + return -1; + } + #endif + // custom charset checks if ((user_options->custom_charset_1 != NULL) @@ -1037,6 +1132,12 @@ int user_options_sanity (hashcat_ctx_t *hashcat_ctx) { show_error = false; } + #ifdef WITH_BRAIN + else if (user_options->brain_server == true) + { + show_error = false; + } + #endif else if (user_options->benchmark == true) { if (user_options->hc_argc == 0) @@ -1153,6 +1254,15 @@ int user_options_sanity (hashcat_ctx_t *hashcat_ctx) { // stdin mode + #ifdef WITH_BRAIN + if (user_options->brain_client == true) + { + event_log_error (hashcat_ctx, "Use of --brain-client is not possible in stdin mode."); + + return -1; + } + #endif + if (user_options->slow_candidates == true) { event_log_error (hashcat_ctx, "Use of --slow-candidates is not possible in stdin mode."); @@ -1260,6 +1370,13 @@ void user_options_preprocess (hashcat_ctx_t *hashcat_ctx) // some options can influence or overwrite other options + #ifdef WITH_BRAIN + if (user_options->brain_client == true) + { + user_options->slow_candidates = true; + } + #endif + if (user_options->example_hashes == true || user_options->opencl_info == true || user_options->keyspace == true @@ -1281,6 +1398,9 @@ void user_options_preprocess (hashcat_ctx_t *hashcat_ctx) user_options->status_timer = 0; user_options->bitmap_min = 1; user_options->bitmap_max = 1; + #ifdef WITH_BRAIN + user_options->brain_client = false; + #endif } if (user_options->benchmark == true) @@ -1302,6 +1422,9 @@ void user_options_preprocess (hashcat_ctx_t *hashcat_ctx) user_options->status_timer = 0; user_options->bitmap_min = 1; user_options->bitmap_max = 1; + #ifdef WITH_BRAIN + user_options->brain_client = false; + #endif if (user_options->workload_profile_chgd == false) { @@ -1745,6 +1868,51 @@ int user_options_check_files (hashcat_ctx_t *hashcat_ctx) user_options_extra_t *user_options_extra = hashcat_ctx->user_options_extra; user_options_t *user_options = hashcat_ctx->user_options; + // brain + + #ifdef WITH_BRAIN + #if defined (_WIN) + if ((user_options->brain_client == true) || (user_options->brain_server == true)) + { + WSADATA wsaData; + + WORD wVersionRequested = MAKEWORD (2,2); + + const int iResult = WSAStartup (wVersionRequested, &wsaData); + + if (iResult != NO_ERROR) + { + fprintf (stderr, "WSAStartup: %s\n", strerror (errno)); + + return -1; + } + } + #endif + + if (user_options->brain_host) + { + struct addrinfo hints; + + memset (&hints, 0, sizeof (hints)); + + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + struct addrinfo *address_info = NULL; + + const int rc_getaddrinfo = getaddrinfo (user_options->brain_host, NULL, &hints, &address_info); + + if (rc_getaddrinfo != 0) + { + fprintf (stderr, "%s: %s\n", user_options->brain_host, gai_strerror (rc_getaddrinfo)); + + return -1; + } + + freeaddrinfo (address_info); + } + #endif + // common folders #if defined (_WIN) @@ -2322,6 +2490,9 @@ void user_options_logger (hashcat_ctx_t *hashcat_ctx) logfile_ctx_t *logfile_ctx = hashcat_ctx->logfile_ctx; logfile_top_char (user_options->separator); + #ifdef WITH_BRAIN + logfile_top_string (user_options->brain_session_whitelist); + #endif logfile_top_string (user_options->cpu_affinity); logfile_top_string (user_options->custom_charset_1); logfile_top_string (user_options->custom_charset_2); @@ -2345,6 +2516,9 @@ void user_options_logger (hashcat_ctx_t *hashcat_ctx) logfile_top_string (user_options->session); logfile_top_string (user_options->truecrypt_keyfiles); logfile_top_string (user_options->veracrypt_keyfiles); + #ifdef WITH_BRAIN + logfile_top_string (user_options->brain_host); + #endif logfile_top_uint64 (user_options->limit); logfile_top_uint64 (user_options->skip); logfile_top_uint (user_options->attack_mode); @@ -2411,4 +2585,11 @@ void user_options_logger (hashcat_ctx_t *hashcat_ctx) logfile_top_uint (user_options->veracrypt_pim); logfile_top_uint (user_options->version); logfile_top_uint (user_options->workload_profile); + #ifdef WITH_BRAIN + logfile_top_uint (user_options->brain_client); + logfile_top_uint (user_options->brain_client_features); + logfile_top_uint (user_options->brain_server); + logfile_top_uint (user_options->brain_port); + logfile_top_uint (user_options->brain_session); + #endif }