# How Device Pairing Information Is Generated in iLoader: A Deep Dive into Lockdown and RPPairing

> Discover how iLoader generates device pairing information by combining lockdown session data with RPPairing data on iOS 17.4+. Understand the technical details of Wi-Fi debugging and CoreDeviceProxy tunnels.

- Repository: [Nicholas Sharp/iloader](https://github.com/nab138/iloader)
- Tags: deep-dive
- Published: 2026-09-13

---

**iLoader generates device pairing information by constructing a combined plist containing traditional lockdown session data for Wi-Fi debugging and, on iOS 17.4+, ephemeral RPPairing data obtained through CoreDeviceProxy tunnels.**

iLoader is an open-source iOS sideloading tool written in Rust that establishes cryptographic trust between a host machine and an iOS device. Understanding how device pairing information is generated in iloader requires examining the orchestration between legacy lockdown services and modern Remote Pairing (RPPairing) frameworks as implemented in [`src-tauri/src/pairing.rs`](https://github.com/nab138/iloader/blob/main/src-tauri/src/pairing.rs).

## The Two-Component Pairing Architecture

iLoader produces a single XML-encoded plist payload that combines two distinct trust mechanisms:

- **Lockdown pairing** – Classic lockdown session data enabling Wi-Fi debugging, generated from the device’s existing pairing record.
- **RPPairing data** – A modern Remote Pairing payload introduced in iOS 17.4, created dynamically by communicating with the device’s CoreDeviceProxy over an untrusted tunnel.

The `pairing_file` function in [`src-tauri/src/pairing.rs`](https://github.com/nab138/iloader/blob/main/src-tauri/src/pairing.rs) orchestrates the generation pipeline, returning a `Vec<u8>` containing the final XML bytes ready for transmission to the device.

## Step-by-Step Generation Process

### Establishing the USBMuxd Connection

The process begins by acquiring a mutable `UsbmuxdConnection` and resolving the target device’s provider. The `pairing_file` function receives the application state, `DeviceInfo`, and a cancellation token, then calls `get_provider` to obtain an `IdeviceProvider` for the specific UDID.

```rust
// src-tauri/src/pairing.rs (lines 6-13)
pub async fn pairing_file(
    app: &AppHandle,
    device_info: &DeviceInfo,
    usbmuxd: &mut UsbmuxdConnection,
    token: CancellationToken,
) -> Result<Vec<u8>, IdeviceError> {
    let provider = device_info.get_provider(usbmuxd).await?;
    // ...
}

```

### Generating Lockdown Pairing Data

The `generate_lockdown_plist` function (lines 65-100) retrieves the existing pair record via `usbmuxd.get_pair_record`, injects the device UDID, initiates a lockdown session, and explicitly enables Wi-Fi debugging. It returns the plist representation as a `Value` type.

This step is **universal**—it executes for all iOS versions regardless of whether RPPairing is required.

### Conditional RPPairing Generation

For devices running **iOS 17.4 or later**, iLoader must supplement lockdown data with RPPairing information. The system first checks for cached data in `InMemoryStorage` or the system key-ring under the key `rppairing_file_<udid>` (lines 34-40).

If no valid cache exists, `generate_rppairing_plist` invokes `generate_rppairing` (lines 21-65), which:

1. Connects to `CoreDeviceProxy` on the device
2. Opens a software tunnel to the Remote Service Daemon (RSD)
3. Performs an RSD handshake to locate the untrusted tunnel service
4. Establishes an XPC channel via `RemoteXpcClient`
5. Creates an `RpPairingFile` and executes the pairing protocol twice—once to push the credential into the device keychain, once to confirm

```rust
// Simplified RPPairing generation flow
let (plist_value, raw_bytes) = generate_rppairing(&provider, token).await?;

```

### Caching and Storage Strategy

Freshly generated RPPairing data is immediately persisted to avoid expensive regeneration. The raw bytes are stored via the `SideloadingStorage` abstraction (implemented in [`src-tauri/src/secure_storage.rs`](https://github.com/nab138/iloader/blob/main/src-tauri/src/secure_storage.rs)) using a key derived from the device UDID (lines 81-86).

Subsequent pairing attempts for the same device will retrieve this cached blob, skipping the network-intensive CoreDeviceProxy negotiation.

### Merging and Serialization

The final phase combines both data sources. The `pairing_file` function merges the lockdown plist and RPPairing plist into a single dictionary using the `plist!` macro, then serializes the result to XML bytes (lines 94-99).

```rust
// Combining both pairing components
let combined = plist!({
    "Lockdown": lockdown_plist,
    "RPPairing": rppairing_plist,
});
let xml_bytes = plist::to_xml_bytes(&combined)?;

```

## Cancellation and Async Handling

All long-running operations—including `generate_lockdown_plist` and `generate_rppairing_plist`—are wrapped in `tokio::select!` blocks (lines 14-19 and 49-54). This allows immediate abortion if the user triggers the cancellation token, preventing hanging connections during the RSD handshake or XPC negotiation.

## Code Examples

### Frontend Invocation (TypeScript/React)

Frontend components trigger pairing generation through Tauri’s command bridge:

```typescript
// src/Device.tsx
await invoke('set_selected_device', { device: selectedDevice });
// Backend executes pairing_file(), storing result in DeviceInfoWithPairing.pairing

```

### Direct Rust Usage

For custom integrations, invoke `pairing_file` directly with the required dependencies:

```rust
use tauri::State;
use iloader::pairing::pairing_file;

let pairing_blob = pairing_file(
    &app_handle,
    &device_info,
    &mut usbmuxd_connection,
    cancellation_token
).await?;

// pairing_blob contains XML plist bytes ready for device transmission

```

### Cache Invalidation

To force regeneration of RPPairing data (for example, after device resets):

```rust
invoke('delete_stored_rppairing', { deviceState, app });

```

## Summary

- **iLoader** generates device pairing information in [`src-tauri/src/pairing.rs`](https://github.com/nab138/iloader/blob/main/src-tauri/src/pairing.rs) by combining legacy lockdown data with modern RPPairing payloads.
- **Lockdown pairing** enables Wi-Fi debugging through modified lockdown session records.
- **RPPairing** requires iOS 17.4+ and involves `CoreDeviceProxy` tunnels, RSD handshakes, and XPC channels via `RemoteXpcClient`.
- **Caching** occurs in `SideloadingStorage` under keys formatted as `rppairing_file_<udid>` to avoid redundant network operations.
- **Cancellation** is supported throughout via `tokio::select!` and `CancellationToken`.

## Frequently Asked Questions

### What is the difference between Lockdown pairing and RPPairing in iLoader?

**Lockdown pairing** is the traditional trust mechanism used for Wi-Fi debugging, generated from existing lockdown records and modified to enable network-based debugging. **RPPairing** is a newer protocol introduced in iOS 17.4 that uses `CoreDeviceProxy` and untrusted tunnels to establish trust without requiring a previous USB pairing, making it essential for modern wireless workflows.

### Where does iLoader store generated pairing data?

iLoader stores RPPairing blobs in an abstraction called `SideloadingStorage`, implemented in [`src-tauri/src/secure_storage.rs`](https://github.com/nab138/iloader/blob/main/src-tauri/src/secure_storage.rs). This storage uses either `InMemoryStorage` or the system key-ring, with keys formatted as `rppairing_file_<udid>`. Lockdown pairing data is never cached; it is generated fresh for each session from the device’s existing lockdown records.

### Why does iLoader need to generate pairing information twice for iOS 17.4+ devices?

According to the source code in [`src-tauri/src/pairing.rs`](https://github.com/nab138/iloader/blob/main/src-tauri/src/pairing.rs), the `generate_rppairing` function runs the pairing protocol **twice**: first to push the `RpPairingFile` into the device’s keychain, and second to confirm the credential persistence. This double-handshake ensures the device retains the trust relationship after the initial session closes.

### How can I cancel an ongoing pairing operation in iLoader?

Pass a `tokio_util::sync::CancellationToken` to the `pairing_file` function. The implementation uses `tokio::select!` to monitor this token during `generate_lockdown_plist` and `generate_rppairing_plist` operations. Triggering the token aborts the connection to `UsbmuxdConnection` or `CoreDeviceProxy` immediately, preventing hang states during network timeouts.