Skip to content
This repository has been archived by the owner on Jan 29, 2019. It is now read-only.

Commit

Permalink
Merge pull request #2 from salesupply/develop
Browse files Browse the repository at this point in the history
Dev to Master for 1.0 merge
  • Loading branch information
rvdlee-salesupply authored Mar 15, 2018
2 parents 9920180 + d4752da commit 0a6cdb4
Show file tree
Hide file tree
Showing 13 changed files with 488 additions and 67 deletions.
26 changes: 1 addition & 25 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,25 +1 @@
# Composer files
composer.phar
vendor/

# Local configs
config/autoload/*.local.php

# Binary gettext files
*.mo

# Data
data/logs/
data/cache/
data/sessions/
data/tmp/
temp/

#Doctrine 2
data/DoctrineORMModule/Proxy/
data/DoctrineORMModule/cache/


# Legacy ZF1
demos/
extras/documentation
config/local.config.php
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,44 @@ Expands [51systems](https://github.com/51systems/doctrine-encrypt/) Doctrine enc

Provides a Zend Framework 3 & Doctrine 2 encryption module.

# Installation

composer require salesupply/zf-doctrine-encrypt-module

# Requirements

* PHP 7.2 or greater (must have Sodium extension enabled)
* [Doctrine encrypt](https://github.com/51systems/doctrine-encrypt/) module by 51systems
* [Doctrine ORM Module](https://github.com/doctrine/doctrine-orm-module/)

If you're on Windows, using Xampp, the PHP 7.2 installation might not automatically enable the Sodium extension. If this
the case, you'll get an error (`'This is not implemented, as it is not possible to securely wipe memory from PHP'`).
Enable Sodium for PHP by adding this to your `php.ini` file:

extension = C:\xampp\php\ext\php_sodium.dll

This might also be applicable ot other local installations.

# Configuration

`*.dist` files are provided. Copy these (remove extension) to your application and fill in the required key/salt values.
If these are filled in, it works out of the box using [Halite](https://github.com/paragonie/halite) for encryption.

However, must be said, at the moment of writing this ReadMe, the Halite module contains duplicate `const` declarations,
as such, you must disable your `E_NOTICE` warnings in your PHP config :(

# Usage example

Simple, consider that you have an `Address` Entity, which under upcoming [EU GDPR regulation](https://www.eugdpr.org/)
requires parts of the address, such as the street, to be encrypted.

To encrypt a street name, add `@Encrypted` like so:

/**
* @var string
* @ORM\Column(name="street", type="string", length=255, nullable=true)
* @Encrypted
*/
protected $street;


6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
"description": "Provides property encryption for Doctrine Entities when used within Zend Framework 3.",
"keywords": ["zf3", "doctrine2", "encrypt", "module", "zend framework 3", "encryption"],
"homepage": "https://www.salesupply.com/",
"time": "2018-03-14",
"license" : "MIT",
"authors": [
{
Expand All @@ -16,8 +15,9 @@
"email": "development@salesupply.com"
},
"require": {
"php": "^7.1",
"51systems/doctrine-encrypt":"^6"
"php": "^7.2",
"51systems/doctrine-encrypt":"^6",
"doctrine/doctrine-orm-module":"^1.1"
},
"autoload": {
"psr-4": {
Expand Down
38 changes: 38 additions & 0 deletions config/global.config.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace ZfDoctrineEncryptModule;

use Doctrine\Common\Annotations\AnnotationReader;
use ZfDoctrineEncryptModule\Adapter\HaliteAdapter;
use ZfDoctrineEncryptModule\Factory\HaliteAdapterFactory;
use ZfDoctrineEncryptModule\Factory\ZfDoctrineEncryptedServiceFactory;

return [
'doctrine_factories' => [
'encryption' => ZfDoctrineEncryptedServiceFactory::class,
],
'doctrine' => [
'encryption' => [
'orm_default' => [
'adapter' => 'encryption_adapter',
'reader' => AnnotationReader::class,
],
],
'eventmanager' => [
'orm_default' => [
'subscribers' => [
'doctrine.encryption.orm_default',
],
],
],
],
'service_manager' => [
'aliases' => [
'encryption_adapter' => HaliteAdapter::class,
],
'factories' => [
// Using aliases so someone else can use own adapter/factory
HaliteAdapter::class => HaliteAdapterFactory::class
],
],
];
14 changes: 14 additions & 0 deletions config/local.config.php.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace ZfDoctrineEncryptModule;

return [
'doctrine' => [
'encryption' => [
'orm_default' => [
'key' => '', // Must be 32 characters - Halite requirement
'salt' => '', // Must be 32 characters - Halite requirement
],
],
],
];
31 changes: 0 additions & 31 deletions config/module.config.php

This file was deleted.

7 changes: 0 additions & 7 deletions config/module.config.php.dist

This file was deleted.

105 changes: 105 additions & 0 deletions src/Adapter/HaliteAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<?php

namespace ZfDoctrineEncryptModule\Adapter;

use DoctrineEncrypt\Encryptors\EncryptorInterface;
use ParagonIE\Halite\Alerts\InvalidKey;
use ParagonIE\Halite\HiddenString;
use ParagonIE\Halite\Symmetric\Crypto;
use ParagonIE\Halite\Symmetric\EncryptionKey;
use ParagonIE\Halite\Util as CryptoUtil;

class HaliteAdapter implements EncryptorInterface
{
/**
* @var EncryptionKey
*/
private $key;

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

/**
* HaliteAdapter constructor.
* @param $key
* @param $salt
* @throws InvalidKey
* @throws \ParagonIE\Halite\Alerts\CannotPerformOperation
*/
public function __construct($key, $salt)
{
if (CryptoUtil::safeStrlen($key) !== \Sodium\CRYPTO_STREAM_KEYBYTES) {

throw new InvalidKey(
'Encryption key used for ' . __CLASS__ . ' must be exactly ' . \Sodium\CRYPTO_STREAM_KEYBYTES . ' characters long'
);
}

if (CryptoUtil::safeStrlen($salt) !== \Sodium\CRYPTO_STREAM_KEYBYTES) {

throw new InvalidKey(
'Salt used for ' . __CLASS__ . ' must be exactly ' . \Sodium\CRYPTO_STREAM_KEYBYTES . ' characters long'
);
}

$this->setKey((new EncryptionKey((new HiddenString($key)))));
$this->setSalt($salt);
}

/**
* {@inheritdoc}
*/
public function encrypt($data)
{
return Crypto::encrypt(new HiddenString($this->getSalt() . $data), $this->getKey());
}

/**
* {@inheritdoc}
*/
public function decrypt($data)
{
$decrypted = Crypto::decrypt($data, $this->getKey());

return str_replace($this->getSalt(), '', $decrypted);
}

/**
* @return EncryptionKey
*/
public function getKey(): EncryptionKey
{
return $this->key;
}

/**
* @param EncryptionKey $key
* @return HaliteAdapter
*/
public function setKey(EncryptionKey $key): HaliteAdapter
{
$this->key = $key;
return $this;
}

/**
* @return string
*/
public function getSalt(): string
{
return $this->salt;
}

/**
* @param string $salt
* @return HaliteAdapter
*/
public function setSalt(string $salt): HaliteAdapter
{
$this->salt = $salt;
return $this;
}

}
6 changes: 6 additions & 0 deletions src/Exception/OptionsNotFoundException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

namespace ZfDoctrineEncryptModule\Exception;

class OptionsNotFoundException extends \Exception
{}
35 changes: 35 additions & 0 deletions src/Factory/HaliteAdapterFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace ZfDoctrineEncryptModule\Factory;

use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
use ZfDoctrineEncryptModule\Adapter\HaliteAdapter;
use ZfDoctrineEncryptModule\Exception\OptionsNotFoundException;

class HaliteAdapterFactory implements FactoryInterface
{
/**
* @param ContainerInterface $container
* @param string $requestedName
* @param array|null $options
* @return object|HaliteAdapter
* @throws OptionsNotFoundException
* @throws \ParagonIE\Halite\Alerts\CannotPerformOperation
* @throws \ParagonIE\Halite\Alerts\InvalidKey
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
if (!key_exists('key', $options) && !is_string($options['key'])) {

throw new OptionsNotFoundException('Option "key" is required.');
}

if (!key_exists('salt', $options) && !is_string($options['salt'])) {

throw new OptionsNotFoundException('Option "salt" is required.');
}

return new HaliteAdapter($options['key'], $options['salt']);
}
}
Loading

0 comments on commit 0a6cdb4

Please sign in to comment.