Replaces pyaes with cryptography and reorganize backup parser code

This commit is contained in:
tek committed 2022-03-04 15:05:10 +01:00
1 parent 6cc67f3c1d
commit a4d08f8f35
2 files changed
+34 -47

No files matched your search

+33 -46
View File
@@ -7,9 +7,11 @@ import io
import zlib import zlib
import json import json
import tarfile import tarfile
import hashlib
import datetime import datetime
import pyaes from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding
from mvt.common.utils import check_for_links, convert_timestamp_to_iso from mvt.common.utils import check_for_links, convert_timestamp_to_iso
@@ -28,37 +30,7 @@ class InvalidBackupPassword(AndroidBackupParsingError):
pass pass
def decrypt_master_key_blob(key, aes_iv, cipher_text):
"""
Decrypt the master key blob with AES
From : https://github.com/FloatingOctothorpe/dump_android_backup
"""
aes = pyaes.AESModeOfOperationCBC(key, aes_iv)
plain_text = b''
while len(plain_text) < len(cipher_text):
offset = len(plain_text)
plain_text += aes.decrypt(cipher_text[offset:(offset + 16)])
blob = io.BytesIO(plain_text)
master_iv_length = ord(blob.read(1))
master_iv = blob.read(master_iv_length)
master_key_length = ord(blob.read(1))
master_key = blob.read(master_key_length)
master_key_checksum_length = ord(blob.read(1))
master_key_checksum = blob.read(master_key_checksum_length)
return master_iv, master_key, master_key_checksum
def to_utf8_bytes(input_bytes): def to_utf8_bytes(input_bytes):
"""Emulate bytes being converted into a "UTF8 byte array"
For more info see the Bouncy Castle Crypto package Strings.toUTF8ByteArray
method:
https://github.com/bcgit/bc-java/blob/master/core/src/main/java/org/bouncycastle/util/Strings.java#L142
From https://github.com/FloatingOctothorpe/dump_android_backup
"""
output = [] output = []
for byte in input_bytes: for byte in input_bytes:
if byte < ord(b'\x80'): if byte < ord(b'\x80'):
@@ -103,7 +75,6 @@ def parse_ab_header(data):
def parse_backup_file(data, password=None): def parse_backup_file(data, password=None):
""" """
Parse an ab file, returns a tar file Parse an ab file, returns a tar file
Inspired by https://github.com/FloatingOctothorpe/dump_android_backup
""" """
if not data.startswith(b"ANDROID BACKUP"): if not data.startswith(b"ANDROID BACKUP"):
raise AndroidBackupParsingError("Invalid file header") raise AndroidBackupParsingError("Invalid file header")
@@ -124,13 +95,25 @@ def parse_backup_file(data, password=None):
user_iv = bytes.fromhex(user_iv.decode("utf-8")) user_iv = bytes.fromhex(user_iv.decode("utf-8"))
master_key_blob = bytes.fromhex(master_key_blob.decode("utf-8")) master_key_blob = bytes.fromhex(master_key_blob.decode("utf-8"))
key = hashlib.pbkdf2_hmac('sha1', kdf = PBKDF2HMAC(
password.encode('utf-8'), algorithm=hashes.SHA1(),
user_salt, length=32,
pbkdf2_rounds, salt=user_salt,
PBKDF2_KEY_SIZE) iterations=pbkdf2_rounds)
key = kdf.derive(password.encode("utf-8"))
cipher = Cipher(algorithms.AES(key), modes.CBC(user_iv))
decryptor = cipher.decryptor()
try: try:
[master_iv, master_key, master_key_checksum] = decrypt_master_key_blob(key, user_iv, master_key_blob) plain_text = decryptor.update(master_key_blob) + decryptor.finalize()
blob = io.BytesIO(plain_text)
master_iv_length = ord(blob.read(1))
master_iv = blob.read(master_iv_length)
master_key_length = ord(blob.read(1))
master_key = blob.read(master_key_length)
master_key_checksum_length = ord(blob.read(1))
master_key_checksum = blob.read(master_key_checksum_length)
except TypeError: except TypeError:
raise InvalidBackupPassword() raise InvalidBackupPassword()
@@ -139,17 +122,21 @@ def parse_backup_file(data, password=None):
else: else:
hmac_mk = master_key hmac_mk = master_key
calculated_checksum = hashlib.pbkdf2_hmac('sha1', kdf = PBKDF2HMAC(
hmac_mk, algorithm=hashes.SHA1(),
checksum_salt, length=32,
pbkdf2_rounds, salt=checksum_salt,
PBKDF2_KEY_SIZE) iterations=pbkdf2_rounds)
calculated_checksum = kdf.derive(hmac_mk)
if master_key_checksum != calculated_checksum: if master_key_checksum != calculated_checksum:
raise InvalidBackupPassword() raise InvalidBackupPassword()
decrypter = pyaes.Decrypter(pyaes.AESModeOfOperationCBC(master_key, master_iv)) cipher = Cipher(algorithms.AES(master_key), modes.CBC(master_iv))
tar_data = decrypter.feed(encrypted_data) decryptor = cipher.decryptor()
tar_data = decryptor.update(encrypted_data) + decryptor.finalize()
unpadder = padding.PKCS7(128).unpadder()
tar_data = data = unpadder.update(tar_data)
if is_compressed == 1: if is_compressed == 1:
try: try:
+1 -1
View File
@@ -29,7 +29,7 @@ requires = (
# Android dependencies: # Android dependencies:
"adb-shell>=0.4.2", "adb-shell>=0.4.2",
"libusb1>=2.0.1", "libusb1>=2.0.1",
"pyaes>=1.6.1" "cryptography>=36.0.1"
) )