Skip to content

Commit

Permalink
Change to re-create masterkeys
Browse files Browse the repository at this point in the history
This change brings a new command to re-create
masterkey

A small modification to the decryptall, to
standard output to console.

Signed-off-by: Sujith H <sharidasan@owncloud.com>
  • Loading branch information
sharidas committed Sep 21, 2017
1 parent 4fdfce0 commit 765ab35
Show file tree
Hide file tree
Showing 7 changed files with 663 additions and 18 deletions.
1 change: 1 addition & 0 deletions appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
</dependencies>
<commands>
<command>OCA\Encryption\Command\SelectEncryptionType</command>
<command>OCA\Encryption\Command\RecreateMasterKey</command>
<command>OCA\Encryption\Command\MigrateKeys</command>
</commands>
<settings>
Expand Down
255 changes: 255 additions & 0 deletions lib/Command/RecreateMasterKey.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
<?php
/**
* @author Sujith Haridasan <sharidasan@owncloud.com>
*
* @copyright Copyright (c) 2017, ownCloud GmbH
* @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\Command;

use OC\Encryption\DecryptAll;
use OC\Encryption\Exceptions\DecryptionFailedException;
use OC\Encryption\Manager;
use OC\Files\Filesystem;
use OC\Files\View;
use OC\Memcache\ArrayCache;
use OCA\Encryption\Crypto\EncryptAll;
use OCA\Encryption\KeyManager;
use OCA\Encryption\Users\Setup;
use OCA\Encryption\Util;
use OCP\App\IAppManager;
use OCP\IAppConfig;
use OCP\IConfig;
use OCP\IL10N;
use OCP\ILogger;
use OCP\ISession;
use OCP\IUserManager;
use OCP\Mail\IMailer;
use OCP\Security\ISecureRandom;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;

class RecreateMasterKey extends Command {

/** @var Manager */
protected $encryptionManager;

/** @var IUserManager */
protected $userManager;

/** @var View */
protected $rootView;

/** @var KeyManager */
protected $keyManager;

/** @var Util */
protected $util;

/** @var \OC\Encryption\Util */
protected $encUtil;

/** @var IAppManager */
protected $IAppManager;

/** @var IAppConfig */
protected $appConfig;

/** @var IConfig */
protected $config;

/** @var ISession */
protected $session;

/** @var QuestionHelper */
protected $questionHelper;

/** @var Setup */
protected $userSetup;

/** @var IMailer */
protected $mailer;

/** @var ISecureRandom */
protected $secureRandom;

/** @var IL10N */
protected $l;

/** @var ILogger */
protected $logger;

/** @var */
protected $encryptAll;

protected $decryptAll;

/** @var array files which couldn't be decrypted */
protected $failed;

/**
* RecreateMasterKey constructor.
*
* @param IUserManager $userManager
* @param View $rootView
* @param KeyManager $keyManager
* @param Util $util
* @param IAppManager $IAppManager
* @param IAppConfig $appConfig
* @param IConfig $config
* @param ISession $session
* @param QuestionHelper $questionHelper
* @param Setup $userSetup
* @param IMailer $mailer
* @param ISecureRandom $secureRandom
* @param IL10N $l
* @param ILogger $logger
*/
public function __construct(IUserManager $userManager, View $rootView, KeyManager $keyManager, Util $util, \OC\Encryption\Util $encUtil,
IAppManager $IAppManager, IAppConfig $appConfig, IConfig $config, ISession $session,
Manager $encryptionManager, QuestionHelper $questionHelper, Setup $userSetup, IMailer $mailer,
ISecureRandom $secureRandom, IL10N $l, ILogger $logger) {

parent::__construct();
$this->userManager = $userManager;
$this->rootView = $rootView;
$this->keyManager = $keyManager;
$this->util = $util;
$this->encUtil = $encUtil;
$this->IAppManager = $IAppManager;
$this->appConfig = $appConfig;
$this->config = $config;
$this->session = $session;
$this->encryptionManager = $encryptionManager;
$this->questionHelper = $questionHelper;
$this->userSetup = $userSetup;
$this->mailer = $mailer;
$this->secureRandom = $secureRandom;
$this->l = $l;
$this->logger = $logger;
}

protected function configure() {
parent::configure();

$this
->setName('encryption:recreate-master-key')
->setDescription('Replace existing master key with new one. Encrypt the file system with newly created master key')
;

$this->addOption(
'yes',
'y',
InputOption::VALUE_NONE,
'Answer yes to all questions'
);
}

protected function execute(InputInterface $input, OutputInterface $output) {
$yes = $input->getOption('yes');
if ($this->util->isMasterKeyEnabled()) {
$question = new ConfirmationQuestion(
'Warning: Inorder to re-create master key, the entire ownCloud filesystem will be decrypted and then encrypted using new master key.'
. ' Do you want to continue? (y/n)', false);
if ($yes || $this->questionHelper->ask($input, $output, $question)) {

$output->writeln("Decryption started\n");
$progress = new ProgressBar($output);
$progress->start();
$progress->setMessage("Decryption progress...");
$progress->advance();

$this->decryptAllUsers($input, $output);
$progress->finish();

if (empty($this->failed)) {

$this->IAppManager->disableApp('encryption');

//Delete the files_encryption dir
$filesEncryptionDir = $this->encUtil->getKeyStorageRoot();
if ($filesEncryptionDir === '') {
$this->rootView->deleteAll('files_encryption');
} else {
$this->rootView->deleteAll($filesEncryptionDir . '/files_encryption');
}

$this->appConfig->setValue('core', 'encryption_enabled', 'no');
$this->appConfig->deleteKey('encryption', 'useMasterKey');
$this->appConfig->deleteKey('encryption', 'masterKeyId');
$this->appConfig->deleteKey('encryption', 'recoveryKeyId');
$this->appConfig->deleteKey('encryption', 'publicShareKeyId');
$this->appConfig->deleteKey('files_encryption', 'installed_version');

}
$output->writeln("\nDecryption completed\n");

//Reencrypt again
$this->IAppManager->enableApp('encryption');
$this->appConfig->setValue('core', 'encryption_enabled', 'yes');
$this->appConfig->setValue('encryption', 'enabled', 'yes');
$output->writeln("Encryption started\n");

$output->writeln("Waiting for creating new masterkey\n");

$this->keyManager->setPublicShareKeyIDAndMasterKeyId();

$output->writeln("New masterkey created successfully\n");

$this->appConfig->setValue('encryption', 'enabled', 'yes');
$this->appConfig->setValue('encryption', 'useMasterKey', '1');

$this->keyManager->validateShareKey();
$this->keyManager->validateMasterKey();
$this->encryptAllUsers($input, $output);
$output->writeln("\nEncryption completed successfully\n");
} else {
$output->writeln("The process is abandoned");
}
} else {
$output->writeln("Master key is not enabled.\n");
}
}

protected function decryptAllUsers(InputInterface $input, OutputInterface $output) {
$this->decryptAll = new DecryptAll($this->encryptionManager, $this->userManager, $this->rootView);
$this->decryptAll->decryptAll($input,$output);
}

protected function encryptAllUsers(InputInterface $input, OutputInterface $output) {
/*
* We are reusing the encryptAll code but not the decryptAll. The reason being
* decryptAll finishes by encrypting. Which is not what we want. This will make
* things out of scope for this command. We want first the entire oC FS to be
* decrypt. Then re-encrypt the entire oC FS with the new master key generated.
*
*/
$this->encryptAll = new EncryptAll(
$this->userSetup, $this->userManager, $this->rootView,
$this->keyManager, $this->util, $this->config,
$this->mailer, $this->l, $this->questionHelper,
$this->secureRandom);
$this->encryptAll->encryptAll($input, $output);
}
}

2 changes: 1 addition & 1 deletion lib/Crypto/DecryptAll.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public function prepare(InputInterface $input, OutputInterface $output, $user) {
$output->writeln('the users password or if he activated the recovery key.');
$output->writeln('');
$questionUseLoginPassword = new ConfirmationQuestion(
'Do you want to use the users login password to decrypt all files? (y/n) ',
'Do you want to use the user: ' . $user . ' login password to decrypt all files? (y/n) ',
false
);
$useLoginPassword = $this->questionHelper->ask($input, $output, $questionUseLoginPassword);
Expand Down
1 change: 1 addition & 0 deletions lib/Crypto/EncryptAll.php
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ protected function encryptFile($path) {
$target = $path . '.encrypted.' . time();

try {
$this->keyManager->setVersion($source, 0, $this->rootView);
$this->rootView->copy($source, $target);
$this->rootView->rename($target, $source);
} catch (DecryptionFailedException $e) {
Expand Down
36 changes: 23 additions & 13 deletions lib/KeyManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,19 +132,7 @@ public function __construct(
$this->recoveryKeyId);
}

$this->publicShareKeyId = $this->config->getAppValue('encryption',
'publicShareKeyId');
if (empty($this->publicShareKeyId)) {
$this->publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8);
$this->config->setAppValue('encryption', 'publicShareKeyId', $this->publicShareKeyId);
}

$this->masterKeyId = $this->config->getAppValue('encryption',
'masterKeyId');
if (empty($this->masterKeyId)) {
$this->masterKeyId = 'master_' . substr(md5(time()), 0, 8);
$this->config->setAppValue('encryption', 'masterKeyId', $this->masterKeyId);
}
$this->setPublicShareKeyIDAndMasterKeyId();

$this->keyId = $userSession && $userSession->isLoggedIn() ? $userSession->getUser()->getUID() : false;
$this->log = $log;
Expand Down Expand Up @@ -701,6 +689,9 @@ public function getMasterKeyPassword() {
* @return string
*/
public function getMasterKeyId() {
if($this->config->getAppValue('encryption', 'masterKeyId') !== $this->masterKeyId) {
$this->masterKeyId = $this->config->getAppValue('encryption', 'masterKeyId');
}
return $this->masterKeyId;
}

Expand All @@ -712,4 +703,23 @@ public function getMasterKeyId() {
public function getPublicMasterKey() {
return $this->keyStorage->getSystemUserKey($this->masterKeyId . '.publicKey', Encryption::ID);
}

/**
* set publicShareKeyId and masterKeyId if not set
*/
public function setPublicShareKeyIDAndMasterKeyId() {
$this->publicShareKeyId = $this->config->getAppValue('encryption',
'publicShareKeyId');
if (empty($this->publicShareKeyId)) {
$this->publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8);
$this->config->setAppValue('encryption', 'publicShareKeyId', $this->publicShareKeyId);
}

$this->masterKeyId = $this->config->getAppValue('encryption',
'masterKeyId');
if (empty($this->masterKeyId)) {
$this->masterKeyId = 'master_' . substr(md5(time()), 0, 8);
$this->config->setAppValue('encryption', 'masterKeyId', $this->masterKeyId);
}
}
}
Loading

0 comments on commit 765ab35

Please sign in to comment.