Bash script failed to Compare SHA-512 salted hashes. Gets wrong output - bash

I was able to fix the error not being able to use * as part of the LIST. However i was not able to compare and get the desired output of the password.
#!/bin/bash
LIST=(W 2 v '*' %)
encr="Cd9AjUI4nGglIcP3MByrZUnu.hHBJc7.eR0o/v0A1gu0/6ztFfBxeJgKTzpgoCLptJS2NnliZLZjO40LUseED/"
salt="8899Uidd"
for i in "${LIST[#]}"
do
for j in "${LIST[#]}"
do
for k in "${LIST[#]}"
do
for l in "${LIST[#]}"
do
for a in "${LIST[#]}"
do
echo -n "$i$j$k$l$a "
test="mkpasswd -m SHA-512 $i$j$k$l$a -s $salt | cut -d"$" -f4"
if [ "$test" == "$encr" ] ; then
echo " Password is: $i$j$k$l$a"
exit
fi
done
done
done
done
done
#error comparing
The Output should be Password is: W2v*%, but it came out as %%%%%

With a little bit of tweaking here and there. Here we have a fixed one :D
Hope its working for you guys as well.
#!/bin/bash
LIST1=(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
LIST2=(0 1 2 3 4 5 6 7 8 9)
LIST3=(a b c d e f g h i j k l m n o p q r s t u v w x y z)
LIST4=("~" "#" "#" "$" "%" "^" "*" "_" "+" "-" "=" "{" "}" "[" "]" "?" ";" ":")
LIST5=("~" "#" "#" "$" "%" "^" "*" "_" "+" "-" "=" "{" "}" "[" "]" "?" ";" ":")
encr="Cd9AjUI4nGglIcP3MByrZUnu.hHBJc7.eR0o/v0A1gu0/6ztFfBxeJgKTzpgoCLptJS2NnliZLZjO40LUseED/"
salt="8899Uidd"
for i in "${LIST1[#]}"
do
for j in "${LIST2[#]}"
do
for k in "${LIST3[#]}"
do
for l in "${LIST4[#]}"
do
for a in "${LIST5[#]}"
do
echo -n "$i$j$k$l$a"
test="$(mkpasswd -m SHA-512 "$i$j$k$l$a" -s $salt | cut -d"$" -f4)"
if [ "$test" == "$encr" ] ; then
echo " Password is: $i$j$k$l$a"
exit
fi
done
done
done
done
done
P.S: I overdid with the list. You can combine the list into one.

Related

How should i shrink my bash script into 5 for loops?

I am trying to shrink bash script so it do not have to rerun the same codes over and over again. but according to some people i can run the line at test dealing with all 4 encryption at 1 go.
help i do not know what do they meant by that.
Code Gore:
#!/bin/bash
LIST1=(K F L W )
LIST2=(8 2 9 2 )
LIST3=(x b s v )
LIST4=("~" "-" "[" "*" )
LIST5=("$" "+" "]" "%" )
encr1=".8742cNKlzqQ8Mgjip/Fg1"
salt1="bCgxj8Yt"
encr2="31HvJ8Iinxk2k"
salt2="31"
encr3="AyPVCzU.ourSwFdL3N6/YP9RRfIwwKZPNrnt0/yn5vB"
salt3="klPjs90j"
encr4="Cd9AjUI4nGglIcP3MByrZUnu.hHBJc7.eR0o/v0A1gu0/6ztFfBxeJgKTzpgoCLptJS2NnliZLZjO40LUseED/"
salt4="8899Uidd"
for i in "${LIST1[#]}"
do
for j in "${LIST2[#]}"
do
for k in "${LIST3[#]}"
do
for l in "${LIST4[#]}"
do
for a in "${LIST5[#]}"
do
test="$(mkpasswd -m MD5 "$i$j$k$l$a" -s $salt1 | cut -d"$" -f4)"
if [ "$test" == "$encr1" ] ; then
echo " MD5 Salted Hash Password is: $i$j$k$l$a"
echo " Salt: "$salt1""
for i in "${LIST1[#]}"
do
for j in "${LIST2[#]}"
do
for k in "${LIST3[#]}"
do
for l in "${LIST4[#]}"
do
for a in "${LIST5[#]}"
do
test="$(mkpasswd -m SHA-256 "$i$j$k$l$a" -s $salt3 | cut -d"$" -f4)"
if [ "$test" == "$encr3" ] ; then
echo " SHA-256 Salted Hash Password is: $i$j$k$l$a"
echo " Salt: "$salt3""
fi
done
done
done
done
done
for i in "${LIST1[#]}"
do
for j in "${LIST2[#]}"
do
for k in "${LIST3[#]}"
do
for l in "${LIST4[#]}"
do
for a in "${LIST5[#]}"
do
test="$(mkpasswd -m SHA-512 "$i$j$k$l$a" -s $salt4 | cut -d"$" -f4)"
if [ "$test" == "$encr4" ] ; then
echo " SHA-512 Salted Hash Password is: $i$j$k$l$a"
echo " Salt: "$salt4""
for i in "${LIST1[#]}"
do
for j in "${LIST2[#]}"
do
for k in "${LIST3[#]}"
do
for l in "${LIST4[#]}"
do
for a in "${LIST5[#]}"
do
test="$(mkpasswd -m des "$i$j$k$l$a" -s $salt2)"
if [ "$test" == "$encr2" ] ; then
echo " DES Salted Hash Password is: $i$j$k$l$a"
echo " Salt: "$salt2""
exit
fi
done
done
done
done
done
fi
done
done
done
done
done
fi
done
done
done
done
done
The Output still somehow displayed as i wanted:
Since you use the arrays LIST1 ... LIST5 only for the 5×for constructs I would replace them with brace expansions. That way you end up with only one loop.
Instead of manually listing and checking variable pairs like encr1 and salt1 use three arrays encr, salt, and algo (the algorithm you specified manually before). Then you can use a loop to iterate over all these triples instead of having to write each check manually.
#! /bin/bash
n=4
encr=(
".8742cNKlzqQ8Mgjip/Fg1"
"31HvJ8Iinxk2k"
"AyPVCzU.ourSwFdL3N6/YP9RRfIwwKZPNrnt0/yn5vB"
"Cd9AjUI4nGglIcP3MByrZUnu.hHBJc7.eR0o/v0A1gu0/6ztFfBxeJgKTzpgoCLptJS2NnliZLZjO40LUseED/"
)
salt=(bCgxj8Yt 31 klPjs90j 8899Uidd)
algo=(MD5 SHA-256 SHA-512 des)
for candidate in {K,F,L,W}{8,2,9}{x,b,s,v}{'~','-','[','*'}{'$','+',']','%'}; do
for (( i = 0; i < n; i++ )); do
test="$(mkpasswd -m "${algo[i]}" "$candidate" -s "${salt[i]}")"
if [ "$test" = "${encr[i]}" ]; then
echo " ${algo[i]} Salted Hash Password is: $candidate"
echo " Salt: ${salt[i]}"
fi
done
done
Here I removed the duplicated 2 from the 2nd symbol candidates. Thank you Gordon Davisson for pointing this out.
By the way: I used the variable names from your original script. However, it would be better to name the array of hashes something other than encr. Hashing and encryption differ – just like shredding a document and then picking ten of its pieces is different from locking the intact document away.
You can loop over all candidates in a single loop with combinatorial {} expansion:
for candidate in {K,F,L,W}{8,2,9,2}{x,b,s,v}{\~,-,[,\*}{$,+,],%}; do
...
done
Note that this is not POSIX, but works in bash and zsh.
In the current script, your loops and if blocks are all weirdly nested inside each other. The simple way to do this is just have one set of loops that generates candidate passwords, and for each candidate test all 4 hashes:
#!/bin/bash
LIST1=(K F L W )
LIST2=(8 2 9 2 )
LIST3=(x b s v )
LIST4=("~" "-" "[" "*" )
LIST5=('$' "+" "]" "%" )
encr1=".8742cNKlzqQ8Mgjip/Fg1"
salt1="bCgxj8Yt"
encr2="31HvJ8Iinxk2k"
salt2="31"
encr3="AyPVCzU.ourSwFdL3N6/YP9RRfIwwKZPNrnt0/yn5vB"
salt3="klPjs90j"
encr4="Cd9AjUI4nGglIcP3MByrZUnu.hHBJc7.eR0o/v0A1gu0/6ztFfBxeJgKTzpgoCLptJS2NnliZLZjO40LUseED/"
salt4="8899Uidd"
# Loop over characters to generate candidate passwords
for i in "${LIST1[#]}"; do
for j in "${LIST2[#]}"; do
for k in "${LIST3[#]}"; do
for l in "${LIST4[#]}"; do
for a in "${LIST5[#]}"; do
# For this candidate...
candidate="$i$j$k$l$a"
# test whether it matches the MD5 hash
test="$(mkpasswd -m MD5 "$candidate" -s "$salt1" | cut -d'$' -f4)"
if [ "$test" = "$encr1" ] ; then
echo " MD5 Salted Hash Password is: $candidate"
echo " Salt: $salt1"
fi
# test whether it matches the SHA-256 hash
test="$(mkpasswd -m SHA-256 "$candidate" -s "$salt3" | cut -d'$' -f4)"
if [ "$test" = "$encr3" ] ; then
echo " SHA-256 Salted Hash Password is: $candidate"
echo " Salt: $salt3"
fi
# test whether it matches the SHA-512 hash
test="$(mkpasswd -m SHA-512 "$candidate" -s "$salt4" | cut -d'$' -f4)"
if [ "$test" = "$encr4" ] ; then
echo " SHA-512 Salted Hash Password is: $candidate"
echo " Salt: $salt4"
fi
# test whether it matches the DES hash
test="$(mkpasswd -m des "$candidate" -s "$salt2")"
if [ "$test" = "$encr2" ] ; then
echo " DES Salted Hash Password is: $candidate"
echo " Salt: $salt2"
fi
done
done
done
done
done
Note that this will find the DES and SHA-512 passwords twice, because "2" is listed twice in LIST2.
This approach is a little less efficient than it could be, because it continues checking for matches to the hashes it's already found matches to. This could be fixed in several ways, but they'd all complicate the code more than I want to get into here. In the usual situation, where you're only looking for one match, you can just break out of the loops as soon as you find it.
BTW, I fixed the comparison operator (as #Jens pointed out, = is standard in a [ ] expression) and quoting (salts were not properly quoted, and using a literal $ in double-quotes is weird even when it's legal).

Bash: tr command with variables representing chars

I want to use the tr command to map chars to new chars, for example:
echo "hello" | tr '[a-z]' '[b-za-b]' Will output: ifmmp
(where each letter in the lower-case alphabet is shifted over one to the right)
See below the mapping to new chars for '[b-za-b]':
[a b c d e f g h i j k l m n o p q r s t u v w x y z] will map to:
[b c d e f g h i j k l m n o p q r s t u v w x y z a]
However, when I want it to rotate multiple times, how can I use a variable to control the rotate-value for the tr command?
Eg: for a shift of 1:
echo "hello" | tr '[a-z]' '[b-za-b]' without variables and:
echo "hello" | tr '[a-z]' '[(a+$var)-za-(a+$var)]' where $var=1
here I have: (a+$var)-z representing the same as b-z and
....................a-(a+$var) representing the same as a-b
I have tried converting the ascii value to a char to use within the tr command but I don't think that is allowed.
My problem is that bash is not interpreting:
(a+$var) as the char b when $var=1
(a+$var) as the char c when $var=2
... etc.
How can I tell bash to interpret these equations as chars for the tr command
EDIT
I tried doing it with an array but it's not working:
chars=( {a..z} )
var=2
echo "hello" | tr '[a-z]' '[(${chars[var]}-z)(a-${chars[var]})]'
I used: (${chars[var]}-z) to represent b-z where var=1
Because ${chars[1]} is b but this is not working. Am I missing something?
What you are trying to do cannot be done using tr which does not handle your requirement. Moreover when you meant to modify and use variables to add to glob patterns in bash which is something you cannot possibly do.
There is a neat little trick you can do with bash arrays!. The tr command can take expanded array sequence over the plain glob patterns also. First define a source array as
source=()
Now add its contents as a list of character ranges from a-z using brace expansion as
source=({a..z})
and now for the transliterating array, from the source array, construct it as follows by using the indices to print the array elements
trans=()
Using a trick to get the array elements from the last with syntax ${array[#]: (-num)} will get you the total length - num of the elements. So building the array first as
var=2
trans+=( "${source[#]:(-(26-$var))}" )
and now to build the second part of the array, use another trick ${array[#]:0:num} to get the first num number of elemtents.
trans+=( "${source[#]:0:$(( $var + 1 ))}" )
So what we have done now is for a given value of var=2, we built the trans array as
echo "${trans[#]}"
c d e f g h i j k l m n o p q r s t u v w x y z a b c
Now you can just use it easily in the tr command
echo "hello" | tr "${source[*]}" "${trans[*]}"
jgnnq
You can just put it all in function and print its value as
transChar() {
local source
local trans
local result
source=({a..z})
trans=()
var="$2"
input="$1"
trans+=( "${source[#]:(-(26-$var))}" )
trans+=( "${source[#]:0:$(( $var + 1 ))}" )
result=$( echo "$input" | tr "${source[*]}" "${trans[*]}" )
echo "$result"
}
Some of the tests
transChar "hello" 1
ifmmp
transChar "hello" 2
jgnnq
transChar "hello" 3
khoor
rot-random:
# generate alphabet as arr:
arr=( {1..26} )
i=$(($RANDOM%24+1))
# left and right
l=$(echo ${arr[$i]})
r=$(echo ${arr[$i+1]})
# reusing arr for testing:
echo ${arr[#]} | tr "a-z" "$r-za-$l"
echo "secret:" | tr "a-z" "$r-za-$l" ; echo $l $r $i
amkzmb:
h i 7
You could use octal \XXX character codes for characters to do what you intend. Using the octal codes you could do any arithmetic manipulations to numbers and then convert them to character codes
# rotr x
#
# if 0 <= x <= 25 rotr x outputs a set specification
# that could be used as an argument to tr command
# otherwise it outputs 'a-z'
function rotr(){
i = $(( 97 + $1 ))
if [ $i -lt 97 ] ; then
translation='a-z'
elif [ $i -eq 97 ] ; then
translation='\141-\172' # 141 is the octal code for "a"
# 172 is the octal code for "z"
elif [ $i -eq 98 ] ; then
translation='\142-\172\141'
elif [ $i -lt 122 ] ; then # $i is between 99 and 121 ("c" and "y")
ii=$(echo "obase=8 ; $i" | bc)
jj=$(echo "obase=8 ; $(( $i - 1 ))" | bc)
translation=\\$ii'-\172\141-'\\$jj
elif [ $i -eq 122 ] ; then
translation='\172\141-\171'
else # $i > 122
tranlation='a-z'
fi
echo $translation
}
Now you could use this as follows
echo hello | tr 'a-z' $(rotr 7)
prints
olssv

Find specific cell from space-separated CSV file in bash

I have a question related to bash operating on comma-separated value files (.csv) saved with spaces as the selected separator.
As an example I'll put small .csv file here:
A B C D
1 a b c d
2 e f g h
3 i j k l
4 m n o p
And here is my question: Is that possible in bash to read specific value for example from cell C4?
Tried to find any topic with similar problem but cannot it.
Thanks in advance!
Can do this very easily in awk :
example.sh
#!/bin/bash
awk '
{
if(NR==5){ print $4; }
}
' < "$1"
output
$ ./example.sh input.txt
o
details
NR filters the line number
$4 refers to the fourth field ( under C column )
The tricky part is converting "C4" into column 3, row 4. Here's one way with bash:
#!/bin/bash
cell=$1
file=$2
colnum() {
local -u col=$1
local val=0 i
for ((i=0; i<${#col}; i++)); do
# ascii value of a char, ref: http://stackoverflow.com/q/890262/7552
printf -v ascii "%d" "'${col:i:1}"
val=$(( val*26 + ascii - 64 ))
done
echo "$val"
}
if ! [[ $cell =~ ^([A-Za-z]+)([0-9]+)$ ]]; then
echo "error: invalid cell '$cell'"
exit 1
fi
col=$(colnum "${BASH_REMATCH[1]}")
row=${BASH_REMATCH[2]}
lineno=0
while read -ra fields; do
if (( ++lineno == row )); then
echo "${fields[col-1]}"
fi
done < "$file"

Assigning a value from csv file to variable in bash [duplicate]

I have a question related to bash operating on comma-separated value files (.csv) saved with spaces as the selected separator.
As an example I'll put small .csv file here:
A B C D
1 a b c d
2 e f g h
3 i j k l
4 m n o p
And here is my question: Is that possible in bash to read specific value for example from cell C4?
Tried to find any topic with similar problem but cannot it.
Thanks in advance!
Can do this very easily in awk :
example.sh
#!/bin/bash
awk '
{
if(NR==5){ print $4; }
}
' < "$1"
output
$ ./example.sh input.txt
o
details
NR filters the line number
$4 refers to the fourth field ( under C column )
The tricky part is converting "C4" into column 3, row 4. Here's one way with bash:
#!/bin/bash
cell=$1
file=$2
colnum() {
local -u col=$1
local val=0 i
for ((i=0; i<${#col}; i++)); do
# ascii value of a char, ref: http://stackoverflow.com/q/890262/7552
printf -v ascii "%d" "'${col:i:1}"
val=$(( val*26 + ascii - 64 ))
done
echo "$val"
}
if ! [[ $cell =~ ^([A-Za-z]+)([0-9]+)$ ]]; then
echo "error: invalid cell '$cell'"
exit 1
fi
col=$(colnum "${BASH_REMATCH[1]}")
row=${BASH_REMATCH[2]}
lineno=0
while read -ra fields; do
if (( ++lineno == row )); then
echo "${fields[col-1]}"
fi
done < "$file"

Escaped asterisk (*) in list of characters outputs file in folder

At the very beginning of my Bash script I'm passing a set of characters like this:
#!/bin/bash
set0="0 1 2 3 4 5 6 7 8 9"
set1="° § + \" ç % & / ( ) = ? ' ^ ! £ $ - _ ; , : . *"
The script combines every single character with the others in order to get all possible combination with length of n.
As you can see in set1 above I have to escape the quote " character for example. My problem now is, that I have to escape the asterisk * as well. But I couldn't figure out how.
This didn't work so far:
#!/bin/bash
set1="° § + \" ç % & / ( ) = ? ' ^ ! £ $ - _ ; , : . \*"
It echoes \*. If I don't escape the asterisk * with a backslash \ the script echoes all the files in current directory all time.
Do you know how I can escape the asterisk * successfully?
This is the whole script:
8 chars0="a b c d e f g h i j k l m n o p q r s t u v w x y z"
9 chars1="A B C D E F G H I J K L M N O P Q R S T U V W X Y Z"
10 chars2="0 1 2 3 4 5 6 7 8 9"
11 chars3="° § + \" ç % & / ( ) = ? ' ^ ! £ $ - _ ; , : . *"
12
13 function increment {
14 INPUT=$1
15 [[ ${#INPUT} -ge $minlen ]] && echo $1
16 if [[ ${#INPUT} -lt $maxlen ]]; then
17 for c in $chars; do
18 increment $1$c
19 done
20 fi
21 }
22
23 function showUsage {
24 echo "$0 MAXLEN [MINLEN] [a [A [n [p]]]]"
25 echo
26 echo " MAXLEN integer Maximum lenght, or specific lengt if MINLEN is omitted"
27 echo " MINLEN integer Minimum lenght, equals MAXLEN if omitted"
28 echo ""
29 echo " characters:"
30 echo " a lower case a-z"
31 echo " A Uppercase A-Z"
32 echo " n numeric 0-9"
33 echo " p punctuation . ?"
34 }
35
36
37
38
39 ## argument handler
40 [[ "$1" = "" ]] && showUsage && exit
41 maxlen=$1
42 [[ $2 -eq 0 ]] && minlen=$maxlen || minlen=$2
43
44
45 for arg in "$#"; do
46 case $arg in
47 a) chars="$chars $chars0" ;;
48 A) chars="$chars $chars1" ;;
49 n) chars="$chars $chars2" ;;
50 p) chars="$chars $chars3" ;;
51 esac;
52 done
53
54 #fallback
55 [[ "$chars" = "" ]] && chars="$chars0"
56
57
58
59 ## kickof
60
61 for i in $chars; do
62 increment $i
63 done
Thank you for all your suggestions. The one that helped me fixing this was
set -f
It's a quick fix of course. But it works well for me.
The best way to do this is maybe to use:
set -o noglob
set="* + ?"
for i in $set; do echo $i; done
*
+
?
The problem when you use the variable. noglob will prevent all of the file glob characters from expanding.
You can't safely loop on a list of words in a string like this, without having nasty globbing effects. In your case, it boils down to this:
a=*
for i in $a; do
echo "$a"
done
You'll see that the files in your current directory are printed, because the (unquoted! horror!) $a in the for statement expands to * which will glob to the list of files in current dir.
You must fix this by using another design. You're lucky, Bash supports arrays very well, so redesign your code to use arrays. For example:
chars=( ° § + \" ç % \& / '(' ')' = \? \' ^ ! £ $ - _ \; , : . \* )
(this defines the array chars) and to loop through that:
for i in "${chars[#]}"; do
echo "$i"
done
(observe the quotes).
Below is a rewriting of your code to show you how to use arrays (and I've fixed/improved some other minor stuff too):
#!/bin/bash
chars_alpha=( {a..z} )
chars_ALPHA=( {A..Z} )
chars_digit=( {0..9} )
chars_punct=( '°' '§' '+' '"' 'ç' '%' '&' '/' '(' ')' '=' '?' "'" '^' '!' '£' '$' '-' '_' ';' ',' ':' '.' '*' )
increment() {
local input=$1
(( ${#input} >= minlen )) && printf '%s\n' "$input"
if (( ${#input} < maxlen )); then
for c in "${chars[#]}"; do
increment "$input$c"
done
fi
}
showUsage() {
cat <<EOF
$0 MAXLEN [MINLEN] [a] [A] [n] [p]
MAXLEN integer Maximum lenght, or specific lengt if MINLEN is omitted
MINLEN integer Minimum lenght, equals MAXLEN if omitted
characters:
a lower case a-z
A Uppercase A-Z
n numeric 0-9
p punctuation . ? etc.
EOF
}
## argument handler
(($#)) || { showUsage; exit 1; }
[[ $1 = +([[:digit:]]) ]] || { showUsage; exit 1; }
((maxlen=10#$1))
shift
# Check that maxlen is >0 or exit gracefully
((maxlen>0)) || exit 0
if [[ $1 = +([[:digit:]]) ]]; then
((minlen=10#$1))
shift
else
((minlen=maxlen))
fi
# Check that minlen<=maxlen otherwise swap them
if ((minlen>maxlen)); then
((temp=minlen,minlen=maxlen,maxlen=temp))
fi
chars=()
while (($#)); do
case $1 in
(a) chars+=( "${chars_alpha[#]}" ); chars_alpha=() ;;
(A) chars+=( "${chars_ALPHA[#]}" ); chars_ALPHA=() ;;
(n) chars+=( "${chars_digit[#]}" ); chars_digit=() ;;
(p) chars+=( "${chars_punct[#]}" ); chars_punct=() ;;
(*) printf >&2 'Ignored arguments %s\n' "$1" ;;
esac
shift
done
#fallback
(( ${#chars[#]} )) || chars=( "${chars_alpha[#]}" )
#kick off!
increment
One of the fixes includes using printf instead of echo. With echo, your code is broken, since the strings:
-e
-n
-E
would never be printed! see help echo to understand why. Try it yourself too:
echo -e
echo -n
echo -E
don't output anything!
Use single quotes to wrap your string instead of double quotes. You won't have to have to escape any characters beside the single quote.

Resources