trezor: add skeleton for Trezor support

readpassword.Trezor() is not implemented yet and returns
a hardcoded dummy key.
This commit is contained in:
Jakob Unterwurzacher 2018-06-17 15:25:09 +02:00
parent 02ab358451
commit c6f6e8ec4d
10 changed files with 87 additions and 27 deletions

View File

@ -22,7 +22,7 @@ type argContainer struct {
plaintextnames, quiet, nosyslog, wpanic, plaintextnames, quiet, nosyslog, wpanic,
longnames, allow_other, reverse, aessiv, nonempty, raw64, longnames, allow_other, reverse, aessiv, nonempty, raw64,
noprealloc, speed, hkdf, serialize_reads, forcedecode, hh, info, noprealloc, speed, hkdf, serialize_reads, forcedecode, hh, info,
sharedstorage, devrandom, fsck bool sharedstorage, devrandom, fsck, trezor bool
// Mount options with opposites // Mount options with opposites
dev, nodev, suid, nosuid, exec, noexec, rw, ro bool dev, nodev, suid, nosuid, exec, noexec, rw, ro bool
masterkey, mountpoint, cipherdir, cpuprofile, extpass, 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.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.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.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 // Mount options with opposites
flagSet.BoolVar(&args.dev, "dev", false, "Allow device files") flagSet.BoolVar(&args.dev, "dev", false, "Allow device files")

View File

@ -43,11 +43,12 @@ func isDir(dir string) error {
return nil 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 // In forward mode, this means creating the gocryptfs.conf and gocryptfs.diriv
// files in an empty directory. // files in an empty directory.
// In reverse mode, we create .gocryptfs.reverse.conf and the directory does // 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) { func initDir(args *argContainer) {
var err error var err error
if args.reverse { if args.reverse {
@ -68,10 +69,18 @@ func initDir(args *argContainer) {
tlog.Info.Printf("Choose a password for protecting your files.") 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 creator := tlog.ProgramName + " " + GitVersion
password := readpassword.Twice(args.extpass) err = configfile.CreateConfFile(args.config, password, args.plaintextnames,
readpassword.CheckTrailingGarbage() args.scryptn, creator, args.aessiv, args.devrandom, args.trezor)
err = configfile.CreateConfFile(args.config, password, args.plaintextnames, args.scryptn, creator, args.aessiv, args.devrandom)
if err != nil { if err != nil {
tlog.Fatal.Println(err) tlog.Fatal.Println(err)
os.Exit(exitcodes.WriteConf) os.Exit(exitcodes.WriteConf)
@ -81,7 +90,7 @@ func initDir(args *argContainer) {
} }
// password runs out of scope here // 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 // in the root dir
if !args.plaintextnames && !args.reverse { if !args.plaintextnames && !args.reverse {
err = nametransform.WriteDirIV(nil, args.cipherdir) err = nametransform.WriteDirIV(nil, args.cipherdir)

View File

@ -67,7 +67,8 @@ func randBytesDevRandom(n int) []byte {
// CreateConfFile - create a new config with a random key encrypted with // CreateConfFile - create a new config with a random key encrypted with
// "password" and write it to "filename". // "password" and write it to "filename".
// Uses scrypt with cost parameter logN. // 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 var cf ConfFile
cf.filename = filename cf.filename = filename
cf.Creator = creator cf.Creator = creator
@ -87,6 +88,9 @@ func CreateConfFile(filename string, password []byte, plaintextNames bool, logN
if aessiv { if aessiv {
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagAESSIV]) cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagAESSIV])
} }
if trezor {
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagTrezor])
}
{ {
// Generate new random master key // Generate new random master key
var key []byte var key []byte

View File

@ -62,7 +62,7 @@ func TestLoadV2StrangeFeature(t *testing.T) {
} }
func TestCreateConfDefault(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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -83,14 +83,14 @@ func TestCreateConfDefault(t *testing.T) {
} }
func TestCreateConfDevRandom(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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestCreateConfPlaintextnames(t *testing.T) { 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -111,7 +111,7 @@ func TestCreateConfPlaintextnames(t *testing.T) {
// Reverse mode uses AESSIV // Reverse mode uses AESSIV
func TestCreateConfFileAESSIV(t *testing.T) { 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -25,6 +25,9 @@ const (
// Note that this flag does not change the password hashing algorithm // Note that this flag does not change the password hashing algorithm
// which always is scrypt. // which always is scrypt.
FlagHKDF 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 // knownFlags stores the known feature flags and their string representation
@ -37,6 +40,7 @@ var knownFlags = map[flagIota]string{
FlagAESSIV: "AESSIV", FlagAESSIV: "AESSIV",
FlagRaw64: "Raw64", FlagRaw64: "Raw64",
FlagHKDF: "HKDF", FlagHKDF: "HKDF",
FlagTrezor: "Trezor",
} }
// Filesystems that do not have these feature flags set are deprecated. // Filesystems that do not have these feature flags set are deprecated.

View File

@ -65,6 +65,9 @@ const (
FsckErrors = 26 FsckErrors = 26
// DeprecatedFS - this filesystem is deprecated // DeprecatedFS - this filesystem is deprecated
DeprecatedFS = 27 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 // Err wraps an error with an associated numeric exit code

View File

@ -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")
}

38
main.go
View File

@ -33,26 +33,33 @@ var raceDetector bool
// loadConfig loads the config file "args.config", prompting the user for the password // loadConfig loads the config file "args.config", prompting the user for the password
func loadConfig(args *argContainer) (masterkey []byte, confFile *configfile.ConfFile, err error) { 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 // First check if the file can be read at all, and find out if a Trezor should
fd, err := os.Open(args.config) // be used instead of a password.
_, cf1, err := configfile.LoadConfFile(args.config, nil)
if err != nil { if err != nil {
tlog.Fatal.Printf("Cannot open config file: %v", err) 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 on the command line (probably because
// The user has passed the master key (probably because he forgot the // he forgot the password).
// password).
if args.masterkey != "" { if args.masterkey != "" {
masterkey = parseMasterKey(args.masterkey, false) masterkey = parseMasterKey(args.masterkey, false)
_, confFile, err = configfile.LoadConfFile(args.config, nil) return masterkey, cf1, nil
} 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
}
} }
var pw []byte
if cf1.IsFeatureFlagSet(configfile.FlagTrezor) {
// Get binary data from from Trezor
pw = readpassword.Trezor()
} else {
// 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 { if err != nil {
tlog.Fatal.Println(err) tlog.Fatal.Println(err)
return nil, nil, err return nil, nil, err
@ -71,6 +78,9 @@ func changePassword(args *argContainer) {
if err != nil { if err != nil {
exitcodes.Exit(err) exitcodes.Exit(err)
} }
if len(masterkey) == 0 {
panic("empty masterkey")
}
tlog.Info.Println("Please enter your new password.") tlog.Info.Println("Please enter your new password.")
newPw := readpassword.Twice(args.extpass) newPw := readpassword.Twice(args.extpass)
readpassword.CheckTrailingGarbage() readpassword.CheckTrailingGarbage()

View File

@ -103,7 +103,9 @@ func getMasterKey(args *argContainer) (masterkey []byte, confFile *configfile.Co
} }
exitcodes.Exit(err) exitcodes.Exit(err)
} }
readpassword.CheckTrailingGarbage() if !args.trezor {
readpassword.CheckTrailingGarbage()
}
if !args.fsck { if !args.fsck {
// We only want to print the masterkey message on a normal mount. // We only want to print the masterkey message on a normal mount.
printMasterKey(masterkey) printMasterKey(masterkey)

View File

@ -69,6 +69,7 @@ func TestExampleFses(t *testing.T) {
fsNames = append(fsNames, e.Name()) fsNames = append(fsNames, e.Name())
} }
for _, n := range fsNames { for _, n := range fsNames {
t.Logf("Checking %q", n)
path := "../example_filesystems/" + n path := "../example_filesystems/" + n
cmd := exec.Command(test_helpers.GocryptfsBinary, "-fsck", "-extpass", "echo test", path) cmd := exec.Command(test_helpers.GocryptfsBinary, "-fsck", "-extpass", "echo test", path)
outBin, err := cmd.CombinedOutput() outBin, err := cmd.CombinedOutput()