From 9a15dfa494c76b5fcadcd32e2e46cbee84218a87 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Mon, 25 Jun 2018 22:27:15 +0200 Subject: [PATCH] trezor: add TrezorPayload TrezorPayload stores 32 random bytes used for unlocking the master key using a Trezor security module. The randomness makes sure that a unique unlock value is used for each gocryptfs filesystem. --- init_dir.go | 7 +++++-- internal/configfile/config_file.go | 9 +++++++-- internal/configfile/config_test.go | 8 ++++---- internal/readpassword/trezor.go | 13 +++++++++++-- main.go | 2 +- tests/trezor/trezor_test.go | 3 +++ 6 files changed, 31 insertions(+), 11 deletions(-) diff --git a/init_dir.go b/init_dir.go index 0cd2957..e264cf0 100644 --- a/init_dir.go +++ b/init_dir.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/rfjakob/gocryptfs/internal/configfile" + "github.com/rfjakob/gocryptfs/internal/cryptocore" "github.com/rfjakob/gocryptfs/internal/exitcodes" "github.com/rfjakob/gocryptfs/internal/nametransform" "github.com/rfjakob/gocryptfs/internal/readpassword" @@ -70,9 +71,11 @@ func initDir(args *argContainer) { } { var password []byte + var trezorPayload []byte if args.trezor { + trezorPayload = cryptocore.RandBytes(readpassword.TrezorPayloadLen) // Get binary data from from Trezor - password = readpassword.Trezor() + password = readpassword.Trezor(trezorPayload) } else { // Normal password entry password = readpassword.Twice(args.extpass) @@ -80,7 +83,7 @@ func initDir(args *argContainer) { } creator := tlog.ProgramName + " " + GitVersion err = configfile.Create(args.config, password, args.plaintextnames, - args.scryptn, creator, args.aessiv, args.devrandom, args.trezor) + args.scryptn, creator, args.aessiv, args.devrandom, trezorPayload) if err != nil { tlog.Fatal.Println(err) os.Exit(exitcodes.WriteConf) diff --git a/internal/configfile/config_file.go b/internal/configfile/config_file.go index a70a511..c856ad0 100644 --- a/internal/configfile/config_file.go +++ b/internal/configfile/config_file.go @@ -45,6 +45,10 @@ type ConfFile struct { // mounting. This mechanism is analogous to the ext4 feature flags that are // stored in the superblock. FeatureFlags []string + // TrezorPayload stores 32 random bytes used for unlocking the master key using + // a Trezor security module. The randomness makes sure that a unique unlock + // value is used for each gocryptfs filesystem. + TrezorPayload []byte `json:",omitempty"` // Filename is the name of the config file. Not exported to JSON. filename string } @@ -68,7 +72,7 @@ func randBytesDevRandom(n int) []byte { // "password" and write it to "filename". // Uses scrypt with cost parameter logN. func Create(filename string, password []byte, plaintextNames bool, - logN int, creator string, aessiv bool, devrandom bool, trezor bool) error { + logN int, creator string, aessiv bool, devrandom bool, trezorPayload []byte) error { var cf ConfFile cf.filename = filename cf.Creator = creator @@ -88,8 +92,9 @@ func Create(filename string, password []byte, plaintextNames bool, if aessiv { cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagAESSIV]) } - if trezor { + if len(trezorPayload) > 0 { cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagTrezor]) + cf.TrezorPayload = trezorPayload } { // Generate new random master key diff --git a/internal/configfile/config_test.go b/internal/configfile/config_test.go index e130cfa..b8ee150 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 := Create("config_test/tmp.conf", testPw, false, 10, "test", false, false, false) + err := Create("config_test/tmp.conf", testPw, false, 10, "test", false, false, nil) if err != nil { t.Fatal(err) } @@ -83,14 +83,14 @@ func TestCreateConfDefault(t *testing.T) { } func TestCreateConfDevRandom(t *testing.T) { - err := Create("config_test/tmp.conf", testPw, false, 10, "test", false, true, false) + err := Create("config_test/tmp.conf", testPw, false, 10, "test", false, true, nil) if err != nil { t.Fatal(err) } } func TestCreateConfPlaintextnames(t *testing.T) { - err := Create("config_test/tmp.conf", testPw, true, 10, "test", false, false, false) + err := Create("config_test/tmp.conf", testPw, true, 10, "test", false, false, nil) 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 := Create("config_test/tmp.conf", testPw, false, 10, "test", true, false, false) + err := Create("config_test/tmp.conf", testPw, false, 10, "test", true, false, nil) if err != nil { t.Fatal(err) } diff --git a/internal/readpassword/trezor.go b/internal/readpassword/trezor.go index 37dde79..45edfd8 100644 --- a/internal/readpassword/trezor.go +++ b/internal/readpassword/trezor.go @@ -7,12 +7,22 @@ import ( "github.com/rfjakob/gocryptfs/internal/tlog" ) +const ( + // TrezorPayloadLen is the length of the payload data passed to Trezor's + // CipherKeyValue function. + TrezorPayloadLen = 32 +) + // 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 { +func Trezor(payload []byte) []byte { + if len(payload) != TrezorPayloadLen { + tlog.Fatal.Printf("Invalid TrezorPayload length: wanted %d, got %d bytes\n", TrezorPayloadLen, len(payload)) + os.Exit(exitcodes.LoadConf) + } var err error // TODO try to read bytes here.... // Handle errors @@ -20,7 +30,6 @@ func Trezor() []byte { 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 da5360b..404a95b 100644 --- a/main.go +++ b/main.go @@ -49,7 +49,7 @@ func loadConfig(args *argContainer) (masterkey []byte, confFile *configfile.Conf var pw []byte if cf1.IsFeatureFlagSet(configfile.FlagTrezor) { // Get binary data from from Trezor - pw = readpassword.Trezor() + pw = readpassword.Trezor(cf1.TrezorPayload) } else { // Normal password entry pw = readpassword.Once(args.extpass, "") diff --git a/tests/trezor/trezor_test.go b/tests/trezor/trezor_test.go index 5db56e2..59e10cb 100644 --- a/tests/trezor/trezor_test.go +++ b/tests/trezor/trezor_test.go @@ -42,6 +42,9 @@ func TestInitTrezor(t *testing.T) { if !c.IsFeatureFlagSet(configfile.FlagTrezor) { t.Error("Trezor flag should be set but is not") } + if len(c.TrezorPayload) != 32 { + t.Errorf("TrezorPayload has wrong length: %d", len(c.TrezorPayload)) + } } // Test using -trezor together with -extpass. Should fail with code 1 (usage error).