keycard-go/globalplatform/apdu_wrapper.go

87 lines
1.9 KiB
Go
Raw Normal View History

2018-09-27 16:01:09 +00:00
package globalplatform
import (
"bytes"
"encoding/binary"
2018-10-19 08:54:02 +00:00
"github.com/status-im/smartcard-go/apdu"
"github.com/status-im/smartcard-go/globalplatform/crypto"
2018-09-27 16:01:09 +00:00
)
2018-10-05 11:46:34 +00:00
// APDUWrapper is a wrapper for apdu commands inside a global platform secure channel.
2018-09-27 16:01:09 +00:00
type APDUWrapper struct {
macKey []byte
icv []byte
}
2018-10-05 11:46:34 +00:00
// NewAPDUWrapper returns a new APDUWrapper using the specified key for MAC generation.
2018-09-27 16:01:09 +00:00
func NewAPDUWrapper(macKey []byte) *APDUWrapper {
return &APDUWrapper{
macKey: macKey,
icv: crypto.NullBytes8,
}
}
2018-10-05 11:46:34 +00:00
// Wrap wraps the apdu command adding the MAC to the end of the command.
// Future implementations will encrypt the message when needed.
2018-09-27 16:01:09 +00:00
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...)
2018-09-28 09:25:08 +00:00
w.icv = mac
newCmd := apdu.NewCommand(cla, cmd.Ins, cmd.P1, cmd.P2, newData)
if ok, le := cmd.Le(); ok {
newCmd.SetLe(le)
}
return newCmd, nil
2018-09-27 16:01:09 +00:00
}