committed by
Thomas Müller
37 changed files with 2630 additions and 253 deletions
-
33apps/encryption/appinfo/app.php
-
182apps/encryption/appinfo/encryption.php
-
36apps/encryption/appinfo/info.xml
-
39apps/encryption/appinfo/routes.php
-
106apps/encryption/controller/recoverycontroller.php
-
37apps/encryption/hooks/apphooks.php
-
32apps/encryption/hooks/contracts/ihook.php
-
46apps/encryption/hooks/filesystemhooks.php
-
40apps/encryption/hooks/sharehooks.php
-
304apps/encryption/hooks/userhooks.php
-
116apps/encryption/lib/crypto/Encryption.php
-
355apps/encryption/lib/crypto/crypt.php
-
64apps/encryption/lib/hookmanager.php
-
217apps/encryption/lib/keymanager.php
-
123apps/encryption/lib/migrator.php
-
134apps/encryption/lib/recovery.php
-
38apps/encryption/lib/setup.php
-
63apps/encryption/lib/users/setup.php
-
24apps/encryption/settings/settings-admin.php
-
41apps/encryption/settings/settings-personal.php
-
90apps/encryption/tests/lib/KeyManagerTest.php
-
62apps/encryption/tests/lib/MigratorTest.php
-
51apps/encryption/tests/lib/RequirementsCheckerTest.php
-
226apps/files_encryption/lib/hooks.php
-
28lib/private/encryption/exceptions/decryptionfailedexception.php
-
28lib/private/encryption/exceptions/emptyencryptiondataexception.php
-
28lib/private/encryption/exceptions/encryptionfailedexception.php
-
28lib/private/encryption/exceptions/encryptionheadertolargeexception.php
-
27lib/private/encryption/exceptions/genericencryptionexception.php
-
28lib/private/encryption/exceptions/privatekeymissingexception.php
-
28lib/private/encryption/exceptions/publickeymissingexception.php
-
28lib/private/encryption/exceptions/unexpectedblocksizeexception.php
-
28lib/private/encryption/exceptions/unexpectedendofencryptionheaderexception.php
-
28lib/private/encryption/exceptions/unknowncipherexception.php
-
57lib/private/encryption/keystorage.php
-
30lib/public/encryption/ikeystorage.php
-
58tests/lib/encryption/managertest.php
@ -0,0 +1,33 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/19/15, 9:52 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
use OCA\Encryption\AppInfo\Encryption; |
|||
|
|||
if (!OC::$CLI) { |
|||
$di = \OC::$server; |
|||
$app = new Encryption('encryption', |
|||
[], |
|||
$di->getEncryptionManager(), |
|||
$di->getConfig()); |
|||
|
|||
$app->boot(); |
|||
} |
|||
|
|||
@ -0,0 +1,182 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 3/11/15, 11:03 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
namespace OCA\Encryption\AppInfo; |
|||
|
|||
|
|||
use OCA\Encryption\Crypto\Crypt; |
|||
use OCA\Encryption\HookManager; |
|||
use OCA\Encryption\Hooks\AppHooks; |
|||
use OCA\Encryption\Hooks\FileSystemHooks; |
|||
use OCA\Encryption\Hooks\ShareHooks; |
|||
use OCA\Encryption\Hooks\UserHooks; |
|||
use OCA\Encryption\KeyManager; |
|||
use OCA\Encryption\Migrator; |
|||
use OCA\Encryption\Recovery; |
|||
use OCA\Encryption\Users\Setup; |
|||
use OCP\App; |
|||
use OCP\AppFramework\IAppContainer; |
|||
use OCP\Encryption\IManager; |
|||
use OCP\IConfig; |
|||
|
|||
|
|||
class Encryption extends \OCP\AppFramework\App { |
|||
/** |
|||
* @var IManager |
|||
*/ |
|||
private $encryptionManager; |
|||
/** |
|||
* @var IConfig |
|||
*/ |
|||
private $config; |
|||
|
|||
/** |
|||
* @param $appName |
|||
* @param array $urlParams |
|||
* @param IManager $encryptionManager |
|||
* @param IConfig $config |
|||
*/ |
|||
public function __construct($appName, $urlParams = array(), IManager $encryptionManager, IConfig $config) { |
|||
parent::__construct($appName, $urlParams); |
|||
$this->encryptionManager = $encryptionManager; |
|||
$this->config = $config; |
|||
} |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
public function boot() { |
|||
$this->registerServices(); |
|||
$this->registerHooks(); |
|||
$this->registerEncryptionModule(); |
|||
$this->registerSettings(); |
|||
} |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
public function registerHooks() { |
|||
if (!$this->config->getSystemValue('maintenance', false)) { |
|||
|
|||
$container = $this->getContainer(); |
|||
$server = $container->getServer(); |
|||
// Register our hooks and fire them.
|
|||
$hookManager = new HookManager(); |
|||
|
|||
$hookManager->registerHook([ |
|||
new UserHooks($container->query('KeyManager'), |
|||
$server->getLogger(), |
|||
$container->query('UserSetup'), |
|||
$container->query('Migrator'), |
|||
$server->getUserSession()), |
|||
// new ShareHooks(),
|
|||
// new FileSystemHooks(),
|
|||
// new AppHooks()
|
|||
]); |
|||
|
|||
$hookManager->fireHooks(); |
|||
|
|||
} else { |
|||
// Logout user if we are in maintenance to force re-login
|
|||
$this->getContainer()->getServer()->getUserSession()->logout(); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
public function registerEncryptionModule() { |
|||
// $this->encryptionManager->registerEncryptionModule(new \OCA\Encryption\Crypto\Encryption());
|
|||
} |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
public function registerServices() { |
|||
$container = $this->getContainer(); |
|||
|
|||
$container->registerService('Crypt', |
|||
function (IAppContainer $c) { |
|||
$server = $c->getServer(); |
|||
return new Crypt($server->getLogger(), |
|||
$server->getUserSession(), |
|||
$server->getConfig()); |
|||
}); |
|||
|
|||
$container->registerService('KeyManager', |
|||
function (IAppContainer $c) { |
|||
$server = $c->getServer(); |
|||
|
|||
return new KeyManager($server->getEncryptionKeyStorage(), |
|||
$c->query('Crypt'), |
|||
$server->getConfig(), |
|||
$server->getUserSession()); |
|||
}); |
|||
|
|||
|
|||
$container->registerService('Recovery', |
|||
function (IAppContainer $c) { |
|||
$server = $c->getServer(); |
|||
|
|||
return new Recovery( |
|||
$server->getUserSession(), |
|||
$c->query('Crypt'), |
|||
$server->getSecureRandom(), |
|||
$c->query('KeyManager'), |
|||
$server->getConfig(), |
|||
$server->getEncryptionKeyStorage()); |
|||
}); |
|||
|
|||
$container->registerService('UserSetup', |
|||
function (IAppContainer $c) { |
|||
$server = $c->getServer(); |
|||
return new Setup($server->getLogger(), |
|||
$server->getUserSession(), |
|||
$c->query('Crypt'), |
|||
$c->query('KeyManager')); |
|||
}); |
|||
|
|||
$container->registerService('Migrator', |
|||
function (IAppContainer $c) { |
|||
$server = $c->getServer(); |
|||
|
|||
return new Migrator($server->getUserSession(), |
|||
$server->getConfig(), |
|||
$server->getUserManager(), |
|||
$server->getLogger(), |
|||
$c->query('Crypt')); |
|||
}); |
|||
|
|||
} |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
public function registerSettings() { |
|||
|
|||
// script('encryption', 'encryption');
|
|||
// script('encryption', 'detect-migration');
|
|||
|
|||
|
|||
// Register settings scripts
|
|||
App::registerAdmin('encryption', 'settings/settings-admin'); |
|||
App::registerPersonal('encryption', 'settings/settings-personal'); |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
<?xml version="1.0"?> |
|||
<info> |
|||
<id>encryption</id> |
|||
<description> |
|||
This application encrypts all files accessed by ownCloud at rest, |
|||
wherever they are stored. As an example, with this application |
|||
enabled, external cloud based Amazon S3 storage will be encrypted, |
|||
protecting this data on storage outside of the control of the Admin. |
|||
When this application is enabled for the first time, all files are |
|||
encrypted as users log in and are prompted for their password. The |
|||
recommended recovery key option enables recovery of files in case |
|||
the key is lost. |
|||
Note that this app encrypts all files that are touched by ownCloud, |
|||
so external storage providers and applications such as SharePoint |
|||
will see new files encrypted when they are accessed. Encryption is |
|||
based on AES 128 or 256 bit keys. More information is available in |
|||
the Encryption documentation |
|||
</description> |
|||
<name>Encryption</name> |
|||
<license>AGPL</license> |
|||
<author>Bjoern Schiessle, Clark Tomlinson</author> |
|||
<requiremin>8</requiremin> |
|||
<shipped>true</shipped> |
|||
<documentation> |
|||
<user>user-encryption</user> |
|||
<admin>admin-encryption</admin> |
|||
</documentation> |
|||
<rememberlogin>false</rememberlogin> |
|||
<types> |
|||
<filesystem/> |
|||
</types> |
|||
<dependencies> |
|||
<lib>openssl</lib> |
|||
</dependencies> |
|||
|
|||
</info> |
|||
@ -0,0 +1,39 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/19/15, 11:22 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
|
|||
use OCP\AppFramework\App; |
|||
|
|||
(new App('encryption'))->registerRoutes($this, array('routes' => array( |
|||
|
|||
[ |
|||
'name' => 'recovery#adminRecovery', |
|||
'url' => '/ajax/adminRecovery', |
|||
'verb' => 'POST' |
|||
], |
|||
[ |
|||
'name' => 'recovery#userRecovery', |
|||
'url' => '/ajax/userRecovery', |
|||
'verb' => 'POST' |
|||
] |
|||
|
|||
|
|||
))); |
|||
@ -0,0 +1,106 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/19/15, 11:25 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Encryption\Controller; |
|||
|
|||
|
|||
use OCA\Encryption\Recovery; |
|||
use OCP\AppFramework\Controller; |
|||
use OCP\IConfig; |
|||
use OCP\IL10N; |
|||
use OCP\IRequest; |
|||
use OCP\JSON; |
|||
use Symfony\Component\HttpFoundation\JsonResponse; |
|||
|
|||
class RecoveryController extends Controller { |
|||
/** |
|||
* @var IConfig |
|||
*/ |
|||
private $config; |
|||
/** |
|||
* @var IL10N |
|||
*/ |
|||
private $l; |
|||
/** |
|||
* @var Recovery |
|||
*/ |
|||
private $recovery; |
|||
|
|||
/** |
|||
* @param string $AppName |
|||
* @param IRequest $request |
|||
* @param IConfig $config |
|||
* @param IL10N $l10n |
|||
* @param Recovery $recovery |
|||
*/ |
|||
public function __construct($AppName, IRequest $request, IConfig $config, IL10N $l10n, Recovery $recovery) { |
|||
parent::__construct($AppName, $request); |
|||
$this->config = $config; |
|||
$this->l = $l10n; |
|||
$this->recovery = $recovery; |
|||
} |
|||
|
|||
public function adminRecovery($recoveryPassword, $confirmPassword, $adminEnableRecovery) { |
|||
// Check if both passwords are the same
|
|||
if (empty($recoveryPassword)) { |
|||
$errorMessage = $this->l->t('Missing recovery key password'); |
|||
return new JsonResponse(['data' => ['message' => $errorMessage]], 500); |
|||
} |
|||
|
|||
if (empty($confirmPassword)) { |
|||
$errorMessage = $this->l->t('Please repeat the recovery key password'); |
|||
return new JsonResponse(['data' => ['message' => $errorMessage]], 500); |
|||
} |
|||
|
|||
if ($recoveryPassword !== $confirmPassword) { |
|||
$errorMessage = $this->l->t('Repeated recovery key password does not match the provided recovery key password'); |
|||
return new JsonResponse(['data' => ['message' => $errorMessage]], 500); |
|||
} |
|||
|
|||
// Enable recoveryAdmin
|
|||
$recoveryKeyId = $this->config->getAppValue('encryption', 'recoveryKeyId'); |
|||
|
|||
if (isset($adminEnableRecovery) && $adminEnableRecovery === '1') { |
|||
if ($this->recovery->enableAdminRecovery($recoveryKeyId, $recoveryPassword)) { |
|||
return new JsonResponse(['data' => array('message' => $this->l->t('Recovery key successfully enabled'))]); |
|||
} |
|||
return new JsonResponse(['data' => array('message' => $this->l->t('Could not enable recovery key. Please check your recovery key password!'))]); |
|||
} elseif (isset($adminEnableRecovery) && $adminEnableRecovery === '0') { |
|||
if ($this->recovery->disableAdminRecovery($recoveryKeyId, $recoveryPassword)) { |
|||
return new JsonResponse(['data' => array('message' => $this->l->t('Recovery key successfully disabled'))]); |
|||
} |
|||
return new JsonResponse(['data' => array('message' => $this->l->t('Could not disable recovery key. Please check your recovery key password!'))]); |
|||
} |
|||
} |
|||
|
|||
public function userRecovery($userEnableRecovery) { |
|||
if (isset($userEnableRecovery) && ($userEnableRecovery === '0' || $userEnableRecovery === '1')) { |
|||
$userId = $this->user->getUID(); |
|||
if ($userEnableRecovery === '1') { |
|||
// Todo xxx figure out if we need keyid's here or what.
|
|||
return $this->recovery->addRecoveryKeys(); |
|||
} |
|||
// Todo xxx see :98
|
|||
return $this->recovery->removeRecoveryKeys(); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/19/15, 10:02 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Encryption\Hooks; |
|||
|
|||
use OCA\Encryption\Hooks\Contracts\IHook; |
|||
use OCP\Util; |
|||
|
|||
class AppHooks implements IHook { |
|||
/** |
|||
* Connects Hooks |
|||
* |
|||
* @return null |
|||
*/ |
|||
public function addHooks() { |
|||
Util::connectHook('OC_App', 'pre_disable', 'OCA\Encryption\Hooks', 'preDisable'); |
|||
Util::connectHook('OC_App', 'post_disable', 'OCA\Encryption\Hooks', 'postEnable'); |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/19/15, 10:03 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Encryption\Hooks\Contracts; |
|||
|
|||
|
|||
interface IHook { |
|||
/** |
|||
* Connects Hooks |
|||
* |
|||
* @return null |
|||
*/ |
|||
public function addHooks(); |
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/19/15, 10:02 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Encryption\Hooks; |
|||
|
|||
|
|||
use OCA\Encryption\Hooks\Contracts\IHook; |
|||
use OCP\Util; |
|||
|
|||
class FileSystemHooks implements IHook { |
|||
|
|||
/** |
|||
* Connects Hooks |
|||
* |
|||
* @return null |
|||
*/ |
|||
public function addHooks() { |
|||
Util::connectHook('OC_Filesystem', 'rename', 'OCA\Encryption\Hooks', 'preRename'); |
|||
Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRenameOrCopy'); |
|||
Util::connectHook('OC_Filesystem', 'copy', 'OCA\Encryption\Hooks', 'preCopy'); |
|||
Util::connectHook('OC_Filesystem', 'post_copy', 'OCA\Encryption\Hooks', 'postRenameOrCopy'); |
|||
Util::connectHook('OC_Filesystem', 'post_delete', 'OCA\Encryption\Hooks', 'postDelete'); |
|||
Util::connectHook('OC_Filesystem', 'delete', 'OCA\Encryption\Hooks', 'preDelete'); |
|||
Util::connectHook('\OC\Core\LostPassword\Controller\LostController', 'post_passwordReset', 'OCA\Encryption\Hooks', 'postPasswordReset'); |
|||
Util::connectHook('OC_Filesystem', 'post_umount', 'OCA\Encryption\Hooks', 'postUnmount'); |
|||
Util::connectHook('OC_Filesystem', 'umount', 'OCA\Encryption\Hooks', 'preUnmount'); |
|||
} |
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/19/15, 10:02 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Encryption\Hooks; |
|||
|
|||
|
|||
use OCA\Encryption\Hooks\Contracts\IHook; |
|||
use OCP\Util; |
|||
|
|||
class ShareHooks implements IHook { |
|||
|
|||
/** |
|||
* Connects Hooks |
|||
* |
|||
* @return null |
|||
*/ |
|||
public function addHooks() { |
|||
Util::connectHook('OCP\Share', 'pre_shared', 'OCA\Encryption\Hooks', 'preShared'); |
|||
Util::connectHook('OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared'); |
|||
Util::connectHook('OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare'); |
|||
} |
|||
} |
|||
@ -0,0 +1,304 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/19/15, 10:02 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Encryption\Hooks; |
|||
|
|||
|
|||
use OCA\Encryption\Hooks\Contracts\IHook; |
|||
use OCA\Encryption\KeyManager; |
|||
use OCA\Encryption\Migrator; |
|||
use OCA\Encryption\RequirementsChecker; |
|||
use OCA\Encryption\Users\Setup; |
|||
use OCP\App; |
|||
use OCP\ILogger; |
|||
use OCP\IUserSession; |
|||
use OCP\Util; |
|||
use Test\User; |
|||
|
|||
class UserHooks implements IHook { |
|||
/** |
|||
* @var KeyManager |
|||
*/ |
|||
private $keyManager; |
|||
/** |
|||
* @var ILogger |
|||
*/ |
|||
private $logger; |
|||
/** |
|||
* @var Setup |
|||
*/ |
|||
private $userSetup; |
|||
/** |
|||
* @var Migrator |
|||
*/ |
|||
private $migrator; |
|||
/** |
|||
* @var IUserSession |
|||
*/ |
|||
private $user; |
|||
|
|||
/** |
|||
* UserHooks constructor. |
|||
* |
|||
* @param KeyManager $keyManager |
|||
* @param ILogger $logger |
|||
* @param Setup $userSetup |
|||
* @param Migrator $migrator |
|||
* @param IUserSession $user |
|||
*/ |
|||
public function __construct( |
|||
KeyManager $keyManager, ILogger $logger, Setup $userSetup, Migrator $migrator, IUserSession $user) { |
|||
|
|||
$this->keyManager = $keyManager; |
|||
$this->logger = $logger; |
|||
$this->userSetup = $userSetup; |
|||
$this->migrator = $migrator; |
|||
$this->user = $user; |
|||
} |
|||
|
|||
/** |
|||
* Connects Hooks |
|||
* |
|||
* @return null |
|||
*/ |
|||
public function addHooks() { |
|||
Util::connectHook('OC_User', 'post_login', $this, 'login'); |
|||
Util::connectHook('OC_User', 'logout', $this, 'logout'); |
|||
Util::connectHook('OC_User', 'post_setPassword', $this, 'setPassphrase'); |
|||
Util::connectHook('OC_User', 'pre_setPassword', $this, 'preSetPassphrase'); |
|||
Util::connectHook('OC_User', 'post_createUser', $this, 'postCreateUser'); |
|||
Util::connectHook('OC_User', 'post_deleteUser', $this, 'postDeleteUser'); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* Startup encryption backend upon user login |
|||
* |
|||
* @note This method should never be called for users using client side encryption |
|||
*/ |
|||
public function login($params) { |
|||
|
|||
if (!App::isEnabled('encryption')) { |
|||
return true; |
|||
} |
|||
|
|||
// ensure filesystem is loaded
|
|||
// Todo: update?
|
|||
if (!\OC\Files\Filesystem::$loaded) { |
|||
\OC_Util::setupFS($params['uid']); |
|||
} |
|||
|
|||
// setup user, if user not ready force relogin
|
|||
if (!$this->userSetup->setupUser($params['password'])) { |
|||
return false; |
|||
} |
|||
|
|||
$cache = $this->keyManager->init(); |
|||
|
|||
// Check if first-run file migration has already been performed
|
|||
$ready = false; |
|||
$migrationStatus = $this->migrator->getStatus($params['uid']); |
|||
if ($migrationStatus === Migrator::$migrationOpen && $cache !== false) { |
|||
$ready = $this->migrator->beginMigration(); |
|||
} elseif ($migrationStatus === Migrator::$migrationInProgress) { |
|||
// refuse login as long as the initial encryption is running
|
|||
sleep(5); |
|||
$this->user->logout(); |
|||
return false; |
|||
} |
|||
|
|||
$result = true; |
|||
|
|||
// If migration not yet done
|
|||
if ($ready) { |
|||
|
|||
// Encrypt existing user files
|
|||
try { |
|||
$result = $util->encryptAll('/' . $params['uid'] . '/' . 'files'); |
|||
} catch (\Exception $ex) { |
|||
\OCP\Util::writeLog('Encryption library', 'Initial encryption failed! Error: ' . $ex->getMessage(), \OCP\Util::FATAL); |
|||
$result = false; |
|||
} |
|||
|
|||
if ($result) { |
|||
\OC_Log::write( |
|||
'Encryption library', 'Encryption of existing files belonging to "' . $params['uid'] . '" completed' |
|||
, \OC_Log::INFO |
|||
); |
|||
// Register successful migration in DB
|
|||
$util->finishMigration(); |
|||
} else { |
|||
\OCP\Util::writeLog('Encryption library', 'Initial encryption failed!', \OCP\Util::FATAL); |
|||
$util->resetMigrationStatus(); |
|||
\OCP\User::logout(); |
|||
} |
|||
} |
|||
|
|||
return $result; |
|||
} |
|||
|
|||
/** |
|||
* remove keys from session during logout |
|||
*/ |
|||
public function logout() { |
|||
$session = new Session(new \OC\Files\View()); |
|||
$session->removeKeys(); |
|||
} |
|||
|
|||
/** |
|||
* setup encryption backend upon user created |
|||
* |
|||
* @note This method should never be called for users using client side encryption |
|||
*/ |
|||
public function postCreateUser($params) { |
|||
|
|||
if (App::isEnabled('files_encryption')) { |
|||
$view = new \OC\Files\View('/'); |
|||
$util = new Util($view, $params['uid']); |
|||
Helper::setupUser($util, $params['password']); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* cleanup encryption backend upon user deleted |
|||
* |
|||
* @note This method should never be called for users using client side encryption |
|||
*/ |
|||
public function postDeleteUser($params) { |
|||
|
|||
if (App::isEnabled('files_encryption')) { |
|||
Keymanager::deletePublicKey(new \OC\Files\View(), $params['uid']); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* If the password can't be changed within ownCloud, than update the key password in advance. |
|||
*/ |
|||
public function preSetPassphrase($params) { |
|||
if (App::isEnabled('files_encryption')) { |
|||
if (!\OC_User::canUserChangePassword($params['uid'])) { |
|||
self::setPassphrase($params); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Change a user's encryption passphrase |
|||
* |
|||
* @param array $params keys: uid, password |
|||
*/ |
|||
public function setPassphrase($params) { |
|||
if (App::isEnabled('files_encryption') === false) { |
|||
return true; |
|||
} |
|||
|
|||
// Only attempt to change passphrase if server-side encryption
|
|||
// is in use (client-side encryption does not have access to
|
|||
// the necessary keys)
|
|||
if (Crypt::mode() === 'server') { |
|||
|
|||
$view = new \OC\Files\View('/'); |
|||
$session = new Session($view); |
|||
|
|||
// Get existing decrypted private key
|
|||
$privateKey = $session->getPrivateKey(); |
|||
|
|||
if ($params['uid'] === \OCP\User::getUser() && $privateKey) { |
|||
|
|||
// Encrypt private key with new user pwd as passphrase
|
|||
$encryptedPrivateKey = Crypt::symmetricEncryptFileContent($privateKey, $params['password'], Helper::getCipher()); |
|||
|
|||
// Save private key
|
|||
if ($encryptedPrivateKey) { |
|||
Keymanager::setPrivateKey($encryptedPrivateKey, \OCP\User::getUser()); |
|||
} else { |
|||
\OCP\Util::writeLog('files_encryption', 'Could not update users encryption password', \OCP\Util::ERROR); |
|||
} |
|||
|
|||
// NOTE: Session does not need to be updated as the
|
|||
// private key has not changed, only the passphrase
|
|||
// used to decrypt it has changed
|
|||
|
|||
|
|||
} else { // admin changed the password for a different user, create new keys and reencrypt file keys
|
|||
|
|||
$user = $params['uid']; |
|||
$util = new Util($view, $user); |
|||
$recoveryPassword = isset($params['recoveryPassword']) ? $params['recoveryPassword'] : null; |
|||
|
|||
// we generate new keys if...
|
|||
// ...we have a recovery password and the user enabled the recovery key
|
|||
// ...encryption was activated for the first time (no keys exists)
|
|||
// ...the user doesn't have any files
|
|||
if (($util->recoveryEnabledForUser() && $recoveryPassword) |
|||
|| !$util->userKeysExists() |
|||
|| !$view->file_exists($user . '/files') |
|||
) { |
|||
|
|||
// backup old keys
|
|||
$util->backupAllKeys('recovery'); |
|||
|
|||
$newUserPassword = $params['password']; |
|||
|
|||
// make sure that the users home is mounted
|
|||
\OC\Files\Filesystem::initMountPoints($user); |
|||
|
|||
$keypair = Crypt::createKeypair(); |
|||
|
|||
// Disable encryption proxy to prevent recursive calls
|
|||
$proxyStatus = \OC_FileProxy::$enabled; |
|||
\OC_FileProxy::$enabled = false; |
|||
|
|||
// Save public key
|
|||
Keymanager::setPublicKey($keypair['publicKey'], $user); |
|||
|
|||
// Encrypt private key with new password
|
|||
$encryptedKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $newUserPassword, Helper::getCipher()); |
|||
if ($encryptedKey) { |
|||
Keymanager::setPrivateKey($encryptedKey, $user); |
|||
|
|||
if ($recoveryPassword) { // if recovery key is set we can re-encrypt the key files
|
|||
$util = new Util($view, $user); |
|||
$util->recoverUsersFiles($recoveryPassword); |
|||
} |
|||
} else { |
|||
\OCP\Util::writeLog('files_encryption', 'Could not update users encryption password', \OCP\Util::ERROR); |
|||
} |
|||
|
|||
\OC_FileProxy::$enabled = $proxyStatus; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* after password reset we create a new key pair for the user |
|||
* |
|||
* @param array $params |
|||
*/ |
|||
public function postPasswordReset($params) { |
|||
$uid = $params['uid']; |
|||
$password = $params['password']; |
|||
|
|||
$util = new Util(new \OC\Files\View(), $uid); |
|||
$util->replaceUserKeys($password); |
|||
} |
|||
} |
|||
@ -0,0 +1,116 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <fallen013@gmail.com> |
|||
* @since 3/6/15, 2:28 PM |
|||
* @link http:/www.clarkt.com |
|||
* @copyright Clark Tomlinson © 2015 |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Encryption\Crypto; |
|||
|
|||
|
|||
use OCP\Encryption\IEncryptionModule; |
|||
|
|||
class Encryption extends Crypt implements IEncryptionModule { |
|||
|
|||
/** |
|||
* @return string defining the technical unique id |
|||
*/ |
|||
public function getId() { |
|||
// TODO: Implement getId() method.
|
|||
} |
|||
|
|||
/** |
|||
* In comparison to getKey() this function returns a human readable (maybe translated) name |
|||
* |
|||
* @return string |
|||
*/ |
|||
public function getDisplayName() { |
|||
// TODO: Implement getDisplayName() method.
|
|||
} |
|||
|
|||
/** |
|||
* 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 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, $header, $accessList) { |
|||
// TODO: Implement begin() method.
|
|||
} |
|||
|
|||
/** |
|||
* 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) { |
|||
// TODO: Implement end() method.
|
|||
} |
|||
|
|||
/** |
|||
* encrypt data |
|||
* |
|||
* @param string $data you want to encrypt |
|||
* @return mixed encrypted data |
|||
*/ |
|||
public function encrypt($data) { |
|||
// Todo: xxx Update Signature and usages
|
|||
$this->symmetricEncryptFileContent($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, $user) { |
|||
// Todo: xxx Update Usages?
|
|||
$this->symmetricDecryptFileContent($data, $user); |
|||
} |
|||
|
|||
/** |
|||
* 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) { |
|||
// TODO: Implement update() method.
|
|||
} |
|||
|
|||
/** |
|||
* should the file be encrypted or not |
|||
* |
|||
* @param string $path |
|||
* @return boolean |
|||
*/ |
|||
public function shouldEncrypt($path) { |
|||
// TODO: Implement shouldEncrypt() method.
|
|||
} |
|||
|
|||
/** |
|||
* calculate unencrypted size |
|||
* |
|||
* @param string $path to file |
|||
* @return integer unencrypted size |
|||
*/ |
|||
public function calculateUnencryptedSize($path) { |
|||
// TODO: Implement calculateUnencryptedSize() method.
|
|||
} |
|||
} |
|||
@ -0,0 +1,355 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/19/15, 1:42 PM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Encryption\Crypto; |
|||
|
|||
|
|||
use OC\Encryption\Exceptions\DecryptionFailedException; |
|||
use OC\Encryption\Exceptions\EncryptionFailedException; |
|||
use OC\Encryption\Exceptions\GenericEncryptionException; |
|||
use OCP\IConfig; |
|||
use OCP\ILogger; |
|||
use OCP\IUser; |
|||
use OCP\IUserSession; |
|||
|
|||
class Crypt { |
|||
|
|||
const ENCRYPTION_UKNOWN_ERROR = -1; |
|||
const ENCRYPTION_NOT_INIALIZED_ERROR = 1; |
|||
const ENCRYPTIION_PRIVATE_KEY_NOT_VALID_ERROR = 2; |
|||
const ENCRYPTION_NO_SHARE_KEY_FOUND = 3; |
|||
|
|||
const BLOCKSIZE = 8192; |
|||
const DEFAULT_CIPHER = 'AES-256-CFB'; |
|||
|
|||
const HEADERSTART = 'HBEGIN'; |
|||
const HEADEREND = 'HEND'; |
|||
/** |
|||
* @var ILogger |
|||
*/ |
|||
private $logger; |
|||
/** |
|||
* @var IUser |
|||
*/ |
|||
private $user; |
|||
/** |
|||
* @var IConfig |
|||
*/ |
|||
private $config; |
|||
|
|||
/** |
|||
* @param ILogger $logger |
|||
* @param IUserSession $userSession |
|||
* @param IConfig $config |
|||
*/ |
|||
public function __construct(ILogger $logger, IUserSession $userSession, IConfig $config) { |
|||
$this->logger = $logger; |
|||
$this->user = $userSession && $userSession->isLoggedIn() ? $userSession->getUser() : false; |
|||
$this->config = $config; |
|||
} |
|||
|
|||
/** |
|||
* @param null $user |
|||
* @return string |
|||
*/ |
|||
public function mode($user = null) { |
|||
return 'server'; |
|||
} |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
public function createKeyPair() { |
|||
|
|||
$log = $this->logger; |
|||
$res = $this->getOpenSSLPKey(); |
|||
|
|||
if (!$res) { |
|||
$log->error("Encryption Library could'nt generate users key-pair for {$this->user->getUID()}", ['app' => 'encryption']); |
|||
|
|||
if (openssl_error_string()) { |
|||
$log->error('Encryption library openssl_pkey_new() fails: ' . openssl_error_string(), ['app' => 'encryption']); |
|||
} |
|||
} elseif (openssl_pkey_export($res, $privateKey, null, $this->getOpenSSLConfig())) { |
|||
$keyDetails = openssl_pkey_get_details($res); |
|||
$publicKey = $keyDetails['key']; |
|||
|
|||
return [ |
|||
'publicKey' => $publicKey, |
|||
'privateKey' => $privateKey |
|||
]; |
|||
} |
|||
$log->error('Encryption library couldn\'t export users private key, please check your servers openSSL configuration.' . $user->getUID(), ['app' => 'encryption']); |
|||
if (openssl_error_string()) { |
|||
$log->error('Encryption Library:' . openssl_error_string(), ['app' => 'encryption']); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* @return resource |
|||
*/ |
|||
public function getOpenSSLPKey() { |
|||
$config = $this->getOpenSSLConfig(); |
|||
return openssl_pkey_new($config); |
|||
} |
|||
|
|||
/** |
|||
* @return array |
|||
*/ |
|||
private function getOpenSSLConfig() { |
|||
$config = ['private_key_bits' => 4096]; |
|||
$config = array_merge(\OC::$server->getConfig()->getSystemValue('openssl', []), $config); |
|||
return $config; |
|||
} |
|||
|
|||
/** |
|||
* @param $plainContent |
|||
* @param $passphrase |
|||
* @return bool|string |
|||
* @throws GenericEncryptionException |
|||
*/ |
|||
public function symmetricEncryptFileContent($plainContent, $passphrase) { |
|||
|
|||
if (!$plainContent) { |
|||
$this->logger->error('Encryption Library, symmetrical encryption failed no content given', ['app' => 'encryption']); |
|||
return false; |
|||
} |
|||
|
|||
$iv = $this->generateIv(); |
|||
|
|||
try { |
|||
$encryptedContent = $this->encrypt($plainContent, $iv, $passphrase, $this->getCipher()); |
|||
// combine content to encrypt the IV identifier and actual IV
|
|||
$catFile = $this->concatIV($encryptedContent, $iv); |
|||
$padded = $this->addPadding($catFile); |
|||
|
|||
return $padded; |
|||
} catch (EncryptionFailedException $e) { |
|||
$message = 'Could not encrypt file content (code: ' . $e->getCode() . '): '; |
|||
$this->logger->error('files_encryption' . $message . $e->getMessage(), ['app' => 'encryption']); |
|||
return false; |
|||
} |
|||
|
|||
} |
|||
|
|||
/** |
|||
* @param $plainContent |
|||
* @param $iv |
|||
* @param string $passphrase |
|||
* @param string $cipher |
|||
* @return string |
|||
* @throws EncryptionFailedException |
|||
*/ |
|||
private function encrypt($plainContent, $iv, $passphrase = '', $cipher = self::DEFAULT_CIPHER) { |
|||
$encryptedContent = openssl_encrypt($plainContent, $cipher, $passphrase, false, $iv); |
|||
|
|||
if (!$encryptedContent) { |
|||
$error = 'Encryption (symmetric) of content failed'; |
|||
$this->logger->error($error . openssl_error_string(), ['app' => 'encryption']); |
|||
throw new EncryptionFailedException($error); |
|||
} |
|||
|
|||
return $encryptedContent; |
|||
} |
|||
|
|||
/** |
|||
* @return mixed|string |
|||
*/ |
|||
public function getCipher() { |
|||
$cipher = $this->config->getSystemValue('cipher', self::DEFAULT_CIPHER); |
|||
if ($cipher !== 'AES-256-CFB' || $cipher !== 'AES-128-CFB') { |
|||
$this->logger->warning('Wrong cipher defined in config.php only AES-128-CFB and AES-256-CFB are supported. Fall back' . self::DEFAULT_CIPHER, ['app' => 'encryption']); |
|||
$cipher = self::DEFAULT_CIPHER; |
|||
} |
|||
|
|||
return $cipher; |
|||
} |
|||
|
|||
/** |
|||
* @param $encryptedContent |
|||
* @param $iv |
|||
* @return string |
|||
*/ |
|||
private function concatIV($encryptedContent, $iv) { |
|||
return $encryptedContent . '00iv00' . $iv; |
|||
} |
|||
|
|||
/** |
|||
* @param $data |
|||
* @return string |
|||
*/ |
|||
private function addPadding($data) { |
|||
return $data . 'xx'; |
|||
} |
|||
|
|||
/** |
|||
* @param $recoveryKey |
|||
* @param $password |
|||
* @return bool|string |
|||
*/ |
|||
public function decryptPrivateKey($recoveryKey, $password) { |
|||
|
|||
$header = $this->parseHeader($recoveryKey); |
|||
$cipher = $this->getCipher($header); |
|||
|
|||
// If we found a header we need to remove it from the key we want to decrypt
|
|||
if (!empty($header)) { |
|||
$recoveryKey = substr($recoveryKey, strpos($recoveryKey, self::HEADEREND) + strlen(self::HEADERSTART)); |
|||
} |
|||
|
|||
$plainKey = $this->symmetricDecryptFileContent($recoveryKey, $password, $cipher); |
|||
|
|||
// Check if this is a valid private key
|
|||
$res = openssl_get_privatekey($plainKey); |
|||
if (is_resource($res)) { |
|||
$sslInfo = openssl_pkey_get_details($res); |
|||
if (!isset($sslInfo['key'])) { |
|||
return false; |
|||
} |
|||
} else { |
|||
return false; |
|||
} |
|||
|
|||
return $plainKey; |
|||
} |
|||
|
|||
/** |
|||
* @param $keyFileContents |
|||
* @param string $passphrase |
|||
* @param string $cipher |
|||
* @return bool|string |
|||
* @throws DecryptionFailedException |
|||
*/ |
|||
public function symmetricDecryptFileContent($keyFileContents, $passphrase = '', $cipher = self::DEFAULT_CIPHER) { |
|||
// Remove Padding
|
|||
$noPadding = $this->removePadding($keyFileContents); |
|||
|
|||
$catFile = $this->splitIv($noPadding); |
|||
|
|||
$plainContent = $this->decrypt($catFile['encrypted'], $catFile['iv'], $passphrase, $cipher); |
|||
|
|||
if ($plainContent) { |
|||
return $plainContent; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* @param $padded |
|||
* @return bool|string |
|||
*/ |
|||
private function removePadding($padded) { |
|||
if (substr($padded, -2) === 'xx') { |
|||
return substr($padded, 0, -2); |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* @param $catFile |
|||
* @return array |
|||
*/ |
|||
private function splitIv($catFile) { |
|||
// Fetch encryption metadata from end of file
|
|||
$meta = substr($catFile, -22); |
|||
|
|||
// Fetch IV from end of file
|
|||
$iv = substr($meta, -16); |
|||
|
|||
// Remove IV and IV Identifier text to expose encrypted content
|
|||
|
|||
$encrypted = substr($catFile, 0, -22); |
|||
|
|||
return [ |
|||
'encrypted' => $encrypted, |
|||
'iv' => $iv |
|||
]; |
|||
} |
|||
|
|||
/** |
|||
* @param $encryptedContent |
|||
* @param $iv |
|||
* @param string $passphrase |
|||
* @param string $cipher |
|||
* @return string |
|||
* @throws DecryptionFailedException |
|||
*/ |
|||
private function decrypt($encryptedContent, $iv, $passphrase = '', $cipher = self::DEFAULT_CIPHER) { |
|||
$plainContent = openssl_decrypt($encryptedContent, $cipher, $passphrase, false, $iv); |
|||
|
|||
if ($plainContent) { |
|||
return $plainContent; |
|||
} else { |
|||
throw new DecryptionFailedException('Encryption library: Decryption (symmetric) of content failed'); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* @param $data |
|||
* @return array |
|||
*/ |
|||
private function parseHeader($data) { |
|||
$result = []; |
|||
|
|||
if (substr($data, 0, strlen(self::HEADERSTART)) === self::HEADERSTART) { |
|||
$endAt = strpos($data, self::HEADEREND); |
|||
$header = substr($data, 0, $endAt + strlen(self::HEADEREND)); |
|||
|
|||
// +1 not to start with an ':' which would result in empty element at the beginning
|
|||
$exploded = explode(':', substr($header, strlen(self::HEADERSTART) + 1)); |
|||
|
|||
$element = array_shift($exploded); |
|||
|
|||
while ($element != self::HEADEREND) { |
|||
$result[$element] = array_shift($exploded); |
|||
$element = array_shift($exploded); |
|||
} |
|||
} |
|||
|
|||
return $result; |
|||
} |
|||
|
|||
/** |
|||
* @return string |
|||
* @throws GenericEncryptionException |
|||
*/ |
|||
private function generateIv() { |
|||
$random = openssl_random_pseudo_bytes(12, $strong); |
|||
if ($random) { |
|||
if (!$strong) { |
|||
// If OpenSSL indicates randomness is insecure log error
|
|||
$this->logger->error('Encryption Library: Insecure symmetric key was generated using openssl_random_psudo_bytes()', ['app' => 'encryption']); |
|||
} |
|||
|
|||
/* |
|||
* We encode the iv purely for string manipulation |
|||
* purposes -it gets decoded before use |
|||
*/ |
|||
return base64_encode($random); |
|||
} |
|||
// If we ever get here we've failed anyway no need for an else
|
|||
throw new GenericEncryptionException('Generating IV Failed'); |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,64 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/19/15, 10:13 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Encryption; |
|||
|
|||
|
|||
use OCA\Encryption\Hooks\Contracts\IHook; |
|||
|
|||
class HookManager { |
|||
|
|||
private $hookInstances = []; |
|||
|
|||
/** |
|||
* @param array|IHook $instances |
|||
* - This accepts either a single instance of IHook or an array of instances of IHook |
|||
* @return bool |
|||
*/ |
|||
public function registerHook($instances) { |
|||
if (is_array($instances)) { |
|||
foreach ($instances as $instance) { |
|||
if (!$instance instanceof IHook) { |
|||
return false; |
|||
} |
|||
$this->hookInstances[] = $instance; |
|||
return true; |
|||
} |
|||
|
|||
} |
|||
$this->hookInstances[] = $instances; |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
public function fireHooks() { |
|||
foreach ($this->hookInstances as $instance) { |
|||
/** |
|||
* @var $instance IHook |
|||
*/ |
|||
$instance->addHooks(); |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,217 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/19/15, 1:20 PM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Encryption; |
|||
|
|||
|
|||
use OC\Encryption\Exceptions\PrivateKeyMissingException; |
|||
use OC\Encryption\Exceptions\PublicKeyMissingException; |
|||
use OCA\Encryption\Crypto\Crypt; |
|||
use OCP\Encryption\IKeyStorage; |
|||
use OCP\IConfig; |
|||
use OCP\IUser; |
|||
use OCP\IUserSession; |
|||
|
|||
class KeyManager { |
|||
|
|||
/** |
|||
* @var IKeyStorage |
|||
*/ |
|||
private $keyStorage; |
|||
|
|||
/** |
|||
* @var Crypt |
|||
*/ |
|||
private $crypt; |
|||
/** |
|||
* @var string |
|||
*/ |
|||
private $recoveryKeyId; |
|||
/** |
|||
* @var string |
|||
*/ |
|||
private $publicShareKeyId; |
|||
/** |
|||
* @var string UserID |
|||
*/ |
|||
private $keyId; |
|||
|
|||
/** |
|||
* @var string |
|||
*/ |
|||
private $publicKeyId = '.public'; |
|||
/** |
|||
* @var string |
|||
*/ |
|||
private $privateKeyId = '.private'; |
|||
/** |
|||
* @var IConfig |
|||
*/ |
|||
private $config; |
|||
|
|||
/** |
|||
* @param IKeyStorage $keyStorage |
|||
* @param Crypt $crypt |
|||
* @param IConfig $config |
|||
* @param IUserSession $userSession |
|||
*/ |
|||
public function __construct(IKeyStorage $keyStorage, Crypt $crypt, IConfig $config, IUserSession $userSession) { |
|||
|
|||
$this->keyStorage = $keyStorage; |
|||
$this->crypt = $crypt; |
|||
$this->config = $config; |
|||
$this->recoveryKeyId = $this->config->getAppValue('encryption', 'recoveryKeyId'); |
|||
$this->publicShareKeyId = $this->config->getAppValue('encryption', 'publicShareKeyId'); |
|||
$this->keyId = $userSession && $userSession->isLoggedIn() ? $userSession->getUser()->getUID() : false; |
|||
|
|||
} |
|||
|
|||
/** |
|||
* @param $userId |
|||
* @return mixed |
|||
* @throws PrivateKeyMissingException |
|||
*/ |
|||
public function getPrivateKey($userId) { |
|||
$privateKey = $this->keyStorage->getUserKey($userId, $this->privateKeyId); |
|||
|
|||
if (strlen($privateKey) !== 0) { |
|||
return $privateKey; |
|||
} |
|||
throw new PrivateKeyMissingException(); |
|||
} |
|||
|
|||
/** |
|||
* @param $userId |
|||
* @return mixed |
|||
* @throws PublicKeyMissingException |
|||
*/ |
|||
public function getPublicKey($userId) { |
|||
$publicKey = $this->keyStorage->getUserKey($userId, $this->publicKeyId); |
|||
|
|||
if (strlen($publicKey) !== 0) { |
|||
return $publicKey; |
|||
} |
|||
throw new PublicKeyMissingException(); |
|||
} |
|||
|
|||
/** |
|||
* @return bool |
|||
*/ |
|||
public function recoveryKeyExists() { |
|||
return (strlen($this->keyStorage->getSystemUserKey($this->recoveryKeyId)) !== 0); |
|||
} |
|||
|
|||
/** |
|||
* @param $userId |
|||
* @return bool |
|||
*/ |
|||
public function userHasKeys($userId) { |
|||
try { |
|||
$this->getPrivateKey($userId); |
|||
$this->getPublicKey($userId); |
|||
} catch (PrivateKeyMissingException $e) { |
|||
return false; |
|||
} catch (PublicKeyMissingException $e) { |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* @param $password |
|||
* @return bool |
|||
*/ |
|||
public function checkRecoveryPassword($password) { |
|||
$recoveryKey = $this->keyStorage->getSystemUserKey($this->recoveryKeyId); |
|||
$decryptedRecoveryKey = $this->crypt->decryptPrivateKey($recoveryKey, $password); |
|||
|
|||
if ($decryptedRecoveryKey) { |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* @param $userId |
|||
* @param $key |
|||
* @return bool |
|||
*/ |
|||
public function setPublicKey($userId, $key) { |
|||
return $this->keyStorage->setUserKey($userId, $this->publicKeyId, $key); |
|||
} |
|||
|
|||
/** |
|||
* @param $userId |
|||
* @param $key |
|||
* @return bool |
|||
*/ |
|||
public function setPrivateKey($userId, $key) { |
|||
return $this->keyStorage->setUserKey($userId, $this->privateKeyId, $key); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* @param $password |
|||
* @param $keyPair |
|||
* @return bool |
|||
*/ |
|||
public function storeKeyPair($password, $keyPair) { |
|||
// Save Public Key
|
|||
$this->setPublicKey($this->keyId, $keyPair['publicKey']); |
|||
|
|||
$encryptedKey = $this->crypt->symmetricEncryptFileContent($keyPair['privateKey'], $password); |
|||
|
|||
if ($encryptedKey) { |
|||
$this->setPrivateKey($this->keyId, $encryptedKey); |
|||
$this->config->setAppValue('encryption', 'recoveryAdminEnabled', 1); |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* @return bool |
|||
*/ |
|||
public function ready() { |
|||
return $this->keyStorage->ready(); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* @return \OCP\ICache |
|||
* @throws PrivateKeyMissingException |
|||
*/ |
|||
public function init() { |
|||
try { |
|||
$privateKey = $this->getPrivateKey($this->keyId); |
|||
} catch (PrivateKeyMissingException $e) { |
|||
return false; |
|||
} |
|||
|
|||
$cache = \OC::$server->getMemCacheFactory(); |
|||
|
|||
$cacheInstance = $cache->create('Encryption'); |
|||
$cacheInstance->set('privateKey', $privateKey); |
|||
|
|||
return $cacheInstance; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,123 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <fallen013@gmail.com> |
|||
* @since 3/9/15, 2:44 PM |
|||
* @link http:/www.clarkt.com |
|||
* @copyright Clark Tomlinson © 2015 |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Encryption; |
|||
|
|||
|
|||
use OCA\Encryption\Crypto\Crypt; |
|||
use OCP\IConfig; |
|||
use OCP\ILogger; |
|||
use OCP\IUserManager; |
|||
use OCP\IUserSession; |
|||
use OCP\PreConditionNotMetException; |
|||
|
|||
class Migrator { |
|||
|
|||
/** |
|||
* @var bool |
|||
*/ |
|||
private $status = false; |
|||
/** |
|||
* @var IUserManager |
|||
*/ |
|||
private $user; |
|||
/** |
|||
* @var IConfig |
|||
*/ |
|||
private $config; |
|||
/** |
|||
* @var string |
|||
*/ |
|||
public static $migrationOpen = '0'; |
|||
/** |
|||
* @var string |
|||
*/ |
|||
public static $migrationInProgress = '-1'; |
|||
/** |
|||
* @var string |
|||
*/ |
|||
public static $migrationComplete = '1'; |
|||
/** |
|||
* @var IUserManager |
|||
*/ |
|||
private $userManager; |
|||
/** |
|||
* @var ILogger |
|||
*/ |
|||
private $log; |
|||
/** |
|||
* @var Crypt |
|||
*/ |
|||
private $crypt; |
|||
|
|||
/** |
|||
* Migrator constructor. |
|||
* |
|||
* @param IUserSession $userSession |
|||
* @param IConfig $config |
|||
* @param IUserManager $userManager |
|||
* @param ILogger $log |
|||
* @param Crypt $crypt |
|||
*/ |
|||
public function __construct(IUserSession $userSession, IConfig $config, IUserManager $userManager, ILogger $log, Crypt $crypt) { |
|||
$this->user = $userSession && $userSession->isLoggedIn() ? $userSession->getUser() : false; |
|||
$this->config = $config; |
|||
$this->userManager = $userManager; |
|||
$this->log = $log; |
|||
$this->crypt = $crypt; |
|||
} |
|||
|
|||
/** |
|||
* @param $userId |
|||
* @return bool|string |
|||
*/ |
|||
public function getStatus($userId) { |
|||
if ($this->userManager->userExists($userId)) { |
|||
$this->status = $this->config->getUserValue($userId, 'encryption', 'migrationStatus', false); |
|||
|
|||
if (!$this->status) { |
|||
$this->config->setUserValue($userId, 'encryption', 'migrationStatus', self::$migrationOpen); |
|||
$this->status = self::$migrationOpen; |
|||
} |
|||
} |
|||
|
|||
return $this->status; |
|||
} |
|||
|
|||
/** |
|||
* @return bool |
|||
*/ |
|||
public function beginMigration() { |
|||
$status = $this->setMigrationStatus(self::$migrationInProgress, self::$migrationOpen); |
|||
|
|||
if ($status) { |
|||
$this->log->info('Encryption Library Start migration to encrypt for ' . $this->user->getUID()); |
|||
return $status; |
|||
} |
|||
$this->log->warning('Encryption Library Could not activate migration for ' . $this->user->getUID() . '. Probably another process already started the inital encryption'); |
|||
return $status; |
|||
} |
|||
|
|||
/** |
|||
* @param $status |
|||
* @param bool $preCondition |
|||
* @return bool |
|||
*/ |
|||
private function setMigrationStatus($status, $preCondition = false) { |
|||
// Convert to string if preCondition is set
|
|||
$preCondition = ($preCondition === false) ? false : (string)$preCondition; |
|||
|
|||
try { |
|||
$this->config->setUserValue($this->user->getUID(), 'encryption', 'migrationStatus', (string)$status, $preCondition); |
|||
return true; |
|||
} catch (PreConditionNotMetException $e) { |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,134 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/19/15, 11:45 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Encryption; |
|||
|
|||
|
|||
use OC\Files\View; |
|||
use OCA\Encryption\Crypto\Crypt; |
|||
use OCP\Encryption\IKeyStorage; |
|||
use OCP\IConfig; |
|||
use OCP\IUser; |
|||
use OCP\Security\ISecureRandom; |
|||
|
|||
class Recovery { |
|||
|
|||
|
|||
/** |
|||
* @var null|IUser |
|||
*/ |
|||
protected $user; |
|||
/** |
|||
* @var Crypt |
|||
*/ |
|||
protected $crypt; |
|||
/** |
|||
* @var ISecureRandom |
|||
*/ |
|||
private $random; |
|||
/** |
|||
* @var KeyManager |
|||
*/ |
|||
private $keyManager; |
|||
/** |
|||
* @var IConfig |
|||
*/ |
|||
private $config; |
|||
/** |
|||
* @var IEncryptionKeyStorage |
|||
*/ |
|||
private $keyStorage; |
|||
|
|||
/** |
|||
* @param IUser $user |
|||
* @param Crypt $crypt |
|||
* @param ISecureRandom $random |
|||
* @param KeyManager $keyManager |
|||
* @param IConfig $config |
|||
* @param IKeyStorage $keyStorage |
|||
*/ |
|||
public function __construct(IUser $user, |
|||
Crypt $crypt, |
|||
ISecureRandom $random, |
|||
KeyManager $keyManager, |
|||
IConfig $config, |
|||
IKeyStorage $keyStorage) { |
|||
$this->user = $user; |
|||
$this->crypt = $crypt; |
|||
$this->random = $random; |
|||
$this->keyManager = $keyManager; |
|||
$this->config = $config; |
|||
$this->keyStorage = $keyStorage; |
|||
} |
|||
|
|||
/** |
|||
* @param $recoveryKeyId |
|||
* @param $password |
|||
* @return bool |
|||
*/ |
|||
public function enableAdminRecovery($recoveryKeyId, $password) { |
|||
$appConfig = $this->config; |
|||
|
|||
if ($recoveryKeyId === null) { |
|||
$recoveryKeyId = $this->random->getLowStrengthGenerator(); |
|||
$appConfig->setAppValue('encryption', 'recoveryKeyId', $recoveryKeyId); |
|||
} |
|||
|
|||
$keyManager = $this->keyManager; |
|||
|
|||
if (!$keyManager->recoveryKeyExists()) { |
|||
$keyPair = $this->crypt->createKeyPair(); |
|||
|
|||
return $this->keyManager->storeKeyPair($password, $keyPair); |
|||
} |
|||
|
|||
if ($keyManager->checkRecoveryPassword($password)) { |
|||
$appConfig->setAppValue('encryption', 'recoveryAdminEnabled', 1); |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* @param $recoveryPassword |
|||
* @return bool |
|||
*/ |
|||
public function disableAdminRecovery($recoveryPassword) { |
|||
$keyManager = $this->keyManager; |
|||
|
|||
if ($keyManager->checkRecoveryPassword($recoveryPassword)) { |
|||
// Set recoveryAdmin as disabled
|
|||
$this->config->setAppValue('encryption', 'recoveryAdminEnabled', 0); |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
public function addRecoveryKeys($keyId) { |
|||
// No idea new way to do this....
|
|||
} |
|||
|
|||
public function removeRecoveryKeys() { |
|||
// No idea new way to do this....
|
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <fallen013@gmail.com> |
|||
* @since 3/6/15, 11:30 AM |
|||
* @link http:/www.clarkt.com |
|||
* @copyright Clark Tomlinson © 2015 |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Encryption; |
|||
|
|||
|
|||
use OCP\ILogger; |
|||
use OCP\IUser; |
|||
use OCP\IUserSession; |
|||
|
|||
class Setup { |
|||
/** |
|||
* @var ILogger |
|||
*/ |
|||
protected $logger; |
|||
/** |
|||
* @var IUser |
|||
*/ |
|||
protected $user; |
|||
|
|||
/** |
|||
* Setup constructor. |
|||
* |
|||
* @param ILogger $logger |
|||
* @param IUserSession $userSession |
|||
*/ |
|||
public function __construct(ILogger $logger, IUserSession $userSession) { |
|||
$this->logger = $logger; |
|||
$this->user = $userSession && $userSession->isLoggedIn() ? $userSession->getUser()->getUID() : false; |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,63 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <fallen013@gmail.com> |
|||
* @since 3/6/15, 11:36 AM |
|||
* @link http:/www.clarkt.com |
|||
* @copyright Clark Tomlinson © 2015 |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Encryption\Users; |
|||
|
|||
|
|||
use OCA\Encryption\Crypto\Crypt; |
|||
use OCA\Encryption\KeyManager; |
|||
use OCP\ILogger; |
|||
use OCP\IUserSession; |
|||
|
|||
class Setup extends \OCA\Encryption\Setup { |
|||
/** |
|||
* @var Crypt |
|||
*/ |
|||
private $crypt; |
|||
/** |
|||
* @var KeyManager |
|||
*/ |
|||
private $keyManager; |
|||
|
|||
|
|||
/** |
|||
* @param ILogger $logger |
|||
* @param IUserSession $userSession |
|||
* @param Crypt $crypt |
|||
* @param KeyManager $keyManager |
|||
*/ |
|||
public function __construct(ILogger $logger, IUserSession $userSession, Crypt $crypt, KeyManager $keyManager) { |
|||
parent::__construct($logger, $userSession); |
|||
$this->crypt = $crypt; |
|||
$this->keyManager = $keyManager; |
|||
} |
|||
|
|||
/** |
|||
* @param $password |
|||
* @return bool |
|||
*/ |
|||
public function setupUser($password) { |
|||
if ($this->keyManager->ready()) { |
|||
$this->logger->debug('Encryption Library: User Account ' . $this->user->getUID() . ' Is not ready for encryption; configuration started'); |
|||
return $this->setupServerSide($password); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* @param $password |
|||
* @return bool |
|||
*/ |
|||
private function setupServerSide($password) { |
|||
// Check if user already has keys
|
|||
if (!$this->keyManager->userHasKeys($this->user->getUID())) { |
|||
return $this->keyManager->storeKeyPair($password, $this->crypt->createKeyPair()); |
|||
} |
|||
return true; |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
<?php |
|||
/** |
|||
* Copyright (c) 2011 Robin Appelman <icewind@owncloud.com> |
|||
* This file is licensed under the Affero General Public License version 3 or |
|||
* later. |
|||
* See the COPYING-README file. |
|||
*/ |
|||
|
|||
\OC_Util::checkAdminUser(); |
|||
|
|||
$tmpl = new OCP\Template('files_encryption', 'settings-admin'); |
|||
|
|||
// Check if an adminRecovery account is enabled for recovering files after lost pwd
|
|||
$recoveryAdminEnabled = \OC::$server->getAppConfig()->getValue('files_encryption', 'recoveryAdminEnabled', '0'); |
|||
$session = new \OCA\Files_Encryption\Session(new \OC\Files\View('/')); |
|||
$initStatus = $session->getInitialized(); |
|||
|
|||
$tmpl->assign('recoveryEnabled', $recoveryAdminEnabled); |
|||
$tmpl->assign('initStatus', $initStatus); |
|||
|
|||
\OCP\Util::addscript('files_encryption', 'settings-admin'); |
|||
\OCP\Util::addscript('core', 'multiselect'); |
|||
|
|||
return $tmpl->fetchPage(); |
|||
@ -0,0 +1,41 @@ |
|||
<?php |
|||
/** |
|||
* Copyright (c) 2013 Sam Tuke <samtuke@owncloud.com> |
|||
* This file is licensed under the Affero General Public License version 3 or |
|||
* later. |
|||
* See the COPYING-README file. |
|||
*/ |
|||
|
|||
// Add CSS stylesheet
|
|||
\OC_Util::addStyle('files_encryption', 'settings-personal'); |
|||
|
|||
$tmpl = new OCP\Template('files_encryption', 'settings-personal'); |
|||
|
|||
$user = \OCP\USER::getUser(); |
|||
$view = new \OC\Files\View('/'); |
|||
$util = new \OCA\Files_Encryption\Util($view, $user); |
|||
$session = new \OCA\Files_Encryption\Session($view); |
|||
|
|||
$privateKeySet = $session->getPrivateKey() !== false; |
|||
// did we tried to initialize the keys for this session?
|
|||
$initialized = $session->getInitialized(); |
|||
|
|||
$recoveryAdminEnabled = \OC::$server->getAppConfig()->getValue('files_encryption', 'recoveryAdminEnabled'); |
|||
$recoveryEnabledForUser = $util->recoveryEnabledForUser(); |
|||
|
|||
$result = false; |
|||
|
|||
if ($recoveryAdminEnabled || !$privateKeySet) { |
|||
|
|||
\OCP\Util::addscript('files_encryption', 'settings-personal'); |
|||
|
|||
$tmpl->assign('recoveryEnabled', $recoveryAdminEnabled); |
|||
$tmpl->assign('recoveryEnabledForUser', $recoveryEnabledForUser); |
|||
$tmpl->assign('privateKeySet', $privateKeySet); |
|||
$tmpl->assign('initialized', $initialized); |
|||
|
|||
$result = $tmpl->fetchPage(); |
|||
} |
|||
|
|||
return $result; |
|||
|
|||
@ -0,0 +1,90 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <fallen013@gmail.com> |
|||
* @since 3/5/15, 10:53 AM |
|||
* @link http:/www.clarkt.com |
|||
* @copyright Clark Tomlinson © 2015 |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Encryption\Tests; |
|||
|
|||
|
|||
use OCA\Encryption\KeyManager; |
|||
use Test\TestCase; |
|||
|
|||
class KeyManagerTest extends TestCase { |
|||
/** |
|||
* @var KeyManager |
|||
*/ |
|||
private $instance; |
|||
/** |
|||
* @var |
|||
*/ |
|||
private $userId; |
|||
/** |
|||
* @var |
|||
*/ |
|||
private $dummyKeys; |
|||
|
|||
public function setUp() { |
|||
parent::setUp(); |
|||
$keyStorageMock = $this->getMock('OCP\Encryption\IKeyStorage'); |
|||
$cryptMock = $this->getMockBuilder('OCA\Encryption\Crypt') |
|||
->disableOriginalConstructor() |
|||
->getMock(); |
|||
$configMock = $this->getMock('OCP\IConfig'); |
|||
$userMock = $this->getMock('OCP\IUser'); |
|||
$userMock->expects($this->once()) |
|||
->method('getUID') |
|||
->will($this->returnValue('admin')); |
|||
$this->userId = 'admin'; |
|||
$this->instance = new KeyManager($keyStorageMock, $cryptMock, $configMock, $userMock); |
|||
|
|||
$this->dummyKeys = ['public' => 'randomweakpublickeyhere', |
|||
'private' => 'randomweakprivatekeyhere']; |
|||
} |
|||
|
|||
/** |
|||
* @expectedException OC\Encryption\Exceptions\PrivateKeyMissingException |
|||
*/ |
|||
public function testGetPrivateKey() { |
|||
$this->assertFalse($this->instance->getPrivateKey($this->userId)); |
|||
} |
|||
|
|||
/** |
|||
* @expectedException OC\Encryption\Exceptions\PublicKeyMissingException |
|||
*/ |
|||
public function testGetPublicKey() { |
|||
$this->assertFalse($this->instance->getPublicKey($this->userId)); |
|||
} |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
public function testRecoveryKeyExists() { |
|||
$this->assertFalse($this->instance->recoveryKeyExists()); |
|||
} |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
public function testCheckRecoveryKeyPassword() { |
|||
$this->assertFalse($this->instance->checkRecoveryPassword('pass')); |
|||
} |
|||
|
|||
public function testSetPublicKey() { |
|||
|
|||
$this->assertTrue($this->instance->setPublicKey($this->userId, $this->dummyKeys['public'])); |
|||
} |
|||
|
|||
public function testSetPrivateKey() { |
|||
$this->assertTrue($this->instance->setPrivateKey($this->userId, $this->dummyKeys['private'])); |
|||
} |
|||
|
|||
public function testUserHasKeys() { |
|||
$this->assertFalse($this->instance->userHasKeys($this->userId)); |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <fallen013@gmail.com> |
|||
* @since 3/9/15, 2:56 PM |
|||
* @link http:/www.clarkt.com |
|||
* @copyright Clark Tomlinson © 2015 |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Encryption\Tests; |
|||
|
|||
|
|||
use OCA\Encryption\Migrator; |
|||
use Test\TestCase; |
|||
|
|||
class MigratorTest extends TestCase { |
|||
|
|||
/** |
|||
* @var Migrator |
|||
*/ |
|||
private $instance; |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
public function testGetStatus() { |
|||
$this->assertFalse($this->instance->getStatus('admin')); |
|||
} |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
public function testBeginMigration() { |
|||
$this->assertTrue($this->instance->beginMigration()); |
|||
} |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
public function testSetMigrationStatus() { |
|||
$this->assertTrue(\Test_Helper::invokePrivate($this->instance, |
|||
'setMigrationStatus', |
|||
['0', '-1']) |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
protected function setUp() { |
|||
parent::setUp(); |
|||
|
|||
$cryptMock = $this->getMockBuilder('OCA\Encryption\Crypto\Crypt')->disableOriginalConstructor()->getMock(); |
|||
$this->instance = new Migrator($this->getMock('OCP\IUser'), |
|||
$this->getMock('OCP\IConfig'), |
|||
$this->getMock('OCP\IUserManager'), |
|||
$this->getMock('OCP\ILogger'), |
|||
$cryptMock); |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,51 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <fallen013@gmail.com> |
|||
* @since 3/6/15, 10:36 AM |
|||
* @link http:/www.clarkt.com |
|||
* @copyright Clark Tomlinson © 2015 |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Encryption\Tests; |
|||
|
|||
|
|||
use OCA\Encryption\RequirementsChecker; |
|||
use Test\TestCase; |
|||
|
|||
class RequirementsCheckerTest extends TestCase { |
|||
/** |
|||
* @var RequirementsChecker |
|||
*/ |
|||
private $instance; |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
protected function setUp() { |
|||
parent::setUp(); |
|||
$log = $this->getMock('OCP\ILogger'); |
|||
$crypt = $this->getMockBuilder('OCA\Encryption\Crypt') |
|||
->disableOriginalConstructor() |
|||
->getMock(); |
|||
$crypt |
|||
->method('getOpenSSLPkey') |
|||
->will($this->returnValue(true)); |
|||
$this->instance = new RequirementsChecker($crypt, $log); |
|||
} |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
public function testCanCheckConfigration() { |
|||
$this->assertTrue($this->instance->checkConfiguration()); |
|||
} |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
public function testCanCheckRequiredExtensions() { |
|||
$this->assertTrue($this->instance->checkExtensions()); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/25/15, 9:38 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
|
|||
namespace OC\Encryption\Exceptions; |
|||
|
|||
|
|||
class DecryptionFailedException extends GenericEncryptionException { |
|||
|
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/25/15, 9:38 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
|
|||
namespace OC\Encryption\Exceptions; |
|||
|
|||
|
|||
class EmptyEncryptionDataException extends GenericEncryptionException{ |
|||
|
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/25/15, 9:37 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
|
|||
namespace OC\Encryption\Exceptions; |
|||
|
|||
|
|||
class EncryptionFailedException extends GenericEncryptionException{ |
|||
|
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/25/15, 9:35 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
|
|||
namespace OC\Encryption\Exceptions; |
|||
|
|||
|
|||
class EncryptionHeaderToLargeException extends GenericEncryptionException { |
|||
|
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/25/15, 9:30 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
namespace OC\Encryption\Exceptions; |
|||
|
|||
|
|||
class GenericEncryptionException extends \Exception { |
|||
|
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/25/15, 9:39 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
|
|||
namespace OC\Encryption\Exceptions; |
|||
|
|||
|
|||
class PrivateKeyMissingException extends GenericEncryptionException{ |
|||
|
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/25/15, 9:39 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
|
|||
namespace OC\Encryption\Exceptions; |
|||
|
|||
|
|||
class PublicKeyMissingException extends GenericEncryptionException { |
|||
|
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/25/15, 9:35 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
|
|||
namespace OC\Encryption\Exceptions; |
|||
|
|||
|
|||
interface UnexpectedBlockSize { |
|||
|
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/25/15, 9:34 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
|
|||
namespace OC\Encryption\Exceptions; |
|||
|
|||
|
|||
class UnexpectedEndOfEncryptionHeaderException extends GenericEncryptionException { |
|||
|
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
<?php |
|||
/** |
|||
* @author Clark Tomlinson <clark@owncloud.com> |
|||
* @since 2/25/15, 9:36 AM |
|||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|||
* @license AGPL-3.0 |
|||
* |
|||
* This code is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License, version 3, |
|||
* as published by the Free Software Foundation. |
|||
* |
|||
* This program 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, version 3, |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
|
|||
namespace OC\Encryption\Exceptions; |
|||
|
|||
|
|||
class UnknownCipherException extends GenericEncryptionException{ |
|||
|
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue