mirror of
https://github.com/jkcoxson/idevice.git
synced 2026-03-02 06:26:15 +01:00
Initial scafolding for RPPairing
This commit is contained in:
190
Cargo.lock
generated
190
Cargo.lock
generated
@@ -17,6 +17,16 @@ version = "2.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aead"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.3"
|
version = "1.1.3"
|
||||||
@@ -415,6 +425,30 @@ version = "0.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chacha20"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cipher",
|
||||||
|
"cpufeatures",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chacha20poly1305"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
|
||||||
|
dependencies = [
|
||||||
|
"aead",
|
||||||
|
"chacha20",
|
||||||
|
"cipher",
|
||||||
|
"poly1305",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.41"
|
version = "0.4.41"
|
||||||
@@ -429,6 +463,17 @@ dependencies = [
|
|||||||
"windows-link",
|
"windows-link",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cipher"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"inout",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clang-sys"
|
name = "clang-sys"
|
||||||
version = "1.8.1"
|
version = "1.8.1"
|
||||||
@@ -562,9 +607,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
|
"rand_core 0.6.4",
|
||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "curve25519-dalek"
|
||||||
|
version = "4.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"curve25519-dalek-derive",
|
||||||
|
"digest",
|
||||||
|
"fiat-crypto",
|
||||||
|
"rustc_version",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "curve25519-dalek-derive"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.101",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "der"
|
name = "der"
|
||||||
version = "0.7.10"
|
version = "0.7.10"
|
||||||
@@ -607,6 +680,7 @@ dependencies = [
|
|||||||
"block-buffer",
|
"block-buffer",
|
||||||
"const-oid",
|
"const-oid",
|
||||||
"crypto-common",
|
"crypto-common",
|
||||||
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -626,6 +700,31 @@ version = "1.0.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
|
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ed25519"
|
||||||
|
version = "2.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
|
||||||
|
dependencies = [
|
||||||
|
"pkcs8",
|
||||||
|
"signature",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ed25519-dalek"
|
||||||
|
version = "2.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871"
|
||||||
|
dependencies = [
|
||||||
|
"curve25519-dalek",
|
||||||
|
"ed25519",
|
||||||
|
"rand_core 0.6.4",
|
||||||
|
"serde",
|
||||||
|
"sha2",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.15.0"
|
version = "1.15.0"
|
||||||
@@ -720,6 +819,12 @@ version = "2.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fiat-crypto"
|
||||||
|
version = "0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flagset"
|
name = "flagset"
|
||||||
version = "0.4.7"
|
version = "0.4.7"
|
||||||
@@ -955,6 +1060,24 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hkdf"
|
||||||
|
version = "0.12.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7"
|
||||||
|
dependencies = [
|
||||||
|
"hmac",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hmac"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "home"
|
name = "home"
|
||||||
version = "0.5.11"
|
version = "0.5.11"
|
||||||
@@ -1187,9 +1310,12 @@ dependencies = [
|
|||||||
"base64",
|
"base64",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"chacha20poly1305",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"ed25519-dalek",
|
||||||
"env_logger 0.11.8",
|
"env_logger 0.11.8",
|
||||||
"futures",
|
"futures",
|
||||||
|
"hkdf",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"json",
|
"json",
|
||||||
"log",
|
"log",
|
||||||
@@ -1208,6 +1334,7 @@ dependencies = [
|
|||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
"tun-rs 2.1.4",
|
"tun-rs 2.1.4",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
"x25519-dalek",
|
||||||
"x509-cert",
|
"x509-cert",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1275,6 +1402,15 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inout"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.11.0"
|
version = "2.11.0"
|
||||||
@@ -1708,6 +1844,12 @@ version = "1.70.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
|
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opaque-debug"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking"
|
name = "parking"
|
||||||
version = "2.2.1"
|
version = "2.2.1"
|
||||||
@@ -1835,6 +1977,17 @@ dependencies = [
|
|||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "poly1305"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
|
||||||
|
dependencies = [
|
||||||
|
"cpufeatures",
|
||||||
|
"opaque-debug",
|
||||||
|
"universal-hash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "portable-atomic"
|
name = "portable-atomic"
|
||||||
version = "1.11.0"
|
version = "1.11.0"
|
||||||
@@ -2178,6 +2331,15 @@ version = "2.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc_version"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||||
|
dependencies = [
|
||||||
|
"semver",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.44"
|
version = "0.38.44"
|
||||||
@@ -2269,6 +2431,12 @@ version = "1.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver"
|
||||||
|
version = "1.0.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.219"
|
version = "1.0.219"
|
||||||
@@ -2863,6 +3031,16 @@ version = "0.1.14"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "universal-hash"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "untrusted"
|
name = "untrusted"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@@ -3462,6 +3640,18 @@ version = "0.6.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
|
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "x25519-dalek"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277"
|
||||||
|
dependencies = [
|
||||||
|
"curve25519-dalek",
|
||||||
|
"rand_core 0.6.4",
|
||||||
|
"serde",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "x509-cert"
|
name = "x509-cert"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ x509-cert = { version = "0.2", optional = true, features = [
|
|||||||
"builder",
|
"builder",
|
||||||
"pem",
|
"pem",
|
||||||
], default-features = false }
|
], default-features = false }
|
||||||
|
x25519-dalek = { version = "2", optional = true }
|
||||||
|
ed25519-dalek = { version = "2", features = ["rand_core"], optional = true }
|
||||||
|
hkdf = { version = "0.12", optional = true }
|
||||||
|
chacha20poly1305 = { version = "0.10", optional = true }
|
||||||
|
|
||||||
obfstr = { version = "0.4", optional = true }
|
obfstr = { version = "0.4", optional = true }
|
||||||
|
|
||||||
@@ -73,6 +77,14 @@ location_simulation = []
|
|||||||
pair = ["chrono/default", "tokio/time", "dep:sha2", "dep:rsa", "dep:x509-cert"]
|
pair = ["chrono/default", "tokio/time", "dep:sha2", "dep:rsa", "dep:x509-cert"]
|
||||||
obfuscate = ["dep:obfstr"]
|
obfuscate = ["dep:obfstr"]
|
||||||
restore_service = []
|
restore_service = []
|
||||||
|
remote_pairing = [
|
||||||
|
"dep:json",
|
||||||
|
"dep:x25519-dalek",
|
||||||
|
"dep:ed25519-dalek",
|
||||||
|
"dep:hkdf",
|
||||||
|
"dep:chacha20poly1305",
|
||||||
|
"dep:uuid",
|
||||||
|
]
|
||||||
rsd = ["xpc"]
|
rsd = ["xpc"]
|
||||||
syslog_relay = ["dep:bytes"]
|
syslog_relay = ["dep:bytes"]
|
||||||
tcp = ["tokio/net"]
|
tcp = ["tokio/net"]
|
||||||
@@ -97,6 +109,10 @@ full = [
|
|||||||
"mobile_image_mounter",
|
"mobile_image_mounter",
|
||||||
"pair",
|
"pair",
|
||||||
"restore_service",
|
"restore_service",
|
||||||
|
"usbmuxd",
|
||||||
|
"xpc",
|
||||||
|
"location_simulation",
|
||||||
|
"remote_pairing",
|
||||||
"rsd",
|
"rsd",
|
||||||
"springboardservices",
|
"springboardservices",
|
||||||
"syslog_relay",
|
"syslog_relay",
|
||||||
|
|||||||
@@ -598,6 +598,25 @@ pub enum IdeviceError {
|
|||||||
#[error("unknown error `{0}` returned from device")]
|
#[error("unknown error `{0}` returned from device")]
|
||||||
UnknownErrorType(String) = -59,
|
UnknownErrorType(String) = -59,
|
||||||
|
|
||||||
|
#[cfg(feature = "remote_pairing")]
|
||||||
|
#[error("could not parse as JSON")]
|
||||||
|
JsonParseFailed(#[from] json::Error) = -63,
|
||||||
|
|
||||||
|
#[cfg(feature = "remote_pairing")]
|
||||||
|
#[error("unknown TLV type: {0}")]
|
||||||
|
UnknownTlv(u8) = -64,
|
||||||
|
|
||||||
|
#[cfg(feature = "remote_pairing")]
|
||||||
|
#[error("malformed TLV")]
|
||||||
|
MalformedTlv = -65,
|
||||||
|
|
||||||
|
#[error("failed to decode base64 string")]
|
||||||
|
Base64Decode(#[from] base64::DecodeError) = -66,
|
||||||
|
|
||||||
|
#[cfg(feature = "remote_pairing")]
|
||||||
|
#[error("pair verify failed")]
|
||||||
|
PairVerifyFailed = -67,
|
||||||
|
|
||||||
#[error("invalid arguments were passed")]
|
#[error("invalid arguments were passed")]
|
||||||
FfiInvalidArg = -60,
|
FfiInvalidArg = -60,
|
||||||
#[error("invalid string was passed")]
|
#[error("invalid string was passed")]
|
||||||
@@ -750,6 +769,16 @@ impl IdeviceError {
|
|||||||
IdeviceError::FfiInvalidArg => -60,
|
IdeviceError::FfiInvalidArg => -60,
|
||||||
IdeviceError::FfiInvalidString => -61,
|
IdeviceError::FfiInvalidString => -61,
|
||||||
IdeviceError::FfiBufferTooSmall(_, _) => -62,
|
IdeviceError::FfiBufferTooSmall(_, _) => -62,
|
||||||
|
|
||||||
|
#[cfg(feature = "remote_pairing")]
|
||||||
|
IdeviceError::JsonParseFailed(_) => -63,
|
||||||
|
#[cfg(feature = "remote_pairing")]
|
||||||
|
IdeviceError::UnknownTlv(_) => -64,
|
||||||
|
#[cfg(feature = "remote_pairing")]
|
||||||
|
IdeviceError::MalformedTlv => -65,
|
||||||
|
IdeviceError::Base64Decode(_) => -66,
|
||||||
|
#[cfg(feature = "remote_pairing")]
|
||||||
|
IdeviceError::PairVerifyFailed => -67,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ pub mod misagent;
|
|||||||
pub mod mobile_image_mounter;
|
pub mod mobile_image_mounter;
|
||||||
#[cfg(feature = "syslog_relay")]
|
#[cfg(feature = "syslog_relay")]
|
||||||
pub mod os_trace_relay;
|
pub mod os_trace_relay;
|
||||||
|
#[cfg(feature = "remote_pairing")]
|
||||||
|
pub mod remote_pairing;
|
||||||
#[cfg(feature = "restore_service")]
|
#[cfg(feature = "restore_service")]
|
||||||
pub mod restore_service;
|
pub mod restore_service;
|
||||||
#[cfg(feature = "rsd")]
|
#[cfg(feature = "rsd")]
|
||||||
|
|||||||
319
idevice/src/services/remote_pairing/mod.rs
Normal file
319
idevice/src/services/remote_pairing/mod.rs
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
// Jackson Coxson
|
||||||
|
|
||||||
|
use base64::{engine::general_purpose::STANDARD as B64, Engine as _};
|
||||||
|
use chacha20poly1305::{
|
||||||
|
aead::{Aead, Payload},
|
||||||
|
ChaCha20Poly1305, KeyInit as _, Nonce,
|
||||||
|
};
|
||||||
|
use ed25519_dalek::{Signature, SigningKey};
|
||||||
|
use hkdf::Hkdf;
|
||||||
|
use json::{object, JsonValue};
|
||||||
|
use log::{debug, warn};
|
||||||
|
use rp_pairing_file::RpPairingFile;
|
||||||
|
use rsa::signature::SignerMut;
|
||||||
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
|
|
||||||
|
use crate::{IdeviceError, ReadWrite};
|
||||||
|
|
||||||
|
pub mod rp_pairing_file;
|
||||||
|
mod tlv;
|
||||||
|
|
||||||
|
const RP_MAGIC: &str = "RPPairing";
|
||||||
|
|
||||||
|
pub struct RPPairingClient<R: ReadWrite> {
|
||||||
|
socket: R,
|
||||||
|
sequence_number: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: ReadWrite> RPPairingClient<R> {
|
||||||
|
pub fn new(socket: R) -> Self {
|
||||||
|
Self {
|
||||||
|
socket,
|
||||||
|
sequence_number: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn handshake(&mut self) -> Result<(), IdeviceError> {
|
||||||
|
let req = object! {
|
||||||
|
"request": {
|
||||||
|
"_0": {
|
||||||
|
"handshake": {
|
||||||
|
"_0": {
|
||||||
|
"hostOptions": {
|
||||||
|
"attemptPairVerify": true
|
||||||
|
},
|
||||||
|
"wireProtocolVersion": 24
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.send_plain(req).await?;
|
||||||
|
let res = self.read_json().await?;
|
||||||
|
debug!("Handshake response: {res:#}");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn pair(&mut self) -> Result<RpPairingFile, IdeviceError> {
|
||||||
|
let pairing = RpPairingFile::generate();
|
||||||
|
|
||||||
|
// M1 for a NEW pairing
|
||||||
|
let t = vec![
|
||||||
|
tlv::TLV8Entry {
|
||||||
|
tlv_type: tlv::PairingDataComponentType::Method,
|
||||||
|
data: vec![0x00],
|
||||||
|
},
|
||||||
|
tlv::TLV8Entry {
|
||||||
|
tlv_type: tlv::PairingDataComponentType::State,
|
||||||
|
data: vec![0x01],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
let t = B64.encode(tlv::serialize_tlv8(&t));
|
||||||
|
|
||||||
|
self.send_pairing_data(object! {
|
||||||
|
"data": t,
|
||||||
|
"kind": "setupManualPairing",
|
||||||
|
"sendingHost": "Mac",
|
||||||
|
"startNewSession": true,
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let res = self.read_event_data().await?;
|
||||||
|
debug!("Pair (M1) res: {res:#?}");
|
||||||
|
|
||||||
|
// M2: Now you handle the SRP steps...
|
||||||
|
todo!("Implement SRP steps using the device's public key and salt from the response");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn validate_pairing(&mut self, pairing: RpPairingFile) -> Result<(), IdeviceError> {
|
||||||
|
let pairing_data = tlv::serialize_tlv8(&[
|
||||||
|
tlv::TLV8Entry {
|
||||||
|
tlv_type: tlv::PairingDataComponentType::State,
|
||||||
|
data: vec![0x01],
|
||||||
|
},
|
||||||
|
tlv::TLV8Entry {
|
||||||
|
tlv_type: tlv::PairingDataComponentType::PublicKey,
|
||||||
|
data: pairing.x_public_key.to_bytes().to_vec(),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
let pairing_data = B64.encode(pairing_data);
|
||||||
|
|
||||||
|
let req = object! {
|
||||||
|
"event": {
|
||||||
|
"_0": {
|
||||||
|
"pairingData": {
|
||||||
|
"_0": {
|
||||||
|
"data": pairing_data,
|
||||||
|
"kind": "verifyManualPairing",
|
||||||
|
"startNewSession": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.send_plain(req).await?;
|
||||||
|
let res = self.read_json().await?;
|
||||||
|
debug!("Public key response: {res:#}");
|
||||||
|
let data =
|
||||||
|
&res["message"]["plain"]["_0"]["event"]["_0"]["pairingData"]["_0"]["data"].as_str();
|
||||||
|
let data = match data {
|
||||||
|
Some(d) => d,
|
||||||
|
None => {
|
||||||
|
warn!("RPPairing validate pair message didn't contain pairingData -> _0 -> data");
|
||||||
|
return Err(IdeviceError::UnexpectedResponse);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let data = B64.decode(data)?;
|
||||||
|
let data = tlv::deserialize_tlv8(&data)?;
|
||||||
|
println!("{data:#?}");
|
||||||
|
|
||||||
|
let device_public_key = match data
|
||||||
|
.iter()
|
||||||
|
.find(|x| x.tlv_type == tlv::PairingDataComponentType::PublicKey)
|
||||||
|
{
|
||||||
|
Some(d) => d,
|
||||||
|
None => {
|
||||||
|
warn!("No public key in TLV data");
|
||||||
|
return Err(IdeviceError::UnexpectedResponse);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let peer_pub_bytes: [u8; 32] = match device_public_key.data.as_slice().try_into() {
|
||||||
|
Ok(d) => d,
|
||||||
|
Err(_) => {
|
||||||
|
warn!("Device public key isn't the expected size");
|
||||||
|
return Err(IdeviceError::NotEnoughBytes(
|
||||||
|
32,
|
||||||
|
device_public_key.data.len(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let device_public_key = x25519_dalek::PublicKey::from(peer_pub_bytes);
|
||||||
|
let shared_secret = pairing.x_private_key.diffie_hellman(&device_public_key);
|
||||||
|
|
||||||
|
// Derive encryption key with HKDF-SHA512
|
||||||
|
let hk =
|
||||||
|
Hkdf::<sha2::Sha512>::new(Some(b"Pair-Verify-Encrypt-Salt"), shared_secret.as_bytes());
|
||||||
|
|
||||||
|
let mut okm = [0u8; 32];
|
||||||
|
hk.expand(b"Pair-Verify-Encrypt-Info", &mut okm).unwrap();
|
||||||
|
|
||||||
|
// ChaCha20Poly1305 AEAD cipher
|
||||||
|
let cipher = ChaCha20Poly1305::new(chacha20poly1305::Key::from_slice(&okm));
|
||||||
|
|
||||||
|
let mut ed25519_signing_key = pairing.e_private_key;
|
||||||
|
|
||||||
|
let mut signbuf = Vec::with_capacity(32 + pairing.identifier.len() + 32);
|
||||||
|
signbuf.extend_from_slice(pairing.x_public_key.as_bytes()); // 32 bytes
|
||||||
|
signbuf.extend_from_slice(pairing.identifier.as_bytes()); // variable
|
||||||
|
signbuf.extend_from_slice(device_public_key.as_bytes()); // 32 bytes
|
||||||
|
|
||||||
|
let signature: Signature = ed25519_signing_key.sign(&signbuf);
|
||||||
|
|
||||||
|
let plaintext = vec![
|
||||||
|
tlv::TLV8Entry {
|
||||||
|
tlv_type: tlv::PairingDataComponentType::Identifier,
|
||||||
|
data: pairing.identifier.as_bytes().to_vec(),
|
||||||
|
},
|
||||||
|
tlv::TLV8Entry {
|
||||||
|
tlv_type: tlv::PairingDataComponentType::Signature,
|
||||||
|
data: signature.to_vec(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
let plaintext = tlv::serialize_tlv8(&plaintext);
|
||||||
|
let nonce = Nonce::from_slice(b"\x00\x00\x00\x00PV-Msg03"); // 12-byte nonce
|
||||||
|
let ciphertext = cipher
|
||||||
|
.encrypt(
|
||||||
|
nonce,
|
||||||
|
Payload {
|
||||||
|
msg: &plaintext,
|
||||||
|
aad: &[],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.expect("encryption should not fail");
|
||||||
|
|
||||||
|
let msg = vec![
|
||||||
|
tlv::TLV8Entry {
|
||||||
|
tlv_type: tlv::PairingDataComponentType::State,
|
||||||
|
data: [0x03].to_vec(),
|
||||||
|
},
|
||||||
|
tlv::TLV8Entry {
|
||||||
|
tlv_type: tlv::PairingDataComponentType::EncryptedData,
|
||||||
|
data: ciphertext,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
let msg = object! {"event": {"_0": {"pairingData": {"_0": {
|
||||||
|
"data": B64.encode(tlv::serialize_tlv8(&msg)),
|
||||||
|
"kind": "verifyManualPairing",
|
||||||
|
"startNewSession": false}}}}};
|
||||||
|
|
||||||
|
self.send_plain(msg).await?;
|
||||||
|
|
||||||
|
let res = self.read_json().await?;
|
||||||
|
debug!("Verify response: {res:#}");
|
||||||
|
|
||||||
|
let data =
|
||||||
|
&res["message"]["plain"]["_0"]["event"]["_0"]["pairingData"]["_0"]["data"].as_str();
|
||||||
|
let data = match data {
|
||||||
|
Some(d) => d,
|
||||||
|
None => {
|
||||||
|
warn!("RPPairing validate pair message didn't contain pairingData -> _0 -> data");
|
||||||
|
return Err(IdeviceError::UnexpectedResponse);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let data = B64.decode(data)?;
|
||||||
|
let data = tlv::deserialize_tlv8(&data)?;
|
||||||
|
println!("{data:#?}");
|
||||||
|
|
||||||
|
// Check if the device responded with an error (which is expected for a new pairing)
|
||||||
|
if data
|
||||||
|
.iter()
|
||||||
|
.any(|x| x.tlv_type == tlv::PairingDataComponentType::ErrorResponse)
|
||||||
|
{
|
||||||
|
debug!("Verification failed, device reported an error. This is expected for a new pairing.");
|
||||||
|
tokio::time::sleep(std::time::Duration::from_secs(3)).await;
|
||||||
|
// Tell the device we are aborting the verification attempt.
|
||||||
|
let msg = object! {"event": {"_0": {"pairVerifyFailed": {}}}};
|
||||||
|
self.send_plain(msg).await?;
|
||||||
|
|
||||||
|
tokio::time::sleep(std::time::Duration::from_secs(3)).await;
|
||||||
|
|
||||||
|
self.pair().await?;
|
||||||
|
// Return a specific error to the caller.
|
||||||
|
return Err(IdeviceError::PairVerifyFailed);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_pairing_data(&mut self, data: JsonValue) -> Result<(), IdeviceError> {
|
||||||
|
self.send_event(object! {
|
||||||
|
"pairingData": {
|
||||||
|
"_0": data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_event(&mut self, data: JsonValue) -> Result<(), IdeviceError> {
|
||||||
|
let req = object! {
|
||||||
|
"event": {
|
||||||
|
"_0": data
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.send_plain(req).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn read_event_data(&mut self) -> Result<Vec<tlv::TLV8Entry>, IdeviceError> {
|
||||||
|
let res = self.read_json().await?;
|
||||||
|
match &res["message"]["plain"]["_0"]["event"]["_0"]["pairingData"]["_0"]["data"].as_str() {
|
||||||
|
Some(r) => Ok(tlv::deserialize_tlv8(&B64.decode(r)?)?),
|
||||||
|
None => Err(IdeviceError::UnexpectedResponse),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_plain(&mut self, data: JsonValue) -> Result<(), IdeviceError> {
|
||||||
|
let req = object! {
|
||||||
|
sequenceNumber: self.sequence_number,
|
||||||
|
originatedBy: "host",
|
||||||
|
message: {
|
||||||
|
plain: {
|
||||||
|
_0: data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
debug!("Sending {req:#}");
|
||||||
|
|
||||||
|
self.sequence_number += 1;
|
||||||
|
self.send_json(req).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_json(&mut self, data: JsonValue) -> Result<(), IdeviceError> {
|
||||||
|
// Send the magic
|
||||||
|
self.socket.write_all(RP_MAGIC.as_bytes()).await?;
|
||||||
|
|
||||||
|
// Packet length
|
||||||
|
let data = data.to_string().into_bytes();
|
||||||
|
self.socket.write_u16(data.len() as u16).await?; // big endian
|
||||||
|
|
||||||
|
self.socket.write_all(&data).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn read_json(&mut self) -> Result<JsonValue, IdeviceError> {
|
||||||
|
// Read the magic
|
||||||
|
let mut magic_buf = [0u8; RP_MAGIC.len()];
|
||||||
|
self.socket.read_exact(&mut magic_buf).await?;
|
||||||
|
|
||||||
|
// Read JSON length
|
||||||
|
let len = self.socket.read_u16().await?;
|
||||||
|
|
||||||
|
let mut buf = vec![0u8; len as usize];
|
||||||
|
self.socket.read_exact(&mut buf).await?;
|
||||||
|
|
||||||
|
let data = String::from_utf8_lossy(&buf);
|
||||||
|
Ok(json::parse(&data)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
35
idevice/src/services/remote_pairing/rp_pairing_file.rs
Normal file
35
idevice/src/services/remote_pairing/rp_pairing_file.rs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
// Jackson Coxson
|
||||||
|
|
||||||
|
use ed25519_dalek::{SigningKey, VerifyingKey};
|
||||||
|
use rsa::rand_core::OsRng;
|
||||||
|
use x25519_dalek::{EphemeralSecret, PublicKey as X25519PublicKey};
|
||||||
|
|
||||||
|
pub struct RpPairingFile {
|
||||||
|
pub(crate) x_private_key: EphemeralSecret,
|
||||||
|
pub(crate) x_public_key: X25519PublicKey,
|
||||||
|
pub(crate) e_private_key: SigningKey,
|
||||||
|
pub(crate) e_public_key: VerifyingKey,
|
||||||
|
pub(crate) identifier: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RpPairingFile {
|
||||||
|
pub fn generate() -> Self {
|
||||||
|
// X25519 private key (ephemeral)
|
||||||
|
let x25519_private_key = EphemeralSecret::random_from_rng(OsRng);
|
||||||
|
let x25519_public_key = X25519PublicKey::from(&x25519_private_key);
|
||||||
|
|
||||||
|
// Ed25519 private key (persistent signing key)
|
||||||
|
let ed25519_private_key = SigningKey::generate(&mut OsRng);
|
||||||
|
let ed25519_public_key = VerifyingKey::from(&ed25519_private_key);
|
||||||
|
|
||||||
|
let identifier = uuid::Uuid::new_v4().to_string().to_uppercase();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
x_private_key: x25519_private_key,
|
||||||
|
x_public_key: x25519_public_key,
|
||||||
|
e_private_key: ed25519_private_key,
|
||||||
|
e_public_key: ed25519_public_key,
|
||||||
|
identifier,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
133
idevice/src/services/remote_pairing/tlv.rs
Normal file
133
idevice/src/services/remote_pairing/tlv.rs
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
// Jackson Coxson
|
||||||
|
|
||||||
|
use crate::IdeviceError;
|
||||||
|
|
||||||
|
// from pym3
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum PairingDataComponentType {
|
||||||
|
Method = 0x00,
|
||||||
|
Identifier = 0x01,
|
||||||
|
Salt = 0x02,
|
||||||
|
PublicKey = 0x03,
|
||||||
|
Proof = 0x04,
|
||||||
|
EncryptedData = 0x05,
|
||||||
|
State = 0x06,
|
||||||
|
ErrorResponse = 0x07,
|
||||||
|
RetryDelay = 0x08,
|
||||||
|
Certificate = 0x09,
|
||||||
|
Signature = 0x0a,
|
||||||
|
Permissions = 0x0b,
|
||||||
|
FragmentData = 0x0c,
|
||||||
|
FragmentLast = 0x0d,
|
||||||
|
SessionId = 0x0e,
|
||||||
|
Ttl = 0x0f,
|
||||||
|
ExtraData = 0x10,
|
||||||
|
Info = 0x11,
|
||||||
|
Acl = 0x12,
|
||||||
|
Flags = 0x13,
|
||||||
|
ValidationData = 0x14,
|
||||||
|
MfiAuthToken = 0x15,
|
||||||
|
MfiProductType = 0x16,
|
||||||
|
SerialNumber = 0x17,
|
||||||
|
MfiAuthTokenUuid = 0x18,
|
||||||
|
AppFlags = 0x19,
|
||||||
|
OwnershipProof = 0x1a,
|
||||||
|
SetupCodeType = 0x1b,
|
||||||
|
ProductionData = 0x1c,
|
||||||
|
AppInfo = 0x1d,
|
||||||
|
Separator = 0xff,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct TLV8Entry {
|
||||||
|
pub tlv_type: PairingDataComponentType,
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TLV8Entry {
|
||||||
|
/// SRP stage
|
||||||
|
pub fn m(stage: u8) -> Self {
|
||||||
|
Self {
|
||||||
|
tlv_type: PairingDataComponentType::State,
|
||||||
|
data: [stage].to_vec(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serialize_tlv8(entries: &[TLV8Entry]) -> Vec<u8> {
|
||||||
|
let mut out = Vec::new();
|
||||||
|
for entry in entries {
|
||||||
|
out.push(entry.tlv_type as u8);
|
||||||
|
out.push(entry.data.len() as u8);
|
||||||
|
out.extend(&entry.data);
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_tlv8(input: &[u8]) -> Result<Vec<TLV8Entry>, IdeviceError> {
|
||||||
|
let mut index = 0;
|
||||||
|
let mut result = Vec::new();
|
||||||
|
|
||||||
|
while index + 2 <= input.len() {
|
||||||
|
let type_byte = input[index];
|
||||||
|
let length = input[index + 1] as usize;
|
||||||
|
index += 2;
|
||||||
|
|
||||||
|
if index + length > input.len() {
|
||||||
|
return Err(IdeviceError::MalformedTlv);
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = input[index..index + length].to_vec();
|
||||||
|
index += length;
|
||||||
|
|
||||||
|
let tlv_type = PairingDataComponentType::try_from(type_byte)
|
||||||
|
.map_err(|_| IdeviceError::UnknownTlv(type_byte))?;
|
||||||
|
|
||||||
|
result.push(TLV8Entry { tlv_type, data });
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for PairingDataComponentType {
|
||||||
|
type Error = u8;
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
use PairingDataComponentType::*;
|
||||||
|
Ok(match value {
|
||||||
|
0x00 => Method,
|
||||||
|
0x01 => Identifier,
|
||||||
|
0x02 => Salt,
|
||||||
|
0x03 => PublicKey,
|
||||||
|
0x04 => Proof,
|
||||||
|
0x05 => EncryptedData,
|
||||||
|
0x06 => State,
|
||||||
|
0x07 => ErrorResponse,
|
||||||
|
0x08 => RetryDelay,
|
||||||
|
0x09 => Certificate,
|
||||||
|
0x0a => Signature,
|
||||||
|
0x0b => Permissions,
|
||||||
|
0x0c => FragmentData,
|
||||||
|
0x0d => FragmentLast,
|
||||||
|
0x0e => SessionId,
|
||||||
|
0x0f => Ttl,
|
||||||
|
0x10 => ExtraData,
|
||||||
|
0x11 => Info,
|
||||||
|
0x12 => Acl,
|
||||||
|
0x13 => Flags,
|
||||||
|
0x14 => ValidationData,
|
||||||
|
0x15 => MfiAuthToken,
|
||||||
|
0x16 => MfiProductType,
|
||||||
|
0x17 => SerialNumber,
|
||||||
|
0x18 => MfiAuthTokenUuid,
|
||||||
|
0x19 => AppFlags,
|
||||||
|
0x1a => OwnershipProof,
|
||||||
|
0x1b => SetupCodeType,
|
||||||
|
0x1c => ProductionData,
|
||||||
|
0x1d => AppInfo,
|
||||||
|
0xff => Separator,
|
||||||
|
other => return Err(other),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -93,6 +93,10 @@ path = "src/lockdown.rs"
|
|||||||
name = "restore_service"
|
name = "restore_service"
|
||||||
path = "src/restore_service.rs"
|
path = "src/restore_service.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "remote_pairing"
|
||||||
|
path = "src/remote_pairing.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
idevice = { path = "../idevice", features = ["full"] }
|
idevice = { path = "../idevice", features = ["full"] }
|
||||||
tokio = { version = "1.43", features = ["io-util", "macros", "time", "full"] }
|
tokio = { version = "1.43", features = ["io-util", "macros", "time", "full"] }
|
||||||
|
|||||||
25
tools/src/remote_pairing.rs
Normal file
25
tools/src/remote_pairing.rs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// Jackson Coxson
|
||||||
|
|
||||||
|
use idevice::{
|
||||||
|
remote_pairing::{rp_pairing_file::RpPairingFile, RPPairingClient},
|
||||||
|
IdeviceError,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), IdeviceError> {
|
||||||
|
env_logger::init();
|
||||||
|
let conn = tokio::net::TcpStream::connect("192.168.50.247:49152")
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut client = RPPairingClient::new(conn);
|
||||||
|
client.handshake().await?;
|
||||||
|
let pairing = RpPairingFile::generate();
|
||||||
|
client
|
||||||
|
.validate_pairing(pairing)
|
||||||
|
.await
|
||||||
|
.expect("No validate?");
|
||||||
|
client.pair().await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user