Skip to content

Commit

Permalink
fix readline trailing \n; remove CreateMnemonic()
Browse files Browse the repository at this point in the history
  • Loading branch information
jaekwon committed Jul 28, 2021
1 parent 63f0c9e commit 8e7254d
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 495 deletions.
4 changes: 2 additions & 2 deletions pkgs/command/prompt.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func (cmd *Command) readLineFromInBuf() (string, error) {
if err != nil {
return "", err
}
return strings.TrimSpace(pass), nil
return pass[:len(pass)-1], nil
}

func (cmd *Command) readPasswordFromInBuf() (string, error) {
Expand All @@ -104,7 +104,7 @@ func (cmd *Command) readPasswordFromInBuf() (string, error) {
if err != nil {
return "", err
}
pass = s
pass = s[:len(s)-1]
}

return pass, nil
Expand Down
26 changes: 6 additions & 20 deletions pkgs/crypto/keys/armor/armor.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,12 @@ import (
)

const (
blockTypePrivKey = "TENDERMINT PRIVATE KEY"
blockTypeKeyInfo = "TENDERMINT KEY INFO"
blockTypePubKey = "TENDERMINT PUBLIC KEY"
blockTypePrivKey = "TENDERMINT PRIVATE KEY"
blockTypeKeyInfo = "TENDERMINT KEY INFO"
blockTypePubKey = "TENDERMINT PUBLIC KEY"
bcryptSecurityParameter = 12
)

// Make bcrypt security parameter var, so it can be changed within the lcd test
// Making the bcrypt security parameter a var shouldn't be a security issue:
// One can't verify an invalid key by maliciously changing the bcrypt
// parameter during a runtime vulnerability. The main security
// threat this then exposes would be something that changes this during
// runtime before the user creates their key. This vulnerability must
// succeed to update this to that same value before every subsequent call
// to the keys command in future startups / or the attacker must get access
// to the filesystem. However, with a similar threat model (changing
// variables in runtime), one can cause the user to sign a different tx
// than what they see, which is a significantly cheaper attack then breaking
// a bcrypt hash. (Recall that the nonce still exists to break rainbow tables)
// For further notes on security parameter choice, see README.md
var BcryptSecurityParameter = 12

//-----------------------------------------------------------------
// add armor

Expand Down Expand Up @@ -102,7 +88,7 @@ func EncryptArmorPrivKey(privKey crypto.PrivKey, passphrase string) string {
// encrypted priv key.
func encryptPrivKey(privKey crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte) {
saltBytes = crypto.CRandBytes(16)
key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), BcryptSecurityParameter)
key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), bcryptSecurityParameter)
if err != nil {
os.Exit("Error generating bcrypt key from passphrase: " + err.Error())
}
Expand Down Expand Up @@ -136,7 +122,7 @@ func UnarmorDecryptPrivKey(armorStr string, passphrase string) (crypto.PrivKey,
}

func decryptPrivKey(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) {
key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), BcryptSecurityParameter)
key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), bcryptSecurityParameter)
if err != nil {
os.Exit("Error generating bcrypt key from passphrase: " + err.Error())
}
Expand Down
4 changes: 3 additions & 1 deletion pkgs/crypto/keys/armor/armor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ func TestArmorUnarmorPubKey(t *testing.T) {
cstore := keys.NewInMemory()

// Add keys and see they return in alphabetical order
info, _, err := cstore.CreateMnemonic("Bob", keys.English, "passphrase", keys.Secp256k1)
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)
require.NoError(t, err)
astr := armor.ArmorPubKeyBytes(info.GetPubKey().Bytes())
pubBytes, err := armor.UnarmorPubKeyBytes(astr)
Expand Down
40 changes: 7 additions & 33 deletions pkgs/crypto/keys/keybase.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,45 +81,19 @@ func NewDBKeybase(db dbm.DB) Keybase {
// instance useful for testing purposes and on-the-fly key generation.
func NewInMemory() Keybase { return dbKeybase{dbm.NewMemDB()} }

// CreateMnemonic generates a new key and persists it to storage, encrypted
// using the provided password.
// It returns the generated mnemonic and the key Info.
// It returns an error if it fails to
// generate a key for the given algo type, or if another key is
// already stored under the same name.
func (kb dbKeybase) CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, mnemonic string, err error) {
if language != English {
return nil, "", ErrUnsupportedLanguage
}
if algo != Secp256k1 {
err = ErrUnsupportedSigningAlgo
return
}

// default number of words (24):
// this generates a mnemonic directly from the number of words by reading system entropy.
entropy, err := bip39.NewEntropy(defaultEntropySize)
if err != nil {
return
}
mnemonic, err = bip39.NewMnemonic(entropy)
if err != nil {
return
}

seed := bip39.NewSeed(mnemonic, DefaultBIP39Passphrase)
info, err = kb.persistDerivedKey(seed, passwd, name, crypto.Bip44DefaultPath)
return
}

// CreateAccount converts a mnemonic to a private key and persists it, encrypted with the given password.
// XXX Info could include the separately derived ed25519 key,
// XXX and a signature from the sec2561key as certificate.
// 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) {
coinType := crypto.CoinType
hdPath := hd.NewFundraiserParams(account, coinType, index)
return kb.Derive(name, mnemonic, bip39Passwd, encryptPasswd, *hdPath)
return kb.CreateAccountBip44(name, mnemonic, bip39Passwd, encryptPasswd, *hdPath)
}

func (kb dbKeybase) Derive(name, mnemonic, bip39Passphrase, encryptPasswd string, params hd.BIP44Params) (info Info, err error) {
func (kb dbKeybase) CreateAccountBip44(name, mnemonic, bip39Passphrase, encryptPasswd string, params hd.BIP44Params) (info Info, err error) {
seed, err := bip39.NewSeedWithErrorChecking(mnemonic, bip39Passphrase)
if err != nil {
return
Expand Down
79 changes: 33 additions & 46 deletions pkgs/crypto/keys/keybase_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,8 @@ import (

"github.com/gnolang/gno/pkgs/crypto"
"github.com/gnolang/gno/pkgs/crypto/ed25519"
"github.com/gnolang/gno/pkgs/crypto/hd"
"github.com/gnolang/gno/pkgs/crypto/keys/mintkey"
)

func init() {
mintkey.BcryptSecurityParameter = 1
}

func TestLanguage(t *testing.T) {
kb := NewInMemory()
_, _, err := kb.CreateMnemonic("something", Japanese, "no_pass", Secp256k1)
assert.Error(t, err)
assert.Equal(t, "unsupported language: only english is supported", err.Error())
}

func TestCreateAccountInvalidMnemonic(t *testing.T) {
kb := NewInMemory()
_, err := kb.CreateAccount(
Expand Down Expand Up @@ -82,26 +69,24 @@ func TestKeyManagement(t *testing.T) {
// make the storage with reasonable defaults
cstore := NewInMemory()

algo := Secp256k1
n1, n2, n3 := "personal", "business", "other"
p1, p2 := "1234", "really-secure!@#$"
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`
mn2 := `lecture salt about avocado smooth height escape general arch head barrel clutch dismiss supply doctor project cat truck fruit abuse gorilla symbol portion glare`
bip39Passphrase := ""

// Check empty state
l, err := cstore.List()
require.Nil(t, err)
assert.Empty(t, l)

_, _, err = cstore.CreateMnemonic(n1, English, p1, Ed25519)
require.Error(t, err, "ed25519 keys are currently not supported by keybase")

// create some keys
_, err = cstore.Get(n1)
require.Error(t, err)
i, _, err := cstore.CreateMnemonic(n1, English, p1, algo)

i, err := cstore.CreateAccount(n1, mn1, bip39Passphrase, p1, 0, 0)
require.NoError(t, err)
require.Equal(t, n1, i.GetName())
_, _, err = cstore.CreateMnemonic(n2, English, p2, algo)
_, err = cstore.CreateAccount(n2, mn2, bip39Passphrase, p2, 0, 0)
require.NoError(t, err)

// we can get these keys
Expand Down Expand Up @@ -164,16 +149,18 @@ func TestKeyManagement(t *testing.T) {
// signatures
func TestSignVerify(t *testing.T) {
cstore := NewInMemory()
algo := Secp256k1

n1, n2, n3 := "some dude", "a dudette", "dude-ish"
p1, p2, p3 := "1234", "foobar", "foobar"
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`
mn2 := `lecture salt about avocado smooth height escape general arch head barrel clutch dismiss supply doctor project cat truck fruit abuse gorilla symbol portion glare`
bip39Passphrase := ""

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

i2, _, err := cstore.CreateMnemonic(n2, English, p2, algo)
i2, err := cstore.CreateAccount(n2, mn2, bip39Passphrase, p2, 0, 0)
require.Nil(t, err)

// Import a public key
Expand Down Expand Up @@ -248,7 +235,10 @@ func TestExportImport(t *testing.T) {
// make the storage with reasonable defaults
cstore := NewInMemory()

info, _, err := cstore.CreateMnemonic("john", English, "secretcpw", Secp256k1)
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)
require.NoError(t, err)
require.Equal(t, info.GetName(), "john")

Expand Down Expand Up @@ -276,9 +266,11 @@ func TestExportImportPubKey(t *testing.T) {
// make the storage with reasonable defaults
cstore := NewInMemory()

// CreateMnemonic a private-public key pair and ensure consistency
// CreateAccount a private-public key pair and ensure consistency
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.CreateMnemonic("john", English, notPasswd, Secp256k1)
info, err := cstore.CreateAccount("john", mn1, bip39Passphrase, notPasswd, 0, 0)
require.Nil(t, err)
require.NotEqual(t, info, "")
require.Equal(t, info.GetName(), "john")
Expand Down Expand Up @@ -315,12 +307,13 @@ func TestAdvancedKeyManagement(t *testing.T) {
// make the storage with reasonable defaults
cstore := NewInMemory()

algo := Secp256k1
n1, n2 := "old-name", "new name"
p1, p2 := "1234", "foobar"
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 := ""

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

Expand Down Expand Up @@ -363,49 +356,43 @@ func TestSeedPhrase(t *testing.T) {
// make the storage with reasonable defaults
cstore := NewInMemory()

algo := Secp256k1
n1, n2 := "lost-key", "found-again"
p1, p2 := "1234", "foobar"
n1 := "lost-key"
p1 := "1234"
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 := ""

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

// now, let us delete this key
err = cstore.Delete(n1, p1, false)
require.Nil(t, err, "%+v", err)
_, err = cstore.Get(n1)
require.NotNil(t, err)

// let us re-create it from the mnemonic-phrase
testCoinType := uint32(118)
params := *hd.NewFundraiserParams(0, testCoinType, 0)
newInfo, err := cstore.Derive(n2, mnemonic, DefaultBIP39Passphrase, p2, params)
require.NoError(t, err)
require.Equal(t, n2, newInfo.GetName())
require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address())
require.Equal(t, info.GetPubKey(), newInfo.GetPubKey())
}

func ExampleNew() {
// Select the encryption and storage for your cryptostore
cstore := NewInMemory()

sec := Secp256k1
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`
mn2 := `lecture salt about avocado smooth height escape general arch head barrel clutch dismiss supply doctor project cat truck fruit abuse gorilla symbol portion glare`
mn3 := `jar nest rug lion shallow spring abuse west gravity skin project comic again dirt pelican better galaxy click hold lottery swap solution census own`
bip39Passphrase := ""

// Add keys and see they return in alphabetical order
bob, _, err := cstore.CreateMnemonic("Bob", English, "friend", sec)
bob, err := cstore.CreateAccount("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.CreateMnemonic("Alice", English, "secret", sec)
_, _, _ = cstore.CreateMnemonic("Carl", English, "mitm", sec)
_, _ = cstore.CreateAccount("Alice", mn2, bip39Passphrase, "secret", 0, 0)
_, _ = cstore.CreateAccount("Carl", mn3, bip39Passphrase, "mitm", 0, 0)
info, _ := cstore.List()
for _, i := range info {
fmt.Println(i.GetName())
Expand Down
14 changes: 2 additions & 12 deletions pkgs/crypto/keys/lazy_keybase.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,6 @@ func (lkb lazyKeybase) Verify(name string, msg, sig []byte) error {
return NewDBKeybase(db).Verify(name, msg, sig)
}

func (lkb lazyKeybase) CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, seed string, err error) {
db, err := dbm.NewGoLevelDB(lkb.name, lkb.dir)
if err != nil {
return nil, "", err
}
defer db.Close()

return NewDBKeybase(db).CreateMnemonic(name, language, passwd, algo)
}

func (lkb lazyKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (Info, error) {
db, err := dbm.NewGoLevelDB(lkb.name, lkb.dir)
if err != nil {
Expand All @@ -105,14 +95,14 @@ func (lkb lazyKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd
return NewDBKeybase(db).CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, account, index)
}

func (lkb lazyKeybase) Derive(name, mnemonic, bip39Passwd, encryptPasswd string, params hd.BIP44Params) (Info, error) {
func (lkb lazyKeybase) CreateAccountBip44(name, mnemonic, bip39Passwd, encryptPasswd string, params hd.BIP44Params) (Info, error) {
db, err := dbm.NewGoLevelDB(lkb.name, lkb.dir)
if err != nil {
return nil, err
}
defer db.Close()

return NewDBKeybase(db).Derive(name, mnemonic, bip39Passwd, encryptPasswd, params)
return NewDBKeybase(db).CreateAccountBip44(name, mnemonic, bip39Passwd, encryptPasswd, params)
}

func (lkb lazyKeybase) CreateLedger(name string, algo SigningAlgo, hrp string, account, index uint32) (info Info, err error) {
Expand Down
Loading

0 comments on commit 8e7254d

Please sign in to comment.