Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: more project layout improvements #12

Merged
merged 1 commit into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions internal/const.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package internal

const (
MaxPINRetries = 3
MaxPUKRetries = 5
MaxFreeSlots = 5
DefMnemoLen = 12
DefPINLen = 6
DefPUKLen = 12
DefPairing = "KeycardDefaultPairing"
)

const (
MasterPath = "m"
WalletRoothPath = "m/44'/60'/0'/0"
WalletPath = WalletRoothPath + "/0"
Eip1581Path = "m/43'/60'/1581'"
WhisperPath = Eip1581Path + "/0'/0"
EncryptionPath = Eip1581Path + "/1'/0"
)
11 changes: 10 additions & 1 deletion internal/keycard_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type KeycardContext struct {
runErr error
}

// Transmit implements the Channel and Transmitter interfaces
func (kc *KeycardContext) Transmit(apdu []byte) ([]byte, error) {
kc.apdu = apdu
kc.command <- Transmit
Expand Down Expand Up @@ -366,8 +367,16 @@ func (kc *KeycardContext) loadSeed(seed []byte) ([]byte, error) {
return pubKey, nil
}

func (kc *KeycardContext) mnemonicToBinarySeed(mnemonic string, password string) []byte {
return pbkdf2.Key(
norm.NFKD.Bytes([]byte(mnemonic)),
norm.NFKD.Bytes([]byte(bip39Salt+password)),
2048, 64, sha512.New,
)
}

func (kc *KeycardContext) LoadMnemonic(mnemonic string, password string) ([]byte, error) {
seed := pbkdf2.Key(norm.NFKD.Bytes([]byte(mnemonic)), norm.NFKD.Bytes([]byte(bip39Salt+password)), 2048, 64, sha512.New)
seed := kc.mnemonicToBinarySeed(mnemonic, password)
return kc.loadSeed(seed)
}

Expand Down
61 changes: 16 additions & 45 deletions internal/types.go
Original file line number Diff line number Diff line change
@@ -1,65 +1,36 @@
package internal

import (
"encoding/json"
"github.com/status-im/status-keycard-go/pkg/utils"
)

type HexString []byte

// MarshalJSON serializes HexString to hex
func (s HexString) MarshalJSON() ([]byte, error) {
bytes, err := json.Marshal(Btox(s))
return bytes, err
}

// UnmarshalJSON deserializes HexString to hex
func (s *HexString) UnmarshalJSON(data []byte) error {
var x string
err := json.Unmarshal(data, &x)
if err != nil {
return err
}
str, err := Xtob(x)
if err != nil {
return err
}

*s = HexString([]byte(str))
return nil
}

type Signature struct {
R HexString `json:"r"`
S HexString `json:"s"`
V byte `json:"v"`
R utils.HexString `json:"r"`
S utils.HexString `json:"s"`
V byte `json:"v"`
}

type ApplicationInfo struct {
Initialized bool `json:"initialized"`
InstanceUID HexString `json:"instanceUID"`
Version int `json:"version"`
AvailableSlots int `json:"availableSlots"`
Initialized bool `json:"initialized"`
InstanceUID utils.HexString `json:"instanceUID"`
Version int `json:"version"`
AvailableSlots int `json:"availableSlots"`
// KeyUID is the sha256 of the master public key on the card.
// It's empty if the card doesn't contain any key.
KeyUID HexString `json:"keyUID"`
}

type PairingInfo struct {
Key HexString `json:"key"`
Index int `json:"index"`
KeyUID utils.HexString `json:"keyUID"`
}

type KeyPair struct {
Address string `json:"address"`
PublicKey HexString `json:"publicKey"`
PrivateKey HexString `json:"privateKey,omitempty"`
ChainCode HexString `json:"chainCode,omitempty"`
Address string `json:"address"`
PublicKey utils.HexString `json:"publicKey"`
PrivateKey utils.HexString `json:"privateKey,omitempty"`
ChainCode utils.HexString `json:"chainCode,omitempty"`
}

type Wallet struct {
Path string `json:"path"`
Address string `json:"address,omitempty"`
PublicKey HexString `json:"publicKey"`
Path string `json:"path"`
Address string `json:"address,omitempty"`
PublicKey utils.HexString `json:"publicKey"`
}

type Metadata struct {
Expand Down
19 changes: 3 additions & 16 deletions internal/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package internal

import (
"encoding/binary"
"encoding/hex"

"github.com/ebfe/scard"
keycard "github.com/status-im/keycard-go"
Expand All @@ -25,14 +24,6 @@ func GetRetries(err error) (int, bool) {
}
}

func Btox(bytes []byte) string {
return hex.EncodeToString(bytes)
}

func Xtob(str string) ([]byte, error) {
return hex.DecodeString(str)
}

func BytesToInt(s []byte) int {
if len(s) > 4 {
return 0
Expand All @@ -54,6 +45,9 @@ func ContainsString(str string, s []string) bool {
}

func ToAppInfo(r *ktypes.ApplicationInfo) ApplicationInfo {
if r == nil {
return ApplicationInfo{}
}
return ApplicationInfo{
Initialized: r.Initialized,
InstanceUID: r.InstanceUID,
Expand All @@ -63,13 +57,6 @@ func ToAppInfo(r *ktypes.ApplicationInfo) ApplicationInfo {
}
}

func ToPairInfo(r *ktypes.PairingInfo) *PairingInfo {
return &PairingInfo{
Key: r.Key,
Index: r.Index,
}
}

func ToSignature(r *ktypes.Signature) *Signature {
return &Signature{
R: r.R(),
Expand Down
38 changes: 20 additions & 18 deletions pkg/flow/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import (
"io"
"strings"

keycard "github.com/status-im/keycard-go"
"github.com/status-im/keycard-go"
"github.com/status-im/keycard-go/apdu"
"github.com/status-im/keycard-go/derivationpath"
ktypes "github.com/status-im/keycard-go/types"

"github.com/status-im/status-keycard-go/internal"
"github.com/status-im/status-keycard-go/pkg/pairing"
"github.com/status-im/status-keycard-go/pkg/utils"
)

func (f *KeycardFlow) factoryReset(kc *internal.KeycardContext) error {
Expand All @@ -33,8 +35,8 @@ func (f *KeycardFlow) selectKeycard(kc *internal.KeycardContext) error {
return restartErr()
}

f.cardInfo.instanceUID = internal.Btox(appInfo.InstanceUID)
f.cardInfo.keyUID = internal.Btox(appInfo.KeyUID)
f.cardInfo.instanceUID = utils.Btox(appInfo.InstanceUID)
f.cardInfo.keyUID = utils.Btox(appInfo.KeyUID)
f.cardInfo.freeSlots = internal.BytesToInt(appInfo.AvailableSlots)
f.cardInfo.version = internal.BytesToInt(appInfo.Version)

Expand Down Expand Up @@ -65,13 +67,13 @@ func (f *KeycardFlow) pair(kc *internal.KeycardContext) error {
pairingPass, ok := f.params[PairingPass]

if !ok {
pairingPass = DefPairing
pairingPass = internal.DefPairing
}

pairing, err := kc.Pair(pairingPass.(string))
pair, err := kc.Pair(pairingPass.(string))

if err == nil {
return f.pairings.Store(f.cardInfo.instanceUID, internal.ToPairInfo(pairing))
return f.pairings.Store(f.cardInfo.instanceUID, pairing.ToPairInfo(pair))
} else if internal.IsSCardError(err) {
return restartErr()
}
Expand Down Expand Up @@ -111,7 +113,7 @@ func (f *KeycardFlow) initCard(kc *internal.KeycardContext) error {

newPairing, pairingOK := f.params[NewPairing]
if !pairingOK {
newPairing = DefPairing
newPairing = internal.DefPairing
}

err := kc.Init(newPIN.(string), newPUK.(string), newPairing.(string))
Expand Down Expand Up @@ -146,7 +148,7 @@ func (f *KeycardFlow) verifyAuthenticity(kc *internal.KeycardContext) error {
}

func (f *KeycardFlow) openSC(kc *internal.KeycardContext, giveup bool) error {
var pairing *internal.PairingInfo
var pairing *pairing.Info

if !kc.ApplicationInfo().Initialized && !giveup {
return f.initCard(kc)
Expand Down Expand Up @@ -210,8 +212,8 @@ func (f *KeycardFlow) unblockPIN(kc *internal.KeycardContext) error {
err = kc.UnblockPIN(puk.(string), newPIN.(string))

if err == nil {
f.cardInfo.pinRetries = MaxPINRetries
f.cardInfo.pukRetries = MaxPUKRetries
f.cardInfo.pinRetries = internal.MaxPINRetries
f.cardInfo.pukRetries = internal.MaxPUKRetries
f.params[PIN] = newPIN
delete(f.params, NewPIN)
delete(f.params, PUK)
Expand Down Expand Up @@ -256,7 +258,7 @@ func (f *KeycardFlow) authenticate(kc *internal.KeycardContext) error {
err := kc.VerifyPin(pin.(string))

if err == nil {
f.cardInfo.pinRetries = MaxPINRetries
f.cardInfo.pinRetries = internal.MaxPINRetries
return nil
} else if internal.IsSCardError(err) {
return restartErr()
Expand Down Expand Up @@ -368,8 +370,8 @@ func (f *KeycardFlow) storeMetadata(kc *internal.KeycardContext) error {

paths := make([]uint32, len(wallets))
for i, p := range wallets {
if !strings.HasPrefix(p.(string), WalletRoothPath) {
return errors.New("path must start with " + WalletRoothPath)
if !strings.HasPrefix(p.(string), internal.WalletRoothPath) {
return errors.New("path must start with " + internal.WalletRoothPath)
}

_, components, err := derivationpath.Decode(p.(string))
Expand Down Expand Up @@ -406,7 +408,7 @@ func (f *KeycardFlow) exportKey(kc *internal.KeycardContext, path string, onlyPu
}

func (f *KeycardFlow) exportKeyExtended(kc *internal.KeycardContext, path string, p2 uint8) (*internal.KeyPair, error) {
keyPair, err := kc.ExportKey(true, path == MasterPath, p2, path)
keyPair, err := kc.ExportKey(true, path == internal.MasterPath, p2, path)

if internal.IsSCardError(err) {
return nil, restartErr()
Expand Down Expand Up @@ -460,7 +462,7 @@ func (f *KeycardFlow) loadKeys(kc *internal.KeycardContext) error {
return err
}

f.cardInfo.keyUID = internal.Btox(keyUID)
f.cardInfo.keyUID = utils.Btox(keyUID)
return nil
}

Expand All @@ -473,10 +475,10 @@ func (f *KeycardFlow) loadKeys(kc *internal.KeycardContext) error {
case float64:
mnemonicLength = int(t)
default:
mnemonicLength = DefMnemoLen
mnemonicLength = internal.DefMnemoLen
}
} else {
mnemonicLength = DefMnemoLen
mnemonicLength = internal.DefMnemoLen
}

indexes, err := kc.GenerateMnemonic(mnemonicLength / 3)
Expand Down Expand Up @@ -581,7 +583,7 @@ func (f *KeycardFlow) sign(kc *internal.KeycardContext) (*internal.Signature, er
var rawHash []byte

if hashOK {
rawHash, err = internal.Xtob(hash.(string))
rawHash, err = utils.Xtob(hash.(string))
if err != nil {
hashOK = false
}
Expand Down
18 changes: 9 additions & 9 deletions pkg/flow/flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,20 +323,20 @@ func (f *KeycardFlow) exportKeysFlow(kc *internal.KeycardContext, recover bool)

result := FlowStatus{KeyUID: f.cardInfo.keyUID, InstanceUID: f.cardInfo.instanceUID}

key, err := f.exportKey(kc, EncryptionPath, false)
key, err := f.exportKey(kc, internal.EncryptionPath, false)
if err != nil {
return nil, err
}
result[EncKey] = key

key, err = f.exportKey(kc, WhisperPath, false)
key, err = f.exportKey(kc, internal.WhisperPath, false)
if err != nil {
return nil, err
}
result[WhisperKey] = key

if recover {
key, err = f.exportKey(kc, Eip1581Path, true)
key, err = f.exportKey(kc, internal.Eip1581Path, true)
if err != nil {
return nil, err
}
Expand All @@ -350,21 +350,21 @@ func (f *KeycardFlow) exportKeysFlow(kc *internal.KeycardContext, recover bool)
exportP2 = keycard.P2ExportKeyExtendedPublic
}

key, err = f.exportKeyExtended(kc, WalletRoothPath, exportP2)
key, err = f.exportKeyExtended(kc, internal.WalletRoothPath, exportP2)
if err != nil {
return nil, err
}
result[WalleRootKey] = key

//if key.ChainCode == nil {
key, err = f.exportKey(kc, WalletPath, true)
key, err = f.exportKey(kc, internal.WalletPath, true)
if err != nil {
return nil, err
}
result[WalletKey] = key
//}

key, err = f.exportKey(kc, MasterPath, true)
key, err = f.exportKey(kc, internal.MasterPath, true)
if err != nil {
return nil, err
}
Expand All @@ -390,7 +390,7 @@ func (f *KeycardFlow) exportPublicFlow(kc *internal.KeycardContext) (FlowStatus,
result := FlowStatus{KeyUID: f.cardInfo.keyUID, InstanceUID: f.cardInfo.instanceUID}

if exportMaster, ok := f.params[ExportMaster]; ok && exportMaster.(bool) {
masterKey, err := f.exportKey(kc, MasterPath, true)
masterKey, err := f.exportKey(kc, internal.MasterPath, true)
result[MasterAddr] = masterKey.Address

if err != nil {
Expand Down Expand Up @@ -525,7 +525,7 @@ func (f *KeycardFlow) unpairOthersFlow(kc *internal.KeycardContext) (FlowStatus,
return nil, err
}

for i := 0; i < MaxFreeSlots; i++ {
for i := 0; i < internal.MaxFreeSlots; i++ {
if i == kc.PairingInfo().Index {
continue
}
Expand Down Expand Up @@ -604,7 +604,7 @@ func (f *KeycardFlow) getMetadataFlow(kc *internal.KeycardContext) (FlowStatus,
}

if exportMaster, ok := f.params[ExportMaster]; ok && exportMaster.(bool) {
masterKey, err := f.exportKey(kc, MasterPath, true)
masterKey, err := f.exportKey(kc, internal.MasterPath, true)
result[MasterAddr] = masterKey.Address

if err != nil {
Expand Down
Loading
Loading