Skip to content

Commit

Permalink
Updated to Doctrine 2.5
Browse files Browse the repository at this point in the history
  • Loading branch information
dev-marcel committed Apr 8, 2015
1 parent 1bfc690 commit 8110500
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 45 deletions.
4 changes: 2 additions & 2 deletions DependencyInjection/DoctrineEncryptExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public function load(array $configs, ContainerBuilder $container) {
$services = array('orm' => 'orm-services');

//set supported encryptor classes
$supportedEncryptorClasses = array('aes256' => 'Ambta\DoctrineEncryptBundle\Encryptors\AES256Encryptor');
$supportedEncryptorClasses = array('variable' => 'Ambta\DoctrineEncryptBundle\Encryptors\VariableEncryptor');

//If no secret key is set, check for framework secret, otherwise throw exception
if (empty($config['secret_key'])) {
Expand All @@ -42,7 +42,7 @@ public function load(array $configs, ContainerBuilder $container) {

//If empty encryptor class, use AES256 encryptor
if (empty($config['encryptor_class'])) {
$config['encryptor_class'] = $supportedEncryptorClasses['aes256'];
$config['encryptor_class'] = $supportedEncryptorClasses['variable'];
}

//Set parameters
Expand Down
79 changes: 79 additions & 0 deletions Encryptors/VariableEncryptor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php

namespace Ambta\DoctrineEncryptBundle\Encryptors;

/**
* Class for variable encryption
*
* @author Victor Melnik <[email protected]>
*/
class VariableEncryptor implements EncryptorInterface {

/**
* @var string
*/
private $secretKey;

/**
* @var string
*/
private $initializationVector;

/**
* {@inheritdoc}
*/
public function __construct($key) {
$this->secretKey = md5($key);
$this->initializationVector = mcrypt_create_iv(
mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
MCRYPT_RAND
);
}

/**
* {@inheritdoc}
*/
public function encrypt($data) {

if(is_string($data)) {
return trim(base64_encode(mcrypt_encrypt(
MCRYPT_RIJNDAEL_256,
$this->secretKey,
$data,
MCRYPT_MODE_ECB,
$this->initializationVector
))) . "<ENC>";
}

/*
* Use ROT13 which is an simple letter substitution cipher with some additions
* Not the safest option but it makes it alot harder for the attacker
*
* Not used, needs improvement or other solution
*/
if(is_integer($data)) {
//Not sure
}

return $data;

}

/**
* {@inheritdoc}
*/
public function decrypt($data) {

if(is_string($data)) {
return trim(mcrypt_decrypt(
MCRYPT_RIJNDAEL_256,
$this->secretKey,
base64_decode($data),
MCRYPT_MODE_ECB,
$this->initializationVector
));
}

return $data;
}
}
25 changes: 11 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,25 +55,22 @@ I'm using Semantic Versioning like described [here](http://semver.org)
The following items will be done in order

1. ~~Review of complete code + fixes/improvements and inline documentation (2.1.1)~~
2. Add support for the other doctrine relationships (manyToMany, ManyToOne) (2.2)
3. Add "Encryption" (reformating based on key) of integers, data time object (2.3)
4. Recreate documentation (2.4)
5. Create example code (2.4)
6. Create an function to encrypt unencrypted database and vice versa (console command, migration, changed key, etc.) (2.5)
7. Look for a posibility of automatic encryption of query parameters (2.6)
8. Look for a positbility to override findOneBy for automatic encryption of parameters (2.7)
9. Add support to encrypt data by reference to other property as key (Encrypt data specific to user with user key etc.) (2.8)
10. Add "Encryption" (reformating based on key) on all other database types) [Doctrine documentation Types](http://doctrine-dbal.readthedocs.org/en/latest/reference/types.html) (3.0)
2. ~~Add support for the other doctrine relationships (manyToMany, ManyToOne) (2.2)~~
4. Recreate documentation (2.3)
5. Create example code (2.3)
6. Create an function to encrypt unencrypted database and vice versa (console command, migration, changed key, etc.) (2.4)
7. Look for a posibility of automatic encryption of query parameters (2.5)
8. Look for a posibility to override findOneBy for automatic encryption of parameters (2.6)
9. Add support to encrypt data by reference to other property as key (Encrypt data specific to user with user key etc.) (2.7)
10. Add [Format-preserving encryption](http://en.wikipedia.org/wiki/Format-preserving_encryption) for all data types [Doctrine documentation Types](http://doctrine-dbal.readthedocs.org/en/latest/reference/types.html) (3.0)

####Roadmap

#####Goals:

- v2.2 - 17-03-2015
- v2.3 - 20-03-2015
- v2.4 - 21-03-2015
- v2.5 - 31-03-2015
- v2.3 - 22-04-2015
- v2.4 - 30-04-2015
- v2.5 - 31-04-2015
- v2.6 - unknown
- v2.7 - unknown
- v2.8 - unknown
- v3.0 - 20-05-2015
2 changes: 1 addition & 1 deletion Resources/doc/configuration_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ ambta_doctrine_encrypt:
# Store a backup of this key on a secure location, losing this key will mean losing your data!
secret_key: ~ # Required
# If you want, you can use your own Encryptor. Encryptor must implements EncryptorInterface interface
# Default: Ambta\DoctrineEncryptBundle\Encryptors\AES256Encryptor
# Default: Ambta\DoctrineEncryptBundle\Encryptors\VariableEncryptor
encryptor_class: ~ #optional
```
41 changes: 17 additions & 24 deletions Subscribers/DoctrineEncryptSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,17 @@ private function processFields($entity, $isEncryptOperation = true) {
$encryptorMethod = $isEncryptOperation ? 'encrypt' : 'decrypt';

//Get the real class, we don't want to use the proxy classes
$realClass = ClassUtils::getClass($entity);
if(strstr(get_class($entity), "Proxies")) {
$realClass = ClassUtils::getClass($entity);
} else {
$realClass = get_class($entity);
}

//Get ReflectionClass of our entity
$reflectionClass = new ReflectionClass($realClass);
$properties = $reflectionClass->getProperties();


//Foreach property in the reflection class
foreach ($properties as $refProperty) {

Expand All @@ -143,19 +148,6 @@ private function processFields($entity, $isEncryptOperation = true) {
*/
$methodName = ucfirst($refProperty->getName());

/**
* Lazy loading, check if the property has an manyToOne relationship.
* if it has look if the set/get exists and recursively call this function based on the entity inside. Only if not empty.
*/
if($this->annReader->getPropertyAnnotation($refProperty, 'Doctrine\ORM\Mapping\ManyToOne')) {
if ($reflectionClass->hasMethod($getter = 'get' . $methodName) && $reflectionClass->hasMethod($setter = 'set' . $methodName)) {
$entity = $entity->$getter();
if(!empty($entity)) {
$this->processFields($entity, $isEncryptOperation);
}
}
}

/**
* If property is an normal value and contains the Encrypt tag, lets encrypt/decrypt that property
*/
Expand All @@ -168,35 +160,36 @@ private function processFields($entity, $isEncryptOperation = true) {
$propName = $refProperty->getName();
$entity->$propName = $this->encryptor->$encryptorMethod($refProperty->getValue());
} else {

//If private or protected check if there is an getter/setter for the property, based on the $methodName
if ($reflectionClass->hasMethod($getter = 'get' . $methodName) && $reflectionClass->hasMethod($setter = 'set' . $methodName)) {

//Get the information (value) of the property
$getInformation = $entity->$getter();
try {
$getInformation = $entity->$getter();
} catch(\Exception $e) {
$getInformation = null;
var_dump($e);
}

/**
* Then decrypt, encrypt the information if not empty, information is an string and the <ENC> tag is there (decrypt) or not (encrypt).
* The <ENC> will be added at the end of an encrypted string so it is marked as encrypted. Also protects against double encryption/decryption
*/
if($encryptorMethod == "decrypt") {
if(!is_null($getInformation) and !empty($getInformation) and is_string($getInformation)) {
if(substr($entity->$getter(), -5) == "<ENC>") {
$currentPropValue = $this->encryptor->$encryptorMethod(substr($entity->$getter(), 0, -5));
if(!is_null($getInformation) and !empty($getInformation)) {
if(substr($getInformation, -5) == "<ENC>") {
$currentPropValue = $this->encryptor->decrypt(substr($getInformation, 0, -5));
$entity->$setter($currentPropValue);
}
}
} else {
if(!is_null($getInformation) and !empty($getInformation) and is_string($getInformation)) {
if(!is_null($getInformation) and !empty($getInformation)) {
if(substr($entity->$getter(), -5) != "<ENC>") {
$currentPropValue = $this->encryptor->$encryptorMethod($entity->$getter()) . "<ENC>";
$currentPropValue = $this->encryptor->encrypt($entity->$getter());
$entity->$setter($currentPropValue);
}
}
}

} else {
throw new \RuntimeException(sprintf("Property %s isn't public and doesn't has getter/setter"));
}
}
}
Expand Down
5 changes: 1 addition & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,14 @@
"require": {
"php": ">=5.3.2",
"symfony/framework-bundle": ">=2.0",
"doctrine/orm": ">=2.5",
"ext-mcrypt": "*"
},
"autoload": {
"psr-0": { "Ambta\\DoctrineEncryptBundle": "" }
},
"target-dir": "Ambta/DoctrineEncryptBundle",
"authors": [
{
"name": "Victor Melnik",
"email": "[email protected]"
},
{
"name": "Marcel van Nuil",
"email": "[email protected]"
Expand Down

0 comments on commit 8110500

Please sign in to comment.