1
0
mirror of https://github.com/hashcat/hashcat.git synced 2025-07-19 13:08:19 +00:00

Merge pull request #4304 from matrix/test_edge

Introduced the 'edge' test type in test.pl along with its corresponding tool, test_edge.sh
This commit is contained in:
hashcat-bot 2025-07-10 18:48:56 +02:00 committed by GitHub
commit 1cc2d435dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 1089 additions and 3 deletions

View File

@ -75,6 +75,7 @@
- Added option --total-candidates to provide the total candidate count for an attack instead of the internal "--keyspace" value
- Added option --backend-devices-keepfree to configure X percentage of device memory available to keep free
- Added display of password length mininum and maximum in the Kernel.Feature status line
- Added the 'edge' test type to test.pl and the corresponding tool test_edge.sh
##
## Performance

View File

@ -27,7 +27,8 @@ Gabriele "matrix" Gristina <matrix@hashcat.net> (@gm4tr1x)
* Universal binary on Apple Silicon
* Hardware monitor initial code base and maintenance
* Test suite initial code base and maintenance
* Makefile initial code base
* Edge case testing suite
* Makefile initial code base and maintenance
* Multithreading initial code base
* MultiGPU initial code base
* Benchmarks initial code base

View File

@ -12,6 +12,8 @@ use Data::Types qw (is_count is_whole);
use File::Basename;
use FindBin;
use List::Util 'shuffle';
use Text::Iconv;
use Digest::MD4 qw (md4_hex);
# allows require by filename
use lib "$FindBin::Bin/test_modules";
@ -23,7 +25,7 @@ if (exists $ENV{"IS_OPTIMIZED"} && defined $ENV{"IS_OPTIMIZED"})
$IS_OPTIMIZED = $ENV{"IS_OPTIMIZED"};
}
my $TYPES = [ 'single', 'passthrough', 'potthrough', 'verify' ];
my $TYPES = [ 'edge', 'single', 'passthrough', 'potthrough', 'verify' ];
my $TYPE = shift @ARGV;
my $MODE = shift @ARGV;
@ -45,7 +47,13 @@ my $single_outputs = 8;
my $constraints = get_module_constraints ();
if ($TYPE eq 'single')
if ($TYPE eq 'edge')
{
usage_exit () if scalar @ARGV > 2;
edge (@ARGV);
}
elsif ($TYPE eq 'single')
{
single (@ARGV);
}
@ -68,6 +76,307 @@ else
usage_exit ();
}
sub edge_format
{
my $word_len = shift;
my $salt_len = shift;
my $attack_type = shift;
my $optimized = shift;
my $hash = "";
my $word = "";
my $salt = "";
my $cond = 0;
do
{
$word = random_numeric_string ($word_len) // "";
$salt = random_numeric_string ($salt_len) // "";
$hash = module_generate_hash ($word, $salt);
$cond = 1;
if ($MODE == 30901 && length ($hash) != 34)
{
$cond = 0;
}
} while ($cond != 1);
if (defined $hash)
{
my $format = "%d,%d,%d,%d,%d,'%s','%s','%s'\n";
printf ($format, $MODE, $attack_type, $optimized, $word_len, $salt_len, $word, $salt, $hash);
}
}
sub edge
{
my $attack_type = shift // 0;
my $optimized = shift // 0;
my @attack_types = (0, 1, 3, 6, 7);
if (not grep $_ == $attack_type, @attack_types)
{
return -1;
}
if ($optimized != 0 && $optimized != 1)
{
return -1;
}
my $idx_max = 0;
my $idx = 0;
my $word_min = ($optimized == 1) ? $constraints->[2]->[0] : $constraints->[0]->[0];
my $word_max = ($optimized == 1) ? $constraints->[2]->[1] : $constraints->[0]->[1];
my $salt_min = ($optimized == 1) ? $constraints->[3]->[0] : $constraints->[1]->[0];
my $salt_max = ($optimized == 1) ? $constraints->[3]->[1] : $constraints->[1]->[1];
my $comb_min = ($optimized == 1) ? $constraints->[4]->[0] : -1;
my $comb_max = ($optimized == 1) ? $constraints->[4]->[1] : -1;
if ($attack_type != 3)
{
if ($optimized == 1)
{
if ($word_min != $word_max && $word_max > 31)
{
$word_max = 31;
}
}
}
if ($attack_type != 0)
{
if ($word_min < 2)
{
$word_min = 2;
}
}
my $word_len = 0;
my $salt_len = 0;
# word_min, salt_min
# word_min, salt_max
# word_max, salt_min
# word_max, salt_max
if ($word_min != -1)
{
if ($salt_min != $salt_max)
{
if ($salt_min != -1) # word_min, salt_min
{
$word_len = $word_min;
$salt_len = $salt_min;
edge_format ($word_len, $salt_len, $attack_type, $optimized);
}
if ($salt_max != -1) # word_min, salt_max
{
my $salt_max_tmp = $salt_max;
if ($optimized == 1)
{
if ($salt_max_tmp > 51)
{
$salt_max_tmp = 51;
}
if ($comb_max != -1)
{
if (($word_len + $salt_max_tmp) > $comb_max)
{
my $off = $word_len + $salt_max_tmp - $comb_max;
if ($salt_max_tmp > $off)
{
$salt_max_tmp -= $off;
}
}
}
}
$word_len = $word_min;
$salt_len = $salt_max_tmp;
edge_format ($word_len, $salt_len, $attack_type, $optimized);
}
}
else
{
if ($salt_min != -1) # word_min, salt_min/salt_max (are the same)
{
$word_len = $word_min;
$salt_len = $salt_min;
edge_format ($word_len, $salt_len, $attack_type, $optimized);
}
else
{
# no salt
$word_len = $word_min;
$salt_len = 0;
edge_format ($word_len, $salt_len, $attack_type, $optimized);
}
}
}
if ($word_max != -1)
{
if ($salt_min != $salt_max)
{
my $last_word_len = -1;
my $last_salt_len = -1;
if ($salt_min != -1) # word_max, salt_min
{
$word_len = $word_max;
$salt_len = $salt_min;
if ($optimized == 1)
{
my $comb_max_cur = 55;
if ($comb_max != -1)
{
$comb_max_cur = $comb_max;
}
if (($word_len + $salt_len) > $comb_max_cur)
{
my $off = $word_len + $salt_len - $comb_max_cur;
if ($word_len > $off)
{
$word_len -= $off;
}
else
{
print ("ERROR with MODE $MODE, WORD $word_len, SALT $salt_len, MAX $comb_max_cur");
exit (1);
}
}
}
edge_format ($word_len, $salt_len, $attack_type, $optimized);
# save last
$last_word_len = $word_len;
$last_salt_len = $salt_len;
}
if ($salt_max != -1) # word_max, salt_max
{
$word_len = $word_max;
$salt_len = $salt_max;
if ($optimized == 1)
{
# limit comb_max to 55 if is not set
my $comb_max_cur = 55;
if ($comb_max != -1)
{
$comb_max_cur = $comb_max;
}
# limit salt_max to 51
my $salt_max_tmp = $salt_len;
if ($salt_max_tmp > 51)
{
$salt_max_tmp = 51;
}
if (($word_len + $salt_max_tmp) > $comb_max_cur)
{
my $off = $word_len + $salt_max_tmp - $comb_max_cur;
if ($last_word_len == $word_len)
{
$word_len -= $off;
if ($word_len < $word_min)
{
$off = $word_min - $word_len;
$word_len = $word_min;
$salt_max_tmp -= $off;
}
}
else
{
$salt_max_tmp -= $off;
if ($salt_max_tmp < $salt_min)
{
$off = $salt_min - $salt_max_tmp;
$salt_max_tmp = $salt_min;
$word_len -= $off;
}
}
}
$salt_len = $salt_max_tmp;
}
edge_format ($word_len, $salt_len, $attack_type, $optimized);
# reset last
$last_word_len = -1;
$last_salt_len = -1;
}
}
else
{
if ($salt_min != -1) # word_max, salt_min/salt_max (are the same)
{
$word_len = $word_max;
$salt_len = $salt_max;
if ($optimized == 1)
{
if ($comb_max != -1)
{
if (($word_len + $salt_len) > $comb_max)
{
my $off = $word_len + $salt_len - $comb_max;
if ($word_len > $off)
{
$word_len -= $off;
if ($word_len < $word_min)
{
$word_len = $word_min;
}
}
}
}
}
edge_format ($word_len, $salt_len, $attack_type, $optimized);
}
else
{
$word_len = $word_max;
$salt_len = 0;
edge_format ($word_len, $salt_len, $attack_type, $optimized);
}
}
}
}
sub single
{
my $len = shift;
@ -159,6 +468,13 @@ sub single
{
for my $salt (sort { length $a <=> length $b } keys %{$db_prev->{$word}})
{
if ($MODE == 31600 || $MODE == 31500)
{
my $converter = Text::Iconv->new('utf8', 'UTF-16LE');
$word = md4_hex ($converter->convert ($word));
}
my $hash = module_generate_hash ($word, $salt);
# possible if the requested length is not supported by algorithm
@ -592,11 +908,18 @@ sub usage_exit
print "\n"
. "Usage:\n"
. " $f edge <mode> [attack-type] [optimized]\n"
. " $f single <mode> [length]\n"
. " $f passthrough <mode>\n"
. " $f potthrough <mode>\n"
. " $f verify <mode> <hashfile> <cracksfile> <outfile>\n"
. "\n"
. "Edge:\n"
. " Generates edge case for selected <mode>.\n"
. " Will be generated a list of value separated by comma to stdout:\n"
. " <mode>,<attack-type>,<optimized>,<word_len>,<salt_len>,<word>,<salt>,<hash>\n"
. " The output can be processed by the test_edge.sh script.\n"
. "\n"
. "Single:\n"
. " Generates up to 32 hashes of random numbers of incrementing length, or up to 32\n"
. " hashes of random numbers of exact [length]. Writes shell commands to stdout that\n"

761
tools/test_edge.sh Executable file
View File

@ -0,0 +1,761 @@
#!/usr/bin/env bash
##
## Author......: See docs/credits.txt
## License.....: MIT
##
function usage()
{
echo "> Usage: $0 [<OPTIONS>]"
echo ""
echo "<OPTIONS>:"
echo ""
echo "-m / --hash-type <arg> : set Hash Type (default: all)"
echo " --hash-type-min <arg> : set min hash-type (default: 0)"
echo " --hash-type-max <arg> : set max hash-type (default: 99999)"
echo ""
echo "-a / --attack-type <arg> : set Attack Type (default: all. supported: 0 (Straight), 1 (Combination), 3 (Brute-force), 6 (Hybrid Wordlist + Mask), 7 (Hybrid Mask + Wordlist))"
echo "-K / --kernel-type <arg> : set Kernel-Type (default: all. supported: 0 (Pure), 1 (Optimized))"
echo "-t / --target-type <arg> : set Target Type (default: all. supported: single, multi)"
echo ""
echo "-V / --vector-width <arg> : set Vector Width (default: all. supported: 1, 2, 4, 8, 16)"
echo " --vector-width-min <arg> : set min vector-width (default: 1)"
echo " --vector-width-max <arg> : set max vector-width (default: 16)"
echo ""
echo "-d <arg> : set Device ID"
echo "-D <arg> : set Device-Type ID"
echo ""
echo "-r <arg> : set max runtime, in seconds, for each kernel execution (default: 270)"
echo " --metal-compiler-runtime <arg> : set max runtime, in seconds, for each kernel build using Apple Metal (default: 120)"
echo ""
echo " --metal-backend : exclude all hash types that do not work with Metal, exclude vector-width > 4, set --metal-compiler-runtime argument"
echo ""
echo "-f / --force : run hashcat using --force"
echo "-v / --verbose : show debug messages"
echo "-h / --help : show this help, then exit"
echo ""
exit 1
}
function is_in_array()
{
for e in "${@:2}"; do
[ "$e" = "$1" ] && return 0
done
return 1
}
export LC_CTYPE=C
export LANG=C
OUTD="test_edge_$(date +%s)"
HASH_TYPE=all
HASH_TYPE_MIN=0
HASH_TYPE_MAX=99999
ATTACK_TYPE=all
ATTACK_TYPES="0 1 3 6 7"
KERNEL_TYPE=all
TARGET_TYPE=all
VECTOR_WIDTH=all
VECTOR_WIDTHS="1 2 4 8 16"
VECTOR_WIDTH_MIN=1
VECTOR_WIDTH_MAX=16
FORCE=0
VERBOSE=0
RUNTIME_MAX=270 # 4.5 min
METAL_BACKEND=0
METAL_COMPILER_RUNTIME=120
OPTS="--quiet --potfile-disable --hwmon-disable --self-test-disable --machine-readable --logfile-disable"
SKIP_HASH_TYPES="2000 2500 2501 16800 16801 99999 32000"
SKIP_HASH_TYPES_METAL="1800 10700 11700 11750 11760 11800 11850 11860 19200 21600"
SKIP_METAL_SCRYPT="8900 15700 9300 22700 27700 28200 29800"
SKIP_OUT_MATCH_HASH_TYPES="14000 14100 18100 22000"
SKIP_SAME_SALT_HASH_TYPES="6600 7100 7200 8200 13200 13400 15300 15310 15900 15910 16900 18300 18900 20200 20300 20400 27000 27100 29700 29930 29940"
#SKIP_SAME_SALT_HASH_TYPES="400 3200 5800 6400 6500 6600 6700 7100 7200 7401 7900 8200 9100 9200 9400 10500 10901 12001 12200 12300 12400 12500 12700 12800 12900 13000 13200 13400 13600 14700 14800 15100 15200 15300 15310 15400 15600 15900 15910 16200 16300 16700 16900 18300 18400 18800 18900 19000 19100 19600 19700 19800 19900 20011 20012 20013 20200 20300 20400 21501 22100 22400 22600 23100 23300 23500 23600 23700 23900 24100 24200 24410 24420 24500 25300 25400 25500 25600 25800 26100 26500 26600 27000 27100 27400 27500 27600 28100 28400 28600 28800 28900 29600 29700 29910 29920 29930 29940 30600 31200 31900"
while [ $# -gt 0 ]; do
case $1 in
--metal-backend) METAL_BACKEND=1 ;;
--metal-compiler-runtime) METAL_COMPILER_RUNTIME=${2}; shift ;;
-r) RUNTIME_MAX=${2}; shift ;;
-h|--help) usage; break ;;
-v|--verbose) VERBOSE=1 ;;
-f|--force) FORCE=1 ;;
-V|--vector-width)
if [ "${2}" != "all" ]; then
if [[ ${2} =~ ^-?[0-9]+$ ]]; then
if [ "${2}" == "1" ]; then
VECTOR_WIDTH=1
elif [ "${2}" == "2" ]; then
VECTOR_WIDTH=2
elif [ "${2}" == "4" ]; then
VECTOR_WIDTH=4
elif [ "${2}" == "8" ]; then
VECTOR_WIDTH=8
elif [ "${2}" == "16" ]; then
VECTOR_WIDTH=16
else
usage
fi
else
usage
fi
fi
shift
;;
--vector-width-min) VECTOR_WIDTH_MIN=${2}; shift ;;
--vector-width-max) VECTOR_WIDTH_MAX=${2}; shift ;;
-t|--target-type)
if [ "${2}" != "all" ]; then
if [ "${2}" == "single" ]; then
TARGET_TYPE=0
elif [ "${2}" == "multi" ]; then
TARGET_TYPE=1
else
usage
fi
fi
shift
;;
-m|--hash-type)
if [ "${2}" != "all" ]; then
if [[ ${2} =~ ^-?[0-9]+$ ]]; then
HASH_TYPE=${2}
else
usage
fi
fi
shift
;;
--hash-type-min) HASH_TYPE_MIN=${2}; shift ;;
--hash-type-max) HASH_TYPE_MAX=${2}; shift ;;
-a|--attack-type)
if [ "${2}" != "all" ]; then
if [[ ${2} =~ ^-?[0-9]+$ ]]; then
if [ "${2}" == "0" ]; then
ATTACK_TYPE=0
elif [ "${2}" == "1" ]; then
ATTACK_TYPE=1
elif [ "${2}" == "3" ]; then
ATTACK_TYPE=3
elif [ "${2}" == "6" ]; then
ATTACK_TYPE=6
elif [ "${OPTARG}" == "7" ]; then
ATTACK_TYPE=7
else
usage
fi
else
usage
fi
fi
shift
;;
-K|--kernel-type)
if [ "${2}" != "all" ]; then
if [[ ${2} =~ ^-?[0-9]+$ ]]; then
if [ "${2}" == "0" ]; then
KERNEL_TYPE=0 #pure
elif [ "${2}" == "1" ]; then
KERNEL_TYPE=1 #optimized
else
usage
fi
else
usage
fi
fi
shift
;;
-d) OPTS="${OPTS} -d ${2}"; shift ;;
-D)
if [ "${2}" == "1" ]; then
OPTS="${OPTS} -D 1"
DEVICE_TYPE="Cpu"
elif [ "${2}" == "2" ]; then
OPTS="${OPTS} -D 2"
DEVICE_TYPE="Gpu"
else
OPTS="${OPTS} -D ${2}"
DEVICE_TYPE="Cpu + Gpu"
fi
shift
;;
*) echo "Unknown parameter passed: $1"; usage; break ;;
esac
shift
done
OPTS="${OPTS} --runtime ${RUNTIME_MAX}"
if [ ${FORCE} -eq 1 ]; then
OPTS="${OPTS} --force"
fi
if [ $METAL_BACKEND -eq 1 ]; then
VECTOR_WIDTHS="1 2 4"
if [ $VECTOR_WIDTH_MAX -gt 4 ]; then
VECTOR_WIDTH_MAX=4
fi
if [ $METAL_COMPILER_RUNTIME -ne 120 ]; then
OPTS="${OPTS} --metal-compiler-runtime ${METAL_COMPILER_RUNTIME}"
fi
fi
mkdir -p ${OUTD} &> /dev/null
for hash_type in $(ls tools/test_modules/*.pm | cut -d'm' -f3 | cut -d'.' -f1 | awk '{print $1+=0}'); do
if [ $HASH_TYPE != "all" ]; then
if [ $HASH_TYPE -ne $hash_type ]; then continue; fi
else
if [ $hash_type -lt ${HASH_TYPE_MIN} ]; then continue; fi
if [ $hash_type -gt ${HASH_TYPE_MAX} ]; then continue; fi
fi
if is_in_array "${hash_type}" ${SKIP_HASH_TYPES}; then
echo "[ ${OUTD} ] > Skip processing Hash-Type ${hash_type} (common)" | tee -a ${OUTD}/test_edge.details.log
continue
fi
if [ $METAL_BACKEND -eq 1 ]; then
if is_in_array "${hash_type}" ${SKIP_HASH_TYPES_METAL}; then
echo "[ ${OUTD} ] > Skip processing Hash-Type ${hash_type} (due to metal kernel build failed)" | tee -a ${OUTD}/test_edge.details.log
continue
fi
if is_in_array "${hash_type}" ${SKIP_METAL_SCRYPT}; then
echo "[ ${OUTD} ] > Skip processing Hash-Type ${hash_type} (due to metal scrypt is broken)" | tee -a ${OUTD}/test_edge.details.log
continue
fi
fi
build_failed_err=0
test_vectors_err=0
for attack_type in ${ATTACK_TYPES}; do
if [ $ATTACK_TYPE != "all" ] && [ $ATTACK_TYPE -ne $attack_type ]; then continue; fi
kernel_types=$(./hashcat -m ${hash_type} -HH | grep 'Kernel.Type(s' | cut -d: -f2 | xargs | sed -e 's/,//g')
for kernel_type in ${kernel_types}; do
kernel_type_pad=$(printf "%9s\n" ${kernel_type})
CUR_OPTS="${OPTS}"
optimized=0
if [ "${kernel_type}" == "optimized" ]; then
optimized=1
CUR_OPTS="${CUR_OPTS} -O"
fi
if [ $KERNEL_TYPE != "all" ] && [ $KERNEL_TYPE -ne $optimized ]; then continue; fi
tmp_salt=$(./hashcat -m ${hash_type} -HH | grep Salt\\.Type)
have_salt=$?
if [ $have_salt -eq 0 ]; then
salt_type=$(echo $tmp_salt | awk '{print $2}')
if [ $salt_type == "Virtual" ]; then
have_salt=1
fi
fi
slow_hash=0
tmp_slow_hash=$(./hashcat -m ${hash_type} -HH | grep Slow\\.Hash | awk '{print $2}')
if [ "${tmp_slow_hash}" == "Yes" ]; then
slow_hash=1
fi
pt_hex=0
tmp_pw_type=$(./hashcat -m ${hash_type} -HH | grep Password\\.Type | awk '{print $2}')
if [ "${tmp_pw_type}" == "HEX" ]; then
pt_hex=1
fi
echo "[ ${OUTD} ] # Export tests for Hash-Type ${hash_type}, Attack-Type ${attack_type}, Kernel-Type ${kernel_type}" >> ${OUTD}/test_edge.details.log
edge_out="${OUTD}/edge_${hash_type}_${kernel_type}_${attack_type}.out"
./tools/test.pl edge ${hash_type} ${attack_type} ${optimized} 2>/dev/null > ${edge_out}
if [ ${VERBOSE} -eq 1 ]; then
cat ${edge_out}
fi
if [ $? -eq 0 ]; then
check_hash=$(cat ${edge_out} | cut -d, -f8- | head -1)
if [ ${#check_hash} -eq 2 ] || [ ${#check_hash} -eq 3 ]; then
echo "[ ${OUTD} ] !> error detected with Hash-Type ${hash_type}: empty test vectors" | tee -a ${OUTD}/test_edge.details.log
break
fi
for vector_width in ${VECTOR_WIDTHS}; do
if [ $VECTOR_WIDTH != "all" ]; then
if [ $VECTOR_WIDTH -ne $vector_width ]; then continue; fi
else
if [ ${vector_width} -lt ${VECTOR_WIDTH_MIN} ]; then continue; fi
if [ ${vector_width} -gt ${VECTOR_WIDTH_MAX} ]; then continue; fi
fi
CUR_OPTS_V="${CUR_OPTS} --backend-vector-width ${vector_width}"
# single hash
if [ $TARGET_TYPE == all ] || [ $TARGET_TYPE == 0 ]; then
echo "[ ${OUTD} ] # Processing Hash-Type ${hash_type}, Attack-Type ${attack_type}, Kernel-Type ${kernel_type}, Vector-Width ${vector_width}, Target-Type single" | tee -a ${OUTD}/test_edge.details.log
cnt=$(wc -l ${edge_out} | awk '{print $1}')
for ((i = 1; i <= cnt; i++)); do
word_compare=None
word_len=$(cat ${edge_out} | cut -d, -f4 | head -${i} | tail -1)
salt_len=$(cat ${edge_out} | cut -d, -f5 | head -${i} | tail -1)
word=$(cat ${edge_out} | cut -d, -f6 | head -${i} | tail -1)
salt=$(cat ${edge_out} | cut -d, -f7 | head -${i} | tail -1)
hash=$(cat ${edge_out} | cut -d, -f8- | head -${i} | tail -1)
x="echo -n '${word}'"
if [ "${hash_type}" == "20510" ]; then
word_compare="echo -n '${word}'"
x="echo -n '${word}' | cut -b7-"
fi
if [ ${have_salt} -eq 1 ]; then
salt_len="None"
salt=
else
z="echo -n '${salt}'"
salt=$(eval $z)
fi
word=$(eval $x)
if [ ${VERBOSE} -eq 1 ]; then
echo "[ ${OUTD} ] > Hash-Type ${hash_type}, Attack-Type ${attack_type}, Kernel-Type ${kernel_type}, Test ID ${i}, Word len ${word_len}, Salt len ${salt_len}, Word '${word}', Salt '${salt}', Hash ${hash}" | tee -a ${OUTD}/test_edge.details.log
else
echo "[ ${OUTD} ] > Hash-Type ${hash_type}, Attack-Type ${attack_type}, Kernel-Type ${kernel_type}, Test ID ${i}, Word len ${word_len}, Salt len ${salt_len}, Word '${word}', Salt '${salt}', Hash ${hash}" >> ${OUTD}/test_edge.details.log
fi
CMD=""
if [ "${attack_type}" -eq 0 ]; then
#echo ${word} > test_${hash_type}_${kernel_type}_${attack_type}_${i}.word
CMD="echo ${word} | ./hashcat ${CUR_OPTS_V} -m ${hash_type} ${hash} -a 0"
elif [ "${attack_type}" -eq 1 ]; then
word=$(eval $x)
if [ "${word_len}" -eq 2 ]; then
word_1=$(echo $word | cut -c -1)
word_2=$(echo $word | cut -c 2-)
elif [ "${word_len}" -gt 2 ]; then
word_1_cnt=$((word_len/2))
word_1=$(echo $word | cut -c -${word_1_cnt})
((word_1_cnt++))
word_2=$(echo $word | cut -c ${word_1_cnt}-)
fi
echo ${word_1} > ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}_${i}.1.word
echo ${word_2} > ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}_${i}.2.word
CMD="./hashcat ${CUR_OPTS_V} -m ${hash_type} ${hash} -a 1 ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}_${i}.1.word ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}_${i}.2.word"
elif [ "${attack_type}" -eq 3 ]; then
if [ $pt_hex -eq 1 ]; then
word_1="${word%??}"
mask_1="?b"
else
if [ "${word_len}" -eq 2 ]; then
word_1="${word%?}"
mask_1="?d"
elif [ "${slow_hash}" -eq 1 ]; then
word_1="${word%??}"
mask_1="?d?d"
else
word_1="${word%???}"
mask_1="?d?d?d"
fi
fi
CMD="./hashcat ${CUR_OPTS_V} -m ${hash_type} ${hash} -a 3 ${word_1}${mask_1}"
elif [ "${attack_type}" -eq 6 ]; then
if [ $pt_hex -eq 1 ]; then
word_1="${word%??}"
mask_1="?b"
else
if [ "${word_len}" -eq 2 ] || [ "${slow_hash}" -eq 1 ]; then
word_1="${word%?}"
mask_1="?d"
else
word_1="${word%??}"
mask_1="?d?d"
fi
fi
echo -n ${word_1} > ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}_${i}_1.word
CMD="./hashcat ${CUR_OPTS_V} -m ${hash_type} ${hash} -a 6 ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}_${i}_1.word ${mask_1}"
elif [ "${attack_type}" -eq 7 ]; then
if [ $pt_hex -eq 1 ]; then
word_1="${word#??}"
mask_1="?b"
else
if [ "${word_len}" -eq 2 ] || [ "${slow_hash}" -eq 1 ]; then
word_1="${word#?}"
mask_1="?d"
else
word_1="${word#??}"
mask_1="?d?d"
fi
fi
echo -n ${word_1} > ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}_${i}_2.word
CMD="./hashcat ${CUR_OPTS_V} -m ${hash_type} ${hash} -a 7 ${mask_1} ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}_${i}_2.word"
fi
cmd_out="${OUTD}/cmd_${hash_type}_${kernel_type}_${attack_type}_${i}.single.log"
eval ${CMD} &> ${cmd_out}
retVal=$?
#echo "RET: $retVal"
cat ${cmd_out} >> ${OUTD}/test_edge.details.log
if [ "${retVal}" -ne 0 ]; then
echo "[ ${OUTD} ] !> error ($retVal) detected with CMD: ${CMD}" | tee -a ${OUTD}/test_edge.details.log
echo "[ ${OUTD} ] !> Hash-Type ${hash_type}, Attack-Type ${attack_type}, Kernel-Type ${kernel_type}, Vector-Width ${vector_width}, Test ID ${i}, Word len ${word_len}, Salt len ${salt_len}, Word '${word}', Hash ${hash}" | tee -a ${OUTD}/test_edge.details.log
echo '```' | tee -a ${OUTD}/test_edge.details.log
cat ${cmd_out} | tee -a ${OUTD}/test_edge.details.log
echo '```' | tee -a ${OUTD}/test_edge.details.log
if [ "${retVal}" -eq 250 ]; then
echo "[ ${OUTD} ] > Skipping current tests due to build error ..." | tee -a ${OUTD}/test_edge.details.log
break
fi
else
if is_in_array "${hash_type}" ${SKIP_OUT_MATCH_HASH_TYPES}; then
echo "[ ${OUTD} ] > Skip output check for Hash-Type ${hash_type} (due to collisions)" >> ${OUTD}/test_edge.details.log
continue
fi
./hashcat -m ${hash_type} -HH | grep 'Keep.Guessing.......: Yes' &> /dev/null
if [ $? -eq 0 ]; then
echo "[ ${OUTD} ] > Skip output check for Hash-Type ${hash_type} (due to keep guessing)" >> ${OUTD}/test_edge.details.log
continue
fi
out=$(grep -v "Unsupported\|STATUS\|^$" ${cmd_out} | sed -e 's/ (user password.*$//g')
x="echo -n ${hash}"
hash=$(eval $x)
md5_1=$(echo ${out} | md5sum | cut -d' ' -f1)
hc_out="${hash}:${word}"
if [ "${word_compare}" != "None" ]; then
word_tmp=$(eval $word_compare)
hc_out="${hash}:${word_tmp}"
fi
md5_2=$(echo ${hc_out} | md5sum | cut -d' ' -f1)
if [ $md5_1 != $md5_2 ]; then
echo "[ ${OUTD} ] !> error detected with CMD: ${CMD}" | tee -a ${OUTD}/test_edge.details.log
echo "[ ${OUTD} ] !> Hash-Type ${hash_type}, Attack-Type ${attack_type}, Kernel-Type ${kernel_type}, Vector-Width ${vector_width}, Test ID ${i}, Word len ${word_len}, Salt len ${salt_len}, Word '${word}', Salt '${salt}', Hash ${hash}" | tee -a ${OUTD}/test_edge.details.log
echo "[ ${OUTD} ] !> output don't match" | tee -a ${OUTD}/test_edge.details.log
echo '```' | tee -a ${OUTD}/test_edge.details.log
echo ${out} | tee -a ${OUTD}/test_edge.details.log
echo '```' | tee -a ${OUTD}/test_edge.details.log
echo "! expected output" | tee -a ${OUTD}/test_edge.details.log
echo '```' | tee -a ${OUTD}/test_edge.details.log
echo ${hc_out} | tee -a ${OUTD}/test_edge.details.log
echo '```' | tee -a ${OUTD}/test_edge.details.log
fi
fi
done
fi
# multi hash
if [ $TARGET_TYPE == all ] || [ $TARGET_TYPE == 1 ]; then
cnt_max=-1
tmp_cnt_max=$(./hashcat -m ${hash_type} -HH | grep Hashes\\.Count\\.Max | awk '{print $2}')
if [[ $tmp_cnt_max =~ ^-?[0-9]+$ ]]; then
cnt_max=$tmp_cnt_max
fi
if [ $hash_type -eq 20510 ]; then
cnt_max=1
fi
if [ $cnt_max -eq 1 ]; then
# cannot exec multi-hash because this hash_type allow max 1 hash at time
echo "[ ${OUTD} ] > Skipping Hash-Type ${hash_type}, Attack-Type ${attack_type}, Kernel-Type ${kernel_type}, Vector-Width ${vector_width}, Target-Type multi (max 1 hash at time allowed)" | tee -a ${OUTD}/test_edge.details.log
cnt=0
continue
fi
# check if hash_type cannot crack multiple hashes with the same salt
same_salt=1
is_in_array "${hash_type}" ${SKIP_SAME_SALT_HASH_TYPES}
if [ ${?} -eq 1 ]; then
multi_hashes_same_salt_allowed=$(./hashcat -m ${hash_type} -HH | grep Hashes\\.w/\\.Same\\.Salt | awk '{print $2}')
if [ "${multi_hashes_same_salt_allowed}" == "Not" ]; then
same_salt=0
fi
fi
cnt=$(wc -l ${edge_out} | awk '{print $1}')
if [ $cnt -eq 0 ]; then
echo "[ ${OUTD} ] > Skipping Hash-Type ${hash_type}, Attack-Type ${attack_type}, Kernel-Type ${kernel_type}, Vector-Width ${vector_width}, Target-Type multi (due to no valid test vectors)" | tee -a ${OUTD}/test_edge.details.log
continue
fi
echo "[ ${OUTD} ] # Processing Hash-Type ${hash_type}, Attack-Type ${attack_type}, Kernel-Type ${kernel_type}, Vector-Width ${vector_width}, Target-Type multi" | tee -a ${OUTD}/test_edge.details.log
CMD=""
SALTS_VAL=""
hash_cnt=0
hash_in="${OUTD}/edge_${hash_type}_${kernel_type}_${attack_type}_${vector_width}.hashes"
for ((i = 1; i <= cnt; i++)); do
# limit to cnt_max if is set
if [ ${cnt_max} -gt 1 ] && [ ${hash_cnt} -gt ${cnt_max} ]; then continue; fi
word_compare=None
word_len=$(cat ${edge_out} | cut -d, -f4 | head -${i} | tail -1)
salt_len=$(cat ${edge_out} | cut -d, -f5 | head -${i} | tail -1)
word=$(cat ${edge_out} | cut -d, -f6 | head -${i} | tail -1)
salt=$(cat ${edge_out} | cut -d, -f7 | head -${i} | tail -1)
hash=$(cat ${edge_out} | cut -d, -f8- | head -${i} | tail -1)
x="echo -n '${word}'"
y="echo -n ${hash}"
if [ "${hash_type}" == "20510" ]; then
word_compare="echo -n '${word}'"
x="echo -n '${word}' | cut -b7-"
fi
if [ ${have_salt} -eq 1 ]; then
salt_len="None"
salt=
else
z="echo -n '${salt}'"
salt=$(eval $z)
# skip hashes with same salt if are not allowed
if [ ${same_salt} -eq 0 ]; then
if is_in_array "${salt_len}:${salt}" ${SALTS_VAL}; then
continue
fi
if [ ${#SALTS_VAL} -eq 0 ]; then
SALTS_VAL="${salt_len}:${salt}"
else
SALTS_VAL="${SALTS_VAL} ${salt_len}:${salt}"
fi
fi
fi
word=$(eval $x)
hash=$(eval $y)
echo $hash >> ${hash_in}
if [ "${word_compare}" != "None" ]; then
w=$(eval $word_compare)
echo $w >> ${OUTD}/edge_${hash_type}_${kernel_type}_${attack_type}_${vector_width}.words_compare
else
echo ${word} >> ${OUTD}/edge_${hash_type}_${kernel_type}_${attack_type}_${vector_width}.words
fi
if [ "${attack_type}" -eq 0 ]; then
((hash_cnt++))
echo ${word} >> ${OUTD}/edge_${hash_type}_${kernel_type}_${attack_type}.1.words
CMD="cat ${OUTD}/edge_${hash_type}_${kernel_type}_${attack_type}.1.words | ./hashcat ${CUR_OPTS_V} -m ${hash_type} ${hash_in} -a 0"
elif [ "${attack_type}" -eq 1 ]; then
((hash_cnt++))
if [ "${word_len}" -eq 2 ]; then
word_1=$(echo $word | cut -c -1)
word_2=$(echo $word | cut -c 2-)
elif [ "${word_len}" -gt 2 ]; then
word_1_cnt=$((word_len/2))
word_1=$(echo $word | cut -c -${word_1_cnt})
((word_1_cnt++))
word_2=$(echo $word | cut -c ${word_1_cnt}-)
fi
echo ${word_1} >> ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}.1.words
echo ${word_2} >> ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}.2.words
CMD="./hashcat ${CUR_OPTS_V} -m ${hash_type} ${hash_in} -a 1 ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}.1.words ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}.2.words"
elif [ "${attack_type}" -eq 3 ]; then
((hash_cnt++))
if [ $pt_hex -eq 1 ]; then
word_1="${word%??}"
mask_1="?b"
else
if [ "${word_len}" -eq 2 ]; then
word_1="${word%?}"
mask_1="?d"
elif [ "${slow_hash}" -eq 1 ]; then
word_1="${word%??}"
mask_1="?d?d"
else
word_1="${word%???}"
mask_1="?d?d?d"
fi
fi
echo -n ${word_1} >> ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}.1.words.masks
echo ${mask_1} >> ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}.1.words.masks
CMD="./hashcat ${CUR_OPTS_V} -m ${hash_type} ${hash_in} -a 3 ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}.1.words.masks"
elif [ "${attack_type}" -eq 6 ]; then
((hash_cnt++))
if [ $pt_hex -eq 1 ]; then
word_1="${word%??}"
mask_1="?b"
else
if [ "${word_len}" -eq 2 ] || [ "${slow_hash}" -eq 1 ]; then
word_1="${word%?}"
mask_1="?d"
else
word_1="${word%??}"
mask_1="?d?d"
fi
fi
echo ${word_1} >> ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}.1.words
echo ${mask_1} >> ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}.1.masks
CMD="./hashcat ${CUR_OPTS_V} -m ${hash_type} ${hash_in} -a 6 ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}.1.words ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}.1.masks"
elif [ "${attack_type}" -eq 7 ]; then
((hash_cnt++))
if [ $pt_hex -eq 1 ]; then
word_1="${word#??}"
mask_1="?b"
else
if [ "${word_len}" -eq 2 ] || [ "${slow_hash}" -eq 1 ]; then
word_1="${word#?}"
mask_1="?d"
else
word_1="${word#??}"
mask_1="?d?d"
fi
fi
echo ${word_1} >> ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}.2.words
echo ${mask_1} >> ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}.2.masks
CMD="./hashcat ${CUR_OPTS_V} -m ${hash_type} ${hash_in} -a 7 ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}.2.masks ${OUTD}/test_${hash_type}_${kernel_type}_${attack_type}.2.words"
fi
done
# echo "hash_cnt: $hash_cnt"
# cat ${OUTD}/edge_${hash_type}_${kernel_type}_${attack_type}.hashes
if [ $hash_cnt -gt 1 ]; then
cmd_out="${OUTD}/cmd_${hash_type}_${kernel_type}_${attack_type}_${vector_width}.multi.log"
eval ${CMD} &> ${cmd_out}
retVal=$?
cat ${cmd_out} >> ${OUTD}/test_edge.details.log
hc_out="${OUTD}/edge_${hash_type}_${kernel_type}_${attack_type}_${vector_width}.hashes.words"
if [ "${word_compare}" != "None" ]; then
word_in="${OUTD}/edge_${hash_type}_${kernel_type}_${attack_type}_${vector_width}.words_compare"
else
word_in="${OUTD}/edge_${hash_type}_${kernel_type}_${attack_type}_${vector_width}.words"
fi
paste -d ":" ${hash_in} ${word_in} > ${hc_out}
if [ "${retVal}" -ne 0 ]; then
echo "[ ${OUTD} ] !> error ($retVal) detected with CMD: ${CMD}" | tee -a ${OUTD}/test_edge.details.log
echo "[ ${OUTD} ] !> Hash-Type ${hash_type}, Attack-Type ${attack_type}, Kernel-Type ${kernel_type}, Vector-Width ${vector_width}, Words ${word_in}, Hashes ${hash_in}" | tee -a ${OUTD}/test_edge.details.log
echo '```' | tee -a ${OUTD}/test_edge.details.log
cat ${cmd_out} | tee -a ${OUTD}/test_edge.details.log
echo '```' | tee -a ${OUTD}/test_edge.details.log
if [ "${retVal}" -eq 250 ]; then
echo "[ ${OUTD} ] > Skipping current tests due to build error ..." | tee -a ${OUTD}/test_edge.details.log
break
fi
else
if is_in_array "${hash_type}" ${SKIP_OUT_MATCH_HASH_TYPES}; then
echo "[ ${OUTD} ] > Skip output check for Hash-Type ${hash_type} (due to collisions)" >> ${OUTD}/test_edge.details.log
continue
fi
./hashcat -m ${hash_type} -HH | grep 'Keep.Guessing.......: Yes' &> /dev/null
if [ $? -eq 0 ]; then
echo "[ ${OUTD} ] > Skip output check for Hash-Type ${hash_type} (due to keep guessing)" >> ${OUTD}/test_edge.details.log
continue
fi
out=$(grep -v "Unsupported\|STATUS\|^$" ${cmd_out} | sed -e 's/ (user password.*$//g')
md5_1=$(echo "${out}" | sort -s | md5sum | cut -d' ' -f1)
md5_2=$(cat ${hc_out} | sort -s | md5sum | cut -d' ' -f1)
if [ $md5_1 != $md5_2 ]; then
echo "[ ${OUTD} ] !> error detected (output don't match) with CMD: ${CMD}" | tee -a ${OUTD}/test_edge.details.log
echo "[ ${OUTD} ] !> Hash-Type ${hash_type}, Attack-Type ${attack_type}, Kernel-Type ${kernel_type}, Vector-Width ${vector_width}, Words ${word_in}, Hashes ${hash_in}" | tee -a ${OUTD}/test_edge.details.log
echo "! output" | tee -a ${OUTD}/test_edge.details.log
echo '```' | tee -a ${OUTD}/test_edge.details.log
echo "${out}" | sort -s | tee -a ${OUTD}/test_edge.details.log
echo '```' | tee -a ${OUTD}/test_edge.details.log
echo "! expected output" | tee -a ${OUTD}/test_edge.details.log
echo '```' | tee -a ${OUTD}/test_edge.details.log
cat ${hc_out} | sort -s | tee -a ${OUTD}/test_edge.details.log
echo '```' | tee -a ${OUTD}/test_edge.details.log
fi
fi
else
echo "[ ${OUTD} ] > Skipping Hash-Type ${hash_type}, Attack-Type ${attack_type}, Kernel-Type ${kernel_type}, Vector-Width ${vector_width}, Target-Type multi, Hashes ${hash_in} (hashes < 2)" | tee -a ${OUTD}/test_edge.details.log
echo "hash_cnt: ${hash_cnt}"
fi
fi
done
fi
done
done
done