keycard.commands package

Submodules

keycard.commands.ident module

keycard.commands.ident.ident(card, challenge)

Sends a challenge to the card to receive a signed identity response.

Return type:

bytes

Parameters:
  • transport – An instance of the Transport class to communicate with the card.

  • challenge (bytes) – A challenge (nonce or data) to send to the card. If None, a random 32-byte challenge is generated.

Returns:

The public key extracted from the card’s identity response.

Return type:

bytes

Raises:

APDUError – If the response status word is not successful (0x9000).

keycard.commands.init module

keycard.commands.init.init(card, pin, puk, pairing_secret)

Initializes a Keycard device with PIN, PUK, and pairing secret.

Establishes an ephemeral ECDH key exchange and sends encrypted credentials to the card.

Return type:

None

Parameters:
  • transport – The transport used to send APDU commands to the card.

  • card_public_key (bytes) – The card’s ECC public key, usually retrieved via select().

  • pin (bytes) – The personal identification number (PIN) as bytes.

  • puk (bytes) – The personal unblocking key (PUK) as bytes.

  • pairing_secret (bytes) – A 32-byte shared secret or a passphrase that will be converted into one.

Raises:
  • NotSelectedError – If no card public key is provided.

  • ValueError – If the encrypted data exceeds a single APDU length.

  • APDUError – If the card returns a failure status word.

keycard.commands.mutually_authenticate module

keycard.commands.mutually_authenticate.mutually_authenticate(card, client_challenge=None)

Performs mutual authentication between the client and the Keycard.

Return type:

None

Preconditions:
  • Secure Channel must be opened

The card will respond with a cryptographic challenge. The secure session will verify the response. If the response is not exactly 32 bytes, or if the response has an unexpected status word, the function raises an error.

Parameters:
  • transport – A Transport instance for sending APDUs.

  • session – A SecureChannel instance used for wrapping/unwrapping.

  • client_challenge (bytes, optional) – Optional challenge bytes. If not provided, a random 32-byte value will be generated.

Raises:
  • APDUError – If the response status word is not 0x9000.

  • ValueError – If the decrypted response is not exactly 32 bytes.

keycard.commands.open_secure_channel module

keycard.commands.open_secure_channel.open_secure_channel(card, pairing_index, pairing_key)

Opens a secure session with the Keycard using ECDH and a pairing key.

This function performs an ephemeral ECDH key exchange with the card, sends the ephemeral public key, and receives cryptographic material from the card to derive a secure session.

Return type:

SecureChannel

Parameters:
  • transport – The transport used to communicate with the card.

  • card_public_key (bytes) – The ECC public key of the card, retrieved via select().

  • pairing_index (int) – The index of the previously established pairing slot.

  • pairing_key (bytes) – The shared 32-byte pairing key.

Returns:

A newly established secure session with the card.

Return type:

SecureChannel

Raises:

keycard.commands.pair module

keycard.commands.pair.pair(card, shared_secret, pairing_mode=PairingMode.ANY)

Performs an ECDH-based pairing handshake with the card.

Return type:

tuple[int, bytes]

Parameters:
  • card – The keycard interface.

  • shared_secret – A 32-byte secret or a passphrase convertible to one.

  • pairing_mode – Mode for pairing: ANY, EPHEMERAL, PERSISTENT

Returns:

Pairing index and derived 32-byte pairing key.

Return type:

tuple[int, bytes]

Raises:
  • ValueError – If the shared secret is not 32 bytes.

  • APDUError – If the card returns a non-success status word.

  • InvalidResponseError – If response lengths or values are unexpected.

keycard.commands.select module

keycard.commands.select.select(card)

Selects the Keycard application on the smart card and retrieves application information.

Sends a SELECT APDU command using the Keycard AID, checks for a successful response, parses the returned application information, and returns it.

Return type:

ApplicationInfo

Parameters:

transport – The transport instance used to send the APDU command.

Returns:

Parsed information about the selected Keycard

application.

Return type:

ApplicationInfo

Raises:

APDUError – If the card returns a status word indicating failure.

keycard.commands.unpair module

keycard.commands.unpair.unpair(card, index)

Sends the UNPAIR command to remove a pairing index from the card.

Return type:

None

Preconditions:
  • Secure Channel must be opened

  • PIN must be verified

This function securely communicates with the card using the established session to instruct it to forget a specific pairing index.

Parameters:
  • transport – The transport interface used to send APDUs.

  • secure_session – The active SecureChannel object used to wrap APDUs.

  • index (int) – The pairing index (0–15) to unpair from the card.

Raises:
  • ValueError – If transport or secure_session is not provided, or if the session is not authenticated.

  • APDUError – If the response status word indicates an error.

keycard.commands.verify_pin module

keycard.commands.verify_pin.verify_pin(card, pin)

Verifies the user PIN with the card using a secure session.

Return type:

bool

Preconditions:
  • Secure Channel must be opened

  • PIN must be verified

Sends the VERIFY PIN APDU command through the secure session. Returns True if the PIN is correct, False if incorrect with remaining attempts, and raises an error if blocked or another APDU error occurs.

Parameters:
  • transport – The transport instance used to send the command.

  • session – An established SecureChannel object.

  • pin (str) – The PIN string to be verified.

Returns:

True if the PIN is correct, False if incorrect but still allowed.

Return type:

bool

Raises:
  • ValueError – If no secure session is provided.

  • RuntimeError – If the PIN is blocked (no attempts remaining).

  • APDUError – For other status word errors returned by the card.

Module contents

keycard.commands.change_secret(card, new_value, pin_type)

Changes the specified secret (PIN, PUK, PAIRING) or secret on the card.

Return type:

None

Preconditions:
  • Secure Channel must be opened

  • User PIN must be verified

Parameters:
  • card – The card session object.

  • new_value (bytes | str) – The new PIN/PUK/secret.

  • pin_type (PinType) – Type of PIN (USER, PUK, or PAIRING)

Raises:
  • ValueError – If input format is invalid.

  • APDUError – If the card returns an error status word.

keycard.commands.derive_key(card, path='')

Set the derivation path for subsequent SIGN and EXPORT KEY commands.

Return type:

None

Parameters:
  • card (CardInterface) – The card interface.

  • path (str) – BIP-32-style path (e.g., “m/44’/60’/0’/0/0”) or “../0/1” (parent) or “./0” (current).

Raises:

APDUError – if the derivation fails or the format is invalid.

keycard.commands.export_key(card, derivation_option, public_only, keypath=None, make_current=False, source=DerivationSource.MASTER)

Export a key (public or private) from the card using an optional keypath.

If derivation_option == CURRENT, keypath can be omitted or empty.

Return type:

ExportedKey

Parameters:
  • card – The card object

  • derivation_option – e.g. DERIVE, CURRENT, DERIVE_AND_MAKE_CURRENT

  • public_only – If True, export only public key

  • keypath – BIP32-style string or packed bytes, or None if CURRENT

  • make_current – Whether to update the card’s current path

  • source – MASTER (0x00), PARENT (0x40), CURRENT (0x80)

Returns:

dict with optional ‘public_key’, ‘private_key’, ‘chain_code’

keycard.commands.factory_reset(card)

Sends the FACTORY_RESET command to the card.

Return type:

None

keycard.commands.generate_key(card)

Generates a new key on the card and returns the key UID.

Return type:

bytes

Preconditions:
  • Secure Channel must be opened

  • PIN must be verified

Parameters:
  • transport – Transport instance for APDU communication

  • session – SecureChannel instance for wrapping/unwrapping

Returns:

Key UID (SHA-256 of the public key)

Return type:

bytes

Raises:

APDUError – If the response status word is not 0x9000

keycard.commands.generate_mnemonic(card, checksum_size=6)

Generate a BIP39 mnemonic using the card’s RNG.

Return type:

list[int]

Parameters:
  • card (CardInterface) – The card interface.

  • checksum_size (int) – Number of checksum bits (between 4 and 8 inclusive).

Returns:

List of integers (0-2047) corresponding to wordlist

indexes.

Return type:

List[int]

Raises:
  • ValueError – If checksum size is outside the allowed range.

  • APDUError – If the card rejects the request.

keycard.commands.get_data(card, slot=StorageSlot.PUBLIC)

Gets the data on the card previously stored with the store data command in the specified slot.

If the secure channel is open, it uses the secure APDU command. Otherwise, it uses the proprietary APDU command.

Return type:

bytes

Parameters:
  • card – The card session object.

  • slot (StorageSlot) – Where to store the data (PUBLIC, NDEF, CASH)

Raises:

ValueError – If slot is invalid or data is too long.

keycard.commands.get_status(card, key_path=False)

Query the application status or key path from the Keycard.

Requires an open Secure Channel.

Return type:

dict[str, int | bool] | list[int]

Parameters:
  • transport – Transport instance used to send APDU bytes.

  • session – An established SecureChannel instance.

  • key_path (bool) – If True, returns the current key path. If False (default), returns application status.

Returns:

dict with keys:
  • pin_retry_count (int)

  • puk_retry_count (int)

  • initialized (bool)

If key_path is True:

List of 32-bit integers representing the current key path.

Return type:

If key_path is False

Raises:
  • APDUError – If the response status word is not 0x9000.

  • ValueError – If the application status template (tag 0xA3) is missing.

keycard.commands.ident(card, challenge)

Sends a challenge to the card to receive a signed identity response.

Return type:

bytes

Parameters:
  • transport – An instance of the Transport class to communicate with the card.

  • challenge (bytes) – A challenge (nonce or data) to send to the card. If None, a random 32-byte challenge is generated.

Returns:

The public key extracted from the card’s identity response.

Return type:

bytes

Raises:

APDUError – If the response status word is not successful (0x9000).

keycard.commands.init(card, pin, puk, pairing_secret)

Initializes a Keycard device with PIN, PUK, and pairing secret.

Establishes an ephemeral ECDH key exchange and sends encrypted credentials to the card.

Return type:

None

Parameters:
  • transport – The transport used to send APDU commands to the card.

  • card_public_key (bytes) – The card’s ECC public key, usually retrieved via select().

  • pin (bytes) – The personal identification number (PIN) as bytes.

  • puk (bytes) – The personal unblocking key (PUK) as bytes.

  • pairing_secret (bytes) – A 32-byte shared secret or a passphrase that will be converted into one.

Raises:
  • NotSelectedError – If no card public key is provided.

  • ValueError – If the encrypted data exceeds a single APDU length.

  • APDUError – If the card returns a failure status word.

keycard.commands.load_key(card, key_type, public_key=None, private_key=None, chain_code=None, bip39_seed=None)

Load a key into the card for signing purposes.

Return type:

bytes

Parameters:
  • card – The card interface.

  • key_type – Key type

  • public_key – Optional ECC public key (tag 0x80).

  • private_key – ECC private key (tag 0x81).

  • chain_code – Optional chain code (tag 0x82, only for extended key).

  • bip39_seed – 64-byte BIP39 seed (only for key_type=BIP39_SEED).

Returns:

UID of the loaded key (SHA-256 of public key).

keycard.commands.mutually_authenticate(card, client_challenge=None)

Performs mutual authentication between the client and the Keycard.

Return type:

None

Preconditions:
  • Secure Channel must be opened

The card will respond with a cryptographic challenge. The secure session will verify the response. If the response is not exactly 32 bytes, or if the response has an unexpected status word, the function raises an error.

Parameters:
  • transport – A Transport instance for sending APDUs.

  • session – A SecureChannel instance used for wrapping/unwrapping.

  • client_challenge (bytes, optional) – Optional challenge bytes. If not provided, a random 32-byte value will be generated.

Raises:
  • APDUError – If the response status word is not 0x9000.

  • ValueError – If the decrypted response is not exactly 32 bytes.

keycard.commands.open_secure_channel(card, pairing_index, pairing_key)

Opens a secure session with the Keycard using ECDH and a pairing key.

This function performs an ephemeral ECDH key exchange with the card, sends the ephemeral public key, and receives cryptographic material from the card to derive a secure session.

Return type:

SecureChannel

Parameters:
  • transport – The transport used to communicate with the card.

  • card_public_key (bytes) – The ECC public key of the card, retrieved via select().

  • pairing_index (int) – The index of the previously established pairing slot.

  • pairing_key (bytes) – The shared 32-byte pairing key.

Returns:

A newly established secure session with the card.

Return type:

SecureChannel

Raises:
keycard.commands.pair(card, shared_secret, pairing_mode=PairingMode.ANY)

Performs an ECDH-based pairing handshake with the card.

Return type:

tuple[int, bytes]

Parameters:
  • card – The keycard interface.

  • shared_secret – A 32-byte secret or a passphrase convertible to one.

  • pairing_mode – Mode for pairing: ANY, EPHEMERAL, PERSISTENT

Returns:

Pairing index and derived 32-byte pairing key.

Return type:

tuple[int, bytes]

Raises:
  • ValueError – If the shared secret is not 32 bytes.

  • APDUError – If the card returns a non-success status word.

  • InvalidResponseError – If response lengths or values are unexpected.

keycard.commands.remove_key(card)

Removes the key from the card, returning it to an uninitialized state.

Return type:

None

keycard.commands.select(card)

Selects the Keycard application on the smart card and retrieves application information.

Sends a SELECT APDU command using the Keycard AID, checks for a successful response, parses the returned application information, and returns it.

Return type:

ApplicationInfo

Parameters:

transport – The transport instance used to send the APDU command.

Returns:

Parsed information about the selected Keycard

application.

Return type:

ApplicationInfo

Raises:

APDUError – If the card returns a status word indicating failure.

keycard.commands.set_pinless_path(card, path)

Set a PIN-less path on the card. Allows signing without PIN/auth if the current derived key matches this path.

Return type:

None

Parameters:
  • card (CardInterface) – The card interface.

  • path (str) – BIP-32-style path (e.g., “m/44’/60’/0’/0/0”). An empty string disables the pinless path.

Raises:

APDUError – if the card rejects the input (invalid path)

keycard.commands.sign(card, digest, p1=DerivationOption.CURRENT, p2=SigningAlgorithm.ECDSA_SECP256K1, derivation_path=None)

Sign a 32-byte digest using the specified key and signing algorithm.

This command sends the SIGN APDU to the Keycard and parses the response, returning a structured SignatureResult object. The signature may be returned as a DER-encoded structure, a raw 65-byte format including the recovery ID, or an ECDSA template depending on card behavior.

Return type:

SignatureResult

Preconditions:
  • Secure Channel must be opened (unless using PINLESS)

  • PIN must be verified (unless using PINLESS)

  • A valid keypair must be loaded on the card

  • If P1=PINLESS, a PIN-less path must be configured

Parameters:
  • card (CardInterface) – Active Keycard transport session.

  • digest (bytes) – 32-byte hash to be signed.

  • p1 (DerivationOption) – Key derivation option. One of: - CURRENT: Sign with the currently loaded key - DERIVE: Derive key for signing without changing current - DERIVE_AND_MAKE_CURRENT: Derive and load for future use - PINLESS: Use pre-defined PIN-less key without SC/PIN

  • p2 (SigningAlgorithm) – Signing algorithm (e.g. ECDSA_SECP256K1).

  • derivation_path (Optional[str]) – String-formatted BIP32 path (e.g. “m/44’/60’/0’/0/0”). Required if p1 uses derivation. The source (master/parent/current) is inferred from the path prefix.

Returns:

Parsed signature result, including the signature (DER or raw), algorithm, and optional recovery ID or public key.

Return type:

SignatureResult

Raises:
  • ValueError – If the digest is not 32 bytes or path is invalid.

  • InvalidStateError – If preconditions (PIN, SC) are not met.

  • APDUError – If the card returns an error (e.g., SW=0x6985).

keycard.commands.store_data(card, data, slot=StorageSlot.PUBLIC)

Stores data on the card in the specified slot.

Return type:

None

Parameters:
  • card – The card session object.

  • data (bytes) – The data to store (max 127 bytes).

  • slot (StorageSlot) – Where to store the data (PUBLIC, NDEF, CASH)

Raises:

ValueError – If slot is invalid or data is too long.

keycard.commands.unblock_pin(card, puk_and_pin)

Unblocks the user PIN using the provided PUK and sets a new PIN.

Return type:

None

Parameters:
  • card – The card session object.

  • puk_and_pin (bytes | str) – Concatenation of PUK (12 digits) + new PIN (6 digits)

Raises:
  • ValueError – If the format is invalid.

  • APDUError – If the card returns an error.

keycard.commands.unpair(card, index)

Sends the UNPAIR command to remove a pairing index from the card.

Return type:

None

Preconditions:
  • Secure Channel must be opened

  • PIN must be verified

This function securely communicates with the card using the established session to instruct it to forget a specific pairing index.

Parameters:
  • transport – The transport interface used to send APDUs.

  • secure_session – The active SecureChannel object used to wrap APDUs.

  • index (int) – The pairing index (0–15) to unpair from the card.

Raises:
  • ValueError – If transport or secure_session is not provided, or if the session is not authenticated.

  • APDUError – If the response status word indicates an error.

keycard.commands.verify_pin(card, pin)

Verifies the user PIN with the card using a secure session.

Return type:

bool

Preconditions:
  • Secure Channel must be opened

  • PIN must be verified

Sends the VERIFY PIN APDU command through the secure session. Returns True if the PIN is correct, False if incorrect with remaining attempts, and raises an error if blocked or another APDU error occurs.

Parameters:
  • transport – The transport instance used to send the command.

  • session – An established SecureChannel object.

  • pin (str) – The PIN string to be verified.

Returns:

True if the PIN is correct, False if incorrect but still allowed.

Return type:

bool

Raises:
  • ValueError – If no secure session is provided.

  • RuntimeError – If the PIN is blocked (no attempts remaining).

  • APDUError – For other status word errors returned by the card.