#!/usr/bin/env bash source bashlib calc() { python -c "import math; print $1"; } scale() { local number=$1 precision=$2 definition unit weight; shift 2 for definition in "$@"; do definition=$definition weight=${definition#*:} [[ ! $weight || $(calc "($number) > ($weight)") = True ]] || break number=$(calc "(1.0 * $number) / (1.0 * ${weight:-1})") unit=${definition%:*} done printf "%'0.${precision}f %s" "$number" "$unit" } scaleTime() { scale "$1" "${2:-2}" 'Seconds:' "Hours:3600" "Days:24" "Months:30" "Years:356/30" "K Years:1000" "M Years:1000" "B Years:1000" "T Years:1000"; } scaleEnergy() { scale "$1" "${2:-2}" 'Wh:' 'kWh:1000' 'MWh:1000' 'GWh:1000' 'TWh:1000'; } scaleCost() { scale "$1" "${2:-2}" '$US:' 'K$US:1000' 'M$US:1000' 'B$US:1000' 'T$US:1000'; } inf 'Calculate the maximum amount of time required to brute-force search for a password.' ## CLASSES V="AEIOU" C="BCDFGHJKLMNPQRSTVWXYZ" v="aeiou" c="bcdfghjklmnpqrstvwxyz" A="$V$C" a="$V$v$C$c" n="0123456789" o="&@%?,=[]_:-+*\$#!'^~;()/." x="$a$n!@#\$%^&*()" w="@words.txt" ## METRICS # Last update: 2016-09 # GTX Titan X -- https://gist.github.com/epixoip/1f26f43e9036d9ce0eb8 #hardwareName='GTX Titan X (SHA1)' hardwareHPS='5302M' hardwareCost='950' hardwareWatt='250' # -mpl: 4.67 m #hardwareName='GTX Titan X (HMAC-SHA-256)' hardwareHPS='2113M' hardwareCost='950' hardwareWatt='250' # -mpl: 0.99 y #hardwareName='GTX Titan X (bcrypt-10)' hardwareHPS='14440/32' hardwareCost='950' hardwareWatt='250' # -mpl: 4.62 My # GTX 980 Ti -- https://gist.github.com/epixoip/d34245293ccecbfcc7c7 #hardwareName='GTX 980 Ti (SHA1)' hardwareHPS='5366M' hardwareCost='450' hardwareWatt='250' # -mpl: 4.61 m #hardwareName='GTX 980 Ti (SHA256)' hardwareHPS='2032M' hardwareCost='450' hardwareWatt='250' # -mpl: 1.03 y #hardwareName='GTX 980 Ti (bcrypt-10)' hardwareHPS='14521/32' hardwareCost='450' hardwareWatt='250' # -mpl: 4.60 My # GTX 1060 -- https://gist.github.com/derpasaurusz/817638385a35026383331b22e6f2d490 #hardwareName='GTX 1060 (SHA1)' hardwareHPS='4218M' hardwareCost='400' hardwareWatt='120' # -mpl: 5.87 m #hardwareName='GTX 1060 (SHA256)' hardwareHPS='1632M' hardwareCost='400' hardwareWatt='120' # -mpl: 1.28 y #hardwareName='GTX 1060 (bcrypt-10)' hardwareHPS='8046/32' hardwareCost='400' hardwareWatt='120' # -mpl: 8.30 My # GTX 1080 Ti -- https://gist.github.com/epixoip/ace60d09981be09544fdd35005051505 #hardwareName='GTX 1080 Ti (SHA1)' hardwareHPS='12696M' hardwareCost='1200' hardwareWatt='250' # -mpl: 1.95 m #hardwareName='GTX 1080 Ti (SHA256)' hardwareHPS='4967M' hardwareCost='1200' hardwareWatt='250' # -mpl: 4.99 m #hardwareName='GTX 1080 Ti (bcrypt-10)' hardwareHPS='23266/32' hardwareCost='1200' hardwareWatt='250' # -mpl: 2.87 My hardwareName='GTX 1080 Ti (mpw?)' hardwareHPS='56*3' hardwareCost='1200' hardwareWatt='250' # -mpl: 2.87 My # ASICs #hardwareName='AntMiner L3+ (scrypt)' hardwareHPS='1M' hardwareCost='2500' hardwareWatt='800' #hardwareName='AntMiner S9 (SHA256)' hardwareHPS='14T' hardwareCost='1288' hardwareWatt='1400' # mpw-bench #hardwareName='2.3 GHz i7, 8GB (MPW)' hardwareHPS=7.46 costPerKWh='0.1' # ~0.1$/kWh hardwareQuantity=$(calc "5000000000 / ($hardwareCost)") second='1' secondsInHour='3600' secondsInDay='3600 * 24' secondsInMonth='3600 * 24 * 30' secondsInYear='3600 * 24 * 356' hardwareHPS=${hardwareHPS//k/000} hardwareHPS=${hardwareHPS//M/000000} hardwareHPS=${hardwareHPS//G/000000000} hardwareHPS=${hardwareHPS//T/000000000000} ## SEARCH SPACE hr inf 'SEARCH SPACE' inf 'You can use the following variables:' for _c in V C v c A a n o x w; do cc=${!_c} if [[ $cc = @* ]]; then file=${cc#@} file=${file/#~\//$HOME\/} if [[ ! -e $file && -e "${BASH_SOURCE%/*}/$file" ]]; then file="${BASH_SOURCE%/*}/$file" fi read cs < <(wc -l < "$file") else cs=${#cc} fi inf '%s: Class contains %d entities: %s' "$_c" "$cs" "$cc" done spaceString=${1:-$(ask -d "x ** 12" "Size of the space?")} case "$spaceString" in -mp*) mpmode=${spaceString#-mp} mpmode=${mpmode:-long} case "$mpmode" in long|l) spaceString='(CvcvnoCvcvCvcv+CvcvCvcvnoCvcv+CvcvCvcvCvcvno+CvccnoCvcvCvcv+CvccCvcvnoCvcv+CvccCvcvCvcvno+CvcvnoCvccCvcv+CvcvCvccnoCvcv+CvcvCvccCvcvno+CvcvnoCvcvCvcc+CvcvCvcvnoCvcc+CvcvCvcvCvccno+CvccnoCvccCvcv+CvccCvccnoCvcv+CvccCvccCvcvno+CvcvnoCvccCvcc+CvcvCvccnoCvcc+CvcvCvccCvccno+CvccnoCvcvCvcc+CvccCvcvnoCvcc+CvccCvcvCvccno)' ;; max|secure|x) spaceString='aonxxxxxxxxxxxxxxxxx+axxxxxxxxxxxxxxxxxon' ;; med|m) spaceString='CvcnoCvc+CvcCvcno' ;; basic|b) spaceString='aaanaaan+aannaaan+aaannaaa' ;; *) ftl 'Unknown mode: %s' "$mpmode" || exit esac ;; -pw*) password=${spaceString#-pw} spaceString= while read -N1 pwchar; do for _c in v c a n x; do cc=${!_c} [[ $cc = *$pwchar* ]] && spaceString+=$_c && break done || spaceString+=" 256 " done <<< "$password" ;; esac spaceSize=$spaceString for _c in V C v c A a n o x w; do cc=${!_c} if [[ $cc = @* ]]; then file=${cc#@} file=${file/#~\//$HOME\/} read cs < <(wc -l < "$file") else cs=${#cc} fi spaceSize=${spaceSize//$_c/ 0$cs } done # Replace sequences of numbers by multiplication of those numbers. Then, pretty-print. spaceSize=$(sed -e 's/\([[:digit:]]\) *\([[:digit:]]\)/\1 * \2/g' -e 's/ 00*\([1-9]\)/ \1/g' <<< "$spaceSize") spaceSize=$(tr -s ' ' <<< "$spaceSize") spaceSize=${spaceSize# } spaceSize=${spaceSize% } inf '' inf "Search space: %s = %s = %'.f possibilities to try (~%.1f bit)." "$spaceString" "$spaceSize" "$(calc "$spaceSize")" "$(bc -l <<< "l($(calc "$spaceSize")) / l(2)")" ## CLUSTER SIZE hr inf 'CLUSTER SIZE' inf "Simulating %s at a rate of about %'.1f attempts per second." "$hardwareName" "$(calc "$hardwareHPS")" cluster=$(ask -d "$hardwareQuantity" "Amount of units?") ## CALCULATE hr inf 'TIMING' inf "Time to search the entire space using %dx %s units (unit rate=%'.1f H/s)" "$cluster" "$hardwareName" "$(calc "$hardwareHPS")" seconds=$(calc "(1.0 * $spaceSize) / (1.0 * $hardwareHPS * $cluster)") inf "Time to crack: %s (ie. %s Seconds)" "$(scale "$seconds" 2 'Seconds:' "Hours:3600" "Days:24" "Months:30" "Years:356/30")" "$seconds" timing() { local title=$1 unit=$2 precision=$3 seconds=$4 time=$(calc "(1.0 * $spaceSize) / (1.0 * $hardwareHPS * $cluster) / ($seconds)") percent=$(calc "(100.0 * $hardwareHPS * $cluster * $seconds) / (1.0 * $spaceSize)") amount=$(calc "$percent / 100.0") if [[ $(calc "$percent < 100") = True ]]; then inf " - %10s: %'0.${precision}f (ie. %0.1f%% / %s)" \ "$title" "$time" "$percent" "$unit" else inf " - %10s: %'0.${precision}f (ie. %0.1fx / %s)" \ "$title" "$time" "$amount" "$unit" fi } timing Seconds s 0 "$second" timing Hours h 2 "$secondsInHour" timing Days d 3 "$secondsInDay" timing Months m 4 "$secondsInMonth" timing Years y 4 "$secondsInYear" hr inf 'COST' inf "Budget required to search the entire space using %dx %s units (unit cost=%s + %s / year => %s annum, %s / HPS)" \ "$cluster" "$hardwareName" "$(scaleCost "$hardwareCost")" "$(scaleCost "1.0 * $hardwareWatt * 356 * 24 * $costPerKWh / 1000")" "$(scaleCost "$hardwareCost + 1.0 * $hardwareWatt * 356 * 24 * $costPerKWh / 1000")" "$(scaleCost "$hardwareCost / (1.0 * $hardwareHPS)")" fixedCost=$(calc "(1.0 * $cluster * $hardwareCost)") energyCost=$(calc "(1.0 * $cluster * $hardwareWatt * $seconds) / 3600") # Wh totalCost=$(calc "1.0 * $fixedCost + ($energyCost * $costPerKWh) / 1000.0") inf "Time cost : %s" "$(scaleTime "$seconds")" inf "Fixed costs: %s" "$(scaleCost "$fixedCost")" inf "Energy cost: %s" "$(scaleEnergy "$energyCost")" inf "Budget cost: %s" "$(scaleCost "$totalCost")"