5

I use the following function to decrypt data on my server:

function decrypt($key, $text) {
    return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($text), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)));
}

I have read a lot about NOT using ECB however (and know it is deprecated so wanted to switch to CBC. Simply switching the mode to:

function decrypt($key, $text) {
    return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($text), MCRYPT_MODE_CBC, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND)));
}

does not work however. No errors are generated but the data returned is still encrypted.

What am I missing?

Updated code - still with errors:

$key = "hello"; 

$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_DEV_RANDOM);

function encrypt($key, $text) {
    return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv)));
}


function decrypt($key, $text) { 
    return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($text), MCRYPT_MODE_CBC, $iv));
}


$text = 12345;

echo "Plain Number : " . $text . "<br><br>";

$encrypted = encrypt($key, $text);
echo "AES Number : " . $encrypted . "<br><br>";

echo "Plain Number : ". decrypt($key, $encrypted) . "<br><br>";

this should work - but it returns the error:

blocksize in

blocksize in> Warning: mcrypt_encrypt()

[function.mcrypt-encrypt]: The IV parameter must be as long as the blocksize inblocksize in

blocksize in

JM4
  • 6,740
  • 18
  • 77
  • 125
  • 1
    Is the return data the same as what you passed in? If it is, then something's wrong with the decryption function. Otherwise it's working normally, and you've just used the wrong key/IV, and gotten garbage back out. – Marc B Nov 10 '10 at 22:22
  • @Marc B - yes, in fact I am running the encryption and decryption on the same page even to make sure info is good but I get errors. I am going to try and see some of the suggestions below make a difference. – JM4 Nov 10 '10 at 22:38

3 Answers3

7

When you decrypt you need to use the same IV as when you encrypted. It looks like you're generating a new, random IV during decryption.

It's OK to append or prepend the IV to the ciphertext. IVs are not secret but they should be unique for each encrypted message and only used once.

Cameron Skinner
  • 51,692
  • 2
  • 65
  • 86
  • 1
    @cameron - thanks for the help - i'll have to look back into IVs but in reality - what is the overall purpose of an IV if you are already using a key to encrypt the file to begin with (likely your IV is stored in the same location as the data itself which isn't very safe if your server is compromised. – JM4 Nov 10 '10 at 22:35
  • The IV is just there to prevent statistical cryptanalysis techniques. It's not a secret so it doesn't matter if it's disclosed. Using a random IV for each message means that if you encrypt the same message twice with the same key you get different ciphertexts. That means an eavesdropper cannot look for patterns in a sequence of messages, even if they know the IV for each message. This is important even if you're not encrypting the same message repeatedly. – Cameron Skinner Nov 10 '10 at 22:42
  • @cameron - there is a new edit above which still gives errors even when on the same page. – JM4 Nov 10 '10 at 22:50
  • Hmm. Not sure. Try checking that `mcrypt_get_iv_size` returns the right number and that `mcrypt_create_iv` actually generates an IV of the right length. It could be that one is reported in bits and the other in bytes. – Cameron Skinner Nov 10 '10 at 23:00
  • $size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC); returns 16 – JM4 Nov 10 '10 at 23:06
  • so it does appear size generates in Bytes whereas the encrypt/decrypt wants bits – JM4 Nov 10 '10 at 23:08
  • Seems OK. Maybe there's something wonky with the base64 encode/decode step. Try removing those bits (and the `trim`, obviously) and see if it works. That'll tell you if it's a crypto issue or an encoding issue. – Cameron Skinner Nov 10 '10 at 23:10
5

Your updated code has an issue with $iv being a global variable that's not available in the respective en-/decoding functions:

$key = "hello"; 

$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_DEV_RANDOM);

function encrypt($key, $text, $iv) {
    return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv)));
}

function decrypt($key, $text, $iv) { 
    return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($text), MCRYPT_MODE_CBC, $iv));
}

$text = 12345;

echo "Plain Number : " . $text . "<br><br>";

$encrypted = encrypt($key, $text, $iv);
echo "AES Number : " . $encrypted . "<br><br>";

echo "Plain Number : ". decrypt($key, $encrypted, $iv) . "<br><br>";

Or you can still rely on the global $iv by importing it into the local function scope:

function encrypt($key, $text) {
    global $iv; // or use $GLOBALS['iv] instead of $iv in the call below
    return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv)));
}

function decrypt($key, $text) { 
    global $iv; // or use $GLOBALS['iv] instead of $iv in the call below
    return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($text), MCRYPT_MODE_CBC, $iv));
}

but this is surely not a recommended practice as it couples your code to global variables.

Stefan Gehrig
  • 82,642
  • 24
  • 155
  • 189
  • `mcrypt_create_iv` eliminates the warning, but it seems to be horribly slow for some reason. – quickshiftin May 31 '13 at 06:31
  • Not sure why, but on my Linux systems using `MCRYPT_DEV_RANDOM` for the call to `mcrypt_create_iv` took a good minute. Using `MCRYPT_DEV_URANDOM` though is practically instant as one would expect. – quickshiftin May 31 '13 at 06:59
  • 1
    No doubt you notice this specifically on VM's. This is due to VM's not having a decent source of entropy for /dev/random. – Schodemeiss Jun 18 '14 at 12:46
3

Did you change the mode when encrypting this text as well?

Also, when using MCRYPT_MODE_CBC, you need to use the same key and IV during encryption and decryption. Randomized IV does not work with CBC.

Dan Grossman
  • 51,866
  • 10
  • 112
  • 101
  • i did change the encrypt mode as well; however, to your last point the 'randomized IV' not working - sample code on php.net seems to state otherwise (although it does use tripledes as cipher) : http://www.php.net/manual/en/function.mcrypt-cbc.php – JM4 Nov 10 '10 at 22:34
  • I think @Dan was saying that you can't decrypt with any old random IV, it must be the same as was used for encryption. ECB doesn't use an IV. – Cameron Skinner Nov 10 '10 at 22:43
  • Note that the IV for the ECB mode is zero, so the IV created for ECB is an empty string. For any other mode, the IV length is greater than zero. – Sven May 11 '16 at 14:34