# Bringing the Noise: Secure Communication in BitChat ## Overview BitChat implements the Noise Protocol Framework for end-to-end encryption, providing forward secrecy, identity hiding, and cryptographic authentication. This document details our Swift implementation and its integration with BitChat's decentralized mesh network. ## The Noise Protocol Framework ### Why Noise? The Noise Protocol Framework offers: - **Forward Secrecy**: Past messages remain secure even if keys are compromised - **Identity Hiding**: Peer identities are encrypted during handshake - **Simplicity**: Clean, auditable protocol with minimal complexity - **Performance**: Efficient for resource-constrained mobile devices - **Flexibility**: Supports various handshake patterns ### The XX Pattern BitChat uses the Noise XX pattern: ``` XX: -> e <- e, ee, s, es -> s, se ``` This three-message pattern provides: - Mutual authentication - Identity encryption (identities revealed only after initial key exchange) - Resistance to key-compromise impersonation ## Implementation Architecture ### Core Components #### NoiseEncryptionService The main service managing all Noise operations: ```swift final class NoiseEncryptionService { private let staticIdentityKey: Curve25519.KeyAgreement.PrivateKey private let sessionManager: NoiseSessionManager private let channelEncryption = NoiseChannelEncryption() } ``` #### NoiseSession Individual session state for each peer: ```swift final class NoiseSession { private var handshakeState: NoiseHandshakeState? private var sendCipher: NoiseCipherState? private var receiveCipher: NoiseCipherState? private let remoteStaticKey: Curve25519.KeyAgreement.PublicKey? } ``` #### NoiseSessionManager Thread-safe session management: ```swift final class NoiseSessionManager { private var sessions: [String: NoiseSession] = [:] private let sessionsQueue = DispatchQueue(label: "noise.sessions", attributes: .concurrent) } ``` ### Handshake Flow 1. **Initiator sends ephemeral key** ```swift let ephemeralKey = Curve25519.KeyAgreement.PrivateKey() let message = ephemeralKey.publicKey.rawRepresentation ``` 2. **Responder sends ephemeral + encrypted static** ```swift // Generate ephemeral, perform DH, encrypt static key let encryptedStatic = encrypt(staticKey, using: sharedSecret) ``` 3. **Initiator sends encrypted static** ```swift // Complete handshake, derive session keys let (sendKey, recvKey) = deriveSessionKeys(transcript) ``` ### Session Management Sessions are managed with automatic cleanup and rekey support: ```swift // Session lookup by peer ID func getSession(for peerID: String) -> NoiseSession? // Automatic session removal on disconnect func removeSession(for peerID: String) // Rekey detection func getSessionsNeedingRekey() -> [(String, Bool)] ``` ## Integration with BitChat ### Peer ID Rotation Noise sessions persist across peer ID rotations through fingerprint mapping: ```swift // Identity announcement after handshake struct NoiseIdentityAnnouncement { let peerID: String let publicKey: Data let nickname: String let previousPeerID: String? let signature: Data } ``` ### Message Encryption All messages are encrypted using established Noise sessions: ```swift // Encrypt message let encrypted = try noiseService.encrypt(messageData, for: peerID) // Decrypt message let decrypted = try noiseService.decrypt(encryptedData, from: peerID) ``` ## Security Properties ### Forward Secrecy - Ephemeral keys are generated for each handshake - Past sessions cannot be decrypted with current keys - Automatic rekey after 1 hour or 10,000 messages ### Authentication - Static keys provide long-term identity - Handshake ensures mutual authentication - MAC tags prevent message tampering ### Privacy - Peer identities encrypted during handshake - Metadata minimization through padding - No persistent session identifiers ## Implementation Details ### Cryptographic Primitives - **DH**: X25519 (Curve25519) - **Cipher**: ChaChaPoly (AEAD) - **Hash**: SHA-256 - **KDF**: HKDF-SHA256 ### Error Handling ```swift enum NoiseError: Error { case handshakeFailed case invalidMessage case sessionNotEstablished case decryptionFailed } ``` ## Performance Optimizations ### Connection Pooling - Reuse established sessions - Lazy handshake initiation - Session caching with TTL ### Message Batching - Combine small messages - Reduce encryption overhead - Optimize for BLE MTU ### Memory Management - Bounded session cache - Automatic cleanup of stale sessions - Efficient key rotation ## Protocol Version Negotiation BitChat implements protocol version negotiation to ensure compatibility between different client versions: ### Version Negotiation Flow 1. **Version Hello**: Upon connection, peers exchange supported protocol versions 2. **Version Agreement**: Peers agree on the highest common version 3. **Graceful Fallback**: Legacy peers without version negotiation assume protocol v1 ### Message Types ```swift case versionHello = 0x20 // Announce supported versions case versionAck = 0x21 // Acknowledge and agree on version ``` ### Backward Compatibility - Peers that don't send version negotiation messages are assumed to support v1 - Future protocol versions can be added to `ProtocolVersion.supportedVersions` - Incompatible peers receive a rejection message and disconnect gracefully ## Future Enhancements ### Post-Quantum Readiness - Hybrid handshake patterns - Kyber integration plans - Graceful algorithm migration ### Advanced Features - Multi-device support - Session backup/restore - Group messaging primitives ## Conclusion BitChat's Noise implementation provides encryption while maintaining the simplicity and performance required for a peer-to-peer messaging application. The protocol's elegant design ensures that people's communications remain private, authenticated, and forward-secure without sacrificing usability.