Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 55 additions & 19 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -287,9 +287,10 @@ <h5 class="fw-bold">Drag & Drop Evidence Files Here</h5>
<tr class="table-header">
<th width="5%" class="ps-4"><input type="checkbox" id="selectAll" onclick="toggleAll(this)"></th>
<th width="5%">#</th>
<th width="30%">Filename</th>
<th width="20%">MD5 Hash</th>
<th width="40%">SHA-256 (Section 63 BSA Compliant)</th>
<th width="25%">Filename</th>
<th width="15%">MD5 Hash</th>
<th width="25%">SHA-256 (Section 63 BSA Compliant)</th>
<th width="25%">SHA-3 (FIPS 202)</th>
</tr>
</thead>
<tbody id="hashTableBody" style="background: white;"></tbody>
Expand Down Expand Up @@ -497,6 +498,7 @@ <h6 class="fw-bold mt-3">Yahoo/Outlook:</h6>
</td>
<td class="hash-font md5">Calculating...</td>
<td class="hash-font sha256">Calculating...</td>
<td class="hash-font sha3">Calculating...</td>
</tr>
`);
fileQueue.push({ file, rowId });
Expand All @@ -517,8 +519,13 @@ <h6 class="fw-bold mt-3">Yahoo/Outlook:</h6>
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();
const md5Val = CryptoJS.MD5(wordArray).toString();
const sha256Val = CryptoJS.SHA256(wordArray).toString();
const sha3Val = CryptoJS.SHA3(wordArray).toString();
console.log(`[System Console] Calculated SHA-3 (FIPS 202) for "${file.name}": ${sha3Val}`);
row.querySelector('.md5').innerText = md5Val;
row.querySelector('.sha256').innerText = sha256Val;
row.querySelector('.sha3').innerText = sha3Val;
}
processQueue();
}, 50);
Expand Down Expand Up @@ -715,7 +722,8 @@ <h6 class="fw-bold mt-3">Yahoo/Outlook:</h6>
rows.push([
cells[1].innerText,
cells[2].innerText,
cells[4].innerText
cells[4].innerText,
cells[5].innerText
]);
}
});
Expand All @@ -727,7 +735,7 @@ <h6 class="fw-bold mt-3">Yahoo/Outlook:</h6>

doc.autoTable({
startY: 70,
head: [['#', 'Filename', 'SHA-256']],
head: [['#', 'Filename', 'SHA-256', 'SHA-3']],
body: rows,
theme: 'grid',
headStyles: {
Expand All @@ -736,13 +744,14 @@ <h6 class="fw-bold mt-3">Yahoo/Outlook:</h6>
fontStyle: 'bold'
},
bodyStyles: {
fontSize: 9,
fontSize: 8,
font: 'courier'
},
columnStyles: {
0: { cellWidth: 40 },
1: { cellWidth: 300 },
2: { cellWidth: 450, font: 'courier' }
0: { cellWidth: 35 },
1: { cellWidth: 160 },
2: { cellWidth: 295, font: 'courier' },
3: { cellWidth: 295, font: 'courier' }
}
});

Expand Down Expand Up @@ -782,6 +791,13 @@ <h6 class="fw-bold mt-3">Yahoo/Outlook:</h6>
alignment: AlignmentType.CENTER
})],
shading: { fill: "003366" }
}),
new TableCell({
children: [new Paragraph({
children: [new TextRun({ text: "SHA-3", bold: true, color: "FFFFFF" })],
alignment: AlignmentType.CENTER
})],
shading: { fill: "003366" }
})
]
}));
Expand All @@ -795,6 +811,9 @@ <h6 class="fw-bold mt-3">Yahoo/Outlook:</h6>
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 })]
})] })
]
}));
Expand Down Expand Up @@ -837,20 +856,26 @@ <h6 class="fw-bold mt-3">Yahoo/Outlook:</h6>

// ===== DOWNLOAD CSV =====
function downloadSelectedCSV() {
let csv = "#,Subject,From,To,Date,Originating IP,DKIM,SHA-256\n";
let csv = "#,Subject/Filename,From,To,Date,Originating IP,DKIM,SHA-256,SHA-3\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')) {
if (tr.querySelector('input').checked && tr.fileData) {
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`;
})
);
if (tr.fileData.name.toLowerCase().endsWith('.eml')) {
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}","${cells[5].innerText}"\n`;
})
);
} else {
promises.push(
Promise.resolve(`${counter++},"${tr.fileData.name}","N/A","N/A","N/A","N/A","N/A","${cells[4].innerText}","${cells[5].innerText}"\n`)
);
}
}
});

Expand Down Expand Up @@ -894,6 +919,17 @@ <h6 class="fw-bold mt-3">Yahoo/Outlook:</h6>
});
}

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).toString());
};
reader.readAsArrayBuffer(file);
});
}

function toggleAll(checkbox) {
document.querySelectorAll('input[name="fileSelect"]').forEach(c => c.checked = checkbox.checked);
}
Expand Down
58 changes: 58 additions & 0 deletions test_sha3_support.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const fs = require('fs');
const path = require('path');
const assert = require('assert');

console.log("Running Acceptance Test for SHA-3 (Keccak) Hashing Support...");

const indexPath = path.join(__dirname, 'index.html');
const htmlContent = fs.readFileSync(indexPath, 'utf-8');

const checks = [
{
name: "Table header has SHA-3 column",
test: () => assert(htmlContent.includes('SHA-3') && htmlContent.includes('FIPS 202'), "Missing 'SHA-3 (FIPS 202)' in table header")
},
{
name: "Table row template has sha3 cell",
test: () => assert(htmlContent.includes('class="hash-font sha3"'), "Missing 'hash-font sha3' in row insertion")
},
{
name: "processQueue integrates CryptoJS.SHA3",
test: () => assert(htmlContent.includes('CryptoJS.SHA3('), "Missing CryptoJS.SHA3 calculation in processQueue")
},
{
name: "Console logging for SHA-3 calculation",
test: () => assert(htmlContent.includes('console.log') && htmlContent.includes('SHA-3'), "Missing console.log for SHA-3 calculation")
},
{
name: "generateHashPDF exports SHA-3",
test: () => assert(htmlContent.includes("'SHA-3'") || htmlContent.includes('"SHA-3"'), "Missing SHA-3 in generateHashPDF table head")
},
{
name: "generateHashWord exports SHA-3",
test: () => assert(htmlContent.includes('text: "SHA-3"'), "Missing SHA-3 in generateHashWord table")
},
{
name: "downloadSelectedCSV exports SHA-3",
test: () => assert(htmlContent.includes('SHA-3\n') || htmlContent.includes(',SHA-3'), "Missing SHA-3 in downloadSelectedCSV header")
}
];

let failed = 0;
checks.forEach(c => {
try {
c.test();
console.log(` ✓ ${c.name}`);
} catch (e) {
console.error(` ✗ FAIL: ${c.name} -> ${e.message}`);
failed++;
}
});

if (failed > 0) {
console.error(`\nTest suite failed with ${failed} missing requirements.`);
process.exit(1);
} else {
console.log("\nAll SHA-3 integration checks passed cleanly!");
process.exit(0);
}