# Protected Notes and Encryption System Trilium's Protected Notes system provides robust, selective encryption for sensitive content using industry-standard AES encryption with scrypt-based key derivation. This guide covers setup, usage, and security considerations. ## Architecture Overview ### Encryption Stack - **Cipher**: AES-128-CBC (Advanced Encryption Standard, Cipher Block Chaining mode) - **Key Derivation**: Scrypt (N=16384, r=8, p=1) with random salt - **Integrity Protection**: SHA-1 digest verification - **Encoding**: Base64 for storage and transmission ### Key Hierarchy ``` Master Password (User Input) ↓ Password-Derived Key (Scrypt + Salt) ↓ Encrypted Data Key (AES-128-CBC) ↓ Session Data Key (In Memory) ↓ Protected Content (AES-128-CBC) ``` ## Setting Up Protected Notes ### Initial Configuration 1. **Set Master Password** - Access via Options → Security → Password - Minimum 8 characters (recommend 12+) - Use unique, complex password 2. **Configure Session Settings** - Session timeout (default: 10 minutes) - Auto-logout on inactivity - Multi-client session handling 3. **Security Options** - Password strength requirements - Session notification preferences - Audit logging settings ### Creating Protected Notes #### Method 1: Right-Click Menu 1. Right-click any note in the tree 2. Select "Toggle Protected Status" 3. Confirm protection in dialog #### Method 2: Note Actions Menu 1. Open note editor 2. Click Actions button (⚙️) 3. Select "Protect this note" #### Method 3: Keyboard Shortcut 1. Select note 2. Press `Ctrl+Shift+U` (toggle protection) ### Bulk Protection Protect multiple notes simultaneously: 1. **Subtree Protection** - Right-click parent note - Select "Protect subtree" - All child notes become protected 2. **Batch Selection** - Use Ctrl+click to select multiple notes - Right-click → "Protect selected notes" ## Protected Sessions ### Session Lifecycle #### Entering Protected Session **Method 1: Manual Entry** ``` 1. Click shield icon in toolbar 2. Enter master password 3. Session activates (shield turns green) ``` **Method 2: Automatic Prompt** ``` 1. Access protected note 2. Password dialog appears 3. Enter credentials to continue ``` **Method 3: Keyboard Shortcut** ``` Press Ctrl+Shift+P to enter protected session ``` #### Session Management - **Active Session**: Shield icon green, protected content accessible - **Session Timeout**: Configurable (60-3600 seconds) - **Activity Tracking**: Timeout resets with each protected note access - **Multi-Client**: Independent sessions per browser/client #### Leaving Protected Session **Manual Logout**: - Click green shield icon - Select "Leave protected session" **Automatic Logout**: - Inactivity timeout - Browser/application close - Security state changes ### Session Security Features #### Timeout Configuration ```typescript // Access via Options → Protected Session protectedSessionTimeout: number // seconds (default: 600) protectedSessionWarning: boolean // show timeout warnings ``` #### Security Events - Session entry/exit logged - Failed authentication attempts tracked - Unusual access patterns detected - Audit trail maintained ## Encryption Technical Details ### Encryption Process Flow ``` Plaintext Data ↓ 1. Compute SHA-1 digest (integrity check) ↓ 2. Prepend digest (4 bytes) to plaintext ↓ 3. Generate random IV (16 bytes) ↓ 4. Encrypt with AES-128-CBC (data key + IV) ↓ 5. Prepend IV to encrypted data ↓ 6. Encode as Base64 ↓ Stored Ciphertext ``` ### Decryption Process Flow ``` Base64 Ciphertext ↓ 1. Decode from Base64 ↓ 2. Extract IV (first 16 bytes) ↓ 3. Extract encrypted data (remaining bytes) ↓ 4. Decrypt with AES-128-CBC (data key + IV) ↓ 5. Extract digest (first 4 bytes) and plaintext ↓ 6. Verify digest matches computed SHA-1 ↓ Verified Plaintext Data ``` ### Key Derivation Details #### Scrypt Parameters ```typescript const scryptParams = { N: 16384, // CPU/memory cost (2^14) r: 8, // Block size parameter p: 1, // Parallelization parameter dkLen: 32 // Derived key length (bytes) }; ``` #### Salt Generation - **Password Salt**: 32-byte random salt for password verification - **Data Key Salt**: 32-byte random salt for data key encryption - **Cryptographic Quality**: Node.js crypto.randomBytes() #### Key Storage ```sql -- Options table entries INSERT INTO options VALUES ('passwordVerificationSalt', '<32-byte-salt>'), ('passwordDerivedKeySalt', '<32-byte-salt>'), ('passwordVerificationHash', ''), ('encryptedDataKey', ''); ``` ## Security Considerations ### Threat Model #### Protected Against ✅ **Database Theft**: Encrypted content unreadable without password ✅ **Backup Compromise**: Encrypted backups maintain protection ✅ **Network Interception**: Data encrypted at rest and in transit ✅ **Server Breach**: Server never stores plaintext of protected content ✅ **Physical Storage Access**: Database files encrypted #### Not Protected Against ❌ **Keyloggers**: Malware capturing password input ❌ **Memory Dumps**: Active sessions store keys in memory ❌ **Screen Capture**: Displayed content vulnerable ❌ **Social Engineering**: User convinced to reveal password ❌ **Endpoint Compromise**: Malware on user device ### Security Limitations #### Metadata Exposure - **Note Structure**: Tree hierarchy visible - **Timestamps**: Creation/modification dates unencrypted - **Note IDs**: Internal identifiers exposed - **Attributes**: Some metadata may be unencrypted #### Search Limitations - **Full-text Search**: Protected content excluded from search index - **Cross-references**: Links to protected notes may be limited - **Content Analysis**: Automated analysis features disabled ### Best Practices #### Password Management 1. **Strong Passwords** - Minimum 12 characters - Mix of letters, numbers, symbols - Avoid common patterns 2. **Password Storage** - Use reputable password manager - Store recovery information securely - Don't reuse passwords 3. **Regular Updates** - Change password periodically - Update after suspected compromise - Coordinate with team members #### Session Management 1. **Timeout Configuration** - Set appropriate timeout for usage pattern - Shorter timeouts for sensitive environments - Balance security with usability 2. **Access Control** - Lock workstation when away - Use screen savers with password - Log out of shared computers 3. **Multi-Device Usage** - Use consistent passwords across devices - Monitor active sessions - Revoke compromised device access ## Troubleshooting ### Common Issues #### Decryption Failures **Error**: "Could not decrypt string" **Causes**: - Incorrect password - Corrupted encrypted data - Database schema issues - Memory corruption **Solutions**: ```bash # Check database integrity sqlite3 document.db "PRAGMA integrity_check;" # Verify options table sqlite3 document.db "SELECT name, length(value) FROM options WHERE name LIKE 'password%';" # Test password verification # (In protected session troubleshooting) ``` #### Session Problems **Error**: Protected session won't start **Diagnostic Steps**: 1. Check browser console for JavaScript errors 2. Verify network connectivity 3. Review server logs for authentication errors 4. Test with fresh browser session **Solutions**: ```bash # Clear browser data # Restart Trilium server # Check file permissions on database # Verify encryption keys in options table ``` #### Performance Issues **Symptoms**: Slow password verification, high CPU usage **Optimization**: ```typescript // Advanced users only - modify scrypt parameters const optimizedParams = { N: 8192, // Reduce for faster verification r: 8, // Keep default p: 1 // Keep default }; ``` **Hardware Recommendations**: - Minimum 4GB RAM for scrypt operations - Modern CPU with AES-NI support - SSD storage for database files ### Recovery Procedures #### Forgotten Password **No Built-in Recovery**: Trilium cannot recover forgotten passwords **Options**: 1. **Restore from Backup**: Use backup with known password 2. **Partial Recovery**: Export unprotected content 3. **Complete Reset**: Lose all protected content ```bash # Reset password (loses all protected content) sqlite3 document.db " UPDATE options SET value = '' WHERE name IN ( 'passwordVerificationSalt', 'passwordDerivedKeySalt', 'passwordVerificationHash', 'encryptedDataKey' ); " ``` #### Data Corruption **Corruption Detection**: - Decryption failures - Database integrity errors - Inconsistent note content **Recovery Steps**: 1. Stop Trilium application 2. Create backup of current database 3. Run database integrity check 4. Restore from known good backup 5. Compare and merge changes if needed ```bash # Database integrity check sqlite3 document.db "PRAGMA integrity_check;" # Quick corruption check sqlite3 document.db "SELECT COUNT(*) FROM notes WHERE isProtected = 1;" ``` ## Performance Optimization ### System Requirements #### Minimum Requirements - **CPU**: 1GHz processor with AES support - **RAM**: 2GB available memory - **Storage**: 100MB free disk space - **Network**: Stable connection for sync #### Recommended Configuration - **CPU**: Multi-core processor with AES-NI - **RAM**: 8GB+ for large datasets - **Storage**: SSD for database files - **Network**: Broadband for sync operations ### Performance Tuning #### Database Optimization ```sql -- Optimize database performance PRAGMA journal_mode = WAL; PRAGMA synchronous = NORMAL; PRAGMA cache_size = 10000; PRAGMA temp_store = MEMORY; ``` #### Memory Management - **Session Caching**: Keep frequently accessed protected notes in memory - **Garbage Collection**: Clear old session data regularly - **Resource Monitoring**: Monitor memory usage patterns #### Network Optimization - **Compression**: Enable content compression - **Caching**: Use appropriate cache headers - **Connection Pooling**: Optimize database connections ## Compliance and Auditing ### Encryption Standards #### Algorithm Compliance - **AES-128**: NIST approved, FIPS 140-2 Level 1 - **Scrypt**: RFC 7914 standard - **SHA-1**: NIST standard (integrity only) #### Key Management - **Generation**: Cryptographically secure random number generator - **Storage**: Encrypted at rest - **Transmission**: Never transmitted in plaintext - **Destruction**: Securely cleared from memory ### Audit Requirements #### Logging Events ```typescript // Security events logged enum AuditEvents { PROTECTED_SESSION_START = 'protected_session_start', PROTECTED_SESSION_END = 'protected_session_end', PROTECTED_NOTE_ACCESS = 'protected_note_access', ENCRYPTION_FAILURE = 'encryption_failure', DECRYPTION_FAILURE = 'decryption_failure', PASSWORD_CHANGE = 'password_change' } ``` #### Compliance Reports - Authentication success/failure rates - Protected content access patterns - Security event timelines - Performance metrics ### Regulatory Considerations #### GDPR Compliance - **Data Protection**: AES encryption provides technical safeguards - **Right to Erasure**: Secure deletion of encryption keys - **Data Portability**: Export capabilities for protected content - **Privacy by Design**: Encryption built into architecture #### HIPAA Requirements - **Administrative Safeguards**: Access controls and audit trails - **Physical Safeguards**: Workstation security recommendations - **Technical Safeguards**: AES encryption meets requirements #### Industry Standards - **ISO 27001**: Information security management - **SOC 2**: Security and availability controls - **PCI DSS**: Data protection requirements ## Advanced Configuration ### Custom Encryption Parameters **Warning**: Modifying encryption parameters requires expert knowledge and may break compatibility with future versions. ```typescript // File: apps/server/src/services/encryption/my_scrypt.ts const customScryptParams = { N: 32768, // Higher security (slower) r: 8, // Block size p: 2 // Parallel processing }; ``` ### Integration Examples #### Backend Script Access ```javascript // Accessing protected notes in backend scripts const protectedNote = api.getNote(noteId); if (protectedNote.isProtected) { // Content is encrypted unless in protected session if (api.isProtectedSessionAvailable()) { const content = protectedNote.getContent(); // Process decrypted content } else { // Request protected session throw new Error('Protected session required'); } } ``` #### API Integration ```typescript // External API access to protected content const etapiToken = 'your-etapi-token'; const headers = { 'Authorization': `Bearer ${etapiToken}`, 'Content-Type': 'application/json' }; // Note: ETAPI cannot access protected content // Protected session must be established in web interface ``` ## Backup and Migration ### Backup Strategies #### Complete Database Backup ```bash # Stop Trilium first sqlite3 document.db ".backup backup-$(date +%Y%m%d).db" # Compressed backup tar czf trilium-backup-$(date +%Y%m%d).tar.gz \ document.db session_secret.txt config.ini ``` #### Encrypted Backup ```bash # GPG encrypted backup tar czf - trilium-data/ | \ gpg --cipher-algo AES256 --compress-algo 1 --symmetric \ --output trilium-backup-$(date +%Y%m%d).tar.gz.gpg ``` #### Protected Content Export ```javascript // Export during protected session const protectedNotes = api.getNotesByLabel('#protected'); protectedNotes.forEach(note => { if (note.isProtected) { const exportData = { title: note.title, content: note.getContent(), attributes: note.getAttributes() }; // Save to secure location } }); ``` ### Migration Procedures #### Same-Password Migration 1. Export data from source installation 2. Create fresh installation 3. Set same master password 4. Import exported data 5. Verify protected content access #### Password Change Migration 1. Enter protected session in source 2. Export all protected content unencrypted 3. Create new installation with new password 4. Import content (will be re-encrypted) 5. Verify all content accessible #### Cross-Platform Migration ```bash # Export from source platform trilium-server --export=/path/to/export.zip # Import to target platform trilium-server --import=/path/to/export.zip ``` Remember: The security of your protected notes depends on maintaining good password practices and following security best practices for your overall system environment.