Skip to content

Commit

Permalink
Upgrade to v2 wallet json format
Browse files Browse the repository at this point in the history
Signed-off-by: Yilun <[email protected]>
  • Loading branch information
yilunzhang committed May 8, 2020
1 parent 6a43891 commit 918b551
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 121 deletions.
8 changes: 4 additions & 4 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}()
Expand Down Expand Up @@ -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 {
Expand Down
13 changes: 13 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,24 +159,37 @@ 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
// fields set to default.
func GetDefaultWalletConfig() *WalletConfig {
walletConf := DefaultWalletConfig
walletConf.SeedRPCServerAddr = NewStringArray(DefaultSeedRPCServerAddr...)
walletConf.ScryptConfig = &ScryptConfig{}
return &walletConf
}

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand Down
18 changes: 6 additions & 12 deletions util.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
144 changes: 42 additions & 102 deletions wallet.go
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
}
Expand All @@ -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.
Expand Down

0 comments on commit 918b551

Please sign in to comment.