From beb99948dbc814456dc93dba937b12c1419e7cf7 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Sun, 14 Jun 2020 11:13:39 +0200 Subject: [PATCH] Extract ReadAezeedFromTerminal into library function --- cmd/chantools/chanbackup.go | 2 +- cmd/chantools/derivekey.go | 2 +- cmd/chantools/dumpbackup.go | 2 +- cmd/chantools/filterbackup.go | 2 +- cmd/chantools/fixoldbackup.go | 2 +- cmd/chantools/forceclose.go | 2 +- cmd/chantools/genimportscript.go | 4 +- cmd/chantools/main.go | 56 ------------------------- cmd/chantools/rescueclosed.go | 2 +- cmd/chantools/rescuefunding.go | 2 +- cmd/chantools/showrootkey.go | 4 +- cmd/chantools/sweeptimelock.go | 2 +- lnd/aezeed.go | 70 ++++++++++++++++++++++++++++++++ 13 files changed, 85 insertions(+), 67 deletions(-) create mode 100644 lnd/aezeed.go diff --git a/cmd/chantools/chanbackup.go b/cmd/chantools/chanbackup.go index 7e871f1..e8410de 100644 --- a/cmd/chantools/chanbackup.go +++ b/cmd/chantools/chanbackup.go @@ -30,7 +30,7 @@ func (c *chanBackupCommand) Execute(_ []string) error { extendedKey, err = hdkeychain.NewKeyFromString(c.RootKey) default: - extendedKey, _, err = rootKeyFromConsole() + extendedKey, _, err = lnd.ReadAezeedFromTerminal(chainParams) } if err != nil { return fmt.Errorf("error reading root key: %v", err) diff --git a/cmd/chantools/derivekey.go b/cmd/chantools/derivekey.go index ea35fa3..95c1d1e 100644 --- a/cmd/chantools/derivekey.go +++ b/cmd/chantools/derivekey.go @@ -27,7 +27,7 @@ func (c *deriveKeyCommand) Execute(_ []string) error { extendedKey, err = hdkeychain.NewKeyFromString(c.RootKey) default: - extendedKey, _, err = rootKeyFromConsole() + extendedKey, _, err = lnd.ReadAezeedFromTerminal(chainParams) } if err != nil { return fmt.Errorf("error reading root key: %v", err) diff --git a/cmd/chantools/dumpbackup.go b/cmd/chantools/dumpbackup.go index 0b60e7f..ce97b85 100644 --- a/cmd/chantools/dumpbackup.go +++ b/cmd/chantools/dumpbackup.go @@ -30,7 +30,7 @@ func (c *dumpBackupCommand) Execute(_ []string) error { extendedKey, err = hdkeychain.NewKeyFromString(c.RootKey) default: - extendedKey, _, err = rootKeyFromConsole() + extendedKey, _, err = lnd.ReadAezeedFromTerminal(chainParams) } if err != nil { return fmt.Errorf("error reading root key: %v", err) diff --git a/cmd/chantools/filterbackup.go b/cmd/chantools/filterbackup.go index 26daf78..2771193 100644 --- a/cmd/chantools/filterbackup.go +++ b/cmd/chantools/filterbackup.go @@ -32,7 +32,7 @@ func (c *filterBackupCommand) Execute(_ []string) error { extendedKey, err = hdkeychain.NewKeyFromString(c.RootKey) default: - extendedKey, _, err = rootKeyFromConsole() + extendedKey, _, err = lnd.ReadAezeedFromTerminal(chainParams) } if err != nil { return fmt.Errorf("error reading root key: %v", err) diff --git a/cmd/chantools/fixoldbackup.go b/cmd/chantools/fixoldbackup.go index c6b7688..1400041 100644 --- a/cmd/chantools/fixoldbackup.go +++ b/cmd/chantools/fixoldbackup.go @@ -30,7 +30,7 @@ func (c *fixOldBackupCommand) Execute(_ []string) error { extendedKey, err = hdkeychain.NewKeyFromString(c.RootKey) default: - extendedKey, _, err = rootKeyFromConsole() + extendedKey, _, err = lnd.ReadAezeedFromTerminal(chainParams) } if err != nil { return fmt.Errorf("error reading root key: %v", err) diff --git a/cmd/chantools/forceclose.go b/cmd/chantools/forceclose.go index fcb40d9..d19db6b 100644 --- a/cmd/chantools/forceclose.go +++ b/cmd/chantools/forceclose.go @@ -39,7 +39,7 @@ func (c *forceCloseCommand) Execute(_ []string) error { extendedKey, err = hdkeychain.NewKeyFromString(c.RootKey) default: - extendedKey, _, err = rootKeyFromConsole() + extendedKey, _, err = lnd.ReadAezeedFromTerminal(chainParams) } if err != nil { return fmt.Errorf("error reading root key: %v", err) diff --git a/cmd/chantools/genimportscript.go b/cmd/chantools/genimportscript.go index 60c36ea..b3f7df8 100644 --- a/cmd/chantools/genimportscript.go +++ b/cmd/chantools/genimportscript.go @@ -44,7 +44,9 @@ func (c *genImportScriptCommand) Execute(_ []string) error { } default: - extendedKey, birthday, err = rootKeyFromConsole() + extendedKey, birthday, err = lnd.ReadAezeedFromTerminal( + chainParams, + ) if err != nil { return fmt.Errorf("error reading root key: %v", err) } diff --git a/cmd/chantools/main.go b/cmd/chantools/main.go index 9213666..9b44b12 100644 --- a/cmd/chantools/main.go +++ b/cmd/chantools/main.go @@ -10,14 +10,11 @@ import ( "path" "strings" "syscall" - "time" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btclog" - "github.com/btcsuite/btcutil/hdkeychain" "github.com/guggero/chantools/dataformat" "github.com/jessevdk/go-flags" - "github.com/lightningnetwork/lnd/aezeed" "github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/chanbackup" "github.com/lightningnetwork/lnd/channeldb" @@ -201,59 +198,6 @@ func readInput(input string) ([]byte, error) { return ioutil.ReadFile(input) } -func rootKeyFromConsole() (*hdkeychain.ExtendedKey, time.Time, error) { - // We'll now prompt the user to enter in their 24-word mnemonic. - fmt.Printf("Input your 24-word mnemonic separated by spaces: ") - reader := bufio.NewReader(os.Stdin) - mnemonicStr, err := reader.ReadString('\n') - if err != nil { - return nil, time.Unix(0, 0), err - } - - // We'll trim off extra spaces, and ensure the mnemonic is all - // lower case, then populate our request. - mnemonicStr = strings.TrimSpace(mnemonicStr) - mnemonicStr = strings.ToLower(mnemonicStr) - - cipherSeedMnemonic := strings.Split(mnemonicStr, " ") - - fmt.Println() - - if len(cipherSeedMnemonic) != 24 { - return nil, time.Unix(0, 0), fmt.Errorf("wrong cipher seed "+ - "mnemonic length: got %v words, expecting %v words", - len(cipherSeedMnemonic), 24) - } - - // Additionally, the user may have a passphrase, that will also - // need to be provided so the daemon can properly decipher the - // cipher seed. - fmt.Printf("Input your cipher seed passphrase (press enter if " + - "your seed doesn't have a passphrase): ") - passphrase, err := terminal.ReadPassword(int(syscall.Stdin)) // nolint - if err != nil { - return nil, time.Unix(0, 0), err - } - fmt.Println() - - var mnemonic aezeed.Mnemonic - copy(mnemonic[:], cipherSeedMnemonic) - - // If we're unable to map it back into the ciphertext, then either the - // mnemonic is wrong, or the passphrase is wrong. - cipherSeed, err := mnemonic.ToCipherSeed(passphrase) - if err != nil { - return nil, time.Unix(0, 0), fmt.Errorf("failed to decrypt "+ - "seed with passphrase: %v", err) - } - rootKey, err := hdkeychain.NewMaster(cipherSeed.Entropy[:], chainParams) - if err != nil { - return nil, time.Unix(0, 0), fmt.Errorf("failed to derive " + - "master extended key") - } - return rootKey, cipherSeed.BirthdayTime(), nil -} - func passwordFromConsole(userQuery string) ([]byte, error) { // Read from terminal (if there is one). if terminal.IsTerminal(int(syscall.Stdin)) { // nolint diff --git a/cmd/chantools/rescueclosed.go b/cmd/chantools/rescueclosed.go index 7edb697..32e4e58 100644 --- a/cmd/chantools/rescueclosed.go +++ b/cmd/chantools/rescueclosed.go @@ -50,7 +50,7 @@ func (c *rescueClosedCommand) Execute(_ []string) error { extendedKey, err = hdkeychain.NewKeyFromString(c.RootKey) default: - extendedKey, _, err = rootKeyFromConsole() + extendedKey, _, err = lnd.ReadAezeedFromTerminal(chainParams) } if err != nil { return fmt.Errorf("error reading root key: %v", err) diff --git a/cmd/chantools/rescuefunding.go b/cmd/chantools/rescuefunding.go index 33bd201..3686b82 100644 --- a/cmd/chantools/rescuefunding.go +++ b/cmd/chantools/rescuefunding.go @@ -39,7 +39,7 @@ func (c *rescueFundingCommand) Execute(_ []string) error { extendedKey, err = hdkeychain.NewKeyFromString(c.RootKey) default: - extendedKey, _, err = rootKeyFromConsole() + extendedKey, _, err = lnd.ReadAezeedFromTerminal(chainParams) } if err != nil { return fmt.Errorf("error reading root key: %v", err) diff --git a/cmd/chantools/showrootkey.go b/cmd/chantools/showrootkey.go index 02960aa..533a8b4 100644 --- a/cmd/chantools/showrootkey.go +++ b/cmd/chantools/showrootkey.go @@ -2,6 +2,8 @@ package main import ( "fmt" + + "github.com/guggero/chantools/lnd" ) type showRootKeyCommand struct{} @@ -9,7 +11,7 @@ type showRootKeyCommand struct{} func (c *showRootKeyCommand) Execute(_ []string) error { setupChainParams(cfg) - rootKey, _, err := rootKeyFromConsole() + rootKey, _, err := lnd.ReadAezeedFromTerminal(chainParams) if err != nil { return fmt.Errorf("failed to read root key from console: %v", err) diff --git a/cmd/chantools/sweeptimelock.go b/cmd/chantools/sweeptimelock.go index 84dbb3e..c487822 100644 --- a/cmd/chantools/sweeptimelock.go +++ b/cmd/chantools/sweeptimelock.go @@ -41,7 +41,7 @@ func (c *sweepTimeLockCommand) Execute(_ []string) error { extendedKey, err = hdkeychain.NewKeyFromString(c.RootKey) default: - extendedKey, _, err = rootKeyFromConsole() + extendedKey, _, err = lnd.ReadAezeedFromTerminal(chainParams) } if err != nil { return fmt.Errorf("error reading root key: %v", err) diff --git a/lnd/aezeed.go b/lnd/aezeed.go new file mode 100644 index 0000000..bba3c9f --- /dev/null +++ b/lnd/aezeed.go @@ -0,0 +1,70 @@ +package lnd + +import ( + "bufio" + "fmt" + "os" + "strings" + "syscall" + "time" + + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcutil/hdkeychain" + "github.com/lightningnetwork/lnd/aezeed" + "golang.org/x/crypto/ssh/terminal" +) + +func ReadAezeedFromTerminal(params *chaincfg.Params) (*hdkeychain.ExtendedKey, + time.Time, error) { + + // We'll now prompt the user to enter in their 24-word mnemonic. + fmt.Printf("Input your 24-word mnemonic separated by spaces: ") + reader := bufio.NewReader(os.Stdin) + mnemonicStr, err := reader.ReadString('\n') + if err != nil { + return nil, time.Unix(0, 0), err + } + + // We'll trim off extra spaces, and ensure the mnemonic is all + // lower case, then populate our request. + mnemonicStr = strings.TrimSpace(mnemonicStr) + mnemonicStr = strings.ToLower(mnemonicStr) + + cipherSeedMnemonic := strings.Split(mnemonicStr, " ") + + fmt.Println() + + if len(cipherSeedMnemonic) != 24 { + return nil, time.Unix(0, 0), fmt.Errorf("wrong cipher seed "+ + "mnemonic length: got %v words, expecting %v words", + len(cipherSeedMnemonic), 24) + } + + // Additionally, the user may have a passphrase, that will also + // need to be provided so the daemon can properly decipher the + // cipher seed. + fmt.Printf("Input your cipher seed passphrase (press enter if " + + "your seed doesn't have a passphrase): ") + passphrase, err := terminal.ReadPassword(int(syscall.Stdin)) // nolint + if err != nil { + return nil, time.Unix(0, 0), err + } + fmt.Println() + + var mnemonic aezeed.Mnemonic + copy(mnemonic[:], cipherSeedMnemonic) + + // If we're unable to map it back into the ciphertext, then either the + // mnemonic is wrong, or the passphrase is wrong. + cipherSeed, err := mnemonic.ToCipherSeed(passphrase) + if err != nil { + return nil, time.Unix(0, 0), fmt.Errorf("failed to decrypt "+ + "seed with passphrase: %v", err) + } + rootKey, err := hdkeychain.NewMaster(cipherSeed.Entropy[:], params) + if err != nil { + return nil, time.Unix(0, 0), fmt.Errorf("failed to derive " + + "master extended key") + } + return rootKey, cipherSeed.BirthdayTime(), nil +}