Skip to content

Commit

Permalink
Merge pull request #4 from boite/master
Browse files Browse the repository at this point in the history
Objectstorage v3; now with modern crypto
  • Loading branch information
joostfaassen committed Jun 2, 2019
2 parents e363dd8 + 995b567 commit beb1ce4
Show file tree
Hide file tree
Showing 32 changed files with 723 additions and 296 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Expand Up @@ -2,6 +2,8 @@

.DS_Store
objectstorage.conf
.php_cs.cache
.phpunit.result.cache

### Eclipse ###
*.pydevproject
Expand Down
17 changes: 17 additions & 0 deletions .php_cs.dist
@@ -0,0 +1,17 @@
<?php

$finder = PhpCsFixer\Finder::create()
->in(__DIR__.'/src')
;

return PhpCsFixer\Config::create()
->setRules([
'@PSR1' => true,
'@PSR2' => true,
'@Symfony' => true,
'phpdoc_align' => false,
'concat_space' => ['spacing' => 'one'],
'array_syntax' => ['syntax' => 'short'],
])
->setFinder($finder)
;
65 changes: 35 additions & 30 deletions README.md
@@ -1,9 +1,7 @@
# ObjectStorage 2.0 library
# ObjectStorage 3.0 library

ObjectStorage library for your cloud-based applications.

*NOTE: version 1.0, previously only available as dev-master, is still available by updating your composer.json to require version ~1.0*

## Object Storage vs a normal file system

Object-based storage solves large scale storage problems for cloud-based applications.
Expand Down Expand Up @@ -78,42 +76,38 @@ $service->delete('my-message');

### Encryption

The library includes an EncryptionAdapter that will allow you to transparently encrypt/decrypt
The library includes adapters to allow you to transparently encrypt/decrypt
your data before it's passed to the storage backend.

This is done by wrapping the original storage adapter (s3, file, pdo, gridfs, etc) into
the EncryptionAdapter. Here's an example
This is done by wrapping the original storage adapter (s3, file, pdo, gridfs,
etc) into the one of the encryption adapters. Here's an example

```php
$adapter = new ObjectStorage\Adapter\PdoAdapter($pdo);
$adapter = new ObjectStorage\Adapter\EncryptionAdapter($adapter, $key, $iv);
// You can use $adapter as before, but all data will be encrypted
$adapter = new \ObjectStorage\Adapter\EncryptedStorageAdapter(
new \ObjectStorage\Adapter\PdoAdapter($pdo),
\ParagonIE\Halite\KeyFactory::loadEncryptionKey($pathToKeyfile)
);
// You can use $adapter as before and both the storage keys and objects will be
// encrypted (use PlaintextKeyEncryptedStorageAdapter if you don't want the
// storage keys to be encrypted).
```

The key and iv are hex encoded strings. To generate these, use the following command:

./bin/objectstorage objectstorage:generatekey
The encryption routines are provided by [ParagonIE/Halite][] and libsodium.

This will output something like the following:

KEY: C2FE680A5613469189621C9E46B52C15C9C80E50370E7950D6FD2D027C4FAEF0
IV: E5F3E442F3CE0ECC931B7E866A5F3121

Save these 2 values somewhere safely.
Use the following command to generate an encryption key and save it to a file :-

The encryption is similar to using the following commands:

openssl enc -aes-256-cbc -K C2FE680A5613469189621C9E46B52C15C9C80E50370E7950D6FD2D027C4FAEF0 -iv E5F3E442F3CE0ECC931B7E866A5F3121 < original.txt > encrypted.aes
```sh
./bin/objectstorage genkey /path/to/a/file
```

openssl enc -d -aes-256-cbc -K C2FE680A5613469189621C9E46B52C15C9C80E50370E7950D6FD2D027C4FAEF0 -iv E5F3E442F3CE0ECC931B7E866A5F3121 < encrypted.aes
You can also use the included encrypt + decrypt commands:
You can also use the included encrypt + decrypt commands. In the following
example we encrypt `example.pdf` with the encryption key in `key.asc` and then
decrypt it again, using the same key and writing it to a new `example-new.pdf`:

export OBJECTSTORAGE_ENCRYPTION_KEY=C2FE680A5613469189621C9E46B52C15C9C80E50370E7950D6FD2D027C4FAEF0
export OBJECTSTORAGE_ENCRYPTION_IV=E5F3E442F3CE0ECC931B7E866A5F3121

bin/objectstorage objectstorage:encrypt example.pdf > example.pdf.encrypted
bin/objectstorage objectstorage:decrypt example.pdf.encrypted > example_new.pdf
```sh
bin/objectstorage encrypt key.asc example.pdf example.pdf.encrypted
bin/objectstorage decrypt key.asc example.pdf.encrypted example-new.pdf
```

## Console tool

Expand Down Expand Up @@ -172,11 +166,20 @@ Then, add `linkorb/objectstorage` to your project's `composer.json`:
```json
{
"require": {
"linkorb/objectstorage": "~2.0"
"linkorb/objectstorage": "^3.0"
}
}
```

## Older versions of this library

Version 1.0, previously only available as dev-master, is still available by
updating your composer.json to require version "~1.0".

The `php5` branch will still work with PHP <= 5.6, but it will not have the
latest features and, particularly, should not be used if you need encrypted
storage.

## Contributing

Ready to build and improve on this repo? Excellent!
Expand All @@ -195,3 +198,5 @@ Btw, we're hiring!
## License

Please check LICENSE.md for full license information

[ParagonIE/Halite]: <https://paragonie.com/project/halite> "Halite - Simple PHP Cryptography Library"
30 changes: 20 additions & 10 deletions bin/objectstorage
@@ -1,17 +1,27 @@
#!/usr/bin/env php
<?php

use Symfony\Component\Console\Application;

require_once(__DIR__ . "/../vendor/autoload.php");

$application = new Application('ObjectStorage CLI utility', '1.0.0');
use ObjectStorage\Command\DecryptCommand;
use ObjectStorage\Command\DeleteCommand;
use ObjectStorage\Command\DownloadCommand;
use ObjectStorage\Command\EncryptCommand;
use ObjectStorage\Command\GenerateKeyCommand;
use ObjectStorage\Command\ListCommand;
use ObjectStorage\Command\UploadCommand;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\CommandLoader\FactoryCommandLoader;

$application = new Application('ObjectStorage CLI utility', 'v3');
$application->setCatchExceptions(true);
$application->add(new \ObjectStorage\Command\UploadCommand());
$application->add(new \ObjectStorage\Command\DownloadCommand());
$application->add(new \ObjectStorage\Command\ListCommand());
$application->add(new \ObjectStorage\Command\DeleteCommand());
$application->add(new \ObjectStorage\Command\GenerateKeyCommand());
$application->add(new \ObjectStorage\Command\EncryptCommand());
$application->add(new \ObjectStorage\Command\DecryptCommand());
$application->setCommandLoader(new FactoryCommandLoader([
'objectstorage:upload' => function () { return new UploadCommand(); },
'objectstorage:download' => function () { return new DownloadCommand(); },
'objectstorage:list' => function () { return new ListCommand(); },
'objectstorage:delete' => function () { return new DeleteCommand(); },
'genkey' => function () { return new GenerateKeyCommand(); },
'encrypt' => function () { return new EncryptCommand(); },
'decrypt' => function () { return new DecryptCommand(); },
]));
$application->run();
9 changes: 6 additions & 3 deletions composer.json
Expand Up @@ -12,11 +12,14 @@
}
],
"require": {
"php": ">=5.3.0"
"php": "^7.2",
"paragonie/halite": "^4"
},
"require-dev": {
"symfony/console": "~2.4",
"aws/aws-sdk-php": "~2.7"
"symfony/console": "^4",
"aws/aws-sdk-php": "^3",
"friendsofphp/php-cs-fixer": "^2.15",
"phpunit/phpunit": "^8.1"
},
"suggest": {
"linkorb/bergen-client-php": "To use the Bergen Adapter."
Expand Down
27 changes: 27 additions & 0 deletions phpunit.xml.dist
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>

<!-- https://phpunit.de/manual/current/en/appendixes.configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/6.5/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="tests/bootstrap.php"
>
<php>
<ini name="error_reporting" value="-1" />
<server name="APP_ENV" value="test" force="true" />
<server name="SHELL_VERBOSITY" value="-1" />
</php>

<testsuites>
<testsuite name="Project Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>

<filter>
<whitelist>
<directory>src</directory>
</whitelist>
</filter>
</phpunit>
3 changes: 2 additions & 1 deletion src/Adapter/BergenAdapter.php
Expand Up @@ -8,7 +8,7 @@
use Bergen\Client\V1\V1StorageClient;
use GuzzleHttp\RequestOptions;

class BergenAdapter implements StorageAdapterInterface
class BergenAdapter implements BuildableAdapterInterface, StorageAdapterInterface
{
/**
* @var \Bergen\Client\V1\V1StorageClient
Expand Down Expand Up @@ -60,6 +60,7 @@ public function getData($key)
} catch (UnexpectedResponseError $e) {
throw new AdapterException('Unable to get data.', null, $e);
}

return (string) $response->getBody();
}

Expand Down
15 changes: 15 additions & 0 deletions src/Adapter/BuildableAdapterInterface.php
@@ -0,0 +1,15 @@
<?php

namespace ObjectStorage\Adapter;

interface BuildableAdapterInterface
{
/**
* Build an instance of the adapter.
*
* @param array $config
*
* @return \ObjectStorage\Adapter\StorageAdapterInterface
*/
public static function build(array $config);
}
5 changes: 2 additions & 3 deletions src/Adapter/Bzip2Adapter.php
Expand Up @@ -2,9 +2,6 @@

namespace ObjectStorage\Adapter;

use RuntimeException;
use InvalidArgumentException;

class Bzip2Adapter implements StorageAdapterInterface
{
private $child;
Expand All @@ -19,13 +16,15 @@ public function __construct(StorageAdapterInterface $child, $level)
public function setData($key, $data)
{
$data = bzcompress($data, $this->level);

return $this->child->setData($key, $data);
}

public function getData($key)
{
$data = $this->child->getData($key);
$data = bzdecompress($data);

return $data;
}

Expand Down

0 comments on commit beb1ce4

Please sign in to comment.