acquire 3.17.dev1__tar.gz → 3.17.dev2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {acquire-3.17.dev1/acquire.egg-info → acquire-3.17.dev2}/PKG-INFO +1 -1
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/crypt.py +1 -1
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/outputs/zip.py +1 -1
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/tools/decrypter.py +38 -24
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/version.py +2 -2
- {acquire-3.17.dev1 → acquire-3.17.dev2/acquire.egg-info}/PKG-INFO +1 -1
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire.egg-info/SOURCES.txt +2 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/tests/conftest.py +6 -0
- acquire-3.17.dev2/tests/data/private_key.pem +28 -0
- acquire-3.17.dev2/tests/data/public_key.pem +9 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/tests/test_outputs_tar.py +18 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/tests/test_outputs_zip.py +18 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/COPYRIGHT +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/LICENSE +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/MANIFEST.in +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/README.md +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/__init__.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/acquire.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/collector.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/dynamic/__init__.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/dynamic/windows/__init__.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/dynamic/windows/collect.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/dynamic/windows/exceptions.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/dynamic/windows/handles.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/dynamic/windows/named_objects.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/dynamic/windows/ntdll.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/dynamic/windows/types.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/esxi.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/gui/__init__.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/gui/base.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/gui/win32.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/hashes.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/log.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/outputs/__init__.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/outputs/base.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/outputs/dir.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/outputs/tar.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/tools/__init__.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/uploaders/__init__.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/uploaders/minio.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/uploaders/plugin.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/uploaders/plugin_registry.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/utils.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire/volatilestream.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire.egg-info/dependency_links.txt +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire.egg-info/entry_points.txt +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire.egg-info/requires.txt +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/acquire.egg-info/top_level.txt +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/pyproject.toml +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/setup.cfg +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/tests/__init__.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/tests/docs/Makefile +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/tests/docs/conf.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/tests/docs/index.rst +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/tests/test_acquire_command.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/tests/test_acquire_modules.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/tests/test_collector.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/tests/test_decryptor_funcs.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/tests/test_esxi_memory.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/tests/test_file_sorting.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/tests/test_gui.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/tests/test_minio_uploader.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/tests/test_misc_users.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/tests/test_outputs_dir.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/tests/test_plugin.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/tests/test_utils.py +0 -0
- {acquire-3.17.dev1 → acquire-3.17.dev2}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: acquire
|
|
3
|
-
Version: 3.17.
|
|
3
|
+
Version: 3.17.dev2
|
|
4
4
|
Summary: A tool to quickly gather forensic artifacts from disk images or a live system into a lightweight container
|
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
|
6
6
|
License: Affero General Public License v3
|
|
@@ -113,7 +113,7 @@ class EncryptedStream(io.RawIOBase):
|
|
|
113
113
|
return self.fh.tell()
|
|
114
114
|
|
|
115
115
|
def seek(self, pos, whence=io.SEEK_CUR):
|
|
116
|
-
raise
|
|
116
|
+
raise io.UnsupportedOperation("seeking is not allowed")
|
|
117
117
|
|
|
118
118
|
def close(self):
|
|
119
119
|
self.finalize()
|
|
@@ -48,7 +48,7 @@ class ZipOutput(Output):
|
|
|
48
48
|
|
|
49
49
|
if encrypt:
|
|
50
50
|
self._fh = EncryptedStream(self.path.open("wb"), public_key)
|
|
51
|
-
self.archive = zipfile.ZipFile(
|
|
51
|
+
self.archive = zipfile.ZipFile(self._fh, mode="w", compression=self.compression, allowZip64=True)
|
|
52
52
|
else:
|
|
53
53
|
self.archive = zipfile.ZipFile(self.path, mode="w", compression=self.compression, allowZip64=True)
|
|
54
54
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import argparse
|
|
2
4
|
import base64
|
|
3
5
|
import contextlib
|
|
@@ -14,6 +16,9 @@ from concurrent.futures import ProcessPoolExecutor
|
|
|
14
16
|
from datetime import datetime, timezone
|
|
15
17
|
from pathlib import Path
|
|
16
18
|
from queue import Empty as QueueEmptyError
|
|
19
|
+
from queue import Queue
|
|
20
|
+
from threading import Event
|
|
21
|
+
from typing import BinaryIO, Iterator
|
|
17
22
|
from urllib import request
|
|
18
23
|
from urllib.error import HTTPError
|
|
19
24
|
from urllib.parse import urljoin
|
|
@@ -73,7 +78,7 @@ class VerifyError(Exception):
|
|
|
73
78
|
|
|
74
79
|
|
|
75
80
|
class EncryptedFile(AlignedStream):
|
|
76
|
-
def __init__(self, fh, key_file=None, key_server=None):
|
|
81
|
+
def __init__(self, fh: BinaryIO, key_file: Path | None = None, key_server: str | None = None) -> None:
|
|
77
82
|
self.fh = fh
|
|
78
83
|
self.key_file = key_file
|
|
79
84
|
self.key_server = key_server
|
|
@@ -116,10 +121,10 @@ class EncryptedFile(AlignedStream):
|
|
|
116
121
|
def seekable(self):
|
|
117
122
|
return False
|
|
118
123
|
|
|
119
|
-
def seek(self, pos, whence=io.SEEK_CUR):
|
|
124
|
+
def seek(self, pos: int, whence: int = io.SEEK_CUR) -> int:
|
|
120
125
|
raise io.UnsupportedOperation("seeking is not allowed")
|
|
121
126
|
|
|
122
|
-
def _read(self, offset, length):
|
|
127
|
+
def _read(self, offset: int, length: int) -> bytes:
|
|
123
128
|
if not self.size:
|
|
124
129
|
result = []
|
|
125
130
|
|
|
@@ -162,25 +167,25 @@ class EncryptedFile(AlignedStream):
|
|
|
162
167
|
read_size = max(0, min(length, self.size - offset))
|
|
163
168
|
return self.cipher.decrypt(self.fh.read(read_size))
|
|
164
169
|
|
|
165
|
-
def chunks(self, chunk_size=CHUNK_SIZE):
|
|
170
|
+
def chunks(self, chunk_size: int = CHUNK_SIZE) -> Iterator[bytes]:
|
|
166
171
|
while True:
|
|
167
172
|
chunk = self.read(chunk_size)
|
|
168
173
|
if not chunk:
|
|
169
174
|
break
|
|
170
175
|
yield chunk
|
|
171
176
|
|
|
172
|
-
def verify(self):
|
|
177
|
+
def verify(self) -> None:
|
|
173
178
|
try:
|
|
174
179
|
self.cipher.verify(self.digest)
|
|
175
180
|
except ValueError:
|
|
176
181
|
raise VerifyError("Digest check failed")
|
|
177
182
|
|
|
178
183
|
@property
|
|
179
|
-
def file_header(self):
|
|
184
|
+
def file_header(self) -> c_acquire.file:
|
|
180
185
|
return self._file_header
|
|
181
186
|
|
|
182
187
|
@file_header.setter
|
|
183
|
-
def file_header(self, file_header):
|
|
188
|
+
def file_header(self, file_header: c_acquire.file) -> None:
|
|
184
189
|
if file_header.magic != FILE_MAGIC:
|
|
185
190
|
raise ValueError(f"Invalid file magic: {file_header.magic}")
|
|
186
191
|
|
|
@@ -193,31 +198,31 @@ class EncryptedFile(AlignedStream):
|
|
|
193
198
|
self._file_header = file_header
|
|
194
199
|
|
|
195
200
|
@property
|
|
196
|
-
def header(self):
|
|
201
|
+
def header(self) -> c_acquire.header:
|
|
197
202
|
return self._header
|
|
198
203
|
|
|
199
204
|
@header.setter
|
|
200
|
-
def header(self, header):
|
|
205
|
+
def header(self, header: c_acquire.header) -> None:
|
|
201
206
|
if header.magic != HEADER_MAGIC:
|
|
202
207
|
raise ValueError(f"Invalid header magic: {header.magic}")
|
|
203
208
|
self._header = header
|
|
204
209
|
|
|
205
210
|
@property
|
|
206
|
-
def footer(self):
|
|
211
|
+
def footer(self) -> c_acquire.footer:
|
|
207
212
|
return self._footer
|
|
208
213
|
|
|
209
214
|
@footer.setter
|
|
210
|
-
def footer(self, footer):
|
|
215
|
+
def footer(self, footer: c_acquire.footer) -> None:
|
|
211
216
|
if footer.magic != FOOTER_MAGIC:
|
|
212
217
|
raise ValueError(f"Invalid footer magic: {footer}")
|
|
213
218
|
self._footer = footer
|
|
214
219
|
|
|
215
220
|
@property
|
|
216
|
-
def timestamp(self):
|
|
221
|
+
def timestamp(self) -> datetime:
|
|
217
222
|
return datetime.fromtimestamp(self.file_header.timestamp, timezone.utc)
|
|
218
223
|
|
|
219
224
|
|
|
220
|
-
def decrypt_header(header, fingerprint, key_file=None, key_server=None):
|
|
225
|
+
def decrypt_header(header, fingerprint: bytes, key_file: Path | None = None, key_server: str | None = None) -> bytes:
|
|
221
226
|
if not key_file and not key_server:
|
|
222
227
|
raise ValueError("Need either key file or key server")
|
|
223
228
|
|
|
@@ -264,7 +269,16 @@ def check_existing(in_path: Path, out_path: Path, status_queue: multiprocessing.
|
|
|
264
269
|
return False
|
|
265
270
|
|
|
266
271
|
|
|
267
|
-
def worker(
|
|
272
|
+
def worker(
|
|
273
|
+
task_id: int,
|
|
274
|
+
stop_event: Event,
|
|
275
|
+
status_queue: Queue,
|
|
276
|
+
in_path: Path,
|
|
277
|
+
out_path: Path,
|
|
278
|
+
key_file: Path | None = None,
|
|
279
|
+
key_server: str | None = None,
|
|
280
|
+
clobber: bool = False,
|
|
281
|
+
) -> None:
|
|
268
282
|
success = False
|
|
269
283
|
message = "An unknown error occurred"
|
|
270
284
|
|
|
@@ -325,23 +339,23 @@ def worker(task_id, stop_event, status_queue, in_path, out_path, key_file=None,
|
|
|
325
339
|
_exit(status_queue, task_id, str(in_path), message, success)
|
|
326
340
|
|
|
327
341
|
|
|
328
|
-
def _start(queue, task_id):
|
|
342
|
+
def _start(queue: Queue, task_id: int) -> None:
|
|
329
343
|
queue.put_nowait((STATUS_START, task_id))
|
|
330
344
|
|
|
331
345
|
|
|
332
|
-
def _update(queue, task_id, *args, **kwargs):
|
|
346
|
+
def _update(queue: Queue, task_id: int, *args, **kwargs) -> None:
|
|
333
347
|
queue.put_nowait((STATUS_UPDATE, (task_id, args, kwargs)))
|
|
334
348
|
|
|
335
349
|
|
|
336
|
-
def _info(queue, msg):
|
|
350
|
+
def _info(queue: Queue, msg: str) -> None:
|
|
337
351
|
queue.put_nowait((STATUS_INFO, msg))
|
|
338
352
|
|
|
339
353
|
|
|
340
|
-
def _exit(queue: multiprocessing.Queue, task_id: int, in_path: str, message: str, success: bool):
|
|
354
|
+
def _exit(queue: multiprocessing.Queue, task_id: int, in_path: str, message: str, success: bool) -> None:
|
|
341
355
|
queue.put_nowait((STATUS_EXIT, (task_id, in_path, message, success)))
|
|
342
356
|
|
|
343
357
|
|
|
344
|
-
def setup_logging(logger, verbosity):
|
|
358
|
+
def setup_logging(logger: logging.Logger, verbosity: int) -> None:
|
|
345
359
|
if verbosity == 1:
|
|
346
360
|
level = logging.ERROR
|
|
347
361
|
elif verbosity == 2:
|
|
@@ -360,7 +374,7 @@ def setup_logging(logger, verbosity):
|
|
|
360
374
|
logger.setLevel(level)
|
|
361
375
|
|
|
362
376
|
|
|
363
|
-
def main():
|
|
377
|
+
def main() -> None:
|
|
364
378
|
parser = argparse.ArgumentParser()
|
|
365
379
|
parser.add_argument("files", nargs="+", type=Path, help="paths to encrypted files")
|
|
366
380
|
parser.add_argument("-o", "--output", type=Path, help="optional path to output file")
|
|
@@ -476,12 +490,12 @@ def main():
|
|
|
476
490
|
# If no successful results, return 1
|
|
477
491
|
if not any(successes):
|
|
478
492
|
exit_code = 1
|
|
479
|
-
# Else, if some results were successful return 2
|
|
493
|
+
# Else, if some results but not all were successful return 2
|
|
480
494
|
elif not all(successes):
|
|
481
495
|
exit_code = 2
|
|
482
|
-
# Else, if all were successful but there were still tasks to handle, return
|
|
483
|
-
elif
|
|
484
|
-
exit_code =
|
|
496
|
+
# Else, if all were successful but there were still tasks to handle, return 3
|
|
497
|
+
elif tasks:
|
|
498
|
+
exit_code = 3
|
|
485
499
|
exit(exit_code)
|
|
486
500
|
|
|
487
501
|
|
|
@@ -12,5 +12,5 @@ __version__: str
|
|
|
12
12
|
__version_tuple__: VERSION_TUPLE
|
|
13
13
|
version_tuple: VERSION_TUPLE
|
|
14
14
|
|
|
15
|
-
__version__ = version = '3.17.
|
|
16
|
-
__version_tuple__ = version_tuple = (3, 17, '
|
|
15
|
+
__version__ = version = '3.17.dev2'
|
|
16
|
+
__version_tuple__ = version_tuple = (3, 17, 'dev2')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: acquire
|
|
3
|
-
Version: 3.17.
|
|
3
|
+
Version: 3.17.dev2
|
|
4
4
|
Summary: A tool to quickly gather forensic artifacts from disk images or a live system into a lightweight container
|
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
|
6
6
|
License: Affero General Public License v3
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
-----BEGIN PRIVATE KEY-----
|
|
2
|
+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDDd7qXEe7cR4b0
|
|
3
|
+
DFmszQm5MNFPkf/uJd5i6Y4ya0prts9s4mDdS90oDUt7bvLl42i/eB+S1fw9UpmK
|
|
4
|
+
r8OBV51VoFPswLVSwHho7LjbGvBSgKCW31skalgOmCAiCl6BqqjI7eIqxJx3V2+G
|
|
5
|
+
tW19v0EvbPJNs4gWlLIzn0WZJ65HWNZxToD9NcM2uZeIFxziUFvQYv1Nzkih/HWA
|
|
6
|
+
8Fw8Sdrq3JN3RG9jikJSH/MisU25IP5ehP5g66akPCufBCEc6Y2OE4wAQ7sbBMpf
|
|
7
|
+
/6PLZHGCVMnE8TXGBUl7m9UVwdyhvfIFBNhGilpqtSQhlqymrko7R7uZ6x5gQIz/
|
|
8
|
+
YzUW/Ho9AgMBAAECggEABqDTvKBeDNgxalXU4KLfS96s6lmAEo+e1+nQPu4byu/w
|
|
9
|
+
XrfaeFvvNuwkfXNeBzpL6K+RGoXpFMdCmk0AKy2mZytATUyc7skaDCzNeUM+QlNG
|
|
10
|
+
9CFvfMT3vB71JVJcBrebxkcoHofQ6ncWOrzXkVEKoSoSRAeXe3SKtRdsi8H9teuX
|
|
11
|
+
uXzs8fyk+Xrp9qBE3y541HcZCh8oLypQgTFoV3cZJgcsrnRaLQUooU2n1lvl+EZx
|
|
12
|
+
xoZnL1LBMmX/teVICE20NJOlJN25Z+Q26tNM6ADMFmmN0hDaHUEv/tlV+MSB01Mq
|
|
13
|
+
nBvC1/q6pHODHW1AsLfxwT2f+VeEz4Hpbxpu1fCkXQKBgQDyhzJgVkkKctCcMlcB
|
|
14
|
+
4fck+mxvQlRuWHs94RdMd28bZay5BQhd/rqicDzqIQ2NIhaPDDbUR5ElqLXQEDZD
|
|
15
|
+
6s+FeHbT+iXTOtWA6qQJL0/alcEL22Nxxv098nFrjUBeinaw+PbOZq5DOT4NVL/Q
|
|
16
|
+
i0lGzQs+6jEH9aYc24Tu9Gi5EwKBgQDOU1KQhAea1rztLkAbEI0giKM/6vf0g6im
|
|
17
|
+
1/UlUy8TjyIaE4Cwgsy/H6LuvY1KOiV/6boO3jBl5OyZZBFqIEbmEd3MH75XC0XP
|
|
18
|
+
bLtI00EVHU6jCf/dLE5wNhxhEuAw0KB12ecR7fZv1Wg9ltj/IR6dFBJ+Q7uuxufk
|
|
19
|
+
yq9R9QU5bwKBgB/Qdl5G01wIha8Ht3wqvTXfl9vccqDrAHe0kE7al/ubEdZPf7J8
|
|
20
|
+
2NS4LnV0EogCAb2QF50vKi4rfHYnukachc53Z/cUqGOWIy2/GfeOekYtQN6iT+A7
|
|
21
|
+
/zpiFFjMdbYxKbK7ZfzbYV62IpqzFFpx+xHLkf8Vz4rAwaKldUG3VAl7AoGASlef
|
|
22
|
+
gk7wZoxFWri1hIr8LuLM37UMTuA5npRl0mMcrVF/miG41uDqYVtG2/sUs9ArvuE6
|
|
23
|
+
lyzcB3rq/YIe/DxRD4kUf/5YGQkIyGqHOQBVjQQYV4q81LaoNKpqo1enzC8AAjbX
|
|
24
|
+
mZBCoZ0liDuYSKVoYHThDPne4GTvHXMipMdCcKUCgYEA5h0686KZxIHgxPx7A4Br
|
|
25
|
+
zHKigjFGda4C9xPWBdpjvLcbFgyc+ULzP61q+h2LnE+HEuFzVqMj56dlIJl73ooI
|
|
26
|
+
FyjJR9ceNDyZ37XzBF3IM5AaxdvPfB/OIjMOGS5yV+1hijcGdy+RgBGVADv4lgUd
|
|
27
|
+
soFdGXF8UUBPdYczZR2R7jQ=
|
|
28
|
+
-----END PRIVATE KEY-----
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
-----BEGIN PUBLIC KEY-----
|
|
2
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw3e6lxHu3EeG9AxZrM0J
|
|
3
|
+
uTDRT5H/7iXeYumOMmtKa7bPbOJg3UvdKA1Le27y5eNov3gfktX8PVKZiq/DgVed
|
|
4
|
+
VaBT7MC1UsB4aOy42xrwUoCglt9bJGpYDpggIgpegaqoyO3iKsScd1dvhrVtfb9B
|
|
5
|
+
L2zyTbOIFpSyM59FmSeuR1jWcU6A/TXDNrmXiBcc4lBb0GL9Tc5Iofx1gPBcPEna
|
|
6
|
+
6tyTd0RvY4pCUh/zIrFNuSD+XoT+YOumpDwrnwQhHOmNjhOMAEO7GwTKX/+jy2Rx
|
|
7
|
+
glTJxPE1xgVJe5vVFcHcob3yBQTYRopaarUkIZaspq5KO0e7meseYECM/2M1Fvx6
|
|
8
|
+
PQIDAQAB
|
|
9
|
+
-----END PUBLIC KEY-----
|
|
@@ -5,6 +5,7 @@ import pytest
|
|
|
5
5
|
from dissect.target.filesystem import VirtualFilesystem
|
|
6
6
|
|
|
7
7
|
from acquire.outputs import TarOutput
|
|
8
|
+
from acquire.tools.decrypter import EncryptedFile
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
@pytest.fixture(params=[(True, "gzip"), (True, "bzip2"), (True, "xz"), (False, None)])
|
|
@@ -41,3 +42,20 @@ def test_tar_output_write_entry(mock_fs: VirtualFilesystem, tar_output: TarOutpu
|
|
|
41
42
|
assert file.issym()
|
|
42
43
|
elif entry.is_file():
|
|
43
44
|
assert file.isfile()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_tar_output_encrypt(mock_fs: VirtualFilesystem, public_key: bytes, tmp_path: Path) -> None:
|
|
48
|
+
entry_name = "/foo/bar/some-file"
|
|
49
|
+
entry = mock_fs.get(entry_name)
|
|
50
|
+
tar_output = TarOutput(tmp_path, compress=True, compression_method="gzip", encrypt=True, public_key=public_key)
|
|
51
|
+
tar_output.write_entry(entry_name, entry)
|
|
52
|
+
tar_output.close()
|
|
53
|
+
|
|
54
|
+
encrypted_stream = EncryptedFile(tar_output.path.open("rb"), Path("tests/data/private_key.pem"))
|
|
55
|
+
decrypted_path = tmp_path / "decrypted.tar"
|
|
56
|
+
# Direct streaming is not an option because tarfile needs seek when reading from encrypted files directly
|
|
57
|
+
with open(decrypted_path, "wb") as f:
|
|
58
|
+
f.write(encrypted_stream.read())
|
|
59
|
+
|
|
60
|
+
tar_file = tarfile.open(name=decrypted_path, mode="r")
|
|
61
|
+
assert entry.open().read() == tar_file.extractfile(entry_name).read()
|
|
@@ -6,6 +6,7 @@ import pytest
|
|
|
6
6
|
from dissect.target.filesystem import VirtualFilesystem
|
|
7
7
|
|
|
8
8
|
from acquire.outputs import ZipOutput
|
|
9
|
+
from acquire.tools.decrypter import EncryptedFile
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
@pytest.fixture(params=[(True, "deflate"), (True, "bzip2"), (True, "lzma"), (False, None)])
|
|
@@ -45,3 +46,20 @@ def test_zip_output_write_entry(mock_fs: VirtualFilesystem, zip_output: ZipOutpu
|
|
|
45
46
|
assert stat.S_ISLNK(file_type)
|
|
46
47
|
elif entry.is_file():
|
|
47
48
|
assert stat.S_ISREG(file_type)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_zip_output_encrypt(mock_fs: VirtualFilesystem, public_key: bytes, tmp_path: Path) -> None:
|
|
52
|
+
entry_name = "/foo/bar/some-file"
|
|
53
|
+
entry = mock_fs.get(entry_name)
|
|
54
|
+
zip_output = ZipOutput(tmp_path, compress=True, compression_method="bzip2", encrypt=True, public_key=public_key)
|
|
55
|
+
zip_output.write_entry(entry_name, entry)
|
|
56
|
+
zip_output.close()
|
|
57
|
+
|
|
58
|
+
encrypted_stream = EncryptedFile(zip_output.path.open("rb"), Path("tests/data/private_key.pem"))
|
|
59
|
+
decrypted_path = tmp_path / "decrypted.zip"
|
|
60
|
+
# Direct streaming is not an option because zipfile needs seek when reading from encrypted files directly
|
|
61
|
+
with open(decrypted_path, "wb") as f:
|
|
62
|
+
f.write(encrypted_stream.read())
|
|
63
|
+
|
|
64
|
+
zip_file = zipfile.ZipFile(decrypted_path, mode="r")
|
|
65
|
+
assert entry.open().read() == zip_file.open(entry_name).read()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|