From fe7355f9ee4ae8e52a9b76202e90032d78824f21 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Fri, 27 Nov 2015 23:34:55 +0100 Subject: [PATCH] diriv: use "DirIV" flag to discern and support mounting old filesystems --- cryptfs/config_file.go | 3 ++ cryptfs/names_diriv.go | 5 +-- integration_tests/example_filesystems_test.go | 2 +- integration_tests/helpers.go | 5 +-- main.go | 34 +++++++++---------- pathfs_frontend/fs.go | 11 +++--- pathfs_frontend/names.go | 12 ++++++- 7 files changed, 44 insertions(+), 28 deletions(-) diff --git a/cryptfs/config_file.go b/cryptfs/config_file.go index 1e7e3b3..a0ab218 100644 --- a/cryptfs/config_file.go +++ b/cryptfs/config_file.go @@ -47,8 +47,11 @@ func CreateConfFile(filename string, password string, plaintextNames bool) error // This sets ScryptObject and EncryptedKey cf.EncryptKey(key, password) + // Set defaults cf.Version = HEADER_CURRENT_VERSION + cf.FeatureFlags = []string{FlagDirIV} + // Set values chosen by the user if plaintextNames { cf.FeatureFlags = append(cf.FeatureFlags, FlagPlaintextNames) } diff --git a/cryptfs/names_diriv.go b/cryptfs/names_diriv.go index ab039f0..6346bc2 100644 --- a/cryptfs/names_diriv.go +++ b/cryptfs/names_diriv.go @@ -22,8 +22,9 @@ func (be *CryptFS) readDirIV(dir string) (iv []byte, err error) { } // WriteDirIV - create diriv file inside "dir" (absolute path) -// This function is exported because it is used from pathfs_frontend -func (be *CryptFS) WriteDirIV(dir string) error { +// This function is exported because it is used from pathfs_frontend, main, +// and also the automated tests. +func WriteDirIV(dir string) error { iv := RandBytes(DIRIV_LEN) file := filepath.Join(dir, DIRIV_FILENAME) // 0444 permissions: the file is not secret but should not be written to diff --git a/integration_tests/example_filesystems_test.go b/integration_tests/example_filesystems_test.go index 644f8e7..7924736 100644 --- a/integration_tests/example_filesystems_test.go +++ b/integration_tests/example_filesystems_test.go @@ -36,7 +36,7 @@ func TestExampleFsNormal(t *testing.T) { checkStatusTxt(t, pDir+"status.txt") unmount(pDir) mount(cDir, pDir, "-masterkey", "74676e34-0b47c145-00dac61a-17a92316-"+ - "bb57044c-e205b71f-65f4fdca-7cabd4b3") + "bb57044c-e205b71f-65f4fdca-7cabd4b3", "-diriv=false") checkStatusTxt(t, pDir+"status.txt") unmount(pDir) err = os.Remove(pDir) diff --git a/integration_tests/helpers.go b/integration_tests/helpers.go index 6fc65cf..bff4e5b 100644 --- a/integration_tests/helpers.go +++ b/integration_tests/helpers.go @@ -8,6 +8,8 @@ import ( "os" "os/exec" "testing" + + "github.com/rfjakob/gocryptfs/cryptfs" ) // Note: the code assumes that all have a trailing slash @@ -38,8 +40,7 @@ func resetTmpDir() { fmt.Println(err) os.Exit(1) } - dirIV := make([]byte, 16) - err = ioutil.WriteFile(defaultCipherDir+"gocryptfs.diriv", dirIV, 0444) + err = cryptfs.WriteDirIV(defaultCipherDir) if err != nil { fmt.Println(err) os.Exit(1) diff --git a/main.go b/main.go index a6131e1..b3944cc 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,6 @@ package main import ( "flag" "fmt" - "io/ioutil" "os" "os/exec" "os/signal" @@ -34,6 +33,15 @@ const ( ERREXIT_MOUNTPOINT = 10 ) +type argContainer struct { + debug, init, zerokey, fusedebug, openssl, passwd, foreground, version, + plaintextnames, quiet, diriv bool + masterkey, mountpoint, cipherdir, cpuprofile, config, extpass string + notifypid int +} + +var flagSet *flag.FlagSet + // GitVersion will be set by the build script "build.bash" var GitVersion = "[version not set - please compile using ./build.bash]" @@ -45,11 +53,7 @@ func initDir(args *argContainer) { } // Create gocryptfs.diriv in the root dir - diriv := cryptfs.RandBytes(cryptfs.DIRIV_LEN) - dirivPath := filepath.Join(args.cipherdir, cryptfs.DIRIV_FILENAME) - cryptfs.Debug.Printf("Creating %s\n", dirivPath) - // 0444 permissions: the file is not secret but should not be written to - err = ioutil.WriteFile(dirivPath, diriv, 0444) + err = cryptfs.WriteDirIV(args.cipherdir) if err != nil { fmt.Println(err) os.Exit(ERREXIT_INIT) @@ -76,15 +80,6 @@ func usageText() { flagSet.PrintDefaults() } -type argContainer struct { - debug, init, zerokey, fusedebug, openssl, passwd, foreground, version, - plaintextnames, quiet bool - masterkey, mountpoint, cipherdir, cpuprofile, config, extpass string - notifypid int -} - -var flagSet *flag.FlagSet - // loadConfig - load the config file "filename", prompting the user for the password func loadConfig(args *argContainer) (masterkey []byte, confFile *cryptfs.ConfFile) { // Check if the file exists at all before prompting for a password @@ -133,9 +128,9 @@ func printVersion() { func main() { runtime.GOMAXPROCS(4) var err error + var args argContainer // Parse command line arguments - var args argContainer flagSet = flag.NewFlagSet(PROGRAM_NAME, flag.ExitOnError) flagSet.Usage = usageText flagSet.BoolVar(&args.debug, "debug", false, "Enable debug output") @@ -149,6 +144,7 @@ func main() { flagSet.BoolVar(&args.plaintextnames, "plaintextnames", false, "Do not encrypt "+ "file names") flagSet.BoolVar(&args.quiet, "q", false, "Quiet - silence informational messages") + flagSet.BoolVar(&args.diriv, "diriv", true, "Use per-directory file name IV") flagSet.StringVar(&args.masterkey, "masterkey", "", "Mount with explicit master key") flagSet.StringVar(&args.cpuprofile, "cpuprofile", "", "Write cpu profile to specified file") flagSet.StringVar(&args.config, "config", "", "Use specified config file instead of CIPHERDIR/gocryptfs.conf") @@ -264,7 +260,9 @@ func main() { var confFile *cryptfs.ConfFile masterkey, confFile = loadConfig(&args) printMasterKey(masterkey) + // Settings from the config file override command line args args.plaintextnames = confFile.IsFeatureFlagSet(cryptfs.FlagPlaintextNames) + args.diriv = confFile.IsFeatureFlagSet(cryptfs.FlagDirIV) } // Initialize FUSE server srv := pathfsFrontend(masterkey, args) @@ -285,7 +283,7 @@ func main() { // Calls os.Exit on errors func pathfsFrontend(key []byte, args argContainer) *fuse.Server { - finalFs := pathfs_frontend.NewFS(key, args.cipherdir, args.openssl, args.plaintextnames) + finalFs := pathfs_frontend.NewFS(key, args.cipherdir, args.openssl, args.plaintextnames, args.diriv) pathFsOpts := &pathfs.PathNodeFsOptions{ClientInodes: true} pathFs := pathfs.NewPathNodeFs(finalFs, pathFsOpts) fuseOpts := &nodefs.Options{ @@ -309,7 +307,7 @@ func pathfsFrontend(key []byte, args argContainer) *fuse.Server { fmt.Printf("Mount failed: %v", err) os.Exit(ERREXIT_MOUNT) } - srv.SetDebug(args.debug) + srv.SetDebug(args.fusedebug) return srv } diff --git a/pathfs_frontend/fs.go b/pathfs_frontend/fs.go index 680b08c..c2b80a3 100644 --- a/pathfs_frontend/fs.go +++ b/pathfs_frontend/fs.go @@ -19,6 +19,8 @@ type FS struct { *cryptfs.CryptFS pathfs.FileSystem // loopbackFileSystem, see go-fuse/fuse/pathfs/loopback.go backingDir string // Backing directory, cipherdir + // Are per-directory filename IVs enabled? + dirIV bool // dirIVLock: Lock()ed if any "gocryptfs.diriv" file is modified // Readers must RLock() it to prevent them from seeing intermediate // states @@ -26,10 +28,11 @@ type FS struct { } // Encrypted FUSE overlay filesystem -func NewFS(key []byte, backing string, useOpenssl bool, plaintextNames bool) *FS { +func NewFS(key []byte, backing string, useOpenssl bool, plaintextNames bool, dirIV bool) *FS { return &FS{ CryptFS: cryptfs.NewCryptFS(key, useOpenssl, plaintextNames), FileSystem: pathfs.NewLoopbackFileSystem(backing), + dirIV: dirIV, backingDir: backing, } } @@ -82,8 +85,8 @@ func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, f // silently ignore "gocryptfs.conf" in the top level dir continue } - if cName == cryptfs.DIRIV_FILENAME { - // silently ignore "gocryptfs.diriv" everywhere + if fs.dirIV && cName == cryptfs.DIRIV_FILENAME { + // silently ignore "gocryptfs.diriv" everywhere if dirIV is enabled continue } name, err := fs.decryptPath(cName) @@ -227,7 +230,7 @@ func (fs *FS) Mkdir(relPath string, mode uint32, context *fuse.Context) (code fu return fuse.ToStatus(err) } // Create gocryptfs.diriv inside - err = fs.CryptFS.WriteDirIV(encPath) + err = cryptfs.WriteDirIV(encPath) if err != nil { // This should not happen cryptfs.Warn.Printf("Creating %s in dir %s failed: %v\n", cryptfs.DIRIV_FILENAME, encPath, err) diff --git a/pathfs_frontend/names.go b/pathfs_frontend/names.go index 9c6e010..122b3dd 100644 --- a/pathfs_frontend/names.go +++ b/pathfs_frontend/names.go @@ -1,14 +1,24 @@ package pathfs_frontend -// This file handles filename encryption +// This file forwards file encryption operations to cryptfs + +import ( + "github.com/rfjakob/gocryptfs/cryptfs" +) func (fs *FS) encryptPath(plainPath string) (string, error) { + if !fs.dirIV { + return fs.CryptFS.TranslatePathZeroIV(plainPath, cryptfs.OpEncrypt) + } fs.dirIVLock.RLock() defer fs.dirIVLock.RUnlock() return fs.CryptFS.EncryptPathDirIV(plainPath, fs.backingDir) } func (fs *FS) decryptPath(cipherPath string) (string, error) { + if !fs.dirIV { + return fs.CryptFS.TranslatePathZeroIV(cipherPath, cryptfs.OpDecrypt) + } fs.dirIVLock.RLock() defer fs.dirIVLock.RUnlock() return fs.CryptFS.DecryptPathDirIV(cipherPath, fs.backingDir)