Peter Fitz
Peter Fitz

Reputation: 11

Reading data encrypted with PHP using Ruby

I'm in the process of replacing and old PHP system with a Ruby one. The developer here for me wrote his own encryption code (ugh). The old PHP uses the below code to encrypt some data. I'm having difficutly writing a "decrypt" method in ruby.

Preface
I'm aware of security issues with this existing php code (tripledes, no salt etc..). The new Ruby code doesn't store any sensitive data, but needs to at least READ data that the PHP has created.

old PHP code

// old PHP code
class encrypter {
  private $_crypt;
  private $_key;
  private $_algorithm;
  private $_mode;
  private $_init_vector;


    public function __construct( $key = 'SomeRandomStringThisOneIsOK', $algorithm = 'tripledes', $mode = 'ecb', $init_vector = false ) {
      $this->_key = $key;
      $this->_algorithm = $algorithm;
      $this->_mode = $mode;
      $this->_init_vector = $init_vector;
      $this->_crypt = mcrypt_module_open($algorithm, '', $mode, '') ;
      $random_seed = MCRYPT_RAND;
      //generate an initialization vector if none is given.
      $init_vector = ($init_vector === false)
        ? mcrypt_create_iv(mcrypt_enc_get_iv_size($this->_crypt), $random_seed)
        : substr($init_vector, 0, mcrypt_enc_get_iv_size($this->_crypt));

      $expected_key_size = mcrypt_enc_get_key_size($this->_crypt);

      // we dont need to know the real key, we just need to be able to confirm a hashed version
      $key = substr(md5($key), 0, $expected_key_size);

      mcrypt_generic_init($this->_crypt, $key, $init_vector);
    }


    public function encrypt($plain_string) {
      return base64_encode(mcrypt_generic($this->_crypt, $plain_string));
    }

    public function decrypt($encrypted_string) {
      return trim(mdecrypt_generic($this->_crypt, base64_decode($encrypted_string)));
    }

    public function __destruct() {
      $this->_crypt = null;
    }

    public function __sleep() {
      $this->_crypt = null;
      return array_keys( get_object_vars( $this ) );
    }

    public function __wakeup () {
      $this->__construct($this->_key, $this->_algorithm, $this->_mode, $this->_init_vector);
    }
  }

What I don't understand
I can't figure out how to emulate this line of the php in Ruby. Admittedly because I'm not sure 100% what the php is doing.

mcrypt_create_iv(mcrypt_enc_get_iv_size($this->_crypt), $random_seed)

Ruby I have so far
I was planning on using the Encryptor Gem (which wraps the OpenSSL methods). I'm not able to get ruby-mcrypt to install on OS X, and figured OpenSSL is built in so why not use it. Again I only need to be able to decyrpt data.

secret = "some_secret_key"
iv = "what goes here?"
Encryptor.default_options.merge!(:algorithm => 'des-ede-cbc', :key => secret)
decrypted_value = Encryptor.decrypt(:value => encrypted_value, :key => secret, :iv => iv)

Upvotes: 1

Views: 275

Answers (3)

Peter Fitz
Peter Fitz

Reputation: 11

I was able to get this working finally by using the following ruby. I'm not 100% sure why, but the Ruby lib doesn't need the IV.

Mcrypt.new(:tripledes, :ecb, Digest::MD5.hexdigest(key)[0,24])
plaintext  = crypto.decrypt(Base64.decode64('some_encryped_base_64_encoded_string')).strip

Upvotes: 0

jww
jww

Reputation: 102296

iv = "what goes here?"

I believe that is answered by:

$init_vector = ($init_vector === false)
    ? mcrypt_create_iv(mcrypt_enc_get_iv_size($this->_crypt), $random_seed)
    : substr($init_vector, 0, mcrypt_enc_get_iv_size($this->_crypt));

If init_vector is false, then a random iv is created. Otherwise, the iv passed into the function __construct is used.

As Frederick stated, the size of the initialization vector is based on the block cipher being used, and it can be fetched with mcrypt_enc_get_iv_size.

You have shown the encryptor class. The decryptor class will be a little different. It will use the existing iv. It will not create one, so the logic should be missing.


Just bike shedding, but this is a little weak:

$key = substr(md5($key), 0, $expected_key_size);

There are better ways to expand and extract entropy.

The folks on the Information Security Stack Exchange or Crypto Stack Exchange should be able to help with entropy extractors. They will probably tell you to use PBKDF, HKDF or use a HMAC rather than just MD5 (MD5 is not a pseudo random permutation or PRP function; while an HMAC possesses the property).

Upvotes: 0

Frederick Cheung
Frederick Cheung

Reputation: 84124

The line you've highlighted creates a new, random initialisation vector (IV) that is used to seed some of the crypto. The length of the IV depends on the algorithm used, mcrypt_enc_get_iv_size returns the correct length for the algorithm used.

To decrypt the data, you need to supply the same initialisation vector that was used to encrypt the message. You can't get this from the code, since it generates a fresh random one each time, albeit using a rather week source of randomness (if one was not explicitly passed to the constructor).

Upvotes: 1

Related Questions