Skip to content

Commit

Permalink
add comments to all packages
Browse files Browse the repository at this point in the history
  • Loading branch information
gravityblast committed Oct 19, 2018
1 parent 02de35c commit 8d061e2
Show file tree
Hide file tree
Showing 11 changed files with 71 additions and 23 deletions.
1 change: 1 addition & 0 deletions globalplatform/channel.go
Expand Up @@ -2,6 +2,7 @@ package globalplatform

import "github.com/status-im/status-go/smartcard/apdu"

// Channel is an interface with a Send method to send apdu commands and receive apdu responses.
type Channel interface {
Send(*apdu.Command) (*apdu.Response, error)
}
14 changes: 7 additions & 7 deletions globalplatform/commands.go
Expand Up @@ -62,7 +62,7 @@ func NewCommandSelect(aid []byte) *apdu.Command {
return c
}

// NewCommandSelect returns an Initialize Update command as defined in the globalplatform specifications.
// NewCommandInitializeUpdate returns an Initialize Update command as defined in the globalplatform specifications.
func NewCommandInitializeUpdate(challenge []byte) *apdu.Command {
c := apdu.NewCommand(
ClaGp,
Expand All @@ -79,7 +79,7 @@ func NewCommandInitializeUpdate(challenge []byte) *apdu.Command {
return c
}

// NewCommandSelect returns an External Authenticate command as defined in the globalplatform specifications.
// NewCommandExternalAuthenticate returns an External Authenticate command as defined in the globalplatform specifications.
func NewCommandExternalAuthenticate(encKey, cardChallenge, hostChallenge []byte) (*apdu.Command, error) {
hostCryptogram, err := calculateHostCryptogram(encKey, cardChallenge, hostChallenge)
if err != nil {
Expand All @@ -95,7 +95,7 @@ func NewCommandExternalAuthenticate(encKey, cardChallenge, hostChallenge []byte)
), nil
}

// NewCommandSelect returns a Get Response command as defined in the globalplatform specifications.
// NewCommandGetResponse returns a Get Response command as defined in the globalplatform specifications.
func NewCommandGetResponse(length uint8) *apdu.Command {
c := apdu.NewCommand(
ClaISO7816,
Expand All @@ -110,7 +110,7 @@ func NewCommandGetResponse(length uint8) *apdu.Command {
return c
}

// NewCommandSelect returns a Delete command as defined in the globalplatform specifications.
// NewCommandDelete returns a Delete command as defined in the globalplatform specifications.
func NewCommandDelete(aid []byte) *apdu.Command {
data := []byte{tagDeleteAID, byte(len(aid))}
data = append(data, aid...)
Expand All @@ -124,7 +124,7 @@ func NewCommandDelete(aid []byte) *apdu.Command {
)
}

// NewCommandSelect returns an Install command with the install-for-load parameter as defined in the globalplatform specifications.
// NewCommandInstallForLoad returns an Install command with the install-for-load parameter as defined in the globalplatform specifications.
func NewCommandInstallForLoad(aid, sdaid []byte) *apdu.Command {
data := []byte{byte(len(aid))}
data = append(data, aid...)
Expand All @@ -142,7 +142,7 @@ func NewCommandInstallForLoad(aid, sdaid []byte) *apdu.Command {
)
}

// NewCommandSelect returns an Install command with the install-for-instalp parameter as defined in the globalplatform specifications.
// NewCommandInstallForInstall returns an Install command with the install-for-instalp parameter as defined in the globalplatform specifications.
func NewCommandInstallForInstall(pkgAID, appletAID, instanceAID, params []byte) *apdu.Command {
data := []byte{byte(len(pkgAID))}
data = append(data, pkgAID...)
Expand Down Expand Up @@ -175,7 +175,7 @@ func NewCommandInstallForInstall(pkgAID, appletAID, instanceAID, params []byte)
)
}

// NewCommandSelect returns a Get Status command as defined in the globalplatform specifications.
// NewCommandGetStatus returns a Get Status command as defined in the globalplatform specifications.
func NewCommandGetStatus(aid []byte, p1 uint8) *apdu.Command {
data := []byte{tagGetStatusAID}
data = append(data, byte(len(aid)))
Expand Down
40 changes: 25 additions & 15 deletions globalplatform/crypto/crypto.go
Expand Up @@ -7,11 +7,15 @@ import (
)

var (
// DerivationPurposeEnc defines 2 bytes used when deriving a encoding key.
DerivationPurposeEnc = []byte{0x01, 0x82}
// DerivationPurposeMac defines 2 bytes used when deriving a mac key.
DerivationPurposeMac = []byte{0x01, 0x01}
NullBytes8 = []byte{0, 0, 0, 0, 0, 0, 0, 0}
// NullBytes8 defined a slice of 8 zero bytes mostrly used as IV in cryptographic functions.
NullBytes8 = []byte{0, 0, 0, 0, 0, 0, 0, 0}
)

// DeriveKey derives a key from the current cardKey using the sequence number receive from the card and the purpose (ENC/MAC).
func DeriveKey(cardKey []byte, seq []byte, purpose []byte) ([]byte, error) {
key24 := resizeKey24(cardKey)

Expand All @@ -32,6 +36,7 @@ func DeriveKey(cardKey []byte, seq []byte, purpose []byte) ([]byte, error) {
return ciphertext, nil
}

// VerifyCryptogram verifies the cryptogram sends from the card to ensure that card and client are using the same keys to communicate.
func VerifyCryptogram(encKey, hostChallenge, cardChallenge, cardCryptogram []byte) (bool, error) {
data := make([]byte, 0)
data = append(data, hostChallenge...)
Expand All @@ -45,6 +50,7 @@ func VerifyCryptogram(encKey, hostChallenge, cardChallenge, cardCryptogram []byt
return bytes.Equal(calculated, cardCryptogram), nil
}

// MacFull3DES generates a full triple DES mac.
func MacFull3DES(key, data, iv []byte) ([]byte, error) {
data = AppendDESPadding(data)

Expand Down Expand Up @@ -76,19 +82,22 @@ func MacFull3DES(key, data, iv []byte) ([]byte, error) {
return ciphertext, nil
}

func EncryptICV(macKey, mac []byte) ([]byte, error) {
// EncryptICV encrypts an ICV with the specified macKey.
// The ICV is usually the mac of the previous command sent in the current session.
func EncryptICV(macKey, icv []byte) ([]byte, error) {
block, err := des.NewCipher(resizeKey8(macKey))
if err != nil {
return nil, err
}

ciphertext := make([]byte, 8)
mode := cipher.NewCBCEncrypter(block, NullBytes8)
mode.CryptBlocks(ciphertext, mac)
mode.CryptBlocks(ciphertext, icv)

return ciphertext, nil
}

// Mac3DES generates the triple DES mac of data using the specified key and icv.
func Mac3DES(key, data, iv []byte) ([]byte, error) {
key24 := resizeKey24(key)

Expand All @@ -105,18 +114,7 @@ func Mac3DES(key, data, iv []byte) ([]byte, error) {
return ciphertext[16:], nil
}

func resizeKey24(key []byte) []byte {
data := make([]byte, 24)
copy(data, key[0:16])
copy(data[16:], key[0:8])

return data
}

func resizeKey8(key []byte) []byte {
return key[:8]
}

// AppendDESPadding appends an 0x80 bytes to data and other zero bytes to make the result length multiple of 8.
func AppendDESPadding(data []byte) []byte {
length := len(data) + 1
for ; length%8 != 0; length++ {
Expand All @@ -128,3 +126,15 @@ func AppendDESPadding(data []byte) []byte {

return newData
}

func resizeKey24(key []byte) []byte {
data := make([]byte, 24)
copy(data, key[0:16])
copy(data[16:], key[0:8])

return data
}

func resizeKey8(key []byte) []byte {
return key[:8]
}
4 changes: 4 additions & 0 deletions globalplatform/keyprovider.go
@@ -1,18 +1,22 @@
package globalplatform

// KeyProvider is a struct that contains encoding and MAC keys used to communicate with smartcards.
type KeyProvider struct {
enc []byte
mac []byte
}

// Enc returns the enc key data.
func (k *KeyProvider) Enc() []byte {
return k.enc
}

// Mac returns the MAC key data.
func (k *KeyProvider) Mac() []byte {
return k.mac
}

// NewKeyProvider returns a new KeyProvider with the specified ENC and MAC keys.
func NewKeyProvider(enc, mac []byte) *KeyProvider {
return &KeyProvider{
enc: enc,
Expand Down
5 changes: 5 additions & 0 deletions globalplatform/load.go
Expand Up @@ -15,13 +15,15 @@ var internalFiles = []string{
"Method", "StaticField", "Export", "ConstantPool", "RefLocation",
}

// LoadCommandStream implement a struct that generates multiple Load commands used to load files to smartcards.
type LoadCommandStream struct {
data *bytes.Reader
currentIndex uint8
currentData []byte
p1 uint8
}

// NewLoadCommandStream returns a new LoadCommandStream to load the specified file.
func NewLoadCommandStream(file *os.File) (*LoadCommandStream, error) {
files, err := loadFiles(file)
if err != nil {
Expand All @@ -39,6 +41,7 @@ func NewLoadCommandStream(file *os.File) (*LoadCommandStream, error) {
}, nil
}

// Next returns initialize the data for the next Load command.
// TODO:@pilu update blockSize when using encrypted data
func (lcs *LoadCommandStream) Next() bool {
if lcs.data.Len() == 0 {
Expand All @@ -62,10 +65,12 @@ func (lcs *LoadCommandStream) Next() bool {
return true
}

// Index returns the command index.
func (lcs *LoadCommandStream) Index() uint8 {
return lcs.currentIndex - 1
}

// GetCommand returns the current apdu command.
func (lcs *LoadCommandStream) GetCommand() *apdu.Command {
return apdu.NewCommand(ClaGp, InsLoad, lcs.p1, lcs.Index(), lcs.currentData)
}
Expand Down
6 changes: 6 additions & 0 deletions globalplatform/normal_channel.go
Expand Up @@ -5,18 +5,24 @@ import (
"github.com/status-im/status-go/smartcard/hexutils"
)

// Transmitter defines an interface with one method to transmit raw commands and receive raw responses.
type Transmitter interface {
Transmit([]byte) ([]byte, error)
}

// NormalChannel implements a normal channel to send apdu commands and receive apdu responses.
type NormalChannel struct {
t Transmitter
}

// NewNormalChannel returns a new NormalChannel that sends commands to Transmitter t.
func NewNormalChannel(t Transmitter) *NormalChannel {
return &NormalChannel{t}
}

// Send sends apdu commands to the current Transmitter.
// Based on the smartcard transport protocol (T=0, T=1), it checks responses and sends a Get Response
// command in case of T=0.
func (c *NormalChannel) Send(cmd *apdu.Command) (*apdu.Response, error) {
rawCmd, err := cmd.Serialize()
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions globalplatform/secure_channel.go
Expand Up @@ -5,12 +5,14 @@ import (
"github.com/status-im/status-go/smartcard/hexutils"
)

// SecureChannel wraps another channel and sends wrapped commands using APDUWrapper.
type SecureChannel struct {
session *Session
c Channel
w *APDUWrapper
}

// NewSecureChannel returns a new SecureChannel based on a session and wrapping a Channel c.
func NewSecureChannel(session *Session, c Channel) *SecureChannel {
return &SecureChannel{
session: session,
Expand All @@ -19,6 +21,7 @@ func NewSecureChannel(session *Session, c Channel) *SecureChannel {
}
}

// Send sends wrapped commands to the inner channel.
func (c *SecureChannel) Send(cmd *apdu.Command) (*apdu.Response, error) {
rawCmd, err := cmd.Serialize()
if err != nil {
Expand Down
5 changes: 5 additions & 0 deletions globalplatform/session.go
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/status-im/status-go/smartcard/globalplatform/crypto"
)

// Session is a struct containing the keys and challenges used in the current communication with a card.
type Session struct {
keyProvider *KeyProvider
cardChallenge []byte
Expand All @@ -16,6 +17,7 @@ type Session struct {

var errBadCryptogram = errors.New("bad card cryptogram")

// NewSession returns a new session after validating the cryptogram received from the card.
func NewSession(cardKeys *KeyProvider, resp *apdu.Response, hostChallenge []byte) (*Session, error) {
if resp.Sw == SwSecurityConditionNotSatisfied {
return nil, apdu.NewErrBadResponse(resp.Sw, "security condition not satisfied")
Expand Down Expand Up @@ -62,14 +64,17 @@ func NewSession(cardKeys *KeyProvider, resp *apdu.Response, hostChallenge []byte
return s, nil
}

// KeyProvider return the current KeyProvider.
func (s *Session) KeyProvider() *KeyProvider {
return s.keyProvider
}

// CardChallenge returns the current card challenge.
func (s *Session) CardChallenge() []byte {
return s.cardChallenge
}

// HostChallenge returns the current host challenge.
func (s *Session) HostChallenge() []byte {
return s.hostChallenge
}
4 changes: 4 additions & 0 deletions hexutils/hexutils.go
Expand Up @@ -7,6 +7,8 @@ import (
"regexp"
)

// HexToBytes convert a hex string to a byte sequence.
// The hex string can have spaces between bytes.
func HexToBytes(s string) []byte {
s = regexp.MustCompile(" ").ReplaceAllString(s, "")
b := make([]byte, hex.DecodedLen(len(s)))
Expand All @@ -18,10 +20,12 @@ func HexToBytes(s string) []byte {
return b[:]
}

// BytesToHexWithSpaces returns an hex string of b adding spaces between bytes.
func BytesToHexWithSpaces(b []byte) string {
return fmt.Sprintf("% X", b)
}

// BytesToHex returns an hex string of b.
func BytesToHex(b []byte) string {
return fmt.Sprintf("%X", b)
}
7 changes: 6 additions & 1 deletion lightwallet/installer.go
Expand Up @@ -18,16 +18,19 @@ var (
statusAppletAID = []byte{0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x57, 0x61, 0x6C, 0x6C, 0x65, 0x74, 0x41, 0x70, 0x70}
)

// Installer defines a struct with methods to install an applet to a smartcard.
type Installer struct {
c globalplatform.Channel
}

// NewInstaller returns a new Installer that communicates to Transmitter t.
func NewInstaller(t globalplatform.Transmitter) *Installer {
return &Installer{
c: globalplatform.NewNormalChannel(t),
}
}

// Install installs the applet from the specified capFile.
func (i *Installer) Install(capFile *os.File, overwriteApplet bool) (*Secrets, error) {
err := i.initSecureChannel(cardManagerAID)
if err != nil {
Expand Down Expand Up @@ -56,6 +59,7 @@ func (i *Installer) Install(capFile *os.File, overwriteApplet bool) (*Secrets, e
return secrets, nil
}

// Info returns if the applet is already installed in the card.
func (i *Installer) Info() (bool, error) {
err := i.initSecureChannel(cardManagerAID)
if err != nil {
Expand All @@ -65,6 +69,7 @@ func (i *Installer) Info() (bool, error) {
return i.isAppletInstalled()
}

// Delete deletes the applet and related package from the card.
func (i *Installer) Delete() error {
err := i.initSecureChannel(cardManagerAID)
if err != nil {
Expand Down Expand Up @@ -214,7 +219,7 @@ func (i *Installer) send(description string, cmd *apdu.Command, allowedResponses
}
}

err = errors.New(fmt.Sprintf("unexpected response from command %s: %x", description, resp.Sw))
err = fmt.Errorf("unexpected response from command %s: %x", description, resp.Sw)

return nil, err
}
Expand Down

0 comments on commit 8d061e2

Please sign in to comment.