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.
This commit is contained in:
Eric Swanson 2015-03-20 22:11:10 -07:00 committed by Jakob Unterwurzacher
parent 82ceb88998
commit 9d06412f1c
4 changed files with 44 additions and 9 deletions

View File

@ -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<EncFS_Opts> &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<EncFS_Opts> &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<EncFS_Opts> &opts) {
shared_ptr<EncFSConfig> 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 ||

View File

@ -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;
}
};

View File

@ -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<EncFS> provides a plaintext view of data on demand. Normally it

View File

@ -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