diff options
author | Jakob Unterwurzacher | 2015-11-01 12:11:36 +0100 |
---|---|---|
committer | Jakob Unterwurzacher | 2015-11-01 12:11:36 +0100 |
commit | 902babdf22199d73171716e643f1ffbb65e6fb48 (patch) | |
tree | c3194bce9fd9b4db0a569fca3b5041abd278be70 /cryptfs | |
parent | 14276c96328a1a1ad2b354c65d8db7fa720559e1 (diff) |
Refactor ciphertext <-> plaintext offset translation functions
Move all the intelligence into the new file address_translation.go.
That the calculations were spread out too much became apparent when adding
the file header. This should make the code much easier to modify in the
future.
Diffstat (limited to 'cryptfs')
-rw-r--r-- | cryptfs/address_translation.go | 79 | ||||
-rw-r--r-- | cryptfs/config_file.go | 2 | ||||
-rw-r--r-- | cryptfs/content_test.go | 22 | ||||
-rw-r--r-- | cryptfs/cryptfs.go | 7 | ||||
-rw-r--r-- | cryptfs/cryptfs_content.go | 115 | ||||
-rw-r--r-- | cryptfs/file_header.go | 10 | ||||
-rw-r--r-- | cryptfs/intrablock.go | 16 |
7 files changed, 113 insertions, 138 deletions
diff --git a/cryptfs/address_translation.go b/cryptfs/address_translation.go new file mode 100644 index 0000000..dfc6ef9 --- /dev/null +++ b/cryptfs/address_translation.go @@ -0,0 +1,79 @@ +package cryptfs + +// CryptFS methods that translate offsets between ciphertext and plaintext + +// get the block number at plain-text offset +func (be *CryptFS) PlainOffToBlockNo(plainOffset uint64) uint64 { + return plainOffset / be.plainBS +} + +// get the block number at ciphter-text offset +func (be *CryptFS) CipherOffToBlockNo(cipherOffset uint64) uint64 { + return (cipherOffset - HEADER_LEN) / be.cipherBS +} + +// get ciphertext offset of block "blockNo" +func (be *CryptFS) BlockNoToCipherOff(blockNo uint64) uint64 { + return HEADER_LEN + blockNo*be.cipherBS +} + +// get plaintext offset of block "blockNo" +func (be *CryptFS) BlockNoToPlainOff(blockNo uint64) uint64 { + return blockNo * be.plainBS +} + +// PlainSize - calculate plaintext size from ciphertext size +func (be *CryptFS) CipherSizeToPlainSize(cipherSize uint64) uint64 { + + // Zero sized files stay zero-sized + if cipherSize == 0 { + return 0 + } + + // Block number at last byte + blockNo := be.CipherOffToBlockNo(cipherSize - 1) + blockCount := blockNo + 1 + + overhead := BLOCK_OVERHEAD*blockCount + HEADER_LEN + + return cipherSize - overhead +} + +// CipherSize - calculate ciphertext size from plaintext size +func (be *CryptFS) PlainSizeToCipherSize(plainSize uint64) uint64 { + + // Block number at last byte + blockNo := be.PlainOffToBlockNo(plainSize - 1) + blockCount := blockNo + 1 + + overhead := BLOCK_OVERHEAD*blockCount + HEADER_LEN + + return plainSize + overhead +} + +// Split a plaintext byte range into (possibly partial) blocks +func (be *CryptFS) ExplodePlainRange(offset uint64, length uint64) []intraBlock { + var blocks []intraBlock + var nextBlock intraBlock + nextBlock.fs = be + + for length > 0 { + nextBlock.BlockNo = be.PlainOffToBlockNo(offset) + nextBlock.Skip = offset - be.BlockNoToPlainOff(nextBlock.BlockNo) + + // Minimum of remaining data and remaining space in the block + nextBlock.Length = MinUint64(length, be.plainBS-nextBlock.Skip) + + blocks = append(blocks, nextBlock) + offset += nextBlock.Length + length -= nextBlock.Length + } + return blocks +} + +func MinUint64(x uint64, y uint64) uint64 { + if x < y { + return x + } + return y +} diff --git a/cryptfs/config_file.go b/cryptfs/config_file.go index 7e762ad..16a3eec 100644 --- a/cryptfs/config_file.go +++ b/cryptfs/config_file.go @@ -1,8 +1,8 @@ package cryptfs import ( - "fmt" "encoding/json" + "fmt" "io/ioutil" ) import "os" diff --git a/cryptfs/content_test.go b/cryptfs/content_test.go index 4e1b447..37635f0 100644 --- a/cryptfs/content_test.go +++ b/cryptfs/content_test.go @@ -16,7 +16,7 @@ func TestSplitRange(t *testing.T) { testRange{0, 10}, testRange{234, 6511}, testRange{65444, 54}, - testRange{0, 1024*1024}, + testRange{0, 1024 * 1024}, testRange{0, 65536}, testRange{6654, 8945}) @@ -24,8 +24,8 @@ func TestSplitRange(t *testing.T) { f := NewCryptFS(key, true) for _, r := range ranges { - parts := f.SplitRange(r.offset, r.length) - var lastBlockNo uint64 = 1<<63 + parts := f.ExplodePlainRange(r.offset, r.length) + var lastBlockNo uint64 = 1 << 63 for _, p := range parts { if p.BlockNo == lastBlockNo { t.Errorf("Duplicate block number %d", p.BlockNo) @@ -51,11 +51,15 @@ func TestCiphertextRange(t *testing.T) { f := NewCryptFS(key, true) for _, r := range ranges { - alignedOffset, alignedLength, skipBytes := f.CiphertextRange(r.offset, r.length) + + blocks := f.ExplodePlainRange(r.offset, r.length) + alignedOffset, alignedLength := blocks[0].JointCiphertextRange(blocks) + skipBytes := blocks[0].Skip + if alignedLength < r.length { t.Errorf("alignedLength=%s is smaller than length=%d", alignedLength, r.length) } - if (alignedOffset - HEADER_LEN)%f.cipherBS != 0 { + if (alignedOffset-HEADER_LEN)%f.cipherBS != 0 { t.Errorf("alignedOffset=%d is not aligned", alignedOffset) } if r.offset%f.plainBS != 0 && skipBytes == 0 { @@ -68,19 +72,19 @@ func TestBlockNo(t *testing.T) { key := make([]byte, KEY_LEN) f := NewCryptFS(key, true) - b := f.BlockNoCipherOff(788) + b := f.CipherOffToBlockNo(788) if b != 0 { t.Errorf("actual: %d", b) } - b = f.BlockNoCipherOff(HEADER_LEN + f.CipherBS()) + b = f.CipherOffToBlockNo(HEADER_LEN + f.cipherBS) if b != 1 { t.Errorf("actual: %d", b) } - b = f.BlockNoPlainOff(788) + b = f.PlainOffToBlockNo(788) if b != 0 { t.Errorf("actual: %d", b) } - b = f.BlockNoPlainOff(f.PlainBS()) + b = f.PlainOffToBlockNo(f.plainBS) if b != 1 { t.Errorf("actual: %d", b) } diff --git a/cryptfs/cryptfs.go b/cryptfs/cryptfs.go index 0593214..9fe492d 100644 --- a/cryptfs/cryptfs.go +++ b/cryptfs/cryptfs.go @@ -13,7 +13,7 @@ const ( KEY_LEN = 32 // AES-256 NONCE_LEN = 12 AUTH_TAG_LEN = 16 - BLOCK_OVERHEAD = NONCE_LEN + AUTH_TAG_LEN + BLOCK_OVERHEAD = NONCE_LEN + AUTH_TAG_LEN ) type CryptFS struct { @@ -61,8 +61,3 @@ func NewCryptFS(key []byte, useOpenssl bool) *CryptFS { func (be *CryptFS) PlainBS() uint64 { return be.plainBS } - -// Get ciphertext block size -func (be *CryptFS) CipherBS() uint64 { - return be.cipherBS -} diff --git a/cryptfs/cryptfs_content.go b/cryptfs/cryptfs_content.go index 03253d3..d74570f 100644 --- a/cryptfs/cryptfs_content.go +++ b/cryptfs/cryptfs_content.go @@ -12,11 +12,6 @@ import ( "os" ) -const ( - // A block of 4124 zero bytes has this md5 - ZeroBlockMd5 = "64331af89bd15a987b39855338336237" -) - // md5sum - debug helper, return md5 hex string func md5sum(buf []byte) string { rawHash := md5.Sum(buf) @@ -110,106 +105,6 @@ func (be *CryptFS) EncryptBlock(plaintext []byte, blockNo uint64, fileId []byte) return ciphertext } -// Split a plaintext byte range into (possibly partial) blocks -func (be *CryptFS) SplitRange(offset uint64, length uint64) []intraBlock { - var b intraBlock - var parts []intraBlock - - b.fs = be - - for length > 0 { - b.BlockNo = offset / be.plainBS - b.Skip = offset % be.plainBS - // Minimum of remaining data and remaining space in the block - b.Length = be.minu64(length, be.plainBS-b.Skip) - parts = append(parts, b) - offset += b.Length - length -= b.Length - } - return parts -} - -// PlainSize - calculate plaintext size from ciphertext size -func (be *CryptFS) PlainSize(size uint64) uint64 { - - // Zero sized files stay zero-sized - if size == 0 { - return 0 - } - - // Account for header - size -= HEADER_LEN - - overhead := be.cipherBS - be.plainBS - nBlocks := (size + be.cipherBS - 1) / be.cipherBS - if nBlocks*overhead > size { - Warn.Printf("PlainSize: Negative size, returning 0 instead\n") - return 0 - } - size -= nBlocks * overhead - - return size -} - -// CipherSize - calculate ciphertext size from plaintext size -func (be *CryptFS) CipherSize(size uint64) uint64 { - overhead := be.cipherBS - be.plainBS - nBlocks := (size + be.plainBS - 1) / be.plainBS - size += nBlocks * overhead - - return size -} - -func (be *CryptFS) minu64(x uint64, y uint64) uint64 { - if x < y { - return x - } - return y -} - -// CiphertextRange - Get byte range in backing ciphertext corresponding -// to plaintext range. Returns a range aligned to ciphertext blocks. -func (be *CryptFS) CiphertextRange(offset uint64, length uint64) (alignedOffset uint64, alignedLength uint64, skipBytes int) { - // Decrypting the ciphertext will yield too many plaintext bytes. Skip this number - // of bytes from the front. - skip := offset % be.plainBS - - firstBlockNo := offset / be.plainBS - lastBlockNo := (offset + length - 1) / be.plainBS - - alignedOffset = HEADER_LEN + firstBlockNo * be.cipherBS - alignedLength = (lastBlockNo - firstBlockNo + 1) * be.cipherBS - - skipBytes = int(skip) - return alignedOffset, alignedLength, skipBytes -} - -// Get the byte range in the ciphertext corresponding to blocks -// (full blocks!) -func (be *CryptFS) JoinCiphertextRange(blocks []intraBlock) (uint64, uint64) { - - offset, _ := blocks[0].CiphertextRange() - last := blocks[len(blocks)-1] - length := (last.BlockNo - blocks[0].BlockNo + 1) * be.cipherBS - - return offset, length -} - -// Crop plaintext that correspons to complete cipher blocks down to what is -// requested according to "iblocks" -func (be *CryptFS) CropPlaintext(plaintext []byte, blocks []intraBlock) []byte { - offset := blocks[0].Skip - last := blocks[len(blocks)-1] - length := (last.BlockNo - blocks[0].BlockNo + 1) * be.plainBS - var cropped []byte - if offset+length > uint64(len(plaintext)) { - cropped = plaintext[offset:] - } else { - cropped = plaintext[offset : offset+length] - } - return cropped -} - // MergeBlocks - Merge newData into oldData at offset // New block may be bigger than both newData and oldData func (be *CryptFS) MergeBlocks(oldData []byte, newData []byte, offset int) []byte { @@ -230,13 +125,3 @@ func (be *CryptFS) MergeBlocks(oldData []byte, newData []byte, offset int) []byt } return out[0:outLen] } - -// Get the block number at plain-text offset -func (be *CryptFS) BlockNoPlainOff(plainOffset uint64) uint64 { - return plainOffset / be.plainBS -} - -// Get the block number at ciphter-text offset -func (be *CryptFS) BlockNoCipherOff(cipherOffset uint64) uint64 { - return (cipherOffset - HEADER_LEN) / be.cipherBS -} diff --git a/cryptfs/file_header.go b/cryptfs/file_header.go index 3fd7266..e16cbab 100644 --- a/cryptfs/file_header.go +++ b/cryptfs/file_header.go @@ -10,15 +10,15 @@ import ( ) const ( - HEADER_CURRENT_VERSION = 1 // Current on-disk-format version - HEADER_VERSION_LEN = 2 // uint16 - HEADER_ID_LEN = 16 // 128 bit random file id - HEADER_LEN = HEADER_VERSION_LEN + HEADER_ID_LEN // Total header length + HEADER_CURRENT_VERSION = 1 // Current on-disk-format version + HEADER_VERSION_LEN = 2 // uint16 + HEADER_ID_LEN = 16 // 128 bit random file id + HEADER_LEN = HEADER_VERSION_LEN + HEADER_ID_LEN // Total header length ) type FileHeader struct { Version uint16 - Id []byte + Id []byte } // Pack - serialize fileHeader object diff --git a/cryptfs/intrablock.go b/cryptfs/intrablock.go index c83976c..faff471 100644 --- a/cryptfs/intrablock.go +++ b/cryptfs/intrablock.go @@ -19,13 +19,13 @@ func (ib *intraBlock) IsPartial() bool { // CiphertextRange - get byte range in ciphertext file corresponding to BlockNo // (complete block) func (ib *intraBlock) CiphertextRange() (offset uint64, length uint64) { - return HEADER_LEN + ib.BlockNo * ib.fs.cipherBS, ib.fs.cipherBS + return ib.fs.BlockNoToCipherOff(ib.BlockNo), ib.fs.cipherBS } // PlaintextRange - get byte range in plaintext corresponding to BlockNo // (complete block) func (ib *intraBlock) PlaintextRange() (offset uint64, length uint64) { - return ib.BlockNo * ib.fs.plainBS, ib.fs.plainBS + return ib.fs.BlockNoToPlainOff(ib.BlockNo), ib.fs.plainBS } // CropBlock - crop a potentially larger plaintext block down to the relevant part @@ -37,3 +37,15 @@ func (ib *intraBlock) CropBlock(d []byte) []byte { } return d[ib.Skip:lenWant] } + +// Ciphertext range corresponding to the sum of all "blocks" (complete blocks) +func (ib *intraBlock) JointCiphertextRange(blocks []intraBlock) (offset uint64, length uint64) { + firstBlock := blocks[0] + lastBlock := blocks[len(blocks)-1] + + offset = ib.fs.BlockNoToCipherOff(firstBlock.BlockNo) + offsetLast := ib.fs.BlockNoToCipherOff(lastBlock.BlockNo) + length = offsetLast + ib.fs.cipherBS - offset + + return offset, length +} |