diff options
Diffstat (limited to 'internal/contentenc')
| -rw-r--r-- | internal/contentenc/content.go | 27 | ||||
| -rw-r--r-- | internal/contentenc/content_test.go | 4 | ||||
| -rw-r--r-- | internal/contentenc/file_header.go | 30 | ||||
| -rw-r--r-- | internal/contentenc/intrablock.go | 28 | ||||
| -rw-r--r-- | internal/contentenc/offsets.go | 48 | 
5 files changed, 75 insertions, 62 deletions
| diff --git a/internal/contentenc/content.go b/internal/contentenc/content.go index ac2e8de..dd3b77a 100644 --- a/internal/contentenc/content.go +++ b/internal/contentenc/content.go @@ -11,21 +11,28 @@ import (  	"github.com/rfjakob/gocryptfs/internal/tlog"  ) +// NonceMode determines how nonces are created.  type NonceMode int  const ( -	// Default plaintext block size +	// DefaultBS is the default plaintext block size  	DefaultBS = 4096 +	// DefaultIVBits is the default length of IV, in bits.  	// We always use 128-bit IVs for file content, but the  	// key in the config file is encrypted with a 96-bit IV.  	DefaultIVBits = 128 -	_                                   = iota // skip zero -	RandomNonce               NonceMode = iota +	_ = iota // skip zero +	// RandomNonce chooses a random nonce. +	RandomNonce NonceMode = iota +	// ReverseDeterministicNonce chooses a deterministic nonce, suitable for +	// use in reverse mode.  	ReverseDeterministicNonce NonceMode = iota -	ExternalNonce             NonceMode = iota +	// ExternalNonce derives a nonce from external sources. +	ExternalNonce NonceMode = iota  ) +// ContentEnc is used to encipher and decipher file content.  type ContentEnc struct {  	// Cryptographic primitives  	cryptoCore *cryptocore.CryptoCore @@ -39,8 +46,8 @@ type ContentEnc struct {  	allZeroNonce []byte  } +// New returns an initialized ContentEnc instance.  func New(cc *cryptocore.CryptoCore, plainBS uint64) *ContentEnc { -  	cipherBS := plainBS + uint64(cc.IVLen) + cryptocore.AuthTagLen  	return &ContentEnc{ @@ -62,16 +69,16 @@ func (be *ContentEnc) CipherBS() uint64 {  	return be.cipherBS  } -// DecryptBlocks - Decrypt a number of blocks +// DecryptBlocks decrypts 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)  	var err error  	var pBuf bytes.Buffer  	for cBuf.Len() > 0 {  		cBlock := cBuf.Next(int(be.cipherBS))  		var pBlock []byte -		pBlock, err = be.DecryptBlock(cBlock, firstBlockNo, fileId) +		pBlock, err = be.DecryptBlock(cBlock, firstBlockNo, fileID)  		if err != nil {  			break  		} @@ -85,7 +92,7 @@ func (be *ContentEnc) DecryptBlocks(ciphertext []byte, firstBlockNo uint64, file  //  // Corner case: A full-sized block of all-zero ciphertext bytes is translated  // to an all-zero plaintext block, i.e. file hole passtrough. -func (be *ContentEnc) DecryptBlock(ciphertext []byte, blockNo uint64, fileId []byte) ([]byte, error) { +func (be *ContentEnc) DecryptBlock(ciphertext []byte, blockNo uint64, fileID []byte) ([]byte, error) {  	// Empty block?  	if len(ciphertext) == 0 { @@ -114,7 +121,7 @@ func (be *ContentEnc) DecryptBlock(ciphertext []byte, blockNo uint64, fileId []b  	// Decrypt  	var plaintext []byte  	aData := make([]byte, 8) -	aData = append(aData, fileId...) +	aData = append(aData, fileID...)  	binary.BigEndian.PutUint64(aData, blockNo)  	plaintext, err := be.cryptoCore.AEADCipher.Open(plaintext, nonce, ciphertext, aData) diff --git a/internal/contentenc/content_test.go b/internal/contentenc/content_test.go index 70b71fe..e6c610c 100644 --- a/internal/contentenc/content_test.go +++ b/internal/contentenc/content_test.go @@ -63,7 +63,7 @@ func TestCiphertextRange(t *testing.T) {  		if alignedLength < r.length {  			t.Errorf("alignedLength=%d is smaller than length=%d", alignedLength, r.length)  		} -		if (alignedOffset-HEADER_LEN)%f.cipherBS != 0 { +		if (alignedOffset-HeaderLen)%f.cipherBS != 0 {  			t.Errorf("alignedOffset=%d is not aligned", alignedOffset)  		}  		if r.offset%f.plainBS != 0 && skipBytes == 0 { @@ -81,7 +81,7 @@ func TestBlockNo(t *testing.T) {  	if b != 0 {  		t.Errorf("actual: %d", b)  	} -	b = f.CipherOffToBlockNo(HEADER_LEN + f.cipherBS) +	b = f.CipherOffToBlockNo(HeaderLen + f.cipherBS)  	if b != 1 {  		t.Errorf("actual: %d", b)  	} diff --git a/internal/contentenc/file_header.go b/internal/contentenc/file_header.go index 1463773..9ae5ae9 100644 --- a/internal/contentenc/file_header.go +++ b/internal/contentenc/file_header.go @@ -12,42 +12,44 @@ import (  )  const ( -	// Current On-Disk-Format version +	// CurrentVersion is the current On-Disk-Format version  	CurrentVersion = 2 -	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 +	headerVersionLen = 2  // uint16 +	headerIDLen      = 16 // 128 bit random file id +	// HeaderLen is the total header length +	HeaderLen = headerVersionLen + headerIDLen  ) +// FileHeader represents the header stored on each non-empty file.  type FileHeader struct {  	Version uint16 -	Id      []byte +	ID      []byte  }  // Pack - serialize fileHeader object  func (h *FileHeader) Pack() []byte { -	if len(h.Id) != HEADER_ID_LEN || h.Version != CurrentVersion { +	if len(h.ID) != headerIDLen || h.Version != CurrentVersion {  		panic("FileHeader object not properly initialized")  	} -	buf := make([]byte, HEADER_LEN) -	binary.BigEndian.PutUint16(buf[0:HEADER_VERSION_LEN], h.Version) -	copy(buf[HEADER_VERSION_LEN:], h.Id) +	buf := make([]byte, HeaderLen) +	binary.BigEndian.PutUint16(buf[0:headerVersionLen], h.Version) +	copy(buf[headerVersionLen:], h.ID)  	return buf  }  // ParseHeader - parse "buf" into fileHeader object  func ParseHeader(buf []byte) (*FileHeader, error) { -	if len(buf) != HEADER_LEN { -		return nil, fmt.Errorf("ParseHeader: invalid length: got %d, want %d", len(buf), HEADER_LEN) +	if len(buf) != HeaderLen { +		return nil, fmt.Errorf("ParseHeader: invalid length: got %d, want %d", len(buf), HeaderLen)  	}  	var h FileHeader -	h.Version = binary.BigEndian.Uint16(buf[0:HEADER_VERSION_LEN]) +	h.Version = binary.BigEndian.Uint16(buf[0:headerVersionLen])  	if h.Version != CurrentVersion {  		return nil, fmt.Errorf("ParseHeader: invalid version: got %d, want %d", h.Version, CurrentVersion)  	} -	h.Id = buf[HEADER_VERSION_LEN:] +	h.ID = buf[headerVersionLen:]  	return &h, nil  } @@ -55,6 +57,6 @@ func ParseHeader(buf []byte) (*FileHeader, error) {  func RandomHeader() *FileHeader {  	var h FileHeader  	h.Version = CurrentVersion -	h.Id = cryptocore.RandBytes(HEADER_ID_LEN) +	h.ID = cryptocore.RandBytes(headerIDLen)  	return &h  } diff --git a/internal/contentenc/intrablock.go b/internal/contentenc/intrablock.go index 632e76b..3714e37 100644 --- a/internal/contentenc/intrablock.go +++ b/internal/contentenc/intrablock.go @@ -1,10 +1,10 @@  package contentenc -// intraBlock identifies a part of a file block -type intraBlock struct { -	// Block number in the file +// IntraBlock identifies a part of a file block +type IntraBlock struct { +	// BlockNo is the block number in the file  	BlockNo uint64 -	// Offset into block payload +	// Skip is an offset into the block payload  	// In forwared mode: block plaintext  	// In reverse mode: offset into block ciphertext. Takes the header into  	// account. @@ -17,8 +17,8 @@ type intraBlock struct {  	fs     *ContentEnc  } -// isPartial - is the block partial? This means we have to do read-modify-write. -func (ib *intraBlock) IsPartial() bool { +// IsPartial - is the block partial? This means we have to do read-modify-write. +func (ib *IntraBlock) IsPartial() bool {  	if ib.Skip > 0 || ib.Length < ib.fs.plainBS {  		return true  	} @@ -26,17 +26,17 @@ func (ib *intraBlock) IsPartial() bool {  }  // BlockCipherOff returns the ciphertext offset corresponding to BlockNo -func (ib *intraBlock) BlockCipherOff() (offset uint64) { +func (ib *IntraBlock) BlockCipherOff() (offset uint64) {  	return ib.fs.BlockNoToCipherOff(ib.BlockNo)  }  // BlockPlainOff returns the plaintext offset corresponding to BlockNo -func (ib *intraBlock) BlockPlainOff() (offset uint64) { +func (ib *IntraBlock) BlockPlainOff() (offset uint64) {  	return ib.fs.BlockNoToPlainOff(ib.BlockNo)  }  // CropBlock - crop a potentially larger plaintext block down to the relevant part -func (ib *intraBlock) CropBlock(d []byte) []byte { +func (ib *IntraBlock) CropBlock(d []byte) []byte {  	lenHave := len(d)  	lenWant := int(ib.Skip + ib.Length)  	if lenHave < lenWant { @@ -45,8 +45,9 @@ 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) { +// JointCiphertextRange is the 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] @@ -57,8 +58,9 @@ 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) { +// JointPlaintextRange is the 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] diff --git a/internal/contentenc/offsets.go b/internal/contentenc/offsets.go index 61939a9..97d7116 100644 --- a/internal/contentenc/offsets.go +++ b/internal/contentenc/offsets.go @@ -8,43 +8,43 @@ import (  // Contentenc methods that translate offsets between ciphertext and plaintext -// get the block number at plain-text offset +// PlainOffToBlockNo converts a plaintext offset to the ciphertext block number.  func (be *ContentEnc) PlainOffToBlockNo(plainOffset uint64) uint64 {  	return plainOffset / be.plainBS  } -// get the block number at cipher-text offset +// CipherOffToBlockNo converts the ciphertext offset to the plaintext block number.  func (be *ContentEnc) CipherOffToBlockNo(cipherOffset uint64) uint64 { -	if cipherOffset < HEADER_LEN { +	if cipherOffset < HeaderLen {  		log.Panicf("BUG: offset %d is inside the file header", cipherOffset)  	} -	return (cipherOffset - HEADER_LEN) / be.cipherBS +	return (cipherOffset - HeaderLen) / be.cipherBS  } -// get ciphertext offset of block "blockNo" +// BlockNoToCipherOff gets the ciphertext offset of block "blockNo"  func (be *ContentEnc) BlockNoToCipherOff(blockNo uint64) uint64 { -	return HEADER_LEN + blockNo*be.cipherBS +	return HeaderLen + blockNo*be.cipherBS  } -// get plaintext offset of block "blockNo" +// BlockNoToPlainOff gets the plaintext offset of block "blockNo"  func (be *ContentEnc) BlockNoToPlainOff(blockNo uint64) uint64 {  	return blockNo * be.plainBS  } -// PlainSize - calculate plaintext size from ciphertext size +// CipherSizeToPlainSize calculates the plaintext size from a ciphertext size  func (be *ContentEnc) CipherSizeToPlainSize(cipherSize uint64) uint64 {  	// Zero-sized files stay zero-sized  	if cipherSize == 0 {  		return 0  	} -	if cipherSize == HEADER_LEN { +	if cipherSize == HeaderLen {  		tlog.Warn.Printf("cipherSize %d == header size: interrupted write?\n", cipherSize)  		return 0  	} -	if cipherSize < HEADER_LEN { -		tlog.Warn.Printf("cipherSize %d < header size %d: corrupt file\n", cipherSize, HEADER_LEN) +	if cipherSize < HeaderLen { +		tlog.Warn.Printf("cipherSize %d < header size %d: corrupt file\n", cipherSize, HeaderLen)  		return 0  	} @@ -52,12 +52,12 @@ func (be *ContentEnc) CipherSizeToPlainSize(cipherSize uint64) uint64 {  	blockNo := be.CipherOffToBlockNo(cipherSize - 1)  	blockCount := blockNo + 1 -	overhead := be.BlockOverhead()*blockCount + HEADER_LEN +	overhead := be.BlockOverhead()*blockCount + HeaderLen  	return cipherSize - overhead  } -// CipherSize - calculate ciphertext size from plaintext size +// PlainSizeToCipherSize calculates the ciphertext size from a plaintext size  func (be *ContentEnc) PlainSizeToCipherSize(plainSize uint64) uint64 {  	// Zero-sized files stay zero-sized  	if plainSize == 0 { @@ -68,16 +68,16 @@ func (be *ContentEnc) PlainSizeToCipherSize(plainSize uint64) uint64 {  	blockNo := be.PlainOffToBlockNo(plainSize - 1)  	blockCount := blockNo + 1 -	overhead := be.BlockOverhead()*blockCount + HEADER_LEN +	overhead := be.BlockOverhead()*blockCount + HeaderLen  	return plainSize + overhead  } -// Split a plaintext byte range into (possibly partial) blocks +// ExplodePlainRange splits a plaintext byte range into (possibly partial) blocks  // Returns an empty slice if length == 0. -func (be *ContentEnc) ExplodePlainRange(offset uint64, length uint64) []intraBlock { -	var blocks []intraBlock -	var nextBlock intraBlock +func (be *ContentEnc) ExplodePlainRange(offset uint64, length uint64) []IntraBlock { +	var blocks []IntraBlock +	var nextBlock IntraBlock  	nextBlock.fs = be  	for length > 0 { @@ -94,11 +94,11 @@ 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 +// ExplodeCipherRange splits 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 { @@ -120,10 +120,12 @@ func (be *ContentEnc) ExplodeCipherRange(offset uint64, length uint64) []intraBl  	return blocks  } +// BlockOverhead returns the per-block overhead.  func (be *ContentEnc) BlockOverhead() uint64 {  	return be.cipherBS - be.plainBS  } +// MinUint64 returns the minimum of two uint64 values.  func MinUint64(x uint64, y uint64) uint64 {  	if x < y {  		return x | 
