diff --git a/globalplatform/commands.go b/globalplatform/commands.go index 00845e8..0739d05 100644 --- a/globalplatform/commands.go +++ b/globalplatform/commands.go @@ -1,13 +1,18 @@ package globalplatform -import "github.com/status-im/status-go/smartcard/apdu" +import ( + "github.com/status-im/status-go/smartcard/apdu" + "github.com/status-im/status-go/smartcard/globalplatform/crypto" +) const ( - Cla = uint8(0x00) - ClaGp = uint8(0x80) + Cla = uint8(0x00) + ClaGp = uint8(0x80) + ClaMac = uint8(0x84) - InsSelect = uint8(0xA4) - InsInitializeUpdate = uint8(0x50) + InsSelect = uint8(0xA4) + InsInitializeUpdate = uint8(0x50) + InsExternalAuthenticate = uint8(0x82) ) func NewCommandSelect(aid []byte) *apdu.Command { @@ -29,3 +34,27 @@ func NewCommandInitializeUpdate(challenge []byte) *apdu.Command { challenge, ) } + +func NewCommandExternalAuthenticate(encKey, cardChallenge, hostChallenge []byte) (*apdu.Command, error) { + hostCryptogram, err := calculateHostCryptogram(encKey, cardChallenge, hostChallenge) + if err != nil { + return nil, err + } + + return apdu.NewCommand( + ClaMac, + InsExternalAuthenticate, + uint8(0x01), // C-MAC + uint8(0x00), + hostCryptogram, + ), nil +} + +func calculateHostCryptogram(encKey, cardChallenge, hostChallenge []byte) ([]byte, error) { + var data []byte + data = append(data, cardChallenge...) + data = append(data, hostChallenge...) + data = crypto.AppendDESPadding(data) + + return crypto.Mac3DES(encKey, data, crypto.NullBytes8) +} diff --git a/globalplatform/commands_test.go b/globalplatform/commands_test.go index 6d57f59..c47a428 100644 --- a/globalplatform/commands_test.go +++ b/globalplatform/commands_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestCommandSelect(t *testing.T) { +func TestNewCommandSelect(t *testing.T) { aid := []byte{} cmd := NewCommandSelect(aid) @@ -17,7 +17,7 @@ func TestCommandSelect(t *testing.T) { assert.Equal(t, uint8(0x00), cmd.P2) } -func TestCommandInitializeUpdate(t *testing.T) { +func TestNewCommandInitializeUpdate(t *testing.T) { challenge := hexutils.HexToBytes("010203") cmd := NewCommandInitializeUpdate(challenge) @@ -27,3 +27,29 @@ func TestCommandInitializeUpdate(t *testing.T) { assert.Equal(t, uint8(0x00), cmd.P2) assert.Equal(t, challenge, cmd.Data) } + +func TestCalculateHostCryptogram(t *testing.T) { + encKey := hexutils.HexToBytes("0EF72A1065236DD6CAC718D5E3F379A4") + cardChallenge := hexutils.HexToBytes("0076a6c0d55e9535") + hostChallenge := hexutils.HexToBytes("266195e638da1b95") + + result, err := calculateHostCryptogram(encKey, cardChallenge, hostChallenge) + assert.NoError(t, err) + + expected := "45A5F48DAE68203C" + assert.Equal(t, expected, hexutils.BytesToHex(result)) +} + +func TestNewCommandExternalAuthenticate(t *testing.T) { + encKey := hexutils.HexToBytes("8D289AFE0AB9C45B1C76DEEA182966F4") + cardChallenge := hexutils.HexToBytes("000f3fd65d4d6e45") + hostChallenge := hexutils.HexToBytes("cf307b6719bf224d") + + cmd, err := NewCommandExternalAuthenticate(encKey, cardChallenge, hostChallenge) + assert.NoError(t, err) + + expected := "84 82 01 00 08 77 02 AC 6C E4 6A 47 F0" + raw, err := cmd.Serialize() + assert.NoError(t, err) + assert.Equal(t, expected, hexutils.BytesToHexWithSpaces(raw)) +} diff --git a/globalplatform/crypto/crypto.go b/globalplatform/crypto/crypto.go index b52d458..c214487 100644 --- a/globalplatform/crypto/crypto.go +++ b/globalplatform/crypto/crypto.go @@ -36,8 +36,8 @@ func VerifyCryptogram(encKey, hostChallenge, cardChallenge, cardCryptogram []byt data := make([]byte, 0) data = append(data, hostChallenge...) data = append(data, cardChallenge...) - paddedData := appendDESPadding(data) - calculated, err := mac3des(encKey, paddedData, NullBytes8) + paddedData := AppendDESPadding(data) + calculated, err := Mac3DES(encKey, paddedData, NullBytes8) if err != nil { return false, err } @@ -46,7 +46,7 @@ func VerifyCryptogram(encKey, hostChallenge, cardChallenge, cardCryptogram []byt } func MacFull3DES(key, data, iv []byte) ([]byte, error) { - data = appendDESPadding(data) + data = AppendDESPadding(data) desBlock, err := des.NewCipher(resizeKey8(key)) if err != nil { @@ -89,7 +89,7 @@ func EncryptICV(macKey, mac []byte) ([]byte, error) { return ciphertext, nil } -func mac3des(key, data, iv []byte) ([]byte, error) { +func Mac3DES(key, data, iv []byte) ([]byte, error) { key24 := resizeKey24(key) block, err := des.NewTripleDESCipher(key24) @@ -117,7 +117,7 @@ func resizeKey8(key []byte) []byte { return key[:8] } -func appendDESPadding(data []byte) []byte { +func AppendDESPadding(data []byte) []byte { length := len(data) + 1 for ; length%8 != 0; length++ { }