diff --git a/README.md b/README.md
index 391486a..45efa38 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# SecureBit.chat v4.02.985 - ECDH + DTLS + SAS
+# SecureBit.chat v4.2.12 - ECDH + DTLS + SAS
diff --git a/dist/app-boot.js b/dist/app-boot.js
index 8e13bd4..0e61ca1 100644
--- a/dist/app-boot.js
+++ b/dist/app-boot.js
@@ -14148,7 +14148,7 @@ Right-click or Ctrl+click to disconnect`,
React.createElement("p", {
key: "subtitle",
className: "text-xs sm:text-sm text-muted hidden sm:block"
- }, "End-to-end freedom v4.02.985")
+ }, "End-to-end freedom v4.2.12")
])
]),
// Status and Controls - Responsive
@@ -14273,7 +14273,7 @@ window.EnhancedMinimalHeader = EnhancedMinimalHeader;
var DownloadApps = () => {
const apps = [
{ id: "web", name: "Web App", subtitle: "Browser Version", icon: "fas fa-globe", platform: "Web", isActive: true, url: "https://securebitchat.github.io/securebit-chat/", color: "green" },
- { id: "windows", name: "Windows", subtitle: "Desktop App", icon: "fab fa-windows", platform: "Desktop", isActive: false, url: "#", color: "blue" },
+ { id: "windows", name: "Windows", subtitle: "Desktop App", icon: "fab fa-windows", platform: "Desktop", isActive: true, url: "https://securebit.chat/download/windows/SecureBit%20Chat%20Setup%204.1.222.exe", color: "blue" },
{ id: "macos", name: "macOS", subtitle: "Desktop App", icon: "fab fa-apple", platform: "Desktop", isActive: false, url: "#", color: "gray" },
{ id: "linux", name: "Linux", subtitle: "Desktop App", icon: "fab fa-linux", platform: "Desktop", isActive: false, url: "#", color: "orange" },
{ id: "ios", name: "iOS", subtitle: "iPhone & iPad", icon: "fab fa-apple", platform: "Mobile", isActive: false, url: "https://apps.apple.com/app/securebit-chat/", color: "blue" },
diff --git a/dist/app-boot.js.map b/dist/app-boot.js.map
index 8277f92..55d7a28 100644
--- a/dist/app-boot.js.map
+++ b/dist/app-boot.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../src/crypto/EnhancedSecureCryptoUtils.js", "../src/transfer/EnhancedSecureFileTransfer.js", "../src/network/EnhancedSecureWebRTCManager.js", "../src/components/ui/SessionTimer.jsx", "../src/components/ui/Header.jsx", "../src/components/ui/DownloadApps.jsx", "../src/components/ui/FileTransfer.jsx", "../src/scripts/app-boot.js"],
- "sourcesContent": ["class EnhancedSecureCryptoUtils {\n\n static _keyMetadata = new WeakMap();\n \n // Initialize secure logging system after class definition\n\n // Utility to sort object keys for deterministic serialization\n static sortObjectKeys(obj) {\n if (typeof obj !== 'object' || obj === null) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map(EnhancedSecureCryptoUtils.sortObjectKeys);\n }\n\n const sortedObj = {};\n Object.keys(obj).sort().forEach(key => {\n sortedObj[key] = EnhancedSecureCryptoUtils.sortObjectKeys(obj[key]);\n });\n return sortedObj;\n }\n\n // Utility to assert CryptoKey type and properties\n static assertCryptoKey(key, expectedName = null, expectedUsages = []) {\n if (!(key instanceof CryptoKey)) throw new Error('Expected CryptoKey');\n if (expectedName && key.algorithm?.name !== expectedName) {\n throw new Error(`Expected algorithm ${expectedName}, got ${key.algorithm?.name}`);\n }\n for (const u of expectedUsages) {\n if (!key.usages || !key.usages.includes(u)) {\n throw new Error(`Missing required key usage: ${u}`);\n }\n }\n }\n // Helper function to convert ArrayBuffer to Base64\n static arrayBufferToBase64(buffer) {\n let binary = '';\n const bytes = new Uint8Array(buffer);\n const len = bytes.byteLength;\n for (let i = 0; i < len; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n }\n\n // Helper function to convert Base64 to ArrayBuffer\n static base64ToArrayBuffer(base64) {\n try {\n // Validate input\n if (typeof base64 !== 'string' || !base64) {\n throw new Error('Invalid base64 input: must be a non-empty string');\n }\n\n // Remove any whitespace and validate base64 format\n const cleanBase64 = base64.trim();\n if (!/^[A-Za-z0-9+/]*={0,2}$/.test(cleanBase64)) {\n throw new Error('Invalid base64 format');\n }\n\n // Handle empty string case\n if (cleanBase64 === '') {\n return new ArrayBuffer(0);\n }\n\n const binaryString = atob(cleanBase64);\n const len = binaryString.length;\n const bytes = new Uint8Array(len);\n for (let i = 0; i < len; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes.buffer;\n } catch (error) {\n console.error('Base64 to ArrayBuffer conversion failed:', error.message);\n throw new Error(`Base64 conversion error: ${error.message}`);\n }\n }\n\n // Helper function to convert hex string to Uint8Array\n static hexToUint8Array(hexString) {\n try {\n if (!hexString || typeof hexString !== 'string') {\n throw new Error('Invalid hex string input: must be a non-empty string');\n }\n\n // Remove colons and spaces from hex string (e.g., \"aa:bb:cc\" -> \"aabbcc\")\n const cleanHex = hexString.replace(/:/g, '').replace(/\\s/g, '');\n \n // Validate hex format\n if (!/^[0-9a-fA-F]*$/.test(cleanHex)) {\n throw new Error('Invalid hex format: contains non-hex characters');\n }\n \n // Ensure even length\n if (cleanHex.length % 2 !== 0) {\n throw new Error('Invalid hex format: odd length');\n }\n\n // Convert hex string to bytes\n const bytes = new Uint8Array(cleanHex.length / 2);\n for (let i = 0; i < cleanHex.length; i += 2) {\n bytes[i / 2] = parseInt(cleanHex.substr(i, 2), 16);\n }\n \n return bytes;\n } catch (error) {\n console.error('Hex to Uint8Array conversion failed:', error.message);\n throw new Error(`Hex conversion error: ${error.message}`);\n }\n }\n\n static async encryptData(data, password) {\n try {\n const dataString = typeof data === 'string' ? data : JSON.stringify(data);\n const salt = crypto.getRandomValues(new Uint8Array(16));\n const encoder = new TextEncoder();\n const passwordBuffer = encoder.encode(password);\n\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n passwordBuffer,\n { name: 'PBKDF2' },\n false,\n ['deriveKey']\n );\n\n const key = await crypto.subtle.deriveKey(\n {\n name: 'PBKDF2',\n salt: salt,\n iterations: 100000,\n hash: 'SHA-256',\n },\n keyMaterial,\n { name: 'AES-GCM', length: 256 },\n false,\n ['encrypt']\n );\n\n const iv = crypto.getRandomValues(new Uint8Array(12));\n const dataBuffer = encoder.encode(dataString);\n const encrypted = await crypto.subtle.encrypt(\n { name: 'AES-GCM', iv: iv },\n key,\n dataBuffer\n );\n\n const encryptedPackage = {\n version: '1.0',\n salt: Array.from(salt),\n iv: Array.from(iv),\n data: Array.from(new Uint8Array(encrypted)),\n timestamp: Date.now(),\n };\n\n const packageString = JSON.stringify(encryptedPackage);\n return EnhancedSecureCryptoUtils.arrayBufferToBase64(new TextEncoder().encode(packageString).buffer);\n\n } catch (error) {\n console.error('Encryption failed:', error.message);\n throw new Error(`Encryption error: ${error.message}`);\n }\n }\n\n static async decryptData(encryptedData, password) {\n try {\n const packageBuffer = EnhancedSecureCryptoUtils.base64ToArrayBuffer(encryptedData);\n const packageString = new TextDecoder().decode(packageBuffer);\n const encryptedPackage = JSON.parse(packageString);\n\n if (!encryptedPackage.version || !encryptedPackage.salt || !encryptedPackage.iv || !encryptedPackage.data) {\n throw new Error('Invalid encrypted data format');\n }\n\n const salt = new Uint8Array(encryptedPackage.salt);\n const iv = new Uint8Array(encryptedPackage.iv);\n const encrypted = new Uint8Array(encryptedPackage.data);\n\n const encoder = new TextEncoder();\n const passwordBuffer = encoder.encode(password);\n\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n passwordBuffer,\n { name: 'PBKDF2' },\n false,\n ['deriveKey']\n );\n\n const key = await crypto.subtle.deriveKey(\n {\n name: 'PBKDF2',\n salt: salt,\n iterations: 100000,\n hash: 'SHA-256'\n },\n keyMaterial,\n { name: 'AES-GCM', length: 256 },\n false,\n ['decrypt']\n );\n\n const decrypted = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv },\n key,\n encrypted\n );\n\n const decryptedString = new TextDecoder().decode(decrypted);\n\n try {\n return JSON.parse(decryptedString);\n } catch {\n return decryptedString;\n }\n\n } catch (error) {\n console.error('Decryption failed:', error.message);\n throw new Error(`Decryption error: ${error.message}`);\n }\n }\n\n \n // Generate secure password for data exchange\n static generateSecurePassword() {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-=[]{}|;:,.<>?';\n const length = 32; \n const randomValues = new Uint32Array(length);\n crypto.getRandomValues(randomValues);\n \n let password = '';\n for (let i = 0; i < length; i++) {\n password += chars[randomValues[i] % chars.length];\n }\n return password;\n }\n\n // Real security level calculation with actual verification\n static async calculateSecurityLevel(securityManager) {\n let score = 0;\n const maxScore = 100; // Fixed: Changed from 110 to 100 for cleaner percentage\n const verificationResults = {};\n \n try {\n // Fallback to basic calculation if securityManager is not fully initialized\n if (!securityManager || !securityManager.securityFeatures) {\n console.warn('Security manager not fully initialized, using fallback calculation');\n return {\n level: 'INITIALIZING',\n score: 0,\n color: 'gray',\n verificationResults: {},\n timestamp: Date.now(),\n details: 'Security system initializing...',\n isRealData: false\n };\n }\n\n // All security features are enabled by default - no session type restrictions\n const sessionType = 'full'; // All features enabled\n const isDemoSession = false; // All features available\n \n // 1. Base encryption verification (20 points) - Available in demo\n try {\n const encryptionResult = await EnhancedSecureCryptoUtils.verifyEncryption(securityManager);\n if (encryptionResult.passed) {\n score += 20;\n verificationResults.verifyEncryption = { passed: true, details: encryptionResult.details, points: 20 };\n } else {\n verificationResults.verifyEncryption = { passed: false, details: encryptionResult.details, points: 0 };\n }\n } catch (error) {\n verificationResults.verifyEncryption = { passed: false, details: `Encryption check failed: ${error.message}`, points: 0 };\n }\n \n // 2. Simple key exchange verification (15 points) - Available in demo\n try {\n const ecdhResult = await EnhancedSecureCryptoUtils.verifyECDHKeyExchange(securityManager);\n if (ecdhResult.passed) {\n score += 15;\n verificationResults.verifyECDHKeyExchange = { passed: true, details: ecdhResult.details, points: 15 };\n } else {\n verificationResults.verifyECDHKeyExchange = { passed: false, details: ecdhResult.details, points: 0 };\n }\n } catch (error) {\n verificationResults.verifyECDHKeyExchange = { passed: false, details: `Key exchange check failed: ${error.message}`, points: 0 };\n }\n \n // 3. Message integrity verification (10 points) - Available in demo\n try {\n const integrityResult = await EnhancedSecureCryptoUtils.verifyMessageIntegrity(securityManager);\n if (integrityResult.passed) {\n score += 10;\n verificationResults.verifyMessageIntegrity = { passed: true, details: integrityResult.details, points: 10 };\n } else {\n verificationResults.verifyMessageIntegrity = { passed: false, details: integrityResult.details, points: 0 };\n }\n } catch (error) {\n verificationResults.verifyMessageIntegrity = { passed: false, details: `Message integrity check failed: ${error.message}`, points: 0 };\n }\n \n // 4. ECDSA signatures verification (15 points) - All features enabled by default\n try {\n const ecdsaResult = await EnhancedSecureCryptoUtils.verifyECDSASignatures(securityManager);\n if (ecdsaResult.passed) {\n score += 15;\n verificationResults.verifyECDSASignatures = { passed: true, details: ecdsaResult.details, points: 15 };\n } else {\n verificationResults.verifyECDSASignatures = { passed: false, details: ecdsaResult.details, points: 0 };\n }\n } catch (error) {\n verificationResults.verifyECDSASignatures = { passed: false, details: `Digital signatures check failed: ${error.message}`, points: 0 };\n }\n \n // 5. Rate limiting verification (5 points) - Available in demo\n try {\n const rateLimitResult = await EnhancedSecureCryptoUtils.verifyRateLimiting(securityManager);\n if (rateLimitResult.passed) {\n score += 5;\n verificationResults.verifyRateLimiting = { passed: true, details: rateLimitResult.details, points: 5 };\n } else {\n verificationResults.verifyRateLimiting = { passed: false, details: rateLimitResult.details, points: 0 };\n }\n } catch (error) {\n verificationResults.verifyRateLimiting = { passed: false, details: `Rate limiting check failed: ${error.message}`, points: 0 };\n }\n \n // 6. Metadata protection verification (10 points) - All features enabled by default\n try {\n const metadataResult = await EnhancedSecureCryptoUtils.verifyMetadataProtection(securityManager);\n if (metadataResult.passed) {\n score += 10;\n verificationResults.verifyMetadataProtection = { passed: true, details: metadataResult.details, points: 10 };\n } else {\n verificationResults.verifyMetadataProtection = { passed: false, details: metadataResult.details, points: 0 };\n }\n } catch (error) {\n verificationResults.verifyMetadataProtection = { passed: false, details: `Metadata protection check failed: ${error.message}`, points: 0 };\n }\n \n // 7. Perfect Forward Secrecy verification (10 points) - All features enabled by default\n try {\n const pfsResult = await EnhancedSecureCryptoUtils.verifyPerfectForwardSecrecy(securityManager);\n if (pfsResult.passed) {\n score += 10;\n verificationResults.verifyPerfectForwardSecrecy = { passed: true, details: pfsResult.details, points: 10 };\n } else {\n verificationResults.verifyPerfectForwardSecrecy = { passed: false, details: pfsResult.details, points: 0 };\n }\n } catch (error) {\n verificationResults.verifyPerfectForwardSecrecy = { passed: false, details: `PFS check failed: ${error.message}`, points: 0 };\n }\n \n // 8. Nested encryption verification (5 points) - All features enabled by default\n if (await EnhancedSecureCryptoUtils.verifyNestedEncryption(securityManager)) {\n score += 5;\n verificationResults.nestedEncryption = { passed: true, details: 'Nested encryption active', points: 5 };\n } else {\n verificationResults.nestedEncryption = { passed: false, details: 'Nested encryption failed', points: 0 };\n }\n \n // 9. Packet padding verification (5 points) - All features enabled by default\n if (await EnhancedSecureCryptoUtils.verifyPacketPadding(securityManager)) {\n score += 5;\n verificationResults.packetPadding = { passed: true, details: 'Packet padding active', points: 5 };\n } else {\n verificationResults.packetPadding = { passed: false, details: 'Packet padding failed', points: 0 };\n }\n \n // 10. Advanced features verification (10 points) - All features enabled by default\n if (await EnhancedSecureCryptoUtils.verifyAdvancedFeatures(securityManager)) {\n score += 10;\n verificationResults.advancedFeatures = { passed: true, details: 'Advanced features active', points: 10 };\n } else {\n verificationResults.advancedFeatures = { passed: false, details: 'Advanced features failed', points: 0 };\n }\n \n const percentage = Math.round((score / maxScore) * 100);\n \n // All security features are available - no restrictions\n const availableChecks = 10; // All 10 security checks available\n const passedChecks = Object.values(verificationResults).filter(r => r.passed).length;\n \n const result = {\n level: percentage >= 85 ? 'HIGH' : percentage >= 65 ? 'MEDIUM' : percentage >= 35 ? 'LOW' : 'CRITICAL',\n score: percentage,\n color: percentage >= 85 ? 'green' : percentage >= 65 ? 'orange' : percentage >= 35 ? 'yellow' : 'red',\n verificationResults,\n timestamp: Date.now(),\n details: `Real verification: ${score}/${maxScore} security checks passed (${passedChecks}/${availableChecks} available)`,\n isRealData: true,\n passedChecks: passedChecks,\n totalChecks: availableChecks,\n sessionType: sessionType,\n maxPossibleScore: 100 // All features enabled - max 100 points\n };\n \n console.log('Real security level calculated:', {\n score: percentage,\n level: result.level,\n passedChecks: passedChecks,\n totalChecks: availableChecks,\n sessionType: sessionType,\n maxPossibleScore: result.maxPossibleScore\n });\n \n return result;\n } catch (error) {\n console.error('Security level calculation failed:', error.message);\n return {\n level: 'UNKNOWN',\n score: 0,\n color: 'red',\n verificationResults: {},\n timestamp: Date.now(),\n details: `Verification failed: ${error.message}`,\n isRealData: false\n };\n }\n }\n\n // Real verification functions\n static async verifyEncryption(securityManager) {\n try {\n if (!securityManager.encryptionKey) {\n return { passed: false, details: 'No encryption key available' };\n }\n \n // Test actual encryption/decryption with multiple data types\n const testCases = [\n 'Test encryption verification',\n '\u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u0442\u0435\u043A\u0441\u0442 \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438',\n 'Special chars: !@#$%^&*()_+-=[]{}|;:,.<>?',\n 'Large data: ' + 'A'.repeat(1000)\n ];\n \n for (const testData of testCases) {\n const encoder = new TextEncoder();\n const testBuffer = encoder.encode(testData);\n const iv = crypto.getRandomValues(new Uint8Array(12));\n \n const encrypted = await crypto.subtle.encrypt(\n { name: 'AES-GCM', iv },\n securityManager.encryptionKey,\n testBuffer\n );\n \n const decrypted = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv },\n securityManager.encryptionKey,\n encrypted\n );\n \n const decryptedText = new TextDecoder().decode(decrypted);\n if (decryptedText !== testData) {\n return { passed: false, details: `Decryption mismatch for: ${testData.substring(0, 20)}...` };\n }\n }\n \n return { passed: true, details: 'AES-GCM encryption/decryption working correctly' };\n } catch (error) {\n console.error('Encryption verification failed:', error.message);\n return { passed: false, details: `Encryption test failed: ${error.message}` };\n }\n }\n \n static async verifyECDHKeyExchange(securityManager) {\n try {\n if (!securityManager.ecdhKeyPair || !securityManager.ecdhKeyPair.privateKey || !securityManager.ecdhKeyPair.publicKey) {\n return { passed: false, details: 'No ECDH key pair available' };\n }\n \n // Test that keys are actually ECDH keys\n const keyType = securityManager.ecdhKeyPair.privateKey.algorithm.name;\n const curve = securityManager.ecdhKeyPair.privateKey.algorithm.namedCurve;\n \n if (keyType !== 'ECDH') {\n return { passed: false, details: `Invalid key type: ${keyType}, expected ECDH` };\n }\n \n if (curve !== 'P-384' && curve !== 'P-256') {\n return { passed: false, details: `Unsupported curve: ${curve}, expected P-384 or P-256` };\n }\n \n // Test key derivation\n try {\n const derivedKey = await crypto.subtle.deriveKey(\n { name: 'ECDH', public: securityManager.ecdhKeyPair.publicKey },\n securityManager.ecdhKeyPair.privateKey,\n { name: 'AES-GCM', length: 256 },\n false,\n ['encrypt', 'decrypt']\n );\n \n if (!derivedKey) {\n return { passed: false, details: 'Key derivation failed' };\n }\n } catch (deriveError) {\n return { passed: false, details: `Key derivation test failed: ${deriveError.message}` };\n }\n \n return { passed: true, details: `ECDH key exchange working with ${curve} curve` };\n } catch (error) {\n console.error('ECDH verification failed:', error.message);\n return { passed: false, details: `ECDH test failed: ${error.message}` };\n }\n }\n \n static async verifyECDSASignatures(securityManager) {\n try {\n if (!securityManager.ecdsaKeyPair || !securityManager.ecdsaKeyPair.privateKey || !securityManager.ecdsaKeyPair.publicKey) {\n return { passed: false, details: 'No ECDSA key pair available' };\n }\n \n // Test actual signing and verification with multiple test cases\n const testCases = [\n 'Test ECDSA signature verification',\n '\u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u0442\u0435\u043A\u0441\u0442 \u0434\u043B\u044F \u043F\u043E\u0434\u043F\u0438\u0441\u0438',\n 'Special chars: !@#$%^&*()_+-=[]{}|;:,.<>?',\n 'Large data: ' + 'B'.repeat(2000)\n ];\n \n for (const testData of testCases) {\n const encoder = new TextEncoder();\n const testBuffer = encoder.encode(testData);\n \n const signature = await crypto.subtle.sign(\n { name: 'ECDSA', hash: 'SHA-256' },\n securityManager.ecdsaKeyPair.privateKey,\n testBuffer\n );\n \n const isValid = await crypto.subtle.verify(\n { name: 'ECDSA', hash: 'SHA-256' },\n securityManager.ecdsaKeyPair.publicKey,\n signature,\n testBuffer\n );\n \n if (!isValid) {\n return { passed: false, details: `Signature verification failed for: ${testData.substring(0, 20)}...` };\n }\n }\n \n return { passed: true, details: 'ECDSA digital signatures working correctly' };\n } catch (error) {\n console.error('ECDSA verification failed:', error.message);\n return { passed: false, details: `ECDSA test failed: ${error.message}` };\n }\n }\n \n static async verifyMessageIntegrity(securityManager) {\n try {\n // Check if macKey exists and is a valid CryptoKey\n if (!securityManager.macKey || !(securityManager.macKey instanceof CryptoKey)) {\n return { passed: false, details: 'MAC key not available or invalid' };\n }\n \n // Test message integrity with HMAC using multiple test cases\n const testCases = [\n 'Test message integrity verification',\n '\u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u0442\u0435\u043A\u0441\u0442 \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u0446\u0435\u043B\u043E\u0441\u0442\u043D\u043E\u0441\u0442\u0438',\n 'Special chars: !@#$%^&*()_+-=[]{}|;:,.<>?',\n 'Large data: ' + 'C'.repeat(3000)\n ];\n \n for (const testData of testCases) {\n const encoder = new TextEncoder();\n const testBuffer = encoder.encode(testData);\n \n const hmac = await crypto.subtle.sign(\n { name: 'HMAC', hash: 'SHA-256' },\n securityManager.macKey,\n testBuffer\n );\n \n const isValid = await crypto.subtle.verify(\n { name: 'HMAC', hash: 'SHA-256' },\n securityManager.macKey,\n hmac,\n testBuffer\n );\n \n if (!isValid) {\n return { passed: false, details: `HMAC verification failed for: ${testData.substring(0, 20)}...` };\n }\n }\n \n return { passed: true, details: 'Message integrity (HMAC) working correctly' };\n } catch (error) {\n console.error('Message integrity verification failed:', error.message);\n return { passed: false, details: `Message integrity test failed: ${error.message}` };\n }\n }\n \n // Additional verification functions\n static async verifyRateLimiting(securityManager) {\n try {\n // Rate limiting is always available in this implementation\n return { passed: true, details: 'Rate limiting is active and working' };\n } catch (error) {\n return { passed: false, details: `Rate limiting test failed: ${error.message}` };\n }\n }\n \n static async verifyMetadataProtection(securityManager) {\n try {\n // Metadata protection is always enabled in this implementation\n return { passed: true, details: 'Metadata protection is working correctly' };\n } catch (error) {\n return { passed: false, details: `Metadata protection test failed: ${error.message}` };\n }\n }\n \n static async verifyPerfectForwardSecrecy(securityManager) {\n try {\n // Perfect Forward Secrecy is always enabled in this implementation\n return { passed: true, details: 'Perfect Forward Secrecy is configured and active' };\n } catch (error) {\n return { passed: false, details: `PFS test failed: ${error.message}` };\n }\n }\n \n static async verifyReplayProtection(securityManager) {\n try {\n console.log('\uD83D\uDD0D verifyReplayProtection debug:');\n console.log(' - securityManager.replayProtection:', securityManager.replayProtection);\n console.log(' - securityManager keys:', Object.keys(securityManager));\n \n // Check if replay protection is enabled\n if (!securityManager.replayProtection) {\n return { passed: false, details: 'Replay protection not enabled' };\n }\n \n return { passed: true, details: 'Replay protection is working correctly' };\n } catch (error) {\n return { passed: false, details: `Replay protection test failed: ${error.message}` };\n }\n }\n \n static async verifyDTLSFingerprint(securityManager) {\n try {\n console.log('\uD83D\uDD0D verifyDTLSFingerprint debug:');\n console.log(' - securityManager.dtlsFingerprint:', securityManager.dtlsFingerprint);\n \n // Check if DTLS fingerprint is available\n if (!securityManager.dtlsFingerprint) {\n return { passed: false, details: 'DTLS fingerprint not available' };\n }\n \n return { passed: true, details: 'DTLS fingerprint is valid and available' };\n } catch (error) {\n return { passed: false, details: `DTLS fingerprint test failed: ${error.message}` };\n }\n }\n \n static async verifySASVerification(securityManager) {\n try {\n console.log('\uD83D\uDD0D verifySASVerification debug:');\n console.log(' - securityManager.sasCode:', securityManager.sasCode);\n \n // Check if SAS code is available\n if (!securityManager.sasCode) {\n return { passed: false, details: 'SAS code not available' };\n }\n \n return { passed: true, details: 'SAS verification code is valid and available' };\n } catch (error) {\n return { passed: false, details: `SAS verification test failed: ${error.message}` };\n }\n }\n \n static async verifyTrafficObfuscation(securityManager) {\n try {\n console.log('\uD83D\uDD0D verifyTrafficObfuscation debug:');\n console.log(' - securityManager.trafficObfuscation:', securityManager.trafficObfuscation);\n \n // Check if traffic obfuscation is enabled\n if (!securityManager.trafficObfuscation) {\n return { passed: false, details: 'Traffic obfuscation not enabled' };\n }\n \n return { passed: true, details: 'Traffic obfuscation is working correctly' };\n } catch (error) {\n return { passed: false, details: `Traffic obfuscation test failed: ${error.message}` };\n }\n }\n \n static async verifyNestedEncryption(securityManager) {\n try {\n // Check if nestedEncryptionKey exists and is a valid CryptoKey\n if (!securityManager.nestedEncryptionKey || !(securityManager.nestedEncryptionKey instanceof CryptoKey)) {\n console.warn('Nested encryption key not available or invalid');\n return false;\n }\n \n // Test nested encryption\n const testData = 'Test nested encryption verification';\n const encoder = new TextEncoder();\n const testBuffer = encoder.encode(testData);\n \n // Simulate nested encryption\n const encrypted = await crypto.subtle.encrypt(\n { name: 'AES-GCM', iv: crypto.getRandomValues(new Uint8Array(12)) },\n securityManager.nestedEncryptionKey,\n testBuffer\n );\n \n return encrypted && encrypted.byteLength > 0;\n } catch (error) {\n console.error('Nested encryption verification failed:', error.message);\n return false;\n }\n }\n \n static async verifyPacketPadding(securityManager) {\n try {\n if (!securityManager.paddingConfig || !securityManager.paddingConfig.enabled) return false;\n \n // Test packet padding functionality\n const testData = 'Test packet padding verification';\n const encoder = new TextEncoder();\n const testBuffer = encoder.encode(testData);\n \n // Simulate packet padding\n const paddingSize = Math.floor(Math.random() * (securityManager.paddingConfig.maxPadding - securityManager.paddingConfig.minPadding)) + securityManager.paddingConfig.minPadding;\n const paddedData = new Uint8Array(testBuffer.byteLength + paddingSize);\n paddedData.set(new Uint8Array(testBuffer), 0);\n \n return paddedData.byteLength >= testBuffer.byteLength + securityManager.paddingConfig.minPadding;\n } catch (error) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Packet padding verification failed', { error: error.message });\n return false;\n }\n }\n \n static async verifyAdvancedFeatures(securityManager) {\n try {\n // Test advanced features like traffic obfuscation, fake traffic, etc.\n const hasFakeTraffic = securityManager.fakeTrafficConfig && securityManager.fakeTrafficConfig.enabled;\n const hasDecoyChannels = securityManager.decoyChannelsConfig && securityManager.decoyChannelsConfig.enabled;\n const hasAntiFingerprinting = securityManager.antiFingerprintingConfig && securityManager.antiFingerprintingConfig.enabled;\n \n return hasFakeTraffic || hasDecoyChannels || hasAntiFingerprinting;\n } catch (error) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Advanced features verification failed', { error: error.message });\n return false;\n }\n }\n \n static async verifyMutualAuth(securityManager) {\n try {\n if (!securityManager.isVerified || !securityManager.verificationCode) return false;\n \n // Test mutual authentication\n return securityManager.isVerified && securityManager.verificationCode.length > 0;\n } catch (error) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Mutual auth verification failed', { error: error.message });\n return false;\n }\n }\n \n \n static async verifyNonExtractableKeys(securityManager) {\n try {\n if (!securityManager.encryptionKey) return false;\n \n // Test if keys are non-extractable\n const keyData = await crypto.subtle.exportKey('raw', securityManager.encryptionKey);\n return keyData && keyData.byteLength > 0;\n } catch (error) {\n // If export fails, keys are non-extractable (which is good)\n return true;\n }\n }\n \n static async verifyEnhancedValidation(securityManager) {\n try {\n if (!securityManager.securityFeatures) return false;\n \n // Test enhanced validation features\n const hasValidation = securityManager.securityFeatures.hasEnhancedValidation || \n securityManager.securityFeatures.hasEnhancedReplayProtection;\n \n return hasValidation;\n } catch (error) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Enhanced validation verification failed', { error: error.message });\n return false;\n }\n }\n \n \n static async verifyPFS(securityManager) {\n try {\n // Check if PFS is active\n return securityManager.securityFeatures &&\n securityManager.securityFeatures.hasPFS === true &&\n securityManager.keyRotationInterval &&\n securityManager.currentKeyVersion !== undefined &&\n securityManager.keyVersions &&\n securityManager.keyVersions instanceof Map;\n } catch (error) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'PFS verification failed', { error: error.message });\n return false;\n }\n }\n\n // Rate limiting implementation\n static rateLimiter = {\n messages: new Map(),\n connections: new Map(),\n locks: new Map(),\n \n async checkMessageRate(identifier, limit = 60, windowMs = 60000) {\n if (typeof identifier !== 'string' || identifier.length > 256) {\n return false;\n }\n \n const key = `msg_${identifier}`;\n\n if (this.locks.has(key)) {\n\n await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 10) + 5));\n return this.checkMessageRate(identifier, limit, windowMs);\n }\n \n this.locks.set(key, true);\n \n try {\n const now = Date.now();\n \n if (!this.messages.has(key)) {\n this.messages.set(key, []);\n }\n \n const timestamps = this.messages.get(key);\n \n const validTimestamps = timestamps.filter(ts => now - ts < windowMs);\n \n if (validTimestamps.length >= limit) {\n return false; \n }\n \n validTimestamps.push(now);\n this.messages.set(key, validTimestamps);\n return true;\n } finally {\n this.locks.delete(key);\n }\n },\n \n async checkConnectionRate(identifier, limit = 5, windowMs = 300000) {\n if (typeof identifier !== 'string' || identifier.length > 256) {\n return false;\n }\n \n const key = `conn_${identifier}`;\n \n if (this.locks.has(key)) {\n await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 10) + 5));\n return this.checkConnectionRate(identifier, limit, windowMs);\n }\n \n this.locks.set(key, true);\n \n try {\n const now = Date.now();\n \n if (!this.connections.has(key)) {\n this.connections.set(key, []);\n }\n \n const timestamps = this.connections.get(key);\n const validTimestamps = timestamps.filter(ts => now - ts < windowMs);\n \n if (validTimestamps.length >= limit) {\n return false;\n }\n \n validTimestamps.push(now);\n this.connections.set(key, validTimestamps);\n return true;\n } finally {\n this.locks.delete(key);\n }\n },\n \n cleanup() {\n const now = Date.now();\n const maxAge = 3600000; \n \n for (const [key, timestamps] of this.messages.entries()) {\n if (this.locks.has(key)) continue;\n \n const valid = timestamps.filter(ts => now - ts < maxAge);\n if (valid.length === 0) {\n this.messages.delete(key);\n } else {\n this.messages.set(key, valid);\n }\n }\n \n for (const [key, timestamps] of this.connections.entries()) {\n if (this.locks.has(key)) continue;\n \n const valid = timestamps.filter(ts => now - ts < maxAge);\n if (valid.length === 0) {\n this.connections.delete(key);\n } else {\n this.connections.set(key, valid);\n }\n }\n\n for (const lockKey of this.locks.keys()) {\n const keyTimestamp = parseInt(lockKey.split('_').pop()) || 0;\n if (now - keyTimestamp > 30000) {\n this.locks.delete(lockKey);\n }\n }\n }\n};\n\n static validateSalt(salt) {\n if (!salt || salt.length !== 64) {\n throw new Error('Salt must be exactly 64 bytes');\n }\n \n const uniqueBytes = new Set(salt);\n if (uniqueBytes.size < 16) {\n throw new Error('Salt has insufficient entropy');\n }\n \n return true;\n }\n\n // Secure logging without data leaks\n static secureLog = {\n logs: [],\n maxLogs: 100,\n isProductionMode: false,\n \n // Initialize production mode detection\n init() {\n this.isProductionMode = this._detectProductionMode();\n if (this.isProductionMode) {\n console.log('[SecureChat] Production mode detected - sensitive logging disabled');\n }\n },\n \n _detectProductionMode() {\n return (\n (typeof process !== 'undefined' && process.env?.NODE_ENV === 'production') ||\n (!window.DEBUG_MODE && !window.DEVELOPMENT_MODE) ||\n (window.location.hostname && !window.location.hostname.includes('localhost') && \n !window.location.hostname.includes('127.0.0.1') && \n !window.location.hostname.includes('.local')) ||\n (typeof window.webpackHotUpdate === 'undefined' && !window.location.search.includes('debug'))\n );\n },\n \n log(level, message, context = {}) {\n const sanitizedContext = this.sanitizeContext(context);\n const logEntry = {\n timestamp: Date.now(),\n level,\n message,\n context: sanitizedContext,\n id: crypto.getRandomValues(new Uint32Array(1))[0]\n };\n \n this.logs.push(logEntry);\n \n // Keep only recent logs\n if (this.logs.length > this.maxLogs) {\n this.logs = this.logs.slice(-this.maxLogs);\n }\n \n // Production-safe console output\n if (this.isProductionMode) {\n if (level === 'error') {\n // \u0412 production \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u043C \u0442\u043E\u043B\u044C\u043A\u043E \u043A\u043E\u0434 \u043E\u0448\u0438\u0431\u043A\u0438 \u0431\u0435\u0437 \u0434\u0435\u0442\u0430\u043B\u0435\u0439\n console.error(`\u274C [SecureChat] ${message} [ERROR_CODE: ${this._generateErrorCode(message)}]`);\n } else if (level === 'warn') {\n // \u0412 production \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u043C \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0440\u0435\u0434\u0443\u043F\u0440\u0435\u0436\u0434\u0435\u043D\u0438\u0435 \u0431\u0435\u0437 \u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442\u0430\n console.warn(`\u26A0\uFE0F [SecureChat] ${message}`);\n } else {\n // \u0412 production \u043D\u0435 \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u043C info/debug \u043B\u043E\u0433\u0438\n return;\n }\n } else {\n // Development mode - \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u043C \u0432\u0441\u0435\n if (level === 'error') {\n console.error(`\u274C [SecureChat] ${message}`, { errorType: sanitizedContext?.constructor?.name || 'Unknown' });\n } else if (level === 'warn') {\n console.warn(`\u26A0\uFE0F [SecureChat] ${message}`, { details: sanitizedContext });\n } else {\n console.log(`[SecureChat] ${message}`, sanitizedContext);\n }\n }\n },\n \n // \u0413\u0435\u043D\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0431\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u044B\u0439 \u043A\u043E\u0434 \u043E\u0448\u0438\u0431\u043A\u0438 \u0434\u043B\u044F production\n _generateErrorCode(message) {\n const hash = message.split('').reduce((a, b) => {\n a = ((a << 5) - a) + b.charCodeAt(0);\n return a & a;\n }, 0);\n return Math.abs(hash).toString(36).substring(0, 6).toUpperCase();\n },\n \n sanitizeContext(context) {\n if (!context || typeof context !== 'object') {\n return context;\n }\n \n const sensitivePatterns = [\n /key/i, /secret/i, /password/i, /token/i, /signature/i,\n /challenge/i, /proof/i, /salt/i, /iv/i, /nonce/i, /hash/i,\n /fingerprint/i, /mac/i, /private/i, /encryption/i, /decryption/i\n ];\n \n const sanitized = {};\n for (const [key, value] of Object.entries(context)) {\n const isSensitive = sensitivePatterns.some(pattern => \n pattern.test(key) || (typeof value === 'string' && pattern.test(value))\n );\n \n if (isSensitive) {\n sanitized[key] = '[REDACTED]';\n } else if (typeof value === 'string' && value.length > 100) {\n sanitized[key] = value.substring(0, 100) + '...[TRUNCATED]';\n } else if (value instanceof ArrayBuffer || value instanceof Uint8Array) {\n sanitized[key] = `[${value.constructor.name}(${value.byteLength || value.length} bytes)]`;\n } else if (value && typeof value === 'object' && !Array.isArray(value)) {\n // \u0420\u0435\u043A\u0443\u0440\u0441\u0438\u0432\u043D\u0430\u044F \u0441\u0430\u043D\u0438\u0442\u0438\u0437\u0430\u0446\u0438\u044F \u0434\u043B\u044F \u043E\u0431\u044A\u0435\u043A\u0442\u043E\u0432\n sanitized[key] = this.sanitizeContext(value);\n } else {\n sanitized[key] = value;\n }\n }\n return sanitized;\n },\n \n getLogs(level = null) {\n if (level) {\n return this.logs.filter(log => log.level === level);\n }\n return [...this.logs];\n },\n \n clearLogs() {\n this.logs = [];\n },\n \n // \u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0438 \u043E\u0448\u0438\u0431\u043E\u043A \u043D\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0432 production\n async sendErrorToServer(errorCode, message, context = {}) {\n if (!this.isProductionMode) {\n return; // \u0412 development \u043D\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u044F\u0435\u043C\n }\n \n try {\n // \u041E\u0442\u043F\u0440\u0430\u0432\u043B\u044F\u0435\u043C \u0442\u043E\u043B\u044C\u043A\u043E \u0431\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u0443\u044E \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044E\n const safeErrorData = {\n errorCode,\n timestamp: Date.now(),\n userAgent: navigator.userAgent.substring(0, 100),\n url: window.location.href.substring(0, 100)\n };\n \n // \u0417\u0434\u0435\u0441\u044C \u043C\u043E\u0436\u043D\u043E \u0434\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0443 \u043D\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\n // await fetch('/api/error-log', { method: 'POST', body: JSON.stringify(safeErrorData) });\n \n if (window.DEBUG_MODE) {\n console.log('[SecureChat] Error logged to server:', safeErrorData);\n }\n } catch (e) {\n // \u041D\u0435 \u043B\u043E\u0433\u0438\u0440\u0443\u0435\u043C \u043E\u0448\u0438\u0431\u043A\u0438 \u043B\u043E\u0433\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F\n }\n }\n };\n\n // Generate ECDH key pair for secure key exchange (non-extractable) with fallback\n static async generateECDHKeyPair() {\n try {\n // Try P-384 first\n try {\n const keyPair = await crypto.subtle.generateKey(\n {\n name: 'ECDH',\n namedCurve: 'P-384'\n },\n false, // Non-extractable for enhanced security\n ['deriveKey']\n );\n \n EnhancedSecureCryptoUtils.secureLog.log('info', 'ECDH key pair generated successfully (P-384)', {\n curve: 'P-384',\n extractable: false\n });\n \n return keyPair;\n } catch (p384Error) {\n EnhancedSecureCryptoUtils.secureLog.log('warn', 'P-384 generation failed, trying P-256', { error: p384Error.message });\n \n // Fallback to P-256\n const keyPair = await crypto.subtle.generateKey(\n {\n name: 'ECDH',\n namedCurve: 'P-256'\n },\n false, // Non-extractable for enhanced security\n ['deriveKey']\n );\n \n EnhancedSecureCryptoUtils.secureLog.log('info', 'ECDH key pair generated successfully (P-256 fallback)', {\n curve: 'P-256',\n extractable: false\n });\n \n return keyPair;\n }\n } catch (error) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'ECDH key generation failed', { error: error.message });\n throw new Error('Failed to create keys for secure exchange');\n }\n }\n\n // Generate ECDSA key pair for digital signatures with fallback\n static async generateECDSAKeyPair() {\n try {\n // Try P-384 first\n try {\n const keyPair = await crypto.subtle.generateKey(\n {\n name: 'ECDSA',\n namedCurve: 'P-384'\n },\n false, // Non-extractable for enhanced security\n ['sign', 'verify']\n );\n \n EnhancedSecureCryptoUtils.secureLog.log('info', 'ECDSA key pair generated successfully (P-384)', {\n curve: 'P-384',\n extractable: false\n });\n \n return keyPair;\n } catch (p384Error) {\n EnhancedSecureCryptoUtils.secureLog.log('warn', 'P-384 generation failed, trying P-256', { error: p384Error.message });\n \n // Fallback to P-256\n const keyPair = await crypto.subtle.generateKey(\n {\n name: 'ECDSA',\n namedCurve: 'P-256'\n },\n false, // Non-extractable for enhanced security\n ['sign', 'verify']\n );\n \n EnhancedSecureCryptoUtils.secureLog.log('info', 'ECDSA key pair generated successfully (P-256 fallback)', {\n curve: 'P-256',\n extractable: false\n });\n \n return keyPair;\n }\n } catch (error) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'ECDSA key generation failed', { error: error.message });\n throw new Error('Failed to generate keys for digital signatures');\n }\n }\n\n // Sign data with ECDSA (P-384 or P-256)\n static async signData(privateKey, data) {\n try {\n const encoder = new TextEncoder();\n const dataBuffer = typeof data === 'string' ? encoder.encode(data) : data;\n \n // Try SHA-384 first, fallback to SHA-256\n try {\n const signature = await crypto.subtle.sign(\n {\n name: 'ECDSA',\n hash: 'SHA-384'\n },\n privateKey,\n dataBuffer\n );\n \n return Array.from(new Uint8Array(signature));\n } catch (sha384Error) {\n EnhancedSecureCryptoUtils.secureLog.log('warn', 'SHA-384 signing failed, trying SHA-256', { error: sha384Error.message });\n \n const signature = await crypto.subtle.sign(\n {\n name: 'ECDSA',\n hash: 'SHA-256'\n },\n privateKey,\n dataBuffer\n );\n \n return Array.from(new Uint8Array(signature));\n }\n } catch (error) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Data signing failed', { error: error.message });\n throw new Error('Failed to sign data');\n }\n }\n\n // Verify ECDSA signature (P-384 or P-256)\n static async verifySignature(publicKey, signature, data) {\n try {\n const encoder = new TextEncoder();\n const dataBuffer = typeof data === 'string' ? encoder.encode(data) : data;\n const signatureBuffer = new Uint8Array(signature);\n \n // Try SHA-384 first, fallback to SHA-256\n try {\n const isValid = await crypto.subtle.verify(\n {\n name: 'ECDSA',\n hash: 'SHA-384'\n },\n publicKey,\n signatureBuffer,\n dataBuffer\n );\n \n EnhancedSecureCryptoUtils.secureLog.log('info', 'Signature verification completed (SHA-384)', {\n isValid,\n dataSize: dataBuffer.length\n });\n \n return isValid;\n } catch (sha384Error) {\n EnhancedSecureCryptoUtils.secureLog.log('warn', 'SHA-384 verification failed, trying SHA-256', { error: sha384Error.message });\n \n const isValid = await crypto.subtle.verify(\n {\n name: 'ECDSA',\n hash: 'SHA-256'\n },\n publicKey,\n signatureBuffer,\n dataBuffer\n );\n \n EnhancedSecureCryptoUtils.secureLog.log('info', 'Signature verification completed (SHA-256 fallback)', {\n isValid,\n dataSize: dataBuffer.length\n });\n \n return isValid;\n }\n } catch (error) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Signature verification failed', { error: error.message });\n throw new Error('Failed to verify digital signature');\n }\n }\n\n // Enhanced DER/SPKI validation with full ASN.1 parsing\n static async validateKeyStructure(keyData, expectedAlgorithm = 'ECDH') {\n try {\n if (!Array.isArray(keyData) || keyData.length === 0) {\n throw new Error('Invalid key data format');\n }\n\n const keyBytes = new Uint8Array(keyData);\n\n // Size limits to prevent DoS\n if (keyBytes.length < 50) {\n throw new Error('Key data too short - invalid SPKI structure');\n }\n if (keyBytes.length > 2000) {\n throw new Error('Key data too long - possible attack');\n }\n\n // Parse ASN.1 DER structure\n const asn1 = EnhancedSecureCryptoUtils.parseASN1(keyBytes);\n \n // Validate SPKI structure\n if (!asn1 || asn1.tag !== 0x30) {\n throw new Error('Invalid SPKI structure - missing SEQUENCE tag');\n }\n\n // SPKI should have exactly 2 elements: AlgorithmIdentifier and BIT STRING\n if (asn1.children.length !== 2) {\n throw new Error(`Invalid SPKI structure - expected 2 elements, got ${asn1.children.length}`);\n }\n\n // Validate AlgorithmIdentifier\n const algIdentifier = asn1.children[0];\n if (algIdentifier.tag !== 0x30) {\n throw new Error('Invalid AlgorithmIdentifier - not a SEQUENCE');\n }\n\n // Parse algorithm OID\n const algOid = algIdentifier.children[0];\n if (algOid.tag !== 0x06) {\n throw new Error('Invalid algorithm OID - not an OBJECT IDENTIFIER');\n }\n\n // Validate algorithm OID based on expected algorithm\n const oidBytes = algOid.value;\n const oidString = EnhancedSecureCryptoUtils.oidToString(oidBytes);\n \n // Check for expected algorithms\n const validAlgorithms = {\n 'ECDH': ['1.2.840.10045.2.1'], // id-ecPublicKey\n 'ECDSA': ['1.2.840.10045.2.1'], // id-ecPublicKey (same as ECDH)\n 'RSA': ['1.2.840.113549.1.1.1'], // rsaEncryption\n 'AES-GCM': ['2.16.840.1.101.3.4.1.6', '2.16.840.1.101.3.4.1.46'] // AES-128-GCM, AES-256-GCM\n };\n\n const expectedOids = validAlgorithms[expectedAlgorithm];\n if (!expectedOids) {\n throw new Error(`Unknown algorithm: ${expectedAlgorithm}`);\n }\n\n if (!expectedOids.includes(oidString)) {\n throw new Error(`Invalid algorithm OID: expected ${expectedOids.join(' or ')}, got ${oidString}`);\n }\n\n // For EC algorithms, validate curve parameters\n if (expectedAlgorithm === 'ECDH' || expectedAlgorithm === 'ECDSA') {\n if (algIdentifier.children.length < 2) {\n throw new Error('Missing curve parameters for EC key');\n }\n\n const curveOid = algIdentifier.children[1];\n if (curveOid.tag !== 0x06) {\n throw new Error('Invalid curve OID - not an OBJECT IDENTIFIER');\n }\n\n const curveOidString = EnhancedSecureCryptoUtils.oidToString(curveOid.value);\n \n // Only allow P-256 and P-384 curves\n const validCurves = {\n '1.2.840.10045.3.1.7': 'P-256', // secp256r1\n '1.3.132.0.34': 'P-384' // secp384r1\n };\n\n if (!validCurves[curveOidString]) {\n throw new Error(`Invalid or unsupported curve OID: ${curveOidString}`);\n }\n\n EnhancedSecureCryptoUtils.secureLog.log('info', 'EC key curve validated', {\n curve: validCurves[curveOidString],\n oid: curveOidString\n });\n }\n\n // Validate public key BIT STRING\n const publicKeyBitString = asn1.children[1];\n if (publicKeyBitString.tag !== 0x03) {\n throw new Error('Invalid public key - not a BIT STRING');\n }\n\n // Check for unused bits (should be 0 for public keys)\n if (publicKeyBitString.value[0] !== 0x00) {\n throw new Error(`Invalid BIT STRING - unexpected unused bits: ${publicKeyBitString.value[0]}`);\n }\n\n // For EC keys, validate point format\n if (expectedAlgorithm === 'ECDH' || expectedAlgorithm === 'ECDSA') {\n const pointData = publicKeyBitString.value.slice(1); // Skip unused bits byte\n \n // Check for uncompressed point format (0x04)\n if (pointData[0] !== 0x04) {\n throw new Error(`Invalid EC point format: expected uncompressed (0x04), got 0x${pointData[0].toString(16)}`);\n }\n\n // Validate point size based on curve\n const expectedSizes = {\n 'P-256': 65, // 1 + 32 + 32\n 'P-384': 97 // 1 + 48 + 48\n };\n\n // We already validated the curve above, so we can determine expected size\n const curveOidString = EnhancedSecureCryptoUtils.oidToString(algIdentifier.children[1].value);\n const curveName = curveOidString === '1.2.840.10045.3.1.7' ? 'P-256' : 'P-384';\n const expectedSize = expectedSizes[curveName];\n\n if (pointData.length !== expectedSize) {\n throw new Error(`Invalid EC point size for ${curveName}: expected ${expectedSize}, got ${pointData.length}`);\n }\n }\n\n // Additional validation: try to import the key\n try {\n const algorithm = expectedAlgorithm === 'ECDSA' || expectedAlgorithm === 'ECDH'\n ? { name: expectedAlgorithm, namedCurve: 'P-384' }\n : { name: expectedAlgorithm };\n\n const usages = expectedAlgorithm === 'ECDSA' ? ['verify'] : [];\n \n await crypto.subtle.importKey('spki', keyBytes.buffer, algorithm, false, usages);\n } catch (importError) {\n // Try P-256 as fallback for EC keys\n if (expectedAlgorithm === 'ECDSA' || expectedAlgorithm === 'ECDH') {\n try {\n const algorithm = { name: expectedAlgorithm, namedCurve: 'P-256' };\n const usages = expectedAlgorithm === 'ECDSA' ? ['verify'] : [];\n await crypto.subtle.importKey('spki', keyBytes.buffer, algorithm, false, usages);\n } catch (fallbackError) {\n throw new Error(`Key import validation failed: ${fallbackError.message}`);\n }\n } else {\n throw new Error(`Key import validation failed: ${importError.message}`);\n }\n }\n\n EnhancedSecureCryptoUtils.secureLog.log('info', 'Key structure validation passed', {\n keyLen: keyBytes.length,\n algorithm: expectedAlgorithm,\n asn1Valid: true,\n oidValid: true,\n importValid: true\n });\n\n return true;\n } catch (err) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Key structure validation failed', {\n error: err.message,\n algorithm: expectedAlgorithm\n });\n throw new Error(`Invalid key structure: ${err.message}`);\n }\n }\n\n // ASN.1 DER parser helper\n static parseASN1(bytes, offset = 0) {\n if (offset >= bytes.length) {\n return null;\n }\n\n const tag = bytes[offset];\n let lengthOffset = offset + 1;\n \n if (lengthOffset >= bytes.length) {\n throw new Error('Truncated ASN.1 structure');\n }\n\n let length = bytes[lengthOffset];\n let valueOffset = lengthOffset + 1;\n\n // Handle long form length\n if (length & 0x80) {\n const numLengthBytes = length & 0x7f;\n if (numLengthBytes > 4) {\n throw new Error('ASN.1 length too large');\n }\n \n length = 0;\n for (let i = 0; i < numLengthBytes; i++) {\n if (valueOffset + i >= bytes.length) {\n throw new Error('Truncated ASN.1 length');\n }\n length = (length << 8) | bytes[valueOffset + i];\n }\n valueOffset += numLengthBytes;\n }\n\n if (valueOffset + length > bytes.length) {\n throw new Error('ASN.1 structure extends beyond data');\n }\n\n const value = bytes.slice(valueOffset, valueOffset + length);\n const node = {\n tag: tag,\n length: length,\n value: value,\n children: []\n };\n\n // Parse children for SEQUENCE and SET\n if (tag === 0x30 || tag === 0x31) {\n let childOffset = 0;\n while (childOffset < value.length) {\n const child = EnhancedSecureCryptoUtils.parseASN1(value, childOffset);\n if (!child) break;\n node.children.push(child);\n childOffset = childOffset + 1 + child.lengthBytes + child.length;\n }\n }\n\n // Calculate how many bytes were used for length encoding\n node.lengthBytes = valueOffset - lengthOffset;\n \n return node;\n }\n\n // OID decoder helper\n static oidToString(bytes) {\n if (!bytes || bytes.length === 0) {\n throw new Error('Empty OID');\n }\n\n const parts = [];\n \n // First byte encodes first two components\n const first = Math.floor(bytes[0] / 40);\n const second = bytes[0] % 40;\n parts.push(first);\n parts.push(second);\n\n // Decode remaining components\n let value = 0;\n for (let i = 1; i < bytes.length; i++) {\n value = (value << 7) | (bytes[i] & 0x7f);\n if (!(bytes[i] & 0x80)) {\n parts.push(value);\n value = 0;\n }\n }\n\n return parts.join('.');\n }\n\n // Helper to validate and sanitize OID string\n static validateOidString(oidString) {\n // OID format: digits separated by dots\n const oidRegex = /^[0-9]+(\\.[0-9]+)*$/;\n if (!oidRegex.test(oidString)) {\n throw new Error(`Invalid OID format: ${oidString}`);\n }\n\n const parts = oidString.split('.').map(Number);\n \n // First component must be 0, 1, or 2\n if (parts[0] > 2) {\n throw new Error(`Invalid OID first component: ${parts[0]}`);\n }\n\n // If first component is 0 or 1, second must be <= 39\n if ((parts[0] === 0 || parts[0] === 1) && parts[1] > 39) {\n throw new Error(`Invalid OID second component: ${parts[1]} (must be <= 39 for first component ${parts[0]})`);\n }\n\n return true;\n }\n\n // Export public key for transmission with signature \n static async exportPublicKeyWithSignature(publicKey, signingKey, keyType = 'ECDH') {\n try {\n // Validate key type\n if (!['ECDH', 'ECDSA'].includes(keyType)) {\n throw new Error('Invalid key type');\n }\n \n const exported = await crypto.subtle.exportKey('spki', publicKey);\n const keyData = Array.from(new Uint8Array(exported));\n \n await EnhancedSecureCryptoUtils.validateKeyStructure(keyData, keyType);\n \n // Create signed key package\n const keyPackage = {\n keyType,\n keyData,\n timestamp: Date.now(),\n version: '4.0'\n };\n \n // Sign the key package\n const packageString = JSON.stringify(keyPackage);\n const signature = await EnhancedSecureCryptoUtils.signData(signingKey, packageString);\n \n const signedPackage = {\n ...keyPackage,\n signature\n };\n \n EnhancedSecureCryptoUtils.secureLog.log('info', 'Public key exported with signature', {\n keyType,\n keySize: keyData.length,\n signed: true\n });\n \n return signedPackage;\n } catch (error) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Public key export failed', {\n error: error.message,\n keyType\n });\n throw new Error(`Failed to export ${keyType} key: ${error.message}`);\n }\n }\n\n // Import and verify signed public key\n static async importSignedPublicKey(signedPackage, verifyingKey, expectedKeyType = 'ECDH') {\n try {\n // Validate package structure\n if (!signedPackage || typeof signedPackage !== 'object') {\n throw new Error('Invalid signed package format');\n }\n \n const { keyType, keyData, timestamp, version, signature } = signedPackage;\n \n if (!keyType || !keyData || !timestamp || !signature) {\n throw new Error('Missing required fields in signed package');\n }\n \n if (!EnhancedSecureCryptoUtils.constantTimeCompare(keyType, expectedKeyType)) {\n throw new Error(`Key type mismatch: expected ${expectedKeyType}, got ${keyType}`);\n }\n \n // Check timestamp (reject keys older than 1 hour)\n const keyAge = Date.now() - timestamp;\n if (keyAge > 3600000) {\n throw new Error('Signed key package is too old');\n }\n \n await EnhancedSecureCryptoUtils.validateKeyStructure(keyData, keyType);\n \n // Verify signature\n const packageCopy = { keyType, keyData, timestamp, version };\n const packageString = JSON.stringify(packageCopy);\n const isValidSignature = await EnhancedSecureCryptoUtils.verifySignature(verifyingKey, signature, packageString);\n \n if (!isValidSignature) {\n throw new Error('Invalid signature on key package - possible MITM attack');\n }\n \n // Import the key with fallback support\n const keyBytes = new Uint8Array(keyData);\n \n // Try P-384 first\n try {\n const algorithm = keyType === 'ECDH' ?\n { name: 'ECDH', namedCurve: 'P-384' }\n : { name: 'ECDSA', namedCurve: 'P-384' };\n \n const keyUsages = keyType === 'ECDH' ? [] : ['verify'];\n \n const publicKey = await crypto.subtle.importKey(\n 'spki',\n keyBytes,\n algorithm,\n false, // Non-extractable\n keyUsages\n );\n \n EnhancedSecureCryptoUtils.secureLog.log('info', 'Signed public key imported successfully (P-384)', {\n keyType,\n signatureValid: true,\n keyAge: Math.round(keyAge / 1000) + 's'\n });\n \n return publicKey;\n } catch (p384Error) {\n // Fallback to P-256\n EnhancedSecureCryptoUtils.secureLog.log('warn', 'P-384 import failed, trying P-256', {\n error: p384Error.message\n });\n \n const algorithm = keyType === 'ECDH' ?\n { name: 'ECDH', namedCurve: 'P-256' }\n : { name: 'ECDSA', namedCurve: 'P-256' };\n \n const keyUsages = keyType === 'ECDH' ? [] : ['verify'];\n \n const publicKey = await crypto.subtle.importKey(\n 'spki',\n keyBytes,\n algorithm,\n false, // Non-extractable\n keyUsages\n );\n \n EnhancedSecureCryptoUtils.secureLog.log('info', 'Signed public key imported successfully (P-256 fallback)', {\n keyType,\n signatureValid: true,\n keyAge: Math.round(keyAge / 1000) + 's'\n });\n \n return publicKey;\n }\n } catch (error) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Signed public key import failed', {\n error: error.message,\n expectedKeyType\n });\n throw new Error(`Failed to import the signed key: ${error.message}`);\n }\n }\n\n // Legacy export for backward compatibility\n static async exportPublicKey(publicKey) {\n try {\n const exported = await crypto.subtle.exportKey('spki', publicKey);\n const keyData = Array.from(new Uint8Array(exported));\n \n await EnhancedSecureCryptoUtils.validateKeyStructure(keyData, 'ECDH');\n \n EnhancedSecureCryptoUtils.secureLog.log('info', 'Legacy public key exported', { keySize: keyData.length });\n return keyData;\n } catch (error) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Legacy public key export failed', { error: error.message });\n throw new Error('Failed to export the public key');\n }\n }\n\n // Legacy import for backward compatibility with fallback\n static async importPublicKey(keyData) {\n try {\n await EnhancedSecureCryptoUtils.validateKeyStructure(keyData, 'ECDH');\n \n const keyBytes = new Uint8Array(keyData);\n \n // Try P-384 first\n try {\n const publicKey = await crypto.subtle.importKey(\n 'spki',\n keyBytes,\n {\n name: 'ECDH',\n namedCurve: 'P-384'\n },\n false, // Non-extractable\n []\n );\n \n EnhancedSecureCryptoUtils.secureLog.log('info', 'Legacy public key imported (P-384)', { keySize: keyData.length });\n return publicKey;\n } catch (p384Error) {\n EnhancedSecureCryptoUtils.secureLog.log('warn', 'P-384 import failed, trying P-256', { error: p384Error.message });\n \n // Fallback to P-256\n const publicKey = await crypto.subtle.importKey(\n 'spki',\n keyBytes,\n {\n name: 'ECDH',\n namedCurve: 'P-256'\n },\n false, // Non-extractable\n []\n );\n \n EnhancedSecureCryptoUtils.secureLog.log('info', 'Legacy public key imported (P-256 fallback)', { keySize: keyData.length });\n return publicKey;\n }\n } catch (error) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Legacy public key import failed', { error: error.message });\n throw new Error('Failed to import the public key');\n }\n }\n\n\n // Method to check if a key is trusted\n static isKeyTrusted(keyOrFingerprint) {\n if (keyOrFingerprint instanceof CryptoKey) {\n const meta = EnhancedSecureCryptoUtils._keyMetadata.get(keyOrFingerprint);\n return meta ? meta.trusted === true : false;\n } else if (keyOrFingerprint && keyOrFingerprint._securityMetadata) {\n // Check by key metadata\n return keyOrFingerprint._securityMetadata.trusted === true;\n }\n\n return false;\n }\n\n static async importPublicKeyFromSignedPackage(signedPackage, verifyingKey = null, options = {}) {\n try {\n if (!signedPackage || !signedPackage.keyData || !signedPackage.signature) {\n throw new Error('Invalid signed key package format');\n }\n\n // Validate all required fields are present\n const requiredFields = ['keyData', 'signature', 'keyType', 'timestamp', 'version'];\n const missingFields = requiredFields.filter(field => !signedPackage[field]);\n\n if (missingFields.length > 0) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Missing required fields in signed package', {\n missingFields: missingFields,\n availableFields: Object.keys(signedPackage)\n });\n throw new Error(`Required fields are missing in the signed package: ${missingFields.join(', ')}`);\n }\n\n // SECURITY ENHANCEMENT: MANDATORY signature verification for signed packages\n if (!verifyingKey) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'SECURITY VIOLATION: Signed package received without verifying key', {\n keyType: signedPackage.keyType,\n keySize: signedPackage.keyData.length,\n timestamp: signedPackage.timestamp,\n version: signedPackage.version,\n securityRisk: 'HIGH - Potential MITM attack vector'\n });\n\n // REJECT the signed package if no verifying key provided\n throw new Error('CRITICAL SECURITY ERROR: Signed key package received without a verification key. ' +\n 'This may indicate a possible MITM attack attempt. Import rejected for security reasons.');\n }\n\n // \u041E\u0411\u041D\u041E\u0412\u041B\u0415\u041D\u041E: \u0418\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u043C \u0443\u043B\u0443\u0447\u0448\u0435\u043D\u043D\u0443\u044E \u0432\u0430\u043B\u0438\u0434\u0430\u0446\u0438\u044E\n await EnhancedSecureCryptoUtils.validateKeyStructure(signedPackage.keyData, signedPackage.keyType || 'ECDH');\n\n // MANDATORY signature verification when verifyingKey is provided\n const packageCopy = { ...signedPackage };\n delete packageCopy.signature;\n const packageString = JSON.stringify(packageCopy);\n const isValidSignature = await EnhancedSecureCryptoUtils.verifySignature(verifyingKey, signedPackage.signature, packageString);\n\n if (!isValidSignature) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'SECURITY BREACH: Invalid signature detected - MITM attack prevented', {\n keyType: signedPackage.keyType,\n keySize: signedPackage.keyData.length,\n timestamp: signedPackage.timestamp,\n version: signedPackage.version,\n attackPrevented: true\n });\n throw new Error('CRITICAL SECURITY ERROR: Invalid key signature detected. ' +\n 'This indicates a possible MITM attack attempt. Key import rejected.');\n }\n\n // Additional MITM protection: Check for key reuse and suspicious patterns\n const keyFingerprint = await EnhancedSecureCryptoUtils.calculateKeyFingerprint(signedPackage.keyData);\n\n // Log successful verification with security details\n EnhancedSecureCryptoUtils.secureLog.log('info', 'SECURE: Signature verification passed for signed package', {\n keyType: signedPackage.keyType,\n keySize: signedPackage.keyData.length,\n timestamp: signedPackage.timestamp,\n version: signedPackage.version,\n signatureVerified: true,\n securityLevel: 'HIGH',\n keyFingerprint: keyFingerprint.substring(0, 8) // Only log first 8 chars for security\n });\n\n // Import the public key with fallback\n const keyBytes = new Uint8Array(signedPackage.keyData);\n const keyType = signedPackage.keyType || 'ECDH';\n\n // Try P-384 first\n try {\n const publicKey = await crypto.subtle.importKey(\n 'spki',\n keyBytes,\n {\n name: keyType,\n namedCurve: 'P-384'\n },\n false, // Non-extractable\n keyType === 'ECDSA' ? ['verify'] : []\n );\n\n // Use WeakMap to store metadata\n EnhancedSecureCryptoUtils._keyMetadata.set(publicKey, {\n trusted: true,\n verificationStatus: 'VERIFIED_SECURE',\n verificationTimestamp: Date.now()\n });\n\n return publicKey;\n } catch (p384Error) {\n EnhancedSecureCryptoUtils.secureLog.log('warn', 'P-384 import failed, trying P-256', { error: p384Error.message });\n\n // Fallback to P-256\n const publicKey = await crypto.subtle.importKey(\n 'spki',\n keyBytes,\n {\n name: keyType,\n namedCurve: 'P-256'\n },\n false, // Non-extractable\n keyType === 'ECDSA' ? ['verify'] : []\n );\n\n // Use WeakMap to store metadata\n EnhancedSecureCryptoUtils._keyMetadata.set(publicKey, {\n trusted: true,\n verificationStatus: 'VERIFIED_SECURE',\n verificationTimestamp: Date.now()\n });\n\n return publicKey;\n }\n } catch (error) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Signed package key import failed', {\n error: error.message,\n securityImplications: 'Potential security breach prevented'\n });\n throw new Error(`Failed to import the public key from the signed package: ${error.message}`);\n }\n }\n\n // Enhanced key derivation with metadata protection and 64-byte salt\n static async deriveSharedKeys(privateKey, publicKey, salt) {\n try {\n // Validate input parameters are CryptoKey instances\n if (!(privateKey instanceof CryptoKey)) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Private key is not a CryptoKey', {\n privateKeyType: typeof privateKey,\n privateKeyAlgorithm: privateKey?.algorithm?.name\n });\n throw new Error('The private key is not a valid CryptoKey.');\n }\n \n if (!(publicKey instanceof CryptoKey)) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Public key is not a CryptoKey', {\n publicKeyType: typeof publicKey,\n publicKeyAlgorithm: publicKey?.algorithm?.name\n });\n throw new Error('The private key is not a valid CryptoKey.');\n }\n \n // Validate salt size (should be 64 bytes for enhanced security)\n if (!salt || salt.length !== 64) {\n throw new Error('Salt must be exactly 64 bytes for enhanced security');\n }\n \n const saltBytes = new Uint8Array(salt);\n const encoder = new TextEncoder();\n \n // Enhanced context info with version and additional entropy\n const contextInfo = encoder.encode('SecureBit.chat v4.0 Enhanced Security Edition');\n \n // Derive master shared secret with enhanced parameters\n // Try SHA-384 first, fallback to SHA-256\n let sharedSecret;\n try {\n sharedSecret = await crypto.subtle.deriveKey(\n {\n name: 'ECDH',\n public: publicKey\n },\n privateKey,\n {\n name: 'HKDF',\n hash: 'SHA-384',\n salt: saltBytes,\n info: contextInfo\n },\n false, // Non-extractable\n ['deriveKey']\n );\n } catch (sha384Error) {\n EnhancedSecureCryptoUtils.secureLog.log('warn', 'SHA-384 key derivation failed, trying SHA-256', { \n error: sha384Error.message,\n privateKeyType: typeof privateKey,\n publicKeyType: typeof publicKey,\n privateKeyAlgorithm: privateKey?.algorithm?.name,\n publicKeyAlgorithm: publicKey?.algorithm?.name\n });\n \n sharedSecret = await crypto.subtle.deriveKey(\n {\n name: 'ECDH',\n public: publicKey\n },\n privateKey,\n {\n name: 'HKDF',\n hash: 'SHA-256',\n salt: saltBytes,\n info: contextInfo\n },\n false, // Non-extractable\n ['deriveKey']\n );\n }\n\n // Derive message encryption key with fallback\n let encryptionKey;\n try {\n encryptionKey = await crypto.subtle.deriveKey(\n {\n name: 'HKDF',\n hash: 'SHA-384',\n salt: saltBytes,\n info: encoder.encode('message-encryption-v4')\n },\n sharedSecret,\n {\n name: 'AES-GCM',\n length: 256\n },\n false, // Non-extractable for enhanced security\n ['encrypt', 'decrypt']\n );\n } catch (sha384Error) {\n encryptionKey = await crypto.subtle.deriveKey(\n {\n name: 'HKDF',\n hash: 'SHA-256',\n salt: saltBytes,\n info: encoder.encode('message-encryption-v4')\n },\n sharedSecret,\n {\n name: 'AES-GCM',\n length: 256\n },\n false, // Non-extractable for enhanced security\n ['encrypt', 'decrypt']\n );\n }\n\n // Derive MAC key for message authentication with fallback\n let macKey;\n try {\n macKey = await crypto.subtle.deriveKey(\n {\n name: 'HKDF',\n hash: 'SHA-384',\n salt: saltBytes,\n info: encoder.encode('message-authentication-v4')\n },\n sharedSecret,\n {\n name: 'HMAC',\n hash: 'SHA-384'\n },\n false, // Non-extractable\n ['sign', 'verify']\n );\n } catch (sha384Error) {\n macKey = await crypto.subtle.deriveKey(\n {\n name: 'HKDF',\n hash: 'SHA-256',\n salt: saltBytes,\n info: encoder.encode('message-authentication-v4')\n },\n sharedSecret,\n {\n name: 'HMAC',\n hash: 'SHA-256'\n },\n false, // Non-extractable\n ['sign', 'verify']\n );\n }\n\n // Derive separate metadata encryption key with fallback\n let metadataKey;\n try {\n metadataKey = await crypto.subtle.deriveKey(\n {\n name: 'HKDF',\n hash: 'SHA-384',\n salt: saltBytes,\n info: encoder.encode('metadata-protection-v4')\n },\n sharedSecret,\n {\n name: 'AES-GCM',\n length: 256\n },\n false, // Non-extractable\n ['encrypt', 'decrypt']\n );\n } catch (sha384Error) {\n metadataKey = await crypto.subtle.deriveKey(\n {\n name: 'HKDF',\n hash: 'SHA-256',\n salt: saltBytes,\n info: encoder.encode('metadata-protection-v4')\n },\n sharedSecret,\n {\n name: 'AES-GCM',\n length: 256\n },\n false, // Non-extractable\n ['encrypt', 'decrypt']\n );\n }\n\n // Generate temporary extractable key for fingerprint calculation with fallback\n let fingerprintKey;\n try {\n fingerprintKey = await crypto.subtle.deriveKey(\n {\n name: 'HKDF',\n hash: 'SHA-384',\n salt: saltBytes,\n info: encoder.encode('fingerprint-generation-v4')\n },\n sharedSecret,\n {\n name: 'AES-GCM',\n length: 256\n },\n true, // Extractable only for fingerprint\n ['encrypt', 'decrypt']\n );\n } catch (sha384Error) {\n fingerprintKey = await crypto.subtle.deriveKey(\n {\n name: 'HKDF',\n hash: 'SHA-256',\n salt: saltBytes,\n info: encoder.encode('fingerprint-generation-v4')\n },\n sharedSecret,\n {\n name: 'AES-GCM',\n length: 256\n },\n true, // Extractable only for fingerprint\n ['encrypt', 'decrypt']\n );\n }\n\n // Generate key fingerprint for verification\n const fingerprintKeyData = await crypto.subtle.exportKey('raw', fingerprintKey);\n const fingerprint = await EnhancedSecureCryptoUtils.generateKeyFingerprint(Array.from(new Uint8Array(fingerprintKeyData)));\n\n // Validate that all derived keys are CryptoKey instances\n if (!(encryptionKey instanceof CryptoKey)) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Derived encryption key is not a CryptoKey', {\n encryptionKeyType: typeof encryptionKey,\n encryptionKeyAlgorithm: encryptionKey?.algorithm?.name\n });\n throw new Error('The derived encryption key is not a valid CryptoKey.');\n }\n \n if (!(macKey instanceof CryptoKey)) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Derived MAC key is not a CryptoKey', {\n macKeyType: typeof macKey,\n macKeyAlgorithm: macKey?.algorithm?.name\n });\n throw new Error('The derived MAC key is not a valid CryptoKey.');\n }\n \n if (!(metadataKey instanceof CryptoKey)) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Derived metadata key is not a CryptoKey', {\n metadataKeyType: typeof metadataKey,\n metadataKeyAlgorithm: metadataKey?.algorithm?.name\n });\n throw new Error('The derived metadata key is not a valid CryptoKey.');\n }\n\n EnhancedSecureCryptoUtils.secureLog.log('info', 'Enhanced shared keys derived successfully', {\n saltSize: salt.length,\n hasMetadataKey: true,\n nonExtractable: true,\n version: '4.0',\n allKeysValid: true\n });\n\n return {\n encryptionKey,\n macKey,\n metadataKey,\n fingerprint,\n timestamp: Date.now(),\n version: '4.0'\n };\n } catch (error) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Enhanced key derivation failed', { error: error.message });\n throw new Error(`Failed to create shared encryption keys: ${error.message}`);\n }\n }\n\n static async generateKeyFingerprint(keyData) {\n const keyBuffer = new Uint8Array(keyData);\n const hashBuffer = await crypto.subtle.digest('SHA-384', keyBuffer);\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n return hashArray.slice(0, 12).map(b => b.toString(16).padStart(2, '0')).join(':');\n }\n\n // Generate mutual authentication challenge\n static generateMutualAuthChallenge() {\n const challenge = crypto.getRandomValues(new Uint8Array(48)); // Increased to 48 bytes\n const timestamp = Date.now();\n const nonce = crypto.getRandomValues(new Uint8Array(16));\n \n return {\n challenge: Array.from(challenge),\n timestamp,\n nonce: Array.from(nonce),\n version: '4.0'\n };\n }\n\n // Create cryptographic proof for mutual authentication\n static async createAuthProof(challenge, privateKey, publicKey) {\n try {\n if (!challenge || !challenge.challenge || !challenge.timestamp || !challenge.nonce) {\n throw new Error('Invalid challenge structure');\n }\n \n // Check challenge age (max 2 minutes)\n const challengeAge = Date.now() - challenge.timestamp;\n if (challengeAge > 120000) {\n throw new Error('Challenge expired');\n }\n \n // Create proof data\n const proofData = {\n challenge: challenge.challenge,\n timestamp: challenge.timestamp,\n nonce: challenge.nonce,\n responseTimestamp: Date.now(),\n publicKeyHash: await EnhancedSecureCryptoUtils.hashPublicKey(publicKey)\n };\n \n // Sign the proof\n const proofString = JSON.stringify(proofData);\n const signature = await EnhancedSecureCryptoUtils.signData(privateKey, proofString);\n \n const proof = {\n ...proofData,\n signature,\n version: '4.0'\n };\n \n EnhancedSecureCryptoUtils.secureLog.log('info', 'Authentication proof created', {\n challengeAge: Math.round(challengeAge / 1000) + 's'\n });\n \n return proof;\n } catch (error) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Authentication proof creation failed', { error: error.message });\n throw new Error(`Failed to create cryptographic proof: ${error.message}`);\n }\n }\n\n // Verify mutual authentication proof\n static async verifyAuthProof(proof, challenge, publicKey) {\n try {\n await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 20) + 5));\n // Assert the public key is valid and has the correct usage\n EnhancedSecureCryptoUtils.assertCryptoKey(publicKey, 'ECDSA', ['verify']);\n\n if (!proof || !challenge || !publicKey) {\n throw new Error('Missing required parameters for proof verification');\n }\n\n // Validate proof structure\n const requiredFields = ['challenge', 'timestamp', 'nonce', 'responseTimestamp', 'publicKeyHash', 'signature'];\n for (const field of requiredFields) {\n if (!proof[field]) {\n throw new Error(`Missing required field: ${field}`);\n }\n }\n\n // Verify challenge matches\n if (!EnhancedSecureCryptoUtils.constantTimeCompareArrays(proof.challenge, challenge.challenge) ||\n proof.timestamp !== challenge.timestamp ||\n !EnhancedSecureCryptoUtils.constantTimeCompareArrays(proof.nonce, challenge.nonce)) {\n throw new Error('Challenge mismatch - possible replay attack');\n }\n\n // Check response time (max 5 minutes)\n const responseAge = Date.now() - proof.responseTimestamp;\n if (responseAge > 300000) {\n throw new Error('Proof response expired');\n }\n\n // Verify public key hash\n const expectedHash = await EnhancedSecureCryptoUtils.hashPublicKey(publicKey);\n if (!EnhancedSecureCryptoUtils.constantTimeCompare(proof.publicKeyHash, expectedHash)) {\n throw new Error('Public key hash mismatch');\n }\n\n // Verify signature\n const proofCopy = { ...proof };\n delete proofCopy.signature;\n const proofString = JSON.stringify(proofCopy);\n const isValidSignature = await EnhancedSecureCryptoUtils.verifySignature(publicKey, proof.signature, proofString);\n\n if (!isValidSignature) {\n throw new Error('Invalid proof signature');\n }\n\n EnhancedSecureCryptoUtils.secureLog.log('info', 'Authentication proof verified successfully', {\n responseAge: Math.round(responseAge / 1000) + 's'\n });\n\n return true;\n } catch (error) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Authentication proof verification failed', { error: error.message });\n throw new Error(`Failed to verify cryptographic proof: ${error.message}`);\n }\n }\n\n // Hash public key for verification\n static async hashPublicKey(publicKey) {\n try {\n const exported = await crypto.subtle.exportKey('spki', publicKey);\n const hash = await crypto.subtle.digest('SHA-384', exported);\n const hashArray = Array.from(new Uint8Array(hash));\n return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');\n } catch (error) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Public key hashing failed', { error: error.message });\n throw new Error('Failed to create hash of the public key');\n }\n }\n\n // Legacy authentication challenge for backward compatibility\n static generateAuthChallenge() {\n const challenge = crypto.getRandomValues(new Uint8Array(32));\n return Array.from(challenge);\n }\n\n // Generate verification code for out-of-band authentication\n static generateVerificationCode() {\n const chars = '0123456789ABCDEF';\n let result = '';\n const values = crypto.getRandomValues(new Uint8Array(6));\n for (let i = 0; i < 6; i++) {\n result += chars[values[i] % chars.length];\n }\n return result.match(/.{1,2}/g).join('-');\n }\n\n // Enhanced message encryption with metadata protection and sequence numbers\n static async encryptMessage(message, encryptionKey, macKey, metadataKey, messageId, sequenceNumber = 0) {\n try {\n if (!message || typeof message !== 'string') {\n throw new Error('Invalid message format');\n }\n\n EnhancedSecureCryptoUtils.assertCryptoKey(encryptionKey, 'AES-GCM', ['encrypt']);\n EnhancedSecureCryptoUtils.assertCryptoKey(macKey, 'HMAC', ['sign']);\n EnhancedSecureCryptoUtils.assertCryptoKey(metadataKey, 'AES-GCM', ['encrypt']);\n\n const encoder = new TextEncoder();\n const messageData = encoder.encode(message);\n const messageIv = crypto.getRandomValues(new Uint8Array(12));\n const metadataIv = crypto.getRandomValues(new Uint8Array(12));\n const timestamp = Date.now();\n\n const paddingSize = 16 - (messageData.length % 16);\n const paddedMessage = new Uint8Array(messageData.length + paddingSize);\n paddedMessage.set(messageData);\n const padding = crypto.getRandomValues(new Uint8Array(paddingSize));\n paddedMessage.set(padding, messageData.length);\n\n const encryptedMessage = await crypto.subtle.encrypt(\n { name: 'AES-GCM', iv: messageIv },\n encryptionKey,\n paddedMessage\n );\n\n const metadata = {\n id: messageId,\n timestamp: timestamp,\n sequenceNumber: sequenceNumber,\n originalLength: messageData.length,\n version: '4.0'\n };\n\n const metadataStr = JSON.stringify(EnhancedSecureCryptoUtils.sortObjectKeys(metadata));\n const encryptedMetadata = await crypto.subtle.encrypt(\n { name: 'AES-GCM', iv: metadataIv },\n metadataKey,\n encoder.encode(metadataStr)\n );\n\n const payload = {\n messageIv: Array.from(messageIv),\n messageData: Array.from(new Uint8Array(encryptedMessage)),\n metadataIv: Array.from(metadataIv),\n metadataData: Array.from(new Uint8Array(encryptedMetadata)),\n version: '4.0'\n };\n\n const sortedPayload = EnhancedSecureCryptoUtils.sortObjectKeys(payload);\n const payloadStr = JSON.stringify(sortedPayload);\n\n const mac = await crypto.subtle.sign(\n 'HMAC',\n macKey,\n encoder.encode(payloadStr)\n );\n\n payload.mac = Array.from(new Uint8Array(mac));\n\n EnhancedSecureCryptoUtils.secureLog.log('info', 'Message encrypted with metadata protection', {\n messageId,\n sequenceNumber,\n hasMetadataProtection: true,\n hasPadding: true\n });\n\n return payload;\n } catch (error) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Message encryption failed', {\n error: error.message,\n messageId\n });\n throw new Error(`Failed to encrypt the message: ${error.message}`);\n }\n }\n\n // Enhanced message decryption with metadata protection and sequence validation\n static async decryptMessage(encryptedPayload, encryptionKey, macKey, metadataKey, expectedSequenceNumber = null) {\n try {\n EnhancedSecureCryptoUtils.assertCryptoKey(encryptionKey, 'AES-GCM', ['decrypt']);\n EnhancedSecureCryptoUtils.assertCryptoKey(macKey, 'HMAC', ['verify']);\n EnhancedSecureCryptoUtils.assertCryptoKey(metadataKey, 'AES-GCM', ['decrypt']);\n\n const requiredFields = ['messageIv', 'messageData', 'metadataIv', 'metadataData', 'mac', 'version'];\n for (const field of requiredFields) {\n if (!encryptedPayload[field]) {\n throw new Error(`Missing required field: ${field}`);\n }\n }\n\n const payloadCopy = { ...encryptedPayload };\n delete payloadCopy.mac;\n const sortedPayloadCopy = EnhancedSecureCryptoUtils.sortObjectKeys(payloadCopy);\n const payloadStr = JSON.stringify(sortedPayloadCopy);\n\n const macValid = await crypto.subtle.verify(\n 'HMAC',\n macKey,\n new Uint8Array(encryptedPayload.mac),\n new TextEncoder().encode(payloadStr)\n );\n\n if (!macValid) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'MAC verification failed', {\n payloadFields: Object.keys(encryptedPayload),\n macLength: encryptedPayload.mac?.length\n });\n throw new Error('Message authentication failed - possible tampering');\n }\n\n const metadataIv = new Uint8Array(encryptedPayload.metadataIv);\n const metadataData = new Uint8Array(encryptedPayload.metadataData);\n\n const decryptedMetadataBuffer = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv: metadataIv },\n metadataKey,\n metadataData\n );\n\n const metadataStr = new TextDecoder().decode(decryptedMetadataBuffer);\n const metadata = JSON.parse(metadataStr);\n\n if (!metadata.id || !metadata.timestamp || metadata.sequenceNumber === undefined || !metadata.originalLength) {\n throw new Error('Invalid metadata structure');\n }\n\n const messageAge = Date.now() - metadata.timestamp;\n if (messageAge > 300000) {\n throw new Error('Message expired (older than 5 minutes)');\n }\n\n if (expectedSequenceNumber !== null) {\n if (metadata.sequenceNumber < expectedSequenceNumber) {\n EnhancedSecureCryptoUtils.secureLog.log('warn', 'Received message with lower sequence number, possible queued message', {\n expected: expectedSequenceNumber,\n received: metadata.sequenceNumber,\n messageId: metadata.id\n });\n } else if (metadata.sequenceNumber > expectedSequenceNumber + 10) {\n throw new Error(`Sequence number gap too large: expected around ${expectedSequenceNumber}, got ${metadata.sequenceNumber}`);\n }\n }\n\n const messageIv = new Uint8Array(encryptedPayload.messageIv);\n const messageData = new Uint8Array(encryptedPayload.messageData);\n\n const decryptedMessageBuffer = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv: messageIv },\n encryptionKey,\n messageData\n );\n\n const paddedMessage = new Uint8Array(decryptedMessageBuffer);\n const originalMessage = paddedMessage.slice(0, metadata.originalLength);\n\n const decoder = new TextDecoder();\n const message = decoder.decode(originalMessage);\n\n EnhancedSecureCryptoUtils.secureLog.log('info', 'Message decrypted successfully', {\n messageId: metadata.id,\n sequenceNumber: metadata.sequenceNumber,\n messageAge: Math.round(messageAge / 1000) + 's'\n });\n\n return {\n message: message,\n messageId: metadata.id,\n timestamp: metadata.timestamp,\n sequenceNumber: metadata.sequenceNumber\n };\n } catch (error) {\n EnhancedSecureCryptoUtils.secureLog.log('error', 'Message decryption failed', { error: error.message });\n throw new Error(`Failed to decrypt the message: ${error.message}`);\n }\n }\n\n // Enhanced input sanitization\n static sanitizeMessage(message) {\n if (typeof message !== 'string') {\n throw new Error('Message must be a string');\n }\n \n return message\n .replace(/