#!/bin/bash #----------------------------------------------------------------------------- # $Id: validate-hashes.sh,v 1.2 2020/12/03 22:24:34 royce Exp royce $ #----------------------------------------------------------------------------- # TODO # - Add algo name # - Abstract hash type IDs to algo names. Again. :) # - or maybe accept either(!) #----------------------------------------------------------------------------- # Principles and lessons learned #----------------------------------------------------------------------------- set -o pipefail show_usage() { >&2 echo "" >&2 echo "Usage: $0 [source-file] [dest-file] [hashcat-hashmode-id]" >&2 echo "" >&2 echo "hashmode ID is optional if session.cfg is present in the current directory," >&2 echo "or if HASHTYPE is defined in the current environment." >&2 echo "" } #----------------------------------------------------------------------------- if [ -f session.cfg ]; then >&2 echo "In a target directory - loading local session.cfg ..." . session.cfg >/dev/null fi if [ ! -z "$1" ]; then SRC_FILE=$1 else >&2 echo "- Error: no source file specified" show_usage exit 1 fi if [ ! -z "$2" ]; then DEST_FILE=$2 else >&2 echo "- Error: no destination file specified" show_usage exit 1 fi if [ ! -z "$3" ]; then HASHTYPE=$3 # TODO - map to hashtype. else if [ -z "${HASHTYPE}" ]; then >&2 echo "- Error: no algorithm specified - supply on cmdline or add to session.cfg" show_usage exit 1 else >&2 echo "- Hashtype is set to ${HASHTYPE}" fi fi #----------------------------------------------------------------------------- compare_line_counts() { file1=$1 file2=$2 if [ -z "$file1" -o -z "$file2" ]; then >&2 echo "Error - bad params supplied to compare_line_counts" exit 1 fi if [ ! -f ${file1} ]; then >&2 echo "- Error: first file ${file1} does not exist" show_usage return 1 fi if [ ! -f ${file2} ]; then >&2 echo "- Error: second file ${file2} does not exist" show_usage return 1 fi echo "- Comparing line counts: $file1 vs $file2 ..." ls -la $file1 $file2 count_file1=$(wc -l $file1 | cut -d\ -f1) count_file2=$(wc -l $file2 | cut -d\ -f1) echo "- Line counts: $file1 ${count_file1}, $file2 ${count_file2}..." if [ "${count_file1}" == "${count_file2}" ]; then >&2 echo "- Same length for $file1 and $file2: $count_file1" return 0 else >&2 echo "- Different lengths for $file1 ($count_file1) vs $file2: ($count_file2)" return 1 fi } #----------------------------------------------------------------------------- validate_file() { local SRC_FILE=$1 local DEST_FILE=$2 if [ -z "${SRC_FILE}" ]; then >&2 echo "- Error: no SRC_FILE defined" exit 1 fi if [ -z "${DEST_FILE}" ]; then >&2 echo "- Error: no DEST_FILE defined" exit 1 fi if [ ! -f "${SRC_FILE}" ]; then >&2 echo "- Source file ${SRC_FILE} does not exist." show_usage exit 1 fi if [ ! -f "${DEST_FILE}" ]; then >&2 echo "- Validated file ${DEST_FILE} does not exist - will generate." else >&2 echo "- Validated file ${DEST_FILE} exists - analyzing." fi # If datestamps match ... if [ ! "${SRC_FILE}" -nt "${DEST_FILE}" -a ! "${SRC_FILE}" -ot "${DEST_FILE}" ]; then # Assume it's valid. if [ -s ${DEST_FILE} ]; then echo "- Src and its dest ${DEST_FILE} have same datestamp - assuming valid" else # Unless it's empty. echo "- Dest valids file ${DEST_FILE} is empty" fi # Otherwise, analyze more closely. else compare_line_counts ${SRC_FILE} ${DEST_FILE} linecount_is_valid=$? #echo "- Linecount validation: ${linecount_is_valid}" if [ "${SRC_FILE}" -ot "${DEST_FILE}" ]; then echo "- ${SRC_FILE} is OLDER than ${DEST_FILE} - unusual" fi if [ "${SRC_FILE}" -nt "${DEST_FILE}" ]; then echo "- ${SRC_FILE} is newer than ${DEST_FILE}" fi # If valid file doesn't exist, or linecount is wrong ... if [ ! -f "${DEST_FILE}" -o "${linecount_is_valid}" != '0' ]; then # If linecount is wrong, note that first. if [ "${linecount_is_valid}" != '0' ]; then >&2 echo "- Linecounts don't match" else echo "- ${SRC_FILE} and ${DEST_FILE} have identical length - good" fi # Validate. echo "- Validating file ${SRC_FILE} to ${DEST_FILE}, please wait ..." # Revalidate - strip any invalid hashes. # TODO - simplify with "hashcat -a 0 -m -O empty.txt --remove" hashcat --backend-ignore-opencl --session=${SRC_FILE}.validate \ --left ${SRC_FILE} -m ${HASHTYPE} --potfile-path=/dev/null \ | egrep -v ' on line '\ >${DEST_FILE} local HASHCAT_EXIT_CODE=${PIPESTATUS[0]} # Only touch the destination file if hashcat completed successfully. if [ "$HASHCAT_EXIT_CODE" == '1' -o "$HASHCAT_EXIT_CODE" == '0' ]; then touch -r ${SRC_FILE} ${DEST_FILE} fi compare_line_counts ${SRC_FILE} ${DEST_FILE} linecount_is_valid=$? if [ "${linecount_is_valid}" != '0' ]; then >&2 echo " - Warning: linecount is STILL mismatched - corrupt source?" else echo " - Linecount matches now - good" fi fi fi } #----------------------------------------------------------------------------- # Main. validate_file ${SRC_FILE} ${DEST_FILE} echo "" #-----------------------------------------------------------------------------