contentenc: add helpers for reverse mode

Add the reverse variant of DecryptBlocks etc:

* EncryptBlocks
* JointPlaintextRange
* ExplodeCipherRange
This commit is contained in:
Jakob Unterwurzacher 2016-08-30 00:20:31 +02:00
parent 1d4c6288f2
commit 5931eea387
3 changed files with 68 additions and 5 deletions

View File

@ -50,6 +50,7 @@ func (be *ContentEnc) CipherBS() uint64 {
} }
// DecryptBlocks - Decrypt a number of blocks // DecryptBlocks - Decrypt a number of blocks
// TODO refactor to three-param for
func (be *ContentEnc) DecryptBlocks(ciphertext []byte, firstBlockNo uint64, fileId []byte) ([]byte, error) { func (be *ContentEnc) DecryptBlocks(ciphertext []byte, firstBlockNo uint64, fileId []byte) ([]byte, error) {
cBuf := bytes.NewBuffer(ciphertext) cBuf := bytes.NewBuffer(ciphertext)
var err error var err error
@ -110,6 +111,19 @@ func (be *ContentEnc) DecryptBlock(ciphertext []byte, blockNo uint64, fileId []b
return plaintext, nil return plaintext, nil
} }
// EncryptBlocks - Encrypt a number of blocks
// Used for reverse mode
func (be *ContentEnc) EncryptBlocks(plaintext []byte, firstBlockNo uint64, fileId []byte) []byte {
inBuf := bytes.NewBuffer(plaintext)
var outBuf bytes.Buffer
for blockNo := firstBlockNo; inBuf.Len() > 0; blockNo++ {
inBlock := inBuf.Next(int(be.plainBS))
outBlock := be.EncryptBlock(inBlock, blockNo, fileId)
outBuf.Write(outBlock)
}
return outBuf.Bytes()
}
// encryptBlock - Encrypt and add IV and MAC // encryptBlock - Encrypt and add IV and MAC
func (be *ContentEnc) EncryptBlock(plaintext []byte, blockNo uint64, fileID []byte) []byte { func (be *ContentEnc) EncryptBlock(plaintext []byte, blockNo uint64, fileID []byte) []byte {

View File

@ -2,9 +2,18 @@ package contentenc
// intraBlock identifies a part of a file block // intraBlock identifies a part of a file block
type intraBlock struct { type intraBlock struct {
BlockNo uint64 // Block number in file // Block number in the file
Skip uint64 // Offset into block plaintext BlockNo uint64
Length uint64 // Length of plaintext data in this block // Offset into block payload
// In forwared mode: block plaintext
// In reverse mode: offset into block ciphertext. Takes the header into
// account.
Skip uint64
// Length of payload data in this block
// In forwared mode: length of the plaintext
// In reverse mode: length of the ciphertext. Takes header and trailer into
// account.
Length uint64
fs *ContentEnc fs *ContentEnc
} }
@ -47,3 +56,14 @@ func (ib *intraBlock) JointCiphertextRange(blocks []intraBlock) (offset uint64,
return offset, length return offset, length
} }
// Plaintext range corresponding to the sum of all "blocks" (complete blocks)
func JointPlaintextRange(blocks []intraBlock) (offset uint64, length uint64) {
firstBlock := blocks[0]
lastBlock := blocks[len(blocks)-1]
offset = firstBlock.BlockPlainOff()
length = lastBlock.BlockPlainOff() + lastBlock.fs.PlainBS() - offset
return offset, length
}

View File

@ -11,8 +11,11 @@ func (be *ContentEnc) PlainOffToBlockNo(plainOffset uint64) uint64 {
return plainOffset / be.plainBS return plainOffset / be.plainBS
} }
// get the block number at ciphter-text offset // get the block number at cipher-text offset
func (be *ContentEnc) CipherOffToBlockNo(cipherOffset uint64) uint64 { func (be *ContentEnc) CipherOffToBlockNo(cipherOffset uint64) uint64 {
if cipherOffset < HEADER_LEN {
panic("BUG: offset is inside the file header")
}
return (cipherOffset - HEADER_LEN) / be.cipherBS return (cipherOffset - HEADER_LEN) / be.cipherBS
} }
@ -89,6 +92,32 @@ func (be *ContentEnc) ExplodePlainRange(offset uint64, length uint64) []intraBlo
return blocks return blocks
} }
// Split a ciphertext byte range into (possibly partial) blocks
// This is used in reverse mode when reading files
func (be *ContentEnc) ExplodeCipherRange(offset uint64, length uint64) []intraBlock {
var blocks []intraBlock
var nextBlock intraBlock
nextBlock.fs = be
for length > 0 {
nextBlock.BlockNo = be.CipherOffToBlockNo(offset)
nextBlock.Skip = offset - be.BlockNoToCipherOff(nextBlock.BlockNo)
// This block can carry up to "maxLen" payload bytes
maxLen := be.cipherBS - nextBlock.Skip
nextBlock.Length = maxLen
// But if the user requested less, we truncate the block to "length".
if length < maxLen {
nextBlock.Length = length
}
blocks = append(blocks, nextBlock)
offset += nextBlock.Length
length -= nextBlock.Length
}
return blocks
}
func (be *ContentEnc) BlockOverhead() uint64 { func (be *ContentEnc) BlockOverhead() uint64 {
return be.cipherBS - be.plainBS return be.cipherBS - be.plainBS
} }