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:
NotSelectedError – If no card public key is provided.
APDUError – If the card returns a failure status word.
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:
- Parameters:
transport – The transport instance used to send the APDU command.
- Returns:
- Parsed information about the selected Keycard
application.
- Return type:
- 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
- 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:
NotSelectedError – If no card public key is provided.
APDUError – If the card returns a failure status word.
- 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:
- Parameters:
transport – The transport instance used to send the APDU command.
- Returns:
- Parsed information about the selected Keycard
application.
- Return type:
- 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.