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?
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
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"
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:
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.