diriv: use "DirIV" flag to discern and support mounting old filesystems

This commit is contained in:
Jakob Unterwurzacher 2015-11-27 23:34:55 +01:00
parent b3d96b6a20
commit fe7355f9ee
7 changed files with 44 additions and 28 deletions

View File

@ -47,8 +47,11 @@ func CreateConfFile(filename string, password string, plaintextNames bool) error
// This sets ScryptObject and EncryptedKey // This sets ScryptObject and EncryptedKey
cf.EncryptKey(key, password) cf.EncryptKey(key, password)
// Set defaults
cf.Version = HEADER_CURRENT_VERSION cf.Version = HEADER_CURRENT_VERSION
cf.FeatureFlags = []string{FlagDirIV}
// Set values chosen by the user
if plaintextNames { if plaintextNames {
cf.FeatureFlags = append(cf.FeatureFlags, FlagPlaintextNames) cf.FeatureFlags = append(cf.FeatureFlags, FlagPlaintextNames)
} }

View File

@ -22,8 +22,9 @@ func (be *CryptFS) readDirIV(dir string) (iv []byte, err error) {
} }
// WriteDirIV - create diriv file inside "dir" (absolute path) // WriteDirIV - create diriv file inside "dir" (absolute path)
// This function is exported because it is used from pathfs_frontend // This function is exported because it is used from pathfs_frontend, main,
func (be *CryptFS) WriteDirIV(dir string) error { // and also the automated tests.
func WriteDirIV(dir string) error {
iv := RandBytes(DIRIV_LEN) iv := RandBytes(DIRIV_LEN)
file := filepath.Join(dir, DIRIV_FILENAME) file := filepath.Join(dir, DIRIV_FILENAME)
// 0444 permissions: the file is not secret but should not be written to // 0444 permissions: the file is not secret but should not be written to

View File

@ -36,7 +36,7 @@ func TestExampleFsNormal(t *testing.T) {
checkStatusTxt(t, pDir+"status.txt") checkStatusTxt(t, pDir+"status.txt")
unmount(pDir) unmount(pDir)
mount(cDir, pDir, "-masterkey", "74676e34-0b47c145-00dac61a-17a92316-"+ mount(cDir, pDir, "-masterkey", "74676e34-0b47c145-00dac61a-17a92316-"+
"bb57044c-e205b71f-65f4fdca-7cabd4b3") "bb57044c-e205b71f-65f4fdca-7cabd4b3", "-diriv=false")
checkStatusTxt(t, pDir+"status.txt") checkStatusTxt(t, pDir+"status.txt")
unmount(pDir) unmount(pDir)
err = os.Remove(pDir) err = os.Remove(pDir)

View File

@ -8,6 +8,8 @@ import (
"os" "os"
"os/exec" "os/exec"
"testing" "testing"
"github.com/rfjakob/gocryptfs/cryptfs"
) )
// Note: the code assumes that all have a trailing slash // Note: the code assumes that all have a trailing slash
@ -38,8 +40,7 @@ func resetTmpDir() {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
} }
dirIV := make([]byte, 16) err = cryptfs.WriteDirIV(defaultCipherDir)
err = ioutil.WriteFile(defaultCipherDir+"gocryptfs.diriv", dirIV, 0444)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)

34
main.go
View File

@ -3,7 +3,6 @@ package main
import ( import (
"flag" "flag"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"os/exec" "os/exec"
"os/signal" "os/signal"
@ -34,6 +33,15 @@ const (
ERREXIT_MOUNTPOINT = 10 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" // GitVersion will be set by the build script "build.bash"
var GitVersion = "[version not set - please compile using ./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 // Create gocryptfs.diriv in the root dir
diriv := cryptfs.RandBytes(cryptfs.DIRIV_LEN) err = cryptfs.WriteDirIV(args.cipherdir)
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)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(ERREXIT_INIT) os.Exit(ERREXIT_INIT)
@ -76,15 +80,6 @@ func usageText() {
flagSet.PrintDefaults() 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 // loadConfig - load the config file "filename", prompting the user for the password
func loadConfig(args *argContainer) (masterkey []byte, confFile *cryptfs.ConfFile) { func loadConfig(args *argContainer) (masterkey []byte, confFile *cryptfs.ConfFile) {
// Check if the file exists at all before prompting for a password // Check if the file exists at all before prompting for a password
@ -133,9 +128,9 @@ func printVersion() {
func main() { func main() {
runtime.GOMAXPROCS(4) runtime.GOMAXPROCS(4)
var err error var err error
var args argContainer
// Parse command line arguments // Parse command line arguments
var args argContainer
flagSet = flag.NewFlagSet(PROGRAM_NAME, flag.ExitOnError) flagSet = flag.NewFlagSet(PROGRAM_NAME, flag.ExitOnError)
flagSet.Usage = usageText flagSet.Usage = usageText
flagSet.BoolVar(&args.debug, "debug", false, "Enable debug output") flagSet.BoolVar(&args.debug, "debug", false, "Enable debug output")
@ -149,6 +144,7 @@ func main() {
flagSet.BoolVar(&args.plaintextnames, "plaintextnames", false, "Do not encrypt "+ flagSet.BoolVar(&args.plaintextnames, "plaintextnames", false, "Do not encrypt "+
"file names") "file names")
flagSet.BoolVar(&args.quiet, "q", false, "Quiet - silence informational messages") 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.masterkey, "masterkey", "", "Mount with explicit master key")
flagSet.StringVar(&args.cpuprofile, "cpuprofile", "", "Write cpu profile to specified file") 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") flagSet.StringVar(&args.config, "config", "", "Use specified config file instead of CIPHERDIR/gocryptfs.conf")
@ -264,7 +260,9 @@ func main() {
var confFile *cryptfs.ConfFile var confFile *cryptfs.ConfFile
masterkey, confFile = loadConfig(&args) masterkey, confFile = loadConfig(&args)
printMasterKey(masterkey) printMasterKey(masterkey)
// Settings from the config file override command line args
args.plaintextnames = confFile.IsFeatureFlagSet(cryptfs.FlagPlaintextNames) args.plaintextnames = confFile.IsFeatureFlagSet(cryptfs.FlagPlaintextNames)
args.diriv = confFile.IsFeatureFlagSet(cryptfs.FlagDirIV)
} }
// Initialize FUSE server // Initialize FUSE server
srv := pathfsFrontend(masterkey, args) srv := pathfsFrontend(masterkey, args)
@ -285,7 +283,7 @@ func main() {
// Calls os.Exit on errors // Calls os.Exit on errors
func pathfsFrontend(key []byte, args argContainer) *fuse.Server { 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} pathFsOpts := &pathfs.PathNodeFsOptions{ClientInodes: true}
pathFs := pathfs.NewPathNodeFs(finalFs, pathFsOpts) pathFs := pathfs.NewPathNodeFs(finalFs, pathFsOpts)
fuseOpts := &nodefs.Options{ fuseOpts := &nodefs.Options{
@ -309,7 +307,7 @@ func pathfsFrontend(key []byte, args argContainer) *fuse.Server {
fmt.Printf("Mount failed: %v", err) fmt.Printf("Mount failed: %v", err)
os.Exit(ERREXIT_MOUNT) os.Exit(ERREXIT_MOUNT)
} }
srv.SetDebug(args.debug) srv.SetDebug(args.fusedebug)
return srv return srv
} }

View File

@ -19,6 +19,8 @@ type FS struct {
*cryptfs.CryptFS *cryptfs.CryptFS
pathfs.FileSystem // loopbackFileSystem, see go-fuse/fuse/pathfs/loopback.go pathfs.FileSystem // loopbackFileSystem, see go-fuse/fuse/pathfs/loopback.go
backingDir string // Backing directory, cipherdir backingDir string // Backing directory, cipherdir
// Are per-directory filename IVs enabled?
dirIV bool
// dirIVLock: Lock()ed if any "gocryptfs.diriv" file is modified // dirIVLock: Lock()ed if any "gocryptfs.diriv" file is modified
// Readers must RLock() it to prevent them from seeing intermediate // Readers must RLock() it to prevent them from seeing intermediate
// states // states
@ -26,10 +28,11 @@ type FS struct {
} }
// Encrypted FUSE overlay filesystem // 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{ return &FS{
CryptFS: cryptfs.NewCryptFS(key, useOpenssl, plaintextNames), CryptFS: cryptfs.NewCryptFS(key, useOpenssl, plaintextNames),
FileSystem: pathfs.NewLoopbackFileSystem(backing), FileSystem: pathfs.NewLoopbackFileSystem(backing),
dirIV: dirIV,
backingDir: backing, 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 // silently ignore "gocryptfs.conf" in the top level dir
continue continue
} }
if cName == cryptfs.DIRIV_FILENAME { if fs.dirIV && cName == cryptfs.DIRIV_FILENAME {
// silently ignore "gocryptfs.diriv" everywhere // silently ignore "gocryptfs.diriv" everywhere if dirIV is enabled
continue continue
} }
name, err := fs.decryptPath(cName) 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) return fuse.ToStatus(err)
} }
// Create gocryptfs.diriv inside // Create gocryptfs.diriv inside
err = fs.CryptFS.WriteDirIV(encPath) err = cryptfs.WriteDirIV(encPath)
if err != nil { if err != nil {
// This should not happen // This should not happen
cryptfs.Warn.Printf("Creating %s in dir %s failed: %v\n", cryptfs.DIRIV_FILENAME, encPath, err) cryptfs.Warn.Printf("Creating %s in dir %s failed: %v\n", cryptfs.DIRIV_FILENAME, encPath, err)

View File

@ -1,14 +1,24 @@
package pathfs_frontend 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) { func (fs *FS) encryptPath(plainPath string) (string, error) {
if !fs.dirIV {
return fs.CryptFS.TranslatePathZeroIV(plainPath, cryptfs.OpEncrypt)
}
fs.dirIVLock.RLock() fs.dirIVLock.RLock()
defer fs.dirIVLock.RUnlock() defer fs.dirIVLock.RUnlock()
return fs.CryptFS.EncryptPathDirIV(plainPath, fs.backingDir) return fs.CryptFS.EncryptPathDirIV(plainPath, fs.backingDir)
} }
func (fs *FS) decryptPath(cipherPath string) (string, error) { func (fs *FS) decryptPath(cipherPath string) (string, error) {
if !fs.dirIV {
return fs.CryptFS.TranslatePathZeroIV(cipherPath, cryptfs.OpDecrypt)
}
fs.dirIVLock.RLock() fs.dirIVLock.RLock()
defer fs.dirIVLock.RUnlock() defer fs.dirIVLock.RUnlock()
return fs.CryptFS.DecryptPathDirIV(cipherPath, fs.backingDir) return fs.CryptFS.DecryptPathDirIV(cipherPath, fs.backingDir)