From 9b89f3ebd4c84f79da39861d596c9ff8c7d449a7 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Thu, 20 Nov 2025 01:59:52 +0100 Subject: [PATCH] crypto: add low_level.pyi stub file --- src/borg/crypto/low_level.pyi | 188 ++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 src/borg/crypto/low_level.pyi diff --git a/src/borg/crypto/low_level.pyi b/src/borg/crypto/low_level.pyi new file mode 100644 index 000000000..7d5b0f9a7 --- /dev/null +++ b/src/borg/crypto/low_level.pyi @@ -0,0 +1,188 @@ +# Type stubs for borg.crypto.low_level +# This file provides type hints for the Cython extension module + +from typing import Optional, Union + +API_VERSION: str + +# Module-level functions +def num_cipher_blocks(length: int, blocksize: int = 16) -> int: + """Return the number of cipher blocks required to encrypt/decrypt bytes of data.""" + ... + +def bytes_to_int(x: bytes, offset: int = 0) -> int: ... +def bytes_to_long(x: bytes, offset: int = 0) -> int: ... +def long_to_bytes(x: int) -> bytes: ... +def hmac_sha256(key: bytes, data: bytes) -> bytes: ... +def blake2b_256(key: bytes, data: bytes) -> bytes: ... +def blake2b_128(data: bytes) -> bytes: ... + +# Exception classes +class CryptoError(Exception): + """Malfunction in the crypto module.""" + + ... + +class IntegrityError(CryptoError): + """Integrity checks failed. Corrupted or tampered data.""" + + ... + +# Cipher classes +class UNENCRYPTED: + """Unencrypted cipher suite (no encryption, no MAC).""" + + header_len: int + iv: Optional[Union[int, bytes]] + + def __init__( + self, + mac_key: None, + enc_key: None, + iv: Optional[Union[int, bytes]] = None, + header_len: int = 1, + aad_offset: int = 1, + ) -> None: ... + def encrypt( + self, data: bytes, header: bytes = b"", iv: Optional[Union[int, bytes]] = None, aad: Optional[bytes] = None + ) -> bytes: ... + def decrypt(self, envelope: bytes, aad: Optional[bytes] = None) -> memoryview: ... + def block_count(self, length: int) -> int: ... + def set_iv(self, iv: Union[int, bytes]) -> None: ... + def next_iv(self) -> Union[int, bytes]: ... + def extract_iv(self, envelope: bytes) -> int: ... + +class AES256_CTR_BASE: + """Base class for AES-256-CTR based cipher suites.""" + + @classmethod + def requirements_check(cls) -> None: ... + def __init__( + self, + mac_key: bytes, + enc_key: bytes, + iv: Optional[Union[int, bytes]] = None, + header_len: int = 1, + aad_offset: int = 1, + ) -> None: ... + def encrypt( + self, data: bytes, header: bytes = b"", iv: Optional[Union[int, bytes]] = None, aad: Optional[bytes] = None + ) -> bytes: ... + def decrypt(self, envelope: bytes, aad: Optional[bytes] = None) -> bytes: ... + def block_count(self, length: int) -> int: ... + def set_iv(self, iv: Union[int, bytes]) -> None: ... + def next_iv(self) -> int: ... + def extract_iv(self, envelope: bytes) -> int: ... + +class AES256_CTR_HMAC_SHA256(AES256_CTR_BASE): + """AES-256-CTR with HMAC-SHA256 authentication.""" + + def __init__( + self, + mac_key: bytes, + enc_key: bytes, + iv: Optional[Union[int, bytes]] = None, + header_len: int = 1, + aad_offset: int = 1, + ) -> None: ... + +class AES256_CTR_BLAKE2b(AES256_CTR_BASE): + """AES-256-CTR with BLAKE2b authentication.""" + + def __init__( + self, + mac_key: bytes, + enc_key: bytes, + iv: Optional[Union[int, bytes]] = None, + header_len: int = 1, + aad_offset: int = 1, + ) -> None: ... + +class _AEAD_BASE: + """Base class for AEAD cipher suites.""" + + @classmethod + def requirements_check(cls) -> None: + """Check whether library requirements for this ciphersuite are satisfied.""" + ... + + def __init__( + self, key: bytes, iv: Optional[Union[int, bytes]] = None, header_len: int = 0, aad_offset: int = 0 + ) -> None: ... + def encrypt( + self, data: bytes, header: bytes = b"", iv: Optional[Union[int, bytes]] = None, aad: bytes = b"" + ) -> bytes: ... + def decrypt(self, envelope: bytes, aad: bytes = b"") -> bytes: ... + def block_count(self, length: int) -> int: ... + def set_iv(self, iv: Union[int, bytes]) -> None: ... + def next_iv(self) -> int: ... + +class AES256_OCB(_AEAD_BASE): + """AES-256-OCB AEAD cipher suite.""" + + @classmethod + def requirements_check(cls) -> None: ... + def __init__( + self, key: bytes, iv: Optional[Union[int, bytes]] = None, header_len: int = 0, aad_offset: int = 0 + ) -> None: ... + +class CHACHA20_POLY1305(_AEAD_BASE): + """ChaCha20-Poly1305 AEAD cipher suite.""" + + @classmethod + def requirements_check(cls) -> None: ... + def __init__( + self, key: bytes, iv: Optional[Union[int, bytes]] = None, header_len: int = 0, aad_offset: int = 0 + ) -> None: ... + +class AES: + """A thin wrapper around the OpenSSL EVP cipher API - for legacy code, like key file encryption.""" + + def __init__(self, enc_key: bytes, iv: Optional[Union[int, bytes]] = None) -> None: ... + def encrypt(self, data: bytes, iv: Optional[Union[int, bytes]] = None) -> bytes: ... + def decrypt(self, data: bytes) -> bytes: ... + def block_count(self, length: int) -> int: ... + def set_iv(self, iv: Union[int, bytes]) -> None: ... + def next_iv(self) -> int: ... + +class CSPRNG: + """ + Cryptographically Secure Pseudo-Random Number Generator based on AES-CTR mode. + + This class provides methods for generating random bytes and shuffling lists + using a deterministic algorithm seeded with a 256-bit key. + """ + + def __init__(self, seed_key: bytes) -> None: + """ + Initialize the CSPRNG with a 256-bit key. + + :param seed_key: A 32-byte key used as the seed for the CSPRNG + """ + ... + + def random_bytes(self, n: int) -> bytes: + """ + Generate n random bytes. + + :param n: Number of bytes to generate + :return: a bytes object containing the random bytes + """ + ... + + def random_int(self, n: int) -> int: + """ + Generate a random integer in the range [0, n). + + :param n: Upper bound (exclusive) + :return: Random integer + """ + ... + + def shuffle(self, items: list) -> None: + """ + Shuffle a list in-place using the Fisher-Yates algorithm. + + :param items: List to shuffle + """ + ...