A proof-of-concept implementation of the Signal Protocol in Flutter/Dart, demonstrating end-to-end encrypted messaging through executable test scenarios.
Credits go to https://github.com/MixinNetwork/libsignal_protocol_dart for the core implementation of the protocol for Dart.
This repository serves as a technical demonstration of Signal Protocol implementation in Dart. Rather than being a runnable application, it provides a comprehensive test suite that showcases:
- Complete Signal Protocol implementation
- Key exchange mechanisms
- Session establishment and proper acknowledgment
- Message encryption/decryption
- Multi-user communication scenarios
- Multi-device support per user
- Group messaging
Important: This codebase is designed to be explored through its test suite. The tests serve as living documentation and executable examples of the Signal Protocol implementation.
- Flutter
>=3.7.2
(Developed with 3.16.9) - Dart
>=3.7.2
(Developed with 3.2.6)
# Clone the repository
git clone https://github.com/stdNullPtr/Flutter-Signal-Protocol-PoC.git
cd Flutter-Signal-Protocol-PoC
# Install dependencies
flutter pub get
# Generate Freezed code
flutter pub run build_runner build --delete-conflicting-outputs
The main Signal Protocol implementation featuring:
- Identity key pair generation and management
- PreKey bundle creation and distribution
- Session establishment with other users
- Proper session acknowledgment for Double Ratchet initialization
- Message encryption using the Double Ratchet algorithm
- Message decryption and session management
- Multi-device support through device-specific sessions
- Group messaging with sender key distribution
Immutable state management using Freezed, containing:
- User identity keys
- PreKey and signed PreKey stores
- Active sessions cache
- Pending messages queue
- One-time PreKey management
UserKeys
(lib/server/models/user_keys.dart
): Represents a user's PreKey bundle for key exchangeMessage
(lib/common/models/message.dart
): Encapsulates encrypted message dataGroupMessage
(lib/common/models/group_message.dart
): Represents encrypted group messagesPublicPreKey
&PublicSignedPreKey
(lib/server/models/
): Key structures for exchange
- PreKey bundle upload and retrieval
- Encrypted message routing
- Message acknowledgment handling
- Multi-device awareness
- Group membership management
Logger
(lib/utils/logger.dart
): Logging utility for debugging
lib/
βββ client/
β βββ signal_client.dart # Signal Protocol implementation
β βββ signal_client.freezed.dart # Generated immutable state
βββ common/
β βββ models/
β βββ message.dart # Message structure
β βββ group_message.dart # Group message support
βββ server/
β βββ models/
β β βββ user_keys.dart # PreKey bundle model
β β βββ public_prekey.dart # Public PreKey structure
β β βββ public_signed_prekey.dart # Signed PreKey structure
β βββ server.dart # Server API client
βββ utils/
βββ logger.dart # Logging utility
test/
βββ signal_protocol_test.dart # Comprehensive test scenarios
βββ key_reuse_test.dart # Tests for key reuse prevention
βββ multi_device_test.dart # Tests for multi-device support
The test suites serve as the primary documentation for this PoC. Each test file demonstrates specific aspects of the Signal Protocol:
test/signal_protocol_test.dart
: Core protocol implementation scenariostest/key_reuse_test.dart
: Security tests for preventing key reuse attackstest/multi_device_test.dart
: Tests for multi-device support
# Run all test scenarios
flutter test
# Run with verbose output to see the implementation in action
flutter test --reporter expanded
# Run a specific test scenario
flutter test --name "should establish session and exchange messages"
-
Basic Key Generation
- Demonstrates identity key creation
- Shows PreKey bundle generation
- Validates cryptographic material
-
PreKey Bundle Exchange
- Shows how users publish their PreKey bundles
- Demonstrates bundle retrieval from server
- Validates bundle integrity
-
Session Establishment
- Illustrates initial session creation
- Shows the X3DH key agreement protocol
- Demonstrates session caching
- Properly acknowledges and transitions session states
-
Message Exchange
- Shows complete message encryption flow
- Demonstrates the Double Ratchet algorithm
- Illustrates proper message type transitions (prekey β whisper)
- Illustrates message decryption
-
Multi-User Scenarios
- Complex interactions between multiple users
- Concurrent session management
- Message ordering and delivery
-
Multi-Device Support
- Multiple devices for a single user
- Proper message routing to all user devices
- Independent session management per device
-
Group Messaging
- Sender key distribution for groups
- Group membership management
- Encrypted group communication
- Handling members joining existing groups
-
Key Reuse Prevention (in
key_reuse_test.dart
)- Ensures one-time PreKeys are not reused
- Validates security against key reuse attacks
- Tests proper key rotation mechanisms
Each test includes comprehensive logging that explains what's happening at each step of the protocol. To see detailed logs while running tests, use the --reporter expanded
flag. The test output can also be seen in the GitHub Actions workflow: https://github.com/stdNullPtr/Flutter-Signal-Protocol-PoC/actions
The implementation follows the Signal Protocol specification:
- Identity Keys: Long-term Curve25519 key pairs
- Signed PreKey: Medium-term keys with signatures
- One-Time PreKeys: Ephemeral keys for perfect forward secrecy
- Sessions: Established using X3DH (Extended Triple Diffie-Hellman)
- Double Ratchet: Provides forward secrecy and break-in recovery
- Session Acknowledgment: Ensures proper state transitions for the ratchet
- Multi-Device Support: Manages separate cryptographic sessions for each device
- Group Messaging: Uses sender keys for efficient group communication
Uses Freezed for immutable state management:
- Ensures thread safety
- Prevents accidental state mutations
- Provides efficient state updates through copying
The implementation requires a compatible server that:
- Stores and serves PreKey bundles
- Routes encrypted messages between users and devices
- Manages group membership
- Never has access to plaintext content
This PoC demonstrates the following security properties:
- End-to-End Encryption: Messages are encrypted on the sender's device and decrypted on the recipient's device
- Perfect Forward Secrecy: Compromised keys don't affect past communications
- Break-in Recovery: Compromised keys don't affect future communications
- Deniable Authentication: Messages can be authenticated by the recipient but anyone could have forged messages after the conversation - protecting users from being cryptographically proven to have sent a message
- Multi-Device Security: Each device maintains its own cryptographic session, preventing compromise of all devices if one is breached
β
Complete Signal Protocol implementation in Dart
β
Proper key management and rotation
β
Session establishment between users
β
Session acknowledgment and state management
β
Message encryption and decryption
β
Multi-user communication patterns
β
Multi-device support per user
β
Group messaging with sender keys
β
Server integration for key exchange
β User interface implementation
β Persistent storage of keys and sessions
β Production-ready error handling
β Message delivery guarantees
β Media/file encryption
β Comprehensive cryptographic auditing
To understand the Signal Protocol implementation:
- Start with the main test file:
test/signal_protocol_test.dart
- Follow the test scenarios in order
- Review security tests in
test/key_reuse_test.dart
- Explore multi-device capabilities in
test/multi_device_test.dart
- Examine the
SignalClient
implementation inlib/client/signal_client.dart
- Review the state management in
SignalClientState
- Understand the server interactions in
lib/server/server.dart
- Explore the data models in
lib/common/models/
andlib/server/models/
The PoC implements proper session acknowledgment, which is crucial for the Double Ratchet algorithm:
- Initial messages use PreKey messages (containing X3DH materials)
- After session establishment, a cryptographic acknowledgment occurs
- When receiving a PreKey message, the receiver creates a session
- The receiver acknowledges the session by clearing unacknowledged PreKey flag
- Subsequent messages use the more efficient "whisper" message type
- This follows the Signal Protocol's security design for session establishment
The implementation demonstrates how Signal handles multiple devices for a single user:
- Each device has its own identity and cryptographic material
- Messages sent to a user are delivered to all their devices
- Each device maintains independent sessions with other users' devices
- This models Signal's approach to multi-device support
Group messaging is implemented using sender keys:
- Each member distributes their sender key to the group
- Messages are efficiently encrypted once and distributed to all members
- New members can join existing groups
- This matches Signal's efficient approach to group communication
- Signal Protocol Documentation
- libsignal_protocol_dart - The Dart implementation of Signal Protocol used in this project
- The X3DH Key Agreement Protocol
- The Double Ratchet Algorithm
- Sender Keys for Group Messaging
This is a proof-of-concept implementation. Contributions should focus on:
- Improving test coverage and scenarios
- Adding clarifying documentation
- Fixing implementation issues
- Demonstrating additional protocol features
This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.
The GPL-3.0 license ensures that:
- Source code must be made available when distributed
- Modifications must be released under the same license
- Commercial use is allowed only if the source code is provided
- Patent rights are granted to users
This proof-of-concept demonstrates how the Signal Protocol can be implemented in Flutter/Dart. Explore the test suite to understand the implementation details.