Reputation: 11
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
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
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
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