remove Trezor support

libgocryptfs
Pavol Rusnak 3 years ago committed by rfjakob
parent 7dda2363e1
commit 1364b44ae3
  1. 10
      Documentation/MANPAGE.md
  2. 10
      cli_args.go
  3. 14
      init_dir.go
  4. 10
      internal/configfile/config_file.go
  5. 8
      internal/configfile/config_test.go
  6. 4
      internal/configfile/feature_flags.go
  7. 4
      internal/exitcodes/exitcodes.go
  8. 119
      internal/readpassword/trezor.go.broken
  9. 25
      internal/readpassword/trezor_disabled.go
  10. 31
      main.go
  11. 58
      tests/trezor/trezor_test.go

@ -405,16 +405,6 @@ You need root permissions to use `-suid`.
#### -trace string
Write execution trace to file. View the trace using "go tool trace FILE".
#### -trezor
With `-init`: Protect the masterkey using a SatoshiLabs Trezor instead of a password.
This feature is disabled by default and must be enabled at compile time using:
./build.bash -tags enable_trezor
You can determine if your gocryptfs binary has Trezor support enabled checking
if the `gocryptfs -version` output contains the string `enable_trezor`.
#### -version
Print version and exit. The output contains three fields separated by ";".
Example: "gocryptfs v1.1.1-5-g75b776c; go-fuse 6b801d3; 2016-11-01 go1.7.3".

@ -18,7 +18,6 @@ import (
"github.com/rfjakob/gocryptfs/internal/configfile"
"github.com/rfjakob/gocryptfs/internal/exitcodes"
"github.com/rfjakob/gocryptfs/internal/prefer_openssl"
"github.com/rfjakob/gocryptfs/internal/readpassword"
"github.com/rfjakob/gocryptfs/internal/stupidgcm"
"github.com/rfjakob/gocryptfs/internal/tlog"
)
@ -29,7 +28,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, trezor bool
sharedstorage, devrandom, fsck bool
// Mount options with opposites
dev, nodev, suid, nosuid, exec, noexec, rw, ro bool
masterkey, mountpoint, cipherdir, cpuprofile,
@ -170,9 +169,6 @@ 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")
if readpassword.TrezorSupport {
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")
@ -282,10 +278,6 @@ func parseCliOpts() (args argContainer) {
tlog.Fatal.Printf("The options -extpass and -masterkey cannot be used at the same time")
os.Exit(exitcodes.Usage)
}
if !args.extpass.Empty() && args.trezor {
tlog.Fatal.Printf("The options -extpass and -trezor cannot be used at the same time")
os.Exit(exitcodes.Usage)
}
if args.idle < 0 {
tlog.Fatal.Printf("Idle timeout cannot be less than 0")
os.Exit(exitcodes.Usage)

@ -9,7 +9,6 @@ import (
"syscall"
"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"
@ -72,19 +71,10 @@ func initDir(args *argContainer) {
tlog.Info.Printf("Choose a password for protecting your files.")
}
{
var password []byte
var trezorPayload []byte
if args.trezor {
trezorPayload = cryptocore.RandBytes(readpassword.TrezorPayloadLen)
// Get binary data from from Trezor
password = readpassword.Trezor(trezorPayload)
} else {
// Normal password entry
password = readpassword.Twice([]string(args.extpass), args.passfile)
}
password := readpassword.Twice([]string(args.extpass), args.passfile)
creator := tlog.ProgramName + " " + GitVersion
err = configfile.Create(args.config, password, args.plaintextnames,
args.scryptn, creator, args.aessiv, args.devrandom, trezorPayload)
args.scryptn, creator, args.aessiv, args.devrandom)
if err != nil {
tlog.Fatal.Println(err)
os.Exit(exitcodes.WriteConf)

@ -46,10 +46,6 @@ 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
}
@ -73,7 +69,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, trezorPayload []byte) error {
logN int, creator string, aessiv bool, devrandom bool) error {
var cf ConfFile
cf.filename = filename
cf.Creator = creator
@ -93,10 +89,6 @@ func Create(filename string, password []byte, plaintextNames bool,
if aessiv {
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagAESSIV])
}
if len(trezorPayload) > 0 {
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagTrezor])
cf.TrezorPayload = trezorPayload
}
{
// Generate new random master key
var key []byte

@ -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, nil)
err := Create("config_test/tmp.conf", testPw, false, 10, "test", false, false)
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, nil)
err := Create("config_test/tmp.conf", testPw, false, 10, "test", false, true)
if err != nil {
t.Fatal(err)
}
}
func TestCreateConfPlaintextnames(t *testing.T) {
err := Create("config_test/tmp.conf", testPw, true, 10, "test", false, false, nil)
err := Create("config_test/tmp.conf", testPw, true, 10, "test", 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 := Create("config_test/tmp.conf", testPw, false, 10, "test", true, false, nil)
err := Create("config_test/tmp.conf", testPw, false, 10, "test", true, false)
if err != nil {
t.Fatal(err)
}

@ -25,9 +25,6 @@ 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
@ -40,7 +37,6 @@ var knownFlags = map[flagIota]string{
FlagAESSIV: "AESSIV",
FlagRaw64: "Raw64",
FlagHKDF: "HKDF",
FlagTrezor: "Trezor",
}
// Filesystems that do not have these feature flags set are deprecated.

@ -65,9 +65,7 @@ const (
FsckErrors = 26
// DeprecatedFS - this filesystem is deprecated
DeprecatedFS = 27
// TrezorError - an error was encountered while interacting with a Trezor
// device
TrezorError = 28
// skip 28
// ExcludeError - an error occurred while processing "-exclude"
ExcludeError = 29
// DevNull means that /dev/null could not be opened

@ -1,119 +0,0 @@
// +build enable_trezor
package readpassword
import (
"bytes"
"log"
"os"
"github.com/rfjakob/gocryptfs/internal/exitcodes"
"github.com/rfjakob/gocryptfs/internal/tlog"
"github.com/xaionaro-go/cryptoWallet"
"github.com/xaionaro-go/cryptoWallet/vendors"
)
const (
// TrezorPayloadLen is the length of the payload data passed to Trezor's
// CipherKeyValue function.
TrezorPayloadLen = 32
trezorNonce = "" // the "nonce" is optional and has no use in here
trezorKeyName = "gocryptfs"
trezorKeyDerivationPath = `m/10019'/0'`
// TrezorSupport is true when gocryptfs has been compile with -tags enable_trezor
TrezorSupport = true
)
func trezorGetPin(title, description, ok, cancel string) ([]byte, error) {
return Once("", title), nil
}
func trezorGetConfirm(title, description, ok, cancel string) (bool, error) {
return false, nil // do not retry on connection failure
}
// Trezor reads 32 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 32 bytes or calls os.Exit to end
// the application.
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)
}
// Find all trezor devices
trezors := cryptoWallet.Find(cryptoWallet.Filter{
VendorID: &[]uint16{vendors.GetVendorID("satoshilabs")}[0],
ProductIDs: []uint16{1 /* Trezor One */},
})
// ATM, we require to one and only one trezor device to be connected.
// The support of multiple trezor devices is not implemented, yet.
if len(trezors) == 0 {
tlog.Fatal.Printf("Trezor device is not found. Check the connection.")
os.Exit(exitcodes.TrezorError)
}
if len(trezors) > 1 {
tlog.Fatal.Printf("It's more than one Trezor device connected. This case is not implemented, yet. The number of currently connected devices: %v.", len(trezors))
os.Exit(exitcodes.TrezorError)
}
// Using the first found device
trezor := trezors[0]
// Trezor may ask for PIN or Passphrase. Setting the handler for this case.
trezor.SetGetPinFunc(trezorGetPin)
// In some cases (like lost connection to the Trezor device and cannot
// reconnect) it's required to get a confirmation from the user to
// retry to reconnect. Setting the handler for this case.
trezor.SetGetConfirmFunc(trezorGetConfirm)
// To reset the state of the device and check if it's initialized.
// If device is not initialized then trezor.Reset() will return an
// error.
err := trezor.Reset()
if err != nil {
tlog.Fatal.Printf("Cannot reset the Trezor device. Error: %v", err.Error())
os.Exit(exitcodes.TrezorError)
}
// To generate a deterministic key we trying to decrypt our
// predefined constant key using the Trezor device. The resulting key
// will depend on next variables:
// * the Trezor master key;
// * the passphrase (passed to the Trezor).
//
// The right key will be received only if both values (mentioned
// above) are correct.
//
// Note:
// Also the resulting key depends on this values (that we defined as
// constants above):
// * the key derivation path;
// * the "encrypted" payload;
// * the nonce;
// * the key name.
key, err := trezor.DecryptKey(trezorKeyDerivationPath, payload, []byte(trezorNonce), trezorKeyName)
if err != nil {
tlog.Fatal.Printf("Cannot get the key from the Trezor device. Error description:\n\t%v", err.Error())
os.Exit(exitcodes.TrezorError)
}
// Sanity checks
if len(key) != TrezorPayloadLen {
log.Panicf("BUG: decrypted value has wrong length %d", len(key))
}
if bytes.Equal(key, payload) {
log.Panicf("BUG: payload and decrypted value are identical")
}
zero := make([]byte, TrezorPayloadLen)
if bytes.Equal(key, zero) {
log.Panicf("BUG: decrypted value is all-zero")
}
// Everything ok
return key
}

@ -1,25 +0,0 @@
// +build !enable_trezor
package readpassword
import (
"os"
"github.com/rfjakob/gocryptfs/internal/tlog"
)
const (
// TrezorPayloadLen is the length of the payload data passed to Trezor's
// CipherKeyValue function.
TrezorPayloadLen = 32
// TrezorSupport is true when gocryptfs has been compile with -tags enable_trezor
TrezorSupport = false
)
// Trezor determinitically derives 32 bytes from the payload and the connected
// USB security module.
func Trezor(payload []byte) []byte {
tlog.Fatal.Printf("This binary has been compiled without Trezor support")
os.Exit(1)
return nil
}

@ -34,8 +34,7 @@ var raceDetector bool
// loadConfig loads the config file "args.config", prompting the user for the password
func loadConfig(args *argContainer) (masterkey []byte, cf *configfile.ConfFile, err error) {
// First check if the file can be read at all, and find out if a Trezor should
// be used instead of a password.
// First check if the file can be read at all.
cf, err = configfile.Load(args.config)
if err != nil {
tlog.Fatal.Printf("Cannot open config file: %v", err)
@ -47,14 +46,7 @@ func loadConfig(args *argContainer) (masterkey []byte, cf *configfile.ConfFile,
masterkey = parseMasterKey(args.masterkey, false)
return masterkey, cf, nil
}
var pw []byte
if cf.IsFeatureFlagSet(configfile.FlagTrezor) {
// Get binary data from Trezor
pw = readpassword.Trezor(cf.TrezorPayload)
} else {
// Normal password entry
pw = readpassword.Once([]string(args.extpass), args.passfile, "")
}
pw := readpassword.Once([]string(args.extpass), args.passfile, "")
tlog.Info.Println("Decrypting master key")
masterkey, err = cf.DecryptMasterKey(pw)
for i := range pw {
@ -71,20 +63,10 @@ func loadConfig(args *argContainer) (masterkey []byte, cf *configfile.ConfFile,
// changePassword - change the password of config file "filename"
// Does not return (calls os.Exit both on success and on error).
func changePassword(args *argContainer) {
// Parse the config file, but do not unlock the master key. We only want to
// know if the Trezor flag is set.
cf1, err := configfile.Load(args.config)
if err != nil {
tlog.Fatal.Printf("Cannot open config file: %v", err)
os.Exit(exitcodes.LoadConf)
}
if cf1.IsFeatureFlagSet(configfile.FlagTrezor) {
tlog.Fatal.Printf("Password change is not supported on Trezor-enabled filesystems.")
os.Exit(exitcodes.Usage)
}
var confFile *configfile.ConfFile
{
var masterkey []byte
var err error
masterkey, confFile, err = loadConfig(args)
if err != nil {
exitcodes.Exit(err)
@ -111,7 +93,7 @@ func changePassword(args *argContainer) {
// "-masterkey"?
if args.masterkey != "" {
bak := args.config + ".bak"
err = os.Link(args.config, bak)
err := os.Link(args.config, bak)
if err != nil {
tlog.Fatal.Printf("Could not create backup file: %v", err)
os.Exit(exitcodes.Init)
@ -121,7 +103,7 @@ func changePassword(args *argContainer) {
"Delete it after you have verified that you can access your files with the new password."+
tlog.ColorReset, bak)
}
err = confFile.WriteFile()
err := confFile.WriteFile()
if err != nil {
tlog.Fatal.Println(err)
os.Exit(exitcodes.WriteConf)
@ -136,9 +118,6 @@ func printVersion() {
if stupidgcm.BuiltWithoutOpenssl {
tagsSlice = append(tagsSlice, "without_openssl")
}
if readpassword.TrezorSupport {
tagsSlice = append(tagsSlice, "enable_trezor")
}
tags := ""
if tagsSlice != nil {
tags = " " + strings.Join(tagsSlice, " ")

@ -1,58 +0,0 @@
package trezor
// Test operations with "-trezor".
// See also the "cli" package - the tests there are very similar.
import (
"os/exec"
"runtime"
"testing"
"github.com/rfjakob/gocryptfs/internal/configfile"
"github.com/rfjakob/gocryptfs/internal/exitcodes"
"github.com/rfjakob/gocryptfs/tests/test_helpers"
)
func isTrezorConnected() bool {
if runtime.GOOS != "linux" {
return false
}
c := exec.Command("lsusb", "-d", "534c:0001")
err := c.Run()
if err != nil {
return false
}
return true
}
// Test -init with -trezor
func TestInitTrezor(t *testing.T) {
if !isTrezorConnected() {
t.Skip("No Trezor device connected")
}
t.Log("Trying gocryptfs -init -trezor ...")
// vvvvvvvvvvvvv disable -extpass
dir := test_helpers.InitFS(t, "-trezor", "-extpass", "")
// The freshly created config file should have the Trezor feature flag set.
c, err := configfile.Load(dir + "/" + configfile.ConfDefaultName)
if err != nil {
t.Fatal(err)
}
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).
func TestTrezorExtpass(t *testing.T) {
cmd := exec.Command(test_helpers.GocryptfsBinary, "-init", "-trezor", "-extpass", "foo", "/tmp")
err := cmd.Run()
exitCode := test_helpers.ExtractCmdExitCode(err)
if exitCode != exitcodes.Usage {
t.Errorf("wrong exit code: want %d, have %d", exitcodes.Usage, exitCode)
}
}
Loading…
Cancel
Save