From 1971f37a9dd12e9ace585fb64692a423acf0373e Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Sun, 1 Sep 2024 14:20:27 +0800 Subject: [PATCH] feat: still working --- README.md | 17 ++++- encfs/file.go | 171 +++++++++++++++++++++++++++----------------------- encfs/fs.go | 29 +++++++-- justfile | 10 +++ main.go | 40 ++++++++---- 5 files changed, 166 insertions(+), 101 deletions(-) create mode 100644 justfile 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 {