Split into FS and File

This commit is contained in:
Jakob Unterwurzacher 2015-09-03 18:57:28 +02:00
parent 4e93fdf820
commit f8fddff769
5 changed files with 78 additions and 66 deletions

View File

@ -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,
}
}

View File

@ -1,19 +1,27 @@
package gocryptfs package cryptfs
import ( import (
"fmt" "fmt"
"os" "os"
"io" "io"
"errors" "errors"
"crypto/cipher"
) )
type File struct {
file *os.File
gcm cipher.AEAD
plainBS int64
cipherBS int64
}
// readCipherBlock - Read ciphertext block number "blockNo", decrypt, // readCipherBlock - Read ciphertext block number "blockNo", decrypt,
// return plaintext // 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) off := blockNo * int64(be.cipherBS)
buf := make([]byte, 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 { if err != nil && err != io.EOF {
return nil, err return nil, err
@ -56,7 +64,7 @@ type intraBlock struct {
} }
// Split a plaintext byte range into (possible partial) blocks // 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 b intraBlock
var parts []intraBlock var parts []intraBlock
@ -71,7 +79,7 @@ func (be *Backend) splitRange(offset int64, length int64, f *os.File) []intraBlo
return parts return parts
} }
func (be *Backend) min64(x int64, y int64) int64 { func (be *File) min64(x int64, y int64) int64 {
if x < y { if x < y {
return x 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" // 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 { if int64(len(plain)) > be.plainBS {
panic("writeCipherBlock: Cannot write block that is larger than 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) cipherBuf := be.gcm.Seal(nonce, nonce, plain, nil)
// WriteAt retries short writes autmatically // 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", debug.Printf("writeCipherBlock: wrote %d ciphertext bytes to block %d\n",
written, blockNo) written, blockNo)
@ -101,12 +109,12 @@ func (be *Backend) writeCipherBlock(blockNo int64, plain []byte, f *os.File) err
// Perform RMW cycle on block // Perform RMW cycle on block
// Write "data" into file location specified in "b" // 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)) { if b.length != int64(len(data)) {
panic("Length mismatch") panic("Length mismatch")
} }
oldBlock, err := be.readCipherBlock(b.blockNo, f) oldBlock, err := be.readCipherBlock(b.blockNo)
if err != nil { if err != nil {
return err 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) copy(newBlock[b.offset:b.offset + b.length], data)
// Actual write // Actual write
err = be.writeCipherBlock(b.blockNo, newBlock, f) err = be.writeCipherBlock(b.blockNo, newBlock)
if err != nil { if err != nil {
// An incomplete write to a ciphertext block means that the whole block // An incomplete write to a ciphertext block means that the whole block

View File

@ -1,16 +1,62 @@
package gocryptfs package cryptfs
import ( import (
"errors" "crypto/cipher"
"crypto/aes"
"fmt" "fmt"
"strings" "strings"
"encoding/base64" "encoding/base64"
"crypto/cipher" "errors"
"crypto/aes" "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 // 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) bin, err := base64.URLEncoding.DecodeString(cipherName)
if err != nil { if err != nil {
@ -35,7 +81,7 @@ func (be *Backend) decryptName(cipherName string) (string, error) {
} }
// EncryptName - encrypt filename // EncryptName - encrypt filename
func (be *Backend) encryptName(plainName string) string { func (be *FS) encryptName(plainName string) string {
bin := []byte(plainName) bin := []byte(plainName)
bin = be.pad16(bin) 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 "/" // TranslatePath - encrypt or decrypt path. Just splits the string on "/"
// and hands the parts to EncryptName() / DecryptName() // 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 var err error
// Empty string means root directory // 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(). // 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) newPath, _ := be.translatePath(path, ENCRYPT)
return newPath return newPath
} }
// DecryptPath - decrypt filename or path. Just hands it to TranslatePath(). // 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) return be.translatePath(path, DECRYPT)
} }
// plainSize - calculate plaintext size from ciphertext size // 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 // Zero sized files stay zero-sized
if s > 0 { if s > 0 {
// Number of blocks // 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 // pad16 - pad filename to 16 byte blocks using standard PKCS#7 padding
// https://tools.ietf.org/html/rfc5652#section-6.3 // 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) oldLen := len(orig)
if oldLen == 0 { if oldLen == 0 {
panic("Padding zero-length string makes no sense") panic("Padding zero-length string makes no sense")
@ -123,7 +169,7 @@ func (be *Backend) pad16(orig []byte) (padded []byte) {
} }
// unPad16 - remove padding // unPad16 - remove padding
func (be *Backend) unPad16(orig []byte) ([]byte, error) { func (be *FS) unPad16(orig []byte) ([]byte, error) {
oldLen := len(orig) oldLen := len(orig)
if oldLen % aes.BlockSize != 0 { if oldLen % aes.BlockSize != 0 {
return nil, errors.New("Unaligned size") return nil, errors.New("Unaligned size")

View File

@ -1,4 +1,4 @@
package gocryptfs package cryptfs
import ( import (
"fmt" "fmt"

View File

@ -1,4 +1,4 @@
package gocryptfs package cryptfs
import ( import (
"encoding/binary" "encoding/binary"