From a057108c0c1ec77b6f61f6f387c0714c84653254 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Wed, 1 Apr 2015 14:24:56 +0200 Subject: [PATCH] make recovery key work --- apps/encryption/appinfo/application.php | 1 + .../controller/recoverycontroller.php | 3 + apps/encryption/hooks/userhooks.php | 23 +++-- apps/encryption/lib/keymanager.php | 14 ++- apps/encryption/lib/recovery.php | 95 ++++++++++--------- settings/changepassword/controller.php | 37 +++++++- settings/users.php | 4 +- 7 files changed, 116 insertions(+), 61 deletions(-) diff --git a/apps/encryption/appinfo/application.php b/apps/encryption/appinfo/application.php index 955146f7182..0d1bd0d6bed 100644 --- a/apps/encryption/appinfo/application.php +++ b/apps/encryption/appinfo/application.php @@ -75,6 +75,7 @@ class Application extends \OCP\AppFramework\App { $server->getUserSession(), $container->query('Util'), new \OCA\Encryption\Session($server->getSession()), + $container->query('Crypt'), $container->query('Recovery')) ]); diff --git a/apps/encryption/controller/recoverycontroller.php b/apps/encryption/controller/recoverycontroller.php index d115feb8e39..24d7f5a06ed 100644 --- a/apps/encryption/controller/recoverycontroller.php +++ b/apps/encryption/controller/recoverycontroller.php @@ -142,6 +142,9 @@ class RecoveryController extends Controller { } } + /** + * @NoAdminRequired + */ public function userSetRecovery($userEnableRecovery) { if ($userEnableRecovery === '0' || $userEnableRecovery === '1') { diff --git a/apps/encryption/hooks/userhooks.php b/apps/encryption/hooks/userhooks.php index 330d8a873ba..3b56135c36b 100644 --- a/apps/encryption/hooks/userhooks.php +++ b/apps/encryption/hooks/userhooks.php @@ -25,6 +25,7 @@ namespace OCA\Encryption\Hooks; use OCP\Util as OCUtil; use OCA\Encryption\Hooks\Contracts\IHook; use OCA\Encryption\KeyManager; +use OCA\Encryption\Crypto\Crypt; use OCA\Encryption\Users\Setup; use OCP\App; use OCP\ILogger; @@ -62,6 +63,10 @@ class UserHooks implements IHook { * @var Recovery */ private $recovery; + /** + * @var Crypt + */ + private $crypt; /** * UserHooks constructor. @@ -72,6 +77,7 @@ class UserHooks implements IHook { * @param IUserSession $user * @param Util $util * @param Session $session + * @param Crypt $crypt * @param Recovery $recovery */ public function __construct(KeyManager $keyManager, @@ -80,6 +86,7 @@ class UserHooks implements IHook { IUserSession $user, Util $util, Session $session, + Crypt $crypt, Recovery $recovery) { $this->keyManager = $keyManager; @@ -89,6 +96,7 @@ class UserHooks implements IHook { $this->util = $util; $this->session = $session; $this->recovery = $recovery; + $this->crypt = $crypt; } /** @@ -214,7 +222,7 @@ class UserHooks implements IHook { // Save private key if ($encryptedPrivateKey) { - $this->setPrivateKey($this->user->getUser()->getUID(), + $this->keyManager->setPrivateKey($this->user->getUser()->getUID(), $encryptedPrivateKey); } else { $this->log->error('Encryption could not update users encryption password'); @@ -231,28 +239,31 @@ class UserHooks implements IHook { // ...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) || !$this->userHasKeys($user) || !$util->userHasFiles($user) + if ( + ($this->recovery->isRecoveryEnabledForUser($user) && $recoveryPassword) + || !$this->keyManager->userHasKeys($user) + || !$this->util->userHasFiles($user) ) { // backup old keys - $this->backupAllKeys('recovery'); + //$this->backupAllKeys('recovery'); $newUserPassword = $params['password']; $keyPair = $this->crypt->createKeyPair(); // Save public key - $this->setPublicKey($user, $keyPair['publicKey']); + $this->keyManager->setPublicKey($user, $keyPair['publicKey']); // Encrypt private key with new password $encryptedKey = $this->crypt->symmetricEncryptFileContent($keyPair['privateKey'], $newUserPassword); if ($encryptedKey) { - $this->setPrivateKey($user, $encryptedKey); + $this->keyManager->setPrivateKey($user, $encryptedKey); if ($recoveryPassword) { // if recovery key is set we can re-encrypt the key files - $this->recovery->recoverUsersFiles($recoveryPassword); + $this->recovery->recoverUsersFiles($recoveryPassword, $user); } } else { $this->log->error('Encryption Could not update users encryption password'); diff --git a/apps/encryption/lib/keymanager.php b/apps/encryption/lib/keymanager.php index f3f96b9ef21..4c5cb1365ea 100644 --- a/apps/encryption/lib/keymanager.php +++ b/apps/encryption/lib/keymanager.php @@ -206,7 +206,6 @@ class KeyManager { if ($encryptedKey) { $this->setPrivateKey($uid, $encryptedKey); - $this->config->setAppValue('encryption', 'recoveryAdminEnabled', 0); return true; } return false; @@ -355,6 +354,19 @@ class KeyManager { throw new FileKeyMissingException(); } + /** + * get the encrypted file key + * + * @param $path + * @return string + */ + public function getEncryptedFileKey($path) { + $encryptedFileKey = $this->keyStorage->getFileKey($path, + $this->fileKeyId); + + return $encryptedFileKey; + } + /** * delete share key * diff --git a/apps/encryption/lib/recovery.php b/apps/encryption/lib/recovery.php index 4201b829ec9..34acdd0a6e3 100644 --- a/apps/encryption/lib/recovery.php +++ b/apps/encryption/lib/recovery.php @@ -156,10 +156,15 @@ class Recovery { } /** + * check if recovery is enabled for user + * + * @param string $user if no user is given we check the current logged-in user + * * @return bool */ - public function recoveryEnabledForUser() { - $recoveryMode = $this->config->getUserValue($this->user->getUID(), + public function isRecoveryEnabledForUser($user = '') { + $uid = empty($user) ? $this->user->getUID() : $user; + $recoveryMode = $this->config->getUserValue($uid, 'encryption', 'recoveryEnabled', 0); @@ -167,6 +172,17 @@ class Recovery { return ($recoveryMode === '1'); } + /** + * check if recovery is key is enabled by the administrator + * + * @return bool + */ + public function isRecoveryKeyEnabled() { + $enabled = $this->config->getAppValue('encryption', 'recoveryAdminEnabled', 0); + + return ($enabled === '1'); + } + /** * @param string $value * @return bool @@ -234,15 +250,18 @@ class Recovery { } /** - * @param $recoveryPassword + * recover users files with the recovery key + * + * @param string $recoveryPassword + * @param string $user */ - public function recoverUsersFiles($recoveryPassword) { - $encryptedKey = $this->keyManager->getSystemPrivateKey(); + public function recoverUsersFiles($recoveryPassword, $user) { + $encryptedKey = $this->keyManager->getSystemPrivateKey($this->keyManager->getRecoveryKeyId()); $privateKey = $this->crypt->decryptPrivateKey($encryptedKey, $recoveryPassword); - $this->recoverAllFiles('/', $privateKey); + $this->recoverAllFiles('/' . $user . '/files/', $privateKey); } /** @@ -250,12 +269,12 @@ class Recovery { * @param $privateKey */ private function recoverAllFiles($path, $privateKey) { - $dirContent = $this->files->getDirectoryContent($path); + $dirContent = $this->view->getDirectoryContent($path); foreach ($dirContent as $item) { // Get relative path from encryption/keyfiles - $filePath = substr($item['path'], strlen('encryption/keys')); - if ($this->files->is_dir($this->user->getUID() . '/files' . '/' . $filePath)) { + $filePath = $item->getPath(); + if ($this->view->is_dir($filePath)) { $this->recoverAllFiles($filePath . '/', $privateKey); } else { $this->recoverFile($filePath, $privateKey); @@ -265,50 +284,32 @@ class Recovery { } /** - * @param $filePath - * @param $privateKey + * @param string $path + * @param string $privateKey */ - private function recoverFile($filePath, $privateKey) { - $sharingEnabled = Share::isEnabled(); - $uid = $this->user->getUID(); - - // Find out who, if anyone, is sharing the file - if ($sharingEnabled) { - $result = Share::getUsersSharingFile($filePath, - $uid, - true); - $userIds = $result['users']; - $userIds[] = 'public'; - } else { - $userIds = [ - $uid, - $this->recoveryKeyId - ]; + private function recoverFile($path, $privateKey) { + $encryptedFileKey = $this->keyManager->getEncryptedFileKey($path); + $shareKey = $this->keyManager->getShareKey($path, $this->keyManager->getRecoveryKeyId()); + + if ($encryptedFileKey && $shareKey && $privateKey) { + $fileKey = $this->crypt->multiKeyDecrypt($encryptedFileKey, + $shareKey, + $privateKey); } - $filteredUids = $this->filterShareReadyUsers($userIds); - // Decrypt file key - $encKeyFile = $this->keyManager->getFileKey($filePath, - $uid); - - $shareKey = $this->keyManager->getShareKey($filePath, - $uid); - - $plainKeyFile = $this->crypt->multiKeyDecrypt($encKeyFile, - $shareKey, - $privateKey); + if (!empty($fileKey)) { + $accessList = $this->file->getAccessList($path); + $publicKeys = array(); + foreach ($accessList['users'] as $uid) { + $publicKeys[$uid] = $this->keyManager->getPublicKey($uid); + } - // Encrypt the file key again to all users, this time with the new publick keyt for the recovered user - $userPublicKeys = $this->keyManager->getPublicKeys($filteredUids['ready']); - $multiEncryptionKey = $this->crypt->multiKeyEncrypt($plainKeyFile, - $userPublicKeys); + $publicKeys = $this->keyManager->addSystemKeys($accessList, $publicKeys); - $this->keyManager->setFileKey($multiEncryptionKey['data'], - $uid); + $encryptedKeyfiles = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys); + $this->keyManager->setAllFileKeys($path, $encryptedKeyfiles); + } - $this->keyManager->setShareKey($filePath, - $uid, - $multiEncryptionKey['keys']); } diff --git a/settings/changepassword/controller.php b/settings/changepassword/controller.php index 1be30b725df..f041cb5b29f 100644 --- a/settings/changepassword/controller.php +++ b/settings/changepassword/controller.php @@ -77,16 +77,43 @@ class Controller { exit(); } - if (\OC_App::isEnabled('files_encryption')) { + if (\OC_App::isEnabled('encryption')) { //handle the recovery case - $util = new \OCA\Files_Encryption\Util(new \OC\Files\View('/'), $username); - $recoveryAdminEnabled = \OC_Appconfig::getValue('files_encryption', 'recoveryAdminEnabled'); + $crypt = new \OCA\Encryption\Crypto\Crypt( + \OC::$server->getLogger(), + \OC::$server->getUserSession(), + \OC::$server->getConfig()); + $keyStorage = \OC::$server->getEncryptionKeyStorage(\OCA\Encryption\Crypto\Encryption::ID); + $util = new \OCA\Encryption\Util( + new \OC\Files\View(), + $crypt, + \OC::$server->getLogger(), + \OC::$server->getUserSession(), + \OC::$server->getConfig()); + $keyManager = new \OCA\Encryption\KeyManager( + $keyStorage, + $crypt, + \OC::$server->getConfig(), + \OC::$server->getUserSession(), + new \OCA\Encryption\Session(\OC::$server->getSession()), + \OC::$server->getLogger(), + $util); + $recovery = new \OCA\Encryption\Recovery( + \OC::$server->getUserSession(), + $crypt, + \OC::$server->getSecureRandom(), + $keyManager, + \OC::$server->getConfig(), + $keyStorage, + \OC::$server->getEncryptionFilesHelper(), + new \OC\Files\View()); + $recoveryAdminEnabled = $recovery->isRecoveryKeyEnabled(); $validRecoveryPassword = false; $recoveryEnabledForUser = false; if ($recoveryAdminEnabled) { - $validRecoveryPassword = $util->checkRecoveryPassword($recoveryPassword); - $recoveryEnabledForUser = $util->recoveryEnabledForUser(); + $validRecoveryPassword = $keyManager->checkRecoveryPassword($recoveryPassword); + $recoveryEnabledForUser = $recovery->isRecoveryEnabledForUser(); } if ($recoveryEnabledForUser && $recoveryPassword === '') { diff --git a/settings/users.php b/settings/users.php index 08498edec29..0fc9fbeafc2 100644 --- a/settings/users.php +++ b/settings/users.php @@ -45,8 +45,8 @@ $groupsInfo = new \OC\Group\MetaData(OC_User::getUser(), $isAdmin, $groupManager $groupsInfo->setSorting($groupsInfo::SORT_USERCOUNT); list($adminGroup, $groups) = $groupsInfo->get(); -$recoveryAdminEnabled = OC_App::isEnabled('files_encryption') && - $config->getAppValue( 'files_encryption', 'recoveryAdminEnabled', null ); +$recoveryAdminEnabled = OC_App::isEnabled('encryption') && + $config->getAppValue( 'encryption', 'recoveryAdminEnabled', null ); if($isAdmin) { $subadmins = OC_SubAdmin::getAllSubAdmins(); -- 2.39.5