add APDUWrapper and test

This commit is contained in:
Andrea Franz 2018-09-27 18:01:09 +02:00
parent 3e3af578eb
commit 7b24b7bc42
No known key found for this signature in database
GPG Key ID: 4F0D2F2D9DE7F29D
6 changed files with 150 additions and 19 deletions

View File

@ -12,6 +12,7 @@ type Command struct {
P2 uint8
Data []byte
Le uint8
requiresLe bool
}
func NewCommand(cla, ins, p1, p2 uint8, data []byte) *Command {
@ -21,9 +22,15 @@ func NewCommand(cla, ins, p1, p2 uint8, data []byte) *Command {
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,9 +59,11 @@ func (c *Command) Serialize() ([]byte, error) {
}
}
if c.requiresLe {
if err := binary.Write(buf, binary.BigEndian, c.Le); err != nil {
return nil, err
}
}
return buf.Bytes(), nil
}

View File

@ -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))
}

View 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
}

View 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))
}

View File

@ -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)

View File

@ -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))