aboutsummaryrefslogtreecommitdiffstats
path: root/apps/encryption/lib
diff options
context:
space:
mode:
authorCôme Chilliet <come.chilliet@nextcloud.com>2023-03-15 18:10:24 +0100
committerCôme Chilliet <come.chilliet@nextcloud.com>2023-03-17 11:08:50 +0100
commitfbe282caeb7dd0d91435f6f547db027e500e248a (patch)
treef74b86c473a4f3d996647e2d4671a9ec20931691 /apps/encryption/lib
parentc7c1133c15f4ab33a69d40bb387354a270ca5541 (diff)
downloadnextcloud-server-fbe282caeb7dd0d91435f6f547db027e500e248a.tar.gz
nextcloud-server-fbe282caeb7dd0d91435f6f547db027e500e248a.zip
Getting rid of openssl_seal and rc4 in server side encryption
Signed-off-by: Côme Chilliet <come.chilliet@nextcloud.com>
Diffstat (limited to 'apps/encryption/lib')
-rw-r--r--apps/encryption/lib/Crypto/Crypt.php63
-rw-r--r--apps/encryption/lib/Crypto/Encryption.php29
-rw-r--r--apps/encryption/lib/KeyManager.php26
3 files changed, 94 insertions, 24 deletions
diff --git a/apps/encryption/lib/Crypto/Crypt.php b/apps/encryption/lib/Crypto/Crypt.php
index fe9813a6cfa..f4544a61716 100644
--- a/apps/encryption/lib/Crypto/Crypt.php
+++ b/apps/encryption/lib/Crypto/Crypt.php
@@ -695,13 +695,25 @@ class Crypt {
}
/**
- * @param string $encKeyFile
- * @param string $shareKey
* @param \OpenSSLAsymmetricKey|\OpenSSLCertificate|array|string $privateKey
- * @return string
* @throws MultiKeyDecryptException
*/
- public function multiKeyDecrypt($encKeyFile, $shareKey, $privateKey) {
+ public function multiKeyDecrypt(string $shareKey, $privateKey): string {
+ $plainContent = '';
+
+ // decrypt the intermediate key with RSA
+ if (openssl_private_decrypt($shareKey, $intermediate, $privateKey, OPENSSL_PKCS1_OAEP_PADDING)) {
+ return $intermediate;
+ } else {
+ throw new MultiKeyDecryptException('multikeydecrypt with share key failed:' . openssl_error_string());
+ }
+ }
+
+ /**
+ * @param \OpenSSLAsymmetricKey|\OpenSSLCertificate|array|string $privateKey
+ * @throws MultiKeyDecryptException
+ */
+ public function multiKeyDecryptLegacy(string $encKeyFile, string $shareKey, $privateKey): string {
if (!$encKeyFile) {
throw new MultiKeyDecryptException('Cannot multikey decrypt empty plain content');
}
@@ -715,12 +727,53 @@ class Crypt {
}
/**
+ * @throws MultiKeyEncryptException
+ */
+ public function multiKeyEncrypt(string $plainContent, array $keyFiles): array {
+ if (empty($plainContent)) {
+ throw new MultiKeyEncryptException('Cannot multikeyencrypt empty plain content');
+ }
+
+ // Set empty vars to be set by openssl by reference
+ $shareKeys = [];
+ $mappedShareKeys = [];
+
+ // make sure that there is at least one public key to use
+ if (count($keyFiles) >= 1) {
+ // prepare the encrypted keys
+ $shareKeys = [];
+
+ // iterate over the public keys and encrypt the intermediate
+ // for each of them with RSA
+ foreach ($keyFiles as $tmp_key) {
+ if (openssl_public_encrypt($plainContent, $tmp_output, $tmp_key, OPENSSL_PKCS1_OAEP_PADDING)) {
+ $shareKeys[] = $tmp_output;
+ }
+ }
+
+ // set the result if everything worked fine
+ if (count($keyFiles) === count($shareKeys)) {
+ $i = 0;
+
+ // Ensure each shareKey is labelled with its corresponding key id
+ foreach ($keyFiles as $userId => $publicKey) {
+ $mappedShareKeys[$userId] = $shareKeys[$i];
+ $i++;
+ }
+
+ return $mappedShareKeys;
+ }
+ }
+ throw new MultiKeyEncryptException('multikeyencryption failed ' . openssl_error_string());
+ }
+
+ /**
* @param string $plainContent
* @param array $keyFiles
* @return array
* @throws MultiKeyEncryptException
*/
- public function multiKeyEncrypt($plainContent, array $keyFiles) {
+ public function multiKeyEncryptLegacy($plainContent, array $keyFiles) {
// openssl_seal returns false without errors if plaincontent is empty
// so trigger our own error
if (empty($plainContent)) {
diff --git a/apps/encryption/lib/Crypto/Encryption.php b/apps/encryption/lib/Crypto/Encryption.php
index b44472fd04a..bee91e530ff 100644
--- a/apps/encryption/lib/Crypto/Encryption.php
+++ b/apps/encryption/lib/Crypto/Encryption.php
@@ -108,6 +108,8 @@ class Encryption implements IEncryptionModule {
/** @var int Current version of the file */
private $version = 0;
+ private bool $useLegacyFileKey = true;
+
/** @var array remember encryption signature version */
private static $rememberVersion = [];
@@ -182,6 +184,8 @@ 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;
}
@@ -195,13 +199,17 @@ class Encryption implements IEncryptionModule {
}
if ($this->session->decryptAllModeActivated()) {
- $encryptedFileKey = $this->keyManager->getEncryptedFileKey($this->path);
$shareKey = $this->keyManager->getShareKey($this->path, $this->session->getDecryptAllUid());
- $this->fileKey = $this->crypt->multiKeyDecrypt($encryptedFileKey,
- $shareKey,
- $this->session->getDecryptAllKey());
+ 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->fileKey = $this->keyManager->getFileKey($this->path, $this->user, $this->useLegacyFileKey);
}
// always use the version from the original file, also part files
@@ -239,7 +247,11 @@ class Encryption implements IEncryptionModule {
$this->cipher = $this->crypt->getLegacyCipher();
}
- $result = ['cipher' => $this->cipher, 'signed' => 'true'];
+ $result = [
+ 'cipher' => $this->cipher,
+ 'signed' => 'true',
+ 'useLegacyFileKey' => 'false',
+ ];
if ($this->useLegacyBase64Encoding !== true) {
$result['encoding'] = Crypt::BINARY_ENCODING_FORMAT;
@@ -296,6 +308,7 @@ 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);
}
@@ -315,7 +328,6 @@ class Encryption implements IEncryptionModule {
// If extra data is left over from the last round, make sure it
// is integrated into the next block
if ($this->writeCache) {
-
// Concat writeCache to start of $data
$data = $this->writeCache . $data;
@@ -327,7 +339,6 @@ class Encryption implements IEncryptionModule {
$encrypted = '';
// While there still remains some data to be processed & written
while (strlen($data) > 0) {
-
// Remaining length for this iteration, not of the
// entire file (may be greater than 8192 bytes)
$remainingLength = strlen($data);
@@ -335,7 +346,6 @@ class Encryption implements IEncryptionModule {
// If data remaining to be written is less than the
// size of 1 unencrypted block
if ($remainingLength < $this->getUnencryptedBlockSize(true)) {
-
// Set writeCache to contents of $data
// The writeCache will be carried over to the
// next write round, and added to the start of
@@ -349,7 +359,6 @@ class Encryption implements IEncryptionModule {
// Clear $data ready for next round
$data = '';
} else {
-
// Read the chunk from the start of $data
$chunk = substr($data, 0, $this->getUnencryptedBlockSize(true));
diff --git a/apps/encryption/lib/KeyManager.php b/apps/encryption/lib/KeyManager.php
index 2c6487d062a..5f35f7a8422 100644
--- a/apps/encryption/lib/KeyManager.php
+++ b/apps/encryption/lib/KeyManager.php
@@ -44,7 +44,6 @@ use OCP\IUserSession;
use OCP\Lock\ILockingProvider;
class KeyManager {
-
/**
* @var Session
*/
@@ -443,15 +442,18 @@ class KeyManager {
* @param $uid
* @return string
*/
- public function getFileKey($path, $uid) {
+ public function getFileKey(string $path, ?string $uid, bool $useLegacyFileKey): string {
if ($uid === '') {
$uid = null;
}
$publicAccess = is_null($uid);
- $encryptedFileKey = $this->keyStorage->getFileKey($path, $this->fileKeyId, Encryption::ID);
- if (empty($encryptedFileKey)) {
- return '';
+ if ($useLegacyFileKey) {
+ $encryptedFileKey = $this->keyStorage->getFileKey($path, $this->fileKeyId, Encryption::ID);
+
+ if (empty($encryptedFileKey)) {
+ return '';
+ }
}
if ($this->util->isMasterKeyEnabled()) {
@@ -475,10 +477,16 @@ class KeyManager {
$privateKey = $this->session->getPrivateKey();
}
- if ($encryptedFileKey && $shareKey && $privateKey) {
- return $this->crypt->multiKeyDecrypt($encryptedFileKey,
- $shareKey,
- $privateKey);
+ if ($useLegacyFileKey) {
+ if ($encryptedFileKey && $shareKey && $privateKey) {
+ return $this->crypt->multiKeyDecryptLegacy($encryptedFileKey,
+ $shareKey,
+ $privateKey);
+ }
+ } else {
+ if ($shareKey && $privateKey) {
+ return $this->crypt->multiKeyDecrypt($shareKey, $privateKey);
+ }
}
return '';