Security::cipher() problems and Suhosin

This problem can now be solved by setting the encryption type in the CookieComponent to rijndael.

Over a week ago I migrated one of my sites to a MediaTemple (ve) Server. I installed nginx, PHP 5.3.2 (with Suhosin), MySQL, APC and Memcache. After a little configuration and debugging, everything was working smoothly except encrypted cookies. I was using my AutoLogin component and login never persisted, but regular cookies worked correctly. I thought it would be an easy fix but I was wrong (I will post another blog on this topic).

While trying to figure out the encryption problem, I debugged the CookieComponent. I tested each function individually around a fake array. I tested __implode(), __encrypt(), __explode() and Security::cipher(). My results were all over the place. When I tested the script locally, everything worked correctly and the ciphering process worked as it should (below). But on the live server, all the encryption strings would change each refresh and the un-cipher would never work.

Implode:
username|gearvOsh,password|dsadnas79dn7n1279dnadnadb1p2sdasd,hash|761c1168c645784b78f5f967160ab390,time|1286152916
Ciphered:
z~¡|ßÛí�"� =�'¥¾E¨ÿÏy� íåÇv¸”^ëS ¦ì•ˆxuŽ?��ãbm}ÜfÇ“„bËV´w±(ÐU�"éQ’Qñn²^6¿2r‰½ùé‹ÄáÄ,‡ ›d¤<ó`'ëÆìÏg$V")ËdÁ&µ‰
Base64 encode:
Q2FrZQ==.en6hfN/b7dMfij3Spb4ERaj/z3ng7eXHdriUXutTIKbslYh4dR6OP8bjYm193GbHk4Riy1a0d7Eowx+QVZbpUZJR8W6yXja/MnKJvfnpixsIxOHELIcgm2QHpDzzYCfrxhrsz2ckVggijwcpy2TBJrWJ
Using Cookie::__encrypt():
Q2FrZQ==.en6hfN/b7dMfij3Spb4ERaj/z3ng7eXHdriUXutTIKbslYh4dR6OP8bjYm193GbHk4Riy1a0d7Eowx+QVZbpUZJR8W6yXja/MnKJvfnpixsIxOHELIcgm2QHpDzzYCfrxhrsz2ckVggijwcpy2TBJrWJ
Base64 decode:
z~¡|ßÛí�"� =�'¥¾E¨ÿÏy� íåÇv¸”^ëS ¦ì•ˆxuŽ?Æãbm}ÜfÇ“„bËV´w±(ÐU�"éQ’Qñn²^6¿2r‰½ùé‹ÄáÄ,‡ ›d¤<ó`'ëÆìÏg$V")ËdÁ&µ‰
De-ciphered:
username|gearvOsh,password|dsadnas79dn7n1279dnadnadb1p2sdasd,hash|761c1168c645784b78f5f967160ab390,time|1286152916

As you can see from the debug (on my local machine), the beginning and resulting strings are the same. I then found out the problem was with Security::cipher() and srand(). I later found out that Suhosin was overriding the srand() and mt_srand() functions, which was causing my seed to always change. I tried disabling Suhosins overwrites, but to no avail.

// Did not work
ini_set('suhosin.mt_srand.ignore', 0);
ini_set('suhosin.srand.ignore', 0);

After some googling and a lot of frustration, I finally found a solution. Thanks to Edgar Valarezo, I was able to get my encrypted cookies working properly. However, I had to overwrite CakePHP's core Security class and will need to maintain it every time I upgrade Cake. Here is the new cipher() snippet for your convenience.

function cipher($text, $key = '') {
    $key .= Configure::read('Security.cipherSeed');
    $out = '';
    $textLength = strlen($text);
    $keyLength = strlen($key);
    $k = 0;
    for ($i = 0; $i < $textLength; $i++) {
        $seed = md5($key . $key[($k++) % $keyLength]);
        $mask = hexdec($seed[6] . $seed[9]); // :)
        $out .= chr(ord($text[$i]) ^ $mask);
    }
    return $out;
}

I see this as a temporary fix and would love any information on this topic. If you ran into this same problem, how did you correct? Is it possible to seed correctly with Suhosin? Thanks again!

Official release of the AutoLogin Component

Many of you have heard me mention a component that keeps your Auth session active, even after the browser is closed. Well I think its time to officially announce it, my AutoLogin component. This component ties into the Auth component and allows a user to "remember me" to keep them constantly logged in. All data is saved to cookies and encrypted and hashed to no hijacking can occur. The best part though, is that the component automatically and magically saves and deletes cookies without you having to configure it (although you can configure it, check out the docs).

Download the latest version of AutoLogin

In other script related news...
Commentia has been updated to v1.3
Resession has been updated to v1.8 (now with more Security!)