0

I'm having troubles to extract the IV generated with the encrypt method from encrypted_strings library for a specific password I provide. From the documentation, I see that this method generates a key and iv based on a password using a C library that calls the same method as openssl to generate the key and iv: EVP_BytesToKey.

What I'm trying to do is to be able to print the IV for any password I specify so I can port the encryption to another language.

Can you think of any method to extract/print this IV vector from a password?

These are the details of the algorithm, mode and padding this library uses:

  • ALGO: DES-EDE3
  • MODE: CBC
  • PADDING: PKCS5

The ruby script below prints out the encrypted message but no clue which iv was used.

#!/usr/bin/ruby
require 'encrypted_strings'

data = 'Whackabad'
password = 'bAJLyifeUJUBFWdHzVbykfDmPHtLKLMzViHW9aHGmyTLD8hGYZ'

encrypted_data = data.encrypt(:symmetric, :password => password)
printf "Data: #{data}\n"
printf "Encrypted Data: #{encrypted_data}"

I tried to use openssl as it allows me to print the iv and key generated using -p option but it uses a PKCS7 padding instead of PKCS5. So if I run the command below, doesn't print the same encrypted string as the ruby code above.

echo -n 'Whackabad' | openssl enc -des-ede3-cbc -nosalt -a -k bAJLyifeUJUBFWdHzVbykfDmPHtLKLMzViHW9aHGmyTLD8hGYZ

NOTE: -a: base64 encode, -k: password, and echo -n: removes the new line from the string so its exactly the same size as the ruby in string.

If I add -nopad option, I don't know how to pad the output to get exactly the same encrypted result.

Any help would be much appreciated

duckhunt
  • 333
  • 1
  • 6
  • 23
  • One often used method is to simply prefix the encrypted data with the IV. In that case just grab the IV from the first block_length bytes and skip past that for the encrypted data. – zaph Feb 23 '17 at 16:37
  • @zaph I'm not sure if the ruby code is actually prefixing the encrypted data with the IV. If so, I should take just the first block_length bytes? – duckhunt Feb 23 '17 at 17:20

1 Answers1

5

PKCS7 padding is basically the same as PKCS5. The reason you get a different result on the command line is that it only uses a single hash iteration, where the function used by encrypted_strings does 2048 iterations by default.

The function used, EVP_BytesToKey is described in the OpenSSL wiki, which include details of the algorithm. Reproducing it in Ruby might look something like this (using MD5 and 2048 iterations):

def hash(d, count)
  count.times do
    d = OpenSSL::Digest.digest('md5', d)
  end
  d
end

password = 'bAJLyifeUJUBFWdHzVbykfDmPHtLKLMzViHW9aHGmyTLD8hGYZ'

bytes = ''
last = ''

# For des-ede3-cbc, 24 byte key + 8 byte IV = 32 bytes.
while bytes.length < 32
  last = hash(last + password, 2048)
  bytes << last
end

key = bytes[0...24]
iv = bytes[24..-1]

You can use these values to decrypt the result of your code (add require 'base64' first):

# This is the result of your code:
encrypted_data = "AEsDXVcgh2jsTjlDgh+REg=="

# enrypted_strings produces base64 encoded results, so we decode first
encrypted_data = Base64.decode64(encrypted_data)

cipher = OpenSSL::Cipher.new('des-ede3-cbc')
cipher.decrypt
cipher.key = key
cipher.iv = iv

plain = cipher.update(encrypted_data) + cipher.final

puts plain #=> "Whackabad"
matt
  • 78,533
  • 8
  • 163
  • 197
  • Awesome! Thanks a lot for this answer. It really helped me! – duckhunt Feb 23 '17 at 18:18
  • And this is one reason OpenSSL is such a POS, the document is lazy-incomplete, it should not be necessary to go to the source code to determine the defaults! – zaph Feb 23 '17 at 18:25
  • @Matt - Please forgive my ignorance. Where is the documentation gap? The command `openssl enc` is documented din the [`enc` man pages](https://www.openssl.org/docs/man1.0.2/apps/enc.html). The documentation states: *"All the block ciphers normally use PKCS#5 padding also known as standard block padding"*. Similarly, the [`EVP_BytesToKey` man page](https://www.openssl.org/docs/man1.0.2/crypto/EVP_BytesToKey.html) documents the OpenSSL function. – jww Feb 23 '17 at 18:36
  • 1
    @jww I think that's maybe because `openssl enc` is documented but says nothing about the number of iterations it uses by default and there is no option to change that count. Was hard to realize, at least for me, that the num of iterations was the problem with the command line result. – duckhunt Feb 23 '17 at 19:16
  • There is ongoing work to fix those issues (iteration count and associated documentation): https://github.com/openssl/openssl/pull/2083 – Matt Caswell Feb 23 '17 at 21:04