mirror of
https://github.com/status-im/keycard-go.git
synced 2025-01-31 06:07:03 +00:00
add command and response structs
This commit is contained in:
parent
c278c2b6b1
commit
b2ef28fa0a
60
apdu/command.go
Normal file
60
apdu/command.go
Normal 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
43
apdu/command_test.go
Normal 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
46
apdu/response.go
Normal 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
26
apdu/response_test.go
Normal 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)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user