Skip to content

Commit

Permalink
Merge pull request #45776 from nextcloud/backport/45669/stable27
Browse files Browse the repository at this point in the history
[stable27] fix: Autodetect legacy filekey instead of trusting the header for legacy header
  • Loading branch information
AndyScherzinger authored Jun 11, 2024
2 parents 3024d71 + e2ed90d commit fc3f8f7
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 43 deletions.
20 changes: 4 additions & 16 deletions apps/encryption/lib/Crypto/Encryption.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,6 @@ 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 = [];

Expand Down Expand Up @@ -184,7 +182,6 @@ public function begin($path, $user, $mode, array $header, array $accessList) {
$this->writeCache = '';
$this->useLegacyBase64Encoding = true;

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

if (isset($header['encoding'])) {
$this->useLegacyBase64Encoding = $header['encoding'] !== Crypt::BINARY_ENCODING_FORMAT;
Expand All @@ -198,19 +195,10 @@ public function begin($path, $user, $mode, array $header, array $accessList) {
}
}

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
Expand Down
11 changes: 5 additions & 6 deletions apps/encryption/lib/KeyManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -438,12 +438,9 @@ public function getPrivateKey($userId) {
}

/**
* @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, bool $useDecryptAll = false): string {
if ($uid === '') {
$uid = null;
}
Expand All @@ -456,8 +453,10 @@ public function getFileKey(string $path, ?string $uid, ?bool $useLegacyFileKey):
return '';
}
}

if ($this->util->isMasterKeyEnabled()) {
if ($useDecryptAll) {
$shareKey = $this->getShareKey($path, $this->session->getDecryptAllUid());
$privateKey = $this->session->getDecryptAllKey();
} elseif ($this->util->isMasterKeyEnabled()) {
$uid = $this->getMasterKeyId();
$shareKey = $this->getShareKey($path, $uid);
if ($publicAccess) {
Expand Down
35 changes: 14 additions & 21 deletions apps/encryption/tests/Crypto/EncryptionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ protected function setUp(): void {
* test if public key from one of the recipients is missing
*/
public function testEndUser1() {
$this->sessionMock->expects($this->once())
->method('decryptAllModeActivated')
->willReturn(false);

$this->instance->begin('/foo/bar', 'user1', 'r', [], ['users' => ['user1', 'user2', 'user3']]);
$this->endTest();
}
Expand All @@ -131,6 +135,10 @@ public function testEndUser1() {
*
*/
public function testEndUser2() {
$this->sessionMock->expects($this->once())
->method('decryptAllModeActivated')
->willReturn(false);

$this->expectException(\OCA\Encryption\Exceptions\PublicKeyMissingException::class);

$this->instance->begin('/foo/bar', 'user2', 'r', [], ['users' => ['user1', 'user2', 'user3']]);
Expand Down Expand Up @@ -252,35 +260,16 @@ public function dataTestBegin() {
*/
public function testBeginDecryptAll() {
$path = '/user/files/foo.txt';
$recoveryKeyId = 'recoveryKeyId';
$recoveryShareKey = 'recoveryShareKey';
$decryptAllKey = 'decryptAllKey';
$fileKey = 'fileKey';

$this->sessionMock->expects($this->once())
->method('decryptAllModeActivated')
->willReturn(true);
$this->sessionMock->expects($this->once())
->method('getDecryptAllUid')
->willReturn($recoveryKeyId);
$this->sessionMock->expects($this->once())
->method('getDecryptAllKey')
->willReturn($decryptAllKey);

$this->keyManagerMock->expects($this->once())
->method('getEncryptedFileKey')
->willReturn('encryptedFileKey');
$this->keyManagerMock->expects($this->once())
->method('getShareKey')
->with($path, $recoveryKeyId)
->willReturn($recoveryShareKey);
$this->cryptMock->expects($this->once())
->method('multiKeyDecryptLegacy')
->with('encryptedFileKey', $recoveryShareKey, $decryptAllKey)
->method('getFileKey')
->with($path, 'user', null, true)
->willReturn($fileKey);

$this->keyManagerMock->expects($this->never())->method('getFileKey');

$this->instance->begin($path, 'user', 'r', [], []);

$this->assertSame($fileKey,
Expand All @@ -294,6 +283,10 @@ public function testBeginDecryptAll() {
* and continue
*/
public function testBeginInitMasterKey() {
$this->sessionMock->expects($this->once())
->method('decryptAllModeActivated')
->willReturn(false);

$this->sessionMock->expects($this->once())->method('isReady')->willReturn(false);
$this->utilMock->expects($this->once())->method('isMasterKeyEnabled')
->willReturn(true);
Expand Down

0 comments on commit fc3f8f7

Please sign in to comment.