aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cryptfs/cryptfs_content.go45
-rw-r--r--frontend/fe_file.go48
2 files changed, 72 insertions, 21 deletions
diff --git a/cryptfs/cryptfs_content.go b/cryptfs/cryptfs_content.go
index 0ebf34d..512bca9 100644
--- a/cryptfs/cryptfs_content.go
+++ b/cryptfs/cryptfs_content.go
@@ -3,6 +3,7 @@ package cryptfs
// File content encryption / decryption
import (
+ "bytes"
"os"
"errors"
"crypto/cipher"
@@ -13,7 +14,23 @@ type CryptFile struct {
gcm cipher.AEAD
}
-// decryptBlock - Verify and decrypt GCM block
+// DecryptBlocks - Decrypt a number of blocks
+func (be *CryptFS) DecryptBlocks(ciphertext []byte) ([]byte, error) {
+ cBuf := bytes.NewBuffer(ciphertext)
+ var err error
+ var pBuf bytes.Buffer
+ for cBuf.Len() > 0 {
+ cBlock := cBuf.Next(int(be.cipherBS))
+ pBlock, err := be.DecryptBlock(cBlock)
+ if err != nil {
+ break
+ }
+ pBuf.Write(pBlock)
+ }
+ return pBuf.Bytes(), err
+}
+
+// DecryptBlock - Verify and decrypt GCM block
func (be *CryptFS) DecryptBlock(ciphertext []byte) ([]byte, error) {
// Empty block?
@@ -92,3 +109,29 @@ func (be *CryptFS) minu64(x uint64, y uint64) uint64 {
}
return y
}
+
+// Get the byte range in the ciphertext corresponding to blocks
+// (full blocks!)
+func (be *CryptFS) JoinCiphertextRange(blocks []intraBlock) (uint64, uint64) {
+
+ offset, _ := blocks[0].CiphertextRange()
+ last := blocks[len(blocks)-1]
+ length := (last.BlockNo - blocks[0].BlockNo + 1) * be.cipherBS
+
+ return offset, length
+}
+
+// Crop plaintext that correspons to complete cipher blocks down to what is
+// requested according to "iblocks"
+func (be *CryptFS) CropPlaintext(plaintext []byte, blocks []intraBlock) []byte {
+ offset := blocks[0].Offset
+ last := blocks[len(blocks)-1]
+ length := (last.BlockNo - blocks[0].BlockNo + 1) * be.plainBS
+ var cropped []byte
+ if offset + length > uint64(len(plaintext)) {
+ cropped = plaintext[offset:len(plaintext)]
+ } else {
+ cropped = plaintext[offset:offset+length]
+ }
+ return cropped
+}
diff --git a/frontend/fe_file.go b/frontend/fe_file.go
index 7cc23ad..b417227 100644
--- a/frontend/fe_file.go
+++ b/frontend/fe_file.go
@@ -67,26 +67,32 @@ func (f *File) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenR
}
func (f *File) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
+
+ fmt.Printf("Read: o=%d l=%d\n", req.Offset, req.Size)
+
+ // Read the backing ciphertext in one go
iblocks := f.crfs.SplitRange(uint64(req.Offset), uint64(req.Size))
- for _, ib := range iblocks {
- var partReq fuse.ReadRequest
- var partResp fuse.ReadResponse
- o, l := ib.CiphertextRange()
- partReq.Offset = int64(o)
- partReq.Size = int(l)
- partResp.Data = make([]byte, int(l))
- err := f.File.Read(ctx, &partReq, &partResp)
- if err != nil {
- return err
- }
- plaintext, err := f.crfs.DecryptBlock(partResp.Data)
- if err != nil {
- fmt.Printf("Read: Error reading block %d: %s\n", ib.BlockNo, err.Error())
- return err
- }
- plaintext = ib.CropBlock(plaintext)
- resp.Data = append(resp.Data, plaintext...)
+ var cipherReq fuse.ReadRequest
+ var cipherResp fuse.ReadResponse
+ o, l := f.crfs.JoinCiphertextRange(iblocks)
+ cipherResp.Data = make([]byte, int(l))
+ cipherReq.Offset = int64(o)
+ cipherReq.Size = int(l)
+ cryptfs.Debug.Printf("Read: cipherReq o=%d l=%d\n", o, l)
+ err := f.File.Read(ctx, &cipherReq, &cipherResp)
+ if err != nil {
+ return err
+ }
+
+ // Decrypt it
+ plaintext, err := f.crfs.DecryptBlocks(cipherResp.Data)
+ if err != nil {
+ resp.Data = plaintext
+ return err
}
+ // Crop down to relevant part
+ resp.Data = f.crfs.CropPlaintext(plaintext, iblocks)
+
return nil
}
@@ -98,6 +104,7 @@ func (f *File) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.Wri
for _, ib := range iblocks {
if ib.IsPartial() {
// RMW
+ cryptfs.Debug.Printf("RMW\n")
blockData = make([]byte, f.crfs.PlainBS())
var readReq fuse.ReadRequest
var readResp fuse.ReadResponse
@@ -127,8 +134,9 @@ func (f *File) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.Wri
return err
}
// Remove written data from the front of the request
- req.Data = req.Data[len(blockData):len(req.Data)]
- resp.Size += len(blockData)
+ cryptfs.Debug.Printf("req.Data[%d:%d]\n", int(ib.Length), len(req.Data))
+ req.Data = req.Data[int(ib.Length):len(req.Data)]
+ resp.Size += int(ib.Length)
}
return nil
}