diff --git a/internal/contentenc/content.go b/internal/contentenc/content.go index 493ec56..375221a 100644 --- a/internal/contentenc/content.go +++ b/internal/contentenc/content.go @@ -50,6 +50,7 @@ func (be *ContentEnc) CipherBS() uint64 { } // DecryptBlocks - Decrypt a number of blocks +// TODO refactor to three-param for func (be *ContentEnc) DecryptBlocks(ciphertext []byte, firstBlockNo uint64, fileId []byte) ([]byte, error) { cBuf := bytes.NewBuffer(ciphertext) var err error @@ -110,6 +111,19 @@ func (be *ContentEnc) DecryptBlock(ciphertext []byte, blockNo uint64, fileId []b 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 func (be *ContentEnc) EncryptBlock(plaintext []byte, blockNo uint64, fileID []byte) []byte { diff --git a/internal/contentenc/intrablock.go b/internal/contentenc/intrablock.go index 9a22ea2..632e76b 100644 --- a/internal/contentenc/intrablock.go +++ b/internal/contentenc/intrablock.go @@ -2,10 +2,19 @@ package contentenc // intraBlock identifies a part of a file block type intraBlock struct { - BlockNo uint64 // Block number in file - Skip uint64 // Offset into block plaintext - Length uint64 // Length of plaintext data in this block - fs *ContentEnc + // Block number in the file + BlockNo uint64 + // 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 } // isPartial - is the block partial? This means we have to do read-modify-write. @@ -47,3 +56,14 @@ func (ib *intraBlock) JointCiphertextRange(blocks []intraBlock) (offset uint64, 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 +} diff --git a/internal/contentenc/offsets.go b/internal/contentenc/offsets.go index 813a15f..e331d55 100644 --- a/internal/contentenc/offsets.go +++ b/internal/contentenc/offsets.go @@ -11,8 +11,11 @@ func (be *ContentEnc) PlainOffToBlockNo(plainOffset uint64) uint64 { 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 { + if cipherOffset < HEADER_LEN { + panic("BUG: offset is inside the file header") + } return (cipherOffset - HEADER_LEN) / be.cipherBS } @@ -89,6 +92,32 @@ func (be *ContentEnc) ExplodePlainRange(offset uint64, length uint64) []intraBlo 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 { return be.cipherBS - be.plainBS }