Skip to content

Instantly share code, notes, and snippets.

@kaz29
Created April 21, 2012 01:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kaz29/2433176 to your computer and use it in GitHub Desktop.
Save kaz29/2433176 to your computer and use it in GitHub Desktop.
EncryptBehavior for CakePHP2.x
<?php
/**
* Encrypt behavior
*
*/
class EncryptBehavior extends ModelBehavior {
// Encryption settings
const CIPHER = MCRYPT_RIJNDAEL_128;
const MODE = MCRYPT_MODE_CBC;
const KEY_SIZE = 32;
const IV_SIZE = 16;
const IV_SOURCE = MCRYPT_DEV_URANDOM;
private $key = null;
public function setup(Model $Model, $config = array())
{
if(!extension_loaded('mcrypt')){
throw new RuntimeException('EncryptBehavior requires the mcrypt extension');
} elseif(!isset($config['key'])){
throw new RuntimeException('Bad configuration');
} elseif(($length = mb_strlen($config['key'], '8bit')) !== self::KEY_SIZE){
throw new RuntimeException('Encryption key length must to be ' . self::KEY_SIZE . ' byte, but got ' . $length);
} else {
$_settings = array(
'key' => null,
'fields' => array(),
);
$this->settings[$Model->name] = array_merge($_settings, $config);
}
}
public function encrypt(Model $Model, $token)
{
$data = serialize($token);
$iv = mcrypt_create_iv(self::IV_SIZE, self::IV_SOURCE);
$cipherText = mcrypt_encrypt(self::CIPHER, $this->settings[$Model->name]['key'], $data, self::MODE, $iv);
return base64_encode($iv . $cipherText);
}
public function decrypt(Model $Model, $cipherText)
{
$cipherText = base64_decode($cipherText);
$iv = substr($cipherText, 0, self::IV_SIZE);
$cipherText = substr($cipherText, self::IV_SIZE);
$data = mcrypt_decrypt(self::CIPHER, $this->settings[$Model->name]['key'], $cipherText, self::MODE, $iv);
return unserialize($data);
}
public function beforeSave(Model $Model)
{
foreach ($this->settings[$Model->name]['fields'] as $field) {
if (!array_key_exists($field, $Model->data[$Model->name]))
continue ;
$Model->data[$Model->name][$field] = $this->encrypt($Model, $Model->data[$Model->name][$field]);
}
return true;
}
public function afterFind(Model $Model, $results, $primary)
{
if ($primary === false) {
foreach($results as $key => &$value) {
foreach ($this->settings[$Model->name]['fields'] as $field) {
if ($key === $field) {
$value = $this->decrypt($Model, $value);
}
}
}
} else {
foreach($results as &$data) {
foreach ($this->settings[$Model->name]['fields'] as $field) {
if (isset($data[$Model->name][$field])) {
$data[$Model->name][$field] = $this->decrypt($Model, $data[$Model->name][$field]);
}
}
}
}
return $results;
}
}
<?php
$encryption_params=null;
class Encryption extends CakeTestModel
{
var $name = 'Encryption';
public function __construct($id = false, $table = null, $ds = null) {
global $encryption_params;
if (is_null($encryption_params)) {
$this->actsAs = array(
'Encrypt'
);
} else {
$this->actsAs = array(
'Encrypt' => $encryption_params,
);
}
parent::__construct($id, $table, $ds);
}
}
class EncriptBehaviorTestCase extends CakeTestCase
{
public $fixtures = array(
'app.encryption',
);
/**
* setUp method
*
* @return void
*/
public function setUp() {
parent::setUp();
}
/**
* tearDown method
*
* @return void
*/
public function tearDown() {
parent::tearDown();
unset($this->Encryption);
}
/**
* @test
*/
function BadConfiguration()
{
try {
$this->Encryption = ClassRegistry::init('Encryption');
} catch (RuntimeException $e) {
return ;
}
$this->fail('BadConfiguration');
}
/**
* @test
*/
function EncryptionKeyLengthError1()
{
try {
global $encryption_params;
$encryption_params = array('key'=>'');
$this->Encryption = ClassRegistry::init('Encryption');
} catch (RuntimeException $e) {
return ;
}
$this->fail('Encryption key length Error1');
}
/**
* @test
*/
function EncryptionKeyLengthError2()
{
try {
global $encryption_params;
$encryption_params = array('key' => "1234567890123456789012345678901");
$this->Encryption = ClassRegistry::init('Encryption');
} catch (RuntimeException $e) {
return ;
}
$this->fail('Encryption key length Error2');
}
/**
* @test
*/
function EncryptionKeyLengthError3()
{
try {
global $encryption_params;
$encryption_params = array('key' => "123456789012345678901234567890123");
$this->Encryption = ClassRegistry::init('Encryption');
} catch (RuntimeException $e) {
return ;
}
$this->fail('Encryption key length Error3');
}
/**
* @test
*/
function SimpleEncryption()
{
global $encryption_params;
$encryption_params = array('key' => "12345678901234567890123456789012");
$this->Encryption = ClassRegistry::init('Encryption');
$plaintext = 'TESTTEST';
$encrypted = $this->Encryption->encrypt($plaintext);
$this->assertFalse(empty($encrypted));
$decrypted = $this->Encryption->decrypt($encrypted);
$this->assertFalse(empty($decrypted));
$this->assertNotEqual($plaintext, $encrypted);
$this->assertEqual($plaintext, $decrypted);
}
/**
* @test
*/
function AutoEncryption()
{
global $encryption_params;
$encryption_params = array(
'key' => "12345678901234567890123456789012",
'fields' => array('encrypt'),
);
$this->Encryption = ClassRegistry::init('Encryption');
$plaintext1 = 'TESTTESTTEST';
$plaintext2 = 'FOOBAR';
$data = array(
'encrypt' => $plaintext1,
);
$this->Encryption->create();
$this->Encryption->set($data);
$actual = $this->Encryption->save();
$this->assertNotEqual($actual['Encryption']['encrypt'], $plaintext1);
$data = array(
'encrypt' => $plaintext2,
);
$this->Encryption->create();
$this->Encryption->set($data);
$actual = $this->Encryption->save();
$this->assertNotEqual($actual['Encryption']['encrypt'], $plaintext2);
$actual = $this->Encryption->find('all', array('order'=>array('id')));
$expected = array(
'Encryption' => array(
'id' => 1,
'encrypt' => $plaintext1,
)
);
$this->assertEqual($actual[0], $expected);
$expected = array(
'Encryption' => array(
'id' => 2,
'encrypt' => $plaintext2,
)
);
$this->assertEqual($actual[1], $expected);
}
}
<?php
class EncryptionFixture extends CakeTestFixture {
var $name = 'Encryption';
var $fields = array(
'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'length' => 20, 'key' => 'primary'),
'encrypt' => array('type' => 'text', 'null' => true, 'default' => NULL),
);
var $records = array();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment