Git · dadoum.zone
Repositories
Help
Report an Issue
apple-crates
Code
Commits
Branches
Tags
Search
Tree:
a74924e
Branches
Tags
main
apple-crates
adi
src
proxy.rs
Refactor and unify a lot of things for another project and implement airdrop support
Dadoum
commited
a74924e
at 2026-10-25 22:15:58
proxy.rs
Blame
History
Raw
use crate::calls::ADIMessage; use serde::{Serialize, Serializer}; use std::ffi::CStr; use std::marker::PhantomData; use std::ops::Deref; use thiserror::Error; #[derive(Copy, Clone, Debug, PartialEq)] pub enum EncryptionType { Clear, Encrypted, } impl From<EncryptionType> for u32 { fn from(value: EncryptionType) -> Self { match value { EncryptionType::Clear => 1, EncryptionType::Encrypted => 2, } } } impl Serialize for EncryptionType { fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { u32::from(*self).serialize(serializer) } } #[repr(i32)] #[derive(Debug, PartialEq, Eq, Error)] pub enum ADIError { #[error("Invalid parameters, have all the library fields been properly initialized? (-45001)")] InvalidParameters = -45001, #[error("Invalid parameters (-45002)")] InvalidParameters2 = -45002, #[error("Trust Key is invalid (-45003)")] InvalidTK = -45003, // -45004 - Unknown, but observed in fm23w5mn5o // <unknown = -45004>, #[error("Valid PTM/TK pair, but not matching the inner ADI state (-45006)")] PTMTKPairMismatch = -45006, #[error("Thread error (-45012)")] ThreadingError = -45012, #[error("Mach call failed, can't contact adid (-45016)")] UnreachableADID = -45016, #[error("Mach call cannot be sent to adid, have you got the right entitlements? (-45017)")] MachMessageError = -45017, #[error("Unknown encryption scheme given to CoreADI (-45018)")] InvalidEncryptionScheme = -45018, #[error("Unimplemented call (-45019)")] InvalidFunctionCode = -45019, #[error("Cannot decrypt the input parameter block (-45020)")] InvalidParameterBody = -45020, #[error("Unknown session number (-45025)")] InvalidSession = -45025, #[error("Empty session number (-45026)")] EmptySession = -45026, #[error("Cryptographic block: Invalid input header (-45031)")] InvalidEncryptedBlockHeader = -45031, #[error("Cryptographic block: Invalid input length (-45032)")] InvalidEncryptedBlockLength = -45032, #[error("Cryptographic block: Input has been tampered with (-45033)")] InvalidEncryptedBlockContent = -45033, #[error("Invalid ADI call: input buffer is too small (-45034)")] InvalidADICall = -45034, #[error("Invalid time (-45036)")] InvalidTime = -45036, #[error("Invalid hardware identifiers (-45046)")] InvalidHardwareIdentifiers = -45046, #[error("Filesystem error (-45054)")] FilesystemError = -45054, #[error("Device has not been provisioned (-45061)")] NotProvisioned = -45061, #[error("No provisioning data to erase (-45062)")] NoProvisioningToErase = -45062, #[error("Another provisioning session is pending (-45063)")] PendingSession = -45063, #[error("Session has been previously ended (-45066)")] TerminatedSession = -45066, #[error("Cannot load the CoreADI executable (-45075)")] LibraryLoadingError = -45075, #[error( "This CoreADI distribution has been phased out in favor of adid. Downgrade CoreADI or switch to adid (-45076)" )] UnsupportedCoreADI = -45076, #[error("Unknown error ({0})")] UnknownError(i32) = -1, } impl ADIError { /// Returns the native ADI error code, preserving unknown values. pub const fn code(&self) -> i32 { match self { ADIError::InvalidParameters => -45001, ADIError::InvalidParameters2 => -45002, ADIError::InvalidTK => -45003, ADIError::PTMTKPairMismatch => -45006, ADIError::ThreadingError => -45012, ADIError::UnreachableADID => -45016, ADIError::MachMessageError => -45017, ADIError::InvalidEncryptionScheme => -45018, ADIError::InvalidFunctionCode => -45019, ADIError::InvalidParameterBody => -45020, ADIError::InvalidSession => -45025, ADIError::EmptySession => -45026, ADIError::InvalidEncryptedBlockHeader => -45031, ADIError::InvalidEncryptedBlockLength => -45032, ADIError::InvalidEncryptedBlockContent => -45033, ADIError::InvalidADICall => -45034, ADIError::InvalidTime => -45036, ADIError::InvalidHardwareIdentifiers => -45046, ADIError::FilesystemError => -45054, ADIError::NotProvisioned => -45061, ADIError::NoProvisioningToErase => -45062, ADIError::PendingSession => -45063, ADIError::TerminatedSession => -45066, ADIError::LibraryLoadingError => -45075, ADIError::UnsupportedCoreADI => -45076, ADIError::UnknownError(code) => *code, } } } impl From<i32> for ADIError { fn from(value: i32) -> Self { match value { -45001 => ADIError::InvalidParameters, -45002 => ADIError::InvalidParameters2, -45003 => ADIError::InvalidTK, -45006 => ADIError::PTMTKPairMismatch, -45012 => ADIError::ThreadingError, -45016 => ADIError::UnreachableADID, -45017 => ADIError::MachMessageError, -45018 => ADIError::InvalidEncryptionScheme, -45019 => ADIError::InvalidFunctionCode, -45020 => ADIError::InvalidParameterBody, -45025 => ADIError::InvalidSession, -45026 => ADIError::EmptySession, -45031 => ADIError::InvalidEncryptedBlockHeader, -45032 => ADIError::InvalidEncryptedBlockLength, -45033 => ADIError::InvalidEncryptedBlockContent, -45034 => ADIError::InvalidADICall, -45036 => ADIError::InvalidTime, -45046 => ADIError::InvalidHardwareIdentifiers, -45054 => ADIError::FilesystemError, -45061 => ADIError::NotProvisioned, -45062 => ADIError::NoProvisioningToErase, -45063 => ADIError::PendingSession, -45066 => ADIError::TerminatedSession, -45075 => ADIError::LibraryLoadingError, -45076 => ADIError::UnsupportedCoreADI, _ => ADIError::UnknownError(value), } } } pub type ADIResult<T> = Result<T, ADIError>; #[derive(Serialize, PartialEq, Debug)] #[repr(C)] pub struct ADIPayload<Message: ADIMessage> { pub encryption_type: EncryptionType, pub marker: u32, pub payload: Message, } #[must_use = "Must be freed using its proxy."] pub struct ADIBuffer<'lt, T>(pub Option<&'lt [T]>); impl<'lt, T> Deref for ADIBuffer<'lt, T> { type Target = [T]; fn deref(&self) -> &Self::Target { self.0.unwrap_or_default() } } #[must_use = "Must be destroyed or finished using its proxy."] pub struct ADIProvisioningSession<'lt> { pub val: u32, pub proxy: PhantomData<&'lt dyn ADIProxy>, } impl<T> Drop for ADIBuffer<'_, T> { fn drop(&mut self) { if !std::thread::panicking() { // it should never be called :( // in D we could have added a static assert here giving a compiling error and preventing misuse. panic!("The ADIBuffer {self:p} has not been disposed properly."); } } } impl Drop for ADIProvisioningSession<'_> { fn drop(&mut self) { if !std::thread::panicking() { // it should never be called :( // in D we could have added a static assert here giving a compiling error and preventing misuse. panic!( "The ADIProvisioningSession {} has not been terminated properly.", self.val ); } } } #[derive(Debug, Clone)] pub struct ADIAccount { pub ds_id: i64, pub mid: Vec<u8>, pub otp: Vec<u8>, } pub trait ADIProxy { /// Returns whether ADI stores provisioning data for a given DSID. fn is_machine_provisioned(&self, ds_id: i64) -> ADIResult<bool>; /// Get a list of every provisioned DSID along with its associated MID and OTP. fn get_all_provisioned_accounts(&self) -> ADIResult<Vec<ADIAccount>>; /// Starts a provisioning session for the DSID. fn start_provisioning( &self, ds_id: i64, spim: &[u8], ) -> ADIResult<(Vec<u8>, ADIProvisioningSession<'_>)>; /// Ends a provisioning session. fn end_provisioning( &self, session: ADIProvisioningSession, ptm: &[u8], tk: &[u8], ) -> ADIResult<()>; /// Cancels a provisioning session. fn destroy_provisioning_session(&self, session: ADIProvisioningSession) -> ADIResult<()>; fn set_idms_routing(&self, ds_id: i64, routing_info: u64) -> ADIResult<()>; fn get_idms_routing(&self, ds_id: i64) -> ADIResult<u64>; fn synchronize(&self, ds_id: i64, sim: &[u8]) -> ADIResult<(Vec<u8>, Vec<u8>)>; fn erase_provisioning(&self, ds_id: i64) -> ADIResult<()>; fn request_otp(&self, ds_id: i64) -> ADIResult<(Vec<u8>, Vec<u8>)>; /// Exclusive to Android's CoreADI: set the provisioning path. fn set_provisioning_path(&self, path: &CStr) -> ADIResult<()>; /// Exclusive to Android's CoreADI: set the hardware identifier used by the library. fn set_android_id(&self, id: &str) -> ADIResult<()>; /// Exclusive to Apple's ADI implementations: compute a 2FA code. fn generate_2fa_code(&self, ds_id: i64) -> ADIResult<u32>; } #[cfg(test)] mod tests { use super::*; #[test] fn native_error_codes_round_trip() { for code in -45100..=0 { assert_eq!(ADIError::from(code).code(), code); } assert_eq!(ADIError::UnknownError(-49876).code(), -49876); } }