Add -masterkey=stdin
functionality
https://github.com/rfjakob/gocryptfs/issues/218
This commit is contained in:
parent
9c86daf499
commit
9bc039a4ba
@ -142,20 +142,24 @@ This flag is useful when recovering old gocryptfs filesystems using
|
|||||||
"-masterkey". It is ignored (stays at the default) otherwise.
|
"-masterkey". It is ignored (stays at the default) otherwise.
|
||||||
|
|
||||||
#### -masterkey string
|
#### -masterkey string
|
||||||
Use a explicit master key specified on the command line. This
|
Use a explicit master key specified on the command line or, if the special
|
||||||
|
value "stdin" is used, read the masterkey from stdin. This
|
||||||
option can be used to mount a gocryptfs filesystem without a config file.
|
option can be used to mount a gocryptfs filesystem without a config file.
|
||||||
Note that the command line, and with it the master key, is visible to
|
Note that the command line, and with it the master key, is visible to
|
||||||
anybody on the machine who can execute "ps -auxwww".
|
anybody on the machine who can execute "ps -auxwww". Use "-masterkey=stdin"
|
||||||
This is meant as a recovery option for emergencies, such as if you have
|
to avoid that risk.
|
||||||
forgotten the password or lost the config file.
|
|
||||||
|
The masterkey option is meant as a recovery option for emergencies, such as
|
||||||
|
if you have forgotten the password or lost the config file.
|
||||||
|
|
||||||
Even if a config file exists, it will not be used. All non-standard
|
Even if a config file exists, it will not be used. All non-standard
|
||||||
settings have to be passed on the command line: `-aessiv` when you
|
settings have to be passed on the command line: `-aessiv` when you
|
||||||
mount a filesystem that was created using reverse mode, or
|
mount a filesystem that was created using reverse mode, or
|
||||||
`-plaintextnames` for a filesystem that was created with that option.
|
`-plaintextnames` for a filesystem that was created with that option.
|
||||||
|
|
||||||
Example master key:
|
Examples:
|
||||||
6f717d8b-6b5f8e8a-fd0aa206-778ec093-62c5669b-abd229cd-241e00cd-b4d6713d
|
-masterkey=6f717d8b-6b5f8e8a-fd0aa206-778ec093-62c5669b-abd229cd-241e00cd-b4d6713d
|
||||||
|
-masterkey=stdin
|
||||||
|
|
||||||
#### -memprofile string
|
#### -memprofile string
|
||||||
Write memory profile to the specified file. This is useful when debugging
|
Write memory profile to the specified file. This is useful when debugging
|
||||||
|
@ -153,6 +153,10 @@ RM: 4.42
|
|||||||
Changelog
|
Changelog
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
vNEXT, in progress
|
||||||
|
* Add `-masterkey=stdin` functionality
|
||||||
|
([#218](https://github.com/rfjakob/gocryptfs/issues/218))
|
||||||
|
|
||||||
v1.4.4, 2018-03-18
|
v1.4.4, 2018-03-18
|
||||||
* Overwrite secrets in memory with zeros as soon as possible
|
* Overwrite secrets in memory with zeros as soon as possible
|
||||||
([#211](https://github.com/rfjakob/gocryptfs/issues/211))
|
([#211](https://github.com/rfjakob/gocryptfs/issues/211))
|
||||||
|
@ -60,7 +60,7 @@ func main() {
|
|||||||
|
|
||||||
func dumpMasterKey(fn string) {
|
func dumpMasterKey(fn string) {
|
||||||
tlog.Info.Enabled = false
|
tlog.Info.Enabled = false
|
||||||
pw := readpassword.Once("")
|
pw := readpassword.Once("", "")
|
||||||
masterkey, _, err := configfile.LoadConfFile(fn, pw)
|
masterkey, _, err := configfile.LoadConfFile(fn, pw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
@ -26,7 +26,7 @@ func TestExtpass(t *testing.T) {
|
|||||||
|
|
||||||
func TestOnceExtpass(t *testing.T) {
|
func TestOnceExtpass(t *testing.T) {
|
||||||
p1 := "lkadsf0923rdfi48rqwhdsf"
|
p1 := "lkadsf0923rdfi48rqwhdsf"
|
||||||
p2 := string(Once("echo " + p1))
|
p2 := string(Once("echo "+p1, ""))
|
||||||
if p1 != p2 {
|
if p1 != p2 {
|
||||||
t.Errorf("p1=%q != p2=%q", p1, p2)
|
t.Errorf("p1=%q != p2=%q", p1, p2)
|
||||||
}
|
}
|
||||||
@ -34,7 +34,7 @@ func TestOnceExtpass(t *testing.T) {
|
|||||||
|
|
||||||
func TestTwiceExtpass(t *testing.T) {
|
func TestTwiceExtpass(t *testing.T) {
|
||||||
p1 := "w5w44t3wfe45srz434"
|
p1 := "w5w44t3wfe45srz434"
|
||||||
p2 := string(Once("echo " + p1))
|
p2 := string(Once("echo "+p1, ""))
|
||||||
if p1 != p2 {
|
if p1 != p2 {
|
||||||
t.Errorf("p1=%q != p2=%q", p1, p2)
|
t.Errorf("p1=%q != p2=%q", p1, p2)
|
||||||
}
|
}
|
||||||
|
@ -23,15 +23,18 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Once tries to get a password from the user, either from the terminal, extpass
|
// Once tries to get a password from the user, either from the terminal, extpass
|
||||||
// or stdin.
|
// or stdin. Leave "prompt" empty to use the default "Password: " prompt.
|
||||||
func Once(extpass string) []byte {
|
func Once(extpass string, prompt string) []byte {
|
||||||
if extpass != "" {
|
if extpass != "" {
|
||||||
return readPasswordExtpass(extpass)
|
return readPasswordExtpass(extpass)
|
||||||
}
|
}
|
||||||
if !terminal.IsTerminal(int(os.Stdin.Fd())) {
|
if prompt == "" {
|
||||||
return readPasswordStdin()
|
prompt = "Password"
|
||||||
}
|
}
|
||||||
return readPasswordTerminal("Password: ")
|
if !terminal.IsTerminal(int(os.Stdin.Fd())) {
|
||||||
|
return readPasswordStdin(prompt)
|
||||||
|
}
|
||||||
|
return readPasswordTerminal(prompt + ": ")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Twice is the same as Once but will prompt twice if we get the password from
|
// Twice is the same as Once but will prompt twice if we get the password from
|
||||||
@ -41,7 +44,7 @@ func Twice(extpass string) []byte {
|
|||||||
return readPasswordExtpass(extpass)
|
return readPasswordExtpass(extpass)
|
||||||
}
|
}
|
||||||
if !terminal.IsTerminal(int(os.Stdin.Fd())) {
|
if !terminal.IsTerminal(int(os.Stdin.Fd())) {
|
||||||
return readPasswordStdin()
|
return readPasswordStdin("Password")
|
||||||
}
|
}
|
||||||
p1 := readPasswordTerminal("Password: ")
|
p1 := readPasswordTerminal("Password: ")
|
||||||
p2 := readPasswordTerminal("Repeat: ")
|
p2 := readPasswordTerminal("Repeat: ")
|
||||||
@ -77,11 +80,11 @@ func readPasswordTerminal(prompt string) []byte {
|
|||||||
|
|
||||||
// readPasswordStdin reads a line from stdin.
|
// readPasswordStdin reads a line from stdin.
|
||||||
// It exits with a fatal error on read error or empty result.
|
// It exits with a fatal error on read error or empty result.
|
||||||
func readPasswordStdin() []byte {
|
func readPasswordStdin(prompt string) []byte {
|
||||||
tlog.Info.Println("Reading password from stdin")
|
tlog.Info.Printf("Reading %s from stdin", prompt)
|
||||||
p := readLineUnbuffered(os.Stdin)
|
p := readLineUnbuffered(os.Stdin)
|
||||||
if len(p) == 0 {
|
if len(p) == 0 {
|
||||||
tlog.Fatal.Println("Got empty password from stdin")
|
tlog.Fatal.Printf("Got empty %s from stdin", prompt)
|
||||||
os.Exit(exitcodes.ReadPassword)
|
os.Exit(exitcodes.ReadPassword)
|
||||||
}
|
}
|
||||||
return p
|
return p
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
func TestStdin(t *testing.T) {
|
func TestStdin(t *testing.T) {
|
||||||
p1 := "g55434t55wef"
|
p1 := "g55434t55wef"
|
||||||
if os.Getenv("TEST_SLAVE") == "1" {
|
if os.Getenv("TEST_SLAVE") == "1" {
|
||||||
p2 := string(readPasswordStdin())
|
p2 := string(readPasswordStdin("foo"))
|
||||||
if p1 != p2 {
|
if p1 != p2 {
|
||||||
fmt.Fprintf(os.Stderr, "%q != %q", p1, p2)
|
fmt.Fprintf(os.Stderr, "%q != %q", p1, p2)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
@ -44,7 +44,7 @@ func TestStdin(t *testing.T) {
|
|||||||
func TestStdinEof(t *testing.T) {
|
func TestStdinEof(t *testing.T) {
|
||||||
p1 := "asd45as5f4a36"
|
p1 := "asd45as5f4a36"
|
||||||
if os.Getenv("TEST_SLAVE") == "1" {
|
if os.Getenv("TEST_SLAVE") == "1" {
|
||||||
p2 := string(readPasswordStdin())
|
p2 := string(readPasswordStdin("foo"))
|
||||||
if p1 != p2 {
|
if p1 != p2 {
|
||||||
fmt.Fprintf(os.Stderr, "%q != %q", p1, p2)
|
fmt.Fprintf(os.Stderr, "%q != %q", p1, p2)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
@ -76,7 +76,7 @@ func TestStdinEof(t *testing.T) {
|
|||||||
// Provide empty password via stdin
|
// Provide empty password via stdin
|
||||||
func TestStdinEmpty(t *testing.T) {
|
func TestStdinEmpty(t *testing.T) {
|
||||||
if os.Getenv("TEST_SLAVE") == "1" {
|
if os.Getenv("TEST_SLAVE") == "1" {
|
||||||
readPasswordStdin()
|
readPasswordStdin("foo")
|
||||||
}
|
}
|
||||||
cmd := exec.Command(os.Args[0], "-test.run=TestStdinEmpty$")
|
cmd := exec.Command(os.Args[0], "-test.run=TestStdinEmpty$")
|
||||||
cmd.Env = append(os.Environ(), "TEST_SLAVE=1")
|
cmd.Env = append(os.Environ(), "TEST_SLAVE=1")
|
||||||
|
4
main.go
4
main.go
@ -43,10 +43,10 @@ func loadConfig(args *argContainer) (masterkey []byte, confFile *configfile.Conf
|
|||||||
// The user has passed the master key (probably because he forgot the
|
// The user has passed the master key (probably because he forgot the
|
||||||
// password).
|
// password).
|
||||||
if args.masterkey != "" {
|
if args.masterkey != "" {
|
||||||
masterkey = parseMasterKey(args.masterkey)
|
masterkey = parseMasterKey(args.masterkey, false)
|
||||||
_, confFile, err = configfile.LoadConfFile(args.config, nil)
|
_, confFile, err = configfile.LoadConfFile(args.config, nil)
|
||||||
} else {
|
} else {
|
||||||
pw := readpassword.Once(args.extpass)
|
pw := readpassword.Once(args.extpass, "")
|
||||||
tlog.Info.Println("Decrypting master key")
|
tlog.Info.Println("Decrypting master key")
|
||||||
masterkey, confFile, err = configfile.LoadConfFile(args.config, pw)
|
masterkey, confFile, err = configfile.LoadConfFile(args.config, pw)
|
||||||
for i := range pw {
|
for i := range pw {
|
||||||
|
10
masterkey.go
10
masterkey.go
@ -46,7 +46,7 @@ paper and store it in a drawer. Use "-q" to suppress this message.
|
|||||||
|
|
||||||
// parseMasterKey - Parse a hex-encoded master key that was passed on the command line
|
// parseMasterKey - Parse a hex-encoded master key that was passed on the command line
|
||||||
// Calls os.Exit on failure
|
// Calls os.Exit on failure
|
||||||
func parseMasterKey(masterkey string) []byte {
|
func parseMasterKey(masterkey string, fromStdin bool) []byte {
|
||||||
masterkey = strings.Replace(masterkey, "-", "", -1)
|
masterkey = strings.Replace(masterkey, "-", "", -1)
|
||||||
key, err := hex.DecodeString(masterkey)
|
key, err := hex.DecodeString(masterkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -58,8 +58,10 @@ func parseMasterKey(masterkey string) []byte {
|
|||||||
os.Exit(exitcodes.MasterKey)
|
os.Exit(exitcodes.MasterKey)
|
||||||
}
|
}
|
||||||
tlog.Info.Printf("Using explicit master key.")
|
tlog.Info.Printf("Using explicit master key.")
|
||||||
tlog.Info.Printf(tlog.ColorYellow +
|
if !fromStdin {
|
||||||
"THE MASTER KEY IS VISIBLE VIA \"ps ax\" AND MAY BE STORED IN YOUR SHELL HISTORY!\n" +
|
tlog.Info.Printf(tlog.ColorYellow +
|
||||||
"ONLY USE THIS MODE FOR EMERGENCIES." + tlog.ColorReset)
|
"THE MASTER KEY IS VISIBLE VIA \"ps ax\" AND MAY BE STORED IN YOUR SHELL HISTORY!\n" +
|
||||||
|
"ONLY USE THIS MODE FOR EMERGENCIES" + tlog.ColorReset)
|
||||||
|
}
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
9
mount.go
9
mount.go
@ -98,9 +98,14 @@ func doMount(args *argContainer) {
|
|||||||
{
|
{
|
||||||
// Get master key (may prompt for the password)
|
// Get master key (may prompt for the password)
|
||||||
var masterkey []byte
|
var masterkey []byte
|
||||||
|
masterkeyFromStdin := false
|
||||||
|
if args.masterkey == "stdin" {
|
||||||
|
args.masterkey = string(readpassword.Once("", "Masterkey"))
|
||||||
|
masterkeyFromStdin = true
|
||||||
|
}
|
||||||
if args.masterkey != "" {
|
if args.masterkey != "" {
|
||||||
// "-masterkey"
|
// "-masterkey"
|
||||||
masterkey = parseMasterKey(args.masterkey)
|
masterkey = parseMasterKey(args.masterkey, masterkeyFromStdin)
|
||||||
} else if args.zerokey {
|
} else if args.zerokey {
|
||||||
// "-zerokey"
|
// "-zerokey"
|
||||||
tlog.Info.Printf("Using all-zero dummy master key.")
|
tlog.Info.Printf("Using all-zero dummy master key.")
|
||||||
@ -354,7 +359,7 @@ func initFuseFrontend(masterkey []byte, args *argContainer, confFile *configfile
|
|||||||
}
|
}
|
||||||
srv, err := fuse.NewServer(conn.RawFS(), args.mountpoint, &mOpts)
|
srv, err := fuse.NewServer(conn.RawFS(), args.mountpoint, &mOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tlog.Fatal.Printf("fuse.NewServer failed: %v", err)
|
tlog.Fatal.Printf("fuse.NewServer failed: %q", err)
|
||||||
if runtime.GOOS == "darwin" {
|
if runtime.GOOS == "darwin" {
|
||||||
tlog.Info.Printf("Maybe you should run: /Library/Filesystems/osxfuse.fs/Contents/Resources/load_osxfuse")
|
tlog.Info.Printf("Maybe you should run: /Library/Filesystems/osxfuse.fs/Contents/Resources/load_osxfuse")
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -252,6 +253,38 @@ func TestExampleFSv13(t *testing.T) {
|
|||||||
test_helpers.UnmountPanic(pDir)
|
test_helpers.UnmountPanic(pDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that the masterkey=stdin cli option works.
|
||||||
|
func TestExampleFSv13MasterkeyStdin(t *testing.T) {
|
||||||
|
cDir := "v1.3"
|
||||||
|
pDir := test_helpers.TmpDir + "/TestExampleFSv13MasterkeyStdin.mnt"
|
||||||
|
err := os.Mkdir(pDir, 0777)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
args := []string{"-q", "-masterkey=stdin", opensslOpt, cDir, pDir}
|
||||||
|
cmd := exec.Command(test_helpers.GocryptfsBinary, args...)
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
p, err := cmd.StdinPipe()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = cmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
// Write masterkey to stdin
|
||||||
|
p.Write([]byte("fd890dab-86bf61cf-ec5ad460-ad3ed01f-9c52d546-2a31783d-a56b088d-3d05232e"))
|
||||||
|
p.Close()
|
||||||
|
err = cmd.Wait()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
// Check that the fs decrypts ok & unmount
|
||||||
|
checkExampleFSLongnames(t, pDir)
|
||||||
|
test_helpers.UnmountPanic(pDir)
|
||||||
|
}
|
||||||
|
|
||||||
// gocryptfs v1.3 introduced HKDF.
|
// gocryptfs v1.3 introduced HKDF.
|
||||||
// We check the md5 sum of the encrypted version of a file to make sure we don't
|
// We check the md5 sum of the encrypted version of a file to make sure we don't
|
||||||
// accidentially change the ciphertext generation.
|
// accidentially change the ciphertext generation.
|
||||||
|
Loading…
Reference in New Issue
Block a user