Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change linter to Ruff #4

Merged
merged 1 commit into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions dissect/fve/bde/bde.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import struct
from bisect import bisect_right
from operator import itemgetter
from typing import BinaryIO, Iterator
from typing import TYPE_CHECKING, BinaryIO
from uuid import UUID

from dissect.util.stream import AlignedStream
Expand All @@ -35,6 +35,10 @@
from dissect.fve.crypto import create_cipher
from dissect.fve.exceptions import InvalidHeaderError

if TYPE_CHECKING:
from collections.abc import Iterator
from uuid import UUID

Check warning on line 40 in dissect/fve/bde/bde.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/bde.py#L39-L40

Added lines #L39 - L40 were not covered by tests

Run = tuple[int, int, int]

log = logging.getLogger(__name__)
Expand All @@ -52,7 +56,7 @@
for offset in self.boot_sector.information_offsets:
try:
self._available_information.append(Information(self.fh, offset))
except InvalidHeaderError as e:
except InvalidHeaderError as e: # noqa: PERF203
log.warning("Failed to parse BDE information at offset 0x%x", offset, exc_info=e)

self._valid_information = [info for info in self._available_information if info.is_valid()]
Expand All @@ -65,13 +69,14 @@
for offset in self.boot_sector.eow_offsets:
try:
self._available_eow_information.append(EowInformation(self.fh, offset))
except InvalidHeaderError as e:
except InvalidHeaderError as e: # noqa: PERF203

Check warning on line 72 in dissect/fve/bde/bde.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/bde.py#L72

Added line #L72 was not covered by tests
log.warning("Failed to parse BDE EOW information at offset 0x%x", offset, exc_info=e)

self._valid_eow_information = [info for info in self._available_eow_information if info.is_valid()]
if self._available_eow_information and not self._valid_eow_information:
raise InvalidHeaderError("No valid EOW information found")
elif self._valid_eow_information:

if self._valid_eow_information:
self.eow_information = self._valid_eow_information[0]

self._fvek = None
Expand All @@ -82,8 +87,7 @@
role=FVE_DATUM_ROLE.VOLUME_MASTER_KEY_INFO,
type_=FVE_DATUM_TYPE.VOLUME_MASTER_KEY_INFO,
)
identifiers = [d.identifier for d in datums]
return identifiers
return [d.identifier for d in datums]

Check warning on line 90 in dissect/fve/bde/bde.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/bde.py#L90

Added line #L90 was not covered by tests

@property
def sector_size(self) -> int:
Expand Down Expand Up @@ -143,7 +147,7 @@

fvek = fvek.unbox(key)
if not isinstance(fvek, KeyDatum):
raise ValueError("Invalid unboxed FVEK")
raise TypeError("Invalid unboxed FVEK")

Check warning on line 150 in dissect/fve/bde/bde.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/bde.py#L150

Added line #L150 was not covered by tests

self._fvek = fvek

Expand Down Expand Up @@ -229,8 +233,12 @@
information_size = ~(self.sector_size - 1) & (self.sector_size + 0xFFFF)

# All information offsets are reserved regions
for offset in self.information.information_offset:
regions.append((offset // self.sector_size, information_size // self.sector_size))
regions.extend(
[
(offset // self.sector_size, information_size // self.sector_size)
for offset in self.information.information_offset
]
)

if self.version >= 2:
num_sectors = self.information.virtualized_sectors or 1
Expand Down Expand Up @@ -514,8 +522,9 @@
try:
fh.seek(0)
BootSector(fh)
return True
except ValueError:
return False
else:
return True
finally:
fh.seek(stored_position)
12 changes: 5 additions & 7 deletions dissect/fve/bde/eow.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from binascii import crc32
from functools import cached_property
from io import BytesIO
from typing import BinaryIO, Iterator
from typing import TYPE_CHECKING, BinaryIO

from dissect.fve.bde.c_bde import (
EOW_BM_SIGNATURE,
Expand All @@ -16,6 +16,9 @@
)
from dissect.fve.exceptions import InvalidHeaderError

if TYPE_CHECKING:
from collections.abc import Iterator

Check warning on line 20 in dissect/fve/bde/eow.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/eow.py#L20

Added line #L20 was not covered by tests


class EowInformation:
"""Bitlocker EOW Information."""
Expand Down Expand Up @@ -51,12 +54,7 @@

@cached_property
def bitmaps(self) -> list[EowBitmap]:
result = []

for offset in self.header.BitmapOffsets:
result.append(EowBitmap(self.fh, offset))

return result
return [EowBitmap(self.fh, offset) for offset in self.header.BitmapOffsets]


class EowBitmap:
Expand Down
46 changes: 34 additions & 12 deletions dissect/fve/bde/information.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from __future__ import annotations

import datetime
import hashlib
from binascii import crc32
from functools import cached_property
from io import BytesIO
from typing import BinaryIO, Iterator
from typing import TYPE_CHECKING, BinaryIO
from uuid import UUID

from Crypto.Cipher import AES
Expand All @@ -23,6 +22,10 @@
)
from dissect.fve.exceptions import InvalidHeaderError

if TYPE_CHECKING:
import datetime
from collections.abc import Iterator

Check warning on line 27 in dissect/fve/bde/information.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/information.py#L26-L27

Added lines #L26 - L27 were not covered by tests


class Information:
"""Bitlocker Information.
Expand Down Expand Up @@ -185,21 +188,25 @@
"""Find the description datum."""
for datum in self.find_datum(FVE_DATUM_ROLE.DESCRIPTION, FVE_DATUM_TYPE.UNICODE):
return datum.text
return None

Check warning on line 191 in dissect/fve/bde/information.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/information.py#L191

Added line #L191 was not covered by tests

def find_virtualization_info(self) -> VirtualizationInfoDatum | None:
"""Find the virtualization info datum."""
for datum in self.find_datum(FVE_DATUM_ROLE.VIRTUALIZATION_INFO, FVE_DATUM_TYPE.VIRTUALIZATION_INFO):
return datum
return None

Check warning on line 197 in dissect/fve/bde/information.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/information.py#L197

Added line #L197 was not covered by tests

def find_startup_key(self) -> ExternalInfoDatum | None:
"""Find the external startup/recovery key information."""
for datum in self.find_datum(FVE_DATUM_ROLE.STARTUP_KEY, FVE_DATUM_TYPE.EXTERNAL_INFO):
return datum
return None

Check warning on line 203 in dissect/fve/bde/information.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/information.py#L203

Added line #L203 was not covered by tests

def find_fvek(self) -> AesCcmEncryptedDatum | None:
"""Find the encrypted FVEK."""
for datum in self.find_datum(FVE_DATUM_ROLE.FULL_VOLUME_ENCRYPTION_KEY, FVE_DATUM_TYPE.AES_CCM_ENCRYPTED_KEY):
return datum
return None

Check warning on line 209 in dissect/fve/bde/information.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/information.py#L209

Added line #L209 was not covered by tests

def find_vmk(
self,
Expand All @@ -220,6 +227,7 @@
"""Find the clear key VMK (for paused volumes)."""
for vmk in self.find_vmk(FVE_KEY_PROTECTOR.CLEAR, max_priority=0xFF, mask=0x0000):
return vmk
return None

Check warning on line 230 in dissect/fve/bde/information.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/information.py#L230

Added line #L230 was not covered by tests

def find_external_vmk(self) -> Iterator[VmkInfoDatum]:
"""Find the external VMK."""
Expand Down Expand Up @@ -497,7 +505,7 @@


class ValidationEntry:
def __init__(self, fh):
def __init__(self, fh: BinaryIO):
self._entry = c_bde.FVE_DATUM_VALIDATION_ENTRY(fh)

def __repr__(self) -> str:
Expand Down Expand Up @@ -544,54 +552,64 @@
encrypted_key = self.aes_ccm_encrypted_key()
return encrypted_key.unbox(key)

def label(self) -> str:
def label(self) -> str | None:
for datum in self.find_property(FVE_DATUM_TYPE.UNICODE):
return datum.text
return None

Check warning on line 558 in dissect/fve/bde/information.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/information.py#L558

Added line #L558 was not covered by tests

def asymmetric_encrypted_key(self) -> AsymmetricEncryptedDatum:
def asymmetric_encrypted_key(self) -> AsymmetricEncryptedDatum | None:
for datum in self.find_property(FVE_DATUM_TYPE.ASYMMETRIC_ENCRYPTED_KEY):
return datum
return None

Check warning on line 563 in dissect/fve/bde/information.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/information.py#L563

Added line #L563 was not covered by tests

def exported_key(self) -> ExportedPublicKeyDatum:
def exported_key(self) -> ExportedPublicKeyDatum | None:
for datum in self.find_property(FVE_DATUM_TYPE.EXPORTED_KEY):
return datum
return None

Check warning on line 568 in dissect/fve/bde/information.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/information.py#L568

Added line #L568 was not covered by tests

def tpm_encrypted_blob(self) -> TpmEncryptedBlobDatum:
def tpm_encrypted_blob(self) -> TpmEncryptedBlobDatum | None:
for datum in self.find_property(FVE_DATUM_TYPE.TPM_ENCRYPTED_BLOB):
return datum
return None

Check warning on line 573 in dissect/fve/bde/information.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/information.py#L573

Added line #L573 was not covered by tests

def aes_ccm_encrypted_key(self) -> AesCcmEncryptedDatum:
def aes_ccm_encrypted_key(self) -> AesCcmEncryptedDatum | None:
for datum in self.find_property(FVE_DATUM_TYPE.AES_CCM_ENCRYPTED_KEY):
return datum
return None

Check warning on line 578 in dissect/fve/bde/information.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/information.py#L578

Added line #L578 was not covered by tests

def public_key_info(self) -> PublicKeyInfoDatum:
def public_key_info(self) -> PublicKeyInfoDatum | None:
for datum in self.find_property(FVE_DATUM_TYPE.PUBLIC_KEY_INFO):
return datum
return None

Check warning on line 583 in dissect/fve/bde/information.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/information.py#L583

Added line #L583 was not covered by tests

def use_keys(self) -> list[UseKeyDatum]:
return list(self.find_property(FVE_DATUM_TYPE.USE_KEY))

def use_key(self, key_type: FVE_KEY_TYPE) -> UseKeyDatum:
def use_key(self, key_type: FVE_KEY_TYPE) -> UseKeyDatum | None:
for datum in self.use_keys():
if key_type is None or datum.key_type == key_type:
return datum
return None

Check warning on line 592 in dissect/fve/bde/information.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/information.py#L592

Added line #L592 was not covered by tests

def stretch_keys(self) -> list[StretchKeyDatum]:
return list(self.find_property(FVE_DATUM_TYPE.STRETCH_KEY))

def stretch_key(self, key_type: FVE_KEY_TYPE) -> StretchKeyDatum:
def stretch_key(self, key_type: FVE_KEY_TYPE) -> StretchKeyDatum | None:
for datum in self.stretch_keys():
if key_type is None or datum.key_type == key_type:
return datum
return None

Check warning on line 601 in dissect/fve/bde/information.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/information.py#L601

Added line #L601 was not covered by tests

def clear_key(self) -> KeyDatum:
def clear_key(self) -> KeyDatum | None:
for datum in self.find_property(FVE_DATUM_TYPE.KEY):
return datum
return None

Check warning on line 606 in dissect/fve/bde/information.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/information.py#L606

Added line #L606 was not covered by tests

def is_enhanced_pin(self) -> bool:
for stretch_key in self.stretch_keys():
if stretch_key.key_type == FVE_KEY_TYPE.AES_CCM_256_2 and stretch_key.key_flags & FVE_KEY_FLAG.ENHANCED_PIN:
return True
return False

Check warning on line 612 in dissect/fve/bde/information.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/information.py#L612

Added line #L612 was not covered by tests

def is_enhanced_crypto(self) -> bool:
for stretch_key in self.stretch_keys():
Expand All @@ -600,6 +618,7 @@
and stretch_key.key_flags & FVE_KEY_FLAG.ENHANCED_CRYPTO
):
return True
return False

Check warning on line 621 in dissect/fve/bde/information.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/information.py#L621

Added line #L621 was not covered by tests

def uses_pbkdf2(self) -> bool:
for stretch_key in self.stretch_keys():
Expand All @@ -608,6 +627,7 @@
and stretch_key.key_flags & FVE_KEY_FLAG.PBKDF2
):
return True
return False

Check warning on line 630 in dissect/fve/bde/information.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/information.py#L630

Added line #L630 was not covered by tests


class ExternalInfoDatum(Datum):
Expand All @@ -630,10 +650,12 @@
def label(self) -> str | None:
for datum in self.find_property(FVE_DATUM_TYPE.UNICODE):
return datum.text
return None

Check warning on line 653 in dissect/fve/bde/information.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/information.py#L653

Added line #L653 was not covered by tests

def external_key(self) -> KeyDatum | None:
for datum in self.find_property(FVE_DATUM_TYPE.KEY):
return datum
return None

Check warning on line 658 in dissect/fve/bde/information.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/bde/information.py#L658

Added line #L658 was not covered by tests


class UpdateDatum(Datum):
Expand Down
2 changes: 2 additions & 0 deletions dissect/fve/bde/keys.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import hashlib
import struct

Expand Down
8 changes: 4 additions & 4 deletions dissect/fve/crypto/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional
from __future__ import annotations

from Crypto.Cipher import AES

Expand Down Expand Up @@ -26,7 +26,7 @@


def create_cipher(
spec: str, key: bytes, key_size: Optional[int] = None, sector_size: int = 512, iv_sector_size: int = 512
spec: str, key: bytes, key_size: int | None = None, sector_size: int = 512, iv_sector_size: int = 512
) -> Cipher:
"""Create a cipher object according to a given cipher specification and key.

Expand Down Expand Up @@ -65,8 +65,8 @@ def create_cipher(


def parse_cipher_spec(
spec: str, key_size: Optional[int] = None, key_size_hint: Optional[int] = None
) -> tuple[str, str, int, str, Optional[str]]:
spec: str, key_size: int | None = None, key_size_hint: int | None = None
) -> tuple[str, str, int, str, str | None]:
"""Parse a cipher specification into a tuple of (cipher, mode, key size, iv mode, iv options).

Inspired by and accepts LUKS/dm-crypt-like cipher specifications in the form of::
Expand Down
10 changes: 5 additions & 5 deletions dissect/fve/crypto/_pycryptodome.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,18 @@

if _raw_api.backend == "cffi":

def get_iv_view(cipher, size):
def get_iv_view(cipher: AES.CbcMode | AES.EcbMode, size: int) -> memoryview:
return _raw_api.ffi.cast(_raw_api.uint8_t_type, cipher._state.get() + POINTER_SIZE)[0:size]

elif _raw_api.backend == "ctypes":
import ctypes

def get_iv_view(cipher, size):
def get_iv_view(cipher: AES.CbcMode | AES.EcbMode, size: int) -> memoryview:
return ctypes.cast(cipher._state.get().value + POINTER_SIZE, ctypes.POINTER(ctypes.c_char * size))[0]

else:

def get_iv_view(cipher, size):
def get_iv_view(cipher: AES.CbcMode | AES.EcbMode, size: int) -> memoryview:

Check warning on line 37 in dissect/fve/crypto/_pycryptodome.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/crypto/_pycryptodome.py#L37

Added line #L37 was not covered by tests
raise NotImplementedError("Unsupported pycryptodome backend")


Expand Down Expand Up @@ -112,7 +112,7 @@

def __init__(
self,
factory: Any,
factory: AES,
key: bytes,
key_size: int,
iv_mode: type[IV],
Expand Down Expand Up @@ -233,7 +233,7 @@


def _create_cipher_factory(mode: type[Cipher]) -> Callable[..., Cipher]:
def cipher_factory(factory: Any, **kwargs) -> Cipher:
def cipher_factory(factory: AES, **kwargs) -> Cipher:
try:
key = kwargs.pop("key")
key_size = kwargs.pop("key_size")
Expand Down
8 changes: 4 additions & 4 deletions dissect/fve/crypto/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
self.iv_mode = iv_mode(self, key, iv_options)

def _crypt_sector(self, mode: int, buffer: bytearray, iv: bytes) -> None:
raise NotImplementedError()
raise NotImplementedError

Check warning on line 28 in dissect/fve/crypto/base.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/crypto/base.py#L28

Added line #L28 was not covered by tests

def _crypt(self, mode: int, ciphertext: bytes, sector: int = 0, output: bytearray | None = None) -> bytes | None:
length = len(ciphertext)
Expand Down Expand Up @@ -101,16 +101,16 @@
class EBOIV(IV):
def __init__(self, cipher: Cipher, key: bytes, iv_options: str | None = None):
# Implementation specific
raise NotImplementedError()
raise NotImplementedError

Check warning on line 104 in dissect/fve/crypto/base.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/crypto/base.py#L104

Added line #L104 was not covered by tests


class ESSIV(IV):
def __init__(self, cipher: Cipher, key: bytes, iv_options: str | None = None):
# Implementation specific
raise NotImplementedError()
raise NotImplementedError

Check warning on line 110 in dissect/fve/crypto/base.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/crypto/base.py#L110

Added line #L110 was not covered by tests


class Elephant(IV):
def __init__(self, cipher: Cipher, key: bytes, iv_options: str | None = None):
# Implementation specific
raise NotImplementedError()
raise NotImplementedError

Check warning on line 116 in dissect/fve/crypto/base.py

View check run for this annotation

Codecov / codecov/patch

dissect/fve/crypto/base.py#L116

Added line #L116 was not covered by tests
Loading
Loading