@@ -10,6 +10,8 @@ import (
1010 "runtime"
1111 "sync"
1212
13+ "github.com/hanwen/go-fuse/fuse"
14+
1315 "github.com/rfjakob/gocryptfs/internal/cryptocore"
1416 "github.com/rfjakob/gocryptfs/internal/stupidgcm"
1517 "github.com/rfjakob/gocryptfs/internal/tlog"
@@ -51,20 +53,43 @@ type ContentEnc struct {
5153 allZeroNonce []byte
5254 // Force decode even if integrity check fails (openSSL only)
5355 forceDecode bool
56+ // Ciphertext block pool. Always returns cipherBS-sized byte slices.
57+ cBlockPool sync.Pool
58+ // Ciphertext write pool. Always returns byte slices of size
59+ // fuse.MAX_KERNEL_WRITE + overhead.
60+ cWritePool sync.Pool
61+ cWriteSize int
5462}
5563
5664// New returns an initialized ContentEnc instance.
5765func New (cc * cryptocore.CryptoCore , plainBS uint64 , forceDecode bool ) * ContentEnc {
5866 cipherBS := plainBS + uint64 (cc .IVLen ) + cryptocore .AuthTagLen
59-
60- return & ContentEnc {
67+ // Take IV and GHASH overhead into account.
68+ cWriteSize := int (fuse .MAX_KERNEL_WRITE / plainBS * cipherBS )
69+ if fuse .MAX_KERNEL_WRITE % plainBS != 0 {
70+ log .Panicf ("unaligned MAX_KERNEL_WRITE=%d" , fuse .MAX_KERNEL_WRITE )
71+ }
72+ c := & ContentEnc {
6173 cryptoCore : cc ,
6274 plainBS : plainBS ,
6375 cipherBS : cipherBS ,
6476 allZeroBlock : make ([]byte , cipherBS ),
6577 allZeroNonce : make ([]byte , cc .IVLen ),
6678 forceDecode : forceDecode ,
79+ cWriteSize : cWriteSize ,
80+ }
81+ c .cBlockPool .New = func () interface {} { return make ([]byte , cipherBS ) }
82+ c .cWritePool .New = func () interface {} { return make ([]byte , cWriteSize ) }
83+ return c
84+ }
85+
86+ // CWritePut puts "buf" back into the cWritePool.
87+ func (be * ContentEnc ) CWritePut (buf []byte ) {
88+ buf = buf [:cap (buf )]
89+ if len (buf ) != be .cWriteSize {
90+ log .Panicf ("wrong len=%d, want=%d" , len (buf ), be .cWriteSize )
6791 }
92+ be .cWritePool .Put (buf )
6893}
6994
7095// PlainBS returns the plaintext block size
@@ -185,12 +210,16 @@ func (be *ContentEnc) EncryptBlocks(plaintextBlocks [][]byte, firstBlockNo uint6
185210 be .doEncryptBlocks (plaintextBlocks , ciphertextBlocks , firstBlockNo , fileID )
186211 }
187212 // Concatenate ciphertext into a single byte array.
188- // Size the output buffer for the maximum possible size (all blocks complete)
189- // to prevent further allocations in out.Write()
190- tmp := make ([]byte , len (plaintextBlocks )* int (be .CipherBS ()))
213+ tmp := be .cWritePool .Get ().([]byte )
191214 out := bytes .NewBuffer (tmp [:0 ])
192215 for _ , v := range ciphertextBlocks {
193216 out .Write (v )
217+ // Return the memory to cBlockPool
218+ cBlock := v [:cap (v )]
219+ if len (cBlock ) != int (be .cipherBS ) {
220+ log .Panicf ("unexpected cBlock length: len=%d cipherBS=%d" , len (cBlock ), be .cipherBS )
221+ }
222+ be .cBlockPool .Put (cBlock )
194223 }
195224 return out .Bytes ()
196225}
@@ -233,15 +262,22 @@ func (be *ContentEnc) doEncryptBlock(plaintext []byte, blockNo uint64, fileID []
233262 if len (nonce ) != be .cryptoCore .IVLen {
234263 log .Panic ("wrong nonce length" )
235264 }
236-
237- // Authenticate block with block number and file ID
265+ // Block is authenticated with block number and file ID
238266 aData := make ([]byte , 8 )
239267 binary .BigEndian .PutUint64 (aData , blockNo )
240268 aData = append (aData , fileID ... )
241-
269+ // Get a cipherBS-sized block of memory, copy the nonce into it and truncate to
270+ // nonce length
271+ cBlock := be .cBlockPool .Get ().([]byte )
272+ copy (cBlock , nonce )
273+ cBlock = cBlock [0 :len (nonce )]
242274 // Encrypt plaintext and append to nonce
243- ciphertext := be .cryptoCore .AEADCipher .Seal (nonce , nonce , plaintext , aData )
244-
275+ ciphertext := be .cryptoCore .AEADCipher .Seal (cBlock , nonce , plaintext , aData )
276+ overhead := int (be .cipherBS - be .plainBS )
277+ if len (plaintext )+ overhead != len (ciphertext ) {
278+ log .Panicf ("unexpected ciphertext length: plaintext=%d, overhead=%d, ciphertext=%d" ,
279+ len (plaintext ), overhead , len (ciphertext ))
280+ }
245281 return ciphertext
246282}
247283
0 commit comments