Skip to content

Commit

Permalink
Merge pull request #21529 from nextcloud/enh/encryption/improve_key_f…
Browse files Browse the repository at this point in the history
…ormat

New SSE key format
  • Loading branch information
MorrisJobke authored Aug 20, 2020
2 parents 0b39e7d + 5340ab3 commit 65b5e65
Show file tree
Hide file tree
Showing 10 changed files with 584 additions and 30 deletions.
261 changes: 261 additions & 0 deletions core/Command/Encryption/MigrateKeyStorage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/


namespace OC\Core\Command\Encryption;

use OC\Encryption\Keys\Storage;
use OC\Encryption\Util;
use OC\Files\View;
use OCP\IConfig;
use OCP\IUserManager;
use OCP\Security\ICrypto;
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\Output\OutputInterface;

class MigrateKeyStorage extends Command {

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

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

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

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

/** @var QuestionHelper */
protected $questionHelper;
/**
* @var ICrypto
*/
private $crypto;

public function __construct(View $view, IUserManager $userManager, IConfig $config, Util $util, ICrypto $crypto) {
parent::__construct();
$this->rootView = $view;
$this->userManager = $userManager;
$this->config = $config;
$this->util = $util;
$this->crypto = $crypto;
}

protected function configure() {
parent::configure();
$this
->setName('encryption:migrate-key-storage-format')
->setDescription('Migrate the format of the keystorage to a newer format');
}

protected function execute(InputInterface $input, OutputInterface $output): int {
$root = $this->util->getKeyStorageRoot();

$output->writeln("Updating key storage format");
$this->updateKeys($root, $output);
$output->writeln("Key storage format successfully updated");

return 0;
}

/**
* move keys to new key storage root
*
* @param string $root
* @param OutputInterface $output
* @return bool
* @throws \Exception
*/
protected function updateKeys(string $root, OutputInterface $output) {
$output->writeln("Start to update the keys:");

$this->updateSystemKeys($root);
$this->updateUsersKeys($root, $output);
$this->config->deleteSystemValue('encryption.key_storage_migrated');
return true;
}

/**
* move system key folder
*
* @param string $root
*/
protected function updateSystemKeys($root) {
if (!$this->rootView->is_dir($root . '/files_encryption')) {
return;
}

$this->traverseKeys($root . '/files_encryption', null);
}

private function traverseKeys(string $folder, ?string $uid) {
$listing = $this->rootView->getDirectoryContent($folder);

foreach ($listing as $node) {
if ($node['mimetype'] === 'httpd/unix-directory') {
//ignore
} else {
$endsWith = function ($haystack, $needle) {
$length = strlen($needle);
if ($length === 0) {
return true;
}

return (substr($haystack, -$length) === $needle);
};

if ($node['name'] === 'fileKey' ||
$endsWith($node['name'], '.privateKey') ||
$endsWith($node['name'], '.publicKey') ||
$endsWith($node['name'], '.shareKey')) {
$path = $folder . '/' . $node['name'];

$content = $this->rootView->file_get_contents($path);

try {
$this->crypto->decrypt($content);
continue;
} catch (\Exception $e) {
// Ignore we now update the data.
}

$data = [
'key' => base64_encode($content),
'uid' => $uid,
];

$enc = $this->crypto->encrypt(json_encode($data));
$this->rootView->file_put_contents($path, $enc);
}
}
}
}

private function traverseFileKeys(string $folder) {
$listing = $this->rootView->getDirectoryContent($folder);

foreach ($listing as $node) {
if ($node['mimetype'] === 'httpd/unix-directory') {
$this->traverseFileKeys($folder . '/' . $node['name']);
} else {
$endsWith = function ($haystack, $needle) {
$length = strlen($needle);
if ($length === 0) {
return true;
}

return (substr($haystack, -$length) === $needle);
};

if ($node['name'] === 'fileKey' ||
$endsWith($node['name'], '.privateKey') ||
$endsWith($node['name'], '.publicKey') ||
$endsWith($node['name'], '.shareKey')) {
$path = $folder . '/' . $node['name'];

$content = $this->rootView->file_get_contents($path);

try {
$this->crypto->decrypt($content);
continue;
} catch (\Exception $e) {
// Ignore we now update the data.
}

$data = [
'key' => base64_encode($content)
];

$enc = $this->crypto->encrypt(json_encode($data));
$this->rootView->file_put_contents($path, $enc);
}
}
}
}


/**
* setup file system for the given user
*
* @param string $uid
*/
protected function setupUserFS($uid) {
\OC_Util::tearDownFS();
\OC_Util::setupFS($uid);
}


/**
* iterate over each user and move the keys to the new storage
*
* @param string $root
* @param OutputInterface $output
*/
protected function updateUsersKeys(string $root, OutputInterface $output) {
$progress = new ProgressBar($output);
$progress->start();

foreach ($this->userManager->getBackends() as $backend) {
$limit = 500;
$offset = 0;
do {
$users = $backend->getUsers('', $limit, $offset);
foreach ($users as $user) {
$progress->advance();
$this->setupUserFS($user);
$this->updateUserKeys($root, $user);
}
$offset += $limit;
} while (count($users) >= $limit);
}
$progress->finish();
}

/**
* move user encryption folder to new root folder
*
* @param string $root
* @param string $user
* @throws \Exception
*/
protected function updateUserKeys(string $root, string $user) {
if ($this->userManager->userExists($user)) {
$source = $root . '/' . $user . '/files_encryption/OC_DEFAULT_MODULE';
if ($this->rootView->is_dir($source)) {
$this->traverseKeys($source, $user);
}

$source = $root . '/' . $user . '/files_encryption/keys';
if ($this->rootView->is_dir($source)) {
$this->traverseFileKeys($source);
}
}
}
}
8 changes: 8 additions & 0 deletions core/register_command.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,14 @@
)
);
$application->add(new OC\Core\Command\Encryption\ShowKeyStorageRoot($util));
$application->add(new OC\Core\Command\Encryption\MigrateKeyStorage(
$view,
\OC::$server->getUserManager(),
\OC::$server->getConfig(),
$util,
\OC::$server->getCrypto()
)
);

$application->add(new OC\Core\Command\Maintenance\DataFingerprint(\OC::$server->getConfig(), new \OC\AppFramework\Utility\TimeFactory()));
$application->add(new OC\Core\Command\Maintenance\Mimetype\UpdateDB(\OC::$server->getMimeTypeDetector(), \OC::$server->getMimeTypeLoader()));
Expand Down
2 changes: 2 additions & 0 deletions lib/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,7 @@
'OC\\Core\\Command\\Encryption\\Enable' => $baseDir . '/core/Command/Encryption/Enable.php',
'OC\\Core\\Command\\Encryption\\EncryptAll' => $baseDir . '/core/Command/Encryption/EncryptAll.php',
'OC\\Core\\Command\\Encryption\\ListModules' => $baseDir . '/core/Command/Encryption/ListModules.php',
'OC\\Core\\Command\\Encryption\\MigrateKeyStorage' => $baseDir . '/core/Command/Encryption/MigrateKeyStorage.php',
'OC\\Core\\Command\\Encryption\\SetDefaultModule' => $baseDir . '/core/Command/Encryption/SetDefaultModule.php',
'OC\\Core\\Command\\Encryption\\ShowKeyStorageRoot' => $baseDir . '/core/Command/Encryption/ShowKeyStorageRoot.php',
'OC\\Core\\Command\\Encryption\\Status' => $baseDir . '/core/Command/Encryption/Status.php',
Expand Down Expand Up @@ -1248,6 +1249,7 @@
'OC\\Repair\\NC16\\ClearCollectionsAccessCache' => $baseDir . '/lib/private/Repair/NC16/ClearCollectionsAccessCache.php',
'OC\\Repair\\NC18\\ResetGeneratedAvatarFlag' => $baseDir . '/lib/private/Repair/NC18/ResetGeneratedAvatarFlag.php',
'OC\\Repair\\NC20\\EncryptionLegacyCipher' => $baseDir . '/lib/private/Repair/NC20/EncryptionLegacyCipher.php',
'OC\\Repair\\NC20\\EncryptionMigration' => $baseDir . '/lib/private/Repair/NC20/EncryptionMigration.php',
'OC\\Repair\\OldGroupMembershipShares' => $baseDir . '/lib/private/Repair/OldGroupMembershipShares.php',
'OC\\Repair\\Owncloud\\DropAccountTermsTable' => $baseDir . '/lib/private/Repair/Owncloud/DropAccountTermsTable.php',
'OC\\Repair\\Owncloud\\SaveAccountsTableData' => $baseDir . '/lib/private/Repair/Owncloud/SaveAccountsTableData.php',
Expand Down
2 changes: 2 additions & 0 deletions lib/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Core\\Command\\Encryption\\Enable' => __DIR__ . '/../../..' . '/core/Command/Encryption/Enable.php',
'OC\\Core\\Command\\Encryption\\EncryptAll' => __DIR__ . '/../../..' . '/core/Command/Encryption/EncryptAll.php',
'OC\\Core\\Command\\Encryption\\ListModules' => __DIR__ . '/../../..' . '/core/Command/Encryption/ListModules.php',
'OC\\Core\\Command\\Encryption\\MigrateKeyStorage' => __DIR__ . '/../../..' . '/core/Command/Encryption/MigrateKeyStorage.php',
'OC\\Core\\Command\\Encryption\\SetDefaultModule' => __DIR__ . '/../../..' . '/core/Command/Encryption/SetDefaultModule.php',
'OC\\Core\\Command\\Encryption\\ShowKeyStorageRoot' => __DIR__ . '/../../..' . '/core/Command/Encryption/ShowKeyStorageRoot.php',
'OC\\Core\\Command\\Encryption\\Status' => __DIR__ . '/../../..' . '/core/Command/Encryption/Status.php',
Expand Down Expand Up @@ -1277,6 +1278,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Repair\\NC16\\ClearCollectionsAccessCache' => __DIR__ . '/../../..' . '/lib/private/Repair/NC16/ClearCollectionsAccessCache.php',
'OC\\Repair\\NC18\\ResetGeneratedAvatarFlag' => __DIR__ . '/../../..' . '/lib/private/Repair/NC18/ResetGeneratedAvatarFlag.php',
'OC\\Repair\\NC20\\EncryptionLegacyCipher' => __DIR__ . '/../../..' . '/lib/private/Repair/NC20/EncryptionLegacyCipher.php',
'OC\\Repair\\NC20\\EncryptionMigration' => __DIR__ . '/../../..' . '/lib/private/Repair/NC20/EncryptionMigration.php',
'OC\\Repair\\OldGroupMembershipShares' => __DIR__ . '/../../..' . '/lib/private/Repair/OldGroupMembershipShares.php',
'OC\\Repair\\Owncloud\\DropAccountTermsTable' => __DIR__ . '/../../..' . '/lib/private/Repair/Owncloud/DropAccountTermsTable.php',
'OC\\Repair\\Owncloud\\SaveAccountsTableData' => __DIR__ . '/../../..' . '/lib/private/Repair/Owncloud/SaveAccountsTableData.php',
Expand Down
Loading

0 comments on commit 65b5e65

Please sign in to comment.