aboutsummaryrefslogtreecommitdiff
path: root/internal/contentenc
diff options
context:
space:
mode:
Diffstat (limited to 'internal/contentenc')
-rw-r--r--internal/contentenc/content.go27
-rw-r--r--internal/contentenc/content_test.go4
-rw-r--r--internal/contentenc/file_header.go30
-rw-r--r--internal/contentenc/intrablock.go28
-rw-r--r--internal/contentenc/offsets.go48
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