Bundle up blocks for bigger reads from the backing filesystem
This commit is contained in:
parent
baa837b788
commit
448e88490b
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user