2

I'm using an mcrypt function to encrypt a block of text using TripleDES. 90% of the time it works as it should and I can decrypt just fine. The other 10% though I just cannot decrypt it at all - as if I have the wrong key or the data is mangled.

The function is as follows:

function enc($text, $key, $iv) {
  $text_num = str_split($text, 8);
  $text_num = 8 - strlen($text_num[count($text_num)-1]);

  for ($i=0; $i < $text_num; $i++) {
    $text = $text . chr($text_num);
  }

  $cipher = mcrypt_module_open(MCRYPT_TRIPLEDES, '', 'cbc', '');
  mcrypt_generic_init($cipher, $key, $iv);
  $decrypted = mcrypt_generic($cipher, $text);
  mcrypt_generic_deinit($cipher);
  return base64_encode($decrypted);
}

They key & IV are the correct lengths (24/8 respectively) and never change. Like I said, it runs the exact same code on everything but only 10% fail in this way.

Is there anything I could be passing in $text that is causing this? Does it not like certain character sets? Or can this happen due to low memory/some other server condition?

Any help pinning this down would be much appreciated. Thanks!

  • How long are the plaintexts that fail? Are they consistently less than a block or more than a block? Are they exactly a multiple of blocks? Your code does not specify padding. – rossum Aug 26 '11 at 20:32
  • Plaintexts are roughly 1500 chars +/- 300. The padding I'm not so sure about - it's not done before it gets passed to this function so I guess none is performed. I inherited the code and not being crypto-savvy by any stretch, I wouldn't know what to change. – Force10 Bob Aug 26 '11 at 20:40
  • Why is it doing all that stuff the `$text`? It looks like it's trying to pad it, but that is not necessary. What happens if you just remove the first 6 lines of the function (eg: from `$text_num = str...` to the end of the for loop) – NullUserException Aug 26 '11 at 20:58
  • 3DES has a 64 bit blocksize (8 bytes). You need to look at the *exact* size of the plaintext to check at it in terms of number of blocks. Look in the documentation for mention of padding, probably PKCS5 or possibly PKCS7. Is your "10%" failure actually 12.5% failure (1 in 8)? That would tend to point to something relating to blocking. – rossum Aug 26 '11 at 21:02
  • Heh, I don't know. I've removed those lines and it seems to be working just fine in my test script. Whether it solves the 10% issue I'm not sure. Is it plausible the random corruption was coming from that? – Force10 Bob Aug 26 '11 at 21:02
  • I've added what I *think* is PKCS5 padding, int he form of the following: `$blocksize = mcrypt_get_block_size('des', 'cbc'); $pad = $blocksize - (strlen($text) % $blocksize); $text = $text . str_repeat(chr($pad), $pad);` It seems to be working ok and the .NET decoder tool is reading this all fine too (it would have the occasional prblem with other encrypted texts). Does that look right? – Force10 Bob Aug 26 '11 at 21:22
  • My PHP is not good, but that looks to be PKCS5/7 padding. Just be careful to add a full block of padding when the plaintext ends exactly on a block boundary. – rossum Aug 26 '11 at 21:43
  • Thanks rossum. It's been nearly a full day and not a single failure so far. I think that might have gone and fixed it (I'd have expected at least a couple by now). Stick that in a reply if you want & I'll give you a tick :) – Force10 Bob Aug 27 '11 at 14:11

1 Answers1

0

(Copied from comment) 3DES has a 64 bit blocksize (8 bytes). You need to look at the exact size of the plaintext to check at it in terms of number of blocks. Look in the documentation for mention of padding, probably PKCS5 or possibly PKCS7. Is your "10%" failure actually 12.5% failure (1 in 8)? That would tend to point to something relating to blocking.

rossum
  • 15,344
  • 1
  • 24
  • 38