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)

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.

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

exception keycard.commands.APDUError(sw)

Bases: KeyCardError

Raised when APDU returns non-success status word.

class keycard.commands.ApplicationInfo(capabilities, ecc_public_key, instance_uid, key_uid, version_major, version_minor)

Bases: object

Represents parsed application information from a TLV-encoded response.

capabilities

Parsed capabilities value, if present.

Type:

Optional[int]

ecc_public_key

ECC public key bytes, if present.

Type:

Optional[bytes]

instance_uid

Unique identifier for the application instance, if present.

Type:

Optional[bytes]

key_uid

Unique identifier for the key, if present.

Type:

Optional[bytes]

version_major

Major version number of the application.

Type:

int

version_minor

Minor version number of the application.

Type:

int

capabilities: Optional[int]
ecc_public_key: Optional[bytes]
instance_uid: Optional[bytes]
property is_initialized: bool

Checks if the application is initialized based on the presence of the key_uid.

Returns:

True if the key_uid is present, False otherwise.

Return type:

bool

key_uid: Optional[bytes]
static parse(data)

Parses a byte sequence containing TLV-encoded application information and returns an ApplicationInfo instance.

Return type:

ApplicationInfo

Parameters:

data (bytes) – The TLV-encoded response data to parse.

Returns:

An instance populated with the parsed application

information fields.

Return type:

ApplicationInfo

The function extracts the following fields from the TLV data:
  • version_major (int): Major version number (from tag 0x02).

  • version_minor (int): Minor version number (from tag 0x02).

  • instance_uid (bytes or None): Instance UID (from tag 0x8F).

  • key_uid (bytes or None): Key UID (from tag 0x8E).

  • ecc_public_key (bytes or None): ECC public key (from tag 0x80).

  • capabilities (Capabilities or None): Capabilities object

    (from tag 0x8D).

Raises:
  • Any exceptions raised by ApplicationInfo._parse_response or

  • Capabilities.parse.

version_major: int
version_minor: int
class keycard.commands.CardInterface(*args, **kwargs)

Bases: Protocol

Abstract base class representing a Keycard interface for command functions.

card_public_key: Optional[bytes]
property is_initialized: bool
property is_pin_verified: bool
property is_secure_channel_open: bool
property is_selected: bool
send_apdu(ins, p1=0, p2=0, data=b'', cla=None)
Return type:

bytes

send_secure_apdu(ins, p1=0, p2=0, data=b'')
Return type:

bytes

class keycard.commands.DerivationOption(*values)

Bases: IntEnum

CURRENT = 0
DERIVE = 1
DERIVE_AND_MAKE_CURRENT = 2
PINLESS = 3
class keycard.commands.DerivationSource(*values)

Bases: IntEnum

CURRENT = 128
MASTER = 0
PARENT = 64
class keycard.commands.ECDH(curve=None, private_key=None, public_key=None)

Bases: object

Elliptic-curve Diffie-Hellman (ECDH). A key agreement protocol.

Allows two parties, each having an elliptic-curve public-private key pair, to establish a shared secret over an insecure channel

generate_private_key()

Generate local private key for ecdh operation with curve that was set.

Raises:

NoCurveError – Curve must be set before key generation.

Returns:

public (verifying) key from this private key.

Return type:

VerifyingKey

generate_sharedsecret()

Generate shared secret from local private key and remote public key.

The objects needs to have both private key and received public key before generation is allowed.

It’s the same for local and remote party, shared secret(local private key, remote public key) == shared secret(local public key, remote private key)

Raises:
  • InvalidCurveError – public_key curve not the same as self.curve

  • NoKeyError – public_key or private_key is not set

Returns:

shared secret

Return type:

int

generate_sharedsecret_bytes()

Generate shared secret from local private key and remote public key.

The objects needs to have both private key and received public key before generation is allowed.

Raises:
  • InvalidCurveError – public_key curve not the same as self.curve

  • NoKeyError – public_key or private_key is not set

Returns:

shared secret

Return type:

bytes

get_public_key()

Provides a public key that matches the local private key.

Needs to be sent to the remote party.

Returns:

public (verifying) key from local private key.

Return type:

VerifyingKey

load_private_key(private_key)

Load private key from SigningKey (keys.py) object.

Needs to have the same curve as was set with set_curve method. If curve is not set - it sets from this SigningKey

Parameters:

private_key (SigningKey) – Initialised SigningKey class

Raises:

InvalidCurveError – private_key curve not the same as self.curve

Returns:

public (verifying) key from this private key.

Return type:

VerifyingKey

load_private_key_bytes(private_key)

Load private key from byte string.

Uses current curve and checks if the provided key matches the curve of ECDH key agreement. Key loads via from_string method of SigningKey class

Parameters:

private_key (bytes-like object) – private key in bytes string format

Raises:

NoCurveError – Curve must be set before loading.

Returns:

public (verifying) key from this private key.

Return type:

VerifyingKey

load_private_key_der(private_key_der)

Load private key from DER byte string.

Compares the curve of the DER-encoded key with the ECDH set curve, uses the former if unset.

Note, the only DER format supported is the RFC5915 Look at keys.py:SigningKey.from_der()

Parameters:

private_key_der (string) – string with the DER encoding of private ECDSA key

Raises:

InvalidCurveError – private_key curve not the same as self.curve

Returns:

public (verifying) key from this private key.

Return type:

VerifyingKey

load_private_key_pem(private_key_pem)

Load private key from PEM string.

Compares the curve of the DER-encoded key with the ECDH set curve, uses the former if unset.

Note, the only PEM format supported is the RFC5915 Look at keys.py:SigningKey.from_pem() it needs to have EC PRIVATE KEY section

Parameters:

private_key_pem (string) – string with PEM-encoded private ECDSA key

Raises:

InvalidCurveError – private_key curve not the same as self.curve

Returns:

public (verifying) key from this private key.

Return type:

VerifyingKey

load_received_public_key(public_key)

Load public key from VerifyingKey (keys.py) object.

Needs to have the same curve as set as current for ecdh operation. If curve is not set - it sets it from VerifyingKey.

Parameters:

public_key (VerifyingKey) – Initialised VerifyingKey class

Raises:

InvalidCurveError – public_key curve not the same as self.curve

load_received_public_key_bytes(public_key_str, valid_encodings=None)

Load public key from byte string.

Uses current curve and checks if key length corresponds to the current curve. Key loads via from_string method of VerifyingKey class

Parameters:
  • public_key_str (bytes-like object) – public key in bytes string format

  • valid_encodings (set-like object) – list of acceptable point encoding formats, supported ones are: uncompressed, compressed, hybrid, and raw encoding (specified with raw name). All formats by default (specified with None).

load_received_public_key_der(public_key_der)

Load public key from DER byte string.

Compares the curve of the DER-encoded key with the ECDH set curve, uses the former if unset.

Note, the only DER format supported is the RFC5912 Look at keys.py:VerifyingKey.from_der()

Parameters:

public_key_der (string) – string with the DER encoding of public ECDSA key

Raises:

InvalidCurveError – public_key curve not the same as self.curve

load_received_public_key_pem(public_key_pem)

Load public key from PEM string.

Compares the curve of the PEM-encoded key with the ECDH set curve, uses the former if unset.

Note, the only PEM format supported is the RFC5912 Look at keys.py:VerifyingKey.from_pem()

Parameters:

public_key_pem (string) – string with PEM-encoded public ECDSA key

Raises:

InvalidCurveError – public_key curve not the same as self.curve

set_curve(key_curve)

Set the working curve for ecdh operations.

Parameters:

key_curve (Curve) – curve from curves module

class keycard.commands.ExportedKey(public_key=None, private_key=None, chain_code=None)

Bases: object

chain_code: Optional[bytes] = None
property has_private: bool
property is_extended: bool
private_key: Optional[bytes] = None
public_key: Optional[bytes] = None
exception keycard.commands.InvalidResponseError

Bases: KeyCardError

Raised when response parsing fails.

exception keycard.commands.InvalidStateError(message)

Bases: KeyCardError

Raised when a precondition is not met.

class keycard.commands.KeyExportOption(*values)

Bases: IntEnum

EXTENDED_PUBLIC = 2
PRIVATE_AND_PUBLIC = 0
PUBLIC_ONLY = 1
class keycard.commands.KeyPath(path, source=DerivationSource.MASTER)

Bases: object

MAX_COMPONENTS = 10
to_string()
Return type:

str

exception keycard.commands.NotSelectedError

Bases: KeyCardError

Raised when trying to use card before select().

class keycard.commands.SecureChannel(enc_key, mac_key, iv, authenticated=False)

Bases: object

SecureChannel manages a secure communication channel using AES encryption and MAC authentication.

enc_key

The AES encryption key for the session.

Type:

bytes

mac_key

The AES MAC key for message authentication.

Type:

bytes

iv

The initialization vector for AES operations.

Type:

bytes

authenticated

Indicates if the session is authenticated.

Type:

bool

authenticated: bool = False
enc_key: bytes
iv: bytes
mac_key: bytes
classmethod open(shared_secret, pairing_key, salt, seed_iv)

Opens a new SecureChannel using the provided cryptographic parameters.

Return type:

SecureChannel

Parameters:
  • shared_secret (bytes) – The shared secret used for key derivation.

  • pairing_key (bytes) – The pairing key used for key derivation.

  • salt (bytes) – The salt value used in the key derivation process.

  • seed_iv (bytes) – The initialization vector (IV) to seed the session.

Returns:

An instance of SecureChannel initialized with

derived encryption and MAC keys, and the provided IV.

Return type:

SecureChannel

unwrap_response(response)

Unwraps and verifies a secure channel response.

Return type:

tuple[bytes, int]

Parameters:

response (bytes) – The encrypted response bytes to unwrap.

Returns:

A tuple containing the decrypted plaintext

(excluding the status word) and the status word as an integer.

Return type:

tuple[bytes, int]

Raises:
  • ValueError – If the secure channel is not authenticated.

  • ValueError – If the response length is invalid.

  • ValueError – If the MAC verification fails.

  • ValueError – If the decrypted plaintext is too short to contain a status word.

wrap_apdu(cla, ins, p1, p2, data)

Wraps an APDU command with secure channel encryption and MAC.

Return type:

bytes

Parameters:
  • cla (int) – The APDU class byte.

  • ins (int) – The APDU instruction byte.

  • p1 (int) – The APDU parameter 1 byte.

  • p2 (int) – The APDU parameter 2 byte.

  • data (bytes) – The APDU data field to be encrypted.

Returns:

The wrapped APDU as a tuple

containing the class, instruction, parameter 1, parameter 2, and the concatenated MAC and encrypted data.

Return type:

tuple[int, int, int, int, bytes]

Raises:

ValueError – If the secure channel is not authenticated and the instruction is not 0x11.

class keycard.commands.SignatureResult(digest, algo, r, s, recovery_id=None, public_key=None)

Bases: object

algo: SigningAlgorithm
public_key: Optional[bytes] = None
r: bytes
recovery_id: Optional[int] = None
s: bytes
property signature: bytes
property signature_der: bytes
class keycard.commands.SigningAlgorithm(*values)

Bases: IntEnum

BLS12_381 = 2
ECDSA_SECP256K1 = 0
EDDSA_ED25519 = 1
SCHNORR_BIP340 = 3
class keycard.commands.SigningKey(_error__please_use_generate=None)

Bases: object

Class for handling keys that can create signatures (private keys).

Variables:
  • curve (Curve) – The Curve over which all the cryptographic operations will take place

  • default_hashfunc – the function that will be used for hashing the data. Should implement the same API as hashlib.sha1

  • baselen (int) – the length of a raw encoding of private key

  • verifying_key (VerifyingKey) – the public key associated with this private key

  • privkey (Private_key) – the actual private key

classmethod from_der(string, hashfunc=<built-in function openssl_sha1>, valid_curve_encodings=None)

Initialise from key stored in DER format.

The DER formats supported are the un-encrypted RFC5915 (the ssleay format) supported by OpenSSL, and the more common un-encrypted RFC5958 (the PKCS #8 format).

Both formats contain an ASN.1 object following the syntax specified in RFC5915:

ECPrivateKey ::= SEQUENCE {
  version        INTEGER { ecPrivkeyVer1(1) }} (ecPrivkeyVer1),
  privateKey     OCTET STRING,
  parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
  publicKey  [1] BIT STRING OPTIONAL
}

publicKey field is ignored completely (errors, if any, in it will be undetected).

Two formats are supported for the parameters field: the named curve and the explicit encoding of curve parameters. In the legacy ssleay format, this implementation requires the optional parameters field to get the curve name. In PKCS #8 format, the curve is part of the PrivateKeyAlgorithmIdentifier.

The PKCS #8 format includes an ECPrivateKey object as the privateKey field within a larger structure:

OneAsymmetricKey ::= SEQUENCE {
    version                   Version,
    privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
    privateKey                PrivateKey,
    attributes            [0] Attributes OPTIONAL,
    ...,
    [[2: publicKey        [1] PublicKey OPTIONAL ]],
    ...
}

The attributes and publicKey fields are completely ignored; errors in them will not be detected.

Parameters:
  • string (bytes-like object) – binary string with DER-encoded private ECDSA key

  • valid_curve_encodings (set-like object) – list of allowed encoding formats for curve parameters. By default (None) all are supported: named_curve and explicit. Ignored for EdDSA.

Raises:
  • MalformedPointError – if the length of encoding doesn’t match the provided curve or the encoded values is too large

  • RuntimeError – if the generation of public key from private key failed

  • UnexpectedDER – if the encoding of the DER file is incorrect

Returns:

Initialised SigningKey object

Return type:

SigningKey

classmethod from_pem(string, hashfunc=<built-in function openssl_sha1>, valid_curve_encodings=None)

Initialise from key stored in PEM format.

The PEM formats supported are the un-encrypted RFC5915 (the ssleay format) supported by OpenSSL, and the more common un-encrypted RFC5958 (the PKCS #8 format).

The legacy format files have the header with the string BEGIN EC PRIVATE KEY. PKCS#8 files have the header BEGIN PRIVATE KEY. Encrypted files (ones that include the string Proc-Type: 4,ENCRYPTED right after the PEM header) are not supported.

See from_der() for ASN.1 syntax of the objects in this files.

Parameters:
  • string (str) – text with PEM-encoded private ECDSA key

  • valid_curve_encodings (set-like object) – list of allowed encoding formats for curve parameters. By default (None) all are supported: named_curve and explicit.

Raises:
  • MalformedPointError – if the length of encoding doesn’t match the provided curve or the encoded values is too large

  • RuntimeError – if the generation of public key from private key failed

  • UnexpectedDER – if the encoding of the PEM file is incorrect

Returns:

Initialised SigningKey object

Return type:

SigningKey

classmethod from_secret_exponent(secexp, curve=NIST192p, hashfunc=<built-in function openssl_sha1>)

Create a private key from a random integer.

Note: it’s a low level method, it’s recommended to use the generate() method to create private keys.

Parameters:
  • secexp (int) – secret multiplier (the actual private key in ECDSA). Needs to be an integer between 1 and the curve order.

  • curve (Curve) – The curve on which the point needs to reside

  • hashfunc (callable) – The default hash function that will be used for signing, needs to implement the same interface as hashlib.sha1

Raises:
  • MalformedPointError – when the provided secexp is too large or too small for the curve selected

  • RuntimeError – if the generation of public key from private key failed

Returns:

Initialised SigningKey object

Return type:

SigningKey

classmethod from_string(string, curve=NIST192p, hashfunc=<built-in function openssl_sha1>)

Decode the private key from raw encoding.

Note: the name of this method is a misnomer coming from days of Python 2, when binary strings and character strings shared a type. In Python 3, the expected type is bytes.

Parameters:
  • string (bytes-like object) – the raw encoding of the private key

  • curve (Curve) – The curve on which the point needs to reside

  • hashfunc (callable) – The default hash function that will be used for signing, needs to implement the same interface as hashlib.sha1

Raises:
  • MalformedPointError – if the length of encoding doesn’t match the provided curve or the encoded values is too large

  • RuntimeError – if the generation of public key from private key failed

Returns:

Initialised SigningKey object

Return type:

SigningKey

classmethod generate(curve=NIST192p, entropy=None, hashfunc=<built-in function openssl_sha1>)

Generate a random private key.

Parameters:
  • curve (Curve) – The curve on which the point needs to reside, defaults to NIST192p

  • entropy (callable) – Source of randomness for generating the private keys, should provide cryptographically secure random numbers if the keys need to be secure. Uses os.urandom() by default.

  • hashfunc (callable) – The default hash function that will be used for signing, needs to implement the same interface as hashlib.sha1

Returns:

Initialised SigningKey object

Return type:

SigningKey

get_verifying_key()

Return the VerifyingKey associated with this private key.

Equivalent to reading the verifying_key field of an instance.

Returns:

a public key that can be used to verify the signatures made with this SigningKey

Return type:

VerifyingKey

sign(data, entropy=None, hashfunc=None, sigencode=<function sigencode_string>, k=None, allow_truncate=True)

Create signature over data.

Uses the probabilistic ECDSA algorithm for Weierstrass curves (NIST256p, etc.) and the deterministic EdDSA algorithm for the Edwards curves (Ed25519, Ed448).

This method uses the standard ECDSA algorithm that requires a cryptographically secure random number generator.

It’s recommended to use the sign_deterministic() method instead of this one.

Parameters:
  • data (bytes-like object) – data that will be hashed for signing

  • entropy (callable) – randomness source, os.urandom() by default. Ignored with EdDSA.

  • hashfunc (callable) – hash function to use for hashing the provided data. If unspecified the default hash function selected during object initialisation will be used (see VerifyingKey.default_hashfunc). Should behave like sha1() from hashlib. The output length of the hash (in bytes) must not be longer than the length of the curve order (rounded up to the nearest byte), so using SHA256 with NIST256p is ok, but SHA256 with NIST192p is not. (In the 2**-96ish unlikely event of a hash output larger than the curve order, the hash will effectively be wrapped mod n). If you want to explicitly allow use of large hashes with small curves set the allow_truncate to True. Use hashfunc=hashlib.sha1 to match openssl’s -ecdsa-with-SHA1 mode, or hashfunc=hashlib.sha256 for openssl-1.0.0’s -ecdsa-with-SHA256. Ignored for EdDSA

  • sigencode (callable) – function used to encode the signature. The function needs to accept three parameters: the two integers that are the signature and the order of the curve over which the signature was computed. It needs to return an encoded signature. See sigencode_string() and sigencode_der() as examples of such functions. Ignored for EdDSA

  • k (int) – a pre-selected nonce for calculating the signature. In typical use cases, it should be set to None (the default) to allow its generation from an entropy source. Ignored for EdDSA.

  • allow_truncate (bool) – if True, the provided digest can have bigger bit-size than the order of the curve, the extra bits (at the end of the digest) will be truncated. Use it when signing SHA-384 output using NIST256p or in similar situations. True by default. Ignored for EdDSA.

Raises:

RSZeroError – in the unlikely event when r parameter or s parameter of the created signature is equal 0, as that would leak the key. Caller should try a better entropy source, retry with different k, or use the sign_deterministic() in such case.

Returns:

encoded signature of the hash of data

Return type:

bytes or sigencode function dependent type

sign_deterministic(data, hashfunc=None, sigencode=<function sigencode_string>, extra_entropy=b'')

Create signature over data.

For Weierstrass curves it uses the deterministic RFC6979 algorithm. For Edwards curves it uses the standard EdDSA algorithm.

For ECDSA the data will be hashed using the hashfunc function before signing. For EdDSA the data will be hashed with the hash associated with the curve (SHA-512 for Ed25519 and SHAKE-256 for Ed448).

This is the recommended method for performing signatures when hashing of data is necessary.

Parameters:
  • data (bytes-like object) – data to be hashed and computed signature over

  • hashfunc (callable) – hash function to use for computing the signature, if unspecified, the default hash function selected during object initialisation will be used (see VerifyingKey.default_hashfunc). The object needs to implement the same interface as hashlib.sha1. Ignored with EdDSA.

  • sigencode (callable) – function used to encode the signature. The function needs to accept three parameters: the two integers that are the signature and the order of the curve over which the signature was computed. It needs to return an encoded signature. See ecdsa.util.sigencode_string and ecdsa.util.sigencode_der as examples of such functions. Ignored with EdDSA.

  • extra_entropy (bytes-like object) – additional data that will be fed into the random number generator used in the RFC6979 process. Entirely optional. Ignored with EdDSA.

Returns:

encoded signature over data

Return type:

bytes or sigencode function dependent type

sign_digest(digest, entropy=None, sigencode=<function sigencode_string>, k=None, allow_truncate=False)

Create signature over digest using the probabilistic ECDSA algorithm.

This method uses the standard ECDSA algorithm that requires a cryptographically secure random number generator.

This method does not hash the input.

It’s recommended to use the sign_digest_deterministic() method instead of this one.

Parameters:
  • digest (bytes-like object) – hash value that will be signed

  • entropy (callable) – randomness source, os.urandom by default

  • sigencode (callable) – function used to encode the signature. The function needs to accept three parameters: the two integers that are the signature and the order of the curve over which the signature was computed. It needs to return an encoded signature. See ecdsa.util.sigencode_string and ecdsa.util.sigencode_der as examples of such functions.

  • k (int) – a pre-selected nonce for calculating the signature. In typical use cases, it should be set to None (the default) to allow its generation from an entropy source.

  • allow_truncate (bool) – if True, the provided digest can have bigger bit-size than the order of the curve, the extra bits (at the end of the digest) will be truncated. Use it when signing SHA-384 output using NIST256p or in similar situations.

Raises:

RSZeroError – in the unlikely event when “r” parameter or “s” parameter of the created signature is equal 0, as that would leak the key. Caller should try a better entropy source, retry with different ‘k’, or use the sign_digest_deterministic() in such case.

Returns:

encoded signature for the digest hash

Return type:

bytes or sigencode function dependent type

sign_digest_deterministic(digest, hashfunc=None, sigencode=<function sigencode_string>, extra_entropy=b'', allow_truncate=False)

Create signature for digest using the deterministic RFC6979 algorithm.

digest should be the output of cryptographically secure hash function like SHA256 or SHA-3-256.

This is the recommended method for performing signatures when no hashing of data is necessary.

Parameters:
  • digest (bytes-like object) – hash of data that will be signed

  • hashfunc (callable) – hash function to use for computing the random “k” value from RFC6979 process, if unspecified, the default hash function selected during object initialisation will be used (see VerifyingKey.default_hashfunc). The object needs to implement the same interface as sha1() from hashlib.

  • sigencode (callable) – function used to encode the signature. The function needs to accept three parameters: the two integers that are the signature and the order of the curve over which the signature was computed. It needs to return an encoded signature. See sigencode_string() and sigencode_der() as examples of such functions.

  • extra_entropy (bytes-like object) – additional data that will be fed into the random number generator used in the RFC6979 process. Entirely optional.

  • allow_truncate (bool) – if True, the provided digest can have bigger bit-size than the order of the curve, the extra bits (at the end of the digest) will be truncated. Use it when signing SHA-384 output using NIST256p or in similar situations.

Returns:

encoded signature for the digest hash

Return type:

bytes or sigencode function dependent type

sign_number(number, entropy=None, k=None)

Sign an integer directly.

Note, this is a low level method, usually you will want to use sign_deterministic() or sign_digest_deterministic().

Parameters:
  • number (int) – number to sign using the probabilistic ECDSA algorithm.

  • entropy (callable) – entropy source, os.urandom by default

  • k (int) – pre-selected nonce for signature operation. If unset it will be selected at random using the entropy source.

Raises:

RSZeroError – in the unlikely event when “r” parameter or “s” parameter of the created signature is equal 0, as that would leak the key. Caller should try a better entropy source, retry with different ‘k’, or use the sign_digest_deterministic() in such case.

Returns:

the “r” and “s” parameters of the signature

Return type:

tuple of ints

to_der(point_encoding='uncompressed', format='ssleay', curve_parameters_encoding=None)

Convert the private key to the DER format.

See from_der() method for format specification.

Only the named curve format is supported. The public key will be included in the generated string.

Parameters:
  • point_encoding (str) – format to use for encoding public point Ignored for EdDSA

  • format (str) – either ssleay (default) or pkcs8. EdDSA keys require pkcs8.

  • curve_parameters_encoding (str) – format of encoded curve parameters, default depends on the curve, if the curve has an associated OID, named_curve format will be used, if no OID is associated with the curve, the fallback of explicit parameters will be used. Ignored for EdDSA.

Returns:

DER encoded private key

Return type:

bytes

to_pem(point_encoding='uncompressed', format='ssleay', curve_parameters_encoding=None)

Convert the private key to the PEM format.

See from_pem() method for format description.

Only the named curve format is supported. The public key will be included in generated string.

The PEM header will specify BEGIN EC PRIVATE KEY or BEGIN PRIVATE KEY, depending on the desired format.

Parameters:
  • point_encoding (str) – format to use for encoding public point

  • format (str) – either ssleay (default) or pkcs8

  • curve_parameters_encoding (str) – format of encoded curve parameters, default depends on the curve, if the curve has an associated OID, named_curve format will be used, if no OID is associated with the curve, the fallback of explicit parameters will be used.

Returns:

PEM encoded private key

Return type:

bytes

Warning

The PEM is encoded to US-ASCII, it needs to be re-encoded if the system is incompatible (e.g. uses UTF-16)

to_ssh()

Convert the private key to the SSH format.

Returns:

SSH encoded private key

Return type:

bytes

to_string()

Convert the private key to raw encoding.

Note: while the method is named “to_string”, its name comes from Python 2 days, when binary and character strings used the same type. The type used in Python 3 is bytes.

Returns:

raw encoding of private key

Return type:

bytes

class keycard.commands.VerifyingKey(_error__please_use_generate=None)

Bases: object

Class for handling keys that can verify signatures (public keys).

Variables:
  • ~.curve (Curve) – The Curve over which all the cryptographic operations will take place

  • default_hashfunc (callable) – the function that will be used for hashing the data. Should implement the same API as hashlib.sha1

  • pubkey (Public_key) – the actual public key

classmethod from_der(string, hashfunc=<built-in function openssl_sha1>, valid_encodings=None, valid_curve_encodings=None)

Initialise the key stored in DER format.

The expected format of the key is the SubjectPublicKeyInfo structure from RFC5912 (for RSA keys, it’s known as the PKCS#1 format):

SubjectPublicKeyInfo {PUBLIC-KEY: IOSet} ::= SEQUENCE {
    algorithm        AlgorithmIdentifier {PUBLIC-KEY, {IOSet}},
    subjectPublicKey BIT STRING
}

Note: only public EC keys are supported by this method. The SubjectPublicKeyInfo.algorithm.algorithm field must specify id-ecPublicKey (see RFC3279).

Only the named curve encoding is supported, thus the SubjectPublicKeyInfo.algorithm.parameters field needs to be an object identifier. A sequence in that field indicates an explicit parameter curve encoding, this format is not supported. A NULL object in that field indicates an “implicitlyCA” encoding, where the curve parameters come from CA certificate, those, again, are not supported.

Parameters:
  • string (bytes-like object) – binary string with the DER encoding of public ECDSA key

  • valid_encodings (set-like object) – list of allowed point encodings. By default uncompressed, compressed, and hybrid. To read malformed files, include raw encoding with raw in the list.

  • valid_curve_encodings (set-like object) – list of allowed encoding formats for curve parameters. By default (None) all are supported: named_curve and explicit.

Returns:

Initialised VerifyingKey object

Return type:

VerifyingKey

classmethod from_pem(string, hashfunc=<built-in function openssl_sha1>, valid_encodings=None, valid_curve_encodings=None)

Initialise from public key stored in PEM format.

The PEM header of the key should be BEGIN PUBLIC KEY.

See the from_der() method for details of the format supported.

Note: only a single PEM object decoding is supported in provided string.

Parameters:
  • string (str) – text with PEM-encoded public ECDSA key

  • valid_encodings (set-like object) – list of allowed point encodings. By default uncompressed, compressed, and hybrid. To read malformed files, include raw encoding with raw in the list.

  • valid_curve_encodings (set-like object) – list of allowed encoding formats for curve parameters. By default (None) all are supported: named_curve and explicit.

Returns:

Initialised VerifyingKey object

Return type:

VerifyingKey

classmethod from_public_key_recovery(signature, data, curve, hashfunc=<built-in function openssl_sha1>, sigdecode=<function sigdecode_string>, allow_truncate=True)

Return keys that can be used as verifiers of the provided signature.

Tries to recover the public key that can be used to verify the signature, usually returns two keys like that.

Parameters:
  • signature (bytes-like object) – the byte string with the encoded signature

  • data (bytes-like object) – the data to be hashed for signature verification

  • curve (Curve) – the curve over which the signature was performed

  • hashfunc (callable) – The default hash function that will be used for verification, needs to implement the same interface as hashlib.sha1

  • sigdecode (callable) – Callable to define the way the signature needs to be decoded to an object, needs to handle signature as the first parameter, the curve order (an int) as the second and return a tuple with two integers, “r” as the first one and “s” as the second one. See ecdsa.util.sigdecode_string() and ecdsa.util.sigdecode_der() for examples.

  • allow_truncate (bool) – if True, the provided hashfunc can generate values larger than the bit size of the order of the curve, the extra bits (at the end of the digest) will be truncated.

Returns:

Initialised VerifyingKey objects

Return type:

list of VerifyingKey

classmethod from_public_key_recovery_with_digest(signature, digest, curve, hashfunc=<built-in function openssl_sha1>, sigdecode=<function sigdecode_string>, allow_truncate=False)

Return keys that can be used as verifiers of the provided signature.

Tries to recover the public key that can be used to verify the signature, usually returns two keys like that.

Parameters:
  • signature (bytes-like object) – the byte string with the encoded signature

  • digest (bytes-like object) – the hash value of the message signed by the signature

  • curve (Curve) – the curve over which the signature was performed

  • hashfunc (callable) – The default hash function that will be used for verification, needs to implement the same interface as hashlib.sha1

  • sigdecode (callable) – Callable to define the way the signature needs to be decoded to an object, needs to handle signature as the first parameter, the curve order (an int) as the second and return a tuple with two integers, “r” as the first one and “s” as the second one. See ecdsa.util.sigdecode_string() and ecdsa.util.sigdecode_der() for examples.

  • allow_truncate (bool) – if True, the provided hashfunc can generate values larger than the bit size of the order of the curve (and the length of provided digest), the extra bits (at the end of the digest) will be truncated.

Returns:

Initialised VerifyingKey object

Return type:

VerifyingKey

classmethod from_public_point(point, curve=NIST192p, hashfunc=<built-in function openssl_sha1>, validate_point=True)

Initialise the object from a Point object.

This is a low-level method, generally you will not want to use it.

Parameters:
  • point (AbstractPoint) – The point to wrap around, the actual public key

  • curve (Curve) – The curve on which the point needs to reside, defaults to NIST192p

  • hashfunc (callable) – The default hash function that will be used for verification, needs to implement the same interface as hashlib.sha1

Raises:

MalformedPointError – if the public point does not lay on the curve

Returns:

Initialised VerifyingKey object

Return type:

VerifyingKey

classmethod from_string(string, curve=NIST192p, hashfunc=<built-in function openssl_sha1>, validate_point=True, valid_encodings=None)

Initialise the object from byte encoding of public key.

The method does accept and automatically detect the type of point encoding used. It supports the raw encoding, uncompressed, compressed, and hybrid encodings. It also works with the native encoding of Ed25519 and Ed448 public keys (technically those are compressed, but encoded differently than in other signature systems).

Note, while the method is named “from_string” it’s a misnomer from Python 2 days when there were no binary strings. In Python 3 the input needs to be a bytes-like object.

Parameters:
  • string (bytes-like object) – single point encoding of the public key

  • curve (Curve) – the curve on which the public key is expected to lay

  • hashfunc (callable) – The default hash function that will be used for verification, needs to implement the same interface as hashlib.sha1. Ignored for EdDSA.

  • validate_point (bool) – whether to verify that the point lays on the provided curve or not, defaults to True. Ignored for EdDSA.

  • valid_encodings (set-like object) – list of acceptable point encoding formats, supported ones are: uncompressed, compressed, hybrid, and raw encoding (specified with raw name). All formats by default (specified with None). Ignored for EdDSA.

Raises:

MalformedPointError – if the public point does not lay on the curve or the encoding is invalid

Returns:

Initialised VerifyingKey object

Return type:

VerifyingKey

precompute(lazy=False)

Precompute multiplication tables for faster signature verification.

Calling this method will cause the library to precompute the scalar multiplication tables, used in signature verification. While it’s an expensive operation (comparable to performing as many signatures as the bit size of the curve, i.e. 256 for NIST256p) it speeds up verification 2 times. You should call this method if you expect to verify hundreds of signatures (or more) using the same VerifyingKey object.

Note: You should call this method only once, this method generates a new precomputation table every time it’s called.

Parameters:

lazy (bool) – whether to calculate the precomputation table now (if set to False) or if it should be delayed to the time of first use (when set to True)

to_der(point_encoding='uncompressed', curve_parameters_encoding=None)

Convert the public key to the DER format.

The format of the key is described in the from_der() method. This method supports only “named curve” encoding of keys.

Parameters:
  • point_encoding (str) – specification of the encoding format of public keys. “uncompressed” is most portable, “compressed” is smallest. “hybrid” is uncommon and unsupported by most implementations, it is as big as “uncompressed”.

  • curve_parameters_encoding (str) – the encoding for curve parameters to use, by default tries to use named_curve encoding, if that is not possible, falls back to explicit encoding.

Returns:

DER encoding of the public key

Return type:

bytes

to_pem(point_encoding='uncompressed', curve_parameters_encoding=None)

Convert the public key to the PEM format.

The PEM header of the key will be BEGIN PUBLIC KEY.

The format of the key is described in the from_der() method. This method supports only “named curve” encoding of keys.

Parameters:
  • point_encoding (str) – specification of the encoding format of public keys. “uncompressed” is most portable, “compressed” is smallest. “hybrid” is uncommon and unsupported by most implementations, it is as big as “uncompressed”.

  • curve_parameters_encoding (str) – the encoding for curve parameters to use, by default tries to use named_curve encoding, if that is not possible, falls back to explicit encoding.

Returns:

portable encoding of the public key

Return type:

bytes

Warning

The PEM is encoded to US-ASCII, it needs to be re-encoded if the system is incompatible (e.g. uses UTF-16)

to_ssh()

Convert the public key to the SSH format.

Returns:

SSH encoding of the public key

Return type:

bytes

to_string(encoding='raw')

Convert the public key to a byte string.

The method by default uses the raw encoding (specified by encoding=”raw”. It can also output keys in uncompressed, compressed and hybrid formats.

Remember that the curve identification is not part of the encoding so to decode the point using from_string(), curve needs to be specified.

Note: while the method is called “to_string”, it’s a misnomer from Python 2 days when character strings and byte strings shared type. On Python 3 the returned type will be bytes.

Returns:

raw encoding of the public key (public point) on the curve

Return type:

bytes

verify(signature, data, hashfunc=None, sigdecode=<function sigdecode_string>, allow_truncate=True)

Verify a signature made over provided data.

Will hash data to verify the signature.

By default expects signature in raw encoding. Can also be used to verify signatures in ASN.1 DER encoding by using ecdsa.util.sigdecode_der() as the sigdecode parameter.

Parameters:
  • signature (sigdecode method dependent) – encoding of the signature

  • data (bytes-like object) – data signed by the signature, will be hashed using hashfunc, if specified, or default hash function

  • hashfunc (callable) – The default hash function that will be used for verification, needs to implement the same interface as hashlib.sha1

  • sigdecode (callable) – Callable to define the way the signature needs to be decoded to an object, needs to handle signature as the first parameter, the curve order (an int) as the second and return a tuple with two integers, “r” as the first one and “s” as the second one. See ecdsa.util.sigdecode_string() and ecdsa.util.sigdecode_der() for examples.

  • allow_truncate (bool) – if True, the provided digest can have bigger bit-size than the order of the curve, the extra bits (at the end of the digest) will be truncated. Use it when verifying SHA-384 output using NIST256p or in similar situations. Defaults to True.

Raises:

BadSignatureError – if the signature is invalid or malformed

Returns:

True if the verification was successful

Return type:

bool

verify_digest(signature, digest, sigdecode=<function sigdecode_string>, allow_truncate=False)

Verify a signature made over provided hash value.

By default expects signature in raw encoding. Can also be used to verify signatures in ASN.1 DER encoding by using ecdsa.util.sigdecode_der() as the sigdecode parameter.

Parameters:
  • signature (sigdecode method dependent) – encoding of the signature

  • digest (bytes-like object) – raw hash value that the signature authenticates.

  • sigdecode (callable) – Callable to define the way the signature needs to be decoded to an object, needs to handle signature as the first parameter, the curve order (an int) as the second and return a tuple with two integers, “r” as the first one and “s” as the second one. See ecdsa.util.sigdecode_string() and ecdsa.util.sigdecode_der() for examples.

  • allow_truncate (bool) – if True, the provided digest can have bigger bit-size than the order of the curve, the extra bits (at the end of the digest) will be truncated. Use it when verifying SHA-384 output using NIST256p or in similar situations.

Raises:
  • BadSignatureError – if the signature is invalid or malformed

  • BadDigestError – if the provided digest is too big for the curve associated with this VerifyingKey and allow_truncate was not set

Returns:

True if the verification was successful

Return type:

bool

keycard.commands.aes_cbc_encrypt(key, iv, data, padding=True)
Return type:

bytes

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.generate_pairing_token(passphrase)
Return type:

bytes

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)

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.

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.parse(challenge, data)
Return type:

bytes

keycard.commands.remove_key(card)

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

Return type:

None

keycard.commands.require_initialized(func)
Return type:

Callable[[ParamSpec(P, bound= None)], TypeVar(R)]

keycard.commands.require_pin_verified(func)
Return type:

Callable[[ParamSpec(P, bound= None)], TypeVar(R)]

keycard.commands.require_secure_channel(func)
Return type:

Callable[[ParamSpec(P, bound= None)], TypeVar(R)]

keycard.commands.require_selected(func)
Return type:

Callable[[ParamSpec(P, bound= None)], TypeVar(R)]

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.sigdecode_der(sig_der, order)

Decoder for DER format of ECDSA signatures.

DER format of signature is one that uses the ASN.1 DER rules to encode it as a sequence of two integers:

Ecdsa-Sig-Value ::= SEQUENCE {
    r       INTEGER,
    s       INTEGER
}

It’s expected that this function will be used as as the sigdecode= parameter to the ecdsa.keys.VerifyingKey.verify() method.

Parameters:
  • sig_der (bytes like object) – encoded signature

  • order (int) – order of the curve over which the signature was computed

Raises:

UnexpectedDER – when the encoding of signature is invalid

Returns:

tuple with decoded r and s values of signature

Return type:

tuple of ints

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.urandom(size, /)

Return a bytes object containing random bytes suitable for cryptographic use.

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.