diff options
| -rw-r--r-- | .travis.yml | 1 | ||||
| -rw-r--r-- | cli_args.go | 3 | ||||
| -rwxr-xr-x | gocryptfs.gz | bin | 0 -> 1849694 bytes | |||
| -rw-r--r-- | internal/speed/speed.go | 120 | ||||
| -rw-r--r-- | internal/speed/speed_test.go | 29 | ||||
| -rw-r--r-- | internal/stupidgcm/stupidgcm_test.go | 58 | ||||
| -rw-r--r-- | main.go | 6 | 
7 files changed, 158 insertions, 59 deletions
| diff --git a/.travis.yml b/.travis.yml index 5fea238..20fc6c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,7 @@ script:    - go build    - ./build-without-openssl.bash    - ./build.bash +  - ./gocryptfs -speed    - ./test.bash  # fuse on travis diff --git a/cli_args.go b/cli_args.go index 25392c4..f52d265 100644 --- a/cli_args.go +++ b/cli_args.go @@ -18,7 +18,7 @@ type argContainer struct {  	debug, init, zerokey, fusedebug, openssl, passwd, fg, version,  	plaintextnames, quiet, nosyslog, wpanic,  	longnames, allow_other, ro, reverse, aessiv, nonempty, raw64, -	noprealloc bool +	noprealloc, speed bool  	masterkey, mountpoint, cipherdir, cpuprofile, extpass,  	memprofile, ko, passfile, ctlsock, fsname string  	// Configuration file name override @@ -110,6 +110,7 @@ func parseCliOpts() (args argContainer) {  	flagSet.BoolVar(&args.nonempty, "nonempty", false, "Allow mounting over non-empty directories")  	flagSet.BoolVar(&args.raw64, "raw64", false, "Use unpadded base64 for file names")  	flagSet.BoolVar(&args.noprealloc, "noprealloc", false, "Disable preallocation before writing") +	flagSet.BoolVar(&args.speed, "speed", false, "Run crypto speed test")  	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") diff --git a/gocryptfs.gz b/gocryptfs.gzBinary files differ new file mode 100755 index 0000000..9c90b18 --- /dev/null +++ b/gocryptfs.gz diff --git a/internal/speed/speed.go b/internal/speed/speed.go new file mode 100644 index 0000000..f9bf93c --- /dev/null +++ b/internal/speed/speed.go @@ -0,0 +1,120 @@ +// Package speed implements the "-speed" command-line option, +// similar to "openssl speed". +// It benchmarks the crypto algorithms and libraries used by +// gocryptfs. +package speed + +import ( +	"crypto/aes" +	"crypto/cipher" +	"crypto/rand" +	"fmt" +	"log" +	"testing" + +	"github.com/rfjakob/gocryptfs/internal/prefer_openssl" +	"github.com/rfjakob/gocryptfs/internal/siv_aead" +	"github.com/rfjakob/gocryptfs/internal/stupidgcm" +) + +func Run() { +	bTable := []struct { +		name      string +		f         func(*testing.B) +		preferred bool +	}{ +		{name: "AES-GCM-256-OpenSSL", f: bStupidGCM, preferred: prefer_openssl.PreferOpenSSL()}, +		{name: "AES-GCM-256-Go", f: bGoGCM, preferred: !prefer_openssl.PreferOpenSSL()}, +		{name: "AES-SIV-512-Go", f: bAESSIV, preferred: false}, +	} +	for _, b := range bTable { +		fmt.Printf("%-20s\t", b.name) +		mbs := mbPerSec(testing.Benchmark(b.f)) +		if mbs > 0 { +			fmt.Printf("%7.2f MB/s", mbs) +		} else { +			fmt.Printf("    N/A") +		} +		if b.preferred { +			fmt.Printf("\t(selected in auto mode)\n") +		} else { +			fmt.Printf("\t\n") +		} +	} +} + +func mbPerSec(r testing.BenchmarkResult) float64 { +	if r.Bytes <= 0 || r.T <= 0 || r.N <= 0 { +		return 0 +	} +	return (float64(r.Bytes) * float64(r.N) / 1e6) / r.T.Seconds() +} + +// Get "n" random bytes from /dev/urandom or panic +func randBytes(n int) []byte { +	b := make([]byte, n) +	_, err := rand.Read(b) +	if err != nil { +		log.Panic("Failed to read random bytes: " + err.Error()) +	} +	return b +} + +const blockSize = 4096 + +func bStupidGCM(b *testing.B) { +	if stupidgcm.BuiltWithoutOpenssl { +		b.Skip("openssl has been disabled at compile-time") +	} +	key := randBytes(32) +	authData := randBytes(24) +	iv := randBytes(16) +	in := make([]byte, blockSize) +	b.SetBytes(int64(len(in))) + +	sGCM := stupidgcm.New(key) + +	b.ResetTimer() +	for i := 0; i < b.N; i++ { +		// Encrypt and append to nonce +		sGCM.Seal(iv, iv, in, authData) +	} +} + +func bGoGCM(b *testing.B) { +	key := randBytes(32) +	authData := randBytes(24) +	iv := randBytes(16) +	in := make([]byte, blockSize) +	b.SetBytes(int64(len(in))) + +	gAES, err := aes.NewCipher(key) +	if err != nil { +		b.Fatal(err) +	} +	gGCM, err := cipher.NewGCMWithNonceSize(gAES, 16) +	if err != nil { +		b.Fatal(err) +	} + +	b.ResetTimer() +	for i := 0; i < b.N; i++ { +		// Encrypt and append to nonce +		gGCM.Seal(iv, iv, in, authData) +	} +} + +func bAESSIV(b *testing.B) { +	key := randBytes(64) +	authData := randBytes(24) +	iv := randBytes(16) +	in := make([]byte, blockSize) +	b.SetBytes(int64(len(in))) +	gGCM := siv_aead.New(key) + +	b.ResetTimer() +	for i := 0; i < b.N; i++ { +		// Encrypt and append to nonce +		gGCM.Seal(iv, iv, in, authData) +	} +} diff --git a/internal/speed/speed_test.go b/internal/speed/speed_test.go new file mode 100644 index 0000000..1e9d859 --- /dev/null +++ b/internal/speed/speed_test.go @@ -0,0 +1,29 @@ +package speed + +/* +Make the "-speed" benchmarks also accessible to the standard test system. +Example run: + +$ go test -bench . +BenchmarkStupidGCM-2   	  100000	     22552 ns/op	 181.62 MB/s +BenchmarkGoGCM-2       	   20000	     81871 ns/op	  50.03 MB/s +BenchmarkAESSIV-2      	   10000	    104623 ns/op	  39.15 MB/s +PASS +ok  	github.com/rfjakob/gocryptfs/internal/speed	6.022s +*/ + +import ( +	"testing" +) + +func BenchmarkStupidGCM(b *testing.B) { +	bStupidGCM(b) +} + +func BenchmarkGoGCM(b *testing.B) { +	bGoGCM(b) +} + +func BenchmarkAESSIV(b *testing.B) { +	bAESSIV(b) +} diff --git a/internal/stupidgcm/stupidgcm_test.go b/internal/stupidgcm/stupidgcm_test.go index d6c0714..ba25855 100644 --- a/internal/stupidgcm/stupidgcm_test.go +++ b/internal/stupidgcm/stupidgcm_test.go @@ -15,9 +15,6 @@ import (  	"encoding/hex"  	"log"  	"testing" - -	// For benchmark comparison -	"github.com/rfjakob/gocryptfs/internal/siv_aead"  )  // Get "n" random bytes from /dev/urandom or panic @@ -121,58 +118,3 @@ func TestCorruption(t *testing.T) {  		t.Fatalf("Should have gotten error")  	}  } - -// $ go test -bench . -// PASS -// Benchmark4kEncStupidGCM-2	   50000	     25622 ns/op	 159.86 MB/s -// Benchmark4kEncGoGCM-2    	   10000	    116544 ns/op	  35.15 MB/s -// ok  	github.com/rfjakob/gocryptfs/internal/stupidgcm	3.775s -func Benchmark4kEncStupidGCM(b *testing.B) { -	key := randBytes(32) -	authData := randBytes(24) -	iv := randBytes(16) -	in := make([]byte, 4096) -	b.SetBytes(int64(len(in))) - -	sGCM := New(key) - -	for i := 0; i < b.N; i++ { -		// Encrypt and append to nonce -		sGCM.Seal(iv, iv, in, authData) -	} -} - -func Benchmark4kEncGoGCM(b *testing.B) { -	key := randBytes(32) -	authData := randBytes(24) -	iv := randBytes(16) -	in := make([]byte, 4096) -	b.SetBytes(int64(len(in))) - -	gAES, err := aes.NewCipher(key) -	if err != nil { -		b.Fatal(err) -	} -	gGCM, err := cipher.NewGCMWithNonceSize(gAES, 16) -	if err != nil { -		b.Fatal(err) -	} - -	for i := 0; i < b.N; i++ { -		// Encrypt and append to nonce -		gGCM.Seal(iv, iv, in, authData) -	} -} - -func Benchmark4kEncAESSIV(b *testing.B) { -	key := randBytes(32) -	authData := randBytes(24) -	iv := randBytes(16) -	in := make([]byte, 4096) -	b.SetBytes(int64(len(in))) -	gGCM := siv_aead.New(key) -	for i := 0; i < b.N; i++ { -		// Encrypt and append to nonce -		gGCM.Seal(iv, iv, in, authData) -	} -} @@ -13,6 +13,7 @@ import (  	"github.com/rfjakob/gocryptfs/internal/configfile"  	"github.com/rfjakob/gocryptfs/internal/contentenc"  	"github.com/rfjakob/gocryptfs/internal/readpassword" +	"github.com/rfjakob/gocryptfs/internal/speed"  	"github.com/rfjakob/gocryptfs/internal/stupidgcm"  	"github.com/rfjakob/gocryptfs/internal/tlog"  ) @@ -149,6 +150,11 @@ func main() {  		printVersion()  		os.Exit(0)  	} +	// "-speed" +	if args.speed { +		speed.Run() +		os.Exit(0) +	}  	if args.wpanic {  		tlog.Warn.Wpanic = true  		tlog.Debug.Printf("Panicing on warnings") | 
