Data commands
GET CARD INFO / READ DATA
Request APDU (encrypted)
CLA |
INS |
P1 |
P2 |
LC |
Data |
|---|---|---|---|---|---|
|
|
Mode |
Selector |
— |
None (or MAC only) |
Preconditions: Secure Channel must be opened.
This command is the main data-retrieval interface of the card. Depending on the P1/P2 combination, it returns card-level metadata, user key slot information, or arbitrary user data pages. It is used after establishing a secure channel to inspect the card’s state and read back stored data.
P1/P2 combinations
P1 |
P2 |
Description |
|---|---|---|
|
|
Card info (name, email, signature counter) |
|
|
User key slot info (slot = P1) |
|
|
User data pages (page = P2-1) |
Response Data — P1=0, P2=0 (Card info)
When both P1 and P2 are zero, the card returns general identity and status information that was
set during initialization with the INIT command. This is useful to display the cardholder’s name
and email, check whether a key has been loaded, and monitor the signing activity through the
signature counter.
Field |
Size |
Description |
|---|---|---|
Key source info |
1B |
|
Name length |
1B |
Length of owner name |
Name |
0-20B |
Owner name (as set during |
Email length |
1B |
Length of owner email |
0-60B |
Owner email (as set during |
|
Signature counter |
4B |
Big-endian unsigned integer, incremented with each |
Response Data — P1=1-3, P2=0 (User key slot)
When P1 is set to a slot index (1–3) with P2=0, the card returns the description and public key stored in that user key slot. These were originally written with the ADD USER KEY command. This requires PIN verification or a successful challenge-response beforehand.
Field |
Size |
Description |
|---|---|---|
Info text |
64B |
User-provided description (fixed 64 bytes, as written by |
Public key |
65B or 256B |
EC R1 uncompressed (65B for slot 1/3) or RSA modulus (256B for slot 2) |
Response Data — P2=1-3 (User data pages)
When P2 is set to a page index (1–3), the card returns the user data stored on that page. Pages are written with the WRITE DATA command and can hold up to 1200 bytes each, for a total of 3600 bytes of user-defined storage. This also requires PIN or challenge-response.
Field |
Size |
Description |
|---|---|---|
User data |
0-1200B |
Data from the requested page |
Status Words
SW |
Description |
|---|---|
|
Success |
|
Secure channel not opened, or PIN/challenge not validated (required when P1>0 or P2>0) |
|
Invalid P1/P2 combination or user data slot out of range |
Note
When reading user data (P2>0), the command must be sent using the extended frame format header to receive data larger than 256 bytes. This is required by the ISO 7816 standard for long response payloads, even though the command frame itself is short.
GET HISTORY
Request APDU (encrypted)
CLA |
INS |
P1 |
P2 |
LC |
Data |
|---|---|---|---|---|---|
|
|
Slot |
|
— |
None (or MAC only) |
Preconditions: Secure Channel opened, PIN or challenge-response validated.
The card maintains a circular history buffer of the last 149 signing operations. Each entry records the value of the signature counter at the time of signing and the 32-byte hash that was signed. This allows the host application to audit past transactions and verify that the card’s signing history matches expected blockchain activity.
The history slot number is provided in P1 (0 to 148). Slot 0 is the most recent entry.
Response Data — 36 bytes
Field |
Size |
Description |
|---|---|---|
Signing counter |
4B |
Big-endian unsigned integer (counter value at time of signing) |
Signed hash |
32B |
The 32-byte hash that was signed in this transaction |
Status Words
SW |
Description |
|---|---|
|
Success |
|
Secure channel not opened or PIN/challenge not performed |
|
Invalid P1 (slot number out of range, must be 0–148) |
WRITE DATA
Request APDU (encrypted)
CLA |
INS |
P1 |
P2 |
LC |
Data |
|---|---|---|---|---|---|
|
|
Mode |
Page |
var |
MAC | Encrypted data |
Preconditions: Secure Channel opened, PIN or challenge-response validated.
This command writes data to one of two storage areas: the user data pages (P1=0) or the custom
bytes field (P1=1) that is returned in every SELECT response.
P1=0x00 — Write user data page
The card provides three pages of user-defined storage, each up to 1200 bytes, for a total of
3600 bytes. Pages are indexed by P2 (0 to 2) and must be written sequentially starting from
page 0. The total user data length is computed as (P2 x 1200) + data_size, meaning
that lower pages are considered fully written. The card verifies that previous pages were fully
written before allowing a higher page to be written; otherwise it returns 0x6985.
For example, writing 200 bytes with P2=1 sets the total user data length to 1400 bytes (1200 for page 0 + 200 for page 1). The data can later be read back with the READ DATA command.
Field |
Size |
Description |
|---|---|---|
User data |
1-1200B |
Data for this page |
P1=0x01 — Write custom bytes
The custom bytes are 16 bytes of public data that are returned in every SELECT response. They
can be used to provide personal hints about how to authenticate with the card, or to indicate
what is stored inside. Take care that anyone who has physical access to the card can freely read
these bytes.
By default, the custom bytes are set to 16 times 0x00.
Field |
Size |
Description |
|---|---|---|
Custom bytes |
16B |
Public data returned in every |
Status Words
SW |
Description |
|---|---|
|
Success |
|
PIN not validated, or previous pages not fully written (P1=0) |
|
Data length incorrect (>1200B for P1=0, or not exactly 16B for P1=1) |
|
P1 not 0 nor 1, or P2 out of range (0–2) |
|
Data too large (outside secure channel frame capacity) |
GET PUBKEY
Request APDU (encrypted, or plaintext for pinless/clear read)
CLA |
INS |
P1 |
P2 |
LC |
Data |
|---|---|---|---|---|---|
|
|
Derive |
Export |
var |
MAC | Encrypted path (or empty) |
Preconditions: Secure Channel opened, PIN or challenge-response validated (except pinless or clear public key read), key loaded.
This is the primary command for exporting public keys from the card. It can return the current key’s public key, the current derivation path, or a full BIP32 extended public key (xpub). It also supports on-the-fly derivation: the card computes the derived key from a given path without changing the card’s current derivation state, which is useful when the host needs a public key at a specific path for address generation without affecting the signing key.
P1 values
P1 |
Description |
|---|---|
|
Current key k1 |
|
Current key r1 |
|
Current key Ed25519 |
|
Derive with k1 (OR with bits 7-6 for derivation source) |
|
Derive with r1 (OR with bits 7-6 for derivation source) |
|
Derive with Ed25519 (OR with bits 7-6 for derivation source + derive flag) |
When using derivation (P1 LSB = 1), the source key can be selected by OR’ing P1 with the
same derivation source flags as the DERIVE KEY command:
Bits 7-6 =
00: derive from masterBits 7-6 =
01: derive from parentBits 7-6 =
10: derive from current
P2 values
P2 |
Description |
|---|---|
|
Read current derivation path |
|
Read public key |
|
Read extended public key (BIP32 xpub, P1 must be |
Request Data — P1=0x01/0x11/0x21 (derive, plaintext)
Field |
Size |
Description |
|---|---|---|
Path elements |
n x 4B |
32-bit big-endian integers (1 to 8 levels) |
When P1=0x00/0x10/0x20 with P2=0x00 or P2=0x01, no data is required.
Response Data — P2=0x00 (path)
Field |
Size |
Description |
|---|---|---|
Path elements |
n x 4B |
Current derivation path as 32-bit big-endian integers |
Response Data — P2=0x01 (public key)
Field |
Size |
Description |
|---|---|---|
Public key |
65B |
EC uncompressed point ( |
Response Data — P2=0x02 (extended public key)
The xpub export must first be enabled using SET PUB EXPORT (P1=0). By default this capability is disabled from factory and after reset.
The response approximately matches the binary serialization format defined in the BIP32 standard. The difference is the fingerprint is given as 32 bytes (the full SHA-256 of the parent key) instead of the standard 4 bytes — the host must apply an external RIPEMD-160 computation and take the first 4 bytes to obtain the final BIP32 fingerprint (except for the master key, which is all zeros). There is no checksum, as the data is not Base58-encoded.
Field |
Size |
Description |
|---|---|---|
Version |
4B |
BIP32 version bytes (default: BTC mainnet |
Depth |
1B |
Derivation depth |
Fingerprint |
32B |
Parent key fingerprint (needs external RIPEMD-160 to get 4B) |
Child number |
4B |
Child index |
Chain code |
32B |
BIP32 chain code |
Public key |
33B |
Compressed public key |
The xpub can only be read at depth >= 3, in compliance with the BIP44 standard (the first 3 levels are hardened). The first 4 version bytes can be changed on the fly by the host to match the target blockchain; the card always sends BTC mainnet version bytes by default.
The extended public key is useful for wallet software to derive the last account address levels outside the card, manage address changes for each transaction, compute payment addresses in advance, and scan the address chain — all without requiring the card for each derivation.
Pinless and clear read modes
The public key can be read without PIN or secure channel in two scenarios:
Pinless path: If a pinless path was set with SET PINLESS PATH, and the current derivation path starts with the EIP-1581 prefix (
m/43'/60'/1581'/...), the public key (P2=1) can be read without authentication. No derivation is allowed in this mode.Clear public key read: If enabled via SET PUB EXPORT (P1=1), the current public key (P1=0/0x10, P2=1) can be read without PIN or secure channel. This is designed for point-of-sale systems that need to read the card’s payment address via NFC tap. No derivation is allowed in this mode.
Note
Using the derive option (P1 LSB=1), the card expects a path in the data. There is no way to
derive with a null path within this command, so the master key cannot be read via live
derivation. If the master public key is needed, set it as the current key with DERIVE KEY
and then read the current key.
Status Words
SW |
Description |
|---|---|
|
Success |
|
Not initialized, no key loaded, PIN not verified, or xpub export disabled |
|
Malformed path |
|
Invalid P1/P2 combination (e.g. P2=2 with P1 != 0) |
|
Pinless path not set up, or clear read not allowed |
|
xpub requested at depth < 3 |
|
Pinless query but current path not in the allowed range |
|
Current key requested with data present, or derive requested without data |