"Bonjour, TCP!" Writing an Encrypted Peer-to-Peer SDK for iOS IoT Apps


Github link
Introduction
In an era where privacy concerns are paramount and centralized servers represent both a bottleneck and a single point of failure, peer-to-peer (P2P) communication has become increasingly relevant. Whether you're building a local multiplayer game, a file-sharing application, or an IoT control system, understanding the fundamentals of secure P2P communication is essential.
This article explores the theoretical foundations and practical applications of building a secure P2P communication framework, using WiPeerKit as our case study. We'll delve into the networking protocols, cryptographic principles, and modern concurrency patterns that make secure local communication possible.
The P2P Communication Challenge
Traditional client-server architectures are well-understood: clients connect to a known server address, the server authenticates clients, and all communication flows through this central hub. But P2P communication presents unique challenges:
Discovery Problem: How do devices find each other without a central registry?
Identity Problem: How can devices verify each other's identity without a trusted third party?
Security Problem: How do we ensure confidentiality and integrity without pre-shared secrets?
Concurrency Problem: How do we handle multiple simultaneous connections safely?
Let's explore how each of these challenges is addressed.
Service Discovery: The Foundation of P2P
Understanding mDNS/Bonjour
Multicast DNS (mDNS) is the cornerstone of local network discovery. Unlike traditional DNS that requires a server, mDNS operates through multicast messages on the local network segment. When a device wants to advertise a service, it sends multicast packets to the special address 224.0.0.251 (IPv4) or FF02::FB (IPv6).
The beauty of mDNS lies in its decentralized nature. Each device maintains its own records and responds to queries about services it provides. This creates a self-organizing network where devices can discover each other without any infrastructure.
DNS Service Discovery (DNS-SD)
Built on top of mDNS, DNS-SD provides a standard way to advertise and discover network services. Services are identified by type (e.g., _http._tcp
) and can include additional metadata through TXT records. This allows rich service discovery where devices can advertise capabilities, versions, and other relevant information.
In WiPeerKit, we use a custom service type _wipeerkit._tcp
to ensure only compatible devices discover each other. This prevents interference with other applications and provides a namespace for our protocol.
The Security Implications
While convenient, open service discovery creates security vulnerabilities. Any device on the network can discover and attempt to connect to your service. This is why authentication becomes crucial - discovery should be easy, but connection should be controlled.
TCP Communication: Reliable Data Transport
Why TCP for P2P?
While UDP might seem attractive for its lower overhead, TCP provides crucial guarantees for secure communication:
Ordered Delivery: Messages arrive in the sequence they were sent
Reliability: Lost packets are automatically retransmitted
Flow Control: Prevents overwhelming slower devices
Connection State: Clear establishment and termination semantics
These properties simplify building secure protocols on top, as we don't need to handle reordering, retransmission, or connection management ourselves.
Message Framing
TCP provides a byte stream abstraction, not message boundaries. This means we need a framing protocol to delineate individual messages. WiPeerKit uses length-prefixing: each message is preceded by a 4-byte header containing the message length. This simple approach is efficient and allows receivers to know exactly how many bytes to read for each message.
Network Framework vs BSD Sockets
Apple's Network framework provides a modern, Swift-native API for network programming. Unlike BSD sockets, it integrates naturally with Swift's concurrency model and provides built-in support for modern networking features like TCP Fast Open and Multipath TCP. The framework also enforces best practices, such as respecting user privacy settings and network interface preferences.
Cryptographic Foundations
The Dual Requirements: Confidentiality and Authentication
Encryption alone is insufficient for secure communication. Consider this: if you encrypt a message but send it to an attacker, the encryption provides no protection. This is why we need both:
Confidentiality: Ensuring only intended recipients can read messages
Authentication: Verifying the identity of communication partners
AES-GCM: Authenticated Encryption
Advanced Encryption Standard in Galois/Counter Mode (AES-GCM) provides both encryption and authentication in a single operation. It offers:
Semantic Security: Identical plaintexts produce different ciphertexts
Authentication: Any tampering is detected through the authentication tag
Performance: Hardware acceleration on modern processors
Nonce-based: Each encryption uses a unique nonce, preventing replay attacks
The 96-bit nonce in GCM mode provides sufficient uniqueness for our use case, while the 128-bit authentication tag ensures message integrity with negligible probability of forgery.
Diffie-Hellman Key Exchange: The Magic of Shared Secrets
The Diffie-Hellman key exchange enables two parties to establish a shared secret over an insecure channel. The mathematical foundation relies on the computational difficulty of the discrete logarithm problem.
Using elliptic curves (specifically P-256 in WiPeerKit), we achieve equivalent security to 3072-bit RSA with just 256-bit keys. The process works as follows:
Each party generates a random private key
They compute their public key by multiplying the base point by their private key
They exchange public keys
Each multiplies the other's public key by their private key
Due to the mathematical properties of elliptic curves, both arrive at the same shared point
This shared secret is then processed through a Key Derivation Function (KDF) to produce suitable encryption keys.
Perfect Forward Secrecy
By generating new key pairs for each connection, we achieve Perfect Forward Secrecy (PFS). Even if a device's long-term keys are compromised, past communications remain secure because the session keys cannot be reconstructed without the ephemeral private keys, which are discarded after use.
Authentication and Authorization
The Trust Problem
In a P2P system without central authority, establishing trust is challenging. WiPeerKit implements multiple authentication strategies:
PIN-Based: Similar to Bluetooth pairing, users verify a shared PIN
QR Code: Visual channel provides out-of-band verification
Trust on First Use (TOFU): Accept initially, remember for future connections
Public Key Pinning: Remember and verify device public keys
Identity Verification
Each device generates a long-term identity key pair stored in the iOS Keychain. This provides a cryptographic identity that persists across app launches. When devices connect, they exchange signed messages proving possession of their private keys.
The challenge is making this process user-friendly. Displaying raw public keys is impractical, so WiPeerKit generates human-readable fingerprints using SHA-256 hashes formatted as grouped hexadecimal digits (e.g., "A3F2-B1C4-D5E6-F8A9").
Authorization Flows
Authentication verifies identity; authorization determines access rights. WiPeerKit supports several authorization models:
Mutual Consent: Both parties must approve the connection
Role-Based: Devices can be designated as servers or clients with different permissions
Time-Limited: Connections can be authorized for specific durations
Capability-Based: Fine-grained permissions for different operations
Swift 6 Concurrency: Thread Safety by Design
The Actor Model
Swift 6's actor model provides a revolutionary approach to concurrent programming. Actors encapsulate state and ensure all access is serialized, eliminating data races by design. In WiPeerKit, each major component is an actor:
ServiceDiscoveryActor
: Manages mDNS operationsTCPTransportActor
: Handles socket communicationEncryptionActor
: Performs cryptographic operationsMessageProtocolActor
: Manages message framing
This architecture ensures thread safety without manual locking, making the code both safer and more maintainable.
Sendable and Data Race Safety
Swift 6's Sendable protocol marks types that can be safely shared across concurrency domains. All public types in WiPeerKit conform to Sendable, ensuring the compiler catches potential data races at compile time rather than runtime.
The @MainActor
isolation of the main WiPeerKit class ensures UI updates happen on the main thread, while background operations run efficiently on appropriate queues.
Structured Concurrency
Using async/await throughout the API provides clear concurrency boundaries. Operations that might block (like network I/O) are explicitly marked as async, making it impossible to accidentally block the main thread. Task groups enable parallel operations while maintaining structured lifetimes and proper cancellation propagation.
Testing Strategies
Unit Testing with Actors
Testing actor-based code requires special consideration. WiPeerKit uses protocol-based design, allowing mock implementations for testing. The mocks themselves are actors, ensuring tests accurately reflect the concurrency characteristics of the real implementation.
Integration Testing
End-to-end tests verify the complete flow from discovery through encrypted communication. These tests use real network operations on localhost, ensuring all components work together correctly. The deterministic nature of actor isolation makes these tests reliable and reproducible.
Security Testing
Cryptographic implementations require careful testing:
Known Answer Tests: Verify encryption/decryption with test vectors
Randomness Testing: Ensure proper entropy for key generation
Protocol Testing: Verify handshake flows and error handling
Negative Testing: Ensure invalid inputs are properly rejected
Real-World Applications
Local Multiplayer Gaming
P2P communication enables lag-free local multiplayer without internet connectivity. Players discover each other automatically, establish secure connections, and exchange game state with minimal latency. The authentication ensures players can't impersonate each other or inject invalid game commands.
IoT Device Control
Smart home devices can communicate directly without cloud dependencies. This improves privacy (data stays local), reduces latency (no round-trip to cloud), and provides resilience (works during internet outages). The security model ensures only authorized devices can send commands.
Collaborative Applications
Document editing, whiteboard sharing, and other collaborative tools benefit from direct P2P connections. Changes propagate instantly between devices, and the encryption ensures confidential information remains private even on public networks.
Emergency Communication
When infrastructure fails, P2P communication over local networks can provide vital connectivity. Devices can form mesh networks, relaying messages between peers. The authentication prevents malicious actors from disrupting emergency communications.
Security Considerations
Attack Vectors and Mitigations
Man-in-the-Middle: Prevented by authenticated key exchange
Replay Attacks: Mitigated through timestamps and nonces
Denial of Service: Rate limiting and connection quotas
Impersonation: Cryptographic identity verification
Eavesdropping: End-to-end encryption
Defense in Depth
Security isn't achieved through a single mechanism but through multiple layers:
Network isolation (Wi-Fi only, no cellular)
Service discovery filtering
Cryptographic authentication
Encrypted transport
Application-level authorization
Audit logging
Privacy Implications
P2P communication can enhance privacy by eliminating central servers that collect metadata. However, it also creates new challenges:
Device names may reveal user identity
Network presence indicates device location
Connection patterns reveal social graphs
WiPeerKit addresses these through configurable privacy levels and anonymous mode options.
Performance Considerations
Computational Overhead
Modern devices handle cryptographic operations efficiently:
AES-GCM: Hardware accelerated, negligible impact
ECDH: ~1ms for key exchange on modern iOS devices
SHA-256: Sub-microsecond for typical messages
The real bottleneck is usually network latency, not cryptography.
Memory Efficiency
The actor model's message-passing semantics can increase memory usage compared to shared-state concurrency. WiPeerKit mitigates this through:
Streaming large messages instead of buffering
Pooling commonly used objects
Careful lifecycle management
Battery Impact
Continuous network activity can drain batteries. WiPeerKit implements:
Adaptive polling intervals
Wake-on-LAN support where available
Batched message transmission
Automatic connection throttling
Future Directions
Quantum Resistance
Current elliptic curve cryptography is vulnerable to quantum computers. Future versions could implement post-quantum key exchange algorithms like CRYSTALS-Kyber, maintaining security in a quantum computing era.
Multi-hop Routing
Extending beyond direct connections to mesh networking would enable communication between devices not in direct range. This requires routing protocols and additional security considerations for relay nodes.
Cross-Platform Support
While WiPeerKit targets Apple platforms, the underlying protocols are platform-agnostic. Implementations for Android, Windows, and Linux would enable broader ecosystem support.
Conclusion
Building secure P2P communication requires carefully orchestrating multiple technologies:
mDNS for discovery
TCP for reliable transport
AES-GCM for confidentiality
ECDH for key agreement
Digital signatures for authentication
Actors for concurrency safety
The WiPeerKit framework demonstrates how these technologies combine to create a secure, user-friendly P2P communication system. By understanding the theoretical foundations and practical tradeoffs, developers can build applications that provide the benefits of direct communication while maintaining security and privacy.
The shift toward P2P architectures represents more than a technical choice - it's a return to the internet's decentralized roots, empowering users with control over their data and communications. As we continue building the future of networked applications, the principles explored here will become increasingly relevant.
The author develops iOS frameworks focusing on secure networking and distributed systems. WiPeerKit is open-source and available on GitHub.
Subscribe to my newsletter
Read articles from Vincent Joy directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Vincent Joy
Vincent Joy
Seasoned Software Engineer with 11 years of experience specializing in native iOS development using Swift, SwiftUI and UIKit. Additional expertise in cross-platform mobile development with React Native and backend API development using Django REST Framework. Proficient in Swift, JavaScript, and Python. Throughout my career, I have balanced roles as a team lead, mentor, code architect, individual contributor and solo developer. I have contributed to products across diverse environments, from early-stage startups to publicly listed companies, spanning industries such as AI, IoT, Travel & Hospitality, Ride Hailing, Navigation, E-commerce and Streaming. . Currently I am exploring possibilities in the emerging fields of AI and AR/VR, by developing applications in Generative AI and Vision OS, via personal projects.