diff --git a/.gitignore b/.gitignore index e19836e..a5be872 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ build/ .gradle/ .kotlin/ local.properties +registration/dev/ diff --git a/docs/imessage-protocol-spec.md b/docs/imessage-protocol-spec.md index 0d605f2..b6ad4ce 100644 --- a/docs/imessage-protocol-spec.md +++ b/docs/imessage-protocol-spec.md @@ -21,7 +21,7 @@ - Current shipped flow (OpenBubbles, 2026): the Mac-side helper (`Mac-Hardware-Info` 1.2.0, notarized) only *reads* the machine identifiers — serial, board ID, model, etc. — via public IORegistry/sysctl APIs (docs: "High Sierra and above", no upper macOS version bound) and exports them as a shareable code (≤ 20 users per code, optional one-time-use/48-hour mode); it never invokes an Apple private framework [OB-MHI], [OB-FAQ]. The client then performs the three-step exchange above itself, in software, keyed with those identifiers and paired with an Apple-Account login — the [JJ] emulation path with an official identifier-export helper in front of it. `TODO(capture):` **C56** — the client-side generation procedure behind the three-step exchange: what the client computes with the `id-initialize-validation` session info (the key-establishment math and blob assembly), how it interacts with the Apple-Account/GSA login and the anisette header set (C6) at activation time, and which pieces are fixed protocol constants vs per-account/per-session state. — 2026-09-10: steps 1–2 of C56 are recorded (bullet above); step 3 — key establishment + signing — is closed source: the public OpenAbsinthe-Stub repo is an official mock whose methods are stubs (its README states the real repository is closed source), so the spec records only the API contract: context creation consumes the certificate chain + hardware configuration and outputs the session-info-request blob; key establishment consumes the server response; signing produces the final blob with no further inputs (all state retained in the context) [RP:macos.rs], [RP:activation.rs], [RP:auth.rs], [OA]. Remaining: wire-verification of the blob against one live activation; the enc-variant derivation rides C57. — 2026-09-11 (rev 14 extraction): the five obfuscation labels are now MAPPED to their fields (previously only listed together): serial → `Gq3489ugfi`, platform UUID → `Fyp98tpgj`, root-disk UUID → `kbjfrfpoJU`, ROM → `oycqAZloTNDm`, MLB → `abKPld1EcMni` [OA:nac.rs]; the derivation producing each `_enc` byte variant is still closed source. The hardware-configuration field set is recorded in full: product name (Apple product-type form, e.g. `Macmini9,1`), MAC address (exactly 6 raw bytes), platform serial, platform UUID, root-disk UUID, board ID, OS build number, ROM (raw bytes), MLB, plus the five `_enc` raw-byte variants [OA:nac.rs]. Step 3's closure is confirmed at the source level: the crate holding the key-establishment math ships as a closed-source stub whose mock methods panic; only the API contract is observable [OA:README.md], [OA:nac.rs]. - The helper's export-code format (2026-09-11, rev 15 — **C58 closed** by facts-only extraction from the helper's public upstream repo, which is unlicensed — facts only): the payload is a 4-byte ASCII magic `OABS`, a one-byte flag (1 = "prevent sharing" mode, 0 otherwise), then a raw protobuf message (no length prefix; protobuf starts at offset 5). Protobuf field map: outer — 1 nested identifier message, 2 macOS product version (sysctl `kern.osproductversion`), 3 protocol version (hardcoded `1640`), 4 device id (the IOPlatformUUID again), 5 a hardcoded iCloudHelper user-agent string, 6 a hardcoded AOSKit version string; nested identifier message — 1 product name (e.g. `MacBookPro18,3`), 2 MAC address (6 raw bytes), 3 platform serial, 4 platform UUID, 5 root-disk UUID, 6 board ID (Apple Silicon: literal prefix `Mac-` + lowercase hex of the device-tree board-id bytes), 7 OS build number (sysctl `kern.osversion`), 8/9/10/12/14 the five `_enc` obfuscated blobs read from the `IOPower:/` registry under Apple's key names (`Gq3489ugfi` serial, `Fyp98tpgj` platform UUID, `kbjfrfpoJU` root-disk UUID, `oycqAZloTNDm` ROM, `abKPld1EcMni` MLB — matching §1.1's label mapping), 11 ROM (Intel: the device-tree options ROM value; Apple Silicon: last 6 bytes of SHA-256 of `/chosen` `unique-chip-id`), 13 MLB string. Two delivery modes: plain = standard base64 of the payload (clipboard text, or the raw payload bytes as a QR code at medium error correction); restricted = AES-256-CBC/PKCS7 over the payload, ciphertext prefixed with ASCII `Salted__` + 8-byte random salt (legacy OpenSSL `enc` container), key/IV derived by the legacy EVP_BytesToKey KDF (repeated MD5 of previous-hash ‖ password ‖ salt to 48 bytes: first 32 = key, next 16 = IV) keyed by a human activation code (`MB` + 4×4 chars from the alphabet `ABCDEFGHJKLMNPQRSTUVWXYZ123456789`), then base64. The restricted mode additionally uploads the blob (JSON `data` + `id` = lowercase hex SHA-256 of the activation code) to the vendor's server (`hw.openbubbles.app/code`) — the ≤20-user/one-time/48-hour mechanics live SERVER-side; nothing is embedded in the payload (no checksum, signature, compression, or expiry). No public parser exists (the client apps are closed-source); the construction above is the parse specification [MHG:ViewController.swift], [MHG:HwIdentifiers.swift], [MHG:mac_hw_info.pb.swift]. - The validation blob is submitted as the `validation-data` field of the IDS register body and, base64, in the `X-Mme-Nas-Qualify` header of the iCloud account login [RP:ids/user.rs], [RP:auth.rs]. `TODO(capture):` C5 — exact byte shape of the blob a genuine Mac produces, and the current exchange over the two validation bag URLs. — 2026-10-04 (rev 26, live): **REPLAY GUARD — one mint = one device record.** Apple keys a validation blob's consumption server-side: re-submitting an already-consumed blob at the sign-in/register pair answers HTTP 409, which is a REPLAY refusal, NOT a blob rejection — a fresh blob under the same device identity succeeds where the reused one failed, and a captured blob of external provenance succeeds outright (session 17: a captured stamp replaced the local mint and the 409 vanished). Client consequences: mint or fetch a fresh blob per registration attempt (the 15-minute validity above makes stale reuse doubly fatal), and mint the sign-in's blob AT SIGN-IN TIME — never a login-start blob carried across the 2FA wait. A caller-injected blob from any source (local mint, relay Mac, staged capture) is a legitimate stamp; the injection points are the register body's `validation-data` and the sign-in's `X-Mme-Nas-Qualify` header. -- Hardware-related anisette headers seen in activation flows: `X-Apple-I-SRL-NO` (serial), `X-Apple-I-MLB` (logic-board serial), `X-Apple-I-ROM` (hex ROM, lowercase) [RP:relay.rs], [APA:anisette]. `TODO(capture):` C6 — the full anisette header set a current client actually sends, including which optional hardware headers appear. — 2026-09-10: the header-set half of C6 is closed by facts-only extraction: per-request anisette headers `X-Apple-I-Client-Time`, `X-Apple-I-TimeZone`, `X-Apple-Locale`, `X-Apple-I-MD-RINFO`, `X-Mme-Device-Id`, `X-Apple-I-MD` (base64 OTP), `X-Apple-I-MD-M` (base64 machine ID), plus per-platform hardware headers — macOS: `X-Apple-I-MLB`, `X-Apple-I-ROM` (lowercase hex), `X-Apple-I-SRL-NO` [APA:omnisette], [APA:icloud-auth], [RP:relay.rs]. They are produced by an ADI provisioning exchange with gsa.apple.com (start/finish provisioning returning machine tokens), then a local OTP [APA:omnisette]. GSA context (cross-referenced with C6): the Albert activation itself needs NO Apple-Account login — only the FairPlay-signed activation-info plist (§1.2); the GSA login (full Apple-ID password, SRP over gsa.apple.com/grandslam/GsService2, s2k/s2k_fo PBKDF2, 2FA-capable) feeds the delegate logins that yield the IDS `auth-token`/`profile-id` and the PET token [RP:auth.rs], [APA:icloud-auth]. The extraction confirms the validation blob rides base64 in the `X-Mme-Nas-Qualify` header of the iCloud sign-in POST (recorded above) [RP:auth.rs]. — 2026-09-11 (rev 14 extraction round over the anisette crates): the value-format and provisioning halves of C6 are closed. Per-request value forms: `X-Apple-I-Client-Time` = UTC now truncated to whole seconds, RFC 3339/ISO-8601 with the offset suffix replaced by `Z` (provisioning requests send the raw offset form without the Z — a recorded inconsistency between code paths); `X-Apple-I-TimeZone` = literal `UTC` (not the device zone); `X-Apple-Locale` = `en_US` hardcoded (a companion `X-Apple-I-Locale: en_US` variant exists on the browser-style header set); `X-Apple-I-MD-RINFO` = verbatim passthrough of the string returned in the finish-provisioning response; `X-Mme-Device-Id` = lowercase hyphenated UUID string of 16 locally random bytes (`keychain_identifier`); `X-Apple-I-MD-M` = base64 (standard, padded) of the 60-byte `mid`; `X-Apple-I-MD-LU` = lowercase hex (no dashes) SHA-256 over the same 16 bytes (real macOS instead uses AuthKit's local-user UUID) — present in some header sets, omitted in others (disagreement — C57). Header sets are cached 60 s; a fresh OTP is generated per cache miss. The ADI provisioning flow: `GET https://gsa.apple.com/grandslam/GsService2/lookup` → XML plist whose `urls` keys `midStartProvisioning`/`midFinishProvisioning` give the endpoint URLs (never hardcoded); POST to the start URL with an XML plist body of two empty top-level dicts `Header` and `Request` → response `Response` → `spim` (base64); a local session is built from `spim` (+ empty hostuuid, DSID `-2`, flavor `Mac`=1 / `IOS`=3, flavor chosen by whether the client-info string contains `iPhone OS`) yielding `cpim` (base64); POST to the finish URL with `Request` = {`cpim`} → response `Response` → `ptm`, `tk` (both base64) and `X-Apple-I-MD-RINFO`; finishing the session with the decoded `tk`/`ptm` yields the machine state: `client_secret` (32 bytes), `mid` (60 bytes, Apple-issued at provisioning — reused for every OTP until re-provisioning, which happens only on a not-provisioned failure, e.g. ADI error -45061), `metadata` (variable blob). Provisioning HTTP specifics: `Content-Type: application/x-www-form-urlencoded` despite the XML-plist body (intentional), title-cased header names forced, HTTP/1.1, Apple root CA pinned (embedded DER), and a fixed companion header set on all three requests: akd `User-Agent`, `X-Apple-Baa-E: -10000`, `X-Apple-Baa-Avail: 2`, `X-Apple-Baa-UE: AKAuthenticationError:-7066|com.apple.devicecheck.error.baa:-10000`, `X-Apple-Host-Baa-E: -7066`, `X-Apple-Client-App-Name: akd`, `Accept: */*`, `Accept-Language: en-US,en;q=0.9`, plus `X-Apple-I-MD-LU`, `X-Mme-Device-Id`, `X-Mme-Client-Info`, `X-Apple-I-Client-Time` and any caller-supplied hardware headers. State persists as an XML plist with `keychain_identifier` (data) + the provisioned fields (`client_secret`, `mid`, `metadata`, `rinfo`, `flavor`) [APA:omnisette]. CLOSED-SOURCE RESIDUE: the OTP (`X-Apple-I-MD`) and trusted-device 2FA-code derivations live inside a closed-source crate — its public repo is a stub with `todo!()` methods; recorded is only the call contract: inputs (32-byte `client_secret`, 60-byte `mid`, `metadata`, flavor) → raw OTP bytes (base64 into the header) / 32-bit 2FA code [OA-stub], [APA:omnisette]. — rides C57/C56 residue; the seam stays injectable in the code. +- Hardware-related anisette headers seen in activation flows: `X-Apple-I-SRL-NO` (serial), `X-Apple-I-MLB` (logic-board serial), `X-Apple-I-ROM` (hex ROM, lowercase) [RP:relay.rs], [APA:anisette]. `TODO(capture):` C6 — the full anisette header set a current client actually sends, including which optional hardware headers appear. — 2026-09-10: the header-set half of C6 is closed by facts-only extraction: per-request anisette headers `X-Apple-I-Client-Time`, `X-Apple-I-TimeZone`, `X-Apple-Locale`, `X-Apple-I-MD-RINFO`, `X-Mme-Device-Id`, `X-Apple-I-MD` (base64 OTP), `X-Apple-I-MD-M` (base64 machine ID), plus per-platform hardware headers — macOS: `X-Apple-I-MLB`, `X-Apple-I-ROM` (lowercase hex), `X-Apple-I-SRL-NO` [APA:omnisette], [APA:icloud-auth], [RP:relay.rs]. They are produced by an ADI provisioning exchange with gsa.apple.com (start/finish provisioning returning machine tokens), then a local OTP [APA:omnisette]. GSA context (cross-referenced with C6): the Albert activation itself needs NO Apple-Account login — only the FairPlay-signed activation-info plist (§1.2); the GSA login (full Apple-ID password, SRP over gsa.apple.com/grandslam/GsService2, s2k/s2k_fo PBKDF2, 2FA-capable) feeds the delegate logins that yield the IDS `auth-token`/`profile-id` and the PET token [RP:auth.rs], [APA:icloud-auth]. The extraction confirms the validation blob rides base64 in the `X-Mme-Nas-Qualify` header of the iCloud sign-in POST (recorded above) [RP:auth.rs]. — 2026-09-11 (rev 14 extraction round over the anisette crates): the value-format and provisioning halves of C6 are closed. Per-request value forms: `X-Apple-I-Client-Time` = UTC now truncated to whole seconds, RFC 3339/ISO-8601 with the offset suffix replaced by `Z` (provisioning requests send the raw offset form without the Z — a recorded inconsistency between code paths); `X-Apple-I-TimeZone` = literal `UTC` (not the device zone); `X-Apple-Locale` = `en_US` hardcoded (a companion `X-Apple-I-Locale: en_US` variant exists on the browser-style header set); `X-Apple-I-MD-RINFO` = verbatim passthrough of the string returned in the finish-provisioning response; `X-Mme-Device-Id` = lowercase hyphenated UUID string of 16 locally random bytes (`keychain_identifier`); `X-Apple-I-MD-M` = base64 (standard, padded) of the 60-byte `mid`; `X-Apple-I-MD-LU` = lowercase hex (no dashes) SHA-256 over the same 16 bytes (real macOS instead uses AuthKit's local-user UUID) — present in some header sets, omitted in others (disagreement — C57). Header sets are cached 60 s; a fresh OTP is generated per cache miss. The ADI provisioning flow: `GET https://gsa.apple.com/grandslam/GsService2/lookup` → XML plist whose `urls` keys `midStartProvisioning`/`midFinishProvisioning` give the endpoint URLs (never hardcoded); POST to the start URL with an XML plist body of two empty top-level dicts `Header` and `Request` → response `Response` → `spim` (base64); a local session is built from `spim` (+ empty hostuuid, DSID `-2`, flavor `Mac`=1 / `IOS`=3, flavor chosen by whether the client-info string contains `iPhone OS`) yielding `cpim` (base64); POST to the finish URL with `Request` = {`cpim`} → response `Response` → `ptm`, `tk` (both base64) and `X-Apple-I-MD-RINFO`; finishing the session with the decoded `tk`/`ptm` yields the machine state: `client_secret` (32 bytes), `mid` (60 bytes, Apple-issued at provisioning — reused for every OTP until re-provisioning, which happens only on a not-provisioned failure, e.g. ADI error -45061), `metadata` (variable blob). Provisioning HTTP specifics: `Content-Type: application/x-www-form-urlencoded` despite the XML-plist body (intentional), title-cased header names forced, HTTP/1.1, Apple root CA pinned (embedded DER), and a fixed companion header set on all three requests: akd `User-Agent`, `X-Apple-Baa-E: -10000`, `X-Apple-Baa-Avail: 2`, `X-Apple-Baa-UE: AKAuthenticationError:-7066|com.apple.devicecheck.error.baa:-10000`, `X-Apple-Host-Baa-E: -7066`, `X-Apple-Client-App-Name: akd`, `Accept: */*`, `Accept-Language: en-US,en;q=0.9`, plus `X-Apple-I-MD-LU`, `X-Mme-Device-Id`, `X-Mme-Client-Info`, `X-Apple-I-Client-Time` and any caller-supplied hardware headers. State persists as an XML plist with `keychain_identifier` (data) + the provisioned fields (`client_secret`, `mid`, `metadata`, `rinfo`, `flavor`) [APA:omnisette]. CLOSED-SOURCE RESIDUE: the OTP (`X-Apple-I-MD`) and trusted-device 2FA-code derivations live inside a closed-source crate — its public repo is a stub with `todo!()` methods; recorded is only the call contract: inputs (32-byte `client_secret`, 60-byte `mid`, `metadata`, flavor) → raw OTP bytes (base64 into the header) / 32-bit 2FA code [OA-stub], [APA:omnisette]. — rides C57/C56 residue; the seam stays injectable in the code. — 2026-10-07 (rev 27, clean-room RE of the OpenBubbles ADI library — unstripped Linux `.so`, oracle-verified; the derivation is no longer closed residue): the OTP is fully local and pure. `gen = unix_seconds / 30`; dispatch by OTP flavor byte: 1 (IOS) → `gen_otp` (0x17fba60), 0 (Mac) → `gen_otp_ios` (0x1801d90) — the binary's naming is inverted relative to the flavor (a distinct numbering from the §1.1 session flavor `Mac`=1/`IOS`=3). Cipher inputs: `one` = the machine's `client_info` (required ≥ 0x190 B IOS / ≥ 0xd0 B Mac, length-checked) and `two` = the 32-byte `mid`; output 16 bytes. The wire `X-Apple-I-MD` frame is 28 B: `u32be(5)` ‖ `u32be(16)` ‖ sig16 ‖ `u32be(flavor)`. The 2FA code is `SHA-1(sig16 ‖ secret60) mod 1_000_000` over the machine's full 60-byte secret slice (`machine[0x38..0x74]`; two standard SHA-1 blocks — an earlier report's "48-byte" reading is wrong, 0x18013a2/0x18013bb/0x18013ef). Provisioning framing, asm-pinned: `spim` = `field1` u32 BE @0 ‖ payload-length u32 BE @4 ‖ payload @8 (payload must exceed 59 B, 0x17efb33; more than 23 trailing bytes rejected with error 0x41); `cpim` = 9 fields (u32be(32) ‖ `encsec(rng2)` 32 B ‖ u32be(32) ‖ rng1 32 B ‖ 60 B blob = caller-extra ‖ rng3 pad ‖ u64 BE of arg9 = −2 ‖ u32 BE of the byte-swapped LE dword at rng3[8..12] ‖ two 256-bit tail fields fed by `encrypt(session, rng16, data)` + `spim_map_signature` — the tail's exact wire assembly is `TODO(capture)`); `ptm` is lenient (u32 BE then the whole tail — every candidate shape accepted, error 0); finish requires `tk` exactly 16 B (error 0x8, 0x17f1f11), key16 = `encrypt(session, NULL iv, tk)` (0x17f1eac), decrypt block count = payload.size/16 (0x17f2548), yielding the 0x78-byte provisioned struct (+0x00 16 B, +0x10 u64, +0x18 u64, +0x20 16 B, +0x30..0x70 64 B metadata, +0x70 u32, +0x74 u8 flavor — which bytes are `client_secret` vs `mid` vs `metadata` is `TODO(capture)`). Kotlin: `registration` module `ClearAdiOtp`/`ClearAdiProvision`/`ClearAdiFraming`/`ClearAnisetteProvider`, 192 tests green incl. byte-exact oracle vectors. ### 1.2 Activation endpoints and certificates diff --git a/registration/src/main/kotlin/dev/fenn/imessage/registration/ClearAdiFraming.kt b/registration/src/main/kotlin/dev/fenn/imessage/registration/ClearAdiFraming.kt new file mode 100644 index 0000000..9c9a8b0 --- /dev/null +++ b/registration/src/main/kotlin/dev/fenn/imessage/registration/ClearAdiFraming.kt @@ -0,0 +1,250 @@ +package dev.fenn.imessage.registration + +/** + * Wire framing of the ClearADI provisioning exchange — the deku reads/writes around the + * already-ported ciphers ([ClearAdiProvision]). Ground truth: `ProvisioningSession::new` + * (0x17eebf0, new.asm) and `finish` (0x17f1e20, finish.asm) of librust_lib_bluebubbles; + * report at /tmp/clearadi-re/analysis/provisioning.md §6–§7. Every field the asm does not + * pin is named by role with its call site cited, never guessed. + */ + +/** The Spim byte stream did not match the shape `new()`'s deku reader accepts (0x17eec98). */ +class SpimFormatException(message: String) : Exception(message) + +/** + * The parsed Spim (start-provisioning `Response.spim`, base64 on the wire). + * + * Wire shape (proven from the asm and pinned against the live library): + * `field1` — u32 BE ([new.asm] 17eeca4; role unrecorded, reader position 4); + * `payloadLength` — u32 BE (17eed81) — the deku `ByteSize` limit of the payload Vec (17eeded); + * `payload` — the next [payloadLength] bytes; the reader rejects a payload of ≤ 59 bytes + * (17efb33, `cmp …,0x3b`) and feeds the 240-byte payload to [ClearAdiProvision.initSession] + * (17efb82). + * + * The asm continues with trailing reads ([T;N] 17eee41, `read_bytes_const` 17eeecd — the + * 0x20 size setup is at 17ef00b — and two u32 reads 17ef05f/17ef3e8). Empirically pinned + * against the live library: a Spim whose bytes after the payload are ≤ 23 parses fine and + * ≥ 24 fails with error 0x41 regardless of the payload length (60…256 tested). Their exact + * semantics are TODO(live-capture). + */ +data class Spim( + val field1: Int, + val payloadLength: Int, + val payload: ByteArray, +) { + companion object { + /** Minimum reader requirement (`cmp rdx,0x3; ja` 17eec6c): the first u32 must fit. */ + private const val MIN_LEN = 4 + /** `cmp QWORD PTR […],0x3b; ja` 17efb33 — the payload Vec must exceed 59 bytes. */ + private const val MIN_PAYLOAD = 60 + /** Live-pinned leftover tolerance: > 23 trailing bytes ⇒ error 0x41. TODO(live-capture). */ + private const val MAX_LEFTOVER = 23 + + fun parse(bytes: ByteArray): Spim { + if (bytes.size < MIN_LEN) throw SpimFormatException("spim shorter than the first u32 (${bytes.size} B)") + val field1 = beU32(bytes, 0) + if (bytes.size < 8) throw SpimFormatException("spim ends before the ByteSize u32") + val payloadLength = beU32(bytes, 4) + if (8 + payloadLength > bytes.size) { + throw SpimFormatException("spim payload Vec needs $payloadLength B, ${bytes.size - 8} available") + } + if (payloadLength < MIN_PAYLOAD) { + throw SpimFormatException("spim payload of $payloadLength B rejected (must exceed 59 B, 17efb33)") + } + val payload = bytes.copyOfRange(8, 8 + payloadLength) + val leftover = bytes.size - 8 - payloadLength + if (leftover > MAX_LEFTOVER) { + throw SpimFormatException("spim has $leftover trailing bytes; the live binary tolerates ≤ 23 (error 0x41)") + } + return Spim(field1, payloadLength, payload) + } + + private fun beU32(b: ByteArray, off: Int): Int = + ((b[off].toInt() and 0xff) shl 24) or ((b[off + 1].toInt() and 0xff) shl 16) or + ((b[off + 2].toInt() and 0xff) shl 8) or (b[off + 3].toInt() and 0xff) + } +} + +/** + * The random material `new()` pulls (thread_rng, 17ef8d1–17efac9): 32 + 32 + 60 bytes. + * Injected so Cpim builds are reproducible in tests; production supplies a secure RNG. + */ +fun interface ClearAdiRng { + /** [n] fresh random bytes (called with 32, 32, 60 in that order — keep draws independent). */ + fun draw(n: Int): ByteArray +} + +/** + * The two trailing 256-bit Cpim fields (provisioning.md §6 items 8–9, written as deku + * `write_bits(0x100)` calls at 17effc9/17f0338/17f0444). The asm shows the material they are + * derived from — `spim_map_signature` over a zeroed 16-byte block (17f0914–17f0931) and a + * SHA-256 over the `encrypt(session, iv16, payload)` output, where the IV is assembled from + * the parsed Spim's trailing fields (17f0848–17f0888) — but their exact wire assembly is not + * provable from the dump alone: TODO(live-capture). The production seal is wired after that + * capture; tests seal deterministically. + */ +fun interface CpimTailSeal { + /** + * Returns the pair of 32-byte Cpim tail fields. [sessionKey] is the 16-byte session key, + * [encryptedPayload] the `encrypt(session, iv, payload)` output, [signatureOfZeroBlock] + * the `spimMapSignature(ByteArray(16))` output, [sha256OfEncrypted] the SHA-256 digest of + * [encryptedPayload] — everything the asm shows feeding the region. + */ + fun seal( + sessionKey: ByteArray, + encryptedPayload: ByteArray, + signatureOfZeroBlock: ByteArray, + sha256OfEncrypted: ByteArray, + ): Pair +} + +/** + * The Cpim wire bytes (`new()`'s deku Writer output, provisioning.md §6 items 1–9): + * + * 1. `00 00 00 20` u32 BE (17efe9b) — the Vec length prefix of item 2 + * 2. `encsec(draw2)` (Vec#1, 32 B — encsec call 17efd5e on the second RNG draw) + * 3. `00 00 00 20` u32 BE — length prefix of item 4 + * 4. `draw1` raw (Vec#2, 32 B — the first RNG draw copied untouched, 17efc95) + * 5. the 60-byte blob: the caller's ≤ 60-byte `extra` slice, padded with the third RNG draw + * (the extra memcpy 17efb21 lands on the draw-3 slot, then the struct copy 17efcb5 takes + * exactly 60 bytes into the Cpim struct) + * 6. [gsaArg] as u64 BE — the omnisette reference passes −2 ("GSA"): `FF FF FF FF FF FF FF FE` + * 7. u32 BE — `bswap` of the little-endian dword at draw3[8..12] (17efc3c → struct +0x7c) + * 8–9. the two 256-bit [CpimTailSeal] fields — TODO(live-capture) + */ +object Cpim { + + /** `extra` must fit the fixed 60-byte blob slot (`cmp rdx,0x3d; jae` → error, 17efb17). */ + const val MAX_EXTRA = 60 + private const val BLOB_LEN = 60 + + fun build( + rng: ClearAdiRng, + extra: ByteArray, + gsaArg: Long, + sessionCtx: ByteArray, + payload240: ByteArray, + tail: CpimTailSeal?, + ): ByteArray { + require(extra.size <= MAX_EXTRA) { "extra blob of ${extra.size} B exceeds the 60 B Cpim slot (17efb17)" } + val draw1 = rng.draw(32) + val draw2 = rng.draw(32) + val draw3 = rng.draw(60) + val vec1 = ClearAdiProvision.encsec(draw2) + val blob = extra + draw3.copyOfRange(extra.size, BLOB_LEN) + val item7 = leU32(draw3, 8) + + val out = ByteArray(4 + 32 + 4 + 32 + BLOB_LEN + 8 + 4 + 32 + 32) + var p = 0 + p = putBeU32(out, p, 32) + System.arraycopy(vec1, 0, out, p, vec1.size); p += vec1.size + p = putBeU32(out, p, 32) + System.arraycopy(draw1, 0, out, p, draw1.size); p += draw1.size + System.arraycopy(blob, 0, out, p, blob.size); p += blob.size + p = putBeU64(out, p, gsaArg) + p = putBeU32(out, p, item7) + if (tail == null) { + throw IllegalStateException( + "Cpim tail fields (§6 items 8–9) need the live capture — no CpimTailSeal supplied (TODO(live-capture))", + ) + } + val iv16 = ByteArray(16) // IV assembled from the Spim's trailing fields — TODO(live-capture) + val encrypted = ClearAdiProvision.encrypt(sessionCtx, iv16, payload240) + val digest = java.security.MessageDigest.getInstance("SHA-256").digest(encrypted) + val signature = ClearAdiProvision.spimMapSignature(ByteArray(16)) + val (field8, field9) = tail.seal( + ClearAdiProvision.sessionKey(sessionCtx), + encrypted, + signature, + digest, + ) + require(field8.size == 32 && field9.size == 32) { "Cpim tail fields must be 32 B each" } + System.arraycopy(field8, 0, out, p, 32); p += 32 + System.arraycopy(field9, 0, out, p, 32); p += 32 + return out.copyOf(p) + } + + private fun putBeU32(b: ByteArray, off: Int, v: Int): Int { + b[off] = (v ushr 24).toByte(); b[off + 1] = (v ushr 16).toByte() + b[off + 2] = (v ushr 8).toByte(); b[off + 3] = v.toByte() + return off + 4 + } + + private fun putBeU64(b: ByteArray, off: Int, v: Long): Int { + for (i in 0 until 8) b[off + i] = (v ushr (56 - 8 * i)).toByte() + return off + 8 + } + + private fun leU32(b: ByteArray, off: Int): Int = + (b[off].toInt() and 0xff) or ((b[off + 1].toInt() and 0xff) shl 8) or + ((b[off + 2].toInt() and 0xff) shl 16) or ((b[off + 3].toInt() and 0xff) shl 24) +} + +/** + * The parsed Ptm (finish-provisioning `Response.ptm`, base64 on the wire). Same reader family + * as [Spim] (finish.asm 17f1f1e–17f2294): `field1` u32 BE first, then a lenient Vec (every + * candidate shape accepted by the live binary, error 0) whose bytes feed + * [ClearAdiProvision.decryptPtm] with `count = payload.size / 16` (17f2548). + * The live binary accepts every candidate shape thrown at it (u32 alone through 128 B tails, + * all error 0) — the trailing [T;N]/read_bytes_const/u32 reads (17f1f6a/17f1fd4/17f20e5) are + * lenient; their exact semantics TODO(live-capture). + */ +data class Ptm( + val field1: Int, + val payload: ByteArray, +) { + companion object { + /** Minimum reader requirement (finish `cmp …,0x3; ja` 17f1eec → 17f1f1e). */ + private const val MIN_LEN = 4 + + fun parse(bytes: ByteArray): Ptm { + if (bytes.size < MIN_LEN) throw SpimFormatException("ptm shorter than the first u32 (${bytes.size} B)") + val field1 = ((bytes[0].toInt() and 0xff) shl 24) or ((bytes[1].toInt() and 0xff) shl 16) or + ((bytes[2].toInt() and 0xff) shl 8) or (bytes[3].toInt() and 0xff) + // Lenient Vec: takes the whole tail after the first u32 — the live binary accepts + // every candidate shape (u32 alone through 128 B tails, all error 0), so field1 + // is not enforced as a length (its role is TODO(live-capture)). + return Ptm(field1, bytes.copyOfRange(4, bytes.size)) + } + } +} + +/** + * `finish()`'s return — the raw 0x78-byte ProvisionedData struct (17f2dec–17f2e56): + * +0x00 16 B, +0x10 u64, +0x18 u64, +0x20 16 B, +0x30..0x70 64 B (metadata blob), +0x70 u32, + * +0x74 u8 (flavor). Which bytes are `mid` vs `client_secret` is NOT provable from the dump + * (an OpenBubbles provisioning run under gdb is pending) — the cross-check against the + * OTP-path report's ProvisionedMachine (client_info 400/208 B, mid 32 B, secret 60 B, + * flavor) is likewise unconfirmed: TODO(live-capture) on the field mapping. Named accessors + * only; nothing is invented. + */ +data class ProvisionedData(val raw: ByteArray) { + init { + require(raw.size >= 0x78) { "ProvisionedData must be 0x78 bytes, got ${raw.size}" } + } + + /** +0x00, 16 B (role unproven). */ + val block00: ByteArray get() = raw.copyOfRange(0x00, 0x10) + /** +0x10, u64 LE (role unproven). */ + val word10: Long get() = le64(raw, 0x10) + /** +0x18, u64 LE (role unproven). */ + val word18: Long get() = le64(raw, 0x18) + /** +0x20, 16 B (role unproven). */ + val block20: ByteArray get() = raw.copyOfRange(0x20, 0x30) + /** +0x30..0x70, 64 B — the metadata blob per the OTP-path report's layout cross-check. */ + val metadata64: ByteArray get() = raw.copyOfRange(0x30, 0x70) + /** +0x70, u32 LE. */ + val word70: Int get() = le32(raw, 0x70) + /** +0x74, u8 — the flavor byte (Mac = 0, IOS = 1, per the ClearAdiOtp flavor convention). */ + val flavor: Int get() = raw[0x74].toInt() and 0xff + + private fun le32(b: ByteArray, off: Int): Int = + (b[off].toInt() and 0xff) or ((b[off + 1].toInt() and 0xff) shl 8) or + ((b[off + 2].toInt() and 0xff) shl 16) or ((b[off + 3].toInt() and 0xff) shl 24) + + private fun le64(b: ByteArray, off: Int): Long { + var v = 0L + for (i in 7 downTo 0) v = (v shl 8) or (b[off + i].toLong() and 0xff) + return v + } +} diff --git a/registration/src/main/kotlin/dev/fenn/imessage/registration/ClearAdiOtp.kt b/registration/src/main/kotlin/dev/fenn/imessage/registration/ClearAdiOtp.kt new file mode 100644 index 0000000..7ff4135 --- /dev/null +++ b/registration/src/main/kotlin/dev/fenn/imessage/registration/ClearAdiOtp.kt @@ -0,0 +1,1168 @@ +package dev.fenn.imessage.registration + +/** + * Kotlin transcription of the ClearADI OTP path (OpenBubbles' white-box CoreADI + * reimplementation, librust_lib_bluebubbles). Address citations refer to that .so. + * Quirks of the white-box network (dead constants, lane drops, non-standard schedule + * arithmetic) are reproduced exactly — they are load-bearing, see analysis/otp-path.md. + */ +internal object ClearAdiOtp { + + // ---- helpers ------------------------------------------------------------- + + private fun u8(b: ByteArray, i: Int): Int = b[i].toInt() and 0xff + + private fun u32le(b: ByteArray, i: Int): Int = + (b[i].toInt() and 0xff) or + ((b[i + 1].toInt() and 0xff) shl 8) or + ((b[i + 2].toInt() and 0xff) shl 16) or + ((b[i + 3].toInt() and 0xff) shl 24) + + private fun putU32le(b: ByteArray, i: Int, v: Int) { + b[i] = v.toByte() + b[i + 1] = (v ushr 8).toByte() + b[i + 2] = (v ushr 16).toByte() + b[i + 3] = (v ushr 24).toByte() + } + + private fun rotr(x: Int, n: Int): Int = (x ushr n) or (x shl (32 - n)) + private fun rotl(x: Int, n: Int): Int = (x shl n) or (x ushr (32 - n)) + + /** one byte of a word, position 0 = LSB. */ + private fun byteOf(x: Int, n: Int): Int = (x ushr (8 * n)) and 0xff + + /** XOR of four u32 T-table lookups, one per byte position (tables b0..b3). */ + private fun mix4(x: Int, t0: IntArray, t1: IntArray, t2: IntArray, t3: IntArray): Int = + t0[byteOf(x, 0)] xor t1[byteOf(x, 1)] xor t2[byteOf(x, 2)] xor t3[byteOf(x, 3)] + + // ---- gentable (0x17f98d0) ------------------------------------------------ + + /** gentable: fills ctx[0x130..0x2b0] (384 B) from `one` (client info, 0x190 B). */ + internal fun genTable(ctx: ByteArray, one: ByteArray) { + val t = ClearAdiTables + // per-chunk byte-S-box tables (gentable @0x17f99bb-0x17f99d0) + val sA = t.byteTable(0x2551c0) + val sB = t.byteTable(0x254ec0) + val sC = t.byteTable(0x2550c0) + val sD = t.byteTable(0x254fc0) + // 9-round Feistel tables (0x17f9bee: slot b0/b3/b1/b2) + val g0 = t.wordTable(0x254ac0) + val g3 = t.wordTable(0x253ec0) + val g1 = t.wordTable(0x2546c0) + val g2 = t.wordTable(0x2542c0) + // 10th (final) round tables 0x17f9cd9-0x17f9d49: slot0/3/1/2 + val f0 = t.wordTable(0x2532c0) + val f3 = t.wordTable(0x253ac0) + val f1 = t.wordTable(0x2536c0) + val f2 = t.wordTable(0x252ec0) + // byte-serial u64 builder tables (0x17f9f05-0x17f9f30) + val bA = t.byteTable(0x252ac0) + val bB = t.byteTable(0x252bc0) + val bC = t.byteTable(0x252cc0) + val bD = t.byteTable(0x252dc0) + // 9 round constants, stack order rsp+0x80..0x100 (0x17f9b33-0x17f9bcb) + val rc = arrayOf( + 0x1a1bc0, 0x1a2200, 0x1a29d0, 0x1a29e0, 0x1a4a70, + 0x1a1f20, 0x1a4190, 0x1a2ec0, 0x1a5af0 + ).map { t.consts16(it) } + val cFinal = t.consts16(0x1a5d80) // pxor after the 10th round (0x17f9e31) + val cOut = t.consts16(0x1a3170) // pxor of each 16-byte output chunk (0x17fa056) + // 0xC00 qword-index blob copied from .rodata 0x24dcc0 (0x17fa094) + val blob = ClearAdiTables.blob() + + val buf = ByteArray(0x190) + // per-chunk 10th-round dword constants: chunk 0 uses the prologue values + // (17f9971-17f99a8); the loop tail re-derives them from the finished chunk's + // raw lanes (17f9fe9-17fa02c, 17fa04d-17fa075) + var cV0 = 0x303d36a2 + var cV1 = 0xeee34595.toInt() + var cV2 = 0x94edc694.toInt() + var cV3 = 0x93de8db0.toInt() + for (chunk in 0 until 25) { + val o = chunk * 16 + // byte-S-box lanes, 17f99c8-17f9bc7: (bA<<24 ^ bC<<16 ^ bD<<8 ^ bB) per 4 bytes + val l1 = ((sA[u8(one, o).toInt() xor 0xfc].toInt() and 0xff) shl 24) xor + ((sC[u8(one, o + 1).toInt() xor 0x30].toInt() and 0xff) shl 16) xor + ((sD[u8(one, o + 2).toInt() xor 0x19].toInt() and 0xff) shl 8) xor + (sB[u8(one, o + 3).toInt() xor 0x9f].toInt() and 0xff) + val l2 = ((sA[u8(one, o + 4).toInt() xor 0xd4].toInt() and 0xff) shl 24) xor + ((sC[u8(one, o + 5).toInt() xor 0x10].toInt() and 0xff) shl 16) xor + ((sD[u8(one, o + 6).toInt() xor 0xd].toInt() and 0xff) shl 8) xor + (sB[u8(one, o + 7).toInt() xor 0x3a].toInt() and 0xff) + val l3 = ((sA[u8(one, o + 8).toInt() xor 0x48].toInt() and 0xff) shl 24) xor + ((sC[u8(one, o + 9).toInt() xor 0x30].toInt() and 0xff) shl 16) xor + ((sD[u8(one, o + 10).toInt() xor 0x89].toInt() and 0xff) shl 8) xor + (sB[u8(one, o + 11).toInt() xor 0x6b].toInt() and 0xff) + val l4 = ((sA[u8(one, o + 12).toInt() xor 0x12].toInt() and 0xff) shl 24) xor + ((sC[u8(one, o + 13).toInt() xor 0xc5].toInt() and 0xff) shl 16) xor + ((sD[u8(one, o + 14).toInt() xor 0x6d].toInt() and 0xff) shl 8) xor + (sB[u8(one, o + 15).toInt() xor 0x89].toInt() and 0xff) + // The .so's round-1 setup loads eax=d, ebx=a, edi=b, r9d=c (17f9b41-17f9bb7) + // while the loop-back extraction (17f9bd0-17f9bea) keeps the plain state — + // so round 1's Feistel input is the state rotated by one lane. + var a = l4 xor 0x5fdff073.toInt() // 17f9bbe + var b = l1 xor 0x948c2d71.toInt() // 17f9b1a + var c = l2 xor 0x5f1a4c6e.toInt() // 17f9b67 + var d = l3 xor 0xb026a63d.toInt() // 17f9bb7 + // 9 uniform Feistel rounds + per-round 16-byte constant (17f9bee-17f9cd3) + for (r in 0 until 9) { + val n0 = g0[byteOf(a, 0)] xor g3[byteOf(d, 3)] xor g1[byteOf(b, 1)] xor g2[byteOf(c, 2)] + val n1 = g0[byteOf(b, 0)] xor g3[byteOf(a, 3)] xor g1[byteOf(c, 1)] xor g2[byteOf(d, 2)] + val n2 = g0[byteOf(c, 0)] xor g3[byteOf(b, 3)] xor g1[byteOf(d, 1)] xor g2[byteOf(a, 2)] + val n3 = g0[byteOf(d, 0)] xor g3[byteOf(c, 3)] xor g1[byteOf(a, 1)] xor g2[byteOf(b, 2)] + val k = rc[r] + a = n0 xor u32le(k, 0) + b = n1 xor u32le(k, 4) + c = n2 xor u32le(k, 8) + d = n3 xor u32le(k, 12) + } + // 10th round, uniform lane rotation (17f9cd9-17f9e31): output i combines + // f0[s_i,0] ^ f1[s_{i+1},1] ^ f3[s_{i+2},2] ^ f2[s_{i+3},3] ^ dword-constant + val v0 = f0[byteOf(a, 0)] xor f1[byteOf(b, 1)] xor f2[byteOf(c, 2)] xor + f3[byteOf(d, 3)] xor cV0 + val v1 = f0[byteOf(b, 0)] xor f1[byteOf(c, 1)] xor f2[byteOf(d, 2)] xor + f3[byteOf(a, 3)] xor cV1 + val v2 = f0[byteOf(c, 0)] xor f1[byteOf(d, 1)] xor f2[byteOf(a, 2)] xor + f3[byteOf(b, 3)] xor cV2 + val v3 = f0[byteOf(d, 0)] xor f1[byteOf(a, 1)] xor f2[byteOf(b, 2)] xor + f3[byteOf(c, 3)] xor cV3 + val k = cFinal + val u0 = v0 xor u32le(k, 0) + val u1 = v1 xor u32le(k, 4) + val u2 = v2 xor u32le(k, 8) + val u3 = v3 xor u32le(k, 12) + // byte-serial u64s, chain order (u0,u3) then (u2,u1) (17f9f0c-17fa041) + val c1 = intArrayOf( + bA[byteOf(u0, 0)].toInt(), bB[byteOf(u0, 1)].toInt(), bC[byteOf(u0, 2)].toInt(), bD[byteOf(u0, 3)].toInt(), + bA[byteOf(u3, 0)].toInt(), bB[byteOf(u3, 1)].toInt(), bC[byteOf(u3, 2)].toInt(), bD[byteOf(u3, 3)].toInt() + ) + val c2 = intArrayOf( + bA[byteOf(u2, 0)].toInt(), bB[byteOf(u2, 1)].toInt(), bC[byteOf(u2, 2)].toInt(), bD[byteOf(u2, 3)].toInt(), + bA[byteOf(u1, 0)].toInt(), bB[byteOf(u1, 1)].toInt(), bC[byteOf(u1, 2)].toInt(), bD[byteOf(u1, 3)].toInt() + ) + // stored as two little-endian u64s (movq at 17fa046/17fa05b) then ^ cOut + for (i in 0 until 8) { + buf[o + i] = (c1[7 - i] xor u8(cOut, i)).toByte() + buf[o + 8 + i] = (c2[7 - i] xor u8(cOut, 8 + i)).toByte() + } + // carry: next chunk's constants from this chunk's raw lanes + // (17f9fe9-17fa00a: l3^0x8af594de -> out2 slot; 17fa015/25: l1^0x60a97028 -> + // out4 slot; 17fa01a/2c: l4^0x19bfc026 -> out3 slot; 17fa04d/05f: + // l2^0x8baea5ec -> out1 slot) + cV0 = l2 xor 0x8baea5ec.toInt() + cV1 = l3 xor 0x8af594de.toInt() + cV2 = l4 xor 0x19bfc026 + cV3 = l1 xor 0x60a97028 + } + // byte-mixing loop over the blob + buf (17fa08a-17fa134) + var acc = (u8(buf, 0x122) + u8(buf, 0x13f) + u8(buf, 0x0e) + u8(buf, 0x124)) and 0xff + for (i in 0 until 0x180) { + val idx = u32le(blob, 8 * i) // blob qwords are small indices + val v = u8(buf, idx) + val m = acc and 7 + if ((acc and 6) == 2) { + // m in {2,3}: ctx = (acc ^ v) & 0xff, acc' = v + 0x12 (17fa109-17fa122) + ctx[0x130 + i] = ((acc xor v) and 0xff).toByte() + acc = v + 0x12 + } else { + // m in {0,1,4..7}: ctx = bb & 0xff, acc' = (acc ^ bb) + 0x12 + // (17fa0c0-17fa0d9; `add bl,buf[idx]` wraps within byte 0) + val bb = when (m) { + 0 -> v - acc + 1 -> (acc and 0xffffff00.toInt()) or ((acc + v) and 0xff) + else -> v + } + ctx[0x130 + i] = (bb and 0xff).toByte() + acc = (acc xor bb) + 0x12 + } + } + } + + // ---- schedule expansion shared by the gensource hash stages (SIMD-recovered) -- + + /** + * The white-box SHA-256-flavored message schedule: for i in 16..63, + * W[i] = W[i-16] + (rotr(W[i-2],19)^rotr(W[i-2],17)) ^ (W[i-7] ^ (W[i-2]>>>10)) + * ^ ((rotr(W[i-15],7)^rotr(W[i-15],18)) - (W[i-15]>>>3)) + * (sigma1 lacks its >>>10 term — it is XORed into the W[i-7] slot instead; sigma0's + * >>>3 term is subtracted, not XORed — 0x17fa449/0x17fa4dd.) + */ + private fun expandSchedule(w: IntArray) { + for (i in 16 until 64) { + val c = w[i - 2] + val s1 = rotr(c, 19) xor rotr(c, 17) + val t = w[i - 7] xor (c ushr 10) + val v = w[i - 15] + val s0 = (rotr(v, 7) xor rotr(v, 18)) - (v ushr 3) + w[i] = w[i - 16] + (s1 xor t xor s0) + } + } + + // ---- the 64-round ARX permutation of gensource (0x17fa54c, 0x17fad5d, 0x17fb8d1) -- + + internal class ArxResult( + val out1: Int, + val out2: Int, + val s1: Int, + val s2: Int, + val s3: Int, + val s4: Int, + val s5: Int, + val s6: Int, + ) + + /** Initial ARX state [s0..s6, d] — the constants at 17fad31-17fad58. */ + private val ARX_STD_INIT = intArrayOf( + 0x16a4e72b, 0x42b9ab8c.toInt(), 0x95a2bd45.toInt(), 0xcc9f011e.toInt(), + 0x460b9fe5.toInt(), 0x0364e21c, 0x5e7aa279, 0x499b3b76, + ) + + private fun arx(w: IntArray, mixTable: IntArray, init: IntArray = ARX_STD_INIT): ArxResult { + var s0 = init[0] + var s1 = init[1] + var s2 = init[2] + var s3 = init[3] + var s4 = init[4] + var s5 = init[5] + var s6 = init[6] + var d = init[7] + var out1 = 0 + var out2 = 0 + for (i in 0 until 64) { + // 17fa55f-17fa5d3 + val x = s3 + val t = rotr(x, 13) xor rotr(x, 2) xor rotl(x, 10) + val m2 = (((((s2 xor s1) and s3) xor s2) - s1)) * 2 + val o1 = m2 xor t + val e = rotl(s6, 7) + rotr(s6, 6) - rotr(s6, 11) + val o2 = (w[i] - s6) + 2 * s4 + 0x6f5d3d27 - mixTable[i] + (s6 xor s5) - (d xor e) + out1 = o1 + o2 + out2 = o2 + s0 + if (i == 63) break + val ns0 = s1; val ns1 = s2; val ns2 = s3; val ns3 = out1 + val ns4 = s5; val ns5 = s6; val ns6 = out2; val nd = s4 + s0 = ns0; s1 = ns1; s2 = ns2; s3 = ns3; s4 = ns4; s5 = ns5; s6 = ns6; d = nd + } + return ArxResult(out1, out2, s1, s2, s3, s4, s5, s6) + } + + // ---- gensource (0x17fa240) ------------------------------------------------- + + /** 8 shift-amount bytes at .rodata 0x1a7948 (read through rsp+0x58). */ + private val SHIFT_BYTES = byteArrayOf(0x10, 0x00, 0x08, 0x18, 0x10, 0x10, 0x08, 0x08) + + /** gensource: fills ctx[0x2c0..0x320] (24 round-constant dwords) from `two` and `gen`. */ + internal fun genSource(ctx: ByteArray, two: ByteArray, gen: UInt) { + val t = ClearAdiTables + val c44 = t.consts16(0x1a3180) + val c4730 = t.consts16(0x1a4730) + val c1f30 = t.consts16(0x1a1f30) + val mt = t.wordTable(0x24e8c0, 64) + + // ---- stage 1: buffer A from `two`, hash expansion, ARX (17fa2d3-17fa5dd) ---- + val src = ByteArray(64) + for (i in 0 until 32) src[i] = (two[i].toInt() xor c44[i and 15].toInt()).toByte() + c4730.copyInto(src, 32) + c1f30.copyInto(src, 48) + val a = IntArray(64) + for (j in 0 until 16) a[j] = Integer.reverseBytes(u32le(src, 4 * j)) xor 0x77777777 + expandSchedule(a) + val r1 = arx(a, mt) + + // ctx[0x2c0..0x2e0] (17fa5e3-17fa6ac) + val p = 0xcc9f011e.toInt() - r1.out1 + val q = r1.s3 + val r = 0x42b9ab8c.toInt() - r1.s2 + val s = r1.s1 + val tv = 0xa1855d85.toInt() - r1.out2 + val u = r1.s6 + val v = 0x460b9fe5.toInt() - r1.s5 + val w = 0x499b3b76 - r1.s4 + putCtxXor(ctx, 0x2c0, intArrayOf(p, q, r, s), 0x1a1bd0) + putCtxXor(ctx, 0x2d0, intArrayOf(tv, u, v, w), 0x1a2ed0) + + // ---- 15 constant blocks + 8-byte tail over rsp+0x168..0x260 (17fa5e3-17fa955) + val c43f0 = t.consts16(0x1a43f0) + val c0980 = t.consts16(0x1a0980) + val c5b00 = t.consts16(0x1a5b00) + val c0bb0 = t.consts16(0x1a0bb0) + val c2ed0 = t.consts16(0x1a2ed0) + val c3e40 = t.consts16(0x1a3e40) + val c1f40 = t.consts16(0x1a1f40) + val c3c40 = t.consts16(0x1a3c40) + val c2480 = t.consts16(0x1a2480) + val c3750 = t.consts16(0x1a3750) + val c13b0 = t.consts16(0x1a13b0) + val c3e50 = t.consts16(0x1a3e50) + val c13c0 = t.consts16(0x1a13c0) + val c2740 = t.consts16(0x1a2740) + val c0bc0 = t.consts16(0x1a0bc0) + // dword index space D[] starts at rsp+0x160; D[0..1] unwritten, D[2..] = blocks + val dReg = IntArray(64) + putXor4(dReg, 2, intArrayOf(s, s, w, tv), c43f0) // rsp+0x168 + putXor4(dReg, 6, intArrayOf(u, u, v, v), c0980) // rsp+0x178 + putXor4(dReg, 10, intArrayOf(q, p, w, q), c5b00) // rsp+0x188 + putXor4(dReg, 14, intArrayOf(w, r, r, s), c0bb0) // rsp+0x198 + putXor4(dReg, 18, intArrayOf(w, u, w, v), c2ed0) // rsp+0x1a8 + putXor4(dReg, 22, intArrayOf(q, w, v, p), c3e40) // rsp+0x1b8 + putXor4(dReg, 26, intArrayOf(u, r, w, s), c1f40) // rsp+0x1c8 + putXor4(dReg, 30, intArrayOf(s, tv, r, u), c3c40) // rsp+0x1d8 + putXor4(dReg, 34, intArrayOf(s, w, w, p), c2480) // rsp+0x1e8 + putXor4(dReg, 38, intArrayOf(u, q, v, r), c3750) // rsp+0x1f8 + putXor4(dReg, 42, intArrayOf(q, tv, w, u), c13b0) // rsp+0x208 + putXor4(dReg, 46, intArrayOf(w, v, r, w), c3e50) // rsp+0x218 + putXor4(dReg, 50, intArrayOf(w, q, w, r), c13c0) // rsp+0x228 + putXor4(dReg, 54, intArrayOf(q, s, v, tv), c2740) // rsp+0x238 + putXor4(dReg, 58, intArrayOf(u, v, w, w), c0bc0) // rsp+0x248 + dReg[62] = s xor 0x22585f05 // rsp+0x258 (17fa8f8/17fa815) + dReg[63] = p xor 0x34fcb82e.toInt() // rsp+0x25c (17fa906/17fa8f2) + + // ---- buf32 (rsp+0x560..0x580), 17fa94e-17faac8 ---- + val buf32 = ByteArray(32) + // buf32[0] (17fa894-17fa966) + buf32[0] = ((((r ushr 16) + 0x2a) xor (q xor u32le(c5b00, 0))) xor 0x59).toByte() + // buf32[1] (17fa748-17fa973); rsp+0x16f = byte 7 of block168 + val sC0 = s xor u32le(c43f0, 0) + val sC1 = s xor u32le(c43f0, 4) + buf32[1] = ((((sC0 xor 0x34fcb82e.toInt()) ushr 8) + 0x2a) xor (sC1 ushr 24) xor 0x43).toByte() + for (j in 2 until 32) { + val sh = 2 * (j and 3) + val hi = dReg[2 * j] xor 0x34fcb82e.toInt() + val lo = dReg[2 * j + 1] xor 0x34fcb82e.toInt() + buf32[j] = (((hi ushr (SHIFT_BYTES[sh].toInt() and 31)) + 0x2a) xor + (lo ushr (SHIFT_BYTES[sh + 1].toInt() and 31)) xor 0x77).toByte() + } + + // ---- stage 2: buffer B = buf32 duplicated (64 B), hash, ARX (17faace-17faded) ---- + val bufB = ByteArray(64) + buf32.copyInto(bufB, 0) + buf32.copyInto(bufB, 32) + val b = IntArray(64) + for (j in 0 until 16) b[j] = Integer.reverseBytes(u32le(bufB, 4 * j)) xor 0x77777777 + expandSchedule(b) + val r2 = arx(b, mt) + // scalar slots saved for the gen section: n1/n2c/n2 XOR partners + // (17faed9-17faeee store [rsp+0x30/0x34/0x38] from xmm15/xmm12 = stage-1 + // state lanes ^ C1a1bd0 / C1a2ed0, kept live from 17fa614/17fa672) + val c1a1bd0 = t.consts16(0x1a1bd0) + val c1a2ed0 = t.consts16(0x1a2ed0) + val slot30 = r2.s3 xor u32le(c1a1bd0, 4) // xmm15[1] = s3 ^ C1a1bd0[1] + val slot34 = r2.s1 xor u32le(c1a1bd0, 12) // xmm15[3] = s1 ^ C1a1bd0[3] + val slot38 = r2.s6 xor u32le(c1a2ed0, 4) // xmm12[1] = s6 ^ C1a2ed0[1] + val s42 = r2.s4 + val s52 = r2.s5 + + // ---- stage 3: ARX over the padding-block schedule (17faecb-17fb22f) ---- + // buffer C at rsp+0x360: word0 = C1a3c50[0..3] raw; words 1..15 = C1a3c50[4..], + // C1a4740, C1a4740, C1a5d90 through the bswap^0x77777777 loop (17faf10-17fafa7); + // words 16..63 expanded (17fafc0-17fb127). Its init state comes from the stage-2 + // lanes packed at 17fae37-17fae93, ^ C4cc0/C34a0 (17fb12d/17fb136) — verified + // against live registers (ebp/r11d/ebx/r8d/r12d/r13d/edi/edx at 17fb1b1). + val c1a3c50 = t.consts16(0x1a3c50) + val c1a4740 = t.consts16(0x1a4740) + val c1a5d90 = t.consts16(0x1a5d90) + val cbuf = ByteArray(0x100) + c1a3c50.copyInto(cbuf, 0) + c1a4740.copyInto(cbuf, 0x10) + c1a4740.copyInto(cbuf, 0x20) + c1a5d90.copyInto(cbuf, 0x30) + val c = IntArray(64) + c[0] = u32le(cbuf, 0) // byte 0x360-0x364 sits before the bswap loop's reach + for (j in 1 until 16) c[j] = Integer.reverseBytes(u32le(cbuf, 4 * j)) xor 0x77777777 + expandSchedule(c) + val c4cc0 = t.consts16(0x1a4cc0) + val c34a0 = t.consts16(0x1a34a0) + val st3Init = intArrayOf( + r2.s1 xor u32le(c4cc0, 12), // s0 = ebp + (0x42b9ab8c.toInt() - r2.s2) xor u32le(c4cc0, 8), // s1 = r11d + r2.s3 xor u32le(c4cc0, 4), // s2 = ebx + (0xcc9f011e.toInt() - r2.out1) xor u32le(c4cc0, 0), // s3 = r8d + (0x460b9fe5.toInt() - r2.s5) xor u32le(c34a0, 8), // s4 = r12d + r2.s6 xor u32le(c34a0, 4), // s5 = r13d + (0xa1855d85.toInt() - r2.out2) xor u32le(c34a0, 0), // s6 = edi + (0x499b3b76 - r2.s4) xor u32le(c34a0, 12), // d = edx + ) + val r4 = arx(c, mt, st3Init) + + // ---- gen section (17fb235-17fb666) ---- + val g = gen.toInt() + val n1 = (r4.s3 xor slot30).inv() + val n2c = (r4.s1 xor slot34).inv() + val n2 = (r4.s6 xor slot38).inv() + val rq = ((r2.s2 - 0x42b9ab8d) - r4.s2) xor 0x34fcb82e.toInt() + val gq = ((s52 - 0x460b9fe6) - r4.s5) xor 0x34fcb82e.toInt() + val hq = ((s42 - 0x499b3b77) - r4.s4) xor 0x34fcb82e.toInt() + val e1 = ((r2.out1 + 0x3360fee1) - r4.out1) xor 0x34fcb82e.toInt() + // 17fb28f-17fb2cc: 0xa1855d84 - r2.out2 - r4.out2, ^ 0x34fcb82e + val e2v = ((0xa1855d84.toInt() - r2.out2) - r4.out2) xor 0x34fcb82e.toInt() + putCtxXor(ctx, 0x2e0, intArrayOf(e1, n1, rq, n2c), null) + putCtxXor(ctx, 0x2f0, intArrayOf(e2v, n2, gq, hq), null) + + // gen math + shuffle-region seed bytes (17fb2aa-17fb483) + val h1v = (g.toLong() * 0x12e0a56bL) ushr 32 + val t1 = ((g - h1v.toInt()).toLong() and 0xffffffffL) + val r14v = (t1 ushr 1) + h1v + val r14w2 = ((r14v ushr 29) and 0xffff).toInt() + val h3v = (g.toLong() * 0x1b39aeb3L) ushr 60 + val dx16 = (h3v and 0xffff).toInt() + val h4v = (g.toLong() * 0x7b85ee89L) ushr 57 + val cx16 = (h4v and 0xffff).toInt() + val r13w = ((g.toLong() * 0x9c715473L) ushr 61 and 0xffff).toInt() + + var ebpV = (r4.s1 and 0xffff0000.toInt()) or ((r14w2 * 0x308f) and 0xffff) + ebpV += g + ebpV = (ebpV and 0xffff0000.toInt()) or ((ebpV and 0xffff) xor 0x7777) + val ebpB0 = ebpV and 0xff + val ebpB1 = (ebpV ushr 8) and 0xff + + var esiV = (e1 and 0xffff0000.toInt()) or ((cx16 * 0xe329) and 0xffff) + esiV += g + esiV = (esiV and 0xffff0000.toInt()) or ((esiV and 0xffff) xor 0x7777) + val rdxByte = esiV and 0xff + val rcxByte = (esiV ushr 8) and 0xff + + // r15 seed: (hq high ‖ dx16*0x4467) + g, low word ^ 0x7777 (17fb321/17fb364/17fb378) + var r15dV = (hq and 0xffff0000.toInt()) or ((dx16 * 0x4467) and 0xffff) + r15dV += g + r15dV = (r15dV and 0xffff0000.toInt()) or ((r15dV and 0xffff) xor 0x7777) + val r15Byte = r15dV and 0xff + val rsiByte = (r15dV ushr 8) and 0xff + + val mVal = (r13w * 0xc259) and 0xffff + var r11dV = (e2v and 0xffff0000.toInt()) or mVal + r11dV += g // 17fb412: ebx was reloaded with g at 17fb2e1 (mov rbx,r13) + r11dV = (r11dV and 0xffff0000.toInt()) or ((r11dV and 0xffff) xor 0x7777) + val r14Byte = ((r11dV and 0xffff) ushr 8) and 0xff + val two1 = u8(two, 1) + val ebx32 = (((two1 xor 0x33) - 0x6d) xor r11dV) + val eaxByte = ebx32 and 0xff + val chain0 = (((ebx32 xor 0x77) * 0x44) xor 0xffffff98.toInt()) + + // 64-byte shuffle region rsp+0x580..0x5c0 (17fb47b-17fb5c0 + blocks) + val shuf = ByteArray(64) + // rax qword (17fb433-17fb47b): rax = eaxByte, then 7× (shl 8 | reg) — the last + // or'ed reg lands in byte 0, so memory order = [r9, rbp, rsi, r15, rcx, rdx, r14, eax] + shuf[0] = ebpB1.toByte(); shuf[1] = ebpB0.toByte() + shuf[2] = rsiByte.toByte(); shuf[3] = r15Byte.toByte() + shuf[4] = rcxByte.toByte(); shuf[5] = rdxByte.toByte() + shuf[6] = r14Byte.toByte(); shuf[7] = eaxByte.toByte() + val c4740 = t.consts16(0x1a4740) + c4740.copyInto(shuf, 8) + c4740.copyInto(shuf, 24) + c4740.copyInto(shuf, 40) + shuf[55] = 0xf7.toByte() // 17fb3b3 + for (i in 56 until 62) shuf[i] = 0x77.toByte() // 17fb245-17fb25c + shuf[62] = 0x76; shuf[63] = 0xcf.toByte() // word 0xcf76 LE (17fb358/17fb389) + // byte shuffle loop, 19 iterations of 5 (17fb490-17fb660; cmp r13d,0x67 ends at n=103); + // pos = n - 55*q(n) + var chain = chain0 + for (k in 0 until 19) { + val base = 8 + 5 * k + val ti = 3 + 10 * k + for (mm in 0 until 5) { + val n = base + mm + val qn = ((n.toLong() * 156180629L) ushr 33).toInt() // magic 0x94f2095, >>33 + val pos = n - 55 * qn + val twoByte = u8(two, (ti + 2 * mm) and 0x1f) + val v = (twoByte xor 0x33) + (chain xor 0xb) + val newByte = (v and 0xff) xor u8(shuf, pos) + shuf[pos] = newByte.toByte() + // chain update uses v with its low byte already replaced by the new + // shuf byte (asm xor sil,[shuf] happens before xor esi,0x77) + chain = chain xor ((((v and 0xffffff00.toInt()) or newByte) xor 0x77) * 0x44) + } + } + + // ---- stage 4: buffer D = shuffled64, hash, ARX (17fb666-17fb99a) ---- + val dd = IntArray(64) + for (j in 0 until 16) dd[j] = Integer.reverseBytes(u32le(shuf, 4 * j)) xor 0x77777777 + expandSchedule(dd) + val r3 = arx(dd, mt) + putCtxXor(ctx, 0x300, intArrayOf( + 0xcc9f011e.toInt() - r3.out1, r3.s3, 0x42b9ab8c.toInt() - r3.s2, r3.s1), 0x1a1bd0) + putCtxXor(ctx, 0x310, intArrayOf( + 0xa1855d85.toInt() - r3.out2, r3.s6, 0x460b9fe5.toInt() - r3.s5, 0x499b3b76 - r3.s4), 0x1a2ed0) + } + + private fun putCtxXor(ctx: ByteArray, off: Int, values: IntArray, constVaddr: Int?) { + val c = constVaddr?.let { ClearAdiTables.consts16(it) } + for (i in 0 until 4) { + val x = if (c != null) values[i] xor u32le(c, 4 * i) else values[i] + putU32le(ctx, off + 4 * i, x) + } + } + + private fun putXor4(target: IntArray, at: Int, values: IntArray, const16: ByteArray) { + for (i in 0 until 4) target[at + i] = values[i] xor u32le(const16, 4 * i) + } // ---- gen_otp (0x17fba60) --------------------------------------------------- + + /** gen_otp: IOS-flavor ADI cipher; 16-byte output. `one` = 0x190 client-info bytes. */ + internal fun genOtp(gen: UInt, one: ByteArray, two: ByteArray): ByteArray { + val t = ClearAdiTables + val ctx = ByteArray(0x320) + genSource(ctx, two, gen) + genTable(ctx, one) + + // A: ctx[0x70+4m] = bswap(ctx[0x210+4m] ^ ctx[0x160+4m]) (17fbac4-17fbb7b) + for (m in 0 until 40) { + putU32le(ctx, 0x70 + 4 * m, + Integer.reverseBytes(u32le(ctx, 0x210 + 4 * m) xor u32le(ctx, 0x160 + 4 * m))) + } + + // B: h[i] = bswap(ctx[0x130+4i]); ctx[0x120..0x130] = [h4..h7] (17fbb81-17fbc89) + val h = IntArray(8) { Integer.reverseBytes(u32le(ctx, 0x130 + 4 * it)) } + for (i in 0 until 4) putU32le(ctx, 0x120 + 4 * i, h[4 + i]) + // (ctx[0x110..0x120] = [h3,h1,h2,h0] is written by the binary but never read) + + // C: key schedule (17fbd39-17fbd6e) + val hi0 = t.wordTable(0x251ac0); val hi1 = t.wordTable(0x251ec0) + val hi2 = t.wordTable(0x2522c0); val hi3 = t.wordTable(0x2526c0) + val lo0 = t.wordTable(0x250ac0); val lo1 = t.wordTable(0x250ec0) + val lo2 = t.wordTable(0x2512c0); val lo3 = t.wordTable(0x2516c0) + val rcA = t.consts16(0x1a41a0) // RC[0..3] + val rcB = t.consts16(0x1a2750) // RC[4..23] (repeated) + for (i in 0 until 24) { + var x = u32le(ctx, 0x2c0 + 4 * i) + if (i < 4) x = x xor u32le(ctx, 0x120 + 4 * i) + val hiMix = hi0[byteOf(x, 3)] xor hi1[byteOf(x, 0)] xor + hi2[byteOf(x, 2)] xor hi3[byteOf(x, 1)] + val loMix = lo0[byteOf(hiMix, 0)] xor lo1[byteOf(hiMix, 1)] xor + lo2[byteOf(hiMix, 2)] xor lo3[byteOf(hiMix, 3)] + var k = loMix xor (if (i < 4) u32le(rcA, 4 * i) else u32le(rcB, 4 * (i and 3))) + if (i < 4) k = k xor u32le(ctx, 0x70 + 4 * i) xor 0xd247337c.toInt() + putU32le(ctx, 0x10 + 4 * i, k) + } + + // tail blocks: iteration t uses ctx[0x80+0x10t..] ^ C (pshufd-reversed) (17fbd70-17fbeef) + val tailConst = intArrayOf( + 0x1a4cd0, 0x1a2770, 0x1a3190, 0x1a1f50, 0x1a2490, + 0x1a2210, 0x1a3e60, 0x1a29f0, 0x1a2760 + ) + val tail = Array(9) { tt -> + val src = IntArray(4) { u32le(ctx, 0x80 + 0x10 * tt + 4 * it) } + val c = t.consts16(tailConst[tt]) + // pshufd 0x1b reverses dwords; usage: n0^dst[3], n1^dst[2], n2^dst[1], n3^dst[0] + intArrayOf(src[0] xor u32le(c, 12), src[1] xor u32le(c, 8), + src[2] xor u32le(c, 4), src[3] xor u32le(c, 0)) + } + + // sieve chunks: iteration t reads the 16 bytes at consts below (17fbe85-17fbf27; + // stack order rsp+0xf0.. — note 0x1a24a0 (xmm3) lands BEFORE 0x1a3760 (xmm4)) + val sieveConst = intArrayOf( + 0x1a3e70, 0x1a24a0, 0x1a3760, 0x1a3a20, 0x1a4400, + 0x1a1990, 0x1a16d0, 0x1a5010, 0x1a0990 + ) + val sieve = Array(9) { t.consts16(sieveConst[it]) } + + val tF5 = t.wordTable(0x24f5c0) + val tF1 = t.wordTable(0x24f1c0) + val tED = t.wordTable(0x24edc0) + val tE9 = t.wordTable(0x24e9c0) + + // stage-2 S-box tables (0x24fac0/0x24fec0/0x2502c0/0x2506c0, b3/b0/b1/b2) and the + // w-block dword outputs, computed inside every round (17fc0d9-17fc311) + val tFa = t.wordTable(0x24fac0) + val tFe = t.wordTable(0x24fec0) + val t02 = t.wordTable(0x2502c0) + val t06 = t.wordTable(0x2506c0) + fun stage2(x: Int): Int = tFa[byteOf(x, 3)] xor tFe[byteOf(x, 0)] xor + t02[byteOf(x, 1)] xor t06[byteOf(x, 2)] + var dwordA = 0; var dwordB = 0; var dwordC = 0; var dwordD = 0 + + var s0 = 0x25e22f28 + var s1 = 0x58cff744 + var s2 = 0x36ac60aa + var s3 = 0x2906000b + var n0 = 0; var n1 = 0; var n2 = 0; var n3 = 0 + for (round in 0 until 6) { + // key dwords K[4r..4r+3] (17fbf4f-17fbf62) + s0 = s0 xor u32le(ctx, 0x10 + 0x10 * round) + s3 = s3 xor u32le(ctx, 0x14 + 0x10 * round) + s1 = s1 xor u32le(ctx, 0x18 + 0x10 * round) + s2 = s2 xor u32le(ctx, 0x1c + 0x10 * round) + for (tt in 0 until 9) { + val sv = sieve[tt] + val tl = tail[tt] + n0 = tF5[byteOf(s3, 2) xor u8(sv, 0)] xor tF1[byteOf(s1, 1) xor u8(sv, 1)] xor + tl[0] xor tED[byteOf(s2, 0) xor u8(sv, 2)] xor tE9[byteOf(s0, 3) xor u8(sv, 3)] + n1 = tF5[byteOf(s1, 2) xor u8(sv, 4)] xor tF1[byteOf(s2, 1) xor u8(sv, 5)] xor + tl[1] xor tED[byteOf(s0, 0) xor u8(sv, 6)] xor tE9[byteOf(s3, 3) xor u8(sv, 7)] + n2 = tF5[byteOf(s2, 2) xor u8(sv, 8)] xor tF1[byteOf(s0, 1) xor u8(sv, 9)] xor + tl[2] xor tED[byteOf(s3, 0) xor u8(sv, 10)] xor tE9[byteOf(s1, 3) xor u8(sv, 11)] + n3 = tF5[byteOf(s0, 2) xor u8(sv, 12)] xor tF1[byteOf(s3, 1) xor u8(sv, 13)] xor + tl[3] xor tED[byteOf(s1, 0) xor u8(sv, 14)] xor tE9[byteOf(s2, 3) xor u8(sv, 15)] + // state rotation quirk (s0,s1,s2,s3) <- (n0, n2, n3, n1) (17fbfa0-17fc0d3) + s0 = n0; s1 = n2; s2 = n3; s3 = n1 + } + + // w-block (17fc0d9-17fc311): runs after EVERY round. Only the last round's + // dwords reach the output bytes — the earlier rounds' results are dead + // except for the register carry back into the next round's state + // (esi/edx/ebx/ecx at 17fc311, XORed with the round key at 17fbf4f). + val w0 = tED[byteOf(n3, 0) xor 0x8f] xor tE9[byteOf(n0, 3) xor 0x10] xor + tF5[byteOf(n1, 2) xor 0x66] xor tF1[byteOf(n2, 1) xor 0x46] xor 0x397d8245 + val w1 = tED[byteOf(n0, 0) xor 0xb0] xor tE9[byteOf(n1, 3) xor 0x68] xor + tF5[byteOf(n2, 2) xor 0xcb] xor tF1[byteOf(n3, 1) xor 0x5e] xor 0x18f62871 + val w2 = tED[byteOf(n1, 0) xor 0x9b] xor tE9[byteOf(n2, 3) xor 0xc7] xor + tF5[byteOf(n3, 2) xor 0x29] xor tF1[byteOf(n0, 1) xor 0x12] xor 0xa06b8293.toInt() + val w3 = tED[byteOf(n2, 0) xor 0xfd] xor tE9[byteOf(n3, 3) xor 0x31] xor + tF5[byteOf(n0, 2) xor 0xce] xor tF1[byteOf(n1, 1) xor 0xcf] xor 0xdbc67afb.toInt() + dwordA = stage2(w3) xor h[3] xor 0xeb34c2c2.toInt() + dwordB = stage2(w1) xor h[1] xor 0x1d59f5dd + dwordC = stage2(w0) xor h[0] xor 0x0ba16ca6 + dwordD = stage2(w2) xor h[2] xor 0x13278ca7 + if (round < 5) { + // register carry (17fc2e1/2ef/2fd + untouched ebx): the carried registers + // hold stage2(w)^h[xor-carry-const] — i.e. the out dword constants + // (0x0ba16ca6/0x1d59f5dd/0x13278ca7) are stripped again before the + // "dead" carry constants 0xc665f28b/0xcf8d9037/0x2c0a2959 are applied + s0 = (dwordC xor 0x0ba16ca6) xor 0xc665f28b.toInt() + s1 = (dwordD xor 0x13278ca7) xor 0xcf8d9037.toInt() + s2 = dwordA + s3 = (dwordB xor 0x1d59f5dd) xor 0x2c0a2959.toInt() + } + } + + // E: finalize via byte table 0x24f9c0 (17fc320-17fc4c3), over the last round's dwords + val eT = t.byteTable(0x24f9c0) + fun byteMix(x: Int): Int = (eT[byteOf(x, 0)].toInt() and 0xff) or + ((eT[byteOf(x, 1)].toInt() and 0xff) shl 8) or + ((eT[byteOf(x, 2)].toInt() and 0xff) shl 16) or + ((eT[byteOf(x, 3)].toInt() and 0xff) shl 24) + val o0 = Integer.reverseBytes( + byteMix(u32le(ctx, 0x70) xor dwordC xor 0x1507bed6) xor h[4] xor 0xb7e2a921.toInt()) + val o1 = Integer.reverseBytes( + byteMix(dwordB xor u32le(ctx, 0x74) xor 0xa947bc24.toInt()) xor h[5] xor 0x4367382c.toInt()) + val o2 = Integer.reverseBytes( + byteMix(dwordD xor u32le(ctx, 0x78) xor 0xafb8d200.toInt()) xor h[6] xor 0x78fe9e63.toInt()) + val o3 = Integer.reverseBytes( + byteMix(dwordA xor u32le(ctx, 0x7c) xor 0x4471a6d1) xor h[7] xor 0x6a81f99f.toInt()) + val out = ByteArray(16) + putU32le(out, 0, o0); putU32le(out, 4, o1); putU32le(out, 8, o2); putU32le(out, 12, o3) + return out + } + + // ---- gen_otp_ios (0x1801d90) — Mac flavor ---------------------------------- + + /** + * gen_otp_ios's own schedule: like expandSchedule but with sigma terms summed + * (sigma1 = rotr18+rotr7 - >>>3, sigma0 = rotr19+rotr17; the >>>10 term is XORed + * into the sum; the whole is subtracted from W[i-16] — 0x1801fc0/0x1801fd4). + */ + private fun expandScheduleIos(w: IntArray) { + for (i in 16 until 64) { + val x = w[i - 2] + val v = w[i - 15] + val s1 = rotr(v, 18) + rotr(v, 7) - (v ushr 3) + val s2 = rotr(x, 19) + rotr(x, 17) xor (x ushr 10) + w[i] = (s1 xor s2) - w[i - 7] - w[i - 16] + } + } + + private class ArxIosResult(val st: IntArray, val out1: Int, val out2: Int) + + /** gen_otp_ios ARX (0x1802100), mixtable 0x2689e0. rot selects the lane rotation. */ + private fun arxIos(w: IntArray, mt: IntArray, init: IntArray, rot2: Boolean): ArxIosResult { + var a = init[0]; var b = init[1]; var c = init[2]; var d = init[3] + var e = init[4]; var f = init[5]; var g = init[6]; var h = init[7] + var out1 = 0; var out2 = 0 + for (i in 0 until 64) { + // 0x1802100-0x18021xx: the mt term is subtracted, (2g-e-f)^f, rotr11^rotr6 + val eax = mt[i] - 0x076fd9aa - w[i] + rotl(g, 7) - + (((2 * g - e - f)) xor f) - (rotr(g, 11) xor rotr(g, 6)) + d + val o1 = (rotr(c, 13) xor rotr(c, 2)) - rotl(c, 10) + (a xor b) - + ((b + c) xor (a + c)) + eax + val o2 = eax + h + out1 = o1; out2 = o2 + if (i == 63) break + val oa = a; val ob = b; val oc = c; val oe = e; val og = g + if (rot2) { a = oc; b = oa } else { a = ob; b = oc } + c = out1; d = f; e = og; f = oe; g = out2; h = if (rot2) ob else oa + } + return ArxIosResult(intArrayOf(a, b, c, d, e, f, g, h), out1, out2) + } + + private val IOS_S1_INIT = intArrayOf( + 0x7c5f6289, 0x593b6cce, -0x3927d65a, -0x338f9db7, + 0x7882d6f2, 0x6f4be3be, 0x750bbed9, -0x06e8dcee, + ) + private val IOS_S2_INIT = intArrayOf( + 0x593b6cce, 0x7c5f6289, -0x3927d65a, -0x338f9db7, + 0x7882d6f2, 0x6f4be3be, 0x750bbed9, -0x06e8dcee, + ) + + /** out-loop constant-pair index (u16 table at rsp+0x4c0, read backwards). */ + private val SG_CONST = intArrayOf(0, 1, 3, 2) + + /** cascade pxor permutation (pshufd 0xc6 lane map). */ + private val PSH = intArrayOf(2, 1, 0, 3) + + /** + * gen_otp_ios: IOS-flavor ADI cipher; 16-byte output. `one` = 0xD0 (208) bytes. + * Transcription of 0x1801d90..0x1804600, verified against the 5 oracle vectors + * (otp.json keys gen_otp_ios-star; inputs one = LCG(2,208), two = LCG(3,32)). + */ + internal fun genOtpIos(gen: UInt, one: ByteArray, two: ByteArray): ByteArray { + val t = ClearAdiTables + val mt = t.wordTable(0x2689e0, 64) + + // ---- stages 1-3: three ARX passes over two-derived schedules (0x1801e00-0x1802?) -- + val c44 = t.consts16(0x1a3180) + val c4730 = t.consts16(0x1a4730) + val c1f30 = t.consts16(0x1a1f30) + val src = ByteArray(64) + for (i in 0 until 16) src[i] = (two[i].toInt() xor c44[i].toInt()).toByte() + for (i in 0 until 16) src[16 + i] = (two[16 + i].toInt() xor c44[i].toInt()).toByte() + c4730.copyInto(src, 32) + c1f30.copyInto(src, 48) + val w1 = IntArray(64) + for (j in 0 until 16) w1[j] = Integer.reverseBytes(u32le(src, 4 * j)) xor 0x77777777 + expandScheduleIos(w1) + val r1 = arxIos(w1, mt, IOS_S1_INIT, rot2 = false) + val a1 = r1.st[0]; val b1 = r1.st[1]; val c1 = r1.st[2] + val e1 = r1.st[4]; val f1 = r1.st[5]; val g1 = r1.st[6] + + // stage-1 lane material used by the gen section and the key-schedule seed (G) + val A = a1; val B = b1; val Cp = c1 + 0x593b6cce; val E = e1; val F = f1; val G = g1 + val o1_1 = r1.out1; val o2_1 = r1.out2 + val o2p = o2_1 + 0x750bbed9 + val rr = mapOf( + "A" to A, "B" to B, "Cp" to Cp, "E" to E, "F" to F, "G" to G, + "o1" to o1_1, "o2p" to o2p, + ) + // 15 constant blocks (lane-letter XOR pattern per dword) + 2 hardcoded tail dwords + val spec = arrayOf( + 0x1a2250 to arrayOf("A", "A", "F", "o2p"), 0x1a1c20 to arrayOf("G", "G", "E", "E"), + 0x1a2c50 to arrayOf("Cp", "o1", "F", "Cp"), 0x1a5850 to arrayOf("F", "B", "B", "A"), + 0x1a3c70 to arrayOf("F", "G", "F", "E"), 0x1a1130 to arrayOf("Cp", "F", "E", "o1"), + 0x1a4cf0 to arrayOf("G", "B", "F", "A"), 0x1a41c0 to arrayOf("A", "o2p", "B", "G"), + 0x1a2f10 to arrayOf("A", "F", "F", "o1"), 0x1a3220 to arrayOf("G", "Cp", "E", "B"), + 0x1a37a0 to arrayOf("Cp", "o2p", "F", "G"), 0x1a4430 to arrayOf("F", "E", "B", "F"), + 0x1a4d00 to arrayOf("F", "Cp", "F", "B"), 0x1a09b0 to arrayOf("Cp", "A", "E", "o2p"), + 0x1a0bf0 to arrayOf("G", "E", "F", "F"), + ) + val dws = IntArray(64) + var di = 2 + for ((vaddr, pat) in spec) { + val cv = t.consts16(vaddr) + for (i in 0 until 4) { + dws[di] = rr[pat[i]]!!.toInt() xor u32le(cv, 4 * i) + di++ + } + } + dws[62] = A xor 0xbaf1f4bf.toInt() + dws[63] = o1_1 xor 0x853efe0b.toInt() + + val X = 0x43e6d7ad.toInt() + val c2250 = t.consts16(0x1a2250) + val c5850 = t.consts16(0x1a5850) + val sh = SHIFT_BYTES + val buf32 = ByteArray(32) + buf32[0] = ((((B xor u32le(c5850, 4)) ushr 16) xor 0x43e6) + 0x2a xor Cp xor 0x77).toByte() + buf32[1] = ((((A xor u32le(c2250, 0)) xor X) ushr 8) + 0x2a xor + ((A xor u32le(c2250, 4)) ushr 24) xor 0x34).toByte() + for (j in 2 until 32) { + val shIdx = 2 * (j and 3) + val lo = (dws[2 * j] xor X) ushr (sh[shIdx].toInt() and 31) + val hi = (dws[2 * j + 1] xor X) ushr (sh[shIdx + 1].toInt() and 31) + buf32[j] = ((lo + 0x2a) xor hi xor 0x77).toByte() + } + + // ---- stage 2 (buf32 duplicated) ---- + val bufB = ByteArray(64) + buf32.copyInto(bufB, 0); buf32.copyInto(bufB, 32) + val w2 = IntArray(64) + for (j in 0 until 16) w2[j] = Integer.reverseBytes(u32le(bufB, 4 * j)) xor 0x77777777 + expandScheduleIos(w2) + val r2 = arxIos(w2, mt, IOS_S2_INIT, rot2 = true) + val a2 = r2.st[0]; val b2 = r2.st[1]; val c2 = r2.st[2] + val e2 = r2.st[4]; val f2 = r2.st[5]; val g2 = r2.st[6] + val c1a0ed0 = t.consts16(0x1a0ed0) + val c1a4a90 = t.consts16(0x1a4a90) + val c2p = c2 + 0x593b6cce + val o2p2 = r2.out2 + 0x750bbed9 + val s3Init = intArrayOf( + a2 xor u32le(c1a0ed0, 8), c2p xor u32le(c1a0ed0, 4), r2.out1 xor u32le(c1a0ed0, 0), + f2 xor u32le(c1a4a90, 12), g2 xor u32le(c1a4a90, 4), e2 xor u32le(c1a4a90, 8), + o2p2 xor u32le(c1a4a90, 0), b2 xor u32le(c1a0ed0, 12), + ) + + // ---- stage 3 (padding-block schedule) ---- + val bc = ByteArray(64) + t.consts16(0x1a3c50).copyInto(bc, 0) + t.consts16(0x1a4740).copyInto(bc, 16) + t.consts16(0x1a4740).copyInto(bc, 32) + t.consts16(0x1a5d90).copyInto(bc, 48) + val w3 = IntArray(64) + w3[0] = u32le(bc, 0) + for (j in 1 until 16) w3[j] = Integer.reverseBytes(u32le(bc, 4 * j)) xor 0x77777777 + expandScheduleIos(w3) + val r3 = arxIos(w3, mt, s3Init, rot2 = false) + val a3 = r3.st[0]; val b3 = r3.st[1]; val c3 = r3.st[2] + val e3 = r3.st[4]; val f3 = r3.st[5]; val g3 = r3.st[6] + + // scatter constants (stage-2 lanes ^ C1a3ea0/C1a0be0) + val ea0 = t.consts16(0x1a3ea0) + val be0 = t.consts16(0x1a0be0) + val s20 = r2.out1 xor u32le(ea0, 0) + val s30 = a2 xor u32le(ea0, 8) + val s70 = b2 xor u32le(ea0, 12) + val s38 = g2 xor u32le(be0, 4) + val s40 = e2 xor u32le(be0, 8) + val s50 = f2 xor u32le(be0, 12) + + // ---- gen section: ctx220/230 candidates + 64-byte shuffle region ---- + val o2p2v = r2.out2 + 0x750bbed9 + val A0 = r3.out1 xor s20 + val E0 = e3 xor s40 + val H0 = (c2p + c3) xor 0x43e6d7ad.toInt() + val B0 = b3 xor s30 + val a3s70 = a3 xor s70 + val G0 = g3 xor s38 + val F0 = f3 xor s50 + val o23p = (r3.out2 + o2p2v) xor 0x43e6d7ad.toInt() + val ctx220 = intArrayOf(A0, H0, B0, a3s70) + val ctx230 = intArrayOf(o23p, G0, E0, F0) + + val g = gen.toInt() + val h1v = (g.toLong() * 0x12e0a56bL) ushr 32 + val t1 = ((g - h1v.toInt()).toLong() and 0xffffffffL) + val r14v = (t1 ushr 1) + h1v + val r14w2 = ((r14v ushr 29) and 0xffff).toInt() + val dx16 = ((g.toLong() * 0x1b39aeb3L) ushr 60 and 0xffff).toInt() + val cx16 = ((g.toLong() * 0x7b85ee89L) ushr 57 and 0xffff).toInt() + val r13w = ((g.toLong() * 0x9c715473L) ushr 61 and 0xffff).toInt() + fun lane16(mult: Int): Int = ((mult + g) and 0xffff) xor 0x7777 + val e0b = lane16(r14w2 * 0x308f) // esi lane + val h0b = lane16(dx16 * 0x4467) // r14 lane + val b0b = lane16(cx16 * 0xe329) // r12 lane + val mVal = (r13w * 0xc259) and 0xffff + var r9full = (0xffff0000.toInt() or mVal) + g + r9full = (r9full and 0xffff0000.toInt()) or ((r9full and 0xffff) xor 0x7777) + val shuf = ByteArray(64) + shuf[0] = ((e0b ushr 8) and 0xff).toByte(); shuf[1] = (e0b and 0xff).toByte() + shuf[2] = ((h0b ushr 8) and 0xff).toByte(); shuf[3] = (h0b and 0xff).toByte() + shuf[4] = ((b0b ushr 8) and 0xff).toByte(); shuf[5] = (b0b and 0xff).toByte() + shuf[6] = ((r9full ushr 8) and 0xff).toByte() + val two1 = u8(two, 1) + val ebx32 = (((two1 xor 0x33) - 0x6d) xor r9full) + shuf[7] = (ebx32 and 0xff).toByte() + var chain = ((ebx32 xor 0x77) * 0x44) xor 0xffffff98.toInt() + val c4740 = t.consts16(0x1a4740) + c4740.copyInto(shuf, 8); c4740.copyInto(shuf, 24); c4740.copyInto(shuf, 40) + shuf[55] = 0xf7.toByte() + for (i in 56 until 62) shuf[i] = 0x77 + shuf[62] = 0x76; shuf[63] = 0xcf.toByte() + for (k in 0 until 19) { + val base = 8 + 5 * k + val ti = 3 + 10 * k + for (mm in 0 until 5) { + val n = base + mm + val qn = ((n.toLong() * 156180629L) ushr 33).toInt() + val pos = n - 55 * qn + val tb = u8(two, (ti + 2 * mm) and 0x1f) + val v = (tb xor 0x33) + (chain xor 0xb) + val nb = (v and 0xff) xor u8(shuf, pos) + shuf[pos] = nb.toByte() + chain = chain xor ((((v and 0xffffff00.toInt()) or nb) xor 0x77) * 0x44) + } + } + + // ---- stage 4 (shuffled64 schedule) ---- + val w4 = IntArray(64) + for (j in 0 until 16) w4[j] = Integer.reverseBytes(u32le(shuf, 4 * j)) xor 0x77777777 + expandScheduleIos(w4) + val r4 = arxIos(w4, mt, IOS_S2_INIT, rot2 = true) + val c4p = r4.st[2] + 0x593b6cce + val o2p4 = r4.out2 + 0x750bbed9 + val ctx240 = intArrayOf( + r4.out1 xor u32le(ea0, 0), c4p xor 0x43e6d7ad.toInt(), + r4.st[0] xor u32le(ea0, 8), r4.st[1] xor u32le(ea0, 12), + o2p4 xor 0x43e6d7ad.toInt(), r4.st[6] xor u32le(be0, 4), + r4.st[4] xor u32le(be0, 8), r4.st[5] xor u32le(be0, 12), + ) + + // ---- stream: 13 whitbox chunks over `one` (0x1803a00-0x1803a70 region) ---- + val tKey0 = t.byteTable(0x26cfe0); val tKey1 = t.byteTable(0x26cee0) + val tKey2 = t.byteTable(0x26cce0); val tKey3 = t.byteTable(0x26cde0) + val tl20 = t.wordTable(0x26d0e0); val tl21 = t.wordTable(0x26d4e0) + val tl22 = t.wordTable(0x26d8e0); val tl23 = t.wordTable(0x26dce0) + val tl30 = t.wordTable(0x26e8e0); val tl31 = t.wordTable(0x26e4e0) + val tl32 = t.wordTable(0x26ece0); val tl33 = t.wordTable(0x26e0e0) + val tl40 = t.byteTable(0x26f4e0); val tl41 = t.byteTable(0x26cbe0) + val tl42 = t.byteTable(0x26f5e0); val tl43 = t.wordTable(0x26f0e0) + fun diag(k16: ByteArray, t0: IntArray, t1: IntArray, t2: IntArray, t3: IntArray, + tdw: IntArray): IntArray { + val out = IntArray(4) + for (i in 0 until 4) { + val v = t0[k16[4 * i].toInt() and 0xff] xor + t1[k16[4 * ((i + 1) and 3) + 1].toInt() and 0xff] xor + t2[k16[4 * ((i + 2) and 3) + 2].toInt() and 0xff] xor + t3[k16[4 * ((i + 3) and 3) + 3].toInt() and 0xff] + out[i] = v xor tdw[i] + } + return out + } + val c24f0 = t.consts16(0x1a24f0) + val c4d10 = t.consts16(0x1a4d10) + val tailC = arrayOf( + 0x1a2a30, 0x1a2c60, 0x1a3a50, 0x1a47d0, 0x1a09c0, + 0x1a2f30, 0x1a3500, 0x1a27a0, 0x1a0ee0, + ).map { t.consts16(it) } + val c1140 = t.consts16(0x1a1140) + val c1700 = t.consts16(0x1a1700) + // hi_const = le64(0x07ef060b00000000) ‖ le64(0x62181bd1975656c6) + val hiConst = byteArrayOf( + 0, 0, 0, 0, 0x0b, 6, 0xef.toByte(), 0x07, + 0xc6.toByte(), 0x56, 0x56, 0x97.toByte(), 0xd1.toByte(), 0x1b, 0x18, 0x62, + ) + val stream = ByteArray(13 * 16) + var l3dw = IntArray(4) { u32le(t.consts16(0x1a2f20), 4 * it) } + for (ch in 0 until 13) { + val o = ch * 16 + val key16 = ByteArray(16) + for (i in 0 until 4) { + val b = IntArray(4) { u8(one, o + 4 * i + it) xor u8(c4d10, 4 * i + it) } + val v = ((tKey0[b[0]].toInt() and 0xff) shl 24) xor + ((tKey1[b[1]].toInt() and 0xff) shl 16) xor + ((tKey2[b[2]].toInt() and 0xff) shl 8) xor + (tKey3[b[3]].toInt() and 0xff) xor u32le(c24f0, 4 * i) + putU32le(key16, 4 * i, v) + } + val k2 = ByteArray(16) + key16.copyInto(k2, 0, 8, 16); key16.copyInto(k2, 8, 0, 8) + for (c in 0 until 9) { + val td = IntArray(4) { u32le(tailC[c], 4 * it) } + val nv = diag(k2, tl20, tl21, tl22, tl23, td) + for (i in 0 until 4) putU32le(k2, 4 * i, nv[i]) + } + val td = IntArray(4) { l3dw[it] xor u32le(c1140, 4 * it) } + val x16 = diag(k2, tl30, tl31, tl32, tl33, td) + val x16b = ByteArray(16) + for (i in 0 until 4) putU32le(x16b, 4 * i, x16[i]) + val mixed = ByteArray(16) + for (i in 0 until 4) { + val d = u32le(x16b, 4 * i) + mixed[4 * i + 0] = tl40[byteOf(d, 3)].toByte() + mixed[4 * i + 1] = tl41[byteOf(d, 2)].toByte() + mixed[4 * i + 2] = tl42[byteOf(d, 1)].toByte() + mixed[4 * i + 3] = (tl43[byteOf(d, 0)] and 0xff).toByte() + } + for (i in 0 until 16) stream[o + i] = (hiConst[i].toInt() xor u8(mixed, i)).toByte() + val keyPrev = IntArray(4) { u32le(key16, 4 * it) } + l3dw = IntArray(4) { keyPrev[it] xor u32le(c1700, 4 * it) } + } + + // ---- VM: 192 output bytes from the permuted stream input (0x1803b90-0x1803ca8) -- + val vb = t.vmBlob() + val c4440 = t.consts16(0x1a4440) + val sadj = ByteArray(stream.size) + for (i in stream.indices) sadj[i] = (stream[i].toInt() xor c4440[i and 15].toInt()).toByte() + val s0seed = (u8(sadj, 0xcd) + u8(sadj, 0x99) + u8(sadj, 0x6b) + u32le(sadj, 0x80)) + var s = s0seed + val vm = ByteArray(192) + for (i in 0 until 192) { + val b = u8(sadj, u32le(vb, 8 * i)) + val m5 = s and 5 + val outB: Int + when (m5) { + 4 -> { outB = (s + b) and 0xff; s = (((outB) xor (s and 0xff)) - 0x66) } + 1 -> { outB = (b - s) and 0xff; s = (((b - s) xor s) - 0x66) } + 0 -> { outB = (b xor s) and 0xff; s = b - 0x66 } + else -> { outB = b and 0xff; s = ((b xor s) - 0x66) } + } + vm[i] = outB.toByte() + } + + // ---- ctx assembly ---- + val ctx = ByteArray(0x270) + for (i in 0 until 4) { + putU32le(ctx, 0x220 + 4 * i, ctx220[i]) + putU32le(ctx, 0x230 + 4 * i, ctx230[i]) + putU32le(ctx, 0x240 + 4 * i, ctx240[i]) + putU32le(ctx, 0x250 + 4 * i, ctx240[4 + i]) + } + vm.copyInto(ctx, 0x130) + // G: ctx[0x200..0x220] — stage-1 derived dwords (17fbd39-adjacent stores) + val c24e0 = t.consts16(0x1a24e0) + val c2240 = t.consts16(0x1a2240) + val gd = intArrayOf( + o1_1 xor u32le(c24e0, 0), + Cp xor u32le(c24e0, 4), + B xor u32le(c24e0, 8), + A xor u32le(c24e0, 12), + o2p xor u32le(c2240, 0), + G xor u32le(c2240, 4), + E xor u32le(c2240, 8), + F xor u32le(c2240, 12), + ) + for (i in 0 until 8) putU32le(ctx, 0x200 + 4 * i, gd[i]) + // ctx[0x120..0x130] = bswap(vm[0..16]); ctx[0x70+4i] = bswap(vm[0x10+4i]) + for (j in 0 until 4) { + ctx[0x120 + 4 * j + 0] = vm[4 * j + 3]; ctx[0x120 + 4 * j + 1] = vm[4 * j + 2] + ctx[0x120 + 4 * j + 2] = vm[4 * j + 1]; ctx[0x120 + 4 * j + 3] = vm[4 * j + 0] + } + for (i in 0 until 40) { + for (k in 0 until 4) ctx[0x70 + 4 * i + k] = vm[0x10 + 4 * i + 3 - k] + } + + // ---- key schedule (0x1803e90-0x1804006) ---- + val ks1 = arrayOf(t.wordTable(0x26bbe0), t.wordTable(0x26c7e0), t.wordTable(0x26c3e0), t.wordTable(0x26bfe0)) + val ks2 = arrayOf(t.wordTable(0x26abe0), t.wordTable(0x26afe0), t.wordTable(0x26b3e0), t.wordTable(0x26b7e0)) + val firstMask = t.raw(0x268980, 96) + val secondMask = t.raw(0x268920, 96) + val finalMask = t.raw(0x2688c0, 96) + val K = IntArray(24) + for (i in 0 until 24) { + var x = u32le(ctx, 0x200 + 4 * i) xor u32le(firstMask, 4 * i) + if (i < 4) x = x xor u32le(ctx, 0x120 + 4 * i) + val t1v = mix4(x, ks1[0], ks1[1], ks1[2], ks1[3]) xor u32le(secondMask, 4 * i) + val t2v = mix4(t1v, ks2[0], ks2[1], ks2[2], ks2[3]) + var k = t2v xor u32le(finalMask, 4 * i) + if (i < 4) k = k xor u32le(ctx, 0x70 + 4 * i) + K[i] = k + } + + // ---- rounds: 6 × (9-step AES-T cascade + post-mix + out) (0x18040e0-0x18044ec) -- + val rtA = t.wordTable(0x26a7e0); val rtB = t.wordTable(0x269be0) + val rtC = t.wordTable(0x26a3e0); val rtD = t.wordTable(0x269fe0) + val m40 = t.wordTable(0x2693e0); val m41 = t.wordTable(0x268be0) + val m42 = t.wordTable(0x2697e0); val m43 = t.wordTable(0x268fe0) + val ksConsts = arrayOf( + 0x1a5590, 0x1a5da0, 0x1a5db0, 0x1a47e0, 0x1a2a40, + 0x1a2c70, 0x1a19c0, 0x1a5860, 0x1a1c30, + ).map { t.consts16(it) } + // W: byte picks from the VM input (sadj = stream ^ C4440*13) + the VM state + // seed low byte; written to ctx[0x110..0x120] by the binary (0x1803d0b-0x1803dd0) + val s0seedLow = (u8(sadj, 0x8a) - s0seed) and 0xff + val wA = (u8(sadj, 0x49) shl 24) or (u8(sadj, 0x00) shl 16) or + (u8(sadj, 0x20) shl 8) or u8(sadj, 0x90) + val wB = (s0seedLow shl 24) or (u8(sadj, 0x1c) shl 16) or + (u8(sadj, 0x7b) shl 8) or u8(sadj, 0x9a) + val wC = (u8(sadj, 0xba) shl 24) or (u8(sadj, 0x38) shl 16) or + (u8(sadj, 0x9e) shl 8) or u8(sadj, 0x25) + val wD = (u8(sadj, 0xcd) shl 24) or (u8(sadj, 0x99) shl 16) or + (u8(sadj, 0x80) shl 8) or u8(sadj, 0x6b) + val wv = intArrayOf(wA, wC, wD, wB) + val yv = IntArray(4) { wv[it] xor u32le(t.consts16(0x1a5030), 4 * it) } + val c0f00 = t.consts16(0x1a0f00) + var prev = intArrayOf(0x28c8ecaf, 0x2cf27d71, 0x18affa28, 0x499e4844) + var mem = IntArray(4) + for (r in 0 until 6) { + val d0 = prev[0] xor K[4 * r] xor 0xad69d16a.toInt() + val d1 = prev[1] xor K[4 * r + 1] xor 0xa95340b4.toInt() + val d2 = prev[2] xor K[4 * r + 2] xor 0x9d0ec7ed.toInt() + val d3 = prev[3] xor K[4 * r + 3] xor 0xcc3f7581.toInt() + var eb = d1; var ec = d0; var ed = d2; var ea = d3 + var o = IntArray(4) + for (k in 0 until 9) { + // aessmix (0x18041df-0x18042bf): RT tables r8/rsi/r15/r12 + o = intArrayOf( + rtA[byteOf(eb, 0)] xor rtB[byteOf(ed, 3)] xor rtC[byteOf(ec, 1)] xor rtD[byteOf(ea, 2)], + rtA[byteOf(ec, 0)] xor rtB[byteOf(eb, 3)] xor rtC[byteOf(ea, 1)] xor rtD[byteOf(ed, 2)], + rtA[byteOf(ea, 0)] xor rtB[byteOf(ec, 3)] xor rtC[byteOf(ed, 1)] xor rtD[byteOf(eb, 2)], + rtA[byteOf(ed, 0)] xor rtB[byteOf(ea, 3)] xor rtC[byteOf(eb, 1)] xor rtD[byteOf(ec, 2)], + ) + val px = o + for (j in 0 until 4) { + // pshufd 0xc6 of the ctx chunk + blobc chunk + val xk = Integer.reverseBytes(u32le(vm, 0x20 + 0x10 * k + 4 * PSH[j])) + o[j] = px[j] xor xk xor u32le(ksConsts[k], 4 * j) + } + val t0 = o[1]; val t1v = o[2]; val t2v = o[0]; val t3v = o[3] + eb = t0; ec = t1v; ed = t2v; ea = t3v + } + // post-mix (0x18042e0-0x180441b): RT lanes over the cascade output + val stv = IntArray(4) { j -> + rtA[byteOf(o[j], 0)] xor rtB[byteOf(o[(j + 3) and 3], 3)] xor + rtC[byteOf(o[(j + 1) and 3], 1)] xor rtD[byteOf(o[(j + 2) and 3], 2)] + } + val c1150 = t.consts16(0x1a1150) + val state = IntArray(4) { stv[it] xor u32le(c1150, 4 * it) } + for (j in 0 until 4) { + val kk = SG_CONST[j] + val v = m40[byteOf(state[j], 0)] xor m41[byteOf(state[j], 1)] xor + m42[byteOf(state[j], 2)] xor m43[byteOf(state[j], 3)] + mem[j] = v xor u32le(c0f00, 4 * kk) xor yv[kk] + } + prev = intArrayOf(mem[3], mem[2], mem[1], mem[0]) + } + + // ---- final (0x18044f2-0x18045c3) ---- + val preout = intArrayOf( + mem[3], mem[2], mem[1], mem[0] xor 0x6145cbf9.toInt(), + ) + val c5040 = t.consts16(0x1a5040) + val c2500 = t.consts16(0x1a2500) + val feist = t.byteTable(0x268ae0) + val out = ByteArray(16) + for (j in 0 until 4) { + val tv = preout[j] xor u32le(c5040, 4 * j) xor u32le(ctx, 0x70 + 4 * j) + val ft = ByteArray(16) + for (i in 0 until 4) ft[i] = feist[byteOf(tv, i)].toByte() + val v = u32le(c2500, 4 * j) xor u32le(ctx, 0x120 + 4 * j) xor u32le(ft, 0) + putU32le(out, 4 * j, Integer.reverseBytes(v)) + } + return out + } + + // ---- gen_code (0x1801360) --------------------------------------------------- + + /** + * gen_code: SHA-1(sig ‖ machine[0x38..0x74]) — the full 60-byte secret, two standard + * blocks (the report's "48 bytes" is wrong: block 2 carries machine[0x68..0x74] plus + * padding, length 608 bits, 0x18013a2/0x18013bb/0x18013ef). Returns + * ((h0<<32)|h1) mod 1_000_000 (0x1801414-0x1801443). + */ + internal fun genCode(sig: ByteArray, secret60: ByteArray): UInt { + require(secret60.size >= 60) { "secret must be 60 bytes" } + val md = java.security.MessageDigest.getInstance("SHA-1") + val input = ByteArray(16 + 60) + sig.copyInto(input, 0) + secret60.copyInto(input, 16, 0, 60) + val d = md.digest(input) + val h0 = ((d[0].toInt() and 0xff) shl 24) or ((d[1].toInt() and 0xff) shl 16) or + ((d[2].toInt() and 0xff) shl 8) or (d[3].toInt() and 0xff) + val h1 = ((d[4].toInt() and 0xff) shl 24) or ((d[5].toInt() and 0xff) shl 16) or + ((d[6].toInt() and 0xff) shl 8) or (d[7].toInt() and 0xff) + val h01 = (h0.toLong() and 0xffffffffL) shl 32 or (h1.toLong() and 0xffffffffL) + return (h01 % 1_000_000L).toInt().toUInt() + } + + // ---- frame builders (generate_sig 0x17eead0 / generate_otp 0x17ee2a0 / gen_2fa_code) -- + + /** 28-byte X-Apple-I-MD payload: u32be(5) ‖ u32be(16) ‖ sig16 ‖ u32be(flavor). */ + fun anisetteOtp(flavor: Int, metadata: ByteArray, mid: ByteArray, unixSeconds: Long): ByteArray { + val gen = (unixSeconds / 30).toInt().toUInt() + // `metadata` feeds the cipher as `one` = the machine's client_info (≥ 0x190 B IOS / + // ≥ 0xd0 B Mac, otp-path.md §3). Until the live capture pins the + // ProvisionedData→client_info mapping, shorter inputs are zero-extended to the + // flavor's minimum (deterministic placeholder). TODO(live-capture) + val need = if (flavor == 1) 0x190 else 0xd0 + val one = if (metadata.size >= need) metadata else metadata + ByteArray(need - metadata.size) + // flavor 1 (IOS) -> gen_otp; flavor 0 (Mac) -> gen_otp_ios (naming inverted in the binary) + val sig = when (flavor) { + 1 -> genOtp(gen, one, mid) + else -> genOtpIos(gen, one, mid) + } + val out = ByteArray(28) + out[0] = 0; out[1] = 0; out[2] = 0; out[3] = 5 + out[4] = 0; out[5] = 0; out[6] = 0; out[7] = 16 + sig.copyInto(out, 8) + out[24] = 0; out[25] = 0 + out[26] = (flavor ushr 8).toByte(); out[27] = flavor.toByte() + return out + } + + /** 2FA code for the current 30-second window. `secret` = machine[0x38..0x74] (60 B). */ + fun twoFactorCode( + flavor: Int, + metadata: ByteArray, + mid: ByteArray, + secret: ByteArray, + unixSeconds: Long, + ): UInt { + val frame = anisetteOtp(flavor, metadata, mid, unixSeconds) + return genCode(frame.copyOfRange(8, 24), secret) + } +} diff --git a/registration/src/main/kotlin/dev/fenn/imessage/registration/ClearAdiProvision.kt b/registration/src/main/kotlin/dev/fenn/imessage/registration/ClearAdiProvision.kt new file mode 100644 index 0000000..aa8b511 --- /dev/null +++ b/registration/src/main/kotlin/dev/fenn/imessage/registration/ClearAdiProvision.kt @@ -0,0 +1,812 @@ +package dev.fenn.imessage.registration + +/** + * Kotlin transcription of the ClearADI provisioning-cipher path (librust_lib_bluebubbles, + * the OpenBubbles white-box CoreADI). Address citations refer to that .so. Quirks of the + * white-box network (rotated round outputs, dead constants, phase-2 pipeline scatter, + * OR-colliding spim_map bits) are reproduced exactly — they are load-bearing. + * + * Ported and byte-exact against the live library: decodeSpim, ingest, docrypt, encrypt, + * encrypt_ingest, encsec, spim_map_signature, init_session (all three phases), decryptPTM + * (0x17ffb50: initial key-mix head, phase A, 4.3 S-box tail, 4.4 key schedule, K0–K4). + */ +internal object ClearAdiProvision { + + // ---- helpers ------------------------------------------------------------- + + private fun u32le(b: ByteArray, i: Int): Int = + (b[i].toInt() and 0xff) or + ((b[i + 1].toInt() and 0xff) shl 8) or + ((b[i + 2].toInt() and 0xff) shl 16) or + ((b[i + 3].toInt() and 0xff) shl 24) + + private fun putU32le(b: ByteArray, i: Int, v: Int) { + b[i] = v.toByte() + b[i + 1] = (v ushr 8).toByte() + b[i + 2] = (v ushr 16).toByte() + b[i + 3] = (v ushr 24).toByte() + } + + /** one byte of a word, position 0 = LSB. */ + private fun byteOf(x: Int, n: Int): Int = (x ushr (8 * n)) and 0xff + + private fun words(b16: ByteArray): IntArray = IntArray(4) { u32le(b16, 4 * it) } + + private fun fromWords(w: IntArray): ByteArray = ByteArray(16).also { for (i in 0 until 4) putU32le(it, 4 * i, w[i]) } + + private fun bswap(x: Int): Int = Integer.reverseBytes(x) + + private fun beWord(b: ByteArray, off: Int): Int = + ((b[off].toInt() and 0xff) shl 24) or ((b[off + 1].toInt() and 0xff) shl 16) or + ((b[off + 2].toInt() and 0xff) shl 8) or (b[off + 3].toInt() and 0xff) + + private fun const16(vaddr: Int): ByteArray = ClearAdiTables.consts16(vaddr) + private fun wordTable(vaddr: Int): IntArray = ClearAdiTables.wordTable(vaddr) + private fun byteTable(vaddr: Int): ByteArray = ClearAdiTables.byteTable(vaddr) + + // ---- shared primitives ----------------------------------------------------- + + private val tJoinB0 = wordTable(0x256ec0) + private val tJoinB1 = wordTable(0x256ac0) + private val tJoinB2 = wordTable(0x2566c0) + private val tJoinB3 = wordTable(0x2562c0) + + private fun join(a: Int, b: Int, c: Int, d: Int): Int = + tJoinB0[byteOf(a, 0)] xor tJoinB1[byteOf(b, 1)] xor + tJoinB2[byteOf(c, 2)] xor tJoinB3[byteOf(d, 3)] + + private val tJ2I = wordTable(0x2556c0) + private val tJ2B1 = wordTable(0x255ac0) + private val tJ2B2 = wordTable(0x2552c0) + private val tJ2B3 = wordTable(0x255ec0) + + private fun join2(i: Int, a: Int, b: Int, c: Int): Int = + tJ2I[i and 0xff] xor tJ2B1[byteOf(a, 1)] xor tJ2B2[byteOf(b, 2)] xor tJ2B3[byteOf(c, 3)] + + private val tAlaB0 = wordTable(0x25b2c0) + private val tAlaB1 = wordTable(0x25b6c0) + private val tAlaB2 = wordTable(0x25bac0) + private val tAlaB3 = wordTable(0x25bec0) + + private fun ala(x: Int): Int = + tAlaB0[byteOf(x, 0)] xor tAlaB1[byteOf(x, 1)] xor + tAlaB2[byteOf(x, 2)] xor tAlaB3[byteOf(x, 3)] + + private val tOgB0 = wordTable(0x25f2c0) + private val tOgB1 = wordTable(0x25f6c0) + private val tOgB2 = wordTable(0x25eac0) + private val tOgB3 = wordTable(0x25eec0) + + private fun outgen(x: Int): Int = + tOgB0[byteOf(x, 0)] xor tOgB1[byteOf(x, 1)] xor + tOgB2[byteOf(x, 2)] xor tOgB3[byteOf(x, 3)] + + private val tIngB0 = wordTable(0x2622c0) + private val tIngB1 = wordTable(0x262ac0) + private val tIngB2 = wordTable(0x2626c0) + private val tIngB3 = wordTable(0x262ec0) + + /** ingest: source words come from the block in [+8,+0xc,+0,+4] order with fixed consts. */ + private fun ingest(block16: ByteArray): IntArray { + val w = words(block16) + val src = intArrayOf( + w[2] xor 0x54F532EA.toInt(), w[3] xor 0x2A1BFBF2.toInt(), + w[0] xor 0x61D5F556, w[1] xor 0x07D1FC1D, + ) + return IntArray(4) { k -> + tIngB0[byteOf(src[k], 0)] xor tIngB1[byteOf(src[k], 1)] xor + tIngB2[byteOf(src[k], 2)] xor tIngB3[byteOf(src[k], 3)] + } + } + + // ---- decodeSpim (0x17fc780) -------------------------------------------------- + + private val dspimKx = byteArrayOf( + 0x86.toByte(), 0x81.toByte(), 0x9a.toByte(), 0xcb.toByte(), + 0x16.toByte(), 0x05.toByte(), 0x2f.toByte(), 0x64.toByte(), + 0x3d.toByte(), 0xce.toByte(), 0x68.toByte(), 0x39.toByte(), + 0xd5.toByte(), 0xd9.toByte(), 0x82.toByte(), 0x53.toByte(), + ) + private val dspimT3 = byteTable(0x2597c0) // byte position 4k + private val dspimT2 = byteTable(0x2596c0) // 4k+1 + private val dspimT1 = byteTable(0x2599c0) // 4k+2 + private val dspimT4 = byteTable(0x2598c0) // 4k+3 + private val dspimC1 = const16(0x1a5b10) + private val dspimChainConst = const16(0x1a3e80) + private val dspimC2Init = const16(0x1a2a00) + private val dspimC3 = const16(0x1a4760) + private val dspimRc = listOf( + 0x1a4750, 0x1a2780, 0x1a3770, 0x1a5290, 0x1a2220, + 0x1a5550, 0x1a4410, 0x1a5b20, 0x1a57f0, + ).map { const16(it) } + + fun decodeSpim(inp: ByteArray): ByteArray { + val out = ByteArray(240) + var c2 = dspimC2Init.copyOf() + for (blk in 0 until 15) { + val ib = inp.copyOfRange(blk * 16, blk * 16 + 16) + val w = IntArray(4) + for (k in 0 until 4) { + val b0 = ib[4 * k].toInt() and 0xff xor (dspimKx[4 * k].toInt() and 0xff) + val b1 = ib[4 * k + 1].toInt() and 0xff xor (dspimKx[4 * k + 1].toInt() and 0xff) + val b2 = ib[4 * k + 2].toInt() and 0xff xor (dspimKx[4 * k + 2].toInt() and 0xff) + val b3 = ib[4 * k + 3].toInt() and 0xff xor (dspimKx[4 * k + 3].toInt() and 0xff) + w[k] = ((dspimT3[b0].toInt() and 0xff) shl 24) or + ((dspimT2[b1].toInt() and 0xff) shl 16) or + ((dspimT1[b2].toInt() and 0xff) shl 8) or + (dspimT4[b3].toInt() and 0xff) + } + val c1w = words(dspimC1) + var state = IntArray(4) { w[it] xor c1w[it] } + for (r in 0 until 9) { + val rcw = words(dspimRc[r]) + val new = IntArray(4) + for (i in 0 until 4) { + new[(i + 1) and 3] = join(state[i], state[(i + 1) and 3], state[(i + 2) and 3], state[(i + 3) and 3]) xor rcw[i] + } + state = new + } + val cw3 = words(dspimC3) + val c2w = words(c2) + val outw = IntArray(4) + for (j in 1..4) { + val k = j and 3 + outw[k] = join2(state[j - 1], state[k], state[(k + 1) and 3], state[(k + 2) and 3]) xor + cw3[j - 1] xor c2w[k] + } + fromWords(outw).copyInto(out, blk * 16) + val cb = dspimChainConst.copyOf() + val wb = fromWords(w) + for (i in 0 until 16) cb[i] = (cb[i].toInt() xor wb[i].toInt()).toByte() + c2 = cb + } + return out + } + + // ---- docrypt (0x17ff550) ------------------------------------------------------- + + private val tDocB0 = wordTable(0x2632c0) + private val tDocB1 = wordTable(0x263ec0) + private val tDocB2 = wordTable(0x2636c0) + private val tDocB3 = wordTable(0x263ac0) + private val tDocfB0 = wordTable(0x2612c0) + private val tDocfB1 = wordTable(0x2616c0) + private val tDocfB2 = wordTable(0x261ac0) + private val tDocfB3 = wordTable(0x261ec0) + private val tDocgB0 = byteTable(0x260ec0) + private val tDocgB1 = byteTable(0x260fc0) + private val tDocgB2 = byteTable(0x2610c0) + private val tDocgB3 = byteTable(0x2611c0) + private val docRc = listOf( + 0x1a31d0, 0x1a19a0, 0x1a5b40, 0x1a31e0, 0x1a1f70, + 0x1a5580, 0x1a31f0, 0x1a09a0, 0x1a3200, + ).map { const16(it) } + private val docC1 = const16(0x1a1bf0) + private val docC2 = const16(0x1a2a20) + private val docC3 = const16(0x1a3c60) + + /** keys: K0..K3 = 0x30-byte buffers (+0x24 outgen word), K4 = 16 bytes. io: 4 words. */ + internal fun docrypt(block16: ByteArray, keys: List, io: IntArray): Pair { + val t = ingest(block16) + val ks = intArrayOf( + outgen(u32le(keys[1], 0x24)), outgen(u32le(keys[2], 0x24)), + outgen(u32le(keys[3], 0x24)), outgen(u32le(keys[0], 0x24)), + ) + val ioNew = intArrayOf( + t[2] xor u32le(docC1, 8), t[3] xor u32le(docC1, 12), + t[0] xor u32le(docC1, 0), t[1] xor u32le(docC1, 4), + ) + var s = IntArray(4) { i -> t[i] xor u32le(docC2, 4 * i) xor ks[i] } + for (r in 0 until 9) { + val rcw = words(docRc[r]) + val new = IntArray(4) + for (i in 0 until 4) { + val kw = u32le(keys[(i - r) and 3], 0x20 - 4 * r) + new[i] = rcw[i] xor ala(kw) xor + tDocB0[byteOf(s[i], 0)] xor tDocB1[byteOf(s[(i + 1) and 3], 1)] xor + tDocB2[byteOf(s[(i + 2) and 3], 2)] xor tDocB3[byteOf(s[(i + 3) and 3], 3)] + } + s = new + } + val k4w = words(keys[4]) + val k4p = intArrayOf(k4w[0], k4w[3], k4w[2], k4w[1]) // pshufd 0x6c + val v = IntArray(4) { i -> + tDocfB0[byteOf(s[i], 0)] xor tDocfB1[byteOf(s[(i + 1) and 3], 1)] xor + tDocfB2[byteOf(s[(i + 2) and 3], 2)] xor tDocfB3[byteOf(s[(i + 3) and 3], 3)] xor + k4p[i] xor u32le(docC3, 4 * i) xor io[i] + } + val gconsts = intArrayOf(0x2965BC00, 0x1664B0A2, 0x84F08D8C.toInt(), 0x52E41983) + val out = IntArray(4) + for (i in 0 until 4) { + val x = ((tDocgB3[byteOf(v[i], 3)].toInt() and 0xff) shl 24) or + ((tDocgB2[byteOf(v[i], 2)].toInt() and 0xff) shl 16) or + ((tDocgB1[byteOf(v[i], 1)].toInt() and 0xff) shl 8) or + (tDocgB0[byteOf(v[i], 0)].toInt() and 0xff) + val y = x xor gconsts[i] + out[i] = ((y and 0xFF) shl 24) or ((y and 0xFF00) shl 8) or ((y ushr 8) and 0xFF00) or ((y ushr 24) and 0xFF) + } + return out to ioNew + } + + // ---- encrypt_ingest (0x17fe9b0) / encrypt (0x17fec30) ---------------------------- + + private val eiW = mapOf(8 to 0x1DC3032F, 12 to 0x63B3D12E, 0 to 0xA772AB1D.toInt(), 4 to 0xF156A067.toInt()) + private val eiC = mapOf( + 8 to intArrayOf(0x68, 0x3a, 0x54, 0x82), 12 to intArrayOf(0x83, 0x95, 0xed, 0xc2), + 0 to intArrayOf(0xe3, 0x52, 0x56, 0x1d), 4 to intArrayOf(0x35, 0xbd, 0x04, 0x69), + ) + private val eiT0 = byteTable(0x259ac0) // indexed by b3 + private val eiT1 = byteTable(0x259dc0) // b0 + private val eiT2 = byteTable(0x259cc0) // b1 + private val eiT3 = byteTable(0x259bc0) // b2 + + private fun encryptIngest(ctx: ByteArray, block16: ByteArray): IntArray { + val out = IntArray(4) + for ((k, o) in listOf(0 to 8, 1 to 12, 2 to 0, 3 to 4)) { + val x = beWord(block16, o) xor eiW[o]!! + val c = eiC[o]!! + // ctx byte-table lookup index may exceed 0xff? No: xor of two bytes stays in range. + out[k] = ((ctx[0x21f0 + ((eiT0[byteOf(x, 3)].toInt() and 0xff) xor c[3])].toInt() and 0xff) shl 24) or + (ctx[0x22f0 + ((eiT1[byteOf(x, 0)].toInt() and 0xff) xor c[0])].toInt() and 0xff) or + ((ctx[0x23f0 + ((eiT2[byteOf(x, 1)].toInt() and 0xff) xor c[1])].toInt() and 0xff) shl 8) or + ((ctx[0x20f0 + ((eiT3[byteOf(x, 2)].toInt() and 0xff) xor c[2])].toInt() and 0xff) shl 16) + } + return out + } + + private val encC = const16(0x1a41b0) + private val encRc = listOf( + 0x1a2a10, 0x1a3a30, 0x1a1100, 0x1a0ec0, 0x1a5020, + 0x1a24c0, 0x1a24d0, 0x1a31c0, 0x1a34f0, // last block is "dead" upstream but still XORed in round 0 + ).map { const16(it) } + private val encC4 = const16(0x1a3a40) + private val encOutX = intArrayOf(0x50, 0xac, 0x80, 0x82) + private val encOutStatic = listOf(byteTable(0x2575c0), byteTable(0x2574c0), byteTable(0x2573c0), byteTable(0x2572c0)) + private val encRoundTabs = intArrayOf(0x0f0, 0x4f0, 0x8f0, 0xcf0) + private val encFinalTabs = intArrayOf(0x18f0, 0x1cf0, 0x10f0, 0x14f0) + private val encP = intArrayOf(0, 1, 3, 2) + + /** [ctx] is the 0x28F0-byte session context from [initSession]. */ + fun encrypt(ctx: ByteArray, iv16: ByteArray?, data: ByteArray): ByteArray { + var s: IntArray + if (iv16 != null) { + val iw = encryptIngest(ctx, iv16) + s = IntArray(4) { i -> u32le(encC, 4 * i) xor iw[i] } + } else { + s = IntArray(4) { i -> u32le(encC, 4 * i) } + } + val o = ByteArray(data.size / 16 * 16) + for (b in 0 until data.size / 16) { + val blk = data.copyOfRange(b * 16, b * 16 + 16) + val t = encryptIngest(ctx, blk) + var st = intArrayOf( + s[0] xor t[0] xor u32le(ctx, 8) xor 0x669B24CB, + s[1] xor t[1] xor u32le(ctx, 0xc) xor 0xF257F9B5.toInt(), + s[3] xor t[3] xor u32le(ctx, 4) xor 0x0E340D47, + s[2] xor t[2] xor u32le(ctx, 0) xor 0xC80F1D02.toInt(), + ) + for (r in 0 until 9) { + val xw = words(encRc[r]) + val base = (r + 1) * 4 + val kv = intArrayOf( + u32le(ctx, 4 * (base + ((r + 3) and 3))), + u32le(ctx, 4 * (base + (r and 3))), + u32le(ctx, 4 * (base + ((r + 1) and 3))), + u32le(ctx, 4 * (base + ((r + 2) and 3))), + ) + val new = IntArray(4) + for (i in 0 until 4) { + var acc = xw[i] xor kv[i] + for (k in 0 until 4) { + val srcw = st[encP[(i - k + 4) % 4]] + acc = acc xor u32le(ctx, encRoundTabs[k] + 4 * byteOf(srcw, k)) + } + new[i] = acc + } + st = intArrayOf(new[0], new[1], new[3], new[2]) + } + val g = st + val v = IntArray(4) + for (i in 0 until 4) { + var acc = u32le(ctx, 0xa0 + 4 * i) xor u32le(encC4, 4 * i) + for (k in 0 until 4) { + val srcw = g[encP[(i - k + 4) % 4]] + acc = acc xor u32le(ctx, encFinalTabs[k] + 4 * byteOf(srcw, k)) + } + v[i] = acc + } + val ob = ByteArray(16) + for (j in 0 until 4) { + val w = v[j] + ob[4 * j + 0] = encOutStatic[0][ctx[0x24f0 + byteOf(w, 3)].toInt() and 0xff xor encOutX[0]] + ob[4 * j + 1] = encOutStatic[1][ctx[0x25f0 + byteOf(w, 2)].toInt() and 0xff xor encOutX[1]] + ob[4 * j + 2] = encOutStatic[2][ctx[0x26f0 + byteOf(w, 1)].toInt() and 0xff xor encOutX[2]] + ob[4 * j + 3] = encOutStatic[3][ctx[0x27f0 + byteOf(w, 0)].toInt() and 0xff xor encOutX[3]] + } + ob.copyInto(o, b * 16) + s = intArrayOf( + v[2] xor 0x099B2D2C, v[3] xor 0x0F8E4FCD.toInt(), + v[0] xor 0x58A1D6B2, v[1] xor 0x2EA87554.toInt(), + ) + } + return o + } + + // ---- encsec (0x17fdb50) ----------------------------------------------------------- + + private val esT0 = wordTable(0x267ec0) + private val esT1 = wordTable(0x267ac0) + private val esT2 = wordTable(0x2676c0) + private val esT3 = wordTable(0x2672c0) + private val esF0 = wordTable(0x266ec0) + private val esF1 = wordTable(0x266ac0) + private val esF2 = wordTable(0x2666c0) + private val esF3 = wordTable(0x2662c0) + private val esSb0 = byteTable(0x25aac0) + private val esSb1 = byteTable(0x25abc0) + private val esSb2 = byteTable(0x25adc0) + private val esSb3 = byteTable(0x25acc0) + private val esG0 = byteTable(0x25b1c0) + private val esG1 = byteTable(0x25aec0) + private val esG2 = byteTable(0x25b0c0) + private val esG3 = byteTable(0x25afc0) + private val esRc = listOf( + 0x1a2ee0, 0x1a34c0, 0x1a2ef0, 0x1a2c20, 0x1a4a80, + 0x1a31a0, 0x1a34d0, 0x1a5560, 0x1a4780, + ).map { const16(it) } + private val esCfin = const16(0x1a1be0) + private val esK = intArrayOf(0xb55e5ed8.toInt(), 0x29ed6f36, 0xc6845ce3.toInt(), 0xeb88ed9a.toInt()) + + fun encsec(data32: ByteArray): ByteArray { + var chainC = 0x2DE7A2A5 + var chainD = 0xF081A453.toInt() + var chainA = 0x18BEC8B9 + var chainB = 0xE88A4A73.toInt() + val out = ByteArray(32) + for (blk in 0 until 2) { + val ib = data32.copyOfRange(blk * 16, blk * 16 + 16) + val w = IntArray(4) + for ((k, o) in listOf(0 to 8, 1 to 0xc, 2 to 0, 3 to 4)) { + val x = beWord(ib, o) xor when (o) { + 8 -> 0x1A9BD3B4; 0xc -> 0xCFBDBC9D.toInt(); 0 -> 0x3C690967; else -> 0xE8902ED5.toInt() + } + w[k] = ((esSb3[byteOf(x, 3)].toInt() and 0xff) shl 24) or + ((esSb1[byteOf(x, 1)].toInt() and 0xff) shl 8) or + ((esSb2[byteOf(x, 2)].toInt() and 0xff) shl 16) or + (esSb0[byteOf(x, 0)].toInt() and 0xff) + } + var st = intArrayOf( + w[0] xor chainA xor 0xDD037774.toInt(), + w[1] xor chainB xor 0x8279C0E3.toInt(), + w[2] xor chainC xor 0x4A4BBC3F, + w[3] xor chainD xor 0xFC774B32.toInt(), + ) + for (r in 0 until 9) { + val rcw = words(esRc[r]) + val new = IntArray(4) { i -> + esT0[byteOf(st[i], 0)] xor esT1[byteOf(st[(i - 1 + 4) and 3], 1)] xor + esT2[byteOf(st[(i - 2 + 4) and 3], 2)] xor + esT3[byteOf(st[(i - 3 + 4) and 3], 3)] xor rcw[i] + } + st = new + } + val t = IntArray(4) { i -> + esF0[byteOf(st[i], 0)] xor esF1[byteOf(st[(i - 1 + 4) and 3], 1)] xor + esF2[byteOf(st[(i - 2 + 4) and 3], 2)] xor + esF3[byteOf(st[(i - 3 + 4) and 3], 3)] + } + chainA = t[2] xor 0xD0437EA3.toInt() + chainB = t[3] xor 0xD5E72963.toInt() + chainC = t[0] xor 0x286B9800 + chainD = t[1] xor 0xD55D8B72.toInt() + val v = IntArray(4) { i -> t[i] xor u32le(esCfin, 4 * i) } + for (j in 0 until 4) { + val x = ((esG0[byteOf(v[j], 3)].toInt() and 0xff) shl 24) or + (esG1[byteOf(v[j], 0)].toInt() and 0xff) or + ((esG2[byteOf(v[j], 2)].toInt() and 0xff) shl 16) or + ((esG3[byteOf(v[j], 1)].toInt() and 0xff) shl 8) + putU32le(out, blk * 16 + 4 * j, bswap(x xor esK[j])) + } + } + return out + } + + // ---- spim_map_signature (0x17fe2a0) ------------------------------------------------- + + private val smsM = const16(0x1a16e0) + private val smsC = intArrayOf(0x19B25BBD, 0x9EEA07D0.toInt(), 0x5C67CBDE, 0xD0F30213.toInt()) + private val smsT24 = byteTable(0x25a1c0) + private val smsT16 = byteTable(0x259fc0) + private val smsT8 = byteTable(0x259ec0) + private val smsT0 = byteTable(0x25a0c0) + private val smsN = const16(0x1a5810) + private val smsHs = listOf(wordTable(0x264ec0), wordTable(0x264ac0), wordTable(0x2646c0), wordTable(0x2642c0)) + private val smsK = listOf( + 0x1a16f0, 0x1a5b30, 0x1a52a0, 0x1a34e0, 0x1a5570, + 0x1a1f60, 0x1a2c30, 0x1a4790, 0x1a5820, + ).map { const16(it) } + private val smsMixt = listOf(wordTable(0x265ec0), wordTable(0x265ac0), wordTable(0x2656c0), wordTable(0x2652c0)) + private val smsCfin2 = const16(0x1a31b0) + private val smsFt = listOf(byteTable(0x25a2c0), byteTable(0x25a3c0), byteTable(0x25a4c0), byteTable(0x25a5c0)) + private val smsF = intArrayOf(0xE4DF5F73.toInt(), 0x1472A937, 0x6BF137C7, 0x3B7AB732) + + fun spimMapSignature(block16: ByteArray): ByteArray { + val w0 = words(block16) + val w = IntArray(4) { j -> bswap(w0[j] xor u32le(smsM, 4 * j)) xor smsC[j] } + val p = intArrayOf(2, 3, 0, 1) + var st = IntArray(4) { l -> + val s = w[p[l]] + ((smsT24[byteOf(s, 3)].toInt() and 0xff) shl 24) or + ((smsT16[byteOf(s, 2)].toInt() and 0xff) shl 16) or + ((smsT8[byteOf(s, 1)].toInt() and 0xff) shl 8) or + (smsT0[byteOf(s, 0)].toInt() and 0xff) xor u32le(smsN, 4 * l) + } + for (r in 0 until 9) { + val kw = words(smsK[r]) + val new = IntArray(4) { j -> + smsHs[0][byteOf(st[j], 0)] xor smsHs[1][byteOf(st[(j + 1) and 3], 1)] xor + smsHs[2][byteOf(st[(j + 2) and 3], 2)] xor + smsHs[3][byteOf(st[(j + 3) and 3], 3)] xor kw[j] + } + st = new + } + val vv = IntArray(4) { i -> + var acc = u32le(smsCfin2, 4 * i) + for (k in 0 until 4) acc = acc xor smsMixt[k][byteOf(st[(i + k) and 3], k)] + acc + } + val out = ByteArray(16) + for (j in 0 until 4) { + val wj = vv[j] + val x = ((smsFt[3][byteOf(wj, 3)].toInt() and 0xff) shl 24) or + ((smsFt[2][byteOf(wj, 2)].toInt() and 0xff) shl 16) or + ((smsFt[1][byteOf(wj, 1)].toInt() and 0xff) shl 8) or + (smsFt[0][byteOf(wj, 0)].toInt() and 0xff) + putU32le(out, 4 * j, bswap(x xor smsF[j])) + } + return out + } + + // ---- init_session (0x17fcbe0) --------------------------------------------------------- + + // Layout: decodeSpim writes 240 bytes at ctx+0x00; phase 1 consumes dec[0xb0:0xf0] + // into buf1 (stack); phase 2 expands buf1 into the 8 byte-tables ctx[0x20f0..0x28f0]; + // phase 3 fills the u32 tables ctx[0x0f0..0x20f0] via spim_map. sessionKey = ctx[0:16]. + + private val isKa = const16(0x1a4770) + const16(0x1a24b0) + const16(0x1a3780) + const16(0x1a4420) + private val isKb = const16(0x1a34b0) + const16(0x1a0eb0) + const16(0x1a5800) + const16(0x1a0bd0) + private val isSbox = listOf(byteTable(0x25a7c0), byteTable(0x25a9c0), byteTable(0x25a8c0), byteTable(0x25a6c0)) + private val isSig = intArrayOf( + 22, 62, 13, 59, 48, 25, 6, 8, 29, 23, 4, 12, 7, 47, 37, 38, 63, 49, 27, 18, 34, 31, + 32, 42, 39, 16, 46, 1, 55, 30, 33, 26, 5, 28, 57, 24, 17, 54, 53, 43, 35, 56, 58, 15, + 3, 51, 0, 19, 36, 60, 21, 11, 50, 40, 45, 20, 41, 44, 2, 9, 10, 14, 52, 61, + ) + private val isS8 = byteTable(0x2598c0) + private val isS9 = byteTable(0x2599c0) + private val isSa = byteTable(0x2596c0) + private val isSb = byteTable(0x2597c0) + + private fun isPhase1(dec: ByteArray): ByteArray { + val buf1 = ByteArray(64) + for (j in 0 until 64) { + buf1[j] = ((isKb[j].toInt() and 0xff) xor + (isSbox[j and 3][(dec[0xb0 + j].toInt() and 0xff) xor (isKa[j].toInt() and 0xff)].toInt() and 0xff)).toByte() + } + return buf1 + } + + /** fold high-low byte fold (asm: shr bx,8; xor bl). */ + private fun hb(x: Int): Int = (x xor (x ushr 8)) and 0xFF + + private val p3ArgTables = intArrayOf(0x2592c0, 0x258ec0, 0x258ac0, 0x2586c0, 0x2582c0, 0x257ec0, 0x257ac0, 0x2576c0) + + /** (arg xor, out base, idx table offset, idx xor, out xor) per phase-3 write; arg table is p3ArgTables[k]. */ + private val p3Cfg = listOf( + P3Slot(0xcd, 0x00f0, 0x22f0, 0x21, 0x3483c86d), + P3Slot(0x26, 0x04f0, 0x23f0, 0x8f, 0x82902656.toInt()), + P3Slot(0x91, 0x08f0, 0x20f0, 0x52, 0xf2b7a9e0.toInt()), + P3Slot(0x8a, 0x0cf0, 0x21f0, 0x48, 0x7160fbad), + P3Slot(0xfa, 0x10f0, 0x20f0, 0x52, 0x45f49eb1), + P3Slot(0x90, 0x14f0, 0x21f0, 0x48, 0x3bd92f65), + P3Slot(0xe0, 0x18f0, 0x22f0, 0x21, 0x0fddc438), + P3Slot(0x96, 0x1cf0, 0x23f0, 0x8f, 0x4df60cb6), + ) + + private class P3Slot(val argXor: Int, val outBase: Int, val idxTab: Int, val idxXor: Int, val outXor: Int) + + private val p3Arg0 = 0xb17f8dc5.toInt() // peeled first-iteration arg (== T2592c0[0xcd]) + + /** spim_map (0x17fc600): byte-table gather, OR-combined (bits 24-31 may OR two bytes). */ + private fun spimMap(ctx: ByteArray, x: Int): Int = + ((ctx[0x23f0 + byteOf(x, 1)].toInt() and 0xff) shl 8) or + (ctx[0x22f0 + byteOf(x, 0)].toInt() and 0xff) or + ((ctx[0x20f0 + byteOf(x, 2)].toInt() and 0xff) shl 16) or + ((ctx[0x21f0 + byteOf(x, 3)].toInt() and 0xff) shl 24) + + fun initSession(spim240: ByteArray): ByteArray { + val ctx = ByteArray(0x28F0) + val dec = decodeSpim(spim240) + dec.copyInto(ctx, 0) + + // phase 1 + val buf1 = isPhase1(dec) + + // phase 2: expand buf1 into the eight ctx byte-tables + val cw = IntArray(64) { buf1[isSig[it]].toInt() and 0xff } + val b20f0 = ByteArray(256); val b21f0 = ByteArray(256) + val b22f0 = ByteArray(256); val b23f0 = ByteArray(256) + val b24f0 = ByteArray(256); val b25f0 = ByteArray(256) + val b26f0 = ByteArray(256); val b27f0 = ByteArray(256) + for (a in 0 until 256) { + fun foldN(base: Int): Int { + var f = 0 + for (k in 0 until 8) f = f xor (cw[base + k] * (a and (1 shl k))) + return f and 0xFFFF + } + fun fold1(): Int { // odd word/bit map, only fold1 has it + var f = 0 + val pairs = listOf(6 to 0, 0 to 1, 1 to 2, 2 to 3, 3 to 4, 4 to 5, 5 to 6, 7 to 7) + for ((w, b) in pairs) f = f xor (cw[w] * (a and (1 shl b))) + return f and 0xFFFF + } + val f1 = fold1() + val f2 = foldN(8) + val f3 = foldN(16) + val f4 = foldN(24) + val f5 = foldN(40) + val f6 = foldN(32) + val f7 = foldN(48) + val f8 = foldN(56) + val s8 = isS8[(hb(f1) xor 0xcb)].toInt() and 0xff + val s9 = isS9[(hb(f2) xor 0xe9)].toInt() and 0xff + val sa = isSa[(hb(f3) xor 0x27)].toInt() and 0xff + val sb = isSb[(hb(f4) xor 0x90)].toInt() and 0xff + val sc = isS8[(a xor 0xdf)].toInt() and 0xff + val sd = isS9[(a xor 0xa1)].toInt() and 0xff + val se = isSa[(a xor 0x14)].toInt() and 0xff + val sf = isSb[(a xor 0x08)].toInt() and 0xff + b22f0[a] = (s8 xor 0x1c).toByte() + b20f0[a] = (sa xor 0xb8).toByte() + b23f0[a] = (s9 xor 0xf1).toByte() + b21f0[a] = (sb xor 0x1e).toByte() + b27f0[(sc xor 0x08) and 0xFF] = hb(f8).toByte() + b26f0[(sd xor 0x4b) and 0xFF] = hb(f7).toByte() + b25f0[(se xor 0x43) and 0xFF] = (hb(f6) xor 0x12).toByte() + b24f0[(sf xor 0x20) and 0xFF] = hb(f5).toByte() + } + b20f0.copyInto(ctx, 0x20f0); b21f0.copyInto(ctx, 0x21f0) + b22f0.copyInto(ctx, 0x22f0); b23f0.copyInto(ctx, 0x23f0) + b24f0.copyInto(ctx, 0x24f0); b25f0.copyInto(ctx, 0x25f0) + b26f0.copyInto(ctx, 0x26f0); b27f0.copyInto(ctx, 0x27f0) + + // phase 3: fill the u32 tables ctx[0x0f0..0x20f0] via spim_map + val idxTabs = mapOf(0x20f0 to b20f0, 0x21f0 to b21f0, 0x22f0 to b22f0, 0x23f0 to b23f0) + p3Cfg.forEachIndexed { k, slot -> + val args = wordTable(p3ArgTables[k]) + val idxTab = idxTabs[slot.idxTab]!! + for (i in 0 until 256) { + val x = if (i == 0 && k == 0) p3Arg0 + else args[(i xor slot.argXor) and 0xff] + val v = spimMap(ctx, x) xor slot.outXor + if (v != 0) { + // the binary skips zero stores, so a later 0 must not clobber an earlier value + val off = slot.outBase + 4 * ((idxTab[i].toInt() and 0xff) xor slot.idxXor) + putU32le(ctx, off, v) + } + } + } + return ctx + } + + /** The 16-byte session key is the head of the context (== dec[0:16]). */ + fun sessionKey(ctx: ByteArray): ByteArray = ctx.copyOfRange(0, 16) + + // ---- decryptPTM (0x17ffb50) ----------------------------------------------- + // decryptPTM(key16, data, count, seed16, out): per 16-byte block out_i, the chain + // advances like docrypt's io; the initial chain is primed from seed16. + + // Initial key-mix head: key words are byte-swapped, xored with per-word constants and + // run through byte tables; lanes consume D words in order [2,1,0,3]. + private val imC = intArrayOf(0xc92bcef6.toInt(), 0xb3c05bdc.toInt(), 0x7848e9ec, 0xd1e6f246.toInt()) + private val imTa = byteTable(0x25fbc0) // b1, <<8 + private val imTb = byteTable(0x25fdc0) // b2, <<16 + private val imTc = byteTable(0x25fac0) // b3, <<24 + private val imTd = byteTable(0x25fcc0) // b0 + private val imC16 = const16(0x1a5830) + + private fun initMix(key16: ByteArray): IntArray { + val kw = words(key16) + val d = IntArray(4) { j -> bswap(kw[j]) xor imC[j] } + return IntArray(4) { j -> + val x = d[(2 - j) and 3] + val v = (imTd[byteOf(x, 0)].toInt() and 0xff) or + ((imTa[byteOf(x, 1)].toInt() and 0xff) shl 8) or + ((imTb[byteOf(x, 2)].toInt() and 0xff) shl 16) or + ((imTc[byteOf(x, 3)].toInt() and 0xff) shl 24) + v xor u32le(imC16, 4 * j) + } + } + + // Phase A: 9 rounds with per-round 16-byte round constants. + private val paT0 = wordTable(0x260ac0) // b0(S_i) + private val paT1 = wordTable(0x25fec0) // b1(S_i+1) + private val paT2 = wordTable(0x2602c0) // b2(S_i+2) + private val paT3 = wordTable(0x2606c0) // b3(S_i-1) + private val paRc = listOf( + 0x1a1c00, 0x1a2c40, 0x1a1f80, 0x1a2230, 0x1a13d0, 0x1a2790, 0x1a1110, 0x1a5b50, 0x1a13e0, + ).map { const16(it) } + + private fun phaseA(s0: IntArray): IntArray { + var s = s0 + for (r in 0 until 9) { + val rcw = words(paRc[r]) + s = IntArray(4) { i -> + paT0[byteOf(s[i], 0)] xor paT1[byteOf(s[(i + 1) and 3], 1)] xor + paT2[byteOf(s[(i + 2) and 3], 2)] xor paT3[byteOf(s[(i + 3) and 3], 3)] xor rcw[i] + } + } + return s + } + + // 4.3: word layer -> byte S-box layers (output-side K1C xor, no consts on layer 2) -> const xor. + private val f43T0 = wordTable(0x25dac0) + private val f43T1 = wordTable(0x25dec0) + private val f43T2 = wordTable(0x25e2c0) + private val f43T3 = wordTable(0x25e6c0) + private val f43C1 = const16(0x1a19b0) + private val f43S1 = listOf(byteTable(0x25d6c0), byteTable(0x25d7c0), byteTable(0x25d8c0), byteTable(0x25d9c0)) + private val f43S2 = listOf(byteTable(0x25d2c0), byteTable(0x25d3c0), byteTable(0x25d4c0), byteTable(0x25d5c0)) + private val f43K1C = byteArrayOf( + 0x66, 0x98.toByte(), 0x1c, 0x7f, 0x7c, 0xb7.toByte(), 0x8f.toByte(), 0x6b, + 0xad.toByte(), 0xe1.toByte(), 0xc0.toByte(), 0x29, 0x00, 0x4f, 0xc3.toByte(), 0x70, + ) + private val f43C2 = const16(0x1a3e90) + + private fun stage43(dw: IntArray): IntArray { + val e = IntArray(4) { j -> + f43T0[byteOf(dw[j], 0)] xor f43T1[byteOf(dw[(j + 1) and 3], 1)] xor + f43T2[byteOf(dw[(j + 2) and 3], 2)] xor f43T3[byteOf(dw[(j + 3) and 3], 3)] xor + u32le(f43C1, 4 * j) + } + val eb = fromWords(e) + val l1 = ByteArray(16) { q -> + (((f43S1[q and 3][eb[q].toInt() and 0xff].toInt() and 0xff) xor f43K1C[q].toInt()) and 0xff).toByte() + } + val sb = ByteArray(16) { q -> (f43S2[q and 3][l1[q].toInt() and 0xff].toInt() xor f43C2[q].toInt()).toByte() } + return words(sb) + } + + // Key schedule: 10 round words, each derived from the state words and prior keys. + // 0x1a6aa0 / 0x1a7548 are outside consts.bin -> hardcoded. + private val ksB = words(const16(0x1a3790)) + words(const16(0x1a3210)) + + intArrayOf(0x80237707.toInt(), 0x89f00877.toInt()) + private val ksW = words(const16(0x1a47a0)) + words(const16(0x1a52b0)) + + intArrayOf(0x4d62ea33, 0x03363763) + private val ksTb0 = wordTable(0x25cac0) + private val ksTb1 = wordTable(0x25c2c0) + private val ksTb2 = wordTable(0x25cec0) + private val ksTb3 = wordTable(0x25c6c0) + + private fun keySchedule(d: IntArray): IntArray { + val keys = IntArray(10) + var acc = d[0] + for (r in 0 until 10) { + var eax = ksB[r] xor d[1] + if (r and 1 == 1) eax = eax xor d[2] + if (((r - 1) and 3) <= 1) eax = eax xor d[3] + for (k in 1..6) { + if (r >= k && ((r - k) and 3) <= 1) eax = eax xor keys[k - 1] + } + if (r >= 7 && ((r - 7) and 3) != 2) eax = eax xor keys[6] + if (r >= 8) eax = eax xor keys[7] + if (r == 9) eax = eax xor keys[8] + val mix = ksTb0[byteOf(eax, 0)] xor ksTb3[byteOf(eax, 3)] xor ksW[r] xor + ksTb2[byteOf(eax, 2)] xor ksTb1[byteOf(eax, 1)] + acc = acc xor mix + keys[r] = acc + } + return keys + } + + // K0: fold composites over the round words. 0x1a6a10 outside consts.bin -> hardcoded tail. + private val k0Const = words(const16(0x1a4ce0)) + words(const16(0x1a47b0)) + + intArrayOf(0x600672ac, 0x77d810cd) + private val k0F = listOf( + listOf(1, 2, 3), listOf(2, 3), listOf(3), listOf(), + listOf(4), listOf(4, 5), listOf(4, 5, 6), listOf(), listOf(8), listOf(8, 9), + ) + + private fun deriveK0(keys: IntArray, d: IntArray): IntArray { + val foldA = keys[0] xor keys[1] xor keys[2] xor keys[3] + val foldB = foldA xor keys[4] xor keys[5] xor keys[6] xor keys[7] + return IntArray(10) { i -> + var x = (if (i >= 7) foldB else foldA) xor d[3] xor k0Const[i] + for (j in k0F[i]) x = x xor keys[j] + x + } + } + + // K0' is pure constant material (0x1a7120 outside consts.bin -> hardcoded tail). + private val k0p = words(const16(0x1a13f0)) + words(const16(0x1a1120)) + + intArrayOf(0xbba29590.toInt(), 0xe3ab739f.toInt()) + + // K1: pre_a/pre_b composites + per-block constants; K1[8]/K1[9] extend pre_b with + // keys[8]/keys[9] and dedicated constants. + private val k1Ca = const16(0x1a52c0) + private val k1Cb = const16(0x1a47c0) + + private fun deriveK1(keys: IntArray, d: IntArray): IntArray { + val k = keys + val d2 = d[2] + val d3 = d[3] + val preA = intArrayOf(k[0] xor d2 xor d3, k[1] xor d2, k[0] xor k[2] xor d2 xor d3, k[1] xor k[3] xor d2) + val preB = intArrayOf( + k[0] xor k[2] xor k[4] xor d2 xor d3, k[1] xor k[3] xor k[5] xor d2, + k[0] xor k[2] xor k[4] xor k[6] xor d2 xor d3, k[1] xor k[3] xor k[5] xor k[7] xor d2, + ) + val out = IntArray(10) + for (i in 0 until 4) out[i] = preA[i] xor u32le(k1Ca, 4 * i) + for (i in 0 until 4) out[4 + i] = preB[i] xor u32le(k1Cb, 4 * i) + out[8] = (k[0] xor k[2] xor k[4] xor k[6] xor k[8] xor d2 xor d3) xor 0x98564777.toInt() + out[9] = (k[1] xor k[3] xor k[5] xor k[7] xor k[9] xor d2) xor 0xb1e6e0bc.toInt() + return out + } + + // K2: chained fold of the round words over K0'. + private fun deriveK2(keys: IntArray, d: IntArray): IntArray { + val dpart = intArrayOf(d[1] xor d[2] xor d[3], d[1] xor d[3], d[1] xor d[2], d[1]) + return IntArray(10) { i -> + var chain = dpart[i and 3] + for (kk in 0..i) { + if (((i - kk) and 3) <= 1) chain = chain xor keys[kk] + } + chain xor k0p[i] + } + } + + // K3: round words + per-range constants (0x1a7378 outside consts.bin -> hardcoded tail). + private val k3Ca = const16(0x1a5840) + private val k3Cb = const16(0x1a2f00) + + private fun deriveK3(keys: IntArray): IntArray = IntArray(10) { i -> + when { + i < 4 -> keys[i] xor u32le(k3Ca, 4 * i) + i < 8 -> keys[i] xor u32le(k3Cb, 4 * (i - 4)) + i == 8 -> keys[8] xor 0x8f438ee4.toInt() + else -> keys[9] xor 0x1d1474bf + } + } + + // K4: outgen of the state words + per-word constant. + private val k4C = const16(0x1a1c10) + + private fun deriveK4(d: IntArray): IntArray = IntArray(4) { i -> outgen(d[i] xor u32le(k4C, 4 * i)) } + + private fun keyBuf(kd: IntArray): ByteArray = ByteArray(0x30).also { b -> + for (i in 0 until 10) putU32le(b, 4 * i, kd[i]) + } + + /** decryptPTM (0x17ffb50): docrypt-chain over [data] in 16-byte blocks; [key16] and + * [seed16] are 16 bytes. Returns count*16 bytes. */ + fun decryptPtm(key16: ByteArray, data: ByteArray, seed16: ByteArray): ByteArray { + require(key16.size == 16 && seed16.size == 16 && data.size % 16 == 0 && data.isNotEmpty()) + val d = stage43(phaseA(initMix(key16))) + val keys = keySchedule(d) + val kbufs = listOf( + keyBuf(deriveK0(keys, d)), keyBuf(deriveK1(keys, d)), + keyBuf(deriveK2(keys, d)), keyBuf(deriveK3(keys)), fromWords(deriveK4(d)), + ) + val t = ingest(seed16) + var io = intArrayOf( + t[2] xor u32le(docC1, 8), t[3] xor u32le(docC1, 12), + t[0] xor u32le(docC1, 0), t[1] xor u32le(docC1, 4), + ) + val out = ByteArray(data.size) + for (off in data.indices step 16) { + val (o, next) = docrypt(data.copyOfRange(off, off + 16), kbufs, io) + for (i in 0 until 4) putU32le(out, off + 4 * i, o[i]) + io = next + } + return out + } +} diff --git a/registration/src/main/kotlin/dev/fenn/imessage/registration/ClearAdiTables.kt b/registration/src/main/kotlin/dev/fenn/imessage/registration/ClearAdiTables.kt new file mode 100644 index 0000000..73dae2a --- /dev/null +++ b/registration/src/main/kotlin/dev/fenn/imessage/registration/ClearAdiTables.kt @@ -0,0 +1,68 @@ +package dev.fenn.imessage.registration + +/** + * Static .rodata tables of the ClearADI white-box (librust_lib_bluebubbles), embedded as + * base64 source in [ClearAdiTablesData] (no Apple-derived binary ships in the repo) and + * decoded once at first use. vaddr V maps to offset V - [TABLES_BASE] in the tables image; + * consts likewise with [CONSTS_BASE]. Word tables are stored little-endian (the x86 memory + * image). + */ +internal object ClearAdiTables { + private const val TABLES_BASE = 0x24DCC0 + private const val CONSTS_BASE = 0x1A0800 + + private val tablesBin: ByteArray by lazy { decode(ClearAdiTablesData.tablesChunks) } + private val constsBin: ByteArray by lazy { decode(ClearAdiTablesData.constsChunks) } + private val wordTableCache = HashMap() + + private fun decode(chunks: List): ByteArray = + java.util.Base64.getMimeDecoder().decode(chunks.joinToString("")) + + /** 256-entry u32 table at .rodata [vaddr], read little-endian. */ + fun wordTable(vaddr: Int): IntArray = wordTableCache.getOrPut(vaddr) { + val off = vaddr - TABLES_BASE + IntArray(256) { i -> + val p = off + 4 * i + (tablesBin[p].toInt() and 0xff) or + ((tablesBin[p + 1].toInt() and 0xff) shl 8) or + ((tablesBin[p + 2].toInt() and 0xff) shl 16) or + ((tablesBin[p + 3].toInt() and 0xff) shl 24) + } + } + + /** n-entry u32 table (the gensource mixtables are 64 entries). */ + fun wordTable(vaddr: Int, count: Int): IntArray { + val off = vaddr - TABLES_BASE + return IntArray(count) { i -> + val p = off + 4 * i + (tablesBin[p].toInt() and 0xff) or + ((tablesBin[p + 1].toInt() and 0xff) shl 8) or + ((tablesBin[p + 2].toInt() and 0xff) shl 16) or + ((tablesBin[p + 3].toInt() and 0xff) shl 24) + } + } + + /** 256-byte table at .rodata [vaddr]. */ + fun byteTable(vaddr: Int): ByteArray { + val off = vaddr - TABLES_BASE + return tablesBin.copyOfRange(off, off + 256) + } + + /** 16-byte constant block from consts.bin. */ + fun consts16(vaddr: Int): ByteArray { + val off = vaddr - CONSTS_BASE + return constsBin.copyOfRange(off, off + 16) + } + + /** The 0xC00 qword-index blob at the start of tables.bin (.rodata 0x24dcc0). */ + fun blob(): ByteArray = tablesBin.copyOfRange(0, 0xC00) + + /** n raw bytes at .rodata [vaddr] (tables.bin image). */ + fun raw(vaddr: Int, n: Int): ByteArray { + val off = vaddr - TABLES_BASE + return tablesBin.copyOfRange(off, off + n) + } + + /** The 0x600 qword-index blob at .rodata 0x2682c0 (gen_otp_ios VM program). */ + fun vmBlob(): ByteArray = raw(0x2682c0, 0x600) +} diff --git a/registration/src/main/kotlin/dev/fenn/imessage/registration/ClearAdiTablesData.kt b/registration/src/main/kotlin/dev/fenn/imessage/registration/ClearAdiTablesData.kt new file mode 100644 index 0000000..deb6bde --- /dev/null +++ b/registration/src/main/kotlin/dev/fenn/imessage/registration/ClearAdiTablesData.kt @@ -0,0 +1,25 @@ +package dev.fenn.imessage.registration + +/** + * GENERATED FILE — regenerate with the extraction script in WORKLOG session 19e; do not hand-edit. + * The ClearADI white-box .rodata tables, embedded as base64 source so no Apple-derived binary + * ships in the repo: tables = .rodata 0x24dcc0..0x26f6e0 (137,760 B), consts = 0x1a0800..0x1a5e00 + * (22,016 B). [ClearAdiTables] decodes these once at first use; dev copies of the raw bins live in + * registration/dev/clearadi/ (gitignored) for byte-level cross-checks. + */ +internal object ClearAdiTablesData { + /** tables, base64, 7 chunk(s) — concatenate in order. */ + val tablesChunks: List = listOf( + "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tyRS6rckUk23JFIEtyRS5bckUkq3JFLntyRS/rckUtm3JFK1tyRSWbckUnS3JFKhtyRSS7ckUoe3JFIFtyRSJbckUv+3JFIYtyRS+rckUmS3JFJltyRS17ckUgu3JFJGtyRSDLckUpq3JFL9tyRSHrckUme3JFLztyRSULckUsW3JFLxtyRSBrckUt+3JFKltyRSOrckUr23JFKutyRSM7ckUnC3JFIptyRSFbckUvC3JFJ4tyRSPLckUhS3JFJctyRSN7ckUua3JFKQtyRSILckUkS3JFK0tyRSQLckUju3JFIZtyRS1rckUsO3JFIXtyRS97ckUqq3JFJttyRSt7ckUs23JFKJtyRSVLckUnq3JFKUtyRS27ckUqa3JFL1tyRSQbckUlq3JFI1tyRS3bckUmq3JFKjtyRSYbckUl+3JFJItyRSArckUi63JFLytyRSA7ckUu63JFKctyRSp7ckUoO3JFIhtyRSzLckUum3JFLttyRS9LckUqy3JFIjtyRSCLckUry3JFJ1tyRS0LckUk63JFLRtyRSkbckUsG3JFIJtyRS9rckUqm3JFIctyRS+LckUpm3JFKWtyRShbckUne3JFJXtyRSqLckUrO3JFL7tyRS3rckUtW3JFJutyRSq7ckUna3JFLTtyRSbLckUsq3JFLktyRSYLckUg+3JFLPtyRSJLckUuK3JFKdtyRSorckUhK3JFLotyRSb7ckUuG3JFKXtyRSzrckUq23JFKbtyRSLbckUh23JFI+tyRSMrckUiq3JFJRtyRSG7ckUsi3JFK6tyRScbckUmu3JFLGtyRSALckUmO3JFJetyRStrckUrC3JFKgtyRSAbckUii3JFKxtyRSZrckUsC3JFK+tyRSTLckUji3JFKGtyRSe7ckUkK3JFL8tyRST7ckUh+3JFJ5tyRSELckUlO3JFKktyRSgLckUrK3JFLCtyRSx7ckUgq3JFKetyRSNrckUjC3JFJ+tyRSxLckUkm3JFJYtyRSVrckUo63JFI5tyRSDrckUmK3JFKBtyRS67ckUtogLKo9B37FoDB2lKsFAPWLTtX+RH5EQXIsddh4FyT7Nq0NGZC+2eC5dgoatYWIw/fb4Ci4Bo4yNHf67SF53a9PMYZjP0abpYPvZr4Moypb/rEOVUPWSa1pqpT3rTIIpID4pW6nwYp9wt/3ATqLr4GZ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IRsZVEQbGVRgGxlUDxsZVGQbGVRGGxlUTRsZVJAbGVRoGxlUchsZVCIbGVSNGxlUVxsZVCAbGVRnGxlUaRsZVMQbGVS9GxlUcRsZVP0bGVQKGxlUKhsZVCcbGVRuGxlUqBsZVNobGVRsGxlUHBsZVNEbGVT1GxlUyxsZVFQbGVQxGxlUzBsZVMAbGVTKGxlU8hsZVDcbGVRiGxlU+hsZVLobGVQmGxlUSRsZVOEbGVTTGxlUZhsZVOUbGVTfGxlUGxsZVNIbGVRqGxlU7hsZVDwbGVS2GxlUWxsZVKwbGVQHGxlUdBsZVCwbGVQIGxlULxsZVIgbGVQdGxlUPxsZVJ8bGVR8GxlUKBsZVPMbGVRPGxlU9xsZVEIbGVQWGxlUzhsZVK4bGVRSGxlUmBsZVNwbGVTCGxlUrxsZVJsbGVQlGxlUpxsZVEwbGVR9GxlUtxsZVFYbGVSUGxlUSBsZVLMbGVTBGxlUFBsZVDgbGVTnGxlUphsZVEEbGVRFGxlUWRsZVO8bGVSLGxlUMBsZVHMbGVRjGxlUzRsZVMgbGVTWGxlUqxsZVLIbGVRLGxlUUBsZVDYbGVSFGxlUnBsZVIwbGVStGxlUxxsZVLwbGVRrGxlUZRsZVDIbGVQEGxlUAhsZVA4bGVSTGxlUehsZVAEbGVRRGxlUjxsZVHkbGVTjGxlUWBsZVN4bGVSZGxlUXxsZVMYbGVRhGxlUpBsZVJUbGVT4GxlU2xsZVIkbGVSBGxlUXhsZVC0bGVQAGxlUihsZVCQbGVSeGxlU6BsZVAsbGVSdGxlUqRsZVC4bGVSlGxlU5BsZVCsbGVTZGxlUXBsZVM8bGVQfGxlU7BsZVBUbGVTrGxlUGhsZVL8bGVRdGxlUvhsZVEMbGVSAGxlUKRsZVEAbGVQMGxlURxsZVDUbGVSHGxlUghsZVBkbGVS4GxlU8RsZVFMbGVTdGxlUfhsZVAYbGVQ7GxlUexsZVLsbGVTpGxlU0BsZVD0bGVT2GxlUufnxtbm88bW5WPG1uUXxtbkE8bW5K/G1uaTxtblO8bW5zPG1uZHxtbld8bW54vG1ucLxtbmX8bW5afG1uSTxtbkj8bW5RPG1uY3xtbnU8bW5DfG1uejxtbk48bW5PvG1uZnxtbly8bW5gPG1uaXxtbki8bW5nPG1ufrxtbk/8bW5lPG1uTTxtbnL8bW5KvG1ufDxtbl68bW5OfG1uVTxtblb8bW5v/G1uavxtbnc8bW5KfG1uYLxtbnm8bW59vG1uUvxtbkX8bW5L/G1uTbxtbmO8bW55/G1uZbxtbmv8bW5ufG1uUHxtbnF8bW5YvG1uRPxtbkx8bW5CPG1uabxtblK8bW5BvG1uVfxtbmJ8bW59/G1uWrxtbmh8bW5rPG1uWDxtbkg8bW5LfG1uWbxtbm98bW5QvG1uQrxtbku8bW5R/G1uSbxtbmD8bW55fG1ucPxtblf8bW5ffG1udvxtbn/8bW5f/G1ubvxtbmt8bW5qPG1ucDxtbnP8bW5uvG1uXzxtbln8bW5h/G1ubbxtblh8bW5VvG1uQDxtbm18bW5bPG1uYXxtblk8bW5M/G1uXDxtblo8bW5GPG1uTLxtblr8bW5UfG1uU/xtbkQ8bW5xvG1uRXxtbmV8bW5m/G1uYvxtbk38bW5VfG1uaPxtbk68bW5JfG1uQzxtbn88bW5e/G1ud/xtbl+8bW51vG1uXfxtbmg8bW5GfG1uezxtbmP8bW5H/G1ud7xtblN8bW5RvG1udjxtbmd8bW5J/G1uRTxtbkW8bW54PG1uWPxtbnI8bW5s/G1uVDxtbk18bW58vG1uW3xtbm48bW5C/G1ubfxtbl28bW5nvG1uaLxtbn78bW5XvG1uerxtbkH8bW5EvG1uQPxtbm+8bW5xPG1uYrxtbmw8bW58fG1uXXxtbnz8bW50/G1ueTxtbma8bW59fG1uZ/xtbla8bW50fG1uTvxtbm08bW5HPG1ueHxtbko8bW5bvG1uUjxtblv8bW5CfG1ucHxtbn08bW5hPG1ud3xtbkB8bW5LPG1uTDxtbnX8bW5yfG1uePxtbl58bW5sfG1udLxtbmB8bW5+PG1uQ/xtbnN8bW5svG1uUDxtbmT8bW50PG1ucfxtbkd8bW56/G1uRrxtbmS8bW5BfG1uc7xtbn+8bW5G/G1uVPxtblD8bW5SfG1udnxtblz8bW5AvG1uRHxtbl08bW5mPG1uZDxtbna8bW5ZfG1uYbxtbmM8bW5ePG1uf3xtbmn8bW5WfG1uarxtbnK8bW5iPG1ue7xtblM8bW5cfG1uVzxtbk98bW5qfG1uVLxtbk88bW5rvG1ue/xtbnV8bW5DvG1uSHxtbke8bW57fG1uenxtS7uTRou7k3zLu5N+y7uTZsu7k0K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N8qjnFbKo5xqyqOca8qjnBvKo5yyyqOcY8qjnBfKo5xXyqOcI8qjnKLKo5xkyqOcuMqjnPfKo5w2yqOc+sqjnFXKo5zRyqOcQ8qjnC3Ko5yryqOc7cqjnF7Ko5wsyqOclsqjnKfKo5yqyqOcgMqjnCbKo5ygyqOchsqjnA3Ko5zgyqOcucqjnNvKo5ytyqOcL8qjnKzKo5wdyqOck8qjnFjKo5zAyqOcB8qjnOvKo5yEyqOcWcqjnDrKo5zSyqOcccqjnHzKo5xiyqOcHMqjnFLKo5zWyqOcxMqjnIzKo5zNyqOch8qjnE/Ko5zmyqOcKMqjnPPKo5wayqOc+cqjnGDKo5x0yqOcXcqjnLvKo5yNyqOccsqjnIvKo5xwyqOcg8qjnEHKo5xCyqOc3sqjnFPKo5wIyqOcAsqjnJzKo5wuyqOc6cqjnEnKo5zDyqOc18qjnADKo5wEyqOcIcqjnArKo5xuyqOcbMqjnI7Ko5xzyqOcqMqjnKPKo5y/yqOctsqjnIrKo5yVyqOcscqjnL3Ko5wwyqOcrsqjnMfKo5wZyqOcPcqjnOjKo5yRyqOc2sqjnJfKo5wLyqOc38qjnMbKo5x7yqOczMqjnJLKo5x5yqOcxcqjnNDKo5yayqOcusqjnEbKo5xayqOcRcqjnIHKo5zUyqOcMsqjnEfKo5ypyqOct8qjnPDKo5zjyqOcNMqjnOTKo5zZyqOcA8qjnLzKo5wRyqOceMqjnCLKo5xhyqOcesqjnH3Ko5xMyqOc3MqjnFHKo5wPyqOcUMqjnPTKo5znyqOcwsqjnBTKo5ybyqOcf8qjnGnKo5zlyqOcTcqjnLbsIJm24yCZtg8gmbY+IJm2EiCZtmsgmbYDIJm20CCZthogmba/IJm2lCCZti8gmbY7IJm28SCZtrEgmbamIJm2tCCZtpkgmbYGIJm2jCCZtiIgmba+IJm2JCCZtpwgmbbzIJm2/SCZtscgmbaSIJm2ICCZtuEgmbb4IJm2MyCZttogmbZ9IJm2USCZtt8gmbYxIJm2biCZtjYgmba3IJm23SCZtpYgmbZCIJm2ZyCZtpsgmbbmIJm2yCCZtmIgmba8IJm2pSCZtjQgmbZ0IJm2ciCZtikgmbb0IJm2bCCZtlYgmbYOIJm2fiCZtqMgmbZmIJm2/yCZtusgmbbbIJm2uCCZtrUgmbaBIJm2XiCZtk4gmbakIJm2JSCZtiMgmbY9IJm2giCZttIgmbbNIJm2fCCZtnAgmbZXIJm2CyCZtkogmbYFIJm29yCZts4gmbawIJm2CiCZtlUgmbagIJm2RCCZtoogmbaXIJm2+yCZtk0gmbZ1IJm21SCZtgcgmbY6IJm2rCCZtlwgmbY3IJm2TCCZtoUgmbZUIJm2qyCZtjAgmbYmIJm2WSCZtiwgmbZ4IJm2DCCZtnEgmbYeIJm2WyCZthcgmba2IJm2hCCZtiggmbZPIJm2iyCZtjkgmbadIJm2oSCZtrsgmbbAIJm2xCCZtnMgmbbZIJm2+iCZttwgmbafIJm2qCCZtm0gmbYnIJm2GSCZth8gmbZ5IJm2QCCZtgIgmbZBIJm2ZSCZtoMgmbbuIJm2FCCZtgQgmbb8IJm24iCZtsMgmbZFIJm2syCZtjwgmbbWIJm2ESCZtgggmbaVIJm2UCCZtkMgmbaQIJm22CCZtjUgmbY/IJm2aCCZtmMgmbZHIJm2zyCZtu8gmbauIJm2rSCZthggmbaPIJm2jSCZtksgmbaGIJm2SSCZtskgmbbFIJm21yCZtocgmbblIJm2pyCZtgkgmbaRIJm2ISCZtncgmbZvIJm2ASCZti4gmbZfIJm28iCZthYgmbaqIJm29iCZtqIgmba5IJm28CCZtn8gmbaJIJm2XSCZthMgmbYbIJm2SCCZtpMgmbY4IJm2UiCZtsEgmbYcIJm2WCCZtmEgmba6IJm2siCZtsogmbYNIJm2KyCZtuggmbbTIJm21CCZtukgmbZpIJm2FSCZtoAgmbZaIJm2ACCZtuAgmbavIJm2diCZtvkgmbapIJm2zCCZttEgmbZqIJm23iCZthAgmbaOIJm2RiCZtucgmbbtIJm2HSCZtsYgmbaYIJm2YCCZtsIgmbYyIJm2LSCZtnogmbaeIJm2ZCCZtoggmbbkIJm2eyCZtlMgmbb1IJm2vSCZtssgmbbqIJm2miCZtv4gmbYqIJnGgiyqxoIsAMaCLLPGgiwDxoIs0saCLEjGgixExoIsf8aCLM/GgiysxoIsIMaCLCbGgizExoIs4MaCLNXGgiwcxoIsesaCLNzGgizkxoIsksaCLHTGgixexoIsTcaCLF/GgixFxoIs2saCLG7GgiwexoIsmcaCLOzGgizqxoIsd8aCLKjGgizixoIspMaCLH7Ggiz6xoIskcaCLO7Ggiy5xoIshcaCLEfGgizQxoIshsaCLC7Ggiy1xoIsfMaCLPLGgiyexoIs7caCLIDGgizTxoIsscaCLHnGgixVxoIswMaCLDrGgiwMxoIsUcaCLBrGgiywxoIsPMaCLJPGgiw7xoIsS8aCLMLGgiyCxoIstMaCLLfGgizFxoIsQsaCLJ3GgiwbxoIsWsaCLGXGgiwtxoIs2MaCLDjGgiwKxoIs5saCLMnGgizexoIsl8aCLBPGgiyQxoIsKMaCLCzGgiwzxoIsiMaCLM7GgiwBxoIs9saCLN3GgizlxoIsb8aCLGbGgiymxoIsWMaCLMbGgizxxoIsi8aCLH3Ggiz7xoIsRsaCLMfGgiwXxoIsmsaCLJbGgixnxoIsBcaCLKHGgiyNxoIsvMaCLFbGgiyDxoIs6caCLHDGgizLxoIsSsaCLNbGgizoxoIsssaCLGPGgiw3xoIsW8aCLDTGgizjxoIsdcaCLCXGgiy7xoIs28aCLNTGgiz0xoIsvcaCLKvGgixoxoIsh8aCLD7Ggiz9xoIszcaCLO/GgiwNxoIs+caCLKDGgiy4xoIsXcaCLMzGgiwxxoIsScaCLK3GgixpxoIsosaCLPzGgizIxoIscsaCLJvGgiw2xoIseMaCLATGgiwkxoIsbcaCLBXGgizBxoIsH8aCLITGgiz/xoIsP8aCLC/GgixzxoIsr8aCLLbGgizrxoIsYsaCLIzGgiz1xoIsFMaCLKXGgizZxoIslcaCLBLGgixkxoIsHcaCLI/GgiwOxoIsKsaCLEPGgixMxoIsQcaCLNfGgiwZxoIsnMaCLE7GgizRxoIsK8aCLALGgiwjxoIsrsaCLGvGgiwIxoIsT8aCLGDGgiwRxoIsGMaCLN/GgiwnxoIsisaCLJTGgix7xoIsjsaCLJjGgiwwxoIsusaCLGHGgizzxoIs+MaCLFzGgiw1xoIsccaCLAbGgixUxoIsUMaCLInGgixZxoIsv8aCLPDGgiwhxoIsasaCLL7GgixTxoIsbMaCLDLGgiyjxoIs98aCLD3GgiyfxoIsEMaCLDnGgiwixoIsQMaCLP7Ggix2xoIsysaCLAvGgiwpxoIsD8aCLMPGgiznxoIsUsaCLKnGgiwWxoIs4caCLAnGgiwHxoIsp8aCLIHGgixXw8YsKe3oAgcVEPr/Oz7U0ZKXfXi8uVNW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WyLRHnYi0R5OItEeuCLRHkoi0R4UItEefSLRHk8i0R4GItEevCLRHvwi0R7aItEe0yLRHusi0R6nItEeESLRHnwi0R54ItEekSLRHv0i0R5YItEeDCLRHrci0R6VItEelCLRHioi0R4bItEe0iLRHuwi0R4WItEeQiLRHhgi0R6PItEeOSLRHlki0R7iItEeHCLRHvMi0R43ItEeICLRHsMi0R5BItEeKSLRHmAi0R6wItEeaSLRHr4i0R7pItEeqiLRHvgi0R7vItEemCLRHqIi0R76ItEeziLRHgci0R7wItEeOCLRHiQi0R7mItEe6CLRHjUi0R6jItEemyLRHr8i0R4eItEemSLRHoQi0R4ZItEeGiLRHooi0R5aItEeFSLRHuQi0R4yItEemiLRHp8i0R5VItEeFyLRHnQi0R4jItEe0CLRHs8i0R5WItEexyLRHuAi0R4NItEet9R3ObeLdzm3THc5t+93Obftdzm3tXc5twJ3ObfCdzm3I3c5t8R3Obeydzm3Bnc5t+V3Obf2dzm3Q3c5t7l3Obcedzm3SXc5t5Z3Obfpdzm3DXc5t6V3Obcadzm3xnc5t5B3Obcsdzm3ZXc5t1V3ObcQdzm3QXc5txV3ObdLdzm3bHc5t8F3ObcSdzm3nnc5t/V3ObdFdzm3inc5t9h3Obcgdzm3BXc5txF3ObcKdzm3kXc5t4Z3Obe6dzm3dnc5t/p3ObfPdzm3JHc5t/l3Obdadzm3bXc5t3N3Obfmdzm383c5twR3Obc+dzm3ZHc5twN3Obc3dzm3qHc5twh3ObdXdzm3JXc5t0R3Obf8dzm3CXc5t0d3Obdxdzm3GXc5tyZ3Obf4dzm3p3c5t9p3Obe2dzm333c5t7d3Obeddzm3mnc5tyd3Obdwdzm3aXc5twB3Obd6dzm3X3c5t5R3Obfudzm3d3c5tw93ObeEdzm3XXc5t9B3Obd8dzm3f3c5t853ObcYdzm3HHc5t1h3ObfZdzm3rnc5t793Obeqdzm3aHc5tw53Obcbdzm3Inc5t1l3ObcMdzm3oXc5t/13ObfJdzm3jHc5txR3ObfAdzm3tHc5t1Z3Obdjdzm3+3c5tyt3Obexdzm3YXc5tyF3ObeBdzm3iXc5twF3ObfKdzm3YHc5t1N3Obfedzm3Z3c5t0J3Obe+dzm3jnc5t693Obfjdzm3anc5t3V3ObdKdzm3Tnc5t3J3ObePdzm3yHc5t3t3Obf+dzm3mXc5t5t3Obcwdzm3w3c5t3h3ObfWdzm3QHc5t413Obfkdzm3PHc5tyh3Obc2dzm3gnc5t293Obfidzm3xXc5t593ObeTdzm3F3c5t7N3Obe7dzm3Knc5t3R3Obfqdzm3rHc5t4B3ObcLdzm3fXc5t5h3Obf0dzm323c5txN3Obfddzm3sHc5t0h3ObcHdzm3H3c5t0Z3ObfMdzm3NHc5ty93Obegdzm3Lnc5t/F3Obekdzm31Xc5tyl3Obejdzm34Hc5t8t3Obc1dzm3Fnc5t093Obfodzm3/3c5t4N3Obc5dzm3LXc5t4V3ObeIdzm3eXc5tzt3ObdRdzm3Xnc5t6t3Obc/dzm3UHc5t2J3Obd+dzm3M3c5tzp3Obc9dzm3pnc5t013Obfndzm3Znc5t/d3Obdrdzm3x3c5t1x3Obfydzm3uHc5t613Obdbdzm3VHc5t9d3Obepdzm3Unc5tzJ3ObeHdzm3vHc5t5x3Obfsdzm3lXc5t+F3Obeidzm3MXc5tzh3Obfrdzm303c5t9J3Obe9dzm3zXc5t/B3ObfRdzm3bnc5t5J3ObeXdzm3HXc5t9x3ObDW3cKw1s7CsNYrwrDWvsKw1rXCsNY6wrDW98Kw1nzCsNaDwrDW2sKw1qjCsNYuwrDWCsKw1h/CsNbxwrDWrMKw1rrCsNbPwrDWL8Kw1pjCsNbBwrDWcMKw1hrCsNaBwrDWxMKw1jPCsNZpwrDWF8Kw1mjCsNaywrDWjMKw1oLCsNYIwrDWOMKw1n7CsNZMwrDWjcKw1uLCsNbewrDWbMKw1jTCsNbswrDWHsKw1g/CsNYDwrDWI8Kw1vPCsNbfwrDWnsKw1uHCsNZJwrDWyMKw1gXCsNYSwrDW+8Kw1qvCsNb/wrDWdsKw1iXCsNZUwrDW8sKw1uDCsNaZwrDWIMKw1rTCsNZ4wrDW+sKw1hTCsNb4wrDWxcKw1v3CsNZawrDWU8Kw1q3CsNYbwrDWfcKw1gnCsNaEwrDWesKw1prCsNbDwrDWDcKw1jDCsNZqwrDWbcKw1lXCsNakwrDWQMKw1rvCsNZjwrDWl8Kw1ifCsNZvwrDWZ8Kw1rbCsNZ7wrDWEcKw1rjCsNZmwrDWB8Kw1kPCsNZrwrDWBsKw1qDCsNYdwrDWQcKw1vTC", + "sNbWwrDWJMKw1rfCsNYLwrDWPcKw1pDCsNYywrDW78Kw1pXCsNYMwrDWW8Kw1mLCsNaxwrDW1MKw1gLCsNZWwrDWn8Kw1nfCsNbrwrDWX8Kw1lzCsNaGwrDWKcKw1ijCsNZkwrDWHMKw1q/CsNaFwrDWFcKw1ujCsNawwrDW9cKw1r3CsNZ/wrDWZcKw1irCsNbQwrDW+cKw1sbCsNZZwrDW48Kw1urCsNadwrDWJsKw1s3CsNY+wrDWYMKw1o/CsNYBwrDWTsKw1kfCsNazwrDWecKw1qbCsNbnwrDWwsKw1jvCsNblwrDWqsKw1iHCsNbXwrDWccKw1u7CsNaOwrDWlsKw1l3CsNb+wrDWgMKw1uTCsNZNwrDWUMKw1svCsNbMwrDW9sKw1hnCsNanwrDWLcKw1nTCsNZewrDW2MKw1ljCsNajwrDWMcKw1m7CsNbpwrDWycKw1ubCsNbAwrDWi8Kw1q7CsNZPwrDWSMKw1kXCsNY/wrDWlMKw1pvCsNahwrDWRsKw1onCsNbtwrDWDsKw1qXCsNbVwrDWLMKw1jXCsNaHwrDW0cKw1pzCsNYQwrDWysKw1hbCsNaRwrDWRMKw1krCsNaiwrDW2cKw1tzCsNY8wrDWAMKw1ojCsNY3wrDWS8Kw1tLCsNbHwrDWk8Kw1jnCsNZRwrDWdcKw1hjCsNYEwrDWV8Kw1iLCsNYTwrDW28Kw1nPCsNapwrDWUsKw1vDCsNa5wrDWisKw1jbCsNbTwrDWcsKw1mHCsNa8wrDWQsKw1pLCsNb8wrDWv8IXWDfGF1g3KBdYNy4XWDcPF1g3axdYN9AXWDdEF1g3GRdYN04XWDelF1g3pBdYN+QXWDdCF1g3iRdYN8AXWDfbF1g3SxdYNxcXWDePF1g3gRdYN2oXWDcrF1g3ZBdYNxAXWDcDF1g3XRdYNxUXWDeYF1g3xxdYN80XWDcwF1g3UhdYN78XWDe5F1g3XBdYN1QXWDeWF1g3bBdYN2IXWDfBF1g3qxdYN8oXWDcMF1g3iBdYN9IXWDe3F1g3oxdYN30XWDd0F1g3nhdYN1AXWDduF1g3/RdYN+gXWDdJF1g3chdYN3cXWDdeF1g3ZhdYNxQXWDfOF1g3NRdYN28XWDdFF1g3nxdYNwAXWDeMF1g3VxdYN6IXWDfJF1g3nRdYN3UXWDf4F1g3YRdYN5AXWDclF1g34hdYNzEXWDfDF1g3khdYN3gXWDfEF1g3fhdYN38XWDdjF1g3exdYN8UXWDcIF1g3IhdYN4oXWDfvF1g32hdYNzwXWDeuF1g3vRdYNwcXWDdNF1g3WRdYNyEXWDcGF1g3WBdYN68XWDcLF1g30RdYN0wXWDfPF1g3vhdYN0AXWDcKF1g3+RdYN7UXWDf2F1g3fBdYNyoXWDfrF1g3uxdYN/cXWDfIF1g3OxdYN/wXWDcaF1g3rRdYN4IXWDehF1g3IxdYNzQXWDdWF1g3ehdYN7oXWDexF1g3RhdYN/4XWDcSF1g3AhdYN0cXWDc+F1g3qRdYN+0XWDeZF1g33xdYNywXWDeDF1g3QRdYN+cXWDc6F1g3lBdYNyAXWDdlF1g3vBdYN1UXWDcNF1g3yxdYN1oXWDfMF1g3LRdYN+wXWDfWF1g3NhdYN7AXWDcyF1g3JxdYN7gXWDc3F1g39BdYN9UXWDecF1g3URdYN4cXWDfZF1g3ZxdYN4AXWDfzF1g3bRdYNwUXWDf/F1g3shdYN4sXWDeVF1g3pxdYN6AXWDesF1g3sxdYNyQXWDcBF1g3+hdYNyYXWDcRF1g3QxdYN1MXWDeXF1g3hRdYNy8XWDcWF1g37hdYN2kXWDfjF1g3DhdYNz8XWDfTF1g38RdYNzkXWDfmF1g3HxdYNwkXWDfgF1g3KRdYN90XWDdxF1g3ShdYN8IXWDdPF1g3qBdYN6YXWDcEF1g33BdYN0gXWDdwF1g38BdYN3MXWDdgF1g3OBdYN5EXWDcTF1g3aBdYN7QXWDd2F1g36hdYN40XWDf7F1g3HhdYN94XWDdbF1g3HBdYNzMXWDdfF1g3hhdYN+UXWDc9F1g3HRdYN9gXWDfpF1g39RdYN44XWDfXF1g3qhdYNxgXWDd5F1g3mxdYNxsXWDeaF1g38hdYN4QXWDeTF1g31BdYN+EXWDe2DT8bUg0/VFINPytSDT9kUg0/hVINP8pSDT+1Ug0/+lINP0RSDT8LUg0/dFINPztSDT/aUg0/lVINP+pSDT+lUg0/g1INP8xSDT+zUg0//FINPx1SDT9SUg0/LVINP2JSDT/cUg0/k1INP+xSDT+jUg0/QlINPw1SDT9yUg0/PVINP39SDT8wUg0/T1INPwBSDT/hUg0/rlINP9FSDT+eUg0/IFINP29SDT8QUg0/X1INP75SDT/xUg0/jlINP8FSDT/nUg0/qFINP9dSDT+YUg0/eVINPzZSDT9JUg0/BlINP7hSDT/3Ug0/iFINP8dSDT8mUg0/aVINPxZSDT9ZUg0/JVINP2pSDT8VUg0/WlINP7tSDT/0Ug0/i1INP8RSDT96Ug0/NVINP0pSDT8FUg0/5FINP6tSDT/UUg0/m1INP71SDT/yUg0/jVINP8JSDT8jUg0/bFINPxNSDT9cUg0/4lINP61SDT/SUg0/nVINP3xSDT8zUg0/TFINPwNSDT9BUg0/DlINP3FSDT8+Ug0/31INP5BSDT/vUg0/oFINPx5SDT9RUg0/LlINP2FSDT+AUg0/z1INP7BSDT//Ug0/2VINP5ZSDT/pUg0/plINP0dSDT8IUg0/d1INPzhSDT+GUg0/yVINP7ZSDT/5Ug0/GFINP1dSDT8oUg0/Z1INP+NSDT+sUg0/01INP5xSDT99Ug0/MlINP01SDT8CUg0/vFINP/NSDT+MUg0/w1INPyJSDT9tUg0/ElINP11SDT97Ug0/NFINP0tSDT8EUg0/5VINP6pSDT/VUg0/mlINPyRSDT9rUg0/FFINP1tSDT+6Ug0/9VINP4pSDT/FUg0/h1INP8hSDT+3Ug0/+FINPxlSDT9WUg0/KVINP2ZSDT/YUg0/l1INP+hSDT+nUg0/RlINPwlSDT92Ug0/OVINPx9SDT9QUg0/L1INP2BSDT+BUg0/zlINP7FSDT/+Ug0/QFINPw9SDT9wUg0/P1INP95SDT+RUg0/7lINP6FSDT/dUg0/klINP+1SDT+iUg0/Q1INPwxSDT9zUg0/PFINP4JSDT/NUg0/slINP/1SDT8cUg0/U1INPyxSDT9jUg0/RVINPwpSDT91Ug0/OlINP9tSDT+UUg0/61INP6RSDT8aUg0/VVINPypSDT9lUg0/hFINP8tSDT+0Ug0/+1INP7lSDT/2Ug0/iVINP8ZSDT8nUg0/aFINPxdSDT9YUg0/5lINP6lSDT/WUg0/mVINP3hSDT83Ug0/SFINPwdSDT8hUg0/blINPxFSDT9eUg0/v1INP/BSDT+PUg0/wFINP35SDT8xUg0/TlINPwFSDT/gUg0/r1INP9BSDT+fUrIH19eyB9fasgfXC7IH1wayB9fHsgfXyrIH1xuyB9cWsgfX87IH1/6yB9cvsgfXIrIH1+OyB9fusgfXP7IH1zKyB9epsgfXpLIH13WyB9d4sgfXubIH17SyB9dlsgfXaLIH142yB9eAsgfXUbIH11yyB9edsgfXkLIH10GyB9dMsgfX3LIH19GyB9cAsgfXDbIH18yyB9fBsgfXELIH1x2yB9f4sgfX9bIH1ySyB9cpsgfX6LIH1+WyB9c0sgfXObIH16KyB9evsgfXfrIH13OyB9eysgfXv7IH126yB9djsgfXhrIH14uyB9dasgfXV7IH15ayB9ebsgfXSrIH10eyB9cgsgfXLbIH1/yyB9fxsgfXMLIH1z2yB9fssgfX4bIH1wSyB9cJsgfX2LIH19WyB9cUsgfXGbIH18iyB9fFsgfXXrIH11OyB9eCsgfXj7IH106yB9dDsgfXkrIH15+yB9d6sgfXd7IH16ayB9ersgfXarIH12eyB9e2sgfXu7IH1yuyB9cmsgfX97IH1/qyB9c7sgfXNrIH1+eyB9fqsgfXD7IH1wKyB9fTsgfX3rIH1x+yB9cSsgfXw7IH186yB9dVsgfXWLIH14myB9eEsgfXRbIH10iyB9eZsgfXlLIH13GyB9d8sgfXrbIH16CyB9dhsgfXbLIH172yB9ewsgfXsbIH17yyB9dtsgfXYLIH16GyB9essgfXfbIH13CyB9eVsgfXmLIH10myB9dEsgfXhbIH14iyB9dZsgfXVLIH18+yB9fCsgfXE7IH1x6yB9ffsgfX0rIH1wOyB9cOsgfX67IH1+ayB9c3sgfXOrIH1/uyB9f2sgfXJ7IH1yqyB9e6sgfXt7IH12ayB9drsgfXqrIH16eyB9d2sgfXe7IH156yB9eTsgfXQrIH10+yB9eOsgfXg7IH11KyB9dfsgfXxLIH18myB9cYsgfXFbIH19SyB9fZsgfXCLIH1wWyB9fgsgfX7bIH1zyyB9cxsgfX8LIH1/2yB9cssgfXIbIH10ayB9dLsgfXmrIH15eyB9dWsgfXW7IH14qyB9eHsgfXYrIH12+yB9e+sgfXs7IH13KyB9d/sgfXrrIH16OyB9c4sgfXNbIH1+SyB9fpsgfXKLIH1yWyB9f0sgfX+bIH1xyyB9cRsgfXwLIH182yB9cMsgfXAbIH19CyB9fdsgfXTbIH10CyB9eRsgfXnLIH112yB9dQsgfXgbIH14yyB9dpsgfXZLIH17WyB9e4sgfXebIH13SyB9elsgfXqLIH1zOyB9c+sgfX77IH1+KyB9cjsgfXLrIH1/+yB9fysgfXF7IH1xqyB9fLsgfXxrIH1weyB9cKsgfX27IH19Z5ptph8qbaYdam2mFdptphNabaYb6m2mGaptphEabaYZem2mEcptphOKbaYbOm2mHbptphUKbaYXSm2mH/ptph+abaYXKm2mFWptph3abaYbWm2mE+ptphGqbaYZGm2mEXptphnKbaYbim2mEzptphW6baYdCm2mH0ptphf6baYUCm2mHLptph76baYWSm2mEMptphh6baYaOm2mEoptphrqbaYSWm2mEBptphiqbaYeKm2mFpptphTabaYcam2mHAptphS6baYW+m2mHkptphjKbaYQem2mEjptphqKbaYS6m2mGlptphgabaYQqm2mFiptph6abaYc2m2mFGptphQqbaYcmm2mHtptphZqbaYQ6m2mGFptphoabaYSqm2mGsptphJ6baYQOm2mGIptph4KbaYWum2mFPptphxKbaYcKm2mFJptphbabaYeam2mGOptphBabaYSGm2mGqptphLKbaYaem2mGDptphCKbaYWCm2mHrptphz6baYUSm2mF7ptph8KbaYdSm2mFfptphN6baYbym2mGYptphE6baYZWm2mEeptphOqbaYbGm2mHZptphUqbaYXam2mH9ptph+6baYXCm2mFUptph36baYbem2mE8ptphGKbaYZOm2mEVptphnqbaYbqm2mExptphWabaYdKm2mH2ptphfabaYeym2mFnptphQ6baYcim2mGgptphK6baYQ+m2mGEptphAqbaYYmm2mGtptphJqbaYU6m2mHFptph4abaYWqm2mFsptph56baYcOm2mFIptphIKbaYaum2mGPptphBKbaYYKm2mEJptphLabaYaam2mHOptphRabaYWGm2mHqptph1abaYV6m2mF6ptph8abaYZmm2mESptphNqbaYb2m2mE7ptphsKbaYZSm2mEfptphd6baYfym2mHYptphU6baYVWm2mHeptph+qbaYXGm2mEZptphkqbaYbam2mE9ptphu6baYTCm2mEUptphn6baYfem2mF8ptphWKbaYdOm2mHXptphXKbaYXim2mHzptphm6baYRCm2mE0ptphv6baYTmm2mGyptphlqbaYR2m2mF1ptph/qbaYdqm2mFRptphV6baYdym2mH4ptphc6baYRum2mGQptphtKbaYT+m2mG5ptphMqbaYRam2mGdptph9abaYX6m2mFaptph0abaYe6m2mFlptphQabaYcqm2mGiptphKabaYQ2m2mGGptphAKbaYYum2mGvptphJKbaYUym2mHHptph46baYWim2mFuptph5abaYcGm2mFKptphIqbaYamm2mGNptphBqbaYYCm2mELptphL6baYaSm2mHMptphR6baYWOm2mHoptphgvzMuoIczLqC08y6gjPMuoLJzLqCKcy6gubMuoIGzLqCL8y6gs/MuoIAzLqC4My6ghrMuoL6zLqCNcy6gtXMuoI8zLqC3My6ghPMuoLzzLqCCcy6gunMuoImzLqCxsy6gu/MuoIPzLqCwMy6giDMuoLazLqCOsy6gvXMuoIVzLqCjsy6gm7MuoKhzLqCQcy6grvMuoJbzLqClMy6gnTMuoJdzLqCvcy6gnLMuoKSzLqCaMy6gojMuoJHzLqCp8y6gk7MuoKuzLqCYcy6goHMuoJ7zLqCm8y6glTMuoK0zLqCncy6gn3MuoKyzLqCUsy6gqjMuoJIzLqCh8y6gmfMuoI2zLqC1sy6ghnMuoL5zLqCA8y6guPMuoIszLqCzMy6guXMuoIFzLqCysy6girMuoLQzLqCMMy6gv/MuoIfzLqC9sy6ghbMuoLZzLqCOcy6gsPMuoIjzLqC7My6ggzMuoIlzLqCxcy6ggrMuoLqzLqCEMy6gvDMuoI/zLqC38y6gkTMuoKkzLqCa8y6govMuoJxzLqCkcy6gl7MuoK+zLqCl8y6gnfMuoK4zLqCWMy6gqLMuoJCzLqCjcy6gm3MuoKEzLqCZMy6gqvMuoJLzLqCscy6glHMuoKezLqCfsy6glfMuoK3zLqCeMy6gpjMuoJizLqCgsy6gk3MuoKtzLqCvMy6glzMuoKTzLqCc8y6gonMuoJpzLqCpsy6gkbMuoJvzLqCj8y6gkDMuoKgzLqCWsy6grrMuoJ1zLqClcy6gnzMuoKczLqCU8y6grPMuoJJzLqCqcy6gmbMuoKGzLqCr8y6gk/MuoKAzLqCYMy6gprMuoJ6zLqCtcy6glXMuoLOzLqCLsy6guHMuoIBzLqC+8y6ghvMuoLUzLqCNMy6gh3MuoL9zLqCMsy6gtLMuoIozLqCyMy6ggfMuoLnzLqCDsy6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DASwvQwExr0MBBG9DAR+vQwE3L0MBJ69DAQYvQwESr0MBKq9DAS4vQwE9L0MBMe9DAQ/vQwEp70MBAC9DARavQwEqL0MBMS9DARMvQwEh70MBNS9DARGvQwE0b0MBKS9DATIvQwEGb0MBFi9DAThvQwEm70MBLS9DAQuvQwEEL0MBPW9DAT6vQwEg70MBCi9DAQ9vQwEHb0MBKy9DAQ5vQwEr70MBKO9DASWvQwEk70MBOu9DAQbvQwEfL0MBHS9DARIvQwEJr0MBNW9DASxvQwErb0MBNa9DATJvQwEnL0MBOC9DAS3vQwEXr0MBDO9DASYvQwEAb0MBIi9DARBvQwEgr0MBNO9DATAvQwEcL0MBJS9DASFvQwEGr0MBHa9DASLvQwEj70MBLa9DATBvQwEkL0MBOS9DATLvQwEa70MBCC9DAR5vQwEY70MBGW9DAQPvQwEbr0MBOK9DAQ7vQwEvL0MBFW9DAQfvQwEkr0MBMy9DASavQwEwr0MBP+9DAQvvQwE2r0MBBW9DARfvQwEn70MBCe9DAS7vQwEU70MBM29DARRvQwEOL0MBAq9DATQvQwE170MBP69DAQ0vQwEYb0MBBa9DASgvQwEyr0MBP29DARcvQwEDr0MBKm9DATYvQwEK70MBFu9DASivQwEF70MBAa9DASVvQwEc70MBGK9DARyvQwEkb0MBDW9DASdveMOE4jjDhPA4w4TJeMOE7/jDhPK4w4TD+MOE/jjDhMZ4w4TN+MOE07jDhMb4w4TteMOE3njDhP64w4TtOMOEwLjDhOr4w4TA+MOE93jDhMw4w4TbOMOE1PjDhND4w4TdeMOE+TjDhPz4w4TkOMOE5XjDhNk4w4TzeMOE6rjDhMB4w4Tb+MOE9DjDhNa4w4T1OMOE8jjDhPG4w4TPeMOE0fjDhOl4w4T8eMOE3fjDhNV4w4T5uMOE1HjDhMj4w4TKuMOE5/jDhNG4w4TC+MOE8XjDhOm4w4TCuMOE/bjDhOO4w4TEOMOEyDjDhOo4w4T1+MOE4LjDhNK4w4TWOMOE/fjDhM44w4TJOMOEwfjDhNj4w4TL+MOE4rjDhPW4w4Tm+MOE/XjDhO24w4TfeMOE23jDhP54w4TTeMOE1zjDhMN4w4T4+MOE4/jDhO94w4TO+MOEyHjDhMU4w4T5eMOE7LjDhP/4w4T6+MOEynjDhOJ4w4T9OMOE0njDhOu4w4T4OMOEzHjDhN74w4TW+MOEy3jDhOH4w4T0uMOE8zjDhPR4w4TUOMOEyLjDhM54w4TweMOE6/jDhOB4w4TNOMOE6PjDhPa4w4TBOMOE1TjDhNp4w4Tz+MOEwbjDhPo4w4Ts+MOE9njDhMI4w4TuuMOE+zjDhNM4w4TsOMOE3HjDhPb4w4TM+MOE7njDhM64w4TrOMOE0TjDhOx4w4TyeMOE3rjDhNd4w4TQuMOE0/jDhPc4w4T7+MOExjjDhNF4w4TmOMOEyvjDhOg4w4TauMOE/vjDhPf4w4TV+MOE+fjDhOU4w4TF+MOE3DjDhNn4w4Tf+MOEx7jDhO44w4TNuMOE8LjDhNB4w4Tp+MOE9jjDhO74w4TE+MOE4vjDhPD4w4TAOMOE8fjDhPL4w4T4uMOE+HjDhMn4w4ThOMOEz7jDhMs4w4TvuMOE2bjDhOp4w4ThuMOE6HjDhN+4w4TgOMOE2XjDhNi4w4TDOMOEwXjDhP+4w4TUuMOEy7jDhMR4w4T7uMOE7zjDhOW4w4Tl+MOE97jDhN84w4TheMOE43jDhNz4w4TCeMOEyjjDhNo4w4TouMOE3jjDhMa4w4TmuMOE3bjDhMy4w4TxOMOEybjDhOc4w4TQOMOE5LjDhNf4w4TmeMOExLjDhOk4w4T/eMOE53jDhPq4w4TbuMOE5PjDhOe4w4T/OMOExXjDhNr4w4TH+MOExbjDhNL4w4T6eMOEzzjDhMc4w4TNeMOE17jDhNI4w4TYeMOEw7jDhPO4w4TjOMOEx3jDhOt4w4T8uMOE9XjDhO34w4Tg+MOE1njDhNW4w4T0+MOE3TjDhNy4w4TkeMOEz/jDhPw4w4TYOMOE+1U//W/VP/1EFT/9Y1U//UiVP/1IVT/9Y5U//UTVP/1vFT/9UlU//XmVP/1e1T/9dRU//XXVP/1eFT/9eVU//VKVP/1wFT/9W9U//XyVP/1XVT/9V5U//XxVP/1bFT/9cNU//U2VP/1mVT/9QRU//WrVP/1qFT/9QdU//WaVP/1NVT/9ZJU//U9VP/1oFT/9Q9U//UMVP/1o1T/9T5U//WRVP/1ZFT/9ctU//VWVP/1+VT/9fpU//VVVP/1yFT/9WdU//XtVP/1QlT/9d9U//VwVP/1c1T/9dxU//VBVP/17lT/9RtU//W0VP/1KVT/9YZU//WFVP/1KlT/9bdU//UYVP/1nVT/9TJU//WvVP/1AFT/9QNU//WsVP/1MVT/9Z5U//VrVP/1xFT/9VlU//X2VP/19VT/9VpU//XHVP/1aFT/9eJU//VNVP/10FT/9X9U//V8VP/101T/9U5U//XhVP/1FFT/9btU//UmVP/1iVT/9YpU//UlVP/1uFT/9RdU//WwVP/1H1T/9YJU//UtVP/1LlT/9YFU//UcVP/1s1T/9UZU//XpVP/1dFT/9dtU//XYVP/1d1T/9epU//VFVP/1z1T/9WBU//X9VP/1UlT/9VFU//X+VP/1Y1T/9cxU//U5VP/1llT/9QtU//WkVP/1p1T/9QhU//WVVP/1OlT/9VhU//X3VP/1alT/9cVU//XGVP/1aVT/9fRU//VbVP/1rlT/9QFU//WcVP/1M1T/9TBU//WfVP/1AlT/9a1U//UnVP/1iFT/9RVU//W6VP/1uVT/9RZU//WLVP/1JFT/9dFU//V+VP/141T/9UxU//VPVP/14FT/9X1U//XSVP/1dVT/9dpU//VHVP/16FT/9etU//VEVP/12VT/9XZU//WDVP/1LFT/9bFU//UeVP/1HVT/9bJU//UvVP/1gFT/9QpU//WlVP/1OFT/9ZdU//WUVP/1O1T/9aZU//UJVP/1/FT/9VNU//XOVP/1YVT/9WJU//XNVP/1UFT/9f9U//V6VP/11VT/9UhU//XnVP/15FT/9UtU//XWVP/1eVT/9YxU//UjVP/1vlT/9RFU//USVP/1vVT/9SBU//WPVP/1BVT/9apU//U3VP/1mFT/9ZtU//U0VP/1qVT/9QZU//XzVP/1XFT/9cFU//VuVP/1bVT/9cJU//VfVP/18FT/9VdU//X4VP/1ZVT/9cpU//XJVP/1ZlT/9ftU//VUVP/1oVT/9Q5U//WTVP/1PFT/9T9U//WQVP/1DVT/9aJU//UoVP/1h1T/9RpU//W1VP/1tlT/9RlU//WEVP/1K1T/9d5U//VxVP/17FT/9UNU//VAVP/171T/9XJU//Xd3oMeON7uHjjeDR443mAeON7nHjjeih443mkeON4EHjjeQR443iweON7PHjjeoh443iUeON5IHjjeqx443sYeON66Hjje1x443jQeON5ZHjje3h443rMeON5QHjjePR443ngeON4VHjje9h443pseON4cHjjecR443pIeON7/HjjenR443vAeON4THjjefh443vkeON6UHjjedx443hoeON5fHjjeMh443tEeON68HjjeOx443lYeON61Hjje2B443qQeON7JHjjeKh443kceON7AHjjerR443k4eON4jHjjeZh443gseON7oHjjehR443gIeON5vHjjejB443uEeON5MHjjeIR443sIeON6vHjjeKB443kUeON6mHjjeyx443o4eON7jHjjeAB443m0eON7qHjjehx443mQeON4JHjjedR443hgeON77Hjjelh443hEeON58Hjjenx443vIeON63Hjje2h443jkeON5UHjje0x443r4eON5dHjjeMB443lIeON4/Hjje3B443rEeON42HjjeWx443rgeON7VHjjekB443v0eON4eHjjecx443vQeON6ZHjjeeh443hceON5rHjjeBh443uUeON6IHjjeDx443mIeON6BHjje7B443qkeON7EHjjeJx443koeON7NHjjeoB443kMeON4uHjjezh443qMeON5AHjjeLR443qoeON7HHjjeJB443kkeON4MHjjeYR443oIeON7vHjjeaB443gUeON7mHjjeix443vceON6aHjjeeR443hQeON6THjje/h443h0eON5wHjjeNR443lgeON67Hjje1h443lEeON48Hjje3x443rIeON7QHjjevR443l4eON4zHjjetB443tkeON46HjjeVx443hIeON5/HjjenB443vEeON52HjjeGx443vgeON6VHjje6R443oQeON5nHjjeCh443o0eON7gHjjeAx443m4eON4rHjjeRh443qUeON7IHjjeTx443iIeON7BHjjerB443gEeON5sHjjejx443uIeON5lHjjeCB443useON6GHjjewx443q4eON5NHjjeIB443qceON7KHjjeKR443kQeON44HjjeVR443rYeON7bHjjeXB443jEeON7SHjjevx443voeON6XHjjedB443hkeON6eHjje8x443hAeON59HjjeHx443nIeON6RHjje/B443nseON4WHjje9R443pgeON7dHjjesB443lMeON4+HjjeuR443tQeON43HjjeWh443iYeON5LHjjeqB443sUeON5CHjjeLx443sweON6hHjje5B443okeON5qHjjeBx443oAeON7tHjjeDh443mMeOHOD+4lzg4qJc4PZiXODqIlzg1aJc4MniXODdIlzgwWJc4NxiXODAIlzg1OJc4MiiXOD3Ilzg62Jc4P+iXODj4lzg7CJc4PBiXODkolzg+OJc4MdiXODbIlzgz+Jc4NOiXODOolzg0uJc4MYiXODaYlzg5eJc4PmiXODtYlzg8SJc4OGiXOD94lzg6SJc4PViXODK4lzg1qJc4MJiXODeIlzgwyJc4N9iXODLolzg1+Jc4OhiXOD0Ilzg4OJc4PyiXODzYlzg7yJc4PviXODnolzg2CJc4MRiXODQolzgzOJc4NHiXODNolzg2WJc4MUiXOD6olzg5uJc4PIiXODuYlzg5CJc4PhiXODsolzg8OJc4M9iXODTIlzgx+Jc4NuiXODGolzg2uJc4M4iXODSYlzg7eJc4PGiXODlYlzg+SJc4PbiXODqolzg/mJc4OIiXODdolzgweJc4NUiXODJYlzg1GJc4MgiXODc4lzgwKJc4P8iXODjYlzg96Jc4OviXOD7Ylzg5yJc4PPiXODvolzg0CJc4MxiXODYolzgxOJc4NniXODFolzg0WJc4M0iXODyolzg7uJc4PoiXODmYlzg6aJc4PXiXODhIlzg/WJc4MLiXODeolzgymJc4NYiXODLIlzg12Jc4MOiXODf4lzg4GJc4PwiXODo4lzg9KJc4NQiXODIYlzg3KJc4MDiXOD/Ylzg4yJc4PfiXODrolzg9qJc4OriXOD+Ilzg4mJc4N3iXODBolzg1WJc4MkiXODG4lzg2qJc4M5iXODSIlzg7aJc4PHiXODlIlzg+WJc4ORiXOD4Ilzg7OJc4PCiXODPIlzg02Jc4MeiXODb4lzgy2Jc4NciXODD4lzg36Jc4OAiXOD8Ylzg6KJc4PTiXODp4lzg9aJc4OFiXOD9IlzgwqJc4N7iXODKIlzg1mJc4NmiXODF4lzg0SJc4M1iXODy4lzg7qJc4PpiXODmIlzg+yJc4OdiXODzolzg7+Jc4NBiXODMIlzg2OJc4MSiXODO4lzg0qJc4MZiXODaIlzg5aJc4PniXODtIlzg8WJc4OxiXODwIlzg5OJc4PiiXODHIlzg22Jc4M+iXODT4lzg3CJc4MBiXODUolzgyOJc4PdiXODrIlzg/+Jc4OOiXOD+olzg4uJc4PYiXODqYlzg1eJc4MmiXODdYlzgwSJc4NGiXODN4lzg2SJc4MViXOD64lzg5qJc4PJiXODuIlzg8yJc4O9iXOD7olzg5+Jc4NhiXODEIlzg0OJc4MyiXODDYlzg3yJc4MviXODXolzg6CJc4PRiXODgolzg/OJc4OHiXOD9olzg6WJc4PUiXODKolzg1uJc4MIiXODeYkL57z0zOe89BrnvPTd57z0P+e89PjnvPQu57z06ee89MbnvPQB57z01+e89BDnvPTy57z0Nee89OPnvPQk57z0O+e89PznvPQq57z07ee89A/nvPTI57z0Hue89NnnvPT257z0Mee89OfnvPQg57z0wue89AXnvPTT57z0FOe89ETnvPSD57z0Vee89JLnvPRw57z0t+e89GHnvPSm57z0iee89E7nvPSY57z0X+e89L3nvPR657z0rOe89GvnvPR057z0s+e89GXnvPSi57z0QOe89IfnvPRR57z0lue89LnnvPR+57z0qOe89G/nvPSN57z0Sue89JznvPRb57z0aue89K3nvPR757z0vOe89F7nvPSZ57z0T+e89IjnvPSn57z0YOe89LbnvPRx57z0k+e89FTnvPSC57z0Ree89FrnvPSd57z0S+e89IznvPRu57z0qee89H/nvPS457z0l+e89FDnvPSG57z0Qee89KPnvPRk57z0sue89HXnvPQl57z04ue89DTnvPTz57z0Eee89NbnvPQA57z0x+e89OjnvPQv57z0+ee89D7nvPTc57z0G+e89M3nvPQK57z0Fee89NLnvPQE57z0w+e89CHnvPTm57z0MOe89PfnvPTY57z0H+e89MnnvPQO57z07Oe89CvnvPT957z0Oue89JTnvPRT57z0hee89ELnvPSg57z0Z+e89LHnvPR257z0Wee89J7nvPRI57z0j+e89G3nvPSq57z0fOe89LvnvPSk57z0Y+e89LXnvPRy57z0kOe89FfnvPSB57z0Rue89GnnvPSu57z0eOe89L/nvPRd57z0mue89EznvPSL57z02+e89BznvPTK57z0Dee89O/nvPQo57z0/ue89DnnvPQW57z00ee89AfnvPTA57z0Iue89OXnvPQz57z09Oe89OvnvPQs57z0+ue89D3nvPTf57z0GOe89M7nvPQJ57z0Jue89OHnvPQ357z08Oe89BLnvPTV57z0A+e89MTnvPT157z0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n4Uag5+FGqWfhRoHn4Ua3p+FGp+fhRopn4Ua0p+FGmmfhRpLn4UaX5+FGsOfhRpBn4UaYp+FGmSfhRpDn4Ua9Z+FGnqfhRqGn4UaF5+FGmifhRq1n4Ua2p+FGtWfhRqrn4Ua1p+FGmCfhRqqn4UazZ+FGiefhRpOn4UaUp+FGoWfhRrtn4UaFZ+FGq+fhRovn4UagZ+FGuefhRq5n4Uasp+FGsefhRqWn4UaOp+FGoSfhRqzn4UaPJ+FGvmfhRoxn4Ual5+FGoCfhRoqn4UavJ+FGlCfhRqtn4UasJ+FGt+fhRorn4UaGJ+FGumfhRoCn4Ua4p+FGkCfhRqun4UaD5+FGvOfhRoBn4UaRZ+FGqifhRrgn4Ua4Z+FGr2fhRrUn4Uae5+FGnWfhRqIn4UaBp+FGsWfhRpYn4UaYZ+FGmufhRqMn4UaZp+FGhqfhRo0n4UawZ+FGjifhRoon4UaA5+FGiKfhRoZn4UamJ+FGu6fhRr9n4Ua/p+FGsafhRoen4UadJ+FGqyfhRpJn4Uajp+FGoqfhRpln4Uafp+FGqCfhRown4UaWp+FGvqfhRq/n4Ua5p+FGuqfhRokn4Uao5+FGhKfhRp8n4UaMp+FGsCfhRpVmDq5zJg6t8yYOvXMmDp+zJg6H8yYOuvMmDobzJg6r8yYOhPMmDoxzJg6qsyYOtzMmDoGzJg6AcyYOirMmDrtzJg6dsyYOjbMmDqUzJg63syYOnjMmDqOzJg64syYOvrMmDr0zJg6e8yYOgPMmDqSzJg6yMyYOiXMmDoVzJg6d8yYOoDMmDrjzJg6FMyYOu7MmDoXzJg61syYOm7MmDr9zJg63cyYOmrMmDohzJg6DsyYOnrMmDplzJg6LcyYOs7MmDpezJg62cyYOk7MmDoFzJg6usyYOr7MmDpMzJg6PMyYOhnMmDrTzJg6UMyYOqDMmDqCzJg68cyYOszMmDorzJg6RcyYOunMmDo7zJg6QMyYOsbMmDpzzJg6hsyYOmDMmDrNzJg6bcyYOhbMmDqnzJg65MyYOvnMmDoKzJg6tsyYOq3MmDpyzJg6MsyYOsrMmDq1zJg6M8yYOt/MmDp0zJg628yYOujMmDo/zJg6msyYOpnMmDr/zJg65cyYOgfMmDrzzJg6ZMyYOlbMmDpnzJg6ocyYOsDMmDpxzJg6nsyYOtfMmDrnzJg6osyYOtjMmDqzzJg6i8yYOijMmDp1zJg6LMyYOkPMmDp9zJg6g8yYOhrMmDoLzJg6ncyYOs/MmDpUzJg6xMyYOtTMmDpLzJg6gcyYOqbMmDopzJg6vcyYOsnMmDoAzJg6WcyYOpzMmDpozJg6qMyYOmPMmDrFzJg6HcyYOlPMmDr4zJg67MyYOmbMmDqIzJg6WMyYOlfMmDqlzJg6JsyYOtLMmDp/zJg6m8yYOgnMmDrRzJg6HMyYOi7MmDpCzJg6D8yYOrLMmDpHzJg6kcyYOkjMmDoYzJg6jcyYOlHMmDojzJg698yYOknMmDrgzJg6AsyYOlvMmDoRzJg6PcyYOiTMmDqszJg6uMyYOhDMmDpdzJg6NcyYOrTMmDpPzJg6h8yYOlXMmDoEzJg6IsyYOl/MmDogzJg6RsyYOoXMmDovzJg6jMyYOrzMmDqfzJg6mMyYOvDMmDpSzJg6DcyYOjTMmDrDzJg6x8yYOq7MmDpNzJg6OMyYOorMmDprzJg61cyYOv7MmDoMzJg6YcyYOjfMmDpwzJg6icyYOo/MmDrLzJg6SsyYOmLMmDr8zJg6EsyYOjrMmDowzJg68syYOvvMmDqQzJg6scyYOh7MmDo5zJg6b8yYOpbMmDpBzJg6acyYOpXMmDrCzJg6J8yYOtrMmDo+zJg6ecyYOu/MmDp8zJg6CMyYOqvMmDqpzJg6v8yYOuHMmDrmzJg60MyYOsHMmDpczJg69syYOrvMmDqwzJg6WsyYOpPMmDqEzJg6RMyYOqTMmDqXzJg66syYOqPMmDpszDdcnrQ33Z60N0CetDd0nrQ3p560N7KetDconrQ3L560NzyetDeWnrQ3fJ60N0KetDdonrQ3w560NzCetDcrnrQ3Jp60N++etDfKnrQ32560NzmetDfCnrQ3wJ60Nx+etDdlnrQ37Z60N8uetDfznrQ3pZ60N5metDcgnrQ3Z560N42etDd4nrQ3DZ60NwGetDclnrQ35J60N9OetDfanrQ3qp60N7yetDeonrQ3bZ60N46etDeunrQ3n560N/6etDfxnrQ3Y560NwaetDf3nrQ3AJ60N0SetDd/nrQ3t560NxaetDecnrQ3wZ60N5KetDc+nrQ3CZ60N+6etDdqnrQ3IZ60NxGetDfgnrQ3Q560N6metDeGnrQ3i560N8SetDcHnrQ34p60N32etDfVnrQ3Cp60N6SetDernrQ3cZ60NzSetDcFnrQ32Z60N9+etDdLnrQ3+560N6yetDcUnrQ3Dp60N1+etDe2nrQ3BJ60N2SetDc7nrQ3aZ60N/aetDcZnrQ3Zp60N4qetDfGnrQ3Vp60N8eetDcznrQ3iJ60Ny6etDcynrQ3jJ60N9KetDeBnrQ3np60Nx6etDfInrQ3P560N+uetDdXnrQ3N560N7uetDf4nrQ3m560N76etDdsnrQ3D560N+eetDcbnrQ3hJ60N/metDcCnrQ3vZ60N3metDdSnrQ3YJ60N1ietDfFnrQ3CJ60N6GetDe4nrQ3v560N8metDddnrQ3RZ60N7metDdZnrQ3F560N3CetDfcnrQ3sZ60N6CetDdJnrQ3e560N+ietDf/nrQ37J60N1WetDdPnrQ38J60N9eetDeQnrQ3d560N/KetDd+nrQ3gJ60N52etDdInrQ3EJ60NwOetDflnrQ3tJ60NyqetDfmnrQ3lJ60NyKetDf1nrQ3TZ60N3KetDc2nrQ3GJ60N0GetDfWnrQ3HZ60N4metDdOnrQ3up60NymetDdenrQ34Z60NyOetDfOnrQ3U560N6KetDfNnrQ3LJ60N96etDf8nrQ3LZ60N5WetDcMnrQ3gp60N6+etDeDnrQ3J560N8+etDcxnrQ3Yp60NwuetDdQnrQ3c560N9GetDdKnrQ3tZ60N0yetDdrnrQ3UZ60NzqetDccnrQ3Wp60N7CetDcanrQ3mp60N9ietDfQnrQ3E560N/2etDeRnrQ3o560NxWetDeznrQ36Z60N3WetDf6nrQ3NZ60N8yetDdHnrQ3k560N5ietDdunrQ31J60NxKetDfqnrQ3hZ60NySetDdUnrQ3b560N2GetDemnrQ34560N0aetDd6nrQ3OJ60N5eetDd2nrQ3PZ60N62etDf0nrQ3j560N1uetDeHnrS1tQdhj7UHYQ21B2H6tQdhB7UHYfK1B2GHtQdhArUHYS21B2HOtQdh5rUHYcO1B2EXtQdhLLUHYbm1B2GrtQdhBrUHYdW1B2EWtQdho7UHYVq1B2FstQdhvrUHYZS1B2F7tQdhYbUHYZW1B2GctQdhxLUHYWe1B2FItQdhMbUHYbG1B2GntQdhtrUHYc21B2E+tQdhhrUHYXG1B2EntQdhUrUHYVi1B2EptQdhJbUHYbS1B2F9tQdhfLUHYQO1B2EitQdhXLUHYdG1B2EktQdhjLUHYWK1B2GEtQdhdLUHYe61B2HZtQdhd7UHYUO1B2GltQdhTbUHYRi1B2HYtQdhFbUHYbu1B2EAtQdhdrUHYYq1B2EQtQdhz7UHYYC1B2GDtQdhM7UHYXC1B2HJtQdhibUHYWi1B2EbtQdh4rUHYX61B2GatQdhabUHYWS1B2E0tQdhXrUHYQq1B2G3tQdhk7UHYVG1B2GdtQdh9rUHYRS1B2G4tQdh5bUHYeq1B2F6tQdh8bUHYU+1B2GLtQdhOLUHYYK1B2GvtQdhVLUHYf61B2HXtQdhrrUHYcu1B2EStQdhrLUHYTy1B2EvtQdhNrUHYTe1B2HatQdhhbUHYR+1B2F/tQdh07UHYR21B2H4tQdh3rUHYVe1B2HztQdhPbUHYWW1B2EatQdhsLUHYUa1B2HMtQdhXbUHYUq1B2FytQdh3bUHYe21B2E7tQdhJrUHYT+1B2EOtQdh5LUHYaC1B2HUtQdhkrUHYb21B2GttQdhRLUHYbK1B2FBtQdhZrUHYVO1B2G6tQdhb7UHYRy1B2HgtQdhS7UHYY61B2FQtQdh4bUHYf21B2F5tQdhLrUHYb+1B2EotQdh97UHYUy1B2HBtQdh0rUHYYG1B2GItQdhR7UHYUm1B2EJtQdh/7UHYZa1B2E1tQdhKrUHYTK1B2ERtQdhHrUHYVW1B2ErtQdhD7UHYam1B2ELtQdhX7UHYVm1B2GQtQdhDLUHYfu1B2HHtQdhc7UHYVu1B2HwtQdhn7UHYRO1B2HCtQdhRbUHYda1B2GYtQdh37UHYey1B2FqtQdhbbUHYcC1B2EgtQdhorUHYZ61B2HQtQdhqLUHYdu1B2H5tQdhyLUHYfy1B2GbtQdhpLUHYaa1B2GNtQdh47UHYZe1B2EItQdh67UHYSG1B2FAtQdhBLUHYe+1B2EjtQdhGbUHYQW1B2H0tQdhObUHYZG1B2FgtQdh57UHYaq1B2H1tQdhxrUHYaG1B2GZtQdhxbUHYTq1B2F4tQdhVrUHYQG1B2GztQdh6bUHYU61B2EwtQdhdbUHYWO1B2FCtQdh3LUHYWu1B2FutQdhvLUHYcq1B2HotQdhV6vbEler29RXq9uyV6vbZFer255Xq9vhV6vbKler26JXq9sMV6vbcler271Xq9uZV6vb3Ver24JXq9sKV6vbs1er2z1Xq9u0V6vb0ler27hXq9swV6vbzVer21tXq9sJV6vbTVer28xXq9tKV6vbZVer2ztXq9thV6vbIFer2yFXq9t4V6vbmFer25RXq9s8V6vbHVer2xtXq9tnV6vbVFer26ZXq9vKV6vbJ1er26BXq9sxV6vb/Fer29VXq9t2V6vbM1er289Xq9u2V6vbi1er25ZXq9tjV6vbbVer22pXq9u6V6vbBFer2wBXq9vaV6vb+Fer2xRXq9uJV6vbx1er2xVXq9u8V6vbyFer2zdXq9uKV6vbqVer2+xXq9vQV6vboVer29NXq9tgV6vbxFer279Xq9uIV6vbkVer26NXq9vZV6vbrler29xXq9v0V6vbNler2xZXq9tZV6vbdVer24xXq9tMV6vbvler2/JXq9vqV6vb81er21VXq9v+V6vbSFer2yVXq9trV6vbGFer2/tXq9v3V6vbjVer209Xq9uoV6vbkler28VXq9vAV6vbQVer25pXq9u7V6vb0Ver2/FXq9tsV6vb41er2ylXq9vuV6vbCFer2xpXq9vrV6vbzler219Xq9tpV6vbxler2yxXq9sGV6vbgVer2+lXq9viV6vbHFer2xFXq9sNV6vbnVer28lXq9sTV6vbl1er25NXq9vmV6vbfVer21pXq9sCV6vbhFer20NXq9utV6vbUler2/VXq9seV6vbOFer2xdXq9unV6vbb1er20JXq9suV6vb5Ver20ZXq9ubV6vb71er2+BXq9sFV6vb21er24BXq9vXV6vbZler2wFXq9svV6vb6Fer23xXq9skV6vbB1er27BXq9twV6vbg1er249Xq9vtV6vblVer26pXq9ufV6vbdFer28tXq9syV6vbXFer205Xq9t5V6vbeler21hXq9u5V6vbD1er20tXq9uHV6vbRFer2xlXq9vYV6vbJler2/lXq9t7V6vbPler211Xq9tAV6vbLVer25xXq9vWV6vbwVer21ZXq9s/V6vbjler2wtXq9uGV6vbbler2/ZXq9sjV6vbXler2wNXq9usV6vbNFer20VXq9u3V6vbV1er2zlXq9vfV6vbpFer2zpXq9srV6vbkFer23dXq9uvV6vb/1er2/BXq9tQV6vbaFer22JXq9uxV6vbKFer2x9Xq9ulV6vbc1er2w5Xq9txV6vb+ler20dXq9tJV6vbUVer2+RXq9uFV6vbw1er2yJXq9vnV6vbtVer2zVXq9t+V6vbwler2xBXq9v9V6vbf1er26tXq9veV6vbU3TF9YZ0xUGGdMVYhnTFAoZ0xceGdMVLhnTFRYZ0xV+GdMXEhnTFA4Z0xTWGdMVrhnTFFoZ0xRuGdMVKhnTF3YZ0xbuGdMUghnTF9IZ0xeGGdMWMhnTFjoZ0xeOGdMUshnTFaYZ0xV2GdMWEhnTFmYZ0xWCGdMUvhnTFW4Z0xeiGdMW1hnTFMIZ0xRGGdMWThnTFWoZ0xduGdMU9hnTFFYZ0xeKGdMVMhnTFl4Z0xXaGdMXkhnTFcIZ0xWSGdMWRhnTF7oZ0xcuGdMUUhnTFnIZ0xfKGdMWbhnTFRoZ0xS6GdMVuhnTF3oZ0xcKGdMXchnTFK4Z0xReGdMVVhnTF8YZ0xW+GdMX9hnTF0oZ0xXmGdMWkhnTFOIZ0xRKGdMUohnTF1YZ0xQ6GdMW3hnTFvIZ0xYKGdMWVhnTFKoZ0xYeGdMWwhnTFCYZ0xUKGdMUlhnTFO4Z0xUeGdMV/hnTFC4Z0xUmGdMW6hnTFq4Z0xW2GdMX2hnTFgIZ0xSmGdMVohnTFfoZ0xVSGdMWDhnTFT4Z0xfeGdMUzhnTF64Z0xT+GdMVXhnTFLYZ0xTaGdMX/hnTF2YZ0xSOGdMWuhnTFyoZ0xdGGdMW+hnTFtIZ0xcyGdMWvhnTFMoZ0xZ6GdMUNhnTFwIZ0xSaGdMXBhnTFxoZ0xZaGdMXQhnTFfYZ0xXeGdMWshnTFEIZ0xemGdMXfhnTFToZ0xeeGdMXwhnTF4IZ0xXyGdMVehnTFGIZ0xUiGdMX5hnTF5oZ0xaOGdMXUhnTFlIZ0xe2GdMUThnTFcYZ0xZCGdMVQhnTF+oZ0xf6GdMWNhnTFc4Z0xbGGdMWqhnTFHoZ0xVyGdMWnhnTFv4Z0xQ+GdMVshnTFUoZ0xbiGdMXDhnTF/IZ0xeyGdMWihnTF84Z0xQiGdMVAhnTFmIZ0xcWGdMUahnTFvYZ0xTeGdMUchnTFHYZ0xXqGdMV0hnTFdYZ0xT6GdMWFhnTFzYZ0xZ+GdMWzhnTFiIZ0xciGdMXThnTFmoZ0xVaGdMXJhnTF1oZ0xTSGdMXYhnTF5YZ0xXuGdMU8hnTFJIZ0xQSGdMWKhnTF+IZ0xXKGdMUGhnTFAIZ0xaGGdMUnhnTF74Z0xZKGdMUHhnTFDIZ0xWeGdMWmhnTF6oZ0xbmGdMUhhnTFU4Z0xYaGdMUFhnTFeIZ0xYmGdMVihnTFZYZ0xTqGdMUfhnTFgYZ0xSKGdMVDhnTFRIZ0xbKGdMXOhnTFYYZ0xa2GdMVZhnTFnYZ0xRmGdMWghnTF+4Z0xTGGdMVjhnTFz4Z0xQqGdMW2hnTFOYZ0xY+GdMXXhnTFaoZ0xWaGdMWLhnTFUYZ0xdqGdMWlhnTFTYZ0xaiGdMWphnTFAYaD6d+ig2jfooNA36KDLt+ig/zfooMT36KDud+ig+TfooNv36KDN9+ig3PfooMB36KDDd+ig7ffooPI36KDMd+ig2DfooMi36KD+d+ig4HfooNb36KDbd+ig3/fooNm36KDrt+ig53fooOE36KDh9+igx7fooNK36KDvt+igwjfooP236KD7t+ig4bfooPc36KDPd+ig83fooPB36KDmt+igwLfooOX36KDWN+ig5bfooMQ36KD09+ig9rfooNS36KDP9+ig5vfooPA36KD6t+igxHfooMD36KDsN+ig3XfooMz36KD1N+ig07fooM736KDDt+ig7rfooNV36KDg9+ig5jfooMA36KDxN+igyDfooP336KDxt+igyjfooPb36KDy9+igyrfooOV36KDft+ig/3fooNG36KDK9+igyffooP/36KDeN+igzbfooOU36KDtt+ig6jfooN336KDGN+igwTfooNR36KDcd+igxXfooMj36KDC9+ig4nfooM436KDjd+ig13fooOh36KDrN+igzrfooNq36KDKd+ig9/fooNX36KDMt+ig5nfooOP36KDq9+ig2TfooNW36KDPN+ig6PfooNw36KDL9+igwrfooNy36KDst+ig/LfooM536KD6N+ig+DfooPV36KDWt+ig8nfooMX36KDQd+igz7fooM036KD69+igwzfooP+36KDgt+ig0vfooOS36KDs9+ig1PfooMW36KDXt+ig6XfooN736KD4t+ig+HfooN636KDUN+ig9DfooPM36KDk9+ig2nfooNF36KDwt+igw/fooNH36KD5t+ig8PfooPX36KDgN+ig/DfooN236KDed+igxvfooMd36KDVN+ig3TfooP736KDbN+ig6LfooMS36KDQt+ig47fooPW36KDkN+ig+3fooOK36KDJt+igy3fooO136KD49+igwffooN936KDLN+ig7HfooNP36KD+t+ig2HfooMw36KDRN+igzXfooOL36KDyt+igxrfooNN36KD5d+ig9HfooNI36KDBd+igxTfooPF36KDu9+ig7zfooNf36KDBt+ig0nfooMk36KDH9+ig63fooOm36KDTN+ig27fooP436KDtN+ig8/fooMJ36KDpN+ig5/fooMc36KDzt+ig2XfooNi36KD3t+ig4XfooO936KD79+ig/TfooN836KDQ9+ig6DfooPS36KDqt+ig5HfooOe36KDa9+igxnfooPd36KDnN+ig/XfooPH36KD2N+ig7jfooPz36KDWd+ig/HfooOI36KDv9+ig6ffooOp36KDJd+ig1zfooNj36KDZ9+ig+zfooOv36KD59+ig4zfooMh36KD2d+iCkHbtZtB27WWQdu180HbtTdB27UbQdu1dkHbtXtB27XvQdu1Z0HbtUVB27U2Qdu1dUHbtbxB27U1Qdu1XkHbtX9B27UcQdu14kHbtexB27WEQdu1uUHbtZRB27VWQdu1GEHbtQ5B27UMQdu1c0HbteVB27U0Qdu12EHbtY9B27U8Qdu1GUHbtfBB27VBQdu1WkHbtehB27X/Qdu1L0HbtStB27X+Qdu1B0Hbtd9B27UuQdu1D0HbtU9B27UGQdu1TUHbteRB27UqQdu1aEHbtYdB27XPQdu1iEHbtShB27WhQdu1GkHbtTlB27XOQdu1UUHbtUBB27UkQdu1EkHbteNB27WvQdu1YEHbtT9B27VcQdu1o0HbtWpB27WtQdu1/UHbtRFB27XXQdu1C0HbtSxB27WSQdu1pUHbtZpB27XmQdu1zEHbtZ5B27UTQdu17UHbtd5B27XKQdu1OkHbtcdB27XcQdu1g0HbtSVB27VSQdu1dEHbtclB27V+Qdu1QkHbtfZB27WsQdu1BEHbtXBB27XTQdu1vUHbtfpB27WgQdu1IUHbtaZB27UDQdu1gEHbtZxB27UtQdu1BUHbtSdB27VyQdu1bkHbtRdB27WQQdu1ekHbtT5B27VIQdu1YUHbtfdB27X0Qdu1aUHbtcBB27XaQdu1jEHbtcZB27UfQdu1skHbtb5B27UBQdu1wUHbtXlB27UiQdu1xUHbtbRB27UQQdu1Y0HbtflB27WqQdu1q0HbtdFB27UUQdu1JkHbtWJB27W3Qdu1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vc9KkL3PSvu9z0oFvc9KVr3PSpm9z0rBvc9KH73PSm69z0rivc9Ky73PSpq9z0r6vc9KQb3PSiq9z0pmvc9KbL3PStO9z0pOvc9Kzr3PSnO9z0rqvc9Kib3PStC9z0oZvc9KeL3PSpy9z0ruvc9KD73PSge9z0pJvc9K673PSoe9z0p8vc9KYb3PSjS9z0rzvc9K0r3PSke9z0prvc9Kqr3PSh69z0oYvc9K/L3PSia9z0q1vc9Keb3PSry9z0pDvc9K5b3PSty9z0p/vc9KhL3PSua9z0rAvc9Kp73PStS9z0qMvc9KQL3PSum9z0oBvc9KDr3PSkK9z0o6vc9Kor3PSji9z0r3vc9Kob3PSi29z0pevc9KcL3PShu9z0qFvc9Kxr3PSmK9z0rKvc9Kkb3PSii9z0rCvc9K7b3PSim9z0rxvc9K773PSui9z0rhvc9KPb3PSo29z0ptvc9KWb3PSiW9z0oEvc9KLr3PSt29z0o1vc9KRr3PSrK9z0pQvc9Knb3PSqu9z0rRvc9KDb3PSju9z0o3vc9Kd73PSme9z0oivc9Kw73PSt69z0qwvc9KUr3PSn69z0oavc9K9L3PSuO9z0qYvc9Kqb3PSj+9z0q2vc9KSr3PSoG9z0owvc9Kz73PSlO9z0qlvc9K2L3PSlW9z0q9vc9KEL3PShG9z0ocvc9KTb3PSnG9z0rwvc9KAL3PSpa9z0oCvc9KpL3PSr69z0oLvc9K/r3PSuS9z0q5vc9Kn73PSmS9z0qovc9K1r3PSru9z0qAvc9Kar3PSpe9z0pIvc9Kk73PSgy9z0ppvc9KOb3PSjK9z0plvc9KtL3PSiu9z0pUvc9KaL3PSpu9z0rVvc9Kj73PSv29z0qjvc9KxL3PSoq9z0rMvc9KL73PSva9z0pcvc9Kur3PSvW9z0q3vc9KRb3PSte9z0pPvc9KCL3PSgq9z0q/vc9KFL3PSha9z0rJvc9Kjr3PSiG9z0osvc9Knr3PStq9z0r4vc9Kr73PSnK9z0qIvc9K573PSn29z0o2vc9K2b3PShW9z0pEvc9KE73PSnS9z0r/vc9Krb3PSjG9z0rFvc9KBr3PSli9z0o+vc9KlL3PSiS9z0rgvc9KIL3PSqC9z0p6zYuf0s3Bn9LNA5/Szdaf0s0rn9LNsJ/SzcCf0s3On9LNjp/SzWef0s3tn9LNGJ/SzX+f0s3in9LNtJ/SzUOf0s31n9LNbZ/SzdCf0s2ln9LNR5/SzTCf0s2pn9LNGZ/SzR2f0s3Pn9LNu5/SzVaf0s0vn9LNyZ/SzZyf0s2Cn9LNyp/SzVWf0s12n9LNop/SzaGf0s3qn9LNOZ/SzUif0s2Vn9LN8p/Szaif0s2Zn9LN1J/SzZCf0s10n9LNzJ/SzWWf0s14n9LNYp/SzWGf0s0gn9LNip/SzWif0s3Dn9LN7J/SzVOf0s0mn9LNgJ/SzYyf0s1Jn9LNNZ/SzUWf0s24n9LNHJ/Szeef0s3Fn9LNBZ/SzQKf0s06n9LNpp/Szd2f0s0un9LNvJ/SzUKf0s1mn9LNr5/SzV2f0s1Nn9LNUZ/SzX2f0s0zn9LNCp/Szbqf0s3pn9LNT5/SzWyf0s3hn9LNdZ/SzRuf0s1Sn9LN85/Szfyf0s3gn9LNv5/SzZaf0s3Ln9LNIZ/Szfuf0s3an9LNgZ/SzUuf0s1an9LNCJ/SzSef0s2Xn9LNsZ/SzWCf0s3jn9LNWJ/SzZOf0s23n9LNyJ/SzfGf0s0pn9LNoJ/SzVSf0s1vn9LNPZ/SzVef0s0Qn9LNY5/SzTaf0s2rn9LNJJ/SzV+f0s2tn9LN+J/SzW6f0s3Zn9LNDp/SzR+f0s2sn9LNLZ/SzTuf0s2+n9LNqp/SzeWf0s36n9LNFZ/SzdGf0s0Jn9LNhJ/SzZKf0s3Sn9LNPJ/Szb2f0s1rn9LNlJ/SzT+f0s1Zn9LNcJ/Szdyf0s39n9LNZJ/SzQ+f0s1qn9LNEp/SzSqf0s0Gn9LNo5/Szeuf0s1En9LNpJ/SzYif0s3Nn9LNE5/SzR6f0s2en9LNc5/Szfaf0s15n9LNmp/SzcKf0s1+n9LN+Z/SzVuf0s0En9LNd5/SzVCf0s0yn9LNQJ/SzRqf0s0jn9LNcp/SzZ2f0s16n9LN6J/SzVyf0s04n9LN15/SzTGf0s1Mn9LNfJ/SzbKf0s3mn9LNtp/SzbWf0s0ln9LNAJ/Szcaf0s3wn9LNxJ/Szfef0s0Bn9LNjZ/SzSyf0s1Bn9LNIp/SzQuf0s2Hn9LNEZ/SzZif0s3+n9LNhp/SzeSf0s3/n9LNn5/SzYOf0s0Xn9LN25/SzYmf0s3fn9LNcZ/SzU6f0s0Hn9LNrp/SzRSf0s0Nn9LNPp/SzY+f0s1Gn9LNXp/Szbmf0s30n9LN3p/Szdif0s3vn9LNx5/SzSif0s3Vn9LNDJ/SzRaf0s00n9LNp5/SzXuf0s2Rn9LNaZ/SzYWf0s2bn9LN05/SzUqf0s2zn9LNN5/Sze6f0pa7KrIyuyqyP7sqsla7KrIZuyqyW7sqsiW7KrKAuyqyTbsqski7KrJVuyqy0bsqsge7KrJ/uyqy57sqsi27KrJxuyqypbsqsuy7KrK4uyqy77sqsgS7KrJYuyqyCLsqsnO7KrKkuyqyJLsqsu27KrKHuyqy2Lsqsg+7KrLjuyqyUrsqskm7KrL9uyqy9bsqspe7KrLpuyqynrsqsgK7KrIRuyqyyLsqstS7KrInuyqyr7sqsse7KrJQuyqyHrsqsgO7KrKUuyqyjbsqsiq7KrIiuyqy5bsqsp27KrIWuyqywLsqspq7KrK6uyqyCrsqsme7KrJhuyqyOrsqsjG7KrKYuyqyN7sqsj27KrJCuyqy1bsqsja7KrLMuyqy+7sqspy7KrKzuyqyLLsqsvO7KrKouyqy8bsqsrS7KrLXuyqyIbsqsny7KrJ7uyqycrsqsm27KrKJuyqy+LsqsmO7KrJOuyqyTLsqsgy7KrIzuyqym7sqso67KrLNuyqyNbsqst27KrKIuyqyALsqsr27KrL3uyqy2rsqsni7KrJsuyqyybsqsqu7KrJPuyqyRbsqsqO7KrIcuyqyYLsqsp+7KrIbuyqyw7sqsqG7KrINuyqy3Lsqsi67KrIduyqyPLsqshe7KrIGuyqysbsqsq67KrLPuyqyj7sqssu7KrLFuyqy5Lsqsta7KrLGuyqyELsqspO7KrK3uyqyorsqssS7KrJ+uyqykbsqsji7KrKGuyqy6LsqssK7KrJvuyqyYrsqske7KrImuyqyPrsqsvq7KrIBuyqy/7sqsg67KrJruyqyBbsqspC7KrLguyqy/Lsqstm7KrIvuyqyersqskS7KrJKuyqyhbsqsq27KrKVuyqyX7sqsgm7KrKLuyqykrsqsvS7KrJluyqy3rsqshW7KrIjuyqyZLsqsku7KrJuuyqyNLsqstO7KrI5uyqyubsqslq7KrLmuyqyFLsqsoS7KrJwuyqy27sqsvC7KrJRuyqyv7sqsn27KrLruyqymbsqslO7KrLquyqysLsqsoO7KrIYuyqysrsqsna7KrKKuyqy37sqsrW7KrLOuyqyvrsqsl67KrLQuyqy", + "K7sqsu67KrLhuyqyoLsqsv67KrKmuyqy+bsqsqq7KrIfuyqyXLsqsl27KrIouyqyarsqsoy7KrJAuyqyZrsqskO7KrKpuyqy9rsqsju7KrJpuyqy0rsqshq7KrJ0uyqyV7sqslS7KrJGuyqyKbsqskG7KrK7uyqyebsqssG7KrKnuyqydbsqshK7KrJouyqyvLsqshO7KrILuyqygbsqsiC7KrIwuyqyWbsqsqy7KrJ3uyqy8rsqsuK7KrKCuyqyyrsqsra7KrLNklqqzZJJqs2SYKrNkhWqzZK+qs2SNqrNkl2qzZK4qs2S76rNkg6qzZIYqs2Sk6rNkl6qzZIwqs2SEarNkqeqzZIWqs2S0qrNkvSqzZIhqs2SRqrNkimqzZLOqs2SrKrNkiuqzZJ8qs2SXKrNkhCqzZKfqs2SrqrNkuqqzZKVqs2SZarNkvWqzZIgqs2ShKrNkvKqzZJUqs2S6KrNksCqzZLRqs2SaqrNkkKqzZI6qs2SJKrNkh2qzZK0qs2SyqrNkn+qzZJ+qs2ScKrNko6qzZIsqs2S56rNkhOqzZIHqs2Se6rNknmqzZKkqs2SHqrNkl+qzZJtqs2SjarNksOqzZIiqs2Ss6rNkjSqzZIMqs2SY6rNknGqzZIvqs2Sr6rNkuGqzZLsqs2S+6rNkhSqzZIEqs2SRKrNkjWqzZIcqs2SAKrNkkeqzZKCqs2SYarNkpqqzZLVqs2S2qrNkgOqzZL8qs2St6rNknOqzZJ3qs2StqrNkv+qzZJZqs2S+KrNklOqzZJVqs2Si6rNks2qzZJFqs2SW6rNkt+qzZLiqs2SBarNksyqzZLrqs2SmKrNkoWqzZIaqs2STKrNktaqzZLFqs2S+qrNkpeqzZKyqs2Su6rNknaqzZK5qs2Sa6rNki6qzZLcqs2SnKrNkveqzZKHqs2SO6rNksmqzZLBqs2SLarNkk6qzZLgqs2SgKrNkr2qzZIXqs2SbqrNksuqzZI8qs2SKqrNkhmqzZJ0qs2SJarNkk2qzZKMqs2SlqrNkuWqzZKSqs2SQarNkj2qzZJAqs2SMqrNkuOqzZIBqs2S8KrNksaqzZJWqs2SSqrNkv2qzZK/qs2S0KrNkkuqzZLbqs2SkarNksiqzZIPqs2S3arNkg2qzZKhqs2SWKrNkjGqzZI4qs2S1KrNkoaqzZKBqs2SM6rNkvOq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", + ) + /** consts, base64, 1 chunk(s) — concatenate in order. */ + val constsChunks: List = listOf( + "eC1jbG91ZGtpdC16b25lc2dyb3VwTWVtYmVycy1rZXn//wAA//8AAP//AAD//wAAY29udGVudF9iYXNlX3VybEludmFsaWRCbXBTdHJpbmdjb2xsZWN0aW9ubWV0YWRh/////////3//////////f2hvcml6b250YWxfYWNjdXJY5NADoTZcgw6euN0FKUjlY29tLmFwcGxlLmdzLmlkbWxpY0VuY3J5cHRpb25LZXlIYW5kc2hha2VGYWlsdXJlbmVlZHNUb1Jlc29sdmVWYW9udENvbmZpZ3VyYXRpb25TaW1wbGlmaWVkUG9zdGVyc2Vzc2lvbklkZW50aWZpZUlDQyBBdXRoIGZhaWxlZCEAAAAAAAAAANAAAAAAAAAAWC1BcHBsZS1JLVRpbWVab39/f39/f39/f39/f39/f38gISIjJCUmJygpKissLS4vEBASEhQUFhYYGBoaHBweHgABAgMAAQIDAAECAwABAgOo5XmVzaVnyDTYCI2nfJiCMlqYNzJamDcuuPw0Lrj8NAwEOVUnowWL9nEW/3KmTh+/yiQqeYjTTOOPFbIhBt0lrdfmQ7/08boTNK0srdfmQ+ob5ylIw8Fdix+q+jlaTGj+pwCAzwQAgA0CAID//w2Ab4l78nRdvnKxlhY7/rHegCYVGmzK3hL/iNwKzMBH/NUsIC4uLiwgaXNfcmVzZXQ9U3RyZWFtRGVwZW5kZW5jeagAAAAAAAAAuAAAAAAAAAAADwAPAA8ADwAPAA8ADwAPgAAAAAAAAACAAAAAAAAAAAUAAAAAAAAABQAAAAAAAABhZGRfY2VydCBlcnJvcjogYmFja2dyb3VuZENvbG9yRGNvbS5hcHBsZS5zZWN1cmVTaGFyZWRCZWFjb25SZWNvdGV4dC94LXhtbC1wbGlzdFJlZ2lzdGVyIGZhaWxlZCBtXcvWLFDrY3hBpldxG4u5ZXhwaXJ5X3RpbWVzdGFtcCwgcmVtYWluaW5nKCkgPSBjYW5XaXBlQWZ0ZXJMb2NrQ2lyY2xlU3RlcDAudW5rMwEAAAADAAAAAAAAAAAAAABEZWNyeXB0aW9uRmFpbGVkPwAAAAAAAAA/AAAAAAAAAEludmFsaWRQcmtMZW5ndGhCYWQgc3RyaW5nIHR5cGUhj/nKbVeoCsvq5KnFZAaRbHdlYkFjY2Vzc0VuYWJsZWRQUlRWUFJUVmBiZGZgYmRmSW52YWxpZEZpZWxkTmFtZXN0YWNrIGJhY2t0cmFjZTouuPw0Lrj8NC64/DQFX1giMlqYNy64/DQuuPw0Lrj8NG59T3+ppI7+NjYGZ/Uwf/l0ae02XwFkOxM0rSzktZaPXwFkOxM0rSzktZaP5LWWj1vCVjnxEfFZpII/ktVeHKsHBgUEAwIBAA8ODQwLCgkISW5hY3RpdmVTdHJlYW1JZGJiYmJiYmJiYmJiYmJiYmJjYW5ub3RfYmVfYV9iYXNlY3Npc29sYXRpbmFyYWJpYw8PDw8PDw8PDw8PDw8PDw/dDv4PUkfsQoKMiIQNlOv4Zbtu3Xy+yx12w7ddF+U4mmNvbm5lY3Rpb24uc3RhdGUBAAAAAAAAAC4AAAAAAAAA/////wUAAFAAAAAAAQAAgFVuc3VwcG9ydGVkRW1wdHkAFAEAWxQBAF0UAQBhFAEAtwAAALcAAABQBAEAfwQBAAARAQA0EQEANhEBAEcRAQAACAAALQgAADAIAAA+CAAALmdudV9kZWJ1Z2FsdGxpbhAU/f8ACP3/AAD9/7Ds/P9iYXRjaERhdGVDcmVhdGVkZXNfd2FsbHBhcGVyX3RhZ2RldmljZVJlc29sdXRpb25ncm91cF9waG90b19ndWlkAAAAAAAAAAD//////////01hc3RlckJlYWNvblJlY29YLUFwcGxlLUdTLVRva2VucHJla2V5X3dyYXBfbW9kZUludmFsaWRBcmd1bWVudHNQcnVuaW5nIGV4cGlyZWQhbG9jYXRpb25GaW5pc2hlZGRldmljZURpc2NvdmVyeUlsYXN0SW5kZXhPYnNlcnZhUENTS2V5U2V0LmtleXNldEV4Y2VlZHNNYXhMZW5ndGhzdGVkUGhvbmVOdW1iZXJzcm1fc2VyaWFsX251bWJlcmVOdW1iZXJpbmdTeXN0ZW1JbmNvbWluZ01lc3NhZ2VzSUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAACT2MqkpLzBSmhQ/zRNy/hS9PX29wAAAAAAAAAAAAAAANrQkXaaBh/EZz44FEYkQprnQ7t27Zn9F7Ck5JcMmwL40nJDTnQB+VVgtgIog+Msq6Yp2MYAAAAAiWJffBIjF/lRy9X5KrJ5wd+MxvvN8kMYAAAAAAAAAAACAAAAAAAAALJZsz4ikvZfIpL2XxYUdmIvO03sz/vAtbzbiYGl27XpV1dXV1dXV1cAAAAAAAAAAOHFaJJgyb6iNCz6xjxyXKhoMjo6RXJyb3I6OmlzX2lv/////40AAFAAAAAAAAAAgAgAAAAIAAAACAAAAAgAAADtIe1neoZZYPj8nSTfE5tmc2NyaXB0ZXh0ZW5zaW9ucy91c3Ivc2hhcmUvem9uZWlwcm90b2NvbF92ZXJzaW9uLXB1YmxpYy1pZGVudGl0eWJhY2t1cC50aW1lc3RhbXBrZ3JvdW5kSW1hZ2VEYXRhQ2FycmllckVudGl0bGVtZWpqampqampqampqampqamr/////////AP//////////SW5zZXJ0IGtleSB1dWlkIE1pc3NpbmdMaWJyYXJpZXNBdXRoQ2VydFJlc3BvbnNldFNlZW5NZXNzYWdlR3VpZG1vZGVsRGlzcGxheU5hbWVhc3NvY2lhdGVkQmVhY29uMwMH3NTcIE2GldljIpjDK3N5bmNfYXR0YWNobWVudHNwbGF0Zm9ybV9zZXJpYWxfd2FzUmVwb3J0ZWRBc0p1bm5zZmVyTWVzc2FnZUdVSURjb25maWd1cmF0aW9uVVVJU2VuZGluZyBjb3VudGVyIA0ODxAAAAAAAAAAAAAAAAANHQshCREbBRUHGR8DFw8TPjJwglK0toVRtXwQcGND26C0c04cuKSvJoKeEmA8nLNrD5qVENnrr1zWNsYxkdUArdfmQ+S1lo8TNK0sC/4+hfAJBO0Z2iePmK96DtYnYXRvR6FMP4MMM1406NR9buGPMDEyMzQ1Njc4OUFCQ0RFRjr0nSftKWhy/kystwUfCFcgd2hlbiBleHBlY3RpbmcgQm9keVdyaXRlQWJvcnRlZAAAAAAAAAAABAAAAAAAAAD/////DYAA/AEAAHgBAAC4LzHs3xi8Khb51u3udOu2qP3oACAwHjAIBgYqhQMCAgkyNTUxOSBjb2xsaXNpb25zVVVVVVVVVVVVVVVVVVVVVXNlbnRlbmNldGVybWluYWxgCwEAcgsBAHgLAQB/CwEAgAgBAJ4IAQCnCAEArwgBAHJpbmdfY2lyY2xlX3R5cGVpY2VTZWNvbmRhcnlBdXRoRGlkIGNpcmNsZSBzdGVwIC1rZXkAAAAAAAAAAAAAAABMb2dTcGVjaWZpY2F0aW9uQXNzZXRHZXRSZXNwb25zZWQAAAAAAAAAAAAAAAAAAABObyByZWNvcmQgZm91bmQ/Q2xvdWRQYXJ0aWNpcGFudF8ZDrgYueJLKcWPj9w1Rl10cnVuY2F0ZWRfa2V5X2lkc29mdHdhcmVfdmVyc2lvbmdldF8yZmFfc21zX29wdHNUcmFuc2NyaXB0RHluYW1pY2xvY2tJbnRlcnNlY3Rpb3ByZWZlcnJlZFRpdGxlQWwBAAAAAQAAAAAAAAAAAAAAZXJhYmxlRGVsZXRlRGF0ZXdhbGxwYXBlckxvd1Jlc0ZLZP/9faga1T99EDJpmzF27u7u7u7u7u7u7u7u7u7u7tDS1NbQ0tTW4OLk5uDi5OYwMjQ2MDI0NkBCREZAQkRGBQYHCAAAAAAAAAAAAAAAAGsFXqEuuPw0Lrj8NDJamDcuuPw0awVeoS64/DQuuPw05+Ql2R1W8JlHiFTu+tnVVhSDWGPw6CquU9MO9PEGfpj3eTsSU8xG/Mt7l97aC2NZswwcOUqq2E5Pypxb828uaAEBAAAAAAAAAAAAAAAAAACn9f//i/D//wAH///rBf//XAsAAO4fAAAAIAAAKiEAAAoAAAAAAAAADwAAAAAAAABVbmtub3duRXh0ZW5zaW9uAAAAAQAAAAAAAAABAAAAAFNFVFRJTkdTX1RJTUVPVVQBAAAAAAAAABUAAAAAAAAA/////wAAAAAAAAAAAAAAgExhenlTdGF0ZUlERXJyb3JMb3dlcmNhc2VfTGV0dGVyABEAAF8RAABgqQAAfKkAAGRfc2VjcmV0AAAAAAAAAABwdWJsaWMtbWVzc2FnZS1pdmlkZW9Db21wbFN0aWxsRHBhcmFsbGF4RGlzYWJsZWQAADBDAAAwRQAAAAAAAAAAdF9pbmRleF9vYnNlcnZlZGV4dGVuc2lvbklkZW50aWZ0aW1lRm9udElkZW50aWZpTWVzc2FnZUVuY3J5cHRlZE1lbWJlclNoYXJpbmdDaXJpcy1jMmstZXF1aXBtZW50R3Vlc3RNb2RlVXBkYXRlZC1zAM1iG7s3jUDcg9y6dc9qb2luLW5vdGlmaWNhdGlvbW9kbmFyb2RzZXR5YmRldAEBAQEBAQEBAQEBAQEBAQFwZWVyX3NpZ25pbmdfa2V5bGVnYWN5R3JvdXBJZGVudG93bmVyQmVhY29uSWRlbnRzaGFyaW5nQ2lyY2xlVHlw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zRABAGVudGl0eSBub3QgZm91bmRmaWVkLWRlbGl2ZXJ5LXYxdGl0bGVfY29uZmlndXJhdGlzLWluaXRpYXRvci1rZXkAAAAAAAAwRQAAAAAAADBFAAAQAAAAMEUAABAAAAAwRTY2NjY2NjY2NjY2NjY2NjYCAAAAAgAAAAIAAAACAAAAQmVhY29uTmFtaW5nUmVjb093bmVyU2hhcmluZ0NpcmNDb250ZW50LUVuY29kaW5nZmlyc3QvaW5pdENsaWVudGludml0YXRpb25BY2NlcHRhbGlnbWVudF9wcm90X3RhAAAAAAAAAAABAAAAAAAAAPAAAAAAAAAA8AAAAAAAAABzYXZlX2F0dGFjaG1lbnRzawAAAAAAAAAAAAAAAAAAAFxcXFxcXFxcXFxcXFxcXFygAAAAAAAAABAnAAAKAAAAAAEAAQQFBAUAAQABBAUEBUBBQEFERURFQEFAQURFREVx8U0qU/3t4L9QxjiKB1WxvEF6oC0Bu7+x/F8jkSEC+m1lLPPQQdhn6D3UnaZvEf87DGzy3INJPUcgdgObYB3FrdfmQ18BZDsTNK0s5LWWj7/08bq/9PG65LWWj63X5kOh6L+iS2YaqHCLS8KjUWzH+v++kOtsUKT3o/m+8nhxxldXV1dXV1dXV1dXV1dXV1dlbmNvZGVkIHNldHRpbmdzU2Vzc2lvblRpY2tldEFjayBpcyBub3Qgb3BlbmVkOzsA9///ABD+/wAB//8A8P7/dmlzaXRlZF9jYXBhY2l0eV8gAABfIAAAADAAAAAwAAAAMAEAVTQBAGA0AQD6QwEAsAQBANMEAQDYBAEA+wQBAGVyAAAAAAAAAAAAAAAAAABiYWNrZ3JvdW5kSW1hZ2VEQ2FycmllcnNCeU1jY01uY3kAAAAAAAAAAAAAAAAAAAB1ZXNwZW1vc2FyZW5lZ3lsRmFpbGVkIHRvIHBhcnNlIGNvbS5hcHBsZS5xdWlja3RCYWQgcmVjZWlwdCB0eXBlYWRtaW5pc3RyYXRpdmVBcnJ1c3RTaGFyZWRTZWNyZXRzZWN1cmVMb2NhdGlvbnNTTG9jYXRlSW5Qcm9ncmVzc1NlY3VyZUJhY2t1cFVzZXNDYWNoZWQga2V5cyBmb3IgdmFsaWRhdGVfdGFyZ2V0c05vIE1lc3NhZ2UgYm9keSFwZXJtYW5lbnREZWxldGVD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dGlvbmRhdGX///////8A////////////AAAAAAMAAAAAAAAAAAAAABAAAAAAAAAAKAAAAAAAAABObyB1cGxvYWQgaW5mbz8/aXNDb25zaWRlcmVkQWNjZXRpbWVGb250Q29uZmlndXJ0aXRsZUNvbnRlbnRTdHlsQ2xvdWRLaXREZWNyeXB0aWNvbnRlbnQtbG9jYXRpb25pc1NjaGVkdWxlZE1lc3NheC1pZC1zdWItc2VydmljZUFQUyBwYXJzZSBlcnJvciBDYXBhY2l0eU92ZXJmbG93ZGVjcnlwdGlvbiBlcnJvckludmFsaWRDb250YWluZXJC4ajUauoyBpfaUutEK0xwUgh2ynLVJ54zRK/mKtZjpmM9I58mMZx9Hf7SdPNHPOit1+ZDC/4+heS1lo+t1+ZDYzsQkZf0e/h9e+HYuoDQ1Q88b4dkIO1+EMIijOa6lgMODwwNAgMAAQYHBAUKCwgJH2ZEh0vIqUliljLLgvIa9fhyulmdJroqDdhOQqc5bSMAAAAA/////wAAAAD/////Y29udGVudC1sYW5ndWFnZUZSQU1FX1NJWkVfRVJST1IBAAAAAAAAACgAAAAAAAAAHPIAgP8PAoD/CACA/9cAgHNpZ25hbCB0b28gbGFyZ2VpZHN1bmFyeW9wZXJhdG9ycmFuZ2UgZW5kIGluZGV4IGxhc3RPYnNlcnZlZEluZGVzaG91bGRGb3JjZVRvU01TcmQAAAAAAAAAAAAAAAAAAGxlAAAAAAAAAAAAAAAAAABhbmdlVG9rZW5FeHBpcmVkYXBwbGljYXRpb24vanNvbnNlYXJjaFBhcnR5VG9rZW4aPLB8zJODDRM7GwSLYuJwdXJpLXRvLXBhcnRpY2lwYWlzb19jb3VudHJ5X2NvZGVlc3NhZ2VfdGltZXN0YW1wLWFkdmVydGlzZWRJbmRleHNlcnZlcl9zdWdnZXN0RGVob25lTnVtYmVyV2ViVXJsZ2V0X2JlYWNvbl9pdGVtc3RpbWVOdW1iZXJpbmdTeXNjcHUuY2ZzX3F1b3RhX3VzAAAAAAAAAAAAAAAAAAAAAWluYWN0aXZlVGltZVJlY3RJbnZhbGlkIHBhZGRpbmchyuUer1myQENDQ1lFKwQM61gtQXBwbGUtSS1DbGllbnSwsrS2sLK0tsDCxMbAwsTGkJKUlpCSlJagoqSmoKKkpmJhZCBkYXRhIGxlbmd0aCE3Tox/+DEDIlWCLW2AwyVdLrj8NDJamDcuuPw0Lrj8NNvF2VP4y3VGGerC4pn8wqXzzkOBJvW5vgg0x8ifNiYBMpfJ7q+81DmuuLCjld0137/08brktZaP5LWWjwv+PoVvP0kJ4YLPDvHpMt/wqM/oRWfn+GtqW98a89bqe/ebOQMAAQIHBAUGCwgJCg8MDQ5CAgOjmKoH2L5vcEUBW4MSS2V5VXBkYXRlUmVxdWVzdFJlc3VtaW5nIHNlc3Npb24A8ADwAPAA8ADwAPAA8ADw/w//D/8P/w//D/8P/w//D2lzX3BlbmRpbmdfcmVzZXQAAPr/AAD5/wAA+P8AAPf//////y2AANAAAAAQAQAAqAAAAP8AAAD/AAAA/wAAAP9TaWdFZDI1NTE5IG5vIEVkgBUBALUVAQC4FQEA3RUBAIAbAAC/GwAAwBwAAMccAACoEQAA/xEAAMvXAAD71wAAgBYBALkWAQDAFgEAyRYBAHgAAAAAAAAAAAAAAAAAAABiZXJTaGFyaW5nQ2lyY2xlRmlsZVBhY2thZ2VFcnJvckludmFsaWRJQTVTdHJpbmdsYXN0X2FkZHJlc3NlZF9oaW1zZ05pY2tuYW1lUHVibGRldmljZURpc3BsYXlOYW1hdGlvbl9pZGVudGlmaWVyX19fX19fX18AAAAAAAAAAGwAAAAAAAAAAAAAAAAAAABzZXNNdWx0aXBsZWlDU0NzZW5jb2RlX2NoYXRwcm90b3BsYXRmb3JtX3V1aWRfZW5VSUNvbG9yQ29tcG9uZW50SU1GaWxlVHJhbnNmZXJDcnJlY292ZXJhYmxlRGVsZXRJbnZhbGlkIGNoYW5uZWw/AQIDBAAAAAAAAAAAAAAAACUAJQAlACUAJQAlACUAJQCQkZKTlJWWl5iZmpucnZ6fDFco8aH4a8VxaAqKQDDB+UREREREREREREREREREREQJCbyZffWDZIhASRqguLoY3d8y5ZKM+fO/Accr2FmW79KSOH+uvoVpZj4stmIgvaqJZ7bIYMXvq8pv9PnmWH9mgpF+13e2a+EsmU0u3dPN5FGwjaI/LdMIN1bZ09Wf47O5FXiHPvHtFfLZ6bGOiCbsivgBfDDcZp733U+mloVkuaor4f83Ubeds6g6SgyuweFfAWQ7rdfmQxM0rSwktbk/zyGtdOWaYRG+HYwCHmW4kVNlcnZlckVDREhQYXJhbXN4LXhzcy1wcm90ZWN0aW9uSW50ZWdlclVuZGVyZmxvd2Nsb3NlcHVuY3R1YXRpb24AAQEAAQEBAJAvAQDyLwEAABoAABsaAAAeGgAAHxoAAKAWAADqFgAA7hYAAPgWAAAHBwcHBwcHBwcHBwcHBwcHYmVhY29uX2lkZW50aWZpZWF0aW9uLWlkZW50aWZpZXJyaWVyRW50aXRsZW1lbnRzAAAAAAAAAAAkAAAAAAAAgHJpbmdDaXJjbGVTZWNyZXRzaG93LXBlZXItZXJyb3JzaXNfaW5pdGlhdG9yX2tleVByb3h5LUNvbm5lY3Rpb25zZWNzX3NpbmNlX2Vwb2NocnRpY2lwYW50LWlkLWtleUN1dHRsZWZpc2hSZWNvcmRvcmlnaW5hbF9ncm91cF9pR3JvdXBJZGVudGlmaWVyc21lc3NhZ2VIYW5kc2hha2VzZWNvbmRhcnlfcmF0Y2hlY29ycmVsYXRpb25faWRlbmNvbW11bmljYXRpb25zSWRtPw+spsnVYnys3altg3eAZGVjb2RlX2NoYXRwcm90b05ld1Nlc3Npb25UaWNrZXQBAAAAAAAAAAAAAAABAAAASU1GaWxlVHJhbnNmZXJGaXJpY2hMaW5rSXNQbGFjZWh3YWxscGFwZXJGaWxlTmFtY291bnRlciBvdmVyZmxvd0RlY29kZVV0ZjE2RXJyb3JYLUFwcGxlLUktTUQtUklOJiQqKC4sMjAmJCooLiwyMP//////////AP////////8gAAAAAAAAACAAAAAAAAAA/////+Mdm/z//////////8jome4BXrhAOrOmABhHUwl1EqdiTMc4mvUEpyUO/iNssozdAC2yRzHV1IzEAD956QUFpfj8NdsyiFVPmRSFi5z+iVk0whfNY6OFz+egZ/Cl2S+9TXOFM2WWJky5ybJ9qwoKCgoKCgoKAAAAAAAAAAAzMzMzMzMzMzMzMzMzMzMz2wX//9YF//+QBf//1gT//4gAAAAAAAAAmAAAAAAAAAABAAAAAAAAACkAAAAAAAAAbWF4IHNpemUgcmVhY2hlZAICAgMAAAAAAAAAAAAAAABmaW5hbHB1bmN0dWF0aW9uWiAAAFogAACAAgEAnAIBAAAJAQAbCQEAHwkBAB8JAQCAqgAA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ZXNldAAA/v8AAP3/AAD8/wAA+/8HAAAAAAAAAAEAAAAAAAAARWFzdF9Bc2lhbl9XaWR0aC9zaGFyZS96b25laW5mby8uZGVidWdfbWFjcm8uZHdvLXJlZnJlc2gtc2Vjb25kc2RGb3JOYW1lAAAAAAAAAABlX3VzYWdlX2J5X21lZGlhdGFfaW5mb19pbl9ieXRlc2UAAAD0AQAAZwAAAGYAAABTZWN1cmVPYmplY3RTeW5jbnVtYmVyT2ZUaW1lc1Jlc2hvcml6b250YWxBY2N1cmFCZWFjb25JZGVudGlmaWVyX3N1Z2dlc3REZWxldGlvblBlcm1pc3Npb25EZW5pZWRjb21wYXJlX2NvbnRlbnRzUGhvdG9Qb3N0ZXJMYXllcldhbGxwYXBlclVwZGF0ZUsDAAAAAAAAAAMAAAAAAAAAZGVsZXRlSW5jb21pbmdNZUlNRmlsZVRyYW5zZmVyTG9taXNzaW5nIHRhZyBmb3Ig0NHS09TV1tfY2drb3N3e32sFXqEuuPw0Lrj8NC64/DQuuPw0Lrj8NC64/DQuuPw0/b/Fm53KcVXIQ1JMlglvhUunSDvJp71f3k2Rak9uiK1wUQ2PaN/Hvy02LCd9miaeAJoHLDMo0BQrUFrpH3VFxgv+PoVju90aJLW5P7/08brzC+DGR5Gn1VFjygZnKSkUVHMKZbsKanYuycKBhSxykjAwMDAwMDAwAAAAAAAAAAB1dXV1dXV1dXV1dXV1dXV1j6eo/ocxFDY7ubz7AQIIIxoAAIABAACAAgAAgAsAAIAvdXNyL2xvY2FsL3NoYXJlYWxsb3dfaGFsZl9jbG9zZWD///8AIP//EAL//wAA//9Yfk3HHMb72xIwBN1q+9jTVHJ5RnJvbUNoYXJFcnJvcgAbAABMGwAAThsAAH8bAACAqAAAxagAAM6oAADZqAAAcGoBAL5qAQDAagEAyWoBAFN0cmlwUHJlZml4RXJyb3Lx/wAA8f8AAPH/AADx/wAA/wD/AP8A/wAAAAAAAAAAAGt0LWxvZ2dhYmxlLWRhdGFzdXBwb3J0cy1jZXJ0aWZp////f////3////9/////f3RhQXNzZXRUeXBlRmxhZ3NNU0Fzc2V0TWV0YWRhdGFBc3RvcmFnZV9pbl9ieXRlc0lsbGVnYWxQYXJhbWV0ZXJsaW1pdGVkUHJlY2lzaW9uEoGbPEUJ8Bj/sKiCRwFpPmdlSGFuZHNoYWtlU3RhdGVmYWxsYmFja1RvTGVnYWN5c2VjdXJlTG9jYXRpb25zQ2UAAAAAAAAAAAAAAAAAAABDaXJjbGVJZGVudGlmaWVyc1Xaj/WtFivimSVAwjztQGxvY2F0ZUluUHJvZ3Jlc3NwY3NwdWJsaWNpZGVudGl0bnNfbnVtYmVyX2RlY29kZW50AAAAAAAAAAAAAAAAAABoYXNUb3BFZGdlQ29udGFjc3RpY2tlckVmZmVjdFR5cGRhdGFSZXByZXNlbnRhdGlOU011dGFibGVEaWN0aW9uc2lnIGNoZWNrIGZhaWxlZFBhcnNlR3JvdXBMZW5ndGigAQAAAAAAAHACAAAAAAAAEBIUFhASFBYgIiQmICIkJv////////////////8AAABJbnZhbGlkIGNoZWNrc3VtKCzZ+kkvPIH9bdHK/qKVo5z3EIn1OZsN+Ou7GND4krEsLZsJzU+OD7LWoVhUdaguv/Txuq3X5kMktbk/XwFkO8Fpm+SGR77vxp3BD8yhDCT/////AAD/AP//gICAAAcCwqIRFnq7jF4HngniyKgznM33zDDrrnLjNEpu9/8VS4xVcGdyYWRlIFJlcXVpcmVkRU9GIG9uIHNlbGYtcGlwZVdvcmRFbmRIYWxmQXNjaWlSZXZlcnNlREZBRW5naW5lVGl0bGVjYXNlX0xldHRlckALAQBVCwEAWAsBAF8LAQCgGAEA8hgBAP8YAQD/GAEALWV4cGlyZXMtc2Vjb25kc0NvbG9yRGVzY3JpcHRpb25tb25vZ3JhbVN1cHBvcnRlZXNjcm93ZWRfc2lnbmluZ2F1dGhlbnRpY2F0aW9uLXJtZQAAAAAAAAAAAAAAAAAAc3RvcmFnZV91c2FnZV9ieQAAAAAAADBDAAAAAAAAMENTaGFyaW5nQ2lyY2xlU2VjAAAAAA0AAAAAAAAAEAAAAGVzcG9uZGVkdG9UaHJlYWRpY3YyAAAAAAAAAAAAAAAAZm9ybWF0dGVkQWRkcmVzc2VhAAAAAAAAAAAAAAAAAAAtYWNjZXB0YW5jZVN0YXRlbnNfc3RyaW5nX2VuY29kZVJlc29sdmVWYXJpYXRpb25maWVsZCBpZGVudGlmaWVySW5kZWZpbml0ZUxlbmd0aFBDU0F0dHJpYnV0ZS5rZXlsYXlv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8ADwACyxHi7k0IhInrx7CO4pyJogIG5vdGlmeWluZyB0YXNrcmVjdl9lb2Y7IHN0YXRlPQEAAAAAAAAANwAAAAAAAABg1wCA0B0AgA4CAID+/wCAR2VuZXJhbF9DYXRlZ29yeVphbmFiYXphcl9TcXVhcmXQ5QEA+uUBAP/lAQD/5QEAdGlvbnNfaWRlbnRpZmllcm4AAAAAAAAAAAAAAAAAAABhY2NlcHRhbmNlX3N0YXRlcwAAAAAAAAAAAAAAAAAAAGtleWNoYWluX2lkZW50aWb/////AAAAAP////8AAAAAAgICAgICAgICAgICAgICAgAAAAAAAAAALAAAAAAAAIB1cGRhdGVkIGtleXMhISEKQ29ubmVjdGlvbkNsb3NlZGNoYXQxTWFuYXRlZVpvbmUoAAAAAAAAABAAAAAAAAAAQ3V0dGxlZmlzaENoYW5nZVJlY29yZElkZW50aWZpZXJ0AAAAAAAAAAAAAAAAAAAAQ2lyY2xlU3RlcDEuYm9keUludmFsaWRCaXRTdHJpbmd1bmlxdWVfZGV2aWNlX2lkY2VydGlmeV9kZWxpdmVyeU1pc3NpbmdFeHRlbnNpb25jb250ZW50c0x1bWluZW5jo6SlpgAAAAAAAAAAAAAAAAABAgMEBQYHCAkKCwwNDg9gYWJjYGFiY2BhYmNgYWJjTG9jYXRpb25MaXN0VHlwZdZvjtu0oy/Jo6nZla6dqKRrBV6hLrj8NC64/DRrBV6hc/0A+tgnI0ECBOLj/JRPOgBo+g433l8EZZc6oFEdrLjttZzzTpX3S99Y9Q6FSOB8swtIJ/Q95OGS98ZeaPkcy8Lp7N/DB7jpAmEDIoW5ukiQ/P//gfz//5Df//8A1P//BAAAAAAAAAAAAAAAAAAAAHRdvnL+sd6Apwbcm3Txm8FvLOktqoR0StypsFzaiPl2UXVldWU6OnB1c2hfYmFja01hbGZvcm1lZEhlYWRlcnMAAAAAAAAAAJYV5MYBAAAAAQAAAAAAAAAcAAAAAAAAAAAAgD8AAIA/AACAPwAAgD/ExKXBF9zVybJGxsZh3XTCwBsAAPMbAAD8GwAA/xsAAAANAQAnDQEAMA0BADkNAQAAqQAALakAAC+pAAAvqQAAc3VjY2Vzc2Z1bF9xdWVyeVgtTW1lLUNsaWVudC1JbmZLZXlBbGlnbm1lbnRSZWNvOm93bmVyQGxvY2FsaG9zdFgtQXBwbGUtSEItVG9rZW5nb3QgSURTIG1lc3NhZ2UgY29udGV4dC1kYXRhLWtleXJrAAAAAAAAAAAAAAAAAABJbnZhbGlkQ3JsTnVtYmVyYWN0aXZhdGlvbkxvY2tlZGRfYmVhY29uc19jbGllbnRuc19zaGFyZWRfc2VjcmV0SW52YWxpZFhtbFN5bnRheHBhc3Njb2RlR2VuZXJhdGlnZXRfZW50aXRsZW1lbnRzZWRpdENvbmZpZ3VyYXRpb3dhbGxwYXBlck1ldGFkYXRwcm90b2NvbC12ZXJzaW9uUGFyc2VJbnZhbGlkVVRGOD8/Pz8/Pz8/Pz8/Pz8/Pz+mpKqorqyysKakqqiurLKwXDWHtNAvI+k9sDenCasRbHd3d3d3d3d3d3d3d3d3dXeNmE4W+5ehOZAXiB+WD7L1sBU2cxjnXB48B4z00RRdNf/P//8AB///EAL//wAA///K8ODC3MhAZmRaxPLoykDWcmVxd2VzdDo6Y29ubmVjdCAgICAgICAgICAgICAgICA=", + ) +} diff --git a/registration/src/main/kotlin/dev/fenn/imessage/registration/ClearAnisetteProvider.kt b/registration/src/main/kotlin/dev/fenn/imessage/registration/ClearAnisetteProvider.kt new file mode 100644 index 0000000..6a51356 --- /dev/null +++ b/registration/src/main/kotlin/dev/fenn/imessage/registration/ClearAnisetteProvider.kt @@ -0,0 +1,364 @@ +package dev.fenn.imessage.registration + +import dev.fenn.imessage.codec.Plist +import dev.fenn.imessage.codec.XmlPlist +import dev.fenn.imessage.ids.IdsHttp +import dev.fenn.imessage.ids.IdsHttpResponse +import java.util.Base64 +import java.util.UUID +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive +import kotlinx.serialization.json.put + +/** Provisioning or header derivation failed (wire shape per anisette_clearadi.rs, flow ref). */ +class ClearAdiProvisioningException(message: String, cause: Throwable? = null) : Exception(message, cause) + +/** + * Persistence seam for the provisioned state (the `AnisetteState` of the reference — + * reference/apple-private-apis/omnisette/src/anisette_clearadi.rs, MPL-2.0 — persisted there + * as a plist file; here a JSON string, because open-madrid is a pure JVM library with no + * Context to derive a files dir from). The caller owns the storage location. + */ +interface ClearAdiStateStore { + /** Persist the JSON (overwrite); called after every successful provisioning. */ + fun save(json: String) + + /** The last saved JSON, or null when nothing was stored yet. */ + fun load(): String? +} + +/** + * The per-request identity inputs the reference's `ClearADIClient.login_info` carries + * (anisette_clearadi.rs §ClearADIClient/build_apple_request). + */ +data class ClearAdiLoginInfo( + /** `User-Agent` — the reference's `akd_user_agent`. */ + val akdUserAgent: String, + /** `X-Mme-Client-Info` — also decides the flavor: "iPhone OS" ⇒ IOS, else Mac. */ + val mmeClientInfo: String, + /** Extra hardware headers appended verbatim after the fixed set (reference: `hardware_headers`). */ + val hardwareHeaders: Map = emptyMap(), +) + +/** + * The provisioning outcome: `finish()`'s raw ProvisionedData plus the response's routing info. + * The ProvisionedData→{client_secret, mid, metadata} mapping is TODO(live-capture) (one + * OpenBubbles provisioning run under gdb) — the raw 0x78 bytes are carried as-is and the + * mapping lives nowhere until then. + */ +data class ClearAdiProvisionResult( + val provisionedData: ProvisionedData, + val rinfo: String, +) + +/** State JSON of [ClearAdiProvisionResult] (hex ProvisionedData + rinfo; mapping TODO). */ +fun resultToJson(result: ClearAdiProvisionResult): String = buildJsonObject { + put("provisioned_data", result.provisionedData.raw.joinToString("") { "%02x".format(it) }) + put("rinfo", result.rinfo) +}.toString() + +fun resultFromJson(json: String): ClearAdiProvisionResult { + val o = Json.parseToJsonElement(json).jsonObject + val hexData = o["provisioned_data"]!!.jsonPrimitive.content + require(hexData.length >= 0x78 * 2) { "stored provisioned_data shorter than 0x78 bytes" } + val raw = ByteArray(hexData.length / 2) { i -> + ((Character.digit(hexData[i * 2], 16) shl 4) or Character.digit(hexData[i * 2 + 1], 16)).toByte() + } + return ClearAdiProvisionResult(ProvisionedData(raw), o["rinfo"]!!.jsonPrimitive.content) +} + +/** + * The header factory over a provisioned machine: the real OTP derivation + * ([ClearAdiOtp.anisetteOtp]) behind the repo's [AnisetteOtp] seam, plus the anisette header + * map of the reference's `AnisetteData::get_headers` (anisette_clearadi.rs, transcribed 1:1: + * client time ISO-8601 with a trailing `Z`, fixed UTC/en_US, rinfo from the state, the UUID + * form of the 16-byte keychain identifier as `X-Mme-Device-Id`). + * + * Takes (metadata, mid, flavor) directly — the ProvisionedData→fields mapping is + * TODO(live-capture), so the caller wires them once the capture names the bytes. + */ +class ClearAdiAnisette( + val metadata: ByteArray, + val mid: ByteArray, + val flavor: Int, + val rinfo: String, + private val keychainIdentifier: ByteArray, + /** `X-Mme-Client-Info` — also the flavor decider of the reference. */ + val clientInfo: String = "", + private val clock: () -> Long = { System.currentTimeMillis() }, +) : AnisetteOtp { + + /** The real derivation — the one-time identifier input is unused (the OTP is time-windowed). */ + override fun otp(input: AnisetteOtpInput): ByteArray = + ClearAdiOtp.anisetteOtp(flavor, metadata, mid, clock() / 1000) + + /** The header map, in the reference's get_headers order. */ + fun headers(): Map { + val otpBytes = otp(AnisetteOtpInput(mid, ByteArray(0))) + if (otpBytes.isEmpty()) throw AnisetteException("OTP derivation returned no bytes for X-Apple-I-MD") + val out = LinkedHashMap() + out["X-Apple-I-Client-Time"] = iso8601Z(clock()) + out["X-Apple-I-TimeZone"] = "UTC" + out["X-Apple-Locale"] = "en_US" + out["X-Apple-I-MD-RINFO"] = rinfo + out["X-Mme-Device-Id"] = uuid(keychainIdentifier) + out["X-Apple-I-MD"] = Base64.getEncoder().encodeToString(otpBytes) + out["X-Apple-I-MD-M"] = Base64.getEncoder().encodeToString(mid) + out["X-Mme-Client-Info"] = clientInfo + return out + } + + companion object { + private fun uuid(bytes: ByteArray): String { + require(bytes.size == 16) { "keychain identifier must be 16 bytes" } + val bb = java.nio.ByteBuffer.wrap(bytes) + return UUID(bb.long, bb.long).toString() + } + } +} + +/** ISO-8601 with the trailing `Z` the reference's get_headers produces (`%+`, +00:00 → Z). */ +internal fun iso8601Z(epochMs: Long): String = + java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'") + .withZone(java.time.ZoneOffset.UTC) + .format(java.time.Instant.ofEpochMilli(epochMs)) + +/** ISO-8601 with the `+00:00` offset the reference's build_apple_request produces (`%+`). */ +internal fun iso8601Offset(epochMs: Long): String = + java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'+00:00'") + .withZone(java.time.ZoneOffset.UTC) + .format(java.time.Instant.ofEpochMilli(epochMs)) + +/** + * The persisted provisioning result (reference `ProvisionedAnisette`): the machine tokens the + * anisette headers derive from plus the server-assigned routing info. Serialized as a JSON + * object of base64/hex/string fields — the reference serializes a plist with `Data` fields; + * the JSON key names mirror its serde names. + */ +data class ProvisionedAnisette( + val clientSecret: ByteArray, + val mid: ByteArray, + val metadata: ByteArray, + val rinfo: String, + /** 0 = Mac, 1 = IOS (ClearAdiOtp's flavor convention; the reference's ProvisionedFlavor). */ + val flavor: Int, +) { + fun toJson(): String = buildJsonObject { + put("client_secret", Base64.getEncoder().encodeToString(clientSecret)) + put("mid", Base64.getEncoder().encodeToString(mid)) + put("metadata", Base64.getEncoder().encodeToString(metadata)) + put("rinfo", rinfo) + put("flavor", flavor) + }.toString() + + companion object { + fun fromJson(json: String): ProvisionedAnisette { + val o = Json.parseToJsonElement(json).jsonObject + fun b64(key: String) = Base64.getDecoder().decode(o[key]!!.jsonPrimitive.content) + return ProvisionedAnisette( + clientSecret = b64("client_secret"), + mid = b64("mid"), + metadata = b64("metadata"), + rinfo = o["rinfo"]!!.jsonPrimitive.content, + flavor = o["flavor"]!!.jsonPrimitive.content.toInt(), + ) + } + } +} + +/** + * The wire-level ClearADI anisette provider — the Kotlin counterpart of the reference + * `ClearADIClient::provision` (reference/apple-private-apis/omnisette/src/anisette_clearadi.rs, + * MPL-2.0; the file is the flow reference, the .so is the wire ground truth): + * + * 1. `GET https://gsa.apple.com/grandslam/GsService2/lookup` → XML plist → + * `urls.{midStartProvisioning, midFinishProvisioning}` + * 2. `POST ` with body `{"header":{}, "request":{}}` (XML plist, + * `Content-Type: application/x-www-form-urlencoded` — "not a bug, it's how you *think + * different*", reference) → `Response.spim` (base64) + * 3. [Spim.parse] the spim → `payload240` → [ClearAdiProvision.initSession] → session context + * 4. [Cpim.build] with 124 RNG bytes (32/32/60), an empty extra blob and the GSA arg −2 → + * base64 into `request.cpim` → `POST ` → `Response.{ptm, tk, X-Apple-I-MD-RINFO}` + * 5. `tk` must be exactly 16 B (finish 17f1e31, error 0x8); key16 = `encrypt(session, NULL iv, + * tk)` (17f1eac); [ClearAdiProvision.decryptPtm] over the parsed Ptm payload → raw + * [ProvisionedData] + * + * The ProvisionedData→token-field mapping and the Cpim tail fields are the two remaining + * TODO(live-capture) items; they are modeled honestly in [ClearAdiFraming] and surfaced here + * as [cpimTailSeal] (required) and [finishSeed] (defaults to zero bytes). + */ +class ClearAnisetteProvider( + private val http: IdsHttp, + private val stateStore: ClearAdiStateStore, + private val loginInfo: ClearAdiLoginInfo, + private val rng: ClearAdiRng, + private val cpimTailSeal: CpimTailSeal, + /** Seed passed to decryptPTM (finish 17f2557's rcx) — zero bytes pending the live capture. */ + private val finishSeed: ByteArray = ByteArray(16), + /** 16 random bytes identifying this client (reference `keychain_identifier`). */ + private val keychainIdentifier: ByteArray = rng.draw(16), + private val clock: () -> Long = { System.currentTimeMillis() }, +) { + + /** Load the stored state, or provision it through the GSA round trips. */ + suspend fun ensureProvisioned(): ClearAdiProvisionResult { + stateStore.load()?.let { return resultFromJson(it) } + val result = provision() + stateStore.save(resultToJson(result)) + return result + } + + /** The full start/finish provisioning exchange; persists nothing (caller decides). */ + suspend fun provision(): ClearAdiProvisionResult { + val urls = lookupUrls() + + val startBody = XmlPlist.encode(mapOf("header" to emptyMap(), "request" to emptyMap())) + val startResponse = exchange("start-provisioning", urls.startProvisioning, startBody) + val spimB64 = responseString(startResponse, "Response", "spim") + val spim = Spim.parse(Base64.getDecoder().decode(spimB64.trim())) + val sessionCtx = ClearAdiProvision.initSession(spim.payload) + + // omnisette passes extra = [] and the GSA arg −2 (reference provision()). + val cpim = Cpim.build(rng, extra = ByteArray(0), gsaArg = GSA_ARG, sessionCtx, spim.payload, cpimTailSeal) + val finishBody = XmlPlist.encode( + mapOf( + "header" to emptyMap(), + "request" to mapOf("cpim" to Base64.getEncoder().encodeToString(cpim)), + ), + ) + val finishResponse = exchange("finish-provisioning", urls.finishProvisioning, finishBody) + val response = responseDict(finishResponse) + val ptm = Base64.getDecoder().decode(requireString(response, "Response", "ptm").trim()) + val tk = Base64.getDecoder().decode(requireString(response, "Response", "tk").trim()) + val rinfo = requireString(response, "Response", "X-Apple-I-MD-RINFO") + + if (tk.size != 16) { + throw ClearAdiProvisioningException("tk not exactly 16 bytes (${tk.size} B; finish 17f1f11, error 0x8)") + } + val parsed = Ptm.parse(ptm) + val key16 = ClearAdiProvision.encrypt(sessionCtx, null, tk) + // count = payload.size / 16 (finish 17f2548); ProvisionedData is the first 0x78 B of + // the decrypted output (17f2dec–17f2e56) + val blocks = parsed.payload.size / 16 + val data = ClearAdiProvision.decryptPtm(key16, parsed.payload.copyOfRange(0, blocks * 16), finishSeed) + return ClearAdiProvisionResult(ProvisionedData(data.copyOf(0x78)), rinfo) + } + + /** The reference's fixed request-header set (`build_apple_request`, transcribed 1:1). */ + fun buildAppleRequestHeaders(nowEpochMs: Long): Map { + val out = LinkedHashMap() + out["User-Agent"] = loginInfo.akdUserAgent + out["X-Apple-Baa-E"] = "-10000" + out["X-Apple-I-MD-LU"] = hex(sha256(keychainIdentifier)) + out["X-Mme-Device-Id"] = uuid(keychainIdentifier) + out["X-Apple-Baa-Avail"] = "2" + out["X-Mme-Client-Info"] = loginInfo.mmeClientInfo + // The reference formats %+ here (…+00:00) and only the get_headers half rewrites to Z. + out["X-Apple-I-Client-Time"] = iso8601Offset(nowEpochMs) + out["Accept-Language"] = "en-US,en;q=0.9" + out["X-Apple-Client-App-Name"] = "akd" + out["Accept"] = "*/*" + out["Content-Type"] = "application/x-www-form-urlencoded" + out["X-Apple-Baa-UE"] = "AKAuthenticationError:-7066|com.apple.devicecheck.error.baa:-10000" + out["X-Apple-Host-Baa-E"] = "-7066" + out.putAll(loginInfo.hardwareHeaders) + return out + } + + /** The anisette header values (reference `AnisetteData::get_headers`, transcribed 1:1). */ + fun anisetteValues(state: ProvisionedAnisette, nowEpochMs: Long): Map = + ClearAdiAnisette( + metadata = state.metadata, + mid = state.mid, + flavor = state.flavor, + rinfo = state.rinfo, + keychainIdentifier = keychainIdentifier, + clientInfo = loginInfo.mmeClientInfo, + ) { nowEpochMs }.headers() + + /** Flavor decision of the reference (anisette_clearadi.rs provision()): mme_client_info. */ + val flavor: Int get() = if (loginInfo.mmeClientInfo.contains("iPhone OS")) FLAVOR_IOS else FLAVOR_MAC + + private suspend fun lookupUrls(): ProvisioningUrls { + val url = "https://$GSA_HOST/grandslam/GsService2/lookup" + val response = http.get(url, buildAppleRequestHeaders(now())) + if (response.status != 200) { + throw ClearAdiProvisioningException("lookup GET $url → HTTP ${response.status}") + } + val root = try { + Plist.parse(response.body) + } catch (e: Exception) { + throw ClearAdiProvisioningException("lookup response is not a plist: ${e.message}", e) + } + val urls = dictOrNull(root, "urls") + ?: throw ClearAdiProvisioningException("lookup plist has no urls dict") + return ProvisioningUrls( + startProvisioning = requireString(urls, "midStartProvisioning"), + finishProvisioning = requireString(urls, "midFinishProvisioning"), + ) + } + + private suspend fun exchange(step: String, url: String, body: ByteArray): IdsHttpResponse { + val response = http.post(url, buildAppleRequestHeaders(now()), body, "application/x-www-form-urlencoded") + if (response.status != 200) { + throw ClearAdiProvisioningException("$step POST $url → HTTP ${response.status}") + } + return response + } + + /** Wall clock, injectable for tests (epoch ms). */ + internal fun now(): Long = clock() + + private fun sha256(bytes: ByteArray): ByteArray = java.security.MessageDigest.getInstance("SHA-256").digest(bytes) + + private fun hex(bytes: ByteArray): String = bytes.joinToString("") { "%02x".format(it) } + + /** `Uuid::from_bytes(identifier)` of the reference — the hyphenated lowercase form. */ + private fun uuid(bytes: ByteArray): String { + require(bytes.size == 16) { "keychain identifier must be 16 bytes" } + val bb = java.nio.ByteBuffer.wrap(bytes) + return UUID(bb.long, bb.long).toString() + } + + private data class ProvisioningUrls(val startProvisioning: String, val finishProvisioning: String) + + private fun responseString(response: IdsHttpResponse, vararg path: String): String = + requireString(responseDict(response), *path) + + private fun responseDict(response: IdsHttpResponse): Map { + val root = try { + Plist.parse(response.body) + } catch (e: Exception) { + throw ClearAdiProvisioningException("response is not a plist: ${e.message}", e) + } + @Suppress("UNCHECKED_CAST") + return root as? Map + ?: throw ClearAdiProvisioningException("response plist root is not a dict") + } + + private fun dictOrNull(map: Any?, key: String): Map? { + @Suppress("UNCHECKED_CAST") + return (map as? Map)?.get(key) as? Map + } + + private fun requireString(map: Map, vararg path: String): String { + var cur: Any? = map + for (key in path) { + @Suppress("UNCHECKED_CAST") + cur = (cur as? Map)?.get(key) + ?: throw ClearAdiProvisioningException("plist path ${path.joinToString(".")} missing at $key") + } + return cur as? String + ?: throw ClearAdiProvisioningException("plist path ${path.joinToString(".")} is not a string") + } + + companion object { + const val GSA_HOST = "gsa.apple.com" + /** The GSA arg the omnisette reference passes (`ProvisioningSession::new(&spim, &[], -2, …)`). */ + const val GSA_ARG: Long = -2L + const val FLAVOR_MAC = 0 + const val FLAVOR_IOS = 1 + } +} diff --git a/registration/src/test/kotlin/dev/fenn/imessage/registration/ClearAdiOtpTest.kt b/registration/src/test/kotlin/dev/fenn/imessage/registration/ClearAdiOtpTest.kt new file mode 100644 index 0000000..22585a5 --- /dev/null +++ b/registration/src/test/kotlin/dev/fenn/imessage/registration/ClearAdiOtpTest.kt @@ -0,0 +1,177 @@ +package dev.fenn.imessage.registration + +import kotlin.test.Test +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals + +/** + * Golden vectors captured from the reference white-box via a local ctypes oracle + * (dev-only; inputs are the deterministic LCG streams of /tmp/clearadi-re/oracle.py). + */ +class ClearAdiOtpTest { + + private fun stream(seed: Int, n: Int): ByteArray { + val out = ArrayList(n) + var x = seed.toLong() and 0xffffffffL + while (out.size < n) { + x = (1103515245L * x + 12345L) and 0xffffffffL + out.add((x and 0xff).toByte()) + out.add(((x ushr 8) and 0xff).toByte()) + out.add(((x ushr 16) and 0xff).toByte()) + out.add(((x ushr 24) and 0xff).toByte()) + } + return out.toByteArray().copyOf(n) + } + + private fun hex(s: String): ByteArray = + ByteArray(s.length / 2) { ((Character.digit(s[it * 2], 16) shl 4) or Character.digit(s[it * 2 + 1], 16)).toByte() } + + private fun toHex(b: ByteArray): String = b.joinToString("") { "%02x".format(it) } + + private val one400 = stream(1, 0x190) + private val one208 = stream(2, 0xD0) + private val two32 = stream(3, 32) + + // ---- tables.json ---- + + private val gentableExpected = hex( + "15c3bd38a696ba62679c556a977f711ed5a108e600a6c0a568d8293b98e803c2" + + "a0b915578171b4e616ad03305ad15dbcfa1393f404be058ce834a7c8aa67b493" + + "d0ce116c2d953961d97c248190638d43fd48b29375106a356469d36498b95426" + + "043467b08038d02edd6994f63ac0d8207634d32e434ab71368de32ae66480ff6" + + "b87f3e981620118f6bffebe1e7d93d563fc2be3bae2e4fbc79f3c342723fe8c0" + + "649f663c66d9127388a75b7082230791931f9cf1a5d0ebe0942d4801d6be68e3" + + "397e22c7c780f3c2d9d40ea65773063262bc92c6aec24a4b441ac4e55e91907a" + + "bcf1e911a8afe98be888c801a40911ccca39156e2e059f6974b0d928d9222c49" + + "a6890936b479aa2dc2eac9833cd3a18230e36f9dc9442b4679527fdc37b1a2c3" + + "5f23c680f9256a17a063d8fa8f00b5c9f06287756af01dcb2c054cc8d2f5d7dc" + + "05edf58ae5e9dad658fea553b4e4dd335ec6443de4b736b8d8b9d4884d7fd4df" + + "098ad959b06985e02b255367381cc53e52c17c971ac860621d37b8a50e0f0e16" + ) + + private val gensourceExpected = mapOf( + 0u to hex( + "2eeaa70b34574c7e98474a24904c5d8976f987bf8457ad10e7eee5f44be2421c" + + "910451b7c13440ee8704e7beeca9c9c330d50baf6100bd06853b65dd6ff95abc" + + "6ff81fa1be6591beb67a7447ff1b6ce1986fdd5265e81383e2f0a5b850da1f20" + ), + 1u to hex( + "2eeaa70b34574c7e98474a24904c5d8976f987bf8457ad10e7eee5f44be2421c" + + "910451b7c13440ee8704e7beeca9c9c330d50baf6100bd06853b65dd6ff95abc" + + "6dcacca23c3b4404cb920ce9f826f7b98173917ef6aa372e8cff4d6c5929e889" + ), + 12345u to hex( + "2eeaa70b34574c7e98474a24904c5d8976f987bf8457ad10e7eee5f44be2421c" + + "910451b7c13440ee8704e7beeca9c9c330d50baf6100bd06853b65dd6ff95abc" + + "7174088a2ee0687227a1c64eab240e0964c4d866d1dc8b869c9d0e2f5366dfe5" + ), + ) + + @Test + fun gentableMatchesOracle() { + val ctx = ByteArray(0x320) + ClearAdiOtp.genTable(ctx, one400) + assertContentEquals(gentableExpected, ctx.copyOfRange(0x130, 0x2b0)) + } + + @Test + fun gensourceMatchesOracle() { + for ((gen, expected) in gensourceExpected) { + val ctx = ByteArray(0x320) + ClearAdiOtp.genSource(ctx, two32, gen) + assertContentEquals(expected, ctx.copyOfRange(0x2c0, 0x320), "gen=$gen") + } + } + + // ---- otp.json (gen_otp / IOS flavor) ---- + + private val genOtpExpected = mapOf( + 0u to "00669cc21c0bd8a670b5959ce58a87bf", + 1u to "e6f70fc4fdb2435a935651582b9c970a", + 12345u to "3bb75405b8512c3f56ec6b824172f26d", + 1467106968u to "14699fcb5b79c8808a3e01334b5f845e", + 375889u to "3878efa22001c4d7f90215088f2e303a", + ) + + @Test + fun genOtpMatchesOracle() { + for ((gen, expected) in genOtpExpected) { + val out = ClearAdiOtp.genOtp(gen, one400, two32) + assertEquals(expected, toHex(out), "gen=$gen") + } + } + + @Test + fun genOtpReadsOnlyFirst0x190BytesOfOne() { + // oracle cross-check: gen_otp(gen=12345, one400+one208) == gen_otp(gen=12345, one400) + val out = ClearAdiOtp.genOtp(12345u, one400 + one208, two32) + assertEquals("3bb75405b8512c3f56ec6b824172f26d", toHex(out)) + } + + // ---- gen_code (0x1801360) ---- + + @Test + fun genCodeIsSha1OverSigAnd60ByteSecret() { + val sig = stream(5, 16) + val secret = stream(4, 60) + val md = java.security.MessageDigest.getInstance("SHA-1") + val expected = md.digest(sig + secret) + val h0 = ((expected[0].toInt() and 0xff) shl 24) or ((expected[1].toInt() and 0xff) shl 16) or + ((expected[2].toInt() and 0xff) shl 8) or (expected[3].toInt() and 0xff) + val h1 = ((expected[4].toInt() and 0xff) shl 24) or ((expected[5].toInt() and 0xff) shl 16) or + ((expected[6].toInt() and 0xff) shl 8) or (expected[7].toInt() and 0xff) + val h01 = ((h0.toLong() and 0xffffffffL) shl 32) or (h1.toLong() and 0xffffffffL) + assertEquals(((h01 % 1_000_000L).toInt()).toUInt(), ClearAdiOtp.genCode(sig, secret)) + } + + // ---- frame shape (generate_otp 0x17ee2a0) ---- + + @Test + fun anisetteOtpFrameLayout() { + val t = 1_700_000_123L // fixed time -> gen = t/30 + val frame = ClearAdiOtp.anisetteOtp(1, one400, two32, t) + assertEquals(28, frame.size) + assertEquals(5, ((frame[0].toInt() and 0xff) shl 24) or ((frame[1].toInt() and 0xff) shl 16) or + ((frame[2].toInt() and 0xff) shl 8) or (frame[3].toInt() and 0xff)) + assertEquals(16, ((frame[4].toInt() and 0xff) shl 24) or ((frame[5].toInt() and 0xff) shl 16) or + ((frame[6].toInt() and 0xff) shl 8) or (frame[7].toInt() and 0xff)) + assertEquals(1, frame[27].toInt() and 0xff) + val expectedSig = ClearAdiOtp.genOtp((t / 30).toInt().toUInt(), one400, two32) + assertContentEquals(expectedSig, frame.copyOfRange(8, 24)) + } + + @Test + fun twoFactorCodeMatchesGenCodeOfFrameSig() { + val t = 1_700_000_123L + val secret = stream(4, 60) + val frame = ClearAdiOtp.anisetteOtp(1, one400, two32, t) + val expected = ClearAdiOtp.genCode(frame.copyOfRange(8, 24), secret) + assertEquals(expected, ClearAdiOtp.twoFactorCode(1, one400, two32, secret, t)) + } + + // ---- gen_otp_ios (Mac flavor) ---- + + @Test + fun genOtpIosMatchesOracle() { + val expected = mapOf( + 0u to "7dfb116f698533c668332b936158feb5", + 1u to "3cd08c5ff781a4778cd971933b12a658", + 12345u to "1b971539b155d6da131dab2c237374f7", + 1467106968u to "2fbf0ad480a1c05716725c7146c0ae17", + 375889u to "404ff1905e7fab582b19a6ed77d168a7", + ) + assertEquals(5, expected.size) + for ((gen, hex) in expected) { + val got = toHex(ClearAdiOtp.genOtpIos(gen, one208, two32)) + assertEquals(hex, got, "gen=$gen") + } + } + + @Test + fun anisetteOtpMacFlavorUsesGenOtpIos() { + val frame = ClearAdiOtp.anisetteOtp(0, one208, two32, 0L) + val expected = ClearAdiOtp.genOtpIos(0u, one208, two32) + assertContentEquals(expected, frame.copyOfRange(8, 24)) + assertEquals(0, frame[26].toInt()); assertEquals(0, frame[27].toInt()) + } +} diff --git a/registration/src/test/kotlin/dev/fenn/imessage/registration/ClearAdiProvisionTest.kt b/registration/src/test/kotlin/dev/fenn/imessage/registration/ClearAdiProvisionTest.kt new file mode 100644 index 0000000..3eb6af0 --- /dev/null +++ b/registration/src/test/kotlin/dev/fenn/imessage/registration/ClearAdiProvisionTest.kt @@ -0,0 +1,534 @@ +package dev.fenn.imessage.registration + +import kotlin.test.Test +import kotlin.test.assertContentEquals + +/** + * Golden vectors captured from the reference white-box via a local ctypes oracle + * (dev-only; inputs are the deterministic LCG streams of /tmp/clearadi-re/oracle.py). + */ +class ClearAdiProvisionTest { + + private fun hex(s: String): ByteArray = + ByteArray(s.length / 2) { ((Character.digit(s[it * 2], 16) shl 4) or Character.digit(s[it * 2 + 1], 16)).toByte() } + + private fun wordsOf(b: ByteArray): IntArray = IntArray(4) { i -> + (b[4 * i].toInt() and 0xff) or ((b[4 * i + 1].toInt() and 0xff) shl 8) or + ((b[4 * i + 2].toInt() and 0xff) shl 16) or ((b[4 * i + 3].toInt() and 0xff) shl 24) + } + + private fun toBytes(w: IntArray): ByteArray = ByteArray(16).also { ob -> + for (i in 0 until 4) { + ob[4 * i] = (w[i] and 0xff).toByte() + ob[4 * i + 1] = ((w[i] ushr 8) and 0xff).toByte() + ob[4 * i + 2] = ((w[i] ushr 16) and 0xff).toByte() + ob[4 * i + 3] = ((w[i] ushr 24) and 0xff).toByte() + } + } + + private val spimIn = hex( + "e88e85d301b9d830a6436b2ce791ac1094b1982d3de496dc32f4f7e98365a6bb" + + "0053195f398712677e212d97dfd6df032c9f40a9f55d0b098ad7f530fb01157f" + + "1882aec571e4800d56e2e165d7c2a718c4a715e6ad56ee15e2cdb1eb73b53b26" + + "307ca702a9b046662ee6a2a1cf35122a5c2b40a365aeb0f43a377b8beb5f265f" + + "48a1520fe1cb02b9068d5571c70f09ebf48994901d45ff7792732db063e17c51" + + "60516a3419165006de362b87bf30d2858c231338d5fa42bfeae2afeddb1903b6" + + "78ec940b516f45abb64321beb7788fab245868978daf209242e575c153e9185e" + + "90d2e43089b7f5f48e1381e7afc7be13", + ) + + private val spimDecoded = hex( + "3d3ed61e955c30950055c90be0c0d9595d21296865f57fc9c92005dd6002b145" + + "62a658444ed719ff6e9a95bc479e2199c8c816e9bda89044678504422cddbebe" + + "0a424906bab2d5ef07bb38f1a0ef188bd0b294420b2a79e9af7b835838a804e8" + + "604dad00e21e0974b8e11a0a14b9f01b22816e94ac53152a4dc8bdb6ad6b297e" + + "106caf2092f33e1426a552a909ff454ce097a7561e9afbcba21bfe7dfe8977fc" + + "a42800295d9b3fbfb6b4cf25ccc9e9e90390845030434d90e3b20653cfd17911" + + "6ef61c34a9d0967276def3f72736f4414d8393f77fb345fb23f696d255eec61a" + + "4c9e0db3af0ace58bf51c9b72a941429", + ) + + private val encIn = hex( + "c22b1257d3ed1db610bd662d0990b9ec0e42db042f944f843c9a6220c523625b" + + "1a710d7f4b444b45281edd4c41374694", + ) + + private val encIv = hex( + "2f7ad8983c88c078c579e4ad1a0fc0da", + ) + + private val encOut = hex( + "721f4fa196e234a9693766d73c5f9cfb2ead0ac5c392320d353725d7f04ef69f" + + "8631961c9f1edf69de19d76af04ebb9f", + ) + + private val encNoIv = hex( + "721f0aa13354b37ed73706d7c78008fb3ead64c5c3c9080dda3758d7f04e5c9f" + + "0231fc1c861ee369de19b36af04efe9f", + ) + + private val encsecIn = hex( + "0917651c0ebd05fe2ff3dfae3c0dcdb6c51abfc71a9ce4ff4b9302f228c1fbca", + ) + + private val encsecOut = hex( + "44ca5ba970c59ab51cbe7935ca59e85bdc146d2fc93c30208145e697765ecfa1", + ) + + private val spimsigIn = hex( + "9cc89edaa522633b7a36622e2b8ec6c8", + ) + + private val spimsigOut = hex( + "63bd0cf46564bb14094ee098041655cb", + ) + + private val docKeys0 = hex( + "bd507e23b226900803e6d6b08009e76eb93b4476fefb554f5fdfd75eac3d730a" + + "75dae3ee0ada11cf7b12c5c89888ac0d", + ) + + private val docKeys1 = hex( + "2a9f44651bc132cbb8a254319188ed5cf683e561f753322364320dfacd1c51da" + + "82e9ddfe93382ebed0109d23c9b8dfd5", + ) + + private val docKeys2 = hex( + "97ed0aa7845bd58d6d5fd2b1a207f44a33cc864df0ab0ef769854295eefb2eaa" + + "8ff8d70e1c974aad250f757efae8129e", + ) + + private val docKeys3 = hex( + "043cd1e8edf57750221c5032b386fa3870142839e903ebca6ed877300fdb0c7a" + + "9c07d21ea5f5669c7a0d4dd92b194666", + ) + + private val docK4 = hex( + "718a972a56901a13d7d8cdb2c4050127", + ) + + private val docIoIn = hex( + "6caf03f735c98c65ca013e363b7f2ea9", + ) + + private val docIoOut = hex( + "668643008a2d2094b86c314b012c80a9", + ) + + private val docBlock = hex( + "ff603db5cc2eeaa21545c0b52a0028bb", + ) + + private val docOut = hex( + "854c599e24bcbe3ed1d286b5b87dcdc0", + ) + + // ---- init_session ctx (0x28F0 bytes) ---- + + private val initCtx = hex( + "3d3ed61e955c30950055c90be0c0d9595d21296865f57fc9c92005dd6002b145" + + "62a658444ed719ff6e9a95bc479e2199c8c816e9bda89044678504422cddbebe" + + "0a424906bab2d5ef07bb38f1a0ef188bd0b294420b2a79e9af7b835838a804e8" + + "604dad00e21e0974b8e11a0a14b9f01b22816e94ac53152a4dc8bdb6ad6b297e" + + "106caf2092f33e1426a552a909ff454ce097a7561e9afbcba21bfe7dfe8977fc" + + "a42800295d9b3fbfb6b4cf25ccc9e9e90390845030434d90e3b20653cfd17911" + + "6ef61c34a9d0967276def3f72736f4414d8393f77fb345fb23f696d255eec61a" + + "4c9e0db3af0ace58bf51c9b72a9414290000000000000000f449ae0700000000" + + "0000000000000000416f7d31000000000000000041b76ae90000000000000000" + + "000000009484f86b0000000000000000d8ee5002000000000000000000000000" + + "e6a079b3000000000000000000000000000000000000000000000000902d15e4" + + "00000000000000000000000062957a6c000000007b88b90f0000000000000000" + + "0000000009b0be0600000000000000000000000000000000dc47bd8d00000000" + + "00000000000000009bd901330000000000000000000000000000000082005359" + + "0000000000000000000000008d412cd025d3d10a000000000000000000000000" + + "10b1fbb400000000000000000000000000000000cac316bf0000000000000000" + + "000000004ef61560000000000000000000000000000000001fec02ec00000000" + + "000000000000000009742f0f000000000000000000000000000000004173fbe0" + + "00000000000000000000000025cf57db250bc6d2000000000000000000000000" + + "b3cb94680000000000000000000000000000000000000000c1ef15b000000000" + + "0000000000000000ed48ebb50000000000000000bc966d300000000000000000" + + "00000000bc52fc3900000000000000002a563f8a000000000000000000000000" + + "dc9faa550000000000000000000000000000000000000000000000002ee354d4" + + "000000000000000000000000663c97e30000000000000000e6bcff6200000000" + + "00000000000000004e2e02b80000000000000000a1e6d2d50000000000000000" + + "00000000e21512ed0000000000000000aa0e40d3000000000000000000000000" + + "38a36eef0000000000000000000000000000000000000000000000009f70ecbc" + + "000000000000000000000000ca1b016700000000d31a44d50000000000000000" + + "000000000dddc2800000000000000000000000000000000066f806ea00000000" + + "00000000000000003867ffe60000000000000000000000000000000094987eba" + + "00000000000000000000000045c690beaea7ad5c000000000000000000000000" + + "dc832c840000000000000000000000000000000066e4803b0000000000000000" + + "000000009fb47db500000000000000000000000000000000624d6db400000000" + + "0000000000000000ae633c5500000000000000000000000000000000d306c204" + + "000000000000000000000000aad6570b02582c00000000000000000000000000" + + "8930d68700000000000000000000000000000000000000002effd20500000000" + + "0000000000000000821cd588000000000000000058aaa98a0000000000000000" + + "000000003cd294b800000000000000003726806f000000000000000000000000" + + "a5972882000000000000000000000000000000000000000000000000f0385450" + + "0000000000000000000000002e3b430c7e2b8080562690820cf2c58f88146e55" + + "59947def248d16b9abfe3ce1cb0344bbf549ad3391a5d2826c4b15e52b4d38e0" + + "3d0ac16a91e17ab2089101505df7b93032b82c077a0cec6fe76d9066ab8cffd5" + + "1120bd8736dbe8d836ed83dc6828d13a395f6eb1b9da01b4391bc681d955bada" + + "32caef33c487c2d21ee093dee30e54b9030480d2f16ec1dc87a6833808d5a960" + + "08a76a544bf4e88a36a92bec9e65fcdb7a7e2f5b6c39d6d1e8e9160fe8adbe3f" + + "d69594837a48445f566238b2e37c978dafab933a3d4e695ad6d13cb3b668ecd9" + + "75faa932cf124350b9a8c280feea47b559a216eb679a3c5707158739f12a69ec" + + "20d8b9627e5943b4cf6080649193b98671996dedec8ad2d0a47aba8824c9be89" + + "8850c6656c0fbdd5abba94d18c77aa8a95b4d5692b3ffbd45610fb86e75bfb62" + + "20eed266b9ec6ab09a429034fedc2cb1d6a3ff87dd367e05a02f1553c0a0ae3d" + + "0c8006bb32fc843708e3c264facd2b5aa0197e574f972c55396905b552733f59" + + "d28493687a3a876b4402add7fafb405ea06bbd63afef3b0a116415b7cb47ec8b" + + "fe9884811543795824bb7dbdf50d0503e34afc89037643e6b62c44e91ab53c05" + + "4bb040bab24f8036dd72d635abc857e50767440dd92779eea05dd6671e9250ea" + + "5245545d3d78025e2f5c3f0b369f40e8882205511575125c681eba3e5dc1d234" + + "d91112ead2f6505c8866ad6171ebaed971ddc5dd1ed6f8da83c547e75db31100" + + "e8df7d0b034028e2e729385607512f091a835701f57fc6374bc2838ef158aad8" + + "c0e4060ddd001501d6e757b7b61a2fed0cc4ae8b9582be6dbdb9c56b7e1deb84" + + "0332ebd6d2c03b587e6f28b0c0d26d0911527eb31531ba6cb20b28064013aa3c" + + "b23d4302392dad852b7b53e49e2154ebb99ea9841116d683d963d1dee89bd53b" + + "95c6165dbd8fae6f1af194355d857a049e5397df1ac7ff31685a120e8c3302ba" + + "4057020c67e8ff63ecce7ae02b0990d0ecbcb9d44fd38465e3383fbdcf56eb60" + + "a40879bccb71878fdd44bd3183f32ce3fabfe86e4b862bbe87d4400cecf811e4" + + "cb352fbff53b6e0767de94679a063804c4c36ae22f2efc3f209c115271af06e9" + + "c096c5391507d1688381efd74fa14751bdcb065fe71f5352a43e12b88c41c18e" + + "444605e7cf2428545201fc6dc4b1a9d6bdfd6d5b2f6a540f328e470344706ee3" + + "638b3bbc2f18973bfeaeef85b279eb320723ec3d24ffd58d4fe5ef6183b784d3" + + "9e173fef59e6bedbfa89836a1ea43beea44cd18c6c7d7ee18790e83cc4f501e6" + + "4061690875ccc23675886a0663bd50b89a3053003d3caa6e63f9f888af9df83e" + + "0cb66dbfd2b2f86c63cf938c59d0d5df9a74fb304025c13867ac57538c0569be" + + "f11c02e8686c790a523797694434c6d3afd9500e95f07d5987e22b08b65e87dd" + + "20aa7a5691d711b6565453b675be0102ef5963140000000000000000ba6d74f8" + + "802b597800000000000000008043dcf600000000000000000000000000000000" + + "00000000000000000000000000000000a88ecf4e0000000000000000b1bd1899" + + "fdd25d2c0000000000000000431cb04e00000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000f602314da7169e2600000000" + + "00000000a77e1ba819d873440000000000000000000000000000000000000000" + + "00000000000000000000000000000000000000007d7a2549efd38aad00000000" + + "00000000e04bdbc527340ffa0000000000000000a35ea32f922a8ef900000000" + + "0000000004cb1c1428c4db1c0000000000000000000000000000000000000000" + + "00000000000000000000000000000000000000002314b77d319f894500000000" + + "00000000c8ee4df33e6f5da30000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000cccef574000000000000000051978e76" + + "2c8ce6150000000000000000193a1f7300000000000000000000000000000000" + + "000000000000000000000000000000006bb9267800000000000000006001cf97" + + "e403e6cc000000000000000080c9354f00000000ebf3322ac71e991500000000" + + "00000000de45cb4ca33626a10000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000553ddf48840be1ff00000000" + + "00000000c3dc4da5c356a41c0000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000f22289ca000000000000000047b6e170" + + "be4dcc7f0000000000000000275c8a7400000000000000000000000000000000" + + "00000000000000000000000000000000acae77c9000000000000000055b736f1" + + "0bd9a4c5000000000000000023f6db4a27d663cd0000000000000000da871ffc" + + "2c060fac00000000000000003a2760aa00000000000000000000000000000000" + + "00000000000000000000000000000000642177100000000000000000c864a44a" + + "fd30311b00000000000000001df8cbc300000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000000000006449f29e3e8d319400000000" + + "000000005eedb329b1d59d170000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000daef9a72317de57200000000" + + "000000008f5164276f7bf2c80000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000b0f4b090ad7fd8f9460c9d76138d63f3" + + "7c938efb2dbc8a7246f0df7d9ce95ec9db3c5d174d81b043dbc01f1cead221a4" + + "cd42e2c854209aaea68a0f4f015d26208a13599e34e1e294f30bf1cad4e3c825" + + "73b059c2ee8099a377e2e1c5ad07227a507222a9bf53df2185308ea7c26135f1" + + "0efa499129ee3275c968a04c65cee61d00000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000a2d8b748771ea3ce050f9e2754a42226" + + "61e4a499f38f4942df92a71b304f18980a54b39df7a50bc66a6989ac6aed3124" + + "0125dca322e7a7c885b4362ff3730b4900000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000017a721776a95cba7ad839af25f290f13" + + "17dfdbf43f6ccfa18548742478c136fc7c17367318004ec60ad00b154226dff2" + + "5b7bb714971c897f2631a7477c6fccf000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000c9ec18c4172399fffc2826f326495dc4" + + "0e7ef1190a2c491e98bbe6ce8a6ba31dd0b170221878b445b4a608976118e692" + + "b08c4a1330cba010783d74f7296a8afd93ca89f081e68e287ceb74781c2a0c42" + + "8e41e199b4def214e5f1f69dbb016726a6764d44983f5e4697e0cb74d04d3229" + + "73c8a341c6338df6934e31781caeb4ca00000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000ea56992c5bff0f9c500ad82ae5754e15" + + "9336cbfbf8fe267cf3f7b3c193b27373058b26af34655a1cc29d77fadbb8e59f" + + "c6cfcffd1c52f6c12dc470f1b070081800000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000468825fe4d7df248175b637c976473fc" + + "f75949cdbbfd252d057764a41309db7b5b034d972912707e78458e74a9d122f5" + + "bf2b25a2e15f0c913f143522221be5c3b19e65450000000000000000b19eca45" + + "b19e09450000000000000000b19ee74500000000000000000000000000000000" + + "00000000000000000000000000000000b19e4c450000000000000000b19e8f45" + + "b19e0d450000000000000000b19ea54500000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000b19e4845b19e334500000000" + + "00000000b19edd45b19e9b450000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000b19eb245b19e244500000000" + + "00000000b19e5b45b19ecd450000000000000000b19e0945b19e204500000000" + + "00000000b19e8c45b19e5c450000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000b19e1945b19e714500000000" + + "00000000b19e1e45b19ee0450000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000b19eca450000000000000000b19ecd45" + + "b19e66450000000000000000b19e344500000000000000000000000000000000" + + "00000000000000000000000000000000b19ee0450000000000000000b19e4b45" + + "b19e61450000000000000000b19ea64500000000b19ef045b19e8f4500000000" + + "00000000b19ea245b19ee7450000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000b19e5845b19edd4500000000" + + "00000000b19ef445b19eb5450000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000b19e9c450000000000000000b19e3045" + + "b19e1e450000000000000000b19e234500000000000000000000000000000000" + + "00000000000000000000000000000000b19e98450000000000000000b19e1945" + + "b19eb2450000000000000000b19eb645b19e62450000000000000000b19ed945" + + "b19e27450000000000000000b19eda4500000000000000000000000000000000" + + "00000000000000000000000000000000b19e9f450000000000000000b19e5f45" + + "b19ea2450000000000000000b19e4f4500000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000b19e7145b19e4f4500000000" + + "00000000b19e1d45b19e61450000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000b19e3745b19ede4500000000" + + "00000000b19ed945b19e9b450000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000652fd9d2652fd983652fd9e1652fd934" + + "652fd93f652fd939652fd9de652fd952652fd98d652fd956652fd9b2652fd9db" + + "652fd9ec652fd96c652fd9b3652fd986652fd98b652fd93c652fd966652fd9d6" + + "652fd95b652fd937652fd9b7652fd904652fd980652fd90e652fd9ef652fd988" + + "652fd95a652fd9d5652fd987652fd93a00000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000652fd95f652fd988652fd96a652fd9d4" + + "652fd951652fd9de652fd95e652fd9ef652fd989652fd9b5652fd9e6652fd95e" + + "652fd901652fd9da652fd957652fd9e100000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000652fd95f652fd9d9652fd9bc652fd963" + + "652fd9d8652fd98b652fd968652fd9d3652fd987652fd983652fd931652fd98a" + + "652fd98f652fd962652fd98e652fd90000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000652fd93f652fd9e7652fd902652fd909" + + "652fd9e2652fd90e652fd9be652fd90c652fd93a652fd904652fd93e652fd96e" + + "652fd955652fd957652fd9ec652fd96d652fd936652fd9bb652fd9b8652fd9e8" + + "652fd967652fd9b9652fd9bf652fd9e2652fd98c652fd906652fd95d652fd905" + + "652fd9dc652fd964652fd98e652fd95000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000652fd963652fd937652fd907652fd907" + + "652fd909652fd956652fd959652fd9b1652fd9d2652fd984652fd9b7652fd935" + + "652fd95b652fd96f652fd9be652fd96a00000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000652fd959652fd969652fd960652fd9e5" + + "652fd98a652fd9dd652fd9ed652fd98c652fd908652fd9ea652fd96b652fd950" + + "652fd989652fd96c652fd90c652fd9e5000000000000000057c4dd0f00000000" + + "0000000000000000b8c4dd0f0000000000000000d3c4dd0f0000000000000000" + + "000000001fc4dd0f0000000000000000d7c4dd0f000000000000000000000000" + + "b3c4dd0f00000000000000000000000000000000000000000000000089c4dd0f" + + "00000000000000000000000070c4dd0f000000004ac4dd0f0000000000000000" + + "00000000d7c4dd0f0000000000000000000000000000000041c4dd0f00000000" + + "000000000000000057c4dd0f0000000000000000000000000000000037c4dd0f" + + "0000000000000000000000004ec4dd0f0dc4dd0f000000000000000000000000" + + "dcc4dd0f0000000000000000000000000000000069c4dd0f0000000000000000" + + "00000000aac4dd0f0000000000000000000000000000000094c4dd0f00000000" + + "00000000000000008dc4dd0f0000000000000000000000000000000089c4dd0f" + + "0000000000000000000000003cc4dd0f66c4dd0f000000000000000000000000" + + "70c4dd0f0000000000000000000000000000000000000000dcc4dd0f00000000" + + "00000000000000005cc4dd0f000000000000000038c4dd0f0000000000000000" + + "0000000062c4dd0f00000000000000002ec4dd0f000000000000000000000000" + + "2ac4dd0f00000000000000000000000000000000000000000000000089c4dd0f" + + "000000000000000000000000e6c4dd0f000000000000000082c4dd0f00000000" + + "0000000000000000c1c4dd0f0000000000000000cec4dd0f0000000000000000" + + "0000000014c4dd0f000000000000000021c4dd0f000000000000000000000000" + + "fbc4dd0f000000000000000000000000000000000000000000000000c1c4dd0f" + + "00000000000000000000000002c4dd0f0000000009c4dd0f0000000000000000" + + "000000001bc4dd0f00000000000000000000000000000000bcc4dd0f00000000" + + "0000000000000000a1c4dd0f000000000000000000000000000000002ec4dd0f" + + "0000000000000000000000002ec4dd0fb7c4dd0f000000000000000000000000" + + "1bc4dd0f000000000000000000000000000000008dc4dd0f0000000000000000" + + "000000009bc4dd0f000000000000000000000000000000001bc4dd0f00000000" + + "0000000000000000edc4dd0f0000000000000000000000000000000038c4dd0f" + + "0000000000000000000000004ac4dd0f38c4dd0f000000000000000000000000" + + "b3c4dd0f0000000000000000000000000000000000000000b8c4dd0f00000000" + + "000000000000000006c4dd0f0000000000000000e9c4dd0f0000000000000000" + + "0000000006c4dd0f0000000000000000d8c4dd0f000000000000000000000000" + + "33c4dd0f000000000000000000000000000000000000000000000000aac4dd0f" + + "000000000000000000000000e2c4dd0fb64bf64db60cf64db642f64db6caf64d" + + "b676f64db6e7f64db635f64db6dff64db6d1f64db673f64db622f64db67ff64d" + + "b636f64db6f9f64db6e8f64db6dcf64db64cf64db66bf64db632f64db6d7f64d" + + "b651f64db6e6f64db68ef64db688f64db6f4f64db6d6f64db67ef64db6def64d" + + "b6aef64db6cdf64db6c9f64db698f64db6b2f64db6f1f64db6b0f64db662f64d" + + "b680f64db61ff64db604f64db6ebf64db689f64db6c0f64db620f64db6aaf64d" + + "b646f64db6e1f64db686f64db67af64db6f7f64db6bcf64db6ccf64db6acf64d" + + "b69bf64db697f64db634f64db6e3f64db61ef64db6f2f64db6faf64db67bf64d" + + "b625f64db6a9f64db675f64db61bf64db631f64db68af64db627f64db66df64d" + + "b640f64db6a8f64db6bff64db660f64db63bf64db69df64db664f64db65af64d" + + "b64df64db6bef64db6cbf64db68bf64db62ef64db674f64db6e5f64db6edf64d" + + "b6a0f64db6c6f64db60af64db6c3f64db68df64db6b5f64db69cf64db6cef64d" + + "b60ef64db603f64db6eff64db6abf64db66ff64db67df64db6dbf64db655f64d" + + "b601f64db6fbf64db68ff64db65bf64db612f64db650f64db626f64db60bf64d" + + "b695f64db68cf64db6fef64db65df64db618f64db63cf64db607f64db62bf64d" + + "b6a6f64db6d4f64db637f64db66cf64db6a2f64db693f64db6e0f64db6b4f64d" + + "b654f64db6ecf64db628f64db6d3f64db6bbf64db6a1f64db61af64db656f64d" + + "b648f64db638f64db6b8f64db670f64db663f64db6b9f64db677f64db699f64d" + + "b667f64db61cf64db6a4f64db64ef64db62af64db653f64db67cf64db623f64d" + + "b6daf64db684f64db6c1f64db60ff64db6b3f64db619f64db606f64db6a7f64d" + + "b66ef64db616f64db617f64db661f64db65cf64db639f64db6b6f64db6c2f64d" + + "b6d9f64db614f64db681f64db63ef64db683f64db6e9f64db66af64db6eaf64d" + + "b62df64db610f64db600f64db6f5f64db6e2f64db63ff64db6f0f64db61df64d" + + "b6c5f64db63df64db696f64db672f64db621f64db6fdf64db652f64db668f64d" + + "b6b7f64db633f64db678f64db641f64db647f64db6d5f64db6aff64db659f64d" + + "b685f64db671f64db690f64db6ddf64db69ef64db6d0f64db6adf64db608f64d" + + "b665f64db6fff64db62cf64db6a5f64db6f6f64db65ff64db624f64db60df64d" + + "b6baf64db6bdf64db669f64db6e4f64db692f64db605f64db657f64db6f8f64d" + + "b609f64db694f64db649f64db643f64db64ff64db64af64db6d8f64db62ff64d" + + "b645f64db6f3f64db679f64db6d2f64db629f64db65ef64db658f64db69ff64d" + + "b6c8f64db666f64db630f64db6fcf64db6a3f64db6cff64db69af64db682f64d" + + "b613f64db602f64db644f64db687f64db615f64db6b1f64db63af64db6c4f64d" + + "b6c7f64db691f64db6eef64db611f64d003e427c3e007c426c522e10526c102e" + + "132d516f2d136f517f413d03417f033dd7e995abe9d7ab95bb85f9c785bbc7f9" + + "c4fa86b8fac4b886a896ead496a8d4ea4678043a78463a042a146856142a5668" + + "556b17296b55291739077b450739457b91afd3edaf91edd3fdc3bf81c3fd81bf" + + "82bcc0febc82fec0eed0ac92d0ee92acfdc3bf81c3fd81bf91afd3edaf91edd3" + + "eed0ac92d0ee92ac82bcc0febc82fec02a146856142a56684678043a78463a04" + + "39077b450739457b556b17296b552917bb85f9c785bbc7f9d7e995abe9d7ab95" + + "a896ead496a8d4eac4fa86b8fac4b8866c522e10526c102e003e427c3e007c42" + + "7f413d03417f033d132d516f2d136f5100603b5bd1b1ea8ae484dfbf35550e6e" + + "38580363e989d2b2dcbce7870d6d3656ee8ed5b53f5f04640a6a3151dbbbe080" + + "d6b6ed8d07673c5c32520969e383d8b867075c3cb6d68ded83e3b8d852326909" + + "5f3f64048eeeb5d5bbdb80e06a0a513189e9b2d2583863036d0d5636bcdc87e7" + + "b1d18aea60005b3b55356e0e84e4bfdfd9b9e282086833533d5d0666ec8cd7b7" + + "e181daba30500b6b05653e5ed4b4ef8f37570c6ce686ddbdd3b3e88802623959" + + "0f6f3454debee585eb8bd0b03a5a0161bede85e56f0f54345a3a61018bebb0d0" + + "86e6bddd57376c0c62025939b3d388e850306b0b81e1badab4d48fef65055e3e" + + "68085333b9d982e28cecb7d75d3d660600ac1db1a804b519a804b51900ac1db1" + + "f65aeb475ef243ef5ef243eff65aeb476fc372dec76bda76c76bda766fc372de" + + "99358428319d2c80319d2c80993584280ba716baa30fbe12a30fbe120ba716ba" + + "fd51e04c55f948e455f948e4fd51e04c64c879d5cc60d17dcc60d17d64c879d5" + + "923e8f233a96278b3a96278b923e8f233a96278b923e8f23923e8f233a96278b" + + "cc60d17d64c879d564c879d5cc60d17d55f948e4fd51e04cfd51e04c55f948e4" + + "a30fbe120ba716ba0ba716baa30fbe12319d2c809935842899358428319d2c80" + + "c76bda766fc372de6fc372dec76bda765ef243eff65aeb47f65aeb475ef243ef" + + "a804b51900ac1db100ac1db1a804b51900e805ed34dc31d9c62ec32bf21af71f" + + "f018f51dc42cc12936de33db02ea07efb058b55d846c8169769e739b42aa47af" + + "40a845ad749c7199866e836bb25ab75f56be53bb628a678f9078957da44ca149" + + "a64ea34b927a977f6088658d54bc51b9e60ee30bd23ad73f20c825cd14fc11f9" + + "16fe13fb22ca27cfd038d53de40ce109648c618950b855bda24aa74f967e937b" + + "947c9179a048a54d52ba57bf668e638bd43cd139e008e50d12fa17ff26ce23cb" + + "24cc21c910f815fde20ae70fd63ed33b32da37df06ee03ebf41cf119c028c52d" + + "c22ac72ff61ef31b04ec01e930d835dd826a876fb65eb35b44ac41a97098759d" + + "729a779f46ae43abb45cb1598068856d0073b2c1ed9e5f2ce19253200c7fbecd" + + "82f130436f1cddae6310d1a28efd3c4f6e1ddcaf83f031428ffc3d4e6211d0a3" + + "ec9f5e2d0172b3c00d7ebfcce0935221285b9ae9c5b67704c9ba7b08245796e5" + + "aad9186b4734f5864b38f98aa6d514674635f487abd8196aa7d415664a39f88b" + + "c4b77605295a9be8255697e4c8bb7a09a2d110634f3cfd8e4330f182aedd1c6f" + + "205392e1cdbe7f0cc1b273002c5f9eedccbf7e0d215293e02d5e9fecc0b37201" + + "4e3dfc8fa3d01162afdc1d6e4231f0838af9384b6714d5a66b18d9aa86f53447" + + "087bbac9e5965724e99a5b280477b6c5e4975625097abbc80576b7c4e89b5a29" + + "6615d4a78bf8394a87f435466a19d8ab12d95c979952d71c01ca4f848a41c40f" + + "6ba025eee02bae6578b336fdf338bd7674bf3af1ff34b17a67ac29e2ec27a269" + + "0dc64388864dc8031ed5509b955edb1030fb7eb5bb70f53e23e86da6a863e62d" + + "498207ccc2098c475a9114dfd11a9f54569d18d3dd169358458e0bc0ce05804b" + + "2fe461aaa46fea213cf772b9b77cf93239f277bcb279fc372ae164afa16aef24" + + "408b0ec5cb00854e53981dd6d813965d5f9411dad41f9a514c8702c9c70c8942" + + "26ed68a3ad66e32835fe7bb0be75f03b1bd0559e905bde1508c3468d8348cd06" + + "62a92ce7e922a76c71ba3ff4fa31b47f7db633f8f63db8736ea520ebe52eab60" + + "04cf4a818f44c10a17dc59929c57d219006f36594728711e89e6bfd0cea1f897" + + "f09fc6a9b7d881ee79164f203e5108678be4bdd2cca3fa95026d345b452a731c" + + "7b144d223c530a65f29dc4abb5da83ecabc49df2ec83dab5224d147b650a533c" + + "5b346d021c732a45d2bde48b95faa3cc204f16796708513ea9c69ff0ee81d8b7" + + "d0bfe68997f8a1ce59366f001e7128479af5acc3ddb2eb84137c254a543b620d" + + "6a055c332d421b74e38cd5baa4cb92fd117e27485639600f98f7aec1dfb0e986" + + "e18ed7b8a6c990ff68075e312f401976315e07687619402fb8d78ee1ff90c9a6" + + "c1aef79886e9b0df48277e110f603956bad58ce3fd92cba4335c056a741b422d" + + "4a257c130d623b54c3acf59a84ebb2dd00c0ad6de828458508c8a565e0204d8d" + + "77b7da1a9f5f32f27fbfd21297573afa00c0ad6de828458508c8a565e0204d8d" + + "77b7da1a9f5f32f27fbfd21297573afad0107dbd38f89555d81875b530f09d5d" + + "a7670aca4f8fe222af6f02c24787ea2ad0107dbd38f89555d81875b530f09d5d" + + "a7670aca4f8fe222af6f02c24787ea2ab87815d55090fd3db0701ddd5898f535" + + "cf0f62a227e78a4ac7076aaa2fef8242b87815d55090fd3db0701ddd5898f535" + + "cf0f62a227e78a4ac7076aaa2fef824268a8c50580402ded60a0cd0d884825e5" + + "1fdfb272f7375a9a17d7ba7aff3f529268a8c50580402ded60a0cd0d884825e5" + + "1fdfb272f7375a9a17d7ba7aff3f5292", + ) + + @Test + fun decodeSpimMatchesOracle() { + assertContentEquals(spimDecoded, ClearAdiProvision.decodeSpim(spimIn)) + } + + @Test + fun docryptMatchesOracle() { + val keys = listOf(docKeys0, docKeys1, docKeys2, docKeys3, docK4) + val (out, ioNew) = ClearAdiProvision.docrypt(docBlock, keys, wordsOf(docIoIn)) + assertContentEquals(docOut, toBytes(out)) + assertContentEquals(docIoOut, toBytes(ioNew)) + } + + @Test + fun encryptMatchesOracle() { + val ctx = initCtx + assertContentEquals(encOut, ClearAdiProvision.encrypt(ctx, encIv, encIn)) + assertContentEquals(encNoIv, ClearAdiProvision.encrypt(ctx, null, encIn)) + } + + @Test + fun encsecMatchesOracle() { + assertContentEquals(encsecOut, ClearAdiProvision.encsec(encsecIn)) + } + + @Test + fun spimMapSignatureMatchesOracle() { + assertContentEquals(spimsigOut, ClearAdiProvision.spimMapSignature(spimsigIn)) + } + + @Test + fun initSessionMatchesOracle() { + val ctx = ClearAdiProvision.initSession(spimIn) + assertContentEquals(initCtx, ctx) + // sessionKey = ctx[0:16] == the first 16 bytes of the decoded spim + assertContentEquals(spimDecoded.copyOfRange(0, 16), ClearAdiProvision.sessionKey(ctx)) + } + + // ---- decryptPTM (0x17ffb50) ---- + + @Test + fun decryptPtmMatchesOracle() { + val key = hex("4171fc46e636443d27a4a9bad4f66807") + val data = hex("aebfc2884fd1e6ffdc60273be5756ff5") + val seed = hex("1b0e89cab86b89c2911da5bbf6f475e3") + val out = hex("6b04544b6be060c42f0ed7b3a0d9eab7") + assertContentEquals(out, ClearAdiProvision.decryptPtm(key, data, seed)) + } + + @Test + fun decryptPtmFreshVectors() { + // fresh oracle captures (LCG streams 50/51/52 and 60/61/62, counts 1 and 2) + val out1 = hex("c11d71db800157dd1f3faeffd9eda975") + assertContentEquals( + out1, + ClearAdiProvision.decryptPtm( + hex("8381bbd8003f9ed7390393bf7eeda953"), + hex("f0cf811a69d9409aeebf10408f6cb041"), + hex("5d1e485cd273e35ca37c8ec0a0ebb62f"), + ), + ) + val out2 = hex( + "e482e99a56404b6f4c0157a9b50f0753" + + "e4aa04c6fde42ee55e4565d63075de0b", + ) + assertContentEquals( + out2, + ClearAdiProvision.decryptPtm( + hex("c5917a6a1a47f8714b627cc428e4ea9f"), + hex("32e040ac83e19a34001ffa443963f18d" + + "7ecd1833df12a03d2c2b623af5f9fb54"), + hex("9f2e07eeec7b3df7b5db77c54ae2f77b"), + ), + ) + } +} diff --git a/registration/src/test/kotlin/dev/fenn/imessage/registration/ClearAnisetteProviderTest.kt b/registration/src/test/kotlin/dev/fenn/imessage/registration/ClearAnisetteProviderTest.kt new file mode 100644 index 0000000..3162d51 --- /dev/null +++ b/registration/src/test/kotlin/dev/fenn/imessage/registration/ClearAnisetteProviderTest.kt @@ -0,0 +1,306 @@ +package dev.fenn.imessage.registration + +import dev.fenn.imessage.codec.Plist +import dev.fenn.imessage.codec.XmlPlist +import dev.fenn.imessage.ids.IdsHttpResponse +import dev.fenn.imessage.ids.IdsHttp +import java.util.Base64 +import kotlin.test.Test +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertTrue + +/** + * Tests for the wire-level ClearADI provider (ClearAdiFraming + ClearAnisetteProvider). + * The framing facts come from new.asm/finish.asm plus live-oracle probes of + * librust_lib_bluebubbles (see WORKLOG session 19e); everything the probes could not pin is + * TODO(live-capture) in the code and asserted only at the shape level here. + */ +class ClearAnisetteProviderTest { + + private fun hex(s: String): ByteArray = + ByteArray(s.length / 2) { ((Character.digit(s[it * 2], 16) shl 4) or Character.digit(s[it * 2 + 1], 16)).toByte() } + + // ---- Spim parse ---------------------------------------------------------- + + private fun spimBytes(field1: Int = 0, payload: ByteArray = ByteArray(240), tail: ByteArray = ByteArray(0)): ByteArray = buildSpim(field1, payload, tail) + + @Test + fun spimParseExtractsFields() { + val payload = ByteArray(240) { it.toByte() } + val spim = Spim.parse(spimBytes(field1 = 0x01020304, payload = payload, tail = ByteArray(23))) + assertEquals(0x01020304, spim.field1) + assertEquals(240, spim.payloadLength) + assertContentEquals(payload, spim.payload) + } + + @Test + fun spimParseRejectsShortPayloadAndBadLeftover() { + // payload ≤ 59 B rejected (17efb33) + assertFailsWith { Spim.parse(spimBytes(payload = ByteArray(59))) } + // > 23 trailing bytes rejected (live-pinned error 0x41) + assertFailsWith { Spim.parse(spimBytes(tail = ByteArray(24))) } + // truncated header + assertFailsWith { Spim.parse(ByteArray(3)) } + // payload length beyond the buffer + val b = spimBytes() + b[4] = 0x00; b[5] = 0x00; b[6] = 0x01; b[7] = 0x00 + assertFailsWith { Spim.parse(b) } + } + + // ---- Cpim build ---------------------------------------------------------- + + /** Deterministic RNG: draws are 0x10, 0x20, 0x30-filled blocks (draw1, draw2, draw3). */ + private class FixedRng : ClearAdiRng { + var n = 0 + override fun draw(n: Int): ByteArray { + val fill = when (++this.n) { 1 -> 0x10; 2 -> 0x20; else -> 0x30 }.toByte() + return ByteArray(n) { fill } + } + } + + private val seal = CpimTailSeal { _, _, sig, digest -> + // the two 256-bit fields: shape-only seal so the test is deterministic + sig.copyOf(32) to digest + } + + @Test + fun cpimBuildMatchesAsmLayout() { + val extra = ByteArray(10) { 0xAB.toByte() } + val session = ClearAdiProvision.initSession(ByteArray(240)) + val cpim = Cpim.build(FixedRng(), extra, -2L, session, ByteArray(240), seal) + // 4+32+4+32+60+8+4+32+32 + assertEquals(208, cpim.size) + assertEquals(32, readBeU32(cpim, 0)) + // vec1 = encsec(draw2) — encsec is deterministic, so byte-exact here + assertContentEquals(ClearAdiProvision.encsec(ByteArray(32) { 0x20.toByte() }), cpim.copyOfRange(4, 36)) + assertEquals(32, readBeU32(cpim, 36)) + assertContentEquals(ByteArray(32) { 0x10.toByte() }, cpim.copyOfRange(40, 72)) // draw1 raw + // blob = extra ‖ draw3 padding + assertContentEquals(extra, cpim.copyOfRange(72, 82)) + assertContentEquals(ByteArray(50) { 0x30.toByte() }, cpim.copyOfRange(82, 132)) + // arg9 = −2 as u64 BE (omnisette "GSA") + assertEquals(-2L, readBeU64(cpim, 132)) + assertContentEquals(hex("FFFFFFFFFFFFFFFE"), cpim.copyOfRange(132, 140)) + // item 7 = BE u32 of the LE dword at draw3[8..12] — draw3 is 0x30-filled ⇒ 0x30303030 + assertEquals(0x30303030, readBeU32(cpim, 140)) + // tail fields present, 32 B each (items 8–9 = 64 B after the 144 B prefix) + assertEquals(64, cpim.size - 144) + } + + @Test + fun cpimBuildRejectsOversizeExtra() { + assertFailsWith { + Cpim.build(FixedRng(), ByteArray(61), -2L, ByteArray(0x28F0), ByteArray(240), seal) + } + } + + // ---- Ptm parse / tk check ------------------------------------------------ + + @Test + fun ptmParseTakesField1AndPayload() { + val ptm = Ptm.parse(hex("00000001") + ByteArray(32)) + assertEquals(1, ptm.field1) + assertEquals(32, ptm.payload.size) + // lenient Vec: field1 clipped to what the buffer holds (live-pinned) + assertEquals(4, Ptm.parse(hex("FFFFFFFF") + ByteArray(4)).payload.size) + } + + @Test + fun finishRejectsTkNot16Bytes() = kotlinx.coroutines.runBlocking { + val http = ScriptedIdsHttp(tkSize = 15) + val provider = provider(http = http) + val ex = assertFailsWith { provider.provision() } + assertTrue(ex.message!!.contains("tk not exactly 16 bytes")) + } + + // ---- ProvisionedData raw layout ------------------------------------------ + + @Test + fun provisionedDataExposesRawLayout() { + val raw = ByteArray(0x78) { (it + 1).toByte() } + val data = ProvisionedData(raw) + assertEquals(16, data.block00.size) + // little-endian u64 of bytes 0x11..0x18 + assertEquals(0x1817161514131211UL.toLong(), data.word10) + assertEquals(64, data.metadata64.size) + assertEquals(0x75, data.flavor) // raw[0x74] = (0x74 + 1) + } + + // ---- header assembly ----------------------------------------------------- + + @Test + fun anisetteHeadersUseRealOtpDerivation() { + val metadata = ByteArray(60) { 0x11.toByte() } + val mid = ByteArray(32) { 0x22.toByte() } + val keychain = hex("000102030405060708090a0b0c0d0e0f") + val now = 1_700_000_000_000L + val anisette = ClearAdiAnisette(metadata, mid, ClearAnisetteProvider.FLAVOR_MAC, "1710631289", keychain, "MacBookPro18,1") { now } + val headers = anisette.headers() + assertEquals("UTC", headers["X-Apple-I-TimeZone"]) + assertEquals("en_US", headers["X-Apple-Locale"]) + assertEquals("1710631289", headers["X-Apple-I-MD-RINFO"]) + assertEquals("2023-11-14T22:13:20Z", headers["X-Apple-I-Client-Time"]) + assertEquals("00010203-0405-0607-0809-0a0b0c0d0e0f", headers["X-Mme-Device-Id"]) + assertEquals(Base64.getEncoder().encodeToString(mid), headers["X-Apple-I-MD-M"]) + // the OTP must be the real derivation: recompute and compare + val otp = ClearAdiOtp.anisetteOtp(ClearAnisetteProvider.FLAVOR_MAC, metadata, mid, now / 1000) + assertEquals(Base64.getEncoder().encodeToString(otp), headers["X-Apple-I-MD"]) + assertEquals(28, Base64.getDecoder().decode(headers["X-Apple-I-MD"]!!).size) + } + + @Test + fun appleRequestHeadersTranscribeBuildAppleRequest() { + val provider = provider(ScriptedIdsHttp()) + val headers = provider.buildAppleRequestHeaders(1_700_000_000_000L) + assertEquals("-10000", headers["X-Apple-Baa-E"]) + assertEquals("2", headers["X-Apple-Baa-Avail"]) + assertEquals("akd", headers["X-Apple-Client-App-Name"]) + assertEquals("en-US,en;q=0.9", headers["Accept-Language"]) + assertEquals("*/*", headers["Accept"]) + assertEquals("application/x-www-form-urlencoded", headers["Content-Type"]) + assertEquals("AKAuthenticationError:-7066|com.apple.devicecheck.error.baa:-10000", headers["X-Apple-Baa-UE"]) + assertEquals("-7066", headers["X-Apple-Host-Baa-E"]) + // build_apple_request formats %+ (+00:00); only get_headers rewrites to Z + assertEquals("2023-11-14T22:13:20+00:00", headers["X-Apple-I-Client-Time"]) + assertEquals("00010203-0405-0607-0809-0a0b0c0d0e0f", headers["X-Mme-Device-Id"]) + assertEquals("akd-user-agent/1", headers["User-Agent"]) + // md_lu = sha256(keychain_identifier) hex + val lu = java.security.MessageDigest.getInstance("SHA-256") + .digest(hex("000102030405060708090a0b0c0d0e0f")) + assertEquals(lu.joinToString("") { "%02x".format(it) }, headers["X-Apple-I-MD-LU"]) + } + + // ---- state round-trip + full scripted flow -------------------------------- + + @Test + fun provisionResultJsonRoundTrip() { + val raw = ByteArray(0x78) { it.toByte() } + val result = ClearAdiProvisionResult(ProvisionedData(raw), "1710631289") + val restored = resultFromJson(resultToJson(result)) + assertContentEquals(raw, restored.provisionedData.raw) + assertEquals("1710631289", restored.rinfo) + } + + @Test + fun provisionFlowsThroughScriptedHttp() = kotlinx.coroutines.runBlocking { + val http = ScriptedIdsHttp() + val store = MemoryStateStore() + val provider = provider(http = http, store = store) + val result = provider.ensureProvisioned() + assertEquals(0x78, result.provisionedData.raw.size) + assertEquals("1710631289", result.rinfo) + // second call is served from the store without new HTTP traffic + val callsAfterFirst = http.calls + val second = provider.ensureProvisioned() + assertEquals(callsAfterFirst, http.calls) + assertContentEquals(result.provisionedData.raw, second.provisionedData.raw) + assertTrue(store.saved!!.contains("provisioned_data")) + } + + private fun provider(http: ScriptedIdsHttp, store: ClearAdiStateStore = MemoryStateStore()): ClearAnisetteProvider = + ClearAnisetteProvider( + http = http, + stateStore = store, + loginInfo = ClearAdiLoginInfo("akd-user-agent/1", "com.apple.mme/1 (MacBookPro18,1)"), + rng = FixedRng(), + cpimTailSeal = seal, + finishSeed = ByteArray(16), + keychainIdentifier = hex("000102030405060708090a0b0c0d0e0f"), + clock = { 1_700_000_000_000L }, + ) + + private class MemoryStateStore : ClearAdiStateStore { + var saved: String? = null + override fun save(json: String) { saved = json } + override fun load(): String? = saved + } + + /** Scripted GSA: lookup → start (spim) → finish (ptm/tk/rinfo), shaped like the reference. */ + private class ScriptedIdsHttp(private val tkSize: Int = 16) : IdsHttp { + var calls = 0 + override fun close() {} + override suspend fun get(url: String, headers: Map): IdsHttpResponse { + calls++ + assertTrue(url.startsWith("https://gsa.apple.com/grandslam/GsService2/lookup")) + assertTrue(headers.containsKey("X-Apple-Baa-E")) + return IdsHttpResponse( + 200, + emptyMap(), + XmlPlist.encode( + mapOf( + "urls" to mapOf( + "midStartProvisioning" to "https://gsa.apple.com/start", + "midFinishProvisioning" to "https://gsa.apple.com/finish", + ), + ), + ), + ) + } + override suspend fun put(url: String, headers: Map, body: ByteArray, contentType: String) = + throw UnsupportedOperationException() + override suspend fun post(url: String, headers: Map, body: ByteArray, contentType: String): IdsHttpResponse { + calls++ + val bodyPlist = Plist.parse(body) + return if (url.endsWith("/start")) { + assertTrue(headers.containsKey("X-Apple-I-Client-Time")) + assertBodyHasEmptyDicts(bodyPlist) + IdsHttpResponse( + 200, + emptyMap(), + XmlPlist.encode( + mapOf("Response" to mapOf("spim" to Base64.getEncoder().encodeToString(buildSpim()))), + ), + ) + } else { + // the cpim must be the base64 request body field + @Suppress("UNCHECKED_CAST") + val request = (bodyPlist as Map)["request"] as Map + assertTrue(request.containsKey("cpim")) + IdsHttpResponse( + 200, + emptyMap(), + XmlPlist.encode( + mapOf( + "Response" to mapOf( + // 240 B ptm ⇒ 15 decrypt blocks ⇒ ≥ 0x78 ProvisionedData source + "ptm" to Base64.getEncoder().encodeToString(ByteArray(240)), + "tk" to Base64.getEncoder().encodeToString(ByteArray(tkSize)), + "X-Apple-I-MD-RINFO" to "1710631289", + ), + ), + ), + ) + } + } + private fun assertBodyHasEmptyDicts(body: Any?) { + @Suppress("UNCHECKED_CAST") + val m = body as Map + assertEquals(0, (m["header"] as Map<*, *>).size) + assertEquals(0, (m["request"] as Map<*, *>).size) + } + } + + private fun readBeU32(b: ByteArray, off: Int): Int = + ((b[off].toInt() and 0xff) shl 24) or ((b[off + 1].toInt() and 0xff) shl 16) or + ((b[off + 2].toInt() and 0xff) shl 8) or (b[off + 3].toInt() and 0xff) + + private fun readBeU64(b: ByteArray, off: Int): Long { + var v = 0L + for (i in 0 until 8) v = (v shl 8) or (b[off + i].toLong() and 0xff) + return v + } +} + +private fun buildSpim(field1: Int = 0, payload: ByteArray = ByteArray(240), tail: ByteArray = ByteArray(0)): ByteArray { + val out = ByteArray(8 + payload.size + tail.size) + out[0] = (field1 ushr 24).toByte(); out[1] = (field1 ushr 16).toByte() + out[2] = (field1 ushr 8).toByte(); out[3] = field1.toByte() + val len = payload.size + out[4] = (len ushr 24).toByte(); out[5] = (len ushr 16).toByte() + out[6] = (len ushr 8).toByte(); out[7] = len.toByte() + payload.copyInto(out, 8) + tail.copyInto(out, 8 + payload.size) + return out +}