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:

Anonymous said...

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!

mbrisby said...

Glad that was helpful.

c

Anonymous said...

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!

Anonymous said...

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

Anonymous said...

You sir are a gentleman and a scholar

Adam said...

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.

mbrisby said...

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.

Anonymous said...

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

thanks!

Andrea

Anonymous said...

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.

Anonymous said...

perfect! thanks.

olga said...

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

Canton said...

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

Anonymous said...

Thank you. It was very helpful.

John Langley said...

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!!

John Langley said...

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

Anonymous said...

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 !

Anonymous said...

Great! Fixed it for me :) Thanks!

Yami said...

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

SilkyJackson said...

Thanks, man. Can't believe that worked.

Anonymous said...

Add me to the list of thankful.

hallamigo said...

Thanks!! You saved me a bunch of time!

Anonymous said...

Thank you! :D

Maarten Bodewes said...

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.