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

Vincent JoyVincent Joy
10 min read

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:

  1. Discovery Problem: How do devices find each other without a central registry?

  2. Identity Problem: How can devices verify each other's identity without a trusted third party?

  3. Security Problem: How do we ensure confidentiality and integrity without pre-shared secrets?

  4. 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:

  1. Ordered Delivery: Messages arrive in the sequence they were sent

  2. Reliability: Lost packets are automatically retransmitted

  3. Flow Control: Prevents overwhelming slower devices

  4. 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:

  1. Confidentiality: Ensuring only intended recipients can read messages

  2. 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:

  1. Each party generates a random private key

  2. They compute their public key by multiplying the base point by their private key

  3. They exchange public keys

  4. Each multiplies the other's public key by their private key

  5. 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:

  1. PIN-Based: Similar to Bluetooth pairing, users verify a shared PIN

  2. QR Code: Visual channel provides out-of-band verification

  3. Trust on First Use (TOFU): Accept initially, remember for future connections

  4. 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 operations

  • TCPTransportActor: Handles socket communication

  • EncryptionActor: Performs cryptographic operations

  • MessageProtocolActor: 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

  1. Man-in-the-Middle: Prevented by authenticated key exchange

  2. Replay Attacks: Mitigated through timestamps and nonces

  3. Denial of Service: Rate limiting and connection quotas

  4. Impersonation: Cryptographic identity verification

  5. 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.

0
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.