mirror of
https://github.com/mvt-project/mvt.git
synced 2024-06-30 16:18:54 +00:00
Refactored to include functionality in existing DecryptBackup class
This commit is contained in:
parent
bfcfb3aa06
commit
b264ae946d
|
@ -17,7 +17,6 @@ from mvt.common.module import run_module, save_timeline
|
||||||
from mvt.common.options import MutuallyExclusiveOption
|
from mvt.common.options import MutuallyExclusiveOption
|
||||||
|
|
||||||
from .decrypt import DecryptBackup
|
from .decrypt import DecryptBackup
|
||||||
from .keyutils import KeyUtils
|
|
||||||
from .modules.fs import BACKUP_MODULES, FS_MODULES
|
from .modules.fs import BACKUP_MODULES, FS_MODULES
|
||||||
|
|
||||||
# Setup logging using Rich.
|
# Setup logging using Rich.
|
||||||
|
@ -55,6 +54,7 @@ def cli():
|
||||||
@click.argument("BACKUP_PATH", type=click.Path(exists=True))
|
@click.argument("BACKUP_PATH", type=click.Path(exists=True))
|
||||||
def decrypt_backup(destination, password, key_file, backup_path):
|
def decrypt_backup(destination, password, key_file, backup_path):
|
||||||
backup = DecryptBackup(backup_path, destination)
|
backup = DecryptBackup(backup_path, destination)
|
||||||
|
|
||||||
if password:
|
if password:
|
||||||
backup.decrypt_with_password(password)
|
backup.decrypt_with_password(password)
|
||||||
elif key_file:
|
elif key_file:
|
||||||
|
@ -63,13 +63,16 @@ def decrypt_backup(destination, password, key_file, backup_path):
|
||||||
raise click.ClickException("Missing required option. Specify either "
|
raise click.ClickException("Missing required option. Specify either "
|
||||||
"--password or --key-file.")
|
"--password or --key-file.")
|
||||||
|
|
||||||
|
backup.process_backup()
|
||||||
|
|
||||||
|
|
||||||
#==============================================================================
|
#==============================================================================
|
||||||
# Command: extract-key
|
# Command: extract-key
|
||||||
#==============================================================================
|
#==============================================================================
|
||||||
@cli.command("extract-key", help="Extract decryption key from an iTunes backup")
|
@cli.command("extract-key", help="Extract decryption key from an iTunes backup")
|
||||||
@click.option("--password", "-p",
|
@click.option("--password", "-p",
|
||||||
help="Password to use to decrypt the backup",
|
help="Password to use to decrypt the backup",
|
||||||
prompt="Backup password",
|
prompt="Enter backup password",
|
||||||
hide_input=True, prompt_required=False, required=True)
|
hide_input=True, prompt_required=False, required=True)
|
||||||
@click.option("--key-file", "-k",
|
@click.option("--key-file", "-k",
|
||||||
help="Key file to be written (if unset, will print to STDOUT)",
|
help="Key file to be written (if unset, will print to STDOUT)",
|
||||||
|
@ -77,11 +80,12 @@ def decrypt_backup(destination, password, key_file, backup_path):
|
||||||
type=click.Path(exists=False, file_okay=True, dir_okay=False, writable=True))
|
type=click.Path(exists=False, file_okay=True, dir_okay=False, writable=True))
|
||||||
@click.argument("BACKUP_PATH", type=click.Path(exists=True))
|
@click.argument("BACKUP_PATH", type=click.Path(exists=True))
|
||||||
def extract_key(password, backup_path, key_file):
|
def extract_key(password, backup_path, key_file):
|
||||||
key_utils = KeyUtils(password, backup_path)
|
backup = DecryptBackup(backup_path)
|
||||||
|
backup.decrypt_with_password(password)
|
||||||
|
backup.get_key()
|
||||||
|
|
||||||
if key_file:
|
if key_file:
|
||||||
key_utils.write_key(key_file)
|
backup.write_key(key_file)
|
||||||
else:
|
|
||||||
key_utils.print_key()
|
|
||||||
|
|
||||||
|
|
||||||
#==============================================================================
|
#==============================================================================
|
||||||
|
|
|
@ -18,7 +18,7 @@ class DecryptBackup:
|
||||||
using either a password or a key file.
|
using either a password or a key file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, backup_path, dest_path):
|
def __init__(self, backup_path, dest_path=None):
|
||||||
"""Decrypts an encrypted iOS backup.
|
"""Decrypts an encrypted iOS backup.
|
||||||
:param backup_path: Path to the encrypted backup folder
|
:param backup_path: Path to the encrypted backup folder
|
||||||
:param dest_path: Path to the folder where to store the decrypted backup
|
:param dest_path: Path to the folder where to store the decrypted backup
|
||||||
|
@ -26,8 +26,12 @@ class DecryptBackup:
|
||||||
self.backup_path = backup_path
|
self.backup_path = backup_path
|
||||||
self.dest_path = dest_path
|
self.dest_path = dest_path
|
||||||
self._backup = None
|
self._backup = None
|
||||||
|
self._decryption_key = None
|
||||||
|
|
||||||
|
def process_backup(self):
|
||||||
|
if not os.path.exists(self.dest_path):
|
||||||
|
os.makedirs(self.dest_path)
|
||||||
|
|
||||||
def _process_backup(self):
|
|
||||||
manifest_path = os.path.join(self.dest_path, "Manifest.db")
|
manifest_path = os.path.join(self.dest_path, "Manifest.db")
|
||||||
# We extract a decrypted Manifest.db.
|
# We extract a decrypted Manifest.db.
|
||||||
self._backup.getManifestDB()
|
self._backup.getManifestDB()
|
||||||
|
@ -69,9 +73,6 @@ class DecryptBackup:
|
||||||
"""
|
"""
|
||||||
log.info("Decrypting iOS backup at path %s with password", self.backup_path)
|
log.info("Decrypting iOS backup at path %s with password", self.backup_path)
|
||||||
|
|
||||||
if not os.path.exists(self.dest_path):
|
|
||||||
os.makedirs(self.dest_path)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._backup = iOSbackup(udid=os.path.basename(self.backup_path),
|
self._backup = iOSbackup(udid=os.path.basename(self.backup_path),
|
||||||
cleartextpassword=password,
|
cleartextpassword=password,
|
||||||
|
@ -79,9 +80,6 @@ class DecryptBackup:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.exception(e)
|
log.exception(e)
|
||||||
log.critical("Failed to decrypt backup. Did you provide the correct password?")
|
log.critical("Failed to decrypt backup. Did you provide the correct password?")
|
||||||
return
|
|
||||||
else:
|
|
||||||
self._process_backup()
|
|
||||||
|
|
||||||
def decrypt_with_key_file(self, key_file):
|
def decrypt_with_key_file(self, key_file):
|
||||||
"""Decrypts an encrypted iOS backup using a key file.
|
"""Decrypts an encrypted iOS backup using a key file.
|
||||||
|
@ -90,9 +88,6 @@ class DecryptBackup:
|
||||||
log.info("Decrypting iOS backup at path %s with key file %s",
|
log.info("Decrypting iOS backup at path %s with key file %s",
|
||||||
self.backup_path, key_file)
|
self.backup_path, key_file)
|
||||||
|
|
||||||
if not os.path.exists(self.dest_path):
|
|
||||||
os.makedirs(self.dest_path)
|
|
||||||
|
|
||||||
with open(key_file, "rb") as handle:
|
with open(key_file, "rb") as handle:
|
||||||
key_bytes = handle.read()
|
key_bytes = handle.read()
|
||||||
|
|
||||||
|
@ -109,6 +104,31 @@ class DecryptBackup:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.exception(e)
|
log.exception(e)
|
||||||
log.critical("Failed to decrypt backup. Did you provide the correct key file?")
|
log.critical("Failed to decrypt backup. Did you provide the correct key file?")
|
||||||
|
|
||||||
|
def get_key(self):
|
||||||
|
"""Retrieve and prints the encryption key.
|
||||||
|
"""
|
||||||
|
if not self._backup:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._decryption_key = self._backup.getDecryptionKey()
|
||||||
|
log.info("Derived decryption key for backup at path %s is: \"%s\"",
|
||||||
|
self.backup_path, self._decryption_key)
|
||||||
|
|
||||||
|
def write_key(self, key_path):
|
||||||
|
"""Save extracted key to file.
|
||||||
|
:param key_path: Path to the file where to write the derived decryption key.
|
||||||
|
"""
|
||||||
|
if not self._decryption_key:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(key_path, 'w') as handle:
|
||||||
|
handle.write(self._decryption_key)
|
||||||
|
except Exception as e:
|
||||||
|
log.exception(e)
|
||||||
|
log.critical("Failed to write key to file: %s", key_path)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
self._process_backup()
|
log.info("Wrote decryption key to file: %s. This file is equivalent to a plaintext password. Keep it safe!",
|
||||||
|
key_path)
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
import os
|
|
||||||
import logging
|
|
||||||
from iOSbackup import iOSbackup
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
class KeyUtils:
|
|
||||||
"""This class provides functions to extract a backup key from a password.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, password, backup_path):
|
|
||||||
"""Generates a key file for an iOS backup.
|
|
||||||
:param password: Backup encryption password
|
|
||||||
:param key_file: Path to the file where to store the generated key file
|
|
||||||
"""
|
|
||||||
self.password = password
|
|
||||||
self.backup_path = backup_path
|
|
||||||
self._backup = None
|
|
||||||
|
|
||||||
def get_key(self):
|
|
||||||
try:
|
|
||||||
self._backup = iOSbackup(udid=os.path.basename(self.backup_path),
|
|
||||||
cleartextpassword=self.password,
|
|
||||||
backuproot=os.path.dirname(self.backup_path))
|
|
||||||
except Exception as e:
|
|
||||||
log.exception(e)
|
|
||||||
log.critical("Failed to decrypt backup. Did you provide the correct password?")
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
self.decryption_key = self._backup.getDecryptionKey()
|
|
||||||
log.info("Extracted decryption key.")
|
|
||||||
|
|
||||||
def print_key(self):
|
|
||||||
self.get_key()
|
|
||||||
log.info("Decryption key for backup at path %s is:\n %s",
|
|
||||||
self.backup_path, self.decryption_key)
|
|
||||||
|
|
||||||
def write_key(self, key_file):
|
|
||||||
self.get_key()
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(key_file, 'w') as writer:
|
|
||||||
writer.write(self.decryption_key)
|
|
||||||
except Exception as e:
|
|
||||||
log.exception(e)
|
|
||||||
log.critical("Failed to write key file.")
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
log.info("Wrote decryption key for backup at path %s to file %s",
|
|
||||||
self.backup_path, key_file)
|
|
||||||
log.warn("The file %s is equivalent to a plaintext password. Keep this file safe!",
|
|
||||||
key_file)
|
|
Loading…
Reference in New Issue
Block a user