diff --git a/pyproject.toml b/pyproject.toml index d00b886..bb807c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,6 @@ classifiers = [ keywords = ["iPhone", "backup", "forensics", "iOS", "WhatsApp", "decryption", "iOS backup", "iTunes Backup"] dependencies = [ - "biplist>=1.0.3", "pycryptodome>=3.20.0" ] diff --git a/src/iphone_backup_decrypt/iphone_backup.py b/src/iphone_backup_decrypt/iphone_backup.py index 4cd8533..22187b5 100644 --- a/src/iphone_backup_decrypt/iphone_backup.py +++ b/src/iphone_backup_decrypt/iphone_backup.py @@ -1,11 +1,10 @@ import os.path +import plistlib import shutil import sqlite3 import struct import tempfile -import biplist - from . import google_iphone_dataprotection __all__ = ["EncryptedBackup", "RelativePath", "RelativePathsLike", "DomainLike", "MatchFiles"] @@ -138,7 +137,7 @@ def _read_and_unlock_keybag(self): return self._unlocked # Open the Manifest.plist file to access the Keybag: with open(self._manifest_plist_path, 'rb') as infile: - self._manifest_plist = biplist.readPlist(infile) + self._manifest_plist = plistlib.load(infile) self._keybag = google_iphone_dataprotection.Keybag(self._manifest_plist['BackupKeyBag']) # Attempt to unlock the Keybag: self._unlocked = self._keybag.unlockWithPassphrase(self._passphrase) @@ -188,8 +187,8 @@ def _decrypt_inner_file(self, *, file_id, file_bplist, if_modified_since=None): # Ensure we've already unlocked the Keybag: self._read_and_unlock_keybag() # Read the plist data and extract file metadata: - plist = biplist.readPlistFromString(file_bplist) - file_data = plist['$objects'][plist['$top']['root'].integer] + plist = plistlib.loads(file_bplist) + file_data = plist['$objects'][plist['$top']['root'].data] file_mtime = file_data.get("LastModified") # Was the file modified since the time requested? if if_modified_since and file_mtime <= if_modified_since: @@ -199,7 +198,7 @@ def _decrypt_inner_file(self, *, file_id, file_bplist, if_modified_since=None): protection_class = file_data['ProtectionClass'] if "EncryptionKey" not in file_data: raise ValueError("Path is not an encrypted file.") # File is not encrypted; either a directory or empty. - encryption_key = plist['$objects'][file_data['EncryptionKey'].integer]['NS.data'][4:] + encryption_key = plist['$objects'][file_data['EncryptionKey'].data]['NS.data'][4:] inner_key = self._keybag.unwrapKeyForClass(protection_class, encryption_key) # Find the encrypted version of the file on disk and decrypt it: filename_in_backup = os.path.join(self._backup_directory, file_id[:2], file_id)