contentenc: add safer "bPool" pool variant; add pBlockPool
bPool verifies the lengths of slices going in and out. Also, add a plaintext block pool - pBlockPool - and use it for decryption.
This commit is contained in:
parent
3d32bcd37b
commit
80676c685f
|
@ -0,0 +1,39 @@
|
||||||
|
package contentenc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// bPool is a byte slice pool
|
||||||
|
type bPool struct {
|
||||||
|
sync.Pool
|
||||||
|
sliceLen int
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBPool(sliceLen int) bPool {
|
||||||
|
return bPool{
|
||||||
|
Pool: sync.Pool{
|
||||||
|
New: func() interface{} { return make([]byte, sliceLen) },
|
||||||
|
},
|
||||||
|
sliceLen: sliceLen,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put grows the slice "s" to its maximum capacity and puts it into the pool.
|
||||||
|
func (b *bPool) Put(s []byte) {
|
||||||
|
s = s[:cap(s)]
|
||||||
|
if len(s) != b.sliceLen {
|
||||||
|
log.Panicf("wrong len=%d, want=%d", len(s), b.sliceLen)
|
||||||
|
}
|
||||||
|
b.Pool.Put(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns a byte slice from the pool.
|
||||||
|
func (b *bPool) Get() (s []byte) {
|
||||||
|
s = b.Pool.Get().([]byte)
|
||||||
|
if len(s) != b.sliceLen {
|
||||||
|
log.Panicf("wrong len=%d, want=%d", len(s), b.sliceLen)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
|
@ -54,18 +54,19 @@ type ContentEnc struct {
|
||||||
// Force decode even if integrity check fails (openSSL only)
|
// Force decode even if integrity check fails (openSSL only)
|
||||||
forceDecode bool
|
forceDecode bool
|
||||||
// Ciphertext block pool. Always returns cipherBS-sized byte slices.
|
// Ciphertext block pool. Always returns cipherBS-sized byte slices.
|
||||||
cBlockPool sync.Pool
|
cBlockPool bPool
|
||||||
// Ciphertext write pool. Always returns byte slices of size
|
// Ciphertext request data pool. Always returns byte slices of size
|
||||||
// fuse.MAX_KERNEL_WRITE + overhead.
|
// fuse.MAX_KERNEL_WRITE + overhead.
|
||||||
cWritePool sync.Pool
|
CReqPool bPool
|
||||||
cWriteSize int
|
// Plaintext block pool. Always returns plainBS-sized byte slices.
|
||||||
|
pBlockPool bPool
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns an initialized ContentEnc instance.
|
// New returns an initialized ContentEnc instance.
|
||||||
func New(cc *cryptocore.CryptoCore, plainBS uint64, forceDecode bool) *ContentEnc {
|
func New(cc *cryptocore.CryptoCore, plainBS uint64, forceDecode bool) *ContentEnc {
|
||||||
cipherBS := plainBS + uint64(cc.IVLen) + cryptocore.AuthTagLen
|
cipherBS := plainBS + uint64(cc.IVLen) + cryptocore.AuthTagLen
|
||||||
// Take IV and GHASH overhead into account.
|
// Take IV and GHASH overhead into account.
|
||||||
cWriteSize := int(fuse.MAX_KERNEL_WRITE / plainBS * cipherBS)
|
cReqSize := int(fuse.MAX_KERNEL_WRITE / plainBS * cipherBS)
|
||||||
if fuse.MAX_KERNEL_WRITE%plainBS != 0 {
|
if fuse.MAX_KERNEL_WRITE%plainBS != 0 {
|
||||||
log.Panicf("unaligned MAX_KERNEL_WRITE=%d", fuse.MAX_KERNEL_WRITE)
|
log.Panicf("unaligned MAX_KERNEL_WRITE=%d", fuse.MAX_KERNEL_WRITE)
|
||||||
}
|
}
|
||||||
|
@ -76,22 +77,13 @@ func New(cc *cryptocore.CryptoCore, plainBS uint64, forceDecode bool) *ContentEn
|
||||||
allZeroBlock: make([]byte, cipherBS),
|
allZeroBlock: make([]byte, cipherBS),
|
||||||
allZeroNonce: make([]byte, cc.IVLen),
|
allZeroNonce: make([]byte, cc.IVLen),
|
||||||
forceDecode: forceDecode,
|
forceDecode: forceDecode,
|
||||||
cWriteSize: cWriteSize,
|
cBlockPool: newBPool(int(cipherBS)),
|
||||||
|
CReqPool: newBPool(cReqSize),
|
||||||
|
pBlockPool: newBPool(int(plainBS)),
|
||||||
}
|
}
|
||||||
c.cBlockPool.New = func() interface{} { return make([]byte, cipherBS) }
|
|
||||||
c.cWritePool.New = func() interface{} { return make([]byte, cWriteSize) }
|
|
||||||
return c
|
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
|
// PlainBS returns the plaintext block size
|
||||||
func (be *ContentEnc) PlainBS() uint64 {
|
func (be *ContentEnc) PlainBS() uint64 {
|
||||||
return be.plainBS
|
return be.plainBS
|
||||||
|
@ -119,6 +111,7 @@ func (be *ContentEnc) DecryptBlocks(ciphertext []byte, firstBlockNo uint64, file
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pBuf.Write(pBlock)
|
pBuf.Write(pBlock)
|
||||||
|
be.pBlockPool.Put(pBlock)
|
||||||
firstBlockNo++
|
firstBlockNo++
|
||||||
}
|
}
|
||||||
return pBuf.Bytes(), err
|
return pBuf.Bytes(), err
|
||||||
|
@ -158,7 +151,8 @@ func (be *ContentEnc) DecryptBlock(ciphertext []byte, blockNo uint64, fileID []b
|
||||||
ciphertext = ciphertext[be.cryptoCore.IVLen:]
|
ciphertext = ciphertext[be.cryptoCore.IVLen:]
|
||||||
|
|
||||||
// Decrypt
|
// Decrypt
|
||||||
var plaintext []byte
|
plaintext := be.pBlockPool.Get()
|
||||||
|
plaintext = plaintext[:0]
|
||||||
aData := make([]byte, 8)
|
aData := make([]byte, 8)
|
||||||
aData = append(aData, fileID...)
|
aData = append(aData, fileID...)
|
||||||
binary.BigEndian.PutUint64(aData, blockNo)
|
binary.BigEndian.PutUint64(aData, blockNo)
|
||||||
|
@ -210,16 +204,12 @@ func (be *ContentEnc) EncryptBlocks(plaintextBlocks [][]byte, firstBlockNo uint6
|
||||||
be.doEncryptBlocks(plaintextBlocks, ciphertextBlocks, firstBlockNo, fileID)
|
be.doEncryptBlocks(plaintextBlocks, ciphertextBlocks, firstBlockNo, fileID)
|
||||||
}
|
}
|
||||||
// Concatenate ciphertext into a single byte array.
|
// Concatenate ciphertext into a single byte array.
|
||||||
tmp := be.cWritePool.Get().([]byte)
|
tmp := be.CReqPool.Get()
|
||||||
out := bytes.NewBuffer(tmp[:0])
|
out := bytes.NewBuffer(tmp[:0])
|
||||||
for _, v := range ciphertextBlocks {
|
for _, v := range ciphertextBlocks {
|
||||||
out.Write(v)
|
out.Write(v)
|
||||||
// Return the memory to cBlockPool
|
// Return the memory to cBlockPool
|
||||||
cBlock := v[:cap(v)]
|
be.cBlockPool.Put(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()
|
return out.Bytes()
|
||||||
}
|
}
|
||||||
|
@ -268,7 +258,7 @@ func (be *ContentEnc) doEncryptBlock(plaintext []byte, blockNo uint64, fileID []
|
||||||
aData = append(aData, fileID...)
|
aData = append(aData, fileID...)
|
||||||
// Get a cipherBS-sized block of memory, copy the nonce into it and truncate to
|
// Get a cipherBS-sized block of memory, copy the nonce into it and truncate to
|
||||||
// nonce length
|
// nonce length
|
||||||
cBlock := be.cBlockPool.Get().([]byte)
|
cBlock := be.cBlockPool.Get()
|
||||||
copy(cBlock, nonce)
|
copy(cBlock, nonce)
|
||||||
cBlock = cBlock[0:len(nonce)]
|
cBlock = cBlock[0:len(nonce)]
|
||||||
// Encrypt plaintext and append to nonce
|
// Encrypt plaintext and append to nonce
|
||||||
|
|
|
@ -311,8 +311,8 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {
|
||||||
}
|
}
|
||||||
// Write
|
// Write
|
||||||
_, err = f.fd.WriteAt(ciphertext, cOff)
|
_, err = f.fd.WriteAt(ciphertext, cOff)
|
||||||
// Return memory to cWritePool
|
// Return memory to CReqPool
|
||||||
f.fs.contentEnc.CWritePut(ciphertext)
|
f.fs.contentEnc.CReqPool.Put(ciphertext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tlog.Warn.Printf("doWrite: Write failed: %s", err.Error())
|
tlog.Warn.Printf("doWrite: Write failed: %s", err.Error())
|
||||||
return 0, fuse.ToStatus(err)
|
return 0, fuse.ToStatus(err)
|
||||||
|
|
Loading…
Reference in New Issue