reverse: add gcmsiv flag and associated tests
This commit is contained in:
parent
f8da264222
commit
2050c7f3b3
@ -58,6 +58,9 @@ to mount the gocryptfs filesytem without user interaction.
|
||||
**-fusedebug**
|
||||
: Enable fuse library debug output
|
||||
|
||||
**-gcmsiv**
|
||||
: Use the GCM-SIV encryption mode (implied by -reverse)
|
||||
|
||||
**-init**
|
||||
: Initialize encrypted directory
|
||||
|
||||
@ -94,7 +97,7 @@ runs as root, you can enable device files by passing the opposite mount option,
|
||||
interesting. For a complete liste see the section
|
||||
`FILESYSTEM-INDEPENDENT MOUNT OPTIONS` in mount(8).
|
||||
|
||||
**-openssl bool**
|
||||
**-openssl bool/"auto"**
|
||||
: Use OpenSSL instead of built-in Go crypto (default "auto"). Using
|
||||
built-in crypto is 4x slower unless your CPU has AES instructions and
|
||||
you are using Go 1.6+. In mode "auto", gocrypts chooses the faster
|
||||
@ -109,6 +112,10 @@ option.
|
||||
**-q, -quiet**
|
||||
: Quiet - silence informational messages
|
||||
|
||||
**-reverse**
|
||||
: Reverse mode shows a read-only encrypted view of a plaintext
|
||||
directory
|
||||
|
||||
**-ro**
|
||||
: Mount the filesystem read-only
|
||||
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
type argContainer struct {
|
||||
debug, init, zerokey, fusedebug, openssl, passwd, foreground, version,
|
||||
plaintextnames, quiet, nosyslog, wpanic,
|
||||
longnames, allow_other, ro, reverse bool
|
||||
longnames, allow_other, ro, reverse, gcmsiv bool
|
||||
masterkey, mountpoint, cipherdir, cpuprofile, extpass,
|
||||
memprofile, o string
|
||||
// Configuration file name override
|
||||
@ -51,6 +51,7 @@ func parseCliOpts() (args argContainer) {
|
||||
"Only works if user_allow_other is set in /etc/fuse.conf.")
|
||||
flagSet.BoolVar(&args.ro, "ro", false, "Mount the filesystem read-only")
|
||||
flagSet.BoolVar(&args.reverse, "reverse", false, "Reverse mode")
|
||||
flagSet.BoolVar(&args.gcmsiv, "gcmsiv", false, "GCM-SIV encryption")
|
||||
flagSet.StringVar(&args.masterkey, "masterkey", "", "Mount with explicit master key")
|
||||
flagSet.StringVar(&args.cpuprofile, "cpuprofile", "", "Write cpu profile to specified file")
|
||||
flagSet.StringVar(&args.memprofile, "memprofile", "", "Write memory profile to specified file")
|
||||
|
16
init_dir.go
16
init_dir.go
@ -39,7 +39,7 @@ func initDir(args *argContainer) {
|
||||
}
|
||||
password := readpassword.Twice(args.extpass)
|
||||
creator := tlog.ProgramName + " " + GitVersion
|
||||
err = configfile.CreateConfFile(args.config, password, args.plaintextnames, args.scryptn, creator, args.reverse)
|
||||
err = configfile.CreateConfFile(args.config, password, args.plaintextnames, args.scryptn, creator, args.gcmsiv)
|
||||
if err != nil {
|
||||
tlog.Fatal.Println(err)
|
||||
os.Exit(ERREXIT_INIT)
|
||||
@ -53,8 +53,14 @@ func initDir(args *argContainer) {
|
||||
os.Exit(ERREXIT_INIT)
|
||||
}
|
||||
}
|
||||
|
||||
tlog.Info.Printf(tlog.ColorGreen + "The filesystem has been created successfully." + tlog.ColorReset)
|
||||
mountArgs := ""
|
||||
fsName := "gocryptfs"
|
||||
if args.reverse {
|
||||
mountArgs = " -reverse"
|
||||
fsName = "gocryptfs-reverse"
|
||||
}
|
||||
tlog.Info.Printf(tlog.ColorGreen+"The %s filesystem has been created successfully."+tlog.ColorReset,
|
||||
fsName)
|
||||
wd, _ := os.Getwd()
|
||||
friendlyPath, _ := filepath.Rel(wd, args.cipherdir)
|
||||
if strings.HasPrefix(friendlyPath, "../") {
|
||||
@ -62,7 +68,7 @@ func initDir(args *argContainer) {
|
||||
// keep the absolute path.
|
||||
friendlyPath = args.cipherdir
|
||||
}
|
||||
tlog.Info.Printf(tlog.ColorGrey+"You can now mount it using: %s %s MOUNTPOINT"+tlog.ColorReset,
|
||||
tlog.ProgramName, friendlyPath)
|
||||
tlog.Info.Printf(tlog.ColorGrey+"You can now mount it using: %s%s %s MOUNTPOINT"+tlog.ColorReset,
|
||||
tlog.ProgramName, mountArgs, friendlyPath)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ type ConfFile struct {
|
||||
// CreateConfFile - create a new config with a random key encrypted with
|
||||
// "password" and write it to "filename".
|
||||
// Uses scrypt with cost parameter logN.
|
||||
func CreateConfFile(filename string, password string, plaintextNames bool, logN int, creator string, reverse bool) error {
|
||||
func CreateConfFile(filename string, password string, plaintextNames bool, logN int, creator string, gcmsiv bool) error {
|
||||
var cf ConfFile
|
||||
cf.filename = filename
|
||||
cf.Creator = creator
|
||||
@ -59,7 +59,7 @@ func CreateConfFile(filename string, password string, plaintextNames bool, logN
|
||||
cf.EncryptKey(key, password, logN)
|
||||
|
||||
// Set feature flags
|
||||
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagGCMIV128])
|
||||
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagGCMIV128]) // 128-bit IVs
|
||||
if plaintextNames {
|
||||
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagPlaintextNames])
|
||||
} else {
|
||||
@ -67,8 +67,8 @@ func CreateConfFile(filename string, password string, plaintextNames bool, logN
|
||||
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagEMENames])
|
||||
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagLongNames])
|
||||
}
|
||||
if reverse {
|
||||
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagGCMSIV])
|
||||
if gcmsiv {
|
||||
cf.FeatureFlags = append(cf.FeatureFlags, knownFlags[FlagGCMSIV]) // GCM-SIV encryption mode
|
||||
}
|
||||
|
||||
// Write file to disk
|
||||
|
@ -71,7 +71,7 @@ func TestCreateConfFile(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestCreateConfFileReverse(t *testing.T) {
|
||||
func TestCreateConfFileGCMSIV(t *testing.T) {
|
||||
err := CreateConfFile("config_test/tmp.conf", "test", false, 10, "test", true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -87,7 +87,7 @@ func TestCreateConfFileReverse(t *testing.T) {
|
||||
|
||||
func TestIsFeatureFlagKnown(t *testing.T) {
|
||||
// Test a few hardcoded values
|
||||
testKnownFlags := []string{"DirIV", "PlaintextNames", "EMENames", "GCMIV128", "LongNames"}
|
||||
testKnownFlags := []string{"DirIV", "PlaintextNames", "EMENames", "GCMIV128", "LongNames", "GCMSIV"}
|
||||
// And also everything in knownFlags (yes, it is likely that we end up with
|
||||
// some duplicates. Does not matter.)
|
||||
for _, f := range knownFlags {
|
||||
|
20
main.go
20
main.go
@ -111,11 +111,9 @@ func printVersion() {
|
||||
func main() {
|
||||
runtime.GOMAXPROCS(4)
|
||||
var err error
|
||||
|
||||
// Parse all command-line options (i.e. arguments starting with "-")
|
||||
// into "args". Path arguments are parsed below.
|
||||
args := parseCliOpts()
|
||||
|
||||
// Fork a child into the background if "-f" is not set AND we are mounting
|
||||
// a filesystem. The child will do all the work.
|
||||
if !args.foreground && flagSet.NArg() == 2 {
|
||||
@ -152,6 +150,10 @@ func main() {
|
||||
if args.quiet {
|
||||
tlog.Info.Enabled = false
|
||||
}
|
||||
// "-reverse" implies "-gcmsiv"
|
||||
if args.reverse {
|
||||
args.gcmsiv = true
|
||||
}
|
||||
// "-config"
|
||||
if args.config != "" {
|
||||
args.config, err = filepath.Abs(args.config)
|
||||
@ -201,7 +203,7 @@ func main() {
|
||||
} else {
|
||||
tlog.Debug.Printf("OpenSSL enabled")
|
||||
}
|
||||
// Operation flags: init, passwd or mount
|
||||
// Operation flags: -init or -passwd; otherwise: mount
|
||||
// "-init"
|
||||
if args.init {
|
||||
if flagSet.NArg() > 1 {
|
||||
@ -288,8 +290,7 @@ func initFuseFrontend(key []byte, args argContainer, confFile *configfile.ConfFi
|
||||
if args.openssl {
|
||||
cryptoBackend = cryptocore.BackendOpenSSL
|
||||
}
|
||||
if args.reverse {
|
||||
// reverse implies GCMSIV
|
||||
if args.gcmsiv {
|
||||
cryptoBackend = cryptocore.BackendGCMSIV
|
||||
}
|
||||
frontendArgs := fusefrontend.Args{
|
||||
@ -306,7 +307,7 @@ func initFuseFrontend(key []byte, args argContainer, confFile *configfile.ConfFi
|
||||
if confFile.IsFeatureFlagSet(configfile.FlagGCMSIV) {
|
||||
frontendArgs.CryptoBackend = cryptocore.BackendGCMSIV
|
||||
} else if args.reverse {
|
||||
tlog.Fatal.Printf("GCMSIV is required by reverse mode, but not enabled in the config file")
|
||||
tlog.Fatal.Printf("GCM-SIV is required by reverse mode, but not enabled in the config file")
|
||||
os.Exit(ERREXIT_USAGE)
|
||||
}
|
||||
}
|
||||
@ -317,11 +318,14 @@ func initFuseFrontend(key []byte, args argContainer, confFile *configfile.ConfFi
|
||||
}
|
||||
jsonBytes, _ := json.MarshalIndent(frontendArgs, "", "\t")
|
||||
tlog.Debug.Printf("frontendArgs: %s", string(jsonBytes))
|
||||
|
||||
if frontendArgs.CryptoBackend == cryptocore.BackendGCMSIV {
|
||||
tlog.Info.Printf(tlog.ColorYellow +
|
||||
"Warning: The GCM-SIV format used by reverse mode is not yet finalized.\n" +
|
||||
"The on-disk format will change in the future." + tlog.ColorReset)
|
||||
}
|
||||
var finalFs pathfs.FileSystem
|
||||
if args.reverse {
|
||||
finalFs = fusefrontend_reverse.NewFS(frontendArgs)
|
||||
tlog.Info.Printf(tlog.ColorYellow + "REVERSE MODE IS EXPERIMENTAL!" + tlog.ColorReset)
|
||||
} else {
|
||||
finalFs = fusefrontend.NewFS(frontendArgs)
|
||||
}
|
||||
|
@ -8,8 +8,8 @@ source build.bash
|
||||
|
||||
go test ./... $*
|
||||
|
||||
# Clean up after ourself, but don't descend into maybe still mounted
|
||||
# example filesystems
|
||||
# Clean up after ourself, but don't descend into possibly still mounted
|
||||
# example filesystems.
|
||||
# The tests cannot to this themselves as they are run in parallel
|
||||
rm -Rf --one-file-system /tmp/gocryptfs-test-parent
|
||||
|
||||
|
@ -5,7 +5,6 @@ package normal
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/rfjakob/gocryptfs/internal/configfile"
|
||||
@ -24,18 +23,45 @@ func TestMain(m *testing.M) {
|
||||
// Test -init flag
|
||||
func TestInit(t *testing.T) {
|
||||
dir := test_helpers.InitFS(t)
|
||||
_, err := os.Stat(filepath.Join(dir, configfile.ConfDefaultName))
|
||||
_, c, err := configfile.LoadConfFile(dir+"/"+configfile.ConfDefaultName, "test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if c.IsFeatureFlagSet(configfile.FlagGCMSIV) {
|
||||
t.Error("GCMSIV flag should not be set")
|
||||
}
|
||||
}
|
||||
|
||||
// Test -passwd flag
|
||||
func TestPasswd(t *testing.T) {
|
||||
// Create FS
|
||||
dir := test_helpers.InitFS(t)
|
||||
// Test -init with -gcmsiv
|
||||
func TestInitGcmsiv(t *testing.T) {
|
||||
dir := test_helpers.InitFS(t, "-gcmsiv")
|
||||
_, c, err := configfile.LoadConfFile(dir+"/"+configfile.ConfDefaultName, "test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !c.IsFeatureFlagSet(configfile.FlagGCMSIV) {
|
||||
t.Error("GCMSIV flag should be set but is not")
|
||||
}
|
||||
}
|
||||
|
||||
// Test -init with -reverse
|
||||
func TestInitReverse(t *testing.T) {
|
||||
dir := test_helpers.InitFS(t, "-reverse")
|
||||
_, c, err := configfile.LoadConfFile(dir+"/"+configfile.ConfReverseName, "test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !c.IsFeatureFlagSet(configfile.FlagGCMSIV) {
|
||||
t.Error("GCMSIV flag should be set but is not")
|
||||
}
|
||||
}
|
||||
|
||||
func testPasswd(t *testing.T, dir string, extraArgs ...string) {
|
||||
// Change password using "-extpass"
|
||||
cmd := exec.Command(test_helpers.GocryptfsBinary, "-q", "-passwd", "-extpass", "echo test", dir)
|
||||
args := []string{"-q", "-passwd", "-extpass", "echo test"}
|
||||
args = append(args, extraArgs...)
|
||||
args = append(args, dir)
|
||||
cmd := exec.Command(test_helpers.GocryptfsBinary, args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
@ -43,7 +69,10 @@ func TestPasswd(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
// Change password using stdin
|
||||
cmd = exec.Command(test_helpers.GocryptfsBinary, "-q", "-passwd", dir)
|
||||
args = []string{"-q", "-passwd", "-extpass", "echo test"}
|
||||
args = append(args, extraArgs...)
|
||||
args = append(args, dir)
|
||||
cmd = exec.Command(test_helpers.GocryptfsBinary, args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
p, err := cmd.StdinPipe()
|
||||
@ -65,6 +94,20 @@ func TestPasswd(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Test -passwd flag
|
||||
func TestPasswd(t *testing.T) {
|
||||
// Create FS
|
||||
dir := test_helpers.InitFS(t)
|
||||
testPasswd(t, dir)
|
||||
}
|
||||
|
||||
// Test -passwd with -reverse
|
||||
func TestPasswdReverse(t *testing.T) {
|
||||
// Create FS
|
||||
dir := test_helpers.InitFS(t, "-reverse")
|
||||
testPasswd(t, dir, "-reverse")
|
||||
}
|
||||
|
||||
// Test -init & -config flag
|
||||
func TestInitConfig(t *testing.T) {
|
||||
config := test_helpers.TmpDir + "/TestInitConfig.conf"
|
||||
|
17
tests/reverse/correctness_test.go
Normal file
17
tests/reverse/correctness_test.go
Normal file
@ -0,0 +1,17 @@
|
||||
package reverse_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLongnameStat(t *testing.T) {
|
||||
_, err := os.Stat(dirA + "/" + "")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = os.Stat(dirA + "/" + "")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
@ -5,34 +5,17 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/rfjakob/gocryptfs/tests/test_helpers"
|
||||
)
|
||||
|
||||
var dirA, dirB, x240 string
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
x240 = string(bytes.Repeat([]byte("x"), 240))
|
||||
dirA = test_helpers.TmpDir + "/a"
|
||||
dirB = test_helpers.TmpDir + "/b"
|
||||
os.Mkdir(dirA, 0700)
|
||||
os.Mkdir(dirB, 0700)
|
||||
generateFiles(dirA)
|
||||
test_helpers.MountOrExit(dirA, dirB, "-zerokey", "-reverse")
|
||||
r := m.Run()
|
||||
test_helpers.UnmountPanic(dirB)
|
||||
os.RemoveAll(test_helpers.TmpDir)
|
||||
os.Exit(r)
|
||||
}
|
||||
|
||||
func genName(i int) string {
|
||||
return fmt.Sprintf("%04d.%s", i, x240)
|
||||
func genName(i int, postfix string) string {
|
||||
return fmt.Sprintf("%04d.%s", i, postfix)
|
||||
}
|
||||
|
||||
// Create 10000 files with long names
|
||||
func generateFiles(dir string) {
|
||||
func generateLongnameFiles(dir string) {
|
||||
x240 := string(bytes.Repeat([]byte("x"), 240))
|
||||
for i := 0; i < 100000; i++ {
|
||||
n := genName(i)
|
||||
n := genName(i, x240)
|
||||
f, err := os.Create(dir + "/" + n)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -41,18 +24,9 @@ func generateFiles(dir string) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLongnameStat(t *testing.T) {
|
||||
_, err := os.Stat(dirA + "/" + genName(0))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = os.Stat(dirA + "/" + genName(9999))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLongnameStat(b *testing.B) {
|
||||
// Setup
|
||||
generateLongnameFiles(dirA)
|
||||
dirFd, err := os.Open(dirB)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
@ -63,6 +37,7 @@ func BenchmarkLongnameStat(b *testing.B) {
|
||||
}
|
||||
l := len(encryptedNames)
|
||||
dirFd.Close()
|
||||
// Benchmark
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := os.Stat(dirB + "/" + encryptedNames[i%l])
|
||||
@ -70,4 +45,8 @@ func BenchmarkLongnameStat(b *testing.B) {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
// Cleanup
|
||||
b.StopTimer()
|
||||
os.RemoveAll(dirA)
|
||||
os.Mkdir(dirA, 0700)
|
||||
}
|
||||
|
32
tests/reverse/main_test.go
Normal file
32
tests/reverse/main_test.go
Normal file
@ -0,0 +1,32 @@
|
||||
package reverse_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/rfjakob/gocryptfs/tests/test_helpers"
|
||||
)
|
||||
|
||||
var dirA, dirB, dirC string
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
dirA = test_helpers.TmpDir + "/a"
|
||||
dirB = test_helpers.TmpDir + "/b"
|
||||
dirC = test_helpers.TmpDir + "/c"
|
||||
if err := os.Mkdir(dirA, 0700); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := os.Mkdir(dirB, 0700); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := os.Mkdir(dirC, 0700); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
test_helpers.MountOrExit(dirA, dirB, "-zerokey", "-reverse")
|
||||
test_helpers.MountOrExit(dirB, dirC, "-zerokey", "-gcmsiv")
|
||||
r := m.Run()
|
||||
test_helpers.UnmountPanic(dirC)
|
||||
test_helpers.UnmountPanic(dirB)
|
||||
os.RemoveAll(test_helpers.TmpDir)
|
||||
os.Exit(r)
|
||||
}
|
Loading…
Reference in New Issue
Block a user