apdu

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Apr 12, 2026 License: MIT Imports: 5 Imported by: 6

README

APDU

CI codecov GoDoc Go Report Card

Package apdu implements encoding and decoding of Application Protocol Data Units (APDU) as defined in ISO 7816-4. Both standard and extended length APDUs are supported.

Install

go get github.com/skythen/apdu

Command APDU (Capdu)

Parse from bytes or hex string
c, err := apdu.ParseCapdu([]byte{0x80, 0xF2, 0xE0, 0x02, 0x02, 0x4F, 0x00, 0x00})

c, err := apdu.ParseCapduHexString("80F2E002024F0000")
Create from struct

Ne is the expected number of response bytes (not the encoded LE value).

c := apdu.Capdu{Cla: 0x00, Ins: 0xA4, P1: 0x04, P2: 0x00, Data: []byte{0xA0, 0x00, 0x00, 0x00, 0x03}, Ne: 256}
Convert to bytes or hex string

The APDU case and format (standard/extended) are determined automatically.

b, err := c.Bytes()
s, err := c.String()
Check extended length
if c.IsExtendedLength() {
    // len(Data) > 255 or Ne > 256
}

Response APDU (Rapdu)

Parse from bytes or hex string
r, err := apdu.ParseRapdu([]byte{0x01, 0x02, 0x03, 0x90, 0x00})

r, err := apdu.ParseRapduHexString("0102039000")
Create from struct
r := apdu.Rapdu{Data: []byte{0x01, 0x02, 0x03}, SW1: 0x90, SW2: 0x00}
Convert to bytes or hex string
b, err := r.Bytes()
s, err := r.String()
Check response status
r.IsSuccess() // SW1=0x61xx or SW1SW2=0x9000
r.IsWarning() // SW1=0x62xx or SW1=0x63xx
r.IsError()   // SW1=0x64xx, 0x65xx, or 0x67xx-0x6Fxx

Documentation

Overview

Package apdu implements parsing and conversion of Application Protocol Data Units (APDU) which is the communication format between a card and off-card applications. The format of the APDU is defined in ISO specification 7816-4. The package has support for extended length APDUs as well.

Index

Examples

Constants

View Source
const (
	// OffsetCla defines the offset to the Cla byte of a Capdu.
	OffsetCla int = 0
	// OffsetIns defines the offset to the Ins byte of a Capdu.
	OffsetIns int = 1
	// OffsetP1 defines the offset to the P1 byte of a Capdu.
	OffsetP1 int = 2
	// OffsetP2 defines the offset to the P2 byte of a Capdu.
	OffsetP2 int = 3
	// OffsetLcStandard defines the offset to the LC byte of a standard length Capdu.
	OffsetLcStandard int = 4
	// OffsetLcExtended defines the offset to the LC byte of an extended length Capdu.
	OffsetLcExtended int = 5
	// OffsetCdataStandard defines the offset to the beginning of the data field of a standard length Capdu.
	OffsetCdataStandard int = 5
	// OffsetCdataExtended defines the offset to the beginning of the data field of an extended length Capdu.
	OffsetCdataExtended int = 7
	// MaxLenCommandDataStandard defines the maximum command data length of a standard length Capdu.
	MaxLenCommandDataStandard int = 255
	// MaxLenResponseDataStandard defines the maximum response data length of a standard length RAPDU.
	MaxLenResponseDataStandard int = 256
	// MaxLenCommandDataExtended defines the maximum command data length of an extended length Capdu.
	MaxLenCommandDataExtended int = 65535
	// MaxLenResponseDataExtended defines the maximum response data length of an extended length RAPDU.
	MaxLenResponseDataExtended int = 65536
	// LenHeader defines the length of the header of an APDU.
	LenHeader int = 4
	// LenLCStandard defines the length of the LC of a standard length APDU.
	LenLCStandard int = 1
	// LenLCExtended defines the length of the LC of an extended length APDU.
	LenLCExtended int = 3
	// LenResponseTrailer defines the length of the trailer of a Response APDU.
	LenResponseTrailer int = 2
)

Variables

View Source
var (
	// ErrInvalidLength indicates that the input has an invalid length.
	ErrInvalidLength = errors.New("invalid length")
	// ErrInvalidLC indicates that the LC value does not match the data length.
	ErrInvalidLC = errors.New("invalid LC value")
	// ErrInvalidHex indicates that the hex string input is malformed.
	ErrInvalidHex = errors.New("invalid hex string")
	// ErrDataTooLong indicates that the data field exceeds the maximum allowed length.
	ErrDataTooLong = errors.New("data too long")
	// ErrNeTooLarge indicates that Ne exceeds the maximum allowed value.
	ErrNeTooLarge = errors.New("ne too large")
)

Functions

This section is empty.

Types

type Capdu

type Capdu struct {
	Cla  byte   // Cla is the class byte.
	Ins  byte   // Ins is the instruction byte.
	P1   byte   // P1 is the p1 byte.
	P2   byte   // P2 is the p2 byte.
	Data []byte // Data is the data field.
	Ne   int    // Ne is the total number of expected response data byte (not LE encoded).
}

Capdu is a Command APDU.

func ParseCapdu

func ParseCapdu(c []byte) (*Capdu, error)

ParseCapdu parses a Command APDU and returns a Capdu.

Example
package main

import (
	"fmt"

	"github.com/skythen/apdu"
)

func main() {
	c, err := apdu.ParseCapdu([]byte{0x80, 0xF2, 0xE0, 0x02, 0x02, 0x4F, 0x00, 0x00})
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("CLA: %02X, INS: %02X, P1: %02X, P2: %02X, Data: %X, Ne: %d\n",
		c.Cla, c.Ins, c.P1, c.P2, c.Data, c.Ne)
}
Output:
CLA: 80, INS: F2, P1: E0, P2: 02, Data: 4F00, Ne: 256
Example (ErrorHandling)
package main

import (
	"errors"
	"fmt"

	"github.com/skythen/apdu"
)

func main() {
	_, err := apdu.ParseCapdu([]byte{0x00, 0xA4})
	if errors.Is(err, apdu.ErrInvalidLength) {
		fmt.Println("invalid length")
	}
}
Output:
invalid length

func ParseCapduHexString

func ParseCapduHexString(s string) (*Capdu, error)

ParseCapduHexString decodes the hex-string representation of a Command APDU, calls ParseCapdu and returns a Capdu.

Example
package main

import (
	"fmt"

	"github.com/skythen/apdu"
)

func main() {
	c, err := apdu.ParseCapduHexString("80F2E002024F0000")
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("CLA: %02X, INS: %02X, P1: %02X, P2: %02X, Data: %X, Ne: %d\n",
		c.Cla, c.Ins, c.P1, c.P2, c.Data, c.Ne)
}
Output:
CLA: 80, INS: F2, P1: E0, P2: 02, Data: 4F00, Ne: 256

func (*Capdu) Bytes

func (c *Capdu) Bytes() ([]byte, error)

Bytes returns the byte representation of the Capdu.

Example
package main

import (
	"fmt"

	"github.com/skythen/apdu"
)

func main() {
	c := apdu.Capdu{Cla: 0x00, Ins: 0xA4, P1: 0x04, P2: 0x00, Data: []byte{0xA0, 0x00, 0x00, 0x00, 0x03}, Ne: 256}
	b, err := c.Bytes()
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("%X\n", b)
}
Output:
00A4040005A00000000300

func (*Capdu) IsExtendedLength

func (c *Capdu) IsExtendedLength() bool

IsExtendedLength returns true if the Capdu has extended length (len of Data > 65535 or Ne > 65536), else false.

Example
package main

import (
	"fmt"

	"github.com/skythen/apdu"
)

func main() {
	standard := apdu.Capdu{Cla: 0x00, Ins: 0xA4, P1: 0x04, P2: 0x00, Ne: 256}
	extended := apdu.Capdu{Cla: 0x00, Ins: 0xA4, P1: 0x04, P2: 0x00, Ne: 65536}
	fmt.Println(standard.IsExtendedLength())
	fmt.Println(extended.IsExtendedLength())
}
Output:
false
true

func (*Capdu) String

func (c *Capdu) String() (string, error)

String calls Bytes and returns the hex encoded string representation of the Capdu.

Example
package main

import (
	"fmt"

	"github.com/skythen/apdu"
)

func main() {
	c := apdu.Capdu{Cla: 0x00, Ins: 0xA4, P1: 0x04, P2: 0x00, Data: []byte{0xA0, 0x00, 0x00, 0x00, 0x03}}
	s, err := c.String()
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(s)
}
Output:
00A4040005A000000003

type Rapdu

type Rapdu struct {
	Data []byte // Data is the data field.
	SW1  byte   // SW1 is the first byte of a status word.
	SW2  byte   // SW2 is the second byte of a status word.
}

Rapdu is a Response APDU.

func ParseRapdu

func ParseRapdu(b []byte) (*Rapdu, error)

ParseRapdu parses a Response APDU and returns a Rapdu.

Example
package main

import (
	"fmt"

	"github.com/skythen/apdu"
)

func main() {
	r, err := apdu.ParseRapdu([]byte{0x01, 0x02, 0x03, 0x90, 0x00})
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("Data: %X, SW1: %02X, SW2: %02X\n", r.Data, r.SW1, r.SW2)
}
Output:
Data: 010203, SW1: 90, SW2: 00

func ParseRapduHexString

func ParseRapduHexString(s string) (*Rapdu, error)

ParseRapduHexString decodes the hex-string representation of a Response APDU, calls ParseRapdu and returns a Rapdu.

Example
package main

import (
	"fmt"

	"github.com/skythen/apdu"
)

func main() {
	r, err := apdu.ParseRapduHexString("0102039000")
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("Data: %X, SW1: %02X, SW2: %02X\n", r.Data, r.SW1, r.SW2)
}
Output:
Data: 010203, SW1: 90, SW2: 00

func (*Rapdu) Bytes

func (r *Rapdu) Bytes() ([]byte, error)

Bytes returns the byte representation of the RAPDU.

Example
package main

import (
	"fmt"

	"github.com/skythen/apdu"
)

func main() {
	r := apdu.Rapdu{Data: []byte{0x01, 0x02, 0x03}, SW1: 0x90, SW2: 0x00}
	b, err := r.Bytes()
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("%X\n", b)
}
Output:
0102039000

func (*Rapdu) IsError

func (r *Rapdu) IsError() bool

IsError returns true if the RAPDU indicates an error during the execution of a command ('0x64xx', '0x65xx' or from '0x67xx' to 0x6Fxx'), otherwise false.

Example
package main

import (
	"fmt"

	"github.com/skythen/apdu"
)

func main() {
	r := apdu.Rapdu{SW1: 0x6A, SW2: 0x82}
	fmt.Println(r.IsError())
}
Output:
true

func (*Rapdu) IsSuccess

func (r *Rapdu) IsSuccess() bool

IsSuccess returns true if the RAPDU indicates the successful execution of a command ('0x61xx' or '0x9000'), otherwise false.

Example
package main

import (
	"fmt"

	"github.com/skythen/apdu"
)

func main() {
	r := apdu.Rapdu{SW1: 0x90, SW2: 0x00}
	fmt.Println(r.IsSuccess())
}
Output:
true

func (*Rapdu) IsWarning

func (r *Rapdu) IsWarning() bool

IsWarning returns true if the RAPDU indicates the execution of a command with a warning ('0x62xx' or '0x63xx'), otherwise false.

Example
package main

import (
	"fmt"

	"github.com/skythen/apdu"
)

func main() {
	r := apdu.Rapdu{SW1: 0x62, SW2: 0x84}
	fmt.Println(r.IsWarning())
}
Output:
true

func (*Rapdu) String

func (r *Rapdu) String() (string, error)

String calls Bytes and returns the hex encoded string representation of the RAPDU.

Example
package main

import (
	"fmt"

	"github.com/skythen/apdu"
)

func main() {
	r := apdu.Rapdu{Data: []byte{0x01, 0x02, 0x03}, SW1: 0x90, SW2: 0x00}
	s, err := r.String()
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(s)
}
Output:
0102039000

Jump to

Keyboard shortcuts

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