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 => `| ${escapeHtml(String(cell))} | `).join('')}
`).join('')}
+
+
+
+ `;
+ 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);
}