diff options
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 +} |