diff --git a/README.md b/README.md
index 19bd870..401bffc 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ In stage 1 we only encrypt file content, the file name is not encrypted.
In the future we are going to encrypt the file name also.
-
+## AES-CTR Introduction
AES-CTR algorithm is show as: https://git.hatter.ink/hatter/simple-rust-tests/src/branch/master/__crypto/aes_ctr_test/src/main.rs
@@ -31,7 +31,20 @@ for counter in 0..plaintext_block_count {
}
```
-
+## EncFile Spec
+
+File ext `*.__encfile`:
+
+```json
+{
+ "iv": "<16 bytes IV in base64>"
+}
+```
+
+> if `*.__encfile` not found, then file is unencrypted.
+
+
+## Reference
Related projects:
* https://github.com/spf13/afero
diff --git a/encfs/file.go b/encfs/file.go
index 2cf6455..92fc144 100644
--- a/encfs/file.go
+++ b/encfs/file.go
@@ -1,111 +1,103 @@
package encfs
-type EncFile struct {}
+import (
+ "os"
+ "syscall"
-func (f *File) Close() error {
+ "github.com/spf13/afero"
+)
+
+type EncFile struct {
+ isDir bool
+ closed bool
+ file *os.File
+}
+
+func NewEncFile(file *os.File) (*EncFile, error) {
+ fileInfo, err := file.Stat()
+ if err != nil {
+ return nil, err
+ }
+ isDir := fileInfo.IsDir()
+ return &EncFile{
+ isDir: isDir,
+ closed: false,
+ file: file,
+ }, nil
+}
+
+func (f *EncFile) Close() error {
if f.closed {
return afero.ErrFileClosed
}
f.closed = true
- f.h = nil
- f.data = nil
- f.fs = nil
-
- return nil
+ return f.file.Close()
}
-func (f *File) Read(p []byte) (n int, err error) {
- if f.closed {
- return 0, afero.ErrFileClosed
+func (f *EncFile) Read(p []byte) (n int, err error) {
+ checkIsFileErr := f.checkIsFile()
+ if checkIsFileErr != nil {
+ return 0, checkIsFileErr
}
- if f.h.Typeflag == tar.TypeDir {
- return 0, syscall.EISDIR
- }
-
- return f.data.Read(p)
+ // TODO decrypt
+ return f.file.Read(p)
}
-func (f *File) ReadAt(p []byte, off int64) (n int, err error) {
- if f.closed {
- return 0, afero.ErrFileClosed
+func (f *EncFile) ReadAt(p []byte, off int64) (n int, err error) {
+ checkIsFileErr := f.checkIsFile()
+ if checkIsFileErr != nil {
+ return 0, checkIsFileErr
}
- if f.h.Typeflag == tar.TypeDir {
- return 0, syscall.EISDIR
- }
-
- return f.data.ReadAt(p, off)
+ // TODO decrypt
+ return f.file.ReadAt(p, off)
}
-func (f *File) Seek(offset int64, whence int) (int64, error) {
- if f.closed {
- return 0, afero.ErrFileClosed
+func (f *EncFile) Seek(offset int64, whence int) (int64, error) {
+ checkIsFileErr := f.checkIsFile()
+ if checkIsFileErr != nil {
+ return 0, checkIsFileErr
}
- if f.h.Typeflag == tar.TypeDir {
- return 0, syscall.EISDIR
- }
-
- return f.data.Seek(offset, whence)
+ // TODO decrypt
+ return f.file.Seek(offset, whence)
}
-func (f *File) Write(p []byte) (n int, err error) { return 0, syscall.EROFS }
-
-func (f *File) WriteAt(p []byte, off int64) (n int, err error) { return 0, syscall.EROFS }
-
-func (f *File) Name() string {
- return filepath.Join(splitpath(f.h.Name))
-}
-
-func (f *File) getDirectoryNames() ([]string, error) {
- d, ok := f.fs.files[f.Name()]
- if !ok {
- return nil, &os.PathError{Op: "readdir", Path: f.Name(), Err: syscall.ENOENT}
+func (f *EncFile) Write(p []byte) (n int, err error) {
+ checkIsFileErr := f.checkIsFile()
+ if checkIsFileErr != nil {
+ return 0, checkIsFileErr
}
- var names []string
- for n := range d {
- names = append(names, n)
- }
- sort.Strings(names)
-
- return names, nil
+ // TODO encrypt
+ return f.file.Write(p)
}
-func (f *File) Readdir(count int) ([]os.FileInfo, error) {
+func (f *EncFile) WriteAt(p []byte, off int64) (n int, err error) {
+ checkIsFileErr := f.checkIsFile()
+ if checkIsFileErr != nil {
+ return 0, checkIsFileErr
+ }
+
+ // TODO encrypt
+ return f.file.WriteAt(p, off)
+}
+
+func (f *EncFile) Name() string {
+ return f.file.Name()
+}
+
+func (f *EncFile) Readdir(count int) ([]os.FileInfo, error) {
if f.closed {
return nil, afero.ErrFileClosed
}
- if !f.h.FileInfo().IsDir() {
- return nil, syscall.ENOTDIR
- }
-
- names, err := f.getDirectoryNames()
- if err != nil {
- return nil, err
- }
-
- d := f.fs.files[f.Name()]
- var fi []os.FileInfo
- for _, n := range names {
- if n == "" {
- continue
- }
-
- f := d[n]
- fi = append(fi, f.h.FileInfo())
- if count > 0 && len(fi) >= count {
- break
- }
- }
-
- return fi, nil
+ return f.file.Readdir(count)
}
-func (f *File) Readdirnames(n int) ([]string, error) {
+func (f *EncFile) Readdirnames(n int) ([]string, error) {
fi, err := f.Readdir(n)
if err != nil {
return nil, err
@@ -119,10 +111,29 @@ func (f *File) Readdirnames(n int) ([]string, error) {
return names, nil
}
-func (f *File) Stat() (os.FileInfo, error) { return f.h.FileInfo(), nil }
+func (f *EncFile) Stat() (os.FileInfo, error) {
+ return f.file.Stat()
+}
-func (f *File) Sync() error { return nil }
+func (f *EncFile) Sync() error {
+ return f.file.Sync()
+}
-func (f *File) Truncate(size int64) error { return syscall.EROFS }
+func (f *EncFile) Truncate(size int64) error {
+ return f.file.Truncate(size)
+}
-func (f *File) WriteString(s string) (ret int, err error) { return 0, syscall.EROFS }
+func (f *EncFile) WriteString(s string) (ret int, err error) {
+ // TODO encrypt
+ return f.file.WriteString(s)
+}
+
+func (f *EncFile) checkIsFile() error {
+ if f.closed {
+ return afero.ErrFileClosed
+ }
+ if f.isDir {
+ return syscall.EISDIR
+ }
+ return nil
+}
diff --git a/encfs/fs.go b/encfs/fs.go
index f1c1f1c..9bd8896 100644
--- a/encfs/fs.go
+++ b/encfs/fs.go
@@ -3,26 +3,28 @@ package encfs
import (
"os"
"time"
+
+ "github.com/spf13/afero"
)
// copied from afero/os.go
type EncFs struct{}
-func NewEncFs() Fs {
+func NewEncFs() afero.Fs {
return &EncFs{}
}
func (EncFs) Name() string { return "EncFs" }
-func (EncFs) Create(name string) (File, error) {
+func (EncFs) Create(name string) (afero.File, error) {
f, e := os.Create(name)
if f == nil {
// while this looks strange, we need to return a bare nil (of type nil) not
// a nil value of type *os.File or nil won't be nil
return nil, e
}
- return f, e
+ return convertOsFileToEncFile(f, e)
}
func (EncFs) Mkdir(name string, perm os.FileMode) error {
@@ -33,17 +35,17 @@ func (EncFs) MkdirAll(path string, perm os.FileMode) error {
return os.MkdirAll(path, perm)
}
-func (EncFs) Open(name string) (File, error) {
+func (EncFs) Open(name string) (afero.File, error) {
f, e := os.Open(name)
if f == nil {
// while this looks strange, we need to return a bare nil (of type nil) not
// a nil value of type *os.File or nil won't be nil
return nil, e
}
- return f, e
+ return convertOsFileToEncFile(f, e)
}
-func (EncFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
+func (EncFs) OpenFile(name string, flag int, perm os.FileMode) (afero.File, error) {
f, e := os.OpenFile(name, flag, perm)
if f == nil {
// while this looks strange, we need to return a bare nil (of type nil) not
@@ -54,14 +56,17 @@ func (EncFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
}
func (EncFs) Remove(name string) error {
+ // TODO remove enc file meta
return os.Remove(name)
}
func (EncFs) RemoveAll(path string) error {
+ // TODO remove enc file meta
return os.RemoveAll(path)
}
func (EncFs) Rename(oldname, newname string) error {
+ // TODO rename enc file meta
return os.Rename(oldname, newname)
}
@@ -93,3 +98,15 @@ func (EncFs) SymlinkIfPossible(oldname, newname string) error {
func (EncFs) ReadlinkIfPossible(name string) (string, error) {
return os.Readlink(name)
}
+
+func convertOsFileToEncFile(file *os.File, e error) (afero.File, error) {
+ if e != nil {
+ return nil, e
+ }
+ // TODO add password, and IV etc ...
+ encFile, err := NewEncFile(file)
+ if err != nil {
+ return nil, err
+ }
+ return encFile, nil
+}
diff --git a/justfile b/justfile
new file mode 100644
index 0000000..f0eb85d
--- /dev/null
+++ b/justfile
@@ -0,0 +1,10 @@
+_:
+ @just --list
+
+run:
+ go run main.go
+
+build:
+ go build main.go
+
+
diff --git a/main.go b/main.go
index d68df66..a479161 100644
--- a/main.go
+++ b/main.go
@@ -1,11 +1,13 @@
package main
import (
- "fmt"
- "math"
+ "crypto/aes"
"encoding/binary"
"encoding/hex"
- "crypto/aes"
+ "fmt"
+ "math"
+
+ "git.hatter.ink/hatter/go-afero-encfs/encfs"
"github.com/spf13/afero"
)
@@ -14,7 +16,7 @@ func main() {
osFs := afero.NewOsFs()
fmt.Println(osFs)
- key := []byte {
+ key := []byte{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
}
cipher, err := aes.NewCipher(key)
@@ -23,10 +25,10 @@ func main() {
return
}
- dest := []byte {
+ dest := []byte{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
}
- src := []byte {
+ src := []byte{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
}
cipher.Encrypt(dest, src)
@@ -35,7 +37,6 @@ func main() {
fmt.Println(hex.EncodeToString(src))
fmt.Println(hex.EncodeToString(dest))
-
fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
nonce, err := hex.DecodeString("0011223344556677ffffffffffffffff")
if err != nil {
@@ -58,12 +59,11 @@ func main() {
newNonce = nonceAdd(newNonce, 1)
fmt.Println(hex.EncodeToString(newNonce))
-
fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
- test_key := []byte {
+ test_key := []byte{
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
}
- test_iv := []byte {
+ test_iv := []byte{
1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0,
}
plaintext := "hello world.hello world.hello world.hello world.hello world.hello world."
@@ -80,13 +80,27 @@ func main() {
}
// SHOULD BE: 84ad8d80732490c061177a58bd26d032d6fcff2e66f9afe3cf95717485d3a4485d4a2a7bd835df3d0756b8192e3bf5a287ad8dd81942c43bc812c82d666ebbb34df4e2a5069467d9
fmt.Println(hex.EncodeToString(plaintextBytes))
+
+ encFs := encfs.NewEncFs()
+
+ encFile, err := encFs.Create("test")
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ len, err := encFile.Write([]byte("hello world"))
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ fmt.Println("write len: ", len)
}
func generateCtrEncryptBytes(key, iv []byte, offset, len int64) ([]byte, error) {
endOffset := offset + len
encryptStartOffset := (offset / 16) * 16
encryptEndOffset := (endOffset / 16) * 16
- if endOffset % 16 > 0 {
+ if endOffset%16 > 0 {
encryptEndOffset += 16
}
blocksCount := int((encryptEndOffset - encryptStartOffset) / 16)
@@ -95,13 +109,13 @@ func generateCtrEncryptBytes(key, iv []byte, offset, len int64) ([]byte, error)
if err != nil {
return nil, err
}
- encryptBytes := make([]byte, blocksCount * 16)
+ encryptBytes := make([]byte, blocksCount*16)
for i := 0; i < blocksCount; i++ {
encNonce := nonceAdd(iv, uint64(i))
cipher.Encrypt(encryptBytes[i*16:(i+1)*16], encNonce)
}
// fmt.Println("XX ", hex.EncodeToString(encryptBytes))
- return encryptBytes[offset-encryptStartOffset:offset-encryptStartOffset+len], nil
+ return encryptBytes[offset-encryptStartOffset : offset-encryptStartOffset+len], nil
}
func nonceAdd(nonce []byte, incrementValue uint64) []byte {