keycard

package module
v4.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 16, 2026 License: MPL-2.0 Imports: 19 Imported by: 0

README

keycard-go

keycard-go is a set of Go packages for interacting with the Status Keycard, a secure NFC-based hardware wallet.

If you only need a CLI tool to initialize your card, check out keycard-cli.

Packages

Package Description
keycard Main API — CommandSet for card operations, secure channel, pairing
keycard/globalplatform GlobalPlatform commands — applet installation, SCP02 secure channel
keycard/apdu APDU command/response types and encoding
keycard/crypto Cryptographic utilities (ECDH, AES-CCM, HMAC, PBKDF2, zeroization)
keycard/derivationpath BIP32 derivation path parsing and encoding
keycard/identifiers AIDs and instance identifiers for Keycard, NDEF, Cash
keycard/tlv TLV encoding/decoding
keycard/types Shared types — Pairing, Signature, Bip32KeyPair, ApplicationInfo, etc.

Keycard Commands

Setup and Status
Command Method(s)
SELECT Select()
INIT Init(), InitWithSecret(), InitV2(), InitWithOptions()
FACTORY RESET FactoryReset()
GET STATUS GetStatus(), GetStatusApplication(), GetStatusKeyPath()
IDENTIFY Identify()
Secure Channel
Feature Details
V1 (pairing-based) OpenSecureChannel(), AutoOpenSecureChannel()
V2 (certificate-based, app ≥ 4.0) AutoOpenSecureChannel(), AutoPair()
Auto-detection SecureChannelVersion() — selected automatically after Select()
Mutual Authentication Performed automatically during channel open
Pairing (Secure Channel V1)
Command Method(s)
PAIR Pair() (legacy), AutoPairWithMode(), AutoPairWithSecret(), AutoPairWithSecretAndMode()
UNPAIR Unpair(index)
UNPAIR OTHERS UnpairOthers()
CHANGE PAIRING PASSWORD ChangePairingPassword()
Pairing modes P2PairAny, P2PairEphemeral, P2PairPersistent
PIN / PUK Management
Command Method(s)
VERIFY PIN VerifyPIN()
CHANGE PIN ChangePIN()
UNBLOCK PIN UnblockPIN(puk, newPIN)
CHANGE PUK ChangePUK()
Key Management
Command Method(s)
LOAD KEY (BIP32) LoadKeyBIP32(), LoadKeyBIP32OmitPublic()
LOAD KEY (Seed) LoadSeed()
LOAD KEY (LEE) LoadLEEKey()
DERIVE KEY DeriveKey(path)
GENERATE KEY GenerateKey()
GENERATE MNEMONIC GenerateMnemonic(checksumSize)
REMOVE KEY RemoveKey()
EXPORT KEY (BIP32) ExportKey(), ExportKeyExtended(), ExportKeyWithP2(), ExportCurrentKey()
EXPORT KEY (LEE) ExportLEEKey(keypath)
EXPORT KEY (BIP85) ExportBIP85(keypath, length)
Signing
Command Method(s) Algorithms
SIGN (current key) Sign(data) ECDSA, EdDSA/Ed25519, BLS12-381, BIP340 Schnorr
SIGN (derived path) SignWithPath(data, path), SignWithPathAndAlgo(data, path, algo) Same
SIGN (pinless) SignPinless(data) ECDSA
SET PINLESS PATH SetPinlessPath(path)
RESET PINLESS PATH ResetPinlessPath()

Sign algorithm constants: P2SignECDSA, P2SignEdDSAEd25519, P2SignBLS12_381, P2SignBIP340Schnorr.

Data Storage
Command Method(s)
STORE DATA StoreData(typ, data), StoreDataWithOffset(typ, data, offset)
GET DATA GetData(typ)
SET NDEF SetNDEF(ndef)
GET CHALLENGE GetChallenge(length)

Data type constants: P1StoreDataPublic, P1StoreDataNDEF, P1StoreDataCash.

GlobalPlatform (Applet Management)

Command Method(s)
SELECT globalplatform.NewCommandSelect(aid)
INITIALIZE UPDATE globalplatform.NewCommandInitializeUpdate(challenge)
EXTERNAL AUTHENTICATE globalplatform.NewCommandExternalAuthenticate(...)
GET RESPONSE globalplatform.NewCommandGetResponse(length)
DELETE globalplatform.NewCommandDelete(aid, p2)
INSTALL FOR LOAD globalplatform.NewCommandInstallForLoad(aid, sdaid)
INSTALL FOR INSTALL globalplatform.NewCommandInstallForInstall(pkgAID, appletAID, instanceAID, params)
SCP02 Secure Channel globalplatform.SCP02Wrapper, globalplatform.SecureChannel
Applet Loading globalplatform.NewLoadCommandStream(file)

Cash Application

Command Method(s)
SELECT CashCommandSet.Select()
SIGN CashCommandSet.Sign(data)

Secure Channel Versions

Version App Version Authentication Notes
V1 < 4.0 ECDH + pairing password (PBKDF2) Up to 5 persistent pairing slots
V2 ≥ 4.0 ECDH + X.509 certificate CA-trusted, no pairing password needed

V2 is auto-selected for app version ≥ 4.0. Use AutoOpenSecureChannel() and AutoPairWithMode() for version-agnostic code.

Documentation

Index

Constants

View Source
const (
	InsInit             = 0xFE
	InsFactoryReset     = 0xFD
	InsGetStatus        = 0xF2
	InsSetNDEF          = 0xF3 // Legacy SET_NDEF (app version <= 2.x)
	InsIdentify         = 0x14
	InsVerifyPIN        = 0x20
	InsChangePIN        = 0x21
	InsUnblockPIN       = 0x22
	InsLoadKey          = 0xD0
	InsDeriveKey        = 0xD1
	InsGenerateMnemonic = 0xD2
	InsRemoveKey        = 0xD3
	InsGenerateKey      = 0xD4
	InsSign             = 0xC0
	InsSetPinlessPath   = 0xC1
	InsExportKey        = 0xC2
	InsExportLEE        = 0xC3 // Export LEE key
	InsExportBIP85      = 0xC4 // Export BIP85 derived key
	InsGetData          = 0xCA
	InsStoreData        = 0xE2
	InsGetChallenge     = 0x84 // Get challenge

	// Secure Channel V1 INS codes.
	InsOpenSecureChannel    = 0x10
	InsMutuallyAuthenticate = 0x11
	InsPair                 = 0x12
	InsUnpair               = 0x13

	// Secure Channel V2 INS codes.
	InsSecuredAPDU = 0x18 // V2 encrypted command wrapper
)

Keycard applet INS codes.

View Source
const (
	P1ChangePinPIN           = 0x00
	P1ChangePinPUK           = 0x01
	P1ChangePinPairingSecret = 0x02
)

CHANGE_PIN P1 values.

View Source
const (
	P1GetStatusApplication = 0x00
	P1GetStatusKeyPath     = 0x01
)

GET_STATUS P1 values.

View Source
const (
	P1LoadKeyEC         = 0x01
	P1LoadKeyECExtended = 0x02
	P1LoadKeySeed       = 0x03
	P1LoadKeyLEE        = 0x04
)

LOAD_KEY P1 values.

View Source
const (
	P1DeriveKeyFromMaster  = 0x00
	P1DeriveKeyFromParent  = 0x40
	P1DeriveKeyFromCurrent = 0x80
)

DERIVE_KEY P1 source values.

View Source
const (
	P1SignCurrentKey           = 0x00
	P1SignDerive               = 0x01
	P1SignDeriveAndMakeCurrent = 0x02
	P1SignPinless              = 0x03
)

SIGN P1 values.

View Source
const (
	P2SignECDSA         = 0x00
	P2SignEdDSAEd25519  = 0x01
	P2SignBLS12_381     = 0x02
	P2SignBIP340Schnorr = 0x03
)

SIGN P2 algorithm values.

View Source
const (
	P1StoreDataPublic = 0x00
	P1StoreDataNDEF   = 0x01
	P1StoreDataCash   = 0x02
)

STORE_DATA P1 data type values.

View Source
const (
	P1ExportKeyCurrent              = 0x00
	P1ExportKeyDerive               = 0x01
	P1ExportKeyDeriveAndMakeCurrent = 0x02
)

EXPORT_KEY P1 values.

View Source
const (
	P2ExportKeyPrivateAndPublic = 0x00
	P2ExportKeyPublicOnly       = 0x01
	P2ExportKeyExtendedPublic   = 0x02
)

EXPORT_KEY P2 values.

View Source
const (
	P1PairingFirstStep = 0x00
	P1PairingFinalStep = 0x01
)

PAIR P1 values.

View Source
const (
	P2PairAny        = 0x00
	P2PairEphemeral  = 0x01
	P2PairPersistent = 0x02
)

PAIR P2 mode values.

View Source
const (
	P1FactoryResetMagic = 0xAA
	P2FactoryResetMagic = 0x55
)

FACTORY_RESET magic values.

View Source
const (
	P1GenerateMnemonicWords12 = 0x04 // 12 words (128 bits entropy)
	P1GenerateMnemonicWords15 = 0x05 // 15 words (160 bits entropy)
	P1GenerateMnemonicWords18 = 0x06 // 18 words (192 bits entropy)
	P1GenerateMnemonicWords21 = 0x07 // 21 words (224 bits entropy)
	P1GenerateMnemonicWords24 = 0x08 // 24 words (256 bits entropy)
)

GENERATE_MNEMONIC P1 word count values.

View Source
const (
	AppStatusInitialized = 0x10 // App is initialized
	AppStatusLEEMode     = 0x20 // App is in LEE mode
)

App status flag bits.

View Source
const (
	SwSecurityConditionNotSatisfied uint16 = 0x6982
	SwAuthenticationMethodBlocked   uint16 = 0x6983
	SwCardLocked                    uint16 = 0x6283
	SwReferencedDataNotFound        uint16 = 0x6A88
	SwConditionsOfUseNotSatisfied   uint16 = 0x6985
	SwWrongPINMask                  uint16 = 0x63C0
)
View Source
const BIP32HMACKey = "Bitcoin seed"

BIP32HMACKey is the HMAC key used for BIP32 master key derivation.

Deprecated: Use globalplatform.ClaGp.

View Source
const KeycardDefaultInstanceIdx = 1

KeycardDefaultInstanceIdx is the default instance index for Keycard.

View Source
const MnemonicPBKDF2Iterations = 2048

MnemonicPBKDF2Iterations is the number of PBKDF2 iterations for mnemonic seed derivation.

View Source
const MnemonicSeedPrefix = "mnemonic"

MnemonicSeedPrefix is the BIP39 mnemonic seed derivation prefix.

View Source
const NDEFMaxChunkSize = 220

NDEFMaxChunkSize is the maximum NDEF chunk size for storage (220 bytes).

View Source
const PairingMaxClientCount = 5

PairingMaxClientCount is the maximum number of pairing slots on the card.

View Source
const PairingPasswordSalt = "Keycard Pairing Password Salt"

PairingPasswordSalt is the salt used for deriving the pairing secret.

View Source
const SwNoAvailablePairingSlots = 0x6A84

SwNoAvailablePairingSlots is the status word returned when no pairing slots are available.

Variables

View Source
var DefaultCAPublicKey = [33]byte{
	0x02,
	0x9a, 0xb9, 0x9e, 0xe1, 0xe7, 0xa7, 0x1b,
	0xdf, 0x45, 0xb3, 0xf9, 0xc5, 0x8c, 0x99,
	0x86, 0x6f, 0xf1, 0x29, 0x4d, 0x2c, 0x1e,
	0x30, 0x4e, 0x22, 0x8a, 0x86, 0xe1, 0x0c,
	0x33, 0x43, 0x50, 0x1c,
}

DefaultCAPublicKey is the default Status CA public key (compressed secp256k1, 33 bytes).

View Source
var ErrBadChecksumSize = errors.New("bad checksum size")
View Source
var ErrNoAvailablePairingSlots = errors.New("no available pairing slots")
View Source
var KeycardAID = []byte{0xA0, 0x00, 0x00, 0x08, 0x04, 0x00, 0x01, 0x01}

KeycardAID is the AID for the Keycard applet.

View Source
var NDEFAID = []byte{0xA0, 0x00, 0x00, 0x08, 0x04, 0x00, 0x01, 0x02}

NDEFAID is the AID for NDEF.

View Source
var NDEFInstanceAID = []byte{0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01}

NDEFInstanceAID is the NDEF instance AID.

View Source
var PackageAID = []byte{0xA0, 0x00, 0x00, 0x08, 0x04, 0x00, 0x01}

PackageAID is the AID for the Keycard package.

Functions

func CheckAuthOK

func CheckAuthOK(resp *apdu.Response) error

CheckAuthOK checks the response status word, handling the 0x63Cx PIN retry mask to return a WrongPINError with the remaining attempt count.

func KeycardInstanceAID

func KeycardInstanceAID(instanceIdx uint8) []byte

KeycardInstanceAID returns the instance AID for a specific Keycard instance. Panics if instanceIdx is 0.

func NewCommandChangePIN

func NewCommandChangePIN(pin string) *apdu.Command

func NewCommandChangePUK

func NewCommandChangePUK(puk string) *apdu.Command

func NewCommandChangePairingSecret

func NewCommandChangePairingSecret(secret []byte) *apdu.Command

func NewCommandDeriveKey

func NewCommandDeriveKey(pathStr string) (*apdu.Command, error)

func NewCommandExportBIP85

func NewCommandExportBIP85(length uint8, path []byte) *apdu.Command

NewCommandExportBIP85 builds an EXPORT BIP85 command.

func NewCommandExportKey

func NewCommandExportKey(p1 uint8, p2 uint8, pathStr string) (*apdu.Command, error)

Export a key

 @param {p1}
		0x00: current key - returns the key that is currently loaded and ready for signing. Does not use derivation path
		0x01: derive - returns derived key
		0x02: derive and make current - returns derived key and also sets it to the current key
 @param {p2}
		0x00: return public and private key pair
		0x01: return only the public key
		0x02: return extended public key
 @param {pathStr}
		Derivation path of format "m/x/x/x/x/x", e.g. "m/44'/0'/0'/0/0"

func NewCommandExportLEE

func NewCommandExportLEE(source uint8, path []byte) *apdu.Command

NewCommandExportLEE builds an EXPORT LEE command.

func NewCommandFactoryReset

func NewCommandFactoryReset() *apdu.Command

func NewCommandGenerateKey

func NewCommandGenerateKey() *apdu.Command

func NewCommandGenerateMnemonic

func NewCommandGenerateMnemonic(checksumSize byte) *apdu.Command

func NewCommandGetChallenge

func NewCommandGetChallenge(length uint8) *apdu.Command

NewCommandGetChallenge builds a GET CHALLENGE command.

func NewCommandGetData

func NewCommandGetData(typ uint8) *apdu.Command

func NewCommandGetStatus

func NewCommandGetStatus(p1 uint8) *apdu.Command

func NewCommandIdentify

func NewCommandIdentify(challenge []byte) *apdu.Command

func NewCommandInit

func NewCommandInit(data []byte) *apdu.Command

func NewCommandLoadKeyBIP32

func NewCommandLoadKeyBIP32(includePublic bool, keyTLV []byte) *apdu.Command

NewCommandLoadKeyBIP32 builds a LOAD KEY command with a BIP32 keypair TLV.

func NewCommandLoadLEEKey

func NewCommandLoadLEEKey(seed []byte) *apdu.Command

NewCommandLoadLEEKey builds a LOAD KEY command for LEE mode (P1 = 0x04).

func NewCommandLoadSeed

func NewCommandLoadSeed(seed []byte) *apdu.Command

func NewCommandMutuallyAuthenticate

func NewCommandMutuallyAuthenticate(data []byte) *apdu.Command

func NewCommandOpenSecureChannel

func NewCommandOpenSecureChannel(pairingIndex uint8, pubKey []byte) *apdu.Command

func NewCommandPairFinalStep

func NewCommandPairFinalStep(cryptogramHash []byte) *apdu.Command

func NewCommandPairFirstStep

func NewCommandPairFirstStep(challenge []byte) *apdu.Command

func NewCommandRemoveKey

func NewCommandRemoveKey() *apdu.Command

func NewCommandSetPinlessPath

func NewCommandSetPinlessPath(pathStr string) (*apdu.Command, error)

func NewCommandSign

func NewCommandSign(data []byte, p1, p2 uint8, pathStr string) (*apdu.Command, error)

func NewCommandStoreData

func NewCommandStoreData(typ uint8, data []byte) *apdu.Command

func NewCommandStoreDataWithOffset

func NewCommandStoreDataWithOffset(typ uint8, data []byte, offset uint16) *apdu.Command

NewCommandStoreDataWithOffset builds a STORE DATA command with an explicit offset. Offset must be a multiple of 4; P1 encodes offset/4.

func NewCommandUnblockPIN

func NewCommandUnblockPIN(puk string, newPIN string) *apdu.Command

func NewCommandUnpair

func NewCommandUnpair(index uint8) *apdu.Command

func NewCommandVerifyPIN

func NewCommandVerifyPIN(pin string) *apdu.Command

func PairingPasswordToSecret

func PairingPasswordToSecret(password string) []byte

PairingPasswordToSecret converts a pairing password to a binary pairing secret via PBKDF2-HMAC-SHA256.

Types

type APDUError

type APDUError struct {
	SW      uint16
	Message string
}

APDUError represents an APDU-level error with a status word.

func AuthenticationMethodBlocked

func AuthenticationMethodBlocked(sw uint16) *APDUError

AuthenticationMethodBlocked returns an APDUError for the authentication method blocked status word.

func SecurityConditionNotSatisfied

func SecurityConditionNotSatisfied(sw uint16) *APDUError

SecurityConditionNotSatisfied returns an APDUError for the security condition not satisfied status word.

func UnexpectedSW

func UnexpectedSW(sw uint16, message string) *APDUError

UnexpectedSW returns an APDUError for an unexpected status word.

func (*APDUError) Error

func (e *APDUError) Error() string

Error implements the error interface.

type CashCommandSet

type CashCommandSet struct {
	CashApplicationInfo *types.CashApplicationInfo
	// contains filtered or unexported fields
}

func NewCashCommandSet

func NewCashCommandSet(c types.Channel) *CashCommandSet

func (*CashCommandSet) Select

func (cs *CashCommandSet) Select() error

func (*CashCommandSet) Sign

func (cs *CashCommandSet) Sign(data []byte) (*types.Signature, error)

func (*CashCommandSet) SignWithAlgo

func (cs *CashCommandSet) SignWithAlgo(data []byte, algo uint8) (*types.Signature, error)

type CommandSet

type CommandSet struct {
	ApplicationInfo *types.ApplicationInfo
	// contains filtered or unexported fields
}

CommandSet is the main API for interacting with a Status Keycard.

The secure channel version (V1 or V2) is auto-detected based on the applet version after the first Select() call.

func NewCommandSet

func NewCommandSet(c types.Channel) *CommandSet

NewCommandSet creates a CommandSet using the given APDU channel.

Uses the default Status CA public key for V2 certificate verification.

func NewCommandSetWithCA

func NewCommandSetWithCA(c types.Channel, caPublicKey [33]byte) *CommandSet

NewCommandSetWithCA creates a CommandSet with a single trusted CA public key.

func NewCommandSetWithCAs

func NewCommandSetWithCAs(c types.Channel, caPublicKeys, whitelistedCardKeys [][33]byte) *CommandSet

NewCommandSetWithCAs creates a CommandSet with custom trusted CA keys and optionally whitelisted card identity keys.

func (*CommandSet) AppInfo

func (cs *CommandSet) AppInfo() *types.ApplicationInfo

AppInfo returns the application info from the last SELECT command.

func (*CommandSet) AutoOpenSecureChannel

func (cs *CommandSet) AutoOpenSecureChannel() error

AutoOpenSecureChannel opens the secure channel using the auto-detected version.

func (*CommandSet) AutoPairWithMode

func (cs *CommandSet) AutoPairWithMode(pairingPass string, mode uint8) error

AutoPairWithMode pairs the card using a pairing password with explicit mode.

func (*CommandSet) AutoPairWithSecret

func (cs *CommandSet) AutoPairWithSecret(sharedSecret []byte) error

AutoPairWithSecret pairs the card using a raw binary shared secret.

func (*CommandSet) AutoPairWithSecretAndMode

func (cs *CommandSet) AutoPairWithSecretAndMode(sharedSecret []byte, mode uint8) error

AutoPairWithSecretAndMode pairs the card using a raw binary shared secret with explicit mode.

func (*CommandSet) ChangePIN

func (cs *CommandSet) ChangePIN(pin string) error

ChangePIN changes the user PIN.

func (*CommandSet) ChangePUK

func (cs *CommandSet) ChangePUK(puk string) error

ChangePUK changes the PUK.

func (*CommandSet) ChangePairingPassword

func (cs *CommandSet) ChangePairingPassword(password string) error

ChangePairingPassword changes the pairing password.

func (*CommandSet) ChangePairingSecret deprecated

func (cs *CommandSet) ChangePairingSecret(password string) error

ChangePairingSecret changes the pairing secret (legacy, uses PBKDF2 from secrets.go).

Deprecated: use ChangePairingPassword instead.

func (*CommandSet) DeriveKey

func (cs *CommandSet) DeriveKey(path string) error

DeriveKey derives a key at the given BIP32 path.

func (*CommandSet) ExportBIP85

func (cs *CommandSet) ExportBIP85(keypath string, length uint8) ([]byte, error)

ExportBIP85 exports a BIP85 derived key at the given path.

func (*CommandSet) ExportCurrentKey

func (cs *CommandSet) ExportCurrentKey(publicOnly bool) (*types.ExportedKey, error)

ExportCurrentKey exports the current key.

func (*CommandSet) ExportKey deprecated

func (cs *CommandSet) ExportKey(derive bool, makeCurrent bool, onlyPublic bool, path string) ([]byte, []byte, error)

ExportKey exports a key at the given path.

Deprecated: use ExportKeyExtended for the new API.

func (*CommandSet) ExportKeyExtended

func (cs *CommandSet) ExportKeyExtended(derive bool, makeCurrent bool, p2 uint8, path string) (*types.ExportedKey, error)

ExportKeyExtended exports a key at the given path with explicit P2.

func (*CommandSet) ExportKeyWithP2

func (cs *CommandSet) ExportKeyWithP2(derive, makeCurrent bool, p2 uint8, path string) (*types.ExportedKey, error)

ExportKeyWithP2 exports a key at the given path with explicit P2.

func (*CommandSet) ExportLEEKey

func (cs *CommandSet) ExportLEEKey(keypath string) ([]byte, error)

ExportLEEKey exports an LEE key at the given BIP32 path.

func (*CommandSet) FactoryReset

func (cs *CommandSet) FactoryReset() error

FactoryReset sends the FACTORY RESET command (unencrypted).

func (*CommandSet) GenerateKey

func (cs *CommandSet) GenerateKey() ([]byte, error)

GenerateKey generates a new key on the card.

func (*CommandSet) GenerateMnemonic

func (cs *CommandSet) GenerateMnemonic(checksumSize int) ([]int, error)

GenerateMnemonic generates a mnemonic on the card.

func (*CommandSet) GetChallenge

func (cs *CommandSet) GetChallenge(length uint8) ([]byte, error)

GetChallenge requests a random challenge from the card.

func (*CommandSet) GetData

func (cs *CommandSet) GetData(typ uint8) ([]byte, error)

GetData retrieves stored data by type.

func (*CommandSet) GetStatus

func (cs *CommandSet) GetStatus(info uint8) (*types.ApplicationStatus, error)

GetStatus returns the application status for the given info type.

func (*CommandSet) GetStatusApplication

func (cs *CommandSet) GetStatusApplication() (*types.ApplicationStatus, error)

GetStatusApplication returns the application-level status.

func (*CommandSet) GetStatusKeyPath

func (cs *CommandSet) GetStatusKeyPath() (*types.ApplicationStatus, error)

GetStatusKeyPath returns the key-path status.

func (*CommandSet) Identify

func (cs *CommandSet) Identify() ([]byte, error)

Identify sends an IDENTIFY CARD command and verifies the card's identity.

func (*CommandSet) Init

func (cs *CommandSet) Init(secrets *Secrets) error

Init initializes the card with the given secrets.

For V1 cards, uses OneShotEncrypt (encrypt with ECDH secret, send as raw command). For V2 cards, opens the secure channel first then sends INIT as an encrypted command.

func (*CommandSet) InitV2

func (cs *CommandSet) InitV2(pin, puk string) error

InitV2 initializes the card without a pairing password (V2 only).

Secure Channel V2 does not use a shared secret for pairing, so this convenience method initializes the card with an empty shared secret. For V1 cards, use Init or InitWithSecret instead.

func (*CommandSet) InitWithOptions

func (cs *CommandSet) InitWithOptions(pin, altPin, puk, pairingPass string, pinRetries, pukRetries uint8) error

InitWithOptions initializes the card with optional alt PIN and retry counts.

func (*CommandSet) InitWithOptionsV2

func (cs *CommandSet) InitWithOptionsV2(pin, altPin, puk string, pinRetries, pukRetries uint8) error

InitWithOptionsV2 initializes the card with optional alt PIN and retry counts.

func (*CommandSet) InitWithSecret

func (cs *CommandSet) InitWithSecret(pin, puk string, sharedSecret []byte) error

InitWithSecret initializes the card with a raw shared secret.

func (*CommandSet) LoadKeyBIP32

func (cs *CommandSet) LoadKeyBIP32(keyPair *types.Bip32KeyPair) error

LoadKeyBIP32 loads a BIP32 keypair onto the card (includes public key).

func (*CommandSet) LoadKeyBIP32OmitPublic

func (cs *CommandSet) LoadKeyBIP32OmitPublic(keyPair *types.Bip32KeyPair) error

LoadKeyBIP32OmitPublic loads a BIP32 keypair onto the card (omits public key).

func (*CommandSet) LoadLEEKey

func (cs *CommandSet) LoadLEEKey(seed []byte) error

LoadLEEKey loads an LEE seed onto the card.

func (*CommandSet) LoadSeed

func (cs *CommandSet) LoadSeed(seed []byte) ([]byte, error)

LoadSeed loads a BIP32 seed onto the card.

func (*CommandSet) OpenSecureChannel

func (cs *CommandSet) OpenSecureChannel() error

OpenSecureChannel opens the secure channel using V1 pairing-based flow.

For V2 cards, use AutoOpenSecureChannel instead.

func (*CommandSet) Pair deprecated

func (cs *CommandSet) Pair(pairingPass string) error

Pair pairs the card using a pairing password (V1 only, legacy PBKDF2-based flow).

Deprecated: use AutoPairWithMode for new code.

func (*CommandSet) Pairing

func (cs *CommandSet) Pairing() *types.Pairing

Pairing returns the current pairing data (V1 only, nil for V2).

func (*CommandSet) RemoveKey

func (cs *CommandSet) RemoveKey() error

RemoveKey removes the current key from the card.

func (*CommandSet) ResetPinlessPath

func (cs *CommandSet) ResetPinlessPath() error

ResetPinlessPath clears the pinless signing path.

func (*CommandSet) SecureChannelVersion

func (cs *CommandSet) SecureChannelVersion() (SecureChannelVersion, bool)

SecureChannelVersion returns the secure channel version in use.

Returns (VersionV1, true) or (VersionV2, true) if secure channel is supported, or (VersionV1, false) if the applet has not been selected yet.

func (*CommandSet) Select

func (cs *CommandSet) Select() error

Select selects the default instance (index 1) of the Keycard applet.

Parses the response as ApplicationInfo and auto-selects the correct secure channel version (V1 or V2) based on applet version.

func (*CommandSet) SetNDEF

func (cs *CommandSet) SetNDEF(ndef []byte) error

SetNDEF sets the NDEF message on the card.

For app version > 2.x, data is chunked and stored via STORE_DATA. For app version <= 2.x, data is sent directly via the legacy SET_NDEF command.

func (*CommandSet) SetPairing

func (cs *CommandSet) SetPairing(p *types.Pairing)

SetPairing sets the pairing data (V1 only, no-op for V2).

func (*CommandSet) SetPinlessPath

func (cs *CommandSet) SetPinlessPath(path string) error

SetPinlessPath sets the pinless signing path.

func (*CommandSet) Sign

func (cs *CommandSet) Sign(data []byte) (*types.Signature, error)

Sign signs a 32-byte hash with the current key (ECDSA).

func (*CommandSet) SignPinless

func (cs *CommandSet) SignPinless(data []byte) (*types.Signature, error)

SignPinless signs using the pinless path (no secure channel needed).

func (*CommandSet) SignWithPath

func (cs *CommandSet) SignWithPath(data []byte, path string) (*types.Signature, error)

SignWithPath signs a 32-byte hash with a derived key path (ECDSA).

func (*CommandSet) SignWithPathAndAlgo

func (cs *CommandSet) SignWithPathAndAlgo(data []byte, path string, algo uint8) (*types.Signature, error)

SignWithPathAndAlgo signs a 32-byte hash with a derived key path and explicit algorithm.

func (*CommandSet) StoreData

func (cs *CommandSet) StoreData(typ uint8, data []byte) error

StoreData stores data by type at offset 0.

func (*CommandSet) StoreDataWithOffset

func (cs *CommandSet) StoreDataWithOffset(typ uint8, data []byte, offset uint16) error

StoreDataWithOffset stores data by type at an explicit offset. Offset must be a multiple of 4.

func (*CommandSet) UnblockPIN

func (cs *CommandSet) UnblockPIN(puk string, newPIN string) error

UnblockPIN unblocks the PIN using the PUK and a new PIN.

func (*CommandSet) Unpair

func (cs *CommandSet) Unpair(index uint8) error

Unpair removes a pairing by index (V1 only).

func (*CommandSet) UnpairOthers

func (cs *CommandSet) UnpairOthers() error

UnpairOthers unpairs all other clients (V1 only).

func (*CommandSet) VerifyPIN

func (cs *CommandSet) VerifyPIN(pin string) error

VerifyPIN verifies the user PIN.

type IdentCommandSet

type IdentCommandSet struct {
	// contains filtered or unexported fields
}

IdentCommandSet is the API for interacting with the Ident applet.

The Ident applet provides a simple signing interface without secure channel or PIN protection.

func NewIdentCommandSet

func NewIdentCommandSet(c types.Channel) *IdentCommandSet

NewIdentCommandSet creates an IdentCommandSet using the given APDU channel.

func (*IdentCommandSet) Select

func (cs *IdentCommandSet) Select() error

Select selects the default instance of the Ident applet.

func (*IdentCommandSet) StoreData

func (cs *IdentCommandSet) StoreData(data []byte) (*apdu.Response, error)

StoreData sends a STORE DATA APDU to the Ident applet.

type Secrets

type Secrets struct {
	// contains filtered or unexported fields
}

Secrets contains the secret data needed to pair a client with a card.

func GenerateSecrets

func GenerateSecrets() (*Secrets, error)

GenerateSecrets generate a new Secrets with random puk and pairing password.

func NewSecrets

func NewSecrets(pin, puk, pairingPass string) *Secrets

func (*Secrets) PairingPass

func (s *Secrets) PairingPass() string

PairingPass returns the pairing password string.

func (*Secrets) PairingToken

func (s *Secrets) PairingToken() []byte

PairingToken returns the pairing token generated from the random pairing password.

func (*Secrets) Pin

func (s *Secrets) Pin() string

Pin returns the pin string.

func (*Secrets) Puk

func (s *Secrets) Puk() string

Puk returns the puk string.

type SecureChannel

type SecureChannel interface {
	// AutoOpen performs the full handshake and opens the secure channel.
	AutoOpen(ch types.Channel) error

	// AutoPair performs the pairing procedure (V1 only).
	AutoPair(ch types.Channel, mode uint8, sharedSecret []byte) error

	// AutoUnpair unpairs the current paired key (V1 only).
	AutoUnpair(ch types.Channel) error

	// UnpairOthers unpairs all other clients (V1 only).
	UnpairOthers(ch types.Channel) error

	// OpenSecureChannel sends an OPEN SECURE CHANNEL APDU.
	OpenSecureChannel(ch types.Channel, index uint8, data []byte) (*apdu.Response, error)

	// MutuallyAuthenticate sends a MUTUALLY AUTHENTICATE APDU (V1 only).
	MutuallyAuthenticate(ch types.Channel) (*apdu.Response, error)

	// Pair sends a PAIR APDU (V1 only).
	Pair(ch types.Channel, p1, p2 uint8, data []byte) (*apdu.Response, error)

	// Unpair sends an UNPAIR APDU (V1 only).
	Unpair(ch types.Channel, p1 uint8) (*apdu.Response, error)

	// ProtectedCommand returns a command APDU with the secure channel wrapper
	// applied. Returns Err if the channel was previously established but is
	// not currently open — the caller must call AutoOpen again.
	ProtectedCommand(cla, ins, p1, p2 uint8, data []byte) (*apdu.Command, error)

	// Transmit sends a protected command APDU and unwraps the response.
	Transmit(ch types.Channel, cmd *apdu.Command) (*apdu.Response, error)

	// Pairing returns the current pairing data (V1 only, nil for V2).
	Pairing() *types.Pairing

	// SetPairing sets the pairing data (V1 only, no-op for V2).
	SetPairing(p *types.Pairing)

	// Reset resets the secure channel, invalidating the current session.
	Reset()

	// Version returns the protocol version of this secure channel.
	Version() SecureChannelVersion
}

SecureChannel is the common interface for Secure Channel V1 and V2.

Both implementations provide encrypted command/response transport. Methods that only apply to one version return an error on the other.

type SecureChannelV1

type SecureChannelV1 struct {
	// contains filtered or unexported fields
}

SecureChannelV1 implements the Secure Channel V1 protocol.

Uses AES-256-CBC with AES-CBC-MAC for encryption and authentication, with pairing-based key derivation via ECDH on secp256k1.

func NewSecureChannel

func NewSecureChannel(c types.Channel) *SecureChannelV1

NewSecureChannel creates a new SecureChannelV1.

func (*SecureChannelV1) AutoOpen

func (sc *SecureChannelV1) AutoOpen(ch types.Channel) error

AutoOpen performs the full V1 secure channel handshake: 1. Send OPEN_SECURE_CHANNEL with pairing index + client public key 2. Derive session keys from response 3. Perform mutual authentication

func (*SecureChannelV1) AutoPair

func (sc *SecureChannelV1) AutoPair(ch types.Channel, mode uint8, sharedSecret []byte) error

AutoPair performs the full V1 pairing procedure.

func (*SecureChannelV1) AutoUnpair

func (sc *SecureChannelV1) AutoUnpair(ch types.Channel) error

AutoUnpair unpairs the current paired key.

func (*SecureChannelV1) GenerateSecret

func (sc *SecureChannelV1) GenerateSecret(cardPubKeyData []byte) error

GenerateSecret generates an ephemeral ECDH key pair and computes the shared secret with the card's static public key.

func (*SecureChannelV1) Init

func (sc *SecureChannelV1) Init(iv, encKey, macKey []byte)

Init initializes the session keys directly (used by legacy OpenSecureChannel flow).

func (*SecureChannelV1) IsOpen

func (sc *SecureChannelV1) IsOpen() bool

IsOpen returns true if the session is currently active.

func (*SecureChannelV1) MutuallyAuthenticate

func (sc *SecureChannelV1) MutuallyAuthenticate(ch types.Channel) (*apdu.Response, error)

MutuallyAuthenticate sends a MUTUALLY AUTHENTICATE APDU with a random challenge.

func (*SecureChannelV1) OneShotEncrypt

func (sc *SecureChannelV1) OneShotEncrypt(secrets *Secrets) ([]byte, error)

OneShotEncrypt encrypts init data for the INIT command.

Uses the ECDH shared secret as the AES key with a random IV. Output format: [pub_key_len] || public_key || iv || encrypted_data

func (*SecureChannelV1) OpenSecureChannel

func (sc *SecureChannelV1) OpenSecureChannel(ch types.Channel, index uint8, data []byte) (*apdu.Response, error)

OpenSecureChannel sends an OPEN SECURE CHANNEL APDU.

func (*SecureChannelV1) Pair

func (sc *SecureChannelV1) Pair(ch types.Channel, p1, p2 uint8, data []byte) (*apdu.Response, error)

Pair sends a PAIR APDU.

func (*SecureChannelV1) Pairing

func (sc *SecureChannelV1) Pairing() *types.Pairing

Pairing returns the current pairing data.

func (*SecureChannelV1) ProtectedCommand

func (sc *SecureChannelV1) ProtectedCommand(cla, ins, p1, p2 uint8, data []byte) (*apdu.Command, error)

ProtectedCommand returns a command APDU with the V1 secure channel wrapper applied. If the channel is not open, returns the command as-is (plaintext). If the channel was previously established but is now closed, returns an error.

func (*SecureChannelV1) PublicKey

func (sc *SecureChannelV1) PublicKey() *ecdsa.PublicKey

PublicKey returns the client's ephemeral public key.

func (*SecureChannelV1) RawPublicKey

func (sc *SecureChannelV1) RawPublicKey() []byte

RawPublicKey returns the client's uncompressed public key (65 bytes).

func (*SecureChannelV1) Reset

func (sc *SecureChannelV1) Reset()

Reset resets the secure channel, invalidating the current session.

func (*SecureChannelV1) Secret

func (sc *SecureChannelV1) Secret() []byte

Secret returns the ECDH shared secret.

func (*SecureChannelV1) Send deprecated

func (sc *SecureChannelV1) Send(cmd *apdu.Command) (*apdu.Response, error)

Send is a convenience method that wraps ProtectedCommand + Transmit.

Deprecated: use ProtectedCommand + Transmit directly for new code.

func (*SecureChannelV1) SetPairing

func (sc *SecureChannelV1) SetPairing(p *types.Pairing)

SetPairing sets the pairing data.

func (*SecureChannelV1) Transmit

func (sc *SecureChannelV1) Transmit(ch types.Channel, cmd *apdu.Command) (*apdu.Response, error)

Transmit sends a command and decrypts the response.

func (*SecureChannelV1) Unpair

func (sc *SecureChannelV1) Unpair(ch types.Channel, p1 uint8) (*apdu.Response, error)

Unpair sends an UNPAIR APDU.

func (*SecureChannelV1) UnpairOthers

func (sc *SecureChannelV1) UnpairOthers(ch types.Channel) error

UnpairOthers unpairs all other clients (all pairing slots except the current one).

func (*SecureChannelV1) Version

func (sc *SecureChannelV1) Version() SecureChannelVersion

Version returns the secure channel protocol version.

type SecureChannelV2

type SecureChannelV2 struct {
	// contains filtered or unexported fields
}

SecureChannelV2 implements the Secure Channel V2 protocol.

Uses ECDHE on secp256k1 with HKDF-SHA256 key derivation and AES-128-CCM (T=8, L=13) for encrypted commands.

func NewSecureChannelV2

func NewSecureChannelV2(caPublicKeys, whitelistedCardKeys [][33]byte) *SecureChannelV2

NewSecureChannelV2 creates a new V2 secure channel with the given trusted CA keys and optionally whitelisted card identity keys.

func NewSecureChannelV2WithCA

func NewSecureChannelV2WithCA(caPublicKey [33]byte) *SecureChannelV2

NewSecureChannelV2WithCA creates a new V2 secure channel with a single CA key.

func (*SecureChannelV2) AutoOpen

func (sc *SecureChannelV2) AutoOpen(ch types.Channel) error

AutoOpen performs the full V2 secure channel handshake: 1. Generate ephemeral key pair and random salt 2. Send OPEN_SECURE_CHANNEL with salt + client public key 3. Process card response (ECDH + HKDF key derivation) 4. Verify card's ECDSA signature over handshake transcript

func (*SecureChannelV2) AutoPair

func (sc *SecureChannelV2) AutoPair(_ types.Channel, _ uint8, _ []byte) error

AutoPair returns an error: pairing is not supported in V2.

func (*SecureChannelV2) AutoUnpair

func (sc *SecureChannelV2) AutoUnpair(_ types.Channel) error

AutoUnpair returns an error: unpairing is not supported in V2.

func (*SecureChannelV2) IsCATrusted

func (sc *SecureChannelV2) IsCATrusted(caPub *[33]byte) bool

IsCATrusted checks if the given CA public key is trusted.

func (*SecureChannelV2) IsCardWhitelisted

func (sc *SecureChannelV2) IsCardWhitelisted(identPub *[33]byte) bool

IsCardWhitelisted checks if the given card identity public key is whitelisted.

func (*SecureChannelV2) IsOpen

func (sc *SecureChannelV2) IsOpen() bool

func (*SecureChannelV2) MutuallyAuthenticate

func (sc *SecureChannelV2) MutuallyAuthenticate(_ types.Channel) (*apdu.Response, error)

MutuallyAuthenticate returns an error: mutual auth is not a separate step in V2.

func (*SecureChannelV2) OpenSecureChannel

func (sc *SecureChannelV2) OpenSecureChannel(ch types.Channel, _ uint8, data []byte) (*apdu.Response, error)

OpenSecureChannel sends an OPEN SECURE CHANNEL APDU (V2).

func (*SecureChannelV2) Pair

func (sc *SecureChannelV2) Pair(_ types.Channel, _, _ uint8, _ []byte) (*apdu.Response, error)

Pair returns an error: pairing is not supported in V2.

func (*SecureChannelV2) Pairing

func (sc *SecureChannelV2) Pairing() *types.Pairing

func (*SecureChannelV2) ProtectedCommand

func (sc *SecureChannelV2) ProtectedCommand(cla, ins, p1, p2 uint8, data []byte) (*apdu.Command, error)

ProtectedCommand returns a command APDU with the V2 secure channel wrapper applied. If the channel is not open, returns the command as-is (plaintext). If the channel was previously established but is now closed, returns an error.

func (*SecureChannelV2) Reset

func (sc *SecureChannelV2) Reset()

func (*SecureChannelV2) SetCardCertificate

func (sc *SecureChannelV2) SetCardCertificate(certData []byte) error

SetCardCertificate parses the card's identity certificate and validates the CA public key against known anchors.

func (*SecureChannelV2) SetPairing

func (sc *SecureChannelV2) SetPairing(_ *types.Pairing)

func (*SecureChannelV2) Transmit

func (sc *SecureChannelV2) Transmit(ch types.Channel, cmd *apdu.Command) (*apdu.Response, error)

Transmit sends a command and decrypts the response.

func (*SecureChannelV2) Unpair

func (sc *SecureChannelV2) Unpair(_ types.Channel, _ uint8) (*apdu.Response, error)

Unpair returns an error: unpairing is not supported in V2.

func (*SecureChannelV2) UnpairOthers

func (sc *SecureChannelV2) UnpairOthers(_ types.Channel) error

UnpairOthers returns an error: unpairing is not supported in V2.

func (*SecureChannelV2) Version

func (sc *SecureChannelV2) Version() SecureChannelVersion

type SecureChannelVersion

type SecureChannelVersion int

SecureChannelVersion identifies which secure channel protocol is in use.

const (
	VersionV1 SecureChannelVersion = iota
	VersionV2
)

type WrongPINError

type WrongPINError struct {
	RemainingAttempts int
}

WrongPINError is returned when a PIN verification fails.

func (*WrongPINError) Error

func (e *WrongPINError) Error() string

type WrongPUKError

type WrongPUKError struct {
	RemainingAttempts int
}

WrongPUKError is returned when a PUK verification fails.

func (*WrongPUKError) Error

func (e *WrongPUKError) Error() string

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL