summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli_args.go3
-rw-r--r--init_dir.go21
-rw-r--r--internal/configfile/config_file.go6
-rw-r--r--internal/configfile/config_test.go8
-rw-r--r--internal/configfile/feature_flags.go4
-rw-r--r--internal/exitcodes/exitcodes.go3
-rw-r--r--internal/readpassword/trezor.go26
-rw-r--r--main.go36
-rw-r--r--masterkey.go4
-rw-r--r--tests/fsck/fsck_test.go1
10 files changed, 86 insertions, 26 deletions
diff --git a/cli_args.go b/cli_args.go
index 08b3186..7e8deeb 100644
--- a/cli_args.go
+++ b/cli_args.go
@@ -22,7 +22,7 @@ type argContainer struct {
plaintextnames, quiet, nosyslog, wpanic,
longnames, allow_other, reverse, aessiv, nonempty, raw64,
noprealloc, speed, hkdf, serialize_reads, forcedecode, hh, info,
- sharedstorage, devrandom, fsck bool
+ sharedstorage, devrandom, fsck, trezor bool
// Mount options with opposites
dev, nodev, suid, nosuid, exec, noexec, rw, ro bool
masterkey, mountpoint, cipherdir, cpuprofile, extpass,
@@ -138,6 +138,7 @@ func parseCliOpts() (args argContainer) {
flagSet.BoolVar(&args.sharedstorage, "sharedstorage", false, "Make concurrent access to a shared CIPHERDIR safer")
flagSet.BoolVar(&args.devrandom, "devrandom", false, "Use /dev/random for generating master key")
flagSet.BoolVar(&args.fsck, "fsck", false, "Run a filesystem check on CIPHERDIR")
+ flagSet.BoolVar(&args.trezor, "trezor", false, "Protect the masterkey using a SatoshiLabs Trezor instead of a password")
// Mount options with opposites
flagSet.BoolVar(&args.dev, "dev", false, "Allow device files")
diff --git a/init_dir.go b/init_dir.go
index 0e1ad95..ea6fff4 100644
--- a/init_dir.go
+++ b/init_dir.go
@@ -43,11 +43,12 @@ func isDir(dir string) error {
return nil
}
-// initDir prepares a directory for use as a gocryptfs storage directory.
+// initDir handles "gocryptfs -init". It prepares a directory for use as a
+// gocryptfs storage directory.
// In forward mode, this means creating the gocryptfs.conf and gocryptfs.diriv
// files in an empty directory.
// In reverse mode, we create .gocryptfs.reverse.conf and the directory does
-// not to be empty.
+// not need to be empty.
func initDir(args *argContainer) {
var err error
if args.reverse {
@@ -68,10 +69,18 @@ func initDir(args *argContainer) {
tlog.Info.Printf("Choose a password for protecting your files.")
}
{
+ var password []byte
+ if args.trezor {
+ // Get binary data from from Trezor
+ password = readpassword.Trezor()
+ } else {
+ // Normal password entry
+ password = readpassword.Twice(args.extpass)
+ readpassword.CheckTrailingGarbage()
+ }
creator := tlog.ProgramName + " " + GitVersion
- password := readpassword.Twice(args.extpass)
- readpassword.CheckTrailingGarbage()
- err = configfile.CreateConfFile(args.config, password, args.plaintextnames, args.scryptn, creator, args.aessiv, args.devrandom)
+ err = configfile.CreateConfFile(args.config, password, args.plaintextnames,
+ args.scryptn, creator, args.aessiv, args.devrandom, args.trezor)
if err != nil {
tlog.Fatal.Println(err)
os.Exit(exitcodes.WriteConf)
@@ -81,7 +90,7 @@ func initDir(args *argContainer) {
}
// password runs out of scope here
}
- // Forward mode with filename encryption enabled needs a gocryptfs.diriv
+ // Forward mode with filename encryption enabled needs a gocryptfs.diriv file
// in the root dir
if !args.plaintextnames && !args.reverse {
err = nametransform.WriteDirIV(nil, args.cipherdir)
diff --git a/internal/configfile/config_file.go b/internal/configfile/config_file.go
index 0d5e545..da6c4da 100644
--- a/internal/configfile/config_file.go
+++ b/internal/configfile/config_file.go
@@ -67,7 +67,8 @@ func randBytesDevRandom(n int) []byte {
// CreateConfFile - create a new config with a random key encrypted with
// "password" and write it to "filename".
// Uses scrypt with cost parameter logN.
-func CreateConfFile(filename string, password []byte, plaintextNames bool, logN int, creator string, aessiv bool, devrandom bool) error {
+func CreateConfFile(filename string, password []byte, plaintextNames bool,
+ logN int, creator string, aessiv bool, devrandom bool, trezor bool) error {
var cf ConfFile
cf.filename = filename
cf.Creator = creator
@@ -87,6 +88,9 @@ func CreateConfFile(filename string, password []byte, plaintextNames bool, logN
if aessiv {
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagAESSIV])
}
+ if trezor {
+ cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagTrezor])
+ }
{
// Generate new random master key
var key []byte
diff --git a/internal/configfile/config_test.go b/internal/configfile/config_test.go
index 15728c6..3152ab5 100644
--- a/internal/configfile/config_test.go
+++ b/internal/configfile/config_test.go
@@ -62,7 +62,7 @@ func TestLoadV2StrangeFeature(t *testing.T) {
}
func TestCreateConfDefault(t *testing.T) {
- err := CreateConfFile("config_test/tmp.conf", testPw, false, 10, "test", false, false)
+ err := CreateConfFile("config_test/tmp.conf", testPw, false, 10, "test", false, false, false)
if err != nil {
t.Fatal(err)
}
@@ -83,14 +83,14 @@ func TestCreateConfDefault(t *testing.T) {
}
func TestCreateConfDevRandom(t *testing.T) {
- err := CreateConfFile("config_test/tmp.conf", testPw, false, 10, "test", false, true)
+ err := CreateConfFile("config_test/tmp.conf", testPw, false, 10, "test", false, true, false)
if err != nil {
t.Fatal(err)
}
}
func TestCreateConfPlaintextnames(t *testing.T) {
- err := CreateConfFile("config_test/tmp.conf", testPw, true, 10, "test", false, false)
+ err := CreateConfFile("config_test/tmp.conf", testPw, true, 10, "test", false, false, false)
if err != nil {
t.Fatal(err)
}
@@ -111,7 +111,7 @@ func TestCreateConfPlaintextnames(t *testing.T) {
// Reverse mode uses AESSIV
func TestCreateConfFileAESSIV(t *testing.T) {
- err := CreateConfFile("config_test/tmp.conf", testPw, false, 10, "test", true, false)
+ err := CreateConfFile("config_test/tmp.conf", testPw, false, 10, "test", true, false, false)
if err != nil {
t.Fatal(err)
}
diff --git a/internal/configfile/feature_flags.go b/internal/configfile/feature_flags.go
index 2d609f2..141b007 100644
--- a/internal/configfile/feature_flags.go
+++ b/internal/configfile/feature_flags.go
@@ -25,6 +25,9 @@ const (
// Note that this flag does not change the password hashing algorithm
// which always is scrypt.
FlagHKDF
+ // FlagTrezor means that "-trezor" was used when creating the filesystem.
+ // The masterkey is protected using a Trezor device instead of a password.
+ FlagTrezor
)
// knownFlags stores the known feature flags and their string representation
@@ -37,6 +40,7 @@ var knownFlags = map[flagIota]string{
FlagAESSIV: "AESSIV",
FlagRaw64: "Raw64",
FlagHKDF: "HKDF",
+ FlagTrezor: "Trezor",
}
// Filesystems that do not have these feature flags set are deprecated.
diff --git a/internal/exitcodes/exitcodes.go b/internal/exitcodes/exitcodes.go
index fc65166..3fbfdc6 100644
--- a/internal/exitcodes/exitcodes.go
+++ b/internal/exitcodes/exitcodes.go
@@ -65,6 +65,9 @@ const (
FsckErrors = 26
// DeprecatedFS - this filesystem is deprecated
DeprecatedFS = 27
+ // TrezorError - an error was encountered while interacting with a Trezor
+ // device
+ TrezorError = 28
)
// Err wraps an error with an associated numeric exit code
diff --git a/internal/readpassword/trezor.go b/internal/readpassword/trezor.go
new file mode 100644
index 0000000..37dde79
--- /dev/null
+++ b/internal/readpassword/trezor.go
@@ -0,0 +1,26 @@
+package readpassword
+
+import (
+ "os"
+
+ "github.com/rfjakob/gocryptfs/internal/exitcodes"
+ "github.com/rfjakob/gocryptfs/internal/tlog"
+)
+
+// Trezor reads 16 deterministically derived bytes from a
+// SatoshiLabs Trezor USB security module.
+// The bytes are pseudorandom binary data and may contain null bytes.
+// This function either succeeds and returns 16 bytes or calls os.Exit to end
+// the application.
+func Trezor() []byte {
+ var err error
+ // TODO try to read bytes here....
+ // Handle errors
+ if err != nil {
+ tlog.Fatal.Printf("xxx some error was encountered...")
+ os.Exit(exitcodes.TrezorError)
+ }
+
+ tlog.Warn.Println("XXX readpassword.Trezor(): not implemented yet - returning hardcoded dummy bytes XXX")
+ return []byte("1234567890123456")
+}
diff --git a/main.go b/main.go
index 226a20a..9fdbc6e 100644
--- a/main.go
+++ b/main.go
@@ -33,26 +33,33 @@ var raceDetector bool
// loadConfig loads the config file "args.config", prompting the user for the password
func loadConfig(args *argContainer) (masterkey []byte, confFile *configfile.ConfFile, err error) {
- // Check if the file can be opened at all before prompting for a password
- fd, err := os.Open(args.config)
+ // First check if the file can be read at all, and find out if a Trezor should
+ // be used instead of a password.
+ _, cf1, err := configfile.LoadConfFile(args.config, nil)
if err != nil {
tlog.Fatal.Printf("Cannot open config file: %v", err)
- return nil, nil, exitcodes.NewErr(err.Error(), exitcodes.OpenConf)
+ return nil, nil, err
}
- fd.Close()
- // The user has passed the master key (probably because he forgot the
- // password).
+ // The user has passed the master key on the command line (probably because
+ // he forgot the password).
if args.masterkey != "" {
masterkey = parseMasterKey(args.masterkey, false)
- _, confFile, err = configfile.LoadConfFile(args.config, nil)
+ return masterkey, cf1, nil
+ }
+ var pw []byte
+ if cf1.IsFeatureFlagSet(configfile.FlagTrezor) {
+ // Get binary data from from Trezor
+ pw = readpassword.Trezor()
} else {
- pw := readpassword.Once(args.extpass, "")
- tlog.Info.Println("Decrypting master key")
- masterkey, confFile, err = configfile.LoadConfFile(args.config, pw)
- for i := range pw {
- pw[i] = 0
- }
+ // Normal password entry
+ pw = readpassword.Once(args.extpass, "")
}
+ tlog.Info.Println("Decrypting master key")
+ masterkey, confFile, err = configfile.LoadConfFile(args.config, pw)
+ for i := range pw {
+ pw[i] = 0
+ }
+
if err != nil {
tlog.Fatal.Println(err)
return nil, nil, err
@@ -71,6 +78,9 @@ func changePassword(args *argContainer) {
if err != nil {
exitcodes.Exit(err)
}
+ if len(masterkey) == 0 {
+ panic("empty masterkey")
+ }
tlog.Info.Println("Please enter your new password.")
newPw := readpassword.Twice(args.extpass)
readpassword.CheckTrailingGarbage()
diff --git a/masterkey.go b/masterkey.go
index c67f115..1b4d9c3 100644
--- a/masterkey.go
+++ b/masterkey.go
@@ -103,7 +103,9 @@ func getMasterKey(args *argContainer) (masterkey []byte, confFile *configfile.Co
}
exitcodes.Exit(err)
}
- readpassword.CheckTrailingGarbage()
+ if !args.trezor {
+ readpassword.CheckTrailingGarbage()
+ }
if !args.fsck {
// We only want to print the masterkey message on a normal mount.
printMasterKey(masterkey)
diff --git a/tests/fsck/fsck_test.go b/tests/fsck/fsck_test.go
index 2faed97..8e73cf7 100644
--- a/tests/fsck/fsck_test.go
+++ b/tests/fsck/fsck_test.go
@@ -69,6 +69,7 @@ func TestExampleFses(t *testing.T) {
fsNames = append(fsNames, e.Name())
}
for _, n := range fsNames {
+ t.Logf("Checking %q", n)
path := "../example_filesystems/" + n
cmd := exec.Command(test_helpers.GocryptfsBinary, "-fsck", "-extpass", "echo test", path)
outBin, err := cmd.CombinedOutput()