From 1c5c75c44fd4ad83535280858c6be7a64b172f22 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Mon, 8 Dec 2014 17:39:10 +0100 Subject: [PATCH 1/7] tests: Name all tests ".t.pl" This way, everything (for example, common.inc) can have its proper ".pl" ending and syntax highlighting works properly in every editor. --- Makefile.am | 4 ++-- tests/{common.inc => common.pl} | 0 tests/{normal.pl => normal.t.pl} | 2 +- tests/{reverse.pl => reverse.t.pl} | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename tests/{common.inc => common.pl} (100%) mode change 100644 => 100755 rename tests/{normal.pl => normal.t.pl} (99%) mode change 100644 => 100755 rename tests/{reverse.pl => reverse.t.pl} (99%) diff --git a/Makefile.am b/Makefile.am index 020fa7a..6689589 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,8 +17,8 @@ ACLOCAL_AMFLAGS = -I m4 .PHONY: test test: - perl -MTest::Harness -e '$$Test::Harness::verbose=0; runtests @ARGV;' tests/*.pl + perl -MTest::Harness -e '$$Test::Harness::verbose=0; runtests @ARGV;' tests/*.t.pl .PHONY: test-verbose test-verbose: - perl -MTest::Harness -e '$$Test::Harness::verbose=1; runtests @ARGV;' tests/*.pl + perl -MTest::Harness -e '$$Test::Harness::verbose=1; runtests @ARGV;' tests/*.t.pl diff --git a/tests/common.inc b/tests/common.pl old mode 100644 new mode 100755 similarity index 100% rename from tests/common.inc rename to tests/common.pl diff --git a/tests/normal.pl b/tests/normal.t.pl old mode 100644 new mode 100755 similarity index 99% rename from tests/normal.pl rename to tests/normal.t.pl index 572ef03..7f0d779 --- a/tests/normal.pl +++ b/tests/normal.t.pl @@ -8,7 +8,7 @@ use File::Copy; use File::Temp; use IO::Handle; -require("tests/common.inc"); +require("tests/common.pl"); my $tempDir = $ENV{'TMPDIR'} || "/tmp"; diff --git a/tests/reverse.pl b/tests/reverse.t.pl similarity index 99% rename from tests/reverse.pl rename to tests/reverse.t.pl index 2c073e8..35a98b8 100755 --- a/tests/reverse.pl +++ b/tests/reverse.t.pl @@ -9,7 +9,7 @@ use File::Temp; use IO::Handle; use Errno qw(EROFS); -require("tests/common.inc"); +require("tests/common.pl"); my $tempDir = $ENV{'TMPDIR'} || "/tmp"; From 9feb263deaf34e7cae9260c97e644cfff304a842 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Mon, 8 Dec 2014 18:05:44 +0100 Subject: [PATCH 2/7] tests: Add benchmark.pl - benchmark EncFS against eCryptfs Example Results * Seagate Barracuda 7200.9, model ST3250824AS * Linux 3.16.3 * EncFS 1c5c75c44fd4ad83535280858c6be7a64b172f22 Test | EncFS | eCryptfs | EncFS advantage ----------------|--------------|--------------|---------------- stream_write | 32 MiB/s | 38 MiB/s | 0.84 extract | 28744 ms | 30027 ms | 1.04 du | 495 MB | 784 MB | 1.58 rsync | 3319 ms | 62486 ms | 18.83 delete | 6462 ms | 74652 ms | 11.55 (eCryptfs is very slow for stat() on a classical HDD) --- tests/benchmark.pl | 194 ++++++++++++++++++++++++++++++++++++ tests/mount-ecryptfs.expect | 22 ++++ 2 files changed, 216 insertions(+) create mode 100755 tests/benchmark.pl create mode 100644 tests/mount-ecryptfs.expect diff --git a/tests/benchmark.pl b/tests/benchmark.pl new file mode 100755 index 0000000..d81dbda --- /dev/null +++ b/tests/benchmark.pl @@ -0,0 +1,194 @@ +#!/usr/bin/perl + +# Benchmark EncFS against eCryptfs + +use Time::HiRes qw( time ); +use File::Temp; +use warnings; + +require("tests/common.pl"); + +# Download linux-3.0.tar.gz unless it already exists ("-c" flag) +sub dl { + our $linuxgz = "/tmp/linux-3.0.tar.gz"; + print "# downloading linux-3.0.tar.gz... "; + system("wget -nv -c https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.0.tar.gz -O $linuxgz"); + print "done\n"; +} + +# Create a new empty working directory +sub newWorkingDir { + my $prefix = shift; + my $workingDir = mkdtemp("$prefix/encfs-performance-XXXX") + || die("Could not create temporary directory"); + + return $workingDir; +} + +sub cleanup { + print "cleaning up..."; + my $workingDir = shift; + system("umount $workingDir/ecryptfs_plaintext"); + system("fusermount -u $workingDir/encfs_plaintext"); + system("rm -Rf $workingDir"); + print "done\n"; +} + +sub mount_encfs { + my $workingDir = shift; + + my $c = "$workingDir/encfs_ciphertext"; + my $p = "$workingDir/encfs_plaintext"; + + mkdir($c); + mkdir($p); + + delete $ENV{"ENCFS6_CONFIG"}; + system("./encfs/encfs --extpass=\"echo test\" --standard $c $p > /dev/null"); + waitForFile("$c/.encfs6.xml") or die("Control file not created"); + + print "# encfs mounted on $p\n"; + + return $p; +} + +sub mount_ecryptfs { + my $workingDir = shift; + + my $c = "$workingDir/ecryptfs_ciphertext"; + my $p = "$workingDir/ecryptfs_plaintext"; + + mkdir($c); + mkdir($p); + + system("expect -c \"spawn mount -t ecryptfs $c $p\" ./tests/mount-ecryptfs.expect > /dev/null") == 0 + or die("ecryptfs mount failed - are you root?"); + + print "# ecryptfs mounted on $p\n"; + + return $p; +} + +# Returns integer $milliseconds from float $seconds +sub ms { + my $seconds = shift; + my $milliseconds = int( $seconds * 1000 ); + return $milliseconds; +} + +sub benchmark { + my $dir = shift; + my $start; + our $linuxgz; + my $delta; + my $line; + + my @results = (); + + system("sync"); + print("# stream_write... "); + $start = time(); + writeZeroes( "$dir/zero", 1024 * 1024 * 100 ); + system("sync"); + $delta = time() - $start; + push( @results, [ 'stream_write', int( 100 / $delta ), "MiB/s" ] ); + printf("done\n"); + unlink("$dir/zero"); + + system("sync"); + system("cat $linuxgz > /dev/null"); + print("# extract... "); + $start = time(); + system("tar xzf $linuxgz -C $dir"); + system("sync"); + $delta = ms( time() - $start ); + push( @results, [ 'extract', $delta, "ms" ] ); + print("done\n"); + + $du = qx(du -sm $dir | cut -f1); + push( @results, [ 'du', $du, 'MB' ] ); + printf( "# disk space used: %d MB\n", $du ); + + system("echo 3 > /proc/sys/vm/drop_caches"); + $start = time(); + system("rsync -an $dir /tmp"); + $delta = time() - $start; + push( @results, [ 'rsync', ms($delta), 'ms' ] ); + printf( "# rsync took %d ms\n", ms($delta) ); + + system("echo 3 > /proc/sys/vm/drop_caches"); + system("sync"); + $start = time(); + system("rm -Rf $dir/*"); + system("sync"); + $delta = time() - $start; + push( @results, [ 'delete', ms($delta), 'ms' ] ); + printf( "# delete took %d ms\n", ms($delta) ); + + return \@results; +} + +sub tabulate { + my $r; + + $r = shift; + my @encfs = @{$r}; + $r = shift; + my @ecryptfs = @{$r}; + + print "Test | EncFS | eCryptfs | EncFS advantage\n"; + print "----------------|--------------|--------------|----------------\n"; + + for ( my $i = 0 ; $i <= $#encfs ; $i++ ) { + my $test = $encfs[$i][0]; + my $unit = $encfs[$i][2]; + + my $en = $encfs[$i][1]; + my $ec = $ecryptfs[$i][1]; + + my $ratio = $ec / $en; + if ( $unit =~ m!/s! ) { + $ratio = $en / $ec; + } + printf( "%-15s | %6d %-5s | %6d %-5s | %2.2f\n", + $test, $en, $unit, $ec, $unit, $ratio ); + } +} + +sub main { + if ( $#ARGV < 0 ) { + print "Usage: test/benchmark.pl MOUNTPOINT [MOUNTPOINT] [...]\n"; + exit(1); + } + + if ( $> != 0 ) { + print("This test must be run as root!\n"); + exit(2); + } + + dl(); + my $workingDir; + my $mountpoint; + my $prefix; + + while ( $prefix = shift(@ARGV) ) { + $workingDir = newWorkingDir($prefix); + + print "# mounting encfs\n"; + $mountpoint = mount_encfs($workingDir); + my $encfs_results = benchmark($mountpoint); + + print "# mounting ecryptfs\n"; + $mountpoint = mount_ecryptfs($workingDir); + my $ecryptfs_results = benchmark($mountpoint); + + cleanup($workingDir); + + print "\nResults for $prefix\n"; + print "==============================\n\n"; + tabulate( $encfs_results, $ecryptfs_results ); + print "\n"; + } +} + +main(); diff --git a/tests/mount-ecryptfs.expect b/tests/mount-ecryptfs.expect new file mode 100644 index 0000000..a2d3ba7 --- /dev/null +++ b/tests/mount-ecryptfs.expect @@ -0,0 +1,22 @@ +#!/bin/expect -f + +# Passed by controlling process via "-c" +#spawn mount -t ecryptfs ecryptfs_ciphertext ecryptfs_plaintext + +expect "Selection: " +send "1\n" +expect "Passphrase: " +send "test\n" +expect "Selection \\\[aes\\\]: " +send "aes\n" +expect "Selection \\\[16\\\]: " +send "16\n" +expect "Enable plaintext passthrough (y/n) \\\[n\\\]: " +send "n\n" +expect "Enable filename encryption (y/n) \\\[n\\\]: " +send "y\n" +# Filename Encryption Key (FNEK) Signature [d395309aaad4de06]: +expect "\\\]: " +send "\n" +expect "Mounted eCryptfs" +send_user "\n" From f4d100648f467a05e687b14f01ad43d290524f04 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Mon, 8 Dec 2014 18:14:35 +0100 Subject: [PATCH 3/7] Rename README to DESIGN.md and link to it in README.md This document provides a nice overview and should be presented prominently. --- README => DESIGN.md | 0 README.md | 2 ++ 2 files changed, 2 insertions(+) rename README => DESIGN.md (100%) diff --git a/README b/DESIGN.md similarity index 100% rename from README rename to DESIGN.md diff --git a/README.md b/README.md index 2a29d02..43690f2 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ EncFS encrypts individual files, by translating all requests for the virtual EncFS filesystem into the equivalent encrypted operations on the raw filesystem. +For more technical details and a usage overview, see [DESIGN.md](DESIGN.md). + ## Status Over the last 10 years, a number of good alternatives have grown up. Computing From ca6c46e2dc411507125c031957745b6914cde7f0 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Mon, 8 Dec 2014 18:20:15 +0100 Subject: [PATCH 4/7] DESIGN.md: Add markdown headings --- DESIGN.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/DESIGN.md b/DESIGN.md index 7cb63cb..cb5e87e 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -1,4 +1,3 @@ - For notes about internationalization, see README-NLS. EncFS is a program which provides an encrypted virtual filesystem for Linux @@ -7,7 +6,8 @@ download the latest version of FUSE ). FUSE provides a loadable kernel module which exports a filesystem interface to user-mode. EncFS runs entirely in user-mode and acts as a transparent encrypted filesystem. -Usage: +Usage +----- - To see command line options, see the man page for encfs and encfsctl, or for brief usage message, run the programs without an argument (or '-h'): @@ -33,7 +33,8 @@ Usage: created. -Technology: +Technology +---------- - Encfs uses algorithms from third-party libraries (OpenSSL is the default) to encrypt data and filenames. @@ -92,7 +93,8 @@ Technology: file has a unique initialization vector. This makes it infeasible to copy a whole block from one file to another. -Backward Compatibility: +Backward Compatibility +---------------------- At the top level of the raw (encrypted) storage for an EncFS filesystem is a configuration file, created automatically by EncFS when a new filesystem is @@ -109,7 +111,8 @@ Backward Compatibility: newer versions use algorithms and/or new options which were not previously available. -Utility: +Utility +------- In addition to the "encfs" main program, a utility "encfsctl" has been provided which can perform some operations on encfs filesystems. Encfsctl @@ -117,7 +120,8 @@ Utility: algorithm used, key length, block size), and more importantly it can also change the user-supplied password used to encrypt the volume key. -Dependencies: +Dependencies +------------ Encfs uses the OpenSSL toolkit (http://www.openssl.org) by default. OpenSSL is not covered by the GPL, and some people are concerned about the From b9c8b5cb4768ec3a6c63ce7cda3240090aef4540 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Mon, 8 Dec 2014 18:43:01 +0100 Subject: [PATCH 5/7] Put benchmark results into PERFORMANCE.md --- PERFORMANCE.md | 103 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 PERFORMANCE.md diff --git a/PERFORMANCE.md b/PERFORMANCE.md new file mode 100644 index 0000000..52e406a --- /dev/null +++ b/PERFORMANCE.md @@ -0,0 +1,103 @@ +EncFS Performance +================= + +EncFS runs in user-space while eCryptfs runs in the kernel. +This is why it is often assumed that eCryptfs is faster than EncFS. +To compare the actual performance of EncFS and eCryptfs on top of +different backing disks, the EncFS test suite contains an automated +performance test - [benchmark.pl](tests/benchmark.pl). + +performance.pl takes care of setting up EncFS and eCryptfs mounts, +clearing caches and syncing disks between the tests, and also to unmount +and clean up everything in the end. + +It performance the following tests: + +* stream_write: Write 100MB of zeros in 4KB blocks +* extract: Extract the [linux-3.0.tar.gz archive](https://www.kernel.org/pub/linux/kernel/v3.x/) +* du: Disk space used after extraction, in megabytes +* rsync: Do an "rsync -an" of the extracted files. + This simulates an rsync to a destination that is + (almost) up-to-date. The workload consists mostly + of stat() calls. +* delete: Recursively delete the extracted files + +For EncFS, the [default options](tests/benchmark.pl#L47) are used. +This means: + +* AES with 192 bit key +* Filename encryption + +For eCryptfs, the [options used](tests/mount-ecryptfs.expect) are + +* AES with 128 bit key +* Filename encryption + +For all the details, take a look at [benchmark.pl](tests/benchmark.pl) . + +Results +------- +The performance of an overlay filesystem depends a lot on the performance +of the backing disk. This is why I have tested three different kinds of +disk: + +* Classic HDD: Seagate Barracuda 7200.9, model ST3250824AS +* Modern SSD: Samsung SSD 840 EVO 250GB +* Ramdisk: tmpfs mounted on /tmp + +All tests are performed on kernel 3.16.3, 64 bit, on an Intel Pentium +G630 (Sandy Bridge, 2 x 2.7GHz). + +If you want to replicate the test, just run + + sudo tests/benchmark.pl /path/to/test/directory + +(the test must be run as root as normal users cannot mount ecryptfs or +clear the caches) + +* HDD: Seagate Barracuda 7200.9 + +Test | EncFS | eCryptfs | EncFS advantage +----------------|-------------:|-------------:|---------------: +stream_write | 32 MiB/s | 38 MiB/s | 0.84 +extract | 28744 ms | 30027 ms | 1.04 +du | 495 MB | 784 MB | 1.58 +rsync | 3319 ms | 62486 ms | 18.83 +delete | 6462 ms | 74652 ms | 11.55 + + +* SSD: Samsung SSD 840 EVO 250GB + +Test | EncFS | eCryptfs | EncFS advantage +----------------|-------------:|-------------:|---------------: +stream_write | 53 MiB/s | 75 MiB/s | 0.71 +extract | 26129 ms | 9692 ms | 0.37 +du | 495 MB | 784 MB | 1.58 +rsync | 2725 ms | 8210 ms | 3.01 +delete | 5444 ms | 9130 ms | 1.68 + +* Ramdisk: tmpfs + +Test | EncFS | eCryptfs | EncFS advantage +----------------|-------------:|-------------:|---------------: +stream_write | 82 MiB/s | 111 MiB/s | 0.74 +extract | 22393 ms | 8117 ms | 0.36 +du | 485 MB | 773 MB | 1.59 +rsync | 1931 ms | 740 ms | 0.38 +delete | 4346 ms | 907 ms | 0.21 + +Interpretation +-------------- +eCryptfs uses a large per-file header (8 KB) which is a big disadvantage +on classic HDDs. For stat()-heavy operations on HDDs, EncFS is 18x faster. + +EncFS stores small files much more efficiently, which is why it consitently +uses less space than eCryptfs: zero-size files take no space at all, +other files get a 8-byte header. Because the filesystem allocates space +in 4KB blocks, the actually used disk space must be rounded up to 4096. + +plaintext size | EncFS raw | EncFS du | eCryptfs raw | eCryptfs du +--------------:|----------:|---------:|-------------:|------------: + 0 | 0 | 0 | 8192 | 8192 + 1 | 9 | 4096 | 12288 | 12288 +1024 | 1032 | 4096 | 12288 | 12288 From 9a64ff97c5c3a18b2b9780681e2635dbdd610f14 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Mon, 8 Dec 2014 19:34:50 +0100 Subject: [PATCH 6/7] benchmark.pl: Align numbers right in Markdown output --- tests/benchmark.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/benchmark.pl b/tests/benchmark.pl index d81dbda..f1ef1b2 100755 --- a/tests/benchmark.pl +++ b/tests/benchmark.pl @@ -136,8 +136,8 @@ sub tabulate { $r = shift; my @ecryptfs = @{$r}; - print "Test | EncFS | eCryptfs | EncFS advantage\n"; - print "----------------|--------------|--------------|----------------\n"; + print " Test | EncFS | eCryptfs | EncFS advantage\n"; + print ":---------------|-------------:|-------------:|---------------:\n"; for ( my $i = 0 ; $i <= $#encfs ; $i++ ) { my $test = $encfs[$i][0]; From 0a274fe77f64456536119b5e6ad0697f69e6d9eb Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Mon, 8 Dec 2014 19:37:30 +0100 Subject: [PATCH 7/7] Mention PERFORMANCE.md in README.md --- README.md | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 43690f2..a63501a 100644 --- a/README.md +++ b/README.md @@ -33,19 +33,30 @@ depends upon community interest. In order to make it easier for anyone to contribute, it is moving a new home on Github. So if you're interested in EncFS, please dive in! -EncFS still has a few unique features that may be interesing to you: +## Unique Features -* `--reverse` mode: Provides an encrypted view of an unencrypted folder. - This enables encrypted remote backups using standard tools like - rsync. -* EncFS is typically faster than ecryptfs for stat()-heavy workloads - when the backing device is a classical hard disk. - This is because ecryptfs has to to read each file header to determine - the file size - EncFS does not. This is one additional seek for each - stat. On SSDs that have virtually no seek time, that difference may - disappear. -* EncFS works on network file systems (NFS, CIFS...), while ecryptfs - is known to still have [problems][1]. +EncFS has a few features still not found anywhere else (as of Dec 2014) +that may be interesing to you: + +### Reverse mode + +`encfs --reverse` provides an encrypted view of an unencrypted folder. +This enables encrypted remote backups using standard tools like rsync. + +### Fast on classical HDDs + +EncFS is typically *much* faster than ecryptfs for stat()-heavy workloads +when the backing device is a classical hard disk. +This is because ecryptfs has to to read each file header to determine +the file size - EncFS does not. This is one additional seek for each +stat. +See [PERFORMANCE.md](PERFORMANCE.md) for detailed benchmarks on +HDD, SSD and ramdisk. + +### Works on top of network filesystems + +EncFS works on network file systems (NFS, CIFS...), while ecryptfs +is known to still have [problems][1]. ## GitHub Transition