How do I decrypt files that are encrypted using des command in Ruby? - ruby

I need to decrypt files that are encrypted with this command:
des -E -u -k "some key" file.in file.out.enc
The decryption code in Ruby:
def decrypt(key)
cipher = OpenSSL::Cipher.new(‘des’).decrypt
cipher.key = key
File.open(‘file.out’, ‘wb’) do |outf|
decrypted = cipher.update(File.read(‘file.in.enc’)) + cipher.final
outf.write(decrypted)
end
end
I’m getting wrong final block length error when I run the code above. I also tried decrypting using the openssl command line tool and got a bad magic number error. Any advice?

Try switching the mode, from CBC to ECB for instance with OpenSSL::Cipher.new('DES-ECB').
If you check which ciphers your Ruby installation supports by looking at OpenSSL::Cipher.ciphers, you'll find a list of available modes too.

Related

Encrypt private key with passphrase using openssl ruby

In order to encrypt my private key and provide the passphrase. Currently, I am using bash cmd to get my encrypted key user_enc.pem
( openssl rsa -in user.pem -pubout && openssl rsa -in user.pem -aes256 ) > user_enc.pem
It would be helpful if someone can have a look and help me out to achieve this by using ruby probably with openssl.
OpenSSL::Cipher, which belong to Ruby standard library, provides symmetric algorithms for encryption and decryption. To use it just require OpenSSL in Ruby:
require 'openssl'
You can create a cipher instance specifying the Cipher algorithm. For example:
cipher = OpenSSL::Cipher::AES256.new(:CBC)
cipher.encrypt
key = cipher.random_key
iv = cipher.random_iv
data = "Confidential data"
encrypted = cipher.update(data) + cipher.final
For more details, check Ruby documentation: https://ruby-doc.org/stdlib-2.5.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html

How to use *.pub/*.sec files to encrypt/decrypt another file?

I created a pair of *.pub and *.sec files using the instructions and code given here:
https://www.gnupg.org/documentation/manuals/gnupg/Unattended-GPG-key-generation.html
(I am using this documentation because the ultimate application I have in
mind is an automated encryption/decryption pipeline.)
Q1: How can I use gpg2 and the *.pub file to encrypt another file?
Q2: How can I use gpg2 and the companion *.sec to decrypt a file encrypted using the companion *.pub file?
Important: I am interested only in answers that are suitable for programmatic implementation of an unsupervised operation. Please do not post answers that can only be carried out interactively. I am particularly interested in solutions that can be implemented in Python.
Please include precise pointers to the relevant documentation.
Some information about what you said:
I created a pair of *.pub and *.sec files using the instructions
Perfect to share the public key(s) with people you are exchanging information, but technically, when you are working programmatically, you don't need to use these files directly.
To be noted:
when you encrypt data, you will specify the recipient corresponding to the key to use to encrypt
when you decrypt data, you will first import the owner's public key, and then you will be able to decrypt data without specifying recipient, because it is embedded in the encrypted data
Actually, I am somewhat confused on this question. I have read conflicting information [...]
I agree it's quite confusing. In this situation, I think it is better to use version 1 for which there is more experience, and for which you find third party library to use.
In this answer, I tried:
python-gnupg (for GnuPG v1) which is a well known Python library and match perfectly your needs
cryptorito (for GnuPG v2) for which I didn't find enough documentation
With the first library, you can simply install it in your system:
sudo pip install python-gnupg
And then write a Python script to perform all the operations you want.
I wrote a simple one to answer your question.
#!/bin/python
import gnupg
GPG_DIR='/home/bsquare/.gnupg'
FILE_TO_ENCRYPT='/tmp/myFileToEncrypt'
ENCRYPTED_FILE='/tmp/encryptedFile'
DECRYPTED_FILE='/tmp/decryptedFile'
SENDER_USER='Bsquare'
TARGET_USER='Kjo'
gpg = gnupg.GPG(gnupghome=GPG_DIR)
print("Listing keys ...")
print(gpg.list_keys())
# On SENDER_USER side ... encrypt the file for TARGET_USER, with his public key (would match the kjo.pub if the key was exported).
print("Encrypting file " + FILE_TO_ENCRYPT + " for " + TARGET_USER + " ...")
with open(FILE_TO_ENCRYPT, "rb") as sourceFile:
encrypted_ascii_data = gpg.encrypt_file(sourceFile, TARGET_USER)
# print(encrypted_ascii_data)
with open(ENCRYPTED_FILE, "w+") as targetFile:
print("encrypted_ascii_data", targetFile)
# On TARGET_USER side ... decrypt the file with his private key (would match the kjo.sec if the key was exported).
print("Decrypting file " + ENCRYPTED_FILE + " for " + TARGET_USER + " ...")
with open(ENCRYPTED_FILE, "rb") as sourceFile:
decrypted_ascii_data = gpg.decrypt_file(sourceFile)
# print(decrypted_ascii_data)
with open(DECRYPTED_FILE, "w+") as targetFile:
print(decrypted_ascii_data, targetFile)
To be noted my keyring contains pub/sec pair for my Bsquare user, and the pub key of Kjo user.
when looking at encrypting and decrypting documents
this hints for pexpect; while I can provide regular expect scripts:
this is not directly a Python solution, but it should be easy to port.
as the tagline reads:
Pexpect makes Python a better tool for controlling other applications.
Encryption:
gpg --output doc.gpg --encrypt --recipient blake#cyb.org doc
as expect script; usage ./encrypt.exp doc blake#cyb.org 1234 (notice the space after the :):
#!/usr/bin/expect -f
set filename [lindex $argv 0]
set recipient [lindex $argv 1]
set passphrase [lindex $argv 2]
spawn gpg --output $filename.gpg --encrypt --recipient $recipient $filename
expect -exact "Enter pass phrase: "
send -- "$passphrase\r"
expect eof
Decryption:
gpg --output doc --decrypt doc.gpg
as expect script; usage: ./decrypt.exp doc 1234:
#!/usr/bin/expect -f
set filename [lindex $argv 0]
set passphrase [lindex $argv 1]
spawn gpg --output $filename --decrypt $filename.gpg
expect -exact "Enter pass phrase: "
send -- "$passphrase\r"
expect eof
Import:
keys can be imported into either key-chain with:
gpg --import somekey.sec
gpg --list-secret-keys
gpg --import somekey.pub
gpg --list-keys
there barely is anything to automate; however setting an imported key as "trusted" would require expect for automation. found this cheat-sheet, which has all commands on one page; and it also hints for: If you have multiple secret keys, it'll choose the correct one, or output an error if the correct one doesn't exist (which should confirm my comment below).
file ~/.gnupg/options is a user's options file; where one can eg. define the default key-server.
Since version 2.1.14, GPG supports the --recipient-file option, which lets you specify the public key to encrypt with without using the keyring. To quote the developer:
It is now possible to bypass the keyring and take the public key
directly from a file. That file may be a binary or an ascii armored
key and only the first keyblock from that file is used. A key
specified with this option is always fully trusted.
This option may be mixed with the standard -r options.
--hidden-recipient-file (or -F) is also available.
To futher assist some use cases the option
--no-keyring
has also been implemented. This is similar to
--no-default-keyring --keyring /dev/null
but portable to Windows and also ignores any keyring specified
(command line or config file).
So to encrypt, you would do:
gpg --output myfileenc --encrypt --recipient-file key.pub myfile
To automate, in addition to using expect or Python as explained in the other answers, you can also use the --batch option. (You will need to see which of the offered answers works best on your system).
No such option, however, is available for the secret key, and, as a matter of fact, the same version of PGP (2.1) deprecated the secring option in the --generate-key command, so this file is not even available any more. The generated key will need to be added to the keyring to be used for decryption.

OpenSSL key length too short in Ruby, not in Bash

I originally experimented with a simple encryption script in Bash and it worked pretty much as expected. However, I'm now trying to do the same thing in Ruby and the Ruby version seems function a little differently.
Bash
Encrypt
echo 'hello' | openssl enc -aes-256-cbc -a
Password: mypass
Result: U2FsdGVkX19rERfOXiKs97FgwIkLy3+ttZzaHkEoQyE=
Decrypt
echo 'U2FsdGVkX19rERfOXiKs97FgwIkLy3+ttZzaHkEoQyE=' | openssl aes-256-cbc -d -a
Password: mypass
Result: hello
Ruby
require "openssl"
require 'base64'
cipher = OpenSSL::Cipher.new('AES-256-CBC').encrypt
cipher.key = 'mypass'
This is what I've attempted in Ruby so far but I receive a OpenSSL::Cipher::CipherError: key length too short error. I would like to mimic Bash as much as possible.
OpenSSL uses a (largely undocumented) password based key derivation function (PBKDF) called EVP_BytesToKey using an 8 byte salt and an iteration count of 1. A magic and salt of 8 bytes each are prefixed to the ciphertext (check the first bytes of the result to see the magic).
Obviously "mypass" cannot be a correct key for AES. AES keys are 16, 24 or 32 byte binary values for the 128, 192 and 256 key sizes. You can however specify a key directly using the -K switch on the command line to make the code compatible with the Ruby Cipher object. In that case you need to specify the key using binary (a file) or hexadecimals for the openssl command line and in Ruby. You would also need to specify an IV.
Alternatively you would have to find an EVP_BytesToKey implementation for Ruby, but note that this is an old OpenSSL specific function with a completely insecure iteration count.

`public_decrypt': padding check failed (OpenSSL::PKey::RSAError)

Im trying to decrypt using a public key.
bob = TCPSocket.open(host, port)
cs_public_key = OpenSSL::PKey::RSA.new File.read 'c_public_key.pem'
puts "Alice is connected to bob"
bobs_public_key = ""
while line = bob.gets # Read lines from socket
bobs_public_key = bobs_public_key + line # and build them
end
bobs_public_key = JSON.parse(bobs_public_key)
puts "Alice recieved Bob's Public Key:"
puts bobs_public_key["key"]
#Error is on this line.
decypted = cs_public_key.public_decrypt(Base64.decode64(bobs_public_key["digest"]))
puts decypted
and am getting the error: 'public_decrypt': padding check failed (OpenSSL::PKey::RSAError)
Can someone explain what this error means and how to avoid it?
I ran into this error recently and tracked it down the the padding algorithm used, OpenSSL::PKey::RSA is defaulting to RSA_PKCS1_PADDING, but the message was generated in another system that defaulted to using the perfered RSA_PKCS1_OAEP_PADDING. The public/private encrypt/decrypt methods all take an optional second argument to set the padding, and this fixed the issue for me.
rsa.private_decrypt encrypted_text, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING
Turns out I was encrypting the digest using the wrong private key, so that public key was unable to decrypt it and threw that error.
Please make sure that the data you are trying to decrypt with Public key should be encrypted data. From the code, it looks like you are passing plain text instead of encrypted data.
Make sure that bobs_public_key["digest"] is encrypted. Generally it is signature of the data which is encrypted and that is to be passed. Check if your data has signature.
You are getting padding error because in RSA encryption, data is treated as a big number whatever is there in binary and then its power is raised and there is some padding. For plain text or slightly modified data, that padding check may fail.
I recently faced this padding issue while trying to decrypt the key using openssl command.
openssl rsautl -decrypt -in key_raw -inkey SIT_private.pem
RSA operation error
16764:error:0407109F:rsa routines:RSA_padding_check_PKCS1_type_2:pkcs decoding error:../openssl-1.1.1k/crypto/rsa/rsa_pk1.c:251:
16764:error:04065072:rsa routines:rsa_ossl_private_decrypt:padding check failed:../openssl-1.1.1k/crypto/rsa/rsa_ossl.c:491:
In my case using -oaep option solved the problem.
openssl rsautl -decrypt -in key_raw -inkey SIT_private.pem -oaep

AES/CBC/PKCS5Padding implementation in Ruby (for rails)

I need to decrypt text encrypted using AES/CBC/PKCS5Padding scheme. The encrypted text I got was generated using some Java software.
All values below are changed by me to something fictional.
What I get is a Key aHjgYFutF672eGIUGGVlgSETyM9VJj0K (256-bit = 32-chars * 8-bit)
and IV: rxYoks3c8hRRsL2P (16-bit)
and (I supposed) Base64 encoded encrypted result ETlAHS5ZcshKxQUaHVB8==
What I need is to decrypt in Ruby this ETlAHS5ZcshKxQUaHVB8== to get in the and a simple string, like 'blablablabla'
I tried to decrypt what I got using both Ruby and just common linux console openssl command.
NOTE: Key and IV below are not the ones used in real code:
# require 'openssl'
# require 'base64'
# decryption
aes = OpenSSL::Cipher::AES256.new(:CBC)
aes.decrypt
aes.padding = 1 # actually it's on by default
aes.key = "aHjgYFutF672eGIUGGVlgSETyM9VJj0K"
aes.iv="rxYoks3c8hRRsL2P"
aes.update(Base64::decode64("ETlAHS5ZcshKxQUaHVB8=="))+aes.final
=> OpenSSL::Cipher::CipherError: bad decrypt
Same as above but in console, key and iv converted to hex with:
$ echo -n $key256 | hexdump -e '16/1 "%02x"'
$ echo -n $iv | hexdump -e '16/1 "%02x"'
$ echo "ETlAHS5ZcshKxQUaHVB8==" | openssl enc -d -aes-256-cbc -a -K 61486a675946757446363732654749554747566c67534554794d39564a6a304b -iv 7278596f6b73336338685252734c3250
bad decrypt
140378046432928:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:539:
BTW. to get back original key and iv in the console you an use:
$ echo 61486a6... | xxd -r -p
#or , but then need to add \x before every character pair
$ eval `printf "\x61\x48......"
Please give me some clues as I hoped in the beginning that I will be able to use https://github.com/chicks/aes gem. The gem seems fine, it's just a nice wrapper for OpenSSL::Cipher::Cipher.
Is it possible that ruby/openssl use different PKCS, let's say PKCS#7, Java uses PKCS#5 and I need to preprocess my data ? Or there is a vesion mismatch between ruby/openssl and that Java's PKCS #7 and #5? #5 is meant for 8byte data blocks and #7 is for 16byte? Just a wild guess ...
The Ruby code in my first post is correct, the problem was this AES/CBC/PKCS5Padding used by Java part.
Java program should not use this scheme for AES-CBC-256. PKCS5 pads to a 64 bit (8 byte) block size, but AES-256-CBC uses 16 byte blocks. Therefore, PKCS7 must be used.

Resources