diff options
author | Jakob Unterwurzacher | 2016-02-06 19:20:54 +0100 |
---|---|---|
committer | Jakob Unterwurzacher | 2016-02-06 19:22:35 +0100 |
commit | 2b8cbd944149afe51fadddbd67ee4499d1d86250 (patch) | |
tree | 76361984cc4394bbb9b19ae987aeaff71fb6073b /pathfs_frontend | |
parent | adcfbd79a8b8bb85cbee25996ab622a05de0dbc1 (diff) |
Major refactoring: Split up "cryptfs" into several internal packages
"git status" for reference:
deleted: cryptfs/cryptfs.go
deleted: cryptfs/names_core.go
modified: integration_tests/cli_test.go
modified: integration_tests/helpers.go
renamed: cryptfs/config_file.go -> internal/configfile/config_file.go
renamed: cryptfs/config_test.go -> internal/configfile/config_test.go
renamed: cryptfs/config_test/.gitignore -> internal/configfile/config_test/.gitignore
renamed: cryptfs/config_test/PlaintextNames.conf -> internal/configfile/config_test/PlaintextNames.conf
renamed: cryptfs/config_test/StrangeFeature.conf -> internal/configfile/config_test/StrangeFeature.conf
renamed: cryptfs/config_test/v1.conf -> internal/configfile/config_test/v1.conf
renamed: cryptfs/config_test/v2.conf -> internal/configfile/config_test/v2.conf
renamed: cryptfs/kdf.go -> internal/configfile/kdf.go
renamed: cryptfs/kdf_test.go -> internal/configfile/kdf_test.go
renamed: cryptfs/cryptfs_content.go -> internal/contentenc/content.go
new file: internal/contentenc/content_api.go
renamed: cryptfs/content_test.go -> internal/contentenc/content_test.go
renamed: cryptfs/file_header.go -> internal/contentenc/file_header.go
renamed: cryptfs/intrablock.go -> internal/contentenc/intrablock.go
renamed: cryptfs/address_translation.go -> internal/contentenc/offsets.go
new file: internal/cryptocore/crypto_api.go
renamed: cryptfs/gcm_go1.4.go -> internal/cryptocore/gcm_go1.4.go
renamed: cryptfs/gcm_go1.5.go -> internal/cryptocore/gcm_go1.5.go
renamed: cryptfs/nonce.go -> internal/cryptocore/nonce.go
renamed: cryptfs/openssl_aead.go -> internal/cryptocore/openssl_aead.go
renamed: cryptfs/openssl_benchmark.bash -> internal/cryptocore/openssl_benchmark.bash
renamed: cryptfs/openssl_test.go -> internal/cryptocore/openssl_test.go
new file: internal/nametransform/name_api.go
new file: internal/nametransform/names_core.go
renamed: cryptfs/names_diriv.go -> internal/nametransform/names_diriv.go
renamed: cryptfs/names_noiv.go -> internal/nametransform/names_noiv.go
renamed: cryptfs/names_test.go -> internal/nametransform/names_test.go
new file: internal/nametransform/pad16.go
renamed: cryptfs/log.go -> internal/toggledlog/log.go
renamed: cryptfs/log_go1.4.go -> internal/toggledlog/log_go1.4.go
renamed: cryptfs/log_go1.5.go -> internal/toggledlog/log_go1.5.go
modified: main.go
modified: masterkey.go
modified: pathfs_frontend/file.go
modified: pathfs_frontend/file_holes.go
modified: pathfs_frontend/fs.go
modified: pathfs_frontend/fs_dir.go
modified: pathfs_frontend/names.go
modified: test.bash
Diffstat (limited to 'pathfs_frontend')
-rw-r--r-- | pathfs_frontend/file.go | 112 | ||||
-rw-r--r-- | pathfs_frontend/file_holes.go | 13 | ||||
-rw-r--r-- | pathfs_frontend/fs.go | 76 | ||||
-rw-r--r-- | pathfs_frontend/fs_dir.go | 44 | ||||
-rw-r--r-- | pathfs_frontend/names.go | 17 |
5 files changed, 143 insertions, 119 deletions
diff --git a/pathfs_frontend/file.go b/pathfs_frontend/file.go index 33ad0c7..387eb35 100644 --- a/pathfs_frontend/file.go +++ b/pathfs_frontend/file.go @@ -13,7 +13,9 @@ import ( "github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse/nodefs" - "github.com/rfjakob/gocryptfs/cryptfs" + + "github.com/rfjakob/gocryptfs/internal/contentenc" + "github.com/rfjakob/gocryptfs/internal/toggledlog" ) // File - based on loopbackFile in go-fuse/fuse/nodefs/files.go @@ -29,19 +31,19 @@ type file struct { // Was the file opened O_WRONLY? writeOnly bool - // Parent CryptFS - cfs *cryptfs.CryptFS + // Content encryption helper + contentEnc *contentenc.ContentEnc // Inode number ino uint64 // File header - header *cryptfs.FileHeader + header *contentenc.FileHeader forgotten bool } -func NewFile(fd *os.File, writeOnly bool, cfs *cryptfs.CryptFS) nodefs.File { +func NewFile(fd *os.File, writeOnly bool, contentEnc *contentenc.ContentEnc) nodefs.File { var st syscall.Stat_t syscall.Fstat(int(fd.Fd()), &st) wlock.register(st.Ino) @@ -49,7 +51,7 @@ func NewFile(fd *os.File, writeOnly bool, cfs *cryptfs.CryptFS) nodefs.File { return &file{ fd: fd, writeOnly: writeOnly, - cfs: cfs, + contentEnc: contentEnc, ino: st.Ino, } } @@ -71,12 +73,12 @@ func (f *file) SetInode(n *nodefs.Inode) { // // Returns io.EOF if the file is empty func (f *file) readHeader() error { - buf := make([]byte, cryptfs.HEADER_LEN) + buf := make([]byte, contentenc.HEADER_LEN) _, err := f.fd.ReadAt(buf, 0) if err != nil { return err } - h, err := cryptfs.ParseHeader(buf) + h, err := contentenc.ParseHeader(buf) if err != nil { return err } @@ -87,13 +89,13 @@ func (f *file) readHeader() error { // createHeader - create a new random header and write it to disk func (f *file) createHeader() error { - h := cryptfs.RandomHeader() + h := contentenc.RandomHeader() buf := h.Pack() // Prevent partially written (=corrupt) header by preallocating the space beforehand - err := prealloc(int(f.fd.Fd()), 0, cryptfs.HEADER_LEN) + err := prealloc(int(f.fd.Fd()), 0, contentenc.HEADER_LEN) if err != nil { - cryptfs.Warn.Printf("ino%d: createHeader: prealloc failed: %s\n", f.ino, err.Error()) + toggledlog.Warn.Printf("ino%d: createHeader: prealloc failed: %s\n", f.ino, err.Error()) return err } @@ -133,29 +135,29 @@ func (f *file) doRead(off uint64, length uint64) ([]byte, fuse.Status) { } // Read the backing ciphertext in one go - blocks := f.cfs.ExplodePlainRange(off, length) + blocks := f.contentEnc.ExplodePlainRange(off, length) alignedOffset, alignedLength := blocks[0].JointCiphertextRange(blocks) skip := blocks[0].Skip - cryptfs.Debug.Printf("JointCiphertextRange(%d, %d) -> %d, %d, %d", off, length, alignedOffset, alignedLength, skip) + toggledlog.Debug.Printf("JointCiphertextRange(%d, %d) -> %d, %d, %d", off, length, alignedOffset, alignedLength, skip) ciphertext := make([]byte, int(alignedLength)) n, err := f.fd.ReadAt(ciphertext, int64(alignedOffset)) if err != nil && err != io.EOF { - cryptfs.Warn.Printf("read: ReadAt: %s", err.Error()) + toggledlog.Warn.Printf("read: ReadAt: %s", err.Error()) return nil, fuse.ToStatus(err) } // Truncate ciphertext buffer down to actually read bytes ciphertext = ciphertext[0:n] firstBlockNo := blocks[0].BlockNo - cryptfs.Debug.Printf("ReadAt offset=%d bytes (%d blocks), want=%d, got=%d", alignedOffset, firstBlockNo, alignedLength, n) + toggledlog.Debug.Printf("ReadAt offset=%d bytes (%d blocks), want=%d, got=%d", alignedOffset, firstBlockNo, alignedLength, n) // Decrypt it - plaintext, err := f.cfs.DecryptBlocks(ciphertext, firstBlockNo, f.header.Id) + plaintext, err := f.contentEnc.DecryptBlocks(ciphertext, firstBlockNo, f.header.Id) if err != nil { - curruptBlockNo := firstBlockNo + f.cfs.PlainOffToBlockNo(uint64(len(plaintext))) - cipherOff := f.cfs.BlockNoToCipherOff(curruptBlockNo) - plainOff := f.cfs.BlockNoToPlainOff(curruptBlockNo) - cryptfs.Warn.Printf("ino%d: doRead: corrupt block #%d (plainOff=%d, cipherOff=%d)", + curruptBlockNo := firstBlockNo + f.contentEnc.PlainOffToBlockNo(uint64(len(plaintext))) + cipherOff := f.contentEnc.BlockNoToCipherOff(curruptBlockNo) + plainOff := f.contentEnc.BlockNoToPlainOff(curruptBlockNo) + toggledlog.Warn.Printf("ino%d: doRead: corrupt block #%d (plainOff=%d, cipherOff=%d)", f.ino, curruptBlockNo, plainOff, cipherOff) return nil, fuse.EIO } @@ -179,23 +181,23 @@ func (f *file) Read(buf []byte, off int64) (resultData fuse.ReadResult, code fus f.fdLock.RLock() defer f.fdLock.RUnlock() - cryptfs.Debug.Printf("ino%d: FUSE Read: offset=%d length=%d", f.ino, len(buf), off) + toggledlog.Debug.Printf("ino%d: FUSE Read: offset=%d length=%d", f.ino, len(buf), off) if f.writeOnly { - cryptfs.Warn.Printf("ino%d: Tried to read from write-only file", f.ino) + toggledlog.Warn.Printf("ino%d: Tried to read from write-only file", f.ino) return nil, fuse.EBADF } out, status := f.doRead(uint64(off), uint64(len(buf))) if status == fuse.EIO { - cryptfs.Warn.Printf("ino%d: Read failed with EIO, offset=%d, length=%d", f.ino, len(buf), off) + toggledlog.Warn.Printf("ino%d: Read failed with EIO, offset=%d, length=%d", f.ino, len(buf), off) } if status != fuse.OK { return nil, status } - cryptfs.Debug.Printf("ino%d: Read: status %v, returning %d bytes", f.ino, status, len(out)) + toggledlog.Debug.Printf("ino%d: Read: status %v, returning %d bytes", f.ino, status, len(out)) return fuse.ReadResultData(out), status } @@ -225,7 +227,7 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) { var written uint32 status := fuse.OK dataBuf := bytes.NewBuffer(data) - blocks := f.cfs.ExplodePlainRange(uint64(off), uint64(len(data))) + blocks := f.contentEnc.ExplodePlainRange(uint64(off), uint64(len(data))) for _, b := range blocks { blockData := dataBuf.Next(int(b.Length)) @@ -234,26 +236,26 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) { if b.IsPartial() { // Read o, _ := b.PlaintextRange() - oldData, status := f.doRead(o, f.cfs.PlainBS()) + oldData, status := f.doRead(o, f.contentEnc.PlainBS()) if status != fuse.OK { - cryptfs.Warn.Printf("ino%d fh%d: RMW read failed: %s", f.ino, f.intFd(), status.String()) + toggledlog.Warn.Printf("ino%d fh%d: RMW read failed: %s", f.ino, f.intFd(), status.String()) return written, status } // Modify - blockData = f.cfs.MergeBlocks(oldData, blockData, int(b.Skip)) - cryptfs.Debug.Printf("len(oldData)=%d len(blockData)=%d", len(oldData), len(blockData)) + blockData = f.contentEnc.MergeBlocks(oldData, blockData, int(b.Skip)) + toggledlog.Debug.Printf("len(oldData)=%d len(blockData)=%d", len(oldData), len(blockData)) } // Encrypt blockOffset, blockLen := b.CiphertextRange() - blockData = f.cfs.EncryptBlock(blockData, b.BlockNo, f.header.Id) - cryptfs.Debug.Printf("ino%d: Writing %d bytes to block #%d", - f.ino, uint64(len(blockData))-f.cfs.BlockOverhead(), b.BlockNo) + blockData = f.contentEnc.EncryptBlock(blockData, b.BlockNo, f.header.Id) + toggledlog.Debug.Printf("ino%d: Writing %d bytes to block #%d", + f.ino, uint64(len(blockData))-f.contentEnc.BlockOverhead(), b.BlockNo) // Prevent partially written (=corrupt) blocks by preallocating the space beforehand err := prealloc(int(f.fd.Fd()), int64(blockOffset), int64(blockLen)) if err != nil { - cryptfs.Warn.Printf("ino%d fh%d: doWrite: prealloc failed: %s", f.ino, f.intFd(), err.Error()) + toggledlog.Warn.Printf("ino%d fh%d: doWrite: prealloc failed: %s", f.ino, f.intFd(), err.Error()) status = fuse.ToStatus(err) break } @@ -262,7 +264,7 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) { _, err = f.fd.WriteAt(blockData, int64(blockOffset)) if err != nil { - cryptfs.Warn.Printf("doWrite: Write failed: %s", err.Error()) + toggledlog.Warn.Printf("doWrite: Write failed: %s", err.Error()) status = fuse.ToStatus(err) break } @@ -278,18 +280,18 @@ func (f *file) Write(data []byte, off int64) (uint32, fuse.Status) { wlock.lock(f.ino) defer wlock.unlock(f.ino) - cryptfs.Debug.Printf("ino%d: FUSE Write: offset=%d length=%d", f.ino, off, len(data)) + toggledlog.Debug.Printf("ino%d: FUSE Write: offset=%d length=%d", f.ino, off, len(data)) fi, err := f.fd.Stat() if err != nil { - cryptfs.Warn.Printf("Write: Fstat failed: %v", err) + toggledlog.Warn.Printf("Write: Fstat failed: %v", err) return 0, fuse.ToStatus(err) } - plainSize := f.cfs.CipherSizeToPlainSize(uint64(fi.Size())) + plainSize := f.contentEnc.CipherSizeToPlainSize(uint64(fi.Size())) if f.createsHole(plainSize, off) { status := f.zeroPad(plainSize) if status != fuse.OK { - cryptfs.Warn.Printf("zeroPad returned error %v", status) + toggledlog.Warn.Printf("zeroPad returned error %v", status) return 0, status } } @@ -337,14 +339,14 @@ func (f *file) Truncate(newSize uint64) fuse.Status { defer wlock.unlock(f.ino) if f.forgotten { - cryptfs.Warn.Printf("ino%d fh%d: Truncate on forgotten file", f.ino, f.intFd()) + toggledlog.Warn.Printf("ino%d fh%d: Truncate on forgotten file", f.ino, f.intFd()) } // Common case first: Truncate to zero if newSize == 0 { err := syscall.Ftruncate(int(f.fd.Fd()), 0) if err != nil { - cryptfs.Warn.Printf("ino%d fh%d: Ftruncate(fd, 0) returned error: %v", f.ino, f.intFd(), err) + toggledlog.Warn.Printf("ino%d fh%d: Ftruncate(fd, 0) returned error: %v", f.ino, f.intFd(), err) return fuse.ToStatus(err) } // Truncate to zero kills the file header @@ -356,14 +358,14 @@ func (f *file) Truncate(newSize uint64) fuse.Status { // the file fi, err := f.fd.Stat() if err != nil { - cryptfs.Warn.Printf("ino%d fh%d: Truncate: Fstat failed: %v", f.ino, f.intFd(), err) + toggledlog.Warn.Printf("ino%d fh%d: Truncate: Fstat failed: %v", f.ino, f.intFd(), err) return fuse.ToStatus(err) } - oldSize := f.cfs.CipherSizeToPlainSize(uint64(fi.Size())) + oldSize := f.contentEnc.CipherSizeToPlainSize(uint64(fi.Size())) { - oldB := float32(oldSize) / float32(f.cfs.PlainBS()) - newB := float32(newSize) / float32(f.cfs.PlainBS()) - cryptfs.Debug.Printf("ino%d: FUSE Truncate from %.2f to %.2f blocks (%d to %d bytes)", f.ino, oldB, newB, oldSize, newSize) + oldB := float32(oldSize) / float32(f.contentEnc.PlainBS()) + newB := float32(newSize) / float32(f.contentEnc.PlainBS()) + toggledlog.Debug.Printf("ino%d: FUSE Truncate from %.2f to %.2f blocks (%d to %d bytes)", f.ino, oldB, newB, oldSize, newSize) } // File size stays the same - nothing to do @@ -382,7 +384,7 @@ func (f *file) Truncate(newSize uint64) fuse.Status { } } - blocks := f.cfs.ExplodePlainRange(oldSize, newSize-oldSize) + blocks := f.contentEnc.ExplodePlainRange(oldSize, newSize-oldSize) for _, b := range blocks { // First and last block may be partial if b.IsPartial() { @@ -396,7 +398,7 @@ func (f *file) Truncate(newSize uint64) fuse.Status { off, length := b.CiphertextRange() err := syscall.Ftruncate(int(f.fd.Fd()), int64(off+length)) if err != nil { - cryptfs.Warn.Printf("grow Ftruncate returned error: %v", err) + toggledlog.Warn.Printf("grow Ftruncate returned error: %v", err) return fuse.ToStatus(err) } } @@ -404,23 +406,23 @@ func (f *file) Truncate(newSize uint64) fuse.Status { return fuse.OK } else { // File shrinks - blockNo := f.cfs.PlainOffToBlockNo(newSize) - cipherOff := f.cfs.BlockNoToCipherOff(blockNo) - plainOff := f.cfs.BlockNoToPlainOff(blockNo) + blockNo := f.contentEnc.PlainOffToBlockNo(newSize) + cipherOff := f.contentEnc.BlockNoToCipherOff(blockNo) + plainOff := f.contentEnc.BlockNoToPlainOff(blockNo) lastBlockLen := newSize - plainOff var data []byte if lastBlockLen > 0 { var status fuse.Status data, status = f.doRead(plainOff, lastBlockLen) if status != fuse.OK { - cryptfs.Warn.Printf("shrink doRead returned error: %v", err) + toggledlog.Warn.Printf("shrink doRead returned error: %v", err) return status } } // Truncate down to last complete block err = syscall.Ftruncate(int(f.fd.Fd()), int64(cipherOff)) if err != nil { - cryptfs.Warn.Printf("shrink Ftruncate returned error: %v", err) + toggledlog.Warn.Printf("shrink Ftruncate returned error: %v", err) return fuse.ToStatus(err) } // Append partial block @@ -450,14 +452,14 @@ func (f *file) GetAttr(a *fuse.Attr) fuse.Status { f.fdLock.RLock() defer f.fdLock.RUnlock() - cryptfs.Debug.Printf("file.GetAttr()") + toggledlog.Debug.Printf("file.GetAttr()") st := syscall.Stat_t{} err := syscall.Fstat(int(f.fd.Fd()), &st) if err != nil { return fuse.ToStatus(err) } a.FromStat(&st) - a.Size = f.cfs.CipherSizeToPlainSize(a.Size) + a.Size = f.contentEnc.CipherSizeToPlainSize(a.Size) return fuse.OK } @@ -468,7 +470,7 @@ var allocateWarned bool func (f *file) Allocate(off uint64, sz uint64, mode uint32) fuse.Status { // Only warn once if !allocateWarned { - cryptfs.Warn.Printf("fallocate(2) is not supported, returning ENOSYS - see https://github.com/rfjakob/gocryptfs/issues/1") + toggledlog.Warn.Printf("fallocate(2) is not supported, returning ENOSYS - see https://github.com/rfjakob/gocryptfs/issues/1") allocateWarned = true } return fuse.ENOSYS diff --git a/pathfs_frontend/file_holes.go b/pathfs_frontend/file_holes.go index fd2e2c1..a147deb 100644 --- a/pathfs_frontend/file_holes.go +++ b/pathfs_frontend/file_holes.go @@ -4,13 +4,14 @@ package pathfs_frontend import ( "github.com/hanwen/go-fuse/fuse" - "github.com/rfjakob/gocryptfs/cryptfs" + + "github.com/rfjakob/gocryptfs/internal/toggledlog" ) // Will a write to offset "off" create a file hole? func (f *file) createsHole(plainSize uint64, off int64) bool { - nextBlock := f.cfs.PlainOffToBlockNo(plainSize) - targetBlock := f.cfs.PlainOffToBlockNo(uint64(off)) + nextBlock := f.contentEnc.PlainOffToBlockNo(plainSize) + targetBlock := f.contentEnc.PlainOffToBlockNo(uint64(off)) if targetBlock > nextBlock { return true } @@ -19,10 +20,10 @@ func (f *file) createsHole(plainSize uint64, off int64) bool { // Zero-pad the file of size plainSize to the next block boundary func (f *file) zeroPad(plainSize uint64) fuse.Status { - lastBlockLen := plainSize % f.cfs.PlainBS() - missing := f.cfs.PlainBS() - lastBlockLen + lastBlockLen := plainSize % f.contentEnc.PlainBS() + missing := f.contentEnc.PlainBS() - lastBlockLen pad := make([]byte, missing) - cryptfs.Debug.Printf("zeroPad: Writing %d bytes\n", missing) + toggledlog.Debug.Printf("zeroPad: Writing %d bytes\n", missing) _, status := f.doWrite(pad, int64(plainSize)) return status } diff --git a/pathfs_frontend/fs.go b/pathfs_frontend/fs.go index a00985d..212f0a7 100644 --- a/pathfs_frontend/fs.go +++ b/pathfs_frontend/fs.go @@ -13,25 +13,41 @@ import ( "github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse/nodefs" "github.com/hanwen/go-fuse/fuse/pathfs" - "github.com/rfjakob/gocryptfs/cryptfs" + + "github.com/rfjakob/gocryptfs/internal/toggledlog" + "github.com/rfjakob/gocryptfs/internal/cryptocore" + "github.com/rfjakob/gocryptfs/internal/nametransform" + "github.com/rfjakob/gocryptfs/internal/contentenc" + "github.com/rfjakob/gocryptfs/internal/configfile" ) +const plainBS = 4096 + type FS struct { - *cryptfs.CryptFS pathfs.FileSystem // loopbackFileSystem, see go-fuse/fuse/pathfs/loopback.go args Args // Stores configuration arguments // dirIVLock: Lock()ed if any "gocryptfs.diriv" file is modified // Readers must RLock() it to prevent them from seeing intermediate // states dirIVLock sync.RWMutex + // Filename encryption helper + nameTransform *nametransform.NameTransform + // Content encryption helper + contentEnc *contentenc.ContentEnc } // Encrypted FUSE overlay filesystem func NewFS(args Args) *FS { + + cryptoCore := cryptocore.New(args.Masterkey, args.OpenSSL, args.GCMIV128) + contentEnc := contentenc.New(cryptoCore, plainBS) + nameTransform := nametransform.New(cryptoCore, args.EMENames) + return &FS{ - CryptFS: cryptfs.NewCryptFS(args.Masterkey, args.OpenSSL, args.PlaintextNames, args.GCMIV128), FileSystem: pathfs.NewLoopbackFileSystem(args.Cipherdir), args: args, + nameTransform: nameTransform, + contentEnc: contentEnc, } } @@ -43,12 +59,12 @@ func (fs *FS) getBackingPath(relPath string) (string, error) { return "", err } cAbsPath := filepath.Join(fs.args.Cipherdir, cPath) - cryptfs.Debug.Printf("getBackingPath: %s + %s -> %s", fs.args.Cipherdir, relPath, cAbsPath) + toggledlog.Debug.Printf("getBackingPath: %s + %s -> %s", fs.args.Cipherdir, relPath, cAbsPath) return cAbsPath, nil } func (fs *FS) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) { - cryptfs.Debug.Printf("FS.GetAttr('%s')", name) + toggledlog.Debug.Printf("FS.GetAttr('%s')", name) if fs.isFiltered(name) { return nil, fuse.EPERM } @@ -58,11 +74,11 @@ func (fs *FS) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Stat } a, status := fs.FileSystem.GetAttr(cName, context) if a == nil { - cryptfs.Debug.Printf("FS.GetAttr failed: %s", status.String()) + toggledlog.Debug.Printf("FS.GetAttr failed: %s", status.String()) return a, status } if a.IsRegular() { - a.Size = fs.CipherSizeToPlainSize(a.Size) + a.Size = fs.contentEnc.CipherSizeToPlainSize(a.Size) } else if a.IsSymlink() { target, _ := fs.Readlink(name, context) a.Size = uint64(len(target)) @@ -71,7 +87,7 @@ func (fs *FS) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Stat } func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) { - cryptfs.Debug.Printf("OpenDir(%s)", dirName) + toggledlog.Debug.Printf("OpenDir(%s)", dirName) cDirName, err := fs.encryptPath(dirName) if err != nil { return nil, fuse.ToStatus(err) @@ -81,12 +97,12 @@ func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, f if cipherEntries == nil { return nil, status } - // Get DirIV (stays zero if DirIV if off) - cachedIV := make([]byte, cryptfs.DIRIV_LEN) + // Get DirIV (stays nil if DirIV if off) + var cachedIV []byte if fs.args.DirIV { // Read the DirIV once and use it for all later name decryptions cDirAbsPath := filepath.Join(fs.args.Cipherdir, cDirName) - cachedIV, err = fs.CryptFS.ReadDirIV(cDirAbsPath) + cachedIV, err = fs.nameTransform.ReadDirIV(cDirAbsPath) if err != nil { return nil, fuse.ToStatus(err) } @@ -95,19 +111,19 @@ func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, f var plain []fuse.DirEntry for i := range cipherEntries { cName := cipherEntries[i].Name - if dirName == "" && cName == cryptfs.ConfDefaultName { + if dirName == "" && cName == configfile.ConfDefaultName { // silently ignore "gocryptfs.conf" in the top level dir continue } - if fs.args.DirIV && cName == cryptfs.DIRIV_FILENAME { + if fs.args.DirIV && cName == nametransform.DirIVFilename { // silently ignore "gocryptfs.diriv" everywhere if dirIV is enabled continue } var name string = cName if !fs.args.PlaintextNames { - name, err = fs.CryptFS.DecryptName(cName, cachedIV, fs.args.EMENames) + name, err = fs.nameTransform.DecryptName(cName, cachedIV) if err != nil { - cryptfs.Warn.Printf("Invalid name \"%s\" in dir \"%s\": %s", cName, cDirName, err) + toggledlog.Warn.Printf("Invalid name \"%s\" in dir \"%s\": %s", cName, cDirName, err) continue } } @@ -137,16 +153,16 @@ func (fs *FS) Open(path string, flags uint32, context *fuse.Context) (fuseFile n iflags, writeOnly := fs.mangleOpenFlags(flags) cPath, err := fs.getBackingPath(path) if err != nil { - cryptfs.Debug.Printf("Open: getBackingPath: %v", err) + toggledlog.Debug.Printf("Open: getBackingPath: %v", err) return nil, fuse.ToStatus(err) } - cryptfs.Debug.Printf("Open: %s", cPath) + toggledlog.Debug.Printf("Open: %s", cPath) f, err := os.OpenFile(cPath, iflags, 0666) if err != nil { return nil, fuse.ToStatus(err) } - return NewFile(f, writeOnly, fs.CryptFS), fuse.OK + return NewFile(f, writeOnly, fs.contentEnc), fuse.OK } func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Context) (fuseFile nodefs.File, code fuse.Status) { @@ -162,7 +178,7 @@ func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Conte if err != nil { return nil, fuse.ToStatus(err) } - return NewFile(f, writeOnly, fs.CryptFS), fuse.OK + return NewFile(f, writeOnly, fs.contentEnc), fuse.OK } func (fs *FS) Chmod(path string, mode uint32, context *fuse.Context) (code fuse.Status) { @@ -203,7 +219,7 @@ var truncateWarned bool func (fs *FS) Truncate(path string, offset uint64, context *fuse.Context) (code fuse.Status) { // Only warn once if !truncateWarned { - cryptfs.Warn.Printf("truncate(2) is not supported, returning ENOSYS - use ftruncate(2)") + toggledlog.Warn.Printf("truncate(2) is not supported, returning ENOSYS - use ftruncate(2)") truncateWarned = true } return fuse.ENOSYS @@ -233,7 +249,7 @@ func (fs *FS) Readlink(path string, context *fuse.Context) (out string, status f if !fs.args.DirIV { target, err := fs.decryptPath(cTarget) if err != nil { - cryptfs.Warn.Printf("Readlink: CBC decryption failed: %v", err) + toggledlog.Warn.Printf("Readlink: CBC decryption failed: %v", err) return "", fuse.EIO } return target, fuse.OK @@ -241,12 +257,12 @@ func (fs *FS) Readlink(path string, context *fuse.Context) (out string, status f // Since gocryptfs v0.5 symlinks are encrypted like file contents (GCM) cBinTarget, err := base64.URLEncoding.DecodeString(cTarget) if err != nil { - cryptfs.Warn.Printf("Readlink: %v", err) + toggledlog.Warn.Printf("Readlink: %v", err) return "", fuse.EIO } - target, err := fs.CryptFS.DecryptBlock([]byte(cBinTarget), 0, nil) + target, err := fs.contentEnc.DecryptBlock([]byte(cBinTarget), 0, nil) if err != nil { - cryptfs.Warn.Printf("Readlink: %v", err) + toggledlog.Warn.Printf("Readlink: %v", err) return "", fuse.EIO } return string(target), fuse.OK @@ -264,7 +280,7 @@ func (fs *FS) Unlink(path string, context *fuse.Context) (code fuse.Status) { } func (fs *FS) Symlink(target string, linkName string, context *fuse.Context) (code fuse.Status) { - cryptfs.Debug.Printf("Symlink(\"%s\", \"%s\")", target, linkName) + toggledlog.Debug.Printf("Symlink(\"%s\", \"%s\")", target, linkName) if fs.isFiltered(linkName) { return fuse.EPERM } @@ -276,18 +292,18 @@ func (fs *FS) Symlink(target string, linkName string, context *fuse.Context) (co if !fs.args.DirIV { cTarget, err := fs.encryptPath(target) if err != nil { - cryptfs.Warn.Printf("Symlink: BUG: we should not get an error here: %v", err) + toggledlog.Warn.Printf("Symlink: BUG: we should not get an error here: %v", err) return fuse.ToStatus(err) } err = os.Symlink(cTarget, cPath) return fuse.ToStatus(err) } // Since gocryptfs v0.5 symlinks are encrypted like file contents (GCM) - cBinTarget := fs.CryptFS.EncryptBlock([]byte(target), 0, nil) + cBinTarget := fs.contentEnc.EncryptBlock([]byte(target), 0, nil) cTarget := base64.URLEncoding.EncodeToString(cBinTarget) err = os.Symlink(cTarget, cPath) - cryptfs.Debug.Printf("Symlink: os.Symlink(%s, %s) = %v", cTarget, cPath, err) + toggledlog.Debug.Printf("Symlink: os.Symlink(%s, %s) = %v", cTarget, cPath, err) return fuse.ToStatus(err) } @@ -305,7 +321,7 @@ func (fs *FS) Rename(oldPath string, newPath string, context *fuse.Context) (cod } // The Rename may cause a directory to take the place of another directory. // That directory may still be in the DirIV cache, clear it. - fs.CryptFS.DirIVCache.Clear() + fs.nameTransform.DirIVCache.Clear() err = os.Rename(cOldPath, cNewPath) @@ -313,7 +329,7 @@ func (fs *FS) Rename(oldPath string, newPath string, context *fuse.Context) (cod // If an empty directory is overwritten we will always get // ENOTEMPTY as the "empty" directory will still contain gocryptfs.diriv. // Handle that case by removing the target directory and trying again. - cryptfs.Debug.Printf("Rename: Handling ENOTEMPTY") + toggledlog.Debug.Printf("Rename: Handling ENOTEMPTY") if fs.Rmdir(newPath, context) == fuse.OK { err = os.Rename(cOldPath, cNewPath) } diff --git a/pathfs_frontend/fs_dir.go b/pathfs_frontend/fs_dir.go index b1edd73..d378d28 100644 --- a/pathfs_frontend/fs_dir.go +++ b/pathfs_frontend/fs_dir.go @@ -9,7 +9,10 @@ import ( "syscall" "github.com/hanwen/go-fuse/fuse" - "github.com/rfjakob/gocryptfs/cryptfs" + + "github.com/rfjakob/gocryptfs/internal/toggledlog" + "github.com/rfjakob/gocryptfs/internal/cryptocore" + "github.com/rfjakob/gocryptfs/internal/nametransform" ) func (fs *FS) Mkdir(relPath string, mode uint32, context *fuse.Context) (code fuse.Status) { @@ -29,7 +32,7 @@ func (fs *FS) Mkdir(relPath string, mode uint32, context *fuse.Context) (code fu mode = mode | 0300 // The new directory may take the place of an older one that is still in the cache - fs.CryptFS.DirIVCache.Clear() + fs.nameTransform.DirIVCache.Clear() // Create directory fs.dirIVLock.Lock() defer fs.dirIVLock.Unlock() @@ -38,13 +41,13 @@ func (fs *FS) Mkdir(relPath string, mode uint32, context *fuse.Context) (code fu return fuse.ToStatus(err) } // Create gocryptfs.diriv inside - err = cryptfs.WriteDirIV(encPath) + err = nametransform.WriteDirIV(encPath) if err != nil { // This should not happen - cryptfs.Warn.Printf("Mkdir: WriteDirIV failed: %v", err) + toggledlog.Warn.Printf("Mkdir: WriteDirIV failed: %v", err) err2 := syscall.Rmdir(encPath) if err2 != nil { - cryptfs.Warn.Printf("Mkdir: Rmdir rollback failed: %v", err2) + toggledlog.Warn.Printf("Mkdir: Rmdir rollback failed: %v", err2) } return fuse.ToStatus(err) } @@ -53,7 +56,7 @@ func (fs *FS) Mkdir(relPath string, mode uint32, context *fuse.Context) (code fu if origMode != mode { err = os.Chmod(encPath, os.FileMode(origMode)) if err != nil { - cryptfs.Warn.Printf("Mkdir: Chmod failed: %v", err) + toggledlog.Warn.Printf("Mkdir: Chmod failed: %v", err) } } @@ -74,17 +77,17 @@ func (fs *FS) Rmdir(name string, context *fuse.Context) (code fuse.Status) { fd, err := os.Open(encPath) if perr, ok := err.(*os.PathError); ok && perr.Err == syscall.EACCES { // We need permission to read and modify the directory - cryptfs.Debug.Printf("Rmdir: handling EACCESS") + toggledlog.Debug.Printf("Rmdir: handling EACCESS") fi, err2 := os.Stat(encPath) if err2 != nil { - cryptfs.Debug.Printf("Rmdir: Stat: %v", err2) + toggledlog.Debug.Printf("Rmdir: Stat: %v", err2) return fuse.ToStatus(err2) } origMode := fi.Mode() newMode := origMode | 0700 err2 = os.Chmod(encPath, newMode) if err2 != nil { - cryptfs.Debug.Printf("Rmdir: Chmod failed: %v", err2) + toggledlog.Debug.Printf("Rmdir: Chmod failed: %v", err2) return fuse.ToStatus(err) } defer func() { @@ -92,7 +95,7 @@ func (fs *FS) Rmdir(name string, context *fuse.Context) (code fuse.Status) { // Undo the chmod if removing the directory failed err3 := os.Chmod(encPath, origMode) if err3 != nil { - cryptfs.Warn.Printf("Rmdir: Chmod rollback failed: %v", err2) + toggledlog.Warn.Printf("Rmdir: Chmod rollback failed: %v", err2) } } }() @@ -100,35 +103,36 @@ func (fs *FS) Rmdir(name string, context *fuse.Context) (code fuse.Status) { fd, err = os.Open(encPath) } if err != nil { - cryptfs.Debug.Printf("Rmdir: Open: %v", err) + toggledlog.Debug.Printf("Rmdir: Open: %v", err) return fuse.ToStatus(err) } list, err := fd.Readdirnames(10) fd.Close() if err != nil { - cryptfs.Debug.Printf("Rmdir: Readdirnames: %v", err) + toggledlog.Debug.Printf("Rmdir: Readdirnames: %v", err) return fuse.ToStatus(err) } if len(list) > 1 { return fuse.ToStatus(syscall.ENOTEMPTY) } else if len(list) == 0 { - cryptfs.Warn.Printf("Rmdir: gocryptfs.diriv missing, allowing deletion") + toggledlog.Warn.Printf("Rmdir: gocryptfs.diriv missing, allowing deletion") return fuse.ToStatus(syscall.Rmdir(encPath)) } // Move "gocryptfs.diriv" to the parent dir as "gocryptfs.diriv.rmdir.XYZ" - dirivPath := filepath.Join(encPath, cryptfs.DIRIV_FILENAME) + dirivPath := filepath.Join(encPath, nametransform.DirIVFilename) parentDir := filepath.Dir(encPath) - tmpName := fmt.Sprintf("gocryptfs.diriv.rmdir.%d", cryptfs.RandUint64()) + tmpName := fmt.Sprintf("gocryptfs.diriv.rmdir.%d", cryptocore.RandUint64()) tmpDirivPath := filepath.Join(parentDir, tmpName) - cryptfs.Debug.Printf("Rmdir: Renaming %s to %s", cryptfs.DIRIV_FILENAME, tmpDirivPath) + toggledlog.Debug.Printf("Rmdir: Renaming %s to %s", nametransform.DirIVFilename, tmpDirivPath) // The directory is in an inconsistent state between rename and rmdir. Protect against // concurrent readers. fs.dirIVLock.Lock() defer fs.dirIVLock.Unlock() err = os.Rename(dirivPath, tmpDirivPath) if err != nil { - cryptfs.Warn.Printf("Rmdir: Renaming %s to %s failed: %v", cryptfs.DIRIV_FILENAME, tmpDirivPath, err) + toggledlog.Warn.Printf("Rmdir: Renaming %s to %s failed: %v", + nametransform.DirIVFilename, tmpDirivPath, err) return fuse.ToStatus(err) } // Actual Rmdir @@ -138,16 +142,16 @@ func (fs *FS) Rmdir(name string, context *fuse.Context) (code fuse.Status) { // meantime, undo the rename err2 := os.Rename(tmpDirivPath, dirivPath) if err2 != nil { - cryptfs.Warn.Printf("Rmdir: Rename rollback failed: %v", err2) + toggledlog.Warn.Printf("Rmdir: Rename rollback failed: %v", err2) } return fuse.ToStatus(err) } // Delete "gocryptfs.diriv.rmdir.INODENUMBER" err = syscall.Unlink(tmpDirivPath) if err != nil { - cryptfs.Warn.Printf("Rmdir: Could not clean up %s: %v", tmpName, err) + toggledlog.Warn.Printf("Rmdir: Could not clean up %s: %v", tmpName, err) } // The now-deleted directory may have been in the DirIV cache. Clear it. - fs.CryptFS.DirIVCache.Clear() + fs.nameTransform.DirIVCache.Clear() return fuse.OK } diff --git a/pathfs_frontend/names.go b/pathfs_frontend/names.go index bd7a249..160fa0a 100644 --- a/pathfs_frontend/names.go +++ b/pathfs_frontend/names.go @@ -3,7 +3,8 @@ package pathfs_frontend // This file forwards file encryption operations to cryptfs import ( - "github.com/rfjakob/gocryptfs/cryptfs" + "github.com/rfjakob/gocryptfs/internal/configfile" + mylog "github.com/rfjakob/gocryptfs/internal/toggledlog" ) // isFiltered - check if plaintext "path" should be forbidden @@ -14,9 +15,9 @@ func (fs *FS) isFiltered(path string) bool { return false } // gocryptfs.conf in the root directory is forbidden - if path == cryptfs.ConfDefaultName { - cryptfs.Info.Printf("The name /%s is reserved when -plaintextnames is used\n", - cryptfs.ConfDefaultName) + if path == configfile.ConfDefaultName { + mylog.Info.Printf("The name /%s is reserved when -plaintextnames is used\n", + configfile.ConfDefaultName) return true } // Note: gocryptfs.diriv is NOT forbidden because diriv and plaintextnames @@ -30,11 +31,11 @@ func (fs *FS) encryptPath(plainPath string) (string, error) { return plainPath, nil } if !fs.args.DirIV { - return fs.CryptFS.EncryptPathNoIV(plainPath), nil + return fs.nameTransform.EncryptPathNoIV(plainPath), nil } fs.dirIVLock.RLock() defer fs.dirIVLock.RUnlock() - return fs.CryptFS.EncryptPathDirIV(plainPath, fs.args.Cipherdir, fs.args.EMENames) + return fs.nameTransform.EncryptPathDirIV(plainPath, fs.args.Cipherdir) } // decryptPath - decrypt relative ciphertext path @@ -43,9 +44,9 @@ func (fs *FS) decryptPath(cipherPath string) (string, error) { return cipherPath, nil } if !fs.args.DirIV { - return fs.CryptFS.DecryptPathNoIV(cipherPath) + return fs.nameTransform.DecryptPathNoIV(cipherPath) } fs.dirIVLock.RLock() defer fs.dirIVLock.RUnlock() - return fs.CryptFS.DecryptPathDirIV(cipherPath, fs.args.Cipherdir, fs.args.EMENames) + return fs.nameTransform.DecryptPathDirIV(cipherPath, fs.args.Cipherdir, fs.args.EMENames) } |