diff --git a/lib/private/Security/Crypto.php b/lib/private/Security/Crypto.php index b03f8a4ddce14..5a4152b1e98d2 100644 --- a/lib/private/Security/Crypto.php +++ b/lib/private/Security/Crypto.php @@ -97,9 +97,25 @@ public function decrypt(string $authenticatedCiphertext, string $password = ''): } return $this->decryptWithoutSecret($authenticatedCiphertext, $password); } catch (Exception $e) { + // If password is empty and the current secret didn't work, attempt with an empty secret as a fallback + // for instances where the secret might not have been set for a time *IF* the ciphertext version + // indicates an empty secret is a possibility. For example, it's pointless (and will fail hard if tried) + // to try the fallback with v3 versioned ciphertext since the keying material can't be empty with that version. + // SO: Only attempt the fallback on older versions (including non-versioned) ciphertexts if ($password === '') { - // Retry with empty secret as a fallback for instances where the secret might not have been set by accident - return $this->decryptWithoutSecret($authenticatedCiphertext, ''); + // Determine the crypto version, if any + $parts = explode('|', $authenticatedCiphertext); + $partCount = \count($parts); + if ($partCount < 3 || $partCount > 4) { + throw new Exception('Authenticated ciphertext could not be decoded (invalid format).'); + } + if ($partCount === 4) { // only newer ciphertext has a version field + $version = $parts[3]; + } + + if ((!empty($version) && $version <= '2') || empty($version)) { // only <3 versioned or old non-versioned ciphertext ever supported empty secrets + return $this->decryptWithoutSecret($authenticatedCiphertext, ''); + } } throw $e; } @@ -110,9 +126,6 @@ private function decryptWithoutSecret(string $authenticatedCiphertext, string $p $parts = explode('|', $authenticatedCiphertext); $partCount = \count($parts); - if ($partCount < 3 || $partCount > 4) { - throw new Exception('Authenticated ciphertext could not be decoded.'); - } $ciphertext = $this->hex2bin($parts[0]); $iv = $parts[1]; diff --git a/tests/lib/Security/CryptoTest.php b/tests/lib/Security/CryptoTest.php index b65a9a36985b7..388cac3266055 100644 --- a/tests/lib/Security/CryptoTest.php +++ b/tests/lib/Security/CryptoTest.php @@ -65,7 +65,7 @@ public function testWrongIV() { public function testWrongParameters() { $this->expectException(\Exception::class); - $this->expectExceptionMessage('Authenticated ciphertext could not be decoded.'); + $this->expectExceptionMessage('Authenticated ciphertext could not be decoded (invalid format).'); $encryptedString = '1|2'; $this->crypto->decrypt($encryptedString, 'ThisIsAVeryS3cur3P4ssw0rd');