Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions BACKLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ workflow remains local, deterministic, and GPU-optional.
- **F2 — Fail-closed potfile validation (P2):** normal runs now require an
existing regular, readable, writable potfile and reject invalid paths before
Hashcat starts; dry-run handling remains non-mutating for a missing potfile.
- **F3 — Runtime contract validation (P2):** wordlist-mode processors now
reject invalid selections consistently, and self-test validates the Markov
helper alongside the other job-specific dependencies.

## Planned

- **F3 — Runtime contract validation (P2):** reject invalid processor modes and
make self-test cover every job-specific helper, including Markov generation.
- **F4 — Supported macOS portability (P2):** remove GNU-only filesystem
assumptions and validate the documented Apple Silicon paths on a real target.
- **F5 — Interactive EOF handling (P3):** terminate the menu promptly when stdin
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ These are only needed for specific menu options.
- Needed for option `18`
- `scripts/extensions/common-substr-linux`
- Needed for options `10` and `11`
- `scripts/extensions/mkpass-linux`
- Needed for option `17` (Markov password generation)

#### macOS

Expand All @@ -60,6 +62,8 @@ These are only needed for specific menu options.
- Needed for option `18`
- `scripts/extensions/common-substr-mac`
- Needed for options `10` and `11`
- `scripts/extensions/mkpass-mac`
- Needed for option `17` (Markov password generation)

Notes:

Expand Down
31 changes: 31 additions & 0 deletions hash-cracker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -277,12 +277,34 @@ function dependency_fail() {
return 1
}

function processor_select_wordlist_mode() {
local mode="${1:-}"

case "$mode" in
[Ss]) source scripts/selectors/wordlist.sh ;;
[Mm]) source scripts/selectors/multiple-wordlist.sh ;;
*)
status_error "Invalid wordlist mode '$mode'. Choose S or M."
return 1
;;
esac
}

function markov_helper_path() {
if [ "$MACHINE" == "Mac" ]; then
printf '%s' "${MKPASS_BIN:-scripts/extensions/mkpass-mac}"
else
printf '%s' "${MKPASS_BIN:-scripts/extensions/mkpass-linux}"
fi
}

function check_job_dependencies() {
local selected="$1"
local common_substr_bin
local python_bin
local statsgen
local maskgen
local markov_bin

case "$selected" in
10 | 11)
Expand Down Expand Up @@ -346,6 +368,15 @@ function check_job_dependencies() {
return 1
fi
;;
17)
markov_bin="$(markov_helper_path)"
if [ ! -x "$markov_bin" ]; then
dependency_fail \
"Option 17 requires Markov helper '$markov_bin'." \
"restore the bundled mkpass helper or set MKPASS_BIN to an executable path."
return 1
fi
;;
18)
if [ -z "$CEWL" ] || [ ! -x "$CEWL" ]; then
dependency_fail \
Expand Down
6 changes: 1 addition & 5 deletions scripts/processors/17-markov-generator.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@

# Requirements
processor_bootstrap
if [ "$MACHINE" == "Mac" ]; then
mkpass_bin="${MKPASS_BIN:-scripts/extensions/mkpass-mac}"
else
mkpass_bin="${MKPASS_BIN:-scripts/extensions/mkpass-linux}"
fi
mkpass_bin="$(markov_helper_path)"

# Rules
source scripts/rules/rules.config
Expand Down
7 changes: 1 addition & 6 deletions scripts/processors/2-light.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,7 @@ processor_bootstrap
# Single or multiple wordlist
read -p "Single or Multiple wordlist mode? S/M: " MODE

if [[ $MODE = [Ss] ]]; then
source scripts/selectors/wordlist.sh
elif [[ $MODE = [Mm] ]]; then
source scripts/selectors/multiple-wordlist.sh
else
status_error "Invalid wordlist mode '$MODE'. Choose S or M."
if ! processor_select_wordlist_mode "$MODE"; then
exit 1
fi

Expand Down
6 changes: 2 additions & 4 deletions scripts/processors/20-stacker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ processor_bootstrap
# Single or multiple wordlist
read -p "Single or Multiple wordlist mode? S/M: " MODE

if [[ $MODE = [Ss] ]]; then
source scripts/selectors/wordlist.sh
elif [[ $MODE = [Mm] ]]; then
source scripts/selectors/multiple-wordlist.sh
if ! processor_select_wordlist_mode "$MODE"; then
exit 1
fi

# Rules
Expand Down
6 changes: 2 additions & 4 deletions scripts/processors/3-heavy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ processor_bootstrap
# Single or multiple wordlist
read -p "Single or Multiple wordlist mode? S/M: " MODE

if [[ $MODE = [Ss] ]]; then
source scripts/selectors/wordlist.sh
elif [[ $MODE = [Mm] ]]; then
source scripts/selectors/multiple-wordlist.sh
if ! processor_select_wordlist_mode "$MODE"; then
exit 1
fi

# Rules
Expand Down
7 changes: 1 addition & 6 deletions scripts/processors/6-hybrid.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,7 @@ processor_bootstrap
# Single or multiple wordlist
read -p "Single or Multiple wordlist mode? S/M: " MODE

if [[ $MODE = [Ss] ]]; then
source scripts/selectors/wordlist.sh
elif [[ $MODE = [Mm] ]]; then
source scripts/selectors/multiple-wordlist.sh
else
status_error "Invalid wordlist mode '$MODE'. Choose S or M."
if ! processor_select_wordlist_mode "$MODE"; then
exit 1
fi

Expand Down
6 changes: 2 additions & 4 deletions scripts/processors/7-toggle.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ processor_bootstrap
# Single or multiple wordlist
read -p "Single or Multiple wordlist mode? S/M: " MODE

if [[ $MODE = [Ss] ]]; then
source scripts/selectors/wordlist.sh
elif [[ $MODE = [Mm] ]]; then
source scripts/selectors/multiple-wordlist.sh
if ! processor_select_wordlist_mode "$MODE"; then
exit 1
fi

# Rules
Expand Down
27 changes: 27 additions & 0 deletions tests/smoke.sh
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,9 @@ run_case helper_missing_python_rulegen bash -lc "source '$REPO_ROOT/hash-cracker
assert_rc_eq 0
run_case helper_missing_python_maskgen bash -lc "source '$REPO_ROOT/hash-cracker.sh'; MACHINE=Linux; DRYRUN=''; PATH='$NO_PYTHON_PATH'; if check_job_dependencies 13; then exit 1; else exit 0; fi"
assert_rc_eq 0
run_case helper_missing_markov_helper bash -lc "source '$REPO_ROOT/hash-cracker.sh'; MACHINE=Linux; MKPASS_BIN='$TMP_DIR/missing-markov-helper'; if check_job_dependencies 17; then exit 1; else exit 0; fi"
assert_rc_eq 0
assert_contains "Option 17 requires Markov helper '$TMP_DIR/missing-markov-helper'."

run_case helper_self_test_hashcat_available bash -lc "source '$REPO_ROOT/hash-cracker.sh'; DRYRUN=''; HASHCAT_BIN=/bin/true; HASHLIST=/dev/null; WORDLIST=/dev/null; WORDLIST2=/dev/null; MACHINE=Linux; CEWL='$CEWL'; run_self_test >/dev/null 2>&1 || true"
assert_rc_eq 0
Expand Down Expand Up @@ -1616,10 +1619,27 @@ assert_contains "Stacking with light rules done"
run_case processor_2_invalid_mode bash -lc "printf '2\nx\n0\n' | ./hash-cracker.sh --dry-run"
assert_rc_eq 0
assert_contains "Invalid wordlist mode 'x'. Choose S or M."
assert_not_contains "Default processing with light rules done"

run_case processor_3_invalid_mode bash -lc "printf '3\nx\n0\n' | ./hash-cracker.sh --dry-run"
assert_rc_eq 0
assert_contains "Invalid wordlist mode 'x'. Choose S or M."
assert_not_contains "Default processing with heavy rules done"

run_case processor_6_invalid_mode bash -lc "printf '6\nx\n0\n' | ./hash-cracker.sh --dry-run"
assert_rc_eq 0
assert_contains "Invalid wordlist mode 'x'. Choose S or M."
assert_not_contains "Hybrid processing done"

run_case processor_7_invalid_mode bash -lc "printf '7\nx\n0\n' | ./hash-cracker.sh --dry-run"
assert_rc_eq 0
assert_contains "Invalid wordlist mode 'x'. Choose S or M."
assert_not_contains "Toggle processing done"

run_case processor_20_invalid_mode bash -lc "printf '20\nx\n0\n' | ./hash-cracker.sh --dry-run"
assert_rc_eq 0
assert_contains "Invalid wordlist mode 'x'. Choose S or M."
assert_not_contains "Stacking with light rules done"

echo "[smoke] processor input validation and alternate paths are exercised"
cat >"$CONFIG_PATH" <<EOF
Expand Down Expand Up @@ -2481,6 +2501,12 @@ fi
assert_contains "Option 18 requires CeWL executable"
assert_contains "Self-test failed"

MISSING_MKPASS="$TMP_DIR/missing-mkpass"
run_case self_test_markov_failure bash -lc "MKPASS_BIN='$MISSING_MKPASS' ./hash-cracker.sh --self-test --dry-run"
assert_rc_eq 1
assert_contains "Option 17 requires Markov helper '$MISSING_MKPASS'."
assert_contains "Self-test failed"

MISSING_PRESET_COMMON="$TMP_DIR/missing-preset-common"
run_case preset_dependency_failure bash -lc "COMMON_SUBSTR_BIN='$MISSING_PRESET_COMMON' ./hash-cracker.sh --dry-run --preset quick-plus"
assert_rc_eq 1
Expand Down Expand Up @@ -2531,6 +2557,7 @@ if [ "$LAST_RC" -ne 0 ] && [ "$LAST_RC" -ne 1 ]; then
exit 1
fi
assert_contains "Self-test: configuration and dependency checks"
assert_contains "Option 17 (Markov-chain passwords generator): OK"
if ! grep -Eq "Self-test (passed|failed)" "$LAST_LOG"; then
echo "[FAIL] expected self-test summary line"
cat "$LAST_LOG"
Expand Down