# VPhoneControl Auto-Updates with SHA-256 Hash Verification: Implementation Guide

> Learn how VPhoneControl auto-updates vphoned with SHA-256 hash verification. Discover how it ensures secure binary updates via vsock handshake and streams new binaries on hash mismatch.

- Repository: [Lakr/vphone-cli](https://github.com/Lakr233/vphone-cli)
- Tags: how-to-guide
- Published: 2026-09-08

---

**VPhoneControl automatically manages binary updates for the guest daemon vphoned by computing a SHA-256 hash of the local binary during initialization and transmitting it during the vsock handshake; if the guest reports a hash mismatch via `need_update: true`, the control streams the new binary over the connection.**

The `VPhoneControl` class in the [Lakr233/vphone-cli](https://github.com/Lakr233/vphone-cli) repository serves as the host-side client that communicates with the guest daemon **vphoned** over a vsock connection. When the `guestBinaryURL` property is configured, the control object implements a sophisticated auto-update mechanism that uses cryptographic hash verification to ensure the guest always executes the latest trusted binary while avoiding redundant data transfers.

## How VPhoneControl Implements SHA-256 Auto-Updates

The auto-update workflow operates as a five-stage process that combines cryptographic integrity checks with efficient binary streaming. Each stage is implemented in [`sources/vphone-cli/VPhoneControl.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneControl.swift) and integrates with the existing vsock communication protocol.

### Loading and Hashing the Binary

The process begins in `loadGuestBinary()`, which executes when the control object initializes or reconnects. This method performs the following operations (lines [28‑38]):

1. Reads the file located at `guestBinaryURL` using `Data(contentsOf:)`
2. Generates a SHA-256 digest using `CryptoKit.SHA256.hash(data:)`
3. Converts the digest to a hexadecimal string stored in `guestBinaryHash`
4. Logs the hash for debugging purposes

This **cryptographically strong SHA-256 hash** becomes the authoritative fingerprint for version comparison between host and guest.

### The Handshake Protocol with Hash Verification

During connection establishment, `performHandshake(fd:attemptToken:)` constructs a JSON dictionary containing the protocol version and type identifier `hello`. If `guestBinaryHash` contains a value, the method injects the `"bin_hash"` field into the payload (lines [75‑79]):

```swift
// Simplified handshake structure
var hello: [String: Any] = [
    "protocol_version": 1,
    "type": "hello"
]
if let hash = guestBinaryHash {
    hello["bin_hash"] = hash
}
// Transmitted via writeMessage(fd:dict:)

```

The dictionary is serialized and transmitted to the guest via `writeMessage(fd:dict:)`, initiating the version negotiation.

### Guest-Side Update Decision

Upon receiving the handshake, the guest daemon parses the `"bin_hash"` value and compares it against the SHA-256 hash of its currently running binary. The guest responds with a JSON message containing the `"need_update"` boolean field (handled in the read-loop at lines [104‑105]):

- **`"need_update": true`** — The guest binary differs from the host copy
- **`"need_update": false`** — The binaries match; no transfer required

This design prevents unnecessary network traffic when the guest already possesses the correct binary version.

### Streaming the Binary Update

When `need_update` evaluates to true and the VM variant is not `.less`, `VPhoneControl` invokes `pushUpdate(fd:)` (lines [40‑68]). This method implements a streaming protocol:

1. **Header Transmission**: Sends an `update` JSON header containing the binary size and a unique request ID
2. **Raw Binary Streaming**: Writes the raw bytes of `guestBinaryData` directly to the socket file descriptor without additional encoding overhead
3. **Completion Handling**: Resumes the read loop to await the guest’s acknowledgment message

The direct byte streaming minimizes latency and memory overhead for large binary transfers.

### Reconnection and Hash Refresh

To handle transient connection failures, `scheduleReconnect(for:reason:)` implements resilient reconnection logic (lines [86‑99]). Before attempting to reconnect, this method:

1. Invokes `loadGuestBinary()` to reload the file from disk
2. Recomputes the SHA-256 hash to catch any binary updates that occurred while disconnected
3. Attempts reconnection with the fresh hash

This ensures the guest always receives the most current binary hash during the subsequent handshake, even after network interruptions.

## Practical Implementation Examples

Configure `VPhoneControl` for automatic hash-verified updates using the following patterns:

### Basic Auto-Update Configuration

```swift
import VPhoneCore

// Initialize control with regular VM variant
let control = VPhoneControl(variant: .regular)

// Point to the signed vphoned binary
control.guestBinaryURL = URL(fileURLWithPath: "/usr/local/lib/vphoned-signed.bin")

// Connect to the VM's vsock device (typically provided by VPhoneVirtualMachine)
control.connect(device: vsockDevice)

// The control automatically:
// 1. Computes SHA-256 hash via loadGuestBinary()
// 2. Sends bin_hash during performHandshake()
// 3. Streams updates via pushUpdate() if needed

```

### Forcing a Manual Update Check

To trigger an update after replacing the binary on disk:

```swift
// After updating the binary file at guestBinaryURL
if control.guestBinaryHash != nil {
    // Disconnect and reconnect to reload hash and re-handshake
    control.disconnect()
    control.connect(device: vsockDevice)
}

```

The reconnect cycle forces `loadGuestBinary()` to execute again, computing the new hash and prompting the guest to request the updated binary if hashes differ.

## Summary

- **SHA-256 Verification**: `VPhoneControl` uses `CryptoKit.SHA256.hash(data:)` in `loadGuestBinary()` (lines [28‑38] of [`VPhoneControl.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneControl.swift)) to generate a cryptographic fingerprint of the guest daemon binary
- **Handshake Integration**: The hash is transmitted as `"bin_hash"` during `performHandshake()` (lines [75‑79]), enabling the guest to detect version mismatches without downloading the entire binary
- **Conditional Streaming**: Updates only occur when the guest responds with `"need_update": true`, conserving bandwidth and reducing latency
- **Automatic Recovery**: The `scheduleReconnect()` method reloads and re-hashes the binary before reconnection attempts, ensuring resilience against file system changes during outages

## Frequently Asked Questions

### How does VPhoneControl determine when to send a binary update?

VPhoneControl relies on the guest daemon's response during the initial handshake. After the host sends the `"bin_hash"` value computed by `loadGuestBinary()`, the guest compares this against its current binary's hash. Only if the guest replies with `"need_update": true` does the host invoke `pushUpdate(fd:)` to stream the binary (lines [40‑68] of [`VPhoneControl.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneControl.swift)).

### What cryptographic method ensures update integrity?

The implementation uses **Apple's CryptoKit framework**, specifically `SHA256.hash(data:)`, to generate a 256-bit digest of the binary file. This hash is converted to a hexadecimal string and stored in `guestBinaryHash`, providing a collision-resistant verification mechanism that prevents corrupted or tampered binaries from executing on the guest.

### Can the auto-update mechanism be disabled?

Yes. The `pushUpdate(fd:)` method checks the VM variant before streaming. If `VPhoneControl` is initialized with the `.less` variant, the update logic is bypassed even when the guest requests an update. For standard operation, setting `guestBinaryURL` to `nil` prevents `loadGuestBinary()` from executing, effectively disabling hash computation and update capabilities.

### What happens if the vsock connection drops during an update?

The `scheduleReconnect(for:reason:)` method handles connection failures by first calling `loadGuestBinary()` to refresh the hash from disk (lines [86‑99]). This ensures that when the connection re-establishes, the host offers the current binary hash. If the previous update was interrupted, the guest will detect the incomplete or missing binary and request a fresh transfer during the next handshake cycle.