add command and response structs

This commit is contained in:
Andrea Franz 2018-09-14 13:30:16 +02:00
parent c278c2b6b1
commit b2ef28fa0a
No known key found for this signature in database
GPG Key ID: 4F0D2F2D9DE7F29D
4 changed files with 175 additions and 0 deletions

60
apdu/command.go Normal file
View File

@ -0,0 +1,60 @@
package apdu
import (
"bytes"
"encoding/binary"
)
type Command struct {
Cla uint8
Ins uint8
P1 uint8
P2 uint8
Data []byte
Le uint8
}
func NewCommand(cla, ins, p1, p2 uint8, data []byte) *Command {
return &Command{
Cla: cla,
Ins: ins,
P1: p1,
P2: p2,
Data: data,
}
}
func (c *Command) serialize() ([]byte, error) {
buf := new(bytes.Buffer)
if err := binary.Write(buf, binary.BigEndian, c.Cla); err != nil {
return nil, err
}
if err := binary.Write(buf, binary.BigEndian, c.Ins); err != nil {
return nil, err
}
if err := binary.Write(buf, binary.BigEndian, c.P1); err != nil {
return nil, err
}
if err := binary.Write(buf, binary.BigEndian, c.P2); err != nil {
return nil, err
}
if len(c.Data) > 0 {
if err := binary.Write(buf, binary.BigEndian, uint8(len(c.Data))); err != nil {
return nil, err
}
if err := binary.Write(buf, binary.BigEndian, c.Data); err != nil {
return nil, err
}
}
if err := binary.Write(buf, binary.BigEndian, c.Le); err != nil {
return nil, err
}
return buf.Bytes(), nil
}

43
apdu/command_test.go Normal file
View File

@ -0,0 +1,43 @@
package apdu
import (
"encoding/hex"
"fmt"
"log"
"testing"
"github.com/stretchr/testify/assert"
)
func hexToBytes(s string) []byte {
b := make([]byte, hex.DecodedLen(len(s)))
_, err := hex.Decode(b, []byte(s))
if err != nil {
log.Fatal(err)
}
return b[:]
}
func bytesToHexWithSpaces(b []byte) string {
return fmt.Sprintf("% X", b)
}
func bytesToHex(b []byte) string {
return fmt.Sprintf("%X", b)
}
func TestNewCommand(t *testing.T) {
var cla uint8 = 0x80
var ins uint8 = 0x50
var p1 uint8 = 1
var p2 uint8 = 2
data := hexToBytes("84762336c5187fe8")
cmd := NewCommand(cla, ins, p1, p2, data)
expected := "80 50 01 02 08 84 76 23 36 C5 18 7F E8 00"
result, err := cmd.serialize()
assert.NoError(t, err)
assert.Equal(t, expected, bytesToHexWithSpaces(result))
}

46
apdu/response.go Normal file
View File

@ -0,0 +1,46 @@
package apdu
import (
"bytes"
"encoding/binary"
"errors"
)
type Response struct {
Data []byte
Sw1 uint8
Sw2 uint8
Sw uint16
}
var ErrBadRawResponse = errors.New("response data must be at least 2 bytes")
func (r *Response) deserialize(data []byte) error {
if len(data) < 2 {
return ErrBadRawResponse
}
r.Data = make([]byte, len(data)-2)
buf := bytes.NewReader(data)
if err := binary.Read(buf, binary.BigEndian, &r.Data); err != nil {
return err
}
if err := binary.Read(buf, binary.BigEndian, &r.Sw1); err != nil {
return err
}
if err := binary.Read(buf, binary.BigEndian, &r.Sw2); err != nil {
return err
}
r.Sw = (uint16(r.Sw1) << 8) | uint16(r.Sw2)
return nil
}
func ParseResponse(data []byte) (*Response, error) {
r := &Response{}
return r, r.deserialize(data)
}

26
apdu/response_test.go Normal file
View File

@ -0,0 +1,26 @@
package apdu
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestParseResponse(t *testing.T) {
raw := hexToBytes("000002650183039536622002003b5e508f751c0af3016e3fbc23d3a69000")
resp, err := ParseResponse(raw)
assert.NoError(t, err)
assert.Equal(t, uint8(0x90), resp.Sw1)
assert.Equal(t, uint8(0x00), resp.Sw2)
assert.Equal(t, uint16(0x9000), resp.Sw)
expected := "000002650183039536622002003B5E508F751C0AF3016E3FBC23D3A6"
assert.Equal(t, expected, bytesToHex(resp.Data))
}
func TestParseResponse_BadData(t *testing.T) {
raw := hexToBytes("")
_, err := ParseResponse(raw)
assert.Equal(t, ErrBadRawResponse, err)
}