accounts, core, internal, node: Add support for smartcard wallets

This commit is contained in:
Nick Johnson 2018-01-07 18:38:11 +00:00 committed by Guillaume Ballet
parent 3996bc1ad9
commit f7027dd68c
21 changed files with 5364 additions and 0 deletions

View File

@ -17,6 +17,7 @@
package accounts package accounts
import ( import (
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"math" "math"
@ -133,3 +134,17 @@ func (path DerivationPath) String() string {
} }
return result return result
} }
func (path DerivationPath) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf("\"%s\"", path.String())), nil
}
func (dp *DerivationPath) UnmarshalJSON(b []byte) error {
var path string
var err error
if err = json.Unmarshal(b, &path); err != nil {
return err
}
*dp, err = ParseDerivationPath(path)
return err
}

96
accounts/scwallet/apdu.go Normal file
View File

@ -0,0 +1,96 @@
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package scwallet
import (
"bytes"
"encoding/binary"
)
const (
CLA_ISO7816 = 0
INS_SELECT = 0xA4
INS_GET_RESPONSE = 0xC0
INS_PAIR = 0x12
INS_UNPAIR = 0x13
INS_OPEN_SECURE_CHANNEL = 0x10
INS_MUTUALLY_AUTHENTICATE = 0x11
SW1_GET_RESPONSE = 0x61
SW1_OK = 0x90
)
// CommandAPDU represents an application data unit sent to a smartcard
type CommandAPDU struct {
Cla, Ins, P1, P2 uint8 // Class, Instruction, Parameter 1, Parameter 2
Data []byte // Command data
Le uint8 // Command data length
}
// serialize serializes a command APDU.
func (ca CommandAPDU) serialize() ([]byte, error) {
buf := new(bytes.Buffer)
if err := binary.Write(buf, binary.BigEndian, ca.Cla); err != nil {
return nil, err
}
if err := binary.Write(buf, binary.BigEndian, ca.Ins); err != nil {
return nil, err
}
if err := binary.Write(buf, binary.BigEndian, ca.P1); err != nil {
return nil, err
}
if err := binary.Write(buf, binary.BigEndian, ca.P2); err != nil {
return nil, err
}
if len(ca.Data) > 0 {
if err := binary.Write(buf, binary.BigEndian, uint8(len(ca.Data))); err != nil {
return nil, err
}
if err := binary.Write(buf, binary.BigEndian, ca.Data); err != nil {
return nil, err
}
}
if err := binary.Write(buf, binary.BigEndian, ca.Le); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// ResponseAPDU represents an application data unit received from a smart card
type ResponseAPDU struct {
Data []byte // response data
Sw1, Sw2 uint8 // status words 1 and 2
}
// deserialize deserializes a response APDU
func (ra *ResponseAPDU) deserialize(data []byte) error {
ra.Data = make([]byte, len(data)-2)
buf := bytes.NewReader(data)
if err := binary.Read(buf, binary.BigEndian, &ra.Data); err != nil {
return err
}
if err := binary.Read(buf, binary.BigEndian, &ra.Sw1); err != nil {
return err
}
if err := binary.Read(buf, binary.BigEndian, &ra.Sw2); err != nil {
return err
}
return nil
}

277
accounts/scwallet/hub.go Normal file
View File

@ -0,0 +1,277 @@
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package scwallet
import (
"encoding/json"
"io/ioutil"
"os"
"reflect"
"sync"
"time"
"github.com/ebfe/scard"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
)
const Scheme = "pcsc"
// refreshCycle is the maximum time between wallet refreshes (if USB hotplug
// notifications don't work).
const refreshCycle = 5 * time.Second
// refreshThrottling is the minimum time between wallet refreshes to avoid thrashing.
const refreshThrottling = 500 * time.Millisecond
// SmartcardPairing contains information about a smart card we have paired with
// or might pair withub.
type SmartcardPairing struct {
PublicKey []byte `json:"publicKey"`
PairingIndex uint8 `json:"pairingIndex"`
PairingKey []byte `json:"pairingKey"`
Accounts map[common.Address]accounts.DerivationPath `json:"accounts"`
}
// Hub is a accounts.Backend that can find and handle generic PC/SC hardware wallets.
type Hub struct {
scheme string // Protocol scheme prefixing account and wallet URLs.
context *scard.Context
datadir string
pairings map[string]SmartcardPairing
refreshed time.Time // Time instance when the list of wallets was last refreshed
wallets map[string]*Wallet // Mapping from reader names to wallet instances
updateFeed event.Feed // Event feed to notify wallet additions/removals
updateScope event.SubscriptionScope // Subscription scope tracking current live listeners
updating bool // Whether the event notification loop is running
quit chan chan error
stateLock sync.Mutex // Protects the internals of the hub from racey access
}
var HubType = reflect.TypeOf(&Hub{})
func (hub *Hub) readPairings() error {
hub.pairings = make(map[string]SmartcardPairing)
pairingFile, err := os.Open(hub.datadir + "/smartcards.json")
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
pairingData, err := ioutil.ReadAll(pairingFile)
if err != nil {
return err
}
var pairings []SmartcardPairing
if err := json.Unmarshal(pairingData, &pairings); err != nil {
return err
}
for _, pairing := range pairings {
hub.pairings[string(pairing.PublicKey)] = pairing
}
return nil
}
func (hub *Hub) writePairings() error {
pairingFile, err := os.OpenFile(hub.datadir+"/smartcards.json", os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
return err
}
pairings := make([]SmartcardPairing, 0, len(hub.pairings))
for _, pairing := range hub.pairings {
pairings = append(pairings, pairing)
}
pairingData, err := json.Marshal(pairings)
if err != nil {
return err
}
if _, err := pairingFile.Write(pairingData); err != nil {
return err
}
return pairingFile.Close()
}
func (hub *Hub) getPairing(wallet *Wallet) *SmartcardPairing {
pairing, ok := hub.pairings[string(wallet.PublicKey)]
if ok {
return &pairing
}
return nil
}
func (hub *Hub) setPairing(wallet *Wallet, pairing *SmartcardPairing) error {
if pairing == nil {
delete(hub.pairings, string(wallet.PublicKey))
} else {
hub.pairings[string(wallet.PublicKey)] = *pairing
}
return hub.writePairings()
}
// NewHub creates a new hardware wallet manager for smartcards.
func NewHub(scheme string, datadir string) (*Hub, error) {
context, err := scard.EstablishContext()
if err != nil {
return nil, err
}
hub := &Hub{
scheme: scheme,
context: context,
datadir: datadir,
wallets: make(map[string]*Wallet),
quit: make(chan chan error),
}
if err := hub.readPairings(); err != nil {
return nil, err
}
hub.refreshWallets()
return hub, nil
}
// Wallets implements accounts.Backend, returning all the currently tracked USB
// devices that appear to be hardware wallets.
func (hub *Hub) Wallets() []accounts.Wallet {
// Make sure the list of wallets is up to date
hub.stateLock.Lock()
defer hub.stateLock.Unlock()
hub.refreshWallets()
cpy := make([]accounts.Wallet, 0, len(hub.wallets))
for _, wallet := range hub.wallets {
if wallet != nil {
cpy = append(cpy, wallet)
}
}
return cpy
}
// refreshWallets scans the USB devices attached to the machine and updates the
// list of wallets based on the found devices.
func (hub *Hub) refreshWallets() {
elapsed := time.Since(hub.refreshed)
if elapsed < refreshThrottling {
return
}
readers, err := hub.context.ListReaders()
if err != nil {
log.Error("Error listing readers", "err", err)
}
events := []accounts.WalletEvent{}
seen := make(map[string]struct{})
for _, reader := range readers {
if wallet, ok := hub.wallets[reader]; ok {
// We already know about this card; check it's still present
if err := wallet.ping(); err != nil {
log.Debug("Got error pinging wallet", "reader", reader, "err", err)
} else {
seen[reader] = struct{}{}
}
continue
}
seen[reader] = struct{}{}
card, err := hub.context.Connect(reader, scard.ShareShared, scard.ProtocolAny)
if err != nil {
log.Debug("Error opening card", "reader", reader, "err", err)
continue
}
wallet := NewWallet(hub, card)
err = wallet.connect()
if err != nil {
log.Debug("Error connecting to wallet", "reader", reader, "err", err)
card.Disconnect(scard.LeaveCard)
continue
}
hub.wallets[reader] = wallet
events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletArrived})
log.Info("Found new smartcard wallet", "reader", reader, "publicKey", hexutil.Encode(wallet.PublicKey[:4]))
}
// Remove any wallets we no longer see
for k, wallet := range hub.wallets {
if _, ok := seen[k]; !ok {
log.Info("Wallet disconnected", "pubkey", hexutil.Encode(wallet.PublicKey[:4]), "reader", k)
wallet.Close()
events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletDropped})
delete(hub.wallets, k)
}
}
for _, event := range events {
hub.updateFeed.Send(event)
}
hub.refreshed = time.Now()
}
// Subscribe implements accounts.Backend, creating an async subscription to
// receive notifications on the addition or removal of wallets.
func (hub *Hub) Subscribe(sink chan<- accounts.WalletEvent) event.Subscription {
// We need the mutex to reliably start/stop the update loop
hub.stateLock.Lock()
defer hub.stateLock.Unlock()
// Subscribe the caller and track the subscriber count
sub := hub.updateScope.Track(hub.updateFeed.Subscribe(sink))
// Subscribers require an active notification loop, start it
if !hub.updating {
hub.updating = true
go hub.updater()
}
return sub
}
// updater is responsible for maintaining an up-to-date list of wallets managed
// by the hub, and for firing wallet addition/removal events.
func (hub *Hub) updater() {
for {
time.Sleep(refreshCycle)
// Run the wallet refresher
hub.stateLock.Lock()
hub.refreshWallets()
// If all our subscribers left, stop the updater
if hub.updateScope.Count() == 0 {
hub.updating = false
hub.stateLock.Unlock()
return
}
hub.stateLock.Unlock()
}
}

View File

@ -0,0 +1,342 @@
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package scwallet
import (
//"crypto/ecdsa"
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
"fmt"
//"math/big"
"github.com/ebfe/scard"
"github.com/ethereum/go-ethereum/crypto"
ecdh "github.com/wsddn/go-ecdh"
)
const (
MAX_PAYLOAD_SIZE = 223
PAIR_P1_FIRST_STEP = 0
PAIR_P1_LAST_STEP = 1
SC_SECRET_LENGTH = 32
SC_BLOCK_SIZE = 16
)
// SecureChannelSession enables secure communication with a hardware wallet
type SecureChannelSession struct {
card *scard.Card // A handle to the smartcard for communication
secret []byte // A shared secret generated from our ECDSA keys
publicKey []byte // Our own ephemeral public key
PairingKey []byte // A permanent shared secret for a pairing, if present
sessionEncKey []byte // The current session encryption key
sessionMacKey []byte // The current session MAC key
iv []byte // The current IV
PairingIndex uint8 // The pairing index
}
// NewSecureChannelSession creates a new secure channel for the given card and public key
func NewSecureChannelSession(card *scard.Card, keyData []byte) (*SecureChannelSession, error) {
// Generate an ECDSA keypair for ourselves
gen := ecdh.NewEllipticECDH(crypto.S256())
private, public, err := gen.GenerateKey(rand.Reader)
if err != nil {
return nil, err
}
cardPublic, ok := gen.Unmarshal(keyData)
if !ok {
return nil, fmt.Errorf("Could not unmarshal public key from card")
}
secret, err := gen.GenerateSharedSecret(private, cardPublic)
if err != nil {
return nil, err
}
return &SecureChannelSession{
card: card,
secret: secret,
publicKey: gen.Marshal(public),
}, nil
}
// Pair establishes a new pairing with the smartcard
func (s *SecureChannelSession) Pair(sharedSecret []byte) error {
secretHash := sha256.Sum256(sharedSecret)
challenge := make([]byte, 32)
if _, err := rand.Read(challenge); err != nil {
return err
}
response, err := s.pair(PAIR_P1_FIRST_STEP, challenge)
if err != nil {
return err
}
md := sha256.New()
md.Write(secretHash[:])
md.Write(challenge)
expectedCryptogram := md.Sum(nil)
cardCryptogram := response.Data[:32]
cardChallenge := response.Data[32:]
if !bytes.Equal(expectedCryptogram, cardCryptogram) {
return fmt.Errorf("Invalid card cryptogram")
}
md.Reset()
md.Write(secretHash[:])
md.Write(cardChallenge)
response, err = s.pair(PAIR_P1_LAST_STEP, md.Sum(nil))
if err != nil {
return err
}
md.Reset()
md.Write(secretHash[:])
md.Write(response.Data[1:])
s.PairingKey = md.Sum(nil)
s.PairingIndex = response.Data[0]
return nil
}
// Unpair disestablishes an existing pairing
func (s *SecureChannelSession) Unpair() error {
if s.PairingKey == nil {
return fmt.Errorf("Cannot unpair: not paired")
}
_, err := s.TransmitEncrypted(CLA_SCWALLET, INS_UNPAIR, s.PairingIndex, 0, []byte{})
if err != nil {
return err
}
s.PairingKey = nil
// Close channel
s.iv = nil
return nil
}
// Open initializes the secure channel
func (s *SecureChannelSession) Open() error {
if s.iv != nil {
return fmt.Errorf("Session already opened")
}
response, err := s.open()
if err != nil {
return err
}
// Generate the encryption/mac key by hashing our shared secret,
// pairing key, and the first bytes returned from the Open APDU.
md := sha512.New()
md.Write(s.secret)
md.Write(s.PairingKey)
md.Write(response.Data[:SC_SECRET_LENGTH])
keyData := md.Sum(nil)
s.sessionEncKey = keyData[:SC_SECRET_LENGTH]
s.sessionMacKey = keyData[SC_SECRET_LENGTH : SC_SECRET_LENGTH*2]
// The IV is the last bytes returned from the Open APDU.
s.iv = response.Data[SC_SECRET_LENGTH:]
if err := s.mutuallyAuthenticate(); err != nil {
return err
}
return nil
}
// mutuallyAuthenticate is an internal method to authenticate both ends of the
// connection.
func (s *SecureChannelSession) mutuallyAuthenticate() error {
data := make([]byte, SC_SECRET_LENGTH)
if _, err := rand.Read(data); err != nil {
return err
}
response, err := s.TransmitEncrypted(CLA_SCWALLET, INS_MUTUALLY_AUTHENTICATE, 0, 0, data)
if err != nil {
return err
}
if response.Sw1 != 0x90 || response.Sw2 != 0x00 {
return fmt.Errorf("Got unexpected response from MUTUALLY_AUTHENTICATE: 0x%x%x", response.Sw1, response.Sw2)
}
if len(response.Data) != SC_SECRET_LENGTH {
return fmt.Errorf("Response from MUTUALLY_AUTHENTICATE was %d bytes, expected %d", len(response.Data), SC_SECRET_LENGTH)
}
return nil
}
// open is an internal method that sends an open APDU
func (s *SecureChannelSession) open() (*ResponseAPDU, error) {
return transmit(s.card, &CommandAPDU{
Cla: CLA_SCWALLET,
Ins: INS_OPEN_SECURE_CHANNEL,
P1: s.PairingIndex,
P2: 0,
Data: s.publicKey,
Le: 0,
})
}
// pair is an internal method that sends a pair APDU
func (s *SecureChannelSession) pair(p1 uint8, data []byte) (*ResponseAPDU, error) {
return transmit(s.card, &CommandAPDU{
Cla: CLA_SCWALLET,
Ins: INS_PAIR,
P1: p1,
P2: 0,
Data: data,
Le: 0,
})
}
// TransmitEncrypted sends an encrypted message, and decrypts and returns the response
func (s *SecureChannelSession) TransmitEncrypted(cla, ins, p1, p2 byte, data []byte) (*ResponseAPDU, error) {
if s.iv == nil {
return nil, fmt.Errorf("Channel not open")
}
data, err := s.encryptAPDU(data)
if err != nil {
return nil, err
}
meta := []byte{cla, ins, p1, p2, byte(len(data) + SC_BLOCK_SIZE), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
if err = s.updateIV(meta, data); err != nil {
return nil, err
}
fulldata := make([]byte, len(s.iv)+len(data))
copy(fulldata, s.iv)
copy(fulldata[len(s.iv):], data)
response, err := transmit(s.card, &CommandAPDU{
Cla: cla,
Ins: ins,
P1: p1,
P2: p2,
Data: fulldata,
})
if err != nil {
return nil, err
}
rmeta := []byte{byte(len(response.Data)), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
rmac := response.Data[:len(s.iv)]
rdata := response.Data[len(s.iv):]
plainData, err := s.decryptAPDU(rdata)
if err != nil {
return nil, err
}
if err = s.updateIV(rmeta, rdata); err != nil {
return nil, err
}
if !bytes.Equal(s.iv, rmac) {
return nil, fmt.Errorf("Invalid MAC in response")
}
rapdu := &ResponseAPDU{}
rapdu.deserialize(plainData)
if rapdu.Sw1 != SW1_OK {
return nil, fmt.Errorf("Unexpected response status Cla=0x%x, Ins=0x%x, Sw=0x%x%x", cla, ins, rapdu.Sw1, rapdu.Sw2)
}
return rapdu, nil
}
// encryptAPDU is an internal method that serializes and encrypts an APDU
func (s *SecureChannelSession) encryptAPDU(data []byte) ([]byte, error) {
if len(data) > MAX_PAYLOAD_SIZE {
return nil, fmt.Errorf("Payload of %d bytes exceeds maximum of %d", len(data), MAX_PAYLOAD_SIZE)
}
data = pad(data, 0x80)
ret := make([]byte, len(data))
a, err := aes.NewCipher(s.sessionEncKey)
if err != nil {
return nil, err
}
crypter := cipher.NewCBCEncrypter(a, s.iv)
crypter.CryptBlocks(ret, data)
return ret, nil
}
// pad applies message padding to a 16 byte boundary
func pad(data []byte, terminator byte) []byte {
padded := make([]byte, (len(data)/16+1)*16)
copy(padded, data)
padded[len(data)] = terminator
return padded
}
// decryptAPDU is an internal method that decrypts and deserializes an APDU
func (s *SecureChannelSession) decryptAPDU(data []byte) ([]byte, error) {
a, err := aes.NewCipher(s.sessionEncKey)
if err != nil {
return nil, err
}
ret := make([]byte, len(data))
crypter := cipher.NewCBCDecrypter(a, s.iv)
crypter.CryptBlocks(ret, data)
return unpad(ret, 0x80)
}
// unpad strips padding from a message
func unpad(data []byte, terminator byte) ([]byte, error) {
for i := 1; i <= 16; i++ {
switch data[len(data)-i] {
case 0:
continue
case terminator:
return data[:len(data)-i], nil
default:
return nil, fmt.Errorf("Expected end of padding, got %d", data[len(data)-i])
}
}
return nil, fmt.Errorf("Expected end of padding, got 0")
}
// updateIV is an internal method that updates the initialization vector after
// each message exchanged.
func (s *SecureChannelSession) updateIV(meta, data []byte) error {
data = pad(data, 0)
a, err := aes.NewCipher(s.sessionMacKey)
if err != nil {
return err
}
crypter := cipher.NewCBCEncrypter(a, make([]byte, 16))
crypter.CryptBlocks(meta, meta)
crypter.CryptBlocks(data, data)
// The first 16 bytes of the last block is the MAC
s.iv = data[len(data)-32 : len(data)-16]
return nil
}

1011
accounts/scwallet/wallet.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,7 @@ import (
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/accounts/scwallet"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
@ -44,6 +45,7 @@ import (
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb"
"github.com/tyler-smith/go-bip39"
) )
const ( const (
@ -471,6 +473,46 @@ func (s *PrivateAccountAPI) SignAndSendTransaction(ctx context.Context, args Sen
return s.SendTransaction(ctx, args, passwd) return s.SendTransaction(ctx, args, passwd)
} }
func (s *PrivateAccountAPI) InitializeWallet(ctx context.Context, url string) (string, error) {
wallet, err := s.am.Wallet(url)
if err != nil {
return "", err
}
entropy, err := bip39.NewEntropy(256)
if err != nil {
return "", err
}
mnemonic, err := bip39.NewMnemonic(entropy)
if err != nil {
return "", err
}
seed := bip39.NewSeed(mnemonic, "")
switch wallet := wallet.(type) {
case *scwallet.Wallet:
return mnemonic, wallet.Initialize(seed)
default:
return "", fmt.Errorf("Specified wallet does not support initialization")
}
}
func (s *PrivateAccountAPI) Unpair(ctx context.Context, url string, pin string) error {
wallet, err := s.am.Wallet(url)
if err != nil {
return err
}
switch wallet := wallet.(type) {
case *scwallet.Wallet:
return wallet.Unpair([]byte(pin))
default:
return fmt.Errorf("Specified wallet does not support pairing")
}
}
// PublicBlockChainAPI provides an API to access the Ethereum blockchain. // PublicBlockChainAPI provides an API to access the Ethereum blockchain.
// It offers only methods that operate on public data that is freely available to anyone. // It offers only methods that operate on public data that is freely available to anyone.
type PublicBlockChainAPI struct { type PublicBlockChainAPI struct {

View File

@ -613,6 +613,16 @@ web3._extend({
params: 2, params: 2,
inputFormatter: [web3._extend.formatters.inputTransactionFormatter, null] inputFormatter: [web3._extend.formatters.inputTransactionFormatter, null]
}), }),
new web3._extend.Method({
name: 'unpair',
call: 'personal_unpair',
params: 2
}),
new web3._extend.Method({
name: 'initializeWallet',
call: 'personal_initializeWallet',
params: 1
})
], ],
properties: [ properties: [
new web3._extend.Property({ new web3._extend.Property({

View File

@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/external" "github.com/ethereum/go-ethereum/accounts/external"
"github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/accounts/scwallet"
"github.com/ethereum/go-ethereum/accounts/usbwallet" "github.com/ethereum/go-ethereum/accounts/usbwallet"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
@ -504,6 +505,12 @@ func makeAccountManager(conf *Config) (*accounts.Manager, string, error) {
backends = append(backends, trezorhub) backends = append(backends, trezorhub)
} }
} }
// Start a smart card hub
if schub, err := scwallet.NewHub(scwallet.Scheme, keydir); err != nil {
log.Warn(fmt.Sprintf("Failed to start smart card hub, disabling: %v", err))
} else {
backends = append(backends, schub)
}
} }
return accounts.NewManager(&accounts.Config{InsecureUnlockAllowed: conf.InsecureUnlockAllowed}, backends...), ephemeral, nil return accounts.NewManager(&accounts.Config{InsecureUnlockAllowed: conf.InsecureUnlockAllowed}, backends...), ephemeral, nil

23
vendor/github.com/ebfe/scard/LICENSE generated vendored Normal file
View File

@ -0,0 +1,23 @@
Copyright (c) 2016, Michael Gehring <mg@ebfe.org>
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

14
vendor/github.com/ebfe/scard/README.md generated vendored Normal file
View File

@ -0,0 +1,14 @@
scard
=====
[![GoDoc](https://godoc.org/github.com/ebfe/scard?status.svg)](https://godoc.org/github.com/ebfe/scard)
Go bindings to the PC/SC API.
## Installation
go get github.com/ebfe/scard
## Bugs
- Memory layouts/GC needs a thorough review.

283
vendor/github.com/ebfe/scard/scard.go generated vendored Normal file
View File

@ -0,0 +1,283 @@
// Package scard provides bindings to the PC/SC API.
package scard
import (
"time"
"unsafe"
)
type CardStatus struct {
Reader string
State State
ActiveProtocol Protocol
Atr []byte
}
type ReaderState struct {
Reader string
UserData interface{}
CurrentState StateFlag
EventState StateFlag
Atr []byte
}
type Context struct {
ctx uintptr
}
type Card struct {
handle uintptr
activeProtocol Protocol
}
// wraps SCardEstablishContext
func EstablishContext() (*Context, error) {
ctx, r := scardEstablishContext(ScopeSystem, 0, 0)
if r != ErrSuccess {
return nil, r
}
return &Context{ctx: ctx}, nil
}
// wraps SCardIsValidContext
func (ctx *Context) IsValid() (bool, error) {
r := scardIsValidContext(ctx.ctx)
switch r {
case ErrSuccess:
return true, nil
case ErrInvalidHandle:
return false, nil
default:
return false, r
}
}
// wraps SCardCancel
func (ctx *Context) Cancel() error {
r := scardCancel(ctx.ctx)
if r != ErrSuccess {
return r
}
return nil
}
// wraps SCardReleaseContext
func (ctx *Context) Release() error {
r := scardReleaseContext(ctx.ctx)
if r != ErrSuccess {
return r
}
return nil
}
// wraps SCardListReaders
func (ctx *Context) ListReaders() ([]string, error) {
needed, r := scardListReaders(ctx.ctx, nil, nil, 0)
if r != ErrSuccess {
return nil, r
}
buf := make(strbuf, needed)
n, r := scardListReaders(ctx.ctx, nil, buf.ptr(), uint32(len(buf)))
if r != ErrSuccess {
return nil, r
}
return decodemstr(buf[:n]), nil
}
// wraps SCardListReaderGroups
func (ctx *Context) ListReaderGroups() ([]string, error) {
needed, r := scardListReaderGroups(ctx.ctx, nil, 0)
if r != ErrSuccess {
return nil, r
}
buf := make(strbuf, needed)
n, r := scardListReaderGroups(ctx.ctx, buf.ptr(), uint32(len(buf)))
if r != ErrSuccess {
return nil, r
}
return decodemstr(buf[:n]), nil
}
// wraps SCardGetStatusChange
func (ctx *Context) GetStatusChange(readerStates []ReaderState, timeout time.Duration) error {
dwTimeout := durationToTimeout(timeout)
states := make([]scardReaderState, len(readerStates))
for i := range readerStates {
var err error
states[i], err = readerStates[i].toSys()
if err != nil {
return err
}
}
r := scardGetStatusChange(ctx.ctx, dwTimeout, states)
if r != ErrSuccess {
return r
}
for i := range readerStates {
(&readerStates[i]).update(&states[i])
}
return nil
}
// wraps SCardConnect
func (ctx *Context) Connect(reader string, mode ShareMode, proto Protocol) (*Card, error) {
creader, err := encodestr(reader)
if err != nil {
return nil, err
}
handle, activeProtocol, r := scardConnect(ctx.ctx, creader.ptr(), mode, proto)
if r != ErrSuccess {
return nil, r
}
return &Card{handle: handle, activeProtocol: activeProtocol}, nil
}
// wraps SCardDisconnect
func (card *Card) Disconnect(d Disposition) error {
r := scardDisconnect(card.handle, d)
if r != ErrSuccess {
return r
}
return nil
}
// wraps SCardReconnect
func (card *Card) Reconnect(mode ShareMode, proto Protocol, disp Disposition) error {
activeProtocol, r := scardReconnect(card.handle, mode, proto, disp)
if r != ErrSuccess {
return r
}
card.activeProtocol = activeProtocol
return nil
}
// wraps SCardBeginTransaction
func (card *Card) BeginTransaction() error {
r := scardBeginTransaction(card.handle)
if r != ErrSuccess {
return r
}
return nil
}
// wraps SCardEndTransaction
func (card *Card) EndTransaction(disp Disposition) error {
r := scardEndTransaction(card.handle, disp)
if r != ErrSuccess {
return r
}
return nil
}
// wraps SCardStatus
func (card *Card) Status() (*CardStatus, error) {
reader, state, proto, atr, err := scardCardStatus(card.handle)
if err != ErrSuccess {
return nil, err
}
return &CardStatus{Reader: reader, State: state, ActiveProtocol: proto, Atr: atr}, nil
}
// wraps SCardTransmit
func (card *Card) Transmit(cmd []byte) ([]byte, error) {
rsp := make([]byte, maxBufferSizeExtended)
rspLen, err := scardTransmit(card.handle, card.activeProtocol, cmd, rsp)
if err != ErrSuccess {
return nil, err
}
return rsp[:rspLen], nil
}
// wraps SCardControl
func (card *Card) Control(ioctl uint32, in []byte) ([]byte, error) {
var out [0xffff]byte
outLen, err := scardControl(card.handle, ioctl, in, out[:])
if err != ErrSuccess {
return nil, err
}
return out[:outLen], nil
}
// wraps SCardGetAttrib
func (card *Card) GetAttrib(id Attrib) ([]byte, error) {
needed, err := scardGetAttrib(card.handle, id, nil)
if err != ErrSuccess {
return nil, err
}
var attrib = make([]byte, needed)
n, err := scardGetAttrib(card.handle, id, attrib)
if err != ErrSuccess {
return nil, err
}
return attrib[:n], nil
}
// wraps SCardSetAttrib
func (card *Card) SetAttrib(id Attrib, data []byte) error {
err := scardSetAttrib(card.handle, id, data)
if err != ErrSuccess {
return err
}
return nil
}
func durationToTimeout(timeout time.Duration) uint32 {
switch {
case timeout < 0:
return infiniteTimeout
case timeout > time.Duration(infiniteTimeout)*time.Millisecond:
return infiniteTimeout - 1
default:
return uint32(timeout / time.Millisecond)
}
}
func (buf strbuf) ptr() unsafe.Pointer {
return unsafe.Pointer(&buf[0])
}
func (buf strbuf) split() []strbuf {
var chunks []strbuf
for len(buf) > 0 && buf[0] != 0 {
i := 0
for i = range buf {
if buf[i] == 0 {
break
}
}
chunks = append(chunks, buf[:i+1])
buf = buf[i+1:]
}
return chunks
}
func encodemstr(strings ...string) (strbuf, error) {
var buf strbuf
for _, s := range strings {
utf16, err := encodestr(s)
if err != nil {
return nil, err
}
buf = append(buf, utf16...)
}
buf = append(buf, 0)
return buf, nil
}
func decodemstr(buf strbuf) []string {
var strings []string
for _, chunk := range buf.split() {
strings = append(strings, decodestr(chunk))
}
return strings
}

219
vendor/github.com/ebfe/scard/scard_darwin.go generated vendored Normal file
View File

@ -0,0 +1,219 @@
// +build darwin
package scard
// #cgo LDFLAGS: -framework PCSC
// #cgo CFLAGS: -I /usr/include
// #include <stdlib.h>
// #include <PCSC/winscard.h>
// #include <PCSC/wintypes.h>
import "C"
import (
"unsafe"
)
func (e Error) Error() string {
return "scard: " + C.GoString(C.pcsc_stringify_error(C.int32_t(e)))
}
// Version returns the libpcsclite version string
func Version() string {
return C.PCSCLITE_VERSION_NUMBER
}
func scardEstablishContext(scope Scope, reserved1, reserved2 uintptr) (uintptr, Error) {
var ctx C.SCARDCONTEXT
r := C.SCardEstablishContext(C.uint32_t(scope), unsafe.Pointer(reserved1), unsafe.Pointer(reserved2), &ctx)
return uintptr(ctx), Error(r)
}
func scardIsValidContext(ctx uintptr) Error {
r := C.SCardIsValidContext(C.SCARDCONTEXT(ctx))
return Error(r)
}
func scardCancel(ctx uintptr) Error {
r := C.SCardCancel(C.SCARDCONTEXT(ctx))
return Error(r)
}
func scardReleaseContext(ctx uintptr) Error {
r := C.SCardReleaseContext(C.SCARDCONTEXT(ctx))
return Error(r)
}
func scardListReaders(ctx uintptr, groups, buf unsafe.Pointer, bufLen uint32) (uint32, Error) {
dwBufLen := C.uint32_t(bufLen)
r := C.SCardListReaders(C.SCARDCONTEXT(ctx), (C.LPCSTR)(groups), (C.LPSTR)(buf), &dwBufLen)
return uint32(dwBufLen), Error(r)
}
func scardListReaderGroups(ctx uintptr, buf unsafe.Pointer, bufLen uint32) (uint32, Error) {
dwBufLen := C.uint32_t(bufLen)
r := C.SCardListReaderGroups(C.SCARDCONTEXT(ctx), (C.LPSTR)(buf), &dwBufLen)
return uint32(dwBufLen), Error(r)
}
func scardGetStatusChange(ctx uintptr, timeout uint32, states []scardReaderState) Error {
// In darwin, the LPSCARD_READERSTATE_A has 1 byte alignment and hence
// has no trailing padding. Go does add 3 bytes of padding (on both 32
// and 64 bits), so we pack an array manually instead.
const size = int(unsafe.Sizeof(states[0])) - 3
buf := make([]byte, size*len(states))
for i, _ := range states {
copy(buf[i*size:(i+1)*size], (*(*[size]byte)(unsafe.Pointer(&states[i])))[:])
}
r := C.SCardGetStatusChange(C.SCARDCONTEXT(ctx), C.uint32_t(timeout), (C.LPSCARD_READERSTATE_A)(unsafe.Pointer(&buf[0])), C.uint32_t(len(states)))
for i, _ := range states {
copy((*(*[size]byte)(unsafe.Pointer(&states[i])))[:], buf[i*size:(i+1)*size])
}
return Error(r)
}
func scardConnect(ctx uintptr, reader unsafe.Pointer, shareMode ShareMode, proto Protocol) (uintptr, Protocol, Error) {
var handle C.SCARDHANDLE
var activeProto C.uint32_t
r := C.SCardConnect(C.SCARDCONTEXT(ctx), C.LPCSTR(reader), C.uint32_t(shareMode), C.uint32_t(proto), &handle, &activeProto)
return uintptr(handle), Protocol(activeProto), Error(r)
}
func scardDisconnect(card uintptr, d Disposition) Error {
r := C.SCardDisconnect(C.SCARDHANDLE(card), C.uint32_t(d))
return Error(r)
}
func scardReconnect(card uintptr, mode ShareMode, proto Protocol, disp Disposition) (Protocol, Error) {
var activeProtocol C.uint32_t
r := C.SCardReconnect(C.SCARDHANDLE(card), C.uint32_t(mode), C.uint32_t(proto), C.uint32_t(disp), &activeProtocol)
return Protocol(activeProtocol), Error(r)
}
func scardBeginTransaction(card uintptr) Error {
r := C.SCardBeginTransaction(C.SCARDHANDLE(card))
return Error(r)
}
func scardEndTransaction(card uintptr, disp Disposition) Error {
r := C.SCardEndTransaction(C.SCARDHANDLE(card), C.uint32_t(disp))
return Error(r)
}
func scardCardStatus(card uintptr) (string, State, Protocol, []byte, Error) {
var readerBuf [C.MAX_READERNAME + 1]byte
var readerLen = C.uint32_t(len(readerBuf))
var state, proto C.uint32_t
var atr [maxAtrSize]byte
var atrLen = C.uint32_t(len(atr))
r := C.SCardStatus(C.SCARDHANDLE(card), (C.LPSTR)(unsafe.Pointer(&readerBuf[0])), &readerLen, &state, &proto, (*C.uchar)(&atr[0]), &atrLen)
return decodestr(readerBuf[:readerLen]), State(state), Protocol(proto), atr[:atrLen], Error(r)
}
func scardTransmit(card uintptr, proto Protocol, cmd []byte, rsp []byte) (uint32, Error) {
var sendpci C.SCARD_IO_REQUEST
var recvpci C.SCARD_IO_REQUEST
var rspLen = C.uint32_t(len(rsp))
switch proto {
case ProtocolT0, ProtocolT1:
sendpci.dwProtocol = C.uint32_t(proto)
default:
panic("unknown protocol")
}
sendpci.cbPciLength = C.sizeof_SCARD_IO_REQUEST
r := C.SCardTransmit(C.SCARDHANDLE(card), &sendpci, (*C.uchar)(&cmd[0]), C.uint32_t(len(cmd)), &recvpci, (*C.uchar)(&rsp[0]), &rspLen)
return uint32(rspLen), Error(r)
}
func scardControl(card uintptr, ioctl uint32, in, out []byte) (uint32, Error) {
var ptrIn unsafe.Pointer
var outLen = C.uint32_t(len(out))
if len(in) != 0 {
ptrIn = unsafe.Pointer(&in[0])
}
r := C.SCardControl(C.SCARDHANDLE(card), C.uint32_t(ioctl), ptrIn, C.uint32_t(len(in)), unsafe.Pointer(&out[0]), C.uint32_t(len(out)), &outLen)
return uint32(outLen), Error(r)
}
func scardGetAttrib(card uintptr, id Attrib, buf []byte) (uint32, Error) {
var ptr *C.uint8_t
if len(buf) != 0 {
ptr = (*C.uint8_t)(&buf[0])
}
bufLen := C.uint32_t(len(buf))
r := C.SCardGetAttrib(C.SCARDHANDLE(card), C.uint32_t(id), ptr, &bufLen)
return uint32(bufLen), Error(r)
}
func scardSetAttrib(card uintptr, id Attrib, buf []byte) Error {
r := C.SCardSetAttrib(C.SCARDHANDLE(card), C.uint32_t(id), ((*C.uint8_t)(&buf[0])), C.uint32_t(len(buf)))
return Error(r)
}
type strbuf []byte
func encodestr(s string) (strbuf, error) {
buf := strbuf(s + "\x00")
return buf, nil
}
func decodestr(buf strbuf) string {
if len(buf) == 0 {
return ""
}
if buf[len(buf)-1] == 0 {
buf = buf[:len(buf)-1]
}
return string(buf)
}
type scardReaderState struct {
szReader uintptr
pvUserData uintptr
dwCurrentState uint32
dwEventState uint32
cbAtr uint32
rgbAtr [33]byte
}
var pinned = map[string]*strbuf{}
func (rs *ReaderState) toSys() (scardReaderState, error) {
var sys scardReaderState
creader, err := encodestr(rs.Reader)
if err != nil {
return scardReaderState{}, err
}
pinned[rs.Reader] = &creader
sys.szReader = uintptr(creader.ptr())
sys.dwCurrentState = uint32(rs.CurrentState)
sys.cbAtr = uint32(len(rs.Atr))
for i, v := range rs.Atr {
sys.rgbAtr[i] = byte(v)
}
return sys, nil
}
func (rs *ReaderState) update(sys *scardReaderState) {
rs.EventState = StateFlag(sys.dwEventState)
if sys.cbAtr > 0 {
rs.Atr = make([]byte, int(sys.cbAtr))
for i := 0; i < int(sys.cbAtr); i++ {
rs.Atr[i] = byte(sys.rgbAtr[i])
}
}
}

206
vendor/github.com/ebfe/scard/scard_unix.go generated vendored Normal file
View File

@ -0,0 +1,206 @@
// +build !windows,!darwin
package scard
// #cgo pkg-config: libpcsclite
// #include <stdlib.h>
// #include <winscard.h>
import "C"
import (
"unsafe"
)
func (e Error) Error() string {
return "scard: " + C.GoString(C.pcsc_stringify_error(C.LONG(e)))
}
// Version returns the libpcsclite version string
func Version() string {
return C.PCSCLITE_VERSION_NUMBER
}
func scardEstablishContext(scope Scope, reserved1, reserved2 uintptr) (uintptr, Error) {
var ctx C.SCARDCONTEXT
r := C.SCardEstablishContext(C.DWORD(scope), C.LPCVOID(reserved1), C.LPCVOID(reserved2), &ctx)
return uintptr(ctx), Error(r)
}
func scardIsValidContext(ctx uintptr) Error {
r := C.SCardIsValidContext(C.SCARDCONTEXT(ctx))
return Error(r)
}
func scardCancel(ctx uintptr) Error {
r := C.SCardCancel(C.SCARDCONTEXT(ctx))
return Error(r)
}
func scardReleaseContext(ctx uintptr) Error {
r := C.SCardReleaseContext(C.SCARDCONTEXT(ctx))
return Error(r)
}
func scardListReaders(ctx uintptr, groups, buf unsafe.Pointer, bufLen uint32) (uint32, Error) {
dwBufLen := C.DWORD(bufLen)
r := C.SCardListReaders(C.SCARDCONTEXT(ctx), (C.LPCSTR)(groups), (C.LPSTR)(buf), &dwBufLen)
return uint32(dwBufLen), Error(r)
}
func scardListReaderGroups(ctx uintptr, buf unsafe.Pointer, bufLen uint32) (uint32, Error) {
dwBufLen := C.DWORD(bufLen)
r := C.SCardListReaderGroups(C.SCARDCONTEXT(ctx), (C.LPSTR)(buf), &dwBufLen)
return uint32(dwBufLen), Error(r)
}
func scardGetStatusChange(ctx uintptr, timeout uint32, states []scardReaderState) Error {
r := C.SCardGetStatusChange(C.SCARDCONTEXT(ctx), C.DWORD(timeout), (C.LPSCARD_READERSTATE)(unsafe.Pointer(&states[0])), C.DWORD(len(states)))
return Error(r)
}
func scardConnect(ctx uintptr, reader unsafe.Pointer, shareMode ShareMode, proto Protocol) (uintptr, Protocol, Error) {
var handle C.SCARDHANDLE
var activeProto C.DWORD
r := C.SCardConnect(C.SCARDCONTEXT(ctx), C.LPCSTR(reader), C.DWORD(shareMode), C.DWORD(proto), &handle, &activeProto)
return uintptr(handle), Protocol(activeProto), Error(r)
}
func scardDisconnect(card uintptr, d Disposition) Error {
r := C.SCardDisconnect(C.SCARDHANDLE(card), C.DWORD(d))
return Error(r)
}
func scardReconnect(card uintptr, mode ShareMode, proto Protocol, disp Disposition) (Protocol, Error) {
var activeProtocol C.DWORD
r := C.SCardReconnect(C.SCARDHANDLE(card), C.DWORD(mode), C.DWORD(proto), C.DWORD(disp), &activeProtocol)
return Protocol(activeProtocol), Error(r)
}
func scardBeginTransaction(card uintptr) Error {
r := C.SCardBeginTransaction(C.SCARDHANDLE(card))
return Error(r)
}
func scardEndTransaction(card uintptr, disp Disposition) Error {
r := C.SCardEndTransaction(C.SCARDHANDLE(card), C.DWORD(disp))
return Error(r)
}
func scardCardStatus(card uintptr) (string, State, Protocol, []byte, Error) {
var readerBuf [C.MAX_READERNAME + 1]byte
var readerLen = C.DWORD(len(readerBuf))
var state, proto C.DWORD
var atr [maxAtrSize]byte
var atrLen = C.DWORD(len(atr))
r := C.SCardStatus(C.SCARDHANDLE(card), (C.LPSTR)(unsafe.Pointer(&readerBuf[0])), &readerLen, &state, &proto, (*C.BYTE)(&atr[0]), &atrLen)
return decodestr(readerBuf[:readerLen]), State(state), Protocol(proto), atr[:atrLen], Error(r)
}
func scardTransmit(card uintptr, proto Protocol, cmd []byte, rsp []byte) (uint32, Error) {
var sendpci C.SCARD_IO_REQUEST
var recvpci C.SCARD_IO_REQUEST
var rspLen = C.DWORD(len(rsp))
switch proto {
case ProtocolT0, ProtocolT1:
sendpci.dwProtocol = C.ulong(proto)
default:
panic("unknown protocol")
}
sendpci.cbPciLength = C.sizeof_SCARD_IO_REQUEST
r := C.SCardTransmit(C.SCARDHANDLE(card), &sendpci, (*C.BYTE)(&cmd[0]), C.DWORD(len(cmd)), &recvpci, (*C.BYTE)(&rsp[0]), &rspLen)
return uint32(rspLen), Error(r)
}
func scardControl(card uintptr, ioctl uint32, in, out []byte) (uint32, Error) {
var ptrIn C.LPCVOID
var outLen = C.DWORD(len(out))
if len(in) != 0 {
ptrIn = C.LPCVOID(unsafe.Pointer(&in[0]))
}
r := C.SCardControl(C.SCARDHANDLE(card), C.DWORD(ioctl), ptrIn, C.DWORD(len(in)), (C.LPVOID)(unsafe.Pointer(&out[0])), C.DWORD(len(out)), &outLen)
return uint32(outLen), Error(r)
}
func scardGetAttrib(card uintptr, id Attrib, buf []byte) (uint32, Error) {
var ptr C.LPBYTE
if len(buf) != 0 {
ptr = C.LPBYTE(unsafe.Pointer(&buf[0]))
}
bufLen := C.DWORD(len(buf))
r := C.SCardGetAttrib(C.SCARDHANDLE(card), C.DWORD(id), ptr, &bufLen)
return uint32(bufLen), Error(r)
}
func scardSetAttrib(card uintptr, id Attrib, buf []byte) Error {
r := C.SCardSetAttrib(C.SCARDHANDLE(card), C.DWORD(id), (*C.BYTE)(unsafe.Pointer(&buf[0])), C.DWORD(len(buf)))
return Error(r)
}
type strbuf []byte
func encodestr(s string) (strbuf, error) {
buf := strbuf(s + "\x00")
return buf, nil
}
func decodestr(buf strbuf) string {
if len(buf) == 0 {
return ""
}
if buf[len(buf)-1] == 0 {
buf = buf[:len(buf)-1]
}
return string(buf)
}
type scardReaderState struct {
szReader uintptr
pvUserData uintptr
dwCurrentState uintptr
dwEventState uintptr
cbAtr uintptr
rgbAtr [33]byte
}
var pinned = map[string]*strbuf{}
func (rs *ReaderState) toSys() (scardReaderState, error) {
var sys scardReaderState
creader, err := encodestr(rs.Reader)
if err != nil {
return scardReaderState{}, err
}
pinned[rs.Reader] = &creader
sys.szReader = uintptr(creader.ptr())
sys.dwCurrentState = uintptr(rs.CurrentState)
sys.cbAtr = uintptr(len(rs.Atr))
for i, v := range rs.Atr {
sys.rgbAtr[i] = byte(v)
}
return sys, nil
}
func (rs *ReaderState) update(sys *scardReaderState) {
rs.EventState = StateFlag(sys.dwEventState)
if sys.cbAtr > 0 {
rs.Atr = make([]byte, int(sys.cbAtr))
for i := 0; i < int(sys.cbAtr); i++ {
rs.Atr[i] = byte(sys.rgbAtr[i])
}
}
}

221
vendor/github.com/ebfe/scard/scard_windows.go generated vendored Normal file
View File

@ -0,0 +1,221 @@
package scard
import (
"fmt"
"syscall"
"unsafe"
)
var (
modwinscard = syscall.NewLazyDLL("winscard.dll")
procEstablishContext = modwinscard.NewProc("SCardEstablishContext")
procReleaseContext = modwinscard.NewProc("SCardReleaseContext")
procIsValidContext = modwinscard.NewProc("SCardIsValidContext")
procCancel = modwinscard.NewProc("SCardCancel")
procListReaders = modwinscard.NewProc("SCardListReadersW")
procListReaderGroups = modwinscard.NewProc("SCardListReaderGroupsW")
procGetStatusChange = modwinscard.NewProc("SCardGetStatusChangeW")
procConnect = modwinscard.NewProc("SCardConnectW")
procDisconnect = modwinscard.NewProc("SCardDisconnect")
procReconnect = modwinscard.NewProc("SCardReconnect")
procBeginTransaction = modwinscard.NewProc("SCardBeginTransaction")
procEndTransaction = modwinscard.NewProc("SCardEndTransaction")
procStatus = modwinscard.NewProc("SCardStatusW")
procTransmit = modwinscard.NewProc("SCardTransmit")
procControl = modwinscard.NewProc("SCardControl")
procGetAttrib = modwinscard.NewProc("SCardGetAttrib")
procSetAttrib = modwinscard.NewProc("SCardSetAttrib")
dataT0Pci = modwinscard.NewProc("g_rgSCardT0Pci")
dataT1Pci = modwinscard.NewProc("g_rgSCardT1Pci")
)
var scardIoReqT0 uintptr
var scardIoReqT1 uintptr
func init() {
if err := dataT0Pci.Find(); err != nil {
panic(err)
}
scardIoReqT0 = dataT0Pci.Addr()
if err := dataT1Pci.Find(); err != nil {
panic(err)
}
scardIoReqT1 = dataT1Pci.Addr()
}
func (e Error) Error() string {
err := syscall.Errno(e)
return fmt.Sprintf("scard: error(%x): %s", uintptr(e), err.Error())
}
func scardEstablishContext(scope Scope, reserved1, reserved2 uintptr) (uintptr, Error) {
var ctx uintptr
r, _, _ := procEstablishContext.Call(uintptr(scope), reserved1, reserved2, uintptr(unsafe.Pointer(&ctx)))
return ctx, Error(r)
}
func scardIsValidContext(ctx uintptr) Error {
r, _, _ := procIsValidContext.Call(ctx)
return Error(r)
}
func scardCancel(ctx uintptr) Error {
r, _, _ := procCancel.Call(ctx)
return Error(r)
}
func scardReleaseContext(ctx uintptr) Error {
r, _, _ := procReleaseContext.Call(ctx)
return Error(r)
}
func scardListReaders(ctx uintptr, groups, buf unsafe.Pointer, bufLen uint32) (uint32, Error) {
dwBufLen := uint32(bufLen)
r, _, _ := procListReaders.Call(ctx, uintptr(groups), uintptr(buf), uintptr(unsafe.Pointer(&dwBufLen)))
return dwBufLen, Error(r)
}
func scardListReaderGroups(ctx uintptr, buf unsafe.Pointer, bufLen uint32) (uint32, Error) {
dwBufLen := uint32(bufLen)
r, _, _ := procListReaderGroups.Call(ctx, uintptr(buf), uintptr(unsafe.Pointer(&dwBufLen)))
return dwBufLen, Error(r)
}
func scardGetStatusChange(ctx uintptr, timeout uint32, states []scardReaderState) Error {
r, _, _ := procGetStatusChange.Call(ctx, uintptr(timeout), uintptr(unsafe.Pointer(&states[0])), uintptr(len(states)))
return Error(r)
}
func scardConnect(ctx uintptr, reader unsafe.Pointer, shareMode ShareMode, proto Protocol) (uintptr, Protocol, Error) {
var handle uintptr
var activeProto uint32
r, _, _ := procConnect.Call(ctx, uintptr(reader), uintptr(shareMode), uintptr(proto), uintptr(unsafe.Pointer(&handle)), uintptr(unsafe.Pointer(&activeProto)))
return handle, Protocol(activeProto), Error(r)
}
func scardDisconnect(card uintptr, d Disposition) Error {
r, _, _ := procDisconnect.Call(card, uintptr(d))
return Error(r)
}
func scardReconnect(card uintptr, mode ShareMode, proto Protocol, disp Disposition) (Protocol, Error) {
var activeProtocol uint32
r, _, _ := procReconnect.Call(card, uintptr(mode), uintptr(proto), uintptr(disp), uintptr(unsafe.Pointer(&activeProtocol)))
return Protocol(activeProtocol), Error(r)
}
func scardBeginTransaction(card uintptr) Error {
r, _, _ := procBeginTransaction.Call(card)
return Error(r)
}
func scardEndTransaction(card uintptr, disp Disposition) Error {
r, _, _ := procEndTransaction.Call(card, uintptr(disp))
return Error(r)
}
func scardCardStatus(card uintptr) (string, State, Protocol, []byte, Error) {
var state, proto uint32
var atr [maxAtrSize]byte
var atrLen = uint32(len(atr))
reader := make(strbuf, maxReadername+1)
readerLen := uint32(len(reader))
r, _, _ := procStatus.Call(card, uintptr(reader.ptr()), uintptr(unsafe.Pointer(&readerLen)), uintptr(unsafe.Pointer(&state)), uintptr(unsafe.Pointer(&proto)), uintptr(unsafe.Pointer(&atr[0])), uintptr(unsafe.Pointer(&atrLen)))
return decodestr(reader[:readerLen]), State(state), Protocol(proto), atr[:atrLen], Error(r)
}
func scardTransmit(card uintptr, proto Protocol, cmd []byte, rsp []byte) (uint32, Error) {
var sendpci uintptr
var rspLen = uint32(len(rsp))
switch proto {
case ProtocolT0:
sendpci = scardIoReqT0
case ProtocolT1:
sendpci = scardIoReqT1
default:
panic("unknown protocol")
}
r, _, _ := procTransmit.Call(card, sendpci, uintptr(unsafe.Pointer(&cmd[0])), uintptr(len(cmd)), uintptr(0), uintptr(unsafe.Pointer(&rsp[0])), uintptr(unsafe.Pointer(&rspLen)))
return rspLen, Error(r)
}
func scardControl(card uintptr, ioctl uint32, in, out []byte) (uint32, Error) {
var ptrIn uintptr
var outLen = uint32(len(out))
if len(in) != 0 {
ptrIn = uintptr(unsafe.Pointer(&in[0]))
}
r, _, _ := procControl.Call(card, uintptr(ioctl), ptrIn, uintptr(len(in)), uintptr(unsafe.Pointer(&out[0])), uintptr(len(out)), uintptr(unsafe.Pointer(&outLen)))
return outLen, Error(r)
}
func scardGetAttrib(card uintptr, id Attrib, buf []byte) (uint32, Error) {
var ptr uintptr
if len(buf) != 0 {
ptr = uintptr(unsafe.Pointer(&buf[0]))
}
bufLen := uint32(len(buf))
r, _, _ := procGetAttrib.Call(card, uintptr(id), ptr, uintptr(unsafe.Pointer(&bufLen)))
return bufLen, Error(r)
}
func scardSetAttrib(card uintptr, id Attrib, buf []byte) Error {
r, _, _ := procSetAttrib.Call(card, uintptr(id), uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)))
return Error(r)
}
type scardReaderState struct {
szReader uintptr
pvUserData uintptr
dwCurrentState uint32
dwEventState uint32
cbAtr uint32
rgbAtr [36]byte
}
func (rs *ReaderState) toSys() (scardReaderState, error) {
var sys scardReaderState
creader, err := encodestr(rs.Reader)
if err != nil {
return scardReaderState{}, err
}
sys.szReader = uintptr(creader.ptr())
sys.dwCurrentState = uint32(rs.CurrentState)
sys.cbAtr = uint32(len(rs.Atr))
copy(sys.rgbAtr[:], rs.Atr)
return sys, nil
}
func (rs *ReaderState) update(sys *scardReaderState) {
rs.EventState = StateFlag(sys.dwEventState)
if sys.cbAtr > 0 {
rs.Atr = make([]byte, int(sys.cbAtr))
copy(rs.Atr, sys.rgbAtr[:])
}
}
type strbuf []uint16
func encodestr(s string) (strbuf, error) {
utf16, err := syscall.UTF16FromString(s)
return strbuf(utf16), err
}
func decodestr(buf strbuf) string {
return syscall.UTF16ToString(buf)
}

190
vendor/github.com/ebfe/scard/zconst.go generated vendored Normal file
View File

@ -0,0 +1,190 @@
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- -I /usr/include/PCSC/ const.go
package scard
type Attrib uint32
const (
AttrVendorName Attrib = 0x10100
AttrVendorIfdType Attrib = 0x10101
AttrVendorIfdVersion Attrib = 0x10102
AttrVendorIfdSerialNo Attrib = 0x10103
AttrChannelId Attrib = 0x20110
AttrAsyncProtocolTypes Attrib = 0x30120
AttrDefaultClk Attrib = 0x30121
AttrMaxClk Attrib = 0x30122
AttrDefaultDataRate Attrib = 0x30123
AttrMaxDataRate Attrib = 0x30124
AttrMaxIfsd Attrib = 0x30125
AttrSyncProtocolTypes Attrib = 0x30126
AttrPowerMgmtSupport Attrib = 0x40131
AttrUserToCardAuthDevice Attrib = 0x50140
AttrUserAuthInputDevice Attrib = 0x50142
AttrCharacteristics Attrib = 0x60150
AttrCurrentProtocolType Attrib = 0x80201
AttrCurrentClk Attrib = 0x80202
AttrCurrentF Attrib = 0x80203
AttrCurrentD Attrib = 0x80204
AttrCurrentN Attrib = 0x80205
AttrCurrentW Attrib = 0x80206
AttrCurrentIfsc Attrib = 0x80207
AttrCurrentIfsd Attrib = 0x80208
AttrCurrentBwt Attrib = 0x80209
AttrCurrentCwt Attrib = 0x8020a
AttrCurrentEbcEncoding Attrib = 0x8020b
AttrExtendedBwt Attrib = 0x8020c
AttrIccPresence Attrib = 0x90300
AttrIccInterfaceStatus Attrib = 0x90301
AttrCurrentIoState Attrib = 0x90302
AttrAtrString Attrib = 0x90303
AttrIccTypePerAtr Attrib = 0x90304
AttrEscReset Attrib = 0x7a000
AttrEscCancel Attrib = 0x7a003
AttrEscAuthrequest Attrib = 0x7a005
AttrMaxinput Attrib = 0x7a007
AttrDeviceUnit Attrib = 0x7fff0001
AttrDeviceInUse Attrib = 0x7fff0002
AttrDeviceFriendlyName Attrib = 0x7fff0003
AttrDeviceSystemName Attrib = 0x7fff0004
AttrSupressT1IfsRequest Attrib = 0x7fff0007
)
type Error uint32
const (
ErrSuccess Error = 0x0
ErrInternalError Error = 0x80100001
ErrCancelled Error = 0x80100002
ErrInvalidHandle Error = 0x80100003
ErrInvalidParameter Error = 0x80100004
ErrInvalidTarget Error = 0x80100005
ErrNoMemory Error = 0x80100006
ErrWaitedTooLong Error = 0x80100007
ErrInsufficientBuffer Error = 0x80100008
ErrUnknownReader Error = 0x80100009
ErrTimeout Error = 0x8010000a
ErrSharingViolation Error = 0x8010000b
ErrNoSmartcard Error = 0x8010000c
ErrUnknownCard Error = 0x8010000d
ErrCantDispose Error = 0x8010000e
ErrProtoMismatch Error = 0x8010000f
ErrNotReady Error = 0x80100010
ErrInvalidValue Error = 0x80100011
ErrSystemCancelled Error = 0x80100012
ErrCommError Error = 0x80100013
ErrUnknownError Error = 0x80100014
ErrInvalidAtr Error = 0x80100015
ErrNotTransacted Error = 0x80100016
ErrReaderUnavailable Error = 0x80100017
ErrShutdown Error = 0x80100018
ErrPciTooSmall Error = 0x80100019
ErrReaderUnsupported Error = 0x8010001a
ErrDuplicateReader Error = 0x8010001b
ErrCardUnsupported Error = 0x8010001c
ErrNoService Error = 0x8010001d
ErrServiceStopped Error = 0x8010001e
ErrUnexpected Error = 0x8010001f
ErrUnsupportedFeature Error = 0x8010001f
ErrIccInstallation Error = 0x80100020
ErrIccCreateorder Error = 0x80100021
ErrFileNotFound Error = 0x80100024
ErrNoDir Error = 0x80100025
ErrNoFile Error = 0x80100026
ErrNoAccess Error = 0x80100027
ErrWriteTooMany Error = 0x80100028
ErrBadSeek Error = 0x80100029
ErrInvalidChv Error = 0x8010002a
ErrUnknownResMng Error = 0x8010002b
ErrNoSuchCertificate Error = 0x8010002c
ErrCertificateUnavailable Error = 0x8010002d
ErrNoReadersAvailable Error = 0x8010002e
ErrCommDataLost Error = 0x8010002f
ErrNoKeyContainer Error = 0x80100030
ErrServerTooBusy Error = 0x80100031
ErrUnsupportedCard Error = 0x80100065
ErrUnresponsiveCard Error = 0x80100066
ErrUnpoweredCard Error = 0x80100067
ErrResetCard Error = 0x80100068
ErrRemovedCard Error = 0x80100069
ErrSecurityViolation Error = 0x8010006a
ErrWrongChv Error = 0x8010006b
ErrChvBlocked Error = 0x8010006c
ErrEof Error = 0x8010006d
ErrCancelledByUser Error = 0x8010006e
ErrCardNotAuthenticated Error = 0x8010006f
)
type Protocol uint32
const (
ProtocolUndefined Protocol = 0x0
ProtocolT0 Protocol = 0x1
ProtocolT1 Protocol = 0x2
ProtocolAny Protocol = ProtocolT0 | ProtocolT1
)
type ShareMode uint32
const (
ShareExclusive ShareMode = 0x1
ShareShared ShareMode = 0x2
ShareDirect ShareMode = 0x3
)
type Disposition uint32
const (
LeaveCard Disposition = 0x0
ResetCard Disposition = 0x1
UnpowerCard Disposition = 0x2
EjectCard Disposition = 0x3
)
type Scope uint32
const (
ScopeUser Scope = 0x0
ScopeTerminal Scope = 0x1
ScopeSystem Scope = 0x2
)
type State uint32
const (
Unknown State = 0x1
Absent State = 0x2
Present State = 0x4
Swallowed State = 0x8
Powered State = 0x10
Negotiable State = 0x20
Specific State = 0x40
)
type StateFlag uint32
const (
StateUnaware StateFlag = 0x0
StateIgnore StateFlag = 0x1
StateChanged StateFlag = 0x2
StateUnknown StateFlag = 0x4
StateUnavailable StateFlag = 0x8
StateEmpty StateFlag = 0x10
StatePresent StateFlag = 0x20
StateAtrmatch StateFlag = 0x40
StateExclusive StateFlag = 0x80
StateInuse StateFlag = 0x100
StateMute StateFlag = 0x200
StateUnpowered StateFlag = 0x400
)
const (
maxBufferSize = 0x108
maxBufferSizeExtended = 0x1000c
maxReadername = 0x80
maxAtrSize = 0x21
)
const (
infiniteTimeout = 0xffffffff
)

21
vendor/github.com/tyler-smith/go-bip39/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Tyler Smith
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

38
vendor/github.com/tyler-smith/go-bip39/README.md generated vendored Normal file
View File

@ -0,0 +1,38 @@
# go-bip39
A golang implementation of the BIP0039 spec for mnemonic seeds
## Credits
English wordlist and test vectors are from the standard Python BIP0039 implementation
from the Trezor guys: [https://github.com/trezor/python-mnemonic](https://github.com/trezor/python-mnemonic)
## Example
```go
package main
import (
"github.com/tyler-smith/go-bip39"
"github.com/tyler-smith/go-bip32"
"fmt"
)
func main(){
// Generate a mnemonic for memorization or user-friendly seeds
entropy, _ := bip39.NewEntropy(256)
mnemonic, _ := bip39.NewMnemonic(entropy)
// Generate a Bip32 HD wallet for the mnemonic and a user supplied password
seed := bip39.NewSeed(mnemonic, "Secret Passphrase")
masterKey, _ := bip32.NewMasterKey(seed)
publicKey := masterKey.PublicKey()
// Display mnemonic and keys
fmt.Println("Mnemonic: ", mnemonic)
fmt.Println("Master private key: ", masterKey)
fmt.Println("Master public key: ", publicKey)
}
```

249
vendor/github.com/tyler-smith/go-bip39/bip39.go generated vendored Normal file
View File

@ -0,0 +1,249 @@
package bip39
import (
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
"encoding/binary"
"errors"
"fmt"
"math/big"
"strings"
"golang.org/x/crypto/pbkdf2"
)
// Some bitwise operands for working with big.Ints
var (
Last11BitsMask = big.NewInt(2047)
RightShift11BitsDivider = big.NewInt(2048)
BigOne = big.NewInt(1)
BigTwo = big.NewInt(2)
)
// NewEntropy will create random entropy bytes
// so long as the requested size bitSize is an appropriate size.
func NewEntropy(bitSize int) ([]byte, error) {
err := validateEntropyBitSize(bitSize)
if err != nil {
return nil, err
}
entropy := make([]byte, bitSize/8)
_, err = rand.Read(entropy)
return entropy, err
}
// NewMnemonic will return a string consisting of the mnemonic words for
// the given entropy.
// If the provide entropy is invalid, an error will be returned.
func NewMnemonic(entropy []byte) (string, error) {
// Compute some lengths for convenience
entropyBitLength := len(entropy) * 8
checksumBitLength := entropyBitLength / 32
sentenceLength := (entropyBitLength + checksumBitLength) / 11
err := validateEntropyBitSize(entropyBitLength)
if err != nil {
return "", err
}
// Add checksum to entropy
entropy = addChecksum(entropy)
// Break entropy up into sentenceLength chunks of 11 bits
// For each word AND mask the rightmost 11 bits and find the word at that index
// Then bitshift entropy 11 bits right and repeat
// Add to the last empty slot so we can work with LSBs instead of MSB
// Entropy as an int so we can bitmask without worrying about bytes slices
entropyInt := new(big.Int).SetBytes(entropy)
// Slice to hold words in
words := make([]string, sentenceLength)
// Throw away big int for AND masking
word := big.NewInt(0)
for i := sentenceLength - 1; i >= 0; i-- {
// Get 11 right most bits and bitshift 11 to the right for next time
word.And(entropyInt, Last11BitsMask)
entropyInt.Div(entropyInt, RightShift11BitsDivider)
// Get the bytes representing the 11 bits as a 2 byte slice
wordBytes := padByteSlice(word.Bytes(), 2)
// Convert bytes to an index and add that word to the list
words[i] = WordList[binary.BigEndian.Uint16(wordBytes)]
}
return strings.Join(words, " "), nil
}
// MnemonicToByteArray takes a mnemonic string and turns it into a byte array
// suitable for creating another mnemonic.
// An error is returned if the mnemonic is invalid.
// FIXME
// This does not work for all values in
// the test vectors. Namely
// Vectors 0, 4, and 8.
// This is not really important because BIP39 doesnt really define a conversion
// from string to bytes.
func MnemonicToByteArray(mnemonic string) ([]byte, error) {
if IsMnemonicValid(mnemonic) == false {
return nil, fmt.Errorf("Invalid mnemonic")
}
mnemonicSlice := strings.Split(mnemonic, " ")
bitSize := len(mnemonicSlice) * 11
err := validateEntropyWithChecksumBitSize(bitSize)
if err != nil {
return nil, err
}
checksumSize := bitSize % 32
b := big.NewInt(0)
modulo := big.NewInt(2048)
for _, v := range mnemonicSlice {
index, found := ReverseWordMap[v]
if found == false {
return nil, fmt.Errorf("Word `%v` not found in reverse map", v)
}
add := big.NewInt(int64(index))
b = b.Mul(b, modulo)
b = b.Add(b, add)
}
hex := b.Bytes()
checksumModulo := big.NewInt(0).Exp(big.NewInt(2), big.NewInt(int64(checksumSize)), nil)
entropy, _ := big.NewInt(0).DivMod(b, checksumModulo, big.NewInt(0))
entropyHex := entropy.Bytes()
byteSize := bitSize/8 + 1
if len(hex) != byteSize {
tmp := make([]byte, byteSize)
diff := byteSize - len(hex)
for i := 0; i < len(hex); i++ {
tmp[i+diff] = hex[i]
}
hex = tmp
}
validationHex := addChecksum(entropyHex)
if len(validationHex) != byteSize {
tmp2 := make([]byte, byteSize)
diff2 := byteSize - len(validationHex)
for i := 0; i < len(validationHex); i++ {
tmp2[i+diff2] = validationHex[i]
}
validationHex = tmp2
}
if len(hex) != len(validationHex) {
panic("[]byte len mismatch - it shouldn't happen")
}
for i := range validationHex {
if hex[i] != validationHex[i] {
return nil, fmt.Errorf("Invalid byte at position %v", i)
}
}
return hex, nil
}
// NewSeedWithErrorChecking creates a hashed seed output given the mnemonic string and a password.
// An error is returned if the mnemonic is not convertible to a byte array.
func NewSeedWithErrorChecking(mnemonic string, password string) ([]byte, error) {
_, err := MnemonicToByteArray(mnemonic)
if err != nil {
return nil, err
}
return NewSeed(mnemonic, password), nil
}
// NewSeed creates a hashed seed output given a provided string and password.
// No checking is performed to validate that the string provided is a valid mnemonic.
func NewSeed(mnemonic string, password string) []byte {
return pbkdf2.Key([]byte(mnemonic), []byte("mnemonic"+password), 2048, 64, sha512.New)
}
// Appends to data the first (len(data) / 32)bits of the result of sha256(data)
// Currently only supports data up to 32 bytes
func addChecksum(data []byte) []byte {
// Get first byte of sha256
hasher := sha256.New()
hasher.Write(data)
hash := hasher.Sum(nil)
firstChecksumByte := hash[0]
// len() is in bytes so we divide by 4
checksumBitLength := uint(len(data) / 4)
// For each bit of check sum we want we shift the data one the left
// and then set the (new) right most bit equal to checksum bit at that index
// staring from the left
dataBigInt := new(big.Int).SetBytes(data)
for i := uint(0); i < checksumBitLength; i++ {
// Bitshift 1 left
dataBigInt.Mul(dataBigInt, BigTwo)
// Set rightmost bit if leftmost checksum bit is set
if uint8(firstChecksumByte&(1<<(7-i))) > 0 {
dataBigInt.Or(dataBigInt, BigOne)
}
}
return dataBigInt.Bytes()
}
func padByteSlice(slice []byte, length int) []byte {
newSlice := make([]byte, length-len(slice))
return append(newSlice, slice...)
}
func validateEntropyBitSize(bitSize int) error {
if (bitSize%32) != 0 || bitSize < 128 || bitSize > 256 {
return errors.New("Entropy length must be [128, 256] and a multiple of 32")
}
return nil
}
func validateEntropyWithChecksumBitSize(bitSize int) error {
if (bitSize != 128+4) && (bitSize != 160+5) && (bitSize != 192+6) && (bitSize != 224+7) && (bitSize != 256+8) {
return fmt.Errorf("Wrong entropy + checksum size - expected %v, got %v", int((bitSize-bitSize%32)+(bitSize-bitSize%32)/32), bitSize)
}
return nil
}
// IsMnemonicValid attempts to verify that the provided mnemonic is valid.
// Validity is determined by both the number of words being appropriate,
// and that all the words in the mnemonic are present in the word list.
func IsMnemonicValid(mnemonic string) bool {
// Create a list of all the words in the mnemonic sentence
words := strings.Fields(mnemonic)
//Get num of words
numOfWords := len(words)
// The number of words should be 12, 15, 18, 21 or 24
if numOfWords%3 != 0 || numOfWords < 12 || numOfWords > 24 {
return false
}
// Check if all words belong in the wordlist
for i := 0; i < numOfWords; i++ {
if !contains(WordList, words[i]) {
return false
}
}
return true
}
func contains(s []string, e string) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}

15
vendor/github.com/tyler-smith/go-bip39/coverage.txt generated vendored Normal file
View File

@ -0,0 +1,15 @@
github.com/CrowBits/go-bip39/bip39.go addChecksum 100.00% (11/11)
github.com/CrowBits/go-bip39/bip39.go IsMnemonicValid 100.00% (8/8)
github.com/CrowBits/go-bip39/bip39.go NewEntropy 100.00% (6/6)
github.com/CrowBits/go-bip39/bip39.go contains 100.00% (4/4)
github.com/CrowBits/go-bip39/bip39.go NewSeedWithErrorChecking 100.00% (4/4)
github.com/CrowBits/go-bip39/bip39.go validateEntropyBitSize 100.00% (3/3)
github.com/CrowBits/go-bip39/bip39.go validateEntropyWithChecksumBitSize 100.00% (3/3)
github.com/CrowBits/go-bip39/bip39.go padByteSlice 100.00% (2/2)
github.com/CrowBits/go-bip39/wordlist.go init 100.00% (2/2)
github.com/CrowBits/go-bip39/bip39.go NewSeed 100.00% (1/1)
github.com/CrowBits/go-bip39/bip39.go NewMnemonic 93.75% (15/16)
github.com/CrowBits/go-bip39/bip39.go MnemonicToByteArray 90.24% (37/41)
github.com/CrowBits/go-bip39 ---------------------------------- 95.05% (96/101)

2067
vendor/github.com/tyler-smith/go-bip39/wordlist.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

18
vendor/vendor.json vendored
View File

@ -103,6 +103,12 @@
"revision": "8e610b2b55bfd1bfa9436ab110d311f5e8a74dcb", "revision": "8e610b2b55bfd1bfa9436ab110d311f5e8a74dcb",
"revisionTime": "2018-06-25T18:44:42Z" "revisionTime": "2018-06-25T18:44:42Z"
}, },
{
"checksumSHA1": "B1sVd5XOmjuSFYivGhBd+vPlc1w=",
"path": "github.com/ebfe/scard",
"revision": "0147d7ead790ac8a5ecc91ee6de68beb7b17c4e9",
"revisionTime": "2017-12-31T19:32:11Z"
},
{ {
"checksumSHA1": "zYnPsNAVm1/ViwCkN++dX2JQhBo=", "checksumSHA1": "zYnPsNAVm1/ViwCkN++dX2JQhBo=",
"path": "github.com/edsrzf/mmap-go", "path": "github.com/edsrzf/mmap-go",
@ -615,6 +621,18 @@
"revision": "a51202d6f4a7e5a219e3841a43614ff7187ae7f1", "revision": "a51202d6f4a7e5a219e3841a43614ff7187ae7f1",
"revisionTime": "2018-06-15T20:27:29Z" "revisionTime": "2018-06-15T20:27:29Z"
}, },
{
"checksumSHA1": "vW7IiPtoA4hQQ/ScHlbmRktY89U=",
"path": "github.com/tyler-smith/go-bip39",
"revision": "8e7a99b3e716f36d3b080a9a70f9eb45abe4edcc",
"revisionTime": "2016-06-29T16:38:56Z"
},
{
"checksumSHA1": "GLCPuvePAkWT+opcWq3mNdhOfGM=",
"path": "github.com/wsddn/go-ecdh",
"revision": "48726bab92085232373de4ec5c51ce7b441c63a0",
"revisionTime": "2016-12-11T03:23:59Z"
},
{ {
"checksumSHA1": "TT1rac6kpQp2vz24m5yDGUNQ/QQ=", "checksumSHA1": "TT1rac6kpQp2vz24m5yDGUNQ/QQ=",
"path": "golang.org/x/crypto/cast5", "path": "golang.org/x/crypto/cast5",