Skip to content

Commit

Permalink
Pass column names as associated data for AesGcm.
Browse files Browse the repository at this point in the history
Create a defaultAssociatedData for encryption without.
  • Loading branch information
mogilvie committed May 28, 2024
1 parent 91e93fd commit b597209
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 36 deletions.
47 changes: 24 additions & 23 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,29 +23,30 @@ public function getConfigTreeBuilder(): TreeBuilder

$rootNode
->children()
->scalarNode('encrypt_key')->end()
->scalarNode('method')->defaultValue('OpenSSL')->end()
->scalarNode('subscriber_class')->defaultValue(DoctrineEncryptSubscriber::class)->end()
->scalarNode('encryptor_class')->defaultValue(AesCbcEncryptor::class)->end()
->scalarNode('is_disabled')->defaultValue(false)->end()
->arrayNode('connections')
->treatNullLike([])
->prototype('scalar')->end()
->defaultValue([
'default',
])
->end()
->arrayNode('annotation_classes')
->treatNullLike([])
->prototype('scalar')->end()
->defaultValue([
Encrypted::class,
])
->end()
->booleanNode('enable_twig')
->defaultTrue()
->info('Enable or disable Twig functionality')
->end()
->scalarNode('encrypt_key')->end()
->scalarNode('default_associated_data')->defaultValue(null)->end()
->scalarNode('method')->defaultValue('OpenSSL')->end()
->scalarNode('subscriber_class')->defaultValue(DoctrineEncryptSubscriber::class)->end()
->scalarNode('encryptor_class')->defaultValue(AesCbcEncryptor::class)->end()
->scalarNode('is_disabled')->defaultValue(false)->end()
->arrayNode('connections')
->treatNullLike([])
->prototype('scalar')->end()
->defaultValue([
'default',
])
->end()
->arrayNode('annotation_classes')
->treatNullLike([])
->prototype('scalar')->end()
->defaultValue([
Encrypted::class,
])
->end()
->booleanNode('enable_twig')
->defaultTrue()
->info('Enable or disable Twig functionality')
->end()
->end()
;

Expand Down
1 change: 1 addition & 0 deletions src/DependencyInjection/SpecShaperEncryptExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public function load(array $configs, ContainerBuilder $container)
}

$container->setParameter($this->getAlias().'.encrypt_key', $encryptKey);
$container->setParameter($this->getAlias().'.default_associated_data', $config['default_associated_data']);
$container->setParameter($this->getAlias().'.method', $config['method']);
$container->setParameter($this->getAlias().'.subscriber_class', $config['subscriber_class']);
$container->setParameter($this->getAlias().'.encryptor_class', $config['encryptor_class']);
Expand Down
4 changes: 2 additions & 2 deletions src/Encryptors/AesCbcEncryptor.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public function setSecretKey(string $secretKey): void
/**
* @throws \Exception
*/
public function encrypt(?string $data): ?string
public function encrypt(?string $data, ?string $columnName = null): ?string
{
// If not data return data (null)
if (is_null($data)) {
Expand Down Expand Up @@ -79,7 +79,7 @@ public function encrypt(?string $data): ?string
/**
* @throws \Exception
*/
public function decrypt(?string $data): ?string
public function decrypt(?string $data, ?string $columnName = null): ?string
{
// If the value is an object or null then ignore
if (is_null($data)) {
Expand Down
18 changes: 14 additions & 4 deletions src/Encryptors/AesGcmEncryptor.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class AesGcmEncryptor implements EncryptorInterface

private EventDispatcherInterface $dispatcher;

private ?string $defaultAssociatedData;

/**
* OpenSslEncryptor constructor.
*/
Expand All @@ -38,10 +40,15 @@ public function setSecretKey(string $secretKey): void
$this->secretKey = $secretKey;
}

public function setDefaultAssociatedData(?string $defaultAssociatedData): void
{
$this->defaultAssociatedData = $defaultAssociatedData;
}

/**
* @throws \Exception
*/
public function encrypt(?string $data): ?string
public function encrypt(?string $data, ?string $columnName): ?string
{
if (is_null($data)) {
return null;
Expand All @@ -55,14 +62,16 @@ public function encrypt(?string $data): ?string
$ivsize = openssl_cipher_iv_length(self::METHOD);
$iv = openssl_random_pseudo_bytes($ivsize);
$tag = '';
$associatedData = $columnName ?? $this->defaultAssociatedData;

$ciphertext = openssl_encrypt(
$data,
self::METHOD,
$key,
OPENSSL_RAW_DATA,
$iv,
$tag
$tag,
$associatedData
);

if ($ciphertext === false) {
Expand All @@ -75,7 +84,7 @@ public function encrypt(?string $data): ?string
/**
* @throws \Exception
*/
public function decrypt(?string $data): ?string
public function decrypt(?string $data, ?string $columnName): ?string
{
if (is_null($data)) {
return null;
Expand Down Expand Up @@ -103,7 +112,8 @@ public function decrypt(?string $data): ?string
$key,
OPENSSL_RAW_DATA,
$iv,
$tag
$tag,
$columnName
);

if ($plaintext === false) {
Expand Down
7 changes: 6 additions & 1 deletion src/Encryptors/EncryptorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@ public function __construct(EventDispatcherInterface $dispatcher)
* Create service will return the desired encryption service.
*
* @param string $encryptKey 256-bit encryption key
* @param string $defaultAssociatedData A fallback string used for AES-GBC-256 encryption.
* @param string|null $encryptorClass the desired encryptor, defaults to OpenSSL, but can be overridden by passing a classname
*/
public function createService(string $encryptKey, ?string $encryptorClass = self::SUPPORTED_EXTENSION_OPENSSL): EncryptorInterface
public function createService(string $encryptKey, ?string $defaultAssociatedData = null, ?string $encryptorClass = self::SUPPORTED_EXTENSION_OPENSSL): EncryptorInterface
{
$encryptor = new $encryptorClass($this->dispatcher);
$encryptor->setSecretKey($encryptKey);

if(method_exists($encryptorClass, 'setDefaultAssociatedData')){
$encryptor->setDefaultAssociatedData($defaultAssociatedData);
}

return $encryptor;
}
}
4 changes: 2 additions & 2 deletions src/Encryptors/EncryptorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public function setSecretKey(string $key): void;
*
* @return string|null Encrypted string
*/
public function encrypt(?string $data): ?string;
public function encrypt(?string $data, ?string $columnName): ?string;

/**
* Must accept data and return decrypted data.
Expand All @@ -25,5 +25,5 @@ public function encrypt(?string $data): ?string;
*
* @return string Unencrypted string
*/
public function decrypt(?string $data): ?string;
public function decrypt(?string $data, ?string $columnName): ?string;
}
8 changes: 4 additions & 4 deletions src/Subscribers/DoctrineEncryptSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,10 @@ public function postLoad(LifecycleEventArgs $args): void
* If the value is an object, or if it does not contain the suffic <ENC> then return the value iteslf back.
* Otherwise, decrypt the value and return.
*/
public function decryptValue(?string $value): ?string
public function decryptValue(?string $value, ?string $columnName): ?string
{
// Else decrypt value and return.
return $this->encryptor->decrypt($value);
return $this->encryptor->decrypt($value, $columnName);
}

public function getEncryptionableProperties(array $allProperties): array
Expand Down Expand Up @@ -182,7 +182,7 @@ protected function processFields(object $entity, EntityManagerInterface $em, boo

// Encrypt value only if change has been detected by Doctrine (comparing unencrypted values, see postLoad flow)
if (isset($changeSet[$field])) {
$encryptedValue = $this->encryptor->encrypt($value);
$encryptedValue = $this->encryptor->encrypt($value, $field);
$refProperty->setValue($entity, $encryptedValue);
$unitOfWork->recomputeSingleEntityChangeSet($meta, $entity);

Expand All @@ -191,7 +191,7 @@ protected function processFields(object $entity, EntityManagerInterface $em, boo
}
} else {
// Decryption is fired by onLoad and postFlush events.
$decryptedValue = $this->decryptValue($value);
$decryptedValue = $this->decryptValue($value, $field);
$refProperty->setValue($entity, $decryptedValue);

// Tell Doctrine the original value was the decrypted one.
Expand Down

0 comments on commit b597209

Please sign in to comment.