ctlsock: implement EncryptPath for reverse mode, add tests
This commit is contained in:
parent
d3764b7753
commit
c03fc46a51
@ -14,6 +14,6 @@ func (fs *FS) EncryptPath(plainPath string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DecryptPath implements ctlsock.Backend
|
// DecryptPath implements ctlsock.Backend
|
||||||
func (fs *FS) DecryptPath(plainPath string) (string, error) {
|
func (fs *FS) DecryptPath(cipherPath string) (string, error) {
|
||||||
return "", errors.New("Not implemented")
|
return "", errors.New("not implemented (yet?)")
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,39 @@
|
|||||||
package fusefrontend_reverse
|
package fusefrontend_reverse
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/rfjakob/gocryptfs/internal/ctlsock"
|
"github.com/rfjakob/gocryptfs/internal/ctlsock"
|
||||||
|
"github.com/rfjakob/gocryptfs/internal/nametransform"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ ctlsock.Interface = &ReverseFS{} // Verify that interface is implemented.
|
var _ ctlsock.Interface = &ReverseFS{} // Verify that interface is implemented.
|
||||||
|
|
||||||
// EncryptPath implements ctlsock.Backend
|
// EncryptPath implements ctlsock.Backend.
|
||||||
|
// This is actually not used inside reverse mode, but we implement it because
|
||||||
|
// third-party tools want to encrypt paths through the control socket.
|
||||||
func (rfs *ReverseFS) EncryptPath(plainPath string) (string, error) {
|
func (rfs *ReverseFS) EncryptPath(plainPath string) (string, error) {
|
||||||
return "", errors.New("Not implemented")
|
if rfs.args.PlaintextNames || plainPath == "" {
|
||||||
|
return plainPath, nil
|
||||||
|
}
|
||||||
|
cipherPath := ""
|
||||||
|
parts := strings.Split(plainPath, "/")
|
||||||
|
for _, part := range parts {
|
||||||
|
dirIV := derivePathIV(cipherPath, ivPurposeDirIV)
|
||||||
|
encryptedPart := rfs.nameTransform.EncryptName(part, dirIV)
|
||||||
|
if rfs.args.LongNames && len(encryptedPart) > syscall.NAME_MAX {
|
||||||
|
encryptedPart = nametransform.HashLongName(encryptedPart)
|
||||||
|
}
|
||||||
|
cipherPath = filepath.Join(cipherPath, encryptedPart)
|
||||||
|
}
|
||||||
|
return cipherPath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecryptPath implements ctlsock.Backend
|
// DecryptPath implements ctlsock.Backend
|
||||||
func (rfs *ReverseFS) DecryptPath(plainPath string) (string, error) {
|
func (rfs *ReverseFS) DecryptPath(cipherPath string) (string, error) {
|
||||||
return rfs.decryptPath(plainPath)
|
p, err := rfs.decryptPath(cipherPath)
|
||||||
|
//fmt.Printf("rfs DecryptPath: %q -> %q %v\n", cipherPath, p, err)
|
||||||
|
return p, err
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,10 @@
|
|||||||
package defaults
|
package defaults
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/rfjakob/gocryptfs/internal/ctlsock"
|
"github.com/rfjakob/gocryptfs/internal/ctlsock"
|
||||||
"github.com/rfjakob/gocryptfs/tests/test_helpers"
|
"github.com/rfjakob/gocryptfs/tests/test_helpers"
|
||||||
@ -48,27 +44,16 @@ func TestCtlSock(t *testing.T) {
|
|||||||
sock := cDir + ".sock"
|
sock := cDir + ".sock"
|
||||||
test_helpers.MountOrFatal(t, cDir, pDir, "-ctlsock="+sock, "-extpass", "echo test")
|
test_helpers.MountOrFatal(t, cDir, pDir, "-ctlsock="+sock, "-extpass", "echo test")
|
||||||
defer test_helpers.UnmountPanic(pDir)
|
defer test_helpers.UnmountPanic(pDir)
|
||||||
conn, err := net.DialTimeout("unix", sock, 1*time.Second)
|
req := ctlsock.RequestStruct{
|
||||||
if err != nil {
|
EncryptPath: "foobar",
|
||||||
t.Fatal(err)
|
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
response := test_helpers.QueryCtlSock(t, sock, req)
|
||||||
conn.SetDeadline(time.Now().Add(time.Second))
|
|
||||||
msg := []byte(`{"EncryptPath": "foobar"}`)
|
|
||||||
_, err = conn.Write(msg)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
buf := make([]byte, 2*syscall.PathMax)
|
|
||||||
n, err := conn.Read(buf)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
buf = buf[:n]
|
|
||||||
var response ctlsock.ResponseStruct
|
|
||||||
json.Unmarshal(buf, &response)
|
|
||||||
if response.Result == "" || response.ErrNo != 0 {
|
if response.Result == "" || response.ErrNo != 0 {
|
||||||
fmt.Printf("%s\n", string(buf))
|
t.Errorf("got an error reply: %+v", response)
|
||||||
t.Errorf("got an error reply")
|
}
|
||||||
|
req.EncryptPath = "not-existing-dir/xyz"
|
||||||
|
response = test_helpers.QueryCtlSock(t, sock, req)
|
||||||
|
if response.ErrNo != int32(syscall.ENOENT) || response.Result != "" {
|
||||||
|
t.Errorf("incorrect error handling: %+v", response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"Creator": "gocryptfs v1.1.1-16-g75ebb28-dirty",
|
||||||
|
"EncryptedKey": "cE5bhCZl1iL1tn0dNLh8aQy8n55NMbojmmkwM8iM8/y0uChO0CGaK16sNHffAKJ++qH287JlCpk/BFyi",
|
||||||
|
"ScryptObject": {
|
||||||
|
"Salt": "yUxEmtl4KeUkCxL8b6aYcEGVtFe2NAlwy0WsFLt8p+Y=",
|
||||||
|
"N": 1024,
|
||||||
|
"R": 8,
|
||||||
|
"P": 1,
|
||||||
|
"KeyLen": 32
|
||||||
|
},
|
||||||
|
"Version": 2,
|
||||||
|
"FeatureFlags": [
|
||||||
|
"GCMIV128",
|
||||||
|
"DirIV",
|
||||||
|
"EMENames",
|
||||||
|
"LongNames",
|
||||||
|
"AESSIV"
|
||||||
|
]
|
||||||
|
}
|
0
tests/reverse/ctlsock_reverse_test_fs/dir/dir/file
Normal file
0
tests/reverse/ctlsock_reverse_test_fs/dir/dir/file
Normal file
0
tests/reverse/ctlsock_reverse_test_fs/dir/file
Normal file
0
tests/reverse/ctlsock_reverse_test_fs/dir/file
Normal file
0
tests/reverse/ctlsock_reverse_test_fs/file
Normal file
0
tests/reverse/ctlsock_reverse_test_fs/file
Normal file
52
tests/reverse/ctlsock_test.go
Normal file
52
tests/reverse/ctlsock_test.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package reverse_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rfjakob/gocryptfs/internal/ctlsock"
|
||||||
|
"github.com/rfjakob/gocryptfs/tests/test_helpers"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ctlSockTestCases = [][]string{
|
||||||
|
{"4RQq1dJlfvQPaVU5Xypf0w==", "file"},
|
||||||
|
{"gocryptfs.longname.ZQCAoi5li3xvDZRO8McBV0L_kzJc4IcAOEzuW-2S1Y4=", "longfile." + x240},
|
||||||
|
{"v6puXntoQOk7Mhl8zJ4Idg==", "dir"},
|
||||||
|
{"v6puXntoQOk7Mhl8zJ4Idg==/UVy2gV0RQTUC8AE4wYoMwg==", "dir/file"},
|
||||||
|
{"v6puXntoQOk7Mhl8zJ4Idg==/fvHFLHlxHCQ7EpVMJu0AZg==", "dir/dir"},
|
||||||
|
{"v6puXntoQOk7Mhl8zJ4Idg==/fvHFLHlxHCQ7EpVMJu0AZg==/_4uudIGniACke55JoDsqDA==", "dir/dir/dir"},
|
||||||
|
{"v6puXntoQOk7Mhl8zJ4Idg==/fvHFLHlxHCQ7EpVMJu0AZg==/QvPahkkeVRKTw2kdZFZxwQ==", "dir/dir/file"},
|
||||||
|
{"v6puXntoQOk7Mhl8zJ4Idg==/gocryptfs.longname.y6rxCn6Id8hIZL2t_STpdLZpu-aE2HpprJR25xD60mk=", "dir/longfile." + x240},
|
||||||
|
{"gocryptfs.longname.cvRximo1ATRJVEzw_V9MZieHFlod9y2iv2Sug1kbiTE=", "longdir." + x240},
|
||||||
|
{"gocryptfs.longname.cvRximo1ATRJVEzw_V9MZieHFlod9y2iv2Sug1kbiTE=/-LMdFgFt6UxO-z5iJvuC9w==", "longdir." + x240 + "/dir"},
|
||||||
|
{"gocryptfs.longname.cvRximo1ATRJVEzw_V9MZieHFlod9y2iv2Sug1kbiTE=/rBPJYAzcHWLdPj1T8kgh8A==", "longdir." + x240 + "/file"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCtlSockDecryptPath(t *testing.T) {
|
||||||
|
mnt, err := ioutil.TempDir(test_helpers.TmpDir, "reverse_mnt_")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
sock := mnt + ".sock"
|
||||||
|
test_helpers.MountOrFatal(t, "ctlsock_reverse_test_fs", mnt, "-reverse", "-extpass", "echo test", "-ctlsock="+sock)
|
||||||
|
defer test_helpers.UnmountPanic(mnt)
|
||||||
|
var req ctlsock.RequestStruct
|
||||||
|
for i, tc := range ctlSockTestCases {
|
||||||
|
// Decrypt
|
||||||
|
req = ctlsock.RequestStruct{DecryptPath: tc[0]}
|
||||||
|
response := test_helpers.QueryCtlSock(t, sock, req)
|
||||||
|
if response.ErrNo != 0 {
|
||||||
|
t.Errorf("Testcase %d Decrypt: %q ErrNo=%d ErrText=%s", i, tc[0], response.ErrNo, response.ErrText)
|
||||||
|
} else if response.Result != tc[1] {
|
||||||
|
t.Errorf("Testcase %d Decrypt: Want %q got %q", i, tc[1], response.Result)
|
||||||
|
}
|
||||||
|
// Encrypt
|
||||||
|
req = ctlsock.RequestStruct{EncryptPath: tc[1]}
|
||||||
|
response = test_helpers.QueryCtlSock(t, sock, req)
|
||||||
|
if response.ErrNo != 0 {
|
||||||
|
t.Errorf("Testcase %d Encrypt: %q ErrNo=%d ErrText=%s", i, tc[0], response.ErrNo, response.ErrText)
|
||||||
|
} else if response.Result != tc[0] {
|
||||||
|
t.Errorf("Testcase %d Encrypt: Want %q got %q", i, tc[1], response.Result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,11 +9,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var dirA, dirB, dirC string
|
var dirA, dirB, dirC string
|
||||||
var x240 string
|
var x240 = string(bytes.Repeat([]byte("x"), 240))
|
||||||
var plaintextnames bool
|
var plaintextnames bool
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
x240 = string(bytes.Repeat([]byte("x"), 240))
|
|
||||||
var r int
|
var r int
|
||||||
for _, plaintextnames = range []bool{false, true} {
|
for _, plaintextnames = range []bool{false, true} {
|
||||||
argsA := []string{"-reverse"}
|
argsA := []string{"-reverse"}
|
||||||
|
@ -3,15 +3,19 @@ package test_helpers
|
|||||||
import (
|
import (
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/rfjakob/gocryptfs/internal/ctlsock"
|
||||||
"github.com/rfjakob/gocryptfs/internal/nametransform"
|
"github.com/rfjakob/gocryptfs/internal/nametransform"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -323,3 +327,30 @@ func Du(t *testing.T, fd int) (nBytes int64) {
|
|||||||
// st.Blocks = number of 512-byte blocks
|
// st.Blocks = number of 512-byte blocks
|
||||||
return st.Blocks * 512
|
return st.Blocks * 512
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QueryCtlSock sends a request to the control socket at "socketPath" and
|
||||||
|
// returns the response.
|
||||||
|
func QueryCtlSock(t *testing.T, socketPath string, req ctlsock.RequestStruct) (response ctlsock.ResponseStruct) {
|
||||||
|
conn, err := net.DialTimeout("unix", socketPath, 1*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
conn.SetDeadline(time.Now().Add(time.Second))
|
||||||
|
msg, err := json.Marshal(req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = conn.Write(msg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
buf := make([]byte, 2*syscall.PathMax)
|
||||||
|
n, err := conn.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
buf = buf[:n]
|
||||||
|
json.Unmarshal(buf, &response)
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user