Why am I getting a hash other than the one I expected? - ruby

When I enter this code from http://ruby.about.com/od/advancedruby/ss/Cryptographic-Hashes-In-Ruby.htm
#!/usr/bin/env ruby
require 'digest'
password = "A user's password"
hash = Digest::SHA1.hexdigest(password)
puts hash
# This will produce the hash
# 62018390552aaba3d344e3b43bfa14e49e535dfc
I get the answer they said I would.
But when I enter this shell command
echo "A user's password" | openssl dgst -sha1 -hex
I get 95f33732bafc1744bf24e0cae4e014ab2e5f1580
Why, please?

Your command-line example is including a newline, which isn't specified in the Ruby string. Try using -n so echo skips the newline:
$ echo "A user's password" | openssl dgst -sha1 -hex
95f33732bafc1744bf24e0cae4e014ab2e5f1580
$ echo -n "A user's password" | openssl dgst -sha1 -hex
62018390552aaba3d344e3b43bfa14e49e535dfc

Related

How to generate an aws4 signed request in bash?

I'm trying to connect to the Scaleway S3 api in bash (it's a subset of aws s3 api). The signature model is aws4_request, and is documented. In the code below I'm uploading a file. I've reviewed every line and although I'm no bash guru, I'm pretty confident I have all the right parts to compute a correct signature, but I still get 403 error as a response. The request itself seems fine, as far as I can see in a wireshark capture. Can anyone find any issue here?
#!/bin/bash
set -e
echo "creds $SCW_ACCESS_KEY/$SCW_SECRET_KEY"
BUCKET="vni-backups"
REGION="fr-par"
HOST="$BUCKET.s3.$REGION.scw.cloud"
filepath="../import.yml"
file_sha256=$(sha256sum -b $filepath | head -c64)
fulldate=$(date +"%Y%m%dT%H%M%SZ" --utc)
shortdate=$(date +"%Y%m%d" --utc)
# Assemble canonical url
canonicalRequest="PUT
/import.yml
content-type:text/plain
host:$HOST
x-amz-content-sha256:$file_sha256
x-amz-date:$fulldate
content-type;host;x-amz-content-sha256;x-amz-date
$file_sha256"
canonReqSha=$(echo -n "$canonicalRequest" | openssl dgst -sha256 | awk '{print $2}')
echo $canonicalRequest
echo "requestHash: $canonReqSha"
echo "
---------------------------------------
"
stringToSign="AWS4-HMAC-SHA256
$fulldate
$shortdate/fr-par/s3/aws4_request
$canonReqSha"
echo $stringToSign
dateKey=$(echo -n "$shortdate" | openssl dgst -sha256 -binary -hmac "AWS4$SCW_SECRET_KEY")
regionKey=$(echo -n "fr-par" | openssl dgst -sha256 -binary -hmac "$dateKey")
serviceKey=$(echo -n "s3" | openssl dgst -sha256 -binary -hmac "$regionKey")
signingKey=$(echo -n "aws4_request" | openssl dgst -sha256 -binary -hmac "$serviceKey")
signature=$(echo -n "$stringToSign" | openssl dgst -sha256 -hmac "$signingKey" | awk '{print $2}')
echo "signature: $signature"
echo "
---------------------------------------
"
# Make request
curl -X PUT \
-H "Content-Type: text/plain" \
-H "x-amz-content-sha256: $file_sha256" \
-H "x-amz-date: $fulldate" \
-H "Authorization: AWS4-HMAC-SHA256" \
-H "Credential: $SCW_ACCESS_KEY/${shortdate}/$REGION/s3/aws4_request" \
-H "SignedHeaders: content-type;host;x-amz-content-sha256;x-amz-date" \
-H "Signature: $signature" \
--data-binary #../import.yml \
"http://$BUCKET.s3.$REGION.scw.cloud/import.yml"
The request is done in clear http just because it's simpler to capture it with network analysis tool (e.g. wireshark) than https.

Bash OpenSSL is not equal to php openssl_encrypt value

I am trying to reach the same value of encryption in bash as it is from php , with no success .
Here is my php script
$message ='{"coupon_key":"011205358365345679","location_id":"288","device_key":"test_1234"}';
$key = "password";
$iv = base64_decode("dU+AyWweQYhAlGKLaxoS9w==");
$base64_iv = base64_encode($iv);
$base64_ev = base64_encode($encrypted_value);
$encrypted_value = openssl_encrypt(
$message,
'AES-256-CBC',
$key,
OPENSSL_RAW_DATA|OPENSSL_NO_PADDING,
$iv
);
$encode = base64_encode($encrypted_value);
//Zi7UcBwqM+gKZC9iZPgF3UHBXLUg1+Age/1+kRIfcstYBgGfYm7N1qCIFnm6jGn4AGQph/Q6hKjR1hYBT0wkJv8c8qFrHHZNUuraMfSRH3s=
$mac = hash_hmac('sha256', $base64_iv . $encode, $key);
echo '{"iv":"'.$base64_iv.'","value":"'.$encode.'","mac":"'.$mac.'"}'."<br>";
//{"iv":"dU+AyWweQYhAlGKLaxoS9w==","value":"Zi7UcBwqM+gKZC9iZPgF3UHBXLUg1+Age/1+kRIfcstYBgGfYm7N1qCIFnm6jGn4AGQph/Q6hKjR1hYBT0wkJv8c8qFrHHZNUuraMfSRH3s=","mac":"97fb6f4226a917322c7361af1d9b2949ad96691c1fc1a7f1c8379c71ae19f356"}
$retString2 = base64_encode('{"iv":"'.$base64_iv.'","value":"'.$encode.'","mac":"'.$mac.'"}');
echo $retString2;
//eyJpdiI6ImRVK0F5V3dlUVloQWxHS0xheG9TOXc9PSIsInZhbHVlIjoiWmk3VWNCd3FNK2dLWkM5aVpQZ0YzVUhCWExVZzErQWdlLzEra1JJZmNzdFlCZ0dmWW03TjFxQ0lGbm02akduNEFHUXBoL1E2aEtqUjFoWUJUMHdrSnY4YzhxRnJISFpOVXVyYU1mU1JIM3M9IiwibWFjIjoiOTdmYjZmNDIyNmE5MTczMjJjNzM2MWFmMWQ5YjI5NDlhZDk2NjkxYzFmYzFhN2YxYzgzNzljNzFhZTE5ZjM1NiJ9
and here is my bash version
password="password";
passwordhex=$(echo "$password" | xxd -c 256 -ps) ;
# iv2=$(hexdump -n 16 -e '4/4 "%08X" 1 "\n"' /dev/random) ;
iv=$(printf 'dU+AyWweQYhAlGKLaxoS9w==' | base64 -d )
biv=$(printf "$iv" | base64) ;
hexiv=$(printf "$iv" | xxd -c 256 -ps) ;
eString=$(printf '{"coupon_key":"011205358365345678","location_id":"288","device_key":"test_1234"}');
tttw=$(printf "$eString" | openssl aes-256-cbc -e -nosalt -a -A -K "$passwordhex" -iv "$hexiv") ;
echo "$tttw" ;
printf "${biv}${tttw}" |openssl dgst -sha256 -hmac abc -macopt hexkey:"$passwordhex" | sed 's/^.* //';
macopt2=$(printf "${biv}${tttw}" |openssl dgst -sha256 -hmac abc -macopt hexkey:"$passwordhex" | sed 's/^.* //');
echo "$macopt2"
finalString="{'iv':'$biv','value':'$tttw','mac':'$macopt2'}";
echo "$finalString";
sendHash=$(printf "$finalString" | base64 -w 0)
echo "$sendHash"
Starting from
tttw=$(echo -n $eString | openssl aes-256-cbc -e -nosalt -a -A -K $passwordhex -iv $hexiv) ;
it goes wrong , because $tttw is returning then
bKG5quB9/YQUsmlFvDHq2H+AfNGQuDfVztyi0dd5hCY7hLfaACnjD8SWlwqy0yy4hXUZSA2YcTXej/xtMg9vqEpoO6CDw9hk7+tUcYOOV5aOdVBnSLowmEllHt0JfjdE
instead of Zi7UcBwqM+gKZC9iZPgF3UHBXLUg1+Age/1+kRIfcstYBgGfYm7N1qCIFnm6jGn4AGQph/Q6hKjR1hYBT0wkJv8c8qFrHHZNUuraMfSRH3s=
Can anybody maybe see what option is going wrong here?
Note1: I have updated the bash script to use prinf instead of echo -n
Note 2 : Seems on my newer machine I get "hex string is too short, padding with zero bytes to length" from the line
tttw=$(printf $eString | openssl aes-256-cbc -e -nosalt -a -A -K $passwordhex -iv $hexiv) ;
Looks like the issue is near the very top:
passwordhex=$(echo "$password" | xxd -c 256 -ps) ;
So essentially the output of echo "$password" is password\n.
Using echo like this will append a line feed to the input for xxd which I assume you already know since the original script was packed with echo -n. I mentioned in the comments that printf is more portable. The accepted way to use printf with a variable is like this:
passwordhex=$(printf '%s' "$password" | xxd -c 256 -ps) ;
The reason for this is that if your variable has a format identifier (like %s), it would change the output unexpectedly. This would have also showed up on shellcheck.
With this one change, here is the output:
Zi7UcBwqM+gKZC9iZPgF3UHBXLUg1+Age/1+kRIfcssepjJ8+wUjTDAjPUMkGA+eF9EL284iD5UIzA+REyhMWLWbUJpPltHFk1+lhQyVlUXXVTw0FFV1G+iQfEWhbyg4
484123c33b54e446c61120112955cd15f3592f42e737c9fa24db266cdec954a2
484123c33b54e446c61120112955cd15f3592f42e737c9fa24db266cdec954a2
{'iv':'dU+AyWweQYhAlGKLaxoS9w==','value':'Zi7UcBwqM+gKZC9iZPgF3UHBXLUg1+Age/1+kRIfcssepjJ8+wUjTDAjPUMkGA+eF9EL284iD5UIzA+REyhMWLWbUJpPltHFk1+lhQyVlUXXVTw0FFV1G+iQfEWhbyg4','mac':'484123c33b54e446c61120112955cd15f3592f42e737c9fa24db266cdec954a2'}
eydpdic6J2RVK0F5V3dlUVloQWxHS0xheG9TOXc9PScsJ3ZhbHVlJzonWmk3VWNCd3FNK2dLWkM5aVpQZ0YzVUhCWExVZzErQWdlLzEra1JJZmNzc2Vwako4K3dValREQWpQVU1rR0ErZUY5RUwyODRpRDVVSXpBK1JFeWhNV0xXYlVKcFBsdEhGazErbGhReVZsVVhYVlR3MEZGVjFHK2lRZkVXaGJ5ZzQnLCdtYWMnOic0ODQxMjNjMzNiNTRlNDQ2YzYxMTIwMTEyOTU1Y2QxNWYzNTkyZjQyZTczN2M5ZmEyNGRiMjY2Y2RlYzk1NGEyJ30=

OpenSSL decrypt AES 256bit (base64) encrypted password - wrong final block length

I am trying to decrypt aes-256-cdc encoded password using OpenSSL
#!/usr/bin/env bash
ak=BgL0cPoZQ4wZWOWl5mXBhlMsNbbZL2zvsWZXjuGy4Iw=
iv=cGEvcGWzE8t7CS3wbeoUFQ==
pass=RCQm23YHOCg3nxOl7CcQ7w==
#change format from base64 into hex
AES_KEY=$(echo "${ak}" | openssl base64 -d | xxd -p |tr -d '\n')
AES_IV=$(echo "${iv}" | openssl base64 -d | xxd -p)
ENCODED_PASSWORD=$(echo "${pass}" | openssl base64 -d | xxd -p)
echo "AES_KEY ${AES_KEY}"
echo "AES_IV ${AES_IV}"
echo "ENCODED_PASSWORD ${ENCODED_PASSWORD}"
#set password file
echo "${ENCODED_PASSWORD}" > in.txt
#decode password
openssl enc -nosalt -aes-256-cbc -d -iv ${AES_IV} -K ${AES_KEY} -in in.txt
this results in error message
AES_KEY 0602f470fa19438c1958e5a5e665c186532c35b6d92f6cefb166578ee1b2e08c
AES_IV 70612f7065b313cb7b092df06dea1415
ENCODED_PASSWORD 53b7adff6e85baedfa9dab80109ad67d
▒▒▒▒▒▒`$;▒▒▒▒%▒O▒Q▒▒▒S▒▒<7 7
bad decrypt
32624:error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length:evp_enc.c:518:
0602f470fa19438c1958e5a5e665c186532c35b6d92f6cefb166578ee1b2
e08c
I think that the problem is aes-key (ak) which has a newline char in it, which I am trying to remove with
|tr -d '\n'
a password should decode as
password
No, what's wrong is the encoding of in.txt. It should not be text at all, it should be binary.
In principle you would not get this error either if you'd use echo -n suppressing the final end-of-line within the ciphertext. The decryption would however still fail as it expects binary instead of an encoded binary value.
You may want to change the name of in.txt to in.bin if you want to keep a file. You should also be able to simply pipe the ciphertext into openssl using the standard input (stdin). In that case you may want to encode it first to store it in a shell variable and then decode before piping it to openssl to decrypt it.
For binary, use cat instead of echo.
If your $pass is long (more than 32 chars maybe), be sure to use openssl -A option, the reason is documented in the openssl manual.
With -A option, for encryption, the base64 encoded string will not be splitted in segments; For decryption, whole line is read to be decoded using base64.
Code example:
plaintxt='hello world"
pass=$(echo ${plaintxt} | openssl enc -aes-128-cbc -a -K ${AES_KEY} -iv ${AES_IV} -A )
echo "decoded password is: "
echo ${pass} | openssl enc -aes-128-cbc -d -a -K ${AES_KEY} -iv ${AES_IV} -A
this works as expected:
#!/usr/bin/env bash
#base64 encoded aes key, iv and password
ak=BgL0cPoZQ4wZWOWl5mXBhlMsNbbZL2zvsWZXjuGy4Iw=
iv=cGEvcGWzE8t7CS3wbeoUFQ==
pass=OfOXO+ruKFTCsBwGHynXwA==
#change format from base64 into hex, for openssl to consume, xxd -p -c32 is taking care of wrapping of the new lines
AES_KEY=$(echo ${ak} | openssl base64 -d | xxd -p -c32)
AES_IV=$(echo ${iv} | openssl base64 -d | xxd -p -c32)
echo "AES_KEY ${ak}"
echo "AES_IV ${iv}"
echo "encoded password ${pass}"
echo "decoded password is: "
echo ${pass} | openssl enc -aes-256-cbc -d -a -K ${AES_KEY} -iv ${AES_IV}
explanation:
openssl enc -aes-256-cbc -d
decode using aes-256-cbc algo
-a
in our case, it means that openssl will accept base64 encoded password
-K
aes key
-iv
aes iv

openssl enc -base64 -d does not decode strings after a certain length

I have a simple bash script that does encoding / decoding for strings using base64. The script is:
#!/bin/bash
echo "encode or decode ?"
read input
if [ "$input" == "encode" ]
then
echo Please, enter your secret message
read message
echo "The cipher representing your message is"
echo -n $message | openssl enc -base64
else
echo "Please enter your cipher"
read cipher
echo "Your secret message is"
echo $cipher | openssl enc -base64 -d
echo ""
fi
The script works fine, as long as the length of the string being encoded is 49 characters at max. Strings longer than 49 characters can not be decoded correctly. Any idea what might be wrong in my script?
Many thanks!
openssl enc -base64 is inserting a carriage return after 64 characters of encoded string. This actually happens about the 49th character of string to be encoded.
To avoid this line break in the encoded string, use option -A in both openssl commands to encode or decode the whole string at once:
echo -n $message | openssl enc -base64 -A
and
echo $cipher | openssl enc -base64 -d -A
This looks to be specific to openssl. If you would use base64 executable from the coreutils package, this would work as well.

Is there a Bash one-liner to check that the output of three commands match?

I'm trying to figure out some Bash-foo to check that the output of three different commands is identical. I can do this with several lines of a Bash script, I'm just wondering if what I want to do is possible in one line with some fancy shell I/O redirection.
What I want to do is check that an SSL certificate matches up with a particular key and certificate signing request.
The commands look like this:
openssl x509 -noout -modulus -in certificate.crt | openssl md5
openssl rsa -noout -modulus -in privateKey.key | openssl md5
openssl req -noout -modulus -in CSR.csr | openssl md5
If the key, cert, and csr match up, all three of those commands should spit out identical output, like: "(stdin)= 95ce143e8418cf8a4f7dd718983ed4eb".
Here's a prototype:
[[ $(echo -e "blah\nblah\nblah" | uniq | wc -l) -eq 1 ]]
But I can't get from there to the final product. This doesn't work:
[[ $(openssl x509 -noout -modulus -in certificate.crt | openssl md5 && openssl rsa -noout -modulus -in privateKey.key | openssl md5 && openssl req -noout -modulus -in CSR.csr | openssl md5 | uniq | wc -l) -eq 1 ]]
One problem is maybe that my prototype generates all three lines of output from one command, but the real thing uses && a couple times.
cmp -s <( cmd1) <(cmd2) && cmp -s <( cmd1) <(cmd3)
Note that this construct executes cmd1 two times.
If you require single exec of each cmd, more complicated line would look something like:
cmd1|tee >( cmp -s <(cmd2) )|cmp -s <(cmd3)
Also for the second one, checking the result is complicated (you have to check PIPESTATUS array)
The problem is that you're piping only the last command "sub-pipeline" into uniq. Try this:
[[ $( { openssl x509 -noout -modulus -in certificate.crt | openssl md5 && openssl rsa -noout -modulus -in privateKey.key | openssl md5 && openssl req -noout -modulus -in CSR.csr | openssl md5; } | uniq | wc -l) -eq 1 ]]
The curly braces make the three "sub-pipelines" act as if together they are one command as far as uniq is concerned, analogously to your echo prototype.
You probably meant something like
((1 == $( ( echo 1 && sleep 1; echo 1 && sleep 1) | sort -u | wc -l ) ))
But it might be easier to do
x1=$( command1 )
x2=$( command2 )
x3=$( command3 )
if [[ $x1 == $x2 && $x2 == $x3 ]] ; then
echo The same.
fi
Edit:
This form should work as well, but reduce the number of stored variables.
x1=$(command1)
[[ $x1 == $(command2) && $x1 == $(command3) ]] && echo match

Resources