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
|
// 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
|
||||||
|
}
|
||||||
|
@ -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)
|
|
||||||
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...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
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
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user