/** * Forensic Utility Functions */ /** * Calculate SHA-256 hash of a string or ArrayBuffer */ export async function calculateHash(data: string | ArrayBuffer): Promise { const msgUint8 = typeof data === 'string' ? new TextEncoder().encode(data) : new Uint8Array(data); const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8); const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); return hashHex; } /** * Calculate Entropy of a string or ArrayBuffer */ export function calculateEntropy(data: string | ArrayBuffer): number { const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : new Uint8Array(data); if (bytes.length === 0) return 0; const frequencies: Record = {}; for (const byte of bytes) { frequencies[byte] = (frequencies[byte] || 0) + 1; } let entropy = 0; for (const count of Object.values(frequencies)) { const p = count / bytes.length; entropy -= p * Math.log2(p); } return entropy; } /** * Extract Magic Bytes (first 16 bytes) */ export function getMagicBytes(data: ArrayBuffer): string { const bytes = new Uint8Array(data.slice(0, 16)); return Array.from(bytes).map(b => b.toString(16).toUpperCase().padStart(2, '0')).join(' '); } /** * Guess file type from Magic Bytes */ export function guessFileTypeFromMagicBytes(magicBytes: string): string | null { const hex = magicBytes.replace(/\s/g, ''); if (hex.startsWith('89504E470D0A1A0A')) return 'image/png'; if (hex.startsWith('FFD8FF')) return 'image/jpeg'; if (hex.startsWith('47494638')) return 'image/gif'; if (hex.startsWith('255044462D')) return 'application/pdf'; if (hex.startsWith('504B0304')) return 'application/zip'; if (hex.startsWith('4D5A')) return 'application/x-msdownload'; // MZ (EXE/DLL) if (hex.startsWith('7F454C46')) return 'application/x-executable'; // ELF if (hex.startsWith('526172211A0700')) return 'application/x-rar-compressed'; if (hex.startsWith('1F8B08')) return 'application/gzip'; if (hex.startsWith('4F676753')) return 'audio/ogg'; if (hex.startsWith('52494646')) return 'audio/wav'; // RIFF if (hex.startsWith('494433')) return 'audio/mpeg'; // ID3 (MP3) return null; } /** * Base64 Decode (Safe) */ export function safeBase64Decode(str: string): string { try { return atob(str); } catch (e) { return 'Invalid Base64'; } } /** * Detect potential AI markers in text */ export function detectAIMarkers(text: string): string[] { const markers: string[] = []; const aiKeywords = [ 'as an ai language model', 'stable diffusion', 'midjourney', 'dall-e', 'generated by ai', 'openai', 'anthropic', 'large language model' ]; const lowerText = text.toLowerCase(); aiKeywords.forEach(keyword => { if (lowerText.includes(keyword)) { markers.push(`AI_KEYWORD_${keyword.toUpperCase().replace(/\s/g, '_')}`); } }); // Check for common AI-generated patterns (very basic) if (text.length > 1000 && (text.match(/\n\n/g) || []).length > 10) { markers.push('PATTERN_HIGH_STRUCTURAL_REGULARITY'); } return markers; } /** * Identify Execution Wrapper / Environment */ export function identifyWrapper(content: string): string { const patterns = [ { name: 'Node.js (CommonJS)', regex: /require\(|module\.exports|process\./ }, { name: 'Node.js (ESM)', regex: /import .* from ['"]node:.*['"]/ }, { name: 'Browser (DOM)', regex: /window\.|document\.|localStorage\.|sessionStorage\./ }, { name: 'React Component', regex: /import .* from ['"]react['"]|useState\(|useEffect\(/ }, { name: 'Deno Runtime', regex: /Deno\./ }, { name: 'Python Script', regex: /if __name__ == ['"]__main__['"]:/ }, { name: 'UMD Wrapper', regex: /typeof define === ['"]function['"] && define\.amd/ }, { name: 'IIFE Wrapper', regex: /^\s*\(function\s*\(/ }, ]; for (const pattern of patterns) { if (pattern.regex.test(content)) return pattern.name; } return 'Generic / Unknown'; } /** * Extract Advanced Metadata from various file types */ export function extractAdvancedMetadata(fileName: string, content: string): Record { const metadata: Record = {}; const ext = fileName.split('.').pop()?.toLowerCase(); // EML / MHT Headers if (ext === 'eml' || ext === 'mht') { const headers = ['From', 'To', 'Subject', 'Date', 'Message-ID', 'Content-Type']; headers.forEach(h => { const regex = new RegExp(`^${h}:\\s*(.*)$`, 'mi'); const match = content.match(regex); if (match) metadata[h] = match[1].trim(); }); } // JSON Analysis if (ext === 'json') { try { const parsed = JSON.parse(content); metadata['Key Count'] = Object.keys(parsed).length; metadata['Is Array'] = Array.isArray(parsed); if (parsed.$schema) metadata['Schema'] = parsed.$schema; } catch (e) { metadata['JSON Error'] = 'Invalid Syntax'; } } // Markdown Analysis if (ext === 'md') { const h1 = content.match(/^#\s+(.*)$/m); if (h1) metadata['Title'] = h1[1].trim(); metadata['Link Count'] = (content.match(/\[.*\]\(.*\)/g) || []).length; } // Code Analysis (JS/TS/PY) if (['js', 'ts', 'jsx', 'tsx', 'mjs', 'cjs', 'msj', 'mcj', 'py'].includes(ext || '')) { const imports = content.match(/import .* from|require\(|from .* import/g); metadata['Import Count'] = imports?.length || 0; const functions = content.match(/function\s+\w+|const\s+\w+\s*=\s*\(|def\s+\w+/g); metadata['Function Count'] = functions?.length || 0; const classes = content.match(/class\s+\w+/g); metadata['Class Count'] = classes?.length || 0; } return metadata; } /** * Deep Syntax Inspection */ export function deepInspectCode(content: string): string[] { const anomalies: string[] = []; // Look for obfuscation markers if (content.includes('eval(')) anomalies.push('DANGEROUS_EVAL_USAGE'); if (content.includes('atob(') || content.includes('btoa(')) anomalies.push('BASE64_TRANSFORM_DETECTED'); if (content.match(/\\x[0-9a-fA-F]{2}/)) anomalies.push('HEX_ESCAPED_STRINGS'); if (content.match(/\\u[0-9a-fA-F]{4}/)) anomalies.push('UNICODE_ESCAPED_STRINGS'); // Look for hidden schemas or large objects if (content.length > 5000 && !content.includes('\n')) anomalies.push('MINIFIED_OR_OBFUSCATED_CORE'); const longStrings = content.match(/['"`][^'"`]{500,}['"`]/g); if (longStrings) anomalies.push('LARGE_EMBEDDED_OBJECTS'); return anomalies; }