Bundle up blocks for bigger reads from the backing filesystem

This commit is contained in:
Jakob Unterwurzacher 2015-09-06 09:47:01 +02:00
parent baa837b788
commit 448e88490b
2 changed files with 72 additions and 21 deletions

View File

@ -3,6 +3,7 @@ package cryptfs
// File content encryption / decryption // File content encryption / decryption
import ( import (
"bytes"
"os" "os"
"errors" "errors"
"crypto/cipher" "crypto/cipher"
@ -13,7 +14,23 @@ type CryptFile struct {
gcm cipher.AEAD 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) { func (be *CryptFS) DecryptBlock(ciphertext []byte) ([]byte, error) {
// Empty block? // Empty block?
@ -92,3 +109,29 @@ func (be *CryptFS) minu64(x uint64, y uint64) uint64 {
} }
return y 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
}

View File

@ -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 { 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)) iblocks := f.crfs.SplitRange(uint64(req.Offset), uint64(req.Size))
for _, ib := range iblocks { var cipherReq fuse.ReadRequest
var partReq fuse.ReadRequest var cipherResp fuse.ReadResponse
var partResp fuse.ReadResponse o, l := f.crfs.JoinCiphertextRange(iblocks)
o, l := ib.CiphertextRange() cipherResp.Data = make([]byte, int(l))
partReq.Offset = int64(o) cipherReq.Offset = int64(o)
partReq.Size = int(l) cipherReq.Size = int(l)
partResp.Data = make([]byte, int(l)) cryptfs.Debug.Printf("Read: cipherReq o=%d l=%d\n", o, l)
err := f.File.Read(ctx, &partReq, &partResp) err := f.File.Read(ctx, &cipherReq, &cipherResp)
if err != nil { if err != nil {
return err return err
} }
plaintext, err := f.crfs.DecryptBlock(partResp.Data)
// Decrypt it
plaintext, err := f.crfs.DecryptBlocks(cipherResp.Data)
if err != nil { if err != nil {
fmt.Printf("Read: Error reading block %d: %s\n", ib.BlockNo, err.Error()) resp.Data = plaintext
return err return err
} }
plaintext = ib.CropBlock(plaintext) // Crop down to relevant part
resp.Data = append(resp.Data, plaintext...) resp.Data = f.crfs.CropPlaintext(plaintext, iblocks)
}
return nil return nil
} }
@ -98,6 +104,7 @@ func (f *File) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.Wri
for _, ib := range iblocks { for _, ib := range iblocks {
if ib.IsPartial() { if ib.IsPartial() {
// RMW // RMW
cryptfs.Debug.Printf("RMW\n")
blockData = make([]byte, f.crfs.PlainBS()) blockData = make([]byte, f.crfs.PlainBS())
var readReq fuse.ReadRequest var readReq fuse.ReadRequest
var readResp fuse.ReadResponse var readResp fuse.ReadResponse
@ -127,8 +134,9 @@ func (f *File) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.Wri
return err return err
} }
// Remove written data from the front of the request // Remove written data from the front of the request
req.Data = req.Data[len(blockData):len(req.Data)] cryptfs.Debug.Printf("req.Data[%d:%d]\n", int(ib.Length), len(req.Data))
resp.Size += len(blockData) req.Data = req.Data[int(ib.Length):len(req.Data)]
resp.Size += int(ib.Length)
} }
return nil return nil
} }