diff --git a/Documentation/MANPAGE.md b/Documentation/MANPAGE.md index 49b3dec..cb725d5 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/prefer_openssl/cpuinfo.pentium_g630.txt b/internal/prefer_openssl/cpuinfo.pentium_g630.txt new file mode 100644 index 0000000..b6d7811 --- /dev/null +++ b/internal/prefer_openssl/cpuinfo.pentium_g630.txt @@ -0,0 +1,54 @@ +processor : 0 +vendor_id : GenuineIntel +cpu family : 6 +model : 42 +model name : Intel(R) Pentium(R) CPU G630 @ 2.70GHz +stepping : 7 +microcode : 0x29 +cpu MHz : 2700.000 +cache size : 3072 KB +physical id : 0 +siblings : 2 +core id : 0 +cpu cores : 2 +apicid : 0 +initial apicid : 0 +fpu : yes +fpu_exception : yes +cpuid level : 13 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 popcnt tsc_deadline_timer xsave lahf_lm arat epb pln pts dtherm tpr_shadow vnmi flexpriority ept vpid xsaveopt +bugs : +bogomips : 5387.85 +clflush size : 64 +cache_alignment : 64 +address sizes : 36 bits physical, 48 bits virtual +power management: + +processor : 1 +vendor_id : GenuineIntel +cpu family : 6 +model : 42 +model name : Intel(R) Pentium(R) CPU G630 @ 2.70GHz +stepping : 7 +microcode : 0x29 +cpu MHz : 2700.000 +cache size : 3072 KB +physical id : 0 +siblings : 2 +core id : 1 +cpu cores : 2 +apicid : 2 +initial apicid : 2 +fpu : yes +fpu_exception : yes +cpuid level : 13 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 popcnt tsc_deadline_timer xsave lahf_lm arat epb pln pts dtherm tpr_shadow vnmi flexpriority ept vpid xsaveopt +bugs : +bogomips : 5387.85 +clflush size : 64 +cache_alignment : 64 +address sizes : 36 bits physical, 48 bits virtual +power management: + diff --git a/internal/prefer_openssl/cpuinfo.xeon_e312xx.txt b/internal/prefer_openssl/cpuinfo.xeon_e312xx.txt new file mode 100644 index 0000000..efad8c3 --- /dev/null +++ b/internal/prefer_openssl/cpuinfo.xeon_e312xx.txt @@ -0,0 +1,52 @@ +processor : 0 +vendor_id : GenuineIntel +cpu family : 6 +model : 42 +model name : Intel Xeon E312xx (Sandy Bridge) +stepping : 1 +microcode : 0x1 +cpu MHz : 3300.022 +cache size : 4096 KB +physical id : 0 +siblings : 1 +core id : 0 +cpu cores : 1 +apicid : 0 +initial apicid : 0 +fpu : yes +fpu_exception : yes +cpuid level : 13 +wp : yes +flags : fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx rdtscp lm constant_tsc rep_good nopl eagerfpu pni pclmulqdq ssse3 cx16 sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx hypervisor lahf_lm xsaveopt +bogomips : 6600.04 +clflush size : 64 +cache_alignment : 64 +address sizes : 40 bits physical, 48 bits virtual +power management: + +processor : 1 +vendor_id : GenuineIntel +cpu family : 6 +model : 42 +model name : Intel Xeon E312xx (Sandy Bridge) +stepping : 1 +microcode : 0x1 +cpu MHz : 3300.022 +cache size : 4096 KB +physical id : 1 +siblings : 1 +core id : 0 +cpu cores : 1 +apicid : 1 +initial apicid : 1 +fpu : yes +fpu_exception : yes +cpuid level : 13 +wp : yes +flags : fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx rdtscp lm constant_tsc rep_good nopl eagerfpu pni pclmulqdq ssse3 cx16 sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx hypervisor lahf_lm xsaveopt +bogomips : 6600.04 +clflush size : 64 +cache_alignment : 64 +address sizes : 40 bits physical, 48 bits virtual +power management: + diff --git a/internal/prefer_openssl/prefer.go b/internal/prefer_openssl/prefer.go new file mode 100644 index 0000000..16788e0 --- /dev/null +++ b/internal/prefer_openssl/prefer.go @@ -0,0 +1,29 @@ +package prefer_openssl + +import ( + "fmt" + "io/ioutil" + "regexp" +) + +// filePreferOpenSSL 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. +// +// filePreferOpenSSL takes an explicit filename so it can be tested with saved +// cpuinfo files instead of /proc/cpuinfo. +func filePreferOpenSSL(file string) bool { + ci, err := ioutil.ReadFile(file) + if err != nil { + fmt.Println(err) + return true + } + haveAes, err := regexp.Match(`(?m)^flags.*\baes\b`, ci) + if err != nil { + fmt.Println(err) + return true + } + return !haveAes +} diff --git a/internal/prefer_openssl/prefer_go1.5.go b/internal/prefer_openssl/prefer_go1.5.go new file mode 100644 index 0000000..4b681e7 --- /dev/null +++ b/internal/prefer_openssl/prefer_go1.5.go @@ -0,0 +1,9 @@ +// +build !go1.6 +// = go 1.5 or lower + +package prefer_openssl + +func PreferOpenSSL() bool { + // OpenSSL is always faster than Go GCM on old Go versions. + return true +} diff --git a/internal/prefer_openssl/prefer_go1.6.go b/internal/prefer_openssl/prefer_go1.6.go new file mode 100644 index 0000000..5d0f426 --- /dev/null +++ b/internal/prefer_openssl/prefer_go1.6.go @@ -0,0 +1,13 @@ +// +build go1.6 +// = go 1.6 or higher + +package prefer_openssl + +// 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 { + return filePreferOpenSSL("/proc/cpuinfo") +} diff --git a/internal/prefer_openssl/prefer_test.go b/internal/prefer_openssl/prefer_test.go new file mode 100644 index 0000000..a2ed737 --- /dev/null +++ b/internal/prefer_openssl/prefer_test.go @@ -0,0 +1,23 @@ +package prefer_openssl + +import ( + "testing" +) + +func TestCurrentCPU(t *testing.T) { + t.Logf("PreferOpenSSL=%v", PreferOpenSSL()) +} + +// Has AES instructions +func TestXeonE312xx(t *testing.T) { + if filePreferOpenSSL("cpuinfo.xeon_e312xx.txt") == true { + t.Fail() + } +} + +// Pentium G do not have AES instructions +func TestPentiumG630(t *testing.T) { + if filePreferOpenSSL("cpuinfo.pentium_g630.txt") == false { + t.Fail() + } +} diff --git a/main.go b/main.go index 8e6e565..d9a37f0 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/prefer_openssl" "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,18 +183,29 @@ 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 = prefer_openssl.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 } - // "-v" - if args.version { - printVersion() - os.Exit(0) - } if args.debug { toggledlog.Debug.Enabled = true - toggledlog.Debug.Printf("Debug output enabled") + } + // "-v" + if args.version { + toggledlog.Debug.Printf("openssl=%v\n", args.openssl) + printVersion() + os.Exit(0) } if args.wpanic { toggledlog.Warn.Wpanic = true @@ -255,7 +269,9 @@ func main() { } // "-openssl" if args.openssl == false { - toggledlog.Info.Printf("Openssl disabled") + toggledlog.Debug.Printf("OpenSSL disabled, using Go GCM") + } else { + toggledlog.Debug.Printf("OpenSSL enabled") } // Operation flags: init, passwd or mount // "-init"