feat: still working

This commit is contained in:
2024-09-01 14:20:27 +08:00
parent 02584eee70
commit 1971f37a9d
5 changed files with 166 additions and 101 deletions

View File

@@ -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. In the future we are going to encrypt the file name also.
<br> ## 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 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 {
} }
``` ```
<br> ## EncFile Spec
File ext `*.__encfile`:
```json
{
"iv": "<16 bytes IV in base64>"
}
```
> if `*.__encfile` not found, then file is unencrypted.
## Reference
Related projects: Related projects:
* https://github.com/spf13/afero * https://github.com/spf13/afero

View File

@@ -1,111 +1,103 @@
package encfs 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 { if f.closed {
return afero.ErrFileClosed return afero.ErrFileClosed
} }
f.closed = true f.closed = true
f.h = nil return f.file.Close()
f.data = nil
f.fs = nil
return nil
} }
func (f *File) Read(p []byte) (n int, err error) { func (f *EncFile) Read(p []byte) (n int, err error) {
if f.closed { checkIsFileErr := f.checkIsFile()
return 0, afero.ErrFileClosed if checkIsFileErr != nil {
return 0, checkIsFileErr
} }
if f.h.Typeflag == tar.TypeDir { // TODO decrypt
return 0, syscall.EISDIR return f.file.Read(p)
}
return f.data.Read(p)
} }
func (f *File) ReadAt(p []byte, off int64) (n int, err error) { func (f *EncFile) ReadAt(p []byte, off int64) (n int, err error) {
if f.closed { checkIsFileErr := f.checkIsFile()
return 0, afero.ErrFileClosed if checkIsFileErr != nil {
return 0, checkIsFileErr
} }
if f.h.Typeflag == tar.TypeDir { // TODO decrypt
return 0, syscall.EISDIR return f.file.ReadAt(p, off)
}
return f.data.ReadAt(p, off)
} }
func (f *File) Seek(offset int64, whence int) (int64, error) { func (f *EncFile) Seek(offset int64, whence int) (int64, error) {
if f.closed { checkIsFileErr := f.checkIsFile()
return 0, afero.ErrFileClosed if checkIsFileErr != nil {
return 0, checkIsFileErr
} }
if f.h.Typeflag == tar.TypeDir { // TODO decrypt
return 0, syscall.EISDIR return f.file.Seek(offset, whence)
}
return f.data.Seek(offset, whence)
} }
func (f *File) Write(p []byte) (n int, err error) { return 0, syscall.EROFS } func (f *EncFile) Write(p []byte) (n int, err error) {
checkIsFileErr := f.checkIsFile()
func (f *File) WriteAt(p []byte, off int64) (n int, err error) { return 0, syscall.EROFS } if checkIsFileErr != nil {
return 0, checkIsFileErr
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}
} }
var names []string // TODO encrypt
for n := range d { return f.file.Write(p)
names = append(names, n)
}
sort.Strings(names)
return names, nil
} }
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 { if f.closed {
return nil, afero.ErrFileClosed return nil, afero.ErrFileClosed
} }
if !f.h.FileInfo().IsDir() { return f.file.Readdir(count)
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
} }
func (f *File) Readdirnames(n int) ([]string, error) { func (f *EncFile) Readdirnames(n int) ([]string, error) {
fi, err := f.Readdir(n) fi, err := f.Readdir(n)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -119,10 +111,29 @@ func (f *File) Readdirnames(n int) ([]string, error) {
return names, nil 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
}

View File

@@ -3,26 +3,28 @@ package encfs
import ( import (
"os" "os"
"time" "time"
"github.com/spf13/afero"
) )
// copied from afero/os.go // copied from afero/os.go
type EncFs struct{} type EncFs struct{}
func NewEncFs() Fs { func NewEncFs() afero.Fs {
return &EncFs{} return &EncFs{}
} }
func (EncFs) Name() string { 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) f, e := os.Create(name)
if f == nil { if f == nil {
// while this looks strange, we need to return a bare nil (of type nil) not // 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 // a nil value of type *os.File or nil won't be nil
return nil, e return nil, e
} }
return f, e return convertOsFileToEncFile(f, e)
} }
func (EncFs) Mkdir(name string, perm os.FileMode) error { 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) 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) f, e := os.Open(name)
if f == nil { if f == nil {
// while this looks strange, we need to return a bare nil (of type nil) not // 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 // a nil value of type *os.File or nil won't be nil
return nil, e 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) f, e := os.OpenFile(name, flag, perm)
if f == nil { if f == nil {
// while this looks strange, we need to return a bare nil (of type nil) not // 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 { func (EncFs) Remove(name string) error {
// TODO remove enc file meta
return os.Remove(name) return os.Remove(name)
} }
func (EncFs) RemoveAll(path string) error { func (EncFs) RemoveAll(path string) error {
// TODO remove enc file meta
return os.RemoveAll(path) return os.RemoveAll(path)
} }
func (EncFs) Rename(oldname, newname string) error { func (EncFs) Rename(oldname, newname string) error {
// TODO rename enc file meta
return os.Rename(oldname, newname) return os.Rename(oldname, newname)
} }
@@ -93,3 +98,15 @@ func (EncFs) SymlinkIfPossible(oldname, newname string) error {
func (EncFs) ReadlinkIfPossible(name string) (string, error) { func (EncFs) ReadlinkIfPossible(name string) (string, error) {
return os.Readlink(name) 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
}

10
justfile Normal file
View File

@@ -0,0 +1,10 @@
_:
@just --list
run:
go run main.go
build:
go build main.go

40
main.go
View File

@@ -1,11 +1,13 @@
package main package main
import ( import (
"fmt" "crypto/aes"
"math"
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"crypto/aes" "fmt"
"math"
"git.hatter.ink/hatter/go-afero-encfs/encfs"
"github.com/spf13/afero" "github.com/spf13/afero"
) )
@@ -14,7 +16,7 @@ func main() {
osFs := afero.NewOsFs() osFs := afero.NewOsFs()
fmt.Println(osFs) fmt.Println(osFs)
key := []byte { key := []byte{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
} }
cipher, err := aes.NewCipher(key) cipher, err := aes.NewCipher(key)
@@ -23,10 +25,10 @@ func main() {
return return
} }
dest := []byte { dest := []byte{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
} }
cipher.Encrypt(dest, src) cipher.Encrypt(dest, src)
@@ -35,7 +37,6 @@ func main() {
fmt.Println(hex.EncodeToString(src)) fmt.Println(hex.EncodeToString(src))
fmt.Println(hex.EncodeToString(dest)) fmt.Println(hex.EncodeToString(dest))
fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>") fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
nonce, err := hex.DecodeString("0011223344556677ffffffffffffffff") nonce, err := hex.DecodeString("0011223344556677ffffffffffffffff")
if err != nil { if err != nil {
@@ -58,12 +59,11 @@ func main() {
newNonce = nonceAdd(newNonce, 1) newNonce = nonceAdd(newNonce, 1)
fmt.Println(hex.EncodeToString(newNonce)) fmt.Println(hex.EncodeToString(newNonce))
fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>") fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
test_key := []byte { test_key := []byte{
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 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." plaintext := "hello world.hello world.hello world.hello world.hello world.hello world."
@@ -80,13 +80,27 @@ func main() {
} }
// SHOULD BE: 84ad8d80732490c061177a58bd26d032d6fcff2e66f9afe3cf95717485d3a4485d4a2a7bd835df3d0756b8192e3bf5a287ad8dd81942c43bc812c82d666ebbb34df4e2a5069467d9 // SHOULD BE: 84ad8d80732490c061177a58bd26d032d6fcff2e66f9afe3cf95717485d3a4485d4a2a7bd835df3d0756b8192e3bf5a287ad8dd81942c43bc812c82d666ebbb34df4e2a5069467d9
fmt.Println(hex.EncodeToString(plaintextBytes)) 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) { func generateCtrEncryptBytes(key, iv []byte, offset, len int64) ([]byte, error) {
endOffset := offset + len endOffset := offset + len
encryptStartOffset := (offset / 16) * 16 encryptStartOffset := (offset / 16) * 16
encryptEndOffset := (endOffset / 16) * 16 encryptEndOffset := (endOffset / 16) * 16
if endOffset % 16 > 0 { if endOffset%16 > 0 {
encryptEndOffset += 16 encryptEndOffset += 16
} }
blocksCount := int((encryptEndOffset - encryptStartOffset) / 16) blocksCount := int((encryptEndOffset - encryptStartOffset) / 16)
@@ -95,13 +109,13 @@ func generateCtrEncryptBytes(key, iv []byte, offset, len int64) ([]byte, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
encryptBytes := make([]byte, blocksCount * 16) encryptBytes := make([]byte, blocksCount*16)
for i := 0; i < blocksCount; i++ { for i := 0; i < blocksCount; i++ {
encNonce := nonceAdd(iv, uint64(i)) encNonce := nonceAdd(iv, uint64(i))
cipher.Encrypt(encryptBytes[i*16:(i+1)*16], encNonce) cipher.Encrypt(encryptBytes[i*16:(i+1)*16], encNonce)
} }
// fmt.Println("XX ", hex.EncodeToString(encryptBytes)) // 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 { func nonceAdd(nonce []byte, incrementValue uint64) []byte {