Rust library for reading, inspecting, and extracting data from encrypted iOS backups
Rust
75
85 commits
updated May 27, 2026
crabapple is a Rust library for reading, inspecting, and extracting data from encrypted iOS backups created by Finder, Apple Devices, or iTunes.
Inspired by imessage-exporter, crabapple provides a flexible foundation for any project that needs to access iOS backup data.
Manifest.plist to obtain metadata, device info, and encryption parametersPBKDF2 (HMAC-SHA256 then HMAC-SHA1) and unwrap protection class keys via AES Key Wrap (RFC 3394)AES-256 encrypted Manifest.db, exposing backup file metadata via rusqliteAES-CBC with PKCS7 padding)This library is available on crates.io.
Documentation is available on docs.rs.
use std::{io::copy, fs::File};
use crabapple::{Backup, Authentication};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize a backup session for a device UDID with a password
let udid_folder = "/Users/you/Library/Application Support/MobileSync/Backup/DEVICE_UDID";
let auth = Authentication::Password("your_password".into());
let backup = Backup::open(udid_folder, &auth)?;
// List all files in the backup
let entries = backup.entries()?;
for entry in &entries {
println!("{} - {}/{}", entry.file_id, entry.domain, entry.relative_path);
}
// Decrypt and read a file entry as a stream
if let Some(entry) = entries.first() {
let mut stream = backup.decrypt_entry_stream(&entry)?;
// Write the stream to a file
let mut file = File::create("decrypted.txt")?;
copy(&mut stream, &mut file)?;
}
// Alternatively, decrypt and read a file entry into memory
if let Some(entry) = entries.get(2) {
let data = backup.decrypt_entry(&entry)?;
println!("Decrypted {} ({} bytes)", entry.relative_path, data.len());
}
// Get the derived key for use elsewhere:
let derived_key = backup.decryption_key_hex();
Ok(())
}
Pre-derived keys bypass the expensive key derivation process:
use crabapple::{Backup, Authentication};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let udid_folder = "/path/to/backup";
let hex_key = "abcdef0123456789...";
let auth = Authentication::DerivedKey(hex_key.to_string());
let backup = Backup::open(udid_folder, &auth)?;
// ... proceed as normal
Ok(())
}
You can retrieve device metadata (like device name, iOS version, and UDID) without opening the full backup database:
use std::path::Path;
use crabapple::backup::device::get_device_basic_info;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let udid_folder = Path::new("/Users/you/Library/Application Support/MobileSync/Backup/DEVICE_UDID");
let info = get_device_basic_info(udid_folder)?;
println!("Device: {} (iOS {})", info.device_name, info.product_version);
println!("UDID: {}", info.unique_device_id);
Ok(())
}
This information is also present on a decrypted Backup instance:
use crabapple::{Backup, Authentication};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let udid_folder = "/path/to/backup";
let hex_key = "abcdef0123456789...";
let auth = Authentication::DerivedKey(hex_key.to_string());
let backup = Backup::open(udid_folder, &auth)?;
println!("Device: {} (iOS {})",
backup.lockdown().device_name,
backup.lockdown().product_version
);
println!("UDID: {}", backup.udid()?);
Ok(())
}
crabapple uses a custom BackupError enum for error reporting. You can match on specific cases:
use crabapple::{Backup, Authentication};
use crabapple::error::BackupError;
match Backup::open("/bad/path", &Authentication::Password("pass".into())) {
Ok(b) => println!("Loaded backup successfully"),
Err(BackupError::ManifestPlistNotFound(path)) => eprintln!("Missing Manifest.plist: {}", path),
Err(err) => eprintln!("Error initializing backup: {}", err),
}
This library targets the current latest public release for iOS. It should work with backups from iOS 10.2 or later, but all features may not be available.

85 commits
Rust
100.0%
Rust library for reading, inspecting, and extracting data from encrypted iOS backups
Rust
75
85 commits
updated May 27, 2026
crabapple is a Rust library for reading, inspecting, and extracting data from encrypted iOS backups created by Finder, Apple Devices, or iTunes.
Inspired by imessage-exporter, crabapple provides a flexible foundation for any project that needs to access iOS backup data.
Manifest.plist to obtain metadata, device info, and encryption parametersPBKDF2 (HMAC-SHA256 then HMAC-SHA1) and unwrap protection class keys via AES Key Wrap (RFC 3394)AES-256 encrypted Manifest.db, exposing backup file metadata via rusqliteAES-CBC with PKCS7 padding)This library is available on crates.io.
Documentation is available on docs.rs.
use std::{io::copy, fs::File};
use crabapple::{Backup, Authentication};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize a backup session for a device UDID with a password
let udid_folder = "/Users/you/Library/Application Support/MobileSync/Backup/DEVICE_UDID";
let auth = Authentication::Password("your_password".into());
let backup = Backup::open(udid_folder, &auth)?;
// List all files in the backup
let entries = backup.entries()?;
for entry in &entries {
println!("{} - {}/{}", entry.file_id, entry.domain, entry.relative_path);
}
// Decrypt and read a file entry as a stream
if let Some(entry) = entries.first() {
let mut stream = backup.decrypt_entry_stream(&entry)?;
// Write the stream to a file
let mut file = File::create("decrypted.txt")?;
copy(&mut stream, &mut file)?;
}
// Alternatively, decrypt and read a file entry into memory
if let Some(entry) = entries.get(2) {
let data = backup.decrypt_entry(&entry)?;
println!("Decrypted {} ({} bytes)", entry.relative_path, data.len());
}
// Get the derived key for use elsewhere:
let derived_key = backup.decryption_key_hex();
Ok(())
}
Pre-derived keys bypass the expensive key derivation process:
use crabapple::{Backup, Authentication};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let udid_folder = "/path/to/backup";
let hex_key = "abcdef0123456789...";
let auth = Authentication::DerivedKey(hex_key.to_string());
let backup = Backup::open(udid_folder, &auth)?;
// ... proceed as normal
Ok(())
}
You can retrieve device metadata (like device name, iOS version, and UDID) without opening the full backup database:
use std::path::Path;
use crabapple::backup::device::get_device_basic_info;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let udid_folder = Path::new("/Users/you/Library/Application Support/MobileSync/Backup/DEVICE_UDID");
let info = get_device_basic_info(udid_folder)?;
println!("Device: {} (iOS {})", info.device_name, info.product_version);
println!("UDID: {}", info.unique_device_id);
Ok(())
}
This information is also present on a decrypted Backup instance:
use crabapple::{Backup, Authentication};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let udid_folder = "/path/to/backup";
let hex_key = "abcdef0123456789...";
let auth = Authentication::DerivedKey(hex_key.to_string());
let backup = Backup::open(udid_folder, &auth)?;
println!("Device: {} (iOS {})",
backup.lockdown().device_name,
backup.lockdown().product_version
);
println!("UDID: {}", backup.udid()?);
Ok(())
}
crabapple uses a custom BackupError enum for error reporting. You can match on specific cases:
use crabapple::{Backup, Authentication};
use crabapple::error::BackupError;
match Backup::open("/bad/path", &Authentication::Password("pass".into())) {
Ok(b) => println!("Loaded backup successfully"),
Err(BackupError::ManifestPlistNotFound(path)) => eprintln!("Missing Manifest.plist: {}", path),
Err(err) => eprintln!("Error initializing backup: {}", err),
}
This library targets the current latest public release for iOS. It should work with backups from iOS 10.2 or later, but all features may not be available.

85 commits
Rust
100.0%