SecurityManager encrypt/decrypt is not working properly.

Hello,

Today I came across an issue with SecurityManager encrypt/decrypt functionality.

The following simple code fails :




./protected/yiic shell

>> $data1 = "hi there";

>> $encdata = Yii::app()->securityManager->encrypt($data1);

>> $data2 = Yii::app()->securityManager->decrypt($encdata); 

PHP Warning:  mcrypt_generic_init(): Iv size incorrect; supplied length: 14, needed: 8 in /home/kefah/NetBeansProjects/yalla3/yii/framework/base/CSecurityManager.php on line 197

PHP Stack trace:

PHP   1. {main}() /home/kefah/NetBeansProjects/yalla3/customer/protected/yiic:0

PHP   2. require_once() /home/kefah/NetBeansProjects/yalla3/customer/protected/yiic:4

PHP   3. require_once() /home/kefah/NetBeansProjects/yalla3/customer/protected/yiic.php:7

PHP   4. CApplication->run() /home/kefah/NetBeansProjects/yalla3/yii/framework/yiic.php:33

PHP   5. CConsoleApplication->processRequest() /home/kefah/NetBeansProjects/yalla3/yii/framework/base/CApplication.php:135

PHP   6. CConsoleCommandRunner->run() /home/kefah/NetBeansProjects/yalla3/yii/framework/console/CConsoleApplication.php:88

PHP   7. ShellCommand->run() /home/kefah/NetBeansProjects/yalla3/yii/framework/console/CConsoleCommandRunner.php:62

PHP   8. ShellCommand->runShell() /home/kefah/NetBeansProjects/yalla3/yii/framework/cli/commands/ShellCommand.php:99

PHP   9. eval() /home/kefah/NetBeansProjects/yalla3/yii/framework/cli/commands/ShellCommand.php:147

PHP  10. CSecurityManager->decrypt() /home/kefah/NetBeansProjects/yalla3/yii/framework/cli/commands/ShellCommand.php(147) : eval()'d code:1

PHP  11. mcrypt_generic_init() /home/kefah/NetBeansProjects/yalla3/yii/framework/base/CSecurityManager.php:197



I use Fedora 13, with PHP 5.3.2. I have php mbstring enabled with mbstring.func_overload = 7 in /etc/php.ini as my php apps are heavily internationalized.

Checking up the SecurityManager sourcecode I found that it relies on strlen and substr, the use of those php functions is not i18n or binary safe.

Applying the following patch solved the problem for me. I think its safe to apply this patch, as it will guarantee proper handling of i18n or binary data within utf8 enabled php setups. It shouldn’t affect other php setups.




diff --git a/yii/framework/base/CSecurityManager.php b/yii/framework/base/CSecurityManager.php

index 4fe77af..2ebb28f 100644

--- a/yii/framework/base/CSecurityManager.php

+++ b/yii/framework/base/CSecurityManager.php

@@ -171,7 +171,7 @@ class CSecurityManager extends CApplicationComponent

        public function encrypt($data,$key=null)

        {

                $module=$this->openCryptModule();

-               $key=substr($key===null ? md5($this->getEncryptionKey()) : $key,0,mcrypt_enc_get_key_size($module));

+               $key=mb_substr($key===null ? md5($this->getEncryptionKey()) : $key,0,mcrypt_enc_get_key_size($module), 'latin1');

                srand();

                $iv=mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND);

                mcrypt_generic_init($module,$key,$iv);

@@ -191,11 +191,11 @@ class CSecurityManager extends CApplicationComponent

        public function decrypt($data,$key=null)

        {

                $module=$this->openCryptModule();

-               $key=substr($key===null ? md5($this->getEncryptionKey()) : $key,0,mcrypt_enc_get_key_size($module));

+               $key=mb_substr($key===null ? md5($this->getEncryptionKey()) : $key,0,mcrypt_enc_get_key_size($module), 'latin1');

                $ivSize=mcrypt_enc_get_iv_size($module);

-               $iv=substr($data,0,$ivSize);

+               $iv=mb_substr($data,0,$ivSize, 'latin1');

                mcrypt_generic_init($module,$key,$iv);

-               $decrypted=mdecrypt_generic($module,substr($data,$ivSize));

+               $decrypted=mdecrypt_generic($module,mb_substr($data,$ivSize, mb_strlen($data, 'latin1'), 'latin1'));

                mcrypt_generic_deinit($module);

                mcrypt_module_close($module);

                return rtrim($decrypted,"\0");

@@ -245,11 +245,11 @@ class CSecurityManager extends CApplicationComponent

         */

        public function validateData($data,$key=null)

        {

-               $len=strlen($this->computeHMAC('test'));

-               if(strlen($data)>=$len)

+               $len=mb_strlen($this->computeHMAC('test'), 'latin1');

+               if(mb_strlen($data, 'latin1')>=$len)

                {

-                       $hmac=substr($data,0,$len);

-                       $data2=substr($data,$len);

+                       $hmac=mb_substr($data,0,$len, 'latin1');

+                       $data2=mb_substr($data,$len, mb_strlen($data, 'latin1'), 'latin1');

                        return $hmac===$this->computeHMAC($data2,$key)?$data2:false;

                }

                else

@@ -281,6 +281,6 @@ class CSecurityManager extends CApplicationComponent

                        $func='md5';

                }

                $key=str_pad($func($key), 64, chr(0));

-               return $func((str_repeat(chr(0x5C), 64) ^ substr($key, 0, 64)) . pack($pack, $func((str_repeat(chr(0x36), 64) ^ substr($key, 0, 64)) . $data)));

+               return $func((str_repeat(chr(0x5C), 64) ^ mb_substr($key, 0, 64, 'latin1')) . pack($pack, $func((str_repeat(chr(0x36), 64) ^ mb_substr($key, 0, 64, 'latin1'))

        }

 }




Here is the patched securitymanager working:




>> $data1 = "hi there";

>> $encdata = Yii::app()->securityManager->encrypt($data1);

>> $data2 = Yii::app()->securityManager->decrypt($encdata); 

>> echo $data2;

hi there



Hmm. This could be problematic as the mbstring extension would be a new requirement for Yii. But there are even more places that are not mb safe, like e.g. CStringValidator. Personally i’d tend to migrate to the mb_* counterparts everywhere. We should open a ticket to collect all places that require a change.

I got the same problem as described above. Any workarounds?

[edit]

Solved for me … had an encoding issue.

1 Like