{"record":{"id":"ac084940a22c0da7","repo":"passbolt/passbolt_api","slug":"decryption-failed-invalid-signature-expected-0-and-got-1","errorCode":null,"errorMessage":"Decryption failed. Invalid signature. Expected {0} and got {1}.","messagePattern":"Decryption failed\\. Invalid signature\\. Expected (.+?) and got (.+?)\\.","errorType":"exception","errorClass":"Cake\\Core\\Exception\\CakeException","httpStatus":null,"severity":"error","filePath":"src/Utility/OpenPGP/Backends/Gnupg.php","lineNumber":409,"sourceCode":"                $decrypted = $this->_gpg->decrypt($text);\n            } else {\n                /** @psalm-suppress InvalidArgument  */\n                $signatureInfo = $this->_gpg->decryptverify($text, $decrypted);\n            }\n        } catch (Exception $e) {\n            $this->clearDecryptKeys();\n            throw new CakeException(__('Decryption failed.') . ' ' . $e->getMessage(), null, $e);\n        }\n        $this->clearDecryptKeys();\n\n        if ($decrypted === false) {\n            throw new CakeException(__('Decryption failed.'));\n        }\n        if ($verifySignature) {\n            if (empty($signatureInfo) || $signatureInfo[0]['fingerprint'] !== $fingerprint) {\n                $msg = __('Expected {0} and got {1}.', $fingerprint, $signatureInfo[0]['fingerprint']);\n                $msg = __('Decryption failed. Invalid signature.') . ' ' . $msg;\n                throw new CakeException($msg);\n            }\n        }\n\n        return $decrypted;\n    }\n\n    /**\n     * Verify a signed message.\n     *\n     * @param string $signedText The signed message to verify.\n     * @param string|null $plainText (optional) if this parameter is passed, it will be filled with the plain text.\n     * @return array signature information\n     * @throws \\Cake\\Core\\Exception\\CakeException If the armored signed message cannot be verified.\n     */\n    public function verify(string $signedText, ?string &$plainText = null): array\n    {\n        $this->assertVerifyKey();\n        $msg = __('The message cannot be verified.');","sourceCodeStart":391,"sourceCodeEnd":427,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Utility/OpenPGP/Backends/Gnupg.php#L391-L427","documentation":"Thrown when decrypt($text, true) succeeds but the signature embedded in the message does not match the verify key fingerprint set via setVerifyKey. It reports 'Decryption failed. Invalid signature. Expected {0} and got {1}.' — the message decrypted, but was not signed by the expected key.","triggerScenarios":"decrypt with $verifySignature = true where signatureInfo is empty (message unsigned) or signatureInfo[0]['fingerprint'] differs from $this->_verifyKeyFingerprint.","commonSituations":"Verifying that a token/message was signed by the server itself but the data was signed by a user key or a different server key (after key rotation); verifying data signed by an older server key not set as verify key; attacker-substituted or replayed payloads.","solutions":["Compare the 'got' fingerprint in the message with your configured verify key; if the server key rotated, set the new/old key accordingly via setVerifyKey before decrypt","If legitimate, re-sign or re-encrypt the data with the current server key","If the sender should differ, pass the expected signer's fingerprint as verify key","Treat as integrity failure — do not trust the decrypted content in security-sensitive flows"],"exampleFix":"// before\n$gpg->setVerifyKey($newServerKeyFingerprint);\n$plain = $gpg->decrypt($msgSignedWithOldKey, true); // Invalid signature. Expected new, got old\n// after\n$gpg->setVerifyKey($oldSigningKeyFingerprint); // fingerprint that actually signed\n$plain = $gpg->decrypt($msgSignedWithOldKey, true);","handlingStrategy":"try-catch","validationCode":"// caller should know the expected signer fingerprint and compare\n$expectedSigner = $this->getExpectedSignerFingerprint($context);\nif ($expectedSigner !== $configuredVerifyFingerprint) {\n    $gpg->setVerifyKey($expectedSigner);\n}","typeGuard":null,"tryCatchPattern":"try {\n    $plain = $gpg->decrypt($armored, true);\n} catch (CakeException $e) {\n    if (str_contains($e->getMessage(), 'Invalid signature')) {\n        $this->log('Signature from unexpected key — possible key rotation or tampering');\n    }\n    throw $e;\n}","preventionTips":["Track which key signed each record when server keys rotate","Keep old server public keys in the keyring for verification of legacy data","Always verify signatures on security-sensitive payloads and fail closed","Monitor fingerprint mismatch logs for tampering signals"],"tags":["openpgp","signature","verification","fingerprint-mismatch"],"backgroundTag":"openpgp-signature-verification-failed","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}