Skip to content

Commit

Permalink
cmd/ethkey: add command to change key passphrase (ethereum#16516)
Browse files Browse the repository at this point in the history
This change introduces 

    ethkey changepassphrase <keyfile>

to change the passphrase of a key file.
  • Loading branch information
stevenroose authored and firmianavan committed Aug 28, 2018
1 parent 88be1f7 commit 3afc1ac
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 19 deletions.
72 changes: 72 additions & 0 deletions cmd/ethkey/changepassphrase.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package main

import (
"fmt"
"io/ioutil"
"strings"

"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/cmd/utils"
"gopkg.in/urfave/cli.v1"
)

var newPassphraseFlag = cli.StringFlag{
Name: "newpasswordfile",
Usage: "the file that contains the new passphrase for the keyfile",
}

var commandChangePassphrase = cli.Command{
Name: "changepassphrase",
Usage: "change the passphrase on a keyfile",
ArgsUsage: "<keyfile>",
Description: `
Change the passphrase of a keyfile.`,
Flags: []cli.Flag{
passphraseFlag,
newPassphraseFlag,
},
Action: func(ctx *cli.Context) error {
keyfilepath := ctx.Args().First()

// Read key from file.
keyjson, err := ioutil.ReadFile(keyfilepath)
if err != nil {
utils.Fatalf("Failed to read the keyfile at '%s': %v", keyfilepath, err)
}

// Decrypt key with passphrase.
passphrase := getPassphrase(ctx)
key, err := keystore.DecryptKey(keyjson, passphrase)
if err != nil {
utils.Fatalf("Error decrypting key: %v", err)
}

// Get a new passphrase.
fmt.Println("Please provide a new passphrase")
var newPhrase string
if passFile := ctx.String(newPassphraseFlag.Name); passFile != "" {
content, err := ioutil.ReadFile(passFile)
if err != nil {
utils.Fatalf("Failed to read new passphrase file '%s': %v", passFile, err)
}
newPhrase = strings.TrimRight(string(content), "\r\n")
} else {
newPhrase = promptPassphrase(true)
}

// Encrypt the key with the new passphrase.
newJson, err := keystore.EncryptKey(key, newPhrase, keystore.StandardScryptN, keystore.StandardScryptP)
if err != nil {
utils.Fatalf("Error encrypting with new passphrase: %v", err)
}

// Then write the new keyfile in place of the old one.
if err := ioutil.WriteFile(keyfilepath, newJson, 600); err != nil {
utils.Fatalf("Error writing new keyfile to disk: %v", err)
}

// Don't print anything. Just return successfully,
// producing a positive exit code.
return nil
},
}
2 changes: 1 addition & 1 deletion cmd/ethkey/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ If you want to encrypt an existing private key, it can be specified by setting
}

// Encrypt key with passphrase.
passphrase := getPassPhrase(ctx, true)
passphrase := promptPassphrase(true)
keyjson, err := keystore.EncryptKey(key, passphrase, keystore.StandardScryptN, keystore.StandardScryptP)
if err != nil {
utils.Fatalf("Error encrypting key: %v", err)
Expand Down
2 changes: 1 addition & 1 deletion cmd/ethkey/inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ make sure to use this feature with great caution!`,
}

// Decrypt key with passphrase.
passphrase := getPassPhrase(ctx, false)
passphrase := getPassphrase(ctx)
key, err := keystore.DecryptKey(keyjson, passphrase)
if err != nil {
utils.Fatalf("Error decrypting key: %v", err)
Expand Down
1 change: 1 addition & 0 deletions cmd/ethkey/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func init() {
app.Commands = []cli.Command{
commandGenerate,
commandInspect,
commandChangePassphrase,
commandSignMessage,
commandVerifyMessage,
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/ethkey/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ To sign a message contained in a file, use the --msgfile flag.
}

// Decrypt key with passphrase.
passphrase := getPassPhrase(ctx, false)
passphrase := getPassphrase(ctx)
key, err := keystore.DecryptKey(keyjson, passphrase)
if err != nil {
utils.Fatalf("Error decrypting key: %v", err)
Expand Down
40 changes: 24 additions & 16 deletions cmd/ethkey/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,14 @@ import (
"gopkg.in/urfave/cli.v1"
)

// getPassPhrase obtains a passphrase given by the user. It first checks the
// --passphrase command line flag and ultimately prompts the user for a
// passphrase.
func getPassPhrase(ctx *cli.Context, confirmation bool) string {
// Look for the --passphrase flag.
passphraseFile := ctx.String(passphraseFlag.Name)
if passphraseFile != "" {
content, err := ioutil.ReadFile(passphraseFile)
if err != nil {
utils.Fatalf("Failed to read passphrase file '%s': %v",
passphraseFile, err)
}
return strings.TrimRight(string(content), "\r\n")
}

// Otherwise prompt the user for the passphrase.
// promptPassphrase prompts the user for a passphrase. Set confirmation to true
// to require the user to confirm the passphrase.
func promptPassphrase(confirmation bool) string {
passphrase, err := console.Stdin.PromptPassword("Passphrase: ")
if err != nil {
utils.Fatalf("Failed to read passphrase: %v", err)
}

if confirmation {
confirm, err := console.Stdin.PromptPassword("Repeat passphrase: ")
if err != nil {
Expand All @@ -57,9 +45,29 @@ func getPassPhrase(ctx *cli.Context, confirmation bool) string {
utils.Fatalf("Passphrases do not match")
}
}

return passphrase
}

// getPassphrase obtains a passphrase given by the user. It first checks the
// --passfile command line flag and ultimately prompts the user for a
// passphrase.
func getPassphrase(ctx *cli.Context) string {
// Look for the --passwordfile flag.
passphraseFile := ctx.String(passphraseFlag.Name)
if passphraseFile != "" {
content, err := ioutil.ReadFile(passphraseFile)
if err != nil {
utils.Fatalf("Failed to read passphrase file '%s': %v",
passphraseFile, err)
}
return strings.TrimRight(string(content), "\r\n")
}

// Otherwise prompt the user for the passphrase.
return promptPassphrase(false)
}

// signHash is a helper function that calculates a hash for the given message
// that can be safely used to calculate a signature from.
//
Expand Down

0 comments on commit 3afc1ac

Please sign in to comment.