From 791c78b203be199960274053ea2b1d44c63b07c6 Mon Sep 17 00:00:00 2001
From: Jakob Unterwurzacher
Date: Sun, 28 May 2017 20:44:54 +0200
Subject: fusefrontend: aessiv: enable deterministiv file id and block iv

Seems to work ok:

 $ echo aaaaaaaaaaaaaaaaaaa > b/foo
 $ gocryptfs-xray a/LAh7EiK-kjleJhStVZ1JGg
 Header: Version: 2, Id: 8d76d368438112fb00cb807fa8210a74
 Block  0: IV: b05bb152f77816678230885d09a4a596, Tag: c1c7d580fe01dd1eb543efd9d8eda8ad, Offset:    18 Len: 52
 $ > b/foo
 $ echo aaaaaaaaaaaaaaaaaaa > b/foo
 $ gocryptfs-xray a/LAh7EiK-kjleJhStVZ1JGg
 Header: Version: 2, Id: 8d76d368438112fb00cb807fa8210a74
 Block  0: IV: b05bb152f77816678230885d09a4a596, Tag: c1c7d580fe01dd1eb543efd9d8eda8ad, Offset:    18 Len: 52

Deterministic diriv generation is still missing.

Part of https://github.com/rfjakob/gocryptfs/issues/108
---
 internal/contentenc/content.go |  5 +++++
 internal/fusefrontend/file.go  | 27 ++++++++++++++++++++++-----
 internal/fusefrontend/fs.go    | 13 +++++++------
 3 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/internal/contentenc/content.go b/internal/contentenc/content.go
index 8220d89..2a5ddbb 100644
--- a/internal/contentenc/content.go
+++ b/internal/contentenc/content.go
@@ -75,6 +75,11 @@ func (be *ContentEnc) CipherBS() uint64 {
 	return be.cipherBS
 }
 
+// UsingSIV returns true if we are using AES-SIV for file content encryption.
+func (be *ContentEnc) UsingSIV() bool {
+	return be.cryptoCore.AEADBackend == cryptocore.BackendAESSIV
+}
+
 // DecryptBlocks decrypts a number of blocks
 // TODO refactor to three-param for
 func (be *ContentEnc) DecryptBlocks(ciphertext []byte, firstBlockNo uint64, fileID []byte) ([]byte, error) {
diff --git a/internal/fusefrontend/file.go b/internal/fusefrontend/file.go
index 57ec9ba..27c8f70 100644
--- a/internal/fusefrontend/file.go
+++ b/internal/fusefrontend/file.go
@@ -16,6 +16,7 @@ import (
 
 	"github.com/rfjakob/gocryptfs/internal/contentenc"
 	"github.com/rfjakob/gocryptfs/internal/openfiletable"
+	"github.com/rfjakob/gocryptfs/internal/pathiv"
 	"github.com/rfjakob/gocryptfs/internal/serialize_reads"
 	"github.com/rfjakob/gocryptfs/internal/stupidgcm"
 	"github.com/rfjakob/gocryptfs/internal/syscallcompat"
@@ -56,10 +57,13 @@ type file struct {
 	// have not implemented. This prevents build breakage when the go-fuse library
 	// adds new methods to the nodefs.File interface.
 	nodefs.File
+	// In AES-SIV mode, file ID and block IVs are deterministically derived from
+	// the path that was used to open the file.
+	pathIVs pathiv.FileIVs
 }
 
 // NewFile returns a new go-fuse File instance.
-func NewFile(fd *os.File, fs *FS) (nodefs.File, fuse.Status) {
+func NewFile(fd *os.File, fs *FS, relPath string) (nodefs.File, fuse.Status) {
 	var st syscall.Stat_t
 	err := syscall.Fstat(int(fd.Fd()), &st)
 	if err != nil {
@@ -68,8 +72,7 @@ func NewFile(fd *os.File, fs *FS) (nodefs.File, fuse.Status) {
 	}
 	qi := openfiletable.QInoFromStat(&st)
 	e := openfiletable.Register(qi)
-
-	return &file{
+	f := &file{
 		fd:             fd,
 		contentEnc:     fs.contentEnc,
 		qIno:           qi,
@@ -77,7 +80,11 @@ func NewFile(fd *os.File, fs *FS) (nodefs.File, fuse.Status) {
 		loopbackFile:   nodefs.NewLoopbackFile(fd),
 		fs:             fs,
 		File:           nodefs.NewDefaultFile(),
-	}, fuse.OK
+	}
+	if fs.contentEnc.UsingSIV() {
+		f.pathIVs = pathiv.DeriveFile(relPath)
+	}
+	return f, fuse.OK
 }
 
 // intFd - return the backing file descriptor as an integer. Used for debug
@@ -115,6 +122,10 @@ func (f *file) readFileID() ([]byte, error) {
 // The caller must hold fileIDLock.Lock().
 func (f *file) createHeader() (fileID []byte, err error) {
 	h := contentenc.RandomHeader()
+	if f.contentEnc.UsingSIV() {
+		// We use a deterministic file ID in SIV mode.
+		h.ID = f.pathIVs.ID
+	}
 	buf := h.Pack()
 	// Prevent partially written (=corrupt) header by preallocating the space beforehand
 	if !f.fs.args.NoPrealloc {
@@ -297,7 +308,13 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {
 			tlog.Debug.Printf("len(oldData)=%d len(blockData)=%d", len(oldData), len(blockData))
 		}
 		// Encrypt
-		blockData = f.contentEnc.EncryptBlock(blockData, b.BlockNo, fileID)
+		if f.fs.contentEnc.UsingSIV() {
+			// We use a deterministic block IV in SIV mode.
+			iv := pathiv.BlockIV(f.pathIVs.Block0IV, b.BlockNo)
+			blockData = f.contentEnc.EncryptBlockNonce(blockData, b.BlockNo, fileID, iv)
+		} else {
+			blockData = f.contentEnc.EncryptBlock(blockData, b.BlockNo, fileID)
+		}
 		tlog.Debug.Printf("ino%d: Writing %d bytes to block #%d",
 			f.qIno.Ino, uint64(len(blockData))-f.contentEnc.BlockOverhead(), b.BlockNo)
 		// Store output data in the writeChain
diff --git a/internal/fusefrontend/fs.go b/internal/fusefrontend/fs.go
index c589302..40b6d2d 100644
--- a/internal/fusefrontend/fs.go
+++ b/internal/fusefrontend/fs.go
@@ -100,11 +100,12 @@ func (fs *FS) Open(path string, flags uint32, context *fuse.Context) (fuseFile n
 		return nil, fuse.EPERM
 	}
 	newFlags := fs.mangleOpenFlags(flags)
-	cPath, err := fs.getBackingPath(path)
+	cRelPath, err := fs.encryptPath(path)
 	if err != nil {
-		tlog.Debug.Printf("Open: getBackingPath: %v", err)
+		tlog.Debug.Printf("Open: encryptPath: %v", err)
 		return nil, fuse.ToStatus(err)
 	}
+	cPath := filepath.Join(fs.args.Cipherdir, cRelPath)
 	tlog.Debug.Printf("Open: %s", cPath)
 	f, err := os.OpenFile(cPath, newFlags, 0666)
 	if err != nil {
@@ -116,8 +117,7 @@ func (fs *FS) Open(path string, flags uint32, context *fuse.Context) (fuseFile n
 		}
 		return nil, fuse.ToStatus(err)
 	}
-
-	return NewFile(f, fs)
+	return NewFile(f, fs, cRelPath)
 }
 
 // Create implements pathfs.Filesystem.
@@ -126,10 +126,11 @@ func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Conte
 		return nil, fuse.EPERM
 	}
 	newFlags := fs.mangleOpenFlags(flags)
-	cPath, err := fs.getBackingPath(path)
+	cRelPath, err := fs.encryptPath(path)
 	if err != nil {
 		return nil, fuse.ToStatus(err)
 	}
+	cPath := filepath.Join(fs.args.Cipherdir, cRelPath)
 
 	var fd *os.File
 	cName := filepath.Base(cPath)
@@ -171,7 +172,7 @@ func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Conte
 			tlog.Warn.Printf("Create: fd.Chown failed: %v", err)
 		}
 	}
-	return NewFile(fd, fs)
+	return NewFile(fd, fs, path)
 }
 
 // Chmod implements pathfs.Filesystem.
-- 
cgit v1.2.3