Skip to content

Commit

Permalink
add new key type to cmd
Browse files Browse the repository at this point in the history
  • Loading branch information
catShaark committed Sep 13, 2021
1 parent a61cedd commit 31dc90b
Show file tree
Hide file tree
Showing 17 changed files with 938 additions and 49 deletions.
Empty file.
1 change: 1 addition & 0 deletions cmd/gnokey/data/keys.db/CURRENT
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
MANIFEST-000000
7 changes: 7 additions & 0 deletions cmd/gnokey/data/keys.db/LOCK
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@







8 changes: 8 additions & 0 deletions cmd/gnokey/data/keys.db/LOG
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
=============== Sep 4, 2021 (+07) ===============

This comment has been minimized.

Copy link
@jaekwon

jaekwon Dec 7, 2021

seems like cmd/gnokey/data should be removed

18:00:07.262699 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
18:00:07.277435 db@open opening
18:00:07.278588 version@stat F·[] S·0B[] Sc·[]
18:00:07.284951 db@janitor F·2 G·0
18:00:07.285021 db@open done T·7.528466ms
18:00:07.285037 db@close closing
18:00:07.285159 db@close done T·115.847µs
Binary file added cmd/gnokey/data/keys.db/MANIFEST-000000
Binary file not shown.
10 changes: 6 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,21 @@ require (
github.com/gdamore/tcell/v2 v2.1.0
github.com/gnolang/cors v1.8.1
github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216
github.com/golang/protobuf v1.5.0
github.com/golang/protobuf v1.5.2
github.com/google/gofuzz v1.0.0
github.com/gorilla/websocket v1.4.2
github.com/jaekwon/testify v1.6.1
github.com/jmhodges/levigo v1.0.0
github.com/libp2p/go-buffer-pool v0.0.2
github.com/mattn/go-runewidth v0.0.10
github.com/pelletier/go-toml v1.9.3 // indirect
github.com/stretchr/testify v1.6.1
github.com/syndtr/goleveldb v1.0.0
github.com/spf13/cobra v1.2.1
github.com/stretchr/testify v1.7.0
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c
github.com/tendermint/classic v0.0.0-20201012085102-0a11024b2668

This comment has been minimized.

Copy link
@jaekwon

jaekwon Dec 7, 2021

can 't import tendermint/classic; all tendermint/classic has been ported into gnolang/gno/pkgs/*, so they must be used instead.

go.etcd.io/bbolt v1.3.6
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/mod v0.4.2
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b
Expand Down
803 changes: 803 additions & 0 deletions go.sum

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pkgs/crypto/keys/armor/armor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func TestArmorUnarmorPubKey(t *testing.T) {
// Add keys and see they return in alphabetical order
mn1 := `lounge napkin all odor tilt dove win inject sleep jazz uncover traffic hint require cargo arm rocket round scan bread report squirrel step lake`
bip39Passphrase := ""
info, err := cstore.CreateAccount("Bob", mn1, bip39Passphrase, "passphrase", 0, 0)
info, err := cstore.CreateAccountBip44("Bob", mn1, bip39Passphrase, "passphrase", 0, 0)
require.NoError(t, err)
astr := armor.ArmorPubKeyBytes(info.GetPubKey().Bytes())
pubBytes, err := armor.UnarmorPubKeyBytes(astr)
Expand Down
59 changes: 48 additions & 11 deletions pkgs/crypto/keys/client/add.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package client

import (
"crypto/sha256"
"fmt"
"sort"

Expand Down Expand Up @@ -28,6 +29,8 @@ type AddOptions struct {
DryRun bool `flag:"dryrun" help:"Perform action, but don't add key to local keystore"`
Account uint32 `flag:"account" help:"Account number for HD derivation"`
Index uint32 `flag:"index" description:"Address index number for HD derivation"`
KeyType string `flag:"type" description:"Type of keys (ed25519|secp256k1)"`
Entropy bool `flag:"entropy" description:"Gen nmenomic from custom entropy"`
}

var DefaultAddOptions = AddOptions{
Expand All @@ -51,6 +54,7 @@ func addApp(cmd *command.Command, args []string, iopts interface{}) error {
var err error
var encryptPassword string
var opts AddOptions = iopts.(AddOptions)
var info keys.Info

if len(args) != 1 {
cmd.ErrPrintfln("Usage: add <keyname>")
Expand Down Expand Up @@ -157,18 +161,49 @@ func addApp(cmd *command.Command, args []string, iopts interface{}) error {
var mnemonic string
const bip39Passphrase string = "" // XXX research.

if opts.Recover && opts.Entropy {
return errors.New("Cannot do both mnemonic generate and mnemonic recover at the same time ")
}

// if user want to recover keys with their mnemonic instead of generating new mnemonic
if opts.Recover {
bip39Message := "Enter your bip39 mnemonic"
mnemonic, err = cmd.GetString(bip39Message)
// Hide mnemonic from output
showMnemonic = false
if err != nil {
return err
}

if !bip39.IsMnemonicValid(mnemonic) {
return errors.New("invalid mnemonic")
}
}

// if user want to gen mnemonic with custom entropy
if opts.Entropy {
// prompt the user to enter some entropy
inputEntropy, err := cmd.GetString("WARNING: Generate at least 256-bits of entropy and enter the results here:")
if err != nil {
return err
}
if len(inputEntropy) < 43 {
return fmt.Errorf("256-bits is 43 characters in Base-64, and 100 in Base-6. You entered %v, and probably want more", len(inputEntropy))
}
conf, err := cmd.GetConfirmation(fmt.Sprintf("Input length: %d", len(inputEntropy)))
if err != nil {
return err
}
if !conf {
return nil
}

// hash input entropy to get entropy seed to get mnemonic
hashedEntropy := sha256.Sum256([]byte(inputEntropy))
entropySeed := hashedEntropy[:]
mnemonic, err = bip39.NewMnemonic(entropySeed[:])
}

// if user don't want to generate nmemonic using custom entropy
if len(mnemonic) == 0 {
// read entropy seed straight from crypto.Rand and convert to mnemonic
entropySeed, err := bip39.NewEntropy(mnemonicEntropySize)
Expand All @@ -182,16 +217,18 @@ func addApp(cmd *command.Command, args []string, iopts interface{}) error {
}
}

info, err := kb.CreateAccount(name, mnemonic, bip39Passphrase, encryptPassword, account, index)
if err != nil {
return err
}

// Recover key from seed passphrase
if opts.Recover {
// Hide mnemonic from output
showMnemonic = false
mnemonic = ""
if opts.KeyType == "secp256k1" {
info, err = kb.CreateAccountBip44(name, mnemonic, bip39Passphrase, encryptPassword, account, index)
if err != nil {
return err
}
} else if opts.KeyType == "ed25519" {
info, err = kb.CreateAccountSha256(name, mnemonic, encryptPassword)
if err != nil {
return err
}
} else {
return fmt.Errorf("invalid key type")
}

return printCreate(cmd, info, showMnemonic, mnemonic)
Expand Down
4 changes: 2 additions & 2 deletions pkgs/crypto/keys/client/delete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ func Test_deleteApp(t *testing.T) {
// Add test accounts to keybase.
kb, err := keys.NewKeyBaseFromDir(opts.Home)
assert.NoError(t, err)
_, err = kb.CreateAccount(fakeKeyName1, testMnemonic, "", "", 0, 0)
_, err = kb.CreateAccountBip44(fakeKeyName1, testMnemonic, "", "", 0, 0)
assert.NoError(t, err)
_, err = kb.CreateAccount(fakeKeyName2, testMnemonic, "", "", 0, 1)
_, err = kb.CreateAccountBip44(fakeKeyName2, testMnemonic, "", "", 0, 1)
assert.NoError(t, err)

// test: Key not found
Expand Down
2 changes: 1 addition & 1 deletion pkgs/crypto/keys/client/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func Test_listApp(t *testing.T) {
// initialize test keybase.
kb, err := keys.NewKeyBaseFromDir(kbHome2)
assert.NoError(t, err)
_, err = kb.CreateAccount("something", testMnemonic, "", "", 0, 0)
_, err = kb.CreateAccountBip44("something", testMnemonic, "", "", 0, 0)
assert.NoError(t, err)

testData := []struct {
Expand Down
2 changes: 1 addition & 1 deletion pkgs/crypto/keys/client/sign_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func Test_signAppBasic(t *testing.T) {
// add test account to keybase.
kb, err := keys.NewKeyBaseFromDir(opts.Home)
assert.NoError(t, err)
_, err = kb.CreateAccount(fakeKeyName1, testMnemonic, "", encPassword, 0, 0)
_, err = kb.CreateAccountBip44(fakeKeyName1, testMnemonic, "", encPassword, 0, 0)
assert.NoError(t, err)

cmd.SetIn(strings.NewReader("XXXDOC"))
Expand Down
2 changes: 1 addition & 1 deletion pkgs/crypto/keys/client/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func Test_verifyAppBasic(t *testing.T) {
// add test account to keybase.
kb, err := keys.NewKeyBaseFromDir(opts.Home)
assert.NoError(t, err)
_, err = kb.CreateAccount(fakeKeyName1, testMnemonic, "", encPassword, 0, 0)
_, err = kb.CreateAccountBip44(fakeKeyName1, testMnemonic, "", encPassword, 0, 0)
assert.NoError(t, err)

// sign test message.
Expand Down
35 changes: 26 additions & 9 deletions pkgs/crypto/keys/keybase.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/gnolang/gno/pkgs/crypto"
"github.com/gnolang/gno/pkgs/crypto/bip39"
"github.com/gnolang/gno/pkgs/crypto/ed25519"
"github.com/gnolang/gno/pkgs/crypto/hd"
"github.com/gnolang/gno/pkgs/crypto/keys/armor"
"github.com/gnolang/gno/pkgs/crypto/keys/keyerror"
Expand Down Expand Up @@ -87,20 +88,31 @@ func NewInMemory() Keybase { return dbKeybase{dbm.NewMemDB()} }
// XXX NOTE: we are not saving the derivation path.
// XXX but this doesn't help encrypted commnuication.
// XXX also there is no document structure.
func (kb dbKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (Info, error) {
func (kb dbKeybase) CreateAccountBip44(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (Info, error) {
coinType := crypto.CoinType
hdPath := hd.NewFundraiserParams(account, coinType, index)
return kb.CreateAccountBip44(name, mnemonic, bip39Passwd, encryptPasswd, *hdPath)
return kb.CreateAccountCustomBip44(name, mnemonic, bip39Passwd, encryptPasswd, *hdPath)
}

func (kb dbKeybase) CreateAccountBip44(name, mnemonic, bip39Passphrase, encryptPasswd string, params hd.BIP44Params) (info Info, err error) {
func (kb dbKeybase) CreateAccountSha256(name, mnemonic, encryptPasswd string) (info Info, err error) {
mnemonicByte, err := bip39.MnemonicToByteArray(mnemonic)
if err != nil {
return nil, err
}
var privKeyByte [64]byte
copy(privKeyByte[:], mnemonicByte[:64])

This comment has been minimized.

Copy link
@jaekwon

jaekwon Dec 7, 2021

I think we after this need to inject some sha256-based KDF before persisting the key. here

info, err = kb.persistDerivedEd25519Key(privKeyByte, name, encryptPasswd)
return info, err
}

func (kb dbKeybase) CreateAccountCustomBip44(name, mnemonic, bip39Passphrase, encryptPasswd string, params hd.BIP44Params) (info Info, err error) {
seed, err := bip39.NewSeedWithErrorChecking(mnemonic, bip39Passphrase)
if err != nil {
return
return nil, err
}

info, err = kb.persistDerivedKey(seed, encryptPasswd, name, params.String())
return
info, err = kb.persistDerivedSecp256k1Key(seed, encryptPasswd, name, params.String())
return info, err
}

// CreateLedger creates a new locally-stored reference to a Ledger keypair
Expand Down Expand Up @@ -134,18 +146,23 @@ func (kb dbKeybase) CreateMulti(name string, pub crypto.PubKey) (Info, error) {
return kb.writeMultisigKey(name, pub), nil
}

func (kb *dbKeybase) persistDerivedKey(seed []byte, passwd, name, fullHdPath string) (info Info, err error) {
func (kb *dbKeybase) persistDerivedEd25519Key(privKey [64]byte, passwd, name string) (info Info, err error) {
info = kb.writeLocalKey(name, ed25519.PrivKeyEd25519(privKey), passwd)
return info, nil
}

func (kb *dbKeybase) persistDerivedSecp256k1Key(seed []byte, passwd, name, fullHdPath string) (info Info, err error) {
// create master key and derive first key:
masterPriv, ch := hd.ComputeMastersFromSeed(seed)
derivedPriv, err := hd.DerivePrivateKeyForPath(masterPriv, ch, fullHdPath)
if err != nil {
return
return nil, err
}

// use possibly blank password to encrypt the private
// key and store it. User must enforce good passwords.
info = kb.writeLocalKey(name, secp256k1.PrivKeySecp256k1(derivedPriv), passwd)
return
return info, nil
}

// List returns the keys from storage in alphabetical order.
Expand Down
24 changes: 12 additions & 12 deletions pkgs/crypto/keys/keybase_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (

func TestCreateAccountInvalidMnemonic(t *testing.T) {
kb := NewInMemory()
_, err := kb.CreateAccount(
_, err := kb.CreateAccountBip44(
"some_account",
"malarkey pair crucial catch public canyon evil outer stage ten gym tornado",
"", "", 0, 1)
Expand Down Expand Up @@ -83,10 +83,10 @@ func TestKeyManagement(t *testing.T) {
// create some keys
_, err = cstore.Get(n1)
require.Error(t, err)
i, err := cstore.CreateAccount(n1, mn1, bip39Passphrase, p1, 0, 0)
i, err := cstore.CreateAccountBip44(n1, mn1, bip39Passphrase, p1, 0, 0)
require.NoError(t, err)
require.Equal(t, n1, i.GetName())
_, err = cstore.CreateAccount(n2, mn2, bip39Passphrase, p2, 0, 0)
_, err = cstore.CreateAccountBip44(n2, mn2, bip39Passphrase, p2, 0, 0)
require.NoError(t, err)

// we can get these keys
Expand Down Expand Up @@ -157,10 +157,10 @@ func TestSignVerify(t *testing.T) {
bip39Passphrase := ""

// create two users and get their info
i1, err := cstore.CreateAccount(n1, mn1, bip39Passphrase, p1, 0, 0)
i1, err := cstore.CreateAccountBip44(n1, mn1, bip39Passphrase, p1, 0, 0)
require.Nil(t, err)

i2, err := cstore.CreateAccount(n2, mn2, bip39Passphrase, p2, 0, 0)
i2, err := cstore.CreateAccountBip44(n2, mn2, bip39Passphrase, p2, 0, 0)
require.Nil(t, err)

// Import a public key
Expand Down Expand Up @@ -238,7 +238,7 @@ func TestExportImport(t *testing.T) {
mn1 := `lounge napkin all odor tilt dove win inject sleep jazz uncover traffic hint require cargo arm rocket round scan bread report squirrel step lake`
bip39Passphrase := ""

info, err := cstore.CreateAccount("john", mn1, bip39Passphrase, "secretcpw", 0, 0)
info, err := cstore.CreateAccountBip44("john", mn1, bip39Passphrase, "secretcpw", 0, 0)
require.NoError(t, err)
require.Equal(t, info.GetName(), "john")

Expand Down Expand Up @@ -270,7 +270,7 @@ func TestExportImportPubKey(t *testing.T) {
mn1 := `lounge napkin all odor tilt dove win inject sleep jazz uncover traffic hint require cargo arm rocket round scan bread report squirrel step lake`
bip39Passphrase := ""
notPasswd := "n9y25ah7"
info, err := cstore.CreateAccount("john", mn1, bip39Passphrase, notPasswd, 0, 0)
info, err := cstore.CreateAccountBip44("john", mn1, bip39Passphrase, notPasswd, 0, 0)
require.Nil(t, err)
require.NotEqual(t, info, "")
require.Equal(t, info.GetName(), "john")
Expand Down Expand Up @@ -313,7 +313,7 @@ func TestAdvancedKeyManagement(t *testing.T) {
bip39Passphrase := ""

// make sure key works with initial password
_, err := cstore.CreateAccount(n1, mn1, bip39Passphrase, p1, 0, 0)
_, err := cstore.CreateAccountBip44(n1, mn1, bip39Passphrase, p1, 0, 0)
require.Nil(t, err, "%+v", err)
assertPassword(t, cstore, n1, p1, p2)

Expand Down Expand Up @@ -362,7 +362,7 @@ func TestSeedPhrase(t *testing.T) {
bip39Passphrase := ""

// make sure key works with initial password
info, err := cstore.CreateAccount(n1, mn1, bip39Passphrase, p1, 0, 0)
info, err := cstore.CreateAccountBip44(n1, mn1, bip39Passphrase, p1, 0, 0)
require.Nil(t, err, "%+v", err)
require.Equal(t, n1, info.GetName())

Expand All @@ -383,16 +383,16 @@ func ExampleNew() {
bip39Passphrase := ""

// Add keys and see they return in alphabetical order
bob, err := cstore.CreateAccount("Bob", mn1, bip39Passphrase, "friend", 0, 0)
bob, err := cstore.CreateAccountBip44("Bob", mn1, bip39Passphrase, "friend", 0, 0)
if err != nil {
// this should never happen
fmt.Println(err)
} else {
// return info here just like in List
fmt.Println(bob.GetName())
}
_, _ = cstore.CreateAccount("Alice", mn2, bip39Passphrase, "secret", 0, 0)
_, _ = cstore.CreateAccount("Carl", mn3, bip39Passphrase, "mitm", 0, 0)
_, _ = cstore.CreateAccountBip44("Alice", mn2, bip39Passphrase, "secret", 0, 0)
_, _ = cstore.CreateAccountBip44("Carl", mn3, bip39Passphrase, "mitm", 0, 0)
info, _ := cstore.List()
for _, i := range info {
fmt.Println(i.GetName())
Expand Down
Loading

0 comments on commit 31dc90b

Please sign in to comment.