From 3eae4f0210149c657d5f40759424ec3129b7362f Mon Sep 17 00:00:00 2001 From: NicolasCantu Date: Sun, 26 Oct 2025 02:28:33 +0100 Subject: [PATCH] feat: encrypt wallet completely and detect security mode from PBKDF2 key **Motivations :** - Encrypt all wallet data with PBKDF2 key, never store in clear - Detect security mode from available PBKDF2 key instead of using fallback - Stop page without fallback if no PBKDF2 key is available - Use existing PBKDF2 keys only, no generation **Modifications :** - wallet-setup.ts: Encrypt device data before storing, store only encrypted_device and encrypted_wallet - wallet-setup.ts: Detect security mode by testing all modes to find a working PBKDF2 key - wallet-setup.ts: Stop without fallback if no PBKDF2 key is found - wallet-setup.ts: Retrieve existing PBKDF2 key (no generation) - wallet-setup.ts: Remove separate security mode storage (already stored via PBKDF2 key in pbkdf2keys store) - wallet-setup.ts: Add verification to reject any wallet stored in clear - wallet-setup.ts: Fix IndexedDB inline key usage (remove explicit key parameter) **Pages affected :** - wallet-setup.html: Encrypts and stores only encrypted wallet data, detects security mode from PBKDF2 key --- src/pages/wallet-setup/wallet-setup.ts | 139 ++++++++++++++++++------- 1 file changed, 99 insertions(+), 40 deletions(-) diff --git a/src/pages/wallet-setup/wallet-setup.ts b/src/pages/wallet-setup/wallet-setup.ts index 9ad7c3d..815500b 100644 --- a/src/pages/wallet-setup/wallet-setup.ts +++ b/src/pages/wallet-setup/wallet-setup.ts @@ -152,15 +152,39 @@ document.addEventListener('DOMContentLoaded', async () => { try { console.log('🔐 Sauvegarde du wallet avec Ă©tat birthday_waiting...'); - // RĂ©cupĂ©rer le mode de sĂ©curitĂ© pour le chiffrement - const { SecurityModeService } = await import('../../services/security-mode.service'); - const securityModeService = SecurityModeService.getInstance(); - let currentMode = await securityModeService.getCurrentMode(); + // DÉTECTER le mode de sĂ©curitĂ© via la clĂ© PBKDF2 disponible + // Le mode de sĂ©curitĂ© est identifiĂ© par la clĂ© PBKDF2 qui fonctionne + const { SecureCredentialsService } = await import('../../services/secure-credentials.service'); + const secureCredentialsService = SecureCredentialsService.getInstance(); - // Si aucun mode n'est trouvĂ©, utiliser le mode par dĂ©faut + console.log('🔍 Testing all security modes to find a PBKDF2 key...'); + + // Tester tous les modes de sĂ©curitĂ© pour trouver une clĂ© PBKDF2 valide + const allSecurityModes: Array<'browser' | 'otp' | 'password' | 'none' | 'os' | 'proton-pass'> = + ['browser', 'otp', 'password', 'none', 'os', 'proton-pass']; + + let currentMode: string | null = null; + + for (const mode of allSecurityModes) { + console.log(`🔍 Testing security mode: ${mode}`); + try { + const key = await secureCredentialsService.retrievePBKDF2Key(mode); + if (key) { + currentMode = mode; + console.log(`✅ PBKDF2 key found for security mode: ${mode}`); + break; + } + } catch (error) { + console.log(`⚠ No PBKDF2 key found for mode ${mode}`); + } + } + + // CRITICAL: Si aucune clĂ© PBKDF2 n'est disponible, arrĂȘter immĂ©diatement if (!currentMode) { - console.log('⚠ No security mode found, using browser mode as fallback'); - currentMode = 'browser'; + console.error('❌ CRITICAL: No PBKDF2 key found for any security mode.'); + console.error('❌ Cannot proceed with wallet creation without encryption key.'); + updateStatus('❌ Erreur: Aucune clĂ© de chiffrement trouvĂ©e. Veuillez configurer la sĂ©curitĂ©.', 'error'); + throw new Error('CRITICAL: No PBKDF2 key found. Cannot create wallet without encryption key.'); } console.log('🔐 Using security mode for wallet encryption:', currentMode); @@ -183,12 +207,15 @@ document.addEventListener('DOMContentLoaded', async () => { console.log('🔐 Wallet data generated:', walletData); - // RĂ©cupĂ©rer la clĂ© PBKDF2 gĂ©nĂ©rĂ©e par le service de sĂ©curitĂ© - const { SecureCredentialsService } = await import('../../services/secure-credentials.service'); - const secureCredentialsService = SecureCredentialsService.getInstance(); - - // GĂ©nĂ©rer la clĂ© PBKDF2 avec le mode de sĂ©curitĂ© choisi - const pbkdf2Key = await secureCredentialsService.generatePBKDF2Key(currentMode); + // RĂ©cupĂ©rer la clĂ© PBKDF2 existante pour le mode dĂ©tectĂ© + // IMPORTANT: Ne PAS gĂ©nĂ©rer de nouvelle clĂ©, utiliser celle qui existe + console.log('🔐 Retrieving existing PBKDF2 key for security mode:', currentMode); + const pbkdf2Key = await secureCredentialsService.retrievePBKDF2Key(currentMode as any); + if (!pbkdf2Key) { + console.error('❌ CRITICAL: Failed to retrieve PBKDF2 key for mode:', currentMode); + updateStatus('❌ Erreur: Impossible de rĂ©cupĂ©rer la clĂ© de chiffrement.', 'error'); + throw new Error('CRITICAL: Failed to retrieve PBKDF2 key'); + } console.log('🔐 PBKDF2 key retrieved for wallet encryption'); // Chiffrer le wallet avec la clĂ© PBKDF2 @@ -260,22 +287,37 @@ document.addEventListener('DOMContentLoaded', async () => { }); console.log(`🔍 Opening transaction for ${DATABASE_CONFIG.stores.wallet.name} store...`); + + // CRITICAL: Chiffrer TOUS les donnĂ©es du wallet avant stockage + // Le device contient des donnĂ©es sensibles (sp_wallet) qui ne doivent JAMAIS ĂȘtre en clair + console.log('🔐 Encrypting device data before storage...'); + const deviceString = JSON.stringify(device); + const encryptedDevice = await encryptionService.encryptWithPassword(deviceString, pbkdf2Key); + console.log('🔐 Device encrypted successfully'); + await new Promise((resolve, reject) => { const transaction = db.transaction([DATABASE_CONFIG.stores.wallet.name], 'readwrite'); const store = transaction.objectStore(DATABASE_CONFIG.stores.wallet.name); console.log('🔍 Store opened:', store.name); - // Stocker le wallet chiffrĂ© sĂ©parĂ©ment et laisser le SDK gĂ©rer sp_wallet + // Stocker UNIQUEMENT des donnĂ©es chiffrĂ©es - aucun wallet en clair const walletObject = { pre_id: '1', - device: device, - encrypted_wallet: encryptedWallet, // Stocker le wallet chiffrĂ© sĂ©parĂ©ment - security_mode: currentMode // Stocker le mode de sĂ©curitĂ© + encrypted_device: encryptedDevice, // Device complĂštement chiffrĂ© + encrypted_wallet: encryptedWallet, // Wallet chiffrĂ© + security_mode: currentMode // Mode de sĂ©curitĂ© utilisĂ© }; - console.log('🔍 Attempting to save wallet object:', walletObject); - // Le store utilise des clĂ©s out-of-line, fournir une clĂ© explicite - const request = store.put(walletObject, '1'); + console.log('🔍 Attempting to save encrypted wallet object'); + console.log('🔐 Object contains only encrypted data:', { + hasEncryptedDevice: !!walletObject.encrypted_device, + hasEncryptedWallet: !!walletObject.encrypted_wallet, + securityMode: walletObject.security_mode, + // Ne pas logger le contenu chiffrĂ© + }); + + // Le store utilise des clĂ©s in-line (keyPath: 'pre_id'), ne pas fournir de clĂ© explicite + const request = store.put(walletObject); request.onsuccess = () => { console.log('✅ Wallet saved in IndexedDB with correct format'); console.log('🔍 Saved wallet object:', walletObject); @@ -308,11 +350,32 @@ document.addEventListener('DOMContentLoaded', async () => { const verificationRequest = store.get('1'); verificationRequest.onsuccess = () => { - console.log('🔍 Verification result:', verificationRequest.result); + console.log('🔍 Verification result structure:', verificationRequest.result ? { + hasPreId: !!verificationRequest.result.pre_id, + hasEncryptedDevice: !!verificationRequest.result.encrypted_device, + hasEncryptedWallet: !!verificationRequest.result.encrypted_wallet, + hasSecurityMode: !!verificationRequest.result.security_mode, + hasDeviceInClear: !!verificationRequest.result.device // DEVRAIT ÊTRE NULL + } : 'null'); + if (verificationRequest.result) { console.log('✅ Wallet verification: Found in IndexedDB with key "1"'); - console.log('🔍 Device state:', verificationRequest.result.device.sp_wallet.state); - console.log('🔍 Encrypted data present:', !!verificationRequest.result.device.sp_wallet.encrypted_data); + + // VĂ©rifier qu'il n'y a AUCUN wallet en clair + if (verificationRequest.result.device) { + console.error('❌ CRITICAL: Device in clear found in database! This should be encrypted.'); + reject(new Error('Security violation: wallet stored in clear')); + return; + } + + // VĂ©rifier que les donnĂ©es chiffrĂ©es sont prĂ©sentes + if (!verificationRequest.result.encrypted_device || !verificationRequest.result.encrypted_wallet) { + console.error('❌ Wallet verification failed: encrypted data missing'); + reject(new Error('Encrypted data missing')); + return; + } + + console.log('✅ Wallet stored correctly: only encrypted data present'); resolve(); } else { console.error('❌ Wallet verification: Not found in IndexedDB with key "1"'); @@ -325,18 +388,9 @@ document.addEventListener('DOMContentLoaded', async () => { }; }); - // Sauvegarder le mode de sĂ©curitĂ© choisi - console.log('🔐 Saving security mode:', currentMode); - await securityModeService.setSecurityMode(currentMode); - - // VĂ©rifier que le mode de sĂ©curitĂ© est bien sauvegardĂ© - const savedMode = await securityModeService.getCurrentMode(); - if (savedMode === currentMode) { - console.log('✅ Security mode saved and verified:', savedMode); - } else { - console.error('❌ Security mode verification failed. Expected:', currentMode, 'Got:', savedMode); - throw new Error('Security mode verification failed'); - } + // Le mode de sĂ©curitĂ© est dĂ©jĂ  stockĂ© via la clĂ© PBKDF2 dans le store pbkdf2keys + // Pas besoin de le stocker sĂ©parĂ©ment + console.log('🔐 Security mode is implicitly stored via PBKDF2 key:', currentMode); // VĂ©rification finale : s'assurer que le wallet est bien dans IndexedDB console.log('🔍 Final verification: checking wallet in IndexedDB...'); @@ -348,14 +402,19 @@ document.addEventListener('DOMContentLoaded', async () => { request.onerror = () => reject(request.error); }); - if (finalVerification && finalVerification.device) { + if (finalVerification) { + // VĂ©rifier qu'il n'y a PAS de device en clair + if (finalVerification.device) { + console.error('❌ CRITICAL: Final verification - Device in clear found!'); + throw new Error('Security violation: wallet stored in clear'); + } + console.log('✅ Wallet saved exclusively in IndexedDB and verified'); - console.log('🔍 Wallet contains:', { - hasSpWallet: !!finalVerification.device.sp_wallet, - hasSpClient: !!finalVerification.device.sp_client, + console.log('🔍 Wallet contains only encrypted data:', { + hasEncryptedDevice: !!finalVerification.encrypted_device, hasEncryptedWallet: !!finalVerification.encrypted_wallet, securityMode: finalVerification.security_mode, - spClientKeys: finalVerification.device.sp_client ? Object.keys(finalVerification.device.sp_client) : 'none' + hasDeviceInClear: !!finalVerification.device // DEVRAIT ÊTRE FALSE }); } else { console.error('❌ Final wallet verification failed - wallet not found in IndexedDB');