Git · dadoum.zone
Repositories
Help
Report an Issue
apple-crates
Code
Commits
Branches
Tags
Search
Tree:
198bf39
Branches
Tags
main
apple-crates
fairplay
README.md
Add FairPlay crate reimplementing fairplay-decrypt and fix APS
Dadoum
commited
198bf39
at 2026-10-25 21:12:14
README.md
Blame
History
Raw
# fairplay Clean Rust port of https://github.com/EthanArbuckle/fairplay-decrypt. A Rust library for the recovered FairPlay page-key algorithm and AES-128-CBC decryption of protected executable regions. It has no IPA, bundle, filesystem, Mach-O or device dependencies. The caller supplies the region and metadata. ```rust use fairplay::{Decryptor, PageRecords, PAGE_SIZE}; fn decrypt_selected_region( credential: &[u8; 16], sinf: &[u8], supf: &[u8], original_file_offset: u64, encrypted_region: &mut [u8], ) -> Result<usize, Box<dyn std::error::Error>> { let decoder = Decryptor::from_sinf(credential, sinf)?; let records = PageRecords::from_supf(supf, 0x0100000c, 0)?; let first_page = u32::try_from(original_file_offset / PAGE_SIZE as u64)?; Ok(decoder.decrypt_region_in_place(encrypted_region, first_page, records)?) } ``` Cache a `Decryptor` for binaries sharing a SINF. `from_sinf_fields` accepts an already parsed `SinfFields { name, iviv, private }`; `from_work_key` accepts the recovered 16-byte masked working key directly. A working key differs from the saved credential and from an individual page AES key. `PageRecords::from_bytes` borrows flat 32-byte records from an existing SUPF parser. `from_supf` provides optional metadata parsing and selects an exact CPU type/subtype; it supports SUPF 3/5 and tags 507/510/612. SINF decoding handles both 440-byte and 448-byte private records. No code parses the executable. ## Caller responsibilities - Pass only the protected region, containing a nonzero whole number of 4096-byte pages. Decryption resets CBC with each record's IV and removes no padding. Extra SUPF records are allowed. - Compute the first absolute page index from the original complete executable offset. For a FAT binary this includes the architecture slice's file base: `(slice_base + cryptoff) / 4096`. Do not reset it to zero for a section or slice. - Match the SUPF architecture and record range to the selected region. Records start at the beginning of the protected region. For a later subregion, advance both `first_page_index` and the record range via `records.slice(start..end)`. - Clear the executable's encryption flag only after decryption succeeds, and handle bundle metadata, signing and output publication in the consuming code. For page-at-a-time or parallel processing, `PageRecords::get` provides a `PageRecord` for `decrypt_page_in_place`. `derive_page_key` is available when another component owns CBC decryption. The decoder can be shared across threads. Region decryption allocates no buffers. Size, record count and page-index validation happens before mutation. Those checks do not authenticate page ciphertext: the recovered scheme uses CBC without an authentication tag. The SINF private record's markers detect credentials that fail its decoding check. Secrets are omitted from Debug and temporary SINF keys/plaintext and AES key schedules use zeroization.