Skip to content

Commit 400d11d

Browse files
Merge pull request #45777 from nextcloud/backport/45669/stable28
[stable28] fix: Autodetect legacy filekey instead of trusting the header for legacy header
2 parents 436663f + 71188dc commit 400d11d

File tree

3 files changed

+23
-43
lines changed

3 files changed

+23
-43
lines changed

apps/encryption/lib/Crypto/Encryption.php

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,6 @@ class Encryption implements IEncryptionModule {
8080
/** @var int Current version of the file */
8181
private int $version = 0;
8282

83-
private bool $useLegacyFileKey = true;
84-
8583
/** @var array remember encryption signature version */
8684
private static $rememberVersion = [];
8785

@@ -138,7 +136,6 @@ public function begin($path, $user, $mode, array $header, array $accessList) {
138136
$this->writeCache = '';
139137
$this->useLegacyBase64Encoding = true;
140138

141-
$this->useLegacyFileKey = ($header['useLegacyFileKey'] ?? 'true') !== 'false';
142139

143140
if (isset($header['encoding'])) {
144141
$this->useLegacyBase64Encoding = $header['encoding'] !== Crypt::BINARY_ENCODING_FORMAT;
@@ -152,19 +149,10 @@ public function begin($path, $user, $mode, array $header, array $accessList) {
152149
}
153150
}
154151

155-
if ($this->session->decryptAllModeActivated()) {
156-
$shareKey = $this->keyManager->getShareKey($this->path, $this->session->getDecryptAllUid());
157-
if ($this->useLegacyFileKey) {
158-
$encryptedFileKey = $this->keyManager->getEncryptedFileKey($this->path);
159-
$this->fileKey = $this->crypt->multiKeyDecryptLegacy($encryptedFileKey,
160-
$shareKey,
161-
$this->session->getDecryptAllKey());
162-
} else {
163-
$this->fileKey = $this->crypt->multiKeyDecrypt($shareKey, $this->session->getDecryptAllKey());
164-
}
165-
} else {
166-
$this->fileKey = $this->keyManager->getFileKey($this->path, $this->user, $this->useLegacyFileKey);
167-
}
152+
/* If useLegacyFileKey is not specified in header, auto-detect, to be safe */
153+
$useLegacyFileKey = (($header['useLegacyFileKey'] ?? '') == 'false' ? false : null);
154+
155+
$this->fileKey = $this->keyManager->getFileKey($this->path, $this->user, $useLegacyFileKey, $this->session->decryptAllModeActivated());
168156

169157
// always use the version from the original file, also part files
170158
// need to have a correct version number if they get moved over to the

apps/encryption/lib/KeyManager.php

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -367,12 +367,9 @@ public function getPrivateKey($userId) {
367367
}
368368

369369
/**
370-
* @param string $path
371-
* @param $uid
372370
* @param ?bool $useLegacyFileKey null means try both
373-
* @return string
374371
*/
375-
public function getFileKey(string $path, ?string $uid, ?bool $useLegacyFileKey): string {
372+
public function getFileKey(string $path, ?string $uid, ?bool $useLegacyFileKey, bool $useDecryptAll = false): string {
376373
if ($uid === '') {
377374
$uid = null;
378375
}
@@ -385,8 +382,10 @@ public function getFileKey(string $path, ?string $uid, ?bool $useLegacyFileKey):
385382
return '';
386383
}
387384
}
388-
389-
if ($this->util->isMasterKeyEnabled()) {
385+
if ($useDecryptAll) {
386+
$shareKey = $this->getShareKey($path, $this->session->getDecryptAllUid());
387+
$privateKey = $this->session->getDecryptAllKey();
388+
} elseif ($this->util->isMasterKeyEnabled()) {
390389
$uid = $this->getMasterKeyId();
391390
$shareKey = $this->getShareKey($path, $uid);
392391
if ($publicAccess) {

apps/encryption/tests/Crypto/EncryptionTest.php

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ protected function setUp(): void {
122122
* test if public key from one of the recipients is missing
123123
*/
124124
public function testEndUser1() {
125+
$this->sessionMock->expects($this->once())
126+
->method('decryptAllModeActivated')
127+
->willReturn(false);
128+
125129
$this->instance->begin('/foo/bar', 'user1', 'r', [], ['users' => ['user1', 'user2', 'user3']]);
126130
$this->endTest();
127131
}
@@ -131,6 +135,10 @@ public function testEndUser1() {
131135
*
132136
*/
133137
public function testEndUser2() {
138+
$this->sessionMock->expects($this->once())
139+
->method('decryptAllModeActivated')
140+
->willReturn(false);
141+
134142
$this->expectException(\OCA\Encryption\Exceptions\PublicKeyMissingException::class);
135143

136144
$this->instance->begin('/foo/bar', 'user2', 'r', [], ['users' => ['user1', 'user2', 'user3']]);
@@ -252,35 +260,16 @@ public function dataTestBegin() {
252260
*/
253261
public function testBeginDecryptAll() {
254262
$path = '/user/files/foo.txt';
255-
$recoveryKeyId = 'recoveryKeyId';
256-
$recoveryShareKey = 'recoveryShareKey';
257-
$decryptAllKey = 'decryptAllKey';
258263
$fileKey = 'fileKey';
259264

260265
$this->sessionMock->expects($this->once())
261266
->method('decryptAllModeActivated')
262267
->willReturn(true);
263-
$this->sessionMock->expects($this->once())
264-
->method('getDecryptAllUid')
265-
->willReturn($recoveryKeyId);
266-
$this->sessionMock->expects($this->once())
267-
->method('getDecryptAllKey')
268-
->willReturn($decryptAllKey);
269-
270-
$this->keyManagerMock->expects($this->once())
271-
->method('getEncryptedFileKey')
272-
->willReturn('encryptedFileKey');
273268
$this->keyManagerMock->expects($this->once())
274-
->method('getShareKey')
275-
->with($path, $recoveryKeyId)
276-
->willReturn($recoveryShareKey);
277-
$this->cryptMock->expects($this->once())
278-
->method('multiKeyDecryptLegacy')
279-
->with('encryptedFileKey', $recoveryShareKey, $decryptAllKey)
269+
->method('getFileKey')
270+
->with($path, 'user', null, true)
280271
->willReturn($fileKey);
281272

282-
$this->keyManagerMock->expects($this->never())->method('getFileKey');
283-
284273
$this->instance->begin($path, 'user', 'r', [], []);
285274

286275
$this->assertSame($fileKey,
@@ -294,6 +283,10 @@ public function testBeginDecryptAll() {
294283
* and continue
295284
*/
296285
public function testBeginInitMasterKey() {
286+
$this->sessionMock->expects($this->once())
287+
->method('decryptAllModeActivated')
288+
->willReturn(false);
289+
297290
$this->sessionMock->expects($this->once())->method('isReady')->willReturn(false);
298291
$this->utilMock->expects($this->once())->method('isMasterKeyEnabled')
299292
->willReturn(true);

0 commit comments

Comments
 (0)