diff --git a/backend.go b/backend.go deleted file mode 100644 index ad80b9a..0000000 --- a/backend.go +++ /dev/null @@ -1,42 +0,0 @@ -package gocryptfs - -import ( - "crypto/cipher" - "crypto/aes" -) - -const ( - NONCE_LEN = 12 - AUTH_TAG_LEN = 16 - DEFAULT_PLAINBS = 4096 - - ENCRYPT = true - DECRYPT = false -) - -type Backend struct { - blockCipher cipher.Block - gcm cipher.AEAD - plainBS int64 - cipherBS int64 -} - -func New(key [16]byte) *Backend { - - b, err := aes.NewCipher(key[:]) - if err != nil { - panic(err) - } - - g, err := cipher.NewGCM(b) - if err != nil { - panic(err) - } - - return &Backend{ - blockCipher: b, - gcm: g, - plainBS: DEFAULT_PLAINBS, - cipherBS: DEFAULT_PLAINBS + NONCE_LEN + AUTH_TAG_LEN, - } -} diff --git a/backend_content.go b/cryptfs/file.go similarity index 81% rename from backend_content.go rename to cryptfs/file.go index 3cf2a87..77262d4 100644 --- a/backend_content.go +++ b/cryptfs/file.go @@ -1,19 +1,27 @@ -package gocryptfs +package cryptfs import ( "fmt" "os" "io" "errors" + "crypto/cipher" ) +type File struct { + file *os.File + gcm cipher.AEAD + plainBS int64 + cipherBS int64 +} + // readCipherBlock - Read ciphertext block number "blockNo", decrypt, // return plaintext -func (be *Backend) readCipherBlock(blockNo int64, f *os.File) ([]byte, error) { +func (be *File) readCipherBlock(blockNo int64) ([]byte, error) { off := blockNo * int64(be.cipherBS) buf := make([]byte, be.cipherBS) - readN, err := f.ReadAt(buf, off) + readN, err := be.file.ReadAt(buf, off) if err != nil && err != io.EOF { return nil, err @@ -56,7 +64,7 @@ type intraBlock struct { } // Split a plaintext byte range into (possible partial) blocks -func (be *Backend) splitRange(offset int64, length int64, f *os.File) []intraBlock { +func (be *File) splitRange(offset int64, length int64) []intraBlock { var b intraBlock var parts []intraBlock @@ -71,7 +79,7 @@ func (be *Backend) splitRange(offset int64, length int64, f *os.File) []intraBlo return parts } -func (be *Backend) min64(x int64, y int64) int64 { +func (be *File) min64(x int64, y int64) int64 { if x < y { return x } @@ -79,7 +87,7 @@ func (be *Backend) min64(x int64, y int64) int64 { } // writeCipherBlock - Encrypt plaintext and write it to file block "blockNo" -func (be *Backend) writeCipherBlock(blockNo int64, plain []byte, f *os.File) error { +func (be *File) writeCipherBlock(blockNo int64, plain []byte) error { if int64(len(plain)) > be.plainBS { panic("writeCipherBlock: Cannot write block that is larger than plainBS") @@ -91,7 +99,7 @@ func (be *Backend) writeCipherBlock(blockNo int64, plain []byte, f *os.File) err cipherBuf := be.gcm.Seal(nonce, nonce, plain, nil) // WriteAt retries short writes autmatically - written, err := f.WriteAt(cipherBuf, blockNo * be.cipherBS) + written, err := be.file.WriteAt(cipherBuf, blockNo * be.cipherBS) debug.Printf("writeCipherBlock: wrote %d ciphertext bytes to block %d\n", written, blockNo) @@ -101,12 +109,12 @@ func (be *Backend) writeCipherBlock(blockNo int64, plain []byte, f *os.File) err // Perform RMW cycle on block // Write "data" into file location specified in "b" -func (be *Backend) rmwWrite(b intraBlock, data []byte, f *os.File) error { +func (be *File) rmwWrite(b intraBlock, data []byte, f *os.File) error { if b.length != int64(len(data)) { panic("Length mismatch") } - oldBlock, err := be.readCipherBlock(b.blockNo, f) + oldBlock, err := be.readCipherBlock(b.blockNo) if err != nil { return err } @@ -128,7 +136,7 @@ func (be *Backend) rmwWrite(b intraBlock, data []byte, f *os.File) error { copy(newBlock[b.offset:b.offset + b.length], data) // Actual write - err = be.writeCipherBlock(b.blockNo, newBlock, f) + err = be.writeCipherBlock(b.blockNo, newBlock) if err != nil { // An incomplete write to a ciphertext block means that the whole block diff --git a/backend_metadata.go b/cryptfs/fs.go similarity index 75% rename from backend_metadata.go rename to cryptfs/fs.go index 9d2e556..b40dcf3 100644 --- a/backend_metadata.go +++ b/cryptfs/fs.go @@ -1,16 +1,62 @@ -package gocryptfs +package cryptfs import ( - "errors" + "crypto/cipher" + "crypto/aes" "fmt" "strings" "encoding/base64" - "crypto/cipher" - "crypto/aes" + "errors" + "os" ) +const ( + NONCE_LEN = 12 + AUTH_TAG_LEN = 16 + DEFAULT_PLAINBS = 4096 + + ENCRYPT = true + DECRYPT = false +) + +type FS struct { + blockCipher cipher.Block + gcm cipher.AEAD + plainBS int64 + cipherBS int64 +} + +func New(key [16]byte) *FS { + + b, err := aes.NewCipher(key[:]) + if err != nil { + panic(err) + } + + g, err := cipher.NewGCM(b) + if err != nil { + panic(err) + } + + return &FS{ + blockCipher: b, + gcm: g, + plainBS: DEFAULT_PLAINBS, + cipherBS: DEFAULT_PLAINBS + NONCE_LEN + AUTH_TAG_LEN, + } +} + +func (fs *FS) NewFile(f *os.File) *File { + return &File { + file: f, + gcm: fs.gcm, + plainBS: fs.plainBS, + cipherBS: fs.cipherBS, + } +} + // DecryptName - decrypt filename -func (be *Backend) decryptName(cipherName string) (string, error) { +func (be *FS) decryptName(cipherName string) (string, error) { bin, err := base64.URLEncoding.DecodeString(cipherName) if err != nil { @@ -35,7 +81,7 @@ func (be *Backend) decryptName(cipherName string) (string, error) { } // EncryptName - encrypt filename -func (be *Backend) encryptName(plainName string) string { +func (be *FS) encryptName(plainName string) string { bin := []byte(plainName) bin = be.pad16(bin) @@ -51,7 +97,7 @@ func (be *Backend) encryptName(plainName string) string { // TranslatePath - encrypt or decrypt path. Just splits the string on "/" // and hands the parts to EncryptName() / DecryptName() -func (be *Backend) translatePath(path string, op bool) (string, error) { +func (be *FS) translatePath(path string, op bool) (string, error) { var err error // Empty string means root directory @@ -79,18 +125,18 @@ func (be *Backend) translatePath(path string, op bool) (string, error) { } // EncryptPath - encrypt filename or path. Just hands it to TranslatePath(). -func (be *Backend) EncryptPath(path string) string { +func (be *FS) EncryptPath(path string) string { newPath, _ := be.translatePath(path, ENCRYPT) return newPath } // DecryptPath - decrypt filename or path. Just hands it to TranslatePath(). -func (be *Backend) DecryptPath(path string) (string, error) { +func (be *FS) DecryptPath(path string) (string, error) { return be.translatePath(path, DECRYPT) } // plainSize - calculate plaintext size from ciphertext size -func (be *Backend) PlainSize(s int64) int64 { +func (be *FS) PlainSize(s int64) int64 { // Zero sized files stay zero-sized if s > 0 { // Number of blocks @@ -103,7 +149,7 @@ func (be *Backend) PlainSize(s int64) int64 { // pad16 - pad filename to 16 byte blocks using standard PKCS#7 padding // https://tools.ietf.org/html/rfc5652#section-6.3 -func (be *Backend) pad16(orig []byte) (padded []byte) { +func (be *FS) pad16(orig []byte) (padded []byte) { oldLen := len(orig) if oldLen == 0 { panic("Padding zero-length string makes no sense") @@ -123,7 +169,7 @@ func (be *Backend) pad16(orig []byte) (padded []byte) { } // unPad16 - remove padding -func (be *Backend) unPad16(orig []byte) ([]byte, error) { +func (be *FS) unPad16(orig []byte) ([]byte, error) { oldLen := len(orig) if oldLen % aes.BlockSize != 0 { return nil, errors.New("Unaligned size") diff --git a/log.go b/cryptfs/log.go similarity index 93% rename from log.go rename to cryptfs/log.go index a6c65b8..947b1c3 100644 --- a/log.go +++ b/cryptfs/log.go @@ -1,4 +1,4 @@ -package gocryptfs +package cryptfs import ( "fmt" diff --git a/backend_nonce.go b/cryptfs/nonce.go similarity index 97% rename from backend_nonce.go rename to cryptfs/nonce.go index 835a80f..3803b8c 100644 --- a/backend_nonce.go +++ b/cryptfs/nonce.go @@ -1,4 +1,4 @@ -package gocryptfs +package cryptfs import ( "encoding/binary"