add comments to all packages
This commit is contained in:
parent
02de35c254
commit
8d061e2c60
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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...)
|
||||
|
@ -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...)
|
||||
|
@ -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...)
|
||||
|
@ -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)))
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
@ -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...)
|
||||
|
@ -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)
|
||||
|
||||
|
@ -76,7 +82,9 @@ 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
|
||||
|
@ -84,11 +92,12 @@ func EncryptICV(macKey, mac []byte) ([]byte, error) {
|
|||
|
||||
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)
|
||||
|
||||
|
@ -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++ {
|
||||
|
@ -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]
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -15,6 +15,7 @@ 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
|
||||
|
@ -22,6 +23,7 @@ type LoadCommandStream struct {
|
|||
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 {
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)))
|
||||
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
|
|
@ -16,12 +16,14 @@ const (
|
|||
maxPukNumber = int64(999999999999)
|
||||
)
|
||||
|
||||
// Secrets contains the secret data needed to pair a client with a card.
|
||||
type Secrets struct {
|
||||
puk string
|
||||
pairingPass string
|
||||
pairingToken []byte
|
||||
}
|
||||
|
||||
// NewSecrets generate a new Secrets with random puk and pairing password.
|
||||
func NewSecrets() (*Secrets, error) {
|
||||
pairingPass, err := generatePairingPass()
|
||||
if err != nil {
|
||||
|
@ -40,14 +42,17 @@ func NewSecrets() (*Secrets, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Puk returns the puk string.
|
||||
func (s *Secrets) Puk() string {
|
||||
return s.puk
|
||||
}
|
||||
|
||||
// PairingPass returns the pairing password string.
|
||||
func (s *Secrets) PairingPass() string {
|
||||
return s.pairingPass
|
||||
}
|
||||
|
||||
// PairingToken returns the pairing token generated from the random pairing password.
|
||||
func (s *Secrets) PairingToken() []byte {
|
||||
return s.pairingToken
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue