diff --git a/internal/fusefrontend_reverse/ctlsock_interface.go b/internal/fusefrontend_reverse/ctlsock_interface.go index 4d9a446..5f61f37 100644 --- a/internal/fusefrontend_reverse/ctlsock_interface.go +++ b/internal/fusefrontend_reverse/ctlsock_interface.go @@ -6,6 +6,7 @@ import ( "syscall" "github.com/rfjakob/gocryptfs/internal/ctlsock" + "github.com/rfjakob/gocryptfs/internal/pathiv" ) var _ ctlsock.Interface = &ReverseFS{} // Verify that interface is implemented. @@ -20,7 +21,7 @@ func (rfs *ReverseFS) EncryptPath(plainPath string) (string, error) { cipherPath := "" parts := strings.Split(plainPath, "/") for _, part := range parts { - dirIV := derivePathIV(cipherPath, ivPurposeDirIV) + dirIV := pathiv.Derive(cipherPath, pathiv.PurposeDirIV) encryptedPart := rfs.nameTransform.EncryptName(part, dirIV) if rfs.args.LongNames && len(encryptedPart) > syscall.NAME_MAX { encryptedPart = rfs.nameTransform.HashLongName(encryptedPart) diff --git a/internal/fusefrontend_reverse/reverse_longnames.go b/internal/fusefrontend_reverse/reverse_longnames.go index 0830298..7e26c90 100644 --- a/internal/fusefrontend_reverse/reverse_longnames.go +++ b/internal/fusefrontend_reverse/reverse_longnames.go @@ -12,6 +12,7 @@ import ( "github.com/hanwen/go-fuse/fuse/nodefs" "github.com/rfjakob/gocryptfs/internal/nametransform" + "github.com/rfjakob/gocryptfs/internal/pathiv" "github.com/rfjakob/gocryptfs/internal/tlog" ) @@ -91,7 +92,7 @@ func (rfs *ReverseFS) newNameFile(relPath string) (nodefs.File, fuse.Status) { if err != nil { return nil, fuse.ToStatus(err) } - dirIV := derivePathIV(cDir, ivPurposeDirIV) + dirIV := pathiv.Derive(cDir, pathiv.PurposeDirIV) // plain name pName, err := rfs.findLongnameParent(pDir, dirIV, longname) if err != nil { diff --git a/internal/fusefrontend_reverse/rfile.go b/internal/fusefrontend_reverse/rfile.go index 9a680bb..b19ad5e 100644 --- a/internal/fusefrontend_reverse/rfile.go +++ b/internal/fusefrontend_reverse/rfile.go @@ -14,6 +14,7 @@ import ( "github.com/hanwen/go-fuse/fuse/nodefs" "github.com/rfjakob/gocryptfs/internal/contentenc" + "github.com/rfjakob/gocryptfs/internal/pathiv" "github.com/rfjakob/gocryptfs/internal/tlog" ) @@ -60,8 +61,8 @@ func (rfs *ReverseFS) newFile(relPath string, flags uint32) (nodefs.File, fuse.S tlog.Debug.Printf("ino%d: newFile: found in the inode table", st.Ino) derivedIVs = v.(derivedIVContainer) } else { - derivedIVs.id = derivePathIV(relPath, ivPurposeFileID) - derivedIVs.block0IV = derivePathIV(relPath, ivPurposeBlock0IV) + derivedIVs.id = pathiv.Derive(relPath, pathiv.PurposeFileID) + derivedIVs.block0IV = pathiv.Derive(relPath, pathiv.PurposeBlock0IV) // Nlink > 1 means there is more than one path to this file. // Store the derived values so we always return the same data, // regardless of the path that is used to access the file. diff --git a/internal/fusefrontend_reverse/rfs.go b/internal/fusefrontend_reverse/rfs.go index 06bbfe9..63384ac 100644 --- a/internal/fusefrontend_reverse/rfs.go +++ b/internal/fusefrontend_reverse/rfs.go @@ -16,6 +16,7 @@ import ( "github.com/rfjakob/gocryptfs/internal/cryptocore" "github.com/rfjakob/gocryptfs/internal/fusefrontend" "github.com/rfjakob/gocryptfs/internal/nametransform" + "github.com/rfjakob/gocryptfs/internal/pathiv" "github.com/rfjakob/gocryptfs/internal/tlog" ) @@ -263,7 +264,7 @@ func (rfs *ReverseFS) OpenDir(cipherPath string, context *fuse.Context) ([]fuse. nVirtual := 1 // Encrypt names - dirIV := derivePathIV(cipherPath, ivPurposeDirIV) + dirIV := pathiv.Derive(cipherPath, pathiv.PurposeDirIV) for i := range entries { var cName string // ".gocryptfs.reverse.conf" in the root directory is mapped to "gocryptfs.conf" @@ -305,7 +306,7 @@ func (rfs *ReverseFS) Readlink(cipherPath string, context *fuse.Context) (string if rfs.args.PlaintextNames { return plainTarget, fuse.OK } - nonce := derivePathIV(cipherPath, ivPurposeSymlinkIV) + nonce := pathiv.Derive(cipherPath, pathiv.PurposeSymlinkIV) // Symlinks are encrypted like file contents and base64-encoded cBinTarget := rfs.contentEnc.EncryptBlockNonce([]byte(plainTarget), 0, nil, nonce) cTarget := rfs.nameTransform.B64.EncodeToString(cBinTarget) diff --git a/internal/fusefrontend_reverse/rpath.go b/internal/fusefrontend_reverse/rpath.go index 5082d11..58e8c91 100644 --- a/internal/fusefrontend_reverse/rpath.go +++ b/internal/fusefrontend_reverse/rpath.go @@ -1,13 +1,13 @@ package fusefrontend_reverse import ( - "crypto/sha256" "encoding/base64" "path/filepath" "strings" "syscall" "github.com/rfjakob/gocryptfs/internal/nametransform" + "github.com/rfjakob/gocryptfs/internal/pathiv" "github.com/rfjakob/gocryptfs/internal/tlog" ) @@ -20,23 +20,6 @@ func saneDir(path string) string { return d } -type ivPurposeType string - -const ( - ivPurposeDirIV ivPurposeType = "DIRIV" - ivPurposeFileID ivPurposeType = "FILEID" - ivPurposeSymlinkIV ivPurposeType = "SYMLINKIV" - ivPurposeBlock0IV ivPurposeType = "BLOCK0IV" -) - -// derivePathIV derives an IV from an encrypted path by hashing it with sha256 -func derivePathIV(path string, purpose ivPurposeType) []byte { - // Use null byte as separator as it cannot occur in the path - extended := []byte(path + "\000" + string(purpose)) - hash := sha256.Sum256(extended) - return hash[:nametransform.DirIVLen] -} - // abs basically returns storage dir + "/" + relPath. // It takes an error parameter so it can directly wrap decryptPath like this: // a, err := rfs.abs(rfs.decryptPath(relPath)) @@ -104,7 +87,7 @@ func (rfs *ReverseFS) decryptPath(relPath string) (string, error) { // Start at the top and recurse currentCipherDir := filepath.Join(parts[:i]...) currentPlainDir := filepath.Join(transformedParts[:i]...) - dirIV = derivePathIV(currentCipherDir, ivPurposeDirIV) + dirIV = pathiv.Derive(currentCipherDir, pathiv.PurposeDirIV) transformedPart, err := rfs.rDecryptName(parts[i], dirIV, currentPlainDir) if err != nil { return "", err diff --git a/internal/fusefrontend_reverse/virtualfile.go b/internal/fusefrontend_reverse/virtualfile.go index 00fa726..5d5d80d 100644 --- a/internal/fusefrontend_reverse/virtualfile.go +++ b/internal/fusefrontend_reverse/virtualfile.go @@ -6,6 +6,7 @@ import ( "github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse/nodefs" + "github.com/rfjakob/gocryptfs/internal/pathiv" "github.com/rfjakob/gocryptfs/internal/tlog" ) @@ -27,7 +28,7 @@ func (rfs *ReverseFS) newDirIVFile(cRelPath string) (nodefs.File, fuse.Status) { if err != nil { return nil, fuse.ToStatus(err) } - return rfs.newVirtualFile(derivePathIV(cDir, ivPurposeDirIV), absDir) + return rfs.newVirtualFile(pathiv.Derive(cDir, pathiv.PurposeDirIV), absDir) } type virtualFile struct { diff --git a/internal/pathiv/pathiv.go b/internal/pathiv/pathiv.go new file mode 100644 index 0000000..d2d90a2 --- /dev/null +++ b/internal/pathiv/pathiv.go @@ -0,0 +1,24 @@ +package pathiv + +import ( + "crypto/sha256" + + "github.com/rfjakob/gocryptfs/internal/nametransform" +) + +type Purpose string + +const ( + PurposeDirIV Purpose = "DIRIV" + PurposeFileID Purpose = "FILEID" + PurposeSymlinkIV Purpose = "SYMLINKIV" + PurposeBlock0IV Purpose = "BLOCK0IV" +) + +// Derive derives an IV from an encrypted path by hashing it with sha256 +func Derive(path string, purpose Purpose) []byte { + // Use null byte as separator as it cannot occur in the path + extended := []byte(path + "\000" + string(purpose)) + hash := sha256.Sum256(extended) + return hash[:nametransform.DirIVLen] +}