aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorCôme Chilliet <come.chilliet@nextcloud.com>2023-03-16 14:53:51 +0100
committerCôme Chilliet <come.chilliet@nextcloud.com>2023-03-17 11:08:58 +0100
commit8900d030d1a6359a0b58b7257e3a3fd33db4a6a4 (patch)
tree5e32030a28cc1fb245d38098da7d84cb93a25e5d /apps
parentfbe282caeb7dd0d91435f6f547db027e500e248a (diff)
downloadnextcloud-server-8900d030d1a6359a0b58b7257e3a3fd33db4a6a4.tar.gz
nextcloud-server-8900d030d1a6359a0b58b7257e3a3fd33db4a6a4.zip
Adapt code to new encryption system
fileKey gets deleted upon save as it’s stored in shareKeys instead now. We use presence of a fileKey to detect if a file is using the legacy system or the new one, because we do not always have access to header data. Signed-off-by: Côme Chilliet <come.chilliet@nextcloud.com>
Diffstat (limited to 'apps')
-rw-r--r--apps/encryption/lib/Crypto/Crypt.php15
-rw-r--r--apps/encryption/lib/Crypto/Encryption.php28
-rw-r--r--apps/encryption/lib/KeyManager.php18
-rw-r--r--apps/encryption/lib/Recovery.php51
-rw-r--r--apps/encryption/tests/Crypto/EncryptionTest.php6
5 files changed, 56 insertions, 62 deletions
diff --git a/apps/encryption/lib/Crypto/Crypt.php b/apps/encryption/lib/Crypto/Crypt.php
index f4544a61716..516164c6a80 100644
--- a/apps/encryption/lib/Crypto/Crypt.php
+++ b/apps/encryption/lib/Crypto/Crypt.php
@@ -185,14 +185,9 @@ class Crypt {
}
/**
- * @param string $plainContent
- * @param string $passPhrase
- * @param int $version
- * @param int $position
- * @return false|string
* @throws EncryptionFailedException
*/
- public function symmetricEncryptFileContent($plainContent, $passPhrase, $version, $position) {
+ public function symmetricEncryptFileContent(string $plainContent, string $passPhrase, int $version, string $position): string|false {
if (!$plainContent) {
$this->logger->error('Encryption Library, symmetrical encryption failed no content given',
['app' => 'encryption']);
@@ -409,7 +404,7 @@ class Crypt {
$privateKey,
$hash,
0,
- 0
+ '0'
);
return $encryptedKey;
@@ -537,12 +532,8 @@ class Crypt {
/**
* create signature
- *
- * @param string $data
- * @param string $passPhrase
- * @return string
*/
- private function createSignature($data, $passPhrase) {
+ private function createSignature(string $data, string $passPhrase): string {
$passPhrase = hash('sha512', $passPhrase . 'a', true);
return hash_hmac('sha256', $data, $passPhrase);
}
diff --git a/apps/encryption/lib/Crypto/Encryption.php b/apps/encryption/lib/Crypto/Encryption.php
index bee91e530ff..838c63e9495 100644
--- a/apps/encryption/lib/Crypto/Encryption.php
+++ b/apps/encryption/lib/Crypto/Encryption.php
@@ -266,14 +266,14 @@ class Encryption implements IEncryptionModule {
* buffer.
*
* @param string $path to the file
- * @param int $position
+ * @param string $position
* @return string remained data which should be written to the file in case
* of a write operation
* @throws PublicKeyMissingException
* @throws \Exception
* @throws \OCA\Encryption\Exceptions\MultiKeyEncryptException
*/
- public function end($path, $position = 0) {
+ public function end($path, $position = '0') {
$result = '';
if ($this->isWriteOperation) {
// in case of a part file we remember the new signature versions
@@ -308,11 +308,13 @@ class Encryption implements IEncryptionModule {
}
$publicKeys = $this->keyManager->addSystemKeys($this->accessList, $publicKeys, $this->getOwner($path));
- //TODO adapt this to new return of the method, same for other calls of multiKeyEncrypt
- $encryptedKeyfiles = $this->crypt->multiKeyEncrypt($this->fileKey, $publicKeys);
- $this->keyManager->setAllFileKeys($this->path, $encryptedKeyfiles);
+ $shareKeys = $this->crypt->multiKeyEncrypt($this->fileKey, $publicKeys);
+ $this->keyManager->deleteLegacyFileKey($this->path);
+ foreach ($shareKeys as $uid => $keyFile) {
+ $this->keyManager->setShareKey($this->path, $uid, $keyFile);
+ }
}
- return $result;
+ return $result ?: '';
}
@@ -362,7 +364,7 @@ class Encryption implements IEncryptionModule {
// Read the chunk from the start of $data
$chunk = substr($data, 0, $this->getUnencryptedBlockSize(true));
- $encrypted .= $this->crypt->symmetricEncryptFileContent($chunk, $this->fileKey, $this->version + 1, $position);
+ $encrypted .= $this->crypt->symmetricEncryptFileContent($chunk, $this->fileKey, $this->version + 1, (string)$position);
// Remove the chunk we just processed from
// $data, leaving only unprocessed data in $data
@@ -400,7 +402,7 @@ class Encryption implements IEncryptionModule {
* @param string $path path to the file which should be updated
* @param string $uid of the user who performs the operation
* @param array $accessList who has access to the file contains the key 'users' and 'public'
- * @return boolean
+ * @return bool
*/
public function update($path, $uid, array $accessList) {
if (empty($accessList)) {
@@ -408,10 +410,10 @@ class Encryption implements IEncryptionModule {
$this->keyManager->setVersion($path, self::$rememberVersion[$path], new View());
unset(self::$rememberVersion[$path]);
}
- return;
+ return false;
}
- $fileKey = $this->keyManager->getFileKey($path, $uid);
+ $fileKey = $this->keyManager->getFileKey($path, $uid, null);
if (!empty($fileKey)) {
$publicKeys = [];
@@ -429,11 +431,13 @@ class Encryption implements IEncryptionModule {
$publicKeys = $this->keyManager->addSystemKeys($accessList, $publicKeys, $this->getOwner($path));
- $encryptedFileKey = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys);
+ $shareKeys = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys);
$this->keyManager->deleteAllFileKeys($path);
- $this->keyManager->setAllFileKeys($path, $encryptedFileKey);
+ foreach ($shareKeys as $uid => $keyFile) {
+ $this->keyManager->setShareKey($this->path, $uid, $keyFile);
+ }
} else {
$this->logger->debug('no file key found, we assume that the file "{file}" is not encrypted',
['file' => $path, 'app' => 'encryption']);
diff --git a/apps/encryption/lib/KeyManager.php b/apps/encryption/lib/KeyManager.php
index 5f35f7a8422..5c933b5f8b2 100644
--- a/apps/encryption/lib/KeyManager.php
+++ b/apps/encryption/lib/KeyManager.php
@@ -440,18 +440,19 @@ class KeyManager {
/**
* @param string $path
* @param $uid
+ * @param ?bool $useLegacyFileKey null means try both
* @return string
*/
- public function getFileKey(string $path, ?string $uid, bool $useLegacyFileKey): string {
+ public function getFileKey(string $path, ?string $uid, ?bool $useLegacyFileKey): string {
if ($uid === '') {
$uid = null;
}
$publicAccess = is_null($uid);
-
- if ($useLegacyFileKey) {
+ $encryptedFileKey = '';
+ if ($useLegacyFileKey ?? true) {
$encryptedFileKey = $this->keyStorage->getFileKey($path, $this->fileKeyId, Encryption::ID);
- if (empty($encryptedFileKey)) {
+ if (empty($encryptedFileKey) && $useLegacyFileKey) {
return '';
}
}
@@ -477,13 +478,14 @@ class KeyManager {
$privateKey = $this->session->getPrivateKey();
}
- if ($useLegacyFileKey) {
+ if ($useLegacyFileKey ?? true) {
if ($encryptedFileKey && $shareKey && $privateKey) {
return $this->crypt->multiKeyDecryptLegacy($encryptedFileKey,
$shareKey,
$privateKey);
}
- } else {
+ }
+ if ($useLegacyFileKey ?? false) {
if ($shareKey && $privateKey) {
return $this->crypt->multiKeyDecrypt($shareKey, $privateKey);
}
@@ -664,6 +666,10 @@ class KeyManager {
return $this->keyStorage->deleteAllFileKeys($path);
}
+ public function deleteLegacyFileKey(string $path): bool {
+ return $this->keyStorage->deleteFileKey($path, $this->fileKeyId, Encryption::ID);
+ }
+
/**
* @param array $userIds
* @return array
diff --git a/apps/encryption/lib/Recovery.php b/apps/encryption/lib/Recovery.php
index f4336ec7c4e..25738dabf89 100644
--- a/apps/encryption/lib/Recovery.php
+++ b/apps/encryption/lib/Recovery.php
@@ -35,8 +35,6 @@ use OCP\IUserSession;
use OCP\PreConditionNotMetException;
class Recovery {
-
-
/**
* @var null|IUser
*/
@@ -102,7 +100,7 @@ class Recovery {
}
if ($keyManager->checkRecoveryPassword($password)) {
- $appConfig->setAppValue('encryption', 'recoveryAdminEnabled', 1);
+ $appConfig->setAppValue('encryption', 'recoveryAdminEnabled', '1');
return true;
}
@@ -140,7 +138,7 @@ class Recovery {
if ($keyManager->checkRecoveryPassword($recoveryPassword)) {
// Set recoveryAdmin as disabled
- $this->config->setAppValue('encryption', 'recoveryAdminEnabled', 0);
+ $this->config->setAppValue('encryption', 'recoveryAdminEnabled', '0');
return true;
}
return false;
@@ -169,7 +167,7 @@ class Recovery {
* @return bool
*/
public function isRecoveryKeyEnabled() {
- $enabled = $this->config->getAppValue('encryption', 'recoveryAdminEnabled', 0);
+ $enabled = $this->config->getAppValue('encryption', 'recoveryAdminEnabled', '0');
return ($enabled === '1');
}
@@ -199,16 +197,15 @@ class Recovery {
/**
* add recovery key to all encrypted files
- * @param string $path
*/
- private function addRecoveryKeys($path) {
+ private function addRecoveryKeys(string $path): void {
$dirContent = $this->view->getDirectoryContent($path);
foreach ($dirContent as $item) {
$filePath = $item->getPath();
if ($item['type'] === 'dir') {
$this->addRecoveryKeys($filePath . '/');
} else {
- $fileKey = $this->keyManager->getFileKey($filePath, $this->user->getUID());
+ $fileKey = $this->keyManager->getFileKey($filePath, $this->user->getUID(), null);
if (!empty($fileKey)) {
$accessList = $this->file->getAccessList($filePath);
$publicKeys = [];
@@ -218,8 +215,11 @@ class Recovery {
$publicKeys = $this->keyManager->addSystemKeys($accessList, $publicKeys, $this->user->getUID());
- $encryptedKeyfiles = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys);
- $this->keyManager->setAllFileKeys($filePath, $encryptedKeyfiles);
+ $shareKeys = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys);
+ $this->keyManager->deleteLegacyFileKey($filePath);
+ foreach ($shareKeys as $uid => $keyFile) {
+ $this->keyManager->setShareKey($filePath, $uid, $keyFile);
+ }
}
}
}
@@ -227,9 +227,8 @@ class Recovery {
/**
* remove recovery key to all encrypted files
- * @param string $path
*/
- private function removeRecoveryKeys($path) {
+ private function removeRecoveryKeys(string $path): void {
$dirContent = $this->view->getDirectoryContent($path);
foreach ($dirContent as $item) {
$filePath = $item->getPath();
@@ -243,11 +242,8 @@ class Recovery {
/**
* recover users files with the recovery key
- *
- * @param string $recoveryPassword
- * @param string $user
*/
- public function recoverUsersFiles($recoveryPassword, $user) {
+ public function recoverUsersFiles(string $recoveryPassword, string $user): void {
$encryptedKey = $this->keyManager->getSystemPrivateKey($this->keyManager->getRecoveryKeyId());
$privateKey = $this->crypt->decryptPrivateKey($encryptedKey, $recoveryPassword);
@@ -258,12 +254,8 @@ class Recovery {
/**
* recover users files
- *
- * @param string $path
- * @param string $privateKey
- * @param string $uid
*/
- private function recoverAllFiles($path, $privateKey, $uid) {
+ private function recoverAllFiles(string $path, string $privateKey, string $uid): void {
$dirContent = $this->view->getDirectoryContent($path);
foreach ($dirContent as $item) {
@@ -279,19 +271,17 @@ class Recovery {
/**
* recover file
- *
- * @param string $path
- * @param string $privateKey
- * @param string $uid
*/
- private function recoverFile($path, $privateKey, $uid) {
+ private function recoverFile(string $path, string $privateKey, string $uid): void {
$encryptedFileKey = $this->keyManager->getEncryptedFileKey($path);
$shareKey = $this->keyManager->getShareKey($path, $this->keyManager->getRecoveryKeyId());
if ($encryptedFileKey && $shareKey && $privateKey) {
- $fileKey = $this->crypt->multiKeyDecrypt($encryptedFileKey,
+ $fileKey = $this->crypt->multiKeyDecryptLegacy($encryptedFileKey,
$shareKey,
$privateKey);
+ } elseif ($shareKey && $privateKey) {
+ $fileKey = $this->crypt->multiKeyDecrypt($shareKey, $privateKey);
}
if (!empty($fileKey)) {
@@ -303,8 +293,11 @@ class Recovery {
$publicKeys = $this->keyManager->addSystemKeys($accessList, $publicKeys, $uid);
- $encryptedKeyfiles = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys);
- $this->keyManager->setAllFileKeys($path, $encryptedKeyfiles);
+ $shareKeys = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys);
+ $this->keyManager->deleteLegacyFileKey($path);
+ foreach ($shareKeys as $uid => $keyFile) {
+ $this->keyManager->setShareKey($path, $uid, $keyFile);
+ }
}
}
}
diff --git a/apps/encryption/tests/Crypto/EncryptionTest.php b/apps/encryption/tests/Crypto/EncryptionTest.php
index 63698dcdc63..675a8bf8e29 100644
--- a/apps/encryption/tests/Crypto/EncryptionTest.php
+++ b/apps/encryption/tests/Crypto/EncryptionTest.php
@@ -42,7 +42,6 @@ use Symfony\Component\Console\Output\OutputInterface;
use Test\TestCase;
class EncryptionTest extends TestCase {
-
/** @var Encryption */
private $instance;
@@ -156,7 +155,7 @@ class EncryptionTest extends TestCase {
->willReturnCallback([$this, 'addSystemKeysCallback']);
$this->cryptMock->expects($this->any())
->method('multiKeyEncrypt')
- ->willReturn(true);
+ ->willReturn([]);
$this->instance->end('/foo/bar');
}
@@ -276,7 +275,7 @@ class EncryptionTest extends TestCase {
->with($path, $recoveryKeyId)
->willReturn($recoveryShareKey);
$this->cryptMock->expects($this->once())
- ->method('multiKeyDecrypt')
+ ->method('multiKeyDecryptLegacy')
->with('encryptedFileKey', $recoveryShareKey, $decryptAllKey)
->willReturn($fileKey);
@@ -378,6 +377,7 @@ class EncryptionTest extends TestCase {
function ($fileKey, $publicKeys) {
$this->assertEmpty($publicKeys);
$this->assertSame('fileKey', $fileKey);
+ return [];
}
);