How to generate RSA1 signature from file with a passphrase - ruby

I need to generate a RSA1 signature for a string using file with a passphrase
ex:
require "openssl"
pri = OpenSSL::PKey::RSA.new( File.read("cert.prv" ) )
string = 'Some string'
sign = pri.sign( "sha1", string.force_encoding("utf-8") )
puts sign
cert.prv file has a passphrase 123456 if I run this script from console I input this passphrase by hand...
But if this is run from a script how can I pass passphrase to OpenSSL ?

Pass the passphrase while opening the file.
pri = OpenSSL::PKey::RSA.new(File.read("cert.prv"), '123456')

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.

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=")

GPG: secret key & check passphrase

How to check that GPG secret key does not contain passphrase?
I wouldn't like import this key.
I found solution:
stdin, stdout, stderr = Open3.popen3("echo '\n\n\n\n\nsave' | gpg --command-fd 0 --homedir #{dir} --edit-key #{secret_key[:keyid]} passwd")
output = stderr.read
if output =~ /.../
...
end

Convert SHA1 password to its binary form

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=

OpenSSL Command Line and Ruby OpenSSL library differ when using same parameters to encrypt text

Note: Using OpenSSL for symmetric encryption of text.
I made a Ruby script to test OpenSSL and I found I'm getting different results. The key, iv, and ciphers are identical, so I would expect the results to be identical. But they are not. Here's my script:
require 'openssl'
require 'base64'
key = "00000000000000000000000000000000"
iv = "00000000000000000000000000000000"
### OPENSSL Command Line ###
puts "*** OpenSSL Command Line ***"
print "Encrypted via Command Line: "
string = `printf %s \"Hello\" | openssl enc -aes-128-cbc -K #{key} -iv #{iv} -base64`
puts string
puts string.inspect
print "Decrypted Data is: "
puts `printf %s \"BC2+AQJ6ZQx0al3GXba+EQ==\n\" | openssl enc -d -aes-128-cbc -K #{key} - iv #{iv} -base64`
puts "\n"
### Ruby OpenSSL Library ###
puts "*** OpenSSL Ruby Library ***"
cipher = OpenSSL::Cipher.new('aes-128-cbc').encrypt
cipher.padding = 1
cipher.key = key
cipher.iv = iv
encrypted_data = cipher.update("Hello")
encrypted_data << cipher.final
encrypted_data = Base64.encode64(encrypted_data)
puts "Encrypted via Ruby is: #{encrypted_data}"
puts encrypted_data.inspect
decipher = OpenSSL::Cipher.new('aes-128-cbc').decrypt
decipher.key = key
decipher.iv = iv
data = decipher.update(Base64.decode64(encrypted_data))
data << decipher.final
puts "Decrypted Data: #{data}"
The results are:
*** OpenSSL Command Line ***
Encrypted via Command Line: BC2+AQJ6ZQx0al3GXba+EQ==
"BC2+AQJ6ZQx0al3GXba+EQ==\n"
Decrypted Data is: Hello
*** OpenSSL Ruby Library ***
Encrypted via Ruby is: ZkeNEgsUXi1J7ps6kCQxdQ==
"ZkeNEgsUXi1J7ps6kCQxdQ==\n"
Decrypted Data: Hello
Just a curious result. Any idea what's causing the data to be different?
Just a guess, without knowing Ruby's OpenSSL interface:
You give the keys and initialization vector to the command line OpenSSL in hexadecimal encoding. E.g. your key and initialization vector are 0x000....
I suppose your Ruby library takes the key and initialization vector as binary data, e.g you are actually passing a key and initialization vector consisting of 0x30303030... (assuming ASCII or anything compatible to it) instead of 0x00000....
Pack them to a binary(Hex) sequence will fix it.
Test on my machine(Mac ox 10.11.1 ruby-2.2.3).
cipher.key = ["#{key}"].pack('H*')
cipher.iv = ["#{iv}"].pack('H*')
ruby Packs
decipher.key = ["#{key}"].pack('H*')
decipher.iv = ["#{iv}"].pack('H*')

Resources