aboutsummaryrefslogtreecommitdiffstats
path: root/apps/encryption/lib/Crypto
diff options
context:
space:
mode:
Diffstat (limited to 'apps/encryption/lib/Crypto')
-rw-r--r--apps/encryption/lib/Crypto/Crypt.php47
-rw-r--r--apps/encryption/lib/Crypto/DecryptAll.php58
-rw-r--r--apps/encryption/lib/Crypto/EncryptAll.php151
-rw-r--r--apps/encryption/lib/Crypto/Encryption.php67
4 files changed, 91 insertions, 232 deletions
diff --git a/apps/encryption/lib/Crypto/Crypt.php b/apps/encryption/lib/Crypto/Crypt.php
index 2d212c1f055..463ca4e22bb 100644
--- a/apps/encryption/lib/Crypto/Crypt.php
+++ b/apps/encryption/lib/Crypto/Crypt.php
@@ -1,34 +1,9 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Bjoern Schiessle <bjoern@schiessle.org>
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Clark Tomlinson <fallen013@gmail.com>
- * @author Côme Chilliet <come.chilliet@nextcloud.com>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Kevin Niehage <kevin@niehage.name>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Stefan Weiberg <sweiberg@suse.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @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/>
- *
+ * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCA\Encryption\Crypto;
@@ -108,7 +83,7 @@ class Crypt {
/**
* create new private/public key-pair for user
*
- * @return array|bool
+ * @return array{publicKey: string, privateKey: string}|false
*/
public function createKeyPair() {
$res = $this->getOpenSSLPKey();
@@ -180,7 +155,7 @@ class Crypt {
$this->getCipher());
// Create a signature based on the key as well as the current version
- $sig = $this->createSignature($encryptedContent, $passPhrase.'_'.$version.'_'.$position);
+ $sig = $this->createSignature($encryptedContent, $passPhrase . '_' . $version . '_' . $position);
// combine content to encrypt the IV identifier and actual IV
$catFile = $this->concatIV($encryptedContent, $iv);
@@ -482,7 +457,7 @@ class Crypt {
if ($enforceSignature) {
throw new GenericEncryptionException('Bad Signature', $this->l->t('Bad Signature'));
} else {
- $this->logger->info("Signature check skipped", ['app' => 'encryption']);
+ $this->logger->info('Signature check skipped', ['app' => 'encryption']);
}
}
}
@@ -776,7 +751,7 @@ class Crypt {
$result = false;
// check if RC4 is used
- if (strcasecmp($cipher_algo, "rc4") === 0) {
+ if (strcasecmp($cipher_algo, 'rc4') === 0) {
// decrypt the intermediate key with RSA
if (openssl_private_decrypt($encrypted_key, $intermediate, $private_key, OPENSSL_PKCS1_PADDING)) {
// decrypt the file key with the intermediate key
@@ -785,7 +760,7 @@ class Crypt {
$result = (strlen($output) === strlen($data));
}
} else {
- throw new DecryptionFailedException('Unsupported cipher '.$cipher_algo);
+ throw new DecryptionFailedException('Unsupported cipher ' . $cipher_algo);
}
return $result;
@@ -801,7 +776,7 @@ class Crypt {
$result = false;
// check if RC4 is used
- if (strcasecmp($cipher_algo, "rc4") === 0) {
+ if (strcasecmp($cipher_algo, 'rc4') === 0) {
// make sure that there is at least one public key to use
if (count($public_key) >= 1) {
// generate the intermediate key
@@ -832,7 +807,7 @@ class Crypt {
}
}
} else {
- throw new EncryptionFailedException('Unsupported cipher '.$cipher_algo);
+ throw new EncryptionFailedException('Unsupported cipher ' . $cipher_algo);
}
return $result;
diff --git a/apps/encryption/lib/Crypto/DecryptAll.php b/apps/encryption/lib/Crypto/DecryptAll.php
index e982da72086..362f43b8672 100644
--- a/apps/encryption/lib/Crypto/DecryptAll.php
+++ b/apps/encryption/lib/Crypto/DecryptAll.php
@@ -1,27 +1,13 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- *
- * @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/>
- *
+ * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCA\Encryption\Crypto;
+use OCA\Encryption\Exceptions\PrivateKeyMissingException;
use OCA\Encryption\KeyManager;
use OCA\Encryption\Session;
use OCA\Encryption\Util;
@@ -33,21 +19,6 @@ use Symfony\Component\Console\Question\Question;
class DecryptAll {
- /** @var Util */
- protected $util;
-
- /** @var QuestionHelper */
- protected $questionHelper;
-
- /** @var Crypt */
- protected $crypt;
-
- /** @var KeyManager */
- protected $keyManager;
-
- /** @var Session */
- protected $session;
-
/**
* @param Util $util
* @param KeyManager $keyManager
@@ -56,17 +27,12 @@ class DecryptAll {
* @param QuestionHelper $questionHelper
*/
public function __construct(
- Util $util,
- KeyManager $keyManager,
- Crypt $crypt,
- Session $session,
- QuestionHelper $questionHelper
+ protected Util $util,
+ protected KeyManager $keyManager,
+ protected Crypt $crypt,
+ protected Session $session,
+ protected QuestionHelper $questionHelper,
) {
- $this->util = $util;
- $this->keyManager = $keyManager;
- $this->crypt = $crypt;
- $this->session = $session;
- $this->questionHelper = $questionHelper;
}
/**
@@ -88,7 +54,7 @@ class DecryptAll {
$recoveryKeyId = $this->keyManager->getRecoveryKeyId();
if (!empty($user)) {
$output->writeln('You can only decrypt the users files if you know');
- $output->writeln('the users password or if he activated the recovery key.');
+ $output->writeln('the users password or if they activated the recovery key.');
$output->writeln('');
$questionUseLoginPassword = new ConfirmationQuestion(
'Do you want to use the users login password to decrypt all files? (y/n) ',
@@ -133,7 +99,7 @@ class DecryptAll {
* @param string $user
* @param string $password
* @return bool|string
- * @throws \OCA\Encryption\Exceptions\PrivateKeyMissingException
+ * @throws PrivateKeyMissingException
*/
protected function getPrivateKey($user, $password) {
$recoveryKeyId = $this->keyManager->getRecoveryKeyId();
diff --git a/apps/encryption/lib/Crypto/EncryptAll.php b/apps/encryption/lib/Crypto/EncryptAll.php
index 5420e729898..4ed75b85a93 100644
--- a/apps/encryption/lib/Crypto/EncryptAll.php
+++ b/apps/encryption/lib/Crypto/EncryptAll.php
@@ -1,29 +1,9 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Bjoern Schiessle <bjoern@schiessle.org>
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Kenneth Newwood <kenneth@newwood.name>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @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/>
- *
+ * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCA\Encryption\Crypto;
@@ -32,6 +12,7 @@ use OC\Files\View;
use OCA\Encryption\KeyManager;
use OCA\Encryption\Users\Setup;
use OCA\Encryption\Util;
+use OCP\Files\FileInfo;
use OCP\IConfig;
use OCP\IL10N;
use OCP\IUser;
@@ -40,6 +21,7 @@ use OCP\L10N\IFactory;
use OCP\Mail\Headers\AutoSubmitted;
use OCP\Mail\IMailer;
use OCP\Security\ISecureRandom;
+use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Helper\Table;
@@ -49,72 +31,29 @@ use Symfony\Component\Console\Question\ConfirmationQuestion;
class EncryptAll {
- /** @var Setup */
- protected $userSetup;
-
- /** @var IUserManager */
- protected $userManager;
-
- /** @var View */
- protected $rootView;
-
- /** @var KeyManager */
- protected $keyManager;
-
- /** @var Util */
- protected $util;
-
- /** @var array */
+ /** @var array */
protected $userPasswords;
- /** @var IConfig */
- protected $config;
-
- /** @var IMailer */
- protected $mailer;
-
- /** @var IL10N */
- protected $l;
-
- /** @var IFactory */
- protected $l10nFactory;
-
- /** @var QuestionHelper */
- protected $questionHelper;
-
- /** @var OutputInterface */
+ /** @var OutputInterface */
protected $output;
- /** @var InputInterface */
+ /** @var InputInterface */
protected $input;
- /** @var ISecureRandom */
- protected $secureRandom;
-
public function __construct(
- Setup $userSetup,
- IUserManager $userManager,
- View $rootView,
- KeyManager $keyManager,
- Util $util,
- IConfig $config,
- IMailer $mailer,
- IL10N $l,
- IFactory $l10nFactory,
- QuestionHelper $questionHelper,
- ISecureRandom $secureRandom
+ protected Setup $userSetup,
+ protected IUserManager $userManager,
+ protected View $rootView,
+ protected KeyManager $keyManager,
+ protected Util $util,
+ protected IConfig $config,
+ protected IMailer $mailer,
+ protected IL10N $l,
+ protected IFactory $l10nFactory,
+ protected QuestionHelper $questionHelper,
+ protected ISecureRandom $secureRandom,
+ protected LoggerInterface $logger,
) {
- $this->userSetup = $userSetup;
- $this->userManager = $userManager;
- $this->rootView = $rootView;
- $this->keyManager = $keyManager;
- $this->util = $util;
- $this->config = $config;
- $this->mailer = $mailer;
- $this->l = $l;
- $this->l10nFactory = $l10nFactory;
- $this->questionHelper = $questionHelper;
- $this->secureRandom = $secureRandom;
// store one time passwords for the users
$this->userPasswords = [];
}
@@ -223,7 +162,7 @@ class EncryptAll {
$userNo++;
}
}
- $progress->setMessage("all files encrypted");
+ $progress->setMessage('all files encrypted');
$progress->finish();
}
@@ -264,33 +203,42 @@ class EncryptAll {
while ($root = array_pop($directories)) {
$content = $this->rootView->getDirectoryContent($root);
foreach ($content as $file) {
- $path = $root . '/' . $file['name'];
- if ($this->rootView->is_dir($path)) {
+ $path = $root . '/' . $file->getName();
+ if ($file->isShared()) {
+ $progress->setMessage("Skip shared file/folder $path");
+ $progress->advance();
+ continue;
+ } elseif ($file->getType() === FileInfo::TYPE_FOLDER) {
$directories[] = $path;
continue;
} else {
$progress->setMessage("encrypt files for user $userCount: $path");
$progress->advance();
- if ($this->encryptFile($path) === false) {
- $progress->setMessage("encrypt files for user $userCount: $path (already encrypted)");
+ try {
+ if ($this->encryptFile($file, $path) === false) {
+ $progress->setMessage("encrypt files for user $userCount: $path (already encrypted)");
+ $progress->advance();
+ }
+ } catch (\Exception $e) {
+ $progress->setMessage("Failed to encrypt path $path: " . $e->getMessage());
$progress->advance();
+ $this->logger->error(
+ 'Failed to encrypt path {path}',
+ [
+ 'user' => $uid,
+ 'path' => $path,
+ 'exception' => $e,
+ ]
+ );
}
}
}
}
}
- /**
- * encrypt file
- *
- * @param string $path
- * @return bool
- */
- protected function encryptFile($path) {
-
+ protected function encryptFile(FileInfo $fileInfo, string $path): bool {
// skip already encrypted files
- $fileInfo = $this->rootView->getFileInfo($path);
- if ($fileInfo !== false && $fileInfo->isEncrypted()) {
+ if ($fileInfo->isEncrypted()) {
return true;
}
@@ -298,7 +246,14 @@ class EncryptAll {
$target = $path . '.encrypted.' . time();
try {
- $this->rootView->copy($source, $target);
+ $copySuccess = $this->rootView->copy($source, $target);
+ if ($copySuccess === false) {
+ /* Copy failed, abort */
+ if ($this->rootView->file_exists($target)) {
+ $this->rootView->unlink($target);
+ }
+ throw new \Exception('Copy failed for ' . $source);
+ }
$this->rootView->rename($target, $source);
} catch (DecryptionFailedException $e) {
if ($this->rootView->file_exists($target)) {
diff --git a/apps/encryption/lib/Crypto/Encryption.php b/apps/encryption/lib/Crypto/Encryption.php
index 1481d3a9a23..6d388624e48 100644
--- a/apps/encryption/lib/Crypto/Encryption.php
+++ b/apps/encryption/lib/Crypto/Encryption.php
@@ -1,41 +1,16 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Bjoern Schiessle <bjoern@schiessle.org>
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Clark Tomlinson <fallen013@gmail.com>
- * @author Jan-Christoph Borchardt <hey@jancborchardt.net>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Julius Härtl <jus@bitgrid.net>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Valdnet <47037905+Valdnet@users.noreply.github.com>
- *
- * @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/>
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCA\Encryption\Crypto;
use OC\Encryption\Exceptions\DecryptionFailedException;
use OC\Files\Cache\Scanner;
use OC\Files\View;
+use OCA\Encryption\Exceptions\MultiKeyEncryptException;
use OCA\Encryption\Exceptions\PublicKeyMissingException;
use OCA\Encryption\KeyManager;
use OCA\Encryption\Session;
@@ -80,8 +55,6 @@ class Encryption implements IEncryptionModule {
/** @var int Current version of the file */
private int $version = 0;
- private bool $useLegacyFileKey = true;
-
/** @var array remember encryption signature version */
private static $rememberVersion = [];
@@ -127,8 +100,8 @@ class Encryption implements IEncryptionModule {
* @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
+ * written to the header, in case of a write operation
+ * or if no additional data is needed return a empty array
*/
public function begin($path, $user, $mode, array $header, array $accessList) {
$this->path = $this->getPathToRealFile($path);
@@ -138,7 +111,6 @@ class Encryption implements IEncryptionModule {
$this->writeCache = '';
$this->useLegacyBase64Encoding = true;
- $this->useLegacyFileKey = ($header['useLegacyFileKey'] ?? 'true') !== 'false';
if (isset($header['encoding'])) {
$this->useLegacyBase64Encoding = $header['encoding'] !== Crypt::BINARY_ENCODING_FORMAT;
@@ -152,19 +124,10 @@ class Encryption implements IEncryptionModule {
}
}
- if ($this->session->decryptAllModeActivated()) {
- $shareKey = $this->keyManager->getShareKey($this->path, $this->session->getDecryptAllUid());
- if ($this->useLegacyFileKey) {
- $encryptedFileKey = $this->keyManager->getEncryptedFileKey($this->path);
- $this->fileKey = $this->crypt->multiKeyDecryptLegacy($encryptedFileKey,
- $shareKey,
- $this->session->getDecryptAllKey());
- } else {
- $this->fileKey = $this->crypt->multiKeyDecrypt($shareKey, $this->session->getDecryptAllKey());
- }
- } else {
- $this->fileKey = $this->keyManager->getFileKey($this->path, $this->user, $this->useLegacyFileKey);
- }
+ /* If useLegacyFileKey is not specified in header, auto-detect, to be safe */
+ $useLegacyFileKey = (($header['useLegacyFileKey'] ?? '') == 'false' ? false : null);
+
+ $this->fileKey = $this->keyManager->getFileKey($this->path, $this->user, $useLegacyFileKey, $this->session->decryptAllModeActivated());
// always use the version from the original file, also part files
// need to have a correct version number if they get moved over to the
@@ -225,7 +188,7 @@ class Encryption implements IEncryptionModule {
* of a write operation
* @throws PublicKeyMissingException
* @throws \Exception
- * @throws \OCA\Encryption\Exceptions\MultiKeyEncryptException
+ * @throws MultiKeyEncryptException
*/
public function end($path, $position = '0') {
$result = '';
@@ -470,7 +433,7 @@ class Encryption implements IEncryptionModule {
* e.g. if all encryption keys exists
*
* @param string $path
- * @param string $uid user for whom we want to check if he can read the file
+ * @param string $uid user for whom we want to check if they can read the file
* @return bool
* @throws DecryptionFailedException
*/
@@ -483,8 +446,8 @@ class Encryption implements IEncryptionModule {
// error message because in this case it means that the file was
// shared with the user at a point where the user didn't had a
// valid private/public key
- $msg = 'Encryption module "' . $this->getDisplayName() .
- '" is not able to read ' . $path;
+ $msg = 'Encryption module "' . $this->getDisplayName()
+ . '" is not able to read ' . $path;
$hint = $this->l->t('Cannot read this file, probably this is a shared file. Please ask the file owner to reshare the file with you.');
$this->logger->warning($msg);
throw new DecryptionFailedException($msg, $hint);