From 5ef4ab0a41e98a4a794987899cf4326912944db9 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Thu, 12 Mar 2015 00:39:28 +0100 Subject: [PATCH 1/9] reverse: re-enable kernel cache Disabling the kernel cache make sure the encrypted view is always up-to-date, however, it causes a factor 3 slowdown. Please use --nocache manually if you want to disable caching. Closes #60. Also replaces the magic identifiers 513 and 514 by proper defines. --- encfs/main.cpp | 22 +++++++++++++++------- tests/reverse.t.pl | 2 +- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/encfs/main.cpp b/encfs/main.cpp index 728517f..d5e98c4 100644 --- a/encfs/main.cpp +++ b/encfs/main.cpp @@ -57,6 +57,11 @@ extern "C" void fuse_unmount_compat22(const char *mountpoint); #define fuse_unmount fuse_unmount_compat22 +/* Arbitrary identifiers for long options that do + * not have a short version */ +#define LONG_OPT_ANNOTATE 513 +#define LONG_OPT_NOCACHE 514 + using namespace std; using namespace rlog; using namespace rel; @@ -215,10 +220,10 @@ static bool processArgs(int argc, char *argv[], {"delaymount", 0, 0, 'M'}, // delay initial mount until use {"public", 0, 0, 'P'}, // public mode {"extpass", 1, 0, 'p'}, // external password program - // {"single-thread", 0, 0, 's'}, // single-threaded mode - {"stdinpass", 0, 0, 'S'}, // read password from stdin - {"annotate", 0, 0, 513}, // Print annotation lines to stderr - {"nocache", 0, 0, 514}, // disable caching + // {"single-thread", 0, 0, 's'}, // single-threaded mode + {"stdinpass", 0, 0, 'S'}, // read password from stdin + {"annotate", 0, 0, LONG_OPT_ANNOTATE}, // Print annotation lines to stderr + {"nocache", 0, 0, LONG_OPT_NOCACHE}, // disable caching {"verbose", 0, 0, 'v'}, // verbose mode {"version", 0, 0, 'V'}, // version {"reverse", 0, 0, 'r'}, // reverse encryption @@ -255,7 +260,7 @@ static bool processArgs(int argc, char *argv[], case 'S': out->opts->useStdin = true; break; - case 513: + case LONG_OPT_ANNOTATE: out->opts->annotate = true; break; case 'f': @@ -295,8 +300,11 @@ static bool processArgs(int argc, char *argv[], * filesystem where something can change the underlying * filesystem without going through fuse can run into * inconsistencies." - * Enabling reverse automatically enables noCache */ - case 514: + * However, disabling the caches causes a factor 3 + * slowdown. If you are concerned about inconsistencies, + * please use --nocache. */ + break; + case LONG_OPT_NOCACHE: /* Disable EncFS block cache * Causes reverse grow tests to fail because short reads * are returned */ diff --git a/tests/reverse.t.pl b/tests/reverse.t.pl index b7f9196..4f670c1 100755 --- a/tests/reverse.t.pl +++ b/tests/reverse.t.pl @@ -46,7 +46,7 @@ sub cleanup sub mount { delete $ENV{"ENCFS6_CONFIG"}; - system("./encfs/encfs --extpass=\"echo test\" --standard $plain $ciphertext --reverse"); + system("./encfs/encfs --extpass=\"echo test\" --standard $plain $ciphertext --reverse --nocache"); ok(waitForFile("$plain/.encfs6.xml"), "plain .encfs6.xml exists") or BAIL_OUT("'$plain/.encfs6.xml'"); my $e = encName(".encfs6.xml"); ok(waitForFile("$ciphertext/$e"), "encrypted .encfs6.xml exists") or BAIL_OUT("'$ciphertext/$e'"); From 0182dbf9d776feb7e019be899caecb7fb7a32341 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Sat, 14 Mar 2015 16:52:12 +0100 Subject: [PATCH 2/9] gitignore: add autogenerated po/*.gmo files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index fc67b7f..1ffb583 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,8 @@ Makefile.in /po/remove-potcdate.sed /po/Makefile.in.in /po/Rules-quot +/po/*.gmo +/po/stamp-po /m4/*.m4 !/m4/ax_boost_base.m4 From d14bedfff627646b5d9c63553f3339260d11f792 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Sun, 15 Mar 2015 15:34:17 +0100 Subject: [PATCH 3/9] encfs manpage: Document --nocache --- encfs/encfs.pod | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/encfs/encfs.pod b/encfs/encfs.pod index 125ca1e..d4e9abd 100644 --- a/encfs/encfs.pod +++ b/encfs/encfs.pod @@ -134,7 +134,7 @@ For example, the following would create an encrypted view in /tmp/crypt-view. encfs --reverse /home/me /tmp/crypt-view You could then copy the /tmp/crypt-view directory in order to have a copy of -the encrypted data. You must also keep a copy of the file /home/me/.encfs5 +the encrypted data. You must also keep a copy of the file /home/me/.encfs6.xml which contains the filesystem information. Together, the two can be used to reproduce the unencrypted data: @@ -145,6 +145,14 @@ Now /tmp/plain-view contains the same data as /home/me Note that B<--reverse> mode only works with limited configuration options, so many settings may be disabled when used. +=item B<--nocache> + +Disable the kernel's cache of file attributes. +Setting this option makes EncFS pass "attr_timeout=0" and "entry_timeout=0" to +FUSE. This makes sure that modifications to the backing files that occour +outside EncFS show up immediately in the EncFS mount. The main use case +for "--nocache" is reverse mode. + =item B<--standard> If creating a new filesystem, this automatically selects standard configuration From 21b3811f86d0803c30bd3baee34e1769d06597b1 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Sun, 15 Mar 2015 23:05:29 +0100 Subject: [PATCH 4/9] reverse mode: Disable unique IV by default Commit 76424a58cb71138e160ff013d976f9cb7a41a8cd enabled unique IV for reverse mode by default, to get more testing and to increase security of reverse mode. The downside is that all IVs change when the inode numbers change, which means that all of the ciphertext changes. This may bite people who copied the plaintext to a new filesystem - they will find out that they have to rsync everything again. This commit disables unique IV for reverse mode by default. It can still be enabled through expert mode. --- encfs/FileUtils.cpp | 26 ++++++++------------------ tests/reverse.t.pl | 4 ++-- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/encfs/FileUtils.cpp b/encfs/FileUtils.cpp index f658bf8..3dae887 100644 --- a/encfs/FileUtils.cpp +++ b/encfs/FileUtils.cpp @@ -893,13 +893,13 @@ static void selectBlockMAC(int *macBytes, int *macRandBytes) { /** * Ask the user if per-file unique IVs should be used */ -static bool selectUniqueIV() { +static bool selectUniqueIV(bool default_answer) { // xgroup(setup) - return boolDefaultYes( + return boolDefault( _("Enable per-file initialization vectors?\n" "This adds about 8 bytes per file to the storage requirements.\n" "It should not affect performance except possibly with applications\n" - "which rely on block-aligned file io for performance.")); + "which rely on block-aligned file io for performance."), default_answer); } /** @@ -977,8 +977,8 @@ RootPtr createV6Config(EncFS_Context *ctx, const shared_ptr &opts) { Interface nameIOIface; // selectNameCoding() int blockMACBytes = 0; // selectBlockMAC() int blockMACRandBytes = 0; // selectBlockMAC() - bool uniqueIV = false; // selectUniqueIV() - bool chainedIV = false; // selectChainedIV() + bool uniqueIV = true; // selectUniqueIV() + bool chainedIV = true; // selectChainedIV() bool externalIV = false; // selectExternalChainedIV() bool allowHoles = true; // selectZeroBlockPassThrough() long desiredKDFDuration = NormalKDFDuration; @@ -986,6 +986,7 @@ RootPtr createV6Config(EncFS_Context *ctx, const shared_ptr &opts) { if (reverseEncryption) { chainedIV = false; externalIV = false; + uniqueIV = false; blockMACBytes = 0; blockMACRandBytes = 0; } @@ -1009,8 +1010,6 @@ RootPtr createV6Config(EncFS_Context *ctx, const shared_ptr &opts) { nameIOIface = BlockNameIO::CurrentInterface(); blockMACBytes = 8; blockMACRandBytes = 0; // using uniqueIV, so this isn't necessary - uniqueIV = true; - chainedIV = true; externalIV = true; desiredKDFDuration = ParanoiaKDFDuration; } else if (configMode == Config_Standard || answer[0] != 'x') { @@ -1021,16 +1020,7 @@ RootPtr createV6Config(EncFS_Context *ctx, const shared_ptr &opts) { keySize = 192; blockSize = DefaultBlockSize; alg = findCipherAlgorithm("AES", keySize); - blockMACBytes = 0; - externalIV = false; nameIOIface = BlockNameIO::CurrentInterface(); - uniqueIV = true; - - if (reverseEncryption) { - cout << _("reverse encryption - chained IV disabled") << "\n"; - } else { - chainedIV = true; - } } if (answer[0] == 'x' || alg.name.empty()) { @@ -1052,7 +1042,7 @@ RootPtr createV6Config(EncFS_Context *ctx, const shared_ptr &opts) { nameIOIface = selectNameCoding(); if (reverseEncryption) { cout << _("reverse encryption - chained IV and MAC disabled") << "\n"; - uniqueIV = selectUniqueIV(); + uniqueIV = selectUniqueIV(false); /* Reverse mounts are read-only by default (set in main.cpp). * If uniqueIV is off, writing can be allowed, because there * is no header that could be overwritten */ @@ -1060,7 +1050,7 @@ RootPtr createV6Config(EncFS_Context *ctx, const shared_ptr &opts) { opts->readOnly = false; } else { chainedIV = selectChainedIV(); - uniqueIV = selectUniqueIV(); + uniqueIV = selectUniqueIV(true); if (chainedIV && uniqueIV) externalIV = selectExternalChainedIV(); else { diff --git a/tests/reverse.t.pl b/tests/reverse.t.pl index 4f670c1..a8405a0 100755 --- a/tests/reverse.t.pl +++ b/tests/reverse.t.pl @@ -116,7 +116,7 @@ sub grow { # autoflush should make sure the write goes to the kernel # immediately. Just to be sure, check it here. sizeVerify($vfh, $i) or die("unexpected plain file size"); - sizeVerify($cfh, $i+8) or $ok = 0; + sizeVerify($cfh, $i) or $ok = 0; sizeVerify($dfh, $i) or $ok = 0; if(md5fh($vfh) ne md5fh($dfh)) @@ -137,7 +137,7 @@ sub largeRead { my $cname = encName("largeRead"); # cfh ... ciphertext file handle ok(open(my $cfh, "<", "$ciphertext/$cname"), "open ciphertext largeRead file"); - ok(sizeVerify($cfh, 1024*1024+8), "1M file size"); + ok(sizeVerify($cfh, 1024*1024), "1M file size"); } # Check that the reverse mount is read-only From c58d311569a18c24fb971fe059ebe277b22577cc Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Fri, 20 Mar 2015 00:12:51 +0100 Subject: [PATCH 5/9] tests: Complain loudly when encfs segfaults while mounting ...instead of having all later tests fail with strange error messages. --- tests/normal.t.pl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/normal.t.pl b/tests/normal.t.pl index b38a19d..e30befe 100755 --- a/tests/normal.t.pl +++ b/tests/normal.t.pl @@ -2,7 +2,7 @@ # Test EncFS normal and paranoid mode -use Test::More tests => 101; +use Test::More tests => 103; use File::Path; use File::Copy; use File::Temp; @@ -307,9 +307,11 @@ sub mount mkdir($crypt) || BAIL_OUT("Could not create $crypt: $!"); delete $ENV{"ENCFS6_CONFIG"}; - qx(./encfs/encfs --extpass="echo test" $args $raw $crypt); - - ok( -f "$raw/.encfs6.xml", "created control file"); + my $cmdline = "./encfs/encfs --extpass=\"echo test\" $args $raw $crypt 2>&1"; + # This makes sure we get to see stderr ^ + my $status = system($cmdline); + ok( $status == 0, "encfs command returns 0") || BAIL_OUT(""); + ok( -f "$raw/.encfs6.xml", "created control file") || BAIL_OUT(""); } # Helper function From 31568b1de5907dafc4d2321fb34a24ee3610ca1c Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Sun, 22 Mar 2015 15:53:25 +0100 Subject: [PATCH 6/9] tests: Add benchmark-reverse.pl Benchmarks "encfs --reverse" rsync performance. Run "make benchmark-reverse" to run it with default settings. --- Makefile.am | 5 +++ tests/benchmark-reverse.pl | 72 ++++++++++++++++++++++++++++++++++++++ tests/benchmark.pl | 48 +------------------------ tests/common.pl | 48 +++++++++++++++++++++++++ 4 files changed, 126 insertions(+), 47 deletions(-) create mode 100755 tests/benchmark-reverse.pl diff --git a/Makefile.am b/Makefile.am index 981ddbd..7e8ed35 100644 --- a/Makefile.am +++ b/Makefile.am @@ -26,3 +26,8 @@ test-verbose: .PHONY: benchmark benchmark: sudo tests/benchmark.pl /var/tmp + +.PHONY: benchmark-reverse +benchmark-reverse: + tests/benchmark-reverse.pl /var/tmp + tests/benchmark-reverse.pl /var/tmp --nocache diff --git a/tests/benchmark-reverse.pl b/tests/benchmark-reverse.pl new file mode 100755 index 0000000..1ba214c --- /dev/null +++ b/tests/benchmark-reverse.pl @@ -0,0 +1,72 @@ +#!/usr/bin/perl + +# Benchmark EncFS reverse mode + +use File::Temp; +use warnings; + +require("tests/common.pl"); + +sub mount_encfs_reverse { + my $p = shift; + my $c = shift; + my $opts = shift; + + my $cmdline = "./encfs/encfs --extpass=\"echo test\" --standard $p $c --reverse $opts 2>&1 > /dev/null"; + # print "mounting encfs: $cmdline\n"; + my $status = system($cmdline); + if ( $status != 0 ) { die("command returned error: $status"); } + waitForFile("$p/.encfs6.xml") or die("Control file not created"); + + # print "encfs --reverse mounted on $c\n"; +} + +sub cleanup { + print "cleaning up... "; + my $workingDir = shift; + for(my $i=0; $i<2; $i++) { + system("fusermount -u $workingDir/c") == 0 and last; + system("lsof $workingDir/c"); + printf "retrying... "; + sleep(1); + } + system("rm -Rf $workingDir 2> /dev/null"); + print "done\n"; +} + +sub main { + + my $prefix = shift(@ARGV) or die("Missing DIR argument"); + my $workingDir = mkdtemp("$prefix/encfs-performance-XXXX") + || die("Could not create temporary directory"); + + my $c = "$workingDir/c"; + my $p = "$workingDir/p"; + + my $opts = ""; + if ( @ARGV > 0 ) { + $opts = shift(@ARGV) + }; + + mkdir($c); + mkdir($p); + + dl_linuxgz(); + our $linuxgz; + system("tar xzf $linuxgz -C $p"); + + mount_encfs_reverse($p, $c, $opts); + + my @results = (); + stopwatch_start("rsync 1 (initial copy)"); + system("rsync -a $c/ $workingDir/rsync-target"); + stopwatch_stop(\@results); + + stopwatch_start("rsync 2 (no changes)"); + system("rsync -a $c/ $workingDir/rsync-target"); + stopwatch_stop(\@results); + + cleanup($workingDir); +} + +main(); diff --git a/tests/benchmark.pl b/tests/benchmark.pl index 0e134a4..f67f30d 100755 --- a/tests/benchmark.pl +++ b/tests/benchmark.pl @@ -2,21 +2,11 @@ # Benchmark EncFS against eCryptfs -use Time::HiRes qw( time ); use File::Temp; use warnings; -use feature 'state'; require("tests/common.pl"); -# Download linux-3.0.tar.gz unless it already exists ("-c" flag) -sub dl { - our $linuxgz = "/var/tmp/linux-3.0.tar.gz"; - print "# downloading linux-3.0.tar.gz (92MiB)... "; - 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; @@ -76,42 +66,6 @@ sub mount_ecryptfs { return $p; } -# Returns integer $milliseconds from float $seconds -sub ms { - my $seconds = shift; - my $milliseconds = int( $seconds * 1000 ); - return $milliseconds; -} - -# stopwatch_start($name) -# start the stopwatch for test "$name" -sub stopwatch_start { - stopwatch(1, shift); -} - -# stopwatch_stop(\@results) -# stop the stopwatch, save time into @results -sub stopwatch_stop { - stopwatch(0, shift); -} - -sub stopwatch { - state $start_time; - state $name; - my $start = shift; - - if($start) { - $name = shift; - print("# $name... "); - $start_time = time(); - } else { - my $delta = ms(time() - $start_time); - print("$delta ms\n"); - my $results = shift; - push( $results, [ $name, $delta, 'ms' ] ); - } -} - sub benchmark { my $dir = shift; our $linuxgz; @@ -205,7 +159,7 @@ sub main { exit(2); } - dl(); + dl_linuxgz(); my $workingDir; my $mountpoint; my $prefix; diff --git a/tests/common.pl b/tests/common.pl index 3a14e36..f3bf059 100755 --- a/tests/common.pl +++ b/tests/common.pl @@ -106,5 +106,53 @@ sub writeZeroes } } +# Returns integer $milliseconds from float $seconds +sub ms { + my $seconds = shift; + my $milliseconds = int( $seconds * 1000 ); + return $milliseconds; +} + +# stopwatch_start($name) +# start the stopwatch for test "$name" +sub stopwatch_start { + stopwatch(1, shift); +} + +# stopwatch_stop(\@results) +# stop the stopwatch, save time into @results +sub stopwatch_stop { + stopwatch(0, shift); +} + +# See stopwatch_{start,stop} above +use feature 'state'; +use Time::HiRes qw( time ); +sub stopwatch { + state $start_time; + state $name; + my $start = shift; + + if($start) { + $name = shift; + print("* $name... "); + $start_time = time(); + } else { + my $delta = ms(time() - $start_time); + print("$delta ms\n"); + my $results = shift; + push( $results, [ $name, $delta, 'ms' ] ); + } +} + +# Download linux-3.0.tar.gz unless it already exists ("-c" flag) +sub dl_linuxgz { + our $linuxgz = "/var/tmp/linux-3.0.tar.gz"; + if ( -e $linuxgz ) { return; } + print "downloading linux-3.0.tar.gz (92MiB)... "; + system("wget -nv -c https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.0.tar.gz -O $linuxgz"); + print "done\n"; +} + # As this file will be require()'d, it needs to return true return 1; From 82ceb88998fccfdbe21d2e66cd8764adef7d55e5 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Sun, 22 Mar 2015 16:41:29 +0100 Subject: [PATCH 7/9] Remove "-o default_permissions" unless needed. It is only needed when "-o allow_other" is specified. "-o default_permissions" causes libfuse to check file access in userspace. This costs CPU cycles and causes additional stat() calls - libfuse has to walk up the whole path to check for "x" permissions on directories. This improves "make benchmark-reverse" performance by 30% when caching is disabled. It also gives a slight improvement with caches on. Before: tests/benchmark-reverse.pl /var/tmp * rsync 1 (initial copy)... 12179 ms * rsync 2 (no changes)... 1840 ms cleaning up... done tests/benchmark-reverse.pl /var/tmp --nocache * rsync 1 (initial copy)... 30696 ms * rsync 2 (no changes)... 10552 ms cleaning up... done After: tests/benchmark-reverse.pl /var/tmp * rsync 1 (initial copy)... 12095 ms * rsync 2 (no changes)... 1693 ms cleaning up... done tests/benchmark-reverse.pl /var/tmp --nocache * rsync 1 (initial copy)... 21266 ms * rsync 2 (no changes)... 6486 ms cleaning up... done --- encfs/main.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/encfs/main.cpp b/encfs/main.cpp index d5e98c4..9281e60 100644 --- a/encfs/main.cpp +++ b/encfs/main.cpp @@ -367,13 +367,6 @@ static bool processArgs(int argc, char *argv[], if (!out->isThreaded) PUSHARG("-s"); - if (useDefaultFlags) { - PUSHARG("-o"); - PUSHARG("use_ino"); - PUSHARG("-o"); - PUSHARG("default_permissions"); - } - // we should have at least 2 arguments left over - the source directory and // the mount point. if (optind + 2 <= argc) { @@ -396,6 +389,26 @@ static bool processArgs(int argc, char *argv[], } } + // Add default flags unless --no-default-flags was passed + if (useDefaultFlags) { + + // Expose the underlying stable inode number + PUSHARG("-o"); + PUSHARG("use_ino"); + + // "default_permissions" comes with a performance cost. Only enable + // it if makes sense. + for(int i=0; i < out->fuseArgc; i++) { + if ( out->fuseArgv[i] == NULL ) { + continue; + } else if (strcmp(out->fuseArgv[i], "allow_other") == 0) { + PUSHARG("-o"); + PUSHARG("default_permissions"); + break; + } + } + } + // sanity check if (out->isDaemon && (!isAbsolutePath(out->mountPoint.c_str()) || !isAbsolutePath(out->opts->rootDir.c_str()))) { From 9d06412f1c68b0607f27f2a4434a2801fa807a2d Mon Sep 17 00:00:00 2001 From: Eric Swanson Date: Fri, 20 Mar 2015 22:11:10 -0700 Subject: [PATCH 8/9] Work around #14 (Editing Configuration File Disables MACs) with "--require-macs" This patch implements the workaround proposed by https://defuse.ca/audits/encfs.htm to create a --require-macs command line argument. If this argument is passed, encfs will refuse to mount with MACs disabled. When creating a filesystem, encfs will force MACs to be enabled. Addressed CR comments, and added docs. --- encfs/FileUtils.cpp | 35 ++++++++++++++++++++++++++--------- encfs/FileUtils.h | 3 +++ encfs/encfs.pod | 9 +++++++++ encfs/main.cpp | 6 ++++++ 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/encfs/FileUtils.cpp b/encfs/FileUtils.cpp index 3dae887..60ca86f 100644 --- a/encfs/FileUtils.cpp +++ b/encfs/FileUtils.cpp @@ -855,14 +855,21 @@ static bool boolDefaultYes(const char *prompt) { /** * Ask the user whether to enable block MAC and random header bytes */ -static void selectBlockMAC(int *macBytes, int *macRandBytes) { - // xgroup(setup) - bool addMAC = boolDefaultNo( - _("Enable block authentication code headers\n" - "on every block in a file? This adds about 12 bytes per block\n" - "to the storage requirements for a file, and significantly affects\n" - "performance but it also means [almost] any modifications or errors\n" - "within a block will be caught and will cause a read error.")); +static void selectBlockMAC(int *macBytes, int *macRandBytes, bool forceMac) { + bool addMAC = false; + if (!forceMac) { + // xgroup(setup) + addMAC = boolDefaultNo( + _("Enable block authentication code headers\n" + "on every block in a file? This adds about 12 bytes per block\n" + "to the storage requirements for a file, and significantly affects\n" + "performance but it also means [almost] any modifications or errors\n" + "within a block will be caught and will cause a read error.")); + } else { + cout << _("\n\nYou specified --require-macs. " + "Enabling block authentication code headers...\n\n"); + addMAC = true; + } if (addMAC) *macBytes = 8; @@ -1021,6 +1028,10 @@ RootPtr createV6Config(EncFS_Context *ctx, const shared_ptr &opts) { blockSize = DefaultBlockSize; alg = findCipherAlgorithm("AES", keySize); nameIOIface = BlockNameIO::CurrentInterface(); + + if (opts->requireMac) { + blockMACBytes = 8; + } } if (answer[0] == 'x' || alg.name.empty()) { @@ -1060,7 +1071,7 @@ RootPtr createV6Config(EncFS_Context *ctx, const shared_ptr &opts) { << "\n"; externalIV = false; } - selectBlockMAC(&blockMACBytes, &blockMACRandBytes); + selectBlockMAC(&blockMACBytes, &blockMACRandBytes, opts->requireMac); allowHoles = selectZeroBlockPassThrough(); } } @@ -1490,6 +1501,12 @@ RootPtr initFS(EncFS_Context *ctx, const shared_ptr &opts) { shared_ptr config(new EncFSConfig); if (readConfig(opts->rootDir, config) != Config_None) { + if (config->blockMACBytes == 0 && opts->requireMac) { + cout + << _("The configuration disabled MAC, but you passed --require-macs\n"); + return rootInfo; + } + if (opts->reverseEncryption) { if (config->blockMACBytes != 0 || config->blockMACRandBytes != 0 || config->externalIVChaining || diff --git a/encfs/FileUtils.h b/encfs/FileUtils.h index 0cedb14..2e4f512 100644 --- a/encfs/FileUtils.h +++ b/encfs/FileUtils.h @@ -88,6 +88,8 @@ struct EncFS_Opts { bool readOnly; // Mount read-only + bool requireMac; // Throw an error if MAC is disabled + ConfigMode configMode; EncFS_Opts() { @@ -104,6 +106,7 @@ struct EncFS_Opts { configMode = Config_Prompt; noCache = false; readOnly = false; + requireMac = false; } }; diff --git a/encfs/encfs.pod b/encfs/encfs.pod index d4e9abd..9cfc581 100644 --- a/encfs/encfs.pod +++ b/encfs/encfs.pod @@ -121,6 +121,15 @@ password. If this succeeds, then the filesystem becomes available again. Do not mount the filesystem when encfs starts; instead, delay mounting until first use. This option only makes sense with B<--ondemand>. +=item B<--require-macs> + +If creating a new filesystem, this forces block authentication code headers to +be enabled. When mounting an existing filesystem, this causes encfs to exit +if block authentication code headers are not enabled. + +This can be used to improve security in case the ciphertext is vulnerable to +tampering, by preventing an attacker from disabling MACs in the config file. + =item B<--reverse> Normally B provides a plaintext view of data on demand. Normally it diff --git a/encfs/main.cpp b/encfs/main.cpp index 9281e60..0fdcb0c 100644 --- a/encfs/main.cpp +++ b/encfs/main.cpp @@ -61,6 +61,7 @@ extern "C" void fuse_unmount_compat22(const char *mountpoint); * not have a short version */ #define LONG_OPT_ANNOTATE 513 #define LONG_OPT_NOCACHE 514 +#define LONG_OPT_REQUIRE_MAC 515 using namespace std; using namespace rlog; @@ -195,6 +196,7 @@ static bool processArgs(int argc, char *argv[], out->opts->useStdin = false; out->opts->annotate = false; out->opts->reverseEncryption = false; + out->opts->requireMac = false; bool useDefaultFlags = true; @@ -229,6 +231,7 @@ static bool processArgs(int argc, char *argv[], {"reverse", 0, 0, 'r'}, // reverse encryption {"standard", 0, 0, '1'}, // standard configuration {"paranoia", 0, 0, '2'}, // standard configuration + {"require-macs", 0, 0, LONG_OPT_REQUIRE_MAC}, // require MACs {0, 0, 0, 0}}; while (1) { @@ -263,6 +266,9 @@ static bool processArgs(int argc, char *argv[], case LONG_OPT_ANNOTATE: out->opts->annotate = true; break; + case LONG_OPT_REQUIRE_MAC: + out->opts->requireMac = true; + break; case 'f': out->isDaemon = false; // this option was added in fuse 2.x From 17e12d3e9aa7e5b6ffec4b8dffb8041ff107d764 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Sun, 22 Mar 2015 22:02:22 +0100 Subject: [PATCH 9/9] Bump version to 1.8.1 and update changelog --- ChangeLog | 20 ++++++++++++++++++++ configure.ac | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 8691eeb..2b1df33 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +Sun Mar 22 2015 Jakob Unterwurzacher + * release version 1.8.1 + * reverse: re-enable kernel cache (bug #60) + * reverse mode: disable unique IV by default + * add "make benchmark-reverse" + * remove "-o default_permissions" to improve performance + +Fri Mar 20 2015 Eric Swanson + * add option "--require-macs" (bug #14) + +Fri Mar 13 2015 Valient Gough + * add po files to git (bug #63) + +Mon Mar 9 2015 Jakob Unterwurzacher + * release version 1.8 + * improve automatic test converage: also test reverse mode (make test) + * add automatic benchmark (make benchmark) + * compare MAC in constant time ( fixes bug #12 ) + * lots of fixes to make building on OSX easier + Sun Nov 23 2014 Jakob Unterwurzacher * add per-file IVs to reverse mode * add --nocache option diff --git a/configure.ac b/configure.ac index cbf003e..7db5d12 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT([encfs], [1.8]) +AC_INIT([encfs], [1.8.1]) AC_CONFIG_SRCDIR([encfs/encfs.h]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([m4])