87 lines
1.9 KiB
Go
87 lines
1.9 KiB
Go
package globalplatform
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
|
|
"github.com/status-im/keycard-go/apdu"
|
|
"github.com/status-im/keycard-go/globalplatform/crypto"
|
|
)
|
|
|
|
// SCP02Wrapper is a wrapper for apdu commands inside a global platform secure channel.
|
|
type SCP02Wrapper struct {
|
|
macKey []byte
|
|
icv []byte
|
|
}
|
|
|
|
// NewSCP02Wrapper returns a new SCP02Wrapper using the specified key for MAC generation.
|
|
func NewSCP02Wrapper(macKey []byte) *SCP02Wrapper {
|
|
return &SCP02Wrapper{
|
|
macKey: macKey,
|
|
icv: crypto.NullBytes8,
|
|
}
|
|
}
|
|
|
|
// Wrap wraps the apdu command adding the MAC to the end of the command.
|
|
// Future implementations will encrypt the message when needed.
|
|
func (w *SCP02Wrapper) 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...)
|
|
|
|
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
|
|
}
|