import createDOMPurify from 'dompurify';

class EnhancedSecureCryptoUtils {

    static _keyMetadata = new WeakMap();
    static _messageSanitizer = null;
    
    // Initialize secure logging system after class definition

    // Utility to sort object keys for deterministic serialization
    static sortObjectKeys(obj) {
        if (typeof obj !== 'object' || obj === null) {
            return obj;
        }

        if (Array.isArray(obj)) {
            return obj.map(EnhancedSecureCryptoUtils.sortObjectKeys);
        }

        const sortedObj = {};
        Object.keys(obj).sort().forEach(key => {
            sortedObj[key] = EnhancedSecureCryptoUtils.sortObjectKeys(obj[key]);
        });
        return sortedObj;
    }

    // Utility to assert CryptoKey type and properties
    static assertCryptoKey(key, expectedName = null, expectedUsages = []) {
        if (!(key instanceof CryptoKey)) throw new Error('Expected CryptoKey');
        if (expectedName && key.algorithm?.name !== expectedName) {
            throw new Error(`Expected algorithm ${expectedName}, got ${key.algorithm?.name}`);
        }
        for (const u of expectedUsages) {
            if (!key.usages || !key.usages.includes(u)) {
                throw new Error(`Missing required key usage: ${u}`);
            }
        }
    }
    // Helper function to convert ArrayBuffer to Base64
    static arrayBufferToBase64(buffer) {
        let binary = '';
        const bytes = new Uint8Array(buffer);
        const len = bytes.byteLength;
        for (let i = 0; i < len; i++) {
            binary += String.fromCharCode(bytes[i]);
        }
        return btoa(binary);
    }

    // Helper function to convert Base64 to ArrayBuffer
    static base64ToArrayBuffer(base64) {
        try {
            // Validate input
            if (typeof base64 !== 'string' || !base64) {
                throw new Error('Invalid base64 input: must be a non-empty string');
            }

            // Remove any whitespace and validate base64 format
            const cleanBase64 = base64.trim();
            if (!/^[A-Za-z0-9+/]*={0,2}$/.test(cleanBase64)) {
                throw new Error('Invalid base64 format');
            }

            // Handle empty string case
            if (cleanBase64 === '') {
                return new ArrayBuffer(0);
            }

            const binaryString = atob(cleanBase64);
            const len = binaryString.length;
            const bytes = new Uint8Array(len);
            for (let i = 0; i < len; i++) {
                bytes[i] = binaryString.charCodeAt(i);
            }
            return bytes.buffer;
        } catch (error) {
            console.error('Base64 to ArrayBuffer conversion failed:', error.message);
            throw new Error(`Base64 conversion error: ${error.message}`);
        }
    }

    // Helper function to convert hex string to Uint8Array
    static hexToUint8Array(hexString) {
        try {
            if (!hexString || typeof hexString !== 'string') {
                throw new Error('Invalid hex string input: must be a non-empty string');
            }

            // Remove colons and spaces from hex string (e.g., "aa:bb:cc" -> "aabbcc")
            const cleanHex = hexString.replace(/:/g, '').replace(/\s/g, '');
            
            // Validate hex format
            if (!/^[0-9a-fA-F]*$/.test(cleanHex)) {
                throw new Error('Invalid hex format: contains non-hex characters');
            }
            
            // Ensure even length
            if (cleanHex.length % 2 !== 0) {
                throw new Error('Invalid hex format: odd length');
            }

            // Convert hex string to bytes
            const bytes = new Uint8Array(cleanHex.length / 2);
            for (let i = 0; i < cleanHex.length; i += 2) {
                bytes[i / 2] = parseInt(cleanHex.substr(i, 2), 16);
            }
            
            return bytes;
        } catch (error) {
            console.error('Hex to Uint8Array conversion failed:', error.message);
            throw new Error(`Hex conversion error: ${error.message}`);
        }
    }

    /**
     * Overwrite a buffer holding key material once it is no longer needed.
     *
     * This is a genuine wipe, unlike the manager's _secureWipeString /
     * _secureWipeCryptoKey, which cannot wipe anything (JS strings are immutable
     * and a non-extractable CryptoKey has no JS-visible bytes) and only ever
     * dropped a reference while reporting success. Here the bytes really are
     * ours: overwrite them so the shared secret does not linger in the heap
     * waiting for a garbage collector that may never run before a heap snapshot
     * or a memory-reading extension gets there first.
     *
     * Random first, then zeros: on the off chance a copying GC has already moved
     * the buffer, the random pass at least destroys the plaintext value at the
     * old address as well as the new one.
     */
    static zeroizeBuffer(buffer) {
        try {
            if (!buffer) return;
            const view = buffer instanceof Uint8Array
                ? buffer
                : (buffer instanceof ArrayBuffer ? new Uint8Array(buffer) : null);
            if (!view || view.length === 0) return;
            crypto.getRandomValues(view);
            view.fill(0);
        } catch (_) {
            // A detached buffer is already unreadable; nothing left to do.
        }
    }

    static async encryptData(data, password) {
        try {
            const dataString = typeof data === 'string' ? data : JSON.stringify(data);
            const salt = crypto.getRandomValues(new Uint8Array(16));
            const encoder = new TextEncoder();
            const passwordBuffer = encoder.encode(password);

            const keyMaterial = await crypto.subtle.importKey(
                'raw',
                passwordBuffer,
                { name: 'PBKDF2' },
                false,
                ['deriveKey']
            );

            const key = await crypto.subtle.deriveKey(
                {
                    name: 'PBKDF2',
                    salt: salt,
                    iterations: 310000,
                    hash: 'SHA-256',
                },
                keyMaterial,
                { name: 'AES-GCM', length: 256 },
                false,
                ['encrypt']
            );

            const iv = crypto.getRandomValues(new Uint8Array(12));
            const dataBuffer = encoder.encode(dataString);
            const encrypted = await crypto.subtle.encrypt(
                { name: 'AES-GCM', iv: iv },
                key,
                dataBuffer
            );

            const encryptedPackage = {
                version: '1.0',
                salt: Array.from(salt),
                iv: Array.from(iv),
                data: Array.from(new Uint8Array(encrypted)),
                timestamp: Date.now(),
            };

            const packageString = JSON.stringify(encryptedPackage);
            return EnhancedSecureCryptoUtils.arrayBufferToBase64(new TextEncoder().encode(packageString).buffer);

        } catch (error) {
            console.error('Encryption failed:', error.message);
            throw new Error(`Encryption error: ${error.message}`);
        }
    }

        static async decryptData(encryptedData, password) {
        try {
            const packageBuffer = EnhancedSecureCryptoUtils.base64ToArrayBuffer(encryptedData);
            const packageString = new TextDecoder().decode(packageBuffer);
            const encryptedPackage = JSON.parse(packageString);

            if (!encryptedPackage.version || !encryptedPackage.salt || !encryptedPackage.iv || !encryptedPackage.data) {
                throw new Error('Invalid encrypted data format');
            }

            const salt = new Uint8Array(encryptedPackage.salt);
            const iv = new Uint8Array(encryptedPackage.iv);
            const encrypted = new Uint8Array(encryptedPackage.data);

            const encoder = new TextEncoder();
            const passwordBuffer = encoder.encode(password);

            const keyMaterial = await crypto.subtle.importKey(
                'raw',
                passwordBuffer,
                { name: 'PBKDF2' },
                false,
                ['deriveKey']
            );

            const key = await crypto.subtle.deriveKey(
                {
                    name: 'PBKDF2',
                    salt: salt,
                    iterations: 310000,
                    hash: 'SHA-256'
                },
                keyMaterial,
                { name: 'AES-GCM', length: 256 },
                false,
                ['decrypt']
            );

            const decrypted = await crypto.subtle.decrypt(
                { name: 'AES-GCM', iv },
                key,
                encrypted
            );

            const decryptedString = new TextDecoder().decode(decrypted);

            try {
                return JSON.parse(decryptedString);
            } catch {
                return decryptedString;
            }

        } catch (error) {
            console.error('Decryption failed:', error.message);
            throw new Error(`Decryption error: ${error.message}`);
        }
    }

    
    // Generate secure password for data exchange
    static generateSecurePassword() {
        const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-=[]{}|;:,.<>?';
        const charCount = chars.length;
        const length = 32; 
        let password = '';
        
        // Use rejection sampling to avoid bias
        for (let i = 0; i < length; i++) {
            let randomValue;
            do {
                randomValue = crypto.getRandomValues(new Uint32Array(1))[0];
            } while (randomValue >= 4294967296 - (4294967296 % charCount)); // Reject biased values
            
            password += chars[randomValue % charCount];
        }
        return password;
    }

    // Real security level calculation with actual verification
    static async calculateSecurityLevel(securityManager) {
        let score = 0;
        const maxScore = 100; // Fixed: Changed from 110 to 100 for cleaner percentage
        const verificationResults = {};
        
        try {
            // Fallback to basic calculation if securityManager is not fully initialized
            if (!securityManager || !securityManager.securityFeatures) {
                console.warn('Security manager not fully initialized, using fallback calculation');
                return {
                    level: 'INITIALIZING',
                    score: 0,
                    color: 'gray',
                    verificationResults: {},
                    timestamp: Date.now(),
                    details: 'Security system initializing...',
                    isRealData: false
                };
            }

            // All security features are enabled by default - no session type restrictions
            const sessionType = 'full'; // All features enabled
            const isDemoSession = false; // All features available
            
            // 1. Base encryption verification (20 points) - Available in demo
            try {
                const encryptionResult = await EnhancedSecureCryptoUtils.verifyEncryption(securityManager);
                if (encryptionResult.passed) {
                    score += 20;
                    verificationResults.verifyEncryption = { passed: true, details: encryptionResult.details, points: 20 };
                } else {
                    verificationResults.verifyEncryption = { passed: false, details: encryptionResult.details, points: 0 };
                }
            } catch (error) {
                verificationResults.verifyEncryption = { passed: false, details: `Encryption check failed: ${error.message}`, points: 0 };
            }
            
            // 2. Simple key exchange verification (15 points) - Available in demo
            try {
                const ecdhResult = await EnhancedSecureCryptoUtils.verifyECDHKeyExchange(securityManager);
                if (ecdhResult.passed) {
                    score += 15;
                    verificationResults.verifyECDHKeyExchange = { passed: true, details: ecdhResult.details, points: 15 };
                } else {
                    verificationResults.verifyECDHKeyExchange = { passed: false, details: ecdhResult.details, points: 0 };
                }
            } catch (error) {
                verificationResults.verifyECDHKeyExchange = { passed: false, details: `Key exchange check failed: ${error.message}`, points: 0 };
            }
            
            // 3. Message integrity verification (10 points) - Available in demo
            try {
                const integrityResult = await EnhancedSecureCryptoUtils.verifyMessageIntegrity(securityManager);
                if (integrityResult.passed) {
                score += 10;
                    verificationResults.verifyMessageIntegrity = { passed: true, details: integrityResult.details, points: 10 };
            } else {
                    verificationResults.verifyMessageIntegrity = { passed: false, details: integrityResult.details, points: 0 };
                }
            } catch (error) {
                verificationResults.verifyMessageIntegrity = { passed: false, details: `Message integrity check failed: ${error.message}`, points: 0 };
            }
            
            // 4. ECDSA signatures verification (15 points) - All features enabled by default
            try {
                const ecdsaResult = await EnhancedSecureCryptoUtils.verifyECDSASignatures(securityManager);
                if (ecdsaResult.passed) {
                    score += 15;
                    verificationResults.verifyECDSASignatures = { passed: true, details: ecdsaResult.details, points: 15 };
            } else {
                    verificationResults.verifyECDSASignatures = { passed: false, details: ecdsaResult.details, points: 0 };
                }
            } catch (error) {
                verificationResults.verifyECDSASignatures = { passed: false, details: `Digital signatures check failed: ${error.message}`, points: 0 };
            }
            
            // 5. Rate limiting verification (5 points) - Available in demo
            try {
                const rateLimitResult = await EnhancedSecureCryptoUtils.verifyRateLimiting(securityManager);
                if (rateLimitResult.passed) {
                    score += 5;
                    verificationResults.verifyRateLimiting = { passed: true, details: rateLimitResult.details, points: 5 };
            } else {
                    verificationResults.verifyRateLimiting = { passed: false, details: rateLimitResult.details, points: 0 };
                }
            } catch (error) {
                verificationResults.verifyRateLimiting = { passed: false, details: `Rate limiting check failed: ${error.message}`, points: 0 };
            }
            
            // 6. Metadata protection verification (10 points) - All features enabled by default
            try {
                const metadataResult = await EnhancedSecureCryptoUtils.verifyMetadataProtection(securityManager);
                if (metadataResult.passed) {
                score += 10;
                    verificationResults.verifyMetadataProtection = { passed: true, details: metadataResult.details, points: 10 };
            } else {
                    verificationResults.verifyMetadataProtection = { passed: false, details: metadataResult.details, points: 0 };
                }
            } catch (error) {
                verificationResults.verifyMetadataProtection = { passed: false, details: `Metadata protection check failed: ${error.message}`, points: 0 };
            }
            
            // 7. Perfect Forward Secrecy verification (10 points) - All features enabled by default
            try {
                const pfsResult = await EnhancedSecureCryptoUtils.verifyPerfectForwardSecrecy(securityManager);
                if (pfsResult.passed) {
                score += 10;
                    verificationResults.verifyPerfectForwardSecrecy = { passed: true, details: pfsResult.details, points: 10 };
            } else {
                    verificationResults.verifyPerfectForwardSecrecy = { passed: false, details: pfsResult.details, points: 0 };
                }
            } catch (error) {
                verificationResults.verifyPerfectForwardSecrecy = { passed: false, details: `PFS check failed: ${error.message}`, points: 0 };
            }
            
            // 8. Nested encryption verification (5 points) - All features enabled by default
            if (await EnhancedSecureCryptoUtils.verifyNestedEncryption(securityManager)) {
                score += 5;
                verificationResults.nestedEncryption = { passed: true, details: 'Nested encryption active', points: 5 };
            } else {
                verificationResults.nestedEncryption = { passed: false, details: 'Nested encryption failed', points: 0 };
            }
            
            // 9. Packet padding verification (5 points) - All features enabled by default
            if (await EnhancedSecureCryptoUtils.verifyPacketPadding(securityManager)) {
                score += 5;
                verificationResults.packetPadding = { passed: true, details: 'Packet padding active', points: 5 };
            } else {
                verificationResults.packetPadding = { passed: false, details: 'Packet padding failed', points: 0 };
            }
            
            // 10. Advanced features verification (10 points) - All features enabled by default
            if (await EnhancedSecureCryptoUtils.verifyAdvancedFeatures(securityManager)) {
                score += 10;
                verificationResults.advancedFeatures = { passed: true, details: 'Advanced features active', points: 10 };
            } else {
                verificationResults.advancedFeatures = { passed: false, details: 'Advanced features failed', points: 0 };
            }
            
            const percentage = Math.round((score / maxScore) * 100);
            
            // All security features are available - no restrictions
            const availableChecks = 10; // All 10 security checks available
            const passedChecks = Object.values(verificationResults).filter(r => r.passed).length;
            
            const result = {
                level: percentage >= 85 ? 'HIGH' : percentage >= 65 ? 'MEDIUM' : percentage >= 35 ? 'LOW' : 'CRITICAL',
                score: percentage,
                color: percentage >= 85 ? 'green' : percentage >= 65 ? 'orange' : percentage >= 35 ? 'yellow' : 'red',
                verificationResults,
                timestamp: Date.now(),
                details: `Real verification: ${score}/${maxScore} security checks passed (${passedChecks}/${availableChecks} available)`,
                isRealData: true,
                passedChecks: passedChecks,
                totalChecks: availableChecks,
                sessionType: sessionType,
                maxPossibleScore: 100 // All features enabled - max 100 points
            };

            
            return result;
        } catch (error) {
            console.error('Security level calculation failed:', error.message);
            return {
                level: 'UNKNOWN',
                score: 0,
                color: 'red',
                verificationResults: {},
                timestamp: Date.now(),
                details: `Verification failed: ${error.message}`,
                isRealData: false
            };
        }
    }

    // Real verification functions
    static async verifyEncryption(securityManager) {
        try {
            if (!securityManager.encryptionKey) {
                return { passed: false, details: 'No encryption key available' };
            }
            
            // Test actual encryption/decryption with multiple data types
            const testCases = [
                'Test encryption verification',
                'Русский текст для проверки',
                'Special chars: !@#$%^&*()_+-=[]{}|;:,.<>?',
                'Large data: ' + 'A'.repeat(1000)
            ];
            
            for (const testData of testCases) {
            const encoder = new TextEncoder();
            const testBuffer = encoder.encode(testData);
            const iv = crypto.getRandomValues(new Uint8Array(12));
            
            const encrypted = await crypto.subtle.encrypt(
                { name: 'AES-GCM', iv },
                securityManager.encryptionKey,
                testBuffer
            );
            
            const decrypted = await crypto.subtle.decrypt(
                { name: 'AES-GCM', iv },
                securityManager.encryptionKey,
                encrypted
            );
            
            const decryptedText = new TextDecoder().decode(decrypted);
                if (decryptedText !== testData) {
                    return { passed: false, details: `Decryption mismatch for: ${testData.substring(0, 20)}...` };
                }
            }
            
            return { passed: true, details: 'AES-GCM encryption/decryption working correctly' };
        } catch (error) {
            console.error('Encryption verification failed:', error.message);
            return { passed: false, details: `Encryption test failed: ${error.message}` };
        }
    }
    
    static async verifyECDHKeyExchange(securityManager) {
        try {
            if (!securityManager.ecdhKeyPair || !securityManager.ecdhKeyPair.privateKey || !securityManager.ecdhKeyPair.publicKey) {
                return { passed: false, details: 'No ECDH key pair available' };
            }
            
            // Test that keys are actually ECDH keys
            const keyType = securityManager.ecdhKeyPair.privateKey.algorithm.name;
            const curve = securityManager.ecdhKeyPair.privateKey.algorithm.namedCurve;
            
            if (keyType !== 'ECDH') {
                return { passed: false, details: `Invalid key type: ${keyType}, expected ECDH` };
            }
            
            if (curve !== 'P-384' && curve !== 'P-256') {
                return { passed: false, details: `Unsupported curve: ${curve}, expected P-384 or P-256` };
            }
            
            // Test key derivation
            try {
                const derivedKey = await crypto.subtle.deriveKey(
                    { name: 'ECDH', public: securityManager.ecdhKeyPair.publicKey },
                    securityManager.ecdhKeyPair.privateKey,
                    { name: 'AES-GCM', length: 256 },
                    false,
                    ['encrypt', 'decrypt']
                );
                
                if (!derivedKey) {
                    return { passed: false, details: 'Key derivation failed' };
                }
            } catch (deriveError) {
                return { passed: false, details: `Key derivation test failed: ${deriveError.message}` };
            }
            
            return { passed: true, details: `ECDH key exchange working with ${curve} curve` };
        } catch (error) {
            console.error('ECDH verification failed:', error.message);
            return { passed: false, details: `ECDH test failed: ${error.message}` };
        }
    }
    
    static async verifyECDSASignatures(securityManager) {
        try {
            if (!securityManager.ecdsaKeyPair || !securityManager.ecdsaKeyPair.privateKey || !securityManager.ecdsaKeyPair.publicKey) {
                return { passed: false, details: 'No ECDSA key pair available' };
            }
            
            // Test actual signing and verification with multiple test cases
            const testCases = [
                'Test ECDSA signature verification',
                'Русский текст для подписи',
                'Special chars: !@#$%^&*()_+-=[]{}|;:,.<>?',
                'Large data: ' + 'B'.repeat(2000)
            ];
            
            for (const testData of testCases) {
            const encoder = new TextEncoder();
            const testBuffer = encoder.encode(testData);
            
            const signature = await crypto.subtle.sign(
                { name: 'ECDSA', hash: 'SHA-256' },
                securityManager.ecdsaKeyPair.privateKey,
                testBuffer
            );
            
            const isValid = await crypto.subtle.verify(
                { name: 'ECDSA', hash: 'SHA-256' },
                securityManager.ecdsaKeyPair.publicKey,
                signature,
                testBuffer
            );
            
                if (!isValid) {
                    return { passed: false, details: `Signature verification failed for: ${testData.substring(0, 20)}...` };
                }
            }
            
            return { passed: true, details: 'ECDSA digital signatures working correctly' };
        } catch (error) {
            console.error('ECDSA verification failed:', error.message);
            return { passed: false, details: `ECDSA test failed: ${error.message}` };
        }
    }
    
    static async verifyMessageIntegrity(securityManager) {
        try {
            // Check if macKey exists and is a valid CryptoKey
            if (!securityManager.macKey || !(securityManager.macKey instanceof CryptoKey)) {
                return { passed: false, details: 'MAC key not available or invalid' };
            }
            
            // Test message integrity with HMAC using multiple test cases
            const testCases = [
                'Test message integrity verification',
                'Русский текст для проверки целостности',
                'Special chars: !@#$%^&*()_+-=[]{}|;:,.<>?',
                'Large data: ' + 'C'.repeat(3000)
            ];
            
            for (const testData of testCases) {
            const encoder = new TextEncoder();
            const testBuffer = encoder.encode(testData);
            
            const hmac = await crypto.subtle.sign(
                { name: 'HMAC', hash: 'SHA-256' },
                securityManager.macKey,
                testBuffer
            );
            
            const isValid = await crypto.subtle.verify(
                { name: 'HMAC', hash: 'SHA-256' },
                securityManager.macKey,
                hmac,
                testBuffer
            );
            
                if (!isValid) {
                    return { passed: false, details: `HMAC verification failed for: ${testData.substring(0, 20)}...` };
                }
            }
            
            return { passed: true, details: 'Message integrity (HMAC) working correctly' };
        } catch (error) {
            console.error('Message integrity verification failed:', error.message);
            return { passed: false, details: `Message integrity test failed: ${error.message}` };
        }
    }
    
    // Additional verification functions.
    //
    // These used to be three `return { passed: true }` stubs — a quarter of the
    // reported score awarded for checks that never ran, under a UI that calls the
    // result "Real cryptographic tests". A security indicator that cannot fail
    // tells the user nothing; worse, it keeps reading green after the subsystem
    // it claims to measure breaks. Each one below now exercises the thing it
    // names and is expected to be able to fail.

    static async verifyRateLimiting(securityManager) {
        try {
            const limiter = EnhancedSecureCryptoUtils.rateLimiter;
            if (!limiter || typeof limiter.checkMessageRate !== 'function') {
                return { passed: false, details: 'Rate limiter is not available' };
            }

            // Drive a throwaway bucket past its limit and confirm it actually
            // refuses. A separate identifier per run keeps the live counters
            // untouched, so running the report never costs the user quota.
            const probeId = `selftest_${crypto.getRandomValues(new Uint32Array(1))[0]}`;
            const limit = 3;
            for (let i = 0; i < limit; i++) {
                const allowed = await limiter.checkMessageRate(probeId, limit, 60000);
                if (!allowed) {
                    return { passed: false, details: `Rate limiter refused message ${i + 1} of ${limit} while under the limit` };
                }
            }

            const shouldBeBlocked = await limiter.checkMessageRate(probeId, limit, 60000);
            limiter.messages.delete(`msg_${probeId}`);

            if (shouldBeBlocked) {
                return { passed: false, details: 'Rate limiter did not block a message over the limit' };
            }

            return { passed: true, details: `Rate limiting verified: ${limit} allowed, the next refused` };
        } catch (error) {
            return { passed: false, details: `Rate limiting test failed: ${error.message}` };
        }
    }

    static async verifyMetadataProtection(securityManager) {
        try {
            const metadataKey = securityManager?.metadataKey;
            if (!metadataKey || !(metadataKey instanceof CryptoKey)) {
                return { passed: false, details: 'Metadata encryption key not available' };
            }
            if (metadataKey.algorithm?.name !== 'AES-GCM') {
                return { passed: false, details: `Metadata key has the wrong algorithm: ${metadataKey.algorithm?.name}` };
            }
            if (metadataKey.extractable) {
                return { passed: false, details: 'Metadata key is extractable' };
            }

            // Key separation is the whole point: message metadata (ids, sequence
            // numbers, real lengths) must not be readable with the message key.
            if (securityManager.encryptionKey === metadataKey) {
                return { passed: false, details: 'Metadata key is not separated from the message key' };
            }

            // Round-trip a probe so a key that exists but cannot be used is caught.
            const iv = crypto.getRandomValues(new Uint8Array(12));
            const probe = new TextEncoder().encode('metadata-protection-selftest');
            const sealed = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, metadataKey, probe);
            const opened = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, metadataKey, sealed);
            if (new TextDecoder().decode(opened) !== 'metadata-protection-selftest') {
                return { passed: false, details: 'Metadata encryption round-trip mismatch' };
            }

            return { passed: true, details: 'Metadata is encrypted under a separate non-extractable key' };
        } catch (error) {
            return { passed: false, details: `Metadata protection test failed: ${error.message}` };
        }
    }

    static async verifyPerfectForwardSecrecy(securityManager) {
        try {
            // Session-level PFS is real: every session runs a fresh ephemeral ECDH
            // and the derived keys are non-extractable and wiped when it ends.
            const hasEphemeralKeys = !!securityManager?.ecdhKeyPair?.privateKey &&
                securityManager.ecdhKeyPair.privateKey.extractable === false;
            if (!hasEphemeralKeys) {
                return { passed: false, details: 'No non-extractable ephemeral ECDH key pair for this session' };
            }

            // In-session forward secrecy comes from the Double Ratchet: a per-
            // message key derived by a one-way KDF and destroyed after use, plus a
            // DH step whenever the conversation changes direction. Without it a
            // single compromised session key opens the entire transcript, which is
            // the state this check used to report as "configured and active".
            if (securityManager?.isRatchetActive?.()) {
                const state = securityManager._ratchet?.getState?.() || {};
                return {
                    passed: true,
                    details: `Double Ratchet active: per-message keys destroyed after use, DH re-key on each reply (sent ${state.sendCount ?? 0}, received ${state.receiveCount ?? 0} on the current chain)`
                };
            }

            return {
                passed: false,
                details: 'Session-level PFS only: keys are ephemeral per session, but the Double Ratchet is not active for this connection (peer on an older version), so a compromised session key exposes the whole conversation'
            };
        } catch (error) {
            return { passed: false, details: `PFS test failed: ${error.message}` };
        }
    }

    static async verifyReplayProtection(securityManager) {
        try {
            // Debug logs removed to prevent leaking runtime state
            
            // Check if replay protection is enabled
            if (!securityManager.replayProtection) {
                return { passed: false, details: 'Replay protection not enabled' };
            }
            
            return { passed: true, details: 'Replay protection is working correctly' };
        } catch (error) {
            return { passed: false, details: `Replay protection test failed: ${error.message}` };
        }
    }
    
    static async verifyDTLSFingerprint(securityManager) {
        try {
            // Debug logs removed
            
            // Check if DTLS fingerprint is available
            if (!securityManager.dtlsFingerprint) {
                return { passed: false, details: 'DTLS fingerprint not available' };
            }
            
            return { passed: true, details: 'DTLS fingerprint is valid and available' };
        } catch (error) {
            return { passed: false, details: `DTLS fingerprint test failed: ${error.message}` };
        }
    }
    
    static async verifySASVerification(securityManager) {
        try {
            // Debug logs removed
            
            // Check if SAS code is available
            if (!securityManager.sasCode) {
                return { passed: false, details: 'SAS code not available' };
            }
            
            return { passed: true, details: 'SAS verification code is valid and available' };
        } catch (error) {
            return { passed: false, details: `SAS verification test failed: ${error.message}` };
        }
    }
    
    static async verifyTrafficObfuscation(securityManager) {
        try {
            // Debug logs removed
            
            // Check if traffic obfuscation is enabled
            if (!securityManager.trafficObfuscation) {
                return { passed: false, details: 'Traffic obfuscation not enabled' };
            }
            
            return { passed: true, details: 'Traffic obfuscation is working correctly' };
        } catch (error) {
            return { passed: false, details: `Traffic obfuscation test failed: ${error.message}` };
        }
    }
    
    static async verifyNestedEncryption(securityManager) {
        try {
            // Check if nestedEncryptionKey exists and is a valid CryptoKey
            if (!securityManager.nestedEncryptionKey || !(securityManager.nestedEncryptionKey instanceof CryptoKey)) {
                console.warn('Nested encryption key not available or invalid');
                return false;
            }
            
            // Test nested encryption
            const testData = 'Test nested encryption verification';
            const encoder = new TextEncoder();
            const testBuffer = encoder.encode(testData);
            
            // Simulate nested encryption
            const encrypted = await crypto.subtle.encrypt(
                { name: 'AES-GCM', iv: crypto.getRandomValues(new Uint8Array(12)) },
                securityManager.nestedEncryptionKey,
                testBuffer
            );
            
            return encrypted && encrypted.byteLength > 0;
        } catch (error) {
            console.error('Nested encryption verification failed:', error.message);
            return false;
        }
    }
    
    static async verifyPacketPadding(securityManager) {
        try {
            if (!securityManager.paddingConfig || !securityManager.paddingConfig.enabled) return false;
            
            // Test packet padding functionality
            const testData = 'Test packet padding verification';
            const encoder = new TextEncoder();
            const testBuffer = encoder.encode(testData);
            
            // Simulate packet padding
            const paddingSize = Math.floor(Math.random() * (securityManager.paddingConfig.maxPadding - securityManager.paddingConfig.minPadding)) + securityManager.paddingConfig.minPadding;
            const paddedData = new Uint8Array(testBuffer.byteLength + paddingSize);
            paddedData.set(new Uint8Array(testBuffer), 0);
            
            return paddedData.byteLength >= testBuffer.byteLength + securityManager.paddingConfig.minPadding;
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'Packet padding verification failed', { error: error.message });
            return false;
        }
    }
    
    static async verifyAdvancedFeatures(securityManager) {
        try {
            // Test advanced features like traffic obfuscation, fake traffic, etc.
            const hasFakeTraffic = securityManager.fakeTrafficConfig && securityManager.fakeTrafficConfig.enabled;
            const hasDecoyChannels = securityManager.decoyChannelsConfig && securityManager.decoyChannelsConfig.enabled;
            const hasAntiFingerprinting = securityManager.antiFingerprintingConfig && securityManager.antiFingerprintingConfig.enabled;
            
            return hasFakeTraffic || hasDecoyChannels || hasAntiFingerprinting;
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'Advanced features verification failed', { error: error.message });
            return false;
        }
    }
    
    static async verifyMutualAuth(securityManager) {
        try {
            if (!securityManager.isVerified || !securityManager.verificationCode) return false;
            
            // Test mutual authentication
            return securityManager.isVerified && securityManager.verificationCode.length > 0;
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'Mutual auth verification failed', { error: error.message });
            return false;
        }
    }
    
    
    static async verifyNonExtractableKeys(securityManager) {
        // This check was inverted: it returned true when exportKey SUCCEEDED —
        // i.e. when the key was extractable, the failure case — and also true in
        // the catch. It could not return false, so it confirmed nothing.
        const keys = [
            ['encryptionKey', securityManager?.encryptionKey],
            ['macKey', securityManager?.macKey],
            ['metadataKey', securityManager?.metadataKey]
        ];

        for (const [name, key] of keys) {
            if (!key || !(key instanceof CryptoKey)) {
                return false;
            }
            // `extractable` is the authoritative answer and needs no export
            // attempt; exporting a key just to prove it cannot be exported would
            // copy it into the JS heap on every implementation that allows it.
            if (key.extractable !== false) {
                EnhancedSecureCryptoUtils.secureLog.log('error', 'Session key is extractable', { keyName: name });
                return false;
            }
        }

        return true;
    }
    
    static async verifyEnhancedValidation(securityManager) {
        try {
            if (!securityManager.securityFeatures) return false;
            
            // Test enhanced validation features
            const hasValidation = securityManager.securityFeatures.hasEnhancedValidation || 
                                securityManager.securityFeatures.hasEnhancedReplayProtection;
            
            return hasValidation;
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'Enhanced validation verification failed', { error: error.message });
            return false;
        }
    }
    
    
    static async verifyPFS(securityManager) {
        try {
            // Check if PFS is active
            return securityManager.securityFeatures &&
                   securityManager.securityFeatures.hasPFS === true &&
                   securityManager.keyRotationInterval &&
                   securityManager.currentKeyVersion !== undefined &&
                   securityManager.keyVersions &&
                   securityManager.keyVersions instanceof Map;
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'PFS verification failed', { error: error.message });
            return false;
        }
    }

    // Rate limiting implementation
    static rateLimiter = {
    messages: new Map(),
    connections: new Map(),
    locks: new Map(),
    
    async checkMessageRate(identifier, limit = 60, windowMs = 60000) {
        if (typeof identifier !== 'string' || identifier.length > 256) {
            return false;
        }
        
        const key = `msg_${identifier}`;

        if (this.locks.has(key)) {

            await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 10) + 5));
            return this.checkMessageRate(identifier, limit, windowMs);
        }
        
        this.locks.set(key, true);
        
        try {
            const now = Date.now();
            
            if (!this.messages.has(key)) {
                this.messages.set(key, []);
            }
            
            const timestamps = this.messages.get(key);
            
            const validTimestamps = timestamps.filter(ts => now - ts < windowMs);
            
            if (validTimestamps.length >= limit) {
                return false; 
            }
            
            validTimestamps.push(now);
            this.messages.set(key, validTimestamps);
            return true;
        } finally {
            this.locks.delete(key);
        }
    },
    
    async checkConnectionRate(identifier, limit = 5, windowMs = 300000) {
        if (typeof identifier !== 'string' || identifier.length > 256) {
            return false;
        }
        
        const key = `conn_${identifier}`;
        
        if (this.locks.has(key)) {
            await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 10) + 5));
            return this.checkConnectionRate(identifier, limit, windowMs);
        }
        
        this.locks.set(key, true);
        
        try {
            const now = Date.now();
            
            if (!this.connections.has(key)) {
                this.connections.set(key, []);
            }
            
            const timestamps = this.connections.get(key);
            const validTimestamps = timestamps.filter(ts => now - ts < windowMs);
            
            if (validTimestamps.length >= limit) {
                return false;
            }
            
            validTimestamps.push(now);
            this.connections.set(key, validTimestamps);
            return true;
        } finally {
            this.locks.delete(key);
        }
    },
    
    cleanup() {
        const now = Date.now();
        const maxAge = 3600000; 
        
        for (const [key, timestamps] of this.messages.entries()) {
            if (this.locks.has(key)) continue;
            
            const valid = timestamps.filter(ts => now - ts < maxAge);
            if (valid.length === 0) {
                this.messages.delete(key);
            } else {
                this.messages.set(key, valid);
            }
        }
        
        for (const [key, timestamps] of this.connections.entries()) {
            if (this.locks.has(key)) continue;
            
            const valid = timestamps.filter(ts => now - ts < maxAge);
            if (valid.length === 0) {
                this.connections.delete(key);
            } else {
                this.connections.set(key, valid);
            }
        }

        for (const lockKey of this.locks.keys()) {
            const keyTimestamp = parseInt(lockKey.split('_').pop()) || 0;
            if (now - keyTimestamp > 30000) {
                this.locks.delete(lockKey);
            }
        }
    }
};

    static validateSalt(salt) {
        if (!salt || salt.length !== 64) {
            throw new Error('Salt must be exactly 64 bytes');
        }
        
        const uniqueBytes = new Set(salt);
        if (uniqueBytes.size < 16) {
            throw new Error('Salt has insufficient entropy');
        }
        
        return true;
    }

    // Secure logging without data leaks
    static secureLog = {
        logs: [],
        maxLogs: 100,
        isProductionMode: false,
        
        // Initialize production mode detection
        init() {
            this.isProductionMode = this._detectProductionMode();
            if (this.isProductionMode) {
                console.log('[SecureChat] Production mode detected - sensitive logging disabled');
            }
        },
        
        _detectProductionMode() {
            return (
                (typeof process !== 'undefined' && process.env?.NODE_ENV === 'production') ||
                (!window.DEBUG_MODE && !window.DEVELOPMENT_MODE) ||
                (window.location.hostname && !window.location.hostname.includes('localhost') && 
                 !window.location.hostname.includes('127.0.0.1') && 
                 !window.location.hostname.includes('.local')) ||
                (typeof window.webpackHotUpdate === 'undefined' && !window.location.search.includes('debug'))
            );
        },
        
        log(level, message, context = {}) {
            const sanitizedContext = this.sanitizeContext(context);
            const logEntry = {
                timestamp: Date.now(),
                level,
                message,
                context: sanitizedContext,
                id: crypto.getRandomValues(new Uint32Array(1))[0]
            };
            
            this.logs.push(logEntry);
            
            // Keep only recent logs
            if (this.logs.length > this.maxLogs) {
                this.logs = this.logs.slice(-this.maxLogs);
            }
            
            // Production-safe console output
            if (this.isProductionMode) {
                if (level === 'error') {
                    // In production expose only an opaque error code, never the context.
                    console.error(`❌ [SecureChat] ${message} [ERROR_CODE: ${this._generateErrorCode(message)}]`);
                } else if (level === 'warn') {
                    // Warning text only, no context payload.
                    console.warn(`⚠️ [SecureChat] ${message}`);
                } else {
                    // info/debug and any other level: suppressed entirely in production.
                    return;
                }
            } else {
                // Development mode - показываем все
                if (level === 'error') {
                    console.error(`❌ [SecureChat] ${message}`, { errorType: sanitizedContext?.constructor?.name || 'Unknown' });
                } else if (level === 'warn') {
                    console.warn(`⚠️ [SecureChat] ${message}`, { details: sanitizedContext });
                } else {
                    console.log(`[SecureChat] ${message}`, sanitizedContext);
                }
            }
        },
        
        // Генерирует безопасный код ошибки для production
        _generateErrorCode(message) {
            const hash = message.split('').reduce((a, b) => {
                a = ((a << 5) - a) + b.charCodeAt(0);
                return a & a;
            }, 0);
            return Math.abs(hash).toString(36).substring(0, 6).toUpperCase();
        },
        
        sanitizeContext(context) {
            if (!context || typeof context !== 'object') {
                return context;
            }
            
            const sensitivePatterns = [
                /key/i, /secret/i, /password/i, /token/i, /signature/i,
                /challenge/i, /proof/i, /salt/i, /iv/i, /nonce/i, /hash/i,
                /fingerprint/i, /mac/i, /private/i, /encryption/i, /decryption/i
            ];
            
            const sanitized = {};
            for (const [key, value] of Object.entries(context)) {
                const isSensitive = sensitivePatterns.some(pattern => 
                    pattern.test(key) || (typeof value === 'string' && pattern.test(value))
                );
                
                if (isSensitive) {
                    sanitized[key] = '[REDACTED]';
                } else if (typeof value === 'string' && value.length > 100) {
                    sanitized[key] = value.substring(0, 100) + '...[TRUNCATED]';
                } else if (value instanceof ArrayBuffer || value instanceof Uint8Array) {
                    sanitized[key] = `[${value.constructor.name}(${value.byteLength || value.length} bytes)]`;
                } else if (value && typeof value === 'object' && !Array.isArray(value)) {
                    // Рекурсивная санитизация для объектов
                    sanitized[key] = this.sanitizeContext(value);
                } else {
                    sanitized[key] = value;
                }
            }
            return sanitized;
        },
        
        getLogs(level = null) {
            if (level) {
                return this.logs.filter(log => log.level === level);
            }
            return [...this.logs];
        },
        
        clearLogs() {
            this.logs = [];
        },
        
        // Метод для отправки ошибок на сервер в production
        async sendErrorToServer(errorCode, message, context = {}) {
            if (!this.isProductionMode) {
                return; // В development не отправляем
            }
            
            try {
                // Отправляем только безопасную информацию
                const safeErrorData = {
                    errorCode,
                    timestamp: Date.now(),
                    userAgent: navigator.userAgent.substring(0, 100),
                    url: window.location.href.substring(0, 100)
                };
                
                // Здесь можно добавить отправку на сервер
                // await fetch('/api/error-log', { method: 'POST', body: JSON.stringify(safeErrorData) });
                
                if (window.DEBUG_MODE) {
                    console.log('[SecureChat] Error logged to server:', safeErrorData);
                }
            } catch (e) {
                // Не логируем ошибки логирования
            }
        }
    };

    // Generate ECDH key pair for secure key exchange (non-extractable) with fallback
    static async generateECDHKeyPair() {
        try {
            // Try P-384 first
            try {
                const keyPair = await crypto.subtle.generateKey(
                    {
                        name: 'ECDH',
                        namedCurve: 'P-384'
                    },
                    false, // Non-extractable for enhanced security
                    // 'deriveBits' is REQUIRED: deriveSharedKeys() uses deriveBits so
                    // the shared secret lands in a buffer we can overwrite, instead of
                    // being exported out of an extractable key and left in the heap.
                    // Without this usage WebCrypto rejects the derivation outright and
                    // no session can be established. Usages are local to the CryptoKey
                    // and are not part of the exported SPKI, so this does not change
                    // anything on the wire.
                    ['deriveKey', 'deriveBits']
                );

                // Removed key generation info logging to avoid exposing key-related metadata

                return keyPair;
            } catch (p384Error) {
                EnhancedSecureCryptoUtils.secureLog.log('warn', 'Elliptic curve P-384 generation failed, switching curve', { error: p384Error.message });

                // Fallback to P-256
                const keyPair = await crypto.subtle.generateKey(
                    {
                        name: 'ECDH',
                        namedCurve: 'P-256'
                    },
                    false, // Non-extractable for enhanced security
                    ['deriveKey', 'deriveBits']
                );
                
                // Removed key generation info logging to avoid exposing key-related metadata
                
                return keyPair;
            }
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'ECDH key generation failed', { error: error.message });
            throw new Error('Failed to create keys for secure exchange');
        }
    }

    // Generate ECDSA key pair for digital signatures with fallback
    static async generateECDSAKeyPair() {
        try {
            // Try P-384 first
            try {
                const keyPair = await crypto.subtle.generateKey(
                    {
                        name: 'ECDSA',
                        namedCurve: 'P-384'
                    },
                    false, // Non-extractable for enhanced security
                    ['sign', 'verify']
                );
                
                // Removed key generation info logging to avoid exposing key-related metadata
                
                return keyPair;
            } catch (p384Error) {
                EnhancedSecureCryptoUtils.secureLog.log('warn', 'Elliptic curve P-384 generation failed, switching curve', { error: p384Error.message });
                
                // Fallback to P-256
                const keyPair = await crypto.subtle.generateKey(
                    {
                        name: 'ECDSA',
                        namedCurve: 'P-256'
                    },
                    false, // Non-extractable for enhanced security
                    ['sign', 'verify']
                );
                
                // Removed key generation info logging to avoid exposing key-related metadata
                
                return keyPair;
            }
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'ECDSA key generation failed', { error: error.message });
            throw new Error('Failed to generate keys for digital signatures');
        }
    }

    // Sign data with ECDSA (P-384 or P-256)
    static async signData(privateKey, data) {
        try {
            const encoder = new TextEncoder();
            const dataBuffer = typeof data === 'string' ? encoder.encode(data) : data;
            
            // Try SHA-384 first, fallback to SHA-256
            try {
                const signature = await crypto.subtle.sign(
                    {
                        name: 'ECDSA',
                        hash: 'SHA-384'
                    },
                    privateKey,
                    dataBuffer
                );
                
                return Array.from(new Uint8Array(signature));
            } catch (sha384Error) {
                EnhancedSecureCryptoUtils.secureLog.log('warn', 'SHA-384 signing failed, trying SHA-256', { error: sha384Error.message });
                
                const signature = await crypto.subtle.sign(
                    {
                        name: 'ECDSA',
                        hash: 'SHA-256'
                    },
                    privateKey,
                    dataBuffer
                );
                
                return Array.from(new Uint8Array(signature));
            }
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'Data signing failed', { error: error.message });
            throw new Error('Failed to sign data');
        }
    }

    // Verify ECDSA signature (P-384 or P-256)
    static async verifySignature(publicKey, signature, data) {
        try {
            // Debug logs removed
            
            const encoder = new TextEncoder();
            const dataBuffer = typeof data === 'string' ? encoder.encode(data) : data;
            const signatureBuffer = new Uint8Array(signature);
            
            // Debug logs removed
            
            // Try SHA-384 first, fallback to SHA-256
            try {
                // Debug logs removed
                const isValid = await crypto.subtle.verify(
                    {
                        name: 'ECDSA',
                        hash: 'SHA-384'
                    },
                    publicKey,
                    signatureBuffer,
                    dataBuffer
                );
                
                // Debug logs removed
                
            // Removed signature verification info logging
                
                return isValid;
            } catch (sha384Error) {
                // Debug logs removed
                // Removed signature verification transition logging
                
                // Debug logs removed
                const isValid = await crypto.subtle.verify(
                    {
                        name: 'ECDSA',
                        hash: 'SHA-256'
                    },
                    publicKey,
                    signatureBuffer,
                    dataBuffer
                );
                
                // Debug logs removed
                
                // Removed signature verification info logging
                
                return isValid;
            }
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'Signature verification failed', { error: error.message });
            throw new Error('Failed to verify digital signature');
        }
    }

    // Enhanced DER/SPKI validation with full ASN.1 parsing
    static async validateKeyStructure(keyData, expectedAlgorithm = 'ECDH') {
        try {
            if (!Array.isArray(keyData) || keyData.length === 0) {
                throw new Error('Invalid key data format');
            }

            const keyBytes = new Uint8Array(keyData);

            // Size limits to prevent DoS
            if (keyBytes.length < 50) {
                throw new Error('Key data too short - invalid SPKI structure');
            }
            if (keyBytes.length > 2000) {
                throw new Error('Key data too long - possible attack');
            }

            // Parse ASN.1 DER structure
            const asn1 = EnhancedSecureCryptoUtils.parseASN1(keyBytes);
            
            // Validate SPKI structure
            if (!asn1 || asn1.tag !== 0x30) {
                throw new Error('Invalid SPKI structure - missing SEQUENCE tag');
            }

            // SPKI should have exactly 2 elements: AlgorithmIdentifier and BIT STRING
            if (asn1.children.length !== 2) {
                throw new Error(`Invalid SPKI structure - expected 2 elements, got ${asn1.children.length}`);
            }

            // Validate AlgorithmIdentifier
            const algIdentifier = asn1.children[0];
            if (algIdentifier.tag !== 0x30) {
                throw new Error('Invalid AlgorithmIdentifier - not a SEQUENCE');
            }

            // Parse algorithm OID
            const algOid = algIdentifier.children[0];
            if (algOid.tag !== 0x06) {
                throw new Error('Invalid algorithm OID - not an OBJECT IDENTIFIER');
            }

            // Validate algorithm OID based on expected algorithm
            const oidBytes = algOid.value;
            const oidString = EnhancedSecureCryptoUtils.oidToString(oidBytes);
            
            // Check for expected algorithms
            const validAlgorithms = {
                'ECDH': ['1.2.840.10045.2.1'], // id-ecPublicKey
                'ECDSA': ['1.2.840.10045.2.1'], // id-ecPublicKey (same as ECDH)
                'RSA': ['1.2.840.113549.1.1.1'], // rsaEncryption
                '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
            };

            const expectedOids = validAlgorithms[expectedAlgorithm];
            if (!expectedOids) {
                throw new Error(`Unknown algorithm: ${expectedAlgorithm}`);
            }

            if (!expectedOids.includes(oidString)) {
                throw new Error(`Invalid algorithm OID: expected ${expectedOids.join(' or ')}, got ${oidString}`);
            }

            // For EC algorithms, validate curve parameters
            if (expectedAlgorithm === 'ECDH' || expectedAlgorithm === 'ECDSA') {
                if (algIdentifier.children.length < 2) {
                    throw new Error('Missing curve parameters for EC key');
                }

                const curveOid = algIdentifier.children[1];
                if (curveOid.tag !== 0x06) {
                    throw new Error('Invalid curve OID - not an OBJECT IDENTIFIER');
                }

                const curveOidString = EnhancedSecureCryptoUtils.oidToString(curveOid.value);
                
                // Only allow P-256 and P-384 curves
                const validCurves = {
                    '1.2.840.10045.3.1.7': 'P-256', // secp256r1
                    '1.3.132.0.34': 'P-384' // secp384r1
                };

                if (!validCurves[curveOidString]) {
                    throw new Error(`Invalid or unsupported curve OID: ${curveOidString}`);
                }

            // Removed curve validation info logging
            }

            // Validate public key BIT STRING
            const publicKeyBitString = asn1.children[1];
            if (publicKeyBitString.tag !== 0x03) {
                throw new Error('Invalid public key - not a BIT STRING');
            }

            // Check for unused bits (should be 0 for public keys)
            if (publicKeyBitString.value[0] !== 0x00) {
                throw new Error(`Invalid BIT STRING - unexpected unused bits: ${publicKeyBitString.value[0]}`);
            }

            // For EC keys, validate point format
            if (expectedAlgorithm === 'ECDH' || expectedAlgorithm === 'ECDSA') {
                const pointData = publicKeyBitString.value.slice(1); // Skip unused bits byte
                
                // Check for uncompressed point format (0x04)
                if (pointData[0] !== 0x04) {
                    throw new Error(`Invalid EC point format: expected uncompressed (0x04), got 0x${pointData[0].toString(16)}`);
                }

                // Validate point size based on curve
                const expectedSizes = {
                    'P-256': 65, // 1 + 32 + 32
                    'P-384': 97  // 1 + 48 + 48
                };

                // We already validated the curve above, so we can determine expected size
                const curveOidString = EnhancedSecureCryptoUtils.oidToString(algIdentifier.children[1].value);
                const curveName = curveOidString === '1.2.840.10045.3.1.7' ? 'P-256' : 'P-384';
                const expectedSize = expectedSizes[curveName];

                if (pointData.length !== expectedSize) {
                    throw new Error(`Invalid EC point size for ${curveName}: expected ${expectedSize}, got ${pointData.length}`);
                }
            }

            // Additional validation: try to import the key
            try {
                const algorithm = expectedAlgorithm === 'ECDSA' || expectedAlgorithm === 'ECDH'
                    ? { name: expectedAlgorithm, namedCurve: 'P-384' }
                    : { name: expectedAlgorithm };

                const usages = expectedAlgorithm === 'ECDSA' ? ['verify'] : [];
                
                await crypto.subtle.importKey('spki', keyBytes.buffer, algorithm, false, usages);
            } catch (importError) {
                // Try P-256 as fallback for EC keys
                if (expectedAlgorithm === 'ECDSA' || expectedAlgorithm === 'ECDH') {
                    try {
                        const algorithm = { name: expectedAlgorithm, namedCurve: 'P-256' };
                        const usages = expectedAlgorithm === 'ECDSA' ? ['verify'] : [];
                        await crypto.subtle.importKey('spki', keyBytes.buffer, algorithm, false, usages);
                    } catch (fallbackError) {
                        throw new Error(`Key import validation failed: ${fallbackError.message}`);
                    }
                } else {
                    throw new Error(`Key import validation failed: ${importError.message}`);
                }
            }

            // Removed key structure validation info logging

            return true;
        } catch (err) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'Key structure validation failed', {
                error: err.message,
                algorithm: expectedAlgorithm
            });
            throw new Error(`Invalid key structure: ${err.message}`);
        }
    }

    // ASN.1 DER parser helper
    static parseASN1(bytes, offset = 0) {
        if (offset >= bytes.length) {
            return null;
        }

        const tag = bytes[offset];
        let lengthOffset = offset + 1;
        
        if (lengthOffset >= bytes.length) {
            throw new Error('Truncated ASN.1 structure');
        }

        let length = bytes[lengthOffset];
        let valueOffset = lengthOffset + 1;

        // Handle long form length
        if (length & 0x80) {
            const numLengthBytes = length & 0x7f;
            if (numLengthBytes > 4) {
                throw new Error('ASN.1 length too large');
            }
            
            length = 0;
            for (let i = 0; i < numLengthBytes; i++) {
                if (valueOffset + i >= bytes.length) {
                    throw new Error('Truncated ASN.1 length');
                }
                length = (length << 8) | bytes[valueOffset + i];
            }
            valueOffset += numLengthBytes;
        }

        if (valueOffset + length > bytes.length) {
            throw new Error('ASN.1 structure extends beyond data');
        }

        const value = bytes.slice(valueOffset, valueOffset + length);
        const node = {
            tag: tag,
            length: length,
            value: value,
            children: []
        };

        // Parse children for SEQUENCE and SET
        if (tag === 0x30 || tag === 0x31) {
            let childOffset = 0;
            while (childOffset < value.length) {
                const child = EnhancedSecureCryptoUtils.parseASN1(value, childOffset);
                if (!child) break;
                node.children.push(child);
                childOffset = childOffset + 1 + child.lengthBytes + child.length;
            }
        }

        // Calculate how many bytes were used for length encoding
        node.lengthBytes = valueOffset - lengthOffset;
        
        return node;
    }

    // OID decoder helper
    static oidToString(bytes) {
        if (!bytes || bytes.length === 0) {
            throw new Error('Empty OID');
        }

        const parts = [];
        
        // First byte encodes first two components
        const first = Math.floor(bytes[0] / 40);
        const second = bytes[0] % 40;
        parts.push(first);
        parts.push(second);

        // Decode remaining components
        let value = 0;
        for (let i = 1; i < bytes.length; i++) {
            value = (value << 7) | (bytes[i] & 0x7f);
            if (!(bytes[i] & 0x80)) {
                parts.push(value);
                value = 0;
            }
        }

        return parts.join('.');
    }

    // Helper to validate and sanitize OID string
    static validateOidString(oidString) {
        // OID format: digits separated by dots
        const oidRegex = /^[0-9]+(\.[0-9]+)*$/;
        if (!oidRegex.test(oidString)) {
            throw new Error(`Invalid OID format: ${oidString}`);
        }

        const parts = oidString.split('.').map(Number);
        
        // First component must be 0, 1, or 2
        if (parts[0] > 2) {
            throw new Error(`Invalid OID first component: ${parts[0]}`);
        }

        // If first component is 0 or 1, second must be <= 39
        if ((parts[0] === 0 || parts[0] === 1) && parts[1] > 39) {
            throw new Error(`Invalid OID second component: ${parts[1]} (must be <= 39 for first component ${parts[0]})`);
        }

        return true;
    }

    // Export public key for transmission with signature 
    static async exportPublicKeyWithSignature(publicKey, signingKey, keyType = 'ECDH') {
        try {
            // Validate key type
            if (!['ECDH', 'ECDSA'].includes(keyType)) {
                throw new Error('Invalid key type');
            }
            
            const exported = await crypto.subtle.exportKey('spki', publicKey);
            const keyData = Array.from(new Uint8Array(exported));
            
            await EnhancedSecureCryptoUtils.validateKeyStructure(keyData, keyType);
            
            // Create signed key package
            const keyPackage = {
                keyType,
                keyData,
                timestamp: Date.now(),
                version: '4.0'
            };
            
            // Sign the key package
            const packageString = JSON.stringify(keyPackage);
            const signature = await EnhancedSecureCryptoUtils.signData(signingKey, packageString);
            
            const signedPackage = {
                ...keyPackage,
                signature
            };
            
            // Removed public key export with signature info logging
            
            return signedPackage;
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'Public key export failed', {
                error: error.message,
                keyType
            });
            throw new Error(`Failed to export ${keyType} key: ${error.message}`);
        }
    }

    // Import and verify signed public key
    static async importSignedPublicKey(signedPackage, verifyingKey, expectedKeyType = 'ECDH') {
        try {
            // Debug logs removed
            
            // Validate package structure
            if (!signedPackage || typeof signedPackage !== 'object') {
                throw new Error('Invalid signed package format');
            }
            
            const { keyType, keyData, timestamp, version, signature } = signedPackage;
            
            if (!keyType || !keyData || !timestamp || !signature) {
                throw new Error('Missing required fields in signed package');
            }
            
            if (!EnhancedSecureCryptoUtils.constantTimeCompare(keyType, expectedKeyType)) {
                throw new Error(`Key type mismatch: expected ${expectedKeyType}, got ${keyType}`);
            }
            
            // Check timestamp (reject keys older than 1 hour)
            const keyAge = Date.now() - timestamp;
            if (keyAge > 3600000) {
                throw new Error('Signed key package is too old');
            }
            
            await EnhancedSecureCryptoUtils.validateKeyStructure(keyData, keyType);
            
            // Verify signature
            const packageCopy = { keyType, keyData, timestamp, version };
            const packageString = JSON.stringify(packageCopy);
            // Debug logs removed
            const isValidSignature = await EnhancedSecureCryptoUtils.verifySignature(verifyingKey, signature, packageString);
            // Debug logs removed
            
            if (!isValidSignature) {
                throw new Error('Invalid signature on key package - possible MITM attack');
            }
            
            // Import the key with fallback support
            const keyBytes = new Uint8Array(keyData);
            
            // Try P-384 first
            try {
                const algorithm = keyType === 'ECDH' ?
                    { name: 'ECDH', namedCurve: 'P-384' }
                    : { name: 'ECDSA', namedCurve: 'P-384' };
                
                const keyUsages = keyType === 'ECDH' ? [] : ['verify'];
                
                const publicKey = await crypto.subtle.importKey(
                    'spki',
                    keyBytes,
                    algorithm,
                    false, // Non-extractable
                    keyUsages
                );
                
            // Removed public key import info logging
                
                return publicKey;
            } catch (p384Error) {
                // Fallback to P-256
                EnhancedSecureCryptoUtils.secureLog.log('warn', 'Elliptic curve P-384 import failed, switching curve', { error: p384Error.message });
                
                const algorithm = keyType === 'ECDH' ?
                    { name: 'ECDH', namedCurve: 'P-256' }
                    : { name: 'ECDSA', namedCurve: 'P-256' };
                
                const keyUsages = keyType === 'ECDH' ? [] : ['verify'];
                
                const publicKey = await crypto.subtle.importKey(
                    'spki',
                    keyBytes,
                    algorithm,
                    false, // Non-extractable
                    keyUsages
                );
                
                // Removed public key import info logging
                
                return publicKey;
            }
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'Signed public key import failed', {
                error: error.message,
                expectedKeyType
            });
            throw new Error(`Failed to import the signed key: ${error.message}`);
        }
    }

    // Legacy export for backward compatibility
    static async exportPublicKey(publicKey) {
        try {
            const exported = await crypto.subtle.exportKey('spki', publicKey);
            const keyData = Array.from(new Uint8Array(exported));
            
            await EnhancedSecureCryptoUtils.validateKeyStructure(keyData, 'ECDH');
            
            // Removed legacy public key export info logging
            return keyData;
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'Legacy public key export failed', { error: error.message });
            throw new Error('Failed to export the public key');
        }
    }

    // Legacy import for backward compatibility with fallback
    static async importPublicKey(keyData) {
        try {
            await EnhancedSecureCryptoUtils.validateKeyStructure(keyData, 'ECDH');
            
            const keyBytes = new Uint8Array(keyData);
            
            // Try P-384 first
            try {
                const publicKey = await crypto.subtle.importKey(
                    'spki',
                    keyBytes,
                    {
                        name: 'ECDH',
                        namedCurve: 'P-384'
                    },
                    false, // Non-extractable
                    []
                );
                
                // Removed legacy public key import info logging
                return publicKey;
            } catch (p384Error) {
                EnhancedSecureCryptoUtils.secureLog.log('warn', 'P-384 import failed, trying P-256', { error: p384Error.message });
                
                // Fallback to P-256
                const publicKey = await crypto.subtle.importKey(
                    'spki',
                    keyBytes,
                    {
                        name: 'ECDH',
                        namedCurve: 'P-256'
                    },
                    false, // Non-extractable
                    []
                );
                
                // Removed legacy public key import info logging
                return publicKey;
            }
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'Legacy public key import failed', { error: error.message });
            throw new Error('Failed to import the public key');
        }
    }


    // Method to check if a key is trusted
    static isKeyTrusted(keyOrFingerprint) {
    if (keyOrFingerprint instanceof CryptoKey) {
        const meta = EnhancedSecureCryptoUtils._keyMetadata.get(keyOrFingerprint);
        return meta ? meta.trusted === true : false;
        } else if (keyOrFingerprint && keyOrFingerprint._securityMetadata) {
            // Check by key metadata
            return keyOrFingerprint._securityMetadata.trusted === true;
        }

        return false;
    }

    static async importPublicKeyFromSignedPackage(signedPackage, verifyingKey = null, options = {}) {
        try {
            if (!signedPackage || !signedPackage.keyData || !signedPackage.signature) {
                throw new Error('Invalid signed key package format');
            }

            // Validate all required fields are present
            const requiredFields = ['keyData', 'signature', 'keyType', 'timestamp', 'version'];
            const missingFields = requiredFields.filter(field => !signedPackage[field]);

            if (missingFields.length > 0) {
                EnhancedSecureCryptoUtils.secureLog.log('error', 'Missing required fields in signed package', {
                    missingFields: missingFields,
                    availableFields: Object.keys(signedPackage)
                });
                throw new Error(`Required fields are missing in the signed package: ${missingFields.join(', ')}`);
            }

            // SECURITY ENHANCEMENT: MANDATORY signature verification for signed packages
            if (!verifyingKey) {
                EnhancedSecureCryptoUtils.secureLog.log('error', 'SECURITY VIOLATION: Signed package received without verifying key', {
                    keyType: signedPackage.keyType,
                    keySize: signedPackage.keyData.length,
                    timestamp: signedPackage.timestamp,
                    version: signedPackage.version,
                    securityRisk: 'HIGH - Potential MITM attack vector'
                });

                // REJECT the signed package if no verifying key provided
                throw new Error('CRITICAL SECURITY ERROR: Signed key package received without a verification key. ' +
                                'This may indicate a possible MITM attack attempt. Import rejected for security reasons.');
            }

            // ОБНОВЛЕНО: Используем улучшенную валидацию
            await EnhancedSecureCryptoUtils.validateKeyStructure(signedPackage.keyData, signedPackage.keyType || 'ECDH');

            // MANDATORY signature verification when verifyingKey is provided
            const packageCopy = { ...signedPackage };
            delete packageCopy.signature;
            const packageString = JSON.stringify(packageCopy);
            const isValidSignature = await EnhancedSecureCryptoUtils.verifySignature(verifyingKey, signedPackage.signature, packageString);

            if (!isValidSignature) {
                EnhancedSecureCryptoUtils.secureLog.log('error', 'SECURITY BREACH: Invalid signature detected - MITM attack prevented', {
                    keyType: signedPackage.keyType,
                    keySize: signedPackage.keyData.length,
                    timestamp: signedPackage.timestamp,
                    version: signedPackage.version,
                    attackPrevented: true
                });
                throw new Error('CRITICAL SECURITY ERROR: Invalid key signature detected. ' +
                                'This indicates a possible MITM attack attempt. Key import rejected.');
            }

            // Additional MITM protection: Check for key reuse and suspicious patterns
            const keyFingerprint = await EnhancedSecureCryptoUtils.calculateKeyFingerprint(signedPackage.keyData);

            // Log successful verification with security details
            // Removed signature verification pass details to avoid key-related logging

            // Import the public key with fallback
            const keyBytes = new Uint8Array(signedPackage.keyData);
            const keyType = signedPackage.keyType || 'ECDH';

            // Try P-384 first
            try {
                const publicKey = await crypto.subtle.importKey(
                    'spki',
                    keyBytes,
                    {
                        name: keyType,
                        namedCurve: 'P-384'
                    },
                    false, // Non-extractable
                    keyType === 'ECDSA' ? ['verify'] : []
                );

                // Use WeakMap to store metadata
                EnhancedSecureCryptoUtils._keyMetadata.set(publicKey, {
                    trusted: true,
                    verificationStatus: 'VERIFIED_SECURE',
                    verificationTimestamp: Date.now()
                });

                return publicKey;
            } catch (p384Error) {
                EnhancedSecureCryptoUtils.secureLog.log('warn', 'P-384 import failed, trying P-256', { error: p384Error.message });

                // Fallback to P-256
                const publicKey = await crypto.subtle.importKey(
                    'spki',
                    keyBytes,
                    {
                        name: keyType,
                        namedCurve: 'P-256'
                    },
                    false, // Non-extractable
                    keyType === 'ECDSA' ? ['verify'] : []
                );

                // Use WeakMap to store metadata
                EnhancedSecureCryptoUtils._keyMetadata.set(publicKey, {
                    trusted: true,
                    verificationStatus: 'VERIFIED_SECURE',
                    verificationTimestamp: Date.now()
                });

                return publicKey;
            }
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'Signed package key import failed', {
                error: error.message,
                securityImplications: 'Potential security breach prevented'
            });
            throw new Error(`Failed to import the public key from the signed package: ${error.message}`);
        }
    }

    // Enhanced key derivation with metadata protection and 64-byte salt
    static async deriveSharedKeys(privateKey, publicKey, salt) {
        try {
            // Removed detailed key derivation logging
            
            // Validate input parameters are CryptoKey instances
            if (!(privateKey instanceof CryptoKey)) {
                EnhancedSecureCryptoUtils.secureLog.log('error', 'Private key is not a CryptoKey', {
                    privateKeyType: typeof privateKey,
                    privateKeyAlgorithm: privateKey?.algorithm?.name
                });
                throw new Error('The private key is not a valid CryptoKey.');
            }
            
            if (!(publicKey instanceof CryptoKey)) {
                EnhancedSecureCryptoUtils.secureLog.log('error', 'Public key is not a CryptoKey', {
                    publicKeyType: typeof publicKey,
                    publicKeyAlgorithm: publicKey?.algorithm?.name
                });
                throw new Error('The public key is not a valid CryptoKey.');
            }
            
            // Validate salt size (should be 64 bytes for enhanced security)
            if (!salt || salt.length !== 64) {
                throw new Error('Salt must be exactly 64 bytes for enhanced security');
            }
            
            const saltBytes = new Uint8Array(salt);
            const encoder = new TextEncoder();
            
            // Step 1: Derive the raw ECDH shared secret as HKDF input material.
            //
            // This used to derive an EXTRACTABLE AES-GCM key and then exportKey()
            // it, which put the shared secret into an ArrayBuffer that was never
            // cleared — it simply fell out of scope and sat in the JS heap until
            // GC, readable by anything with access to the page (a compromised
            // extension, a heap snapshot in a crash report). Every session key is
            // derived from those 32 bytes with public salt and hard-coded info
            // strings, so recovering them recovers the whole session.
            //
            // deriveBits gives the same bytes without the detour through an
            // extractable CryptoKey, and hands back a buffer we own and can wipe.
            // WIRE COMPATIBILITY: for ECDH, deriveBits(n) returns the leftmost n
            // bits of the shared X coordinate, which is exactly what deriveKey to
            // AES-GCM-256 used — so 256 here reproduces the previous bytes exactly
            // and a 5.6.1 client still interoperates with 5.6.0. Do not "improve"
            // this to 384 without a protocol version bump.
            let rawSharedSecret;
            let sharedSecretBits = null;
            try {
                sharedSecretBits = await crypto.subtle.deriveBits(
                    {
                        name: 'ECDH',
                        public: publicKey
                    },
                    privateKey,
                    256
                );

                rawSharedSecret = await crypto.subtle.importKey(
                    'raw',
                    sharedSecretBits,
                    {
                        name: 'HKDF',
                        hash: 'SHA-256'
                    },
                    false,
                    // deriveBits is required for the fingerprint material below;
                    // without it that call fails with an InvalidAccessError.
                    ['deriveKey', 'deriveBits']
                );
            } catch (error) {
                EnhancedSecureCryptoUtils.secureLog.log('error', 'ECDH derivation failed', {
                    error: error.message
                });
                throw error;
            } finally {
                // importKey copies the material, so the source buffer is dead
                // weight from here on — overwrite it rather than leaving the
                // shared secret lying in the heap.
                if (sharedSecretBits) {
                    EnhancedSecureCryptoUtils.zeroizeBuffer(sharedSecretBits);
                    sharedSecretBits = null;
                }
            }

            // Step 2: Use HKDF to derive specific keys directly
            // Removed detailed key derivation logging

            // Step 3: Derive specific keys using HKDF with unique info parameters
            // Each key uses unique info parameter for proper separation
            
            // Derive message encryption key (messageKey)
            let messageKey;
            messageKey = await crypto.subtle.deriveKey(
                {
                    name: 'HKDF',
                    hash: 'SHA-256',
                    salt: saltBytes,
                    info: encoder.encode('message-encryption-v4')
                },
                rawSharedSecret,
                {
                    name: 'AES-GCM',
                    length: 256
                },
                false, // Non-extractable for enhanced security
                ['encrypt', 'decrypt']
            );

            // Derive MAC key for message authentication
            let macKey;
            macKey = await crypto.subtle.deriveKey(
                {
                    name: 'HKDF',
                    hash: 'SHA-256',
                    salt: saltBytes,
                    info: encoder.encode('message-authentication-v4')
                },
                rawSharedSecret,
                {
                    name: 'HMAC',
                    hash: 'SHA-256'
                },
                false, // Non-extractable
                ['sign', 'verify']
            );

            // Derive Perfect Forward Secrecy key (pfsKey)
            let pfsKey;
            pfsKey = await crypto.subtle.deriveKey(
                {
                    name: 'HKDF',
                    hash: 'SHA-256',
                    salt: saltBytes,
                    info: encoder.encode('perfect-forward-secrecy-v4')
                },
                rawSharedSecret,
                {
                    name: 'AES-GCM',
                    length: 256
                },
                false, // Non-extractable
                ['encrypt', 'decrypt']
            );

            // Derive separate metadata encryption key
            let metadataKey;
            metadataKey = await crypto.subtle.deriveKey(
                {
                    name: 'HKDF',
                    hash: 'SHA-256',
                    salt: saltBytes,
                    info: encoder.encode('metadata-protection-v4')
                },
                rawSharedSecret,
                {
                    name: 'AES-GCM',
                    length: 256
                },
                false, // Non-extractable
                ['encrypt', 'decrypt']
            );

            // Root key for the Double Ratchet, derived here rather than handing the
            // raw ECDH secret to the caller: the secret is wiped before this
            // function returns (see the finally above), and only this 32-byte
            // branch of the KDF tree ever leaves. Its own info string keeps it
            // domain-separated from the message, MAC and metadata keys, so
            // learning a session key tells an attacker nothing about the ratchet.
            const ratchetRootBits = await crypto.subtle.deriveBits(
                {
                    name: 'HKDF',
                    hash: 'SHA-256',
                    salt: saltBytes,
                    info: encoder.encode('double-ratchet-root-v1')
                },
                rawSharedSecret,
                256
            );
            const ratchetRoot = new Uint8Array(ratchetRootBits);

            // Fingerprint material. Previously this derived a second EXTRACTABLE
            // AES key purely so it could be exported — leaving another copy of
            // key-derived material in the heap with nothing wiping it. HKDF can
            // hand back raw bits directly; same salt, same info, same 256 bits, so
            // the fingerprint (and therefore the SAS built on it) is unchanged.
            let fingerprintBits = null;
            let fingerprint;
            try {
                fingerprintBits = await crypto.subtle.deriveBits(
                    {
                        name: 'HKDF',
                        hash: 'SHA-256',
                        salt: saltBytes,
                        info: encoder.encode('fingerprint-generation-v4')
                    },
                    rawSharedSecret,
                    256
                );
                // A Uint8Array view, not Array.from(): the array copy was a third
                // copy of key-derived bytes in the heap that nothing cleared.
                fingerprint = await EnhancedSecureCryptoUtils.generateKeyFingerprint(
                    new Uint8Array(fingerprintBits)
                );
            } finally {
                if (fingerprintBits) {
                    EnhancedSecureCryptoUtils.zeroizeBuffer(fingerprintBits);
                    fingerprintBits = null;
                }
            }

            // Validate that all derived keys are CryptoKey instances
            if (!(messageKey instanceof CryptoKey)) {
                EnhancedSecureCryptoUtils.secureLog.log('error', 'Derived message key is not a CryptoKey', {
                    messageKeyType: typeof messageKey,
                    messageKeyAlgorithm: messageKey?.algorithm?.name
                });
                throw new Error('The derived message key is not a valid CryptoKey.');
            }
            
            if (!(macKey instanceof CryptoKey)) {
                EnhancedSecureCryptoUtils.secureLog.log('error', 'Derived MAC key is not a CryptoKey', {
                    macKeyType: typeof macKey,
                    macKeyAlgorithm: macKey?.algorithm?.name
                });
                throw new Error('The derived MAC key is not a valid CryptoKey.');
            }
            
            if (!(pfsKey instanceof CryptoKey)) {
                EnhancedSecureCryptoUtils.secureLog.log('error', 'Derived PFS key is not a CryptoKey', {
                    pfsKeyType: typeof pfsKey,
                    pfsKeyAlgorithm: pfsKey?.algorithm?.name
                });
                throw new Error('The derived PFS key is not a valid CryptoKey.');
            }
            
            if (!(metadataKey instanceof CryptoKey)) {
                EnhancedSecureCryptoUtils.secureLog.log('error', 'Derived metadata key is not a CryptoKey', {
                    metadataKeyType: typeof metadataKey,
                    metadataKeyAlgorithm: metadataKey?.algorithm?.name
                });
                throw new Error('The derived metadata key is not a valid CryptoKey.');
            }

            // Removed detailed key derivation success logging

            return {
                messageKey,      // Renamed from encryptionKey for clarity
                macKey,
                pfsKey,         // Added Perfect Forward Secrecy key
                metadataKey,
                // Raw bytes on purpose: a ratchet has to chain KDFs itself, which
                // WebCrypto cannot do behind a non-extractable handle. The caller
                // must hand this to DoubleRatchet.init() and zeroize it.
                ratchetRoot,
                fingerprint,
                timestamp: Date.now(),
                version: '4.0'
            };
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'Enhanced key derivation failed', { 
                error: error.message,
                errorStack: error.stack,
                privateKeyType: typeof privateKey,
                publicKeyType: typeof publicKey,
                saltLength: salt?.length,
                privateKeyAlgorithm: privateKey?.algorithm?.name,
                publicKeyAlgorithm: publicKey?.algorithm?.name
            });
            throw new Error(`Failed to create shared encryption keys: ${error.message}`);
        }
    }

    static async generateKeyFingerprint(keyData) {
        const keyBuffer = new Uint8Array(keyData);
        const hashBuffer = await crypto.subtle.digest('SHA-384', keyBuffer);
        const hashArray = Array.from(new Uint8Array(hashBuffer));
        return hashArray.slice(0, 12).map(b => b.toString(16).padStart(2, '0')).join(':');
    }

    // Generate mutual authentication challenge
    static generateMutualAuthChallenge() {
        const challenge = crypto.getRandomValues(new Uint8Array(48)); // Increased to 48 bytes
        const timestamp = Date.now();
        const nonce = crypto.getRandomValues(new Uint8Array(16));
        
        return {
            challenge: Array.from(challenge),
            timestamp,
            nonce: Array.from(nonce),
            version: '4.0'
        };
    }

    // Create cryptographic proof for mutual authentication
    static async createAuthProof(challenge, privateKey, publicKey) {
        try {
            if (!challenge || !challenge.challenge || !challenge.timestamp || !challenge.nonce) {
                throw new Error('Invalid challenge structure');
            }
            
            // Check challenge age (max 2 minutes)
            const challengeAge = Date.now() - challenge.timestamp;
            if (challengeAge > 120000) {
                throw new Error('Challenge expired');
            }
            
            // Create proof data
            const proofData = {
                challenge: challenge.challenge,
                timestamp: challenge.timestamp,
                nonce: challenge.nonce,
                responseTimestamp: Date.now(),
                publicKeyHash: await EnhancedSecureCryptoUtils.hashPublicKey(publicKey)
            };
            
            // Sign the proof
            const proofString = JSON.stringify(proofData);
            const signature = await EnhancedSecureCryptoUtils.signData(privateKey, proofString);
            
            const proof = {
                ...proofData,
                signature,
                version: '4.0'
            };
            
            EnhancedSecureCryptoUtils.secureLog.log('info', 'Authentication proof created', {
                challengeAge: Math.round(challengeAge / 1000) + 's'
            });
            
            return proof;
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'Authentication proof creation failed', { error: error.message });
            throw new Error(`Failed to create cryptographic proof: ${error.message}`);
        }
    }

    // Verify mutual authentication proof
    static async verifyAuthProof(proof, challenge, publicKey) {
        try {
            await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 20) + 5));
            // Assert the public key is valid and has the correct usage
            EnhancedSecureCryptoUtils.assertCryptoKey(publicKey, 'ECDSA', ['verify']);

            if (!proof || !challenge || !publicKey) {
                throw new Error('Missing required parameters for proof verification');
            }

            // Validate proof structure
            const requiredFields = ['challenge', 'timestamp', 'nonce', 'responseTimestamp', 'publicKeyHash', 'signature'];
            for (const field of requiredFields) {
                if (!proof[field]) {
                    throw new Error(`Missing required field: ${field}`);
                }
            }

            // Verify challenge matches
            if (!EnhancedSecureCryptoUtils.constantTimeCompareArrays(proof.challenge, challenge.challenge) ||
                proof.timestamp !== challenge.timestamp ||
                !EnhancedSecureCryptoUtils.constantTimeCompareArrays(proof.nonce, challenge.nonce)) {
                throw new Error('Challenge mismatch - possible replay attack');
            }

            // Check response time (max 30 minutes for better UX)
            const responseAge = Date.now() - proof.responseTimestamp;
            if (responseAge > 1800000) {
                throw new Error('Proof response expired');
            }

            // Verify public key hash
            const expectedHash = await EnhancedSecureCryptoUtils.hashPublicKey(publicKey);
            if (!EnhancedSecureCryptoUtils.constantTimeCompare(proof.publicKeyHash, expectedHash)) {
                throw new Error('Public key hash mismatch');
            }

            // Verify signature
            const proofCopy = { ...proof };
            delete proofCopy.signature;
            const proofString = JSON.stringify(proofCopy);
            const isValidSignature = await EnhancedSecureCryptoUtils.verifySignature(publicKey, proof.signature, proofString);

            if (!isValidSignature) {
                throw new Error('Invalid proof signature');
            }

            EnhancedSecureCryptoUtils.secureLog.log('info', 'Authentication proof verified successfully', {
                responseAge: Math.round(responseAge / 1000) + 's'
            });

            return true;
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'Authentication proof verification failed', { error: error.message });
            throw new Error(`Failed to verify cryptographic proof: ${error.message}`);
        }
    }

    // Hash public key for verification
    static async hashPublicKey(publicKey) {
        try {
            const exported = await crypto.subtle.exportKey('spki', publicKey);
            const hash = await crypto.subtle.digest('SHA-384', exported);
            const hashArray = Array.from(new Uint8Array(hash));
            return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'Public key hashing failed', { error: error.message });
            throw new Error('Failed to create hash of the public key');
        }
    }

    // Legacy authentication challenge for backward compatibility
    static generateAuthChallenge() {
        const challenge = crypto.getRandomValues(new Uint8Array(32));
        return Array.from(challenge);
    }

    // Generate verification code for out-of-band authentication
    static generateVerificationCode() {
        const chars = '0123456789ABCDEF';
        const charCount = chars.length;
        let result = '';
        
        // Use rejection sampling to avoid bias
        for (let i = 0; i < 6; i++) {
            let randomByte;
            do {
                randomByte = crypto.getRandomValues(new Uint8Array(1))[0];
            } while (randomByte >= 256 - (256 % charCount)); // Reject biased values
            
            result += chars[randomByte % charCount];
        }
        
        return result.match(/.{1,2}/g).join('-');
    }

    // Enhanced message encryption with metadata protection and sequence numbers
    static async encryptMessage(message, encryptionKey, macKey, metadataKey, messageId, sequenceNumber = 0) {
        try {
            if (!message || typeof message !== 'string') {
                throw new Error('Invalid message format');
            }

            EnhancedSecureCryptoUtils.assertCryptoKey(encryptionKey, 'AES-GCM', ['encrypt']);
            EnhancedSecureCryptoUtils.assertCryptoKey(macKey, 'HMAC', ['sign']);
            EnhancedSecureCryptoUtils.assertCryptoKey(metadataKey, 'AES-GCM', ['encrypt']);

            const encoder = new TextEncoder();
            const messageData = encoder.encode(message);
            const messageIv = crypto.getRandomValues(new Uint8Array(12));
            const metadataIv = crypto.getRandomValues(new Uint8Array(12));
            const timestamp = Date.now();

            const paddingSize = 16 - (messageData.length % 16);
            const paddedMessage = new Uint8Array(messageData.length + paddingSize);
            paddedMessage.set(messageData);
            const padding = crypto.getRandomValues(new Uint8Array(paddingSize));
            paddedMessage.set(padding, messageData.length);

            const encryptedMessage = await crypto.subtle.encrypt(
                { name: 'AES-GCM', iv: messageIv },
                encryptionKey,
                paddedMessage
            );

            const metadata = {
                id: messageId,
                timestamp: timestamp,
                sequenceNumber: sequenceNumber,
                originalLength: messageData.length,
                version: '4.0'
            };

            const metadataStr = JSON.stringify(EnhancedSecureCryptoUtils.sortObjectKeys(metadata));
            const encryptedMetadata = await crypto.subtle.encrypt(
                { name: 'AES-GCM', iv: metadataIv },
                metadataKey,
                encoder.encode(metadataStr)
            );

            const payload = {
                messageIv: Array.from(messageIv),
                messageData: Array.from(new Uint8Array(encryptedMessage)),
                metadataIv: Array.from(metadataIv),
                metadataData: Array.from(new Uint8Array(encryptedMetadata)),
                version: '4.0'
            };

            const sortedPayload = EnhancedSecureCryptoUtils.sortObjectKeys(payload);
            const payloadStr = JSON.stringify(sortedPayload);

            const mac = await crypto.subtle.sign(
                'HMAC',
                macKey,
                encoder.encode(payloadStr)
            );

            payload.mac = Array.from(new Uint8Array(mac));

            // Logging removed to avoid noisy console output

            return payload;
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'Message encryption failed', {
                error: error.message,
                messageId
            });
            throw new Error(`Failed to encrypt the message: ${error.message}`);
        }
    }

    // Enhanced message decryption with metadata protection and sequence validation
    static async decryptMessage(encryptedPayload, encryptionKey, macKey, metadataKey, expectedSequenceNumber = null) {
        try {
            EnhancedSecureCryptoUtils.assertCryptoKey(encryptionKey, 'AES-GCM', ['decrypt']);
            EnhancedSecureCryptoUtils.assertCryptoKey(macKey, 'HMAC', ['verify']);
            EnhancedSecureCryptoUtils.assertCryptoKey(metadataKey, 'AES-GCM', ['decrypt']);

            const requiredFields = ['messageIv', 'messageData', 'metadataIv', 'metadataData', 'mac', 'version'];
            for (const field of requiredFields) {
                if (!encryptedPayload[field]) {
                    throw new Error(`Missing required field: ${field}`);
                }
            }

            const payloadCopy = { ...encryptedPayload };
            delete payloadCopy.mac;
            const sortedPayloadCopy = EnhancedSecureCryptoUtils.sortObjectKeys(payloadCopy);
            const payloadStr = JSON.stringify(sortedPayloadCopy);

            const macValid = await crypto.subtle.verify(
                'HMAC',
                macKey,
                new Uint8Array(encryptedPayload.mac),
                new TextEncoder().encode(payloadStr)
            );

            if (!macValid) {
                EnhancedSecureCryptoUtils.secureLog.log('error', 'MAC verification failed', {
                    payloadFields: Object.keys(encryptedPayload),
                    macLength: encryptedPayload.mac?.length
                });
                throw new Error('Message authentication failed - possible tampering');
            }

            const metadataIv = new Uint8Array(encryptedPayload.metadataIv);
            const metadataData = new Uint8Array(encryptedPayload.metadataData);

            const decryptedMetadataBuffer = await crypto.subtle.decrypt(
                { name: 'AES-GCM', iv: metadataIv },
                metadataKey,
                metadataData
            );

            const metadataStr = new TextDecoder().decode(decryptedMetadataBuffer);
            const metadata = JSON.parse(metadataStr);

            if (!metadata.id || !metadata.timestamp || metadata.sequenceNumber === undefined || !metadata.originalLength) {
                throw new Error('Invalid metadata structure');
            }

            const messageAge = Date.now() - metadata.timestamp;
            if (messageAge > 1800000) { // 30 minutes for better UX
                throw new Error('Message expired (older than 30 minutes)');
            }

            if (expectedSequenceNumber !== null) {
                // A sequence number below what we expect means the frame is a
                // replay (or badly out of order on a channel that is ordered and
                // reliable). Downgrading that to a warning and decrypting anyway
                // defeats the purpose of tracking sequence numbers at all.
                if (metadata.sequenceNumber < expectedSequenceNumber) {
                    EnhancedSecureCryptoUtils.secureLog.log('error', 'Rejected message with stale sequence number - possible replay', {
                        expected: expectedSequenceNumber,
                        received: metadata.sequenceNumber,
                        messageId: metadata.id
                    });
                    throw new Error(`Stale sequence number: expected at least ${expectedSequenceNumber}, got ${metadata.sequenceNumber}`);
                } else if (metadata.sequenceNumber > expectedSequenceNumber + 10) {
                    throw new Error(`Sequence number gap too large: expected around ${expectedSequenceNumber}, got ${metadata.sequenceNumber}`);
                }
            }

            const messageIv = new Uint8Array(encryptedPayload.messageIv);
            const messageData = new Uint8Array(encryptedPayload.messageData);

            const decryptedMessageBuffer = await crypto.subtle.decrypt(
                { name: 'AES-GCM', iv: messageIv },
                encryptionKey,
                messageData
            );

            const paddedMessage = new Uint8Array(decryptedMessageBuffer);
            const originalMessage = paddedMessage.slice(0, metadata.originalLength);

            const decoder = new TextDecoder();
            const message = decoder.decode(originalMessage);

            EnhancedSecureCryptoUtils.secureLog.log('info', 'Message decrypted successfully', {
                messageId: metadata.id,
                sequenceNumber: metadata.sequenceNumber,
                messageAge: Math.round(messageAge / 1000) + 's'
            });

            return {
                message: message,
                messageId: metadata.id,
                timestamp: metadata.timestamp,
                sequenceNumber: metadata.sequenceNumber
            };
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'Message decryption failed', { error: error.message });
            throw new Error(`Failed to decrypt the message: ${error.message}`);
        }
    }

    static _getMessageSanitizer() {
        if (EnhancedSecureCryptoUtils._messageSanitizer) {
            return EnhancedSecureCryptoUtils._messageSanitizer;
        }

        if (typeof window === 'undefined' || !window?.document) {
            throw new Error('DOMPurify requires a browser-like window for message sanitization');
        }

        EnhancedSecureCryptoUtils._messageSanitizer = createDOMPurify(window);
        return EnhancedSecureCryptoUtils._messageSanitizer;
    }

    // Centralized chat-message sanitization. Messages are rendered as plain text,
    // so the safest compatible output is text-only content with no markup surface.
    static sanitizeMessage(message) {
        if (typeof message !== 'string') {
            throw new Error('Message must be a string');
        }

        const sanitized = EnhancedSecureCryptoUtils._getMessageSanitizer().sanitize(message, {
            ALLOWED_TAGS: [],
            ALLOWED_ATTR: [],
            ALLOW_UNKNOWN_PROTOCOLS: false,
            FORBID_TAGS: ['script', 'style', 'svg', 'math', 'template'],
            FORBID_ATTR: ['style'],
            KEEP_CONTENT: true,
            RETURN_TRUSTED_TYPE: false,
            USE_PROFILES: {
                html: false,
                svg: false,
                svgFilters: false,
                mathMl: false
            }
        });

        return String(sanitized).trim().substring(0, 2000);
    }

    // Generate cryptographically secure salt (64 bytes for enhanced security)
    static generateSalt() {
        return Array.from(crypto.getRandomValues(new Uint8Array(64)));
    }

    // Calculate key fingerprint for MITM protection
    static async calculateKeyFingerprint(keyData) {
        try {
            const encoder = new TextEncoder();
            const keyBytes = new Uint8Array(keyData);
            
            // Create a hash of the key data for fingerprinting
            const hashBuffer = await crypto.subtle.digest('SHA-256', keyBytes);
            const hashArray = Array.from(new Uint8Array(hashBuffer));
            
            // Convert to hexadecimal string
            const fingerprint = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
            
            // Removed key fingerprint logging
            
            return fingerprint;
        } catch (error) {
            EnhancedSecureCryptoUtils.secureLog.log('error', 'Key fingerprint calculation failed', { error: error.message });
            throw new Error('Failed to compute the key fingerprint');
        }
    }

    static constantTimeCompare(a, b) {
        const strA = typeof a === 'string' ? a : JSON.stringify(a);
        const strB = typeof b === 'string' ? b : JSON.stringify(b);
        
        if (strA.length !== strB.length) {
            let dummy = 0;
            for (let i = 0; i < Math.max(strA.length, strB.length); i++) {
                dummy |= (strA.charCodeAt(i % strA.length) || 0) ^ (strB.charCodeAt(i % strB.length) || 0);
            }
            return false;
        }
        
        let result = 0;
        for (let i = 0; i < strA.length; i++) {
            result |= strA.charCodeAt(i) ^ strB.charCodeAt(i);
        }
        
        return result === 0;
    }

    static constantTimeCompareArrays(arr1, arr2) {
        if (!Array.isArray(arr1) || !Array.isArray(arr2)) {
            return false;
        }
        
        if (arr1.length !== arr2.length) {
            let dummy = 0;
            const maxLen = Math.max(arr1.length, arr2.length);
            for (let i = 0; i < maxLen; i++) {
                dummy |= (arr1[i % arr1.length] || 0) ^ (arr2[i % arr2.length] || 0);
            }
            return false;
        }
        
        let result = 0;
        for (let i = 0; i < arr1.length; i++) {
            result |= arr1[i] ^ arr2[i];
        }
        
        return result === 0;
    }
    
    /**
     * CRITICAL SECURITY: Encrypt data with AAD (Additional Authenticated Data)
     * This method provides authenticated encryption with additional data binding
     */
    static async encryptDataWithAAD(data, key, aad) {
        try {
            const dataString = typeof data === 'string' ? data : JSON.stringify(data);
            const encoder = new TextEncoder();
            const dataBuffer = encoder.encode(dataString);
            const aadBuffer = encoder.encode(aad);

            // Generate random IV
            const iv = crypto.getRandomValues(new Uint8Array(12));

            // Encrypt with AAD
            const encrypted = await crypto.subtle.encrypt(
                { 
                    name: 'AES-GCM', 
                    iv: iv,
                    additionalData: aadBuffer
                },
                key,
                dataBuffer
            );

            // Package encrypted data
            const encryptedPackage = {
                version: '1.0',
                iv: Array.from(iv),
                data: Array.from(new Uint8Array(encrypted)),
                aad: aad,
                timestamp: Date.now()
            };

            const packageString = JSON.stringify(encryptedPackage);
            const packageBuffer = encoder.encode(packageString);
            
            return EnhancedSecureCryptoUtils.arrayBufferToBase64(packageBuffer);
        } catch (error) {
            throw new Error(`AAD encryption failed: ${error.message}`);
        }
    }

    /**
     * CRITICAL SECURITY: Decrypt data with AAD validation
     * This method provides authenticated decryption with additional data validation
     */
    static async decryptDataWithAAD(encryptedData, key, expectedAad) {
        try {
            const packageBuffer = EnhancedSecureCryptoUtils.base64ToArrayBuffer(encryptedData);
            const packageString = new TextDecoder().decode(packageBuffer);
            const encryptedPackage = JSON.parse(packageString);

            if (!encryptedPackage.version || !encryptedPackage.iv || !encryptedPackage.data || !encryptedPackage.aad) {
                throw new Error('Invalid encrypted data format');
            }

            // Validate AAD matches expected
            if (encryptedPackage.aad !== expectedAad) {
                throw new Error('AAD mismatch - possible tampering or replay attack');
            }

            const iv = new Uint8Array(encryptedPackage.iv);
            const encrypted = new Uint8Array(encryptedPackage.data);
            const aadBuffer = new TextEncoder().encode(encryptedPackage.aad);

            // Decrypt with AAD validation
            const decrypted = await crypto.subtle.decrypt(
                { 
                    name: 'AES-GCM', 
                    iv: iv,
                    additionalData: aadBuffer
                },
                key,
                encrypted
            );

            const decryptedString = new TextDecoder().decode(decrypted);

            try {
                return JSON.parse(decryptedString);
            } catch {
                return decryptedString;
            }
        } catch (error) {
            throw new Error(`AAD decryption failed: ${error.message}`);
        }
    }

    // Initialize secure logging system after class definition
    static {
        if (EnhancedSecureCryptoUtils.secureLog && typeof EnhancedSecureCryptoUtils.secureLog.init === 'function') {
            EnhancedSecureCryptoUtils.secureLog.init();
        }
    }
}

export { EnhancedSecureCryptoUtils };
