Skip to content

Commit

Permalink
Merge pull request #6 from Bit-Nation/feature/open_with_mnemonic
Browse files Browse the repository at this point in the history
Feature/open with mnemonic
  • Loading branch information
florianlenz authored Apr 17, 2018
2 parents f2f5a06 + c95149a commit 34b1aeb
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 16 deletions.
74 changes: 63 additions & 11 deletions keyManager/keyManager.go
Original file line number Diff line number Diff line change
@@ -1,51 +1,103 @@
package keyManager

import (
"encoding/json"
"errors"
crypto "github.com/Bit-Nation/panthalassa/crypto"
ks "github.com/Bit-Nation/panthalassa/keyStore"
)

type KeyManager struct {
keyStore *ks.KeyStore
account accountKeyStore
}

//Open an encrypted key store file
func Open(encryptedKeyStore, pw string) (*KeyManager, error) {
type accountKeyStore struct {
Password string `json:"password"`
EncryptedKeyStore string `json:"encrypted_key_store"`
Version uint8 `json:"version"`
}

//Open encrypted keystore with password
func OpenWithPassword(encryptedAccount, pw string) (*KeyManager, error) {

//unmarshal encrypted account
var acc accountKeyStore
if err := json.Unmarshal([]byte(encryptedAccount), &acc); err != nil {
return &KeyManager{}, err
}

//Decrypt key store
jsonKeyStore, err := crypto.DecryptScryptCipherText(pw, encryptedKeyStore)
jsonKeyStore, err := crypto.DecryptScryptCipherText(pw, acc.EncryptedKeyStore)
if err != nil {
return &KeyManager{}, nil
return &KeyManager{}, err
}

//transform json key store string to KeyStore
//unmarshal key store
keyStore, err := ks.FromJson(jsonKeyStore)

if err != nil {
return &KeyManager{}, nil
return &KeyManager{}, err
}

//
return &KeyManager{
keyStore: keyStore,
account: acc,
}, nil

}

//Export the key store
//Open account with mnemonic.
//This should only be used as a backup
func OpenWithMnemonic(encryptedAccount, mnemonic string) (*KeyManager, error) {

//unmarshal encrypted account
var acc accountKeyStore
if err := json.Unmarshal([]byte(encryptedAccount), &acc); err != nil {
return &KeyManager{}, err
}

//decrypt password with mnemonic
pw, err := crypto.DecryptScryptCipherText(mnemonic, acc.Password)
if err != nil {
return &KeyManager{}, err
}

return OpenWithPassword(encryptedAccount, pw)

}

//Export the account
func (km KeyManager) Export(pw, pwConfirm string) (string, error) {

//Exit if password's are not equal
if pw != pwConfirm {
return "", errors.New("password miss match")
}

keyStoreJson, err := km.keyStore.Marshal()
//Marshal the keystore
keyStore, err := km.keyStore.Marshal()
if err != nil {
return "", err
}
return crypto.NewScryptCipherText(pw, string(keyStoreJson))

//encrypt key store with password
encryptedKeyStore, err := crypto.NewScryptCipherText(pw, string(keyStore))
if err != nil {
return "", err
}

//encrypt password with mnemonic
encryptedPassword, err := crypto.NewScryptCipherText(km.keyStore.GetMnemonic(), pw)

//Marshal account
acc, err := json.Marshal(accountKeyStore{
Password: encryptedPassword,
EncryptedKeyStore: encryptedKeyStore,
Version: 1,
})

return string(acc), err

}

//Get ethereum private key
Expand Down
39 changes: 38 additions & 1 deletion keyManager/keyManager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ import (
"testing"
)

//Test the Create from function
func TestCreateFromKeyStore(t *testing.T) {
//create keyStore
ks, err := keyStore.NewKeyStoreFactory()
require.Nil(t, err)

km := CreateFromKeyStore(ks)

require.Equal(t, km.keyStore, ks)
}

func TestExportFunction(t *testing.T) {

//create key storage
Expand All @@ -22,11 +33,37 @@ func TestExportFunction(t *testing.T) {
require.Nil(t, err)

//Decrypt the exported encrypted key storage
km, err = Open(cipherText, "my_password")
km, err = OpenWithPassword(cipherText, "my_password")
require.Nil(t, err)

jsonKs, err := km.keyStore.Marshal()
require.Nil(t, err)

require.Equal(t, jsonKeyStore, string(jsonKs))
}

func TestOpenWithMnemonic(t *testing.T) {

//create key storage
jsonKeyStore := `{"mnemonic":"abandon amount liar amount expire adjust cage candy arch gather drum buyer","keys":{"eth_private_key":"dedbc9eb2b7eea18727f4b2e2d440b93e597cb283f00a3245943481785944d75"},"version":1}`
ks, err := keyStore.FromJson(jsonKeyStore)
require.Nil(t, err)

//create key manager
km := CreateFromKeyStore(ks)

//Export the key storage via the key manager
//The export should be encrypted
cipherText, err := km.Export("my_password", "my_password")
require.Nil(t, err)

//Decrypt the exported encrypted key storage
km, err = OpenWithMnemonic(cipherText, "abandon amount liar amount expire adjust cage candy arch gather drum buyer")
require.Nil(t, err)

jsonKs, err := km.keyStore.Marshal()
require.Nil(t, err)

require.Equal(t, jsonKeyStore, string(jsonKs))

}
15 changes: 13 additions & 2 deletions keyStore/keyStore.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ func (ks KeyStore) validate() error {
return nil
}

//Get mnemonic
func (ks KeyStore) GetMnemonic() string {
return ks.mnemonic
}

//Marshal key store
func (ks KeyStore) Marshal() ([]byte, error) {

Expand Down Expand Up @@ -135,7 +140,13 @@ func NewKeyStoreFactory() (*KeyStore, error) {
return &KeyStore{}, err
}

k, err := bip32.NewMasterKey(bip39.NewSeed(mn, "coins"))
return NewFromMnemonic(mn)
}

//Create new keyStore from mnemonic
func NewFromMnemonic(mnemonic string) (*KeyStore, error) {

k, err := bip32.NewMasterKey(bip39.NewSeed(mnemonic, "coins"))
if err != nil {
return &KeyStore{}, err
}
Expand All @@ -147,7 +158,7 @@ func NewKeyStoreFactory() (*KeyStore, error) {
}

ks := KeyStore{
mnemonic: mn,
mnemonic: mnemonic,
keys: map[string]string{
"eth_private_key": hex.EncodeToString(ethKey.Key),
},
Expand Down
10 changes: 10 additions & 0 deletions keyStore/keyStore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,13 @@ func TestNewKeyStoreFactory(t *testing.T) {
require.Equal(t, ks.version, uint8(1))

}

func TestGetMnemonic(t *testing.T) {

ks := KeyStore{
mnemonic: "abandon amount liar amount expire adjust cage candy arch gather drum buyer",
}

require.Equal(t, "abandon amount liar amount expire adjust cage candy arch gather drum buyer", ks.GetMnemonic())

}
9 changes: 7 additions & 2 deletions panthalassa.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,15 @@ func (p *Panthalassa) Stop() error {
return nil
}

//Export account with the given password
func (p *Panthalassa) Export(pw, pwConfirm string) (string, error) {
return p.km.Export(pw, pwConfirm)
}

//Create an new instance of panthalassa
func NewPanthalassa(keyStore, pw string) (*Panthalassa, error) {
func NewPanthalassa(encryptedAccount, pw string) (*Panthalassa, error) {

km, err := keyManager.Open(keyStore, pw)
km, err := keyManager.OpenWithPassword(encryptedAccount, pw)
if err != nil {
return &Panthalassa{}, nil
}
Expand Down
11 changes: 11 additions & 0 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,14 @@ func NewAccountKeys(pw, pwConfirm string) (string, error) {
km := keyManager.CreateFromKeyStore(ks)
return km.Export(pw, pwConfirm)
}

//Create new account store from mnemonic
//This can e.g. be used in case you need to recover your account
func NewAccountKeysFromMnemonic(mnemonic, pw, pwConfirm string) (string, error) {
ks, err := keyStore.NewFromMnemonic(mnemonic)
if err != nil {
return "", err
}
km := keyManager.CreateFromKeyStore(ks)
return km.Export(pw, pwConfirm)
}

0 comments on commit 34b1aeb

Please sign in to comment.