**Major Features Added:** - **Inline Reply System**: Replace compose screen with inline reply boxes - **Thread Navigation**: Parent/child navigation with jump functionality - **Chain Flow UI**: Reply counts, expand/collapse animations, visual hierarchy - **Enhanced Animations**: Smooth transitions, hover effects, micro-interactions **Frontend Changes:** - **ThreadedCommentWidget**: Complete rewrite with animations and navigation - **ThreadNode Model**: Added parent references and descendant counting - **ThreadedConversationScreen**: Integrated navigation handlers - **PostDetailScreen**: Replaced with threaded conversation view - **ComposeScreen**: Added reply indicators and context - **PostActions**: Fixed visibility checks for chain buttons **Backend Changes:** - **API Route**: Added /posts/:id/thread endpoint - **Post Repository**: Include allow_chain and visibility fields in feed - **Thread Handler**: Support for fetching post chains **UI/UX Improvements:** - **Reply Context**: Clear indication when replying to specific posts - **Character Counting**: 500 character limit with live counter - **Visual Hierarchy**: Depth-based indentation and styling - **Smooth Animations**: SizeTransition, FadeTransition, hover states - **Chain Navigation**: Parent/child buttons with visual feedback **Technical Enhancements:** - **Animation Controllers**: Proper lifecycle management - **State Management**: Clean separation of concerns - **Navigation Callbacks**: Reusable navigation system - **Error Handling**: Graceful fallbacks and user feedback This creates a Reddit-style threaded conversation experience with smooth animations, inline replies, and intuitive navigation between posts in a chain.
235 lines
8.1 KiB
Markdown
235 lines
8.1 KiB
Markdown
# E2EE Implementation Complete Guide
|
|
|
|
## Overview
|
|
This document describes the complete end-to-end encryption (E2EE) implementation for Sojorn, including all issues encountered and fixes applied.
|
|
|
|
## Architecture
|
|
- **Flutter Client**: Uses X25519 for key exchange, Ed25519 for signatures, AES-GCM for encryption
|
|
- **Go Backend**: Stores key bundles in PostgreSQL, serves encryption keys
|
|
- **Protocol**: X3DH (Extended Triple Diffie-Hellman) for key agreement
|
|
|
|
## Key Components
|
|
|
|
### 1. Key Storage
|
|
- **FlutterSecureStorage**: Local key persistence with `e2ee_keys_v3` key
|
|
- **PostgreSQL Tables**: `profiles`, `signed_prekeys`, `one_time_prekeys`
|
|
- **Key Format**: Identity keys stored as `Ed25519:X25519` (base64 concatenated with colon)
|
|
|
|
### 2. Key Generation Flow
|
|
1. Generate Ed25519 signing key pair (for signatures)
|
|
2. Generate X25519 identity key pair (for DH)
|
|
3. Generate X25519 signed prekey with Ed25519 signature
|
|
4. Generate 20 X25519 one-time prekeys (OTKs)
|
|
5. Upload key bundle to backend
|
|
|
|
### 3. Message Encryption Flow
|
|
1. Fetch recipient's key bundle from backend
|
|
2. Verify signed prekey signature with Ed25519
|
|
3. Perform X3DH key agreement
|
|
4. Derive shared secret using KDF (SHA-256)
|
|
5. Encrypt message with AES-GCM
|
|
6. Delete used OTK from server
|
|
|
|
## Issues Encountered & Fixes
|
|
|
|
### Issue #1: 208-bit Key Bug ❌→✅
|
|
**Problem**: Keys were 26 characters (208 bits) instead of 32 bytes (256 bits)
|
|
**Root Cause**: Using string-based KDF instead of proper byte-based KDF
|
|
**Fix**: Updated `_kdf` method to use SHA-256 on byte arrays
|
|
**Files Modified**: `simple_e2ee_service.dart`
|
|
|
|
### Issue #2: Database Constraint Error ❌→✅
|
|
**Problem**: `SQLSTATE 42P10` - ON CONFLICT constraint mismatch
|
|
**Root Cause**: Go code used `ON CONFLICT (user_id)` but DB had `PRIMARY KEY (user_id, key_id)`
|
|
**Fix**: Updated Go code to use correct constraint `ON CONFLICT (user_id, key_id)`
|
|
**Files Modified**: `user_repository.go`
|
|
|
|
### Issue #3: Fake Zero Signatures ❌→✅
|
|
**Problem**: SPK signatures were all zeros (`AAAAAAAA...`)
|
|
**Root Cause**: Manual upload used fake signature for testing
|
|
**Fix**: Updated manual upload to generate real Ed25519 signatures
|
|
**Files Modified**: `simple_e2ee_service.dart`
|
|
|
|
### Issue #4: Asymmetric Security ❌→✅
|
|
**Problem**: One user skipped signature verification (legacy), other enforced it
|
|
**Root Cause**: Legacy user detection created security asymmetry
|
|
**Fix**: Removed legacy logic, enforced signature verification for all users
|
|
**Files Modified**: `simple_e2ee_service.dart`
|
|
|
|
### Issue #5: Key Upload Not Automatic ❌→✅
|
|
**Problem**: Keys loaded locally but never uploaded to backend
|
|
**Root Cause**: `_doInitialize` returned early after loading keys
|
|
**Fix**: Added backend existence check and automatic upload
|
|
**Files Modified**: `simple_e2ee_service.dart`
|
|
|
|
### Issue #6: NULL Database Values ❌→✅
|
|
**Problem**: `registration_id` was NULL causing scan errors
|
|
**Root Cause**: Database column allowed NULL values
|
|
**Fix**: Updated Go code to handle `sql.NullInt64` with default values
|
|
**Files Modified**: `user_repository.go`
|
|
|
|
### Issue #7: Noisy WebSocket Logs ❌→✅
|
|
**Problem**: Ping/pong messages cluttered console
|
|
**Root Cause**: WebSocket heartbeat logging
|
|
**Fix**: Filtered out ping/pong messages completely
|
|
**Files Modified**: `secure_chat_service.dart`
|
|
|
|
### Issue #8: Modal Header Override ❌→✅
|
|
**Problem**: AppBar changes in chat screen were hidden by modal wrapper
|
|
**Root Cause**: `SecureChatModal` had custom header overriding `SecureChatScreen` AppBar
|
|
**Fix**: Added upload button to modal header instead
|
|
**Files Modified**: `secure_chat_modal_sheet.dart`
|
|
|
|
## Current Status ✅
|
|
|
|
### Working Components
|
|
- ✅ 32-byte key generation
|
|
- ✅ Valid Ed25519 signatures
|
|
- ✅ Signature verification
|
|
- ✅ Key bundle upload/download
|
|
- ✅ X3DH key agreement
|
|
- ✅ AES-GCM encryption/decryption
|
|
- ✅ OTK management (generation, usage, deletion)
|
|
- ✅ Backend key storage/retrieval
|
|
- ✅ Cross-platform encryption (Android↔Web)
|
|
|
|
### Key Files Modified
|
|
```
|
|
Flutter:
|
|
- lib/services/simple_e2ee_service.dart (core E2EE logic)
|
|
- lib/services/secure_chat_service.dart (WebSocket + key management)
|
|
- lib/screens/secure_chat/secure_chat_modal_sheet.dart (UI upload button)
|
|
|
|
Go Backend:
|
|
- internal/handlers/key_handler.go (API endpoints + validation)
|
|
- internal/repository/user_repository.go (database operations)
|
|
```
|
|
|
|
### Database Schema
|
|
```sql
|
|
-- Key storage tables
|
|
profiles (identity_key, registration_id)
|
|
signed_prekeys (user_id, key_id, public_key, signature)
|
|
one_time_prekeys (user_id, key_id, public_key)
|
|
```
|
|
|
|
## Testing Checklist
|
|
|
|
### Before Testing
|
|
1. Ensure both users have valid keys (check `[E2EE] Keys exist on backend - ready`)
|
|
2. Verify signatures are non-zero (check backend logs)
|
|
3. Confirm OTKs are available (should have 20 OTKs each)
|
|
|
|
### Test Flow
|
|
1. **Key Upload**: Tap "🔑" button → should see `[E2EE] Key bundle uploaded successfully`
|
|
2. **Message Send**: Type message → should see `[E2EE] SPK signature verified successfully`
|
|
3. **Message Receive**: Should see `[DECRYPT] SUCCESS: Decrypted message: "..."`
|
|
4. **OTK Deletion**: Should see `[E2EE] Deleted used OTK #[id] from server`
|
|
|
|
### Expected Logs
|
|
```
|
|
Sender:
|
|
[ENCRYPT] Fetching key bundle for recipient: [...]
|
|
[E2EE] SPK signature verified successfully.
|
|
[E2EE] Deleted used OTK #[id] from server
|
|
|
|
Receiver:
|
|
[DECRYPT] Used OTK with key_id: [id]
|
|
[DECRYPT] SUCCESS: Decrypted message: "[message_text]"
|
|
```
|
|
|
|
## Next Steps: Message Recovery
|
|
|
|
### Problem
|
|
When users uninstall the app or lose local keys, they cannot decrypt historical messages.
|
|
|
|
### Solution Requirements
|
|
1. **Key Backup Strategy**: Securely backup encryption keys
|
|
2. **Message Recovery**: Allow decryption of historical messages after key recovery
|
|
3. **Security**: Maintain E2EE guarantees while enabling recovery
|
|
|
|
### Proposed Solutions
|
|
|
|
#### Option 1: Cloud Key Backup
|
|
- Encrypt identity keys with user password
|
|
- Store encrypted backup in cloud storage
|
|
- Recover keys with password authentication
|
|
|
|
#### Option 2: Social Recovery
|
|
- Allow trusted contacts to help recover keys
|
|
- Use Shamir's Secret Sharing for security
|
|
- Requires multiple trusted contacts
|
|
|
|
#### Option 3: Server-Side Recovery (Limited)
|
|
- Store encrypted key backups on server
|
|
- Server cannot decrypt without user password
|
|
- Similar to Signal's approach
|
|
|
|
#### Option 4: Message Re-encryption
|
|
- Store messages encrypted with server keys
|
|
- Re-encrypt with new keys after recovery
|
|
- Breaks perfect forward secrecy
|
|
|
|
### Recommended Approach
|
|
Start with **Option 1 (Cloud Key Backup)** as it's:
|
|
- Most user-friendly
|
|
- Maintains security (password-protected)
|
|
- Technically straightforward
|
|
- Reversible if needed
|
|
|
|
## Implementation Plan for Key Recovery
|
|
|
|
### Phase 1: Key Backup
|
|
1. Add password-based key encryption
|
|
2. Implement cloud backup storage
|
|
3. Add backup/restore UI
|
|
4. Test backup/restore flow
|
|
|
|
### Phase 2: Message Recovery
|
|
1. Store message headers for re-decryption
|
|
2. Implement batch message re-decryption
|
|
3. Add recovery progress indicators
|
|
4. Test with historical messages
|
|
|
|
### Phase 3: Security Enhancements
|
|
1. Add backup encryption verification
|
|
2. Implement backup rotation
|
|
3. Add recovery security checks
|
|
4. Monitor recovery success rates
|
|
|
|
## Security Considerations
|
|
|
|
### Current Security Model
|
|
- ✅ Perfect Forward Secrecy (PFS) via OTKs
|
|
- ✅ Post-Compromise Security via key rotation
|
|
- ✅ Authentication via Ed25519 signatures
|
|
- ✅ Confidentiality via AES-GCM
|
|
|
|
### Recovery Security Impact
|
|
- ⚠️ Breaks PFS for recovered messages
|
|
- ✅ Maintains confidentiality with password protection
|
|
- ✅ Preserves authentication via signature verification
|
|
- ⚠️ Requires trust in backup storage
|
|
|
|
### Mitigation Strategies
|
|
1. Use strong password requirements
|
|
2. Implement backup encryption verification
|
|
3. Add backup expiration policies
|
|
4. Monitor backup access patterns
|
|
|
|
## Conclusion
|
|
|
|
The E2EE implementation is now fully functional with all major issues resolved. The system provides:
|
|
|
|
- Strong cryptographic guarantees
|
|
- Cross-platform compatibility
|
|
- Automatic key management
|
|
- Secure message transmission
|
|
|
|
The next phase focuses on key recovery to handle user device changes while maintaining security principles.
|
|
|
|
---
|
|
|
|
**Last Updated**: January 29, 2026
|
|
**Status**: ✅ Production Ready (except key recovery)
|