diff --git a/accounts/keystore/key.go b/accounts/keystore/key.go index 211fa863d7..4031884c42 100644 --- a/accounts/keystore/key.go +++ b/accounts/keystore/key.go @@ -53,6 +53,8 @@ type keyStore interface { GetKey(addr common.Address, filename string, auth string) (*Key, error) // Writes and encrypts the key. StoreKey(filename string, k *Key, auth string) error + // Creates and encrypts the key and returns in JSON + CreateKeyStore(k *Key, auth string) ([]byte, error) // Joins filename with the key directory unless it is already absolute. JoinPath(filename string) string } @@ -179,6 +181,19 @@ func storeNewKey(ks keyStore, rand io.Reader, auth string) (*Key, accounts.Accou return key, a, err } +func newKeyStore(ks keyStore, rand io.Reader, auth string) (*Key, []byte, error) { + key, err := newKey(rand) + if err != nil { + return nil, []byte{}, err + } + json, err := ks.CreateKeyStore(key, auth) + if err != nil { + zeroKey(key.PrivateKey) + return nil, []byte{}, err + } + return key, json, err +} + func writeKeyFile(file string, content []byte) error { // Create the keystore directory with appropriate permissions // in case it is not present yet. diff --git a/accounts/keystore/keystore_passphrase.go b/accounts/keystore/keystore_passphrase.go index eaec39f7df..bf3aec39b7 100644 --- a/accounts/keystore/keystore_passphrase.go +++ b/accounts/keystore/keystore_passphrase.go @@ -98,13 +98,27 @@ func StoreKey(dir, auth string, scryptN, scryptP int) (common.Address, error) { } func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) error { - keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP) + keyjson, err := ks.CreateKeyStore(key, auth) if err != nil { return err } return writeKeyFile(filename, keyjson) } +// CreateKeyStore generates a key, encrypts with 'auth' +func CreateKeyStore(auth string, scryptN, scryptP int) ([]byte, error) { + _, json, err := newKeyStore(&keyStorePassphrase{scryptN: scryptN, scryptP: scryptP}, crand.Reader, auth) + return json, err +} + +func (ks keyStorePassphrase) CreateKeyStore(key *Key, auth string) ([]byte, error) { + keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP) + if err != nil { + return []byte{}, err + } + return keyjson, nil +} + func (ks keyStorePassphrase) JoinPath(filename string) string { if filepath.IsAbs(filename) { return filename diff --git a/accounts/keystore/keystore_plain.go b/accounts/keystore/keystore_plain.go index b490ca72b8..4bf1803c5c 100644 --- a/accounts/keystore/keystore_plain.go +++ b/accounts/keystore/keystore_plain.go @@ -53,6 +53,14 @@ func (ks keyStorePlain) StoreKey(filename string, key *Key, auth string) error { return writeKeyFile(filename, content) } +func (ks keyStorePlain) CreateKeyStore(key *Key, auth string) ([]byte, error) { + content, err := json.Marshal(key) + if err != nil { + return []byte{}, err + } + return content, nil +} + func (ks keyStorePlain) JoinPath(filename string) string { if filepath.IsAbs(filename) { return filename diff --git a/cmd/geth/accountcmd.go b/cmd/geth/accountcmd.go index 0db5c4ce0f..1bd6123ee7 100644 --- a/cmd/geth/accountcmd.go +++ b/cmd/geth/accountcmd.go @@ -110,6 +110,7 @@ Print a short summary of all accounts`, utils.KeyStoreDirFlag, utils.PasswordFileFlag, utils.LightKDFFlag, + utils.WriteKeyStoreOnlyToStdout, }, Description: ` geth account new @@ -307,12 +308,20 @@ func accountCreate(ctx *cli.Context) error { password := getPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx)) - address, err := keystore.StoreKey(keydir, password, scryptN, scryptP) - - if err != nil { - utils.Fatalf("Failed to create account: %v", err) + if ctx.GlobalBool(utils.WriteKeyStoreOnlyToStdout.Name) { + keystore, err := keystore.CreateKeyStore(password, scryptN, scryptP) + if err != nil { + utils.Fatalf("Failed to create account: %v", err) + } + fmt.Printf("%s\n", keystore) + } else { + address, err := keystore.StoreKey(keydir, password, scryptN, scryptP) + if err != nil { + utils.Fatalf("Failed to create account: %v", err) + } + fmt.Printf("Address: {%x}\n", address) } - fmt.Printf("Address: {%x}\n", address) + return nil } diff --git a/cmd/geth/main.go b/cmd/geth/main.go index b955bd243e..a28b679083 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -60,6 +60,7 @@ var ( utils.BootnodesV5Flag, utils.DataDirFlag, utils.KeyStoreDirFlag, + utils.WriteKeyStoreOnlyToStdout, utils.NoUSBFlag, utils.DashboardEnabledFlag, utils.DashboardAddrFlag, diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index a834d5b7ae..b5d010e514 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -135,6 +135,7 @@ var AppHelpFlagGroups = []flagGroup{ Flags: []cli.Flag{ utils.UnlockedAccountFlag, utils.PasswordFileFlag, + utils.WriteKeyStoreOnlyToStdout, }, }, { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 3766ea4a60..ee241e2c4d 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -122,6 +122,10 @@ var ( Name: "keystore", Usage: "Directory for the keystore (default = inside the datadir)", } + WriteKeyStoreOnlyToStdout = cli.BoolFlag{ + Name: "stdoutkeystore", + Usage: "Prevents writing keystore to file, instead outputs the keystore to standard output (stdout)", + } NoUSBFlag = cli.BoolFlag{ Name: "nousb", Usage: "Disables monitoring for and managing USB hardware wallets", @@ -858,6 +862,9 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { if ctx.GlobalIsSet(KeyStoreDirFlag.Name) { cfg.KeyStoreDir = ctx.GlobalString(KeyStoreDirFlag.Name) } + if ctx.GlobalIsSet(WriteKeyStoreOnlyToStdout.Name) { + cfg.WriteKeyStoreOnlyToStdout = ctx.GlobalBool(WriteKeyStoreOnlyToStdout.Name) + } if ctx.GlobalIsSet(LightKDFFlag.Name) { cfg.UseLightweightKDF = ctx.GlobalBool(LightKDFFlag.Name) } diff --git a/node/config.go b/node/config.go index 7a0c1688ec..ebe514ed9b 100644 --- a/node/config.go +++ b/node/config.go @@ -78,6 +78,9 @@ type Config struct { // is created by New and destroyed when the node is stopped. KeyStoreDir string `toml:",omitempty"` + // Prevents writing keystore to file, instead outputs the keystore to standard output (stdout) + WriteKeyStoreOnlyToStdout bool `toml:",omitempty"` + // UseLightweightKDF lowers the memory and CPU requirements of the key store // scrypt KDF at the expense of security. UseLightweightKDF bool `toml:",omitempty"`