diff options
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/contentenc/content.go | 56 | ||||
| -rw-r--r-- | internal/fusefrontend/file.go | 2 | 
2 files changed, 48 insertions, 10 deletions
| diff --git a/internal/contentenc/content.go b/internal/contentenc/content.go index 3f578e8..9bc1c50 100644 --- a/internal/contentenc/content.go +++ b/internal/contentenc/content.go @@ -10,6 +10,8 @@ import (  	"runtime"  	"sync" +	"github.com/hanwen/go-fuse/fuse" +  	"github.com/rfjakob/gocryptfs/internal/cryptocore"  	"github.com/rfjakob/gocryptfs/internal/stupidgcm"  	"github.com/rfjakob/gocryptfs/internal/tlog" @@ -51,20 +53,43 @@ type ContentEnc struct {  	allZeroNonce []byte  	// Force decode even if integrity check fails (openSSL only)  	forceDecode bool +	// Ciphertext block pool. Always returns cipherBS-sized byte slices. +	cBlockPool sync.Pool +	// Ciphertext write pool. Always returns byte slices of size +	// fuse.MAX_KERNEL_WRITE + overhead. +	cWritePool sync.Pool +	cWriteSize int  }  // New returns an initialized ContentEnc instance.  func New(cc *cryptocore.CryptoCore, plainBS uint64, forceDecode bool) *ContentEnc {  	cipherBS := plainBS + uint64(cc.IVLen) + cryptocore.AuthTagLen - -	return &ContentEnc{ +	// Take IV and GHASH overhead into account. +	cWriteSize := int(fuse.MAX_KERNEL_WRITE / plainBS * cipherBS) +	if fuse.MAX_KERNEL_WRITE%plainBS != 0 { +		log.Panicf("unaligned MAX_KERNEL_WRITE=%d", fuse.MAX_KERNEL_WRITE) +	} +	c := &ContentEnc{  		cryptoCore:   cc,  		plainBS:      plainBS,  		cipherBS:     cipherBS,  		allZeroBlock: make([]byte, cipherBS),  		allZeroNonce: make([]byte, cc.IVLen),  		forceDecode:  forceDecode, +		cWriteSize:   cWriteSize, +	} +	c.cBlockPool.New = func() interface{} { return make([]byte, cipherBS) } +	c.cWritePool.New = func() interface{} { return make([]byte, cWriteSize) } +	return c +} + +// CWritePut puts "buf" back into the cWritePool. +func (be *ContentEnc) CWritePut(buf []byte) { +	buf = buf[:cap(buf)] +	if len(buf) != be.cWriteSize { +		log.Panicf("wrong len=%d, want=%d", len(buf), be.cWriteSize)  	} +	be.cWritePool.Put(buf)  }  // PlainBS returns the plaintext block size @@ -185,12 +210,16 @@ func (be *ContentEnc) EncryptBlocks(plaintextBlocks [][]byte, firstBlockNo uint6  		be.doEncryptBlocks(plaintextBlocks, ciphertextBlocks, firstBlockNo, fileID)  	}  	// Concatenate ciphertext into a single byte array. -	// Size the output buffer for the maximum possible size (all blocks complete) -	// to prevent further allocations in out.Write() -	tmp := make([]byte, len(plaintextBlocks)*int(be.CipherBS())) +	tmp := be.cWritePool.Get().([]byte)  	out := bytes.NewBuffer(tmp[:0])  	for _, v := range ciphertextBlocks {  		out.Write(v) +		// Return the memory to cBlockPool +		cBlock := v[:cap(v)] +		if len(cBlock) != int(be.cipherBS) { +			log.Panicf("unexpected cBlock length: len=%d cipherBS=%d", len(cBlock), be.cipherBS) +		} +		be.cBlockPool.Put(cBlock)  	}  	return out.Bytes()  } @@ -233,15 +262,22 @@ func (be *ContentEnc) doEncryptBlock(plaintext []byte, blockNo uint64, fileID []  	if len(nonce) != be.cryptoCore.IVLen {  		log.Panic("wrong nonce length")  	} - -	// Authenticate block with block number and file ID +	// Block is authenticated with block number and file ID  	aData := make([]byte, 8)  	binary.BigEndian.PutUint64(aData, blockNo)  	aData = append(aData, fileID...) - +	// Get a cipherBS-sized block of memory, copy the nonce into it and truncate to +	// nonce length +	cBlock := be.cBlockPool.Get().([]byte) +	copy(cBlock, nonce) +	cBlock = cBlock[0:len(nonce)]  	// Encrypt plaintext and append to nonce -	ciphertext := be.cryptoCore.AEADCipher.Seal(nonce, nonce, plaintext, aData) - +	ciphertext := be.cryptoCore.AEADCipher.Seal(cBlock, nonce, plaintext, aData) +	overhead := int(be.cipherBS - be.plainBS) +	if len(plaintext)+overhead != len(ciphertext) { +		log.Panicf("unexpected ciphertext length: plaintext=%d, overhead=%d, ciphertext=%d", +			len(plaintext), overhead, len(ciphertext)) +	}  	return ciphertext  } diff --git a/internal/fusefrontend/file.go b/internal/fusefrontend/file.go index 5b0a254..f70c9a5 100644 --- a/internal/fusefrontend/file.go +++ b/internal/fusefrontend/file.go @@ -311,6 +311,8 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {  	}  	// Write  	_, err = f.fd.WriteAt(ciphertext, cOff) +	// Return memory to cWritePool +	f.fs.contentEnc.CWritePut(ciphertext)  	if err != nil {  		tlog.Warn.Printf("doWrite: Write failed: %s", err.Error())  		return 0, fuse.ToStatus(err) | 
