From 238723da306090aa62bda6c0922bae99d841203f Mon Sep 17 00:00:00 2001 From: zsh <1242643352@qq.com> Date: Tue, 12 May 2026 21:21:23 +0800 Subject: [PATCH] Add SHA-3 hash reporting support --- index.html | 329 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 224 insertions(+), 105 deletions(-) diff --git a/index.html b/index.html index d276a17..01426ac 100644 --- a/index.html +++ b/index.html @@ -56,12 +56,13 @@ .btn-tile:hover { transform: translateY(-3px); box-shadow: 0 5px 15px rgba(0,0,0,0.15); } .btn-tile i { font-size: 1.5rem; margin-bottom: 5px; } - .bg-csv { background-color: #4666ff; color: white; } - .bg-pdf { background-color: #dc3545; color: white; } - .bg-word { background-color: #000000; color: white; } - .bg-email { background-color: #ffffff; color: #dc3545; border: 1px solid #dc3545; } - .bg-guide { background-color: #cfb137; color: #000; } - .bg-clear { background-color: #ffffff; color: #666; border: 1px solid #ddd; } + .bg-csv { background-color: #4666ff; color: white; } + .bg-pdf { background-color: #dc3545; color: white; } + .bg-word { background-color: #000000; color: white; } + .bg-excel { background-color: #198754; color: white; } + .bg-email { background-color: #ffffff; color: #dc3545; border: 1px solid #dc3545; } + .bg-guide { background-color: #cfb137; color: #000; } + .bg-clear { background-color: #ffffff; color: #666; border: 1px solid #ddd; } /* DROP ZONE */ .drop-zone { @@ -247,16 +248,21 @@

Evidence Validation Suite

Hash PDF -
- -
-
- -
+
+ +
+
+ +
+
+ +
@@ -494,12 +501,13 @@
Yahoo/Outlook:
${file.name} ${isEml ? 'EMAIL' : ''} - - Calculating... - Calculating... - - `); - fileQueue.push({ file, rowId }); + + Calculating... + Calculating... + Calculating... + + `); + fileQueue.push({ file, rowId }); }); if (!isProcessing) processQueue(); } @@ -515,13 +523,18 @@
Yahoo/Outlook:
const reader = new FileReader(); reader.onload = function(e) { const wordArray = CryptoJS.lib.WordArray.create(e.target.result); - setTimeout(() => { - if (row) { - row.querySelector('.md5').innerText = CryptoJS.MD5(wordArray).toString(); - row.querySelector('.sha256').innerText = CryptoJS.SHA256(wordArray).toString(); - } - processQueue(); - }, 50); + setTimeout(() => { + if (row) { + const md5 = CryptoJS.MD5(wordArray).toString(); + const sha256 = CryptoJS.SHA256(wordArray).toString(); + const sha3 = CryptoJS.SHA3(wordArray, { outputLength: 256 }).toString(); + row.querySelector('.md5').innerText = md5; + row.querySelector('.sha256').innerText = sha256; + row.querySelector('.sha3').innerText = sha3; + console.log(`[Hash Report] SHA-3-256 calculated for ${file.name}: ${sha3}`); + } + processQueue(); + }, 50); }; reader.readAsArrayBuffer(file); } @@ -611,8 +624,9 @@
Yahoo/Outlook:
doc.addPage(); const text = await readFile(files[i]); - const emailData = parseEml(text); - const sha256 = await calculateSHA256(files[i]); + const emailData = parseEml(text); + const sha256 = await calculateSHA256(files[i]); + const sha3 = await calculateSHA3(files[i]); // HEADER WITH WRAPPED FILENAME doc.setFillColor(0, 51, 102); @@ -644,10 +658,11 @@
Yahoo/Outlook:
['To', emailData.to], ['Date', emailData.date], ['Message-ID', emailData.messageId], - ['Originating IP', emailData.serverIP], - ['DKIM Status', emailData.dkim], - ['SHA-256 Hash', sha256] - ], + ['Originating IP', emailData.serverIP], + ['DKIM Status', emailData.dkim], + ['SHA-256 Hash', sha256], + ['SHA-3-256 Hash', sha3] + ], theme: 'grid', headStyles: { fillColor: [0, 51, 102], @@ -713,23 +728,24 @@
Yahoo/Outlook:
if (tr.querySelector('input').checked) { const cells = tr.querySelectorAll('td'); rows.push([ - cells[1].innerText, - cells[2].innerText, - cells[4].innerText - ]); - } - }); + cells[1].innerText, + cells[2].innerText, + cells[4].innerText, + cells[5].innerText + ]); + } + }); if (rows.length === 0) { alert("Please select files to include in report."); return; } - doc.autoTable({ - startY: 70, - head: [['#', 'Filename', 'SHA-256']], - body: rows, - theme: 'grid', + doc.autoTable({ + startY: 70, + head: [['#', 'Filename', 'SHA-256', 'SHA-3-256']], + body: rows, + theme: 'grid', headStyles: { fillColor: [0, 51, 102], fontSize: 11, @@ -739,12 +755,13 @@
Yahoo/Outlook:
fontSize: 9, font: 'courier' }, - columnStyles: { - 0: { cellWidth: 40 }, - 1: { cellWidth: 300 }, - 2: { cellWidth: 450, font: 'courier' } - } - }); + columnStyles: { + 0: { cellWidth: 40 }, + 1: { cellWidth: 240 }, + 2: { cellWidth: 260, font: 'courier' }, + 3: { cellWidth: 260, font: 'courier' } + } + }); doc.save("Hash_Report.pdf", { compress: true }); } @@ -776,15 +793,22 @@
Yahoo/Outlook:
})], shading: { fill: "003366" } }), - new TableCell({ - children: [new Paragraph({ - children: [new TextRun({ text: "SHA-256", bold: true, color: "FFFFFF" })], - alignment: AlignmentType.CENTER - })], - shading: { fill: "003366" } - }) - ] - })); + new TableCell({ + children: [new Paragraph({ + children: [new TextRun({ text: "SHA-256", bold: true, color: "FFFFFF" })], + alignment: AlignmentType.CENTER + })], + shading: { fill: "003366" } + }), + new TableCell({ + children: [new Paragraph({ + children: [new TextRun({ text: "SHA-3-256", bold: true, color: "FFFFFF" })], + alignment: AlignmentType.CENTER + })], + shading: { fill: "003366" } + }) + ] + })); document.querySelectorAll("#hashTableBody tr").forEach(tr => { if (tr.querySelector('input').checked) { @@ -792,12 +816,15 @@
Yahoo/Outlook:
rows.push(new TableRow({ children: [ new TableCell({ children: [new Paragraph(cells[1].innerText)] }), - new TableCell({ children: [new Paragraph(cells[2].innerText)] }), - new TableCell({ children: [new Paragraph({ - children: [new TextRun({ text: cells[4].innerText, font: "Courier New", size: 18 })] - })] }) - ] - })); + new TableCell({ children: [new Paragraph(cells[2].innerText)] }), + new TableCell({ children: [new Paragraph({ + children: [new TextRun({ text: cells[4].innerText, font: "Courier New", size: 18 })] + })] }), + new TableCell({ children: [new Paragraph({ + children: [new TextRun({ text: cells[5].innerText, font: "Courier New", size: 18 })] + })] }) + ] + })); } }); @@ -833,36 +860,103 @@
Yahoo/Outlook:
a.download = "Hash_Report.docx"; a.click(); }); - } - - // ===== DOWNLOAD CSV ===== - function downloadSelectedCSV() { - let csv = "#,Subject,From,To,Date,Originating IP,DKIM,SHA-256\n"; - - let counter = 1; - const promises = []; - - document.querySelectorAll("#hashTableBody tr").forEach(tr => { - if (tr.querySelector('input').checked && tr.fileData && tr.fileData.name.toLowerCase().endsWith('.eml')) { - const cells = tr.querySelectorAll('td'); - promises.push( - readFile(tr.fileData).then(text => { - const eml = parseEml(text); - return `${counter++},"${eml.subject}","${eml.from}","${eml.to}","${eml.date}","${eml.serverIP}","${eml.dkim}","${cells[4].innerText}"\n`; - }) - ); - } - }); + } + + // ===== GENERATE HASH EXCEL ===== + function generateHashExcel() { + const rows = []; + rows.push(['#', 'Filename', 'MD5', 'SHA-256', 'SHA-3-256']); + + document.querySelectorAll("#hashTableBody tr").forEach(tr => { + if (tr.querySelector('input').checked) { + const cells = tr.querySelectorAll('td'); + rows.push([ + cells[1].innerText, + cells[2].innerText, + cells[3].innerText, + cells[4].innerText, + cells[5].innerText + ]); + } + }); + + if (rows.length === 1) { + alert("Please select files to include in report."); + return; + } + + const html = ` + + + + + ${rows.map(row => `${row.map(cell => ``).join('')}`).join('')} +
${escapeHtml(String(cell))}
+ + + `; + const blob = new Blob([html], { type: 'application/vnd.ms-excel' }); + const a = document.createElement('a'); + a.href = URL.createObjectURL(blob); + a.download = "Hash_Report.xls"; + a.click(); + } + + // ===== DOWNLOAD CSV ===== + function downloadSelectedCSV() { + let csv = "#,Filename,Subject,From,To,Date,Originating IP,DKIM,MD5,SHA-256,SHA-3-256\n"; + + let counter = 1; + const promises = []; + + document.querySelectorAll("#hashTableBody tr").forEach(tr => { + if (tr.querySelector('input').checked && tr.fileData) { + const cells = tr.querySelectorAll('td'); + const appendRow = (eml) => { + const row = [ + counter++, + tr.fileData.name, + eml.subject, + eml.from, + eml.to, + eml.date, + eml.serverIP, + eml.dkim, + cells[3].innerText, + cells[4].innerText, + cells[5].innerText + ]; + return `${row.map(csvEscape).join(',')}\n`; + }; + + if (tr.fileData.name.toLowerCase().endsWith('.eml')) { + promises.push(readFile(tr.fileData).then(text => { + const eml = parseEml(text); + return appendRow(eml); + })); + } + else { + promises.push(Promise.resolve(appendRow({ + subject: '', + from: '', + to: '', + date: '', + serverIP: '', + dkim: '' + }))); + } + } + }); Promise.all(promises).then(rows => { csv += rows.join(''); const blob = new Blob([csv], { type: 'text/csv' }); const a = document.createElement('a'); - a.href = URL.createObjectURL(blob); - a.download = "Email_Report.csv"; - a.click(); - }); - } + a.href = URL.createObjectURL(blob); + a.download = "Hash_Report.csv"; + a.click(); + }); + } // ===== UTILITY FUNCTIONS ===== function getSelectedEmlFiles() { @@ -883,17 +977,42 @@
Yahoo/Outlook:
}); } - async function calculateSHA256(file) { - return new Promise(resolve => { + async function calculateSHA256(file) { + return new Promise(resolve => { const reader = new FileReader(); reader.onload = e => { const wordArray = CryptoJS.lib.WordArray.create(e.target.result); resolve(CryptoJS.SHA256(wordArray).toString()); }; - reader.readAsArrayBuffer(file); - }); - } - + reader.readAsArrayBuffer(file); + }); + } + + async function calculateSHA3(file) { + return new Promise(resolve => { + const reader = new FileReader(); + reader.onload = e => { + const wordArray = CryptoJS.lib.WordArray.create(e.target.result); + resolve(CryptoJS.SHA3(wordArray, { outputLength: 256 }).toString()); + }; + reader.readAsArrayBuffer(file); + }); + } + + function csvEscape(value) { + const text = String(value ?? ''); + return `"${text.replace(/"/g, '""')}"`; + } + + function escapeHtml(value) { + return value + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + } + function toggleAll(checkbox) { document.querySelectorAll('input[name="fileSelect"]').forEach(c => c.checked = checkbox.checked); }