From b860e5ae5c5639ca4948c8893f98b324d744feb6 Mon Sep 17 00:00:00 2001 From: Roma Sosnovsky Date: Mon, 8 Jun 2026 22:33:16 +0300 Subject: [PATCH] #6240 Improve checksum mismatch validation --- extension/js/common/core/crypto/key.ts | 9 ++++----- extension/js/common/message-renderer.ts | 2 +- test/source/tests/unit-node.ts | 14 ++++++++++++++ 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/extension/js/common/core/crypto/key.ts b/extension/js/common/core/crypto/key.ts index 144f6f6db5c..ed49354cf09 100644 --- a/extension/js/common/core/crypto/key.ts +++ b/extension/js/common/core/crypto/key.ts @@ -495,13 +495,12 @@ export class KeyUtil { return keys.map(k => ({ id: k.id, emails: k.users.map(u => u.email).filter((e): e is string => !!e), armored: KeyUtil.armor(k), family: k.family })); } - public static validateChecksum(armoredText: string): boolean { + public static isChecksumMismatch(armoredText: string): boolean { // Regex to capture any PGP armor block, e.g. SIGNATURE, MESSAGE, etc. // It captures: the block type in group (1), and the content in group (2) const pgpBlockRegex = /-----BEGIN PGP ([A-Z ]+)-----([\s\S]*?)-----END PGP \1-----/g; let match: RegExpExecArray | null; - let validFound = false; // Iterate over all PGP blocks in the text while ((match = pgpBlockRegex.exec(armoredText))) { @@ -553,12 +552,12 @@ export class KeyUtil { const rawData = decodedChunks.join(''); // eslint-disable-next-line @typescript-eslint/no-misused-spread const dataBytes = new Uint8Array([...rawData].map(c => c.charCodeAt(0))); - if (KeyUtil.crc24(dataBytes) === providedCRC) { - validFound = true; + if (KeyUtil.crc24(dataBytes) !== providedCRC) { + return true; } } - return validFound; + return false; } private static crc24 = (dataBytes: Uint8Array): number => { diff --git a/extension/js/common/message-renderer.ts b/extension/js/common/message-renderer.ts index 095850e4d7d..5b7c1270beb 100644 --- a/extension/js/common/message-renderer.ts +++ b/extension/js/common/message-renderer.ts @@ -774,7 +774,7 @@ export class MessageRenderer { renderModule, this.getRetryVerification(signerEmail, verificationPubs => MessageRenderer.decryptFunctionToVerifyRes(() => decrypt(verificationPubs))), plainSubject, - !KeyUtil.validateChecksum(encryptedData.toString()) + typeof encryptedData === 'string' && KeyUtil.isChecksumMismatch(encryptedData) ); } else if (result.error.type === DecryptErrTypes.format) { if (fallbackToPlainText) { diff --git a/test/source/tests/unit-node.ts b/test/source/tests/unit-node.ts index 51709d7b634..08f9a40458a 100644 --- a/test/source/tests/unit-node.ts +++ b/test/source/tests/unit-node.ts @@ -85,6 +85,20 @@ Something wrong with this key`), } ); }); + test(`[unit][KeyUtil.isChecksumMismatch] detects only present checksum mismatches`, t => { + const armoredWithValidChecksum = `-----BEGIN PGP MESSAGE----- + +aGVsbG8= +=R/WK +-----END PGP MESSAGE-----`; + const armoredWithInvalidChecksum = armoredWithValidChecksum.replace('=R/WK', '=AAAA'); + const armoredWithoutChecksum = armoredWithValidChecksum.replace('\n=R/WK', ''); + + expect(KeyUtil.isChecksumMismatch(armoredWithValidChecksum)).to.equal(false); + expect(KeyUtil.isChecksumMismatch(armoredWithInvalidChecksum)).to.equal(true); + expect(KeyUtil.isChecksumMismatch(armoredWithoutChecksum)).to.equal(false); + t.pass(); + }); test(`[unit][OpenPGPKey.parse] throws on invalid input`, async t => { await t.throwsAsync( () =>