Finding cipher algorithm of an encrypted file

April 2, 2019


Antoine Brunet




I was solving a CTF challenge when I came in contact with an encrypted file I downloaded from a FTP that I had just compromised. I decided to write a quick write up about how I managed to find the cipher algorithm used to encrypt the file in the goal of brute forcing it.

Share this article:

CTF context

I was solving a CTF challenge when I came in contact with an encrypted file I downloaded from a FTP that I had just compromised. I decided to write a quick write up about how I managed to find the cipher algorithm used to encrypt the file in the goal of brute forcing it.

Actually, there is no process or magic trick to truly define the cipher algorithm used from an encrypted file. What I managed to do here is to improve your chance to find the good cipher algorithm (In my CTF I was super lucky, in real life things can be much more difficult).

Operating mode

I downloaded the encrypted file secret.enc. After reading, it appears to be a base64 encoding.

$ cat secret.enc

I decode it with the following command:

$ base64 -d secret.enc
Salted__=/���&=�2����_���0�f�B�`�	�9M1�P�h�����E7�
                                                        ��HT�b����&�gz j`�~-�ɒ���2ڈ�"C�B�.b�45

As we can see it’s encrypted. So I placed the decoded message in a new file that I call encrypted.enc and use the file command to receive more information.

$ base64 -d secret.enc > encrypted.enc
$ file encrypted.enc
    encrypted.enc: openssl enc'd data with salted password

I was now informed that the file has been encrypted with Openssl with a salted password.

To simplify the brute force process, I had to find the algorithm used during the encryption phase.

The command openssl enc -ciphers will display a list of all the algorithms supported by Openssl, it helped me to define a first list of ciphers. I redirect them in a file I called ciphers.list and after a count it appears that Openssl supports 111 different ciphers.

My goal now was to reduce that list as much as I can.

In order to reduce that list it is necessary to get the length in bytes of the encrypted file.

$ wc -c encrypted.enc
    96 encrypted.enc

We have a file of 96 bytes. This number of bytes is divisible by 8, so there is a good chance that the cipher algorithm used to encrypt the file is using block cipher techniques (source). So I decided to remove all the stream ciphers from my file ciphers.list. After removing them, my list was reduced to 102 ciphers.

Let’s now create some samples in order to find a pattern between the encoded message and the encoded sample, as we know our encrypted file is 96 bytes long, the clear message is normally lower or equal to 96 bytes.

Let’s create some clear text sample with values between 0 and 96.

$ for sample in $(seq 0 8 96); do python -c "print 'A'*$sample" > $sample; done

So now let’s encrypt our samples with all our cipher algorithms defined in the file ciphers.list.
I use this script to achieve this task:

for cipher in $(cat ciphers.list); do
    for sample in $(seq 0 8 96); do
        openssl enc -$cipher -e -in $sample -out $sample$cipher.enc -k whyDudewhy

After I execute this script I received a bunch of encrypted files. I start by finding the file with 96 bytes length with the following command:

$ ls *.enc | xargs wc -c | grep '96 '
   96 64-aes-128-cbc.enc
   96 64-aes-128-ecb.enc
   96 64-aes128.enc
   96 64-aes-192-cbc.enc
   96 64-aes-192-ecb.enc
   96 64-aes192.enc
   96 64-aes-256-cbc.enc
   96 64-aes-256-ecb.enc
   96 64-aes256.enc
   96 64-camellia-128-cbc.enc
   96 64-camellia-128-ecb.enc
   96 64-camellia128.enc
   96 64-camellia-192-cbc.enc
   96 64-camellia-192-ecb.enc
   96 64-camellia192.enc
   96 64-camellia-256-cbc.enc
   96 64-camellia-256-ecb.enc
   96 64-camellia256.enc
   96 64-seed-cbc.enc
   96 64-seed-ecb.enc
   96 64-seed.enc
   96 72-aes-128-cbc.enc
   96 72-aes-128-ecb.enc
   96 72-aes128.enc
   96 72-aes-192-cbc.enc
   96 72-aes-192-ecb.enc
   96 72-aes192.enc
   96 72-aes-256-cbc.enc
   96 72-aes-256-ecb.enc
   96 72-aes256.enc
   96 72-bf-cbc.enc
   96 72-bf-ecb.enc
   96 72-bf.enc
   96 72-blowfish.enc
   96 72-camellia-128-cbc.enc
   96 72-camellia-128-ecb.enc
   96 72-camellia128.enc
   96 72-camellia-192-cbc.enc
   96 72-camellia-192-ecb.enc
   96 72-camellia192.enc
   96 72-camellia-256-cbc.enc
   96 72-camellia-256-ecb.enc
   96 72-camellia256.enc
   96 72-cast5-cbc.enc
   96 72-cast5-ecb.enc
   96 72-cast-cbc.enc
   96 72-cast.enc
   96 72-des3.enc
   96 72-des-cbc.enc
   96 72-des-ecb.enc
   96 72-des-ede3-cbc.enc
   96 72-des-ede3-ecb.enc
   96 72-des-ede3.enc
   96 72-des-ede-cbc.enc
   96 72-des-ede-ecb.enc
   96 72-des-ede.enc
   96 72-des.enc
   96 72-desx-cbc.enc
   96 72-desx.enc
   96 72-rc2-128.enc
   96 72-rc2-40-cbc.enc
   96 72-rc2-40.enc
   96 72-rc2-64-cbc.enc
   96 72-rc2-64.enc
   96 72-rc2-cbc.enc
   96 72-rc2-ecb.enc
   96 72-rc2.enc
   96 72-seed-cbc.enc
   96 72-seed-ecb.enc
   96 72-seed.enc

As we can see, I got some matches. These matches come from the clear text 64 bytes and the 72 bytes. I decided to only take the cipher algorithms which match with both clear texts. Now my list of cipher algorithms is reduced to only 14.

  • aes-128-cbc
  • aes-128-ecb
  • aes-192-cbc
  • aes-192-ecb
  • aes-256-cbc
  • aes-256-ecb
  • camellia-128-cbc
  • camellia-128-ecb
  • camellia-192-cbc
  • camellia-192-ecb
  • camellia-256-cbc
  • camellia-256-ecb
  • seed-cbc
  • seed-ecb

So, even if 14 is much better than 111, it is still long when you have to brute force them with a long password list. I decided to find the more common cipher in this list, and I chose aes-256-cbc. AES is clearly the most common algorithm in this list, the 256 key lengths is famous for being really secure and CBC (Cipher Block Chaining) is the default cipher used by Openssl for the AES algorithm as shown here:

$ openssl enc -aes256 -e -in text.clear -out blabla.enc
    enter aes-256-cbc encryption password:

For executing the brute force I had to install bruteforce-salted-openssl.

When you use the tool, keep in mind to set the message digest to sha256, which is the default message digest of Openssl (source). Also, you must know that bruteforce-salted-openssl will not keep the password if more than 10% of the decrypted data is not printable. It will move to the next password of the list, so this tool is unable to brute force: images (png, jpg…), videos(avi, mp4…), or other kinds of non printable files, which are apt to be encrypted by openssl.

I used this bruteforce-salted-openssl command: bruteforce-salted-openssl -t 15 -f rockyou.txt -c aes-256-cbc -d sha256 encrypted.enc to brute force the file.

After only a second the tool was able to find the password => bubbles.

Finally, I was able to decrypt the encoded message with the following Openssl command:

$ openssl enc -aes-256-cbc -d -in encrypted.enc -out clear.txt -k bubbles
$ cat clear.txt
    42 is the answer to the ultimate question of life the universe and everything