From 918b55119995e7429e4338728f6e3cd526e07e2b Mon Sep 17 00:00:00 2001 From: Yilun Date: Thu, 7 May 2020 01:59:53 -0700 Subject: [PATCH] Upgrade to v2 wallet json format Signed-off-by: Yilun --- client.go | 8 +-- config.go | 13 +++++ go.mod | 2 +- go.sum | 6 ++- util.go | 18 +++---- wallet.go | 144 ++++++++++++++++-------------------------------------- 6 files changed, 70 insertions(+), 121 deletions(-) diff --git a/client.go b/client.go index f1b55237..a80c49d5 100644 --- a/client.go +++ b/client.go @@ -420,9 +420,9 @@ func (c *Client) handleMessage(msgType int, data []byte) error { return err } - if len(inboundMsg.PrevSignature) > 0 { + if len(inboundMsg.PrevHash) > 0 { go func() { - if err := c.sendReceipt(inboundMsg.PrevSignature); err != nil { + if err := c.sendReceipt(inboundMsg.PrevHash); err != nil { log.Println(err) } }() @@ -700,8 +700,8 @@ func (c *Client) sendReceipt(prevSignature []byte) error { } receipt := &pb.Receipt{ - PrevSignature: prevSignature, - Signature: signature, + PrevHash: prevSignature, + Signature: signature, } receiptData, err := proto.Marshal(receipt) if err != nil { diff --git a/config.go b/config.go index 09f2be91..657f550f 100644 --- a/config.go +++ b/config.go @@ -159,17 +159,29 @@ func GetDefaultDialConfig(baseSessionConfig *ncp.Config) *DialConfig { return &dialConf } +// ScryptConfig is the scrypt configuration. +type ScryptConfig struct { + Salt []byte + N int + R int + P int +} + // WalletConfig is the wallet configuration. type WalletConfig struct { SeedRPCServerAddr *StringArray Password string IV []byte MasterKey []byte + ScryptConfig *ScryptConfig } // DefaultWalletConfig is the default wallet configuration. var DefaultWalletConfig = WalletConfig{ SeedRPCServerAddr: nil, + IV: nil, + MasterKey: nil, + ScryptConfig: nil, } // GetDefaultWalletConfig returns the default wallet config with nil pointer @@ -177,6 +189,7 @@ var DefaultWalletConfig = WalletConfig{ func GetDefaultWalletConfig() *WalletConfig { walletConf := DefaultWalletConfig walletConf.SeedRPCServerAddr = NewStringArray(DefaultSeedRPCServerAddr...) + walletConf.ScryptConfig = &ScryptConfig{} return &walletConf } diff --git a/go.mod b/go.mod index 28b0a4c7..a243ae0e 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/itchyny/base58-go v0.1.0 // indirect github.com/nknorg/consequential v0.0.0-20191113113929-5fd13b7f5984 // indirect github.com/nknorg/ncp-go v0.0.0-20200211003710-7d840c67ad9a - github.com/nknorg/nkn v1.1.6-beta.0.20200421021041-94637b061691 + github.com/nknorg/nkn v1.1.7-beta.0.20200508191852-5f3b0f1ddca2 github.com/patrickmn/go-cache v2.1.0+incompatible golang.org/x/crypto v0.0.0-20200406173513-056763e48d71 ) diff --git a/go.sum b/go.sum index bd914449..5328221a 100644 --- a/go.sum +++ b/go.sum @@ -104,8 +104,8 @@ github.com/nknorg/go-portscanner v0.0.0-20181002101859-8493ef01db79 h1:AT5YRim06 github.com/nknorg/go-portscanner v0.0.0-20181002101859-8493ef01db79/go.mod h1:lTev9/EZpc4U3w/sp95T8UPeaav/0Hk+JjykVDuPaQs= github.com/nknorg/ncp-go v0.0.0-20200211003710-7d840c67ad9a h1:3uodemsadDicySAj76O7MRDmSSuR788YNyFFi5eDtAI= github.com/nknorg/ncp-go v0.0.0-20200211003710-7d840c67ad9a/go.mod h1:LfiwrFlKZAAoMwhCBA959jSzVD8E9RGOH9nyfXkQSfY= -github.com/nknorg/nkn v1.1.6-beta.0.20200421021041-94637b061691 h1:gcjPG5UqJUlFzpHWSz2Rs2xTHr7wugzru458LMDqskE= -github.com/nknorg/nkn v1.1.6-beta.0.20200421021041-94637b061691/go.mod h1:TBjYy6L84CwDpX4sU7rvR95UyqLS3l/jwWCpWh0Qn/w= +github.com/nknorg/nkn v1.1.7-beta.0.20200508191852-5f3b0f1ddca2 h1:9ag+UBR8QzJQgP5xg7zwAeqV3KAOrCae4CqH6zmue+o= +github.com/nknorg/nkn v1.1.7-beta.0.20200508191852-5f3b0f1ddca2/go.mod h1:ucbvc8OwUzCJVe0tTvYvU5NGxj2qyCSjwFUrJVkWTMI= github.com/nknorg/nnet v0.0.0-20200410235204-23cc169e8564 h1:ti9VeFaELvkk9mO2oUgm6SN+jUM1JJLblN+qetJMzmk= github.com/nknorg/nnet v0.0.0-20200410235204-23cc169e8564/go.mod h1:4DHEQEMhlRGIKGSyhATdjeusdqaHafDatadtpeHBpvI= github.com/nknorg/portmapper v0.0.0-20200114081049-1c03cdccc283 h1:uS3/DvxCbi0zZau66ggQAgEjyGmql2mj77UQFgumq1I= @@ -190,6 +190,8 @@ golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/util.go b/util.go index 7677cb4b..7b360835 100644 --- a/util.go +++ b/util.go @@ -30,19 +30,13 @@ type Account struct{ *vault.Account } // NewAccount creates an account from secret seed. Seed length should be 32 or // 0. If seed has zero length (including nil), a random seed will be generated. func NewAccount(seed []byte) (*Account, error) { - if len(seed) == 0 { - account, err := vault.NewAccount() - return &Account{account}, err - } - - err := crypto.CheckSeed(seed) - if err != nil { - return nil, err + var account *vault.Account + var err error + if len(seed) > 0 { + account, err = vault.NewAccountWithSeed(seed) + } else { + account, err = vault.NewAccount() } - - privateKey := crypto.GetPrivateKeyFromSeed(seed) - - account, err := vault.NewAccountWithPrivatekey(privateKey) if err != nil { return nil, err } diff --git a/wallet.go b/wallet.go index 93aaac4c..27e661a6 100644 --- a/wallet.go +++ b/wallet.go @@ -1,13 +1,10 @@ package nkn import ( - "bytes" - "crypto/sha256" "encoding/hex" "encoding/json" "github.com/nknorg/nkn/common" - "github.com/nknorg/nkn/crypto" "github.com/nknorg/nkn/pb" "github.com/nknorg/nkn/program" "github.com/nknorg/nkn/signature" @@ -18,14 +15,10 @@ import ( // Wallet manages assets, query state from blockchain, and send transactions to // blockchain. type Wallet struct { - config *WalletConfig - account *Account - address string - seedEncrypted []byte - iv []byte - masterKeyEncrypted []byte - passwordHash []byte - contractData []byte + config *WalletConfig + account *Account + address string + walletData *vault.WalletData } // NewWallet creates a wallet from an account and an optional config. For any @@ -45,49 +38,25 @@ func NewWallet(account *Account, config *WalletConfig) (*Wallet, error) { config.MasterKey = nil }() - iv := config.IV - if iv == nil { - iv, err = RandomBytes(vault.WalletIVLength) - if err != nil { - return nil, err - } - } - - masterKey := config.MasterKey - if masterKey == nil { - masterKey, err = RandomBytes(vault.WalletMasterKeyLength) - if err != nil { - return nil, err - } - } - - passwordKey := crypto.ToAesKey([]byte(config.Password)) - passwordHash := sha256.Sum256(passwordKey) - - seedEncrypted, err := crypto.AesEncrypt(account.Seed(), masterKey, iv) - if err != nil { - return nil, err - } - - masterKeyEncrypted, err := crypto.AesEncrypt(masterKey, passwordKey, iv) - if err != nil { - return nil, err - } - - contract, err := program.CreateSignatureProgramContext(account.Account.PubKey()) + walletData, err := vault.NewWalletData( + account.Account, + []byte(config.Password), + config.MasterKey, + config.IV, + config.ScryptConfig.Salt, + config.ScryptConfig.N, + config.ScryptConfig.R, + config.ScryptConfig.P, + ) if err != nil { return nil, err } wallet := &Wallet{ - config: config, - account: account, - address: account.WalletAddress(), - seedEncrypted: seedEncrypted, - iv: iv, - masterKeyEncrypted: masterKeyEncrypted, - passwordHash: passwordHash[:], - contractData: contract.ToArray(), + config: config, + account: account, + address: account.WalletAddress(), + walletData: walletData, } return wallet, nil @@ -96,85 +65,58 @@ func NewWallet(account *Account, config *WalletConfig) (*Wallet, error) { // WalletFromJSON recovers a wallet from wallet JSON and wallet config. The // password in config must match the password used to create the wallet. func WalletFromJSON(walletJSON string, config *WalletConfig) (*Wallet, error) { - walletData := &vault.WalletData{} - err := json.Unmarshal([]byte(walletJSON), walletData) - if err != nil { - return nil, err - } - - if walletData.Version < vault.MinCompatibleWalletVersion || walletData.Version > vault.MaxCompatibleWalletVersion { - return nil, ErrInvalidWalletVersion - } - - if config == nil { - config = &WalletConfig{} - } - - passwordKey := crypto.ToAesKey([]byte(config.Password)) - passwordKeyHash, err := hex.DecodeString(walletData.PasswordHash) + config, err := MergeWalletConfig(config) if err != nil { return nil, err } - pkh := sha256.Sum256(passwordKey) - if !bytes.Equal(pkh[:], passwordKeyHash) { - return nil, ErrWrongPassword - } - iv, err := hex.DecodeString(walletData.IV) - if err != nil { - return nil, err - } + defer func() { + config.Password = "" + config.MasterKey = nil + }() - masterKeyEncrypted, err := hex.DecodeString(walletData.MasterKey) + walletData := &vault.WalletData{} + err = json.Unmarshal([]byte(walletJSON), walletData) if err != nil { return nil, err } - masterKey, err := crypto.AesDecrypt(masterKeyEncrypted, passwordKey, iv) - if err != nil { - return nil, err + if walletData.Version < vault.MinCompatibleWalletVersion || walletData.Version > vault.MaxCompatibleWalletVersion { + return nil, ErrInvalidWalletVersion } - seedEncrypted, err := hex.DecodeString(walletData.SeedEncrypted) + iv, err := hex.DecodeString(walletData.IV) if err != nil { return nil, err } - seed, err := crypto.AesDecrypt(seedEncrypted, masterKey, iv) + masterKey, err := walletData.DecryptMasterKey([]byte(config.Password)) if err != nil { return nil, err } - account, err := NewAccount(seed) + account, err := walletData.DecryptAccount([]byte(config.Password)) if err != nil { return nil, err } - configCopy := *config - configCopy.IV = iv - configCopy.MasterKey = masterKey + config.IV = iv + config.MasterKey = masterKey - return NewWallet(account, &configCopy) + return NewWallet(&Account{account}, config) } -// ToJSON serialize the wallet to JSON string encrypted by password used to +// MarshalJSON serialize the wallet to JSON string encrypted by password used to // create the wallet. The same password must be used to recover the wallet from // JSON string. +func (w *Wallet) MarshalJSON() ([]byte, error) { + return json.Marshal(w.walletData) +} + +// ToJSON is a shortcut for wallet.MarshalJSON, but returns string instead of +// bytes. func (w *Wallet) ToJSON() (string, error) { - b, err := json.Marshal(vault.WalletData{ - HeaderData: vault.HeaderData{ - PasswordHash: hex.EncodeToString(w.passwordHash), - IV: hex.EncodeToString(w.iv), - MasterKey: hex.EncodeToString(w.masterKeyEncrypted), - Version: vault.WalletVersion, - }, - AccountData: vault.AccountData{ - Address: w.address, - ProgramHash: w.account.ProgramHash.ToHexString(), - SeedEncrypted: hex.EncodeToString(w.seedEncrypted), - ContractData: hex.EncodeToString(w.contractData), - }, - }) + b, err := w.MarshalJSON() if err != nil { return "", err } @@ -200,9 +142,7 @@ func (w *Wallet) Address() string { // VerifyPassword returns whether a password is the correct password of this // wallet. func (w *Wallet) VerifyPassword(password string) bool { - passwordKey := crypto.ToAesKey([]byte(password)) - passwordHash := sha256.Sum256(passwordKey) - return bytes.Equal(passwordHash[:], w.passwordHash) + return w.walletData.VerifyPassword([]byte(password)) == nil } // ProgramHash returns the program hash of this wallet's account.