diff --git a/extension/js/common/core/crypto/key.ts b/extension/js/common/core/crypto/key.ts index 51bcddabfb7..b856789671b 100644 --- a/extension/js/common/core/crypto/key.ts +++ b/extension/js/common/core/crypto/key.ts @@ -492,20 +492,40 @@ export class KeyUtil { public static validateChecksum = (armoredText: string): boolean => { const lines = armoredText.split('\n').map(l => l.trim()); + // Filter out known non-data lines const dataCandidates = lines.filter(line => line.length > 0 && !line.startsWith('-----') && !line.startsWith('Version:') && !line.startsWith('Comment:')); + // Find checksum line const checksumIndex = dataCandidates.findIndex(line => line.startsWith('=')); if (checksumIndex === -1) return false; const checksumLine = dataCandidates[checksumIndex].slice(1); const dataLines = dataCandidates.slice(0, checksumIndex); - const providedBytes = atob(checksumLine); + // Decode checksum + let providedBytes: string; + try { + providedBytes = atob(checksumLine); + } catch { + return false; + } if (providedBytes.length !== 3) return false; const providedCRC = (providedBytes.charCodeAt(0) << 16) | (providedBytes.charCodeAt(1) << 8) | providedBytes.charCodeAt(2); - const rawData = atob(dataLines.join('')); + // Attempt to decode all data lines (some may not be base64) + const decodedChunks: string[] = []; + for (const line of dataLines) { + try { + decodedChunks.push(atob(line)); + } catch { + // Not a valid base64 line, skip it + } + } + + if (decodedChunks.length === 0) return false; + + const rawData = decodedChunks.join(''); const dataBytes = new Uint8Array([...rawData].map(c => c.charCodeAt(0))); return KeyUtil.crc24(dataBytes) === providedCRC;