Split into FS and File
This commit is contained in:
parent
4e93fdf820
commit
f8fddff769
42
backend.go
42
backend.go
@ -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,
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
@ -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")
|
@ -1,4 +1,4 @@
|
|||||||
package gocryptfs
|
package cryptfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
@ -1,4 +1,4 @@
|
|||||||
package gocryptfs
|
package cryptfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
Loading…
Reference in New Issue
Block a user