mirror of
https://github.com/status-im/keycard-go.git
synced 2025-03-03 04:50:30 +00:00
add APDUWrapper and test
This commit is contained in:
parent
3e3af578eb
commit
7b24b7bc42
@ -6,24 +6,31 @@ import (
|
||||
)
|
||||
|
||||
type Command struct {
|
||||
Cla uint8
|
||||
Ins uint8
|
||||
P1 uint8
|
||||
P2 uint8
|
||||
Data []byte
|
||||
Le uint8
|
||||
Cla uint8
|
||||
Ins uint8
|
||||
P1 uint8
|
||||
P2 uint8
|
||||
Data []byte
|
||||
Le uint8
|
||||
requiresLe bool
|
||||
}
|
||||
|
||||
func NewCommand(cla, ins, p1, p2 uint8, data []byte) *Command {
|
||||
return &Command{
|
||||
Cla: cla,
|
||||
Ins: ins,
|
||||
P1: p1,
|
||||
P2: p2,
|
||||
Data: data,
|
||||
Cla: cla,
|
||||
Ins: ins,
|
||||
P1: p1,
|
||||
P2: p2,
|
||||
Data: data,
|
||||
requiresLe: false,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Command) SetLE(le uint8) {
|
||||
c.requiresLe = true
|
||||
c.Le = le
|
||||
}
|
||||
|
||||
func (c *Command) Serialize() ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
@ -52,8 +59,10 @@ func (c *Command) Serialize() ([]byte, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if err := binary.Write(buf, binary.BigEndian, c.Le); err != nil {
|
||||
return nil, err
|
||||
if c.requiresLe {
|
||||
if err := binary.Write(buf, binary.BigEndian, c.Le); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
|
@ -15,9 +15,15 @@ func TestNewCommand(t *testing.T) {
|
||||
data := hexutils.HexToBytes("84762336c5187fe8")
|
||||
|
||||
cmd := NewCommand(cla, ins, p1, p2, data)
|
||||
expected := "80 50 01 02 08 84 76 23 36 C5 18 7F E8 00"
|
||||
|
||||
expected := "80 50 01 02 08 84 76 23 36 C5 18 7F E8"
|
||||
result, err := cmd.Serialize()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, hexutils.BytesToHexWithSpaces(result))
|
||||
|
||||
cmd.SetLE(uint8(0x77))
|
||||
expected = "80 50 01 02 08 84 76 23 36 C5 18 7F E8 77"
|
||||
result, err = cmd.Serialize()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, hexutils.BytesToHexWithSpaces(result))
|
||||
}
|
||||
|
75
globalplatform/apdu_wrapper.go
Normal file
75
globalplatform/apdu_wrapper.go
Normal file
@ -0,0 +1,75 @@
|
||||
package globalplatform
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/status-im/status-go/smartcard/apdu"
|
||||
"github.com/status-im/status-go/smartcard/globalplatform/crypto"
|
||||
)
|
||||
|
||||
type APDUWrapper struct {
|
||||
macKey []byte
|
||||
icv []byte
|
||||
}
|
||||
|
||||
func NewAPDUWrapper(macKey []byte) *APDUWrapper {
|
||||
return &APDUWrapper{
|
||||
macKey: macKey,
|
||||
icv: crypto.NullBytes8,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *APDUWrapper) Wrap(cmd *apdu.Command) (*apdu.Command, error) {
|
||||
macData := new(bytes.Buffer)
|
||||
|
||||
cla := cmd.Cla | 0x04
|
||||
if err := binary.Write(macData, binary.BigEndian, cla); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := binary.Write(macData, binary.BigEndian, cmd.Ins); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := binary.Write(macData, binary.BigEndian, cmd.P1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := binary.Write(macData, binary.BigEndian, cmd.P2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := binary.Write(macData, binary.BigEndian, uint8(len(cmd.Data)+8)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := binary.Write(macData, binary.BigEndian, cmd.Data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
icv []byte
|
||||
err error
|
||||
)
|
||||
|
||||
if bytes.Equal(w.icv, crypto.NullBytes8) {
|
||||
icv = w.icv
|
||||
} else {
|
||||
icv, err = crypto.EncryptICV(w.macKey, w.icv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
mac, err := crypto.MacFull3DES(w.macKey, macData.Bytes(), icv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newData := make([]byte, 0)
|
||||
newData = append(newData, cmd.Data...)
|
||||
newData = append(newData, mac...)
|
||||
|
||||
return apdu.NewCommand(cla, cmd.Ins, cmd.P1, cmd.P2, newData), nil
|
||||
}
|
28
globalplatform/apdu_wrapper_test.go
Normal file
28
globalplatform/apdu_wrapper_test.go
Normal file
@ -0,0 +1,28 @@
|
||||
package globalplatform
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/status-im/status-go/smartcard/apdu"
|
||||
"github.com/status-im/status-go/smartcard/globalplatform/crypto"
|
||||
"github.com/status-im/status-go/smartcard/hexutils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPDUWrapper_Wrap(t *testing.T) {
|
||||
macKey := hexutils.HexToBytes("2983BA77D709C2DAA1E6000ABCCAC951")
|
||||
data := hexutils.HexToBytes("1d4de92eaf7a2c9f")
|
||||
|
||||
cmd := apdu.NewCommand(uint8(0x80), uint8(0x82), uint8(0x01), uint8(0x00), data)
|
||||
w := NewAPDUWrapper(macKey)
|
||||
|
||||
assert.Equal(t, crypto.NullBytes8, w.icv)
|
||||
|
||||
wrappedCmd, err := w.Wrap(cmd)
|
||||
assert.NoError(t, err)
|
||||
raw, err := wrappedCmd.Serialize()
|
||||
assert.NoError(t, err)
|
||||
|
||||
expected := "84 82 01 00 10 1D 4D E9 2E AF 7A 2C 9F 8F 9B 0D F6 81 C1 D3 EC"
|
||||
assert.Equal(t, expected, hexutils.BytesToHexWithSpaces(raw))
|
||||
}
|
@ -9,7 +9,7 @@ import (
|
||||
var (
|
||||
DerivationPurposeEnc = []byte{0x01, 0x82}
|
||||
DerivationPurposeMac = []byte{0x01, 0x01}
|
||||
nullBytes8 = []byte{0, 0, 0, 0, 0, 0, 0, 0}
|
||||
NullBytes8 = []byte{0, 0, 0, 0, 0, 0, 0, 0}
|
||||
)
|
||||
|
||||
func DeriveKey(cardKey []byte, seq []byte, purpose []byte) ([]byte, error) {
|
||||
@ -26,7 +26,7 @@ func DeriveKey(cardKey []byte, seq []byte, purpose []byte) ([]byte, error) {
|
||||
|
||||
ciphertext := make([]byte, 16)
|
||||
|
||||
mode := cipher.NewCBCEncrypter(block, nullBytes8)
|
||||
mode := cipher.NewCBCEncrypter(block, NullBytes8)
|
||||
mode.CryptBlocks(ciphertext, derivation)
|
||||
|
||||
return ciphertext, nil
|
||||
@ -37,7 +37,7 @@ func VerifyCryptogram(encKey, hostChallenge, cardChallenge, cardCryptogram []byt
|
||||
data = append(data, hostChallenge...)
|
||||
data = append(data, cardChallenge...)
|
||||
paddedData := appendDESPadding(data)
|
||||
calculated, err := mac3des(encKey, paddedData, nullBytes8)
|
||||
calculated, err := mac3des(encKey, paddedData, NullBytes8)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@ -76,6 +76,19 @@ func MacFull3DES(key, data, iv []byte) ([]byte, error) {
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
||||
func EncryptICV(macKey, mac []byte) ([]byte, error) {
|
||||
block, err := des.NewCipher(resizeKey8(macKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ciphertext := make([]byte, 16)
|
||||
mode := cipher.NewCBCEncrypter(block, NullBytes8)
|
||||
mode.CryptBlocks(ciphertext, mac)
|
||||
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
||||
func mac3des(key, data, iv []byte) ([]byte, error) {
|
||||
key24 := resizeKey24(key)
|
||||
|
||||
|
@ -46,7 +46,7 @@ func TestVerifyCryptogram(t *testing.T) {
|
||||
func TestMac3des(t *testing.T) {
|
||||
key := hexutils.HexToBytes("16B5867FF50BE7239C2BF1245B83A362")
|
||||
data := hexutils.HexToBytes("32DA078D7AAC1CFF007284F64A7D64658000000000000000")
|
||||
result, err := mac3des(key, data, nullBytes8)
|
||||
result, err := mac3des(key, data, NullBytes8)
|
||||
assert.NoError(t, err)
|
||||
|
||||
expected := "05C4BB8A86014E22"
|
||||
@ -56,7 +56,7 @@ func TestMac3des(t *testing.T) {
|
||||
func TestMacFull3DES(t *testing.T) {
|
||||
key := hexutils.HexToBytes("5b02e75ad63190aece0622936f11abab")
|
||||
data := hexutils.HexToBytes("8482010010810b098a8fbb88da")
|
||||
result, err := MacFull3DES(key, data, nullBytes8)
|
||||
result, err := MacFull3DES(key, data, NullBytes8)
|
||||
assert.NoError(t, err)
|
||||
expected := "5271D7174A5A166A"
|
||||
assert.Equal(t, expected, hexutils.BytesToHex(result))
|
||||
|
Loading…
x
Reference in New Issue
Block a user