feat: still working
This commit is contained in:
17
README.md
17
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.
|
||||
|
||||
|
||||
<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
|
||||
|
||||
@@ -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:
|
||||
* https://github.com/spf13/afero
|
||||
|
||||
171
encfs/file.go
171
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
|
||||
}
|
||||
|
||||
29
encfs/fs.go
29
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
|
||||
}
|
||||
|
||||
10
justfile
Normal file
10
justfile
Normal file
@@ -0,0 +1,10 @@
|
||||
_:
|
||||
@just --list
|
||||
|
||||
run:
|
||||
go run main.go
|
||||
|
||||
build:
|
||||
go build main.go
|
||||
|
||||
|
||||
40
main.go
40
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 {
|
||||
|
||||
Reference in New Issue
Block a user