kdbxtool.security

Security-critical components for kdbxtool.

This module contains all security-sensitive code including: - Secure memory handling (SecureBytes) - Cryptographic operations - Key derivation functions - YubiKey challenge-response support

All code in this module should be audited carefully.

class kdbxtool.security.SecureBytes(data)[source]

Bases: object

A secure container for sensitive byte data that zeroizes on destruction.

Unlike Python’s immutable bytes, SecureBytes uses a mutable bytearray that can be explicitly zeroed when no longer needed. This prevents sensitive data like passwords and cryptographic keys from lingering in memory.

Usage:

# Basic usage key = SecureBytes(derived_key_bytes) # … use key.data for crypto operations … key.zeroize() # Explicit cleanup

# Context manager (recommended) with SecureBytes(password.encode()) as pwd:

hash = sha256(pwd.data)

# Automatically zeroized here

Note

While this provides defense-in-depth against memory disclosure attacks, Python’s memory management means copies may still exist. For maximum security, consider using specialized libraries like PyNaCl’s SecretBox.

Parameters:

data (bytes | bytearray)

__init__(data)[source]

Initialize with sensitive data.

Parameters:

data (bytes | bytearray) – The sensitive bytes to protect. Will be copied into internal buffer.

Return type:

None

property data: bytes

Access the underlying data as immutable bytes.

Returns:

The protected data as bytes.

Raises:

ValueError – If the buffer has already been zeroized.

classmethod from_str(s, encoding='utf-8')[source]

Create SecureBytes from a string.

Parameters:
  • s (str) – String to encode

  • encoding (str) – Character encoding (default: utf-8)

Returns:

SecureBytes containing the encoded string

Return type:

Self

zeroize()[source]

Overwrite the buffer with zeros.

This method overwrites every byte in the buffer with 0x00, making the original data unrecoverable from this object. Safe to call multiple times.

Return type:

None

class kdbxtool.security.Cipher(*values)[source]

Bases: Enum

Supported ciphers for KDBX encryption.

KDBX supports three ciphers: - AES-256-CBC: Traditional cipher, widely supported - ChaCha20: Modern stream cipher, faster in software - Twofish-256-CBC: Legacy cipher, requires oxifish package

Note: KDBX uses plain ChaCha20, not ChaCha20-Poly1305. Authentication is provided by the HMAC block stream.

The UUID values are defined in the KDBX specification.

property key_size: int

Return the key size in bytes for this cipher.

property iv_size: int

Return the IV/nonce size in bytes for this cipher.

property display_name: str

Human-readable cipher name.

classmethod from_uuid(uuid_bytes)[source]

Look up cipher by its KDBX UUID.

Parameters:

uuid_bytes (bytes) – 16-byte cipher identifier from KDBX header

Returns:

The corresponding Cipher enum value

Raises:

ValueError – If the UUID doesn’t match any known cipher

Return type:

Cipher

AES256_CBC = b'1\xc1\xf2\xe6\xbfqCP\xbeX\x05!j\xfcZ\xff'
CHACHA20 = b'\xd6\x03\x8a+\x8boL\xb5\xa5$3\x9a1\xdb\xb5\x9a'
TWOFISH256_CBC = b'\xadh\xf2\x9fWoK\xb9\xa3j\xd4z\xf9e4l'
class kdbxtool.security.CipherContext(cipher, key, iv)[source]

Bases: object

Context for encrypting or decrypting data with a KDBX cipher.

This class wraps PyCryptodome cipher implementations with a consistent interface for KDBX operations.

Parameters:
__init__(cipher, key, iv)[source]

Initialize cipher context.

Parameters:
  • cipher (Cipher) – Which cipher algorithm to use

  • key (bytes) – Encryption key (32 bytes)

  • iv (bytes) – Initialization vector/nonce

Raises:
Return type:

None

decrypt(ciphertext)[source]

Decrypt ciphertext data.

For AES-CBC and Twofish-CBC, returns decrypted data (caller must remove padding). For ChaCha20, returns stream-decrypted plaintext.

Parameters:

ciphertext (bytes) – Data to decrypt

Returns:

Decrypted plaintext

Return type:

bytes

encrypt(plaintext)[source]

Encrypt plaintext data.

For AES-CBC and Twofish-CBC, data must be padded to block size. For ChaCha20, returns stream-encrypted ciphertext (same length as input).

Parameters:

plaintext (bytes) – Data to encrypt

Returns:

Encrypted data (same length as input for ChaCha20)

Return type:

bytes

kdbxtool.security.compute_hmac_sha256(key, data)[source]

Compute HMAC-SHA256 of data using the given key.

Parameters:
  • key (bytes) – HMAC key

  • data (bytes) – Data to authenticate

Returns:

32-byte HMAC-SHA256 digest

Return type:

bytes

kdbxtool.security.constant_time_compare(a, b)[source]

Compare two byte sequences in constant time.

This prevents timing attacks where an attacker could measure response time differences to deduce secret values.

Parameters:
Returns:

True if sequences are equal, False otherwise

Return type:

bool

kdbxtool.security.secure_random_bytes(n)[source]

Generate cryptographically secure random bytes.

Uses os.urandom which is suitable for cryptographic use.

Parameters:

n (int) – Number of random bytes to generate

Returns:

n cryptographically random bytes

Return type:

bytes

kdbxtool.security.verify_hmac_sha256(key, data, expected_mac)[source]

Verify HMAC-SHA256 in constant time.

Parameters:
  • key (bytes) – HMAC key

  • data (bytes) – Data that was authenticated

  • expected_mac (bytes) – Expected MAC value to verify against

Returns:

True if MAC is valid, False otherwise

Return type:

bool

class kdbxtool.security.AesKdfConfig(rounds, salt)[source]

Bases: object

Configuration for AES-KDF key derivation.

AES-KDF is supported in both KDBX3 and KDBX4. While Argon2 is generally recommended for new databases, AES-KDF may be preferred for compatibility with older KeePass clients or on systems where Argon2 is slow.

Parameters:
rounds

Number of AES encryption rounds (higher = slower but more secure)

Type:

int

salt

32-byte salt

Type:

bytes

rounds: int
salt: bytes
__init__(rounds, salt)
Parameters:
Return type:

None

classmethod fast(salt=None)[source]

Create configuration for fast operations (testing only).

WARNING: Uses only 60,000 rounds which provides minimal security. Only use for testing or development.

Parameters:

salt (bytes | None) – Optional salt (32 random bytes generated if not provided)

Returns:

AesKdfConfig with minimal parameters

Return type:

AesKdfConfig

classmethod high_security(salt=None)[source]

Create configuration for high-security applications.

Uses 6,000,000 rounds for stronger protection at the cost of longer unlock times.

Parameters:

salt (bytes | None) – Optional salt (32 random bytes generated if not provided)

Returns:

AesKdfConfig with high security parameters

Return type:

AesKdfConfig

classmethod standard(salt=None)[source]

Create configuration with balanced security/performance.

Uses 600,000 rounds which provides reasonable security while keeping unlock times acceptable on most hardware.

Parameters:

salt (bytes | None) – Optional salt (32 random bytes generated if not provided)

Returns:

AesKdfConfig with standard parameters

Return type:

AesKdfConfig

class kdbxtool.security.Argon2Config(memory_kib, iterations, parallelism, salt, variant=KdfType.ARGON2D)[source]

Bases: object

Configuration for Argon2 key derivation.

Parameters:
memory_kib

Memory usage in KiB

Type:

int

iterations

Number of iterations (time cost)

Type:

int

parallelism

Degree of parallelism

Type:

int

salt

Random salt (must be at least 16 bytes)

Type:

bytes

variant

Argon2 variant (Argon2d or Argon2id)

Type:

kdbxtool.security.kdf.KdfType

memory_kib: int
iterations: int
parallelism: int
salt: bytes
variant: KdfType
__init__(memory_kib, iterations, parallelism, salt, variant=KdfType.ARGON2D)
Parameters:
Return type:

None

classmethod default(salt=None, variant=KdfType.ARGON2D)[source]

Create configuration with secure defaults.

Alias for standard(). Provides balanced security and performance.

Parameters:
  • salt (bytes | None) – Optional salt (32 random bytes generated if not provided)

  • variant (KdfType) – Argon2 variant (ARGON2D or ARGON2ID). Default is ARGON2D which provides better GPU resistance for local password databases.

Returns:

Argon2Config with recommended security parameters

Return type:

Argon2Config

classmethod fast(salt=None, variant=KdfType.ARGON2D)[source]

Create configuration for fast operations (testing only).

WARNING: This provides minimal security and should only be used for testing or development. Not suitable for production databases.

Parameters: 16 MiB memory, 3 iterations, 2 parallelism

Parameters:
  • salt (bytes | None) – Optional salt (32 random bytes generated if not provided)

  • variant (KdfType) – Argon2 variant (ARGON2D or ARGON2ID). Default is ARGON2D.

Returns:

Argon2Config with minimal parameters

Return type:

Argon2Config

classmethod high_security(salt=None, variant=KdfType.ARGON2D)[source]

Create configuration for high-security applications.

Use for sensitive data where longer unlock times are acceptable. Provides stronger protection against brute-force attacks.

Parameters: 256 MiB memory, 10 iterations, 4 parallelism

Parameters:
  • salt (bytes | None) – Optional salt (32 random bytes generated if not provided)

  • variant (KdfType) – Argon2 variant (ARGON2D or ARGON2ID). Default is ARGON2D which provides better GPU resistance for local password databases.

Returns:

Argon2Config with high security parameters

Return type:

Argon2Config

classmethod standard(salt=None, variant=KdfType.ARGON2D)[source]

Create configuration with balanced security/performance.

Suitable for most use cases. Provides good security with reasonable unlock times on modern hardware.

Parameters: 64 MiB memory, 3 iterations, 4 parallelism

Parameters:
  • salt (bytes | None) – Optional salt (32 random bytes generated if not provided)

  • variant (KdfType) – Argon2 variant (ARGON2D or ARGON2ID). Default is ARGON2D which provides better GPU resistance for local password databases. Use ARGON2ID if timing attack resistance is needed.

Returns:

Argon2Config with standard security parameters

Return type:

Argon2Config

validate_security()[source]

Check that parameters meet minimum security requirements.

Raises:

ValueError – If parameters are below security minimums

Return type:

None

class kdbxtool.security.KdfType(*values)[source]

Bases: Enum

Supported Key Derivation Functions in KDBX.

The UUID values are defined in the KDBX specification.

property display_name: str

Human-readable KDF name.

classmethod from_uuid(uuid_bytes)[source]

Look up KDF by its KDBX UUID.

Parameters:

uuid_bytes (bytes) – 16-byte KDF identifier from KDBX header

Returns:

The corresponding KdfType enum value

Raises:

ValueError – If the UUID doesn’t match any known KDF

Return type:

KdfType

ARGON2D = b'\xefcm\xdf\x8c)DK\x91\xf7\xa9\xa4\x03\xe3\n\x0c'
ARGON2ID = b'\x9e)\x8b\x19V\xdbGs\xb2=\xfc>\xc6\xf0\xa1\xe6'
AES_KDF = b'\xc9\xd9\xf3\x9ab\x8aD`\xbft\r\x08\xc1\x8aO\xea'
kdbxtool.security.derive_composite_key(password=None, keyfile_data=None, yubikey_response=None)[source]

Create composite key from password, keyfile, and/or YubiKey response.

The composite key is SHA-256(password_hash || keyfile_key || challenge_result).

KeePassXC-compatible YubiKey handling: - The YubiKey response (20 bytes HMAC-SHA1) is SHA-256 hashed - This hash is appended to the other key components before final SHA-256 - The challenge used to obtain the response should be the KDF salt

The keyfile_key is processed according to KeePass keyfile format rules.

Parameters:
  • password (str | None) – Optional password string

  • keyfile_data (bytes | None) – Optional keyfile contents

  • yubikey_response (bytes | None) – Optional 20-byte YubiKey HMAC-SHA1 response

Returns:

32-byte composite key wrapped in SecureBytes

Raises:
Return type:

SecureBytes

kdbxtool.security.derive_key_aes_kdf(password, config)[source]

Derive a 32-byte key using legacy AES-KDF.

This performs repeated AES-ECB encryption of the password using the salt as key. Only use for KDBX3 compatibility.

Parameters:
  • password (bytes) – 32-byte password hash

  • config (AesKdfConfig) – AES-KDF configuration

Returns:

32-byte derived key wrapped in SecureBytes

Raises:

ValueError – If password is not 32 bytes

Return type:

SecureBytes

kdbxtool.security.derive_key_argon2(password, config, *, enforce_minimums=True)[source]

Derive a 32-byte key using Argon2.

Parameters:
  • password (bytes) – Password bytes (usually composite key hash)

  • config (Argon2Config) – Argon2 configuration parameters

  • enforce_minimums (bool) – If True, reject weak parameters

Returns:

32-byte derived key wrapped in SecureBytes

Raises:

ValueError – If parameters are invalid or below minimums

Return type:

SecureBytes

class kdbxtool.security.KeyFileVersion(*values)[source]

Bases: StrEnum

Supported KeePass keyfile formats.

XML_V2

XML format v2.0 with hex-encoded key and SHA-256 hash verification. This is the recommended format for new keyfiles. Uses .keyx extension.

XML_V1

Legacy XML format v1.0 with base64-encoded key. Supported for compatibility. Uses .key extension.

RAW_32

Raw 32-byte binary key. Simple but no integrity verification.

HEX_64

64-character hex string (32 bytes encoded as hex).

XML_V2 = 'xml_v2'
XML_V1 = 'xml_v1'
RAW_32 = 'raw_32'
HEX_64 = 'hex_64'
kdbxtool.security.create_keyfile(path, version=KeyFileVersion.XML_V2)[source]

Create a new keyfile at the specified path.

Generates a cryptographically secure 32-byte random key and saves it in the specified format.

Parameters:
  • path (str | Path) – Path where the keyfile will be created.

  • version (KeyFileVersion) – Keyfile format to use. Defaults to XML_V2 (recommended).

Raises:

OSError – If the file cannot be written.

Return type:

None

Example

# Create XML v2.0 keyfile (recommended) create_keyfile(“vault.keyx”)

# Create raw binary keyfile create_keyfile(“vault.key”, version=KeyFileVersion.RAW_32)

kdbxtool.security.create_keyfile_bytes(version=KeyFileVersion.XML_V2)[source]

Create a new keyfile and return its contents as bytes.

Generates a cryptographically secure 32-byte random key and encodes it in the specified format.

Parameters:

version (KeyFileVersion) – Keyfile format to use. Defaults to XML_V2 (recommended).

Returns:

Keyfile contents as bytes, ready to write to a file.

Return type:

bytes

Example

keyfile_data = create_keyfile_bytes(KeyFileVersion.XML_V2) with open(“my.keyx”, “wb”) as f:

f.write(keyfile_data)

kdbxtool.security.parse_keyfile(keyfile_data)[source]

Parse keyfile data and extract the 32-byte key.

KeePass supports several keyfile formats: 1. XML keyfile (v1.0 or v2.0) - key is base64/hex encoded in XML 2. 32-byte raw binary - used directly 3. 64-byte hex string - decoded from hex 4. Any other size - SHA-256 hashed

Parameters:

keyfile_data (bytes) – Raw keyfile contents.

Returns:

32-byte key derived from keyfile.

Raises:

InvalidKeyFileError – If keyfile format is invalid or hash verification fails.

Return type:

bytes

class kdbxtool.security.YubiKeyConfig(slot=2, serial=None, timeout_seconds=15.0)[source]

Bases: object

Configuration for YubiKey challenge-response.

Parameters:
  • slot (int)

  • serial (int | None)

  • timeout_seconds (float)

slot

YubiKey slot to use (1 or 2). Slot 2 is typically used for challenge-response as slot 1 is often used for OTP.

Type:

int

serial

Optional serial number to select a specific YubiKey when multiple devices are connected. If None, uses the first device. Use list_yubikeys() to discover available devices and serials.

Type:

int | None

timeout_seconds

Timeout for challenge-response operation in seconds. If touch is required, this is the time to wait for the button press.

Type:

float

slot: int
serial: int | None
timeout_seconds: float
__init__(slot=2, serial=None, timeout_seconds=15.0)
Parameters:
  • slot (int)

  • serial (int | None)

  • timeout_seconds (float)

Return type:

None

kdbxtool.security.check_slot_configured(slot=2, serial=None)[source]

Check if a YubiKey slot is configured for HMAC-SHA1.

This is a convenience function to verify that a slot is properly configured before attempting to use it.

Parameters:
  • slot (int) – YubiKey slot to check (1 or 2).

  • serial (int | None) – Optional serial number to select a specific YubiKey when multiple devices are connected.

Returns:

True if the slot is configured for HMAC-SHA1, False otherwise.

Raises:
Return type:

bool

kdbxtool.security.compute_challenge_response(challenge, config=None)[source]

Send challenge to YubiKey and return HMAC-SHA1 response.

This function sends the challenge (the database’s KDF salt) to the YubiKey and returns the HMAC-SHA1 response. The response is computed by the YubiKey hardware using a secret that never leaves the device.

Parameters:
  • challenge (bytes) – Challenge bytes (32-byte KDF salt from KDBX header). Must be at least 1 byte.

  • config (YubiKeyConfig | None) – Optional YubiKey configuration. If not provided, uses slot 2 with 15 second timeout.

Returns:

20-byte HMAC-SHA1 response wrapped in SecureBytes for automatic zeroization when no longer needed.

Raises:
Return type:

SecureBytes

kdbxtool.security.list_yubikeys()[source]

List connected YubiKey devices.

Returns:

  • serial: Device serial number (if available)

  • name: Device name/model

Return type:

List of dictionaries containing device info

Raises:

YubiKeyNotAvailableError – If yubikey-manager is not installed.

Modules

crypto

Cryptographic primitives and utilities for kdbxtool.

kdf

Key Derivation Functions for KDBX databases.

keyfile

KeePass keyfile creation and parsing.

memory

Secure memory handling for sensitive data.

totp

TOTP (Time-based One-Time Password) implementation per RFC 6238.

yubikey

YubiKey HMAC-SHA1 challenge-response support.