write encrypted file to disc
This commit is contained in:
parent
7ffd77fac9
commit
198b73fe32
|
@ -27,7 +27,6 @@ use OCA\Encryption\Crypto\Crypt;
|
||||||
use OCA\Encryption\HookManager;
|
use OCA\Encryption\HookManager;
|
||||||
use OCA\Encryption\Hooks\UserHooks;
|
use OCA\Encryption\Hooks\UserHooks;
|
||||||
use OCA\Encryption\KeyManager;
|
use OCA\Encryption\KeyManager;
|
||||||
use OCA\Encryption\Migrator;
|
|
||||||
use OCA\Encryption\Recovery;
|
use OCA\Encryption\Recovery;
|
||||||
use OCA\Encryption\Users\Setup;
|
use OCA\Encryption\Users\Setup;
|
||||||
use OCA\Encryption\Util;
|
use OCA\Encryption\Util;
|
||||||
|
@ -98,7 +97,7 @@ class Encryption extends \OCP\AppFramework\App {
|
||||||
public function registerEncryptionModule() {
|
public function registerEncryptionModule() {
|
||||||
$container = $this->getContainer();
|
$container = $this->getContainer();
|
||||||
$container->registerService('EncryptionModule', function (IAppContainer $c) {
|
$container->registerService('EncryptionModule', function (IAppContainer $c) {
|
||||||
return new \OCA\Encryption\Crypto\Encryption($c->query('Crypt'));
|
return new \OCA\Encryption\Crypto\Encryption($c->query('Crypt'), $c->query('KeyManager'));
|
||||||
});
|
});
|
||||||
$module = $container->query('EncryptionModule');
|
$module = $container->query('EncryptionModule');
|
||||||
$this->encryptionManager->registerEncryptionModule($module);
|
$this->encryptionManager->registerEncryptionModule($module);
|
||||||
|
@ -122,8 +121,7 @@ class Encryption extends \OCP\AppFramework\App {
|
||||||
function (IAppContainer $c) {
|
function (IAppContainer $c) {
|
||||||
$server = $c->getServer();
|
$server = $c->getServer();
|
||||||
|
|
||||||
$moduleId = $c->query('EncryptionModule')->getId();
|
return new KeyManager($server->getEncryptionKeyStorage(\OCA\Encryption\Crypto\Encryption::ID),
|
||||||
return new KeyManager($server->getEncryptionKeyStorage($moduleId),
|
|
||||||
$c->query('Crypt'),
|
$c->query('Crypt'),
|
||||||
$server->getConfig(),
|
$server->getConfig(),
|
||||||
$server->getUserSession(),
|
$server->getUserSession(),
|
||||||
|
@ -137,14 +135,13 @@ class Encryption extends \OCP\AppFramework\App {
|
||||||
function (IAppContainer $c) {
|
function (IAppContainer $c) {
|
||||||
$server = $c->getServer();
|
$server = $c->getServer();
|
||||||
|
|
||||||
$moduleId = $c->query('EncryptionModule')->getId();
|
|
||||||
return new Recovery(
|
return new Recovery(
|
||||||
$server->getUserSession(),
|
$server->getUserSession(),
|
||||||
$c->query('Crypt'),
|
$c->query('Crypt'),
|
||||||
$server->getSecureRandom(),
|
$server->getSecureRandom(),
|
||||||
$c->query('KeyManager'),
|
$c->query('KeyManager'),
|
||||||
$server->getConfig(),
|
$server->getConfig(),
|
||||||
$server->getEncryptionKeyStorage($moduleId));
|
$server->getEncryptionKeyStorage(\OCA\Encryption\Crypto\Encryption::ID));
|
||||||
});
|
});
|
||||||
|
|
||||||
$container->registerService('UserSetup',
|
$container->registerService('UserSetup',
|
||||||
|
|
|
@ -25,6 +25,7 @@ namespace OCA\Encryption\Crypto;
|
||||||
use OC\Encryption\Exceptions\DecryptionFailedException;
|
use OC\Encryption\Exceptions\DecryptionFailedException;
|
||||||
use OC\Encryption\Exceptions\EncryptionFailedException;
|
use OC\Encryption\Exceptions\EncryptionFailedException;
|
||||||
use OC\Encryption\Exceptions\GenericEncryptionException;
|
use OC\Encryption\Exceptions\GenericEncryptionException;
|
||||||
|
use OCA\Encryption\KeyManager;
|
||||||
use OCA\Files_Encryption\Exception\MultiKeyDecryptException;
|
use OCA\Files_Encryption\Exception\MultiKeyDecryptException;
|
||||||
use OCA\Files_Encryption\Exception\MultiKeyEncryptException;
|
use OCA\Files_Encryption\Exception\MultiKeyEncryptException;
|
||||||
use OCP\IConfig;
|
use OCP\IConfig;
|
||||||
|
@ -379,6 +380,21 @@ class Crypt {
|
||||||
throw new GenericEncryptionException('Generating IV Failed');
|
throw new GenericEncryptionException('Generating IV Failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a pseudo random 256-bit ASCII key, used as file key
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function generateFileKey() {
|
||||||
|
// Generate key
|
||||||
|
$key = base64_encode(openssl_random_pseudo_bytes(32, $strong));
|
||||||
|
if (!$key || !$strong) {
|
||||||
|
// If OpenSSL indicates randomness is insecure, log error
|
||||||
|
throw new \Exception('Encryption library, Insecure symmetric key was generated using openssl_random_pseudo_bytes()');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $key;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a file's contents contains an IV and is symmetrically encrypted
|
* Check if a file's contents contains an IV and is symmetrically encrypted
|
||||||
*
|
*
|
||||||
|
|
|
@ -11,24 +11,51 @@ namespace OCA\Encryption\Crypto;
|
||||||
|
|
||||||
|
|
||||||
use OCP\Encryption\IEncryptionModule;
|
use OCP\Encryption\IEncryptionModule;
|
||||||
|
use OCA\Encryption\KeyManager;
|
||||||
|
|
||||||
class Encryption implements IEncryptionModule {
|
class Encryption implements IEncryptionModule {
|
||||||
|
|
||||||
|
const ID = '42';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Crypt
|
* @var Crypt
|
||||||
*/
|
*/
|
||||||
private $crypt;
|
private $crypt;
|
||||||
|
|
||||||
public function __construct(Crypt $crypt) {
|
/** @var string */
|
||||||
|
private $cipher;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $path;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $user;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $fileKey;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $writeCache;
|
||||||
|
|
||||||
|
/** @var KeyManager */
|
||||||
|
private $keymanager;
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
private $accessList;
|
||||||
|
|
||||||
|
/** @var boolean */
|
||||||
|
private $isWriteOperation;
|
||||||
|
|
||||||
|
public function __construct(Crypt $crypt, KeyManager $keymanager) {
|
||||||
$this->crypt = $crypt;
|
$this->crypt = $crypt;
|
||||||
|
$this->keymanager = $keymanager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string defining the technical unique id
|
* @return string defining the technical unique id
|
||||||
*/
|
*/
|
||||||
public function getId() {
|
public function getId() {
|
||||||
// we need to hard code this value
|
return self::ID;
|
||||||
return md5($this->getDisplayName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,6 +73,7 @@ class Encryption implements IEncryptionModule {
|
||||||
* chunks
|
* chunks
|
||||||
*
|
*
|
||||||
* @param string $path to the file
|
* @param string $path to the file
|
||||||
|
* @param string $user who read/write the file
|
||||||
* @param array $header contains the header data read from the file
|
* @param array $header contains the header data read from the file
|
||||||
* @param array $accessList who has access to the file contains the key 'users' and 'public'
|
* @param array $accessList who has access to the file contains the key 'users' and 'public'
|
||||||
*
|
*
|
||||||
|
@ -53,9 +81,23 @@ class Encryption implements IEncryptionModule {
|
||||||
* written to the header, in case of a write operation
|
* written to the header, in case of a write operation
|
||||||
* or if no additional data is needed return a empty array
|
* or if no additional data is needed return a empty array
|
||||||
*/
|
*/
|
||||||
public function begin($path, $header, $accessList) {
|
public function begin($path, $user, $header, $accessList) {
|
||||||
|
|
||||||
$cipher = $header[''];
|
if (isset($header['cipher'])) {
|
||||||
|
$this->cipher = $header['cipher'];
|
||||||
|
} else {
|
||||||
|
$this->cipher = $this->crypt->getCipher();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->path = $path;
|
||||||
|
$this->accessList = $accessList;
|
||||||
|
$this->user = $user;
|
||||||
|
$this->writeCache = '';
|
||||||
|
$this->isWriteOperation = false;
|
||||||
|
|
||||||
|
$this->fileKey = $this->keymanager->getFileKey($path);
|
||||||
|
|
||||||
|
return array('cipher' => $this->cipher);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,7 +110,20 @@ class Encryption implements IEncryptionModule {
|
||||||
* of a write operation
|
* of a write operation
|
||||||
*/
|
*/
|
||||||
public function end($path) {
|
public function end($path) {
|
||||||
// TODO: Implement end() method.
|
$result = '';
|
||||||
|
if ($this->isWriteOperation) {
|
||||||
|
if (!empty($this->writeCache)) {
|
||||||
|
$result = $this->crypt->symmetricEncryptFileContent($this->writeCache, $this->fileKey);
|
||||||
|
$this->writeCache = '';
|
||||||
|
}
|
||||||
|
$publicKeys = array();
|
||||||
|
foreach ($this->accessList['users'] as $user) {
|
||||||
|
$publicKeys[] = $this->keymanager->getPublicKey($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->crypt->multiKeyEncrypt($this->fileKey, $publicKeys);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,21 +133,80 @@ class Encryption implements IEncryptionModule {
|
||||||
* @return mixed encrypted data
|
* @return mixed encrypted data
|
||||||
*/
|
*/
|
||||||
public function encrypt($data) {
|
public function encrypt($data) {
|
||||||
// Todo: xxx Update Signature and usages
|
$this->isWriteOperation = true;
|
||||||
// passphrase is file key decrypted with user private/share key
|
if (empty($this->fileKey)) {
|
||||||
$this->symmetricEncryptFileContent($data);
|
$this->fileKey = $this->crypt->generateFileKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If extra data is left over from the last round, make sure it
|
||||||
|
// is integrated into the next 6126 / 8192 block
|
||||||
|
if ($this->writeCache) {
|
||||||
|
|
||||||
|
// Concat writeCache to start of $data
|
||||||
|
$data = $this->writeCache . $data;
|
||||||
|
|
||||||
|
// Clear the write cache, ready for reuse - it has been
|
||||||
|
// flushed and its old contents processed
|
||||||
|
$this->writeCache = '';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$encrypted = '';
|
||||||
|
// While there still remains some data to be processed & written
|
||||||
|
while (strlen($data) > 0) {
|
||||||
|
|
||||||
|
// Remaining length for this iteration, not of the
|
||||||
|
// entire file (may be greater than 8192 bytes)
|
||||||
|
$remainingLength = strlen($data);
|
||||||
|
|
||||||
|
// If data remaining to be written is less than the
|
||||||
|
// size of 1 6126 byte block
|
||||||
|
if ($remainingLength < 6126) {
|
||||||
|
|
||||||
|
// Set writeCache to contents of $data
|
||||||
|
// The writeCache will be carried over to the
|
||||||
|
// next write round, and added to the start of
|
||||||
|
// $data to ensure that written blocks are
|
||||||
|
// always the correct length. If there is still
|
||||||
|
// data in writeCache after the writing round
|
||||||
|
// has finished, then the data will be written
|
||||||
|
// to disk by $this->flush().
|
||||||
|
$this->writeCache = $data;
|
||||||
|
|
||||||
|
// Clear $data ready for next round
|
||||||
|
$data = '';
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Read the chunk from the start of $data
|
||||||
|
$chunk = substr($data, 0, 6126);
|
||||||
|
|
||||||
|
$encrypted .= $this->crypt->symmetricEncryptFileContent($chunk, $this->fileKey);
|
||||||
|
|
||||||
|
// Remove the chunk we just processed from
|
||||||
|
// $data, leaving only unprocessed data in $data
|
||||||
|
// var, for handling on the next round
|
||||||
|
$data = substr($data, 6126);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $encrypted;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* decrypt data
|
* decrypt data
|
||||||
*
|
*
|
||||||
* @param string $data you want to decrypt
|
* @param string $data you want to decrypt
|
||||||
* @param string $user decrypt as user (null for public access)
|
|
||||||
* @return mixed decrypted data
|
* @return mixed decrypted data
|
||||||
*/
|
*/
|
||||||
public function decrypt($data, $user) {
|
public function decrypt($data) {
|
||||||
// Todo: xxx Update Usages?
|
$result = '';
|
||||||
$this->symmetricDecryptFileContent($data, $user);
|
if (!empty($data)) {
|
||||||
|
$result = $this->crypt->symmetricDecryptFileContent($data, $this->fileKey);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -113,7 +227,7 @@ class Encryption implements IEncryptionModule {
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function shouldEncrypt($path) {
|
public function shouldEncrypt($path) {
|
||||||
// TODO: Implement shouldEncrypt() method.
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -133,6 +247,6 @@ class Encryption implements IEncryptionModule {
|
||||||
* @return integer
|
* @return integer
|
||||||
*/
|
*/
|
||||||
public function getUnencryptedBlockSize() {
|
public function getUnencryptedBlockSize() {
|
||||||
// TODO: Implement getUnencryptedBlockSize() method.
|
return 6126;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,21 +62,21 @@ class KeyManager {
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $publicKeyId = 'public';
|
private $publicKeyId = 'publicKey';
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $privateKeyId = 'private';
|
private $privateKeyId = 'privateKey';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $shareKeyId = 'sharekey';
|
private $shareKeyId = 'shareKey';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $fileKeyId = 'filekey';
|
private $fileKeyId = 'fileKey';
|
||||||
/**
|
/**
|
||||||
* @var IConfig
|
* @var IConfig
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue