How to extract the IV vector generated by encrypt

2019-09-14 04:54发布

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

1条回答
姐就是有狂的资本
2楼-- · 2019-09-14 05:45

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"
查看更多
登录 后发表回答