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