Skip to content

Commit

Permalink
Change linter to Ruff
Browse files Browse the repository at this point in the history
  • Loading branch information
Schamper committed Jan 23, 2025
1 parent 39523e4 commit f70d913
Show file tree
Hide file tree
Showing 25 changed files with 282 additions and 169 deletions.
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 @@ def __init__(self, fh: BinaryIO):
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 @@ def __init__(self, fh: BinaryIO):
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 @@ def identifiers(self) -> list[UUID]:
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 @@ def unlock(self, key: bytes) -> None:

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 @@ def reserved_regions(self) -> list[tuple[int, int]]:
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 @@ def is_bde_volume(fh: BinaryIO) -> bool:
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 @@ def conv_log_size(self) -> int:

@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 @@ def find_description(self) -> str | None:
"""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 @@ def find_clear_vmk(self) -> VmkInfoDatum | None:
"""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 @@ def data(self) -> bytes:


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 @@ def decrypt(self, key: KeyDatum | bytes) -> KeyDatum:
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 @@ def is_enhanced_crypto(self) -> bool:
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 @@ def uses_pbkdf2(self) -> bool:
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 datetime(self) -> datetime.datetime:
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 @@ class XtsMode(Cipher):

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 post(self, mode: int, data: bytearray, sector: int = 0) -> None:


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 @@ def __init__(
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 @@ def generate(self, mode: int, iv: bytearray, data: bytearray, sector: int = 0) -
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

0 comments on commit f70d913

Please sign in to comment.