Archive

Posts Tagged ‘behavior’

Cipher Behavior

August 11th, 2008 2 comments

If your want to cipher critical data of your cakephp model like passwords or emails, the cipher behavior of phtagr handles the symmetric encryption and decryption on the fly. For the symmetric encryption the cipher BlowFish is used, but other symmetric encryption algorithms are possible. This behavior is very useful if your data should not be stored in clear text in the database (e.g. external database connections).

The behavior could be configured simple for your needs. By default the behavior ciphers the password Model property.

The Behavior

First of all the PEAR package of BlowFish must be installed. This packages comes with an PHP implementation of BlowFish and does not required the MCrypt PHP extension. If the MCrypt extension is installed, the PEAR library will use it.

Usage

As mentioned above, the behavior ciphers the password property (table column) by default.

Model:

class User extends AppModel
{
  var $name = 'User';

  var $actsAs = array('Cipher' => array());

}

Following example saves the User model. Submit your login data via a formular. The $this->data might looks like:

Array
(
    [User] => Array
        (
            [id] => 1
            [username] => admin
            [password] => MySecret
        )
)

In the controller you save your submitted data:

Controller:

$this->User->save($this->data);

Now every time a User is saved, the password will be ciphered. The behavior only ciphers the properties, if the values do not start with the ciphered prefix $E$.

The ciphered data looks now like:

Array
(
    [User] => Array
        (
            [id] => 1
            [username] => admin
            [password] => $E$fIOGYbF6jQMXOOa5umzgXGWBfo7roAuk
        )
)

By default the behavior does not decrypt the properties and the decryption must be called explicitly:

Controller:

$user = $this->User->findByUsername($this->data['User']['username']);
$this->User->decrypt(&$user);
if ($user['User']['password'] == $this->data['User']['password']) {
// successful login
}

Configuration

Automatic Decryption

If you want to decrpyt all data automatically (might cost some CPU cycles and slows down your requests), you can configure the cipher behavior:

Model:

class User extends AppModel
{
  var $name = 'User';

  var $actsAs = array('Cipher' => array('autoDecypt' => true));
}

Model Properties

By default, the cipher behavior encrypts and decrypts the model property (table column) password. Other fields are also possible.

Model:

class User extends AppModel
{
  var $name = 'User';

  var $actsAs = array('Cipher' => array('cipher' => array('password', 'email', 'creditnumber')));
}

Custom Key

By default, the cipher behavior uses the Security.salt as cipher key. If you require a custom key, you can set in on the configuration:

Model:

class User extends AppModel
{
  var $name = 'User';

  var $actsAs = array('Cipher' => array('key' => 'MySuperSecureCipherKey'));
}

Note: Since the Security.salt is used from your configuration config/core.php and cipher key, it is very important to change the default value of Security.salt! Otherwise the encryption is not secure!

 /**
  * A random string used in security hashing methods.
  */
      Configure::write('Security.salt', 'NewSecureAndUnknownSecuritySaltForCake');

Salt and Padding

Before a value is encrypted it will be packed and padded. The clear text before the value is ciphered is surrounded by a salt and padded to a specific length block to $salt.$value.$padding.$salt.

The salt is used to avoid same encrypted results of same values. It is also used to discover the correct decryption. The padding is used to hide the original value lengths. By default, the salt and padding have the length of 4. This could be changed in the behavior configuration.

Note: The salt should be at least 2 characters long. Otherwise the successful decryption could not be detected well (apart of the diversity of the ciphered value).

Model:

class User extends AppModel
{
  var $name = 'User';

  var $actsAs = array('Cipher' => array('saltLen' => 6, 'padding' => 8));
}

Prefix

To distinguish between ciphered value and a clear text value, the ciphered value has a prefix. The default prefix is $E$ but could be change in the configuration.

Model:

class User extends AppModel
{
  var $name = 'User';

  var $actsAs = array('Cipher' => array('prefix' => '$ciphered$'));
}

Debug

The behavior dumps log message to the standard log if something goes wrong. Please watch these entries while developing with the cipher behavior.

Changing Security.salt

If you using this behavior and some data is already ciphered but have to change the Security.salt, you need to decrypt all the data with the old Security.salt, save the clear text and encrypt all values with the new Security.salt.

Decrypt all values with the old Security.salt value:

Model:

class User extends AppModel
{
  var $name = 'User';

  var $actsAs = array('Cipher' => array('noEncrypt' => true, 'autoDecrypt' => true));

  function clearCipher() {
    $users = $this->findAll();
    foreach ($users as $user) {
      $this->id = $user['User']['id'];
      $this->save($user);
    }
  }
}

Controller:

$this->User->clearCipher();

Encrypt now all values with the new Security.salt.

Model:

class User extends AppModel
{
  var $name = 'User';

  var $actsAs = array('Cipher' => array());

  function cipherAll() {
    $users = $this->findAll();
    foreach ($users as $user) {
      $this->id = $user['User']['id'];
      $this->save($user);
    }
  }
}

Controller:

$this->User->cipherAll();