summaryrefslogtreecommitdiff
path: root/internal/nametransform
diff options
context:
space:
mode:
authorJakob Unterwurzacher2016-02-06 22:54:14 +0100
committerJakob Unterwurzacher2016-02-06 22:54:14 +0100
commite111e20649cfacd7b02dd454d75db879aa2ca53c (patch)
tree5020d3172bfa2462f05898473093dabd3688e64f /internal/nametransform
parent5abd9cec136bfb981c728eb3bf0f92b2282601c6 (diff)
longnames part I: Create and OpenDir work with long filenames > 176 bytes
Todo: Rename, Unlink, Rmdir, Mknod, Mkdir
Diffstat (limited to 'internal/nametransform')
-rw-r--r--internal/nametransform/longnames.go68
-rw-r--r--internal/nametransform/longnames_test.go22
-rw-r--r--internal/nametransform/name_api.go4
-rw-r--r--internal/nametransform/names_core.go5
-rw-r--r--internal/nametransform/names_diriv.go25
-rw-r--r--internal/nametransform/names_noiv.go2
-rw-r--r--internal/nametransform/names_test.go2
7 files changed, 115 insertions, 13 deletions
diff --git a/internal/nametransform/longnames.go b/internal/nametransform/longnames.go
new file mode 100644
index 0000000..e442b64
--- /dev/null
+++ b/internal/nametransform/longnames.go
@@ -0,0 +1,68 @@
+package nametransform
+
+import (
+ "syscall"
+ "path/filepath"
+ "io/ioutil"
+ "crypto/sha256"
+ "encoding/base64"
+ "strings"
+
+ "github.com/rfjakob/gocryptfs/internal/toggledlog"
+)
+
+// Files with long names are stored in two files:
+// gocryptfs.longname.[sha256] <--- File content
+// gocryptfs.longname.[sha256].name <--- File name
+const longNamePrefix = "gocryptfs.longname."
+const longNameSuffix = ".name"
+
+// HashLongName - take the hash of a long string "name" and return
+// "gocryptfs.longname.[sha256]"
+func HashLongName(name string) string {
+ hashBin := sha256.Sum256([]byte(name))
+ hashBase64 := base64.URLEncoding.EncodeToString(hashBin[:])
+ return longNamePrefix + hashBase64
+}
+
+// IsLongName - detect if cName is
+// gocryptfs.longname.* ........ 1
+// gocryptfs.longname.*.name ... 2
+// else ........................ 0
+func IsLongName(cName string) int {
+ if !strings.HasPrefix(cName, longNamePrefix) {
+ return 0
+ }
+ if strings.HasSuffix(cName, longNameSuffix) {
+ return 2
+ }
+ return 1
+}
+
+// ReadLongName - read "path".name
+func ReadLongName(path string) (string, error) {
+ content, err := ioutil.ReadFile(path+longNameSuffix)
+ if err != nil {
+ toggledlog.Warn.Printf("ReadLongName: %v", err)
+ }
+ return string(content), err
+}
+
+// WriteLongName -
+func (n *NameTransform) WriteLongName(cDir string, hashedName string, plainName string) (err error) {
+ if len(plainName) > syscall.NAME_MAX {
+ return syscall.ENAMETOOLONG
+ }
+
+ dirIV, err := ReadDirIV(cDir)
+ if err != nil {
+ toggledlog.Warn.Printf("WriteLongName: %v", err)
+ return err
+ }
+ cName := n.EncryptName(plainName, dirIV)
+ err = ioutil.WriteFile(filepath.Join(cDir, hashedName + longNameSuffix), []byte(cName), 0600)
+ if err != nil {
+ toggledlog.Warn.Printf("WriteLongName: %v", err)
+ }
+ return err
+}
diff --git a/internal/nametransform/longnames_test.go b/internal/nametransform/longnames_test.go
new file mode 100644
index 0000000..dc4098c
--- /dev/null
+++ b/internal/nametransform/longnames_test.go
@@ -0,0 +1,22 @@
+package nametransform
+
+import (
+ "testing"
+)
+
+func TestIsLongName(t *testing.T) {
+ n := "gocryptfs.longname.LkwUdALvV_ANnzQN6ZZMYnxxfARD3IeZWCKnxGJjYmU=.name"
+ if IsLongName(n) != 2 {
+ t.Errorf("False negative")
+ }
+
+ n = "gocryptfs.longname.LkwUdALvV_ANnzQN6ZZMYnxxfARD3IeZWCKnxGJjYmU="
+ if IsLongName(n) != 1 {
+ t.Errorf("False negative")
+ }
+
+ n = "LkwUdALvV_ANnzQN6ZZMYnxxfARD3IeZWCKnxGJjYmU="
+ if IsLongName(n) != 0 {
+ t.Errorf("False positive")
+ }
+}
diff --git a/internal/nametransform/name_api.go b/internal/nametransform/name_api.go
index fe68e09..391a5ce 100644
--- a/internal/nametransform/name_api.go
+++ b/internal/nametransform/name_api.go
@@ -5,12 +5,14 @@ import "github.com/rfjakob/gocryptfs/internal/cryptocore"
type NameTransform struct {
cryptoCore *cryptocore.CryptoCore
useEME bool
+ longNames bool
DirIVCache dirIVCache
}
-func New(c *cryptocore.CryptoCore, useEME bool) *NameTransform {
+func New(c *cryptocore.CryptoCore, useEME bool, longNames bool) *NameTransform {
return &NameTransform{
cryptoCore: c,
+ longNames: longNames,
useEME: useEME,
}
}
diff --git a/internal/nametransform/names_core.go b/internal/nametransform/names_core.go
index 2eb0026..779b885 100644
--- a/internal/nametransform/names_core.go
+++ b/internal/nametransform/names_core.go
@@ -45,7 +45,10 @@ func (n *NameTransform) DecryptName(cipherName string, iv []byte) (string, error
// encryptName - encrypt "plainName", return base64-encoded "cipherName64"
// The used encryption is either CBC or EME, depending on "useEME".
-func (n *NameTransform) encryptName(plainName string, iv []byte) (cipherName64 string) {
+//
+// This function is exported because fusefrontend needs access to the full (not hashed)
+// name if longname is used
+func (n *NameTransform) EncryptName(plainName string, iv []byte) (cipherName64 string) {
bin := []byte(plainName)
bin = pad16(bin)
diff --git a/internal/nametransform/names_diriv.go b/internal/nametransform/names_diriv.go
index 94c41c8..d45f91b 100644
--- a/internal/nametransform/names_diriv.go
+++ b/internal/nametransform/names_diriv.go
@@ -1,6 +1,7 @@
package nametransform
import (
+ "syscall"
"fmt"
"io/ioutil"
"os"
@@ -19,8 +20,9 @@ const (
DirIVFilename = "gocryptfs.diriv"
)
-// readDirIV - read the "gocryptfs.diriv" file from "dir" (absolute ciphertext path)
-func (be *NameTransform) ReadDirIV(dir string) (iv []byte, readErr error) {
+// ReadDirIV - read the "gocryptfs.diriv" file from "dir" (absolute ciphertext path)
+// This function is exported because it allows for an efficient readdir implementation
+func ReadDirIV(dir string) (iv []byte, readErr error) {
ivfile := filepath.Join(dir, DirIVFilename)
toggledlog.Debug.Printf("ReadDirIV: reading %s\n", ivfile)
iv, readErr = ioutil.ReadFile(ivfile)
@@ -62,9 +64,11 @@ func (be *NameTransform) EncryptPathDirIV(plainPath string, rootDir string) (cip
parentDir := filepath.Dir(plainPath)
found, iv, cParentDir := be.DirIVCache.lookup(parentDir)
if found {
- //fmt.Print("h")
baseName := filepath.Base(plainPath)
- cBaseName := be.encryptName(baseName, iv)
+ cBaseName := be.EncryptName(baseName, iv)
+ if be.longNames && len(cBaseName) > syscall.NAME_MAX {
+ cBaseName = HashLongName(cBaseName)
+ }
cipherPath = cParentDir + "/" + cBaseName
return cipherPath, nil
}
@@ -73,29 +77,32 @@ func (be *NameTransform) EncryptPathDirIV(plainPath string, rootDir string) (cip
var encryptedNames []string
plainNames := strings.Split(plainPath, "/")
for _, plainName := range plainNames {
- iv, err = be.ReadDirIV(wd)
+ iv, err = ReadDirIV(wd)
if err != nil {
return "", err
}
- encryptedName := be.encryptName(plainName, iv)
+ encryptedName := be.EncryptName(plainName, iv)
+ if be.longNames && len(encryptedName) > syscall.NAME_MAX {
+ encryptedName = HashLongName(encryptedName)
+ }
encryptedNames = append(encryptedNames, encryptedName)
wd = filepath.Join(wd, encryptedName)
}
- // Cache the final DirIV
cipherPath = strings.Join(encryptedNames, "/")
+ // Cache the final DirIV
cParentDir = filepath.Dir(cipherPath)
be.DirIVCache.store(parentDir, iv, cParentDir)
return cipherPath, nil
}
// DecryptPathDirIV - decrypt path using EME with DirIV
-func (be *NameTransform) DecryptPathDirIV(encryptedPath string, rootDir string, eme bool) (string, error) {
+func (be *NameTransform) DecryptPathDirIV(encryptedPath string, rootDir string) (string, error) {
var wd = rootDir
var plainNames []string
encryptedNames := strings.Split(encryptedPath, "/")
toggledlog.Debug.Printf("DecryptPathDirIV: decrypting %v\n", encryptedNames)
for _, encryptedName := range encryptedNames {
- iv, err := be.ReadDirIV(wd)
+ iv, err := ReadDirIV(wd)
if err != nil {
return "", err
}
diff --git a/internal/nametransform/names_noiv.go b/internal/nametransform/names_noiv.go
index f301e52..f1009e4 100644
--- a/internal/nametransform/names_noiv.go
+++ b/internal/nametransform/names_noiv.go
@@ -49,7 +49,7 @@ func (be *NameTransform) translatePathNoIV(path string, op int) (string, error)
}
var newPart string
if op == OpEncrypt {
- newPart = be.encryptName(part, zeroIV)
+ newPart = be.EncryptName(part, zeroIV)
} else {
newPart, err = be.DecryptName(part, zeroIV)
if err != nil {
diff --git a/internal/nametransform/names_test.go b/internal/nametransform/names_test.go
index fdb9f05..4a0043b 100644
--- a/internal/nametransform/names_test.go
+++ b/internal/nametransform/names_test.go
@@ -15,7 +15,7 @@ func TestEncryptPathNoIV(t *testing.T) {
key := make([]byte, cryptocore.KeyLen)
cc := cryptocore.New(key, false, true)
- fs := New(cc, true)
+ fs := New(cc, true, false)
for _, n := range s {
c := fs.EncryptPathNoIV(n)