Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
dev-marcel authored Apr 27, 2020
2 parents 62ff384 + af38348 commit f8a31fa
Show file tree
Hide file tree
Showing 29 changed files with 585 additions and 381 deletions.
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
composer.json
.idea/
composer.lock
.idea/
.php_cs.cache
53 changes: 24 additions & 29 deletions Command/DoctrineDecryptDatabaseCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,20 @@
namespace Ambta\DoctrineEncryptBundle\Command;

use Ambta\DoctrineEncryptBundle\DependencyInjection\DoctrineEncryptExtension;
use Doctrine\Common\Annotations\AnnotationReader;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;

/**
* Decrypt whole database on tables which are encrypted
* Decrypt whole database on tables which are encrypted.
*
* @author Marcel van Nuil <[email protected]>
* @author Michael Feinbier <[email protected]>
*/
class DoctrineDecryptDatabaseCommand extends AbstractCommand
{

/**
* {@inheritdoc}
*/
Expand All @@ -28,7 +25,7 @@ protected function configure()
$this
->setName('doctrine:decrypt:database')
->setDescription('Decrypt whole database on tables which are encrypted')
->addArgument("encryptor", InputArgument::OPTIONAL, 'The encryptor you want to decrypt the database with')
->addArgument('encryptor', InputArgument::OPTIONAL, 'The encryptor you want to decrypt the database with')
->addArgument('batchSize', InputArgument::OPTIONAL, 'The update/flush batch size', 20);
}

Expand All @@ -45,17 +42,17 @@ protected function execute(InputInterface $input, OutputInterface $output)
$batchSize = $input->getArgument('batchSize');

//If encryptor has been set use that encryptor else use default
if($input->getArgument('encryptor')) {
if(isset($supportedExtensions[$input->getArgument('encryptor')])) {
if ($input->getArgument('encryptor')) {
if (isset($supportedExtensions[$input->getArgument('encryptor')])) {
$this->subscriber->setEncryptor($supportedExtensions[$input->getArgument('encryptor')]);
} else {
if(class_exists($input->getArgument('encryptor')))
{
if (class_exists($input->getArgument('encryptor'))) {
$this->subscriber->setEncryptor($input->getArgument('encryptor'));
} else {
$output->writeln('\nGiven encryptor does not exists');
$output->writeln('Supported encryptors: ' . implode(', ', array_keys($supportedExtensions)));
$output->writeln('You can also define your own class. (example: Ambta\DoctrineEncryptBundle\Encryptors\Rijndael128Encryptor)');
$output->writeln('Supported encryptors: '.implode(', ', array_keys($supportedExtensions)));
$output->writeln('You can also define your own class. (example: \Ambta\DoctrineEncryptBundle\Encryptors\AES256Encryptor)');

return;
}
}
Expand All @@ -66,7 +63,7 @@ protected function execute(InputInterface $input, OutputInterface $output)

//Set counter and loop through entity manager meta data
$propertyCount = 0;
foreach($metaDataArray as $metaData) {
foreach ($metaDataArray as $metaData) {
if ($metaData->isMappedSuperclass) {
continue;
}
Expand All @@ -76,11 +73,11 @@ protected function execute(InputInterface $input, OutputInterface $output)
}

$confirmationQuestion = new ConfirmationQuestion(
"<question>\n" . count($metaDataArray) . " entities found which are containing " . $propertyCount . " properties with the encryption tag. \n\n" .
"Which are going to be decrypted with [" . $this->subscriber->getEncryptor() . "]. \n\n" .
"Wrong settings can mess up your data and it will be unrecoverable. \n" .
"I advise you to make <bg=yellow;options=bold>a backup</bg=yellow;options=bold>. \n\n" .
"Continue with this action? (y/yes)</question>", false
"<question>\n".count($metaDataArray).' entities found which are containing '.$propertyCount." properties with the encryption tag. \n\n".
'Which are going to be decrypted with ['.$this->subscriber->getEncryptor()."]. \n\n".
"Wrong settings can mess up your data and it will be unrecoverable. \n".
"I advise you to make <bg=yellow;options=bold>a backup</bg=yellow;options=bold>. \n\n".
'Continue with this action? (y/yes)</question>', false
);

if (!$question->ask($input, $output, $confirmationQuestion)) {
Expand All @@ -93,40 +90,39 @@ protected function execute(InputInterface $input, OutputInterface $output)
$valueCounter = 0;

//Loop through entity manager meta data
foreach($this->getEncryptionableEntityMetaData() as $metaData) {
foreach ($this->getEncryptionableEntityMetaData() as $metaData) {
$i = 0;
$iterator = $this->getEntityIterator($metaData->name);
$totalCount = $this->getTableCount($metaData->name);

$output->writeln(sprintf('Processing <comment>%s</comment>', $metaData->name));
$progressBar = new ProgressBar($output, $totalCount);
foreach($iterator as $row) {
foreach ($iterator as $row) {
$entity = $row[0];

//Create reflectionClass for each entity
$entityReflectionClass = New \ReflectionClass($entity);
$entityReflectionClass = new \ReflectionClass($entity);

//Get the current encryptor used
$encryptorUsed = $this->subscriber->getEncryptor();

//Loop through the property's in the entity
foreach($this->getEncryptionableProperties($metaData) as $property) {
foreach ($this->getEncryptionableProperties($metaData) as $property) {
//Get and check getters and setters
$methodeName = ucfirst($property->getName());

$getter = "get" . $methodeName;
$setter = "set" . $methodeName;
$getter = 'get'.$methodeName;
$setter = 'set'.$methodeName;

//Check if getter and setter are set
if($entityReflectionClass->hasMethod($getter) && $entityReflectionClass->hasMethod($setter)) {

if ($entityReflectionClass->hasMethod($getter) && $entityReflectionClass->hasMethod($setter)) {
//Get decrypted data
$unencrypted = $entity->$getter();

//Set raw data
$entity->$setter($unencrypted);

$valueCounter++;
++$valueCounter;
}
}

Expand All @@ -139,13 +135,12 @@ protected function execute(InputInterface $input, OutputInterface $output)
$this->entityManager->clear();
}
$progressBar->advance(1);
$i++;
++$i;

//Set the encryptor again
$this->subscriber->setEncryptor($encryptorUsed);
}


$progressBar->finish();
$output->writeln('');
//Get the current encryptor used
Expand All @@ -158,6 +153,6 @@ protected function execute(InputInterface $input, OutputInterface $output)
}

//Say it is finished
$output->writeln("\nDecryption finished values found: <info>" . $valueCounter . "</info>, decrypted: <info>" . $this->subscriber->decryptCounter . "</info>.\nAll values are now decrypted.");
$output->writeln("\nDecryption finished values found: <info>".$valueCounter.'</info>, decrypted: <info>'.$this->subscriber->decryptCounter."</info>.\nAll values are now decrypted.");
}
}
2 changes: 1 addition & 1 deletion Command/DoctrineEncryptDatabaseCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
} else {
$output->writeln('\nGiven encryptor does not exists');
$output->writeln('Supported encryptors: ' . implode(', ', array_keys($supportedExtensions)));
$output->writeln('You can also define your own class. (example: Ambta\DoctrineEncryptBundle\Encryptors\Rijndael128Encryptor)');
$output->writeln('You can also define your own class. (example: \Ambta\DoctrineEncryptBundle\Encryptors\AES256Encryptor)');
return;
}
}
Expand Down
11 changes: 9 additions & 2 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,21 @@ class Configuration implements ConfigurationInterface {
public function getConfigTreeBuilder() {

//Create tree builder
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('ambta_doctrine_encrypt');
if (method_exists(TreeBuilder::class, 'getRootNode')) {
$treeBuilder = new TreeBuilder('ambta_doctrine_encrypt');
$rootNode = $treeBuilder->getRootNode();
} else {
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('ambta_doctrine_encrypt');
}

// Grammar of config tree
$rootNode
->children()
->scalarNode('secret_key')
->end()
->scalarNode('encrypted_suffix')
->end()
->scalarNode('encryptor')
->end()
->scalarNode('encryptor_class')
Expand Down
41 changes: 26 additions & 15 deletions DependencyInjection/DoctrineEncryptExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Ambta\DoctrineEncryptBundle\DependencyInjection;

use Ambta\DoctrineEncryptBundle\Encryptors\AES192Encryptor;
use Ambta\DoctrineEncryptBundle\Encryptors\AES256Encryptor;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
Expand All @@ -14,22 +16,24 @@
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
*/
class DoctrineEncryptExtension extends Extension {

public static $supportedEncryptorClasses = array('rijndael256' => 'Ambta\DoctrineEncryptBundle\Encryptors\Rijndael256Encryptor',
'rijndael128'=> 'Ambta\DoctrineEncryptBundle\Encryptors\Rijndael128Encryptor');
class DoctrineEncryptExtension extends Extension
{
public static $supportedEncryptorClasses = [
AES256Encryptor::METHOD_NAME => AES256Encryptor::class,
AES192Encryptor::METHOD_NAME => AES192Encryptor::class,
];

/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container) {

public function load(array $configs, ContainerBuilder $container)
{
//Create configuration object
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);

//Set orm-service in array of services
$services = array('orm' => 'orm-services');
$services = ['orm' => 'orm-services'];

//set supported encryptor classes
$supportedEncryptorClasses = self::$supportedEncryptorClasses;
Expand All @@ -43,31 +47,38 @@ public function load(array $configs, ContainerBuilder $container) {
}
}

//If no encryption suffix then set the default
if (empty($config['encrypted_suffix'])) {
$config['encrypted_suffix'] = '<ENC>';
}


//If empty encryptor class, use Rijndael 256 encryptor
if(empty($config['encryptor_class'])) {
if(isset($config['encryptor']) and isset($supportedEncryptorClasses[$config['encryptor']])) {
if (empty($config['encryptor_class'])) {
if (isset($config['encryptor']) and isset($supportedEncryptorClasses[$config['encryptor']])) {
$config['encryptor_class'] = $supportedEncryptorClasses[$config['encryptor']];
} else {
$config['encryptor_class'] = $supportedEncryptorClasses['rijndael256'];
$config['encryptor_class'] = $supportedEncryptorClasses[AES256Encryptor::METHOD_NAME];
}
}

//Set parameters
$container->setParameter('ambta_doctrine_encrypt.encryptor_class_name', $config['encryptor_class']);
$container->setParameter('ambta_doctrine_encrypt.secret_key', $config['secret_key']);
$container->setParameter('ambta_doctrine_encrypt.encrypted_suffix', $config['encrypted_suffix']);

//Load service file
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load(sprintf('%s.yml', $services['orm']));

}

/**
* Get alias for configuration
* Get alias for configuration.
*
* @return string
*/
public function getAlias() {
public function getAlias()
{
return 'ambta_doctrine_encrypt';
}
}
85 changes: 85 additions & 0 deletions Encryptors/AES192Encryptor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

namespace Ambta\DoctrineEncryptBundle\Encryptors;

/**
* Class for AES256 encryption.
*
* @author Victor Melnik <[email protected]>
*/
class AES192Encryptor implements EncryptorInterface
{
const METHOD_NAME = 'AES-192';
const ENCRYPT_MODE = 'ECB';

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

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

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

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

/**
* {@inheritdoc}
*/
public function __construct($key, $suffix)
{
$this->secretKey = md5($key);
$this->suffix = $suffix;
$this->encryptMethod = sprintf('%s-%s', self::METHOD_NAME, self::ENCRYPT_MODE);
$this->initializationVector = openssl_random_pseudo_bytes(
openssl_cipher_iv_length($this->encryptMethod)
);
}

/**
* {@inheritdoc}
*/
public function encrypt($data)
{
if (is_string($data)) {
return trim(base64_encode(openssl_encrypt(
$data,
$this->encryptMethod,
$this->secretKey,
0,
$this->initializationVector
))).$this->suffix;
}

return $data;
}

/**
* {@inheritdoc}
*/
public function decrypt($data)
{
if (is_string($data)) {
$data = str_replace($this->suffix, '', $data);

return trim(openssl_decrypt(
base64_decode($data),
$this->encryptMethod,
$this->secretKey,
0,
$this->initializationVector
));
}

return $data;
}
}
Loading

0 comments on commit f8a31fa

Please sign in to comment.