1#!/usr/bin/env bash
2
3##
4## Author......: See docs/credits.txt
5## License.....: MIT
6##
7
8OPTS="--quiet --potfile-disable --runtime 400 --hwmon-disable"
9
10TDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
11
12# List of TrueCrypt modes which have test containers
13TC_MODES="6211 6212 6213 6221 6222 6223 6231 6232 6233 6241 6242 6243"
14
15# List of VeraCrypt modes which have test containers
16VC_MODES="13711 13712 13713 13721 13722 13723 13731 13732 13733 13741 13742 13743 13751 13752 13753 13761 13762 13763 13771 13772 13773 13781 13782 13783"
17
18# List of modes which either are OPTS_TYPE_PT_NEVERCRACK or produce collisions
19NEVER_CRACK="9720 9820 14900 18100"
20
21# List of modes which return a different output hash format than the input hash format
22NOCHECK_ENCODING="16800 22000"
23
24# LUKS mode has test containers
25LUKS_MODE="14600"
26
27# Cryptoloop mode which have test containers
28CL_MODES="14511 14512 14513 14521 14522 14523 14531 14532 14533 14541 14542 14543 14551 14552 14553"
29
30# missing hash types: 5200
31
32HASH_TYPES=$(ls "${TDIR}"/test_modules/*.pm | sed -E 's/.*m0*([0-9]+).pm/\1/')
33HASH_TYPES="${HASH_TYPES} ${TC_MODES} ${VC_MODES} ${LUKS_MODE} ${CL_MODES}"
34HASH_TYPES=$(echo -n "${HASH_TYPES}" | tr ' ' '\n' | sort -u -n | tr '\n' ' ')
35
36VECTOR_WIDTHS="1 2 4 8 16"
37
38HASHFILE_ONLY=$(grep -l OPTS_TYPE_BINARY_HASHFILE "${TDIR}"/../src/modules/module_*.c | sed -E 's/.*module_0*([0-9]+).c/\1/' | tr '\n' ' ')
39SLOW_ALGOS=$(grep -l ATTACK_EXEC_OUTSIDE_KERNEL "${TDIR}"/../src/modules/module_*.c | sed -E 's/.*module_0*([0-9]+).c/\1/' | tr '\n' ' ')
40
41OUTD="test_$(date +%s)"
42
43PACKAGE_CMD="7z a"
44PACKAGE_FOLDER=""
45
46EXTRACT_CMD="7z x"
47
48mask_3[0]=""
49mask_3[1]="?d"
50mask_3[2]="?d?d"
51mask_3[3]="?d?d?d"
52mask_3[4]="?d?d?d?d"
53mask_3[5]="?d?d?d?d?d"
54mask_3[6]="?d?d?d?d?d?d"
55mask_3[7]="?d?d?d?d?d?d?d"
56mask_3[8]="?d?d?d?d?d?d?d?d"
57mask_3[9]="?d?d?d?d?d?d?d?d?d"
58mask_3[10]="?d?d?d?d?d?d?d?d?d?d"
59mask_3[11]="?d?d?d?d?d?d?d?d?d?d?d"
60mask_3[12]="?d?d?d?d?d?d?d?d?d?d?d?d"
61mask_3[13]="?d?d?d?d?d?d?d?d?d?d?d?d?d"
62mask_3[14]="?d?d?d?d?d?d?d?d?d?d?d?d?d?d"
63mask_3[15]="?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d"
64mask_3[16]="?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d0"
65mask_3[17]="?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d00"
66mask_3[18]="?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d000"
67mask_3[19]="?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d0000"
68mask_3[20]="?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d00000"
69mask_3[21]="?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d000000"
70mask_3[22]="?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d0000000"
71mask_3[23]="?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d00000000"
72mask_3[24]="?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d000000000"
73mask_3[25]="?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d0000000000"
74mask_3[26]="?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d00000000000"
75mask_3[27]="?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d000000000000"
76mask_3[28]="?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d0000000000000"
77mask_3[29]="?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d00000000000000"
78mask_3[30]="?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d000000000000000"
79mask_3[31]="?d?d?d?d?d?d?d?d?d?d?d?d?d?d?d0000000000000000"
80
81mask_6[0]=""
82mask_6[1]=""
83mask_6[2]="?d"
84mask_6[3]="?d?d"
85mask_6[4]="?d?d"
86mask_6[5]="?d?d?d"
87mask_6[6]="?d?d?d"
88mask_6[7]="?d?d?d?d"
89mask_6[8]="?d?d?d?d"
90mask_6[9]="?d?d?d?d?d"
91mask_6[10]="?d?d?d?d?d"
92mask_6[11]="?d?d?d?d?d?d"
93mask_6[12]="?d?d?d?d?d?d"
94mask_6[13]="?d?d?d?d?d?d?d"
95mask_6[14]="?d?d?d?d?d?d?d"
96mask_6[15]="?d?d?d?d?d?d?d?d"
97mask_6[16]="?d?d?d?d?d?d?d?d"
98mask_6[17]="?d?d?d?d?d?d?d?d0"
99mask_6[18]="?d?d?d?d?d?d?d?d0"
100mask_6[19]="?d?d?d?d?d?d?d?d00"
101mask_6[20]="?d?d?d?d?d?d?d?d00"
102mask_6[21]="?d?d?d?d?d?d?d?d000"
103mask_6[22]="?d?d?d?d?d?d?d?d000"
104mask_6[23]="?d?d?d?d?d?d?d?d0000"
105mask_6[24]="?d?d?d?d?d?d?d?d0000"
106mask_6[25]="?d?d?d?d?d?d?d?d00000"
107mask_6[26]="?d?d?d?d?d?d?d?d00000"
108mask_6[27]="?d?d?d?d?d?d?d?d000000"
109mask_6[28]="?d?d?d?d?d?d?d?d000000"
110mask_6[29]="?d?d?d?d?d?d?d?d0000000"
111mask_6[30]="?d?d?d?d?d?d?d?d0000000"
112mask_6[31]="?d?d?d?d?d?d?d?d00000000"
113
114mask_7[0]=""
115mask_7[1]=""
116mask_7[2]="?d"
117mask_7[3]="?d"
118mask_7[4]="?d?d"
119mask_7[5]="?d?d"
120mask_7[6]="?d?d?d"
121mask_7[7]="?d?d?d"
122mask_7[8]="?d?d?d?d"
123mask_7[9]="?d?d?d?d"
124mask_7[10]="?d?d?d?d?d"
125mask_7[11]="?d?d?d?d?d"
126mask_7[12]="?d?d?d?d?d?d"
127mask_7[13]="?d?d?d?d?d?d"
128mask_7[14]="?d?d?d?d?d?d?d"
129mask_7[15]="?d?d?d?d?d?d?d"
130mask_7[16]="?d?d?d?d?d?d?d?d"
131mask_7[17]="?d?d?d?d?d?d?d?d"
132mask_7[18]="?d?d?d?d?d?d?d?d0"
133mask_7[19]="?d?d?d?d?d?d?d?d0"
134mask_7[20]="?d?d?d?d?d?d?d?d00"
135mask_7[21]="?d?d?d?d?d?d?d?d00"
136mask_7[22]="?d?d?d?d?d?d?d?d000"
137mask_7[23]="?d?d?d?d?d?d?d?d000"
138mask_7[24]="?d?d?d?d?d?d?d?d0000"
139mask_7[25]="?d?d?d?d?d?d?d?d0000"
140mask_7[26]="?d?d?d?d?d?d?d?d00000"
141mask_7[27]="?d?d?d?d?d?d?d?d00000"
142mask_7[28]="?d?d?d?d?d?d?d?d000000"
143mask_7[29]="?d?d?d?d?d?d?d?d000000"
144mask_7[30]="?d?d?d?d?d?d?d?d0000000"
145mask_7[31]="?d?d?d?d?d?d?d?d0000000"
146
147# Array lookup
148# $1: value
149# $2: array
150# Returns 0 (SUCCESS) if the value is found, 1 otherwise
151function is_in_array()
152{
153  for e in "${@:2}"; do
154    [ "$e" = "$1" ] && return 0
155  done
156  return 1
157}
158
159function init()
160{
161  if [ "${PACKAGE}" -eq 1 ]; then
162    echo "[ ${OUTD} ] > Generate tests for hash type $hash_type."
163  else
164    echo "[ ${OUTD} ] > Init test for hash type $hash_type."
165  fi
166
167  rm -rf "${OUTD}/${hash_type}.sh" "${OUTD}/${hash_type}_passwords.txt" "${OUTD}/${hash_type}_hashes.txt"
168
169  # Exclude TrueCrypt, VeraCrypt and CryptoLoop testing modes
170  if is_in_array "${hash_type}" ${TC_MODES}; then
171    return 0
172  fi
173  if is_in_array "${hash_type}" ${VC_MODES}; then
174    return 0
175  fi
176  if is_in_array "${hash_type}" ${CL_MODES}; then
177    return 0
178  fi
179
180  if [ "${hash_type}" -eq ${LUKS_MODE} ]; then
181
182    luks_tests_folder="${TDIR}/luks_tests/"
183
184    if [ ! -d "${luks_tests_folder}" ]; then
185      mkdir -p "${luks_tests_folder}"
186    fi
187
188    luks_first_test_file="${luks_tests_folder}/hashcat_ripemd160_aes_cbc-essiv_128.luks"
189
190    if [ ! -f "${luks_first_test_file}" ]; then
191      luks_tests="hashcat_luks_testfiles.7z"
192      luks_tests_url="https://hashcat.net/misc/example_hashes/${luks_tests}"
193
194      cd "${TDIR}" || exit
195
196      # if the file already exists, but was not successfully extracted, we assume it's a broken
197      # downloaded file and therefore it should be deleted
198
199      if [ -f "${luks_tests}" ]; then
200        rm -f "${luks_tests}"
201      fi
202
203      echo ""
204      echo "ATTENTION: the luks test files (for -m ${hash_type}) are currently missing on your system."
205      echo "They will be fetched from ${luks_tests_url}"
206      echo "Note: this needs to be done only once and could take a little bit to download/extract."
207      echo "These luks test files are not shipped directly with hashcat because the file sizes are"
208      echo "particularily large and therefore a bandwidth burner for users who do not run these tests."
209      echo ""
210
211      # download:
212
213      if ! wget -q "${luks_tests_url}" >/dev/null 2>/dev/null; then
214        cd - >/dev/null
215        echo "ERROR: Could not fetch the luks test files from this url: ${luks_tests_url}"
216        exit 1
217      fi
218
219      # extract:
220
221      ${EXTRACT_CMD} "${luks_tests}" >/dev/null 2>/dev/null
222
223      # cleanup:
224
225      rm -f "${luks_tests}"
226      cd - >/dev/null || exit
227
228      # just to be very sure, check again that (one of) the files now exist:
229
230      if [ ! -f "${luks_first_test_file}" ]; then
231        echo "ERROR: downloading and extracting ${luks_tests} into ${luks_tests_folder} did not complete successfully"
232        exit 1
233      fi
234    fi
235
236    return 0
237  fi
238
239  # create list of password and hashes of same type
240  cmd_file=${OUTD}/${hash_type}.sh
241
242  grep " ${hash_type} '" "${OUTD}/all.sh" > "${cmd_file}" 2>/dev/null
243
244  # create separate list of password and hashes
245  sed 's/^echo *|.*$//'       "${cmd_file}" | awk '{print $2}'                  > "${OUTD}/${hash_type}_passwords.txt"
246  sed 's/^echo *|/echo "" |/' "${cmd_file}" | awk '{print $10}' | cut -d"'" -f2 > "${OUTD}/${hash_type}_hashes.txt"
247
248  if [ "${hash_type}" -eq 10300 ]; then
249    #cat ${OUTD}/${hash_type}.sh | cut -d' ' -f11- | cut -d"'" -f2 > ${OUTD}/${hash_type}_hashes.txt
250    cut -d"'" -f2 "${OUTD}/${hash_type}.sh" > "${OUTD}/${hash_type}_hashes.txt"
251  fi
252
253  # truncate dicts
254  rm -rf "${OUTD}/${hash_type}_dict1" "${OUTD}/${hash_type}_dict2"
255  touch "${OUTD}/${hash_type}_dict1" "${OUTD}/${hash_type}_dict2"
256
257  # minimum password length
258
259  min=1         # minimum line number from start of the file
260  min_offset=0  # minimum offset starting from ${min} lines
261
262  if   [ "${hash_type}" -eq  2500 ]; then
263    min_offset=7 # means length 8, since we start with 0
264  elif [ "${hash_type}" -eq 14000 ]; then
265    min=0
266    min_offset=4
267  elif [ "${hash_type}" -eq 14100 ]; then
268    min=0
269    min_offset=3
270  elif [ "${hash_type}" -eq 14900 ]; then
271    min=0
272    min_offset=5
273  elif [ "${hash_type}" -eq 15400 ]; then
274    min=0
275    min_offset=3
276  elif [ "${hash_type}" -eq 16800 ]; then
277    min_offset=7 # means length 8, since we start with 0
278  elif [ "${hash_type}" -eq 22000 ]; then
279    min_offset=7 # means length 8, since we start with 0
280  fi
281
282  # foreach password entry split password in 2 (skip first entry, is len 1)
283
284  i=1
285
286  while read -r -u 9 pass; do
287
288    if [ ${i} -gt ${min} ]; then
289
290      # split password, 'i' is the len
291      p0=$((i / 2))
292      p1=$((p0 + 1))
293
294      # special case (passwords longer than expected)
295      pass_len=${#pass}
296
297      if [ "${pass_len}" -gt 1 ]
298      then
299
300        p1=$((p1 + min_offset))
301        p0=$((p0 + min_offset))
302
303        if [ "${p1}" -gt "${pass_len}" ]; then
304
305          p1=${pass_len}
306          p0=$((p1 - 1))
307
308        fi
309
310        # add splitted password to dicts
311        echo "${pass}" | cut -c -${p0} >> "${OUTD}/${hash_type}_dict1"
312        echo "${pass}" | cut -c ${p1}- >> "${OUTD}/${hash_type}_dict2"
313      elif [ "${pass_len}" -eq 1 ]; then
314        echo "${pass}" >> "${OUTD}/${hash_type}_dict1"
315        echo >> "${OUTD}/${hash_type}_dict2"
316      else
317        echo >> "${OUTD}/${hash_type}_dict1"
318        echo >> "${OUTD}/${hash_type}_dict2"
319      fi
320
321    fi
322
323    i=$((i + 1))
324
325  done 9< "${OUTD}/${hash_type}_passwords.txt"
326
327  min_len=0
328
329  if   [ "${hash_type}" -eq  2500 ]; then
330    min_len=7 # means length 8, since we start with 0
331  elif [ "${hash_type}" -eq 14000 ]; then
332    min_len=7
333  elif [ "${hash_type}" -eq 14100 ]; then
334    min_len=23
335  elif [ "${hash_type}" -eq 14900 ]; then
336    min_len=9
337  elif [ "${hash_type}" -eq 15400 ]; then
338    min_len=31
339  elif [ "${hash_type}" -eq 16800 ]; then
340    min_len=7 # means length 8, since we start with 0
341  elif [ "${hash_type}" -eq 22000 ]; then
342    min_len=7 # means length 8, since we start with 0
343  fi
344
345  # generate multiple pass/hash foreach len (2 to 8)
346  if [ "${MODE}" -ge 1 ]; then
347
348    i=2
349    while [ "$i" -lt 9 ]; do
350
351      cmd_file=${OUTD}/${hash_type}_multi_${i}.txt
352
353      rm -rf "${cmd_file}" "${OUTD}/${hash_type}_passwords_multi_${i}.txt" "${OUTD}/${hash_type}_hashes_multi_${i}.txt"
354      rm -rf "${OUTD}/${hash_type}_dict1_multi_${i}" "${OUTD}/${hash_type}_dict2_multi_${i}"
355      touch "${OUTD}/${hash_type}_dict1_multi_${i}" "${OUTD}/${hash_type}_dict2_multi_${i}"
356
357      perl tools/test.pl single "${hash_type}" ${i} > "${cmd_file}"
358
359      sed 's/^echo *|.*$//'       "${cmd_file}" | awk '{print $2}'                  > "${OUTD}/${hash_type}_passwords_multi_${i}.txt"
360      sed 's/^echo *|/echo "" |/' "${cmd_file}" | awk '{print $10}' | cut -d"'" -f2 > "${OUTD}/${hash_type}_hashes_multi_${i}.txt"
361
362      if [ "${hash_type}" -eq 10300 ]; then
363        #cat ${OUTD}/${hash_type}_multi_${i}.txt | cut -d' ' -f11- | cut -d"'" -f2 > ${OUTD}/${hash_type}_hashes_multi_${i}.txt
364        cut -d"'" -f2 "${OUTD}/${hash_type}_multi_${i}.txt" > "${OUTD}/${hash_type}_hashes_multi_${i}.txt"
365      fi
366
367      # split password, 'i' is the len
368      p0=$((i / 2))
369      p1=$((p0 + 1))
370
371      p0=$((p0 + min_len))
372      p1=$((p1 + min_len))
373
374      while read -r -u 9 pass; do
375
376        # add splitted password to dicts
377        echo "${pass}" | cut -c -${p0} >> "${OUTD}/${hash_type}_dict1_multi_${i}"
378        echo "${pass}" | cut -c ${p1}- >> "${OUTD}/${hash_type}_dict2_multi_${i}"
379
380      done 9< "${OUTD}/${hash_type}_passwords_multi_${i}.txt"
381      i=$((i + 1))
382
383    done
384
385  fi
386}
387
388function status()
389{
390  RET=$1
391
392  cnt=$((cnt + 1))
393
394  if [ "${RET}" -ne 0 ]; then
395    case ${RET} in
396      1)
397        if ! is_in_array "${hash_type}" ${NEVER_CRACK_ALGOS}; then
398
399           echo "password not found, cmdline : ${CMD}" >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
400           e_nf=$((e_nf + 1))
401
402        fi
403
404        ;;
405      4)
406        echo "timeout reached, cmdline : ${CMD}" >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
407        e_to=$((e_to + 1))
408
409        ;;
410      10)
411        if is_in_array "${hash_type}" ${NEVER_CRACK_ALGOS}; then
412          return
413        fi
414
415        if [ "${pass_only}" -eq 1 ]; then
416          echo "plains not found in output, cmdline : ${CMD}" >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
417        else
418          echo "hash:plains not matched in output, cmdline : ${CMD}" >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.tx"t
419        fi
420        e_nm=$((e_nm + 1))
421
422        ;;
423      *)
424        echo "! unhandled return code ${RET}, cmdline : ${CMD}" >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
425        echo "! unhandled return code, see ${OUTD}/logfull.txt for details."
426        e_nf=$((e_nf + 1))
427        ;;
428    esac
429  fi
430}
431
432function attack_0()
433{
434  file_only=0
435
436  if is_in_array "${hash_type}" ${FILE_BASED_ALGOS}; then
437
438    file_only=1
439
440  fi
441
442  # single hash
443  if [ "${MODE}" -ne 1 ]; then
444
445    e_to=0
446    e_nf=0
447    e_nm=0
448    cnt=0
449
450    echo "> Testing hash type $hash_type with attack mode 0, markov ${MARKOV}, single hash, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR}." >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
451
452    max=32
453
454    if is_in_array "${hash_type}" ${TIMEOUT_ALGOS}; then
455
456      max=12
457
458    fi
459
460    i=0
461
462    while read -r -u 9 line; do
463
464      if [ "${i}" -ge ${max} ]; then
465
466        break
467
468      fi
469
470      hash="$(echo "${line}" | cut -d\'  -f2)"
471      pass="$(echo "${line}" | cut -d' ' -f2)"
472
473      if [ -z "${hash}" ]; then
474
475        break
476
477      fi
478
479      if [ "${file_only}" -eq 1 ]; then
480
481        temp_file="${OUTD}/${hash_type}_filebased_only_temp.txt"
482
483        if [ "${hash_type}" -ne 22000 ]; then
484          echo "${hash}" | base64 -d > "${temp_file}"
485        else
486          echo "${hash}" > "${temp_file}"
487        fi
488
489        hash="${temp_file}"
490
491      fi
492
493      pass_old=${pass}
494
495      if [ "${hash_type}" -eq 20510 ]; then # special case for PKZIP Master Key
496        pass=$(echo "${pass}" | cut -b 7-) # skip the first 6 chars
497      fi
498
499      CMD="echo ${pass} | ./${BIN} ${OPTS} -a 0 -m ${hash_type} '${hash}'"
500
501      echo -n "[ len $((i + 1)) ] " >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
502
503      output=$(echo "${pass}" | ./${BIN} ${OPTS} -a 0 -m ${hash_type} "${hash}" 2>&1)
504
505      ret=${?}
506
507      pass=${pass_old}
508
509      echo "${output}" >> "${OUTD}/logfull.txt"
510
511      if [ "${ret}" -eq 0 ]; then
512
513        if [ "${pass_only}" -eq 1 ]; then
514          search=":${pass}"
515        else
516          search="${hash}:${pass}"
517        fi
518
519        echo "${output}" | grep -F "${search}" >/dev/null 2>/dev/null
520
521        if [ "${?}" -ne 0 ]; then
522
523            ret=10
524
525        fi
526
527      fi
528
529      status ${ret}
530
531      i=$((i + 1))
532
533    done 9< "${OUTD}/${hash_type}.sh"
534
535    msg="OK"
536
537    if [ "${e_nf}" -ne 0 ] || [ "${e_nm}" -ne 0 ]; then
538
539      msg="Error"
540
541    elif [ "${e_to}" -ne 0 ]; then
542
543      msg="Warning"
544
545    fi
546
547    echo "[ ${OUTD} ] [ Type ${hash_type}, Attack 0, Mode single, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR} ] > $msg : ${e_nf}/${cnt} not found, ${e_nm}/${cnt} not matched, ${e_to}/${cnt} timeout"
548
549  fi
550
551  # multihash
552  if [ "${MODE}" -ne 0 ]; then
553
554    e_to=0
555    e_nf=0
556    e_nm=0
557    cnt=0
558
559    echo "> Testing hash type $hash_type with attack mode 0, markov ${MARKOV}, multi hash, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR}." >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
560
561    hash_file=${OUTD}/${hash_type}_hashes.txt
562
563    # if file_only -> decode all base64 "hashes" and put them in the temporary file
564
565    if [ "${file_only}" -eq 1 ]; then
566
567      temp_file="${OUTD}/${hash_type}_filebased_only_temp.txt"
568      rm -f "${temp_file}"
569
570      hash_file=${temp_file}
571
572      while read -r file_only_hash; do
573
574        if [ "${hash_type}" -ne 22000 ]; then
575          echo -n "${file_only_hash}" | base64 -d >> "${temp_file}"
576        else
577          echo "${file_only_hash}" >> "${temp_file}"
578        fi
579
580      done < "${OUTD}/${hash_type}_hashes.txt"
581
582    fi
583
584    CMD="cat ${OUTD}/${hash_type}_passwords.txt | ./${BIN} ${OPTS} -a 0 -m ${hash_type} ${hash_file}"
585
586    output=$(./${BIN} ${OPTS} -a 0 -m ${hash_type} ${hash_file} < ${OUTD}/${hash_type}_passwords.txt 2>&1)
587
588    ret=${?}
589
590    echo "${output}" >> "${OUTD}/logfull.txt"
591
592    if [ "${ret}" -eq 0 ]; then
593
594      i=1
595
596      while read -r -u 9 hash; do
597
598        pass=$(sed -n ${i}p "${OUTD}/${hash_type}_passwords.txt")
599
600        if [ "${pass_only}" -eq 1 ]; then
601          search=":${pass}"
602        else
603          search="${hash}:${pass}"
604        fi
605
606        echo "${output}" | grep -F "${search}" >/dev/null 2>/dev/null
607
608        if [ "${?}" -ne 0 ]; then
609
610          ret=10
611
612          break
613
614        fi
615
616        i=$((i + 1))
617
618      done 9< "${OUTD}/${hash_type}_hashes.txt"
619
620    fi
621
622    status ${ret}
623
624    msg="OK"
625
626    if [ "${e_nf}" -ne 0 ] || [ "${e_nm}" -ne 0 ]; then
627
628      msg="Error"
629
630    elif [ "${e_to}" -ne 0 ]; then
631
632      msg="Warning"
633
634    fi
635
636    echo "[ ${OUTD} ] [ Type ${hash_type}, Attack 0, Mode multi,  Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR} ] > $msg : ${e_nf}/${cnt} not found, ${e_nm}/${cnt} not matched, ${e_to}/${cnt} timeout"
637
638  fi
639}
640
641function attack_1()
642{
643  file_only=0
644
645  if is_in_array "${hash_type}" ${FILE_BASED_ALGOS}; then
646
647    file_only=1
648
649  fi
650
651  # single hash
652  if [ "${MODE}" -ne 1 ]; then
653
654    e_to=0
655    e_nf=0
656    e_nm=0
657    cnt=0
658
659    min=1
660    max=8
661
662    if   [ "${hash_type}" -eq 14000 ]; then
663      min=0
664      max=5
665    elif [ "${hash_type}" -eq 14100 ]; then
666      min=0
667      max=5
668    elif [ "${hash_type}" -eq 14900 ]; then
669      min=0
670      max=5
671    elif [ "${hash_type}" -eq 15400 ]; then
672      min=0
673      max=5
674    fi
675
676    echo "> Testing hash type $hash_type with attack mode 1, markov ${MARKOV}, single hash, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR}." >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
677    i=1
678    while read -r -u 9 hash; do
679
680      if [ $i -gt ${min} ]; then
681
682        if [ "${file_only}" -eq 1 ]; then
683
684          temp_file="${OUTD}/${hash_type}_filebased_only_temp.txt"
685
686          if [ "${hash_type}" -ne 22000 ]; then
687            echo "${hash}" | base64 -d > "${temp_file}"
688          else
689            echo "${hash}" > "${temp_file}"
690          fi
691
692          hash="${temp_file}"
693
694        fi
695
696        line_nr=1
697
698        if [ "$min" -eq 0 ]; then
699          line_nr=$i
700        elif [ "${i}" -gt 1 ]; then
701          line_nr=$((i - 1))
702        fi
703
704        dict1="${OUTD}/${hash_type}_dict1"
705        dict2="${OUTD}/${hash_type}_dict2"
706
707        if [ "${hash_type}" -eq 20510 ]; then # special case for PKZIP Master Key
708          line_dict1=$(sed -n ${line_nr}p "${dict1}")
709          line_dict2=$(sed -n ${line_nr}p "${dict2}")
710          line_num=$(wc -l "${dict1}" | sed -E 's/ *([0-9]+) .*$/\1/')
711
712          line_dict1_orig=${line_dict1}
713          line_dict2_orig=${line_dict2}
714
715          if [ "${#line_dict1}" -ge 6 ]; then
716            line_dict1=$(echo "${line_dict1}" | cut -b 7-) # skip the first 6 chars
717          else
718            # we need to also "steal" some chars from the second dict
719            num_to_steal=$((6 - ${#line_dict1}))
720            num_steal_start=$((num_to_steal + 1))
721
722            if [ "${#line_dict2}" -ge 6 ]; then
723              num_to_steal_new=$(((${#line_dict2} - num_to_steal) / 2))
724
725              if [ "${num_to_steal_new}" -gt ${num_to_steal} ]; then
726                num_to_steal=${num_to_steal_new}
727              fi
728            fi
729
730            line_chars_stolen=$(echo "${line_dict2}" | cut -b -${num_to_steal} | cut -b ${num_steal_start}-)
731
732            line_dict1="${line_chars_stolen}"
733            line_dict2=$(echo "${line_dict2}" | cut -b $((num_to_steal + 1))-)
734          fi
735
736          # finally, modify the dicts accordingly:
737
738          tmp_file="${dict1}_mod"
739
740          head -n $((line_nr - 1)) "${dict1}" > "${tmp_file}"
741          echo "${line_dict1}" >> "${tmp_file}"
742          tail -n $((line_num - line_nr - 1)) "${dict1}" >> "${tmp_file}"
743
744          dict1=${tmp_file}
745
746          tmp_file="${dict2}_mod"
747
748          head -n $((line_nr - 1)) "${dict2}" > "${tmp_file}"
749          echo "${line_dict2}" >> "${tmp_file}"
750          tail -n $((line_num - line_nr - 1)) "${dict2}" >> "${tmp_file}"
751
752          dict2=${tmp_file}
753        fi
754
755        CMD="./${BIN} ${OPTS} -a 1 -m ${hash_type} '${hash}' ${dict1} ${dict2}"
756
757        echo -n "[ len $i ] " >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
758
759        output=$(./${BIN} ${OPTS} -a 1 -m ${hash_type} "${hash}" ${dict1} ${dict2} 2>&1)
760
761        ret=${?}
762
763        echo "${output}" >> "${OUTD}/logfull.txt"
764
765        if [ "${ret}" -eq 0 ]; then
766
767          line_dict1=$(sed -n ${line_nr}p "${OUTD}/${hash_type}_dict1")
768          line_dict2=$(sed -n ${line_nr}p "${OUTD}/${hash_type}_dict2")
769
770          if [ "${pass_only}" -eq 1 ]; then
771            search=":${line_dict1}${line_dict2}"
772          else
773            search="${hash}:${line_dict1}${line_dict2}"
774          fi
775
776          echo "${output}" | grep -F "${search}" >/dev/null 2>/dev/null
777
778          if [ "${?}" -ne 0 ]; then
779
780            ret=10
781
782          fi
783
784        fi
785
786        status ${ret}
787
788      fi
789
790      if [ $i -eq ${max} ]; then break; fi
791
792      i=$((i + 1))
793
794    done 9< "${OUTD}/${hash_type}_hashes.txt"
795
796    msg="OK"
797
798    if [ "${e_nf}" -ne 0 ] || [ "${e_nm}" -ne 0 ]; then
799
800      msg="Error"
801
802    elif [ "${e_to}" -ne 0 ]; then
803
804      msg="Warning"
805
806    fi
807
808    echo "[ ${OUTD} ] [ Type ${hash_type}, Attack 1, Mode single, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR} ] > $msg : ${e_nf}/${cnt} not found, ${e_nm}/${cnt} not matched, ${e_to}/${cnt} timeout"
809
810  fi
811
812  # multihash
813  if [ "${MODE}" -ne 0 ]; then
814
815    # no multi hash checks for these modes (because we only have 1 hash for each of them)
816
817    if   [ "${hash_type}" -eq 14000 ]; then
818      return
819    elif [ "${hash_type}" -eq 14100 ]; then
820      return
821    elif [ "${hash_type}" -eq 14900 ]; then
822      return
823    elif [ "${hash_type}" -eq 15400 ]; then
824      return
825    fi
826
827    e_to=0
828    e_nf=0
829    e_nm=0
830    cnt=0
831
832    offset=7
833
834    if [ "${hash_type}" -eq  5800 ]; then
835      offset=6
836    elif [ "${hash_type}" -eq  3000 ]; then
837      offset=6
838    fi
839
840    hash_file=${OUTD}/${hash_type}_multihash_combi.txt
841
842    tail -n ${offset} "${OUTD}/${hash_type}_hashes.txt" > "${hash_file}"
843
844    # if file_only -> decode all base64 "hashes" and put them in the temporary file
845
846    if [ "${file_only}" -eq 1 ]; then
847
848      temp_file="${OUTD}/${hash_type}_filebased_only_temp.txt"
849      rm -f "${temp_file}"
850
851      hash_file=${temp_file}
852
853      while read -r file_only_hash; do
854
855        if [ "${hash_type}" -ne 22000 ]; then
856          echo -n "${file_only_hash}" | base64 -d >> "${temp_file}"
857        else
858          echo "${file_only_hash}" >> "${temp_file}"
859        fi
860
861      done < "${OUTD}/${hash_type}_multihash_combi.txt"
862
863    fi
864
865    CMD="./${BIN} ${OPTS} -a 1 -m ${hash_type} ${hash_file} ${OUTD}/${hash_type}_dict1 ${OUTD}/${hash_type}_dict2"
866
867    echo "> Testing hash type $hash_type with attack mode 1, markov ${MARKOV}, multi hash, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR}." >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
868
869    output=$(./${BIN} ${OPTS} -a 1 -m ${hash_type} ${hash_file} ${OUTD}/${hash_type}_dict1 ${OUTD}/${hash_type}_dict2 2>&1)
870
871    ret=${?}
872
873    echo "${output}" >> "${OUTD}/logfull.txt"
874
875    if [ "${ret}" -eq 0 ]; then
876
877      i=0
878
879      while read -r -u 9 hash; do
880
881        line_nr=1
882
883        if [ "${offset}" -gt ${i} ]; then
884          line_nr=$((offset - i))
885        fi
886
887        line_dict1=$(tail -n ${line_nr} "${OUTD}/${hash_type}_dict1" | head -1)
888        line_dict2=$(tail -n ${line_nr} "${OUTD}/${hash_type}_dict2" | head -1)
889
890        if [ "${pass_only}" -eq 1 ]; then
891          search=":${line_dict1}${line_dict2}"
892        else
893          search="${hash}:${line_dict1}${line_dict2}"
894        fi
895
896        echo "${output}" | grep -F "${search}" >/dev/null 2>/dev/null
897
898        if [ "${?}" -ne 0 ]; then
899
900          ret=10
901
902          break
903
904        fi
905
906        i=$((i + 1))
907
908      done 9< "${OUTD}/${hash_type}_multihash_combi.txt"
909
910    fi
911
912    status ${ret}
913
914    msg="OK"
915
916    if [ "${e_nf}" -ne 0 ] || [ "${e_nm}" -ne 0 ]; then
917
918      msg="Error"
919
920    elif [ "${e_to}" -ne 0 ]; then
921
922      msg="Warning"
923
924    fi
925
926    echo "[ ${OUTD} ] [ Type ${hash_type}, Attack 1, Mode multi,  Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR} ] > $msg : ${e_nf}/${cnt} not found, ${e_nm}/${cnt} not matched, ${e_to}/${cnt} timeout"
927
928  fi
929}
930
931function attack_3()
932{
933  file_only=0
934
935  if is_in_array "${hash_type}" ${FILE_BASED_ALGOS}; then
936
937    file_only=1
938
939  fi
940
941  # single hash
942  if [ "${MODE}" -ne 1 ]; then
943
944    e_to=0
945    e_nf=0
946    e_nm=0
947    cnt=0
948
949    echo "> Testing hash type $hash_type with attack mode 3, markov ${MARKOV}, single hash, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR}." >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
950
951    max=8
952
953    # some algos have a minimum password length
954
955    if   [ "${hash_type}" -eq  2500 ]; then
956      max=7
957    elif [ "${hash_type}" -eq 14000 ]; then
958      max=1
959    elif [ "${hash_type}" -eq 14100 ]; then
960      max=1
961    elif [ "${hash_type}" -eq 14900 ]; then
962      max=1
963    elif [ "${hash_type}" -eq 15400 ]; then
964      max=1
965    elif [ "${hash_type}" -eq 16800 ]; then
966      max=7
967    elif [ "${hash_type}" -eq 22000 ]; then
968      max=7
969    fi
970
971    i=1
972
973    while read -r -u 9 hash; do
974
975      if [ "${i}" -gt 6 ]; then
976
977        if is_in_array "${hash_type}" ${TIMEOUT_ALGOS}; then
978
979          break
980
981        fi
982
983      fi
984
985      if [ "${file_only}" -eq 1 ]; then
986
987        temp_file="${OUTD}/${hash_type}_filebased_only_temp.txt"
988
989        if [ "${hash_type}" -ne 22000 ]; then
990          echo "${hash}" | base64 -d > "${temp_file}"
991        else
992          echo "${hash}" > "${temp_file}"
993        fi
994
995        hash="${temp_file}"
996
997      fi
998
999
1000      # construct a meaningful mask from the password itself:
1001
1002      dict="${OUTD}/${hash_type}_passwords.txt"
1003
1004      pass=$(sed -n ${i}p "${dict}")
1005
1006      # passwords can't be smaller than mask in -a 3 = mask attack
1007
1008      if [ "${#pass}" -lt ${i} ]; then
1009        i=$((i + 1))
1010        continue
1011      fi
1012
1013      pass_part_2=$(echo -n "${pass}" | cut -b  $((i + 1))-)
1014
1015      mask=""
1016
1017      if   [ "${hash_type}" -eq 14000 ]; then
1018
1019        mask="${pass}"
1020
1021      elif [ "${hash_type}" -eq 14100 ]; then
1022
1023        mask="${pass}"
1024
1025      else
1026
1027        for i in $(seq 1 ${i}); do
1028          mask="${mask}?d"
1029        done
1030
1031        mask="${mask}${pass_part_2}"
1032
1033      fi
1034
1035      if [ "${hash_type}" -eq 20510 ]; then # special case for PKZIP Master Key
1036        if [ "${i}" -le 1 ]; then
1037          i=$((i + 1))
1038          continue
1039        fi
1040
1041        cut_pos=$((i * 2 + 6 - i + 1)) # skip it in groups of 2 ("?d"), at least 6, offset +1 for cut to work
1042
1043        if [ "${i}" -gt 6 ]; then
1044          cut_pos=13 # 6 * ?d + 1 (6 * 2 + 1)
1045        fi
1046
1047        mask=$(echo "${mask}" | cut -b ${cut_pos}-)
1048      fi
1049
1050      CMD="./${BIN} ${OPTS} -a 3 -m ${hash_type} '${hash}' ${mask}"
1051
1052      echo -n "[ len $i ] " >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
1053
1054      output=$(./${BIN} ${OPTS} -a 3 -m ${hash_type} "${hash}" ${mask} 2>&1)
1055
1056      ret=${?}
1057
1058      echo "${output}" >> "${OUTD}/logfull.txt"
1059
1060      if [ "${ret}" -eq 0 ]; then
1061
1062        line_dict=$(sed -n ${i}p "${dict}")
1063
1064        if [ "${pass_only}" -eq 1 ]; then
1065          search=":${line_dict}"
1066        else
1067          search="${hash}:${line_dict}"
1068        fi
1069
1070        echo "${output}" | grep -F "${search}" >/dev/null 2>/dev/null
1071
1072        if [ "${?}" -ne 0 ]; then
1073
1074          ret=10
1075
1076        fi
1077
1078      fi
1079
1080      status ${ret}
1081
1082      if [ $i -eq ${max} ]; then break; fi
1083
1084      i=$((i + 1))
1085
1086    done 9< "${OUTD}/${hash_type}_hashes.txt"
1087
1088    msg="OK"
1089
1090    if [ "${e_nf}" -ne 0 ] || [ "${e_nm}" -ne 0 ]; then
1091
1092      msg="Error"
1093
1094    elif [ "${e_to}" -ne 0 ]; then
1095
1096      msg="Warning"
1097
1098    fi
1099
1100    echo "[ ${OUTD} ] [ Type ${hash_type}, Attack 3, Mode single, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR} ] > $msg : ${e_nf}/${cnt} not found, ${e_nm}/${cnt} not matched, ${e_to}/${cnt} timeout"
1101
1102  fi
1103
1104  # multihash
1105  if [ "${MODE}" -ne 0 ]; then
1106
1107    # no multi hash checks for these modes (because we only have 1 hash for each of them)
1108
1109    if   [ "${hash_type}" -eq 14000 ]; then
1110      return
1111    elif [ "${hash_type}" -eq 14100 ]; then
1112      return
1113    elif [ "${hash_type}" -eq 14900 ]; then
1114      return
1115    elif [ "${hash_type}" -eq 15400 ]; then
1116      return
1117    fi
1118
1119    e_to=0
1120    e_nf=0
1121    e_nm=0
1122    cnt=0
1123
1124    increment_max=8
1125
1126    if is_in_array "${hash_type}" ${TIMEOUT_ALGOS}; then
1127
1128      increment_max=5
1129
1130    fi
1131
1132    increment_min=1
1133
1134    if   [ "${hash_type}" -eq  2500 ]; then
1135      increment_min=8
1136      increment_max=9
1137    fi
1138
1139    if   [ "${hash_type}" -eq 16800 ]; then
1140      increment_min=8
1141      increment_max=9
1142    fi
1143
1144    if   [ "${hash_type}" -eq 22000 ]; then
1145      increment_min=8
1146      increment_max=9
1147    fi
1148
1149    # if file_only -> decode all base64 "hashes" and put them in the temporary file
1150
1151    if [ "${file_only}" -eq 1 ]; then
1152
1153      temp_file="${OUTD}/${hash_type}_filebased_only_temp.txt"
1154      rm -f "${temp_file}"
1155
1156      hash_file=${temp_file}
1157
1158      while read -r file_only_hash; do
1159
1160        if [ "${hash_type}" -ne 22000 ]; then
1161          echo -n "${file_only_hash}" | base64 -d >> "${temp_file}"
1162        else
1163          echo "${file_only_hash}" >> "${temp_file}"
1164        fi
1165
1166      done < "${OUTD}/${hash_type}_multihash_bruteforce.txt"
1167
1168    fi
1169
1170    hash_file=${OUTD}/${hash_type}_multihash_bruteforce.txt
1171
1172    tail_hashes=$(awk "length >= ${increment_min} && length <= ${increment_max}" "${OUTD}/${hash_type}_passwords.txt" | wc -l)
1173    head_hashes=$(awk                               "length <= ${increment_max}" "${OUTD}/${hash_type}_passwords.txt" | wc -l)
1174
1175    # in very rare cases (e.g. without -O and long passwords) we need to use .hcmask files with the passwords in it
1176    # otherwise there are no good masks we can test for such long passwords
1177
1178    need_hcmask=0
1179
1180    if [ "${tail_hashes}" -gt "${head_hashes}" ]; then
1181      need_hcmask=1
1182    fi
1183
1184    if [ "${tail_hashes}" -lt 1 ]; then
1185      need_hcmask=1
1186    fi
1187
1188    if [ ${need_hcmask} -eq 0 ]; then
1189      head -n "${head_hashes}" "${OUTD}/${hash_type}_hashes.txt" | tail -n "${tail_hashes}" > "${hash_file}"
1190    else
1191      tail_hashes=$(awk "length >= ${increment_min}" "${OUTD}/${hash_type}_passwords.txt" | wc -l)
1192
1193      if [ "${tail_hashes}" -lt 1 ]; then
1194        return
1195      fi
1196
1197      tail -n "${tail_hashes}" "${OUTD}/${hash_type}_hashes.txt"  > "${hash_file}"
1198    fi
1199
1200    mask_pos=8
1201
1202    if [ "${increment_min}" -gt ${mask_pos} ]; then
1203      mask_pos=${increment_min}
1204    fi
1205
1206    mask=""
1207    cracks_offset=0
1208
1209    if [ ${need_hcmask} -eq 0 ]; then
1210      cracks_offset=$((head_hashes - tail_hashes))
1211
1212      mask=${mask_3[${mask_pos}]}
1213    else
1214      num_hashes=$(wc -l < "${OUTD}/${hash_type}_hashes.txt")
1215      cracks_offset=$((num_hashes - tail_hashes))
1216
1217      mask=${OUTD}/${hash_type}_passwords.txt # fake hcmask file (i.e. the original dict)
1218    fi
1219
1220    custom_charsets=""
1221
1222    # modify "default" mask if needed (and set custom charset to reduce keyspace)
1223
1224    if [ "${hash_type}" -eq 2500 ]; then
1225
1226      mask="?d?d?d?d?d?1?2?3?4"
1227
1228      charset_1=""
1229      charset_2=""
1230      charset_3=""
1231      charset_4=""
1232
1233      # check positions (here we assume that mask is always composed of non literal chars
1234      # i.e. something like ?d?l?u?s?1 is possible, but ?d?dsuffix not
1235      charset_1_pos=$(expr index "${mask}" 1)
1236      charset_2_pos=$(expr index "${mask}" 2)
1237      charset_3_pos=$(expr index "${mask}" 3)
1238      charset_4_pos=$(expr index "${mask}" 4)
1239
1240      # divide each charset position by 2 since each of them occupies 2 positions in the mask
1241
1242      charset_1_pos=$((charset_1_pos / 2))
1243      charset_2_pos=$((charset_2_pos / 2))
1244      charset_3_pos=$((charset_3_pos / 2))
1245      charset_4_pos=$((charset_4_pos / 2))
1246
1247      i=1
1248
1249      while read -r -u 9 hash; do
1250
1251        pass=$(sed -n ${i}p "${OUTD}/${hash_type}_passwords.txt")
1252
1253        # charset 1
1254        char=$(echo "${pass}" | cut -b ${charset_1_pos})
1255        charset_1=$(printf "%s\n%s\n" "${charset_1}" "${char}")
1256
1257        # charset 2
1258        char=$(echo "${pass}" | cut -b ${charset_2_pos})
1259        charset_2=$(printf "%s\n%s\n" "${charset_2}" "${char}")
1260
1261        # charset 3
1262        char=$(echo "${pass}" | cut -b ${charset_3_pos})
1263        charset_3=$(printf "%s\n%s\n" "${charset_3}" "${char}")
1264
1265        # charset 4
1266        char=$(echo "${pass}" | cut -b ${charset_4_pos})
1267        charset_4=$(printf "%s\n%s\n" "${charset_4}" "${char}")
1268
1269        i=$((i + 1))
1270
1271      done 9< "${OUTD}/${hash_type}_multihash_bruteforce.txt"
1272
1273      # just make sure that all custom charset fields are initialized
1274
1275      if [ -z "${charset_1}" ]; then
1276
1277        charset_1="1"
1278
1279      fi
1280
1281      if [ -z "${charset_2}" ]; then
1282
1283        charset_2="2"
1284
1285      fi
1286
1287      if [ -z "${charset_3}" ]; then
1288
1289        charset_3="3"
1290
1291      fi
1292
1293      if [ -z "${charset_4}" ]; then
1294
1295        charset_4="4"
1296
1297      fi
1298
1299      # unique and remove new lines
1300
1301      charset_1=$(echo "${charset_1}" | sort -u | tr -d '\n')
1302      charset_2=$(echo "${charset_2}" | sort -u | tr -d '\n')
1303      charset_3=$(echo "${charset_3}" | sort -u | tr -d '\n')
1304      charset_4=$(echo "${charset_4}" | sort -u | tr -d '\n')
1305
1306      custom_charsets="-1 ${charset_1} -2 ${charset_2} -3 ${charset_3} -4 ${charset_4}"
1307    fi
1308
1309    if [ "${hash_type}" -eq 16800 ]; then
1310
1311      mask="?d?d?d?d?d?1?2?3?4"
1312
1313      charset_1=""
1314      charset_2=""
1315      charset_3=""
1316      charset_4=""
1317
1318      # check positions (here we assume that mask is always composed of non literal chars
1319      # i.e. something like ?d?l?u?s?1 is possible, but ?d?dsuffix not
1320      charset_1_pos=$(expr index "${mask}" 1)
1321      charset_2_pos=$(expr index "${mask}" 2)
1322      charset_3_pos=$(expr index "${mask}" 3)
1323      charset_4_pos=$(expr index "${mask}" 4)
1324
1325      # divide each charset position by 2 since each of them occupies 2 positions in the mask
1326
1327      charset_1_pos=$((charset_1_pos / 2))
1328      charset_2_pos=$((charset_2_pos / 2))
1329      charset_3_pos=$((charset_3_pos / 2))
1330      charset_4_pos=$((charset_4_pos / 2))
1331
1332      i=1
1333
1334      while read -r -u 9 hash; do
1335
1336        pass=$(sed -n ${i}p "${OUTD}/${hash_type}_passwords.txt")
1337
1338        # charset 1
1339        char=$(echo "${pass}" | cut -b ${charset_1_pos})
1340        charset_1=$(printf "%s\n%s\n" "${charset_1}" "${char}")
1341
1342        # charset 2
1343        char=$(echo "${pass}" | cut -b ${charset_2_pos})
1344        charset_2=$(printf "%s\n%s\n" "${charset_2}" "${char}")
1345
1346        # charset 3
1347        char=$(echo "${pass}" | cut -b ${charset_3_pos})
1348        charset_3=$(printf "%s\n%s\n" "${charset_3}" "${char}")
1349
1350        # charset 4
1351        char=$(echo "${pass}" | cut -b ${charset_4_pos})
1352        charset_4=$(printf "%s\n%s\n" "${charset_4}" "${char}")
1353
1354        i=$((i + 1))
1355
1356      done 9< "${OUTD}/${hash_type}_multihash_bruteforce.txt"
1357
1358      # just make sure that all custom charset fields are initialized
1359
1360      if [ -z "${charset_1}" ]; then
1361
1362        charset_1="1"
1363
1364      fi
1365
1366      if [ -z "${charset_2}" ]; then
1367
1368        charset_2="2"
1369
1370      fi
1371
1372      if [ -z "${charset_3}" ]; then
1373
1374        charset_3="3"
1375
1376      fi
1377
1378      if [ -z "${charset_4}" ]; then
1379
1380        charset_4="4"
1381
1382      fi
1383
1384      # unique and remove new lines
1385
1386      charset_1=$(echo "${charset_1}" | sort -u | tr -d '\n')
1387      charset_2=$(echo "${charset_2}" | sort -u | tr -d '\n')
1388      charset_3=$(echo "${charset_3}" | sort -u | tr -d '\n')
1389      charset_4=$(echo "${charset_4}" | sort -u | tr -d '\n')
1390
1391      custom_charsets="-1 ${charset_1} -2 ${charset_2} -3 ${charset_3} -4 ${charset_4}"
1392    fi
1393
1394    if [ "${hash_type}" -eq 22000 ]; then
1395
1396      mask="?d?d?d?d?d?1?2?3?4"
1397
1398      charset_1=""
1399      charset_2=""
1400      charset_3=""
1401      charset_4=""
1402
1403      # check positions (here we assume that mask is always composed of non literal chars
1404      # i.e. something like ?d?l?u?s?1 is possible, but ?d?dsuffix not
1405      charset_1_pos=$(expr index "${mask}" 1)
1406      charset_2_pos=$(expr index "${mask}" 2)
1407      charset_3_pos=$(expr index "${mask}" 3)
1408      charset_4_pos=$(expr index "${mask}" 4)
1409
1410      # divide each charset position by 2 since each of them occupies 2 positions in the mask
1411
1412      charset_1_pos=$((charset_1_pos / 2))
1413      charset_2_pos=$((charset_2_pos / 2))
1414      charset_3_pos=$((charset_3_pos / 2))
1415      charset_4_pos=$((charset_4_pos / 2))
1416
1417      i=1
1418
1419      while read -r -u 9 hash; do
1420
1421        pass=$(sed -n ${i}p "${OUTD}/${hash_type}_passwords.txt")
1422
1423        # charset 1
1424        char=$(echo "${pass}" | cut -b ${charset_1_pos})
1425        charset_1=$(printf "%s\n%s\n" "${charset_1}" "${char}")
1426
1427        # charset 2
1428        char=$(echo "${pass}" | cut -b ${charset_2_pos})
1429        charset_2=$(printf "%s\n%s\n" "${charset_2}" "${char}")
1430
1431        # charset 3
1432        char=$(echo "${pass}" | cut -b ${charset_3_pos})
1433        charset_3=$(printf "%s\n%s\n" "${charset_3}" "${char}")
1434
1435        # charset 4
1436        char=$(echo "${pass}" | cut -b ${charset_4_pos})
1437        charset_4=$(printf "%s\n%s\n" "${charset_4}" "${char}")
1438
1439        i=$((i + 1))
1440
1441      done 9< "${OUTD}/${hash_type}_multihash_bruteforce.txt"
1442
1443      # just make sure that all custom charset fields are initialized
1444
1445      if [ -z "${charset_1}" ]; then
1446
1447        charset_1="1"
1448
1449      fi
1450
1451      if [ -z "${charset_2}" ]; then
1452
1453        charset_2="2"
1454
1455      fi
1456
1457      if [ -z "${charset_3}" ]; then
1458
1459        charset_3="3"
1460
1461      fi
1462
1463      if [ -z "${charset_4}" ]; then
1464
1465        charset_4="4"
1466
1467      fi
1468
1469      # unique and remove new lines
1470
1471      charset_1=$(echo "${charset_1}" | sort -u | tr -d '\n')
1472      charset_2=$(echo "${charset_2}" | sort -u | tr -d '\n')
1473      charset_3=$(echo "${charset_3}" | sort -u | tr -d '\n')
1474      charset_4=$(echo "${charset_4}" | sort -u | tr -d '\n')
1475
1476      custom_charsets="-1 ${charset_1} -2 ${charset_2} -3 ${charset_3} -4 ${charset_4}"
1477    fi
1478
1479    increment_charset_opts=""
1480
1481    if [ ${need_hcmask} -eq 0 ]; then # the "normal" case without .hcmask file
1482      increment_charset_opts="--increment --increment-min ${increment_min} --increment-max ${increment_max}"
1483
1484      if [ -n "${custom_charsets}" ]; then
1485        increment_charset_opts="${increment_charset_opts} ${custom_charsets}"
1486      fi
1487    fi
1488
1489    CMD="./${BIN} ${OPTS} -a 3 -m ${hash_type} ${increment_charset_opts} ${hash_file} ${mask} "
1490
1491    echo "> Testing hash type $hash_type with attack mode 3, markov ${MARKOV}, multi hash, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR}." >> "${OUTD}/logfull.txt"  2>> "${OUTD}/logfull.txt"
1492
1493    output=$(./${BIN} ${OPTS} -a 3 -m ${hash_type} ${increment_charset_opts} ${hash_file} ${mask} 2>&1)
1494
1495    ret=${?}
1496
1497    echo "${output}" >> "${OUTD}/logfull.txt"
1498
1499    if [ "${ret}" -eq 0 ]; then
1500
1501      i=1
1502
1503      while read -r -u 9 hash; do
1504        line_nr=$((i + cracks_offset))
1505
1506        pass=$(sed -n ${line_nr}p "${OUTD}/${hash_type}_passwords.txt")
1507
1508        if [ "${pass_only}" -eq 1 ]; then
1509          search=":${pass}"
1510        else
1511          search="${hash}:${pass}"
1512        fi
1513
1514        echo "${output}" | grep -F "${search}" >/dev/null 2>/dev/null
1515
1516        if [ "${?}" -ne 0 ]; then
1517
1518          ret=10
1519
1520          break
1521
1522        fi
1523
1524        i=$((i + 1))
1525
1526      done 9< "${OUTD}/${hash_type}_multihash_bruteforce.txt"
1527
1528    fi
1529
1530    status ${ret}
1531
1532    msg="OK"
1533
1534    if [ "${e_nf}" -ne 0 ] || [ "${e_nm}" -ne 0 ]; then
1535
1536      msg="Error"
1537
1538    elif [ "${e_to}" -ne 0 ]; then
1539
1540      msg="Warning"
1541
1542    fi
1543
1544    echo "[ ${OUTD} ] [ Type ${hash_type}, Attack 3, Mode multi,  Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR} ] > $msg : ${e_nf}/${cnt} not found, ${e_nm}/${cnt} not matched, ${e_to}/${cnt} timeout"
1545
1546  fi
1547}
1548
1549function attack_6()
1550{
1551  file_only=0
1552
1553  if is_in_array "${hash_type}" ${FILE_BASED_ALGOS}; then
1554
1555    file_only=1
1556
1557  fi
1558
1559  # single hash
1560  if [ "${MODE}" -ne 1 ]; then
1561
1562    e_to=0
1563    e_nf=0
1564    e_nm=0
1565    cnt=0
1566
1567    echo "> Testing hash type $hash_type with attack mode 6, markov ${MARKOV}, single hash, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR}." >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
1568
1569    min=1
1570    max=8
1571    mask_offset=0
1572
1573    if   [ "${hash_type}" -eq  2500 ]; then
1574      max=6
1575    elif [ "${hash_type}" -eq 14000 ]; then
1576      min=0
1577      max=1
1578      mask_offset=4
1579    elif [ "${hash_type}" -eq 14100 ]; then
1580      min=0
1581      max=1
1582      mask_offset=21
1583    elif [ "${hash_type}" -eq 14900 ]; then
1584      min=0
1585      max=1
1586      mask_offset=5
1587    elif [ "${hash_type}" -eq 15400 ]; then
1588      min=0
1589      max=1
1590      mask_offset=29
1591    elif [ "${hash_type}" -eq 16800 ]; then
1592      max=6
1593    elif [ "${hash_type}" -eq 22000 ]; then
1594      max=6
1595    fi
1596
1597    # special case: we need to split the first line
1598
1599    if [ "${min}" -eq 0 ]; then
1600
1601      pass_part_1=$(sed -n 1p "${OUTD}/${hash_type}_dict1")
1602      pass_part_2=$(sed -n 1p "${OUTD}/${hash_type}_dict2")
1603
1604      pass="${pass_part_1}${pass_part_2}"
1605
1606      echo -n "${pass}" | cut -b -$((mask_offset + 0))  > "${OUTD}/${hash_type}_dict1_custom"
1607      echo -n "${pass}" | cut -b  $((mask_offset + 1))- > "${OUTD}/${hash_type}_dict2_custom"
1608
1609      mask_custom=""
1610
1611      for i in $(seq 1 $((${#pass} - mask_offset))); do
1612
1613        if   [ "${hash_type}" -eq 14000 ]; then
1614
1615          char=$(echo -n "${pass}" | cut -b $((i + mask_offset)))
1616          mask_custom="${mask_custom}${char}"
1617
1618        elif [ "${hash_type}" -eq 14100 ]; then
1619
1620          char=$(echo -n "${pass}" | cut -b $((i + mask_offset)))
1621          mask_custom="${mask_custom}${char}"
1622
1623        else
1624
1625          mask_custom="${mask_custom}?d"
1626
1627        fi
1628
1629      done
1630
1631    fi
1632
1633
1634    i=1
1635
1636    while read -r -u 9 hash; do
1637
1638      if [ "${i}" -gt 6 ]; then
1639
1640        if is_in_array "${hash_type}" ${TIMEOUT_ALGOS}; then
1641
1642          break
1643
1644        fi
1645
1646      fi
1647
1648      if [ ${i} -gt ${min} ]; then
1649
1650        if [ "${file_only}" -eq 1 ]; then
1651
1652          temp_file="${OUTD}/${hash_type}_filebased_only_temp.txt"
1653
1654          if [ "${hash_type}" -ne 22000 ]; then
1655            echo "${hash}" | base64 -d > "${temp_file}"
1656          else
1657            echo "${hash}" > "${temp_file}"
1658          fi
1659
1660          hash="${temp_file}"
1661
1662        fi
1663
1664        dict1=${OUTD}/${hash_type}_dict1
1665        dict2=${OUTD}/${hash_type}_dict2
1666
1667        dict1_a6=${OUTD}/${hash_type}_dict1_a6
1668
1669        cp "${dict1}" "${dict1_a6}"
1670
1671        pass=$(sed -n ${i}p "${OUTD}/${hash_type}_passwords.txt")
1672
1673        if [ "${hash_type}" -eq 20510 ]; then # special case for PKZIP Master Key
1674          pass=$(echo "${pass}" | cut -b 7-) # skip the first 6 chars
1675        fi
1676
1677        if [ ${#pass} -le ${i} ]; then
1678          i=$((i + 1))
1679          continue
1680        fi
1681
1682        echo "${pass}" | cut -b -$((${#pass} - i)) >> "${dict1_a6}"
1683
1684        # the block below is just a fancy way to do a "shuf" (or sort -R) because macOS doesn't really support it natively
1685        # we do not really need a shuf, but it's actually better for testing purposes
1686
1687        rm -f "${dict1_a6}.txt" # temporary file
1688
1689        line_num=$(wc -l "${dict1_a6}" | sed -E 's/ *([0-9]+) .*$/\1/')
1690
1691        sorted_lines=$(seq 1 "${line_num}")
1692
1693        for lines in $(seq 1 "${line_num}"); do
1694
1695          random_num=$((RANDOM % line_num))
1696          random_num=$((random_num + 1)) # sed -n [n]p starts counting with 1 (not 0)
1697
1698          random_line=$(echo -n "${sorted_lines}" | sed -n ${random_num}p)
1699
1700          sed -n ${random_line}p "${dict1_a6}" >> "${dict1_a6}.txt"
1701
1702          # update the temp list of lines
1703
1704          sorted_lines=$(echo -n "${sorted_lines}" | grep -v "^${random_line}$")
1705
1706          line_num=$((line_num - 1))
1707
1708        done
1709
1710        mv "${dict1_a6}.txt" "${dict1_a6}"
1711
1712        # end of shuf/sort -R
1713
1714
1715        mask=""
1716
1717        for j in $(seq 1 ${i}); do
1718          mask="${mask}?d"
1719        done
1720
1721        CMD="./${BIN} ${OPTS} -a 6 -m ${hash_type} '${hash}' ${dict1_a6} ${mask}"
1722
1723        echo -n "[ len $i ] " >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
1724
1725        output=$(./${BIN} ${OPTS} -a 6 -m ${hash_type} "${hash}" ${dict1_a6} ${mask} 2>&1)
1726
1727        ret=${?}
1728
1729        echo "${output}" >> "${OUTD}/logfull.txt"
1730
1731        if [ "${ret}" -eq 0 ]; then
1732
1733          line_nr=1
1734
1735          if [ "${i}" -gt 1 ]; then
1736            line_nr=$((i - 1))
1737          fi
1738
1739          line_dict1=$(sed -n ${line_nr}p "${dict1}")
1740          line_dict2=$(sed -n ${line_nr}p "${dict2}")
1741
1742          if [ "${pass_only}" -eq 1 ]; then
1743            search=":${line_dict1}${line_dict2}"
1744          else
1745            search="${hash}:${line_dict1}${line_dict2}"
1746          fi
1747
1748          echo "${output}" | grep -F "${search}" >/dev/null 2>/dev/null
1749
1750          if [ "${?}" -ne 0 ]; then
1751
1752            ret=10
1753
1754          fi
1755
1756        fi
1757
1758        status ${ret}
1759
1760      fi
1761
1762      if [ "${i}" -eq ${max} ]; then break; fi
1763
1764      i=$((i + 1))
1765
1766    done 9< "${OUTD}/${hash_type}_hashes.txt"
1767
1768    msg="OK"
1769
1770    if [ "${e_nf}" -ne 0 ] || [ "${e_nm}" -ne 0 ]; then
1771
1772      msg="Error"
1773
1774    elif [ "${e_to}" -ne 0 ]; then
1775
1776      msg="Warning"
1777
1778    fi
1779
1780    echo "[ ${OUTD} ] [ Type ${hash_type}, Attack 6, Mode single, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR} ] > $msg : ${e_nf}/${cnt} not found, ${e_nm}/${cnt} not matched, ${e_to}/${cnt} timeout"
1781
1782    rm -f "${OUTD}/${hash_type}_dict1_custom"
1783    rm -f "${OUTD}/${hash_type}_dict2_custom"
1784
1785  fi
1786
1787  # multihash
1788  if [ "${MODE}" -ne 0 ]; then
1789
1790    # no multi hash checks for these modes (because we only have 1 hash for each of them)
1791
1792    if   [ "${hash_type}" -eq 14000 ]; then
1793      return
1794    elif [ "${hash_type}" -eq 14100 ]; then
1795      return
1796    elif [ "${hash_type}" -eq 14900 ]; then
1797      return
1798    elif [ "${hash_type}" -eq 15400 ]; then
1799      return
1800    fi
1801
1802    e_to=0
1803    e_nf=0
1804    e_nm=0
1805    cnt=0
1806
1807    max=9
1808
1809    if   [ "${hash_type}" -eq  2500 ]; then
1810      max=5
1811    elif [ "${hash_type}" -eq  3000 ]; then
1812      max=8
1813    elif [ "${hash_type}" -eq  7700 ] || [ "${hash_type}" -eq  7701 ]; then
1814      max=8
1815    elif [ "${hash_type}" -eq  8500 ]; then
1816      max=8
1817    elif [ "${hash_type}" -eq 16800 ]; then
1818      max=5
1819    elif [ "${hash_type}" -eq 22000 ]; then
1820      max=5
1821    fi
1822
1823    if is_in_array "${hash_type}" ${TIMEOUT_ALGOS}; then
1824
1825      max=5
1826
1827      if [ "${hash_type}" -eq 3200 ]; then
1828
1829        max=3
1830
1831      fi
1832
1833    fi
1834
1835    i=2
1836    while [ "$i" -lt "$max" ]; do
1837
1838      hash_file=${OUTD}/${hash_type}_hashes_multi_${i}.txt
1839
1840      # if file_only -> decode all base64 "hashes" and put them in the temporary file
1841
1842      if [ "${file_only}" -eq 1 ]; then
1843
1844        temp_file="${OUTD}/${hash_type}_filebased_only_temp.txt"
1845        rm -f "${temp_file}"
1846
1847        hash_file=${temp_file}
1848
1849        while read -r file_only_hash; do
1850
1851          if [ "${hash_type}" -ne 22000 ]; then
1852            echo -n "${file_only_hash}" | base64 -d >> "${temp_file}"
1853          else
1854            echo "${file_only_hash}" >> "${temp_file}"
1855          fi
1856
1857        done < "${OUTD}/${hash_type}_hashes_multi_${i}.txt"
1858
1859      fi
1860
1861      mask=${mask_6[$i]}
1862
1863      CMD="./${BIN} ${OPTS} -a 6 -m ${hash_type} ${hash_file} ${OUTD}/${hash_type}_dict1_multi_${i} ${mask}"
1864
1865      echo "> Testing hash type $hash_type with attack mode 6, markov ${MARKOV}, multi hash with word len ${i}." >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
1866
1867      output=$(./${BIN} ${OPTS} -a 6 -m ${hash_type} ${hash_file} ${OUTD}/${hash_type}_dict1_multi_${i} ${mask} 2>&1)
1868
1869      ret=${?}
1870
1871      echo "${output}" >> "${OUTD}/logfull.txt"
1872
1873      if [ "${ret}" -eq 0 ]; then
1874
1875        j=1
1876
1877        while read -r -u 9 hash; do
1878
1879          line_dict1=$(sed -n ${j}p "${OUTD}/${hash_type}_dict1_multi_${i}")
1880          line_dict2=$(sed -n ${j}p "${OUTD}/${hash_type}_dict2_multi_${i}")
1881
1882          if [ "${pass_only}" -eq 1 ]; then
1883            search=":${line_dict1}${line_dict2}"
1884          else
1885            search="${hash}:${line_dict1}${line_dict2}"
1886          fi
1887
1888          echo "${output}" | grep -F "${search}" >/dev/null 2>/dev/null
1889
1890          if [ "${?}" -ne 0 ]; then
1891
1892            ret=10
1893
1894            break
1895
1896          fi
1897
1898          j=$((j + 1))
1899
1900        done 9< "${OUTD}/${hash_type}_hashes_multi_${i}.txt"
1901
1902      fi
1903
1904      status ${ret}
1905      i=$((i + 1))
1906
1907    done
1908
1909    msg="OK"
1910
1911    if [ "${e_nf}" -ne 0 ] || [ "${e_nm}" -ne 0 ]; then
1912
1913      msg="Error"
1914
1915    elif [ "${e_to}" -ne 0 ]; then
1916
1917      msg="Warning"
1918
1919    fi
1920
1921    echo "[ ${OUTD} ] [ Type ${hash_type}, Attack 6, Mode multi,  Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR} ] > $msg : ${e_nf}/${cnt} not found, ${e_nm}/${cnt} not matched, ${e_to}/${cnt} timeout"
1922
1923  fi
1924}
1925
1926function attack_7()
1927{
1928  file_only=0
1929
1930  if is_in_array "${hash_type}" ${FILE_BASED_ALGOS}; then
1931
1932    file_only=1
1933
1934  fi
1935
1936  # single hash
1937  if [ "${MODE}" -ne 1 ]; then
1938
1939    e_to=0
1940    e_nf=0
1941    e_nm=0
1942    cnt=0
1943
1944    echo "> Testing hash type $hash_type with attack mode 7, markov ${MARKOV}, single hash, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR}." >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
1945
1946    min=1
1947    max=8
1948
1949    mask_offset=0
1950
1951    if   [ "${hash_type}" -eq  2500 ]; then
1952      max=5
1953    elif [ "${hash_type}" -eq 14000 ]; then
1954      mask_offset=4
1955      min=0
1956      max=1
1957    elif [ "${hash_type}" -eq 14100 ]; then
1958      mask_offset=3
1959      min=0
1960      max=1
1961    elif [ "${hash_type}" -eq 14900 ]; then
1962      mask_offset=5
1963      min=0
1964      max=1
1965    elif [ "${hash_type}" -eq 15400 ]; then
1966      mask_offset=3
1967      min=0
1968      max=1
1969    elif [ "${hash_type}" -eq 16800 ]; then
1970      max=5
1971    elif [ "${hash_type}" -eq 22000 ]; then
1972      max=5
1973    fi
1974
1975    # special case: we need to split the first line
1976
1977    if [ "${min}" -eq 0 ]; then
1978
1979      pass_part_1=$(sed -n 1p "${OUTD}/${hash_type}_dict1")
1980      pass_part_2=$(sed -n 1p "${OUTD}/${hash_type}_dict2")
1981
1982      pass="${pass_part_1}${pass_part_2}"
1983
1984      echo -n "${pass}" | cut -b -$((mask_offset + 0))  > "${OUTD}/${hash_type}_dict1_custom"
1985      echo -n "${pass}" | cut -b  $((mask_offset + 1))- > "${OUTD}/${hash_type}_dict2_custom"
1986
1987      mask_custom=""
1988
1989      for i in $(seq 1 ${mask_offset}); do
1990
1991        if   [ "${hash_type}" -eq 14000 ]; then
1992
1993          char=$(echo -n "${pass}" | cut -b ${i})
1994          mask_custom="${mask_custom}${char}"
1995
1996        elif [ "${hash_type}" -eq 14100 ]; then
1997
1998          char=$(echo -n "${pass}" | cut -b ${i})
1999          mask_custom="${mask_custom}${char}"
2000
2001        else
2002
2003          mask_custom="${mask_custom}?d"
2004
2005        fi
2006
2007      done
2008
2009    fi
2010
2011    i=1
2012
2013    while read -r -u 9 hash; do
2014
2015      if [ ${i} -gt ${min} ]; then
2016
2017        if [ "${file_only}" -eq 1 ]; then
2018
2019          temp_file="${OUTD}/${hash_type}_filebased_only_temp.txt"
2020
2021          if [ "${hash_type}" -ne 22000 ]; then
2022            echo "${hash}" | base64 -d > "${temp_file}"
2023          else
2024            echo "${hash}" > "${temp_file}"
2025          fi
2026
2027          hash="${temp_file}"
2028
2029        fi
2030
2031        mask=${mask_7[$i]}
2032
2033        # adjust mask if needed
2034
2035        line_nr=1
2036
2037        if [ "${i}" -gt 1 ]; then
2038          line_nr=$((i - 1))
2039        fi
2040
2041        if [ "${hash_type}" -eq 2500 ]; then
2042
2043          pass_part_1=$(sed -n ${line_nr}p "${OUTD}/${hash_type}_dict1")
2044          pass_part_2=$(sed -n ${line_nr}p "${OUTD}/${hash_type}_dict2")
2045
2046          pass_part_2_len=${#pass_part_2}
2047
2048          pass=${pass_part_1}${pass_part_2}
2049
2050          pass_len=${#pass}
2051
2052          # add first x chars of password to mask and append the (old) mask
2053
2054          mask_len=${#mask}
2055          mask_len=$((mask_len / 2))
2056
2057          mask_prefix=$(echo ${pass} | cut -b -$((pass_len - mask_len - pass_part_2_len)))
2058          mask=${mask_prefix}${mask}
2059
2060        fi
2061
2062        if [ "${hash_type}" -eq 16800 ]; then
2063
2064          pass_part_1=$(sed -n ${line_nr}p "${OUTD}/${hash_type}_dict1")
2065          pass_part_2=$(sed -n ${line_nr}p "${OUTD}/${hash_type}_dict2")
2066
2067          pass_part_2_len=${#pass_part_2}
2068
2069          pass=${pass_part_1}${pass_part_2}
2070          pass_len=${#pass}
2071
2072          # add first x chars of password to mask and append the (old) mask
2073
2074          mask_len=${#mask}
2075          mask_len=$((mask_len / 2))
2076
2077          mask_prefix=$(echo "${pass}" | cut -b -$((pass_len - mask_len - pass_part_2_len)))
2078          mask=${mask_prefix}${mask}
2079
2080        fi
2081
2082        if [ "${hash_type}" -eq 22000 ]; then
2083
2084          pass_part_1=$(sed -n ${line_nr}p "${OUTD}/${hash_type}_dict1")
2085          pass_part_2=$(sed -n ${line_nr}p "${OUTD}/${hash_type}_dict2")
2086
2087          pass_part_2_len=${#pass_part_2}
2088
2089          pass=${pass_part_1}${pass_part_2}
2090          pass_len=${#pass}
2091
2092          # add first x chars of password to mask and append the (old) mask
2093
2094          mask_len=${#mask}
2095          mask_len=$((mask_len / 2))
2096
2097          mask_prefix=$(echo "${pass}" | cut -b -$((pass_len - mask_len - pass_part_2_len)))
2098          mask=${mask_prefix}${mask}
2099
2100        fi
2101
2102        if [ "${hash_type}" -eq 20510 ]; then
2103
2104          pass_part_1=$(sed -n ${line_nr}p "${OUTD}/${hash_type}_dict1")
2105          pass_part_2=$(sed -n ${line_nr}p "${OUTD}/${hash_type}_dict2")
2106
2107          pass=${pass_part_1}${pass_part_2}
2108
2109          pass_len=${#pass}
2110
2111          if [ "${pass_len}" -le 6 ]; then
2112            i=$((i + 1))
2113            continue
2114          fi
2115
2116          pass_old=${pass}
2117
2118          pass=$(echo "${pass}" | cut -b 7-) # skip the first 6 chars
2119
2120          mask_len=$((${#mask} / 2))
2121
2122          echo "${pass_old}" | cut -b -$((6 + mask_len)) > "${OUTD}/${hash_type}_dict1_custom"
2123          echo "${pass}"     | cut -b $((mask_len + 1))- > "${OUTD}/${hash_type}_dict2_custom"
2124
2125          min=0 # hack to use the custom dict
2126          mask_custom=${mask}
2127
2128        fi
2129
2130        dict1=${OUTD}/${hash_type}_dict1
2131        dict2=${OUTD}/${hash_type}_dict2
2132
2133        if [ "${min}" -eq 0 ]; then
2134          mask=${mask_custom}
2135
2136          dict1=${OUTD}/${hash_type}_dict1_custom
2137          dict2=${OUTD}/${hash_type}_dict2_custom
2138        fi
2139
2140        CMD="./${BIN} ${OPTS} -a 7 -m ${hash_type} '${hash}' ${mask} ${dict2}"
2141
2142        echo -n "[ len $i ] " >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
2143
2144        output=$(./${BIN} ${OPTS} -a 7 -m ${hash_type} "${hash}" ${mask} ${dict2} 2>&1)
2145
2146        ret=${?}
2147
2148        echo "${output}" >> "${OUTD}/logfull.txt"
2149
2150        if [ "${ret}" -eq 0 ]; then
2151
2152          line_nr=1
2153
2154          if [ "${i}" -gt 1 ]; then
2155            line_nr=$((i - 1))
2156          fi
2157
2158          line_dict1=$(sed -n ${line_nr}p "${dict1}")
2159          line_dict2=$(sed -n ${line_nr}p "${dict2}")
2160
2161          if [ "${pass_only}" -eq 1 ]; then
2162            search=":${line_dict1}${line_dict2}"
2163          else
2164            search="${hash}:${line_dict1}${line_dict2}"
2165          fi
2166
2167          echo "${output}" | grep -F "${search}" >/dev/null 2>/dev/null
2168
2169          if [ "${?}" -ne 0 ]; then
2170
2171            ret=10
2172
2173          fi
2174
2175        fi
2176
2177        status ${ret}
2178
2179      fi
2180
2181      if [ $i -eq ${max} ]; then break; fi
2182
2183      i=$((i + 1))
2184
2185    done 9< "${OUTD}/${hash_type}_hashes.txt"
2186
2187    msg="OK"
2188
2189    if [ "${e_nf}" -ne 0 ] || [ "${e_nm}" -ne 0 ]; then
2190
2191      msg="Error"
2192
2193    elif [ "${e_to}" -ne 0 ]; then
2194
2195      msg="Warning"
2196
2197    fi
2198
2199    echo "[ ${OUTD} ] [ Type ${hash_type}, Attack 7, Mode single, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR} ] > $msg : ${e_nf}/${cnt} not found, ${e_nm}/${cnt} not matched, ${e_to}/${cnt} timeout"
2200
2201    rm -f "${OUTD}/${hash_type}_dict1_custom"
2202    rm -f "${OUTD}/${hash_type}_dict2_custom"
2203
2204  fi
2205
2206  # multihash
2207  if [ "${MODE}" -ne 0 ]; then
2208
2209    # no multi hash checks for these modes (because we only have 1 hash for each of them)
2210
2211    if   [ "${hash_type}" -eq 14000 ]; then
2212      return
2213    elif [ "${hash_type}" -eq 14100 ]; then
2214      return
2215    elif [ "${hash_type}" -eq 14900 ]; then
2216      return
2217    elif [ "${hash_type}" -eq 15400 ]; then
2218      return
2219    fi
2220
2221    e_to=0
2222    e_nf=0
2223    e_nm=0
2224    cnt=0
2225
2226    max=9
2227
2228    if   [ "${hash_type}" -eq  2500 ]; then
2229      max=5
2230    elif [ "${hash_type}" -eq  3000 ]; then
2231      max=8
2232    elif [ "${hash_type}" -eq  7700 ] || [ "${hash_type}" -eq  7701 ]; then
2233      max=8
2234    elif [ "${hash_type}" -eq  8500 ]; then
2235      max=8
2236    elif [ "${hash_type}" -eq 14000 ]; then
2237      max=5
2238    elif [ "${hash_type}" -eq 14100 ]; then
2239      max=5
2240    elif [ "${hash_type}" -eq 14900 ]; then
2241      max=5
2242    elif [ "${hash_type}" -eq 15400 ]; then
2243      max=5
2244    elif [ "${hash_type}" -eq 16800 ]; then
2245      max=5
2246    elif [ "${hash_type}" -eq 22000 ]; then
2247      max=5
2248    fi
2249
2250    if is_in_array "${hash_type}" ${TIMEOUT_ALGOS}; then
2251
2252      max=7
2253
2254      if [ "${hash_type}" -eq 3200 ]; then
2255
2256        max=4
2257
2258      fi
2259
2260    fi
2261
2262    i=2
2263    while [ "$i" -lt "$max" ]; do
2264
2265      hash_file=${OUTD}/${hash_type}_hashes_multi_${i}.txt
2266      dict_file=${OUTD}/${hash_type}_dict2_multi_${i}
2267
2268      mask=${mask_7[$i]}
2269
2270      # if file_only -> decode all base64 "hashes" and put them in the temporary file
2271
2272      if [ "${file_only}" -eq 1 ]; then
2273
2274        temp_file="${OUTD}/${hash_type}_filebased_only_temp.txt"
2275        rm -f "${temp_file}"
2276
2277        hash_file=${temp_file}
2278
2279        while read -r file_only_hash; do
2280
2281          if [ "${hash_type}" -ne 22000 ]; then
2282            echo -n "${file_only_hash}" | base64 -d >> "${temp_file}"
2283          else
2284            echo "${file_only_hash}" >> "${temp_file}"
2285          fi
2286
2287        done < "${OUTD}/${hash_type}_hashes_multi_${i}.txt"
2288
2289        # a little hack: since we don't want to have a very large mask (and wpa has minimum length of 8),
2290        # we need to create a temporary dict file on-the-fly and use it like this: [small mask] [long(er) words in dict]
2291
2292        dict_file=${OUTD}/${hash_type}_dict2_multi_${i}_longer
2293        rm -f "${dict_file}"
2294
2295        mask_len=${#mask}
2296        mask_len=$((mask_len / 2))
2297
2298        j=1
2299
2300        while read -r -u 9 hash; do
2301
2302          pass_part_1=$(sed -n ${j}p "${OUTD}/${hash_type}_dict1_multi_${i}")
2303          pass_part_2=$(sed -n ${j}p "${OUTD}/${hash_type}_dict2_multi_${i}")
2304
2305          pass="${pass_part_1}${pass_part_2}"
2306
2307          pass_suffix=$(echo "${pass}" | cut -b $((mask_len + 1))-)
2308
2309          echo "${pass_suffix}" >> "${dict_file}"
2310
2311          j=$((j + 1))
2312
2313        done 9< "${OUTD}/${hash_type}_hashes_multi_${i}.txt"
2314
2315      fi
2316
2317      CMD="./${BIN} ${OPTS} -a 7 -m ${hash_type} ${hash_file} ${mask} ${dict_file}"
2318
2319      echo "> Testing hash type $hash_type with attack mode 7, markov ${MARKOV}, multi hash with word len ${i}." >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
2320
2321      output=$(./${BIN} ${OPTS} -a 7 -m ${hash_type} ${hash_file} ${mask} ${dict_file} 2>&1)
2322
2323      ret=${?}
2324
2325      echo "${output}" >> "${OUTD}/logfull.txt"
2326
2327      if [ "${ret}" -eq 0 ]; then
2328
2329        j=1
2330
2331        while read -r -u 9 hash; do
2332
2333          line_dict1=$(sed -n ${j}p "${OUTD}/${hash_type}_dict1_multi_${i}")
2334          line_dict2=$(sed -n ${j}p "${OUTD}/${hash_type}_dict2_multi_${i}")
2335
2336          if [ "${pass_only}" -eq 1 ]; then
2337            search=":${line_dict1}${line_dict2}"
2338          else
2339            search="${hash}:${line_dict1}${line_dict2}"
2340          fi
2341
2342          echo "${output}" | grep -F "${search}" >/dev/null 2>/dev/null
2343
2344          if [ "${?}" -ne 0 ]; then
2345
2346            ret=10
2347
2348            break
2349
2350          fi
2351
2352          j=$((j + 1))
2353
2354        done 9< "${OUTD}/${hash_type}_hashes_multi_${i}.txt"
2355
2356      fi
2357
2358      status ${ret}
2359      i=$((i + 1))
2360
2361    done
2362
2363    msg="OK"
2364
2365    if [ "${e_nf}" -ne 0 ] || [ "${e_nm}" -ne 0 ]; then
2366
2367      msg="Error"
2368
2369    elif [ "${e_to}" -ne 0 ]; then
2370
2371      msg="Warning"
2372
2373    fi
2374
2375    echo "[ ${OUTD} ] [ Type ${hash_type}, Attack 7, Mode multi,  Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR} ] > $msg : ${e_nf}/${cnt} not found, ${e_nm}/${cnt} not matched, ${e_to}/${cnt} timeout"
2376
2377  fi
2378}
2379
2380function cryptoloop_test()
2381{
2382  hashType=$1
2383  keySize=$2
2384  CMD="unset"
2385
2386  mkdir -p ${OUTD}/cl_tests
2387  chmod u+x ${TDIR}/cryptoloop2hashcat.py
2388
2389  case $hashType in
2390
2391    14511)
2392      case $keySize in
2393        128|192|256)
2394          ${TDIR}/cryptoloop2hashcat.py --source ${TDIR}/cl_tests/hashcat_sha1_aes_${keySize}.img --hash sha1 --cipher aes --keysize ${keySize} > ${OUTD}/cl_tests/hashcat_sha1_aes_${keySize}.hash
2395          CMD="./${BIN} ${OPTS} -a 3 -m 14500 ${OUTD}/cl_tests/hashcat_sha1_aes_${keySize}.hash hashca?l"
2396          ;;
2397      esac
2398      ;;
2399
2400    14512)
2401      case $keySize in
2402        128|192|256)
2403          ${TDIR}/cryptoloop2hashcat.py --source ${TDIR}/cl_tests/hashcat_sha1_serpent_${keySize}.img --hash sha1 --cipher serpent --keysize ${keySize} > ${OUTD}/cl_tests/hashcat_sha1_serpent_${keySize}.hash
2404          CMD="./${BIN} ${OPTS} -a 3 -m 14500 ${OUTD}/cl_tests/hashcat_sha1_serpent_${keySize}.hash hashca?l"
2405          ;;
2406      esac
2407      ;;
2408
2409    14513)
2410      case $keySize in
2411        128|192|256)
2412          ${TDIR}/cryptoloop2hashcat.py --source ${TDIR}/cl_tests/hashcat_sha1_twofish_${keySize}.img --hash sha1 --cipher twofish --keysize ${keySize} > ${OUTD}/cl_tests/hashcat_sha1_twofish_${keySize}.hash
2413          CMD="./${BIN} ${OPTS} -a 3 -m 14500 ${OUTD}/cl_tests/hashcat_sha1_twofish_${keySize}.hash hashca?l"
2414          ;;
2415      esac
2416      ;;
2417
2418    14521)
2419      case $keySize in
2420        128|192|256)
2421          ${TDIR}/cryptoloop2hashcat.py --source ${TDIR}/cl_tests/hashcat_sha256_aes_${keySize}.img --hash sha256 --cipher aes --keysize ${keySize} > ${OUTD}/cl_tests/hashcat_sha256_aes_${keySize}.hash
2422          CMD="./${BIN} ${OPTS} -a 3 -m 14500 ${OUTD}/cl_tests/hashcat_sha256_aes_${keySize}.hash hashca?l"
2423          ;;
2424      esac
2425      ;;
2426
2427    14522)
2428      case $keySize in
2429        128|192|256)
2430          ${TDIR}/cryptoloop2hashcat.py --source ${TDIR}/cl_tests/hashcat_sha256_serpent_${keySize}.img --hash sha256 --cipher serpent --keysize ${keySize} > ${OUTD}/cl_tests/hashcat_sha256_serpent_${keySize}.hash
2431          CMD="./${BIN} ${OPTS} -a 3 -m 14500 ${OUTD}/cl_tests/hashcat_sha256_serpent_${keySize}.hash hashca?l"
2432          ;;
2433      esac
2434      ;;
2435
2436    14523)
2437      case $keySize in
2438        128|192|256)
2439          ${TDIR}/cryptoloop2hashcat.py --source ${TDIR}/cl_tests/hashcat_sha256_twofish_${keySize}.img --hash sha256 --cipher twofish --keysize ${keySize} > ${OUTD}/cl_tests/hashcat_sha256_twofish_${keySize}.hash
2440          CMD="./${BIN} ${OPTS} -a 3 -m 14500 ${OUTD}/cl_tests/hashcat_sha256_twofish_${keySize}.hash hashca?l"
2441          ;;
2442      esac
2443      ;;
2444
2445    14531)
2446      case $keySize in
2447        128|192|256)
2448          ${TDIR}/cryptoloop2hashcat.py --source ${TDIR}/cl_tests/hashcat_sha512_aes_${keySize}.img --hash sha512 --cipher aes --keysize ${keySize} > ${OUTD}/cl_tests/hashcat_sha512_aes_${keySize}.hash
2449          CMD="./${BIN} ${OPTS} -a 3 -m 14500 ${OUTD}/cl_tests/hashcat_sha512_aes_${keySize}.hash hashca?l"
2450          ;;
2451      esac
2452      ;;
2453
2454    14532)
2455      case $keySize in
2456        128|192|256)
2457          ${TDIR}/cryptoloop2hashcat.py --source ${TDIR}/cl_tests/hashcat_sha512_serpent_${keySize}.img --hash sha512 --cipher serpent --keysize ${keySize} > ${OUTD}/cl_tests/hashcat_sha512_serpent_${keySize}.hash
2458          CMD="./${BIN} ${OPTS} -a 3 -m 14500 ${OUTD}/cl_tests/hashcat_sha512_serpent_${keySize}.hash hashca?l"
2459          ;;
2460      esac
2461      ;;
2462
2463    14533)
2464      case $keySize in
2465        128|192|256)
2466          ${TDIR}/cryptoloop2hashcat.py --source ${TDIR}/cl_tests/hashcat_sha512_twofish_${keySize}.img --hash sha512 --cipher twofish --keysize ${keySize} > ${OUTD}/cl_tests/hashcat_sha512_twofish_${keySize}.hash
2467          CMD="./${BIN} ${OPTS} -a 3 -m 14500 ${OUTD}/cl_tests/hashcat_sha512_twofish_${keySize}.hash hashca?l"
2468          ;;
2469      esac
2470      ;;
2471
2472    14541)
2473      case $keySize in
2474        128|192|256)
2475          ${TDIR}/cryptoloop2hashcat.py --source ${TDIR}/cl_tests/hashcat_ripemd160_aes_${keySize}.img --hash ripemd160 --cipher aes --keysize ${keySize} > ${OUTD}/cl_tests/hashcat_ripemd160_aes_${keySize}.hash
2476          CMD="./${BIN} ${OPTS} -a 3 -m 14500 ${OUTD}/cl_tests/hashcat_ripemd160_aes_${keySize}.hash hashca?l"
2477          ;;
2478      esac
2479      ;;
2480
2481    14542)
2482      case $keySize in
2483        128|192|256)
2484          ${TDIR}/cryptoloop2hashcat.py --source ${TDIR}/cl_tests/hashcat_ripemd160_serpent_${keySize}.img --hash ripemd160 --cipher serpent --keysize ${keySize} > ${OUTD}/cl_tests/hashcat_ripemd160_serpent_${keySize}.hash
2485          CMD="./${BIN} ${OPTS} -a 3 -m 14500 ${OUTD}/cl_tests/hashcat_ripemd160_serpent_${keySize}.hash hashca?l"
2486          ;;
2487      esac
2488      ;;
2489
2490    14543)
2491      case $keySize in
2492        128|192|256)
2493          ${TDIR}/cryptoloop2hashcat.py --source ${TDIR}/cl_tests/hashcat_ripemd160_twofish_${keySize}.img --hash ripemd160 --cipher twofish --keysize ${keySize} > ${OUTD}/cl_tests/hashcat_ripemd160_twofish_${keySize}.hash
2494          CMD="./${BIN} ${OPTS} -a 3 -m 14500 ${OUTD}/cl_tests/hashcat_ripemd160_twofish_${keySize}.hash hashca?l"
2495          ;;
2496      esac
2497      ;;
2498
2499    14551)
2500      case $keySize in
2501        128|192|256)
2502          ${TDIR}/cryptoloop2hashcat.py --source ${TDIR}/cl_tests/hashcat_whirlpool_aes_${keySize}.img --hash whirlpool --cipher aes --keysize ${keySize} > ${OUTD}/cl_tests/hashcat_whirlpool_aes_${keySize}.hash
2503          CMD="./${BIN} ${OPTS} -a 3 -m 14500 ${OUTD}/cl_tests/hashcat_whirlpool_aes_${keySize}.hash hashca?l"
2504          ;;
2505      esac
2506      ;;
2507
2508    14552)
2509      case $keySize in
2510        128|192|256)
2511          ${TDIR}/cryptoloop2hashcat.py --source ${TDIR}/cl_tests/hashcat_whirlpool_serpent_${keySize}.img --hash whirlpool --cipher serpent --keysize ${keySize} > ${OUTD}/cl_tests/hashcat_whirlpool_serpent_${keySize}.hash
2512          CMD="./${BIN} ${OPTS} -a 3 -m 14500 ${OUTD}/cl_tests/hashcat_whirlpool_serpent_${keySize}.hash hashca?l"
2513          ;;
2514      esac
2515      ;;
2516
2517    14553)
2518      case $keySize in
2519        128|192|256)
2520          ${TDIR}/cryptoloop2hashcat.py --source ${TDIR}/cl_tests/hashcat_whirlpool_twofish_${keySize}.img --hash whirlpool --cipher twofish --keysize ${keySize} > ${OUTD}/cl_tests/hashcat_whirlpool_twofish_${keySize}.hash
2521          CMD="./${BIN} ${OPTS} -a 3 -m 14500 ${OUTD}/cl_tests/hashcat_whirlpool_twofish_${keySize}.hash hashca?l"
2522          ;;
2523      esac
2524      ;;
2525  esac
2526
2527  if [ ${#CMD} -gt 5 ]; then
2528    echo "> Testing hash type $hashType with attack mode 3, markov ${MARKOV}, single hash, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR}, Key-Size ${keySize}" >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
2529
2530    output=$(${CMD} 2>&1)
2531
2532    ret=${?}
2533
2534    echo "${output}" >> "${OUTD}/logfull.txt"
2535
2536    cnt=1
2537    e_nf=0
2538    msg="OK"
2539
2540    if [ ${ret} -ne 0 ]; then
2541      e_nf=1
2542      msg="Error"
2543    fi
2544
2545    echo "[ ${OUTD} ] [ Type ${hash_type}, Attack 3, Mode single, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR}, Key-Size ${keySize} ] > $msg : ${e_nf}/${cnt} not found"
2546
2547    status ${ret}
2548  fi
2549}
2550
2551function truecrypt_test()
2552{
2553  hashType=$1
2554  tcMode=$2
2555  CMD="unset"
2556
2557  case $hashType in
2558
2559    6211)
2560      case $tcMode in
2561        0)
2562          CMD="./${BIN} ${OPTS} -a 3 -m 6211 ${TDIR}/tc_tests/hashcat_ripemd160_aes.tc hashca?l"
2563          ;;
2564        1)
2565          CMD="./${BIN} ${OPTS} -a 3 -m 6211 ${TDIR}/tc_tests/hashcat_ripemd160_serpent.tc hashca?l"
2566          ;;
2567        2)
2568          CMD="./${BIN} ${OPTS} -a 3 -m 6211 ${TDIR}/tc_tests/hashcat_ripemd160_twofish.tc hashca?l"
2569          ;;
2570      esac
2571      ;;
2572
2573    6212)
2574      case $tcMode in
2575        0)
2576          CMD="./${BIN} ${OPTS} -a 3 -m 6212 ${TDIR}/tc_tests/hashcat_ripemd160_aes-twofish.tc hashca?l"
2577          ;;
2578        1)
2579          CMD="./${BIN} ${OPTS} -a 3 -m 6212 ${TDIR}/tc_tests/hashcat_ripemd160_serpent-aes.tc hashca?l"
2580          ;;
2581        2)
2582          CMD="./${BIN} ${OPTS} -a 3 -m 6212 ${TDIR}/tc_tests/hashcat_ripemd160_twofish-serpent.tc hashca?l"
2583          ;;
2584      esac
2585      ;;
2586
2587    6213)
2588      case $tcMode in
2589        0)
2590          CMD="./${BIN} ${OPTS} -a 3 -m 6213 ${TDIR}/tc_tests/hashcat_ripemd160_aes-twofish-serpent.tc hashca?l"
2591          ;;
2592        1)
2593          CMD="./${BIN} ${OPTS} -a 3 -m 6213 ${TDIR}/tc_tests/hashcat_ripemd160_serpent-twofish-aes.tc hashca?l"
2594          ;;
2595      esac
2596      ;;
2597
2598    6221)
2599      case $tcMode in
2600        0)
2601          CMD="./${BIN} ${OPTS} -a 3 -m 6221 ${TDIR}/tc_tests/hashcat_sha512_aes.tc hashca?l"
2602          ;;
2603        1)
2604          CMD="./${BIN} ${OPTS} -a 3 -m 6221 ${TDIR}/tc_tests/hashcat_sha512_serpent.tc hashca?l"
2605          ;;
2606        2)
2607          CMD="./${BIN} ${OPTS} -a 3 -m 6221 ${TDIR}/tc_tests/hashcat_sha512_twofish.tc hashca?l"
2608          ;;
2609      esac
2610      ;;
2611
2612    6222)
2613      case $tcMode in
2614        0)
2615          CMD="./${BIN} ${OPTS} -a 3 -m 6222 ${TDIR}/tc_tests/hashcat_sha512_aes-twofish.tc hashca?l"
2616          ;;
2617        1)
2618          CMD="./${BIN} ${OPTS} -a 3 -m 6222 ${TDIR}/tc_tests/hashcat_sha512_serpent-aes.tc hashca?l"
2619          ;;
2620        2)
2621          CMD="./${BIN} ${OPTS} -a 3 -m 6222 ${TDIR}/tc_tests/hashcat_sha512_twofish-serpent.tc hashca?l"
2622          ;;
2623      esac
2624      ;;
2625
2626    6223)
2627      case $tcMode in
2628        0)
2629          CMD="./${BIN} ${OPTS} -a 3 -m 6223 ${TDIR}/tc_tests/hashcat_sha512_aes-twofish-serpent.tc hashca?l"
2630          ;;
2631        1)
2632          CMD="./${BIN} ${OPTS} -a 3 -m 6223 ${TDIR}/tc_tests/hashcat_sha512_serpent-twofish-aes.tc hashca?l"
2633          ;;
2634      esac
2635      ;;
2636
2637    6231)
2638      case $tcMode in
2639        0)
2640          CMD="./${BIN} ${OPTS} -a 3 -m 6231 ${TDIR}/tc_tests/hashcat_whirlpool_aes.tc hashca?l"
2641          ;;
2642        1)
2643          CMD="./${BIN} ${OPTS} -a 3 -m 6231 ${TDIR}/tc_tests/hashcat_whirlpool_serpent.tc hashca?l"
2644          ;;
2645        2)
2646          CMD="./${BIN} ${OPTS} -a 3 -m 6231 ${TDIR}/tc_tests/hashcat_whirlpool_twofish.tc hashca?l"
2647          ;;
2648      esac
2649      ;;
2650
2651    6232)
2652      case $tcMode in
2653        0)
2654          CMD="./${BIN} ${OPTS} -a 3 -m 6232 ${TDIR}/tc_tests/hashcat_whirlpool_aes-twofish.tc hashca?l"
2655          ;;
2656        1)
2657          CMD="./${BIN} ${OPTS} -a 3 -m 6232 ${TDIR}/tc_tests/hashcat_whirlpool_serpent-aes.tc hashca?l"
2658          ;;
2659        2)
2660          CMD="./${BIN} ${OPTS} -a 3 -m 6232 ${TDIR}/tc_tests/hashcat_whirlpool_twofish-serpent.tc hashca?l"
2661          ;;
2662      esac
2663      ;;
2664
2665    6233)
2666      case $tcMode in
2667        0)
2668          CMD="./${BIN} ${OPTS} -a 3 -m 6233 ${TDIR}/tc_tests/hashcat_whirlpool_aes-twofish-serpent.tc hashca?l"
2669          ;;
2670        1)
2671          CMD="./${BIN} ${OPTS} -a 3 -m 6233 ${TDIR}/tc_tests/hashcat_whirlpool_serpent-twofish-aes.tc hashca?l"
2672          ;;
2673      esac
2674      ;;
2675
2676    6241)
2677      case $tcMode in
2678        0)
2679          CMD="./${BIN} ${OPTS} -a 3 -m 6241 ${TDIR}/tc_tests/hashcat_ripemd160_aes_boot.tc hashca?l"
2680          ;;
2681        1)
2682          CMD="./${BIN} ${OPTS} -a 3 -m 6241 ${TDIR}/tc_tests/hashcat_ripemd160_serpent_boot.tc hashca?l"
2683          ;;
2684        2)
2685          CMD="./${BIN} ${OPTS} -a 3 -m 6241 ${TDIR}/tc_tests/hashcat_ripemd160_twofish_boot.tc hashca?l"
2686          ;;
2687      esac
2688      ;;
2689
2690    6242)
2691      case $tcMode in
2692        0)
2693          CMD="./${BIN} ${OPTS} -a 3 -m 6242 ${TDIR}/tc_tests/hashcat_ripemd160_aes-twofish_boot.tc hashca?l"
2694          ;;
2695        1)
2696          CMD="./${BIN} ${OPTS} -a 3 -m 6242 ${TDIR}/tc_tests/hashcat_ripemd160_serpent-aes_boot.tc hashca?l"
2697          ;;
2698      esac
2699      ;;
2700
2701    6243)
2702      case $tcMode in
2703        0)
2704          CMD="./${BIN} ${OPTS} -a 3 -m 6243 ${TDIR}/tc_tests/hashcat_ripemd160_aes-twofish-serpent_boot.tc hashca?l"
2705          ;;
2706      esac
2707      ;;
2708  esac
2709
2710  if [ ${#CMD} -gt 5 ]; then
2711    echo "> Testing hash type $hashType with attack mode 3, markov ${MARKOV}, single hash, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR}, tcMode ${tcMode}" >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
2712
2713    output=$(${CMD} 2>&1)
2714
2715    ret=${?}
2716
2717    echo "${output}" >> "${OUTD}/logfull.txt"
2718
2719    cnt=1
2720    e_nf=0
2721    msg="OK"
2722
2723    if [ ${ret} -ne 0 ]; then
2724      e_nf=1
2725      msg="Error"
2726    fi
2727
2728    echo "[ ${OUTD} ] [ Type ${hash_type}, Attack 3, Mode single, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR}, tcMode ${tcMode} ] > $msg : ${e_nf}/${cnt} not found"
2729
2730    status ${ret}
2731  fi
2732}
2733
2734# Compose and execute hashcat command on a VeraCrypt test container
2735# Must not be called for hash types other than 137XY
2736# $1: cipher variation, can be 0-6
2737function veracrypt_test()
2738{
2739  cipher_variation=$1
2740
2741  hash_function=""
2742
2743  hash_digit="${hash_type:3:1}"
2744  [ "$hash_digit" -eq "1" ] && hash_function="ripemd160"
2745  [ "$hash_digit" -eq "2" ] && hash_function="sha512"
2746  [ "$hash_digit" -eq "3" ] && hash_function="whirlpool"
2747  [ "$hash_digit" -eq "5" ] && hash_function="sha256"
2748  [ "$hash_digit" -eq "7" ] && hash_function="streebog"
2749
2750  [ -n "$hash_function" ] || return
2751
2752  cipher_cascade=""
2753
2754  cipher_digit="${hash_type:4:1}"
2755  case $cipher_digit in
2756    1)
2757      [ "$cipher_variation" -eq "0" ] && cipher_cascade="aes"
2758      [ "$cipher_variation" -eq "1" ] && cipher_cascade="serpent"
2759      [ "$cipher_variation" -eq "2" ] && cipher_cascade="twofish"
2760      [ "$cipher_variation" -eq "3" ] && cipher_cascade="camellia"
2761      [ "$cipher_variation" -eq "5" ] && cipher_cascade="kuznyechik"
2762      ;;
2763    2)
2764      [ "$cipher_variation" -eq "0" ] && cipher_cascade="aes-twofish"
2765      [ "$cipher_variation" -eq "1" ] && cipher_cascade="serpent-aes"
2766      [ "$cipher_variation" -eq "2" ] && cipher_cascade="twofish-serpent"
2767      [ "$cipher_variation" -eq "3" ] && cipher_cascade="camellia-kuznyechik"
2768      [ "$cipher_variation" -eq "4" ] && cipher_cascade="camellia-serpent"
2769      [ "$cipher_variation" -eq "5" ] && cipher_cascade="kuznyechik-aes"
2770      [ "$cipher_variation" -eq "6" ] && cipher_cascade="kuznyechik-twofish"
2771      ;;
2772    3)
2773      [ "$cipher_variation" -eq "0" ] && cipher_cascade="aes-twofish-serpent"
2774      [ "$cipher_variation" -eq "1" ] && cipher_cascade="serpent-twofish-aes"
2775      [ "$cipher_variation" -eq "5" ] && cipher_cascade="kuznyechik-serpent-camellia"
2776      ;;
2777  esac
2778
2779  [ -n "$cipher_cascade" ] || return
2780
2781  filename="${TDIR}/vc_tests/hashcat_${hash_function}_${cipher_cascade}.vc"
2782
2783  # The hash-cipher combination might be invalid (e.g. RIPEMD-160 + Kuznyechik)
2784  [ -f "${filename}" ] || return
2785
2786  CMD="./${BIN} ${OPTS} -a 3 -m ${hash_type} ${filename} hashc?lt"
2787
2788  echo "> Testing hash type ${hash_type} with attack mode 0, markov ${MARKOV}, single hash, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR}, Cipher ${cipher_cascade}" >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
2789
2790  output=$(${CMD} 2>&1)
2791
2792  ret=${?}
2793
2794  echo "${output}" >> "${OUTD}/logfull.txt"
2795
2796  cnt=1
2797  e_nf=0
2798  msg="OK"
2799
2800  if [ ${ret} -ne 0 ]; then
2801    e_nf=1
2802    msg="Error"
2803  fi
2804
2805  echo "[ ${OUTD} ] [ Type ${hash_type}, Attack 0, Mode single, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR}, Cipher ${cipher_cascade} ] > $msg : ${e_nf}/${cnt} not found"
2806
2807  status ${ret}
2808}
2809
2810function luks_test()
2811{
2812  hashType=$1
2813  attackType=$2
2814
2815  # if -m all was set let us default to -a 3 only. You could specify the attack type directly, e.g. -m 0
2816  # the problem with defaulting to all=0,1,3,6,7 is that it could take way too long
2817
2818  if [ "${attackType}" -eq 65535 ]; then
2819    attackType=3
2820  fi
2821
2822  #LUKS_HASHES="sha1 sha256 sha512 ripemd160 whirlpool"
2823  LUKS_HASHES="sha1 sha256 sha512 ripemd160"
2824  LUKS_CIPHERS="aes serpent twofish"
2825  LUKS_MODES="cbc-essiv cbc-plain64 xts-plain64"
2826  LUKS_KEYSIZES="128 256 512"
2827
2828  LUKS_PASSWORD=$(cat "${TDIR}/luks_tests/pw")
2829
2830  for luks_h in ${LUKS_HASHES}; do
2831    for luks_c in ${LUKS_CIPHERS}; do
2832      for luks_m in ${LUKS_MODES}; do
2833        for luks_k in ${LUKS_KEYSIZES}; do
2834
2835          CMD=""
2836
2837          # filter out not supported combinations:
2838
2839          case "${luks_k}" in
2840            128)
2841              case "${luks_m}" in
2842                cbc-essiv|cbc-plain64)
2843                ;;
2844                *)
2845                  continue
2846                ;;
2847              esac
2848            ;;
2849            256)
2850              case "${luks_m}" in
2851                cbc-essiv|cbc-plain64|xts-plain64)
2852                ;;
2853                *)
2854                  continue
2855                ;;
2856              esac
2857            ;;
2858            512)
2859              case "${luks_m}" in
2860                xts-plain64)
2861                ;;
2862                *)
2863                  continue
2864                ;;
2865              esac
2866            ;;
2867          esac
2868
2869          luks_mode="${luks_h}-${luks_c}-${luks_m}-${luks_k}"
2870          luks_file="${TDIR}/luks_tests/hashcat_${luks_h}_${luks_c}_${luks_m}_${luks_k}.luks"
2871          luks_main_mask="?l"
2872          luks_mask="${luks_main_mask}"
2873
2874          # for combination or hybrid attacks
2875          luks_pass_part_file1="${OUTD}/${hashType}_dict1"
2876          luks_pass_part_file2="${OUTD}/${hashType}_dict2"
2877
2878          case $attackType in
2879            0)
2880              CMD="./${BIN} ${OPTS} -a 0 -m ${hashType} ${luks_file} ${TDIR}/luks_tests/pw"
2881              ;;
2882            1)
2883              luks_pass_part1_len=$((${#LUKS_PASSWORD} / 2))
2884              luks_pass_part2_start=$((luks_pass_part1_len + 1))
2885
2886              echo "${LUKS_PASSWORD}" | cut -c-${luks_pass_part1_len} > "${luks_pass_part_file1}"
2887              echo "${LUKS_PASSWORD}" | cut -c${luks_pass_part2_start}- > "${luks_pass_part_file2}"
2888
2889              CMD="./${BIN} ${OPTS} -a 6 -m ${hashType} ${luks_file} ${luks_pass_part_file1} ${luks_pass_part_file2}"
2890              ;;
2891            3)
2892              luks_mask_fixed_len=$((${#LUKS_PASSWORD} - 1))
2893
2894              luks_mask="$(echo "${LUKS_PASSWORD}" | cut -c-${luks_mask_fixed_len})"
2895              luks_mask="${luks_mask}${luks_main_mask}"
2896
2897              CMD="./${BIN} ${OPTS} -a 3 -m ${hashType} ${luks_file} ${luks_mask}"
2898              ;;
2899            6)
2900              luks_pass_part1_len=$((${#LUKS_PASSWORD} - 1))
2901
2902              echo "${LUKS_PASSWORD}" | cut -c-${luks_pass_part1_len} > "${luks_pass_part_file1}"
2903
2904              CMD="./${BIN} ${OPTS} -a 6 -m ${hashType} ${luks_file} ${luks_pass_part_file1} ${luks_mask}"
2905              ;;
2906            7)
2907              echo "${LUKS_PASSWORD}" | cut -c2- > "${luks_pass_part_file1}"
2908
2909              CMD="./${BIN} ${OPTS} -a 7 -m ${hashType} ${luks_file} ${luks_mask} ${luks_pass_part_file1}"
2910              ;;
2911          esac
2912
2913          if [ -n "${CMD}" ]; then
2914            echo "> Testing hash type ${hashType} with attack mode ${attackType}, markov ${MARKOV}, single hash, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR}, luksMode ${luks_mode}" >> "${OUTD}/logfull.txt" 2>> "${OUTD}/logfull.txt"
2915
2916            output=$(${CMD} 2>&1)
2917            ret=${?}
2918
2919            echo "${output}" >> "${OUTD}/logfull.txt"
2920
2921            cnt=1
2922            e_nf=0
2923            msg="OK"
2924
2925            if [ ${ret} -ne 0 ]; then
2926              e_nf=1
2927              msg="Error"
2928            fi
2929
2930            echo "[ ${OUTD} ] [ Type ${hash_type}, Attack ${attackType}, Mode single, Device-Type ${TYPE}, Kernel-Type ${KERNEL_TYPE}, Vector-Width ${VECTOR}, luksMode ${luks_mode} ] > $msg : ${e_nf}/${cnt} not found"
2931
2932            status ${ret}
2933          fi
2934        done
2935      done
2936    done
2937  done
2938}
2939
2940function usage()
2941{
2942cat << EOF
2943> Usage : ${0} <options>
2944
2945OPTIONS:
2946
2947  -V    Backend vector-width (either 1, 2, 4 or 8), overrides value from device query :
2948        '1'         => vector-width 1
2949        '2'         => vector-width 2 (default)
2950        '4'         => vector-width 4
2951        '8'         => vector-width 8
2952        'all'       => test sequentially vector-width ${VECTOR_WIDTHS}
2953
2954  -t    Select test mode :
2955        'single'    => single hash (default)
2956        'multi'     => multi hash
2957        'all'       => single and multi hash
2958
2959  -m    Select hash type :
2960        'all'       => all hash type supported
2961        (int)       => hash type integer code (default : 0)
2962        (int)-(int) => hash type integer range
2963
2964  -a    Select attack mode :
2965        'all'       => all attack modes
2966        (int)       => attack mode integer code (default : 0)
2967
2968  -x    Select cpu architecture :
2969        '32'        => 32 bit architecture
2970        '64'        => 64 bit architecture (default)
2971
2972  -o    Select operating system :
2973        'win'       => Windows operating system (use .exe file extension)
2974        'linux'     => Linux operating system (use .bin file extension)
2975        'macos'     => macOS operating system (use .app file extension)
2976
2977  -d    Select the Backend device :
2978        (int)[,int] => comma separated list of devices (default : 1)
2979
2980  -D    Select the OpenCL device types :
2981        '1'         => CPU
2982        '2'         => GPU (default)
2983        '3'         => FPGA, DSP, Co-Processor
2984        (int)[,int] => multiple comma separated device types from the list above
2985
2986  -O    Use optimized kernels (default : -O)
2987
2988  -P    Use pure kernels instead of optimized kernels (default : -O)
2989
2990  -s    Use this session name instead of the default one (default : "hashcat")
2991
2992  -c    Disables markov-chains
2993
2994  -p    Package the tests into a .7z file
2995
2996  -F    Use this folder as test folder instead of the default one
2997        (string)    => path to folder
2998
2999  -I    Use this folder as input/output folder for packaged tests
3000        (string)    => path to folder
3001
3002  -h    Show this help
3003
3004EOF
3005
3006  exit 1
3007}
3008
3009BIN="hashcat"
3010MARKOV="enabled"
3011ATTACK=0
3012MODE=0
3013TYPE="null"
3014KERNEL_TYPE="Optimized"
3015VECTOR="default"
3016HT=0
3017PACKAGE=0
3018OPTIMIZED=1
3019
3020while getopts "V:t:m:a:b:hcpd:x:o:d:D:F:POI:s:" opt; do
3021
3022  case ${opt} in
3023    "V")
3024      if [ "${OPTARG}" = "1" ]; then
3025        VECTOR=1
3026      elif [ "${OPTARG}" = "2" ]; then
3027        VECTOR=2
3028      elif [ "${OPTARG}" = "4" ]; then
3029        VECTOR=4
3030      elif [ "${OPTARG}" = "8" ]; then
3031        VECTOR=8
3032      elif [ "${OPTARG}" = "16" ]; then
3033        VECTOR=16
3034      elif [ "${OPTARG}" = "all" ]; then
3035        VECTOR="all"
3036      else
3037        usage
3038      fi
3039      ;;
3040
3041    "t")
3042      if [ "${OPTARG}" = "single" ]; then
3043        MODE=0
3044      elif [ "${OPTARG}" = "multi" ]; then
3045        MODE=1
3046      elif [ "${OPTARG}" = "all" ]; then
3047        MODE=2
3048      else
3049        usage
3050      fi
3051      ;;
3052
3053    "m")
3054      if [ "${OPTARG}" = "all" ]; then
3055        HT=65535
3056      else
3057        HT=${OPTARG}
3058      fi
3059      ;;
3060
3061    "a")
3062      if [ "${OPTARG}" = "all" ]; then
3063        ATTACK=65535
3064      elif [ "${OPTARG}" = "0" ]; then
3065        ATTACK=0
3066      elif [ "${OPTARG}" = "1" ]; then
3067        ATTACK=1
3068      elif [ "${OPTARG}" = "3" ]; then
3069        ATTACK=3
3070      elif [ "${OPTARG}" = "6" ]; then
3071        ATTACK=6
3072      elif [ "${OPTARG}" = "7" ]; then
3073        ATTACK=7
3074      else
3075        usage
3076      fi
3077      ;;
3078
3079    "c")
3080      OPTS="${OPTS} --markov-disable"
3081      MARKOV="disabled"
3082      ;;
3083
3084    "I")
3085      PACKAGE_FOLDER=$( echo "${OPTARG}" | sed 's!/$!!g' )
3086      ;;
3087
3088    "s")
3089      OPTS="${OPTS} --session \"${OPTARG}\""
3090      ;;
3091
3092    "p")
3093      PACKAGE=1
3094      ;;
3095
3096    "x")
3097      if [ "${OPTARG}" = "32" ]; then
3098        ARCHITECTURE=32
3099      elif [ "${OPTARG}" = "64" ]; then
3100        ARCHITECTURE=64
3101      else
3102        usage
3103      fi
3104      ;;
3105
3106    "o")
3107      if [ "${OPTARG}" = "win" ]; then
3108        EXTENSION="exe"
3109      elif [ "${OPTARG}" = "linux" ]; then
3110        EXTENSION="bin"
3111      elif [ "${OPTARG}" = "macos" ]; then
3112        EXTENSION="app"
3113      else
3114        usage
3115      fi
3116      ;;
3117
3118    "O")
3119        # optimized is already default, ignore it
3120      ;;
3121
3122    "d")
3123        OPTS="${OPTS} -d ${OPTARG}"
3124      ;;
3125
3126    "D")
3127      if [ "${OPTARG}" = "1" ]; then
3128        OPTS="${OPTS} -D 1"
3129        TYPE="Cpu"
3130      elif [ "${OPTARG}" = "2" ]; then
3131        OPTS="${OPTS} -D 2"
3132        TYPE="Gpu"
3133      else
3134        OPTS="${OPTS} -D ${OPTARG}"
3135        TYPE="Cpu + Gpu"
3136      fi
3137      ;;
3138
3139    "F")
3140        OUTD=$( echo "${OPTARG}" | sed 's!/$!!g' )
3141      ;;
3142
3143    "P")
3144        OPTIMIZED=0
3145        KERNEL_TYPE="Pure"
3146      ;;
3147
3148    \?)
3149      usage
3150      ;;
3151
3152    "h")
3153      usage
3154      ;;
3155  esac
3156
3157done
3158
3159export IS_OPTIMIZED=${OPTIMIZED}
3160
3161if [ "${OPTIMIZED}" -eq 1 ]; then
3162  OPTS="${OPTS} -O"
3163fi
3164
3165if [ "${TYPE}" = "null" ]; then
3166  OPTS="${OPTS} -D 2"
3167  TYPE="Gpu"
3168fi
3169
3170if [ -n "${ARCHITECTURE}" ]; then
3171
3172  BIN="${BIN}${ARCHITECTURE}"
3173
3174fi
3175
3176if [ -n "${EXTENSION}" ]; then
3177
3178  BIN="${BIN}.${EXTENSION}"
3179
3180fi
3181
3182if [ -n "${PACKAGE_FOLDER}" ]; then
3183
3184  if [ ! -e "${PACKAGE_FOLDER}" ]; then
3185    echo "! folder '${PACKAGE_FOLDER}' does not exist"
3186    exit 1
3187  fi
3188
3189fi
3190
3191if [ "${PACKAGE}" -eq 0 ] || [ -z "${PACKAGE_FOLDER}" ]; then
3192
3193  # check existence of binary
3194  if [ ! -e "${BIN}" ]; then
3195    echo "! ${BIN} not found, please build binary before run test."
3196    exit 1
3197  fi
3198
3199  HT_MIN=0
3200  HT_MAX=0
3201
3202  if echo -n "${HT}" | grep -q '^[0-9]\+$'; then
3203    HT_MIN=${HT}
3204    HT_MAX=${HT}
3205  elif echo -n "${HT}" | grep -q '^[0-9]\+-[1-9][0-9]*$'; then
3206
3207    HT_MIN=$(echo -n ${HT} | sed "s/-.*//")
3208    HT_MAX=$(echo -n ${HT} | sed "s/.*-//")
3209
3210    if [ "${HT_MIN}" -gt "${HT_MAX}" ]; then
3211      echo "! hash type range -m ${HT} is not valid ..."
3212      usage
3213    fi
3214  else
3215    echo "! hash type is not a number ..."
3216    usage
3217  fi
3218
3219  HT=${HT_MIN}
3220
3221  # filter by hash_type
3222  if [ "${HT}" -ne 65535 ]; then
3223
3224    # validate filter
3225
3226    if ! is_in_array "${HT_MIN}" ${HASH_TYPES}; then
3227      echo "! invalid hash type selected ..."
3228      usage
3229    fi
3230
3231    if ! is_in_array "${HT_MAX}" ${HASH_TYPES}; then
3232      echo "! invalid hash type selected ..."
3233      usage
3234    fi
3235  fi
3236
3237  if [ -z "${PACKAGE_FOLDER}" ]; then
3238
3239    # make new dir
3240    mkdir -p "${OUTD}"
3241
3242    # generate random test entry
3243    if [ "${HT}" -eq 65535 ]; then
3244      for TMP_HT in ${HASH_TYPES}; do
3245        if [ "${TMP_HT}" -ne ${LUKS_MODE} ]; then
3246          if ! is_in_array "${TMP_HT}" ${TC_MODES}; then
3247            if ! is_in_array "${TMP_HT}" ${VC_MODES}; then
3248              if ! is_in_array "${TMP_HT}" ${CL_MODES}; then
3249                perl tools/test.pl single "${TMP_HT}" >> "${OUTD}/all.sh"
3250              fi
3251            fi
3252          fi
3253        fi
3254      done
3255    else
3256      for TMP_HT in $(seq "${HT_MIN}" "${HT_MAX}"); do
3257        if ! is_in_array "${TMP_HT}" ${HASH_TYPES}; then
3258          continue
3259        fi
3260
3261        if [ "${TMP_HT}" -ne ${LUKS_MODE} ]; then
3262          # Exclude TrueCrypt and VeraCrypt testing modes
3263          if ! is_in_array "${TMP_HT}" ${TC_MODES}; then
3264            if ! is_in_array "${TMP_HT}" ${VC_MODES}; then
3265              if ! is_in_array "${TMP_HT}" ${CL_MODES}; then
3266                perl tools/test.pl single "${TMP_HT}" >> "${OUTD}/all.sh"
3267              fi
3268            fi
3269          fi
3270        fi
3271      done
3272    fi
3273
3274  else
3275
3276    OUTD=${PACKAGE_FOLDER}
3277
3278  fi
3279
3280  rm -rf "${OUTD}/logfull.txt" && touch "${OUTD}/logfull.txt"
3281
3282  # populate array of hash types where we only should check if pass is in output (not both hash:pass)
3283  IFS=';' read -ra PASS_ONLY <<< "${HASHFILE_ONLY} ${NOCHECK_ENCODING}"
3284  IFS=';' read -ra TIMEOUT_ALGOS <<< "${SLOW_ALGOS}"
3285
3286  IFS=';' read -ra NEVER_CRACK_ALGOS <<< "${NEVER_CRACK}"
3287
3288  # for these particular algos we need to save the output to a temporary file
3289  IFS=';' read -ra FILE_BASED_ALGOS <<< "${HASHFILE_ONLY}"
3290
3291  for hash_type in $HASH_TYPES; do
3292
3293    if [ "${HT}" -ne 65535 ]; then
3294
3295      # check if the loop variable "hash_type" is between HT_MIN and HT_MAX (both included)
3296
3297      if   [ "${hash_type}" -lt "${HT_MIN}" ]; then
3298        continue
3299      elif [ "${hash_type}" -gt "${HT_MAX}" ]; then
3300        # we are done because hash_type is larger than range:
3301        break
3302      fi
3303    fi
3304
3305    if [ "${hash_type}" -eq 20510 ]; then # special case for PKZIP Master Key
3306      if [ "${MODE}" -eq 1 ]; then # if "multi" was forced we need to skip it
3307        if [ "${HT_MIN}" -eq 20510 ]; then
3308          if [ "${HT_MAX}" -eq 20510 ]; then
3309            echo "ERROR: -m 20510 = PKZIP Master Key can only be run with a single hash"
3310          fi
3311        fi
3312
3313        continue
3314      fi
3315    fi
3316
3317    if [ -z "${PACKAGE_FOLDER}" ]; then
3318
3319      # init test data
3320      init
3321
3322    else
3323
3324      echo "[ ${OUTD} ] > Run packaged test for hash type $hash_type."
3325
3326    fi
3327
3328    if [ "${PACKAGE}" -eq 0 ]; then
3329
3330      # should we check only the pass?
3331      pass_only=0
3332      is_in_array "${hash_type}"  ${PASS_ONLY} && pass_only=1
3333
3334      IS_SLOW=0
3335      is_in_array "${hash_type}" ${SLOW_ALGOS} && IS_SLOW=1
3336
3337      # we use phpass as slow hash for testing the AMP kernel
3338      [ "${hash_type}" -eq 400 ] && IS_SLOW=0
3339
3340      OPTS_OLD=${OPTS}
3341      VECTOR_OLD=${VECTOR}
3342      MODE_OLD=${MODE}
3343
3344      if [ "${hash_type}" -eq 20510 ]; then # special case for PKZIP Master Key
3345        if [ "${MODE}" -eq 1 ]; then # if "multi" was forced we need to skip it
3346          continue
3347        fi
3348
3349        MODE=0 # force single only
3350      fi
3351
3352      for CUR_WIDTH in $VECTOR_WIDTHS; do
3353
3354        if [ "${VECTOR_OLD}" = "all" ] || [ "${VECTOR_OLD}" = "default" ] || [ "${VECTOR_OLD}" = "${CUR_WIDTH}" ]; then
3355
3356          if [ "${VECTOR_OLD}" = "default" ] && \
3357             [ "${CUR_WIDTH}" != "1" ] && \
3358             [ "${CUR_WIDTH}" != "4" ]; then
3359
3360             continue
3361          fi
3362
3363          VECTOR=${CUR_WIDTH}
3364          OPTS="${OPTS_OLD} --backend-vector-width ${VECTOR}"
3365
3366          if [ ${IS_SLOW} -eq 1 ]; then
3367
3368            # Look up if this is one of supported VeraCrypt modes
3369            if is_in_array "${hash_type}" ${VC_MODES}; then
3370              veracrypt_test 0 # aes
3371              veracrypt_test 1 # serpent
3372              veracrypt_test 2 # twofish
3373              veracrypt_test 3 # camellia
3374              veracrypt_test 4 # camellia (alternative cascade)
3375              veracrypt_test 5 # kuznyechik
3376              veracrypt_test 6 # kuznyechik (alternative cascade)
3377            elif is_in_array "${hash_type}" ${TC_MODES}; then
3378              # run truecrypt tests
3379              truecrypt_test "${hash_type}" 0
3380              truecrypt_test "${hash_type}" 1
3381              truecrypt_test "${hash_type}" 2
3382            elif [ "${hash_type}" -eq ${LUKS_MODE} ]; then
3383              # run luks tests
3384              luks_test "${hash_type}" ${ATTACK}
3385            else
3386              # run attack mode 0 (stdin)
3387              if [ ${ATTACK} -eq 65535 ] || [ ${ATTACK} -eq 0 ]; then attack_0; fi
3388            fi
3389
3390          else
3391
3392            if is_in_array "${hash_type}" ${CL_MODES}; then
3393              # run cryptoloop tests
3394              cryptoloop_test "${hash_type}" 128
3395              cryptoloop_test "${hash_type}" 192
3396              cryptoloop_test "${hash_type}" 256
3397            else
3398              # run attack mode 0 (stdin)
3399              if [ ${ATTACK} -eq 65535 ] || [ ${ATTACK} -eq 0 ]; then attack_0; fi
3400
3401              # run attack mode 1 (combinator)
3402              if [ ${ATTACK} -eq 65535 ] || [ ${ATTACK} -eq 1 ]; then attack_1; fi
3403
3404              # run attack mode 3 (bruteforce)
3405              if [ ${ATTACK} -eq 65535 ] || [ ${ATTACK} -eq 3 ]; then attack_3; fi
3406
3407              # run attack mode 6 (dict+mask)
3408              if [ ${ATTACK} -eq 65535 ] || [ ${ATTACK} -eq 6 ]; then attack_6; fi
3409
3410              # run attack mode 7 (mask+dict)
3411              if [ ${ATTACK} -eq 65535 ] || [ ${ATTACK} -eq 7 ]; then attack_7; fi
3412            fi
3413
3414          fi
3415        fi
3416      done
3417      OPTS="${OPTS_OLD}"
3418      VECTOR="${VECTOR_OLD}"
3419      MODE=${MODE_OLD}
3420    fi
3421  done
3422
3423else
3424
3425  OUTD=${PACKAGE_FOLDER}
3426
3427fi
3428
3429# fix logfile
3430if [ "${PACKAGE}" -eq 0 ]; then
3431  cat -vet "${OUTD}/logfull.txt" | sed -e 's/\^M                                             \^M//g' | sed -e 's/\$$//g' > "${OUTD}/test_report.log"
3432fi
3433
3434rm -rf "${OUTD}/logfull.txt"
3435
3436if [ "${PACKAGE}" -eq 1 ]; then
3437
3438  echo "[ ${OUTD} ] > Generate package ${OUTD}/${OUTD}.7z"
3439
3440  cp "${BASH_SOURCE[0]}" "${OUTD}/test.sh"
3441
3442  copy_luks_dir=0
3443  copy_tc_dir=0
3444  copy_vc_dir=0
3445  copy_cl_dir=0
3446
3447  if [ "${HT}" -eq 65535 ]; then
3448    copy_luks_dir=1
3449    copy_tc_dir=1
3450    copy_vc_dir=1
3451    copy_cl_dir=1
3452  else
3453    for TMP_HT in $(seq "${HT_MIN}" "${HT_MAX}"); do
3454      if [ "${TMP_HT}" -eq "${LUKS_MODE}" ]; then
3455        copy_luks_dir=1
3456      elif is_in_array "${TMP_HT}" ${TC_MODES}; then
3457        copy_tc_dir=1
3458      elif is_in_array "${TMP_HT}" ${VC_MODES}; then
3459        copy_vc_dir=1
3460      elif is_in_array "${TMP_HT}" ${CL_MODES}; then
3461        copy_cl_dir=1
3462      fi
3463    done
3464  fi
3465
3466  if [ "${copy_luks_dir}" -eq 1 ]; then
3467    mkdir "${OUTD}/luks_tests/"
3468    cp ${TDIR}/luks_tests/* "${OUTD}/luks_tests/"
3469  fi
3470
3471  if [ "${copy_tc_dir}" -eq 1 ]; then
3472    mkdir "${OUTD}/tc_tests/"
3473    cp ${TDIR}/tc_tests/* "${OUTD}/tc_tests/"
3474  fi
3475
3476  if [ "${copy_vc_dir}" -eq 1 ]; then
3477    mkdir "${OUTD}/vc_tests/"
3478    cp ${TDIR}/vc_tests/* "${OUTD}/vc_tests/"
3479  fi
3480
3481  if [ "${copy_cl_dir}" -eq 1 ]; then
3482    mkdir "${OUTD}/cl_tests/"
3483    cp ${TDIR}/cl_tests/* "${OUTD}/cl_tests/"
3484  fi
3485
3486  # if we package from a given folder, we need to check if e.g. the files needed for multi mode are there
3487
3488  if [ -n "${PACKAGE_FOLDER}" ]; then
3489
3490    MODE=2
3491
3492    ls "${PACKAGE_FOLDER}"/*multi* >/dev/null 2>/dev/null
3493
3494    if [ "${?}" -ne 0 ]
3495    then
3496
3497      MODE=0
3498
3499    fi
3500
3501    HT=$(grep -o -- "-m  *[0-9]*" "${PACKAGE_FOLDER}/all.sh" | sort -u | sed 's/-m  //' 2> /dev/null)
3502
3503    if [ -n "${HT}" ]; then
3504
3505      HT_COUNT=$(echo "${HT}" | wc -l)
3506
3507      if [ "${HT_COUNT}" -gt 1 ]; then
3508
3509        HT=65535
3510
3511      fi
3512
3513    fi
3514
3515    #ATTACK=65535 # more appropriate ?
3516  fi
3517
3518  # for convenience: 'run package' is default action for packaged test.sh ( + add other defaults too )
3519
3520  SED_IN_PLACE='-i'
3521
3522  UNAME=$(uname -s)
3523
3524  # of course macOS requires us to implement a special case (sed -i "" for the backup file)
3525  if [ "${UNAME}" = "Darwin" ] ; then
3526    SED_IN_PLACE='-i ""'
3527  fi
3528
3529  HT_PACKAGED=${HT}
3530
3531  if [ "${HT_MIN}" -ne "${HT_MAX}" ]; then
3532    HT_PACKAGED=${HT_MIN}-${HT_MAX}
3533  fi
3534
3535  HASH_TYPES_PACKAGED=$(   echo "${HASH_TYPES}"    | tr '\n' ' ' | sed 's/ $//')
3536  HASHFILE_ONLY_PACKAGED=$(echo "${HASHFILE_ONLY}" | tr '\n' ' ' | sed 's/ $//')
3537  NEVER_CRACK_PACKAGED=$(  echo "${NEVER_CRACK}"   | tr '\n' ' ' | sed 's/ $//')
3538  SLOW_ALGOS_PACKAGED=$(   echo "${SLOW_ALGOS}"    | tr '\n' ' ' | sed 's/ $//')
3539
3540  sed "${SED_IN_PLACE}" -e 's/^\(PACKAGE_FOLDER\)=""/\1="$( echo "${BASH_SOURCE[0]}" | sed \"s!test.sh\\$!!\" )"/' \
3541    -e "s/^\(HASH_TYPES\)=\$(.*/\1=\"${HASH_TYPES_PACKAGED}\"/" \
3542    -e "s/^\(HASHFILE_ONLY\)=\$(.*/\1=\"${HASHFILE_ONLY_PACKAGED}\"/" \
3543    -e "s/^\(NEVER_CRACK\)=\$(.*/\1=\"${NEVER_CRACK_PACKAGED}\"/" \
3544    -e "s/^\(SLOW_ALGOS\)=\$(.*/\1=\"${SLOW_ALGOS_PACKAGED}\"/" \
3545    -e "s/^\(HT\)=0/\1=${HT_PACKAGED}/" \
3546    -e "s/^\(MODE\)=0/\1=${MODE}/" \
3547    -e "s/^\(ATTACK\)=0/\1=${ATTACK}/" \
3548    "${OUTD}/test.sh"
3549
3550  ${PACKAGE_CMD} "${OUTD}/${OUTD}.7z" "${OUTD}/" >/dev/null 2>/dev/null
3551
3552fi
3553