Add dump unencrypted data sub command to the wallet (#1661)

This commit is contained in:
Ori Newman 2021-04-06 12:29:13 +03:00 committed by GitHub
parent 73b36f12f0
commit 6dd3d4a9e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 127 additions and 12 deletions

View File

@ -12,10 +12,11 @@ const (
createSubCmd = "create"
balanceSubCmd = "balance"
sendSubCmd = "send"
createUnsignedTransactionSubCmd = "createUnsignedTransaction"
createUnsignedTransactionSubCmd = "create-unsigned-transaction"
signSubCmd = "sign"
broadcastSubCmd = "broadcast"
showAddressSubCmd = "show-address"
dumpUnencryptedDataSubCmd = "dump-unencrypted-data"
)
type configFlags struct {
@ -70,6 +71,11 @@ type showAddressConfig struct {
config.NetworkFlags
}
type dumpUnencryptedDataConfig struct {
KeysFile string `long:"keys-file" short:"f" description:"Keys file location (default: ~/.kaspawallet/keys.json (*nix), %USERPROFILE%\\AppData\\Local\\Kaspawallet\\key.json (Windows))"`
config.NetworkFlags
}
func parseCommandLine() (subCommand string, config interface{}) {
cfg := &configFlags{}
parser := flags.NewParser(cfg, flags.PrintErrors|flags.HelpFlag)
@ -102,6 +108,11 @@ func parseCommandLine() (subCommand string, config interface{}) {
parser.AddCommand(showAddressSubCmd, "Shows the public address of the current wallet",
"Shows the public address of the current wallet", showAddressConf)
dumpUnencryptedDataConf := &dumpUnencryptedDataConfig{}
parser.AddCommand(dumpUnencryptedDataSubCmd, "Prints the unencrypted wallet data",
"Prints the unencrypted wallet data including its private keys. Anyone that sees it can access "+
"the funds. Use only on safe environment.", dumpUnencryptedDataConf)
_, err := parser.Parse()
if err != nil {
@ -164,6 +175,13 @@ func parseCommandLine() (subCommand string, config interface{}) {
printErrorAndExit(err)
}
config = showAddressConf
case dumpUnencryptedDataSubCmd:
combineNetworkFlags(&dumpUnencryptedDataConf.NetworkFlags, &cfg.NetworkFlags)
err := dumpUnencryptedDataConf.ResolveNetwork(parser)
if err != nil {
printErrorAndExit(err)
}
config = dumpUnencryptedDataConf
}
return parser.Command.Active.Name, config

View File

@ -0,0 +1,69 @@
package main
import (
"bufio"
"fmt"
"github.com/kaspanet/kaspad/cmd/kaspawallet/keys"
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
"github.com/pkg/errors"
"os"
)
func dumpUnencryptedData(conf *dumpUnencryptedDataConfig) error {
err := confirmDump()
if err != nil {
return err
}
keysFile, err := keys.ReadKeysFile(conf.KeysFile)
if err != nil {
return err
}
privateKeys, err := keysFile.DecryptPrivateKeys()
if err != nil {
return err
}
privateKeysPublicKeys := make(map[string]struct{})
for i, privateKey := range privateKeys {
fmt.Printf("Private key #%d:\n%x\n\n", i+1, privateKey)
publicKey, err := libkaspawallet.PublicKeyFromPrivateKey(privateKey)
if err != nil {
return err
}
privateKeysPublicKeys[string(publicKey)] = struct{}{}
}
i := 1
for _, publicKey := range keysFile.PublicKeys {
if _, exists := privateKeysPublicKeys[string(publicKey)]; exists {
continue
}
fmt.Printf("Public key #%d:\n%x\n\n", i, publicKey)
i++
}
fmt.Printf("Minimum number of signatures: %d\n", keysFile.MinimumSignatures)
return nil
}
func confirmDump() error {
reader := bufio.NewReader(os.Stdin)
fmt.Printf("This operation will print your unencrypted keys on the screen. Anyone that sees this information " +
"will be able to steal your funds. Are you sure you want to proceed (y/N)? ")
line, isPrefix, err := reader.ReadLine()
if err != nil {
return err
}
fmt.Println()
if isPrefix || string(line) != "y" {
return errors.Errorf("Dump aborted by user")
}
return nil
}

View File

@ -4,6 +4,7 @@ import (
"bufio"
"crypto/rand"
"crypto/subtle"
"encoding/hex"
"fmt"
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
"github.com/pkg/errors"
@ -29,7 +30,17 @@ func ImportKeyPairs(numKeys uint32) (encryptedPrivateKeys []*EncryptedPrivateKey
if isPrefix {
return nil, nil, errors.Errorf("Private key is too long")
}
return libkaspawallet.KeyPairFromPrivateKeyHex(string(line))
privateKey, err := hex.DecodeString(string(line))
if err != nil {
return nil, nil, err
}
publicKey, err := libkaspawallet.PublicKeyFromPrivateKey(privateKey)
if err != nil {
return nil, nil, err
}
return privateKey, publicKey, nil
})
}

View File

@ -1,7 +1,6 @@
package libkaspawallet
import (
"encoding/hex"
"github.com/kaspanet/go-secp256k1"
"github.com/kaspanet/kaspad/domain/dagconfig"
"github.com/kaspanet/kaspad/util"
@ -10,24 +9,40 @@ import (
// CreateKeyPair generates a private-public key pair
func CreateKeyPair() ([]byte, []byte, error) {
privateKey, err := secp256k1.GenerateSchnorrKeyPair()
keyPair, err := secp256k1.GenerateSchnorrKeyPair()
if err != nil {
return nil, nil, errors.Wrap(err, "Failed to generate private key")
}
return keyPairBytes(privateKey)
publicKey, err := keyPair.SchnorrPublicKey()
if err != nil {
return nil, nil, errors.Wrap(err, "Failed to generate public key")
}
publicKeySerialized, err := publicKey.Serialize()
if err != nil {
return nil, nil, errors.Wrap(err, "Failed to serialize public key")
}
return keyPair.SerializePrivateKey()[:], publicKeySerialized[:], nil
}
// KeyPairFromPrivateKeyHex decodes a private-public key pair out of `privateKeyHex`
func KeyPairFromPrivateKeyHex(privateKeyHex string) ([]byte, []byte, error) {
privateKeyBytes, err := hex.DecodeString(privateKeyHex)
// PublicKeyFromPrivateKey returns the public key associated with a private key
func PublicKeyFromPrivateKey(privateKeyBytes []byte) ([]byte, error) {
keyPair, err := secp256k1.DeserializeSchnorrPrivateKeyFromSlice(privateKeyBytes)
if err != nil {
return nil, nil, errors.Wrap(err, "Failed to deserialized private key")
return nil, errors.Wrap(err, "Failed to deserialized private key")
}
privateKey, err := secp256k1.DeserializeSchnorrPrivateKeyFromSlice(privateKeyBytes)
publicKey, err := keyPair.SchnorrPublicKey()
if err != nil {
return nil, nil, errors.Wrap(err, "Failed to deserialized private key")
return nil, errors.Wrap(err, "Failed to generate public key")
}
return keyPairBytes(privateKey)
publicKeySerialized, err := publicKey.Serialize()
if err != nil {
return nil, errors.Wrap(err, "Failed to serialize public key")
}
return publicKeySerialized[:], nil
}
func keyPairBytes(keyPair *secp256k1.SchnorrKeyPair) ([]byte, []byte, error) {

View File

@ -21,6 +21,8 @@ func main() {
err = broadcast(config.(*broadcastConfig))
case showAddressSubCmd:
err = showAddress(config.(*showAddressConfig))
case dumpUnencryptedDataSubCmd:
err = dumpUnencryptedData(config.(*dumpUnencryptedDataConfig))
default:
err = errors.Errorf("Unknown sub-command '%s'\n", subCmd)
}