diff --git a/Documentation/MANPAGE.md b/Documentation/MANPAGE.md index 49b3dec9..cb725d5a 100644 --- a/Documentation/MANPAGE.md +++ b/Documentation/MANPAGE.md @@ -96,8 +96,10 @@ continue be printed to stdout and stderr. used internally for daemonization. **-openssl bool** -: Use OpenSSL instead of built-in Go crypto (default true). Using -built-in crypto is 4x slower. +: Use OpenSSL instead of built-in Go crypto (default "auto"). Using +built-in crypto is 4x slower unless you CPU has AES instructions and +you are using Go 1.6+. In mode "auto", gocrypts chooses the faster +option. **-passwd** : Change password diff --git a/internal/stupidgcm/prefer_go1.5.go b/internal/stupidgcm/prefer_go1.5.go new file mode 100644 index 00000000..feaa1d05 --- /dev/null +++ b/internal/stupidgcm/prefer_go1.5.go @@ -0,0 +1,9 @@ +// +build !go1.6 +// = go 1.5 or lower + +package stupidgcm + +func PreferOpenSSL() bool { + // OpenSSL is always faster than Go GCM on old Go versions. + return true +} diff --git a/internal/stupidgcm/prefer_go1.6.go b/internal/stupidgcm/prefer_go1.6.go new file mode 100644 index 00000000..4c94492a --- /dev/null +++ b/internal/stupidgcm/prefer_go1.6.go @@ -0,0 +1,31 @@ +// +build go1.6 +// = go 1.6 or higher + +package stupidgcm + +import ( + "fmt" + "io/ioutil" + "regexp" + "runtime" +) + +// PreferOpenSSL tells us if OpenSSL is faster than Go GCM on this machine. +// Go GCM is fastern when the CPU has AES instructions and Go is v1.6 or higher. +// +// See https://github.com/rfjakob/gocryptfs/issues/23#issuecomment-218286502 +// for benchmarks. +func PreferOpenSSL() bool { + runtime.G + ci, err := ioutil.ReadFile("/proc/cpuinfo") + if err != nil { + fmt.Println(err) + return true + } + match, err := regexp.Match("(?m)^flags.*\baes\b", ci) + if err != nil { + fmt.Println(err) + return true + } + return match +} diff --git a/internal/stupidgcm/stupidgcm_test.go b/internal/stupidgcm/stupidgcm_test.go index 82516b30..9cadc068 100644 --- a/internal/stupidgcm/stupidgcm_test.go +++ b/internal/stupidgcm/stupidgcm_test.go @@ -13,6 +13,7 @@ import ( "crypto/cipher" "crypto/rand" "encoding/hex" + "fmt" "testing" ) @@ -26,6 +27,15 @@ func randBytes(n int) []byte { return b } +func TestPreferOpenSSL(t *testing.T) { + h := PreferOpenSSL() + p := "Go GCM" + if h { + p = "OpenSSL" + } + fmt.Printf("PreferOpenSSL=%v, gocryptfs will prefer %s\n", h, p) +} + // TestEncryptDecrypt encrypts and decrypts using both stupidgcm and Go's built-in // GCM implemenatation and verifies that the results are identical. func TestEncryptDecrypt(t *testing.T) { diff --git a/main.go b/main.go index 8e6e565f..ca5d6a76 100644 --- a/main.go +++ b/main.go @@ -11,6 +11,7 @@ import ( "path/filepath" "runtime" "runtime/pprof" + "strconv" "syscall" "time" @@ -25,6 +26,7 @@ import ( "github.com/rfjakob/gocryptfs/internal/cryptocore" "github.com/rfjakob/gocryptfs/internal/fusefrontend" "github.com/rfjakob/gocryptfs/internal/nametransform" + "github.com/rfjakob/gocryptfs/internal/stupidgcm" "github.com/rfjakob/gocryptfs/internal/toggledlog" ) @@ -149,6 +151,7 @@ func main() { setupColors() // Parse command line arguments + var opensslAuto string flagSet = flag.NewFlagSet(toggledlog.ProgramName, flag.ExitOnError) flagSet.Usage = usageText flagSet.BoolVar(&args.debug, "d", false, "") @@ -156,7 +159,7 @@ func main() { flagSet.BoolVar(&args.fusedebug, "fusedebug", false, "Enable fuse library debug output") flagSet.BoolVar(&args.init, "init", false, "Initialize encrypted directory") flagSet.BoolVar(&args.zerokey, "zerokey", false, "Use all-zero dummy master key") - flagSet.BoolVar(&args.openssl, "openssl", true, "Use OpenSSL instead of built-in Go crypto") + flagSet.StringVar(&opensslAuto, "openssl", "auto", "Use OpenSSL instead of built-in Go crypto") flagSet.BoolVar(&args.passwd, "passwd", false, "Change password") flagSet.BoolVar(&args.foreground, "f", false, "Stay in the foreground") flagSet.BoolVar(&args.version, "version", false, "Print version and exit") @@ -180,6 +183,17 @@ func main() { "Setting this to a lower value speeds up mounting but makes the password susceptible to brute-force attacks") flagSet.Parse(os.Args[1:]) + // "-openssl" needs some post-processing + if opensslAuto == "auto" { + args.openssl = stupidgcm.PreferOpenSSL() + } else { + args.openssl, err = strconv.ParseBool(opensslAuto) + if err != nil { + fmt.Printf(colorRed+"Invalid \"-openssl\" setting: %v\n"+colorReset, err) + os.Exit(ERREXIT_USAGE) + } + } + // Fork a child into the background if "-f" is not set AND we are mounting a filesystem if !args.foreground && flagSet.NArg() == 2 { forkChild() // does not return @@ -255,7 +269,7 @@ func main() { } // "-openssl" if args.openssl == false { - toggledlog.Info.Printf("Openssl disabled") + toggledlog.Info.Printf("OpenSSL disabled, using Go GCM") } // Operation flags: init, passwd or mount // "-init"