Convert SHA1 password to its binary form - ruby

I have a database with passwords encrypted in SHA1, I need to convert them to the SHA1 binary form and encode with base64, how can I get that?
This is what I have:
# echo -n "password" | openssl sha1
5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8
This is what I need:
# echo -n "password" | openssl sha1 -binary | base64
W6ph5Mm5Pz8GgiULbPgzG37mj9g=

require 'digest/sha1'
require 'base64'
Base64.encode64(Digest::SHA1.digest('password'))
# => "W6ph5Mm5Pz8GgiULbPgzG37mj9g=\n"
this adds a newline though so you may need to use
Base64.encode64(Digest::SHA1.digest('password')).chop
# => "W6ph5Mm5Pz8GgiULbPgzG37mj9g="
or even simpler, as #FrederickCheung suggested:
Digest::SHA1.base64digest('password')
Edit
when you only have the hex string of the SHA-1 encoded password, then do
require 'base64'
pass = "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8"
Base64.encode64([pass].pack('H*')).chop
# => "W6ph5Mm5Pz8GgiULbPgzG37mj9g="
or you can even bypass the base64 library and solely rely on pack:
[[pass].pack('H*')].pack('m0')
# => "W6ph5Mm5Pz8GgiULbPgzG37mj9g="

Python 3 approach:
import sys, base64
def hex_to_b64(word):
number = int(word, base=16)
bytestr = number.to_bytes(20, 'big')
b64 = base64.b64encode(bytestr).decode('ascii')
return b64
if __name__ == '__main__':
for word in sys.argv[1:]:
print(hex_to_b64(word))
which gives
localhost-2:coding $ python3 shaswitch.py 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8
W6ph5Mm5Pz8GgiULbPgzG37mj9g=

Why resort to python; OP wanted bash:
% openssl sha1 -binary <(echo -n 'password') | base64
W6ph5Mm5Pz8GgiULbPgzG37mj9g=

Related

How to use Ruby to decrypt plaintext that was encrypted with the openssl command line utility using a password and no salt?

I have encrypted some plaintext using the openssl command line utility using a password:
echo -n "foo" | openssl enc -e -base64 -rc4 -nosalt -pass pass:secretkey
This returns:
ryW2
How can I decrypt this value using Ruby?
Finally with reference of Above in Ruby
Encode
def encrypt(str, key)
cipher = OpenSSL::Cipher.new('RC4')
cipher.key = OpenSSL::Digest.digest('md5', key)
cipher.decrypt
Base64.encode64(cipher.update(str) + cipher.final)
end
encrypt('This is Test', 'Test')
=> "JGmpM+ewGA79qaZH\n"
Decode
def decrypt(encrypted_string, key)
decipher = OpenSSL::Cipher.new('RC4')
decipher.key = OpenSSL::Digest.digest('md5', key)
decipher.decrypt
decipher.update(Base64.decode64(encrypted_string)) + decipher.final
end
decrypt("JGmpM+ewGA79qaZH\n", "Test")
=> "This is Test"
Here is the command you would need to enter to encrypt the string foo into some ciphertext:
echo -n "foo" | openssl enc -e -base64 -rc4 -nosalt -pass pass:secretkey -p
And this returns:
key=610A2EE688CDA9E724885E23CD2CFDEE
ryW2
ryW2 is your base64 encoded ciphertext.
We have added -p so we can see the key that is used for encryption.
-p is required because OpenSSL uses an internal function EVP_BytesToKey to convert the passphrase to a key and there is no equivalent Ruby method to do this. Accordingly, you'll have to use this key value directly in Ruby when encrypting or decrypting instead of the passphrase.
Decryption is just as straight-forward:
echo "ryW2" | openssl enc -d -base64 -rc4 -nosalt -pass pass:secretkey
This returns:
foo
Given all this, here is how you would encrypt this string using Ruby to get the same value:
require 'openssl'
require 'base64'
plaintext = 'foo'
cipher = OpenSSL::Cipher.new('rc4')
cipher.encrypt
# Use the key that was generated by EVP_BytesToKey
key = '610A2EE688CDA9E724885E23CD2CFDEE'
# Convert the key to a byte string
key_bytes = key.scan(/../).map { |x| x.hex.chr }.join
cipher.key = key_bytes
ciphertext = cipher.update(plaintext) + cipher.final
base64 = Base64.strict_encode64(ciphertext)
This returns the same value as OpenSSL on the command line:
ryW2
Decryption is fairly straightforward:
decipher = OpenSSL::Cipher.new('rc4')
decipher.decrypt
decipher.key = key_bytes
decrypted = decipher.update(ciphertext) + decipher.final
This returns the original plaintext:
foo
Ultimately, encryption and decryption is fairly straightforward as long as you know what EVP_BytesToKey will return for a given pass. You can read more about EVP_BytesToKey here:
How to extract the IV vector generated by encrypt method from encrypted_strings
How do I refactor OpenSSL pkcs5_keyivgen in ruby?
https://github.com/crypto-browserify/EVP_BytesToKey
https://www.openssl.org/docs/man1.0.2/man3/EVP_BytesToKey.html
I wasn't happy that there is no built-in way to do this in Ruby. My other answer to this question is a functional workaround but it requires some time-consuming steps that I'm not crazy about. So I wrote a gem called evp_bytes_to_key that'll do it for you!
First install the gem:
gem install evp_bytes_to_key
Then generate your ciphertext:
echo -n "foo" | openssl enc -e -base64 -rc4 -nosalt -pass pass:secretkey
This returns:
ryW2
Then decrypt it in Ruby:
require 'evp_bytes_to_key'
require 'openssl'
require 'base64'
decipher = OpenSSL::Cipher.new('rc4')
decipher.decrypt
decipher.key = EvpBytesToKey::Key.new('secretkey', nil, 128, 0).key
ciphertext = Base64.strict_decode64('ryW2')
plaintext = decipher.update(ciphertext) + decipher.final
This returns the original plaintext:
foo
More examples for using this gem can be found in the README.

How to get sha256 hash output as binary data instead of hex using powershell?

Is there an in-built method to generate SHA256 as a binary data for a given string ? Basically, I am using below bash script to first generate a hash as a binary data and then do a base64 encoding. All I want to have is the exact thing in Powershell so that both the outputs are identical:
clearString="test"
payloadDigest=`echo -n "$clearString" | openssl dgst -binary -sha256 | openssl base64 `
echo ${payloadDigest}
In powershell, I can get the SHA256 in hex using the below script, but then struggling to get it as a binary data:
$ClearString= "test"
$hasher = [System.Security.Cryptography.HashAlgorithm]::Create('sha256')
$hash = $hasher.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($ClearString))
$hashString = [System.BitConverter]::ToString($hash)
$256String= $hashString.Replace('-', '').ToLower()
$sha256String="(stdin)= "+$256String
$sha256String
I can then use [Convert]::ToBase64String($Bytes) to convert to base64 but in between how do I get a binary data similar to bash output before I pass it to base64 conversion.
I think you are over-doing this, since the ComputeHash method already returns a Byte[] array (binary data). To do what (I think) you are trying to achieve, don't convert the bytes to string, because that will result in a hexadecimal string.
$ClearString= "test"
$hasher = [System.Security.Cryptography.HashAlgorithm]::Create('sha256')
$hash = $hasher.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($ClearString))
# $hash is a Byte[] array
# convert to Base64
[Convert]::ToBase64String($hash)
returns
n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=

AES 256 CBC encrypt with Ruby with OpenSSL not working

I'm trying to encrypt data with OpenSSL library in Ruby using passphrase.
Ruby code looks like this:
require('openssl')
require('base64')
cipher = OpenSSL::Cipher.new ('AES-256-CBC')
cipher.encrypt
cipher.iv = iv = cipher.random_iv
pwd = 'topsecret'
salt = OpenSSL::Random.random_bytes 8
iter = 10000
key_len = cipher.key_len
digest = OpenSSL::Digest::SHA256.new
key = OpenSSL::PKCS5.pbkdf2_hmac(pwd, salt, iter, key_len, digest)
cipher.key = key
puts "salt=#{salt.unpack('H*')[0]}"
puts "key=#{key.unpack('H*')[0]}"
puts "iv=#{iv.unpack('H*')[0]}"
encrypted = cipher.update 'my data to encrypt'
encrypted << cipher.final
puts "encrypted=#{Base64.strict_encode64(encrypted)}"
# it returns:
# salt=1332e5603cbc018a
# key=11a168cf01556a5ee3e22e049f0e65d3adcd75f39e32c7d19aec32a0ccb40d93
# iv=35a08f2d3e719abbee78a0f4fe47c938
# encrypted=E3Ag6cRL2R+xytgw01i6tKSFpV7s7bKoiiWvPA1FYxM=
Unfortunately, when I try to decrypt this, I get error bad magic number:
$ echo "E3Ag6cRL2R+xytgw01i6tKSFpV7s7bKoiiWvPA1FYxM=" | openssl enc -aes-256-cbc -base64 -d -p -pass pass:topsecret
bad magic number
However, when I try this in terminal by running openssl enc command, it works:
$ echo 'my data' | openssl enc -aes-256-cbc -base64 -p -pass pass:topsecret
salt=8135837A305553F2
key=8B4373ABD786BAC107F4112640E95E920C77C017FCEC18E1BD919CED42F0298E
iv =910637CE50FADF27D944B7A8DD239E6D
U2FsdGVkX1+BNYN6MFVT8oWa5P/oxZFwzMk1DRCSSGg=
$ echo "U2FsdGVkX1+BNYN6MFVT8oWa5P/oxZFwzMk1DRCSSGg=" | openssl enc - aes-256-cbc -d -p -base64 -pass pass:topsecret
salt=8135837A305553F2
key=8B4373ABD786BAC107F4112640E95E920C77C017FCEC18E1BD919CED42F0298E
iv =910637CE50FADF27D944B7A8DD239E6D
my data
I think I tried every possible combination of generating key/IV from passphrase but I get error every time. Is anyone able to spot where is the problem with this way? I've spent entire day on this.

Ruby OpenSSL DES encoding "wrong final block length"

I have the following encryption/decryption using OpenSSL (under Linux in my example):
$ echo test | openssl des -a -K 79616d7379616d73 -iv 1234567890ABCDEF
+ax5NT+Pjh0=
$ echo +ax5NT+Pjh0= | openssl des -a -d -K 79616d7379616d73 -iv 1234567890ABCDEF
test
All good. I need to translate it in Ruby code. As far as I did:
#!/usr/bin/env ruby
require 'openssl'
key = "\x79\x61\x6d\x73\x79\x61\x6d\x73"
iv = "\x12\x34\x56\x78\x90\xAB\xCD\xEF"
todecode = "+ax5NT+Pjh0="
def decode(encryptedString, key, iv)
decrypt = OpenSSL::Cipher::Cipher.new('des-cbc')
decrypt.decrypt
decrypt.key = key
decrypt.iv = iv
decrypt.update(encryptedString) + decrypt.final
end
decoded = decode(todecode, key, iv)
puts decoded
It throws me the following error:
decode.rb:14:in `final': wrong final block length (OpenSSL::Cipher::CipherError)`
What am I doing wrong? Did I select the wrong encryption or wrong use of key/iv?
Seems I forgot to base64_decode the string.
todecode = Base64::decode64("+ax5NT+Pjh0=")

Ruby openssl lib - Why does AES-256-CBC decrypting gives readable data without the correct IV?

Given the following script
require "openssl"
require "securerandom"
key = SecureRandom.random_bytes(32)
iv = SecureRandom.random_bytes(16)
aes = OpenSSL::Cipher::Cipher.new("AES-256-CBC")
aes.encrypt
aes.key = key
aes.iv = iv
crypted = aes.update("a"*50)+aes.final
aes = OpenSSL::Cipher::Cipher.new("AES-256-CBC")
aes.decrypt
aes.key = key
aes.iv = iv
puts aes.update(crypted)+aes.final
aes = OpenSSL::Cipher::Cipher.new("AES-256-CBC")
aes.decrypt
aes.key = key
puts aes.update(crypted)+aes.final
I get the following output (e.g.):
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
���y��f{�K~:y��aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Does I need to perform these CBC-style XOR operations, block size caring etc. on my own? I cannot find any example which is not simply calling the update function passing the string which should be decrypted. I already tried to add .dup to all string assignments to prevent inplace edit issues. What is going on here?
Environment: ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux]
The IV's purpose is to prevent discovery of the key by analyzing multiple messages containing the same data. It is not intended to obscure the information if you have the key. Without the proper IV, the first block of the ciphertext will be incorrect, but subsequent blocks will decrypt properly, as you found. The IV protects the key, not the data.
You get the same thing if you perform similar encryption via the openssl command line tools (here I replace the 8-byte IV embedded in the encrypted ciphertext with 8 space character):
echo "Ruby openssl lib - Why does AES-256-CBC decrypting gives readable data without the correct IV?" | \
openssl enc -aes-256-cbc -salt -pass pass:password | \
perl -pi -e "s/^(.{8})(.{8})/\1 /" | \
openssl enc -d -aes-256-cbc -salt -pass pass:password
▒▒▒▒▒▒t▒8q▒g] -▒▒▒▒▒▒7<s AES-256-CBC decrypting gives readable data without the correct IV?

Resources