22 June 2008

mcrypt randomness in PHP

The other day I was trying to debug a PHP program which was being really slow. I'm not bright enough to use proper debugging tools (like xdebug), so I just sprinkled in a bucketload of error_log() calls until I figured out what was gumming up the works.

It turned out to be an mcrypt_create_iv() call. Sometimes that call would run in a fraction of a second, and sometimes it would take over a minute, with no discernible pattern. I had pretty much done a copy-and-paste from the mcrypt_module_open() manual page, which shows using the MCRYPT_DEV_RANDOM constant as the second argument to mcrypt_create_iv(). It finally occurred to me to try using the MCRYPT_DEV_URANDOM constant (note the "U"), instead, and the encryptions immediately became consistently fast.

This was happening on a VMWare ESX guest running RHEL4. A Web search or two found a good comparison of /dev/random v. /dev/urandom, and my problem turned out to be a good illustration of /dev/random blocking the caller until sufficient entropy is attained.

23 comments:

  1. Anonymous1:20 AM

    You, sir, are my hero. I had been banging my head against the wall with a similar problem in a MediaWiki/AuthDrupal situation. The change from MCRYPT_DEV_RANDOM to MCRYPT_DEV_URANDOM made a world of difference. Thanks!

    ReplyDelete
  2. Glad that was helpful.

    c

    ReplyDelete
  3. Anonymous1:46 AM

    Excellent! I had tracked down the slow point myself but I found this post I had no idea *why* it was slow... And I happen to be one of those curious types that can't stand not understanding why some function is running arbitrarily slooooooowwwwww. :D Thanks!

    ReplyDelete
  4. Anonymous7:45 PM

    You Sir, have saved me hours of work. Thanks!

    ReplyDelete
  5. Anonymous1:56 AM

    You sir are a gentleman and a scholar

    ReplyDelete
  6. You've helped me a lots! Thanks! mcrypt with MCRYPT_DEV_RANDOM is unusable slow, they should disable it by default!

    Some of my friends say PHP is obsolete and they have their reasons. If I only had time I'd switch to Python ASAP.

    If I could return the favor a little, maybe you'll find useful my optimisations: when working with unicode strings - use regex (preg_match, preg_replace and such) instead of mb_strings functions. They are way faster! PHP manual says just oposite, but I tested a lots of code with and without regexes - perl regex in PHP is very fast. Then - unset is much slower than $x = null. Never use unset inside any loop. "===" is a little faster than "==".

    Oh, and never use '\b' inside unicode regex. It's broken in PHP, all versions. It took me hours to figure it out. There is no good workaround, you could try matching whitespace and non-word (listed) characters instead - but it won't be very fast.

    ReplyDelete
  7. Adam,

    I'm glad that the mcrypt hint was useful.

    I guess all the PHP stuff I've done has been in English with fairly uncomplicated character sets, so I don't know anything about the Unicode features.

    ReplyDelete
  8. Anonymous6:33 AM

    You saved my day sir, i've been banging my head on the wall the whole morning :)

    thanks!

    Andrea

    ReplyDelete
  9. Anonymous7:45 PM

    Actually the slowness is due to /dev/random than caused by PHP. If you read some docs on openssl or Apache, you'll see using urandom is recommended, meaning affecting not just PHP but everything that uses /dev/random will be slow.

    ReplyDelete
  10. Anonymous4:08 PM

    perfect! thanks.

    ReplyDelete
  11. Thanks! The login time to our intranet just went from 60 seconds to 0 seconds :)

    ReplyDelete
  12. SUPERB. Thank you. I would never have figured this out. I was rebooting the server, spinning in circles. Instant fix as per your instructions.

    ReplyDelete
  13. Anonymous3:14 AM

    Thank you. It was very helpful.

    ReplyDelete
  14. After taking 2 hours to track down some slowness in my application to mcrypt_iv_slow, your suggestion fixed my problem in seconds... Wonderful information!!

    ReplyDelete
  15. Thank you very much for posting this, it was very helpful!

    ReplyDelete
  16. Anonymous8:37 AM

    That what I call a very big help !
    As many others, I was struggling with the somehow ramdomly slow encryption on a VMware ubuntu.
    After some logging, I too found out that mcrypt_create_iv was the slow point.
    I'm very glag I found your post ! Thanx a lot ! You're my saviour !

    ReplyDelete
  17. Anonymous3:26 AM

    Great! Fixed it for me :) Thanks!

    ReplyDelete
  18. After 3 days of work, I finally isolated this issue and your suggestion saved me another 3 days. You're my hero!

    ReplyDelete
  19. Thanks, man. Can't believe that worked.

    ReplyDelete
  20. Anonymous7:34 PM

    Add me to the list of thankful.

    ReplyDelete
  21. Thanks!! You saved me a bunch of time!

    ReplyDelete
  22. Anonymous3:22 AM

    Thank you! :D

    ReplyDelete
  23. MCRYPT_DEV_URANDOM has been the default since 5.6.0 according to the manual pages of mcrypt-create-iv. So there is no need to jump through hoops anymore, at least if you are using the 5.6 branch.

    ReplyDelete