def extract_v1(self): for l in self.layout: if l.filename is not None: self.fd.seek(l.offset) out_filename = unique_file_name(l.filename.decode()) with open(out_filename, 'w+b') as out_fd: n, cz = 0, self.chunksize while n < l.size: n += cz if n > l.size: cz -= n - l.size out_fd.write(str2bytes(self.fd.read(cz))) if self.password_extractor is not None: if l.type == CSP_LAYOUT_PASSWORD: try: self.password = check_output( [self.password_extractor, l.filename]) except CalledProcessError as e: warning(str(e)) elif l.type == CSP_LAYOUT_APPL: if self.password is None: warning('Password wasn\'t extracted') continue app_out_filename = splitext(out_filename)[0] self.decrypt_v1(out_filename, l.size, app_out_filename) os.unlink(out_filename) self.untar(app_out_filename, splitext(app_out_filename)[0])
def extract(self): if not self.valid: return False for sec in self.sections: if sec.type in [ SECTION_TYPE_ARCHIVE_TBZ2, SECTION_TYPE_ENCRYPTED_ARCHIVE_TBZ2 ]: self.fd.seek(sec.data_offset) if sec.type == SECTION_TYPE_ENCRYPTED_ARCHIVE_TBZ2: decryptor = AES.new(self.key, AES.MODE_CBC, sec.vector) out_filename = unique_file_name('{}_off{:X}.{}.tbz2'.format( abspath(self.fd.path), sec.offset, sec.name)) with open(out_filename, 'w+b') as out_fd: n, cz = 0, self.chunksize while n < sec.data_size: n += cz if n > sec.data_size: cz -= n - sec.data_size chunk = str2bytes(self.fd.read(cz)) if sec.type == SECTION_TYPE_ENCRYPTED_ARCHIVE_TBZ2: chunk = decryptor.decrypt(chunk) out_fd.write(chunk) self.untar(out_filename, splitext(out_filename)[0]) return True
def __init__(self, fd): super(Section, self).__init__() self.fd = fd self.offset = fd.tell() self.type, self.name, self.size = unpack( SEC_HEADER_FORMAT, str2bytes(fd.read(SEC_HEADER_SIZE))) self.name = self.name.decode().strip('\x00') self.data_offset = self.offset + SEC_HEADER_SIZE self.is_encryped = self.type == SECTION_TYPE_ENCRYPTED_ARCHIVE_TBZ2 self.data_size = self.real_size = self.size if self.is_encryped: self.real_size = unpack('<Q', str2bytes(fd.read(calcsize('Q'))))[0] self.vector = str2bytes(fd.read(16)) self.hash = str2bytes(fd.read(56)) self.data_offset = fd.tell() self.data_size -= self.data_offset - self.offset - SEC_HEADER_SIZE fd.seek(self.offset + SEC_HEADER_SIZE + self.size)
def __init__(self, fd, mod): super(CSPFile, self).__init__() self.fd = fd self.csp_header = CSPFileHeader._make( unpack(CSP_HEADER_FORMAT, str2bytes(fd.read(CSP_HEADER_SIZE)))) assert self.csp_header.magic == CSP_SIGNATURE_GUID self.key_type = self.csp_header.flag & 0x03 self.key_version = ((self.csp_header.flag >> 2) & 0x3F) self.key_version_c = bytes(str(self.key_version), 'ascii').hex() self.version = ((self.csp_header.flag >> 8) & 0xFF) self.verbose = mod.config.verbose self.verbose_offset = mod.HEADER_FORMAT.strip('\n') % ('', '', '') getattr(self, 'load_v{:d}'.format(self.version), self.unsupported_csp)()
def decrypt_v1(self, in_filename, in_filesize, out_filename, key_length=32): with open(in_filename, 'rb') as in_file, open(out_filename, 'wb') as out_file: salt = in_file.read(AES.block_size)[len('Salted__'):] key, iv = self.derive_key_and_iv(self.password, salt, key_length, AES.block_size) cipher = AES.new(key, AES.MODE_CBC, iv) n, cz = 0, self.chunksize while n < in_filesize: n += cz if n > in_filesize: cz -= n - in_filesize chunk = str2bytes(in_file.read(cz)) chunk = cipher.decrypt(chunk) out_file.write(chunk)
def __init__(self, fd): super(PKGFile, self).__init__() self.fd = fd magic, self.version, self.num_sections, self.type, _ = unpack( PKG_HEADER_FORMAT, str2bytes(fd.read(PKG_HEADER_SIZE))) assert magic == MAGIC_NUMBER self.sections = list(Section(fd) for _ in range(self.num_sections)) if self.type in [ ENCRYPTED_CONTENT_CHECKSUM_PKG_TYPE, ENCRYPTED_CONTENT_SIGNED_CHECKSUM_PKG_TYPE ]: for sec in self.sections: if sec.type == SECTION_TYPE_KEY: decryptor = AES.new(ON_BOX_ENC_KEY, AES.MODE_CBC, '\x00' * 16) self.key = decryptor.decrypt(sec.value) break self.valid = self.key is not None
def load_v1(self): v1_header = CSPv1Header._make( unpack(CSPv1_HEADER_FORMAT, str2bytes(self.fd.read(CSPv1_HEADER_SIZE)))) self.size = CSP_HEADER_SIZE + CSPv1_HEADER_SIZE + v1_header.password_len + \ v1_header.appl_name_len + v1_header.metadata_len + v1_header.sign_len + \ v1_header.appl_len + v1_header.sign_len self.layout = [ Layout(self.fd, CSP_LAYOUT_PASSWORD, v1_header.password_len), Layout(self.fd, CSP_LAYOUT_APPL_NAME, v1_header.appl_name_len), Layout(self.fd, CSP_LAYOUT_METADATA, v1_header.metadata_len), Layout(self.fd, CSP_LAYOUT_METADATA_SIGN, v1_header.sign_len), Layout(self.fd, CSP_LAYOUT_APPL, v1_header.appl_len), Layout(self.fd, CSP_LAYOUT_SIGNATURE_ENVELOPE, v1_header.sign_len) ] filename = v1_header.filename.strip(b'\x00') metadata_filename, appl_filename = next( filter(lambda l: l.type == CSP_LAYOUT_APPL_NAME, self.layout)).value.split() layout_filenames = { CSP_LAYOUT_PASSWORD: filename + b'.pwd', CSP_LAYOUT_METADATA: metadata_filename, CSP_LAYOUT_METADATA_SIGN: metadata_filename + b'.sig', CSP_LAYOUT_APPL: appl_filename + b'.enc', CSP_LAYOUT_SIGNATURE_ENVELOPE: filename + b'.sig' } for l in self.layout: l.filename = layout_filenames.get(l.type, None) self.password_extractor = join(dirname(__file__), ZL_CSP_v1_PWD_EXTRACTOR) if not isfile(self.password_extractor): warning('Invalid password extractor ({})'.format( self.password_extractor)) self.password_extractor = None
def value(self): self.fd.seek(self.offset) return str2bytes(self.fd.read(self.size))
def value(self): self.fd.seek(self.data_offset) return str2bytes( self.fd.read(self.data_size if self.is_encryped else self.size))