7 releases
Uses new Rust 2024
new 0.2.0 | May 19, 2025 |
---|---|
0.1.5 | May 18, 2025 |
#274 in Cryptography
439 downloads per month
95KB
1.5K
SLoC
crabapple
Crabapple is a Rust library for reading, inspecting, and extracting data from encrypted iOS backups created by Finder, Apple Devices, or iTunes.
⚠️ Warning ⚠️
This library is currently in an alpha state and should not be used in production code.
Features
- Load and parse the backup's
Manifest.plist
to obtain metadata, device info, and encryption parameters - Derive encryption keys using
PBKDF2
(HMAC-SHA256
thenHMAC-SHA1
) and unwrap protection class keys via AES Key Wrap (RFC 3394
) - Decrypt and query the
AES-256
encryptedManifest.db
, exposing backup file metadata viarusqlite
- Retrieve and decrypt individual files by protection class (per-file
AES-CBC
withPKCS7
padding) - Cross-platform support for macOS, Windows, and Linux
Installation
This library is available on crates.io.
Documentation
Documentation is available on docs.rs.
Quick Start
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::new(udid_folder, &auth)?;
// List all files in the backup
let entries = backup.get_backup_files_list()?;
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());
}
Ok(())
}
Getting Basic Device Information
You can retrieve device metadata (like device name, iOS version, and UDID) without opening the full backup database:
use std::path::Path;
use crabapple::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(())
}
Using a Pre-derived Key
If you have already derived the encryption key elsewhere, provide it directly:
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::new(udid_folder, &auth)?;
// ... proceed as normal
Ok(())
}
Error Handling
crabapple
uses a custom BackupError
enum for error reporting. You can match on specific cases:
use crabapple::{Backup, Authentication, BackupError};
match Backup::new("/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),
}
Crabapple Tree
Dependencies
~26MB
~510K SLoC