Commit ff9c85ce authored by Bjoern Schiessle's avatar Bjoern Schiessle
Browse files

implement basic encryption functionallity in core to enable multiple encryption modules

parent a9b4f0d8
......@@ -11,6 +11,8 @@
/apps*/*
!/apps/files
!/apps/files_encryption
!/apps/encryption
!/apps/encryption_dummy
!/apps/files_external
!/apps/files_sharing
!/apps/files_trashbin
......
<?php
$manager = \OC::$server->getEncryptionManager();
$module = new \OCA\Encryption_Dummy\DummyModule();
$manager->registerEncryptionModule($module);
<?xml version="1.0"?>
<info>
<id>encryption_dummy</id>
<name>dummy encryption module</name>
<description>
This module does nothing, it is used for testing purpose only
</description>
<licence>AGPL</licence>
<author>Bjoern Schiessle</author>
<requiremin>8</requiremin>
<shipped>true</shipped>
<rememberlogin>false</rememberlogin>
<types>
<filesystem/>
</types>
<ocsid>166047</ocsid>
<dependencies>
<lib>openssl</lib>
</dependencies>
</info>
<?php
/**
* ownCloud
*
* @copyright (C) 2015 ownCloud, Inc.
*
* @author Bjoern Schiessle <schiessle@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
namespace OCA\Encryption_Dummy;
class DummyModule implements \OCP\Encryption\IEncryptionModule {
/** @var boolean */
protected $isWriteOperation;
/**
* @return string defining the technical unique id
*/
public function getId() {
return "34876934";
}
/**
* In comparison to getKey() this function returns a human readable (maybe translated) name
*
* @return string
*/
public function getDisplayName() {
return "Dummy Encryption Module";
}
/**
* start receiving chunks from a file. This is the place where you can
* perform some initial step before starting encrypting/decrypting the
* chunks
*
* @param string $path to the file
* @param string $user who read/write the file (null for public access)
* @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'
*
* $return array $header contain data as key-value pairs which should be
* written to the header, in case of a write operation
* or if no additional data is needed return a empty array
*/
public function begin($path, $user, $header, $accessList) {
return array();
}
/**
* last chunk received. This is the place where you can perform some final
* operation and return some remaining data if something is left in your
* buffer.
*
* @param string $path to the file
* @return string remained data which should be written to the file in case
* of a write operation
*/
public function end($path) {
if ($this->isWriteOperation) {
$storage = \OC::$server->getEncryptionKeyStorage($this->getId());
$storage->setFileKey($path, 'fileKey', 'foo');
}
return '';
}
/**
* encrypt data
*
* @param string $data you want to encrypt
* @return mixed encrypted data
*/
public function encrypt($data) {
$this->isWriteOperation = true;
return $data;
}
/**
* decrypt data
*
* @param string $data you want to decrypt
* @param string $user decrypt as user (null for public access)
* @return mixed decrypted data
*/
public function decrypt($data) {
$this->isWriteOperation=false;
return $data;
}
/**
* update encrypted file, e.g. give additional users access to the file
*
* @param string $path path to the file which should be updated
* @param array $accessList who has access to the file contains the key 'users' and 'public'
* @return boolean
*/
public function update($path, $accessList) {
return true;
}
/**
* should the file be encrypted or not
*
* @param string $path
* @return boolean
*/
public function shouldEncrypt($path) {
if (strpos($path, '/'. \OCP\User::getUser() . '/files/') === 0) {
return true;
}
return false;
}
/**
* calculate unencrypted size
*
* @param string $path to file
* @return integer unencrypted size
*/
public function calculateUnencryptedSize($path) {
return 42;
}
public function getUnencryptedBlockSize() {
return 6126;
}
}
\ No newline at end of file
......@@ -148,7 +148,7 @@ class OC {
// search the 3rdparty folder
OC::$THIRDPARTYROOT = OC_Config::getValue('3rdpartyroot', null);
OC::$THIRDPARTYWEBROOT = OC_Config::getValue('3rdpartyurl', null);
if (empty(OC::$THIRDPARTYROOT) && empty(OC::$THIRDPARTYWEBROOT)) {
if (file_exists(OC::$SERVERROOT . '/3rdparty')) {
OC::$THIRDPARTYROOT = OC::$SERVERROOT;
......@@ -163,7 +163,7 @@ class OC {
. ' folder in the ownCloud folder or the folder above.'
. ' You can also configure the location in the config.php file.');
}
// search the apps folder
$config_paths = OC_Config::getValue('apps_paths', array());
if (!empty($config_paths)) {
......@@ -613,6 +613,8 @@ class OC {
self::registerShareHooks();
self::registerLogRotate();
self::registerLocalAddressBook();
self::registerEncryptionWrapper();
self::registerEncryptionHooks();
//make sure temporary files are cleaned up
$tmpManager = \OC::$server->getTempManager();
......@@ -669,6 +671,45 @@ class OC {
});
}
private static function registerEncryptionWrapper() {
$enabled = self::$server->getEncryptionManager()->isEnabled();
if ($enabled) {
\OC\Files\Filesystem::addStorageWrapper('oc_encryption', function ($mountPoint, $storage) {
$parameters = array('storage' => $storage, 'mountPoint' => $mountPoint);
$manager = \OC::$server->getEncryptionManager();
$util = new \OC\Encryption\Util(new \OC\Files\View(), \OC::$server->getUserManager());
$user = \OC::$server->getUserSession()->getUser();
$logger = \OC::$server->getLogger();
$uid = $user ? $user->getUID() : null;
return new \OC\Files\Storage\Wrapper\Encryption($parameters, $manager,$util, $logger, $uid);
});
}
}
private static function registerEncryptionHooks() {
$enabled = self::$server->getEncryptionManager()->isEnabled();
if ($enabled) {
$user = \OC::$server->getUserSession()->getUser();
$uid = '';
if ($user) {
$uid = $user->getUID();
}
$updater = new \OC\Encryption\Update(
new \OC\Files\View(),
new \OC\Encryption\Util(new \OC\Files\View(), \OC::$server->getUserManager()),
\OC\Files\Filesystem::getMountManager(),
\OC::$server->getEncryptionManager(),
$uid
);
\OCP\Util::connectHook('OCP\Share', 'post_shared', $updater, 'postShared');
\OCP\Util::connectHook('OCP\Share', 'post_unshare', $updater, 'postUnshared');
//\OCP\Util::connectHook('OC_Filesystem', 'post_umount', 'OCA\Files_Encryption\Hooks', 'postUnmount');
//\OCP\Util::connectHook('OC_Filesystem', 'umount', 'OCA\Files_Encryption\Hooks', 'preUnmount');
}
}
/**
* register hooks for the cache
*/
......
<?php
/**
* ownCloud
*
* @copyright (C) 2015 ownCloud, Inc.
*
* @author Bjoern Schiessle <schiessle@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
namespace OC\Encryption\Exceptions;
class EncryptionHeaderKeyExistsException extends \Exception {
}
\ No newline at end of file
<?php
/**
* ownCloud
*
* @copyright (C) 2015 ownCloud, Inc.
*
* @author Bjoern Schiessle <schiessle@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
namespace OC\Encryption\Exceptions;
class ModuleAlreadyExistsException extends \Exception {
}
<?php
/**
* ownCloud
*
* @copyright (C) 2015 ownCloud, Inc.
*
* @author Bjoern Schiessle <schiessle@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
namespace OC\Encryption\Exceptions;
class ModuleDoesNotExistsException extends \Exception {
}
<?php
/**
* ownCloud
*
* @copyright (C) 2015 ownCloud, Inc.
*
* @author Bjoern Schiessle <schiessle@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
namespace OC\Encryption\Keys;
use OC\Encryption\Util;
use OC\Files\View;
use OC\User;
/**
* Factory provides KeyStorage for different encryption modules
*/
class Factory {
/** @var array */
protected $instances = array();
/**
* get a KeyStorage instance
*
* @param string $encryptionModuleId
* @param View $view
* @param Util $util
* @return Storage
*/
public function get($encryptionModuleId,View $view, Util $util) {
if (!isset($this->instances[$encryptionModuleId])) {
$this->instances[$encryptionModuleId] = new Storage($encryptionModuleId, $view, $util);
}
return $this->instances[$encryptionModuleId];
}
}
<?php
/**
* ownCloud
*
* @copyright (C) 2015 ownCloud, Inc.
*
* @author Bjoern Schiessle <schiessle@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
namespace OC\Encryption\Keys;
use OC\Encryption\Util;
use OC\Files\View;
use OCA\Files_Encryption\Exception\EncryptionException;
class Storage implements \OCP\Encryption\Keys\IStorage {
/** @var View */
private $view;
/** @var Util */
private $util;
// base dir where all the file related keys are stored
private $keys_base_dir;
private $encryption_base_dir;
private $keyCache = array();
/** @var string */
private $encryptionModuleId;
/**
* @param string $encryptionModuleId
* @param View $view
* @param Util $util
*/
public function __construct($encryptionModuleId, View $view, Util $util) {
$this->view = $view;
$this->util = $util;
$this->encryptionModuleId = $encryptionModuleId;
$this->encryption_base_dir = '/files_encryption';
$this->keys_base_dir = $this->encryption_base_dir .'/keys';
}
/**
* get user specific key
*
* @param string $uid ID if the user for whom we want the key
* @param string $keyId id of the key
*
* @return mixed key
*/
public function getUserKey($uid, $keyId) {
$path = $this->constructUserKeyPath($keyId, $uid);
return $this->getKey($path);
}
/**
* get file specific key
*
* @param string $path path to file
* @param string $keyId id of the key
*
* @return mixed key
*/
public function getFileKey($path, $keyId) {
$keyDir = $this->getFileKeyDir($path);
return $this->getKey($keyDir . $keyId);
}
/**
* get system-wide encryption keys not related to a specific user,
* e.g something like a key for public link shares
*
* @param string $keyId id of the key
*
* @return mixed key
*/
public function getSystemUserKey($keyId) {
$path = $this->constructUserKeyPath($keyId);
return $this->getKey($path);
}
/**
* set user specific key
*
* @param string $uid ID if the user for whom we want the key
* @param string $keyId id of the key
* @param mixed $key
*/
public function setUserKey($uid, $keyId, $key) {
$path = $this->constructUserKeyPath($keyId, $uid);
return $this->setKey($path, $key);
}
/**
* set file specific key
*
* @param string $path path to file
* @param string $keyId id of the key
* @param boolean
*/
public function setFileKey($path, $keyId, $key) {
$keyDir = $this->getFileKeyDir($path);
return $this->setKey($keyDir . $keyId, $key);
}
/**
* set system-wide encryption keys not related to a specific user,
* e.g something like a key for public link shares
*
* @param string $keyId id of the key
* @param mixed $key
*
* @return mixed key
*/
public function setSystemUserKey($keyId, $key) {
$path = $this->constructUserKeyPath($keyId);
return $this->setKey($path, $key);
}
/**
* delete user specific key
*
* @param string $uid ID if the user for whom we want to delete the key
* @param string $keyId id of the key
*
* @return boolean
*/
public function deleteUserKey($uid, $keyId) {
$path = $this->constructUserKeyPath($keyId, $uid);
return $this->view->unlink($path);
}
/**
* delete file specific key
*
* @param string $path path to file
* @param string $keyId id of the key
*
* @return boolean
*/
public function deleteFileKey($path, $keyId) {
$keyDir = $this->getFileKeyDir($path);
return $this->view->unlink($keyDir . $keyId);
}
/**
* delete all file keys for a given file
*
* @param string $path to the file
* @return boolean
*/
public function deleteAllFileKeys($path) {
$keyDir = $this->getFileKeyDir($path);
return $this->view->deleteAll(dirname($keyDir));
}
/**
* delete system-wide encryption keys not related to a specific user,
* e.g something like a key for public link shares
*
* @param string $keyId id of the key
*
* @return boolean
*/
public function deleteSystemUserKey($keyId) {
$path = $this->constructUserKeyPath($keyId);
return $this->view->unlink($path);
}
/**
* construct path to users key
*
* @param string $keyId
* @param string $uid
* @return string
*/
protected function constructUserKeyPath($keyId, $uid = null) {
if ($uid === null) {
$path = $this->encryption_base_dir . '/' . $this->encryptionModuleId . '/' . $keyId;
} else {
$path = '/' . $uid . $this->encryption_base_dir . '/'
. $this->encryptionModuleId . '/' . $uid . '.' . $keyId;
}
return $path;
}
/**
* read key from hard disk
*
* @param string $path to key
* @return string
*/
private function getKey($path) {
$key = '';