From 5d99db5376ee6c0527c57be095d74f50e71cb3c2 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Thu, 26 Apr 2012 02:18:26 +0000 Subject: [PATCH 01/51] reformat files before major edits git-svn-id: http://encfs.googlecode.com/svn/trunk@78 db9cf616-1c43-0410-9cb8-a902689de0d6 --- encfs/FileUtils.cpp | 2694 ++++++++++++++++++++++--------------------- encfs/FileUtils.h | 94 +- 2 files changed, 1395 insertions(+), 1393 deletions(-) diff --git a/encfs/FileUtils.cpp b/encfs/FileUtils.cpp index 165ce21..9e89d5d 100644 --- a/encfs/FileUtils.cpp +++ b/encfs/FileUtils.cpp @@ -103,160 +103,162 @@ const int V6SubVersion = 20100713; // add version field for boost 1.42+ struct ConfigInfo { - const char *fileName; - ConfigType type; - const char *environmentOverride; - bool (*loadFunc)(const char *fileName, - const boost::shared_ptr &config, - ConfigInfo *cfg); - bool (*saveFunc)(const char *fileName, - const boost::shared_ptr &config); - int currentSubVersion; - int defaultSubVersion; + const char *fileName; + ConfigType type; + const char *environmentOverride; + bool (*loadFunc)(const char *fileName, + const boost::shared_ptr &config, + ConfigInfo *cfg); + bool (*saveFunc)(const char *fileName, + const boost::shared_ptr &config); + int currentSubVersion; + int defaultSubVersion; } ConfigFileMapping[] = { - {".encfs6.xml", Config_V6, "ENCFS6_CONFIG", readV6Config, writeV6Config, - V6SubVersion, 0 }, - // backward compatible support for older versions - {".encfs5", Config_V5, "ENCFS5_CONFIG", readV5Config, writeV5Config, - V5SubVersion, V5SubVersionDefault }, - {".encfs4", Config_V4, NULL, readV4Config, writeV4Config, 0, 0 }, - // no longer support earlier versions - {".encfs3", Config_V3, NULL, NULL, NULL, 0, 0 }, - {".encfs2", Config_Prehistoric, NULL, NULL, NULL, 0, 0 }, - {".encfs", Config_Prehistoric, NULL, NULL, NULL, 0, 0 }, - {NULL,Config_None, NULL, NULL, NULL, 0, 0}}; + {".encfs6.xml", Config_V6, "ENCFS6_CONFIG", readV6Config, writeV6Config, + V6SubVersion, 0 }, + // backward compatible support for older versions + {".encfs5", Config_V5, "ENCFS5_CONFIG", readV5Config, writeV5Config, + V5SubVersion, V5SubVersionDefault }, + {".encfs4", Config_V4, NULL, readV4Config, writeV4Config, 0, 0 }, + // no longer support earlier versions + {".encfs3", Config_V3, NULL, NULL, NULL, 0, 0 }, + {".encfs2", Config_Prehistoric, NULL, NULL, NULL, 0, 0 }, + {".encfs", Config_Prehistoric, NULL, NULL, NULL, 0, 0 }, + {NULL,Config_None, NULL, NULL, NULL, 0, 0}}; #include "boost-versioning.h" // define serialization helpers +// TODO(vgough): eliminate entirely namespace boost { - namespace serialization - { - template - void save(Archive &ar, const EncFSConfig &cfg, - unsigned int version) - { - (void)version; - // version 20 (aka 20100613) - if (cfg.subVersion == 0) - ar << make_nvp("version", V6SubVersion); - else - ar << make_nvp("version", cfg.subVersion); +namespace serialization +{ - ar << make_nvp("creator", cfg.creator); - ar << make_nvp("cipherAlg", cfg.cipherIface); - ar << make_nvp("nameAlg", cfg.nameIface); - ar << make_nvp("keySize", cfg.keySize); - ar << make_nvp("blockSize", cfg.blockSize); - ar << make_nvp("uniqueIV", cfg.uniqueIV); - ar << make_nvp("chainedNameIV", cfg.chainedNameIV); - ar << make_nvp("externalIVChaining", cfg.externalIVChaining); - ar << make_nvp("blockMACBytes", cfg.blockMACBytes); - ar << make_nvp("blockMACRandBytes", cfg.blockMACRandBytes); - ar << make_nvp("allowHoles", cfg.allowHoles); +template +void save(Archive &ar, const EncFSConfig &cfg, + unsigned int version) +{ + (void)version; + // version 20 (aka 20100613) + if (cfg.subVersion == 0) + ar << make_nvp("version", V6SubVersion); + else + ar << make_nvp("version", cfg.subVersion); - int encodedSize = cfg.keyData.size(); - ar << make_nvp("encodedKeySize", encodedSize); - ar << make_nvp("encodedKeyData", - serial::make_binary_object(cfg.getKeyData(), encodedSize)); + ar << make_nvp("creator", cfg.creator); + ar << make_nvp("cipherAlg", cfg.cipherIface); + ar << make_nvp("nameAlg", cfg.nameIface); + ar << make_nvp("keySize", cfg.keySize); + ar << make_nvp("blockSize", cfg.blockSize); + ar << make_nvp("uniqueIV", cfg.uniqueIV); + ar << make_nvp("chainedNameIV", cfg.chainedNameIV); + ar << make_nvp("externalIVChaining", cfg.externalIVChaining); + ar << make_nvp("blockMACBytes", cfg.blockMACBytes); + ar << make_nvp("blockMACRandBytes", cfg.blockMACRandBytes); + ar << make_nvp("allowHoles", cfg.allowHoles); - // version 20080816 - int size = cfg.salt.size(); - ar << make_nvp("saltLen", size); - ar << make_nvp("saltData", - serial::make_binary_object(cfg.getSaltData(), size)); - ar << make_nvp("kdfIterations", cfg.kdfIterations); - ar << make_nvp("desiredKDFDuration", cfg.desiredKDFDuration); - } + int encodedSize = cfg.keyData.size(); + ar << make_nvp("encodedKeySize", encodedSize); + ar << make_nvp("encodedKeyData", + serial::make_binary_object(cfg.getKeyData(), encodedSize)); - template - void load(Archive &ar, EncFSConfig &cfg, unsigned int version) - { - rInfo("version = %i", version); - // TODO: figure out how to deprecate all but the first case.. - if (version == 20 || version >= 20100713) - { - rInfo("found new serialization format"); - ar >> make_nvp("version", cfg.subVersion); - } else if (version == 26800) - { - rInfo("found 20080816 version"); - cfg.subVersion = 20080816; - } else if (version == 26797) - { - rInfo("found 20080813"); - cfg.subVersion = 20080813; - } else if (version < (unsigned int)V5SubVersion) - { - rError("Invalid version %i - please fix config file", version); - } else - { - rInfo("Boost <= 1.41 compatibility mode"); - cfg.subVersion = version; - } - rInfo("subVersion = %i", cfg.subVersion); - - ar >> make_nvp("creator", cfg.creator); - ar >> make_nvp("cipherAlg", cfg.cipherIface); - ar >> make_nvp("nameAlg", cfg.nameIface); - ar >> make_nvp("keySize", cfg.keySize); - ar >> make_nvp("blockSize", cfg.blockSize); - ar >> make_nvp("uniqueIV", cfg.uniqueIV); - ar >> make_nvp("chainedNameIV", cfg.chainedNameIV); - ar >> make_nvp("externalIVChaining", cfg.externalIVChaining); - ar >> make_nvp("blockMACBytes", cfg.blockMACBytes); - ar >> make_nvp("blockMACRandBytes", cfg.blockMACRandBytes); - ar >> make_nvp("allowHoles", cfg.allowHoles); - - int encodedSize; - ar >> make_nvp("encodedKeySize", encodedSize); - rAssert(encodedSize == cfg.getCipher()->encodedKeySize()); - - unsigned char *key = new unsigned char[encodedSize]; - ar >> make_nvp("encodedKeyData", - serial::make_binary_object(key, encodedSize)); - cfg.assignKeyData(key, encodedSize); - delete[] key; - - if(cfg.subVersion >= 20080816) - { - int saltLen; - ar >> make_nvp("saltLen", saltLen); - unsigned char *salt = new unsigned char[saltLen]; - ar >> make_nvp("saltData", - serial::make_binary_object(salt, saltLen)); - cfg.assignSaltData(salt, saltLen); - delete[] salt; - - ar >> make_nvp("kdfIterations", cfg.kdfIterations); - ar >> make_nvp("desiredKDFDuration", cfg.desiredKDFDuration); - } else - { - cfg.salt.clear(); - cfg.kdfIterations = 16; - cfg.desiredKDFDuration = NormalKDFDuration; - } - } - - template - void serialize(Archive &ar, EncFSConfig &cfg, unsigned int version) - { - split_free(ar, cfg, version); - } - - template - void serialize(Archive &ar, Interface &i, const unsigned int version) - { - (void)version; - ar & make_nvp("name", i.name()); - ar & make_nvp("major", i.current()); - ar & make_nvp("minor", i.revision()); - } - } + // version 20080816 + int size = cfg.salt.size(); + ar << make_nvp("saltLen", size); + ar << make_nvp("saltData", + serial::make_binary_object(cfg.getSaltData(), size)); + ar << make_nvp("kdfIterations", cfg.kdfIterations); + ar << make_nvp("desiredKDFDuration", cfg.desiredKDFDuration); } +template +void load(Archive &ar, EncFSConfig &cfg, unsigned int version) +{ + rInfo("version = %i", version); + // TODO: figure out how to deprecate all but the first case.. + if (version == 20 || version >= 20100713) + { + rInfo("found new serialization format"); + ar >> make_nvp("version", cfg.subVersion); + } else if (version == 26800) + { + rInfo("found 20080816 version"); + cfg.subVersion = 20080816; + } else if (version == 26797) + { + rInfo("found 20080813"); + cfg.subVersion = 20080813; + } else if (version < (unsigned int)V5SubVersion) + { + rError("Invalid version %i - please fix config file", version); + } else + { + rInfo("Boost <= 1.41 compatibility mode"); + cfg.subVersion = version; + } + rInfo("subVersion = %i", cfg.subVersion); + + ar >> make_nvp("creator", cfg.creator); + ar >> make_nvp("cipherAlg", cfg.cipherIface); + ar >> make_nvp("nameAlg", cfg.nameIface); + ar >> make_nvp("keySize", cfg.keySize); + ar >> make_nvp("blockSize", cfg.blockSize); + ar >> make_nvp("uniqueIV", cfg.uniqueIV); + ar >> make_nvp("chainedNameIV", cfg.chainedNameIV); + ar >> make_nvp("externalIVChaining", cfg.externalIVChaining); + ar >> make_nvp("blockMACBytes", cfg.blockMACBytes); + ar >> make_nvp("blockMACRandBytes", cfg.blockMACRandBytes); + ar >> make_nvp("allowHoles", cfg.allowHoles); + + int encodedSize; + ar >> make_nvp("encodedKeySize", encodedSize); + rAssert(encodedSize == cfg.getCipher()->encodedKeySize()); + + unsigned char *key = new unsigned char[encodedSize]; + ar >> make_nvp("encodedKeyData", + serial::make_binary_object(key, encodedSize)); + cfg.assignKeyData(key, encodedSize); + delete[] key; + + if(cfg.subVersion >= 20080816) + { + int saltLen; + ar >> make_nvp("saltLen", saltLen); + unsigned char *salt = new unsigned char[saltLen]; + ar >> make_nvp("saltData", + serial::make_binary_object(salt, saltLen)); + cfg.assignSaltData(salt, saltLen); + delete[] salt; + + ar >> make_nvp("kdfIterations", cfg.kdfIterations); + ar >> make_nvp("desiredKDFDuration", cfg.desiredKDFDuration); + } else + { + cfg.salt.clear(); + cfg.kdfIterations = 16; + cfg.desiredKDFDuration = NormalKDFDuration; + } +} + +template +void serialize(Archive &ar, EncFSConfig &cfg, unsigned int version) +{ + split_free(ar, cfg, version); +} + +template +void serialize(Archive &ar, Interface &i, const unsigned int version) +{ + (void)version; + ar & make_nvp("name", i.name()); + ar & make_nvp("major", i.current()); + ar & make_nvp("minor", i.revision()); +} +} // namespace serialization +} // namespace boost + EncFS_Root::EncFS_Root() { } @@ -268,50 +270,50 @@ EncFS_Root::~EncFS_Root() bool fileExists( const char * fileName ) { - struct stat buf; - if(!lstat( fileName, &buf )) - { - return true; - } else - { - // XXX show perror? - return false; - } + struct stat buf; + if(!lstat( fileName, &buf )) + { + return true; + } else + { + // XXX show perror? + return false; + } } bool isDirectory( const char *fileName ) { - struct stat buf; - if( !lstat( fileName, &buf )) - { - return S_ISDIR( buf.st_mode ); - } else - { - return false; - } + struct stat buf; + if( !lstat( fileName, &buf )) + { + return S_ISDIR( buf.st_mode ); + } else + { + return false; + } } bool isAbsolutePath( const char *fileName ) { - if(fileName && fileName[0] != '\0' && fileName[0] == '/') - return true; - else - return false; + if(fileName && fileName[0] != '\0' && fileName[0] == '/') + return true; + else + return false; } const char *lastPathElement( const char *name ) { - const char *loc = strrchr( name, '/' ); - return loc ? loc + 1 : name; + const char *loc = strrchr( name, '/' ); + return loc ? loc + 1 : name; } std::string parentDirectory( const std::string &path ) { - size_t last = path.find_last_of( '/' ); - if(last == string::npos) - return string(""); - else - return path.substr(0, last); + size_t last = path.find_last_of( '/' ); + if(last == string::npos) + return string(""); + else + return path.substr(0, last); } bool userAllowMkdir(const char *path, mode_t mode ) @@ -321,1408 +323,1408 @@ bool userAllowMkdir(const char *path, mode_t mode ) bool userAllowMkdir(int promptno, const char *path, mode_t mode ) { - // TODO: can we internationalize the y/n names? Seems strange to prompt in - // their own language but then have to respond 'y' or 'n'. - // xgroup(setup) - cerr << autosprintf( _("The directory \"%s\" does not exist. Should it be created? (y,n) "), path ); - char answer[10]; - char *res; + // TODO: can we internationalize the y/n names? Seems strange to prompt in + // their own language but then have to respond 'y' or 'n'. + // xgroup(setup) + cerr << autosprintf( _("The directory \"%s\" does not exist. Should it be created? (y,n) "), path ); + char answer[10]; + char *res; - switch (promptno) - { - case 1: - cerr << endl << "$PROMPT$ create_root_dir" << endl; - break; - case 2: - cerr << endl << "$PROMPT$ create_mount_point" << endl; - break; - default: - break; - } - res = fgets( answer, sizeof(answer), stdin ); + switch (promptno) + { + case 1: + cerr << endl << "$PROMPT$ create_root_dir" << endl; + break; + case 2: + cerr << endl << "$PROMPT$ create_mount_point" << endl; + break; + default: + break; + } + res = fgets( answer, sizeof(answer), stdin ); - if(res != 0 && toupper(answer[0]) == 'Y') + if(res != 0 && toupper(answer[0]) == 'Y') + { + int result = mkdir( path, mode ); + if(result < 0) { - int result = mkdir( path, mode ); - if(result < 0) - { - perror( _("Unable to create directory: ") ); - return false; - } else - return true; + perror( _("Unable to create directory: ") ); + return false; } else - { - // Directory not created, by user request - cerr << _("Directory not created.") << "\n"; - return false; - } + return true; + } else + { + // Directory not created, by user request + cerr << _("Directory not created.") << "\n"; + return false; + } } ConfigType readConfig_load( ConfigInfo *nm, const char *path, - const boost::shared_ptr &config ) + const boost::shared_ptr &config ) { - if( nm->loadFunc ) + if( nm->loadFunc ) + { + try { - try - { - if( (*nm->loadFunc)( path, config, nm )) - { - config->cfgType = nm->type; - return nm->type; - } - } catch( rlog::Error & err ) - { - err.log( _RLWarningChannel ); - } - - rError( _("Found config file %s, but failed to load"), path); - return Config_None; - } else - { - // No load function - must be an unsupported type.. + if( (*nm->loadFunc)( path, config, nm )) + { config->cfgType = nm->type; - return nm->type; + return nm->type; + } + } catch( rlog::Error & err ) + { + err.log( _RLWarningChannel ); } + + rError( _("Found config file %s, but failed to load"), path); + return Config_None; + } else + { + // No load function - must be an unsupported type.. + config->cfgType = nm->type; + return nm->type; + } } ConfigType readConfig( const string &rootDir, - const boost::shared_ptr &config ) + const boost::shared_ptr &config ) { - ConfigInfo *nm = ConfigFileMapping; - while(nm->fileName) + ConfigInfo *nm = ConfigFileMapping; + while(nm->fileName) + { + // allow environment variable to override default config path + if( nm->environmentOverride != NULL ) { - // allow environment variable to override default config path - if( nm->environmentOverride != NULL ) - { - char *envFile = getenv( nm->environmentOverride ); - if( envFile != NULL ) - return readConfig_load( nm, envFile, config ); - } - // the standard place to look is in the root directory - string path = rootDir + nm->fileName; - if( fileExists( path.c_str() ) ) - return readConfig_load( nm, path.c_str(), config); - - ++nm; + char *envFile = getenv( nm->environmentOverride ); + if( envFile != NULL ) + return readConfig_load( nm, envFile, config ); } + // the standard place to look is in the root directory + string path = rootDir + nm->fileName; + if( fileExists( path.c_str() ) ) + return readConfig_load( nm, path.c_str(), config); - return Config_None; + ++nm; + } + + return Config_None; } bool readV6Config( const char *configFile, - const boost::shared_ptr &config, - ConfigInfo *info) + const boost::shared_ptr &config, + ConfigInfo *info) { - (void)info; + (void)info; - fs::ifstream st( configFile ); - if(st.is_open()) + fs::ifstream st( configFile ); + if(st.is_open()) + { + try { - try - { - boost::archive::xml_iarchive ia( st ); - ia >> BOOST_SERIALIZATION_NVP( *config ); - - return true; - } catch(boost::archive::archive_exception &e) - { - rError("Archive exception: %s", e.what()); - return false; - } - } else + boost::archive::xml_iarchive ia( st ); + ia >> BOOST_SERIALIZATION_NVP( *config ); + + return true; + } catch(boost::archive::archive_exception &e) { - rInfo("Failed to load config file %s", configFile); - return false; + rError("Archive exception: %s", e.what()); + return false; } + } else + { + rInfo("Failed to load config file %s", configFile); + return false; + } } bool readV5Config( const char *configFile, - const boost::shared_ptr &config, - ConfigInfo *info) + const boost::shared_ptr &config, + ConfigInfo *info) { - bool ok = false; + bool ok = false; - // use Config to parse the file and query it.. - ConfigReader cfgRdr; - if(cfgRdr.load( configFile )) + // use Config to parse the file and query it.. + ConfigReader cfgRdr; + if(cfgRdr.load( configFile )) + { + try { - try - { - config->subVersion = cfgRdr["subVersion"].readInt( - info->defaultSubVersion ); - if(config->subVersion > info->currentSubVersion) - { - /* config file specifies a version outside our supported - range.. */ - rWarning(_("Config subversion %i found, but this version of" - " encfs only supports up to version %i."), - config->subVersion, info->currentSubVersion); - return false; - } - if( config->subVersion < 20040813 ) - { - rError(_("This version of EncFS doesn't support " - "filesystems created before 2004-08-13")); - return false; - } + config->subVersion = cfgRdr["subVersion"].readInt( + info->defaultSubVersion ); + if(config->subVersion > info->currentSubVersion) + { + /* config file specifies a version outside our supported + range.. */ + rWarning(_("Config subversion %i found, but this version of" + " encfs only supports up to version %i."), + config->subVersion, info->currentSubVersion); + return false; + } + if( config->subVersion < 20040813 ) + { + rError(_("This version of EncFS doesn't support " + "filesystems created before 2004-08-13")); + return false; + } - cfgRdr["creator"] >> config->creator; - cfgRdr["cipher"] >> config->cipherIface; - cfgRdr["naming"] >> config->nameIface; - cfgRdr["keySize"] >> config->keySize; - cfgRdr["blockSize"] >> config->blockSize; + cfgRdr["creator"] >> config->creator; + cfgRdr["cipher"] >> config->cipherIface; + cfgRdr["naming"] >> config->nameIface; + cfgRdr["keySize"] >> config->keySize; + cfgRdr["blockSize"] >> config->blockSize; - string data; - cfgRdr["keyData"] >> data; - config->assignKeyData(data); - config->uniqueIV = cfgRdr["uniqueIV"].readBool( false ); - config->chainedNameIV = cfgRdr["chainedIV"].readBool( false ); - config->externalIVChaining = cfgRdr["externalIV"].readBool( false ); - config->blockMACBytes = cfgRdr["blockMACBytes"].readInt(0); - config->blockMACRandBytes = - cfgRdr["blockMACRandBytes"].readInt(0); + string data; + cfgRdr["keyData"] >> data; + config->assignKeyData(data); + config->uniqueIV = cfgRdr["uniqueIV"].readBool( false ); + config->chainedNameIV = cfgRdr["chainedIV"].readBool( false ); + config->externalIVChaining = cfgRdr["externalIV"].readBool( false ); + config->blockMACBytes = cfgRdr["blockMACBytes"].readInt(0); + config->blockMACRandBytes = + cfgRdr["blockMACRandBytes"].readInt(0); - ok = true; - } catch( rlog::Error &err) - { - err.log( _RLWarningChannel ); - rDebug("Error parsing data in config file %s", configFile); - ok = false; - } + ok = true; + } catch( rlog::Error &err) + { + err.log( _RLWarningChannel ); + rDebug("Error parsing data in config file %s", configFile); + ok = false; } + } - return ok; + return ok; } bool readV4Config( const char *configFile, - const boost::shared_ptr &config, - ConfigInfo *info) + const boost::shared_ptr &config, + ConfigInfo *info) { - bool ok = false; + bool ok = false; - // use Config to parse the file and query it.. - ConfigReader cfgRdr; - if(cfgRdr.load( configFile )) + // use Config to parse the file and query it.. + ConfigReader cfgRdr; + if(cfgRdr.load( configFile )) + { + try { - try - { - cfgRdr["cipher"] >> config->cipherIface; - cfgRdr["keySize"] >> config->keySize; - cfgRdr["blockSize"] >> config->blockSize; - string data; - cfgRdr["keyData"] >> data; - config->assignKeyData(data); + cfgRdr["cipher"] >> config->cipherIface; + cfgRdr["keySize"] >> config->keySize; + cfgRdr["blockSize"] >> config->blockSize; + string data; + cfgRdr["keyData"] >> data; + config->assignKeyData(data); - // fill in default for V4 - config->nameIface = Interface("nameio/stream", 1, 0, 0); - config->creator = "EncFS 1.0.x"; - config->subVersion = info->defaultSubVersion; - config->blockMACBytes = 0; - config->blockMACRandBytes = 0; - config->uniqueIV = false; - config->externalIVChaining = false; - config->chainedNameIV = false; + // fill in default for V4 + config->nameIface = Interface("nameio/stream", 1, 0, 0); + config->creator = "EncFS 1.0.x"; + config->subVersion = info->defaultSubVersion; + config->blockMACBytes = 0; + config->blockMACRandBytes = 0; + config->uniqueIV = false; + config->externalIVChaining = false; + config->chainedNameIV = false; - ok = true; - } catch( rlog::Error &err) - { - err.log( _RLWarningChannel ); - rDebug("Error parsing config file %s", configFile); - ok = false; - } + ok = true; + } catch( rlog::Error &err) + { + err.log( _RLWarningChannel ); + rDebug("Error parsing config file %s", configFile); + ok = false; } + } - return ok; + return ok; } bool saveConfig( ConfigType type, const string &rootDir, - const boost::shared_ptr &config ) + const boost::shared_ptr &config ) { - bool ok = false; + bool ok = false; - ConfigInfo *nm = ConfigFileMapping; - while(nm->fileName) + ConfigInfo *nm = ConfigFileMapping; + while(nm->fileName) + { + if( nm->type == type && nm->saveFunc ) { - if( nm->type == type && nm->saveFunc ) - { - string path = rootDir + nm->fileName; - if( nm->environmentOverride != NULL ) - { - // use environment file if specified.. - const char *envFile = getenv( nm->environmentOverride ); - if( envFile != NULL ) - path.assign( envFile ); - } + string path = rootDir + nm->fileName; + if( nm->environmentOverride != NULL ) + { + // use environment file if specified.. + const char *envFile = getenv( nm->environmentOverride ); + if( envFile != NULL ) + path.assign( envFile ); + } - try - { - ok = (*nm->saveFunc)( path.c_str(), config ); - } catch( rlog::Error &err ) - { - err.log( _RLWarningChannel ); - ok = false; - } - break; - } - ++nm; + try + { + ok = (*nm->saveFunc)( path.c_str(), config ); + } catch( rlog::Error &err ) + { + err.log( _RLWarningChannel ); + ok = false; + } + break; } + ++nm; + } - return ok; + return ok; } bool writeV6Config( const char *configFile, - const boost::shared_ptr &config ) + const boost::shared_ptr &config ) { - fs::ofstream st( configFile ); - if(!st.is_open()) - return false; + fs::ofstream st( configFile ); + if(!st.is_open()) + return false; - st << *config; - return true; + st << *config; + return true; } std::ostream &operator << (std::ostream &st, const EncFSConfig &cfg) { - boost::archive::xml_oarchive oa(st); - oa << BOOST_SERIALIZATION_NVP( cfg ); + boost::archive::xml_oarchive oa(st); + oa << BOOST_SERIALIZATION_NVP( cfg ); - return st; + return st; } std::istream &operator >> (std::istream &st, EncFSConfig &cfg) { - boost::archive::xml_iarchive ia(st); - ia >> BOOST_SERIALIZATION_NVP( cfg ); + boost::archive::xml_iarchive ia(st); + ia >> BOOST_SERIALIZATION_NVP( cfg ); - return st; + return st; } bool writeV5Config( const char *configFile, - const boost::shared_ptr &config ) + const boost::shared_ptr &config ) { - ConfigReader cfg; + ConfigReader cfg; - cfg["creator"] << config->creator; - cfg["subVersion"] << config->subVersion; - cfg["cipher"] << config->cipherIface; - cfg["naming"] << config->nameIface; - cfg["keySize"] << config->keySize; - cfg["blockSize"] << config->blockSize; - string key; - key.assign((char *)config->getKeyData(), config->keyData.size()); - cfg["keyData"] << key; - cfg["blockMACBytes"] << config->blockMACBytes; - cfg["blockMACRandBytes"] << config->blockMACRandBytes; - cfg["uniqueIV"] << config->uniqueIV; - cfg["chainedIV"] << config->chainedNameIV; - cfg["externalIV"] << config->externalIVChaining; + cfg["creator"] << config->creator; + cfg["subVersion"] << config->subVersion; + cfg["cipher"] << config->cipherIface; + cfg["naming"] << config->nameIface; + cfg["keySize"] << config->keySize; + cfg["blockSize"] << config->blockSize; + string key; + key.assign((char *)config->getKeyData(), config->keyData.size()); + cfg["keyData"] << key; + cfg["blockMACBytes"] << config->blockMACBytes; + cfg["blockMACRandBytes"] << config->blockMACRandBytes; + cfg["uniqueIV"] << config->uniqueIV; + cfg["chainedIV"] << config->chainedNameIV; + cfg["externalIV"] << config->externalIVChaining; - return cfg.save( configFile ); + return cfg.save( configFile ); } bool writeV4Config( const char *configFile, - const boost::shared_ptr &config ) + const boost::shared_ptr &config ) { - ConfigReader cfg; + ConfigReader cfg; - cfg["cipher"] << config->cipherIface; - cfg["keySize"] << config->keySize; - cfg["blockSize"] << config->blockSize; - string key; - key.assign((char *)config->getKeyData(), config->keyData.size()); - cfg["keyData"] << key; + cfg["cipher"] << config->cipherIface; + cfg["keySize"] << config->keySize; + cfg["blockSize"] << config->blockSize; + string key; + key.assign((char *)config->getKeyData(), config->keyData.size()); + cfg["keyData"] << key; - return cfg.save( configFile ); + return cfg.save( configFile ); } static Cipher::CipherAlgorithm findCipherAlgorithm(const char *name, - int keySize ) + int keySize ) { - Cipher::AlgorithmList algorithms = Cipher::GetAlgorithmList(); - Cipher::AlgorithmList::const_iterator it; - for(it = algorithms.begin(); it != algorithms.end(); ++it) + Cipher::AlgorithmList algorithms = Cipher::GetAlgorithmList(); + Cipher::AlgorithmList::const_iterator it; + for(it = algorithms.begin(); it != algorithms.end(); ++it) + { + if( !strcmp( name, it->name.c_str() ) + && it->keyLength.allowed( keySize )) { - if( !strcmp( name, it->name.c_str() ) - && it->keyLength.allowed( keySize )) - { - return *it; - } + return *it; } + } - Cipher::CipherAlgorithm result; - return result; + Cipher::CipherAlgorithm result; + return result; } static Cipher::CipherAlgorithm selectCipherAlgorithm() { - for(;;) + for(;;) + { + // figure out what cipher they want to use.. + // xgroup(setup) + cout << _("The following cipher algorithms are available:") << "\n"; + Cipher::AlgorithmList algorithms = Cipher::GetAlgorithmList(); + Cipher::AlgorithmList::const_iterator it; + int optNum = 1; + for(it = algorithms.begin(); it != algorithms.end(); ++it, ++optNum) { - // figure out what cipher they want to use.. - // xgroup(setup) - cout << _("The following cipher algorithms are available:") << "\n"; - Cipher::AlgorithmList algorithms = Cipher::GetAlgorithmList(); - Cipher::AlgorithmList::const_iterator it; - int optNum = 1; - for(it = algorithms.begin(); it != algorithms.end(); ++it, ++optNum) - { - cout << optNum << ". " << it->name - << " : " << gettext(it->description.c_str()) << "\n"; - if(it->keyLength.min() == it->keyLength.max()) - { - // shown after algorithm name and description. - // xgroup(setup) - cout << autosprintf(_(" -- key length %i bits") - , it->keyLength.min()) << "\n"; - } else - { - cout << autosprintf( - // shown after algorithm name and description. - // xgroup(setup) - _(" -- Supports key lengths of %i to %i bits"), - it->keyLength.min(), it->keyLength.max()) << "\n"; - } + cout << optNum << ". " << it->name + << " : " << gettext(it->description.c_str()) << "\n"; + if(it->keyLength.min() == it->keyLength.max()) + { + // shown after algorithm name and description. + // xgroup(setup) + cout << autosprintf(_(" -- key length %i bits") + , it->keyLength.min()) << "\n"; + } else + { + cout << autosprintf( + // shown after algorithm name and description. + // xgroup(setup) + _(" -- Supports key lengths of %i to %i bits"), + it->keyLength.min(), it->keyLength.max()) << "\n"; + } - if(it->blockSize.min() == it->blockSize.max()) - { - cout << autosprintf( - // shown after algorithm name and description. - // xgroup(setup) - _(" -- block size %i bytes"), it->blockSize.min()) - << "\n"; - } else - { - cout << autosprintf( - // shown after algorithm name and description. - // xgroup(setup) - _(" -- Supports block sizes of %i to %i bytes"), - it->blockSize.min(), it->blockSize.max()) << "\n"; - } - } - - // xgroup(setup) - cout << "\n" << _("Enter the number corresponding to your choice: "); - char answer[10]; - char *res = fgets( answer, sizeof(answer), stdin ); - int cipherNum = (res == 0 ? 0 : atoi( answer )); - cout << "\n"; - - if( cipherNum < 1 || cipherNum > (int)algorithms.size() ) - { - cerr << _("Invalid selection.") << "\n"; - continue; - } - - it = algorithms.begin(); - while(--cipherNum) // numbering starts at 1 - ++it; - - Cipher::CipherAlgorithm alg = *it; - - // xgroup(setup) - cout << autosprintf(_("Selected algorithm \"%s\""), alg.name.c_str()) - << "\n\n"; - - return alg; + if(it->blockSize.min() == it->blockSize.max()) + { + cout << autosprintf( + // shown after algorithm name and description. + // xgroup(setup) + _(" -- block size %i bytes"), it->blockSize.min()) + << "\n"; + } else + { + cout << autosprintf( + // shown after algorithm name and description. + // xgroup(setup) + _(" -- Supports block sizes of %i to %i bytes"), + it->blockSize.min(), it->blockSize.max()) << "\n"; + } } + + // xgroup(setup) + cout << "\n" << _("Enter the number corresponding to your choice: "); + char answer[10]; + char *res = fgets( answer, sizeof(answer), stdin ); + int cipherNum = (res == 0 ? 0 : atoi( answer )); + cout << "\n"; + + if( cipherNum < 1 || cipherNum > (int)algorithms.size() ) + { + cerr << _("Invalid selection.") << "\n"; + continue; + } + + it = algorithms.begin(); + while(--cipherNum) // numbering starts at 1 + ++it; + + Cipher::CipherAlgorithm alg = *it; + + // xgroup(setup) + cout << autosprintf(_("Selected algorithm \"%s\""), alg.name.c_str()) + << "\n\n"; + + return alg; + } } static Interface selectNameCoding() { - for(;;) + for(;;) + { + // figure out what cipher they want to use.. + // xgroup(setup) + cout << _("The following filename encoding algorithms are available:") + << "\n"; + NameIO::AlgorithmList algorithms = NameIO::GetAlgorithmList(); + NameIO::AlgorithmList::const_iterator it; + int optNum = 1; + for(it = algorithms.begin(); it != algorithms.end(); ++it, ++optNum) { - // figure out what cipher they want to use.. - // xgroup(setup) - cout << _("The following filename encoding algorithms are available:") - << "\n"; - NameIO::AlgorithmList algorithms = NameIO::GetAlgorithmList(); - NameIO::AlgorithmList::const_iterator it; - int optNum = 1; - for(it = algorithms.begin(); it != algorithms.end(); ++it, ++optNum) - { - cout << optNum << ". " << it->name - << " : " << gettext(it->description.c_str()) << "\n"; - } - - // xgroup(setup) - cout << "\n" << _("Enter the number corresponding to your choice: "); - char answer[10]; - char *res = fgets( answer, sizeof(answer), stdin ); - int algNum = (res == 0 ? 0 : atoi( answer )); - cout << "\n"; - - if( algNum < 1 || algNum > (int)algorithms.size() ) - { - cerr << _("Invalid selection.") << "\n"; - continue; - } - - it = algorithms.begin(); - while(--algNum) // numbering starts at 1 - ++it; - - // xgroup(setup) - cout << autosprintf(_("Selected algorithm \"%s\""), it->name.c_str()) - << "\"\n\n"; - - return it->iface; + cout << optNum << ". " << it->name + << " : " << gettext(it->description.c_str()) << "\n"; } + + // xgroup(setup) + cout << "\n" << _("Enter the number corresponding to your choice: "); + char answer[10]; + char *res = fgets( answer, sizeof(answer), stdin ); + int algNum = (res == 0 ? 0 : atoi( answer )); + cout << "\n"; + + if( algNum < 1 || algNum > (int)algorithms.size() ) + { + cerr << _("Invalid selection.") << "\n"; + continue; + } + + it = algorithms.begin(); + while(--algNum) // numbering starts at 1 + ++it; + + // xgroup(setup) + cout << autosprintf(_("Selected algorithm \"%s\""), it->name.c_str()) + << "\"\n\n"; + + return it->iface; + } } static int selectKeySize( const Cipher::CipherAlgorithm &alg ) { - if(alg.keyLength.min() == alg.keyLength.max()) + if(alg.keyLength.min() == alg.keyLength.max()) + { + cout << autosprintf(_("Using key size of %i bits"), + alg.keyLength.min()) << "\n"; + return alg.keyLength.min(); + } + + cout << autosprintf( + // xgroup(setup) + _("Please select a key size in bits. The cipher you have chosen\n" + "supports sizes from %i to %i bits in increments of %i bits.\n" + "For example: "), alg.keyLength.min(), alg.keyLength.max(), + alg.keyLength.inc()) << "\n"; + + int numAvail = (alg.keyLength.max() - alg.keyLength.min()) + / alg.keyLength.inc(); + + if(numAvail < 5) + { + // show them all + for(int i=0; i<=numAvail; ++i) { - cout << autosprintf(_("Using key size of %i bits"), - alg.keyLength.min()) << "\n"; - return alg.keyLength.min(); + if(i) + cout << ", "; + cout << alg.keyLength.min() + i * alg.keyLength.inc(); } - - cout << autosprintf( - // xgroup(setup) - _("Please select a key size in bits. The cipher you have chosen\n" - "supports sizes from %i to %i bits in increments of %i bits.\n" - "For example: "), alg.keyLength.min(), alg.keyLength.max(), - alg.keyLength.inc()) << "\n"; - - int numAvail = (alg.keyLength.max() - alg.keyLength.min()) - / alg.keyLength.inc(); - - if(numAvail < 5) + } else + { + // partial + for(int i=0; i<3; ++i) { - // show them all - for(int i=0; i<=numAvail; ++i) - { - if(i) - cout << ", "; - cout << alg.keyLength.min() + i * alg.keyLength.inc(); - } - } else - { - // partial - for(int i=0; i<3; ++i) - { - if(i) - cout << ", "; - cout << alg.keyLength.min() + i * alg.keyLength.inc(); - } - cout << " ... " << alg.keyLength.max() - alg.keyLength.inc(); - cout << ", " << alg.keyLength.max(); + if(i) + cout << ", "; + cout << alg.keyLength.min() + i * alg.keyLength.inc(); } - // xgroup(setup) - cout << "\n" << _("Selected key size: "); + cout << " ... " << alg.keyLength.max() - alg.keyLength.inc(); + cout << ", " << alg.keyLength.max(); + } + // xgroup(setup) + cout << "\n" << _("Selected key size: "); - char answer[10]; - char *res = fgets( answer, sizeof(answer), stdin ); - int keySize = (res == 0 ? 0 : atoi( answer )); - cout << "\n"; + char answer[10]; + char *res = fgets( answer, sizeof(answer), stdin ); + int keySize = (res == 0 ? 0 : atoi( answer )); + cout << "\n"; - keySize = alg.keyLength.closest( keySize ); + keySize = alg.keyLength.closest( keySize ); - // xgroup(setup) - cout << autosprintf(_("Using key size of %i bits"), keySize) << "\n\n"; + // xgroup(setup) + cout << autosprintf(_("Using key size of %i bits"), keySize) << "\n\n"; - return keySize; + return keySize; } static int selectBlockSize( const Cipher::CipherAlgorithm &alg ) { - if(alg.blockSize.min() == alg.blockSize.max()) - { - cout << autosprintf( - // xgroup(setup) - _("Using filesystem block size of %i bytes"), - alg.blockSize.min()) << "\n"; - return alg.blockSize.min(); - } - + if(alg.blockSize.min() == alg.blockSize.max()) + { cout << autosprintf( - // xgroup(setup) - _("Select a block size in bytes. The cipher you have chosen\n" - "supports sizes from %i to %i bytes in increments of %i.\n" - "Or just hit enter for the default (%i bytes)\n"), - alg.blockSize.min(), alg.blockSize.max(), alg.blockSize.inc(), - DefaultBlockSize); + // xgroup(setup) + _("Using filesystem block size of %i bytes"), + alg.blockSize.min()) << "\n"; + return alg.blockSize.min(); + } - // xgroup(setup) - cout << "\n" << _("filesystem block size: "); - - int blockSize = DefaultBlockSize; - char answer[10]; - char *res = fgets( answer, sizeof(answer), stdin ); - cout << "\n"; + cout << autosprintf( + // xgroup(setup) + _("Select a block size in bytes. The cipher you have chosen\n" + "supports sizes from %i to %i bytes in increments of %i.\n" + "Or just hit enter for the default (%i bytes)\n"), + alg.blockSize.min(), alg.blockSize.max(), alg.blockSize.inc(), + DefaultBlockSize); - if( res != 0 && atoi( answer ) >= alg.blockSize.min() ) - blockSize = atoi( answer ); + // xgroup(setup) + cout << "\n" << _("filesystem block size: "); - blockSize = alg.blockSize.closest( blockSize ); + int blockSize = DefaultBlockSize; + char answer[10]; + char *res = fgets( answer, sizeof(answer), stdin ); + cout << "\n"; - // xgroup(setup) - cout << autosprintf(_("Using filesystem block size of %i bytes"), - blockSize) << "\n\n"; + if( res != 0 && atoi( answer ) >= alg.blockSize.min() ) + blockSize = atoi( answer ); - return blockSize; + blockSize = alg.blockSize.closest( blockSize ); + + // xgroup(setup) + cout << autosprintf(_("Using filesystem block size of %i bytes"), + blockSize) << "\n\n"; + + return blockSize; } static bool boolDefaultNo(const char *prompt) { - cout << prompt << "\n"; - cout << _("The default here is No.\n" - "Any response that does not begin with 'y' will mean No: "); + cout << prompt << "\n"; + cout << _("The default here is No.\n" + "Any response that does not begin with 'y' will mean No: "); - char answer[10]; - char *res = fgets( answer, sizeof(answer), stdin ); - cout << "\n"; + char answer[10]; + char *res = fgets( answer, sizeof(answer), stdin ); + cout << "\n"; - if(res != 0 && tolower(answer[0]) == 'y') - return true; - else - return false; + if(res != 0 && tolower(answer[0]) == 'y') + return true; + else + return false; } 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.")); + // 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.")); - if(addMAC) - *macBytes = 8; - else - *macBytes = 0; + if(addMAC) + *macBytes = 8; + else + *macBytes = 0; - // xgroup(setup) - cout << _("Add random bytes to each block header?\n" - "This adds a performance penalty, but ensures that blocks\n" - "have different authentication codes. Note that you can\n" - "have the same benefits by enabling per-file initialization\n" - "vectors, which does not come with as great of performance\n" - "penalty. \n" - "Select a number of bytes, from 0 (no random bytes) to 8: "); + // xgroup(setup) + cout << _("Add random bytes to each block header?\n" + "This adds a performance penalty, but ensures that blocks\n" + "have different authentication codes. Note that you can\n" + "have the same benefits by enabling per-file initialization\n" + "vectors, which does not come with as great of performance\n" + "penalty. \n" + "Select a number of bytes, from 0 (no random bytes) to 8: "); - char answer[10]; - int randSize = 0; - char *res = fgets( answer, sizeof(answer), stdin ); - cout << "\n"; + char answer[10]; + int randSize = 0; + char *res = fgets( answer, sizeof(answer), stdin ); + cout << "\n"; - randSize = (res == 0 ? 0 : atoi( answer )); - if(randSize < 0) - randSize = 0; - if(randSize > 8) - randSize = 8; + randSize = (res == 0 ? 0 : atoi( answer )); + if(randSize < 0) + randSize = 0; + if(randSize > 8) + randSize = 8; - *macRandBytes = randSize; + *macRandBytes = randSize; } static bool boolDefaultYes(const char *prompt) { - cout << prompt << "\n"; - cout << _("The default here is Yes.\n" - "Any response that does not begin with 'n' will mean Yes: "); + cout << prompt << "\n"; + cout << _("The default here is Yes.\n" + "Any response that does not begin with 'n' will mean Yes: "); - char answer[10]; - char *res = fgets( answer, sizeof(answer), stdin ); - cout << "\n"; + char answer[10]; + char *res = fgets( answer, sizeof(answer), stdin ); + cout << "\n"; - if(res != 0 && tolower(answer[0]) == 'n') - return false; - else - return true; + if(res != 0 && tolower(answer[0]) == 'n') + return false; + else + return true; } static bool selectUniqueIV() { - // xgroup(setup) - return boolDefaultYes( - _("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.")); + // xgroup(setup) + return boolDefaultYes( + _("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.")); } static bool selectChainedIV() { - // xgroup(setup) - return boolDefaultYes( - _("Enable filename initialization vector chaining?\n" - "This makes filename encoding dependent on the complete path, \n" - "rather then encoding each path element individually.")); + // xgroup(setup) + return boolDefaultYes( + _("Enable filename initialization vector chaining?\n" + "This makes filename encoding dependent on the complete path, \n" + "rather then encoding each path element individually.")); } static bool selectExternalChainedIV() { - // xgroup(setup) - return boolDefaultNo( - _("Enable filename to IV header chaining?\n" - "This makes file data encoding dependent on the complete file path.\n" - "If a file is renamed, it will not decode sucessfully unless it\n" - "was renamed by encfs with the proper key.\n" - "If this option is enabled, then hard links will not be supported\n" - "in the filesystem.")); + // xgroup(setup) + return boolDefaultNo( + _("Enable filename to IV header chaining?\n" + "This makes file data encoding dependent on the complete file path.\n" + "If a file is renamed, it will not decode sucessfully unless it\n" + "was renamed by encfs with the proper key.\n" + "If this option is enabled, then hard links will not be supported\n" + "in the filesystem.")); } static bool selectZeroBlockPassThrough() { - // xgroup(setup) - return boolDefaultYes( - _("Enable file-hole pass-through?\n" - "This avoids writing encrypted blocks when file holes are created.")); + // xgroup(setup) + return boolDefaultYes( + _("Enable file-hole pass-through?\n" + "This avoids writing encrypted blocks when file holes are created.")); } RootPtr createV6Config( EncFS_Context *ctx, - const shared_ptr &opts ) + const shared_ptr &opts ) { - const std::string rootDir = opts->rootDir; - bool enableIdleTracking = opts->idleTracking; - bool forceDecode = opts->forceDecode; - const std::string passwordProgram = opts->passwordProgram; - bool useStdin = opts->useStdin; - bool reverseEncryption = opts->reverseEncryption; - ConfigMode configMode = opts->configMode; - bool annotate = opts->annotate; - - RootPtr rootInfo; + const std::string rootDir = opts->rootDir; + bool enableIdleTracking = opts->idleTracking; + bool forceDecode = opts->forceDecode; + const std::string passwordProgram = opts->passwordProgram; + bool useStdin = opts->useStdin; + bool reverseEncryption = opts->reverseEncryption; + ConfigMode configMode = opts->configMode; + bool annotate = opts->annotate; - // creating new volume key.. should check that is what the user is - // expecting... + RootPtr rootInfo; + + // creating new volume key.. should check that is what the user is + // expecting... + // xgroup(setup) + cout << _("Creating new encrypted volume.") << endl; + + char answer[10] = {0}; + if(configMode == Config_Prompt) + { // xgroup(setup) - cout << _("Creating new encrypted volume.") << endl; + cout << _("Please choose from one of the following options:\n" + " enter \"x\" for expert configuration mode,\n" + " enter \"p\" for pre-configured paranoia mode,\n" + " anything else, or an empty line will select standard mode.\n" + "?> "); - char answer[10] = {0}; - if(configMode == Config_Prompt) - { - // xgroup(setup) - cout << _("Please choose from one of the following options:\n" - " enter \"x\" for expert configuration mode,\n" - " enter \"p\" for pre-configured paranoia mode,\n" - " anything else, or an empty line will select standard mode.\n" - "?> "); - - if (annotate) - cerr << "$PROMPT$ config_option" << endl; + if (annotate) + cerr << "$PROMPT$ config_option" << endl; - char *res = fgets( answer, sizeof(answer), stdin ); - (void)res; - cout << "\n"; - } + char *res = fgets( answer, sizeof(answer), stdin ); + (void)res; + cout << "\n"; + } - int keySize = 0; - int blockSize = 0; - Cipher::CipherAlgorithm alg; - Interface nameIOIface; - int blockMACBytes = 0; - int blockMACRandBytes = 0; - bool uniqueIV = false; - bool chainedIV = false; - bool externalIV = false; - bool allowHoles = true; - long desiredKDFDuration = NormalKDFDuration; - + int keySize = 0; + int blockSize = 0; + Cipher::CipherAlgorithm alg; + Interface nameIOIface; + int blockMACBytes = 0; + int blockMACRandBytes = 0; + bool uniqueIV = false; + bool chainedIV = false; + bool externalIV = false; + bool allowHoles = true; + long desiredKDFDuration = NormalKDFDuration; + + if (reverseEncryption) + { + uniqueIV = false; + chainedIV = false; + externalIV = false; + blockMACBytes = 0; + blockMACRandBytes = 0; + } + + if(configMode == Config_Paranoia || answer[0] == 'p') + { if (reverseEncryption) { - uniqueIV = false; - chainedIV = false; - externalIV = false; - blockMACBytes = 0; - blockMACRandBytes = 0; + rError(_("Paranoia configuration not supported for --reverse")); + return rootInfo; } - if(configMode == Config_Paranoia || answer[0] == 'p') + // xgroup(setup) + cout << _("Paranoia configuration selected.") << "\n"; + // look for AES with 256 bit key.. + // Use block filename encryption mode. + // Enable per-block HMAC headers at substantial performance penalty.. + // Enable per-file initialization vector headers. + // Enable filename initialization vector chaning + keySize = 256; + blockSize = DefaultBlockSize; + alg = findCipherAlgorithm("AES", keySize); + 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') + { + // xgroup(setup) + cout << _("Standard configuration selected.") << "\n"; + // AES w/ 192 bit key, block name encoding, per-file initialization + // vectors are all standard. + keySize = 192; + blockSize = DefaultBlockSize; + alg = findCipherAlgorithm("AES", keySize); + blockMACBytes = 0; + externalIV = false; + nameIOIface = BlockNameIO::CurrentInterface(); + + if (reverseEncryption) { - if (reverseEncryption) - { - rError(_("Paranoia configuration not supported for --reverse")); - return rootInfo; - } - - // xgroup(setup) - cout << _("Paranoia configuration selected.") << "\n"; - // look for AES with 256 bit key.. - // Use block filename encryption mode. - // Enable per-block HMAC headers at substantial performance penalty.. - // Enable per-file initialization vector headers. - // Enable filename initialization vector chaning - keySize = 256; - blockSize = DefaultBlockSize; - alg = findCipherAlgorithm("AES", keySize); - 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') - { - // xgroup(setup) - cout << _("Standard configuration selected.") << "\n"; - // AES w/ 192 bit key, block name encoding, per-file initialization - // vectors are all standard. - keySize = 192; - blockSize = DefaultBlockSize; - alg = findCipherAlgorithm("AES", keySize); - blockMACBytes = 0; - externalIV = false; - nameIOIface = BlockNameIO::CurrentInterface(); - - if (reverseEncryption) - { - cout << _("--reverse specified, not using unique/chained IV") - << "\n"; - } else - { - uniqueIV = true; - chainedIV = true; - } - } - - if(answer[0] == 'x' || alg.name.empty()) - { - if(answer[0] != 'x') - { - // xgroup(setup) - cout << _("Sorry, unable to locate cipher for predefined " - "configuration...\n" - "Falling through to Manual configuration mode."); - } else - { - // xgroup(setup) - cout << _("Manual configuration mode selected."); - } - cout << endl; - - // query user for settings.. - alg = selectCipherAlgorithm(); - keySize = selectKeySize( alg ); - blockSize = selectBlockSize( alg ); - nameIOIface = selectNameCoding(); - if (reverseEncryption) - { - cout << _("--reverse specified, not using unique/chained IV") << "\n"; - } else - { - chainedIV = selectChainedIV(); - uniqueIV = selectUniqueIV(); - if(chainedIV && uniqueIV) - externalIV = selectExternalChainedIV(); - else - { - // xgroup(setup) - cout << _("External chained IV disabled, as both 'IV chaining'\n" - "and 'unique IV' features are required for this option.") - << "\n"; - externalIV = false; - } - selectBlockMAC(&blockMACBytes, &blockMACRandBytes); - allowHoles = selectZeroBlockPassThrough(); - } - } - - shared_ptr cipher = Cipher::New( alg.name, keySize ); - if(!cipher) - { - rError(_("Unable to instanciate cipher %s, key size %i, block size %i"), - alg.name.c_str(), keySize, blockSize); - return rootInfo; + cout << _("--reverse specified, not using unique/chained IV") + << "\n"; } else { - rDebug("Using cipher %s, key size %i, block size %i", - alg.name.c_str(), keySize, blockSize); + uniqueIV = true; + chainedIV = true; } - - shared_ptr config( new EncFSConfig ); + } - config->cfgType = Config_V6; - config->cipherIface = cipher->interface(); - config->keySize = keySize; - config->blockSize = blockSize; - config->nameIface = nameIOIface; - config->creator = "EncFS " VERSION; - config->subVersion = V6SubVersion; - config->blockMACBytes = blockMACBytes; - config->blockMACRandBytes = blockMACRandBytes; - config->uniqueIV = uniqueIV; - config->chainedNameIV = chainedIV; - config->externalIVChaining = externalIV; - config->allowHoles = allowHoles; - - config->salt.clear(); - config->kdfIterations = 0; // filled in by keying function - config->desiredKDFDuration = desiredKDFDuration; - - cout << "\n"; - // xgroup(setup) - cout << _("Configuration finished. The filesystem to be created has\n" - "the following properties:") << endl; - showFSInfo( config ); - - if( config->externalIVChaining ) + if(answer[0] == 'x' || alg.name.empty()) + { + if(answer[0] != 'x') { - cout << - _("-------------------------- WARNING --------------------------\n") - << - _("The external initialization-vector chaining option has been\n" - "enabled. This option disables the use of hard links on the\n" - "filesystem. Without hard links, some programs may not work.\n" - "The programs 'mutt' and 'procmail' are known to fail. For\n" - "more information, please see the encfs mailing list.\n" - "If you would like to choose another configuration setting,\n" - "please press CTRL-C now to abort and start over.") << endl; - cout << endl; - } - - // xgroup(setup) - cout << _("Now you will need to enter a password for your filesystem.\n" - "You will need to remember this password, as there is absolutely\n" - "no recovery mechanism. However, the password can be changed\n" - "later using encfsctl.\n\n"); - - int encodedKeySize = cipher->encodedKeySize(); - unsigned char *encodedKey = new unsigned char[ encodedKeySize ]; - - CipherKey volumeKey = cipher->newRandomKey(); - - // get user key and use it to encode volume key - CipherKey userKey; - rDebug( "useStdin: %i", useStdin ); - if(useStdin) + // xgroup(setup) + cout << _("Sorry, unable to locate cipher for predefined " + "configuration...\n" + "Falling through to Manual configuration mode."); + } else { - if (annotate) - cerr << "$PROMPT$ new_passwd" << endl; - userKey = config->getUserKey( useStdin ); + // xgroup(setup) + cout << _("Manual configuration mode selected."); } - else if(!passwordProgram.empty()) - userKey = config->getUserKey( passwordProgram, rootDir ); + cout << endl; + + // query user for settings.. + alg = selectCipherAlgorithm(); + keySize = selectKeySize( alg ); + blockSize = selectBlockSize( alg ); + nameIOIface = selectNameCoding(); + if (reverseEncryption) + { + cout << _("--reverse specified, not using unique/chained IV") << "\n"; + } else + { + chainedIV = selectChainedIV(); + uniqueIV = selectUniqueIV(); + if(chainedIV && uniqueIV) + externalIV = selectExternalChainedIV(); + else + { + // xgroup(setup) + cout << _("External chained IV disabled, as both 'IV chaining'\n" + "and 'unique IV' features are required for this option.") + << "\n"; + externalIV = false; + } + selectBlockMAC(&blockMACBytes, &blockMACRandBytes); + allowHoles = selectZeroBlockPassThrough(); + } + } + + shared_ptr cipher = Cipher::New( alg.name, keySize ); + if(!cipher) + { + rError(_("Unable to instanciate cipher %s, key size %i, block size %i"), + alg.name.c_str(), keySize, blockSize); + return rootInfo; + } else + { + rDebug("Using cipher %s, key size %i, block size %i", + alg.name.c_str(), keySize, blockSize); + } + + shared_ptr config( new EncFSConfig ); + + config->cfgType = Config_V6; + config->cipherIface = cipher->interface(); + config->keySize = keySize; + config->blockSize = blockSize; + config->nameIface = nameIOIface; + config->creator = "EncFS " VERSION; + config->subVersion = V6SubVersion; + config->blockMACBytes = blockMACBytes; + config->blockMACRandBytes = blockMACRandBytes; + config->uniqueIV = uniqueIV; + config->chainedNameIV = chainedIV; + config->externalIVChaining = externalIV; + config->allowHoles = allowHoles; + + config->salt.clear(); + config->kdfIterations = 0; // filled in by keying function + config->desiredKDFDuration = desiredKDFDuration; + + cout << "\n"; + // xgroup(setup) + cout << _("Configuration finished. The filesystem to be created has\n" + "the following properties:") << endl; + showFSInfo( config ); + + if( config->externalIVChaining ) + { + cout << + _("-------------------------- WARNING --------------------------\n") + << + _("The external initialization-vector chaining option has been\n" + "enabled. This option disables the use of hard links on the\n" + "filesystem. Without hard links, some programs may not work.\n" + "The programs 'mutt' and 'procmail' are known to fail. For\n" + "more information, please see the encfs mailing list.\n" + "If you would like to choose another configuration setting,\n" + "please press CTRL-C now to abort and start over.") << endl; + cout << endl; + } + + // xgroup(setup) + cout << _("Now you will need to enter a password for your filesystem.\n" + "You will need to remember this password, as there is absolutely\n" + "no recovery mechanism. However, the password can be changed\n" + "later using encfsctl.\n\n"); + + int encodedKeySize = cipher->encodedKeySize(); + unsigned char *encodedKey = new unsigned char[ encodedKeySize ]; + + CipherKey volumeKey = cipher->newRandomKey(); + + // get user key and use it to encode volume key + CipherKey userKey; + rDebug( "useStdin: %i", useStdin ); + if(useStdin) + { + if (annotate) + cerr << "$PROMPT$ new_passwd" << endl; + userKey = config->getUserKey( useStdin ); + } + else if(!passwordProgram.empty()) + userKey = config->getUserKey( passwordProgram, rootDir ); + else + userKey = config->getNewUserKey(); + + cipher->writeKey( volumeKey, encodedKey, userKey ); + userKey.reset(); + + config->assignKeyData(encodedKey, encodedKeySize); + delete[] encodedKey; + + if(!volumeKey) + { + rWarning(_("Failure generating new volume key! " + "Please report this error.")); + return rootInfo; + } + + if(!saveConfig( Config_V6, rootDir, config )) + return rootInfo; + + // fill in config struct + shared_ptr nameCoder = NameIO::New( config->nameIface, + cipher, volumeKey ); + if(!nameCoder) + { + rWarning(_("Name coding interface not supported")); + cout << _("The filename encoding interface requested is not available") + << endl; + return rootInfo; + } + + nameCoder->setChainedNameIV( config->chainedNameIV ); + nameCoder->setReverseEncryption( reverseEncryption ); + + FSConfigPtr fsConfig (new FSConfig); + fsConfig->cipher = cipher; + fsConfig->key = volumeKey; + fsConfig->nameCoding = nameCoder; + fsConfig->config = config; + fsConfig->forceDecode = forceDecode; + fsConfig->reverseEncryption = reverseEncryption; + fsConfig->idleTracking = enableIdleTracking; + fsConfig->opts = opts; + + rootInfo = RootPtr( new EncFS_Root ); + rootInfo->cipher = cipher; + rootInfo->volumeKey = volumeKey; + rootInfo->root = shared_ptr( + new DirNode( ctx, rootDir, fsConfig )); + + return rootInfo; +} + +void showFSInfo( const boost::shared_ptr &config ) +{ + shared_ptr cipher = Cipher::New( config->cipherIface, -1 ); + { + cout << autosprintf( + // xgroup(diag) + _("Filesystem cipher: \"%s\", version %i:%i:%i"), + config->cipherIface.name().c_str(), config->cipherIface.current(), + config->cipherIface.revision(), config->cipherIface.age()); + // check if we support this interface.. + if(!cipher) + cout << _(" (NOT supported)\n"); else - userKey = config->getNewUserKey(); + { + // if we're using a newer interface, show the version number + if( config->cipherIface != cipher->interface() ) + { + Interface iface = cipher->interface(); + // xgroup(diag) + cout << autosprintf(_(" (using %i:%i:%i)\n"), + iface.current(), iface.revision(), iface.age()); + } else + cout << "\n"; + } + } + { + // xgroup(diag) + cout << autosprintf(_("Filename encoding: \"%s\", version %i:%i:%i"), + config->nameIface.name().c_str(), config->nameIface.current(), + config->nameIface.revision(), config->nameIface.age()); - cipher->writeKey( volumeKey, encodedKey, userKey ); + // check if we support the filename encoding interface.. + shared_ptr nameCoder = NameIO::New( config->nameIface, + cipher, CipherKey() ); + if(!nameCoder) + { + // xgroup(diag) + cout << _(" (NOT supported)\n"); + } else + { + // if we're using a newer interface, show the version number + if( config->nameIface != nameCoder->interface() ) + { + Interface iface = nameCoder->interface(); + cout << autosprintf(_(" (using %i:%i:%i)\n"), + iface.current(), iface.revision(), iface.age()); + } else + cout << "\n"; + } + } + { + cout << autosprintf(_("Key Size: %i bits"), config->keySize); + cipher = config->getCipher(); + if(!cipher) + { + // xgroup(diag) + cout << _(" (NOT supported)\n"); + } else + cout << "\n"; + } + if(config->kdfIterations > 0 && config->salt.size() > 0) + { + cout << autosprintf(_("Using PBKDF2, with %i iterations"), + config->kdfIterations) << "\n"; + cout << autosprintf(_("Salt Size: %i bits"), + 8*(int)config->salt.size()) << "\n"; + } + if(config->blockMACBytes || config->blockMACRandBytes) + { + if(config->subVersion < 20040813) + { + cout << autosprintf( + // xgroup(diag) + _("Block Size: %i bytes + %i byte MAC header"), + config->blockSize, + config->blockMACBytes + config->blockMACRandBytes) << endl; + } else + { + // new version stores the header as part of that block size.. + cout << autosprintf( + // xgroup(diag) + _("Block Size: %i bytes, including %i byte MAC header"), + config->blockSize, + config->blockMACBytes + config->blockMACRandBytes) << endl; + } + } else + { + // xgroup(diag) + cout << autosprintf(_("Block Size: %i bytes"), config->blockSize); + cout << "\n"; + } + + if(config->uniqueIV) + { + // xgroup(diag) + cout << _("Each file contains 8 byte header with unique IV data.\n"); + } + if(config->chainedNameIV) + { + // xgroup(diag) + cout << _("Filenames encoded using IV chaining mode.\n"); + } + if(config->externalIVChaining) + { + // xgroup(diag) + cout << _("File data IV is chained to filename IV.\n"); + } + if(config->allowHoles) + { + // xgroup(diag) + cout << _("File holes passed through to ciphertext.\n"); + } + cout << "\n"; +} + +shared_ptr EncFSConfig::getCipher() const +{ + return Cipher::New( cipherIface, keySize ); +} + +void EncFSConfig::assignKeyData(const std::string &in) +{ + keyData.assign(in.data(), in.data()+in.length()); +} + +void EncFSConfig::assignKeyData(unsigned char *data, int len) +{ + keyData.assign(data, data+len); +} + +void EncFSConfig::assignSaltData(unsigned char *data, int len) +{ + salt.assign(data, data+len); +} + +unsigned char *EncFSConfig::getKeyData() const +{ + return const_cast(&keyData.front()); +} + +unsigned char *EncFSConfig::getSaltData() const +{ + return const_cast(&salt.front()); +} + +CipherKey EncFSConfig::makeKey(const char *password, int passwdLen) +{ + CipherKey userKey; + shared_ptr cipher = getCipher(); + + // if no salt is set and we're creating a new password for a new + // FS type, then initialize salt.. + if(salt.size() == 0 && kdfIterations == 0 && cfgType >= Config_V6) + { + // upgrade to using salt + salt.resize(20); + } + + if(salt.size() > 0) + { + // if iterations isn't known, then we're creating a new key, so + // randomize the salt.. + if(kdfIterations == 0 && !cipher->randomize( + getSaltData(), salt.size(), true)) + { + cout << _("Error creating salt\n"); + return userKey; + } + + userKey = cipher->newKey( password, passwdLen, + kdfIterations, desiredKDFDuration, + getSaltData(), salt.size()); + } else + { + userKey = cipher->newKey( password, passwdLen ); + } + + return userKey; +} + +CipherKey EncFSConfig::getUserKey(bool useStdin) +{ + char passBuf[MaxPassBuf]; + char *res; + + if( useStdin ) + { + res = fgets( passBuf, sizeof(passBuf), stdin ); + // Kill the trailing newline. + if(passBuf[ strlen(passBuf)-1 ] == '\n') + passBuf[ strlen(passBuf)-1 ] = '\0'; + } else + { + // xgroup(common) + res = readpassphrase( _("EncFS Password: "), + passBuf, sizeof(passBuf), RPP_ECHO_OFF ); + } + + CipherKey userKey; + if(!res) + cerr << _("Zero length password not allowed\n"); + else + userKey = makeKey(passBuf, strlen(passBuf)); + + memset( passBuf, 0, sizeof(passBuf) ); + + return userKey; +} + +std::string readPassword( int FD ) +{ + char buffer[1024]; + string result; + + while(1) + { + ssize_t rdSize = recv(FD, buffer, sizeof(buffer), 0); + + if(rdSize > 0) + { + result.append( buffer, rdSize ); + memset(buffer, 0, sizeof(buffer)); + } else + break; + } + + // chop off trailing "\n" if present.. + // This is done so that we can use standard programs like ssh-askpass + // without modification, as it returns trailing newline.. + if(!result.empty() && result[ result.length()-1 ] == '\n' ) + result.resize( result.length() -1 ); + + return result; +} + +CipherKey EncFSConfig::getUserKey( const std::string &passProg, + const std::string &rootDir ) +{ + // have a child process run the command and get the result back to us. + int fds[2], pid; + int res; + CipherKey result; + + res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); + if(res == -1) + { + perror(_("Internal error: socketpair() failed")); + return result; + } + rDebug("getUserKey: fds = %i, %i", fds[0], fds[1]); + + pid = fork(); + if(pid == -1) + { + perror(_("Internal error: fork() failed")); + close(fds[0]); + close(fds[1]); + return result; + } + + if(pid == 0) + { + const char *argv[4]; + argv[0] = "/bin/sh"; + argv[1] = "-c"; + argv[2] = passProg.c_str(); + argv[3] = 0; + + // child process.. run the command and send output to fds[0] + close(fds[1]); // we don't use the other half.. + + // make a copy of stdout and stderr descriptors, and set an environment + // variable telling where to find them, in case a child wants it.. + int stdOutCopy = dup( STDOUT_FILENO ); + int stdErrCopy = dup( STDERR_FILENO ); + // replace STDOUT with our socket, which we'll used to receive the + // password.. + dup2( fds[0], STDOUT_FILENO ); + + // ensure that STDOUT_FILENO and stdout/stderr are not closed on exec.. + fcntl(STDOUT_FILENO, F_SETFD, 0); // don't close on exec.. + fcntl(stdOutCopy, F_SETFD, 0); + fcntl(stdErrCopy, F_SETFD, 0); + + char tmpBuf[8]; + + setenv(ENCFS_ENV_ROOTDIR, rootDir.c_str(), 1); + + snprintf(tmpBuf, sizeof(tmpBuf)-1, "%i", stdOutCopy); + setenv(ENCFS_ENV_STDOUT, tmpBuf, 1); + + snprintf(tmpBuf, sizeof(tmpBuf)-1, "%i", stdErrCopy); + setenv(ENCFS_ENV_STDERR, tmpBuf, 1); + + execvp( argv[0], (char * const *)argv ); // returns only on error.. + + perror(_("Internal error: failed to exec program")); + exit(1); + } + + close(fds[0]); + string password = readPassword(fds[1]); + close(fds[1]); + + waitpid(pid, NULL, 0); + + // convert to key.. + result = makeKey(password.c_str(), password.length()); + + // clear buffer.. + password.assign( password.length(), '\0' ); + + return result; +} + +CipherKey EncFSConfig::getNewUserKey() +{ + CipherKey userKey; + char passBuf[MaxPassBuf]; + char passBuf2[MaxPassBuf]; + + do + { + // xgroup(common) + char *res1 = readpassphrase(_("New Encfs Password: "), passBuf, + sizeof(passBuf)-1, RPP_ECHO_OFF); + // xgroup(common) + char *res2 = readpassphrase(_("Verify Encfs Password: "), passBuf2, + sizeof(passBuf2)-1, RPP_ECHO_OFF); + + if(res1 && res2 && !strcmp(passBuf, passBuf2)) + { + userKey = makeKey(passBuf, strlen(passBuf)); + } else + { + // xgroup(common) -- probably not common, but group with the others + cerr << _("Passwords did not match, please try again\n"); + } + + memset( passBuf, 0, sizeof(passBuf) ); + memset( passBuf2, 0, sizeof(passBuf2) ); + } while( !userKey ); + + return userKey; +} + +RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) +{ + RootPtr rootInfo; + boost::shared_ptr config(new EncFSConfig); + + if(readConfig( opts->rootDir, config ) != Config_None) + { + if(opts->reverseEncryption) + { + if (config->blockMACBytes != 0 || config->blockMACRandBytes != 0 + || config->uniqueIV || config->externalIVChaining + || config->chainedNameIV ) + { + cout << _("The configuration loaded is not compatible with --reverse\n"); + return rootInfo; + } + } + + // first, instanciate the cipher. + shared_ptr cipher = config->getCipher(); + if(!cipher) + { + rError(_("Unable to find cipher %s, version %i:%i:%i"), + config->cipherIface.name().c_str(), + config->cipherIface.current(), + config->cipherIface.revision(), + config->cipherIface.age()); + // xgroup(diag) + cout << _("The requested cipher interface is not available\n"); + return rootInfo; + } + + // get user key + CipherKey userKey; + + if(opts->passwordProgram.empty()) + { + rDebug( "useStdin: %i", opts->useStdin ); + if (opts->annotate) + cerr << "$PROMPT$ passwd" << endl; + userKey = config->getUserKey( opts->useStdin ); + } else + userKey = config->getUserKey( opts->passwordProgram, opts->rootDir ); + + if(!userKey) + return rootInfo; + + rDebug("cipher key size = %i", cipher->encodedKeySize()); + // decode volume key.. + CipherKey volumeKey = cipher->readKey( + config->getKeyData(), userKey, opts->checkKey); userKey.reset(); - config->assignKeyData(encodedKey, encodedKeySize); - delete[] encodedKey; - if(!volumeKey) { - rWarning(_("Failure generating new volume key! " - "Please report this error.")); - return rootInfo; + // xgroup(diag) + cout << _("Error decoding volume key, password incorrect\n"); + return rootInfo; } - if(!saveConfig( Config_V6, rootDir, config )) - return rootInfo; - - // fill in config struct - shared_ptr nameCoder = NameIO::New( config->nameIface, - cipher, volumeKey ); + shared_ptr nameCoder = NameIO::New( config->nameIface, + cipher, volumeKey ); if(!nameCoder) { - rWarning(_("Name coding interface not supported")); - cout << _("The filename encoding interface requested is not available") - << endl; - return rootInfo; + rError(_("Unable to find nameio interface %s, version %i:%i:%i"), + config->nameIface.name().c_str(), + config->nameIface.current(), + config->nameIface.revision(), + config->nameIface.age()); + // xgroup(diag) + cout << _("The requested filename coding interface is " + "not available\n"); + return rootInfo; } - - nameCoder->setChainedNameIV( config->chainedNameIV ); - nameCoder->setReverseEncryption( reverseEncryption ); - FSConfigPtr fsConfig (new FSConfig); + nameCoder->setChainedNameIV( config->chainedNameIV ); + nameCoder->setReverseEncryption( opts->reverseEncryption ); + + FSConfigPtr fsConfig( new FSConfig ); fsConfig->cipher = cipher; fsConfig->key = volumeKey; fsConfig->nameCoding = nameCoder; fsConfig->config = config; - fsConfig->forceDecode = forceDecode; - fsConfig->reverseEncryption = reverseEncryption; - fsConfig->idleTracking = enableIdleTracking; + fsConfig->forceDecode = opts->forceDecode; + fsConfig->reverseEncryption = opts->reverseEncryption; fsConfig->opts = opts; rootInfo = RootPtr( new EncFS_Root ); rootInfo->cipher = cipher; rootInfo->volumeKey = volumeKey; rootInfo->root = shared_ptr( - new DirNode( ctx, rootDir, fsConfig )); - - return rootInfo; -} - -void showFSInfo( const boost::shared_ptr &config ) -{ - shared_ptr cipher = Cipher::New( config->cipherIface, -1 ); + new DirNode( ctx, opts->rootDir, fsConfig )); + } else + { + if(opts->createIfNotFound) { - cout << autosprintf( - // xgroup(diag) - _("Filesystem cipher: \"%s\", version %i:%i:%i"), - config->cipherIface.name().c_str(), config->cipherIface.current(), - config->cipherIface.revision(), config->cipherIface.age()); - // check if we support this interface.. - if(!cipher) - cout << _(" (NOT supported)\n"); - else - { - // if we're using a newer interface, show the version number - if( config->cipherIface != cipher->interface() ) - { - Interface iface = cipher->interface(); - // xgroup(diag) - cout << autosprintf(_(" (using %i:%i:%i)\n"), - iface.current(), iface.revision(), iface.age()); - } else - cout << "\n"; - } - } - { - // xgroup(diag) - cout << autosprintf(_("Filename encoding: \"%s\", version %i:%i:%i"), - config->nameIface.name().c_str(), config->nameIface.current(), - config->nameIface.revision(), config->nameIface.age()); - - // check if we support the filename encoding interface.. - shared_ptr nameCoder = NameIO::New( config->nameIface, - cipher, CipherKey() ); - if(!nameCoder) - { - // xgroup(diag) - cout << _(" (NOT supported)\n"); - } else - { - // if we're using a newer interface, show the version number - if( config->nameIface != nameCoder->interface() ) - { - Interface iface = nameCoder->interface(); - cout << autosprintf(_(" (using %i:%i:%i)\n"), - iface.current(), iface.revision(), iface.age()); - } else - cout << "\n"; - } - } - { - cout << autosprintf(_("Key Size: %i bits"), config->keySize); - cipher = config->getCipher(); - if(!cipher) - { - // xgroup(diag) - cout << _(" (NOT supported)\n"); - } else - cout << "\n"; - } - if(config->kdfIterations > 0 && config->salt.size() > 0) - { - cout << autosprintf(_("Using PBKDF2, with %i iterations"), - config->kdfIterations) << "\n"; - cout << autosprintf(_("Salt Size: %i bits"), - 8*(int)config->salt.size()) << "\n"; - } - if(config->blockMACBytes || config->blockMACRandBytes) - { - if(config->subVersion < 20040813) - { - cout << autosprintf( - // xgroup(diag) - _("Block Size: %i bytes + %i byte MAC header"), - config->blockSize, - config->blockMACBytes + config->blockMACRandBytes) << endl; - } else - { - // new version stores the header as part of that block size.. - cout << autosprintf( - // xgroup(diag) - _("Block Size: %i bytes, including %i byte MAC header"), - config->blockSize, - config->blockMACBytes + config->blockMACRandBytes) << endl; - } - } else - { - // xgroup(diag) - cout << autosprintf(_("Block Size: %i bytes"), config->blockSize); - cout << "\n"; + // creating a new encrypted filesystem + rootInfo = createV6Config( ctx, opts ); } + } - if(config->uniqueIV) - { - // xgroup(diag) - cout << _("Each file contains 8 byte header with unique IV data.\n"); - } - if(config->chainedNameIV) - { - // xgroup(diag) - cout << _("Filenames encoded using IV chaining mode.\n"); - } - if(config->externalIVChaining) - { - // xgroup(diag) - cout << _("File data IV is chained to filename IV.\n"); - } - if(config->allowHoles) - { - // xgroup(diag) - cout << _("File holes passed through to ciphertext.\n"); - } - cout << "\n"; -} - -shared_ptr EncFSConfig::getCipher() const -{ - return Cipher::New( cipherIface, keySize ); -} - -void EncFSConfig::assignKeyData(const std::string &in) -{ - keyData.assign(in.data(), in.data()+in.length()); -} - -void EncFSConfig::assignKeyData(unsigned char *data, int len) -{ - keyData.assign(data, data+len); -} - -void EncFSConfig::assignSaltData(unsigned char *data, int len) -{ - salt.assign(data, data+len); -} - -unsigned char *EncFSConfig::getKeyData() const -{ - return const_cast(&keyData.front()); -} - -unsigned char *EncFSConfig::getSaltData() const -{ - return const_cast(&salt.front()); -} - -CipherKey EncFSConfig::makeKey(const char *password, int passwdLen) -{ - CipherKey userKey; - shared_ptr cipher = getCipher(); - - // if no salt is set and we're creating a new password for a new - // FS type, then initialize salt.. - if(salt.size() == 0 && kdfIterations == 0 && cfgType >= Config_V6) - { - // upgrade to using salt - salt.resize(20); - } - - if(salt.size() > 0) - { - // if iterations isn't known, then we're creating a new key, so - // randomize the salt.. - if(kdfIterations == 0 && !cipher->randomize( - getSaltData(), salt.size(), true)) - { - cout << _("Error creating salt\n"); - return userKey; - } - - userKey = cipher->newKey( password, passwdLen, - kdfIterations, desiredKDFDuration, - getSaltData(), salt.size()); - } else - { - userKey = cipher->newKey( password, passwdLen ); - } - - return userKey; -} - -CipherKey EncFSConfig::getUserKey(bool useStdin) -{ - char passBuf[MaxPassBuf]; - char *res; - - if( useStdin ) - { - res = fgets( passBuf, sizeof(passBuf), stdin ); - // Kill the trailing newline. - if(passBuf[ strlen(passBuf)-1 ] == '\n') - passBuf[ strlen(passBuf)-1 ] = '\0'; - } else - { - // xgroup(common) - res = readpassphrase( _("EncFS Password: "), - passBuf, sizeof(passBuf), RPP_ECHO_OFF ); - } - - CipherKey userKey; - if(!res) - cerr << _("Zero length password not allowed\n"); - else - userKey = makeKey(passBuf, strlen(passBuf)); - - memset( passBuf, 0, sizeof(passBuf) ); - - return userKey; -} - -std::string readPassword( int FD ) -{ - char buffer[1024]; - string result; - - while(1) - { - ssize_t rdSize = recv(FD, buffer, sizeof(buffer), 0); - - if(rdSize > 0) - { - result.append( buffer, rdSize ); - memset(buffer, 0, sizeof(buffer)); - } else - break; - } - - // chop off trailing "\n" if present.. - // This is done so that we can use standard programs like ssh-askpass - // without modification, as it returns trailing newline.. - if(!result.empty() && result[ result.length()-1 ] == '\n' ) - result.resize( result.length() -1 ); - - return result; -} - -CipherKey EncFSConfig::getUserKey( const std::string &passProg, - const std::string &rootDir ) -{ - // have a child process run the command and get the result back to us. - int fds[2], pid; - int res; - CipherKey result; - - res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); - if(res == -1) - { - perror(_("Internal error: socketpair() failed")); - return result; - } - rDebug("getUserKey: fds = %i, %i", fds[0], fds[1]); - - pid = fork(); - if(pid == -1) - { - perror(_("Internal error: fork() failed")); - close(fds[0]); - close(fds[1]); - return result; - } - - if(pid == 0) - { - const char *argv[4]; - argv[0] = "/bin/sh"; - argv[1] = "-c"; - argv[2] = passProg.c_str(); - argv[3] = 0; - - // child process.. run the command and send output to fds[0] - close(fds[1]); // we don't use the other half.. - - // make a copy of stdout and stderr descriptors, and set an environment - // variable telling where to find them, in case a child wants it.. - int stdOutCopy = dup( STDOUT_FILENO ); - int stdErrCopy = dup( STDERR_FILENO ); - // replace STDOUT with our socket, which we'll used to receive the - // password.. - dup2( fds[0], STDOUT_FILENO ); - - // ensure that STDOUT_FILENO and stdout/stderr are not closed on exec.. - fcntl(STDOUT_FILENO, F_SETFD, 0); // don't close on exec.. - fcntl(stdOutCopy, F_SETFD, 0); - fcntl(stdErrCopy, F_SETFD, 0); - - char tmpBuf[8]; - - setenv(ENCFS_ENV_ROOTDIR, rootDir.c_str(), 1); - - snprintf(tmpBuf, sizeof(tmpBuf)-1, "%i", stdOutCopy); - setenv(ENCFS_ENV_STDOUT, tmpBuf, 1); - - snprintf(tmpBuf, sizeof(tmpBuf)-1, "%i", stdErrCopy); - setenv(ENCFS_ENV_STDERR, tmpBuf, 1); - - execvp( argv[0], (char * const *)argv ); // returns only on error.. - - perror(_("Internal error: failed to exec program")); - exit(1); - } - - close(fds[0]); - string password = readPassword(fds[1]); - close(fds[1]); - - waitpid(pid, NULL, 0); - - // convert to key.. - result = makeKey(password.c_str(), password.length()); - - // clear buffer.. - password.assign( password.length(), '\0' ); - - return result; -} - -CipherKey EncFSConfig::getNewUserKey() -{ - CipherKey userKey; - char passBuf[MaxPassBuf]; - char passBuf2[MaxPassBuf]; - - do - { - // xgroup(common) - char *res1 = readpassphrase(_("New Encfs Password: "), passBuf, - sizeof(passBuf)-1, RPP_ECHO_OFF); - // xgroup(common) - char *res2 = readpassphrase(_("Verify Encfs Password: "), passBuf2, - sizeof(passBuf2)-1, RPP_ECHO_OFF); - - if(res1 && res2 && !strcmp(passBuf, passBuf2)) - { - userKey = makeKey(passBuf, strlen(passBuf)); - } else - { - // xgroup(common) -- probably not common, but group with the others - cerr << _("Passwords did not match, please try again\n"); - } - - memset( passBuf, 0, sizeof(passBuf) ); - memset( passBuf2, 0, sizeof(passBuf2) ); - } while( !userKey ); - - return userKey; -} - -RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) -{ - RootPtr rootInfo; - boost::shared_ptr config(new EncFSConfig); - - if(readConfig( opts->rootDir, config ) != Config_None) - { - if(opts->reverseEncryption) - { - if (config->blockMACBytes != 0 || config->blockMACRandBytes != 0 - || config->uniqueIV || config->externalIVChaining - || config->chainedNameIV ) - { - cout << _("The configuration loaded is not compatible with --reverse\n"); - return rootInfo; - } - } - - // first, instanciate the cipher. - shared_ptr cipher = config->getCipher(); - if(!cipher) - { - rError(_("Unable to find cipher %s, version %i:%i:%i"), - config->cipherIface.name().c_str(), - config->cipherIface.current(), - config->cipherIface.revision(), - config->cipherIface.age()); - // xgroup(diag) - cout << _("The requested cipher interface is not available\n"); - return rootInfo; - } - - // get user key - CipherKey userKey; - - if(opts->passwordProgram.empty()) - { - rDebug( "useStdin: %i", opts->useStdin ); - if (opts->annotate) - cerr << "$PROMPT$ passwd" << endl; - userKey = config->getUserKey( opts->useStdin ); - } else - userKey = config->getUserKey( opts->passwordProgram, opts->rootDir ); - - if(!userKey) - return rootInfo; - - rDebug("cipher key size = %i", cipher->encodedKeySize()); - // decode volume key.. - CipherKey volumeKey = cipher->readKey( - config->getKeyData(), userKey, opts->checkKey); - userKey.reset(); - - if(!volumeKey) - { - // xgroup(diag) - cout << _("Error decoding volume key, password incorrect\n"); - return rootInfo; - } - - shared_ptr nameCoder = NameIO::New( config->nameIface, - cipher, volumeKey ); - if(!nameCoder) - { - rError(_("Unable to find nameio interface %s, version %i:%i:%i"), - config->nameIface.name().c_str(), - config->nameIface.current(), - config->nameIface.revision(), - config->nameIface.age()); - // xgroup(diag) - cout << _("The requested filename coding interface is " - "not available\n"); - return rootInfo; - } - - nameCoder->setChainedNameIV( config->chainedNameIV ); - nameCoder->setReverseEncryption( opts->reverseEncryption ); - - FSConfigPtr fsConfig( new FSConfig ); - fsConfig->cipher = cipher; - fsConfig->key = volumeKey; - fsConfig->nameCoding = nameCoder; - fsConfig->config = config; - fsConfig->forceDecode = opts->forceDecode; - fsConfig->reverseEncryption = opts->reverseEncryption; - fsConfig->opts = opts; - - rootInfo = RootPtr( new EncFS_Root ); - rootInfo->cipher = cipher; - rootInfo->volumeKey = volumeKey; - rootInfo->root = shared_ptr( - new DirNode( ctx, opts->rootDir, fsConfig )); - } else - { - if(opts->createIfNotFound) - { - // creating a new encrypted filesystem - rootInfo = createV6Config( ctx, opts ); - } - } - - return rootInfo; + return rootInfo; } int remountFS(EncFS_Context *ctx) { - rDebug("Attempting to reinitialize filesystem"); + rDebug("Attempting to reinitialize filesystem"); - RootPtr rootInfo = initFS( ctx, ctx->opts ); - if(rootInfo) - { - ctx->setRoot(rootInfo->root); - return 0; - } else - { - rInfo(_("Remount failed")); - return -EACCES; - } + RootPtr rootInfo = initFS( ctx, ctx->opts ); + if(rootInfo) + { + ctx->setRoot(rootInfo->root); + return 0; + } else + { + rInfo(_("Remount failed")); + return -EACCES; + } } diff --git a/encfs/FileUtils.h b/encfs/FileUtils.h index b852ee7..febe328 100644 --- a/encfs/FileUtils.h +++ b/encfs/FileUtils.h @@ -44,96 +44,96 @@ class DirNode; struct EncFS_Root { - boost::shared_ptr cipher; - CipherKey volumeKey; - boost::shared_ptr root; + boost::shared_ptr cipher; + CipherKey volumeKey; + boost::shared_ptr root; - EncFS_Root(); - ~EncFS_Root(); + EncFS_Root(); + ~EncFS_Root(); }; typedef boost::shared_ptr RootPtr; enum ConfigMode { - Config_Prompt, - Config_Standard, - Config_Paranoia + Config_Prompt, + Config_Standard, + Config_Paranoia }; struct EncFS_Opts { - std::string rootDir; - bool createIfNotFound; // create filesystem if not found - bool idleTracking; // turn on idle monitoring of filesystem - bool mountOnDemand; // mounting on-demand + std::string rootDir; + bool createIfNotFound; // create filesystem if not found + bool idleTracking; // turn on idle monitoring of filesystem + bool mountOnDemand; // mounting on-demand - bool checkKey; // check crypto key decoding - bool forceDecode; // force decode on MAC block failures + bool checkKey; // check crypto key decoding + bool forceDecode; // force decode on MAC block failures - std::string passwordProgram; // path to password program (or empty) - bool useStdin; // read password from stdin rather then prompting - bool annotate; // print annotation line prompt to stderr. + std::string passwordProgram; // path to password program (or empty) + bool useStdin; // read password from stdin rather then prompting + bool annotate; // print annotation line prompt to stderr. - bool ownerCreate; // set owner of new files to caller + bool ownerCreate; // set owner of new files to caller - bool reverseEncryption; // Reverse encryption + bool reverseEncryption; // Reverse encryption - ConfigMode configMode; + ConfigMode configMode; - EncFS_Opts() - { - createIfNotFound = true; - idleTracking = false; - mountOnDemand = false; - checkKey = true; - forceDecode = false; - useStdin = false; - annotate = false; - ownerCreate = false; - reverseEncryption = false; - configMode = Config_Prompt; - } + EncFS_Opts() + { + createIfNotFound = true; + idleTracking = false; + mountOnDemand = false; + checkKey = true; + forceDecode = false; + useStdin = false; + annotate = false; + ownerCreate = false; + reverseEncryption = false; + configMode = Config_Prompt; + } }; /* Read existing config file. Looks for any supported configuration version. -*/ + */ ConfigType readConfig( const std::string &rootDir, - const boost::shared_ptr &config ); + const boost::shared_ptr &config ); /* Save the configuration. Saves back as the same configuration type as was read from. -*/ + */ bool saveConfig( ConfigType type, const std::string &rootdir, - const boost::shared_ptr &config ); + const boost::shared_ptr &config ); class EncFS_Context; RootPtr initFS( EncFS_Context *ctx, const boost::shared_ptr &opts ); RootPtr createV6Config( EncFS_Context *ctx, - const boost::shared_ptr &opts ); + const boost::shared_ptr &opts ); void showFSInfo( const boost::shared_ptr &config ); bool readV4Config( const char *configFile, - const boost::shared_ptr &config, - struct ConfigInfo *); + const boost::shared_ptr &config, + struct ConfigInfo *); bool writeV4Config( const char *configFile, - const boost::shared_ptr &config); + const boost::shared_ptr &config); bool readV5Config( const char *configFile, - const boost::shared_ptr &config, - struct ConfigInfo *); + const boost::shared_ptr &config, + struct ConfigInfo *); bool writeV5Config( const char *configFile, - const boost::shared_ptr &config); + const boost::shared_ptr &config); bool readV6Config( const char *configFile, - const boost::shared_ptr &config, - struct ConfigInfo *); + const boost::shared_ptr &config, + struct ConfigInfo *); bool writeV6Config( const char *configFile, - const boost::shared_ptr &config); + const boost::shared_ptr &config); #endif From 67821fb2099d05b558f89cddcdc64cebbc5aada5 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Thu, 26 Apr 2012 02:30:08 +0000 Subject: [PATCH 02/51] add name collision test git-svn-id: http://encfs.googlecode.com/svn/trunk@79 db9cf616-1c43-0410-9cb8-a902689de0d6 --- encfs/test.cpp | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/encfs/test.cpp b/encfs/test.cpp index 95517c4..4bb2faa 100644 --- a/encfs/test.cpp +++ b/encfs/test.cpp @@ -47,6 +47,8 @@ #endif #endif +#include + using namespace std; using namespace rel; @@ -106,7 +108,8 @@ int checkErrorPropogation( const shared_ptr &cipher, const char TEST_ROOTDIR[] = "/foo"; static -bool testNameCoding( DirNode &dirNode, bool verbose ) +bool testNameCoding( DirNode &dirNode, bool verbose, + bool collisionTest = false ) { // encrypt a name const char *name[] = { @@ -161,6 +164,29 @@ bool testNameCoding( DirNode &dirNode, bool verbose ) orig++; } + if (collisionTest) + { + if (verbose) + cerr << "Checking for name collections, this will take a while..\n"; + // check for collision rate + char buf[64]; + tr1::unordered_set encryptedNames; + for (long i=0; i < 10000000; i++) + { + snprintf(buf, sizeof(buf), "%li", i); + string encName = dirNode.relativeCipherPath( buf ); + // simulate a case-insisitive filesystem.. + std::transform(encName.begin(), encName.end(), encName.begin(), + ::toupper); + + if (encryptedNames.insert(encName).second == false) { + cerr << "collision detected after " << i << " iterations"; + break; + } + } + cerr << "NO collisions detected"; + } + return true; } From 67c72dfe99fd0767d9608583a79a251cf9a7052b Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Thu, 26 Apr 2012 02:34:15 +0000 Subject: [PATCH 03/51] Replace boost::serialization. Boost::serialization and the corresponding internal configuration structure are replace with a protocol buffer message. Dropped support for writing old configuration files. Only the new format can be written. A password change will write a newly formatted configuration file, but does not delete the old file. Version bumped to 1.8 git-svn-id: http://encfs.googlecode.com/svn/trunk@80 db9cf616-1c43-0410-9cb8-a902689de0d6 --- ChangeLog | 28 ++ configure.ac | 18 +- encfs/BlockFileIO.cpp | 3 +- encfs/BlockNameIO.cpp | 9 +- encfs/BlockNameIO.h | 6 +- encfs/Cipher.cpp | 3 +- encfs/Cipher.h | 12 +- encfs/CipherFileIO.cpp | 11 +- encfs/CipherFileIO.h | 2 +- encfs/DirNode.cpp | 4 +- encfs/FSConfig.h | 87 +--- encfs/FileIO.h | 2 +- encfs/FileNode.cpp | 6 +- encfs/FileUtils.cpp | 886 +++++++++++++++++++---------------------- encfs/FileUtils.h | 28 +- encfs/Interface.cpp | 232 +++-------- encfs/Interface.h | 71 +--- encfs/MACFileIO.cpp | 22 +- encfs/MACFileIO.h | 2 +- encfs/Makefile.am | 19 +- encfs/MemoryPool.cpp | 33 ++ encfs/MemoryPool.h | 9 + encfs/NameIO.cpp | 3 +- encfs/NameIO.h | 10 +- encfs/NullCipher.cpp | 3 +- encfs/NullCipher.h | 6 +- encfs/NullNameIO.cpp | 3 +- encfs/NullNameIO.h | 4 +- encfs/RawFileIO.cpp | 6 +- encfs/RawFileIO.h | 2 +- encfs/SSL_Cipher.cpp | 33 +- encfs/SSL_Cipher.h | 8 +- encfs/StreamNameIO.cpp | 7 +- encfs/StreamNameIO.h | 6 +- encfs/XmlReader.cpp | 191 +++++++++ encfs/XmlReader.h | 78 ++++ encfs/config.proto | 36 ++ encfs/encfsctl.cpp | 50 +-- encfs/main.cpp | 1 - encfs/test.cpp | 48 +-- 40 files changed, 1028 insertions(+), 960 deletions(-) create mode 100644 encfs/XmlReader.cpp create mode 100644 encfs/XmlReader.h create mode 100644 encfs/config.proto diff --git a/ChangeLog b/ChangeLog index 963bcf6..af35923 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +Thu Mar 22 2012 Valient Gough + * skip name collision test + * bump version to 1.8.0 + * drop boost serialization from requirements + +Sun Mar 4 2012 Valient Gough + * bump ld version + * replace EncFSConfig with protocol buffer + +Fri Mar 2 2012 Valient Gough + * replace boost serialization with protocol buffer support + +Wed Feb 29 2012 Valient Gough + * switch to OpenSSL B64 decode to be comptible with boost serialization + * implement v6 config reader using XML reader based on tinyxml + +Mon Jan 2 2012 Valient Gough + * test for name case collisions in b64 coding + +Thu Dec 29 2011 Valient Gough + * add base32 support for name encoding + +Thu Mar 3 2011 Valient Gough + * update copyright on BlockNameIO + +Thu Dec 29 2011 Valient Gough + * revert fuse_unmount change, wasn't working + Wed Dec 28 2011 Valient Gough * remove m4-local * bump version to 1.7.5 diff --git a/configure.ac b/configure.ac index 32fcf89..0a1d3e5 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(encfs/encfs.h) dnl a source file from your sub dir AC_CONFIG_AUX_DIR([build-aux]) -AM_INIT_AUTOMAKE(encfs, 1.7.5) dnl searches for some needed programs +AM_INIT_AUTOMAKE(encfs, 1.8.0) dnl searches for some needed programs AC_CONFIG_MACRO_DIR([m4]) AC_CANONICAL_HOST @@ -48,7 +48,6 @@ AX_PTHREAD AX_BOOST_BASE([1.34]) AX_BOOST_SYSTEM -AX_BOOST_SERIALIZATION AX_BOOST_FILESYSTEM dnl Need to include any user specified flags in the tests below, as they might @@ -203,6 +202,21 @@ if test "$with_rlog" = "test" && test "x$RLOG_LIBS" = "x"; then [AC_MSG_ERROR([EncFS depends on librlog])]) fi +# find Protocol Buffers +PKG_CHECK_MODULES(PROTOBUF, protobuf >= 2.0) +AC_PATH_PROG(PROTOC, protoc, [no]) +if test "$PROTOC" == "no"; then + AC_MSG_FAILURE([Protocol Buffers compiler 'protoc' is required to build.]) +fi + +# find TinyXML +AC_LANG_PUSH([C++]) +CPPFLAGS="$CPPFLAGS -DTIXML_USE_STL" +AC_CHECK_HEADER([tinyxml.h],,[AC_MSG_ERROR([tinyxml.h not found])]) +AC_CHECK_LIB([tinyxml],[main],, + [AC_MSG_ERROR([you must install libtinyxml dev])]) +AC_LANG_POP([C++]) + # look for pod2man program for building man pages AC_PATH_PROG(POD2MAN, pod2man, [no]) AC_PATH_PROG(POD2HTML, pod2html, [no]) diff --git a/encfs/BlockFileIO.cpp b/encfs/BlockFileIO.cpp index e6b9df5..9d65313 100644 --- a/encfs/BlockFileIO.cpp +++ b/encfs/BlockFileIO.cpp @@ -18,6 +18,7 @@ #include "BlockFileIO.h" #include "MemoryPool.h" +#include "config.pb.h" #include #include @@ -38,7 +39,7 @@ static void clearCache( IORequest &req, int blockSize ) BlockFileIO::BlockFileIO( int blockSize, const FSConfigPtr &cfg ) : _blockSize( blockSize ) - , _allowHoles( cfg->config->allowHoles ) + , _allowHoles( cfg->config->allow_holes() ) { rAssert( _blockSize > 1 ); _cache.data = new unsigned char [ _blockSize ]; diff --git a/encfs/BlockNameIO.cpp b/encfs/BlockNameIO.cpp index c754bab..34366a3 100644 --- a/encfs/BlockNameIO.cpp +++ b/encfs/BlockNameIO.cpp @@ -31,7 +31,6 @@ #include "i18n.h" using namespace rlog; -using namespace rel; using namespace boost; static RLogChannel * Info = DEF_CHANNEL( "info/nameio", Log_Info ); @@ -94,16 +93,16 @@ Interface BlockNameIO::CurrentInterface(bool caseSensitive) { // implement major version 4 plus support for two prior versions if (caseSensitive) - return Interface("nameio/block32", 4, 0, 2); + return makeInterface("nameio/block32", 4, 0, 2); else - return Interface("nameio/block", 4, 0, 2); + return makeInterface("nameio/block", 4, 0, 2); } -BlockNameIO::BlockNameIO( const rel::Interface &iface, +BlockNameIO::BlockNameIO( const Interface &iface, const shared_ptr &cipher, const CipherKey &key, int blockSize, bool caseSensitiveEncoding ) - : _interface( iface.current() ) + : _interface( iface.major() ) , _bs( blockSize ) , _cipher( cipher ) , _key( key ) diff --git a/encfs/BlockNameIO.h b/encfs/BlockNameIO.h index 591d042..a2a0f5f 100644 --- a/encfs/BlockNameIO.h +++ b/encfs/BlockNameIO.h @@ -33,15 +33,15 @@ class Cipher; class BlockNameIO : public NameIO { public: - static rel::Interface CurrentInterface(bool caseSensitive = false); + static Interface CurrentInterface(bool caseSensitive = false); - BlockNameIO( const rel::Interface &iface, + BlockNameIO( const Interface &iface, const boost::shared_ptr &cipher, const CipherKey &key, int blockSize, bool caseSensitiveEncoding = false ); virtual ~BlockNameIO(); - virtual rel::Interface interface() const; + virtual Interface interface() const; virtual int maxEncodedNameLen( int plaintextNameLen ) const; virtual int maxDecodedNameLen( int encodedNameLen ) const; diff --git a/encfs/Cipher.cpp b/encfs/Cipher.cpp index fe00b3a..1c1047c 100644 --- a/encfs/Cipher.cpp +++ b/encfs/Cipher.cpp @@ -34,7 +34,6 @@ #include "SSL_Cipher.h" using namespace std; -using namespace rel; using boost::shared_ptr; #define REF_MODULE(TYPE) \ @@ -150,7 +149,7 @@ shared_ptr Cipher::New( const Interface &iface, int keyLen ) for(it = gCipherMap->begin(); it != mapEnd; ++it) { // TODO: we should look for the newest implementation.. - if( it->second.iface.implements( iface ) ) + if( implements(it->second.iface, iface) ) { CipherConstructor fn = it->second.constructor; // pass in requested interface.. diff --git a/encfs/Cipher.h b/encfs/Cipher.h index a5a6a38..83648f3 100644 --- a/encfs/Cipher.h +++ b/encfs/Cipher.h @@ -42,14 +42,14 @@ class Cipher public: // if no key length was indicated when cipher was registered, then keyLen // <= 0 will be used. - typedef boost::shared_ptr (*CipherConstructor)( const rel::Interface &iface, + typedef boost::shared_ptr (*CipherConstructor)( const Interface &iface, int keyLenBits ); struct CipherAlgorithm { std::string name; std::string description; - rel::Interface iface; + Interface iface; Range keyLength; Range blockSize; }; @@ -59,7 +59,7 @@ public: static AlgorithmList GetAlgorithmList( bool includeHidden = false ); - static boost::shared_ptr New( const rel::Interface &iface, + static boost::shared_ptr New( const Interface &iface, int keyLen = -1); static boost::shared_ptr New( const std::string &cipherName, int keyLen = -1 ); @@ -67,12 +67,12 @@ public: static bool Register(const char *cipherName, const char *description, - const rel::Interface &iface, + const Interface &iface, CipherConstructor constructor, bool hidden = false); static bool Register(const char *cipherName, const char *description, - const rel::Interface &iface, + const Interface &iface, const Range &keyLength, const Range &blockSize, CipherConstructor constructor, bool hidden = false); @@ -81,7 +81,7 @@ public: Cipher(); virtual ~Cipher(); - virtual rel::Interface interface() const =0; + virtual Interface interface() const =0; // create a new key based on a password // if iterationCount == 0, then iteration count will be determined diff --git a/encfs/CipherFileIO.cpp b/encfs/CipherFileIO.cpp index 11e97a0..d7af35b 100644 --- a/encfs/CipherFileIO.cpp +++ b/encfs/CipherFileIO.cpp @@ -19,6 +19,7 @@ #include "Cipher.h" #include "MemoryPool.h" +#include "config.pb.h" #include #include @@ -34,7 +35,7 @@ using boost::shared_ptr; filesystem at the filesystem configuration level. When headers are disabled, 2:0 is compatible with version 1:0. */ -static rel::Interface CipherFileIO_iface("FileIO/Cipher", 2, 0, 1); +static Interface CipherFileIO_iface = makeInterface("FileIO/Cipher", 2, 0, 1); const int HEADER_SIZE = 8; // 64 bit initialization vector.. @@ -51,9 +52,9 @@ static bool checkSize( int fsBlockSize, int cipherBlockSize ) CipherFileIO::CipherFileIO( const shared_ptr &_base, const FSConfigPtr &cfg) - : BlockFileIO( cfg->config->blockSize, cfg ) + : BlockFileIO( cfg->config->block_size(), cfg ) , base( _base ) - , haveHeader( cfg->config->uniqueIV ) + , haveHeader( cfg->config->unique_iv() ) , externalIV( 0 ) , fileIV( 0 ) , lastFlags( 0 ) @@ -65,7 +66,7 @@ CipherFileIO::CipherFileIO( const shared_ptr &_base, static bool warnOnce = false; if(!warnOnce) - warnOnce = checkSize( fsConfig->config->blockSize, + warnOnce = checkSize( fsConfig->config->block_size(), fsConfig->cipher->cipherBlockSize() ); } @@ -73,7 +74,7 @@ CipherFileIO::~CipherFileIO() { } -rel::Interface CipherFileIO::interface() const +Interface CipherFileIO::interface() const { return CipherFileIO_iface; } diff --git a/encfs/CipherFileIO.h b/encfs/CipherFileIO.h index 04200d5..d4b4c1b 100644 --- a/encfs/CipherFileIO.h +++ b/encfs/CipherFileIO.h @@ -38,7 +38,7 @@ public: const FSConfigPtr &cfg); virtual ~CipherFileIO(); - virtual rel::Interface interface() const; + virtual Interface interface() const; virtual void setFileName( const char *fileName ); virtual const char *getFileName() const; diff --git a/encfs/DirNode.cpp b/encfs/DirNode.cpp index 18429f1..7d95fcc 100644 --- a/encfs/DirNode.cpp +++ b/encfs/DirNode.cpp @@ -690,7 +690,7 @@ int DirNode::link( const char *from, const char *to ) rLog(Info, "link %s -> %s", fromCName.c_str(), toCName.c_str()); int res = -EPERM; - if( fsConfig->config->externalIVChaining ) + if( fsConfig->config->external_iv() ) { rLog(Info, "hard links not supported with external IV chaining!"); } else @@ -756,7 +756,7 @@ shared_ptr DirNode::findOrCreate( const char *plainName) plainName, (rootDir + cipherName).c_str())); - if(fsConfig->config->externalIVChaining) + if(fsConfig->config->external_iv()) node->setName(0, 0, iv); rLog(Info, "created FileNode for %s", node->cipherName()); diff --git a/encfs/FSConfig.h b/encfs/FSConfig.h index 81ac0eb..32bc329 100644 --- a/encfs/FSConfig.h +++ b/encfs/FSConfig.h @@ -32,88 +32,37 @@ enum ConfigType { Config_None = 0, Config_Prehistoric, - Config_V3, - Config_V4, - Config_V5, - Config_V6 + Config_V3 = 3, + Config_V4 = 4, + Config_V5 = 5, + Config_V6 = 6, + Config_V7 = 7 }; class EncFS_Opts; class Cipher; class NameIO; +class EncfsConfig; -struct EncFSConfig -{ - ConfigType cfgType; +CipherKey getUserKey(const EncfsConfig &config, bool useStdin); +CipherKey getUserKey(const EncfsConfig &config, + const std::string &passwordProgram, + const std::string &rootDir); - std::string creator; - int subVersion; - - // interface of cipher - rel::Interface cipherIface; - // interface used for file name coding - rel::Interface nameIface; - int keySize; // reported in bits - int blockSize; // reported in bytes - - std::vector keyData; - - std::vector salt; - int kdfIterations; - long desiredKDFDuration; - - int blockMACBytes; // MAC headers on blocks.. - int blockMACRandBytes; // number of random bytes in the block header - - bool uniqueIV; // per-file Initialization Vector - bool externalIVChaining; // IV seeding by filename IV chaining - - bool chainedNameIV; // filename IV chaining - bool allowHoles; // allow holes in files (implicit zero blocks) - - EncFSConfig() - : keyData() - , salt() - { - cfgType = Config_None; - subVersion = 0; - blockMACBytes = 0; - blockMACRandBytes = 0; - uniqueIV = false; - externalIVChaining = false; - chainedNameIV = false; - allowHoles = false; - - kdfIterations = 0; - desiredKDFDuration = 500; - } - - CipherKey getUserKey(bool useStdin); - CipherKey getUserKey(const std::string &passwordProgram, - const std::string &rootDir); - CipherKey getNewUserKey(); +CipherKey getNewUserKey(EncfsConfig &config, bool useStdin, + const std::string &program, const std::string &rootDir); - boost::shared_ptr getCipher() const; +boost::shared_ptr getCipher(const EncfsConfig &cfg); +boost::shared_ptr getCipher(const Interface &iface, int keySize); - // deprecated - void assignKeyData(const std::string &in); - void assignKeyData(unsigned char *data, int length); - void assignSaltData(unsigned char *data, int length); - - unsigned char *getKeyData() const; - unsigned char *getSaltData() const; - -private: - CipherKey makeKey(const char *password, int passwdLen); -}; - // helpers for serializing to/from a stream -std::ostream &operator << (std::ostream &os, const EncFSConfig &cfg); -std::istream &operator >> (std::istream &os, EncFSConfig &cfg); +std::ostream &operator << (std::ostream &os, const EncfsConfig &cfg); +std::istream &operator >> (std::istream &os, EncfsConfig &cfg); +// Filesystem state struct FSConfig { - boost::shared_ptr config; + boost::shared_ptr config; boost::shared_ptr opts; boost::shared_ptr cipher; diff --git a/encfs/FileIO.h b/encfs/FileIO.h index 1889a27..5e0df17 100644 --- a/encfs/FileIO.h +++ b/encfs/FileIO.h @@ -48,7 +48,7 @@ public: FileIO(); virtual ~FileIO(); - virtual rel::Interface interface() const =0; + virtual Interface interface() const =0; // default implementation returns 1, meaning this is not block oriented. virtual int blockSize() const; diff --git a/encfs/FileNode.cpp b/encfs/FileNode.cpp index 4d15037..2671a60 100644 --- a/encfs/FileNode.cpp +++ b/encfs/FileNode.cpp @@ -80,7 +80,7 @@ FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg, shared_ptr rawIO( new RawFileIO( _cname ) ); io = shared_ptr( new CipherFileIO( rawIO, fsConfig )); - if(cfg->config->blockMACBytes || cfg->config->blockMACRandBytes) + if(cfg->config->block_mac_bytes() || cfg->config->block_mac_rand_bytes()) io = shared_ptr(new MACFileIO(io, fsConfig)); } @@ -127,7 +127,7 @@ bool FileNode::setName( const char *plaintextName_, const char *cipherName_, rDebug("calling setIV on %s", cipherName_); if(setIVFirst) { - if(fsConfig->config->externalIVChaining && !setIV(io, iv)) + if(fsConfig->config->external_iv() && !setIV(io, iv)) return false; // now change the name.. @@ -151,7 +151,7 @@ bool FileNode::setName( const char *plaintextName_, const char *cipherName_, io->setFileName( cipherName_ ); } - if(fsConfig->config->externalIVChaining && !setIV(io, iv)) + if(fsConfig->config->external_iv() && !setIV(io, iv)) { _pname = oldPName; _cname = oldCName; diff --git a/encfs/FileUtils.cpp b/encfs/FileUtils.cpp index 9e89d5d..9972731 100644 --- a/encfs/FileUtils.cpp +++ b/encfs/FileUtils.cpp @@ -23,12 +23,14 @@ #include "encfs.h" #include "config.h" +#include "config.pb.h" #include "readpassphrase.h" #include "autosprintf.h" #include "FileUtils.h" #include "ConfigReader.h" +#include "XmlReader.h" #include "FSConfig.h" #include "DirNode.h" @@ -37,6 +39,7 @@ #include "BlockNameIO.h" #include "NullNameIO.h" #include "Context.h" +#include "MemoryPool.h" #include #include @@ -60,21 +63,18 @@ #include #include -#include -#include -#include -#include + +#include +#include // disable rlog section grouping for this file.. seems to cause problems #undef RLOG_SECTION #define RLOG_SECTION -using namespace rel; using namespace rlog; using namespace std; using namespace gnu; namespace fs = boost::filesystem; -namespace serial = boost::serialization; static const int DefaultBlockSize = 1024; // The maximum length of text passwords. If longer are needed, @@ -94,170 +94,34 @@ static const char ENCFS_ENV_STDERR[] = "encfs_stderr"; //static int V5SubVersion = 20040518; //static int V5SubVersion = 20040621; // add external IV chaining static int V5SubVersion = 20040813; // fix MACFileIO block size issues -static int V5SubVersionDefault = 0; // 20080813 was really made on 20080413 -- typo on date.. //const int V6SubVersion = 20080813; // switch to v6/XML, add allowHoles option //const int V6SubVersion = 20080816; // add salt and iteration count const int V6SubVersion = 20100713; // add version field for boost 1.42+ +const int ProtoSubVersion = 20120302; + +const char ConfigFileName[] = ".encfs.txt"; + struct ConfigInfo { - const char *fileName; ConfigType type; + const char *fileName; const char *environmentOverride; bool (*loadFunc)(const char *fileName, - const boost::shared_ptr &config, - ConfigInfo *cfg); - bool (*saveFunc)(const char *fileName, - const boost::shared_ptr &config); - int currentSubVersion; - int defaultSubVersion; + EncfsConfig &config, ConfigInfo *cfg); } ConfigFileMapping[] = { - {".encfs6.xml", Config_V6, "ENCFS6_CONFIG", readV6Config, writeV6Config, - V6SubVersion, 0 }, + {Config_V7, ConfigFileName, "ENCFS_CONFIG", readProtoConfig }, + {Config_V6, ".encfs6.xml", "ENCFS6_CONFIG", readV6Config }, // backward compatible support for older versions - {".encfs5", Config_V5, "ENCFS5_CONFIG", readV5Config, writeV5Config, - V5SubVersion, V5SubVersionDefault }, - {".encfs4", Config_V4, NULL, readV4Config, writeV4Config, 0, 0 }, - // no longer support earlier versions - {".encfs3", Config_V3, NULL, NULL, NULL, 0, 0 }, - {".encfs2", Config_Prehistoric, NULL, NULL, NULL, 0, 0 }, - {".encfs", Config_Prehistoric, NULL, NULL, NULL, 0, 0 }, - {NULL,Config_None, NULL, NULL, NULL, 0, 0}}; - - -#include "boost-versioning.h" - -// define serialization helpers -// TODO(vgough): eliminate entirely -namespace boost -{ -namespace serialization -{ - -template -void save(Archive &ar, const EncFSConfig &cfg, - unsigned int version) -{ - (void)version; - // version 20 (aka 20100613) - if (cfg.subVersion == 0) - ar << make_nvp("version", V6SubVersion); - else - ar << make_nvp("version", cfg.subVersion); - - ar << make_nvp("creator", cfg.creator); - ar << make_nvp("cipherAlg", cfg.cipherIface); - ar << make_nvp("nameAlg", cfg.nameIface); - ar << make_nvp("keySize", cfg.keySize); - ar << make_nvp("blockSize", cfg.blockSize); - ar << make_nvp("uniqueIV", cfg.uniqueIV); - ar << make_nvp("chainedNameIV", cfg.chainedNameIV); - ar << make_nvp("externalIVChaining", cfg.externalIVChaining); - ar << make_nvp("blockMACBytes", cfg.blockMACBytes); - ar << make_nvp("blockMACRandBytes", cfg.blockMACRandBytes); - ar << make_nvp("allowHoles", cfg.allowHoles); - - int encodedSize = cfg.keyData.size(); - ar << make_nvp("encodedKeySize", encodedSize); - ar << make_nvp("encodedKeyData", - serial::make_binary_object(cfg.getKeyData(), encodedSize)); - - // version 20080816 - int size = cfg.salt.size(); - ar << make_nvp("saltLen", size); - ar << make_nvp("saltData", - serial::make_binary_object(cfg.getSaltData(), size)); - ar << make_nvp("kdfIterations", cfg.kdfIterations); - ar << make_nvp("desiredKDFDuration", cfg.desiredKDFDuration); -} - -template -void load(Archive &ar, EncFSConfig &cfg, unsigned int version) -{ - rInfo("version = %i", version); - // TODO: figure out how to deprecate all but the first case.. - if (version == 20 || version >= 20100713) - { - rInfo("found new serialization format"); - ar >> make_nvp("version", cfg.subVersion); - } else if (version == 26800) - { - rInfo("found 20080816 version"); - cfg.subVersion = 20080816; - } else if (version == 26797) - { - rInfo("found 20080813"); - cfg.subVersion = 20080813; - } else if (version < (unsigned int)V5SubVersion) - { - rError("Invalid version %i - please fix config file", version); - } else - { - rInfo("Boost <= 1.41 compatibility mode"); - cfg.subVersion = version; - } - rInfo("subVersion = %i", cfg.subVersion); - - ar >> make_nvp("creator", cfg.creator); - ar >> make_nvp("cipherAlg", cfg.cipherIface); - ar >> make_nvp("nameAlg", cfg.nameIface); - ar >> make_nvp("keySize", cfg.keySize); - ar >> make_nvp("blockSize", cfg.blockSize); - ar >> make_nvp("uniqueIV", cfg.uniqueIV); - ar >> make_nvp("chainedNameIV", cfg.chainedNameIV); - ar >> make_nvp("externalIVChaining", cfg.externalIVChaining); - ar >> make_nvp("blockMACBytes", cfg.blockMACBytes); - ar >> make_nvp("blockMACRandBytes", cfg.blockMACRandBytes); - ar >> make_nvp("allowHoles", cfg.allowHoles); - - int encodedSize; - ar >> make_nvp("encodedKeySize", encodedSize); - rAssert(encodedSize == cfg.getCipher()->encodedKeySize()); - - unsigned char *key = new unsigned char[encodedSize]; - ar >> make_nvp("encodedKeyData", - serial::make_binary_object(key, encodedSize)); - cfg.assignKeyData(key, encodedSize); - delete[] key; - - if(cfg.subVersion >= 20080816) - { - int saltLen; - ar >> make_nvp("saltLen", saltLen); - unsigned char *salt = new unsigned char[saltLen]; - ar >> make_nvp("saltData", - serial::make_binary_object(salt, saltLen)); - cfg.assignSaltData(salt, saltLen); - delete[] salt; - - ar >> make_nvp("kdfIterations", cfg.kdfIterations); - ar >> make_nvp("desiredKDFDuration", cfg.desiredKDFDuration); - } else - { - cfg.salt.clear(); - cfg.kdfIterations = 16; - cfg.desiredKDFDuration = NormalKDFDuration; - } -} - -template -void serialize(Archive &ar, EncFSConfig &cfg, unsigned int version) -{ - split_free(ar, cfg, version); -} - -template -void serialize(Archive &ar, Interface &i, const unsigned int version) -{ - (void)version; - ar & make_nvp("name", i.name()); - ar & make_nvp("major", i.current()); - ar & make_nvp("minor", i.revision()); -} -} // namespace serialization -} // namespace boost + {Config_V5, ".encfs5", "ENCFS5_CONFIG", readV5Config }, + {Config_V3, ".encfs4", NULL, readV4Config }, + // prehistoric - no longer support + {Config_V3, ".encfs3", NULL, NULL }, + {Config_Prehistoric, ".encfs2", NULL, NULL }, + {Config_Prehistoric, ".encfs", NULL, NULL }, + {Config_None, NULL, NULL, NULL } }; EncFS_Root::EncFS_Root() { @@ -361,17 +225,14 @@ bool userAllowMkdir(int promptno, const char *path, mode_t mode ) } ConfigType readConfig_load( ConfigInfo *nm, const char *path, - const boost::shared_ptr &config ) + EncfsConfig &config ) { if( nm->loadFunc ) { try { if( (*nm->loadFunc)( path, config, nm )) - { - config->cfgType = nm->type; return nm->type; - } } catch( rlog::Error & err ) { err.log( _RLWarningChannel ); @@ -382,13 +243,11 @@ ConfigType readConfig_load( ConfigInfo *nm, const char *path, } else { // No load function - must be an unsupported type.. - config->cfgType = nm->type; - return nm->type; + return Config_None; } } -ConfigType readConfig( const string &rootDir, - const boost::shared_ptr &config ) +ConfigType readConfig( const string &rootDir, EncfsConfig &config ) { ConfigInfo *nm = ConfigFileMapping; while(nm->fileName) @@ -411,36 +270,110 @@ ConfigType readConfig( const string &rootDir, return Config_None; } +// Read a boost::serialization config file using an Xml reader.. bool readV6Config( const char *configFile, - const boost::shared_ptr &config, - ConfigInfo *info) + EncfsConfig &cfg, ConfigInfo *info) { (void)info; - fs::ifstream st( configFile ); - if(st.is_open()) + XmlReader rdr; + if (!rdr.load(configFile)) { - try - { - boost::archive::xml_iarchive ia( st ); - ia >> BOOST_SERIALIZATION_NVP( *config ); - - return true; - } catch(boost::archive::archive_exception &e) - { - rError("Archive exception: %s", e.what()); - return false; - } - } else - { - rInfo("Failed to load config file %s", configFile); + rError("Failed to load config file %s", configFile); return false; } + + XmlValuePtr serialization = rdr["boost_serialization"]; + XmlValuePtr config = (*serialization)["cfg"]; + int version = 0; + (*config)["@version"] >> version; + + // version numbering was complicated by boost::archive + if (version == 20 || version >= 20100713) + { + rInfo("found new serialization format"); + (*config)["version"] >> version; + cfg.set_revision(version); + } else if (version == 26800) + { + rInfo("found 20080816 version"); + cfg.set_revision(20080816); + } else if (version == 26797) + { + rInfo("found 20080813"); + cfg.set_revision(20080813); + } else if (version < V5SubVersion) + { + rError("Invalid version %i - please fix config file", version); + } else + { + rInfo("Boost <= 1.41 compatibility mode"); + cfg.set_revision(version); + } + rInfo("subVersion = %i", cfg.revision()); + + (*config)["creator"] >> (*cfg.mutable_creator()); + (*config)["cipherAlg"] >> (*cfg.mutable_cipher()); + (*config)["nameAlg"] >> (*cfg.mutable_naming()); + + //(*config)["keySize"] >> cfg.keySize; + int blockSize, blockMacBytes, blockMacRandBytes; + bool uniqueIv, chainedNameIv, externalIv, allowHoles; + + (*config)["blockSize"] >> blockSize; + (*config)["uniqueIV"] >> uniqueIv; + (*config)["chainedNameIV"] >> chainedNameIv; + (*config)["externalIVChaining"] >> externalIv; + (*config)["blockMACBytes"] >> blockMacBytes; + (*config)["blockMACRandBytes"] >> blockMacRandBytes; + (*config)["allowHoles"] >> allowHoles; + + cfg.set_block_size(blockSize); + cfg.set_unique_iv(uniqueIv); + cfg.set_chained_iv(chainedNameIv); + cfg.set_external_iv(externalIv); + cfg.set_block_mac_bytes(blockMacBytes); + cfg.set_block_mac_rand_bytes(blockMacRandBytes); + cfg.set_allow_holes(allowHoles); + + int encodedSize; + (*config)["encodedKeySize"] >> encodedSize; + unsigned char *key = new unsigned char[encodedSize]; + (*config)["encodedKeyData"]->readB64Data(key, encodedSize); + cfg.set_key(key, encodedSize); + delete[] key; + + int keySize; + (*config)["keySize"] >> keySize; + cfg.set_key_size(keySize); + + if(cfg.revision() >= 20080816) + { + int saltLen; + (*config)["saltLen"] >> saltLen; + unsigned char *salt = new unsigned char[saltLen]; + (*config)["saltData"]->readB64Data(salt, saltLen); + cfg.set_salt(salt, saltLen); + delete[] salt; + + int kdfIterations, desiredKDFDuration; + (*config)["kdfIterations"] >> kdfIterations; + (*config)["desiredKDFDuration"] >> desiredKDFDuration; + cfg.set_kdf_iterations(kdfIterations); + cfg.set_kdf_duration(desiredKDFDuration); + } else + { + cfg.clear_salt(); + cfg.set_kdf_iterations(16); + cfg.set_kdf_duration(NormalKDFDuration); + } + + return true; } +// Read a v5 archive, which is a proprietary binary format. bool readV5Config( const char *configFile, - const boost::shared_ptr &config, - ConfigInfo *info) + EncfsConfig &config, ConfigInfo *) { bool ok = false; @@ -450,39 +383,41 @@ bool readV5Config( const char *configFile, { try { - config->subVersion = cfgRdr["subVersion"].readInt( - info->defaultSubVersion ); - if(config->subVersion > info->currentSubVersion) + config.set_revision(cfgRdr["subVersion"].readInt(0)); + if(config.revision() > V5SubVersion) { /* config file specifies a version outside our supported range.. */ rWarning(_("Config subversion %i found, but this version of" " encfs only supports up to version %i."), - config->subVersion, info->currentSubVersion); + config.revision(), V5SubVersion); return false; } - if( config->subVersion < 20040813 ) + if( config.revision() < 20040813 ) { rError(_("This version of EncFS doesn't support " "filesystems created before 2004-08-13")); return false; } - cfgRdr["creator"] >> config->creator; - cfgRdr["cipher"] >> config->cipherIface; - cfgRdr["naming"] >> config->nameIface; - cfgRdr["keySize"] >> config->keySize; - cfgRdr["blockSize"] >> config->blockSize; + cfgRdr["creator"] >> (*config.mutable_creator()); + cfgRdr["cipher"] >> (*config.mutable_cipher()); + cfgRdr["naming"] >> (*config.mutable_naming()); - string data; - cfgRdr["keyData"] >> data; - config->assignKeyData(data); - config->uniqueIV = cfgRdr["uniqueIV"].readBool( false ); - config->chainedNameIV = cfgRdr["chainedIV"].readBool( false ); - config->externalIVChaining = cfgRdr["externalIV"].readBool( false ); - config->blockMACBytes = cfgRdr["blockMACBytes"].readInt(0); - config->blockMACRandBytes = - cfgRdr["blockMACRandBytes"].readInt(0); + int blockSize; + cfgRdr["blockSize"] >> blockSize; + config.set_block_size(blockSize); + + int keySize; + cfgRdr["keySize"] >> keySize; + config.set_key_size(keySize); + cfgRdr["keyData"] >> (*config.mutable_key()); + + config.set_unique_iv( cfgRdr["uniqueIV"].readBool( false ) ); + config.set_chained_iv( cfgRdr["chainedIV"].readBool( false ) ); + config.set_external_iv( cfgRdr["externalIV"].readBool( false ) ); + config.set_block_mac_bytes( cfgRdr["blockMACBytes"].readInt(0) ); + config.set_block_mac_rand_bytes( cfgRdr["blockMACRandBytes"].readInt(0) ); ok = true; } catch( rlog::Error &err) @@ -497,8 +432,7 @@ bool readV5Config( const char *configFile, } bool readV4Config( const char *configFile, - const boost::shared_ptr &config, - ConfigInfo *info) + EncfsConfig &config, ConfigInfo *) { bool ok = false; @@ -508,22 +442,16 @@ bool readV4Config( const char *configFile, { try { - cfgRdr["cipher"] >> config->cipherIface; - cfgRdr["keySize"] >> config->keySize; - cfgRdr["blockSize"] >> config->blockSize; - string data; - cfgRdr["keyData"] >> data; - config->assignKeyData(data); + cfgRdr["cipher"] >> (*config.mutable_cipher()); + int blockSize; + cfgRdr["blockSize"] >> blockSize; + config.set_block_size(blockSize); + + cfgRdr["keyData"] >> (*config.mutable_key()); // fill in default for V4 - config->nameIface = Interface("nameio/stream", 1, 0, 0); - config->creator = "EncFS 1.0.x"; - config->subVersion = info->defaultSubVersion; - config->blockMACBytes = 0; - config->blockMACRandBytes = 0; - config->uniqueIV = false; - config->externalIVChaining = false; - config->chainedNameIV = false; + config.mutable_naming()->MergeFrom( makeInterface("nameio/stream", 1, 0, 0) ); + config.set_creator( "EncFS 1.0.x" ); ok = true; } catch( rlog::Error &err) @@ -537,106 +465,66 @@ bool readV4Config( const char *configFile, return ok; } -bool saveConfig( ConfigType type, const string &rootDir, - const boost::shared_ptr &config ) +bool writeTextConfig( const char *fileName, const EncfsConfig &cfg ) +{ + int fd = ::open( fileName, O_RDWR | O_CREAT, 0640 ); + if (fd < 0) + { + rError("Unable to open or create file %s", fileName); + return false; + } + + google::protobuf::io::FileOutputStream fos( fd ); + google::protobuf::TextFormat::Print( cfg, &fos ); + + fos.Close(); + return true; +} + +bool saveConfig( const string &rootDir, const EncfsConfig &config ) { bool ok = false; ConfigInfo *nm = ConfigFileMapping; - while(nm->fileName) + + // TODO(vgough): remove old config after saving a new one? + string path = rootDir + ConfigFileName; + if( nm->environmentOverride != NULL ) { - if( nm->type == type && nm->saveFunc ) - { - string path = rootDir + nm->fileName; - if( nm->environmentOverride != NULL ) - { - // use environment file if specified.. - const char *envFile = getenv( nm->environmentOverride ); - if( envFile != NULL ) - path.assign( envFile ); - } + // use environment file if specified.. + const char *envFile = getenv( nm->environmentOverride ); + if( envFile != NULL ) + path.assign( envFile ); + } - try - { - ok = (*nm->saveFunc)( path.c_str(), config ); - } catch( rlog::Error &err ) - { - err.log( _RLWarningChannel ); - ok = false; - } - break; - } - ++nm; + try + { + ok = writeTextConfig( path.c_str(), config ); + } catch( rlog::Error &err ) + { + err.log( _RLWarningChannel ); + ok = false; } return ok; } -bool writeV6Config( const char *configFile, - const boost::shared_ptr &config ) +bool readProtoConfig( const char *fileName, EncfsConfig &config, + struct ConfigInfo *) { - fs::ofstream st( configFile ); - if(!st.is_open()) + int fd = ::open( fileName, O_RDONLY, 0640 ); + if (fd < 0) + { + rError("Unable to open file %s", fileName); return false; + } + + google::protobuf::io::FileInputStream fis( fd ); + google::protobuf::TextFormat::Parse( &fis, &config ); - st << *config; return true; } -std::ostream &operator << (std::ostream &st, const EncFSConfig &cfg) -{ - boost::archive::xml_oarchive oa(st); - oa << BOOST_SERIALIZATION_NVP( cfg ); - - return st; -} - -std::istream &operator >> (std::istream &st, EncFSConfig &cfg) -{ - boost::archive::xml_iarchive ia(st); - ia >> BOOST_SERIALIZATION_NVP( cfg ); - - return st; -} - -bool writeV5Config( const char *configFile, - const boost::shared_ptr &config ) -{ - ConfigReader cfg; - - cfg["creator"] << config->creator; - cfg["subVersion"] << config->subVersion; - cfg["cipher"] << config->cipherIface; - cfg["naming"] << config->nameIface; - cfg["keySize"] << config->keySize; - cfg["blockSize"] << config->blockSize; - string key; - key.assign((char *)config->getKeyData(), config->keyData.size()); - cfg["keyData"] << key; - cfg["blockMACBytes"] << config->blockMACBytes; - cfg["blockMACRandBytes"] << config->blockMACRandBytes; - cfg["uniqueIV"] << config->uniqueIV; - cfg["chainedIV"] << config->chainedNameIV; - cfg["externalIV"] << config->externalIVChaining; - - return cfg.save( configFile ); -} - -bool writeV4Config( const char *configFile, - const boost::shared_ptr &config ) -{ - ConfigReader cfg; - - cfg["cipher"] << config->cipherIface; - cfg["keySize"] << config->keySize; - cfg["blockSize"] << config->blockSize; - string key; - key.assign((char *)config->getKeyData(), config->keyData.size()); - cfg["keyData"] << key; - - return cfg.save( configFile ); -} - static Cipher::CipherAlgorithm findCipherAlgorithm(const char *name, int keySize ) @@ -986,7 +874,7 @@ bool selectZeroBlockPassThrough() "This avoids writing encrypted blocks when file holes are created.")); } -RootPtr createV6Config( EncFS_Context *ctx, +RootPtr createConfig( EncFS_Context *ctx, const shared_ptr &opts ) { const std::string rootDir = opts->rootDir; @@ -1147,25 +1035,24 @@ RootPtr createV6Config( EncFS_Context *ctx, alg.name.c_str(), keySize, blockSize); } - shared_ptr config( new EncFSConfig ); + EncfsConfig config; - config->cfgType = Config_V6; - config->cipherIface = cipher->interface(); - config->keySize = keySize; - config->blockSize = blockSize; - config->nameIface = nameIOIface; - config->creator = "EncFS " VERSION; - config->subVersion = V6SubVersion; - config->blockMACBytes = blockMACBytes; - config->blockMACRandBytes = blockMACRandBytes; - config->uniqueIV = uniqueIV; - config->chainedNameIV = chainedIV; - config->externalIVChaining = externalIV; - config->allowHoles = allowHoles; + config.mutable_cipher()->MergeFrom( cipher->interface() ); + //config.keySize = keySize; + config.set_block_size( blockSize ); + config.mutable_naming()->MergeFrom( nameIOIface ); + config.set_creator( "EncFS " VERSION ); + config.set_revision( V6SubVersion ); + config.set_block_mac_bytes( blockMACBytes ); + config.set_block_mac_rand_bytes( blockMACRandBytes ); + config.set_unique_iv( uniqueIV ); + config.set_chained_iv( chainedIV ); + config.set_external_iv( externalIV ); + config.set_allow_holes( allowHoles ); - config->salt.clear(); - config->kdfIterations = 0; // filled in by keying function - config->desiredKDFDuration = desiredKDFDuration; + config.clear_salt(); + config.clear_kdf_iterations(); // filled in by keying function + config.set_kdf_duration( desiredKDFDuration ); cout << "\n"; // xgroup(setup) @@ -1173,7 +1060,7 @@ RootPtr createV6Config( EncFS_Context *ctx, "the following properties:") << endl; showFSInfo( config ); - if( config->externalIVChaining ) + if( config.external_iv() ) { cout << _("-------------------------- WARNING --------------------------\n") @@ -1206,17 +1093,13 @@ RootPtr createV6Config( EncFS_Context *ctx, { if (annotate) cerr << "$PROMPT$ new_passwd" << endl; - userKey = config->getUserKey( useStdin ); } - else if(!passwordProgram.empty()) - userKey = config->getUserKey( passwordProgram, rootDir ); - else - userKey = config->getNewUserKey(); + userKey = getNewUserKey( config, useStdin, passwordProgram, rootDir ); cipher->writeKey( volumeKey, encodedKey, userKey ); userKey.reset(); - config->assignKeyData(encodedKey, encodedKeySize); + config.set_key(encodedKey, encodedKeySize); delete[] encodedKey; if(!volumeKey) @@ -1226,11 +1109,11 @@ RootPtr createV6Config( EncFS_Context *ctx, return rootInfo; } - if(!saveConfig( Config_V6, rootDir, config )) + if(!saveConfig( rootDir, config )) return rootInfo; // fill in config struct - shared_ptr nameCoder = NameIO::New( config->nameIface, + shared_ptr nameCoder = NameIO::New( config.naming(), cipher, volumeKey ); if(!nameCoder) { @@ -1240,14 +1123,14 @@ RootPtr createV6Config( EncFS_Context *ctx, return rootInfo; } - nameCoder->setChainedNameIV( config->chainedNameIV ); + nameCoder->setChainedNameIV( config.chained_iv() ); nameCoder->setReverseEncryption( reverseEncryption ); FSConfigPtr fsConfig (new FSConfig); fsConfig->cipher = cipher; fsConfig->key = volumeKey; fsConfig->nameCoding = nameCoder; - fsConfig->config = config; + fsConfig->config = boost::shared_ptr(new EncfsConfig(config)); fsConfig->forceDecode = forceDecode; fsConfig->reverseEncryption = reverseEncryption; fsConfig->idleTracking = enableIdleTracking; @@ -1262,27 +1145,27 @@ RootPtr createV6Config( EncFS_Context *ctx, return rootInfo; } -void showFSInfo( const boost::shared_ptr &config ) +void showFSInfo( const EncfsConfig &config ) { - shared_ptr cipher = Cipher::New( config->cipherIface, -1 ); + shared_ptr cipher = Cipher::New( config.cipher(), -1 ); { cout << autosprintf( // xgroup(diag) _("Filesystem cipher: \"%s\", version %i:%i:%i"), - config->cipherIface.name().c_str(), config->cipherIface.current(), - config->cipherIface.revision(), config->cipherIface.age()); + config.cipher().name().c_str(), config.cipher().major(), + config.cipher().minor(), config.cipher().age()); // check if we support this interface.. if(!cipher) cout << _(" (NOT supported)\n"); else { // if we're using a newer interface, show the version number - if( config->cipherIface != cipher->interface() ) + if( config.cipher() != cipher->interface() ) { Interface iface = cipher->interface(); // xgroup(diag) cout << autosprintf(_(" (using %i:%i:%i)\n"), - iface.current(), iface.revision(), iface.age()); + iface.major(), iface.minor(), iface.age()); } else cout << "\n"; } @@ -1290,11 +1173,11 @@ void showFSInfo( const boost::shared_ptr &config ) { // xgroup(diag) cout << autosprintf(_("Filename encoding: \"%s\", version %i:%i:%i"), - config->nameIface.name().c_str(), config->nameIface.current(), - config->nameIface.revision(), config->nameIface.age()); + config.naming().name().c_str(), config.naming().major(), + config.naming().minor(), config.naming().age()); // check if we support the filename encoding interface.. - shared_ptr nameCoder = NameIO::New( config->nameIface, + shared_ptr nameCoder = NameIO::New( config.naming(), cipher, CipherKey() ); if(!nameCoder) { @@ -1303,18 +1186,18 @@ void showFSInfo( const boost::shared_ptr &config ) } else { // if we're using a newer interface, show the version number - if( config->nameIface != nameCoder->interface() ) + if( config.naming() != nameCoder->interface() ) { Interface iface = nameCoder->interface(); cout << autosprintf(_(" (using %i:%i:%i)\n"), - iface.current(), iface.revision(), iface.age()); + iface.major(), iface.minor(), iface.age()); } else cout << "\n"; } } { - cout << autosprintf(_("Key Size: %i bits"), config->keySize); - cipher = config->getCipher(); + cout << autosprintf(_("Key Size: %i bits"), config.key_size()); + cipher = getCipher(config); if(!cipher) { // xgroup(diag) @@ -1322,54 +1205,54 @@ void showFSInfo( const boost::shared_ptr &config ) } else cout << "\n"; } - if(config->kdfIterations > 0 && config->salt.size() > 0) + if(config.kdf_iterations() > 0 && config.salt().size() > 0) { cout << autosprintf(_("Using PBKDF2, with %i iterations"), - config->kdfIterations) << "\n"; + config.kdf_iterations()) << "\n"; cout << autosprintf(_("Salt Size: %i bits"), - 8*(int)config->salt.size()) << "\n"; + 8*(int)config.salt().size()) << "\n"; } - if(config->blockMACBytes || config->blockMACRandBytes) + if(config.block_mac_bytes() || config.block_mac_rand_bytes()) { - if(config->subVersion < 20040813) + if(config.revision() < 20040813) { cout << autosprintf( // xgroup(diag) _("Block Size: %i bytes + %i byte MAC header"), - config->blockSize, - config->blockMACBytes + config->blockMACRandBytes) << endl; + config.block_size(), + config.block_mac_bytes() + config.block_mac_rand_bytes()) << endl; } else { // new version stores the header as part of that block size.. cout << autosprintf( // xgroup(diag) _("Block Size: %i bytes, including %i byte MAC header"), - config->blockSize, - config->blockMACBytes + config->blockMACRandBytes) << endl; + config.block_size(), + config.block_mac_bytes() + config.block_mac_rand_bytes()) << endl; } } else { // xgroup(diag) - cout << autosprintf(_("Block Size: %i bytes"), config->blockSize); + cout << autosprintf(_("Block Size: %i bytes"), config.block_size()); cout << "\n"; } - if(config->uniqueIV) + if(config.unique_iv()) { // xgroup(diag) cout << _("Each file contains 8 byte header with unique IV data.\n"); } - if(config->chainedNameIV) + if(config.chained_iv()) { // xgroup(diag) cout << _("Filenames encoded using IV chaining mode.\n"); } - if(config->externalIVChaining) + if(config.external_iv()) { // xgroup(diag) cout << _("File data IV is chained to filename IV.\n"); } - if(config->allowHoles) + if(config.allow_holes()) { // xgroup(diag) cout << _("File holes passed through to ciphertext.\n"); @@ -1377,113 +1260,77 @@ void showFSInfo( const boost::shared_ptr &config ) cout << "\n"; } -shared_ptr EncFSConfig::getCipher() const +shared_ptr getCipher(const EncfsConfig &config) { - return Cipher::New( cipherIface, keySize ); + return getCipher(config.cipher(), config.key_size()); } -void EncFSConfig::assignKeyData(const std::string &in) +shared_ptr getCipher(const Interface &iface, int keySize) { - keyData.assign(in.data(), in.data()+in.length()); + return Cipher::New( iface, keySize ); } -void EncFSConfig::assignKeyData(unsigned char *data, int len) -{ - keyData.assign(data, data+len); -} - -void EncFSConfig::assignSaltData(unsigned char *data, int len) -{ - salt.assign(data, data+len); -} - -unsigned char *EncFSConfig::getKeyData() const -{ - return const_cast(&keyData.front()); -} - -unsigned char *EncFSConfig::getSaltData() const -{ - return const_cast(&salt.front()); -} - -CipherKey EncFSConfig::makeKey(const char *password, int passwdLen) +CipherKey makeNewKey(EncfsConfig &config, const char *password, int passwdLen) { CipherKey userKey; - shared_ptr cipher = getCipher(); + shared_ptr cipher = getCipher(config); - // if no salt is set and we're creating a new password for a new - // FS type, then initialize salt.. - if(salt.size() == 0 && kdfIterations == 0 && cfgType >= Config_V6) + unsigned char salt[20]; + if(!cipher->randomize( salt, sizeof(salt), true)) { - // upgrade to using salt - salt.resize(20); + cout << _("Error creating salt\n"); + return userKey; } + config.set_salt(salt, sizeof(salt)); - if(salt.size() > 0) + int iterations = config.kdf_iterations(); + userKey = cipher->newKey( password, passwdLen, + iterations, config.kdf_duration(), + salt, sizeof(salt)); + config.set_kdf_iterations(iterations); + + return userKey; +} + +CipherKey decryptKey(const EncfsConfig &config, const char *password, int passwdLen) +{ + CipherKey userKey; + shared_ptr cipher = getCipher(config.cipher(), config.key_size()); + + if(!config.salt().empty()) { - // if iterations isn't known, then we're creating a new key, so - // randomize the salt.. - if(kdfIterations == 0 && !cipher->randomize( - getSaltData(), salt.size(), true)) - { - cout << _("Error creating salt\n"); + int iterations = config.kdf_iterations(); + userKey = cipher->newKey( password, passwdLen, + iterations, config.kdf_duration(), + (const unsigned char *)config.salt().data(), config.salt().size()); + + if (iterations != config.kdf_iterations()) { + rError("Error in KDF, iteration mismatch"); return userKey; } - - userKey = cipher->newKey( password, passwdLen, - kdfIterations, desiredKDFDuration, - getSaltData(), salt.size()); } else { + // old KDF, no salt.. userKey = cipher->newKey( password, passwdLen ); } return userKey; } -CipherKey EncFSConfig::getUserKey(bool useStdin) -{ - char passBuf[MaxPassBuf]; - char *res; - - if( useStdin ) - { - res = fgets( passBuf, sizeof(passBuf), stdin ); - // Kill the trailing newline. - if(passBuf[ strlen(passBuf)-1 ] == '\n') - passBuf[ strlen(passBuf)-1 ] = '\0'; - } else - { - // xgroup(common) - res = readpassphrase( _("EncFS Password: "), - passBuf, sizeof(passBuf), RPP_ECHO_OFF ); - } - - CipherKey userKey; - if(!res) - cerr << _("Zero length password not allowed\n"); - else - userKey = makeKey(passBuf, strlen(passBuf)); - - memset( passBuf, 0, sizeof(passBuf) ); - - return userKey; -} - +// Doesn't use SecureMem, since we don't know how much will be read. +// Besides, password is being produced by another program. std::string readPassword( int FD ) { - char buffer[1024]; + SecureMem *buf = new SecureMem(1024); string result; while(1) { - ssize_t rdSize = recv(FD, buffer, sizeof(buffer), 0); + ssize_t rdSize = recv(FD, buf->data, buf->size, 0); if(rdSize > 0) { - result.append( buffer, rdSize ); - memset(buffer, 0, sizeof(buffer)); + result.append( buf->data, rdSize ); } else break; } @@ -1494,22 +1341,22 @@ std::string readPassword( int FD ) if(!result.empty() && result[ result.length()-1 ] == '\n' ) result.resize( result.length() -1 ); + delete buf; return result; } -CipherKey EncFSConfig::getUserKey( const std::string &passProg, - const std::string &rootDir ) +SecureMem *passwordFromProgram(const std::string &passProg, + const std::string &rootDir) { // have a child process run the command and get the result back to us. int fds[2], pid; int res; - CipherKey result; res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); if(res == -1) { perror(_("Internal error: socketpair() failed")); - return result; + return NULL; } rDebug("getUserKey: fds = %i, %i", fds[0], fds[1]); @@ -1519,7 +1366,7 @@ CipherKey EncFSConfig::getUserKey( const std::string &passProg, perror(_("Internal error: fork() failed")); close(fds[0]); close(fds[1]); - return result; + return NULL; } if(pid == 0) @@ -1568,58 +1415,143 @@ CipherKey EncFSConfig::getUserKey( const std::string &passProg, waitpid(pid, NULL, 0); - // convert to key.. - result = makeKey(password.c_str(), password.length()); - - // clear buffer.. - password.assign( password.length(), '\0' ); + SecureMem *result = new SecureMem(password.length()+1); + if (result) + strncpy(result->data, password.c_str(), result->size); + password.assign(password.length(), '\0'); return result; } -CipherKey EncFSConfig::getNewUserKey() +SecureMem *passwordFromStdin() { - CipherKey userKey; - char passBuf[MaxPassBuf]; - char passBuf2[MaxPassBuf]; + SecureMem *buf = new SecureMem(MaxPassBuf); + + char *res = fgets( buf->data, buf->size, stdin ); + if (res) + { + // Kill the trailing newline. + int last = strnlen(buf->data, buf->size); + if (last > 0 && buf->data[last-1] == '\n') + buf->data[ last-1 ] = '\0'; + } + + return buf; +} + +SecureMem *passwordFromPrompt() +{ + SecureMem *buf = new SecureMem(MaxPassBuf); + + // xgroup(common) + char *res = readpassphrase( _("EncFS Password: "), + buf->data, buf->size-1, RPP_ECHO_OFF ); + if (!res) + { + delete buf; + buf = NULL; + } + + return buf; +} + +SecureMem *passwordFromPrompts() +{ + SecureMem *buf = new SecureMem(MaxPassBuf); + SecureMem *buf2 = new SecureMem(MaxPassBuf); do { // xgroup(common) - char *res1 = readpassphrase(_("New Encfs Password: "), passBuf, - sizeof(passBuf)-1, RPP_ECHO_OFF); + char *res1 = readpassphrase(_("New Encfs Password: "), + buf->data, buf->size-1, RPP_ECHO_OFF); // xgroup(common) - char *res2 = readpassphrase(_("Verify Encfs Password: "), passBuf2, - sizeof(passBuf2)-1, RPP_ECHO_OFF); + char *res2 = readpassphrase(_("Verify Encfs Password: "), + buf2->data, buf2->size-1, RPP_ECHO_OFF); - if(res1 && res2 && !strcmp(passBuf, passBuf2)) + if(res1 && res2 && !strncmp(buf->data, buf2->data, MaxPassBuf)) { - userKey = makeKey(passBuf, strlen(passBuf)); + break; } else { // xgroup(common) -- probably not common, but group with the others cerr << _("Passwords did not match, please try again\n"); } + } while(1); - memset( passBuf, 0, sizeof(passBuf) ); - memset( passBuf2, 0, sizeof(passBuf2) ); - } while( !userKey ); + delete buf2; + return buf; +} + +CipherKey getUserKey(const EncfsConfig &config, bool useStdin) +{ + CipherKey userKey; + SecureMem *password; + + if (useStdin) + password = passwordFromStdin(); + else + password = passwordFromPrompt(); + + if (password) + { + userKey = decryptKey(config, password->data, strlen(password->data)); + delete password; + } return userKey; } +CipherKey getUserKey( const EncfsConfig &config, const std::string &passProg, + const std::string &rootDir ) +{ + CipherKey result; + SecureMem *password = passwordFromProgram(passProg, rootDir); + + if (password) + { + result = decryptKey(config, password->data, strlen(password->data)); + delete password; + } + + return result; +} + +CipherKey getNewUserKey(EncfsConfig &config, + bool useStdin, const std::string &passProg, + const std::string &rootDir) +{ + CipherKey result; + SecureMem *password; + + if (useStdin) + password = passwordFromStdin(); + else if (!passProg.empty()) + password = passwordFromProgram(passProg, rootDir); + else + password = passwordFromPrompts(); + + if (password) + { + result = makeNewKey(config, password->data, strlen(password->data)); + delete password; + } + + return result; +} + RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) { RootPtr rootInfo; - boost::shared_ptr config(new EncFSConfig); + EncfsConfig config; if(readConfig( opts->rootDir, config ) != Config_None) { if(opts->reverseEncryption) { - if (config->blockMACBytes != 0 || config->blockMACRandBytes != 0 - || config->uniqueIV || config->externalIVChaining - || config->chainedNameIV ) + if (config.block_mac_bytes() != 0 || config.block_mac_rand_bytes() != 0 + || config.unique_iv() || config.external_iv() + || config.chained_iv() ) { cout << _("The configuration loaded is not compatible with --reverse\n"); return rootInfo; @@ -1627,14 +1559,14 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) } // first, instanciate the cipher. - shared_ptr cipher = config->getCipher(); + shared_ptr cipher = getCipher(config); if(!cipher) { rError(_("Unable to find cipher %s, version %i:%i:%i"), - config->cipherIface.name().c_str(), - config->cipherIface.current(), - config->cipherIface.revision(), - config->cipherIface.age()); + config.cipher().name().c_str(), + config.cipher().major(), + config.cipher().minor(), + config.cipher().age()); // xgroup(diag) cout << _("The requested cipher interface is not available\n"); return rootInfo; @@ -1648,9 +1580,9 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) rDebug( "useStdin: %i", opts->useStdin ); if (opts->annotate) cerr << "$PROMPT$ passwd" << endl; - userKey = config->getUserKey( opts->useStdin ); + userKey = getUserKey( config, opts->useStdin ); } else - userKey = config->getUserKey( opts->passwordProgram, opts->rootDir ); + userKey = getUserKey( config, opts->passwordProgram, opts->rootDir ); if(!userKey) return rootInfo; @@ -1658,7 +1590,7 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) rDebug("cipher key size = %i", cipher->encodedKeySize()); // decode volume key.. CipherKey volumeKey = cipher->readKey( - config->getKeyData(), userKey, opts->checkKey); + (const unsigned char *)config.key().data(), userKey, opts->checkKey); userKey.reset(); if(!volumeKey) @@ -1668,29 +1600,29 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) return rootInfo; } - shared_ptr nameCoder = NameIO::New( config->nameIface, + shared_ptr nameCoder = NameIO::New( config.naming(), cipher, volumeKey ); if(!nameCoder) { rError(_("Unable to find nameio interface %s, version %i:%i:%i"), - config->nameIface.name().c_str(), - config->nameIface.current(), - config->nameIface.revision(), - config->nameIface.age()); + config.naming().name().c_str(), + config.naming().major(), + config.naming().minor(), + config.naming().age()); // xgroup(diag) cout << _("The requested filename coding interface is " "not available\n"); return rootInfo; } - nameCoder->setChainedNameIV( config->chainedNameIV ); + nameCoder->setChainedNameIV( config.chained_iv() ); nameCoder->setReverseEncryption( opts->reverseEncryption ); FSConfigPtr fsConfig( new FSConfig ); fsConfig->cipher = cipher; fsConfig->key = volumeKey; fsConfig->nameCoding = nameCoder; - fsConfig->config = config; + fsConfig->config = boost::shared_ptr(new EncfsConfig(config)); fsConfig->forceDecode = opts->forceDecode; fsConfig->reverseEncryption = opts->reverseEncryption; fsConfig->opts = opts; @@ -1705,7 +1637,7 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) if(opts->createIfNotFound) { // creating a new encrypted filesystem - rootInfo = createV6Config( ctx, opts ); + rootInfo = createConfig( ctx, opts ); } } diff --git a/encfs/FileUtils.h b/encfs/FileUtils.h index febe328..c20fbab 100644 --- a/encfs/FileUtils.h +++ b/encfs/FileUtils.h @@ -99,41 +99,33 @@ struct EncFS_Opts /* Read existing config file. Looks for any supported configuration version. */ -ConfigType readConfig( const std::string &rootDir, - const boost::shared_ptr &config ); +ConfigType readConfig( const std::string &rootDir, EncfsConfig &config ); /* Save the configuration. Saves back as the same configuration type as was read from. */ -bool saveConfig( ConfigType type, const std::string &rootdir, - const boost::shared_ptr &config ); +bool saveConfig( const std::string &rootdir, const EncfsConfig &config ); class EncFS_Context; RootPtr initFS( EncFS_Context *ctx, const boost::shared_ptr &opts ); -RootPtr createV6Config( EncFS_Context *ctx, +RootPtr createConfig( EncFS_Context *ctx, const boost::shared_ptr &opts ); -void showFSInfo( const boost::shared_ptr &config ); +void showFSInfo( const EncfsConfig &config ); -bool readV4Config( const char *configFile, - const boost::shared_ptr &config, +bool readV4Config( const char *configFile, EncfsConfig &config, struct ConfigInfo *); -bool writeV4Config( const char *configFile, - const boost::shared_ptr &config); -bool readV5Config( const char *configFile, - const boost::shared_ptr &config, +bool readV5Config( const char *configFile, EncfsConfig &config, struct ConfigInfo *); -bool writeV5Config( const char *configFile, - const boost::shared_ptr &config); -bool readV6Config( const char *configFile, - const boost::shared_ptr &config, +bool readV6Config( const char *configFile, EncfsConfig &config, + struct ConfigInfo *); + +bool readProtoConfig( const char *configFile, EncfsConfig &config, struct ConfigInfo *); -bool writeV6Config( const char *configFile, - const boost::shared_ptr &config); #endif diff --git a/encfs/Interface.cpp b/encfs/Interface.cpp index 01ecb1c..ff32005 100644 --- a/encfs/Interface.cpp +++ b/encfs/Interface.cpp @@ -22,205 +22,69 @@ #include #include -using namespace rel; using namespace rlog; static RLogChannel * Info = DEF_CHANNEL( "info/iface", Log_Info ); -Interface::Interface(const char *name_, int Current, int Revision, int Age) - : _name( name_ ) - , _current( Current ) - , _revision( Revision ) - , _age( Age ) +bool implements(const Interface &A, const Interface &B) { + rLog(Info, "checking if %s(%i:%i:%i) implements %s(%i:%i:%i)", + A.name().c_str(), A.major(), A.minor(), A.age(), + B.name().c_str(), B.major(), B.minor(), B.age()); + + if( A.name() != B.name() ) + return false; + + int currentDiff = A.major() - B.major(); + return ( currentDiff >= 0 && currentDiff <= (int)A.age() ); } -Interface::Interface(const std::string &name_, int Current, - int Revision, int Age) - : _name( name_ ) - , _current( Current ) - , _revision( Revision ) - , _age( Age ) +Interface makeInterface(const char *name, int major, int minor, int age) { + Interface iface; + iface.set_name(name); + iface.set_major(major); + iface.set_minor(minor); + iface.set_age(age); + return iface; } -Interface::Interface(const Interface &src) - : _name( src._name ) - , _current( src._current ) - , _revision( src._revision ) - , _age( src._age ) +ConfigVar & operator << (ConfigVar &dst, const Interface &iface) { -} - -Interface::Interface() - : _current( 0 ) - , _revision( 0 ) - , _age( 0 ) -{ -} - -Interface &Interface::operator = (const Interface &src) -{ - _name = src._name; - _current = src._current; - _revision = src._revision; - _age = src._age; - return *this; -} - -const std::string & Interface::name() const -{ - return _name; -} - -std::string & Interface::name() -{ - return _name; -} - -int Interface::current() const -{ - return _current; -} - -int &Interface::current() -{ - return _current; -} - -int Interface::revision() const -{ - return _revision; -} - -int &Interface::revision() -{ - return _revision; -} - -int Interface::age() const -{ - return _age; -} - -int &Interface::age() -{ - return _age; -} - -bool operator == (const Interface &A, const Interface &B) -{ - return ( A.name() == B.name() - && A.current() == B.current() - && A.revision() == B.revision() - && A.age() == B.age() ); -} - -bool operator != (const Interface &A, const Interface &B) -{ - return ( A.name() != B.name() - || A.current() != B.current() - || A.revision() != B.revision() - || A.age() != B.age() ); -} - -// zero branch method of getting comparison sign.. -// tricky.. makes assumptions -#if 0 -static int sign( int a, int b ) -{ - unsigned int ab = ((unsigned int)(a - b)) >> 31; - unsigned int ba = ((unsigned int)(b - a)) >> 31; - - return 1 + ba - ab; -} -#else -// simple, easy to check, unlikely to break due to unforseen events.. -static int sign( int a, int b ) -{ - if(a < b) - return 0; - else if(a == b) - return 1; - else - return 2; -} -#endif - -static int diffSum( const Interface &A, const Interface &B ) -{ - int cS = sign( A.current() , B.current() ); - int aS = sign( A.age(), B.age() ); - int rS = sign( A.revision(), B.revision() ); - - return (cS * 3 + aS) * 3 + rS; -} - -const int EqualVersion = (1 * 3 + 1) * 3 + 1; - -bool Interface::implements(const Interface &B) const -{ - rLog(Info, "checking if %s(%i:%i:%i) implements %s(%i:%i:%i)", - name().c_str(), current(), revision(), age(), - B.name().c_str(), B.current(), B.revision(), B.age()); - - if( name() != B.name() ) - return false; - - int currentDiff = current() - B.current(); - return ( currentDiff >= 0 && currentDiff <= age() ); -} - - -bool operator < (const Interface &A, const Interface &B) -{ - if( A.name() == B.name() ) - { - return ( diffSum(A,B) < EqualVersion ); - } else - return A.name() < B.name(); -} - -bool operator > (const Interface &A, const Interface &B) -{ - if( A.name() == B.name() ) - { - return ( diffSum(A,B) > EqualVersion ); - } else - return A.name() < B.name(); -} - -bool operator <= (const Interface &A, const Interface &B) -{ - if( A.name() == B.name() ) - { - return ( diffSum(A,B) <= EqualVersion ); - } else - return A.name() < B.name(); -} - -bool operator >= (const Interface &A, const Interface &B) -{ - if( A.name() == B.name() ) - { - return ( diffSum(A,B) >= EqualVersion ); - } else - return A.name() < B.name(); -} - - -ConfigVar & operator << (ConfigVar &dst, const rel::Interface &iface) -{ - dst << iface.name() << iface.current() << iface.revision() << iface.age(); - return dst; + dst << iface.name() << (int)iface.major() << (int)iface.minor() << (int)iface.age(); + return dst; } const ConfigVar & operator >> (const ConfigVar &src, Interface &iface) { - src >> iface.name(); - src >> iface.current(); - src >> iface.revision(); - src >> iface.age(); + src >> *iface.mutable_name(); + int major, minor, age; + src >> major >> minor >> age; + iface.set_major(major); + iface.set_minor(minor); + iface.set_age(age); + return src; +} + +const XmlValuePtr & operator >> (const XmlValuePtr &src, Interface &iface) +{ + (*src)["name"] >> *iface.mutable_name(); + int major, minor; + (*src)["major"] >> major; + (*src)["minor"] >> minor; + iface.set_major(major); + iface.set_minor(minor); return src; } +bool operator != (const Interface &a, const Interface &b) +{ + if (a.major() != b.major()) + return true; + + if (a.minor() != b.minor()) + return true; + + return false; +} + diff --git a/encfs/Interface.h b/encfs/Interface.h index b74e3f7..6ddca40 100644 --- a/encfs/Interface.h +++ b/encfs/Interface.h @@ -19,66 +19,23 @@ #define _Interface_incl_ #include +#include "XmlReader.h" +#include "config.pb.h" +// check if A implements the interface described by B. +// Note that implements(A, B) is not the same as implements(B, A) +// This checks the current() version and age() against B.current() for +// compatibility. Even if A.implements(B) is true, B > A may also be +// true, meaning B is a newer revision of the interface then A. +bool implements( const Interface &a, const Interface &b ); +Interface makeInterface( const char *name, int major, int minor, int age ); + +// Reae operation class ConfigVar; +const ConfigVar & operator >> (const ConfigVar &, Interface &); +const XmlValuePtr & operator >> (const XmlValuePtr &, Interface &); -// part of REL library.. -namespace rel -{ - - class Interface - { - public: - - /*! - Version numbers as described by libtool: info://libtool/versioning - Current - the most recent interface api that is implemented. - Revision - the implementation number of the current interface. - Age - the difference between the newest and oldest interfaces that - are implemented. - */ - Interface( const char *name, int Current, int Revision, int Age ); - Interface( const std::string &name, int Current, int Revision, int Age); - Interface(const Interface &src); - Interface(); - - // check if we implement the interface described by B. - // Note that A.implements(B) is not the same as B.implements(A) - // This checks the current() version and age() against B.current() for - // compatibility. Even if A.implements(B) is true, B > A may also be - // true, meaning B is a newer revision of the interface then A. - bool implements( const Interface &dst ) const; - - const std::string &name() const; - int current() const; - int revision() const; - int age() const; - - std::string &name(); - int ¤t(); - int &revision(); - int &age(); - - Interface &operator = ( const Interface &src ); - - private: - std::string _name; - int _current; - int _revision; - int _age; - }; - -} - -ConfigVar & operator << (ConfigVar &, const rel::Interface &); -const ConfigVar & operator >> (const ConfigVar &, rel::Interface &); - -bool operator < (const rel::Interface &A, const rel::Interface &B); -bool operator > (const rel::Interface &A, const rel::Interface &B); -bool operator <= (const rel::Interface &A, const rel::Interface &B); -bool operator >= (const rel::Interface &A, const rel::Interface &B); -bool operator == (const rel::Interface &A, const rel::Interface &B); -bool operator != (const rel::Interface &A, const rel::Interface &B); +bool operator != (const Interface &a, const Interface &b); #endif diff --git a/encfs/MACFileIO.cpp b/encfs/MACFileIO.cpp index 816e64b..ac69ccc 100644 --- a/encfs/MACFileIO.cpp +++ b/encfs/MACFileIO.cpp @@ -19,6 +19,7 @@ #include "MemoryPool.h" #include "FileUtils.h" +#include "config.pb.h" #include #include @@ -29,7 +30,6 @@ #include "i18n.h" using namespace rlog; -using namespace rel; using namespace std; using boost::shared_ptr; using boost::dynamic_pointer_cast; @@ -48,13 +48,13 @@ static RLogChannel *Info = DEF_CHANNEL("info/MACFileIO", Log_Info); // compatible, except at a high level by checking a revision number for the // filesystem... // -static rel::Interface MACFileIO_iface("FileIO/MAC", 2, 1, 0); +static Interface MACFileIO_iface = makeInterface("FileIO/MAC", 2, 1, 0); int dataBlockSize(const FSConfigPtr &cfg) { - return cfg->config->blockSize - - cfg->config->blockMACBytes - - cfg->config->blockMACRandBytes; + return cfg->config->block_size() + - cfg->config->block_mac_bytes() + - cfg->config->block_mac_rand_bytes(); } MACFileIO::MACFileIO( const shared_ptr &_base, @@ -63,23 +63,23 @@ MACFileIO::MACFileIO( const shared_ptr &_base, , base( _base ) , cipher( cfg->cipher ) , key( cfg->key ) - , macBytes( cfg->config->blockMACBytes ) - , randBytes( cfg->config->blockMACRandBytes ) + , macBytes( cfg->config->block_mac_bytes() ) + , randBytes( cfg->config->block_mac_rand_bytes() ) , warnOnly( cfg->opts->forceDecode ) { rAssert( macBytes >= 0 && macBytes <= 8 ); rAssert( randBytes >= 0 ); rLog(Info, "fs block size = %i, macBytes = %i, randBytes = %i", - cfg->config->blockSize, - cfg->config->blockMACBytes, - cfg->config->blockMACRandBytes); + cfg->config->block_size(), + cfg->config->block_mac_bytes(), + cfg->config->block_mac_rand_bytes()); } MACFileIO::~MACFileIO() { } -rel::Interface MACFileIO::interface() const +Interface MACFileIO::interface() const { return MACFileIO_iface; } diff --git a/encfs/MACFileIO.h b/encfs/MACFileIO.h index 46573a6..4b6aac5 100644 --- a/encfs/MACFileIO.h +++ b/encfs/MACFileIO.h @@ -36,7 +36,7 @@ public: MACFileIO(); virtual ~MACFileIO(); - virtual rel::Interface interface() const; + virtual Interface interface() const; virtual void setFileName( const char *fileName ); virtual const char *getFileName() const; diff --git a/encfs/Makefile.am b/encfs/Makefile.am index ce6665d..ba7c6c8 100644 --- a/encfs/Makefile.am +++ b/encfs/Makefile.am @@ -2,8 +2,10 @@ include $(top_srcdir)/Makefile.common ALL_INCLUDES = @RLOG_CFLAGS@ @OPENSSL_CFLAGS@ @BOOST_CPPFLAGS@ +ALL_INCLUDES += @PROTOBUF_CFLAGS@ ALL_LDFLAGS = @RLOG_LIBS@ @OPENSSL_LIBS@ @BOOST_LDFLAGS@ -ALL_LDFLAGS += @BOOST_SERIALIZATION_LIB@ @BOOST_FILESYSTEM_LIB@ @BOOST_SYSTEM_LIB@ +ALL_LDFLAGS += @BOOST_FILESYSTEM_LIB@ @BOOST_SYSTEM_LIB@ +ALL_LDFLAGS += @PROTOBUF_LIBS@ INCLUDES = $(all_includes) -I../intl @@ -47,10 +49,10 @@ endif # : : 0 => no new interfaces, but breaks old apps # : +1 : => internal changes, nothing breaks # -libencfs_la_LDFLAGS = -version-info 6:2:0 +libencfs_la_LDFLAGS = -version-info 7:0:0 libencfs_la_LIBADD = @RLOG_LIBS@ \ @OPENSSL_LIBS@ \ - @BOOST_SERIALIZATION_LIB@ @BOOST_FILESYSTEM_LIB@ @BOOST_SYSTEM_LIB@ + @BOOST_FILESYSTEM_LIB@ @BOOST_SYSTEM_LIB@ EXTRASRC = ../intl/autosprintf.cpp if BUILD_OPENSSL @@ -62,6 +64,7 @@ endif libencfs_la_SOURCES = \ readpassphrase.cpp \ base64.cpp \ + config.pb.cc \ ConfigReader.cpp \ ConfigVar.cpp \ Context.cpp \ @@ -83,6 +86,7 @@ libencfs_la_SOURCES = \ FileNode.cpp \ FileUtils.cpp \ openssl.cpp \ + XmlReader.cpp \ ${EXTRASRC} @@ -109,6 +113,7 @@ noinst_HEADERS = \ CipherKey.h \ ConfigReader.h \ ConfigVar.h \ + config.pb.h \ Context.h \ DirNode.h \ encfs.h \ @@ -134,8 +139,14 @@ noinst_HEADERS = \ man_MANS=encfs.1 encfsctl.1 EXTRA_DIST = encfs.pod encfsctl.pod encfs.1 encfsctl.1 encfs-man.html +SUFFIXES = .1 .pod .proto + +config.pb.cc: config.pb.h + +config.pb.h: config.proto + @PROTOC@ --cpp_out=. config.proto + if BUILD_MAN -SUFFIXES = .1 .pod # since we have POD2MAN, we can specify how to rebuild encfs.1 if necessary .pod.1: @POD2MAN@ --section=1 --release=@VERSION@ --center="Encrypted Filesystem" $< $@ diff --git a/encfs/MemoryPool.cpp b/encfs/MemoryPool.cpp index 1fe79be..d78c946 100644 --- a/encfs/MemoryPool.cpp +++ b/encfs/MemoryPool.cpp @@ -25,6 +25,8 @@ #include "config.h" #include +#include + #ifdef HAVE_VALGRIND_MEMCHECK_H #include #else @@ -34,6 +36,7 @@ using namespace rlog; +# include # include #define BLOCKDATA( BLOCK ) (unsigned char*)BLOCK->data->data @@ -140,4 +143,34 @@ void MemoryPool::destroyAll() } } +SecureMem::SecureMem(int len) +{ + data = (char *)OPENSSL_malloc(len); + if (data) + { + size = len; + mlock(data, size); + memset(data, '\0', size); + VALGRIND_MAKE_MEM_UNDEFINED( data, size ); + } else + { + size = 0; + } +} + +SecureMem::~SecureMem() +{ + if (size) + { + memset(data, '\0', size); + munlock(data, size); + + OPENSSL_free(data); + VALGRIND_MAKE_MEM_NOACCESS( data, size ); + + data = NULL; + size = 0; + } +} + diff --git a/encfs/MemoryPool.h b/encfs/MemoryPool.h index b1edcda..62349bd 100644 --- a/encfs/MemoryPool.h +++ b/encfs/MemoryPool.h @@ -50,5 +50,14 @@ namespace MemoryPool void destroyAll(); } +struct SecureMem +{ + int size; + char *data; + + SecureMem(int len); + ~SecureMem(); +}; + #endif diff --git a/encfs/NameIO.cpp b/encfs/NameIO.cpp index a13694f..3e2b81e 100644 --- a/encfs/NameIO.cpp +++ b/encfs/NameIO.cpp @@ -32,7 +32,6 @@ #include "NullNameIO.h" using namespace std; -using namespace rel; using namespace rlog; #define REF_MODULE(TYPE) \ @@ -130,7 +129,7 @@ shared_ptr NameIO::New( const Interface &iface, NameIOMap_t::const_iterator end = gNameIOMap->end(); for(it = gNameIOMap->begin(); it != end; ++it) { - if( it->second.iface.implements( iface )) + if( implements(it->second.iface, iface )) { Constructor fn = it->second.constructor; result = (*fn)( iface, cipher, key ); diff --git a/encfs/NameIO.h b/encfs/NameIO.h index 0017bd7..93f48a1 100644 --- a/encfs/NameIO.h +++ b/encfs/NameIO.h @@ -32,33 +32,33 @@ class Cipher; class NameIO { public: - typedef shared_ptr (*Constructor)( const rel::Interface &iface, + typedef shared_ptr (*Constructor)( const Interface &iface, const shared_ptr &cipher, const CipherKey &key); struct Algorithm { std::string name; std::string description; - rel::Interface iface; + Interface iface; }; typedef std::list AlgorithmList; static AlgorithmList GetAlgorithmList( bool includeHidden = false ); - static shared_ptr New( const rel::Interface &iface, + static shared_ptr New( const Interface &iface, const shared_ptr &cipher, const CipherKey &key); static shared_ptr New( const std::string &name, const shared_ptr &cipher, const CipherKey &key); static bool Register( const char *name, const char *description, - const rel::Interface &iface, Constructor constructor, + const Interface &iface, Constructor constructor, bool hidden = false); NameIO(); virtual ~NameIO(); - virtual rel::Interface interface() const =0; + virtual Interface interface() const =0; void setChainedNameIV( bool enable ); bool getChainedNameIV() const; diff --git a/encfs/NullCipher.cpp b/encfs/NullCipher.cpp index fa6ca72..f70e077 100644 --- a/encfs/NullCipher.cpp +++ b/encfs/NullCipher.cpp @@ -26,13 +26,12 @@ #include using namespace std; -using namespace rel; using namespace rlog; using boost::shared_ptr; using boost::dynamic_pointer_cast; -static Interface NullInterface( "nullCipher", 1, 0, 0 ); +static Interface NullInterface = makeInterface( "nullCipher", 1, 0, 0 ); static Range NullKeyRange(0); static Range NullBlockRange(1,4096,1); diff --git a/encfs/NullCipher.h b/encfs/NullCipher.h index 3d7ff67..14ed804 100644 --- a/encfs/NullCipher.h +++ b/encfs/NullCipher.h @@ -28,13 +28,13 @@ */ class NullCipher : public Cipher { - rel::Interface iface; + Interface iface; public: - NullCipher(const rel::Interface &iface); + NullCipher(const Interface &iface); virtual ~NullCipher(); - virtual rel::Interface interface() const; + virtual Interface interface() const; // create a new key based on a password virtual CipherKey newKey(const char *password, int passwdLength, diff --git a/encfs/NullNameIO.cpp b/encfs/NullNameIO.cpp index 90485ef..8792e37 100644 --- a/encfs/NullNameIO.cpp +++ b/encfs/NullNameIO.cpp @@ -22,7 +22,6 @@ #include -using namespace rel; using boost::shared_ptr; static shared_ptr NewNNIO( const Interface &, @@ -31,7 +30,7 @@ static shared_ptr NewNNIO( const Interface &, return shared_ptr( new NullNameIO() ); } -static Interface NNIOIface("nameio/null", 1, 0, 0); +static Interface NNIOIface = makeInterface("nameio/null", 1, 0, 0); static bool NullNameIO_registered = NameIO::Register("Null", "No encryption of filenames", NNIOIface, NewNNIO); diff --git a/encfs/NullNameIO.h b/encfs/NullNameIO.h index e86368b..ee5d9d9 100644 --- a/encfs/NullNameIO.h +++ b/encfs/NullNameIO.h @@ -23,13 +23,13 @@ class NullNameIO : public NameIO { public: - static rel::Interface CurrentInterface(); + static Interface CurrentInterface(); NullNameIO( ); virtual ~NullNameIO(); - virtual rel::Interface interface() const; + virtual Interface interface() const; virtual int maxEncodedNameLen( int plaintextNameLen ) const; virtual int maxDecodedNameLen( int encodedNameLen ) const; diff --git a/encfs/RawFileIO.cpp b/encfs/RawFileIO.cpp index 9b01dfc..44bbad9 100644 --- a/encfs/RawFileIO.cpp +++ b/encfs/RawFileIO.cpp @@ -33,9 +33,9 @@ using namespace std; -static rel::Interface RawFileIO_iface("FileIO/Raw", 1, 0, 0); +static Interface RawFileIO_iface = makeInterface("FileIO/Raw", 1, 0, 0); -FileIO *NewRawFileIO( const rel::Interface &iface ) +FileIO *NewRawFileIO( const Interface &iface ) { (void)iface; return new RawFileIO(); @@ -82,7 +82,7 @@ RawFileIO::~RawFileIO() close( _fd ); } -rel::Interface RawFileIO::interface() const +Interface RawFileIO::interface() const { return RawFileIO_iface; } diff --git a/encfs/RawFileIO.h b/encfs/RawFileIO.h index 6e481ee..0156c4c 100644 --- a/encfs/RawFileIO.h +++ b/encfs/RawFileIO.h @@ -29,7 +29,7 @@ public: RawFileIO( const std::string &fileName ); virtual ~RawFileIO(); - virtual rel::Interface interface() const; + virtual Interface interface() const; virtual void setFileName( const char *fileName ); virtual const char *getFileName() const; diff --git a/encfs/SSL_Cipher.cpp b/encfs/SSL_Cipher.cpp index a6e9290..98d5b27 100644 --- a/encfs/SSL_Cipher.cpp +++ b/encfs/SSL_Cipher.cpp @@ -66,10 +66,7 @@ inline int MIN(int a, int b) the state of EVP_CIPHER struct. EVP_BytesToKey will only produce 128 bit keys for the EVP Blowfish interface, which is not what we want. - Eliminated the salt code, since we don't use it.. Reason is that we're - using the derived key to encode random data. Since there is no known - plaintext, there is no ability for an attacker to pre-compute known - password->data mappings, which is what the salt is meant to frustrate. + DEPRECATED: this is here for backward compatibilty only. Use PBKDF */ int BytesToKey( int keyLen, int ivLen, const EVP_MD *md, const unsigned char *data, int dataLen, @@ -103,7 +100,7 @@ int BytesToKey( int keyLen, int ivLen, const EVP_MD *md, } int offset = 0; - int toCopy = MIN( nkey, mds - offset ); + int toCopy = MIN( nkey, (int)mds - offset ); if( toCopy ) { memcpy( key, mdBuf+offset, toCopy ); @@ -111,7 +108,7 @@ int BytesToKey( int keyLen, int ivLen, const EVP_MD *md, nkey -= toCopy; offset += toCopy; } - toCopy = MIN( niv, mds - offset ); + toCopy = MIN( niv, (int)mds - offset ); if( toCopy ) { memcpy( iv, mdBuf+offset, toCopy ); @@ -174,8 +171,8 @@ int TimedPBKDF2(const char *pass, int passlen, // - Version 2:1 adds support for Message Digest function interface // - Version 2:2 adds PBKDF2 for password derivation // - Version 3:0 adds a new IV mechanism -static Interface BlowfishInterface( "ssl/blowfish", 3, 0, 2 ); -static Interface AESInterface( "ssl/aes", 3, 0, 2 ); +static Interface BlowfishInterface = makeInterface( "ssl/blowfish", 3, 0, 2 ); +static Interface AESInterface = makeInterface( "ssl/aes", 3, 0, 2 ); #if defined(HAVE_EVP_BF) @@ -275,19 +272,20 @@ SSLKey::SSLKey(int keySize_, int ivLength_) this->ivLength = ivLength_; pthread_mutex_init( &mutex, 0 ); buffer = (unsigned char *)OPENSSL_malloc( keySize + ivLength ); - memset( buffer, 0, keySize + ivLength ); // most likely fails unless we're running as root, or a user-page-lock // kernel patch is applied.. mlock( buffer, keySize + ivLength ); + + memset( buffer, 0, keySize + ivLength ); } SSLKey::~SSLKey() { memset( buffer, 0, keySize + ivLength ); - OPENSSL_free( buffer ); munlock( buffer, keySize + ivLength ); + OPENSSL_free( buffer ); keySize = 0; ivLength = 0; @@ -370,7 +368,7 @@ SSL_Cipher::SSL_Cipher(const Interface &iface_, iface.name().c_str(), _keySize, _ivLength); if( (EVP_CIPHER_key_length( _blockCipher ) != (int )_keySize) - && iface.current() == 1) + && iface.major() == 1) { rWarning("Running in backward compatibilty mode for 1.0 - \n" "key is really %i bits, not %i.\n" @@ -438,7 +436,7 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength) shared_ptr key( new SSLKey( _keySize, _ivLength) ); int bytes = 0; - if( iface.current() > 1 ) + if( iface.major() > 1 ) { // now we use BytesToKey, which can deal with Blowfish keys larger then // 128 bits. @@ -680,7 +678,7 @@ int SSL_Cipher::cipherBlockSize() const void SSL_Cipher::setIVec( unsigned char *ivec, uint64_t seed, const shared_ptr &key) const { - if (iface.current() >= 3) + if (iface.major() >= 3) { memcpy( ivec, IVData(key), _ivLength ); @@ -707,7 +705,7 @@ void SSL_Cipher::setIVec( unsigned char *ivec, uint64_t seed, } } -/** For backward compatibility. +/** Deprecated: For backward compatibility only. A watermark attack was discovered against this IV setup. If an attacker could get a victim to store a carefully crafted file, they could later determine if the victim had the file in encrypted storage (without @@ -717,13 +715,6 @@ void SSL_Cipher::setIVec_old(unsigned char *ivec, unsigned int seed, const shared_ptr &key) const { - /* These multiplication constants chosen as they represent (non optimal) - Golumb rulers, the idea being to spread around the information in the - seed. - - 0x060a4011 : ruler length 26, 7 marks, 21 measurable lengths - 0x0221040d : ruler length 25, 7 marks, 21 measurable lengths - */ unsigned int var1 = 0x060a4011 * seed; unsigned int var2 = 0x0221040d * (seed ^ 0xD3FEA11C); diff --git a/encfs/SSL_Cipher.h b/encfs/SSL_Cipher.h index cb5ab4a..5ea7f72 100644 --- a/encfs/SSL_Cipher.h +++ b/encfs/SSL_Cipher.h @@ -70,21 +70,21 @@ using boost::shared_ptr; */ class SSL_Cipher : public Cipher { - rel::Interface iface; - rel::Interface realIface; + Interface iface; + Interface realIface; const EVP_CIPHER *_blockCipher; const EVP_CIPHER *_streamCipher; unsigned int _keySize; // in bytes unsigned int _ivLength; public: - SSL_Cipher(const rel::Interface &iface, const rel::Interface &realIface, + SSL_Cipher(const Interface &iface, const Interface &realIface, const EVP_CIPHER *blockCipher, const EVP_CIPHER *streamCipher, int keyLength); virtual ~SSL_Cipher(); // returns the real interface, not the one we're emulating (if any).. - virtual rel::Interface interface() const; + virtual Interface interface() const; // create a new key based on a password virtual CipherKey newKey(const char *password, int passwdLength, diff --git a/encfs/StreamNameIO.cpp b/encfs/StreamNameIO.cpp index cd7f4a4..615f31b 100644 --- a/encfs/StreamNameIO.cpp +++ b/encfs/StreamNameIO.cpp @@ -26,7 +26,6 @@ #include "i18n.h" #include -using namespace rel; using namespace std; static shared_ptr NewStreamNameIO( const Interface &iface, @@ -65,13 +64,13 @@ static bool StreamIO_registered = NameIO::Register("Stream", Interface StreamNameIO::CurrentInterface() { // implement major version 2, 1, and 0 - return Interface("nameio/stream", 2, 1, 2); + return makeInterface("nameio/stream", 2, 1, 2); } -StreamNameIO::StreamNameIO( const rel::Interface &iface, +StreamNameIO::StreamNameIO( const Interface &iface, const shared_ptr &cipher, const CipherKey &key ) - : _interface( iface.current() ) + : _interface( iface.major() ) , _cipher( cipher ) , _key( key ) { diff --git a/encfs/StreamNameIO.h b/encfs/StreamNameIO.h index 38e4be8..2940ff3 100644 --- a/encfs/StreamNameIO.h +++ b/encfs/StreamNameIO.h @@ -27,14 +27,14 @@ using boost::shared_ptr; class StreamNameIO : public NameIO { public: - static rel::Interface CurrentInterface(); + static Interface CurrentInterface(); - StreamNameIO( const rel::Interface &iface, + StreamNameIO( const Interface &iface, const shared_ptr &cipher, const CipherKey &key ); virtual ~StreamNameIO(); - virtual rel::Interface interface() const; + virtual Interface interface() const; virtual int maxEncodedNameLen( int plaintextNameLen ) const; virtual int maxDecodedNameLen( int encodedNameLen ) const; diff --git a/encfs/XmlReader.cpp b/encfs/XmlReader.cpp new file mode 100644 index 0000000..f5b54a9 --- /dev/null +++ b/encfs/XmlReader.cpp @@ -0,0 +1,191 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2012, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include "XmlReader.h" +#include "base64.h" + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +using namespace std; +using namespace rlog; + +XmlValue::~XmlValue() +{ +} + +XmlValuePtr XmlValue::operator[] (const char *path) const +{ + return this->find(path); +} + +XmlValuePtr XmlValue::find(const char *name) const +{ + rError("in XmlValue::operator[%s]", name); + return XmlValuePtr(new XmlValue()); +} + +const XmlValuePtr & operator >> (const XmlValuePtr &ptr, std::string &out) +{ + out = ptr->text(); + return ptr; +} + +const XmlValuePtr & operator >> (const XmlValuePtr &ptr, int &out) +{ + out = atoi(ptr->text().c_str()); + return ptr; +} + +const XmlValuePtr & operator >> (const XmlValuePtr &ptr, long &out) +{ + out = atol(ptr->text().c_str()); + return ptr; +} + +const XmlValuePtr & operator >> (const XmlValuePtr &ptr, double &out) +{ + out = atof(ptr->text().c_str()); + return ptr; +} + +const XmlValuePtr & operator >> (const XmlValuePtr &ptr, bool &out) +{ + out = atoi(ptr->text().c_str()); + return ptr; +} + +bool XmlValue::readB64Data(unsigned char *data, int length) const +{ + std::string s = value; + s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end()); + + BIO *b64 = BIO_new(BIO_f_base64()); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + + BIO *bmem = BIO_new_mem_buf((void *)s.c_str(), s.size()); + bmem = BIO_push(b64, bmem); + + int decodedSize = BIO_read(bmem, data, length); + BIO_free_all(b64); + + if (decodedSize != length) + { + rError("decoding bytes len %i, expecting output len %i, got %i", + (int)s.size(), length, decodedSize); + return false; + } + + return true; +} + +std::string safeValueForNode(TiXmlElement *element) +{ + std::string value; + const TiXmlNode *child = element->FirstChild(); + if (child) + { + const TiXmlText *childText = child->ToText(); + if (childText) + value = childText->Value(); + } + + return value; +} + +class XmlNode : virtual public XmlValue +{ + TiXmlElement *element; +public: + XmlNode(TiXmlElement *element_) + : XmlValue(safeValueForNode(element_)) + , element(element_) + { + } + + virtual ~XmlNode() + { + } + + virtual XmlValuePtr find(const char *name) const + { + if (name[0] == '@') + { + return XmlValuePtr(new XmlValue(element->Attribute(name+1))); + } else + { + return XmlValuePtr(new XmlNode(element->FirstChild(name)->ToElement())); + } + } +}; + +struct XmlReader::XmlReaderData +{ + boost::shared_ptr doc; +}; + +XmlReader::XmlReader() + : pd(new XmlReaderData()) +{ +} + +XmlReader::~XmlReader() +{ +} + +bool XmlReader::load(const char *fileName) +{ + pd->doc.reset(new TiXmlDocument(fileName)); + + return pd->doc->LoadFile(); +} + +XmlValuePtr XmlReader::operator[] ( const char *name ) const +{ + TiXmlNode *node = pd->doc->FirstChild(name); + if (node == NULL) + { + rError("Xml node %s not found", name); + return XmlValuePtr(new XmlValue()); + } + + TiXmlElement *element = node->ToElement(); + if (element == NULL) + { + rError("Xml node %s not element, type = %i", name, node->Type()); + return XmlValuePtr(new XmlValue()); + } + + return XmlValuePtr(new XmlNode(element)); +} + diff --git a/encfs/XmlReader.h b/encfs/XmlReader.h new file mode 100644 index 0000000..e538a66 --- /dev/null +++ b/encfs/XmlReader.h @@ -0,0 +1,78 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2012, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef _XmlReader_incl_ +#define _XmlReader_incl_ + +#include +#include + +class XmlValue; +typedef boost::shared_ptr XmlValuePtr; + +class XmlValue +{ + std::string value; +public: + XmlValue() + { + } + + XmlValue(const std::string &value) + { + this->value = value; + } + virtual ~XmlValue(); + + XmlValuePtr operator[] (const char *path) const; + + bool readB64Data(unsigned char *data, int length) const; + + const std::string &text() const + { + return value; + } + +protected: + virtual XmlValuePtr find(const char *name) const; +}; + +const XmlValuePtr & operator >> (const XmlValuePtr &ptr, std::string &outStr); +const XmlValuePtr & operator >> (const XmlValuePtr &ptr, int &out); +const XmlValuePtr & operator >> (const XmlValuePtr &ptr, long &out); +const XmlValuePtr & operator >> (const XmlValuePtr &ptr, double &out); +const XmlValuePtr & operator >> (const XmlValuePtr &ptr, bool &out); + +class XmlReader +{ +public: + XmlReader(); + ~XmlReader(); + + bool load(const char *fileName); + + XmlValuePtr operator[](const char *name) const; + +private: + struct XmlReaderData; + boost::shared_ptr pd; +}; + +#endif diff --git a/encfs/config.proto b/encfs/config.proto new file mode 100644 index 0000000..3f975fa --- /dev/null +++ b/encfs/config.proto @@ -0,0 +1,36 @@ + +message EncfsConfig +{ + optional string creator = 1; + optional int32 revision = 2 [default=0]; + + required Interface cipher = 3; + required bytes key = 4; + optional bytes salt = 41; + required int32 key_size = 42; // in bits + optional int32 kdf_iterations = 43 [default=0]; + optional int32 kdf_duration = 44 [default=500]; + + optional Interface naming = 5; + optional bool unique_iv = 51 [default=false]; + optional bool chained_iv = 52 [default=false]; + optional bool external_iv = 53 [default=false]; + + required int32 block_size = 6; + optional int32 block_mac_bytes = 61 [default=0]; + optional int32 block_mac_rand_bytes = 611 [default=0]; + optional bool allow_holes = 62 [default = false]; +} + +message Interface +{ + required string name = 1; + required uint32 major = 2; // major version number + required uint32 minor = 3; // minor version number + + // Age indicates number of major versions supported. 0 means no backward + // compatibility. See libtool "updating version information" for more + // details on how major/minor/age are used for versioning libraries. + optional uint32 age = 4; +} + diff --git a/encfs/encfsctl.cpp b/encfs/encfsctl.cpp index 369c37a..4cc2a37 100644 --- a/encfs/encfsctl.cpp +++ b/encfs/encfsctl.cpp @@ -176,7 +176,7 @@ static int showInfo( int argc, char **argv ) if( !checkDir( rootDir )) return EXIT_FAILURE; - boost::shared_ptr config(new EncFSConfig); + EncfsConfig config; ConfigType type = readConfig( rootDir, config ); // show information stored in config.. @@ -194,24 +194,22 @@ static int showInfo( int argc, char **argv ) case Config_V3: // xgroup(diag) cout << "\n" << autosprintf(_("Version 3 configuration; " - "created by %s\n"), config->creator.c_str()); + "created by %s\n"), config.creator().c_str()); break; case Config_V4: // xgroup(diag) cout << "\n" << autosprintf(_("Version 4 configuration; " - "created by %s\n"), config->creator.c_str()); + "created by %s\n"), config.creator().c_str()); break; case Config_V5: - // xgroup(diag) - cout << "\n" << autosprintf(_("Version 5 configuration; " - "created by %s (revision %i)\n"), config->creator.c_str(), - config->subVersion); - break; case Config_V6: + case Config_V7: // xgroup(diag) - cout << "\n" << autosprintf(_("Version 6 configuration; " - "created by %s (revision %i)\n"), config->creator.c_str(), - config->subVersion); + cout << "\n" << autosprintf(_("Version %i configuration; " + "created by %s (revision %i)\n"), + type, + config.creator().c_str(), + config.revision()); break; } @@ -687,9 +685,7 @@ static int cmd_showcruft( int argc, char **argv ) int filesFound = showcruft( rootInfo, "/" ); - cerr << autosprintf( - ngettext("Found %i invalid file.", "Found %i invalid files.", - filesFound), filesFound) << "\n"; + cerr << autosprintf("Found %i invalid file(s).", filesFound) << "\n"; return EXIT_SUCCESS; } @@ -701,7 +697,7 @@ static int do_chpasswd( bool useStdin, bool annotate, int argc, char **argv ) if( !checkDir( rootDir )) return EXIT_FAILURE; - boost::shared_ptr config(new EncFSConfig); + EncfsConfig config; ConfigType cfgType = readConfig( rootDir, config ); if(cfgType == Config_None) @@ -711,12 +707,11 @@ static int do_chpasswd( bool useStdin, bool annotate, int argc, char **argv ) } // instanciate proper cipher - shared_ptr cipher = Cipher::New( - config->cipherIface, config->keySize ); + shared_ptr cipher = getCipher(config); if(!cipher) { cout << autosprintf(_("Unable to find specified cipher \"%s\"\n"), - config->cipherIface.name().c_str()); + config.cipher().name().c_str()); return EXIT_FAILURE; } @@ -724,13 +719,14 @@ static int do_chpasswd( bool useStdin, bool annotate, int argc, char **argv ) cout << _("Enter current Encfs password\n"); if (annotate) cerr << "$PROMPT$ passwd" << endl; - CipherKey userKey = config->getUserKey( useStdin ); + CipherKey userKey = getUserKey( config, useStdin ); if(!userKey) return EXIT_FAILURE; // decode volume key using user key -- at this point we detect an incorrect // password if the key checksum does not match (causing readKey to fail). - CipherKey volumeKey = cipher->readKey( config->getKeyData(), userKey ); + CipherKey volumeKey = cipher->readKey( + (const unsigned char *)config.key().data(), userKey ); if(!volumeKey) { @@ -741,17 +737,15 @@ static int do_chpasswd( bool useStdin, bool annotate, int argc, char **argv ) // Now, get New user key.. userKey.reset(); cout << _("Enter new Encfs password\n"); - // reinitialize salt and iteration count - config->kdfIterations = 0; // generate new + // create new key if( useStdin ) { if (annotate) cerr << "$PROMPT$ new_passwd" << endl; - userKey = config->getUserKey( true ); } - else - userKey = config->getNewUserKey(); + + userKey = getNewUserKey( config, useStdin, string(), string() ); // re-encode the volume key using the new user key and write it out.. int result = EXIT_FAILURE; @@ -764,10 +758,10 @@ static int do_chpasswd( bool useStdin, bool annotate, int argc, char **argv ) cipher->writeKey( volumeKey, keyBuf, userKey ); userKey.reset(); - config->assignKeyData( keyBuf, encodedKeySize ); + config.set_key( keyBuf, encodedKeySize ); delete[] keyBuf; - if(saveConfig( cfgType, rootDir, config )) + if(saveConfig( rootDir, config )) { // password modified -- changes volume key of filesystem.. cout << _("Volume Key successfully updated.\n"); @@ -816,7 +810,7 @@ int main(int argc, char **argv) slog->subscribeTo( GetGlobalChannel("error") ); slog->subscribeTo( GetGlobalChannel("warning") ); #ifndef NO_DEBUG - //slog->subscribeTo( GetGlobalChannel("debug") ); + slog->subscribeTo( GetGlobalChannel("debug") ); #endif if(argc < 2) diff --git a/encfs/main.cpp b/encfs/main.cpp index 393ebb5..c086704 100644 --- a/encfs/main.cpp +++ b/encfs/main.cpp @@ -69,7 +69,6 @@ inline static int MAX(int a, int b) using namespace std; using namespace rlog; -using namespace rel; using namespace gnu; using boost::shared_ptr; using boost::scoped_ptr; diff --git a/encfs/test.cpp b/encfs/test.cpp index 4bb2faa..3d0e6dc 100644 --- a/encfs/test.cpp +++ b/encfs/test.cpp @@ -47,11 +47,12 @@ #endif #endif +#include + #include using namespace std; -using namespace rel; using namespace rlog; using boost::shared_ptr; @@ -235,35 +236,28 @@ bool runTests(const shared_ptr &cipher, bool verbose) cipher->writeKey( key, keyBuf, encodingKey ); // store in config struct.. - EncFSConfig cfg; - cfg.cipherIface = cipher->interface(); - cfg.keySize = 8 * cipher->keySize(); - cfg.blockSize = FSBlockSize; - cfg.assignKeyData( keyBuf, encodedKeySize ); + EncfsConfig cfg; + cfg.mutable_cipher()->MergeFrom(cipher->interface()); + cfg.set_key_size(8 * cipher->keySize()); + cfg.set_block_size(FSBlockSize); + cfg.set_key( keyBuf, encodedKeySize ); // save config string data; - { - ostringstream st; - st << cfg; - data = st.str(); - } + google::protobuf::TextFormat::PrintToString(cfg, &data); // read back in and check everything.. - EncFSConfig cfg2; - { - istringstream st(data); - st >> cfg2; - } + EncfsConfig cfg2; + google::protobuf::TextFormat::ParseFromString(data, &cfg2); // check.. - rAssert( cfg.cipherIface.implements(cfg2.cipherIface) ); - rAssert( cfg.keySize == cfg2.keySize ); - rAssert( cfg.blockSize == cfg2.blockSize ); + rAssert( implements(cfg.cipher(),cfg2.cipher()) ); + rAssert( cfg.key_size() == cfg2.key_size() ); + rAssert( cfg.block_size() == cfg2.block_size() ); // try decoding key.. - CipherKey key2 = cipher->readKey( cfg2.getKeyData(), encodingKey ); + CipherKey key2 = cipher->readKey( (unsigned char *)cfg2.key().data(), encodingKey ); if(!key2) { if(verbose) @@ -286,15 +280,15 @@ bool runTests(const shared_ptr &cipher, bool verbose) FSConfigPtr fsCfg = FSConfigPtr(new FSConfig); fsCfg->cipher = cipher; fsCfg->key = key; - fsCfg->config.reset(new EncFSConfig); - fsCfg->config->blockSize = FSBlockSize; + fsCfg->config.reset(new EncfsConfig); + fsCfg->config->set_block_size(FSBlockSize); if(verbose) cerr << "Testing name encode/decode (stream coding w/ IV chaining)\n"; { fsCfg->opts.reset(new EncFS_Opts); fsCfg->opts->idleTracking = false; - fsCfg->config->uniqueIV = false; + fsCfg->config->set_unique_iv(false); fsCfg->nameCoding.reset( new StreamNameIO( StreamNameIO::CurrentInterface(), cipher, key ) ); @@ -310,7 +304,7 @@ bool runTests(const shared_ptr &cipher, bool verbose) cerr << "Testing name encode/decode (block coding w/ IV chaining)\n"; { fsCfg->opts->idleTracking = false; - fsCfg->config->uniqueIV = false; + fsCfg->config->set_unique_iv(false); fsCfg->nameCoding.reset( new BlockNameIO( BlockNameIO::CurrentInterface(), cipher, key, cipher->cipherBlockSize() ) ); @@ -326,7 +320,7 @@ bool runTests(const shared_ptr &cipher, bool verbose) cerr << "Testing name encode/decode (block coding w/ IV chaining, base32)\n"; { fsCfg->opts->idleTracking = false; - fsCfg->config->uniqueIV = false; + fsCfg->config->set_unique_iv(false); fsCfg->nameCoding.reset( new BlockNameIO( BlockNameIO::CurrentInterface(), cipher, key, cipher->cipherBlockSize(), true ) ); @@ -503,8 +497,8 @@ int main(int argc, char *argv[]) { cerr << it->name << " ( " << it->iface.name() << " " - << it->iface.current() << ":" - << it->iface.revision() << ":" + << it->iface.major() << ":" + << it->iface.minor() << ":" << it->iface.age() << " ) : " << it->description << "\n"; cerr << " - key length " << it->keyLength.min() << " to " << it->keyLength.max() << " , block size " << it->blockSize.min() From a4089d44790b4164cc1f0e194f1c126902391f27 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Thu, 26 Apr 2012 02:38:10 +0000 Subject: [PATCH 04/51] update changelog git-svn-id: http://encfs.googlecode.com/svn/trunk@81 db9cf616-1c43-0410-9cb8-a902689de0d6 --- ChangeLog | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index af35923..01fa5d5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +Wed Apr 25 2012 Valient Gough + * fix encfsctl cat when iv chaining is enabled. Fixes issue #132 + Thu Mar 22 2012 Valient Gough * skip name collision test * bump version to 1.8.0 @@ -12,7 +15,7 @@ Fri Mar 2 2012 Valient Gough Wed Feb 29 2012 Valient Gough * switch to OpenSSL B64 decode to be comptible with boost serialization - * implement v6 config reader using XML reader based on tinyxml + * implement v6 config reader using XML reader based on libxml2 Mon Jan 2 2012 Valient Gough * test for name case collisions in b64 coding From 7efdea5e1729ad3e8c2b9d5772758a45d9712c07 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Mon, 14 May 2012 03:13:23 +0000 Subject: [PATCH 05/51] allow "config" as top-level XML node when reading Boost serialization config. git-svn-id: http://encfs.googlecode.com/svn/trunk@82 db9cf616-1c43-0410-9cb8-a902689de0d6 --- encfs/FileUtils.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/encfs/FileUtils.cpp b/encfs/FileUtils.cpp index 9972731..75caa11 100644 --- a/encfs/FileUtils.cpp +++ b/encfs/FileUtils.cpp @@ -285,6 +285,14 @@ bool readV6Config( const char *configFile, XmlValuePtr serialization = rdr["boost_serialization"]; XmlValuePtr config = (*serialization)["cfg"]; + if (!config) { + config = (*serialization)["config"]; + } + if (!config) { + rError("Unable to find XML configuration in file %s", configFile); + return false; + } + int version = 0; (*config)["@version"] >> version; From f144de359f0d8cfb5931ceffb3d5fc21332b9c40 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Mon, 20 Aug 2012 05:04:18 +0000 Subject: [PATCH 06/51] minor updates git-svn-id: http://encfs.googlecode.com/svn/trunk@83 db9cf616-1c43-0410-9cb8-a902689de0d6 --- encfs/FileUtils.cpp | 1 - encfs/main.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/encfs/FileUtils.cpp b/encfs/FileUtils.cpp index 75caa11..92f3fd6 100644 --- a/encfs/FileUtils.cpp +++ b/encfs/FileUtils.cpp @@ -1585,7 +1585,6 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) if(opts->passwordProgram.empty()) { - rDebug( "useStdin: %i", opts->useStdin ); if (opts->annotate) cerr << "$PROMPT$ passwd" << endl; userKey = getUserKey( config, opts->useStdin ); diff --git a/encfs/main.cpp b/encfs/main.cpp index c086704..d20d00a 100644 --- a/encfs/main.cpp +++ b/encfs/main.cpp @@ -245,7 +245,7 @@ bool processArgs(int argc, char *argv[], const shared_ptr &out) // 'm' : mount-on-demand // 'S' : password from stdin // 'o' : arguments meant for fuse - int res = getopt_long( argc, argv, "HsSfvdmi:o:", + int res = getopt_long( argc, argv, "HsSfvVdmi:o:", long_options, &option_index); if(res == -1) From 183dca787f03857b2afcd61cf26586115c2edc0b Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Mon, 20 Aug 2012 05:04:59 +0000 Subject: [PATCH 07/51] reformat file git-svn-id: http://encfs.googlecode.com/svn/trunk@84 db9cf616-1c43-0410-9cb8-a902689de0d6 --- encfs/Cipher.h | 201 +++++++++++++++++++++++++------------------------ 1 file changed, 102 insertions(+), 99 deletions(-) diff --git a/encfs/Cipher.h b/encfs/Cipher.h index 83648f3..87efd5b 100644 --- a/encfs/Cipher.h +++ b/encfs/Cipher.h @@ -40,126 +40,129 @@ using boost::shared_ptr; class Cipher { public: - // if no key length was indicated when cipher was registered, then keyLen - // <= 0 will be used. - typedef boost::shared_ptr (*CipherConstructor)( const Interface &iface, - int keyLenBits ); + // if no key length was indicated when cipher was registered, then keyLen + // <= 0 will be used. + typedef boost::shared_ptr (*CipherConstructor)( + const Interface &iface, int keyLenBits ); - struct CipherAlgorithm - { - std::string name; - std::string description; - Interface iface; - Range keyLength; - Range blockSize; - }; + struct CipherAlgorithm + { + std::string name; + std::string description; + Interface iface; + Range keyLength; + Range blockSize; + }; - typedef std::list AlgorithmList; - static AlgorithmList GetAlgorithmList( bool includeHidden = false ); + typedef std::list AlgorithmList; + static AlgorithmList GetAlgorithmList( bool includeHidden = false ); - static boost::shared_ptr New( const Interface &iface, - int keyLen = -1); - static boost::shared_ptr New( const std::string &cipherName, - int keyLen = -1 ); + static boost::shared_ptr New( const Interface &iface, + int keyLen = -1); + static boost::shared_ptr New( const std::string &cipherName, + int keyLen = -1 ); - static bool Register(const char *cipherName, - const char *description, - const Interface &iface, - CipherConstructor constructor, - bool hidden = false); - static bool Register(const char *cipherName, - const char *description, - const Interface &iface, - const Range &keyLength, const Range &blockSize, - CipherConstructor constructor, - bool hidden = false); + static bool Register(const char *cipherName, + const char *description, + const Interface &iface, + CipherConstructor constructor, + bool hidden = false); + static bool Register(const char *cipherName, + const char *description, + const Interface &iface, + const Range &keyLength, const Range &blockSize, + CipherConstructor constructor, + bool hidden = false); - Cipher(); - virtual ~Cipher(); + Cipher(); + virtual ~Cipher(); - virtual Interface interface() const =0; + virtual Interface interface() const =0; - // create a new key based on a password - // if iterationCount == 0, then iteration count will be determined - // by newKey function and filled in. - // If iterationCount == 0, then desiredFunctionDuration is how many - // milliseconds the password derivation function should take to run. - virtual CipherKey newKey(const char *password, int passwdLength, - int &iterationCount, long desiredFunctionDuration, - const unsigned char *salt, int saltLen) =0; - // deprecated - for backward compatibility - virtual CipherKey newKey(const char *password, int passwdLength ) =0; - // create a new random key - virtual CipherKey newRandomKey() =0; + // create a new key based on a password + // if iterationCount == 0, then iteration count will be determined + // by newKey function and filled in. + // If iterationCount == 0, then desiredFunctionDuration is how many + // milliseconds the password derivation function should take to run. + virtual CipherKey newKey(const char *password, int passwdLength, + int &iterationCount, long desiredFunctionDuration, + const unsigned char *salt, int saltLen) =0; - // data must be len encodedKeySize() - virtual CipherKey readKey(const unsigned char *data, - const CipherKey &encodingKey, - bool checkKey = true) =0; - virtual void writeKey(const CipherKey &key, unsigned char *data, - const CipherKey &encodingKey) =0; + // deprecated - for backward compatibility + virtual CipherKey newKey(const char *password, int passwdLength ) =0; - virtual std::string encodeAsString(const CipherKey &key, - const CipherKey &encodingKey ); + // create a new random key + virtual CipherKey newRandomKey() =0; - // for testing purposes - virtual bool compareKey( const CipherKey &A, const CipherKey &B ) const =0; + // data must be len encodedKeySize() + virtual CipherKey readKey(const unsigned char *data, + const CipherKey &encodingKey, + bool checkKey = true) =0; - // meta-data about the cypher - virtual int keySize() const=0; - virtual int encodedKeySize() const=0; // size - virtual int cipherBlockSize() const=0; // size of a cipher block + virtual void writeKey(const CipherKey &key, unsigned char *data, + const CipherKey &encodingKey) =0; - // fill the supplied buffer with random data - // The data may be pseudo random and might not be suitable for key - // generation. For generating keys, uses newRandomKey() instead. - // Returns true on success, false on failure. - virtual bool randomize( unsigned char *buf, int len, - bool strongRandom ) const =0; + virtual std::string encodeAsString(const CipherKey &key, + const CipherKey &encodingKey ); - // 64 bit MAC of the data with the given key - virtual uint64_t MAC_64( const unsigned char *src, int len, - const CipherKey &key, uint64_t *chainedIV = 0 ) const =0; - // based on reductions of MAC_64 - unsigned int MAC_32( const unsigned char *src, int len, - const CipherKey &key, uint64_t *chainedIV = 0 ) const; - unsigned int MAC_16( const unsigned char *src, int len, - const CipherKey &key, uint64_t *chainedIV = 0 ) const; + // for testing purposes + virtual bool compareKey( const CipherKey &A, const CipherKey &B ) const =0; - // functional interfaces - /* - Stream encoding of data in-place. The stream data can be any length. - */ - virtual bool streamEncode( unsigned char *data, int len, - uint64_t iv64, const CipherKey &key) const=0; - virtual bool streamDecode( unsigned char *data, int len, - uint64_t iv64, const CipherKey &key) const=0; + // meta-data about the cypher + virtual int keySize() const=0; + virtual int encodedKeySize() const=0; // size + virtual int cipherBlockSize() const=0; // size of a cipher block - /* - These are just aliases of streamEncode / streamDecode, but there are - provided here for backward compatibility for earlier ciphers that has - effectively two stream modes - one for encoding partial blocks and - another for encoding filenames. - */ - virtual bool nameEncode( unsigned char *data, int len, - uint64_t iv64, const CipherKey &key) const; - virtual bool nameDecode( unsigned char *data, int len, - uint64_t iv64, const CipherKey &key) const; + // fill the supplied buffer with random data + // The data may be pseudo random and might not be suitable for key + // generation. For generating keys, uses newRandomKey() instead. + // Returns true on success, false on failure. + virtual bool randomize( unsigned char *buf, int len, + bool strongRandom ) const =0; - /* - Block encoding of data in-place. The data size should be a multiple of - the cipher block size. - */ - virtual bool blockEncode(unsigned char *buf, int size, - uint64_t iv64, const CipherKey &key) const=0; - virtual bool blockDecode(unsigned char *buf, int size, - uint64_t iv64, const CipherKey &key) const=0; + // 64 bit MAC of the data with the given key + virtual uint64_t MAC_64( const unsigned char *src, int len, + const CipherKey &key, uint64_t *chainedIV = 0 ) const =0; + + // based on reductions of MAC_64 + unsigned int MAC_32( const unsigned char *src, int len, + const CipherKey &key, uint64_t *chainedIV = 0 ) const; + unsigned int MAC_16( const unsigned char *src, int len, + const CipherKey &key, uint64_t *chainedIV = 0 ) const; + + // functional interfaces + /* + Stream encoding of data in-place. The stream data can be any length. + */ + virtual bool streamEncode( unsigned char *data, int len, + uint64_t iv64, const CipherKey &key) const=0; + virtual bool streamDecode( unsigned char *data, int len, + uint64_t iv64, const CipherKey &key) const=0; + + /* + These are just aliases of streamEncode / streamDecode, but there are + provided here for backward compatibility for earlier ciphers that has + effectively two stream modes - one for encoding partial blocks and + another for encoding filenames. + */ + virtual bool nameEncode( unsigned char *data, int len, + uint64_t iv64, const CipherKey &key) const; + virtual bool nameDecode( unsigned char *data, int len, + uint64_t iv64, const CipherKey &key) const; + + /* + Block encoding of data in-place. The data size should be a multiple of + the cipher block size. + */ + virtual bool blockEncode(unsigned char *buf, int size, + uint64_t iv64, const CipherKey &key) const=0; + virtual bool blockDecode(unsigned char *buf, int size, + uint64_t iv64, const CipherKey &key) const=0; }; - #endif From 36946fdea78a9f7046d3bb39ff1be2d184cb62af Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Mon, 20 Aug 2012 05:05:16 +0000 Subject: [PATCH 08/51] move encrypted key into separate config block git-svn-id: http://encfs.googlecode.com/svn/trunk@85 db9cf616-1c43-0410-9cb8-a902689de0d6 --- encfs/FileUtils.cpp | 69 +++++++++++++++++++++++++-------------------- encfs/config.proto | 17 +++++++---- encfs/encfsctl.cpp | 5 ++-- encfs/test.cpp | 9 +++--- 4 files changed, 58 insertions(+), 42 deletions(-) diff --git a/encfs/FileUtils.cpp b/encfs/FileUtils.cpp index 92f3fd6..436d1f6 100644 --- a/encfs/FileUtils.cpp +++ b/encfs/FileUtils.cpp @@ -344,16 +344,17 @@ bool readV6Config( const char *configFile, cfg.set_block_mac_rand_bytes(blockMacRandBytes); cfg.set_allow_holes(allowHoles); + EncryptedKey *encryptedKey = cfg.mutable_key(); int encodedSize; (*config)["encodedKeySize"] >> encodedSize; unsigned char *key = new unsigned char[encodedSize]; (*config)["encodedKeyData"]->readB64Data(key, encodedSize); - cfg.set_key(key, encodedSize); + encryptedKey->set_ciphertext(key, encodedSize); delete[] key; int keySize; (*config)["keySize"] >> keySize; - cfg.set_key_size(keySize); + encryptedKey->set_size(keySize / 8); // save as size in bytes if(cfg.revision() >= 20080816) { @@ -361,19 +362,19 @@ bool readV6Config( const char *configFile, (*config)["saltLen"] >> saltLen; unsigned char *salt = new unsigned char[saltLen]; (*config)["saltData"]->readB64Data(salt, saltLen); - cfg.set_salt(salt, saltLen); + encryptedKey->set_salt(salt, saltLen); delete[] salt; int kdfIterations, desiredKDFDuration; (*config)["kdfIterations"] >> kdfIterations; (*config)["desiredKDFDuration"] >> desiredKDFDuration; - cfg.set_kdf_iterations(kdfIterations); - cfg.set_kdf_duration(desiredKDFDuration); + encryptedKey->set_kdf_iterations(kdfIterations); + encryptedKey->set_kdf_duration(desiredKDFDuration); } else { - cfg.clear_salt(); - cfg.set_kdf_iterations(16); - cfg.set_kdf_duration(NormalKDFDuration); + encryptedKey->clear_salt(); + encryptedKey->set_kdf_iterations(16); + encryptedKey->clear_kdf_duration(); } return true; @@ -416,10 +417,11 @@ bool readV5Config( const char *configFile, cfgRdr["blockSize"] >> blockSize; config.set_block_size(blockSize); + EncryptedKey *encryptedKey = config.mutable_key(); int keySize; cfgRdr["keySize"] >> keySize; - config.set_key_size(keySize); - cfgRdr["keyData"] >> (*config.mutable_key()); + encryptedKey->set_size(keySize / 8); + cfgRdr["keyData"] >> (*encryptedKey->mutable_ciphertext()); config.set_unique_iv( cfgRdr["uniqueIV"].readBool( false ) ); config.set_chained_iv( cfgRdr["chainedIV"].readBool( false ) ); @@ -455,7 +457,8 @@ bool readV4Config( const char *configFile, cfgRdr["blockSize"] >> blockSize; config.set_block_size(blockSize); - cfgRdr["keyData"] >> (*config.mutable_key()); + EncryptedKey *key = config.mutable_key(); + cfgRdr["keyData"] >> (*key->mutable_ciphertext()); // fill in default for V4 config.mutable_naming()->MergeFrom( makeInterface("nameio/stream", 1, 0, 0) ); @@ -1058,9 +1061,10 @@ RootPtr createConfig( EncFS_Context *ctx, config.set_external_iv( externalIV ); config.set_allow_holes( allowHoles ); - config.clear_salt(); - config.clear_kdf_iterations(); // filled in by keying function - config.set_kdf_duration( desiredKDFDuration ); + EncryptedKey *key = config.mutable_key(); + key->clear_salt(); + key->clear_kdf_iterations(); // filled in by keying function + key->set_kdf_duration( desiredKDFDuration ); cout << "\n"; // xgroup(setup) @@ -1107,7 +1111,7 @@ RootPtr createConfig( EncFS_Context *ctx, cipher->writeKey( volumeKey, encodedKey, userKey ); userKey.reset(); - config.set_key(encodedKey, encodedKeySize); + key->set_ciphertext(encodedKey, encodedKeySize); delete[] encodedKey; if(!volumeKey) @@ -1203,8 +1207,9 @@ void showFSInfo( const EncfsConfig &config ) cout << "\n"; } } + const EncryptedKey &key = config.key(); { - cout << autosprintf(_("Key Size: %i bits"), config.key_size()); + cout << autosprintf(_("Key Size: %i bits"), 8 * key.size()); cipher = getCipher(config); if(!cipher) { @@ -1213,12 +1218,12 @@ void showFSInfo( const EncfsConfig &config ) } else cout << "\n"; } - if(config.kdf_iterations() > 0 && config.salt().size() > 0) + if(key.kdf_iterations() > 0 && key.salt().size() > 0) { cout << autosprintf(_("Using PBKDF2, with %i iterations"), - config.kdf_iterations()) << "\n"; + key.kdf_iterations()) << "\n"; cout << autosprintf(_("Salt Size: %i bits"), - 8*(int)config.salt().size()) << "\n"; + 8*(int)key.salt().size()) << "\n"; } if(config.block_mac_bytes() || config.block_mac_rand_bytes()) { @@ -1270,7 +1275,7 @@ void showFSInfo( const EncfsConfig &config ) shared_ptr getCipher(const EncfsConfig &config) { - return getCipher(config.cipher(), config.key_size()); + return getCipher(config.cipher(), 8 * config.key().size()); } shared_ptr getCipher(const Interface &iface, int keySize) @@ -1289,30 +1294,32 @@ CipherKey makeNewKey(EncfsConfig &config, const char *password, int passwdLen) cout << _("Error creating salt\n"); return userKey; } - config.set_salt(salt, sizeof(salt)); + EncryptedKey *key = config.mutable_key(); + key->set_salt(salt, sizeof(salt)); - int iterations = config.kdf_iterations(); + int iterations = key->kdf_iterations(); userKey = cipher->newKey( password, passwdLen, - iterations, config.kdf_duration(), + iterations, key->kdf_duration(), salt, sizeof(salt)); - config.set_kdf_iterations(iterations); + key->set_kdf_iterations(iterations); return userKey; } CipherKey decryptKey(const EncfsConfig &config, const char *password, int passwdLen) { + const EncryptedKey &key = config.key(); CipherKey userKey; - shared_ptr cipher = getCipher(config.cipher(), config.key_size()); + shared_ptr cipher = getCipher(config.cipher(), 8 * key.size()); - if(!config.salt().empty()) + if(!key.salt().empty()) { - int iterations = config.kdf_iterations(); + int iterations = key.kdf_iterations(); userKey = cipher->newKey( password, passwdLen, - iterations, config.kdf_duration(), - (const unsigned char *)config.salt().data(), config.salt().size()); + iterations, key.kdf_duration(), + (const unsigned char *)key.salt().data(), key.salt().size()); - if (iterations != config.kdf_iterations()) { + if (iterations != key.kdf_iterations()) { rError("Error in KDF, iteration mismatch"); return userKey; } @@ -1597,7 +1604,7 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) rDebug("cipher key size = %i", cipher->encodedKeySize()); // decode volume key.. CipherKey volumeKey = cipher->readKey( - (const unsigned char *)config.key().data(), userKey, opts->checkKey); + (const unsigned char *)config.key().ciphertext().data(), userKey, opts->checkKey); userKey.reset(); if(!volumeKey) diff --git a/encfs/config.proto b/encfs/config.proto index 3f975fa..eeaf6df 100644 --- a/encfs/config.proto +++ b/encfs/config.proto @@ -5,11 +5,7 @@ message EncfsConfig optional int32 revision = 2 [default=0]; required Interface cipher = 3; - required bytes key = 4; - optional bytes salt = 41; - required int32 key_size = 42; // in bits - optional int32 kdf_iterations = 43 [default=0]; - optional int32 kdf_duration = 44 [default=500]; + required EncryptedKey key = 4; optional Interface naming = 5; optional bool unique_iv = 51 [default=false]; @@ -22,6 +18,17 @@ message EncfsConfig optional bool allow_holes = 62 [default = false]; } +message EncryptedKey +{ + required bytes ciphertext = 1; + required int32 size = 2; // Size of data in bytes + + optional bytes salt = 6; + + optional int32 kdf_iterations = 10; + optional int32 kdf_duration = 11 [default=500]; +} + message Interface { required string name = 1; diff --git a/encfs/encfsctl.cpp b/encfs/encfsctl.cpp index 4cc2a37..6a5dd9f 100644 --- a/encfs/encfsctl.cpp +++ b/encfs/encfsctl.cpp @@ -726,7 +726,7 @@ static int do_chpasswd( bool useStdin, bool annotate, int argc, char **argv ) // decode volume key using user key -- at this point we detect an incorrect // password if the key checksum does not match (causing readKey to fail). CipherKey volumeKey = cipher->readKey( - (const unsigned char *)config.key().data(), userKey ); + (const unsigned char *)config.key().ciphertext().data(), userKey ); if(!volumeKey) { @@ -758,7 +758,8 @@ static int do_chpasswd( bool useStdin, bool annotate, int argc, char **argv ) cipher->writeKey( volumeKey, keyBuf, userKey ); userKey.reset(); - config.set_key( keyBuf, encodedKeySize ); + EncryptedKey *key = config.mutable_key(); + key->set_ciphertext( keyBuf, encodedKeySize ); delete[] keyBuf; if(saveConfig( rootDir, config )) diff --git a/encfs/test.cpp b/encfs/test.cpp index 3d0e6dc..dbdf2ab 100644 --- a/encfs/test.cpp +++ b/encfs/test.cpp @@ -238,9 +238,10 @@ bool runTests(const shared_ptr &cipher, bool verbose) // store in config struct.. EncfsConfig cfg; cfg.mutable_cipher()->MergeFrom(cipher->interface()); - cfg.set_key_size(8 * cipher->keySize()); + EncryptedKey *encryptedKey = cfg.mutable_key(); + encryptedKey->set_size(8 * cipher->keySize()); + encryptedKey->set_ciphertext( keyBuf, encodedKeySize ); cfg.set_block_size(FSBlockSize); - cfg.set_key( keyBuf, encodedKeySize ); // save config string data; @@ -252,12 +253,12 @@ bool runTests(const shared_ptr &cipher, bool verbose) // check.. rAssert( implements(cfg.cipher(),cfg2.cipher()) ); - rAssert( cfg.key_size() == cfg2.key_size() ); + rAssert( cfg.key().size() == cfg2.key().size() ); rAssert( cfg.block_size() == cfg2.block_size() ); // try decoding key.. - CipherKey key2 = cipher->readKey( (unsigned char *)cfg2.key().data(), encodingKey ); + CipherKey key2 = cipher->readKey( (unsigned char *)cfg2.key().ciphertext().data(), encodingKey ); if(!key2) { if(verbose) From 1680008df1d42217d7fb46b1c35f038da65a7ee7 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Wed, 22 Aug 2012 04:46:36 +0000 Subject: [PATCH 09/51] eliminate boost dependency, replace with C++11 features git-svn-id: http://encfs.googlecode.com/svn/trunk@86 db9cf616-1c43-0410-9cb8-a902689de0d6 --- ChangeLog | 13 ++ configure.ac | 4 +- encfs/BlockNameIO.cpp | 1 - encfs/BlockNameIO.h | 7 +- encfs/Cipher.cpp | 1 - encfs/Cipher.h | 8 +- encfs/CipherFileIO.cpp | 2 - encfs/CipherFileIO.h | 6 +- encfs/CipherKey.h | 4 +- encfs/ConfigVar.h | 4 +- encfs/Context.cpp | 2 +- encfs/Context.h | 21 ++-- encfs/DirNode.h | 16 +-- encfs/FSConfig.h | 16 +-- encfs/FileNode.cpp | 1 - encfs/FileNode.h | 1 - encfs/FileUtils.cpp | 35 ++---- encfs/FileUtils.h | 10 +- encfs/MACFileIO.cpp | 2 - encfs/MACFileIO.h | 2 - encfs/Makefile.am | 10 +- encfs/NameIO.h | 1 - encfs/NullCipher.cpp | 4 +- encfs/NullNameIO.cpp | 2 - encfs/SSL_Cipher.cpp | 3 - encfs/SSL_Cipher.h | 2 - encfs/StreamNameIO.h | 1 - encfs/XmlReader.cpp | 5 +- encfs/XmlReader.h | 6 +- encfs/boost-versioning.h | 96 --------------- encfs/encfs.cpp | 51 ++++---- encfs/encfsctl.cpp | 9 +- encfs/main.cpp | 9 +- encfs/shared_ptr.h | 38 ++++++ encfs/test.cpp | 13 +- m4/ax_boost_base.m4 | 223 ----------------------------------- m4/ax_boost_filesystem.m4 | 118 ------------------ m4/ax_boost_serialization.m4 | 117 ------------------ m4/ax_boost_system.m4 | 120 ------------------- 39 files changed, 149 insertions(+), 835 deletions(-) delete mode 100644 encfs/boost-versioning.h create mode 100644 encfs/shared_ptr.h delete mode 100644 m4/ax_boost_base.m4 delete mode 100644 m4/ax_boost_filesystem.m4 delete mode 100644 m4/ax_boost_serialization.m4 delete mode 100644 m4/ax_boost_system.m4 diff --git a/ChangeLog b/ChangeLog index 01fa5d5..cb778bc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +Tue Aug 21 2012 Valient Gough + * replace boost with C++11 + +Sun Aug 19 2012 Valient Gough + * move encrypted key into separate config block + +Sat Aug 18 2012 Valient Gough + * add V to getopt for version + +Sun May 13 2012 Valient Gough + * allow "config" for top-level v6 xml config + * drop logging of useStdin state + Wed Apr 25 2012 Valient Gough * fix encfsctl cat when iv chaining is enabled. Fixes issue #132 diff --git a/configure.ac b/configure.ac index 0a1d3e5..e9438e3 100644 --- a/configure.ac +++ b/configure.ac @@ -46,9 +46,7 @@ AC_PROG_LIBTOOL AX_PTHREAD -AX_BOOST_BASE([1.34]) -AX_BOOST_SYSTEM -AX_BOOST_FILESYSTEM +AC_CHECK_HEADERS([tr1/memory tr1/unordered_map tr1/unordered_set tr1/tuple]) dnl Need to include any user specified flags in the tests below, as they might dnl specify required include directories.. diff --git a/encfs/BlockNameIO.cpp b/encfs/BlockNameIO.cpp index 34366a3..9faa662 100644 --- a/encfs/BlockNameIO.cpp +++ b/encfs/BlockNameIO.cpp @@ -31,7 +31,6 @@ #include "i18n.h" using namespace rlog; -using namespace boost; static RLogChannel * Info = DEF_CHANNEL( "info/nameio", Log_Info ); diff --git a/encfs/BlockNameIO.h b/encfs/BlockNameIO.h index a2a0f5f..7bc4514 100644 --- a/encfs/BlockNameIO.h +++ b/encfs/BlockNameIO.h @@ -21,7 +21,7 @@ #include "NameIO.h" #include "CipherKey.h" -#include +#include class Cipher; @@ -36,7 +36,7 @@ public: static Interface CurrentInterface(bool caseSensitive = false); BlockNameIO( const Interface &iface, - const boost::shared_ptr &cipher, + const shared_ptr &cipher, const CipherKey &key, int blockSize, bool caseSensitiveEncoding = false ); virtual ~BlockNameIO(); @@ -57,11 +57,10 @@ protected: private: int _interface; int _bs; - boost::shared_ptr _cipher; + shared_ptr _cipher; CipherKey _key; bool _caseSensitive; }; - #endif diff --git a/encfs/Cipher.cpp b/encfs/Cipher.cpp index 1c1047c..211f653 100644 --- a/encfs/Cipher.cpp +++ b/encfs/Cipher.cpp @@ -34,7 +34,6 @@ #include "SSL_Cipher.h" using namespace std; -using boost::shared_ptr; #define REF_MODULE(TYPE) \ if( !TYPE::Enabled() ) \ diff --git a/encfs/Cipher.h b/encfs/Cipher.h index 87efd5b..bfb209d 100644 --- a/encfs/Cipher.h +++ b/encfs/Cipher.h @@ -29,8 +29,6 @@ #include #include -using boost::shared_ptr; - /* Mostly pure virtual interface defining operations on a cipher. @@ -42,7 +40,7 @@ class Cipher public: // if no key length was indicated when cipher was registered, then keyLen // <= 0 will be used. - typedef boost::shared_ptr (*CipherConstructor)( + typedef shared_ptr (*CipherConstructor)( const Interface &iface, int keyLenBits ); struct CipherAlgorithm @@ -59,9 +57,9 @@ public: static AlgorithmList GetAlgorithmList( bool includeHidden = false ); - static boost::shared_ptr New( const Interface &iface, + static shared_ptr New( const Interface &iface, int keyLen = -1); - static boost::shared_ptr New( const std::string &cipherName, + static shared_ptr New( const std::string &cipherName, int keyLen = -1 ); diff --git a/encfs/CipherFileIO.cpp b/encfs/CipherFileIO.cpp index d7af35b..fb2b4ca 100644 --- a/encfs/CipherFileIO.cpp +++ b/encfs/CipherFileIO.cpp @@ -27,8 +27,6 @@ #include #include -using boost::shared_ptr; - /* - Version 2:0 adds support for a per-file initialization vector with a fixed 8 byte header. The headers are enabled globally within a diff --git a/encfs/CipherFileIO.h b/encfs/CipherFileIO.h index d4b4c1b..79535e4 100644 --- a/encfs/CipherFileIO.h +++ b/encfs/CipherFileIO.h @@ -34,7 +34,7 @@ class Cipher; class CipherFileIO : public BlockFileIO { public: - CipherFileIO( const boost::shared_ptr &base, + CipherFileIO( const shared_ptr &base, const FSConfigPtr &cfg); virtual ~CipherFileIO(); @@ -68,7 +68,7 @@ private: bool streamWrite( unsigned char *buf, int size, uint64_t iv64 ) const; - boost::shared_ptr base; + shared_ptr base; FSConfigPtr fsConfig; @@ -80,7 +80,7 @@ private: uint64_t fileIV; int lastFlags; - boost::shared_ptr cipher; + shared_ptr cipher; CipherKey key; }; diff --git a/encfs/CipherKey.h b/encfs/CipherKey.h index 9c88cd7..1935d3c 100644 --- a/encfs/CipherKey.h +++ b/encfs/CipherKey.h @@ -21,7 +21,7 @@ #ifndef _CipherKey_incl_ #define _CipherKey_incl_ -#include +#include "shared_ptr.h" class AbstractCipherKey { @@ -30,7 +30,7 @@ public: virtual ~AbstractCipherKey(); }; -typedef boost::shared_ptr CipherKey; +typedef shared_ptr CipherKey; #endif diff --git a/encfs/ConfigVar.h b/encfs/ConfigVar.h index 0c8ca04..5bf903f 100644 --- a/encfs/ConfigVar.h +++ b/encfs/ConfigVar.h @@ -19,9 +19,7 @@ #define _ConfigVar_incl_ #include -#include - -using boost::shared_ptr; +#include "shared_ptr.h" class ConfigVar { diff --git a/encfs/Context.cpp b/encfs/Context.cpp index 3ab8435..c7ef5c2 100644 --- a/encfs/Context.cpp +++ b/encfs/Context.cpp @@ -140,7 +140,7 @@ shared_ptr EncFS_Context::getNode(void *pl) } void *EncFS_Context::putNode(const char *path, - const boost::shared_ptr &node) + const shared_ptr &node) { Lock lock( contextMutex ); Placeholder *pl = new Placeholder( node ); diff --git a/encfs/Context.h b/encfs/Context.h index 5628bd2..0b810da 100644 --- a/encfs/Context.h +++ b/encfs/Context.h @@ -19,16 +19,17 @@ #define _Context_incl_ #include "encfs.h" -#include +#include "shared_ptr.h" #include -#ifdef USE_HASHMAP -#include +#if HAVE_TR1_UNORDERED_MAP +#include +using std::tr1::unordered_map; #else -#include +#include +using std::unordered_map; #endif -using boost::shared_ptr; struct EncFS_Args; struct EncFS_Opts; class FileNode; @@ -87,15 +88,9 @@ private: }; // set of open files, indexed by path -#ifdef USE_HASHMAP - typedef __gnu_cxx::hash_map > FileMap; -#else - typedef std::map< std::string, - std::set > FileMap; -#endif - + typedef unordered_map > FileMap; mutable pthread_mutex_t contextMutex; + FileMap openFiles; int usageCount; diff --git a/encfs/DirNode.h b/encfs/DirNode.h index f075a8a..34240be 100644 --- a/encfs/DirNode.h +++ b/encfs/DirNode.h @@ -31,8 +31,7 @@ #include "NameIO.h" #include "CipherKey.h" #include "FSConfig.h" - -using boost::shared_ptr; +#include "shared_ptr.h" class Cipher; class RenameOp; @@ -72,19 +71,6 @@ private: }; inline bool DirTraverse::valid() const { return dir != 0; } -#ifdef USE_HASHMAP -namespace __gnu_cxx -{ - template<> struct hash - { - size_t operator() (const std::string &__s) const - { - return __stl_hash_string( __s.c_str() ); - } - }; -} -#endif - class DirNode { public: diff --git a/encfs/FSConfig.h b/encfs/FSConfig.h index 32bc329..0ac02e4 100644 --- a/encfs/FSConfig.h +++ b/encfs/FSConfig.h @@ -24,9 +24,9 @@ #include "encfs.h" #include "Interface.h" #include "CipherKey.h" +#include "shared_ptr.h" #include -#include enum ConfigType { @@ -52,8 +52,8 @@ CipherKey getUserKey(const EncfsConfig &config, CipherKey getNewUserKey(EncfsConfig &config, bool useStdin, const std::string &program, const std::string &rootDir); -boost::shared_ptr getCipher(const EncfsConfig &cfg); -boost::shared_ptr getCipher(const Interface &iface, int keySize); +shared_ptr getCipher(const EncfsConfig &cfg); +shared_ptr getCipher(const Interface &iface, int keySize); // helpers for serializing to/from a stream std::ostream &operator << (std::ostream &os, const EncfsConfig &cfg); @@ -62,12 +62,12 @@ std::istream &operator >> (std::istream &os, EncfsConfig &cfg); // Filesystem state struct FSConfig { - boost::shared_ptr config; - boost::shared_ptr opts; + shared_ptr config; + shared_ptr opts; - boost::shared_ptr cipher; + shared_ptr cipher; CipherKey key; - boost::shared_ptr nameCoding; + shared_ptr nameCoding; bool forceDecode; // force decode on MAC block failures bool reverseEncryption; // reverse encryption operation @@ -75,7 +75,7 @@ struct FSConfig bool idleTracking; // turn on idle monitoring of filesystem }; -typedef boost::shared_ptr FSConfigPtr; +typedef shared_ptr FSConfigPtr; #endif diff --git a/encfs/FileNode.cpp b/encfs/FileNode.cpp index 2671a60..5e73190 100644 --- a/encfs/FileNode.cpp +++ b/encfs/FileNode.cpp @@ -50,7 +50,6 @@ using namespace std; using namespace rel; using namespace rlog; -using boost::dynamic_pointer_cast; /* TODO: locking at the FileNode level is inefficient, since this precludes diff --git a/encfs/FileNode.h b/encfs/FileNode.h index 6ad954a..df8caec 100644 --- a/encfs/FileNode.h +++ b/encfs/FileNode.h @@ -29,7 +29,6 @@ class Cipher; class FileIO; class DirNode; -using boost::shared_ptr; class FileNode { diff --git a/encfs/FileUtils.cpp b/encfs/FileUtils.cpp index 436d1f6..10cee18 100644 --- a/encfs/FileUtils.cpp +++ b/encfs/FileUtils.cpp @@ -61,9 +61,6 @@ #include "i18n.h" -#include -#include - #include #include @@ -74,7 +71,6 @@ using namespace rlog; using namespace std; using namespace gnu; -namespace fs = boost::filesystem; static const int DefaultBlockSize = 1024; // The maximum length of text passwords. If longer are needed, @@ -90,17 +86,8 @@ static const char ENCFS_ENV_ROOTDIR[] = "encfs_root"; static const char ENCFS_ENV_STDOUT[] = "encfs_stdout"; static const char ENCFS_ENV_STDERR[] = "encfs_stderr"; - -//static int V5SubVersion = 20040518; -//static int V5SubVersion = 20040621; // add external IV chaining -static int V5SubVersion = 20040813; // fix MACFileIO block size issues - -// 20080813 was really made on 20080413 -- typo on date.. -//const int V6SubVersion = 20080813; // switch to v6/XML, add allowHoles option -//const int V6SubVersion = 20080816; // add salt and iteration count -const int V6SubVersion = 20100713; // add version field for boost 1.42+ - -const int ProtoSubVersion = 20120302; +const int V5Latest = 20040813; // fix MACFileIO block size issues +const int ProtoSubVersion = 20120819; const char ConfigFileName[] = ".encfs.txt"; @@ -116,7 +103,7 @@ struct ConfigInfo {Config_V6, ".encfs6.xml", "ENCFS6_CONFIG", readV6Config }, // backward compatible support for older versions {Config_V5, ".encfs5", "ENCFS5_CONFIG", readV5Config }, - {Config_V3, ".encfs4", NULL, readV4Config }, + {Config_V4, ".encfs4", NULL, readV4Config }, // prehistoric - no longer support {Config_V3, ".encfs3", NULL, NULL }, {Config_Prehistoric, ".encfs2", NULL, NULL }, @@ -310,7 +297,7 @@ bool readV6Config( const char *configFile, { rInfo("found 20080813"); cfg.set_revision(20080813); - } else if (version < V5SubVersion) + } else if (version < V5Latest) { rError("Invalid version %i - please fix config file", version); } else @@ -393,16 +380,16 @@ bool readV5Config( const char *configFile, try { config.set_revision(cfgRdr["subVersion"].readInt(0)); - if(config.revision() > V5SubVersion) + if(config.revision() > V5Latest) { /* config file specifies a version outside our supported range.. */ rWarning(_("Config subversion %i found, but this version of" " encfs only supports up to version %i."), - config.revision(), V5SubVersion); + config.revision(), V5Latest); return false; } - if( config.revision() < 20040813 ) + if( config.revision() < V5Latest ) { rError(_("This version of EncFS doesn't support " "filesystems created before 2004-08-13")); @@ -1053,7 +1040,7 @@ RootPtr createConfig( EncFS_Context *ctx, config.set_block_size( blockSize ); config.mutable_naming()->MergeFrom( nameIOIface ); config.set_creator( "EncFS " VERSION ); - config.set_revision( V6SubVersion ); + config.set_revision( ProtoSubVersion ); config.set_block_mac_bytes( blockMACBytes ); config.set_block_mac_rand_bytes( blockMACRandBytes ); config.set_unique_iv( uniqueIV ); @@ -1142,7 +1129,7 @@ RootPtr createConfig( EncFS_Context *ctx, fsConfig->cipher = cipher; fsConfig->key = volumeKey; fsConfig->nameCoding = nameCoder; - fsConfig->config = boost::shared_ptr(new EncfsConfig(config)); + fsConfig->config = shared_ptr(new EncfsConfig(config)); fsConfig->forceDecode = forceDecode; fsConfig->reverseEncryption = reverseEncryption; fsConfig->idleTracking = enableIdleTracking; @@ -1227,7 +1214,7 @@ void showFSInfo( const EncfsConfig &config ) } if(config.block_mac_bytes() || config.block_mac_rand_bytes()) { - if(config.revision() < 20040813) + if(config.revision() < V5Latest) { cout << autosprintf( // xgroup(diag) @@ -1636,7 +1623,7 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) fsConfig->cipher = cipher; fsConfig->key = volumeKey; fsConfig->nameCoding = nameCoder; - fsConfig->config = boost::shared_ptr(new EncfsConfig(config)); + fsConfig->config = shared_ptr(new EncfsConfig(config)); fsConfig->forceDecode = opts->forceDecode; fsConfig->reverseEncryption = opts->reverseEncryption; fsConfig->opts = opts; diff --git a/encfs/FileUtils.h b/encfs/FileUtils.h index c20fbab..483ae3f 100644 --- a/encfs/FileUtils.h +++ b/encfs/FileUtils.h @@ -44,15 +44,15 @@ class DirNode; struct EncFS_Root { - boost::shared_ptr cipher; + shared_ptr cipher; CipherKey volumeKey; - boost::shared_ptr root; + shared_ptr root; EncFS_Root(); ~EncFS_Root(); }; -typedef boost::shared_ptr RootPtr; +typedef shared_ptr RootPtr; enum ConfigMode { @@ -109,10 +109,10 @@ bool saveConfig( const std::string &rootdir, const EncfsConfig &config ); class EncFS_Context; -RootPtr initFS( EncFS_Context *ctx, const boost::shared_ptr &opts ); +RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ); RootPtr createConfig( EncFS_Context *ctx, - const boost::shared_ptr &opts ); + const shared_ptr &opts ); void showFSInfo( const EncfsConfig &config ); diff --git a/encfs/MACFileIO.cpp b/encfs/MACFileIO.cpp index ac69ccc..4d6898c 100644 --- a/encfs/MACFileIO.cpp +++ b/encfs/MACFileIO.cpp @@ -31,8 +31,6 @@ using namespace rlog; using namespace std; -using boost::shared_ptr; -using boost::dynamic_pointer_cast; static RLogChannel *Info = DEF_CHANNEL("info/MACFileIO", Log_Info); // diff --git a/encfs/MACFileIO.h b/encfs/MACFileIO.h index 4b6aac5..e8b4262 100644 --- a/encfs/MACFileIO.h +++ b/encfs/MACFileIO.h @@ -21,8 +21,6 @@ #include "BlockFileIO.h" #include "Cipher.h" -using boost::shared_ptr; - class MACFileIO : public BlockFileIO { public: diff --git a/encfs/Makefile.am b/encfs/Makefile.am index ba7c6c8..c2cd157 100644 --- a/encfs/Makefile.am +++ b/encfs/Makefile.am @@ -1,10 +1,9 @@ include $(top_srcdir)/Makefile.common -ALL_INCLUDES = @RLOG_CFLAGS@ @OPENSSL_CFLAGS@ @BOOST_CPPFLAGS@ +ALL_INCLUDES = @RLOG_CFLAGS@ @OPENSSL_CFLAGS@ ALL_INCLUDES += @PROTOBUF_CFLAGS@ -ALL_LDFLAGS = @RLOG_LIBS@ @OPENSSL_LIBS@ @BOOST_LDFLAGS@ -ALL_LDFLAGS += @BOOST_FILESYSTEM_LIB@ @BOOST_SYSTEM_LIB@ +ALL_LDFLAGS = @RLOG_LIBS@ @OPENSSL_LIBS@ ALL_LDFLAGS += @PROTOBUF_LIBS@ INCLUDES = $(all_includes) -I../intl @@ -50,9 +49,7 @@ endif # : +1 : => internal changes, nothing breaks # libencfs_la_LDFLAGS = -version-info 7:0:0 -libencfs_la_LIBADD = @RLOG_LIBS@ \ - @OPENSSL_LIBS@ \ - @BOOST_FILESYSTEM_LIB@ @BOOST_SYSTEM_LIB@ +libencfs_la_LIBADD = @RLOG_LIBS@ @OPENSSL_LIBS@ EXTRASRC = ../intl/autosprintf.cpp if BUILD_OPENSSL @@ -105,7 +102,6 @@ encfsctl_SOURCES = \ noinst_HEADERS = \ base64.h \ - boost-versioning.h \ BlockFileIO.h \ BlockNameIO.h \ CipherFileIO.h \ diff --git a/encfs/NameIO.h b/encfs/NameIO.h index 93f48a1..603d257 100644 --- a/encfs/NameIO.h +++ b/encfs/NameIO.h @@ -26,7 +26,6 @@ #include "Interface.h" #include "CipherKey.h" -using boost::shared_ptr; class Cipher; class NameIO diff --git a/encfs/NullCipher.cpp b/encfs/NullCipher.cpp index f70e077..18daff4 100644 --- a/encfs/NullCipher.cpp +++ b/encfs/NullCipher.cpp @@ -19,16 +19,14 @@ #include "Range.h" #include "Interface.h" +#include "shared_ptr.h" -#include #include #include using namespace std; using namespace rlog; -using boost::shared_ptr; -using boost::dynamic_pointer_cast; static Interface NullInterface = makeInterface( "nullCipher", 1, 0, 0 ); diff --git a/encfs/NullNameIO.cpp b/encfs/NullNameIO.cpp index 8792e37..65733a9 100644 --- a/encfs/NullNameIO.cpp +++ b/encfs/NullNameIO.cpp @@ -22,8 +22,6 @@ #include -using boost::shared_ptr; - static shared_ptr NewNNIO( const Interface &, const shared_ptr &, const CipherKey & ) { diff --git a/encfs/SSL_Cipher.cpp b/encfs/SSL_Cipher.cpp index 98d5b27..3e00899 100644 --- a/encfs/SSL_Cipher.cpp +++ b/encfs/SSL_Cipher.cpp @@ -46,9 +46,6 @@ using namespace std; using namespace rel; using namespace rlog; -using boost::shared_ptr; -using boost::dynamic_pointer_cast; - const int MAX_KEYLENGTH = 32; // in bytes (256 bit) const int MAX_IVLENGTH = 16; const int KEY_CHECKSUM_BYTES = 4; diff --git a/encfs/SSL_Cipher.h b/encfs/SSL_Cipher.h index 5ea7f72..fd2a76f 100644 --- a/encfs/SSL_Cipher.h +++ b/encfs/SSL_Cipher.h @@ -28,8 +28,6 @@ struct evp_cipher_st; typedef struct evp_cipher_st EVP_CIPHER; #endif -using boost::shared_ptr; - /* Implements Cipher interface for OpenSSL's ciphers. diff --git a/encfs/StreamNameIO.h b/encfs/StreamNameIO.h index 2940ff3..3983db0 100644 --- a/encfs/StreamNameIO.h +++ b/encfs/StreamNameIO.h @@ -22,7 +22,6 @@ #include "CipherKey.h" class Cipher; -using boost::shared_ptr; class StreamNameIO : public NameIO { diff --git a/encfs/XmlReader.cpp b/encfs/XmlReader.cpp index f5b54a9..c318d95 100644 --- a/encfs/XmlReader.cpp +++ b/encfs/XmlReader.cpp @@ -27,8 +27,9 @@ #include #include #include -#include +#include +#include #include #include @@ -151,7 +152,7 @@ public: struct XmlReader::XmlReaderData { - boost::shared_ptr doc; + shared_ptr doc; }; XmlReader::XmlReader() diff --git a/encfs/XmlReader.h b/encfs/XmlReader.h index e538a66..497fc1e 100644 --- a/encfs/XmlReader.h +++ b/encfs/XmlReader.h @@ -21,11 +21,11 @@ #ifndef _XmlReader_incl_ #define _XmlReader_incl_ -#include #include +#include "shared_ptr.h" class XmlValue; -typedef boost::shared_ptr XmlValuePtr; +typedef shared_ptr XmlValuePtr; class XmlValue { @@ -72,7 +72,7 @@ public: private: struct XmlReaderData; - boost::shared_ptr pd; + shared_ptr pd; }; #endif diff --git a/encfs/boost-versioning.h b/encfs/boost-versioning.h deleted file mode 100644 index b3cfa51..0000000 --- a/encfs/boost-versioning.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef BOOST_VERSIONING_INCL -#define BOOST_VERSIONING_INCL - -// This header stores workaround code for dealing with incompatible changes -// made to boost archive/serialization classes. - - -#if (BOOST_VERSION <= 104100) -// Easy case, boost archive serial numbers are sizeof(int) -BOOST_CLASS_VERSION(EncFSConfig, V6SubVersion) -#else -// starting with boost 1.42, serial numbers change to 8-bit. However to make -// things tricker, the internal comparison is more like 16bit, which makes -// writing backward compatible code very tricky. - -// We make a partial specialization of the iserializer class to remove the -// version number checking which would otherwise cause boost::serialization to -// throw an exception if it came across a version that was greater then what -// we specify in BOOST_CLASS_VERSION below. Without this, manual editing -// of the file is needed before boost will allow us to read it. - -// See bug http://code.google.com/p/encfs/issues/detail?id=60 - -BOOST_CLASS_VERSION(EncFSConfig, 20) - - -namespace boost { -namespace archive { -namespace detail { - - -// Specialize iserializer class in order to get rid of version check -template -class iserializer : public basic_iserializer -{ -private: - virtual void destroy(/*const*/ void *address) const { - boost::serialization::access::destroy(static_cast(address)); - } -protected: - explicit iserializer() : - basic_iserializer( - boost::serialization::singleton< - BOOST_DEDUCED_TYPENAME - boost::serialization::type_info_implementation::type - >::get_const_instance() - ) - {} -public: - virtual BOOST_DLLEXPORT void load_object_data( - basic_iarchive & ar, - void *x, - const unsigned int file_version - ) const BOOST_USED; - virtual bool class_info() const { - return boost::serialization::implementation_level::value - >= boost::serialization::object_class_info; - } - virtual bool tracking(const unsigned int /* flags */) const { - return boost::serialization::tracking_level::value - == boost::serialization::track_always - || ( boost::serialization::tracking_level::value - == boost::serialization::track_selectively - && serialized_as_pointer()); - } - virtual version_type version() const { - return version_type(::boost::serialization::version::value); - } - virtual bool is_polymorphic() const { - return boost::is_polymorphic::value; - } - virtual ~iserializer(){}; -}; - -template -BOOST_DLLEXPORT void iserializer::load_object_data( - basic_iarchive & ar, - void *x, - const unsigned int file_version -) const { - boost::serialization::serialize_adl( - boost::serialization::smart_cast_reference(ar), - * static_cast(x), - file_version - ); -} - -} -} -} - -#endif - - - -#endif // BOOST_VERSIONING_INCL diff --git a/encfs/encfs.cpp b/encfs/encfs.cpp index dac15bd..69f3dd7 100644 --- a/encfs/encfs.cpp +++ b/encfs/encfs.cpp @@ -41,14 +41,21 @@ #include #include -#include -#include +#if HAVE_TR1_TUPLE +#include +using namespace std; +using namespace std::tr1; +#else +#include +using namespace std; +#endif #include "DirNode.h" #include "MemoryPool.h" #include "FileUtils.h" #include "Mutex.h" #include "Context.h" +#include "shared_ptr.h" #include #include @@ -59,10 +66,8 @@ #define ESUCCESS 0 -using namespace std; using namespace rlog; using rel::Lock; -using namespace boost; #define GET_FN(ctx, finfo) ctx->getNode((void*)(uintptr_t)finfo->fh) @@ -165,16 +170,16 @@ int _do_getattr(FileNode *fnode, struct stat *stbuf) if(FSRoot) { // determine plaintext link size.. Easiest to read and decrypt.. - scoped_array buf(new char[stbuf->st_size+1]); + vector buf(stbuf->st_size+1, 0); - res = ::readlink( fnode->cipherName(), buf.get(), stbuf->st_size ); + res = ::readlink( fnode->cipherName(), &buf[0], stbuf->st_size ); if(res >= 0) { // other functions expect c-strings to be null-terminated, which // readlink doesn't provide buf[res] = '\0'; - stbuf->st_size = FSRoot->plainPath( buf.get() ).length(); + stbuf->st_size = FSRoot->plainPath( &buf[0] ).length(); res = ESUCCESS; } else @@ -363,8 +368,8 @@ int encfs_rmdir(const char *path) int _do_readlink(EncFS_Context *ctx, const string &cyName, tuple data ) { - char *buf = data.get<0>(); - size_t size = data.get<1>(); + char *buf = get<0>(data); + size_t size = get<1>(data); int res = ESUCCESS; shared_ptr FSRoot = ctx->getRoot(&res); @@ -500,7 +505,7 @@ int encfs_chmod(const char *path, mode_t mode) int _do_chown(EncFS_Context *, const string &cyName, tuple data) { - int res = lchown( cyName.c_str(), data.get<0>(), data.get<1>() ); + int res = lchown( cyName.c_str(), get<0>(data), get<1>(data) ); return (res == -1) ? -errno : ESUCCESS; } @@ -633,7 +638,7 @@ int encfs_release(const char *path, struct fuse_file_info *finfo) int _do_read(FileNode *fnode, tuple data) { - return fnode->read( data.get<2>(), data.get<0>(), data.get<1>()); + return fnode->read( get<2>(data), get<0>(data), get<1>(data)); } int encfs_read(const char *path, char *buf, size_t size, off_t offset, @@ -656,8 +661,8 @@ int encfs_fsync(const char *path, int dataSync, int _do_write(FileNode *fnode, tuple data) { - size_t size = data.get<1>(); - if(fnode->write( data.get<2>(), (unsigned char *)data.get<0>(), size )) + size_t size = get<1>(data); + if(fnode->write( get<2>(data), (unsigned char *)get<0>(data), size )) return size; else return -EIO; @@ -707,8 +712,8 @@ int _do_setxattr(EncFS_Context *, const string &cyName, tuple data) { int options = 0; - return ::setxattr( cyName.c_str(), data.get<0>(), data.get<1>(), - data.get<2>(), data.get<3>(), options ); + return ::setxattr( cyName.c_str(), get<0>(data), get<1>(data), + get<2>(data), get<3>(data), options ); } int encfs_setxattr( const char *path, const char *name, const char *value, size_t size, int flags, uint32_t position ) @@ -721,8 +726,8 @@ int encfs_setxattr( const char *path, const char *name, int _do_setxattr(EncFS_Context *, const string &cyName, tuple data) { - return ::setxattr( cyName.c_str(), data.get<0>(), data.get<1>(), - data.get<2>(), data.get<3>() ); + return ::setxattr( cyName.c_str(), get<0>(data), get<1>(data), + get<2>(data), get<3>(data) ); } int encfs_setxattr( const char *path, const char *name, const char *value, size_t size, int flags ) @@ -738,8 +743,8 @@ int _do_getxattr(EncFS_Context *, const string &cyName, tuple data) { int options = 0; - return ::getxattr( cyName.c_str(), data.get<0>(), - data.get<1>(), data.get<2>(), data.get<3>(), options ); + return ::getxattr( cyName.c_str(), get<0>(data), + get<1>(data), get<2>(data), get<3>(data), options ); } int encfs_getxattr( const char *path, const char *name, char *value, size_t size, uint32_t position ) @@ -751,8 +756,8 @@ int encfs_getxattr( const char *path, const char *name, int _do_getxattr(EncFS_Context *, const string &cyName, tuple data) { - return ::getxattr( cyName.c_str(), data.get<0>(), - data.get<1>(), data.get<2>()); + return ::getxattr( cyName.c_str(), get<0>(data), + get<1>(data), get<2>(data)); } int encfs_getxattr( const char *path, const char *name, char *value, size_t size ) @@ -768,10 +773,10 @@ int _do_listxattr(EncFS_Context *, const string &cyName, { #ifdef XATTR_ADD_OPT int options = 0; - int res = ::listxattr( cyName.c_str(), data.get<0>(), data.get<1>(), + int res = ::listxattr( cyName.c_str(), get<0>(data), get<1>(data), options ); #else - int res = ::listxattr( cyName.c_str(), data.get<0>(), data.get<1>() ); + int res = ::listxattr( cyName.c_str(), get<0>(data), get<1>(data) ); #endif return (res == -1) ? -errno : res; } diff --git a/encfs/encfsctl.cpp b/encfs/encfsctl.cpp index 6a5dd9f..c208769 100644 --- a/encfs/encfsctl.cpp +++ b/encfs/encfsctl.cpp @@ -45,8 +45,6 @@ #include "i18n.h" -#include - #ifdef HAVE_SSL #define NO_DES #include @@ -55,7 +53,6 @@ using namespace rlog; using namespace std; using namespace gnu; -using namespace boost; static int showInfo( int argc, char **argv ); @@ -472,8 +469,8 @@ static int copyLink(const struct stat &stBuf, const shared_ptr &rootInfo, const string &cpath, const string &destName ) { - scoped_array buf(new char[stBuf.st_size+1]); - int res = ::readlink( cpath.c_str(), buf.get(), stBuf.st_size ); + vector buf(stBuf.st_size+1, 0); + int res = ::readlink( cpath.c_str(), &buf[0], stBuf.st_size ); if(res == -1) { cerr << "unable to readlink of " << cpath << "\n"; @@ -481,7 +478,7 @@ static int copyLink(const struct stat &stBuf, } buf[res] = '\0'; - string decodedLink = rootInfo->root->plainPath(buf.get()); + string decodedLink = rootInfo->root->plainPath(&buf[0]); res = ::symlink( decodedLink.c_str(), destName.c_str() ); if(res == -1) diff --git a/encfs/main.cpp b/encfs/main.cpp index d20d00a..66911ca 100644 --- a/encfs/main.cpp +++ b/encfs/main.cpp @@ -33,9 +33,6 @@ #include -#include -#include - #include #include #include @@ -70,8 +67,6 @@ inline static int MAX(int a, int b) using namespace std; using namespace rlog; using namespace gnu; -using boost::shared_ptr; -using boost::scoped_ptr; // Maximum number of arguments that we're going to pass on to fuse. Doesn't // affect how many arguments we can handle, just how many we can pass on.. @@ -501,8 +496,8 @@ int main(int argc, char *argv[]) #endif // log to stderr by default.. - scoped_ptr slog( new StdioNode( STDERR_FILENO ) ); - scoped_ptr logNode; + shared_ptr slog( new StdioNode( STDERR_FILENO ) ); + shared_ptr logNode; // show error and warning output slog->subscribeTo( GetGlobalChannel("error") ); diff --git a/encfs/shared_ptr.h b/encfs/shared_ptr.h new file mode 100644 index 0000000..fd4fa8f --- /dev/null +++ b/encfs/shared_ptr.h @@ -0,0 +1,38 @@ + +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2012 Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef _SHARED_PTR_incl_ +#define _SHARED_PTR_incl_ + +#include "config.h" + +#ifdef HAVE_TR1_MEMORY + #include + using std::tr1::shared_ptr; + using std::tr1::dynamic_pointer_cast; +#else + #include + using std::shared_ptr; + using std::dynamic_pointer_cast; +#endif + +#endif + diff --git a/encfs/test.cpp b/encfs/test.cpp index dbdf2ab..66ca7a0 100644 --- a/encfs/test.cpp +++ b/encfs/test.cpp @@ -20,8 +20,8 @@ #include "config.h" +#include #include - #include #include @@ -49,14 +49,17 @@ #include +#if HAVE_TR1_UNORDERED_SET #include - +using std::tr1::unordered_set; +#else +#include +using std::unordered_set; +#endif using namespace std; using namespace rlog; -using boost::shared_ptr; - const int FSBlockSize = 256; static @@ -171,7 +174,7 @@ bool testNameCoding( DirNode &dirNode, bool verbose, cerr << "Checking for name collections, this will take a while..\n"; // check for collision rate char buf[64]; - tr1::unordered_set encryptedNames; + unordered_set encryptedNames; for (long i=0; i < 10000000; i++) { snprintf(buf, sizeof(buf), "%li", i); diff --git a/m4/ax_boost_base.m4 b/m4/ax_boost_base.m4 deleted file mode 100644 index 2e5afd0..0000000 --- a/m4/ax_boost_base.m4 +++ /dev/null @@ -1,223 +0,0 @@ -# =========================================================================== -# http://autoconf-archive.cryp.to/ax_boost_base.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_BOOST_BASE([MINIMUM-VERSION]) -# -# DESCRIPTION -# -# Test for the Boost C++ libraries of a particular version (or newer) -# -# If no path to the installed boost library is given the macro searchs -# under /usr, /usr/local, /opt and /opt/local and evaluates the -# $BOOST_ROOT environment variable. Further documentation is available at -# . -# -# This macro calls: -# -# AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS) -# -# And sets: -# -# HAVE_BOOST -# -# LAST MODIFICATION -# -# 2008-04-12 -# -# COPYLEFT -# -# Copyright (c) 2008 Thomas Porschberg -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. - -AC_DEFUN([AX_BOOST_BASE], -[ -AC_ARG_WITH([boost], - AS_HELP_STRING([--with-boost@<:@=DIR@:>@], [use boost (default is yes) - it is possible to specify the root directory for boost (optional)]), - [ - if test "$withval" = "no"; then - want_boost="no" - elif test "$withval" = "yes"; then - want_boost="yes" - ac_boost_path="" - else - want_boost="yes" - ac_boost_path="$withval" - fi - ], - [want_boost="yes"]) - - -AC_ARG_WITH([boost-libdir], - AS_HELP_STRING([--with-boost-libdir=LIB_DIR], - [Force given directory for boost libraries. Note that this will overwrite library path detection, so use this parameter only if default library detection fails and you know exactly where your boost libraries are located.]), - [ - if test -d $withval - then - ac_boost_lib_path="$withval" - else - AC_MSG_ERROR(--with-boost-libdir expected directory name) - fi - ], - [ac_boost_lib_path=""] -) - -if test "x$want_boost" = "xyes"; then - boost_lib_version_req=ifelse([$1], ,1.20.0,$1) - boost_lib_version_req_shorten=`expr $boost_lib_version_req : '\([[0-9]]*\.[[0-9]]*\)'` - boost_lib_version_req_major=`expr $boost_lib_version_req : '\([[0-9]]*\)'` - boost_lib_version_req_minor=`expr $boost_lib_version_req : '[[0-9]]*\.\([[0-9]]*\)'` - boost_lib_version_req_sub_minor=`expr $boost_lib_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` - if test "x$boost_lib_version_req_sub_minor" = "x" ; then - boost_lib_version_req_sub_minor="0" - fi - WANT_BOOST_VERSION=`expr $boost_lib_version_req_major \* 100000 \+ $boost_lib_version_req_minor \* 100 \+ $boost_lib_version_req_sub_minor` - AC_MSG_CHECKING(for boostlib >= $boost_lib_version_req) - succeeded=no - - dnl first we check the system location for boost libraries - dnl this location ist chosen if boost libraries are installed with the --layout=system option - dnl or if you install boost with RPM - if test "$ac_boost_path" != ""; then - BOOST_LDFLAGS="-L$ac_boost_path/lib" - BOOST_CPPFLAGS="-I$ac_boost_path/include" - else - for ac_boost_path_tmp in /usr /usr/local /opt /opt/local ; do - if test -d "$ac_boost_path_tmp/include/boost" && test -r "$ac_boost_path_tmp/include/boost"; then - BOOST_LDFLAGS="-L$ac_boost_path_tmp/lib" - BOOST_CPPFLAGS="-I$ac_boost_path_tmp/include" - break; - fi - done - fi - - dnl overwrite ld flags if we have required special directory with - dnl --with-boost-libdir parameter - if test "$ac_boost_lib_path" != ""; then - BOOST_LDFLAGS="-L$ac_boost_lib_path" - fi - - CPPFLAGS_SAVED="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" - export CPPFLAGS - - LDFLAGS_SAVED="$LDFLAGS" - LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" - export LDFLAGS - - AC_LANG_PUSH(C++) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - @%:@include - ]], [[ - #if BOOST_VERSION >= $WANT_BOOST_VERSION - // Everything is okay - #else - # error Boost version is too old - #endif - ]])],[ - AC_MSG_RESULT(yes) - succeeded=yes - found_system=yes - ],[ - ]) - AC_LANG_POP([C++]) - - - - dnl if we found no boost with system layout we search for boost libraries - dnl built and installed without the --layout=system option or for a staged(not installed) version - if test "x$succeeded" != "xyes"; then - _version=0 - if test "$ac_boost_path" != ""; then - if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then - for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do - _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` - V_CHECK=`expr $_version_tmp \> $_version` - if test "$V_CHECK" = "1" ; then - _version=$_version_tmp - fi - VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` - BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE" - done - fi - else - for ac_boost_path in /usr /usr/local /opt /opt/local ; do - if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then - for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do - _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` - V_CHECK=`expr $_version_tmp \> $_version` - if test "$V_CHECK" = "1" ; then - _version=$_version_tmp - best_path=$ac_boost_path - fi - done - fi - done - - VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` - BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE" - if test "$ac_boost_lib_path" = "" - then - BOOST_LDFLAGS="-L$best_path/lib" - fi - - if test "x$BOOST_ROOT" != "x"; then - if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/lib" && test -r "$BOOST_ROOT/stage/lib"; then - version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'` - stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'` - stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'` - V_CHECK=`expr $stage_version_shorten \>\= $_version` - if test "$V_CHECK" = "1" -a "$ac_boost_lib_path" = "" ; then - AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT) - BOOST_CPPFLAGS="-I$BOOST_ROOT" - BOOST_LDFLAGS="-L$BOOST_ROOT/stage/lib" - fi - fi - fi - fi - - CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" - export CPPFLAGS - LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" - export LDFLAGS - - AC_LANG_PUSH(C++) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - @%:@include - ]], [[ - #if BOOST_VERSION >= $WANT_BOOST_VERSION - // Everything is okay - #else - # error Boost version is too old - #endif - ]])],[ - AC_MSG_RESULT(yes) - succeeded=yes - found_system=yes - ],[ - ]) - AC_LANG_POP([C++]) - fi - - if test "$succeeded" != "yes" ; then - if test "$_version" = "0" ; then - AC_MSG_ERROR([[We could not detect the boost libraries (version $boost_lib_version_req_shorten or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in . See http://randspringer.de/boost for more documentation.]]) - else - AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).]) - fi - else - AC_SUBST(BOOST_CPPFLAGS) - AC_SUBST(BOOST_LDFLAGS) - AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available]) - fi - - CPPFLAGS="$CPPFLAGS_SAVED" - LDFLAGS="$LDFLAGS_SAVED" -fi - -]) diff --git a/m4/ax_boost_filesystem.m4 b/m4/ax_boost_filesystem.m4 deleted file mode 100644 index 18df8f4..0000000 --- a/m4/ax_boost_filesystem.m4 +++ /dev/null @@ -1,118 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_boost_filesystem.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_BOOST_FILESYSTEM -# -# DESCRIPTION -# -# Test for Filesystem library from the Boost C++ libraries. The macro -# requires a preceding call to AX_BOOST_BASE. Further documentation is -# available at . -# -# This macro calls: -# -# AC_SUBST(BOOST_FILESYSTEM_LIB) -# -# And sets: -# -# HAVE_BOOST_FILESYSTEM -# -# LICENSE -# -# Copyright (c) 2009 Thomas Porschberg -# Copyright (c) 2009 Michael Tindal -# Copyright (c) 2009 Roman Rybalko -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 22 - -AC_DEFUN([AX_BOOST_FILESYSTEM], -[ - AC_ARG_WITH([boost-filesystem], - AS_HELP_STRING([--with-boost-filesystem@<:@=special-lib@:>@], - [use the Filesystem library from boost - it is possible to specify a certain library for the linker - e.g. --with-boost-filesystem=boost_filesystem-gcc-mt ]), - [ - if test "$withval" = "no"; then - want_boost="no" - elif test "$withval" = "yes"; then - want_boost="yes" - ax_boost_user_filesystem_lib="" - else - want_boost="yes" - ax_boost_user_filesystem_lib="$withval" - fi - ], - [want_boost="yes"] - ) - - if test "x$want_boost" = "xyes"; then - AC_REQUIRE([AC_PROG_CC]) - CPPFLAGS_SAVED="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" - export CPPFLAGS - - LDFLAGS_SAVED="$LDFLAGS" - LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" - export LDFLAGS - - LIBS_SAVED=$LIBS - LIBS="$LIBS $BOOST_SYSTEM_LIB" - export LIBS - - AC_CACHE_CHECK(whether the Boost::Filesystem library is available, - ax_cv_boost_filesystem, - [AC_LANG_PUSH([C++]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], - [[using namespace boost::filesystem; - path my_path( "foo/bar/data.txt" ); - return 0;]])], - ax_cv_boost_filesystem=yes, ax_cv_boost_filesystem=no) - AC_LANG_POP([C++]) - ]) - if test "x$ax_cv_boost_filesystem" = "xyes"; then - AC_DEFINE(HAVE_BOOST_FILESYSTEM,,[define if the Boost::Filesystem library is available]) - BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` - if test "x$ax_boost_user_filesystem_lib" = "x"; then - for libextension in `ls $BOOSTLIBDIR/libboost_filesystem*.so* $BOOSTLIBDIR/libboost_filesystem*.dylib* $BOOSTLIBDIR/libboost_filesystem*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_filesystem.*\)\.so.*$;\1;' -e 's;^lib\(boost_filesystem.*\)\.a*$;\1;' -e 's;^lib\(boost_filesystem.*\)\.dylib$;\1;'` ; do - ax_lib=${libextension} - AC_CHECK_LIB($ax_lib, exit, - [BOOST_FILESYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_FILESYSTEM_LIB) link_filesystem="yes"; break], - [link_filesystem="no"]) - done - if test "x$link_filesystem" != "xyes"; then - for libextension in `ls $BOOSTLIBDIR/boost_filesystem*.{dll,a}* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_filesystem.*\)\.dll.*$;\1;' -e 's;^\(boost_filesystem.*\)\.a*$;\1;'` ; do - ax_lib=${libextension} - AC_CHECK_LIB($ax_lib, exit, - [BOOST_FILESYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_FILESYSTEM_LIB) link_filesystem="yes"; break], - [link_filesystem="no"]) - done - fi - else - for ax_lib in $ax_boost_user_filesystem_lib boost_filesystem-$ax_boost_user_filesystem_lib; do - AC_CHECK_LIB($ax_lib, exit, - [BOOST_FILESYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_FILESYSTEM_LIB) link_filesystem="yes"; break], - [link_filesystem="no"]) - done - - fi - if test "x$ax_lib" = "x"; then - AC_MSG_ERROR(Could not find a version of the library!) - fi - if test "x$link_filesystem" != "xyes"; then - AC_MSG_ERROR(Could not link against $ax_lib !) - fi - fi - - CPPFLAGS="$CPPFLAGS_SAVED" - LDFLAGS="$LDFLAGS_SAVED" - LIBS="$LIBS_SAVED" - fi -]) diff --git a/m4/ax_boost_serialization.m4 b/m4/ax_boost_serialization.m4 deleted file mode 100644 index 47e955a..0000000 --- a/m4/ax_boost_serialization.m4 +++ /dev/null @@ -1,117 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_boost_serialization.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_BOOST_SERIALIZATION -# -# DESCRIPTION -# -# Test for Serialization library from the Boost C++ libraries. The macro -# requires a preceding call to AX_BOOST_BASE. Further documentation is -# available at . -# -# This macro calls: -# -# AC_SUBST(BOOST_SERIALIZATION_LIB) -# -# And sets: -# -# HAVE_BOOST_SERIALIZATION -# -# LICENSE -# -# Copyright (c) 2008 Thomas Porschberg -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 18 - -AC_DEFUN([AX_BOOST_SERIALIZATION], -[ - AC_ARG_WITH([boost-serialization], - AS_HELP_STRING([--with-boost-serialization@<:@=special-lib@:>@], - [use the Serialization library from boost - it is possible to specify a certain library for the linker - e.g. --with-boost-serialization=boost_serialization-gcc-mt-d-1_33_1 ]), - [ - if test "$withval" = "no"; then - want_boost="no" - elif test "$withval" = "yes"; then - want_boost="yes" - ax_boost_user_serialization_lib="" - else - want_boost="yes" - ax_boost_user_serialization_lib="$withval" - fi - ], - [want_boost="yes"] - ) - - if test "x$want_boost" = "xyes"; then - AC_REQUIRE([AC_PROG_CC]) - CPPFLAGS_SAVED="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" - AC_MSG_WARN(BOOST_CPPFLAGS $BOOST_CPPFLAGS) - export CPPFLAGS - - LDFLAGS_SAVED="$LDFLAGS" - LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" - export LDFLAGS - - AC_CACHE_CHECK(whether the Boost::Serialization library is available, - ax_cv_boost_serialization, - [AC_LANG_PUSH([C++]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include - @%:@include - @%:@include - ]], - [[std::ofstream ofs("filename"); - boost::archive::text_oarchive oa(ofs); - return 0; - ]])], - ax_cv_boost_serialization=yes, ax_cv_boost_serialization=no) - AC_LANG_POP([C++]) - ]) - if test "x$ax_cv_boost_serialization" = "xyes"; then - AC_DEFINE(HAVE_BOOST_SERIALIZATION,,[define if the Boost::Serialization library is available]) - BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` - if test "x$ax_boost_user_serialization_lib" = "x"; then - for libextension in `ls $BOOSTLIBDIR/libboost_serialization*.so* $BOOSTLIBDIR/libboost_serialization*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_serialization.*\)\.so.*$;\1;' -e 's;^lib\(boost_serialization.*\)\.a*$;\1;'` ; do - ax_lib=${libextension} - AC_CHECK_LIB($ax_lib, exit, - [BOOST_SERIALIZATION_LIB="-l$ax_lib"; AC_SUBST(BOOST_SERIALIZATION_LIB) link_serialization="yes"; break], - [link_serialization="no"]) - done - if test "x$link_serialization" != "xyes"; then - for libextension in `ls $BOOSTLIBDIR/boost_serialization*.{dll,a}* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_serialization.*\)\.dll.*$;\1;' -e 's;^\(boost_serialization.*\)\.a*$;\1;'` ; do - ax_lib=${libextension} - AC_CHECK_LIB($ax_lib, exit, - [BOOST_SERIALIZATION_LIB="-l$ax_lib"; AC_SUBST(BOOST_SERIALIZATION_LIB) link_serialization="yes"; break], - [link_serialization="no"]) - done - fi - - else - for ax_lib in $ax_boost_user_serialization_lib boost_serialization-$ax_boost_user_serialization_lib; do - AC_CHECK_LIB($ax_lib, main, - [BOOST_SERIALIZATION_LIB="-l$ax_lib"; AC_SUBST(BOOST_SERIALIZATION_LIB) link_serialization="yes"; break], - [link_serialization="no"]) - done - - fi - if test "x$ax_lib" = "x"; then - AC_MSG_ERROR(Could not find a version of the library!) - fi - if test "x$link_serialization" != "xyes"; then - AC_MSG_ERROR(Could not link against $ax_lib !) - fi - fi - - CPPFLAGS="$CPPFLAGS_SAVED" - LDFLAGS="$LDFLAGS_SAVED" - fi -]) diff --git a/m4/ax_boost_system.m4 b/m4/ax_boost_system.m4 deleted file mode 100644 index 7fbf6d3..0000000 --- a/m4/ax_boost_system.m4 +++ /dev/null @@ -1,120 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_boost_system.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_BOOST_SYSTEM -# -# DESCRIPTION -# -# Test for System library from the Boost C++ libraries. The macro requires -# a preceding call to AX_BOOST_BASE. Further documentation is available at -# . -# -# This macro calls: -# -# AC_SUBST(BOOST_SYSTEM_LIB) -# -# And sets: -# -# HAVE_BOOST_SYSTEM -# -# LICENSE -# -# Copyright (c) 2008 Thomas Porschberg -# Copyright (c) 2008 Michael Tindal -# Copyright (c) 2008 Daniel Casimiro -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 14 - -AC_DEFUN([AX_BOOST_SYSTEM], -[ - AC_ARG_WITH([boost-system], - AS_HELP_STRING([--with-boost-system@<:@=special-lib@:>@], - [use the System library from boost - it is possible to specify a certain library for the linker - e.g. --with-boost-system=boost_system-gcc-mt ]), - [ - if test "$withval" = "no"; then - want_boost="no" - elif test "$withval" = "yes"; then - want_boost="yes" - ax_boost_user_system_lib="" - else - want_boost="yes" - ax_boost_user_system_lib="$withval" - fi - ], - [want_boost="yes"] - ) - - if test "x$want_boost" = "xyes"; then - AC_REQUIRE([AC_PROG_CC]) - AC_REQUIRE([AC_CANONICAL_BUILD]) - CPPFLAGS_SAVED="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" - export CPPFLAGS - - LDFLAGS_SAVED="$LDFLAGS" - LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" - export LDFLAGS - - AC_CACHE_CHECK(whether the Boost::System library is available, - ax_cv_boost_system, - [AC_LANG_PUSH([C++]) - CXXFLAGS_SAVE=$CXXFLAGS - - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], - [[boost::system::system_category]])], - ax_cv_boost_system=yes, ax_cv_boost_system=no) - CXXFLAGS=$CXXFLAGS_SAVE - AC_LANG_POP([C++]) - ]) - if test "x$ax_cv_boost_system" = "xyes"; then - AC_SUBST(BOOST_CPPFLAGS) - - AC_DEFINE(HAVE_BOOST_SYSTEM,,[define if the Boost::System library is available]) - BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` - - LDFLAGS_SAVE=$LDFLAGS - if test "x$ax_boost_user_system_lib" = "x"; then - for libextension in `ls $BOOSTLIBDIR/libboost_system*.so* $BOOSTLIBDIR/libboost_system*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_system.*\)\.so.*$;\1;' -e 's;^lib\(boost_system.*\)\.a*$;\1;'` ; do - ax_lib=${libextension} - AC_CHECK_LIB($ax_lib, exit, - [BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break], - [link_system="no"]) - done - if test "x$link_system" != "xyes"; then - for libextension in `ls $BOOSTLIBDIR/boost_system*.{dll,a}* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_system.*\)\.dll.*$;\1;' -e 's;^\(boost_system.*\)\.a*$;\1;'` ; do - ax_lib=${libextension} - AC_CHECK_LIB($ax_lib, exit, - [BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break], - [link_system="no"]) - done - fi - - else - for ax_lib in $ax_boost_user_system_lib boost_system-$ax_boost_user_system_lib; do - AC_CHECK_LIB($ax_lib, exit, - [BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break], - [link_system="no"]) - done - - fi - if test "x$ax_lib" = "x"; then - AC_MSG_ERROR(Could not find a version of the library!) - fi - if test "x$link_system" = "xno"; then - AC_MSG_ERROR(Could not link against $ax_lib !) - fi - fi - - CPPFLAGS="$CPPFLAGS_SAVED" - LDFLAGS="$LDFLAGS_SAVED" - fi -]) From a3a676c7d00d160d50b7eb3832d63f2a7959dd89 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Wed, 22 Aug 2012 04:56:28 +0000 Subject: [PATCH 10/51] fix key size setting on new filesystems git-svn-id: http://encfs.googlecode.com/svn/trunk@87 db9cf616-1c43-0410-9cb8-a902689de0d6 --- encfs/FileUtils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/encfs/FileUtils.cpp b/encfs/FileUtils.cpp index 10cee18..3bbec93 100644 --- a/encfs/FileUtils.cpp +++ b/encfs/FileUtils.cpp @@ -1036,7 +1036,6 @@ RootPtr createConfig( EncFS_Context *ctx, EncfsConfig config; config.mutable_cipher()->MergeFrom( cipher->interface() ); - //config.keySize = keySize; config.set_block_size( blockSize ); config.mutable_naming()->MergeFrom( nameIOIface ); config.set_creator( "EncFS " VERSION ); @@ -1052,6 +1051,7 @@ RootPtr createConfig( EncFS_Context *ctx, key->clear_salt(); key->clear_kdf_iterations(); // filled in by keying function key->set_kdf_duration( desiredKDFDuration ); + key->set_size(keySize / 8); cout << "\n"; // xgroup(setup) @@ -1588,7 +1588,7 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) if(!userKey) return rootInfo; - rDebug("cipher key size = %i", cipher->encodedKeySize()); + rDebug("cipher encoded key size = %i", cipher->encodedKeySize()); // decode volume key.. CipherKey volumeKey = cipher->readKey( (const unsigned char *)config.key().ciphertext().data(), userKey, opts->checkKey); From 22e29faea170b9128048e64f22d8c3545a266604 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sun, 26 Aug 2012 06:43:01 +0000 Subject: [PATCH 11/51] reworked encfs6 read support to better handle variants git-svn-id: http://encfs.googlecode.com/svn/trunk@88 db9cf616-1c43-0410-9cb8-a902689de0d6 --- encfs/FileUtils.cpp | 43 +++++++++-------- encfs/Interface.cpp | 11 ----- encfs/Interface.h | 2 - encfs/XmlReader.cpp | 113 ++++++++++++++++++++++++++++++++------------ encfs/XmlReader.h | 20 ++++---- 5 files changed, 119 insertions(+), 70 deletions(-) diff --git a/encfs/FileUtils.cpp b/encfs/FileUtils.cpp index 3bbec93..2791184 100644 --- a/encfs/FileUtils.cpp +++ b/encfs/FileUtils.cpp @@ -280,14 +280,17 @@ bool readV6Config( const char *configFile, return false; } - int version = 0; - (*config)["@version"] >> version; + int version; + if (!config->read("version", &version) && + !config->read("@version", &version)) { + rError("Unable to find version in config file"); + return false; + } // version numbering was complicated by boost::archive if (version == 20 || version >= 20100713) { rInfo("found new serialization format"); - (*config)["version"] >> version; cfg.set_revision(version); } else if (version == 26800) { @@ -307,21 +310,21 @@ bool readV6Config( const char *configFile, } rInfo("subVersion = %i", cfg.revision()); - (*config)["creator"] >> (*cfg.mutable_creator()); - (*config)["cipherAlg"] >> (*cfg.mutable_cipher()); - (*config)["nameAlg"] >> (*cfg.mutable_naming()); + config->read("creator", cfg.mutable_creator()); + config->read("cipherAlg", cfg.mutable_cipher()); + config->read("nameAlg", cfg.mutable_naming()); //(*config)["keySize"] >> cfg.keySize; int blockSize, blockMacBytes, blockMacRandBytes; bool uniqueIv, chainedNameIv, externalIv, allowHoles; - (*config)["blockSize"] >> blockSize; - (*config)["uniqueIV"] >> uniqueIv; - (*config)["chainedNameIV"] >> chainedNameIv; - (*config)["externalIVChaining"] >> externalIv; - (*config)["blockMACBytes"] >> blockMacBytes; - (*config)["blockMACRandBytes"] >> blockMacRandBytes; - (*config)["allowHoles"] >> allowHoles; + config->read("blockSize", &blockSize); + config->read("uniqueIV", &uniqueIv); + config->read("chainedNameIV", &chainedNameIv); + config->read("externalIVChaining", &externalIv); + config->read("blockMACBytes", &blockMacBytes); + config->read("blockMACRandBytes", &blockMacRandBytes); + config->read("allowHoles", &allowHoles); cfg.set_block_size(blockSize); cfg.set_unique_iv(uniqueIv); @@ -333,28 +336,28 @@ bool readV6Config( const char *configFile, EncryptedKey *encryptedKey = cfg.mutable_key(); int encodedSize; - (*config)["encodedKeySize"] >> encodedSize; + config->read("encodedKeySize", &encodedSize); unsigned char *key = new unsigned char[encodedSize]; - (*config)["encodedKeyData"]->readB64Data(key, encodedSize); + config->readB64("encodedKeyData", key, encodedSize); encryptedKey->set_ciphertext(key, encodedSize); delete[] key; int keySize; - (*config)["keySize"] >> keySize; + config->read("keySize", &keySize); encryptedKey->set_size(keySize / 8); // save as size in bytes if(cfg.revision() >= 20080816) { int saltLen; - (*config)["saltLen"] >> saltLen; + config->read("saltLen", &saltLen); unsigned char *salt = new unsigned char[saltLen]; - (*config)["saltData"]->readB64Data(salt, saltLen); + config->readB64("saltData", salt, saltLen); encryptedKey->set_salt(salt, saltLen); delete[] salt; int kdfIterations, desiredKDFDuration; - (*config)["kdfIterations"] >> kdfIterations; - (*config)["desiredKDFDuration"] >> desiredKDFDuration; + config->read("kdfIterations", &kdfIterations); + config->read("desiredKDFDuration", &desiredKDFDuration); encryptedKey->set_kdf_iterations(kdfIterations); encryptedKey->set_kdf_duration(desiredKDFDuration); } else diff --git a/encfs/Interface.cpp b/encfs/Interface.cpp index ff32005..3012a8e 100644 --- a/encfs/Interface.cpp +++ b/encfs/Interface.cpp @@ -66,17 +66,6 @@ const ConfigVar & operator >> (const ConfigVar &src, Interface &iface) return src; } -const XmlValuePtr & operator >> (const XmlValuePtr &src, Interface &iface) -{ - (*src)["name"] >> *iface.mutable_name(); - int major, minor; - (*src)["major"] >> major; - (*src)["minor"] >> minor; - iface.set_major(major); - iface.set_minor(minor); - return src; -} - bool operator != (const Interface &a, const Interface &b) { if (a.major() != b.major()) diff --git a/encfs/Interface.h b/encfs/Interface.h index 6ddca40..63df4cd 100644 --- a/encfs/Interface.h +++ b/encfs/Interface.h @@ -19,7 +19,6 @@ #define _Interface_incl_ #include -#include "XmlReader.h" #include "config.pb.h" // check if A implements the interface described by B. @@ -33,7 +32,6 @@ Interface makeInterface( const char *name, int major, int minor, int age ); // Reae operation class ConfigVar; const ConfigVar & operator >> (const ConfigVar &, Interface &); -const XmlValuePtr & operator >> (const XmlValuePtr &, Interface &); bool operator != (const Interface &a, const Interface &b); diff --git a/encfs/XmlReader.cpp b/encfs/XmlReader.cpp index c318d95..f0ccf39 100644 --- a/encfs/XmlReader.cpp +++ b/encfs/XmlReader.cpp @@ -19,9 +19,6 @@ */ #include "XmlReader.h" -#include "base64.h" - -#include #include #include @@ -38,6 +35,10 @@ #include #include +#include +#include "base64.h" +#include "Interface.h" + using namespace std; using namespace rlog; @@ -47,48 +48,72 @@ XmlValue::~XmlValue() XmlValuePtr XmlValue::operator[] (const char *path) const { - return this->find(path); + return find(path); } -XmlValuePtr XmlValue::find(const char *name) const +XmlValuePtr XmlValue::find(const char *path) const { - rError("in XmlValue::operator[%s]", name); - return XmlValuePtr(new XmlValue()); + rError("in XmlValue::find(%s)", path); + return XmlValuePtr(); } -const XmlValuePtr & operator >> (const XmlValuePtr &ptr, std::string &out) +bool XmlValue::read(const char *path, std::string *out) const { - out = ptr->text(); - return ptr; + XmlValuePtr value = find(path); + if (!value) + return false; + + *out = value->text(); + return true; } -const XmlValuePtr & operator >> (const XmlValuePtr &ptr, int &out) +bool XmlValue::read(const char *path, int *out) const { - out = atoi(ptr->text().c_str()); - return ptr; + XmlValuePtr value = find(path); + if (!value) + return false; + + *out = atoi(value->text().c_str()); + return true; } -const XmlValuePtr & operator >> (const XmlValuePtr &ptr, long &out) +bool XmlValue::read(const char *path, long *out) const { - out = atol(ptr->text().c_str()); - return ptr; + XmlValuePtr value = find(path); + if (!value) + return false; + + *out = atol(value->text().c_str()); + return true; } -const XmlValuePtr & operator >> (const XmlValuePtr &ptr, double &out) +bool XmlValue::read(const char *path, double *out) const { - out = atof(ptr->text().c_str()); - return ptr; + XmlValuePtr value = find(path); + if (!value) + return false; + + *out = atof(value->text().c_str()); + return true; } -const XmlValuePtr & operator >> (const XmlValuePtr &ptr, bool &out) +bool XmlValue::read(const char *path, bool *out) const { - out = atoi(ptr->text().c_str()); - return ptr; + XmlValuePtr value = find(path); + if (!value) + return false; + + *out = atoi(value->text().c_str()); + return true; } -bool XmlValue::readB64Data(unsigned char *data, int length) const +bool XmlValue::readB64(const char *path, unsigned char *data, int length) const { - std::string s = value; + XmlValuePtr value = find(path); + if (!value) + return false; + + std::string s = value->text(); s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end()); BIO *b64 = BIO_new(BIO_f_base64()); @@ -110,9 +135,31 @@ bool XmlValue::readB64Data(unsigned char *data, int length) const return true; } -std::string safeValueForNode(TiXmlElement *element) +bool XmlValue::read(const char *path, Interface *out) const +{ + XmlValuePtr node = find(path); + if (!node) + return false; + + int major, minor; + bool ok = node->read("name", out->mutable_name()) + && node->read("major", &major) + && node->read("minor", &minor); + + if (!ok) + return false; + + out->set_major(major); + out->set_minor(minor); + return true; +} + +std::string safeValueForNode(const TiXmlElement *element) { std::string value; + if (element == NULL) + return value; + const TiXmlNode *child = element->FirstChild(); if (child) { @@ -126,9 +173,9 @@ std::string safeValueForNode(TiXmlElement *element) class XmlNode : virtual public XmlValue { - TiXmlElement *element; + const TiXmlElement *element; public: - XmlNode(TiXmlElement *element_) + XmlNode(const TiXmlElement *element_) : XmlValue(safeValueForNode(element_)) , element(element_) { @@ -142,10 +189,18 @@ public: { if (name[0] == '@') { - return XmlValuePtr(new XmlValue(element->Attribute(name+1))); + const char *value = element->Attribute(name+1); + if (value) + return XmlValuePtr(new XmlValue(value)); + else + return XmlValuePtr(); } else { - return XmlValuePtr(new XmlNode(element->FirstChild(name)->ToElement())); + const TiXmlElement *el = element->FirstChildElement(name); + if (el) + return XmlValuePtr(new XmlNode(el)); + else + return XmlValuePtr(); } } }; diff --git a/encfs/XmlReader.h b/encfs/XmlReader.h index 497fc1e..a1c95d9 100644 --- a/encfs/XmlReader.h +++ b/encfs/XmlReader.h @@ -27,6 +27,8 @@ class XmlValue; typedef shared_ptr XmlValuePtr; +class Interface; + class XmlValue { std::string value; @@ -43,23 +45,25 @@ public: XmlValuePtr operator[] (const char *path) const; - bool readB64Data(unsigned char *data, int length) const; - const std::string &text() const { return value; } + bool read(const char *path, std::string *out) const; + bool readB64(const char *path, unsigned char *out, int length) const; + + bool read(const char *path, int *out) const; + bool read(const char *path, long *out) const; + bool read(const char *path, double *out) const; + bool read(const char *path, bool *out) const; + + bool read(const char *path, Interface *out) const; + protected: virtual XmlValuePtr find(const char *name) const; }; -const XmlValuePtr & operator >> (const XmlValuePtr &ptr, std::string &outStr); -const XmlValuePtr & operator >> (const XmlValuePtr &ptr, int &out); -const XmlValuePtr & operator >> (const XmlValuePtr &ptr, long &out); -const XmlValuePtr & operator >> (const XmlValuePtr &ptr, double &out); -const XmlValuePtr & operator >> (const XmlValuePtr &ptr, bool &out); - class XmlReader { public: From efe358c2d56ae9fc21221603783e56831cb76f28 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Wed, 3 Oct 2012 05:12:17 +0000 Subject: [PATCH 12/51] replace libencfs license headers with lgpl git-svn-id: http://encfs.googlecode.com/svn/trunk@89 db9cf616-1c43-0410-9cb8-a902689de0d6 --- COPYING | 674 +---------------------------------------- COPYING.GPL | 674 +++++++++++++++++++++++++++++++++++++++++ COPYING.LGPL | 165 ++++++++++ encfs/BlockFileIO.cpp | 17 +- encfs/BlockFileIO.h | 17 +- encfs/BlockNameIO.cpp | 16 +- encfs/BlockNameIO.h | 17 +- encfs/Cipher.cpp | 16 +- encfs/Cipher.h | 16 +- encfs/CipherFileIO.cpp | 17 +- encfs/CipherFileIO.h | 17 +- encfs/CipherKey.cpp | 16 +- encfs/CipherKey.h | 16 +- encfs/ConfigReader.cpp | 17 +- encfs/ConfigReader.h | 17 +- encfs/ConfigVar.cpp | 17 +- encfs/ConfigVar.h | 17 +- encfs/Context.cpp | 16 +- encfs/Context.h | 17 +- encfs/DirNode.cpp | 17 +- encfs/DirNode.h | 17 +- encfs/FSConfig.h | 16 +- encfs/FileIO.cpp | 17 +- encfs/FileIO.h | 17 +- encfs/FileNode.cpp | 17 +- encfs/FileNode.h | 17 +- encfs/FileUtils.cpp | 19 +- encfs/FileUtils.h | 19 +- encfs/Interface.cpp | 17 +- encfs/Interface.h | 17 +- encfs/MACFileIO.cpp | 17 +- encfs/MACFileIO.h | 17 +- encfs/MemoryPool.cpp | 16 +- encfs/MemoryPool.h | 16 +- encfs/Mutex.h | 17 +- encfs/NameIO.cpp | 17 +- encfs/NameIO.h | 17 +- encfs/NullCipher.cpp | 17 +- encfs/NullCipher.h | 16 +- encfs/NullNameIO.cpp | 17 +- encfs/NullNameIO.h | 17 +- encfs/Range.h | 17 +- encfs/RawFileIO.cpp | 17 +- encfs/RawFileIO.h | 17 +- encfs/SSL_Cipher.cpp | 16 +- encfs/SSL_Cipher.h | 16 +- encfs/StreamNameIO.cpp | 17 +- encfs/StreamNameIO.h | 17 +- encfs/XmlReader.cpp | 18 +- encfs/XmlReader.h | 18 +- encfs/base64.cpp | 16 +- encfs/base64.h | 16 +- encfs/encfs.h | 16 +- encfs/i18n.h | 17 +- encfs/openssl.cpp | 16 +- encfs/openssl.h | 16 +- encfs/shared_ptr.h | 16 +- 57 files changed, 1355 insertions(+), 1064 deletions(-) create mode 100644 COPYING.GPL create mode 100644 COPYING.LGPL diff --git a/COPYING b/COPYING index 94a9ed0..30b961c 100644 --- a/COPYING +++ b/COPYING @@ -1,674 +1,4 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. +For portions of Encfs which are licensed under the LGPL: see COPYING.LGPL. +For portions of Encfs which are licensed under the GPL: see COPYING.GPL. - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/COPYING.GPL b/COPYING.GPL new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/COPYING.GPL @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/COPYING.LGPL b/COPYING.LGPL new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/COPYING.LGPL @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/encfs/BlockFileIO.cpp b/encfs/BlockFileIO.cpp index 9d65313..c3e91e4 100644 --- a/encfs/BlockFileIO.cpp +++ b/encfs/BlockFileIO.cpp @@ -4,15 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "BlockFileIO.h" diff --git a/encfs/BlockFileIO.h b/encfs/BlockFileIO.h index b7780fb..2a76d78 100644 --- a/encfs/BlockFileIO.h +++ b/encfs/BlockFileIO.h @@ -4,15 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _BlockFileIO_incl_ diff --git a/encfs/BlockNameIO.cpp b/encfs/BlockNameIO.cpp index 9faa662..b318965 100644 --- a/encfs/BlockNameIO.cpp +++ b/encfs/BlockNameIO.cpp @@ -4,18 +4,18 @@ ***************************************************************************** * Copyright (c) 2004-2011, Valient Gough * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "BlockNameIO.h" diff --git a/encfs/BlockNameIO.h b/encfs/BlockNameIO.h index 7bc4514..b57f5b3 100644 --- a/encfs/BlockNameIO.h +++ b/encfs/BlockNameIO.h @@ -4,15 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _BlockNameIO_incl_ diff --git a/encfs/Cipher.cpp b/encfs/Cipher.cpp index 211f653..6e6e47b 100644 --- a/encfs/Cipher.cpp +++ b/encfs/Cipher.cpp @@ -4,16 +4,18 @@ ***************************************************************************** * Copyright (c) 2002-2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "config.h" diff --git a/encfs/Cipher.h b/encfs/Cipher.h index bfb209d..e0dc3b2 100644 --- a/encfs/Cipher.h +++ b/encfs/Cipher.h @@ -4,16 +4,18 @@ ***************************************************************************** * Copyright (c) 2002-2003, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _Cipher_incl_ diff --git a/encfs/CipherFileIO.cpp b/encfs/CipherFileIO.cpp index fb2b4ca..4cbb8e8 100644 --- a/encfs/CipherFileIO.cpp +++ b/encfs/CipherFileIO.cpp @@ -4,15 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "CipherFileIO.h" diff --git a/encfs/CipherFileIO.h b/encfs/CipherFileIO.h index 79535e4..90dfc11 100644 --- a/encfs/CipherFileIO.h +++ b/encfs/CipherFileIO.h @@ -4,15 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _CipherFileIO_incl_ diff --git a/encfs/CipherKey.cpp b/encfs/CipherKey.cpp index b85e1f1..c2e815a 100644 --- a/encfs/CipherKey.cpp +++ b/encfs/CipherKey.cpp @@ -4,18 +4,18 @@ ***************************************************************************** * Copyright (c) 2007, Valient Gough * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "CipherKey.h" diff --git a/encfs/CipherKey.h b/encfs/CipherKey.h index 1935d3c..b8cf639 100644 --- a/encfs/CipherKey.h +++ b/encfs/CipherKey.h @@ -4,18 +4,18 @@ ***************************************************************************** * Copyright (c) 2007, Valient Gough * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _CipherKey_incl_ diff --git a/encfs/ConfigReader.cpp b/encfs/ConfigReader.cpp index d5952c2..8218e59 100644 --- a/encfs/ConfigReader.cpp +++ b/encfs/ConfigReader.cpp @@ -3,16 +3,19 @@ * ***************************************************************************** * Copyright (c) 2004, Valient Gough - * - * This program is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "ConfigReader.h" diff --git a/encfs/ConfigReader.h b/encfs/ConfigReader.h index c1e68bc..4d6bf71 100644 --- a/encfs/ConfigReader.h +++ b/encfs/ConfigReader.h @@ -3,16 +3,19 @@ * ***************************************************************************** * Copyright (c) 2004, Valient Gough - * - * This program is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _ConfigReader_incl_ diff --git a/encfs/ConfigVar.cpp b/encfs/ConfigVar.cpp index 9a988f6..a677236 100644 --- a/encfs/ConfigVar.cpp +++ b/encfs/ConfigVar.cpp @@ -3,16 +3,19 @@ * ***************************************************************************** * Copyright (c) 2004, Valient Gough - * - * This program is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "ConfigVar.h" diff --git a/encfs/ConfigVar.h b/encfs/ConfigVar.h index 5bf903f..4a51304 100644 --- a/encfs/ConfigVar.h +++ b/encfs/ConfigVar.h @@ -3,16 +3,19 @@ * ***************************************************************************** * Copyright (c) 2004, Valient Gough - * - * This program is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _ConfigVar_incl_ diff --git a/encfs/Context.cpp b/encfs/Context.cpp index c7ef5c2..3eba9e5 100644 --- a/encfs/Context.cpp +++ b/encfs/Context.cpp @@ -4,18 +4,18 @@ ***************************************************************************** * Copyright (c) 2007, Valient Gough * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "FileNode.h" diff --git a/encfs/Context.h b/encfs/Context.h index 0b810da..282dad5 100644 --- a/encfs/Context.h +++ b/encfs/Context.h @@ -3,16 +3,19 @@ * ***************************************************************************** * Copyright (c) 2007, Valient Gough - * - * This program is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _Context_incl_ diff --git a/encfs/DirNode.cpp b/encfs/DirNode.cpp index 7d95fcc..169c580 100644 --- a/encfs/DirNode.cpp +++ b/encfs/DirNode.cpp @@ -3,16 +3,19 @@ * ***************************************************************************** * Copyright (c) 2003-2004, Valient Gough - * - * This program is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "encfs.h" diff --git a/encfs/DirNode.h b/encfs/DirNode.h index 34240be..a1e3fdf 100644 --- a/encfs/DirNode.h +++ b/encfs/DirNode.h @@ -3,16 +3,19 @@ * ***************************************************************************** * Copyright (c) 2003, Valient Gough - * - * This program is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _DirNode_incl_ diff --git a/encfs/FSConfig.h b/encfs/FSConfig.h index 0ac02e4..c777679 100644 --- a/encfs/FSConfig.h +++ b/encfs/FSConfig.h @@ -4,18 +4,18 @@ ***************************************************************************** * Copyright (c) 2010 Valient Gough * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _FSConfig_incl_ diff --git a/encfs/FileIO.cpp b/encfs/FileIO.cpp index d4da8f3..3bd226c 100644 --- a/encfs/FileIO.cpp +++ b/encfs/FileIO.cpp @@ -4,15 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "FileIO.h" diff --git a/encfs/FileIO.h b/encfs/FileIO.h index 5e0df17..c97ff2a 100644 --- a/encfs/FileIO.h +++ b/encfs/FileIO.h @@ -4,15 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _FileIO_incl_ diff --git a/encfs/FileNode.cpp b/encfs/FileNode.cpp index 5e73190..4363423 100644 --- a/encfs/FileNode.cpp +++ b/encfs/FileNode.cpp @@ -3,16 +3,19 @@ * ***************************************************************************** * Copyright (c) 2003-2004, Valient Gough - * - * This program is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ // Include encfs first, because we need to include fuse.h before any inclusion diff --git a/encfs/FileNode.h b/encfs/FileNode.h index df8caec..0037643 100644 --- a/encfs/FileNode.h +++ b/encfs/FileNode.h @@ -3,16 +3,19 @@ * ***************************************************************************** * Copyright (c) 2003, Valient Gough - * - * This program is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _FileNode_incl_ diff --git a/encfs/FileUtils.cpp b/encfs/FileUtils.cpp index 2791184..b045d54 100644 --- a/encfs/FileUtils.cpp +++ b/encfs/FileUtils.cpp @@ -2,17 +2,20 @@ * Author: Valient Gough * ***************************************************************************** - * Copyright (c) 2004, Valient Gough - * - * This program is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * Copyright (c) 2004-2012, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ // defines needed for RedHat 7.3... diff --git a/encfs/FileUtils.h b/encfs/FileUtils.h index 483ae3f..9cb058e 100644 --- a/encfs/FileUtils.h +++ b/encfs/FileUtils.h @@ -2,17 +2,20 @@ * Author: Valient Gough * ***************************************************************************** - * Copyright (c) 2004, Valient Gough - * - * This program is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * Copyright (c) 2004-2012, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _FileUtils_incl_ diff --git a/encfs/Interface.cpp b/encfs/Interface.cpp index 3012a8e..489996d 100644 --- a/encfs/Interface.cpp +++ b/encfs/Interface.cpp @@ -3,16 +3,19 @@ * ***************************************************************************** * Copyright (c) 2004, Valient Gough - * - * This program is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "Interface.h" diff --git a/encfs/Interface.h b/encfs/Interface.h index 63df4cd..bfced6d 100644 --- a/encfs/Interface.h +++ b/encfs/Interface.h @@ -3,16 +3,19 @@ * ***************************************************************************** * Copyright (c) 2004, Valient Gough - * - * This program is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _Interface_incl_ diff --git a/encfs/MACFileIO.cpp b/encfs/MACFileIO.cpp index 4d6898c..b0002d2 100644 --- a/encfs/MACFileIO.cpp +++ b/encfs/MACFileIO.cpp @@ -4,15 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "MACFileIO.h" diff --git a/encfs/MACFileIO.h b/encfs/MACFileIO.h index e8b4262..eba1b4b 100644 --- a/encfs/MACFileIO.h +++ b/encfs/MACFileIO.h @@ -4,15 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _MACFileIO_incl_ diff --git a/encfs/MemoryPool.cpp b/encfs/MemoryPool.cpp index d78c946..4d983b0 100644 --- a/encfs/MemoryPool.cpp +++ b/encfs/MemoryPool.cpp @@ -4,16 +4,18 @@ ***************************************************************************** * Copyright (c) 2003, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "MemoryPool.h" diff --git a/encfs/MemoryPool.h b/encfs/MemoryPool.h index 62349bd..ba46bff 100644 --- a/encfs/MemoryPool.h +++ b/encfs/MemoryPool.h @@ -4,16 +4,18 @@ ***************************************************************************** * Copyright (c) 2003, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (LGPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _MemoryPool_incl_ diff --git a/encfs/Mutex.h b/encfs/Mutex.h index b443e76..318c56a 100644 --- a/encfs/Mutex.h +++ b/encfs/Mutex.h @@ -3,16 +3,19 @@ * ***************************************************************************** * Copyright (c) 2003, Valient Gough - * - * This program is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _Mutex_incl_ diff --git a/encfs/NameIO.cpp b/encfs/NameIO.cpp index 3e2b81e..b9705fc 100644 --- a/encfs/NameIO.cpp +++ b/encfs/NameIO.cpp @@ -4,15 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "NameIO.h" diff --git a/encfs/NameIO.h b/encfs/NameIO.h index 603d257..73e0800 100644 --- a/encfs/NameIO.h +++ b/encfs/NameIO.h @@ -4,15 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _NameIO_incl_ diff --git a/encfs/NullCipher.cpp b/encfs/NullCipher.cpp index 18daff4..4971fd8 100644 --- a/encfs/NullCipher.cpp +++ b/encfs/NullCipher.cpp @@ -4,15 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "NullCipher.h" diff --git a/encfs/NullCipher.h b/encfs/NullCipher.h index 14ed804..103a141 100644 --- a/encfs/NullCipher.h +++ b/encfs/NullCipher.h @@ -4,16 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _NullCipher_incl_ diff --git a/encfs/NullNameIO.cpp b/encfs/NullNameIO.cpp index 65733a9..11200dd 100644 --- a/encfs/NullNameIO.cpp +++ b/encfs/NullNameIO.cpp @@ -4,15 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "NullNameIO.h" diff --git a/encfs/NullNameIO.h b/encfs/NullNameIO.h index ee5d9d9..2f37bab 100644 --- a/encfs/NullNameIO.h +++ b/encfs/NullNameIO.h @@ -4,15 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _NullNameIO_incl_ diff --git a/encfs/Range.h b/encfs/Range.h index 8c60e0c..f4f3c7d 100644 --- a/encfs/Range.h +++ b/encfs/Range.h @@ -3,16 +3,19 @@ * ***************************************************************************** * Copyright (c) 2004, Valient Gough - * - * This program is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _Range_incl_ diff --git a/encfs/RawFileIO.cpp b/encfs/RawFileIO.cpp index 44bbad9..cb7515f 100644 --- a/encfs/RawFileIO.cpp +++ b/encfs/RawFileIO.cpp @@ -4,15 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifdef linux diff --git a/encfs/RawFileIO.h b/encfs/RawFileIO.h index 0156c4c..d172b09 100644 --- a/encfs/RawFileIO.h +++ b/encfs/RawFileIO.h @@ -4,15 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _RawFileIO_incl_ diff --git a/encfs/SSL_Cipher.cpp b/encfs/SSL_Cipher.cpp index 3e00899..10f2d61 100644 --- a/encfs/SSL_Cipher.cpp +++ b/encfs/SSL_Cipher.cpp @@ -4,16 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "encfs.h" diff --git a/encfs/SSL_Cipher.h b/encfs/SSL_Cipher.h index fd2a76f..375ae14 100644 --- a/encfs/SSL_Cipher.h +++ b/encfs/SSL_Cipher.h @@ -4,16 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _SSL_Cipher_incl_ diff --git a/encfs/StreamNameIO.cpp b/encfs/StreamNameIO.cpp index 615f31b..8e275de 100644 --- a/encfs/StreamNameIO.cpp +++ b/encfs/StreamNameIO.cpp @@ -4,15 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "StreamNameIO.h" diff --git a/encfs/StreamNameIO.h b/encfs/StreamNameIO.h index 3983db0..a18e23c 100644 --- a/encfs/StreamNameIO.h +++ b/encfs/StreamNameIO.h @@ -4,15 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _StreamNameIO_incl_ diff --git a/encfs/XmlReader.cpp b/encfs/XmlReader.cpp index f0ccf39..925271c 100644 --- a/encfs/XmlReader.cpp +++ b/encfs/XmlReader.cpp @@ -3,19 +3,19 @@ * ***************************************************************************** * Copyright (c) 2012, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "XmlReader.h" diff --git a/encfs/XmlReader.h b/encfs/XmlReader.h index a1c95d9..e869261 100644 --- a/encfs/XmlReader.h +++ b/encfs/XmlReader.h @@ -3,19 +3,19 @@ * ***************************************************************************** * Copyright (c) 2012, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _XmlReader_incl_ diff --git a/encfs/base64.cpp b/encfs/base64.cpp index ca2fb43..2f0da1d 100644 --- a/encfs/base64.cpp +++ b/encfs/base64.cpp @@ -4,16 +4,18 @@ ***************************************************************************** * Copyright (c) 2002-2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "base64.h" diff --git a/encfs/base64.h b/encfs/base64.h index f8b7f89..2d7b9b2 100644 --- a/encfs/base64.h +++ b/encfs/base64.h @@ -4,16 +4,18 @@ ***************************************************************************** * Copyright (c) 2002-2003, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _base64_incl_ diff --git a/encfs/encfs.h b/encfs/encfs.h index 94f29a2..3256300 100644 --- a/encfs/encfs.h +++ b/encfs/encfs.h @@ -4,16 +4,18 @@ ***************************************************************************** * Copyright (c) 2003, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _encfs_incl_ diff --git a/encfs/i18n.h b/encfs/i18n.h index 604d538..29b2582 100644 --- a/encfs/i18n.h +++ b/encfs/i18n.h @@ -4,15 +4,18 @@ ***************************************************************************** * Copyright (c) 2004, Valient Gough * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _i18n_incl_ diff --git a/encfs/openssl.cpp b/encfs/openssl.cpp index 27a4ffe..dc388da 100644 --- a/encfs/openssl.cpp +++ b/encfs/openssl.cpp @@ -4,18 +4,18 @@ ***************************************************************************** * Copyright (c) 2007, Valient Gough * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #include "openssl.h" diff --git a/encfs/openssl.h b/encfs/openssl.h index 01d5875..a7df0e2 100644 --- a/encfs/openssl.h +++ b/encfs/openssl.h @@ -4,18 +4,18 @@ ***************************************************************************** * Copyright (c) 2007, Valient Gough * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _openssl_incl_ diff --git a/encfs/shared_ptr.h b/encfs/shared_ptr.h index fd4fa8f..4c2ebed 100644 --- a/encfs/shared_ptr.h +++ b/encfs/shared_ptr.h @@ -5,18 +5,18 @@ ***************************************************************************** * Copyright (c) 2012 Valient Gough * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ #ifndef _SHARED_PTR_incl_ From fb9a8ff8791af4c4955e84ee35749eaf39782eb3 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Tue, 29 Jan 2013 03:07:54 +0000 Subject: [PATCH 13/51] Reformat files, replace autoconf with CMake, and RLog with GLog. git-svn-id: http://encfs.googlecode.com/svn/trunk@92 db9cf616-1c43-0410-9cb8-a902689de0d6 --- ABOUT-NLS | 1068 ----------------------- AUTHORS | 14 +- CMakeLists.txt | 67 ++ CMakeModules/FindFUSE.cmake | 35 + CMakeModules/FindGLog.cmake | 59 ++ CMakeModules/FindTinyXML.cmake | 26 + CMakeModules/GettextTranslate.cmake | 287 +++++++ CMakeModules/OpenSSLTests.cmake | 24 + Makefile.am | 17 - Makefile.common | 2 - Makefile.dist | 5 - README | 11 +- README-NLS | 63 +- TRANSLATORS | 7 - base/CMakeLists.txt | 29 + base/ConfigReader.cpp | 157 ++++ {encfs => base}/ConfigReader.h | 2 +- base/ConfigVar.cpp | 253 ++++++ {encfs => base}/ConfigVar.h | 2 +- base/Error.cpp | 7 + base/Error.h | 25 + {encfs => base}/Interface.cpp | 26 +- {encfs => base}/Interface.h | 4 +- {encfs => base}/Mutex.h | 59 +- {encfs => base}/Range.h | 2 + {encfs => base}/XmlReader.cpp | 23 +- {encfs => base}/XmlReader.h | 2 +- {intl => base}/autosprintf.cpp | 2 +- {intl => base}/autosprintf.h | 0 {encfs => base}/base64.cpp | 2 +- {encfs => base}/base64.h | 0 base/config.h.cmake | 19 + {encfs => base}/config.proto | 5 + {intl => base}/gettext.h | 0 {encfs => base}/i18n.h | 4 +- {encfs => base}/shared_ptr.h | 2 +- cipher/CMakeLists.txt | 41 + {encfs => cipher}/Cipher.cpp | 43 +- {encfs => cipher}/Cipher.h | 28 +- {encfs => cipher}/CipherKey.cpp | 2 +- {encfs => cipher}/CipherKey.h | 2 +- cipher/MemoryPool.cpp | 164 ++++ {encfs => cipher}/MemoryPool.h | 24 +- {encfs => cipher}/NullCipher.cpp | 107 ++- {encfs => cipher}/NullCipher.h | 4 +- cipher/SSL_Cipher.cpp | 973 +++++++++++++++++++++ cipher/SSL_Cipher.h | 159 ++++ cipher/openssl.cpp | 109 +++ {encfs => cipher}/openssl.h | 0 {encfs => cipher}/readpassphrase.cpp | 2 +- {encfs => cipher}/readpassphrase.h | 0 configure | 1 + configure.ac | 235 ------ devmode | 2 + encfs.spec.in | 207 ----- encfs/BlockFileIO.cpp | 433 ---------- encfs/BlockNameIO.cpp | 267 ------ encfs/CMakeLists.txt | 39 + encfs/CipherFileIO.cpp | 438 ---------- encfs/ConfigReader.cpp | 162 ---- encfs/ConfigVar.cpp | 252 ------ encfs/Context.cpp | 177 ---- encfs/DirNode.cpp | 831 ------------------ encfs/FileNode.cpp | 306 ------- encfs/MACFileIO.cpp | 304 ------- encfs/Makefile.am | 163 ---- encfs/MemoryPool.cpp | 178 ---- encfs/NameIO.cpp | 351 -------- encfs/RawFileIO.cpp | 325 ------- encfs/SSL_Cipher.cpp | 927 -------------------- encfs/SSL_Cipher.h | 150 ---- encfs/StreamNameIO.cpp | 208 ----- encfs/docs/Makefile.am | 4 - encfs/docs/en/Makefile.am | 4 - encfs/encfs.cpp | 807 ------------------ encfs/encfs.pod | 154 ++-- encfs/encfsctl.cpp | 853 ------------------- encfs/main.cpp | 1173 +++++++++++++------------- encfs/openssl.cpp | 109 --- encfs/test.cpp | 563 ------------ encfs/tests.t | 213 ----- fs/BlockFileIO.cpp | 426 ++++++++++ {encfs => fs}/BlockFileIO.h | 2 +- fs/BlockNameIO.cpp | 250 ++++++ {encfs => fs}/BlockNameIO.h | 6 +- fs/CMakeLists.txt | 56 ++ fs/CipherFileIO.cpp | 513 +++++++++++ {encfs => fs}/CipherFileIO.h | 18 +- fs/Context.cpp | 175 ++++ {encfs => fs}/Context.h | 6 +- fs/DirNode.cpp | 816 ++++++++++++++++++ {encfs => fs}/DirNode.h | 10 +- {encfs => fs}/FSConfig.h | 10 +- {encfs => fs}/FileIO.cpp | 0 {encfs => fs}/FileIO.h | 5 +- fs/FileNode.cpp | 303 +++++++ {encfs => fs}/FileNode.h | 6 +- {encfs => fs}/FileUtils.cpp | 193 +++-- {encfs => fs}/FileUtils.h | 8 +- fs/MACFileIO.cpp | 295 +++++++ {encfs => fs}/MACFileIO.h | 4 +- fs/MemBlockFileIO.cpp | 76 ++ fs/MemBlockFileIO.h | 59 ++ fs/MemFileIO.cpp | 106 +++ fs/MemFileIO.h | 58 ++ fs/NameIO.cpp | 338 ++++++++ {encfs => fs}/NameIO.h | 24 +- {encfs => fs}/NullNameIO.cpp | 38 +- {encfs => fs}/NullNameIO.h | 0 fs/RawFileIO.cpp | 330 ++++++++ {encfs => fs}/RawFileIO.h | 4 +- fs/StreamNameIO.cpp | 206 +++++ {encfs => fs}/StreamNameIO.h | 4 +- fs/encfs.cpp | 793 +++++++++++++++++ {encfs => fs}/encfs.h | 2 +- fs/test.cpp | 556 ++++++++++++ fs/test_BlockIO.cpp | 67 ++ fs/test_IO.cpp | 95 +++ {encfs => fs}/testextpass | 0 fs/testing.cpp | 171 ++++ fs/testing.h | 23 + m4/Makefile.am | 10 - m4/ax_ext_check_header.m4 | 58 -- m4/ax_ext_have_lib.m4 | 72 -- m4/ax_pthread.m4 | 309 ------- makedist.sh | 12 - makedist2.sh.in | 27 - po/CMakeLists.txt | 37 + po/ChangeLog | 5 - po/Makefile.in.in | 429 ---------- po/POTFILES.in | 12 +- po/Rules-quot | 47 -- po/boldquot.sed | 10 - po/en@boldquot.header | 25 - po/en@quot.header | 22 - po/insert-header.sin | 23 - po/quot.sed | 6 - po/remove-potcdate.sin | 19 - reconfig.sh | 3 - subdirs | 3 - util/CMakeLists.txt | 40 + util/encfsctl.cpp | 844 ++++++++++++++++++ {encfs => util}/encfsctl.pod | 0 {encfs => util}/encfssh | 0 {encfs => util}/makeKey.cpp | 0 145 files changed, 10139 insertions(+), 11730 deletions(-) delete mode 100644 ABOUT-NLS create mode 100644 CMakeLists.txt create mode 100644 CMakeModules/FindFUSE.cmake create mode 100644 CMakeModules/FindGLog.cmake create mode 100644 CMakeModules/FindTinyXML.cmake create mode 100644 CMakeModules/GettextTranslate.cmake create mode 100644 CMakeModules/OpenSSLTests.cmake delete mode 100644 Makefile.am delete mode 100644 Makefile.common delete mode 100644 Makefile.dist delete mode 100644 TRANSLATORS create mode 100644 base/CMakeLists.txt create mode 100644 base/ConfigReader.cpp rename {encfs => base}/ConfigReader.h (98%) create mode 100644 base/ConfigVar.cpp rename {encfs => base}/ConfigVar.h (98%) create mode 100644 base/Error.cpp create mode 100644 base/Error.h rename {encfs => base}/Interface.cpp (81%) rename {encfs => base}/Interface.h (97%) rename {encfs => base}/Mutex.h (63%) rename {encfs => base}/Range.h (97%) rename {encfs => base}/XmlReader.cpp (90%) rename {encfs => base}/XmlReader.h (98%) rename {intl => base}/autosprintf.cpp (98%) rename {intl => base}/autosprintf.h (100%) rename {encfs => base}/base64.cpp (99%) rename {encfs => base}/base64.h (100%) create mode 100644 base/config.h.cmake rename {encfs => base}/config.proto (87%) rename {intl => base}/gettext.h (100%) rename {encfs => base}/i18n.h (95%) rename {encfs => base}/shared_ptr.h (97%) create mode 100644 cipher/CMakeLists.txt rename {encfs => cipher}/Cipher.cpp (89%) rename {encfs => cipher}/Cipher.h (88%) rename {encfs => cipher}/CipherKey.cpp (97%) rename {encfs => cipher}/CipherKey.h (97%) create mode 100644 cipher/MemoryPool.cpp rename {encfs => cipher}/MemoryPool.h (90%) rename {encfs => cipher}/NullCipher.cpp (63%) rename {encfs => cipher}/NullCipher.h (98%) create mode 100644 cipher/SSL_Cipher.cpp create mode 100644 cipher/SSL_Cipher.h create mode 100644 cipher/openssl.cpp rename {encfs => cipher}/openssl.h (100%) rename {encfs => cipher}/readpassphrase.cpp (99%) rename {encfs => cipher}/readpassphrase.h (100%) create mode 100644 configure delete mode 100644 configure.ac create mode 100644 devmode delete mode 100644 encfs.spec.in delete mode 100644 encfs/BlockFileIO.cpp delete mode 100644 encfs/BlockNameIO.cpp create mode 100644 encfs/CMakeLists.txt delete mode 100644 encfs/CipherFileIO.cpp delete mode 100644 encfs/ConfigReader.cpp delete mode 100644 encfs/ConfigVar.cpp delete mode 100644 encfs/Context.cpp delete mode 100644 encfs/DirNode.cpp delete mode 100644 encfs/FileNode.cpp delete mode 100644 encfs/MACFileIO.cpp delete mode 100644 encfs/Makefile.am delete mode 100644 encfs/MemoryPool.cpp delete mode 100644 encfs/NameIO.cpp delete mode 100644 encfs/RawFileIO.cpp delete mode 100644 encfs/SSL_Cipher.cpp delete mode 100644 encfs/SSL_Cipher.h delete mode 100644 encfs/StreamNameIO.cpp delete mode 100644 encfs/docs/Makefile.am delete mode 100644 encfs/docs/en/Makefile.am delete mode 100644 encfs/encfs.cpp delete mode 100644 encfs/encfsctl.cpp delete mode 100644 encfs/openssl.cpp delete mode 100644 encfs/test.cpp delete mode 100644 encfs/tests.t create mode 100644 fs/BlockFileIO.cpp rename {encfs => fs}/BlockFileIO.h (97%) create mode 100644 fs/BlockNameIO.cpp rename {encfs => fs}/BlockNameIO.h (95%) create mode 100644 fs/CMakeLists.txt create mode 100644 fs/CipherFileIO.cpp rename {encfs => fs}/CipherFileIO.h (85%) create mode 100644 fs/Context.cpp rename {encfs => fs}/Context.h (97%) create mode 100644 fs/DirNode.cpp rename {encfs => fs}/DirNode.h (97%) rename {encfs => fs}/FSConfig.h (94%) rename {encfs => fs}/FileIO.cpp (100%) rename {encfs => fs}/FileIO.h (97%) create mode 100644 fs/FileNode.cpp rename {encfs => fs}/FileNode.h (97%) rename {encfs => fs}/FileUtils.cpp (90%) rename {encfs => fs}/FileUtils.h (97%) create mode 100644 fs/MACFileIO.cpp rename {encfs => fs}/MACFileIO.h (97%) create mode 100644 fs/MemBlockFileIO.cpp create mode 100644 fs/MemBlockFileIO.h create mode 100644 fs/MemFileIO.cpp create mode 100644 fs/MemFileIO.h create mode 100644 fs/NameIO.cpp rename {encfs => fs}/NameIO.h (93%) rename {encfs => fs}/NullNameIO.cpp (73%) rename {encfs => fs}/NullNameIO.h (100%) create mode 100644 fs/RawFileIO.cpp rename {encfs => fs}/RawFileIO.h (96%) create mode 100644 fs/StreamNameIO.cpp rename {encfs => fs}/StreamNameIO.h (97%) create mode 100644 fs/encfs.cpp rename {encfs => fs}/encfs.h (99%) create mode 100644 fs/test.cpp create mode 100644 fs/test_BlockIO.cpp create mode 100644 fs/test_IO.cpp rename {encfs => fs}/testextpass (100%) create mode 100644 fs/testing.cpp create mode 100644 fs/testing.h delete mode 100644 m4/Makefile.am delete mode 100644 m4/ax_ext_check_header.m4 delete mode 100644 m4/ax_ext_have_lib.m4 delete mode 100644 m4/ax_pthread.m4 delete mode 100644 makedist.sh delete mode 100644 makedist2.sh.in create mode 100644 po/CMakeLists.txt delete mode 100644 po/ChangeLog delete mode 100644 po/Makefile.in.in delete mode 100644 po/Rules-quot delete mode 100644 po/boldquot.sed delete mode 100644 po/en@boldquot.header delete mode 100644 po/en@quot.header delete mode 100644 po/insert-header.sin delete mode 100644 po/quot.sed delete mode 100644 po/remove-potcdate.sin delete mode 100644 reconfig.sh delete mode 100644 subdirs create mode 100644 util/CMakeLists.txt create mode 100644 util/encfsctl.cpp rename {encfs => util}/encfsctl.pod (100%) rename {encfs => util}/encfssh (100%) rename {encfs => util}/makeKey.cpp (100%) diff --git a/ABOUT-NLS b/ABOUT-NLS deleted file mode 100644 index 83bc72e..0000000 --- a/ABOUT-NLS +++ /dev/null @@ -1,1068 +0,0 @@ -1 Notes on the Free Translation Project -*************************************** - -Free software is going international! The Free Translation Project is -a way to get maintainers of free software, translators, and users all -together, so that free software will gradually become able to speak many -languages. A few packages already provide translations for their -messages. - - If you found this `ABOUT-NLS' file inside a distribution, you may -assume that the distributed package does use GNU `gettext' internally, -itself available at your nearest GNU archive site. But you do _not_ -need to install GNU `gettext' prior to configuring, installing or using -this package with messages translated. - - Installers will find here some useful hints. These notes also -explain how users should proceed for getting the programs to use the -available translations. They tell how people wanting to contribute and -work on translations can contact the appropriate team. - - When reporting bugs in the `intl/' directory or bugs which may be -related to internationalization, you should tell about the version of -`gettext' which is used. The information can be found in the -`intl/VERSION' file, in internationalized packages. - -1.1 Quick configuration advice -============================== - -If you want to exploit the full power of internationalization, you -should configure it using - - ./configure --with-included-gettext - -to force usage of internationalizing routines provided within this -package, despite the existence of internationalizing capabilities in the -operating system where this package is being installed. So far, only -the `gettext' implementation in the GNU C library version 2 provides as -many features (such as locale alias, message inheritance, automatic -charset conversion or plural form handling) as the implementation here. -It is also not possible to offer this additional functionality on top -of a `catgets' implementation. Future versions of GNU `gettext' will -very likely convey even more functionality. So it might be a good idea -to change to GNU `gettext' as soon as possible. - - So you need _not_ provide this option if you are using GNU libc 2 or -you have installed a recent copy of the GNU gettext package with the -included `libintl'. - -1.2 INSTALL Matters -=================== - -Some packages are "localizable" when properly installed; the programs -they contain can be made to speak your own native language. Most such -packages use GNU `gettext'. Other packages have their own ways to -internationalization, predating GNU `gettext'. - - By default, this package will be installed to allow translation of -messages. It will automatically detect whether the system already -provides the GNU `gettext' functions. If not, the included GNU -`gettext' library will be used. This library is wholly contained -within this package, usually in the `intl/' subdirectory, so prior -installation of the GNU `gettext' package is _not_ required. -Installers may use special options at configuration time for changing -the default behaviour. The commands: - - ./configure --with-included-gettext - ./configure --disable-nls - -will, respectively, bypass any pre-existing `gettext' to use the -internationalizing routines provided within this package, or else, -_totally_ disable translation of messages. - - When you already have GNU `gettext' installed on your system and run -configure without an option for your new package, `configure' will -probably detect the previously built and installed `libintl.a' file and -will decide to use this. This might not be desirable. You should use -the more recent version of the GNU `gettext' library. I.e. if the file -`intl/VERSION' shows that the library which comes with this package is -more recent, you should use - - ./configure --with-included-gettext - -to prevent auto-detection. - - The configuration process will not test for the `catgets' function -and therefore it will not be used. The reason is that even an -emulation of `gettext' on top of `catgets' could not provide all the -extensions of the GNU `gettext' library. - - Internationalized packages usually have many `po/LL.po' files, where -LL gives an ISO 639 two-letter code identifying the language. Unless -translations have been forbidden at `configure' time by using the -`--disable-nls' switch, all available translations are installed -together with the package. However, the environment variable `LINGUAS' -may be set, prior to configuration, to limit the installed set. -`LINGUAS' should then contain a space separated list of two-letter -codes, stating which languages are allowed. - -1.3 Using This Package -====================== - -As a user, if your language has been installed for this package, you -only have to set the `LANG' environment variable to the appropriate -`LL_CC' combination. If you happen to have the `LC_ALL' or some other -`LC_xxx' environment variables set, you should unset them before -setting `LANG', otherwise the setting of `LANG' will not have the -desired effect. Here `LL' is an ISO 639 two-letter language code, and -`CC' is an ISO 3166 two-letter country code. For example, let's -suppose that you speak German and live in Germany. At the shell -prompt, merely execute `setenv LANG de_DE' (in `csh'), -`export LANG; LANG=de_DE' (in `sh') or `export LANG=de_DE' (in `bash'). -This can be done from your `.login' or `.profile' file, once and for -all. - - You might think that the country code specification is redundant. -But in fact, some languages have dialects in different countries. For -example, `de_AT' is used for Austria, and `pt_BR' for Brazil. The -country code serves to distinguish the dialects. - - The locale naming convention of `LL_CC', with `LL' denoting the -language and `CC' denoting the country, is the one use on systems based -on GNU libc. On other systems, some variations of this scheme are -used, such as `LL' or `LL_CC.ENCODING'. You can get the list of -locales supported by your system for your language by running the -command `locale -a | grep '^LL''. - - Not all programs have translations for all languages. By default, an -English message is shown in place of a nonexistent translation. If you -understand other languages, you can set up a priority list of languages. -This is done through a different environment variable, called -`LANGUAGE'. GNU `gettext' gives preference to `LANGUAGE' over `LANG' -for the purpose of message handling, but you still need to have `LANG' -set to the primary language; this is required by other parts of the -system libraries. For example, some Swedish users who would rather -read translations in German than English for when Swedish is not -available, set `LANGUAGE' to `sv:de' while leaving `LANG' to `sv_SE'. - - Special advice for Norwegian users: The language code for Norwegian -bokma*l changed from `no' to `nb' recently (in 2003). During the -transition period, while some message catalogs for this language are -installed under `nb' and some older ones under `no', it's recommended -for Norwegian users to set `LANGUAGE' to `nb:no' so that both newer and -older translations are used. - - In the `LANGUAGE' environment variable, but not in the `LANG' -environment variable, `LL_CC' combinations can be abbreviated as `LL' -to denote the language's main dialect. For example, `de' is equivalent -to `de_DE' (German as spoken in Germany), and `pt' to `pt_PT' -(Portuguese as spoken in Portugal) in this context. - -1.4 Translating Teams -===================== - -For the Free Translation Project to be a success, we need interested -people who like their own language and write it well, and who are also -able to synergize with other translators speaking the same language. -Each translation team has its own mailing list. The up-to-date list of -teams can be found at the Free Translation Project's homepage, -`http://translationproject.org/', in the "Teams" area. - - If you'd like to volunteer to _work_ at translating messages, you -should become a member of the translating team for your own language. -The subscribing address is _not_ the same as the list itself, it has -`-request' appended. For example, speakers of Swedish can send a -message to `sv-request@li.org', having this message body: - - subscribe - - Keep in mind that team members are expected to participate -_actively_ in translations, or at solving translational difficulties, -rather than merely lurking around. If your team does not exist yet and -you want to start one, or if you are unsure about what to do or how to -get started, please write to `coordinator@translationproject.org' to -reach the coordinator for all translator teams. - - The English team is special. It works at improving and uniformizing -the terminology in use. Proven linguistic skills are praised more than -programming skills, here. - -1.5 Available Packages -====================== - -Languages are not equally supported in all packages. The following -matrix shows the current state of internationalization, as of November -2007. The matrix shows, in regard of each package, for which languages -PO files have been submitted to translation coordination, with a -translation percentage of at least 50%. - - Ready PO files af am ar az be bg bs ca cs cy da de el en en_GB eo - +----------------------------------------------------+ - Compendium | [] [] [] [] | - a2ps | [] [] [] [] [] | - aegis | () | - ant-phone | () | - anubis | [] | - ap-utils | | - aspell | [] [] [] [] [] | - bash | [] | - bfd | | - bibshelf | [] | - binutils | | - bison | [] [] | - bison-runtime | [] | - bluez-pin | [] [] [] [] [] | - cflow | [] | - clisp | [] [] [] | - console-tools | [] [] | - coreutils | [] [] [] [] | - cpio | | - cpplib | [] [] [] | - cryptonit | [] | - dialog | | - diffutils | [] [] [] [] [] [] | - doodle | [] | - e2fsprogs | [] [] | - enscript | [] [] [] [] | - fetchmail | [] [] () [] [] | - findutils | [] | - findutils_stable | [] [] [] | - flex | [] [] [] | - fslint | | - gas | | - gawk | [] [] [] | - gcal | [] | - gcc | [] | - gettext-examples | [] [] [] [] [] | - gettext-runtime | [] [] [] [] [] | - gettext-tools | [] [] | - gip | [] | - gliv | [] [] | - glunarclock | [] | - gmult | [] [] | - gnubiff | () | - gnucash | [] [] () () [] | - gnuedu | | - gnulib | [] | - gnunet | | - gnunet-gtk | | - gnutls | [] | - gpe-aerial | [] [] | - gpe-beam | [] [] | - gpe-calendar | | - gpe-clock | [] [] | - gpe-conf | [] [] | - gpe-contacts | | - gpe-edit | [] | - gpe-filemanager | | - gpe-go | [] | - gpe-login | [] [] | - gpe-ownerinfo | [] [] | - gpe-package | | - gpe-sketchbook | [] [] | - gpe-su | [] [] | - gpe-taskmanager | [] [] | - gpe-timesheet | [] | - gpe-today | [] [] | - gpe-todo | | - gphoto2 | [] [] [] [] | - gprof | [] [] | - gpsdrive | | - gramadoir | [] [] | - grep | [] [] | - gretl | () | - gsasl | | - gss | | - gst-plugins-bad | [] [] | - gst-plugins-base | [] [] | - gst-plugins-good | [] [] [] | - gst-plugins-ugly | [] [] | - gstreamer | [] [] [] [] [] [] [] | - gtick | () | - gtkam | [] [] [] [] | - gtkorphan | [] [] | - gtkspell | [] [] [] [] | - gutenprint | [] | - hello | [] [] [] [] [] | - herrie | [] | - hylafax | | - idutils | [] [] | - indent | [] [] [] [] | - iso_15924 | | - iso_3166 | [] [] [] [] [] [] [] [] [] [] [] | - iso_3166_2 | | - iso_4217 | [] [] [] | - iso_639 | [] [] [] [] | - jpilot | [] | - jtag | | - jwhois | | - kbd | [] [] [] [] | - keytouch | [] [] | - keytouch-editor | [] | - keytouch-keyboa... | [] | - latrine | () | - ld | [] | - leafpad | [] [] [] [] [] | - libc | [] [] [] [] | - libexif | [] | - libextractor | [] | - libgpewidget | [] [] [] | - libgpg-error | [] | - libgphoto2 | [] [] | - libgphoto2_port | [] [] | - libgsasl | | - libiconv | [] [] | - libidn | [] [] [] | - lifelines | [] () | - lilypond | [] | - lingoteach | | - lprng | | - lynx | [] [] [] [] | - m4 | [] [] [] [] | - mailfromd | | - mailutils | [] | - make | [] [] | - man-db | [] [] [] | - minicom | [] [] [] | - nano | [] [] [] | - opcodes | [] | - parted | [] [] | - pilot-qof | | - popt | [] [] [] | - psmisc | [] | - pwdutils | | - qof | | - radius | [] | - recode | [] [] [] [] [] [] | - rpm | [] | - screem | | - scrollkeeper | [] [] [] [] [] [] [] [] | - sed | [] [] [] | - shared-mime-info | [] [] [] [] () [] [] [] | - sharutils | [] [] [] [] [] [] | - shishi | | - skencil | [] () | - solfege | | - soundtracker | [] [] | - sp | [] | - system-tools-ba... | [] [] [] [] [] [] [] [] [] | - tar | [] [] | - texinfo | [] [] [] | - tin | () () | - tuxpaint | [] [] [] [] [] [] | - unicode-han-tra... | | - unicode-transla... | | - util-linux | [] [] [] [] | - util-linux-ng | [] [] [] [] | - vorbis-tools | [] | - wastesedge | () | - wdiff | [] [] [] [] | - wget | [] [] [] | - xchat | [] [] [] [] [] [] [] | - xkeyboard-config | [] | - xpad | [] [] [] | - +----------------------------------------------------+ - af am ar az be bg bs ca cs cy da de el en en_GB eo - 6 0 2 1 8 26 2 40 48 2 56 88 15 1 15 18 - - es et eu fa fi fr ga gl gu he hi hr hu id is it - +--------------------------------------------------+ - Compendium | [] [] [] [] [] | - a2ps | [] [] [] () | - aegis | | - ant-phone | [] | - anubis | [] | - ap-utils | [] [] | - aspell | [] [] [] | - bash | [] | - bfd | [] [] | - bibshelf | [] [] [] | - binutils | [] [] [] | - bison | [] [] [] [] [] [] | - bison-runtime | [] [] [] [] [] | - bluez-pin | [] [] [] [] [] | - cflow | [] | - clisp | [] [] | - console-tools | | - coreutils | [] [] [] [] [] [] | - cpio | [] [] [] | - cpplib | [] [] | - cryptonit | [] | - dialog | [] [] [] | - diffutils | [] [] [] [] [] [] [] [] [] | - doodle | [] [] | - e2fsprogs | [] [] [] | - enscript | [] [] [] | - fetchmail | [] | - findutils | [] [] [] | - findutils_stable | [] [] [] [] | - flex | [] [] [] | - fslint | | - gas | [] [] | - gawk | [] [] [] [] () | - gcal | [] [] | - gcc | [] | - gettext-examples | [] [] [] [] [] [] [] | - gettext-runtime | [] [] [] [] [] [] | - gettext-tools | [] [] [] [] | - gip | [] [] [] [] | - gliv | () | - glunarclock | [] [] [] | - gmult | [] [] [] | - gnubiff | () () | - gnucash | () () () | - gnuedu | [] | - gnulib | [] [] [] | - gnunet | | - gnunet-gtk | | - gnutls | | - gpe-aerial | [] [] | - gpe-beam | [] [] | - gpe-calendar | | - gpe-clock | [] [] [] [] | - gpe-conf | [] | - gpe-contacts | [] [] | - gpe-edit | [] [] [] [] | - gpe-filemanager | [] | - gpe-go | [] [] [] | - gpe-login | [] [] [] | - gpe-ownerinfo | [] [] [] [] [] | - gpe-package | [] | - gpe-sketchbook | [] [] | - gpe-su | [] [] [] [] | - gpe-taskmanager | [] [] [] | - gpe-timesheet | [] [] [] [] | - gpe-today | [] [] [] [] | - gpe-todo | [] | - gphoto2 | [] [] [] [] [] | - gprof | [] [] [] [] [] | - gpsdrive | [] | - gramadoir | [] [] | - grep | [] [] [] | - gretl | [] [] [] () | - gsasl | [] [] | - gss | [] [] | - gst-plugins-bad | [] [] [] [] | - gst-plugins-base | [] [] [] [] | - gst-plugins-good | [] [] [] [] [] | - gst-plugins-ugly | [] [] [] [] | - gstreamer | [] [] [] | - gtick | [] [] [] | - gtkam | [] [] [] [] | - gtkorphan | [] [] | - gtkspell | [] [] [] [] [] [] [] | - gutenprint | [] | - hello | [] [] [] [] [] [] [] [] [] [] [] [] [] | - herrie | [] | - hylafax | | - idutils | [] [] [] [] [] | - indent | [] [] [] [] [] [] [] [] [] [] | - iso_15924 | [] | - iso_3166 | [] [] [] [] [] [] [] [] [] [] [] [] [] | - iso_3166_2 | [] | - iso_4217 | [] [] [] [] [] [] | - iso_639 | [] [] [] [] [] [] | - jpilot | [] [] | - jtag | [] | - jwhois | [] [] [] [] [] | - kbd | [] [] | - keytouch | [] [] [] | - keytouch-editor | [] | - keytouch-keyboa... | [] [] | - latrine | [] [] | - ld | [] [] [] [] | - leafpad | [] [] [] [] [] [] | - libc | [] [] [] [] [] | - libexif | [] | - libextractor | [] | - libgpewidget | [] [] [] [] [] | - libgpg-error | [] | - libgphoto2 | [] [] [] | - libgphoto2_port | [] [] | - libgsasl | [] [] | - libiconv | [] [] [] | - libidn | [] [] | - lifelines | () | - lilypond | [] [] [] | - lingoteach | [] [] [] | - lprng | | - lynx | [] [] [] | - m4 | [] [] [] [] | - mailfromd | | - mailutils | [] [] | - make | [] [] [] [] [] [] [] [] | - man-db | [] | - minicom | [] [] [] [] | - nano | [] [] [] [] [] [] [] | - opcodes | [] [] [] [] | - parted | [] [] [] | - pilot-qof | | - popt | [] [] [] [] | - psmisc | [] [] | - pwdutils | | - qof | [] | - radius | [] [] | - recode | [] [] [] [] [] [] [] [] | - rpm | [] [] | - screem | | - scrollkeeper | [] [] [] | - sed | [] [] [] [] [] | - shared-mime-info | [] [] [] [] [] [] | - sharutils | [] [] [] [] [] [] [] [] | - shishi | [] | - skencil | [] [] | - solfege | [] | - soundtracker | [] [] [] | - sp | [] | - system-tools-ba... | [] [] [] [] [] [] [] [] [] | - tar | [] [] [] [] [] | - texinfo | [] [] [] | - tin | [] () | - tuxpaint | [] [] | - unicode-han-tra... | | - unicode-transla... | [] [] | - util-linux | [] [] [] [] [] [] [] | - util-linux-ng | [] [] [] [] [] [] [] | - vorbis-tools | | - wastesedge | () | - wdiff | [] [] [] [] [] [] [] [] | - wget | [] [] [] [] [] [] [] [] | - xchat | [] [] [] [] [] [] [] | - xkeyboard-config | [] [] [] [] | - xpad | [] [] [] | - +--------------------------------------------------+ - es et eu fa fi fr ga gl gu he hi hr hu id is it - 85 22 14 2 48 101 61 12 2 8 2 6 53 29 1 52 - - ja ka ko ku ky lg lt lv mk mn ms mt nb ne nl nn - +--------------------------------------------------+ - Compendium | [] | - a2ps | () [] [] | - aegis | () | - ant-phone | [] | - anubis | [] [] [] | - ap-utils | [] | - aspell | [] [] | - bash | [] | - bfd | | - bibshelf | [] | - binutils | | - bison | [] [] [] | - bison-runtime | [] [] [] | - bluez-pin | [] [] [] | - cflow | | - clisp | [] | - console-tools | | - coreutils | [] | - cpio | [] | - cpplib | [] | - cryptonit | [] | - dialog | [] [] | - diffutils | [] [] [] | - doodle | | - e2fsprogs | [] | - enscript | [] | - fetchmail | [] [] | - findutils | [] | - findutils_stable | [] | - flex | [] [] | - fslint | | - gas | | - gawk | [] [] | - gcal | | - gcc | | - gettext-examples | [] [] [] | - gettext-runtime | [] [] [] | - gettext-tools | [] [] | - gip | [] [] | - gliv | [] | - glunarclock | [] [] | - gmult | [] [] [] | - gnubiff | | - gnucash | () () () | - gnuedu | | - gnulib | [] [] | - gnunet | | - gnunet-gtk | | - gnutls | [] | - gpe-aerial | [] | - gpe-beam | [] | - gpe-calendar | [] | - gpe-clock | [] [] [] | - gpe-conf | [] [] [] | - gpe-contacts | [] | - gpe-edit | [] [] [] | - gpe-filemanager | [] [] | - gpe-go | [] [] [] | - gpe-login | [] [] [] | - gpe-ownerinfo | [] [] | - gpe-package | [] [] | - gpe-sketchbook | [] [] | - gpe-su | [] [] [] | - gpe-taskmanager | [] [] [] [] | - gpe-timesheet | [] | - gpe-today | [] [] | - gpe-todo | [] | - gphoto2 | [] [] | - gprof | [] | - gpsdrive | [] | - gramadoir | () | - grep | [] [] | - gretl | | - gsasl | [] | - gss | | - gst-plugins-bad | [] | - gst-plugins-base | [] | - gst-plugins-good | [] | - gst-plugins-ugly | [] | - gstreamer | [] | - gtick | [] | - gtkam | [] [] | - gtkorphan | [] | - gtkspell | [] [] | - gutenprint | [] | - hello | [] [] [] [] [] [] [] | - herrie | [] | - hylafax | | - idutils | [] | - indent | [] [] | - iso_15924 | [] | - iso_3166 | [] [] [] [] [] [] [] [] | - iso_3166_2 | [] | - iso_4217 | [] [] [] | - iso_639 | [] [] [] [] | - jpilot | () () | - jtag | | - jwhois | [] | - kbd | [] | - keytouch | [] | - keytouch-editor | [] | - keytouch-keyboa... | | - latrine | [] | - ld | | - leafpad | [] [] | - libc | [] [] [] | - libexif | | - libextractor | | - libgpewidget | [] | - libgpg-error | | - libgphoto2 | [] | - libgphoto2_port | [] | - libgsasl | [] | - libiconv | [] | - libidn | [] [] | - lifelines | [] | - lilypond | [] | - lingoteach | [] | - lprng | | - lynx | [] [] | - m4 | [] [] | - mailfromd | | - mailutils | | - make | [] [] [] | - man-db | | - minicom | [] | - nano | [] [] [] | - opcodes | [] | - parted | [] [] | - pilot-qof | | - popt | [] [] [] | - psmisc | [] [] [] | - pwdutils | | - qof | | - radius | | - recode | [] | - rpm | [] [] | - screem | [] | - scrollkeeper | [] [] [] [] | - sed | [] [] | - shared-mime-info | [] [] [] [] [] [] [] | - sharutils | [] [] | - shishi | | - skencil | | - solfege | () () | - soundtracker | | - sp | () | - system-tools-ba... | [] [] [] [] | - tar | [] [] [] | - texinfo | [] [] | - tin | | - tuxpaint | () [] [] | - unicode-han-tra... | | - unicode-transla... | | - util-linux | [] [] | - util-linux-ng | [] [] | - vorbis-tools | | - wastesedge | [] | - wdiff | [] [] | - wget | [] [] | - xchat | [] [] [] [] | - xkeyboard-config | [] [] [] | - xpad | [] [] [] | - +--------------------------------------------------+ - ja ka ko ku ky lg lt lv mk mn ms mt nb ne nl nn - 51 2 25 3 2 0 6 0 2 2 20 0 11 1 103 6 - - or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv ta - +--------------------------------------------------+ - Compendium | [] [] [] [] [] | - a2ps | () [] [] [] [] [] [] | - aegis | () () | - ant-phone | [] [] | - anubis | [] [] [] | - ap-utils | () | - aspell | [] [] [] | - bash | [] [] | - bfd | | - bibshelf | [] | - binutils | [] [] | - bison | [] [] [] [] [] | - bison-runtime | [] [] [] [] [] | - bluez-pin | [] [] [] [] [] [] [] [] [] | - cflow | [] | - clisp | [] | - console-tools | [] | - coreutils | [] [] [] [] | - cpio | [] [] [] | - cpplib | [] | - cryptonit | [] [] | - dialog | [] | - diffutils | [] [] [] [] [] [] | - doodle | [] [] | - e2fsprogs | [] [] | - enscript | [] [] [] [] [] | - fetchmail | [] [] [] | - findutils | [] [] [] | - findutils_stable | [] [] [] [] [] [] | - flex | [] [] [] [] [] | - fslint | [] | - gas | | - gawk | [] [] [] [] | - gcal | [] | - gcc | [] [] | - gettext-examples | [] [] [] [] [] [] [] [] | - gettext-runtime | [] [] [] [] [] [] [] [] | - gettext-tools | [] [] [] [] [] [] [] | - gip | [] [] [] [] | - gliv | [] [] [] [] [] [] | - glunarclock | [] [] [] [] [] [] | - gmult | [] [] [] [] | - gnubiff | () [] | - gnucash | () [] | - gnuedu | | - gnulib | [] [] [] | - gnunet | | - gnunet-gtk | [] | - gnutls | [] [] | - gpe-aerial | [] [] [] [] [] [] [] | - gpe-beam | [] [] [] [] [] [] [] | - gpe-calendar | [] [] [] [] | - gpe-clock | [] [] [] [] [] [] [] [] | - gpe-conf | [] [] [] [] [] [] [] | - gpe-contacts | [] [] [] [] [] | - gpe-edit | [] [] [] [] [] [] [] [] [] | - gpe-filemanager | [] [] | - gpe-go | [] [] [] [] [] [] [] [] | - gpe-login | [] [] [] [] [] [] [] [] | - gpe-ownerinfo | [] [] [] [] [] [] [] [] | - gpe-package | [] [] | - gpe-sketchbook | [] [] [] [] [] [] [] [] | - gpe-su | [] [] [] [] [] [] [] [] | - gpe-taskmanager | [] [] [] [] [] [] [] [] | - gpe-timesheet | [] [] [] [] [] [] [] [] | - gpe-today | [] [] [] [] [] [] [] [] | - gpe-todo | [] [] [] [] | - gphoto2 | [] [] [] [] [] [] | - gprof | [] [] [] | - gpsdrive | [] [] | - gramadoir | [] [] | - grep | [] [] [] [] | - gretl | [] [] [] | - gsasl | [] [] [] | - gss | [] [] [] [] | - gst-plugins-bad | [] [] [] | - gst-plugins-base | [] [] | - gst-plugins-good | [] [] | - gst-plugins-ugly | [] [] [] | - gstreamer | [] [] [] [] | - gtick | [] | - gtkam | [] [] [] [] [] | - gtkorphan | [] | - gtkspell | [] [] [] [] [] [] [] [] | - gutenprint | [] | - hello | [] [] [] [] [] [] [] [] | - herrie | [] [] [] | - hylafax | | - idutils | [] [] [] [] [] | - indent | [] [] [] [] [] [] [] | - iso_15924 | | - iso_3166 | [] [] [] [] [] [] [] [] [] [] [] [] [] | - iso_3166_2 | | - iso_4217 | [] [] [] [] [] [] [] | - iso_639 | [] [] [] [] [] [] [] | - jpilot | | - jtag | [] | - jwhois | [] [] [] [] | - kbd | [] [] [] | - keytouch | [] | - keytouch-editor | [] | - keytouch-keyboa... | [] | - latrine | | - ld | [] | - leafpad | [] [] [] [] [] [] | - libc | [] [] [] [] | - libexif | [] [] | - libextractor | [] [] | - libgpewidget | [] [] [] [] [] [] [] [] | - libgpg-error | [] [] [] | - libgphoto2 | [] | - libgphoto2_port | [] [] [] | - libgsasl | [] [] [] [] | - libiconv | [] [] [] | - libidn | [] [] () | - lifelines | [] [] | - lilypond | | - lingoteach | [] | - lprng | [] | - lynx | [] [] [] | - m4 | [] [] [] [] [] | - mailfromd | [] | - mailutils | [] [] [] | - make | [] [] [] [] | - man-db | [] [] [] [] | - minicom | [] [] [] [] [] | - nano | [] [] [] [] | - opcodes | [] [] | - parted | [] | - pilot-qof | | - popt | [] [] [] [] | - psmisc | [] [] | - pwdutils | [] [] | - qof | [] [] | - radius | [] [] | - recode | [] [] [] [] [] [] [] | - rpm | [] [] [] [] | - screem | | - scrollkeeper | [] [] [] [] [] [] [] | - sed | [] [] [] [] [] [] [] [] [] | - shared-mime-info | [] [] [] [] [] [] | - sharutils | [] [] [] [] | - shishi | [] | - skencil | [] [] [] | - solfege | [] | - soundtracker | [] [] | - sp | | - system-tools-ba... | [] [] [] [] [] [] [] [] [] | - tar | [] [] [] [] | - texinfo | [] [] [] [] | - tin | () | - tuxpaint | [] [] [] [] [] [] | - unicode-han-tra... | | - unicode-transla... | | - util-linux | [] [] [] [] | - util-linux-ng | [] [] [] [] | - vorbis-tools | [] | - wastesedge | | - wdiff | [] [] [] [] [] [] [] | - wget | [] [] [] [] | - xchat | [] [] [] [] [] [] [] | - xkeyboard-config | [] [] [] | - xpad | [] [] [] | - +--------------------------------------------------+ - or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv ta - 0 5 77 31 53 4 58 72 3 45 46 9 45 122 3 - - tg th tk tr uk ven vi wa xh zh_CN zh_HK zh_TW zu - +---------------------------------------------------+ - Compendium | [] [] [] [] | 19 - a2ps | [] [] [] | 19 - aegis | [] | 1 - ant-phone | [] [] | 6 - anubis | [] [] [] | 11 - ap-utils | () [] | 4 - aspell | [] [] [] | 16 - bash | [] | 6 - bfd | | 2 - bibshelf | [] | 7 - binutils | [] [] [] [] | 9 - bison | [] [] [] [] | 20 - bison-runtime | [] [] [] [] | 18 - bluez-pin | [] [] [] [] [] [] | 28 - cflow | [] [] | 5 - clisp | | 9 - console-tools | [] [] | 5 - coreutils | [] [] [] | 18 - cpio | [] [] [] [] | 11 - cpplib | [] [] [] [] [] | 12 - cryptonit | [] | 6 - dialog | [] [] [] | 9 - diffutils | [] [] [] [] [] | 29 - doodle | [] | 6 - e2fsprogs | [] [] | 10 - enscript | [] [] [] | 16 - fetchmail | [] [] | 12 - findutils | [] [] [] | 11 - findutils_stable | [] [] [] [] | 18 - flex | [] [] | 15 - fslint | [] | 2 - gas | [] | 3 - gawk | [] [] [] | 16 - gcal | [] | 5 - gcc | [] [] [] | 7 - gettext-examples | [] [] [] [] [] [] | 29 - gettext-runtime | [] [] [] [] [] [] | 28 - gettext-tools | [] [] [] [] [] | 20 - gip | [] [] | 13 - gliv | [] [] | 11 - glunarclock | [] [] [] | 15 - gmult | [] [] [] [] | 16 - gnubiff | [] | 2 - gnucash | () [] | 5 - gnuedu | [] | 2 - gnulib | [] | 10 - gnunet | | 0 - gnunet-gtk | [] [] | 3 - gnutls | | 4 - gpe-aerial | [] [] | 14 - gpe-beam | [] [] | 14 - gpe-calendar | [] [] | 7 - gpe-clock | [] [] [] [] | 21 - gpe-conf | [] [] [] | 16 - gpe-contacts | [] [] | 10 - gpe-edit | [] [] [] [] [] | 22 - gpe-filemanager | [] [] | 7 - gpe-go | [] [] [] [] | 19 - gpe-login | [] [] [] [] [] | 21 - gpe-ownerinfo | [] [] [] [] | 21 - gpe-package | [] | 6 - gpe-sketchbook | [] [] | 16 - gpe-su | [] [] [] [] | 21 - gpe-taskmanager | [] [] [] [] | 21 - gpe-timesheet | [] [] [] [] | 18 - gpe-today | [] [] [] [] [] | 21 - gpe-todo | [] [] | 8 - gphoto2 | [] [] [] [] | 21 - gprof | [] [] | 13 - gpsdrive | [] | 5 - gramadoir | [] | 7 - grep | [] | 12 - gretl | | 6 - gsasl | [] [] [] | 9 - gss | [] | 7 - gst-plugins-bad | [] [] [] | 13 - gst-plugins-base | [] [] | 11 - gst-plugins-good | [] [] [] [] [] | 16 - gst-plugins-ugly | [] [] [] | 13 - gstreamer | [] [] [] | 18 - gtick | [] [] | 7 - gtkam | [] | 16 - gtkorphan | [] | 7 - gtkspell | [] [] [] [] [] [] | 27 - gutenprint | | 4 - hello | [] [] [] [] [] | 38 - herrie | [] [] | 8 - hylafax | | 0 - idutils | [] [] | 15 - indent | [] [] [] [] [] | 28 - iso_15924 | [] [] | 4 - iso_3166 | [] [] [] [] [] [] [] [] [] | 54 - iso_3166_2 | [] [] | 4 - iso_4217 | [] [] [] [] [] | 24 - iso_639 | [] [] [] [] [] | 26 - jpilot | [] [] [] [] | 7 - jtag | [] | 3 - jwhois | [] [] [] | 13 - kbd | [] [] [] | 13 - keytouch | [] | 8 - keytouch-editor | [] | 5 - keytouch-keyboa... | [] | 5 - latrine | [] [] | 5 - ld | [] [] [] [] | 10 - leafpad | [] [] [] [] [] | 24 - libc | [] [] [] | 19 - libexif | [] | 5 - libextractor | [] | 5 - libgpewidget | [] [] [] | 20 - libgpg-error | [] | 6 - libgphoto2 | [] [] | 9 - libgphoto2_port | [] [] [] | 11 - libgsasl | [] | 8 - libiconv | [] [] | 11 - libidn | [] [] | 11 - lifelines | | 4 - lilypond | [] | 6 - lingoteach | [] | 6 - lprng | [] | 2 - lynx | [] [] [] | 15 - m4 | [] [] [] | 18 - mailfromd | [] [] | 3 - mailutils | [] [] | 8 - make | [] [] [] | 20 - man-db | [] | 9 - minicom | [] | 14 - nano | [] [] [] | 20 - opcodes | [] [] | 10 - parted | [] [] [] | 11 - pilot-qof | [] | 1 - popt | [] [] [] [] | 18 - psmisc | [] [] | 10 - pwdutils | [] | 3 - qof | [] | 4 - radius | [] [] | 7 - recode | [] [] [] | 25 - rpm | [] [] [] [] | 13 - screem | [] | 2 - scrollkeeper | [] [] [] [] | 26 - sed | [] [] [] [] | 23 - shared-mime-info | [] [] [] | 29 - sharutils | [] [] [] | 23 - shishi | [] | 3 - skencil | [] | 7 - solfege | [] | 3 - soundtracker | [] [] | 9 - sp | [] | 3 - system-tools-ba... | [] [] [] [] [] [] [] | 38 - tar | [] [] [] | 17 - texinfo | [] [] [] | 15 - tin | | 1 - tuxpaint | [] [] [] | 19 - unicode-han-tra... | | 0 - unicode-transla... | | 2 - util-linux | [] [] [] | 20 - util-linux-ng | [] [] [] | 20 - vorbis-tools | [] [] | 4 - wastesedge | | 1 - wdiff | [] [] | 23 - wget | [] [] [] | 20 - xchat | [] [] [] [] | 29 - xkeyboard-config | [] [] [] | 14 - xpad | [] [] [] | 15 - +---------------------------------------------------+ - 76 teams tg th tk tr uk ven vi wa xh zh_CN zh_HK zh_TW zu - 163 domains 0 3 1 74 51 0 143 21 1 57 7 45 0 2036 - - Some counters in the preceding matrix are higher than the number of -visible blocks let us expect. This is because a few extra PO files are -used for implementing regional variants of languages, or language -dialects. - - For a PO file in the matrix above to be effective, the package to -which it applies should also have been internationalized and -distributed as such by its maintainer. There might be an observable -lag between the mere existence a PO file and its wide availability in a -distribution. - - If November 2007 seems to be old, you may fetch a more recent copy -of this `ABOUT-NLS' file on most GNU archive sites. The most -up-to-date matrix with full percentage details can be found at -`http://translationproject.org/extra/matrix.html'. - -1.6 Using `gettext' in new packages -=================================== - -If you are writing a freely available program and want to -internationalize it you are welcome to use GNU `gettext' in your -package. Of course you have to respect the GNU Library General Public -License which covers the use of the GNU `gettext' library. This means -in particular that even non-free programs can use `libintl' as a shared -library, whereas only free software can use `libintl' as a static -library or use modified versions of `libintl'. - - Once the sources are changed appropriately and the setup can handle -the use of `gettext' the only thing missing are the translations. The -Free Translation Project is also available for packages which are not -developed inside the GNU project. Therefore the information given above -applies also for every other Free Software Project. Contact -`coordinator@translationproject.org' to make the `.pot' files available -to the translation teams. - diff --git a/AUTHORS b/AUTHORS index 54a20ce..a36c116 100644 --- a/AUTHORS +++ b/AUTHORS @@ -2,7 +2,15 @@ Valient Gough -Also, thanks to the work of many contributors, encfs as of 1.1.11 now has -full or partial translations for many languages. -See README-NLS and TRANSLATORS for more details. +With significant contributions from: + +Csaba Henk +David Rosenstrauch +Gerald Klix +Janne Hellsten +p.kosseff + + +Also, thanks to the work of many contributors, encfs has full or partial +translations for many languages. See README-NLS for more details. diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..a7fe73c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,67 @@ +cmake_minimum_required(VERSION 2.8) +project(Encfs) + +set (ENCFS_MAJOR 2) +set (ENCFS_MINOR 0) +set (ENCFS_PATCH 0) +set (ENCFS_VERSION "${ENCFS_MAJOR}.${ENCFS_MINOR}.${ENCFS_PATCH}") + +option (BUILD_SHARED_LIBS "Build dynamic link libraries" OFF) + +set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + "${CMAKE_SOURCE_DIR}/CMakeModules/") + +set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall") + +set (CPACK_PACKAGE_NAME "Encfs") +set (CPACK_PACKAGE_VERSION_MAJOR ${ENCFS_MAJOR}) +set (CPACK_PACKAGE_VERSION_MINOR ${ENCFS_MINOR}) +set (CPACK_PACKAGE_VERSION_PATCH ${ENCFS_PATCH}) +set (CPACK_SOURCE_GENERATOR TGZ) +set (CPACK_SOURCE_IGNORE_FILES + "/_darcs/" + "/build/") +include (CPack) + +include (CheckIncludeFileCXX) +check_include_file_cxx (attr/xattr.h HAVE_ATTR_XATTR_H) +check_include_file_cxx (sys/xattr.h HAVE_SYS_XATTR_H) + +check_include_file_cxx (tr1/memory HAVE_TR1_MEMORY) +check_include_file_cxx (tr1/unordered_map HAVE_TR1_UNORDERED_MAP) +check_include_file_cxx (tr1/unordered_set HAVE_TR1_UNORDERED_SET) +check_include_file_cxx (tr1/tuple HAVE_TR1_TUPLE) + +check_include_file_cxx (valgrind/valgrind.h HAVE_VALGRIND_VALGRIND_H) +check_include_file_cxx (valgrind/memcheck.h HAVE_VALGRIND_MEMCHECK_H) + +# TODO: move this to cipher directory. +find_package (OpenSSL REQUIRED) +include (OpenSSLTests) + +# Check if xattr functions take extra argument. +include (CheckCXXSourceCompiles) +CHECK_CXX_SOURCE_COMPILES ("#include + #include + int main() { getxattr(0,0,0,0,0,0); return 1; } " XATTR_ADD_OPT) + +add_definitions (-D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=26) +if (APPLE) + add_definitions (-D__FreeBSD__=10) +endif (APPLE) + +find_package (GLog REQUIRED) +include_directories (${GLOG_INCLUDE_DIRS}) + +find_program (POD2MAN pod2man) + +include_directories (${Encfs_BINARY_DIR}) +include_directories (${Encfs_SOURCE_DIR}) + +add_subdirectory(base) +add_subdirectory(cipher) +add_subdirectory(fs) +add_subdirectory(encfs) +add_subdirectory(util) +add_subdirectory(po) + diff --git a/CMakeModules/FindFUSE.cmake b/CMakeModules/FindFUSE.cmake new file mode 100644 index 0000000..2458c00 --- /dev/null +++ b/CMakeModules/FindFUSE.cmake @@ -0,0 +1,35 @@ +# Find the FUSE includes and library +# +# FUSE_INCLUDE_DIR - where to find fuse.h, etc. +# FUSE_LIBRARIES - List of libraries when using FUSE. +# FUSE_FOUND - True if FUSE lib is found. + +# check if already in cache, be silent +IF (FUSE_INCLUDE_DIR) + SET (FUSE_FIND_QUIETLY TRUE) +ENDIF (FUSE_INCLUDE_DIR) + +# find includes +FIND_PATH (FUSE_INCLUDE_DIR fuse.h + /usr/local/include/osxfuse + /usr/local/include + /usr/include +) + +# find lib +if (APPLE) + SET(FUSE_NAMES libosxfuse.dylib fuse) +else (APPLE) + SET(FUSE_NAMES fuse) +endif (APPLE) +FIND_LIBRARY(FUSE_LIBRARIES + NAMES ${FUSE_NAMES} + PATHS /lib64 /lib /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib +) + +include ("FindPackageHandleStandardArgs") +find_package_handle_standard_args ("FUSE" DEFAULT_MSG + FUSE_INCLUDE_DIR FUSE_LIBRARIES) + +mark_as_advanced (FUSE_INCLUDE_DIR FUSE_LIBRARIES) + diff --git a/CMakeModules/FindGLog.cmake b/CMakeModules/FindGLog.cmake new file mode 100644 index 0000000..a4960ee --- /dev/null +++ b/CMakeModules/FindGLog.cmake @@ -0,0 +1,59 @@ +# Try to find the libglog libraries +# Once done this will define : +# +# Glog_FOUND - system has libglog +# Glog_INCLUDE_DIRS - the libglog include directory +# Glog_LIBRARIES - libglog library + +# Inputs to this module: +# GLOG_ROOT The preferred installation prefix for searching for glog. Set +# this if the module has problems finding the proper glog installation. + +# If GLOG_ROOT was defined in the environment, use it. +IF (NOT GLOG_ROOT AND NOT $ENV{GLOG_ROOT} STREQUAL "") + SET(GLOG_ROOT $ENV{GLOG_ROOT}) +ENDIF(NOT GLOG_ROOT AND NOT $ENV{GLOG_ROOT} STREQUAL "") +IF( GLOG_ROOT ) + file(TO_CMAKE_PATH ${GLOG_ROOT} GLOG_ROOT) +ENDIF( GLOG_ROOT ) + +SET (GLOG_INCLUDE_DIRS) +SET (GLOG_LIBRARIES) +IF(WIN32) + IF(MSVC) + FIND_PATH(GLOG_INCLUDE_DIRS NAMES src/windows/glog/logging.h HINTS ${GLOG_ROOT}) + IF(GLOG_INCLUDE_DIRS) + SET(GLOG_INCLUDE_DIRS ${GLOG_INCLUDE_DIRS}/src/windows) + ENDIF(GLOG_INCLUDE_DIRS) + + IF (CMAKE_BUILD_TYPE STREQUAL "Release") + message (STATUS " searching ${GLOG_ROOT}/Release/libglog.lib ...") + FIND_LIBRARY(GLOG_LIBRARIES NAMES libglog.lib HINTS ${GLOG_ROOT}/Release $ENV{LIB} PATH_SUFFIXES ".lib") + ELSE (CMAKE_BUILD_TYPE STREQUAL "Release") + message (STATUS " searching ${GLOG_ROOT}/Debug/libglog.lib ...") + FIND_LIBRARY(GLOG_LIBRARIES NAMES libglog.lib HINTS ${GLOG_ROOT}/Debug $ENV{LIB} PATH_SUFFIXES ".lib") + ENDIF (CMAKE_BUILD_TYPE STREQUAL "Release") + ELSE(MSVC) + SET(Glog_FOUND FALSE) + message (STATUS " Crap. this module supports only MSVC in Windows.") + ENDIF(MSVC) +ELSE(WIN32) + FIND_PATH(GLOG_INCLUDE_DIRS NAMES glog/logging.h HINTS ${GLOG_ROOT}/include ${GLOG_ROOT} /include/ /usr/include/ /usr/local/include/ /opt/local/include/) + FIND_LIBRARY(GLOG_LIBRARIES NAMES glog HINTS ${GLOG_ROOT}/lib ${GLOG_ROOT} /lib /usr/lib /usr/local/lib /opt/local/lib) +ENDIF(WIN32) + +IF(GLOG_INCLUDE_DIRS AND GLOG_LIBRARIES) + SET(Glog_FOUND TRUE) + message (STATUS " glog found in include=${GLOG_INCLUDE_DIRS},lib=${GLOG_LIBRARIES}") +ELSE(GLOG_INCLUDE_DIRS AND GLOG_LIBRARIES) + SET(Glog_FOUND FALSE) + message (STATUS " glog not found. Please set GLOG_ROOT to the root directory containing glog.") + IF(GLOG_INCLUDE_DIRS) + message (STATUS " include=${GLOG_INCLUDE_DIRS}, but lib not found") + ENDIF(GLOG_INCLUDE_DIRS) + IF(GLOG_LIBRARIES) + message (STATUS " lib=${GLOG_LIBRARIES}, but include not found") + ENDIF(GLOG_LIBRARIES) +ENDIF(GLOG_INCLUDE_DIRS AND GLOG_LIBRARIES) + +MARK_AS_ADVANCED(GLOG_INCLUDE_DIRS GLOG_LIBRARIES) diff --git a/CMakeModules/FindTinyXML.cmake b/CMakeModules/FindTinyXML.cmake new file mode 100644 index 0000000..2f3bc3c --- /dev/null +++ b/CMakeModules/FindTinyXML.cmake @@ -0,0 +1,26 @@ +# - Find TinyXML +# Find the native TinyXML includes and library +# +# TINYXML_FOUND - True if TinyXML found. +# TINYXML_INCLUDE_DIR - where to find tinyxml.h, etc. +# TINYXML_LIBRARIES - List of libraries when using TinyXML. +# + +IF( TINYXML_INCLUDE_DIR ) + # Already in cache, be silent + SET( TinyXML_FIND_QUIETLY TRUE ) +ENDIF( TINYXML_INCLUDE_DIR ) + +FIND_PATH( TINYXML_INCLUDE_DIR "tinyxml.h" + PATH_SUFFIXES "tinyxml" ) + +FIND_LIBRARY( TINYXML_LIBRARIES + NAMES "tinyxml" + PATH_SUFFIXES "tinyxml" ) + +# handle the QUIETLY and REQUIRED arguments and set TINYXML_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE( "FindPackageHandleStandardArgs" ) +FIND_PACKAGE_HANDLE_STANDARD_ARGS( "TinyXML" DEFAULT_MSG TINYXML_INCLUDE_DIR TINYXML_LIBRARIES ) + +MARK_AS_ADVANCED( TINYXML_INCLUDE_DIR TINYXML_LIBRARIES ) diff --git a/CMakeModules/GettextTranslate.cmake b/CMakeModules/GettextTranslate.cmake new file mode 100644 index 0000000..e6b5d20 --- /dev/null +++ b/CMakeModules/GettextTranslate.cmake @@ -0,0 +1,287 @@ +# Copyright (c) 2012, Jarryd Beck +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + + +# This module creates build rules for updating translation files made +# with gettext +# In your top level CMakeLists.txt, do +# include(GettextTranslate) +# then in any po directory where you want things to be translated, write +# GettextTranslate() +# +# This module also finds the gettext binaries. If these are in a non-standard +# location, you can define the following variables to provide paths to search +# in +# GettextTranslate_BINARIES --- a path in which to look for every program +# GettextTranslate_XGETTEXT --- the xgettext program +# GettextTranslate_MSGINIT --- the msginit program +# GettextTranslate_MSGFILTER --- the msgfilter program +# GettextTranslate_MSGCONV --- the msgconv program +# GettextTranslate_MSGMERGE --- the msgmerge program +# GettextTranslate_MSGFMT --- the msgfmt program +# these are searched first before $PATH, so set this if you have your own +# version that overrides the system version +# +# it reads variables from Makevars, one of the most important being DOMAIN +# it reads the languages to generate from LINGUAS +# +# it adds the following targets +# update-po +# update-gmo +# ${DOMAIN}-pot.update +# generate-${DOMAIN}-${lang}-po +# generate-${DOMAIN}-${lang}-gmo +# +# where ${DOMAIN} is the DOMAIN variable read from Makevars +# and ${lang} is each language mentioned in LINGUAS +# +# if you want update-gmo to be added to the "all" target, then define the +# variable GettextTranslate_ALL before including this file +# +# by default, the gmo files are built in the source directory. If you want +# them to be built in the binary directory, then define the variable +# GettextTranslate_GMO_BINARY + + + +# add the update-po and update-gmo targets, the actual files that need to +# depend on this will be added as we go + +if (DEFINED GettextTranslate_ALL) + set(_addToALL "ALL") +endif() + +add_custom_target(update-po) +add_custom_target(update-gmo ${_addToALL}) + +#look for all the programs +#xgettext, msginit, msgfilter, msgconv, msgmerge, msgfmt + +function(REQUIRE_BINARY binname varname) + if (defined ${${varname}-NOTFOUND}) + message(FATAL_ERROR "Could not find " binname) + endif() +endfunction() + +find_program(GettextTranslate_XGETTEXT_EXECUTABLE xgettext + HINTS ${GettextTranslate_XGETTEXT} ${GettextTranslate_BINARIES} +) +REQUIRE_BINARY(xgettext GettextTranslate_XGETTEXT_EXECUTABLE) + +find_program(GettextTranslate_MSGINIT_EXECUTABLE msginit + HINTS ${GettextTranslate_MSGINIT} ${GettextTranslate_BINARIES} +) +REQUIRE_BINARY(msginit GettextTranslate_MSGINIT_EXECUTABLE) + +find_program(GettextTranslate_MSGFILTER_EXECUTABLE msgfilter + HINTS ${GettextTranslate_MSGFILTER} ${GettextTranslate_BINARIES} +) +REQUIRE_BINARY(msgfilter GettextTranslate_MSGFILTER_EXECUTABLE) + +find_program(GettextTranslate_MSGCONV_EXECUTABLE msgconv + HINTS ${GettextTranslate_MSGCONV} ${GettextTranslate_BINARIES} +) +REQUIRE_BINARY(msgconv GettextTranslate_MSGCONV_EXECUTABLE) + +find_program(GettextTranslate_MSGMERGE_EXECUTABLE msgmerge + HINTS ${GettextTranslate_MSGMERGE} ${GettextTranslate_BINARIES} +) +REQUIRE_BINARY(msgmerge GettextTranslate_MSGMERGE_EXECUTABLE) + +find_program(GettextTranslate_MSGFMT_EXECUTABLE msgfmt + HINTS ${GettextTranslate_MSGFMT} ${GettextTranslate_BINARIES} +) +REQUIRE_BINARY(msgfmt GettextTranslate_MSGFMT_EXECUTABLE) + +mark_as_advanced( + GettextTranslate_MSGCONV_EXECUTABLE + GettextTranslate_MSGFILTER_EXECUTABLE + GettextTranslate_MSGFMT_EXECUTABLE + GettextTranslate_MSGINIT_EXECUTABLE + GettextTranslate_MSGMERGE_EXECUTABLE + GettextTranslate_XGETTEXT_EXECUTABLE +) + +macro(GettextTranslate) + + if(GettextTranslate_GMO_BINARY) + set (GMO_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}) + else() + set (GMO_BUILD_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + endif() + + if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/POTFILES.in) + message(FATAL_ERROR "There is no POTFILES.in in + ${CMAKE_CURRENT_SOURCE_DIR}") + endif() + + if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/Makevars) + message(FATAL_ERROR "There is no Makevars in ${CMAKE_CURRENT_SOURCE_DIR}") + endif() + + file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/Makevars makevars + REGEX "^[^=]+=(.*)$" + ) + + foreach(makevar ${makevars}) + string(REGEX REPLACE "^([^= ]+) =[ ]?(.*)$" "\\1" MAKEVAR_KEY ${makevar}) + string(REGEX REPLACE "^([^= ]+) =[ ]?(.*)$" "\\2" + MAKEVAR_${MAKEVAR_KEY} ${makevar}) + endforeach() + + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/POTFILES.in + ${CMAKE_CURRENT_BINARY_DIR}/POTFILES + COPYONLY + ) + + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/LINGUAS + ${CMAKE_CURRENT_BINARY_DIR}/LINGUAS + COPYONLY + ) + + #set the directory to not clean + set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + PROPERTY CLEAN_NO_CUSTOM true) + + file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/POTFILES.in potfiles + REGEX "^[^#].*" + ) + + foreach(potfile ${potfiles}) + list(APPEND source_translatable + ${CMAKE_CURRENT_SOURCE_DIR}/${MAKEVAR_top_builddir}/${potfile}) + endforeach() + + set(TEMPLATE_FILE ${MAKEVAR_DOMAIN}.pot) + set(TEMPLATE_FILE_ABS ${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_FILE}) + string(REGEX MATCHALL "[^ ]+" XGETTEXT_OPTS ${MAKEVAR_XGETTEXT_OPTIONS}) + #add_custom_target(${MAKEVAR_DOMAIN}.pot-update DEPENDS + # ${TEMPLATE_FILE_ABS} + #) + + add_custom_target(${MAKEVAR_DOMAIN}.pot-update + COMMAND ${GettextTranslate_XGETTEXT_EXECUTABLE} ${XGETTEXT_OPTS} + -o ${TEMPLATE_FILE_ABS} + --default-domain=${MAKEVAR_DOMAIN} + --add-comments=TRANSLATORS: + --copyright-holder=${MAKEVAR_COPYRIGHT_HOLDER} + --msgid-bugs-address="${MAKEVAR_MSGID_BUGS_ADDRESS}" + --directory=${MAKEVAR_top_builddir} + --files-from=${CMAKE_CURRENT_BINARY_DIR}/POTFILES + --package-version=${VERSION} + --package-name=${CMAKE_PROJECT_NAME} + DEPENDS ${source_translatable} + ${CMAKE_CURRENT_SOURCE_DIR}/POTFILES.in + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + + #add_custom_command(OUTPUT ${TEMPLATE_FILE_ABS} + # COMMAND ${GettextTranslate_XGETTEXT_EXECUTABLE} ${XGETTEXT_OPTS} + # -o ${TEMPLATE_FILE_ABS} + # --default-domain=${MAKEVAR_DOMAIN} + # --add-comments=TRANSLATORS: + # --copyright-holder=${MAKEVAR_COPYRIGHT_HOLDER} + # --msgid-bugs-address="${MAKEVAR_MSGID_BUGS_ADDRESS}" + # --directory=${MAKEVAR_top_builddir} + # --files-from=${CMAKE_CURRENT_BINARY_DIR}/POTFILES + # --package-version=${VERSION} + # --package-name=${CMAKE_PROJECT_NAME} + # DEPENDS ${source_translatable} + # ${CMAKE_CURRENT_SOURCE_DIR}/POTFILES.in + # WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + #) + + #add_dependencies(update-po ${MAKEVAR_DOMAIN}.pot-update) + + file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/LINGUAS LINGUAS + REGEX "^[^#].*") + string(REGEX MATCHALL "[^ ]+" languages ${LINGUAS}) + + foreach(lang ${languages}) + set(PO_FILE_NAME "${CMAKE_CURRENT_SOURCE_DIR}/${lang}.po") + set(GMO_FILE_NAME "${GMO_BUILD_DIR}/${lang}.gmo") + set(PO_TARGET "generate-${MAKEVAR_DOMAIN}-${lang}-po") + set(GMO_TARGET "generate-${MAKEVAR_DOMAIN}-${lang}-gmo") + list(APPEND po_files ${PO_TARGET}) + list(APPEND gmo_files ${GMO_TARGET}) + + if(${lang} MATCHES "en@(.*)quot") + + add_custom_command(OUTPUT ${lang}.insert-header + COMMAND + sed -e "'/^#/d'" -e 's/HEADER/${lang}.header/g' + ${CMAKE_CURRENT_SOURCE_DIR}/insert-header.sin > ${lang}.insert-header + ) + + #generate the en@quot files + add_custom_command(OUTPUT ${PO_FILE_NAME} + COMMAND + ${GettextTranslate_MSGINIT_EXECUTABLE} -i ${TEMPLATE_FILE_ABS} + --no-translator -l ${lang} + -o - 2>/dev/null + | sed -f ${CMAKE_CURRENT_BINARY_DIR}/${lang}.insert-header + | ${GettextTranslate_MSGCONV_EXECUTABLE} -t UTF-8 + | ${GettextTranslate_MSGFILTER_EXECUTABLE} sed -f + ${CMAKE_CURRENT_SOURCE_DIR}/`echo ${lang} + | sed -e 's/.*@//'`.sed 2>/dev/null > + ${PO_FILE_NAME} + DEPENDS ${lang}.insert-header ${TEMPLATE_FILE_ABS} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + + else() + + add_custom_command(OUTPUT ${PO_FILE_NAME} + COMMAND ${GettextTranslate_MSGMERGE_EXECUTABLE} --lang=${lang} + ${PO_FILE_NAME} ${TEMPLATE_FILE_ABS} + -o ${PO_FILE_NAME}.new + COMMAND mv ${PO_FILE_NAME}.new ${PO_FILE_NAME} + DEPENDS ${TEMPLATE_FILE_ABS} + ) + + endif() + + add_custom_command(OUTPUT ${GMO_FILE_NAME} + COMMAND ${GettextTranslate_MSGFMT_EXECUTABLE} -c --statistics --verbose + -o ${GMO_FILE_NAME} ${PO_FILE_NAME} + DEPENDS ${PO_TARGET} + ) + add_custom_target(${GMO_TARGET} DEPENDS ${GMO_FILE_NAME}) + + add_custom_target(${PO_TARGET} DEPENDS ${PO_FILE_NAME}) + add_dependencies(${PO_TARGET} ${MAKEVAR_DOMAIN}.pot-update) + + install(FILES ${GMO_FILE_NAME} DESTINATION + ${LOCALEDIR}/${lang}/LC_MESSAGES + RENAME ${MAKEVAR_DOMAIN}.mo + ) + + endforeach() + + add_dependencies(update-po ${po_files}) + add_dependencies(update-gmo ${gmo_files}) + +#string(REGEX MATCH "^[^=]+=(.*)$" parsed_variables ${makevars}) + +endmacro() diff --git a/CMakeModules/OpenSSLTests.cmake b/CMakeModules/OpenSSLTests.cmake new file mode 100644 index 0000000..2e64c33 --- /dev/null +++ b/CMakeModules/OpenSSLTests.cmake @@ -0,0 +1,24 @@ + +include (CheckFunctionExists) + +set (CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES}) +set (CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR}) + +check_function_exists (EVP_bf_cbc HAVE_EVP_BF) +if (NOT HAVE_EVP_BF) + message (STATUS " Blowfish support disabled.") +endif (NOT HAVE_EVP_BF) + +check_function_exists (EVP_aes_128_cbc HAVE_EVP_AES) +if (NOT HAVE_EVP_AES) + message (STATUS " AES support disabled.") +endif (NOT HAVE_EVP_AES) + +check_function_exists (EVP_aes_128_xts HAVE_EVP_AES_XTS) +if (NOT HAVE_EVP_AES_XTS) + message (STATUS " AES/XTS support disabled.") +endif (NOT HAVE_EVP_AES_XTS) + +set (CMAKE_REQUIRED_LIBRARIES) +set (CMAKE_REQUIRED_INCLUDES) + diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 4908fb0..0000000 --- a/Makefile.am +++ /dev/null @@ -1,17 +0,0 @@ - -if BUILD_NLS -NLS_DIR = po -endif - -SUBDIRS = encfs m4 $(NLS_DIR) - - -EXTRA_DIST = config.rpath mkinstalldirs encfs.spec makedist.sh makedist2.sh \ - intl/autosprintf.h intl/autosprintf.cpp intl/gettext.h - -AUTOMAKE_OPTIONS = foreign - -MAINTAINERCLEANFILES = aclocal.m4 - - -ACLOCAL_AMFLAGS = -I m4 diff --git a/Makefile.common b/Makefile.common deleted file mode 100644 index f6faeb4..0000000 --- a/Makefile.common +++ /dev/null @@ -1,2 +0,0 @@ -KDE_OPTIONS = qtonly - diff --git a/Makefile.dist b/Makefile.dist deleted file mode 100644 index 21faf23..0000000 --- a/Makefile.dist +++ /dev/null @@ -1,5 +0,0 @@ -default: all - -all: - autoreconf -if - diff --git a/README b/README index 7cb63cb..9be3259 100644 --- a/README +++ b/README @@ -35,12 +35,13 @@ Usage: Technology: - - Encfs uses algorithms from third-party libraries (OpenSSL is the default) to - encrypt data and filenames. + - Encfs uses algorithms from the third-party library OpenSSL to encrypt data + and filenames. - - a user supplied password is used to decrypt a volume key, and the volume key - is used for encrypting all file names and contents. This makes it possible - to change the password without needing to re-encrypt all files. + - a user supplied password is used to decrypt a randomly generated volume key, + and the volume key is used for encrypting all file names and contents. This + makes it possible to change the password without needing to re-encrypt all + files. - EncFS has two encryption modes, which are used in different places: - Stream encryption: diff --git a/README-NLS b/README-NLS index 422156d..66bfc37 100644 --- a/README-NLS +++ b/README-NLS @@ -1,67 +1,6 @@ -Quick configuration advice -========================== - -The configuration script will automatically find and make use of your installed -'gettext' package. If you do not have gettext installed, or do not want -internationalization support included in the build, then you can disable native -language support using - ./configu --disable-nls - -Using This Package -================== - -As a user, if your language has been installed for this package, you -only have to set the `LANG' environment variable to the appropriate -`LL_CC' combination. Here `LL' is an ISO 639 two-letter language code, -and `CC' is an ISO 3166 two-letter country code. For example, let's -suppose that you speak German and live in Germany. At the shell -prompt, merely execute `setenv LANG de_DE' (in `csh'), -`export LANG; LANG=de_DE' (in `sh') or `export LANG=de_DE' (in `bash'). -This can be done from your `.login' or `.profile' file, once and for -all. - - You might think that the country code specification is redundant. -But in fact, some languages have dialects in different countries. For -example, `de_AT' is used for Austria, and `pt_BR' for Brazil. The -country code serves to distinguish the dialects. - - The locale naming convention of `LL_CC', with `LL' denoting the -language and `CC' denoting the country, is the one use on systems based -on GNU libc. On other systems, some variations of this scheme are -used, such as `LL' or `LL_CC.ENCODING'. You can get the list of -locales supported by your system for your country by running the command -`locale -a | grep '^LL''. - - Not all programs have translations for all languages. By default, an -English message is shown in place of a nonexistent translation. If you -understand other languages, you can set up a priority list of languages. -This is done through a different environment variable, called -`LANGUAGE'. GNU `gettext' gives preference to `LANGUAGE' over `LANG' -for the purpose of message handling, but you still need to have `LANG' -set to the primary language; this is required by other parts of the -system libraries. For example, some Swedish users who would rather -read translations in German than English for when Swedish is not -available, set `LANGUAGE' to `sv:de' while leaving `LANG' to `sv_SE'. - - Special advice for Norwegian users: The language code for Norwegian -bokma*l changed from `no' to `nb' recently (in 2003). During the -transition period, while some message catalogs for this language are -installed under `nb' and some older ones under `no', it's recommended -for Norwegian users to set `LANGUAGE' to `nb:no' so that both newer and -older translations are used. - - In the `LANGUAGE' environment variable, but not in the `LANG' -environment variable, `LL_CC' combinations can be abbreviated as `LL' -to denote the language's main dialect. For example, `de' is equivalent -to `de_DE' (German as spoken in Germany), and `pt' to `pt_PT' -(Portuguese as spoken in Portugal) in this context. - -Translating -=========== - EncFS is registered with Rosetta - an online interface for supplying -translations. See https://launchpad.ubuntu.com/rosetta/products/encfs +translations. See https://translations.launchpad.net/encfs If your language is not included in this distribution, you may want to check if translated text is already available online in Rosetta. diff --git a/TRANSLATORS b/TRANSLATORS deleted file mode 100644 index 58e520f..0000000 --- a/TRANSLATORS +++ /dev/null @@ -1,7 +0,0 @@ -Many people have contributed translations for EncFS. Thank you for making -EncFS easier for everyone to use! - -If you would like to help with translations, please use the online -interface provided by Canonical Ltd (the makers of Ubuntu Linux): - https://translations.launchpad.net/encfs/main/ - diff --git a/base/CMakeLists.txt b/base/CMakeLists.txt new file mode 100644 index 0000000..e08d26c --- /dev/null +++ b/base/CMakeLists.txt @@ -0,0 +1,29 @@ +find_package (Protobuf REQUIRED) +include_directories (${PROTOBUF_INCLUDE_DIR}) + +find_package (TinyXML REQUIRED) +include_directories (${TINYXML_INCLUDE_DIR}) +set (LIBS ${LIBS} ${TINYXML_LIBRARIES}) + +protobuf_generate_cpp (PROTO_SRCS PROTO_HDRS config.proto) + +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/config.h) + +add_library (encfs-base + autosprintf.cpp + base64.cpp + ConfigReader.cpp + ConfigVar.cpp + Error.cpp + Interface.cpp + XmlReader.cpp + ${PROTO_SRCS} + ${PROTO_HDRS} +) + +target_link_libraries (encfs-base + ${PROTOBUF_LIBRARY} + ${TINYXML_LIBRARIES} +) + diff --git a/base/ConfigReader.cpp b/base/ConfigReader.cpp new file mode 100644 index 0000000..1ba71dd --- /dev/null +++ b/base/ConfigReader.cpp @@ -0,0 +1,157 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2004-2013, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "base/ConfigReader.h" + +#include + +#include +#include +#include +#include +#include + + +using namespace std; + + +ConfigReader::ConfigReader() +{ +} + +ConfigReader::~ConfigReader() +{ +} + +// read the entire file into a ConfigVar instance and then use that to decode +// into mapped variables. +bool ConfigReader::load(const char *fileName) +{ + struct stat stbuf; + memset( &stbuf, 0, sizeof(struct stat)); + if( lstat( fileName, &stbuf ) != 0) + return false; + + int size = stbuf.st_size; + + int fd = open( fileName, O_RDONLY ); + if(fd < 0) + return false; + + char *buf = new char[size]; + + int res = ::read( fd, buf, size ); + close( fd ); + + if( res != size ) + { + LOG(WARNING) << "Partial read of config file, expecting " + << size << " bytes, got " << res; + delete[] buf; + return false; + } + + ConfigVar in; + in.write( (unsigned char *)buf, size ); + delete[] buf; + + return loadFromVar( in ); +} + +bool ConfigReader::loadFromVar(ConfigVar &in) +{ + in.resetOffset(); + + // parse. + int numEntries = in.readInt(); + + for(int i=0; i> key >> value; + + if(key.length() == 0) + { + LOG(ERROR) << "Invalid key encoding in buffer"; + return false; + } + ConfigVar newVar( value ); + vars.insert( make_pair( key, newVar ) ); + } + + return true; +} + +bool ConfigReader::save(const char *fileName) const +{ + // write everything to a ConfigVar, then output to disk + ConfigVar out = toVar(); + + int fd = ::open( fileName, O_RDWR | O_CREAT, 0640 ); + if(fd >= 0) + { + int retVal = ::write( fd, out.buffer(), out.size() ); + close( fd ); + if(retVal != out.size()) + { + LOG(ERROR) << "Error writing to config file " << fileName; + return false; + } + } else + { + LOG(ERROR) << "Unable to open or create file " << fileName; + return false; + } + + return true; +} + +ConfigVar ConfigReader::toVar() const +{ + // write everything to a ConfigVar, then output to disk + ConfigVar out; + out.writeInt( vars.size() ); + map::const_iterator it; + for(it = vars.begin(); it != vars.end(); ++it) + { + out.writeInt( it->first.size() ); + out.write( (unsigned char*)it->first.data(), it->first.size() ); + out.writeInt( it->second.size() ); + out.write( (unsigned char*)it->second.buffer(), it->second.size() ); + } + + return out; +} + +ConfigVar ConfigReader::operator[] ( const std::string &varName ) const +{ + // read only + map::const_iterator it = vars.find( varName ); + if( it == vars.end() ) + return ConfigVar(); + else + return it->second; +} + +ConfigVar &ConfigReader::operator[] ( const std::string &varName ) +{ + return vars[ varName ]; +} + diff --git a/encfs/ConfigReader.h b/base/ConfigReader.h similarity index 98% rename from encfs/ConfigReader.h rename to base/ConfigReader.h index 4d6bf71..da521e3 100644 --- a/encfs/ConfigReader.h +++ b/base/ConfigReader.h @@ -24,7 +24,7 @@ #include #include -#include "ConfigVar.h" +#include "base/ConfigVar.h" /* handles Configuration load / store for Encfs filesystems. diff --git a/base/ConfigVar.cpp b/base/ConfigVar.cpp new file mode 100644 index 0000000..eb1a1a1 --- /dev/null +++ b/base/ConfigVar.cpp @@ -0,0 +1,253 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2004, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "base/ConfigVar.h" +#include "base/Error.h" + +#include +#include + +#ifndef MIN +inline int MIN(int a, int b) +{ + return (a < b) ? a : b; +} +#endif + + +ConfigVar::ConfigVar() + : pd( new ConfigVarData ) +{ + pd->offset = 0; +} + +ConfigVar::ConfigVar(const std::string &buf) + : pd( new ConfigVarData ) +{ + pd->buffer = buf; + pd->offset = 0; +} + +ConfigVar::ConfigVar(const ConfigVar &src) +{ + pd = src.pd; +} + +ConfigVar::~ConfigVar() +{ + pd.reset(); +} + +ConfigVar & ConfigVar::operator = (const ConfigVar &src) +{ + if(src.pd == pd) + return *this; + else + pd = src.pd; + + return *this; +} + +void ConfigVar::resetOffset() +{ + pd->offset = 0; +} + +int ConfigVar::read(unsigned char *buffer_, int bytes) const +{ + int toCopy = MIN( bytes, pd->buffer.size() - pd->offset ); + + if(toCopy > 0) + memcpy( buffer_, pd->buffer.data() + pd->offset, toCopy ); + + pd->offset += toCopy; + + return toCopy; +} + +int ConfigVar::write(const unsigned char *data, int bytes) +{ + if(pd->buffer.size() == (unsigned int)pd->offset) + { + pd->buffer.append( (const char *)data, bytes ); + } else + { + pd->buffer.insert( pd->offset, (const char *)data, bytes ); + } + + pd->offset += bytes; + + return bytes; +} + +int ConfigVar::size() const +{ + return pd->buffer.size(); +} + +const char *ConfigVar::buffer() const +{ + return pd->buffer.data(); +} + +int ConfigVar::at() const +{ + return pd->offset; +} + +void ConfigVar::writeString(const char *data, int bytes) +{ + writeInt( bytes ); + write( (const unsigned char *)data, bytes ); +} + + +// convert integer to BER encoded integer +void ConfigVar::writeInt(int val) +{ + // we can represent 7 bits per char output, so a 32bit number may take up + // to 5 bytes. + // first byte: 0x0000007f 0111,1111 + // second byte: 0x00003f80 0011,1111 1000,0000 + // third byte: 0x001fb000 0000,0000 0001,1111 1100,0000 0000,0000 + // fourth byte: 0x0fe00000 0000,1111 1110,0000 + // fifth byte: 0xf0000000 1111,0000 + unsigned char digit[5]; + + digit[4] = (unsigned char)((val & 0x0000007f)); + digit[3] = 0x80 | (unsigned char)((val & 0x00003f80) >> 7); + digit[2] = 0x80 | (unsigned char)((val & 0x001fc000) >> 14); + digit[1] = 0x80 | (unsigned char)((val & 0x0fe00000) >> 21); + digit[0] = 0x80 | (unsigned char)((val & 0xf0000000) >> 28); + + // find the starting point - we only need to output starting at the most + // significant non-zero digit.. + int start = 0; + while(digit[start] == 0x80) + ++start; + + write( digit + start, 5-start ); +} + +int ConfigVar::readInt() const +{ + const unsigned char * buf = (const unsigned char *)buffer(); + int bytes = this->size(); + int offset = at(); + int value = 0; + bool highBitSet; + + rAssert( offset < bytes ); + + do + { + unsigned char tmp = buf[offset++]; + highBitSet = tmp & 0x80; + + value = (value << 7) | (int)(tmp & 0x7f); + } while(highBitSet && offset < bytes); + + pd->offset = offset; + + // should never end up with a negative number.. + rAssert( value >= 0 ); + + return value; +} + +int ConfigVar::readInt( int defaultValue ) const +{ + int bytes = this->size(); + int offset = at(); + + if(offset >= bytes) + return defaultValue; + else + return readInt(); +} + +bool ConfigVar::readBool( bool defaultValue ) const +{ + int tmp = readInt( defaultValue ? 1 : 0 ); + return (tmp != 0); +} + +ConfigVar & operator << (ConfigVar &src, bool value) +{ + src.writeInt( value ? 1 : 0 ); + return src; +} + +ConfigVar & operator << (ConfigVar &src, int var) +{ + src.writeInt( var ); + return src; +} + +ConfigVar & operator << (ConfigVar &src, const std::string &str) +{ + src.writeString( str.data(), str.length() ); + return src; +} + +const ConfigVar & operator >> (const ConfigVar &src, bool &result) +{ + int tmp = src.readInt(); + result = (tmp != 0); + return src; +} + +const ConfigVar & operator >> (const ConfigVar &src, int &result) +{ + result = src.readInt(); + return src; +} + +const ConfigVar & operator >> (const ConfigVar &src, std::string &result) +{ + int length = src.readInt(); + LOG_IF(WARNING, length <= 0) << "Invalid config length " << length; + + int readLen; + + unsigned char tmpBuf[32]; + if(length > (int)sizeof(tmpBuf)) + { + unsigned char *ptr = new unsigned char[length]; + readLen = src.read( ptr, length ); + result.assign( (char*)ptr, length ); + delete[] ptr; + } else + { + readLen = src.read( tmpBuf, length ); + result.assign( (char*)tmpBuf, length ); + } + + if(readLen != length) + { + VLOG(1) << "string encoded as size " << length + << " bytes, read " << readLen; + } + + rAssert(readLen == length); + + return src; +} + diff --git a/encfs/ConfigVar.h b/base/ConfigVar.h similarity index 98% rename from encfs/ConfigVar.h rename to base/ConfigVar.h index 4a51304..5dcbaa7 100644 --- a/encfs/ConfigVar.h +++ b/base/ConfigVar.h @@ -22,7 +22,7 @@ #define _ConfigVar_incl_ #include -#include "shared_ptr.h" +#include "base/shared_ptr.h" class ConfigVar { diff --git a/base/Error.cpp b/base/Error.cpp new file mode 100644 index 0000000..ee628e0 --- /dev/null +++ b/base/Error.cpp @@ -0,0 +1,7 @@ +#include "base/Error.h" + +Error::Error(const char *msg) + : runtime_error(msg) +{ +} + diff --git a/base/Error.h b/base/Error.h new file mode 100644 index 0000000..836af32 --- /dev/null +++ b/base/Error.h @@ -0,0 +1,25 @@ +#ifndef _Error_incl_ +#define _Error_incl_ + +#include +#include + +class Error : public std::runtime_error +{ +public: + Error(const char *msg); +}; + +#define STR(X) #X + +#define rAssert( cond ) \ + do { \ + if( (cond) == false) \ + { LOG(ERROR) << "Assert failed: " << STR(cond); \ + throw Error(STR(cond)); \ + } \ + } while(0) + + +#endif + diff --git a/encfs/Interface.cpp b/base/Interface.cpp similarity index 81% rename from encfs/Interface.cpp rename to base/Interface.cpp index 489996d..03c0d10 100644 --- a/encfs/Interface.cpp +++ b/base/Interface.cpp @@ -2,7 +2,7 @@ * Author: Valient Gough * ***************************************************************************** - * Copyright (c) 2004, Valient Gough + * Copyright (c) 2004-2013, Valient Gough * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the @@ -18,22 +18,23 @@ * along with this program. If not, see . */ -#include "Interface.h" +#include "base/Interface.h" -#include "ConfigVar.h" +#include "base/ConfigVar.h" -#include -#include +#include +#include -using namespace rlog; - -static RLogChannel * Info = DEF_CHANNEL( "info/iface", Log_Info ); +std::ostream& operator << (std::ostream& out, const Interface &iface) +{ + out << iface.name() << "(" << iface.major() + << ":" << iface.minor() << ":" << iface.age() << ")"; + return out; +} bool implements(const Interface &A, const Interface &B) { - rLog(Info, "checking if %s(%i:%i:%i) implements %s(%i:%i:%i)", - A.name().c_str(), A.major(), A.minor(), A.age(), - B.name().c_str(), B.major(), B.minor(), B.age()); + VLOG(1) << "checking if " << A << " implements " << B; if( A.name() != B.name() ) return false; @@ -54,7 +55,8 @@ Interface makeInterface(const char *name, int major, int minor, int age) ConfigVar & operator << (ConfigVar &dst, const Interface &iface) { - dst << iface.name() << (int)iface.major() << (int)iface.minor() << (int)iface.age(); + dst << iface.name() << (int)iface.major() << (int)iface.minor() + << (int)iface.age(); return dst; } diff --git a/encfs/Interface.h b/base/Interface.h similarity index 97% rename from encfs/Interface.h rename to base/Interface.h index bfced6d..38b5e62 100644 --- a/encfs/Interface.h +++ b/base/Interface.h @@ -22,7 +22,7 @@ #define _Interface_incl_ #include -#include "config.pb.h" +#include "base/config.pb.h" // check if A implements the interface described by B. // Note that implements(A, B) is not the same as implements(B, A) @@ -32,7 +32,7 @@ bool implements( const Interface &a, const Interface &b ); Interface makeInterface( const char *name, int major, int minor, int age ); -// Reae operation +// Read operation class ConfigVar; const ConfigVar & operator >> (const ConfigVar &, Interface &); diff --git a/encfs/Mutex.h b/base/Mutex.h similarity index 63% rename from encfs/Mutex.h rename to base/Mutex.h index 318c56a..0a13a60 100644 --- a/encfs/Mutex.h +++ b/base/Mutex.h @@ -26,40 +26,41 @@ namespace rel { - class Lock - { - public: - Lock( pthread_mutex_t &mutex ); - ~Lock(); +class Lock +{ +public: + Lock( pthread_mutex_t &mutex ); + ~Lock(); - // leave the lock as it is. When the Lock wrapper is destroyed, it - // will do nothing with the pthread mutex. - void leave(); + // leave the lock as it is. When the Lock wrapper is destroyed, it + // will do nothing with the pthread mutex. + void leave(); - private: - Lock(const Lock &src); // not allowed - Lock &operator = (const Lock &src); // not allowed +private: + Lock(const Lock &src); // not allowed + Lock &operator = (const Lock &src); // not allowed - pthread_mutex_t *_mutex; - }; + pthread_mutex_t *_mutex; +}; - inline Lock::Lock( pthread_mutex_t &mutex ) - : _mutex( &mutex ) - { - pthread_mutex_lock( _mutex ); - } - - inline Lock::~Lock( ) - { - if(_mutex) - pthread_mutex_unlock( _mutex ); - } - - inline void Lock::leave() - { - _mutex = 0; - } +inline Lock::Lock( pthread_mutex_t &mutex ) + : _mutex( &mutex ) +{ + pthread_mutex_lock( _mutex ); } +inline Lock::~Lock( ) +{ + if(_mutex) + pthread_mutex_unlock( _mutex ); +} + +inline void Lock::leave() +{ + _mutex = 0; +} + +} // namespace rel + #endif diff --git a/encfs/Range.h b/base/Range.h similarity index 97% rename from encfs/Range.h rename to base/Range.h index f4f3c7d..b89804c 100644 --- a/encfs/Range.h +++ b/base/Range.h @@ -66,6 +66,8 @@ inline Range::Range() inline bool Range::allowed(int value) const { + if(minVal < 0 && maxVal < 0) + return true; if(value >= minVal && value <= maxVal) { int tmp = value - minVal; diff --git a/encfs/XmlReader.cpp b/base/XmlReader.cpp similarity index 90% rename from encfs/XmlReader.cpp rename to base/XmlReader.cpp index 925271c..c774708 100644 --- a/encfs/XmlReader.cpp +++ b/base/XmlReader.cpp @@ -2,7 +2,7 @@ * Author: Valient Gough * ***************************************************************************** - * Copyright (c) 2012, Valient Gough + * Copyright (c) 2012-2013, Valient Gough * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the @@ -18,7 +18,7 @@ * along with this program. If not, see . */ -#include "XmlReader.h" +#include "base/XmlReader.h" #include #include @@ -35,12 +35,11 @@ #include #include -#include -#include "base64.h" -#include "Interface.h" +#include +#include "base/base64.h" +#include "base/Interface.h" using namespace std; -using namespace rlog; XmlValue::~XmlValue() { @@ -53,7 +52,7 @@ XmlValuePtr XmlValue::operator[] (const char *path) const XmlValuePtr XmlValue::find(const char *path) const { - rError("in XmlValue::find(%s)", path); + LOG_FIRST_N(ERROR, 1) << "in XmlValue::find( " << path << ")"; return XmlValuePtr(); } @@ -127,8 +126,9 @@ bool XmlValue::readB64(const char *path, unsigned char *data, int length) const if (decodedSize != length) { - rError("decoding bytes len %i, expecting output len %i, got %i", - (int)s.size(), length, decodedSize); + LOG(ERROR) << "decoding bytes len " << s.size() + << ", expecting output len " << length + << ", got " << decodedSize; return false; } @@ -231,14 +231,15 @@ XmlValuePtr XmlReader::operator[] ( const char *name ) const TiXmlNode *node = pd->doc->FirstChild(name); if (node == NULL) { - rError("Xml node %s not found", name); + LOG(ERROR) << "Xml node " << name << " not found"; return XmlValuePtr(new XmlValue()); } TiXmlElement *element = node->ToElement(); if (element == NULL) { - rError("Xml node %s not element, type = %i", name, node->Type()); + LOG(ERROR) << "Xml node " << name + << " not element, type = " << node->Type(); return XmlValuePtr(new XmlValue()); } diff --git a/encfs/XmlReader.h b/base/XmlReader.h similarity index 98% rename from encfs/XmlReader.h rename to base/XmlReader.h index e869261..dae3826 100644 --- a/encfs/XmlReader.h +++ b/base/XmlReader.h @@ -22,7 +22,7 @@ #define _XmlReader_incl_ #include -#include "shared_ptr.h" +#include "base/shared_ptr.h" class XmlValue; typedef shared_ptr XmlValuePtr; diff --git a/intl/autosprintf.cpp b/base/autosprintf.cpp similarity index 98% rename from intl/autosprintf.cpp rename to base/autosprintf.cpp index ce76011..842c80a 100644 --- a/intl/autosprintf.cpp +++ b/base/autosprintf.cpp @@ -25,7 +25,7 @@ #endif /* Specification. */ -#include "autosprintf.h" +#include "base/autosprintf.h" #include #include diff --git a/intl/autosprintf.h b/base/autosprintf.h similarity index 100% rename from intl/autosprintf.h rename to base/autosprintf.h diff --git a/encfs/base64.cpp b/base/base64.cpp similarity index 99% rename from encfs/base64.cpp rename to base/base64.cpp index 2f0da1d..cfb0e38 100644 --- a/encfs/base64.cpp +++ b/base/base64.cpp @@ -18,7 +18,7 @@ * along with this program. If not, see . */ -#include "base64.h" +#include "base/base64.h" #include diff --git a/encfs/base64.h b/base/base64.h similarity index 100% rename from encfs/base64.h rename to base/base64.h diff --git a/base/config.h.cmake b/base/config.h.cmake new file mode 100644 index 0000000..b9834f2 --- /dev/null +++ b/base/config.h.cmake @@ -0,0 +1,19 @@ +#cmakedefine HAVE_ATTR_XATTR_H +#cmakedefine HAVE_SYS_XATTR_H +#cmakedefine XATTR_ADD_OPT +#cmakedefine HAVE_COMMON_CRYPTO + +#cmakedefine HAVE_TR1_MEMORY +#cmakedefine HAVE_TR1_UNORDERED_MAP +#cmakedefine HAVE_TR1_UNORDERED_SET +#cmakedefine HAVE_TR1_TUPLE + +#cmakedefine HAVE_EVP_BF +#cmakedefine HAVE_EVP_AES +#cmakedefine HAVE_EVP_AES_XTS + +#cmakedefine HAVE_VALGRIND_VALGRIND_H +#cmakedefine HAVE_VALGRIND_MEMCHECK_H + +#define VERSION "@ENCFS_VERSION@" + diff --git a/encfs/config.proto b/base/config.proto similarity index 87% rename from encfs/config.proto rename to base/config.proto index eeaf6df..28b1bad 100644 --- a/encfs/config.proto +++ b/base/config.proto @@ -2,9 +2,13 @@ message EncfsConfig { optional string creator = 1; + optional string writer = 11; optional int32 revision = 2 [default=0]; required Interface cipher = 3; + // added for FileIO/Cipher 3.0 (encfs 1.8) + // Use only block encryption, no stream encryption. + optional bool block_mode_only = 31; required EncryptedKey key = 4; optional Interface naming = 5; @@ -16,6 +20,7 @@ message EncfsConfig optional int32 block_mac_bytes = 61 [default=0]; optional int32 block_mac_rand_bytes = 611 [default=0]; optional bool allow_holes = 62 [default = false]; + } message EncryptedKey diff --git a/intl/gettext.h b/base/gettext.h similarity index 100% rename from intl/gettext.h rename to base/gettext.h diff --git a/encfs/i18n.h b/base/i18n.h similarity index 95% rename from encfs/i18n.h rename to base/i18n.h index 29b2582..4a73f14 100644 --- a/encfs/i18n.h +++ b/base/i18n.h @@ -23,11 +23,11 @@ #if defined(LOCALEDIR) -# include "gettext.h" +# include "base/gettext.h" // make shortcut for gettext # define _(STR) gettext (STR) -# include "autosprintf.h" +# include "base/autosprintf.h" using gnu::autosprintf; #else diff --git a/encfs/shared_ptr.h b/base/shared_ptr.h similarity index 97% rename from encfs/shared_ptr.h rename to base/shared_ptr.h index 4c2ebed..82b9068 100644 --- a/encfs/shared_ptr.h +++ b/base/shared_ptr.h @@ -22,7 +22,7 @@ #ifndef _SHARED_PTR_incl_ #define _SHARED_PTR_incl_ -#include "config.h" +#include "base/config.h" #ifdef HAVE_TR1_MEMORY #include diff --git a/cipher/CMakeLists.txt b/cipher/CMakeLists.txt new file mode 100644 index 0000000..ea56731 --- /dev/null +++ b/cipher/CMakeLists.txt @@ -0,0 +1,41 @@ +include_directories (${OPENSSL_INCLUDE_DIR}) + +link_directories (${Encfs_BINARY_DIR}/base) + +enable_testing () +find_package (GTest REQUIRED) + +add_library (encfs-cipher + readpassphrase.cpp + Cipher.cpp + CipherKey.cpp + MemoryPool.cpp + NullCipher.cpp + openssl.cpp + SSL_Cipher.cpp +) + +target_link_libraries (encfs-cipher + ${OPENSSL_LIBRARIES} +) + +#include_directories (${GTEST_INCLUDE_DIR}) +#add_executable (unittests +#MemBlockFileIO.cpp +#MemFileIO.cpp +#testing.cpp +#test_IO.cpp +#test_BlockIO.cpp +#) + +#target_link_libraries (unittests +#${GTEST_BOTH_LIBRARIES} +#encfs-fs +#encfs-base +#${GLOG_LIBRARIES} +#) + +#add_test (UnitTests unittests) +#GTEST_ADD_TESTS (unittests "${UnitTestArgs}" test_IO.cpp test_BlockIO.cpp) +#add_custom_target (test COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS unittests) + diff --git a/encfs/Cipher.cpp b/cipher/Cipher.cpp similarity index 89% rename from encfs/Cipher.cpp rename to cipher/Cipher.cpp index 6e6e47b..2d208c0 100644 --- a/encfs/Cipher.cpp +++ b/cipher/Cipher.cpp @@ -18,12 +18,12 @@ * along with this program. If not, see . */ -#include "config.h" +#include "base/config.h" +#include "cipher/Cipher.h" -#include "Cipher.h" -#include "Interface.h" -#include "Range.h" -#include "base64.h" +#include "base/Interface.h" +#include "base/Range.h" +#include "base/base64.h" #include #include @@ -57,6 +57,7 @@ struct CipherAlg Interface iface; Range keyLength; Range blockSize; + bool hasStreamMode; }; typedef multimap< string, CipherAlg> CipherMap_t; @@ -84,6 +85,7 @@ Cipher::GetAlgorithmList( bool includeHidden ) tmp.iface = it->second.iface; tmp.keyLength = it->second.keyLength; tmp.blockSize = it->second.blockSize; + tmp.hasStreamMode = it->second.hasStreamMode; result.push_back( tmp ); } @@ -93,18 +95,21 @@ Cipher::GetAlgorithmList( bool includeHidden ) } bool Cipher::Register(const char *name, const char *description, - const Interface &iface, CipherConstructor fn, bool hidden) + const Interface &iface, CipherConstructor fn, + bool hasStreamMode, bool hidden) { Range keyLength(-1,-1,1); Range blockSize(-1,-1,1); return Cipher::Register( name, description, iface, - keyLength, blockSize, fn, hidden ); + keyLength, blockSize, fn, hasStreamMode, hidden ); } bool Cipher::Register(const char *name, const char *description, const Interface &iface, const Range &keyLength, const Range &blockSize, - CipherConstructor fn, bool hidden) + CipherConstructor fn, + bool hasStreamMode, + bool hidden) { if(!gCipherMap) gCipherMap = new CipherMap_t; @@ -116,6 +121,7 @@ bool Cipher::Register(const char *name, const char *description, ca.iface = iface; ca.keyLength = keyLength; ca.blockSize = blockSize; + ca.hasStreamMode = hasStreamMode; gCipherMap->insert( make_pair(string(name), ca) ); return true; @@ -195,26 +201,13 @@ unsigned int Cipher::MAC_16( const unsigned char *src, int len, return mac16; } -bool Cipher::nameEncode( unsigned char *data, int len, - uint64_t iv64, const CipherKey &key ) const -{ - return streamEncode( data, len, iv64, key ); -} - -bool Cipher::nameDecode( unsigned char *data, int len, - uint64_t iv64, const CipherKey &key ) const -{ - return streamDecode( data, len, iv64, key ); -} - string Cipher::encodeAsString(const CipherKey &key, const CipherKey &encodingKey ) { int encodedKeySize = this->encodedKeySize(); unsigned char *keyBuf = new unsigned char[ encodedKeySize ]; - // write the key, encoding it with itself. - this->writeKey( key, keyBuf, key ); + this->writeKey( key, keyBuf, encodingKey ); int b64Len = B256ToB64Bytes( encodedKeySize ); unsigned char *b64Key = new unsigned char[ b64Len + 1 ]; @@ -226,3 +219,9 @@ string Cipher::encodeAsString(const CipherKey &key, return string( (const char *)b64Key ); } + +bool Cipher::hasStreamMode() const +{ + return true; +} + diff --git a/encfs/Cipher.h b/cipher/Cipher.h similarity index 88% rename from encfs/Cipher.h rename to cipher/Cipher.h index e0dc3b2..8b0795d 100644 --- a/encfs/Cipher.h +++ b/cipher/Cipher.h @@ -21,11 +21,9 @@ #ifndef _Cipher_incl_ #define _Cipher_incl_ -#include "encfs.h" - -#include "Range.h" -#include "Interface.h" -#include "CipherKey.h" +#include "cipher/CipherKey.h" +#include "base/Interface.h" +#include "base/Range.h" #include #include @@ -52,6 +50,7 @@ public: Interface iface; Range keyLength; Range blockSize; + bool hasStreamMode; }; @@ -60,15 +59,16 @@ public: static shared_ptr New( const Interface &iface, - int keyLen = -1); + int keyLen = -1); static shared_ptr New( const std::string &cipherName, - int keyLen = -1 ); + int keyLen = -1 ); static bool Register(const char *cipherName, const char *description, const Interface &iface, CipherConstructor constructor, + bool hasStreamMode, bool hidden = false); static bool Register(const char *cipherName, @@ -76,6 +76,7 @@ public: const Interface &iface, const Range &keyLength, const Range &blockSize, CipherConstructor constructor, + bool hasStreamMode, bool hidden = false); Cipher(); @@ -117,6 +118,8 @@ public: virtual int encodedKeySize() const=0; // size virtual int cipherBlockSize() const=0; // size of a cipher block + virtual bool hasStreamMode() const; + // fill the supplied buffer with random data // The data may be pseudo random and might not be suitable for key // generation. For generating keys, uses newRandomKey() instead. @@ -143,17 +146,6 @@ public: virtual bool streamDecode( unsigned char *data, int len, uint64_t iv64, const CipherKey &key) const=0; - /* - These are just aliases of streamEncode / streamDecode, but there are - provided here for backward compatibility for earlier ciphers that has - effectively two stream modes - one for encoding partial blocks and - another for encoding filenames. - */ - virtual bool nameEncode( unsigned char *data, int len, - uint64_t iv64, const CipherKey &key) const; - virtual bool nameDecode( unsigned char *data, int len, - uint64_t iv64, const CipherKey &key) const; - /* Block encoding of data in-place. The data size should be a multiple of the cipher block size. diff --git a/encfs/CipherKey.cpp b/cipher/CipherKey.cpp similarity index 97% rename from encfs/CipherKey.cpp rename to cipher/CipherKey.cpp index c2e815a..01b9a3f 100644 --- a/encfs/CipherKey.cpp +++ b/cipher/CipherKey.cpp @@ -18,7 +18,7 @@ * along with this program. If not, see . */ -#include "CipherKey.h" +#include "cipher/CipherKey.h" AbstractCipherKey::AbstractCipherKey() { diff --git a/encfs/CipherKey.h b/cipher/CipherKey.h similarity index 97% rename from encfs/CipherKey.h rename to cipher/CipherKey.h index b8cf639..9c1490b 100644 --- a/encfs/CipherKey.h +++ b/cipher/CipherKey.h @@ -21,7 +21,7 @@ #ifndef _CipherKey_incl_ #define _CipherKey_incl_ -#include "shared_ptr.h" +#include "base/shared_ptr.h" class AbstractCipherKey { diff --git a/cipher/MemoryPool.cpp b/cipher/MemoryPool.cpp new file mode 100644 index 0000000..d1cd935 --- /dev/null +++ b/cipher/MemoryPool.cpp @@ -0,0 +1,164 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2003-2013, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "cipher/MemoryPool.h" + +#include +#include + +#include "base/config.h" +#include "base/Error.h" + +#include + +#include + +#include + +#ifdef HAVE_VALGRIND_MEMCHECK_H +#include +#else +#define VALGRIND_MAKE_MEM_NOACCESS( a, b ) +#define VALGRIND_MAKE_MEM_UNDEFINED( a, b ) +#endif + +#include +#include + +using namespace std; + +# include +# include + +static BUF_MEM *allocBlock( int size ) +{ + BUF_MEM *block = BUF_MEM_new( ); + BUF_MEM_grow( block, size ); + VALGRIND_MAKE_MEM_NOACCESS( block->data, block->max ); + + return block; +} + +static void freeBlock( BUF_MEM *block ) +{ + VALGRIND_MAKE_MEM_UNDEFINED( block->data, block->max ); + BUF_MEM_free( block ); +} + +static pthread_mutex_t gMPoolMutex = PTHREAD_MUTEX_INITIALIZER; + +typedef std::map > FreeBlockMap; +static FreeBlockMap gFreeBlocks; + +void MemBlock::allocate(int size) +{ + rAssert(size > 0); + pthread_mutex_lock( &gMPoolMutex ); + + list &freeList = gFreeBlocks[size]; + BUF_MEM *mem; + + if (!freeList.empty()) + { + mem = freeList.front(); + freeList.pop_front(); + pthread_mutex_unlock( &gMPoolMutex ); + } else + { + pthread_mutex_unlock( &gMPoolMutex ); + mem = allocBlock( size ); + } + + internalData = mem; + data = reinterpret_cast(mem->data); + VALGRIND_MAKE_MEM_UNDEFINED( data, size ); +} + +MemBlock::~MemBlock() +{ + BUF_MEM *block = (BUF_MEM*)internalData; + data = NULL; + internalData = NULL; + + if (block) + { + // wipe the buffer.. + VALGRIND_MAKE_MEM_UNDEFINED( block->data, block->max ); + memset( block->data , 0, block->max); + VALGRIND_MAKE_MEM_NOACCESS( block->data, block->max ); + + pthread_mutex_lock( &gMPoolMutex ); + gFreeBlocks[ block->max ].push_front(block); + pthread_mutex_unlock( &gMPoolMutex ); + } +} + +void MemoryPool::destroyAll() +{ + pthread_mutex_lock( &gMPoolMutex ); + + for (FreeBlockMap::const_iterator it = gFreeBlocks.begin(); + it != gFreeBlocks.end(); it++) + { + for (list::const_iterator bIt = it->second.begin(); + bIt != it->second.end(); bIt++) + { + freeBlock( *bIt ); + } + } + + gFreeBlocks.clear(); + + pthread_mutex_unlock( &gMPoolMutex ); +} + +SecureMem::SecureMem(int len) +{ + rAssert(len > 0); + data = (char *)OPENSSL_malloc(len); + if (data) + { + size = len; + mlock(data, size); + memset(data, '\0', size); + VALGRIND_MAKE_MEM_UNDEFINED( data, size ); + } else + { + size = 0; + } +} + +SecureMem::~SecureMem() +{ + if (size) + { + memset(data, '\0', size); + OPENSSL_cleanse(data, size); + + munlock(data, size); + OPENSSL_free(data); + VALGRIND_MAKE_MEM_NOACCESS( data, size ); + + data = NULL; + size = 0; + } +} + + diff --git a/encfs/MemoryPool.h b/cipher/MemoryPool.h similarity index 90% rename from encfs/MemoryPool.h rename to cipher/MemoryPool.h index ba46bff..330e5ce 100644 --- a/encfs/MemoryPool.h +++ b/cipher/MemoryPool.h @@ -21,14 +21,25 @@ #ifndef _MemoryPool_incl_ #define _MemoryPool_incl_ +/* + Memory Pool for fixed sized objects. + Usage: + MemBlock mb( size ); + // do things with storage in mb.data + unsigned char *buffer = mb.data; + + // memblock freed when destructed +*/ struct MemBlock { unsigned char *data; - void *internalData; MemBlock(); + ~MemBlock(); + + void allocate(int size); }; inline MemBlock::MemBlock() @@ -36,19 +47,8 @@ inline MemBlock::MemBlock() { } -/* - Memory Pool for fixed sized objects. - - Usage: - MemBlock mb = MemoryPool::allocate( size ); - // do things with storage in mb.data - unsigned char *buffer = mb.data; - MemoryPool::release( mb ); -*/ namespace MemoryPool { - MemBlock allocate( int size ); - void release( const MemBlock &el ); void destroyAll(); } diff --git a/encfs/NullCipher.cpp b/cipher/NullCipher.cpp similarity index 63% rename from encfs/NullCipher.cpp rename to cipher/NullCipher.cpp index 4971fd8..867328b 100644 --- a/encfs/NullCipher.cpp +++ b/cipher/NullCipher.cpp @@ -18,18 +18,15 @@ * along with this program. If not, see . */ -#include "NullCipher.h" +#include "cipher/NullCipher.h" -#include "Range.h" -#include "Interface.h" -#include "shared_ptr.h" - -#include +#include "base/Range.h" +#include "base/Interface.h" +#include "base/shared_ptr.h" #include using namespace std; -using namespace rlog; static Interface NullInterface = makeInterface( "nullCipher", 1, 0, 0 ); @@ -38,40 +35,40 @@ static Range NullBlockRange(1,4096,1); static shared_ptr NewNullCipher(const Interface &iface, int keyLen) { - (void)keyLen; - return shared_ptr( new NullCipher( iface ) ); + (void)keyLen; + return shared_ptr( new NullCipher( iface ) ); } const bool HiddenCipher = true; static bool NullCipher_registered = Cipher::Register("Null", - "Non encrypting cipher. For testing only!", - NullInterface, NullKeyRange, NullBlockRange, NewNullCipher, - HiddenCipher); + "Non encrypting cipher. For testing only!", + NullInterface, NullKeyRange, NullBlockRange, NewNullCipher, + HiddenCipher); class NullKey : public AbstractCipherKey { public: - NullKey() {} - virtual ~NullKey() {} + NullKey() {} + virtual ~NullKey() {} }; class NullDestructor { public: - NullDestructor() {} - NullDestructor(const NullDestructor &) {} - ~NullDestructor() {} + NullDestructor() {} + NullDestructor(const NullDestructor &) {} + ~NullDestructor() {} - NullDestructor &operator = (const NullDestructor &){ return *this; } - void operator ()(NullKey *&) {} + NullDestructor &operator = (const NullDestructor &){ return *this; } + void operator ()(NullKey *&) {} }; shared_ptr gNullKey( new NullKey(), NullDestructor() ); NullCipher::NullCipher(const Interface &iface_) { - this->iface = iface_; + this->iface = iface_; } NullCipher::~NullCipher() @@ -80,105 +77,105 @@ NullCipher::~NullCipher() Interface NullCipher::interface() const { - return iface; + return iface; } CipherKey NullCipher::newKey(const char *, int, int &, long, const unsigned char *, int ) { - return gNullKey; + return gNullKey; } CipherKey NullCipher::newKey(const char *, int) { - return gNullKey; + return gNullKey; } CipherKey NullCipher::newRandomKey() { - return gNullKey; + return gNullKey; } bool NullCipher::randomize( unsigned char *buf, int len, bool ) const { - memset( buf, 0, len ); - return true; + memset( buf, 0, len ); + return true; } uint64_t NullCipher::MAC_64(const unsigned char *, int , - const CipherKey &, uint64_t *) const + const CipherKey &, uint64_t *) const { - return 0; + return 0; } CipherKey NullCipher::readKey( const unsigned char *, - const CipherKey &, bool) + const CipherKey &, bool) { - return gNullKey; + return gNullKey; } void NullCipher::writeKey(const CipherKey &, unsigned char *, - const CipherKey &) + const CipherKey &) { } bool NullCipher::compareKey(const CipherKey &A_, - const CipherKey &B_) const + const CipherKey &B_) const { - shared_ptr A = dynamic_pointer_cast(A_); - shared_ptr B = dynamic_pointer_cast(B_); - return A.get() == B.get(); + shared_ptr A = dynamic_pointer_cast(A_); + shared_ptr B = dynamic_pointer_cast(B_); + return A.get() == B.get(); } int NullCipher::encodedKeySize() const { - return 0; + return 0; } int NullCipher::keySize() const { - return 0; + return 0; } int NullCipher::cipherBlockSize() const { - return 1; + return 1; } bool NullCipher::streamEncode( unsigned char *src, int len, - uint64_t iv64, const CipherKey &key) const + uint64_t iv64, const CipherKey &key) const { - (void)src; - (void)len; - (void)iv64; - (void)key; - return true; + (void)src; + (void)len; + (void)iv64; + (void)key; + return true; } bool NullCipher::streamDecode( unsigned char *src, int len, - uint64_t iv64, const CipherKey &key) const + uint64_t iv64, const CipherKey &key) const { - (void)src; - (void)len; - (void)iv64; - (void)key; - return true; + (void)src; + (void)len; + (void)iv64; + (void)key; + return true; } bool NullCipher::blockEncode( unsigned char *, int , uint64_t, - const CipherKey & ) const + const CipherKey & ) const { - return true; + return true; } bool NullCipher::blockDecode( unsigned char *, int, uint64_t, - const CipherKey & ) const + const CipherKey & ) const { - return true; + return true; } bool NullCipher::Enabled() { - return true; + return true; } diff --git a/encfs/NullCipher.h b/cipher/NullCipher.h similarity index 98% rename from encfs/NullCipher.h rename to cipher/NullCipher.h index 103a141..afe6cb4 100644 --- a/encfs/NullCipher.h +++ b/cipher/NullCipher.h @@ -21,8 +21,8 @@ #ifndef _NullCipher_incl_ #define _NullCipher_incl_ -#include "Cipher.h" -#include "Interface.h" +#include "cipher/Cipher.h" +#include "base/Interface.h" /* Implements Cipher interface for a pass-through mode. May be useful for diff --git a/cipher/SSL_Cipher.cpp b/cipher/SSL_Cipher.cpp new file mode 100644 index 0000000..8390ad3 --- /dev/null +++ b/cipher/SSL_Cipher.cpp @@ -0,0 +1,973 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2004, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "base/config.h" + +#include +#include +#include +#include +#include + +#include "cipher/SSL_Cipher.h" +#include "cipher/MemoryPool.h" +#include "base/Error.h" +#include "base/Mutex.h" +#include "base/Range.h" + +#include +#include + +#include +#include + +#include + +#include "base/i18n.h" + +using namespace std; +using namespace rel; + +const int MAX_KEYLENGTH = 64; // in bytes (256 bit) +const int MAX_IVLENGTH = 16; +const int KEY_CHECKSUM_BYTES = 4; + +#ifndef MIN +inline int MIN(int a, int b) +{ + return (a < b) ? a : b; +} +#endif + +/* + This produces the same result as OpenSSL's EVP_BytesToKey. The difference + is that here we can explicitly specify the key size, instead of relying on + the state of EVP_CIPHER struct. EVP_BytesToKey will only produce 128 bit + keys for the EVP Blowfish interface, which is not what we want. + + DEPRECATED: this is here for backward compatibilty only. Use PBKDF +*/ +int BytesToKey( int keyLen, int ivLen, const EVP_MD *md, + const unsigned char *data, int dataLen, + unsigned int rounds, unsigned char *key, unsigned char *iv) +{ + if( data == NULL || dataLen == 0 ) + return 0; // OpenSSL returns nkey here, but why? It is a failure.. + + unsigned char mdBuf[ EVP_MAX_MD_SIZE ]; + unsigned int mds=0; + int addmd =0; + int nkey = key ? keyLen : 0; + int niv = iv ? ivLen : 0; + + EVP_MD_CTX cx; + EVP_MD_CTX_init( &cx ); + + for(;;) + { + EVP_DigestInit_ex( &cx, md, NULL ); + if( addmd++ ) + EVP_DigestUpdate( &cx, mdBuf, mds ); + EVP_DigestUpdate( &cx, data, dataLen ); + EVP_DigestFinal_ex( &cx, mdBuf, &mds ); + + for(unsigned int i=1; i < rounds; ++i) + { + EVP_DigestInit_ex( &cx, md, NULL ); + EVP_DigestUpdate( &cx, mdBuf, mds ); + EVP_DigestFinal_ex( &cx, mdBuf, &mds ); + } + + int offset = 0; + int toCopy = MIN( nkey, (int)mds - offset ); + if( toCopy ) + { + memcpy( key, mdBuf+offset, toCopy ); + key += toCopy; + nkey -= toCopy; + offset += toCopy; + } + toCopy = MIN( niv, (int)mds - offset ); + if( toCopy ) + { + memcpy( iv, mdBuf+offset, toCopy ); + iv += toCopy; + niv -= toCopy; + offset += toCopy; + } + if((nkey == 0) && (niv == 0)) break; + } + EVP_MD_CTX_cleanup( &cx ); + OPENSSL_cleanse( mdBuf, sizeof(mdBuf) ); + + return keyLen; +} + +long time_diff(const timeval &end, const timeval &start) +{ + return (end.tv_sec - start.tv_sec) * 1000 * 1000 + + (end.tv_usec - start.tv_usec); +} + +int SSL_Cipher::TimedPBKDF2(const char *pass, int passlen, + const unsigned char *salt, int saltlen, + int keylen, unsigned char *out, + long desiredPDFTime) +{ + int iter = 1000; + timeval start, end; + + for(;;) + { + gettimeofday( &start, 0 ); + int res = PKCS5_PBKDF2_HMAC_SHA1( + pass, passlen, const_cast(salt), saltlen, + iter, keylen, out); + if(res != 1) + return -1; + + gettimeofday( &end, 0 ); + + long delta = time_diff(end, start); + if(delta < desiredPDFTime / 8) + { + iter *= 4; + } else if(delta < (5 * desiredPDFTime / 6)) + { + // estimate number of iterations to get close to desired time + iter = (int)((double)iter * (double)desiredPDFTime + / (double)delta); + } else + return iter; + } +} + + +// - Version 1:0 used EVP_BytesToKey, which didn't do the right thing for +// Blowfish key lengths > 128 bit. +// - Version 2:0 uses BytesToKey. +// We support both 2:0 and 1:0, hence current:revision:age = 2:0:1 +// - Version 2:1 adds support for Message Digest function interface +// - Version 2:2 adds PBKDF2 for password derivation +// - Version 3:0 adds a new IV mechanism +// - Version 3:1 adds ssl/aes_xts +static Interface BlowfishInterface = makeInterface( "ssl/blowfish", 3, 0, 2 ); +static Interface AESInterface = makeInterface( "ssl/aes", 3, 0, 2 ); +static Interface AesXtsInterface = makeInterface( "ssl/aes_xts", 3, 1, 2 ); + +#if defined(HAVE_EVP_BF) + +static Range BFKeyRange(128,256,32); +static Range BFBlockRange(64,4096,8); + +static shared_ptr NewBFCipher( const Interface &iface, int keyLen ) +{ + if( keyLen <= 0 ) + keyLen = 160; + + keyLen = BFKeyRange.closest( keyLen ); + + const EVP_CIPHER *blockCipher = EVP_bf_cbc(); + const EVP_CIPHER *streamCipher = EVP_bf_cfb(); + + return shared_ptr( new SSL_Cipher(iface, BlowfishInterface, + blockCipher, streamCipher, keyLen / 8) ); +} + +static bool BF_Cipher_registered = Cipher::Register( + "Blowfish", + // xgroup(setup) + gettext_noop("8 byte block cipher"), + BlowfishInterface, BFKeyRange, BFBlockRange, NewBFCipher, true); +#endif + + +#if defined(HAVE_EVP_AES) + +static Range AESKeyRange(128,256,64); +static Range AESBlockRange(64,4096,16); + +static shared_ptr NewAESCipher( const Interface &iface, int keyLen ) +{ + if( keyLen <= 0 ) + keyLen = 192; + + keyLen = AESKeyRange.closest( keyLen ); + + const EVP_CIPHER *blockCipher = 0; + const EVP_CIPHER *streamCipher = 0; + + switch(keyLen) + { + case 128: + blockCipher = EVP_aes_128_cbc(); + streamCipher = EVP_aes_128_cfb(); + break; + + case 192: + blockCipher = EVP_aes_192_cbc(); + streamCipher = EVP_aes_192_cfb(); + break; + + case 256: + default: + blockCipher = EVP_aes_256_cbc(); + streamCipher = EVP_aes_256_cfb(); + break; + } + + return shared_ptr( new SSL_Cipher(iface, AESInterface, + blockCipher, streamCipher, keyLen / 8) ); +} + +static bool AES_Cipher_registered = Cipher::Register( + "AES", "16 byte block cipher", + AESInterface, AESKeyRange, AESBlockRange, NewAESCipher, true); +#endif + +#if defined(HAVE_EVP_AES_XTS) + +static Range AesXtsKeyRange(128,256,128); +static Range AesXtsBlockRange(1024,8192,256); + +static shared_ptr NewAesXtsCipher( const Interface &iface, int keyLen ) +{ + if( keyLen <= 0 ) + keyLen = 256; + + keyLen = AesXtsKeyRange.closest( keyLen ); + + const EVP_CIPHER *blockCipher = 0; + + switch(keyLen) + { + case 128: + blockCipher = EVP_aes_128_xts(); + break; + + case 256: + default: + blockCipher = EVP_aes_256_xts(); + break; + } + + // XTS uses 2 keys, so the key size is doubled here. + // Eg XTS-AES-256 uses two 256 bit keys. + return shared_ptr( new SSL_Cipher(iface, AesXtsInterface, + blockCipher, NULL, 2 * keyLen / 8) ); +} + +static bool AES_XTS_Cipher_registered = Cipher::Register( + "AES_XTS", "Tweakable wide-block cipher", + AesXtsInterface, AesXtsKeyRange, AesXtsBlockRange, NewAesXtsCipher, false); +#endif + +class SSLKey : public AbstractCipherKey +{ + public: + pthread_mutex_t mutex; + + unsigned int keySize; // in bytes + unsigned int ivLength; + + // key data is first _keySize bytes, + // followed by iv of _ivLength bytes, + SecureMem buf; + + EVP_CIPHER_CTX block_enc; + EVP_CIPHER_CTX block_dec; + EVP_CIPHER_CTX stream_enc; + EVP_CIPHER_CTX stream_dec; + + HMAC_CTX mac_ctx; + + SSLKey(int keySize, int ivLength); + ~SSLKey(); +}; + +SSLKey::SSLKey(int keySize_, int ivLength_) + : buf(keySize_ + ivLength_) +{ + rAssert(keySize_ >= 8); + rAssert(ivLength_ >= 8); + + this->keySize = keySize_; + this->ivLength = ivLength_; + pthread_mutex_init( &mutex, 0 ); +} + +SSLKey::~SSLKey() +{ + keySize = 0; + ivLength = 0; + + EVP_CIPHER_CTX_cleanup( &block_enc ); + EVP_CIPHER_CTX_cleanup( &block_dec ); + + EVP_CIPHER_CTX_cleanup( &stream_enc ); + EVP_CIPHER_CTX_cleanup( &stream_dec ); + + HMAC_CTX_cleanup( &mac_ctx ); + + pthread_mutex_destroy( &mutex ); +} + +inline unsigned char* KeyData( const shared_ptr &key ) +{ + return (unsigned char *)key->buf.data; +} + +inline unsigned char* IVData( const shared_ptr &key ) +{ + return (unsigned char *)key->buf.data + key->keySize; +} + +void initKey(const shared_ptr &key, const EVP_CIPHER *_blockCipher, + const EVP_CIPHER *_streamCipher, int _keySize) +{ + Lock lock( key->mutex ); + // initialize the cipher context once so that we don't have to do it for + // every block.. + EVP_CIPHER_CTX_init( &key->block_enc ); + EVP_CIPHER_CTX_init( &key->block_dec ); + EVP_EncryptInit_ex( &key->block_enc, _blockCipher, NULL, NULL, NULL); + EVP_DecryptInit_ex( &key->block_dec, _blockCipher, NULL, NULL, NULL); + EVP_CIPHER_CTX_set_key_length( &key->block_enc, _keySize ); + EVP_CIPHER_CTX_set_key_length( &key->block_dec, _keySize ); + EVP_CIPHER_CTX_set_padding( &key->block_enc, 0 ); + EVP_CIPHER_CTX_set_padding( &key->block_dec, 0 ); + EVP_EncryptInit_ex( &key->block_enc, NULL, NULL, KeyData(key), NULL); + EVP_DecryptInit_ex( &key->block_dec, NULL, NULL, KeyData(key), NULL); + + EVP_CIPHER_CTX_init( &key->stream_enc ); + EVP_CIPHER_CTX_init( &key->stream_dec ); + if (_streamCipher != NULL) + { + EVP_EncryptInit_ex( &key->stream_enc, _streamCipher, NULL, NULL, NULL); + EVP_DecryptInit_ex( &key->stream_dec, _streamCipher, NULL, NULL, NULL); + EVP_CIPHER_CTX_set_key_length( &key->stream_enc, _keySize ); + EVP_CIPHER_CTX_set_key_length( &key->stream_dec, _keySize ); + EVP_CIPHER_CTX_set_padding( &key->stream_enc, 0 ); + EVP_CIPHER_CTX_set_padding( &key->stream_dec, 0 ); + EVP_EncryptInit_ex( &key->stream_enc, NULL, NULL, KeyData(key), NULL); + EVP_DecryptInit_ex( &key->stream_dec, NULL, NULL, KeyData(key), NULL); + } + + HMAC_CTX_init( &key->mac_ctx ); + HMAC_Init_ex( &key->mac_ctx, KeyData(key), _keySize, EVP_sha1(), 0 ); +} + + +SSL_Cipher::SSL_Cipher(const Interface &iface_, + const Interface &realIface_, + const EVP_CIPHER *blockCipher, + const EVP_CIPHER *streamCipher, + int keySize_) +{ + this->iface = iface_; + this->realIface = realIface_; + this->_blockCipher = blockCipher; + this->_streamCipher = streamCipher; + this->_keySize = keySize_; + this->_ivLength = EVP_CIPHER_iv_length( _blockCipher ); + + rAssert(_ivLength == 8 || _ivLength == 16); + rAssert(_ivLength <= _keySize); + + VLOG(1) << "allocated cipher " << iface.name() + << ", keySize " << _keySize + << ", ivlength " << _ivLength; + + // EVP_CIPHER_key_length isn't useful for variable-length ciphers like + // Blowfish. Version 1 relied upon it incorrectly. + if( (EVP_CIPHER_key_length( _blockCipher ) != (int )_keySize) + && iface.major() == 1) + { + LOG(WARNING) << "Running in backward compatibilty mode for 1.0 - \n" + << "key is really " << EVP_CIPHER_key_length( _blockCipher ) * 8 + << " bits, not " << _keySize * 8; + } +} + +SSL_Cipher::~SSL_Cipher() +{ +} + +Interface SSL_Cipher::interface() const +{ + return realIface; +} + +/* + Create a key from the password. + Use SHA to distribute entropy from the password into the key. + + This algorithm must remain constant for backward compatibility, as this key + is used to encipher/decipher the master key. +*/ +CipherKey SSL_Cipher::newKey(const char *password, int passwdLength, + int &iterationCount, long desiredDuration, + const unsigned char *salt, int saltLen) +{ + shared_ptr key( new SSLKey( _keySize, _ivLength) ); + + if(iterationCount == 0) + { + // timed run, fills in iteration count + int res = TimedPBKDF2(password, passwdLength, + salt, saltLen, + _keySize+_ivLength, KeyData(key), + 1000 * desiredDuration); + if(res <= 0) + { + LOG(ERROR) << "openssl error, PBKDF2 failed"; + return CipherKey(); + } else + iterationCount = res; + } else + { + // known iteration length + if(PKCS5_PBKDF2_HMAC_SHA1( + password, passwdLength, + const_cast(salt), saltLen, + iterationCount, _keySize + _ivLength, KeyData(key)) != 1) + { + LOG(ERROR) << "openssl error, PBKDF2 failed"; + return CipherKey(); + } + } + + initKey( key, _blockCipher, _streamCipher, _keySize ); + + return key; +} + +CipherKey SSL_Cipher::newKey(const char *password, int passwdLength) +{ + shared_ptr key( new SSLKey( _keySize, _ivLength) ); + + int bytes = 0; + if( iface.major() > 1 ) + { + // now we use BytesToKey, which can deal with Blowfish keys larger then + // 128 bits. + bytes = BytesToKey( _keySize, _ivLength, EVP_sha1(), + (unsigned char *)password, passwdLength, 16, + KeyData(key), IVData(key) ); + + // the reason for moving from EVP_BytesToKey to BytesToKey function.. + if(bytes != (int)_keySize) + { + LOG(WARNING) << "newKey: BytesToKey returned " << bytes + << ", expecting " << _keySize << " key bytes"; + } + } else + { + // for backward compatibility with filesystems created with 1:0 + bytes = EVP_BytesToKey( _blockCipher, EVP_sha1(), NULL, + (unsigned char *)password, passwdLength, 16, + KeyData(key), IVData(key) ); + } + + initKey( key, _blockCipher, _streamCipher, _keySize ); + + return key; +} + +/* + Create a random key. + We use the OpenSSL library to generate random bytes, then take the hash of + those bytes to use as the key. + + This algorithm can change at any time without affecting backward + compatibility. +*/ +CipherKey SSL_Cipher::newRandomKey() +{ + const int bufLen = MAX_KEYLENGTH; + unsigned char tmpBuf[ bufLen ]; + int saltLen = 20; + unsigned char saltBuf[ saltLen ]; + + if(!randomize(tmpBuf, bufLen, true) || + !randomize(saltBuf, saltLen, true)) + return CipherKey(); + + shared_ptr key( new SSLKey( _keySize, _ivLength) ); + + // doesn't need to be versioned, because a random key is a random key.. + // Doesn't need to be reproducable.. + if(PKCS5_PBKDF2_HMAC_SHA1((char*)tmpBuf, bufLen, saltBuf, saltLen, + 1000, _keySize + _ivLength, KeyData(key)) != 1) + { + LOG(ERROR) << "openssl error, PBKDF2 failed"; + return CipherKey(); + } + + OPENSSL_cleanse(tmpBuf, bufLen); + + initKey( key, _blockCipher, _streamCipher, _keySize ); + + return key; +} + +/* + Compute a 64-bit check value for the data using HMAC. +*/ +static uint64_t _checksum_64(SSLKey *key, + const unsigned char *data, + int dataLen, + uint64_t *chainedIV) +{ + rAssert( dataLen > 0 ); + Lock lock( key->mutex ); + + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int mdLen = EVP_MAX_MD_SIZE; + + HMAC_Init_ex( &key->mac_ctx, 0, 0, 0, 0 ); + HMAC_Update( &key->mac_ctx, data, dataLen ); + if(chainedIV) + { + // toss in the chained IV as well + uint64_t tmp = *chainedIV; + unsigned char h[8]; + for(unsigned int i=0; i<8; ++i) + { + h[i] = tmp & 0xff; + tmp >>= 8; + } + + HMAC_Update( &key->mac_ctx, h, 8 ); + } + + HMAC_Final( &key->mac_ctx, md, &mdLen ); + + rAssert(mdLen >= 8); + + // chop this down to a 64bit value.. + unsigned char h[8] = {0,0,0,0,0,0,0,0}; + for(unsigned int i=0; i<(mdLen-1); ++i) + h[i%8] ^= (unsigned char)(md[i]); + + uint64_t value = (uint64_t)h[0]; + for(int i=1; i<8; ++i) + value = (value << 8) | (uint64_t)h[i]; + + return value; +} + +bool SSL_Cipher::randomize( unsigned char *buf, int len, + bool strongRandom ) const +{ + // to avoid warnings of uninitialized data from valgrind + memset(buf, 0, len); + int result; + if(strongRandom) + result = RAND_bytes( buf, len ); + else + result = RAND_pseudo_bytes( buf, len ); + + if(result != 1) + { + char errStr[120]; // specs require string at least 120 bytes long.. + unsigned long errVal = 0; + if((errVal = ERR_get_error()) != 0) + LOG(ERROR) << "openssl error: " << ERR_error_string( errVal, errStr ); + + return false; + } else + return true; +} + +uint64_t SSL_Cipher::MAC_64( const unsigned char *data, int len, + const CipherKey &key, uint64_t *chainedIV ) const +{ + shared_ptr mk = dynamic_pointer_cast(key); + uint64_t tmp = _checksum_64( mk.get(), data, len, chainedIV ); + + if(chainedIV) + *chainedIV = tmp; + + return tmp; +} + +CipherKey SSL_Cipher::readKey(const unsigned char *data, + const CipherKey &masterKey, bool checkKey) +{ + shared_ptr mk = dynamic_pointer_cast(masterKey); + rAssert(mk->keySize == _keySize); + + unsigned char tmpBuf[ 2 * MAX_KEYLENGTH ]; + + // First N bytes are checksum bytes. + unsigned int checksum = 0; + for(int i=0; i key( new SSLKey( _keySize, _ivLength) ); + + rAssert(_keySize + _ivLength == (unsigned int)key->buf.size ); + memcpy( key->buf.data, tmpBuf, key->buf.size ); + OPENSSL_cleanse(tmpBuf, sizeof(tmpBuf)); + + initKey( key, _blockCipher, _streamCipher, _keySize ); + + return key; +} + +void SSL_Cipher::writeKey(const CipherKey &ckey, unsigned char *data, + const CipherKey &masterKey) +{ + shared_ptr key = dynamic_pointer_cast(ckey); + rAssert(key->keySize == _keySize); + rAssert(key->ivLength == _ivLength); + + shared_ptr mk = dynamic_pointer_cast(masterKey); + rAssert(mk->keySize == _keySize); + rAssert(mk->ivLength == _ivLength); + + unsigned char tmpBuf[ 2 * MAX_KEYLENGTH ]; + + unsigned int bufLen = key->buf.size; + rAssert(_keySize + _ivLength == bufLen ); + memcpy( tmpBuf, key->buf.data, bufLen ); + + unsigned int checksum = MAC_32( tmpBuf, bufLen, masterKey ); + + if (_streamCipher != NULL) + streamEncode(tmpBuf, bufLen, checksum, masterKey); + else + { + bufLen = 2 * _keySize; + blockEncode(tmpBuf, bufLen, checksum, masterKey); + } + + memcpy( data+KEY_CHECKSUM_BYTES, tmpBuf, bufLen ); + + // first N bytes contain HMAC derived checksum.. + for(int i=1; i<=KEY_CHECKSUM_BYTES; ++i) + { + data[KEY_CHECKSUM_BYTES-i] = checksum & 0xff; + checksum >>= 8; + } + + OPENSSL_cleanse(tmpBuf, sizeof(tmpBuf)); +} + +bool SSL_Cipher::compareKey( const CipherKey &A, const CipherKey &B) const +{ + shared_ptr key1 = dynamic_pointer_cast(A); + shared_ptr key2 = dynamic_pointer_cast(B); + + rAssert(key1->buf.size == key2->buf.size); + + if(memcmp(key1->buf.data, key2->buf.data, key1->buf.size) != 0) + return false; + else + return true; +} + +int SSL_Cipher::encodedKeySize() const +{ + if (_streamCipher != NULL) + return _keySize + _ivLength + KEY_CHECKSUM_BYTES; + else + return 2 * _keySize + KEY_CHECKSUM_BYTES; +} + +int SSL_Cipher::keySize() const +{ + return _keySize; +} + +int SSL_Cipher::cipherBlockSize() const +{ + int size = EVP_CIPHER_block_size( _blockCipher ); + // OpenSSL (1.0.1-4ubuntu5.5) reports a block size of 1 for aes_xts. + // If this happens, use a single key width (ie 32 bytes for aes-xts-256). + if (size == 1) + size = _keySize / 2; + return size; +} + +void SSL_Cipher::setIVec(unsigned char *ivec, uint64_t seed, + const shared_ptr &key) const +{ + if (iface.major() >= 3) + { + memcpy( ivec, IVData(key), _ivLength ); + + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int mdLen = EVP_MAX_MD_SIZE; + + for(int i=0; i<8; ++i) + { + md[i] = (unsigned char)(seed & 0xff); + seed >>= 8; + } + + // combine ivec and seed with HMAC + HMAC_Init_ex( &key->mac_ctx, 0, 0, 0, 0 ); + HMAC_Update( &key->mac_ctx, ivec, _ivLength ); + HMAC_Update( &key->mac_ctx, md, 8 ); + HMAC_Final( &key->mac_ctx, md, &mdLen ); + rAssert(mdLen >= _ivLength); + + memcpy( ivec, md, _ivLength ); + } else + { + setIVec_old(ivec, seed, key); + } +} + +// Deprecated: For backward compatibility only. +// A watermark attack was discovered against this IV setup. If an attacker +// could get a victim to store a carefully crafted file, they could later +// determine if the victim had the file in encrypted storage (without decrypting +// the file). +void SSL_Cipher::setIVec_old(unsigned char *ivec, + unsigned int seed, + const shared_ptr &key) const +{ + unsigned int var1 = 0x060a4011 * seed; + unsigned int var2 = 0x0221040d * (seed ^ 0xD3FEA11C); + + memcpy( ivec, IVData(key), _ivLength ); + + ivec[0] ^= (var1 >> 24) & 0xff; + ivec[1] ^= (var2 >> 16) & 0xff; + ivec[2] ^= (var1 >> 8 ) & 0xff; + ivec[3] ^= (var2 ) & 0xff; + ivec[4] ^= (var2 >> 24) & 0xff; + ivec[5] ^= (var1 >> 16) & 0xff; + ivec[6] ^= (var2 >> 8 ) & 0xff; + ivec[7] ^= (var1 ) & 0xff; + + if(_ivLength > 8) + { + ivec[8+0] ^= (var1 ) & 0xff; + ivec[8+1] ^= (var2 >> 8 ) & 0xff; + ivec[8+2] ^= (var1 >> 16) & 0xff; + ivec[8+3] ^= (var2 >> 24) & 0xff; + ivec[8+4] ^= (var1 >> 24) & 0xff; + ivec[8+5] ^= (var2 >> 16) & 0xff; + ivec[8+6] ^= (var1 >> 8 ) & 0xff; + ivec[8+7] ^= (var2 ) & 0xff; + } +} + +static void flipBytes(unsigned char *buf, int size) +{ + unsigned char revBuf[64]; + + int bytesLeft = size; + while(bytesLeft) + { + int toFlip = MIN( (int)sizeof(revBuf), bytesLeft ); + + for(int i=0; i 0 ); + shared_ptr key = dynamic_pointer_cast(ckey); + rAssert(key->keySize == _keySize); + rAssert(key->ivLength == _ivLength); + rAssert( key->stream_enc.key_len > 0 ); + + Lock lock( key->mutex ); + + unsigned char ivec[ MAX_IVLENGTH ]; + int dstLen=0, tmpLen=0; + + shuffleBytes( buf, size ); + + setIVec( ivec, iv64, key ); + EVP_EncryptInit_ex( &key->stream_enc, NULL, NULL, NULL, ivec); + EVP_EncryptUpdate( &key->stream_enc, buf, &dstLen, buf, size ); + EVP_EncryptFinal_ex( &key->stream_enc, buf+dstLen, &tmpLen ); + + flipBytes( buf, size ); + shuffleBytes( buf, size ); + + setIVec( ivec, iv64 + 1, key ); + EVP_EncryptInit_ex( &key->stream_enc, NULL, NULL, NULL, ivec); + EVP_EncryptUpdate( &key->stream_enc, buf, &dstLen, buf, size ); + EVP_EncryptFinal_ex( &key->stream_enc, buf+dstLen, &tmpLen ); + + dstLen += tmpLen; + LOG_IF(ERROR, dstLen != size) << "encoding " << size + << " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; + + return true; +} + +bool SSL_Cipher::streamDecode(unsigned char *buf, int size, + uint64_t iv64, const CipherKey &ckey) const +{ + rAssert( size > 0 ); + shared_ptr key = dynamic_pointer_cast(ckey); + rAssert(key->keySize == _keySize); + rAssert(key->ivLength == _ivLength); + rAssert( key->stream_dec.key_len > 0 ); + + Lock lock( key->mutex ); + + unsigned char ivec[ MAX_IVLENGTH ]; + int dstLen=0, tmpLen=0; + + setIVec( ivec, iv64 + 1, key ); + EVP_DecryptInit_ex( &key->stream_dec, NULL, NULL, NULL, ivec); + EVP_DecryptUpdate( &key->stream_dec, buf, &dstLen, buf, size ); + EVP_DecryptFinal_ex( &key->stream_dec, buf+dstLen, &tmpLen ); + + unshuffleBytes( buf, size ); + flipBytes( buf, size ); + + setIVec( ivec, iv64, key ); + EVP_DecryptInit_ex( &key->stream_dec, NULL, NULL, NULL, ivec); + EVP_DecryptUpdate( &key->stream_dec, buf, &dstLen, buf, size ); + EVP_DecryptFinal_ex( &key->stream_dec, buf+dstLen, &tmpLen ); + + unshuffleBytes( buf, size ); + + dstLen += tmpLen; + LOG_IF(ERROR, dstLen != size) << "encoding " << size + << " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; + + return true; +} + + +bool SSL_Cipher::blockEncode(unsigned char *buf, int size, + uint64_t iv64, const CipherKey &ckey ) const +{ + rAssert( size > 0 ); + shared_ptr key = dynamic_pointer_cast(ckey); + rAssert(key->keySize == _keySize); + rAssert(key->ivLength == _ivLength); + + // data must be integer number of blocks + const int blockMod = size % EVP_CIPHER_CTX_block_size( &key->block_enc ); + rAssert(blockMod == 0); + + Lock lock( key->mutex ); + + unsigned char ivec[ MAX_IVLENGTH ]; + + int dstLen = 0, tmpLen = 0; + setIVec( ivec, iv64, key ); + + EVP_EncryptInit_ex( &key->block_enc, NULL, NULL, NULL, ivec); + EVP_EncryptUpdate( &key->block_enc, buf, &dstLen, buf, size ); + EVP_EncryptFinal_ex( &key->block_enc, buf+dstLen, &tmpLen ); + dstLen += tmpLen; + + LOG_IF(ERROR, dstLen != size) << "encoding " << size + << " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; + + return true; +} + +bool SSL_Cipher::blockDecode(unsigned char *buf, int size, + uint64_t iv64, const CipherKey &ckey ) const +{ + rAssert( size > 0 ); + shared_ptr key = dynamic_pointer_cast(ckey); + rAssert(key->keySize == _keySize); + rAssert(key->ivLength == _ivLength); + + // data must be integer number of blocks + const int blockMod = size % EVP_CIPHER_CTX_block_size( &key->block_dec ); + rAssert(blockMod == 0); + + Lock lock( key->mutex ); + + unsigned char ivec[ MAX_IVLENGTH ]; + + int dstLen = 0, tmpLen = 0; + setIVec( ivec, iv64, key ); + + EVP_DecryptInit_ex( &key->block_dec, NULL, NULL, NULL, ivec); + EVP_DecryptUpdate( &key->block_dec, buf, &dstLen, buf, size ); + EVP_DecryptFinal_ex( &key->block_dec, buf+dstLen, &tmpLen ); + dstLen += tmpLen; + + LOG_IF(ERROR, dstLen != size) << "decoding " << size + << " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; + + return true; +} + +bool SSL_Cipher::Enabled() +{ + return true; +} + +bool SSL_Cipher::hasStreamMode() const +{ + return false; +} diff --git a/cipher/SSL_Cipher.h b/cipher/SSL_Cipher.h new file mode 100644 index 0000000..9eb4d1b --- /dev/null +++ b/cipher/SSL_Cipher.h @@ -0,0 +1,159 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2004, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef _SSL_Cipher_incl_ +#define _SSL_Cipher_incl_ + +#include "cipher/Cipher.h" +#include "base/Interface.h" + +class SSLKey; +#ifndef EVP_CIPHER +struct evp_cipher_st; +typedef struct evp_cipher_st EVP_CIPHER; +#endif + +/* + Implements Cipher interface for OpenSSL's ciphers. + + Design: + Variable algorithm, key size, and block size. + + Partial blocks, keys, and names are encrypted using the cipher in a pseudo + stream mode (CFB). + + Keys are encrypted with 2-4 (KEY_CHECKSUM_BYTES define) checksum bytes + derived from an HMAC over both they key data and the initial value vector + associated with the key. This allows a good chance at detecting an + incorrect password when we try and decrypt the master key. + + File names are encrypted in the same way, with 2 checksum bytes derived + from an HMAC over the filename. This is done not to allow checking the + results, but to make the output much more random. Changing one letter in a + filename should result in a completely different encrypted filename, to + help frustrate any attempt to guess information about files from their + encrypted names. + + Stream encryption involves two encryption passes over the data, implemented + as: + 1. shuffle + 2. encrypt + 3. reverse + 4. shuffle + 5. encrypt + The reason for the shuffle and reverse steps (and the second encrypt pass) + is to try and propogate any changed bits to a larger set. If only a single + pass was made with the stream cipher in CFB mode, then a change to one byte + may only affect one byte of output, allowing some XOR attacks. + + The shuffle/encrypt is used as above in filename encryption as well, + although it is not necessary as they have checksum bytes which augment the + initial value vector to randomize the output. But it makes the code + simpler to reuse the encryption algorithm as is. +*/ +class SSL_Cipher : public Cipher +{ + Interface iface; + Interface realIface; + const EVP_CIPHER *_blockCipher; + const EVP_CIPHER *_streamCipher; + unsigned int _keySize; // in bytes + unsigned int _ivLength; + + public: + SSL_Cipher(const Interface &iface, const Interface &realIface, + const EVP_CIPHER *blockCipher, const EVP_CIPHER *streamCipher, + int keyLength); + virtual ~SSL_Cipher(); + + // returns the real interface, not the one we're emulating (if any).. + virtual Interface interface() const; + + // create a new key based on a password + virtual CipherKey newKey(const char *password, int passwdLength, + int &iterationCount, long desiredDuration, + const unsigned char *salt, int saltLen); + // deprecated - for backward compatibility + virtual CipherKey newKey(const char *password, int passwdLength); + // create a new random key + virtual CipherKey newRandomKey(); + + // data must be len keySize() + virtual CipherKey readKey(const unsigned char *data, + const CipherKey &encodingKey, + bool checkKey); + virtual void writeKey(const CipherKey &key, unsigned char *data, + const CipherKey &encodingKey); + virtual bool compareKey( const CipherKey &A, + const CipherKey &B ) const; + + // meta-data about the cypher + virtual int keySize() const; + virtual int encodedKeySize() const; + virtual int cipherBlockSize() const; + + virtual bool hasStreamMode() const; + + virtual bool randomize( unsigned char *buf, int len, + bool strongRandom ) const; + + virtual uint64_t MAC_64( const unsigned char *src, int len, + const CipherKey &key, uint64_t *augment ) const; + + // functional interfaces + /* + Stream encoding in-place. + */ + virtual bool streamEncode(unsigned char *in, int len, + uint64_t iv64, const CipherKey &key) const; + virtual bool streamDecode(unsigned char *in, int len, + uint64_t iv64, const CipherKey &key) const; + + /* + Block encoding is done in-place. Partial blocks are supported, but + blocks are always expected to begin on a block boundary. See + blockSize(). + */ + virtual bool blockEncode(unsigned char *buf, int size, + uint64_t iv64, const CipherKey &key) const; + virtual bool blockDecode(unsigned char *buf, int size, + uint64_t iv64, const CipherKey &key) const; + + // hack to help with static builds + static bool Enabled(); + + // Password-based key derivation function which determines the + // number of iterations based on a desired execution time (in microseconds). + // Returns the number of iterations applied. + static int TimedPBKDF2(const char *pass, int passLen, + const unsigned char *salt, int saltLen, + int keyLen, unsigned char *out, + long desiredPDFTimeMicroseconds); + private: + void setIVec( unsigned char *ivec, uint64_t seed, + const shared_ptr &key ) const; + + // deprecated - for backward compatibility + void setIVec_old( unsigned char *ivec, unsigned int seed, + const shared_ptr &key ) const; +}; + +#endif + diff --git a/cipher/openssl.cpp b/cipher/openssl.cpp new file mode 100644 index 0000000..658ea99 --- /dev/null +++ b/cipher/openssl.cpp @@ -0,0 +1,109 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2007, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "cipher/openssl.h" + +#include + +#include + +#define NO_DES +#include +#include +#ifndef OPENSSL_NO_ENGINE +#include +#endif + +unsigned long pthreads_thread_id() +{ + return (unsigned long)pthread_self(); +} + +static pthread_mutex_t *crypto_locks = NULL; +void pthreads_locking_callback( int mode, int n, + const char *caller_file, int caller_line ) +{ + (void)caller_file; + (void)caller_line; + + if(!crypto_locks) + { + VLOG(1) << "Allocating " << CRYPTO_num_locks() << " locks for OpenSSL"; + crypto_locks = new pthread_mutex_t[ CRYPTO_num_locks() ]; + for(int i=0; i= 5) - { - return 0; - } else - return -1; -]])], - [AC_MSG_RESULT([yes])], - [AC_MSG_RESULT([no]) - AC_MSG_FAILURE([ -Encfs 1.3 requires FUSE 2.5 or newer. Please check config.log for errors. If -you cannot determine the problem, mail encfs-users@lists.sourceforge.net -and include the config.log file]) - ] -) - -dnl fuse_operations.setxattr was added 2004-03-31 -dnl only enable it if setxattr function is found.. -AC_CHECK_HEADERS([attr/xattr.h sys/xattr.h]) - -dnl xattr functions take additional arguments on some systems (eg Darwin). -AC_CACHE_CHECK([whether xattr interface takes additional options], - smb_attr_cv_xattr_add_opt, [ - old_LIBS=$LIBS - LIBS="$LIBS $ACL_LIBS" - AC_TRY_COMPILE([ - #include - #if HAVE_ATTR_XATTR_H - #include - #elif HAVE_SYS_XATTR_H - #include - #endif - ],[ - getxattr(0, 0, 0, 0, 0, 0); - ], - [smb_attr_cv_xattr_add_opt=yes], - [smb_attr_cv_xattr_add_opt=no;LIBS=$old_LIBS]) -]) -if test x"$smb_attr_cv_xattr_add_opt" = x"yes"; then - AC_DEFINE(XATTR_ADD_OPT, 1, [xattr functions have additional options]) -fi - -dnl Check for valgrind headers.. -AC_ARG_ENABLE(valgrind, - AC_HELP_STRING([--enable-valgrind], - [build with valgrind support.]), - AC_CHECK_HEADERS([valgrind/valgrind.h valgrind/memcheck.h]) - ) - -# allow user option of not using ssl.. -AC_ARG_ENABLE(openssl, - AC_HELP_STRING([--disable-openssl], - [disables openssl library usage.]), - with_openssl=$enableval, with_openssl="yes" ) - -# try checking for openssl using -if test "x$with_openssl" = "xyes"; then - # look for openssl using pkg-config first.. - PKG_CHECK_MODULES(OPENSSL, openssl >= 0.9.7, - with_openssl="yes", with_openssl="old-test") - - # If that fails, try checking via old methods - which isn't as robust when - # it comes to extra include paths, etc.. - if test "x$with_openssl" = "xold-test"; then - AC_CHECK_HEADER(openssl/ssl.h, - AC_CHECK_LIB(ssl,SSL_new, - [with_openssl="yes"])) - OPENSSL_LIBS="-lssl" - fi - - # if we have openssl, then examine available interfaces. - if test "x$with_openssl" = "xyes"; then - AC_DEFINE(HAVE_SSL, [1], [Linking with OpenSSL]) - - # add in the libs just for the test.. - oldflags=$CXXFLAGS - oldlibs=$LIBS - CXXFLAGS="$CXXFLAGS $OPENSSL_CFLAGS" - LIBS="$LIBS $OPENSSL_LIBS" - AC_CHECK_FUNCS(EVP_aes_128_cbc EVP_aes_192_cbc EVP_aes_256_cbc, - AC_DEFINE(HAVE_EVP_AES, [1], [Have EVP AES interfaces])) - AC_CHECK_FUNCS(EVP_bf_cbc, - AC_DEFINE(HAVE_EVP_BF, [1], [Have EVP Blowfish interfaces])) - AC_CHECK_FUNCS(EVP_CIPHER_CTX_set_padding, - with_opensslevp=yes, - AC_MSG_WARN([New SSL cipher code only enabled for OpenSSL 0.9.7 or later])) - AC_CHECK_FUNCS(HMAC_Init_ex, - AC_DEFINE(HAVE_HMAC_INIT_EX, [1], [Have HMAC_Init_ex function])) - - CXXFLAGS="$oldflags" - LIBS="$oldlibs" - - AC_SUBST(HAVE_EVP_AES) - AC_SUBST(HAVE_EVP_BF) - AC_SUBST(HAVE_HMAC_INIT_EX) - fi -fi -AM_CONDITIONAL( BUILD_OPENSSL, test "x$with_openssl" = "xyes" ) -AM_CONDITIONAL( BUILD_SSLCIPHER, test "x$with_opensslevp" = "xyes" ) -AC_SUBST(HAVE_SSL) - -if test "x$with_openssl" != "xyes"; then - AC_MSG_ERROR( [Encfs requires OpenSSL]) -fi - -# check for RLOG -PKG_CHECK_MODULES(RLOG, librlog >= 1.3, with_rlog="yes", with_rlog="test") - -# manual check for rlog, unless environment variable already set -if test "$with_rlog" = "test" && test "x$RLOG_LIBS" = "x"; then - AC_MSG_WARN([Checking for librlog the hard way]) - AC_CHECK_LIB(rlog, RLogVersion, [RLOG_LIBS="-lrlog"], - [AC_MSG_ERROR([EncFS depends on librlog])]) -fi - -# find Protocol Buffers -PKG_CHECK_MODULES(PROTOBUF, protobuf >= 2.0) -AC_PATH_PROG(PROTOC, protoc, [no]) -if test "$PROTOC" == "no"; then - AC_MSG_FAILURE([Protocol Buffers compiler 'protoc' is required to build.]) -fi - -# find TinyXML -AC_LANG_PUSH([C++]) -CPPFLAGS="$CPPFLAGS -DTIXML_USE_STL" -AC_CHECK_HEADER([tinyxml.h],,[AC_MSG_ERROR([tinyxml.h not found])]) -AC_CHECK_LIB([tinyxml],[main],, - [AC_MSG_ERROR([you must install libtinyxml dev])]) -AC_LANG_POP([C++]) - -# look for pod2man program for building man pages -AC_PATH_PROG(POD2MAN, pod2man, [no]) -AC_PATH_PROG(POD2HTML, pod2html, [no]) -AM_CONDITIONAL( BUILD_MAN, test "x$POD2MAN" != "xno" ) -AM_CONDITIONAL( BUILD_MANHTML, test "x$POD2HTML" != "xno" ) -AM_CONDITIONAL( BUILD_NLS, test "x$USE_NLS" != "xno" ) - - -AC_CONFIG_FILES([Makefile] \ - [encfs/Makefile] \ - [encfs.spec] \ - [makedist2.sh] \ - [m4/Makefile] \ - [po/Makefile.in] \ - [po/Makefile]) - -AC_OUTPUT - diff --git a/devmode b/devmode new file mode 100644 index 0000000..5d53278 --- /dev/null +++ b/devmode @@ -0,0 +1,2 @@ +mkdir build +cd build && cmake .. -DCMAKE_BUILD_TYPE=Debug $@ diff --git a/encfs.spec.in b/encfs.spec.in deleted file mode 100644 index bab0b81..0000000 --- a/encfs.spec.in +++ /dev/null @@ -1,207 +0,0 @@ -Name: encfs -Summary: Encrypted pass-thru filesystem for Linux -Version: @VERSION@ -Release: @RELEASE@ -License: GPL -Group: System/Filesystems -Source: %{name}-%{version}-%{release}.tgz -BuildRoot: %{_tmppath}/build-root-%{name} -Packager: Valient Gough -#Distribution: Suse 9.1 -Prefix: /usr -Url: http://pobox.com/~vgough/encfs -Provides: encfs -Provides: encfsctl -Provides: libencfs.1 - -Requires: rlog >= 1.3 -Requires: openssl -Requires: fuse >= 2.2 - -%description -EncFS implements an encrypted filesystem in userspace using FUSE. FUSE -provides a Linux kernel module which allows virtual filesystems to be written -in userspace. EncFS encrypts all data and filenames in the filesystem and -passes access through to the underlying filesystem. Similar to CFS except that -it does not use NFS. - -%changelog -* Fri Nov 11 2005 Valient Gough -- Release 1.2.5 -- Fix race condition when using newer versions of GCC. Fixes problem reported - by Chris at x.nu. -- add encfssh script, thanks to David Rosenstrauch -* Fri Aug 26 2005 Valient Gough -- Release 1.2.4 -- fix segfault if small invalid filenames were encountered in the encrypted - directory, reported by paulgfx. -- try and detect if user tries to mount the filesystem over the top of the - encrypted directory, problem reported by paulgfx. -- environment variable ENCFS5_CONFIG can be used to override the location of - the .encfs5 configuration file. -- add encfsctl 'export' command, patch from Janne Hellsten - -* Tue Apr 19 2005 Valient Gough -- Release 1.2.1 -- add --public mount option -- add --stdinpass option to read password from stdin for scripting -- import latest rosetta translation updates - -* Thu Feb 10 2005 Valient Gough -- Release 1.2.0 -- Fix bug with MAC headers and files > 2GB, reported by Damian Frank -- Fix bug with external password interface which could result in problems - communicating with external password program. Found by Olivier Dournaux. -- Switch to FUSE 2.2 API -- support for FUSE 1.x has been dropped. -- Add support for inode numbering pass-thru (when used 'use_ino' option to - fuse). This allows encoded filesystem to use the same inode numbers as the - underlying filesystem. - -* Wed Jan 12 2005 Valient Gough -- Release 1.1.11 -- add internationalization support. Thanks to lots of contributors, there are - translations for serveral languages. -- added workaround for libfuse mount failure with FUSE 1.4 -- fix compile failure with FUSE 1.4 - -* Mon Nov 8 2004 Valient Gough -- Release 1.1.10 -- fix problems with recursive rename -- fix incorrect error codes from xattr functions - -* Tue Aug 15 2004 Valient Gough -- Release 1.1.9 -- fix another rename bug (affected filesystems with 'paranoia' configuration) - -* Mon Aug 14 2004 Valient Gough -- Release 1.1.8 -- Improve MAC block header processing. - -* Sat Aug 12 2004 Valient Gough -- Release 1.1.7 -- fix bug in truncate() for unopened files. - -* Mon Aug 9 2004 Valient Gough -- Release 1.1.6 -- fix header IV creation when truncate() used to create files. -- add support for IV chaining to old 0.x filesystem support code (useful for - systems with old OpenSSL, like RedHat 7.x). - -* Tue Jul 22 2004 Valient Gough -- Release 1.1.5 - -* Sat Jul 10 2004 Valient Gough -- Release 1.1.4 -- add external password prompt support. - -* Thu Jun 24 2004 Valient Gough -- Release 1.1.3 - -* Fri May 28 2004 Valient Gough -- Release 1.1.2 -- Fix bug affecting filesystems with small empty directories (like XFS) -- Updates to recursive rename code to undo all changes on failure. -- Fix OpenSSL dependency path inclusion in build. - -* Wed May 19 2004 Valient Gough -- Release 1.1.1 -- Fix MAC header memory size allocation error. -- Add file rename-while-open support needed for Evolution. - -* Thu May 13 2004 Valient Gough -- Second release candidate for version 1.1 -- Add support for block mode filename encryption. -- Add support for per-file initialization vectors. -- Add support for directory IV chaining for per-directory initialization - vectors. -- Add support for per-block MAC headers for file contents. -- Backward compatibility support dropped for filesystems created by version - 0.x. Maintains backward compatible support for versions 1.0.x. - -* Sun Apr 4 2004 Valient Gough -- Release 1.0.5 -- Allow truncate call to extend file (only shrinking was supported) - -* Fri Mar 26 2004 Valient Gough -- Release 1.0.4 -- Large speed improvement. -- Add support for FUSE major version 2 API. - -* Thu Mar 18 2004 Valient Gough -- Release 1.0.3 -- Fix bugs in truncation and padding code. - -* Sat Mar 13 2004 Valient Gough -- Release 1.0.2 -- Use pkg-config to check for OpenSSL and RLog build settings -- Add support for '--' argument to encfs to pass arbitrary options to FUSE / - fusermount. -- Add man pages. - -* Tue Mar 2 2004 Valient Gough -- Release 1.0.1 -- Fix problem with using OpenSSL's EVP_BytesToKey function with variable - key length ciphers like Blowfish, as it would only generate 128 bit keys. -- Some configure script changes to make it possible to use --with-extra-include - configure option to pick up any necessary directories for OpenSSL. - -* Fri Feb 27 2004 Valient Gough -- Release 1.0 -- Added some pre-defined configuration options at startup to make filesystem - creation a bit more user friendly. - -* Mon Feb 23 2004 Valient Gough -- Merge development branch to mainline. Source modularized to make it easier - to support different algorithms. -- Added encfsctl program which can show information about an encrypted - directory and can change the user password used to store the volume key. -- Added support for AES and BlowFish with user specified keys and block sizes - (when building with OpenSSL >= 0.9.7). -- Backward compatible with old format, but new filesystems store configuration - information in a new format which is not readable by old encfs versions. - -* Sat Feb 7 2004 Valient Gough -- Improved performance by fixing cache bug which caused cached data to not be - used as often as it could have been. Random seek performance improved by - 600% according to Bonnie++ benchmark. -- Fixed bugs preventing files larger then 2GB. Limit should now be around - 128GB (untested - I don't have that much drive space). > 2GB also requires - recent version of FUSE module (from Feb 6 or later) and an underlying - filesystem which supports large files. -- Release 0.6 - -%prep -rm -rf $RPM_BUILD_ROOT -mkdir $RPM_BUILD_ROOT - -%setup -q - -%build -CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_FLAGS" \ -./configure --enable-debug=no --prefix=%{prefix} --mandir=%{_mandir} -make SED=/usr/bin/sed -j 2 - -%install -make DESTDIR=$RPM_BUILD_ROOT install-strip - -cd $RPM_BUILD_ROOT - -find . -type d -fprint $RPM_BUILD_DIR/file.list.%{name}.dirs -find . -type f -fprint $RPM_BUILD_DIR/file.list.%{name}.files.tmp -sed '/\/man\//s/$/.gz/g' $RPM_BUILD_DIR/file.list.%{name}.files.tmp > $RPM_BUILD_DIR/file.list.%{name}.files -find . -type l -fprint $RPM_BUILD_DIR/file.list.%{name}.libs -sed '1,2d;s,^\.,\%attr(-\,root\,root) \%dir ,' $RPM_BUILD_DIR/file.list.%{name}.dirs > $RPM_BUILD_DIR/file.list.%{name} -sed 's,^\.,\%attr(-\,root\,root) ,' $RPM_BUILD_DIR/file.list.%{name}.files >> $RPM_BUILD_DIR/file.list.%{name} -sed 's,^\.,\%attr(-\,root\,root) ,' $RPM_BUILD_DIR/file.list.%{name}.libs >> $RPM_BUILD_DIR/file.list.%{name} - -%clean -case "$RPM_BUILD_ROOT" in build-root-*) rm -rf $RPM_BUILD_ROOT ;; esac -rm -f $RPM_BUILD_DIR/file.list.%{name} -rm -f $RPM_BUILD_DIR/file.list.%{name}.libs -rm -f $RPM_BUILD_DIR/file.list.%{name}.files -rm -f $RPM_BUILD_DIR/file.list.%{name}.files.tmp -rm -f $RPM_BUILD_DIR/file.list.%{name}.dirs - -%files -f ../file.list.%{name} - -%defattr(-,root,root,0755) diff --git a/encfs/BlockFileIO.cpp b/encfs/BlockFileIO.cpp deleted file mode 100644 index c3e91e4..0000000 --- a/encfs/BlockFileIO.cpp +++ /dev/null @@ -1,433 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2004, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include "BlockFileIO.h" - -#include "MemoryPool.h" -#include "config.pb.h" - -#include -#include - -#include "i18n.h" - -template -inline Type min( Type A, Type B ) -{ - return (B < A) ? B : A; -} - -static void clearCache( IORequest &req, int blockSize ) -{ - memset( req.data, 0, blockSize ); - req.dataLen = 0; -} - -BlockFileIO::BlockFileIO( int blockSize, const FSConfigPtr &cfg ) - : _blockSize( blockSize ) - , _allowHoles( cfg->config->allow_holes() ) -{ - rAssert( _blockSize > 1 ); - _cache.data = new unsigned char [ _blockSize ]; -} - -BlockFileIO::~BlockFileIO() -{ - clearCache( _cache, _blockSize ); - delete[] _cache.data; -} - -ssize_t BlockFileIO::cacheReadOneBlock( const IORequest &req ) const -{ - // we can satisfy the request even if _cache.dataLen is too short, because - // we always request a full block during reads.. - if((req.offset == _cache.offset) && (_cache.dataLen != 0)) - { - // satisfy request from cache - int len = req.dataLen; - if(_cache.dataLen < len) - len = _cache.dataLen; - memcpy( req.data, _cache.data, len ); - return len; - } else - { - if(_cache.dataLen > 0) - clearCache( _cache, _blockSize ); - - // cache results of read -- issue reads for full blocks - IORequest tmp; - tmp.offset = req.offset; - tmp.data = _cache.data; - tmp.dataLen = _blockSize; - ssize_t result = readOneBlock( tmp ); - if(result > 0) - { - _cache.offset = req.offset; - _cache.dataLen = result; // the amount we really have - if(result > req.dataLen) - result = req.dataLen; // only as much as requested - memcpy( req.data, _cache.data, result ); - } - return result; - } -} - -bool BlockFileIO::cacheWriteOneBlock( const IORequest &req ) -{ - // cache results of write (before pass-thru, because it may be modified - // in-place) - memcpy( _cache.data, req.data, req.dataLen ); - _cache.offset = req.offset; - _cache.dataLen = req.dataLen; - bool ok = writeOneBlock( req ); - if(!ok) - clearCache( _cache, _blockSize ); - return ok; -} - -ssize_t BlockFileIO::read( const IORequest &req ) const -{ - rAssert( _blockSize != 0 ); - - int partialOffset = req.offset % _blockSize; - off_t blockNum = req.offset / _blockSize; - ssize_t result = 0; - - if(partialOffset == 0 && req.dataLen <= _blockSize) - { - // read completely within a single block -- can be handled as-is by - // readOneBloc(). - return cacheReadOneBlock( req ); - } else - { - size_t size = req.dataLen; - - // if the request is larger then a block, then request each block - // individually - MemBlock mb; // in case we need to allocate a temporary block.. - IORequest blockReq; // for requests we may need to make - blockReq.dataLen = _blockSize; - blockReq.data = NULL; - - unsigned char *out = req.data; - while( size ) - { - blockReq.offset = blockNum * _blockSize; - - // if we're reading a full block, then read directly into the - // result buffer instead of using a temporary - if(partialOffset == 0 && size >= (size_t)_blockSize) - blockReq.data = out; - else - { - if(!mb.data) - mb = MemoryPool::allocate( _blockSize ); - blockReq.data = mb.data; - } - - ssize_t readSize = cacheReadOneBlock( blockReq ); - if(unlikely(readSize <= partialOffset)) - break; // didn't get enough bytes - - int cpySize = min( (size_t)(readSize - partialOffset), size ); - rAssert(cpySize <= readSize); - - // if we read to a temporary buffer, then move the data - if(blockReq.data != out) - memcpy( out, blockReq.data + partialOffset, cpySize ); - - result += cpySize; - size -= cpySize; - out += cpySize; - ++blockNum; - partialOffset = 0; - - if(unlikely(readSize < _blockSize)) - break; - } - - if(mb.data) - MemoryPool::release( mb ); - } - - return result; -} - -bool BlockFileIO::write( const IORequest &req ) -{ - rAssert( _blockSize != 0 ); - - off_t fileSize = getSize(); - - // where write request begins - off_t blockNum = req.offset / _blockSize; - int partialOffset = req.offset % _blockSize; - - // last block of file (for testing write overlaps with file boundary) - off_t lastFileBlock = fileSize / _blockSize; - ssize_t lastBlockSize = fileSize % _blockSize; - - off_t lastNonEmptyBlock = lastFileBlock; - if(lastBlockSize == 0) - --lastNonEmptyBlock; - - if( req.offset > fileSize ) - { - // extend file first to fill hole with 0's.. - const bool forceWrite = false; - padFile( fileSize, req.offset, forceWrite ); - } - - // check against edge cases where we can just let the base class handle the - // request as-is.. - if(partialOffset == 0 && req.dataLen <= _blockSize) - { - // if writing a full block.. pretty safe.. - if( req.dataLen == _blockSize ) - return cacheWriteOneBlock( req ); - - // if writing a partial block, but at least as much as what is - // already there.. - if(blockNum == lastFileBlock && req.dataLen >= lastBlockSize) - return cacheWriteOneBlock( req ); - } - - // have to merge data with existing block(s).. - MemBlock mb; - - IORequest blockReq; - blockReq.data = NULL; - blockReq.dataLen = _blockSize; - - bool ok = true; - size_t size = req.dataLen; - unsigned char *inPtr = req.data; - while( size ) - { - blockReq.offset = blockNum * _blockSize; - int toCopy = min((size_t)(_blockSize - partialOffset), size); - - // if writing an entire block, or writing a partial block that requires - // no merging with existing data.. - if( (toCopy == _blockSize) - ||(partialOffset == 0 && blockReq.offset + toCopy >= fileSize)) - { - // write directly from buffer - blockReq.data = inPtr; - blockReq.dataLen = toCopy; - } else - { - // need a temporary buffer, since we have to either merge or pad - // the data. - if(!mb.data) - mb = MemoryPool::allocate( _blockSize ); - memset( mb.data, 0, _blockSize ); - blockReq.data = mb.data; - - if(blockNum > lastNonEmptyBlock) - { - // just pad.. - blockReq.dataLen = toCopy + partialOffset; - } else - { - // have to merge with existing block data.. - blockReq.dataLen = _blockSize; - blockReq.dataLen = cacheReadOneBlock( blockReq ); - - // extend data if necessary.. - if( partialOffset + toCopy > blockReq.dataLen ) - blockReq.dataLen = partialOffset + toCopy; - } - // merge in the data to be written.. - memcpy( blockReq.data + partialOffset, inPtr, toCopy ); - } - - // Finally, write the damn thing! - if(!cacheWriteOneBlock( blockReq )) - { - ok = false; - break; - } - - // prepare to start all over with the next block.. - size -= toCopy; - inPtr += toCopy; - ++blockNum; - partialOffset = 0; - } - - if(mb.data) - MemoryPool::release( mb ); - - return ok; -} - -int BlockFileIO::blockSize() const -{ - return _blockSize; -} - -void BlockFileIO::padFile( off_t oldSize, off_t newSize, bool forceWrite ) -{ - off_t oldLastBlock = oldSize / _blockSize; - off_t newLastBlock = newSize / _blockSize; - int newBlockSize = newSize % _blockSize; - - IORequest req; - MemBlock mb; - - if(oldLastBlock == newLastBlock) - { - // when the real write occurs, it will have to read in the existing - // data and pad it anyway, so we won't do it here (unless we're - // forced). - if( forceWrite ) - { - mb = MemoryPool::allocate( _blockSize ); - req.data = mb.data; - - req.offset = oldLastBlock * _blockSize; - req.dataLen = oldSize % _blockSize; - int outSize = newSize % _blockSize; // outSize > req.dataLen - - if(outSize) - { - memset( mb.data, 0, outSize ); - cacheReadOneBlock( req ); - req.dataLen = outSize; - cacheWriteOneBlock( req ); - } - } else - rDebug("optimization: not padding last block"); - } else - { - mb = MemoryPool::allocate( _blockSize ); - req.data = mb.data; - - // 1. extend the first block to full length - // 2. write the middle empty blocks - // 3. write the last block - - req.offset = oldLastBlock * _blockSize; - req.dataLen = oldSize % _blockSize; - - // 1. req.dataLen == 0, iff oldSize was already a multiple of blocksize - if(req.dataLen != 0) - { - rDebug("padding block %" PRIi64, oldLastBlock); - memset( mb.data, 0, _blockSize ); - cacheReadOneBlock( req ); - req.dataLen = _blockSize; // expand to full block size - cacheWriteOneBlock( req ); - ++oldLastBlock; - } - - // 2, pad zero blocks unless holes are allowed - if(!_allowHoles) - { - for(; oldLastBlock != newLastBlock; ++oldLastBlock) - { - rDebug("padding block %" PRIi64, oldLastBlock); - req.offset = oldLastBlock * _blockSize; - req.dataLen = _blockSize; - memset( mb.data, 0, req.dataLen ); - cacheWriteOneBlock( req ); - } - } - - // 3. only necessary if write is forced and block is non 0 length - if(forceWrite && newBlockSize) - { - req.offset = newLastBlock * _blockSize; - req.dataLen = newBlockSize; - memset( mb.data, 0, req.dataLen ); - cacheWriteOneBlock( req ); - } - } - - if(mb.data) - MemoryPool::release( mb ); -} - -int BlockFileIO::truncate( off_t size, FileIO *base ) -{ - int partialBlock = size % _blockSize; - int res = 0; - - off_t oldSize = getSize(); - - if( size > oldSize ) - { - // truncate can be used to extend a file as well. truncate man page - // states that it will pad with 0's. - // do the truncate so that the underlying filesystem can allocate - // the space, and then we'll fill it in padFile.. - if(base) - base->truncate( size ); - - const bool forceWrite = true; - padFile( oldSize, size, forceWrite ); - } else - if( size == oldSize ) - { - // the easiest case, but least likely.... - } else - if( partialBlock ) - { - // partial block after truncate. Need to read in the block being - // truncated before the truncate. Then write it back out afterwards, - // since the encoding will change.. - off_t blockNum = size / _blockSize; - MemBlock mb = MemoryPool::allocate( _blockSize ); - - IORequest req; - req.offset = blockNum * _blockSize; - req.dataLen = _blockSize; - req.data = mb.data; - - ssize_t rdSz = cacheReadOneBlock( req ); - - // do the truncate - if(base) - res = base->truncate( size ); - - // write back out partial block - req.dataLen = partialBlock; - bool wrRes = cacheWriteOneBlock( req ); - - if((rdSz < 0) || (!wrRes)) - { - // rwarning - unlikely to ever occur.. - rWarning(_("truncate failure: read %i bytes, partial block of %i"), - (int)rdSz, partialBlock ); - } - - MemoryPool::release( mb ); - } else - { - // truncating on a block bounday. No need to re-encode the last - // block.. - if(base) - res = base->truncate( size ); - } - - return res; -} - diff --git a/encfs/BlockNameIO.cpp b/encfs/BlockNameIO.cpp deleted file mode 100644 index b318965..0000000 --- a/encfs/BlockNameIO.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2004-2011, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include "BlockNameIO.h" - -#include "Cipher.h" -#include "base64.h" - -#include -#include -#include -#include - -#include "i18n.h" - -using namespace rlog; - -static RLogChannel * Info = DEF_CHANNEL( "info/nameio", Log_Info ); - - -static shared_ptr NewBlockNameIO( const Interface &iface, - const shared_ptr &cipher, const CipherKey &key ) -{ - int blockSize = 8; - if(cipher) - blockSize = cipher->cipherBlockSize(); - - return shared_ptr( - new BlockNameIO( iface, cipher, key, blockSize, false)); -} - -static shared_ptr NewBlockNameIO32( const Interface &iface, - const shared_ptr &cipher, const CipherKey &key ) -{ - int blockSize = 8; - if(cipher) - blockSize = cipher->cipherBlockSize(); - - return shared_ptr( - new BlockNameIO( iface, cipher, key, blockSize, true)); -} - -static bool BlockIO_registered = NameIO::Register("Block", - // description of block name encoding algorithm.. - // xgroup(setup) - gettext_noop("Block encoding, hides file name size somewhat"), - BlockNameIO::CurrentInterface(false), - NewBlockNameIO); - -static bool BlockIO32_registered = NameIO::Register("Block32", - // description of block name encoding algorithm.. - // xgroup(setup) - gettext_noop("Block encoding with base32 output for case-sensitive systems"), - BlockNameIO::CurrentInterface(true), - NewBlockNameIO32); - -/* - - Version 1.0 computed MAC over the filename, but not the padding bytes. - This version was from pre-release 1.1, never publically released, so no - backward compatibility necessary. - - - Version 2.0 includes padding bytes in MAC computation. This way the MAC - computation uses the same number of bytes regardless of the number of - padding bytes. - - - Version 3.0 uses full 64 bit initialization vector during IV chaining. - Prior versions used only the output from the MAC_16 call, giving a 1 in - 2^16 chance of the same name being produced. Using the full 64 bit IV - changes that to a 1 in 2^64 chance.. - - - Version 4.0 adds support for base32, creating names more suitable for - case-insensitive filesystems (eg Mac). -*/ -Interface BlockNameIO::CurrentInterface(bool caseSensitive) -{ - // implement major version 4 plus support for two prior versions - if (caseSensitive) - return makeInterface("nameio/block32", 4, 0, 2); - else - return makeInterface("nameio/block", 4, 0, 2); -} - -BlockNameIO::BlockNameIO( const Interface &iface, - const shared_ptr &cipher, - const CipherKey &key, int blockSize, - bool caseSensitiveEncoding ) - : _interface( iface.major() ) - , _bs( blockSize ) - , _cipher( cipher ) - , _key( key ) - , _caseSensitive( caseSensitiveEncoding ) -{ - // just to be safe.. - rAssert( blockSize < 128 ); -} - -BlockNameIO::~BlockNameIO() -{ -} - -Interface BlockNameIO::interface() const -{ - return CurrentInterface(_caseSensitive); -} - -int BlockNameIO::maxEncodedNameLen( int plaintextNameLen ) const -{ - // number of blocks, rounded up.. Only an estimate at this point, err on - // the size of too much space rather then too little. - int numBlocks = ( plaintextNameLen + _bs ) / _bs; - int encodedNameLen = numBlocks * _bs + 2; // 2 checksum bytes - if (_caseSensitive) - return B256ToB32Bytes( encodedNameLen ); - else - return B256ToB64Bytes( encodedNameLen ); -} - -int BlockNameIO::maxDecodedNameLen( int encodedNameLen ) const -{ - int decLen256 = _caseSensitive ? - B32ToB256Bytes( encodedNameLen ) : - B64ToB256Bytes( encodedNameLen ); - return decLen256 - 2; // 2 checksum bytes removed.. -} - -int BlockNameIO::encodeName( const char *plaintextName, int length, - uint64_t *iv, char *encodedName ) const -{ - // copy the data into the encoding buffer.. - memcpy( encodedName+2, plaintextName, length ); - - // Pad encryption buffer to block boundary.. - int padding = _bs - length % _bs; - if(padding == 0) - padding = _bs; // padding a full extra block! - - memset( encodedName+length+2, (unsigned char)padding, padding ); - - // store the IV before it is modified by the MAC call. - uint64_t tmpIV = 0; - if( iv && _interface >= 3 ) - tmpIV = *iv; - - // include padding in MAC computation - unsigned int mac = _cipher->MAC_16( (unsigned char *)encodedName+2, - length+padding, _key, iv ); - - // add checksum bytes - encodedName[0] = (mac >> 8) & 0xff; - encodedName[1] = (mac ) & 0xff; - - _cipher->blockEncode( (unsigned char *)encodedName+2, length+padding, - (uint64_t)mac ^ tmpIV, _key); - - // convert to base 64 ascii - int encodedStreamLen = length + 2 + padding; - int encLen; - - if (_caseSensitive) - { - encLen = B256ToB32Bytes( encodedStreamLen ); - - changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen, - 8, 5, true ); - B32ToAscii( (unsigned char *)encodedName, encLen ); - } else - { - encLen = B256ToB64Bytes( encodedStreamLen ); - - changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen, - 8, 6, true ); - B64ToAscii( (unsigned char *)encodedName, encLen ); - } - - return encLen; -} - -int BlockNameIO::decodeName( const char *encodedName, int length, - uint64_t *iv, char *plaintextName ) const -{ - int decLen256 = _caseSensitive ? - B32ToB256Bytes( length ) : - B64ToB256Bytes( length ); - int decodedStreamLen = decLen256 - 2; - - // don't bother trying to decode files which are too small - if(decodedStreamLen < _bs) - throw ERROR("Filename too small to decode"); - - BUFFER_INIT( tmpBuf, 32, (unsigned int)length ); - - // decode into tmpBuf, - if (_caseSensitive) - { - AsciiToB32((unsigned char *)tmpBuf, (unsigned char *)encodedName, length); - changeBase2Inline((unsigned char *)tmpBuf, length, 5, 8, false); - } else - { - AsciiToB64((unsigned char *)tmpBuf, (unsigned char *)encodedName, length); - changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false); - } - - // pull out the header information - unsigned int mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 - | ((unsigned int)((unsigned char)tmpBuf[1])); - - uint64_t tmpIV = 0; - if( iv && _interface >= 3 ) - tmpIV = *iv; - - _cipher->blockDecode( (unsigned char *)tmpBuf+2, decodedStreamLen, - (uint64_t)mac ^ tmpIV, _key); - - // find out true string length - int padding = (unsigned char)tmpBuf[2+decodedStreamLen-1]; - int finalSize = decodedStreamLen - padding; - - // might happen if there is an error decoding.. - if(padding > _bs || finalSize < 0) - { - rDebug("padding, _bx, finalSize = %i, %i, %i", padding, - _bs, finalSize); - throw ERROR( "invalid padding size" ); - } - - // copy out the result.. - memcpy(plaintextName, tmpBuf+2, finalSize); - plaintextName[finalSize] = '\0'; - - // check the mac - unsigned int mac2 = _cipher->MAC_16((const unsigned char *)tmpBuf+2, - decodedStreamLen, _key, iv); - - BUFFER_RESET( tmpBuf ); - - if(mac2 != mac) - { - rDebug("checksum mismatch: expected %u, got %u", mac, mac2); - rDebug("on decode of %i bytes", finalSize); - throw ERROR( "checksum mismatch in filename decode" ); - } - - return finalSize; -} - -bool BlockNameIO::Enabled() -{ - return true; -} - diff --git a/encfs/CMakeLists.txt b/encfs/CMakeLists.txt new file mode 100644 index 0000000..ef21be2 --- /dev/null +++ b/encfs/CMakeLists.txt @@ -0,0 +1,39 @@ + +include_directories (${Encfs_SOURCE_DIR}/base) +link_directories (${Encfs_BINARY_DIR}/base) + +include_directories (${Encfs_SOURCE_DIR}/cipher) +link_directories (${Encfs_BINARY_DIR}/cipher) + +include_directories (${Encfs_SOURCE_DIR}/fs) +link_directories (${Encfs_BINARY_DIR}/fs) + +# TODO: move FUSE code into encfs-fs. +find_package (FUSE REQUIRED) +include_directories (${FUSE_INCLUDE_DIR}) + +include_directories (${CMAKE_BINARY_DIR}/base) + +add_executable (encfs + main.cpp) +target_link_libraries (encfs + encfs-fs + encfs-cipher + encfs-base + ${GLOG_LIBRARIES} + ${FUSE_LIBRARIES} +) + +if (POD2MAN) + add_custom_target(man ALL + COMMAND ${POD2MAN} -u --section=1 --release=${ENCFS_VERSION} + --center="Encrypted Filesystem" + ${CMAKE_CURRENT_SOURCE_DIR}/encfs.pod + encfs.1) + install (FILES ${CMAKE_CURRENT_BINARY_DIR}/encfs.1 + DESTINATION + share/man/man1) +endif (POD2MAN) + +install (TARGETS encfs DESTINATION bin) + diff --git a/encfs/CipherFileIO.cpp b/encfs/CipherFileIO.cpp deleted file mode 100644 index 4cbb8e8..0000000 --- a/encfs/CipherFileIO.cpp +++ /dev/null @@ -1,438 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2004, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include "CipherFileIO.h" - -#include "Cipher.h" -#include "MemoryPool.h" -#include "config.pb.h" - -#include -#include - -#include -#include - -/* - - Version 2:0 adds support for a per-file initialization vector with a - fixed 8 byte header. The headers are enabled globally within a - filesystem at the filesystem configuration level. - When headers are disabled, 2:0 is compatible with version 1:0. -*/ -static Interface CipherFileIO_iface = makeInterface("FileIO/Cipher", 2, 0, 1); - -const int HEADER_SIZE = 8; // 64 bit initialization vector.. - -static bool checkSize( int fsBlockSize, int cipherBlockSize ) -{ - int blockBoundary = fsBlockSize % cipherBlockSize ; - if(blockBoundary != 0) - { - rError("CipherFileIO: blocks should be multiple of cipher block size"); - return true; - } else - return false; -} - -CipherFileIO::CipherFileIO( const shared_ptr &_base, - const FSConfigPtr &cfg) - : BlockFileIO( cfg->config->block_size(), cfg ) - , base( _base ) - , haveHeader( cfg->config->unique_iv() ) - , externalIV( 0 ) - , fileIV( 0 ) - , lastFlags( 0 ) -{ - fsConfig = cfg; - cipher = cfg->cipher; - key = cfg->key; - - static bool warnOnce = false; - - if(!warnOnce) - warnOnce = checkSize( fsConfig->config->block_size(), - fsConfig->cipher->cipherBlockSize() ); -} - -CipherFileIO::~CipherFileIO() -{ -} - -Interface CipherFileIO::interface() const -{ - return CipherFileIO_iface; -} - -int CipherFileIO::open( int flags ) -{ - int res = base->open( flags ); - - if( res >= 0 ) - lastFlags = flags; - - return res; -} - -void CipherFileIO::setFileName( const char *fileName ) -{ - base->setFileName( fileName ); -} - -const char *CipherFileIO::getFileName() const -{ - return base->getFileName(); -} - -bool CipherFileIO::setIV( uint64_t iv ) -{ - rDebug("in setIV, current IV = %" PRIu64 ", new IV = %" PRIu64 - ", fileIV = %" PRIu64, - externalIV, iv, fileIV); - if(externalIV == 0) - { - // we're just being told about which IV to use. since we haven't - // initialized the fileIV, there is no need to just yet.. - externalIV = iv; - if(fileIV != 0) - rWarning("fileIV initialized before externalIV! (%" PRIu64 - ", %" PRIu64 ")", fileIV, externalIV); - } else - if(haveHeader) - { - // we have an old IV, and now a new IV, so we need to update the fileIV - // on disk. - if(fileIV == 0) - { - // ensure the file is open for read/write.. - int newFlags = lastFlags | O_RDWR; - int res = base->open( newFlags ); - if(res < 0) - { - if(res == -EISDIR) - { - // duh -- there are no file headers for directories! - externalIV = iv; - return base->setIV( iv ); - } else - { - rDebug("writeHeader failed to re-open for write"); - return false; - } - } - initHeader(); - } - - uint64_t oldIV = externalIV; - externalIV = iv; - if(!writeHeader()) - { - externalIV = oldIV; - return false; - } - } - - return base->setIV( iv ); -} - -int CipherFileIO::getAttr( struct stat *stbuf ) const -{ - int res = base->getAttr( stbuf ); - // adjust size if we have a file header - if((res == 0) && haveHeader && - S_ISREG(stbuf->st_mode) && (stbuf->st_size > 0)) - { - rAssert(stbuf->st_size >= HEADER_SIZE); - stbuf->st_size -= HEADER_SIZE; - } - - return res; -} - -off_t CipherFileIO::getSize() const -{ - off_t size = base->getSize(); - // No check on S_ISREG here -- don't call getSize over getAttr unless this - // is a normal file! - if(haveHeader && size > 0) - { - rAssert(size >= HEADER_SIZE); - size -= HEADER_SIZE; - } - return size; -} - -void CipherFileIO::initHeader( ) -{ - // check if the file has a header, and read it if it does.. Otherwise, - // create one. - off_t rawSize = base->getSize(); - if(rawSize >= HEADER_SIZE) - { - rDebug("reading existing header, rawSize = %" PRIi64, rawSize); - // has a header.. read it - unsigned char buf[8] = {0}; - - IORequest req; - req.offset = 0; - req.data = buf; - req.dataLen = 8; - base->read( req ); - - cipher->streamDecode( buf, sizeof(buf), - externalIV, key ); - - fileIV = 0; - for(int i=0; i<8; ++i) - fileIV = (fileIV << 8) | (uint64_t)buf[i]; - - rAssert(fileIV != 0); // 0 is never used.. - } else - { - rDebug("creating new file IV header"); - - unsigned char buf[8] = {0}; - do - { - if(!cipher->randomize( buf, 8, false )) - throw ERROR("Unable to generate a random file IV"); - - fileIV = 0; - for(int i=0; i<8; ++i) - fileIV = (fileIV << 8) | (uint64_t)buf[i]; - - if(fileIV == 0) - rWarning("Unexpected result: randomize returned 8 null bytes!"); - } while(fileIV == 0); // don't accept 0 as an option.. - - if( base->isWritable() ) - { - cipher->streamEncode( buf, sizeof(buf), externalIV, key ); - - IORequest req; - req.offset = 0; - req.data = buf; - req.dataLen = 8; - - base->write( req ); - } else - rDebug("base not writable, IV not written.."); - } - rDebug("initHeader finished, fileIV = %" PRIu64 , fileIV); -} - -bool CipherFileIO::writeHeader( ) -{ - if( !base->isWritable() ) - { - // open for write.. - int newFlags = lastFlags | O_RDWR; - if( base->open( newFlags ) < 0 ) - { - rDebug("writeHeader failed to re-open for write"); - return false; - } - } - - if(fileIV == 0) - rError("Internal error: fileIV == 0 in writeHeader!!!"); - rDebug("writing fileIV %" PRIu64 , fileIV); - - unsigned char buf[8] = {0}; - for(int i=0; i<8; ++i) - { - buf[sizeof(buf)-1-i] = (unsigned char)(fileIV & 0xff); - fileIV >>= 8; - } - - cipher->streamEncode( buf, sizeof(buf), externalIV, key ); - - IORequest req; - req.offset = 0; - req.data = buf; - req.dataLen = 8; - - base->write( req ); - - return true; -} - -ssize_t CipherFileIO::readOneBlock( const IORequest &req ) const -{ - // read raw data, then decipher it.. - int bs = blockSize(); - off_t blockNum = req.offset / bs; - - ssize_t readSize = 0; - IORequest tmpReq = req; - - if(haveHeader) - tmpReq.offset += HEADER_SIZE; - readSize = base->read( tmpReq ); - - bool ok; - if(readSize > 0) - { - if(haveHeader && fileIV == 0) - const_cast(this)->initHeader(); - - if(readSize != bs) - { - ok = streamRead( tmpReq.data, (int)readSize, blockNum ^ fileIV); - } else - { - ok = blockRead( tmpReq.data, (int)readSize, blockNum ^ fileIV); - } - - if(!ok) - { - rDebug("decodeBlock failed for block %" PRIi64 ", size %i", - blockNum, (int)readSize ); - readSize = -1; - } - } else - rDebug("readSize zero for offset %" PRIi64, req.offset); - - return readSize; -} - - -bool CipherFileIO::writeOneBlock( const IORequest &req ) -{ - int bs = blockSize(); - off_t blockNum = req.offset / bs; - - if(haveHeader && fileIV == 0) - initHeader(); - - bool ok; - if( req.dataLen != bs ) - { - ok = streamWrite( req.data, (int)req.dataLen, - blockNum ^ fileIV ); - } else - { - ok = blockWrite( req.data, (int)req.dataLen, - blockNum ^ fileIV ); - } - - if( ok ) - { - if(haveHeader) - { - IORequest tmpReq = req; - tmpReq.offset += HEADER_SIZE; - ok = base->write( tmpReq ); - } else - ok = base->write( req ); - } else - { - rDebug("encodeBlock failed for block %" PRIi64 ", size %i", - blockNum, req.dataLen); - ok = false; - } - return ok; -} - -bool CipherFileIO::blockWrite( unsigned char *buf, int size, - uint64_t _iv64 ) const -{ - if (!fsConfig->reverseEncryption) - return cipher->blockEncode( buf, size, _iv64, key ); - else - return cipher->blockDecode( buf, size, _iv64, key ); -} - -bool CipherFileIO::streamWrite( unsigned char *buf, int size, - uint64_t _iv64 ) const -{ - if (!fsConfig->reverseEncryption) - return cipher->streamEncode( buf, size, _iv64, key ); - else - return cipher->streamDecode( buf, size, _iv64, key ); -} - - -bool CipherFileIO::blockRead( unsigned char *buf, int size, - uint64_t _iv64 ) const -{ - if (fsConfig->reverseEncryption) - return cipher->blockEncode( buf, size, _iv64, key ); - else - { - if(_allowHoles) - { - // special case - leave all 0's alone - for(int i=0; iblockDecode( buf, size, _iv64, key ); - - return true; - } else - return cipher->blockDecode( buf, size, _iv64, key ); - } -} - -bool CipherFileIO::streamRead( unsigned char *buf, int size, - uint64_t _iv64 ) const -{ - if (fsConfig->reverseEncryption) - return cipher->streamEncode( buf, size, _iv64, key ); - else - return cipher->streamDecode( buf, size, _iv64, key ); -} - - - -int CipherFileIO::truncate( off_t size ) -{ - int res = 0; - if(!haveHeader) - { - res = BlockFileIO::truncate( size, base.get() ); - } else - { - if(0 == fileIV) - { - // empty file.. create the header.. - if( !base->isWritable() ) - { - // open for write.. - int newFlags = lastFlags | O_RDWR; - if( base->open( newFlags ) < 0 ) - rDebug("writeHeader failed to re-open for write"); - } - initHeader(); - } - - // can't let BlockFileIO call base->truncate(), since it would be using - // the wrong size.. - res = BlockFileIO::truncate( size, 0 ); - - if(res == 0) - base->truncate( size + HEADER_SIZE ); - } - return res; -} - -bool CipherFileIO::isWritable() const -{ - return base->isWritable(); -} - diff --git a/encfs/ConfigReader.cpp b/encfs/ConfigReader.cpp deleted file mode 100644 index 8218e59..0000000 --- a/encfs/ConfigReader.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2004, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include "ConfigReader.h" - -#include - -#include -#include -#include -#include -#include - - -using namespace std; -using namespace rlog; - - -ConfigReader::ConfigReader() -{ -} - -ConfigReader::~ConfigReader() -{ -} - -// read the entire file into a ConfigVar instance and then use that to decode -// into mapped variables. -bool -ConfigReader::load(const char *fileName) -{ - struct stat stbuf; - memset( &stbuf, 0, sizeof(struct stat)); - if( lstat( fileName, &stbuf ) != 0) - return false; - - int size = stbuf.st_size; - - int fd = open( fileName, O_RDONLY ); - if(fd < 0) - return false; - - char *buf = new char[size]; - - int res = ::read( fd, buf, size ); - close( fd ); - - if( res != size ) - { - rWarning("Partial read of config file, expecting %i bytes, got %i", - size, res); - delete[] buf; - return false; - } - - ConfigVar in; - in.write( (unsigned char *)buf, size ); - delete[] buf; - - return loadFromVar( in ); -} - -bool -ConfigReader::loadFromVar(ConfigVar &in) -{ - in.resetOffset(); - - // parse. - int numEntries = in.readInt(); - - for(int i=0; i> key >> value; - - if(key.length() == 0) - { - rError("Invalid key encoding in buffer"); - return false; - } - ConfigVar newVar( value ); - vars.insert( make_pair( key, newVar ) ); - } - - return true; -} - -bool -ConfigReader::save(const char *fileName) const -{ - // write everything to a ConfigVar, then output to disk - ConfigVar out = toVar(); - - int fd = ::open( fileName, O_RDWR | O_CREAT, 0640 ); - if(fd >= 0) - { - int retVal = ::write( fd, out.buffer(), out.size() ); - close( fd ); - if(retVal != out.size()) - { - rError("Error writing to config file %s", fileName); - return false; - } - } else - { - rError("Unable to open or create file %s", fileName); - return false; - } - - return true; -} - -ConfigVar -ConfigReader::toVar() const -{ - // write everything to a ConfigVar, then output to disk - ConfigVar out; - out.writeInt( vars.size() ); - map::const_iterator it; - for(it = vars.begin(); it != vars.end(); ++it) - { - out.writeInt( it->first.size() ); - out.write( (unsigned char*)it->first.data(), it->first.size() ); - out.writeInt( it->second.size() ); - out.write( (unsigned char*)it->second.buffer(), it->second.size() ); - } - - return out; -} - -ConfigVar ConfigReader::operator[] ( const std::string &varName ) const -{ - // read only - map::const_iterator it = vars.find( varName ); - if( it == vars.end() ) - return ConfigVar(); - else - return it->second; -} - -ConfigVar &ConfigReader::operator[] ( const std::string &varName ) -{ - return vars[ varName ]; -} - diff --git a/encfs/ConfigVar.cpp b/encfs/ConfigVar.cpp deleted file mode 100644 index a677236..0000000 --- a/encfs/ConfigVar.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2004, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include "ConfigVar.h" -#include - -#include - -using namespace rlog; - -#ifndef MIN -inline int MIN(int a, int b) -{ - return (a < b) ? a : b; -} -#endif - - -ConfigVar::ConfigVar() - : pd( new ConfigVarData ) -{ - pd->offset = 0; -} - -ConfigVar::ConfigVar(const std::string &buf) - : pd( new ConfigVarData ) -{ - pd->buffer = buf; - pd->offset = 0; -} - -ConfigVar::ConfigVar(const ConfigVar &src) -{ - pd = src.pd; -} - -ConfigVar::~ConfigVar() -{ - pd.reset(); -} - -ConfigVar & ConfigVar::operator = (const ConfigVar &src) -{ - if(src.pd == pd) - return *this; - else - pd = src.pd; - - return *this; -} - -void ConfigVar::resetOffset() -{ - pd->offset = 0; -} - -int ConfigVar::read(unsigned char *buffer_, int bytes) const -{ - int toCopy = MIN( bytes, pd->buffer.size() - pd->offset ); - - if(toCopy > 0) - memcpy( buffer_, pd->buffer.data() + pd->offset, toCopy ); - - pd->offset += toCopy; - - return toCopy; -} - -int ConfigVar::write(const unsigned char *data, int bytes) -{ - if(pd->buffer.size() == (unsigned int)pd->offset) - { - pd->buffer.append( (const char *)data, bytes ); - } else - { - pd->buffer.insert( pd->offset, (const char *)data, bytes ); - } - - pd->offset += bytes; - - return bytes; -} - -int ConfigVar::size() const -{ - return pd->buffer.size(); -} - -const char *ConfigVar::buffer() const -{ - return pd->buffer.data(); -} - -int ConfigVar::at() const -{ - return pd->offset; -} - -void ConfigVar::writeString(const char *data, int bytes) -{ - writeInt( bytes ); - write( (const unsigned char *)data, bytes ); -} - - -// convert integer to BER encoded integer -void ConfigVar::writeInt(int val) -{ - // we can represent 7 bits per char output, so a 32bit number may take up - // to 5 bytes. - // first byte: 0x0000007f 0111,1111 - // second byte: 0x00003f80 0011,1111 1000,0000 - // third byte: 0x001fb000 0000,0000 0001,1111 1100,0000 0000,0000 - // fourth byte: 0x0fe00000 0000,1111 1110,0000 - // fifth byte: 0xf0000000 1111,0000 - unsigned char digit[5]; - - digit[4] = (unsigned char)((val & 0x0000007f)); - digit[3] = 0x80 | (unsigned char)((val & 0x00003f80) >> 7); - digit[2] = 0x80 | (unsigned char)((val & 0x001fc000) >> 14); - digit[1] = 0x80 | (unsigned char)((val & 0x0fe00000) >> 21); - digit[0] = 0x80 | (unsigned char)((val & 0xf0000000) >> 28); - - // find the starting point - we only need to output starting at the most - // significant non-zero digit.. - int start = 0; - while(digit[start] == 0x80) - ++start; - - write( digit + start, 5-start ); -} - -int ConfigVar::readInt() const -{ - const unsigned char * buf = (const unsigned char *)buffer(); - int bytes = this->size(); - int offset = at(); - int value = 0; - bool highBitSet; - - rAssert( offset < bytes ); - - do - { - unsigned char tmp = buf[offset++]; - highBitSet = tmp & 0x80; - - value = (value << 7) | (int)(tmp & 0x7f); - } while(highBitSet && offset < bytes); - - pd->offset = offset; - - // should never end up with a negative number.. - rAssert( value >= 0 ); - - return value; -} - -int ConfigVar::readInt( int defaultValue ) const -{ - int bytes = this->size(); - int offset = at(); - - if(offset >= bytes) - return defaultValue; - else - return readInt(); -} - -bool ConfigVar::readBool( bool defaultValue ) const -{ - int tmp = readInt( defaultValue ? 1 : 0 ); - return (tmp != 0); -} - -ConfigVar & operator << (ConfigVar &src, bool value) -{ - src.writeInt( value ? 1 : 0 ); - return src; -} - -ConfigVar & operator << (ConfigVar &src, int var) -{ - src.writeInt( var ); - return src; -} - -ConfigVar & operator << (ConfigVar &src, const std::string &str) -{ - src.writeString( str.data(), str.length() ); - return src; -} - -const ConfigVar & operator >> (const ConfigVar &src, bool &result) -{ - int tmp = src.readInt(); - result = (tmp != 0); - return src; -} - -const ConfigVar & operator >> (const ConfigVar &src, int &result) -{ - result = src.readInt(); - return src; -} - -const ConfigVar & operator >> (const ConfigVar &src, std::string &result) -{ - int length = src.readInt(); - //rAssert(length > 0); - - int readLen; - - unsigned char tmpBuf[32]; - if(length > (int)sizeof(tmpBuf)) - { - unsigned char *ptr = new unsigned char[length]; - readLen = src.read( ptr, length ); - result.assign( (char*)ptr, length ); - delete[] ptr; - } else - { - readLen = src.read( tmpBuf, length ); - result.assign( (char*)tmpBuf, length ); - } - - if(readLen != length) - { - rDebug("string encoded as size %i bytes, read %i", length, readLen ); - } - rAssert(readLen == length); - - return src; -} - diff --git a/encfs/Context.cpp b/encfs/Context.cpp deleted file mode 100644 index 3eba9e5..0000000 --- a/encfs/Context.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2007, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include "FileNode.h" -#include "Context.h" -#include "Mutex.h" -#include "FileUtils.h" -#include "DirNode.h" - -#include - -using namespace rel; -using namespace rlog; - -EncFS_Context::EncFS_Context() -{ - pthread_cond_init( &wakeupCond, 0 ); - pthread_mutex_init( &wakeupMutex, 0 ); - pthread_mutex_init( &contextMutex, 0 ); - - usageCount = 0; -} - -EncFS_Context::~EncFS_Context() -{ - pthread_mutex_destroy( &contextMutex ); - pthread_mutex_destroy( &wakeupMutex ); - pthread_cond_destroy( &wakeupCond ); - - // release all entries from map - openFiles.clear(); -} - -shared_ptr EncFS_Context::getRoot(int *errCode) -{ - shared_ptr ret; - do - { - { - Lock lock( contextMutex ); - ret = root; - ++usageCount; - } - - if(!ret) - { - int res = remountFS( this ); - if(res != 0) - { - *errCode = res; - break; - } - } - } while(!ret); - - return ret; -} - -void EncFS_Context::setRoot(const shared_ptr &r) -{ - Lock lock( contextMutex ); - - root = r; - if(r) - rootCipherDir = r->rootDirectory(); -} - -bool EncFS_Context::isMounted() -{ - return root; -} - -int EncFS_Context::getAndResetUsageCounter() -{ - Lock lock( contextMutex ); - - int count = usageCount; - usageCount = 0; - - return count; -} - -int EncFS_Context::openFileCount() const -{ - Lock lock( contextMutex ); - - return openFiles.size(); -} - -shared_ptr EncFS_Context::lookupNode(const char *path) -{ - Lock lock( contextMutex ); - - FileMap::iterator it = openFiles.find( std::string(path) ); - if(it != openFiles.end()) - { - // all the items in the set point to the same node.. so just use the - // first - return (*it->second.begin())->node; - } else - { - return shared_ptr(); - } -} - -void EncFS_Context::renameNode(const char *from, const char *to) -{ - Lock lock( contextMutex ); - - FileMap::iterator it = openFiles.find( std::string(from) ); - if(it != openFiles.end()) - { - std::set val = it->second; - openFiles.erase(it); - openFiles[ std::string(to) ] = val; - } -} - -shared_ptr EncFS_Context::getNode(void *pl) -{ - Placeholder *ph = (Placeholder*)pl; - return ph->node; -} - -void *EncFS_Context::putNode(const char *path, - const shared_ptr &node) -{ - Lock lock( contextMutex ); - Placeholder *pl = new Placeholder( node ); - openFiles[ std::string(path) ].insert(pl); - - return (void *)pl; -} - -void EncFS_Context::eraseNode(const char *path, void *pl) -{ - Lock lock( contextMutex ); - - Placeholder *ph = (Placeholder *)pl; - - FileMap::iterator it = openFiles.find( std::string(path) ); - rAssert(it != openFiles.end()); - - int rmCount = it->second.erase( ph ); - - rAssert(rmCount == 1); - - // if no more references to this file, remove the record all together - if(it->second.empty()) - { - // attempts to make use of shallow copy to clear memory used to hold - // unencrypted filenames.. not sure this does any good.. - std::string storedName = it->first; - openFiles.erase( it ); - storedName.assign( storedName.length(), '\0' ); - } - - delete ph; -} - diff --git a/encfs/DirNode.cpp b/encfs/DirNode.cpp deleted file mode 100644 index 169c580..0000000 --- a/encfs/DirNode.cpp +++ /dev/null @@ -1,831 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2003-2004, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include "encfs.h" - -#include "DirNode.h" -#include "FileUtils.h" - -#include -#include -#include -#include -#include -#include -#include -#ifdef linux -#include -#endif - -#include - -#include "Context.h" -#include "Cipher.h" -#include "Mutex.h" -#include -#include - -#include - -using namespace std; -using namespace rel; -using namespace rlog; - -static RLogChannel *Info = DEF_CHANNEL( "info/DirNode", Log_Info ); - -class DirDeleter -{ -public: - void operator () ( DIR *d ) - { - ::closedir( d ); - } -}; - - -DirTraverse::DirTraverse(const shared_ptr &_dirPtr, - uint64_t _iv, const shared_ptr &_naming) - : dir( _dirPtr ) - , iv( _iv ) - , naming( _naming ) -{ -} - -DirTraverse::DirTraverse(const DirTraverse &src) - : dir( src.dir ) - , iv( src.iv ) - , naming( src.naming ) -{ -} - -DirTraverse &DirTraverse::operator = (const DirTraverse &src) -{ - dir = src.dir; - iv = src.iv; - naming = src.naming; - - return *this; -} - -DirTraverse::~DirTraverse() -{ - dir.reset(); - iv = 0; - naming.reset(); -} - -static -bool _nextName(struct dirent *&de, const shared_ptr &dir, - int *fileType, ino_t *inode) -{ - de = ::readdir( dir.get() ); - - if(de) - { - if(fileType) - { -#if defined(_DIRENT_HAVE_D_TYPE) || defined(__FreeBSD__) - *fileType = de->d_type; -#else -#warning "struct dirent.d_type not supported" - *fileType = 0; -#endif - } - if(inode) - *inode = de->d_ino; - return true; - } else - { - if(fileType) - *fileType = 0; - return false; - } -} - - -std::string DirTraverse::nextPlaintextName(int *fileType, ino_t *inode) -{ - struct dirent *de=0; - while(_nextName(de, dir, fileType, inode)) - { - try - { - uint64_t localIv = iv; - return naming->decodePath( de->d_name, &localIv ); - } catch ( rlog::Error &ex ) - { - // .. .problem decoding, ignore it and continue on to next name.. - rDebug("error decoding filename: %s", de->d_name); - } - } - - return string(); -} - -std::string DirTraverse::nextInvalid() -{ - struct dirent *de=0; - // find the first name which produces a decoding error... - while(_nextName(de, dir, (int*)0, (ino_t*)0)) - { - try - { - uint64_t localIv = iv; - naming->decodePath( de->d_name, &localIv ); - continue; - } catch( rlog::Error &ex ) - { - return string( de->d_name ); - } - } - - return string(); -} - -struct RenameEl -{ - // ciphertext names - string oldCName; - string newCName; // intermediate name (not final cname) - - // plaintext names - string oldPName; - string newPName; - - bool isDirectory; -}; - -class RenameOp -{ -private: - DirNode *dn; - shared_ptr< list > renameList; - list::const_iterator last; - -public: - RenameOp( DirNode *_dn, const shared_ptr< list > &_renameList ) - : dn(_dn), renameList(_renameList) - { - last = renameList->begin(); - } - - RenameOp(const RenameOp &src) - : dn(src.dn) - , renameList(src.renameList) - , last(src.last) - { - } - - ~RenameOp(); - - operator bool () const - { - return renameList; - } - - bool apply(); - void undo(); -}; - -RenameOp::~RenameOp() -{ - if(renameList) - { - // got a bunch of decoded filenames sitting in memory.. do a little - // cleanup before leaving.. - list::iterator it; - for(it = renameList->begin(); it != renameList->end(); ++it) - { - it->oldPName.assign( it->oldPName.size(), ' ' ); - it->newPName.assign( it->newPName.size(), ' ' ); - } - } -} - -bool RenameOp::apply() -{ - try - { - while(last != renameList->end()) - { - // backing store rename. - rDebug("renaming %s -> %s", - last->oldCName.c_str(), last->newCName.c_str()); - - struct stat st; - bool preserve_mtime = ::stat(last->oldCName.c_str(), &st) == 0; - - // internal node rename.. - dn->renameNode( last->oldPName.c_str(), - last->newPName.c_str() ); - - // rename on disk.. - if(::rename( last->oldCName.c_str(), - last->newCName.c_str() ) == -1) - { - rWarning("Error renaming %s: %s", - last->oldCName.c_str(), strerror( errno )); - dn->renameNode( last->newPName.c_str(), - last->oldPName.c_str(), false ); - return false; - } - - if(preserve_mtime) - { - struct utimbuf ut; - ut.actime = st.st_atime; - ut.modtime = st.st_mtime; - ::utime(last->newCName.c_str(), &ut); - } - - ++last; - } - - return true; - } catch( rlog::Error &err ) - { - err.log( _RLWarningChannel ); - return false; - } -} - -void RenameOp::undo() -{ - rDebug("in undoRename"); - - if(last == renameList->begin()) - { - rDebug("nothing to undo"); - return; // nothing to undo - } - - // list has to be processed backwards, otherwise we may rename - // directories and directory contents in the wrong order! - int undoCount = 0; - list::const_iterator it = last; - - while( it != renameList->begin() ) - { - --it; - - rDebug("undo: renaming %s -> %s", - it->newCName.c_str(), it->oldCName.c_str()); - - ::rename( it->newCName.c_str(), it->oldCName.c_str() ); - try - { - dn->renameNode( it->newPName.c_str(), - it->oldPName.c_str(), false ); - } catch( rlog::Error &err ) - { - err.log( _RLWarningChannel ); - // continue on anyway... - } - ++undoCount; - }; - - rWarning("Undo rename count: %i", undoCount); -} - -DirNode::DirNode(EncFS_Context *_ctx, - const string &sourceDir, - const FSConfigPtr &_config) -{ - pthread_mutex_init( &mutex, 0 ); - - Lock _lock( mutex ); - - ctx = _ctx; - rootDir = sourceDir; - fsConfig = _config; - - // make sure rootDir ends in '/', so that we can form a path by appending - // the rest.. - if( rootDir[ rootDir.length()-1 ] != '/' ) - rootDir.append( 1, '/'); - - naming = fsConfig->nameCoding; -} - -DirNode::~DirNode() -{ -} - -bool -DirNode::hasDirectoryNameDependency() const -{ - return naming ? naming->getChainedNameIV() : false; -} - -string -DirNode::rootDirectory() -{ - // don't update last access here, otherwise 'du' would cause lastAccess to - // be reset. - // chop off '/' terminator from root dir. - return string( rootDir, 0, rootDir.length()-1 ); -} - -string -DirNode::cipherPath( const char *plaintextPath ) -{ - return rootDir + naming->encodePath( plaintextPath ); -} - -string -DirNode::cipherPathWithoutRoot( const char *plaintextPath ) -{ - return naming->encodePath( plaintextPath ); -} - -string -DirNode::plainPath( const char *cipherPath_ ) -{ - try - { - if( !strncmp( cipherPath_, rootDir.c_str(), - rootDir.length() ) ) - { - return naming->decodePath( cipherPath_ + rootDir.length() ); - } else - { - if ( cipherPath_[0] == '+' ) - { - // decode as fully qualified path - return string("/") + naming->decodeName( cipherPath_+1, - strlen(cipherPath_+1) ); - } else - { - return naming->decodePath( cipherPath_ ); - } - } - - } catch( rlog::Error &err ) - { - rError("decode err: %s", err.message()); - err.log( _RLWarningChannel ); - - return string(); - } -} - -string -DirNode::relativeCipherPath( const char *plaintextPath ) -{ - try - { - if(plaintextPath[0] == '/') - { - // mark with '+' to indicate special decoding.. - return string("+") + naming->encodeName(plaintextPath+1, - strlen(plaintextPath+1)); - } else - { - return naming->encodePath( plaintextPath ); - } - } catch( rlog::Error &err ) - { - rError("encode err: %s", err.message()); - err.log( _RLWarningChannel ); - - return string(); - } -} - -DirTraverse DirNode::openDir(const char *plaintextPath) -{ - string cyName = rootDir + naming->encodePath( plaintextPath ); - //rDebug("openDir on %s", cyName.c_str() ); - - DIR *dir = ::opendir( cyName.c_str() ); - if(dir == NULL) - { - rDebug("opendir error %s", strerror(errno)); - return DirTraverse( shared_ptr(), 0, shared_ptr() ); - } else - { - shared_ptr dp( dir, DirDeleter() ); - - uint64_t iv = 0; - // if we're using chained IV mode, then compute the IV at this - // directory level.. - try - { - if( naming->getChainedNameIV() ) - naming->encodePath( plaintextPath, &iv ); - } catch( rlog::Error &err ) - { - rError("encode err: %s", err.message()); - err.log( _RLWarningChannel ); - } - return DirTraverse( dp, iv, naming ); - } -} - -bool DirNode::genRenameList( list &renameList, - const char *fromP, const char *toP ) -{ - uint64_t fromIV = 0, toIV = 0; - - // compute the IV for both paths - string fromCPart = naming->encodePath( fromP, &fromIV ); - string toCPart = naming->encodePath( toP, &toIV ); - - // where the files live before the rename.. - string sourcePath = rootDir + fromCPart; - - // ok..... we wish it was so simple.. should almost never happen - if(fromIV == toIV) - return true; - - // generate the real destination path, where we expect to find the files.. - rDebug("opendir %s", sourcePath.c_str() ); - shared_ptr dir = shared_ptr( - opendir( sourcePath.c_str() ), DirDeleter() ); - if(!dir) - return false; - - struct dirent *de = NULL; - while((de = ::readdir( dir.get() )) != NULL) - { - // decode the name using the oldIV - uint64_t localIV = fromIV; - string plainName; - - if((de->d_name[0] == '.') && - ((de->d_name[1] == '\0') - || ((de->d_name[1] == '.') && (de->d_name[2] == '\0')))) - { - // skip "." and ".." - continue; - } - - try - { - plainName = naming->decodePath( de->d_name, &localIV ); - } catch( rlog::Error &ex ) - { - // if filename can't be decoded, then ignore it.. - continue; - } - - // any error in the following will trigger a rename failure. - try - { - // re-encode using the new IV.. - localIV = toIV; - string newName = naming->encodePath( plainName.c_str(), &localIV ); - - // store rename information.. - string oldFull = sourcePath + '/' + de->d_name; - string newFull = sourcePath + '/' + newName; - - RenameEl ren; - ren.oldCName = oldFull; - ren.newCName = newFull; - ren.oldPName = string(fromP) + '/' + plainName; - ren.newPName = string(toP) + '/' + plainName; - - bool isDir; -#if defined(_DIRENT_HAVE_D_TYPE) - if(de->d_type != DT_UNKNOWN) - { - isDir = (de->d_type == DT_DIR); - } else -#endif - { - isDir = isDirectory( oldFull.c_str() ); - } - - ren.isDirectory = isDir; - - if(isDir) - { - // recurse.. We want to add subdirectory elements before the - // parent, as that is the logical rename order.. - if(!genRenameList( renameList, - ren.oldPName.c_str(), - ren.newPName.c_str())) - { - return false; - } - } - - rDebug("adding file %s to rename list", - oldFull.c_str()); - - renameList.push_back( ren ); - - } catch( rlog::Error &err ) - { - // We can't convert this name, because we don't have a valid IV for - // it (or perhaps a valid key).. It will be inaccessible.. - rWarning("Aborting rename: error on file: %s", - fromCPart.append(1, '/').append(de->d_name).c_str()); - err.log( _RLDebugChannel ); - - // abort.. Err on the side of safety and disallow rename, rather - // then loosing files.. - return false; - } - } - - return true; -} - - -/* - A bit of a pain.. If a directory is renamed in a filesystem with - directory initialization vector chaining, then we have to recursively - rename every descendent of this directory, as all initialization vectors - will have changed.. - - Returns a list of renamed items on success, a null list on failure. -*/ -shared_ptr -DirNode::newRenameOp( const char *fromP, const char *toP ) -{ - // Do the rename in two stages to avoid chasing our tail - // Undo everything if we encounter an error! - shared_ptr< list > renameList(new list); - if(!genRenameList( *renameList.get(), fromP, toP )) - { - rWarning("Error during generation of recursive rename list"); - return shared_ptr(); - } else - return shared_ptr( new RenameOp(this, renameList) ); -} - - -int DirNode::mkdir(const char *plaintextPath, mode_t mode, - uid_t uid, gid_t gid) -{ - string cyName = rootDir + naming->encodePath( plaintextPath ); - rAssert( !cyName.empty() ); - - rLog( Info, "mkdir on %s", cyName.c_str() ); - - // if uid or gid are set, then that should be the directory owner - int olduid = -1; - int oldgid = -1; - if(uid != 0) - olduid = setfsuid( uid ); - if(gid != 0) - oldgid = setfsgid( gid ); - - int res = ::mkdir( cyName.c_str(), mode ); - - if(olduid >= 0) - setfsuid( olduid ); - if(oldgid >= 0) - setfsgid( oldgid ); - - if(res == -1) - { - int eno = errno; - rWarning("mkdir error on %s mode %i: %s", cyName.c_str(), - mode, strerror(eno)); - res = -eno; - } else - res = 0; - - return res; -} - -int -DirNode::rename( const char *fromPlaintext, const char *toPlaintext ) -{ - Lock _lock( mutex ); - - string fromCName = rootDir + naming->encodePath( fromPlaintext ); - string toCName = rootDir + naming->encodePath( toPlaintext ); - rAssert( !fromCName.empty() ); - rAssert( !toCName.empty() ); - - rLog( Info, "rename %s -> %s", fromCName.c_str(), toCName.c_str() ); - - shared_ptr toNode = findOrCreate( toPlaintext ); - - shared_ptr renameOp; - if( hasDirectoryNameDependency() && isDirectory( fromCName.c_str() )) - { - rLog( Info, "recursive rename begin" ); - renameOp = newRenameOp( fromPlaintext, toPlaintext ); - - if(!renameOp || !renameOp->apply()) - { - if(renameOp) - renameOp->undo(); - - rWarning("rename aborted"); - return -EACCES; - } - rLog( Info, "recursive rename end" ); - } - - int res = 0; - try - { - struct stat st; - bool preserve_mtime = ::stat(fromCName.c_str(), &st) == 0; - - renameNode( fromPlaintext, toPlaintext ); - res = ::rename( fromCName.c_str(), toCName.c_str() ); - - if(res == -1) - { - // undo - res = -errno; - renameNode( toPlaintext, fromPlaintext, false ); - - if(renameOp) - renameOp->undo(); - } else if(preserve_mtime) - { - struct utimbuf ut; - ut.actime = st.st_atime; - ut.modtime = st.st_mtime; - ::utime(toCName.c_str(), &ut); - } - } catch( rlog::Error &err ) - { - // exception from renameNode, just show the error and continue.. - err.log( _RLWarningChannel ); - res = -EIO; - } - - if(res != 0) - { - rLog( Info, "rename failed: %s", strerror( errno )); - res = -errno; - } - - return res; -} - -int DirNode::link( const char *from, const char *to ) -{ - Lock _lock( mutex ); - - string fromCName = rootDir + naming->encodePath( from ); - string toCName = rootDir + naming->encodePath( to ); - - rAssert( !fromCName.empty() ); - rAssert( !toCName.empty() ); - - rLog(Info, "link %s -> %s", fromCName.c_str(), toCName.c_str()); - - int res = -EPERM; - if( fsConfig->config->external_iv() ) - { - rLog(Info, "hard links not supported with external IV chaining!"); - } else - { - res = ::link( fromCName.c_str(), toCName.c_str() ); - if(res == -1) - res = -errno; - else - res = 0; - } - - return res; -} - -/* - The node is keyed by filename, so a rename means the internal node names - must be changed. -*/ -shared_ptr DirNode::renameNode( const char *from, const char *to ) -{ - return renameNode( from, to, true ); -} - -shared_ptr DirNode::renameNode( const char *from, const char *to, - bool forwardMode ) -{ - shared_ptr node = findOrCreate( from ); - - if(node) - { - uint64_t newIV = 0; - string cname = rootDir + naming->encodePath( to, &newIV ); - - rLog(Info, "renaming internal node %s -> %s", - node->cipherName(), cname.c_str()); - - if(node->setName( to, cname.c_str(), newIV, forwardMode )) - { - if(ctx) - ctx->renameNode( from, to ); - } else - { - // rename error! - put it back - rError("renameNode failed"); - throw ERROR("Internal node name change failed!"); - } - } - - return node; -} - -shared_ptr DirNode::findOrCreate( const char *plainName) -{ - shared_ptr node; - if(ctx) - node = ctx->lookupNode( plainName ); - - if(!node) - { - uint64_t iv = 0; - string cipherName = naming->encodePath( plainName, &iv ); - node.reset( new FileNode( this, fsConfig, - plainName, - (rootDir + cipherName).c_str())); - - if(fsConfig->config->external_iv()) - node->setName(0, 0, iv); - - rLog(Info, "created FileNode for %s", node->cipherName()); - } - - return node; -} - -shared_ptr -DirNode::lookupNode( const char *plainName, const char * requestor ) -{ - (void)requestor; - Lock _lock( mutex ); - - shared_ptr node = findOrCreate( plainName ); - - return node; -} - -/* - Similar to lookupNode, except that we also call open() and only return a - node on sucess.. This is done in one step to avoid any race conditions - with the stored state of the file. -*/ -shared_ptr -DirNode::openNode( const char *plainName, const char * requestor, int flags, - int *result ) -{ - (void)requestor; - rAssert( result != NULL ); - Lock _lock( mutex ); - - shared_ptr node = findOrCreate( plainName ); - - if( node && (*result = node->open( flags )) >= 0 ) - return node; - else - return shared_ptr(); -} - -int DirNode::unlink( const char *plaintextName ) -{ - string cyName = naming->encodePath( plaintextName ); - rLog( Info, "unlink %s", cyName.c_str() ); - - Lock _lock( mutex ); - - int res = 0; - if(ctx && ctx->lookupNode( plaintextName )) - { - // If FUSE is running with "hard_remove" option where it doesn't - // hide open files for us, then we can't allow an unlink of an open - // file.. - rWarning("Refusing to unlink open file: %s, hard_remove option " - "is probably in effect", cyName.c_str() ); - res = -EBUSY; - } else - { - string fullName = rootDir + cyName; - res = ::unlink( fullName.c_str() ); - if(res == -1) - { - res = -errno; - rDebug("unlink error: %s", strerror(errno)); - } - } - - return res; -} diff --git a/encfs/FileNode.cpp b/encfs/FileNode.cpp deleted file mode 100644 index 4363423..0000000 --- a/encfs/FileNode.cpp +++ /dev/null @@ -1,306 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2003-2004, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -// Include encfs first, because we need to include fuse.h before any inclusion -// of sys/stat.h or other system headers (to be safe) -#include "encfs.h" - -#include -#include -#include -#include -#include -#ifdef linux -#include -#endif - -#include - -#include "config.h" - -#include "FileNode.h" -#include "FileUtils.h" -#include "Cipher.h" -#include "CipherFileIO.h" -#include "RawFileIO.h" -#include "MACFileIO.h" -#include "DirNode.h" - -#include "FileIO.h" -#include "MemoryPool.h" -#include "Mutex.h" - -#include -#include - -using namespace std; -using namespace rel; -using namespace rlog; - -/* - TODO: locking at the FileNode level is inefficient, since this precludes - multiple IO operations from going on concurrently within the same file. - - There is no reason why simultainous reads cannot be satisfied, or why one - read has to wait for the decoding of the previous read before it can be - sent to the IO subsystem! -*/ - -static RLogChannel *Info = DEF_CHANNEL("info/FileNode", Log_Info); - -FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg, - const char *plaintextName_, const char *cipherName_) -{ - pthread_mutex_init( &mutex, 0 ); - - Lock _lock( mutex ); - - this->_pname = plaintextName_; - this->_cname = cipherName_; - this->parent = parent_; - - this->fsConfig = cfg; - - // chain RawFileIO & CipherFileIO - shared_ptr rawIO( new RawFileIO( _cname ) ); - io = shared_ptr( new CipherFileIO( rawIO, fsConfig )); - - if(cfg->config->block_mac_bytes() || cfg->config->block_mac_rand_bytes()) - io = shared_ptr(new MACFileIO(io, fsConfig)); -} - -FileNode::~FileNode() -{ - // FileNode mutex should be locked before the destructor is called - //pthread_mutex_lock( &mutex ); - - _pname.assign( _pname.length(), '\0' ); - _cname.assign( _cname.length(), '\0' ); - io.reset(); - - pthread_mutex_destroy( &mutex ); -} - -const char *FileNode::cipherName() const -{ - return _cname.c_str(); -} - -const char *FileNode::plaintextName() const -{ - return _pname.c_str(); -} - -string FileNode::plaintextParent() const -{ - return parentDirectory( _pname ); -} - -static bool setIV(const shared_ptr &io, uint64_t iv) -{ - struct stat stbuf; - if((io->getAttr(&stbuf) < 0) || S_ISREG(stbuf.st_mode)) - return io->setIV( iv ); - else - return true; -} - -bool FileNode::setName( const char *plaintextName_, const char *cipherName_, - uint64_t iv, bool setIVFirst ) -{ - //Lock _lock( mutex ); - rDebug("calling setIV on %s", cipherName_); - if(setIVFirst) - { - if(fsConfig->config->external_iv() && !setIV(io, iv)) - return false; - - // now change the name.. - if(plaintextName_) - this->_pname = plaintextName_; - if(cipherName_) - { - this->_cname = cipherName_; - io->setFileName( cipherName_ ); - } - } else - { - std::string oldPName = _pname; - std::string oldCName = _cname; - - if(plaintextName_) - this->_pname = plaintextName_; - if(cipherName_) - { - this->_cname = cipherName_; - io->setFileName( cipherName_ ); - } - - if(fsConfig->config->external_iv() && !setIV(io, iv)) - { - _pname = oldPName; - _cname = oldCName; - return false; - } - } - - return true; -} - -int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid) -{ - Lock _lock( mutex ); - - int res; - int olduid = -1; - int oldgid = -1; - if(uid != 0) - { - olduid = setfsuid( uid ); - if(olduid == -1) - { - rInfo("setfsuid error: %s", strerror(errno)); - return -EPERM; - } - } - if(gid != 0) - { - oldgid = setfsgid( gid ); - if(oldgid == -1) - { - rInfo("setfsgid error: %s", strerror(errno)); - return -EPERM; - } - } - - /* - * cf. xmp_mknod() in fusexmp.c - * The regular file stuff could be stripped off if there - * were a create method (advised to have) - */ - if (S_ISREG( mode )) { - res = ::open( _cname.c_str(), O_CREAT | O_EXCL | O_WRONLY, mode ); - if (res >= 0) - res = ::close( res ); - } else if (S_ISFIFO( mode )) - res = ::mkfifo( _cname.c_str(), mode ); - else - res = ::mknod( _cname.c_str(), mode, rdev ); - - if(olduid >= 0) - setfsuid( olduid ); - if(oldgid >= 0) - setfsgid( oldgid ); - - if(res == -1) - { - int eno = errno; - rDebug("mknod error: %s", strerror(eno)); - res = -eno; - } - - return res; -} - -int FileNode::open(int flags) const -{ - Lock _lock( mutex ); - - int res = io->open( flags ); - return res; -} - -int FileNode::getAttr(struct stat *stbuf) const -{ - Lock _lock( mutex ); - - int res = io->getAttr( stbuf ); - return res; -} - -off_t FileNode::getSize() const -{ - Lock _lock( mutex ); - - int res = io->getSize(); - return res; -} - -ssize_t FileNode::read( off_t offset, unsigned char *data, ssize_t size ) const -{ - IORequest req; - req.offset = offset; - req.dataLen = size; - req.data = data; - - Lock _lock( mutex ); - - return io->read( req ); -} - -bool FileNode::write(off_t offset, unsigned char *data, ssize_t size) -{ - rLog(Info, "FileNode::write offset %" PRIi64 ", data size %i", - offset, (int)size); - - IORequest req; - req.offset = offset; - req.dataLen = size; - req.data = data; - - Lock _lock( mutex ); - - return io->write( req ); -} - -int FileNode::truncate( off_t size ) -{ - Lock _lock( mutex ); - - return io->truncate( size ); -} - -int FileNode::sync(bool datasync) -{ - Lock _lock( mutex ); - - int fh = io->open( O_RDONLY ); - if(fh >= 0) - { - int res = -EIO; -#ifdef linux - if(datasync) - res = fdatasync( fh ); - else - res = fsync( fh ); -#else - // no fdatasync support - // TODO: use autoconfig to check for it.. - res = fsync(fh); -#endif - - if(res == -1) - res = -errno; - - return res; - } else - return fh; -} - diff --git a/encfs/MACFileIO.cpp b/encfs/MACFileIO.cpp deleted file mode 100644 index b0002d2..0000000 --- a/encfs/MACFileIO.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2004, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include "MACFileIO.h" - -#include "MemoryPool.h" -#include "FileUtils.h" -#include "config.pb.h" - -#include -#include -#include - -#include - -#include "i18n.h" - -using namespace rlog; -using namespace std; - -static RLogChannel *Info = DEF_CHANNEL("info/MACFileIO", Log_Info); -// -// Version 1.0 worked on blocks of size (blockSize + headerSize). -// That is, it took [blockSize] worth of user data and added headers. -// Version 2.0 takes [blockSize - headerSize] worth of user data and writes -// [blockSize] bytes. That way the size going into the crypto engine is -// valid from what was selected based on the crypto module allowed ranges! -// Version 2.1 allows per-block rand bytes to be used without enabling MAC. -// -// The information about MACFileIO currently does not make its way into the -// configuration file, so there is no easy way to make this backward -// compatible, except at a high level by checking a revision number for the -// filesystem... -// -static Interface MACFileIO_iface = makeInterface("FileIO/MAC", 2, 1, 0); - -int dataBlockSize(const FSConfigPtr &cfg) -{ - return cfg->config->block_size() - - cfg->config->block_mac_bytes() - - cfg->config->block_mac_rand_bytes(); -} - -MACFileIO::MACFileIO( const shared_ptr &_base, - const FSConfigPtr &cfg ) - : BlockFileIO( dataBlockSize( cfg ), cfg ) - , base( _base ) - , cipher( cfg->cipher ) - , key( cfg->key ) - , macBytes( cfg->config->block_mac_bytes() ) - , randBytes( cfg->config->block_mac_rand_bytes() ) - , warnOnly( cfg->opts->forceDecode ) -{ - rAssert( macBytes >= 0 && macBytes <= 8 ); - rAssert( randBytes >= 0 ); - rLog(Info, "fs block size = %i, macBytes = %i, randBytes = %i", - cfg->config->block_size(), - cfg->config->block_mac_bytes(), - cfg->config->block_mac_rand_bytes()); -} - -MACFileIO::~MACFileIO() -{ -} - -Interface MACFileIO::interface() const -{ - return MACFileIO_iface; -} - -int MACFileIO::open( int flags ) -{ - return base->open( flags ); -} - -void MACFileIO::setFileName( const char *fileName ) -{ - base->setFileName( fileName ); -} - -const char *MACFileIO::getFileName() const -{ - return base->getFileName(); -} - -bool MACFileIO::setIV( uint64_t iv ) -{ - return base->setIV( iv ); -} - -inline static off_t roundUpDivide( off_t numerator, int denominator ) -{ - // integer arithmetic always rounds down, so we can round up by adding - // enough so that any value other then a multiple of denominator gets - // rouned to the next highest value. - return ( numerator + denominator - 1 ) / denominator; -} - -// Convert from a location in the raw file to a location when MAC headers are -// interleved with the data. -// So, if the filesystem stores/encrypts [blockSize] bytes per block, then -// [blockSize - headerSize] of those bytes will contain user-supplied data, -// and the rest ([headerSize]) will contain the MAC header for this block. -// Example, offset points to second block (of user-data) -// offset = blockSize - headerSize -// ... blockNum = 1 -// ... partialBlock = 0 -// ... adjLoc = 1 * blockSize -static off_t locWithHeader( off_t offset, int blockSize, int headerSize ) -{ - off_t blockNum = roundUpDivide( offset , blockSize - headerSize ); - return offset + blockNum * headerSize; -} - -// convert from a given location in the stream containing headers, and return a -// location in the user-data stream (which doesn't contain MAC headers).. -// The output value will always be less then the input value, because the -// headers are stored at the beginning of the block, so even the first data is -// offset by the size of the header. -static off_t locWithoutHeader( off_t offset, int blockSize, int headerSize ) -{ - off_t blockNum = roundUpDivide( offset , blockSize ); - return offset - blockNum * headerSize; -} - -int MACFileIO::getAttr( struct stat *stbuf ) const -{ - int res = base->getAttr( stbuf ); - - if(res == 0 && S_ISREG(stbuf->st_mode)) - { - // have to adjust size field.. - int headerSize = macBytes + randBytes; - int bs = blockSize() + headerSize; - stbuf->st_size = locWithoutHeader( stbuf->st_size, bs, headerSize ); - } - - return res; -} - -off_t MACFileIO::getSize() const -{ - // adjust the size to hide the header overhead we tack on.. - int headerSize = macBytes + randBytes; - int bs = blockSize() + headerSize; - - off_t size = base->getSize(); - if(size > 0) - size = locWithoutHeader( size, bs, headerSize ); - - return size; -} - -ssize_t MACFileIO::readOneBlock( const IORequest &req ) const -{ - int headerSize = macBytes + randBytes; - - int bs = blockSize() + headerSize; - - MemBlock mb = MemoryPool::allocate( bs ); - - IORequest tmp; - tmp.offset = locWithHeader( req.offset, bs, headerSize ); - tmp.data = mb.data; - tmp.dataLen = headerSize + req.dataLen; - - // get the data from the base FileIO layer - ssize_t readSize = base->read( tmp ); - - // don't store zeros if configured for zero-block pass-through - bool skipBlock = true; - if( _allowHoles ) - { - for(int i=0; i 0) - skipBlock = false; - - if(readSize > headerSize) - { - if(!skipBlock) - { - // At this point the data has been decoded. So, compute the MAC of - // the block and check against the checksum stored in the header.. - uint64_t mac = cipher->MAC_64( tmp.data + macBytes, - readSize - macBytes, key ); - - for(int i=0; i>= 8) - { - int test = mac & 0xff; - int stored = tmp.data[i]; - if(test != stored) - { - // uh oh.. - long blockNum = req.offset / bs; - rWarning(_("MAC comparison failure in block %li"), - blockNum); - if( !warnOnly ) - { - MemoryPool::release( mb ); - throw ERROR( - _("MAC comparison failure, refusing to read")); - } - break; - } - } - } - - // now copy the data to the output buffer - readSize -= headerSize; - memcpy( req.data, tmp.data + headerSize, readSize ); - } else - { - rDebug("readSize %i at offset %" PRIi64, (int)readSize, req.offset); - if(readSize > 0) - readSize = 0; - } - - MemoryPool::release( mb ); - - return readSize; -} - -bool MACFileIO::writeOneBlock( const IORequest &req ) -{ - int headerSize = macBytes + randBytes; - - int bs = blockSize() + headerSize; - - // we have the unencrypted data, so we need to attach a header to it. - MemBlock mb = MemoryPool::allocate( bs ); - - IORequest newReq; - newReq.offset = locWithHeader( req.offset, bs, headerSize ); - newReq.data = mb.data; - newReq.dataLen = headerSize + req.dataLen; - - memset( newReq.data, 0, headerSize ); - memcpy( newReq.data + headerSize, req.data, req.dataLen ); - if(randBytes > 0) - { - if(!cipher->randomize( newReq.data+macBytes, randBytes, false )) - return false; - } - - if(macBytes > 0) - { - // compute the mac (which includes the random data) and fill it in - uint64_t mac = cipher->MAC_64( newReq.data+macBytes, - req.dataLen + randBytes, key ); - - for(int i=0; i>= 8; - } - } - - // now, we can let the next level have it.. - bool ok = base->write( newReq ); - - MemoryPool::release( mb ); - - return ok; -} - -int MACFileIO::truncate( off_t size ) -{ - int headerSize = macBytes + randBytes; - int bs = blockSize() + headerSize; - - int res = BlockFileIO::truncate( size, 0 ); - - if(res == 0) - base->truncate( locWithHeader( size, bs, headerSize ) ); - - return res; -} - -bool MACFileIO::isWritable() const -{ - return base->isWritable(); -} diff --git a/encfs/Makefile.am b/encfs/Makefile.am deleted file mode 100644 index c2cd157..0000000 --- a/encfs/Makefile.am +++ /dev/null @@ -1,163 +0,0 @@ - -include $(top_srcdir)/Makefile.common - -ALL_INCLUDES = @RLOG_CFLAGS@ @OPENSSL_CFLAGS@ -ALL_INCLUDES += @PROTOBUF_CFLAGS@ -ALL_LDFLAGS = @RLOG_LIBS@ @OPENSSL_LIBS@ -ALL_LDFLAGS += @PROTOBUF_LIBS@ - -INCLUDES = $(all_includes) -I../intl - -AM_CXXFLAGS = -DRLOG_COMPONENT="encfs" $(ALL_INCLUDES) - -if DARWIN -# needed to select correct API in fuse.h -AM_CXXFLAGS += -D__FreeBSD__=10 -endif - -if BUILD_NLS -# define a C macro LOCALEDIR indicating where catalogs will be installed -#localedir = $(datadir)/locale - -AM_CXXFLAGS += -DLOCALEDIR=\"$(localedir)\" -ALL_LDFLAGS += @LIBINTL@ -endif - -lib_LTLIBRARIES = libencfs.la -bin_PROGRAMS = encfs encfsctl -dist_bin_SCRIPTS = encfssh -noinst_PROGRAMS = test makeKey - -all-local: encfs-man.html - -encfs_LDADD = libencfs.la $(ALL_LDFLAGS) -encfsctl_LDADD = libencfs.la $(ALL_LDFLAGS) -test_LDADD = libencfs.la $(ALL_LDFLAGS) -makeKey_LDADD = libencfs.la $(ALL_LDFLAGS) - -if BUILD_STATIC -encfs_LDFLAGS = -all-static -encfsctl_LDFLAGS = -all-static -test_LDFLAGS = -all-static -makeKey_LDFLAGS = -all-static -endif - -# CURRENT : REVISION : AGE -# +1 : 0 : +1 => new interface that does not break old one -# +1 : 0 : 0 => new interface that breaks old one -# : : 0 => no new interfaces, but breaks old apps -# : +1 : => internal changes, nothing breaks -# -libencfs_la_LDFLAGS = -version-info 7:0:0 -libencfs_la_LIBADD = @RLOG_LIBS@ @OPENSSL_LIBS@ - -EXTRASRC = ../intl/autosprintf.cpp -if BUILD_OPENSSL -if BUILD_SSLCIPHER -EXTRASRC += SSL_Cipher.cpp -endif -endif - -libencfs_la_SOURCES = \ - readpassphrase.cpp \ - base64.cpp \ - config.pb.cc \ - ConfigReader.cpp \ - ConfigVar.cpp \ - Context.cpp \ - Cipher.cpp \ - CipherKey.cpp \ - FileIO.cpp \ - RawFileIO.cpp \ - BlockFileIO.cpp \ - CipherFileIO.cpp \ - MACFileIO.cpp \ - NameIO.cpp \ - StreamNameIO.cpp \ - BlockNameIO.cpp \ - NullNameIO.cpp \ - Interface.cpp \ - MemoryPool.cpp \ - NullCipher.cpp \ - DirNode.cpp \ - FileNode.cpp \ - FileUtils.cpp \ - openssl.cpp \ - XmlReader.cpp \ - ${EXTRASRC} - - -encfs_SOURCES = \ - encfs.cpp \ - main.cpp - -test_SOURCES = \ - test.cpp - -makeKey_SOURCES = \ - makeKey.cpp - -encfsctl_SOURCES = \ - encfsctl.cpp - -noinst_HEADERS = \ - base64.h \ - BlockFileIO.h \ - BlockNameIO.h \ - CipherFileIO.h \ - Cipher.h \ - CipherKey.h \ - ConfigReader.h \ - ConfigVar.h \ - config.pb.h \ - Context.h \ - DirNode.h \ - encfs.h \ - FileIO.h \ - FileNode.h \ - FileUtils.h \ - FSConfig.h \ - Interface.h \ - i18n.h \ - MACFileIO.h \ - MemoryPool.h \ - Mutex.h \ - NameIO.h \ - NullCipher.h \ - NullNameIO.h \ - openssl.h \ - Range.h \ - RawFileIO.h \ - readpassphrase.h \ - SSL_Cipher.h \ - StreamNameIO.h - -man_MANS=encfs.1 encfsctl.1 -EXTRA_DIST = encfs.pod encfsctl.pod encfs.1 encfsctl.1 encfs-man.html - -SUFFIXES = .1 .pod .proto - -config.pb.cc: config.pb.h - -config.pb.h: config.proto - @PROTOC@ --cpp_out=. config.proto - -if BUILD_MAN -# since we have POD2MAN, we can specify how to rebuild encfs.1 if necessary -.pod.1: - @POD2MAN@ --section=1 --release=@VERSION@ --center="Encrypted Filesystem" $< $@ - -CLEANFILES = encfs.1 encfsctl.1 -endif - -if BUILD_MANHTML -encfs-man.html: encfs.pod - @POD2HTML@ encfs.pod > $@ -endif - -tests: - perl -MTest::Harness -e '$$Test::Harness::verbose=0; runtests @ARGV;' *.t - -tests-verbose: - perl -MTest::Harness -e '$$Test::Harness::verbose=1; runtests @ARGV;' *.t - diff --git a/encfs/MemoryPool.cpp b/encfs/MemoryPool.cpp deleted file mode 100644 index 4d983b0..0000000 --- a/encfs/MemoryPool.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2003, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include "MemoryPool.h" -#include - -#include -#include - -#include "config.h" -#include - -#include - -#ifdef HAVE_VALGRIND_MEMCHECK_H -#include -#else -#define VALGRIND_MAKE_MEM_NOACCESS( a, b ) -#define VALGRIND_MAKE_MEM_UNDEFINED( a, b ) -#endif - -using namespace rlog; - -# include -# include -#define BLOCKDATA( BLOCK ) (unsigned char*)BLOCK->data->data - - -struct BlockList -{ - BlockList *next; - int size; - BUF_MEM *data; -}; - -static BlockList *allocBlock( int size ) -{ - BlockList *block = new BlockList; - block->size = size; - block->data = BUF_MEM_new( ); - BUF_MEM_grow( block->data, size ); - VALGRIND_MAKE_MEM_NOACCESS( block->data->data, block->data->max ); - - return block; -} - -static void freeBlock( BlockList *el ) -{ - VALGRIND_MAKE_MEM_UNDEFINED( el->data->data, el->data->max ); - BUF_MEM_free( el->data ); - - delete el; -} - -static pthread_mutex_t gMPoolMutex = PTHREAD_MUTEX_INITIALIZER; -static BlockList *gMemPool = NULL; - - - -MemBlock MemoryPool::allocate( int size ) -{ - pthread_mutex_lock( &gMPoolMutex ); - - BlockList *parent = NULL; - BlockList *block = gMemPool; - // check if we already have a large enough block available.. - while(block != NULL && block->size < size) - { - parent = block; - block = block->next; - } - - // unlink block from list - if(block) - { - if(!parent) - gMemPool = block->next; - else - parent->next = block->next; - } - pthread_mutex_unlock( &gMPoolMutex ); - - if(!block) - block = allocBlock( size ); - block->next = NULL; - - MemBlock result; - result.data = BLOCKDATA(block); - result.internalData = block; - - VALGRIND_MAKE_MEM_UNDEFINED( result.data, size ); - - return result; -} - -void MemoryPool::release( const MemBlock &mb ) -{ - pthread_mutex_lock( &gMPoolMutex ); - - BlockList *block = (BlockList*)mb.internalData; - - // just to be sure there's nothing important left in buffers.. - VALGRIND_MAKE_MEM_UNDEFINED( block->data->data, block->size ); - memset( BLOCKDATA(block) , 0, block->size); - VALGRIND_MAKE_MEM_NOACCESS( block->data->data, block->data->max ); - - block->next = gMemPool; - gMemPool = block; - - pthread_mutex_unlock( &gMPoolMutex ); -} - -void MemoryPool::destroyAll() -{ - pthread_mutex_lock( &gMPoolMutex ); - - BlockList *block = gMemPool; - gMemPool = NULL; - - pthread_mutex_unlock( &gMPoolMutex ); - - while(block != NULL) - { - BlockList *next = block->next; - - freeBlock( block ); - block = next; - } -} - -SecureMem::SecureMem(int len) -{ - data = (char *)OPENSSL_malloc(len); - if (data) - { - size = len; - mlock(data, size); - memset(data, '\0', size); - VALGRIND_MAKE_MEM_UNDEFINED( data, size ); - } else - { - size = 0; - } -} - -SecureMem::~SecureMem() -{ - if (size) - { - memset(data, '\0', size); - munlock(data, size); - - OPENSSL_free(data); - VALGRIND_MAKE_MEM_NOACCESS( data, size ); - - data = NULL; - size = 0; - } -} - - diff --git a/encfs/NameIO.cpp b/encfs/NameIO.cpp deleted file mode 100644 index b9705fc..0000000 --- a/encfs/NameIO.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2004, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include "NameIO.h" -#include "config.h" - -#include -#include - -#include -#include - -// for static build. Need to reference the modules which are registered at -// run-time, to ensure that the linker doesn't optimize them away. -#include -#include "BlockNameIO.h" -#include "StreamNameIO.h" -#include "NullNameIO.h" - -using namespace std; -using namespace rlog; - -#define REF_MODULE(TYPE) \ - if(!TYPE::Enabled() ) \ - cerr << "referenceModule: should never happen\n"; - -static -void AddSymbolReferences() -{ - REF_MODULE(BlockNameIO) - REF_MODULE(StreamNameIO) - REF_MODULE(NullNameIO) -} - - -struct NameIOAlg -{ - bool hidden; - NameIO::Constructor constructor; - string description; - Interface iface; -}; - -typedef multimap< string, NameIOAlg > NameIOMap_t; -static NameIOMap_t *gNameIOMap = 0; - - -list< NameIO::Algorithm > -NameIO::GetAlgorithmList( bool includeHidden ) -{ - AddSymbolReferences(); - - list< Algorithm > result; - if(gNameIOMap) - { - NameIOMap_t::const_iterator it; - NameIOMap_t::const_iterator end = gNameIOMap->end(); - for(it = gNameIOMap->begin(); it != end; ++it) - { - if(includeHidden || !it->second.hidden) - { - Algorithm tmp; - tmp.name = it->first; - tmp.description = it->second.description; - tmp.iface = it->second.iface; - - result.push_back( tmp ); - } - } - } - - return result; -} - -bool NameIO::Register( const char *name, const char *description, - const Interface &iface, Constructor constructor, - bool hidden ) -{ - if( !gNameIOMap ) - gNameIOMap = new NameIOMap_t; - - NameIOAlg alg; - alg.hidden = hidden; - alg.constructor = constructor; - alg.description = description; - alg.iface = iface; - - gNameIOMap->insert( make_pair( string(name), alg )); - return true; -} - -shared_ptr NameIO::New( const string &name, - const shared_ptr &cipher, const CipherKey &key) -{ - shared_ptr result; - if(gNameIOMap) - { - NameIOMap_t::const_iterator it = gNameIOMap->find( name ); - if(it != gNameIOMap->end()) - { - Constructor fn = it->second.constructor; - result = (*fn)( it->second.iface, cipher, key ); - } - } - return result; -} - -shared_ptr NameIO::New( const Interface &iface, - const shared_ptr &cipher, const CipherKey &key ) -{ - shared_ptr result; - if(gNameIOMap) - { - NameIOMap_t::const_iterator it; - NameIOMap_t::const_iterator end = gNameIOMap->end(); - for(it = gNameIOMap->begin(); it != end; ++it) - { - if( implements(it->second.iface, iface )) - { - Constructor fn = it->second.constructor; - result = (*fn)( iface, cipher, key ); - break; - } - } - } - return result; -} - - - -NameIO::NameIO() - : chainedNameIV( false ), reverseEncryption( false ) -{ -} - -NameIO::~NameIO() -{ -} - -void NameIO::setChainedNameIV( bool enable ) -{ - chainedNameIV = enable; -} - -bool NameIO::getChainedNameIV() const -{ - return chainedNameIV; -} - -void NameIO::setReverseEncryption( bool enable ) -{ - reverseEncryption = enable; -} - -bool NameIO::getReverseEncryption() const -{ - return reverseEncryption; -} - - -std::string NameIO::recodePath( const char *path, - int (NameIO::*_length)(int) const, - int (NameIO::*_code)(const char*, int, uint64_t *, char*) const, - uint64_t *iv ) const -{ - string output; - - while( *path ) - { - if( *path == '/' ) - { - if( !output.empty() ) // don't start the string with '/' - output += '/'; - ++path; - } else - { - bool isDotFile = (*path == '.'); - const char *next = strchr( path, '/' ); - int len = next ? next - path : strlen( path ); - - // at this point we know that len > 0 - if( isDotFile && (path[len-1] == '.') && (len <= 2) ) - { - output.append(len, '.'); // append [len] copies of '.' - path += len; - continue; - } - - // figure out buffer sizes - int approxLen = (this->*_length)( len ); - if(approxLen <= 0) - throw ERROR("Filename too small to decode"); - - BUFFER_INIT( codeBuf, 32, (unsigned int)approxLen+1 ) - - // code the name - int codedLen = (this->*_code)( path, len, iv, codeBuf ); - rAssert( codedLen <= approxLen ); - rAssert( codeBuf[codedLen] == '\0' ); - path += len; - - // append result to string - output += (char*)codeBuf; - - BUFFER_RESET( codeBuf ) - } - } - - return output; -} - -std::string NameIO::encodePath( const char *plaintextPath ) const -{ - uint64_t iv = 0; - return encodePath( plaintextPath, &iv); -} - -std::string NameIO::decodePath( const char *cipherPath ) const -{ - uint64_t iv = 0; - return decodePath( cipherPath, &iv ); -} - -std::string NameIO::_encodePath( const char *plaintextPath, uint64_t *iv ) const -{ - // if chaining is not enabled, then the iv pointer is not used.. - if(!chainedNameIV) - iv = 0; - return recodePath( plaintextPath, - &NameIO::maxEncodedNameLen, &NameIO::encodeName, iv); -} - -std::string NameIO::_decodePath( const char *cipherPath, uint64_t *iv ) const -{ - // if chaining is not enabled, then the iv pointer is not used.. - if(!chainedNameIV) - iv = 0; - return recodePath( cipherPath, - &NameIO::maxDecodedNameLen, &NameIO::decodeName, iv); -} - -std::string NameIO::encodePath( const char *path, uint64_t *iv ) const -{ - return getReverseEncryption() ? - _decodePath( path, iv ) : - _encodePath( path, iv ); -} - -std::string NameIO::decodePath( const char *path, uint64_t *iv ) const -{ - return getReverseEncryption() ? - _encodePath( path, iv ) : - _decodePath( path, iv ); -} - - -int NameIO::encodeName( const char *input, int length, char *output ) const -{ - return encodeName( input, length, (uint64_t*)0, output ); -} - -int NameIO::decodeName( const char *input, int length, char *output ) const -{ - return decodeName( input, length, (uint64_t*)0, output ); -} - -std::string NameIO::_encodeName( const char *plaintextName, int length ) const -{ - int approxLen = maxEncodedNameLen( length ); - - BUFFER_INIT( codeBuf, 32, (unsigned int)approxLen+1 ) - - // code the name - int codedLen = encodeName( plaintextName, length, 0, codeBuf ); - rAssert( codedLen <= approxLen ); - rAssert( codeBuf[codedLen] == '\0' ); - - // append result to string - std::string result = (char*)codeBuf; - - BUFFER_RESET( codeBuf ) - - return result; -} - -std::string NameIO::_decodeName( const char *encodedName, int length ) const -{ - int approxLen = maxDecodedNameLen( length ); - - BUFFER_INIT( codeBuf, 32, (unsigned int)approxLen+1 ) - - // code the name - int codedLen = decodeName( encodedName, length, 0, codeBuf ); - rAssert( codedLen <= approxLen ); - rAssert( codeBuf[codedLen] == '\0' ); - - // append result to string - std::string result = (char*)codeBuf; - - BUFFER_RESET( codeBuf ) - - return result; -} - -std::string NameIO::encodeName( const char *path, int length ) const -{ - return getReverseEncryption() ? - _decodeName( path, length ) : - _encodeName( path, length ); -} - -std::string NameIO::decodeName( const char *path, int length ) const -{ - return getReverseEncryption() ? - _encodeName( path, length ) : - _decodeName( path, length ); -} -/* -int NameIO::encodeName( const char *path, int length, - char *output ) const -{ - return getReverseEncryption() ? - _decodeName( path, length, output ) : - _encodeName( path, length, output ); -} - -int NameIO::decodeName( const char *path, int length, - char *output ) const -{ - return getReverseEncryption() ? - _encodeName( path, length, output ) : - _decodeName( path, length, output ); -} -*/ diff --git a/encfs/RawFileIO.cpp b/encfs/RawFileIO.cpp deleted file mode 100644 index cb7515f..0000000 --- a/encfs/RawFileIO.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2004, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#ifdef linux -#define _XOPEN_SOURCE 500 // pick up pread , pwrite -#endif -#include - -#include "RawFileIO.h" - -#include - -#include -#include -#include -#include - -#include - -using namespace std; - -static Interface RawFileIO_iface = makeInterface("FileIO/Raw", 1, 0, 0); - -FileIO *NewRawFileIO( const Interface &iface ) -{ - (void)iface; - return new RawFileIO(); -} - -inline void swap( int &x, int &y ) -{ - int tmp = x; - x = y; - y = tmp; -} - -RawFileIO::RawFileIO( ) - : knownSize( false ) - , fileSize(0) - , fd( -1 ) - , oldfd( -1 ) - , canWrite( false ) -{ -} - -RawFileIO::RawFileIO( const std::string &fileName ) - : name( fileName ) - , knownSize( false ) - , fileSize( 0 ) - , fd( -1 ) - , oldfd( -1 ) - , canWrite( false ) -{ -} - -RawFileIO::~RawFileIO() -{ - int _fd = -1; - int _oldfd = -1; - - swap( _fd, fd ); - swap( _oldfd, oldfd ); - - if( _oldfd != -1 ) - close( _oldfd ); - - if( _fd != -1 ) - close( _fd ); -} - -Interface RawFileIO::interface() const -{ - return RawFileIO_iface; -} - -/* - Workaround for opening a file for write when permissions don't allow. - Since the kernel has already checked permissions, we can assume it is ok to - provide access. So force it by changing permissions temporarily. Should - be called with a lock around it so that there won't be a race condition - with calls to lstat picking up the wrong permissions. -*/ -static int open_readonly_workaround(const char *path, int flags) -{ - int fd = -1; - struct stat stbuf; - memset(&stbuf, 0, sizeof(struct stat)); - if(lstat( path, &stbuf ) != -1) - { - // make sure user has read/write permission.. - chmod( path , stbuf.st_mode | 0600 ); - fd = ::open( path , flags ); - chmod( path , stbuf.st_mode ); - } else - { - rInfo("can't stat file %s", path ); - } - - return fd; -} - -/* - We shouldn't have to support all possible open flags, so untaint the flags - argument by only taking ones we understand and accept. - - Since the kernel has already done permission tests before calling us, we - shouldn't have to worry about access control. - - Basically we just need to distinguish between read and write flags - - Also keep the O_LARGEFILE flag, in case the underlying filesystem needs - it.. -*/ -int RawFileIO::open(int flags) -{ - bool requestWrite = ((flags & O_RDWR) || (flags & O_WRONLY)); - - rDebug("open call for %s file", requestWrite ? "writable" : "read only"); - - int result = 0; - - // if we have a descriptor and it is writable, or we don't need writable.. - if((fd >= 0) && (canWrite || !requestWrite)) - { - rDebug("using existing file descriptor"); - result = fd; // success - } else - { - int finalFlags = requestWrite ? O_RDWR : O_RDONLY; - -#if defined(O_LARGEFILE) - if( flags & O_LARGEFILE ) - finalFlags |= O_LARGEFILE; -#else -#warning O_LARGEFILE not supported -#endif - - int newFd = ::open( name.c_str(), finalFlags ); - - rDebug("open file with flags %i, result = %i", finalFlags, newFd); - - if((newFd == -1) && (errno == EACCES)) - { - rDebug("using readonly workaround for open"); - newFd = open_readonly_workaround( name.c_str(), finalFlags ); - } - - if(newFd >= 0) - { - if(oldfd >= 0) - { - rError("leaking FD?: oldfd = %i, fd = %i, newfd = %i", - oldfd, fd, newFd); - } - - // the old fd might still be in use, so just keep it around for - // now. - canWrite = requestWrite; - oldfd = fd; - result = fd = newFd; - } else - { - result = -errno; - rInfo("::open error: %s", strerror(errno)); - } - } - - if(result < 0) - rInfo("file %s open failure: %i", name.c_str(), -result); - - return result; -} - -int RawFileIO::getAttr( struct stat *stbuf ) const -{ - int res = lstat( name.c_str(), stbuf ); - int eno = errno; - - if(res < 0) - rInfo("getAttr error on %s: %s", name.c_str(), strerror( eno )); - - return ( res < 0 ) ? -eno : 0; -} - -void RawFileIO::setFileName( const char *fileName ) -{ - name = fileName; -} - -const char *RawFileIO::getFileName() const -{ - return name.c_str(); -} - -off_t RawFileIO::getSize() const -{ - if(!knownSize) - { - struct stat stbuf; - memset( &stbuf, 0, sizeof( struct stat )); - int res = lstat( name.c_str(), &stbuf ); - - if(res == 0) - { - const_cast(this)->fileSize = stbuf.st_size; - const_cast(this)->knownSize = true; - return fileSize; - } else - return -1; - } else - { - return fileSize; - } -} - -ssize_t RawFileIO::read( const IORequest &req ) const -{ - rAssert( fd >= 0 ); - - ssize_t readSize = pread( fd, req.data, req.dataLen, req.offset ); - - if(readSize < 0) - { - rInfo("read failed at offset %" PRIi64 " for %i bytes: %s", - req.offset, req.dataLen, strerror( errno )); - } - - return readSize; -} - -bool RawFileIO::write( const IORequest &req ) -{ - rAssert( fd >= 0 ); - rAssert( true == canWrite ); - - int retrys = 10; - void *buf = req.data; - ssize_t bytes = req.dataLen; - off_t offset = req.offset; - - while( bytes && retrys > 0 ) - { - ssize_t writeSize = ::pwrite( fd, buf, bytes, offset ); - - if( writeSize < 0 ) - { - knownSize = false; - rInfo("write failed at offset %" PRIi64 " for %i bytes: %s", - offset, (int)bytes, strerror( errno )); - return false; - } - - bytes -= writeSize; - offset += writeSize; - buf = (void*)((char*)buf + writeSize); - --retrys; - } - - if(bytes != 0) - { - rError("Write error: wrote %i bytes of %i, max retries reached\n", - (int)(req.dataLen - bytes), req.dataLen ); - knownSize = false; - return false; - } else - { - if(knownSize) - { - off_t last = req.offset + req.dataLen; - if(last > fileSize) - fileSize = last; - } - - return true; - } -} - -int RawFileIO::truncate( off_t size ) -{ - int res; - - if(fd >= 0 && canWrite) - { - res = ::ftruncate( fd, size ); -#ifndef __FreeBSD__ - ::fdatasync( fd ); -#endif - } else - res = ::truncate( name.c_str(), size ); - - if(res < 0) - { - int eno = errno; - rInfo("truncate failed for %s (%i) size %" PRIi64 ", error %s", - name.c_str(), fd, size, strerror(eno)); - res = -eno; - knownSize = false; - } else - { - res = 0; - fileSize = size; - knownSize = true; - } - - return res; -} - -bool RawFileIO::isWritable() const -{ - return canWrite; -} diff --git a/encfs/SSL_Cipher.cpp b/encfs/SSL_Cipher.cpp deleted file mode 100644 index 10f2d61..0000000 --- a/encfs/SSL_Cipher.cpp +++ /dev/null @@ -1,927 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2004, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include "encfs.h" - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "SSL_Cipher.h" -#include "Range.h" -#include "MemoryPool.h" -#include "Mutex.h" - -#include -#include - -#include -#include - -#include -#include - -#include "i18n.h" - -using namespace std; -using namespace rel; -using namespace rlog; - -const int MAX_KEYLENGTH = 32; // in bytes (256 bit) -const int MAX_IVLENGTH = 16; -const int KEY_CHECKSUM_BYTES = 4; - -#ifndef MIN -inline int MIN(int a, int b) -{ - return (a < b) ? a : b; -} -#endif - -/* - This produces the same result as OpenSSL's EVP_BytesToKey. The difference - is that here we can explicitly specify the key size, instead of relying on - the state of EVP_CIPHER struct. EVP_BytesToKey will only produce 128 bit - keys for the EVP Blowfish interface, which is not what we want. - - DEPRECATED: this is here for backward compatibilty only. Use PBKDF -*/ -int BytesToKey( int keyLen, int ivLen, const EVP_MD *md, - const unsigned char *data, int dataLen, - unsigned int rounds, unsigned char *key, unsigned char *iv) -{ - if( data == NULL || dataLen == 0 ) - return 0; // OpenSSL returns nkey here, but why? It is a failure.. - - unsigned char mdBuf[ EVP_MAX_MD_SIZE ]; - unsigned int mds=0; - int addmd =0; - int nkey = key ? keyLen : 0; - int niv = iv ? ivLen : 0; - - EVP_MD_CTX cx; - EVP_MD_CTX_init( &cx ); - - for(;;) - { - EVP_DigestInit_ex( &cx, md, NULL ); - if( addmd++ ) - EVP_DigestUpdate( &cx, mdBuf, mds ); - EVP_DigestUpdate( &cx, data, dataLen ); - EVP_DigestFinal_ex( &cx, mdBuf, &mds ); - - for(unsigned int i=1; i < rounds; ++i) - { - EVP_DigestInit_ex( &cx, md, NULL ); - EVP_DigestUpdate( &cx, mdBuf, mds ); - EVP_DigestFinal_ex( &cx, mdBuf, &mds ); - } - - int offset = 0; - int toCopy = MIN( nkey, (int)mds - offset ); - if( toCopy ) - { - memcpy( key, mdBuf+offset, toCopy ); - key += toCopy; - nkey -= toCopy; - offset += toCopy; - } - toCopy = MIN( niv, (int)mds - offset ); - if( toCopy ) - { - memcpy( iv, mdBuf+offset, toCopy ); - iv += toCopy; - niv -= toCopy; - offset += toCopy; - } - if((nkey == 0) && (niv == 0)) break; - } - EVP_MD_CTX_cleanup( &cx ); - OPENSSL_cleanse( mdBuf, sizeof(mdBuf) ); - - return keyLen; -} - -long time_diff(const timeval &end, const timeval &start) -{ - return (end.tv_sec - start.tv_sec) * 1000 * 1000 + - (end.tv_usec - start.tv_usec); -} - -int TimedPBKDF2(const char *pass, int passlen, - const unsigned char *salt, int saltlen, - int keylen, unsigned char *out, - long desiredPDFTime) -{ - int iter = 1000; - timeval start, end; - - for(;;) - { - gettimeofday( &start, 0 ); - int res = PKCS5_PBKDF2_HMAC_SHA1( - pass, passlen, const_cast(salt), saltlen, - iter, keylen, out); - if(res != 1) - return -1; - - gettimeofday( &end, 0 ); - - long delta = time_diff(end, start); - if(delta < desiredPDFTime / 8) - { - iter *= 4; - } else if(delta < (5 * desiredPDFTime / 6)) - { - // estimate number of iterations to get close to desired time - iter = (int)((double)iter * (double)desiredPDFTime - / (double)delta); - } else - return iter; - } -} - - -// - Version 1:0 used EVP_BytesToKey, which didn't do the right thing for -// Blowfish key lengths > 128 bit. -// - Version 2:0 uses BytesToKey. -// We support both 2:0 and 1:0, hence current:revision:age = 2:0:1 -// - Version 2:1 adds support for Message Digest function interface -// - Version 2:2 adds PBKDF2 for password derivation -// - Version 3:0 adds a new IV mechanism -static Interface BlowfishInterface = makeInterface( "ssl/blowfish", 3, 0, 2 ); -static Interface AESInterface = makeInterface( "ssl/aes", 3, 0, 2 ); - -#if defined(HAVE_EVP_BF) - -static Range BFKeyRange(128,256,32); -static Range BFBlockRange(64,4096,8); - -static shared_ptr NewBFCipher( const Interface &iface, int keyLen ) -{ - if( keyLen <= 0 ) - keyLen = 160; - - keyLen = BFKeyRange.closest( keyLen ); - - const EVP_CIPHER *blockCipher = EVP_bf_cbc(); - const EVP_CIPHER *streamCipher = EVP_bf_cfb(); - - return shared_ptr( new SSL_Cipher(iface, BlowfishInterface, - blockCipher, streamCipher, keyLen / 8) ); -} - -static bool BF_Cipher_registered = Cipher::Register("Blowfish", - // xgroup(setup) - gettext_noop("8 byte block cipher"), - BlowfishInterface, BFKeyRange, BFBlockRange, NewBFCipher); -#endif - - -#if defined(HAVE_EVP_AES) - -static Range AESKeyRange(128,256,64); -static Range AESBlockRange(64,4096,16); - -static shared_ptr NewAESCipher( const Interface &iface, int keyLen ) -{ - if( keyLen <= 0 ) - keyLen = 192; - - keyLen = AESKeyRange.closest( keyLen ); - - const EVP_CIPHER *blockCipher = 0; - const EVP_CIPHER *streamCipher = 0; - - switch(keyLen) - { - case 128: - blockCipher = EVP_aes_128_cbc(); - streamCipher = EVP_aes_128_cfb(); - break; - - case 192: - blockCipher = EVP_aes_192_cbc(); - streamCipher = EVP_aes_192_cfb(); - break; - - case 256: - default: - blockCipher = EVP_aes_256_cbc(); - streamCipher = EVP_aes_256_cfb(); - break; - } - - return shared_ptr( new SSL_Cipher(iface, AESInterface, - blockCipher, streamCipher, keyLen / 8) ); -} - -static bool AES_Cipher_registered = Cipher::Register("AES", - "16 byte block cipher", - AESInterface, AESKeyRange, AESBlockRange, NewAESCipher); -#endif - -class SSLKey : public AbstractCipherKey -{ -public: - pthread_mutex_t mutex; - - unsigned int keySize; // in bytes - unsigned int ivLength; - - // key data is first _keySize bytes, - // followed by iv of _ivLength bytes, - unsigned char *buffer; - - EVP_CIPHER_CTX block_enc; - EVP_CIPHER_CTX block_dec; - EVP_CIPHER_CTX stream_enc; - EVP_CIPHER_CTX stream_dec; - - HMAC_CTX mac_ctx; - - SSLKey(int keySize, int ivLength); - ~SSLKey(); -}; - -SSLKey::SSLKey(int keySize_, int ivLength_) -{ - this->keySize = keySize_; - this->ivLength = ivLength_; - pthread_mutex_init( &mutex, 0 ); - buffer = (unsigned char *)OPENSSL_malloc( keySize + ivLength ); - - // most likely fails unless we're running as root, or a user-page-lock - // kernel patch is applied.. - mlock( buffer, keySize + ivLength ); - - memset( buffer, 0, keySize + ivLength ); -} - -SSLKey::~SSLKey() -{ - memset( buffer, 0, keySize + ivLength ); - - munlock( buffer, keySize + ivLength ); - OPENSSL_free( buffer ); - - keySize = 0; - ivLength = 0; - buffer = 0; - - EVP_CIPHER_CTX_cleanup( &block_enc ); - EVP_CIPHER_CTX_cleanup( &block_dec ); - EVP_CIPHER_CTX_cleanup( &stream_enc ); - EVP_CIPHER_CTX_cleanup( &stream_dec ); - - HMAC_CTX_cleanup( &mac_ctx ); - - pthread_mutex_destroy( &mutex ); -} - - -inline unsigned char* KeyData( const shared_ptr &key ) -{ - return key->buffer; -} -inline unsigned char* IVData( const shared_ptr &key ) -{ - return key->buffer + key->keySize; -} - -void initKey(const shared_ptr &key, const EVP_CIPHER *_blockCipher, - const EVP_CIPHER *_streamCipher, int _keySize) -{ - Lock lock( key->mutex ); - // initialize the cipher context once so that we don't have to do it for - // every block.. - EVP_CIPHER_CTX_init( &key->block_enc ); - EVP_CIPHER_CTX_init( &key->block_dec ); - EVP_CIPHER_CTX_init( &key->stream_enc ); - EVP_CIPHER_CTX_init( &key->stream_dec ); - - EVP_EncryptInit_ex( &key->block_enc, _blockCipher, NULL, NULL, NULL); - EVP_DecryptInit_ex( &key->block_dec, _blockCipher, NULL, NULL, NULL); - EVP_EncryptInit_ex( &key->stream_enc, _streamCipher, NULL, NULL, NULL); - EVP_DecryptInit_ex( &key->stream_dec, _streamCipher, NULL, NULL, NULL); - - EVP_CIPHER_CTX_set_key_length( &key->block_enc, _keySize ); - EVP_CIPHER_CTX_set_key_length( &key->block_dec, _keySize ); - EVP_CIPHER_CTX_set_key_length( &key->stream_enc, _keySize ); - EVP_CIPHER_CTX_set_key_length( &key->stream_dec, _keySize ); - - EVP_CIPHER_CTX_set_padding( &key->block_enc, 0 ); - EVP_CIPHER_CTX_set_padding( &key->block_dec, 0 ); - EVP_CIPHER_CTX_set_padding( &key->stream_enc, 0 ); - EVP_CIPHER_CTX_set_padding( &key->stream_dec, 0 ); - - EVP_EncryptInit_ex( &key->block_enc, NULL, NULL, KeyData(key), NULL); - EVP_DecryptInit_ex( &key->block_dec, NULL, NULL, KeyData(key), NULL); - EVP_EncryptInit_ex( &key->stream_enc, NULL, NULL, KeyData(key), NULL); - EVP_DecryptInit_ex( &key->stream_dec, NULL, NULL, KeyData(key), NULL); - - HMAC_CTX_init( &key->mac_ctx ); - HMAC_Init_ex( &key->mac_ctx, KeyData(key), _keySize, EVP_sha1(), 0 ); -} - - -static RLogChannel * CipherInfo = DEF_CHANNEL( "info/cipher", Log_Info ); - -SSL_Cipher::SSL_Cipher(const Interface &iface_, - const Interface &realIface_, - const EVP_CIPHER *blockCipher, - const EVP_CIPHER *streamCipher, - int keySize_) -{ - this->iface = iface_; - this->realIface = realIface_; - this->_blockCipher = blockCipher; - this->_streamCipher = streamCipher; - this->_keySize = keySize_; - this->_ivLength = EVP_CIPHER_iv_length( _blockCipher ); - - rAssert(_ivLength == 8 || _ivLength == 16); - - rLog(CipherInfo, "allocated cipher %s, keySize %i, ivlength %i", - iface.name().c_str(), _keySize, _ivLength); - - if( (EVP_CIPHER_key_length( _blockCipher ) != (int )_keySize) - && iface.major() == 1) - { - rWarning("Running in backward compatibilty mode for 1.0 - \n" - "key is really %i bits, not %i.\n" - "Consider creating a new filesystem and moving your data.", - EVP_CIPHER_key_length( _blockCipher ) * 8, - _keySize * 8 ); - } -} - -SSL_Cipher::~SSL_Cipher() -{ -} - -Interface SSL_Cipher::interface() const -{ - return realIface; -} - -/* - create a key from the password. - Use SHA to distribute entropy from the password into the key. - - This algorithm must remain constant for backward compatibility, as this key - is used to encipher/decipher the master key. -*/ -CipherKey SSL_Cipher::newKey(const char *password, int passwdLength, - int &iterationCount, long desiredDuration, - const unsigned char *salt, int saltLen) -{ - shared_ptr key( new SSLKey( _keySize, _ivLength) ); - - if(iterationCount == 0) - { - // timed run, fills in iteration count - int res = TimedPBKDF2(password, passwdLength, - salt, saltLen, - _keySize+_ivLength, KeyData(key), - 1000 * desiredDuration); - if(res <= 0) - { - rWarning("openssl error, PBKDF2 failed"); - return CipherKey(); - } else - iterationCount = res; - } else - { - // known iteration length - if(PKCS5_PBKDF2_HMAC_SHA1( - password, passwdLength, - const_cast(salt), saltLen, - iterationCount, _keySize + _ivLength, KeyData(key)) != 1) - { - rWarning("openssl error, PBKDF2 failed"); - return CipherKey(); - } - } - - initKey( key, _blockCipher, _streamCipher, _keySize ); - - return key; -} - -CipherKey SSL_Cipher::newKey(const char *password, int passwdLength) -{ - shared_ptr key( new SSLKey( _keySize, _ivLength) ); - - int bytes = 0; - if( iface.major() > 1 ) - { - // now we use BytesToKey, which can deal with Blowfish keys larger then - // 128 bits. - bytes = BytesToKey( _keySize, _ivLength, EVP_sha1(), - (unsigned char *)password, passwdLength, 16, - KeyData(key), IVData(key) ); - - // the reason for moving from EVP_BytesToKey to BytesToKey function.. - if(bytes != (int)_keySize) - { - rWarning("newKey: BytesToKey returned %i, expecting %i key bytes", - bytes, _keySize); - } - } else - { - // for backward compatibility with filesystems created with 1:0 - bytes = EVP_BytesToKey( _blockCipher, EVP_sha1(), NULL, - (unsigned char *)password, passwdLength, 16, - KeyData(key), IVData(key) ); - } - - initKey( key, _blockCipher, _streamCipher, _keySize ); - - return key; -} - -/* - Create a random key. - We use the OpenSSL library to generate random bytes, then take the hash of - those bytes to use as the key. - - This algorithm can change at any time without affecting backward - compatibility. -*/ -CipherKey SSL_Cipher::newRandomKey() -{ - const int bufLen = MAX_KEYLENGTH; - unsigned char tmpBuf[ bufLen ]; - int saltLen = 20; - unsigned char saltBuf[ saltLen ]; - - if(!randomize(tmpBuf, bufLen, true) || - !randomize(saltBuf, saltLen, true)) - return CipherKey(); - - shared_ptr key( new SSLKey( _keySize, _ivLength) ); - - // doesn't need to be versioned, because a random key is a random key.. - // Doesn't need to be reproducable.. - if(PKCS5_PBKDF2_HMAC_SHA1((char*)tmpBuf, bufLen, saltBuf, saltLen, - 1000, _keySize + _ivLength, KeyData(key)) != 1) - { - rWarning("openssl error, PBKDF2 failed"); - return CipherKey(); - } - - OPENSSL_cleanse(tmpBuf, bufLen); - - initKey( key, _blockCipher, _streamCipher, _keySize ); - - return key; -} - -/* - compute a 64-bit check value for the data using HMAC. -*/ -static uint64_t _checksum_64( SSLKey *key, - const unsigned char *data, int dataLen, uint64_t *chainedIV) -{ - rAssert( dataLen > 0 ); - Lock lock( key->mutex ); - - unsigned char md[EVP_MAX_MD_SIZE]; - unsigned int mdLen = EVP_MAX_MD_SIZE; - - HMAC_Init_ex( &key->mac_ctx, 0, 0, 0, 0 ); - HMAC_Update( &key->mac_ctx, data, dataLen ); - if(chainedIV) - { - // toss in the chained IV as well - uint64_t tmp = *chainedIV; - unsigned char h[8]; - for(unsigned int i=0; i<8; ++i) - { - h[i] = tmp & 0xff; - tmp >>= 8; - } - - HMAC_Update( &key->mac_ctx, h, 8 ); - } - - HMAC_Final( &key->mac_ctx, md, &mdLen ); - - rAssert(mdLen >= 8); - - // chop this down to a 64bit value.. - unsigned char h[8] = {0,0,0,0,0,0,0,0}; - for(unsigned int i=0; i<(mdLen-1); ++i) - h[i%8] ^= (unsigned char)(md[i]); - - uint64_t value = (uint64_t)h[0]; - for(int i=1; i<8; ++i) - value = (value << 8) | (uint64_t)h[i]; - - return value; -} - -bool SSL_Cipher::randomize( unsigned char *buf, int len, - bool strongRandom ) const -{ - // to avoid warnings of uninitialized data from valgrind - memset(buf, 0, len); - int result; - if(strongRandom) - result = RAND_bytes( buf, len ); - else - result = RAND_pseudo_bytes( buf, len ); - - if(result != 1) - { - char errStr[120]; // specs require string at least 120 bytes long.. - unsigned long errVal = 0; - if((errVal = ERR_get_error()) != 0) - rWarning("openssl error: %s", ERR_error_string( errVal, errStr )); - - return false; - } else - return true; -} - -uint64_t SSL_Cipher::MAC_64( const unsigned char *data, int len, - const CipherKey &key, uint64_t *chainedIV ) const -{ - shared_ptr mk = dynamic_pointer_cast(key); - uint64_t tmp = _checksum_64( mk.get(), data, len, chainedIV ); - - if(chainedIV) - *chainedIV = tmp; - - return tmp; -} - -CipherKey SSL_Cipher::readKey(const unsigned char *data, - const CipherKey &masterKey, bool checkKey) -{ - shared_ptr mk = dynamic_pointer_cast(masterKey); - rAssert(mk->keySize == _keySize); - - unsigned char tmpBuf[ MAX_KEYLENGTH + MAX_IVLENGTH ]; - - // First N bytes are checksum bytes. - unsigned int checksum = 0; - for(int i=0; i key( new SSLKey( _keySize, _ivLength) ); - - memcpy( key->buffer, tmpBuf, _keySize + _ivLength ); - memset( tmpBuf, 0, sizeof(tmpBuf) ); - - initKey( key, _blockCipher, _streamCipher, _keySize ); - - return key; -} - -void SSL_Cipher::writeKey(const CipherKey &ckey, unsigned char *data, - const CipherKey &masterKey) -{ - shared_ptr key = dynamic_pointer_cast(ckey); - rAssert(key->keySize == _keySize); - rAssert(key->ivLength == _ivLength); - - shared_ptr mk = dynamic_pointer_cast(masterKey); - rAssert(mk->keySize == _keySize); - rAssert(mk->ivLength == _ivLength); - - unsigned char tmpBuf[ MAX_KEYLENGTH + MAX_IVLENGTH ]; - - int bufLen = _keySize + _ivLength; - memcpy( tmpBuf, key->buffer, bufLen ); - - unsigned int checksum = MAC_32( tmpBuf, bufLen, masterKey ); - - streamEncode(tmpBuf, bufLen, checksum, masterKey); - memcpy( data+KEY_CHECKSUM_BYTES, tmpBuf, bufLen ); - - // first N bytes contain HMAC derived checksum.. - for(int i=1; i<=KEY_CHECKSUM_BYTES; ++i) - { - data[KEY_CHECKSUM_BYTES-i] = checksum & 0xff; - checksum >>= 8; - } - - memset( tmpBuf, 0, sizeof(tmpBuf) ); -} - -bool SSL_Cipher::compareKey( const CipherKey &A, const CipherKey &B) const -{ - shared_ptr key1 = dynamic_pointer_cast(A); - shared_ptr key2 = dynamic_pointer_cast(B); - - rAssert(key1->keySize == _keySize); - rAssert(key2->keySize == _keySize); - - if(memcmp(key1->buffer, key2->buffer, _keySize + _ivLength) != 0) - return false; - else - return true; -} - -int SSL_Cipher::encodedKeySize() const -{ - return _keySize + _ivLength + KEY_CHECKSUM_BYTES; -} - -int SSL_Cipher::keySize() const -{ - return _keySize; -} - -int SSL_Cipher::cipherBlockSize() const -{ - return EVP_CIPHER_block_size( _blockCipher ); -} - -void SSL_Cipher::setIVec( unsigned char *ivec, uint64_t seed, - const shared_ptr &key) const -{ - if (iface.major() >= 3) - { - memcpy( ivec, IVData(key), _ivLength ); - - unsigned char md[EVP_MAX_MD_SIZE]; - unsigned int mdLen = EVP_MAX_MD_SIZE; - - for(int i=0; i<8; ++i) - { - md[i] = (unsigned char)(seed & 0xff); - seed >>= 8; - } - - // combine ivec and seed with HMAC - HMAC_Init_ex( &key->mac_ctx, 0, 0, 0, 0 ); - HMAC_Update( &key->mac_ctx, ivec, _ivLength ); - HMAC_Update( &key->mac_ctx, md, 8 ); - HMAC_Final( &key->mac_ctx, md, &mdLen ); - rAssert(mdLen >= _ivLength); - - memcpy( ivec, md, _ivLength ); - } else - { - setIVec_old(ivec, seed, key); - } -} - -/** Deprecated: For backward compatibility only. - A watermark attack was discovered against this IV setup. If an attacker - could get a victim to store a carefully crafted file, they could later - determine if the victim had the file in encrypted storage (without - decrypting the file). - */ -void SSL_Cipher::setIVec_old(unsigned char *ivec, - unsigned int seed, - const shared_ptr &key) const -{ - unsigned int var1 = 0x060a4011 * seed; - unsigned int var2 = 0x0221040d * (seed ^ 0xD3FEA11C); - - memcpy( ivec, IVData(key), _ivLength ); - - ivec[0] ^= (var1 >> 24) & 0xff; - ivec[1] ^= (var2 >> 16) & 0xff; - ivec[2] ^= (var1 >> 8 ) & 0xff; - ivec[3] ^= (var2 ) & 0xff; - ivec[4] ^= (var2 >> 24) & 0xff; - ivec[5] ^= (var1 >> 16) & 0xff; - ivec[6] ^= (var2 >> 8 ) & 0xff; - ivec[7] ^= (var1 ) & 0xff; - - if(_ivLength > 8) - { - ivec[8+0] ^= (var1 ) & 0xff; - ivec[8+1] ^= (var2 >> 8 ) & 0xff; - ivec[8+2] ^= (var1 >> 16) & 0xff; - ivec[8+3] ^= (var2 >> 24) & 0xff; - ivec[8+4] ^= (var1 >> 24) & 0xff; - ivec[8+5] ^= (var2 >> 16) & 0xff; - ivec[8+6] ^= (var1 >> 8 ) & 0xff; - ivec[8+7] ^= (var2 ) & 0xff; - } -} - -static void flipBytes(unsigned char *buf, int size) -{ - unsigned char revBuf[64]; - - int bytesLeft = size; - while(bytesLeft) - { - int toFlip = MIN( sizeof(revBuf), bytesLeft ); - - for(int i=0; i 0 ); - shared_ptr key = dynamic_pointer_cast(ckey); - rAssert(key->keySize == _keySize); - rAssert(key->ivLength == _ivLength); - - Lock lock( key->mutex ); - - unsigned char ivec[ MAX_IVLENGTH ]; - int dstLen=0, tmpLen=0; - - shuffleBytes( buf, size ); - - setIVec( ivec, iv64, key ); - EVP_EncryptInit_ex( &key->stream_enc, NULL, NULL, NULL, ivec); - EVP_EncryptUpdate( &key->stream_enc, buf, &dstLen, buf, size ); - EVP_EncryptFinal_ex( &key->stream_enc, buf+dstLen, &tmpLen ); - - flipBytes( buf, size ); - shuffleBytes( buf, size ); - - setIVec( ivec, iv64 + 1, key ); - EVP_EncryptInit_ex( &key->stream_enc, NULL, NULL, NULL, ivec); - EVP_EncryptUpdate( &key->stream_enc, buf, &dstLen, buf, size ); - EVP_EncryptFinal_ex( &key->stream_enc, buf+dstLen, &tmpLen ); - - dstLen += tmpLen; - if(dstLen != size) - { - rError("encoding %i bytes, got back %i (%i in final_ex)", - size, dstLen, tmpLen); - } - - return true; -} - -bool SSL_Cipher::streamDecode(unsigned char *buf, int size, - uint64_t iv64, const CipherKey &ckey) const -{ - rAssert( size > 0 ); - shared_ptr key = dynamic_pointer_cast(ckey); - rAssert(key->keySize == _keySize); - rAssert(key->ivLength == _ivLength); - - Lock lock( key->mutex ); - - unsigned char ivec[ MAX_IVLENGTH ]; - int dstLen=0, tmpLen=0; - - setIVec( ivec, iv64 + 1, key ); - EVP_DecryptInit_ex( &key->stream_dec, NULL, NULL, NULL, ivec); - EVP_DecryptUpdate( &key->stream_dec, buf, &dstLen, buf, size ); - EVP_DecryptFinal_ex( &key->stream_dec, buf+dstLen, &tmpLen ); - - unshuffleBytes( buf, size ); - flipBytes( buf, size ); - - setIVec( ivec, iv64, key ); - EVP_DecryptInit_ex( &key->stream_dec, NULL, NULL, NULL, ivec); - EVP_DecryptUpdate( &key->stream_dec, buf, &dstLen, buf, size ); - EVP_DecryptFinal_ex( &key->stream_dec, buf+dstLen, &tmpLen ); - - unshuffleBytes( buf, size ); - - dstLen += tmpLen; - if(dstLen != size) - { - rError("encoding %i bytes, got back %i (%i in final_ex)", - size, dstLen, tmpLen); - } - - return true; -} - - -bool SSL_Cipher::blockEncode(unsigned char *buf, int size, - uint64_t iv64, const CipherKey &ckey ) const -{ - rAssert( size > 0 ); - shared_ptr key = dynamic_pointer_cast(ckey); - rAssert(key->keySize == _keySize); - rAssert(key->ivLength == _ivLength); - - // data must be integer number of blocks - const int blockMod = size % EVP_CIPHER_CTX_block_size( &key->block_enc ); - if(blockMod != 0) - throw ERROR("Invalid data size, not multiple of block size"); - - Lock lock( key->mutex ); - - unsigned char ivec[ MAX_IVLENGTH ]; - - int dstLen = 0, tmpLen = 0; - setIVec( ivec, iv64, key ); - - EVP_EncryptInit_ex( &key->block_enc, NULL, NULL, NULL, ivec); - EVP_EncryptUpdate( &key->block_enc, buf, &dstLen, buf, size ); - EVP_EncryptFinal_ex( &key->block_enc, buf+dstLen, &tmpLen ); - dstLen += tmpLen; - - if(dstLen != size) - { - rError("encoding %i bytes, got back %i (%i in final_ex)", - size, dstLen, tmpLen); - } - - return true; -} - -bool SSL_Cipher::blockDecode(unsigned char *buf, int size, - uint64_t iv64, const CipherKey &ckey ) const -{ - rAssert( size > 0 ); - shared_ptr key = dynamic_pointer_cast(ckey); - rAssert(key->keySize == _keySize); - rAssert(key->ivLength == _ivLength); - - // data must be integer number of blocks - const int blockMod = size % EVP_CIPHER_CTX_block_size( &key->block_dec ); - if(blockMod != 0) - throw ERROR("Invalid data size, not multiple of block size"); - - Lock lock( key->mutex ); - - unsigned char ivec[ MAX_IVLENGTH ]; - - int dstLen = 0, tmpLen = 0; - setIVec( ivec, iv64, key ); - - EVP_DecryptInit_ex( &key->block_dec, NULL, NULL, NULL, ivec); - EVP_DecryptUpdate( &key->block_dec, buf, &dstLen, buf, size ); - EVP_DecryptFinal_ex( &key->block_dec, buf+dstLen, &tmpLen ); - dstLen += tmpLen; - - if(dstLen != size) - { - rError("decoding %i bytes, got back %i (%i in final_ex)", - size, dstLen, tmpLen); - } - - return true; -} - -bool SSL_Cipher::Enabled() -{ - return true; -} - diff --git a/encfs/SSL_Cipher.h b/encfs/SSL_Cipher.h deleted file mode 100644 index 375ae14..0000000 --- a/encfs/SSL_Cipher.h +++ /dev/null @@ -1,150 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2004, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#ifndef _SSL_Cipher_incl_ -#define _SSL_Cipher_incl_ - -#include "Cipher.h" -#include "Interface.h" - -struct SSLKey; -#ifndef EVP_CIPHER -struct evp_cipher_st; -typedef struct evp_cipher_st EVP_CIPHER; -#endif - -/* - Implements Cipher interface for OpenSSL's ciphers. - - Design: - Variable algorithm, key size, and block size. - - Partial blocks, keys, and names are encrypted using the cipher in a pseudo - stream mode (CFB). - - Keys are encrypted with 2-4 (KEY_CHECKSUM_BYTES define) checksum bytes - derived from an HMAC over both they key data and the initial value vector - associated with the key. This allows a good chance at detecting an - incorrect password when we try and decrypt the master key. - - File names are encrypted in the same way, with 2 checksum bytes derived - from an HMAC over the filename. This is done not to allow checking the - results, but to make the output much more random. Changing one letter in a - filename should result in a completely different encrypted filename, to - help frustrate any attempt to guess information about files from their - encrypted names. - - Stream encryption involves two encryption passes over the data, implemented - as: - 1. shuffle - 2. encrypt - 3. reverse - 4. shuffle - 5. encrypt - The reason for the shuffle and reverse steps (and the second encrypt pass) - is to try and propogate any changed bits to a larger set. If only a single - pass was made with the stream cipher in CFB mode, then a change to one byte - may only affect one byte of output, allowing some XOR attacks. - - The shuffle/encrypt is used as above in filename encryption as well, - although it is not necessary as they have checksum bytes which augment the - initial value vector to randomize the output. But it makes the code - simpler to reuse the encryption algorithm as is. -*/ -class SSL_Cipher : public Cipher -{ - Interface iface; - Interface realIface; - const EVP_CIPHER *_blockCipher; - const EVP_CIPHER *_streamCipher; - unsigned int _keySize; // in bytes - unsigned int _ivLength; - -public: - SSL_Cipher(const Interface &iface, const Interface &realIface, - const EVP_CIPHER *blockCipher, const EVP_CIPHER *streamCipher, - int keyLength); - virtual ~SSL_Cipher(); - - // returns the real interface, not the one we're emulating (if any).. - virtual Interface interface() const; - - // create a new key based on a password - virtual CipherKey newKey(const char *password, int passwdLength, - int &iterationCount, long desiredDuration, - const unsigned char *salt, int saltLen); - // deprecated - for backward compatibility - virtual CipherKey newKey(const char *password, int passwdLength); - // create a new random key - virtual CipherKey newRandomKey(); - - // data must be len keySize() - virtual CipherKey readKey(const unsigned char *data, - const CipherKey &encodingKey, - bool checkKey); - virtual void writeKey(const CipherKey &key, unsigned char *data, - const CipherKey &encodingKey); - virtual bool compareKey( const CipherKey &A, - const CipherKey &B ) const; - - // meta-data about the cypher - virtual int keySize() const; - virtual int encodedKeySize() const; - virtual int cipherBlockSize() const; - - virtual bool randomize( unsigned char *buf, int len, - bool strongRandom ) const; - - virtual uint64_t MAC_64( const unsigned char *src, int len, - const CipherKey &key, uint64_t *augment ) const; - - // functional interfaces - /* - Stream encoding in-place. - */ - virtual bool streamEncode(unsigned char *in, int len, - uint64_t iv64, const CipherKey &key) const; - virtual bool streamDecode(unsigned char *in, int len, - uint64_t iv64, const CipherKey &key) const; - - /* - Block encoding is done in-place. Partial blocks are supported, but - blocks are always expected to begin on a block boundary. See - blockSize(). - */ - virtual bool blockEncode(unsigned char *buf, int size, - uint64_t iv64, const CipherKey &key) const; - virtual bool blockDecode(unsigned char *buf, int size, - uint64_t iv64, const CipherKey &key) const; - - // hack to help with static builds - static bool Enabled(); -private: - void setIVec( unsigned char *ivec, uint64_t seed, - const shared_ptr &key ) const; - - // deprecated - for backward compatibility - void setIVec_old( unsigned char *ivec, unsigned int seed, - const shared_ptr &key ) const; -}; - - -#endif - diff --git a/encfs/StreamNameIO.cpp b/encfs/StreamNameIO.cpp deleted file mode 100644 index 8e275de..0000000 --- a/encfs/StreamNameIO.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2004, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include "StreamNameIO.h" - -#include "Cipher.h" -#include "base64.h" - -#include -#include - -#include "i18n.h" -#include - -using namespace std; - -static shared_ptr NewStreamNameIO( const Interface &iface, - const shared_ptr &cipher, const CipherKey &key) -{ - return shared_ptr( new StreamNameIO( iface, cipher, key ) ); -} - -static bool StreamIO_registered = NameIO::Register("Stream", - gettext_noop("Stream encoding, keeps filenames as short as possible"), - StreamNameIO::CurrentInterface(), - NewStreamNameIO); - - -/* - - Version 0.1 is for EncFS 0.x support. The difference to 1.0 is that 0.x - stores the file checksums at the end of the encoded name, where 1.0 - stores them at the beginning. - - - Version 1.0 is the basic stream encoding mode used since the beginning of - EncFS. There is a slight difference in filename encodings from EncFS 0.x - to 1.0.x. This implements just the 1.0.x method. - - - Version 1.1 adds support for IV chaining. This is transparently - backward compatible, since older filesystems do not use IV chaining. - - - Version 2.0 uses full 64 bit IV during IV chaining mode. Prior versions - used only the 16 bit output from MAC_16. This reduces the theoretical - possibility (unlikely to make any difference in practice) of two files - with the same name in different directories ending up with the same - encrypted name. Added because there is no good reason to chop to 16 - bits. - - - Version 2.1 adds support for version 0 for EncFS 0.x compatibility. -*/ -Interface StreamNameIO::CurrentInterface() -{ - // implement major version 2, 1, and 0 - return makeInterface("nameio/stream", 2, 1, 2); -} - -StreamNameIO::StreamNameIO( const Interface &iface, - const shared_ptr &cipher, - const CipherKey &key ) - : _interface( iface.major() ) - , _cipher( cipher ) - , _key( key ) -{ - -} - -StreamNameIO::~StreamNameIO() -{ -} - -Interface StreamNameIO::interface() const -{ - return CurrentInterface(); -} - -int StreamNameIO::maxEncodedNameLen( int plaintextStreamLen ) const -{ - int encodedStreamLen = 2 + plaintextStreamLen; - return B256ToB64Bytes( encodedStreamLen ); -} - -int StreamNameIO::maxDecodedNameLen( int encodedStreamLen ) const -{ - int decLen256 = B64ToB256Bytes( encodedStreamLen ); - return decLen256 - 2; -} - -int StreamNameIO::encodeName( const char *plaintextName, int length, - uint64_t *iv, char *encodedName ) const -{ - uint64_t tmpIV = 0; - if( iv && _interface >= 2 ) - tmpIV = *iv; - - unsigned int mac = _cipher->MAC_16( (const unsigned char *)plaintextName, - length, _key, iv ); - - // add on checksum bytes - unsigned char *encodeBegin; - if(_interface >= 1) - { - // current versions store the checksum at the beginning - encodedName[0] = (mac >> 8) & 0xff; - encodedName[1] = (mac ) & 0xff; - encodeBegin = (unsigned char *)encodedName+2; - } else - { - // encfs 0.x stored checksums at the end. - encodedName[length] = (mac >> 8) & 0xff; - encodedName[length+1] = (mac ) & 0xff; - encodeBegin = (unsigned char *)encodedName; - } - - // stream encode the plaintext bytes - memcpy( encodeBegin, plaintextName, length ); - _cipher->nameEncode( encodeBegin, length, (uint64_t)mac ^ tmpIV, _key); - - // convert the entire thing to base 64 ascii.. - int encodedStreamLen = length + 2; - int encLen64 = B256ToB64Bytes( encodedStreamLen ); - - changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen, - 8, 6, true ); - B64ToAscii( (unsigned char *)encodedName, encLen64 ); - - return encLen64; -} - -int StreamNameIO::decodeName( const char *encodedName, int length, - uint64_t *iv, char *plaintextName ) const -{ - rAssert(length > 2); - int decLen256 = B64ToB256Bytes( length ); - int decodedStreamLen = decLen256 - 2; - - if(decodedStreamLen <= 0) - throw ERROR("Filename too small to decode"); - - BUFFER_INIT( tmpBuf, 32, (unsigned int)length ); - - // decode into tmpBuf, because this step produces more data then we can fit - // into the result buffer.. - AsciiToB64( (unsigned char *)tmpBuf, (unsigned char *)encodedName, length ); - changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false); - - // pull out the checksum value which is used as an initialization vector - uint64_t tmpIV = 0; - unsigned int mac; - if(_interface >= 1) - { - // current versions store the checksum at the beginning - mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 - | ((unsigned int)((unsigned char)tmpBuf[1])); - - // version 2 adds support for IV chaining.. - if( iv && _interface >= 2 ) - tmpIV = *iv; - - memcpy( plaintextName, tmpBuf+2, decodedStreamLen ); - } else - { - // encfs 0.x stored checksums at the end. - mac = ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen])) << 8 - | ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen+1])); - - memcpy( plaintextName, tmpBuf, decodedStreamLen ); - } - - // use nameDeocde instead of streamDecode for backward compatibility - _cipher->nameDecode( (unsigned char *)plaintextName, decodedStreamLen, - (uint64_t)mac ^ tmpIV, _key); - - // compute MAC to check with stored value - unsigned int mac2 = _cipher->MAC_16((const unsigned char *)plaintextName, - decodedStreamLen, _key, iv); - - BUFFER_RESET( tmpBuf ); - if(mac2 != mac) - { - rDebug("checksum mismatch: expected %u, got %u", mac, mac2); - rDebug("on decode of %i bytes", decodedStreamLen); - throw ERROR( "checksum mismatch in filename decode" ); - } - - return decodedStreamLen; -} - -bool StreamNameIO::Enabled() -{ - return true; -} - diff --git a/encfs/docs/Makefile.am b/encfs/docs/Makefile.am deleted file mode 100644 index 271bd41..0000000 --- a/encfs/docs/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -####### kdevelop will overwrite this part!!! (begin)########## - - -####### kdevelop will overwrite this part!!! (end)############ diff --git a/encfs/docs/en/Makefile.am b/encfs/docs/en/Makefile.am deleted file mode 100644 index 271bd41..0000000 --- a/encfs/docs/en/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -####### kdevelop will overwrite this part!!! (begin)########## - - -####### kdevelop will overwrite this part!!! (end)############ diff --git a/encfs/encfs.cpp b/encfs/encfs.cpp deleted file mode 100644 index 69f3dd7..0000000 --- a/encfs/encfs.cpp +++ /dev/null @@ -1,807 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2003-2007, Valient Gough - * - * This program is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#include "encfs.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#ifdef linux -#include -#endif - -#ifdef HAVE_ATTR_XATTR_H -#include -#elif HAVE_SYS_XATTR_H -#include -#endif - - -#include -#include - -#if HAVE_TR1_TUPLE -#include -using namespace std; -using namespace std::tr1; -#else -#include -using namespace std; -#endif - -#include "DirNode.h" -#include "MemoryPool.h" -#include "FileUtils.h" -#include "Mutex.h" -#include "Context.h" -#include "shared_ptr.h" - -#include -#include - -#ifndef MIN -#define MIN(a,b) (((a)<(b)) ? (a): (b)) -#endif - -#define ESUCCESS 0 - -using namespace rlog; -using rel::Lock; - -#define GET_FN(ctx, finfo) ctx->getNode((void*)(uintptr_t)finfo->fh) - -static RLogChannel *Info = DEF_CHANNEL("info", Log_Info); - -static EncFS_Context * context() -{ - return (EncFS_Context*)fuse_get_context()->private_data; -} - -// helper function -- apply a functor to a cipher path, given the plain path -template -static int withCipherPath( const char *opName, const char *path, - int (*op)(EncFS_Context *, const string &name, T data ), T data, - bool passReturnCode = false ) -{ - EncFS_Context *ctx = context(); - - int res = -EIO; - shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; - - try - { - string cyName = FSRoot->cipherPath( path ); - rLog(Info, "%s %s", opName, cyName.c_str()); - - res = op( ctx, cyName, data ); - - if(res == -1) - { - int eno = errno; - rInfo("%s error: %s", opName, strerror(eno)); - res = -eno; - } else if(!passReturnCode) - res = ESUCCESS; - } catch( rlog::Error &err ) - { - rError("error caught in %s", opName); - err.log( _RLWarningChannel ); - } - return res; -} - -// helper function -- apply a functor to a node -template -static int withFileNode( const char *opName, - const char *path, struct fuse_file_info *fi, - int (*op)(FileNode *, T data ), T data ) -{ - EncFS_Context *ctx = context(); - - int res = -EIO; - shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; - - try - { - shared_ptr fnode; - - if(fi != NULL) - fnode = GET_FN(ctx, fi); - else - fnode = FSRoot->lookupNode( path, opName ); - - rAssert(fnode != NULL); - rLog(Info, "%s %s", opName, fnode->cipherName()); - res = op( fnode.get(), data ); - - if(res < 0) - rInfo("%s error: %s", opName, strerror(-res)); - } catch( rlog::Error &err ) - { - rError("error caught in %s", opName); - err.log( _RLWarningChannel ); - } - return res; -} - -/* - The rLog messages below always print out encrypted filenames, not - plaintext. The reason is so that it isn't possible to leak information - about the encrypted data through rlog interfaces. - - - The purpose of this layer of code is to take the FUSE request and dispatch - to the internal interfaces. Any marshaling of arguments and return types - can be done here. -*/ - -int _do_getattr(FileNode *fnode, struct stat *stbuf) -{ - int res = fnode->getAttr(stbuf); - if(res == ESUCCESS && S_ISLNK(stbuf->st_mode)) - { - EncFS_Context *ctx = context(); - shared_ptr FSRoot = ctx->getRoot(&res); - if(FSRoot) - { - // determine plaintext link size.. Easiest to read and decrypt.. - vector buf(stbuf->st_size+1, 0); - - res = ::readlink( fnode->cipherName(), &buf[0], stbuf->st_size ); - if(res >= 0) - { - // other functions expect c-strings to be null-terminated, which - // readlink doesn't provide - buf[res] = '\0'; - - stbuf->st_size = FSRoot->plainPath( &buf[0] ).length(); - - res = ESUCCESS; - } else - res = -errno; - } - } - - return res; -} - -int encfs_getattr(const char *path, struct stat *stbuf) -{ - return withFileNode( "getattr", path, NULL, _do_getattr, stbuf ); -} - -int encfs_fgetattr(const char *path, struct stat *stbuf, - struct fuse_file_info *fi) -{ - return withFileNode( "fgetattr", path, fi, _do_getattr, stbuf ); -} - -int encfs_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler) -{ - EncFS_Context *ctx = context(); - - int res = ESUCCESS; - shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; - - try - { - - DirTraverse dt = FSRoot->openDir( path ); - - rLog(Info, "getdir on %s", FSRoot->cipherPath(path).c_str()); - - if(dt.valid()) - { - int fileType = 0; - ino_t inode = 0; - - std::string name = dt.nextPlaintextName( &fileType, &inode ); - while( !name.empty() ) - { - res = filler( h, name.c_str(), fileType, inode ); - - if(res != ESUCCESS) - break; - - name = dt.nextPlaintextName( &fileType, &inode ); - } - } else - { - rInfo("getdir request invalid, path: '%s'", path); - } - - return res; - } catch( rlog::Error &err ) - { - rError("Error caught in getdir"); - err.log( _RLWarningChannel ); - return -EIO; - } -} - -int encfs_mknod(const char *path, mode_t mode, dev_t rdev) -{ - EncFS_Context *ctx = context(); - - int res = -EIO; - shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; - - try - { - shared_ptr fnode = FSRoot->lookupNode( path, "mknod" ); - - rLog(Info, "mknod on %s, mode %i, dev %" PRIi64, - fnode->cipherName(), mode, (int64_t)rdev); - - uid_t uid = 0; - gid_t gid = 0; - if(ctx->publicFilesystem) - { - fuse_context *context = fuse_get_context(); - uid = context->uid; - gid = context->gid; - } - res = fnode->mknod( mode, rdev, uid, gid ); - // Is this error due to access problems? - if(ctx->publicFilesystem && -res == EACCES) - { - // try again using the parent dir's group - string parent = fnode->plaintextParent(); - rInfo("trying public filesystem workaround for %s", parent.c_str()); - shared_ptr dnode = - FSRoot->lookupNode( parent.c_str(), "mknod" ); - - struct stat st; - if(dnode->getAttr( &st ) == 0) - res = fnode->mknod( mode, rdev, uid, st.st_gid ); - } - } catch( rlog::Error &err ) - { - rError("error caught in mknod"); - err.log( _RLWarningChannel ); - } - return res; -} - -int encfs_mkdir(const char *path, mode_t mode) -{ - fuse_context *fctx = fuse_get_context(); - EncFS_Context *ctx = context(); - - int res = -EIO; - shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; - - try - { - uid_t uid = 0; - gid_t gid = 0; - if(ctx->publicFilesystem) - { - uid = fctx->uid; - gid = fctx->gid; - } - res = FSRoot->mkdir( path, mode, uid, gid ); - // Is this error due to access problems? - if(ctx->publicFilesystem && -res == EACCES) - { - // try again using the parent dir's group - string parent = parentDirectory( path ); - shared_ptr dnode = - FSRoot->lookupNode( parent.c_str(), "mkdir" ); - - struct stat st; - if(dnode->getAttr( &st ) == 0) - res = FSRoot->mkdir( path, mode, uid, st.st_gid ); - } - } catch( rlog::Error &err ) - { - rError("error caught in mkdir"); - err.log( _RLWarningChannel ); - } - return res; -} - -int encfs_unlink(const char *path) -{ - EncFS_Context *ctx = context(); - - int res = -EIO; - shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; - - try - { - // let DirNode handle it atomically so that it can handle race - // conditions - res = FSRoot->unlink( path ); - } catch( rlog::Error &err ) - { - rError("error caught in unlink"); - err.log( _RLWarningChannel ); - } - return res; -} - - -int _do_rmdir(EncFS_Context *, const string &cipherPath, int ) -{ - return rmdir( cipherPath.c_str() ); -} - -int encfs_rmdir(const char *path) -{ - return withCipherPath( "rmdir", path, _do_rmdir, 0 ); -} - -int _do_readlink(EncFS_Context *ctx, const string &cyName, - tuple data ) -{ - char *buf = get<0>(data); - size_t size = get<1>(data); - - int res = ESUCCESS; - shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; - - res = ::readlink( cyName.c_str(), buf, size-1 ); - - if(res == -1) - return -errno; - - buf[res] = '\0'; // ensure null termination - string decodedName; - try - { - decodedName = FSRoot->plainPath( buf ); - } catch(...) { } - - if(!decodedName.empty()) - { - strncpy(buf, decodedName.c_str(), size-1); - buf[size-1] = '\0'; - - return ESUCCESS; - } else - { - rWarning("Error decoding link"); - return -1; - } -} - -int encfs_readlink(const char *path, char *buf, size_t size) -{ - return withCipherPath( "readlink", path, _do_readlink, - make_tuple(buf, size) ); -} - -int encfs_symlink(const char *from, const char *to) -{ - EncFS_Context *ctx = context(); - - int res = -EIO; - shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; - - try - { - // allow fully qualified names in symbolic links. - string fromCName = FSRoot->relativeCipherPath( from ); - string toCName = FSRoot->cipherPath( to ); - - rLog(Info, "symlink %s -> %s", fromCName.c_str(), toCName.c_str()); - - // use setfsuid / setfsgid so that the new link will be owned by the - // uid/gid provided by the fuse_context. - int olduid = -1; - int oldgid = -1; - if(ctx->publicFilesystem) - { - fuse_context *context = fuse_get_context(); - olduid = setfsuid( context->uid ); - oldgid = setfsgid( context->gid ); - } - res = ::symlink( fromCName.c_str(), toCName.c_str() ); - if(olduid >= 0) - setfsuid( olduid ); - if(oldgid >= 0) - setfsgid( oldgid ); - - if(res == -1) - res = -errno; - else - res = ESUCCESS; - } catch( rlog::Error &err ) - { - rError("error caught in symlink"); - err.log( _RLWarningChannel ); - } - return res; -} - -int encfs_link(const char *from, const char *to) -{ - EncFS_Context *ctx = context(); - - int res = -EIO; - shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; - - try - { - res = FSRoot->link( from, to ); - } catch( rlog::Error &err ) - { - rError("error caught in link"); - err.log( _RLWarningChannel ); - } - return res; -} - -int encfs_rename(const char *from, const char *to) -{ - EncFS_Context *ctx = context(); - - int res = -EIO; - shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; - - try - { - res = FSRoot->rename( from, to ); - } catch( rlog::Error &err ) - { - rError("error caught in rename"); - err.log( _RLWarningChannel ); - } - return res; -} - -int _do_chmod(EncFS_Context *, const string &cipherPath, mode_t mode) -{ - return chmod( cipherPath.c_str(), mode ); -} - -int encfs_chmod(const char *path, mode_t mode) -{ - return withCipherPath( "chmod", path, _do_chmod, mode ); -} - -int _do_chown(EncFS_Context *, const string &cyName, - tuple data) -{ - int res = lchown( cyName.c_str(), get<0>(data), get<1>(data) ); - return (res == -1) ? -errno : ESUCCESS; -} - -int encfs_chown(const char *path, uid_t uid, gid_t gid) -{ - return withCipherPath( "chown", path, _do_chown, make_tuple(uid, gid)); -} - -int _do_truncate( FileNode *fnode, off_t size ) -{ - return fnode->truncate( size ); -} - -int encfs_truncate(const char *path, off_t size) -{ - return withFileNode( "truncate", path, NULL, _do_truncate, size ); -} - -int encfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi) -{ - return withFileNode( "ftruncate", path, fi, _do_truncate, size ); -} - -int _do_utime(EncFS_Context *, const string &cyName, struct utimbuf *buf) -{ - int res = utime( cyName.c_str(), buf); - return (res == -1) ? -errno : ESUCCESS; -} - -int encfs_utime(const char *path, struct utimbuf *buf) -{ - return withCipherPath( "utime", path, _do_utime, buf ); -} - -int _do_utimens(EncFS_Context *, const string &cyName, - const struct timespec ts[2]) -{ - struct timeval tv[2]; - tv[0].tv_sec = ts[0].tv_sec; - tv[0].tv_usec = ts[0].tv_nsec / 1000; - tv[1].tv_sec = ts[1].tv_sec; - tv[1].tv_usec = ts[1].tv_nsec / 1000; - - int res = lutimes( cyName.c_str(), tv); - return (res == -1) ? -errno : ESUCCESS; -} - -int encfs_utimens(const char *path, const struct timespec ts[2] ) -{ - return withCipherPath( "utimens", path, _do_utimens, ts ); -} - -int encfs_open(const char *path, struct fuse_file_info *file) -{ - EncFS_Context *ctx = context(); - - int res = -EIO; - shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; - - try - { - shared_ptr fnode = - FSRoot->openNode( path, "open", file->flags, &res ); - - if(fnode) - { - rLog(Info, "encfs_open for %s, flags %i", fnode->cipherName(), - file->flags); - - if( res >= 0 ) - { - file->fh = (uintptr_t)ctx->putNode(path, fnode); - res = ESUCCESS; - } - } - } catch( rlog::Error &err ) - { - rError("error caught in open"); - err.log( _RLWarningChannel ); - } - - return res; -} - -int _do_flush(FileNode *fnode, int ) -{ - /* Flush can be called multiple times for an open file, so it doesn't - close the file. However it is important to call close() for some - underlying filesystems (like NFS). - */ - int res = fnode->open( O_RDONLY ); - if(res >= 0) - { - int fh = res; - res = close(dup(fh)); - if(res == -1) - res = -errno; - } - - return res; -} - -int encfs_flush(const char *path, struct fuse_file_info *fi) -{ - return withFileNode( "flush", path, fi, _do_flush, 0 ); -} - -/* -Note: This is advisory -- it might benefit us to keep file nodes around for a -bit after they are released just in case they are reopened soon. But that -requires a cache layer. - */ -int encfs_release(const char *path, struct fuse_file_info *finfo) -{ - EncFS_Context *ctx = context(); - - try - { - ctx->eraseNode( path, (void*)(uintptr_t)finfo->fh ); - return ESUCCESS; - } catch( rlog::Error &err ) - { - rError("error caught in release"); - err.log( _RLWarningChannel ); - return -EIO; - } -} - -int _do_read(FileNode *fnode, tuple data) -{ - return fnode->read( get<2>(data), get<0>(data), get<1>(data)); -} - -int encfs_read(const char *path, char *buf, size_t size, off_t offset, - struct fuse_file_info *file) -{ - return withFileNode( "read", path, file, _do_read, - make_tuple((unsigned char *)buf, size, offset)); -} - -int _do_fsync(FileNode *fnode, int dataSync) -{ - return fnode->sync( dataSync != 0 ); -} - -int encfs_fsync(const char *path, int dataSync, - struct fuse_file_info *file) -{ - return withFileNode( "fsync", path, file, _do_fsync, dataSync ); -} - -int _do_write(FileNode *fnode, tuple data) -{ - size_t size = get<1>(data); - if(fnode->write( get<2>(data), (unsigned char *)get<0>(data), size )) - return size; - else - return -EIO; -} - -int encfs_write(const char *path, const char *buf, size_t size, - off_t offset, struct fuse_file_info *file) -{ - return withFileNode("write", path, file, _do_write, - make_tuple(buf, size, offset)); -} - -// statfs works even if encfs is detached.. -int encfs_statfs(const char *path, struct statvfs *st) -{ - EncFS_Context *ctx = context(); - - int res = -EIO; - try - { - (void)path; // path should always be '/' for now.. - rAssert( st != NULL ); - string cyName = ctx->rootCipherDir; - - rLog(Info, "doing statfs of %s", cyName.c_str()); - res = statvfs( cyName.c_str(), st ); - if(!res) - { - // adjust maximum name length.. - st->f_namemax = 6 * (st->f_namemax - 2) / 8; // approx.. - } - if(res == -1) - res = -errno; - } catch( rlog::Error &err ) - { - rError("error caught in statfs"); - err.log( _RLWarningChannel ); - } - return res; -} - -#ifdef HAVE_XATTR - - -#ifdef XATTR_ADD_OPT -int _do_setxattr(EncFS_Context *, const string &cyName, - tuple data) -{ - int options = 0; - return ::setxattr( cyName.c_str(), get<0>(data), get<1>(data), - get<2>(data), get<3>(data), options ); -} -int encfs_setxattr( const char *path, const char *name, - const char *value, size_t size, int flags, uint32_t position ) -{ - (void)flags; - return withCipherPath( "setxattr", path, _do_setxattr, - make_tuple(name, value, size, position) ); -} -#else -int _do_setxattr(EncFS_Context *, const string &cyName, - tuple data) -{ - return ::setxattr( cyName.c_str(), get<0>(data), get<1>(data), - get<2>(data), get<3>(data) ); -} -int encfs_setxattr( const char *path, const char *name, - const char *value, size_t size, int flags ) -{ - return withCipherPath( "setxattr", path, _do_setxattr, - make_tuple(name, value, size, flags) ); -} -#endif - - -#ifdef XATTR_ADD_OPT -int _do_getxattr(EncFS_Context *, const string &cyName, - tuple data) -{ - int options = 0; - return ::getxattr( cyName.c_str(), get<0>(data), - get<1>(data), get<2>(data), get<3>(data), options ); -} -int encfs_getxattr( const char *path, const char *name, - char *value, size_t size, uint32_t position ) -{ - return withCipherPath( "getxattr", path, _do_getxattr, - make_tuple(name, (void *)value, size, position), true ); -} -#else -int _do_getxattr(EncFS_Context *, const string &cyName, - tuple data) -{ - return ::getxattr( cyName.c_str(), get<0>(data), - get<1>(data), get<2>(data)); -} -int encfs_getxattr( const char *path, const char *name, - char *value, size_t size ) -{ - return withCipherPath( "getxattr", path, _do_getxattr, - make_tuple(name, (void *)value, size), true ); -} -#endif - - -int _do_listxattr(EncFS_Context *, const string &cyName, - tuple data) -{ -#ifdef XATTR_ADD_OPT - int options = 0; - int res = ::listxattr( cyName.c_str(), get<0>(data), get<1>(data), - options ); -#else - int res = ::listxattr( cyName.c_str(), get<0>(data), get<1>(data) ); -#endif - return (res == -1) ? -errno : res; -} - -int encfs_listxattr( const char *path, char *list, size_t size ) -{ - return withCipherPath( "listxattr", path, _do_listxattr, - make_tuple(list, size), true ); -} - -int _do_removexattr(EncFS_Context *, const string &cyName, const char *name) -{ -#ifdef XATTR_ADD_OPT - int options = 0; - int res = ::removexattr( cyName.c_str(), name, options ); -#else - int res = ::removexattr( cyName.c_str(), name ); -#endif - return (res == -1) ? -errno : res; -} - -int encfs_removexattr( const char *path, const char *name ) -{ - return withCipherPath( "removexattr", path, _do_removexattr, name ); -} - -#endif // HAVE_XATTR - diff --git a/encfs/encfs.pod b/encfs/encfs.pod index d519366..3807d2f 100644 --- a/encfs/encfs.pod +++ b/encfs/encfs.pod @@ -1,12 +1,3 @@ -=cut -Copyright (c) 2003-2008, Valient Gough -All rights reserved. - -EncFS is free software; you can distribute it and/or modify it under the terms -of the GNU General Public License (GPL), as published by the Free Software -Foundation; either version 3 of the License, or (at your option) any later -version. - =pod =head1 NAME @@ -174,9 +165,8 @@ the B help page for information on available commands. =item B<--no-default-flags> B adds the FUSE flags "use_ino" and "default_permissions" by default, as -of version 1.2.2, because that improves compatibility with some programs.. If -for some reason you need to disable one or both of these flags, use the option -B<--no-default-flags>. +that improves compatibility with some programs.. If you need to disable one or +both of these flags, use the option B<--no-default-flags>. The following command lines produce the same result: @@ -196,10 +186,6 @@ for a trailing newline (\n) which will be removed. For example, specifying B<--extpass>=I will cause B to use ssh's password prompt program. -B: B reads at most 2k of data from the password program, and it -removes any trailing newline. Versions before 1.4.x accepted only 64 bytes of -text. - =item B<-S>, B<--stdinpass> Read password from standard input, without prompting. This may be useful for @@ -209,6 +195,10 @@ Note that you should make sure the filesystem and mount points exist first. Otherwise encfs will prompt for the filesystem creation options, which may interfere with your script. +B: B reads a limited amount of data from the console (roughly 2k +bytes), and it removes any trailing newline. If your password is larger than +this, use --extpass. + =item B<--anykey> Turn off key validation checking. This allows B to be used with @@ -275,10 +265,10 @@ to decode filenames if desired. =head1 CAVEATS B is not a true filesystem. It does not deal with any of the actual -storage or maintenance of files. It simply translates requests (encrypting or +storage or maintenance of files. It translates requests (encrypting or decrypting as necessary) and passes the requests through to the underlying -host filesystem. Therefor any limitations of the host filesystem will likely -be inherited by B (or possibly be further limited). +host filesystem. Therefor any limitations of the host filesystem will be +inherited by B (or possibly be further limited). One such limitation is filename length. If your underlying filesystem limits you to N characters in a filename, then B will limit you to approximately @@ -328,20 +318,20 @@ they mean: =head1 Key Derivation Function -As of version 1.5, B now uses PBKDF2 as the default key derivation -function. The number of iterations in the keying function is selected based on -wall clock time to generate the key. In standard mode, a target time of 0.5 -seconds is used, and in paranoia mode a target of 3.0 seconds is used. +B uses PBKDF2 as the key derivation function. The number of iterations +in the keying function is selected based on wall clock time to generate the +key. In standard mode, a target time of 0.5 seconds is used, and in paranoia +mode a target of 3.0 seconds is used. On a 1.6Ghz AMD 64 system, it rougly 64k iterations of the key derivation function can be handled in half a second. The exact number of iterations to use is stored in the configuration file, as it is needed to remount the filesystem. -If an B filesystem configuration from 1.4.x is modified with version 1.5 -(such as when using encfsctl to change the password), then the new PBKDF2 -function will be used and the filesystem will no longer be readable by older -versions. +If an B filesystem configuration from 1.4.x is modified with a later +version (such as when using encfsctl to change the password), then the new +PBKDF2 function will be used and the filesystem will no longer be readable by +older versions. =over 4 @@ -375,18 +365,16 @@ read and decoded, so a large block size adds overhead to small requests. With write calls it is even worse, as a block must be read and decoded, the change applied and the block encoded and written back out. -The default is 512 bytes as of version 1.0. It was hard coded to 64 bytes in -version 0.x, which was not as efficient as the current setting for general -usage. +The default block size is currently 2k. =item I -B. A choice is given between stream encoding of filename and block -encoding. The advantage of stream encoding is that the encoded filenames will -be as short as possible. If you have a filename with a single letter, it will -be very short in the encoded form, where as block encoded filenames are always -rounded up to the block size of the encryption cipher (8 bytes for Blowfish and -16 bytes for AES). +A choice is given between stream encoding of filename and block encoding. The +advantage of stream encoding is that the encoded filenames will be as short as +possible. If you have a filename with a single letter, it will be very short +in the encoded form, where as block encoded filenames are always rounded up to +the block size of the encryption cipher (8 bytes for Blowfish and 16 bytes for +AES). The advantage of block encoding mode is that filename lenths all come out as a multiple of the cipher block size. This means that someone looking at your @@ -395,16 +383,14 @@ on by default, as it takes a similar amount of time to using the stream cipher. However stream cipher mode may be useful if you want shorter encrypted filenames for some reason. -Prior to version 1.1, only stream encoding was supported. - =item I -B. In previous versions of B, each filename element in -a path was encoded separately. So if "foo" encoded to "XXX", then it would -always encode that way (given the same encryption key), no matter if the path -was "a/b/foo", or "aa/foo/cc", etc. That meant it was possible for someone -looking at the encrypted data to see if two files in different directories had -the same name, even though they wouldn't know what that name decoded to. +In previous versions of B, each filename element in a path was encoded +separately. So if "foo" encoded to "XXX", then it would always encode that way +(given the same encryption key), no matter if the path was "a/b/foo", or +"aa/foo/cc", etc. That meant it was possible for someone looking at the +encrypted data to see if two files in different directories had the same name, +even though they wouldn't know what that name decoded to. With initialization vector chaining, each directory gets its own initialization vector. So "a/foo" and "b/foo" will have completely different encoded names @@ -422,11 +408,11 @@ rename will fail. =item I -B. In previous versions of B, each file was encoded in the -same way. Each block in a file has always had its own initialization vector, -but in a deterministic way so that block N in one file is encoded in the same -was as block N in another file. That made it possible for someone to tell if -two files were identical (or parts of the file were identical) by comparing the +In previous versions of B, each file was encoded in the same way. Each +block in a file has always had its own initialization vector, but in a +deterministic way so that block N in one file is encoded in the same was as +block N in another file. That made it possible for someone to tell if two +files were identical (or parts of the file were identical) by comparing the encoded data. With per-file initialization vectors, each file gets its own 64bit random @@ -436,10 +422,9 @@ This option is enabled by default. =item I -B. This option is closely related to Per-File Initialization -Vectors and Filename Initialization Vector Chaining. Basically it extends the -initialization vector chaining from filenames to the per-file initialization -vector. +This option is closely related to Per-File Initialization Vectors and Filename +Initialization Vector Chaining. Basically it extends the initialization vector +chaining from filenames to the per-file initialization vector. When this option is enabled, the per-file initialization vector is encoded using the initialization vector derived from the filename initialization vector @@ -461,11 +446,11 @@ Because of these limits, this option is disabled by default for standard mode =item I -B. If this is enabled, every block in every file is stored along -with a cryptographic checksum (Message Authentication Code). This makes it -virtually impossible to modify a file without the change being detected by -B. B will refuse to read data which does not pass the checksum, -and will log the error and return an IO error to the application. +If this is enabled, every block in every file is stored along with a +cryptographic checksum (Message Authentication Code). This makes it virtually +impossible to modify a file without the change being detected by B. +B will refuse to read data which does not pass the checksum, and will +log the error and return an IO error to the application. This adds substantial overhead (default being 8 bytes per filesystem block), plus computational overhead, and is not enabled by default except in paranoia @@ -498,28 +483,6 @@ filesystem contents along with the algorithms B supports to thwart them: =over 4 -=item B: modifying a few bytes of an encrypted file (without knowing -what they will decode to). - -B does not use any form of XOR encryption which would allow -single bytes to be modified without affecting others. Most modifications -would affect dozens or more bytes. Additionally, MAC Block headers can be -used to identify any changes to files. - -=item B: copying a random block of one file to a random block of another file. - -Each block has its own [deterministic] initialization vector. - -=item B: copying block N to block N of another file. - -When the Per-File Initialization Vector support is enabled (default -in 1.1.x filesystems), a copied block will not decode properly when copied to -another file. - -=item B: copying an entire file to another file. - -Can be prevented by enabling External IV Chaining mode. - =item B: determine if two filenames are the same by looking at encrypted names. Filename Initialization Vector chaining prevents this by giving each file a @@ -529,8 +492,39 @@ Filename Initialization Vector chaining prevents this by giving each file a Per-File Initialization Vector support prevents this. +=item B: copying an entire file to another file. + +Can be prevented by enabling External IV Chaining mode. + +=item B: copying a random block of one file to a random block of another file. + +Each block has its own [deterministic] initialization vector. + +=item B: copying block N to block N of another file. + +When the Per-File Initialization Vector support is enabled (the default), a +copied block will not decode properly when copied to another file. + +=item B: modifying a few bytes of an encrypted file (without knowing +what they will decode to). + +B does not use any form of XOR encryption which would allow +single bytes to be modified without affecting others. Most modifications +would affect dozens or more bytes. Additionally, MAC Block headers can be +used to identify any changes to files. + =back +=head1 LICENSE + +EncFS is free software; you can distribute it and/or modify it under the terms +of the GNU General Public License (GPL), as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +The library portion of EncFS is licensed under the LGPL version 3. See the +COPYING files in the source distribution for details. + =head1 DISCLAIMER This library is distributed in the hope that it will be useful, but WITHOUT ANY diff --git a/encfs/encfsctl.cpp b/encfs/encfsctl.cpp deleted file mode 100644 index c208769..0000000 --- a/encfs/encfsctl.cpp +++ /dev/null @@ -1,853 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2004, Valient Gough - * - * This program is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - - -#include "encfs.h" - -#include "autosprintf.h" -#include "config.h" - -#include "FileUtils.h" -#include "Cipher.h" - -#include "Context.h" -#include "FileNode.h" -#include "DirNode.h" - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#ifdef __FreeBSD__ -#include -#endif - -#include "i18n.h" - -#ifdef HAVE_SSL -#define NO_DES -#include -#endif - -using namespace rlog; -using namespace std; -using namespace gnu; - - -static int showInfo( int argc, char **argv ); -static int showVersion( int argc, char **argv ); -static int chpasswd( int argc, char **argv ); -static int chpasswdAutomaticly( int argc, char **argv ); -static int cmd_ls( int argc, char **argv ); -static int cmd_decode( int argc, char **argv ); -static int cmd_encode( int argc, char **argv ); -static int cmd_showcruft( int argc, char **argv ); -static int cmd_cat( int argc, char **argv ); -static int cmd_export( int argc, char **argv ); -static int cmd_showKey( int argc, char **argv ); - -struct CommandOpts -{ - const char *name; - int minOptions; - int maxOptions; - int (*func)(int argc, char **argv); - const char *argStr; - const char *usageStr; -} commands[] = -{ - {"info", 1, 1, showInfo, "(root dir)", - // xgroup(usage) - gettext_noop(" -- show information (Default command)")}, - {"showKey", 1, 1, cmd_showKey, "(root dir)", - // xgroup(usage) - gettext_noop(" -- show key")}, - {"passwd", 1, 1, chpasswd, "(root dir)", - // xgroup(usage) - gettext_noop(" -- change password for volume")}, - {"autopasswd", 1, 1, chpasswdAutomaticly, "(root dir)", - // xgroup(usage) - gettext_noop(" -- change password for volume, taking password" - " from standard input.\n\tNo prompts are issued.")}, - {"ls", 1, 2, cmd_ls, 0,0}, - {"showcruft", 1, 1, cmd_showcruft, "(root dir)", - // xgroup(usage) - gettext_noop(" -- show undecodable filenames in the volume")}, - {"cat", 2, 2, cmd_cat, "(root dir) path", - // xgroup(usage) - gettext_noop(" -- decodes the file and cats it to standard out")}, - {"decode", 1, 100, cmd_decode, "[--extpass=prog] (root dir) [encoded-name ...]", - // xgroup(usage) - gettext_noop(" -- decodes name and prints plaintext version")}, - {"encode", 1, 100, cmd_encode, "[--extpass=prog] (root dir) [plaintext-name ...]", - // xgroup(usage) - gettext_noop(" -- encodes a filename and print result")}, - {"export", 2, 2, cmd_export, "(root dir) path", - // xgroup(usage) - gettext_noop(" -- decrypts a volume and writes results to path")}, - {"--version", 0, 0, showVersion, "", - // xgroup(usage) - gettext_noop(" -- print version number and exit")}, - {0,0,0,0,0,0} -}; - - - -static -void usage(const char *name) -{ - cerr << autosprintf(_("encfsctl version %s"), VERSION) << "\n" - << _("Usage:\n") - // displays usage commands, eg "./encfs (root dir) ..." - // xgroup(usage) - << autosprintf(_("%s (root dir)\n" - " -- displays information about the filesystem, or \n"), name); - - int offset = 0; - while(commands[offset].name != 0) - { - if( commands[offset].argStr != 0 ) - { - cerr << "encfsctl " << commands[offset].name << " " - << commands[offset].argStr << "\n" - << gettext( commands[offset].usageStr ) << "\n"; - } - ++offset; - } - - cerr << "\n" - // xgroup(usage) - << autosprintf(_("Example: \n%s info ~/.crypt\n"), name) - << "\n"; -} - -static bool checkDir( string &rootDir ) -{ - if( !isDirectory( rootDir.c_str() )) - { - cerr << autosprintf(_("directory %s does not exist.\n"), - rootDir.c_str()); - return false; - } - if(rootDir[ rootDir.length()-1 ] != '/') - rootDir.append("/"); - - return true; -} - -static int showVersion( int argc, char **argv ) -{ - (void)argc; - (void)argv; - // xgroup(usage) - cerr << autosprintf(_("encfsctl version %s"), VERSION) << "\n"; - - return EXIT_SUCCESS; -} - -static int showInfo( int argc, char **argv ) -{ - (void)argc; - string rootDir = argv[1]; - if( !checkDir( rootDir )) - return EXIT_FAILURE; - - EncfsConfig config; - ConfigType type = readConfig( rootDir, config ); - - // show information stored in config.. - switch(type) - { - case Config_None: - // xgroup(diag) - cout << _("Unable to load or parse config file\n"); - return EXIT_FAILURE; - case Config_Prehistoric: - // xgroup(diag) - cout << _("A really old EncFS filesystem was found. \n" - "It is not supported in this EncFS build.\n"); - return EXIT_FAILURE; - case Config_V3: - // xgroup(diag) - cout << "\n" << autosprintf(_("Version 3 configuration; " - "created by %s\n"), config.creator().c_str()); - break; - case Config_V4: - // xgroup(diag) - cout << "\n" << autosprintf(_("Version 4 configuration; " - "created by %s\n"), config.creator().c_str()); - break; - case Config_V5: - case Config_V6: - case Config_V7: - // xgroup(diag) - cout << "\n" << autosprintf(_("Version %i configuration; " - "created by %s (revision %i)\n"), - type, - config.creator().c_str(), - config.revision()); - break; - } - - showFSInfo( config ); - - return EXIT_SUCCESS; -} - -static RootPtr initRootInfo(int &argc, char ** &argv) -{ - RootPtr result; - shared_ptr opts( new EncFS_Opts() ); - opts->createIfNotFound = false; - opts->checkKey = false; - - static struct option long_options[] = { - {"extpass", 1, 0, 'p'}, - {0,0,0,0} - }; - - for(;;) - { - int option_index = 0; - - int res = getopt_long( argc, argv, "", - long_options, &option_index); - if(res == -1) - break; - - switch(res) - { - case 'p': - opts->passwordProgram.assign(optarg); - break; - default: - rWarning(_("getopt error: %i"), res); - break; - } - } - - argc -= optind; - argv += optind; - - if(argc == 0) - { - cerr << _("Incorrect number of arguments") << "\n"; - } else - { - opts->rootDir = string( argv[0] ); - - --argc; - ++argv; - - if(checkDir( opts->rootDir )) - result = initFS( NULL, opts ); - - if(!result) - cerr << _("Unable to initialize encrypted filesystem - check path.\n"); - } - - return result; -} - -static RootPtr initRootInfo(const char* crootDir) -{ - string rootDir(crootDir); - RootPtr result; - - if(checkDir( rootDir )) - { - shared_ptr opts( new EncFS_Opts() ); - opts->rootDir = rootDir; - opts->createIfNotFound = false; - opts->checkKey = false; - result = initFS( NULL, opts ); - } - - if(!result) - cerr << _("Unable to initialize encrypted filesystem - check path.\n"); - - return result; -} - -static int cmd_showKey( int argc, char **argv ) -{ - RootPtr rootInfo = initRootInfo(argv[1]); - - if(!rootInfo) - return EXIT_FAILURE; - else - { - // encode with itself - string b64Key = rootInfo->cipher->encodeAsString( - rootInfo->volumeKey, rootInfo->volumeKey ); - - cout << b64Key << "\n"; - - return EXIT_SUCCESS; - } -} - -static int cmd_decode( int argc, char **argv ) -{ - RootPtr rootInfo = initRootInfo(argc, argv); - if(!rootInfo) - return EXIT_FAILURE; - - if(argc > 0) - { - for(int i=0; iroot->plainPath( argv[i] ); - cout << name << "\n"; - } - } else - { - char buf[PATH_MAX+1]; - while(cin.getline(buf,PATH_MAX)) - { - cout << rootInfo->root->plainPath( buf ) << "\n"; - } - } - return EXIT_SUCCESS; -} - -static int cmd_encode( int argc, char **argv ) -{ - RootPtr rootInfo = initRootInfo(argc, argv); - if(!rootInfo) - return EXIT_FAILURE; - - if(argc > 0) - { - for(int i=0; iroot->cipherPathWithoutRoot(argv[i]); - cout << name << "\n"; - } - } else - { - char buf[PATH_MAX+1]; - while(cin.getline(buf,PATH_MAX)) - { - cout << rootInfo->root->cipherPathWithoutRoot( buf ) << "\n"; - } - } - return EXIT_SUCCESS; -} - -static int cmd_ls( int argc, char **argv ) -{ - (void)argc; - - RootPtr rootInfo = initRootInfo(argv[1]); - - if(!rootInfo) - return EXIT_FAILURE; - - // show files in directory - { - DirTraverse dt = rootInfo->root->openDir("/"); - if(dt.valid()) - { - for(string name = dt.nextPlaintextName(); !name.empty(); - name = dt.nextPlaintextName()) - { - shared_ptr fnode = - rootInfo->root->lookupNode( name.c_str(), "encfsctl-ls" ); - struct stat stbuf; - fnode->getAttr( &stbuf ); - - struct tm stm; - localtime_r( &stbuf.st_mtime, &stm ); - stm.tm_year += 1900; - // TODO: when I add "%s" to the end and name.c_str(), I get a - // seg fault from within strlen. Why ??? - printf("%11i %4i-%02i-%02i %02i:%02i:%02i %s\n", - int(stbuf.st_size), - int(stm.tm_year), int(stm.tm_mon), int(stm.tm_mday), - int(stm.tm_hour), int(stm.tm_min), int(stm.tm_sec), - name.c_str()); - } - } - } - - return EXIT_SUCCESS; -} - -// apply an operation to every block in the file -template -int processContents( const shared_ptr &rootInfo, - const char *path, T &op ) -{ - int errCode = 0; - shared_ptr node = rootInfo->root->openNode( path, "encfsctl", - O_RDONLY, &errCode ); - - if(!node) - { - // try treating filename as an enciphered path - string plainName = rootInfo->root->plainPath( path ); - node = rootInfo->root->lookupNode( plainName.c_str(), "encfsctl" ); - if(node) - { - errCode = node->open( O_RDONLY ); - if(errCode < 0) - node.reset(); - } - } - - if(!node) - { - cerr << "unable to open " << path << "\n"; - return errCode; - } else - { - unsigned char buf[512]; - int blocks = (node->getSize() + sizeof(buf)-1) / sizeof(buf); - // read all the data in blocks - for(int i=0; iread(i*sizeof(buf), buf, sizeof(buf)); - int res = op(buf, bytes); - if(res < 0) - return res; - } - } - return 0; -} - -class WriteOutput -{ - int _fd; -public: - WriteOutput(int fd) { _fd = fd; } - ~WriteOutput() { close(_fd); } - - int operator()(const void *buf, int count) - { - return (int)write(_fd, buf, count); - } -}; - -static int cmd_cat( int argc, char **argv ) -{ - (void)argc; - RootPtr rootInfo = initRootInfo(argv[1]); - - if(!rootInfo) - return EXIT_FAILURE; - - const char *path = argv[2]; - WriteOutput output(STDOUT_FILENO); - int errCode = processContents( rootInfo, path, output ); - - return errCode; -} - -static int copyLink(const struct stat &stBuf, - const shared_ptr &rootInfo, - const string &cpath, const string &destName ) -{ - vector buf(stBuf.st_size+1, 0); - int res = ::readlink( cpath.c_str(), &buf[0], stBuf.st_size ); - if(res == -1) - { - cerr << "unable to readlink of " << cpath << "\n"; - return EXIT_FAILURE; - } - - buf[res] = '\0'; - string decodedLink = rootInfo->root->plainPath(&buf[0]); - - res = ::symlink( decodedLink.c_str(), destName.c_str() ); - if(res == -1) - { - cerr << "unable to create symlink for " << cpath - << " to " << decodedLink << "\n"; - } - - return EXIT_SUCCESS; -} - -static int copyContents(const shared_ptr &rootInfo, - const char* encfsName, const char* targetName) -{ - shared_ptr node = - rootInfo->root->lookupNode( encfsName, "encfsctl" ); - - if(!node) - { - cerr << "unable to open " << encfsName << "\n"; - return EXIT_FAILURE; - } else - { - struct stat st; - - if(node->getAttr(&st) != 0) - return EXIT_FAILURE; - - if((st.st_mode & S_IFLNK) == S_IFLNK) - { - string d = rootInfo->root->cipherPath(encfsName); - char linkContents[PATH_MAX+2]; - - if(readlink (d.c_str(), linkContents, PATH_MAX + 1) <= 0) - { - cerr << "unable to read link " << encfsName << "\n"; - return EXIT_FAILURE; - } - symlink(rootInfo->root->plainPath(linkContents).c_str(), - targetName); - } else - { - int outfd = creat(targetName, st.st_mode); - - WriteOutput output(outfd); - processContents( rootInfo, encfsName, output ); - } - } - return EXIT_SUCCESS; -} - -static bool endsWith(const string &str, char ch) -{ - if(str.empty()) - return false; - else - return str[str.length()-1] == ch; -} - -static int traverseDirs(const shared_ptr &rootInfo, - string volumeDir, string destDir) -{ - if(!endsWith(volumeDir, '/')) - volumeDir.append("/"); - if(!endsWith(destDir, '/')) - destDir.append("/"); - - // Lookup directory node so we can create a destination directory - // with the same permissions - { - struct stat st; - shared_ptr dirNode = - rootInfo->root->lookupNode( volumeDir.c_str(), "encfsctl" ); - if(dirNode->getAttr(&st)) - return EXIT_FAILURE; - - mkdir(destDir.c_str(), st.st_mode); - } - - // show files in directory - DirTraverse dt = rootInfo->root->openDir(volumeDir.c_str()); - if(dt.valid()) - { - for(string name = dt.nextPlaintextName(); !name.empty(); - name = dt.nextPlaintextName()) - { - // Recurse to subdirectories - if(name != "." && name != "..") - { - string plainPath = volumeDir + name; - string cpath = rootInfo->root->cipherPath(plainPath.c_str()); - string destName = destDir + name; - - int r = EXIT_SUCCESS; - struct stat stBuf; - if( !lstat( cpath.c_str(), &stBuf )) - { - if( S_ISDIR( stBuf.st_mode ) ) - { - traverseDirs(rootInfo, (plainPath + '/').c_str(), - destName + '/'); - } else if( S_ISLNK( stBuf.st_mode )) - { - r = copyLink( stBuf, rootInfo, cpath, destName ); - } else - { - r = copyContents(rootInfo, plainPath.c_str(), - destName.c_str()); - } - } else - { - r = EXIT_FAILURE; - } - - if(r != EXIT_SUCCESS) - return r; - } - } - } - return EXIT_SUCCESS; -} - -static int cmd_export( int argc, char **argv ) -{ - (void)argc; - - RootPtr rootInfo = initRootInfo(argv[1]); - - if(!rootInfo) - return EXIT_FAILURE; - - string destDir = argv[2]; - // if the dir doesn't exist, then create it (with user permission) - if(!checkDir(destDir) && !userAllowMkdir(destDir.c_str(), 0700)) - return EXIT_FAILURE; - - return traverseDirs(rootInfo, "/", destDir); -} - -int showcruft( const shared_ptr &rootInfo, const char *dirName ) -{ - int found = 0; - DirTraverse dt = rootInfo->root->openDir( dirName ); - if(dt.valid()) - { - bool showedDir = false; - for(string name = dt.nextInvalid(); !name.empty(); - name = dt.nextInvalid()) - { - string cpath = rootInfo->root->cipherPath( dirName ); - cpath += '/'; - cpath += name; - - if(!showedDir) - { - // just before showing a list of files in a directory - cout << autosprintf(_("In directory %s: \n"), dirName); - showedDir = true; - } - ++found; - cout << cpath << "\n"; - } - - // now go back and look for directories to recurse into.. - dt = rootInfo->root->openDir( dirName ); - if(dt.valid()) - { - for(string name = dt.nextPlaintextName(); !name.empty(); - name = dt.nextPlaintextName()) - { - if( name == "." || name == "..") - continue; - - string plainPath = dirName; - plainPath += '/'; - plainPath += name; - - string cpath = rootInfo->root->cipherPath( plainPath.c_str() ); - - if(isDirectory( cpath.c_str() )) - found += showcruft( rootInfo, plainPath.c_str() ); - } - } - } - - return found; -} - -/* - iterate recursively through the filesystem and print out names of files - which have filenames which cannot be decoded with the given key.. -*/ -static int cmd_showcruft( int argc, char **argv ) -{ - (void)argc; - - RootPtr rootInfo = initRootInfo(argv[1]); - - if(!rootInfo) - return EXIT_FAILURE; - - int filesFound = showcruft( rootInfo, "/" ); - - cerr << autosprintf("Found %i invalid file(s).", filesFound) << "\n"; - - return EXIT_SUCCESS; -} - -static int do_chpasswd( bool useStdin, bool annotate, int argc, char **argv ) -{ - (void)argc; - string rootDir = argv[1]; - if( !checkDir( rootDir )) - return EXIT_FAILURE; - - EncfsConfig config; - ConfigType cfgType = readConfig( rootDir, config ); - - if(cfgType == Config_None) - { - cout << _("Unable to load or parse config file\n"); - return EXIT_FAILURE; - } - - // instanciate proper cipher - shared_ptr cipher = getCipher(config); - if(!cipher) - { - cout << autosprintf(_("Unable to find specified cipher \"%s\"\n"), - config.cipher().name().c_str()); - return EXIT_FAILURE; - } - - // ask for existing password - cout << _("Enter current Encfs password\n"); - if (annotate) - cerr << "$PROMPT$ passwd" << endl; - CipherKey userKey = getUserKey( config, useStdin ); - if(!userKey) - return EXIT_FAILURE; - - // decode volume key using user key -- at this point we detect an incorrect - // password if the key checksum does not match (causing readKey to fail). - CipherKey volumeKey = cipher->readKey( - (const unsigned char *)config.key().ciphertext().data(), userKey ); - - if(!volumeKey) - { - cout << _("Invalid password\n"); - return EXIT_FAILURE; - } - - // Now, get New user key.. - userKey.reset(); - cout << _("Enter new Encfs password\n"); - - // create new key - if( useStdin ) - { - if (annotate) - cerr << "$PROMPT$ new_passwd" << endl; - } - - userKey = getNewUserKey( config, useStdin, string(), string() ); - - // re-encode the volume key using the new user key and write it out.. - int result = EXIT_FAILURE; - if(userKey) - { - int encodedKeySize = cipher->encodedKeySize(); - unsigned char *keyBuf = new unsigned char[ encodedKeySize ]; - - // encode volume key with new user key - cipher->writeKey( volumeKey, keyBuf, userKey ); - userKey.reset(); - - EncryptedKey *key = config.mutable_key(); - key->set_ciphertext( keyBuf, encodedKeySize ); - delete[] keyBuf; - - if(saveConfig( rootDir, config )) - { - // password modified -- changes volume key of filesystem.. - cout << _("Volume Key successfully updated.\n"); - result = EXIT_SUCCESS; - } else - { - cout << _("Error saving modified config file.\n"); - } - } else - { - cout << _("Error creating key\n"); - } - - volumeKey.reset(); - - return result; -} - -static int chpasswd( int argc, char **argv ) -{ - return do_chpasswd( false, false, argc, argv ); -} - -static int chpasswdAutomaticly( int argc, char **argv ) -{ - return do_chpasswd( true, false, argc, argv ); -} - - -int main(int argc, char **argv) -{ - RLogInit( argc, argv ); - -#ifdef LOCALEDIR - setlocale( LC_ALL, "" ); - bindtextdomain( PACKAGE, LOCALEDIR ); - textdomain( PACKAGE ); -#endif - -#ifdef HAVE_SSL - SSL_load_error_strings(); - SSL_library_init(); -#endif - - StdioNode *slog = new StdioNode( STDERR_FILENO ); - slog->subscribeTo( GetGlobalChannel("error") ); - slog->subscribeTo( GetGlobalChannel("warning") ); -#ifndef NO_DEBUG - slog->subscribeTo( GetGlobalChannel("debug") ); -#endif - - if(argc < 2) - { - usage( argv[0] ); - return EXIT_FAILURE; - } - - if(argc == 2 && !(*argv[1] == '-' && *(argv[1]+1) == '-')) - { - // default command when only 1 argument given -- treat the argument as - // a directory.. - return showInfo( argc, argv ); - } else - { - // find the specified command - int offset = 0; - while(commands[offset].name != 0) - { - if(!strcmp( argv[1], commands[offset].name )) - break; - ++offset; - } - - if(commands[offset].name == 0) - { - cerr << autosprintf(_("invalid command: \"%s\""), argv[1]) << "\n"; - } else - { - if((argc-2 < commands[offset].minOptions) || - (argc-2 > commands[offset].maxOptions)) - { - cerr << autosprintf( - _("Incorrect number of arguments for command \"%s\""), - argv[1]) << "\n"; - } else - return (*commands[offset].func)( argc-1, argv+1 ); - } - } - - return EXIT_FAILURE; -} diff --git a/encfs/main.cpp b/encfs/main.cpp index 66911ca..b7f2ecb 100644 --- a/encfs/main.cpp +++ b/encfs/main.cpp @@ -16,9 +16,7 @@ * */ -#include "encfs.h" -#include "config.h" -#include "autosprintf.h" +#include "fs/encfs.h" #include #include @@ -33,25 +31,24 @@ #include -#include -#include -#include -#include -#include +#include -#include "ConfigReader.h" -#include "Interface.h" -#include "MemoryPool.h" -#include "FileUtils.h" -#include "DirNode.h" -#include "Context.h" +#include "base/config.h" +#include "base/autosprintf.h" +#include "base/ConfigReader.h" +#include "base/Error.h" +#include "base/Interface.h" +#include "base/i18n.h" -#include "openssl.h" +#include "cipher/MemoryPool.h" +#include "cipher/openssl.h" + +#include "fs/FileUtils.h" +#include "fs/DirNode.h" +#include "fs/Context.h" #include -#include "i18n.h" - // Fuse version >= 26 requires another argument to fuse_unmount, which we // don't have. So use the backward compatible call instead.. extern "C" void fuse_unmount_compat22(const char *mountpoint); @@ -60,12 +57,11 @@ extern "C" void fuse_unmount_compat22(const char *mountpoint); #ifndef MAX inline static int MAX(int a, int b) { - return (a > b) ? a : b; + return (a > b) ? a : b; } #endif using namespace std; -using namespace rlog; using namespace gnu; // Maximum number of arguments that we're going to pass on to fuse. Doesn't @@ -73,44 +69,44 @@ using namespace gnu; const int MaxFuseArgs = 32; struct EncFS_Args { - string mountPoint; // where to make filesystem visible - bool isDaemon; // true == spawn in background, log to syslog - bool isThreaded; // true == threaded - bool isVerbose; // false == only enable warning/error messages - int idleTimeout; // 0 == idle time in minutes to trigger unmount - const char *fuseArgv[MaxFuseArgs]; - int fuseArgc; + string mountPoint; // where to make filesystem visible + bool isDaemon; // true == spawn in background, log to syslog + bool isThreaded; // true == threaded + bool isVerbose; // false == only enable warning/error messages + int idleTimeout; // 0 == idle time in minutes to trigger unmount + const char *fuseArgv[MaxFuseArgs]; + int fuseArgc; - shared_ptr opts; + shared_ptr opts; - // for debugging - // In case someone sends me a log dump, I want to know how what options are - // in effect. Not internationalized, since it is something that is mostly - // useful for me! - string toString() - { - ostringstream ss; - ss << (isDaemon ? "(daemon) " : "(fg) "); - ss << (isThreaded ? "(threaded) " : "(UP) "); - if(idleTimeout > 0) - ss << "(timeout " << idleTimeout << ") "; - if(opts->checkKey) ss << "(keyCheck) "; - if(opts->forceDecode) ss << "(forceDecode) "; - if(opts->ownerCreate) ss << "(ownerCreate) "; - if(opts->useStdin) ss << "(useStdin) "; - if(opts->annotate) ss << "(annotate) "; - if(opts->reverseEncryption) ss << "(reverseEncryption) "; - if(opts->mountOnDemand) ss << "(mountOnDemand) "; - for(int i=0; i 0) + ss << "(timeout " << idleTimeout << ") "; + if(opts->checkKey) ss << "(keyCheck) "; + if(opts->forceDecode) ss << "(forceDecode) "; + if(opts->ownerCreate) ss << "(ownerCreate) "; + if(opts->useStdin) ss << "(useStdin) "; + if(opts->annotate) ss << "(annotate) "; + if(opts->reverseEncryption) ss << "(reverseEncryption) "; + if(opts->mountOnDemand) ss << "(mountOnDemand) "; + for(int i=0; i(argv), (fuse_operations*)NULL, NULL); + int argc = 2; + const char *argv[] = {"...", "-h"}; + fuse_main( argc, const_cast(argv), (fuse_operations*)NULL, NULL); } #define PUSHARG(ARG) do { \ -rAssert(out->fuseArgc < MaxFuseArgs); \ -out->fuseArgv[out->fuseArgc++] = (ARG); } while(0) + rAssert(out->fuseArgc < MaxFuseArgs); \ + out->fuseArgv[out->fuseArgc++] = (ARG); } \ +while(0) static string slashTerminate( const string &src ) { - string result = src; - if( result[ result.length()-1 ] != '/' ) - result.append( "/" ); - return result; + string result = src; + if( result[ result.length()-1 ] != '/' ) + result.append( "/" ); + return result; } static bool processArgs(int argc, char *argv[], const shared_ptr &out) { - // set defaults - out->isDaemon = true; - out->isThreaded = true; - out->isVerbose = false; - out->idleTimeout = 0; - out->fuseArgc = 0; - out->opts->idleTracking = false; - out->opts->checkKey = true; - out->opts->forceDecode = false; - out->opts->ownerCreate = false; - out->opts->useStdin = false; - out->opts->annotate = false; - out->opts->reverseEncryption = false; - - bool useDefaultFlags = true; + // set defaults + out->isDaemon = true; + out->isThreaded = true; + out->isVerbose = false; + out->idleTimeout = 0; + out->fuseArgc = 0; + out->opts->idleTracking = false; + out->opts->checkKey = true; + out->opts->forceDecode = false; + out->opts->ownerCreate = false; + out->opts->useStdin = false; + out->opts->annotate = false; + out->opts->reverseEncryption = false; - // pass executable name through - out->fuseArgv[0] = lastPathElement(argv[0]); - ++out->fuseArgc; + bool useDefaultFlags = true; - // leave a space for mount point, as FUSE expects the mount point before - // any flags - out->fuseArgv[1] = NULL; - ++out->fuseArgc; - - // TODO: can flags be internationalized? - static struct option long_options[] = { - {"fuse-debug", 0, 0, 'd'}, // Fuse debug mode - {"forcedecode", 0, 0, 'D'}, // force decode - // {"foreground", 0, 0, 'f'}, // foreground mode (no daemon) - {"fuse-help", 0, 0, 'H'}, // fuse_mount usage - {"idle", 1, 0, 'i'}, // idle timeout - {"anykey", 0, 0, 'k'}, // skip key checks - {"no-default-flags", 0, 0, 'N'}, // don't use default fuse flags - {"ondemand", 0, 0, 'm'}, // mount on-demand - {"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 - {"verbose", 0, 0, 'v'}, // verbose mode - {"version", 0, 0, 'V'}, //version - {"reverse", 0, 0, 'r'}, // reverse encryption - {"standard", 0, 0, '1'}, // standard configuration - {"paranoia", 0, 0, '2'}, // standard configuration - {0,0,0,0} - }; + // pass executable name through + out->fuseArgv[0] = lastPathElement(argv[0]); + ++out->fuseArgc; - while (1) + // leave a space for mount point, as FUSE expects the mount point before + // any flags + out->fuseArgv[1] = NULL; + ++out->fuseArgc; + + // TODO: can flags be internationalized? + static struct option long_options[] = { + {"fuse-debug", 0, 0, 'd'}, // Fuse debug mode + {"forcedecode", 0, 0, 'D'}, // force decode + // {"foreground", 0, 0, 'f'}, // foreground mode (no daemon) + {"fuse-help", 0, 0, 'H'}, // fuse_mount usage + {"idle", 1, 0, 'i'}, // idle timeout + {"anykey", 0, 0, 'k'}, // skip key checks + {"no-default-flags", 0, 0, 'N'}, // don't use default fuse flags + {"ondemand", 0, 0, 'm'}, // mount on-demand + {"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 + {"verbose", 0, 0, 'v'}, // verbose mode + {"version", 0, 0, 'V'}, //version + {"reverse", 0, 0, 'r'}, // reverse encryption + {"standard", 0, 0, '1'}, // standard configuration + {"paranoia", 0, 0, '2'}, // standard configuration + {0,0,0,0} + }; + + while (1) + { + int option_index = 0; + + // 's' : single-threaded mode + // 'f' : foreground mode + // 'v' : verbose mode (same as --verbose) + // 'd' : fuse debug mode (same as --fusedebug) + // 'i' : idle-timeout, takes argument + // 'm' : mount-on-demand + // 'S' : password from stdin + // 'o' : arguments meant for fuse + int res = getopt_long( argc, argv, "HsSfvVdmi:o:", + long_options, &option_index); + + if(res == -1) + break; + + switch( res ) { - int option_index = 0; - - // 's' : single-threaded mode - // 'f' : foreground mode - // 'v' : verbose mode (same as --verbose) - // 'd' : fuse debug mode (same as --fusedebug) - // 'i' : idle-timeout, takes argument - // 'm' : mount-on-demand - // 'S' : password from stdin - // 'o' : arguments meant for fuse - int res = getopt_long( argc, argv, "HsSfvVdmi:o:", - long_options, &option_index); - - if(res == -1) - break; - - switch( res ) - { - case '1': - out->opts->configMode = Config_Standard; - break; - case '2': - out->opts->configMode = Config_Paranoia; - break; - case 's': - out->isThreaded = false; - break; - case 'S': - out->opts->useStdin = true; - break; - case 513: - out->opts->annotate = true; - break; - case 'f': - out->isDaemon = false; - // this option was added in fuse 2.x - PUSHARG("-f"); - break; - case 'v': - out->isVerbose = true; - break; - case 'd': - PUSHARG("-d"); - break; - case 'i': - out->idleTimeout = strtol( optarg, (char**)NULL, 10); - out->opts->idleTracking = true; - break; - case 'k': - out->opts->checkKey = false; - break; - case 'D': - out->opts->forceDecode = true; - break; - case 'r': - out->opts->reverseEncryption = true; - break; - case 'm': - out->opts->mountOnDemand = true; - break; - case 'N': - useDefaultFlags = false; - break; - case 'o': - PUSHARG("-o"); - PUSHARG( optarg ); - break; - case 'p': - out->opts->passwordProgram.assign( optarg ); - break; - case 'P': - if(geteuid() != 0) - rWarning(_("option '--public' ignored for non-root user")); - else - { - out->opts->ownerCreate = true; - // add 'allow_other' option - // add 'default_permissions' option (default) - PUSHARG("-o"); - PUSHARG("allow_other"); - } - break; - case 'V': - // xgroup(usage) - cerr << autosprintf(_("encfs version %s"), VERSION) << endl; - exit(EXIT_SUCCESS); - break; - case 'H': - FuseUsage(); - exit(EXIT_SUCCESS); - break; - case '?': - // invalid options.. - break; - case ':': - // missing parameter for option.. - break; - default: - rWarning(_("getopt error: %i"), res); - break; - } + case '1': + out->opts->configMode = Config_Standard; + break; + case '2': + out->opts->configMode = Config_Paranoia; + break; + case 's': + out->isThreaded = false; + break; + case 'S': + out->opts->useStdin = true; + break; + case 513: + out->opts->annotate = true; + break; + case 'f': + out->isDaemon = false; + // this option was added in fuse 2.x + PUSHARG("-f"); + break; + case 'v': + out->isVerbose = true; + break; + case 'd': + PUSHARG("-d"); + break; + case 'i': + out->idleTimeout = strtol( optarg, (char**)NULL, 10); + out->opts->idleTracking = true; + break; + case 'k': + out->opts->checkKey = false; + break; + case 'D': + out->opts->forceDecode = true; + break; + case 'r': + out->opts->reverseEncryption = true; + break; + case 'm': + out->opts->mountOnDemand = true; + break; + case 'N': + useDefaultFlags = false; + break; + case 'o': + PUSHARG("-o"); + PUSHARG( optarg ); + break; + case 'p': + out->opts->passwordProgram.assign( optarg ); + break; + case 'P': + if(geteuid() != 0) + LOG(WARNING) << "option '--public' ignored for non-root user"; + else + { + out->opts->ownerCreate = true; + // add 'allow_other' option + // add 'default_permissions' option (default) + PUSHARG("-o"); + PUSHARG("allow_other"); + } + break; + case 'V': + // xgroup(usage) + cerr << autosprintf(_("encfs version %s"), VERSION) << endl; + exit(EXIT_SUCCESS); + break; + case 'H': + FuseUsage(); + exit(EXIT_SUCCESS); + break; + case '?': + // invalid options.. + break; + case ':': + // missing parameter for option.. + break; + default: + LOG(WARNING) << "getopt error: " << res; + break; } + } - if(!out->isThreaded) - PUSHARG("-s"); + if(!out->isThreaded) + PUSHARG("-s"); - if(useDefaultFlags) + 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) + { + out->opts->rootDir = slashTerminate( argv[optind++] ); + out->mountPoint = argv[optind++]; + } else + { + // no mount point specified + LOG(ERROR) << "Missing one or more arguments, aborting."; + return false; + } + + // If there are still extra unparsed arguments, pass them onto FUSE.. + if(optind < argc) + { + rAssert(out->fuseArgc < MaxFuseArgs); + + while(optind < argc) { - PUSHARG("-o"); - PUSHARG("use_ino"); - PUSHARG("-o"); - PUSHARG("default_permissions"); + rAssert(out->fuseArgc < MaxFuseArgs); + out->fuseArgv[out->fuseArgc++] = argv[optind]; + ++optind; } - - // we should have at least 2 arguments left over - the source directory and - // the mount point. - if(optind+2 <= argc) + } + + // sanity check + if(out->isDaemon && + (!isAbsolutePath( out->mountPoint.c_str() ) || + !isAbsolutePath( out->opts->rootDir.c_str() ) ) + ) + { + cerr << + // xgroup(usage) + _("When specifying daemon mode, you must use absolute paths " + "(beginning with '/')") + << endl; + return false; + } + + // the raw directory may not be a subdirectory of the mount point. + { + string testMountPoint = slashTerminate( out->mountPoint ); + string testRootDir = + out->opts->rootDir.substr(0, testMountPoint.length()); + + if( testMountPoint == testRootDir ) { - out->opts->rootDir = slashTerminate( argv[optind++] ); - out->mountPoint = argv[optind++]; - } else - { - // no mount point specified - rWarning(_("Missing one or more arguments, aborting.")); - return false; + cerr << + // xgroup(usage) + _("The raw directory may not be a subdirectory of the " + "mount point.") << endl; + return false; } + } - // If there are still extra unparsed arguments, pass them onto FUSE.. - if(optind < argc) - { - rAssert(out->fuseArgc < MaxFuseArgs); + if(out->opts->mountOnDemand && out->opts->passwordProgram.empty()) + { + cerr << + // xgroup(usage) + _("Must set password program when using mount-on-demand") + << endl; + return false; + } - while(optind < argc) - { - rAssert(out->fuseArgc < MaxFuseArgs); - out->fuseArgv[out->fuseArgc++] = argv[optind]; - ++optind; - } - } + // check that the directories exist, or that we can create them.. + if(!isDirectory( out->opts->rootDir.c_str() ) && + !userAllowMkdir( out->opts->annotate? 1:0, + out->opts->rootDir.c_str() ,0700)) + { + LOG(WARNING) << "Unable to locate root directory, aborting."; + return false; + } + if(!isDirectory( out->mountPoint.c_str() ) && + !userAllowMkdir( out->opts->annotate? 2:0, + out->mountPoint.c_str(),0700)) + { + LOG(WARNING) << "Unable to locate mount point, aborting."; + return false; + } - // sanity check - if(out->isDaemon && - (!isAbsolutePath( out->mountPoint.c_str() ) || - !isAbsolutePath( out->opts->rootDir.c_str() ) ) - ) - { - cerr << - // xgroup(usage) - _("When specifying daemon mode, you must use absolute paths " - "(beginning with '/')") - << endl; - return false; - } + // fill in mount path for fuse + out->fuseArgv[1] = out->mountPoint.c_str(); - // the raw directory may not be a subdirectory of the mount point. - { - string testMountPoint = slashTerminate( out->mountPoint ); - string testRootDir = - out->opts->rootDir.substr(0, testMountPoint.length()); - - if( testMountPoint == testRootDir ) - { - cerr << - // xgroup(usage) - _("The raw directory may not be a subdirectory of the " - "mount point.") << endl; - return false; - } - } - - if(out->opts->mountOnDemand && out->opts->passwordProgram.empty()) - { - cerr << - // xgroup(usage) - _("Must set password program when using mount-on-demand") - << endl; - return false; - } - - // check that the directories exist, or that we can create them.. - if(!isDirectory( out->opts->rootDir.c_str() ) && - !userAllowMkdir( out->opts->annotate? 1:0, - out->opts->rootDir.c_str() ,0700)) - { - rWarning(_("Unable to locate root directory, aborting.")); - return false; - } - if(!isDirectory( out->mountPoint.c_str() ) && - !userAllowMkdir( out->opts->annotate? 2:0, - out->mountPoint.c_str(),0700)) - { - rWarning(_("Unable to locate mount point, aborting.")); - return false; - } - - // fill in mount path for fuse - out->fuseArgv[1] = out->mountPoint.c_str(); - - return true; + return true; } static void * idleMonitor(void *); void *encfs_init(fuse_conn_info *conn) { - EncFS_Context *ctx = (EncFS_Context*)fuse_get_context()->private_data; + EncFS_Context *ctx = (EncFS_Context*)fuse_get_context()->private_data; - // set fuse connection options - conn->async_read = true; + // set fuse connection options + conn->async_read = true; - // if an idle timeout is specified, then setup a thread to monitor the - // filesystem. - if(ctx->args->idleTimeout > 0) + // if an idle timeout is specified, then setup a thread to monitor the + // filesystem. + if(ctx->args->idleTimeout > 0) + { + VLOG(1) << "starting idle monitoring thread"; + ctx->running = true; + + int res = pthread_create( &ctx->monitorThread, 0, idleMonitor, + (void*)ctx ); + if(res != 0) { - rDebug("starting idle monitoring thread"); - ctx->running = true; - - int res = pthread_create( &ctx->monitorThread, 0, idleMonitor, - (void*)ctx ); - if(res != 0) - { - rError("error starting idle monitor thread, " - "res = %i, errno = %i", res, errno); - } + LOG(ERROR) << "error starting idle monitor thread, " + "res = " << res << ", errno = " << errno; } + } - if(ctx->args->isDaemon && oldStderr >= 0) - { - rInfo("Closing stderr"); - close(oldStderr); - oldStderr = -1; - } + if(ctx->args->isDaemon && oldStderr >= 0) + { + VLOG(1) << "Closing stderr"; + close(oldStderr); + oldStderr = -1; + } - return (void*)ctx; + return (void*)ctx; } void encfs_destroy( void *_ctx ) { - EncFS_Context *ctx = (EncFS_Context*)_ctx; - if(ctx->args->idleTimeout > 0) - { - ctx->running = false; + EncFS_Context *ctx = (EncFS_Context*)_ctx; + if(ctx->args->idleTimeout > 0) + { + ctx->running = false; - // wake up the thread if it is waiting.. - rDebug("waking up monitoring thread"); - pthread_mutex_lock( &ctx->wakeupMutex ); - pthread_cond_signal( &ctx->wakeupCond ); - pthread_mutex_unlock( &ctx->wakeupMutex ); - rDebug("joining with idle monitoring thread"); - pthread_join( ctx->monitorThread , 0 ); - rDebug("join done"); - } + // wake up the thread if it is waiting.. + VLOG(1) << "waking up monitoring thread"; + pthread_mutex_lock( &ctx->wakeupMutex ); + pthread_cond_signal( &ctx->wakeupCond ); + pthread_mutex_unlock( &ctx->wakeupMutex ); + VLOG(1) << "joining with idle monitoring thread"; + pthread_join( ctx->monitorThread , 0 ); + VLOG(1) << "join done"; + } } int main(int argc, char *argv[]) { - // initialize the logging library - RLogInit( argc, argv ); + // log to stderr by default.. + FLAGS_logtostderr = 1; + FLAGS_minloglevel = 1; // WARNING and above. + + google::InitGoogleLogging(argv[0]); + google::InstallFailureSignalHandler(); #ifdef LOCALEDIR - setlocale( LC_ALL, "" ); - bindtextdomain( PACKAGE, LOCALEDIR ); - textdomain( PACKAGE ); + setlocale( LC_ALL, "" ); + bindtextdomain( PACKAGE, LOCALEDIR ); + textdomain( PACKAGE ); #endif - // log to stderr by default.. - shared_ptr slog( new StdioNode( STDERR_FILENO ) ); - shared_ptr logNode; + // anything that comes from the user should be considered tainted until + // we've processed it and only allowed through what we support. + shared_ptr encfsArgs( new EncFS_Args ); + for(int i=0; ifuseArgv[i] = NULL; // libfuse expects null args.. - // show error and warning output - slog->subscribeTo( GetGlobalChannel("error") ); - slog->subscribeTo( GetGlobalChannel("warning") ); + if(argc == 1 || !processArgs(argc, argv, encfsArgs)) + { + usage(argv[0]); + return EXIT_FAILURE; + } - // anything that comes from the user should be considered tainted until - // we've processed it and only allowed through what we support. - shared_ptr encfsArgs( new EncFS_Args ); - for(int i=0; ifuseArgv[i] = NULL; // libfuse expects null args.. + if(encfsArgs->isVerbose) + FLAGS_minloglevel = 0; - if(argc == 1 || !processArgs(argc, argv, encfsArgs)) - { - usage(argv[0]); - return EXIT_FAILURE; - } + LOG(INFO) << "Root directory: " << encfsArgs->opts->rootDir; + LOG(INFO) << "Fuse arguments: " << encfsArgs->toString(); - if(encfsArgs->isVerbose) - { - // subscribe to more logging channels.. - slog->subscribeTo( GetGlobalChannel("info") ); - slog->subscribeTo( GetGlobalChannel("debug") ); - } - - rDebug("Root directory: %s", encfsArgs->opts->rootDir.c_str()); - rDebug("Fuse arguments: %s", encfsArgs->toString().c_str()); - - fuse_operations encfs_oper; - // in case this code is compiled against a newer FUSE library and new - // members have been added to fuse_operations, make sure they get set to - // 0.. - memset(&encfs_oper, 0, sizeof(fuse_operations)); + fuse_operations encfs_oper; + // in case this code is compiled against a newer FUSE library and new + // members have been added to fuse_operations, make sure they get set to + // 0.. + memset(&encfs_oper, 0, sizeof(fuse_operations)); - encfs_oper.getattr = encfs_getattr; - encfs_oper.readlink = encfs_readlink; - encfs_oper.getdir = encfs_getdir; // deprecated for readdir - encfs_oper.mknod = encfs_mknod; - encfs_oper.mkdir = encfs_mkdir; - encfs_oper.unlink = encfs_unlink; - encfs_oper.rmdir = encfs_rmdir; - encfs_oper.symlink = encfs_symlink; - encfs_oper.rename = encfs_rename; - encfs_oper.link = encfs_link; - encfs_oper.chmod = encfs_chmod; - encfs_oper.chown = encfs_chown; - encfs_oper.truncate = encfs_truncate; - encfs_oper.utime = encfs_utime; // deprecated for utimens - encfs_oper.open = encfs_open; - encfs_oper.read = encfs_read; - encfs_oper.write = encfs_write; - encfs_oper.statfs = encfs_statfs; - encfs_oper.flush = encfs_flush; - encfs_oper.release = encfs_release; - encfs_oper.fsync = encfs_fsync; + encfs_oper.getattr = encfs_getattr; + encfs_oper.readlink = encfs_readlink; + encfs_oper.getdir = encfs_getdir; // deprecated for readdir + encfs_oper.mknod = encfs_mknod; + encfs_oper.mkdir = encfs_mkdir; + encfs_oper.unlink = encfs_unlink; + encfs_oper.rmdir = encfs_rmdir; + encfs_oper.symlink = encfs_symlink; + encfs_oper.rename = encfs_rename; + encfs_oper.link = encfs_link; + encfs_oper.chmod = encfs_chmod; + encfs_oper.chown = encfs_chown; + encfs_oper.truncate = encfs_truncate; + encfs_oper.utime = encfs_utime; // deprecated for utimens + encfs_oper.open = encfs_open; + encfs_oper.read = encfs_read; + encfs_oper.write = encfs_write; + encfs_oper.statfs = encfs_statfs; + encfs_oper.flush = encfs_flush; + encfs_oper.release = encfs_release; + encfs_oper.fsync = encfs_fsync; #ifdef HAVE_XATTR - encfs_oper.setxattr = encfs_setxattr; - encfs_oper.getxattr = encfs_getxattr; - encfs_oper.listxattr = encfs_listxattr; - encfs_oper.removexattr = encfs_removexattr; + encfs_oper.setxattr = encfs_setxattr; + encfs_oper.getxattr = encfs_getxattr; + encfs_oper.listxattr = encfs_listxattr; + encfs_oper.removexattr = encfs_removexattr; #endif // HAVE_XATTR - //encfs_oper.opendir = encfs_opendir; - //encfs_oper.readdir = encfs_readdir; - //encfs_oper.releasedir = encfs_releasedir; - //encfs_oper.fsyncdir = encfs_fsyncdir; - encfs_oper.init = encfs_init; - encfs_oper.destroy = encfs_destroy; - //encfs_oper.access = encfs_access; - //encfs_oper.create = encfs_create; - encfs_oper.ftruncate = encfs_ftruncate; - encfs_oper.fgetattr = encfs_fgetattr; - //encfs_oper.lock = encfs_lock; - encfs_oper.utimens = encfs_utimens; - //encfs_oper.bmap = encfs_bmap; + //encfs_oper.opendir = encfs_opendir; + //encfs_oper.readdir = encfs_readdir; + //encfs_oper.releasedir = encfs_releasedir; + //encfs_oper.fsyncdir = encfs_fsyncdir; + encfs_oper.init = encfs_init; + encfs_oper.destroy = encfs_destroy; + //encfs_oper.access = encfs_access; + //encfs_oper.create = encfs_create; + encfs_oper.ftruncate = encfs_ftruncate; + encfs_oper.fgetattr = encfs_fgetattr; + //encfs_oper.lock = encfs_lock; + encfs_oper.utimens = encfs_utimens; + //encfs_oper.bmap = encfs_bmap; #if (__FreeBSD__ >= 10) - // encfs_oper.setvolname - // encfs_oper.exchange - // encfs_oper.getxtimes - // encfs_oper.setbkuptime - // encfs_oper.setchgtime - // encfs_oper.setcrtime - // encfs_oper.chflags - // encfs_oper.setattr_x - // encfs_oper.fsetattr_x + // encfs_oper.setvolname + // encfs_oper.exchange + // encfs_oper.getxtimes + // encfs_oper.setbkuptime + // encfs_oper.setchgtime + // encfs_oper.setcrtime + // encfs_oper.chflags + // encfs_oper.setattr_x + // encfs_oper.fsetattr_x #endif - openssl_init( encfsArgs->isThreaded ); + openssl_init( encfsArgs->isThreaded ); - // context is not a smart pointer because it will live for the life of - // the filesystem. - EncFS_Context *ctx = new EncFS_Context; - ctx->publicFilesystem = encfsArgs->opts->ownerCreate; - RootPtr rootInfo = initFS( ctx, encfsArgs->opts ); - - int returnCode = EXIT_FAILURE; + // context is not a smart pointer because it will live for the life of + // the filesystem. + EncFS_Context *ctx = new EncFS_Context; + ctx->publicFilesystem = encfsArgs->opts->ownerCreate; + RootPtr rootInfo = initFS( ctx, encfsArgs->opts ); - if( rootInfo ) + int returnCode = EXIT_FAILURE; + + if( rootInfo ) + { + // set the globally visible root directory node + ctx->setRoot( rootInfo->root ); + ctx->args = encfsArgs; + ctx->opts = encfsArgs->opts; + + if(encfsArgs->isThreaded == false && encfsArgs->idleTimeout > 0) { - // set the globally visible root directory node - ctx->setRoot( rootInfo->root ); - ctx->args = encfsArgs; - ctx->opts = encfsArgs->opts; - - if(encfsArgs->isThreaded == false && encfsArgs->idleTimeout > 0) - { - // xgroup(usage) - cerr << _("Note: requested single-threaded mode, but an idle\n" - "timeout was specified. The filesystem will operate\n" - "single-threaded, but threads will still be used to\n" - "implement idle checking.") << endl; - } - - // reset umask now, since we don't want it to interfere with the - // pass-thru calls.. - umask( 0 ); - - if(encfsArgs->isDaemon) - { - // switch to logging just warning and error messages via syslog - logNode.reset( new SyslogNode( "encfs" ) ); - logNode->subscribeTo( GetGlobalChannel("warning") ); - logNode->subscribeTo( GetGlobalChannel("error") ); - - // disable stderr reporting.. - slog.reset(); - - // keep around a pointer just in case we end up needing it to - // report a fatal condition later (fuse_main exits unexpectedly)... - oldStderr = dup( STDERR_FILENO ); - } - - try - { - time_t startTime, endTime; - - if (encfsArgs->opts->annotate) - cerr << "$STATUS$ fuse_main_start" << endl; - - // FIXME: workaround for fuse_main returning an error on normal - // exit. Only print information if fuse_main returned - // immediately.. - time( &startTime ); - - // fuse_main returns an error code in newer versions of fuse.. - int res = fuse_main( encfsArgs->fuseArgc, - const_cast(encfsArgs->fuseArgv), - &encfs_oper, (void*)ctx); - - time( &endTime ); - - if (encfsArgs->opts->annotate) - cerr << "$STATUS$ fuse_main_end" << endl; - - if(res == 0) - returnCode = EXIT_SUCCESS; - - if(res != 0 && encfsArgs->isDaemon && (oldStderr >= 0) - && (endTime - startTime <= 1) ) - { - // the users will not have seen any message from fuse, so say a - // few words in libfuse's memory.. - FILE *out = fdopen( oldStderr, "a" ); - // xgroup(usage) - fprintf(out, _("fuse failed. Common problems:\n" - " - fuse kernel module not installed (modprobe fuse)\n" - " - invalid options -- see usage message\n")); - fclose(out); - } - } catch(std::exception &ex) - { - rError(_("Internal error: Caught exception from main loop: %s"), - ex.what()); - } catch(...) - { - rError(_("Internal error: Caught unexpected exception")); - } + // xgroup(usage) + cerr << _("Note: requested single-threaded mode, but an idle\n" + "timeout was specified. The filesystem will operate\n" + "single-threaded, but threads will still be used to\n" + "implement idle checking.") << endl; } - // cleanup so that we can check for leaked resources.. - rootInfo.reset(); - ctx->setRoot( shared_ptr() ); + // reset umask now, since we don't want it to interfere with the + // pass-thru calls.. + umask( 0 ); - MemoryPool::destroyAll(); - openssl_shutdown( encfsArgs->isThreaded ); + if(encfsArgs->isDaemon) + { + // switch to logging just warning and error messages via syslog + FLAGS_minloglevel = 1; + FLAGS_logtostderr = 0; - return returnCode; + // keep around a pointer just in case we end up needing it to + // report a fatal condition later (fuse_main exits unexpectedly)... + oldStderr = dup( STDERR_FILENO ); + } + + try + { + time_t startTime, endTime; + + if (encfsArgs->opts->annotate) + cerr << "$STATUS$ fuse_main_start" << endl; + + // FIXME: workaround for fuse_main returning an error on normal + // exit. Only print information if fuse_main returned + // immediately.. + time( &startTime ); + + // fuse_main returns an error code in newer versions of fuse.. + int res = fuse_main( encfsArgs->fuseArgc, + const_cast(encfsArgs->fuseArgv), + &encfs_oper, (void*)ctx); + + time( &endTime ); + + if (encfsArgs->opts->annotate) + cerr << "$STATUS$ fuse_main_end" << endl; + + if(res == 0) + returnCode = EXIT_SUCCESS; + + if(res != 0 && encfsArgs->isDaemon && (oldStderr >= 0) + && (endTime - startTime <= 1) ) + { + // the users will not have seen any message from fuse, so say a + // few words in libfuse's memory.. + FILE *out = fdopen( oldStderr, "a" ); + // xgroup(usage) + fprintf(out, _("fuse failed. Common problems:\n" + " - fuse kernel module not installed (modprobe fuse)\n" + " - invalid options -- see usage message\n")); + fclose(out); + } + } catch(std::exception &ex) + { + LOG(ERROR) << "Internal error: Caught exception from main loop: " + << ex.what(); + } catch(...) + { + LOG(ERROR) << "Internal error: Caught unexpected exception"; + } + } + + // cleanup so that we can check for leaked resources.. + rootInfo.reset(); + ctx->setRoot( shared_ptr() ); + + MemoryPool::destroyAll(); + openssl_shutdown( encfsArgs->isThreaded ); + + return returnCode; } /* @@ -699,73 +684,69 @@ static bool unmountFS(EncFS_Context *ctx); static void * idleMonitor(void *_arg) { - EncFS_Context *ctx = (EncFS_Context*)_arg; - shared_ptr arg = ctx->args; + EncFS_Context *ctx = (EncFS_Context*)_arg; + shared_ptr arg = ctx->args; - const int timeoutCycles = 60 * arg->idleTimeout / ActivityCheckInterval; - int idleCycles = 0; + const int timeoutCycles = 60 * arg->idleTimeout / ActivityCheckInterval; + int idleCycles = 0; - pthread_mutex_lock( &ctx->wakeupMutex ); - - while(ctx->running) + pthread_mutex_lock( &ctx->wakeupMutex ); + + while(ctx->running) + { + int usage = ctx->getAndResetUsageCounter(); + + if(usage == 0 && ctx->isMounted()) + ++idleCycles; + else + idleCycles = 0; + + if(idleCycles >= timeoutCycles) { - int usage = ctx->getAndResetUsageCounter(); + int openCount = ctx->openFileCount(); + if( openCount == 0 && unmountFS( ctx ) ) + { + // wait for main thread to wake us up + pthread_cond_wait( &ctx->wakeupCond, &ctx->wakeupMutex ); + break; + } - if(usage == 0 && ctx->isMounted()) - ++idleCycles; - else - idleCycles = 0; - - if(idleCycles >= timeoutCycles) - { - int openCount = ctx->openFileCount(); - if( openCount == 0 && unmountFS( ctx ) ) - { - // wait for main thread to wake us up - pthread_cond_wait( &ctx->wakeupCond, &ctx->wakeupMutex ); - break; - } - - rDebug("num open files: %i", openCount ); - } - - rDebug("idle cycle count: %i, timeout after %i", idleCycles, - timeoutCycles); - - struct timeval currentTime; - gettimeofday( ¤tTime, 0 ); - struct timespec wakeupTime; - wakeupTime.tv_sec = currentTime.tv_sec + ActivityCheckInterval; - wakeupTime.tv_nsec = currentTime.tv_usec * 1000; - pthread_cond_timedwait( &ctx->wakeupCond, - &ctx->wakeupMutex, &wakeupTime ); + VLOG(1) << "num open files: " << openCount; } - - pthread_mutex_unlock( &ctx->wakeupMutex ); - rDebug("Idle monitoring thread exiting"); + VLOG(1) << "idle cycle count: " << idleCycles + << ", timeout after " << timeoutCycles; - return 0; + struct timeval currentTime; + gettimeofday( ¤tTime, 0 ); + struct timespec wakeupTime; + wakeupTime.tv_sec = currentTime.tv_sec + ActivityCheckInterval; + wakeupTime.tv_nsec = currentTime.tv_usec * 1000; + pthread_cond_timedwait( &ctx->wakeupCond, + &ctx->wakeupMutex, &wakeupTime ); + } + + pthread_mutex_unlock( &ctx->wakeupMutex ); + + VLOG(1) << "Idle monitoring thread exiting"; + + return 0; } static bool unmountFS(EncFS_Context *ctx) { - shared_ptr arg = ctx->args; - if( arg->opts->mountOnDemand ) - { - rDebug("Detaching filesystem %s due to inactivity", - arg->mountPoint.c_str()); + shared_ptr arg = ctx->args; + LOG(INFO) << "Detaching filesystem " << arg->mountPoint + << " due to inactivity"; - ctx->setRoot( shared_ptr() ); - return false; - } else - { - // Time to unmount! - // xgroup(diag) - rWarning(_("Unmounting filesystem %s due to inactivity"), - arg->mountPoint.c_str()); - fuse_unmount( arg->mountPoint.c_str() ); - return true; - } + if( arg->opts->mountOnDemand ) + { + ctx->setRoot( shared_ptr() ); + return false; + } else + { + fuse_unmount( arg->mountPoint.c_str() ); + return true; + } } diff --git a/encfs/openssl.cpp b/encfs/openssl.cpp deleted file mode 100644 index dc388da..0000000 --- a/encfs/openssl.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2007, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include "openssl.h" - -#include - -#include - -#define NO_DES -#include -#include -#ifndef OPENSSL_NO_ENGINE -#include -#endif - -unsigned long pthreads_thread_id() -{ - return (unsigned long)pthread_self(); -} - -static pthread_mutex_t *crypto_locks = NULL; -void pthreads_locking_callback( int mode, int n, - const char *caller_file, int caller_line ) -{ - (void)caller_file; - (void)caller_line; - - if(!crypto_locks) - { - rDebug("Allocating %i locks for OpenSSL", CRYPTO_num_locks() ); - crypto_locks = new pthread_mutex_t[ CRYPTO_num_locks() ]; - for(int i=0; i - * - ***************************************************************************** - * Copyright (c) 2003, Valient Gough - * - * This library is free software; you can distribute it and/or modify it under - * the terms of the GNU General Public License (GPL), as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more - * details. - * - */ - -#include "encfs.h" - -#include "config.h" - -#include -#include -#include -#include - -#include "Cipher.h" -#include "DirNode.h" -#include "MemoryPool.h" -#include "Interface.h" -#include "FileUtils.h" -#include "StreamNameIO.h" -#include "BlockNameIO.h" -#include "NullNameIO.h" - -#include -#include -#include -#include - -#ifdef HAVE_SSL -#define NO_DES -#include -#ifndef OPENSSL_NO_ENGINE -#include -#endif -#endif - -#include - -#if HAVE_TR1_UNORDERED_SET -#include -using std::tr1::unordered_set; -#else -#include -using std::unordered_set; -#endif - -using namespace std; -using namespace rlog; - -const int FSBlockSize = 256; - -static -int checkErrorPropogation( const shared_ptr &cipher, - int size, int byteToChange, const CipherKey &key ) -{ - MemBlock orig = MemoryPool::allocate(size); - MemBlock data = MemoryPool::allocate(size); - - for(int i=0; istreamEncode( data.data, size, 0, key ); - else - cipher->blockEncode( data.data, size, 0, key ); - - // intoduce an error in the encoded data, so we can check error propogation - if(byteToChange >= 0 && byteToChange < size) - { - unsigned char previousValue = data.data[byteToChange]; - do - { - data.data[byteToChange] = rand(); - } while(data.data[byteToChange] == previousValue); - } - - if(size != FSBlockSize) - cipher->streamDecode( data.data, size, 0, key ); - else - cipher->blockDecode( data.data, size, 0, key ); - - int numByteErrors = 0; - for(int i=0; i \"" << encName.c_str() << "\""; - - // decrypt name - string decName = dirNode.plainPath( encName.c_str() ); - - if(decName == *orig) - { - if(verbose) - cerr << " OK\n"; - } else - { - if(verbose) - cerr << " FAILED (got " << decName << ")\n"; - return false; - } - - orig++; - } - - if (collisionTest) - { - if (verbose) - cerr << "Checking for name collections, this will take a while..\n"; - // check for collision rate - char buf[64]; - unordered_set encryptedNames; - for (long i=0; i < 10000000; i++) - { - snprintf(buf, sizeof(buf), "%li", i); - string encName = dirNode.relativeCipherPath( buf ); - // simulate a case-insisitive filesystem.. - std::transform(encName.begin(), encName.end(), encName.begin(), - ::toupper); - - if (encryptedNames.insert(encName).second == false) { - cerr << "collision detected after " << i << " iterations"; - break; - } - } - cerr << "NO collisions detected"; - } - - return true; -} - -bool runTests(const shared_ptr &cipher, bool verbose) -{ - // create a random key - if(verbose) - cerr << "Generating new key, output will be different on each run\n\n"; - CipherKey key = cipher->newRandomKey(); - - if(verbose) - cerr << "Testing key save / restore :"; - { - CipherKey encodingKey = cipher->newRandomKey(); - int encodedKeySize = cipher->encodedKeySize(); - unsigned char *keyBuf = new unsigned char [ encodedKeySize ]; - - cipher->writeKey( key, keyBuf, encodingKey ); - CipherKey key2 = cipher->readKey( keyBuf, encodingKey ); - if(!key2) - { - if(verbose) - cerr << " FAILED (decode error)\n"; - return false; - } - - if(cipher->compareKey( key, key2 )) - { - if(verbose) - cerr << " OK\n"; - } else - { - if(verbose) - cerr << " FAILED\n"; - return false; - } - } - - if(verbose) - cerr << "Testing Config interface load / store :"; - { - CipherKey encodingKey = cipher->newRandomKey(); - int encodedKeySize = cipher->encodedKeySize(); - unsigned char *keyBuf = new unsigned char [ encodedKeySize ]; - - cipher->writeKey( key, keyBuf, encodingKey ); - - // store in config struct.. - EncfsConfig cfg; - cfg.mutable_cipher()->MergeFrom(cipher->interface()); - EncryptedKey *encryptedKey = cfg.mutable_key(); - encryptedKey->set_size(8 * cipher->keySize()); - encryptedKey->set_ciphertext( keyBuf, encodedKeySize ); - cfg.set_block_size(FSBlockSize); - - // save config - string data; - google::protobuf::TextFormat::PrintToString(cfg, &data); - - // read back in and check everything.. - EncfsConfig cfg2; - google::protobuf::TextFormat::ParseFromString(data, &cfg2); - - // check.. - rAssert( implements(cfg.cipher(),cfg2.cipher()) ); - rAssert( cfg.key().size() == cfg2.key().size() ); - rAssert( cfg.block_size() == cfg2.block_size() ); - - // try decoding key.. - - CipherKey key2 = cipher->readKey( (unsigned char *)cfg2.key().ciphertext().data(), encodingKey ); - if(!key2) - { - if(verbose) - cerr << " FAILED (decode error)\n"; - return false; - } - - if(cipher->compareKey( key, key2 )) - { - if(verbose) - cerr << " OK\n"; - } else - { - if(verbose) - cerr << " FAILED\n"; - return false; - } - } - - FSConfigPtr fsCfg = FSConfigPtr(new FSConfig); - fsCfg->cipher = cipher; - fsCfg->key = key; - fsCfg->config.reset(new EncfsConfig); - fsCfg->config->set_block_size(FSBlockSize); - - if(verbose) - cerr << "Testing name encode/decode (stream coding w/ IV chaining)\n"; - { - fsCfg->opts.reset(new EncFS_Opts); - fsCfg->opts->idleTracking = false; - fsCfg->config->set_unique_iv(false); - - fsCfg->nameCoding.reset( new StreamNameIO( - StreamNameIO::CurrentInterface(), cipher, key ) ); - fsCfg->nameCoding->setChainedNameIV( true ); - - DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); - - if(!testNameCoding( dirNode, verbose )) - return false; - } - - if(verbose) - cerr << "Testing name encode/decode (block coding w/ IV chaining)\n"; - { - fsCfg->opts->idleTracking = false; - fsCfg->config->set_unique_iv(false); - fsCfg->nameCoding.reset( new BlockNameIO( - BlockNameIO::CurrentInterface(), cipher, key, - cipher->cipherBlockSize() ) ); - fsCfg->nameCoding->setChainedNameIV( true ); - - DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); - - if(!testNameCoding( dirNode, verbose )) - return false; - } - - if(verbose) - cerr << "Testing name encode/decode (block coding w/ IV chaining, base32)\n"; - { - fsCfg->opts->idleTracking = false; - fsCfg->config->set_unique_iv(false); - fsCfg->nameCoding.reset( new BlockNameIO( - BlockNameIO::CurrentInterface(), cipher, key, - cipher->cipherBlockSize(), true ) ); - fsCfg->nameCoding->setChainedNameIV( true ); - - DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); - - if(!testNameCoding( dirNode, verbose )) - return false; - } - - if(!verbose) - { - { - // test stream mode, this time without IV chaining - fsCfg->nameCoding = - shared_ptr( new StreamNameIO( - StreamNameIO::CurrentInterface(), cipher, key ) ); - fsCfg->nameCoding->setChainedNameIV( false ); - - DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); - - if(!testNameCoding( dirNode, verbose )) - return false; - } - - { - // test block mode, this time without IV chaining - fsCfg->nameCoding = shared_ptr( new BlockNameIO( - BlockNameIO::CurrentInterface(), cipher, key, - cipher->cipherBlockSize() ) ); - fsCfg->nameCoding->setChainedNameIV( false ); - - DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); - - if(!testNameCoding( dirNode, verbose )) - return false; - } - } - - if(verbose) - cerr << "Testing block encode/decode on full block - "; - { - int numErrors = checkErrorPropogation( cipher, - FSBlockSize, -1, key ); - if(numErrors) - { - if(verbose) - cerr << " FAILED!\n"; - return false; - } else - { - if(verbose) - cerr << " OK\n"; - } - } - if(verbose) - cerr << "Testing block encode/decode on partial block - "; - { - int numErrors = checkErrorPropogation( cipher, - FSBlockSize-1, -1, key ); - if(numErrors) - { - if(verbose) - cerr << " FAILED!\n"; - return false; - } else - { - if(verbose) - cerr << " OK\n"; - } - } - - if(verbose) - cerr << "Checking error propogation in partial block:\n"; - { - int minChanges = FSBlockSize-1; - int maxChanges = 0; - int minAt = 0; - int maxAt = 0; - for(int i=0; i maxChanges) - { - maxChanges = numErrors; - maxAt = i; - } - } - - if(verbose) - { - cerr << "modification of 1 byte affected between " << minChanges - << " and " << maxChanges << " decoded bytes\n"; - cerr << "minimum change at byte " << minAt - << " and maximum at byte " << maxAt << "\n"; - } - } - if(verbose) - cerr << "Checking error propogation on full block:\n"; - { - int minChanges = FSBlockSize; - int maxChanges = 0; - int minAt = 0; - int maxAt = 0; - for(int i=0; i maxChanges) - { - maxChanges = numErrors; - maxAt = i; - } - } - - if(verbose) - { - cerr << "modification of 1 byte affected between " << minChanges - << " and " << maxChanges << " decoded bytes\n"; - cerr << "minimum change at byte " << minAt - << " and maximum at byte " << maxAt << "\n"; - } - } - - return true; -} - - -int main(int argc, char *argv[]) -{ - RLogInit( argc, argv ); - - StdioNode stdLog( STDERR_FILENO ); - stdLog.subscribeTo( RLOG_CHANNEL("error") ); - stdLog.subscribeTo( RLOG_CHANNEL("warning") ); -#ifndef NO_DEBUG - stdLog.subscribeTo( RLOG_CHANNEL("debug") ); -#endif - -#ifdef HAVE_SSL - SSL_load_error_strings(); - SSL_library_init(); - -#ifndef OPENSSL_NO_ENGINE - ENGINE_load_builtin_engines(); - ENGINE_register_all_ciphers(); - ENGINE_register_all_digests(); - ENGINE_register_all_RAND(); -#endif -#endif - - srand( time(0) ); - - // get a list of the available algorithms - std::list algorithms = - Cipher::GetAlgorithmList(); - std::list::const_iterator it; - cerr << "Supported Crypto interfaces:\n"; - for(it = algorithms.begin(); it != algorithms.end(); ++it) - { - cerr << it->name - << " ( " << it->iface.name() << " " - << it->iface.major() << ":" - << it->iface.minor() << ":" - << it->iface.age() << " ) : " << it->description << "\n"; - cerr << " - key length " << it->keyLength.min() << " to " - << it->keyLength.max() << " , block size " << it->blockSize.min() - << " to " << it->blockSize.max() << "\n"; - } - cerr << "\n"; - - cerr << "Testing interfaces\n"; - for(it = algorithms.begin(); it != algorithms.end(); ++it) - { - int blockSize = it->blockSize.closest( 256 ); - for(int keySize = it->keyLength.min(); keySize <= it->keyLength.max(); - keySize += it->keyLength.inc()) - { - cerr << it->name << ", key length " << keySize - << ", block size " << blockSize << ": "; - - shared_ptr cipher = Cipher::New( it->name, keySize ); - if(!cipher) - { - cerr << "FAILED TO CREATE\n"; - } else - { - try - { - if(runTests( cipher, false )) - cerr << "OK\n"; - else - cerr << "FAILED\n"; - } catch( rlog::Error &er ) - { - cerr << "Error: " << er.what() << "\n"; - } - } - } - } - - // run one test with verbose output too.. - shared_ptr cipher = Cipher::New("AES", 192); - if(!cipher) - { - cerr << "\nNo AES cipher found, skipping verbose test.\n"; - } else - { - cerr << "\nVerbose output for " << cipher->interface().name() - << " test, key length " << cipher->keySize()*8 << ", block size " - << FSBlockSize << ":\n"; - - runTests( cipher, true ); - } - - MemoryPool::destroyAll(); - - return 0; -} - - - diff --git a/encfs/tests.t b/encfs/tests.t deleted file mode 100644 index 4c9e6c0..0000000 --- a/encfs/tests.t +++ /dev/null @@ -1,213 +0,0 @@ -#!/usr/bin/perl -w - -use Test::More qw( no_plan ); -use File::Path; -use IO::Handle; -use Digest::MD5; - -my $tempDir = $ENV{'TMPDIR'} || "/tmp"; - -my $raw = "$tempDir/crypt-raw-$$"; -my $crypt = "$tempDir/crypt-$$"; - - -# test filesystem in standard config mode -&runTests('standard'); - -# test in paranoia mode -&runTests('paranoia'); - - - -sub runTests -{ - my $mode = shift; - - my $hardlinks = 1; - if($mode eq 'standard') - { - &mount("--standard"); - } elsif($mode eq 'paranoia') - { - &mount("--paranoia"); - $hardlinks = 0; # no hardlinks in paranoia mode - } else - { - die "invalid test mode"; - } - - # tests.. - &fileCreation; - &links($hardlinks); - &truncate; - &renames; - - &cleanup; -} - -sub renames -{ - ok( open(F, ">$crypt/orig-name") && close F, "create file for rename test"); - ok( -f "$crypt/orig-name", "file exists"); - - ok( rename("$crypt/orig-name", "$crypt/2nd-name"), "rename"); - ok( ! -f "$crypt/orig-name", "file exists"); - ok( -f "$crypt/2nd-name", "file exists"); - - # rename directory with contents - ok( mkpath("$crypt/orig-dir/foo"), "mkdir for rename test"); - ok( open(F, ">$crypt/orig-dir/foo/bar") && close F, "make file"); - - ok( rename("$crypt/orig-dir", "$crypt/new-dir"), "rename dir"); - ok( -f "$crypt/new-dir/foo/bar", "dir rename contents"); - - # TODO: rename failure? (check undo works) - - # check time stamps of files on rename - my $mtime = (stat "$crypt/2nd-name")[9]; - # change time to 60 seconds earlier - my $olderTime = $mtime - 60; - ok( utime($olderTime, $olderTime, "$crypt/2nd-name"), "change time"); - - ok( rename("$crypt/2nd-name", "$crypt/3rd-name"), "rename"); - is( (stat "$crypt/3rd-name")[9], $olderTime, "time unchanged by rename"); -} - -sub truncate -{ - # write to file, then truncate it - ok( open(OUT, "+> $crypt/trunc"), "create truncate-test file"); - autoflush OUT 1; - print OUT "12345678901234567890"; - - is( -s "$crypt/trunc", 20, "initial file size" ); - - ok( truncate(OUT, 10), "truncate" ); - - is( -s "$crypt/trunc", 10, "truncated file size"); - is( qx(cat "$crypt/trunc"), "1234567890", "truncated file contents"); - - # try growing the file as well. - ok( truncate(OUT, 30), "truncate extend"); - is( -s "$crypt/trunc", 30, "truncated file size"); - - seek(OUT, 30, 0); - print OUT "12345"; - is( -s "$crypt/trunc", 35, "truncated file size"); - - seek(OUT, 0, 0); - is( Digest::MD5->new->addfile(*OUT)->hexdigest, - "5f170cc34b1944d75d86cc01496292df", "content digest"); - - # try crossing block boundaries - seek(OUT, 10000,0); - print OUT "abcde"; - seek(OUT, 0, 0); - is( Digest::MD5->new->addfile(*OUT)->hexdigest, - "117a51c980b64dcd21df097d02206f98", "content digest"); - - # then truncate back to 35 chars - truncate(OUT, 35); - seek(OUT, 0, 0); - is( Digest::MD5->new->addfile(*OUT)->hexdigest, - "5f170cc34b1944d75d86cc01496292df", "content digest"); - - close OUT; -} - -sub fileCreation -{ - # create a file - qx(df -ah > "$crypt/df.txt"); - ok( -f "$crypt/df.txt", "file created" ); - - # ensure there is an encrypted version. - my $c = qx(./encfsctl encode --extpass="echo test" $raw df.txt); - chomp($c); - cmp_ok( length($c), '>', 8, "encrypted name ok" ); - ok( -f "$raw/$c", "encrypted file created" ); - - # check contents - my $count = qx(grep -c crypt-$$ "$crypt/df.txt"); - isnt(scalar($count), 0, "encrypted file readable"); - - unlink "$crypt/df.txt"; - ok( ! -f "$crypt/df.txt", "file removal" ); - ok( ! -f "$raw/$c", "file removal" ); -} - -sub checkContents -{ - my ($file, $expected, $testName) = @_; - - open(IN, "< $file"); - my $line = ; - is( $line, $expected, $testName ); - - close IN; -} - -sub links -{ - my $hardlinkTests = shift; - - my $contents = "hello world\n"; - ok( open(OUT, "> $crypt/data"), "create file for link test" ); - print OUT $contents; - close OUT; - - # symlinks - ok( symlink("$crypt/data", "$crypt/data-fqn") , "fqn symlink"); - checkContents("$crypt/data-fqn", $contents, "fqn link traversal"); - is( readlink("$crypt/data-fqn"), "$crypt/data", "read fqn symlink"); - - ok( symlink("data", "$crypt/data-rel"), "local symlink"); - checkContents("$crypt/data-rel", $contents, "rel link traversal"); - is( readlink("$crypt/data-rel"), "data", "read rel symlink"); - - SKIP: { - skip "No hardlink support" unless $hardlinkTests; - - ok( link("$crypt/data", "$crypt/data.2"), "hard link"); - checkContents("$crypt/data.2", $contents, "hardlink read"); - }; -} - -sub mount -{ - my $args = shift; - - ok( ! -d $raw, "no existing dir"); - ok( ! -d $crypt, "no existing dir"); - - mkdir $raw; - ok( -d $raw, "created dir" ); - mkdir $crypt; - ok( -d $crypt, "created dir" ); - - qx(./encfs --extpass="echo test" $args $raw $crypt); - - ok( -f "$raw/.encfs6.xml", "created control file"); -} - -sub cleanup -{ - my $fusermount = qx(which fusermount); - if(-f $fusermount) - { - qx($fusermount -u "$crypt"); - } else - { - qx(umount "$crypt"); - } - - rmdir $crypt; - ok( ! -d $crypt, "unmount ok, mount point removed"); - - if(-d $raw) - { - rmtree($raw); - } - ok( ! -d $raw, "encrypted directory removed"); -} - diff --git a/fs/BlockFileIO.cpp b/fs/BlockFileIO.cpp new file mode 100644 index 0000000..2b0632e --- /dev/null +++ b/fs/BlockFileIO.cpp @@ -0,0 +1,426 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2004, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "fs/BlockFileIO.h" + +#include "base/config.pb.h" +#include "base/Error.h" +#include "base/i18n.h" +#include "cipher/MemoryPool.h" + +#include +#include + +template +inline Type min( Type A, Type B ) +{ + return (B < A) ? B : A; +} + +static void clearCache( IORequest &req, int blockSize ) +{ + memset( req.data, 0, blockSize ); + req.dataLen = 0; +} + +BlockFileIO::BlockFileIO( int blockSize, const FSConfigPtr &cfg ) + : _blockSize( blockSize ) + , _allowHoles( cfg->config->allow_holes() ) +{ + rAssert( _blockSize > 1 ); + _cache.data = new unsigned char [ _blockSize ]; +} + +BlockFileIO::~BlockFileIO() +{ + clearCache( _cache, _blockSize ); + delete[] _cache.data; +} + +ssize_t BlockFileIO::cacheReadOneBlock( const IORequest &req ) const +{ + // we can satisfy the request even if _cache.dataLen is too short, because + // we always request a full block during reads.. + if((req.offset == _cache.offset) && (_cache.dataLen != 0)) + { + // satisfy request from cache + int len = req.dataLen; + if(_cache.dataLen < len) + len = _cache.dataLen; + memcpy( req.data, _cache.data, len ); + return len; + } else + { + if(_cache.dataLen > 0) + clearCache( _cache, _blockSize ); + + // cache results of read -- issue reads for full blocks + IORequest tmp; + tmp.offset = req.offset; + tmp.data = _cache.data; + tmp.dataLen = _blockSize; + + ssize_t result = readOneBlock( tmp ); + if(result > 0) + { + _cache.offset = req.offset; + _cache.dataLen = result; // the amount we really have + if(result > req.dataLen) + result = req.dataLen; // only as much as requested + memcpy( req.data, _cache.data, result ); + } + return result; + } +} + +bool BlockFileIO::cacheWriteOneBlock( const IORequest &req ) +{ + // cache results of write (before pass-thru, because it may be modified + // in-place) + memcpy( _cache.data, req.data, req.dataLen ); + _cache.offset = req.offset; + _cache.dataLen = req.dataLen; + bool ok = writeOneBlock( req ); + if(!ok) + clearCache( _cache, _blockSize ); + return ok; +} + +ssize_t BlockFileIO::read( const IORequest &req ) const +{ + rAssert( _blockSize != 0 ); + + int partialOffset = req.offset % _blockSize; + off_t blockNum = req.offset / _blockSize; + ssize_t result = 0; + + if(partialOffset == 0 && req.dataLen <= _blockSize) + { + // read completely within a single block -- can be handled as-is by + // readOneBloc(). + return cacheReadOneBlock( req ); + } else + { + size_t size = req.dataLen; + + // if the request is larger then a block, then request each block + // individually + MemBlock mb; // in case we need to allocate a temporary block.. + IORequest blockReq; // for requests we may need to make + blockReq.dataLen = _blockSize; + blockReq.data = NULL; + + unsigned char *out = req.data; + while( size ) + { + blockReq.offset = blockNum * _blockSize; + + // if we're reading a full block, then read directly into the + // result buffer instead of using a temporary + if(partialOffset == 0 && size >= (size_t)_blockSize) + blockReq.data = out; + else + { + if(!mb.data) + mb.allocate( _blockSize ); + blockReq.data = mb.data; + } + + ssize_t readSize = cacheReadOneBlock( blockReq ); + if(readSize <= partialOffset) + break; // didn't get enough bytes + + int cpySize = min( (size_t)(readSize - partialOffset), size ); + rAssert(cpySize <= readSize); + + // if we read to a temporary buffer, then move the data + if(blockReq.data != out) + memcpy( out, blockReq.data + partialOffset, cpySize ); + + result += cpySize; + size -= cpySize; + out += cpySize; + ++blockNum; + partialOffset = 0; + + if(readSize < _blockSize) + break; + } + + return result; + } +} + +bool BlockFileIO::write( const IORequest &req ) +{ + rAssert( _blockSize != 0 ); + + off_t fileSize = getSize(); + + // where write request begins + off_t blockNum = req.offset / _blockSize; + int partialOffset = req.offset % _blockSize; + + // last block of file (for testing write overlaps with file boundary) + off_t lastFileBlock = fileSize / _blockSize; + ssize_t lastBlockSize = fileSize % _blockSize; + + off_t lastNonEmptyBlock = lastFileBlock; + if(lastBlockSize == 0) + --lastNonEmptyBlock; + + if( req.offset > fileSize ) + { + // extend file first to fill hole with 0's.. + const bool forceWrite = false; + padFile( fileSize, req.offset, forceWrite ); + } + + // check against edge cases where we can just let the base class handle the + // request as-is.. + if(partialOffset == 0 && req.dataLen <= _blockSize) + { + // if writing a full block.. pretty safe.. + if( req.dataLen == _blockSize ) + return cacheWriteOneBlock( req ); + + // if writing a partial block, but at least as much as what is + // already there.. + if(blockNum == lastFileBlock && req.dataLen >= lastBlockSize) + return cacheWriteOneBlock( req ); + } + + // have to merge data with existing block(s).. + MemBlock mb; + + IORequest blockReq; + blockReq.data = NULL; + blockReq.dataLen = _blockSize; + + bool ok = true; + size_t size = req.dataLen; + unsigned char *inPtr = req.data; + while( size ) + { + blockReq.offset = blockNum * _blockSize; + int toCopy = min((size_t)(_blockSize - partialOffset), size); + + // if writing an entire block, or writing a partial block that requires + // no merging with existing data.. + if( (toCopy == _blockSize) + ||(partialOffset == 0 && blockReq.offset + toCopy >= fileSize)) + { + // write directly from buffer + blockReq.data = inPtr; + blockReq.dataLen = toCopy; + } else + { + // need a temporary buffer, since we have to either merge or pad + // the data. + if(!mb.data) + mb.allocate( _blockSize ); + memset( mb.data, 0, _blockSize ); + blockReq.data = mb.data; + + if(blockNum > lastNonEmptyBlock) + { + // just pad.. + blockReq.dataLen = toCopy + partialOffset; + } else + { + // have to merge with existing block data.. + blockReq.dataLen = _blockSize; + blockReq.dataLen = cacheReadOneBlock( blockReq ); + + // extend data if necessary.. + if( partialOffset + toCopy > blockReq.dataLen ) + blockReq.dataLen = partialOffset + toCopy; + } + // merge in the data to be written.. + memcpy( blockReq.data + partialOffset, inPtr, toCopy ); + } + + // Finally, write the damn thing! + if(!cacheWriteOneBlock( blockReq )) + { + ok = false; + break; + } + + // prepare to start all over with the next block.. + size -= toCopy; + inPtr += toCopy; + ++blockNum; + partialOffset = 0; + } + + return ok; +} + +int BlockFileIO::blockSize() const +{ + return _blockSize; +} + +void BlockFileIO::padFile( off_t oldSize, off_t newSize, bool forceWrite ) +{ + off_t oldLastBlock = oldSize / _blockSize; + off_t newLastBlock = newSize / _blockSize; + int lastBlockSize = newSize % _blockSize; + + IORequest req; + MemBlock mb; + + if(oldLastBlock == newLastBlock) + { + // when the real write occurs, it will have to read in the existing + // data and pad it anyway, so we won't do it here (unless we're + // forced). + if( forceWrite ) + { + mb.allocate( _blockSize ); + req.data = mb.data; + + req.offset = oldLastBlock * _blockSize; + req.dataLen = oldSize % _blockSize; + int outSize = newSize % _blockSize; // outSize > req.dataLen + + if(outSize) + { + memset( mb.data, 0, outSize ); + cacheReadOneBlock( req ); + req.dataLen = outSize; + cacheWriteOneBlock( req ); + } + } else + VLOG(1) << "optimization: not padding last block"; + } else + { + mb.allocate( _blockSize ); + req.data = mb.data; + + // 1. extend the first block to full length + // 2. write the middle empty blocks + // 3. write the last block + + req.offset = oldLastBlock * _blockSize; + req.dataLen = oldSize % _blockSize; + + // 1. req.dataLen == 0, iff oldSize was already a multiple of blocksize + if(req.dataLen != 0) + { + VLOG(1) << "padding block " << oldLastBlock; + memset( mb.data, 0, _blockSize ); + cacheReadOneBlock( req ); + req.dataLen = _blockSize; // expand to full block size + cacheWriteOneBlock( req ); + ++oldLastBlock; + } + + // 2, pad zero blocks unless holes are allowed + if(!_allowHoles) + { + for(; oldLastBlock != newLastBlock; ++oldLastBlock) + { + VLOG(1) << "padding block " << oldLastBlock; + req.offset = oldLastBlock * _blockSize; + req.dataLen = _blockSize; + memset( mb.data, 0, req.dataLen ); + cacheWriteOneBlock( req ); + } + } + + // 3. only necessary if write is forced and block is non 0 length + if(forceWrite && lastBlockSize) + { + req.offset = newLastBlock * _blockSize; + req.dataLen = lastBlockSize; + memset( mb.data, 0, req.dataLen ); + cacheWriteOneBlock( req ); + } + } +} + +int BlockFileIO::blockTruncate( off_t size, FileIO *base ) +{ + rAssert(size >= 0); + + int partialBlock = size % _blockSize; + int res = 0; + + off_t oldSize = getSize(); + + if( size > oldSize ) + { + // truncate can be used to extend a file as well. truncate man page + // states that it will pad with 0's. + // do the truncate so that the underlying filesystem can allocate + // the space, and then we'll fill it in padFile.. + if(base) + base->truncate( size ); + + const bool forceWrite = true; + padFile( oldSize, size, forceWrite ); + } else + if( size == oldSize ) + { + // the easiest case, but least likely.... + } else + if( partialBlock ) + { + // partial block after truncate. Need to read in the block being + // truncated before the truncate. Then write it back out afterwards, + // since the encoding will change.. + off_t blockNum = size / _blockSize; + MemBlock mb; + mb.allocate( _blockSize ); + + IORequest req; + req.offset = blockNum * _blockSize; + req.dataLen = _blockSize; + req.data = mb.data; + + ssize_t rdSz = cacheReadOneBlock( req ); + + // do the truncate + if(base) + res = base->truncate( size ); + + // write back out partial block + req.dataLen = partialBlock; + bool wrRes = cacheWriteOneBlock( req ); + + if((rdSz < 0) || (!wrRes)) + { + LOG(ERROR) << "truncate failure: read size " << rdSz + << ", partial block of " << partialBlock; + } + + } else + { + // truncating on a block bounday. No need to re-encode the last + // block.. + if(base) + res = base->truncate( size ); + } + + return res; +} + diff --git a/encfs/BlockFileIO.h b/fs/BlockFileIO.h similarity index 97% rename from encfs/BlockFileIO.h rename to fs/BlockFileIO.h index 2a76d78..42acd54 100644 --- a/encfs/BlockFileIO.h +++ b/fs/BlockFileIO.h @@ -46,7 +46,7 @@ public: protected: - int truncate( off_t size, FileIO *base ); + int blockTruncate( off_t size, FileIO *base ); void padFile( off_t oldSize, off_t newSize, bool forceWrite ); // same as read(), except that the request.offset field is guarenteed to be diff --git a/fs/BlockNameIO.cpp b/fs/BlockNameIO.cpp new file mode 100644 index 0000000..69b4f91 --- /dev/null +++ b/fs/BlockNameIO.cpp @@ -0,0 +1,250 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2004-2011, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "fs/BlockNameIO.h" + +#include "base/base64.h" +#include "base/Error.h" +#include "base/i18n.h" +#include "cipher/Cipher.h" + +#include +#include + +static shared_ptr NewBlockNameIO( const Interface &iface, + const shared_ptr &cipher, const CipherKey &key ) +{ + return shared_ptr( + new BlockNameIO( iface, cipher, key, false)); +} + +static shared_ptr NewBlockNameIO32( const Interface &iface, + const shared_ptr &cipher, const CipherKey &key ) +{ + return shared_ptr( + new BlockNameIO( iface, cipher, key, true)); +} + +static bool BlockIO_registered = NameIO::Register("Block", + // description of block name encoding algorithm.. + // xgroup(setup) + gettext_noop("Block encoding, hides file name size somewhat"), + BlockNameIO::CurrentInterface(false), + NewBlockNameIO, false); + +static bool BlockIO32_registered = NameIO::Register("Block32", + // description of block name encoding algorithm.. + // xgroup(setup) + gettext_noop("Block encoding with base32 output for case-sensitive systems"), + BlockNameIO::CurrentInterface(true), + NewBlockNameIO32, false); + +/* + - Version 1.0 computed MAC over the filename, but not the padding bytes. + This version was from pre-release 1.1, never publically released, so no + backward compatibility necessary. + + - Version 2.0 includes padding bytes in MAC computation. This way the MAC + computation uses the same number of bytes regardless of the number of + padding bytes. + + - Version 3.0 uses full 64 bit initialization vector during IV chaining. + Prior versions used only the output from the MAC_16 call, giving a 1 in + 2^16 chance of the same name being produced. Using the full 64 bit IV + changes that to a 1 in 2^64 chance.. + + - Version 4.0 adds support for base32, creating names more suitable for + case-insensitive filesystems (eg Mac). + */ +Interface BlockNameIO::CurrentInterface(bool caseSensitive) +{ + // implement major version 4 plus support for two prior versions + if (caseSensitive) + return makeInterface("nameio/block32", 4, 0, 2); + else + return makeInterface("nameio/block", 4, 0, 2); +} + +BlockNameIO::BlockNameIO( const Interface &iface, + const shared_ptr &cipher, + const CipherKey &key, bool caseSensitiveEncoding ) + : _interface( iface.major() ) + , _bs( cipher->cipherBlockSize() ) + , _cipher( cipher ) + , _key( key ) + , _caseSensitive( caseSensitiveEncoding ) +{ + rAssert( _bs < 128 ); +} + +BlockNameIO::~BlockNameIO() +{ +} + +Interface BlockNameIO::interface() const +{ + return CurrentInterface(_caseSensitive); +} + +int BlockNameIO::maxEncodedNameLen( int plaintextNameLen ) const +{ + // number of blocks, rounded up.. Only an estimate at this point, err on + // the size of too much space rather then too little. + int numBlocks = ( plaintextNameLen + _bs ) / _bs; + int encodedNameLen = numBlocks * _bs + 2; // 2 checksum bytes + if (_caseSensitive) + return B256ToB32Bytes( encodedNameLen ); + else + return B256ToB64Bytes( encodedNameLen ); +} + +int BlockNameIO::maxDecodedNameLen( int encodedNameLen ) const +{ + int decLen256 = _caseSensitive ? + B32ToB256Bytes( encodedNameLen ) : + B64ToB256Bytes( encodedNameLen ); + return decLen256 - 2; // 2 checksum bytes removed.. +} + +int BlockNameIO::encodeName( const char *plaintextName, int length, + uint64_t *iv, char *encodedName ) const +{ + // copy the data into the encoding buffer.. + memcpy( encodedName+2, plaintextName, length ); + + // Pad encryption buffer to block boundary.. + int padding = _bs - length % _bs; + if(padding == 0) + padding = _bs; // padding a full extra block! + + memset( encodedName+length+2, (unsigned char)padding, padding ); + + // store the IV before it is modified by the MAC call. + uint64_t tmpIV = 0; + if( iv && _interface >= 3 ) + tmpIV = *iv; + + // include padding in MAC computation + unsigned int mac = _cipher->MAC_16( (unsigned char *)encodedName+2, + length+padding, _key, iv ); + + // add checksum bytes + encodedName[0] = (mac >> 8) & 0xff; + encodedName[1] = (mac ) & 0xff; + + _cipher->blockEncode( (unsigned char *)encodedName+2, length+padding, + (uint64_t)mac ^ tmpIV, _key); + + // convert to base 64 ascii + int encodedStreamLen = length + 2 + padding; + int encLen; + + if (_caseSensitive) + { + encLen = B256ToB32Bytes( encodedStreamLen ); + + changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen, + 8, 5, true ); + B32ToAscii( (unsigned char *)encodedName, encLen ); + } else + { + encLen = B256ToB64Bytes( encodedStreamLen ); + + changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen, + 8, 6, true ); + B64ToAscii( (unsigned char *)encodedName, encLen ); + } + + return encLen; +} + +int BlockNameIO::decodeName( const char *encodedName, int length, + uint64_t *iv, char *plaintextName ) const +{ + int decLen256 = _caseSensitive ? + B32ToB256Bytes( length ) : + B64ToB256Bytes( length ); + int decodedStreamLen = decLen256 - 2; + + // don't bother trying to decode files which are too small + if(decodedStreamLen < _bs) + throw Error("Filename too small to decode"); + + BUFFER_INIT( tmpBuf, 32, (unsigned int)length ); + + // decode into tmpBuf, + if (_caseSensitive) + { + AsciiToB32((unsigned char *)tmpBuf, (unsigned char *)encodedName, length); + changeBase2Inline((unsigned char *)tmpBuf, length, 5, 8, false); + } else + { + AsciiToB64((unsigned char *)tmpBuf, (unsigned char *)encodedName, length); + changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false); + } + + // pull out the header information + unsigned int mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 + | ((unsigned int)((unsigned char)tmpBuf[1])); + + uint64_t tmpIV = 0; + if( iv && _interface >= 3 ) + tmpIV = *iv; + + _cipher->blockDecode( (unsigned char *)tmpBuf+2, decodedStreamLen, + (uint64_t)mac ^ tmpIV, _key); + + // find out true string length + int padding = (unsigned char)tmpBuf[2+decodedStreamLen-1]; + int finalSize = decodedStreamLen - padding; + + // might happen if there is an error decoding.. + if(padding > _bs || finalSize < 0) + { + VLOG(1) << "padding, _bx, finalSize = " << padding + << ", " << _bs << ", " << finalSize; + throw Error( "invalid padding size" ); + } + + // copy out the result.. + memcpy(plaintextName, tmpBuf+2, finalSize); + plaintextName[finalSize] = '\0'; + + // check the mac + unsigned int mac2 = _cipher->MAC_16((const unsigned char *)tmpBuf+2, + decodedStreamLen, _key, iv); + + BUFFER_RESET( tmpBuf ); + + if(mac2 != mac) + { + LOG(INFO) << "checksum mismatch: expected " << mac << ", got " + << mac2 << " on decode of " << finalSize << " bytes"; + throw Error( "checksum mismatch in filename decode" ); + } + + return finalSize; +} + +bool BlockNameIO::Enabled() +{ + return true; +} + diff --git a/encfs/BlockNameIO.h b/fs/BlockNameIO.h similarity index 95% rename from encfs/BlockNameIO.h rename to fs/BlockNameIO.h index b57f5b3..832bad3 100644 --- a/encfs/BlockNameIO.h +++ b/fs/BlockNameIO.h @@ -21,8 +21,8 @@ #ifndef _BlockNameIO_incl_ #define _BlockNameIO_incl_ -#include "NameIO.h" -#include "CipherKey.h" +#include "cipher/CipherKey.h" +#include "fs/NameIO.h" #include @@ -40,7 +40,7 @@ public: BlockNameIO( const Interface &iface, const shared_ptr &cipher, - const CipherKey &key, int blockSize, + const CipherKey &key, bool caseSensitiveEncoding = false ); virtual ~BlockNameIO(); diff --git a/fs/CMakeLists.txt b/fs/CMakeLists.txt new file mode 100644 index 0000000..22ff52c --- /dev/null +++ b/fs/CMakeLists.txt @@ -0,0 +1,56 @@ +find_package (FUSE REQUIRED) +include_directories (${FUSE_INCLUDE_DIR}) + +enable_testing () +find_package (GTest) + +add_library (encfs-fs + encfs.cpp + Context.cpp + FileIO.cpp + RawFileIO.cpp + BlockFileIO.cpp + CipherFileIO.cpp + MACFileIO.cpp + NameIO.cpp + StreamNameIO.cpp + BlockNameIO.cpp + NullNameIO.cpp + DirNode.cpp + FileNode.cpp + FileUtils.cpp + ${PROTO_SRCS} + ${PROTO_HDRS} +) + +target_link_libraries (encfs-fs + ${PROTOBUF_LIBRARY} +) + +# Unit tests are optional, depends on libgtest (Google's C++ test framework). +if (GTEST_FOUND) + link_directories (${Encfs_BINARY_DIR}/base) + link_directories (${Encfs_BINARY_DIR}/cipher) + + include_directories (${GTEST_INCLUDE_DIR}) + add_executable (unittests + MemBlockFileIO.cpp + MemFileIO.cpp + testing.cpp + test_IO.cpp + test_BlockIO.cpp + ) + + target_link_libraries (unittests + ${GTEST_BOTH_LIBRARIES} + encfs-fs + encfs-cipher + encfs-base + ${GLOG_LIBRARIES} + ) + + add_test (UnitTests unittests) + GTEST_ADD_TESTS (unittests "${UnitTestArgs}" test_IO.cpp test_BlockIO.cpp) + add_custom_target (test COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS unittests) + +endif (GTEST_FOUND) diff --git a/fs/CipherFileIO.cpp b/fs/CipherFileIO.cpp new file mode 100644 index 0000000..11dcddf --- /dev/null +++ b/fs/CipherFileIO.cpp @@ -0,0 +1,513 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2004-2013, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "fs/CipherFileIO.h" + +#include "base/config.pb.h" +#include "base/Error.h" +#include "cipher/Cipher.h" +#include "cipher/MemoryPool.h" + +#include + +#include +#include + +/* + Version 3:0 adds support for block-only encryption by adding space for + a full block to the file header. + + Version 2:0 adds support for a per-file initialization vector with a + fixed 8 byte header. The headers are enabled globally within a + filesystem at the filesystem configuration level. + When headers are disabled, 2:0 is compatible with version 1:0. +*/ +static Interface CipherFileIO_iface = makeInterface("FileIO/Cipher", 3, 0, 2); + +CipherFileIO::CipherFileIO( const shared_ptr &_base, + const FSConfigPtr &cfg) + : BlockFileIO( cfg->config->block_size(), cfg ) + , base( _base ) + , headerLen( 0 ) + , blockOnlyMode( cfg->config->block_mode_only() ) + , perFileIV( cfg->config->unique_iv() ) + , externalIV( 0 ) + , fileIV( 0 ) + , lastFlags( 0 ) +{ + fsConfig = cfg; + cipher = cfg->cipher; + key = cfg->key; + + if ( blockOnlyMode ) + { + headerLen += blockSize(); + if ( perFileIV ) + headerLen += cipher->cipherBlockSize(); + } else + { + if ( perFileIV ) + headerLen += sizeof(uint64_t); // 64bit IV per file + } + + int blockBoundary = fsConfig->config->block_size() % + fsConfig->cipher->cipherBlockSize(); + if(blockBoundary != 0) + { + LOG_FIRST_N(ERROR, 1) + << "CipherFileIO: blocks should be multiple of cipher block size"; + } +} + +CipherFileIO::~CipherFileIO() +{ +} + +Interface CipherFileIO::interface() const +{ + return CipherFileIO_iface; +} + +int CipherFileIO::open( int flags ) +{ + int res = base->open( flags ); + + if( res >= 0 ) + lastFlags = flags; + + return res; +} + +void CipherFileIO::setFileName( const char *fileName ) +{ + base->setFileName( fileName ); +} + +const char *CipherFileIO::getFileName() const +{ + return base->getFileName(); +} + +bool CipherFileIO::setIV( uint64_t iv ) +{ + VLOG(1) << "in setIV, current IV = " << externalIV + << ", new IV = " << iv << ", fileIV = " << fileIV; + if(externalIV == 0) + { + // we're just being told about which IV to use. since we haven't + // initialized the fileIV, there is no need to just yet.. + externalIV = iv; + LOG_IF(WARNING, fileIV != 0) + << "fileIV initialized before externalIV! (" << fileIV + << ", " << externalIV << ")"; + } else if(perFileIV) + { + // we have an old IV, and now a new IV, so we need to update the fileIV + // on disk. + if(fileIV == 0) + { + // ensure the file is open for read/write.. + int newFlags = lastFlags | O_RDWR; + int res = base->open( newFlags ); + if(res < 0) + { + if(res == -EISDIR) + { + // duh -- there are no file headers for directories! + externalIV = iv; + return base->setIV( iv ); + } else + { + VLOG(1) << "writeHeader failed to re-open for write"; + return false; + } + } + initHeader(); + } + + uint64_t oldIV = externalIV; + externalIV = iv; + if(!writeHeader()) + { + externalIV = oldIV; + return false; + } + } + + return base->setIV( iv ); +} + +off_t CipherFileIO::adjustedSize(off_t rawSize) const +{ + off_t size = rawSize; + + if (rawSize >= headerLen) + size -= headerLen; + + return size; +} + +int CipherFileIO::getAttr( struct stat *stbuf ) const +{ + int res = base->getAttr( stbuf ); + + // adjust size if we have a file header + if((res == 0) && S_ISREG(stbuf->st_mode)) + stbuf->st_size = adjustedSize(stbuf->st_size); + + return res; +} + +off_t CipherFileIO::getSize() const +{ + // No check on S_ISREG here -- getSize only for normal files! + off_t size = base->getSize(); + return adjustedSize(size); +} + +void CipherFileIO::initHeader( ) +{ + int cbs = cipher->cipherBlockSize(); + + MemBlock mb; + mb.allocate(cbs); + + // check if the file has a header, and read it if it does.. Otherwise, + // create one. + off_t rawSize = base->getSize(); + if(rawSize >= headerLen) + { + VLOG(1) << "reading existing header, rawSize = " << rawSize; + + IORequest req; + req.offset = 0; + if (blockOnlyMode) + req.offset += blockSize(); + + req.data = mb.data; + req.dataLen = blockOnlyMode ? cbs : sizeof(uint64_t); + base->read( req ); + + if (perFileIV) + { + if (blockOnlyMode) + cipher->blockDecode( mb.data, cbs, externalIV, key ); + else + cipher->streamDecode( mb.data, sizeof(uint64_t), externalIV, key ); + + fileIV = 0; + for(unsigned int i=0; irandomize( mb.data, 8, false )) + throw Error("Unable to generate a random file IV"); + + fileIV = 0; + for(unsigned int i=0; iblockEncode( mb.data, cbs, externalIV, key ); + else + cipher->streamEncode( mb.data, sizeof(uint64_t), externalIV, key ); + + if( base->isWritable() ) + { + IORequest req; + req.offset = 0; + if (blockOnlyMode) + req.offset += blockSize(); + + req.data = mb.data; + req.dataLen = blockOnlyMode ? cbs : sizeof(uint64_t); + + base->write( req ); + } else + VLOG(1) << "base not writable, IV not written.."; + } + VLOG(1) << "initHeader finished, fileIV = " << fileIV; +} + +bool CipherFileIO::writeHeader( ) +{ + if( !base->isWritable() ) + { + // open for write.. + int newFlags = lastFlags | O_RDWR; + if( base->open( newFlags ) < 0 ) + { + VLOG(1) << "writeHeader failed to re-open for write"; + return false; + } + } + + LOG_IF(ERROR, fileIV == 0) + << "Internal error: fileIV == 0 in writeHeader!!!"; + VLOG(1) << "writing fileIV " << fileIV; + + MemBlock mb; + mb.allocate(headerLen); + + if (perFileIV) + { + int cbs = cipher->cipherBlockSize(); + unsigned char *buf = mb.data + (blockOnlyMode ? blockSize() : 0); + + for(int i=sizeof(buf)-1; i>=0; --i) + { + buf[i] = (unsigned char)(fileIV & 0xff); + fileIV >>= 8; + } + + if (blockOnlyMode) + cipher->blockEncode( buf, cbs, externalIV, key ); + else + cipher->streamEncode( buf, sizeof(uint64_t), externalIV, key); + } + + IORequest req; + req.offset = 0; + req.data = mb.data; + req.dataLen = headerLen; + + base->write( req ); + + return true; +} + +ssize_t CipherFileIO::readOneBlock( const IORequest &req ) const +{ + // read raw data, then decipher it.. + int bs = blockSize(); + rAssert(req.dataLen <= bs); + + off_t blockNum = req.offset / bs; + + ssize_t readSize = 0; + IORequest tmpReq = req; + + MemBlock mb; + if (headerLen != 0) + tmpReq.offset += headerLen; + + int maxReadSize = req.dataLen; + if (blockOnlyMode) + { + off_t size = getSize(); + if (req.offset + req.dataLen > size) + { + // Last block written as full block at front of the file header. + mb.allocate(bs); + + tmpReq.offset = 0; + tmpReq.dataLen = bs; + tmpReq.data = mb.data; + + // TODO: what is the expected behavior if req.offset >= size? + maxReadSize = size - req.offset; + if (maxReadSize <= 0) + return 0; + } + } + + readSize = base->read( tmpReq ); + + bool ok; + if(readSize > 0) + { + if(headerLen != 0 && fileIV == 0) + const_cast(this)->initHeader(); + + if(blockOnlyMode || readSize == bs) + { + ok = blockRead( tmpReq.data, bs, blockNum ^ fileIV); + } else + { + ok = streamRead( tmpReq.data, (int)readSize, blockNum ^ fileIV); + } + + if(!ok) + { + VLOG(1) << "decodeBlock failed for block " << blockNum + << ", size " << readSize; + readSize = -1; + } else if (tmpReq.data != req.data) + { + if (readSize > maxReadSize) + readSize = maxReadSize; + memcpy(req.data, tmpReq.data, readSize); + } + } else + VLOG(1) << "readSize zero for offset " << req.offset; + + return readSize; +} + + +bool CipherFileIO::writeOneBlock( const IORequest &req ) +{ + int bs = blockSize(); + int cbs = cipher->cipherBlockSize(); + off_t blockNum = req.offset / bs; + + if(headerLen != 0 && fileIV == 0) + initHeader(); + + MemBlock mb; + + bool ok; + if (req.dataLen == bs) + { + ok = blockWrite( req.data, bs, blockNum ^ fileIV ); + } else if (blockOnlyMode) + { + mb.allocate(bs); + cipher->randomize(mb.data + bs - cbs, cbs, false); + memcpy(mb.data, req.data, req.dataLen); + + ok = blockWrite( mb.data, bs, blockNum ^ fileIV ); + } else + { + ok = streamWrite( req.data, (int)req.dataLen, + blockNum ^ fileIV ); + } + + if( ok ) + { + if(headerLen != 0) + { + IORequest nreq = req; + + if (mb.data == NULL) + { + nreq.offset += headerLen; + } else + { + // Partial block is stored at front of file. + nreq.offset = 0; + nreq.data = mb.data; + nreq.dataLen = bs; + base->truncate(req.offset + req.dataLen + headerLen); + } + + ok = base->write( nreq ); + } else + ok = base->write( req ); + } else + { + VLOG(1) << "encodeBlock failed for block " << blockNum + << ", size " << req.dataLen; + ok = false; + } + return ok; +} + +bool CipherFileIO::blockWrite( unsigned char *buf, int size, + uint64_t _iv64 ) const +{ + if (!fsConfig->reverseEncryption) + return cipher->blockEncode( buf, size, _iv64, key ); + else + return cipher->blockDecode( buf, size, _iv64, key ); +} + +bool CipherFileIO::streamWrite( unsigned char *buf, int size, + uint64_t _iv64 ) const +{ + if (!fsConfig->reverseEncryption) + return cipher->streamEncode( buf, size, _iv64, key ); + else + return cipher->streamDecode( buf, size, _iv64, key ); +} + + +bool CipherFileIO::blockRead( unsigned char *buf, int size, + uint64_t _iv64 ) const +{ + if (fsConfig->reverseEncryption) + return cipher->blockEncode( buf, size, _iv64, key ); + else if(_allowHoles) + { + // special case - leave all 0's alone + for(int i=0; iblockDecode( buf, size, _iv64, key ); + + return true; + } else + return cipher->blockDecode( buf, size, _iv64, key ); +} + +bool CipherFileIO::streamRead( unsigned char *buf, int size, + uint64_t _iv64 ) const +{ + if (fsConfig->reverseEncryption) + return cipher->streamEncode( buf, size, _iv64, key ); + else + return cipher->streamDecode( buf, size, _iv64, key ); +} + +int CipherFileIO::truncate( off_t size ) +{ + rAssert(size >= 0); + + if(headerLen == 0) + { + return blockTruncate( size, base.get() ); + } else if(0 == fileIV) + { + // empty file.. create the header.. + if( !base->isWritable() ) + { + // open for write.. + int newFlags = lastFlags | O_RDWR; + if( base->open( newFlags ) < 0 ) + VLOG(1) << "writeHeader failed to re-open for write"; + } + initHeader(); + } + + // can't let BlockFileIO call base->truncate(), since it would be using + // the wrong size.. + int res = blockTruncate( size, 0 ); + + if(res == 0) + base->truncate( size + headerLen ); + + return res; +} + +bool CipherFileIO::isWritable() const +{ + return base->isWritable(); +} + diff --git a/encfs/CipherFileIO.h b/fs/CipherFileIO.h similarity index 85% rename from encfs/CipherFileIO.h rename to fs/CipherFileIO.h index 90dfc11..efc1dcd 100644 --- a/encfs/CipherFileIO.h +++ b/fs/CipherFileIO.h @@ -21,9 +21,9 @@ #ifndef _CipherFileIO_incl_ #define _CipherFileIO_incl_ -#include "BlockFileIO.h" -#include "CipherKey.h" -#include "FileUtils.h" +#include "cipher/CipherKey.h" +#include "fs/BlockFileIO.h" +#include "fs/FileUtils.h" #include @@ -52,6 +52,9 @@ public: virtual int getAttr( struct stat *stbuf ) const; virtual off_t getSize() const; + // NOTE: if truncate is used to extend the file, the extended plaintext is + // not 0. The extended ciphertext may be 0, resulting in non-zero + // plaintext. virtual int truncate( off_t size ); virtual bool isWritable() const; @@ -71,13 +74,18 @@ private: bool streamWrite( unsigned char *buf, int size, uint64_t iv64 ) const; + off_t adjustedSize(off_t size) const; + shared_ptr base; FSConfigPtr fsConfig; // if haveHeader is true, then we have a transparent file header which - // contains a 64 bit initialization vector. - bool haveHeader; + int headerLen; + // Use block only encryption, no stream encryption. + bool blockOnlyMode; + + bool perFileIV; bool externalIVChaining; uint64_t externalIV; uint64_t fileIV; diff --git a/fs/Context.cpp b/fs/Context.cpp new file mode 100644 index 0000000..b24d06a --- /dev/null +++ b/fs/Context.cpp @@ -0,0 +1,175 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2007, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "base/Mutex.h" +#include "base/Error.h" +#include "fs/FileNode.h" +#include "fs/Context.h" +#include "fs/FileUtils.h" +#include "fs/DirNode.h" + +using namespace rel; + +EncFS_Context::EncFS_Context() +{ + pthread_cond_init( &wakeupCond, 0 ); + pthread_mutex_init( &wakeupMutex, 0 ); + pthread_mutex_init( &contextMutex, 0 ); + + usageCount = 0; +} + +EncFS_Context::~EncFS_Context() +{ + pthread_mutex_destroy( &contextMutex ); + pthread_mutex_destroy( &wakeupMutex ); + pthread_cond_destroy( &wakeupCond ); + + // release all entries from map + openFiles.clear(); +} + +shared_ptr EncFS_Context::getRoot(int *errCode) +{ + shared_ptr ret; + do + { + { + Lock lock( contextMutex ); + ret = root; + ++usageCount; + } + + if(!ret) + { + int res = remountFS( this ); + if(res != 0) + { + *errCode = res; + break; + } + } + } while(!ret); + + return ret; +} + +void EncFS_Context::setRoot(const shared_ptr &r) +{ + Lock lock( contextMutex ); + + root = r; + if(r) + rootCipherDir = r->rootDirectory(); +} + +bool EncFS_Context::isMounted() +{ + return root; +} + +int EncFS_Context::getAndResetUsageCounter() +{ + Lock lock( contextMutex ); + + int count = usageCount; + usageCount = 0; + + return count; +} + +int EncFS_Context::openFileCount() const +{ + Lock lock( contextMutex ); + + return openFiles.size(); +} + +shared_ptr EncFS_Context::lookupNode(const char *path) +{ + Lock lock( contextMutex ); + + FileMap::iterator it = openFiles.find( std::string(path) ); + if(it != openFiles.end()) + { + // all the items in the set point to the same node.. so just use the + // first + return (*it->second.begin())->node; + } else + { + return shared_ptr(); + } +} + +void EncFS_Context::renameNode(const char *from, const char *to) +{ + Lock lock( contextMutex ); + + FileMap::iterator it = openFiles.find( std::string(from) ); + if(it != openFiles.end()) + { + std::set val = it->second; + openFiles.erase(it); + openFiles[ std::string(to) ] = val; + } +} + +shared_ptr EncFS_Context::getNode(void *pl) +{ + Placeholder *ph = (Placeholder*)pl; + return ph->node; +} + +void *EncFS_Context::putNode(const char *path, + const shared_ptr &node) +{ + Lock lock( contextMutex ); + Placeholder *pl = new Placeholder( node ); + openFiles[ std::string(path) ].insert(pl); + + return (void *)pl; +} + +void EncFS_Context::eraseNode(const char *path, void *pl) +{ + Lock lock( contextMutex ); + + Placeholder *ph = (Placeholder *)pl; + + FileMap::iterator it = openFiles.find( std::string(path) ); + rAssert(it != openFiles.end()); + + int rmCount = it->second.erase( ph ); + + rAssert(rmCount == 1); + + // if no more references to this file, remove the record all together + if(it->second.empty()) + { + // attempts to make use of shallow copy to clear memory used to hold + // unencrypted filenames.. not sure this does any good.. + std::string storedName = it->first; + openFiles.erase( it ); + storedName.assign( storedName.length(), '\0' ); + } + + delete ph; +} + diff --git a/encfs/Context.h b/fs/Context.h similarity index 97% rename from encfs/Context.h rename to fs/Context.h index 282dad5..0f470a4 100644 --- a/encfs/Context.h +++ b/fs/Context.h @@ -21,11 +21,11 @@ #ifndef _Context_incl_ #define _Context_incl_ -#include "encfs.h" -#include "shared_ptr.h" +#include "base/shared_ptr.h" +#include "fs/encfs.h" #include -#if HAVE_TR1_UNORDERED_MAP +#ifdef HAVE_TR1_UNORDERED_MAP #include using std::tr1::unordered_map; #else diff --git a/fs/DirNode.cpp b/fs/DirNode.cpp new file mode 100644 index 0000000..8a967e0 --- /dev/null +++ b/fs/DirNode.cpp @@ -0,0 +1,816 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2003-2004, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "fs/encfs.h" + +#include +#include +#include +#include +#include +#include +#include +#ifdef linux +#include +#endif + +#include + +#include "cipher/Cipher.h" +#include "base/Error.h" +#include "base/Mutex.h" +#include "fs/Context.h" +#include "fs/DirNode.h" +#include "fs/FileUtils.h" + + +#include + +#include + +using namespace std; +using namespace rel; + +class DirDeleter +{ +public: + void operator () ( DIR *d ) + { + ::closedir( d ); + } +}; + + +DirTraverse::DirTraverse(const shared_ptr &_dirPtr, + uint64_t _iv, const shared_ptr &_naming) + : dir( _dirPtr ) + , iv( _iv ) + , naming( _naming ) +{ +} + +DirTraverse::DirTraverse(const DirTraverse &src) + : dir( src.dir ) + , iv( src.iv ) + , naming( src.naming ) +{ +} + +DirTraverse &DirTraverse::operator = (const DirTraverse &src) +{ + dir = src.dir; + iv = src.iv; + naming = src.naming; + + return *this; +} + +DirTraverse::~DirTraverse() +{ + dir.reset(); + iv = 0; + naming.reset(); +} + +static +bool _nextName(struct dirent *&de, const shared_ptr &dir, + int *fileType, ino_t *inode) +{ + de = ::readdir( dir.get() ); + + if(de) + { + if(fileType) + { +#if defined(_DIRENT_HAVE_D_TYPE) || defined(__FreeBSD__) + *fileType = de->d_type; +#else +#warning "struct dirent.d_type not supported" + *fileType = 0; +#endif + } + if(inode) + *inode = de->d_ino; + return true; + } else + { + if(fileType) + *fileType = 0; + return false; + } +} + + +std::string DirTraverse::nextPlaintextName(int *fileType, ino_t *inode) +{ + struct dirent *de=0; + while(_nextName(de, dir, fileType, inode)) + { + try + { + uint64_t localIv = iv; + return naming->decodePath( de->d_name, &localIv ); + } catch ( Error &ex ) + { + // .. .problem decoding, ignore it and continue on to next name.. + VLOG(1) << "error decoding filename " << de->d_name + << " : " << ex.what(); + } + } + + return string(); +} + +std::string DirTraverse::nextInvalid() +{ + struct dirent *de=0; + // find the first name which produces a decoding error... + while(_nextName(de, dir, (int*)0, (ino_t*)0)) + { + try + { + uint64_t localIv = iv; + naming->decodePath( de->d_name, &localIv ); + continue; + } catch( Error &ex ) + { + return string( de->d_name ); + } + } + + return string(); +} + +struct RenameEl +{ + // ciphertext names + string oldCName; + string newCName; // intermediate name (not final cname) + + // plaintext names + string oldPName; + string newPName; + + bool isDirectory; +}; + +class RenameOp +{ +private: + DirNode *dn; + shared_ptr< list > renameList; + list::const_iterator last; + +public: + RenameOp( DirNode *_dn, const shared_ptr< list > &_renameList ) + : dn(_dn), renameList(_renameList) + { + last = renameList->begin(); + } + + RenameOp(const RenameOp &src) + : dn(src.dn) + , renameList(src.renameList) + , last(src.last) + { + } + + ~RenameOp(); + + operator bool () const + { + return renameList; + } + + bool apply(); + void undo(); +}; + +RenameOp::~RenameOp() +{ + if(renameList) + { + // got a bunch of decoded filenames sitting in memory.. do a little + // cleanup before leaving.. + list::iterator it; + for(it = renameList->begin(); it != renameList->end(); ++it) + { + it->oldPName.assign( it->oldPName.size(), ' ' ); + it->newPName.assign( it->newPName.size(), ' ' ); + } + } +} + +bool RenameOp::apply() +{ + try + { + while(last != renameList->end()) + { + // backing store rename. + VLOG(2) << "renaming " << last->oldCName << "-> " << last->newCName; + + struct stat st; + bool preserve_mtime = ::stat(last->oldCName.c_str(), &st) == 0; + + // internal node rename.. + dn->renameNode( last->oldPName.c_str(), + last->newPName.c_str() ); + + // rename on disk.. + if(::rename( last->oldCName.c_str(), + last->newCName.c_str() ) == -1) + { + LOG(WARNING) << "Error renaming " << last->oldCName << ": " << + strerror(errno); + dn->renameNode( last->newPName.c_str(), + last->oldPName.c_str(), false ); + return false; + } + + if(preserve_mtime) + { + struct utimbuf ut; + ut.actime = st.st_atime; + ut.modtime = st.st_mtime; + ::utime(last->newCName.c_str(), &ut); + } + + ++last; + } + + return true; + } catch( Error &err ) + { + LOG(WARNING) << "caught error in rename application: " << err.what(); + return false; + } +} + +void RenameOp::undo() +{ + VLOG(1) << "in undoRename"; + + if(last == renameList->begin()) + { + VLOG(1) << "nothing to undo"; + return; // nothing to undo + } + + // list has to be processed backwards, otherwise we may rename + // directories and directory contents in the wrong order! + int undoCount = 0; + int errorCount = 0; + list::const_iterator it = last; + + while( it != renameList->begin() ) + { + --it; + + VLOG(1) << "undo: renaming " << it->newCName << " -> " << it->oldCName; + + ::rename( it->newCName.c_str(), it->oldCName.c_str() ); + try + { + dn->renameNode( it->newPName.c_str(), + it->oldPName.c_str(), false ); + } catch( Error &err ) + { + if (++errorCount == 1) + LOG(WARNING) << "error in rename und: " << err.what(); + // continue on anyway... + } + ++undoCount; + }; + + LOG(WARNING) << "Undo rename count: " << undoCount; +} + +DirNode::DirNode(EncFS_Context *_ctx, + const string &sourceDir, + const FSConfigPtr &_config) +{ + pthread_mutex_init( &mutex, 0 ); + + Lock _lock( mutex ); + + ctx = _ctx; + rootDir = sourceDir; + fsConfig = _config; + + // make sure rootDir ends in '/', so that we can form a path by appending + // the rest.. + if( rootDir[ rootDir.length()-1 ] != '/' ) + rootDir.append( 1, '/'); + + naming = fsConfig->nameCoding; +} + +DirNode::~DirNode() +{ +} + +bool DirNode::hasDirectoryNameDependency() const +{ + return naming ? naming->getChainedNameIV() : false; +} + +string DirNode::rootDirectory() +{ + // don't update last access here, otherwise 'du' would cause lastAccess to + // be reset. + // chop off '/' terminator from root dir. + return string( rootDir, 0, rootDir.length()-1 ); +} + +string DirNode::cipherPath( const char *plaintextPath ) +{ + return rootDir + naming->encodePath( plaintextPath ); +} + +string DirNode::cipherPathWithoutRoot( const char *plaintextPath ) +{ + return naming->encodePath( plaintextPath ); +} + +string DirNode::plainPath( const char *cipherPath_ ) +{ + try + { + if( !strncmp( cipherPath_, rootDir.c_str(), + rootDir.length() ) ) + { + return naming->decodePath( cipherPath_ + rootDir.length() ); + } else + { + if ( cipherPath_[0] == '+' ) + { + // decode as fully qualified path + return string("/") + naming->decodeName( cipherPath_+1, + strlen(cipherPath_+1) ); + } else + { + return naming->decodePath( cipherPath_ ); + } + } + + } catch( Error &err ) + { + LOG(ERROR) << "decode err: " << err.what(); + return string(); + } +} + +string DirNode::relativeCipherPath( const char *plaintextPath ) +{ + try + { + if(plaintextPath[0] == '/') + { + // mark with '+' to indicate special decoding.. + return string("+") + naming->encodeName(plaintextPath+1, + strlen(plaintextPath+1)); + } else + { + return naming->encodePath( plaintextPath ); + } + } catch( Error &err ) + { + LOG(ERROR) << "encode err: " << err.what(); + return string(); + } +} + +DirTraverse DirNode::openDir(const char *plaintextPath) +{ + string cyName = rootDir + naming->encodePath( plaintextPath ); + //rDebug("openDir on %s", cyName.c_str() ); + + DIR *dir = ::opendir( cyName.c_str() ); + if(dir == NULL) + { + VLOG(1) << "opendir error " << strerror(errno); + return DirTraverse( shared_ptr(), 0, shared_ptr() ); + } else + { + shared_ptr dp( dir, DirDeleter() ); + + uint64_t iv = 0; + // if we're using chained IV mode, then compute the IV at this + // directory level.. + try + { + if( naming->getChainedNameIV() ) + naming->encodePath( plaintextPath, &iv ); + } catch( Error &err ) + { + LOG(ERROR) << "encode err: " << err.what(); + } + return DirTraverse( dp, iv, naming ); + } +} + +bool DirNode::genRenameList( list &renameList, + const char *fromP, const char *toP ) +{ + uint64_t fromIV = 0, toIV = 0; + + // compute the IV for both paths + string fromCPart = naming->encodePath( fromP, &fromIV ); + string toCPart = naming->encodePath( toP, &toIV ); + + // where the files live before the rename.. + string sourcePath = rootDir + fromCPart; + + // ok..... we wish it was so simple.. should almost never happen + if(fromIV == toIV) + return true; + + // generate the real destination path, where we expect to find the files.. + VLOG(1) << "opendir " << sourcePath; + shared_ptr dir = shared_ptr( + opendir( sourcePath.c_str() ), DirDeleter() ); + if(!dir) + return false; + + struct dirent *de = NULL; + while((de = ::readdir( dir.get() )) != NULL) + { + // decode the name using the oldIV + uint64_t localIV = fromIV; + string plainName; + + if((de->d_name[0] == '.') && + ((de->d_name[1] == '\0') + || ((de->d_name[1] == '.') && (de->d_name[2] == '\0')))) + { + // skip "." and ".." + continue; + } + + try + { + plainName = naming->decodePath( de->d_name, &localIV ); + } catch( Error &ex ) + { + // if filename can't be decoded, then ignore it.. + continue; + } + + // any error in the following will trigger a rename failure. + try + { + // re-encode using the new IV.. + localIV = toIV; + string newName = naming->encodePath( plainName.c_str(), &localIV ); + + // store rename information.. + string oldFull = sourcePath + '/' + de->d_name; + string newFull = sourcePath + '/' + newName; + + RenameEl ren; + ren.oldCName = oldFull; + ren.newCName = newFull; + ren.oldPName = string(fromP) + '/' + plainName; + ren.newPName = string(toP) + '/' + plainName; + + bool isDir; +#if defined(_DIRENT_HAVE_D_TYPE) + if(de->d_type != DT_UNKNOWN) + { + isDir = (de->d_type == DT_DIR); + } else +#endif + { + isDir = isDirectory( oldFull.c_str() ); + } + + ren.isDirectory = isDir; + + if(isDir) + { + // recurse.. We want to add subdirectory elements before the + // parent, as that is the logical rename order.. + if(!genRenameList( renameList, + ren.oldPName.c_str(), + ren.newPName.c_str())) + { + return false; + } + } + + VLOG(1) << "adding file " << oldFull << " to rename list"; + renameList.push_back( ren ); + + } catch( Error &err ) + { + // We can't convert this name, because we don't have a valid IV for + // it (or perhaps a valid key).. It will be inaccessible.. + LOG(WARNING) << "Aborting rename: error on file " << + fromCPart.append(1, '/').append(de->d_name) << ":" << err.what(); + + // abort.. Err on the side of safety and disallow rename, rather + // then loosing files.. + return false; + } + } + + return true; +} + + +/* + A bit of a pain.. If a directory is renamed in a filesystem with + directory initialization vector chaining, then we have to recursively + rename every descendent of this directory, as all initialization vectors + will have changed.. + + Returns a list of renamed items on success, a null list on failure. +*/ +shared_ptr +DirNode::newRenameOp( const char *fromP, const char *toP ) +{ + // Do the rename in two stages to avoid chasing our tail + // Undo everything if we encounter an error! + shared_ptr< list > renameList(new list); + if(!genRenameList( *renameList.get(), fromP, toP )) + { + LOG(WARNING) << "Error during generation of recursive rename list"; + return shared_ptr(); + } else + return shared_ptr( new RenameOp(this, renameList) ); +} + + +int DirNode::mkdir(const char *plaintextPath, mode_t mode, + uid_t uid, gid_t gid) +{ + string cyName = rootDir + naming->encodePath( plaintextPath ); + rAssert( !cyName.empty() ); + + VLOG(1) << "mkdir on " << cyName; + + // if uid or gid are set, then that should be the directory owner + int olduid = -1; + int oldgid = -1; + if(uid != 0) + olduid = setfsuid( uid ); + if(gid != 0) + oldgid = setfsgid( gid ); + + int res = ::mkdir( cyName.c_str(), mode ); + + if(olduid >= 0) + setfsuid( olduid ); + if(oldgid >= 0) + setfsgid( oldgid ); + + if(res == -1) + { + int eno = errno; + LOG(WARNING) << "mkdir error on " << cyName + << " mode " << mode << ": " << strerror(eno); + res = -eno; + } else + res = 0; + + return res; +} + +int +DirNode::rename( const char *fromPlaintext, const char *toPlaintext ) +{ + Lock _lock( mutex ); + + string fromCName = rootDir + naming->encodePath( fromPlaintext ); + string toCName = rootDir + naming->encodePath( toPlaintext ); + rAssert( !fromCName.empty() ); + rAssert( !toCName.empty() ); + + VLOG(1) << "rename " << fromCName << " -> " << toCName; + + shared_ptr toNode = findOrCreate( toPlaintext ); + + shared_ptr renameOp; + if( hasDirectoryNameDependency() && isDirectory( fromCName.c_str() )) + { + VLOG(1) << "recursive rename begin"; + renameOp = newRenameOp( fromPlaintext, toPlaintext ); + + if(!renameOp || !renameOp->apply()) + { + if(renameOp) + renameOp->undo(); + + LOG(WARNING) << "rename aborted"; + return -EACCES; + } + VLOG(1) << "recursive rename end"; + } + + int res = 0; + try + { + struct stat st; + bool preserve_mtime = ::stat(fromCName.c_str(), &st) == 0; + + renameNode( fromPlaintext, toPlaintext ); + res = ::rename( fromCName.c_str(), toCName.c_str() ); + + if(res == -1) + { + // undo + res = -errno; + renameNode( toPlaintext, fromPlaintext, false ); + + if(renameOp) + renameOp->undo(); + } else if(preserve_mtime) + { + struct utimbuf ut; + ut.actime = st.st_atime; + ut.modtime = st.st_mtime; + ::utime(toCName.c_str(), &ut); + } + } catch( Error &err ) + { + // exception from renameNode, just show the error and continue.. + LOG(ERROR) << "rename err: " << err.what(); + res = -EIO; + } + + if(res != 0) + { + VLOG(1) << "rename failed: " << strerror( errno ); + res = -errno; + } + + return res; +} + +int DirNode::link( const char *from, const char *to ) +{ + Lock _lock( mutex ); + + string fromCName = rootDir + naming->encodePath( from ); + string toCName = rootDir + naming->encodePath( to ); + + rAssert( !fromCName.empty() ); + rAssert( !toCName.empty() ); + + VLOG(1) << "link " << fromCName << " -> " << toCName; + + int res = -EPERM; + if( fsConfig->config->external_iv() ) + { + VLOG(1) << "hard links not supported with external IV chaining!"; + } else + { + res = ::link( fromCName.c_str(), toCName.c_str() ); + if(res == -1) + res = -errno; + else + res = 0; + } + + return res; +} + +/* + The node is keyed by filename, so a rename means the internal node names + must be changed. +*/ +shared_ptr DirNode::renameNode( const char *from, const char *to ) +{ + return renameNode( from, to, true ); +} + +shared_ptr DirNode::renameNode( const char *from, const char *to, + bool forwardMode ) +{ + shared_ptr node = findOrCreate( from ); + + if(node) + { + uint64_t newIV = 0; + string cname = rootDir + naming->encodePath( to, &newIV ); + + VLOG(1) << "renaming internal node " << node->cipherName() + << " -> " << cname.c_str(); + + if(node->setName( to, cname.c_str(), newIV, forwardMode )) + { + if(ctx) + ctx->renameNode( from, to ); + } else + { + // rename error! - put it back + LOG(ERROR) << "renameNode failed"; + throw Error("Internal node name change failed!"); + } + } + + return node; +} + +shared_ptr DirNode::findOrCreate( const char *plainName) +{ + shared_ptr node; + if(ctx) + node = ctx->lookupNode( plainName ); + + if(!node) + { + uint64_t iv = 0; + string cipherName = naming->encodePath( plainName, &iv ); + node.reset( new FileNode( this, fsConfig, + plainName, + (rootDir + cipherName).c_str())); + + if(fsConfig->config->external_iv()) + node->setName(0, 0, iv); + + VLOG(1) << "created FileNode for " << node->cipherName(); + } + + return node; +} + +shared_ptr +DirNode::lookupNode( const char *plainName, const char * requestor ) +{ + (void)requestor; + Lock _lock( mutex ); + + shared_ptr node = findOrCreate( plainName ); + + return node; +} + +/* + Similar to lookupNode, except that we also call open() and only return a + node on sucess.. This is done in one step to avoid any race conditions + with the stored state of the file. +*/ +shared_ptr +DirNode::openNode( const char *plainName, const char * requestor, int flags, + int *result ) +{ + (void)requestor; + rAssert( result != NULL ); + Lock _lock( mutex ); + + shared_ptr node = findOrCreate( plainName ); + + if( node && (*result = node->open( flags )) >= 0 ) + return node; + else + return shared_ptr(); +} + +int DirNode::unlink( const char *plaintextName ) +{ + string cyName = naming->encodePath( plaintextName ); + VLOG(1) << "unlink " << cyName; + + Lock _lock( mutex ); + + int res = 0; + if(ctx && ctx->lookupNode( plaintextName )) + { + // If FUSE is running with "hard_remove" option where it doesn't + // hide open files for us, then we can't allow an unlink of an open + // file.. + LOG(WARNING) << "Refusing to unlink open file: " + << cyName << ", hard_remove option is probably in effect"; + res = -EBUSY; + } else + { + string fullName = rootDir + cyName; + res = ::unlink( fullName.c_str() ); + if(res == -1) + { + res = -errno; + VLOG(1) << "unlink error: " << strerror(errno); + } + } + + return res; +} diff --git a/encfs/DirNode.h b/fs/DirNode.h similarity index 97% rename from encfs/DirNode.h rename to fs/DirNode.h index a1e3fdf..0c3a344 100644 --- a/encfs/DirNode.h +++ b/fs/DirNode.h @@ -30,11 +30,11 @@ #include #include -#include "FileNode.h" -#include "NameIO.h" -#include "CipherKey.h" -#include "FSConfig.h" -#include "shared_ptr.h" +#include "base/shared_ptr.h" +#include "cipher/CipherKey.h" +#include "fs/FileNode.h" +#include "fs/NameIO.h" +#include "fs/FSConfig.h" class Cipher; class RenameOp; diff --git a/encfs/FSConfig.h b/fs/FSConfig.h similarity index 94% rename from encfs/FSConfig.h rename to fs/FSConfig.h index c777679..75cc003 100644 --- a/encfs/FSConfig.h +++ b/fs/FSConfig.h @@ -21,10 +21,10 @@ #ifndef _FSConfig_incl_ #define _FSConfig_incl_ -#include "encfs.h" -#include "Interface.h" -#include "CipherKey.h" -#include "shared_ptr.h" +#include "base/Interface.h" +#include "base/shared_ptr.h" +#include "cipher/CipherKey.h" +#include "fs/encfs.h" #include @@ -39,7 +39,7 @@ enum ConfigType Config_V7 = 7 }; -class EncFS_Opts; +struct EncFS_Opts; class Cipher; class NameIO; class EncfsConfig; diff --git a/encfs/FileIO.cpp b/fs/FileIO.cpp similarity index 100% rename from encfs/FileIO.cpp rename to fs/FileIO.cpp diff --git a/encfs/FileIO.h b/fs/FileIO.h similarity index 97% rename from encfs/FileIO.h rename to fs/FileIO.h index c97ff2a..0c71213 100644 --- a/encfs/FileIO.h +++ b/fs/FileIO.h @@ -21,12 +21,11 @@ #ifndef _FileIO_incl_ #define _FileIO_incl_ -#include "encfs.h" +#include "base/Interface.h" +#include "fs/encfs.h" #include -#include "Interface.h" - struct IORequest { off_t offset; diff --git a/fs/FileNode.cpp b/fs/FileNode.cpp new file mode 100644 index 0000000..fc5cdc8 --- /dev/null +++ b/fs/FileNode.cpp @@ -0,0 +1,303 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2003-2004, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +// Include encfs first, because we need to include fuse.h before any inclusion +// of sys/stat.h or other system headers (to be safe) +#include "fs/encfs.h" + +#include +#include +#include +#include +#include +#ifdef linux +#include +#endif + +#include + +#include "base/config.h" +#include "base/Error.h" +#include "base/Mutex.h" +#include "cipher/Cipher.h" +#include "cipher/MemoryPool.h" + +#include "fs/FileNode.h" +#include "fs/FileUtils.h" +#include "fs/CipherFileIO.h" +#include "fs/RawFileIO.h" +#include "fs/MACFileIO.h" +#include "fs/DirNode.h" + +#include "fs/FileIO.h" + +#include + +using namespace std; +using namespace rel; + +/* + TODO: locking at the FileNode level is inefficient, since this precludes + multiple concurrent IO operations within the same file. + + There is no reason why simultainous reads cannot be satisfied, or why one + read has to wait for the decoding of the previous read before it can be + sent to the IO subsystem! +*/ + +FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg, + const char *plaintextName_, const char *cipherName_) +{ + pthread_mutex_init( &mutex, 0 ); + + Lock _lock( mutex ); + + this->_pname = plaintextName_; + this->_cname = cipherName_; + this->parent = parent_; + + this->fsConfig = cfg; + + // chain RawFileIO & CipherFileIO + shared_ptr rawIO( new RawFileIO( _cname ) ); + io = shared_ptr( new CipherFileIO( rawIO, fsConfig )); + + if(cfg->config->block_mac_bytes() || cfg->config->block_mac_rand_bytes()) + io = shared_ptr(new MACFileIO(io, fsConfig)); +} + +FileNode::~FileNode() +{ + // FileNode mutex should be locked before the destructor is called + //pthread_mutex_lock( &mutex ); + + _pname.assign( _pname.length(), '\0' ); + _cname.assign( _cname.length(), '\0' ); + io.reset(); + + pthread_mutex_destroy( &mutex ); +} + +const char *FileNode::cipherName() const +{ + return _cname.c_str(); +} + +const char *FileNode::plaintextName() const +{ + return _pname.c_str(); +} + +string FileNode::plaintextParent() const +{ + return parentDirectory( _pname ); +} + +static bool setIV(const shared_ptr &io, uint64_t iv) +{ + struct stat stbuf; + if((io->getAttr(&stbuf) < 0) || S_ISREG(stbuf.st_mode)) + return io->setIV( iv ); + else + return true; +} + +bool FileNode::setName( const char *plaintextName_, const char *cipherName_, + uint64_t iv, bool setIVFirst ) +{ + //Lock _lock( mutex ); + VLOG(1) << "calling setIV on " << cipherName_; + if(setIVFirst) + { + if(fsConfig->config->external_iv() && !setIV(io, iv)) + return false; + + // now change the name.. + if(plaintextName_) + this->_pname = plaintextName_; + if(cipherName_) + { + this->_cname = cipherName_; + io->setFileName( cipherName_ ); + } + } else + { + std::string oldPName = _pname; + std::string oldCName = _cname; + + if(plaintextName_) + this->_pname = plaintextName_; + if(cipherName_) + { + this->_cname = cipherName_; + io->setFileName( cipherName_ ); + } + + if(fsConfig->config->external_iv() && !setIV(io, iv)) + { + _pname = oldPName; + _cname = oldCName; + return false; + } + } + + return true; +} + +int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid) +{ + Lock _lock( mutex ); + + int res; + int olduid = -1; + int oldgid = -1; + if(uid != 0) + { + olduid = setfsuid( uid ); + if(olduid == -1) + { + LOG(INFO) << "setfsuid error: " << strerror(errno); + return -EPERM; + } + } + if(gid != 0) + { + oldgid = setfsgid( gid ); + if(oldgid == -1) + { + LOG(INFO) << "setfsgid error: " << strerror(errno); + return -EPERM; + } + } + + /* + * cf. xmp_mknod() in fusexmp.c + * The regular file stuff could be stripped off if there + * were a create method (advised to have) + */ + if (S_ISREG( mode )) { + res = ::open( _cname.c_str(), O_CREAT | O_EXCL | O_WRONLY, mode ); + if (res >= 0) + res = ::close( res ); + } else if (S_ISFIFO( mode )) + res = ::mkfifo( _cname.c_str(), mode ); + else + res = ::mknod( _cname.c_str(), mode, rdev ); + + if(olduid >= 0) + setfsuid( olduid ); + if(oldgid >= 0) + setfsgid( oldgid ); + + if(res == -1) + { + int eno = errno; + VLOG(1) << "mknod error: " << strerror(eno); + res = -eno; + } + + return res; +} + +int FileNode::open(int flags) const +{ + Lock _lock( mutex ); + + int res = io->open( flags ); + return res; +} + +int FileNode::getAttr(struct stat *stbuf) const +{ + Lock _lock( mutex ); + + int res = io->getAttr( stbuf ); + return res; +} + +off_t FileNode::getSize() const +{ + Lock _lock( mutex ); + + int res = io->getSize(); + return res; +} + +ssize_t FileNode::read( off_t offset, unsigned char *data, ssize_t size ) const +{ + IORequest req; + req.offset = offset; + req.dataLen = size; + req.data = data; + + Lock _lock( mutex ); + + return io->read( req ); +} + +bool FileNode::write(off_t offset, unsigned char *data, ssize_t size) +{ + VLOG(1) << "FileNode::write offset " << offset + << ", data size " << size; + + IORequest req; + req.offset = offset; + req.dataLen = size; + req.data = data; + + Lock _lock( mutex ); + + return io->write( req ); +} + +int FileNode::truncate( off_t size ) +{ + Lock _lock( mutex ); + + return io->truncate( size ); +} + +int FileNode::sync(bool datasync) +{ + Lock _lock( mutex ); + + int fh = io->open( O_RDONLY ); + if(fh >= 0) + { + int res = -EIO; +#ifdef linux + if(datasync) + res = fdatasync( fh ); + else + res = fsync( fh ); +#else + // no fdatasync support + // TODO: use autoconfig to check for it.. + res = fsync(fh); +#endif + + if(res == -1) + res = -errno; + + return res; + } else + return fh; +} + diff --git a/encfs/FileNode.h b/fs/FileNode.h similarity index 97% rename from encfs/FileNode.h rename to fs/FileNode.h index 0037643..c827a89 100644 --- a/encfs/FileNode.h +++ b/fs/FileNode.h @@ -21,9 +21,9 @@ #ifndef _FileNode_incl_ #define _FileNode_incl_ -#include "encfs.h" -#include "CipherKey.h" -#include "FileUtils.h" +#include "cipher/CipherKey.h" +#include "fs/encfs.h" +#include "fs/FileUtils.h" #include #include diff --git a/encfs/FileUtils.cpp b/fs/FileUtils.cpp similarity index 90% rename from encfs/FileUtils.cpp rename to fs/FileUtils.cpp index b045d54..28ab025 100644 --- a/encfs/FileUtils.cpp +++ b/fs/FileUtils.cpp @@ -24,28 +24,29 @@ #endif #define _BSD_SOURCE // pick up setenv on RH7.3 -#include "encfs.h" -#include "config.h" -#include "config.pb.h" +#include "fs/encfs.h" -#include "readpassphrase.h" -#include "autosprintf.h" +#include "base/autosprintf.h" +#include "base/config.h" +#include "base/config.pb.h" +#include "base/ConfigReader.h" +#include "base/Error.h" +#include "base/i18n.h" +#include "base/XmlReader.h" -#include "FileUtils.h" -#include "ConfigReader.h" -#include "XmlReader.h" -#include "FSConfig.h" +#include "cipher/Cipher.h" +#include "cipher/MemoryPool.h" +#include "cipher/readpassphrase.h" -#include "DirNode.h" -#include "Cipher.h" -#include "StreamNameIO.h" -#include "BlockNameIO.h" -#include "NullNameIO.h" -#include "Context.h" -#include "MemoryPool.h" +#include "fs/BlockNameIO.h" +#include "fs/Context.h" +#include "fs/DirNode.h" +#include "fs/FileUtils.h" +#include "fs/FSConfig.h" +#include "fs/NullNameIO.h" +#include "fs/StreamNameIO.h" -#include -#include +#include #include #include @@ -62,23 +63,16 @@ #include #include -#include "i18n.h" - #include #include -// disable rlog section grouping for this file.. seems to cause problems -#undef RLOG_SECTION -#define RLOG_SECTION - -using namespace rlog; using namespace std; using namespace gnu; -static const int DefaultBlockSize = 1024; +static const int DefaultBlockSize = 2048; // The maximum length of text passwords. If longer are needed, // use the extpass option, as extpass can return arbitrary length binary data. -static const int MaxPassBuf = 512; +static const int MaxPassBuf = 2048; static const int NormalKDFDuration = 500; // 1/2 a second static const int ParanoiaKDFDuration = 3000; // 3 seconds @@ -90,7 +84,7 @@ static const char ENCFS_ENV_STDOUT[] = "encfs_stdout"; static const char ENCFS_ENV_STDERR[] = "encfs_stderr"; const int V5Latest = 20040813; // fix MACFileIO block size issues -const int ProtoSubVersion = 20120819; +const int ProtoSubVersion = 20120902; const char ConfigFileName[] = ".encfs.txt"; @@ -223,12 +217,12 @@ ConfigType readConfig_load( ConfigInfo *nm, const char *path, { if( (*nm->loadFunc)( path, config, nm )) return nm->type; - } catch( rlog::Error & err ) + } catch( Error &err ) { - err.log( _RLWarningChannel ); + LOG(WARNING) << "readConfig failed: " << err.what(); } - rError( _("Found config file %s, but failed to load"), path); + LOG(ERROR) << "Found config file " << path << ", but failed to load"; return Config_None; } else { @@ -269,7 +263,7 @@ bool readV6Config( const char *configFile, XmlReader rdr; if (!rdr.load(configFile)) { - rError("Failed to load config file %s", configFile); + LOG(ERROR) << "Failed to load config file " << configFile; return false; } @@ -279,39 +273,40 @@ bool readV6Config( const char *configFile, config = (*serialization)["config"]; } if (!config) { - rError("Unable to find XML configuration in file %s", configFile); + LOG(ERROR) << "Unable to find XML configuration in file " << configFile; return false; } int version; if (!config->read("version", &version) && !config->read("@version", &version)) { - rError("Unable to find version in config file"); + LOG(ERROR) << "Unable to find version in config file"; return false; } // version numbering was complicated by boost::archive if (version == 20 || version >= 20100713) { - rInfo("found new serialization format"); + VLOG(1) << "found new serialization format"; cfg.set_revision(version); } else if (version == 26800) { - rInfo("found 20080816 version"); + VLOG(1) << "found 20080816 version"; cfg.set_revision(20080816); } else if (version == 26797) { - rInfo("found 20080813"); + VLOG(1) << "found 20080813"; cfg.set_revision(20080813); } else if (version < V5Latest) { - rError("Invalid version %i - please fix config file", version); + LOG(ERROR) << "Invalid version " << version + << " - please fix config file"; } else { - rInfo("Boost <= 1.41 compatibility mode"); + LOG(INFO) << "Boost <= 1.41 compatibility mode"; cfg.set_revision(version); } - rInfo("subVersion = %i", cfg.revision()); + VLOG(1) << "subVersion = " << cfg.revision(); config->read("creator", cfg.mutable_creator()); config->read("cipherAlg", cfg.mutable_cipher()); @@ -390,15 +385,15 @@ bool readV5Config( const char *configFile, { /* config file specifies a version outside our supported range.. */ - rWarning(_("Config subversion %i found, but this version of" - " encfs only supports up to version %i."), - config.revision(), V5Latest); + LOG(ERROR) << "Config subversion " << config.revision() + << " found, but this version of encfs only supports up to version " + << V5Latest; return false; } if( config.revision() < V5Latest ) { - rError(_("This version of EncFS doesn't support " - "filesystems created before 2004-08-13")); + LOG(ERROR) << "This version of EncFS doesn't support " + << "filesystems created with EncFS releases before 2004-08-13"; return false; } @@ -423,10 +418,10 @@ bool readV5Config( const char *configFile, config.set_block_mac_rand_bytes( cfgRdr["blockMACRandBytes"].readInt(0) ); ok = true; - } catch( rlog::Error &err) + } catch( Error &err) { - err.log( _RLWarningChannel ); - rDebug("Error parsing data in config file %s", configFile); + LOG(WARNING) << "Error parsing data in config file " << configFile + << "; " << err.what(); ok = false; } } @@ -458,10 +453,10 @@ bool readV4Config( const char *configFile, config.set_creator( "EncFS 1.0.x" ); ok = true; - } catch( rlog::Error &err) + } catch( Error &err) { - err.log( _RLWarningChannel ); - rDebug("Error parsing config file %s", configFile); + LOG(WARNING) << "Error parsing config file " << configFile + << ": " << err.what(); ok = false; } } @@ -474,7 +469,7 @@ bool writeTextConfig( const char *fileName, const EncfsConfig &cfg ) int fd = ::open( fileName, O_RDWR | O_CREAT, 0640 ); if (fd < 0) { - rError("Unable to open or create file %s", fileName); + LOG(ERROR) << "Unable to open or create file " << fileName; return false; } @@ -503,10 +498,11 @@ bool saveConfig( const string &rootDir, const EncfsConfig &config ) try { + const_cast(config).set_writer("EncFS " VERSION ); ok = writeTextConfig( path.c_str(), config ); - } catch( rlog::Error &err ) + } catch( Error &err ) { - err.log( _RLWarningChannel ); + LOG(WARNING) << "saveConfig failed: " << err.what(); ok = false; } @@ -519,7 +515,7 @@ bool readProtoConfig( const char *fileName, EncfsConfig &config, int fd = ::open( fileName, O_RDONLY, 0640 ); if (fd < 0) { - rError("Unable to open file %s", fileName); + LOG(ERROR) << "Unable to open file " << fileName; return false; } @@ -623,7 +619,7 @@ Cipher::CipherAlgorithm selectCipherAlgorithm() } static -Interface selectNameCoding() +Interface selectNameCoding(const Cipher::CipherAlgorithm &alg) { for(;;) { @@ -634,10 +630,15 @@ Interface selectNameCoding() NameIO::AlgorithmList algorithms = NameIO::GetAlgorithmList(); NameIO::AlgorithmList::const_iterator it; int optNum = 1; - for(it = algorithms.begin(); it != algorithms.end(); ++it, ++optNum) + map algMap; + for(it = algorithms.begin(); it != algorithms.end(); ++it) { + if (it->needsStreamMode && !alg.hasStreamMode) + continue; + cout << optNum << ". " << it->name << " : " << gettext(it->description.c_str()) << "\n"; + algMap[optNum++] = it; } // xgroup(setup) @@ -647,15 +648,13 @@ Interface selectNameCoding() int algNum = (res == 0 ? 0 : atoi( answer )); cout << "\n"; - if( algNum < 1 || algNum > (int)algorithms.size() ) + if( algNum < 1 || algNum >= optNum ) { cerr << _("Invalid selection.") << "\n"; continue; } - it = algorithms.begin(); - while(--algNum) // numbering starts at 1 - ++it; + it = algMap[algNum]; // xgroup(setup) cout << autosprintf(_("Selected algorithm \"%s\""), it->name.c_str()) @@ -940,7 +939,7 @@ RootPtr createConfig( EncFS_Context *ctx, { if (reverseEncryption) { - rError(_("Paranoia configuration not supported for --reverse")); + LOG(ERROR) << "Paranoia configuration not supported for --reverse"; return rootInfo; } @@ -953,7 +952,7 @@ RootPtr createConfig( EncFS_Context *ctx, // Enable filename initialization vector chaning keySize = 256; blockSize = DefaultBlockSize; - alg = findCipherAlgorithm("AES", keySize); + alg = findCipherAlgorithm("AES_XTS", keySize); nameIOIface = BlockNameIO::CurrentInterface(); blockMACBytes = 8; blockMACRandBytes = 0; // using uniqueIV, so this isn't necessary @@ -1004,7 +1003,7 @@ RootPtr createConfig( EncFS_Context *ctx, alg = selectCipherAlgorithm(); keySize = selectKeySize( alg ); blockSize = selectBlockSize( alg ); - nameIOIface = selectNameCoding(); + nameIOIface = selectNameCoding( alg ); if (reverseEncryption) { cout << _("--reverse specified, not using unique/chained IV") << "\n"; @@ -1030,18 +1029,22 @@ RootPtr createConfig( EncFS_Context *ctx, shared_ptr cipher = Cipher::New( alg.name, keySize ); if(!cipher) { - rError(_("Unable to instanciate cipher %s, key size %i, block size %i"), - alg.name.c_str(), keySize, blockSize); + LOG(ERROR) << "Unable to instanciate cipher " << alg.name + << ", key size " << keySize << ", block size " << blockSize; return rootInfo; } else { - rDebug("Using cipher %s, key size %i, block size %i", - alg.name.c_str(), keySize, blockSize); + VLOG(1) << "Using cipher " << alg.name + << ", key size " << keySize << ", block size " << blockSize; } EncfsConfig config; config.mutable_cipher()->MergeFrom( cipher->interface() ); + // TODO: allow user config + if (!cipher->hasStreamMode()) + config.set_block_mode_only(true); + config.set_block_size( blockSize ); config.mutable_naming()->MergeFrom( nameIOIface ); config.set_creator( "EncFS " VERSION ); @@ -1093,7 +1096,7 @@ RootPtr createConfig( EncFS_Context *ctx, // get user key and use it to encode volume key CipherKey userKey; - rDebug( "useStdin: %i", useStdin ); + VLOG(1) << "useStdin: " << useStdin; if(useStdin) { if (annotate) @@ -1109,8 +1112,8 @@ RootPtr createConfig( EncFS_Context *ctx, if(!volumeKey) { - rWarning(_("Failure generating new volume key! " - "Please report this error.")); + LOG(ERROR) << "Failure generating new volume key! " + << "Please report this error."; return rootInfo; } @@ -1122,7 +1125,7 @@ RootPtr createConfig( EncFS_Context *ctx, cipher, volumeKey ); if(!nameCoder) { - rWarning(_("Name coding interface not supported")); + LOG(WARNING) << "Name coding interface not supported"; cout << _("The filename encoding interface requested is not available") << endl; return rootInfo; @@ -1175,12 +1178,17 @@ void showFSInfo( const EncfsConfig &config ) cout << "\n"; } } - { - // xgroup(diag) - cout << autosprintf(_("Filename encoding: \"%s\", version %i:%i:%i"), - config.naming().name().c_str(), config.naming().major(), - config.naming().minor(), config.naming().age()); + // xgroup(diag) + cout << autosprintf(_("Filename encoding: \"%s\", version %i:%i:%i"), + config.naming().name().c_str(), config.naming().major(), + config.naming().minor(), config.naming().age()); + + if (!cipher) + { + cout << "\n"; + } else + { // check if we support the filename encoding interface.. shared_ptr nameCoder = NameIO::New( config.naming(), cipher, CipherKey() ); @@ -1312,8 +1320,9 @@ CipherKey decryptKey(const EncfsConfig &config, const char *password, int passwd iterations, key.kdf_duration(), (const unsigned char *)key.salt().data(), key.salt().size()); - if (iterations != key.kdf_iterations()) { - rError("Error in KDF, iteration mismatch"); + if (iterations != key.kdf_iterations()) + { + LOG(ERROR) << "Error in KDF, iteration mismatch"; return userKey; } } else @@ -1366,7 +1375,7 @@ SecureMem *passwordFromProgram(const std::string &passProg, perror(_("Internal error: socketpair() failed")); return NULL; } - rDebug("getUserKey: fds = %i, %i", fds[0], fds[1]); + VLOG(1) << "getUserKey: fds = " << fds[0] << ", " << fds[1]; pid = fork(); if(pid == -1) @@ -1570,11 +1579,10 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) shared_ptr cipher = getCipher(config); if(!cipher) { - rError(_("Unable to find cipher %s, version %i:%i:%i"), - config.cipher().name().c_str(), - config.cipher().major(), - config.cipher().minor(), - config.cipher().age()); + Interface iface = config.cipher(); + LOG(ERROR) << "Unable to find cipher " << iface.name() + << ", version " << iface.major() + << ":" << iface.minor() << ":" << iface.age(); // xgroup(diag) cout << _("The requested cipher interface is not available\n"); return rootInfo; @@ -1594,7 +1602,7 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) if(!userKey) return rootInfo; - rDebug("cipher encoded key size = %i", cipher->encodedKeySize()); + VLOG(1) << "cipher encoded key size = " << cipher->encodedKeySize(); // decode volume key.. CipherKey volumeKey = cipher->readKey( (const unsigned char *)config.key().ciphertext().data(), userKey, opts->checkKey); @@ -1611,11 +1619,10 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) cipher, volumeKey ); if(!nameCoder) { - rError(_("Unable to find nameio interface %s, version %i:%i:%i"), - config.naming().name().c_str(), - config.naming().major(), - config.naming().minor(), - config.naming().age()); + Interface iface = config.naming(); + LOG(ERROR) << "Unable to find nameio interface " << iface.name() + << ", version " << iface.major() + << ":" << iface.minor() << ":" << iface.age(); // xgroup(diag) cout << _("The requested filename coding interface is " "not available\n"); @@ -1653,7 +1660,7 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) int remountFS(EncFS_Context *ctx) { - rDebug("Attempting to reinitialize filesystem"); + VLOG(1) << "Attempting to reinitialize filesystem"; RootPtr rootInfo = initFS( ctx, ctx->opts ); if(rootInfo) @@ -1662,7 +1669,7 @@ int remountFS(EncFS_Context *ctx) return 0; } else { - rInfo(_("Remount failed")); + LOG(WARNING) << "Remount failed"; return -EACCES; } } diff --git a/encfs/FileUtils.h b/fs/FileUtils.h similarity index 97% rename from encfs/FileUtils.h rename to fs/FileUtils.h index 9cb058e..83b4f56 100644 --- a/encfs/FileUtils.h +++ b/fs/FileUtils.h @@ -21,10 +21,10 @@ #ifndef _FileUtils_incl_ #define _FileUtils_incl_ -#include "encfs.h" -#include "Interface.h" -#include "CipherKey.h" -#include "FSConfig.h" +#include "base/Interface.h" +#include "cipher/CipherKey.h" +#include "fs/encfs.h" +#include "fs/FSConfig.h" // true if the path points to an existing node (of any type) bool fileExists( const char *fileName ); diff --git a/fs/MACFileIO.cpp b/fs/MACFileIO.cpp new file mode 100644 index 0000000..430464b --- /dev/null +++ b/fs/MACFileIO.cpp @@ -0,0 +1,295 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2004, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "fs/MACFileIO.h" + +#include "base/config.pb.h" +#include "base/Error.h" +#include "base/i18n.h" +#include "cipher/MemoryPool.h" +#include "fs/FileUtils.h" + +#include + +#include + +using namespace std; + +// +// Version 1.0 worked on blocks of size (blockSize + headerSize). +// That is, it took [blockSize] worth of user data and added headers. +// Version 2.0 takes [blockSize - headerSize] worth of user data and writes +// [blockSize] bytes. That way the size going into the crypto engine is +// valid from what was selected based on the crypto module allowed ranges! +// Version 2.1 allows per-block rand bytes to be used without enabling MAC. +// +// The information about MACFileIO currently does not make its way into the +// configuration file, so there is no easy way to make this backward +// compatible, except at a high level by checking a revision number for the +// filesystem... +// +static Interface MACFileIO_iface = makeInterface("FileIO/MAC", 2, 1, 0); + +int dataBlockSize(const FSConfigPtr &cfg) +{ + return cfg->config->block_size() + - cfg->config->block_mac_bytes() + - cfg->config->block_mac_rand_bytes(); +} + +MACFileIO::MACFileIO( const shared_ptr &_base, + const FSConfigPtr &cfg ) + : BlockFileIO( dataBlockSize( cfg ), cfg ) + , base( _base ) + , cipher( cfg->cipher ) + , key( cfg->key ) + , macBytes( cfg->config->block_mac_bytes() ) + , randBytes( cfg->config->block_mac_rand_bytes() ) + , warnOnly( cfg->opts->forceDecode ) +{ + rAssert( macBytes >= 0 && macBytes <= 8 ); + rAssert( randBytes >= 0 ); + VLOG(1) << "fs block size = " << cfg->config->block_size() + << ", macBytes = " << cfg->config->block_mac_bytes() + << ", randBytes = " << cfg->config->block_mac_rand_bytes(); +} + +MACFileIO::~MACFileIO() +{ +} + +Interface MACFileIO::interface() const +{ + return MACFileIO_iface; +} + +int MACFileIO::open( int flags ) +{ + return base->open( flags ); +} + +void MACFileIO::setFileName( const char *fileName ) +{ + base->setFileName( fileName ); +} + +const char *MACFileIO::getFileName() const +{ + return base->getFileName(); +} + +bool MACFileIO::setIV( uint64_t iv ) +{ + return base->setIV( iv ); +} + +inline static off_t roundUpDivide( off_t numerator, int denominator ) +{ + // integer arithmetic always rounds down, so we can round up by adding + // enough so that any value other then a multiple of denominator gets + // rouned to the next highest value. + return ( numerator + denominator - 1 ) / denominator; +} + +// Convert from a location in the raw file to a location when MAC headers are +// interleved with the data. +// So, if the filesystem stores/encrypts [blockSize] bytes per block, then +// [blockSize - headerSize] of those bytes will contain user-supplied data, +// and the rest ([headerSize]) will contain the MAC header for this block. +// Example, offset points to second block (of user-data) +// offset = blockSize - headerSize +// ... blockNum = 1 +// ... partialBlock = 0 +// ... adjLoc = 1 * blockSize +static off_t locWithHeader( off_t offset, int blockSize, int headerSize ) +{ + off_t blockNum = roundUpDivide( offset , blockSize - headerSize ); + return offset + blockNum * headerSize; +} + +// convert from a given location in the stream containing headers, and return a +// location in the user-data stream (which doesn't contain MAC headers).. +// The output value will always be less then the input value, because the +// headers are stored at the beginning of the block, so even the first data is +// offset by the size of the header. +static off_t locWithoutHeader( off_t offset, int blockSize, int headerSize ) +{ + off_t blockNum = roundUpDivide( offset , blockSize ); + return offset - blockNum * headerSize; +} + +int MACFileIO::getAttr( struct stat *stbuf ) const +{ + int res = base->getAttr( stbuf ); + + if(res == 0 && S_ISREG(stbuf->st_mode)) + { + // have to adjust size field.. + int headerSize = macBytes + randBytes; + int bs = blockSize() + headerSize; + stbuf->st_size = locWithoutHeader( stbuf->st_size, bs, headerSize ); + } + + return res; +} + +off_t MACFileIO::getSize() const +{ + // adjust the size to hide the header overhead we tack on.. + int headerSize = macBytes + randBytes; + int bs = blockSize() + headerSize; + + off_t size = base->getSize(); + if(size > 0) + size = locWithoutHeader( size, bs, headerSize ); + + return size; +} + +ssize_t MACFileIO::readOneBlock( const IORequest &req ) const +{ + int headerSize = macBytes + randBytes; + + int bs = blockSize() + headerSize; + + MemBlock mb; + mb.allocate( bs ); + + IORequest tmp; + tmp.offset = locWithHeader( req.offset, bs, headerSize ); + tmp.data = mb.data; + tmp.dataLen = headerSize + req.dataLen; + + // get the data from the base FileIO layer + ssize_t readSize = base->read( tmp ); + + // don't store zeros if configured for zero-block pass-through + bool skipBlock = true; + if( _allowHoles ) + { + for(int i=0; i 0) + skipBlock = false; + + if(readSize > headerSize) + { + if(!skipBlock) + { + // At this point the data has been decoded. So, compute the MAC of + // the block and check against the checksum stored in the header.. + uint64_t mac = cipher->MAC_64( tmp.data + macBytes, + readSize - macBytes, key ); + + for(int i=0; i>= 8) + { + int test = mac & 0xff; + int stored = tmp.data[i]; + if(test != stored) + { + // uh oh.. + long blockNum = req.offset / bs; + LOG(WARNING) << "MAC comparison failure in block " << blockNum; + if( !warnOnly ) + { + throw Error( + _("MAC comparison failure, refusing to read")); + } + break; + } + } + } + + // now copy the data to the output buffer + readSize -= headerSize; + memcpy( req.data, tmp.data + headerSize, readSize ); + } else + { + VLOG(1) << "readSize " << readSize << " at offset " << req.offset; + if(readSize > 0) + readSize = 0; + } + + return readSize; +} + +bool MACFileIO::writeOneBlock( const IORequest &req ) +{ + int headerSize = macBytes + randBytes; + + int bs = blockSize() + headerSize; + + // we have the unencrypted data, so we need to attach a header to it. + MemBlock mb; + mb.allocate( bs ); + + IORequest newReq; + newReq.offset = locWithHeader( req.offset, bs, headerSize ); + newReq.data = mb.data; + newReq.dataLen = headerSize + req.dataLen; + + memset( newReq.data, 0, headerSize ); + memcpy( newReq.data + headerSize, req.data, req.dataLen ); + if(randBytes > 0) + { + if(!cipher->randomize( newReq.data+macBytes, randBytes, false )) + return false; + } + + if(macBytes > 0) + { + // compute the mac (which includes the random data) and fill it in + uint64_t mac = cipher->MAC_64( newReq.data+macBytes, + req.dataLen + randBytes, key ); + + for(int i=0; i>= 8; + } + } + + // now, we can let the next level have it.. + bool ok = base->write( newReq ); + + return ok; +} + +int MACFileIO::truncate( off_t size ) +{ + int headerSize = macBytes + randBytes; + int bs = blockSize() + headerSize; + + int res = blockTruncate( size, 0 ); + + if(res == 0) + base->truncate( locWithHeader( size, bs, headerSize ) ); + + return res; +} + +bool MACFileIO::isWritable() const +{ + return base->isWritable(); +} diff --git a/encfs/MACFileIO.h b/fs/MACFileIO.h similarity index 97% rename from encfs/MACFileIO.h rename to fs/MACFileIO.h index eba1b4b..0a27709 100644 --- a/encfs/MACFileIO.h +++ b/fs/MACFileIO.h @@ -21,8 +21,8 @@ #ifndef _MACFileIO_incl_ #define _MACFileIO_incl_ -#include "BlockFileIO.h" -#include "Cipher.h" +#include "cipher/Cipher.h" +#include "fs/BlockFileIO.h" class MACFileIO : public BlockFileIO { diff --git a/fs/MemBlockFileIO.cpp b/fs/MemBlockFileIO.cpp new file mode 100644 index 0000000..5192f79 --- /dev/null +++ b/fs/MemBlockFileIO.cpp @@ -0,0 +1,76 @@ + +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2012 Valient Gough + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "fs/MemBlockFileIO.h" +#include "fs/MemFileIO.h" + +#include + +static Interface MemBlockFileIO_iface = makeInterface("FileIO/MemBlock", + 1, 0, 0); + +MemBlockFileIO::MemBlockFileIO(int blockSize, const FSConfigPtr &cfg) + : BlockFileIO(blockSize, cfg), impl(new MemFileIO(0)) { +} + +MemBlockFileIO::~MemBlockFileIO() { +} + +Interface MemBlockFileIO::interface() const { + return MemBlockFileIO_iface; +} + +void MemBlockFileIO::setFileName(const char *name) { + return impl->setFileName(name); +} + +const char *MemBlockFileIO::getFileName() const { + return impl->getFileName(); +} + +int MemBlockFileIO::open(int flags) { + return impl->open(flags); +} + +int MemBlockFileIO::getAttr(struct stat* stbuf) const { + return impl->getAttr(stbuf); +} + +off_t MemBlockFileIO::getSize() const { + return impl->getSize(); +} + +ssize_t MemBlockFileIO::readOneBlock(const IORequest& req) const { + return impl->read(req); +} + +bool MemBlockFileIO::writeOneBlock(const IORequest& req) { + return impl->write(req); +} + +int MemBlockFileIO::truncate(off_t size) { + return impl->truncate(size); +} + +bool MemBlockFileIO::isWritable() const { + return impl->isWritable(); +} + diff --git a/fs/MemBlockFileIO.h b/fs/MemBlockFileIO.h new file mode 100644 index 0000000..82f8484 --- /dev/null +++ b/fs/MemBlockFileIO.h @@ -0,0 +1,59 @@ + +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2012 Valient Gough + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef _MEMBLOCKFILEIO_incl_ +#define _MEMBLOCKFILEIO_incl_ + +#include "fs/BlockFileIO.h" + +#include +#include + +class MemFileIO; + +class MemBlockFileIO : public BlockFileIO { + public: + MemBlockFileIO(int blockSize, const FSConfigPtr &cfg); + virtual ~MemBlockFileIO(); + + virtual Interface interface() const; + + virtual void setFileName(const char *name); + virtual const char *getFileName() const; + + virtual int open(int flags); + + virtual int getAttr(struct stat *stbuf) const; + virtual off_t getSize() const; + + virtual bool isWritable() const; + + virtual int truncate(off_t size); + protected: + virtual ssize_t readOneBlock(const IORequest &req) const; + virtual bool writeOneBlock(const IORequest &req); + + private: + MemFileIO *impl; +}; + +#endif + diff --git a/fs/MemFileIO.cpp b/fs/MemFileIO.cpp new file mode 100644 index 0000000..d24e583 --- /dev/null +++ b/fs/MemFileIO.cpp @@ -0,0 +1,106 @@ + +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2012 Valient Gough + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "fs/MemFileIO.h" + +#include "base/Error.h" + +#include + +static Interface MemFileIO_iface = makeInterface("FileIO/Mem", 1, 0, 0); + +MemFileIO* NewMemFileIO(const Interface& iface) { + (void)iface; + return new MemFileIO(0); +} + +MemFileIO::MemFileIO(int size) + : writable(false) { + buf.resize(size); +} + +MemFileIO::~MemFileIO() { +} + +Interface MemFileIO::interface() const { + return MemFileIO_iface; +} + +void MemFileIO::setFileName(const char *name) { + this->name = name; +} + +const char *MemFileIO::getFileName() const { + return name.c_str(); +} + +int MemFileIO::open(int flags) { + bool requestWrite = ((flags & O_RDWR) || (flags & O_WRONLY)); + + writable = writable || requestWrite; + LOG(ERROR) << "returning fake file descriptor"; + return 0; +} + +int MemFileIO::getAttr(struct stat* stbuf) const { + stbuf->st_size = buf.size(); + return 0; +} + +off_t MemFileIO::getSize() const { + return buf.size(); +} + +ssize_t MemFileIO::read(const IORequest& req) const { + rAssert(req.offset >= 0); + + int len = req.dataLen; + if (req.offset + req.dataLen > getSize()) { + len = getSize() - req.offset; + } + if (len < 0) { + len = 0; + } + + memcpy(req.data, &buf[req.offset], len); + return len; +} + +bool MemFileIO::write(const IORequest& req) { + rAssert(req.offset >= 0); + if (req.offset + req.dataLen > getSize()) { + truncate(req.offset + req.dataLen); + } + rAssert(req.offset + req.dataLen <= getSize()); + + memcpy(&buf[req.offset], req.data, req.dataLen); + return true; +} + +int MemFileIO::truncate(off_t size) { + buf.resize(size); + return 0; +} + +bool MemFileIO::isWritable() const { + return writable; +} + diff --git a/fs/MemFileIO.h b/fs/MemFileIO.h new file mode 100644 index 0000000..894f229 --- /dev/null +++ b/fs/MemFileIO.h @@ -0,0 +1,58 @@ + +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2012 Valient Gough + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef _MEMFILEIO_incl_ +#define _MEMFILEIO_incl_ + +#include "FileIO.h" + +#include +#include + +class MemFileIO : public FileIO { + public: + MemFileIO(int size); + virtual ~MemFileIO(); + + virtual Interface interface() const; + + virtual void setFileName(const char *name); + virtual const char *getFileName() const; + + virtual int open(int flags); + + virtual int getAttr(struct stat *stbuf) const; + virtual off_t getSize() const; + + virtual ssize_t read(const IORequest& req) const; + virtual bool write(const IORequest& req); + + virtual int truncate(off_t size); + virtual bool isWritable() const; + + private: + std::vector buf; + std::string name; + bool writable; +}; + +#endif + diff --git a/fs/NameIO.cpp b/fs/NameIO.cpp new file mode 100644 index 0000000..a3795ff --- /dev/null +++ b/fs/NameIO.cpp @@ -0,0 +1,338 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2004, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "base/config.h" +#include "base/Error.h" +#include "fs/NameIO.h" + +#include + +#include +#include + +// for static build. Need to reference the modules which are registered at +// run-time, to ensure that the linker doesn't optimize them away. +#include +#include "fs/BlockNameIO.h" +#include "fs/StreamNameIO.h" +#include "fs/NullNameIO.h" + +using namespace std; + +#define REF_MODULE(TYPE) \ + do { \ + if(!TYPE::Enabled() ) \ + cerr << "referenceModule: should never happen\n"; \ + } while(0) + +static +void AddSymbolReferences() +{ + REF_MODULE(BlockNameIO); + REF_MODULE(StreamNameIO); + REF_MODULE(NullNameIO); +} + + +struct NameIOAlg +{ + bool hidden; + NameIO::Constructor constructor; + string description; + Interface iface; + bool needsStreamMode; +}; + +typedef multimap< string, NameIOAlg > NameIOMap_t; +static NameIOMap_t *gNameIOMap = 0; + + +list< NameIO::Algorithm > NameIO::GetAlgorithmList( bool includeHidden ) +{ + AddSymbolReferences(); + + list< Algorithm > result; + if(gNameIOMap) + { + NameIOMap_t::const_iterator it; + NameIOMap_t::const_iterator end = gNameIOMap->end(); + for(it = gNameIOMap->begin(); it != end; ++it) + { + if(includeHidden || !it->second.hidden) + { + Algorithm tmp; + tmp.name = it->first; + tmp.description = it->second.description; + tmp.iface = it->second.iface; + tmp.needsStreamMode = it->second.needsStreamMode; + + result.push_back( tmp ); + } + } + } + + return result; +} + +bool NameIO::Register( const char *name, const char *description, + const Interface &iface, Constructor constructor, + bool needsStreamMode, + bool hidden ) +{ + if( !gNameIOMap ) + gNameIOMap = new NameIOMap_t; + + NameIOAlg alg; + alg.hidden = hidden; + alg.constructor = constructor; + alg.description = description; + alg.iface = iface; + alg.needsStreamMode = needsStreamMode; + + gNameIOMap->insert( make_pair( string(name), alg )); + return true; +} + +shared_ptr NameIO::New( const string &name, + const shared_ptr &cipher, const CipherKey &key) +{ + shared_ptr result; + if(gNameIOMap) + { + NameIOMap_t::const_iterator it = gNameIOMap->find( name ); + if(it != gNameIOMap->end()) + { + Constructor fn = it->second.constructor; + result = (*fn)( it->second.iface, cipher, key ); + } + } + return result; +} + +shared_ptr NameIO::New( const Interface &iface, + const shared_ptr &cipher, const CipherKey &key ) +{ + shared_ptr result; + if(gNameIOMap) + { + NameIOMap_t::const_iterator it; + NameIOMap_t::const_iterator end = gNameIOMap->end(); + for(it = gNameIOMap->begin(); it != end; ++it) + { + if( implements(it->second.iface, iface )) + { + Constructor fn = it->second.constructor; + result = (*fn)( iface, cipher, key ); + break; + } + } + } + return result; +} + + + +NameIO::NameIO() + : chainedNameIV( false ), reverseEncryption( false ) +{ +} + +NameIO::~NameIO() +{ +} + +void NameIO::setChainedNameIV( bool enable ) +{ + chainedNameIV = enable; +} + +bool NameIO::getChainedNameIV() const +{ + return chainedNameIV; +} + +void NameIO::setReverseEncryption( bool enable ) +{ + reverseEncryption = enable; +} + +bool NameIO::getReverseEncryption() const +{ + return reverseEncryption; +} + + +std::string NameIO::recodePath( const char *path, + int (NameIO::*_length)(int) const, + int (NameIO::*_code)(const char*, int, uint64_t *, char*) const, + uint64_t *iv ) const +{ + string output; + + while( *path ) + { + if( *path == '/' ) + { + if( !output.empty() ) // don't start the string with '/' + output += '/'; + ++path; + } else + { + bool isDotFile = (*path == '.'); + const char *next = strchr( path, '/' ); + int len = next ? next - path : strlen( path ); + + // at this point we know that len > 0 + if( isDotFile && (path[len-1] == '.') && (len <= 2) ) + { + output.append(len, '.'); // append [len] copies of '.' + path += len; + continue; + } + + // figure out buffer sizes + int approxLen = (this->*_length)( len ); + if(approxLen <= 0) + throw Error("Filename too small to decode"); + + BUFFER_INIT( codeBuf, 32, (unsigned int)approxLen+1 ); + + // code the name + int codedLen = (this->*_code)( path, len, iv, codeBuf ); + rAssert( codedLen <= approxLen ); + rAssert( codeBuf[codedLen] == '\0' ); + path += len; + + // append result to string + output += (char*)codeBuf; + + BUFFER_RESET( codeBuf ); + } + } + + return output; +} + +std::string NameIO::encodePath( const char *plaintextPath ) const +{ + uint64_t iv = 0; + return encodePath( plaintextPath, &iv); +} + +std::string NameIO::decodePath( const char *cipherPath ) const +{ + uint64_t iv = 0; + return decodePath( cipherPath, &iv ); +} + +std::string NameIO::_encodePath( const char *plaintextPath, uint64_t *iv ) const +{ + // if chaining is not enabled, then the iv pointer is not used.. + if(!chainedNameIV) + iv = 0; + return recodePath( plaintextPath, + &NameIO::maxEncodedNameLen, &NameIO::encodeName, iv); +} + +std::string NameIO::_decodePath( const char *cipherPath, uint64_t *iv ) const +{ + // if chaining is not enabled, then the iv pointer is not used.. + if(!chainedNameIV) + iv = 0; + return recodePath( cipherPath, + &NameIO::maxDecodedNameLen, &NameIO::decodeName, iv); +} + +std::string NameIO::encodePath( const char *path, uint64_t *iv ) const +{ + return getReverseEncryption() ? + _decodePath( path, iv ) : + _encodePath( path, iv ); +} + +std::string NameIO::decodePath( const char *path, uint64_t *iv ) const +{ + return getReverseEncryption() ? + _encodePath( path, iv ) : + _decodePath( path, iv ); +} + + +int NameIO::encodeName( const char *input, int length, char *output ) const +{ + return encodeName( input, length, (uint64_t*)0, output ); +} + +int NameIO::decodeName( const char *input, int length, char *output ) const +{ + return decodeName( input, length, (uint64_t*)0, output ); +} + +std::string NameIO::_encodeName( const char *plaintextName, int length ) const +{ + int approxLen = maxEncodedNameLen( length ); + + BUFFER_INIT( codeBuf, 32, (unsigned int)approxLen+1 ); + + // code the name + int codedLen = encodeName( plaintextName, length, 0, codeBuf ); + rAssert( codedLen <= approxLen ); + rAssert( codeBuf[codedLen] == '\0' ); + + // append result to string + std::string result = (char*)codeBuf; + + BUFFER_RESET( codeBuf ); + + return result; +} + +std::string NameIO::_decodeName( const char *encodedName, int length ) const +{ + int approxLen = maxDecodedNameLen( length ); + + BUFFER_INIT( codeBuf, 32, (unsigned int)approxLen+1 ); + + // code the name + int codedLen = decodeName( encodedName, length, 0, codeBuf ); + rAssert( codedLen <= approxLen ); + rAssert( codeBuf[codedLen] == '\0' ); + + // append result to string + std::string result = (char*)codeBuf; + + BUFFER_RESET( codeBuf ); + + return result; +} + +std::string NameIO::encodeName( const char *path, int length ) const +{ + return getReverseEncryption() ? + _decodeName( path, length ) : + _encodeName( path, length ); +} + +std::string NameIO::decodeName( const char *path, int length ) const +{ + return getReverseEncryption() ? + _encodeName( path, length ) : + _decodeName( path, length ); +} diff --git a/encfs/NameIO.h b/fs/NameIO.h similarity index 93% rename from encfs/NameIO.h rename to fs/NameIO.h index 73e0800..7761a06 100644 --- a/encfs/NameIO.h +++ b/fs/NameIO.h @@ -26,8 +26,8 @@ #include -#include "Interface.h" -#include "CipherKey.h" +#include "base/Interface.h" +#include "cipher/CipherKey.h" class Cipher; @@ -42,6 +42,7 @@ public: std::string name; std::string description; Interface iface; + bool needsStreamMode; }; typedef std::list AlgorithmList; @@ -54,6 +55,7 @@ public: static bool Register( const char *name, const char *description, const Interface &iface, Constructor constructor, + bool needsStreamMode, bool hidden = false); @@ -121,17 +123,19 @@ private: char Name ## _Raw [ OptimizedSize ]; \ char *Name = Name ## _Raw; \ if( sizeof(Name ## _Raw) < Size ) \ - Name = new char[ Size ];\ -memset( Name, 0, Size ); +{ \ + Name = new char[ Size ];\ +} \ +memset( Name, 0, Size ) #define BUFFER_RESET( Name ) \ do { \ - if( Name != Name ## _Raw ) \ - { \ - delete[] Name; \ - Name = Name ## _Raw; \ - } \ -} while(0); + if( Name != Name ## _Raw ) \ + { \ + delete[] Name; \ + Name = Name ## _Raw; \ + } \ +} while(0) #endif diff --git a/encfs/NullNameIO.cpp b/fs/NullNameIO.cpp similarity index 73% rename from encfs/NullNameIO.cpp rename to fs/NullNameIO.cpp index 11200dd..d3295c1 100644 --- a/encfs/NullNameIO.cpp +++ b/fs/NullNameIO.cpp @@ -18,26 +18,24 @@ * along with this program. If not, see . */ -#include "NullNameIO.h" - -#include "Cipher.h" -#include "base64.h" +#include "base/base64.h" +#include "cipher/Cipher.h" +#include "fs/NullNameIO.h" #include static shared_ptr NewNNIO( const Interface &, - const shared_ptr &, const CipherKey & ) + const shared_ptr &, const CipherKey & ) { - return shared_ptr( new NullNameIO() ); + return shared_ptr( new NullNameIO() ); } static Interface NNIOIface = makeInterface("nameio/null", 1, 0, 0); static bool NullNameIO_registered = NameIO::Register("Null", - "No encryption of filenames", NNIOIface, NewNNIO); + "No encryption of filenames", NNIOIface, NewNNIO, false); NullNameIO::NullNameIO( ) { - } NullNameIO::~NullNameIO() @@ -46,43 +44,41 @@ NullNameIO::~NullNameIO() Interface NullNameIO::interface() const { - return NNIOIface; + return NNIOIface; } Interface NullNameIO::CurrentInterface() { - return NNIOIface; + return NNIOIface; } int NullNameIO::maxEncodedNameLen( int plaintextNameLen ) const { - return plaintextNameLen; + return plaintextNameLen; } int NullNameIO::maxDecodedNameLen( int encodedNameLen ) const { - return encodedNameLen; + return encodedNameLen; } int NullNameIO::encodeName( const char *plaintextName, int length, - uint64_t *iv, char *encodedName ) const + uint64_t *iv, char *encodedName ) const { - memcpy( encodedName, plaintextName, length ); - - return length; + memcpy( encodedName, plaintextName, length ); + return length; } int NullNameIO::decodeName( const char *encodedName, int length, - uint64_t *iv, char *plaintextName ) const + uint64_t *iv, char *plaintextName ) const { - memcpy( plaintextName, encodedName, length ); - - return length; + memcpy( plaintextName, encodedName, length ); + return length; } bool NullNameIO::Enabled() { - return true; + return true; } diff --git a/encfs/NullNameIO.h b/fs/NullNameIO.h similarity index 100% rename from encfs/NullNameIO.h rename to fs/NullNameIO.h diff --git a/fs/RawFileIO.cpp b/fs/RawFileIO.cpp new file mode 100644 index 0000000..a46e916 --- /dev/null +++ b/fs/RawFileIO.cpp @@ -0,0 +1,330 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2004, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifdef linux +#define _XOPEN_SOURCE 500 // pick up pread , pwrite +#endif +#include + +#include "base/Error.h" +#include "fs/RawFileIO.h" + +#include + +#include +#include +#include +#include + +#include + +using namespace std; + +static Interface RawFileIO_iface = makeInterface("FileIO/Raw", 1, 0, 0); + +FileIO *NewRawFileIO( const Interface &iface ) +{ + (void)iface; + return new RawFileIO(); +} + +inline void swap( int &x, int &y ) +{ + int tmp = x; + x = y; + y = tmp; +} + +RawFileIO::RawFileIO( ) + : knownSize( false ) + , fileSize(0) + , fd( -1 ) + , oldfd( -1 ) + , canWrite( false ) +{ +} + +RawFileIO::RawFileIO( const std::string &fileName ) + : name( fileName ) + , knownSize( false ) + , fileSize( 0 ) + , fd( -1 ) + , oldfd( -1 ) + , canWrite( false ) +{ +} + +RawFileIO::~RawFileIO() +{ + int _fd = -1; + int _oldfd = -1; + + swap( _fd, fd ); + swap( _oldfd, oldfd ); + + if( _oldfd != -1 ) + close( _oldfd ); + + if( _fd != -1 ) + close( _fd ); +} + +Interface RawFileIO::interface() const +{ + return RawFileIO_iface; +} + +/* + Workaround for opening a file for write when permissions don't allow. + Since the kernel has already checked permissions, we can assume it is ok to + provide access. So force it by changing permissions temporarily. Should + be called with a lock around it so that there won't be a race condition + with calls to lstat picking up the wrong permissions. +*/ +static int open_readonly_workaround(const char *path, int flags) +{ + int fd = -1; + struct stat stbuf; + memset(&stbuf, 0, sizeof(struct stat)); + if(lstat( path, &stbuf ) != -1) + { + // make sure user has read/write permission.. + chmod( path , stbuf.st_mode | 0600 ); + fd = ::open( path , flags ); + chmod( path , stbuf.st_mode ); + } else + { + LOG(INFO) << "can't stat file " << path; + } + + return fd; +} + +/* + We shouldn't have to support all possible open flags, so untaint the flags + argument by only taking ones we understand and accept. + - Since the kernel has already done permission tests before calling us, we + shouldn't have to worry about access control. + - Basically we just need to distinguish between read and write flags + - Also keep the O_LARGEFILE flag, in case the underlying filesystem needs + it.. +*/ +int RawFileIO::open(int flags) +{ + bool requestWrite = ((flags & O_RDWR) || (flags & O_WRONLY)); + + VLOG(1) << "open call for " + << (requestWrite ? "writable" : "read only") + << " file"; + + int result = 0; + + // if we have a descriptor and it is writable, or we don't need writable.. + if((fd >= 0) && (canWrite || !requestWrite)) + { + VLOG(1) << "using existing file descriptor"; + result = fd; // success + } else + { + int finalFlags = requestWrite ? O_RDWR : O_RDONLY; + +#if defined(O_LARGEFILE) + if( flags & O_LARGEFILE ) + finalFlags |= O_LARGEFILE; +#else +#warning O_LARGEFILE not supported +#endif + + int newFd = ::open( name.c_str(), finalFlags ); + + VLOG(1) << "open file with flags " << finalFlags << ", result = " << newFd; + + if((newFd == -1) && (errno == EACCES)) + { + VLOG(1) << "using readonly workaround for open"; + newFd = open_readonly_workaround( name.c_str(), finalFlags ); + } + + if(newFd >= 0) + { + if(oldfd >= 0) + { + LOG(ERROR) << "leaking FD?: oldfd = " + << oldfd << ", fd = " << fd << ", newfd = " << newFd; + } + + // the old fd might still be in use, so just keep it around for + // now. + canWrite = requestWrite; + oldfd = fd; + result = fd = newFd; + } else + { + result = -errno; + LOG(INFO) << "::open error: " << strerror(errno); + } + } + + LOG_IF(INFO, result < 0) << "file " << name << " open failure: " << -result; + + return result; +} + +int RawFileIO::getAttr( struct stat *stbuf ) const +{ + int res = lstat( name.c_str(), stbuf ); + int eno = errno; + + LOG_IF(INFO, res < 0) << "getAttr error on " << name + << ": " << strerror( eno ); + + return ( res < 0 ) ? -eno : 0; +} + +void RawFileIO::setFileName( const char *fileName ) +{ + name = fileName; +} + +const char *RawFileIO::getFileName() const +{ + return name.c_str(); +} + +off_t RawFileIO::getSize() const +{ + if(!knownSize) + { + struct stat stbuf; + memset( &stbuf, 0, sizeof( struct stat )); + int res = lstat( name.c_str(), &stbuf ); + + if(res == 0) + { + fileSize = stbuf.st_size; + knownSize = true; + return fileSize; + } else + return -1; + } else + { + return fileSize; + } +} + +ssize_t RawFileIO::read( const IORequest &req ) const +{ + rAssert( fd >= 0 ); + + VLOG(2) << "Read " << req.dataLen << " bytes from offset " << req.offset; + ssize_t readSize = pread( fd, req.data, req.dataLen, req.offset ); + + if(readSize < 0) + { + LOG(INFO) << "read failed at offset " << req.offset + << " for " << req.dataLen << " bytes: " << strerror(errno); + } + + return readSize; +} + +bool RawFileIO::write( const IORequest &req ) +{ + rAssert( fd >= 0 ); + rAssert( true == canWrite ); + + VLOG(2) << "Write " << req.dataLen << " bytes to offset " << req.offset; + + int retrys = 10; + void *buf = req.data; + ssize_t bytes = req.dataLen; + off_t offset = req.offset; + + while( bytes && retrys > 0 ) + { + ssize_t writeSize = ::pwrite( fd, buf, bytes, offset ); + + if( writeSize < 0 ) + { + knownSize = false; + LOG(INFO) << "write failed at offset " << offset << " for " + << bytes << " bytes: " << strerror(errno); + return false; + } + + bytes -= writeSize; + offset += writeSize; + buf = (void*)((char*)buf + writeSize); + --retrys; + } + + if(bytes != 0) + { + LOG(ERROR) << "Write error: wrote " << (req.dataLen-bytes) + << " bytes of " << req.dataLen << ", max retries reached"; + knownSize = false; + return false; + } else + { + if(knownSize) + { + off_t last = req.offset + req.dataLen; + if(last > fileSize) + fileSize = last; + } + + return true; + } +} + +int RawFileIO::truncate( off_t size ) +{ + int res; + + if(fd >= 0 && canWrite) + { + res = ::ftruncate( fd, size ); +#ifndef __FreeBSD__ + ::fdatasync( fd ); +#endif + } else + res = ::truncate( name.c_str(), size ); + + if(res < 0) + { + int eno = errno; + LOG(INFO) << "truncate failed for " << name + << " (" << fd << ") size " << size << ", error " << strerror(eno); + res = -eno; + knownSize = false; + } else + { + res = 0; + fileSize = size; + knownSize = true; + } + + return res; +} + +bool RawFileIO::isWritable() const +{ + return canWrite; +} diff --git a/encfs/RawFileIO.h b/fs/RawFileIO.h similarity index 96% rename from encfs/RawFileIO.h rename to fs/RawFileIO.h index d172b09..b2c58a9 100644 --- a/encfs/RawFileIO.h +++ b/fs/RawFileIO.h @@ -52,8 +52,8 @@ protected: std::string name; - bool knownSize; - off_t fileSize; + mutable bool knownSize; + mutable off_t fileSize; int fd; int oldfd; diff --git a/fs/StreamNameIO.cpp b/fs/StreamNameIO.cpp new file mode 100644 index 0000000..d03df64 --- /dev/null +++ b/fs/StreamNameIO.cpp @@ -0,0 +1,206 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2004, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "base/base64.h" +#include "base/Error.h" +#include "base/i18n.h" +#include "cipher/Cipher.h" +#include "fs/StreamNameIO.h" + +#include + +#include + +using namespace std; + +static shared_ptr NewStreamNameIO( const Interface &iface, + const shared_ptr &cipher, const CipherKey &key) +{ + return shared_ptr( new StreamNameIO( iface, cipher, key ) ); +} + +static bool StreamIO_registered = NameIO::Register("Stream", + gettext_noop("Stream encoding, keeps filenames as short as possible"), + StreamNameIO::CurrentInterface(), + NewStreamNameIO, true); + + +/* + - Version 0.1 is for EncFS 0.x support. The difference to 1.0 is that 0.x + stores the file checksums at the end of the encoded name, where 1.0 + stores them at the beginning. + + - Version 1.0 is the basic stream encoding mode used since the beginning of + EncFS. There is a slight difference in filename encodings from EncFS 0.x + to 1.0.x. This implements just the 1.0.x method. + + - Version 1.1 adds support for IV chaining. This is transparently + backward compatible, since older filesystems do not use IV chaining. + + - Version 2.0 uses full 64 bit IV during IV chaining mode. Prior versions + used only the 16 bit output from MAC_16. This reduces the theoretical + possibility (unlikely to make any difference in practice) of two files + with the same name in different directories ending up with the same + encrypted name. Added because there is no good reason to chop to 16 + bits. + + - Version 2.1 adds support for version 0 for EncFS 0.x compatibility. +*/ +Interface StreamNameIO::CurrentInterface() +{ + // implement major version 2, 1, and 0 + return makeInterface("nameio/stream", 2, 1, 2); +} + +StreamNameIO::StreamNameIO( const Interface &iface, + const shared_ptr &cipher, + const CipherKey &key ) + : _interface( iface.major() ) + , _cipher( cipher ) + , _key( key ) +{ + +} + +StreamNameIO::~StreamNameIO() +{ +} + +Interface StreamNameIO::interface() const +{ + return CurrentInterface(); +} + +int StreamNameIO::maxEncodedNameLen( int plaintextStreamLen ) const +{ + int encodedStreamLen = 2 + plaintextStreamLen; + return B256ToB64Bytes( encodedStreamLen ); +} + +int StreamNameIO::maxDecodedNameLen( int encodedStreamLen ) const +{ + int decLen256 = B64ToB256Bytes( encodedStreamLen ); + return decLen256 - 2; +} + +int StreamNameIO::encodeName( const char *plaintextName, int length, + uint64_t *iv, char *encodedName ) const +{ + uint64_t tmpIV = 0; + if( iv && _interface >= 2 ) + tmpIV = *iv; + + unsigned int mac = _cipher->MAC_16( (const unsigned char *)plaintextName, + length, _key, iv ); + + // add on checksum bytes + unsigned char *encodeBegin; + if(_interface >= 1) + { + // current versions store the checksum at the beginning + encodedName[0] = (mac >> 8) & 0xff; + encodedName[1] = (mac ) & 0xff; + encodeBegin = (unsigned char *)encodedName+2; + } else + { + // encfs 0.x stored checksums at the end. + encodedName[length] = (mac >> 8) & 0xff; + encodedName[length+1] = (mac ) & 0xff; + encodeBegin = (unsigned char *)encodedName; + } + + // stream encode the plaintext bytes + memcpy( encodeBegin, plaintextName, length ); + _cipher->streamEncode( encodeBegin, length, (uint64_t)mac ^ tmpIV, _key); + + // convert the entire thing to base 64 ascii.. + int encodedStreamLen = length + 2; + int encLen64 = B256ToB64Bytes( encodedStreamLen ); + + changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen, + 8, 6, true ); + B64ToAscii( (unsigned char *)encodedName, encLen64 ); + + return encLen64; +} + +int StreamNameIO::decodeName( const char *encodedName, int length, + uint64_t *iv, char *plaintextName ) const +{ + rAssert(length > 2); + int decLen256 = B64ToB256Bytes( length ); + int decodedStreamLen = decLen256 - 2; + + if(decodedStreamLen <= 0) + throw Error("Filename too small to decode"); + + BUFFER_INIT( tmpBuf, 32, (unsigned int)length ); + + // decode into tmpBuf, because this step produces more data then we can fit + // into the result buffer.. + AsciiToB64( (unsigned char *)tmpBuf, (unsigned char *)encodedName, length ); + changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false); + + // pull out the checksum value which is used as an initialization vector + uint64_t tmpIV = 0; + unsigned int mac; + if(_interface >= 1) + { + // current versions store the checksum at the beginning + mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 + | ((unsigned int)((unsigned char)tmpBuf[1])); + + // version 2 adds support for IV chaining.. + if( iv && _interface >= 2 ) + tmpIV = *iv; + + memcpy( plaintextName, tmpBuf+2, decodedStreamLen ); + } else + { + // encfs 0.x stored checksums at the end. + mac = ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen])) << 8 + | ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen+1])); + + memcpy( plaintextName, tmpBuf, decodedStreamLen ); + } + + _cipher->streamDecode( (unsigned char *)plaintextName, decodedStreamLen, + (uint64_t)mac ^ tmpIV, _key); + + // compute MAC to check with stored value + unsigned int mac2 = _cipher->MAC_16((const unsigned char *)plaintextName, + decodedStreamLen, _key, iv); + + BUFFER_RESET( tmpBuf ); + if(mac2 != mac) + { + VLOG(1) << "checksum mismatch: expected " << mac << ", got " << mac2 + << "on decode of " << decodedStreamLen << " bytes"; + throw Error( "checksum mismatch in filename decode" ); + } + + return decodedStreamLen; +} + +bool StreamNameIO::Enabled() +{ + return true; +} + diff --git a/encfs/StreamNameIO.h b/fs/StreamNameIO.h similarity index 97% rename from encfs/StreamNameIO.h rename to fs/StreamNameIO.h index a18e23c..9ff40a3 100644 --- a/encfs/StreamNameIO.h +++ b/fs/StreamNameIO.h @@ -21,8 +21,8 @@ #ifndef _StreamNameIO_incl_ #define _StreamNameIO_incl_ -#include "NameIO.h" -#include "CipherKey.h" +#include "cipher/CipherKey.h" +#include "fs/NameIO.h" class Cipher; diff --git a/fs/encfs.cpp b/fs/encfs.cpp new file mode 100644 index 0000000..e41620d --- /dev/null +++ b/fs/encfs.cpp @@ -0,0 +1,793 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2003-2007, Valient Gough + * + * This program is free software; you can distribute it and/or modify it under + * the terms of the GNU General Public License (GPL), as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include "fs/encfs.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#ifdef linux +#include +#endif + +#ifdef HAVE_ATTR_XATTR_H +#include +#elif defined(HAVE_SYS_XATTR_H) +#include +#endif + + +#include +#include + +#ifdef HAVE_TR1_TUPLE +#include +using namespace std; +using namespace std::tr1; +#else +#include +using namespace std; +#endif + +#include "base/shared_ptr.h" +#include "base/Mutex.h" +#include "base/Error.h" +#include "cipher/MemoryPool.h" +#include "fs/DirNode.h" +#include "fs/FileUtils.h" +#include "fs/Context.h" + +#include + +#ifndef MIN +#define MIN(a,b) (((a)<(b)) ? (a): (b)) +#endif + +#define ESUCCESS 0 + +using rel::Lock; + +#define GET_FN(ctx, finfo) ctx->getNode((void*)(uintptr_t)finfo->fh) + +static EncFS_Context * context() +{ + return (EncFS_Context*)fuse_get_context()->private_data; +} + +/* + The log messages below always print out encrypted filenames, not + plaintext. The reason is so that it isn't possible to leak information + about the encrypted data through logging interfaces. + + + The purpose of this layer of code is to take the FUSE request and dispatch + to the internal interfaces. Any marshaling of arguments and return types + can be done here. +*/ + +// helper function -- apply a functor to a cipher path, given the plain path +template +static int withCipherPath( const char *opName, const char *path, + int (*op)(EncFS_Context *, const string &name, T data ), T data, + bool passReturnCode = false ) +{ + EncFS_Context *ctx = context(); + + int res = -EIO; + shared_ptr FSRoot = ctx->getRoot(&res); + if(!FSRoot) + return res; + + try + { + string cyName = FSRoot->cipherPath( path ); + VLOG(1) << opName << " " << cyName.c_str(); + + res = op( ctx, cyName, data ); + + if(res == -1) + { + res = -errno; + LOG(INFO) << opName << " error: " << strerror(-res); + } else if(!passReturnCode) + res = ESUCCESS; + } catch( Error &err ) + { + LOG(ERROR) << "error caught in " << opName << + ":" << err.what(); + } + return res; +} + +// helper function -- apply a functor to a node +template +static int withFileNode( const char *opName, + const char *path, struct fuse_file_info *fi, + int (*op)(FileNode *, T data ), T data ) +{ + EncFS_Context *ctx = context(); + + int res = -EIO; + shared_ptr FSRoot = ctx->getRoot(&res); + if(!FSRoot) + return res; + + try + { + shared_ptr fnode; + + if(fi != NULL) + fnode = GET_FN(ctx, fi); + else + fnode = FSRoot->lookupNode( path, opName ); + + rAssert(fnode != NULL); + VLOG(1) << opName << " " << fnode->cipherName(); + res = op( fnode.get(), data ); + + LOG_IF(INFO, res < 0) << opName << " error: " << strerror(-res); + } catch( Error &err ) + { + LOG(ERROR) << "error caught in " << opName << + ":" << err.what(); + } + return res; +} + +int _do_getattr(FileNode *fnode, struct stat *stbuf) +{ + int res = fnode->getAttr(stbuf); + if(res == ESUCCESS && S_ISLNK(stbuf->st_mode)) + { + EncFS_Context *ctx = context(); + shared_ptr FSRoot = ctx->getRoot(&res); + if(FSRoot) + { + // determine plaintext link size.. Easiest to read and decrypt.. + vector buf(stbuf->st_size+1, 0); + + res = ::readlink( fnode->cipherName(), &buf[0], stbuf->st_size ); + if(res >= 0) + { + // other functions expect c-strings to be null-terminated, which + // readlink doesn't provide + buf[res] = '\0'; + + stbuf->st_size = FSRoot->plainPath( &buf[0] ).length(); + + res = ESUCCESS; + } else + res = -errno; + } + } + + return res; +} + +int encfs_getattr(const char *path, struct stat *stbuf) +{ + return withFileNode( "getattr", path, NULL, _do_getattr, stbuf ); +} + +int encfs_fgetattr(const char *path, struct stat *stbuf, + struct fuse_file_info *fi) +{ + return withFileNode( "fgetattr", path, fi, _do_getattr, stbuf ); +} + +int encfs_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler) +{ + EncFS_Context *ctx = context(); + + int res = ESUCCESS; + shared_ptr FSRoot = ctx->getRoot(&res); + if(!FSRoot) + return res; + + try + { + + DirTraverse dt = FSRoot->openDir( path ); + + VLOG(1) << "getdir on " << FSRoot->cipherPath(path); + + if(dt.valid()) + { + int fileType = 0; + ino_t inode = 0; + + std::string name = dt.nextPlaintextName( &fileType, &inode ); + while( !name.empty() ) + { + res = filler( h, name.c_str(), fileType, inode ); + + if(res != ESUCCESS) + break; + + name = dt.nextPlaintextName( &fileType, &inode ); + } + } else + { + LOG(INFO) << "getdir request invalid, path: '" << path << "'"; + } + + return res; + } catch( Error &err ) + { + LOG(ERROR) << "error caught in getdir: " << err.what(); + return -EIO; + } +} + +int encfs_mknod(const char *path, mode_t mode, dev_t rdev) +{ + EncFS_Context *ctx = context(); + + int res = -EIO; + shared_ptr FSRoot = ctx->getRoot(&res); + if(!FSRoot) + return res; + + try + { + shared_ptr fnode = FSRoot->lookupNode( path, "mknod" ); + + VLOG(1) << "mknod on " << fnode->cipherName() + << ", mode " << mode << ", dev " << rdev; + + uid_t uid = 0; + gid_t gid = 0; + if(ctx->publicFilesystem) + { + fuse_context *context = fuse_get_context(); + uid = context->uid; + gid = context->gid; + } + res = fnode->mknod( mode, rdev, uid, gid ); + // Is this error due to access problems? + if(ctx->publicFilesystem && -res == EACCES) + { + // try again using the parent dir's group + string parent = fnode->plaintextParent(); + LOG(INFO) << "attempting public filesystem workaround for " + << parent.c_str(); + shared_ptr dnode = + FSRoot->lookupNode( parent.c_str(), "mknod" ); + + struct stat st; + if(dnode->getAttr( &st ) == 0) + res = fnode->mknod( mode, rdev, uid, st.st_gid ); + } + } catch( Error &err ) + { + LOG(ERROR) << "error caught in mknod: " << err.what(); + } + return res; +} + +int encfs_mkdir(const char *path, mode_t mode) +{ + fuse_context *fctx = fuse_get_context(); + EncFS_Context *ctx = context(); + + int res = -EIO; + shared_ptr FSRoot = ctx->getRoot(&res); + if(!FSRoot) + return res; + + try + { + uid_t uid = 0; + gid_t gid = 0; + if(ctx->publicFilesystem) + { + uid = fctx->uid; + gid = fctx->gid; + } + res = FSRoot->mkdir( path, mode, uid, gid ); + // Is this error due to access problems? + if(ctx->publicFilesystem && -res == EACCES) + { + // try again using the parent dir's group + string parent = parentDirectory( path ); + shared_ptr dnode = + FSRoot->lookupNode( parent.c_str(), "mkdir" ); + + struct stat st; + if(dnode->getAttr( &st ) == 0) + res = FSRoot->mkdir( path, mode, uid, st.st_gid ); + } + } catch( Error &err ) + { + LOG(ERROR) << "error caught in mkdir: " << err.what(); + } + return res; +} + +int encfs_unlink(const char *path) +{ + EncFS_Context *ctx = context(); + + int res = -EIO; + shared_ptr FSRoot = ctx->getRoot(&res); + if(!FSRoot) + return res; + + try + { + // let DirNode handle it atomically so that it can handle race + // conditions + res = FSRoot->unlink( path ); + } catch( Error &err ) + { + LOG(ERROR) << "error caught in unlink: " << err.what(); + } + return res; +} + + +int _do_rmdir(EncFS_Context *, const string &cipherPath, int ) +{ + return rmdir( cipherPath.c_str() ); +} + +int encfs_rmdir(const char *path) +{ + return withCipherPath( "rmdir", path, _do_rmdir, 0 ); +} + +int _do_readlink(EncFS_Context *ctx, const string &cyName, + tuple data ) +{ + char *buf = get<0>(data); + size_t size = get<1>(data); + + int res = ESUCCESS; + shared_ptr FSRoot = ctx->getRoot(&res); + if(!FSRoot) + return res; + + res = ::readlink( cyName.c_str(), buf, size-1 ); + + if(res == -1) + return -errno; + + buf[res] = '\0'; // ensure null termination + string decodedName; + try + { + decodedName = FSRoot->plainPath( buf ); + } catch(...) { } + + if(!decodedName.empty()) + { + strncpy(buf, decodedName.c_str(), size-1); + buf[size-1] = '\0'; + + return ESUCCESS; + } else + { + LOG(WARNING) << "Error decoding link"; + return -1; + } +} + +int encfs_readlink(const char *path, char *buf, size_t size) +{ + return withCipherPath( "readlink", path, _do_readlink, + make_tuple(buf, size) ); +} + +int encfs_symlink(const char *from, const char *to) +{ + EncFS_Context *ctx = context(); + + int res = -EIO; + shared_ptr FSRoot = ctx->getRoot(&res); + if(!FSRoot) + return res; + + try + { + // allow fully qualified names in symbolic links. + string fromCName = FSRoot->relativeCipherPath( from ); + string toCName = FSRoot->cipherPath( to ); + + VLOG(1) << "symlink " << fromCName << " -> " << toCName; + + // use setfsuid / setfsgid so that the new link will be owned by the + // uid/gid provided by the fuse_context. + int olduid = -1; + int oldgid = -1; + if(ctx->publicFilesystem) + { + fuse_context *context = fuse_get_context(); + olduid = setfsuid( context->uid ); + oldgid = setfsgid( context->gid ); + } + res = ::symlink( fromCName.c_str(), toCName.c_str() ); + if(olduid >= 0) + setfsuid( olduid ); + if(oldgid >= 0) + setfsgid( oldgid ); + + if(res == -1) + res = -errno; + else + res = ESUCCESS; + } catch( Error &err ) + { + LOG(ERROR) << "error caught in symlink: " << err.what(); + } + return res; +} + +int encfs_link(const char *from, const char *to) +{ + EncFS_Context *ctx = context(); + + int res = -EIO; + shared_ptr FSRoot = ctx->getRoot(&res); + if(!FSRoot) + return res; + + try + { + res = FSRoot->link( from, to ); + } catch( Error &err ) + { + LOG(ERROR) << "error caught in link: " << err.what(); + } + return res; +} + +int encfs_rename(const char *from, const char *to) +{ + EncFS_Context *ctx = context(); + + int res = -EIO; + shared_ptr FSRoot = ctx->getRoot(&res); + if(!FSRoot) + return res; + + try + { + res = FSRoot->rename( from, to ); + } catch( Error &err ) + { + LOG(ERROR) << "error caught in rename: " << err.what(); + } + return res; +} + +int _do_chmod(EncFS_Context *, const string &cipherPath, mode_t mode) +{ + return chmod( cipherPath.c_str(), mode ); +} + +int encfs_chmod(const char *path, mode_t mode) +{ + return withCipherPath( "chmod", path, _do_chmod, mode ); +} + +int _do_chown(EncFS_Context *, const string &cyName, + tuple data) +{ + int res = lchown( cyName.c_str(), get<0>(data), get<1>(data) ); + return (res == -1) ? -errno : ESUCCESS; +} + +int encfs_chown(const char *path, uid_t uid, gid_t gid) +{ + return withCipherPath( "chown", path, _do_chown, make_tuple(uid, gid)); +} + +int _do_truncate( FileNode *fnode, off_t size ) +{ + return fnode->truncate( size ); +} + +int encfs_truncate(const char *path, off_t size) +{ + return withFileNode( "truncate", path, NULL, _do_truncate, size ); +} + +int encfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi) +{ + return withFileNode( "ftruncate", path, fi, _do_truncate, size ); +} + +int _do_utime(EncFS_Context *, const string &cyName, struct utimbuf *buf) +{ + int res = utime( cyName.c_str(), buf); + return (res == -1) ? -errno : ESUCCESS; +} + +int encfs_utime(const char *path, struct utimbuf *buf) +{ + return withCipherPath( "utime", path, _do_utime, buf ); +} + +int _do_utimens(EncFS_Context *, const string &cyName, + const struct timespec ts[2]) +{ + struct timeval tv[2]; + tv[0].tv_sec = ts[0].tv_sec; + tv[0].tv_usec = ts[0].tv_nsec / 1000; + tv[1].tv_sec = ts[1].tv_sec; + tv[1].tv_usec = ts[1].tv_nsec / 1000; + + int res = lutimes( cyName.c_str(), tv); + return (res == -1) ? -errno : ESUCCESS; +} + +int encfs_utimens(const char *path, const struct timespec ts[2] ) +{ + return withCipherPath( "utimens", path, _do_utimens, ts ); +} + +int encfs_open(const char *path, struct fuse_file_info *file) +{ + EncFS_Context *ctx = context(); + + int res = -EIO; + shared_ptr FSRoot = ctx->getRoot(&res); + if(!FSRoot) + return res; + + try + { + shared_ptr fnode = + FSRoot->openNode( path, "open", file->flags, &res ); + + if(fnode) + { + VLOG(1) << "encfs_open for " << fnode->cipherName() + << ", flags " << file->flags; + + if( res >= 0 ) + { + file->fh = (uintptr_t)ctx->putNode(path, fnode); + res = ESUCCESS; + } + } + } catch( Error &err ) + { + LOG(ERROR) << "error caught in open: " << err.what(); + } + + return res; +} + +int _do_flush(FileNode *fnode, int ) +{ + /* Flush can be called multiple times for an open file, so it doesn't + close the file. However it is important to call close() for some + underlying filesystems (like NFS). + */ + int res = fnode->open( O_RDONLY ); + if(res >= 0) + { + int fh = res; + res = close(dup(fh)); + if(res == -1) + res = -errno; + } + + return res; +} + +int encfs_flush(const char *path, struct fuse_file_info *fi) +{ + return withFileNode( "flush", path, fi, _do_flush, 0 ); +} + +/* +Note: This is advisory -- it might benefit us to keep file nodes around for a +bit after they are released just in case they are reopened soon. But that +requires a cache layer. + */ +int encfs_release(const char *path, struct fuse_file_info *finfo) +{ + EncFS_Context *ctx = context(); + + try + { + ctx->eraseNode( path, (void*)(uintptr_t)finfo->fh ); + return ESUCCESS; + } catch( Error &err ) + { + LOG(ERROR) << "error caught in release: " << err.what(); + return -EIO; + } +} + +int _do_read(FileNode *fnode, tuple data) +{ + return fnode->read( get<2>(data), get<0>(data), get<1>(data)); +} + +int encfs_read(const char *path, char *buf, size_t size, off_t offset, + struct fuse_file_info *file) +{ + return withFileNode( "read", path, file, _do_read, + make_tuple((unsigned char *)buf, size, offset)); +} + +int _do_fsync(FileNode *fnode, int dataSync) +{ + return fnode->sync( dataSync != 0 ); +} + +int encfs_fsync(const char *path, int dataSync, + struct fuse_file_info *file) +{ + return withFileNode( "fsync", path, file, _do_fsync, dataSync ); +} + +int _do_write(FileNode *fnode, tuple data) +{ + size_t size = get<1>(data); + if(fnode->write( get<2>(data), (unsigned char *)get<0>(data), size )) + return size; + else + return -EIO; +} + +int encfs_write(const char *path, const char *buf, size_t size, + off_t offset, struct fuse_file_info *file) +{ + return withFileNode("write", path, file, _do_write, + make_tuple(buf, size, offset)); +} + +// statfs works even if encfs is detached.. +int encfs_statfs(const char *path, struct statvfs *st) +{ + EncFS_Context *ctx = context(); + + int res = -EIO; + try + { + (void)path; // path should always be '/' for now.. + rAssert( st != NULL ); + string cyName = ctx->rootCipherDir; + + VLOG(1) << "doing statfs of " << cyName; + res = statvfs( cyName.c_str(), st ); + if(!res) + { + // adjust maximum name length.. + st->f_namemax = 6 * (st->f_namemax - 2) / 8; // approx.. + } + if(res == -1) + res = -errno; + } catch( Error &err ) + { + LOG(ERROR) << "error caught in statfs: " << err.what(); + } + return res; +} + +#ifdef HAVE_XATTR + + +#ifdef XATTR_ADD_OPT +int _do_setxattr(EncFS_Context *, const string &cyName, + tuple data) +{ + int options = 0; + return ::setxattr( cyName.c_str(), get<0>(data), get<1>(data), + get<2>(data), get<3>(data), options ); +} +int encfs_setxattr( const char *path, const char *name, + const char *value, size_t size, int flags, uint32_t position ) +{ + (void)flags; + return withCipherPath( "setxattr", path, _do_setxattr, + make_tuple(name, value, size, position) ); +} +#else +int _do_setxattr(EncFS_Context *, const string &cyName, + tuple data) +{ + return ::setxattr( cyName.c_str(), get<0>(data), get<1>(data), + get<2>(data), get<3>(data) ); +} +int encfs_setxattr( const char *path, const char *name, + const char *value, size_t size, int flags ) +{ + return withCipherPath( "setxattr", path, _do_setxattr, + make_tuple(name, value, size, flags) ); +} +#endif + + +#ifdef XATTR_ADD_OPT +int _do_getxattr(EncFS_Context *, const string &cyName, + tuple data) +{ + int options = 0; + return ::getxattr( cyName.c_str(), get<0>(data), + get<1>(data), get<2>(data), get<3>(data), options ); +} +int encfs_getxattr( const char *path, const char *name, + char *value, size_t size, uint32_t position ) +{ + return withCipherPath( "getxattr", path, _do_getxattr, + make_tuple(name, (void *)value, size, position), true ); +} +#else +int _do_getxattr(EncFS_Context *, const string &cyName, + tuple data) +{ + return ::getxattr( cyName.c_str(), get<0>(data), + get<1>(data), get<2>(data)); +} +int encfs_getxattr( const char *path, const char *name, + char *value, size_t size ) +{ + return withCipherPath( "getxattr", path, _do_getxattr, + make_tuple(name, (void *)value, size), true ); +} +#endif + + +int _do_listxattr(EncFS_Context *, const string &cyName, + tuple data) +{ +#ifdef XATTR_ADD_OPT + int options = 0; + int res = ::listxattr( cyName.c_str(), get<0>(data), get<1>(data), + options ); +#else + int res = ::listxattr( cyName.c_str(), get<0>(data), get<1>(data) ); +#endif + return (res == -1) ? -errno : res; +} + +int encfs_listxattr( const char *path, char *list, size_t size ) +{ + return withCipherPath( "listxattr", path, _do_listxattr, + make_tuple(list, size), true ); +} + +int _do_removexattr(EncFS_Context *, const string &cyName, const char *name) +{ +#ifdef XATTR_ADD_OPT + int options = 0; + int res = ::removexattr( cyName.c_str(), name, options ); +#else + int res = ::removexattr( cyName.c_str(), name ); +#endif + return (res == -1) ? -errno : res; +} + +int encfs_removexattr( const char *path, const char *name ) +{ + return withCipherPath( "removexattr", path, _do_removexattr, name ); +} + +#endif // HAVE_XATTR + diff --git a/encfs/encfs.h b/fs/encfs.h similarity index 99% rename from encfs/encfs.h rename to fs/encfs.h index 3256300..912e9fd 100644 --- a/encfs/encfs.h +++ b/fs/encfs.h @@ -21,7 +21,7 @@ #ifndef _encfs_incl_ #define _encfs_incl_ -#include "config.h" +#include "base/config.h" #include #include diff --git a/fs/test.cpp b/fs/test.cpp new file mode 100644 index 0000000..f7c9af4 --- /dev/null +++ b/fs/test.cpp @@ -0,0 +1,556 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2003, Valient Gough + * + * This library is free software; you can distribute it and/or modify it under + * the terms of the GNU General Public License (GPL), as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GPL in the file COPYING for more + * details. + * + */ + +#include "fs/encfs.h" + +#include +#include +#include +#include + +#include "base/config.h" +#include "base/Interface.h" +#include "base/Error.h" +#include "cipher/Cipher.h" +#include "cipher/MemoryPool.h" +#include "fs/DirNode.h" +#include "fs/FileUtils.h" +#include "fs/StreamNameIO.h" +#include "fs/BlockNameIO.h" +#include "fs/NullNameIO.h" + +#include + +#ifdef HAVE_SSL +#define NO_DES +#include +#ifndef OPENSSL_NO_ENGINE +#include +#endif +#endif + +#include + +#if HAVE_TR1_UNORDERED_SET +#include +using std::tr1::unordered_set; +#else +#include +using std::unordered_set; +#endif + +using namespace std; + +const int FSBlockSize = 256; + +static +int checkErrorPropogation( const shared_ptr &cipher, + int size, int byteToChange, const CipherKey &key ) +{ + MemBlock orig; + orig.allocate(size); + MemBlock data; + data.allocate(size); + + for(int i=0; istreamEncode( data.data, size, 0, key ); + else + cipher->blockEncode( data.data, size, 0, key ); + + // intoduce an error in the encoded data, so we can check error propogation + if(byteToChange >= 0 && byteToChange < size) + { + unsigned char previousValue = data.data[byteToChange]; + do + { + data.data[byteToChange] = rand(); + } while(data.data[byteToChange] == previousValue); + } + + if(size != FSBlockSize) + cipher->streamDecode( data.data, size, 0, key ); + else + cipher->blockDecode( data.data, size, 0, key ); + + int numByteErrors = 0; + for(int i=0; i \"" << encName.c_str() << "\""; + + // decrypt name + string decName = dirNode.plainPath( encName.c_str() ); + + if(decName == *orig) + { + if(verbose) + cerr << " OK\n"; + } else + { + if(verbose) + cerr << " FAILED (got " << decName << ")\n"; + return false; + } + + orig++; + } + + if (collisionTest) + { + if (verbose) + cerr << "Checking for name collections, this will take a while..\n"; + // check for collision rate + char buf[64]; + unordered_set encryptedNames; + for (long i=0; i < 10000000; i++) + { + snprintf(buf, sizeof(buf), "%li", i); + string encName = dirNode.relativeCipherPath( buf ); + // simulate a case-insisitive filesystem.. + std::transform(encName.begin(), encName.end(), encName.begin(), + ::toupper); + + if (encryptedNames.insert(encName).second == false) { + cerr << "collision detected after " << i << " iterations"; + break; + } + } + cerr << "NO collisions detected"; + } + + return true; +} + +bool runTests(const shared_ptr &cipher, bool verbose) +{ + // create a random key + if(verbose) + cerr << "Generating new key, output will be different on each run\n\n"; + CipherKey key = cipher->newRandomKey(); + + if(verbose) + cerr << "Testing key save / restore :"; + { + CipherKey encodingKey = cipher->newRandomKey(); + int encodedKeySize = cipher->encodedKeySize(); + unsigned char *keyBuf = new unsigned char [ encodedKeySize ]; + + cipher->writeKey( key, keyBuf, encodingKey ); + CipherKey key2 = cipher->readKey( keyBuf, encodingKey ); + if(!key2) + { + if(verbose) + cerr << " FAILED (decode error)\n"; + return false; + } + + if(cipher->compareKey( key, key2 )) + { + if(verbose) + cerr << " OK\n"; + } else + { + if(verbose) + cerr << " FAILED\n"; + return false; + } + } + + if(verbose) + cerr << "Testing Config interface load / store :"; + { + CipherKey encodingKey = cipher->newRandomKey(); + int encodedKeySize = cipher->encodedKeySize(); + unsigned char *keyBuf = new unsigned char [ encodedKeySize ]; + + cipher->writeKey( key, keyBuf, encodingKey ); + + // store in config struct.. + EncfsConfig cfg; + cfg.mutable_cipher()->MergeFrom(cipher->interface()); + EncryptedKey *encryptedKey = cfg.mutable_key(); + encryptedKey->set_size(8 * cipher->keySize()); + encryptedKey->set_ciphertext( keyBuf, encodedKeySize ); + cfg.set_block_size(FSBlockSize); + + // save config + string data; + google::protobuf::TextFormat::PrintToString(cfg, &data); + + // read back in and check everything.. + EncfsConfig cfg2; + google::protobuf::TextFormat::ParseFromString(data, &cfg2); + + // check.. + rAssert( implements(cfg.cipher(),cfg2.cipher()) ); + rAssert( cfg.key().size() == cfg2.key().size() ); + rAssert( cfg.block_size() == cfg2.block_size() ); + + // try decoding key.. + + CipherKey key2 = cipher->readKey( (unsigned char *)cfg2.key().ciphertext().data(), encodingKey ); + if(!key2) + { + if(verbose) + cerr << " FAILED (decode error)\n"; + return false; + } + + if(cipher->compareKey( key, key2 )) + { + if(verbose) + cerr << " OK\n"; + } else + { + if(verbose) + cerr << " FAILED\n"; + return false; + } + } + + FSConfigPtr fsCfg = FSConfigPtr(new FSConfig); + fsCfg->cipher = cipher; + fsCfg->key = key; + fsCfg->config.reset(new EncfsConfig); + fsCfg->config->set_block_size(FSBlockSize); + fsCfg->opts.reset(new EncFS_Opts); + + if(verbose) + cerr << "Testing name encode/decode (stream coding w/ IV chaining)\n"; + if (cipher->hasStreamMode()) + { + fsCfg->opts->idleTracking = false; + fsCfg->config->set_unique_iv(false); + + fsCfg->nameCoding.reset( new StreamNameIO( + StreamNameIO::CurrentInterface(), cipher, key ) ); + fsCfg->nameCoding->setChainedNameIV( true ); + + DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); + + if(!testNameCoding( dirNode, verbose )) + return false; + } + + if(verbose) + cerr << "Testing name encode/decode (block coding w/ IV chaining)\n"; + { + fsCfg->opts->idleTracking = false; + fsCfg->config->set_unique_iv(false); + fsCfg->nameCoding.reset( new BlockNameIO( + BlockNameIO::CurrentInterface(), cipher, key ) ); + fsCfg->nameCoding->setChainedNameIV( true ); + + DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); + + if(!testNameCoding( dirNode, verbose )) + return false; + } + + if(verbose) + cerr << "Testing name encode/decode (block coding w/ IV chaining, base32)\n"; + { + fsCfg->opts->idleTracking = false; + fsCfg->config->set_unique_iv(false); + fsCfg->nameCoding.reset( new BlockNameIO( + BlockNameIO::CurrentInterface(), cipher, key, true ) ); + fsCfg->nameCoding->setChainedNameIV( true ); + + DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); + + if(!testNameCoding( dirNode, verbose )) + return false; + } + + if(!verbose) + { + if (cipher->hasStreamMode()) + { + // test stream mode, this time without IV chaining + fsCfg->nameCoding = + shared_ptr( new StreamNameIO( + StreamNameIO::CurrentInterface(), cipher, key ) ); + fsCfg->nameCoding->setChainedNameIV( false ); + + DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); + + if(!testNameCoding( dirNode, verbose )) + return false; + } + + { + // test block mode, this time without IV chaining + fsCfg->nameCoding = shared_ptr( new BlockNameIO( + BlockNameIO::CurrentInterface(), cipher, key ) ); + fsCfg->nameCoding->setChainedNameIV( false ); + + DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); + + if(!testNameCoding( dirNode, verbose )) + return false; + } + } + + if(verbose) + cerr << "Testing block encode/decode on full block - "; + { + int numErrors = checkErrorPropogation( cipher, + FSBlockSize, -1, key ); + if(numErrors) + { + if(verbose) + cerr << " FAILED!\n"; + return false; + } else + { + if(verbose) + cerr << " OK\n"; + } + } + if(verbose) + cerr << "Testing block encode/decode on partial block - "; + if (cipher->hasStreamMode()) + { + int numErrors = checkErrorPropogation( cipher, + FSBlockSize-1, -1, key ); + if(numErrors) + { + if(verbose) + cerr << " FAILED!\n"; + return false; + } else + { + if(verbose) + cerr << " OK\n"; + } + } + + if(verbose) + cerr << "Checking error propogation in partial block:\n"; + if (cipher->hasStreamMode()) + { + int minChanges = FSBlockSize-1; + int maxChanges = 0; + int minAt = 0; + int maxAt = 0; + for(int i=0; i maxChanges) + { + maxChanges = numErrors; + maxAt = i; + } + } + + if(verbose) + { + cerr << "modification of 1 byte affected between " << minChanges + << " and " << maxChanges << " decoded bytes\n"; + cerr << "minimum change at byte " << minAt + << " and maximum at byte " << maxAt << "\n"; + } + } + if(verbose) + cerr << "Checking error propogation on full block:\n"; + { + int minChanges = FSBlockSize; + int maxChanges = 0; + int minAt = 0; + int maxAt = 0; + for(int i=0; i maxChanges) + { + maxChanges = numErrors; + maxAt = i; + } + } + + if(verbose) + { + cerr << "modification of 1 byte affected between " << minChanges + << " and " << maxChanges << " decoded bytes\n"; + cerr << "minimum change at byte " << minAt + << " and maximum at byte " << maxAt << "\n"; + } + } + + return true; +} + + +int main(int argc, char *argv[]) +{ + FLAGS_logtostderr = 1; + FLAGS_minloglevel = 1; + + google::InitGoogleLogging(argv[0]); + google::InstallFailureSignalHandler(); + +#ifdef HAVE_SSL + SSL_load_error_strings(); + SSL_library_init(); + +#ifndef OPENSSL_NO_ENGINE + ENGINE_load_builtin_engines(); + ENGINE_register_all_ciphers(); + ENGINE_register_all_digests(); + ENGINE_register_all_RAND(); +#endif +#endif + + srand( time(0) ); + + // get a list of the available algorithms + std::list algorithms = + Cipher::GetAlgorithmList(); + std::list::const_iterator it; + cerr << "Supported Crypto interfaces:\n"; + for(it = algorithms.begin(); it != algorithms.end(); ++it) + { + cerr << it->name + << " ( " << it->iface.name() << " " + << it->iface.major() << ":" + << it->iface.minor() << ":" + << it->iface.age() << " ) : " << it->description << "\n"; + cerr << " - key length " << it->keyLength.min() << " to " + << it->keyLength.max() << " , block size " << it->blockSize.min() + << " to " << it->blockSize.max() << "\n"; + } + cerr << "\n"; + + cerr << "Testing interfaces\n"; + for(it = algorithms.begin(); it != algorithms.end(); ++it) + { + int blockSize = it->blockSize.closest( 256 ); + for(int keySize = it->keyLength.min(); keySize <= it->keyLength.max(); + keySize += it->keyLength.inc()) + { + cerr << it->name << ", key length " << keySize + << ", block size " << blockSize << ": "; + + shared_ptr cipher = Cipher::New( it->name, keySize ); + if(!cipher) + { + cerr << "FAILED TO CREATE\n"; + } else + { + try + { + if(runTests( cipher, false )) + cerr << "OK\n"; + else + cerr << "FAILED\n"; + } catch( Error &er ) + { + cerr << "Error: " << er.what() << "\n"; + } + } + } + } + + // run one test with verbose output too.. + shared_ptr cipher = Cipher::New("AES", 192); + if(!cipher) + { + cerr << "\nNo AES cipher found, skipping verbose test.\n"; + } else + { + cerr << "\nVerbose output for " << cipher->interface().name() + << " test, key length " << cipher->keySize()*8 << ", block size " + << FSBlockSize << ":\n"; + + runTests( cipher, true ); + } + + MemoryPool::destroyAll(); + + return 0; +} + + + diff --git a/fs/test_BlockIO.cpp b/fs/test_BlockIO.cpp new file mode 100644 index 0000000..c81462e --- /dev/null +++ b/fs/test_BlockIO.cpp @@ -0,0 +1,67 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2012 Valient Gough + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include + +#include "cipher/MemoryPool.h" + +#include "fs/testing.h" +#include "fs/FileUtils.h" +#include "fs/FSConfig.h" +#include "fs/MemFileIO.h" +#include "fs/MemBlockFileIO.h" + +namespace { + +TEST(BlockFileIOTest, BasicIO) { + // Base for comparison. + MemFileIO base(1024); + ASSERT_EQ(1024, base.getSize()); + + FSConfigPtr cfg = makeConfig( Cipher::New("Null"), 512); + MemBlockFileIO block(512, cfg); + block.truncate(1024); + ASSERT_EQ(1024, block.getSize()); + + MemBlock mb; + mb.allocate(256); + + IORequest req; + req.offset = 0; + req.data = mb.data; + req.dataLen = 256; + + for (int i = 0; i < 4; i++) { + req.offset = i * 256; + memset(req.data, 0, req.dataLen); + ASSERT_TRUE(base.write(req)); + + req.offset = i * 256; + memset(req.data, 0, req.dataLen); + ASSERT_TRUE(block.write(req)); + } + + ASSERT_NO_FATAL_FAILURE(compare(&base, &block, 0, 1024)); +} + +} // namespace + diff --git a/fs/test_IO.cpp b/fs/test_IO.cpp new file mode 100644 index 0000000..a89317e --- /dev/null +++ b/fs/test_IO.cpp @@ -0,0 +1,95 @@ + +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2012 Valient Gough + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include +#include "fs/testing.h" + +#include "cipher/Cipher.h" +#include "cipher/MemoryPool.h" + +#include "fs/CipherFileIO.h" +#include "fs/FileUtils.h" +#include "fs/FSConfig.h" +#include "fs/MACFileIO.h" +#include "fs/MemFileIO.h" + +namespace { + +TEST(MemIOTest, BasicIO) { + MemFileIO io(1024); + ASSERT_EQ(1024, io.getSize()); + + MemBlock mb; + mb.allocate(256); + + IORequest req; + req.offset = 0; + req.data = mb.data; + req.dataLen = 256; + + for (int i = 0; i < 4; i++) { + req.offset = i * 256; + memset(req.data, 0, req.dataLen); + ASSERT_TRUE(io.write(req)); + } + + for (int i = 0; i < 4; i++) { + req.offset = i * 256; + ASSERT_EQ(req.dataLen, io.read(req)); + } +} + +void testMacIO(FSConfigPtr& cfg) { + shared_ptr base(new MemFileIO(0)); + shared_ptr test(new MACFileIO(base, cfg)); + + shared_ptr dup(new MemFileIO(0)); + comparisonTest(cfg, test.get(), dup.get()); +} + +TEST(IOTest, NullMacIO) { + runWithCipher("Null", 512, testMacIO); +} + +TEST(IOTest, MacIO) { + runWithAllCiphers(testMacIO); +} + +void testCipherIO(FSConfigPtr& cfg) { + shared_ptr base(new MemFileIO(0)); + shared_ptr test(new CipherFileIO(base, cfg)); + + shared_ptr dup(new MemFileIO(0)); + comparisonTest(cfg, test.get(), dup.get()); +} + +TEST(IOTest, NullCipherFileIO) { + runWithCipher("Null", 512, testCipherIO); +} + +TEST(IOTest, CipherFileIO) { + runWithAllCiphers(testCipherIO); +} + +} // namespace + diff --git a/encfs/testextpass b/fs/testextpass similarity index 100% rename from encfs/testextpass rename to fs/testextpass diff --git a/fs/testing.cpp b/fs/testing.cpp new file mode 100644 index 0000000..819f7d5 --- /dev/null +++ b/fs/testing.cpp @@ -0,0 +1,171 @@ + +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2012 Valient Gough + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + + +#include "fs/testing.h" + +#include +#include + +#include + +#include "cipher/Cipher.h" +#include "cipher/MemoryPool.h" + +#include "fs/MemFileIO.h" +#include "fs/FileUtils.h" +#include "fs/FSConfig.h" +#include "fs/MACFileIO.h" + +using namespace std; + +FSConfigPtr makeConfig(const shared_ptr& cipher, int blockSize) { + FSConfigPtr cfg = FSConfigPtr(new FSConfig); + cfg->cipher = cipher; + cfg->key = cipher->newRandomKey(); + cfg->config.reset(new EncfsConfig); + cfg->config->set_block_size(blockSize); + cfg->opts.reset(new EncFS_Opts); + + return cfg; +} + +void runWithCipher(const string& cipherName, int blockSize, + void (*func)(FSConfigPtr& config)) { + shared_ptr cipher = Cipher::New(cipherName); + ASSERT_TRUE(cipher.get() != NULL); + + FSConfigPtr cfg = makeConfig(cipher, blockSize); + ASSERT_NO_FATAL_FAILURE(func(cfg)); +} + +void runWithAllCiphers(void (*func)(FSConfigPtr& config)) { + list algorithms = Cipher::GetAlgorithmList(); + list::const_iterator it; + for (it = algorithms.begin(); it != algorithms.end(); ++it) { + int blockSize = it->blockSize.closest(512); + int keyLength = it->keyLength.closest(128); + SCOPED_TRACE(testing::Message() << "Testng with cipher " << it->name + << ", blocksize " << blockSize << ", keyLength " << keyLength); + shared_ptr cipher = Cipher::New(it->name, keyLength); + ASSERT_TRUE(cipher.get() != NULL); + + FSConfigPtr cfg = makeConfig(cipher, blockSize); + ASSERT_NO_FATAL_FAILURE(func(cfg)); + } +} + +void truncate(FileIO* a, FileIO* b, int len) { + SCOPED_TRACE(testing::Message() << "Truncate from " << a->getSize() + << " to len " << len); + a->truncate(len); + ASSERT_EQ(len, a->getSize()); + + b->truncate(len); + ASSERT_EQ(len, b->getSize()); + + compare(a, b, 0, len); +} + +void writeRandom(FSConfigPtr& cfg, FileIO* a, FileIO* b, int offset, int len) { + SCOPED_TRACE(testing::Message() << "Write random " << offset << ", " << len); + + if (a->getSize() < offset + len) + a->truncate(offset + len); + + unsigned char *buf = new unsigned char[len]; + ASSERT_TRUE(cfg->cipher->randomize(buf, len, false)); + + IORequest req; + req.data = new unsigned char[len]; + req.dataLen = len; + + memcpy(req.data, buf, len); + req.offset = offset; + ASSERT_TRUE(a->write(req)); + + memcpy(req.data, buf, len); + req.offset = offset; + ASSERT_TRUE(b->write(req)); + + compare(a, b, offset, len); + + delete[] buf; +} + +void compare(FileIO* a, FileIO* b, int offset, int len) { + SCOPED_TRACE(testing::Message() << "compare " << offset << ", " << len + << " from file length " << a->getSize()); + unsigned char *buf1 = new unsigned char[len]; + unsigned char *buf2 = new unsigned char[len]; + memset(buf1, 0, len); + memset(buf2, 0, len); + + IORequest req; + req.offset = offset; + req.data = buf1; + req.dataLen = len; + ssize_t size1 = a->read(req); + + req.offset = offset; + req.data = buf2; + req.dataLen = len; + ssize_t size2 = b->read(req); + + ASSERT_EQ(size1, size2); + for(int i = 0; i < len; i++) { + bool match = (buf1[i] == buf2[i]); + ASSERT_TRUE(match) << "mismatched data at offset " << i << " of " << len; + if(!match) { + break; + } + } + + delete[] buf1; + delete[] buf2; +} + +void comparisonTest(FSConfigPtr& cfg, FileIO* a, FileIO* b) { + const int size = 18*1024; + writeRandom(cfg, a, b, 0, size); + if (testing::Test::HasFatalFailure()) return; + compare(a, b, 0, size); + if (testing::Test::HasFatalFailure()) return; + + for (int i = 0; i < 10000; i++) { + SCOPED_TRACE(testing::Message() << "Test Loop " << i); + int len = 128 + random() % 2048; + int offset = (len == a->getSize()) ? 0 + : random() % (a->getSize() - len); + writeRandom(cfg, a, b, offset, len); + if (testing::Test::HasFatalFailure()) return; + ASSERT_EQ(a->getSize(), b->getSize()); + } + + SCOPED_TRACE("Final Compare"); + compare(a, b, 0, a->getSize()); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/fs/testing.h b/fs/testing.h new file mode 100644 index 0000000..a4aeec3 --- /dev/null +++ b/fs/testing.h @@ -0,0 +1,23 @@ +#ifndef _TESTING_incl_ +#define _TESTING_incl_ + +#include + +#include "cipher/Cipher.h" +#include "fs/FileUtils.h" +#include "fs/FSConfig.h" + +class FileIO; + +FSConfigPtr makeConfig(const shared_ptr& cipher, int blockSize); + +void runWithCipher(const std::string& cipherName, int blockSize, + void (*func)(FSConfigPtr& config)); +void runWithAllCiphers(void (*func)(FSConfigPtr& config)); + +void comparisonTest(FSConfigPtr& cfg, FileIO* a, FileIO* b); + +void compare(FileIO* a, FileIO* b, int offset, int len); + +#endif + diff --git a/m4/Makefile.am b/m4/Makefile.am deleted file mode 100644 index 33905df..0000000 --- a/m4/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -EXTRA_DIST = *.m4 - -#\ -# ax_pthread.m4 intl.m4 lib-ld.m4 ltsugar.m4 size_max.m4 \ -# codeset.m4 intldir.m4 lib-link.m4 ltversion.m4 stdint_h.m4 \ -# gettext.m4 intlmacosx.m4 lib-prefix.m4 lt~obsolete.m4 uintmax_t.m4 \ -# glibc2.m4 intmax.m4 libtool.m4 nls.m4 visibility.m4 \ -# glibc21.m4 inttypes-pri.m4 lock.m4 po.m4 wchar_t.m4 \ -# iconv.m4 inttypes_h.m4 longlong.m4 printf-posix.m4 wint_t.m4 \ -# intdiv0.m4 lcmessage.m4 ltoptions.m4 progtest.m4 xsize.m4 diff --git a/m4/ax_ext_check_header.m4 b/m4/ax_ext_check_header.m4 deleted file mode 100644 index af52745..0000000 --- a/m4/ax_ext_check_header.m4 +++ /dev/null @@ -1,58 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_ext_check_header.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_EXT_CHECK_HEADER(
, ). -# -# DESCRIPTION -# -# Check for
with -I for each path in if need be. -# The first sucecssful path is chosen (eg if you say -# AX_EXT_CHECK_HEADER(foo.h, bar baz qux) and -Ibaz works then -Iqux will -# not be tested. -# -# Any -I flags that locate a header are added to CFLAGS and CPPFLAGS. AS -# with AC_CHECK_HEADERS it causes HAVE_
_H to be defined as 1. -# -# Example: -# -# AX_EXT_HAVE_HEADER(openssl/rsa.h, /usr/local/include /usr/local/ssl/include /usr/local/openssl/include) -# -# LICENSE -# -# Copyright (c) 2008 Duncan Simpson -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 7 - -AC_DEFUN([AX_EXT_HAVE_HEADER], -[AC_LANG_PUSH(C) - AC_CHECK_HEADER($1, [$3 got="yes"], [$4 got="no"], $5) - hdr=`echo $1 | $as_tr_sh` - for dir in $2; do - if test "x${got}" = "xno"; then - ext_hashdr_cvdir=`echo $dir | $as_tr_sh` - AC_CACHE_CHECK([for $1 library with -I$dir], - [ext_cv${ext_hashdr_cvdir}_hashdr_${hdr}], - [ext_have_hdr_save_cflags=${CFLAGS} - CFLAGS="${CFLAGS} -I${dir}" - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM([#include <$1>])], - [got="yes"; eval "ext_cv${ext_hashdr_cvdir}_hashdr_${hdr}"="yes"], - [got="no"; eval "ext_cv${ext_hashdr_cvdir}_hashdr_${hdr}"="no"]) - CFLAGS=$ext_have_hdr_save_cflags]) - if eval `echo 'test x${'ext_cv${ext_hashdr_cvdir}_hashdr_${hdr}'}' = "xyes"`; then - CFLAGS="${CFLAGS} -I${dir}" - CPPFLAGS="${CPPFLAGS} -I${dir}" - got="yes"; - hdr=`echo $1 | $as_tr_cpp` - AC_DEFINE_UNQUOTED(HAVE_${hdr}, 1, - [Define this if you have the $1 header]) - fi; fi; done -AC_LANG_POP]) diff --git a/m4/ax_ext_have_lib.m4 b/m4/ax_ext_have_lib.m4 deleted file mode 100644 index 4b84ba0..0000000 --- a/m4/ax_ext_have_lib.m4 +++ /dev/null @@ -1,72 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_ext_have_lib.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_EXT_HAVE_LIB(, , , ) -# -# DESCRIPTION -# -# AX_EXT_HAVE_LIB is identical to AC_SEARCH_LIBS with the exception that -# will add -L when looking, and use a different variable for -# each directory. -# -# Any required -L flags are added to LDFLAGS and located -# libraies are added to LIBS -# -# Some libraries are unlinkable without other extra libraries, which can -# be specified in the 4th argument. The mysql client library needs -lz, -# for example. -# -# Example: -# -# AX_EXT_HAVE_LIB(/lib /usr/lib /usr/local/lib /usr/lib/mysql /usr/local/mysql/lib, mysqlclient, mysql_init, [-lz]) -# -# which finds the mysql client library if succeds system when it tries -# with -L/usr/lib/mysql then it adds -lmysqlclient to LIBS and -# -L/usr/lib/mysql to LDFLAGS. -# -# The test itself is based on the autoconf 2.53 version of AC_SEARCH_LIBS. -# -# LICENSE -# -# Copyright (c) 2008 Duncan Simpson -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 9 - -AC_DEFUN([AX_EXT_HAVE_LIB], -[ -new_ldflags=${LDFLAGS} -new_libs=$LIBS -AC_CHECK_LIB([$2], $3, new_libs="-l$2"; ext_lib_found="yes", ext_lib_found="no") -for dir in $1 -do -if test $ext_lib_found = no -then -ext_haslib_cvdir=`echo $dir | $as_tr_sh` -AC_CACHE_CHECK([for $2 library with -L$dir], [ext_cv${ext_haslib_cvdir}_haslib_$2], -[ext_func_search_save_LIBS=$LIBS -ext_func_save_ldflags=${LDFLAGS} -LIBS="-l$2 $4 ${ext_func_search_save_LIBS}" -LDFLAGS="-L$dir ${ext_func_save_ldflags}" -AC_TRY_LINK_FUNC([$3], [eval "ext_cv${ext_haslib_cvdir}_haslib_$2"="yes"], -[eval "ext_cv${ext_haslib_cvdir}_haslib_$2"="no"]) -LIBS=$ext_func_search_save_LIBS -LDFLAGS=$ext_func_save_ldflags -]) -if eval `echo 'test x${'ext_cv${ext_haslib_cvdir}_haslib_$2'}' = "xyes"`; then -new_libs="-l$2" -new_ldflags="-L${dir} ${new_ldflags}" -ext_lib_found="yes" -fi -fi -done -LIBS="$new_libs ${LIBS}" -LDFLAGS=$new_ldflags -]) diff --git a/m4/ax_pthread.m4 b/m4/ax_pthread.m4 deleted file mode 100644 index e20a388..0000000 --- a/m4/ax_pthread.m4 +++ /dev/null @@ -1,309 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_pthread.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) -# -# DESCRIPTION -# -# This macro figures out how to build C programs using POSIX threads. It -# sets the PTHREAD_LIBS output variable to the threads library and linker -# flags, and the PTHREAD_CFLAGS output variable to any special C compiler -# flags that are needed. (The user can also force certain compiler -# flags/libs to be tested by setting these environment variables.) -# -# Also sets PTHREAD_CC to any special C compiler that is needed for -# multi-threaded programs (defaults to the value of CC otherwise). (This -# is necessary on AIX to use the special cc_r compiler alias.) -# -# NOTE: You are assumed to not only compile your program with these flags, -# but also link it with them as well. e.g. you should link with -# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS -# -# If you are only building threads programs, you may wish to use these -# variables in your default LIBS, CFLAGS, and CC: -# -# LIBS="$PTHREAD_LIBS $LIBS" -# CFLAGS="$CFLAGS $PTHREAD_CFLAGS" -# CC="$PTHREAD_CC" -# -# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant -# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name -# (e.g. PTHREAD_CREATE_UNDETACHED on AIX). -# -# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the -# PTHREAD_PRIO_INHERIT symbol is defined when compiling with -# PTHREAD_CFLAGS. -# -# ACTION-IF-FOUND is a list of shell commands to run if a threads library -# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it -# is not found. If ACTION-IF-FOUND is not specified, the default action -# will define HAVE_PTHREAD. -# -# Please let the authors know if this macro fails on any platform, or if -# you have any other suggestions or comments. This macro was based on work -# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help -# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by -# Alejandro Forero Cuervo to the autoconf macro repository. We are also -# grateful for the helpful feedback of numerous users. -# -# Updated for Autoconf 2.68 by Daniel Richard G. -# -# LICENSE -# -# Copyright (c) 2008 Steven G. Johnson -# Copyright (c) 2011 Daniel Richard G. -# -# This program is free software: you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation, either version 3 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 17 - -AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) -AC_DEFUN([AX_PTHREAD], [ -AC_REQUIRE([AC_CANONICAL_HOST]) -AC_LANG_PUSH([C]) -ax_pthread_ok=no - -# We used to check for pthread.h first, but this fails if pthread.h -# requires special compiler flags (e.g. on True64 or Sequent). -# It gets checked for in the link test anyway. - -# First of all, check if the user has set any of the PTHREAD_LIBS, -# etcetera environment variables, and if threads linking works using -# them: -if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) - AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes) - AC_MSG_RESULT($ax_pthread_ok) - if test x"$ax_pthread_ok" = xno; then - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" - fi - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" -fi - -# We must check for the threads library under a number of different -# names; the ordering is very important because some systems -# (e.g. DEC) have both -lpthread and -lpthreads, where one of the -# libraries is broken (non-POSIX). - -# Create a list of thread flags to try. Items starting with a "-" are -# C compiler flags, and other items are library names, except for "none" -# which indicates that we try without any flags at all, and "pthread-config" -# which is a program returning the flags for the Pth emulation library. - -ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" - -# The ordering *is* (sometimes) important. Some notes on the -# individual items follow: - -# pthreads: AIX (must check this before -lpthread) -# none: in case threads are in libc; should be tried before -Kthread and -# other compiler flags to prevent continual compiler warnings -# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) -# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) -# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) -# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) -# -pthreads: Solaris/gcc -# -mthreads: Mingw32/gcc, Lynx/gcc -# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it -# doesn't hurt to check since this sometimes defines pthreads too; -# also defines -D_REENTRANT) -# ... -mt is also the pthreads flag for HP/aCC -# pthread: Linux, etcetera -# --thread-safe: KAI C++ -# pthread-config: use pthread-config program (for GNU Pth library) - -case "${host_cpu}-${host_os}" in - *solaris*) - - # On Solaris (at least, for some versions), libc contains stubbed - # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (We need to link with -pthreads/-mt/ - # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather - # a function called by this macro, so we could check for that, but - # who knows whether they'll stub that too in a future libc.) So, - # we'll just look for -pthreads and -lpthread first: - - ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" - ;; - - *-darwin*) - ax_pthread_flags="-pthread $ax_pthread_flags" - ;; -esac - -if test x"$ax_pthread_ok" = xno; then -for flag in $ax_pthread_flags; do - - case $flag in - none) - AC_MSG_CHECKING([whether pthreads work without any flags]) - ;; - - -*) - AC_MSG_CHECKING([whether pthreads work with $flag]) - PTHREAD_CFLAGS="$flag" - ;; - - pthread-config) - AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no) - if test x"$ax_pthread_config" = xno; then continue; fi - PTHREAD_CFLAGS="`pthread-config --cflags`" - PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" - ;; - - *) - AC_MSG_CHECKING([for the pthreads library -l$flag]) - PTHREAD_LIBS="-l$flag" - ;; - esac - - save_LIBS="$LIBS" - save_CFLAGS="$CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - - # Check for various functions. We must include pthread.h, - # since some functions may be macros. (On the Sequent, we - # need a special flag -Kthread to make this header compile.) - # We check for pthread_join because it is in -lpthread on IRIX - # while pthread_create is in libc. We check for pthread_attr_init - # due to DEC craziness with -lpthreads. We check for - # pthread_cleanup_push because it is one of the few pthread - # functions on Solaris that doesn't have a non-functional libc stub. - # We try pthread_create on general principles. - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include - static void routine(void *a) { a = 0; } - static void *start_routine(void *a) { return a; }], - [pthread_t th; pthread_attr_t attr; - pthread_create(&th, 0, start_routine, 0); - pthread_join(th, 0); - pthread_attr_init(&attr); - pthread_cleanup_push(routine, 0); - pthread_cleanup_pop(0) /* ; */])], - [ax_pthread_ok=yes], - []) - - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" - - AC_MSG_RESULT($ax_pthread_ok) - if test "x$ax_pthread_ok" = xyes; then - break; - fi - - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" -done -fi - -# Various other checks: -if test "x$ax_pthread_ok" = xyes; then - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - - # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. - AC_MSG_CHECKING([for joinable pthread attribute]) - attr_name=unknown - for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], - [int attr = $attr; return attr /* ; */])], - [attr_name=$attr; break], - []) - done - AC_MSG_RESULT($attr_name) - if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then - AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, - [Define to necessary symbol if this constant - uses a non-standard name on your system.]) - fi - - AC_MSG_CHECKING([if more special flags are required for pthreads]) - flag=no - case "${host_cpu}-${host_os}" in - *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; - *-osf* | *-hpux*) flag="-D_REENTRANT";; - *solaris*) - if test "$GCC" = "yes"; then - flag="-D_REENTRANT" - else - flag="-mt -D_REENTRANT" - fi - ;; - esac - AC_MSG_RESULT(${flag}) - if test "x$flag" != xno; then - PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" - fi - - AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], - ax_cv_PTHREAD_PRIO_INHERIT, [ - AC_LINK_IFELSE([ - AC_LANG_PROGRAM([[#include ]], [[int i = PTHREAD_PRIO_INHERIT;]])], - [ax_cv_PTHREAD_PRIO_INHERIT=yes], - [ax_cv_PTHREAD_PRIO_INHERIT=no]) - ]) - AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], - AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.])) - - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" - - # More AIX lossage: must compile with xlc_r or cc_r - if test x"$GCC" != xyes; then - AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) - else - PTHREAD_CC=$CC - fi -else - PTHREAD_CC="$CC" -fi - -AC_SUBST(PTHREAD_LIBS) -AC_SUBST(PTHREAD_CFLAGS) -AC_SUBST(PTHREAD_CC) - -# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test x"$ax_pthread_ok" = xyes; then - ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) - : -else - ax_pthread_ok=no - $2 -fi -AC_LANG_POP -])dnl AX_PTHREAD diff --git a/makedist.sh b/makedist.sh deleted file mode 100644 index fefded9..0000000 --- a/makedist.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -rm m4/[c-z]*.m4 - -echo Creating autoconf scripts... -sh ./reconfig.sh - -echo Configuring... -./configure - -sh ./makedist2.sh - diff --git a/makedist2.sh.in b/makedist2.sh.in deleted file mode 100644 index 8034705..0000000 --- a/makedist2.sh.in +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -# create distribution file -make dist - -# create tar archive and signature -tarArchive=@PACKAGE@-@VERSION@.tgz -mv @PACKAGE@-@VERSION@.tar.gz $tarArchive -# let the user know why they're being asked for a passpharse -echo "Signing tar archive - enter GPG password"; -gpg --detach-sign -a $tarArchive - -# create rpms -#cp $tarArchive /usr/src/packages/SOURCES -#echo "Building signed RPM files - enter GPG password"; -#rpmbuild -ba --sign @PACKAGE@.spec - -# move all distribution files to dist directory -mkdir dist -mv $tarArchive dist -mv $tarArchive.asc dist -#mv /usr/src/packages/SRPMS/@PACKAGE@-@VERSION@-@RELEASE@.src.rpm dist -#mv /usr/src/packages/RPMS/i586/@PACKAGE@-@VERSION@-@RELEASE@.i586.rpm dist - -# cleanup -#rm /usr/src/packages/SOURCES/$tarArchive - diff --git a/po/CMakeLists.txt b/po/CMakeLists.txt new file mode 100644 index 0000000..feff967 --- /dev/null +++ b/po/CMakeLists.txt @@ -0,0 +1,37 @@ + +file (GLOB PO_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.po") +file (GLOB CXX_FILES RELATIVE ${PROJECT_SOURCE_DIR} "*/*.cpp") + +set (GettextTranslate_GMO_BINARY true) + +include (GetTextTranslate) + + + +#find_package (Gettext REQUIRED) +#find_program (GETTEXT_XGETTEXT_EXE xgettext) +# +#if (NOT GETTEXT_FOUND) +# message (STATUS " Gettext not found") +#endif (NOT GETTEXT_FOUND) +#if (NOT GETTEXT_XGETTEXT_EXE) +# message (STATUS " Can't find xgettext") +#endif (NOT GETTEXT_XGETTEXT_EXE) +# +# +#if (GETTEXT_FOUND AND GETTEXT_XGETTEXT_EXE) +# add_custom_command( +# OUTPUT ${PROJECT_NAME}.pot +# COMMAND ${GETTEXT_XGETTEXT_EXE} --omit-header --keyword=_ --keyword=N_ ${CXX_FILES} -o ${PROJECT_NAME}.pot +# ) +# +# if (PO_FILES) +# message (STATUS "Translations will be built!") +# gettext_create_translations (${PROJECT_NAME}.pot ALL ${PO_FILES}) +# else (PO_FILES) +# message (STATUS "Translations not found!") +# endif (PO_FILES) +#else (GETTEXT_FOUND AND GETTEXT_XGETTEXT_EXE) +# message (STATUS "Translations won't be built.") +#endif (GETTEXT_FOUND AND GETTEXT_XGETTEXT_EXE) + diff --git a/po/ChangeLog b/po/ChangeLog deleted file mode 100644 index 4734f6e..0000000 --- a/po/ChangeLog +++ /dev/null @@ -1,5 +0,0 @@ -2008-05-22 gettextize - - * Makefile.in.in: Upgrade to gettext-0.17. - * POTFILES.in: New file. - diff --git a/po/Makefile.in.in b/po/Makefile.in.in deleted file mode 100644 index fecf500..0000000 --- a/po/Makefile.in.in +++ /dev/null @@ -1,429 +0,0 @@ -# Makefile for PO directory in any package using GNU gettext. -# Copyright (C) 1995-1997, 2000-2007 by Ulrich Drepper -# -# This file can be copied and used freely without restrictions. It can -# be used in projects which are not available under the GNU General Public -# License but which still want to provide support for the GNU gettext -# functionality. -# Please note that the actual code of GNU gettext is covered by the GNU -# General Public License and is *not* in the public domain. -# -# Origin: gettext-0.17 -GETTEXT_MACRO_VERSION = 0.17 - -PACKAGE = @PACKAGE@ -VERSION = @VERSION@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ - -SHELL = /bin/sh -@SET_MAKE@ - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ - -prefix = @prefix@ -exec_prefix = @exec_prefix@ -datarootdir = @datarootdir@ -datadir = @datadir@ -localedir = @localedir@ -gettextsrcdir = $(datadir)/gettext/po - -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ - -# We use $(mkdir_p). -# In automake <= 1.9.x, $(mkdir_p) is defined either as "mkdir -p --" or as -# "$(mkinstalldirs)" or as "$(install_sh) -d". For these automake versions, -# @install_sh@ does not start with $(SHELL), so we add it. -# In automake >= 1.10, @mkdir_p@ is derived from ${MKDIR_P}, which is defined -# either as "/path/to/mkdir -p" or ".../install-sh -c -d". For these automake -# versions, $(mkinstalldirs) and $(install_sh) are unused. -mkinstalldirs = $(SHELL) @install_sh@ -d -install_sh = $(SHELL) @install_sh@ -MKDIR_P = @MKDIR_P@ -mkdir_p = @mkdir_p@ - -GMSGFMT_ = @GMSGFMT@ -GMSGFMT_no = @GMSGFMT@ -GMSGFMT_yes = @GMSGFMT_015@ -GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT)) -MSGFMT_ = @MSGFMT@ -MSGFMT_no = @MSGFMT@ -MSGFMT_yes = @MSGFMT_015@ -MSGFMT = $(MSGFMT_$(USE_MSGCTXT)) -XGETTEXT_ = @XGETTEXT@ -XGETTEXT_no = @XGETTEXT@ -XGETTEXT_yes = @XGETTEXT_015@ -XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT)) -MSGMERGE = msgmerge -MSGMERGE_UPDATE = @MSGMERGE@ --update -MSGINIT = msginit -MSGCONV = msgconv -MSGFILTER = msgfilter - -POFILES = @POFILES@ -GMOFILES = @GMOFILES@ -UPDATEPOFILES = @UPDATEPOFILES@ -DUMMYPOFILES = @DUMMYPOFILES@ -DISTFILES.common = Makefile.in.in remove-potcdate.sin \ -$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3) -DISTFILES = $(DISTFILES.common) Makevars POTFILES.in \ -$(POFILES) $(GMOFILES) \ -$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3) - -POTFILES = \ - -CATALOGS = @CATALOGS@ - -# Makevars gets inserted here. (Don't remove this line!) - -.SUFFIXES: -.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-create .po-update - -.po.mo: - @echo "$(MSGFMT) -c -o $@ $<"; \ - $(MSGFMT) -c -o t-$@ $< && mv t-$@ $@ - -.po.gmo: - @lang=`echo $* | sed -e 's,.*/,,'`; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o $${lang}.gmo $${lang}.po"; \ - cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo - -.sin.sed: - sed -e '/^#/d' $< > t-$@ - mv t-$@ $@ - - -all: check-macro-version all-@USE_NLS@ - -all-yes: stamp-po -all-no: - -# Ensure that the gettext macros and this Makefile.in.in are in sync. -check-macro-version: - @test "$(GETTEXT_MACRO_VERSION)" = "@GETTEXT_MACRO_VERSION@" \ - || { echo "*** error: gettext infrastructure mismatch: using a Makefile.in.in from gettext version $(GETTEXT_MACRO_VERSION) but the autoconf macros are from gettext version @GETTEXT_MACRO_VERSION@" 1>&2; \ - exit 1; \ - } - -# $(srcdir)/$(DOMAIN).pot is only created when needed. When xgettext finds no -# internationalized messages, no $(srcdir)/$(DOMAIN).pot is created (because -# we don't want to bother translators with empty POT files). We assume that -# LINGUAS is empty in this case, i.e. $(POFILES) and $(GMOFILES) are empty. -# In this case, stamp-po is a nop (i.e. a phony target). - -# stamp-po is a timestamp denoting the last time at which the CATALOGS have -# been loosely updated. Its purpose is that when a developer or translator -# checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS, -# "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent -# invocations of "make" will do nothing. This timestamp would not be necessary -# if updating the $(CATALOGS) would always touch them; however, the rule for -# $(POFILES) has been designed to not touch files that don't need to be -# changed. -stamp-po: $(srcdir)/$(DOMAIN).pot - test ! -f $(srcdir)/$(DOMAIN).pot || \ - test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) - @test ! -f $(srcdir)/$(DOMAIN).pot || { \ - echo "touch stamp-po" && \ - echo timestamp > stamp-poT && \ - mv stamp-poT stamp-po; \ - } - -# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update', -# otherwise packages like GCC can not be built if only parts of the source -# have been downloaded. - -# This target rebuilds $(DOMAIN).pot; it is an expensive operation. -# Note that $(DOMAIN).pot is not touched if it doesn't need to be changed. -$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed - if LC_ALL=C grep 'GNU @PACKAGE@' $(top_srcdir)/* 2>/dev/null | grep -v 'libtool:' >/dev/null; then \ - package_gnu='GNU '; \ - else \ - package_gnu=''; \ - fi; \ - if test -n '$(MSGID_BUGS_ADDRESS)' || test '$(PACKAGE_BUGREPORT)' = '@'PACKAGE_BUGREPORT'@'; then \ - msgid_bugs_address='$(MSGID_BUGS_ADDRESS)'; \ - else \ - msgid_bugs_address='$(PACKAGE_BUGREPORT)'; \ - fi; \ - case `$(XGETTEXT) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ - '' | 0.[0-9] | 0.[0-9].* | 0.1[0-5] | 0.1[0-5].* | 0.16 | 0.16.[0-1]*) \ - $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ - --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) @XGETTEXT_EXTRA_OPTIONS@ \ - --files-from=$(srcdir)/POTFILES.in \ - --copyright-holder='$(COPYRIGHT_HOLDER)' \ - --msgid-bugs-address="$$msgid_bugs_address" \ - ;; \ - *) \ - $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ - --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) @XGETTEXT_EXTRA_OPTIONS@ \ - --files-from=$(srcdir)/POTFILES.in \ - --copyright-holder='$(COPYRIGHT_HOLDER)' \ - --package-name="$${package_gnu}@PACKAGE@" \ - --package-version='@VERSION@' \ - --msgid-bugs-address="$$msgid_bugs_address" \ - ;; \ - esac - test ! -f $(DOMAIN).po || { \ - if test -f $(srcdir)/$(DOMAIN).pot; then \ - sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \ - sed -f remove-potcdate.sed < $(DOMAIN).po > $(DOMAIN).2po && \ - if cmp $(DOMAIN).1po $(DOMAIN).2po >/dev/null 2>&1; then \ - rm -f $(DOMAIN).1po $(DOMAIN).2po $(DOMAIN).po; \ - else \ - rm -f $(DOMAIN).1po $(DOMAIN).2po $(srcdir)/$(DOMAIN).pot && \ - mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ - fi; \ - else \ - mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ - fi; \ - } - -# This rule has no dependencies: we don't need to update $(DOMAIN).pot at -# every "make" invocation, only create it when it is missing. -# Only "make $(DOMAIN).pot-update" or "make dist" will force an update. -$(srcdir)/$(DOMAIN).pot: - $(MAKE) $(DOMAIN).pot-update - -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot - @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ - if test -f "$(srcdir)/$${lang}.po"; then \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) && $(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot; \ - else \ - $(MAKE) $${lang}.po-create; \ - fi - - -install: install-exec install-data -install-exec: -install-data: install-data-@USE_NLS@ - if test "$(PACKAGE)" = "gettext-tools"; then \ - $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ - for file in $(DISTFILES.common) Makevars.template; do \ - $(INSTALL_DATA) $(srcdir)/$$file \ - $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - for file in Makevars; do \ - rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - else \ - : ; \ - fi -install-data-no: all -install-data-yes: all - $(mkdir_p) $(DESTDIR)$(datadir) - @catalogs='$(CATALOGS)'; \ - for cat in $$catalogs; do \ - cat=`basename $$cat`; \ - lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ - dir=$(localedir)/$$lang/LC_MESSAGES; \ - $(mkdir_p) $(DESTDIR)$$dir; \ - if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \ - $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \ - echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \ - for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ - if test -n "$$lc"; then \ - if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ - link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ - mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ - mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ - (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ - for file in *; do \ - if test -f $$file; then \ - ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ - fi; \ - done); \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ - else \ - if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ - :; \ - else \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ - mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ - fi; \ - fi; \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ - ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ - ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ - cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ - echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \ - fi; \ - done; \ - done - -install-strip: install - -installdirs: installdirs-exec installdirs-data -installdirs-exec: -installdirs-data: installdirs-data-@USE_NLS@ - if test "$(PACKAGE)" = "gettext-tools"; then \ - $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ - else \ - : ; \ - fi -installdirs-data-no: -installdirs-data-yes: - $(mkdir_p) $(DESTDIR)$(datadir) - @catalogs='$(CATALOGS)'; \ - for cat in $$catalogs; do \ - cat=`basename $$cat`; \ - lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ - dir=$(localedir)/$$lang/LC_MESSAGES; \ - $(mkdir_p) $(DESTDIR)$$dir; \ - for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ - if test -n "$$lc"; then \ - if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ - link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ - mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ - mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ - (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ - for file in *; do \ - if test -f $$file; then \ - ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ - fi; \ - done); \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ - else \ - if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ - :; \ - else \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ - mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ - fi; \ - fi; \ - fi; \ - done; \ - done - -# Define this as empty until I found a useful application. -installcheck: - -uninstall: uninstall-exec uninstall-data -uninstall-exec: -uninstall-data: uninstall-data-@USE_NLS@ - if test "$(PACKAGE)" = "gettext-tools"; then \ - for file in $(DISTFILES.common) Makevars.template; do \ - rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - else \ - : ; \ - fi -uninstall-data-no: -uninstall-data-yes: - catalogs='$(CATALOGS)'; \ - for cat in $$catalogs; do \ - cat=`basename $$cat`; \ - lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ - for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ - done; \ - done - -check: all - -info dvi ps pdf html tags TAGS ctags CTAGS ID: - -mostlyclean: - rm -f remove-potcdate.sed - rm -f stamp-poT - rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po - rm -fr *.o - -clean: mostlyclean - -distclean: clean - rm -f Makefile Makefile.in POTFILES *.mo - -maintainer-clean: distclean - @echo "This command is intended for maintainers to use;" - @echo "it deletes files that may require special tools to rebuild." - rm -f stamp-po $(GMOFILES) - -distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) -dist distdir: - $(MAKE) update-po - @$(MAKE) dist2 -# This is a separate target because 'update-po' must be executed before. -dist2: stamp-po $(DISTFILES) - dists="$(DISTFILES)"; \ - if test "$(PACKAGE)" = "gettext-tools"; then \ - dists="$$dists Makevars.template"; \ - fi; \ - if test -f $(srcdir)/$(DOMAIN).pot; then \ - dists="$$dists $(DOMAIN).pot stamp-po"; \ - fi; \ - if test -f $(srcdir)/ChangeLog; then \ - dists="$$dists ChangeLog"; \ - fi; \ - for i in 0 1 2 3 4 5 6 7 8 9; do \ - if test -f $(srcdir)/ChangeLog.$$i; then \ - dists="$$dists ChangeLog.$$i"; \ - fi; \ - done; \ - if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \ - for file in $$dists; do \ - if test -f $$file; then \ - cp -p $$file $(distdir) || exit 1; \ - else \ - cp -p $(srcdir)/$$file $(distdir) || exit 1; \ - fi; \ - done - -update-po: Makefile - $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) - $(MAKE) update-gmo - -# General rule for creating PO files. - -.nop.po-create: - @lang=`echo $@ | sed -e 's/\.po-create$$//'`; \ - echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ - exit 1 - -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if $(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$tmpdir/$$lang.new.po; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - -$(DUMMYPOFILES): - -update-gmo: Makefile $(GMOFILES) - @: - -Makefile: Makefile.in.in Makevars $(top_builddir)/config.status @POMAKEFILEDEPS@ - cd $(top_builddir) \ - && $(SHELL) ./config.status $(subdir)/$@.in po-directories - -force: - -# Tell versions [3.59,3.63) of GNU make not to export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/po/POTFILES.in b/po/POTFILES.in index 667e27c..ec651e8 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1 +1,11 @@ -# List of source files which contain translatable strings. +# For updating this file, look at the result of: +# $ head -3 po/POTFILES.in > /tmp/POTFILES.in && grep -l 'i18n.h' ../*.{cpp,h}* >> /tmp/POTFILES.in && cp -f /tmp/POTFILES.in po/ + +../cipher/SSL_Cipher.cpp +../encfs/main.cpp +../fs/BlockFileIO.cpp +../fs/BlockNameIO.cpp +../fs/FileUtils.cpp +../fs/MACFileIO.cpp +../fs/StreamNameIO.cpp +../util/encfsctl.cpp diff --git a/po/Rules-quot b/po/Rules-quot deleted file mode 100644 index 9c2a995..0000000 --- a/po/Rules-quot +++ /dev/null @@ -1,47 +0,0 @@ -# Special Makefile rules for English message catalogs with quotation marks. - -DISTFILES.common.extra1 = quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot - -.SUFFIXES: .insert-header .po-update-en - -en@quot.po-create: - $(MAKE) en@quot.po-update -en@boldquot.po-create: - $(MAKE) en@boldquot.po-update - -en@quot.po-update: en@quot.po-update-en -en@boldquot.po-update: en@boldquot.po-update-en - -.insert-header.po-update-en: - @lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \ - if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - ll=`echo $$lang | sed -e 's/@.*//'`; \ - LC_ALL=C; export LC_ALL; \ - cd $(srcdir); \ - if $(MSGINIT) -i $(DOMAIN).pot --no-translator -l $$ll -o - 2>/dev/null | sed -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | $(MSGFILTER) sed -f `echo $$lang | sed -e 's/.*@//'`.sed 2>/dev/null > $$tmpdir/$$lang.new.po; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "creation of $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - -en@quot.insert-header: insert-header.sin - sed -e '/^#/d' -e 's/HEADER/en@quot.header/g' $(srcdir)/insert-header.sin > en@quot.insert-header - -en@boldquot.insert-header: insert-header.sin - sed -e '/^#/d' -e 's/HEADER/en@boldquot.header/g' $(srcdir)/insert-header.sin > en@boldquot.insert-header - -mostlyclean: mostlyclean-quot -mostlyclean-quot: - rm -f *.insert-header diff --git a/po/boldquot.sed b/po/boldquot.sed deleted file mode 100644 index 4b937aa..0000000 --- a/po/boldquot.sed +++ /dev/null @@ -1,10 +0,0 @@ -s/"\([^"]*\)"/“\1”/g -s/`\([^`']*\)'/‘\1’/g -s/ '\([^`']*\)' / ‘\1’ /g -s/ '\([^`']*\)'$/ ‘\1’/g -s/^'\([^`']*\)' /‘\1’ /g -s/“”/""/g -s/“/“/g -s/”/”/g -s/‘/‘/g -s/’/’/g diff --git a/po/en@boldquot.header b/po/en@boldquot.header deleted file mode 100644 index fedb6a0..0000000 --- a/po/en@boldquot.header +++ /dev/null @@ -1,25 +0,0 @@ -# All this catalog "translates" are quotation characters. -# The msgids must be ASCII and therefore cannot contain real quotation -# characters, only substitutes like grave accent (0x60), apostrophe (0x27) -# and double quote (0x22). These substitutes look strange; see -# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html -# -# This catalog translates grave accent (0x60) and apostrophe (0x27) to -# left single quotation mark (U+2018) and right single quotation mark (U+2019). -# It also translates pairs of apostrophe (0x27) to -# left single quotation mark (U+2018) and right single quotation mark (U+2019) -# and pairs of quotation mark (0x22) to -# left double quotation mark (U+201C) and right double quotation mark (U+201D). -# -# When output to an UTF-8 terminal, the quotation characters appear perfectly. -# When output to an ISO-8859-1 terminal, the single quotation marks are -# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to -# grave/acute accent (by libiconv), and the double quotation marks are -# transliterated to 0x22. -# When output to an ASCII terminal, the single quotation marks are -# transliterated to apostrophes, and the double quotation marks are -# transliterated to 0x22. -# -# This catalog furthermore displays the text between the quotation marks in -# bold face, assuming the VT100/XTerm escape sequences. -# diff --git a/po/en@quot.header b/po/en@quot.header deleted file mode 100644 index a9647fc..0000000 --- a/po/en@quot.header +++ /dev/null @@ -1,22 +0,0 @@ -# All this catalog "translates" are quotation characters. -# The msgids must be ASCII and therefore cannot contain real quotation -# characters, only substitutes like grave accent (0x60), apostrophe (0x27) -# and double quote (0x22). These substitutes look strange; see -# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html -# -# This catalog translates grave accent (0x60) and apostrophe (0x27) to -# left single quotation mark (U+2018) and right single quotation mark (U+2019). -# It also translates pairs of apostrophe (0x27) to -# left single quotation mark (U+2018) and right single quotation mark (U+2019) -# and pairs of quotation mark (0x22) to -# left double quotation mark (U+201C) and right double quotation mark (U+201D). -# -# When output to an UTF-8 terminal, the quotation characters appear perfectly. -# When output to an ISO-8859-1 terminal, the single quotation marks are -# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to -# grave/acute accent (by libiconv), and the double quotation marks are -# transliterated to 0x22. -# When output to an ASCII terminal, the single quotation marks are -# transliterated to apostrophes, and the double quotation marks are -# transliterated to 0x22. -# diff --git a/po/insert-header.sin b/po/insert-header.sin deleted file mode 100644 index b26de01..0000000 --- a/po/insert-header.sin +++ /dev/null @@ -1,23 +0,0 @@ -# Sed script that inserts the file called HEADER before the header entry. -# -# At each occurrence of a line starting with "msgid ", we execute the following -# commands. At the first occurrence, insert the file. At the following -# occurrences, do nothing. The distinction between the first and the following -# occurrences is achieved by looking at the hold space. -/^msgid /{ -x -# Test if the hold space is empty. -s/m/m/ -ta -# Yes it was empty. First occurrence. Read the file. -r HEADER -# Output the file's contents by reading the next line. But don't lose the -# current line while doing this. -g -N -bb -:a -# The hold space was nonempty. Following occurrences. Do nothing. -x -:b -} diff --git a/po/quot.sed b/po/quot.sed deleted file mode 100644 index 0122c46..0000000 --- a/po/quot.sed +++ /dev/null @@ -1,6 +0,0 @@ -s/"\([^"]*\)"/“\1”/g -s/`\([^`']*\)'/‘\1’/g -s/ '\([^`']*\)' / ‘\1’ /g -s/ '\([^`']*\)'$/ ‘\1’/g -s/^'\([^`']*\)' /‘\1’ /g -s/“”/""/g diff --git a/po/remove-potcdate.sin b/po/remove-potcdate.sin deleted file mode 100644 index 2436c49..0000000 --- a/po/remove-potcdate.sin +++ /dev/null @@ -1,19 +0,0 @@ -# Sed script that remove the POT-Creation-Date line in the header entry -# from a POT file. -# -# The distinction between the first and the following occurrences of the -# pattern is achieved by looking at the hold space. -/^"POT-Creation-Date: .*"$/{ -x -# Test if the hold space is empty. -s/P/P/ -ta -# Yes it was empty. First occurrence. Remove the line. -g -d -bb -:a -# The hold space was nonempty. Following occurrences. Do nothing. -x -:b -} diff --git a/reconfig.sh b/reconfig.sh deleted file mode 100644 index 9f86811..0000000 --- a/reconfig.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -autoreconf -i - diff --git a/subdirs b/subdirs deleted file mode 100644 index 6897267..0000000 --- a/subdirs +++ /dev/null @@ -1,3 +0,0 @@ -admin -autom4te.cache -encfs diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt new file mode 100644 index 0000000..e362709 --- /dev/null +++ b/util/CMakeLists.txt @@ -0,0 +1,40 @@ + +include_directories (${Encfs_SOURCE_DIR}/base) +link_directories (${Encfs_BINARY_DIR}/base) + +include_directories (${Encfs_SOURCE_DIR}/cipher) +link_directories (${Encfs_BINARY_DIR}/cipher) + +include_directories (${Encfs_SOURCE_DIR}/fs) +link_directories (${Encfs_BINARY_DIR}/fs) + +# TODO: move FUSE code into encfs-fs. +find_package (FUSE REQUIRED) +include_directories (${FUSE_INCLUDE_DIR}) + +include_directories (${CMAKE_BINARY_DIR}/base) + + +add_executable (encfsctl + encfsctl.cpp) +target_link_libraries (encfsctl + encfs-fs + encfs-cipher + encfs-base + ${GLOG_LIBRARIES} + ${FUSE_LIBRARIES} +) + +if (POD2MAN) + add_custom_target(util-man ALL + COMMAND ${POD2MAN} -u --section=1 --release=${ENCFS_VERSION} + --center="Encrypted Filesystem" + ${CMAKE_CURRENT_SOURCE_DIR}/encfsctl.pod + encfsctl.1) + install (FILES ${CMAKE_CURRENT_BINARY_DIR}/encfsctl.1 + DESTINATION + share/man/man1) +endif (POD2MAN) + +install (TARGETS encfsctl DESTINATION bin) + diff --git a/util/encfsctl.cpp b/util/encfsctl.cpp new file mode 100644 index 0000000..8b89113 --- /dev/null +++ b/util/encfsctl.cpp @@ -0,0 +1,844 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2004, Valient Gough + * + * This program is free software; you can distribute it and/or modify it under + * the terms of the GNU General Public License (GPL), as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + + +#include "fs/encfs.h" + +#include "base/autosprintf.h" +#include "base/config.h" +#include "base/Error.h" +#include "base/i18n.h" + +#include "cipher/Cipher.h" + +#include "fs/FileUtils.h" +#include "fs/Context.h" +#include "fs/FileNode.h" +#include "fs/DirNode.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef HAVE_SSL +#define NO_DES +#include +#endif + +using namespace std; +using namespace gnu; + + +static int showInfo( int argc, char **argv ); +static int showVersion( int argc, char **argv ); +static int chpasswd( int argc, char **argv ); +static int chpasswdAutomaticly( int argc, char **argv ); +static int cmd_ls( int argc, char **argv ); +static int cmd_decode( int argc, char **argv ); +static int cmd_encode( int argc, char **argv ); +static int cmd_showcruft( int argc, char **argv ); +static int cmd_cat( int argc, char **argv ); +static int cmd_export( int argc, char **argv ); +static int cmd_showKey( int argc, char **argv ); + +struct CommandOpts +{ + const char *name; + int minOptions; + int maxOptions; + int (*func)(int argc, char **argv); + const char *argStr; + const char *usageStr; +} commands[] = +{ + {"info", 1, 1, showInfo, "(root dir)", + // xgroup(usage) + gettext_noop(" -- show information (Default command)")}, + {"showKey", 1, 1, cmd_showKey, "(root dir)", + // xgroup(usage) + gettext_noop(" -- show key")}, + {"passwd", 1, 1, chpasswd, "(root dir)", + // xgroup(usage) + gettext_noop(" -- change password for volume")}, + {"autopasswd", 1, 1, chpasswdAutomaticly, "(root dir)", + // xgroup(usage) + gettext_noop(" -- change password for volume, taking password" + " from standard input.\n\tNo prompts are issued.")}, + {"ls", 1, 2, cmd_ls, 0,0}, + {"showcruft", 1, 1, cmd_showcruft, "(root dir)", + // xgroup(usage) + gettext_noop(" -- show undecodable filenames in the volume")}, + {"cat", 2, 2, cmd_cat, "(root dir) path", + // xgroup(usage) + gettext_noop(" -- decodes the file and cats it to standard out")}, + {"decode", 1, 100, cmd_decode, "[--extpass=prog] (root dir) [encoded-name ...]", + // xgroup(usage) + gettext_noop(" -- decodes name and prints plaintext version")}, + {"encode", 1, 100, cmd_encode, "[--extpass=prog] (root dir) [plaintext-name ...]", + // xgroup(usage) + gettext_noop(" -- encodes a filename and print result")}, + {"export", 2, 2, cmd_export, "(root dir) path", + // xgroup(usage) + gettext_noop(" -- decrypts a volume and writes results to path")}, + {"--version", 0, 0, showVersion, "", + // xgroup(usage) + gettext_noop(" -- print version number and exit")}, + {0,0,0,0,0,0} +}; + + +static +void usage(const char *name) +{ + cerr << autosprintf(_("encfsctl version %s"), VERSION) << "\n" + << _("Usage:\n") + // displays usage commands, eg "./encfs (root dir) ..." + // xgroup(usage) + << autosprintf(_("%s (root dir)\n" + " -- displays information about the filesystem, or \n"), name); + + int offset = 0; + while(commands[offset].name != 0) + { + if( commands[offset].argStr != 0 ) + { + cerr << "encfsctl " << commands[offset].name << " " + << commands[offset].argStr << "\n" + << gettext( commands[offset].usageStr ) << "\n"; + } + ++offset; + } + + cerr << "\n" + // xgroup(usage) + << autosprintf(_("Example: \n%s info ~/.crypt\n"), name) + << "\n"; +} + +static bool checkDir( string &rootDir ) +{ + if( !isDirectory( rootDir.c_str() )) + { + cerr << autosprintf(_("directory %s does not exist.\n"), + rootDir.c_str()); + return false; + } + if(rootDir[ rootDir.length()-1 ] != '/') + rootDir.append("/"); + + return true; +} + +static int showVersion( int argc, char **argv ) +{ + (void)argc; + (void)argv; + // xgroup(usage) + cerr << autosprintf(_("encfsctl version %s"), VERSION) << "\n"; + + return EXIT_SUCCESS; +} + +static int showInfo( int argc, char **argv ) +{ + (void)argc; + string rootDir = argv[1]; + if( !checkDir( rootDir )) + return EXIT_FAILURE; + + EncfsConfig config; + ConfigType type = readConfig( rootDir, config ); + + // show information stored in config.. + switch(type) + { + case Config_None: + // xgroup(diag) + cout << _("Unable to load or parse config file\n"); + return EXIT_FAILURE; + case Config_Prehistoric: + // xgroup(diag) + cout << _("A really old EncFS filesystem was found. \n" + "It is not supported in this EncFS build.\n"); + return EXIT_FAILURE; + case Config_V3: + // xgroup(diag) + cout << "\n" << autosprintf(_("Version 3 configuration; " + "created by %s\n"), config.creator().c_str()); + break; + case Config_V4: + // xgroup(diag) + cout << "\n" << autosprintf(_("Version 4 configuration; " + "created by %s\n"), config.creator().c_str()); + break; + case Config_V5: + case Config_V6: + case Config_V7: + // xgroup(diag) + cout << "\n" << autosprintf(_("Version %i configuration; " + "created by %s (revision %i)\n"), + type, + config.creator().c_str(), + config.revision()); + break; + } + + showFSInfo( config ); + + return EXIT_SUCCESS; +} + +static RootPtr initRootInfo(int &argc, char ** &argv) +{ + RootPtr result; + shared_ptr opts( new EncFS_Opts() ); + opts->createIfNotFound = false; + opts->checkKey = false; + + static struct option long_options[] = { + {"extpass", 1, 0, 'p'}, + {0,0,0,0} + }; + + for(;;) + { + int option_index = 0; + + int res = getopt_long( argc, argv, "", + long_options, &option_index); + if(res == -1) + break; + + switch(res) + { + case 'p': + opts->passwordProgram.assign(optarg); + break; + default: + LOG(WARNING) << "getopt error: " << res; + break; + } + } + + argc -= optind; + argv += optind; + + if(argc == 0) + { + cerr << _("Incorrect number of arguments") << "\n"; + } else + { + opts->rootDir = string( argv[0] ); + + --argc; + ++argv; + + if(checkDir( opts->rootDir )) + result = initFS( NULL, opts ); + + if(!result) + cerr << _("Unable to initialize encrypted filesystem - check path.\n"); + } + + return result; +} + +static RootPtr initRootInfo(const char* crootDir) +{ + string rootDir(crootDir); + RootPtr result; + + if(checkDir( rootDir )) + { + shared_ptr opts( new EncFS_Opts() ); + opts->rootDir = rootDir; + opts->createIfNotFound = false; + opts->checkKey = false; + result = initFS( NULL, opts ); + } + + if(!result) + cerr << _("Unable to initialize encrypted filesystem - check path.\n"); + + return result; +} + +static int cmd_showKey( int argc, char **argv ) +{ + RootPtr rootInfo = initRootInfo(argv[1]); + + if(!rootInfo) + return EXIT_FAILURE; + else + { + // encode with itself + string b64Key = rootInfo->cipher->encodeAsString( + rootInfo->volumeKey, rootInfo->volumeKey ); + + cout << b64Key << "\n"; + + return EXIT_SUCCESS; + } +} + +static int cmd_decode( int argc, char **argv ) +{ + RootPtr rootInfo = initRootInfo(argc, argv); + if(!rootInfo) + return EXIT_FAILURE; + + if(argc > 0) + { + for(int i=0; iroot->plainPath( argv[i] ); + cout << name << "\n"; + } + } else + { + char buf[PATH_MAX+1]; + while(cin.getline(buf,PATH_MAX)) + { + cout << rootInfo->root->plainPath( buf ) << "\n"; + } + } + return EXIT_SUCCESS; +} + +static int cmd_encode( int argc, char **argv ) +{ + RootPtr rootInfo = initRootInfo(argc, argv); + if(!rootInfo) + return EXIT_FAILURE; + + if(argc > 0) + { + for(int i=0; iroot->cipherPathWithoutRoot(argv[i]); + cout << name << "\n"; + } + } else + { + char buf[PATH_MAX+1]; + while(cin.getline(buf,PATH_MAX)) + { + cout << rootInfo->root->cipherPathWithoutRoot( buf ) << "\n"; + } + } + return EXIT_SUCCESS; +} + +static int cmd_ls( int argc, char **argv ) +{ + (void)argc; + + RootPtr rootInfo = initRootInfo(argv[1]); + + if(!rootInfo) + return EXIT_FAILURE; + + // show files in directory + { + DirTraverse dt = rootInfo->root->openDir("/"); + if(dt.valid()) + { + for(string name = dt.nextPlaintextName(); !name.empty(); + name = dt.nextPlaintextName()) + { + shared_ptr fnode = + rootInfo->root->lookupNode( name.c_str(), "encfsctl-ls" ); + struct stat stbuf; + fnode->getAttr( &stbuf ); + + struct tm stm; + localtime_r( &stbuf.st_mtime, &stm ); + stm.tm_year += 1900; + // TODO: when I add "%s" to the end and name.c_str(), I get a + // seg fault from within strlen. Why ??? + printf("%11i %4i-%02i-%02i %02i:%02i:%02i %s\n", + int(stbuf.st_size), + int(stm.tm_year), int(stm.tm_mon), int(stm.tm_mday), + int(stm.tm_hour), int(stm.tm_min), int(stm.tm_sec), + name.c_str()); + } + } + } + + return EXIT_SUCCESS; +} + +// apply an operation to every block in the file +template +int processContents( const shared_ptr &rootInfo, + const char *path, T &op ) +{ + int errCode = 0; + shared_ptr node = rootInfo->root->openNode( path, "encfsctl", + O_RDONLY, &errCode ); + + if(!node) + { + // try treating filename as an enciphered path + string plainName = rootInfo->root->plainPath( path ); + node = rootInfo->root->lookupNode( plainName.c_str(), "encfsctl" ); + if(node) + { + errCode = node->open( O_RDONLY ); + if(errCode < 0) + node.reset(); + } + } + + if(!node) + { + cerr << "unable to open " << path << "\n"; + return errCode; + } else + { + unsigned char buf[512]; + int blocks = (node->getSize() + sizeof(buf)-1) / sizeof(buf); + // read all the data in blocks + for(int i=0; iread(i*sizeof(buf), buf, sizeof(buf)); + int res = op(buf, bytes); + if(res < 0) + return res; + } + } + return 0; +} + +class WriteOutput +{ + int _fd; +public: + WriteOutput(int fd) { _fd = fd; } + ~WriteOutput() { close(_fd); } + + int operator()(const void *buf, int count) + { + return (int)write(_fd, buf, count); + } +}; + +static int cmd_cat( int argc, char **argv ) +{ + (void)argc; + RootPtr rootInfo = initRootInfo(argv[1]); + + if(!rootInfo) + return EXIT_FAILURE; + + const char *path = argv[2]; + WriteOutput output(STDOUT_FILENO); + int errCode = processContents( rootInfo, path, output ); + + return errCode; +} + +static int copyLink(const struct stat &stBuf, + const shared_ptr &rootInfo, + const string &cpath, const string &destName ) +{ + vector buf(stBuf.st_size+1, 0); + int res = ::readlink( cpath.c_str(), &buf[0], stBuf.st_size ); + if(res == -1) + { + cerr << "unable to readlink of " << cpath << "\n"; + return EXIT_FAILURE; + } + + buf[res] = '\0'; + string decodedLink = rootInfo->root->plainPath(&buf[0]); + + res = ::symlink( decodedLink.c_str(), destName.c_str() ); + if(res == -1) + { + cerr << "unable to create symlink for " << cpath + << " to " << decodedLink << "\n"; + } + + return EXIT_SUCCESS; +} + +static int copyContents(const shared_ptr &rootInfo, + const char* encfsName, const char* targetName) +{ + shared_ptr node = + rootInfo->root->lookupNode( encfsName, "encfsctl" ); + + if(!node) + { + cerr << "unable to open " << encfsName << "\n"; + return EXIT_FAILURE; + } else + { + struct stat st; + + if(node->getAttr(&st) != 0) + return EXIT_FAILURE; + + if((st.st_mode & S_IFLNK) == S_IFLNK) + { + string d = rootInfo->root->cipherPath(encfsName); + char linkContents[PATH_MAX+2]; + + if(readlink (d.c_str(), linkContents, PATH_MAX + 1) <= 0) + { + cerr << "unable to read link " << encfsName << "\n"; + return EXIT_FAILURE; + } + symlink(rootInfo->root->plainPath(linkContents).c_str(), + targetName); + } else + { + int outfd = creat(targetName, st.st_mode); + + WriteOutput output(outfd); + processContents( rootInfo, encfsName, output ); + } + } + return EXIT_SUCCESS; +} + +static bool endsWith(const string &str, char ch) +{ + if(str.empty()) + return false; + else + return str[str.length()-1] == ch; +} + +static int traverseDirs(const shared_ptr &rootInfo, + string volumeDir, string destDir) +{ + if(!endsWith(volumeDir, '/')) + volumeDir.append("/"); + if(!endsWith(destDir, '/')) + destDir.append("/"); + + // Lookup directory node so we can create a destination directory + // with the same permissions + { + struct stat st; + shared_ptr dirNode = + rootInfo->root->lookupNode( volumeDir.c_str(), "encfsctl" ); + if(dirNode->getAttr(&st)) + return EXIT_FAILURE; + + mkdir(destDir.c_str(), st.st_mode); + } + + // show files in directory + DirTraverse dt = rootInfo->root->openDir(volumeDir.c_str()); + if(dt.valid()) + { + for(string name = dt.nextPlaintextName(); !name.empty(); + name = dt.nextPlaintextName()) + { + // Recurse to subdirectories + if(name != "." && name != "..") + { + string plainPath = volumeDir + name; + string cpath = rootInfo->root->cipherPath(plainPath.c_str()); + string destName = destDir + name; + + int r = EXIT_SUCCESS; + struct stat stBuf; + if( !lstat( cpath.c_str(), &stBuf )) + { + if( S_ISDIR( stBuf.st_mode ) ) + { + traverseDirs(rootInfo, (plainPath + '/').c_str(), + destName + '/'); + } else if( S_ISLNK( stBuf.st_mode )) + { + r = copyLink( stBuf, rootInfo, cpath, destName ); + } else + { + r = copyContents(rootInfo, plainPath.c_str(), + destName.c_str()); + } + } else + { + r = EXIT_FAILURE; + } + + if(r != EXIT_SUCCESS) + return r; + } + } + } + return EXIT_SUCCESS; +} + +static int cmd_export( int argc, char **argv ) +{ + (void)argc; + + RootPtr rootInfo = initRootInfo(argv[1]); + + if(!rootInfo) + return EXIT_FAILURE; + + string destDir = argv[2]; + // if the dir doesn't exist, then create it (with user permission) + if(!checkDir(destDir) && !userAllowMkdir(destDir.c_str(), 0700)) + return EXIT_FAILURE; + + return traverseDirs(rootInfo, "/", destDir); +} + +int showcruft( const shared_ptr &rootInfo, const char *dirName ) +{ + int found = 0; + DirTraverse dt = rootInfo->root->openDir( dirName ); + if(dt.valid()) + { + bool showedDir = false; + for(string name = dt.nextInvalid(); !name.empty(); + name = dt.nextInvalid()) + { + string cpath = rootInfo->root->cipherPath( dirName ); + cpath += '/'; + cpath += name; + + if(!showedDir) + { + // just before showing a list of files in a directory + cout << autosprintf(_("In directory %s: \n"), dirName); + showedDir = true; + } + ++found; + cout << cpath << "\n"; + } + + // now go back and look for directories to recurse into.. + dt = rootInfo->root->openDir( dirName ); + if(dt.valid()) + { + for(string name = dt.nextPlaintextName(); !name.empty(); + name = dt.nextPlaintextName()) + { + if( name == "." || name == "..") + continue; + + string plainPath = dirName; + plainPath += '/'; + plainPath += name; + + string cpath = rootInfo->root->cipherPath( plainPath.c_str() ); + + if(isDirectory( cpath.c_str() )) + found += showcruft( rootInfo, plainPath.c_str() ); + } + } + } + + return found; +} + +/* + iterate recursively through the filesystem and print out names of files + which have filenames which cannot be decoded with the given key.. + */ +static int cmd_showcruft( int argc, char **argv ) +{ + (void)argc; + + RootPtr rootInfo = initRootInfo(argv[1]); + + if(!rootInfo) + return EXIT_FAILURE; + + int filesFound = showcruft( rootInfo, "/" ); + + cerr << autosprintf("Found %i invalid file(s).", filesFound) << "\n"; + + return EXIT_SUCCESS; +} + +static int do_chpasswd( bool useStdin, bool annotate, int argc, char **argv ) +{ + (void)argc; + string rootDir = argv[1]; + if( !checkDir( rootDir )) + return EXIT_FAILURE; + + EncfsConfig config; + ConfigType cfgType = readConfig( rootDir, config ); + + if(cfgType == Config_None) + { + cout << _("Unable to load or parse config file\n"); + return EXIT_FAILURE; + } + + // instanciate proper cipher + shared_ptr cipher = getCipher(config); + if(!cipher) + { + cout << autosprintf(_("Unable to find specified cipher \"%s\"\n"), + config.cipher().name().c_str()); + return EXIT_FAILURE; + } + + // ask for existing password + cout << _("Enter current Encfs password\n"); + if (annotate) + cerr << "$PROMPT$ passwd" << endl; + CipherKey userKey = getUserKey( config, useStdin ); + if(!userKey) + return EXIT_FAILURE; + + // decode volume key using user key -- at this point we detect an incorrect + // password if the key checksum does not match (causing readKey to fail). + CipherKey volumeKey = cipher->readKey( + (const unsigned char *)config.key().ciphertext().data(), userKey ); + + if(!volumeKey) + { + cout << _("Invalid password\n"); + return EXIT_FAILURE; + } + + // Now, get New user key.. + userKey.reset(); + cout << _("Enter new Encfs password\n"); + + // create new key + if( useStdin ) + { + if (annotate) + cerr << "$PROMPT$ new_passwd" << endl; + } + + userKey = getNewUserKey( config, useStdin, string(), string() ); + + // re-encode the volume key using the new user key and write it out.. + int result = EXIT_FAILURE; + if(userKey) + { + int encodedKeySize = cipher->encodedKeySize(); + unsigned char *keyBuf = new unsigned char[ encodedKeySize ]; + + // encode volume key with new user key + cipher->writeKey( volumeKey, keyBuf, userKey ); + userKey.reset(); + + EncryptedKey *key = config.mutable_key(); + key->set_ciphertext( keyBuf, encodedKeySize ); + delete[] keyBuf; + + if(saveConfig( rootDir, config )) + { + // password modified -- changes volume key of filesystem.. + cout << _("Volume Key successfully updated.\n"); + result = EXIT_SUCCESS; + } else + { + cout << _("Error saving modified config file.\n"); + } + } else + { + cout << _("Error creating key\n"); + } + + volumeKey.reset(); + + return result; +} + +static int chpasswd( int argc, char **argv ) +{ + return do_chpasswd( false, false, argc, argv ); +} + +static int chpasswdAutomaticly( int argc, char **argv ) +{ + return do_chpasswd( true, false, argc, argv ); +} + + +int main(int argc, char **argv) +{ + FLAGS_logtostderr = 1; + FLAGS_minloglevel = 1; + + google::InitGoogleLogging(argv[0]); + google::InstallFailureSignalHandler(); + +#ifdef LOCALEDIR + setlocale( LC_ALL, "" ); + bindtextdomain( PACKAGE, LOCALEDIR ); + textdomain( PACKAGE ); +#endif + +#ifdef HAVE_SSL + SSL_load_error_strings(); + SSL_library_init(); +#endif + + if(argc < 2) + { + usage( argv[0] ); + return EXIT_FAILURE; + } + + if(argc == 2 && !(*argv[1] == '-' && *(argv[1]+1) == '-')) + { + // default command when only 1 argument given -- treat the argument as + // a directory.. + return showInfo( argc, argv ); + } else + { + // find the specified command + int offset = 0; + while(commands[offset].name != 0) + { + if(!strcmp( argv[1], commands[offset].name )) + break; + ++offset; + } + + if(commands[offset].name == 0) + { + cerr << autosprintf(_("invalid command: \"%s\""), argv[1]) << "\n"; + } else + { + if((argc-2 < commands[offset].minOptions) || + (argc-2 > commands[offset].maxOptions)) + { + cerr << autosprintf( + _("Incorrect number of arguments for command \"%s\""), + argv[1]) << "\n"; + } else + return (*commands[offset].func)( argc-1, argv+1 ); + } + } + + return EXIT_FAILURE; +} diff --git a/encfs/encfsctl.pod b/util/encfsctl.pod similarity index 100% rename from encfs/encfsctl.pod rename to util/encfsctl.pod diff --git a/encfs/encfssh b/util/encfssh similarity index 100% rename from encfs/encfssh rename to util/encfssh diff --git a/encfs/makeKey.cpp b/util/makeKey.cpp similarity index 100% rename from encfs/makeKey.cpp rename to util/makeKey.cpp From 7799c88df6b3d8f49879ad83269c96efac9f3895 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Tue, 5 Mar 2013 06:29:58 +0000 Subject: [PATCH 14/51] move code into encfs namespace, split protobufs git-svn-id: http://encfs.googlecode.com/svn/trunk@93 db9cf616-1c43-0410-9cb8-a902689de0d6 --- CMakeLists.txt | 3 + base/CMakeLists.txt | 8 +- base/ConfigReader.cpp | 9 ++- base/ConfigReader.h | 4 + base/ConfigVar.cpp | 29 +++---- base/ConfigVar.h | 9 ++- base/Error.cpp | 3 + base/Error.h | 4 + base/Interface.cpp | 3 + base/Interface.h | 6 +- base/Mutex.h | 4 +- base/Range.h | 2 + base/XmlReader.cpp | 5 +- base/XmlReader.h | 7 +- base/base64.cpp | 39 +++++----- base/base64.h | 23 +++--- base/types.h | 10 +++ cipher/CMakeLists.txt | 1 + cipher/Cipher.cpp | 23 +++--- cipher/Cipher.h | 27 ++++--- cipher/CipherKey.cpp | 4 + cipher/CipherKey.h | 4 + cipher/MemoryPool.cpp | 5 +- cipher/MemoryPool.h | 10 ++- cipher/NullCipher.cpp | 20 ++--- cipher/NullCipher.h | 21 ++--- cipher/SSL_Cipher.cpp | 91 +++++++++++----------- cipher/SSL_Cipher.h | 32 ++++---- cipher/openssl.cpp | 3 + cipher/openssl.h | 4 + encfs/main.cpp | 5 ++ fs/BlockFileIO.cpp | 5 +- fs/BlockFileIO.h | 8 +- fs/BlockNameIO.cpp | 4 + fs/BlockNameIO.h | 4 + fs/CMakeLists.txt | 3 + fs/CipherFileIO.cpp | 5 +- fs/CipherFileIO.h | 4 + fs/Context.cpp | 3 +- fs/Context.h | 4 + fs/DirNode.cpp | 7 +- fs/DirNode.h | 4 + fs/FSConfig.h | 6 +- fs/FileIO.cpp | 5 +- fs/FileIO.h | 4 + fs/FileNode.cpp | 14 ++-- fs/FileNode.h | 3 + fs/FileUtils.cpp | 5 +- fs/FileUtils.h | 4 + fs/MACFileIO.cpp | 6 +- fs/MACFileIO.h | 4 + fs/MemBlockFileIO.cpp | 3 + fs/MemBlockFileIO.h | 4 + fs/MemFileIO.cpp | 3 + fs/MemFileIO.h | 6 +- fs/NameIO.cpp | 5 ++ fs/NameIO.h | 3 + fs/NullNameIO.cpp | 4 + fs/NullNameIO.h | 5 +- fs/RawFileIO.cpp | 5 ++ fs/RawFileIO.h | 6 +- fs/StreamNameIO.cpp | 4 + fs/StreamNameIO.h | 3 + fs/encfs.cpp | 6 +- fs/encfs.h | 4 + fs/test.cpp | 4 +- fs/test_BlockIO.cpp | 4 +- fs/test_IO.cpp | 2 + fs/testing.cpp | 9 ++- fs/testing.h | 4 + base/config.proto => protos/fsconfig.proto | 18 ++--- protos/interface.proto | 17 ++++ util/encfsctl.cpp | 2 +- 73 files changed, 449 insertions(+), 192 deletions(-) create mode 100644 base/types.h rename base/config.proto => protos/fsconfig.proto (70%) create mode 100644 protos/interface.proto diff --git a/CMakeLists.txt b/CMakeLists.txt index a7fe73c..660d9cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,9 @@ if (APPLE) add_definitions (-D__FreeBSD__=10) endif (APPLE) +find_package (Protobuf REQUIRED) +include_directories (${PROTOBUF_INCLUDE_DIR}) + find_package (GLog REQUIRED) include_directories (${GLOG_INCLUDE_DIRS}) diff --git a/base/CMakeLists.txt b/base/CMakeLists.txt index e08d26c..f27f773 100644 --- a/base/CMakeLists.txt +++ b/base/CMakeLists.txt @@ -1,11 +1,11 @@ -find_package (Protobuf REQUIRED) -include_directories (${PROTOBUF_INCLUDE_DIR}) - find_package (TinyXML REQUIRED) include_directories (${TINYXML_INCLUDE_DIR}) set (LIBS ${LIBS} ${TINYXML_LIBRARIES}) -protobuf_generate_cpp (PROTO_SRCS PROTO_HDRS config.proto) +find_package (Protobuf REQUIRED) + + +protobuf_generate_cpp (PROTO_SRCS PROTO_HDRS ${Encfs_SOURCE_DIR}/protos/interface.proto) configure_file (${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) diff --git a/base/ConfigReader.cpp b/base/ConfigReader.cpp index 1ba71dd..f5a8f60 100644 --- a/base/ConfigReader.cpp +++ b/base/ConfigReader.cpp @@ -28,9 +28,11 @@ #include #include +#include "base/types.h" using namespace std; +namespace encfs { ConfigReader::ConfigReader() { @@ -69,7 +71,7 @@ bool ConfigReader::load(const char *fileName) } ConfigVar in; - in.write( (unsigned char *)buf, size ); + in.write( (byte *)buf, size ); delete[] buf; return loadFromVar( in ); @@ -132,9 +134,9 @@ ConfigVar ConfigReader::toVar() const for(it = vars.begin(); it != vars.end(); ++it) { out.writeInt( it->first.size() ); - out.write( (unsigned char*)it->first.data(), it->first.size() ); + out.write( (byte*)it->first.data(), it->first.size() ); out.writeInt( it->second.size() ); - out.write( (unsigned char*)it->second.buffer(), it->second.size() ); + out.write( (byte*)it->second.buffer(), it->second.size() ); } return out; @@ -155,3 +157,4 @@ ConfigVar &ConfigReader::operator[] ( const std::string &varName ) return vars[ varName ]; } +} // namespace encfs diff --git a/base/ConfigReader.h b/base/ConfigReader.h index da521e3..95ee22f 100644 --- a/base/ConfigReader.h +++ b/base/ConfigReader.h @@ -26,6 +26,8 @@ #include "base/ConfigVar.h" +namespace encfs { + /* handles Configuration load / store for Encfs filesystems. @@ -63,4 +65,6 @@ private: }; +} // namespace encfs + #endif diff --git a/base/ConfigVar.cpp b/base/ConfigVar.cpp index eb1a1a1..94b7b06 100644 --- a/base/ConfigVar.cpp +++ b/base/ConfigVar.cpp @@ -24,6 +24,8 @@ #include #include +namespace encfs { + #ifndef MIN inline int MIN(int a, int b) { @@ -70,7 +72,7 @@ void ConfigVar::resetOffset() pd->offset = 0; } -int ConfigVar::read(unsigned char *buffer_, int bytes) const +int ConfigVar::read(byte *buffer_, int bytes) const { int toCopy = MIN( bytes, pd->buffer.size() - pd->offset ); @@ -82,7 +84,7 @@ int ConfigVar::read(unsigned char *buffer_, int bytes) const return toCopy; } -int ConfigVar::write(const unsigned char *data, int bytes) +int ConfigVar::write(const byte *data, int bytes) { if(pd->buffer.size() == (unsigned int)pd->offset) { @@ -115,7 +117,7 @@ int ConfigVar::at() const void ConfigVar::writeString(const char *data, int bytes) { writeInt( bytes ); - write( (const unsigned char *)data, bytes ); + write( (const byte *)data, bytes ); } @@ -129,13 +131,13 @@ void ConfigVar::writeInt(int val) // third byte: 0x001fb000 0000,0000 0001,1111 1100,0000 0000,0000 // fourth byte: 0x0fe00000 0000,1111 1110,0000 // fifth byte: 0xf0000000 1111,0000 - unsigned char digit[5]; + byte digit[5]; - digit[4] = (unsigned char)((val & 0x0000007f)); - digit[3] = 0x80 | (unsigned char)((val & 0x00003f80) >> 7); - digit[2] = 0x80 | (unsigned char)((val & 0x001fc000) >> 14); - digit[1] = 0x80 | (unsigned char)((val & 0x0fe00000) >> 21); - digit[0] = 0x80 | (unsigned char)((val & 0xf0000000) >> 28); + digit[4] = (byte)((val & 0x0000007f)); + digit[3] = 0x80 | (byte)((val & 0x00003f80) >> 7); + digit[2] = 0x80 | (byte)((val & 0x001fc000) >> 14); + digit[1] = 0x80 | (byte)((val & 0x0fe00000) >> 21); + digit[0] = 0x80 | (byte)((val & 0xf0000000) >> 28); // find the starting point - we only need to output starting at the most // significant non-zero digit.. @@ -148,7 +150,7 @@ void ConfigVar::writeInt(int val) int ConfigVar::readInt() const { - const unsigned char * buf = (const unsigned char *)buffer(); + const byte * buf = (const byte *)buffer(); int bytes = this->size(); int offset = at(); int value = 0; @@ -158,7 +160,7 @@ int ConfigVar::readInt() const do { - unsigned char tmp = buf[offset++]; + byte tmp = buf[offset++]; highBitSet = tmp & 0x80; value = (value << 7) | (int)(tmp & 0x7f); @@ -227,10 +229,10 @@ const ConfigVar & operator >> (const ConfigVar &src, std::string &result) int readLen; - unsigned char tmpBuf[32]; + byte tmpBuf[32]; if(length > (int)sizeof(tmpBuf)) { - unsigned char *ptr = new unsigned char[length]; + byte *ptr = new byte[length]; readLen = src.read( ptr, length ); result.assign( (char*)ptr, length ); delete[] ptr; @@ -251,3 +253,4 @@ const ConfigVar & operator >> (const ConfigVar &src, std::string &result) return src; } +} // namespace encfs diff --git a/base/ConfigVar.h b/base/ConfigVar.h index 5dcbaa7..1d431db 100644 --- a/base/ConfigVar.h +++ b/base/ConfigVar.h @@ -23,6 +23,9 @@ #include #include "base/shared_ptr.h" +#include "base/types.h" + +namespace encfs { class ConfigVar { @@ -46,10 +49,10 @@ public: void resetOffset(); // read bytes - int read(unsigned char *buffer, int size) const; + int read(byte *buffer, int size) const; // write bytes.. - int write(const unsigned char *data, int size); + int write(const byte *data, int size); int readInt() const; int readInt( int defaultValue ) const; @@ -77,5 +80,7 @@ const ConfigVar & operator >> (const ConfigVar &, bool &); const ConfigVar & operator >> (const ConfigVar &, int &); const ConfigVar & operator >> (const ConfigVar &, std::string &str); +} // namespace encfs + #endif diff --git a/base/Error.cpp b/base/Error.cpp index ee628e0..e901c8e 100644 --- a/base/Error.cpp +++ b/base/Error.cpp @@ -1,7 +1,10 @@ #include "base/Error.h" +namespace encfs { + Error::Error(const char *msg) : runtime_error(msg) { } +} // namespace encfs diff --git a/base/Error.h b/base/Error.h index 836af32..ce76f0b 100644 --- a/base/Error.h +++ b/base/Error.h @@ -4,6 +4,8 @@ #include #include +namespace encfs { + class Error : public std::runtime_error { public: @@ -21,5 +23,7 @@ public: } while(0) +} // namespace encfs + #endif diff --git a/base/Interface.cpp b/base/Interface.cpp index 03c0d10..d1b9b00 100644 --- a/base/Interface.cpp +++ b/base/Interface.cpp @@ -25,6 +25,8 @@ #include #include +namespace encfs { + std::ostream& operator << (std::ostream& out, const Interface &iface) { out << iface.name() << "(" << iface.major() @@ -82,3 +84,4 @@ bool operator != (const Interface &a, const Interface &b) return false; } +} // namespace encfs diff --git a/base/Interface.h b/base/Interface.h index 38b5e62..1c144c4 100644 --- a/base/Interface.h +++ b/base/Interface.h @@ -22,7 +22,9 @@ #define _Interface_incl_ #include -#include "base/config.pb.h" +#include "base/interface.pb.h" + +namespace encfs { // check if A implements the interface described by B. // Note that implements(A, B) is not the same as implements(B, A) @@ -38,5 +40,7 @@ const ConfigVar & operator >> (const ConfigVar &, Interface &); bool operator != (const Interface &a, const Interface &b); +} // namespace encfs + #endif diff --git a/base/Mutex.h b/base/Mutex.h index 0a13a60..4675af6 100644 --- a/base/Mutex.h +++ b/base/Mutex.h @@ -23,7 +23,7 @@ #include -namespace rel +namespace encfs { class Lock @@ -60,7 +60,7 @@ inline void Lock::leave() _mutex = 0; } -} // namespace rel +} // namespace encfs #endif diff --git a/base/Range.h b/base/Range.h index b89804c..f5f6a81 100644 --- a/base/Range.h +++ b/base/Range.h @@ -21,6 +21,7 @@ #ifndef _Range_incl_ #define _Range_incl_ +namespace encfs { class Range { @@ -112,4 +113,5 @@ inline int Range::inc() const return increment; } +} // namespace encfs #endif diff --git a/base/XmlReader.cpp b/base/XmlReader.cpp index c774708..ad37b45 100644 --- a/base/XmlReader.cpp +++ b/base/XmlReader.cpp @@ -41,6 +41,8 @@ using namespace std; +namespace encfs { + XmlValue::~XmlValue() { } @@ -106,7 +108,7 @@ bool XmlValue::read(const char *path, bool *out) const return true; } -bool XmlValue::readB64(const char *path, unsigned char *data, int length) const +bool XmlValue::readB64(const char *path, byte *data, int length) const { XmlValuePtr value = find(path); if (!value) @@ -246,3 +248,4 @@ XmlValuePtr XmlReader::operator[] ( const char *name ) const return XmlValuePtr(new XmlNode(element)); } +} // namespace encfs diff --git a/base/XmlReader.h b/base/XmlReader.h index dae3826..37b38b2 100644 --- a/base/XmlReader.h +++ b/base/XmlReader.h @@ -23,6 +23,9 @@ #include #include "base/shared_ptr.h" +#include "base/types.h" + +namespace encfs { class XmlValue; typedef shared_ptr XmlValuePtr; @@ -51,7 +54,7 @@ public: } bool read(const char *path, std::string *out) const; - bool readB64(const char *path, unsigned char *out, int length) const; + bool readB64(const char *path, byte *out, int length) const; bool read(const char *path, int *out) const; bool read(const char *path, long *out) const; @@ -79,4 +82,6 @@ private: shared_ptr pd; }; +} // namespace encfs + #endif diff --git a/base/base64.cpp b/base/base64.cpp index cfb0e38..f89997f 100644 --- a/base/base64.cpp +++ b/base/base64.cpp @@ -22,17 +22,19 @@ #include +namespace encfs { + // change between two powers of two, stored as the low bits of the bytes in the // arrays. // It is the caller's responsibility to make sure the output array is large // enough. -void changeBase2(unsigned char *src, int srcLen, int src2Pow, - unsigned char *dst, int dstLen, int dst2Pow) +void changeBase2(byte *src, int srcLen, int src2Pow, + byte *dst, int dstLen, int dst2Pow) { unsigned long work = 0; int workBits = 0; // number of bits left in the work buffer - unsigned char *end = src + srcLen; - unsigned char *origDst = dst; + byte *end = src + srcLen; + byte *origDst = dst; const int mask = (1 << dst2Pow) -1; // copy the new bits onto the high bits of the stream. @@ -63,12 +65,12 @@ void changeBase2(unsigned char *src, int srcLen, int src2Pow, to be written, then write the value at the tail end of the recursion. */ static -void changeBase2Inline(unsigned char *src, int srcLen, +void changeBase2Inline(byte *src, int srcLen, int src2Pow, int dst2Pow, bool outputPartialLastByte, unsigned long work, int workBits, - unsigned char *outLoc) + byte *outLoc) { const int mask = (1 << dst2Pow) -1; if(!outLoc) @@ -84,7 +86,7 @@ void changeBase2Inline(unsigned char *src, int srcLen, } // we have at least one value that can be output - unsigned char outVal = work & mask; + byte outVal = work & mask; work >>= dst2Pow; workBits -= dst2Pow; @@ -112,7 +114,7 @@ void changeBase2Inline(unsigned char *src, int srcLen, } } -void changeBase2Inline(unsigned char *src, int srcLen, +void changeBase2Inline(byte *src, int srcLen, int src2Pow, int dst2Pow, bool outputPartialLastByte) { @@ -128,7 +130,7 @@ void changeBase2Inline(unsigned char *src, int srcLen, // '.' included in the encrypted names, so that it can be reserved for files // with special meaning. static const char B642AsciiTable[] = ",-0123456789"; -void B64ToAscii(unsigned char *in, int length) +void B64ToAscii(byte *in, int length) { for(int offset=0; offset= 'A') { if(ch >= 'a') @@ -174,7 +176,7 @@ void AsciiToB64(unsigned char *out, const unsigned char *in, int length) } -void B32ToAscii(unsigned char *buf, int len) +void B32ToAscii(byte *buf, int len) { for(int offset=0; offset= 'A') lch -= 'A'; else lch += 26 - '2'; - *out++ = (unsigned char)lch; + *out++ = (byte)lch; } } +} // namespace encfs diff --git a/base/base64.h b/base/base64.h index 2d7b9b2..6be224c 100644 --- a/base/base64.h +++ b/base/base64.h @@ -21,6 +21,9 @@ #ifndef _base64_incl_ #define _base64_incl_ +#include "base/types.h" + +namespace encfs { inline int B64ToB256Bytes( int numB64Bytes ) { @@ -46,29 +49,31 @@ inline int B256ToB32Bytes( int numB256Bytes ) /* convert data between different bases - each being a power of 2. */ -void changeBase2(unsigned char *src, int srcLength, int srcPow2, - unsigned char *dst, int dstLength, int dstPow2); +void changeBase2(byte *src, int srcLength, int srcPow2, + byte *dst, int dstLength, int dstPow2); /* same as changeBase2, but writes output over the top of input data. */ -void changeBase2Inline(unsigned char *buf, int srcLength, +void changeBase2Inline(byte *buf, int srcLength, int srcPow2, int dst2Pow, bool outputPartialLastByte); // inplace translation from values [0,2^6] => base64 ASCII -void B64ToAscii(unsigned char *buf, int length); +void B64ToAscii(byte *buf, int length); // inplace translation from values [0,2^5] => base32 ASCII -void B32ToAscii(unsigned char *buf, int length); +void B32ToAscii(byte *buf, int length); // inplace translation from values base64 ASCII => [0,2^6] -void AsciiToB64(unsigned char *buf, int length); -void AsciiToB64(unsigned char *out, const unsigned char *in, int length); +void AsciiToB64(byte *buf, int length); +void AsciiToB64(byte *out, const byte *in, int length); // inplace translation from values base32 ASCII => [0,2^5] -void AsciiToB32(unsigned char *buf, int length); -void AsciiToB32(unsigned char *out, const unsigned char *in, int length); +void AsciiToB32(byte *buf, int length); +void AsciiToB32(byte *out, const byte *in, int length); + +} // namespace encfs #endif diff --git a/base/types.h b/base/types.h new file mode 100644 index 0000000..2f6d519 --- /dev/null +++ b/base/types.h @@ -0,0 +1,10 @@ +#ifndef TYPES_H +#define TYPES_H + +namespace encfs { + +typedef unsigned char byte; + +} + +#endif // TYPES_H diff --git a/cipher/CMakeLists.txt b/cipher/CMakeLists.txt index ea56731..158b28e 100644 --- a/cipher/CMakeLists.txt +++ b/cipher/CMakeLists.txt @@ -7,6 +7,7 @@ find_package (GTest REQUIRED) add_library (encfs-cipher readpassphrase.cpp + BlockCipher.cpp Cipher.cpp CipherKey.cpp MemoryPool.cpp diff --git a/cipher/Cipher.cpp b/cipher/Cipher.cpp index 2d208c0..b84684e 100644 --- a/cipher/Cipher.cpp +++ b/cipher/Cipher.cpp @@ -21,22 +21,24 @@ #include "base/config.h" #include "cipher/Cipher.h" -#include "base/Interface.h" -#include "base/Range.h" -#include "base/base64.h" - #include #include #include #include +#include "base/Interface.h" +#include "base/Range.h" +#include "base/base64.h" + // for static build. Need to reference the modules which are registered at // run-time, to ensure that the linker doesn't optimize them away. -#include "NullCipher.h" -#include "SSL_Cipher.h" +#include "cipher/NullCipher.h" +#include "cipher/SSL_Cipher.h" using namespace std; +namespace encfs { + #define REF_MODULE(TYPE) \ if( !TYPE::Enabled() ) \ cerr << "referenceModule: should never happen\n"; @@ -180,7 +182,7 @@ Cipher::~Cipher() { } -unsigned int Cipher::MAC_32( const unsigned char *src, int len, +unsigned int Cipher::MAC_32( const byte *src, int len, const CipherKey &key, uint64_t *chainedIV ) const { uint64_t mac64 = MAC_64( src, len, key, chainedIV ); @@ -190,7 +192,7 @@ unsigned int Cipher::MAC_32( const unsigned char *src, int len, return mac32; } -unsigned int Cipher::MAC_16( const unsigned char *src, int len, +unsigned int Cipher::MAC_16( const byte *src, int len, const CipherKey &key, uint64_t *chainedIV ) const { uint64_t mac64 = MAC_64( src, len, key, chainedIV ); @@ -205,12 +207,12 @@ string Cipher::encodeAsString(const CipherKey &key, const CipherKey &encodingKey ) { int encodedKeySize = this->encodedKeySize(); - unsigned char *keyBuf = new unsigned char[ encodedKeySize ]; + byte *keyBuf = new byte[ encodedKeySize ]; this->writeKey( key, keyBuf, encodingKey ); int b64Len = B256ToB64Bytes( encodedKeySize ); - unsigned char *b64Key = new unsigned char[ b64Len + 1 ]; + byte *b64Key = new byte[ b64Len + 1 ]; changeBase2( keyBuf, encodedKeySize, 8, b64Key, b64Len, 6 ); @@ -225,3 +227,4 @@ bool Cipher::hasStreamMode() const return true; } +} // namespace encfs diff --git a/cipher/Cipher.h b/cipher/Cipher.h index 8b0795d..229dffb 100644 --- a/cipher/Cipher.h +++ b/cipher/Cipher.h @@ -24,11 +24,14 @@ #include "cipher/CipherKey.h" #include "base/Interface.h" #include "base/Range.h" +#include "base/types.h" #include #include #include +namespace encfs { + /* Mostly pure virtual interface defining operations on a cipher. @@ -91,7 +94,7 @@ public: // milliseconds the password derivation function should take to run. virtual CipherKey newKey(const char *password, int passwdLength, int &iterationCount, long desiredFunctionDuration, - const unsigned char *salt, int saltLen) =0; + const byte *salt, int saltLen) =0; // deprecated - for backward compatibility virtual CipherKey newKey(const char *password, int passwdLength ) =0; @@ -100,11 +103,11 @@ public: virtual CipherKey newRandomKey() =0; // data must be len encodedKeySize() - virtual CipherKey readKey(const unsigned char *data, + virtual CipherKey readKey(const byte *data, const CipherKey &encodingKey, bool checkKey = true) =0; - virtual void writeKey(const CipherKey &key, unsigned char *data, + virtual void writeKey(const CipherKey &key, byte *data, const CipherKey &encodingKey) =0; virtual std::string encodeAsString(const CipherKey &key, @@ -124,37 +127,39 @@ public: // The data may be pseudo random and might not be suitable for key // generation. For generating keys, uses newRandomKey() instead. // Returns true on success, false on failure. - virtual bool randomize( unsigned char *buf, int len, + virtual bool randomize( byte *buf, int len, bool strongRandom ) const =0; // 64 bit MAC of the data with the given key - virtual uint64_t MAC_64( const unsigned char *src, int len, + virtual uint64_t MAC_64( const byte *src, int len, const CipherKey &key, uint64_t *chainedIV = 0 ) const =0; // based on reductions of MAC_64 - unsigned int MAC_32( const unsigned char *src, int len, + unsigned int MAC_32( const byte *src, int len, const CipherKey &key, uint64_t *chainedIV = 0 ) const; - unsigned int MAC_16( const unsigned char *src, int len, + unsigned int MAC_16( const byte *src, int len, const CipherKey &key, uint64_t *chainedIV = 0 ) const; // functional interfaces /* Stream encoding of data in-place. The stream data can be any length. */ - virtual bool streamEncode( unsigned char *data, int len, + virtual bool streamEncode( byte *data, int len, uint64_t iv64, const CipherKey &key) const=0; - virtual bool streamDecode( unsigned char *data, int len, + virtual bool streamDecode( byte *data, int len, uint64_t iv64, const CipherKey &key) const=0; /* Block encoding of data in-place. The data size should be a multiple of the cipher block size. */ - virtual bool blockEncode(unsigned char *buf, int size, + virtual bool blockEncode(byte *buf, int size, uint64_t iv64, const CipherKey &key) const=0; - virtual bool blockDecode(unsigned char *buf, int size, + virtual bool blockDecode(byte *buf, int size, uint64_t iv64, const CipherKey &key) const=0; }; +} // namespace encfs + #endif diff --git a/cipher/CipherKey.cpp b/cipher/CipherKey.cpp index 01b9a3f..6512466 100644 --- a/cipher/CipherKey.cpp +++ b/cipher/CipherKey.cpp @@ -20,6 +20,8 @@ #include "cipher/CipherKey.h" +namespace encfs { + AbstractCipherKey::AbstractCipherKey() { } @@ -28,3 +30,5 @@ AbstractCipherKey::~AbstractCipherKey() { } +} // namespace encfs + diff --git a/cipher/CipherKey.h b/cipher/CipherKey.h index 9c1490b..62edaf0 100644 --- a/cipher/CipherKey.h +++ b/cipher/CipherKey.h @@ -23,6 +23,8 @@ #include "base/shared_ptr.h" +namespace encfs { + class AbstractCipherKey { public: @@ -32,5 +34,7 @@ public: typedef shared_ptr CipherKey; +} // namespace encfs + #endif diff --git a/cipher/MemoryPool.cpp b/cipher/MemoryPool.cpp index d1cd935..5d7793f 100644 --- a/cipher/MemoryPool.cpp +++ b/cipher/MemoryPool.cpp @@ -47,6 +47,8 @@ using namespace std; # include # include +namespace encfs { + static BUF_MEM *allocBlock( int size ) { BUF_MEM *block = BUF_MEM_new( ); @@ -87,7 +89,7 @@ void MemBlock::allocate(int size) } internalData = mem; - data = reinterpret_cast(mem->data); + data = reinterpret_cast(mem->data); VALGRIND_MAKE_MEM_UNDEFINED( data, size ); } @@ -161,4 +163,5 @@ SecureMem::~SecureMem() } } +} // namespace encfs diff --git a/cipher/MemoryPool.h b/cipher/MemoryPool.h index 330e5ce..1fe3b72 100644 --- a/cipher/MemoryPool.h +++ b/cipher/MemoryPool.h @@ -21,19 +21,23 @@ #ifndef _MemoryPool_incl_ #define _MemoryPool_incl_ +#include "base/types.h" + +namespace encfs { + /* Memory Pool for fixed sized objects. Usage: MemBlock mb( size ); // do things with storage in mb.data - unsigned char *buffer = mb.data; + byte *buffer = mb.data; // memblock freed when destructed */ struct MemBlock { - unsigned char *data; + byte *data; void *internalData; MemBlock(); @@ -61,5 +65,7 @@ struct SecureMem ~SecureMem(); }; +} // namespace encfs + #endif diff --git a/cipher/NullCipher.cpp b/cipher/NullCipher.cpp index 867328b..7af4a10 100644 --- a/cipher/NullCipher.cpp +++ b/cipher/NullCipher.cpp @@ -28,6 +28,7 @@ using namespace std; +namespace encfs { static Interface NullInterface = makeInterface( "nullCipher", 1, 0, 0 ); static Range NullKeyRange(0); @@ -81,7 +82,7 @@ Interface NullCipher::interface() const } CipherKey NullCipher::newKey(const char *, int, - int &, long, const unsigned char *, int ) + int &, long, const byte *, int ) { return gNullKey; } @@ -96,25 +97,25 @@ CipherKey NullCipher::newRandomKey() return gNullKey; } -bool NullCipher::randomize( unsigned char *buf, int len, bool ) const +bool NullCipher::randomize( byte *buf, int len, bool ) const { memset( buf, 0, len ); return true; } -uint64_t NullCipher::MAC_64(const unsigned char *, int , +uint64_t NullCipher::MAC_64(const byte *, int , const CipherKey &, uint64_t *) const { return 0; } -CipherKey NullCipher::readKey( const unsigned char *, +CipherKey NullCipher::readKey( const byte *, const CipherKey &, bool) { return gNullKey; } -void NullCipher::writeKey(const CipherKey &, unsigned char *, +void NullCipher::writeKey(const CipherKey &, byte *, const CipherKey &) { } @@ -142,7 +143,7 @@ int NullCipher::cipherBlockSize() const return 1; } -bool NullCipher::streamEncode( unsigned char *src, int len, +bool NullCipher::streamEncode( byte *src, int len, uint64_t iv64, const CipherKey &key) const { (void)src; @@ -152,7 +153,7 @@ bool NullCipher::streamEncode( unsigned char *src, int len, return true; } -bool NullCipher::streamDecode( unsigned char *src, int len, +bool NullCipher::streamDecode( byte *src, int len, uint64_t iv64, const CipherKey &key) const { (void)src; @@ -162,13 +163,13 @@ bool NullCipher::streamDecode( unsigned char *src, int len, return true; } -bool NullCipher::blockEncode( unsigned char *, int , uint64_t, +bool NullCipher::blockEncode( byte *, int , uint64_t, const CipherKey & ) const { return true; } -bool NullCipher::blockDecode( unsigned char *, int, uint64_t, +bool NullCipher::blockDecode( byte *, int, uint64_t, const CipherKey & ) const { return true; @@ -179,3 +180,4 @@ bool NullCipher::Enabled() return true; } +} // namespace encfs diff --git a/cipher/NullCipher.h b/cipher/NullCipher.h index afe6cb4..e3b815f 100644 --- a/cipher/NullCipher.h +++ b/cipher/NullCipher.h @@ -24,6 +24,8 @@ #include "cipher/Cipher.h" #include "base/Interface.h" +namespace encfs { + /* Implements Cipher interface for a pass-through mode. May be useful for testing, but that's it. @@ -41,16 +43,16 @@ public: // create a new key based on a password virtual CipherKey newKey(const char *password, int passwdLength, int &iterationCount, long desiredDuration, - const unsigned char *salt, int saltLen); + const byte *salt, int saltLen); virtual CipherKey newKey(const char *password, int passwdLength); // create a new random key virtual CipherKey newRandomKey(); // data must be len keySize() - virtual CipherKey readKey(const unsigned char *data, + virtual CipherKey readKey(const byte *data, const CipherKey &encodingKey, bool checkKey); - virtual void writeKey(const CipherKey &key, unsigned char *data, + virtual void writeKey(const CipherKey &key, byte *data, const CipherKey &encodingKey); virtual bool compareKey( const CipherKey &A, const CipherKey &B ) const; @@ -60,27 +62,28 @@ public: virtual int encodedKeySize() const; virtual int cipherBlockSize() const; - virtual bool randomize( unsigned char *buf, int len, + virtual bool randomize( byte *buf, int len, bool strongRandom ) const; - virtual uint64_t MAC_64(const unsigned char *data, int len, + virtual uint64_t MAC_64(const byte *data, int len, const CipherKey &key, uint64_t *chainedIV) const; // functional interfaces - virtual bool streamEncode(unsigned char *in, int len, + virtual bool streamEncode(byte *in, int len, uint64_t iv64, const CipherKey &key) const; - virtual bool streamDecode(unsigned char *in, int len, + virtual bool streamDecode(byte *in, int len, uint64_t iv64, const CipherKey &key) const; - virtual bool blockEncode(unsigned char *buf, int size, + virtual bool blockEncode(byte *buf, int size, uint64_t iv64, const CipherKey &key) const; - virtual bool blockDecode(unsigned char *buf, int size, + virtual bool blockDecode(byte *buf, int size, uint64_t iv64, const CipherKey &key) const; // hack to help with static builds static bool Enabled(); }; +} // namespace encfs #endif diff --git a/cipher/SSL_Cipher.cpp b/cipher/SSL_Cipher.cpp index 8390ad3..d8614ce 100644 --- a/cipher/SSL_Cipher.cpp +++ b/cipher/SSL_Cipher.cpp @@ -43,7 +43,8 @@ #include "base/i18n.h" using namespace std; -using namespace rel; + +namespace encfs { const int MAX_KEYLENGTH = 64; // in bytes (256 bit) const int MAX_IVLENGTH = 16; @@ -65,13 +66,13 @@ inline int MIN(int a, int b) DEPRECATED: this is here for backward compatibilty only. Use PBKDF */ int BytesToKey( int keyLen, int ivLen, const EVP_MD *md, - const unsigned char *data, int dataLen, - unsigned int rounds, unsigned char *key, unsigned char *iv) + const byte *data, int dataLen, + unsigned int rounds, byte *key, byte *iv) { if( data == NULL || dataLen == 0 ) return 0; // OpenSSL returns nkey here, but why? It is a failure.. - unsigned char mdBuf[ EVP_MAX_MD_SIZE ]; + byte mdBuf[ EVP_MAX_MD_SIZE ]; unsigned int mds=0; int addmd =0; int nkey = key ? keyLen : 0; @@ -127,8 +128,8 @@ long time_diff(const timeval &end, const timeval &start) } int SSL_Cipher::TimedPBKDF2(const char *pass, int passlen, - const unsigned char *salt, int saltlen, - int keylen, unsigned char *out, + const byte *salt, int saltlen, + int keylen, byte *out, long desiredPDFTime) { int iter = 1000; @@ -138,7 +139,7 @@ int SSL_Cipher::TimedPBKDF2(const char *pass, int passlen, { gettimeofday( &start, 0 ); int res = PKCS5_PBKDF2_HMAC_SHA1( - pass, passlen, const_cast(salt), saltlen, + pass, passlen, const_cast(salt), saltlen, iter, keylen, out); if(res != 1) return -1; @@ -329,14 +330,14 @@ SSLKey::~SSLKey() pthread_mutex_destroy( &mutex ); } -inline unsigned char* KeyData( const shared_ptr &key ) +inline byte* KeyData( const shared_ptr &key ) { - return (unsigned char *)key->buf.data; + return (byte *)key->buf.data; } -inline unsigned char* IVData( const shared_ptr &key ) +inline byte* IVData( const shared_ptr &key ) { - return (unsigned char *)key->buf.data + key->keySize; + return (byte *)key->buf.data + key->keySize; } void initKey(const shared_ptr &key, const EVP_CIPHER *_blockCipher, @@ -424,7 +425,7 @@ Interface SSL_Cipher::interface() const */ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength, int &iterationCount, long desiredDuration, - const unsigned char *salt, int saltLen) + const byte *salt, int saltLen) { shared_ptr key( new SSLKey( _keySize, _ivLength) ); @@ -446,7 +447,7 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength, // known iteration length if(PKCS5_PBKDF2_HMAC_SHA1( password, passwdLength, - const_cast(salt), saltLen, + const_cast(salt), saltLen, iterationCount, _keySize + _ivLength, KeyData(key)) != 1) { LOG(ERROR) << "openssl error, PBKDF2 failed"; @@ -469,7 +470,7 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength) // now we use BytesToKey, which can deal with Blowfish keys larger then // 128 bits. bytes = BytesToKey( _keySize, _ivLength, EVP_sha1(), - (unsigned char *)password, passwdLength, 16, + (byte *)password, passwdLength, 16, KeyData(key), IVData(key) ); // the reason for moving from EVP_BytesToKey to BytesToKey function.. @@ -482,7 +483,7 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength) { // for backward compatibility with filesystems created with 1:0 bytes = EVP_BytesToKey( _blockCipher, EVP_sha1(), NULL, - (unsigned char *)password, passwdLength, 16, + (byte *)password, passwdLength, 16, KeyData(key), IVData(key) ); } @@ -502,9 +503,9 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength) CipherKey SSL_Cipher::newRandomKey() { const int bufLen = MAX_KEYLENGTH; - unsigned char tmpBuf[ bufLen ]; + byte tmpBuf[ bufLen ]; int saltLen = 20; - unsigned char saltBuf[ saltLen ]; + byte saltBuf[ saltLen ]; if(!randomize(tmpBuf, bufLen, true) || !randomize(saltBuf, saltLen, true)) @@ -532,14 +533,14 @@ CipherKey SSL_Cipher::newRandomKey() Compute a 64-bit check value for the data using HMAC. */ static uint64_t _checksum_64(SSLKey *key, - const unsigned char *data, + const byte *data, int dataLen, uint64_t *chainedIV) { rAssert( dataLen > 0 ); Lock lock( key->mutex ); - unsigned char md[EVP_MAX_MD_SIZE]; + byte md[EVP_MAX_MD_SIZE]; unsigned int mdLen = EVP_MAX_MD_SIZE; HMAC_Init_ex( &key->mac_ctx, 0, 0, 0, 0 ); @@ -548,7 +549,7 @@ static uint64_t _checksum_64(SSLKey *key, { // toss in the chained IV as well uint64_t tmp = *chainedIV; - unsigned char h[8]; + byte h[8]; for(unsigned int i=0; i<8; ++i) { h[i] = tmp & 0xff; @@ -563,9 +564,9 @@ static uint64_t _checksum_64(SSLKey *key, rAssert(mdLen >= 8); // chop this down to a 64bit value.. - unsigned char h[8] = {0,0,0,0,0,0,0,0}; + byte h[8] = {0,0,0,0,0,0,0,0}; for(unsigned int i=0; i<(mdLen-1); ++i) - h[i%8] ^= (unsigned char)(md[i]); + h[i%8] ^= (byte)(md[i]); uint64_t value = (uint64_t)h[0]; for(int i=1; i<8; ++i) @@ -574,7 +575,7 @@ static uint64_t _checksum_64(SSLKey *key, return value; } -bool SSL_Cipher::randomize( unsigned char *buf, int len, +bool SSL_Cipher::randomize( byte *buf, int len, bool strongRandom ) const { // to avoid warnings of uninitialized data from valgrind @@ -597,7 +598,7 @@ bool SSL_Cipher::randomize( unsigned char *buf, int len, return true; } -uint64_t SSL_Cipher::MAC_64( const unsigned char *data, int len, +uint64_t SSL_Cipher::MAC_64( const byte *data, int len, const CipherKey &key, uint64_t *chainedIV ) const { shared_ptr mk = dynamic_pointer_cast(key); @@ -609,13 +610,13 @@ uint64_t SSL_Cipher::MAC_64( const unsigned char *data, int len, return tmp; } -CipherKey SSL_Cipher::readKey(const unsigned char *data, +CipherKey SSL_Cipher::readKey(const byte *data, const CipherKey &masterKey, bool checkKey) { shared_ptr mk = dynamic_pointer_cast(masterKey); rAssert(mk->keySize == _keySize); - unsigned char tmpBuf[ 2 * MAX_KEYLENGTH ]; + byte tmpBuf[ 2 * MAX_KEYLENGTH ]; // First N bytes are checksum bytes. unsigned int checksum = 0; @@ -654,7 +655,7 @@ CipherKey SSL_Cipher::readKey(const unsigned char *data, return key; } -void SSL_Cipher::writeKey(const CipherKey &ckey, unsigned char *data, +void SSL_Cipher::writeKey(const CipherKey &ckey, byte *data, const CipherKey &masterKey) { shared_ptr key = dynamic_pointer_cast(ckey); @@ -665,7 +666,7 @@ void SSL_Cipher::writeKey(const CipherKey &ckey, unsigned char *data, rAssert(mk->keySize == _keySize); rAssert(mk->ivLength == _ivLength); - unsigned char tmpBuf[ 2 * MAX_KEYLENGTH ]; + byte tmpBuf[ 2 * MAX_KEYLENGTH ]; unsigned int bufLen = key->buf.size; rAssert(_keySize + _ivLength == bufLen ); @@ -729,19 +730,19 @@ int SSL_Cipher::cipherBlockSize() const return size; } -void SSL_Cipher::setIVec(unsigned char *ivec, uint64_t seed, +void SSL_Cipher::setIVec(byte *ivec, uint64_t seed, const shared_ptr &key) const { if (iface.major() >= 3) { memcpy( ivec, IVData(key), _ivLength ); - unsigned char md[EVP_MAX_MD_SIZE]; + byte md[EVP_MAX_MD_SIZE]; unsigned int mdLen = EVP_MAX_MD_SIZE; for(int i=0; i<8; ++i) { - md[i] = (unsigned char)(seed & 0xff); + md[i] = (byte)(seed & 0xff); seed >>= 8; } @@ -764,7 +765,7 @@ void SSL_Cipher::setIVec(unsigned char *ivec, uint64_t seed, // could get a victim to store a carefully crafted file, they could later // determine if the victim had the file in encrypted storage (without decrypting // the file). -void SSL_Cipher::setIVec_old(unsigned char *ivec, +void SSL_Cipher::setIVec_old(byte *ivec, unsigned int seed, const shared_ptr &key) const { @@ -795,9 +796,9 @@ void SSL_Cipher::setIVec_old(unsigned char *ivec, } } -static void flipBytes(unsigned char *buf, int size) +static void flipBytes(byte *buf, int size) { - unsigned char revBuf[64]; + byte revBuf[64]; int bytesLeft = size; while(bytesLeft) @@ -814,13 +815,13 @@ static void flipBytes(unsigned char *buf, int size) memset(revBuf, 0, sizeof(revBuf)); } -static void shuffleBytes(unsigned char *buf, int size) +static void shuffleBytes(byte *buf, int size) { for(int i=0; i 0 ); @@ -840,7 +841,7 @@ bool SSL_Cipher::streamEncode(unsigned char *buf, int size, Lock lock( key->mutex ); - unsigned char ivec[ MAX_IVLENGTH ]; + byte ivec[ MAX_IVLENGTH ]; int dstLen=0, tmpLen=0; shuffleBytes( buf, size ); @@ -865,7 +866,7 @@ bool SSL_Cipher::streamEncode(unsigned char *buf, int size, return true; } -bool SSL_Cipher::streamDecode(unsigned char *buf, int size, +bool SSL_Cipher::streamDecode(byte *buf, int size, uint64_t iv64, const CipherKey &ckey) const { rAssert( size > 0 ); @@ -876,7 +877,7 @@ bool SSL_Cipher::streamDecode(unsigned char *buf, int size, Lock lock( key->mutex ); - unsigned char ivec[ MAX_IVLENGTH ]; + byte ivec[ MAX_IVLENGTH ]; int dstLen=0, tmpLen=0; setIVec( ivec, iv64 + 1, key ); @@ -902,7 +903,7 @@ bool SSL_Cipher::streamDecode(unsigned char *buf, int size, } -bool SSL_Cipher::blockEncode(unsigned char *buf, int size, +bool SSL_Cipher::blockEncode(byte *buf, int size, uint64_t iv64, const CipherKey &ckey ) const { rAssert( size > 0 ); @@ -916,7 +917,7 @@ bool SSL_Cipher::blockEncode(unsigned char *buf, int size, Lock lock( key->mutex ); - unsigned char ivec[ MAX_IVLENGTH ]; + byte ivec[ MAX_IVLENGTH ]; int dstLen = 0, tmpLen = 0; setIVec( ivec, iv64, key ); @@ -932,7 +933,7 @@ bool SSL_Cipher::blockEncode(unsigned char *buf, int size, return true; } -bool SSL_Cipher::blockDecode(unsigned char *buf, int size, +bool SSL_Cipher::blockDecode(byte *buf, int size, uint64_t iv64, const CipherKey &ckey ) const { rAssert( size > 0 ); @@ -946,7 +947,7 @@ bool SSL_Cipher::blockDecode(unsigned char *buf, int size, Lock lock( key->mutex ); - unsigned char ivec[ MAX_IVLENGTH ]; + byte ivec[ MAX_IVLENGTH ]; int dstLen = 0, tmpLen = 0; setIVec( ivec, iv64, key ); @@ -971,3 +972,5 @@ bool SSL_Cipher::hasStreamMode() const { return false; } + +} // namespace encfs diff --git a/cipher/SSL_Cipher.h b/cipher/SSL_Cipher.h index 9eb4d1b..1dcd1d6 100644 --- a/cipher/SSL_Cipher.h +++ b/cipher/SSL_Cipher.h @@ -24,12 +24,14 @@ #include "cipher/Cipher.h" #include "base/Interface.h" -class SSLKey; #ifndef EVP_CIPHER struct evp_cipher_st; typedef struct evp_cipher_st EVP_CIPHER; #endif +namespace encfs { +class SSLKey; + /* Implements Cipher interface for OpenSSL's ciphers. @@ -89,17 +91,17 @@ class SSL_Cipher : public Cipher // create a new key based on a password virtual CipherKey newKey(const char *password, int passwdLength, int &iterationCount, long desiredDuration, - const unsigned char *salt, int saltLen); + const byte *salt, int saltLen); // deprecated - for backward compatibility virtual CipherKey newKey(const char *password, int passwdLength); // create a new random key virtual CipherKey newRandomKey(); // data must be len keySize() - virtual CipherKey readKey(const unsigned char *data, + virtual CipherKey readKey(const byte *data, const CipherKey &encodingKey, bool checkKey); - virtual void writeKey(const CipherKey &key, unsigned char *data, + virtual void writeKey(const CipherKey &key, byte *data, const CipherKey &encodingKey); virtual bool compareKey( const CipherKey &A, const CipherKey &B ) const; @@ -111,19 +113,19 @@ class SSL_Cipher : public Cipher virtual bool hasStreamMode() const; - virtual bool randomize( unsigned char *buf, int len, + virtual bool randomize( byte *buf, int len, bool strongRandom ) const; - virtual uint64_t MAC_64( const unsigned char *src, int len, + virtual uint64_t MAC_64( const byte *src, int len, const CipherKey &key, uint64_t *augment ) const; // functional interfaces /* Stream encoding in-place. */ - virtual bool streamEncode(unsigned char *in, int len, + virtual bool streamEncode(byte *in, int len, uint64_t iv64, const CipherKey &key) const; - virtual bool streamDecode(unsigned char *in, int len, + virtual bool streamDecode(byte *in, int len, uint64_t iv64, const CipherKey &key) const; /* @@ -131,9 +133,9 @@ class SSL_Cipher : public Cipher blocks are always expected to begin on a block boundary. See blockSize(). */ - virtual bool blockEncode(unsigned char *buf, int size, + virtual bool blockEncode(byte *buf, int size, uint64_t iv64, const CipherKey &key) const; - virtual bool blockDecode(unsigned char *buf, int size, + virtual bool blockDecode(byte *buf, int size, uint64_t iv64, const CipherKey &key) const; // hack to help with static builds @@ -143,17 +145,19 @@ class SSL_Cipher : public Cipher // number of iterations based on a desired execution time (in microseconds). // Returns the number of iterations applied. static int TimedPBKDF2(const char *pass, int passLen, - const unsigned char *salt, int saltLen, - int keyLen, unsigned char *out, + const byte *salt, int saltLen, + int keyLen, byte *out, long desiredPDFTimeMicroseconds); private: - void setIVec( unsigned char *ivec, uint64_t seed, + void setIVec( byte *ivec, uint64_t seed, const shared_ptr &key ) const; // deprecated - for backward compatibility - void setIVec_old( unsigned char *ivec, unsigned int seed, + void setIVec_old( byte *ivec, unsigned int seed, const shared_ptr &key ) const; }; +} // namespace encfs + #endif diff --git a/cipher/openssl.cpp b/cipher/openssl.cpp index 658ea99..f38e4b0 100644 --- a/cipher/openssl.cpp +++ b/cipher/openssl.cpp @@ -31,6 +31,8 @@ #include #endif +namespace encfs { + unsigned long pthreads_thread_id() { return (unsigned long)pthread_self(); @@ -107,3 +109,4 @@ void openssl_shutdown(bool threaded) pthreads_locking_cleanup(); } +} // namespace encfs diff --git a/cipher/openssl.h b/cipher/openssl.h index a7df0e2..c021c48 100644 --- a/cipher/openssl.h +++ b/cipher/openssl.h @@ -21,9 +21,13 @@ #ifndef _openssl_incl_ #define _openssl_incl_ +namespace encfs { + void openssl_init(bool isThreaded); void openssl_shutdown(bool isThreaded); +} // namespace encfs + #endif diff --git a/encfs/main.cpp b/encfs/main.cpp index b7f2ecb..f331baa 100644 --- a/encfs/main.cpp +++ b/encfs/main.cpp @@ -63,6 +63,9 @@ inline static int MAX(int a, int b) using namespace std; using namespace gnu; +using namespace encfs; + +namespace encfs { // Maximum number of arguments that we're going to pass on to fuse. Doesn't // affect how many arguments we can handle, just how many we can pass on.. @@ -111,6 +114,8 @@ struct EncFS_Args static int oldStderr = STDERR_FILENO; +} // namespace encfs + static void usage(const char *name) { diff --git a/fs/BlockFileIO.cpp b/fs/BlockFileIO.cpp index 2b0632e..5dbd178 100644 --- a/fs/BlockFileIO.cpp +++ b/fs/BlockFileIO.cpp @@ -20,14 +20,16 @@ #include "fs/BlockFileIO.h" -#include "base/config.pb.h" #include "base/Error.h" #include "base/i18n.h" #include "cipher/MemoryPool.h" +#include "fs/fsconfig.pb.h" #include #include +namespace encfs { + template inline Type min( Type A, Type B ) { @@ -424,3 +426,4 @@ int BlockFileIO::blockTruncate( off_t size, FileIO *base ) return res; } +} // namespace encfs diff --git a/fs/BlockFileIO.h b/fs/BlockFileIO.h index 42acd54..4cc8898 100644 --- a/fs/BlockFileIO.h +++ b/fs/BlockFileIO.h @@ -21,8 +21,10 @@ #ifndef _BlockFileIO_incl_ #define _BlockFileIO_incl_ -#include "FileIO.h" -#include "FSConfig.h" +#include "fs/FileIO.h" +#include "fs/FSConfig.h" + +namespace encfs { /* Implements block scatter / gather interface. Requires derived classes to @@ -64,5 +66,7 @@ protected: mutable IORequest _cache; }; +} // namespace encfs + #endif diff --git a/fs/BlockNameIO.cpp b/fs/BlockNameIO.cpp index 69b4f91..3b78f54 100644 --- a/fs/BlockNameIO.cpp +++ b/fs/BlockNameIO.cpp @@ -28,6 +28,8 @@ #include #include +namespace encfs { + static shared_ptr NewBlockNameIO( const Interface &iface, const shared_ptr &cipher, const CipherKey &key ) { @@ -248,3 +250,5 @@ bool BlockNameIO::Enabled() return true; } +} // namespace encfs + diff --git a/fs/BlockNameIO.h b/fs/BlockNameIO.h index 832bad3..cfce608 100644 --- a/fs/BlockNameIO.h +++ b/fs/BlockNameIO.h @@ -26,6 +26,8 @@ #include +namespace encfs { + class Cipher; /* @@ -65,5 +67,7 @@ private: bool _caseSensitive; }; +} // namespace encfs + #endif diff --git a/fs/CMakeLists.txt b/fs/CMakeLists.txt index 22ff52c..2b64e50 100644 --- a/fs/CMakeLists.txt +++ b/fs/CMakeLists.txt @@ -1,9 +1,12 @@ find_package (FUSE REQUIRED) include_directories (${FUSE_INCLUDE_DIR}) +protobuf_generate_cpp (PROTO_SRCS PROTO_HDRS ${Encfs_SOURCE_DIR}/protos/fsconfig.proto) + enable_testing () find_package (GTest) +include_directories (${Encfs_BINARY_DIR}/base) add_library (encfs-fs encfs.cpp Context.cpp diff --git a/fs/CipherFileIO.cpp b/fs/CipherFileIO.cpp index 11dcddf..e2cde83 100644 --- a/fs/CipherFileIO.cpp +++ b/fs/CipherFileIO.cpp @@ -20,16 +20,18 @@ #include "fs/CipherFileIO.h" -#include "base/config.pb.h" #include "base/Error.h" #include "cipher/Cipher.h" #include "cipher/MemoryPool.h" +#include "fs/fsconfig.pb.h" #include #include #include +namespace encfs { + /* Version 3:0 adds support for block-only encryption by adding space for a full block to the file header. @@ -511,3 +513,4 @@ bool CipherFileIO::isWritable() const return base->isWritable(); } +} // namespace encfs diff --git a/fs/CipherFileIO.h b/fs/CipherFileIO.h index efc1dcd..5ebb4e6 100644 --- a/fs/CipherFileIO.h +++ b/fs/CipherFileIO.h @@ -27,6 +27,8 @@ #include +namespace encfs { + class Cipher; /* @@ -95,4 +97,6 @@ private: CipherKey key; }; +} // namespace encfs + #endif diff --git a/fs/Context.cpp b/fs/Context.cpp index b24d06a..af7fc9c 100644 --- a/fs/Context.cpp +++ b/fs/Context.cpp @@ -25,7 +25,7 @@ #include "fs/FileUtils.h" #include "fs/DirNode.h" -using namespace rel; +namespace encfs { EncFS_Context::EncFS_Context() { @@ -173,3 +173,4 @@ void EncFS_Context::eraseNode(const char *path, void *pl) delete ph; } +} // namespace encfs diff --git a/fs/Context.h b/fs/Context.h index 0f470a4..a27da53 100644 --- a/fs/Context.h +++ b/fs/Context.h @@ -33,6 +33,8 @@ using std::tr1::unordered_map; using std::unordered_map; #endif +namespace encfs { + struct EncFS_Args; struct EncFS_Opts; class FileNode; @@ -102,5 +104,7 @@ private: int remountFS( EncFS_Context *ctx ); +} // namespace encfs + #endif diff --git a/fs/DirNode.cpp b/fs/DirNode.cpp index 8a967e0..13aa807 100644 --- a/fs/DirNode.cpp +++ b/fs/DirNode.cpp @@ -39,6 +39,7 @@ #include "fs/Context.h" #include "fs/DirNode.h" #include "fs/FileUtils.h" +#include "fs/fsconfig.pb.h" #include @@ -46,7 +47,8 @@ #include using namespace std; -using namespace rel; + +namespace encfs { class DirDeleter { @@ -814,3 +816,6 @@ int DirNode::unlink( const char *plaintextName ) return res; } + +} // namespace encfs + diff --git a/fs/DirNode.h b/fs/DirNode.h index 0c3a344..8bee674 100644 --- a/fs/DirNode.h +++ b/fs/DirNode.h @@ -36,6 +36,8 @@ #include "fs/NameIO.h" #include "fs/FSConfig.h" +namespace encfs { + class Cipher; class RenameOp; struct RenameEl; @@ -170,4 +172,6 @@ private: shared_ptr naming; }; +} // namespace encfs + #endif diff --git a/fs/FSConfig.h b/fs/FSConfig.h index 75cc003..a351870 100644 --- a/fs/FSConfig.h +++ b/fs/FSConfig.h @@ -25,9 +25,12 @@ #include "base/shared_ptr.h" #include "cipher/CipherKey.h" #include "fs/encfs.h" +#include "fs/fsconfig.pb.h" #include +namespace encfs { + enum ConfigType { Config_None = 0, @@ -42,7 +45,6 @@ enum ConfigType struct EncFS_Opts; class Cipher; class NameIO; -class EncfsConfig; CipherKey getUserKey(const EncfsConfig &config, bool useStdin); CipherKey getUserKey(const EncfsConfig &config, @@ -77,5 +79,7 @@ struct FSConfig typedef shared_ptr FSConfigPtr; +} // namespace encfs + #endif diff --git a/fs/FileIO.cpp b/fs/FileIO.cpp index 3bd226c..7f44bb0 100644 --- a/fs/FileIO.cpp +++ b/fs/FileIO.cpp @@ -18,7 +18,9 @@ * along with this program. If not, see . */ -#include "FileIO.h" +#include "fs/FileIO.h" + +namespace encfs { FileIO::FileIO() { @@ -39,3 +41,4 @@ bool FileIO::setIV( uint64_t iv ) return true; } +} // namespace encfs diff --git a/fs/FileIO.h b/fs/FileIO.h index 0c71213..dca4831 100644 --- a/fs/FileIO.h +++ b/fs/FileIO.h @@ -26,6 +26,8 @@ #include +namespace encfs { + struct IORequest { off_t offset; @@ -82,5 +84,7 @@ private: FileIO &operator = ( const FileIO & ); }; +} // namespace encfs + #endif diff --git a/fs/FileNode.cpp b/fs/FileNode.cpp index fc5cdc8..ca38c61 100644 --- a/fs/FileNode.cpp +++ b/fs/FileNode.cpp @@ -39,19 +39,20 @@ #include "cipher/Cipher.h" #include "cipher/MemoryPool.h" +#include "fs/CipherFileIO.h" +#include "fs/DirNode.h" +#include "fs/FileIO.h" #include "fs/FileNode.h" #include "fs/FileUtils.h" -#include "fs/CipherFileIO.h" -#include "fs/RawFileIO.h" #include "fs/MACFileIO.h" -#include "fs/DirNode.h" - -#include "fs/FileIO.h" +#include "fs/RawFileIO.h" +#include "fs/fsconfig.pb.h" #include using namespace std; -using namespace rel; + +namespace encfs { /* TODO: locking at the FileNode level is inefficient, since this precludes @@ -301,3 +302,4 @@ int FileNode::sync(bool datasync) return fh; } +} // namespace encfs diff --git a/fs/FileNode.h b/fs/FileNode.h index c827a89..9bae285 100644 --- a/fs/FileNode.h +++ b/fs/FileNode.h @@ -29,6 +29,8 @@ #include #include +namespace encfs { + class Cipher; class FileIO; class DirNode; @@ -95,6 +97,7 @@ private: }; +} // namespace encfs #endif diff --git a/fs/FileUtils.cpp b/fs/FileUtils.cpp index 28ab025..b8a5a34 100644 --- a/fs/FileUtils.cpp +++ b/fs/FileUtils.cpp @@ -25,10 +25,10 @@ #define _BSD_SOURCE // pick up setenv on RH7.3 #include "fs/encfs.h" +#include "fs/fsconfig.pb.h" #include "base/autosprintf.h" #include "base/config.h" -#include "base/config.pb.h" #include "base/ConfigReader.h" #include "base/Error.h" #include "base/i18n.h" @@ -69,6 +69,8 @@ using namespace std; using namespace gnu; +namespace encfs { + static const int DefaultBlockSize = 2048; // The maximum length of text passwords. If longer are needed, // use the extpass option, as extpass can return arbitrary length binary data. @@ -1674,3 +1676,4 @@ int remountFS(EncFS_Context *ctx) } } +} // namespace encfs diff --git a/fs/FileUtils.h b/fs/FileUtils.h index 83b4f56..bbcdfa4 100644 --- a/fs/FileUtils.h +++ b/fs/FileUtils.h @@ -26,6 +26,8 @@ #include "fs/encfs.h" #include "fs/FSConfig.h" +namespace encfs { + // true if the path points to an existing node (of any type) bool fileExists( const char *fileName ); // true if path is a directory @@ -131,4 +133,6 @@ bool readV6Config( const char *configFile, EncfsConfig &config, bool readProtoConfig( const char *configFile, EncfsConfig &config, struct ConfigInfo *); + +} // namespace encfs #endif diff --git a/fs/MACFileIO.cpp b/fs/MACFileIO.cpp index 430464b..95c4aa7 100644 --- a/fs/MACFileIO.cpp +++ b/fs/MACFileIO.cpp @@ -19,8 +19,8 @@ */ #include "fs/MACFileIO.h" +#include "fs/fsconfig.pb.h" -#include "base/config.pb.h" #include "base/Error.h" #include "base/i18n.h" #include "cipher/MemoryPool.h" @@ -32,6 +32,8 @@ using namespace std; +namespace encfs { + // // Version 1.0 worked on blocks of size (blockSize + headerSize). // That is, it took [blockSize] worth of user data and added headers. @@ -293,3 +295,5 @@ bool MACFileIO::isWritable() const { return base->isWritable(); } + +} // namespace encfs diff --git a/fs/MACFileIO.h b/fs/MACFileIO.h index 0a27709..bf73f67 100644 --- a/fs/MACFileIO.h +++ b/fs/MACFileIO.h @@ -24,6 +24,8 @@ #include "cipher/Cipher.h" #include "fs/BlockFileIO.h" +namespace encfs { + class MACFileIO : public BlockFileIO { public: @@ -63,5 +65,7 @@ private: bool warnOnly; }; +} // namespace encfs + #endif diff --git a/fs/MemBlockFileIO.cpp b/fs/MemBlockFileIO.cpp index 5192f79..dd85989 100644 --- a/fs/MemBlockFileIO.cpp +++ b/fs/MemBlockFileIO.cpp @@ -24,6 +24,8 @@ #include +namespace encfs { + static Interface MemBlockFileIO_iface = makeInterface("FileIO/MemBlock", 1, 0, 0); @@ -74,3 +76,4 @@ bool MemBlockFileIO::isWritable() const { return impl->isWritable(); } +} // namespace encfs diff --git a/fs/MemBlockFileIO.h b/fs/MemBlockFileIO.h index 82f8484..b1bf64e 100644 --- a/fs/MemBlockFileIO.h +++ b/fs/MemBlockFileIO.h @@ -27,6 +27,8 @@ #include #include +namespace encfs { + class MemFileIO; class MemBlockFileIO : public BlockFileIO { @@ -55,5 +57,7 @@ class MemBlockFileIO : public BlockFileIO { MemFileIO *impl; }; +} // namespace encfs + #endif diff --git a/fs/MemFileIO.cpp b/fs/MemFileIO.cpp index d24e583..0ca5a5b 100644 --- a/fs/MemFileIO.cpp +++ b/fs/MemFileIO.cpp @@ -25,6 +25,8 @@ #include +namespace encfs { + static Interface MemFileIO_iface = makeInterface("FileIO/Mem", 1, 0, 0); MemFileIO* NewMemFileIO(const Interface& iface) { @@ -104,3 +106,4 @@ bool MemFileIO::isWritable() const { return writable; } +} // namespace encfs diff --git a/fs/MemFileIO.h b/fs/MemFileIO.h index 894f229..804a107 100644 --- a/fs/MemFileIO.h +++ b/fs/MemFileIO.h @@ -22,11 +22,13 @@ #ifndef _MEMFILEIO_incl_ #define _MEMFILEIO_incl_ -#include "FileIO.h" +#include "fs/FileIO.h" #include #include +namespace encfs { + class MemFileIO : public FileIO { public: MemFileIO(int size); @@ -54,5 +56,7 @@ class MemFileIO : public FileIO { bool writable; }; +} // namespace encfs + #endif diff --git a/fs/NameIO.cpp b/fs/NameIO.cpp index a3795ff..0ec1b2f 100644 --- a/fs/NameIO.cpp +++ b/fs/NameIO.cpp @@ -36,6 +36,8 @@ using namespace std; +namespace encfs { + #define REF_MODULE(TYPE) \ do { \ if(!TYPE::Enabled() ) \ @@ -336,3 +338,6 @@ std::string NameIO::decodeName( const char *path, int length ) const _encodeName( path, length ) : _decodeName( path, length ); } + +} // namespace encfs + diff --git a/fs/NameIO.h b/fs/NameIO.h index 7761a06..d5344dd 100644 --- a/fs/NameIO.h +++ b/fs/NameIO.h @@ -29,6 +29,8 @@ #include "base/Interface.h" #include "cipher/CipherKey.h" +namespace encfs { + class Cipher; class NameIO @@ -137,6 +139,7 @@ do { \ } \ } while(0) +} // namespace encfs #endif diff --git a/fs/NullNameIO.cpp b/fs/NullNameIO.cpp index d3295c1..deeb2a6 100644 --- a/fs/NullNameIO.cpp +++ b/fs/NullNameIO.cpp @@ -24,6 +24,8 @@ #include +namespace encfs { + static shared_ptr NewNNIO( const Interface &, const shared_ptr &, const CipherKey & ) { @@ -82,3 +84,5 @@ bool NullNameIO::Enabled() return true; } +} // namespace encfs + diff --git a/fs/NullNameIO.h b/fs/NullNameIO.h index 2f37bab..3f1f1f1 100644 --- a/fs/NullNameIO.h +++ b/fs/NullNameIO.h @@ -21,7 +21,9 @@ #ifndef _NullNameIO_incl_ #define _NullNameIO_incl_ -#include "NameIO.h" +#include "fs/NameIO.h" + +namespace encfs { class NullNameIO : public NameIO { @@ -47,6 +49,7 @@ protected: private: }; +} // namespace encfs #endif diff --git a/fs/RawFileIO.cpp b/fs/RawFileIO.cpp index a46e916..4b15743 100644 --- a/fs/RawFileIO.cpp +++ b/fs/RawFileIO.cpp @@ -37,6 +37,8 @@ using namespace std; +namespace encfs { + static Interface RawFileIO_iface = makeInterface("FileIO/Raw", 1, 0, 0); FileIO *NewRawFileIO( const Interface &iface ) @@ -328,3 +330,6 @@ bool RawFileIO::isWritable() const { return canWrite; } + +} // namespace encfs + diff --git a/fs/RawFileIO.h b/fs/RawFileIO.h index b2c58a9..dc7c7ab 100644 --- a/fs/RawFileIO.h +++ b/fs/RawFileIO.h @@ -21,10 +21,12 @@ #ifndef _RawFileIO_incl_ #define _RawFileIO_incl_ -#include "FileIO.h" +#include "fs/FileIO.h" #include +namespace encfs { + class RawFileIO : public FileIO { public: @@ -60,5 +62,7 @@ protected: bool canWrite; }; +} // namespace encfs + #endif diff --git a/fs/StreamNameIO.cpp b/fs/StreamNameIO.cpp index d03df64..df9b18a 100644 --- a/fs/StreamNameIO.cpp +++ b/fs/StreamNameIO.cpp @@ -30,6 +30,8 @@ using namespace std; +namespace encfs { + static shared_ptr NewStreamNameIO( const Interface &iface, const shared_ptr &cipher, const CipherKey &key) { @@ -204,3 +206,5 @@ bool StreamNameIO::Enabled() return true; } +} // namespace encfs + diff --git a/fs/StreamNameIO.h b/fs/StreamNameIO.h index 9ff40a3..5238cda 100644 --- a/fs/StreamNameIO.h +++ b/fs/StreamNameIO.h @@ -24,6 +24,8 @@ #include "cipher/CipherKey.h" #include "fs/NameIO.h" +namespace encfs { + class Cipher; class StreamNameIO : public NameIO @@ -54,6 +56,7 @@ private: CipherKey _key; }; +} // namespace encfs #endif diff --git a/fs/encfs.cpp b/fs/encfs.cpp index e41620d..500acb6 100644 --- a/fs/encfs.cpp +++ b/fs/encfs.cpp @@ -60,14 +60,14 @@ using namespace std; #include +namespace encfs { + #ifndef MIN #define MIN(a,b) (((a)<(b)) ? (a): (b)) #endif #define ESUCCESS 0 -using rel::Lock; - #define GET_FN(ctx, finfo) ctx->getNode((void*)(uintptr_t)finfo->fh) static EncFS_Context * context() @@ -789,5 +789,7 @@ int encfs_removexattr( const char *path, const char *name ) return withCipherPath( "removexattr", path, _do_removexattr, name ); } +} // namespace encfs + #endif // HAVE_XATTR diff --git a/fs/encfs.h b/fs/encfs.h index 912e9fd..d380185 100644 --- a/fs/encfs.h +++ b/fs/encfs.h @@ -57,6 +57,8 @@ static __inline int setfsgid(gid_t gid) } #endif +namespace encfs { + int encfs_getattr(const char *path, struct stat *stbuf); int encfs_fgetattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi); @@ -105,5 +107,7 @@ int encfs_removexattr( const char *path, const char *name ); int encfs_utimens( const char *path, const struct timespec ts[2] ); +} // namespace encfs + #endif diff --git a/fs/test.cpp b/fs/test.cpp index f7c9af4..c1a0c1d 100644 --- a/fs/test.cpp +++ b/fs/test.cpp @@ -56,6 +56,8 @@ using std::unordered_set; using namespace std; +namespace encfs { + const int FSBlockSize = 256; static @@ -552,5 +554,5 @@ int main(int argc, char *argv[]) return 0; } - +} // namespace encfs diff --git a/fs/test_BlockIO.cpp b/fs/test_BlockIO.cpp index c81462e..b5f529c 100644 --- a/fs/test_BlockIO.cpp +++ b/fs/test_BlockIO.cpp @@ -30,6 +30,8 @@ #include "fs/MemFileIO.h" #include "fs/MemBlockFileIO.h" +using namespace encfs; + namespace { TEST(BlockFileIOTest, BasicIO) { @@ -63,5 +65,5 @@ TEST(BlockFileIOTest, BasicIO) { ASSERT_NO_FATAL_FAILURE(compare(&base, &block, 0, 1024)); } -} // namespace +} // namespace encfs diff --git a/fs/test_IO.cpp b/fs/test_IO.cpp index a89317e..5efe7cf 100644 --- a/fs/test_IO.cpp +++ b/fs/test_IO.cpp @@ -33,6 +33,8 @@ #include "fs/MACFileIO.h" #include "fs/MemFileIO.h" +using namespace encfs; + namespace { TEST(MemIOTest, BasicIO) { diff --git a/fs/testing.cpp b/fs/testing.cpp index 819f7d5..c3288cf 100644 --- a/fs/testing.cpp +++ b/fs/testing.cpp @@ -30,13 +30,16 @@ #include "cipher/Cipher.h" #include "cipher/MemoryPool.h" -#include "fs/MemFileIO.h" -#include "fs/FileUtils.h" #include "fs/FSConfig.h" +#include "fs/fsconfig.pb.h" +#include "fs/FileUtils.h" #include "fs/MACFileIO.h" +#include "fs/MemFileIO.h" using namespace std; +namespace encfs { + FSConfigPtr makeConfig(const shared_ptr& cipher, int blockSize) { FSConfigPtr cfg = FSConfigPtr(new FSConfig); cfg->cipher = cipher; @@ -169,3 +172,5 @@ int main(int argc, char **argv) { return RUN_ALL_TESTS(); } +} // namespace encfs + diff --git a/fs/testing.h b/fs/testing.h index a4aeec3..ab291cf 100644 --- a/fs/testing.h +++ b/fs/testing.h @@ -7,6 +7,8 @@ #include "fs/FileUtils.h" #include "fs/FSConfig.h" +namespace encfs { + class FileIO; FSConfigPtr makeConfig(const shared_ptr& cipher, int blockSize); @@ -19,5 +21,7 @@ void comparisonTest(FSConfigPtr& cfg, FileIO* a, FileIO* b); void compare(FileIO* a, FileIO* b, int offset, int len); +} // namespace encfs + #endif diff --git a/base/config.proto b/protos/fsconfig.proto similarity index 70% rename from base/config.proto rename to protos/fsconfig.proto index 28b1bad..5d34f94 100644 --- a/base/config.proto +++ b/protos/fsconfig.proto @@ -1,4 +1,10 @@ +package encfs; + +option optimize_for = CODE_SIZE; + +import "interface.proto"; + message EncfsConfig { optional string creator = 1; @@ -34,15 +40,3 @@ message EncryptedKey optional int32 kdf_duration = 11 [default=500]; } -message Interface -{ - required string name = 1; - required uint32 major = 2; // major version number - required uint32 minor = 3; // minor version number - - // Age indicates number of major versions supported. 0 means no backward - // compatibility. See libtool "updating version information" for more - // details on how major/minor/age are used for versioning libraries. - optional uint32 age = 4; -} - diff --git a/protos/interface.proto b/protos/interface.proto new file mode 100644 index 0000000..3fb88fb --- /dev/null +++ b/protos/interface.proto @@ -0,0 +1,17 @@ + +package encfs; + +option optimize_for = CODE_SIZE; + +message Interface +{ + required string name = 1; + required uint32 major = 2; // major version number + required uint32 minor = 3; // minor version number + + // Age indicates number of major versions supported. 0 means no backward + // compatibility. See libtool "updating version information" for more + // details on how major/minor/age are used for versioning libraries. + optional uint32 age = 4; +} + diff --git a/util/encfsctl.cpp b/util/encfsctl.cpp index 8b89113..1357fc8 100644 --- a/util/encfsctl.cpp +++ b/util/encfsctl.cpp @@ -48,7 +48,7 @@ using namespace std; using namespace gnu; - +using namespace encfs; static int showInfo( int argc, char **argv ); static int showVersion( int argc, char **argv ); From f00ef5c6d393e47a6bcf4642f951204c43fe7dc0 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Tue, 5 Mar 2013 06:32:27 +0000 Subject: [PATCH 15/51] break out cipher primitives, add unit tests git-svn-id: http://encfs.googlecode.com/svn/trunk@94 db9cf616-1c43-0410-9cb8-a902689de0d6 --- CMakeLists.txt | 41 ++++- base/CMakeLists.txt | 2 + base/Range.h | 14 ++ base/Registry.h | 94 ++++++++++ cipher/BlockCipher.cpp | 29 +++ cipher/BlockCipher.h | 28 +++ cipher/BlockCipher_test.cpp | 95 ++++++++++ cipher/CMakeLists.txt | 43 ++--- cipher/MAC.cpp | 16 ++ cipher/MAC.h | 43 +++++ cipher/MAC_test.cpp | 88 +++++++++ cipher/MemoryPool.cpp | 2 +- cipher/MemoryPool.h | 5 +- cipher/PBKDF.cpp | 16 ++ cipher/PBKDF.h | 35 ++++ cipher/PBKDF_test.cpp | 78 ++++++++ cipher/SSL_Cipher.cpp | 114 ++++++------ cipher/StreamCipher.cpp | 20 ++ cipher/StreamCipher.h | 60 ++++++ cipher/openssl.cpp | 355 +++++++++++++++++++++++++++++++++++- cipher/openssl.h | 11 +- cipher/testing.cpp | 30 +++ cipher/testing.h | 36 ++++ encfs/CMakeLists.txt | 4 - encfs/main.cpp | 4 +- fs/CMakeLists.txt | 24 +-- fs/FileUtils.cpp | 26 +-- util/CMakeLists.txt | 4 - util/encfsctl.cpp | 48 ++++- 29 files changed, 1235 insertions(+), 130 deletions(-) create mode 100644 base/Registry.h create mode 100644 cipher/BlockCipher.cpp create mode 100644 cipher/BlockCipher.h create mode 100644 cipher/BlockCipher_test.cpp create mode 100644 cipher/MAC.cpp create mode 100644 cipher/MAC.h create mode 100644 cipher/MAC_test.cpp create mode 100644 cipher/PBKDF.cpp create mode 100644 cipher/PBKDF.h create mode 100644 cipher/PBKDF_test.cpp create mode 100644 cipher/StreamCipher.cpp create mode 100644 cipher/StreamCipher.h create mode 100644 cipher/testing.cpp create mode 100644 cipher/testing.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 660d9cd..e4764f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,8 +11,28 @@ option (BUILD_SHARED_LIBS "Build dynamic link libraries" OFF) set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMakeModules/") +# Tweak compiler flags. set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall") +include (CheckCXXCompilerFlag) +check_cxx_compiler_flag (-std=c++11 HAVE_C11_FLAG) +check_cxx_compiler_flag (-std=gnu++11 HAVE_GNU11_FLAG) + +if (HAVE_GNU11_FLAG) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") +elseif (HAVE_C11_FLAG) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +endif (HAVE_GNU11_FLAG) + +# Flume specific flags. +find_package (FUSE REQUIRED) +include_directories (${FUSE_INCLUDE_DIR}) +add_definitions (-D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=26) +if (APPLE) + add_definitions (-D__FreeBSD__=10) +endif (APPLE) + +# Packaging config. set (CPACK_PACKAGE_NAME "Encfs") set (CPACK_PACKAGE_VERSION_MAJOR ${ENCFS_MAJOR}) set (CPACK_PACKAGE_VERSION_MINOR ${ENCFS_MINOR}) @@ -23,6 +43,7 @@ set (CPACK_SOURCE_IGNORE_FILES "/build/") include (CPack) +# Check for external files. include (CheckIncludeFileCXX) check_include_file_cxx (attr/xattr.h HAVE_ATTR_XATTR_H) check_include_file_cxx (sys/xattr.h HAVE_SYS_XATTR_H) @@ -45,11 +66,7 @@ CHECK_CXX_SOURCE_COMPILES ("#include #include int main() { getxattr(0,0,0,0,0,0); return 1; } " XATTR_ADD_OPT) -add_definitions (-D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=26) -if (APPLE) - add_definitions (-D__FreeBSD__=10) -endif (APPLE) - +# Libraries or programs used for multiple modules. find_package (Protobuf REQUIRED) include_directories (${PROTOBUF_INCLUDE_DIR}) @@ -58,9 +75,16 @@ include_directories (${GLOG_INCLUDE_DIRS}) find_program (POD2MAN pod2man) +find_package (GTest) +if (GTEST_FOUND) + enable_testing() +endif (GTEST_FOUND) + +# Prefix for encfs module includes. include_directories (${Encfs_BINARY_DIR}) include_directories (${Encfs_SOURCE_DIR}) +# Subdirectories. add_subdirectory(base) add_subdirectory(cipher) add_subdirectory(fs) @@ -68,3 +92,10 @@ add_subdirectory(encfs) add_subdirectory(util) add_subdirectory(po) +# Test target. +if (GTEST_FOUND) + add_custom_target (test COMMAND ${CMAKE_TEST_COMMAND} DEPENDS + cipher/cipher-tests fs/fs-tests) +endif (GTEST_FOUND) + + diff --git a/base/CMakeLists.txt b/base/CMakeLists.txt index f27f773..9287894 100644 --- a/base/CMakeLists.txt +++ b/base/CMakeLists.txt @@ -17,6 +17,8 @@ add_library (encfs-base ConfigVar.cpp Error.cpp Interface.cpp + Range.h + Registry.h XmlReader.cpp ${PROTO_SRCS} ${PROTO_HDRS} diff --git a/base/Range.h b/base/Range.h index f5f6a81..1639d6b 100644 --- a/base/Range.h +++ b/base/Range.h @@ -21,6 +21,8 @@ #ifndef _Range_incl_ #define _Range_incl_ +#include + namespace encfs { class Range @@ -42,6 +44,18 @@ public: int inc() const; }; +inline std::ostream & operator << (std::ostream &st, const Range &r) { + bool separator = false; + for (int size = r.min(); size <= r.max(); size += r.inc()) { + if (separator) + st << ", "; + else + separator = true; + st << size; + } + return st; +} + inline Range::Range(int minMax) { this->minVal = minMax; diff --git a/base/Registry.h b/base/Registry.h new file mode 100644 index 0000000..49c66c7 --- /dev/null +++ b/base/Registry.h @@ -0,0 +1,94 @@ +#ifndef REGISTRY_H +#define REGISTRY_H + +#include +#include + +namespace encfs { + +template +class Registry +{ +public: + typedef T *(*FactoryFn)(); + struct Data { + FactoryFn constructor; + typename T::Properties properties; + }; + + void Register(const char *name, FactoryFn fn, + typename T::Properties properties) + { + Data d; + d.constructor = fn; + d.properties = properties; + data[name] = d; + } + + T* Create(const char *name) + { + auto it = data.find(name); + if (it == data.end()) + return NULL; + return (*it->second.constructor)(); + } + + T* CreateForMatch(const std::string &description) + { + for (auto &it : data) { + if (description == it.second.properties.toString()) + return (*it.second.constructor)(); + } + return NULL; + } + + std::list GetAll() const { + std::list result; + for (auto &it : data) { + result.push_back(it.first); + } + return result; + } + + const typename T::Properties *GetProperties(const char *name) const { + auto it = data.find(name); + if (it == data.end()) + return NULL; + return &(it->second.properties); + } + +private: + std::map data; +}; + +template +class Registrar +{ +public: + Registrar(const char *name) + { + BASE::GetRegistry().Register(name, + Registrar::Construct, + T::GetProperties()); + } + + static BASE *Construct() { + return new T(); + } +}; + +#define DECLARE_REGISTERABLE_TYPE(TYPE) \ + static Registry& GetRegistry() + +#define DEFINE_REGISTERABLE_TYPE(TYPE) \ + Registry& TYPE::GetRegistry() { \ + static Registry registry; \ + return registry; \ + } + +#define REGISTER_CLASS(DERIVED, BASE) \ + static Registrar registrar_##DERIVED(#DERIVED) + +} // namespace encfs + +#endif // REGISTRY_H diff --git a/cipher/BlockCipher.cpp b/cipher/BlockCipher.cpp new file mode 100644 index 0000000..3bc9d15 --- /dev/null +++ b/cipher/BlockCipher.cpp @@ -0,0 +1,29 @@ +#include "cipher/BlockCipher.h" + +// TODO: add ifdef when OpenSSL becomes optional. +#include "cipher/openssl.h" + +namespace encfs { + +Registry& BlockCipher::GetRegistry() +{ + static Registry registry; + static bool first = true; + if (first) + { + OpenSSL::registerCiphers(); + first = false; + } + return registry; +} + +BlockCipher::BlockCipher() +{ +} + +BlockCipher::~BlockCipher() +{ +} + +} // namespace encfs + diff --git a/cipher/BlockCipher.h b/cipher/BlockCipher.h new file mode 100644 index 0000000..7f853dc --- /dev/null +++ b/cipher/BlockCipher.h @@ -0,0 +1,28 @@ +#ifndef BLOCKCIPHER_H +#define BLOCKCIPHER_H + +#include "base/Interface.h" +#include "base/Range.h" +#include "base/Registry.h" +#include "base/shared_ptr.h" +#include "base/types.h" +#include "cipher/StreamCipher.h" + +namespace encfs { + +// BlockCipher is a StreamCipher with a block size. +// Encryption and decryption must be in multiples of the block size. +class BlockCipher : public StreamCipher +{ + public: + static Registry& GetRegistry(); + + BlockCipher(); + virtual ~BlockCipher(); + + virtual int blockSize() const =0; +}; + +} // namespace encfs + +#endif // BLOCKCIPHER_H diff --git a/cipher/BlockCipher_test.cpp b/cipher/BlockCipher_test.cpp new file mode 100644 index 0000000..724d8f0 --- /dev/null +++ b/cipher/BlockCipher_test.cpp @@ -0,0 +1,95 @@ + +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2013 Valient Gough + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include + +#include "base/shared_ptr.h" +#include "cipher/BlockCipher.h" +#include "cipher/MemoryPool.h" + +using namespace encfs; +using std::list; +using std::string; + +namespace { + +void compare(const byte *a, const byte *b, int size) { + for (int i = 0; i < size; i++) { + bool match = (a[i] == b[i]); + ASSERT_TRUE(match) << "mismatched data at offset " << i + << " of " << size; + if (!match) + break; + } +} + +TEST(BlockEncryptionTest, BlockCipher) { + Registry registry = BlockCipher::GetRegistry(); + list ciphers = registry.GetAll(); + for (const string &name : ciphers) { + const BlockCipher::Properties *properties = registry.GetProperties(name.c_str()); + SCOPED_TRACE(testing::Message() << "Cipher " << name); + + for (int keySize = properties->keySize.min(); + keySize <= properties->keySize.max(); + keySize += properties->keySize.inc()) { + SCOPED_TRACE(testing::Message() << "Key size " << keySize); + + shared_ptr cipher (registry.Create(name.c_str())); + + ASSERT_TRUE(cipher->randomKey(keySize / 8)); + + // Create some data to encrypt. + int blockSize = cipher->blockSize(); + MemBlock mb; + mb.allocate(16 * blockSize); + + for (int i = 0; i < 16 * blockSize; i++) { + mb.data[i] = i % 256; + } + + MemBlock iv; + iv.allocate(blockSize); + for (int i = 0; i < blockSize; i++) { + iv.data[i] = i; + } + + // Encrypt. + MemBlock encrypted; + encrypted.allocate(16 * blockSize); + + ASSERT_TRUE(cipher->encrypt(iv.data, mb.data, + encrypted.data, 16 * blockSize)); + + // Decrypt. + MemBlock decrypted; + decrypted.allocate(16 * blockSize); + ASSERT_TRUE(cipher->decrypt(iv.data, encrypted.data, + decrypted.data, 16 * blockSize)); + + compare(mb.data, decrypted.data, 16 * blockSize); + } + } +} + +} // namespace diff --git a/cipher/CMakeLists.txt b/cipher/CMakeLists.txt index 158b28e..f586f46 100644 --- a/cipher/CMakeLists.txt +++ b/cipher/CMakeLists.txt @@ -2,41 +2,42 @@ include_directories (${OPENSSL_INCLUDE_DIR}) link_directories (${Encfs_BINARY_DIR}/base) -enable_testing () -find_package (GTest REQUIRED) - add_library (encfs-cipher - readpassphrase.cpp BlockCipher.cpp Cipher.cpp CipherKey.cpp + MAC.cpp MemoryPool.cpp NullCipher.cpp openssl.cpp + PBKDF.cpp + readpassphrase.cpp SSL_Cipher.cpp + StreamCipher.cpp ) target_link_libraries (encfs-cipher ${OPENSSL_LIBRARIES} ) -#include_directories (${GTEST_INCLUDE_DIR}) -#add_executable (unittests -#MemBlockFileIO.cpp -#MemFileIO.cpp -#testing.cpp -#test_IO.cpp -#test_BlockIO.cpp -#) +if (GTEST_FOUND) + link_directories (${PROJECT_BINARY_DIR}/base) + include_directories (${GTEST_INCLUDE_DIR}) -#target_link_libraries (unittests -#${GTEST_BOTH_LIBRARIES} -#encfs-fs -#encfs-base -#${GLOG_LIBRARIES} -#) + file (GLOB TEST_FILES "*_test.cpp") -#add_test (UnitTests unittests) -#GTEST_ADD_TESTS (unittests "${UnitTestArgs}" test_IO.cpp test_BlockIO.cpp) -#add_custom_target (test COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS unittests) + add_executable (cipher-tests + testing.cpp + ${TEST_FILES} + ) + target_link_libraries (cipher-tests + ${GTEST_BOTH_LIBRARIES} + encfs-cipher + encfs-base + ${GLOG_LIBRARIES} + ) + + add_test (CipherTests cipher-tests) + GTEST_ADD_TESTS (cipher-tests "${CipherTestArgs}" ${TEST_FILES}) +endif (GTEST_FOUND) diff --git a/cipher/MAC.cpp b/cipher/MAC.cpp new file mode 100644 index 0000000..64e08e1 --- /dev/null +++ b/cipher/MAC.cpp @@ -0,0 +1,16 @@ +#include "cipher/MAC.h" + +namespace encfs { + +DEFINE_REGISTERABLE_TYPE(MessageAuthenticationCode) + +MessageAuthenticationCode::MessageAuthenticationCode() +{ +} + +MessageAuthenticationCode::~MessageAuthenticationCode() +{ +} + +} // namespace encfs + diff --git a/cipher/MAC.h b/cipher/MAC.h new file mode 100644 index 0000000..d7849e2 --- /dev/null +++ b/cipher/MAC.h @@ -0,0 +1,43 @@ +#ifndef ENCFS_MAC_H +#define ENCFS_MAC_H + +#include + +#include "base/Registry.h" +#include "base/types.h" + +namespace encfs { + +// MessageAuthenticationCode provides keyed MAC algorithms, eg HMAC. +class MessageAuthenticationCode +{ + public: + DECLARE_REGISTERABLE_TYPE(MessageAuthenticationCode); + + struct Properties { + int blockSize; // Block length of hash function. + std::string hashFunction; + std::string mode; + std::string library; + + std::string toString() const { + return hashFunction + "/" + mode; + } + }; + + MessageAuthenticationCode(); + virtual ~MessageAuthenticationCode(); + + virtual int outputSize() const =0; + + virtual bool setKey(const byte *key, int keyLength) =0; + virtual bool randomKey(int keyLength) =0; + + virtual void reset() =0; + virtual bool update(const byte *in, int length) =0; + virtual bool write(byte *out) =0; +}; + +} // namespace encfs + +#endif // ENCFS_MAC_H diff --git a/cipher/MAC_test.cpp b/cipher/MAC_test.cpp new file mode 100644 index 0000000..c93bd8a --- /dev/null +++ b/cipher/MAC_test.cpp @@ -0,0 +1,88 @@ + +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2013 Valient Gough + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + + +#include + +#include + +#include "base/shared_ptr.h" +#include "cipher/MAC.h" +#include "cipher/testing.h" + +using namespace encfs; + +namespace { + +TEST(HMacSha1Test, MessageAuthenticationCode) { + Registry registry = + MessageAuthenticationCode::GetRegistry(); + shared_ptr hmac( + registry.CreateForMatch( "SHA-1/HMAC" )); + ASSERT_FALSE(!hmac); + + // Test cases from rfc2202 + // Test case 1 + byte key[20]; + byte out[20]; + for (int i = 0; i < 20; ++i) + key[i] = 0x0b; + hmac->setKey(key, 20); + hmac->reset(); + hmac->update((byte *)"Hi There", 8); + hmac->write(out); + ASSERT_EQ("b617318655057264e28bc0b6fb378c8ef146be00", stringToHex(out, 20)); + + // Test case 2 + strcpy((char *)key, "Jefe"); + hmac->setKey(key, 4); + hmac->reset(); + hmac->update((byte *)"what do ya want for nothing?", 28); + hmac->write(out); + ASSERT_EQ("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79", stringToHex(out, 20)); + + // Test case 3 + for (int i = 0; i < 20; ++i) + key[i] = 0xaa; + hmac->setKey(key, 20); + hmac->reset(); + { + byte data[50]; + memset(data, 0xdd, 50); + hmac->update(data, 50); + } + hmac->write(out); + ASSERT_EQ("125d7342b9ac11cd91a39af48aa17b4f63f175d3", stringToHex(out, 20)); + + // Test #7 + byte longKey[80]; + memset(longKey, 0xaa, 80); + hmac->setKey(longKey, 80); + hmac->reset(); + hmac->update((byte *)"Test Using Larger Than Block-Size Key and Larger " + "Than One Block-Size Data", 73); + hmac->write(out); + ASSERT_EQ("e8e99d0f45237d786d6bbaa7965c7808bbff1a91", stringToHex(out, 20)); +} + + +} // namespace + diff --git a/cipher/MemoryPool.cpp b/cipher/MemoryPool.cpp index 5d7793f..5c079f3 100644 --- a/cipher/MemoryPool.cpp +++ b/cipher/MemoryPool.cpp @@ -134,7 +134,7 @@ void MemoryPool::destroyAll() SecureMem::SecureMem(int len) { rAssert(len > 0); - data = (char *)OPENSSL_malloc(len); + data = (byte *)OPENSSL_malloc(len); if (data) { size = len; diff --git a/cipher/MemoryPool.h b/cipher/MemoryPool.h index 1fe3b72..b6f1c54 100644 --- a/cipher/MemoryPool.h +++ b/cipher/MemoryPool.h @@ -29,7 +29,8 @@ namespace encfs { Memory Pool for fixed sized objects. Usage: - MemBlock mb( size ); + MemBlock mb; + mb.allocate( size ); // do things with storage in mb.data byte *buffer = mb.data; @@ -59,7 +60,7 @@ namespace MemoryPool struct SecureMem { int size; - char *data; + byte *data; SecureMem(int len); ~SecureMem(); diff --git a/cipher/PBKDF.cpp b/cipher/PBKDF.cpp new file mode 100644 index 0000000..5267090 --- /dev/null +++ b/cipher/PBKDF.cpp @@ -0,0 +1,16 @@ +#include "cipher/PBKDF.h" + +namespace encfs { + +DEFINE_REGISTERABLE_TYPE(PBKDF) + +PBKDF::PBKDF() +{ +} + +PBKDF::~PBKDF() +{ +} + +} // namespace encfs + diff --git a/cipher/PBKDF.h b/cipher/PBKDF.h new file mode 100644 index 0000000..228d9b1 --- /dev/null +++ b/cipher/PBKDF.h @@ -0,0 +1,35 @@ +#ifndef ENCFS_PBKDF_H +#define ENCFS_PBKDF_H + +#include + +#include "base/Registry.h" +#include "base/types.h" + +namespace encfs { + +// Password Based Key Derivation Function. +class PBKDF +{ + public: + DECLARE_REGISTERABLE_TYPE(PBKDF); + + struct Properties { + std::string mode; + std::string library; + + std::string toString() const { return mode; } + }; + + PBKDF(); + virtual ~PBKDF(); + + virtual bool makeKey(const char *password, int passwordLength, + const byte *salt, int saltLength, + int numIterations, + byte *outKey, int keyLength) const = 0; +}; + +} // namespace encfs + +#endif // ENCFS_PBKDF_H diff --git a/cipher/PBKDF_test.cpp b/cipher/PBKDF_test.cpp new file mode 100644 index 0000000..0faeb23 --- /dev/null +++ b/cipher/PBKDF_test.cpp @@ -0,0 +1,78 @@ + +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2013 Valient Gough + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + + +#include + +#include + +#include "base/shared_ptr.h" +#include "cipher/PBKDF.h" +#include "cipher/testing.h" + +using namespace encfs; + +namespace { + +TEST(PKCS5_PBKDF2_HMAC_SHA1, PBKDF) { + Registry registry = PBKDF::GetRegistry(); + shared_ptr impl( registry.CreateForMatch( "PKCS5_PBKDF2_HMAC_SHA1" )); + ASSERT_FALSE(!impl); + + // Test cases from rfc6070 + // Test case 1 + { + byte key[20]; + bool ok = impl->makeKey("password", 8, + (byte*)"salt", 4, + 1, + key, sizeof(key)); + ASSERT_TRUE(ok); + ASSERT_EQ("0c60c80f961f0e71f3a9b524af6012062fe037a6", + stringToHex(key, sizeof(key))); + } + + { + byte key[25]; + bool ok = impl->makeKey("passwordPASSWORDpassword", 24, + (byte*)"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, + 4096, + key, sizeof(key)); + ASSERT_TRUE(ok); + ASSERT_EQ("3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038", + stringToHex(key, sizeof(key))); + } + + { + byte key[16]; + bool ok = impl->makeKey("pass\0word", 9, + (byte*)"sa\0lt", 5, + 4096, + key, sizeof(key)); + ASSERT_TRUE(ok); + ASSERT_EQ("56fa6aa75548099dcc37d7f03425e0c3", + stringToHex(key, sizeof(key))); + } +} + + +} // namespace + diff --git a/cipher/SSL_Cipher.cpp b/cipher/SSL_Cipher.cpp index d8614ce..b434ee6 100644 --- a/cipher/SSL_Cipher.cpp +++ b/cipher/SSL_Cipher.cpp @@ -28,6 +28,7 @@ #include "cipher/SSL_Cipher.h" #include "cipher/MemoryPool.h" +#include "cipher/BlockCipher.h" #include "base/Error.h" #include "base/Mutex.h" #include "base/Range.h" @@ -65,13 +66,13 @@ inline int MIN(int a, int b) DEPRECATED: this is here for backward compatibilty only. Use PBKDF */ -int BytesToKey( int keyLen, int ivLen, const EVP_MD *md, +int BytesToKey(int keyLen, int ivLen, const EVP_MD *md, const byte *data, int dataLen, unsigned int rounds, byte *key, byte *iv) { if( data == NULL || dataLen == 0 ) return 0; // OpenSSL returns nkey here, but why? It is a failure.. - + byte mdBuf[ EVP_MAX_MD_SIZE ]; unsigned int mds=0; int addmd =0; @@ -110,7 +111,7 @@ int BytesToKey( int keyLen, int ivLen, const EVP_MD *md, { memcpy( iv, mdBuf+offset, toCopy ); iv += toCopy; - niv -= toCopy; + niv -= toCopy; offset += toCopy; } if((nkey == 0) && (niv == 0)) break; @@ -128,9 +129,9 @@ long time_diff(const timeval &end, const timeval &start) } int SSL_Cipher::TimedPBKDF2(const char *pass, int passlen, - const byte *salt, int saltlen, - int keylen, byte *out, - long desiredPDFTime) + const byte *salt, int saltlen, + int keylen, byte *out, + long desiredPDFTime) { int iter = 1000; timeval start, end; @@ -188,8 +189,9 @@ static shared_ptr NewBFCipher( const Interface &iface, int keyLen ) const EVP_CIPHER *blockCipher = EVP_bf_cbc(); const EVP_CIPHER *streamCipher = EVP_bf_cfb(); - return shared_ptr( new SSL_Cipher(iface, BlowfishInterface, - blockCipher, streamCipher, keyLen / 8) ); + return shared_ptr( + new SSL_Cipher(iface, BlowfishInterface, + blockCipher, streamCipher, keyLen / 8) ); } static bool BF_Cipher_registered = Cipher::Register( @@ -239,8 +241,8 @@ static shared_ptr NewAESCipher( const Interface &iface, int keyLen ) } static bool AES_Cipher_registered = Cipher::Register( - "AES", "16 byte block cipher", - AESInterface, AESKeyRange, AESBlockRange, NewAESCipher, true); + "AES", "16 byte block cipher", + AESInterface, AESKeyRange, AESBlockRange, NewAESCipher, true); #endif #if defined(HAVE_EVP_AES_XTS) @@ -276,35 +278,35 @@ static shared_ptr NewAesXtsCipher( const Interface &iface, int keyLen ) } static bool AES_XTS_Cipher_registered = Cipher::Register( - "AES_XTS", "Tweakable wide-block cipher", - AesXtsInterface, AesXtsKeyRange, AesXtsBlockRange, NewAesXtsCipher, false); + "AES_XTS", "Tweakable wide-block cipher", + AesXtsInterface, AesXtsKeyRange, AesXtsBlockRange, NewAesXtsCipher, false); #endif class SSLKey : public AbstractCipherKey { - public: - pthread_mutex_t mutex; +public: + pthread_mutex_t mutex; - unsigned int keySize; // in bytes - unsigned int ivLength; + unsigned int keySize; // in bytes + unsigned int ivLength; - // key data is first _keySize bytes, - // followed by iv of _ivLength bytes, - SecureMem buf; + // key data is first _keySize bytes, + // followed by iv of _ivLength bytes, + SecureMem buf; - EVP_CIPHER_CTX block_enc; - EVP_CIPHER_CTX block_dec; - EVP_CIPHER_CTX stream_enc; - EVP_CIPHER_CTX stream_dec; + EVP_CIPHER_CTX block_enc; + EVP_CIPHER_CTX block_dec; + EVP_CIPHER_CTX stream_enc; + EVP_CIPHER_CTX stream_dec; - HMAC_CTX mac_ctx; + HMAC_CTX mac_ctx; - SSLKey(int keySize, int ivLength); - ~SSLKey(); + SSLKey(int keySize, int ivLength); + ~SSLKey(); }; SSLKey::SSLKey(int keySize_, int ivLength_) - : buf(keySize_ + ivLength_) +: buf(keySize_ + ivLength_) { rAssert(keySize_ >= 8); rAssert(ivLength_ >= 8); @@ -341,7 +343,7 @@ inline byte* IVData( const shared_ptr &key ) } void initKey(const shared_ptr &key, const EVP_CIPHER *_blockCipher, - const EVP_CIPHER *_streamCipher, int _keySize) + const EVP_CIPHER *_streamCipher, int _keySize) { Lock lock( key->mutex ); // initialize the cipher context once so that we don't have to do it for @@ -377,10 +379,10 @@ void initKey(const shared_ptr &key, const EVP_CIPHER *_blockCipher, SSL_Cipher::SSL_Cipher(const Interface &iface_, - const Interface &realIface_, - const EVP_CIPHER *blockCipher, - const EVP_CIPHER *streamCipher, - int keySize_) + const Interface &realIface_, + const EVP_CIPHER *blockCipher, + const EVP_CIPHER *streamCipher, + int keySize_) { this->iface = iface_; this->realIface = realIface_; @@ -393,8 +395,8 @@ SSL_Cipher::SSL_Cipher(const Interface &iface_, rAssert(_ivLength <= _keySize); VLOG(1) << "allocated cipher " << iface.name() - << ", keySize " << _keySize - << ", ivlength " << _ivLength; + << ", keySize " << _keySize + << ", ivlength " << _ivLength; // EVP_CIPHER_key_length isn't useful for variable-length ciphers like // Blowfish. Version 1 relied upon it incorrectly. @@ -402,8 +404,8 @@ SSL_Cipher::SSL_Cipher(const Interface &iface_, && iface.major() == 1) { LOG(WARNING) << "Running in backward compatibilty mode for 1.0 - \n" - << "key is really " << EVP_CIPHER_key_length( _blockCipher ) * 8 - << " bits, not " << _keySize * 8; + << "key is really " << EVP_CIPHER_key_length( _blockCipher ) * 8 + << " bits, not " << _keySize * 8; } } @@ -422,10 +424,10 @@ Interface SSL_Cipher::interface() const This algorithm must remain constant for backward compatibility, as this key is used to encipher/decipher the master key. -*/ + */ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength, - int &iterationCount, long desiredDuration, - const byte *salt, int saltLen) + int &iterationCount, long desiredDuration, + const byte *salt, int saltLen) { shared_ptr key( new SSLKey( _keySize, _ivLength) ); @@ -477,7 +479,7 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength) if(bytes != (int)_keySize) { LOG(WARNING) << "newKey: BytesToKey returned " << bytes - << ", expecting " << _keySize << " key bytes"; + << ", expecting " << _keySize << " key bytes"; } } else { @@ -499,7 +501,7 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength) This algorithm can change at any time without affecting backward compatibility. -*/ + */ CipherKey SSL_Cipher::newRandomKey() { const int bufLen = MAX_KEYLENGTH; @@ -531,11 +533,11 @@ CipherKey SSL_Cipher::newRandomKey() /* Compute a 64-bit check value for the data using HMAC. -*/ + */ static uint64_t _checksum_64(SSLKey *key, - const byte *data, - int dataLen, - uint64_t *chainedIV) + const byte *data, + int dataLen, + uint64_t *chainedIV) { rAssert( dataLen > 0 ); Lock lock( key->mutex ); @@ -576,7 +578,7 @@ static uint64_t _checksum_64(SSLKey *key, } bool SSL_Cipher::randomize( byte *buf, int len, - bool strongRandom ) const + bool strongRandom ) const { // to avoid warnings of uninitialized data from valgrind memset(buf, 0, len); @@ -599,7 +601,7 @@ bool SSL_Cipher::randomize( byte *buf, int len, } uint64_t SSL_Cipher::MAC_64( const byte *data, int len, - const CipherKey &key, uint64_t *chainedIV ) const + const CipherKey &key, uint64_t *chainedIV ) const { shared_ptr mk = dynamic_pointer_cast(key); uint64_t tmp = _checksum_64( mk.get(), data, len, chainedIV ); @@ -611,7 +613,7 @@ uint64_t SSL_Cipher::MAC_64( const byte *data, int len, } CipherKey SSL_Cipher::readKey(const byte *data, - const CipherKey &masterKey, bool checkKey) + const CipherKey &masterKey, bool checkKey) { shared_ptr mk = dynamic_pointer_cast(masterKey); rAssert(mk->keySize == _keySize); @@ -638,8 +640,8 @@ CipherKey SSL_Cipher::readKey(const byte *data, if(checksum2 != checksum && checkKey) { VLOG(1) << "checksum mismatch: expected " << checksum - << ", got " << checksum2 - << "on decode of " << _keySize + _ivLength << " bytes"; + << ", got " << checksum2 + << "on decode of " << _keySize + _ivLength << " bytes"; OPENSSL_cleanse(tmpBuf, sizeof(tmpBuf)); return CipherKey(); } @@ -656,7 +658,7 @@ CipherKey SSL_Cipher::readKey(const byte *data, } void SSL_Cipher::writeKey(const CipherKey &ckey, byte *data, - const CipherKey &masterKey) + const CipherKey &masterKey) { shared_ptr key = dynamic_pointer_cast(ckey); rAssert(key->keySize == _keySize); @@ -771,7 +773,7 @@ void SSL_Cipher::setIVec_old(byte *ivec, { unsigned int var1 = 0x060a4011 * seed; unsigned int var2 = 0x0221040d * (seed ^ 0xD3FEA11C); - + memcpy( ivec, IVData(key), _ivLength ); ivec[0] ^= (var1 >> 24) & 0xff; @@ -861,7 +863,7 @@ bool SSL_Cipher::streamEncode(byte *buf, int size, dstLen += tmpLen; LOG_IF(ERROR, dstLen != size) << "encoding " << size - << " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; + << " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; return true; } @@ -897,7 +899,7 @@ bool SSL_Cipher::streamDecode(byte *buf, int size, dstLen += tmpLen; LOG_IF(ERROR, dstLen != size) << "encoding " << size - << " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; + << " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; return true; } @@ -928,7 +930,7 @@ bool SSL_Cipher::blockEncode(byte *buf, int size, dstLen += tmpLen; LOG_IF(ERROR, dstLen != size) << "encoding " << size - << " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; + << " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; return true; } @@ -958,7 +960,7 @@ bool SSL_Cipher::blockDecode(byte *buf, int size, dstLen += tmpLen; LOG_IF(ERROR, dstLen != size) << "decoding " << size - << " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; + << " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; return true; } diff --git a/cipher/StreamCipher.cpp b/cipher/StreamCipher.cpp new file mode 100644 index 0000000..c12e31a --- /dev/null +++ b/cipher/StreamCipher.cpp @@ -0,0 +1,20 @@ +#include "cipher/StreamCipher.h" + +namespace encfs { + +Registry& StreamCipher::GetRegistry() +{ + static Registry registry; + return registry; +} + +StreamCipher::StreamCipher() +{ +} + +StreamCipher::~StreamCipher() +{ +} + +} // namespace encfs + diff --git a/cipher/StreamCipher.h b/cipher/StreamCipher.h new file mode 100644 index 0000000..6efb6e0 --- /dev/null +++ b/cipher/StreamCipher.h @@ -0,0 +1,60 @@ + +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2013 Valient Gough + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef _STREAMCIPHER_incl_ +#define _STREAMCIPHER_incl_ + +#include "base/Range.h" +#include "base/Registry.h" +#include "base/shared_ptr.h" +#include "base/types.h" + +namespace encfs { + +class StreamCipher +{ + public: + static Registry& GetRegistry(); + + struct Properties { + Range keySize; + std::string cipher; + std::string mode; + std::string library; + }; + + StreamCipher(); + virtual ~StreamCipher(); + + virtual bool setKey(const byte *key, int keyLength) =0; + virtual bool randomKey(int keyLength) =0; + + virtual bool encrypt(const byte *iv, const byte *in, + byte *out, int numBytes) =0; + virtual bool decrypt(const byte *iv, const byte *in, + byte *out, int numBytes) =0; +}; + +} // namespace encfs + + +#endif + diff --git a/cipher/openssl.cpp b/cipher/openssl.cpp index f38e4b0..9ec2982 100644 --- a/cipher/openssl.cpp +++ b/cipher/openssl.cpp @@ -2,7 +2,7 @@ * Author: Valient Gough * ***************************************************************************** - * Copyright (c) 2007, Valient Gough + * Copyright (c) 2007-2013, Valient Gough * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the @@ -20,10 +20,16 @@ #include "cipher/openssl.h" +#include +#include #include +#include +#include #include +#include "base/config.h" + #define NO_DES #include #include @@ -31,8 +37,345 @@ #include #endif +#include +#include +#include +#include +#include + +#include "base/Error.h" +#include "base/i18n.h" +#include "base/Mutex.h" +#include "base/Range.h" + +#include "cipher/BlockCipher.h" +#include "cipher/MAC.h" +#include "cipher/MemoryPool.h" +#include "cipher/PBKDF.h" +#include "cipher/StreamCipher.h" + +using namespace std; + namespace encfs { +const int MAX_KEYLENGTH = 64; // in bytes (256 bit) +const int MAX_IVLENGTH = 16; +const int KEY_CHECKSUM_BYTES = 4; + +#ifndef MIN +inline int MIN(int a, int b) +{ + return (a < b) ? a : b; +} +#endif + + +// Base for {Block,Stream}Cipher implementation. +class OpenSSLCipher : public BlockCipher { + public: + OpenSSLCipher() { + } + + virtual ~OpenSSLCipher() { + EVP_CIPHER_CTX_cleanup( &enc ); + EVP_CIPHER_CTX_cleanup( &dec ); + } + + bool rekey(const EVP_CIPHER *cipher, const byte *key, int length) { + EVP_CIPHER_CTX_init( &enc ); + EVP_EncryptInit_ex( &enc, cipher, NULL, NULL, NULL); + EVP_CIPHER_CTX_set_key_length( &enc, length ); + EVP_CIPHER_CTX_set_padding( &enc, 0 ); + EVP_EncryptInit_ex( &enc, NULL, NULL, key, NULL); + + EVP_CIPHER_CTX_init( &dec ); + EVP_DecryptInit_ex( &dec, cipher, NULL, NULL, NULL); + EVP_CIPHER_CTX_set_key_length( &dec, length ); + EVP_CIPHER_CTX_set_padding( &dec, 0 ); + EVP_DecryptInit_ex( &dec, NULL, NULL, key, NULL); + return true; + } + + static bool randomize(byte *out, int len) { + int result = RAND_bytes( out, len ); + if(result != 1) + { + char errStr[120]; // specs require string at least 120 bytes long.. + unsigned long errVal = 0; + if((errVal = ERR_get_error()) != 0) + LOG(ERROR) << "openssl error: " << ERR_error_string( errVal, errStr ); + + return false; + } + return true; + } + + // Rekey with random key. + bool rekey(const EVP_CIPHER *cipher, int keyLength) { + SecureMem key(keyLength); + + if (!randomize(key.data, key.size)) + return false; + + return rekey(cipher, key.data, key.size); + } + + virtual int blockSize() const { + return EVP_CIPHER_CTX_block_size(&enc); + } + + virtual bool encrypt(const byte *ivec, const byte *in, + byte *out, int size) { + int dstLen = 0, tmpLen = 0; + EVP_EncryptInit_ex( &enc, NULL, NULL, NULL, ivec); + EVP_EncryptUpdate( &enc, out, &dstLen, in, size); + EVP_EncryptFinal_ex( &enc, out+dstLen, &tmpLen ); + dstLen += tmpLen; + + if (dstLen != size) { + LOG(ERROR) << "encoding " << size + << " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; + return false; + } + + return true; + } + + virtual bool decrypt(const byte *ivec, const byte *in, + byte *out, int size) { + int dstLen = 0, tmpLen = 0; + EVP_DecryptInit_ex( &dec, NULL, NULL, NULL, ivec); + EVP_DecryptUpdate( &dec, out, &dstLen, in, size ); + EVP_DecryptFinal_ex( &dec, out+dstLen, &tmpLen ); + dstLen += tmpLen; + + if (dstLen != size) { + LOG(ERROR) << "decoding " << size + << " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; + return false; + } + + return true; + } + + private: + EVP_CIPHER_CTX enc; + EVP_CIPHER_CTX dec; +}; + + +#if defined(HAVE_EVP_BF) +static Range BfKeyRange(128,256,32); +class BfCbcBlockCipher : public OpenSSLCipher { + public: + BfCbcBlockCipher() {} + virtual ~BfCbcBlockCipher() {} + + virtual bool setKey(const byte *key, int length) { + if (BfKeyRange.allowed(length * 8)) + return rekey(EVP_bf_cbc(), key, length); + else + return false; + } + + virtual bool randomKey(int length) { + return BfKeyRange.allowed(length * 8) && rekey(EVP_bf_cbc(), length); + } + + static Properties GetProperties() { + Properties props; + props.keySize = BfKeyRange; + props.cipher = "Blowfish"; + props.mode = "CBC"; + props.library = "OpenSSL"; + return props; + } +}; +REGISTER_CLASS(BfCbcBlockCipher, BlockCipher); + +class BfCfbStreamCipher : public OpenSSLCipher { + public: + BfCfbStreamCipher() {} + virtual ~BfCfbStreamCipher() {} + + virtual bool setKey(const byte *key, int length) { + return BfKeyRange.allowed(length * 8) && rekey(EVP_bf_cfb(), key, length); + } + + virtual bool randomKey(int length) { + return BfKeyRange.allowed(length * 8) && rekey(EVP_bf_cfb(), length); + } + + static Properties GetProperties() { + Properties props; + props.keySize = BfKeyRange; + props.cipher = "Blowfish"; + props.mode = "CFB"; + props.library = "OpenSSL"; + return props; + } +}; +REGISTER_CLASS(BfCfbStreamCipher, StreamCipher); +#endif + + +#if defined(HAVE_EVP_AES) +static Range AesKeyRange(128,256,64); +class AesCbcBlockCipher : public OpenSSLCipher { + public: + AesCbcBlockCipher() {} + virtual ~AesCbcBlockCipher() {} + + virtual bool setKey(const byte *key, int length) { + const EVP_CIPHER *cipher = getCipher(length); + return (cipher != NULL) && rekey(cipher, key, length); + } + + virtual bool randomKey(int length) { + const EVP_CIPHER *cipher = getCipher(length); + return (cipher != NULL) && rekey(cipher, length); + } + + static const EVP_CIPHER *getCipher(int keyLength) { + switch(keyLength * 8) + { + case 128: return EVP_aes_128_cbc(); + case 192: return EVP_aes_192_cbc(); + case 256: return EVP_aes_256_cbc(); + default: + return NULL; + } + } + + static Properties GetProperties() { + Properties props; + props.keySize = AesKeyRange; + props.cipher = "AES"; + props.mode = "CBC"; + props.library = "OpenSSL"; + return props; + } +}; +REGISTER_CLASS(AesCbcBlockCipher, BlockCipher); +#endif + +#if defined(HAVE_EVP_AES_XTS) +static Range AesXtsKeyRange(128,256,128); +class AesXtsBlockCipher : public OpenSSLCipher { + public: + AesXtsBlockCipher() {} + virtual ~AesXtsBlockCipher() {} + + virtual bool setKey(const byte *key, int length) { + const EVP_CIPHER *cipher = getCipher(length); + return (cipher != NULL) && rekey(cipher, key, length); + } + + virtual bool randomKey(int length) { + const EVP_CIPHER *cipher = getCipher(length); + return (cipher != NULL) && rekey(cipher, length); + } + + static const EVP_CIPHER *getCipher(int keyLength) { + switch(keyLength * 8) + { + case 128: return EVP_aes_128_xts(); + case 256: return EVP_aes_256_xts(); + default: return NULL; + } + } + + static Properties GetProperties() { + Properties props; + props.keySize = AesXtsKeyRange; + props.cipher = "AES"; + props.mode = "XTS"; + props.library = "OpenSSL"; + return props; + } +}; +REGISTER_CLASS(AesXtsBlockCipher, BlockCipher); +#endif + +class Sha1HMac : public MessageAuthenticationCode { + public: + Sha1HMac() {} + virtual ~Sha1HMac() { + HMAC_CTX_cleanup(&ctx); + } + + virtual int outputSize() const { + return 20; // 160 bit. + } + + virtual bool setKey(const byte *key, int keyLength) { + HMAC_CTX_init(&ctx); + HMAC_Init_ex(&ctx, key, keyLength, EVP_sha1(), 0); + return true; + } + + virtual bool randomKey(int keyLength) { + SecureMem key(keyLength); + + return OpenSSLCipher::randomize(key.data, key.size) + && setKey(key.data, key.size); + } + + virtual void reset() { + HMAC_Init_ex(&ctx, 0, 0, 0, 0); + } + + virtual bool update(const byte *in, int length) { + HMAC_Update(&ctx, in, length); + return true; + } + + virtual bool write(byte *out) { + unsigned int outSize = 0; + HMAC_Final(&ctx, (unsigned char *)out, &outSize); + CHECK_EQ(outputSize(), outSize) << "Invalid HMAC output size"; + return true; + } + + static Properties GetProperties() { + Properties props; + props.blockSize = 20; + props.hashFunction = "SHA-1"; + props.mode = "HMAC"; + props.library = "OpenSSL"; + return props; + } + private: + HMAC_CTX ctx; +}; +REGISTER_CLASS(Sha1HMac, MessageAuthenticationCode); + + +class PbkdfPkcs5HmacSha1 : public PBKDF { + public: + PbkdfPkcs5HmacSha1() {} + virtual ~PbkdfPkcs5HmacSha1() {} + + virtual bool makeKey(const char *password, int passwordLength, + const byte *salt, int saltLength, + int numIterations, + byte *outKey, int keyLength) const { + return PKCS5_PBKDF2_HMAC_SHA1( + password, passwordLength, + const_cast(salt), saltLength, + numIterations, keyLength, outKey) == 1; + } + + static Properties GetProperties() { + Properties props; + props.mode = "PKCS5_PBKDF2_HMAC_SHA1"; + props.library = "OpenSSL"; + return props; + } +}; +REGISTER_CLASS(PbkdfPkcs5HmacSha1, PBKDF); + + unsigned long pthreads_thread_id() { return (unsigned long)pthread_self(); @@ -73,7 +416,7 @@ void pthreads_locking_cleanup() } } -void openssl_init(bool threaded) +void OpenSSL::init(bool threaded) { // initialize the SSL library SSL_load_error_strings(); @@ -99,7 +442,7 @@ void openssl_init(bool threaded) } } -void openssl_shutdown(bool threaded) +void OpenSSL::shutdown(bool threaded) { #ifndef OPENSSL_NO_ENGINE ENGINE_cleanup(); @@ -109,4 +452,10 @@ void openssl_shutdown(bool threaded) pthreads_locking_cleanup(); } +void OpenSSL::registerCiphers() +{ + // Nothing required.. Just need to reference this code block to get static + // initializers. +} + } // namespace encfs diff --git a/cipher/openssl.h b/cipher/openssl.h index c021c48..b38506e 100644 --- a/cipher/openssl.h +++ b/cipher/openssl.h @@ -21,10 +21,17 @@ #ifndef _openssl_incl_ #define _openssl_incl_ +#include "base/Registry.h" + namespace encfs { -void openssl_init(bool isThreaded); -void openssl_shutdown(bool isThreaded); +class OpenSSL { + public: + static void init(bool isThreaded); + static void shutdown(bool isThreaded); + + static void registerCiphers(); +}; } // namespace encfs diff --git a/cipher/testing.cpp b/cipher/testing.cpp new file mode 100644 index 0000000..0af7ce1 --- /dev/null +++ b/cipher/testing.cpp @@ -0,0 +1,30 @@ + +#include + +#include "cipher/testing.h" + +namespace encfs { + +std::string stringToHex(const byte *data, int len) { + static const char lookup[] = "0123456789abcdef"; + + std::string out; + out.reserve(2 * len); + for (int i = 0; i < len; ++i) { + unsigned int c = (unsigned int)data[i] & 0xff; + int first = (unsigned int)c >> 4; + int second = (unsigned int)c & 15; + + out.push_back(lookup[first]); + out.push_back(lookup[second]); + } + return out; +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + +} // namespace encfs + diff --git a/cipher/testing.h b/cipher/testing.h new file mode 100644 index 0000000..a2aa9ad --- /dev/null +++ b/cipher/testing.h @@ -0,0 +1,36 @@ + +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2013 Valient Gough + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef _CIPHER_TESTING_incl_ +#define _CIPHER_TESTING_incl_ + +#include + +#include "base/types.h" + +namespace encfs { + +std::string stringToHex(const byte *data, int len); + +} // namespace encfs + +#endif + diff --git a/encfs/CMakeLists.txt b/encfs/CMakeLists.txt index ef21be2..458e52a 100644 --- a/encfs/CMakeLists.txt +++ b/encfs/CMakeLists.txt @@ -8,10 +8,6 @@ link_directories (${Encfs_BINARY_DIR}/cipher) include_directories (${Encfs_SOURCE_DIR}/fs) link_directories (${Encfs_BINARY_DIR}/fs) -# TODO: move FUSE code into encfs-fs. -find_package (FUSE REQUIRED) -include_directories (${FUSE_INCLUDE_DIR}) - include_directories (${CMAKE_BINARY_DIR}/base) add_executable (encfs diff --git a/encfs/main.cpp b/encfs/main.cpp index f331baa..64ce2d2 100644 --- a/encfs/main.cpp +++ b/encfs/main.cpp @@ -578,7 +578,7 @@ int main(int argc, char *argv[]) // encfs_oper.fsetattr_x #endif - openssl_init( encfsArgs->isThreaded ); + OpenSSL::init( encfsArgs->isThreaded ); // context is not a smart pointer because it will live for the life of // the filesystem. @@ -671,7 +671,7 @@ int main(int argc, char *argv[]) ctx->setRoot( shared_ptr() ); MemoryPool::destroyAll(); - openssl_shutdown( encfsArgs->isThreaded ); + OpenSSL::shutdown( encfsArgs->isThreaded ); return returnCode; } diff --git a/fs/CMakeLists.txt b/fs/CMakeLists.txt index 2b64e50..ae6b86c 100644 --- a/fs/CMakeLists.txt +++ b/fs/CMakeLists.txt @@ -1,12 +1,6 @@ -find_package (FUSE REQUIRED) -include_directories (${FUSE_INCLUDE_DIR}) +protobuf_generate_cpp (PROTO_SRCS PROTO_HDRS ${PROJECT_SOURCE_DIR}/protos/fsconfig.proto) -protobuf_generate_cpp (PROTO_SRCS PROTO_HDRS ${Encfs_SOURCE_DIR}/protos/fsconfig.proto) - -enable_testing () -find_package (GTest) - -include_directories (${Encfs_BINARY_DIR}/base) +include_directories (${PROJECT_BINARY_DIR}/base) add_library (encfs-fs encfs.cpp Context.cpp @@ -32,11 +26,11 @@ target_link_libraries (encfs-fs # Unit tests are optional, depends on libgtest (Google's C++ test framework). if (GTEST_FOUND) - link_directories (${Encfs_BINARY_DIR}/base) - link_directories (${Encfs_BINARY_DIR}/cipher) + link_directories (${PROJECT_BINARY_DIR}/base) + link_directories (${PROJECT_BINARY_DIR}/cipher) include_directories (${GTEST_INCLUDE_DIR}) - add_executable (unittests + add_executable (fs-tests MemBlockFileIO.cpp MemFileIO.cpp testing.cpp @@ -44,7 +38,7 @@ if (GTEST_FOUND) test_BlockIO.cpp ) - target_link_libraries (unittests + target_link_libraries (fs-tests ${GTEST_BOTH_LIBRARIES} encfs-fs encfs-cipher @@ -52,8 +46,6 @@ if (GTEST_FOUND) ${GLOG_LIBRARIES} ) - add_test (UnitTests unittests) - GTEST_ADD_TESTS (unittests "${UnitTestArgs}" test_IO.cpp test_BlockIO.cpp) - add_custom_target (test COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS unittests) - + add_test (FSTests fs-tests) + GTEST_ADD_TESTS (fs-tests "${FSTestArgs}" test_IO.cpp test_BlockIO.cpp) endif (GTEST_FOUND) diff --git a/fs/FileUtils.cpp b/fs/FileUtils.cpp index b8a5a34..d47b8c0 100644 --- a/fs/FileUtils.cpp +++ b/fs/FileUtils.cpp @@ -1349,7 +1349,7 @@ std::string readPassword( int FD ) if(rdSize > 0) { - result.append( buf->data, rdSize ); + result.append( (char*)buf->data, rdSize ); } else break; } @@ -1436,7 +1436,7 @@ SecureMem *passwordFromProgram(const std::string &passProg, SecureMem *result = new SecureMem(password.length()+1); if (result) - strncpy(result->data, password.c_str(), result->size); + strncpy((char *)result->data, password.c_str(), result->size); password.assign(password.length(), '\0'); return result; @@ -1446,11 +1446,11 @@ SecureMem *passwordFromStdin() { SecureMem *buf = new SecureMem(MaxPassBuf); - char *res = fgets( buf->data, buf->size, stdin ); + char *res = fgets( (char *)buf->data, buf->size, stdin ); if (res) { // Kill the trailing newline. - int last = strnlen(buf->data, buf->size); + int last = strnlen((char *)buf->data, buf->size); if (last > 0 && buf->data[last-1] == '\n') buf->data[ last-1 ] = '\0'; } @@ -1464,7 +1464,7 @@ SecureMem *passwordFromPrompt() // xgroup(common) char *res = readpassphrase( _("EncFS Password: "), - buf->data, buf->size-1, RPP_ECHO_OFF ); + (char *)buf->data, buf->size-1, RPP_ECHO_OFF ); if (!res) { delete buf; @@ -1483,12 +1483,13 @@ SecureMem *passwordFromPrompts() { // xgroup(common) char *res1 = readpassphrase(_("New Encfs Password: "), - buf->data, buf->size-1, RPP_ECHO_OFF); + (char *)buf->data, buf->size-1, RPP_ECHO_OFF); // xgroup(common) char *res2 = readpassphrase(_("Verify Encfs Password: "), - buf2->data, buf2->size-1, RPP_ECHO_OFF); + (char *)buf2->data, buf2->size-1, RPP_ECHO_OFF); - if(res1 && res2 && !strncmp(buf->data, buf2->data, MaxPassBuf)) + if(res1 && res2 + && !strncmp((char*)buf->data, (char*)buf2->data, MaxPassBuf)) { break; } else @@ -1514,7 +1515,8 @@ CipherKey getUserKey(const EncfsConfig &config, bool useStdin) if (password) { - userKey = decryptKey(config, password->data, strlen(password->data)); + userKey = decryptKey(config, (char*)password->data, + strlen((char*)password->data)); delete password; } @@ -1529,7 +1531,8 @@ CipherKey getUserKey( const EncfsConfig &config, const std::string &passProg, if (password) { - result = decryptKey(config, password->data, strlen(password->data)); + result = decryptKey(config, (char*)password->data, + strlen((char*)password->data)); delete password; } @@ -1552,7 +1555,8 @@ CipherKey getNewUserKey(EncfsConfig &config, if (password) { - result = makeNewKey(config, password->data, strlen(password->data)); + result = makeNewKey(config, (char*)password->data, + strlen((char*)password->data)); delete password; } diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index e362709..6bdfde1 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -8,10 +8,6 @@ link_directories (${Encfs_BINARY_DIR}/cipher) include_directories (${Encfs_SOURCE_DIR}/fs) link_directories (${Encfs_BINARY_DIR}/fs) -# TODO: move FUSE code into encfs-fs. -find_package (FUSE REQUIRED) -include_directories (${FUSE_INCLUDE_DIR}) - include_directories (${CMAKE_BINARY_DIR}/base) diff --git a/util/encfsctl.cpp b/util/encfsctl.cpp index 1357fc8..6b46b1b 100644 --- a/util/encfsctl.cpp +++ b/util/encfsctl.cpp @@ -24,6 +24,9 @@ #include "base/i18n.h" #include "cipher/Cipher.h" +#include "cipher/BlockCipher.h" +#include "cipher/MAC.h" +#include "cipher/StreamCipher.h" #include "fs/FileUtils.h" #include "fs/Context.h" @@ -35,6 +38,7 @@ #include #include #include +#include #include #include @@ -52,6 +56,7 @@ using namespace encfs; static int showInfo( int argc, char **argv ); static int showVersion( int argc, char **argv ); +static int showCiphers( int argc, char **argv ); static int chpasswd( int argc, char **argv ); static int chpasswdAutomaticly( int argc, char **argv ); static int cmd_ls( int argc, char **argv ); @@ -101,6 +106,9 @@ struct CommandOpts {"export", 2, 2, cmd_export, "(root dir) path", // xgroup(usage) gettext_noop(" -- decrypts a volume and writes results to path")}, + {"--ciphers", 0, 0, showCiphers, "", + // xgroup(usage) + gettext_noop(" -- show available ciphers")}, {"--version", 0, 0, showVersion, "", // xgroup(usage) gettext_noop(" -- print version number and exit")}, @@ -140,7 +148,7 @@ static bool checkDir( string &rootDir ) { if( !isDirectory( rootDir.c_str() )) { - cerr << autosprintf(_("directory %s does not exist.\n"), + cout << autosprintf(_("directory %s does not exist.\n"), rootDir.c_str()); return false; } @@ -155,11 +163,45 @@ static int showVersion( int argc, char **argv ) (void)argc; (void)argv; // xgroup(usage) - cerr << autosprintf(_("encfsctl version %s"), VERSION) << "\n"; + cout << autosprintf(_("encfsctl version %s"), VERSION) << "\n"; return EXIT_SUCCESS; } +static int showCiphers( int argc, char **argv ) +{ + (void)argc; + (void)argv; + list names = BlockCipher::GetRegistry().GetAll(); + for (const string& name : names) { + auto props = BlockCipher::GetRegistry().GetProperties(name.c_str()); + cout << _("Implementation: ") << name << "\n"; + cout << "\t" << _("Block cipher: ") << props->cipher << " / " << props->mode + << " ( " << autosprintf(_("via %s"), props->library.c_str()) << " )\n"; + cout << "\t" << _("Key Sizes: ") << props->keySize << "\n"; + } + + names = StreamCipher::GetRegistry().GetAll(); + for (const string& name : names) { + auto props = StreamCipher::GetRegistry().GetProperties(name.c_str()); + cout << _("Implementation: ") << name << "\n"; + cout << "\t" << _("Stream cipher: ") << props->cipher << " / " << props->mode + << " ( " << autosprintf(_("via %s"), props->library.c_str()) << " )\n"; + cout << "\t" << _("Key Sizes: ") << props->keySize << "\n"; + } + + names = MessageAuthenticationCode::GetRegistry().GetAll(); + for (const string& name : names) { + auto props = MessageAuthenticationCode::GetRegistry() + .GetProperties(name.c_str()); + cout << _("Implementation: ") << name << "\n"; + cout << "\t" << _("HMAC: ") << props->hashFunction << " / " << props->mode + << " ( " << autosprintf(_("via %s"), props->library.c_str()) << " )\n"; + cout << "\t" << _("Block size: ") << props->blockSize << "\n"; + } + return EXIT_SUCCESS; +} + static int showInfo( int argc, char **argv ) { (void)argc; @@ -676,7 +718,7 @@ static int cmd_showcruft( int argc, char **argv ) int filesFound = showcruft( rootInfo, "/" ); - cerr << autosprintf("Found %i invalid file(s).", filesFound) << "\n"; + cout << autosprintf("Found %i invalid file(s).", filesFound) << "\n"; return EXIT_SUCCESS; } From 7e95ff90c877784105c18a9ac3c32d834ec87fc6 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Tue, 5 Mar 2013 06:36:32 +0000 Subject: [PATCH 16/51] encapsulate old cipher support layer git-svn-id: http://encfs.googlecode.com/svn/trunk@95 db9cf616-1c43-0410-9cb8-a902689de0d6 --- CMakeLists.txt | 3 + base/Mutex.h | 50 +- base/Registry.h | 17 +- base/config.h.cmake | 5 +- cipher/BlockCipher.cpp | 2 + cipher/BlockCipher.h | 7 +- cipher/BlockCipher_test.cpp | 136 ++-- cipher/CMakeLists.txt | 5 +- cipher/Cipher.cpp | 230 ------- cipher/Cipher.h | 165 ----- cipher/CipherKey.cpp | 79 ++- cipher/CipherKey.h | 32 +- cipher/CipherV1.cpp | 668 +++++++++++++++++++ cipher/{SSL_Cipher.h => CipherV1.h} | 174 ++--- cipher/MAC.cpp | 6 +- cipher/MAC.h | 16 +- cipher/MAC_test.cpp | 29 +- cipher/MemoryPool.h | 5 +- cipher/NullCipher.cpp | 183 ------ cipher/NullCipher.h | 89 --- cipher/NullCiphers.cpp | 73 +++ cipher/NullCiphers.h | 37 ++ cipher/PBKDF.h | 14 +- cipher/PBKDF_test.cpp | 25 +- cipher/SSL_Cipher.cpp | 978 ---------------------------- cipher/StreamCipher.cpp | 6 +- cipher/StreamCipher.h | 12 +- cipher/openssl.cpp | 155 +++-- cipher/testing.cpp | 35 +- cipher/testing.h | 7 + encfs/main.cpp | 18 +- fs/BlockNameIO.cpp | 29 +- fs/BlockNameIO.h | 47 +- fs/CipherFileIO.cpp | 96 +-- fs/CipherFileIO.h | 5 +- fs/Context.cpp | 12 +- fs/Context.h | 98 +-- fs/DirNode.cpp | 4 - fs/DirNode.h | 3 +- fs/FSConfig.h | 8 +- fs/FileNode.cpp | 6 - fs/FileNode.h | 3 +- fs/FileUtils.cpp | 131 ++-- fs/FileUtils.h | 4 +- fs/MACFileIO.cpp | 7 +- fs/MACFileIO.h | 5 +- fs/NameIO.cpp | 12 +- fs/NameIO.h | 152 +++-- fs/NullNameIO.cpp | 4 +- fs/StreamNameIO.cpp | 22 +- fs/StreamNameIO.h | 9 +- fs/test_BlockIO.cpp | 2 +- fs/test_IO.cpp | 1 - fs/testing.cpp | 15 +- fs/testing.h | 4 +- protos/fsconfig.proto | 3 - util/encfsctl.cpp | 82 ++- 57 files changed, 1705 insertions(+), 2320 deletions(-) delete mode 100644 cipher/Cipher.cpp delete mode 100644 cipher/Cipher.h create mode 100644 cipher/CipherV1.cpp rename cipher/{SSL_Cipher.h => CipherV1.h} (57%) delete mode 100644 cipher/NullCipher.cpp delete mode 100644 cipher/NullCipher.h create mode 100644 cipher/NullCiphers.cpp create mode 100644 cipher/NullCiphers.h delete mode 100644 cipher/SSL_Cipher.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e4764f7..2a3ed14 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,6 +73,9 @@ include_directories (${PROTOBUF_INCLUDE_DIR}) find_package (GLog REQUIRED) include_directories (${GLOG_INCLUDE_DIRS}) +find_package (Threads) + +set (CMAKE_THREAD_PREFER_PTHREAD) find_program (POD2MAN pod2man) find_package (GTest) diff --git a/base/Mutex.h b/base/Mutex.h index 4675af6..7e8df4e 100644 --- a/base/Mutex.h +++ b/base/Mutex.h @@ -21,15 +21,38 @@ #ifndef _Mutex_incl_ #define _Mutex_incl_ +#include "base/config.h" + +#ifdef CMAKE_USE_PTHREADS_INIT #include +#else +#warning No thread support. +#endif namespace encfs { +class Mutex +{ + public: +#ifdef CMAKE_USE_PTHREADS_INIT + pthread_mutex_t _mutex; + Mutex() { + pthread_mutex_init( &_mutex, 0 ); + } + ~Mutex() { + pthread_mutex_destroy( &_mutex ); + } +#endif + + void lock(); + void unlock(); +}; + class Lock { public: - Lock( pthread_mutex_t &mutex ); + explicit Lock( Mutex &mutex ); ~Lock(); // leave the lock as it is. When the Lock wrapper is destroyed, it @@ -40,24 +63,39 @@ private: Lock(const Lock &src); // not allowed Lock &operator = (const Lock &src); // not allowed - pthread_mutex_t *_mutex; + Mutex *_mutex; }; -inline Lock::Lock( pthread_mutex_t &mutex ) +inline void Mutex::lock() +{ +#ifdef CMAKE_USE_PTHREADS_INIT + pthread_mutex_lock( &_mutex ); +#endif +} + +inline void Mutex::unlock() +{ +#ifdef CMAKE_USE_PTHREADS_INIT + pthread_mutex_unlock( &_mutex ); +#endif +} + +inline Lock::Lock( Mutex &mutex ) : _mutex( &mutex ) { - pthread_mutex_lock( _mutex ); + if (_mutex) + _mutex->lock(); } inline Lock::~Lock( ) { if(_mutex) - pthread_mutex_unlock( _mutex ); + _mutex->unlock(); } inline void Lock::leave() { - _mutex = 0; + _mutex = NULL; } } // namespace encfs diff --git a/base/Registry.h b/base/Registry.h index 49c66c7..e9182d1 100644 --- a/base/Registry.h +++ b/base/Registry.h @@ -3,6 +3,7 @@ #include #include +#include namespace encfs { @@ -36,7 +37,8 @@ public: T* CreateForMatch(const std::string &description) { for (auto &it : data) { - if (description == it.second.properties.toString()) + auto name = it.second.properties.toString(); + if (!name.compare(0, description.size(), description)) return (*it.second.constructor)(); } return NULL; @@ -56,6 +58,17 @@ public: return NULL; return &(it->second.properties); } + + const typename T::Properties *GetPropertiesForMatch( + const std::string &description) const { + for (auto &it : data) { + auto name = it.second.properties.toString(); + if (!name.compare(0, description.size(), description)) + return &(it.second.properties); + } + return NULL; + } + private: std::map data; @@ -87,7 +100,7 @@ public: } #define REGISTER_CLASS(DERIVED, BASE) \ - static Registrar registrar_##DERIVED(#DERIVED) + static Registrar registrar_ ## DERIVED ## _ ## BASE (#DERIVED) } // namespace encfs diff --git a/base/config.h.cmake b/base/config.h.cmake index b9834f2..748bd61 100644 --- a/base/config.h.cmake +++ b/base/config.h.cmake @@ -1,3 +1,5 @@ +#define VERSION "@ENCFS_VERSION@" + #cmakedefine HAVE_ATTR_XATTR_H #cmakedefine HAVE_SYS_XATTR_H #cmakedefine XATTR_ADD_OPT @@ -15,5 +17,6 @@ #cmakedefine HAVE_VALGRIND_VALGRIND_H #cmakedefine HAVE_VALGRIND_MEMCHECK_H -#define VERSION "@ENCFS_VERSION@" +/* TODO: add other thread library support. */ +#cmakedefine CMAKE_USE_PTHREADS_INIT diff --git a/cipher/BlockCipher.cpp b/cipher/BlockCipher.cpp index 3bc9d15..75305c6 100644 --- a/cipher/BlockCipher.cpp +++ b/cipher/BlockCipher.cpp @@ -2,6 +2,7 @@ // TODO: add ifdef when OpenSSL becomes optional. #include "cipher/openssl.h" +#include "cipher/NullCiphers.h" namespace encfs { @@ -12,6 +13,7 @@ Registry& BlockCipher::GetRegistry() if (first) { OpenSSL::registerCiphers(); + NullCiphers::registerCiphers(); first = false; } return registry; diff --git a/cipher/BlockCipher.h b/cipher/BlockCipher.h index 7f853dc..f920a9c 100644 --- a/cipher/BlockCipher.h +++ b/cipher/BlockCipher.h @@ -10,16 +10,21 @@ namespace encfs { +static const char NAME_AES_CBC[] = "AES/CBC"; +static const char NAME_BLOWFISH_CBC[] = "Blowfish/CBC"; + // BlockCipher is a StreamCipher with a block size. // Encryption and decryption must be in multiples of the block size. class BlockCipher : public StreamCipher { public: - static Registry& GetRegistry(); + DECLARE_REGISTERABLE_TYPE(BlockCipher); BlockCipher(); virtual ~BlockCipher(); + // Not valid until a key has been set, as they key size may determine the + // block size. virtual int blockSize() const =0; }; diff --git a/cipher/BlockCipher_test.cpp b/cipher/BlockCipher_test.cpp index 724d8f0..8cf89f9 100644 --- a/cipher/BlockCipher_test.cpp +++ b/cipher/BlockCipher_test.cpp @@ -26,6 +26,8 @@ #include "base/shared_ptr.h" #include "cipher/BlockCipher.h" #include "cipher/MemoryPool.h" +#include "cipher/PBKDF.h" +#include "cipher/testing.h" using namespace encfs; using std::list; @@ -34,62 +36,112 @@ using std::string; namespace { void compare(const byte *a, const byte *b, int size) { - for (int i = 0; i < size; i++) { - bool match = (a[i] == b[i]); - ASSERT_TRUE(match) << "mismatched data at offset " << i - << " of " << size; - if (!match) - break; - } + for (int i = 0; i < size; i++) { + bool match = (a[i] == b[i]); + ASSERT_TRUE(match) << "mismatched data at offset " << i + << " of " << size; + if (!match) + break; + } +} + +TEST(RequiredBlockCiphers, BlockCipher) { + auto aes_cbc = BlockCipher::GetRegistry().CreateForMatch(NAME_AES_CBC); + ASSERT_TRUE(aes_cbc != NULL); + + auto bf_cbc = BlockCipher::GetRegistry().CreateForMatch(NAME_BLOWFISH_CBC); + ASSERT_TRUE(bf_cbc != NULL); +} + +TEST(RequiredStreamCiphers, StreamCipher) { + auto aes_cfb = StreamCipher::GetRegistry().CreateForMatch(NAME_AES_CFB); + ASSERT_TRUE(aes_cfb != NULL); + + auto bf_cfb = StreamCipher::GetRegistry().CreateForMatch(NAME_BLOWFISH_CFB); + ASSERT_TRUE(bf_cfb != NULL); +} + +TEST(BlowfishTestVector, BlockCihper) { + auto cbc = BlockCipher::GetRegistry().CreateForMatch(NAME_BLOWFISH_CBC); + auto cfb = StreamCipher::GetRegistry().CreateForMatch(NAME_BLOWFISH_CFB); + + CipherKey key(16); + setDataFromHex(key.data(), key.size(), "0123456789abcdeff0e1d2c3b4a59687"); + cbc->setKey(key); + cfb->setKey(key); + + byte iv[8]; + setDataFromHex(iv, 8, "fedcba9876543210"); + + byte data[32]; + setDataFromHex(data, 32, + "37363534333231204e6f77206973207468652074696d6520666f722000000000"); + + byte cipherData[32]; + cbc->encrypt(iv, data, cipherData, 32); + + ASSERT_EQ("6b77b4d63006dee605b156e27403979358deb9e7154616d959f1652bd5ff92cc", + stringToHex(cipherData, 32)); + + cfb->encrypt(iv, data, cipherData, 29); + ASSERT_EQ("e73214a2822139caf26ecf6d2eb9e76e3da3de04d1517200519d57a6c3", + stringToHex(cipherData, 29)); } TEST(BlockEncryptionTest, BlockCipher) { - Registry registry = BlockCipher::GetRegistry(); - list ciphers = registry.GetAll(); - for (const string &name : ciphers) { - const BlockCipher::Properties *properties = registry.GetProperties(name.c_str()); - SCOPED_TRACE(testing::Message() << "Cipher " << name); + Registry registry = BlockCipher::GetRegistry(); - for (int keySize = properties->keySize.min(); - keySize <= properties->keySize.max(); - keySize += properties->keySize.inc()) { - SCOPED_TRACE(testing::Message() << "Key size " << keySize); + shared_ptr pbkdf( + PBKDF::GetRegistry().CreateForMatch(NAME_PKCS5_PBKDF2_HMAC_SHA1)); - shared_ptr cipher (registry.Create(name.c_str())); + list ciphers = registry.GetAll(); + for (const string &name : ciphers) { + const BlockCipher::Properties *properties = + registry.GetProperties(name.c_str()); + SCOPED_TRACE(testing::Message() << "Cipher " << name); - ASSERT_TRUE(cipher->randomKey(keySize / 8)); + for (int keySize = properties->keySize.min(); + keySize <= properties->keySize.max(); + keySize += properties->keySize.inc()) { + SCOPED_TRACE(testing::Message() << "Key size " << keySize); - // Create some data to encrypt. - int blockSize = cipher->blockSize(); - MemBlock mb; - mb.allocate(16 * blockSize); + shared_ptr cipher (registry.Create(name.c_str())); - for (int i = 0; i < 16 * blockSize; i++) { - mb.data[i] = i % 256; - } + CipherKey key = pbkdf->randomKey(keySize / 8); + ASSERT_TRUE(key.valid()); + cipher->setKey(key); - MemBlock iv; - iv.allocate(blockSize); - for (int i = 0; i < blockSize; i++) { - iv.data[i] = i; - } + // Create some data to encrypt. + int blockSize = cipher->blockSize(); + MemBlock mb; + mb.allocate(16 * blockSize); - // Encrypt. - MemBlock encrypted; - encrypted.allocate(16 * blockSize); + for (int i = 0; i < 16 * blockSize; i++) { + mb.data[i] = i % 256; + } - ASSERT_TRUE(cipher->encrypt(iv.data, mb.data, - encrypted.data, 16 * blockSize)); + MemBlock iv; + iv.allocate(blockSize); + for (int i = 0; i < blockSize; i++) { + iv.data[i] = i; + } - // Decrypt. - MemBlock decrypted; - decrypted.allocate(16 * blockSize); - ASSERT_TRUE(cipher->decrypt(iv.data, encrypted.data, - decrypted.data, 16 * blockSize)); + // Encrypt. + MemBlock encrypted; + encrypted.allocate(16 * blockSize); - compare(mb.data, decrypted.data, 16 * blockSize); - } + ASSERT_TRUE(cipher->encrypt(iv.data, mb.data, + encrypted.data, 16 * blockSize)); + + // Decrypt. + MemBlock decrypted; + decrypted.allocate(16 * blockSize); + ASSERT_TRUE(cipher->decrypt(iv.data, encrypted.data, + decrypted.data, 16 * blockSize)); + + compare(mb.data, decrypted.data, 16 * blockSize); } + } } } // namespace diff --git a/cipher/CMakeLists.txt b/cipher/CMakeLists.txt index f586f46..f00a2c4 100644 --- a/cipher/CMakeLists.txt +++ b/cipher/CMakeLists.txt @@ -4,15 +4,14 @@ link_directories (${Encfs_BINARY_DIR}/base) add_library (encfs-cipher BlockCipher.cpp - Cipher.cpp CipherKey.cpp + CipherV1.cpp MAC.cpp MemoryPool.cpp - NullCipher.cpp + NullCiphers.cpp openssl.cpp PBKDF.cpp readpassphrase.cpp - SSL_Cipher.cpp StreamCipher.cpp ) diff --git a/cipher/Cipher.cpp b/cipher/Cipher.cpp deleted file mode 100644 index b84684e..0000000 --- a/cipher/Cipher.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2002-2004, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include "base/config.h" -#include "cipher/Cipher.h" - -#include -#include -#include -#include - -#include "base/Interface.h" -#include "base/Range.h" -#include "base/base64.h" - -// for static build. Need to reference the modules which are registered at -// run-time, to ensure that the linker doesn't optimize them away. -#include "cipher/NullCipher.h" -#include "cipher/SSL_Cipher.h" - -using namespace std; - -namespace encfs { - -#define REF_MODULE(TYPE) \ - if( !TYPE::Enabled() ) \ - cerr << "referenceModule: should never happen\n"; - -static -void AddSymbolReferences() -{ - REF_MODULE(SSL_Cipher) - REF_MODULE(NullCipher) -} - - -struct CipherAlg -{ - bool hidden; - Cipher::CipherConstructor constructor; - string description; - Interface iface; - Range keyLength; - Range blockSize; - bool hasStreamMode; -}; - -typedef multimap< string, CipherAlg> CipherMap_t; -static CipherMap_t *gCipherMap = NULL; - -std::list -Cipher::GetAlgorithmList( bool includeHidden ) -{ - AddSymbolReferences(); - - list result; - - if(!gCipherMap) - return result; - - CipherMap_t::const_iterator it; - CipherMap_t::const_iterator mapEnd = gCipherMap->end(); - for(it = gCipherMap->begin(); it != mapEnd; ++it) - { - if(includeHidden || !it->second.hidden) - { - CipherAlgorithm tmp; - tmp.name = it->first; - tmp.description = it->second.description; - tmp.iface = it->second.iface; - tmp.keyLength = it->second.keyLength; - tmp.blockSize = it->second.blockSize; - tmp.hasStreamMode = it->second.hasStreamMode; - - result.push_back( tmp ); - } - } - - return result; -} - -bool Cipher::Register(const char *name, const char *description, - const Interface &iface, CipherConstructor fn, - bool hasStreamMode, bool hidden) -{ - Range keyLength(-1,-1,1); - Range blockSize(-1,-1,1); - return Cipher::Register( name, description, iface, - keyLength, blockSize, fn, hasStreamMode, hidden ); -} - -bool Cipher::Register(const char *name, const char *description, - const Interface &iface, const Range &keyLength, - const Range &blockSize, - CipherConstructor fn, - bool hasStreamMode, - bool hidden) -{ - if(!gCipherMap) - gCipherMap = new CipherMap_t; - - CipherAlg ca; - ca.hidden = hidden; - ca.constructor = fn; - ca.description = description; - ca.iface = iface; - ca.keyLength = keyLength; - ca.blockSize = blockSize; - ca.hasStreamMode = hasStreamMode; - - gCipherMap->insert( make_pair(string(name), ca) ); - return true; -} - -shared_ptr Cipher::New(const string &name, int keyLen) -{ - shared_ptr result; - - if(gCipherMap) - { - CipherMap_t::const_iterator it = gCipherMap->find( name ); - if(it != gCipherMap->end()) - { - CipherConstructor fn = it->second.constructor; - // use current interface.. - result = (*fn)( it->second.iface, keyLen ); - } - } - - return result; -} - -shared_ptr Cipher::New( const Interface &iface, int keyLen ) -{ - shared_ptr result; - if(gCipherMap) - { - CipherMap_t::const_iterator it; - CipherMap_t::const_iterator mapEnd = gCipherMap->end(); - - for(it = gCipherMap->begin(); it != mapEnd; ++it) - { - // TODO: we should look for the newest implementation.. - if( implements(it->second.iface, iface) ) - { - CipherConstructor fn = it->second.constructor; - // pass in requested interface.. - result = (*fn)( iface, keyLen ); - - // if we're not going to compare the options, then just stop - // now.. - break; - } - } - } - - return result; -} - -Cipher::Cipher() -{ -} - -Cipher::~Cipher() -{ -} - -unsigned int Cipher::MAC_32( const byte *src, int len, - const CipherKey &key, uint64_t *chainedIV ) const -{ - uint64_t mac64 = MAC_64( src, len, key, chainedIV ); - - unsigned int mac32 = ((mac64 >> 32) & 0xffffffff) ^ (mac64 & 0xffffffff); - - return mac32; -} - -unsigned int Cipher::MAC_16( const byte *src, int len, - const CipherKey &key, uint64_t *chainedIV ) const -{ - uint64_t mac64 = MAC_64( src, len, key, chainedIV ); - - unsigned int mac32 = ((mac64 >> 32) & 0xffffffff) ^ (mac64 & 0xffffffff); - unsigned int mac16 = ((mac32 >> 16) & 0xffff) ^ (mac32 & 0xffff); - - return mac16; -} - -string Cipher::encodeAsString(const CipherKey &key, - const CipherKey &encodingKey ) -{ - int encodedKeySize = this->encodedKeySize(); - byte *keyBuf = new byte[ encodedKeySize ]; - - this->writeKey( key, keyBuf, encodingKey ); - - int b64Len = B256ToB64Bytes( encodedKeySize ); - byte *b64Key = new byte[ b64Len + 1 ]; - - changeBase2( keyBuf, encodedKeySize, 8, b64Key, - b64Len, 6 ); - B64ToAscii( b64Key, b64Len ); - b64Key[ b64Len - 1 ] = '\0'; - - return string( (const char *)b64Key ); -} - -bool Cipher::hasStreamMode() const -{ - return true; -} - -} // namespace encfs diff --git a/cipher/Cipher.h b/cipher/Cipher.h deleted file mode 100644 index 229dffb..0000000 --- a/cipher/Cipher.h +++ /dev/null @@ -1,165 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2002-2003, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#ifndef _Cipher_incl_ -#define _Cipher_incl_ - -#include "cipher/CipherKey.h" -#include "base/Interface.h" -#include "base/Range.h" -#include "base/types.h" - -#include -#include -#include - -namespace encfs { - -/* - Mostly pure virtual interface defining operations on a cipher. - - Cipher's should register themselves so they can be instanciated via - Cipher::New(). -*/ -class Cipher -{ -public: - // if no key length was indicated when cipher was registered, then keyLen - // <= 0 will be used. - typedef shared_ptr (*CipherConstructor)( - const Interface &iface, int keyLenBits ); - - struct CipherAlgorithm - { - std::string name; - std::string description; - Interface iface; - Range keyLength; - Range blockSize; - bool hasStreamMode; - }; - - - typedef std::list AlgorithmList; - static AlgorithmList GetAlgorithmList( bool includeHidden = false ); - - - static shared_ptr New( const Interface &iface, - int keyLen = -1); - static shared_ptr New( const std::string &cipherName, - int keyLen = -1 ); - - - static bool Register(const char *cipherName, - const char *description, - const Interface &iface, - CipherConstructor constructor, - bool hasStreamMode, - bool hidden = false); - - static bool Register(const char *cipherName, - const char *description, - const Interface &iface, - const Range &keyLength, const Range &blockSize, - CipherConstructor constructor, - bool hasStreamMode, - bool hidden = false); - - Cipher(); - virtual ~Cipher(); - - virtual Interface interface() const =0; - - // create a new key based on a password - // if iterationCount == 0, then iteration count will be determined - // by newKey function and filled in. - // If iterationCount == 0, then desiredFunctionDuration is how many - // milliseconds the password derivation function should take to run. - virtual CipherKey newKey(const char *password, int passwdLength, - int &iterationCount, long desiredFunctionDuration, - const byte *salt, int saltLen) =0; - - // deprecated - for backward compatibility - virtual CipherKey newKey(const char *password, int passwdLength ) =0; - - // create a new random key - virtual CipherKey newRandomKey() =0; - - // data must be len encodedKeySize() - virtual CipherKey readKey(const byte *data, - const CipherKey &encodingKey, - bool checkKey = true) =0; - - virtual void writeKey(const CipherKey &key, byte *data, - const CipherKey &encodingKey) =0; - - virtual std::string encodeAsString(const CipherKey &key, - const CipherKey &encodingKey ); - - // for testing purposes - virtual bool compareKey( const CipherKey &A, const CipherKey &B ) const =0; - - // meta-data about the cypher - virtual int keySize() const=0; - virtual int encodedKeySize() const=0; // size - virtual int cipherBlockSize() const=0; // size of a cipher block - - virtual bool hasStreamMode() const; - - // fill the supplied buffer with random data - // The data may be pseudo random and might not be suitable for key - // generation. For generating keys, uses newRandomKey() instead. - // Returns true on success, false on failure. - virtual bool randomize( byte *buf, int len, - bool strongRandom ) const =0; - - // 64 bit MAC of the data with the given key - virtual uint64_t MAC_64( const byte *src, int len, - const CipherKey &key, uint64_t *chainedIV = 0 ) const =0; - - // based on reductions of MAC_64 - unsigned int MAC_32( const byte *src, int len, - const CipherKey &key, uint64_t *chainedIV = 0 ) const; - unsigned int MAC_16( const byte *src, int len, - const CipherKey &key, uint64_t *chainedIV = 0 ) const; - - // functional interfaces - /* - Stream encoding of data in-place. The stream data can be any length. - */ - virtual bool streamEncode( byte *data, int len, - uint64_t iv64, const CipherKey &key) const=0; - virtual bool streamDecode( byte *data, int len, - uint64_t iv64, const CipherKey &key) const=0; - - /* - Block encoding of data in-place. The data size should be a multiple of - the cipher block size. - */ - virtual bool blockEncode(byte *buf, int size, - uint64_t iv64, const CipherKey &key) const=0; - virtual bool blockDecode(byte *buf, int size, - uint64_t iv64, const CipherKey &key) const=0; -}; - -} // namespace encfs - -#endif - diff --git a/cipher/CipherKey.cpp b/cipher/CipherKey.cpp index 6512466..aebf4d7 100644 --- a/cipher/CipherKey.cpp +++ b/cipher/CipherKey.cpp @@ -1,18 +1,19 @@ + /***************************************************************************** * Author: Valient Gough * ***************************************************************************** - * Copyright (c) 2007, Valient Gough + * Copyright (c) 2013 Valient Gough * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . @@ -20,14 +21,72 @@ #include "cipher/CipherKey.h" +#include "base/shared_ptr.h" +#include "base/types.h" +#include "cipher/MemoryPool.h" + namespace encfs { -AbstractCipherKey::AbstractCipherKey() +CipherKey::CipherKey() + : _valid(false) { } -AbstractCipherKey::~AbstractCipherKey() +CipherKey::CipherKey(int length) + : _valid(true) { + if (length > 0) + _mem.reset(new SecureMem(length)); +} + +CipherKey::CipherKey(const byte *data, int length) + : _valid(true) +{ + _mem.reset(new SecureMem(length)); + memcpy(_mem->data, data, length); +} + +CipherKey::CipherKey(const CipherKey& src) + : _valid(src._valid), + _mem(src._mem) +{ +} + +CipherKey::~CipherKey() +{ +} + +void CipherKey::operator = (const CipherKey& src) +{ + _mem = src._mem; + _valid = src._valid; +} + +byte *CipherKey::data() const +{ + return !_mem ? NULL : _mem->data; +} + +int CipherKey::size() const +{ + return !_mem ? 0 : _mem->size; +} + +void CipherKey::reset() +{ + _mem.reset(); + _valid = false; +} + +bool CipherKey::valid() const +{ + return _valid; +} + +bool operator == (const CipherKey &a, const CipherKey &b) { + if (a.size() != b.size()) + return false; + return memcmp(a.data(), b.data(), a.size()) == 0; } } // namespace encfs diff --git a/cipher/CipherKey.h b/cipher/CipherKey.h index 62edaf0..4cd6e27 100644 --- a/cipher/CipherKey.h +++ b/cipher/CipherKey.h @@ -21,18 +21,40 @@ #ifndef _CipherKey_incl_ #define _CipherKey_incl_ +#include + #include "base/shared_ptr.h" +#include "base/types.h" namespace encfs { -class AbstractCipherKey +class SecureMem; + +class CipherKey { -public: - AbstractCipherKey(); - virtual ~AbstractCipherKey(); + public: + CipherKey(); // Creates a key for which valid() returns false. + explicit CipherKey(int length); + CipherKey(const byte *data, int length); + CipherKey(const CipherKey& src); + ~CipherKey(); + + void operator = (const CipherKey& src); + + byte *data() const; + int size() const; + + // Clear memory associated with key. + void reset(); + + bool valid() const; + + private: + bool _valid; + shared_ptr _mem; }; -typedef shared_ptr CipherKey; +bool operator == (const CipherKey &a, const CipherKey &b); } // namespace encfs diff --git a/cipher/CipherV1.cpp b/cipher/CipherV1.cpp new file mode 100644 index 0000000..fec3206 --- /dev/null +++ b/cipher/CipherV1.cpp @@ -0,0 +1,668 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2004, Valient Gough + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "cipher/CipherV1.h" + +#include +#include + +#include +#include + +#include + +#include "base/base64.h" +#include "base/Error.h" +#include "base/i18n.h" +#include "base/Mutex.h" +#include "base/Range.h" +#include "cipher/MemoryPool.h" +#include "cipher/MAC.h" +#include "cipher/BlockCipher.h" +#include "cipher/PBKDF.h" +#include "cipher/StreamCipher.h" + +using namespace std; + +namespace encfs { + +const int MAX_KEYLENGTH = 64; // in bytes (256 bit) +const int MAX_IVLENGTH = 16; +const int KEY_CHECKSUM_BYTES = 4; + +#ifndef MIN +inline int MIN(int a, int b) +{ + return (a < b) ? a : b; +} +#endif + +/* + DEPRECATED: this is here for backward compatibilty only. Use PBKDF + + This duplicated some code in OpenSSL, correcting an issue with key lengths + produced for Blowfish. +*/ +bool BytesToKey(const byte *data, int dataLen, + unsigned int rounds, CipherKey *key) +{ + Registry registry = MAC::GetRegistry(); + shared_ptr sha1(registry.CreateForMatch("SHA-1")); + if (!sha1) + return false; + + if( data == NULL || dataLen == 0 ) + return false; // OpenSSL returns nkey here, but why? It is a failure.. + + SecureMem mdBuf( sha1->outputSize() ); + int addmd = 0; + int remaining = key->size(); + + for(;;) + { + sha1->reset(); + if( addmd++ ) + sha1->update(mdBuf.data, mdBuf.size); + sha1->update(data, dataLen); + sha1->write(mdBuf.data); + + for(unsigned int i=1; i < rounds; ++i) + { + sha1->reset(); + sha1->update(mdBuf.data, mdBuf.size); + sha1->write(mdBuf.data); + } + + int offset = 0; + int toCopy = MIN( remaining, (int)mdBuf.size - offset ); + if( toCopy ) + { + memcpy( key->data(), mdBuf.data+offset, toCopy ); + key += toCopy; + remaining -= toCopy; + offset += toCopy; + } + if(remaining == 0) break; + } + + return true; +} + +long time_diff(const timeval &end, const timeval &start) +{ + return (end.tv_sec - start.tv_sec) * 1000 * 1000 + + (end.tv_usec - start.tv_usec); +} + +int CipherV1::TimedPBKDF2(const char *pass, int passlen, + const byte *salt, int saltlen, + CipherKey *key, long desiredPDFTime) +{ + Registry registry = PBKDF::GetRegistry(); + shared_ptr impl(registry.CreateForMatch(NAME_PKCS5_PBKDF2_HMAC_SHA1)); + if (!impl) + return -1; + + int iter = 1000; + timeval start, end; + + for(;;) + { + gettimeofday( &start, 0 ); + if (!impl->makeKey(pass, passlen, salt, saltlen, iter, key)) + return -1; + + gettimeofday( &end, 0 ); + + long delta = time_diff(end, start); + if(delta < desiredPDFTime / 8) + { + iter *= 4; + } else if(delta < (5 * desiredPDFTime / 6)) + { + // estimate number of iterations to get close to desired time + iter = (int)((double)iter * (double)desiredPDFTime + / (double)delta); + } else + return iter; + } +} + + +// - Version 1:0 used EVP_BytesToKey, which didn't do the right thing for +// Blowfish key lengths > 128 bit. +// - Version 2:0 uses BytesToKey. +// We support both 2:0 and 1:0, hence current:revision:age = 2:0:1 +// - Version 2:1 adds support for Message Digest function interface +// - Version 2:2 adds PBKDF2 for password derivation +// - Version 3:0 adds a new IV mechanism +// - Version 3:1 drops support for verison 1:0 blowfish keys, in order to avoid +// having to duplicate the behavior of old EVP_BytesToKey implementations. +static Interface BlowfishInterface = makeInterface( "ssl/blowfish", 3, 1, 1 ); +static Interface AESInterface = makeInterface( "ssl/aes", 3, 1, 2 ); + +static Interface NullCipherInterface = makeInterface( "nullCipher", 1, 0, 0); + +static Range BFKeyRange(128,256,32); +static int BFDefaultKeyLen = 160; + +static Range AESKeyRange(128,256,64); +static int AESDefaultKeyLen = 192; + +list CipherV1::GetAlgorithmList() +{ + list result; + Registry blockCipherRegistry = BlockCipher::GetRegistry(); + + if (blockCipherRegistry.GetPropertiesForMatch(NAME_AES_CBC) != NULL) { + CipherV1::CipherAlgorithm alg; + alg.name = "AES"; + alg.description = "16 byte block cipher"; + alg.iface = AESInterface; + alg.keyLength = AESKeyRange; + alg.blockSize = Range(64, 4096, 16); + result.push_back(alg); + } + + if (blockCipherRegistry.GetPropertiesForMatch(NAME_BLOWFISH_CBC) != NULL) { + CipherV1::CipherAlgorithm alg; + alg.name = "Blowfish"; + alg.description = "8 byte block cipher"; + alg.iface = BlowfishInterface; + alg.keyLength = BFKeyRange; + alg.blockSize = Range(64, 4096, 8); + result.push_back(alg); + } + + CipherV1::CipherAlgorithm alg; + alg.name = "Null"; + alg.description = "Pass-through cipher, for testing only!"; + alg.iface = NullCipherInterface; + alg.keyLength = Range(0); + alg.blockSize = Range(64, 4096, 8); + result.push_back(alg); + + return result; +} + +shared_ptr CipherV1::New(const std::string& name, int keyLen) { + for (auto &it : GetAlgorithmList()) { + if (it.name == name) + return New(it.iface, keyLen); + } + + return shared_ptr(); +} + +shared_ptr CipherV1::New(const Interface &iface, int keyLen) { + return shared_ptr(new CipherV1(iface, iface, keyLen)); +} + +CipherV1::CipherV1(const Interface &iface, const Interface &realIface, + int keyLength) +{ + this->iface = iface; + this->realIface = realIface; + + Registry blockCipherRegistry = BlockCipher::GetRegistry(); + Registry streamCipherRegistry = StreamCipher::GetRegistry(); + + int defaultKeyLength; + Range keyRange; + + if (implements(AESInterface, iface)) { + keyRange = AESKeyRange; + defaultKeyLength = AESDefaultKeyLen; + _blockCipher.reset( blockCipherRegistry.CreateForMatch(NAME_AES_CBC) ); + _streamCipher.reset( streamCipherRegistry.CreateForMatch(NAME_AES_CFB) ); + } else if (implements(BlowfishInterface, iface)) { + keyRange = BFKeyRange; + defaultKeyLength = BFDefaultKeyLen; + _blockCipher.reset( blockCipherRegistry.CreateForMatch(NAME_BLOWFISH_CBC) ); + _streamCipher.reset( streamCipherRegistry.CreateForMatch + (NAME_BLOWFISH_CFB) ); + } else if (implements(NullCipherInterface, iface)) { + keyRange = Range(0); + defaultKeyLength = 0; + _blockCipher.reset( blockCipherRegistry.CreateForMatch("NullCipher") ); + _streamCipher.reset( streamCipherRegistry.CreateForMatch("NullCipher") ); + } else { + throw Error("Unsupported cipher"); + } + + if (!_blockCipher || !_streamCipher) { + throw Error("Requested cipher not available"); + } + + if (keyLength <= 0) + _keySize = defaultKeyLength / 8; + else + _keySize = keyRange.closest(keyLength) / 8; + + _pbkdf.reset(PBKDF::GetRegistry().CreateForMatch( + NAME_PKCS5_PBKDF2_HMAC_SHA1)); + if (!_pbkdf) { + throw Error("PBKDF not available"); + } + + // Initialize the cipher with a temporary key in order to determine the block + // size. + CipherKey tmpKey = _pbkdf->randomKey(_keySize); + _blockCipher->setKey(tmpKey); + _ivLength = _blockCipher->blockSize(); + _iv.reset(new SecureMem(_ivLength)); + _keySet = false; + + Lock l(_hmacMutex); + _hmac.reset(MAC::GetRegistry().CreateForMatch(NAME_SHA1_HMAC)); + if (!_hmac) + throw Error("SHA1_HMAC not available"); +} + +CipherV1::~CipherV1() +{ +} + +Interface CipherV1::interface() const +{ + return realIface; +} + +/* + Create a key from the password. + Use SHA to distribute entropy from the password into the key. + + This algorithm must remain constant for backward compatibility, as this key + is used to encipher/decipher the master key. + */ +CipherKey CipherV1::newKey(const char *password, int passwdLength, + int *iterationCount, long desiredDuration, + const byte *salt, int saltLen) +{ + CipherKey key(_keySize + _ivLength); + + if(*iterationCount == 0) + { + // timed run, fills in iteration count + int res = TimedPBKDF2(password, passwdLength, + salt, saltLen, &key, + 1000 * desiredDuration); + if(res <= 0) + { + LOG(ERROR) << "openssl error, PBKDF2 failed"; + return CipherKey(); + } else + *iterationCount = res; + } else + { + // known iteration length + if (!_pbkdf->makeKey(password, passwdLength, + salt, saltLen, *iterationCount, &key)) + { + LOG(ERROR) << "openssl error, PBKDF2 failed"; + return CipherKey(); + } + } + + return key; +} + +// Deprecated - for use only with filesystems which used a fixed-round PBKDF. +// Such configurations are replaced with a new PBKDF2 implementation when the +// password is changed or configuration is rewritten. +CipherKey CipherV1::newKey(const char *password, int passwdLength) +{ + CipherKey key(_keySize + _ivLength); + + bool ok = BytesToKey((byte *)password, passwdLength, 16, &key); + LOG_IF(ERROR, !ok) << "newKey: BytesToKey failed"; + if (!ok) + throw Error("BytesToKey failed"); + + return key; +} + +CipherKey CipherV1::newRandomKey() +{ + return _pbkdf->randomKey(_keySize + _ivLength); +} + +bool CipherV1::pseudoRandomize( byte *buf, int len ) +{ + return _pbkdf->pseudoRandom(buf, len); +} + +bool CipherV1::setKey(const CipherKey &keyIv) { + Lock l(_hmacMutex); + + // Key is actually key plus iv, so extract the different parts. + CipherKey key(_keySize); + memcpy(key.data(), keyIv.data(), _keySize); + memcpy(_iv->data, keyIv.data() + _keySize, _ivLength); + + if (_blockCipher->setKey(key) + && _streamCipher->setKey(key) + && _hmac->setKey(key)) { + _keySet = true; + return true; + } + + return false; +} + +uint64_t CipherV1::MAC_64(const byte *data, int len, + uint64_t *chainedIV ) const +{ + rAssert( len > 0 ); + rAssert( _keySet ); + + byte md[_hmac->outputSize()]; + + Lock l(_hmacMutex); + _hmac->reset(); + + _hmac->update(data, len); + if(chainedIV) + { + // toss in the chained IV as well + uint64_t tmp = *chainedIV; + byte h[8]; + for(unsigned int i=0; i<8; ++i) + { + h[i] = tmp & 0xff; + tmp >>= 8; + } + + _hmac->update(h, 8); + } + + bool ok = _hmac->write(md); + rAssert(ok); + + // chop this down to a 64bit value.. + byte h[8] = {0,0,0,0,0,0,0,0}; + // TODO: outputSize - 1? + for(unsigned int i=0; i<_hmac->outputSize(); ++i) + h[i%8] ^= (byte)(md[i]); + + uint64_t value = (uint64_t)h[0]; + for(int i=1; i<8; ++i) + value = (value << 8) | (uint64_t)h[i]; + + // TODO: should not be here. + if(chainedIV) + *chainedIV = value; + + return value; +} + +unsigned int CipherV1::reduceMac32(uint64_t mac64) +{ + return ((mac64 >> 32) & 0xffffffff) ^ (mac64 & 0xffffffff); +} + +unsigned int CipherV1::reduceMac16(uint64_t mac64) +{ + unsigned int mac32 = reduceMac32(mac64); + return ((mac32 >> 16) & 0xffff) ^ (mac32 & 0xffff); +} + +CipherKey CipherV1::readKey(const byte *data, bool checkKey) +{ + rAssert( _keySet ); + CipherKey key(_keySize + _ivLength); + + // First N bytes are checksum bytes. + unsigned int checksum = 0; + for(int i=0; i KEY_CHECKSUM_BYTES); + + SecureMem tmpBuf(ckey.size()); + memcpy(tmpBuf.data, ckey.data(), tmpBuf.size); + + unsigned int checksum = reduceMac32( + MAC_64( tmpBuf.data, tmpBuf.size, NULL )); + streamEncode(tmpBuf.data, tmpBuf.size, checksum); + + memcpy( out+KEY_CHECKSUM_BYTES, tmpBuf.data, tmpBuf.size ); + + // first N bytes contain HMAC derived checksum.. + for(int i=1; i<=KEY_CHECKSUM_BYTES; ++i) + { + out[KEY_CHECKSUM_BYTES-i] = checksum & 0xff; + checksum >>= 8; + } +} + +std::string CipherV1::encodeAsString(const CipherKey &key) +{ + rAssert( _keySet ); + int encodedSize = encodedKeySize(); + vector buf(encodedSize); + writeKey(key, buf.data()); + + int b64Len = B256ToB64Bytes( encodedSize ); + byte *b64Key = new byte[b64Len + 1]; + + changeBase2( buf.data(), encodedSize, 8, b64Key, b64Len, 6); + B64ToAscii( b64Key, b64Len ); + b64Key[ b64Len - 1 ] = '\0'; + + return string( (const char *)b64Key ); +} + +int CipherV1::encodedKeySize() const +{ + return _keySize + _ivLength + KEY_CHECKSUM_BYTES; +} + +int CipherV1::keySize() const +{ + return _keySize; +} + +int CipherV1::cipherBlockSize() const +{ + rAssert( _keySet ); + return _blockCipher->blockSize(); +} + +// Deprecated: For backward compatibility only. +// A watermark attack was discovered against this IV construction. If an +// attacker could get a victim to store a carefully crafted file, they could +// later determine if the victim had the file in encrypted storage (without +// decrypting the file). +static void setIVec_old(byte *ivec, int ivLen, unsigned int seed) +{ + unsigned int var1 = 0x060a4011 * seed; + unsigned int var2 = 0x0221040d * (seed ^ 0xD3FEA11C); + + ivec[0] ^= (var1 >> 24) & 0xff; + ivec[1] ^= (var2 >> 16) & 0xff; + ivec[2] ^= (var1 >> 8 ) & 0xff; + ivec[3] ^= (var2 ) & 0xff; + ivec[4] ^= (var2 >> 24) & 0xff; + ivec[5] ^= (var1 >> 16) & 0xff; + ivec[6] ^= (var2 >> 8 ) & 0xff; + ivec[7] ^= (var1 ) & 0xff; + + if(ivLen > 8) + { + ivec[8+0] ^= (var1 ) & 0xff; + ivec[8+1] ^= (var2 >> 8 ) & 0xff; + ivec[8+2] ^= (var1 >> 16) & 0xff; + ivec[8+3] ^= (var2 >> 24) & 0xff; + ivec[8+4] ^= (var1 >> 24) & 0xff; + ivec[8+5] ^= (var2 >> 16) & 0xff; + ivec[8+6] ^= (var1 >> 8 ) & 0xff; + ivec[8+7] ^= (var2 ) & 0xff; + } +} + +void CipherV1::setIVec(byte *ivec, uint64_t seed) const +{ + rAssert( _keySet ); + memcpy( ivec, _iv->data, _ivLength ); + if (iface.major() < 3) + { + // Backward compatible mode. + setIVec_old(ivec, _ivLength, seed); + return; + } + + vector md(_hmac->outputSize()); + for(int i=0; i<8; ++i) + { + md[i] = (byte)(seed & 0xff); + seed >>= 8; + } + + // combine ivec and seed with HMAC + Lock l(_hmacMutex); + _hmac->reset(); + _hmac->update(ivec, _ivLength); + _hmac->update(md.data(), 8); + _hmac->write(md.data()); + + memcpy(ivec, md.data(), _ivLength); +} + +static void flipBytes(byte *buf, int size) +{ + byte revBuf[64]; + + int bytesLeft = size; + while(bytesLeft) + { + int toFlip = MIN( (int)sizeof(revBuf), bytesLeft ); + + for(int i=0; i 0 ); + + vector ivec(_ivLength); + shuffleBytes( buf, size ); + + setIVec( ivec.data(), iv64 ); + if (!_streamCipher->encrypt(ivec.data(), buf, buf, size)) + return false; + + flipBytes( buf, size ); + shuffleBytes( buf, size ); + + setIVec( ivec.data(), iv64 + 1 ); + if (!_streamCipher->encrypt(ivec.data(), buf, buf, size)) + return false; + + return true; +} + +bool CipherV1::streamDecode(byte *buf, int size, uint64_t iv64) const +{ + rAssert( _keySet ); + rAssert( size > 0 ); + + vector ivec(_ivLength); + setIVec( ivec.data(), iv64 + 1 ); + if (!_streamCipher->decrypt(ivec.data(), buf, buf, size)) + return false; + + unshuffleBytes( buf, size ); + flipBytes( buf, size ); + + setIVec( ivec.data(), iv64 ); + if (!_streamCipher->decrypt(ivec.data(), buf, buf, size)) + return false; + + unshuffleBytes( buf, size ); + + return true; +} + + +bool CipherV1::blockEncode(byte *buf, int size, uint64_t iv64) const +{ + rAssert( _keySet ); + rAssert( size > 0 ); + + vector ivec(_ivLength); + setIVec( ivec.data(), iv64 ); + return _blockCipher->encrypt(ivec.data(), buf, buf, size); +} + +bool CipherV1::blockDecode(byte *buf, int size, uint64_t iv64) const +{ + rAssert( _keySet ); + rAssert( size > 0 ); + + vector ivec(_ivLength); + setIVec( ivec.data(), iv64 ); + return _blockCipher->decrypt(ivec.data(), buf, buf, size); +} + +} // namespace encfs diff --git a/cipher/SSL_Cipher.h b/cipher/CipherV1.h similarity index 57% rename from cipher/SSL_Cipher.h rename to cipher/CipherV1.h index 1dcd1d6..376cfc1 100644 --- a/cipher/SSL_Cipher.h +++ b/cipher/CipherV1.h @@ -2,7 +2,7 @@ * Author: Valient Gough * ***************************************************************************** - * Copyright (c) 2004, Valient Gough + * Copyright (c) 2004-2013, Valient Gough * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the @@ -18,22 +18,24 @@ * along with this program. If not, see . */ -#ifndef _SSL_Cipher_incl_ -#define _SSL_Cipher_incl_ +#ifndef _CipherV1_incl_ +#define _CipherV1_incl_ -#include "cipher/Cipher.h" #include "base/Interface.h" +#include "base/Mutex.h" +#include "base/shared_ptr.h" -#ifndef EVP_CIPHER -struct evp_cipher_st; -typedef struct evp_cipher_st EVP_CIPHER; -#endif +#include "cipher/BlockCipher.h" +#include "cipher/StreamCipher.h" +#include "cipher/MAC.h" +#include "cipher/PBKDF.h" namespace encfs { -class SSLKey; + +class SecureMem; /* - Implements Cipher interface for OpenSSL's ciphers. + Implements Encfs V1.x ciphers support. Design: Variable algorithm, key size, and block size. @@ -70,91 +72,107 @@ class SSLKey; initial value vector to randomize the output. But it makes the code simpler to reuse the encryption algorithm as is. */ -class SSL_Cipher : public Cipher +class CipherV1 { Interface iface; Interface realIface; - const EVP_CIPHER *_blockCipher; - const EVP_CIPHER *_streamCipher; + + shared_ptr _blockCipher; + shared_ptr _streamCipher; + shared_ptr _pbkdf; + + // HMac is stateful, so access is controlled via mutex. + mutable Mutex _hmacMutex; + mutable shared_ptr _hmac; + unsigned int _keySize; // in bytes unsigned int _ivLength; + shared_ptr _iv; + bool _keySet; + public: - SSL_Cipher(const Interface &iface, const Interface &realIface, - const EVP_CIPHER *blockCipher, const EVP_CIPHER *streamCipher, - int keyLength); - virtual ~SSL_Cipher(); - // returns the real interface, not the one we're emulating (if any).. - virtual Interface interface() const; + struct CipherAlgorithm + { + std::string name; + std::string description; + Interface iface; + Range keyLength; + Range blockSize; + }; - // create a new key based on a password - virtual CipherKey newKey(const char *password, int passwdLength, - int &iterationCount, long desiredDuration, - const byte *salt, int saltLen); - // deprecated - for backward compatibility - virtual CipherKey newKey(const char *password, int passwdLength); - // create a new random key - virtual CipherKey newRandomKey(); - - // data must be len keySize() - virtual CipherKey readKey(const byte *data, - const CipherKey &encodingKey, - bool checkKey); - virtual void writeKey(const CipherKey &key, byte *data, - const CipherKey &encodingKey); - virtual bool compareKey( const CipherKey &A, - const CipherKey &B ) const; - - // meta-data about the cypher - virtual int keySize() const; - virtual int encodedKeySize() const; - virtual int cipherBlockSize() const; - - virtual bool hasStreamMode() const; - - virtual bool randomize( byte *buf, int len, - bool strongRandom ) const; - - virtual uint64_t MAC_64( const byte *src, int len, - const CipherKey &key, uint64_t *augment ) const; - - // functional interfaces - /* - Stream encoding in-place. - */ - virtual bool streamEncode(byte *in, int len, - uint64_t iv64, const CipherKey &key) const; - virtual bool streamDecode(byte *in, int len, - uint64_t iv64, const CipherKey &key) const; - - /* - Block encoding is done in-place. Partial blocks are supported, but - blocks are always expected to begin on a block boundary. See - blockSize(). - */ - virtual bool blockEncode(byte *buf, int size, - uint64_t iv64, const CipherKey &key) const; - virtual bool blockDecode(byte *buf, int size, - uint64_t iv64, const CipherKey &key) const; - - // hack to help with static builds - static bool Enabled(); + // Returns a list of supported algorithms. + static std::list GetAlgorithmList(); + static shared_ptr New(const std::string &name, int keyLen = -1); + static shared_ptr New(const Interface &alg, int keyLen = -1); // Password-based key derivation function which determines the // number of iterations based on a desired execution time (in microseconds). // Returns the number of iterations applied. static int TimedPBKDF2(const char *pass, int passLen, const byte *salt, int saltLen, - int keyLen, byte *out, - long desiredPDFTimeMicroseconds); - private: - void setIVec( byte *ivec, uint64_t seed, - const shared_ptr &key ) const; + CipherKey *out, long desiredPDFTimeMicroseconds); + CipherV1(const Interface &iface, const Interface &realIface, int keyLength); + ~CipherV1(); + + // returns the real interface, not the one we're emulating (if any).. + Interface interface() const; + + // create a new key based on a password + CipherKey newKey(const char *password, int passwdLength, + int *iterationCount, long desiredDuration, + const byte *salt, int saltLen); // deprecated - for backward compatibility - void setIVec_old( byte *ivec, unsigned int seed, - const shared_ptr &key ) const; + CipherKey newKey(const char *password, int passwdLength); + // create a new random key + CipherKey newRandomKey(); + + // Read and decrypt a key. + // data must be len keySize() + CipherKey readKey(const byte *data, bool checkKey); + + // Encrypt and write the given key. + void writeKey(const CipherKey &key, byte *data); + + // Encrypt and store a key as a string. + std::string encodeAsString(const CipherKey &key); + + + // meta-data about the cypher + int keySize() const; + int encodedKeySize() const; + int cipherBlockSize() const; + + bool pseudoRandomize(byte *buf, int len); + + // Sets the key used for encoding / decoding, and MAC operations. + bool setKey(const CipherKey &key); + + uint64_t MAC_64(const byte *src, int len, + uint64_t *augment = NULL) const; + + static unsigned int reduceMac32(uint64_t mac64); + static unsigned int reduceMac16(uint64_t mac64); + + // functional interfaces + /* + Stream encoding in-place. + */ + bool streamEncode(byte *data, int len, uint64_t iv64) const; + bool streamDecode(byte *data, int len, uint64_t iv64) const; + + /* + Block encoding is done in-place. Partial blocks are supported, but + blocks are always expected to begin on a block boundary. See + blockSize(). + */ + bool blockEncode(byte *buf, int size, uint64_t iv64) const; + bool blockDecode(byte *buf, int size, uint64_t iv64) const; + + private: + void setIVec(byte *out, uint64_t seed) const; }; } // namespace encfs diff --git a/cipher/MAC.cpp b/cipher/MAC.cpp index 64e08e1..8534d77 100644 --- a/cipher/MAC.cpp +++ b/cipher/MAC.cpp @@ -2,13 +2,13 @@ namespace encfs { -DEFINE_REGISTERABLE_TYPE(MessageAuthenticationCode) +DEFINE_REGISTERABLE_TYPE(MAC) -MessageAuthenticationCode::MessageAuthenticationCode() +MAC::MAC() { } -MessageAuthenticationCode::~MessageAuthenticationCode() +MAC::~MAC() { } diff --git a/cipher/MAC.h b/cipher/MAC.h index d7849e2..436e6d6 100644 --- a/cipher/MAC.h +++ b/cipher/MAC.h @@ -5,14 +5,17 @@ #include "base/Registry.h" #include "base/types.h" +#include "cipher/CipherKey.h" namespace encfs { -// MessageAuthenticationCode provides keyed MAC algorithms, eg HMAC. -class MessageAuthenticationCode +static const char NAME_SHA1_HMAC[] = "SHA-1/HMAC"; + +// MAC provides keyed MessageAuthenticationCode algorithms, eg HMAC. +class MAC { public: - DECLARE_REGISTERABLE_TYPE(MessageAuthenticationCode); + DECLARE_REGISTERABLE_TYPE(MAC); struct Properties { int blockSize; // Block length of hash function. @@ -25,13 +28,12 @@ class MessageAuthenticationCode } }; - MessageAuthenticationCode(); - virtual ~MessageAuthenticationCode(); + MAC(); + virtual ~MAC(); virtual int outputSize() const =0; - virtual bool setKey(const byte *key, int keyLength) =0; - virtual bool randomKey(int keyLength) =0; + virtual bool setKey(const CipherKey &key) =0; virtual void reset() =0; virtual bool update(const byte *in, int length) =0; diff --git a/cipher/MAC_test.cpp b/cipher/MAC_test.cpp index c93bd8a..de8115c 100644 --- a/cipher/MAC_test.cpp +++ b/cipher/MAC_test.cpp @@ -32,37 +32,36 @@ using namespace encfs; namespace { -TEST(HMacSha1Test, MessageAuthenticationCode) { - Registry registry = - MessageAuthenticationCode::GetRegistry(); - shared_ptr hmac( - registry.CreateForMatch( "SHA-1/HMAC" )); +TEST(HMacSha1Test, MAC) { + Registry registry = MAC::GetRegistry(); + shared_ptr hmac( registry.CreateForMatch( NAME_SHA1_HMAC )); ASSERT_FALSE(!hmac); // Test cases from rfc2202 // Test case 1 - byte key[20]; + CipherKey key(20); byte out[20]; for (int i = 0; i < 20; ++i) - key[i] = 0x0b; - hmac->setKey(key, 20); + key.data()[i] = 0x0b; + hmac->setKey(key); hmac->reset(); hmac->update((byte *)"Hi There", 8); hmac->write(out); ASSERT_EQ("b617318655057264e28bc0b6fb378c8ef146be00", stringToHex(out, 20)); // Test case 2 - strcpy((char *)key, "Jefe"); - hmac->setKey(key, 4); + key = CipherKey((const byte *)"Jefe", 4); + hmac->setKey(key); hmac->reset(); hmac->update((byte *)"what do ya want for nothing?", 28); hmac->write(out); ASSERT_EQ("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79", stringToHex(out, 20)); // Test case 3 + key = CipherKey(20); for (int i = 0; i < 20; ++i) - key[i] = 0xaa; - hmac->setKey(key, 20); + key.data()[i] = 0xaa; + hmac->setKey(key); hmac->reset(); { byte data[50]; @@ -73,9 +72,9 @@ TEST(HMacSha1Test, MessageAuthenticationCode) { ASSERT_EQ("125d7342b9ac11cd91a39af48aa17b4f63f175d3", stringToHex(out, 20)); // Test #7 - byte longKey[80]; - memset(longKey, 0xaa, 80); - hmac->setKey(longKey, 80); + key = CipherKey(80); + memset(key.data(), 0xaa, 80); + hmac->setKey(key); hmac->reset(); hmac->update((byte *)"Test Using Larger Than Block-Size Key and Larger " "Than One Block-Size Data", 73); diff --git a/cipher/MemoryPool.h b/cipher/MemoryPool.h index b6f1c54..26070a4 100644 --- a/cipher/MemoryPool.h +++ b/cipher/MemoryPool.h @@ -57,12 +57,13 @@ namespace MemoryPool void destroyAll(); } -struct SecureMem +class SecureMem { + public: int size; byte *data; - SecureMem(int len); + explicit SecureMem(int len); ~SecureMem(); }; diff --git a/cipher/NullCipher.cpp b/cipher/NullCipher.cpp deleted file mode 100644 index 7af4a10..0000000 --- a/cipher/NullCipher.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2004, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include "cipher/NullCipher.h" - -#include "base/Range.h" -#include "base/Interface.h" -#include "base/shared_ptr.h" - -#include - -using namespace std; - -namespace encfs { - -static Interface NullInterface = makeInterface( "nullCipher", 1, 0, 0 ); -static Range NullKeyRange(0); -static Range NullBlockRange(1,4096,1); - -static shared_ptr NewNullCipher(const Interface &iface, int keyLen) -{ - (void)keyLen; - return shared_ptr( new NullCipher( iface ) ); -} - -const bool HiddenCipher = true; - -static bool NullCipher_registered = Cipher::Register("Null", - "Non encrypting cipher. For testing only!", - NullInterface, NullKeyRange, NullBlockRange, NewNullCipher, - HiddenCipher); - -class NullKey : public AbstractCipherKey -{ -public: - NullKey() {} - virtual ~NullKey() {} -}; - -class NullDestructor -{ -public: - NullDestructor() {} - NullDestructor(const NullDestructor &) {} - ~NullDestructor() {} - - NullDestructor &operator = (const NullDestructor &){ return *this; } - void operator ()(NullKey *&) {} -}; - -shared_ptr gNullKey( new NullKey(), NullDestructor() ); - -NullCipher::NullCipher(const Interface &iface_) -{ - this->iface = iface_; -} - -NullCipher::~NullCipher() -{ -} - -Interface NullCipher::interface() const -{ - return iface; -} - -CipherKey NullCipher::newKey(const char *, int, - int &, long, const byte *, int ) -{ - return gNullKey; -} - -CipherKey NullCipher::newKey(const char *, int) -{ - return gNullKey; -} - -CipherKey NullCipher::newRandomKey() -{ - return gNullKey; -} - -bool NullCipher::randomize( byte *buf, int len, bool ) const -{ - memset( buf, 0, len ); - return true; -} - -uint64_t NullCipher::MAC_64(const byte *, int , - const CipherKey &, uint64_t *) const -{ - return 0; -} - -CipherKey NullCipher::readKey( const byte *, - const CipherKey &, bool) -{ - return gNullKey; -} - -void NullCipher::writeKey(const CipherKey &, byte *, - const CipherKey &) -{ -} - -bool NullCipher::compareKey(const CipherKey &A_, - const CipherKey &B_) const -{ - shared_ptr A = dynamic_pointer_cast(A_); - shared_ptr B = dynamic_pointer_cast(B_); - return A.get() == B.get(); -} - -int NullCipher::encodedKeySize() const -{ - return 0; -} - -int NullCipher::keySize() const -{ - return 0; -} - -int NullCipher::cipherBlockSize() const -{ - return 1; -} - -bool NullCipher::streamEncode( byte *src, int len, - uint64_t iv64, const CipherKey &key) const -{ - (void)src; - (void)len; - (void)iv64; - (void)key; - return true; -} - -bool NullCipher::streamDecode( byte *src, int len, - uint64_t iv64, const CipherKey &key) const -{ - (void)src; - (void)len; - (void)iv64; - (void)key; - return true; -} - -bool NullCipher::blockEncode( byte *, int , uint64_t, - const CipherKey & ) const -{ - return true; -} - -bool NullCipher::blockDecode( byte *, int, uint64_t, - const CipherKey & ) const -{ - return true; -} - -bool NullCipher::Enabled() -{ - return true; -} - -} // namespace encfs diff --git a/cipher/NullCipher.h b/cipher/NullCipher.h deleted file mode 100644 index e3b815f..0000000 --- a/cipher/NullCipher.h +++ /dev/null @@ -1,89 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2004, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#ifndef _NullCipher_incl_ -#define _NullCipher_incl_ - -#include "cipher/Cipher.h" -#include "base/Interface.h" - -namespace encfs { - -/* - Implements Cipher interface for a pass-through mode. May be useful for - testing, but that's it. -*/ -class NullCipher : public Cipher -{ - Interface iface; - -public: - NullCipher(const Interface &iface); - virtual ~NullCipher(); - - virtual Interface interface() const; - - // create a new key based on a password - virtual CipherKey newKey(const char *password, int passwdLength, - int &iterationCount, long desiredDuration, - const byte *salt, int saltLen); - virtual CipherKey newKey(const char *password, int passwdLength); - // create a new random key - virtual CipherKey newRandomKey(); - - // data must be len keySize() - virtual CipherKey readKey(const byte *data, - const CipherKey &encodingKey, - bool checkKey); - virtual void writeKey(const CipherKey &key, byte *data, - const CipherKey &encodingKey); - virtual bool compareKey( const CipherKey &A, - const CipherKey &B ) const; - - // meta-data about the cypher - virtual int keySize() const; - virtual int encodedKeySize() const; - virtual int cipherBlockSize() const; - - virtual bool randomize( byte *buf, int len, - bool strongRandom ) const; - - virtual uint64_t MAC_64(const byte *data, int len, - const CipherKey &key, uint64_t *chainedIV) const; - - // functional interfaces - virtual bool streamEncode(byte *in, int len, - uint64_t iv64, const CipherKey &key) const; - virtual bool streamDecode(byte *in, int len, - uint64_t iv64, const CipherKey &key) const; - - virtual bool blockEncode(byte *buf, int size, - uint64_t iv64, const CipherKey &key) const; - virtual bool blockDecode(byte *buf, int size, - uint64_t iv64, const CipherKey &key) const; - - // hack to help with static builds - static bool Enabled(); -}; - -} // namespace encfs - -#endif - diff --git a/cipher/NullCiphers.cpp b/cipher/NullCiphers.cpp new file mode 100644 index 0000000..b09ed4c --- /dev/null +++ b/cipher/NullCiphers.cpp @@ -0,0 +1,73 @@ + +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2013 Valient Gough + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "cipher/NullCiphers.h" + +#include "cipher/BlockCipher.h" +#include "cipher/StreamCipher.h" + +namespace encfs { + +class NullCipher : public BlockCipher { + public: + virtual ~NullCipher() {} + + virtual int blockSize() const { + return 8; + } + + virtual bool setKey(const CipherKey &key) { + return true; + } + + virtual bool encrypt(const byte *iv, const byte *in, + byte *out, int numBytes) { + if (in != out) + memcpy(out, in, numBytes); + return true; + } + + virtual bool decrypt(const byte *iv, const byte *in, + byte *out, int numBytes) { + if (in != out) + memcpy(out, in, numBytes); + return true; + } + + static Properties GetProperties() { + Properties props; + props.keySize = Range(0); + props.cipher = "NullCipher"; + props.mode = "ECB"; + props.library = "internal"; + return props; + } +}; + +REGISTER_CLASS(NullCipher, BlockCipher); +REGISTER_CLASS(NullCipher, StreamCipher); + +void NullCiphers::registerCiphers() { + // Nothing required. +} + +} // namespace encfs + diff --git a/cipher/NullCiphers.h b/cipher/NullCiphers.h new file mode 100644 index 0000000..b810ac9 --- /dev/null +++ b/cipher/NullCiphers.h @@ -0,0 +1,37 @@ + +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2013 Valient Gough + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef _NULLCIPHERS_incl_ +#define _NULLCIPHERS_incl_ + +#include "base/Registry.h" + +namespace encfs { + +class NullCiphers { + public: + static void registerCiphers(); +}; + +} // namespace encfs + +#endif + diff --git a/cipher/PBKDF.h b/cipher/PBKDF.h index 228d9b1..0f1435d 100644 --- a/cipher/PBKDF.h +++ b/cipher/PBKDF.h @@ -5,9 +5,13 @@ #include "base/Registry.h" #include "base/types.h" +#include "cipher/CipherKey.h" namespace encfs { +// Well-known algorithms. +static const char NAME_PKCS5_PBKDF2_HMAC_SHA1[] = "PKCS5_PBKDF2_HMAC_SHA1"; + // Password Based Key Derivation Function. class PBKDF { @@ -26,8 +30,14 @@ class PBKDF virtual bool makeKey(const char *password, int passwordLength, const byte *salt, int saltLength, - int numIterations, - byte *outKey, int keyLength) const = 0; + int numIterations, CipherKey *outKey) = 0; + + // Create a new key with strong randomization. + virtual CipherKey randomKey(int length) =0; + + // Randomize the output. Pseudo randomization is allowed, so this may not be + // used for keys or other critical values. + virtual bool pseudoRandom(byte *out, int byteLen) =0; }; } // namespace encfs diff --git a/cipher/PBKDF_test.cpp b/cipher/PBKDF_test.cpp index 0faeb23..350de9f 100644 --- a/cipher/PBKDF_test.cpp +++ b/cipher/PBKDF_test.cpp @@ -34,42 +34,37 @@ namespace { TEST(PKCS5_PBKDF2_HMAC_SHA1, PBKDF) { Registry registry = PBKDF::GetRegistry(); - shared_ptr impl( registry.CreateForMatch( "PKCS5_PBKDF2_HMAC_SHA1" )); + shared_ptr impl( registry.CreateForMatch(NAME_PKCS5_PBKDF2_HMAC_SHA1)); ASSERT_FALSE(!impl); // Test cases from rfc6070 // Test case 1 { - byte key[20]; + CipherKey key(20); bool ok = impl->makeKey("password", 8, (byte*)"salt", 4, - 1, - key, sizeof(key)); + 1, &key); ASSERT_TRUE(ok); - ASSERT_EQ("0c60c80f961f0e71f3a9b524af6012062fe037a6", - stringToHex(key, sizeof(key))); + ASSERT_EQ("0c60c80f961f0e71f3a9b524af6012062fe037a6", stringToHex(key)); } { - byte key[25]; + CipherKey key(25); bool ok = impl->makeKey("passwordPASSWORDpassword", 24, (byte*)"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, - 4096, - key, sizeof(key)); + 4096, &key); ASSERT_TRUE(ok); ASSERT_EQ("3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038", - stringToHex(key, sizeof(key))); + stringToHex(key)); } { - byte key[16]; + CipherKey key(16); bool ok = impl->makeKey("pass\0word", 9, (byte*)"sa\0lt", 5, - 4096, - key, sizeof(key)); + 4096, &key); ASSERT_TRUE(ok); - ASSERT_EQ("56fa6aa75548099dcc37d7f03425e0c3", - stringToHex(key, sizeof(key))); + ASSERT_EQ("56fa6aa75548099dcc37d7f03425e0c3", stringToHex(key)); } } diff --git a/cipher/SSL_Cipher.cpp b/cipher/SSL_Cipher.cpp deleted file mode 100644 index b434ee6..0000000 --- a/cipher/SSL_Cipher.cpp +++ /dev/null @@ -1,978 +0,0 @@ -/***************************************************************************** - * Author: Valient Gough - * - ***************************************************************************** - * Copyright (c) 2004, Valient Gough - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include "base/config.h" - -#include -#include -#include -#include -#include - -#include "cipher/SSL_Cipher.h" -#include "cipher/MemoryPool.h" -#include "cipher/BlockCipher.h" -#include "base/Error.h" -#include "base/Mutex.h" -#include "base/Range.h" - -#include -#include - -#include -#include - -#include - -#include "base/i18n.h" - -using namespace std; - -namespace encfs { - -const int MAX_KEYLENGTH = 64; // in bytes (256 bit) -const int MAX_IVLENGTH = 16; -const int KEY_CHECKSUM_BYTES = 4; - -#ifndef MIN -inline int MIN(int a, int b) -{ - return (a < b) ? a : b; -} -#endif - -/* - This produces the same result as OpenSSL's EVP_BytesToKey. The difference - is that here we can explicitly specify the key size, instead of relying on - the state of EVP_CIPHER struct. EVP_BytesToKey will only produce 128 bit - keys for the EVP Blowfish interface, which is not what we want. - - DEPRECATED: this is here for backward compatibilty only. Use PBKDF -*/ -int BytesToKey(int keyLen, int ivLen, const EVP_MD *md, - const byte *data, int dataLen, - unsigned int rounds, byte *key, byte *iv) -{ - if( data == NULL || dataLen == 0 ) - return 0; // OpenSSL returns nkey here, but why? It is a failure.. - - byte mdBuf[ EVP_MAX_MD_SIZE ]; - unsigned int mds=0; - int addmd =0; - int nkey = key ? keyLen : 0; - int niv = iv ? ivLen : 0; - - EVP_MD_CTX cx; - EVP_MD_CTX_init( &cx ); - - for(;;) - { - EVP_DigestInit_ex( &cx, md, NULL ); - if( addmd++ ) - EVP_DigestUpdate( &cx, mdBuf, mds ); - EVP_DigestUpdate( &cx, data, dataLen ); - EVP_DigestFinal_ex( &cx, mdBuf, &mds ); - - for(unsigned int i=1; i < rounds; ++i) - { - EVP_DigestInit_ex( &cx, md, NULL ); - EVP_DigestUpdate( &cx, mdBuf, mds ); - EVP_DigestFinal_ex( &cx, mdBuf, &mds ); - } - - int offset = 0; - int toCopy = MIN( nkey, (int)mds - offset ); - if( toCopy ) - { - memcpy( key, mdBuf+offset, toCopy ); - key += toCopy; - nkey -= toCopy; - offset += toCopy; - } - toCopy = MIN( niv, (int)mds - offset ); - if( toCopy ) - { - memcpy( iv, mdBuf+offset, toCopy ); - iv += toCopy; - niv -= toCopy; - offset += toCopy; - } - if((nkey == 0) && (niv == 0)) break; - } - EVP_MD_CTX_cleanup( &cx ); - OPENSSL_cleanse( mdBuf, sizeof(mdBuf) ); - - return keyLen; -} - -long time_diff(const timeval &end, const timeval &start) -{ - return (end.tv_sec - start.tv_sec) * 1000 * 1000 + - (end.tv_usec - start.tv_usec); -} - -int SSL_Cipher::TimedPBKDF2(const char *pass, int passlen, - const byte *salt, int saltlen, - int keylen, byte *out, - long desiredPDFTime) -{ - int iter = 1000; - timeval start, end; - - for(;;) - { - gettimeofday( &start, 0 ); - int res = PKCS5_PBKDF2_HMAC_SHA1( - pass, passlen, const_cast(salt), saltlen, - iter, keylen, out); - if(res != 1) - return -1; - - gettimeofday( &end, 0 ); - - long delta = time_diff(end, start); - if(delta < desiredPDFTime / 8) - { - iter *= 4; - } else if(delta < (5 * desiredPDFTime / 6)) - { - // estimate number of iterations to get close to desired time - iter = (int)((double)iter * (double)desiredPDFTime - / (double)delta); - } else - return iter; - } -} - - -// - Version 1:0 used EVP_BytesToKey, which didn't do the right thing for -// Blowfish key lengths > 128 bit. -// - Version 2:0 uses BytesToKey. -// We support both 2:0 and 1:0, hence current:revision:age = 2:0:1 -// - Version 2:1 adds support for Message Digest function interface -// - Version 2:2 adds PBKDF2 for password derivation -// - Version 3:0 adds a new IV mechanism -// - Version 3:1 adds ssl/aes_xts -static Interface BlowfishInterface = makeInterface( "ssl/blowfish", 3, 0, 2 ); -static Interface AESInterface = makeInterface( "ssl/aes", 3, 0, 2 ); -static Interface AesXtsInterface = makeInterface( "ssl/aes_xts", 3, 1, 2 ); - -#if defined(HAVE_EVP_BF) - -static Range BFKeyRange(128,256,32); -static Range BFBlockRange(64,4096,8); - -static shared_ptr NewBFCipher( const Interface &iface, int keyLen ) -{ - if( keyLen <= 0 ) - keyLen = 160; - - keyLen = BFKeyRange.closest( keyLen ); - - const EVP_CIPHER *blockCipher = EVP_bf_cbc(); - const EVP_CIPHER *streamCipher = EVP_bf_cfb(); - - return shared_ptr( - new SSL_Cipher(iface, BlowfishInterface, - blockCipher, streamCipher, keyLen / 8) ); -} - -static bool BF_Cipher_registered = Cipher::Register( - "Blowfish", - // xgroup(setup) - gettext_noop("8 byte block cipher"), - BlowfishInterface, BFKeyRange, BFBlockRange, NewBFCipher, true); -#endif - - -#if defined(HAVE_EVP_AES) - -static Range AESKeyRange(128,256,64); -static Range AESBlockRange(64,4096,16); - -static shared_ptr NewAESCipher( const Interface &iface, int keyLen ) -{ - if( keyLen <= 0 ) - keyLen = 192; - - keyLen = AESKeyRange.closest( keyLen ); - - const EVP_CIPHER *blockCipher = 0; - const EVP_CIPHER *streamCipher = 0; - - switch(keyLen) - { - case 128: - blockCipher = EVP_aes_128_cbc(); - streamCipher = EVP_aes_128_cfb(); - break; - - case 192: - blockCipher = EVP_aes_192_cbc(); - streamCipher = EVP_aes_192_cfb(); - break; - - case 256: - default: - blockCipher = EVP_aes_256_cbc(); - streamCipher = EVP_aes_256_cfb(); - break; - } - - return shared_ptr( new SSL_Cipher(iface, AESInterface, - blockCipher, streamCipher, keyLen / 8) ); -} - -static bool AES_Cipher_registered = Cipher::Register( - "AES", "16 byte block cipher", - AESInterface, AESKeyRange, AESBlockRange, NewAESCipher, true); -#endif - -#if defined(HAVE_EVP_AES_XTS) - -static Range AesXtsKeyRange(128,256,128); -static Range AesXtsBlockRange(1024,8192,256); - -static shared_ptr NewAesXtsCipher( const Interface &iface, int keyLen ) -{ - if( keyLen <= 0 ) - keyLen = 256; - - keyLen = AesXtsKeyRange.closest( keyLen ); - - const EVP_CIPHER *blockCipher = 0; - - switch(keyLen) - { - case 128: - blockCipher = EVP_aes_128_xts(); - break; - - case 256: - default: - blockCipher = EVP_aes_256_xts(); - break; - } - - // XTS uses 2 keys, so the key size is doubled here. - // Eg XTS-AES-256 uses two 256 bit keys. - return shared_ptr( new SSL_Cipher(iface, AesXtsInterface, - blockCipher, NULL, 2 * keyLen / 8) ); -} - -static bool AES_XTS_Cipher_registered = Cipher::Register( - "AES_XTS", "Tweakable wide-block cipher", - AesXtsInterface, AesXtsKeyRange, AesXtsBlockRange, NewAesXtsCipher, false); -#endif - -class SSLKey : public AbstractCipherKey -{ -public: - pthread_mutex_t mutex; - - unsigned int keySize; // in bytes - unsigned int ivLength; - - // key data is first _keySize bytes, - // followed by iv of _ivLength bytes, - SecureMem buf; - - EVP_CIPHER_CTX block_enc; - EVP_CIPHER_CTX block_dec; - EVP_CIPHER_CTX stream_enc; - EVP_CIPHER_CTX stream_dec; - - HMAC_CTX mac_ctx; - - SSLKey(int keySize, int ivLength); - ~SSLKey(); -}; - -SSLKey::SSLKey(int keySize_, int ivLength_) -: buf(keySize_ + ivLength_) -{ - rAssert(keySize_ >= 8); - rAssert(ivLength_ >= 8); - - this->keySize = keySize_; - this->ivLength = ivLength_; - pthread_mutex_init( &mutex, 0 ); -} - -SSLKey::~SSLKey() -{ - keySize = 0; - ivLength = 0; - - EVP_CIPHER_CTX_cleanup( &block_enc ); - EVP_CIPHER_CTX_cleanup( &block_dec ); - - EVP_CIPHER_CTX_cleanup( &stream_enc ); - EVP_CIPHER_CTX_cleanup( &stream_dec ); - - HMAC_CTX_cleanup( &mac_ctx ); - - pthread_mutex_destroy( &mutex ); -} - -inline byte* KeyData( const shared_ptr &key ) -{ - return (byte *)key->buf.data; -} - -inline byte* IVData( const shared_ptr &key ) -{ - return (byte *)key->buf.data + key->keySize; -} - -void initKey(const shared_ptr &key, const EVP_CIPHER *_blockCipher, - const EVP_CIPHER *_streamCipher, int _keySize) -{ - Lock lock( key->mutex ); - // initialize the cipher context once so that we don't have to do it for - // every block.. - EVP_CIPHER_CTX_init( &key->block_enc ); - EVP_CIPHER_CTX_init( &key->block_dec ); - EVP_EncryptInit_ex( &key->block_enc, _blockCipher, NULL, NULL, NULL); - EVP_DecryptInit_ex( &key->block_dec, _blockCipher, NULL, NULL, NULL); - EVP_CIPHER_CTX_set_key_length( &key->block_enc, _keySize ); - EVP_CIPHER_CTX_set_key_length( &key->block_dec, _keySize ); - EVP_CIPHER_CTX_set_padding( &key->block_enc, 0 ); - EVP_CIPHER_CTX_set_padding( &key->block_dec, 0 ); - EVP_EncryptInit_ex( &key->block_enc, NULL, NULL, KeyData(key), NULL); - EVP_DecryptInit_ex( &key->block_dec, NULL, NULL, KeyData(key), NULL); - - EVP_CIPHER_CTX_init( &key->stream_enc ); - EVP_CIPHER_CTX_init( &key->stream_dec ); - if (_streamCipher != NULL) - { - EVP_EncryptInit_ex( &key->stream_enc, _streamCipher, NULL, NULL, NULL); - EVP_DecryptInit_ex( &key->stream_dec, _streamCipher, NULL, NULL, NULL); - EVP_CIPHER_CTX_set_key_length( &key->stream_enc, _keySize ); - EVP_CIPHER_CTX_set_key_length( &key->stream_dec, _keySize ); - EVP_CIPHER_CTX_set_padding( &key->stream_enc, 0 ); - EVP_CIPHER_CTX_set_padding( &key->stream_dec, 0 ); - EVP_EncryptInit_ex( &key->stream_enc, NULL, NULL, KeyData(key), NULL); - EVP_DecryptInit_ex( &key->stream_dec, NULL, NULL, KeyData(key), NULL); - } - - HMAC_CTX_init( &key->mac_ctx ); - HMAC_Init_ex( &key->mac_ctx, KeyData(key), _keySize, EVP_sha1(), 0 ); -} - - -SSL_Cipher::SSL_Cipher(const Interface &iface_, - const Interface &realIface_, - const EVP_CIPHER *blockCipher, - const EVP_CIPHER *streamCipher, - int keySize_) -{ - this->iface = iface_; - this->realIface = realIface_; - this->_blockCipher = blockCipher; - this->_streamCipher = streamCipher; - this->_keySize = keySize_; - this->_ivLength = EVP_CIPHER_iv_length( _blockCipher ); - - rAssert(_ivLength == 8 || _ivLength == 16); - rAssert(_ivLength <= _keySize); - - VLOG(1) << "allocated cipher " << iface.name() - << ", keySize " << _keySize - << ", ivlength " << _ivLength; - - // EVP_CIPHER_key_length isn't useful for variable-length ciphers like - // Blowfish. Version 1 relied upon it incorrectly. - if( (EVP_CIPHER_key_length( _blockCipher ) != (int )_keySize) - && iface.major() == 1) - { - LOG(WARNING) << "Running in backward compatibilty mode for 1.0 - \n" - << "key is really " << EVP_CIPHER_key_length( _blockCipher ) * 8 - << " bits, not " << _keySize * 8; - } -} - -SSL_Cipher::~SSL_Cipher() -{ -} - -Interface SSL_Cipher::interface() const -{ - return realIface; -} - -/* - Create a key from the password. - Use SHA to distribute entropy from the password into the key. - - This algorithm must remain constant for backward compatibility, as this key - is used to encipher/decipher the master key. - */ -CipherKey SSL_Cipher::newKey(const char *password, int passwdLength, - int &iterationCount, long desiredDuration, - const byte *salt, int saltLen) -{ - shared_ptr key( new SSLKey( _keySize, _ivLength) ); - - if(iterationCount == 0) - { - // timed run, fills in iteration count - int res = TimedPBKDF2(password, passwdLength, - salt, saltLen, - _keySize+_ivLength, KeyData(key), - 1000 * desiredDuration); - if(res <= 0) - { - LOG(ERROR) << "openssl error, PBKDF2 failed"; - return CipherKey(); - } else - iterationCount = res; - } else - { - // known iteration length - if(PKCS5_PBKDF2_HMAC_SHA1( - password, passwdLength, - const_cast(salt), saltLen, - iterationCount, _keySize + _ivLength, KeyData(key)) != 1) - { - LOG(ERROR) << "openssl error, PBKDF2 failed"; - return CipherKey(); - } - } - - initKey( key, _blockCipher, _streamCipher, _keySize ); - - return key; -} - -CipherKey SSL_Cipher::newKey(const char *password, int passwdLength) -{ - shared_ptr key( new SSLKey( _keySize, _ivLength) ); - - int bytes = 0; - if( iface.major() > 1 ) - { - // now we use BytesToKey, which can deal with Blowfish keys larger then - // 128 bits. - bytes = BytesToKey( _keySize, _ivLength, EVP_sha1(), - (byte *)password, passwdLength, 16, - KeyData(key), IVData(key) ); - - // the reason for moving from EVP_BytesToKey to BytesToKey function.. - if(bytes != (int)_keySize) - { - LOG(WARNING) << "newKey: BytesToKey returned " << bytes - << ", expecting " << _keySize << " key bytes"; - } - } else - { - // for backward compatibility with filesystems created with 1:0 - bytes = EVP_BytesToKey( _blockCipher, EVP_sha1(), NULL, - (byte *)password, passwdLength, 16, - KeyData(key), IVData(key) ); - } - - initKey( key, _blockCipher, _streamCipher, _keySize ); - - return key; -} - -/* - Create a random key. - We use the OpenSSL library to generate random bytes, then take the hash of - those bytes to use as the key. - - This algorithm can change at any time without affecting backward - compatibility. - */ -CipherKey SSL_Cipher::newRandomKey() -{ - const int bufLen = MAX_KEYLENGTH; - byte tmpBuf[ bufLen ]; - int saltLen = 20; - byte saltBuf[ saltLen ]; - - if(!randomize(tmpBuf, bufLen, true) || - !randomize(saltBuf, saltLen, true)) - return CipherKey(); - - shared_ptr key( new SSLKey( _keySize, _ivLength) ); - - // doesn't need to be versioned, because a random key is a random key.. - // Doesn't need to be reproducable.. - if(PKCS5_PBKDF2_HMAC_SHA1((char*)tmpBuf, bufLen, saltBuf, saltLen, - 1000, _keySize + _ivLength, KeyData(key)) != 1) - { - LOG(ERROR) << "openssl error, PBKDF2 failed"; - return CipherKey(); - } - - OPENSSL_cleanse(tmpBuf, bufLen); - - initKey( key, _blockCipher, _streamCipher, _keySize ); - - return key; -} - -/* - Compute a 64-bit check value for the data using HMAC. - */ -static uint64_t _checksum_64(SSLKey *key, - const byte *data, - int dataLen, - uint64_t *chainedIV) -{ - rAssert( dataLen > 0 ); - Lock lock( key->mutex ); - - byte md[EVP_MAX_MD_SIZE]; - unsigned int mdLen = EVP_MAX_MD_SIZE; - - HMAC_Init_ex( &key->mac_ctx, 0, 0, 0, 0 ); - HMAC_Update( &key->mac_ctx, data, dataLen ); - if(chainedIV) - { - // toss in the chained IV as well - uint64_t tmp = *chainedIV; - byte h[8]; - for(unsigned int i=0; i<8; ++i) - { - h[i] = tmp & 0xff; - tmp >>= 8; - } - - HMAC_Update( &key->mac_ctx, h, 8 ); - } - - HMAC_Final( &key->mac_ctx, md, &mdLen ); - - rAssert(mdLen >= 8); - - // chop this down to a 64bit value.. - byte h[8] = {0,0,0,0,0,0,0,0}; - for(unsigned int i=0; i<(mdLen-1); ++i) - h[i%8] ^= (byte)(md[i]); - - uint64_t value = (uint64_t)h[0]; - for(int i=1; i<8; ++i) - value = (value << 8) | (uint64_t)h[i]; - - return value; -} - -bool SSL_Cipher::randomize( byte *buf, int len, - bool strongRandom ) const -{ - // to avoid warnings of uninitialized data from valgrind - memset(buf, 0, len); - int result; - if(strongRandom) - result = RAND_bytes( buf, len ); - else - result = RAND_pseudo_bytes( buf, len ); - - if(result != 1) - { - char errStr[120]; // specs require string at least 120 bytes long.. - unsigned long errVal = 0; - if((errVal = ERR_get_error()) != 0) - LOG(ERROR) << "openssl error: " << ERR_error_string( errVal, errStr ); - - return false; - } else - return true; -} - -uint64_t SSL_Cipher::MAC_64( const byte *data, int len, - const CipherKey &key, uint64_t *chainedIV ) const -{ - shared_ptr mk = dynamic_pointer_cast(key); - uint64_t tmp = _checksum_64( mk.get(), data, len, chainedIV ); - - if(chainedIV) - *chainedIV = tmp; - - return tmp; -} - -CipherKey SSL_Cipher::readKey(const byte *data, - const CipherKey &masterKey, bool checkKey) -{ - shared_ptr mk = dynamic_pointer_cast(masterKey); - rAssert(mk->keySize == _keySize); - - byte tmpBuf[ 2 * MAX_KEYLENGTH ]; - - // First N bytes are checksum bytes. - unsigned int checksum = 0; - for(int i=0; i key( new SSLKey( _keySize, _ivLength) ); - - rAssert(_keySize + _ivLength == (unsigned int)key->buf.size ); - memcpy( key->buf.data, tmpBuf, key->buf.size ); - OPENSSL_cleanse(tmpBuf, sizeof(tmpBuf)); - - initKey( key, _blockCipher, _streamCipher, _keySize ); - - return key; -} - -void SSL_Cipher::writeKey(const CipherKey &ckey, byte *data, - const CipherKey &masterKey) -{ - shared_ptr key = dynamic_pointer_cast(ckey); - rAssert(key->keySize == _keySize); - rAssert(key->ivLength == _ivLength); - - shared_ptr mk = dynamic_pointer_cast(masterKey); - rAssert(mk->keySize == _keySize); - rAssert(mk->ivLength == _ivLength); - - byte tmpBuf[ 2 * MAX_KEYLENGTH ]; - - unsigned int bufLen = key->buf.size; - rAssert(_keySize + _ivLength == bufLen ); - memcpy( tmpBuf, key->buf.data, bufLen ); - - unsigned int checksum = MAC_32( tmpBuf, bufLen, masterKey ); - - if (_streamCipher != NULL) - streamEncode(tmpBuf, bufLen, checksum, masterKey); - else - { - bufLen = 2 * _keySize; - blockEncode(tmpBuf, bufLen, checksum, masterKey); - } - - memcpy( data+KEY_CHECKSUM_BYTES, tmpBuf, bufLen ); - - // first N bytes contain HMAC derived checksum.. - for(int i=1; i<=KEY_CHECKSUM_BYTES; ++i) - { - data[KEY_CHECKSUM_BYTES-i] = checksum & 0xff; - checksum >>= 8; - } - - OPENSSL_cleanse(tmpBuf, sizeof(tmpBuf)); -} - -bool SSL_Cipher::compareKey( const CipherKey &A, const CipherKey &B) const -{ - shared_ptr key1 = dynamic_pointer_cast(A); - shared_ptr key2 = dynamic_pointer_cast(B); - - rAssert(key1->buf.size == key2->buf.size); - - if(memcmp(key1->buf.data, key2->buf.data, key1->buf.size) != 0) - return false; - else - return true; -} - -int SSL_Cipher::encodedKeySize() const -{ - if (_streamCipher != NULL) - return _keySize + _ivLength + KEY_CHECKSUM_BYTES; - else - return 2 * _keySize + KEY_CHECKSUM_BYTES; -} - -int SSL_Cipher::keySize() const -{ - return _keySize; -} - -int SSL_Cipher::cipherBlockSize() const -{ - int size = EVP_CIPHER_block_size( _blockCipher ); - // OpenSSL (1.0.1-4ubuntu5.5) reports a block size of 1 for aes_xts. - // If this happens, use a single key width (ie 32 bytes for aes-xts-256). - if (size == 1) - size = _keySize / 2; - return size; -} - -void SSL_Cipher::setIVec(byte *ivec, uint64_t seed, - const shared_ptr &key) const -{ - if (iface.major() >= 3) - { - memcpy( ivec, IVData(key), _ivLength ); - - byte md[EVP_MAX_MD_SIZE]; - unsigned int mdLen = EVP_MAX_MD_SIZE; - - for(int i=0; i<8; ++i) - { - md[i] = (byte)(seed & 0xff); - seed >>= 8; - } - - // combine ivec and seed with HMAC - HMAC_Init_ex( &key->mac_ctx, 0, 0, 0, 0 ); - HMAC_Update( &key->mac_ctx, ivec, _ivLength ); - HMAC_Update( &key->mac_ctx, md, 8 ); - HMAC_Final( &key->mac_ctx, md, &mdLen ); - rAssert(mdLen >= _ivLength); - - memcpy( ivec, md, _ivLength ); - } else - { - setIVec_old(ivec, seed, key); - } -} - -// Deprecated: For backward compatibility only. -// A watermark attack was discovered against this IV setup. If an attacker -// could get a victim to store a carefully crafted file, they could later -// determine if the victim had the file in encrypted storage (without decrypting -// the file). -void SSL_Cipher::setIVec_old(byte *ivec, - unsigned int seed, - const shared_ptr &key) const -{ - unsigned int var1 = 0x060a4011 * seed; - unsigned int var2 = 0x0221040d * (seed ^ 0xD3FEA11C); - - memcpy( ivec, IVData(key), _ivLength ); - - ivec[0] ^= (var1 >> 24) & 0xff; - ivec[1] ^= (var2 >> 16) & 0xff; - ivec[2] ^= (var1 >> 8 ) & 0xff; - ivec[3] ^= (var2 ) & 0xff; - ivec[4] ^= (var2 >> 24) & 0xff; - ivec[5] ^= (var1 >> 16) & 0xff; - ivec[6] ^= (var2 >> 8 ) & 0xff; - ivec[7] ^= (var1 ) & 0xff; - - if(_ivLength > 8) - { - ivec[8+0] ^= (var1 ) & 0xff; - ivec[8+1] ^= (var2 >> 8 ) & 0xff; - ivec[8+2] ^= (var1 >> 16) & 0xff; - ivec[8+3] ^= (var2 >> 24) & 0xff; - ivec[8+4] ^= (var1 >> 24) & 0xff; - ivec[8+5] ^= (var2 >> 16) & 0xff; - ivec[8+6] ^= (var1 >> 8 ) & 0xff; - ivec[8+7] ^= (var2 ) & 0xff; - } -} - -static void flipBytes(byte *buf, int size) -{ - byte revBuf[64]; - - int bytesLeft = size; - while(bytesLeft) - { - int toFlip = MIN( (int)sizeof(revBuf), bytesLeft ); - - for(int i=0; i 0 ); - shared_ptr key = dynamic_pointer_cast(ckey); - rAssert(key->keySize == _keySize); - rAssert(key->ivLength == _ivLength); - rAssert( key->stream_enc.key_len > 0 ); - - Lock lock( key->mutex ); - - byte ivec[ MAX_IVLENGTH ]; - int dstLen=0, tmpLen=0; - - shuffleBytes( buf, size ); - - setIVec( ivec, iv64, key ); - EVP_EncryptInit_ex( &key->stream_enc, NULL, NULL, NULL, ivec); - EVP_EncryptUpdate( &key->stream_enc, buf, &dstLen, buf, size ); - EVP_EncryptFinal_ex( &key->stream_enc, buf+dstLen, &tmpLen ); - - flipBytes( buf, size ); - shuffleBytes( buf, size ); - - setIVec( ivec, iv64 + 1, key ); - EVP_EncryptInit_ex( &key->stream_enc, NULL, NULL, NULL, ivec); - EVP_EncryptUpdate( &key->stream_enc, buf, &dstLen, buf, size ); - EVP_EncryptFinal_ex( &key->stream_enc, buf+dstLen, &tmpLen ); - - dstLen += tmpLen; - LOG_IF(ERROR, dstLen != size) << "encoding " << size - << " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; - - return true; -} - -bool SSL_Cipher::streamDecode(byte *buf, int size, - uint64_t iv64, const CipherKey &ckey) const -{ - rAssert( size > 0 ); - shared_ptr key = dynamic_pointer_cast(ckey); - rAssert(key->keySize == _keySize); - rAssert(key->ivLength == _ivLength); - rAssert( key->stream_dec.key_len > 0 ); - - Lock lock( key->mutex ); - - byte ivec[ MAX_IVLENGTH ]; - int dstLen=0, tmpLen=0; - - setIVec( ivec, iv64 + 1, key ); - EVP_DecryptInit_ex( &key->stream_dec, NULL, NULL, NULL, ivec); - EVP_DecryptUpdate( &key->stream_dec, buf, &dstLen, buf, size ); - EVP_DecryptFinal_ex( &key->stream_dec, buf+dstLen, &tmpLen ); - - unshuffleBytes( buf, size ); - flipBytes( buf, size ); - - setIVec( ivec, iv64, key ); - EVP_DecryptInit_ex( &key->stream_dec, NULL, NULL, NULL, ivec); - EVP_DecryptUpdate( &key->stream_dec, buf, &dstLen, buf, size ); - EVP_DecryptFinal_ex( &key->stream_dec, buf+dstLen, &tmpLen ); - - unshuffleBytes( buf, size ); - - dstLen += tmpLen; - LOG_IF(ERROR, dstLen != size) << "encoding " << size - << " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; - - return true; -} - - -bool SSL_Cipher::blockEncode(byte *buf, int size, - uint64_t iv64, const CipherKey &ckey ) const -{ - rAssert( size > 0 ); - shared_ptr key = dynamic_pointer_cast(ckey); - rAssert(key->keySize == _keySize); - rAssert(key->ivLength == _ivLength); - - // data must be integer number of blocks - const int blockMod = size % EVP_CIPHER_CTX_block_size( &key->block_enc ); - rAssert(blockMod == 0); - - Lock lock( key->mutex ); - - byte ivec[ MAX_IVLENGTH ]; - - int dstLen = 0, tmpLen = 0; - setIVec( ivec, iv64, key ); - - EVP_EncryptInit_ex( &key->block_enc, NULL, NULL, NULL, ivec); - EVP_EncryptUpdate( &key->block_enc, buf, &dstLen, buf, size ); - EVP_EncryptFinal_ex( &key->block_enc, buf+dstLen, &tmpLen ); - dstLen += tmpLen; - - LOG_IF(ERROR, dstLen != size) << "encoding " << size - << " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; - - return true; -} - -bool SSL_Cipher::blockDecode(byte *buf, int size, - uint64_t iv64, const CipherKey &ckey ) const -{ - rAssert( size > 0 ); - shared_ptr key = dynamic_pointer_cast(ckey); - rAssert(key->keySize == _keySize); - rAssert(key->ivLength == _ivLength); - - // data must be integer number of blocks - const int blockMod = size % EVP_CIPHER_CTX_block_size( &key->block_dec ); - rAssert(blockMod == 0); - - Lock lock( key->mutex ); - - byte ivec[ MAX_IVLENGTH ]; - - int dstLen = 0, tmpLen = 0; - setIVec( ivec, iv64, key ); - - EVP_DecryptInit_ex( &key->block_dec, NULL, NULL, NULL, ivec); - EVP_DecryptUpdate( &key->block_dec, buf, &dstLen, buf, size ); - EVP_DecryptFinal_ex( &key->block_dec, buf+dstLen, &tmpLen ); - dstLen += tmpLen; - - LOG_IF(ERROR, dstLen != size) << "decoding " << size - << " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; - - return true; -} - -bool SSL_Cipher::Enabled() -{ - return true; -} - -bool SSL_Cipher::hasStreamMode() const -{ - return false; -} - -} // namespace encfs diff --git a/cipher/StreamCipher.cpp b/cipher/StreamCipher.cpp index c12e31a..ef92dba 100644 --- a/cipher/StreamCipher.cpp +++ b/cipher/StreamCipher.cpp @@ -2,11 +2,7 @@ namespace encfs { -Registry& StreamCipher::GetRegistry() -{ - static Registry registry; - return registry; -} +DEFINE_REGISTERABLE_TYPE(StreamCipher); StreamCipher::StreamCipher() { diff --git a/cipher/StreamCipher.h b/cipher/StreamCipher.h index 6efb6e0..3a54e1e 100644 --- a/cipher/StreamCipher.h +++ b/cipher/StreamCipher.h @@ -26,26 +26,32 @@ #include "base/Registry.h" #include "base/shared_ptr.h" #include "base/types.h" +#include "cipher/CipherKey.h" namespace encfs { +static const char NAME_AES_CFB[] = "AES/CFB"; +static const char NAME_BLOWFISH_CFB[] = "Blowfish/CFB"; + class StreamCipher { public: - static Registry& GetRegistry(); + DECLARE_REGISTERABLE_TYPE(StreamCipher); struct Properties { Range keySize; std::string cipher; std::string mode; std::string library; + std::string toString() const { + return cipher + "/" + mode; + } }; StreamCipher(); virtual ~StreamCipher(); - virtual bool setKey(const byte *key, int keyLength) =0; - virtual bool randomKey(int keyLength) =0; + virtual bool setKey(const CipherKey& key) =0; virtual bool encrypt(const byte *iv, const byte *in, byte *out, int numBytes) =0; diff --git a/cipher/openssl.cpp b/cipher/openssl.cpp index 9ec2982..ebf5f63 100644 --- a/cipher/openssl.cpp +++ b/cipher/openssl.cpp @@ -74,6 +74,8 @@ inline int MIN(int a, int b) class OpenSSLCipher : public BlockCipher { public: OpenSSLCipher() { + EVP_CIPHER_CTX_init( &enc ); + EVP_CIPHER_CTX_init( &dec ); } virtual ~OpenSSLCipher() { @@ -81,23 +83,36 @@ class OpenSSLCipher : public BlockCipher { EVP_CIPHER_CTX_cleanup( &dec ); } - bool rekey(const EVP_CIPHER *cipher, const byte *key, int length) { - EVP_CIPHER_CTX_init( &enc ); + bool rekey(const EVP_CIPHER *cipher, const CipherKey &key) { + VLOG(1) << "setting key length " << key.size(); EVP_EncryptInit_ex( &enc, cipher, NULL, NULL, NULL); - EVP_CIPHER_CTX_set_key_length( &enc, length ); + EVP_CIPHER_CTX_set_key_length( &enc, key.size() ); EVP_CIPHER_CTX_set_padding( &enc, 0 ); - EVP_EncryptInit_ex( &enc, NULL, NULL, key, NULL); + EVP_EncryptInit_ex( &enc, NULL, NULL, key.data(), NULL); - EVP_CIPHER_CTX_init( &dec ); EVP_DecryptInit_ex( &dec, cipher, NULL, NULL, NULL); - EVP_CIPHER_CTX_set_key_length( &dec, length ); + EVP_CIPHER_CTX_set_key_length( &dec, key.size() ); EVP_CIPHER_CTX_set_padding( &dec, 0 ); - EVP_DecryptInit_ex( &dec, NULL, NULL, key, NULL); + EVP_DecryptInit_ex( &dec, NULL, NULL, key.data(), NULL); return true; } - static bool randomize(byte *out, int len) { - int result = RAND_bytes( out, len ); + static bool randomize(CipherKey *key) { + int result = RAND_bytes( key->data(), key->size() ); + if(result != 1) + { + char errStr[120]; // specs require string at least 120 bytes long.. + unsigned long errVal = 0; + if((errVal = ERR_get_error()) != 0) + LOG(ERROR) << "openssl error: " << ERR_error_string( errVal, errStr ); + + return false; + } + return true; + } + + static bool pseudoRandomize(byte *out, int length) { + int result = RAND_pseudo_bytes( out, length ); if(result != 1) { char errStr[120]; // specs require string at least 120 bytes long.. @@ -112,12 +127,12 @@ class OpenSSLCipher : public BlockCipher { // Rekey with random key. bool rekey(const EVP_CIPHER *cipher, int keyLength) { - SecureMem key(keyLength); + CipherKey key(keyLength); - if (!randomize(key.data, key.size)) + if (!randomize(&key)) return false; - return rekey(cipher, key.data, key.size); + return rekey(cipher, key); } virtual int blockSize() const { @@ -171,17 +186,13 @@ class BfCbcBlockCipher : public OpenSSLCipher { BfCbcBlockCipher() {} virtual ~BfCbcBlockCipher() {} - virtual bool setKey(const byte *key, int length) { - if (BfKeyRange.allowed(length * 8)) - return rekey(EVP_bf_cbc(), key, length); + virtual bool setKey(const CipherKey &key) { + if (BfKeyRange.allowed(key.size() * 8)) + return rekey(EVP_bf_cbc(), key); else return false; } - virtual bool randomKey(int length) { - return BfKeyRange.allowed(length * 8) && rekey(EVP_bf_cbc(), length); - } - static Properties GetProperties() { Properties props; props.keySize = BfKeyRange; @@ -198,12 +209,8 @@ class BfCfbStreamCipher : public OpenSSLCipher { BfCfbStreamCipher() {} virtual ~BfCfbStreamCipher() {} - virtual bool setKey(const byte *key, int length) { - return BfKeyRange.allowed(length * 8) && rekey(EVP_bf_cfb(), key, length); - } - - virtual bool randomKey(int length) { - return BfKeyRange.allowed(length * 8) && rekey(EVP_bf_cfb(), length); + virtual bool setKey(const CipherKey &key) { + return BfKeyRange.allowed(key.size() * 8) && rekey(EVP_bf_cfb(), key); } static Properties GetProperties() { @@ -226,14 +233,9 @@ class AesCbcBlockCipher : public OpenSSLCipher { AesCbcBlockCipher() {} virtual ~AesCbcBlockCipher() {} - virtual bool setKey(const byte *key, int length) { - const EVP_CIPHER *cipher = getCipher(length); - return (cipher != NULL) && rekey(cipher, key, length); - } - - virtual bool randomKey(int length) { - const EVP_CIPHER *cipher = getCipher(length); - return (cipher != NULL) && rekey(cipher, length); + virtual bool setKey(const CipherKey& key) { + const EVP_CIPHER *cipher = getCipher(key.size()); + return (cipher != NULL) && rekey(cipher, key); } static const EVP_CIPHER *getCipher(int keyLength) { @@ -243,6 +245,7 @@ class AesCbcBlockCipher : public OpenSSLCipher { case 192: return EVP_aes_192_cbc(); case 256: return EVP_aes_256_cbc(); default: + LOG(INFO) << "Unsupported key length: " << keyLength; return NULL; } } @@ -257,6 +260,39 @@ class AesCbcBlockCipher : public OpenSSLCipher { } }; REGISTER_CLASS(AesCbcBlockCipher, BlockCipher); + +class AesCfbStreamCipher : public OpenSSLCipher { + public: + AesCfbStreamCipher() {} + virtual ~AesCfbStreamCipher() {} + + virtual bool setKey(const CipherKey& key) { + const EVP_CIPHER *cipher = getCipher(key.size()); + return (cipher != NULL) && rekey(cipher, key); + } + + static const EVP_CIPHER *getCipher(int keyLength) { + switch(keyLength * 8) + { + case 128: return EVP_aes_128_cfb(); + case 192: return EVP_aes_192_cfb(); + case 256: return EVP_aes_256_cfb(); + default: + LOG(INFO) << "Unsupported key length: " << keyLength; + return NULL; + } + } + + static Properties GetProperties() { + Properties props; + props.keySize = AesKeyRange; + props.cipher = "AES"; + props.mode = "CFB"; + props.library = "OpenSSL"; + return props; + } +}; +REGISTER_CLASS(AesCfbStreamCipher, StreamCipher); #endif #if defined(HAVE_EVP_AES_XTS) @@ -266,14 +302,9 @@ class AesXtsBlockCipher : public OpenSSLCipher { AesXtsBlockCipher() {} virtual ~AesXtsBlockCipher() {} - virtual bool setKey(const byte *key, int length) { - const EVP_CIPHER *cipher = getCipher(length); - return (cipher != NULL) && rekey(cipher, key, length); - } - - virtual bool randomKey(int length) { - const EVP_CIPHER *cipher = getCipher(length); - return (cipher != NULL) && rekey(cipher, length); + virtual bool setKey(const CipherKey &key) { + const EVP_CIPHER *cipher = getCipher(key.size()); + return (cipher != NULL) && rekey(cipher, key); } static const EVP_CIPHER *getCipher(int keyLength) { @@ -297,9 +328,11 @@ class AesXtsBlockCipher : public OpenSSLCipher { REGISTER_CLASS(AesXtsBlockCipher, BlockCipher); #endif -class Sha1HMac : public MessageAuthenticationCode { +class Sha1HMac : public MAC { public: - Sha1HMac() {} + Sha1HMac() { + HMAC_CTX_init(&ctx); + } virtual ~Sha1HMac() { HMAC_CTX_cleanup(&ctx); } @@ -308,19 +341,11 @@ class Sha1HMac : public MessageAuthenticationCode { return 20; // 160 bit. } - virtual bool setKey(const byte *key, int keyLength) { - HMAC_CTX_init(&ctx); - HMAC_Init_ex(&ctx, key, keyLength, EVP_sha1(), 0); + virtual bool setKey(const CipherKey &key) { + HMAC_Init_ex(&ctx, key.data(), key.size(), EVP_sha1(), 0); return true; } - virtual bool randomKey(int keyLength) { - SecureMem key(keyLength); - - return OpenSSLCipher::randomize(key.data, key.size) - && setKey(key.data, key.size); - } - virtual void reset() { HMAC_Init_ex(&ctx, 0, 0, 0, 0); } @@ -331,6 +356,11 @@ class Sha1HMac : public MessageAuthenticationCode { } virtual bool write(byte *out) { +#ifdef HAVE_VALGRIND_MEMCHECK_H + if (VALGRIND_CHECK_MEM_IS_ADDRESSABLE(out, 20) != 0) { + return false; + } +#endif unsigned int outSize = 0; HMAC_Final(&ctx, (unsigned char *)out, &outSize); CHECK_EQ(outputSize(), outSize) << "Invalid HMAC output size"; @@ -348,7 +378,7 @@ class Sha1HMac : public MessageAuthenticationCode { private: HMAC_CTX ctx; }; -REGISTER_CLASS(Sha1HMac, MessageAuthenticationCode); +REGISTER_CLASS(Sha1HMac, MAC); class PbkdfPkcs5HmacSha1 : public PBKDF { @@ -359,16 +389,27 @@ class PbkdfPkcs5HmacSha1 : public PBKDF { virtual bool makeKey(const char *password, int passwordLength, const byte *salt, int saltLength, int numIterations, - byte *outKey, int keyLength) const { + CipherKey *outKey) { return PKCS5_PBKDF2_HMAC_SHA1( password, passwordLength, const_cast(salt), saltLength, - numIterations, keyLength, outKey) == 1; + numIterations, outKey->size(), outKey->data()) == 1; + } + + virtual CipherKey randomKey(int length) { + CipherKey key(length); + if (!OpenSSLCipher::randomize(&key)) + key.reset(); + return key; + } + + virtual bool pseudoRandom(byte *out, int length) { + return OpenSSLCipher::pseudoRandomize(out, length); } static Properties GetProperties() { Properties props; - props.mode = "PKCS5_PBKDF2_HMAC_SHA1"; + props.mode = NAME_PKCS5_PBKDF2_HMAC_SHA1; props.library = "OpenSSL"; return props; } diff --git a/cipher/testing.cpp b/cipher/testing.cpp index 0af7ce1..547b694 100644 --- a/cipher/testing.cpp +++ b/cipher/testing.cpp @@ -5,9 +5,9 @@ namespace encfs { -std::string stringToHex(const byte *data, int len) { - static const char lookup[] = "0123456789abcdef"; +static const char hexLut[] = "0123456789abcdef"; +std::string stringToHex(const byte *data, int len) { std::string out; out.reserve(2 * len); for (int i = 0; i < len; ++i) { @@ -15,12 +15,39 @@ std::string stringToHex(const byte *data, int len) { int first = (unsigned int)c >> 4; int second = (unsigned int)c & 15; - out.push_back(lookup[first]); - out.push_back(lookup[second]); + out.push_back(hexLut[first]); + out.push_back(hexLut[second]); } return out; } +void setDataFromHex(byte *out, int len, const char *hex) { + bool odd = false; + unsigned int last = 0; + while (len > 0 && *hex != '\0') { + byte nibble = *hex++; + if (nibble >= '0' && nibble <= '9') + nibble -= '0'; + else if (nibble >= 'A' && nibble <= 'F') + nibble -= 'A' - 10; + else if (nibble >= 'a' && nibble <= 'f') + nibble -= 'a' - 10; + else + nibble = 0; + + last |= (unsigned int)nibble; + if (odd) { + *out++ = (byte)last; + --len; + last = 0; + odd = false; + } else { + last <<= 4; + odd = true; + } + } +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/cipher/testing.h b/cipher/testing.h index a2aa9ad..484e36b 100644 --- a/cipher/testing.h +++ b/cipher/testing.h @@ -30,6 +30,13 @@ namespace encfs { std::string stringToHex(const byte *data, int len); +template +std::string stringToHex(const T& value) { + return stringToHex(value.data(), value.size()); +} + +void setDataFromHex(byte *out, int size, const char *hex); + } // namespace encfs #endif diff --git a/encfs/main.cpp b/encfs/main.cpp index 64ce2d2..f1cfbc4 100644 --- a/encfs/main.cpp +++ b/encfs/main.cpp @@ -475,14 +475,16 @@ void encfs_destroy( void *_ctx ) { ctx->running = false; +#ifdef CMAKE_USE_PTHREADS_INIT // wake up the thread if it is waiting.. VLOG(1) << "waking up monitoring thread"; - pthread_mutex_lock( &ctx->wakeupMutex ); + ctx->wakeupMutex.lock(); pthread_cond_signal( &ctx->wakeupCond ); - pthread_mutex_unlock( &ctx->wakeupMutex ); + ctx->wakeupMutex.unlock(); VLOG(1) << "joining with idle monitoring thread"; pthread_join( ctx->monitorThread , 0 ); VLOG(1) << "join done"; +#endif } } @@ -695,7 +697,7 @@ void * idleMonitor(void *_arg) const int timeoutCycles = 60 * arg->idleTimeout / ActivityCheckInterval; int idleCycles = 0; - pthread_mutex_lock( &ctx->wakeupMutex ); + ctx->wakeupMutex.lock(); while(ctx->running) { @@ -711,8 +713,10 @@ void * idleMonitor(void *_arg) int openCount = ctx->openFileCount(); if( openCount == 0 && unmountFS( ctx ) ) { +#ifdef CMAKE_USE_PTHREADS_INIT // wait for main thread to wake us up - pthread_cond_wait( &ctx->wakeupCond, &ctx->wakeupMutex ); + pthread_cond_wait( &ctx->wakeupCond, &ctx->wakeupMutex._mutex ); +#endif break; } @@ -727,11 +731,13 @@ void * idleMonitor(void *_arg) struct timespec wakeupTime; wakeupTime.tv_sec = currentTime.tv_sec + ActivityCheckInterval; wakeupTime.tv_nsec = currentTime.tv_usec * 1000; +#ifdef CMAKE_USE_PTHREADS_INIT pthread_cond_timedwait( &ctx->wakeupCond, - &ctx->wakeupMutex, &wakeupTime ); + &ctx->wakeupMutex._mutex, &wakeupTime ); +#endif } - pthread_mutex_unlock( &ctx->wakeupMutex ); + ctx->wakeupMutex.unlock(); VLOG(1) << "Idle monitoring thread exiting"; diff --git a/fs/BlockNameIO.cpp b/fs/BlockNameIO.cpp index 3b78f54..293e76f 100644 --- a/fs/BlockNameIO.cpp +++ b/fs/BlockNameIO.cpp @@ -23,7 +23,7 @@ #include "base/base64.h" #include "base/Error.h" #include "base/i18n.h" -#include "cipher/Cipher.h" +#include "cipher/CipherV1.h" #include #include @@ -31,17 +31,17 @@ namespace encfs { static shared_ptr NewBlockNameIO( const Interface &iface, - const shared_ptr &cipher, const CipherKey &key ) + const shared_ptr &cipher ) { return shared_ptr( - new BlockNameIO( iface, cipher, key, false)); + new BlockNameIO( iface, cipher, false)); } static shared_ptr NewBlockNameIO32( const Interface &iface, - const shared_ptr &cipher, const CipherKey &key ) + const shared_ptr &cipher ) { return shared_ptr( - new BlockNameIO( iface, cipher, key, true)); + new BlockNameIO( iface, cipher, true)); } static bool BlockIO_registered = NameIO::Register("Block", @@ -85,12 +85,11 @@ Interface BlockNameIO::CurrentInterface(bool caseSensitive) } BlockNameIO::BlockNameIO( const Interface &iface, - const shared_ptr &cipher, - const CipherKey &key, bool caseSensitiveEncoding ) + const shared_ptr &cipher, + bool caseSensitiveEncoding ) : _interface( iface.major() ) , _bs( cipher->cipherBlockSize() ) , _cipher( cipher ) - , _key( key ) , _caseSensitive( caseSensitiveEncoding ) { rAssert( _bs < 128 ); @@ -144,15 +143,16 @@ int BlockNameIO::encodeName( const char *plaintextName, int length, tmpIV = *iv; // include padding in MAC computation - unsigned int mac = _cipher->MAC_16( (unsigned char *)encodedName+2, - length+padding, _key, iv ); + unsigned int mac = _cipher->reduceMac16( + _cipher->MAC_64( (unsigned char *)encodedName+2, + length+padding, iv )); // add checksum bytes encodedName[0] = (mac >> 8) & 0xff; encodedName[1] = (mac ) & 0xff; _cipher->blockEncode( (unsigned char *)encodedName+2, length+padding, - (uint64_t)mac ^ tmpIV, _key); + (uint64_t)mac ^ tmpIV ); // convert to base 64 ascii int encodedStreamLen = length + 2 + padding; @@ -211,7 +211,7 @@ int BlockNameIO::decodeName( const char *encodedName, int length, tmpIV = *iv; _cipher->blockDecode( (unsigned char *)tmpBuf+2, decodedStreamLen, - (uint64_t)mac ^ tmpIV, _key); + (uint64_t)mac ^ tmpIV ); // find out true string length int padding = (unsigned char)tmpBuf[2+decodedStreamLen-1]; @@ -230,8 +230,9 @@ int BlockNameIO::decodeName( const char *encodedName, int length, plaintextName[finalSize] = '\0'; // check the mac - unsigned int mac2 = _cipher->MAC_16((const unsigned char *)tmpBuf+2, - decodedStreamLen, _key, iv); + unsigned int mac2 = _cipher->reduceMac16( + _cipher->MAC_64((const unsigned char *)tmpBuf+2, + decodedStreamLen, iv)); BUFFER_RESET( tmpBuf ); diff --git a/fs/BlockNameIO.h b/fs/BlockNameIO.h index cfce608..bd19791 100644 --- a/fs/BlockNameIO.h +++ b/fs/BlockNameIO.h @@ -21,14 +21,13 @@ #ifndef _BlockNameIO_incl_ #define _BlockNameIO_incl_ -#include "cipher/CipherKey.h" #include "fs/NameIO.h" #include namespace encfs { -class Cipher; +class CipherV1; /* Implement NameIO interface for filename encoding. Uses cipher in block @@ -37,34 +36,32 @@ class Cipher; */ class BlockNameIO : public NameIO { -public: - static Interface CurrentInterface(bool caseSensitive = false); + public: + static Interface CurrentInterface(bool caseSensitive = false); - BlockNameIO( const Interface &iface, - const shared_ptr &cipher, - const CipherKey &key, - bool caseSensitiveEncoding = false ); - virtual ~BlockNameIO(); + BlockNameIO(const Interface &iface, + const shared_ptr &cipher, + bool caseSensitiveEncoding = false ); + virtual ~BlockNameIO(); - virtual Interface interface() const; + virtual Interface interface() const; - virtual int maxEncodedNameLen( int plaintextNameLen ) const; - virtual int maxDecodedNameLen( int encodedNameLen ) const; + virtual int maxEncodedNameLen( int plaintextNameLen ) const; + virtual int maxDecodedNameLen( int encodedNameLen ) const; - // hack to help with static builds - static bool Enabled(); -protected: - virtual int encodeName( const char *plaintextName, int length, - uint64_t *iv, char *encodedName ) const; - virtual int decodeName( const char *encodedName, int length, - uint64_t *iv, char *plaintextName ) const; + // hack to help with static builds + static bool Enabled(); + protected: + virtual int encodeName(const char *plaintextName, int length, + uint64_t *iv, char *encodedName ) const; + virtual int decodeName(const char *encodedName, int length, + uint64_t *iv, char *plaintextName ) const; -private: - int _interface; - int _bs; - shared_ptr _cipher; - CipherKey _key; - bool _caseSensitive; + private: + int _interface; + int _bs; + shared_ptr _cipher; + bool _caseSensitive; }; } // namespace encfs diff --git a/fs/CipherFileIO.cpp b/fs/CipherFileIO.cpp index e2cde83..762a090 100644 --- a/fs/CipherFileIO.cpp +++ b/fs/CipherFileIO.cpp @@ -21,7 +21,7 @@ #include "fs/CipherFileIO.h" #include "base/Error.h" -#include "cipher/Cipher.h" +#include "cipher/CipherV1.h" #include "cipher/MemoryPool.h" #include "fs/fsconfig.pb.h" @@ -33,9 +33,6 @@ namespace encfs { /* - Version 3:0 adds support for block-only encryption by adding space for - a full block to the file header. - Version 2:0 adds support for a per-file initialization vector with a fixed 8 byte header. The headers are enabled globally within a filesystem at the filesystem configuration level. @@ -48,7 +45,6 @@ CipherFileIO::CipherFileIO( const shared_ptr &_base, : BlockFileIO( cfg->config->block_size(), cfg ) , base( _base ) , headerLen( 0 ) - , blockOnlyMode( cfg->config->block_mode_only() ) , perFileIV( cfg->config->unique_iv() ) , externalIV( 0 ) , fileIV( 0 ) @@ -56,18 +52,9 @@ CipherFileIO::CipherFileIO( const shared_ptr &_base, { fsConfig = cfg; cipher = cfg->cipher; - key = cfg->key; - if ( blockOnlyMode ) - { - headerLen += blockSize(); - if ( perFileIV ) - headerLen += cipher->cipherBlockSize(); - } else - { - if ( perFileIV ) - headerLen += sizeof(uint64_t); // 64bit IV per file - } + if ( perFileIV ) + headerLen += sizeof(uint64_t); // 64bit IV per file int blockBoundary = fsConfig->config->block_size() % fsConfig->cipher->cipherBlockSize(); @@ -200,19 +187,13 @@ void CipherFileIO::initHeader( ) IORequest req; req.offset = 0; - if (blockOnlyMode) - req.offset += blockSize(); - req.data = mb.data; - req.dataLen = blockOnlyMode ? cbs : sizeof(uint64_t); + req.dataLen = sizeof(uint64_t); base->read( req ); if (perFileIV) { - if (blockOnlyMode) - cipher->blockDecode( mb.data, cbs, externalIV, key ); - else - cipher->streamDecode( mb.data, sizeof(uint64_t), externalIV, key ); + cipher->streamDecode( mb.data, sizeof(uint64_t), externalIV ); fileIV = 0; for(unsigned int i=0; irandomize( mb.data, 8, false )) + if(!cipher->pseudoRandomize( mb.data, 8 )) throw Error("Unable to generate a random file IV"); fileIV = 0; @@ -237,20 +218,14 @@ void CipherFileIO::initHeader( ) << "Unexpected result: randomize returned 8 null bytes!"; } while(fileIV == 0); // don't accept 0 as an option.. - if (blockOnlyMode) - cipher->blockEncode( mb.data, cbs, externalIV, key ); - else - cipher->streamEncode( mb.data, sizeof(uint64_t), externalIV, key ); + cipher->streamEncode( mb.data, sizeof(uint64_t), externalIV ); if( base->isWritable() ) { IORequest req; req.offset = 0; - if (blockOnlyMode) - req.offset += blockSize(); - req.data = mb.data; - req.dataLen = blockOnlyMode ? cbs : sizeof(uint64_t); + req.dataLen = sizeof(uint64_t); base->write( req ); } else @@ -281,8 +256,7 @@ bool CipherFileIO::writeHeader( ) if (perFileIV) { - int cbs = cipher->cipherBlockSize(); - unsigned char *buf = mb.data + (blockOnlyMode ? blockSize() : 0); + unsigned char *buf = mb.data; for(int i=sizeof(buf)-1; i>=0; --i) { @@ -290,10 +264,7 @@ bool CipherFileIO::writeHeader( ) fileIV >>= 8; } - if (blockOnlyMode) - cipher->blockEncode( buf, cbs, externalIV, key ); - else - cipher->streamEncode( buf, sizeof(uint64_t), externalIV, key); + cipher->streamEncode( buf, sizeof(uint64_t), externalIV ); } IORequest req; @@ -322,25 +293,6 @@ ssize_t CipherFileIO::readOneBlock( const IORequest &req ) const tmpReq.offset += headerLen; int maxReadSize = req.dataLen; - if (blockOnlyMode) - { - off_t size = getSize(); - if (req.offset + req.dataLen > size) - { - // Last block written as full block at front of the file header. - mb.allocate(bs); - - tmpReq.offset = 0; - tmpReq.dataLen = bs; - tmpReq.data = mb.data; - - // TODO: what is the expected behavior if req.offset >= size? - maxReadSize = size - req.offset; - if (maxReadSize <= 0) - return 0; - } - } - readSize = base->read( tmpReq ); bool ok; @@ -349,7 +301,7 @@ ssize_t CipherFileIO::readOneBlock( const IORequest &req ) const if(headerLen != 0 && fileIV == 0) const_cast(this)->initHeader(); - if(blockOnlyMode || readSize == bs) + if(readSize == bs) { ok = blockRead( tmpReq.data, bs, blockNum ^ fileIV); } else @@ -378,7 +330,6 @@ ssize_t CipherFileIO::readOneBlock( const IORequest &req ) const bool CipherFileIO::writeOneBlock( const IORequest &req ) { int bs = blockSize(); - int cbs = cipher->cipherBlockSize(); off_t blockNum = req.offset / bs; if(headerLen != 0 && fileIV == 0) @@ -390,13 +341,6 @@ bool CipherFileIO::writeOneBlock( const IORequest &req ) if (req.dataLen == bs) { ok = blockWrite( req.data, bs, blockNum ^ fileIV ); - } else if (blockOnlyMode) - { - mb.allocate(bs); - cipher->randomize(mb.data + bs - cbs, cbs, false); - memcpy(mb.data, req.data, req.dataLen); - - ok = blockWrite( mb.data, bs, blockNum ^ fileIV ); } else { ok = streamWrite( req.data, (int)req.dataLen, @@ -437,18 +381,18 @@ bool CipherFileIO::blockWrite( unsigned char *buf, int size, uint64_t _iv64 ) const { if (!fsConfig->reverseEncryption) - return cipher->blockEncode( buf, size, _iv64, key ); + return cipher->blockEncode( buf, size, _iv64 ); else - return cipher->blockDecode( buf, size, _iv64, key ); + return cipher->blockDecode( buf, size, _iv64 ); } bool CipherFileIO::streamWrite( unsigned char *buf, int size, uint64_t _iv64 ) const { if (!fsConfig->reverseEncryption) - return cipher->streamEncode( buf, size, _iv64, key ); + return cipher->streamEncode( buf, size, _iv64 ); else - return cipher->streamDecode( buf, size, _iv64, key ); + return cipher->streamDecode( buf, size, _iv64 ); } @@ -456,26 +400,26 @@ bool CipherFileIO::blockRead( unsigned char *buf, int size, uint64_t _iv64 ) const { if (fsConfig->reverseEncryption) - return cipher->blockEncode( buf, size, _iv64, key ); + return cipher->blockEncode( buf, size, _iv64 ); else if(_allowHoles) { // special case - leave all 0's alone for(int i=0; iblockDecode( buf, size, _iv64, key ); + return cipher->blockDecode( buf, size, _iv64 ); return true; } else - return cipher->blockDecode( buf, size, _iv64, key ); + return cipher->blockDecode( buf, size, _iv64 ); } bool CipherFileIO::streamRead( unsigned char *buf, int size, uint64_t _iv64 ) const { if (fsConfig->reverseEncryption) - return cipher->streamEncode( buf, size, _iv64, key ); + return cipher->streamEncode( buf, size, _iv64 ); else - return cipher->streamDecode( buf, size, _iv64, key ); + return cipher->streamDecode( buf, size, _iv64 ); } int CipherFileIO::truncate( off_t size ) diff --git a/fs/CipherFileIO.h b/fs/CipherFileIO.h index 5ebb4e6..2193b39 100644 --- a/fs/CipherFileIO.h +++ b/fs/CipherFileIO.h @@ -29,7 +29,7 @@ namespace encfs { -class Cipher; +class CipherV1; /* Implement the FileIO interface encrypting data in blocks. @@ -93,8 +93,7 @@ private: uint64_t fileIV; int lastFlags; - shared_ptr cipher; - CipherKey key; + shared_ptr cipher; }; } // namespace encfs diff --git a/fs/Context.cpp b/fs/Context.cpp index af7fc9c..a4900a0 100644 --- a/fs/Context.cpp +++ b/fs/Context.cpp @@ -18,10 +18,10 @@ * along with this program. If not, see . */ -#include "base/Mutex.h" +#include "fs/Context.h" + #include "base/Error.h" #include "fs/FileNode.h" -#include "fs/Context.h" #include "fs/FileUtils.h" #include "fs/DirNode.h" @@ -29,18 +29,18 @@ namespace encfs { EncFS_Context::EncFS_Context() { +#ifdef CMAKE_USE_PTHREADS_INIT pthread_cond_init( &wakeupCond, 0 ); - pthread_mutex_init( &wakeupMutex, 0 ); - pthread_mutex_init( &contextMutex, 0 ); +#endif usageCount = 0; } EncFS_Context::~EncFS_Context() { - pthread_mutex_destroy( &contextMutex ); - pthread_mutex_destroy( &wakeupMutex ); +#ifdef CMAKE_USE_PTHREADS_INIT pthread_cond_destroy( &wakeupCond ); +#endif // release all entries from map openFiles.clear(); diff --git a/fs/Context.h b/fs/Context.h index a27da53..61888e3 100644 --- a/fs/Context.h +++ b/fs/Context.h @@ -21,8 +21,10 @@ #ifndef _Context_incl_ #define _Context_incl_ +#include "base/config.h" #include "base/shared_ptr.h" -#include "fs/encfs.h" +#include "base/Mutex.h" + #include #ifdef HAVE_TR1_UNORDERED_MAP @@ -42,64 +44,70 @@ class DirNode; class EncFS_Context { -public: - EncFS_Context(); - ~EncFS_Context(); + public: + EncFS_Context(); + ~EncFS_Context(); - shared_ptr getNode(void *ptr); - shared_ptr lookupNode(const char *path); + shared_ptr getNode(void *ptr); + shared_ptr lookupNode(const char *path); - int getAndResetUsageCounter(); - int openFileCount() const; + int getAndResetUsageCounter(); + int openFileCount() const; - void *putNode(const char *path, const shared_ptr &node); + void *putNode(const char *path, const shared_ptr &node); - void eraseNode(const char *path, void *placeholder); + void eraseNode(const char *path, void *placeholder); - void renameNode(const char *oldName, const char *newName); + void renameNode(const char *oldName, const char *newName); - void setRoot(const shared_ptr &root); - shared_ptr getRoot(int *err); - bool isMounted(); + void setRoot(const shared_ptr &root); + shared_ptr getRoot(int *err); + bool isMounted(); - shared_ptr args; - shared_ptr opts; - bool publicFilesystem; + shared_ptr args; + shared_ptr opts; + bool publicFilesystem; - // root path to cipher dir - std::string rootCipherDir; + // root path to cipher dir + std::string rootCipherDir; - // for idle monitor - bool running; - pthread_t monitorThread; - pthread_cond_t wakeupCond; - pthread_mutex_t wakeupMutex; + // for idle monitor + bool running; -private: - /* This placeholder is what is referenced in FUSE context (passed to - * callbacks). - * - * A FileNode may be opened many times, but only one FileNode instance per - * file is kept. Rather then doing reference counting in FileNode, we - * store a unique Placeholder for each open() until the corresponding - * release() is called. shared_ptr then does our reference counting for - * us. - */ - struct Placeholder - { - shared_ptr node; +#ifdef CMAKE_USE_PTHREADS_INIT + pthread_t monitorThread; + pthread_cond_t wakeupCond; + Mutex wakeupMutex; +#endif - Placeholder( const shared_ptr &ptr ) : node(ptr) {} - }; + private: + /* This placeholder is what is referenced in FUSE context (passed to + * callbacks). + * + * A FileNode may be opened many times, but only one FileNode instance per + * file is kept. Rather then doing reference counting in FileNode, we + * store a unique Placeholder for each open() until the corresponding + * release() is called. shared_ptr then does our reference counting for + * us. + */ + struct Placeholder + { + shared_ptr node; - // set of open files, indexed by path - typedef unordered_map > FileMap; - mutable pthread_mutex_t contextMutex; + Placeholder( const shared_ptr &ptr ) : node(ptr) {} + }; - FileMap openFiles; + // set of open files, indexed by path + typedef unordered_map > FileMap; - int usageCount; - shared_ptr root; +#ifdef CMAKE_USE_PTHREADS_INIT + mutable Mutex contextMutex; +#endif + + FileMap openFiles; + + int usageCount; + shared_ptr root; }; int remountFS( EncFS_Context *ctx ); diff --git a/fs/DirNode.cpp b/fs/DirNode.cpp index 13aa807..54ab0cd 100644 --- a/fs/DirNode.cpp +++ b/fs/DirNode.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #ifdef linux #include @@ -33,7 +32,6 @@ #include -#include "cipher/Cipher.h" #include "base/Error.h" #include "base/Mutex.h" #include "fs/Context.h" @@ -309,8 +307,6 @@ DirNode::DirNode(EncFS_Context *_ctx, const string &sourceDir, const FSConfigPtr &_config) { - pthread_mutex_init( &mutex, 0 ); - Lock _lock( mutex ); ctx = _ctx; diff --git a/fs/DirNode.h b/fs/DirNode.h index 8bee674..7360536 100644 --- a/fs/DirNode.h +++ b/fs/DirNode.h @@ -30,6 +30,7 @@ #include #include +#include "base/Mutex.h" #include "base/shared_ptr.h" #include "cipher/CipherKey.h" #include "fs/FileNode.h" @@ -161,7 +162,7 @@ private: shared_ptr findOrCreate( const char *plainName); - pthread_mutex_t mutex; + Mutex mutex; EncFS_Context *ctx; diff --git a/fs/FSConfig.h b/fs/FSConfig.h index a351870..296841a 100644 --- a/fs/FSConfig.h +++ b/fs/FSConfig.h @@ -43,7 +43,7 @@ enum ConfigType }; struct EncFS_Opts; -class Cipher; +class CipherV1; class NameIO; CipherKey getUserKey(const EncfsConfig &config, bool useStdin); @@ -54,8 +54,8 @@ CipherKey getUserKey(const EncfsConfig &config, CipherKey getNewUserKey(EncfsConfig &config, bool useStdin, const std::string &program, const std::string &rootDir); -shared_ptr getCipher(const EncfsConfig &cfg); -shared_ptr getCipher(const Interface &iface, int keySize); +shared_ptr getCipher(const EncfsConfig &cfg); +shared_ptr getCipher(const Interface &iface, int keySize); // helpers for serializing to/from a stream std::ostream &operator << (std::ostream &os, const EncfsConfig &cfg); @@ -67,7 +67,7 @@ struct FSConfig shared_ptr config; shared_ptr opts; - shared_ptr cipher; + shared_ptr cipher; CipherKey key; shared_ptr nameCoding; diff --git a/fs/FileNode.cpp b/fs/FileNode.cpp index ca38c61..978d7c4 100644 --- a/fs/FileNode.cpp +++ b/fs/FileNode.cpp @@ -36,7 +36,6 @@ #include "base/config.h" #include "base/Error.h" #include "base/Mutex.h" -#include "cipher/Cipher.h" #include "cipher/MemoryPool.h" #include "fs/CipherFileIO.h" @@ -66,8 +65,6 @@ namespace encfs { FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg, const char *plaintextName_, const char *cipherName_) { - pthread_mutex_init( &mutex, 0 ); - Lock _lock( mutex ); this->_pname = plaintextName_; @@ -87,13 +84,10 @@ FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg, FileNode::~FileNode() { // FileNode mutex should be locked before the destructor is called - //pthread_mutex_lock( &mutex ); _pname.assign( _pname.length(), '\0' ); _cname.assign( _cname.length(), '\0' ); io.reset(); - - pthread_mutex_destroy( &mutex ); } const char *FileNode::cipherName() const diff --git a/fs/FileNode.h b/fs/FileNode.h index 9bae285..a4e6633 100644 --- a/fs/FileNode.h +++ b/fs/FileNode.h @@ -21,6 +21,7 @@ #ifndef _FileNode_incl_ #define _FileNode_incl_ +#include "base/Mutex.h" #include "cipher/CipherKey.h" #include "fs/encfs.h" #include "fs/FileUtils.h" @@ -82,7 +83,7 @@ private: // easier to avoid any race conditions with operations such as // truncate() which may result in multiple calls down to the FileIO // level. - mutable pthread_mutex_t mutex; + mutable Mutex mutex; FSConfigPtr fsConfig; diff --git a/fs/FileUtils.cpp b/fs/FileUtils.cpp index d47b8c0..938da03 100644 --- a/fs/FileUtils.cpp +++ b/fs/FileUtils.cpp @@ -34,7 +34,7 @@ #include "base/i18n.h" #include "base/XmlReader.h" -#include "cipher/Cipher.h" +#include "cipher/CipherV1.h" #include "cipher/MemoryPool.h" #include "cipher/readpassphrase.h" @@ -528,60 +528,57 @@ bool readProtoConfig( const char *fileName, EncfsConfig &config, } static -Cipher::CipherAlgorithm findCipherAlgorithm(const char *name, +CipherV1::CipherAlgorithm findCipherAlgorithm(const char *name, int keySize ) { - Cipher::AlgorithmList algorithms = Cipher::GetAlgorithmList(); - Cipher::AlgorithmList::const_iterator it; - for(it = algorithms.begin(); it != algorithms.end(); ++it) + for (auto &it : CipherV1::GetAlgorithmList()) { - if( !strcmp( name, it->name.c_str() ) - && it->keyLength.allowed( keySize )) + if( !strcmp( name, it.name.c_str() ) + && it.keyLength.allowed( keySize )) { - return *it; + return it; } } - Cipher::CipherAlgorithm result; + CipherV1::CipherAlgorithm result; return result; } static -Cipher::CipherAlgorithm selectCipherAlgorithm() +CipherV1::CipherAlgorithm selectCipherAlgorithm() { for(;;) { // figure out what cipher they want to use.. // xgroup(setup) cout << _("The following cipher algorithms are available:") << "\n"; - Cipher::AlgorithmList algorithms = Cipher::GetAlgorithmList(); - Cipher::AlgorithmList::const_iterator it; - int optNum = 1; - for(it = algorithms.begin(); it != algorithms.end(); ++it, ++optNum) + int optNum = 0; + auto algorithms = CipherV1::GetAlgorithmList(); + for (auto &it : algorithms) { - cout << optNum << ". " << it->name - << " : " << gettext(it->description.c_str()) << "\n"; - if(it->keyLength.min() == it->keyLength.max()) + cout << ++optNum << ". " << it.name + << " : " << gettext(it.description.c_str()) << "\n"; + if(it.keyLength.min() == it.keyLength.max()) { // shown after algorithm name and description. // xgroup(setup) cout << autosprintf(_(" -- key length %i bits") - , it->keyLength.min()) << "\n"; + , it.keyLength.min()) << "\n"; } else { cout << autosprintf( // shown after algorithm name and description. // xgroup(setup) _(" -- Supports key lengths of %i to %i bits"), - it->keyLength.min(), it->keyLength.max()) << "\n"; + it.keyLength.min(), it.keyLength.max()) << "\n"; } - if(it->blockSize.min() == it->blockSize.max()) + if(it.blockSize.min() == it.blockSize.max()) { cout << autosprintf( // shown after algorithm name and description. // xgroup(setup) - _(" -- block size %i bytes"), it->blockSize.min()) + _(" -- block size %i bytes"), it.blockSize.min()) << "\n"; } else { @@ -589,7 +586,7 @@ Cipher::CipherAlgorithm selectCipherAlgorithm() // shown after algorithm name and description. // xgroup(setup) _(" -- Supports block sizes of %i to %i bytes"), - it->blockSize.min(), it->blockSize.max()) << "\n"; + it.blockSize.min(), it.blockSize.max()) << "\n"; } } @@ -606,11 +603,15 @@ Cipher::CipherAlgorithm selectCipherAlgorithm() continue; } - it = algorithms.begin(); - while(--cipherNum) // numbering starts at 1 - ++it; - - Cipher::CipherAlgorithm alg = *it; + CipherV1::CipherAlgorithm alg; + for (auto &it : algorithms) + { + if (!--cipherNum) + { + alg = it; + break; + } + } // xgroup(setup) cout << autosprintf(_("Selected algorithm \"%s\""), alg.name.c_str()) @@ -621,7 +622,7 @@ Cipher::CipherAlgorithm selectCipherAlgorithm() } static -Interface selectNameCoding(const Cipher::CipherAlgorithm &alg) +Interface selectNameCoding(const CipherV1::CipherAlgorithm &alg) { for(;;) { @@ -635,9 +636,6 @@ Interface selectNameCoding(const Cipher::CipherAlgorithm &alg) map algMap; for(it = algorithms.begin(); it != algorithms.end(); ++it) { - if (it->needsStreamMode && !alg.hasStreamMode) - continue; - cout << optNum << ". " << it->name << " : " << gettext(it->description.c_str()) << "\n"; algMap[optNum++] = it; @@ -667,7 +665,7 @@ Interface selectNameCoding(const Cipher::CipherAlgorithm &alg) } static -int selectKeySize( const Cipher::CipherAlgorithm &alg ) +int selectKeySize( const CipherV1::CipherAlgorithm &alg ) { if(alg.keyLength.min() == alg.keyLength.max()) { @@ -724,7 +722,7 @@ int selectKeySize( const Cipher::CipherAlgorithm &alg ) } static -int selectBlockSize( const Cipher::CipherAlgorithm &alg ) +int selectBlockSize( const CipherV1::CipherAlgorithm &alg ) { if(alg.blockSize.min() == alg.blockSize.max()) { @@ -918,7 +916,7 @@ RootPtr createConfig( EncFS_Context *ctx, int keySize = 0; int blockSize = 0; - Cipher::CipherAlgorithm alg; + CipherV1::CipherAlgorithm alg; Interface nameIOIface; int blockMACBytes = 0; int blockMACRandBytes = 0; @@ -954,7 +952,7 @@ RootPtr createConfig( EncFS_Context *ctx, // Enable filename initialization vector chaning keySize = 256; blockSize = DefaultBlockSize; - alg = findCipherAlgorithm("AES_XTS", keySize); + alg = findCipherAlgorithm("AES", keySize); nameIOIface = BlockNameIO::CurrentInterface(); blockMACBytes = 8; blockMACRandBytes = 0; // using uniqueIV, so this isn't necessary @@ -1028,7 +1026,7 @@ RootPtr createConfig( EncFS_Context *ctx, } } - shared_ptr cipher = Cipher::New( alg.name, keySize ); + shared_ptr cipher = CipherV1::New( alg.iface, keySize ); if(!cipher) { LOG(ERROR) << "Unable to instanciate cipher " << alg.name @@ -1043,10 +1041,6 @@ RootPtr createConfig( EncFS_Context *ctx, EncfsConfig config; config.mutable_cipher()->MergeFrom( cipher->interface() ); - // TODO: allow user config - if (!cipher->hasStreamMode()) - config.set_block_mode_only(true); - config.set_block_size( blockSize ); config.mutable_naming()->MergeFrom( nameIOIface ); config.set_creator( "EncFS " VERSION ); @@ -1106,25 +1100,26 @@ RootPtr createConfig( EncFS_Context *ctx, } userKey = getNewUserKey( config, useStdin, passwordProgram, rootDir ); - cipher->writeKey( volumeKey, encodedKey, userKey ); + cipher->setKey( userKey ); + cipher->writeKey( volumeKey, encodedKey ); userKey.reset(); key->set_ciphertext(encodedKey, encodedKeySize); delete[] encodedKey; - if(!volumeKey) + if(!volumeKey.valid()) { LOG(ERROR) << "Failure generating new volume key! " << "Please report this error."; return rootInfo; } + cipher->setKey( volumeKey ); if(!saveConfig( rootDir, config )) return rootInfo; // fill in config struct - shared_ptr nameCoder = NameIO::New( config.naming(), - cipher, volumeKey ); + shared_ptr nameCoder = NameIO::New( config.naming(), cipher ); if(!nameCoder) { LOG(WARNING) << "Name coding interface not supported"; @@ -1157,7 +1152,7 @@ RootPtr createConfig( EncFS_Context *ctx, void showFSInfo( const EncfsConfig &config ) { - shared_ptr cipher = Cipher::New( config.cipher(), -1 ); + shared_ptr cipher = CipherV1::New( config.cipher(), -1 ); { cout << autosprintf( // xgroup(diag) @@ -1192,8 +1187,7 @@ void showFSInfo( const EncfsConfig &config ) } else { // check if we support the filename encoding interface.. - shared_ptr nameCoder = NameIO::New( config.naming(), - cipher, CipherKey() ); + shared_ptr nameCoder = NameIO::New( config.naming(), cipher ); if(!nameCoder) { // xgroup(diag) @@ -1276,34 +1270,35 @@ void showFSInfo( const EncfsConfig &config ) cout << "\n"; } -shared_ptr getCipher(const EncfsConfig &config) +shared_ptr getCipher(const EncfsConfig &config) { return getCipher(config.cipher(), 8 * config.key().size()); } -shared_ptr getCipher(const Interface &iface, int keySize) +shared_ptr getCipher(const Interface &iface, int keySize) { - return Cipher::New( iface, keySize ); + return CipherV1::New( iface, keySize ); } CipherKey makeNewKey(EncfsConfig &config, const char *password, int passwdLen) { CipherKey userKey; - shared_ptr cipher = getCipher(config); + shared_ptr cipher = getCipher(config); + + EncryptedKey *key = config.mutable_key(); unsigned char salt[20]; - if(!cipher->randomize( salt, sizeof(salt), true)) + if(!cipher->pseudoRandomize( salt, sizeof(salt))) { cout << _("Error creating salt\n"); return userKey; } - EncryptedKey *key = config.mutable_key(); key->set_salt(salt, sizeof(salt)); int iterations = key->kdf_iterations(); - userKey = cipher->newKey( password, passwdLen, - iterations, key->kdf_duration(), - salt, sizeof(salt)); + userKey = cipher->newKey(password, passwdLen, + &iterations, key->kdf_duration(), + salt, sizeof(salt)); key->set_kdf_iterations(iterations); return userKey; @@ -1313,14 +1308,15 @@ CipherKey decryptKey(const EncfsConfig &config, const char *password, int passwd { const EncryptedKey &key = config.key(); CipherKey userKey; - shared_ptr cipher = getCipher(config.cipher(), 8 * key.size()); + shared_ptr cipher = getCipher(config.cipher(), 8 * key.size()); if(!key.salt().empty()) { int iterations = key.kdf_iterations(); - userKey = cipher->newKey( password, passwdLen, - iterations, key.kdf_duration(), - (const unsigned char *)key.salt().data(), key.salt().size()); + userKey = cipher->newKey(password, passwdLen, + &iterations, key.kdf_duration(), + (const byte *)key.salt().data(), + key.salt().size()); if (iterations != key.kdf_iterations()) { @@ -1582,7 +1578,7 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) } // first, instanciate the cipher. - shared_ptr cipher = getCipher(config); + shared_ptr cipher = getCipher(config); if(!cipher) { Interface iface = config.cipher(); @@ -1605,24 +1601,27 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) } else userKey = getUserKey( config, opts->passwordProgram, opts->rootDir ); - if(!userKey) + if(!userKey.valid()) return rootInfo; + cipher->setKey(userKey); + VLOG(1) << "cipher encoded key size = " << cipher->encodedKeySize(); // decode volume key.. CipherKey volumeKey = cipher->readKey( - (const unsigned char *)config.key().ciphertext().data(), userKey, opts->checkKey); + (const unsigned char *)config.key().ciphertext().data(), opts->checkKey); userKey.reset(); - if(!volumeKey) + if(!volumeKey.valid()) { // xgroup(diag) cout << _("Error decoding volume key, password incorrect\n"); return rootInfo; } - shared_ptr nameCoder = NameIO::New( config.naming(), - cipher, volumeKey ); + cipher->setKey(volumeKey); + + shared_ptr nameCoder = NameIO::New( config.naming(), cipher ); if(!nameCoder) { Interface iface = config.naming(); diff --git a/fs/FileUtils.h b/fs/FileUtils.h index bbcdfa4..4008c40 100644 --- a/fs/FileUtils.h +++ b/fs/FileUtils.h @@ -44,12 +44,12 @@ std::string parentDirectory( const std::string &path ); bool userAllowMkdir(const char *dirPath, mode_t mode ); bool userAllowMkdir(int promptno, const char *dirPath, mode_t mode ); -class Cipher; +class CipherV1; class DirNode; struct EncFS_Root { - shared_ptr cipher; + shared_ptr cipher; CipherKey volumeKey; shared_ptr root; diff --git a/fs/MACFileIO.cpp b/fs/MACFileIO.cpp index 95c4aa7..cef8e6d 100644 --- a/fs/MACFileIO.cpp +++ b/fs/MACFileIO.cpp @@ -61,7 +61,6 @@ MACFileIO::MACFileIO( const shared_ptr &_base, : BlockFileIO( dataBlockSize( cfg ), cfg ) , base( _base ) , cipher( cfg->cipher ) - , key( cfg->key ) , macBytes( cfg->config->block_mac_bytes() ) , randBytes( cfg->config->block_mac_rand_bytes() ) , warnOnly( cfg->opts->forceDecode ) @@ -202,7 +201,7 @@ ssize_t MACFileIO::readOneBlock( const IORequest &req ) const // At this point the data has been decoded. So, compute the MAC of // the block and check against the checksum stored in the header.. uint64_t mac = cipher->MAC_64( tmp.data + macBytes, - readSize - macBytes, key ); + readSize - macBytes ); for(int i=0; i>= 8) { @@ -255,7 +254,7 @@ bool MACFileIO::writeOneBlock( const IORequest &req ) memcpy( newReq.data + headerSize, req.data, req.dataLen ); if(randBytes > 0) { - if(!cipher->randomize( newReq.data+macBytes, randBytes, false )) + if(!cipher->pseudoRandomize( newReq.data+macBytes, randBytes)) return false; } @@ -263,7 +262,7 @@ bool MACFileIO::writeOneBlock( const IORequest &req ) { // compute the mac (which includes the random data) and fill it in uint64_t mac = cipher->MAC_64( newReq.data+macBytes, - req.dataLen + randBytes, key ); + req.dataLen + randBytes ); for(int i=0; i base; - shared_ptr cipher; - CipherKey key; + shared_ptr cipher; int macBytes; int randBytes; bool warnOnly; diff --git a/fs/NameIO.cpp b/fs/NameIO.cpp index 0ec1b2f..a7494aa 100644 --- a/fs/NameIO.cpp +++ b/fs/NameIO.cpp @@ -112,8 +112,8 @@ bool NameIO::Register( const char *name, const char *description, return true; } -shared_ptr NameIO::New( const string &name, - const shared_ptr &cipher, const CipherKey &key) +shared_ptr NameIO::New(const string &name, + const shared_ptr &cipher) { shared_ptr result; if(gNameIOMap) @@ -122,14 +122,14 @@ shared_ptr NameIO::New( const string &name, if(it != gNameIOMap->end()) { Constructor fn = it->second.constructor; - result = (*fn)( it->second.iface, cipher, key ); + result = (*fn)( it->second.iface, cipher ); } } return result; } -shared_ptr NameIO::New( const Interface &iface, - const shared_ptr &cipher, const CipherKey &key ) +shared_ptr NameIO::New(const Interface &iface, + const shared_ptr &cipher) { shared_ptr result; if(gNameIOMap) @@ -141,7 +141,7 @@ shared_ptr NameIO::New( const Interface &iface, if( implements(it->second.iface, iface )) { Constructor fn = it->second.constructor; - result = (*fn)( iface, cipher, key ); + result = (*fn)( iface, cipher ); break; } } diff --git a/fs/NameIO.h b/fs/NameIO.h index d5344dd..548df9e 100644 --- a/fs/NameIO.h +++ b/fs/NameIO.h @@ -27,117 +27,115 @@ #include #include "base/Interface.h" -#include "cipher/CipherKey.h" +#include "base/shared_ptr.h" namespace encfs { -class Cipher; +class CipherV1; class NameIO { -public: - typedef shared_ptr (*Constructor)( const Interface &iface, - const shared_ptr &cipher, const CipherKey &key); + public: + typedef shared_ptr (*Constructor)(const Interface &iface, + const shared_ptr &cipher); - struct Algorithm - { - std::string name; - std::string description; - Interface iface; - bool needsStreamMode; - }; + struct Algorithm + { + std::string name; + std::string description; + Interface iface; + bool needsStreamMode; + }; - typedef std::list AlgorithmList; - static AlgorithmList GetAlgorithmList( bool includeHidden = false ); + typedef std::list AlgorithmList; + static AlgorithmList GetAlgorithmList( bool includeHidden = false ); - static shared_ptr New( const Interface &iface, - const shared_ptr &cipher, const CipherKey &key); - static shared_ptr New( const std::string &name, - const shared_ptr &cipher, const CipherKey &key); + static shared_ptr New(const Interface &iface, + const shared_ptr &cipher); + static shared_ptr New(const std::string &name, + const shared_ptr &cipher); - static bool Register( const char *name, const char *description, - const Interface &iface, Constructor constructor, - bool needsStreamMode, - bool hidden = false); + static bool Register( const char *name, const char *description, + const Interface &iface, Constructor constructor, + bool needsStreamMode, + bool hidden = false); - NameIO(); - virtual ~NameIO(); + NameIO(); + virtual ~NameIO(); - virtual Interface interface() const =0; + virtual Interface interface() const =0; - void setChainedNameIV( bool enable ); - bool getChainedNameIV() const; - void setReverseEncryption( bool enable ); - bool getReverseEncryption() const; + void setChainedNameIV( bool enable ); + bool getChainedNameIV() const; + void setReverseEncryption( bool enable ); + bool getReverseEncryption() const; - std::string encodePath( const char *plaintextPath ) const; - std::string decodePath( const char *encodedPath ) const; + std::string encodePath( const char *plaintextPath ) const; + std::string decodePath( const char *encodedPath ) const; - std::string encodePath( const char *plaintextPath, uint64_t *iv ) const; - std::string decodePath( const char *encodedPath, uint64_t *iv ) const; + std::string encodePath( const char *plaintextPath, uint64_t *iv ) const; + std::string decodePath( const char *encodedPath, uint64_t *iv ) const; - virtual int maxEncodedNameLen( int plaintextNameLen ) const =0; - virtual int maxDecodedNameLen( int encodedNameLen ) const =0; + virtual int maxEncodedNameLen( int plaintextNameLen ) const =0; + virtual int maxDecodedNameLen( int encodedNameLen ) const =0; - std::string encodeName( const char *plaintextName, int length ) const; - std::string decodeName( const char *encodedName, int length ) const; + std::string encodeName( const char *plaintextName, int length ) const; + std::string decodeName( const char *encodedName, int length ) const; -protected: - virtual int encodeName( const char *plaintextName, int length, - char *encodedName ) const; - virtual int decodeName( const char *encodedName, int length, - char *plaintextName ) const; + protected: + virtual int encodeName( const char *plaintextName, int length, + char *encodedName ) const; + virtual int decodeName( const char *encodedName, int length, + char *plaintextName ) const; - virtual int encodeName( const char *plaintextName, int length, - uint64_t *iv, char *encodedName ) const =0; - virtual int decodeName( const char *encodedName, int length, - uint64_t *iv, char *plaintextName ) const =0; + virtual int encodeName( const char *plaintextName, int length, + uint64_t *iv, char *encodedName ) const =0; + virtual int decodeName( const char *encodedName, int length, + uint64_t *iv, char *plaintextName ) const =0; -private: + private: - std::string recodePath( const char *path, - int (NameIO::*codingLen)(int) const, - int (NameIO::*codingFunc)(const char *, int, - uint64_t *, char *) const, - uint64_t *iv ) const; + std::string recodePath( const char *path, + int (NameIO::*codingLen)(int) const, + int (NameIO::*codingFunc)(const char *, int, + uint64_t *, char *) const, + uint64_t *iv ) const; - std::string _encodePath( const char *plaintextPath, uint64_t *iv ) const; - std::string _decodePath( const char *encodedPath, uint64_t *iv ) const; - std::string _encodeName( const char *plaintextName, int length ) const; - std::string _decodeName( const char *encodedName, int length ) const; + std::string _encodePath( const char *plaintextPath, uint64_t *iv ) const; + std::string _decodePath( const char *encodedPath, uint64_t *iv ) const; + std::string _encodeName( const char *plaintextName, int length ) const; + std::string _decodeName( const char *encodedName, int length ) const; - bool chainedNameIV; - bool reverseEncryption; + bool chainedNameIV; + bool reverseEncryption; }; /* - Helper macros for creating temporary buffers with an optimization that - below a given size (OptimizedSize) is allocated on the stack, and when a - larger size is requested it is allocated on the heap. + Helper macros for creating temporary buffers with an optimization that + below a given size (OptimizedSize) is allocated on the stack, and when a + larger size is requested it is allocated on the heap. - BUFFER_RESET should be called for the same name as BUFFER_INIT -*/ + BUFFER_RESET should be called for the same name as BUFFER_INIT + */ #define BUFFER_INIT( Name, OptimizedSize, Size ) \ -char Name ## _Raw [ OptimizedSize ]; \ -char *Name = Name ## _Raw; \ -if( sizeof(Name ## _Raw) < Size ) \ -{ \ - Name = new char[ Size ];\ -} \ -memset( Name, 0, Size ) + char Name ## _Raw [ OptimizedSize ]; \ + char *Name = Name ## _Raw; \ + if( sizeof(Name ## _Raw) < Size ) { \ + Name = new char[ Size ];\ + } \ + memset( Name, 0, Size ) #define BUFFER_RESET( Name ) \ -do { \ - if( Name != Name ## _Raw ) \ - { \ - delete[] Name; \ - Name = Name ## _Raw; \ - } \ -} while(0) + do { \ + if( Name != Name ## _Raw ) { \ + delete[] Name; \ + Name = Name ## _Raw; \ + } \ + } while(0) } // namespace encfs diff --git a/fs/NullNameIO.cpp b/fs/NullNameIO.cpp index deeb2a6..0b78e64 100644 --- a/fs/NullNameIO.cpp +++ b/fs/NullNameIO.cpp @@ -19,7 +19,7 @@ */ #include "base/base64.h" -#include "cipher/Cipher.h" +#include "cipher/CipherV1.h" #include "fs/NullNameIO.h" #include @@ -27,7 +27,7 @@ namespace encfs { static shared_ptr NewNNIO( const Interface &, - const shared_ptr &, const CipherKey & ) + const shared_ptr & ) { return shared_ptr( new NullNameIO() ); } diff --git a/fs/StreamNameIO.cpp b/fs/StreamNameIO.cpp index df9b18a..a7a703d 100644 --- a/fs/StreamNameIO.cpp +++ b/fs/StreamNameIO.cpp @@ -21,7 +21,7 @@ #include "base/base64.h" #include "base/Error.h" #include "base/i18n.h" -#include "cipher/Cipher.h" +#include "cipher/CipherV1.h" #include "fs/StreamNameIO.h" #include @@ -33,9 +33,9 @@ using namespace std; namespace encfs { static shared_ptr NewStreamNameIO( const Interface &iface, - const shared_ptr &cipher, const CipherKey &key) + const shared_ptr &cipher ) { - return shared_ptr( new StreamNameIO( iface, cipher, key ) ); + return shared_ptr( new StreamNameIO( iface, cipher ) ); } static bool StreamIO_registered = NameIO::Register("Stream", @@ -72,11 +72,9 @@ Interface StreamNameIO::CurrentInterface() } StreamNameIO::StreamNameIO( const Interface &iface, - const shared_ptr &cipher, - const CipherKey &key ) + const shared_ptr &cipher ) : _interface( iface.major() ) , _cipher( cipher ) - , _key( key ) { } @@ -109,8 +107,8 @@ int StreamNameIO::encodeName( const char *plaintextName, int length, if( iv && _interface >= 2 ) tmpIV = *iv; - unsigned int mac = _cipher->MAC_16( (const unsigned char *)plaintextName, - length, _key, iv ); + unsigned int mac = _cipher->reduceMac16( + _cipher->MAC_64((const byte *)plaintextName, length, iv )); // add on checksum bytes unsigned char *encodeBegin; @@ -130,7 +128,7 @@ int StreamNameIO::encodeName( const char *plaintextName, int length, // stream encode the plaintext bytes memcpy( encodeBegin, plaintextName, length ); - _cipher->streamEncode( encodeBegin, length, (uint64_t)mac ^ tmpIV, _key); + _cipher->streamEncode( encodeBegin, length, (uint64_t)mac ^ tmpIV); // convert the entire thing to base 64 ascii.. int encodedStreamLen = length + 2; @@ -184,11 +182,11 @@ int StreamNameIO::decodeName( const char *encodedName, int length, } _cipher->streamDecode( (unsigned char *)plaintextName, decodedStreamLen, - (uint64_t)mac ^ tmpIV, _key); + (uint64_t)mac ^ tmpIV ); // compute MAC to check with stored value - unsigned int mac2 = _cipher->MAC_16((const unsigned char *)plaintextName, - decodedStreamLen, _key, iv); + unsigned int mac2 = _cipher->reduceMac16( + _cipher->MAC_64((const byte *)plaintextName, decodedStreamLen, iv)); BUFFER_RESET( tmpBuf ); if(mac2 != mac) diff --git a/fs/StreamNameIO.h b/fs/StreamNameIO.h index 5238cda..60b03de 100644 --- a/fs/StreamNameIO.h +++ b/fs/StreamNameIO.h @@ -21,12 +21,11 @@ #ifndef _StreamNameIO_incl_ #define _StreamNameIO_incl_ -#include "cipher/CipherKey.h" #include "fs/NameIO.h" namespace encfs { -class Cipher; +class CipherV1; class StreamNameIO : public NameIO { @@ -34,8 +33,7 @@ public: static Interface CurrentInterface(); StreamNameIO( const Interface &iface, - const shared_ptr &cipher, - const CipherKey &key ); + const shared_ptr &cipher); virtual ~StreamNameIO(); virtual Interface interface() const; @@ -52,8 +50,7 @@ protected: uint64_t *iv, char *plaintextName ) const; private: int _interface; - shared_ptr _cipher; - CipherKey _key; + shared_ptr _cipher; }; } // namespace encfs diff --git a/fs/test_BlockIO.cpp b/fs/test_BlockIO.cpp index b5f529c..6b43be7 100644 --- a/fs/test_BlockIO.cpp +++ b/fs/test_BlockIO.cpp @@ -39,7 +39,7 @@ TEST(BlockFileIOTest, BasicIO) { MemFileIO base(1024); ASSERT_EQ(1024, base.getSize()); - FSConfigPtr cfg = makeConfig( Cipher::New("Null"), 512); + FSConfigPtr cfg = makeConfig( CipherV1::New("Null"), 512); MemBlockFileIO block(512, cfg); block.truncate(1024); ASSERT_EQ(1024, block.getSize()); diff --git a/fs/test_IO.cpp b/fs/test_IO.cpp index 5efe7cf..2e82cb9 100644 --- a/fs/test_IO.cpp +++ b/fs/test_IO.cpp @@ -24,7 +24,6 @@ #include #include "fs/testing.h" -#include "cipher/Cipher.h" #include "cipher/MemoryPool.h" #include "fs/CipherFileIO.h" diff --git a/fs/testing.cpp b/fs/testing.cpp index c3288cf..329e08b 100644 --- a/fs/testing.cpp +++ b/fs/testing.cpp @@ -27,7 +27,7 @@ #include -#include "cipher/Cipher.h" +#include "cipher/CipherV1.h" #include "cipher/MemoryPool.h" #include "fs/FSConfig.h" @@ -40,10 +40,11 @@ using namespace std; namespace encfs { -FSConfigPtr makeConfig(const shared_ptr& cipher, int blockSize) { +FSConfigPtr makeConfig(const shared_ptr& cipher, int blockSize) { FSConfigPtr cfg = FSConfigPtr(new FSConfig); cfg->cipher = cipher; cfg->key = cipher->newRandomKey(); + cfg->cipher->setKey(cfg->key); cfg->config.reset(new EncfsConfig); cfg->config->set_block_size(blockSize); cfg->opts.reset(new EncFS_Opts); @@ -53,7 +54,7 @@ FSConfigPtr makeConfig(const shared_ptr& cipher, int blockSize) { void runWithCipher(const string& cipherName, int blockSize, void (*func)(FSConfigPtr& config)) { - shared_ptr cipher = Cipher::New(cipherName); + shared_ptr cipher = CipherV1::New(cipherName); ASSERT_TRUE(cipher.get() != NULL); FSConfigPtr cfg = makeConfig(cipher, blockSize); @@ -61,14 +62,14 @@ void runWithCipher(const string& cipherName, int blockSize, } void runWithAllCiphers(void (*func)(FSConfigPtr& config)) { - list algorithms = Cipher::GetAlgorithmList(); - list::const_iterator it; + list algorithms = CipherV1::GetAlgorithmList(); + list::const_iterator it; for (it = algorithms.begin(); it != algorithms.end(); ++it) { int blockSize = it->blockSize.closest(512); int keyLength = it->keyLength.closest(128); SCOPED_TRACE(testing::Message() << "Testng with cipher " << it->name << ", blocksize " << blockSize << ", keyLength " << keyLength); - shared_ptr cipher = Cipher::New(it->name, keyLength); + shared_ptr cipher = CipherV1::New(it->iface, keyLength); ASSERT_TRUE(cipher.get() != NULL); FSConfigPtr cfg = makeConfig(cipher, blockSize); @@ -95,7 +96,7 @@ void writeRandom(FSConfigPtr& cfg, FileIO* a, FileIO* b, int offset, int len) { a->truncate(offset + len); unsigned char *buf = new unsigned char[len]; - ASSERT_TRUE(cfg->cipher->randomize(buf, len, false)); + ASSERT_TRUE(cfg->cipher->pseudoRandomize(buf, len)); IORequest req; req.data = new unsigned char[len]; diff --git a/fs/testing.h b/fs/testing.h index ab291cf..04ec7c3 100644 --- a/fs/testing.h +++ b/fs/testing.h @@ -3,7 +3,7 @@ #include -#include "cipher/Cipher.h" +#include "cipher/CipherV1.h" #include "fs/FileUtils.h" #include "fs/FSConfig.h" @@ -11,7 +11,7 @@ namespace encfs { class FileIO; -FSConfigPtr makeConfig(const shared_ptr& cipher, int blockSize); +FSConfigPtr makeConfig(const shared_ptr& cipher, int blockSize); void runWithCipher(const std::string& cipherName, int blockSize, void (*func)(FSConfigPtr& config)); diff --git a/protos/fsconfig.proto b/protos/fsconfig.proto index 5d34f94..88df3e1 100644 --- a/protos/fsconfig.proto +++ b/protos/fsconfig.proto @@ -12,9 +12,6 @@ message EncfsConfig optional int32 revision = 2 [default=0]; required Interface cipher = 3; - // added for FileIO/Cipher 3.0 (encfs 1.8) - // Use only block encryption, no stream encryption. - optional bool block_mode_only = 31; required EncryptedKey key = 4; optional Interface naming = 5; diff --git a/util/encfsctl.cpp b/util/encfsctl.cpp index 6b46b1b..2caa72a 100644 --- a/util/encfsctl.cpp +++ b/util/encfsctl.cpp @@ -23,7 +23,7 @@ #include "base/Error.h" #include "base/i18n.h" -#include "cipher/Cipher.h" +#include "cipher/CipherV1.h" #include "cipher/BlockCipher.h" #include "cipher/MAC.h" #include "cipher/StreamCipher.h" @@ -172,33 +172,49 @@ static int showCiphers( int argc, char **argv ) { (void)argc; (void)argv; - list names = BlockCipher::GetRegistry().GetAll(); - for (const string& name : names) { + + cout << _("Block modes:\n"); + for (const string& name : BlockCipher::GetRegistry().GetAll()) { auto props = BlockCipher::GetRegistry().GetProperties(name.c_str()); cout << _("Implementation: ") << name << "\n"; - cout << "\t" << _("Block cipher: ") << props->cipher << " / " << props->mode - << " ( " << autosprintf(_("via %s"), props->library.c_str()) << " )\n"; + cout << "\t" << _("Provider: ") << props->library << "\n"; + cout << "\t" << _("Block cipher: ") << props->cipher << " / " + << props->mode << "\n"; cout << "\t" << _("Key Sizes: ") << props->keySize << "\n"; } - - names = StreamCipher::GetRegistry().GetAll(); - for (const string& name : names) { + cout << "\n"; + + cout << _("Stream modes:\n"); + for (const string& name : StreamCipher::GetRegistry().GetAll()) { auto props = StreamCipher::GetRegistry().GetProperties(name.c_str()); cout << _("Implementation: ") << name << "\n"; - cout << "\t" << _("Stream cipher: ") << props->cipher << " / " << props->mode - << " ( " << autosprintf(_("via %s"), props->library.c_str()) << " )\n"; + cout << "\t" << _("Provider: ") << props->library << "\n"; + cout << "\t" << _("Stream cipher: ") << props->cipher << " / " + << props->mode << "\n"; cout << "\t" << _("Key Sizes: ") << props->keySize << "\n"; } + cout << "\n"; - names = MessageAuthenticationCode::GetRegistry().GetAll(); - for (const string& name : names) { - auto props = MessageAuthenticationCode::GetRegistry() - .GetProperties(name.c_str()); + cout << _("MAC modes:\n"); + for (const string& name : MAC::GetRegistry().GetAll()) { + auto props = MAC::GetRegistry().GetProperties(name.c_str()); cout << _("Implementation: ") << name << "\n"; - cout << "\t" << _("HMAC: ") << props->hashFunction << " / " << props->mode - << " ( " << autosprintf(_("via %s"), props->library.c_str()) << " )\n"; + cout << "\t" << _("Provider: ") << props->library << "\n"; + cout << "\t" << _("Hash mode: ") << props->hashFunction << " / " + << props->mode << "\n"; cout << "\t" << _("Block size: ") << props->blockSize << "\n"; } + cout << "\n"; + + cout << _("PBKDF modes:\n"); + for (const string& name : PBKDF::GetRegistry().GetAll()) { + auto props = PBKDF::GetRegistry().GetProperties(name.c_str()); + cout << _("Implementation: ") << name << "\n"; + cout << "\t" << _("Provider: ") << props->library << "\n"; + cout << "\t" << _("Mode: ") << props->mode << "\n"; + } + cout << "\n"; + return EXIT_SUCCESS; } @@ -335,8 +351,7 @@ static int cmd_showKey( int argc, char **argv ) else { // encode with itself - string b64Key = rootInfo->cipher->encodeAsString( - rootInfo->volumeKey, rootInfo->volumeKey ); + string b64Key = rootInfo->cipher->encodeAsString( rootInfo->volumeKey ); cout << b64Key << "\n"; @@ -739,34 +754,37 @@ static int do_chpasswd( bool useStdin, bool annotate, int argc, char **argv ) return EXIT_FAILURE; } + // ask for existing password + cout << _("Enter current Encfs password\n"); + if (annotate) + cerr << "$PROMPT$ passwd" << endl; + CipherKey userKey = getUserKey( config, useStdin ); + if(!userKey.valid()) + return EXIT_FAILURE; + // instanciate proper cipher - shared_ptr cipher = getCipher(config); + shared_ptr cipher = getCipher(config); if(!cipher) { cout << autosprintf(_("Unable to find specified cipher \"%s\"\n"), config.cipher().name().c_str()); return EXIT_FAILURE; } - - // ask for existing password - cout << _("Enter current Encfs password\n"); - if (annotate) - cerr << "$PROMPT$ passwd" << endl; - CipherKey userKey = getUserKey( config, useStdin ); - if(!userKey) - return EXIT_FAILURE; + cipher->setKey(userKey); // decode volume key using user key -- at this point we detect an incorrect // password if the key checksum does not match (causing readKey to fail). CipherKey volumeKey = cipher->readKey( - (const unsigned char *)config.key().ciphertext().data(), userKey ); + (const unsigned char *)config.key().ciphertext().data(), true ); - if(!volumeKey) + if(!volumeKey.valid()) { cout << _("Invalid password\n"); return EXIT_FAILURE; } + cipher->setKey(volumeKey); + // Now, get New user key.. userKey.reset(); cout << _("Enter new Encfs password\n"); @@ -782,14 +800,16 @@ static int do_chpasswd( bool useStdin, bool annotate, int argc, char **argv ) // re-encode the volume key using the new user key and write it out.. int result = EXIT_FAILURE; - if(userKey) + if(userKey.valid()) { int encodedKeySize = cipher->encodedKeySize(); unsigned char *keyBuf = new unsigned char[ encodedKeySize ]; // encode volume key with new user key - cipher->writeKey( volumeKey, keyBuf, userKey ); + cipher->setKey(userKey); + cipher->writeKey( volumeKey, keyBuf ); userKey.reset(); + cipher->setKey(volumeKey); EncryptedKey *key = config.mutable_key(); key->set_ciphertext( keyBuf, encodedKeySize ); From 5a126ea79794b7c2af5e91f82ca0aff5fbf3e09c Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Tue, 5 Mar 2013 06:38:00 +0000 Subject: [PATCH 17/51] use lchmod when available, fixes #158 git-svn-id: http://encfs.googlecode.com/svn/trunk@96 db9cf616-1c43-0410-9cb8-a902689de0d6 --- CMakeLists.txt | 3 +++ base/config.h.cmake | 2 ++ fs/encfs.cpp | 7 ++++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a3ed14..782b26c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,9 @@ CHECK_CXX_SOURCE_COMPILES ("#include #include int main() { getxattr(0,0,0,0,0,0); return 1; } " XATTR_ADD_OPT) +include (CheckFunctionExists) +check_function_exists(lchmod HAVE_LCHMOD) + # Libraries or programs used for multiple modules. find_package (Protobuf REQUIRED) include_directories (${PROTOBUF_INCLUDE_DIR}) diff --git a/base/config.h.cmake b/base/config.h.cmake index 748bd61..68fecab 100644 --- a/base/config.h.cmake +++ b/base/config.h.cmake @@ -14,6 +14,8 @@ #cmakedefine HAVE_EVP_AES #cmakedefine HAVE_EVP_AES_XTS +#cmakedefine HAVE_LCHMOD + #cmakedefine HAVE_VALGRIND_VALGRIND_H #cmakedefine HAVE_VALGRIND_MEMCHECK_H diff --git a/fs/encfs.cpp b/fs/encfs.cpp index 500acb6..5068c68 100644 --- a/fs/encfs.cpp +++ b/fs/encfs.cpp @@ -50,6 +50,7 @@ using namespace std::tr1; using namespace std; #endif +#include "base/config.h" #include "base/shared_ptr.h" #include "base/Mutex.h" #include "base/Error.h" @@ -483,7 +484,11 @@ int encfs_rename(const char *from, const char *to) int _do_chmod(EncFS_Context *, const string &cipherPath, mode_t mode) { +#ifdef HAVE_LCHMOD + return lchmod( cipherPath.c_str(), mode ); +#else return chmod( cipherPath.c_str(), mode ); +#endif } int encfs_chmod(const char *path, mode_t mode) @@ -697,7 +702,7 @@ int encfs_statfs(const char *path, struct statvfs *st) int _do_setxattr(EncFS_Context *, const string &cyName, tuple data) { - int options = 0; + int options = XATTR_NOFOLLOW; return ::setxattr( cyName.c_str(), get<0>(data), get<1>(data), get<2>(data), get<3>(data), options ); } From 63c2d1c539d26df5af487f5fd3631c27e3b34ca4 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Tue, 5 Mar 2013 06:39:51 +0000 Subject: [PATCH 18/51] add CommonCrypto support, other misc fixes git-svn-id: http://encfs.googlecode.com/svn/trunk@97 db9cf616-1c43-0410-9cb8-a902689de0d6 --- CMakeLists.txt | 23 ++- base/ConfigReader.cpp | 4 +- base/XmlReader.cpp | 16 +-- base/base64.cpp | 111 ++++++++------ base/base64.h | 2 + base/config.h.cmake | 10 +- cipher/BlockCipher.cpp | 14 +- cipher/BlockCipher_test.cpp | 103 ++++++++++--- cipher/CMakeLists.txt | 17 ++- cipher/CipherKey_test.cpp | 45 ++++++ cipher/CipherV1.cpp | 107 +++++++++++--- cipher/CipherV1.h | 8 +- cipher/CommonCrypto.cpp | 263 ++++++++++++++++++++++++++++++++++ cipher/CommonCrypto.h | 35 +++++ cipher/MAC.h | 3 +- cipher/MAC_test.cpp | 8 +- cipher/MemoryPool.cpp | 121 ++++++---------- cipher/MemoryPool.h | 11 +- cipher/StreamCipher.h | 11 +- cipher/openssl.cpp | 48 ++++++- cipher/testing.cpp | 10 ++ encfs/main.cpp | 15 +- fs/CMakeLists.txt | 10 ++ fs/CipherFileIO.cpp | 3 +- fs/CipherFileIO.h | 2 - fs/Context.h | 1 + fs/DirNode.cpp | 3 +- fs/FSConfig.h | 5 + fs/FileNode.cpp | 2 +- fs/FileUtils.cpp | 13 +- fs/MACFileIO.cpp | 2 - fs/NameIO.cpp | 6 +- fs/RawFileIO.cpp | 2 - fs/StreamNameIO.cpp | 2 - fs/{test.cpp => checkops.cpp} | 79 +++++----- fs/encfs.cpp | 13 +- fs/test_IO.cpp | 32 +++++ fs/testing.cpp | 35 +++-- po/CMakeLists.txt | 2 +- util/CMakeLists.txt | 1 - util/encfsctl.cpp | 9 +- util/makeKey.cpp | 2 - 42 files changed, 917 insertions(+), 292 deletions(-) create mode 100644 cipher/CipherKey_test.cpp create mode 100644 cipher/CommonCrypto.cpp create mode 100644 cipher/CommonCrypto.h rename fs/{test.cpp => checkops.cpp} (88%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 782b26c..b54f226 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,11 +3,17 @@ project(Encfs) set (ENCFS_MAJOR 2) set (ENCFS_MINOR 0) -set (ENCFS_PATCH 0) -set (ENCFS_VERSION "${ENCFS_MAJOR}.${ENCFS_MINOR}.${ENCFS_PATCH}") +set (ENCFS_VERSION "${ENCFS_MAJOR}.${ENCFS_MINOR}") option (BUILD_SHARED_LIBS "Build dynamic link libraries" OFF) +option (WITH_OPENSSL "WithOpenSSL" ON) +option (WITH_COMMON_CRYPTO "WithCommonCrypto" OFF) + +if (WITH_COMMON_CRYPTO) + set (WITH_OPENSSL OFF) +endif (WITH_COMMON_CRYPTO) + set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMakeModules/") @@ -36,7 +42,6 @@ endif (APPLE) set (CPACK_PACKAGE_NAME "Encfs") set (CPACK_PACKAGE_VERSION_MAJOR ${ENCFS_MAJOR}) set (CPACK_PACKAGE_VERSION_MINOR ${ENCFS_MINOR}) -set (CPACK_PACKAGE_VERSION_PATCH ${ENCFS_PATCH}) set (CPACK_SOURCE_GENERATOR TGZ) set (CPACK_SOURCE_IGNORE_FILES "/_darcs/" @@ -56,9 +61,15 @@ check_include_file_cxx (tr1/tuple HAVE_TR1_TUPLE) check_include_file_cxx (valgrind/valgrind.h HAVE_VALGRIND_VALGRIND_H) check_include_file_cxx (valgrind/memcheck.h HAVE_VALGRIND_MEMCHECK_H) -# TODO: move this to cipher directory. -find_package (OpenSSL REQUIRED) -include (OpenSSLTests) +if (WITH_COMMON_CRYPTO) + check_include_file_cxx (Security/SecRandom.h HAVE_SEC_RANDOM_H) +endif (WITH_COMMON_CRYPTO) + +if (WITH_OPENSSL) + # TODO: move this to cipher directory. + find_package (OpenSSL REQUIRED) + include (OpenSSLTests) +endif (WITH_OPENSSL) # Check if xattr functions take extra argument. include (CheckCXXSourceCompiles) diff --git a/base/ConfigReader.cpp b/base/ConfigReader.cpp index f5a8f60..a623b67 100644 --- a/base/ConfigReader.cpp +++ b/base/ConfigReader.cpp @@ -30,7 +30,9 @@ #include "base/types.h" -using namespace std; +using std::make_pair; +using std::map; +using std::string; namespace encfs { diff --git a/base/XmlReader.cpp b/base/XmlReader.cpp index ad37b45..75088e7 100644 --- a/base/XmlReader.cpp +++ b/base/XmlReader.cpp @@ -38,8 +38,7 @@ #include #include "base/base64.h" #include "base/Interface.h" - -using namespace std; +#include "base/shared_ptr.h" namespace encfs { @@ -116,16 +115,9 @@ bool XmlValue::readB64(const char *path, byte *data, int length) const std::string s = value->text(); s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end()); + s.erase(s.find_last_not_of("=")+1); - BIO *b64 = BIO_new(BIO_f_base64()); - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - - BIO *bmem = BIO_new_mem_buf((void *)s.c_str(), s.size()); - bmem = BIO_push(b64, bmem); - - int decodedSize = BIO_read(bmem, data, length); - BIO_free_all(b64); - + int decodedSize = B64ToB256Bytes(s.size()); if (decodedSize != length) { LOG(ERROR) << "decoding bytes len " << s.size() @@ -133,6 +125,8 @@ bool XmlValue::readB64(const char *path, byte *data, int length) const << ", got " << decodedSize; return false; } + changeBase2((byte *)s.data(), s.size(), 6, data, length, 8); + B64ToAsciiStandard(data, length); return true; } diff --git a/base/base64.cpp b/base/base64.cpp index f89997f..215b02e 100644 --- a/base/base64.cpp +++ b/base/base64.cpp @@ -132,20 +132,39 @@ void changeBase2Inline(byte *src, int srcLen, static const char B642AsciiTable[] = ",-0123456789"; void B64ToAscii(byte *in, int length) { - for(int offset=0; offset 11) { - int ch = in[offset]; - if(ch > 11) - { - if(ch > 37) - ch += 'a' - 38; - else - ch += 'A' - 12; - } else - ch = B642AsciiTable[ ch ]; - - in[offset] = ch; - } + if(ch > 37) + ch += 'a' - 38; + else + ch += 'A' - 12; + } else + ch = B642AsciiTable[ ch ]; + + in[offset] = ch; + } +} + +void B64ToAsciiStandard(byte *in, int length) +{ + static const char LookupTable[] = "+/0123456789"; + for(int offset=0; offset 11) + { + if(ch > 37) + ch += 'a' - 38; + else + ch += 'A' - 12; + } else + ch = LookupTable[ ch ]; + + in[offset] = ch; + } } static const byte Ascii2B64Table[] = @@ -159,55 +178,55 @@ void AsciiToB64(byte *in, int length) void AsciiToB64(byte *out, const byte *in, int length) { - while(length--) + while(length--) + { + byte ch = *in++; + if(ch >= 'A') { - byte ch = *in++; - if(ch >= 'A') - { - if(ch >= 'a') - ch += 38 - 'a'; - else - ch += 12 - 'A'; - } else - ch = Ascii2B64Table[ ch ] - '0'; + if(ch >= 'a') + ch += 38 - 'a'; + else + ch += 12 - 'A'; + } else + ch = Ascii2B64Table[ ch ] - '0'; - *out++ = ch; - } + *out++ = ch; + } } void B32ToAscii(byte *buf, int len) { - for(int offset=0; offset= 0 && ch < 26) - ch += 'A'; - else - ch += '2' - 26; - - buf[offset] = ch; - } + for(int offset=0; offset= 0 && ch < 26) + ch += 'A'; + else + ch += '2' - 26; + + buf[offset] = ch; + } } void AsciiToB32(byte *in, int length) { - return AsciiToB32(in, in, length); + return AsciiToB32(in, in, length); } void AsciiToB32(byte *out, const byte *in, int length) { - while(length--) - { - byte ch = *in++; - int lch = toupper(ch); - if (lch >= 'A') - lch -= 'A'; - else - lch += 26 - '2'; + while(length--) + { + byte ch = *in++; + int lch = toupper(ch); + if (lch >= 'A') + lch -= 'A'; + else + lch += 26 - '2'; - *out++ = (byte)lch; - } + *out++ = (byte)lch; + } } } // namespace encfs diff --git a/base/base64.h b/base/base64.h index 6be224c..4434041 100644 --- a/base/base64.h +++ b/base/base64.h @@ -62,6 +62,8 @@ void changeBase2Inline(byte *buf, int srcLength, // inplace translation from values [0,2^6] => base64 ASCII void B64ToAscii(byte *buf, int length); +// Like B64ToAscii, but uses standard characters "+" and "/" in encoding. +void B64ToAsciiStandard(byte *buf, int length); // inplace translation from values [0,2^5] => base32 ASCII void B32ToAscii(byte *buf, int length); diff --git a/base/config.h.cmake b/base/config.h.cmake index 68fecab..fb3b11b 100644 --- a/base/config.h.cmake +++ b/base/config.h.cmake @@ -10,15 +10,19 @@ #cmakedefine HAVE_TR1_UNORDERED_SET #cmakedefine HAVE_TR1_TUPLE +#cmakedefine HAVE_VALGRIND_VALGRIND_H +#cmakedefine HAVE_VALGRIND_MEMCHECK_H + +#cmakedefine WITH_OPENSSL +#cmakedefine WITH_COMMON_CRYPTO +#cmakedefine HAVE_SEC_RANDOM_H + #cmakedefine HAVE_EVP_BF #cmakedefine HAVE_EVP_AES #cmakedefine HAVE_EVP_AES_XTS #cmakedefine HAVE_LCHMOD -#cmakedefine HAVE_VALGRIND_VALGRIND_H -#cmakedefine HAVE_VALGRIND_MEMCHECK_H - /* TODO: add other thread library support. */ #cmakedefine CMAKE_USE_PTHREADS_INIT diff --git a/cipher/BlockCipher.cpp b/cipher/BlockCipher.cpp index 75305c6..8d7e82d 100644 --- a/cipher/BlockCipher.cpp +++ b/cipher/BlockCipher.cpp @@ -1,7 +1,14 @@ #include "cipher/BlockCipher.h" -// TODO: add ifdef when OpenSSL becomes optional. +#include "base/config.h" + +#ifdef WITH_OPENSSL #include "cipher/openssl.h" +#endif +#ifdef WITH_COMMON_CRYPTO +#include "cipher/CommonCrypto.h" +#endif + #include "cipher/NullCiphers.h" namespace encfs { @@ -12,7 +19,12 @@ Registry& BlockCipher::GetRegistry() static bool first = true; if (first) { +#ifdef WITH_OPENSSL OpenSSL::registerCiphers(); +#endif +#ifdef WITH_COMMON_CRYPTO + CommonCrypto::registerCiphers(); +#endif NullCiphers::registerCiphers(); first = false; } diff --git a/cipher/BlockCipher_test.cpp b/cipher/BlockCipher_test.cpp index 8cf89f9..feeee7e 100644 --- a/cipher/BlockCipher_test.cpp +++ b/cipher/BlockCipher_test.cpp @@ -23,12 +23,17 @@ #include +#include "base/config.h" #include "base/shared_ptr.h" #include "cipher/BlockCipher.h" #include "cipher/MemoryPool.h" #include "cipher/PBKDF.h" #include "cipher/testing.h" +#ifdef HAVE_VALGRIND_MEMCHECK_H +#include +#endif + using namespace encfs; using std::list; using std::string; @@ -36,6 +41,10 @@ using std::string; namespace { void compare(const byte *a, const byte *b, int size) { +#ifdef HAVE_VALGRIND_MEMCHECK_H + ASSERT_EQ(0, VALGRIND_CHECK_MEM_IS_DEFINED(a, size)); + ASSERT_EQ(0, VALGRIND_CHECK_MEM_IS_DEFINED(b, size)); +#endif for (int i = 0; i < size; i++) { bool match = (a[i] == b[i]); ASSERT_TRUE(match) << "mismatched data at offset " << i @@ -61,31 +70,83 @@ TEST(RequiredStreamCiphers, StreamCipher) { ASSERT_TRUE(bf_cfb != NULL); } -TEST(BlowfishTestVector, BlockCihper) { - auto cbc = BlockCipher::GetRegistry().CreateForMatch(NAME_BLOWFISH_CBC); - auto cfb = StreamCipher::GetRegistry().CreateForMatch(NAME_BLOWFISH_CFB); +template +void checkTestVector(const char *cipherName, + const char *hexKey, + const char *hexIv, + const char *hexPlaintext, + const char *hexCipher) { + SCOPED_TRACE(testing::Message() << "Testing cipher: " << cipherName + << ", key = " << hexKey << ", plaintext = " << hexPlaintext); - CipherKey key(16); - setDataFromHex(key.data(), key.size(), "0123456789abcdeff0e1d2c3b4a59687"); - cbc->setKey(key); - cfb->setKey(key); + auto cipher = T::GetRegistry().CreateForMatch(cipherName); + ASSERT_TRUE(cipher != NULL); - byte iv[8]; - setDataFromHex(iv, 8, "fedcba9876543210"); + CipherKey key(strlen(hexKey)/2); + setDataFromHex(key.data(), key.size(), hexKey); + ASSERT_TRUE(cipher->setKey(key)); - byte data[32]; - setDataFromHex(data, 32, - "37363534333231204e6f77206973207468652074696d6520666f722000000000"); + byte iv[strlen(hexIv)/2]; + setDataFromHex(iv, sizeof(iv), hexIv); - byte cipherData[32]; - cbc->encrypt(iv, data, cipherData, 32); + byte plaintext[strlen(hexPlaintext)/2]; + setDataFromHex(plaintext, sizeof(plaintext), hexPlaintext); - ASSERT_EQ("6b77b4d63006dee605b156e27403979358deb9e7154616d959f1652bd5ff92cc", - stringToHex(cipherData, 32)); + byte ciphertext[sizeof(plaintext)]; + ASSERT_TRUE(cipher->encrypt(iv, plaintext, ciphertext, sizeof(ciphertext))); - cfb->encrypt(iv, data, cipherData, 29); - ASSERT_EQ("e73214a2822139caf26ecf6d2eb9e76e3da3de04d1517200519d57a6c3", - stringToHex(cipherData, 29)); + ASSERT_EQ(hexCipher, stringToHex(ciphertext, sizeof(ciphertext))); + + byte decypered[sizeof(plaintext)]; + ASSERT_TRUE(cipher->decrypt(iv, ciphertext, decypered, sizeof(ciphertext))); + + for (unsigned int i = 0; i < sizeof(plaintext); ++i) { + ASSERT_EQ(plaintext[i], decypered[i]); + } +} + +TEST(TestVectors, BlockCipher) { + // BF128 CBC + checkTestVector(NAME_BLOWFISH_CBC, + "0123456789abcdeff0e1d2c3b4a59687", + "fedcba9876543210", + "37363534333231204e6f77206973207468652074696d6520666f722000000000", + "6b77b4d63006dee605b156e27403979358deb9e7154616d959f1652bd5ff92cc"); + + // BF128 CFB + checkTestVector(NAME_BLOWFISH_CFB, + "0123456789abcdeff0e1d2c3b4a59687", + "fedcba9876543210", + "37363534333231204e6f77206973207468652074696d6520666f722000", + "e73214a2822139caf26ecf6d2eb9e76e3da3de04d1517200519d57a6c3"); + + // AES128 CBC + checkTestVector(NAME_AES_CBC, + "2b7e151628aed2a6abf7158809cf4f3c", + "000102030405060708090a0b0c0d0e0f", + "6bc1bee22e409f96e93d7e117393172a", + "7649abac8119b246cee98e9b12e9197d"); + + // AES128 CFB + checkTestVector(NAME_AES_CFB, + "2b7e151628aed2a6abf7158809cf4f3c", + "000102030405060708090a0b0c0d0e0f", + "6bc1bee22e409f96e93d7e117393172a", + "3b3fd92eb72dad20333449f8e83cfb4a"); + + // AES256 CBC + checkTestVector(NAME_AES_CBC, + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", + "000102030405060708090a0b0c0d0e0f", + "6bc1bee22e409f96e93d7e117393172a", + "f58c4c04d6e5f1ba779eabfb5f7bfbd6"); + + // AES256 CFB + checkTestVector(NAME_AES_CFB, + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", + "000102030405060708090a0b0c0d0e0f", + "6bc1bee22e409f96e93d7e117393172a", + "dc7e84bfda79164b7ecd8486985d3860"); } TEST(BlockEncryptionTest, BlockCipher) { @@ -109,10 +170,12 @@ TEST(BlockEncryptionTest, BlockCipher) { CipherKey key = pbkdf->randomKey(keySize / 8); ASSERT_TRUE(key.valid()); - cipher->setKey(key); + ASSERT_TRUE(cipher->setKey(key)); // Create some data to encrypt. int blockSize = cipher->blockSize(); + SCOPED_TRACE(testing::Message() << "blockSize " << blockSize); + MemBlock mb; mb.allocate(16 * blockSize); diff --git a/cipher/CMakeLists.txt b/cipher/CMakeLists.txt index f00a2c4..be1101e 100644 --- a/cipher/CMakeLists.txt +++ b/cipher/CMakeLists.txt @@ -1,7 +1,16 @@ -include_directories (${OPENSSL_INCLUDE_DIR}) - link_directories (${Encfs_BINARY_DIR}/base) +if (WITH_COMMON_CRYPTO) + find_library (SECURITY_FRAMEWORK Security) + mark_as_advanced (SECURITY_FRAMEWORK) + set (EXTRA_LIBS ${SECURITY_FRAMEWORK}) + set (EXTRA_SOURCE CommonCrypto.cpp) +elseif (WITH_OPENSSL) + include_directories (${OPENSSL_INCLUDE_DIR}) + set (EXTRA_LIBS ${OPENSSL_LIBRARIES}) + set (EXTRA_SOURCE openssl.cpp) +endif (WITH_COMMON_CRYPTO) + add_library (encfs-cipher BlockCipher.cpp CipherKey.cpp @@ -9,14 +18,14 @@ add_library (encfs-cipher MAC.cpp MemoryPool.cpp NullCiphers.cpp - openssl.cpp PBKDF.cpp readpassphrase.cpp StreamCipher.cpp + ${EXTRA_SOURCE} ) target_link_libraries (encfs-cipher - ${OPENSSL_LIBRARIES} + ${EXTRA_LIBS} ) if (GTEST_FOUND) diff --git a/cipher/CipherKey_test.cpp b/cipher/CipherKey_test.cpp new file mode 100644 index 0000000..a5898f2 --- /dev/null +++ b/cipher/CipherKey_test.cpp @@ -0,0 +1,45 @@ + +#include + +#include + +#include "base/config.h" +#include "base/shared_ptr.h" +#include "cipher/CipherV1.h" +#include "cipher/MemoryPool.h" +#include "cipher/testing.h" + +#ifdef HAVE_VALGRIND_MEMCHECK_H +#include +#endif + +using namespace encfs; +using std::list; +using std::string; + +namespace { + +TEST(CipherKey, ReadWrite) { + for (auto alg : CipherV1::GetAlgorithmList()) { + auto cipher = CipherV1::New(alg.iface); + + CipherKey masterKey = cipher->newRandomKey(); + CipherKey volumeKey = cipher->newRandomKey(); + + int encodedSize = cipher->encodedKeySize(); + unsigned char *keyBuf = new unsigned char[encodedSize]; + + cipher->setKey(masterKey); + cipher->writeKey(volumeKey, keyBuf); + + CipherKey readKey = cipher->readKey(keyBuf, true); + ASSERT_TRUE(readKey.valid()); + ASSERT_TRUE(readKey == volumeKey); + ASSERT_FALSE(readKey == masterKey); + + delete[] keyBuf; + } +} + + +} // namespace diff --git a/cipher/CipherV1.cpp b/cipher/CipherV1.cpp index fec3206..8dea654 100644 --- a/cipher/CipherV1.cpp +++ b/cipher/CipherV1.cpp @@ -19,6 +19,7 @@ */ #include "cipher/CipherV1.h" +#include "base/config.h" #include #include @@ -28,18 +29,29 @@ #include +#ifdef HAVE_VALGRIND_MEMCHECK_H +#include +#endif + #include "base/base64.h" #include "base/Error.h" #include "base/i18n.h" #include "base/Mutex.h" #include "base/Range.h" + #include "cipher/MemoryPool.h" #include "cipher/MAC.h" #include "cipher/BlockCipher.h" #include "cipher/PBKDF.h" #include "cipher/StreamCipher.h" -using namespace std; +#ifdef WITH_OPENSSL +#include "cipher/openssl.h" +#endif + +using std::list; +using std::string; +using std::vector; namespace encfs { @@ -54,6 +66,18 @@ inline int MIN(int a, int b) } #endif +void CipherV1::init(bool threaded) { +#ifdef WITH_OPENSSL + OpenSSL::init(threaded); +#endif +} + +void CipherV1::shutdown(bool threaded) { +#ifdef WITH_OPENSSL + OpenSSL::shutdown(threaded); +#endif +} + /* DEPRECATED: this is here for backward compatibilty only. Use PBKDF @@ -77,7 +101,7 @@ bool BytesToKey(const byte *data, int dataLen, for(;;) { - sha1->reset(); + sha1->init(); if( addmd++ ) sha1->update(mdBuf.data, mdBuf.size); sha1->update(data, dataLen); @@ -85,7 +109,7 @@ bool BytesToKey(const byte *data, int dataLen, for(unsigned int i=1; i < rounds; ++i) { - sha1->reset(); + sha1->init(); sha1->update(mdBuf.data, mdBuf.size); sha1->write(mdBuf.data); } @@ -115,6 +139,10 @@ int CipherV1::TimedPBKDF2(const char *pass, int passlen, const byte *salt, int saltlen, CipherKey *key, long desiredPDFTime) { +#ifdef HAVE_VALGRIND_MEMCHECK_H + VALGRIND_CHECK_MEM_IS_DEFINED(pass, passlen); + VALGRIND_CHECK_MEM_IS_DEFINED(salt, saltlen); +#endif Registry registry = PBKDF::GetRegistry(); shared_ptr impl(registry.CreateForMatch(NAME_PKCS5_PBKDF2_HMAC_SHA1)); if (!impl) @@ -212,11 +240,18 @@ shared_ptr CipherV1::New(const std::string& name, int keyLen) { } shared_ptr CipherV1::New(const Interface &iface, int keyLen) { - return shared_ptr(new CipherV1(iface, iface, keyLen)); + shared_ptr result(new CipherV1()); + if (!result->initCiphers(iface, iface, keyLen)) + result.reset(); + return result; } -CipherV1::CipherV1(const Interface &iface, const Interface &realIface, - int keyLength) +CipherV1::CipherV1() +{ +} + +bool CipherV1::initCiphers(const Interface &iface, const Interface &realIface, + int keyLength) { this->iface = iface; this->realIface = realIface; @@ -243,12 +278,11 @@ CipherV1::CipherV1(const Interface &iface, const Interface &realIface, defaultKeyLength = 0; _blockCipher.reset( blockCipherRegistry.CreateForMatch("NullCipher") ); _streamCipher.reset( streamCipherRegistry.CreateForMatch("NullCipher") ); - } else { - throw Error("Unsupported cipher"); } if (!_blockCipher || !_streamCipher) { - throw Error("Requested cipher not available"); + LOG(INFO) << "Unsupported cipher " << iface.name(); + return false; } if (keyLength <= 0) @@ -259,7 +293,8 @@ CipherV1::CipherV1(const Interface &iface, const Interface &realIface, _pbkdf.reset(PBKDF::GetRegistry().CreateForMatch( NAME_PKCS5_PBKDF2_HMAC_SHA1)); if (!_pbkdf) { - throw Error("PBKDF not available"); + LOG(ERROR) << "PBKDF missing"; + return false; } // Initialize the cipher with a temporary key in order to determine the block @@ -272,8 +307,12 @@ CipherV1::CipherV1(const Interface &iface, const Interface &realIface, Lock l(_hmacMutex); _hmac.reset(MAC::GetRegistry().CreateForMatch(NAME_SHA1_HMAC)); - if (!_hmac) - throw Error("SHA1_HMAC not available"); + if (!_hmac) { + LOG(ERROR) << "SHA1_HMAC not available"; + return false; + } + + return true; } CipherV1::~CipherV1() @@ -296,6 +335,10 @@ CipherKey CipherV1::newKey(const char *password, int passwdLength, int *iterationCount, long desiredDuration, const byte *salt, int saltLen) { +#ifdef HAVE_VALGRIND_MEMCHECK_H + VALGRIND_CHECK_MEM_IS_DEFINED(password, passwdLength); + VALGRIND_CHECK_MEM_IS_DEFINED(salt, saltLen); +#endif CipherKey key(_keySize + _ivLength); if(*iterationCount == 0) @@ -329,6 +372,9 @@ CipherKey CipherV1::newKey(const char *password, int passwdLength, // password is changed or configuration is rewritten. CipherKey CipherV1::newKey(const char *password, int passwdLength) { +#ifdef HAVE_VALGRIND_MEMCHECK_H + VALGRIND_CHECK_MEM_IS_DEFINED(password, passwdLength); +#endif CipherKey key(_keySize + _ivLength); bool ok = BytesToKey((byte *)password, passwdLength, 16, &key); @@ -376,8 +422,8 @@ uint64_t CipherV1::MAC_64(const byte *data, int len, byte md[_hmac->outputSize()]; Lock l(_hmacMutex); - _hmac->reset(); + _hmac->init(); _hmac->update(data, len); if(chainedIV) { @@ -398,8 +444,11 @@ uint64_t CipherV1::MAC_64(const byte *data, int len, // chop this down to a 64bit value.. byte h[8] = {0,0,0,0,0,0,0,0}; - // TODO: outputSize - 1? - for(unsigned int i=0; i<_hmac->outputSize(); ++i) + + // XXX: the last byte off the hmac isn't used. This minor inconsistency + // must be maintained in order to maintain backward compatiblity with earlier + // releases. + for(int i=0; i<_hmac->outputSize()-1; ++i) h[i%8] ^= (byte)(md[i]); uint64_t value = (uint64_t)h[0]; @@ -435,14 +484,27 @@ CipherKey CipherV1::readKey(const byte *data, bool checkKey) checksum = (checksum << 8) | (unsigned int)data[i]; memcpy( key.data(), data+KEY_CHECKSUM_BYTES, key.size() ); - streamDecode(key.data(), key.size(), checksum); + if (!streamDecode(key.data(), key.size(), checksum)) { + LOG(ERROR) << "stream decode failure"; + return CipherKey(); + } // check for success +#ifdef HAVE_VALGRIND_MEMCHECK_H + VALGRIND_CHECK_MEM_IS_DEFINED(key.data(), key.size()); +#endif + unsigned int checksum2 = reduceMac32( MAC_64( key.data(), key.size(), NULL )); - if(checksum2 != checksum && checkKey) + +#ifdef HAVE_VALGRIND_MEMCHECK_H + VALGRIND_CHECK_VALUE_IS_DEFINED(checksum2); + VALGRIND_CHECK_VALUE_IS_DEFINED(checksum); +#endif + + if(checkKey && (checksum2 != checksum)) { - VLOG(1) << "checksum mismatch: expected " << checksum + LOG(INFO) << "checksum mismatch: expected " << checksum << ", got " << checksum2 << "on decode of " << _keySize + _ivLength << " bytes"; return CipherKey(); @@ -454,23 +516,22 @@ CipherKey CipherV1::readKey(const byte *data, bool checkKey) void CipherV1::writeKey(const CipherKey &ckey, byte *out) { rAssert( _keySet ); - rAssert(ckey.size() > KEY_CHECKSUM_BYTES); SecureMem tmpBuf(ckey.size()); memcpy(tmpBuf.data, ckey.data(), tmpBuf.size); unsigned int checksum = reduceMac32( - MAC_64( tmpBuf.data, tmpBuf.size, NULL )); + MAC_64(tmpBuf.data, tmpBuf.size, NULL)); streamEncode(tmpBuf.data, tmpBuf.size, checksum); - memcpy( out+KEY_CHECKSUM_BYTES, tmpBuf.data, tmpBuf.size ); - // first N bytes contain HMAC derived checksum.. for(int i=1; i<=KEY_CHECKSUM_BYTES; ++i) { out[KEY_CHECKSUM_BYTES-i] = checksum & 0xff; checksum >>= 8; } + + memcpy( out+KEY_CHECKSUM_BYTES, tmpBuf.data, tmpBuf.size ); } std::string CipherV1::encodeAsString(const CipherKey &key) @@ -558,7 +619,7 @@ void CipherV1::setIVec(byte *ivec, uint64_t seed) const // combine ivec and seed with HMAC Lock l(_hmacMutex); - _hmac->reset(); + _hmac->init(); _hmac->update(ivec, _ivLength); _hmac->update(md.data(), 8); _hmac->write(md.data()); diff --git a/cipher/CipherV1.h b/cipher/CipherV1.h index 376cfc1..03a840a 100644 --- a/cipher/CipherV1.h +++ b/cipher/CipherV1.h @@ -102,6 +102,9 @@ class CipherV1 Range blockSize; }; + static void init(bool threaded); + static void shutdown(bool threaded); + // Returns a list of supported algorithms. static std::list GetAlgorithmList(); static shared_ptr New(const std::string &name, int keyLen = -1); @@ -114,9 +117,12 @@ class CipherV1 const byte *salt, int saltLen, CipherKey *out, long desiredPDFTimeMicroseconds); - CipherV1(const Interface &iface, const Interface &realIface, int keyLength); + CipherV1(); ~CipherV1(); + bool initCiphers(const Interface &iface, + const Interface &realIface, int keyLength); + // returns the real interface, not the one we're emulating (if any).. Interface interface() const; diff --git a/cipher/CommonCrypto.cpp b/cipher/CommonCrypto.cpp new file mode 100644 index 0000000..1bb24d0 --- /dev/null +++ b/cipher/CommonCrypto.cpp @@ -0,0 +1,263 @@ + +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2013 Valient Gough + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "cipher/CommonCrypto.h" + +#include + +#include +#include +#include +#include + +#include "base/config.h" +#include "cipher/BlockCipher.h" +#include "cipher/MAC.h" +#include "cipher/PBKDF.h" + +#ifdef HAVE_SEC_RANDOM_H +#include +#endif + +namespace encfs { +namespace commoncrypto { + +class PbkdfPkcs5HmacSha1CC : public PBKDF { +public: + PbkdfPkcs5HmacSha1CC() {} + virtual ~PbkdfPkcs5HmacSha1CC() {} + + virtual bool makeKey(const char *password, int passwordLength, + const byte *salt, int saltLength, + int numIterations, + CipherKey *outKey) { + int ret = CCKeyDerivationPBKDF(kCCPBKDF2, password, passwordLength, + salt, saltLength, kCCPRFHmacAlgSHA1, + numIterations, + outKey->data(), outKey->size()); + if (ret != 0) { + PLOG(ERROR) << "CCKeyDerivationPBKDF failed"; + return false; + } + return true; + } + + virtual CipherKey randomKey(int length) { + CipherKey key(length); + if (length == 0) return key; +#ifdef HAVE_SEC_RANDOM_H + if (SecRandomCopyBytes(kSecRandomDefault, key.size(), key.data()) < 0) { + PLOG(ERROR) << "random key generation failure for length " << length; + key.reset(); + } +#else +#error No random number generator provided. +#endif + return key; + } + + virtual bool pseudoRandom(byte *out, int length) { + if (length == 0) return true; +#ifdef HAVE_SEC_RANDOM_H + if (SecRandomCopyBytes(kSecRandomDefault, length, out) < 0) { + PLOG(ERROR) << "random key generation failure for length " << length; + return false; + } +#else +#error No random number generator provided. +#endif + return true; + } + + static Properties GetProperties() { + Properties props; + props.mode = NAME_PKCS5_PBKDF2_HMAC_SHA1; + props.library = "CommonCrypto"; + return props; + } +}; +REGISTER_CLASS(PbkdfPkcs5HmacSha1CC, PBKDF); + +class CCCipher : public BlockCipher { + CipherKey key; + CCAlgorithm algorithm; + CCMode mode; + public: + CCCipher() { } + virtual ~CCCipher() { } + + bool rekey(const CipherKey &key, CCAlgorithm algorithm, CCMode mode) { + this->key = key; + this->algorithm = algorithm; + this->mode = mode; + return true; + } + + virtual bool encrypt(const byte *iv, const byte *in, byte *out, int size) { + CCCryptorRef cryptor; + CCCryptorCreateWithMode(kCCEncrypt, mode, algorithm, 0, + iv, key.data(), key.size(), + NULL, 0, 0, 0, &cryptor); + size_t updateLength = 0; + CCCryptorUpdate(cryptor, in, size, out, size, &updateLength); + CCCryptorRelease(cryptor); + return true; + } + + virtual bool decrypt(const byte *iv, const byte *in, byte *out, int size) { + CCCryptorRef cryptor; + CCCryptorCreateWithMode(kCCDecrypt, mode, algorithm, 0, + iv, key.data(), key.size(), + NULL, 0, 0, 0, &cryptor); + size_t updateLength = 0; + CCCryptorUpdate(cryptor, in, size, out, size, &updateLength); + CCCryptorRelease(cryptor); + return true; + } +}; + +class BfCbc : public CCCipher { + public: + BfCbc() {} + virtual ~BfCbc() {} + + virtual bool setKey(const CipherKey &key) { + return CCCipher::rekey(key, kCCAlgorithmBlowfish, kCCModeCBC); + } + + virtual int blockSize() const { + return kCCBlockSizeBlowfish; + } + + static Properties GetProperties() { + return Properties(Range(128,256,32), "Blowfish", "CBC", "CommonCrypto"); + } +}; +REGISTER_CLASS(BfCbc, BlockCipher); + +class AesCbc : public CCCipher { + public: + AesCbc() {} + virtual ~AesCbc() {} + + virtual bool setKey(const CipherKey &key) { + return CCCipher::rekey(key, kCCAlgorithmAES128, kCCModeCBC); + } + + virtual int blockSize() const { + return kCCBlockSizeAES128; + } + + static Properties GetProperties() { + return Properties(Range(128,256,64), "AES", "CBC", "CommonCrypto"); + } +}; +REGISTER_CLASS(AesCbc, BlockCipher); + +class BfCfb : public CCCipher { + public: + BfCfb() {} + virtual ~BfCfb() {} + + virtual bool setKey(const CipherKey &key) { + return CCCipher::rekey(key, kCCAlgorithmBlowfish, kCCModeCFB); + } + + virtual int blockSize() const { return 1; } + + static Properties GetProperties() { + return Properties(Range(128,256,32), "Blowfish", "CFB", "CommonCrypto"); + } +}; +REGISTER_CLASS(BfCfb, StreamCipher); + +class AesCfb : public CCCipher { + public: + AesCfb() {} + virtual ~AesCfb() {} + + virtual bool setKey(const CipherKey &key) { + return CCCipher::rekey(key, kCCAlgorithmAES128, kCCModeCFB); + } + + virtual int blockSize() const { return 1; } + + static Properties GetProperties() { + return Properties(Range(128,256,64), "AES", "CFB", "CommonCrypto"); + } +}; +REGISTER_CLASS(AesCfb, StreamCipher); + +class Sha1HMac : public MAC { + public: + Sha1HMac() {} + virtual ~Sha1HMac() {} + + virtual int outputSize() const { + return CC_SHA1_DIGEST_LENGTH; + } + + virtual bool setKey(const CipherKey &key) { + this->key = key; + return true; + } + + virtual void init() { + if (key.size() > 0) { + CCHmacInit(&ctx, kCCHmacAlgSHA1, key.data(), key.size()); + } else { + // CommonCrypto will segfault later on if a null key is passed, even if + // key length is 0. + CCHmacInit(&ctx, kCCHmacAlgSHA1, &ctx, 0); + } + } + + virtual bool update (const byte *in, int length) { + CCHmacUpdate(&ctx, in, length); + return true; + } + + virtual bool write(byte *out) { + CCHmacFinal(&ctx, out); + return true; + } + + static Properties GetProperties() { + Properties props; + props.blockSize = CC_SHA1_DIGEST_LENGTH; + props.hashFunction = "SHA-1"; + props.mode = "HMAC"; + props.library = "CommonCrypto"; + return props; + } + + private: + CipherKey key; + CCHmacContext ctx; +}; +REGISTER_CLASS(Sha1HMac, MAC); + +} // namespace commoncrypto + +void CommonCrypto::registerCiphers() { +} + +} // namespace encfs diff --git a/cipher/CommonCrypto.h b/cipher/CommonCrypto.h new file mode 100644 index 0000000..d08289b --- /dev/null +++ b/cipher/CommonCrypto.h @@ -0,0 +1,35 @@ + +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2013 Valient Gough + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef _COMMONCRYPTO_incl_ +#define _COMMONCRYPTO_incl_ + +namespace encfs { + +struct CommonCrypto { + static void registerCiphers(); +}; + +} // namespace encfs + + +#endif + diff --git a/cipher/MAC.h b/cipher/MAC.h index 436e6d6..d0b7fd5 100644 --- a/cipher/MAC.h +++ b/cipher/MAC.h @@ -35,7 +35,8 @@ class MAC virtual bool setKey(const CipherKey &key) =0; - virtual void reset() =0; + // Init must be called before any calls to update. + virtual void init() =0; virtual bool update(const byte *in, int length) =0; virtual bool write(byte *out) =0; }; diff --git a/cipher/MAC_test.cpp b/cipher/MAC_test.cpp index de8115c..7afc7d9 100644 --- a/cipher/MAC_test.cpp +++ b/cipher/MAC_test.cpp @@ -44,7 +44,7 @@ TEST(HMacSha1Test, MAC) { for (int i = 0; i < 20; ++i) key.data()[i] = 0x0b; hmac->setKey(key); - hmac->reset(); + hmac->init(); hmac->update((byte *)"Hi There", 8); hmac->write(out); ASSERT_EQ("b617318655057264e28bc0b6fb378c8ef146be00", stringToHex(out, 20)); @@ -52,7 +52,7 @@ TEST(HMacSha1Test, MAC) { // Test case 2 key = CipherKey((const byte *)"Jefe", 4); hmac->setKey(key); - hmac->reset(); + hmac->init(); hmac->update((byte *)"what do ya want for nothing?", 28); hmac->write(out); ASSERT_EQ("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79", stringToHex(out, 20)); @@ -62,7 +62,7 @@ TEST(HMacSha1Test, MAC) { for (int i = 0; i < 20; ++i) key.data()[i] = 0xaa; hmac->setKey(key); - hmac->reset(); + hmac->init(); { byte data[50]; memset(data, 0xdd, 50); @@ -75,7 +75,7 @@ TEST(HMacSha1Test, MAC) { key = CipherKey(80); memset(key.data(), 0xaa, 80); hmac->setKey(key); - hmac->reset(); + hmac->init(); hmac->update((byte *)"Test Using Larger Than Block-Size Key and Larger " "Than One Block-Size Data", 73); hmac->write(out); diff --git a/cipher/MemoryPool.cpp b/cipher/MemoryPool.cpp index 5c079f3..14e68c6 100644 --- a/cipher/MemoryPool.cpp +++ b/cipher/MemoryPool.cpp @@ -42,105 +42,69 @@ #include #include -using namespace std; - +#ifdef WITH_OPENSSL # include # include +#endif namespace encfs { -static BUF_MEM *allocBlock( int size ) +#ifdef WITH_OPENSSL +static byte *allocBlock( int size ) { - BUF_MEM *block = BUF_MEM_new( ); - BUF_MEM_grow( block, size ); - VALGRIND_MAKE_MEM_NOACCESS( block->data, block->max ); - - return block; + byte *block = (byte *)OPENSSL_malloc(size); + return block; } -static void freeBlock( BUF_MEM *block ) +static void freeBlock( byte *block, int size ) { - VALGRIND_MAKE_MEM_UNDEFINED( block->data, block->max ); - BUF_MEM_free( block ); + OPENSSL_cleanse(block, size); + OPENSSL_free(block); +} +#elif defined(WITH_COMMON_CRYPTO) +static byte *allocBlock(int size) { + byte *block = new byte[size]; + return block; } -static pthread_mutex_t gMPoolMutex = PTHREAD_MUTEX_INITIALIZER; - -typedef std::map > FreeBlockMap; -static FreeBlockMap gFreeBlocks; +unsigned char cleanse_ctr = 0; +static void freeBlock(byte *data, int len) { + byte *p = data; + size_t loop = len, ctr = cleanse_ctr; + while(loop--) + { + *(p++) = (unsigned char)ctr; + ctr += (17 + ((size_t)p & 0xF)); + } + // Try to ensure the compiler doesn't optimize away the loop. + p=(byte *)memchr(data, (unsigned char)ctr, len); + if(p) + ctr += (63 + (size_t)p); + cleanse_ctr = (unsigned char)ctr; + delete[] data; +} +#endif void MemBlock::allocate(int size) { - rAssert(size > 0); - pthread_mutex_lock( &gMPoolMutex ); - - list &freeList = gFreeBlocks[size]; - BUF_MEM *mem; - - if (!freeList.empty()) - { - mem = freeList.front(); - freeList.pop_front(); - pthread_mutex_unlock( &gMPoolMutex ); - } else - { - pthread_mutex_unlock( &gMPoolMutex ); - mem = allocBlock( size ); - } - - internalData = mem; - data = reinterpret_cast(mem->data); - VALGRIND_MAKE_MEM_UNDEFINED( data, size ); + rAssert(size > 0); + this->data = allocBlock(size); + this->size = size; } MemBlock::~MemBlock() { - BUF_MEM *block = (BUF_MEM*)internalData; - data = NULL; - internalData = NULL; - - if (block) - { - // wipe the buffer.. - VALGRIND_MAKE_MEM_UNDEFINED( block->data, block->max ); - memset( block->data , 0, block->max); - VALGRIND_MAKE_MEM_NOACCESS( block->data, block->max ); - - pthread_mutex_lock( &gMPoolMutex ); - gFreeBlocks[ block->max ].push_front(block); - pthread_mutex_unlock( &gMPoolMutex ); - } -} - -void MemoryPool::destroyAll() -{ - pthread_mutex_lock( &gMPoolMutex ); - - for (FreeBlockMap::const_iterator it = gFreeBlocks.begin(); - it != gFreeBlocks.end(); it++) - { - for (list::const_iterator bIt = it->second.begin(); - bIt != it->second.end(); bIt++) - { - freeBlock( *bIt ); - } - } - - gFreeBlocks.clear(); - - pthread_mutex_unlock( &gMPoolMutex ); + freeBlock(data, size); } SecureMem::SecureMem(int len) { rAssert(len > 0); - data = (byte *)OPENSSL_malloc(len); + data = allocBlock(len); if (data) { size = len; mlock(data, size); - memset(data, '\0', size); - VALGRIND_MAKE_MEM_UNDEFINED( data, size ); } else { size = 0; @@ -151,17 +115,18 @@ SecureMem::~SecureMem() { if (size) { - memset(data, '\0', size); - OPENSSL_cleanse(data, size); - + freeBlock(data, size); munlock(data, size); - OPENSSL_free(data); - VALGRIND_MAKE_MEM_NOACCESS( data, size ); data = NULL; size = 0; } } - + +bool operator == (const SecureMem &a, const SecureMem &b) { + return (a.size == b.size) && + (memcmp(a.data, b.data, a.size) == 0); +} + } // namespace encfs diff --git a/cipher/MemoryPool.h b/cipher/MemoryPool.h index 26070a4..fcd5d96 100644 --- a/cipher/MemoryPool.h +++ b/cipher/MemoryPool.h @@ -39,7 +39,7 @@ namespace encfs { struct MemBlock { byte *data; - void *internalData; + int size; MemBlock(); ~MemBlock(); @@ -48,15 +48,10 @@ struct MemBlock }; inline MemBlock::MemBlock() - : data(0), internalData(0) + : data(0), size(0) { } -namespace MemoryPool -{ - void destroyAll(); -} - class SecureMem { public: @@ -67,6 +62,8 @@ class SecureMem ~SecureMem(); }; +bool operator == (const SecureMem &a, const SecureMem &b); + } // namespace encfs #endif diff --git a/cipher/StreamCipher.h b/cipher/StreamCipher.h index 3a54e1e..c5c8055 100644 --- a/cipher/StreamCipher.h +++ b/cipher/StreamCipher.h @@ -46,6 +46,13 @@ class StreamCipher std::string toString() const { return cipher + "/" + mode; } + Properties() {} + Properties(Range keys, const char *cipher_, const char *mode_, + const char *library_) + : keySize(keys), + cipher(cipher_), + mode(mode_), + library(library_) { } }; StreamCipher(); @@ -53,9 +60,9 @@ class StreamCipher virtual bool setKey(const CipherKey& key) =0; - virtual bool encrypt(const byte *iv, const byte *in, + virtual bool encrypt(const byte *ivec, const byte *in, byte *out, int numBytes) =0; - virtual bool decrypt(const byte *iv, const byte *in, + virtual bool decrypt(const byte *ivec, const byte *in, byte *out, int numBytes) =0; }; diff --git a/cipher/openssl.cpp b/cipher/openssl.cpp index ebf5f63..7e44e6e 100644 --- a/cipher/openssl.cpp +++ b/cipher/openssl.cpp @@ -19,6 +19,7 @@ */ #include "cipher/openssl.h" +#include "base/config.h" #include #include @@ -28,6 +29,10 @@ #include +#ifdef HAVE_VALGRIND_MEMCHECK_H +#include +#endif + #include "base/config.h" #define NO_DES @@ -54,8 +59,6 @@ #include "cipher/PBKDF.h" #include "cipher/StreamCipher.h" -using namespace std; - namespace encfs { const int MAX_KEYLENGTH = 64; // in bytes (256 bit) @@ -108,10 +111,18 @@ class OpenSSLCipher : public BlockCipher { return false; } +#ifdef HAVE_VALGRIND_MEMCHECK_H + VALGRIND_MAKE_MEM_DEFINED(key->data(), key->size()); +#endif return true; } static bool pseudoRandomize(byte *out, int length) { +#ifdef HAVE_VALGRIND_MEMCHECK_H + if (VALGRIND_CHECK_MEM_IS_ADDRESSABLE(out, length) != 0) { + return false; + } +#endif int result = RAND_pseudo_bytes( out, length ); if(result != 1) { @@ -136,12 +147,27 @@ class OpenSSLCipher : public BlockCipher { } virtual int blockSize() const { - return EVP_CIPHER_CTX_block_size(&enc); + int len = EVP_CIPHER_CTX_block_size(&enc); + // Some versions of OpenSSL report 1 for block size os AES_XTS.. + if (len == 1) + len = EVP_CIPHER_CTX_key_length(&enc); + return len; } virtual bool encrypt(const byte *ivec, const byte *in, byte *out, int size) { int dstLen = 0, tmpLen = 0; +#ifdef HAVE_VALGRIND_MEMCHECK_H + int ivLen = EVP_CIPHER_CTX_iv_length(&enc); + if (VALGRIND_CHECK_MEM_IS_DEFINED(ivec, ivLen) != 0) { + LOG(ERROR) << "expected iv of length " << ivLen; + return false; + } + if (VALGRIND_CHECK_MEM_IS_ADDRESSABLE(out, size) != 0) { + LOG(ERROR) << "expected output length " << size; + return false; + } +#endif EVP_EncryptInit_ex( &enc, NULL, NULL, NULL, ivec); EVP_EncryptUpdate( &enc, out, &dstLen, in, size); EVP_EncryptFinal_ex( &enc, out+dstLen, &tmpLen ); @@ -159,6 +185,17 @@ class OpenSSLCipher : public BlockCipher { virtual bool decrypt(const byte *ivec, const byte *in, byte *out, int size) { int dstLen = 0, tmpLen = 0; +#ifdef HAVE_VALGRIND_MEMCHECK_H + int ivLen = EVP_CIPHER_CTX_iv_length(&enc); + if (VALGRIND_CHECK_MEM_IS_DEFINED(ivec, ivLen) != 0) { + LOG(ERROR) << "expected iv of length " << ivLen; + return false; + } + if (VALGRIND_CHECK_MEM_IS_ADDRESSABLE(out, size) != 0) { + LOG(ERROR) << "expected output length " << size; + return false; + } +#endif EVP_DecryptInit_ex( &dec, NULL, NULL, NULL, ivec); EVP_DecryptUpdate( &dec, out, &dstLen, in, size ); EVP_DecryptFinal_ex( &dec, out+dstLen, &tmpLen ); @@ -346,7 +383,7 @@ class Sha1HMac : public MAC { return true; } - virtual void reset() { + virtual void init() { HMAC_Init_ex(&ctx, 0, 0, 0, 0); } @@ -364,6 +401,9 @@ class Sha1HMac : public MAC { unsigned int outSize = 0; HMAC_Final(&ctx, (unsigned char *)out, &outSize); CHECK_EQ(outputSize(), outSize) << "Invalid HMAC output size"; +#ifdef HAVE_VALGRIND_MEMCHECK_H + VALGRIND_MAKE_MEM_DEFINED(out, outSize); +#endif return true; } diff --git a/cipher/testing.cpp b/cipher/testing.cpp index 547b694..1ed5649 100644 --- a/cipher/testing.cpp +++ b/cipher/testing.cpp @@ -1,8 +1,14 @@ +#include #include +#include "base/config.h" #include "cipher/testing.h" +#ifdef HAVE_VALGRIND_MEMCHECK_H +#include +#endif + namespace encfs { static const char hexLut[] = "0123456789abcdef"; @@ -22,6 +28,9 @@ std::string stringToHex(const byte *data, int len) { } void setDataFromHex(byte *out, int len, const char *hex) { +#ifdef HAVE_VALGRIND_MEMCHECK_H + VALGRIND_CHECK_MEM_IS_ADDRESSABLE(out, len); +#endif bool odd = false; unsigned int last = 0; while (len > 0 && *hex != '\0') { @@ -49,6 +58,7 @@ void setDataFromHex(byte *out, int len, const char *hex) { } int main(int argc, char **argv) { + google::InitGoogleLogging(argv[0]); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } diff --git a/encfs/main.cpp b/encfs/main.cpp index f1cfbc4..374adcb 100644 --- a/encfs/main.cpp +++ b/encfs/main.cpp @@ -40,8 +40,7 @@ #include "base/Interface.h" #include "base/i18n.h" -#include "cipher/MemoryPool.h" -#include "cipher/openssl.h" +#include "cipher/CipherV1.h" #include "fs/FileUtils.h" #include "fs/DirNode.h" @@ -61,9 +60,12 @@ inline static int MAX(int a, int b) } #endif -using namespace std; -using namespace gnu; using namespace encfs; +using gnu::autosprintf; +using std::cerr; +using std::endl; +using std::string; +using std::ostringstream; namespace encfs { @@ -580,7 +582,7 @@ int main(int argc, char *argv[]) // encfs_oper.fsetattr_x #endif - OpenSSL::init( encfsArgs->isThreaded ); + CipherV1::init( encfsArgs->isThreaded ); // context is not a smart pointer because it will live for the life of // the filesystem. @@ -672,8 +674,7 @@ int main(int argc, char *argv[]) rootInfo.reset(); ctx->setRoot( shared_ptr() ); - MemoryPool::destroyAll(); - OpenSSL::shutdown( encfsArgs->isThreaded ); + CipherV1::shutdown( encfsArgs->isThreaded ); return returnCode; } diff --git a/fs/CMakeLists.txt b/fs/CMakeLists.txt index ae6b86c..27c837a 100644 --- a/fs/CMakeLists.txt +++ b/fs/CMakeLists.txt @@ -24,6 +24,16 @@ target_link_libraries (encfs-fs ${PROTOBUF_LIBRARY} ) +add_executable (checkops + checkops.cpp +) +target_link_libraries (checkops + encfs-fs + encfs-cipher + encfs-base + ${GLOG_LIBRARIES} +) + # Unit tests are optional, depends on libgtest (Google's C++ test framework). if (GTEST_FOUND) link_directories (${PROJECT_BINARY_DIR}/base) diff --git a/fs/CipherFileIO.cpp b/fs/CipherFileIO.cpp index 762a090..2bb4438 100644 --- a/fs/CipherFileIO.cpp +++ b/fs/CipherFileIO.cpp @@ -289,8 +289,7 @@ ssize_t CipherFileIO::readOneBlock( const IORequest &req ) const IORequest tmpReq = req; MemBlock mb; - if (headerLen != 0) - tmpReq.offset += headerLen; + tmpReq.offset += headerLen; int maxReadSize = req.dataLen; readSize = base->read( tmpReq ); diff --git a/fs/CipherFileIO.h b/fs/CipherFileIO.h index 2193b39..2c17f5b 100644 --- a/fs/CipherFileIO.h +++ b/fs/CipherFileIO.h @@ -84,8 +84,6 @@ private: // if haveHeader is true, then we have a transparent file header which int headerLen; - // Use block only encryption, no stream encryption. - bool blockOnlyMode; bool perFileIV; bool externalIVChaining; diff --git a/fs/Context.h b/fs/Context.h index 61888e3..00426c3 100644 --- a/fs/Context.h +++ b/fs/Context.h @@ -26,6 +26,7 @@ #include "base/Mutex.h" #include +#include #ifdef HAVE_TR1_UNORDERED_MAP #include diff --git a/fs/DirNode.cpp b/fs/DirNode.cpp index 54ab0cd..21e5452 100644 --- a/fs/DirNode.cpp +++ b/fs/DirNode.cpp @@ -44,7 +44,8 @@ #include -using namespace std; +using std::list; +using std::string; namespace encfs { diff --git a/fs/FSConfig.h b/fs/FSConfig.h index 296841a..94d1bea 100644 --- a/fs/FSConfig.h +++ b/fs/FSConfig.h @@ -75,6 +75,11 @@ struct FSConfig bool reverseEncryption; // reverse encryption operation bool idleTracking; // turn on idle monitoring of filesystem + + FSConfig() + : forceDecode(false), + reverseEncryption(false), + idleTracking(false) { } }; typedef shared_ptr FSConfigPtr; diff --git a/fs/FileNode.cpp b/fs/FileNode.cpp index 978d7c4..1895f07 100644 --- a/fs/FileNode.cpp +++ b/fs/FileNode.cpp @@ -49,7 +49,7 @@ #include -using namespace std; +using std::string; namespace encfs { diff --git a/fs/FileUtils.cpp b/fs/FileUtils.cpp index 938da03..3f61e1f 100644 --- a/fs/FileUtils.cpp +++ b/fs/FileUtils.cpp @@ -66,8 +66,12 @@ #include #include -using namespace std; -using namespace gnu; +using gnu::autosprintf; +using std::cout; +using std::cerr; +using std::endl; +using std::map; +using std::string; namespace encfs { @@ -1186,6 +1190,11 @@ void showFSInfo( const EncfsConfig &config ) cout << "\n"; } else { + // Set a null key - the cipher won't work, but it will at least know the + // key size and blocksize. + CipherKey tmpKey(config.key().size()); + cipher->setKey(tmpKey); + // check if we support the filename encoding interface.. shared_ptr nameCoder = NameIO::New( config.naming(), cipher ); if(!nameCoder) diff --git a/fs/MACFileIO.cpp b/fs/MACFileIO.cpp index cef8e6d..db48c81 100644 --- a/fs/MACFileIO.cpp +++ b/fs/MACFileIO.cpp @@ -30,8 +30,6 @@ #include -using namespace std; - namespace encfs { // diff --git a/fs/NameIO.cpp b/fs/NameIO.cpp index a7494aa..b8c6740 100644 --- a/fs/NameIO.cpp +++ b/fs/NameIO.cpp @@ -34,7 +34,11 @@ #include "fs/StreamNameIO.h" #include "fs/NullNameIO.h" -using namespace std; +using std::cerr; +using std::list; +using std::make_pair; +using std::multimap; +using std::string; namespace encfs { diff --git a/fs/RawFileIO.cpp b/fs/RawFileIO.cpp index 4b15743..fa76676 100644 --- a/fs/RawFileIO.cpp +++ b/fs/RawFileIO.cpp @@ -35,8 +35,6 @@ #include -using namespace std; - namespace encfs { static Interface RawFileIO_iface = makeInterface("FileIO/Raw", 1, 0, 0); diff --git a/fs/StreamNameIO.cpp b/fs/StreamNameIO.cpp index a7a703d..77968cf 100644 --- a/fs/StreamNameIO.cpp +++ b/fs/StreamNameIO.cpp @@ -28,8 +28,6 @@ #include -using namespace std; - namespace encfs { static shared_ptr NewStreamNameIO( const Interface &iface, diff --git a/fs/test.cpp b/fs/checkops.cpp similarity index 88% rename from fs/test.cpp rename to fs/checkops.cpp index c1a0c1d..591ca34 100644 --- a/fs/test.cpp +++ b/fs/checkops.cpp @@ -26,7 +26,7 @@ #include "base/config.h" #include "base/Interface.h" #include "base/Error.h" -#include "cipher/Cipher.h" +#include "cipher/CipherV1.h" #include "cipher/MemoryPool.h" #include "fs/DirNode.h" #include "fs/FileUtils.h" @@ -46,7 +46,7 @@ #include -#if HAVE_TR1_UNORDERED_SET +#ifdef HAVE_TR1_UNORDERED_SET #include using std::tr1::unordered_set; #else @@ -54,15 +54,17 @@ using std::tr1::unordered_set; using std::unordered_set; #endif -using namespace std; +using std::cerr; +using std::string; +using namespace encfs; namespace encfs { const int FSBlockSize = 256; static -int checkErrorPropogation( const shared_ptr &cipher, - int size, int byteToChange, const CipherKey &key ) +int checkErrorPropogation( const shared_ptr &cipher, + int size, int byteToChange ) { MemBlock orig; orig.allocate(size); @@ -77,9 +79,9 @@ int checkErrorPropogation( const shared_ptr &cipher, } if(size != FSBlockSize) - cipher->streamEncode( data.data, size, 0, key ); + cipher->streamEncode( data.data, size, 0 ); else - cipher->blockEncode( data.data, size, 0, key ); + cipher->blockEncode( data.data, size, 0 ); // intoduce an error in the encoded data, so we can check error propogation if(byteToChange >= 0 && byteToChange < size) @@ -92,9 +94,9 @@ int checkErrorPropogation( const shared_ptr &cipher, } if(size != FSBlockSize) - cipher->streamDecode( data.data, size, 0, key ); + cipher->streamDecode( data.data, size, 0 ); else - cipher->blockDecode( data.data, size, 0, key ); + cipher->blockDecode( data.data, size, 0 ); int numByteErrors = 0; for(int i=0; i &cipher, bool verbose) +bool runTests(const shared_ptr &cipher, bool verbose) { // create a random key if(verbose) @@ -205,16 +207,17 @@ bool runTests(const shared_ptr &cipher, bool verbose) int encodedKeySize = cipher->encodedKeySize(); unsigned char *keyBuf = new unsigned char [ encodedKeySize ]; - cipher->writeKey( key, keyBuf, encodingKey ); - CipherKey key2 = cipher->readKey( keyBuf, encodingKey ); - if(!key2) + cipher->setKey(encodingKey); + cipher->writeKey( key, keyBuf ); + CipherKey key2 = cipher->readKey( keyBuf, true ); + if(!key2.valid()) { if(verbose) cerr << " FAILED (decode error)\n"; return false; } - if(cipher->compareKey( key, key2 )) + if(key == key2) { if(verbose) cerr << " OK\n"; @@ -233,7 +236,8 @@ bool runTests(const shared_ptr &cipher, bool verbose) int encodedKeySize = cipher->encodedKeySize(); unsigned char *keyBuf = new unsigned char [ encodedKeySize ]; - cipher->writeKey( key, keyBuf, encodingKey ); + cipher->setKey(encodingKey); + cipher->writeKey( key, keyBuf ); // store in config struct.. EncfsConfig cfg; @@ -257,16 +261,15 @@ bool runTests(const shared_ptr &cipher, bool verbose) rAssert( cfg.block_size() == cfg2.block_size() ); // try decoding key.. - - CipherKey key2 = cipher->readKey( (unsigned char *)cfg2.key().ciphertext().data(), encodingKey ); - if(!key2) + CipherKey key2 = cipher->readKey( (unsigned char *)cfg2.key().ciphertext().data(), true ); + if(!key2.valid()) { if(verbose) cerr << " FAILED (decode error)\n"; return false; } - if(cipher->compareKey( key, key2 )) + if(key == key2) { if(verbose) cerr << " OK\n"; @@ -285,15 +288,15 @@ bool runTests(const shared_ptr &cipher, bool verbose) fsCfg->config->set_block_size(FSBlockSize); fsCfg->opts.reset(new EncFS_Opts); + cipher->setKey(key); if(verbose) cerr << "Testing name encode/decode (stream coding w/ IV chaining)\n"; - if (cipher->hasStreamMode()) { fsCfg->opts->idleTracking = false; fsCfg->config->set_unique_iv(false); fsCfg->nameCoding.reset( new StreamNameIO( - StreamNameIO::CurrentInterface(), cipher, key ) ); + StreamNameIO::CurrentInterface(), cipher) ); fsCfg->nameCoding->setChainedNameIV( true ); DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); @@ -308,7 +311,7 @@ bool runTests(const shared_ptr &cipher, bool verbose) fsCfg->opts->idleTracking = false; fsCfg->config->set_unique_iv(false); fsCfg->nameCoding.reset( new BlockNameIO( - BlockNameIO::CurrentInterface(), cipher, key ) ); + BlockNameIO::CurrentInterface(), cipher) ); fsCfg->nameCoding->setChainedNameIV( true ); DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); @@ -323,7 +326,7 @@ bool runTests(const shared_ptr &cipher, bool verbose) fsCfg->opts->idleTracking = false; fsCfg->config->set_unique_iv(false); fsCfg->nameCoding.reset( new BlockNameIO( - BlockNameIO::CurrentInterface(), cipher, key, true ) ); + BlockNameIO::CurrentInterface(), cipher) ); fsCfg->nameCoding->setChainedNameIV( true ); DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); @@ -334,12 +337,11 @@ bool runTests(const shared_ptr &cipher, bool verbose) if(!verbose) { - if (cipher->hasStreamMode()) { // test stream mode, this time without IV chaining fsCfg->nameCoding = shared_ptr( new StreamNameIO( - StreamNameIO::CurrentInterface(), cipher, key ) ); + StreamNameIO::CurrentInterface(), cipher) ); fsCfg->nameCoding->setChainedNameIV( false ); DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); @@ -351,7 +353,7 @@ bool runTests(const shared_ptr &cipher, bool verbose) { // test block mode, this time without IV chaining fsCfg->nameCoding = shared_ptr( new BlockNameIO( - BlockNameIO::CurrentInterface(), cipher, key ) ); + BlockNameIO::CurrentInterface(), cipher) ); fsCfg->nameCoding->setChainedNameIV( false ); DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); @@ -365,7 +367,7 @@ bool runTests(const shared_ptr &cipher, bool verbose) cerr << "Testing block encode/decode on full block - "; { int numErrors = checkErrorPropogation( cipher, - FSBlockSize, -1, key ); + FSBlockSize, -1 ); if(numErrors) { if(verbose) @@ -379,10 +381,9 @@ bool runTests(const shared_ptr &cipher, bool verbose) } if(verbose) cerr << "Testing block encode/decode on partial block - "; - if (cipher->hasStreamMode()) { int numErrors = checkErrorPropogation( cipher, - FSBlockSize-1, -1, key ); + FSBlockSize-1, -1 ); if(numErrors) { if(verbose) @@ -397,7 +398,6 @@ bool runTests(const shared_ptr &cipher, bool verbose) if(verbose) cerr << "Checking error propogation in partial block:\n"; - if (cipher->hasStreamMode()) { int minChanges = FSBlockSize-1; int maxChanges = 0; @@ -406,7 +406,7 @@ bool runTests(const shared_ptr &cipher, bool verbose) for(int i=0; i &cipher, bool verbose) for(int i=0; i &cipher, bool verbose) return true; } +} // namespace encfs int main(int argc, char *argv[]) { @@ -488,9 +489,9 @@ int main(int argc, char *argv[]) srand( time(0) ); // get a list of the available algorithms - std::list algorithms = - Cipher::GetAlgorithmList(); - std::list::const_iterator it; + std::list algorithms = + CipherV1::GetAlgorithmList(); + std::list::const_iterator it; cerr << "Supported Crypto interfaces:\n"; for(it = algorithms.begin(); it != algorithms.end(); ++it) { @@ -515,7 +516,7 @@ int main(int argc, char *argv[]) cerr << it->name << ", key length " << keySize << ", block size " << blockSize << ": "; - shared_ptr cipher = Cipher::New( it->name, keySize ); + shared_ptr cipher = CipherV1::New( it->name, keySize ); if(!cipher) { cerr << "FAILED TO CREATE\n"; @@ -536,7 +537,7 @@ int main(int argc, char *argv[]) } // run one test with verbose output too.. - shared_ptr cipher = Cipher::New("AES", 192); + shared_ptr cipher = CipherV1::New("AES", 192); if(!cipher) { cerr << "\nNo AES cipher found, skipping verbose test.\n"; @@ -549,10 +550,6 @@ int main(int argc, char *argv[]) runTests( cipher, true ); } - MemoryPool::destroyAll(); - return 0; } -} // namespace encfs - diff --git a/fs/encfs.cpp b/fs/encfs.cpp index 5068c68..e3e4f18 100644 --- a/fs/encfs.cpp +++ b/fs/encfs.cpp @@ -43,11 +43,14 @@ #ifdef HAVE_TR1_TUPLE #include -using namespace std; -using namespace std::tr1; +using std::tr1::get; +using std::tr1::make_tuple; +using std::tr1::tuple; #else #include -using namespace std; +using std::get; +using std::make_tuple; +using std::tuple; #endif #include "base/config.h" @@ -61,6 +64,10 @@ using namespace std; #include +using std::map; +using std::string; +using std::vector; + namespace encfs { #ifndef MIN diff --git a/fs/test_IO.cpp b/fs/test_IO.cpp index 2e82cb9..9e4bfd6 100644 --- a/fs/test_IO.cpp +++ b/fs/test_IO.cpp @@ -76,6 +76,38 @@ TEST(IOTest, MacIO) { runWithAllCiphers(testMacIO); } +void testBasicCipherIO(FSConfigPtr& cfg) { + shared_ptr base(new MemFileIO(0)); + shared_ptr test(new CipherFileIO(base, cfg)); + + byte buf[1024]; + cfg->cipher->pseudoRandomize(buf, sizeof(buf)); + + IORequest req; + req.data = new byte[sizeof(buf)]; + req.offset = 0; + req.dataLen = sizeof(buf); + + memcpy(req.data, buf, sizeof(buf)); + ASSERT_TRUE(test->write(req)); + + memset(req.data, 0, sizeof(buf)); + ASSERT_EQ(req.dataLen, test->read(req)); + + for (unsigned int i = 0; i < sizeof(buf); ++i) { + bool match = (buf[i] == req.data[i]); + ASSERT_TRUE(match) << "mismatched data at offset " << i; + if (!match) + break; + } + + delete[] req.data; +} + +TEST(IOTest, BasicCipherFileIO) { + runWithAllCiphers(testBasicCipherIO); +} + void testCipherIO(FSConfigPtr& cfg) { shared_ptr base(new MemFileIO(0)); shared_ptr test(new CipherFileIO(base, cfg)); diff --git a/fs/testing.cpp b/fs/testing.cpp index 329e08b..960843b 100644 --- a/fs/testing.cpp +++ b/fs/testing.cpp @@ -36,7 +36,8 @@ #include "fs/MACFileIO.h" #include "fs/MemFileIO.h" -using namespace std; +using std::list; +using std::string; namespace encfs { @@ -92,27 +93,46 @@ void truncate(FileIO* a, FileIO* b, int len) { void writeRandom(FSConfigPtr& cfg, FileIO* a, FileIO* b, int offset, int len) { SCOPED_TRACE(testing::Message() << "Write random " << offset << ", " << len); - if (a->getSize() < offset + len) + if (a->getSize() < offset + len) { a->truncate(offset + len); + } + if (b->getSize() < offset + len) { + b->truncate(offset + len); + } + unsigned char *buf = new unsigned char[len]; ASSERT_TRUE(cfg->cipher->pseudoRandomize(buf, len)); IORequest req; req.data = new unsigned char[len]; req.dataLen = len; - + memcpy(req.data, buf, len); req.offset = offset; ASSERT_TRUE(a->write(req)); + + // Check that write succeeded. + req.offset = offset; + req.dataLen = len; + ASSERT_EQ(len, a->read(req)); + ASSERT_TRUE(memcmp(req.data, buf, len) == 0); memcpy(req.data, buf, len); req.offset = offset; + req.dataLen = len; ASSERT_TRUE(b->write(req)); + // Check that write succeeded. + req.offset = offset; + req.dataLen = len; + ASSERT_EQ(len, b->read(req)); + ASSERT_TRUE(memcmp(req.data, buf, len) == 0); + compare(a, b, offset, len); delete[] buf; + delete[] req.data; } void compare(FileIO* a, FileIO* b, int offset, int len) { @@ -137,7 +157,8 @@ void compare(FileIO* a, FileIO* b, int offset, int len) { ASSERT_EQ(size1, size2); for(int i = 0; i < len; i++) { bool match = (buf1[i] == buf2[i]); - ASSERT_TRUE(match) << "mismatched data at offset " << i << " of " << len; + ASSERT_TRUE(match) << "mismatched data at offset " << i << " of " << len + << ", got " << int(buf1[i]) << " and " << int(buf2[i]); if(!match) { break; } @@ -148,15 +169,13 @@ void compare(FileIO* a, FileIO* b, int offset, int len) { } void comparisonTest(FSConfigPtr& cfg, FileIO* a, FileIO* b) { - const int size = 18*1024; + const int size = 2*1024; writeRandom(cfg, a, b, 0, size); if (testing::Test::HasFatalFailure()) return; - compare(a, b, 0, size); - if (testing::Test::HasFatalFailure()) return; for (int i = 0; i < 10000; i++) { SCOPED_TRACE(testing::Message() << "Test Loop " << i); - int len = 128 + random() % 2048; + int len = 128 + random() % 512; int offset = (len == a->getSize()) ? 0 : random() % (a->getSize() - len); writeRandom(cfg, a, b, offset, len); diff --git a/po/CMakeLists.txt b/po/CMakeLists.txt index feff967..ef928b0 100644 --- a/po/CMakeLists.txt +++ b/po/CMakeLists.txt @@ -4,7 +4,7 @@ file (GLOB CXX_FILES RELATIVE ${PROJECT_SOURCE_DIR} "*/*.cpp") set (GettextTranslate_GMO_BINARY true) -include (GetTextTranslate) +include (GettextTranslate) diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 6bdfde1..700f07f 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -18,7 +18,6 @@ target_link_libraries (encfsctl encfs-cipher encfs-base ${GLOG_LIBRARIES} - ${FUSE_LIBRARIES} ) if (POD2MAN) diff --git a/util/encfsctl.cpp b/util/encfsctl.cpp index 2caa72a..6b4fffb 100644 --- a/util/encfsctl.cpp +++ b/util/encfsctl.cpp @@ -50,9 +50,14 @@ #include #endif -using namespace std; -using namespace gnu; using namespace encfs; +using gnu::autosprintf; +using std::cerr; +using std::cin; +using std::cout; +using std::endl; +using std::string; +using std::vector; static int showInfo( int argc, char **argv ); static int showVersion( int argc, char **argv ); diff --git a/util/makeKey.cpp b/util/makeKey.cpp index d5e4479..fb93585 100644 --- a/util/makeKey.cpp +++ b/util/makeKey.cpp @@ -29,8 +29,6 @@ #include #include -using namespace std; - void genKey( const shared_ptr &cipher ) { CipherKey key = cipher->newRandomKey(); From 95750d4539cc12bcaa2a90a2c2c6ec7ddec174c3 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Wed, 6 Mar 2013 08:02:23 +0000 Subject: [PATCH 19/51] begin adding Botan support. implement pbkdf-hmac-sha256 module for Botan and CommonCrypto. git-svn-id: http://encfs.googlecode.com/svn/trunk@98 db9cf616-1c43-0410-9cb8-a902689de0d6 --- CMakeLists.txt | 21 +++--- CMakeModules/FindBotan.cmake | 46 ++++++++++++ base/config.h.cmake | 1 + cipher/BlockCipher_test.cpp | 2 +- cipher/CMakeLists.txt | 6 ++ cipher/CipherKey.cpp | 6 +- cipher/CipherV1.cpp | 35 +++++---- cipher/CommonCrypto.cpp | 33 ++++++-- cipher/MemoryPool.cpp | 49 ++++++++---- cipher/MemoryPool.h | 34 ++++++++- cipher/PBKDF.h | 3 +- cipher/PBKDF_test.cpp | 46 +++++++++++- cipher/botan.cpp | 141 +++++++++++++++++++++++++++++++++++ cipher/botan.h | 36 +++++++++ cipher/openssl.cpp | 4 +- fs/FileUtils.cpp | 34 ++++----- 16 files changed, 422 insertions(+), 75 deletions(-) create mode 100644 CMakeModules/FindBotan.cmake create mode 100644 cipher/botan.cpp create mode 100644 cipher/botan.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b54f226..ccb331f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,12 +7,16 @@ set (ENCFS_VERSION "${ENCFS_MAJOR}.${ENCFS_MINOR}") option (BUILD_SHARED_LIBS "Build dynamic link libraries" OFF) -option (WITH_OPENSSL "WithOpenSSL" ON) +option (WITH_OPENSSL "WithOpenSSL" OFF) option (WITH_COMMON_CRYPTO "WithCommonCrypto" OFF) +option (WITH_BOTAN "WithBotan" ON) -if (WITH_COMMON_CRYPTO) +if (WITH_BOTAN) + set (WITH_COMMON_CRYPTO OFF) set (WITH_OPENSSL OFF) -endif (WITH_COMMON_CRYPTO) +elseif (WITH_COMMON_CRYPTO) + set (WITH_OPENSSL OFF) +endif (WITH_BOTAN) set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMakeModules/") @@ -61,15 +65,8 @@ check_include_file_cxx (tr1/tuple HAVE_TR1_TUPLE) check_include_file_cxx (valgrind/valgrind.h HAVE_VALGRIND_VALGRIND_H) check_include_file_cxx (valgrind/memcheck.h HAVE_VALGRIND_MEMCHECK_H) -if (WITH_COMMON_CRYPTO) - check_include_file_cxx (Security/SecRandom.h HAVE_SEC_RANDOM_H) -endif (WITH_COMMON_CRYPTO) - -if (WITH_OPENSSL) - # TODO: move this to cipher directory. - find_package (OpenSSL REQUIRED) - include (OpenSSLTests) -endif (WITH_OPENSSL) +# Used with CommonCrypto +check_include_file_cxx (Security/SecRandom.h HAVE_SEC_RANDOM_H) # Check if xattr functions take extra argument. include (CheckCXXSourceCompiles) diff --git a/CMakeModules/FindBotan.cmake b/CMakeModules/FindBotan.cmake new file mode 100644 index 0000000..54a084d --- /dev/null +++ b/CMakeModules/FindBotan.cmake @@ -0,0 +1,46 @@ +# - Try to find the Botan library +# +# Once done this will define +# +# BOTAN_FOUND - System has Botan +# BOTAN_INCLUDE_DIR - The Botan include directory +# BOTAN_LIBRARIES - The libraries needed to use Botan +# BOTAN_DEFINITIONS - Compiler switches required for using Botan + +IF (BOTAN_INCLUDE_DIR AND BOTAN_LIBRARY) + # in cache already + SET(Botan_FIND_QUIETLY TRUE) +ENDIF (BOTAN_INCLUDE_DIR AND BOTAN_LIBRARY) + +IF (NOT WIN32) + # try using pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + # also fills in BOTAN_DEFINITIONS, although that isn't normally useful + FIND_PACKAGE(PkgConfig) + PKG_SEARCH_MODULE(PC_BOTAN botan-1.10 botan-1.9 botan-1.8 botan) + SET(BOTAN_DEFINITIONS ${PC_BOTAN_CFLAGS}) +ENDIF (NOT WIN32) + +FIND_PATH(BOTAN_INCLUDE_DIR botan/botan.h + HINTS + ${PC_BOTAN_INCLUDEDIR} + ${PC_BOTAN_INCLUDE_DIRS} + ) + +FIND_LIBRARY(BOTAN_LIBRARY NAMES ${PC_BOTAN_LIBRARIES} + HINTS + ${PC_BOTAN_LIBDIR} + ${PC_BOTAN_LIBRARY_DIRS} + ) + +MARK_AS_ADVANCED(BOTAN_INCLUDE_DIR BOTAN_LIBRARY) + +# handle the QUIETLY and REQUIRED arguments and set BOTAN_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Botan DEFAULT_MSG BOTAN_LIBRARY BOTAN_INCLUDE_DIR) + +IF(BOTAN_FOUND) + SET(BOTAN_LIBRARIES ${BOTAN_LIBRARY}) + SET(BOTAN_INCLUDE_DIRS ${BOTAN_INCLUDE_DIR}) +ENDIF() diff --git a/base/config.h.cmake b/base/config.h.cmake index fb3b11b..2fb95f3 100644 --- a/base/config.h.cmake +++ b/base/config.h.cmake @@ -15,6 +15,7 @@ #cmakedefine WITH_OPENSSL #cmakedefine WITH_COMMON_CRYPTO +#cmakedefine WITH_BOTAN #cmakedefine HAVE_SEC_RANDOM_H #cmakedefine HAVE_EVP_BF diff --git a/cipher/BlockCipher_test.cpp b/cipher/BlockCipher_test.cpp index feeee7e..372c0a2 100644 --- a/cipher/BlockCipher_test.cpp +++ b/cipher/BlockCipher_test.cpp @@ -153,7 +153,7 @@ TEST(BlockEncryptionTest, BlockCipher) { Registry registry = BlockCipher::GetRegistry(); shared_ptr pbkdf( - PBKDF::GetRegistry().CreateForMatch(NAME_PKCS5_PBKDF2_HMAC_SHA1)); + PBKDF::GetRegistry().CreateForMatch(NAME_PBKDF2_HMAC_SHA1)); list ciphers = registry.GetAll(); for (const string &name : ciphers) { diff --git a/cipher/CMakeLists.txt b/cipher/CMakeLists.txt index be1101e..789d8cc 100644 --- a/cipher/CMakeLists.txt +++ b/cipher/CMakeLists.txt @@ -6,9 +6,15 @@ if (WITH_COMMON_CRYPTO) set (EXTRA_LIBS ${SECURITY_FRAMEWORK}) set (EXTRA_SOURCE CommonCrypto.cpp) elseif (WITH_OPENSSL) + find_package (OpenSSL REQUIRED) + include (OpenSSLTests) include_directories (${OPENSSL_INCLUDE_DIR}) set (EXTRA_LIBS ${OPENSSL_LIBRARIES}) set (EXTRA_SOURCE openssl.cpp) +elseif (WITH_BOTAN) + find_package (Botan REQUIRED) + set (EXTRA_LIBS ${BOTAN_LIBRARIES}) + set (EXTRA_SOURCE botan.cpp) endif (WITH_COMMON_CRYPTO) add_library (encfs-cipher diff --git a/cipher/CipherKey.cpp b/cipher/CipherKey.cpp index aebf4d7..7e45ebb 100644 --- a/cipher/CipherKey.cpp +++ b/cipher/CipherKey.cpp @@ -43,7 +43,7 @@ CipherKey::CipherKey(const byte *data, int length) : _valid(true) { _mem.reset(new SecureMem(length)); - memcpy(_mem->data, data, length); + memcpy(_mem->data(), data, length); } CipherKey::CipherKey(const CipherKey& src) @@ -64,12 +64,12 @@ void CipherKey::operator = (const CipherKey& src) byte *CipherKey::data() const { - return !_mem ? NULL : _mem->data; + return !_mem ? NULL : _mem->data(); } int CipherKey::size() const { - return !_mem ? 0 : _mem->size; + return !_mem ? 0 : _mem->size(); } void CipherKey::reset() diff --git a/cipher/CipherV1.cpp b/cipher/CipherV1.cpp index 8dea654..a45acec 100644 --- a/cipher/CipherV1.cpp +++ b/cipher/CipherV1.cpp @@ -49,6 +49,10 @@ #include "cipher/openssl.h" #endif +#ifdef WITH_BOTAN +#include "cipher/botan.h" +#endif + using std::list; using std::string; using std::vector; @@ -70,6 +74,9 @@ void CipherV1::init(bool threaded) { #ifdef WITH_OPENSSL OpenSSL::init(threaded); #endif +#ifdef WITH_BOTAN + Botan_init(threaded); +#endif } void CipherV1::shutdown(bool threaded) { @@ -103,22 +110,22 @@ bool BytesToKey(const byte *data, int dataLen, { sha1->init(); if( addmd++ ) - sha1->update(mdBuf.data, mdBuf.size); + sha1->update(mdBuf.data(), mdBuf.size()); sha1->update(data, dataLen); - sha1->write(mdBuf.data); + sha1->write(mdBuf.data()); for(unsigned int i=1; i < rounds; ++i) { sha1->init(); - sha1->update(mdBuf.data, mdBuf.size); - sha1->write(mdBuf.data); + sha1->update(mdBuf.data(), mdBuf.size()); + sha1->write(mdBuf.data()); } int offset = 0; - int toCopy = MIN( remaining, (int)mdBuf.size - offset ); + int toCopy = MIN( remaining, mdBuf.size() - offset ); if( toCopy ) { - memcpy( key->data(), mdBuf.data+offset, toCopy ); + memcpy( key->data(), mdBuf.data()+offset, toCopy ); key += toCopy; remaining -= toCopy; offset += toCopy; @@ -144,7 +151,7 @@ int CipherV1::TimedPBKDF2(const char *pass, int passlen, VALGRIND_CHECK_MEM_IS_DEFINED(salt, saltlen); #endif Registry registry = PBKDF::GetRegistry(); - shared_ptr impl(registry.CreateForMatch(NAME_PKCS5_PBKDF2_HMAC_SHA1)); + shared_ptr impl(registry.CreateForMatch(NAME_PBKDF2_HMAC_SHA1)); if (!impl) return -1; @@ -291,7 +298,7 @@ bool CipherV1::initCiphers(const Interface &iface, const Interface &realIface, _keySize = keyRange.closest(keyLength) / 8; _pbkdf.reset(PBKDF::GetRegistry().CreateForMatch( - NAME_PKCS5_PBKDF2_HMAC_SHA1)); + NAME_PBKDF2_HMAC_SHA1)); if (!_pbkdf) { LOG(ERROR) << "PBKDF missing"; return false; @@ -401,7 +408,7 @@ bool CipherV1::setKey(const CipherKey &keyIv) { // Key is actually key plus iv, so extract the different parts. CipherKey key(_keySize); memcpy(key.data(), keyIv.data(), _keySize); - memcpy(_iv->data, keyIv.data() + _keySize, _ivLength); + memcpy(_iv->data(), keyIv.data() + _keySize, _ivLength); if (_blockCipher->setKey(key) && _streamCipher->setKey(key) @@ -518,11 +525,11 @@ void CipherV1::writeKey(const CipherKey &ckey, byte *out) rAssert( _keySet ); SecureMem tmpBuf(ckey.size()); - memcpy(tmpBuf.data, ckey.data(), tmpBuf.size); + memcpy(tmpBuf.data(), ckey.data(), tmpBuf.size()); unsigned int checksum = reduceMac32( - MAC_64(tmpBuf.data, tmpBuf.size, NULL)); - streamEncode(tmpBuf.data, tmpBuf.size, checksum); + MAC_64(tmpBuf.data(), tmpBuf.size(), NULL)); + streamEncode(tmpBuf.data(), tmpBuf.size(), checksum); // first N bytes contain HMAC derived checksum.. for(int i=1; i<=KEY_CHECKSUM_BYTES; ++i) @@ -531,7 +538,7 @@ void CipherV1::writeKey(const CipherKey &ckey, byte *out) checksum >>= 8; } - memcpy( out+KEY_CHECKSUM_BYTES, tmpBuf.data, tmpBuf.size ); + memcpy( out+KEY_CHECKSUM_BYTES, tmpBuf.data(), tmpBuf.size() ); } std::string CipherV1::encodeAsString(const CipherKey &key) @@ -602,7 +609,7 @@ static void setIVec_old(byte *ivec, int ivLen, unsigned int seed) void CipherV1::setIVec(byte *ivec, uint64_t seed) const { rAssert( _keySet ); - memcpy( ivec, _iv->data, _ivLength ); + memcpy( ivec, _iv->data(), _ivLength ); if (iface.major() < 3) { // Backward compatible mode. diff --git a/cipher/CommonCrypto.cpp b/cipher/CommonCrypto.cpp index 1bb24d0..0e405a1 100644 --- a/cipher/CommonCrypto.cpp +++ b/cipher/CommonCrypto.cpp @@ -40,17 +40,19 @@ namespace encfs { namespace commoncrypto { -class PbkdfPkcs5HmacSha1CC : public PBKDF { +class PbkdfPkcs5Hmac : public PBKDF { + CCPseudoRandomAlgorithm prf_; public: - PbkdfPkcs5HmacSha1CC() {} - virtual ~PbkdfPkcs5HmacSha1CC() {} + PbkdfPkcs5Hmac(CCPseudoRandomAlgorithm prf) + : prf_(prf) {} + virtual ~PbkdfPkcs5Hmac() {} virtual bool makeKey(const char *password, int passwordLength, const byte *salt, int saltLength, int numIterations, CipherKey *outKey) { int ret = CCKeyDerivationPBKDF(kCCPBKDF2, password, passwordLength, - salt, saltLength, kCCPRFHmacAlgSHA1, + salt, saltLength, prf_, numIterations, outKey->data(), outKey->size()); if (ret != 0) { @@ -86,16 +88,37 @@ public: #endif return true; } +}; + +class PbkdfPkcs5HmacSha1CC : public PbkdfPkcs5Hmac { +public: + PbkdfPkcs5HmacSha1CC() : PbkdfPkcs5Hmac(kCCPRFHmacAlgSHA1) {} + ~PbkdfPkcs5HmacSha1CC() {} + static Properties GetProperties() { Properties props; - props.mode = NAME_PKCS5_PBKDF2_HMAC_SHA1; + props.mode = NAME_PBKDF2_HMAC_SHA1; props.library = "CommonCrypto"; return props; } }; REGISTER_CLASS(PbkdfPkcs5HmacSha1CC, PBKDF); +class PbkdfPkcs5HmacSha256CC : public PbkdfPkcs5Hmac { +public: + PbkdfPkcs5HmacSha256CC() : PbkdfPkcs5Hmac(kCCPRFHmacAlgSHA256) {} + ~PbkdfPkcs5HmacSha256CC() {} + + static Properties GetProperties() { + Properties props; + props.mode = NAME_PBKDF2_HMAC_SHA256; + props.library = "CommonCrypto"; + return props; + } +}; +REGISTER_CLASS(PbkdfPkcs5HmacSha256CC, PBKDF); + class CCCipher : public BlockCipher { CipherKey key; CCAlgorithm algorithm; diff --git a/cipher/MemoryPool.cpp b/cipher/MemoryPool.cpp index 14e68c6..b69173e 100644 --- a/cipher/MemoryPool.cpp +++ b/cipher/MemoryPool.cpp @@ -47,6 +47,10 @@ # include #endif +#ifdef WITH_BOTAN +# include +#endif + namespace encfs { #ifdef WITH_OPENSSL @@ -61,14 +65,16 @@ static void freeBlock( byte *block, int size ) OPENSSL_cleanse(block, size); OPENSSL_free(block); } -#elif defined(WITH_COMMON_CRYPTO) + +#else + static byte *allocBlock(int size) { byte *block = new byte[size]; return block; } unsigned char cleanse_ctr = 0; -static void freeBlock(byte *data, int len) { +static void cleanBlock(byte *data, int len) { byte *p = data; size_t loop = len, ctr = cleanse_ctr; while(loop--) @@ -81,8 +87,8 @@ static void freeBlock(byte *data, int len) { if(p) ctr += (63 + (size_t)p); cleanse_ctr = (unsigned char)ctr; - delete[] data; } + #endif void MemBlock::allocate(int size) @@ -94,38 +100,49 @@ void MemBlock::allocate(int size) MemBlock::~MemBlock() { - freeBlock(data, size); + cleanBlock(data, size); + delete[] data; } SecureMem::SecureMem(int len) +#ifdef WITH_BOTAN + : data_(len) +#endif { rAssert(len > 0); - data = allocBlock(len); - if (data) +#ifndef WITH_BOTAN + data_ = allocBlock(len); + if (data_) { - size = len; - mlock(data, size); + size_ = len; + mlock(data_, size_); } else { - size = 0; + size_ = 0; } +#endif } SecureMem::~SecureMem() { - if (size) +#ifdef WITH_BOTAN + data_.destroy(); +#else + if (size_) { - freeBlock(data, size); - munlock(data, size); + cleanBlock(data_, size_); + delete[] data_; + munlock(data_, size_); - data = NULL; - size = 0; + data_ = NULL; + size_ = 0; } +#endif } bool operator == (const SecureMem &a, const SecureMem &b) { - return (a.size == b.size) && - (memcmp(a.data, b.data, a.size) == 0); + return (a.size() == b.size()) && + (memcmp(a.data(), b.data(), a.size()) == 0); } } // namespace encfs diff --git a/cipher/MemoryPool.h b/cipher/MemoryPool.h index fcd5d96..ef7cf2e 100644 --- a/cipher/MemoryPool.h +++ b/cipher/MemoryPool.h @@ -21,12 +21,18 @@ #ifndef _MemoryPool_incl_ #define _MemoryPool_incl_ +#include "base/config.h" #include "base/types.h" +#ifdef WITH_BOTAN +#include +#endif + namespace encfs { /* Memory Pool for fixed sized objects. + Use SecureMem if storing sensitive information. Usage: MemBlock mb; @@ -55,13 +61,37 @@ inline MemBlock::MemBlock() class SecureMem { public: - int size; - byte *data; + byte* data() const; + int size() const; explicit SecureMem(int len); ~SecureMem(); + + private: +#ifdef WITH_BOTAN + Botan::SecureVector data_; +#else + byte *data_; + int size_; +#endif }; +#ifdef WITH_BOTAN +inline byte* SecureMem::data() const { + return const_cast(data_.begin()); +} +inline int SecureMem::size() const { + return data_.size(); +} +#else +inline byte* SecureMem::data() const { + return data_; +} +inline int SecureMem::size() const { + return size_; +} +#endif + bool operator == (const SecureMem &a, const SecureMem &b); } // namespace encfs diff --git a/cipher/PBKDF.h b/cipher/PBKDF.h index 0f1435d..d2a00ef 100644 --- a/cipher/PBKDF.h +++ b/cipher/PBKDF.h @@ -10,7 +10,8 @@ namespace encfs { // Well-known algorithms. -static const char NAME_PKCS5_PBKDF2_HMAC_SHA1[] = "PKCS5_PBKDF2_HMAC_SHA1"; +static const char NAME_PBKDF2_HMAC_SHA1[] = "PBKDF2_HMAC_SHA1"; +static const char NAME_PBKDF2_HMAC_SHA256[] = "PBKDF2_HMAC_SHA256"; // Password Based Key Derivation Function. class PBKDF diff --git a/cipher/PBKDF_test.cpp b/cipher/PBKDF_test.cpp index 350de9f..2de091a 100644 --- a/cipher/PBKDF_test.cpp +++ b/cipher/PBKDF_test.cpp @@ -34,7 +34,7 @@ namespace { TEST(PKCS5_PBKDF2_HMAC_SHA1, PBKDF) { Registry registry = PBKDF::GetRegistry(); - shared_ptr impl( registry.CreateForMatch(NAME_PKCS5_PBKDF2_HMAC_SHA1)); + shared_ptr impl( registry.CreateForMatch(NAME_PBKDF2_HMAC_SHA1)); ASSERT_FALSE(!impl); // Test cases from rfc6070 @@ -68,6 +68,50 @@ TEST(PKCS5_PBKDF2_HMAC_SHA1, PBKDF) { } } +TEST(PKCS5_PBKDF2_HMAC_SHA256, PBKDF) { + Registry registry = PBKDF::GetRegistry(); + shared_ptr impl( + registry.CreateForMatch(NAME_PBKDF2_HMAC_SHA256)); + ASSERT_FALSE(!impl); + + // Test case 1 + { + CipherKey key(32); + bool ok = impl->makeKey("password", 8, + (byte*)"salt", 4, + 1, &key); + ASSERT_TRUE(ok); + ASSERT_EQ("120fb6cffcf8b32c" + "43e7225256c4f837" + "a86548c92ccc3548" + "0805987cb70be17b", stringToHex(key)); + } + + // Test case 2 + { + CipherKey key(40); + bool ok = impl->makeKey("passwordPASSWORDpassword", 24, + (byte*)"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, + 4096, &key); + ASSERT_TRUE(ok); + ASSERT_EQ("348c89dbcbd32b2f" + "32d814b8116e84cf" + "2b17347ebc180018" + "1c4e2a1fb8dd53e1" + "c635518c7dac47e9", + stringToHex(key)); + } + + // Test case 3 + { + CipherKey key(16); + bool ok = impl->makeKey("pass\0word", 9, + (byte*)"sa\0lt", 5, + 4096, &key); + ASSERT_TRUE(ok); + ASSERT_EQ("89b69d0516f829893c696226650a8687", stringToHex(key)); + } +} } // namespace diff --git a/cipher/botan.cpp b/cipher/botan.cpp new file mode 100644 index 0000000..0fa1dd3 --- /dev/null +++ b/cipher/botan.cpp @@ -0,0 +1,141 @@ + +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2013 Valient Gough + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "cipher/botan.h" +#include "base/config.h" + +#include +#include + +#include "base/Error.h" +#include "base/Mutex.h" +#include "base/Range.h" + +#include "cipher/BlockCipher.h" +#include "cipher/MAC.h" +#include "cipher/MemoryPool.h" +#include "cipher/PBKDF.h" +#include "cipher/StreamCipher.h" + +#include + +using namespace Botan; + +namespace encfs { +namespace botan { + +class PbkdfPkcs5Hmac : public PBKDF { + Botan::PBKDF* pbkdf_; + + public: + PbkdfPkcs5Hmac(Botan::PBKDF* pbkdf) : pbkdf_(pbkdf) {} + virtual ~PbkdfPkcs5Hmac() { + delete pbkdf_; + } + + virtual bool makeKey(const char *password, int passwordLength, + const byte *salt, int saltLength, + int numIterations, + CipherKey *outKey) { + if (pbkdf_ == NULL) { + // TODO: error message + return false; + } + + std::string pass; + pass.assign(password, passwordLength); + OctetString key = pbkdf_->derive_key(outKey->size(), + pass, + salt, saltLength, + numIterations); + memcpy(outKey->data(), key.begin(), outKey->size()); + return true; + } + + virtual CipherKey randomKey(int length) { + CipherKey key(length); + rng.randomize(key.data(), key.size()); + return key; + } + + virtual bool pseudoRandom(byte *out, int length) { + rng.randomize(out, length); + return true; + } + + AutoSeeded_RNG rng; +}; + +class PbkdfPkcs5HmacSha1 : public PbkdfPkcs5Hmac { + public: + PbkdfPkcs5HmacSha1() + : PbkdfPkcs5Hmac( get_pbkdf("PBKDF2(SHA-1)")) { } + ~PbkdfPkcs5HmacSha1() {} + + static Properties GetProperties() { + Properties props; + props.mode = NAME_PBKDF2_HMAC_SHA1; + props.library = "Botan"; + return props; + } +}; +REGISTER_CLASS(PbkdfPkcs5HmacSha1, PBKDF); + +class PbkdfPkcs5HmacSha256 : public PbkdfPkcs5Hmac { + public: + PbkdfPkcs5HmacSha256() + : PbkdfPkcs5Hmac( get_pbkdf("PBKDF2(SHA-256)")) { } + ~PbkdfPkcs5HmacSha256() {} + + static Properties GetProperties() { + Properties props; + props.mode = NAME_PBKDF2_HMAC_SHA256; + props.library = "Botan"; + return props; + } +}; +REGISTER_CLASS(PbkdfPkcs5HmacSha256, PBKDF); + + + +} // namespace botan + +static Botan::LibraryInitializer* initializer; + +void Botan_init(bool threaded) { + if (threaded) { + initializer = new Botan::LibraryInitializer("thread_safe=true"); + } else { + initializer = new Botan::LibraryInitializer(); + } +} + +void Botan_shutdown() { + delete initializer; + initializer = NULL; +} + +void Botan_registerCiphers() { + // Just a reference to ensure static initializers are linked. +} + +} // namespace encfs + diff --git a/cipher/botan.h b/cipher/botan.h new file mode 100644 index 0000000..b3f5eea --- /dev/null +++ b/cipher/botan.h @@ -0,0 +1,36 @@ + +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * Copyright (c) 2013 Valient Gough + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef _CIPHER_BOTAN_incl_ +#define _CIPHER_BOTAN_incl_ + +#include "base/Registry.h" + +namespace encfs { + +extern void Botan_init(bool threaded); +extern void Botan_shutdown(); +extern void Botan_registerCiphers(); + +} // namespace encfs + +#endif + diff --git a/cipher/openssl.cpp b/cipher/openssl.cpp index 7e44e6e..ba9c6e6 100644 --- a/cipher/openssl.cpp +++ b/cipher/openssl.cpp @@ -33,8 +33,6 @@ #include #endif -#include "base/config.h" - #define NO_DES #include #include @@ -449,7 +447,7 @@ class PbkdfPkcs5HmacSha1 : public PBKDF { static Properties GetProperties() { Properties props; - props.mode = NAME_PKCS5_PBKDF2_HMAC_SHA1; + props.mode = NAME_PBKDF2_HMAC_SHA1; props.library = "OpenSSL"; return props; } diff --git a/fs/FileUtils.cpp b/fs/FileUtils.cpp index 3f61e1f..cfb0ee2 100644 --- a/fs/FileUtils.cpp +++ b/fs/FileUtils.cpp @@ -1350,11 +1350,11 @@ std::string readPassword( int FD ) while(1) { - ssize_t rdSize = recv(FD, buf->data, buf->size, 0); + ssize_t rdSize = recv(FD, buf->data(), buf->size(), 0); if(rdSize > 0) { - result.append( (char*)buf->data, rdSize ); + result.append( (char*)buf->data(), rdSize ); } else break; } @@ -1441,7 +1441,7 @@ SecureMem *passwordFromProgram(const std::string &passProg, SecureMem *result = new SecureMem(password.length()+1); if (result) - strncpy((char *)result->data, password.c_str(), result->size); + strncpy((char *)result->data(), password.c_str(), result->size()); password.assign(password.length(), '\0'); return result; @@ -1451,13 +1451,13 @@ SecureMem *passwordFromStdin() { SecureMem *buf = new SecureMem(MaxPassBuf); - char *res = fgets( (char *)buf->data, buf->size, stdin ); + char *res = fgets( (char *)buf->data(), buf->size(), stdin ); if (res) { // Kill the trailing newline. - int last = strnlen((char *)buf->data, buf->size); - if (last > 0 && buf->data[last-1] == '\n') - buf->data[ last-1 ] = '\0'; + int last = strnlen((char *)buf->data(), buf->size()); + if (last > 0 && buf->data()[last-1] == '\n') + buf->data()[ last-1 ] = '\0'; } return buf; @@ -1469,7 +1469,7 @@ SecureMem *passwordFromPrompt() // xgroup(common) char *res = readpassphrase( _("EncFS Password: "), - (char *)buf->data, buf->size-1, RPP_ECHO_OFF ); + (char *)buf->data(), buf->size()-1, RPP_ECHO_OFF ); if (!res) { delete buf; @@ -1488,13 +1488,13 @@ SecureMem *passwordFromPrompts() { // xgroup(common) char *res1 = readpassphrase(_("New Encfs Password: "), - (char *)buf->data, buf->size-1, RPP_ECHO_OFF); + (char *)buf->data(), buf->size()-1, RPP_ECHO_OFF); // xgroup(common) char *res2 = readpassphrase(_("Verify Encfs Password: "), - (char *)buf2->data, buf2->size-1, RPP_ECHO_OFF); + (char *)buf2->data(), buf2->size()-1, RPP_ECHO_OFF); if(res1 && res2 - && !strncmp((char*)buf->data, (char*)buf2->data, MaxPassBuf)) + && !strncmp((char*)buf->data(), (char*)buf2->data(), MaxPassBuf)) { break; } else @@ -1520,8 +1520,8 @@ CipherKey getUserKey(const EncfsConfig &config, bool useStdin) if (password) { - userKey = decryptKey(config, (char*)password->data, - strlen((char*)password->data)); + userKey = decryptKey(config, (char*)password->data(), + strlen((char*)password->data())); delete password; } @@ -1536,8 +1536,8 @@ CipherKey getUserKey( const EncfsConfig &config, const std::string &passProg, if (password) { - result = decryptKey(config, (char*)password->data, - strlen((char*)password->data)); + result = decryptKey(config, (char*)password->data(), + strlen((char*)password->data())); delete password; } @@ -1560,8 +1560,8 @@ CipherKey getNewUserKey(EncfsConfig &config, if (password) { - result = makeNewKey(config, (char*)password->data, - strlen((char*)password->data)); + result = makeNewKey(config, (char*)password->data(), + strlen((char*)password->data())); delete password; } From bd182db260f70527f2720e03a8157f9d06a63cb6 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Mon, 17 Jun 2013 03:11:46 +0000 Subject: [PATCH 20/51] Implement more Botan support. git-svn-id: http://encfs.googlecode.com/svn/trunk@99 db9cf616-1c43-0410-9cb8-a902689de0d6 --- CMakeLists.txt | 1 + base/XmlReader.cpp | 4 - cipher/BlockCipher_test.cpp | 33 ++++-- cipher/CMakeLists.txt | 1 + cipher/CipherKey_test.cpp | 10 +- cipher/CipherV1.cpp | 5 + cipher/MemoryPool.cpp | 37 +++++-- cipher/MemoryPool.h | 15 +-- cipher/botan.cpp | 197 ++++++++++++++++++++++++++++++++++++ 9 files changed, 268 insertions(+), 35 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ccb331f..9df06ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,6 +91,7 @@ find_program (POD2MAN pod2man) find_package (GTest) if (GTEST_FOUND) + include_directories(${GTEST_INCLUDE_DIR}) enable_testing() endif (GTEST_FOUND) diff --git a/base/XmlReader.cpp b/base/XmlReader.cpp index 75088e7..9c38a52 100644 --- a/base/XmlReader.cpp +++ b/base/XmlReader.cpp @@ -31,10 +31,6 @@ #include -#include -#include -#include - #include #include "base/base64.h" #include "base/Interface.h" diff --git a/cipher/BlockCipher_test.cpp b/cipher/BlockCipher_test.cpp index 372c0a2..6e09d4c 100644 --- a/cipher/BlockCipher_test.cpp +++ b/cipher/BlockCipher_test.cpp @@ -26,6 +26,7 @@ #include "base/config.h" #include "base/shared_ptr.h" #include "cipher/BlockCipher.h" +#include "cipher/CipherV1.h" #include "cipher/MemoryPool.h" #include "cipher/PBKDF.h" #include "cipher/testing.h" @@ -40,6 +41,13 @@ using std::string; namespace { +class BlockCipherTest : public testing::Test { + public: + virtual void SetUp() { + CipherV1::init(false); + } +}; + void compare(const byte *a, const byte *b, int size) { #ifdef HAVE_VALGRIND_MEMCHECK_H ASSERT_EQ(0, VALGRIND_CHECK_MEM_IS_DEFINED(a, size)); @@ -54,7 +62,7 @@ void compare(const byte *a, const byte *b, int size) { } } -TEST(RequiredBlockCiphers, BlockCipher) { +TEST_F(BlockCipherTest, RequiredBlockCiphers) { auto aes_cbc = BlockCipher::GetRegistry().CreateForMatch(NAME_AES_CBC); ASSERT_TRUE(aes_cbc != NULL); @@ -62,7 +70,7 @@ TEST(RequiredBlockCiphers, BlockCipher) { ASSERT_TRUE(bf_cbc != NULL); } -TEST(RequiredStreamCiphers, StreamCipher) { +TEST_F(BlockCipherTest, RequiredStreamCiphers) { auto aes_cfb = StreamCipher::GetRegistry().CreateForMatch(NAME_AES_CFB); ASSERT_TRUE(aes_cfb != NULL); @@ -84,6 +92,7 @@ void checkTestVector(const char *cipherName, CipherKey key(strlen(hexKey)/2); setDataFromHex(key.data(), key.size(), hexKey); + ASSERT_TRUE(cipher->setKey(key)); byte iv[strlen(hexIv)/2]; @@ -93,19 +102,23 @@ void checkTestVector(const char *cipherName, setDataFromHex(plaintext, sizeof(plaintext), hexPlaintext); byte ciphertext[sizeof(plaintext)]; - ASSERT_TRUE(cipher->encrypt(iv, plaintext, ciphertext, sizeof(ciphertext))); - ASSERT_EQ(hexCipher, stringToHex(ciphertext, sizeof(ciphertext))); + // Run test in a loop with the same cipher, since that's how we use it later. + for (int i = 0; i < 2; ++i) { + ASSERT_TRUE(cipher->encrypt(iv, plaintext, ciphertext, sizeof(ciphertext))); - byte decypered[sizeof(plaintext)]; - ASSERT_TRUE(cipher->decrypt(iv, ciphertext, decypered, sizeof(ciphertext))); + ASSERT_EQ(hexCipher, stringToHex(ciphertext, sizeof(ciphertext))); - for (unsigned int i = 0; i < sizeof(plaintext); ++i) { - ASSERT_EQ(plaintext[i], decypered[i]); + byte decypered[sizeof(plaintext)]; + ASSERT_TRUE(cipher->decrypt(iv, ciphertext, decypered, sizeof(ciphertext))); + + for (unsigned int i = 0; i < sizeof(plaintext); ++i) { + ASSERT_EQ(plaintext[i], decypered[i]); + } } } -TEST(TestVectors, BlockCipher) { +TEST_F(BlockCipherTest, TestVectors) { // BF128 CBC checkTestVector(NAME_BLOWFISH_CBC, "0123456789abcdeff0e1d2c3b4a59687", @@ -149,7 +162,7 @@ TEST(TestVectors, BlockCipher) { "dc7e84bfda79164b7ecd8486985d3860"); } -TEST(BlockEncryptionTest, BlockCipher) { +TEST_F(BlockCipherTest, BlockEncryptionTest) { Registry registry = BlockCipher::GetRegistry(); shared_ptr pbkdf( diff --git a/cipher/CMakeLists.txt b/cipher/CMakeLists.txt index 789d8cc..4d59d64 100644 --- a/cipher/CMakeLists.txt +++ b/cipher/CMakeLists.txt @@ -15,6 +15,7 @@ elseif (WITH_BOTAN) find_package (Botan REQUIRED) set (EXTRA_LIBS ${BOTAN_LIBRARIES}) set (EXTRA_SOURCE botan.cpp) + include_directories (${BOTAN_INCLUDE_DIR}) endif (WITH_COMMON_CRYPTO) add_library (encfs-cipher diff --git a/cipher/CipherKey_test.cpp b/cipher/CipherKey_test.cpp index a5898f2..10ee8c7 100644 --- a/cipher/CipherKey_test.cpp +++ b/cipher/CipherKey_test.cpp @@ -19,9 +19,17 @@ using std::string; namespace { -TEST(CipherKey, ReadWrite) { +class CipherKeyTest : public testing::Test { + protected: + virtual void SetUp() { + CipherV1::init(false); + } +}; + +TEST_F(CipherKeyTest, ReadWrite) { for (auto alg : CipherV1::GetAlgorithmList()) { auto cipher = CipherV1::New(alg.iface); + ASSERT_FALSE(!cipher); CipherKey masterKey = cipher->newRandomKey(); CipherKey volumeKey = cipher->newRandomKey(); diff --git a/cipher/CipherV1.cpp b/cipher/CipherV1.cpp index a45acec..bcf78b5 100644 --- a/cipher/CipherV1.cpp +++ b/cipher/CipherV1.cpp @@ -297,6 +297,8 @@ bool CipherV1::initCiphers(const Interface &iface, const Interface &realIface, else _keySize = keyRange.closest(keyLength) / 8; + LOG_IF(ERROR, _keySize == 0) << "invalid key size"; + _pbkdf.reset(PBKDF::GetRegistry().CreateForMatch( NAME_PBKDF2_HMAC_SHA1)); if (!_pbkdf) { @@ -405,6 +407,9 @@ bool CipherV1::pseudoRandomize( byte *buf, int len ) bool CipherV1::setKey(const CipherKey &keyIv) { Lock l(_hmacMutex); + LOG_IF(ERROR, _keySize != keyIv.size()) << "Mismatched key size: passed " + << keyIv.size() << ", expecting " << _keySize; + // Key is actually key plus iv, so extract the different parts. CipherKey key(_keySize); memcpy(key.data(), keyIv.data(), _keySize); diff --git a/cipher/MemoryPool.cpp b/cipher/MemoryPool.cpp index b69173e..57da524 100644 --- a/cipher/MemoryPool.cpp +++ b/cipher/MemoryPool.cpp @@ -49,6 +49,7 @@ #ifdef WITH_BOTAN # include +# include #endif namespace encfs { @@ -104,13 +105,33 @@ MemBlock::~MemBlock() delete[] data; } -SecureMem::SecureMem(int len) #ifdef WITH_BOTAN - : data_(len) -#endif +SecureMem::SecureMem(int len) + : data_(new Botan::SecureVector(len)) +{ + rAssert(len > 0); +} + +SecureMem::~SecureMem() +{ +# if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + data_->destroy(); +# endif + delete data_; +} + +byte* SecureMem::data() const { + return const_cast(data_->begin()); +} + +int SecureMem::size() const { + return data_->size(); +} + +#else +SecureMem::SecureMem(int len) { rAssert(len > 0); -#ifndef WITH_BOTAN data_ = allocBlock(len); if (data_) { @@ -120,14 +141,10 @@ SecureMem::SecureMem(int len) { size_ = 0; } -#endif } - + SecureMem::~SecureMem() { -#ifdef WITH_BOTAN - data_.destroy(); -#else if (size_) { cleanBlock(data_, size_); @@ -137,8 +154,8 @@ SecureMem::~SecureMem() data_ = NULL; size_ = 0; } -#endif } +#endif bool operator == (const SecureMem &a, const SecureMem &b) { return (a.size() == b.size()) && diff --git a/cipher/MemoryPool.h b/cipher/MemoryPool.h index ef7cf2e..8429545 100644 --- a/cipher/MemoryPool.h +++ b/cipher/MemoryPool.h @@ -25,7 +25,9 @@ #include "base/types.h" #ifdef WITH_BOTAN -#include +namespace Botan { +template class SecureVector; +} #endif namespace encfs { @@ -69,21 +71,14 @@ class SecureMem private: #ifdef WITH_BOTAN - Botan::SecureVector data_; + Botan::SecureVector *data_; #else byte *data_; int size_; #endif }; -#ifdef WITH_BOTAN -inline byte* SecureMem::data() const { - return const_cast(data_.begin()); -} -inline int SecureMem::size() const { - return data_.size(); -} -#else +#ifndef WITH_BOTAN inline byte* SecureMem::data() const { return data_; } diff --git a/cipher/botan.cpp b/cipher/botan.cpp index 0fa1dd3..ffea23d 100644 --- a/cipher/botan.cpp +++ b/cipher/botan.cpp @@ -21,6 +21,7 @@ #include "cipher/botan.h" #include "base/config.h" +#include "base/shared_ptr.h" #include #include @@ -35,9 +36,14 @@ #include "cipher/PBKDF.h" #include "cipher/StreamCipher.h" +#ifdef HAVE_VALGRIND_MEMCHECK_H +#include +#endif + #include using namespace Botan; +using std::string; namespace encfs { namespace botan { @@ -115,6 +121,197 @@ class PbkdfPkcs5HmacSha256 : public PbkdfPkcs5Hmac { REGISTER_CLASS(PbkdfPkcs5HmacSha256, PBKDF); +class BotanBlockCipher : public BlockCipher { + Keyed_Filter *encryption; // Not owned. + Keyed_Filter *decryption; // Not owned. + shared_ptr encryptor; + shared_ptr decryptor; + public: + BotanBlockCipher() {} + virtual ~BotanBlockCipher() {} + + bool rekey(const CipherKey& key, const string& cipherMode) { + SymmetricKey bkey(key.data(), key.size()); + OctetString iv; + encryption = Botan::get_cipher(cipherMode, bkey, iv, Botan::ENCRYPTION); + decryption = Botan::get_cipher(cipherMode, bkey, iv, Botan::DECRYPTION); + if (encryption == nullptr || decryption == nullptr) { + return false; + } + encryptor.reset(new Pipe(encryption)); + decryptor.reset(new Pipe(decryption)); + return true; + } + + virtual bool encrypt(const byte* iv, const byte* in, byte* out, int size) { +#ifdef HAVE_VALGRIND_MEMCHECK_H + if (VALGRIND_CHECK_MEM_IS_ADDRESSABLE(in, size) != 0 || + VALGRIND_CHECK_MEM_IS_ADDRESSABLE(out, size) != 0 || + VALGRIND_CHECK_MEM_IS_ADDRESSABLE(iv, blockSize())) { + return false; + } +#endif + encryption->set_iv(OctetString(iv, blockSize())); + encryptor->process_msg(in, size); + auto written = encryptor->read(out, size, Pipe::LAST_MESSAGE); + LOG_IF(ERROR, (int)written != size) << "expected output size " << size + << ", got " << written; + LOG_IF(ERROR, encryptor->remaining() > 0) << "unread bytes in pipe: " + << encryptor->remaining(); + return true; + } + + virtual bool decrypt(const byte* iv, const byte* in, byte* out, int size) { +#ifdef HAVE_VALGRIND_MEMCHECK_H + if (VALGRIND_CHECK_MEM_IS_ADDRESSABLE(in, size) != 0 || + VALGRIND_CHECK_MEM_IS_ADDRESSABLE(out, size) != 0 || + VALGRIND_CHECK_MEM_IS_ADDRESSABLE(iv, blockSize())) { + return false; + } +#endif + decryption->set_iv(OctetString(iv, blockSize())); + decryptor->process_msg(in, size); + auto written = decryptor->read(out, size, Pipe::LAST_MESSAGE); + LOG_IF(ERROR, (int)written != size) << "expected output size " << size + << ", got " << written; + LOG_IF(ERROR, encryptor->remaining() > 0) << "unread bytes in pipe: " + << encryptor->remaining(); + return true; + } +}; + +class BotanAesCbc : public BotanBlockCipher { + public: + BotanAesCbc() {} + virtual ~BotanAesCbc() {} + + virtual bool setKey(const CipherKey& key) { + std::ostringstream ss; + ss << "AES-" << (key.size() * 8) << "/CBC/NoPadding"; + return rekey(key, ss.str()); + } + + virtual int blockSize() const { + return 128 >> 3; + } + + static Properties GetProperties() { + return Properties(Range(128,256,64), "AES", "CBC", "Botan"); + } +}; +REGISTER_CLASS(BotanAesCbc, BlockCipher); + +class BotanAesCfb : public BotanBlockCipher { + public: + BotanAesCfb() {} + virtual ~BotanAesCfb() {} + + virtual bool setKey(const CipherKey& key) { + std::ostringstream ss; + ss << "AES-" << (key.size() * 8) << "/CFB"; + return rekey(key, ss.str()); + } + + virtual int blockSize() const { + return 128 >> 3; + } + + static Properties GetProperties() { + return Properties(Range(128,256,64), "AES", "CFB", "Botan"); + } +}; +REGISTER_CLASS(BotanAesCfb, StreamCipher); + +class BotanBlowfishCbc : public BotanBlockCipher { + public: + BotanBlowfishCbc() {} + virtual ~BotanBlowfishCbc() {} + + virtual bool setKey(const CipherKey& key) { + std::ostringstream ss; + ss << "Blowfish" << "/CBC/NoPadding"; + return rekey(key, ss.str()); + } + + virtual int blockSize() const { + return 64 >> 3; + } + + static Properties GetProperties() { + return Properties(Range(128,256,32), "Blowfish", "CBC", "Botan"); + } +}; +REGISTER_CLASS(BotanBlowfishCbc, BlockCipher); + +class BotanBlowfishCfb : public BotanBlockCipher { + public: + BotanBlowfishCfb() {} + virtual ~BotanBlowfishCfb() {} + + virtual bool setKey(const CipherKey& key) { + std::ostringstream ss; + ss << "Blowfish" << "/CFB"; + return rekey(key, ss.str()); + } + + virtual int blockSize() const { + return 64 >> 3; + } + + static Properties GetProperties() { + return Properties(Range(128,256,32), "Blowfish", "CFB", "Botan"); + } +}; +REGISTER_CLASS(BotanBlowfishCfb, StreamCipher); + + +class Sha1HMac : public MAC { + MessageAuthenticationCode *mac; + + public: + Sha1HMac() : mac(Botan::get_mac("HMAC(SHA-1)")) {} + virtual ~Sha1HMac() { + delete mac; + } + + virtual int outputSize() const { + return mac->output_length(); + } + + virtual bool setKey(const CipherKey &key) { + SymmetricKey bkey(key.data(), key.size()); + mac->set_key(bkey); + return true; + } + + virtual void init() { + } + + virtual bool update(const byte *in, int length) { + mac->update(in, length); + return true; + } + + virtual bool write(byte *out) { +#ifdef HAVE_VALGRIND_MEMCHECK_H + if (VALGRIND_CHECK_MEM_IS_ADDRESSABLE(out, outputSize()) != 0) { + return false; + } +#endif + mac->final(out); + return true; + } + + static Properties GetProperties() { + Properties props; + props.blockSize = 160 >> 3; + props.hashFunction = "SHA-1"; + props.mode = "HMAC"; + props.library = "Botan"; + return props; + } +}; +REGISTER_CLASS(Sha1HMac, MAC); } // namespace botan From 2d90473d09794d2d427a910df531d63799400a73 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Mon, 17 Jun 2013 03:17:31 +0000 Subject: [PATCH 21/51] fix compiler signed comparison warning git-svn-id: http://encfs.googlecode.com/svn/trunk@100 db9cf616-1c43-0410-9cb8-a902689de0d6 --- cipher/CipherV1.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cipher/CipherV1.cpp b/cipher/CipherV1.cpp index bcf78b5..92b471d 100644 --- a/cipher/CipherV1.cpp +++ b/cipher/CipherV1.cpp @@ -407,7 +407,8 @@ bool CipherV1::pseudoRandomize( byte *buf, int len ) bool CipherV1::setKey(const CipherKey &keyIv) { Lock l(_hmacMutex); - LOG_IF(ERROR, _keySize != keyIv.size()) << "Mismatched key size: passed " + LOG_IF(ERROR, (int)_keySize != keyIv.size()) + << "Mismatched key size: passed " << keyIv.size() << ", expecting " << _keySize; // Key is actually key plus iv, so extract the different parts. From b55fd2b010785b34c6f42f7333d51ed8ab21c772 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Mon, 17 Jun 2013 03:33:45 +0000 Subject: [PATCH 22/51] fix MemoryPool build with openssl git-svn-id: http://encfs.googlecode.com/svn/trunk@101 db9cf616-1c43-0410-9cb8-a902689de0d6 --- cipher/MemoryPool.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cipher/MemoryPool.cpp b/cipher/MemoryPool.cpp index 57da524..0b5e14d 100644 --- a/cipher/MemoryPool.cpp +++ b/cipher/MemoryPool.cpp @@ -75,7 +75,7 @@ static byte *allocBlock(int size) { } unsigned char cleanse_ctr = 0; -static void cleanBlock(byte *data, int len) { +static void freeBlock(byte *data, int len) { byte *p = data; size_t loop = len, ctr = cleanse_ctr; while(loop--) @@ -88,6 +88,7 @@ static void cleanBlock(byte *data, int len) { if(p) ctr += (63 + (size_t)p); cleanse_ctr = (unsigned char)ctr; + delete[] data; } #endif @@ -101,8 +102,7 @@ void MemBlock::allocate(int size) MemBlock::~MemBlock() { - cleanBlock(data, size); - delete[] data; + freeBlock(data, size); } #ifdef WITH_BOTAN @@ -147,8 +147,7 @@ SecureMem::~SecureMem() { if (size_) { - cleanBlock(data_, size_); - delete[] data_; + freeBlock(data_, size_); munlock(data_, size_); data_ = NULL; From 33b8c00a674e5e7665d121d8584fb2cde98c8495 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Mon, 17 Jun 2013 05:48:09 +0000 Subject: [PATCH 23/51] fixes config.h setup for crypto options git-svn-id: http://encfs.googlecode.com/svn/trunk@102 db9cf616-1c43-0410-9cb8-a902689de0d6 --- CMakeLists.txt | 27 ++++++++++++++++++++------- cipher/CMakeLists.txt | 5 ----- cipher/openssl.cpp | 3 +++ 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9df06ed..fc78d68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,16 +11,29 @@ option (WITH_OPENSSL "WithOpenSSL" OFF) option (WITH_COMMON_CRYPTO "WithCommonCrypto" OFF) option (WITH_BOTAN "WithBotan" ON) -if (WITH_BOTAN) - set (WITH_COMMON_CRYPTO OFF) - set (WITH_OPENSSL OFF) -elseif (WITH_COMMON_CRYPTO) - set (WITH_OPENSSL OFF) -endif (WITH_BOTAN) - set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMakeModules/") +# Include Crypto checks here so that they can set values in config.h +if (WITH_COMMON_CRYPTO) + set (WITH_BOTAN OFF) + set (WITH_OPENSSL OFF) + + find_library (SECURITY_FRAMEWORK Security) + mark_as_advanced (SECURITY_FRAMEWORK) +elseif (WITH_BOTAN) + set (WITH_COMMON_CRYPTO OFF) + set (WITH_OPENSSL OFF) + + find_package (Botan REQUIRED) +elseif (WITH_OPENSSL) + set (WITH_BOTAN OFF) + set (WITH_COMMON_CRYPTO OFF) + + find_package (OpenSSL REQUIRED) + include (OpenSSLTests) +endif (WITH_COMMON_CRYPTO) + # Tweak compiler flags. set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall") diff --git a/cipher/CMakeLists.txt b/cipher/CMakeLists.txt index 4d59d64..0805bb1 100644 --- a/cipher/CMakeLists.txt +++ b/cipher/CMakeLists.txt @@ -1,18 +1,13 @@ link_directories (${Encfs_BINARY_DIR}/base) if (WITH_COMMON_CRYPTO) - find_library (SECURITY_FRAMEWORK Security) - mark_as_advanced (SECURITY_FRAMEWORK) set (EXTRA_LIBS ${SECURITY_FRAMEWORK}) set (EXTRA_SOURCE CommonCrypto.cpp) elseif (WITH_OPENSSL) - find_package (OpenSSL REQUIRED) - include (OpenSSLTests) include_directories (${OPENSSL_INCLUDE_DIR}) set (EXTRA_LIBS ${OPENSSL_LIBRARIES}) set (EXTRA_SOURCE openssl.cpp) elseif (WITH_BOTAN) - find_package (Botan REQUIRED) set (EXTRA_LIBS ${BOTAN_LIBRARIES}) set (EXTRA_SOURCE botan.cpp) include_directories (${BOTAN_INCLUDE_DIR}) diff --git a/cipher/openssl.cpp b/cipher/openssl.cpp index ba9c6e6..c70c76a 100644 --- a/cipher/openssl.cpp +++ b/cipher/openssl.cpp @@ -131,6 +131,9 @@ class OpenSSLCipher : public BlockCipher { return false; } +#ifdef HAVE_VALGRIND_MEMCHECK_H + VALGRIND_MAKE_MEM_DEFINED(out, length); +#endif return true; } From 3a34db8ce42070f49400e10fc66a800ff3fd044a Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Mon, 17 Jun 2013 05:57:10 +0000 Subject: [PATCH 24/51] adds openssl implementation of PBKDF2 hmac-sha256 git-svn-id: http://encfs.googlecode.com/svn/trunk@103 db9cf616-1c43-0410-9cb8-a902689de0d6 --- cipher/openssl.cpp | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/cipher/openssl.cpp b/cipher/openssl.cpp index c70c76a..2cbb1ea 100644 --- a/cipher/openssl.cpp +++ b/cipher/openssl.cpp @@ -457,6 +457,42 @@ class PbkdfPkcs5HmacSha1 : public PBKDF { }; REGISTER_CLASS(PbkdfPkcs5HmacSha1, PBKDF); +class PbkdfPkcs5HmacSha256 : public PBKDF { + public: + PbkdfPkcs5HmacSha256() {} + virtual ~PbkdfPkcs5HmacSha256() {} + + virtual bool makeKey(const char *password, int passwordLength, + const byte *salt, int saltLength, + int numIterations, + CipherKey *outKey) { + return PKCS5_PBKDF2_HMAC( + password, passwordLength, + const_cast(salt), saltLength, + numIterations, EVP_sha256(), + outKey->size(), outKey->data()) == 1; + } + + virtual CipherKey randomKey(int length) { + CipherKey key(length); + if (!OpenSSLCipher::randomize(&key)) + key.reset(); + return key; + } + + virtual bool pseudoRandom(byte *out, int length) { + return OpenSSLCipher::pseudoRandomize(out, length); + } + + static Properties GetProperties() { + Properties props; + props.mode = NAME_PBKDF2_HMAC_SHA256; + props.library = "OpenSSL"; + return props; + } +}; +REGISTER_CLASS(PbkdfPkcs5HmacSha256, PBKDF); + unsigned long pthreads_thread_id() { From f4cd48aea180d6aa1abb4c4f058517bc9a40678e Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Tue, 18 Jun 2013 05:28:02 +0000 Subject: [PATCH 25/51] fix bad logging tests git-svn-id: http://encfs.googlecode.com/svn/trunk@104 db9cf616-1c43-0410-9cb8-a902689de0d6 --- cipher/CipherV1.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cipher/CipherV1.cpp b/cipher/CipherV1.cpp index 92b471d..a6070e7 100644 --- a/cipher/CipherV1.cpp +++ b/cipher/CipherV1.cpp @@ -297,8 +297,6 @@ bool CipherV1::initCiphers(const Interface &iface, const Interface &realIface, else _keySize = keyRange.closest(keyLength) / 8; - LOG_IF(ERROR, _keySize == 0) << "invalid key size"; - _pbkdf.reset(PBKDF::GetRegistry().CreateForMatch( NAME_PBKDF2_HMAC_SHA1)); if (!_pbkdf) { @@ -407,7 +405,7 @@ bool CipherV1::pseudoRandomize( byte *buf, int len ) bool CipherV1::setKey(const CipherKey &keyIv) { Lock l(_hmacMutex); - LOG_IF(ERROR, (int)_keySize != keyIv.size()) + LOG_IF(ERROR, (int)_keySize + _ivLength != keyIv.size()) << "Mismatched key size: passed " << keyIv.size() << ", expecting " << _keySize; From fe2cb136a4e36f16fb2f773628ae45e753baa0e1 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Tue, 18 Jun 2013 05:54:58 +0000 Subject: [PATCH 26/51] add KDF duration prompt in expert config mode, fixes #168 git-svn-id: http://encfs.googlecode.com/svn/trunk@105 db9cf616-1c43-0410-9cb8-a902689de0d6 --- fs/FileUtils.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/fs/FileUtils.cpp b/fs/FileUtils.cpp index cfb0ee2..9b5bd8d 100644 --- a/fs/FileUtils.cpp +++ b/fs/FileUtils.cpp @@ -668,6 +668,18 @@ Interface selectNameCoding(const CipherV1::CipherAlgorithm &alg) } } +static int selectKDFDuration() { + cout << autosprintf(_("Select desired KDF duration in milliseconds.\n" + "The default is 500 (half a second): ")); + + char answer[10]; + char *res = fgets( answer, sizeof(answer), stdin ); + int duration = (res == 0 ? 0 : atoi( answer )); + cout << "\n"; + + return duration; +} + static int selectKeySize( const CipherV1::CipherAlgorithm &alg ) { @@ -1028,6 +1040,7 @@ RootPtr createConfig( EncFS_Context *ctx, selectBlockMAC(&blockMACBytes, &blockMACRandBytes); allowHoles = selectZeroBlockPassThrough(); } + desiredKDFDuration = selectKDFDuration(); } shared_ptr cipher = CipherV1::New( alg.iface, keySize ); From e0c5258e8304013bdf3ec8f6a8628365b22f785c Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Tue, 18 Jun 2013 06:01:11 +0000 Subject: [PATCH 27/51] fix incorrect use of it's git-svn-id: http://encfs.googlecode.com/svn/trunk@106 db9cf616-1c43-0410-9cb8-a902689de0d6 --- encfs/encfs.pod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encfs/encfs.pod b/encfs/encfs.pod index 3807d2f..b637633 100644 --- a/encfs/encfs.pod +++ b/encfs/encfs.pod @@ -102,7 +102,7 @@ you want before considering the use of B<--public>. Mount the filesystem on-demand. This currently only makes sense in combination with B<--idle> and B<--extpass> options. When the filesystem becomes idle, instead of exiting, B stops allowing access to the filesystem by -internally dropping it's reference to it. If someone attempts to access the +internally dropping its reference to it. If someone attempts to access the filesystem again, the extpass program is used to prompt the user for the password. If this succeeds, then the filesystem becomes available again. From d128220fe4ef6984730745886b49de41f2ffb304 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Tue, 18 Jun 2013 06:03:16 +0000 Subject: [PATCH 28/51] fix english in prompt git-svn-id: http://encfs.googlecode.com/svn/trunk@107 db9cf616-1c43-0410-9cb8-a902689de0d6 --- fs/FileUtils.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/FileUtils.cpp b/fs/FileUtils.cpp index 9b5bd8d..5336f15 100644 --- a/fs/FileUtils.cpp +++ b/fs/FileUtils.cpp @@ -180,7 +180,8 @@ bool userAllowMkdir(int promptno, const char *path, mode_t mode ) // TODO: can we internationalize the y/n names? Seems strange to prompt in // their own language but then have to respond 'y' or 'n'. // xgroup(setup) - cerr << autosprintf( _("The directory \"%s\" does not exist. Should it be created? (y,n) "), path ); + cerr << autosprintf( _("The directory \"%s\" does not exist. " + "Should it be created? (y,n) "), path ); char answer[10]; char *res; @@ -868,7 +869,7 @@ bool selectChainedIV() return boolDefaultYes( _("Enable filename initialization vector chaining?\n" "This makes filename encoding dependent on the complete path, \n" - "rather then encoding each path element individually.")); + "rather than encoding each path element individually.")); } static From 00248b6a8f9b75b92b8211689ddac78d4ecae33f Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Thu, 20 Jun 2013 05:48:50 +0000 Subject: [PATCH 29/51] fix unsigned comparison warning, tweak comment git-svn-id: http://encfs.googlecode.com/svn/trunk@108 db9cf616-1c43-0410-9cb8-a902689de0d6 --- cipher/CipherV1.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cipher/CipherV1.cpp b/cipher/CipherV1.cpp index a6070e7..5b99afe 100644 --- a/cipher/CipherV1.cpp +++ b/cipher/CipherV1.cpp @@ -405,7 +405,7 @@ bool CipherV1::pseudoRandomize( byte *buf, int len ) bool CipherV1::setKey(const CipherKey &keyIv) { Lock l(_hmacMutex); - LOG_IF(ERROR, (int)_keySize + _ivLength != keyIv.size()) + LOG_IF(ERROR, (int)(_keySize + _ivLength) != keyIv.size()) << "Mismatched key size: passed " << keyIv.size() << ", expecting " << _keySize; @@ -579,10 +579,9 @@ int CipherV1::cipherBlockSize() const } // Deprecated: For backward compatibility only. -// A watermark attack was discovered against this IV construction. If an -// attacker could get a victim to store a carefully crafted file, they could -// later determine if the victim had the file in encrypted storage (without -// decrypting the file). +// A watermark attack was published against this data-independent IV schedule. +// The replacement incorporates the filesystem key, making it unique to each +// filesystem. static void setIVec_old(byte *ivec, int ivLen, unsigned int seed) { unsigned int var1 = 0x060a4011 * seed; From c44b208078bfb5d51b823fb6b67d1aca07d8d994 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sat, 22 Jun 2013 20:08:14 +0000 Subject: [PATCH 30/51] fix botan post-decryption test git-svn-id: http://encfs.googlecode.com/svn/trunk@109 db9cf616-1c43-0410-9cb8-a902689de0d6 --- cipher/botan.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cipher/botan.cpp b/cipher/botan.cpp index ffea23d..9a04b4b 100644 --- a/cipher/botan.cpp +++ b/cipher/botan.cpp @@ -174,8 +174,8 @@ class BotanBlockCipher : public BlockCipher { auto written = decryptor->read(out, size, Pipe::LAST_MESSAGE); LOG_IF(ERROR, (int)written != size) << "expected output size " << size << ", got " << written; - LOG_IF(ERROR, encryptor->remaining() > 0) << "unread bytes in pipe: " - << encryptor->remaining(); + LOG_IF(ERROR, decryptor->remaining() > 0) << "unread bytes in pipe: " + << decryptor->remaining(); return true; } }; From 1e6b715380b323bd937d42243fa8081c94f26966 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sat, 22 Jun 2013 21:00:05 +0000 Subject: [PATCH 31/51] fix cipher initialization git-svn-id: http://encfs.googlecode.com/svn/trunk@110 db9cf616-1c43-0410-9cb8-a902689de0d6 --- cipher/CipherV1.cpp | 4 ++-- fs/FileUtils.cpp | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/cipher/CipherV1.cpp b/cipher/CipherV1.cpp index 5b99afe..cf8478e 100644 --- a/cipher/CipherV1.cpp +++ b/cipher/CipherV1.cpp @@ -358,8 +358,9 @@ CipherKey CipherV1::newKey(const char *password, int passwdLength, { LOG(ERROR) << "openssl error, PBKDF2 failed"; return CipherKey(); - } else + } else { *iterationCount = res; + } } else { // known iteration length @@ -574,7 +575,6 @@ int CipherV1::keySize() const int CipherV1::cipherBlockSize() const { - rAssert( _keySet ); return _blockCipher->blockSize(); } diff --git a/fs/FileUtils.cpp b/fs/FileUtils.cpp index 5336f15..c84de1f 100644 --- a/fs/FileUtils.cpp +++ b/fs/FileUtils.cpp @@ -1170,7 +1170,8 @@ RootPtr createConfig( EncFS_Context *ctx, void showFSInfo( const EncfsConfig &config ) { - shared_ptr cipher = CipherV1::New( config.cipher(), -1 ); + shared_ptr cipher = CipherV1::New( config.cipher(), + config.key().size() ); { cout << autosprintf( // xgroup(diag) @@ -1204,11 +1205,6 @@ void showFSInfo( const EncfsConfig &config ) cout << "\n"; } else { - // Set a null key - the cipher won't work, but it will at least know the - // key size and blocksize. - CipherKey tmpKey(config.key().size()); - cipher->setKey(tmpKey); - // check if we support the filename encoding interface.. shared_ptr nameCoder = NameIO::New( config.naming(), cipher ); if(!nameCoder) From b59d806e4b11cb1f5da9be2c09dc3930cf39c38f Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sat, 22 Jun 2013 21:16:01 +0000 Subject: [PATCH 32/51] replace OpenSSL references with CipherV1::init git-svn-id: http://encfs.googlecode.com/svn/trunk@111 db9cf616-1c43-0410-9cb8-a902689de0d6 --- fs/checkops.cpp | 27 ++++++++------------------- util/encfsctl.cpp | 13 ++++--------- 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/fs/checkops.cpp b/fs/checkops.cpp index 591ca34..48f5b9c 100644 --- a/fs/checkops.cpp +++ b/fs/checkops.cpp @@ -36,14 +36,6 @@ #include -#ifdef HAVE_SSL -#define NO_DES -#include -#ifndef OPENSSL_NO_ENGINE -#include -#endif -#endif - #include #ifdef HAVE_TR1_UNORDERED_SET @@ -210,6 +202,8 @@ bool runTests(const shared_ptr &cipher, bool verbose) cipher->setKey(encodingKey); cipher->writeKey( key, keyBuf ); CipherKey key2 = cipher->readKey( keyBuf, true ); + delete[] keyBuf; + if(!key2.valid()) { if(verbose) @@ -247,6 +241,8 @@ bool runTests(const shared_ptr &cipher, bool verbose) encryptedKey->set_ciphertext( keyBuf, encodedKeySize ); cfg.set_block_size(FSBlockSize); + delete[] keyBuf; + // save config string data; google::protobuf::TextFormat::PrintToString(cfg, &data); @@ -474,17 +470,8 @@ int main(int argc, char *argv[]) google::InitGoogleLogging(argv[0]); google::InstallFailureSignalHandler(); -#ifdef HAVE_SSL - SSL_load_error_strings(); - SSL_library_init(); - -#ifndef OPENSSL_NO_ENGINE - ENGINE_load_builtin_engines(); - ENGINE_register_all_ciphers(); - ENGINE_register_all_digests(); - ENGINE_register_all_RAND(); -#endif -#endif + bool isThreaded = false; + CipherV1::init(isThreaded); srand( time(0) ); @@ -550,6 +537,8 @@ int main(int argc, char *argv[]) runTests( cipher, true ); } + CipherV1::shutdown(isThreaded); + return 0; } diff --git a/util/encfsctl.cpp b/util/encfsctl.cpp index 6b4fffb..2c620fb 100644 --- a/util/encfsctl.cpp +++ b/util/encfsctl.cpp @@ -45,11 +45,6 @@ #include #include -#ifdef HAVE_SSL -#define NO_DES -#include -#endif - using namespace encfs; using gnu::autosprintf; using std::cerr; @@ -864,10 +859,8 @@ int main(int argc, char **argv) textdomain( PACKAGE ); #endif -#ifdef HAVE_SSL - SSL_load_error_strings(); - SSL_library_init(); -#endif + bool isThreaded = false; + CipherV1::init(isThreaded); if(argc < 2) { @@ -907,5 +900,7 @@ int main(int argc, char **argv) } } + CipherV1::shutdown(isThreaded); + return EXIT_FAILURE; } From 0b6fabffded74b7316cd81388fe325014aa80e7d Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Thu, 3 Oct 2013 05:10:01 +0000 Subject: [PATCH 33/51] fix build issues on Ubuntu git-svn-id: http://encfs.googlecode.com/svn/trunk@114 db9cf616-1c43-0410-9cb8-a902689de0d6 --- CMakeLists.txt | 2 +- cipher/botan.cpp | 1 + encfs/CMakeLists.txt | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fc78d68..7ac8c1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 2.8) -project(Encfs) +project(Encfs C CXX) set (ENCFS_MAJOR 2) set (ENCFS_MINOR 0) diff --git a/cipher/botan.cpp b/cipher/botan.cpp index 9a04b4b..177a53d 100644 --- a/cipher/botan.cpp +++ b/cipher/botan.cpp @@ -41,6 +41,7 @@ #endif #include +#include using namespace Botan; using std::string; diff --git a/encfs/CMakeLists.txt b/encfs/CMakeLists.txt index 458e52a..c01e5d9 100644 --- a/encfs/CMakeLists.txt +++ b/encfs/CMakeLists.txt @@ -18,6 +18,7 @@ target_link_libraries (encfs encfs-base ${GLOG_LIBRARIES} ${FUSE_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} ) if (POD2MAN) From e2b912c731d99cb7cd92622d3309a1f6bd54c1b3 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Thu, 3 Oct 2013 05:10:23 +0000 Subject: [PATCH 34/51] add delaymount option which delays initial mount. Patch by Jeff King git-svn-id: http://encfs.googlecode.com/svn/trunk@115 db9cf616-1c43-0410-9cb8-a902689de0d6 --- encfs/encfs.pod | 7 ++++++- encfs/main.cpp | 18 ++++++++++++++++++ fs/FileUtils.cpp | 8 ++++++++ fs/FileUtils.h | 2 ++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/encfs/encfs.pod b/encfs/encfs.pod index b637633..d264b83 100644 --- a/encfs/encfs.pod +++ b/encfs/encfs.pod @@ -10,7 +10,7 @@ B [B<--version>] [B<-s>] [B<-f>] [B<-v>|B<--verbose>] [B<-i MINUTES>|B<--idle=MINUTES>] [B<--extpass=program>] [B<-S>|B<--stdinpass>] [B<--anykey>] [B<--forcedecode>] [B<-d>|B<--fuse-debug>] [B<--public>] [B<--no-default-flags>] -[B<--ondemand>] [B<--reverse>] [B<--standard>] +[B<--ondemand>] [B<--delaymount>] [B<--reverse>] [B<--standard>] [B<-o FUSE_OPTION>] I I [B<--> [I]] @@ -106,6 +106,11 @@ internally dropping its reference to it. If someone attempts to access the filesystem again, the extpass program is used to prompt the user for the password. If this succeeds, then the filesystem becomes available again. +=item B<--delaymount> + +Do not mount the filesystem when encfs starts; instead, delay mounting until +first use. This option only makes sense with B<--ondemand>. + =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 374adcb..bf0d05a 100644 --- a/encfs/main.cpp +++ b/encfs/main.cpp @@ -102,6 +102,7 @@ struct EncFS_Args if(opts->annotate) ss << "(annotate) "; if(opts->reverseEncryption) ss << "(reverseEncryption) "; if(opts->mountOnDemand) ss << "(mountOnDemand) "; + if(opts->delayMount) ss << "(delayMount) "; for(int i=0; i &out) {"anykey", 0, 0, 'k'}, // skip key checks {"no-default-flags", 0, 0, 'N'}, // don't use default fuse flags {"ondemand", 0, 0, 'm'}, // mount on-demand + {"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 @@ -294,6 +296,9 @@ bool processArgs(int argc, char *argv[], const shared_ptr &out) case 'm': out->opts->mountOnDemand = true; break; + case 'M': + out->opts->delayMount = true; + break; case 'N': useDefaultFlags = false; break; @@ -404,6 +409,15 @@ bool processArgs(int argc, char *argv[], const shared_ptr &out) } } + if(out->opts->delayMount && !out->opts->mountOnDemand) + { + cerr << + // xgroup(usage) + _("You must use mount-on-demand with delay-mount") + << endl; + return false; + } + if(out->opts->mountOnDemand && out->opts->passwordProgram.empty()) { cerr << @@ -594,6 +608,10 @@ int main(int argc, char *argv[]) if( rootInfo ) { + // turn off delayMount, as our prior call to initFS has already + // respected any delay, and we want future calls to actually mount. + encfsArgs->opts->delayMount = false; + // set the globally visible root directory node ctx->setRoot( rootInfo->root ); ctx->args = encfsArgs; diff --git a/fs/FileUtils.cpp b/fs/FileUtils.cpp index c84de1f..40c4195 100644 --- a/fs/FileUtils.cpp +++ b/fs/FileUtils.cpp @@ -1609,6 +1609,14 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) return rootInfo; } + if(opts->delayMount) + { + rootInfo = RootPtr( new EncFS_Root ); + rootInfo->cipher = cipher; + rootInfo->root = shared_ptr(); + return rootInfo; + } + // get user key CipherKey userKey; diff --git a/fs/FileUtils.h b/fs/FileUtils.h index 4008c40..a821838 100644 --- a/fs/FileUtils.h +++ b/fs/FileUtils.h @@ -72,6 +72,7 @@ struct EncFS_Opts bool createIfNotFound; // create filesystem if not found bool idleTracking; // turn on idle monitoring of filesystem bool mountOnDemand; // mounting on-demand + bool delayMount; // delay initial mount bool checkKey; // check crypto key decoding bool forceDecode; // force decode on MAC block failures @@ -91,6 +92,7 @@ struct EncFS_Opts createIfNotFound = true; idleTracking = false; mountOnDemand = false; + delayMount = false; checkKey = true; forceDecode = false; useStdin = false; From 6c3f2105bfa2d9816e7b9442ee2a0a758e4a7c86 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Thu, 3 Oct 2013 05:15:25 +0000 Subject: [PATCH 35/51] [issue 175] fix thread linkage git-svn-id: http://encfs.googlecode.com/svn/trunk@116 db9cf616-1c43-0410-9cb8-a902689de0d6 --- encfs/CMakeLists.txt | 1 - fs/CMakeLists.txt | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/encfs/CMakeLists.txt b/encfs/CMakeLists.txt index c01e5d9..458e52a 100644 --- a/encfs/CMakeLists.txt +++ b/encfs/CMakeLists.txt @@ -18,7 +18,6 @@ target_link_libraries (encfs encfs-base ${GLOG_LIBRARIES} ${FUSE_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} ) if (POD2MAN) diff --git a/fs/CMakeLists.txt b/fs/CMakeLists.txt index 27c837a..bb73eb4 100644 --- a/fs/CMakeLists.txt +++ b/fs/CMakeLists.txt @@ -22,6 +22,7 @@ add_library (encfs-fs target_link_libraries (encfs-fs ${PROTOBUF_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT} ) add_executable (checkops From 9c1b8f590f7916a253c2e74116b706f29ddf9ad0 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Thu, 3 Oct 2013 05:24:59 +0000 Subject: [PATCH 36/51] add warning to encfs output, to discourage use of 2.x branch by non-developers git-svn-id: http://encfs.googlecode.com/svn/trunk@117 db9cf616-1c43-0410-9cb8-a902689de0d6 --- encfs/main.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/encfs/main.cpp b/encfs/main.cpp index bf0d05a..8a071ef 100644 --- a/encfs/main.cpp +++ b/encfs/main.cpp @@ -506,6 +506,15 @@ void encfs_destroy( void *_ctx ) int main(int argc, char *argv[]) { + cerr << "\n\n"; + cerr << "====== WARNING ======= WARNING ======== WARNING ========\n"; + cerr << "NOTE: this version of Encfs comes from SVN mainline and is\n" + "an unreleased 2.x BETA. It is known to have issues!\n"; + cerr << " USE AT YOUR OWN RISK!\n"; + cerr << "Stable releases are available from the Encfs website, or look\n" + "for the 1.x branch in SVN for the stable 1.x series."; + cerr << "\n\n"; + // log to stderr by default.. FLAGS_logtostderr = 1; FLAGS_minloglevel = 1; // WARNING and above. From 2b01a089380c48252099760ab18a79d2946a1439 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sat, 19 Oct 2013 07:08:46 +0000 Subject: [PATCH 37/51] check for gflags, enable in encfsctl git-svn-id: http://encfs.googlecode.com/svn/trunk@119 db9cf616-1c43-0410-9cb8-a902689de0d6 --- CMakeLists.txt | 6 +++++ CMakeModules/FindGFlags.cmake | 48 +++++++++++++++++++++++++++++++++ util/encfsctl.cpp | 50 ++++++++++++++++------------------- 3 files changed, 77 insertions(+), 27 deletions(-) create mode 100644 CMakeModules/FindGFlags.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ac8c1d..b218fdd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,6 +97,12 @@ include_directories (${PROTOBUF_INCLUDE_DIR}) find_package (GLog REQUIRED) include_directories (${GLOG_INCLUDE_DIRS}) +find_package (GFlags) +if (GFLAGS_FOUND) + include_directories (${GFLAGS_INCLUDE_DIRS}) + set (GLOG_LIBRARIES ${GLOG_LIBRARIES} ${GFLAGS_LIBRARIES}) +endif (GFLAGS_FOUND) + find_package (Threads) set (CMAKE_THREAD_PREFER_PTHREAD) diff --git a/CMakeModules/FindGFlags.cmake b/CMakeModules/FindGFlags.cmake new file mode 100644 index 0000000..7df5b06 --- /dev/null +++ b/CMakeModules/FindGFlags.cmake @@ -0,0 +1,48 @@ +# - Try to find GFLAGS +# +# The following variables are optionally searched for defaults +# GFLAGS_ROOT_DIR: Base directory where all GFLAGS components are found +# +# The following are set after configuration is done: +# GFLAGS_FOUND +# GFLAGS_INCLUDE_DIRS +# GFLAGS_LIBRARIES +# GFLAGS_LIBRARYRARY_DIRS + +include(FindPackageHandleStandardArgs) + +set(GFLAGS_ROOT_DIR "" CACHE PATH "Folder contains Gflags") + +# We are testing only a couple of files in the include directories +if(WIN32) + find_path(GFLAGS_INCLUDE_DIR gflags/gflags.h + PATHS ${GFLAGS_ROOT_DIR}/src/windows) +else() + find_path(GFLAGS_INCLUDE_DIR gflags/gflags.h + PATHS ${GFLAGS_ROOT_DIR}) +endif() + +if(MSVC) + find_library(GFLAGS_LIBRARY_RELEASE + NAMES libgflags + PATHS ${GFLAGS_ROOT_DIR} + PATH_SUFFIXES Release) + + find_library(GFLAGS_LIBRARY_DEBUG + NAMES libgflags-debug + PATHS ${GFLAGS_ROOT_DIR} + PATH_SUFFIXES Debug) + + set(GFLAGS_LIBRARY optimized ${GFLAGS_LIBRARY_RELEASE} debug ${GFLAGS_LIBRARY_DEBUG}) +else() + find_library(GFLAGS_LIBRARY gflags) +endif() + +find_package_handle_standard_args(GFLAGS DEFAULT_MSG + GFLAGS_INCLUDE_DIR GFLAGS_LIBRARY) + + +if(GFLAGS_FOUND) + set(GFLAGS_INCLUDE_DIRS ${GFLAGS_INCLUDE_DIR}) + set(GFLAGS_LIBRARIES ${GFLAGS_LIBRARY}) +endif() diff --git a/util/encfsctl.cpp b/util/encfsctl.cpp index 2c620fb..7e0d49f 100644 --- a/util/encfsctl.cpp +++ b/util/encfsctl.cpp @@ -106,10 +106,10 @@ struct CommandOpts {"export", 2, 2, cmd_export, "(root dir) path", // xgroup(usage) gettext_noop(" -- decrypts a volume and writes results to path")}, - {"--ciphers", 0, 0, showCiphers, "", + {"ciphers", 0, 0, showCiphers, "", // xgroup(usage) gettext_noop(" -- show available ciphers")}, - {"--version", 0, 0, showVersion, "", + {"version", 0, 0, showVersion, "", // xgroup(usage) gettext_noop(" -- print version number and exit")}, {0,0,0,0,0,0} @@ -850,6 +850,10 @@ int main(int argc, char **argv) FLAGS_logtostderr = 1; FLAGS_minloglevel = 1; +#ifdef DECLARE_VARIABLE + google::ParseCommandLineFlags(&argc, &argv, true); +#endif + google::InitGoogleLogging(argv[0]); google::InstallFailureSignalHandler(); @@ -868,36 +872,28 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - if(argc == 2 && !(*argv[1] == '-' && *(argv[1]+1) == '-')) + // find the specified command + int offset = 0; + while(commands[offset].name != 0) { - // default command when only 1 argument given -- treat the argument as - // a directory.. - return showInfo( argc, argv ); + if(!strcmp( argv[1], commands[offset].name )) + break; + ++offset; + } + + if(commands[offset].name == 0) + { + cerr << autosprintf(_("invalid command: \"%s\""), argv[1]) << "\n"; } else { - // find the specified command - int offset = 0; - while(commands[offset].name != 0) + if((argc-2 < commands[offset].minOptions) || + (argc-2 > commands[offset].maxOptions)) { - if(!strcmp( argv[1], commands[offset].name )) - break; - ++offset; - } - - if(commands[offset].name == 0) - { - cerr << autosprintf(_("invalid command: \"%s\""), argv[1]) << "\n"; + cerr << autosprintf( + _("Incorrect number of arguments for command \"%s\""), + argv[1]) << "\n"; } else - { - if((argc-2 < commands[offset].minOptions) || - (argc-2 > commands[offset].maxOptions)) - { - cerr << autosprintf( - _("Incorrect number of arguments for command \"%s\""), - argv[1]) << "\n"; - } else - return (*commands[offset].func)( argc-1, argv+1 ); - } + return (*commands[offset].func)( argc-1, argv+1 ); } CipherV1::shutdown(isThreaded); From 154ce001a175b36344690aaa69727842e79350b8 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sat, 19 Oct 2013 07:09:15 +0000 Subject: [PATCH 38/51] fix broken b64 decoding when reading encfs 1.x XML files git-svn-id: http://encfs.googlecode.com/svn/trunk@120 db9cf616-1c43-0410-9cb8-a902689de0d6 --- base/XmlReader.cpp | 6 ++-- base/base64.cpp | 87 ++++++++++++++++++++++++++++++++++++---------- base/base64.h | 6 ++-- 3 files changed, 76 insertions(+), 23 deletions(-) diff --git a/base/XmlReader.cpp b/base/XmlReader.cpp index 9c38a52..704aa1e 100644 --- a/base/XmlReader.cpp +++ b/base/XmlReader.cpp @@ -121,8 +121,10 @@ bool XmlValue::readB64(const char *path, byte *data, int length) const << ", got " << decodedSize; return false; } - changeBase2((byte *)s.data(), s.size(), 6, data, length, 8); - B64ToAsciiStandard(data, length); + if (!B64StandardDecode(data, (byte*) s.data(), s.size())) { + LOG(ERROR) << "B64 decode failure on " << s; + return false; + } return true; } diff --git a/base/base64.cpp b/base/base64.cpp index 215b02e..2d22609 100644 --- a/base/base64.cpp +++ b/base/base64.cpp @@ -21,6 +21,7 @@ #include "base/base64.h" #include +#include namespace encfs { @@ -148,25 +149,6 @@ void B64ToAscii(byte *in, int length) } } -void B64ToAsciiStandard(byte *in, int length) -{ - static const char LookupTable[] = "+/0123456789"; - for(int offset=0; offset 11) - { - if(ch > 37) - ch += 'a' - 38; - else - ch += 'A' - 12; - } else - ch = LookupTable[ ch ]; - - in[offset] = ch; - } -} - static const byte Ascii2B64Table[] = " 01 23456789:; "; // 0123456789 123456789 123456789 123456789 123456789 123456789 1234 @@ -229,4 +211,71 @@ void AsciiToB32(byte *out, const byte *in, int length) } } + +#define WHITESPACE 64 +#define EQUALS 65 +#define INVALID 66 + +static const byte d[] = { + 66,66,66,66,66,66,66,66,66,64, + 66,66,66,66,66,66,66,66,66,66, + 66,66,66,66,66,66,66,66,66,66, + 66,66,66,66,66,66,66,66,66,66, + 66,66,66,62,66,66,66,63,52,53, + + 54,55,56,57,58,59,60,61,66,66, // 50-59 + 66,65,66,66,66, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9,10,11,12,13,14, + 15,16,17,18,19,20,21,22,23,24, + 25,66,66,66,66,66,66,26,27,28, + + 29,30,31,32,33,34,35,36,37,38, // 100-109 + 39,40,41,42,43,44,45,46,47,48, + 49,50,51 +}; + +bool B64StandardDecode(byte *out, const byte *in, int inLen) { + const byte *end = in + inLen; + size_t buf = 1; + + while (in < end) { + byte v = *in++; + if (v > 'z') { + LOG(ERROR) << "Invalid character: " << (unsigned int)v; + return false; + } + byte c = d[v]; + + switch (c) { + case WHITESPACE: continue; /* skip whitespace */ + case INVALID: + LOG(ERROR) << "Invalid character: " << (unsigned int)v; + return false; /* invalid input, return error */ + case EQUALS: /* pad character, end of data */ + in = end; + continue; + default: + buf = buf << 6 | c; + + /* If the buffer is full, split it into bytes */ + if (buf & 0x1000000) { + *out++ = buf >> 16; + *out++ = buf >> 8; + *out++ = buf; + buf = 1; + } + } + } + + if (buf & 0x40000) { + *out++ = buf >> 10; + *out++ = buf >> 2; + } + else if (buf & 0x1000) { + *out++ = buf >> 4; + } + + return true; +} + } // namespace encfs diff --git a/base/base64.h b/base/base64.h index 4434041..2cfdc65 100644 --- a/base/base64.h +++ b/base/base64.h @@ -62,8 +62,6 @@ void changeBase2Inline(byte *buf, int srcLength, // inplace translation from values [0,2^6] => base64 ASCII void B64ToAscii(byte *buf, int length); -// Like B64ToAscii, but uses standard characters "+" and "/" in encoding. -void B64ToAsciiStandard(byte *buf, int length); // inplace translation from values [0,2^5] => base32 ASCII void B32ToAscii(byte *buf, int length); @@ -75,6 +73,10 @@ void AsciiToB64(byte *out, const byte *in, int length); void AsciiToB32(byte *buf, int length); void AsciiToB32(byte *out, const byte *in, int length); +// Decode B64 standard into the output array. +// The output size must be at least B64ToB256Bytes(inputLen). +bool B64StandardDecode(byte *out, const byte *in, int inputLen); + } // namespace encfs #endif From a89752dfe7a9a9bae16519ab9710f799d7b8f6c3 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sat, 19 Oct 2013 22:35:26 +0000 Subject: [PATCH 39/51] reformat with clang-format -style=Google git-svn-id: http://encfs.googlecode.com/svn/trunk@121 db9cf616-1c43-0410-9cb8-a902689de0d6 --- base/ConfigReader.cpp | 97 ++- base/ConfigReader.h | 30 +- base/ConfigVar.cpp | 161 ++--- base/ConfigVar.h | 77 ++- base/Error.cpp | 5 +- base/Error.h | 21 +- base/Interface.cpp | 37 +- base/Interface.h | 11 +- base/Mutex.h | 58 +- base/Range.h | 130 ++-- base/Registry.h | 59 +- base/XmlReader.cpp | 142 ++--- base/XmlReader.h | 35 +- base/autosprintf.cpp | 73 +-- base/autosprintf.h | 65 +- base/base64.cpp | 266 ++++---- base/base64.h | 34 +- base/gettext.h | 203 +++--- base/i18n.h | 18 +- base/shared_ptr.h | 15 +- base/types.h | 3 +- cipher/BlockCipher.cpp | 15 +- cipher/BlockCipher.h | 7 +- cipher/BlockCipher_test.cpp | 83 ++- cipher/CipherKey.cpp | 58 +- cipher/CipherKey.h | 12 +- cipher/CipherKey_test.cpp | 7 +- cipher/CipherV1.cpp | 417 +++++-------- cipher/CipherV1.h | 33 +- cipher/CommonCrypto.cpp | 73 +-- cipher/CommonCrypto.h | 4 +- cipher/MAC.cpp | 9 +- cipher/MAC.h | 21 +- cipher/MAC_test.cpp | 13 +- cipher/MemoryPool.cpp | 81 +-- cipher/MemoryPool.h | 39 +- cipher/NullCiphers.cpp | 31 +- cipher/NullCiphers.h | 3 +- cipher/PBKDF.cpp | 9 +- cipher/PBKDF.h | 13 +- cipher/PBKDF_test.cpp | 52 +- cipher/StreamCipher.cpp | 9 +- cipher/StreamCipher.h | 28 +- cipher/botan.cpp | 104 ++-- cipher/botan.h | 3 +- cipher/openssl.cpp | 254 ++++---- cipher/openssl.h | 4 +- cipher/readpassphrase.cpp | 212 +++---- cipher/readpassphrase.h | 19 +- cipher/testing.cpp | 3 +- cipher/testing.h | 5 +- encfs/main.cpp | 677 +++++++++----------- fs/BlockFileIO.cpp | 306 ++++----- fs/BlockFileIO.h | 49 +- fs/BlockNameIO.cpp | 192 +++--- fs/BlockNameIO.h | 24 +- fs/CipherFileIO.cpp | 338 ++++------ fs/CipherFileIO.h | 84 ++- fs/Context.cpp | 110 ++-- fs/Context.h | 15 +- fs/DirNode.cpp | 602 +++++++----------- fs/DirNode.h | 194 +++--- fs/FSConfig.h | 55 +- fs/FileIO.cpp | 22 +- fs/FileIO.h | 79 ++- fs/FileNode.cpp | 182 +++--- fs/FileNode.h | 95 ++- fs/FileUtils.cpp | 1177 +++++++++++++++-------------------- fs/FileUtils.h | 78 ++- fs/MACFileIO.cpp | 193 +++--- fs/MACFileIO.h | 59 +- fs/MemBlockFileIO.cpp | 40 +- fs/MemBlockFileIO.h | 6 +- fs/MemFileIO.cpp | 30 +- fs/MemFileIO.h | 9 +- fs/NameIO.cpp | 281 ++++----- fs/NameIO.h | 110 ++-- fs/NullNameIO.cpp | 58 +- fs/NullNameIO.h | 38 +- fs/RawFileIO.cpp | 233 +++---- fs/RawFileIO.h | 50 +- fs/StreamNameIO.cpp | 135 ++-- fs/StreamNameIO.h | 43 +- fs/checkops.cpp | 395 +++++------- fs/encfs.cpp | 600 ++++++++---------- fs/encfs.h | 68 +- fs/test_BlockIO.cpp | 7 +- fs/test_IO.cpp | 26 +- fs/testing.cpp | 38 +- fs/testing.h | 1 - util/encfsctl.cpp | 757 ++++++++++------------ util/makeKey.cpp | 48 +- 92 files changed, 4420 insertions(+), 6245 deletions(-) diff --git a/base/ConfigReader.cpp b/base/ConfigReader.cpp index a623b67..18378f4 100644 --- a/base/ConfigReader.cpp +++ b/base/ConfigReader.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -36,90 +36,75 @@ using std::string; namespace encfs { -ConfigReader::ConfigReader() -{ -} +ConfigReader::ConfigReader() {} -ConfigReader::~ConfigReader() -{ -} +ConfigReader::~ConfigReader() {} // read the entire file into a ConfigVar instance and then use that to decode // into mapped variables. -bool ConfigReader::load(const char *fileName) -{ +bool ConfigReader::load(const char *fileName) { struct stat stbuf; - memset( &stbuf, 0, sizeof(struct stat)); - if( lstat( fileName, &stbuf ) != 0) - return false; + memset(&stbuf, 0, sizeof(struct stat)); + if (lstat(fileName, &stbuf) != 0) return false; int size = stbuf.st_size; - int fd = open( fileName, O_RDONLY ); - if(fd < 0) - return false; + int fd = open(fileName, O_RDONLY); + if (fd < 0) return false; char *buf = new char[size]; - int res = ::read( fd, buf, size ); - close( fd ); + int res = ::read(fd, buf, size); + close(fd); - if( res != size ) - { - LOG(WARNING) << "Partial read of config file, expecting " - << size << " bytes, got " << res; + if (res != size) { + LOG(WARNING) << "Partial read of config file, expecting " << size + << " bytes, got " << res; delete[] buf; return false; } ConfigVar in; - in.write( (byte *)buf, size ); + in.write((byte *)buf, size); delete[] buf; - return loadFromVar( in ); + return loadFromVar(in); } -bool ConfigReader::loadFromVar(ConfigVar &in) -{ +bool ConfigReader::loadFromVar(ConfigVar &in) { in.resetOffset(); // parse. int numEntries = in.readInt(); - for(int i=0; i> key >> value; - if(key.length() == 0) - { + if (key.length() == 0) { LOG(ERROR) << "Invalid key encoding in buffer"; return false; } - ConfigVar newVar( value ); - vars.insert( make_pair( key, newVar ) ); + ConfigVar newVar(value); + vars.insert(make_pair(key, newVar)); } return true; } -bool ConfigReader::save(const char *fileName) const -{ +bool ConfigReader::save(const char *fileName) const { // write everything to a ConfigVar, then output to disk ConfigVar out = toVar(); - int fd = ::open( fileName, O_RDWR | O_CREAT, 0640 ); - if(fd >= 0) - { - int retVal = ::write( fd, out.buffer(), out.size() ); - close( fd ); - if(retVal != out.size()) - { + int fd = ::open(fileName, O_RDWR | O_CREAT, 0640); + if (fd >= 0) { + int retVal = ::write(fd, out.buffer(), out.size()); + close(fd); + if (retVal != out.size()) { LOG(ERROR) << "Error writing to config file " << fileName; return false; } - } else - { + } else { LOG(ERROR) << "Unable to open or create file " << fileName; return false; } @@ -127,36 +112,32 @@ bool ConfigReader::save(const char *fileName) const return true; } -ConfigVar ConfigReader::toVar() const -{ +ConfigVar ConfigReader::toVar() const { // write everything to a ConfigVar, then output to disk ConfigVar out; - out.writeInt( vars.size() ); + out.writeInt(vars.size()); map::const_iterator it; - for(it = vars.begin(); it != vars.end(); ++it) - { - out.writeInt( it->first.size() ); - out.write( (byte*)it->first.data(), it->first.size() ); - out.writeInt( it->second.size() ); - out.write( (byte*)it->second.buffer(), it->second.size() ); + for (it = vars.begin(); it != vars.end(); ++it) { + out.writeInt(it->first.size()); + out.write((byte *)it->first.data(), it->first.size()); + out.writeInt(it->second.size()); + out.write((byte *)it->second.buffer(), it->second.size()); } return out; } -ConfigVar ConfigReader::operator[] ( const std::string &varName ) const -{ +ConfigVar ConfigReader::operator[](const std::string &varName) const { // read only - map::const_iterator it = vars.find( varName ); - if( it == vars.end() ) + map::const_iterator it = vars.find(varName); + if (it == vars.end()) return ConfigVar(); else return it->second; } -ConfigVar &ConfigReader::operator[] ( const std::string &varName ) -{ - return vars[ varName ]; +ConfigVar &ConfigReader::operator[](const std::string &varName) { + return vars[varName]; } } // namespace encfs diff --git a/base/ConfigReader.h b/base/ConfigReader.h index 95ee22f..c53fe6d 100644 --- a/base/ConfigReader.h +++ b/base/ConfigReader.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ - + #ifndef _ConfigReader_incl_ #define _ConfigReader_incl_ @@ -45,26 +45,24 @@ namespace encfs { ConfigReader cfg; cfg["cipher"] << cipher->interface(); */ -class ConfigReader -{ -public: - ConfigReader(); - ~ConfigReader(); +class ConfigReader { + public: + ConfigReader(); + ~ConfigReader(); - bool load(const char *fileName); - bool save(const char *fileName) const; + bool load(const char *fileName); + bool save(const char *fileName) const; - ConfigVar toVar() const; - bool loadFromVar( ConfigVar &var ); + ConfigVar toVar() const; + bool loadFromVar(ConfigVar &var); - ConfigVar operator[](const std::string &varName) const; - ConfigVar &operator[](const std::string &varName); + ConfigVar operator[](const std::string &varName) const; + ConfigVar &operator[](const std::string &varName); -private: - std::map vars; + private: + std::map vars; }; - } // namespace encfs #endif diff --git a/base/ConfigVar.cpp b/base/ConfigVar.cpp index 94b7b06..71c7eb5 100644 --- a/base/ConfigVar.cpp +++ b/base/ConfigVar.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -27,39 +27,22 @@ namespace encfs { #ifndef MIN -inline int MIN(int a, int b) -{ - return (a < b) ? a : b; -} +inline int MIN(int a, int b) { return (a < b) ? a : b; } #endif +ConfigVar::ConfigVar() : pd(new ConfigVarData) { pd->offset = 0; } -ConfigVar::ConfigVar() - : pd( new ConfigVarData ) -{ - pd->offset = 0; -} - -ConfigVar::ConfigVar(const std::string &buf) - : pd( new ConfigVarData ) -{ +ConfigVar::ConfigVar(const std::string &buf) : pd(new ConfigVarData) { pd->buffer = buf; pd->offset = 0; } -ConfigVar::ConfigVar(const ConfigVar &src) -{ - pd = src.pd; -} +ConfigVar::ConfigVar(const ConfigVar &src) { pd = src.pd; } -ConfigVar::~ConfigVar() -{ - pd.reset(); -} +ConfigVar::~ConfigVar() { pd.reset(); } -ConfigVar & ConfigVar::operator = (const ConfigVar &src) -{ - if(src.pd == pd) +ConfigVar &ConfigVar::operator=(const ConfigVar &src) { + if (src.pd == pd) return *this; else pd = src.pd; @@ -67,31 +50,23 @@ ConfigVar & ConfigVar::operator = (const ConfigVar &src) return *this; } -void ConfigVar::resetOffset() -{ - pd->offset = 0; -} +void ConfigVar::resetOffset() { pd->offset = 0; } -int ConfigVar::read(byte *buffer_, int bytes) const -{ - int toCopy = MIN( bytes, pd->buffer.size() - pd->offset ); +int ConfigVar::read(byte *buffer_, int bytes) const { + int toCopy = MIN(bytes, pd->buffer.size() - pd->offset); - if(toCopy > 0) - memcpy( buffer_, pd->buffer.data() + pd->offset, toCopy ); + if (toCopy > 0) memcpy(buffer_, pd->buffer.data() + pd->offset, toCopy); pd->offset += toCopy; return toCopy; } -int ConfigVar::write(const byte *data, int bytes) -{ - if(pd->buffer.size() == (unsigned int)pd->offset) - { - pd->buffer.append( (const char *)data, bytes ); - } else - { - pd->buffer.insert( pd->offset, (const char *)data, bytes ); +int ConfigVar::write(const byte *data, int bytes) { + if (pd->buffer.size() == (unsigned int)pd->offset) { + pd->buffer.append((const char *)data, bytes); + } else { + pd->buffer.insert(pd->offset, (const char *)data, bytes); } pd->offset += bytes; @@ -99,31 +74,19 @@ int ConfigVar::write(const byte *data, int bytes) return bytes; } -int ConfigVar::size() const -{ - return pd->buffer.size(); -} +int ConfigVar::size() const { return pd->buffer.size(); } -const char *ConfigVar::buffer() const -{ - return pd->buffer.data(); -} +const char *ConfigVar::buffer() const { return pd->buffer.data(); } -int ConfigVar::at() const -{ - return pd->offset; -} +int ConfigVar::at() const { return pd->offset; } -void ConfigVar::writeString(const char *data, int bytes) -{ - writeInt( bytes ); - write( (const byte *)data, bytes ); +void ConfigVar::writeString(const char *data, int bytes) { + writeInt(bytes); + write((const byte *)data, bytes); } - // convert integer to BER encoded integer -void ConfigVar::writeInt(int val) -{ +void ConfigVar::writeInt(int val) { // we can represent 7 bits per char output, so a 32bit number may take up // to 5 bytes. // first byte: 0x0000007f 0111,1111 @@ -133,7 +96,7 @@ void ConfigVar::writeInt(int val) // fifth byte: 0xf0000000 1111,0000 byte digit[5]; - digit[4] = (byte)((val & 0x0000007f)); + digit[4] = (byte)((val & 0x0000007f)); digit[3] = 0x80 | (byte)((val & 0x00003f80) >> 7); digit[2] = 0x80 | (byte)((val & 0x001fc000) >> 14); digit[1] = 0x80 | (byte)((val & 0x0fe00000) >> 21); @@ -142,110 +105,96 @@ void ConfigVar::writeInt(int val) // find the starting point - we only need to output starting at the most // significant non-zero digit.. int start = 0; - while(digit[start] == 0x80) - ++start; + while (digit[start] == 0x80) ++start; - write( digit + start, 5-start ); + write(digit + start, 5 - start); } -int ConfigVar::readInt() const -{ - const byte * buf = (const byte *)buffer(); +int ConfigVar::readInt() const { + const byte *buf = (const byte *)buffer(); int bytes = this->size(); int offset = at(); int value = 0; bool highBitSet; - rAssert( offset < bytes ); + rAssert(offset < bytes); - do - { + do { byte tmp = buf[offset++]; highBitSet = tmp & 0x80; value = (value << 7) | (int)(tmp & 0x7f); - } while(highBitSet && offset < bytes); + } while (highBitSet && offset < bytes); pd->offset = offset; // should never end up with a negative number.. - rAssert( value >= 0 ); + rAssert(value >= 0); return value; } -int ConfigVar::readInt( int defaultValue ) const -{ +int ConfigVar::readInt(int defaultValue) const { int bytes = this->size(); int offset = at(); - if(offset >= bytes) + if (offset >= bytes) return defaultValue; else return readInt(); } -bool ConfigVar::readBool( bool defaultValue ) const -{ - int tmp = readInt( defaultValue ? 1 : 0 ); +bool ConfigVar::readBool(bool defaultValue) const { + int tmp = readInt(defaultValue ? 1 : 0); return (tmp != 0); } -ConfigVar & operator << (ConfigVar &src, bool value) -{ - src.writeInt( value ? 1 : 0 ); +ConfigVar &operator<<(ConfigVar &src, bool value) { + src.writeInt(value ? 1 : 0); return src; } -ConfigVar & operator << (ConfigVar &src, int var) -{ - src.writeInt( var ); +ConfigVar &operator<<(ConfigVar &src, int var) { + src.writeInt(var); return src; } -ConfigVar & operator << (ConfigVar &src, const std::string &str) -{ - src.writeString( str.data(), str.length() ); +ConfigVar &operator<<(ConfigVar &src, const std::string &str) { + src.writeString(str.data(), str.length()); return src; } -const ConfigVar & operator >> (const ConfigVar &src, bool &result) -{ +const ConfigVar &operator>>(const ConfigVar &src, bool &result) { int tmp = src.readInt(); result = (tmp != 0); return src; } -const ConfigVar & operator >> (const ConfigVar &src, int &result) -{ +const ConfigVar &operator>>(const ConfigVar &src, int &result) { result = src.readInt(); return src; } -const ConfigVar & operator >> (const ConfigVar &src, std::string &result) -{ +const ConfigVar &operator>>(const ConfigVar &src, std::string &result) { int length = src.readInt(); LOG_IF(WARNING, length <= 0) << "Invalid config length " << length; int readLen; byte tmpBuf[32]; - if(length > (int)sizeof(tmpBuf)) - { + if (length > (int)sizeof(tmpBuf)) { byte *ptr = new byte[length]; - readLen = src.read( ptr, length ); - result.assign( (char*)ptr, length ); + readLen = src.read(ptr, length); + result.assign((char *)ptr, length); delete[] ptr; - } else - { - readLen = src.read( tmpBuf, length ); - result.assign( (char*)tmpBuf, length ); + } else { + readLen = src.read(tmpBuf, length); + result.assign((char *)tmpBuf, length); } - if(readLen != length) - { - VLOG(1) << "string encoded as size " << length - << " bytes, read " << readLen; + if (readLen != length) { + VLOG(1) << "string encoded as size " << length << " bytes, read " + << readLen; } rAssert(readLen == length); diff --git a/base/ConfigVar.h b/base/ConfigVar.h index 1d431db..0a7757f 100644 --- a/base/ConfigVar.h +++ b/base/ConfigVar.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -27,60 +27,57 @@ namespace encfs { -class ConfigVar -{ - struct ConfigVarData - { - std::string buffer; - int offset; - }; +class ConfigVar { + struct ConfigVarData { + std::string buffer; + int offset; + }; - shared_ptr pd; + shared_ptr pd; -public: - ConfigVar(); - ConfigVar(const std::string &buffer); - ConfigVar(const ConfigVar &src); - ~ConfigVar(); + public: + ConfigVar(); + ConfigVar(const std::string &buffer); + ConfigVar(const ConfigVar &src); + ~ConfigVar(); - ConfigVar & operator = (const ConfigVar &src); + ConfigVar &operator=(const ConfigVar &src); - // reset read/write offset.. - void resetOffset(); + // reset read/write offset.. + void resetOffset(); - // read bytes - int read(byte *buffer, int size) const; + // read bytes + int read(byte *buffer, int size) const; - // write bytes.. - int write(const byte *data, int size); + // write bytes.. + int write(const byte *data, int size); - int readInt() const; - int readInt( int defaultValue ) const; - void writeInt(int value); + int readInt() const; + int readInt(int defaultValue) const; + void writeInt(int value); - bool readBool( bool defaultValue ) const; + bool readBool(bool defaultValue) const; - void writeString(const char *data, int size); + void writeString(const char *data, int size); - // return amount of data in var - int size() const; - // return data pointer - returns front of data pointer, not the current - // position. - const char *buffer() const; + // return amount of data in var + int size() const; + // return data pointer - returns front of data pointer, not the current + // position. + const char *buffer() const; - // return current position in data() buffer. - int at() const; + // return current position in data() buffer. + int at() const; }; -ConfigVar & operator << (ConfigVar &, bool); -ConfigVar & operator << (ConfigVar &, int); -ConfigVar & operator << (ConfigVar &, const std::string &str); +ConfigVar &operator<<(ConfigVar &, bool); +ConfigVar &operator<<(ConfigVar &, int); +ConfigVar &operator<<(ConfigVar &, const std::string &str); -const ConfigVar & operator >> (const ConfigVar &, bool &); -const ConfigVar & operator >> (const ConfigVar &, int &); -const ConfigVar & operator >> (const ConfigVar &, std::string &str); +const ConfigVar &operator>>(const ConfigVar &, bool &); +const ConfigVar &operator>>(const ConfigVar &, int &); +const ConfigVar &operator>>(const ConfigVar &, std::string &str); } // namespace encfs #endif - diff --git a/base/Error.cpp b/base/Error.cpp index e901c8e..898279d 100644 --- a/base/Error.cpp +++ b/base/Error.cpp @@ -2,9 +2,6 @@ namespace encfs { -Error::Error(const char *msg) - : runtime_error(msg) -{ -} +Error::Error(const char *msg) : runtime_error(msg) {} } // namespace encfs diff --git a/base/Error.h b/base/Error.h index ce76f0b..08fd466 100644 --- a/base/Error.h +++ b/base/Error.h @@ -6,24 +6,21 @@ namespace encfs { -class Error : public std::runtime_error -{ -public: +class Error : public std::runtime_error { + public: Error(const char *msg); }; #define STR(X) #X -#define rAssert( cond ) \ - do { \ - if( (cond) == false) \ - { LOG(ERROR) << "Assert failed: " << STR(cond); \ - throw Error(STR(cond)); \ - } \ - } while(0) - +#define rAssert(cond) \ + do { \ + if ((cond) == false) { \ + LOG(ERROR) << "Assert failed: " << STR(cond); \ + throw Error(STR(cond)); \ + } \ + } while (0) } // namespace encfs #endif - diff --git a/base/Interface.cpp b/base/Interface.cpp index d1b9b00..f7229cd 100644 --- a/base/Interface.cpp +++ b/base/Interface.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ - + #include "base/Interface.h" #include "base/ConfigVar.h" @@ -27,26 +27,22 @@ namespace encfs { -std::ostream& operator << (std::ostream& out, const Interface &iface) -{ - out << iface.name() << "(" << iface.major() - << ":" << iface.minor() << ":" << iface.age() << ")"; +std::ostream &operator<<(std::ostream &out, const Interface &iface) { + out << iface.name() << "(" << iface.major() << ":" << iface.minor() << ":" + << iface.age() << ")"; return out; } -bool implements(const Interface &A, const Interface &B) -{ +bool implements(const Interface &A, const Interface &B) { VLOG(1) << "checking if " << A << " implements " << B; - if( A.name() != B.name() ) - return false; + if (A.name() != B.name()) return false; int currentDiff = A.major() - B.major(); - return ( currentDiff >= 0 && currentDiff <= (int)A.age() ); + return (currentDiff >= 0 && currentDiff <= (int)A.age()); } -Interface makeInterface(const char *name, int major, int minor, int age) -{ +Interface makeInterface(const char *name, int major, int minor, int age) { Interface iface; iface.set_name(name); iface.set_major(major); @@ -55,15 +51,13 @@ Interface makeInterface(const char *name, int major, int minor, int age) return iface; } -ConfigVar & operator << (ConfigVar &dst, const Interface &iface) -{ +ConfigVar &operator<<(ConfigVar &dst, const Interface &iface) { dst << iface.name() << (int)iface.major() << (int)iface.minor() << (int)iface.age(); return dst; } -const ConfigVar & operator >> (const ConfigVar &src, Interface &iface) -{ +const ConfigVar &operator>>(const ConfigVar &src, Interface &iface) { src >> *iface.mutable_name(); int major, minor, age; src >> major >> minor >> age; @@ -73,13 +67,10 @@ const ConfigVar & operator >> (const ConfigVar &src, Interface &iface) return src; } -bool operator != (const Interface &a, const Interface &b) -{ - if (a.major() != b.major()) - return true; +bool operator!=(const Interface &a, const Interface &b) { + if (a.major() != b.major()) return true; - if (a.minor() != b.minor()) - return true; + if (a.minor() != b.minor()) return true; return false; } diff --git a/base/Interface.h b/base/Interface.h index 1c144c4..d93b1d7 100644 --- a/base/Interface.h +++ b/base/Interface.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -31,16 +31,15 @@ namespace encfs { // This checks the current() version and age() against B.current() for // compatibility. Even if A.implements(B) is true, B > A may also be // true, meaning B is a newer revision of the interface then A. -bool implements( const Interface &a, const Interface &b ); -Interface makeInterface( const char *name, int major, int minor, int age ); +bool implements(const Interface &a, const Interface &b); +Interface makeInterface(const char *name, int major, int minor, int age); // Read operation class ConfigVar; -const ConfigVar & operator >> (const ConfigVar &, Interface &); +const ConfigVar &operator>>(const ConfigVar &, Interface &); -bool operator != (const Interface &a, const Interface &b); +bool operator!=(const Interface &a, const Interface &b); } // namespace encfs #endif - diff --git a/base/Mutex.h b/base/Mutex.h index 7e8df4e..36c26be 100644 --- a/base/Mutex.h +++ b/base/Mutex.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -29,76 +29,58 @@ #warning No thread support. #endif -namespace encfs -{ +namespace encfs { -class Mutex -{ +class Mutex { public: #ifdef CMAKE_USE_PTHREADS_INIT pthread_mutex_t _mutex; - Mutex() { - pthread_mutex_init( &_mutex, 0 ); - } - ~Mutex() { - pthread_mutex_destroy( &_mutex ); - } + Mutex() { pthread_mutex_init(&_mutex, 0); } + ~Mutex() { pthread_mutex_destroy(&_mutex); } #endif void lock(); void unlock(); }; -class Lock -{ -public: - explicit Lock( Mutex &mutex ); +class Lock { + public: + explicit Lock(Mutex &mutex); ~Lock(); // leave the lock as it is. When the Lock wrapper is destroyed, it // will do nothing with the pthread mutex. void leave(); -private: - Lock(const Lock &src); // not allowed - Lock &operator = (const Lock &src); // not allowed + private: + Lock(const Lock &src); // not allowed + Lock &operator=(const Lock &src); // not allowed Mutex *_mutex; }; -inline void Mutex::lock() -{ +inline void Mutex::lock() { #ifdef CMAKE_USE_PTHREADS_INIT - pthread_mutex_lock( &_mutex ); + pthread_mutex_lock(&_mutex); #endif } -inline void Mutex::unlock() -{ +inline void Mutex::unlock() { #ifdef CMAKE_USE_PTHREADS_INIT - pthread_mutex_unlock( &_mutex ); + pthread_mutex_unlock(&_mutex); #endif } -inline Lock::Lock( Mutex &mutex ) - : _mutex( &mutex ) -{ - if (_mutex) - _mutex->lock(); +inline Lock::Lock(Mutex &mutex) : _mutex(&mutex) { + if (_mutex) _mutex->lock(); } -inline Lock::~Lock( ) -{ - if(_mutex) - _mutex->unlock(); +inline Lock::~Lock() { + if (_mutex) _mutex->unlock(); } -inline void Lock::leave() -{ - _mutex = NULL; -} +inline void Lock::leave() { _mutex = NULL; } } // namespace encfs #endif - diff --git a/base/Range.h b/base/Range.h index 1639d6b..647e4fb 100644 --- a/base/Range.h +++ b/base/Range.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ - + #ifndef _Range_incl_ #define _Range_incl_ @@ -25,26 +25,26 @@ namespace encfs { -class Range -{ - int minVal; - int maxVal; - int increment; -public: - Range(); - Range(int minMax); - Range(int min, int max, int increment); +class Range { + int minVal; + int maxVal; + int increment; - bool allowed(int value) const; + public: + Range(); + Range(int minMax); + Range(int min, int max, int increment); - int closest(int value) const; + bool allowed(int value) const; - int min() const; - int max() const; - int inc() const; + int closest(int value) const; + + int min() const; + int max() const; + int inc() const; }; -inline std::ostream & operator << (std::ostream &st, const Range &r) { +inline std::ostream &operator<<(std::ostream &st, const Range &r) { bool separator = false; for (int size = r.min(); size <= r.max(); size += r.inc()) { if (separator) @@ -56,76 +56,52 @@ inline std::ostream & operator << (std::ostream &st, const Range &r) { return st; } -inline Range::Range(int minMax) -{ - this->minVal = minMax; - this->maxVal = minMax; - this->increment = 1; +inline Range::Range(int minMax) { + this->minVal = minMax; + this->maxVal = minMax; + this->increment = 1; } -inline Range::Range(int min_, int max_, int increment_) -{ - this->minVal = min_; - this->maxVal = max_; - this->increment = increment_; - if(increment == 0) - this->increment = 1; +inline Range::Range(int min_, int max_, int increment_) { + this->minVal = min_; + this->maxVal = max_; + this->increment = increment_; + if (increment == 0) this->increment = 1; } -inline Range::Range() - : minVal(-1) - , maxVal(-1) - , increment(1) -{ -} +inline Range::Range() : minVal(-1), maxVal(-1), increment(1) {} -inline bool Range::allowed(int value) const -{ - if(minVal < 0 && maxVal < 0) - return true; - if(value >= minVal && value <= maxVal) - { - int tmp = value - minVal; - if((tmp % increment) == 0) - return true; - } - return false; -} - -inline int Range::closest(int value) const -{ - if(allowed(value)) - return value; - else - if(value < minVal) - return minVal; - else - if(value > maxVal) - return maxVal; - - // must be inbetween but not matched with increment +inline bool Range::allowed(int value) const { + if (minVal < 0 && maxVal < 0) return true; + if (value >= minVal && value <= maxVal) { int tmp = value - minVal; - // try rounding to the nearest increment.. - tmp += (increment >> 1); - tmp -= (tmp % increment); - - return closest( value + tmp ); + if ((tmp % increment) == 0) return true; + } + return false; } - -inline int Range::min() const -{ + +inline int Range::closest(int value) const { + if (allowed(value)) + return value; + else if (value < minVal) return minVal; -} - -inline int Range::max() const -{ + else if (value > maxVal) return maxVal; + + // must be inbetween but not matched with increment + int tmp = value - minVal; + // try rounding to the nearest increment.. + tmp += (increment >> 1); + tmp -= (tmp % increment); + + return closest(value + tmp); } -inline int Range::inc() const -{ - return increment; -} +inline int Range::min() const { return minVal; } -} // namespace encfs +inline int Range::max() const { return maxVal; } + +inline int Range::inc() const { return increment; } + +} // namespace encfs #endif diff --git a/base/Registry.h b/base/Registry.h index e9182d1..1e81f79 100644 --- a/base/Registry.h +++ b/base/Registry.h @@ -8,34 +8,29 @@ namespace encfs { template -class Registry -{ -public: +class Registry { + public: typedef T *(*FactoryFn)(); struct Data { FactoryFn constructor; typename T::Properties properties; }; - void Register(const char *name, FactoryFn fn, - typename T::Properties properties) - { + void Register(const char *name, FactoryFn fn, + typename T::Properties properties) { Data d; d.constructor = fn; d.properties = properties; data[name] = d; } - T* Create(const char *name) - { + T *Create(const char *name) { auto it = data.find(name); - if (it == data.end()) - return NULL; + if (it == data.end()) return NULL; return (*it->second.constructor)(); } - T* CreateForMatch(const std::string &description) - { + T *CreateForMatch(const std::string &description) { for (auto &it : data) { auto name = it.second.properties.toString(); if (!name.compare(0, description.size(), description)) @@ -54,11 +49,10 @@ public: const typename T::Properties *GetProperties(const char *name) const { auto it = data.find(name); - if (it == data.end()) - return NULL; + if (it == data.end()) return NULL; return &(it->second.properties); } - + const typename T::Properties *GetPropertiesForMatch( const std::string &description) const { for (auto &it : data) { @@ -69,39 +63,32 @@ public: return NULL; } - -private: + private: std::map data; }; template -class Registrar -{ -public: - Registrar(const char *name) - { - BASE::GetRegistry().Register(name, - Registrar::Construct, +class Registrar { + public: + Registrar(const char *name) { + BASE::GetRegistry().Register(name, Registrar::Construct, T::GetProperties()); } - static BASE *Construct() { - return new T(); - } + static BASE *Construct() { return new T(); } }; -#define DECLARE_REGISTERABLE_TYPE(TYPE) \ - static Registry& GetRegistry() +#define DECLARE_REGISTERABLE_TYPE(TYPE) static Registry &GetRegistry() -#define DEFINE_REGISTERABLE_TYPE(TYPE) \ - Registry& TYPE::GetRegistry() { \ - static Registry registry; \ - return registry; \ - } +#define DEFINE_REGISTERABLE_TYPE(TYPE) \ + Registry &TYPE::GetRegistry() { \ + static Registry registry; \ + return registry; \ + } #define REGISTER_CLASS(DERIVED, BASE) \ - static Registrar registrar_ ## DERIVED ## _ ## BASE (#DERIVED) + static Registrar registrar_##DERIVED##_##BASE(#DERIVED) } // namespace encfs -#endif // REGISTRY_H +#endif // REGISTRY_H diff --git a/base/XmlReader.cpp b/base/XmlReader.cpp index 704aa1e..458306b 100644 --- a/base/XmlReader.cpp +++ b/base/XmlReader.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -38,90 +38,70 @@ namespace encfs { -XmlValue::~XmlValue() -{ -} +XmlValue::~XmlValue() {} -XmlValuePtr XmlValue::operator[] (const char *path) const -{ - return find(path); -} +XmlValuePtr XmlValue::operator[](const char *path) const { return find(path); } -XmlValuePtr XmlValue::find(const char *path) const -{ +XmlValuePtr XmlValue::find(const char *path) const { LOG_FIRST_N(ERROR, 1) << "in XmlValue::find( " << path << ")"; return XmlValuePtr(); } -bool XmlValue::read(const char *path, std::string *out) const -{ +bool XmlValue::read(const char *path, std::string *out) const { XmlValuePtr value = find(path); - if (!value) - return false; + if (!value) return false; *out = value->text(); return true; } -bool XmlValue::read(const char *path, int *out) const -{ +bool XmlValue::read(const char *path, int *out) const { XmlValuePtr value = find(path); - if (!value) - return false; + if (!value) return false; *out = atoi(value->text().c_str()); return true; } -bool XmlValue::read(const char *path, long *out) const -{ +bool XmlValue::read(const char *path, long *out) const { XmlValuePtr value = find(path); - if (!value) - return false; + if (!value) return false; *out = atol(value->text().c_str()); return true; } -bool XmlValue::read(const char *path, double *out) const -{ +bool XmlValue::read(const char *path, double *out) const { XmlValuePtr value = find(path); - if (!value) - return false; + if (!value) return false; *out = atof(value->text().c_str()); return true; } -bool XmlValue::read(const char *path, bool *out) const -{ +bool XmlValue::read(const char *path, bool *out) const { XmlValuePtr value = find(path); - if (!value) - return false; + if (!value) return false; *out = atoi(value->text().c_str()); return true; } -bool XmlValue::readB64(const char *path, byte *data, int length) const -{ +bool XmlValue::readB64(const char *path, byte *data, int length) const { XmlValuePtr value = find(path); - if (!value) - return false; - + if (!value) return false; + std::string s = value->text(); s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end()); - s.erase(s.find_last_not_of("=")+1); + s.erase(s.find_last_not_of("=") + 1); int decodedSize = B64ToB256Bytes(s.size()); - if (decodedSize != length) - { - LOG(ERROR) << "decoding bytes len " << s.size() - << ", expecting output len " << length - << ", got " << decodedSize; + if (decodedSize != length) { + LOG(ERROR) << "decoding bytes len " << s.size() << ", expecting output len " + << length << ", got " << decodedSize; return false; } - if (!B64StandardDecode(data, (byte*) s.data(), s.size())) { + if (!B64StandardDecode(data, (byte *)s.data(), s.size())) { LOG(ERROR) << "B64 decode failure on " << s; return false; } @@ -129,67 +109,51 @@ bool XmlValue::readB64(const char *path, byte *data, int length) const return true; } -bool XmlValue::read(const char *path, Interface *out) const -{ +bool XmlValue::read(const char *path, Interface *out) const { XmlValuePtr node = find(path); - if (!node) - return false; + if (!node) return false; int major, minor; - bool ok = node->read("name", out->mutable_name()) - && node->read("major", &major) - && node->read("minor", &minor); + bool ok = node->read("name", out->mutable_name()) && + node->read("major", &major) && node->read("minor", &minor); - if (!ok) - return false; + if (!ok) return false; out->set_major(major); out->set_minor(minor); return true; } -std::string safeValueForNode(const TiXmlElement *element) -{ +std::string safeValueForNode(const TiXmlElement *element) { std::string value; - if (element == NULL) - return value; + if (element == NULL) return value; const TiXmlNode *child = element->FirstChild(); - if (child) - { + if (child) { const TiXmlText *childText = child->ToText(); - if (childText) - value = childText->Value(); + if (childText) value = childText->Value(); } return value; } -class XmlNode : virtual public XmlValue -{ +class XmlNode : virtual public XmlValue { const TiXmlElement *element; -public: + + public: XmlNode(const TiXmlElement *element_) - : XmlValue(safeValueForNode(element_)) - , element(element_) - { - } + : XmlValue(safeValueForNode(element_)), element(element_) {} - virtual ~XmlNode() - { - } + virtual ~XmlNode() {} - virtual XmlValuePtr find(const char *name) const - { - if (name[0] == '@') - { - const char *value = element->Attribute(name+1); + virtual XmlValuePtr find(const char *name) const { + if (name[0] == '@') { + const char *value = element->Attribute(name + 1); if (value) return XmlValuePtr(new XmlValue(value)); - else + else return XmlValuePtr(); - } else - { + } else { const TiXmlElement *el = element->FirstChildElement(name); if (el) return XmlValuePtr(new XmlNode(el)); @@ -199,39 +163,29 @@ public: } }; -struct XmlReader::XmlReaderData -{ +struct XmlReader::XmlReaderData { shared_ptr doc; }; -XmlReader::XmlReader() - : pd(new XmlReaderData()) -{ -} +XmlReader::XmlReader() : pd(new XmlReaderData()) {} -XmlReader::~XmlReader() -{ -} +XmlReader::~XmlReader() {} -bool XmlReader::load(const char *fileName) -{ +bool XmlReader::load(const char *fileName) { pd->doc.reset(new TiXmlDocument(fileName)); return pd->doc->LoadFile(); } -XmlValuePtr XmlReader::operator[] ( const char *name ) const -{ +XmlValuePtr XmlReader::operator[](const char *name) const { TiXmlNode *node = pd->doc->FirstChild(name); - if (node == NULL) - { + if (node == NULL) { LOG(ERROR) << "Xml node " << name << " not found"; return XmlValuePtr(new XmlValue()); } TiXmlElement *element = node->ToElement(); - if (element == NULL) - { + if (element == NULL) { LOG(ERROR) << "Xml node " << name << " not element, type = " << node->Type(); return XmlValuePtr(new XmlValue()); diff --git a/base/XmlReader.h b/base/XmlReader.h index 37b38b2..18d01f6 100644 --- a/base/XmlReader.h +++ b/base/XmlReader.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ - + #ifndef _XmlReader_incl_ #define _XmlReader_incl_ @@ -32,26 +32,18 @@ typedef shared_ptr XmlValuePtr; class Interface; -class XmlValue -{ +class XmlValue { std::string value; -public: - XmlValue() - { - } - XmlValue(const std::string &value) - { - this->value = value; - } + public: + XmlValue() {} + + XmlValue(const std::string &value) { this->value = value; } virtual ~XmlValue(); - XmlValuePtr operator[] (const char *path) const; + XmlValuePtr operator[](const char *path) const; - const std::string &text() const - { - return value; - } + const std::string &text() const { return value; } bool read(const char *path, std::string *out) const; bool readB64(const char *path, byte *out, int length) const; @@ -63,13 +55,12 @@ public: bool read(const char *path, Interface *out) const; -protected: + protected: virtual XmlValuePtr find(const char *name) const; }; -class XmlReader -{ -public: +class XmlReader { + public: XmlReader(); ~XmlReader(); @@ -77,7 +68,7 @@ public: XmlValuePtr operator[](const char *name) const; -private: + private: struct XmlReaderData; shared_ptr pd; }; diff --git a/base/autosprintf.cpp b/base/autosprintf.cpp index 842c80a..5b45e1a 100644 --- a/base/autosprintf.cpp +++ b/base/autosprintf.cpp @@ -21,7 +21,7 @@ This must come before because may include , and once has been included, it's too late. */ #ifndef _GNU_SOURCE -# define _GNU_SOURCE 1 +#define _GNU_SOURCE 1 #endif /* Specification. */ @@ -33,46 +33,35 @@ //#include "lib-asprintf.h" #include -namespace gnu -{ +namespace gnu { - /* Constructor: takes a format string and the printf arguments. */ - autosprintf::autosprintf (const char *format, ...) - { - va_list args; - va_start (args, format); - if (vasprintf (&str, format, args) < 0) - str = NULL; - va_end (args); - } - - /* Copy constructor. Necessary because the destructor is nontrivial. */ - autosprintf::autosprintf (const autosprintf& src) - { - str = (src.str != NULL ? strdup (src.str) : NULL); - } - - /* Destructor: frees the temporarily allocated string. */ - autosprintf::~autosprintf () - { - free (str); - } - - /* Conversion to string. */ - autosprintf::operator char * () const - { - if (str != NULL) - { - size_t length = strlen (str) + 1; - char *copy = new char[length]; - memcpy (copy, str, length); - return copy; - } - else - return NULL; - } - autosprintf::operator std::string () const - { - return std::string (str ? str : "(error in autosprintf)"); - } +/* Constructor: takes a format string and the printf arguments. */ +autosprintf::autosprintf(const char *format, ...) { + va_list args; + va_start(args, format); + if (vasprintf(&str, format, args) < 0) str = NULL; + va_end(args); +} + +/* Copy constructor. Necessary because the destructor is nontrivial. */ +autosprintf::autosprintf(const autosprintf &src) { + str = (src.str != NULL ? strdup(src.str) : NULL); +} + +/* Destructor: frees the temporarily allocated string. */ +autosprintf::~autosprintf() { free(str); } + +/* Conversion to string. */ +autosprintf::operator char *() const { + if (str != NULL) { + size_t length = strlen(str) + 1; + char *copy = new char[length]; + memcpy(copy, str, length); + return copy; + } else + return NULL; +} +autosprintf::operator std::string() const { + return std::string(str ? str : "(error in autosprintf)"); +} } diff --git a/base/autosprintf.h b/base/autosprintf.h index ac21ff2..339e60b 100644 --- a/base/autosprintf.h +++ b/base/autosprintf.h @@ -21,46 +21,45 @@ #ifndef __attribute__ /* This feature is available in gcc versions 2.5 and later. */ -# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__ -# define __attribute__(Spec) /* empty */ -# endif +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__ +#define __attribute__(Spec) /* empty */ +#endif /* The __-protected variants of `format' and `printf' attributes are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ -# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) -# define __format__ format -# define __printf__ printf -# endif +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) +#define __format__ format +#define __printf__ printf +#endif #endif #include #include -namespace gnu -{ - /* A temporary object, usually allocated on the stack, representing - the result of an asprintf() call. */ - class autosprintf - { - public: - /* Constructor: takes a format string and the printf arguments. */ - autosprintf (const char *format, ...) - __attribute__ ((__format__ (__printf__, 2, 3))); - /* Copy constructor. */ - autosprintf (const autosprintf& src); - /* Destructor: frees the temporarily allocated string. */ - ~autosprintf (); - /* Conversion to string. */ - operator char * () const; - operator std::string () const; - /* Output to an ostream. */ - friend inline std::ostream& operator<< (std::ostream& stream, const autosprintf& tmp) - { - stream << (tmp.str ? tmp.str : "(error in autosprintf)"); - return stream; - } - private: - char *str; - }; +namespace gnu { +/* A temporary object, usually allocated on the stack, representing + the result of an asprintf() call. */ +class autosprintf { + public: + /* Constructor: takes a format string and the printf arguments. */ + autosprintf(const char* format, ...) + __attribute__((__format__(__printf__, 2, 3))); + /* Copy constructor. */ + autosprintf(const autosprintf& src); + /* Destructor: frees the temporarily allocated string. */ + ~autosprintf(); + /* Conversion to string. */ + operator char*() const; + operator std::string() const; + /* Output to an ostream. */ + friend inline std::ostream& operator<<(std::ostream& stream, + const autosprintf& tmp) { + stream << (tmp.str ? tmp.str : "(error in autosprintf)"); + return stream; + } + + private: + char* str; +}; } #endif /* _AUTOSPRINTF_H */ diff --git a/base/base64.cpp b/base/base64.cpp index 2d22609..071a989 100644 --- a/base/base64.cpp +++ b/base/base64.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -29,33 +29,29 @@ namespace encfs { // arrays. // It is the caller's responsibility to make sure the output array is large // enough. -void changeBase2(byte *src, int srcLen, int src2Pow, - byte *dst, int dstLen, int dst2Pow) -{ - unsigned long work = 0; - int workBits = 0; // number of bits left in the work buffer - byte *end = src + srcLen; - byte *origDst = dst; - const int mask = (1 << dst2Pow) -1; +void changeBase2(byte *src, int srcLen, int src2Pow, byte *dst, int dstLen, + int dst2Pow) { + unsigned long work = 0; + int workBits = 0; // number of bits left in the work buffer + byte *end = src + srcLen; + byte *origDst = dst; + const int mask = (1 << dst2Pow) - 1; - // copy the new bits onto the high bits of the stream. - // The bits that fall off the low end are the output bits. - while(src != end) - { - work |= ((unsigned long)(*src++)) << workBits; - workBits += src2Pow; + // copy the new bits onto the high bits of the stream. + // The bits that fall off the low end are the output bits. + while (src != end) { + work |= ((unsigned long)(*src++)) << workBits; + workBits += src2Pow; - while(workBits >= dst2Pow) - { - *dst++ = work & mask; - work >>= dst2Pow; - workBits -= dst2Pow; - } + while (workBits >= dst2Pow) { + *dst++ = work & mask; + work >>= dst2Pow; + workBits -= dst2Pow; } + } - // now, we could have a partial value left in the work buffer.. - if(workBits && ((dst - origDst) < dstLen)) - *dst++ = work & mask; + // now, we could have a partial value left in the work buffer.. + if (workBits && ((dst - origDst) < dstLen)) *dst++ = work & mask; } /* @@ -65,65 +61,51 @@ void changeBase2(byte *src, int srcLen, int src2Pow, Uses the stack to store output values. Recurse every time a new value is to be written, then write the value at the tail end of the recursion. */ -static -void changeBase2Inline(byte *src, int srcLen, - int src2Pow, int dst2Pow, - bool outputPartialLastByte, - unsigned long work, - int workBits, - byte *outLoc) -{ - const int mask = (1 << dst2Pow) -1; - if(!outLoc) - outLoc = src; +static void changeBase2Inline(byte *src, int srcLen, int src2Pow, int dst2Pow, + bool outputPartialLastByte, unsigned long work, + int workBits, byte *outLoc) { + const int mask = (1 << dst2Pow) - 1; + if (!outLoc) outLoc = src; - // copy the new bits onto the high bits of the stream. - // The bits that fall off the low end are the output bits. - while(srcLen && workBits < dst2Pow) - { - work |= ((unsigned long)(*src++)) << workBits; - workBits += src2Pow; - --srcLen; - } - - // we have at least one value that can be output - byte outVal = work & mask; - work >>= dst2Pow; - workBits -= dst2Pow; - - if(srcLen) - { - // more input left, so recurse - changeBase2Inline( src, srcLen, src2Pow, dst2Pow, - outputPartialLastByte, work, workBits, outLoc+1); - *outLoc = outVal; - } else - { - // no input left, we can write remaining values directly - *outLoc++ = outVal; - - // we could have a partial value left in the work buffer.. - if(outputPartialLastByte) - { - while(workBits > 0) - { - *outLoc++ = work & mask; - work >>= dst2Pow; - workBits -= dst2Pow; - } - } + // copy the new bits onto the high bits of the stream. + // The bits that fall off the low end are the output bits. + while (srcLen && workBits < dst2Pow) { + work |= ((unsigned long)(*src++)) << workBits; + workBits += src2Pow; + --srcLen; + } + + // we have at least one value that can be output + byte outVal = work & mask; + work >>= dst2Pow; + workBits -= dst2Pow; + + if (srcLen) { + // more input left, so recurse + changeBase2Inline(src, srcLen, src2Pow, dst2Pow, outputPartialLastByte, + work, workBits, outLoc + 1); + *outLoc = outVal; + } else { + // no input left, we can write remaining values directly + *outLoc++ = outVal; + + // we could have a partial value left in the work buffer.. + if (outputPartialLastByte) { + while (workBits > 0) { + *outLoc++ = work & mask; + work >>= dst2Pow; + workBits -= dst2Pow; + } } + } } -void changeBase2Inline(byte *src, int srcLen, - int src2Pow, int dst2Pow, - bool outputPartialLastByte) -{ - changeBase2Inline(src, srcLen, src2Pow, dst2Pow, - outputPartialLastByte, 0, 0, 0); +void changeBase2Inline(byte *src, int srcLen, int src2Pow, int dst2Pow, + bool outputPartialLastByte) { + changeBase2Inline(src, srcLen, src2Pow, dst2Pow, outputPartialLastByte, 0, 0, + 0); } - // character set for ascii b64: // ",-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" // a standard base64 (eg a64l doesn't use ',-' but uses './'. We don't @@ -131,56 +113,44 @@ void changeBase2Inline(byte *src, int srcLen, // '.' included in the encrypted names, so that it can be reserved for files // with special meaning. static const char B642AsciiTable[] = ",-0123456789"; -void B64ToAscii(byte *in, int length) -{ - for(int offset=0; offset 11) - { - if(ch > 37) + if (ch > 11) { + if (ch > 37) ch += 'a' - 38; else ch += 'A' - 12; } else - ch = B642AsciiTable[ ch ]; + ch = B642AsciiTable[ch]; in[offset] = ch; } } -static const byte Ascii2B64Table[] = - " 01 23456789:; "; - // 0123456789 123456789 123456789 123456789 123456789 123456789 1234 - // 0 1 2 3 4 5 6 -void AsciiToB64(byte *in, int length) -{ - return AsciiToB64(in, in, length); -} +static const byte Ascii2B64Table[] = + " 01 23456789:; "; +// 0123456789 123456789 123456789 123456789 123456789 123456789 1234 +// 0 1 2 3 4 5 6 +void AsciiToB64(byte *in, int length) { return AsciiToB64(in, in, length); } -void AsciiToB64(byte *out, const byte *in, int length) -{ - while(length--) - { +void AsciiToB64(byte *out, const byte *in, int length) { + while (length--) { byte ch = *in++; - if(ch >= 'A') - { - if(ch >= 'a') + if (ch >= 'A') { + if (ch >= 'a') ch += 38 - 'a'; else ch += 12 - 'A'; } else - ch = Ascii2B64Table[ ch ] - '0'; + ch = Ascii2B64Table[ch] - '0'; *out++ = ch; } } - -void B32ToAscii(byte *buf, int len) -{ - for(int offset=0; offset= 0 && ch < 26) ch += 'A'; @@ -191,15 +161,10 @@ void B32ToAscii(byte *buf, int len) } } -void AsciiToB32(byte *in, int length) -{ - return AsciiToB32(in, in, length); -} +void AsciiToB32(byte *in, int length) { return AsciiToB32(in, in, length); } -void AsciiToB32(byte *out, const byte *in, int length) -{ - while(length--) - { +void AsciiToB32(byte *out, const byte *in, int length) { + while (length--) { byte ch = *in++; int lch = toupper(ch); if (lch >= 'A') @@ -211,33 +176,24 @@ void AsciiToB32(byte *out, const byte *in, int length) } } - #define WHITESPACE 64 -#define EQUALS 65 -#define INVALID 66 - +#define EQUALS 65 +#define INVALID 66 + static const byte d[] = { - 66,66,66,66,66,66,66,66,66,64, - 66,66,66,66,66,66,66,66,66,66, - 66,66,66,66,66,66,66,66,66,66, - 66,66,66,66,66,66,66,66,66,66, - 66,66,66,62,66,66,66,63,52,53, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 64, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 62, 66, 66, 66, 63, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 66, 66, // 50-59 + 66, 65, 66, 66, 66, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 66, 66, 66, + 66, 66, 66, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // 100-109 + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51}; - 54,55,56,57,58,59,60,61,66,66, // 50-59 - 66,65,66,66,66, 0, 1, 2, 3, 4, - 5, 6, 7, 8, 9,10,11,12,13,14, - 15,16,17,18,19,20,21,22,23,24, - 25,66,66,66,66,66,66,26,27,28, - - 29,30,31,32,33,34,35,36,37,38, // 100-109 - 39,40,41,42,43,44,45,46,47,48, - 49,50,51 -}; - -bool B64StandardDecode(byte *out, const byte *in, int inLen) { +bool B64StandardDecode(byte *out, const byte *in, int inLen) { const byte *end = in + inLen; size_t buf = 1; - + while (in < end) { byte v = *in++; if (v > 'z') { @@ -247,31 +203,31 @@ bool B64StandardDecode(byte *out, const byte *in, int inLen) { byte c = d[v]; switch (c) { - case WHITESPACE: continue; /* skip whitespace */ - case INVALID: - LOG(ERROR) << "Invalid character: " << (unsigned int)v; - return false; /* invalid input, return error */ - case EQUALS: /* pad character, end of data */ - in = end; - continue; - default: - buf = buf << 6 | c; - - /* If the buffer is full, split it into bytes */ - if (buf & 0x1000000) { - *out++ = buf >> 16; - *out++ = buf >> 8; - *out++ = buf; - buf = 1; - } + case WHITESPACE: + continue; /* skip whitespace */ + case INVALID: + LOG(ERROR) << "Invalid character: " << (unsigned int)v; + return false; /* invalid input, return error */ + case EQUALS: /* pad character, end of data */ + in = end; + continue; + default: + buf = buf << 6 | c; + + /* If the buffer is full, split it into bytes */ + if (buf & 0x1000000) { + *out++ = buf >> 16; + *out++ = buf >> 8; + *out++ = buf; + buf = 1; + } } } if (buf & 0x40000) { *out++ = buf >> 10; *out++ = buf >> 2; - } - else if (buf & 0x1000) { + } else if (buf & 0x1000) { *out++ = buf >> 4; } diff --git a/base/base64.h b/base/base64.h index 2cfdc65..5977c29 100644 --- a/base/base64.h +++ b/base/base64.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -25,40 +25,33 @@ namespace encfs { -inline int B64ToB256Bytes( int numB64Bytes ) -{ - return (numB64Bytes * 6) / 8; // round down +inline int B64ToB256Bytes(int numB64Bytes) { + return (numB64Bytes * 6) / 8; // round down } -inline int B32ToB256Bytes( int numB32Bytes ) -{ - return (numB32Bytes * 5) / 8; // round down +inline int B32ToB256Bytes(int numB32Bytes) { + return (numB32Bytes * 5) / 8; // round down } -inline int B256ToB64Bytes( int numB256Bytes ) -{ - return (numB256Bytes * 8 + 5) / 6; // round up +inline int B256ToB64Bytes(int numB256Bytes) { + return (numB256Bytes * 8 + 5) / 6; // round up } -inline int B256ToB32Bytes( int numB256Bytes ) -{ - return (numB256Bytes * 8 + 4) / 5; // round up +inline int B256ToB32Bytes(int numB256Bytes) { + return (numB256Bytes * 8 + 4) / 5; // round up } - /* convert data between different bases - each being a power of 2. */ -void changeBase2(byte *src, int srcLength, int srcPow2, - byte *dst, int dstLength, int dstPow2); +void changeBase2(byte *src, int srcLength, int srcPow2, byte *dst, + int dstLength, int dstPow2); /* same as changeBase2, but writes output over the top of input data. */ -void changeBase2Inline(byte *buf, int srcLength, - int srcPow2, int dst2Pow, - bool outputPartialLastByte); - +void changeBase2Inline(byte *buf, int srcLength, int srcPow2, int dst2Pow, + bool outputPartialLastByte); // inplace translation from values [0,2^6] => base64 ASCII void B64ToAscii(byte *buf, int length); @@ -80,4 +73,3 @@ bool B64StandardDecode(byte *out, const byte *in, int inputLen); } // namespace encfs #endif - diff --git a/base/gettext.h b/base/gettext.h index 209921e..6d77d32 100644 --- a/base/gettext.h +++ b/base/gettext.h @@ -23,19 +23,18 @@ #if ENABLE_NLS /* Get declarations of GNU message catalog functions. */ -# include +#include /* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by the gettext() and ngettext() macros. This is an alternative to calling textdomain(), and is useful for libraries. */ -# ifdef DEFAULT_TEXT_DOMAIN -# undef gettext -# define gettext(Msgid) \ - dgettext (DEFAULT_TEXT_DOMAIN, Msgid) -# undef ngettext -# define ngettext(Msgid1, Msgid2, N) \ - dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N) -# endif +#ifdef DEFAULT_TEXT_DOMAIN +#undef gettext +#define gettext(Msgid) dgettext(DEFAULT_TEXT_DOMAIN, Msgid) +#undef ngettext +#define ngettext(Msgid1, Msgid2, N) \ + dngettext(DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N) +#endif #else @@ -46,17 +45,17 @@ and also including would fail on SunOS 4, whereas is OK. */ #if defined(__sun) -# include +#include #endif /* Many header files from the libstdc++ coming with g++ 3.3 or newer include , which chokes if dcgettext is defined as a macro. So include it now, to make later inclusions of a NOP. */ #if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) -# include -# if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H -# include -# endif +#include +#if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H +#include +#endif #endif /* Disabled NLS. @@ -64,23 +63,22 @@ for invalid uses of the value returned from these functions. On pre-ANSI systems without 'const', the config.h file is supposed to contain "#define const". */ -# define gettext(Msgid) ((const char *) (Msgid)) -# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid)) -# define dcgettext(Domainname, Msgid, Category) \ - ((void) (Category), dgettext (Domainname, Msgid)) -# define ngettext(Msgid1, Msgid2, N) \ - ((N) == 1 \ - ? ((void) (Msgid2), (const char *) (Msgid1)) \ - : ((void) (Msgid1), (const char *) (Msgid2))) -# define dngettext(Domainname, Msgid1, Msgid2, N) \ - ((void) (Domainname), ngettext (Msgid1, Msgid2, N)) -# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ - ((void) (Category), dngettext(Domainname, Msgid1, Msgid2, N)) -# define textdomain(Domainname) ((const char *) (Domainname)) -# define bindtextdomain(Domainname, Dirname) \ - ((void) (Domainname), (const char *) (Dirname)) -# define bind_textdomain_codeset(Domainname, Codeset) \ - ((void) (Domainname), (const char *) (Codeset)) +#define gettext(Msgid) ((const char *)(Msgid)) +#define dgettext(Domainname, Msgid) ((void)(Domainname), gettext(Msgid)) +#define dcgettext(Domainname, Msgid, Category) \ + ((void)(Category), dgettext(Domainname, Msgid)) +#define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? ((void)(Msgid2), (const char *)(Msgid1)) \ + : ((void)(Msgid1), (const char *)(Msgid2))) +#define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((void)(Domainname), ngettext(Msgid1, Msgid2, N)) +#define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((void)(Category), dngettext(Domainname, Msgid1, Msgid2, N)) +#define textdomain(Domainname) ((const char *)(Domainname)) +#define bindtextdomain(Domainname, Dirname) \ + ((void)(Domainname), (const char *)(Dirname)) +#define bind_textdomain_codeset(Domainname, Codeset) \ + ((void)(Domainname), (const char *)(Codeset)) #endif @@ -101,27 +99,33 @@ short and rarely need to change. The letter 'p' stands for 'particular' or 'special'. */ #ifdef DEFAULT_TEXT_DOMAIN -# define pgettext(Msgctxt, Msgid) \ - pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) +#define pgettext(Msgctxt, Msgid) \ + pgettext_aux(DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, \ + LC_MESSAGES) #else -# define pgettext(Msgctxt, Msgid) \ - pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) +#define pgettext(Msgctxt, Msgid) \ + pgettext_aux(NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) #endif -#define dpgettext(Domainname, Msgctxt, Msgid) \ - pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) +#define dpgettext(Domainname, Msgctxt, Msgid) \ + pgettext_aux(Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, \ + LC_MESSAGES) #define dcpgettext(Domainname, Msgctxt, Msgid, Category) \ - pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category) + pgettext_aux(Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category) #ifdef DEFAULT_TEXT_DOMAIN -# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ - npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) +#define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ + npgettext_aux(DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, \ + Msgid, MsgidPlural, N, LC_MESSAGES) #else -# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ - npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) +#define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ + npgettext_aux(NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, \ + N, LC_MESSAGES) #endif -#define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ - npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) +#define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ + npgettext_aux(Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, \ + MsgidPlural, N, LC_MESSAGES) #define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \ - npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category) + npgettext_aux(Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, \ + MsgidPlural, N, Category) #ifdef __GNUC__ __inline @@ -130,12 +134,10 @@ __inline inline #endif #endif -static const char * -pgettext_aux (const char *domain, - const char *msg_ctxt_id, const char *msgid, - int category) -{ - const char *translation = dcgettext (domain, msg_ctxt_id, category); + static const char * +pgettext_aux(const char *domain, const char *msg_ctxt_id, const char *msgid, + int category) { + const char *translation = dcgettext(domain, msg_ctxt_id, category); if (translation == msg_ctxt_id) return msgid; else @@ -149,14 +151,11 @@ __inline inline #endif #endif -static const char * -npgettext_aux (const char *domain, - const char *msg_ctxt_id, const char *msgid, - const char *msgid_plural, unsigned long int n, - int category) -{ + static const char * +npgettext_aux(const char *domain, const char *msg_ctxt_id, const char *msgid, + const char *msgid_plural, unsigned long int n, int category) { const char *translation = - dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); + dcngettext(domain, msg_ctxt_id, msgid_plural, n, category); if (translation == msg_ctxt_id || translation == msgid_plural) return (n == 1 ? msgid : msgid_plural); else @@ -169,18 +168,18 @@ npgettext_aux (const char *domain, #include -#define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS \ +#define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS \ (((__GNUC__ >= 3 || __GNUG__ >= 2) && !__STRICT_ANSI__) \ - /* || __STDC_VERSION__ >= 199901L */ ) + /* || __STDC_VERSION__ >= 199901L */) #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS #include #endif #define pgettext_expr(Msgctxt, Msgid) \ - dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES) + dcpgettext_expr(NULL, Msgctxt, Msgid, LC_MESSAGES) #define dpgettext_expr(Domainname, Msgctxt, Msgid) \ - dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES) + dcpgettext_expr(Domainname, Msgctxt, Msgid, LC_MESSAGES) #ifdef __GNUC__ __inline @@ -189,43 +188,38 @@ __inline inline #endif #endif -static const char * -dcpgettext_expr (const char *domain, - const char *msgctxt, const char *msgid, - int category) -{ - size_t msgctxt_len = strlen (msgctxt) + 1; - size_t msgid_len = strlen (msgid) + 1; + static const char * +dcpgettext_expr(const char *domain, const char *msgctxt, const char *msgid, + int category) { + size_t msgctxt_len = strlen(msgctxt) + 1; + size_t msgid_len = strlen(msgid) + 1; const char *translation; #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS char msg_ctxt_id[msgctxt_len + msgid_len]; #else char buf[1024]; - char *msg_ctxt_id = - (msgctxt_len + msgid_len <= sizeof (buf) - ? buf - : (char *) malloc (msgctxt_len + msgid_len)); + char *msg_ctxt_id = (msgctxt_len + msgid_len <= sizeof(buf) + ? buf + : (char *)malloc(msgctxt_len + msgid_len)); if (msg_ctxt_id != NULL) #endif - { - memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); - msg_ctxt_id[msgctxt_len - 1] = '\004'; - memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); - translation = dcgettext (domain, msg_ctxt_id, category); + { + memcpy(msg_ctxt_id, msgctxt, msgctxt_len - 1); + msg_ctxt_id[msgctxt_len - 1] = '\004'; + memcpy(msg_ctxt_id + msgctxt_len, msgid, msgid_len); + translation = dcgettext(domain, msg_ctxt_id, category); #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS - if (msg_ctxt_id != buf) - free (msg_ctxt_id); + if (msg_ctxt_id != buf) free(msg_ctxt_id); #endif - if (translation != msg_ctxt_id) - return translation; - } + if (translation != msg_ctxt_id) return translation; + } return msgid; } #define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \ - dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) + dcnpgettext_expr(NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) #define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ - dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) + dcnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) #ifdef __GNUC__ __inline @@ -234,37 +228,32 @@ __inline inline #endif #endif -static const char * -dcnpgettext_expr (const char *domain, - const char *msgctxt, const char *msgid, - const char *msgid_plural, unsigned long int n, - int category) -{ - size_t msgctxt_len = strlen (msgctxt) + 1; - size_t msgid_len = strlen (msgid) + 1; + static const char * +dcnpgettext_expr(const char *domain, const char *msgctxt, const char *msgid, + const char *msgid_plural, unsigned long int n, int category) { + size_t msgctxt_len = strlen(msgctxt) + 1; + size_t msgid_len = strlen(msgid) + 1; const char *translation; #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS char msg_ctxt_id[msgctxt_len + msgid_len]; #else char buf[1024]; - char *msg_ctxt_id = - (msgctxt_len + msgid_len <= sizeof (buf) - ? buf - : (char *) malloc (msgctxt_len + msgid_len)); + char *msg_ctxt_id = (msgctxt_len + msgid_len <= sizeof(buf) + ? buf + : (char *)malloc(msgctxt_len + msgid_len)); if (msg_ctxt_id != NULL) #endif - { - memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); - msg_ctxt_id[msgctxt_len - 1] = '\004'; - memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); - translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); + { + memcpy(msg_ctxt_id, msgctxt, msgctxt_len - 1); + msg_ctxt_id[msgctxt_len - 1] = '\004'; + memcpy(msg_ctxt_id + msgctxt_len, msgid, msgid_len); + translation = dcngettext(domain, msg_ctxt_id, msgid_plural, n, category); #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS - if (msg_ctxt_id != buf) - free (msg_ctxt_id); + if (msg_ctxt_id != buf) free(msg_ctxt_id); #endif - if (!(translation == msg_ctxt_id || translation == msgid_plural)) - return translation; - } + if (!(translation == msg_ctxt_id || translation == msgid_plural)) + return translation; + } return (n == 1 ? msgid : msgid_plural); } diff --git a/base/i18n.h b/base/i18n.h index 4a73f14..6094a12 100644 --- a/base/i18n.h +++ b/base/i18n.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -23,22 +23,20 @@ #if defined(LOCALEDIR) -# include "base/gettext.h" +#include "base/gettext.h" // make shortcut for gettext -# define _(STR) gettext (STR) +#define _(STR) gettext(STR) -# include "base/autosprintf.h" +#include "base/autosprintf.h" using gnu::autosprintf; #else -# define gettext(STR) (STR) -# define gettext_noop(STR) (STR) -# define _(STR) (STR) -# define N_(STR) (STR) +#define gettext(STR) (STR) +#define gettext_noop(STR) (STR) +#define _(STR) (STR) +#define N_(STR) (STR) #endif #endif - - diff --git a/base/shared_ptr.h b/base/shared_ptr.h index 82b9068..8dda3c9 100644 --- a/base/shared_ptr.h +++ b/base/shared_ptr.h @@ -8,7 +8,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -25,14 +25,13 @@ #include "base/config.h" #ifdef HAVE_TR1_MEMORY - #include - using std::tr1::shared_ptr; - using std::tr1::dynamic_pointer_cast; +#include +using std::tr1::shared_ptr; +using std::tr1::dynamic_pointer_cast; #else - #include - using std::shared_ptr; - using std::dynamic_pointer_cast; +#include +using std::shared_ptr; +using std::dynamic_pointer_cast; #endif #endif - diff --git a/base/types.h b/base/types.h index 2f6d519..b68337f 100644 --- a/base/types.h +++ b/base/types.h @@ -4,7 +4,6 @@ namespace encfs { typedef unsigned char byte; - } -#endif // TYPES_H +#endif // TYPES_H diff --git a/cipher/BlockCipher.cpp b/cipher/BlockCipher.cpp index 8d7e82d..580f00d 100644 --- a/cipher/BlockCipher.cpp +++ b/cipher/BlockCipher.cpp @@ -13,12 +13,10 @@ namespace encfs { -Registry& BlockCipher::GetRegistry() -{ +Registry& BlockCipher::GetRegistry() { static Registry registry; static bool first = true; - if (first) - { + if (first) { #ifdef WITH_OPENSSL OpenSSL::registerCiphers(); #endif @@ -31,13 +29,8 @@ Registry& BlockCipher::GetRegistry() return registry; } -BlockCipher::BlockCipher() -{ -} +BlockCipher::BlockCipher() {} -BlockCipher::~BlockCipher() -{ -} +BlockCipher::~BlockCipher() {} } // namespace encfs - diff --git a/cipher/BlockCipher.h b/cipher/BlockCipher.h index f920a9c..d0970d3 100644 --- a/cipher/BlockCipher.h +++ b/cipher/BlockCipher.h @@ -15,8 +15,7 @@ static const char NAME_BLOWFISH_CBC[] = "Blowfish/CBC"; // BlockCipher is a StreamCipher with a block size. // Encryption and decryption must be in multiples of the block size. -class BlockCipher : public StreamCipher -{ +class BlockCipher : public StreamCipher { public: DECLARE_REGISTERABLE_TYPE(BlockCipher); @@ -25,9 +24,9 @@ class BlockCipher : public StreamCipher // Not valid until a key has been set, as they key size may determine the // block size. - virtual int blockSize() const =0; + virtual int blockSize() const = 0; }; } // namespace encfs -#endif // BLOCKCIPHER_H +#endif // BLOCKCIPHER_H diff --git a/cipher/BlockCipher_test.cpp b/cipher/BlockCipher_test.cpp index 6e09d4c..b5cfdbe 100644 --- a/cipher/BlockCipher_test.cpp +++ b/cipher/BlockCipher_test.cpp @@ -8,7 +8,7 @@ * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS @@ -43,9 +43,7 @@ namespace { class BlockCipherTest : public testing::Test { public: - virtual void SetUp() { - CipherV1::init(false); - } + virtual void SetUp() { CipherV1::init(false); } }; void compare(const byte *a, const byte *b, int size) { @@ -55,10 +53,8 @@ void compare(const byte *a, const byte *b, int size) { #endif for (int i = 0; i < size; i++) { bool match = (a[i] == b[i]); - ASSERT_TRUE(match) << "mismatched data at offset " << i - << " of " << size; - if (!match) - break; + ASSERT_TRUE(match) << "mismatched data at offset " << i << " of " << size; + if (!match) break; } } @@ -79,26 +75,25 @@ TEST_F(BlockCipherTest, RequiredStreamCiphers) { } template -void checkTestVector(const char *cipherName, - const char *hexKey, - const char *hexIv, - const char *hexPlaintext, +void checkTestVector(const char *cipherName, const char *hexKey, + const char *hexIv, const char *hexPlaintext, const char *hexCipher) { SCOPED_TRACE(testing::Message() << "Testing cipher: " << cipherName - << ", key = " << hexKey << ", plaintext = " << hexPlaintext); + << ", key = " << hexKey + << ", plaintext = " << hexPlaintext); auto cipher = T::GetRegistry().CreateForMatch(cipherName); ASSERT_TRUE(cipher != NULL); - CipherKey key(strlen(hexKey)/2); + CipherKey key(strlen(hexKey) / 2); setDataFromHex(key.data(), key.size(), hexKey); ASSERT_TRUE(cipher->setKey(key)); - byte iv[strlen(hexIv)/2]; + byte iv[strlen(hexIv) / 2]; setDataFromHex(iv, sizeof(iv), hexIv); - byte plaintext[strlen(hexPlaintext)/2]; + byte plaintext[strlen(hexPlaintext) / 2]; setDataFromHex(plaintext, sizeof(plaintext), hexPlaintext); byte ciphertext[sizeof(plaintext)]; @@ -120,45 +115,41 @@ void checkTestVector(const char *cipherName, TEST_F(BlockCipherTest, TestVectors) { // BF128 CBC - checkTestVector(NAME_BLOWFISH_CBC, - "0123456789abcdeff0e1d2c3b4a59687", - "fedcba9876543210", + checkTestVector( + NAME_BLOWFISH_CBC, "0123456789abcdeff0e1d2c3b4a59687", "fedcba9876543210", "37363534333231204e6f77206973207468652074696d6520666f722000000000", "6b77b4d63006dee605b156e27403979358deb9e7154616d959f1652bd5ff92cc"); // BF128 CFB - checkTestVector(NAME_BLOWFISH_CFB, - "0123456789abcdeff0e1d2c3b4a59687", - "fedcba9876543210", + checkTestVector( + NAME_BLOWFISH_CFB, "0123456789abcdeff0e1d2c3b4a59687", "fedcba9876543210", "37363534333231204e6f77206973207468652074696d6520666f722000", "e73214a2822139caf26ecf6d2eb9e76e3da3de04d1517200519d57a6c3"); - + // AES128 CBC - checkTestVector(NAME_AES_CBC, - "2b7e151628aed2a6abf7158809cf4f3c", - "000102030405060708090a0b0c0d0e0f", - "6bc1bee22e409f96e93d7e117393172a", - "7649abac8119b246cee98e9b12e9197d"); - + checkTestVector(NAME_AES_CBC, "2b7e151628aed2a6abf7158809cf4f3c", + "000102030405060708090a0b0c0d0e0f", + "6bc1bee22e409f96e93d7e117393172a", + "7649abac8119b246cee98e9b12e9197d"); + // AES128 CFB - checkTestVector(NAME_AES_CFB, - "2b7e151628aed2a6abf7158809cf4f3c", - "000102030405060708090a0b0c0d0e0f", - "6bc1bee22e409f96e93d7e117393172a", + checkTestVector( + NAME_AES_CFB, "2b7e151628aed2a6abf7158809cf4f3c", + "000102030405060708090a0b0c0d0e0f", "6bc1bee22e409f96e93d7e117393172a", "3b3fd92eb72dad20333449f8e83cfb4a"); // AES256 CBC - checkTestVector(NAME_AES_CBC, + checkTestVector( + NAME_AES_CBC, "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", - "000102030405060708090a0b0c0d0e0f", - "6bc1bee22e409f96e93d7e117393172a", + "000102030405060708090a0b0c0d0e0f", "6bc1bee22e409f96e93d7e117393172a", "f58c4c04d6e5f1ba779eabfb5f7bfbd6"); - + // AES256 CFB - checkTestVector(NAME_AES_CFB, + checkTestVector( + NAME_AES_CFB, "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", - "000102030405060708090a0b0c0d0e0f", - "6bc1bee22e409f96e93d7e117393172a", + "000102030405060708090a0b0c0d0e0f", "6bc1bee22e409f96e93d7e117393172a", "dc7e84bfda79164b7ecd8486985d3860"); } @@ -168,7 +159,7 @@ TEST_F(BlockCipherTest, BlockEncryptionTest) { shared_ptr pbkdf( PBKDF::GetRegistry().CreateForMatch(NAME_PBKDF2_HMAC_SHA1)); - list ciphers = registry.GetAll(); + list ciphers = registry.GetAll(); for (const string &name : ciphers) { const BlockCipher::Properties *properties = registry.GetProperties(name.c_str()); @@ -179,7 +170,7 @@ TEST_F(BlockCipherTest, BlockEncryptionTest) { keySize += properties->keySize.inc()) { SCOPED_TRACE(testing::Message() << "Key size " << keySize); - shared_ptr cipher (registry.Create(name.c_str())); + shared_ptr cipher(registry.Create(name.c_str())); CipherKey key = pbkdf->randomKey(keySize / 8); ASSERT_TRUE(key.valid()); @@ -206,14 +197,14 @@ TEST_F(BlockCipherTest, BlockEncryptionTest) { MemBlock encrypted; encrypted.allocate(16 * blockSize); - ASSERT_TRUE(cipher->encrypt(iv.data, mb.data, - encrypted.data, 16 * blockSize)); + ASSERT_TRUE( + cipher->encrypt(iv.data, mb.data, encrypted.data, 16 * blockSize)); // Decrypt. MemBlock decrypted; decrypted.allocate(16 * blockSize); - ASSERT_TRUE(cipher->decrypt(iv.data, encrypted.data, - decrypted.data, 16 * blockSize)); + ASSERT_TRUE(cipher->decrypt(iv.data, encrypted.data, decrypted.data, + 16 * blockSize)); compare(mb.data, decrypted.data, 16 * blockSize); } diff --git a/cipher/CipherKey.cpp b/cipher/CipherKey.cpp index 7e45ebb..c2e329f 100644 --- a/cipher/CipherKey.cpp +++ b/cipher/CipherKey.cpp @@ -8,7 +8,7 @@ * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS @@ -27,67 +27,41 @@ namespace encfs { -CipherKey::CipherKey() - : _valid(false) -{ +CipherKey::CipherKey() : _valid(false) {} + +CipherKey::CipherKey(int length) : _valid(true) { + if (length > 0) _mem.reset(new SecureMem(length)); } -CipherKey::CipherKey(int length) - : _valid(true) -{ - if (length > 0) - _mem.reset(new SecureMem(length)); -} - -CipherKey::CipherKey(const byte *data, int length) - : _valid(true) -{ +CipherKey::CipherKey(const byte *data, int length) : _valid(true) { _mem.reset(new SecureMem(length)); memcpy(_mem->data(), data, length); } -CipherKey::CipherKey(const CipherKey& src) - : _valid(src._valid), - _mem(src._mem) -{ -} +CipherKey::CipherKey(const CipherKey &src) + : _valid(src._valid), _mem(src._mem) {} -CipherKey::~CipherKey() -{ -} +CipherKey::~CipherKey() {} -void CipherKey::operator = (const CipherKey& src) -{ +void CipherKey::operator=(const CipherKey &src) { _mem = src._mem; _valid = src._valid; } -byte *CipherKey::data() const -{ - return !_mem ? NULL : _mem->data(); -} +byte *CipherKey::data() const { return !_mem ? NULL : _mem->data(); } -int CipherKey::size() const -{ - return !_mem ? 0 : _mem->size(); -} +int CipherKey::size() const { return !_mem ? 0 : _mem->size(); } -void CipherKey::reset() -{ +void CipherKey::reset() { _mem.reset(); _valid = false; } -bool CipherKey::valid() const -{ - return _valid; -} +bool CipherKey::valid() const { return _valid; } -bool operator == (const CipherKey &a, const CipherKey &b) { - if (a.size() != b.size()) - return false; +bool operator==(const CipherKey &a, const CipherKey &b) { + if (a.size() != b.size()) return false; return memcmp(a.data(), b.data(), a.size()) == 0; } } // namespace encfs - diff --git a/cipher/CipherKey.h b/cipher/CipherKey.h index 4cd6e27..9fc5e9e 100644 --- a/cipher/CipherKey.h +++ b/cipher/CipherKey.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -30,16 +30,15 @@ namespace encfs { class SecureMem; -class CipherKey -{ +class CipherKey { public: CipherKey(); // Creates a key for which valid() returns false. explicit CipherKey(int length); CipherKey(const byte *data, int length); - CipherKey(const CipherKey& src); + CipherKey(const CipherKey &src); ~CipherKey(); - void operator = (const CipherKey& src); + void operator=(const CipherKey &src); byte *data() const; int size() const; @@ -54,9 +53,8 @@ class CipherKey shared_ptr _mem; }; -bool operator == (const CipherKey &a, const CipherKey &b); +bool operator==(const CipherKey &a, const CipherKey &b); } // namespace encfs #endif - diff --git a/cipher/CipherKey_test.cpp b/cipher/CipherKey_test.cpp index 10ee8c7..4c00507 100644 --- a/cipher/CipherKey_test.cpp +++ b/cipher/CipherKey_test.cpp @@ -21,9 +21,7 @@ namespace { class CipherKeyTest : public testing::Test { protected: - virtual void SetUp() { - CipherV1::init(false); - } + virtual void SetUp() { CipherV1::init(false); } }; TEST_F(CipherKeyTest, ReadWrite) { @@ -49,5 +47,4 @@ TEST_F(CipherKeyTest, ReadWrite) { } } - -} // namespace +} // namespace diff --git a/cipher/CipherV1.cpp b/cipher/CipherV1.cpp index cf8478e..82b74f1 100644 --- a/cipher/CipherV1.cpp +++ b/cipher/CipherV1.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -59,15 +59,12 @@ using std::vector; namespace encfs { -const int MAX_KEYLENGTH = 64; // in bytes (256 bit) +const int MAX_KEYLENGTH = 64; // in bytes (256 bit) const int MAX_IVLENGTH = 16; const int KEY_CHECKSUM_BYTES = 4; #ifndef MIN -inline int MIN(int a, int b) -{ - return (a < b) ? a : b; -} +inline int MIN(int a, int b) { return (a < b) ? a : b; } #endif void CipherV1::init(bool threaded) { @@ -91,118 +88,101 @@ void CipherV1::shutdown(bool threaded) { This duplicated some code in OpenSSL, correcting an issue with key lengths produced for Blowfish. */ -bool BytesToKey(const byte *data, int dataLen, - unsigned int rounds, CipherKey *key) -{ +bool BytesToKey(const byte *data, int dataLen, unsigned int rounds, + CipherKey *key) { Registry registry = MAC::GetRegistry(); shared_ptr sha1(registry.CreateForMatch("SHA-1")); - if (!sha1) - return false; + if (!sha1) return false; - if( data == NULL || dataLen == 0 ) - return false; // OpenSSL returns nkey here, but why? It is a failure.. + if (data == NULL || dataLen == 0) + return false; // OpenSSL returns nkey here, but why? It is a failure.. - SecureMem mdBuf( sha1->outputSize() ); + SecureMem mdBuf(sha1->outputSize()); int addmd = 0; int remaining = key->size(); - for(;;) - { + for (;;) { sha1->init(); - if( addmd++ ) - sha1->update(mdBuf.data(), mdBuf.size()); + if (addmd++) sha1->update(mdBuf.data(), mdBuf.size()); sha1->update(data, dataLen); sha1->write(mdBuf.data()); - for(unsigned int i=1; i < rounds; ++i) - { + for (unsigned int i = 1; i < rounds; ++i) { sha1->init(); sha1->update(mdBuf.data(), mdBuf.size()); sha1->write(mdBuf.data()); } int offset = 0; - int toCopy = MIN( remaining, mdBuf.size() - offset ); - if( toCopy ) - { - memcpy( key->data(), mdBuf.data()+offset, toCopy ); + int toCopy = MIN(remaining, mdBuf.size() - offset); + if (toCopy) { + memcpy(key->data(), mdBuf.data() + offset, toCopy); key += toCopy; remaining -= toCopy; offset += toCopy; } - if(remaining == 0) break; + if (remaining == 0) break; } return true; } -long time_diff(const timeval &end, const timeval &start) -{ +long time_diff(const timeval &end, const timeval &start) { return (end.tv_sec - start.tv_sec) * 1000 * 1000 + - (end.tv_usec - start.tv_usec); + (end.tv_usec - start.tv_usec); } -int CipherV1::TimedPBKDF2(const char *pass, int passlen, - const byte *salt, int saltlen, - CipherKey *key, long desiredPDFTime) -{ +int CipherV1::TimedPBKDF2(const char *pass, int passlen, const byte *salt, + int saltlen, CipherKey *key, long desiredPDFTime) { #ifdef HAVE_VALGRIND_MEMCHECK_H VALGRIND_CHECK_MEM_IS_DEFINED(pass, passlen); VALGRIND_CHECK_MEM_IS_DEFINED(salt, saltlen); #endif Registry registry = PBKDF::GetRegistry(); shared_ptr impl(registry.CreateForMatch(NAME_PBKDF2_HMAC_SHA1)); - if (!impl) - return -1; + if (!impl) return -1; int iter = 1000; timeval start, end; - for(;;) - { - gettimeofday( &start, 0 ); - if (!impl->makeKey(pass, passlen, salt, saltlen, iter, key)) - return -1; + for (;;) { + gettimeofday(&start, 0); + if (!impl->makeKey(pass, passlen, salt, saltlen, iter, key)) return -1; - gettimeofday( &end, 0 ); + gettimeofday(&end, 0); long delta = time_diff(end, start); - if(delta < desiredPDFTime / 8) - { + if (delta < desiredPDFTime / 8) { iter *= 4; - } else if(delta < (5 * desiredPDFTime / 6)) - { + } else if (delta < (5 * desiredPDFTime / 6)) { // estimate number of iterations to get close to desired time - iter = (int)((double)iter * (double)desiredPDFTime - / (double)delta); + iter = (int)((double)iter * (double)desiredPDFTime / (double)delta); } else return iter; } } - // - Version 1:0 used EVP_BytesToKey, which didn't do the right thing for // Blowfish key lengths > 128 bit. -// - Version 2:0 uses BytesToKey. +// - Version 2:0 uses BytesToKey. // We support both 2:0 and 1:0, hence current:revision:age = 2:0:1 // - Version 2:1 adds support for Message Digest function interface // - Version 2:2 adds PBKDF2 for password derivation // - Version 3:0 adds a new IV mechanism // - Version 3:1 drops support for verison 1:0 blowfish keys, in order to avoid // having to duplicate the behavior of old EVP_BytesToKey implementations. -static Interface BlowfishInterface = makeInterface( "ssl/blowfish", 3, 1, 1 ); -static Interface AESInterface = makeInterface( "ssl/aes", 3, 1, 2 ); +static Interface BlowfishInterface = makeInterface("ssl/blowfish", 3, 1, 1); +static Interface AESInterface = makeInterface("ssl/aes", 3, 1, 2); -static Interface NullCipherInterface = makeInterface( "nullCipher", 1, 0, 0); +static Interface NullCipherInterface = makeInterface("nullCipher", 1, 0, 0); -static Range BFKeyRange(128,256,32); +static Range BFKeyRange(128, 256, 32); static int BFDefaultKeyLen = 160; -static Range AESKeyRange(128,256,64); +static Range AESKeyRange(128, 256, 64); static int AESDefaultKeyLen = 192; -list CipherV1::GetAlgorithmList() -{ +list CipherV1::GetAlgorithmList() { list result; Registry blockCipherRegistry = BlockCipher::GetRegistry(); @@ -213,7 +193,7 @@ list CipherV1::GetAlgorithmList() alg.iface = AESInterface; alg.keyLength = AESKeyRange; alg.blockSize = Range(64, 4096, 16); - result.push_back(alg); + result.push_back(alg); } if (blockCipherRegistry.GetPropertiesForMatch(NAME_BLOWFISH_CBC) != NULL) { @@ -223,7 +203,7 @@ list CipherV1::GetAlgorithmList() alg.iface = BlowfishInterface; alg.keyLength = BFKeyRange; alg.blockSize = Range(64, 4096, 8); - result.push_back(alg); + result.push_back(alg); } CipherV1::CipherAlgorithm alg; @@ -232,15 +212,14 @@ list CipherV1::GetAlgorithmList() alg.iface = NullCipherInterface; alg.keyLength = Range(0); alg.blockSize = Range(64, 4096, 8); - result.push_back(alg); - + result.push_back(alg); + return result; } -shared_ptr CipherV1::New(const std::string& name, int keyLen) { +shared_ptr CipherV1::New(const std::string &name, int keyLen) { for (auto &it : GetAlgorithmList()) { - if (it.name == name) - return New(it.iface, keyLen); + if (it.name == name) return New(it.iface, keyLen); } return shared_ptr(); @@ -248,18 +227,14 @@ shared_ptr CipherV1::New(const std::string& name, int keyLen) { shared_ptr CipherV1::New(const Interface &iface, int keyLen) { shared_ptr result(new CipherV1()); - if (!result->initCiphers(iface, iface, keyLen)) - result.reset(); + if (!result->initCiphers(iface, iface, keyLen)) result.reset(); return result; } -CipherV1::CipherV1() -{ -} +CipherV1::CipherV1() {} bool CipherV1::initCiphers(const Interface &iface, const Interface &realIface, - int keyLength) -{ + int keyLength) { this->iface = iface; this->realIface = realIface; @@ -270,21 +245,20 @@ bool CipherV1::initCiphers(const Interface &iface, const Interface &realIface, Range keyRange; if (implements(AESInterface, iface)) { - keyRange = AESKeyRange; + keyRange = AESKeyRange; defaultKeyLength = AESDefaultKeyLen; - _blockCipher.reset( blockCipherRegistry.CreateForMatch(NAME_AES_CBC) ); - _streamCipher.reset( streamCipherRegistry.CreateForMatch(NAME_AES_CFB) ); + _blockCipher.reset(blockCipherRegistry.CreateForMatch(NAME_AES_CBC)); + _streamCipher.reset(streamCipherRegistry.CreateForMatch(NAME_AES_CFB)); } else if (implements(BlowfishInterface, iface)) { keyRange = BFKeyRange; defaultKeyLength = BFDefaultKeyLen; - _blockCipher.reset( blockCipherRegistry.CreateForMatch(NAME_BLOWFISH_CBC) ); - _streamCipher.reset( streamCipherRegistry.CreateForMatch - (NAME_BLOWFISH_CFB) ); + _blockCipher.reset(blockCipherRegistry.CreateForMatch(NAME_BLOWFISH_CBC)); + _streamCipher.reset(streamCipherRegistry.CreateForMatch(NAME_BLOWFISH_CFB)); } else if (implements(NullCipherInterface, iface)) { keyRange = Range(0); defaultKeyLength = 0; - _blockCipher.reset( blockCipherRegistry.CreateForMatch("NullCipher") ); - _streamCipher.reset( streamCipherRegistry.CreateForMatch("NullCipher") ); + _blockCipher.reset(blockCipherRegistry.CreateForMatch("NullCipher")); + _streamCipher.reset(streamCipherRegistry.CreateForMatch("NullCipher")); } if (!_blockCipher || !_streamCipher) { @@ -297,8 +271,7 @@ bool CipherV1::initCiphers(const Interface &iface, const Interface &realIface, else _keySize = keyRange.closest(keyLength) / 8; - _pbkdf.reset(PBKDF::GetRegistry().CreateForMatch( - NAME_PBKDF2_HMAC_SHA1)); + _pbkdf.reset(PBKDF::GetRegistry().CreateForMatch(NAME_PBKDF2_HMAC_SHA1)); if (!_pbkdf) { LOG(ERROR) << "PBKDF missing"; return false; @@ -322,14 +295,9 @@ bool CipherV1::initCiphers(const Interface &iface, const Interface &realIface, return true; } -CipherV1::~CipherV1() -{ -} +CipherV1::~CipherV1() {} -Interface CipherV1::interface() const -{ - return realIface; -} +Interface CipherV1::interface() const { return realIface; } /* Create a key from the password. @@ -340,33 +308,27 @@ Interface CipherV1::interface() const */ CipherKey CipherV1::newKey(const char *password, int passwdLength, int *iterationCount, long desiredDuration, - const byte *salt, int saltLen) -{ + const byte *salt, int saltLen) { #ifdef HAVE_VALGRIND_MEMCHECK_H VALGRIND_CHECK_MEM_IS_DEFINED(password, passwdLength); VALGRIND_CHECK_MEM_IS_DEFINED(salt, saltLen); #endif CipherKey key(_keySize + _ivLength); - if(*iterationCount == 0) - { + if (*iterationCount == 0) { // timed run, fills in iteration count - int res = TimedPBKDF2(password, passwdLength, - salt, saltLen, &key, + int res = TimedPBKDF2(password, passwdLength, salt, saltLen, &key, 1000 * desiredDuration); - if(res <= 0) - { + if (res <= 0) { LOG(ERROR) << "openssl error, PBKDF2 failed"; return CipherKey(); } else { *iterationCount = res; } - } else - { + } else { // known iteration length - if (!_pbkdf->makeKey(password, passwdLength, - salt, saltLen, *iterationCount, &key)) - { + if (!_pbkdf->makeKey(password, passwdLength, salt, saltLen, *iterationCount, + &key)) { LOG(ERROR) << "openssl error, PBKDF2 failed"; return CipherKey(); } @@ -378,8 +340,7 @@ CipherKey CipherV1::newKey(const char *password, int passwdLength, // Deprecated - for use only with filesystems which used a fixed-round PBKDF. // Such configurations are replaced with a new PBKDF2 implementation when the // password is changed or configuration is rewritten. -CipherKey CipherV1::newKey(const char *password, int passwdLength) -{ +CipherKey CipherV1::newKey(const char *password, int passwdLength) { #ifdef HAVE_VALGRIND_MEMCHECK_H VALGRIND_CHECK_MEM_IS_DEFINED(password, passwdLength); #endif @@ -387,37 +348,33 @@ CipherKey CipherV1::newKey(const char *password, int passwdLength) bool ok = BytesToKey((byte *)password, passwdLength, 16, &key); LOG_IF(ERROR, !ok) << "newKey: BytesToKey failed"; - if (!ok) - throw Error("BytesToKey failed"); + if (!ok) throw Error("BytesToKey failed"); return key; } -CipherKey CipherV1::newRandomKey() -{ +CipherKey CipherV1::newRandomKey() { return _pbkdf->randomKey(_keySize + _ivLength); } -bool CipherV1::pseudoRandomize( byte *buf, int len ) -{ +bool CipherV1::pseudoRandomize(byte *buf, int len) { return _pbkdf->pseudoRandom(buf, len); } bool CipherV1::setKey(const CipherKey &keyIv) { Lock l(_hmacMutex); - LOG_IF(ERROR, (int)(_keySize + _ivLength) != keyIv.size()) - << "Mismatched key size: passed " - << keyIv.size() << ", expecting " << _keySize; + LOG_IF(ERROR, (int)(_keySize + _ivLength) != keyIv.size()) + << "Mismatched key size: passed " << keyIv.size() << ", expecting " + << _keySize; // Key is actually key plus iv, so extract the different parts. CipherKey key(_keySize); memcpy(key.data(), keyIv.data(), _keySize); memcpy(_iv->data(), keyIv.data() + _keySize, _ivLength); - if (_blockCipher->setKey(key) - && _streamCipher->setKey(key) - && _hmac->setKey(key)) { + if (_blockCipher->setKey(key) && _streamCipher->setKey(key) && + _hmac->setKey(key)) { _keySet = true; return true; } @@ -426,24 +383,21 @@ bool CipherV1::setKey(const CipherKey &keyIv) { } uint64_t CipherV1::MAC_64(const byte *data, int len, - uint64_t *chainedIV ) const -{ - rAssert( len > 0 ); - rAssert( _keySet ); + uint64_t *chainedIV) const { + rAssert(len > 0); + rAssert(_keySet); byte md[_hmac->outputSize()]; - + Lock l(_hmacMutex); _hmac->init(); _hmac->update(data, len); - if(chainedIV) - { + if (chainedIV) { // toss in the chained IV as well uint64_t tmp = *chainedIV; byte h[8]; - for(unsigned int i=0; i<8; ++i) - { + for (unsigned int i = 0; i < 8; ++i) { h[i] = tmp & 0xff; tmp >>= 8; } @@ -455,174 +409,151 @@ uint64_t CipherV1::MAC_64(const byte *data, int len, rAssert(ok); // chop this down to a 64bit value.. - byte h[8] = {0,0,0,0,0,0,0,0}; + byte h[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // XXX: the last byte off the hmac isn't used. This minor inconsistency // must be maintained in order to maintain backward compatiblity with earlier // releases. - for(int i=0; i<_hmac->outputSize()-1; ++i) - h[i%8] ^= (byte)(md[i]); + for (int i = 0; i < _hmac->outputSize() - 1; ++i) h[i % 8] ^= (byte)(md[i]); uint64_t value = (uint64_t)h[0]; - for(int i=1; i<8; ++i) - value = (value << 8) | (uint64_t)h[i]; + for (int i = 1; i < 8; ++i) value = (value << 8) | (uint64_t)h[i]; // TODO: should not be here. - if(chainedIV) - *chainedIV = value; + if (chainedIV) *chainedIV = value; return value; } -unsigned int CipherV1::reduceMac32(uint64_t mac64) -{ +unsigned int CipherV1::reduceMac32(uint64_t mac64) { return ((mac64 >> 32) & 0xffffffff) ^ (mac64 & 0xffffffff); } -unsigned int CipherV1::reduceMac16(uint64_t mac64) -{ +unsigned int CipherV1::reduceMac16(uint64_t mac64) { unsigned int mac32 = reduceMac32(mac64); return ((mac32 >> 16) & 0xffff) ^ (mac32 & 0xffff); } -CipherKey CipherV1::readKey(const byte *data, bool checkKey) -{ - rAssert( _keySet ); +CipherKey CipherV1::readKey(const byte *data, bool checkKey) { + rAssert(_keySet); CipherKey key(_keySize + _ivLength); // First N bytes are checksum bytes. unsigned int checksum = 0; - for(int i=0; i>= 8; } - memcpy( out+KEY_CHECKSUM_BYTES, tmpBuf.data(), tmpBuf.size() ); + memcpy(out + KEY_CHECKSUM_BYTES, tmpBuf.data(), tmpBuf.size()); } -std::string CipherV1::encodeAsString(const CipherKey &key) -{ - rAssert( _keySet ); +std::string CipherV1::encodeAsString(const CipherKey &key) { + rAssert(_keySet); int encodedSize = encodedKeySize(); vector buf(encodedSize); writeKey(key, buf.data()); - int b64Len = B256ToB64Bytes( encodedSize ); + int b64Len = B256ToB64Bytes(encodedSize); byte *b64Key = new byte[b64Len + 1]; - changeBase2( buf.data(), encodedSize, 8, b64Key, b64Len, 6); - B64ToAscii( b64Key, b64Len ); - b64Key[ b64Len - 1 ] = '\0'; + changeBase2(buf.data(), encodedSize, 8, b64Key, b64Len, 6); + B64ToAscii(b64Key, b64Len); + b64Key[b64Len - 1] = '\0'; - return string( (const char *)b64Key ); + return string((const char *)b64Key); } -int CipherV1::encodedKeySize() const -{ +int CipherV1::encodedKeySize() const { return _keySize + _ivLength + KEY_CHECKSUM_BYTES; } -int CipherV1::keySize() const -{ - return _keySize; -} +int CipherV1::keySize() const { return _keySize; } -int CipherV1::cipherBlockSize() const -{ - return _blockCipher->blockSize(); -} +int CipherV1::cipherBlockSize() const { return _blockCipher->blockSize(); } // Deprecated: For backward compatibility only. // A watermark attack was published against this data-independent IV schedule. // The replacement incorporates the filesystem key, making it unique to each // filesystem. -static void setIVec_old(byte *ivec, int ivLen, unsigned int seed) -{ - unsigned int var1 = 0x060a4011 * seed; +static void setIVec_old(byte *ivec, int ivLen, unsigned int seed) { + unsigned int var1 = 0x060a4011 * seed; unsigned int var2 = 0x0221040d * (seed ^ 0xD3FEA11C); ivec[0] ^= (var1 >> 24) & 0xff; ivec[1] ^= (var2 >> 16) & 0xff; - ivec[2] ^= (var1 >> 8 ) & 0xff; - ivec[3] ^= (var2 ) & 0xff; + ivec[2] ^= (var1 >> 8) & 0xff; + ivec[3] ^= (var2) & 0xff; ivec[4] ^= (var2 >> 24) & 0xff; ivec[5] ^= (var1 >> 16) & 0xff; - ivec[6] ^= (var2 >> 8 ) & 0xff; - ivec[7] ^= (var1 ) & 0xff; + ivec[6] ^= (var2 >> 8) & 0xff; + ivec[7] ^= (var1) & 0xff; - if(ivLen > 8) - { - ivec[8+0] ^= (var1 ) & 0xff; - ivec[8+1] ^= (var2 >> 8 ) & 0xff; - ivec[8+2] ^= (var1 >> 16) & 0xff; - ivec[8+3] ^= (var2 >> 24) & 0xff; - ivec[8+4] ^= (var1 >> 24) & 0xff; - ivec[8+5] ^= (var2 >> 16) & 0xff; - ivec[8+6] ^= (var1 >> 8 ) & 0xff; - ivec[8+7] ^= (var2 ) & 0xff; + if (ivLen > 8) { + ivec[8 + 0] ^= (var1) & 0xff; + ivec[8 + 1] ^= (var2 >> 8) & 0xff; + ivec[8 + 2] ^= (var1 >> 16) & 0xff; + ivec[8 + 3] ^= (var2 >> 24) & 0xff; + ivec[8 + 4] ^= (var1 >> 24) & 0xff; + ivec[8 + 5] ^= (var2 >> 16) & 0xff; + ivec[8 + 6] ^= (var1 >> 8) & 0xff; + ivec[8 + 7] ^= (var2) & 0xff; } } -void CipherV1::setIVec(byte *ivec, uint64_t seed) const -{ - rAssert( _keySet ); - memcpy( ivec, _iv->data(), _ivLength ); - if (iface.major() < 3) - { +void CipherV1::setIVec(byte *ivec, uint64_t seed) const { + rAssert(_keySet); + memcpy(ivec, _iv->data(), _ivLength); + if (iface.major() < 3) { // Backward compatible mode. setIVec_old(ivec, _ivLength, seed); return; } vector md(_hmac->outputSize()); - for(int i=0; i<8; ++i) - { + for (int i = 0; i < 8; ++i) { md[i] = (byte)(seed & 0xff); seed >>= 8; } @@ -637,102 +568,86 @@ void CipherV1::setIVec(byte *ivec, uint64_t seed) const memcpy(ivec, md.data(), _ivLength); } -static void flipBytes(byte *buf, int size) -{ +static void flipBytes(byte *buf, int size) { byte revBuf[64]; int bytesLeft = size; - while(bytesLeft) - { - int toFlip = MIN( (int)sizeof(revBuf), bytesLeft ); + while (bytesLeft) { + int toFlip = MIN((int)sizeof(revBuf), bytesLeft); - for(int i=0; i 0 ); +bool CipherV1::streamEncode(byte *buf, int size, uint64_t iv64) const { + rAssert(_keySet); + rAssert(size > 0); vector ivec(_ivLength); - shuffleBytes( buf, size ); + shuffleBytes(buf, size); - setIVec( ivec.data(), iv64 ); - if (!_streamCipher->encrypt(ivec.data(), buf, buf, size)) - return false; + setIVec(ivec.data(), iv64); + if (!_streamCipher->encrypt(ivec.data(), buf, buf, size)) return false; - flipBytes( buf, size ); - shuffleBytes( buf, size ); + flipBytes(buf, size); + shuffleBytes(buf, size); - setIVec( ivec.data(), iv64 + 1 ); - if (!_streamCipher->encrypt(ivec.data(), buf, buf, size)) - return false; + setIVec(ivec.data(), iv64 + 1); + if (!_streamCipher->encrypt(ivec.data(), buf, buf, size)) return false; return true; } -bool CipherV1::streamDecode(byte *buf, int size, uint64_t iv64) const -{ - rAssert( _keySet ); - rAssert( size > 0 ); +bool CipherV1::streamDecode(byte *buf, int size, uint64_t iv64) const { + rAssert(_keySet); + rAssert(size > 0); vector ivec(_ivLength); - setIVec( ivec.data(), iv64 + 1 ); - if (!_streamCipher->decrypt(ivec.data(), buf, buf, size)) - return false; + setIVec(ivec.data(), iv64 + 1); + if (!_streamCipher->decrypt(ivec.data(), buf, buf, size)) return false; - unshuffleBytes( buf, size ); - flipBytes( buf, size ); + unshuffleBytes(buf, size); + flipBytes(buf, size); - setIVec( ivec.data(), iv64 ); - if (!_streamCipher->decrypt(ivec.data(), buf, buf, size)) - return false; + setIVec(ivec.data(), iv64); + if (!_streamCipher->decrypt(ivec.data(), buf, buf, size)) return false; - unshuffleBytes( buf, size ); + unshuffleBytes(buf, size); return true; } - -bool CipherV1::blockEncode(byte *buf, int size, uint64_t iv64) const -{ - rAssert( _keySet ); - rAssert( size > 0 ); +bool CipherV1::blockEncode(byte *buf, int size, uint64_t iv64) const { + rAssert(_keySet); + rAssert(size > 0); vector ivec(_ivLength); - setIVec( ivec.data(), iv64 ); + setIVec(ivec.data(), iv64); return _blockCipher->encrypt(ivec.data(), buf, buf, size); } -bool CipherV1::blockDecode(byte *buf, int size, uint64_t iv64) const -{ - rAssert( _keySet ); - rAssert( size > 0 ); +bool CipherV1::blockDecode(byte *buf, int size, uint64_t iv64) const { + rAssert(_keySet); + rAssert(size > 0); vector ivec(_ivLength); - setIVec( ivec.data(), iv64 ); + setIVec(ivec.data(), iv64); return _blockCipher->decrypt(ivec.data(), buf, buf, size); } diff --git a/cipher/CipherV1.h b/cipher/CipherV1.h index 03a840a..3a197d4 100644 --- a/cipher/CipherV1.h +++ b/cipher/CipherV1.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -72,8 +72,7 @@ class SecureMem; initial value vector to randomize the output. But it makes the code simpler to reuse the encryption algorithm as is. */ -class CipherV1 -{ +class CipherV1 { Interface iface; Interface realIface; @@ -85,16 +84,14 @@ class CipherV1 mutable Mutex _hmacMutex; mutable shared_ptr _hmac; - unsigned int _keySize; // in bytes + unsigned int _keySize; // in bytes unsigned int _ivLength; shared_ptr _iv; bool _keySet; public: - - struct CipherAlgorithm - { + struct CipherAlgorithm { std::string name; std::string description; Interface iface; @@ -113,23 +110,22 @@ class CipherV1 // Password-based key derivation function which determines the // number of iterations based on a desired execution time (in microseconds). // Returns the number of iterations applied. - static int TimedPBKDF2(const char *pass, int passLen, - const byte *salt, int saltLen, - CipherKey *out, long desiredPDFTimeMicroseconds); + static int TimedPBKDF2(const char *pass, int passLen, const byte *salt, + int saltLen, CipherKey *out, + long desiredPDFTimeMicroseconds); CipherV1(); ~CipherV1(); - bool initCiphers(const Interface &iface, - const Interface &realIface, int keyLength); + bool initCiphers(const Interface &iface, const Interface &realIface, + int keyLength); // returns the real interface, not the one we're emulating (if any).. Interface interface() const; // create a new key based on a password - CipherKey newKey(const char *password, int passwdLength, - int *iterationCount, long desiredDuration, - const byte *salt, int saltLen); + CipherKey newKey(const char *password, int passwdLength, int *iterationCount, + long desiredDuration, const byte *salt, int saltLen); // deprecated - for backward compatibility CipherKey newKey(const char *password, int passwdLength); // create a new random key @@ -140,11 +136,10 @@ class CipherV1 CipherKey readKey(const byte *data, bool checkKey); // Encrypt and write the given key. - void writeKey(const CipherKey &key, byte *data); + void writeKey(const CipherKey &key, byte *data); // Encrypt and store a key as a string. std::string encodeAsString(const CipherKey &key); - // meta-data about the cypher int keySize() const; @@ -156,8 +151,7 @@ class CipherV1 // Sets the key used for encoding / decoding, and MAC operations. bool setKey(const CipherKey &key); - uint64_t MAC_64(const byte *src, int len, - uint64_t *augment = NULL) const; + uint64_t MAC_64(const byte *src, int len, uint64_t *augment = NULL) const; static unsigned int reduceMac32(uint64_t mac64); static unsigned int reduceMac16(uint64_t mac64); @@ -184,4 +178,3 @@ class CipherV1 } // namespace encfs #endif - diff --git a/cipher/CommonCrypto.cpp b/cipher/CommonCrypto.cpp index 0e405a1..e91efb8 100644 --- a/cipher/CommonCrypto.cpp +++ b/cipher/CommonCrypto.cpp @@ -8,7 +8,7 @@ * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS @@ -42,18 +42,16 @@ namespace commoncrypto { class PbkdfPkcs5Hmac : public PBKDF { CCPseudoRandomAlgorithm prf_; -public: - PbkdfPkcs5Hmac(CCPseudoRandomAlgorithm prf) - : prf_(prf) {} + + public: + PbkdfPkcs5Hmac(CCPseudoRandomAlgorithm prf) : prf_(prf) {} virtual ~PbkdfPkcs5Hmac() {} - + virtual bool makeKey(const char *password, int passwordLength, - const byte *salt, int saltLength, - int numIterations, + const byte *salt, int saltLength, int numIterations, CipherKey *outKey) { - int ret = CCKeyDerivationPBKDF(kCCPBKDF2, password, passwordLength, - salt, saltLength, prf_, - numIterations, + int ret = CCKeyDerivationPBKDF(kCCPBKDF2, password, passwordLength, salt, + saltLength, prf_, numIterations, outKey->data(), outKey->size()); if (ret != 0) { PLOG(ERROR) << "CCKeyDerivationPBKDF failed"; @@ -75,7 +73,7 @@ public: #endif return key; } - + virtual bool pseudoRandom(byte *out, int length) { if (length == 0) return true; #ifdef HAVE_SEC_RANDOM_H @@ -90,9 +88,8 @@ public: } }; - class PbkdfPkcs5HmacSha1CC : public PbkdfPkcs5Hmac { -public: + public: PbkdfPkcs5HmacSha1CC() : PbkdfPkcs5Hmac(kCCPRFHmacAlgSHA1) {} ~PbkdfPkcs5HmacSha1CC() {} @@ -106,7 +103,7 @@ public: REGISTER_CLASS(PbkdfPkcs5HmacSha1CC, PBKDF); class PbkdfPkcs5HmacSha256CC : public PbkdfPkcs5Hmac { -public: + public: PbkdfPkcs5HmacSha256CC() : PbkdfPkcs5Hmac(kCCPRFHmacAlgSHA256) {} ~PbkdfPkcs5HmacSha256CC() {} @@ -123,9 +120,10 @@ class CCCipher : public BlockCipher { CipherKey key; CCAlgorithm algorithm; CCMode mode; + public: - CCCipher() { } - virtual ~CCCipher() { } + CCCipher() {} + virtual ~CCCipher() {} bool rekey(const CipherKey &key, CCAlgorithm algorithm, CCMode mode) { this->key = key; @@ -136,20 +134,18 @@ class CCCipher : public BlockCipher { virtual bool encrypt(const byte *iv, const byte *in, byte *out, int size) { CCCryptorRef cryptor; - CCCryptorCreateWithMode(kCCEncrypt, mode, algorithm, 0, - iv, key.data(), key.size(), - NULL, 0, 0, 0, &cryptor); + CCCryptorCreateWithMode(kCCEncrypt, mode, algorithm, 0, iv, key.data(), + key.size(), NULL, 0, 0, 0, &cryptor); size_t updateLength = 0; CCCryptorUpdate(cryptor, in, size, out, size, &updateLength); CCCryptorRelease(cryptor); return true; } - + virtual bool decrypt(const byte *iv, const byte *in, byte *out, int size) { CCCryptorRef cryptor; - CCCryptorCreateWithMode(kCCDecrypt, mode, algorithm, 0, - iv, key.data(), key.size(), - NULL, 0, 0, 0, &cryptor); + CCCryptorCreateWithMode(kCCDecrypt, mode, algorithm, 0, iv, key.data(), + key.size(), NULL, 0, 0, 0, &cryptor); size_t updateLength = 0; CCCryptorUpdate(cryptor, in, size, out, size, &updateLength); CCCryptorRelease(cryptor); @@ -166,12 +162,10 @@ class BfCbc : public CCCipher { return CCCipher::rekey(key, kCCAlgorithmBlowfish, kCCModeCBC); } - virtual int blockSize() const { - return kCCBlockSizeBlowfish; - } + virtual int blockSize() const { return kCCBlockSizeBlowfish; } static Properties GetProperties() { - return Properties(Range(128,256,32), "Blowfish", "CBC", "CommonCrypto"); + return Properties(Range(128, 256, 32), "Blowfish", "CBC", "CommonCrypto"); } }; REGISTER_CLASS(BfCbc, BlockCipher); @@ -184,13 +178,11 @@ class AesCbc : public CCCipher { virtual bool setKey(const CipherKey &key) { return CCCipher::rekey(key, kCCAlgorithmAES128, kCCModeCBC); } - - virtual int blockSize() const { - return kCCBlockSizeAES128; - } - + + virtual int blockSize() const { return kCCBlockSizeAES128; } + static Properties GetProperties() { - return Properties(Range(128,256,64), "AES", "CBC", "CommonCrypto"); + return Properties(Range(128, 256, 64), "AES", "CBC", "CommonCrypto"); } }; REGISTER_CLASS(AesCbc, BlockCipher); @@ -207,7 +199,7 @@ class BfCfb : public CCCipher { virtual int blockSize() const { return 1; } static Properties GetProperties() { - return Properties(Range(128,256,32), "Blowfish", "CFB", "CommonCrypto"); + return Properties(Range(128, 256, 32), "Blowfish", "CFB", "CommonCrypto"); } }; REGISTER_CLASS(BfCfb, StreamCipher); @@ -220,11 +212,11 @@ class AesCfb : public CCCipher { virtual bool setKey(const CipherKey &key) { return CCCipher::rekey(key, kCCAlgorithmAES128, kCCModeCFB); } - + virtual int blockSize() const { return 1; } static Properties GetProperties() { - return Properties(Range(128,256,64), "AES", "CFB", "CommonCrypto"); + return Properties(Range(128, 256, 64), "AES", "CFB", "CommonCrypto"); } }; REGISTER_CLASS(AesCfb, StreamCipher); @@ -234,9 +226,7 @@ class Sha1HMac : public MAC { Sha1HMac() {} virtual ~Sha1HMac() {} - virtual int outputSize() const { - return CC_SHA1_DIGEST_LENGTH; - } + virtual int outputSize() const { return CC_SHA1_DIGEST_LENGTH; } virtual bool setKey(const CipherKey &key) { this->key = key; @@ -253,7 +243,7 @@ class Sha1HMac : public MAC { } } - virtual bool update (const byte *in, int length) { + virtual bool update(const byte *in, int length) { CCHmacUpdate(&ctx, in, length); return true; } @@ -280,7 +270,6 @@ REGISTER_CLASS(Sha1HMac, MAC); } // namespace commoncrypto -void CommonCrypto::registerCiphers() { -} +void CommonCrypto::registerCiphers() {} } // namespace encfs diff --git a/cipher/CommonCrypto.h b/cipher/CommonCrypto.h index d08289b..ae2bce6 100644 --- a/cipher/CommonCrypto.h +++ b/cipher/CommonCrypto.h @@ -8,7 +8,7 @@ * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS @@ -30,6 +30,4 @@ struct CommonCrypto { } // namespace encfs - #endif - diff --git a/cipher/MAC.cpp b/cipher/MAC.cpp index 8534d77..4772f7c 100644 --- a/cipher/MAC.cpp +++ b/cipher/MAC.cpp @@ -4,13 +4,8 @@ namespace encfs { DEFINE_REGISTERABLE_TYPE(MAC) -MAC::MAC() -{ -} +MAC::MAC() {} -MAC::~MAC() -{ -} +MAC::~MAC() {} } // namespace encfs - diff --git a/cipher/MAC.h b/cipher/MAC.h index d0b7fd5..d73349c 100644 --- a/cipher/MAC.h +++ b/cipher/MAC.h @@ -12,35 +12,32 @@ namespace encfs { static const char NAME_SHA1_HMAC[] = "SHA-1/HMAC"; // MAC provides keyed MessageAuthenticationCode algorithms, eg HMAC. -class MAC -{ +class MAC { public: DECLARE_REGISTERABLE_TYPE(MAC); struct Properties { - int blockSize; // Block length of hash function. + int blockSize; // Block length of hash function. std::string hashFunction; std::string mode; std::string library; - std::string toString() const { - return hashFunction + "/" + mode; - } + std::string toString() const { return hashFunction + "/" + mode; } }; MAC(); virtual ~MAC(); - virtual int outputSize() const =0; + virtual int outputSize() const = 0; - virtual bool setKey(const CipherKey &key) =0; + virtual bool setKey(const CipherKey &key) = 0; // Init must be called before any calls to update. - virtual void init() =0; - virtual bool update(const byte *in, int length) =0; - virtual bool write(byte *out) =0; + virtual void init() = 0; + virtual bool update(const byte *in, int length) = 0; + virtual bool write(byte *out) = 0; }; } // namespace encfs -#endif // ENCFS_MAC_H +#endif // ENCFS_MAC_H diff --git a/cipher/MAC_test.cpp b/cipher/MAC_test.cpp index 7afc7d9..07f7715 100644 --- a/cipher/MAC_test.cpp +++ b/cipher/MAC_test.cpp @@ -8,7 +8,7 @@ * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS @@ -19,7 +19,6 @@ * along with this program. If not, see . */ - #include #include @@ -34,15 +33,14 @@ namespace { TEST(HMacSha1Test, MAC) { Registry registry = MAC::GetRegistry(); - shared_ptr hmac( registry.CreateForMatch( NAME_SHA1_HMAC )); + shared_ptr hmac(registry.CreateForMatch(NAME_SHA1_HMAC)); ASSERT_FALSE(!hmac); // Test cases from rfc2202 // Test case 1 CipherKey key(20); byte out[20]; - for (int i = 0; i < 20; ++i) - key.data()[i] = 0x0b; + for (int i = 0; i < 20; ++i) key.data()[i] = 0x0b; hmac->setKey(key); hmac->init(); hmac->update((byte *)"Hi There", 8); @@ -59,8 +57,7 @@ TEST(HMacSha1Test, MAC) { // Test case 3 key = CipherKey(20); - for (int i = 0; i < 20; ++i) - key.data()[i] = 0xaa; + for (int i = 0; i < 20; ++i) key.data()[i] = 0xaa; hmac->setKey(key); hmac->init(); { @@ -82,6 +79,4 @@ TEST(HMacSha1Test, MAC) { ASSERT_EQ("e8e99d0f45237d786d6bbaa7965c7808bbff1a91", stringToHex(out, 20)); } - } // namespace - diff --git a/cipher/MemoryPool.cpp b/cipher/MemoryPool.cpp index 0b5e14d..ba2c63e 100644 --- a/cipher/MemoryPool.cpp +++ b/cipher/MemoryPool.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -35,34 +35,32 @@ #ifdef HAVE_VALGRIND_MEMCHECK_H #include #else -#define VALGRIND_MAKE_MEM_NOACCESS( a, b ) -#define VALGRIND_MAKE_MEM_UNDEFINED( a, b ) +#define VALGRIND_MAKE_MEM_NOACCESS(a, b) +#define VALGRIND_MAKE_MEM_UNDEFINED(a, b) #endif #include #include #ifdef WITH_OPENSSL -# include -# include +#include +#include #endif #ifdef WITH_BOTAN -# include -# include +#include +#include #endif namespace encfs { #ifdef WITH_OPENSSL -static byte *allocBlock( int size ) -{ +static byte *allocBlock(int size) { byte *block = (byte *)OPENSSL_malloc(size); return block; } -static void freeBlock( byte *block, int size ) -{ +static void freeBlock(byte *block, int size) { OPENSSL_cleanse(block, size); OPENSSL_free(block); } @@ -78,88 +76,69 @@ unsigned char cleanse_ctr = 0; static void freeBlock(byte *data, int len) { byte *p = data; size_t loop = len, ctr = cleanse_ctr; - while(loop--) - { + while (loop--) { *(p++) = (unsigned char)ctr; ctr += (17 + ((size_t)p & 0xF)); } // Try to ensure the compiler doesn't optimize away the loop. - p=(byte *)memchr(data, (unsigned char)ctr, len); - if(p) - ctr += (63 + (size_t)p); + p = (byte *)memchr(data, (unsigned char)ctr, len); + if (p) ctr += (63 + (size_t)p); cleanse_ctr = (unsigned char)ctr; delete[] data; } #endif -void MemBlock::allocate(int size) -{ +void MemBlock::allocate(int size) { rAssert(size > 0); this->data = allocBlock(size); this->size = size; } -MemBlock::~MemBlock() -{ - freeBlock(data, size); -} +MemBlock::~MemBlock() { freeBlock(data, size); } #ifdef WITH_BOTAN -SecureMem::SecureMem(int len) - : data_(new Botan::SecureVector(len)) -{ +SecureMem::SecureMem(int len) + : data_(new Botan::SecureVector(len)) { rAssert(len > 0); } -SecureMem::~SecureMem() -{ -# if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) +SecureMem::~SecureMem() { +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1, 11, 0) data_->destroy(); -# endif +#endif delete data_; } -byte* SecureMem::data() const { - return const_cast(data_->begin()); -} +byte *SecureMem::data() const { return const_cast(data_->begin()); } -int SecureMem::size() const { - return data_->size(); -} +int SecureMem::size() const { return data_->size(); } #else -SecureMem::SecureMem(int len) -{ +SecureMem::SecureMem(int len) { rAssert(len > 0); data_ = allocBlock(len); - if (data_) - { + if (data_) { size_ = len; mlock(data_, size_); - } else - { + } else { size_ = 0; } -} +} -SecureMem::~SecureMem() -{ - if (size_) - { +SecureMem::~SecureMem() { + if (size_) { freeBlock(data_, size_); munlock(data_, size_); data_ = NULL; size_ = 0; } -} +} #endif -bool operator == (const SecureMem &a, const SecureMem &b) { - return (a.size() == b.size()) && - (memcmp(a.data(), b.data(), a.size()) == 0); +bool operator==(const SecureMem &a, const SecureMem &b) { + return (a.size() == b.size()) && (memcmp(a.data(), b.data(), a.size()) == 0); } } // namespace encfs - diff --git a/cipher/MemoryPool.h b/cipher/MemoryPool.h index 8429545..c7a5db7 100644 --- a/cipher/MemoryPool.h +++ b/cipher/MemoryPool.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -26,7 +26,8 @@ #ifdef WITH_BOTAN namespace Botan { -template class SecureVector; +template +class SecureVector; } #endif @@ -44,26 +45,21 @@ namespace encfs { // memblock freed when destructed */ -struct MemBlock -{ - byte *data; - int size; +struct MemBlock { + byte *data; + int size; - MemBlock(); - ~MemBlock(); + MemBlock(); + ~MemBlock(); - void allocate(int size); + void allocate(int size); }; -inline MemBlock::MemBlock() - : data(0), size(0) -{ -} +inline MemBlock::MemBlock() : data(0), size(0) {} -class SecureMem -{ +class SecureMem { public: - byte* data() const; + byte *data() const; int size() const; explicit SecureMem(int len); @@ -79,17 +75,12 @@ class SecureMem }; #ifndef WITH_BOTAN -inline byte* SecureMem::data() const { - return data_; -} -inline int SecureMem::size() const { - return size_; -} +inline byte *SecureMem::data() const { return data_; } +inline int SecureMem::size() const { return size_; } #endif -bool operator == (const SecureMem &a, const SecureMem &b); +bool operator==(const SecureMem &a, const SecureMem &b); } // namespace encfs #endif - diff --git a/cipher/NullCiphers.cpp b/cipher/NullCiphers.cpp index b09ed4c..503365b 100644 --- a/cipher/NullCiphers.cpp +++ b/cipher/NullCiphers.cpp @@ -8,7 +8,7 @@ * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS @@ -30,25 +30,19 @@ class NullCipher : public BlockCipher { public: virtual ~NullCipher() {} - virtual int blockSize() const { - return 8; - } + virtual int blockSize() const { return 8; } - virtual bool setKey(const CipherKey &key) { + virtual bool setKey(const CipherKey &key) { return true; } + + virtual bool encrypt(const byte *iv, const byte *in, byte *out, + int numBytes) { + if (in != out) memcpy(out, in, numBytes); return true; } - virtual bool encrypt(const byte *iv, const byte *in, - byte *out, int numBytes) { - if (in != out) - memcpy(out, in, numBytes); - return true; - } - - virtual bool decrypt(const byte *iv, const byte *in, - byte *out, int numBytes) { - if (in != out) - memcpy(out, in, numBytes); + virtual bool decrypt(const byte *iv, const byte *in, byte *out, + int numBytes) { + if (in != out) memcpy(out, in, numBytes); return true; } @@ -66,8 +60,7 @@ REGISTER_CLASS(NullCipher, BlockCipher); REGISTER_CLASS(NullCipher, StreamCipher); void NullCiphers::registerCiphers() { - // Nothing required. + // Nothing required. } -} // namespace encfs - +} // namespace encfs diff --git a/cipher/NullCiphers.h b/cipher/NullCiphers.h index b810ac9..fd61947 100644 --- a/cipher/NullCiphers.h +++ b/cipher/NullCiphers.h @@ -8,7 +8,7 @@ * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS @@ -34,4 +34,3 @@ class NullCiphers { } // namespace encfs #endif - diff --git a/cipher/PBKDF.cpp b/cipher/PBKDF.cpp index 5267090..69fc650 100644 --- a/cipher/PBKDF.cpp +++ b/cipher/PBKDF.cpp @@ -4,13 +4,8 @@ namespace encfs { DEFINE_REGISTERABLE_TYPE(PBKDF) -PBKDF::PBKDF() -{ -} +PBKDF::PBKDF() {} -PBKDF::~PBKDF() -{ -} +PBKDF::~PBKDF() {} } // namespace encfs - diff --git a/cipher/PBKDF.h b/cipher/PBKDF.h index d2a00ef..7a81915 100644 --- a/cipher/PBKDF.h +++ b/cipher/PBKDF.h @@ -14,8 +14,7 @@ static const char NAME_PBKDF2_HMAC_SHA1[] = "PBKDF2_HMAC_SHA1"; static const char NAME_PBKDF2_HMAC_SHA256[] = "PBKDF2_HMAC_SHA256"; // Password Based Key Derivation Function. -class PBKDF -{ +class PBKDF { public: DECLARE_REGISTERABLE_TYPE(PBKDF); @@ -30,17 +29,17 @@ class PBKDF virtual ~PBKDF(); virtual bool makeKey(const char *password, int passwordLength, - const byte *salt, int saltLength, - int numIterations, CipherKey *outKey) = 0; + const byte *salt, int saltLength, int numIterations, + CipherKey *outKey) = 0; // Create a new key with strong randomization. - virtual CipherKey randomKey(int length) =0; + virtual CipherKey randomKey(int length) = 0; // Randomize the output. Pseudo randomization is allowed, so this may not be // used for keys or other critical values. - virtual bool pseudoRandom(byte *out, int byteLen) =0; + virtual bool pseudoRandom(byte *out, int byteLen) = 0; }; } // namespace encfs -#endif // ENCFS_PBKDF_H +#endif // ENCFS_PBKDF_H diff --git a/cipher/PBKDF_test.cpp b/cipher/PBKDF_test.cpp index 2de091a..b528be9 100644 --- a/cipher/PBKDF_test.cpp +++ b/cipher/PBKDF_test.cpp @@ -8,7 +8,7 @@ * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS @@ -19,7 +19,6 @@ * along with this program. If not, see . */ - #include #include @@ -34,23 +33,21 @@ namespace { TEST(PKCS5_PBKDF2_HMAC_SHA1, PBKDF) { Registry registry = PBKDF::GetRegistry(); - shared_ptr impl( registry.CreateForMatch(NAME_PBKDF2_HMAC_SHA1)); + shared_ptr impl(registry.CreateForMatch(NAME_PBKDF2_HMAC_SHA1)); ASSERT_FALSE(!impl); // Test cases from rfc6070 // Test case 1 { CipherKey key(20); - bool ok = impl->makeKey("password", 8, - (byte*)"salt", 4, - 1, &key); + bool ok = impl->makeKey("password", 8, (byte*)"salt", 4, 1, &key); ASSERT_TRUE(ok); ASSERT_EQ("0c60c80f961f0e71f3a9b524af6012062fe037a6", stringToHex(key)); } { CipherKey key(25); - bool ok = impl->makeKey("passwordPASSWORDpassword", 24, + bool ok = impl->makeKey("passwordPASSWORDpassword", 24, (byte*)"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, 4096, &key); ASSERT_TRUE(ok); @@ -60,9 +57,7 @@ TEST(PKCS5_PBKDF2_HMAC_SHA1, PBKDF) { { CipherKey key(16); - bool ok = impl->makeKey("pass\0word", 9, - (byte*)"sa\0lt", 5, - 4096, &key); + bool ok = impl->makeKey("pass\0word", 9, (byte*)"sa\0lt", 5, 4096, &key); ASSERT_TRUE(ok); ASSERT_EQ("56fa6aa75548099dcc37d7f03425e0c3", stringToHex(key)); } @@ -70,48 +65,45 @@ TEST(PKCS5_PBKDF2_HMAC_SHA1, PBKDF) { TEST(PKCS5_PBKDF2_HMAC_SHA256, PBKDF) { Registry registry = PBKDF::GetRegistry(); - shared_ptr impl( - registry.CreateForMatch(NAME_PBKDF2_HMAC_SHA256)); + shared_ptr impl(registry.CreateForMatch(NAME_PBKDF2_HMAC_SHA256)); ASSERT_FALSE(!impl); // Test case 1 { CipherKey key(32); - bool ok = impl->makeKey("password", 8, - (byte*)"salt", 4, - 1, &key); + bool ok = impl->makeKey("password", 8, (byte*)"salt", 4, 1, &key); ASSERT_TRUE(ok); - ASSERT_EQ("120fb6cffcf8b32c" - "43e7225256c4f837" - "a86548c92ccc3548" - "0805987cb70be17b", stringToHex(key)); + ASSERT_EQ( + "120fb6cffcf8b32c" + "43e7225256c4f837" + "a86548c92ccc3548" + "0805987cb70be17b", + stringToHex(key)); } // Test case 2 { CipherKey key(40); - bool ok = impl->makeKey("passwordPASSWORDpassword", 24, + bool ok = impl->makeKey("passwordPASSWORDpassword", 24, (byte*)"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, 4096, &key); ASSERT_TRUE(ok); - ASSERT_EQ("348c89dbcbd32b2f" - "32d814b8116e84cf" - "2b17347ebc180018" - "1c4e2a1fb8dd53e1" - "c635518c7dac47e9", - stringToHex(key)); + ASSERT_EQ( + "348c89dbcbd32b2f" + "32d814b8116e84cf" + "2b17347ebc180018" + "1c4e2a1fb8dd53e1" + "c635518c7dac47e9", + stringToHex(key)); } // Test case 3 { CipherKey key(16); - bool ok = impl->makeKey("pass\0word", 9, - (byte*)"sa\0lt", 5, - 4096, &key); + bool ok = impl->makeKey("pass\0word", 9, (byte*)"sa\0lt", 5, 4096, &key); ASSERT_TRUE(ok); ASSERT_EQ("89b69d0516f829893c696226650a8687", stringToHex(key)); } } } // namespace - diff --git a/cipher/StreamCipher.cpp b/cipher/StreamCipher.cpp index ef92dba..432cb78 100644 --- a/cipher/StreamCipher.cpp +++ b/cipher/StreamCipher.cpp @@ -4,13 +4,8 @@ namespace encfs { DEFINE_REGISTERABLE_TYPE(StreamCipher); -StreamCipher::StreamCipher() -{ -} +StreamCipher::StreamCipher() {} -StreamCipher::~StreamCipher() -{ -} +StreamCipher::~StreamCipher() {} } // namespace encfs - diff --git a/cipher/StreamCipher.h b/cipher/StreamCipher.h index c5c8055..0152327 100644 --- a/cipher/StreamCipher.h +++ b/cipher/StreamCipher.h @@ -8,7 +8,7 @@ * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS @@ -33,8 +33,7 @@ namespace encfs { static const char NAME_AES_CFB[] = "AES/CFB"; static const char NAME_BLOWFISH_CFB[] = "Blowfish/CFB"; -class StreamCipher -{ +class StreamCipher { public: DECLARE_REGISTERABLE_TYPE(StreamCipher); @@ -43,31 +42,24 @@ class StreamCipher std::string cipher; std::string mode; std::string library; - std::string toString() const { - return cipher + "/" + mode; - } + std::string toString() const { return cipher + "/" + mode; } Properties() {} Properties(Range keys, const char *cipher_, const char *mode_, - const char *library_) - : keySize(keys), - cipher(cipher_), - mode(mode_), - library(library_) { } + const char *library_) + : keySize(keys), cipher(cipher_), mode(mode_), library(library_) {} }; StreamCipher(); virtual ~StreamCipher(); - virtual bool setKey(const CipherKey& key) =0; + virtual bool setKey(const CipherKey &key) = 0; - virtual bool encrypt(const byte *ivec, const byte *in, - byte *out, int numBytes) =0; - virtual bool decrypt(const byte *ivec, const byte *in, - byte *out, int numBytes) =0; + virtual bool encrypt(const byte *ivec, const byte *in, byte *out, + int numBytes) = 0; + virtual bool decrypt(const byte *ivec, const byte *in, byte *out, + int numBytes) = 0; }; } // namespace encfs - #endif - diff --git a/cipher/botan.cpp b/cipher/botan.cpp index 177a53d..e074c67 100644 --- a/cipher/botan.cpp +++ b/cipher/botan.cpp @@ -8,7 +8,7 @@ * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS @@ -54,14 +54,11 @@ class PbkdfPkcs5Hmac : public PBKDF { public: PbkdfPkcs5Hmac(Botan::PBKDF* pbkdf) : pbkdf_(pbkdf) {} - virtual ~PbkdfPkcs5Hmac() { - delete pbkdf_; - } + virtual ~PbkdfPkcs5Hmac() { delete pbkdf_; } - virtual bool makeKey(const char *password, int passwordLength, - const byte *salt, int saltLength, - int numIterations, - CipherKey *outKey) { + virtual bool makeKey(const char* password, int passwordLength, + const byte* salt, int saltLength, int numIterations, + CipherKey* outKey) { if (pbkdf_ == NULL) { // TODO: error message return false; @@ -69,10 +66,8 @@ class PbkdfPkcs5Hmac : public PBKDF { std::string pass; pass.assign(password, passwordLength); - OctetString key = pbkdf_->derive_key(outKey->size(), - pass, - salt, saltLength, - numIterations); + OctetString key = pbkdf_->derive_key(outKey->size(), pass, salt, saltLength, + numIterations); memcpy(outKey->data(), key.begin(), outKey->size()); return true; } @@ -83,19 +78,18 @@ class PbkdfPkcs5Hmac : public PBKDF { return key; } - virtual bool pseudoRandom(byte *out, int length) { + virtual bool pseudoRandom(byte* out, int length) { rng.randomize(out, length); return true; } AutoSeeded_RNG rng; }; - + class PbkdfPkcs5HmacSha1 : public PbkdfPkcs5Hmac { public: - PbkdfPkcs5HmacSha1() - : PbkdfPkcs5Hmac( get_pbkdf("PBKDF2(SHA-1)")) { } - ~PbkdfPkcs5HmacSha1() {} + PbkdfPkcs5HmacSha1() : PbkdfPkcs5Hmac(get_pbkdf("PBKDF2(SHA-1)")) {} + ~PbkdfPkcs5HmacSha1() {} static Properties GetProperties() { Properties props; @@ -108,9 +102,8 @@ REGISTER_CLASS(PbkdfPkcs5HmacSha1, PBKDF); class PbkdfPkcs5HmacSha256 : public PbkdfPkcs5Hmac { public: - PbkdfPkcs5HmacSha256() - : PbkdfPkcs5Hmac( get_pbkdf("PBKDF2(SHA-256)")) { } - ~PbkdfPkcs5HmacSha256() {} + PbkdfPkcs5HmacSha256() : PbkdfPkcs5Hmac(get_pbkdf("PBKDF2(SHA-256)")) {} + ~PbkdfPkcs5HmacSha256() {} static Properties GetProperties() { Properties props; @@ -121,12 +114,12 @@ class PbkdfPkcs5HmacSha256 : public PbkdfPkcs5Hmac { }; REGISTER_CLASS(PbkdfPkcs5HmacSha256, PBKDF); - class BotanBlockCipher : public BlockCipher { - Keyed_Filter *encryption; // Not owned. - Keyed_Filter *decryption; // Not owned. + Keyed_Filter* encryption; // Not owned. + Keyed_Filter* decryption; // Not owned. shared_ptr encryptor; shared_ptr decryptor; + public: BotanBlockCipher() {} virtual ~BotanBlockCipher() {} @@ -147,7 +140,7 @@ class BotanBlockCipher : public BlockCipher { virtual bool encrypt(const byte* iv, const byte* in, byte* out, int size) { #ifdef HAVE_VALGRIND_MEMCHECK_H if (VALGRIND_CHECK_MEM_IS_ADDRESSABLE(in, size) != 0 || - VALGRIND_CHECK_MEM_IS_ADDRESSABLE(out, size) != 0 || + VALGRIND_CHECK_MEM_IS_ADDRESSABLE(out, size) != 0 || VALGRIND_CHECK_MEM_IS_ADDRESSABLE(iv, blockSize())) { return false; } @@ -156,9 +149,9 @@ class BotanBlockCipher : public BlockCipher { encryptor->process_msg(in, size); auto written = encryptor->read(out, size, Pipe::LAST_MESSAGE); LOG_IF(ERROR, (int)written != size) << "expected output size " << size - << ", got " << written; - LOG_IF(ERROR, encryptor->remaining() > 0) << "unread bytes in pipe: " - << encryptor->remaining(); + << ", got " << written; + LOG_IF(ERROR, encryptor->remaining() > 0) + << "unread bytes in pipe: " << encryptor->remaining(); return true; } @@ -174,9 +167,9 @@ class BotanBlockCipher : public BlockCipher { decryptor->process_msg(in, size); auto written = decryptor->read(out, size, Pipe::LAST_MESSAGE); LOG_IF(ERROR, (int)written != size) << "expected output size " << size - << ", got " << written; - LOG_IF(ERROR, decryptor->remaining() > 0) << "unread bytes in pipe: " - << decryptor->remaining(); + << ", got " << written; + LOG_IF(ERROR, decryptor->remaining() > 0) + << "unread bytes in pipe: " << decryptor->remaining(); return true; } }; @@ -192,12 +185,10 @@ class BotanAesCbc : public BotanBlockCipher { return rekey(key, ss.str()); } - virtual int blockSize() const { - return 128 >> 3; - } + virtual int blockSize() const { return 128 >> 3; } static Properties GetProperties() { - return Properties(Range(128,256,64), "AES", "CBC", "Botan"); + return Properties(Range(128, 256, 64), "AES", "CBC", "Botan"); } }; REGISTER_CLASS(BotanAesCbc, BlockCipher); @@ -213,12 +204,10 @@ class BotanAesCfb : public BotanBlockCipher { return rekey(key, ss.str()); } - virtual int blockSize() const { - return 128 >> 3; - } + virtual int blockSize() const { return 128 >> 3; } static Properties GetProperties() { - return Properties(Range(128,256,64), "AES", "CFB", "Botan"); + return Properties(Range(128, 256, 64), "AES", "CFB", "Botan"); } }; REGISTER_CLASS(BotanAesCfb, StreamCipher); @@ -230,16 +219,15 @@ class BotanBlowfishCbc : public BotanBlockCipher { virtual bool setKey(const CipherKey& key) { std::ostringstream ss; - ss << "Blowfish" << "/CBC/NoPadding"; + ss << "Blowfish" + << "/CBC/NoPadding"; return rekey(key, ss.str()); } - virtual int blockSize() const { - return 64 >> 3; - } + virtual int blockSize() const { return 64 >> 3; } static Properties GetProperties() { - return Properties(Range(128,256,32), "Blowfish", "CBC", "Botan"); + return Properties(Range(128, 256, 32), "Blowfish", "CBC", "Botan"); } }; REGISTER_CLASS(BotanBlowfishCbc, BlockCipher); @@ -251,49 +239,42 @@ class BotanBlowfishCfb : public BotanBlockCipher { virtual bool setKey(const CipherKey& key) { std::ostringstream ss; - ss << "Blowfish" << "/CFB"; + ss << "Blowfish" + << "/CFB"; return rekey(key, ss.str()); } - virtual int blockSize() const { - return 64 >> 3; - } + virtual int blockSize() const { return 64 >> 3; } static Properties GetProperties() { - return Properties(Range(128,256,32), "Blowfish", "CFB", "Botan"); + return Properties(Range(128, 256, 32), "Blowfish", "CFB", "Botan"); } }; REGISTER_CLASS(BotanBlowfishCfb, StreamCipher); - class Sha1HMac : public MAC { - MessageAuthenticationCode *mac; + MessageAuthenticationCode* mac; public: Sha1HMac() : mac(Botan::get_mac("HMAC(SHA-1)")) {} - virtual ~Sha1HMac() { - delete mac; - } + virtual ~Sha1HMac() { delete mac; } - virtual int outputSize() const { - return mac->output_length(); - } + virtual int outputSize() const { return mac->output_length(); } - virtual bool setKey(const CipherKey &key) { + virtual bool setKey(const CipherKey& key) { SymmetricKey bkey(key.data(), key.size()); mac->set_key(bkey); return true; } - virtual void init() { - } + virtual void init() {} - virtual bool update(const byte *in, int length) { + virtual bool update(const byte* in, int length) { mac->update(in, length); return true; } - virtual bool write(byte *out) { + virtual bool write(byte* out) { #ifdef HAVE_VALGRIND_MEMCHECK_H if (VALGRIND_CHECK_MEM_IS_ADDRESSABLE(out, outputSize()) != 0) { return false; @@ -336,4 +317,3 @@ void Botan_registerCiphers() { } } // namespace encfs - diff --git a/cipher/botan.h b/cipher/botan.h index b3f5eea..cb82b88 100644 --- a/cipher/botan.h +++ b/cipher/botan.h @@ -8,7 +8,7 @@ * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS @@ -33,4 +33,3 @@ extern void Botan_registerCiphers(); } // namespace encfs #endif - diff --git a/cipher/openssl.cpp b/cipher/openssl.cpp index 2cbb1ea..71f0ed6 100644 --- a/cipher/openssl.cpp +++ b/cipher/openssl.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -59,53 +59,48 @@ namespace encfs { -const int MAX_KEYLENGTH = 64; // in bytes (256 bit) +const int MAX_KEYLENGTH = 64; // in bytes (256 bit) const int MAX_IVLENGTH = 16; const int KEY_CHECKSUM_BYTES = 4; #ifndef MIN -inline int MIN(int a, int b) -{ - return (a < b) ? a : b; -} +inline int MIN(int a, int b) { return (a < b) ? a : b; } #endif - // Base for {Block,Stream}Cipher implementation. class OpenSSLCipher : public BlockCipher { public: OpenSSLCipher() { - EVP_CIPHER_CTX_init( &enc ); - EVP_CIPHER_CTX_init( &dec ); + EVP_CIPHER_CTX_init(&enc); + EVP_CIPHER_CTX_init(&dec); } virtual ~OpenSSLCipher() { - EVP_CIPHER_CTX_cleanup( &enc ); - EVP_CIPHER_CTX_cleanup( &dec ); + EVP_CIPHER_CTX_cleanup(&enc); + EVP_CIPHER_CTX_cleanup(&dec); } bool rekey(const EVP_CIPHER *cipher, const CipherKey &key) { VLOG(1) << "setting key length " << key.size(); - EVP_EncryptInit_ex( &enc, cipher, NULL, NULL, NULL); - EVP_CIPHER_CTX_set_key_length( &enc, key.size() ); - EVP_CIPHER_CTX_set_padding( &enc, 0 ); - EVP_EncryptInit_ex( &enc, NULL, NULL, key.data(), NULL); + EVP_EncryptInit_ex(&enc, cipher, NULL, NULL, NULL); + EVP_CIPHER_CTX_set_key_length(&enc, key.size()); + EVP_CIPHER_CTX_set_padding(&enc, 0); + EVP_EncryptInit_ex(&enc, NULL, NULL, key.data(), NULL); - EVP_DecryptInit_ex( &dec, cipher, NULL, NULL, NULL); - EVP_CIPHER_CTX_set_key_length( &dec, key.size() ); - EVP_CIPHER_CTX_set_padding( &dec, 0 ); - EVP_DecryptInit_ex( &dec, NULL, NULL, key.data(), NULL); + EVP_DecryptInit_ex(&dec, cipher, NULL, NULL, NULL); + EVP_CIPHER_CTX_set_key_length(&dec, key.size()); + EVP_CIPHER_CTX_set_padding(&dec, 0); + EVP_DecryptInit_ex(&dec, NULL, NULL, key.data(), NULL); return true; } static bool randomize(CipherKey *key) { - int result = RAND_bytes( key->data(), key->size() ); - if(result != 1) - { - char errStr[120]; // specs require string at least 120 bytes long.. + int result = RAND_bytes(key->data(), key->size()); + if (result != 1) { + char errStr[120]; // specs require string at least 120 bytes long.. unsigned long errVal = 0; - if((errVal = ERR_get_error()) != 0) - LOG(ERROR) << "openssl error: " << ERR_error_string( errVal, errStr ); + if ((errVal = ERR_get_error()) != 0) + LOG(ERROR) << "openssl error: " << ERR_error_string(errVal, errStr); return false; } @@ -114,20 +109,19 @@ class OpenSSLCipher : public BlockCipher { #endif return true; } - + static bool pseudoRandomize(byte *out, int length) { #ifdef HAVE_VALGRIND_MEMCHECK_H if (VALGRIND_CHECK_MEM_IS_ADDRESSABLE(out, length) != 0) { return false; } #endif - int result = RAND_pseudo_bytes( out, length ); - if(result != 1) - { - char errStr[120]; // specs require string at least 120 bytes long.. + int result = RAND_pseudo_bytes(out, length); + if (result != 1) { + char errStr[120]; // specs require string at least 120 bytes long.. unsigned long errVal = 0; - if((errVal = ERR_get_error()) != 0) - LOG(ERROR) << "openssl error: " << ERR_error_string( errVal, errStr ); + if ((errVal = ERR_get_error()) != 0) + LOG(ERROR) << "openssl error: " << ERR_error_string(errVal, errStr); return false; } @@ -141,8 +135,7 @@ class OpenSSLCipher : public BlockCipher { bool rekey(const EVP_CIPHER *cipher, int keyLength) { CipherKey key(keyLength); - if (!randomize(&key)) - return false; + if (!randomize(&key)) return false; return rekey(cipher, key); } @@ -150,13 +143,11 @@ class OpenSSLCipher : public BlockCipher { virtual int blockSize() const { int len = EVP_CIPHER_CTX_block_size(&enc); // Some versions of OpenSSL report 1 for block size os AES_XTS.. - if (len == 1) - len = EVP_CIPHER_CTX_key_length(&enc); + if (len == 1) len = EVP_CIPHER_CTX_key_length(&enc); return len; } - virtual bool encrypt(const byte *ivec, const byte *in, - byte *out, int size) { + virtual bool encrypt(const byte *ivec, const byte *in, byte *out, int size) { int dstLen = 0, tmpLen = 0; #ifdef HAVE_VALGRIND_MEMCHECK_H int ivLen = EVP_CIPHER_CTX_iv_length(&enc); @@ -169,22 +160,21 @@ class OpenSSLCipher : public BlockCipher { return false; } #endif - EVP_EncryptInit_ex( &enc, NULL, NULL, NULL, ivec); - EVP_EncryptUpdate( &enc, out, &dstLen, in, size); - EVP_EncryptFinal_ex( &enc, out+dstLen, &tmpLen ); + EVP_EncryptInit_ex(&enc, NULL, NULL, NULL, ivec); + EVP_EncryptUpdate(&enc, out, &dstLen, in, size); + EVP_EncryptFinal_ex(&enc, out + dstLen, &tmpLen); dstLen += tmpLen; if (dstLen != size) { - LOG(ERROR) << "encoding " << size - << " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; + LOG(ERROR) << "encoding " << size << " bytes, got back " << dstLen << " (" + << tmpLen << " in final_ex)"; return false; } return true; } - virtual bool decrypt(const byte *ivec, const byte *in, - byte *out, int size) { + virtual bool decrypt(const byte *ivec, const byte *in, byte *out, int size) { int dstLen = 0, tmpLen = 0; #ifdef HAVE_VALGRIND_MEMCHECK_H int ivLen = EVP_CIPHER_CTX_iv_length(&enc); @@ -197,14 +187,14 @@ class OpenSSLCipher : public BlockCipher { return false; } #endif - EVP_DecryptInit_ex( &dec, NULL, NULL, NULL, ivec); - EVP_DecryptUpdate( &dec, out, &dstLen, in, size ); - EVP_DecryptFinal_ex( &dec, out+dstLen, &tmpLen ); + EVP_DecryptInit_ex(&dec, NULL, NULL, NULL, ivec); + EVP_DecryptUpdate(&dec, out, &dstLen, in, size); + EVP_DecryptFinal_ex(&dec, out + dstLen, &tmpLen); dstLen += tmpLen; if (dstLen != size) { - LOG(ERROR) << "decoding " << size - << " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; + LOG(ERROR) << "decoding " << size << " bytes, got back " << dstLen << " (" + << tmpLen << " in final_ex)"; return false; } @@ -216,9 +206,8 @@ class OpenSSLCipher : public BlockCipher { EVP_CIPHER_CTX dec; }; - #if defined(HAVE_EVP_BF) -static Range BfKeyRange(128,256,32); +static Range BfKeyRange(128, 256, 32); class BfCbcBlockCipher : public OpenSSLCipher { public: BfCbcBlockCipher() {} @@ -263,28 +252,29 @@ class BfCfbStreamCipher : public OpenSSLCipher { REGISTER_CLASS(BfCfbStreamCipher, StreamCipher); #endif - #if defined(HAVE_EVP_AES) -static Range AesKeyRange(128,256,64); +static Range AesKeyRange(128, 256, 64); class AesCbcBlockCipher : public OpenSSLCipher { public: AesCbcBlockCipher() {} virtual ~AesCbcBlockCipher() {} - virtual bool setKey(const CipherKey& key) { + virtual bool setKey(const CipherKey &key) { const EVP_CIPHER *cipher = getCipher(key.size()); return (cipher != NULL) && rekey(cipher, key); } static const EVP_CIPHER *getCipher(int keyLength) { - switch(keyLength * 8) - { - case 128: return EVP_aes_128_cbc(); - case 192: return EVP_aes_192_cbc(); - case 256: return EVP_aes_256_cbc(); + switch (keyLength * 8) { + case 128: + return EVP_aes_128_cbc(); + case 192: + return EVP_aes_192_cbc(); + case 256: + return EVP_aes_256_cbc(); default: - LOG(INFO) << "Unsupported key length: " << keyLength; - return NULL; + LOG(INFO) << "Unsupported key length: " << keyLength; + return NULL; } } @@ -304,20 +294,22 @@ class AesCfbStreamCipher : public OpenSSLCipher { AesCfbStreamCipher() {} virtual ~AesCfbStreamCipher() {} - virtual bool setKey(const CipherKey& key) { + virtual bool setKey(const CipherKey &key) { const EVP_CIPHER *cipher = getCipher(key.size()); return (cipher != NULL) && rekey(cipher, key); } static const EVP_CIPHER *getCipher(int keyLength) { - switch(keyLength * 8) - { - case 128: return EVP_aes_128_cfb(); - case 192: return EVP_aes_192_cfb(); - case 256: return EVP_aes_256_cfb(); + switch (keyLength * 8) { + case 128: + return EVP_aes_128_cfb(); + case 192: + return EVP_aes_192_cfb(); + case 256: + return EVP_aes_256_cfb(); default: - LOG(INFO) << "Unsupported key length: " << keyLength; - return NULL; + LOG(INFO) << "Unsupported key length: " << keyLength; + return NULL; } } @@ -334,7 +326,7 @@ REGISTER_CLASS(AesCfbStreamCipher, StreamCipher); #endif #if defined(HAVE_EVP_AES_XTS) -static Range AesXtsKeyRange(128,256,128); +static Range AesXtsKeyRange(128, 256, 128); class AesXtsBlockCipher : public OpenSSLCipher { public: AesXtsBlockCipher() {} @@ -346,11 +338,13 @@ class AesXtsBlockCipher : public OpenSSLCipher { } static const EVP_CIPHER *getCipher(int keyLength) { - switch(keyLength * 8) - { - case 128: return EVP_aes_128_xts(); - case 256: return EVP_aes_256_xts(); - default: return NULL; + switch (keyLength * 8) { + case 128: + return EVP_aes_128_xts(); + case 256: + return EVP_aes_256_xts(); + default: + return NULL; } } @@ -368,15 +362,11 @@ REGISTER_CLASS(AesXtsBlockCipher, BlockCipher); class Sha1HMac : public MAC { public: - Sha1HMac() { - HMAC_CTX_init(&ctx); - } - virtual ~Sha1HMac() { - HMAC_CTX_cleanup(&ctx); - } + Sha1HMac() { HMAC_CTX_init(&ctx); } + virtual ~Sha1HMac() { HMAC_CTX_cleanup(&ctx); } virtual int outputSize() const { - return 20; // 160 bit. + return 20; // 160 bit. } virtual bool setKey(const CipherKey &key) { @@ -384,10 +374,8 @@ class Sha1HMac : public MAC { return true; } - virtual void init() { - HMAC_Init_ex(&ctx, 0, 0, 0, 0); - } - + virtual void init() { HMAC_Init_ex(&ctx, 0, 0, 0, 0); } + virtual bool update(const byte *in, int length) { HMAC_Update(&ctx, in, length); return true; @@ -416,31 +404,28 @@ class Sha1HMac : public MAC { props.library = "OpenSSL"; return props; } + private: HMAC_CTX ctx; }; REGISTER_CLASS(Sha1HMac, MAC); - class PbkdfPkcs5HmacSha1 : public PBKDF { public: PbkdfPkcs5HmacSha1() {} virtual ~PbkdfPkcs5HmacSha1() {} virtual bool makeKey(const char *password, int passwordLength, - const byte *salt, int saltLength, - int numIterations, + const byte *salt, int saltLength, int numIterations, CipherKey *outKey) { return PKCS5_PBKDF2_HMAC_SHA1( - password, passwordLength, - const_cast(salt), saltLength, - numIterations, outKey->size(), outKey->data()) == 1; + password, passwordLength, const_cast(salt), saltLength, + numIterations, outKey->size(), outKey->data()) == 1; } virtual CipherKey randomKey(int length) { CipherKey key(length); - if (!OpenSSLCipher::randomize(&key)) - key.reset(); + if (!OpenSSLCipher::randomize(&key)) key.reset(); return key; } @@ -463,20 +448,16 @@ class PbkdfPkcs5HmacSha256 : public PBKDF { virtual ~PbkdfPkcs5HmacSha256() {} virtual bool makeKey(const char *password, int passwordLength, - const byte *salt, int saltLength, - int numIterations, + const byte *salt, int saltLength, int numIterations, CipherKey *outKey) { - return PKCS5_PBKDF2_HMAC( - password, passwordLength, - const_cast(salt), saltLength, - numIterations, EVP_sha256(), - outKey->size(), outKey->data()) == 1; + return PKCS5_PBKDF2_HMAC(password, passwordLength, const_cast(salt), + saltLength, numIterations, EVP_sha256(), + outKey->size(), outKey->data()) == 1; } virtual CipherKey randomKey(int length) { CipherKey key(length); - if (!OpenSSLCipher::randomize(&key)) - key.reset(); + if (!OpenSSLCipher::randomize(&key)) key.reset(); return key; } @@ -493,85 +474,70 @@ class PbkdfPkcs5HmacSha256 : public PBKDF { }; REGISTER_CLASS(PbkdfPkcs5HmacSha256, PBKDF); - -unsigned long pthreads_thread_id() -{ - return (unsigned long)pthread_self(); -} +unsigned long pthreads_thread_id() { return (unsigned long)pthread_self(); } static pthread_mutex_t *crypto_locks = NULL; -void pthreads_locking_callback( int mode, int n, - const char *caller_file, int caller_line ) -{ +void pthreads_locking_callback(int mode, int n, const char *caller_file, + int caller_line) { (void)caller_file; (void)caller_line; - if(!crypto_locks) - { + if (!crypto_locks) { VLOG(1) << "Allocating " << CRYPTO_num_locks() << " locks for OpenSSL"; - crypto_locks = new pthread_mutex_t[ CRYPTO_num_locks() ]; - for(int i=0; i @@ -28,7 +29,8 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$OpenBSD: readpassphrase.c,v 1.12 2001/12/15 05:41:00 millert Exp $"; +static const char rcsid[] = + "$OpenBSD: readpassphrase.c,v 1.12 2001/12/15 05:41:00 millert Exp $"; #endif /* LIBC_SCCS and not lint */ //#include "includes.h" @@ -50,134 +52,126 @@ static const char rcsid[] = "$OpenBSD: readpassphrase.c,v 1.12 2001/12/15 05:41: #include "cipher/readpassphrase.h" #ifdef TCSASOFT -# define _T_FLUSH (TCSAFLUSH|TCSASOFT) +#define _T_FLUSH (TCSAFLUSH | TCSASOFT) #else -# define _T_FLUSH (TCSAFLUSH) +#define _T_FLUSH (TCSAFLUSH) #endif /* SunOS 4.x which lacks _POSIX_VDISABLE, but has VDISABLE */ #if !defined(_POSIX_VDISABLE) && defined(VDISABLE) -# define _POSIX_VDISABLE VDISABLE +#define _POSIX_VDISABLE VDISABLE #endif static volatile sig_atomic_t signo; static void handler(int); -char * -readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) -{ - ssize_t nr; - int input, output, save_errno; - char ch, *p, *end; - struct termios term, oterm; - struct sigaction sa, saveint, savehup, savequit, saveterm; - struct sigaction savetstp, savettin, savettou; +char *readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) { + ssize_t nr; + int input, output, save_errno; + char ch, *p, *end; + struct termios term, oterm; + struct sigaction sa, saveint, savehup, savequit, saveterm; + struct sigaction savetstp, savettin, savettou; - /* I suppose we could alloc on demand in this case (XXX). */ - if (bufsiz == 0) { - errno = EINVAL; - return(NULL); - } + /* I suppose we could alloc on demand in this case (XXX). */ + if (bufsiz == 0) { + errno = EINVAL; + return (NULL); + } restart: - /* - * Read and write to /dev/tty if available. If not, read from - * stdin and write to stderr unless a tty is required. - */ - if ((input = output = open(_PATH_TTY, O_RDWR)) == -1) { - if (flags & RPP_REQUIRE_TTY) { - errno = ENOTTY; - return(NULL); - } - input = STDIN_FILENO; - output = STDERR_FILENO; - } + /* + * Read and write to /dev/tty if available. If not, read from + * stdin and write to stderr unless a tty is required. + */ + if ((input = output = open(_PATH_TTY, O_RDWR)) == -1) { + if (flags & RPP_REQUIRE_TTY) { + errno = ENOTTY; + return (NULL); + } + input = STDIN_FILENO; + output = STDERR_FILENO; + } - /* - * Catch signals that would otherwise cause the user to end - * up with echo turned off in the shell. Don't worry about - * things like SIGALRM and SIGPIPE for now. - */ - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; /* don't restart system calls */ - sa.sa_handler = handler; - (void)sigaction(SIGINT, &sa, &saveint); - (void)sigaction(SIGHUP, &sa, &savehup); - (void)sigaction(SIGQUIT, &sa, &savequit); - (void)sigaction(SIGTERM, &sa, &saveterm); - (void)sigaction(SIGTSTP, &sa, &savetstp); - (void)sigaction(SIGTTIN, &sa, &savettin); - (void)sigaction(SIGTTOU, &sa, &savettou); + /* + * Catch signals that would otherwise cause the user to end + * up with echo turned off in the shell. Don't worry about + * things like SIGALRM and SIGPIPE for now. + */ + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; /* don't restart system calls */ + sa.sa_handler = handler; + (void)sigaction(SIGINT, &sa, &saveint); + (void)sigaction(SIGHUP, &sa, &savehup); + (void)sigaction(SIGQUIT, &sa, &savequit); + (void)sigaction(SIGTERM, &sa, &saveterm); + (void)sigaction(SIGTSTP, &sa, &savetstp); + (void)sigaction(SIGTTIN, &sa, &savettin); + (void)sigaction(SIGTTOU, &sa, &savettou); - /* Turn off echo if possible. */ - if (tcgetattr(input, &oterm) == 0) { - memcpy(&term, &oterm, sizeof(term)); - if (!(flags & RPP_ECHO_ON)) - term.c_lflag &= ~(ECHO | ECHONL); + /* Turn off echo if possible. */ + if (tcgetattr(input, &oterm) == 0) { + memcpy(&term, &oterm, sizeof(term)); + if (!(flags & RPP_ECHO_ON)) term.c_lflag &= ~(ECHO | ECHONL); #ifdef VSTATUS - if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) - term.c_cc[VSTATUS] = _POSIX_VDISABLE; + if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) + term.c_cc[VSTATUS] = _POSIX_VDISABLE; #endif - (void)tcsetattr(input, _T_FLUSH, &term); - } else { - memset(&term, 0, sizeof(term)); - memset(&oterm, 0, sizeof(oterm)); - } + (void)tcsetattr(input, _T_FLUSH, &term); + } else { + memset(&term, 0, sizeof(term)); + memset(&oterm, 0, sizeof(oterm)); + } - (void)write(output, prompt, strlen(prompt)); - end = buf + bufsiz - 1; - for (p = buf; (nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r';) { - if (p < end) { - if ((flags & RPP_SEVENBIT)) - ch &= 0x7f; - if (isalpha(ch)) { - if ((flags & RPP_FORCELOWER)) - ch = tolower(ch); - if ((flags & RPP_FORCEUPPER)) - ch = toupper(ch); - } - *p++ = ch; - } - } - *p = '\0'; - save_errno = errno; - if (!(term.c_lflag & ECHO)) - (void)write(output, "\n", 1); + (void)write(output, prompt, strlen(prompt)); + end = buf + bufsiz - 1; + for (p = buf; (nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r';) { + if (p < end) { + if ((flags & RPP_SEVENBIT)) ch &= 0x7f; + if (isalpha(ch)) { + if ((flags & RPP_FORCELOWER)) ch = tolower(ch); + if ((flags & RPP_FORCEUPPER)) ch = toupper(ch); + } + *p++ = ch; + } + } + *p = '\0'; + save_errno = errno; + if (!(term.c_lflag & ECHO)) (void)write(output, "\n", 1); - /* Restore old terminal settings and signals. */ - if (memcmp(&term, &oterm, sizeof(term)) != 0) - (void)tcsetattr(input, _T_FLUSH, &oterm); - (void)sigaction(SIGINT, &saveint, NULL); - (void)sigaction(SIGHUP, &savehup, NULL); - (void)sigaction(SIGQUIT, &savequit, NULL); - (void)sigaction(SIGTERM, &saveterm, NULL); - (void)sigaction(SIGTSTP, &savetstp, NULL); - (void)sigaction(SIGTTIN, &savettin, NULL); - (void)sigaction(SIGTTOU, &savettou, NULL); - if (input != STDIN_FILENO) - (void)close(input); + /* Restore old terminal settings and signals. */ + if (memcmp(&term, &oterm, sizeof(term)) != 0) + (void)tcsetattr(input, _T_FLUSH, &oterm); + (void)sigaction(SIGINT, &saveint, NULL); + (void)sigaction(SIGHUP, &savehup, NULL); + (void)sigaction(SIGQUIT, &savequit, NULL); + (void)sigaction(SIGTERM, &saveterm, NULL); + (void)sigaction(SIGTSTP, &savetstp, NULL); + (void)sigaction(SIGTTIN, &savettin, NULL); + (void)sigaction(SIGTTOU, &savettou, NULL); + if (input != STDIN_FILENO) (void)close(input); - /* - * If we were interrupted by a signal, resend it to ourselves - * now that we have restored the signal handlers. - */ - if (signo) { - kill(getpid(), signo); - switch (signo) { - case SIGTSTP: - case SIGTTIN: - case SIGTTOU: - signo = 0; - goto restart; - } - } + /* + * If we were interrupted by a signal, resend it to ourselves + * now that we have restored the signal handlers. + */ + if (signo) { + kill(getpid(), signo); + switch (signo) { + case SIGTSTP: + case SIGTTIN: + case SIGTTOU: + signo = 0; + goto restart; + } + } - errno = save_errno; - return(nr == -1 ? NULL : buf); + errno = save_errno; + return (nr == -1 ? NULL : buf); } #endif /* HAVE_READPASSPHRASE */ - + #if 0 char * getpass(const char *prompt) @@ -188,8 +182,4 @@ getpass(const char *prompt) } #endif -static void handler(int s) -{ - - signo = s; -} +static void handler(int s) { signo = s; } diff --git a/cipher/readpassphrase.h b/cipher/readpassphrase.h index e17db34..eed8674 100644 --- a/cipher/readpassphrase.h +++ b/cipher/readpassphrase.h @@ -1,4 +1,5 @@ -/* $OpenBSD: readpassphrase.h,v 1.1 2000/11/21 00:48:38 millert Exp $ */ +/* $OpenBSD: readpassphrase.h,v 1.1 2000/11/21 00:48:38 millert Exp $ + */ /* * Copyright (c) 2000 Todd C. Miller @@ -35,17 +36,19 @@ #ifndef HAVE_READPASSPHRASE -#define RPP_ECHO_OFF 0x00 /* Turn off echo (default). */ -#define RPP_ECHO_ON 0x01 /* Leave echo on. */ -#define RPP_REQUIRE_TTY 0x02 /* Fail if there is no tty. */ -#define RPP_FORCELOWER 0x04 /* Force input to lower case. */ -#define RPP_FORCEUPPER 0x08 /* Force input to upper case. */ -#define RPP_SEVENBIT 0x10 /* Strip the high bit from input. */ +#define RPP_ECHO_OFF 0x00 /* Turn off echo (default). */ +#define RPP_ECHO_ON 0x01 /* Leave echo on. */ +#define RPP_REQUIRE_TTY 0x02 /* Fail if there is no tty. */ +#define RPP_FORCELOWER 0x04 /* Force input to lower case. */ +#define RPP_FORCEUPPER 0x08 /* Force input to upper case. */ +#define RPP_SEVENBIT 0x10 /* Strip the high bit from input. */ #ifdef __cplusplus extern "C" #endif -char *readpassphrase(const char *prompt, char *buf, size_t bufSize, int flags); + char * + readpassphrase(const char *prompt, char *buf, size_t bufSize, + int flags); #endif /* HAVE_READPASSPHRASE */ diff --git a/cipher/testing.cpp b/cipher/testing.cpp index 1ed5649..c82e745 100644 --- a/cipher/testing.cpp +++ b/cipher/testing.cpp @@ -35,7 +35,7 @@ void setDataFromHex(byte *out, int len, const char *hex) { unsigned int last = 0; while (len > 0 && *hex != '\0') { byte nibble = *hex++; - if (nibble >= '0' && nibble <= '9') + if (nibble >= '0' && nibble <= '9') nibble -= '0'; else if (nibble >= 'A' && nibble <= 'F') nibble -= 'A' - 10; @@ -64,4 +64,3 @@ int main(int argc, char **argv) { } } // namespace encfs - diff --git a/cipher/testing.h b/cipher/testing.h index 484e36b..4c8eade 100644 --- a/cipher/testing.h +++ b/cipher/testing.h @@ -8,7 +8,7 @@ * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS @@ -31,7 +31,7 @@ namespace encfs { std::string stringToHex(const byte *data, int len); template -std::string stringToHex(const T& value) { +std::string stringToHex(const T &value) { return stringToHex(value.data(), value.size()); } @@ -40,4 +40,3 @@ void setDataFromHex(byte *out, int size, const char *hex); } // namespace encfs #endif - diff --git a/encfs/main.cpp b/encfs/main.cpp index 8a071ef..90c7783 100644 --- a/encfs/main.cpp +++ b/encfs/main.cpp @@ -54,10 +54,7 @@ extern "C" void fuse_unmount_compat22(const char *mountpoint); #define fuse_unmount fuse_unmount_compat22 #ifndef MAX -inline static int MAX(int a, int b) -{ - return (a > b) ? a : b; -} +inline static int MAX(int a, int b) { return (a > b) ? a : b; } #endif using namespace encfs; @@ -72,13 +69,12 @@ namespace encfs { // Maximum number of arguments that we're going to pass on to fuse. Doesn't // affect how many arguments we can handle, just how many we can pass on.. const int MaxFuseArgs = 32; -struct EncFS_Args -{ - string mountPoint; // where to make filesystem visible - bool isDaemon; // true == spawn in background, log to syslog - bool isThreaded; // true == threaded - bool isVerbose; // false == only enable warning/error messages - int idleTimeout; // 0 == idle time in minutes to trigger unmount +struct EncFS_Args { + string mountPoint; // where to make filesystem visible + bool isDaemon; // true == spawn in background, log to syslog + bool isThreaded; // true == threaded + bool isVerbose; // false == only enable warning/error messages + int idleTimeout; // 0 == idle time in minutes to trigger unmount const char *fuseArgv[MaxFuseArgs]; int fuseArgc; @@ -88,103 +84,98 @@ struct EncFS_Args // In case someone sends me a log dump, I want to know how what options are // in effect. Not internationalized, since it is something that is mostly // useful for me! - string toString() - { + string toString() { ostringstream ss; ss << (isDaemon ? "(daemon) " : "(fg) "); ss << (isThreaded ? "(threaded) " : "(UP) "); - if(idleTimeout > 0) - ss << "(timeout " << idleTimeout << ") "; - if(opts->checkKey) ss << "(keyCheck) "; - if(opts->forceDecode) ss << "(forceDecode) "; - if(opts->ownerCreate) ss << "(ownerCreate) "; - if(opts->useStdin) ss << "(useStdin) "; - if(opts->annotate) ss << "(annotate) "; - if(opts->reverseEncryption) ss << "(reverseEncryption) "; - if(opts->mountOnDemand) ss << "(mountOnDemand) "; - if(opts->delayMount) ss << "(delayMount) "; - for(int i=0; i 0) ss << "(timeout " << idleTimeout << ") "; + if (opts->checkKey) ss << "(keyCheck) "; + if (opts->forceDecode) ss << "(forceDecode) "; + if (opts->ownerCreate) ss << "(ownerCreate) "; + if (opts->useStdin) ss << "(useStdin) "; + if (opts->annotate) ss << "(annotate) "; + if (opts->reverseEncryption) ss << "(reverseEncryption) "; + if (opts->mountOnDemand) ss << "(mountOnDemand) "; + if (opts->delayMount) ss << "(delayMount) "; + for (int i = 0; i < fuseArgc; ++i) ss << fuseArgv[i] << ' '; return ss.str(); } - EncFS_Args() - : opts( new EncFS_Opts() ) - { - } + EncFS_Args() : opts(new EncFS_Opts()) {} }; static int oldStderr = STDERR_FILENO; } // namespace encfs -static -void usage(const char *name) -{ +static void usage(const char *name) { // xgroup(usage) - cerr << autosprintf( _("Build: encfs version %s"), VERSION ) - << "\n\n" - // xgroup(usage) - << autosprintf(_("Usage: %s [options] rootDir mountPoint [-- [FUSE Mount Options]]"), name) << "\n\n" - // xgroup(usage) - << _("Common Options:\n" - " -H\t\t\t" "show optional FUSE Mount Options\n" - " -s\t\t\t" "disable multithreaded operation\n" - " -f\t\t\t" "run in foreground (don't spawn daemon).\n" - "\t\t\tError messages will be sent to stderr\n" - "\t\t\tinstead of syslog.\n") + cerr << autosprintf(_("Build: encfs version %s"), VERSION) << "\n\n" + // xgroup(usage) + << autosprintf(_("Usage: %s [options] rootDir mountPoint [-- [FUSE " + "Mount Options]]"), + name) << "\n\n" + // xgroup(usage) + << _("Common Options:\n" + " -H\t\t\t" + "show optional FUSE Mount Options\n" + " -s\t\t\t" + "disable multithreaded operation\n" + " -f\t\t\t" + "run in foreground (don't spawn daemon).\n" + "\t\t\tError messages will be sent to stderr\n" + "\t\t\tinstead of syslog.\n") - // xgroup(usage) - << _(" -v, --verbose\t\t" "verbose: output encfs debug messages\n" - " -i, --idle=MINUTES\t""Auto unmount after period of inactivity\n" - " --anykey\t\t" "Do not verify correct key is being used\n" - " --forcedecode\t\t" "decode data even if an error is detected\n" - "\t\t\t(for filesystems using MAC block headers)\n") - << _(" --public\t\t" "act as a typical multi-user filesystem\n" - "\t\t\t(encfs must be run as root)\n") - << _(" --reverse\t\t" "reverse encryption\n") + // xgroup(usage) + << _(" -v, --verbose\t\t" + "verbose: output encfs debug messages\n" + " -i, --idle=MINUTES\t" + "Auto unmount after period of inactivity\n" + " --anykey\t\t" + "Do not verify correct key is being used\n" + " --forcedecode\t\t" + "decode data even if an error is detected\n" + "\t\t\t(for filesystems using MAC block headers)\n") + << _(" --public\t\t" + "act as a typical multi-user filesystem\n" + "\t\t\t(encfs must be run as root)\n") << _(" --reverse\t\t" + "reverse encryption\n") - // xgroup(usage) - << _(" --extpass=program\tUse external program for password prompt\n" - "\n" - "Example, to mount at ~/crypt with raw storage in ~/.crypt :\n" - " encfs ~/.crypt ~/crypt\n" - "\n") - // xgroup(usage) - << _("For more information, see the man page encfs(1)") << "\n" - << endl; + // xgroup(usage) + << _(" --extpass=program\tUse external program for password prompt\n" + "\n" + "Example, to mount at ~/crypt with raw storage in ~/.crypt :\n" + " encfs ~/.crypt ~/crypt\n" + "\n") + // xgroup(usage) + << _("For more information, see the man page encfs(1)") << "\n" << endl; } -static -void FuseUsage() -{ +static void FuseUsage() { // xgroup(usage) cerr << _("encfs [options] rootDir mountPoint -- [FUSE Mount Options]\n" - "valid FUSE Mount Options follow:\n") << endl; + "valid FUSE Mount Options follow:\n") << endl; int argc = 2; const char *argv[] = {"...", "-h"}; - fuse_main( argc, const_cast(argv), (fuse_operations*)NULL, NULL); + fuse_main(argc, const_cast(argv), (fuse_operations *)NULL, NULL); } -#define PUSHARG(ARG) do { \ - rAssert(out->fuseArgc < MaxFuseArgs); \ - out->fuseArgv[out->fuseArgc++] = (ARG); } \ -while(0) +#define PUSHARG(ARG) \ + do { \ + rAssert(out->fuseArgc < MaxFuseArgs); \ + out->fuseArgv[out->fuseArgc++] = (ARG); \ + } while (0) -static -string slashTerminate( const string &src ) -{ +static string slashTerminate(const string &src) { string result = src; - if( result[ result.length()-1 ] != '/' ) - result.append( "/" ); + if (result[result.length() - 1] != '/') result.append("/"); return result; } -static -bool processArgs(int argc, char *argv[], const shared_ptr &out) -{ +static bool processArgs(int argc, char *argv[], + const shared_ptr &out) { // set defaults out->isDaemon = true; out->isThreaded = true; @@ -212,30 +203,28 @@ bool processArgs(int argc, char *argv[], const shared_ptr &out) // TODO: can flags be internationalized? static struct option long_options[] = { - {"fuse-debug", 0, 0, 'd'}, // Fuse debug mode - {"forcedecode", 0, 0, 'D'}, // force decode - // {"foreground", 0, 0, 'f'}, // foreground mode (no daemon) - {"fuse-help", 0, 0, 'H'}, // fuse_mount usage - {"idle", 1, 0, 'i'}, // idle timeout - {"anykey", 0, 0, 'k'}, // skip key checks - {"no-default-flags", 0, 0, 'N'}, // don't use default fuse flags - {"ondemand", 0, 0, 'm'}, // mount on-demand - {"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 - {"verbose", 0, 0, 'v'}, // verbose mode - {"version", 0, 0, 'V'}, //version - {"reverse", 0, 0, 'r'}, // reverse encryption - {"standard", 0, 0, '1'}, // standard configuration - {"paranoia", 0, 0, '2'}, // standard configuration - {0,0,0,0} - }; + {"fuse-debug", 0, 0, 'd'}, // Fuse debug mode + {"forcedecode", 0, 0, 'D'}, // force decode + // {"foreground", 0, 0, 'f'}, // foreground mode (no daemon) + {"fuse-help", 0, 0, 'H'}, // fuse_mount usage + {"idle", 1, 0, 'i'}, // idle timeout + {"anykey", 0, 0, 'k'}, // skip key checks + {"no-default-flags", 0, 0, 'N'}, // don't use default fuse flags + {"ondemand", 0, 0, 'm'}, // mount on-demand + {"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 + {"verbose", 0, 0, 'v'}, // verbose mode + {"version", 0, 0, 'V'}, // version + {"reverse", 0, 0, 'r'}, // reverse encryption + {"standard", 0, 0, '1'}, // standard configuration + {"paranoia", 0, 0, '2'}, // standard configuration + {0, 0, 0, 0}}; - while (1) - { + while (1) { int option_index = 0; // 's' : single-threaded mode @@ -246,107 +235,102 @@ bool processArgs(int argc, char *argv[], const shared_ptr &out) // 'm' : mount-on-demand // 'S' : password from stdin // 'o' : arguments meant for fuse - int res = getopt_long( argc, argv, "HsSfvVdmi:o:", - long_options, &option_index); + int res = + getopt_long(argc, argv, "HsSfvVdmi:o:", long_options, &option_index); - if(res == -1) - break; + if (res == -1) break; - switch( res ) - { - case '1': - out->opts->configMode = Config_Standard; - break; - case '2': - out->opts->configMode = Config_Paranoia; - break; - case 's': - out->isThreaded = false; - break; - case 'S': - out->opts->useStdin = true; - break; - case 513: - out->opts->annotate = true; - break; - case 'f': - out->isDaemon = false; - // this option was added in fuse 2.x - PUSHARG("-f"); - break; - case 'v': - out->isVerbose = true; - break; - case 'd': - PUSHARG("-d"); - break; - case 'i': - out->idleTimeout = strtol( optarg, (char**)NULL, 10); - out->opts->idleTracking = true; - break; - case 'k': - out->opts->checkKey = false; - break; - case 'D': - out->opts->forceDecode = true; - break; - case 'r': - out->opts->reverseEncryption = true; - break; - case 'm': - out->opts->mountOnDemand = true; - break; - case 'M': - out->opts->delayMount = true; - break; - case 'N': - useDefaultFlags = false; - break; - case 'o': - PUSHARG("-o"); - PUSHARG( optarg ); - break; - case 'p': - out->opts->passwordProgram.assign( optarg ); - break; - case 'P': - if(geteuid() != 0) - LOG(WARNING) << "option '--public' ignored for non-root user"; - else - { - out->opts->ownerCreate = true; - // add 'allow_other' option - // add 'default_permissions' option (default) + switch (res) { + case '1': + out->opts->configMode = Config_Standard; + break; + case '2': + out->opts->configMode = Config_Paranoia; + break; + case 's': + out->isThreaded = false; + break; + case 'S': + out->opts->useStdin = true; + break; + case 513: + out->opts->annotate = true; + break; + case 'f': + out->isDaemon = false; + // this option was added in fuse 2.x + PUSHARG("-f"); + break; + case 'v': + out->isVerbose = true; + break; + case 'd': + PUSHARG("-d"); + break; + case 'i': + out->idleTimeout = strtol(optarg, (char **)NULL, 10); + out->opts->idleTracking = true; + break; + case 'k': + out->opts->checkKey = false; + break; + case 'D': + out->opts->forceDecode = true; + break; + case 'r': + out->opts->reverseEncryption = true; + break; + case 'm': + out->opts->mountOnDemand = true; + break; + case 'M': + out->opts->delayMount = true; + break; + case 'N': + useDefaultFlags = false; + break; + case 'o': PUSHARG("-o"); - PUSHARG("allow_other"); - } - break; - case 'V': - // xgroup(usage) - cerr << autosprintf(_("encfs version %s"), VERSION) << endl; - exit(EXIT_SUCCESS); - break; - case 'H': - FuseUsage(); - exit(EXIT_SUCCESS); - break; - case '?': - // invalid options.. - break; - case ':': - // missing parameter for option.. - break; - default: - LOG(WARNING) << "getopt error: " << res; - break; + PUSHARG(optarg); + break; + case 'p': + out->opts->passwordProgram.assign(optarg); + break; + case 'P': + if (geteuid() != 0) + LOG(WARNING) << "option '--public' ignored for non-root user"; + else { + out->opts->ownerCreate = true; + // add 'allow_other' option + // add 'default_permissions' option (default) + PUSHARG("-o"); + PUSHARG("allow_other"); + } + break; + case 'V': + // xgroup(usage) + cerr << autosprintf(_("encfs version %s"), VERSION) << endl; + exit(EXIT_SUCCESS); + break; + case 'H': + FuseUsage(); + exit(EXIT_SUCCESS); + break; + case '?': + // invalid options.. + break; + case ':': + // missing parameter for option.. + break; + default: + LOG(WARNING) << "getopt error: " << res; + break; } } - if(!out->isThreaded) - PUSHARG("-s"); + if (!out->isThreaded) PUSHARG("-s"); - if(useDefaultFlags) - { + if (useDefaultFlags) { PUSHARG("-o"); PUSHARG("use_ino"); PUSHARG("-o"); @@ -355,24 +339,20 @@ bool processArgs(int argc, char *argv[], const shared_ptr &out) // we should have at least 2 arguments left over - the source directory and // the mount point. - if(optind+2 <= argc) - { - out->opts->rootDir = slashTerminate( argv[optind++] ); + if (optind + 2 <= argc) { + out->opts->rootDir = slashTerminate(argv[optind++]); out->mountPoint = argv[optind++]; - } else - { + } else { // no mount point specified LOG(ERROR) << "Missing one or more arguments, aborting."; return false; } // If there are still extra unparsed arguments, pass them onto FUSE.. - if(optind < argc) - { + if (optind < argc) { rAssert(out->fuseArgc < MaxFuseArgs); - while(optind < argc) - { + while (optind < argc) { rAssert(out->fuseArgc < MaxFuseArgs); out->fuseArgv[out->fuseArgc++] = argv[optind]; ++optind; @@ -380,65 +360,53 @@ bool processArgs(int argc, char *argv[], const shared_ptr &out) } // sanity check - if(out->isDaemon && - (!isAbsolutePath( out->mountPoint.c_str() ) || - !isAbsolutePath( out->opts->rootDir.c_str() ) ) - ) - { - cerr << - // xgroup(usage) - _("When specifying daemon mode, you must use absolute paths " - "(beginning with '/')") - << endl; + if (out->isDaemon && (!isAbsolutePath(out->mountPoint.c_str()) || + !isAbsolutePath(out->opts->rootDir.c_str()))) { + cerr << + // xgroup(usage) + _("When specifying daemon mode, you must use absolute paths " + "(beginning with '/')") << endl; return false; } // the raw directory may not be a subdirectory of the mount point. { - string testMountPoint = slashTerminate( out->mountPoint ); - string testRootDir = - out->opts->rootDir.substr(0, testMountPoint.length()); + string testMountPoint = slashTerminate(out->mountPoint); + string testRootDir = out->opts->rootDir.substr(0, testMountPoint.length()); - if( testMountPoint == testRootDir ) - { - cerr << - // xgroup(usage) - _("The raw directory may not be a subdirectory of the " + if (testMountPoint == testRootDir) { + cerr << + // xgroup(usage) + _("The raw directory may not be a subdirectory of the " "mount point.") << endl; return false; } } - if(out->opts->delayMount && !out->opts->mountOnDemand) - { + if (out->opts->delayMount && !out->opts->mountOnDemand) { cerr << - // xgroup(usage) - _("You must use mount-on-demand with delay-mount") - << endl; + // xgroup(usage) + _("You must use mount-on-demand with delay-mount") << endl; return false; } - if(out->opts->mountOnDemand && out->opts->passwordProgram.empty()) - { - cerr << - // xgroup(usage) - _("Must set password program when using mount-on-demand") - << endl; + if (out->opts->mountOnDemand && out->opts->passwordProgram.empty()) { + cerr << + // xgroup(usage) + _("Must set password program when using mount-on-demand") << endl; return false; } // check that the directories exist, or that we can create them.. - if(!isDirectory( out->opts->rootDir.c_str() ) && - !userAllowMkdir( out->opts->annotate? 1:0, - out->opts->rootDir.c_str() ,0700)) - { + if (!isDirectory(out->opts->rootDir.c_str()) && + !userAllowMkdir(out->opts->annotate ? 1 : 0, out->opts->rootDir.c_str(), + 0700)) { LOG(WARNING) << "Unable to locate root directory, aborting."; return false; } - if(!isDirectory( out->mountPoint.c_str() ) && - !userAllowMkdir( out->opts->annotate? 2:0, - out->mountPoint.c_str(),0700)) - { + if (!isDirectory(out->mountPoint.c_str()) && + !userAllowMkdir(out->opts->annotate ? 2 : 0, out->mountPoint.c_str(), + 0700)) { LOG(WARNING) << "Unable to locate mount point, aborting."; return false; } @@ -449,99 +417,89 @@ bool processArgs(int argc, char *argv[], const shared_ptr &out) return true; } -static void * idleMonitor(void *); +static void *idleMonitor(void *); -void *encfs_init(fuse_conn_info *conn) -{ - EncFS_Context *ctx = (EncFS_Context*)fuse_get_context()->private_data; +void *encfs_init(fuse_conn_info *conn) { + EncFS_Context *ctx = (EncFS_Context *)fuse_get_context()->private_data; // set fuse connection options conn->async_read = true; // if an idle timeout is specified, then setup a thread to monitor the // filesystem. - if(ctx->args->idleTimeout > 0) - { + if (ctx->args->idleTimeout > 0) { VLOG(1) << "starting idle monitoring thread"; ctx->running = true; - int res = pthread_create( &ctx->monitorThread, 0, idleMonitor, - (void*)ctx ); - if(res != 0) - { + int res = pthread_create(&ctx->monitorThread, 0, idleMonitor, (void *)ctx); + if (res != 0) { LOG(ERROR) << "error starting idle monitor thread, " - "res = " << res << ", errno = " << errno; + "res = " << res << ", errno = " << errno; } } - if(ctx->args->isDaemon && oldStderr >= 0) - { + if (ctx->args->isDaemon && oldStderr >= 0) { VLOG(1) << "Closing stderr"; close(oldStderr); oldStderr = -1; } - return (void*)ctx; + return (void *)ctx; } - -void encfs_destroy( void *_ctx ) -{ - EncFS_Context *ctx = (EncFS_Context*)_ctx; - if(ctx->args->idleTimeout > 0) - { + +void encfs_destroy(void *_ctx) { + EncFS_Context *ctx = (EncFS_Context *)_ctx; + if (ctx->args->idleTimeout > 0) { ctx->running = false; #ifdef CMAKE_USE_PTHREADS_INIT // wake up the thread if it is waiting.. VLOG(1) << "waking up monitoring thread"; ctx->wakeupMutex.lock(); - pthread_cond_signal( &ctx->wakeupCond ); + pthread_cond_signal(&ctx->wakeupCond); ctx->wakeupMutex.unlock(); VLOG(1) << "joining with idle monitoring thread"; - pthread_join( ctx->monitorThread , 0 ); + pthread_join(ctx->monitorThread, 0); VLOG(1) << "join done"; #endif } } -int main(int argc, char *argv[]) -{ +int main(int argc, char *argv[]) { cerr << "\n\n"; cerr << "====== WARNING ======= WARNING ======== WARNING ========\n"; cerr << "NOTE: this version of Encfs comes from SVN mainline and is\n" - "an unreleased 2.x BETA. It is known to have issues!\n"; + "an unreleased 2.x BETA. It is known to have issues!\n"; cerr << " USE AT YOUR OWN RISK!\n"; cerr << "Stable releases are available from the Encfs website, or look\n" - "for the 1.x branch in SVN for the stable 1.x series."; + "for the 1.x branch in SVN for the stable 1.x series."; cerr << "\n\n"; // log to stderr by default.. - FLAGS_logtostderr = 1; - FLAGS_minloglevel = 1; // WARNING and above. + FLAGS_logtostderr = 1; + FLAGS_minloglevel = 1; // WARNING and above. - google::InitGoogleLogging(argv[0]); + google::InitGoogleLogging(argv[0]); google::InstallFailureSignalHandler(); #ifdef LOCALEDIR - setlocale( LC_ALL, "" ); - bindtextdomain( PACKAGE, LOCALEDIR ); - textdomain( PACKAGE ); + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); #endif // anything that comes from the user should be considered tainted until // we've processed it and only allowed through what we support. - shared_ptr encfsArgs( new EncFS_Args ); - for(int i=0; ifuseArgv[i] = NULL; // libfuse expects null args.. + shared_ptr encfsArgs(new EncFS_Args); + for (int i = 0; i < MaxFuseArgs; ++i) + encfsArgs->fuseArgv[i] = NULL; // libfuse expects null args.. - if(argc == 1 || !processArgs(argc, argv, encfsArgs)) - { + if (argc == 1 || !processArgs(argc, argv, encfsArgs)) { usage(argv[0]); return EXIT_FAILURE; } - if(encfsArgs->isVerbose) - FLAGS_minloglevel = 0; + if (encfsArgs->isVerbose) FLAGS_minloglevel = 0; LOG(INFO) << "Root directory: " << encfsArgs->opts->rootDir; LOG(INFO) << "Fuse arguments: " << encfsArgs->toString(); @@ -554,7 +512,7 @@ int main(int argc, char *argv[]) encfs_oper.getattr = encfs_getattr; encfs_oper.readlink = encfs_readlink; - encfs_oper.getdir = encfs_getdir; // deprecated for readdir + encfs_oper.getdir = encfs_getdir; // deprecated for readdir encfs_oper.mknod = encfs_mknod; encfs_oper.mkdir = encfs_mkdir; encfs_oper.unlink = encfs_unlink; @@ -565,7 +523,7 @@ int main(int argc, char *argv[]) encfs_oper.chmod = encfs_chmod; encfs_oper.chown = encfs_chown; encfs_oper.truncate = encfs_truncate; - encfs_oper.utime = encfs_utime; // deprecated for utimens + encfs_oper.utime = encfs_utime; // deprecated for utimens encfs_oper.open = encfs_open; encfs_oper.read = encfs_read; encfs_oper.write = encfs_write; @@ -578,130 +536,122 @@ int main(int argc, char *argv[]) encfs_oper.getxattr = encfs_getxattr; encfs_oper.listxattr = encfs_listxattr; encfs_oper.removexattr = encfs_removexattr; -#endif // HAVE_XATTR - //encfs_oper.opendir = encfs_opendir; - //encfs_oper.readdir = encfs_readdir; - //encfs_oper.releasedir = encfs_releasedir; - //encfs_oper.fsyncdir = encfs_fsyncdir; +#endif // HAVE_XATTR + // encfs_oper.opendir = encfs_opendir; + // encfs_oper.readdir = encfs_readdir; + // encfs_oper.releasedir = encfs_releasedir; + // encfs_oper.fsyncdir = encfs_fsyncdir; encfs_oper.init = encfs_init; encfs_oper.destroy = encfs_destroy; - //encfs_oper.access = encfs_access; - //encfs_oper.create = encfs_create; + // encfs_oper.access = encfs_access; + // encfs_oper.create = encfs_create; encfs_oper.ftruncate = encfs_ftruncate; encfs_oper.fgetattr = encfs_fgetattr; - //encfs_oper.lock = encfs_lock; + // encfs_oper.lock = encfs_lock; encfs_oper.utimens = encfs_utimens; - //encfs_oper.bmap = encfs_bmap; +// encfs_oper.bmap = encfs_bmap; #if (__FreeBSD__ >= 10) - // encfs_oper.setvolname - // encfs_oper.exchange - // encfs_oper.getxtimes - // encfs_oper.setbkuptime - // encfs_oper.setchgtime - // encfs_oper.setcrtime - // encfs_oper.chflags - // encfs_oper.setattr_x - // encfs_oper.fsetattr_x +// encfs_oper.setvolname +// encfs_oper.exchange +// encfs_oper.getxtimes +// encfs_oper.setbkuptime +// encfs_oper.setchgtime +// encfs_oper.setcrtime +// encfs_oper.chflags +// encfs_oper.setattr_x +// encfs_oper.fsetattr_x #endif - CipherV1::init( encfsArgs->isThreaded ); + CipherV1::init(encfsArgs->isThreaded); // context is not a smart pointer because it will live for the life of // the filesystem. EncFS_Context *ctx = new EncFS_Context; ctx->publicFilesystem = encfsArgs->opts->ownerCreate; - RootPtr rootInfo = initFS( ctx, encfsArgs->opts ); + RootPtr rootInfo = initFS(ctx, encfsArgs->opts); int returnCode = EXIT_FAILURE; - if( rootInfo ) - { + if (rootInfo) { // turn off delayMount, as our prior call to initFS has already // respected any delay, and we want future calls to actually mount. encfsArgs->opts->delayMount = false; // set the globally visible root directory node - ctx->setRoot( rootInfo->root ); + ctx->setRoot(rootInfo->root); ctx->args = encfsArgs; ctx->opts = encfsArgs->opts; - if(encfsArgs->isThreaded == false && encfsArgs->idleTimeout > 0) - { + if (encfsArgs->isThreaded == false && encfsArgs->idleTimeout > 0) { // xgroup(usage) cerr << _("Note: requested single-threaded mode, but an idle\n" - "timeout was specified. The filesystem will operate\n" - "single-threaded, but threads will still be used to\n" - "implement idle checking.") << endl; + "timeout was specified. The filesystem will operate\n" + "single-threaded, but threads will still be used to\n" + "implement idle checking.") << endl; } // reset umask now, since we don't want it to interfere with the // pass-thru calls.. - umask( 0 ); + umask(0); - if(encfsArgs->isDaemon) - { + if (encfsArgs->isDaemon) { // switch to logging just warning and error messages via syslog FLAGS_minloglevel = 1; FLAGS_logtostderr = 0; // keep around a pointer just in case we end up needing it to // report a fatal condition later (fuse_main exits unexpectedly)... - oldStderr = dup( STDERR_FILENO ); + oldStderr = dup(STDERR_FILENO); } - try - { + try { time_t startTime, endTime; - if (encfsArgs->opts->annotate) - cerr << "$STATUS$ fuse_main_start" << endl; + if (encfsArgs->opts->annotate) cerr << "$STATUS$ fuse_main_start" << endl; // FIXME: workaround for fuse_main returning an error on normal // exit. Only print information if fuse_main returned // immediately.. - time( &startTime ); + time(&startTime); // fuse_main returns an error code in newer versions of fuse.. - int res = fuse_main( encfsArgs->fuseArgc, - const_cast(encfsArgs->fuseArgv), - &encfs_oper, (void*)ctx); + int res = fuse_main(encfsArgs->fuseArgc, + const_cast(encfsArgs->fuseArgv), &encfs_oper, + (void *)ctx); - time( &endTime ); + time(&endTime); - if (encfsArgs->opts->annotate) - cerr << "$STATUS$ fuse_main_end" << endl; + if (encfsArgs->opts->annotate) cerr << "$STATUS$ fuse_main_end" << endl; - if(res == 0) - returnCode = EXIT_SUCCESS; + if (res == 0) returnCode = EXIT_SUCCESS; - if(res != 0 && encfsArgs->isDaemon && (oldStderr >= 0) - && (endTime - startTime <= 1) ) - { + if (res != 0 && encfsArgs->isDaemon && (oldStderr >= 0) && + (endTime - startTime <= 1)) { // the users will not have seen any message from fuse, so say a // few words in libfuse's memory.. - FILE *out = fdopen( oldStderr, "a" ); + FILE *out = fdopen(oldStderr, "a"); // xgroup(usage) fprintf(out, _("fuse failed. Common problems:\n" - " - fuse kernel module not installed (modprobe fuse)\n" - " - invalid options -- see usage message\n")); + " - fuse kernel module not installed (modprobe fuse)\n" + " - invalid options -- see usage message\n")); fclose(out); } - } catch(std::exception &ex) - { + } + catch (std::exception &ex) { LOG(ERROR) << "Internal error: Caught exception from main loop: " - << ex.what(); - } catch(...) - { + << ex.what(); + } + catch (...) { LOG(ERROR) << "Internal error: Caught unexpected exception"; } } // cleanup so that we can check for leaked resources.. rootInfo.reset(); - ctx->setRoot( shared_ptr() ); + ctx->setRoot(shared_ptr()); - CipherV1::shutdown( encfsArgs->isThreaded ); + CipherV1::shutdown(encfsArgs->isThreaded); return returnCode; } @@ -716,10 +666,8 @@ int main(int argc, char *argv[]) const int ActivityCheckInterval = 10; static bool unmountFS(EncFS_Context *ctx); -static -void * idleMonitor(void *_arg) -{ - EncFS_Context *ctx = (EncFS_Context*)_arg; +static void *idleMonitor(void *_arg) { + EncFS_Context *ctx = (EncFS_Context *)_arg; shared_ptr arg = ctx->args; const int timeoutCycles = 60 * arg->idleTimeout / ActivityCheckInterval; @@ -727,23 +675,20 @@ void * idleMonitor(void *_arg) ctx->wakeupMutex.lock(); - while(ctx->running) - { + while (ctx->running) { int usage = ctx->getAndResetUsageCounter(); - if(usage == 0 && ctx->isMounted()) + if (usage == 0 && ctx->isMounted()) ++idleCycles; else idleCycles = 0; - if(idleCycles >= timeoutCycles) - { + if (idleCycles >= timeoutCycles) { int openCount = ctx->openFileCount(); - if( openCount == 0 && unmountFS( ctx ) ) - { + if (openCount == 0 && unmountFS(ctx)) { #ifdef CMAKE_USE_PTHREADS_INIT // wait for main thread to wake us up - pthread_cond_wait( &ctx->wakeupCond, &ctx->wakeupMutex._mutex ); + pthread_cond_wait(&ctx->wakeupCond, &ctx->wakeupMutex._mutex); #endif break; } @@ -751,17 +696,17 @@ void * idleMonitor(void *_arg) VLOG(1) << "num open files: " << openCount; } - VLOG(1) << "idle cycle count: " << idleCycles - << ", timeout after " << timeoutCycles; + VLOG(1) << "idle cycle count: " << idleCycles << ", timeout after " + << timeoutCycles; struct timeval currentTime; - gettimeofday( ¤tTime, 0 ); + gettimeofday(¤tTime, 0); struct timespec wakeupTime; wakeupTime.tv_sec = currentTime.tv_sec + ActivityCheckInterval; wakeupTime.tv_nsec = currentTime.tv_usec * 1000; #ifdef CMAKE_USE_PTHREADS_INIT - pthread_cond_timedwait( &ctx->wakeupCond, - &ctx->wakeupMutex._mutex, &wakeupTime ); + pthread_cond_timedwait(&ctx->wakeupCond, &ctx->wakeupMutex._mutex, + &wakeupTime); #endif } @@ -772,20 +717,16 @@ void * idleMonitor(void *_arg) return 0; } -static bool unmountFS(EncFS_Context *ctx) -{ +static bool unmountFS(EncFS_Context *ctx) { shared_ptr arg = ctx->args; - LOG(INFO) << "Detaching filesystem " << arg->mountPoint - << " due to inactivity"; + LOG(INFO) << "Detaching filesystem " << arg->mountPoint + << " due to inactivity"; - if( arg->opts->mountOnDemand ) - { - ctx->setRoot( shared_ptr() ); + if (arg->opts->mountOnDemand) { + ctx->setRoot(shared_ptr()); return false; - } else - { - fuse_unmount( arg->mountPoint.c_str() ); + } else { + fuse_unmount(arg->mountPoint.c_str()); return true; } } - diff --git a/fs/BlockFileIO.cpp b/fs/BlockFileIO.cpp index 5dbd178..c4f63ad 100644 --- a/fs/BlockFileIO.cpp +++ b/fs/BlockFileIO.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -30,131 +30,111 @@ namespace encfs { -template -inline Type min( Type A, Type B ) -{ +template +inline Type min(Type A, Type B) { return (B < A) ? B : A; } -static void clearCache( IORequest &req, int blockSize ) -{ - memset( req.data, 0, blockSize ); +static void clearCache(IORequest &req, int blockSize) { + memset(req.data, 0, blockSize); req.dataLen = 0; } -BlockFileIO::BlockFileIO( int blockSize, const FSConfigPtr &cfg ) - : _blockSize( blockSize ) - , _allowHoles( cfg->config->allow_holes() ) -{ - rAssert( _blockSize > 1 ); - _cache.data = new unsigned char [ _blockSize ]; +BlockFileIO::BlockFileIO(int blockSize, const FSConfigPtr &cfg) + : _blockSize(blockSize), _allowHoles(cfg->config->allow_holes()) { + rAssert(_blockSize > 1); + _cache.data = new unsigned char[_blockSize]; } -BlockFileIO::~BlockFileIO() -{ - clearCache( _cache, _blockSize ); +BlockFileIO::~BlockFileIO() { + clearCache(_cache, _blockSize); delete[] _cache.data; } -ssize_t BlockFileIO::cacheReadOneBlock( const IORequest &req ) const -{ +ssize_t BlockFileIO::cacheReadOneBlock(const IORequest &req) const { // we can satisfy the request even if _cache.dataLen is too short, because // we always request a full block during reads.. - if((req.offset == _cache.offset) && (_cache.dataLen != 0)) - { + if ((req.offset == _cache.offset) && (_cache.dataLen != 0)) { // satisfy request from cache int len = req.dataLen; - if(_cache.dataLen < len) - len = _cache.dataLen; - memcpy( req.data, _cache.data, len ); + if (_cache.dataLen < len) len = _cache.dataLen; + memcpy(req.data, _cache.data, len); return len; - } else - { - if(_cache.dataLen > 0) - clearCache( _cache, _blockSize ); + } else { + if (_cache.dataLen > 0) clearCache(_cache, _blockSize); // cache results of read -- issue reads for full blocks IORequest tmp; tmp.offset = req.offset; tmp.data = _cache.data; tmp.dataLen = _blockSize; - - ssize_t result = readOneBlock( tmp ); - if(result > 0) - { + + ssize_t result = readOneBlock(tmp); + if (result > 0) { _cache.offset = req.offset; - _cache.dataLen = result; // the amount we really have - if(result > req.dataLen) - result = req.dataLen; // only as much as requested - memcpy( req.data, _cache.data, result ); + _cache.dataLen = result; // the amount we really have + if (result > req.dataLen) + result = req.dataLen; // only as much as requested + memcpy(req.data, _cache.data, result); } return result; } } -bool BlockFileIO::cacheWriteOneBlock( const IORequest &req ) -{ +bool BlockFileIO::cacheWriteOneBlock(const IORequest &req) { // cache results of write (before pass-thru, because it may be modified // in-place) - memcpy( _cache.data, req.data, req.dataLen ); + memcpy(_cache.data, req.data, req.dataLen); _cache.offset = req.offset; _cache.dataLen = req.dataLen; - bool ok = writeOneBlock( req ); - if(!ok) - clearCache( _cache, _blockSize ); + bool ok = writeOneBlock(req); + if (!ok) clearCache(_cache, _blockSize); return ok; } -ssize_t BlockFileIO::read( const IORequest &req ) const -{ - rAssert( _blockSize != 0 ); +ssize_t BlockFileIO::read(const IORequest &req) const { + rAssert(_blockSize != 0); int partialOffset = req.offset % _blockSize; off_t blockNum = req.offset / _blockSize; ssize_t result = 0; - if(partialOffset == 0 && req.dataLen <= _blockSize) - { + if (partialOffset == 0 && req.dataLen <= _blockSize) { // read completely within a single block -- can be handled as-is by // readOneBloc(). - return cacheReadOneBlock( req ); - } else - { + return cacheReadOneBlock(req); + } else { size_t size = req.dataLen; // if the request is larger then a block, then request each block // individually - MemBlock mb; // in case we need to allocate a temporary block.. - IORequest blockReq; // for requests we may need to make + MemBlock mb; // in case we need to allocate a temporary block.. + IORequest blockReq; // for requests we may need to make blockReq.dataLen = _blockSize; blockReq.data = NULL; unsigned char *out = req.data; - while( size ) - { + while (size) { blockReq.offset = blockNum * _blockSize; // if we're reading a full block, then read directly into the // result buffer instead of using a temporary - if(partialOffset == 0 && size >= (size_t)_blockSize) + if (partialOffset == 0 && size >= (size_t)_blockSize) blockReq.data = out; - else - { - if(!mb.data) - mb.allocate( _blockSize ); + else { + if (!mb.data) mb.allocate(_blockSize); blockReq.data = mb.data; } - ssize_t readSize = cacheReadOneBlock( blockReq ); - if(readSize <= partialOffset) - break; // didn't get enough bytes + ssize_t readSize = cacheReadOneBlock(blockReq); + if (readSize <= partialOffset) break; // didn't get enough bytes - int cpySize = min( (size_t)(readSize - partialOffset), size ); + int cpySize = min((size_t)(readSize - partialOffset), size); rAssert(cpySize <= readSize); // if we read to a temporary buffer, then move the data - if(blockReq.data != out) - memcpy( out, blockReq.data + partialOffset, cpySize ); + if (blockReq.data != out) + memcpy(out, blockReq.data + partialOffset, cpySize); result += cpySize; size -= cpySize; @@ -162,17 +142,15 @@ ssize_t BlockFileIO::read( const IORequest &req ) const ++blockNum; partialOffset = 0; - if(readSize < _blockSize) - break; + if (readSize < _blockSize) break; } return result; } } -bool BlockFileIO::write( const IORequest &req ) -{ - rAssert( _blockSize != 0 ); +bool BlockFileIO::write(const IORequest &req) { + rAssert(_blockSize != 0); off_t fileSize = getSize(); @@ -185,29 +163,25 @@ bool BlockFileIO::write( const IORequest &req ) ssize_t lastBlockSize = fileSize % _blockSize; off_t lastNonEmptyBlock = lastFileBlock; - if(lastBlockSize == 0) - --lastNonEmptyBlock; + if (lastBlockSize == 0) --lastNonEmptyBlock; - if( req.offset > fileSize ) - { + if (req.offset > fileSize) { // extend file first to fill hole with 0's.. const bool forceWrite = false; - padFile( fileSize, req.offset, forceWrite ); + padFile(fileSize, req.offset, forceWrite); } // check against edge cases where we can just let the base class handle the // request as-is.. - if(partialOffset == 0 && req.dataLen <= _blockSize) - { + if (partialOffset == 0 && req.dataLen <= _blockSize) { // if writing a full block.. pretty safe.. - if( req.dataLen == _blockSize ) - return cacheWriteOneBlock( req ); + if (req.dataLen == _blockSize) return cacheWriteOneBlock(req); // if writing a partial block, but at least as much as what is // already there.. - if(blockNum == lastFileBlock && req.dataLen >= lastBlockSize) - return cacheWriteOneBlock( req ); - } + if (blockNum == lastFileBlock && req.dataLen >= lastBlockSize) + return cacheWriteOneBlock(req); + } // have to merge data with existing block(s).. MemBlock mb; @@ -219,49 +193,42 @@ bool BlockFileIO::write( const IORequest &req ) bool ok = true; size_t size = req.dataLen; unsigned char *inPtr = req.data; - while( size ) - { + while (size) { blockReq.offset = blockNum * _blockSize; int toCopy = min((size_t)(_blockSize - partialOffset), size); // if writing an entire block, or writing a partial block that requires // no merging with existing data.. - if( (toCopy == _blockSize) - ||(partialOffset == 0 && blockReq.offset + toCopy >= fileSize)) - { + if ((toCopy == _blockSize) || + (partialOffset == 0 && blockReq.offset + toCopy >= fileSize)) { // write directly from buffer blockReq.data = inPtr; blockReq.dataLen = toCopy; - } else - { + } else { // need a temporary buffer, since we have to either merge or pad // the data. - if(!mb.data) - mb.allocate( _blockSize ); - memset( mb.data, 0, _blockSize ); + if (!mb.data) mb.allocate(_blockSize); + memset(mb.data, 0, _blockSize); blockReq.data = mb.data; - if(blockNum > lastNonEmptyBlock) - { + if (blockNum > lastNonEmptyBlock) { // just pad.. blockReq.dataLen = toCopy + partialOffset; - } else - { + } else { // have to merge with existing block data.. blockReq.dataLen = _blockSize; - blockReq.dataLen = cacheReadOneBlock( blockReq ); + blockReq.dataLen = cacheReadOneBlock(blockReq); // extend data if necessary.. - if( partialOffset + toCopy > blockReq.dataLen ) + if (partialOffset + toCopy > blockReq.dataLen) blockReq.dataLen = partialOffset + toCopy; } // merge in the data to be written.. - memcpy( blockReq.data + partialOffset, inPtr, toCopy ); + memcpy(blockReq.data + partialOffset, inPtr, toCopy); } // Finally, write the damn thing! - if(!cacheWriteOneBlock( blockReq )) - { + if (!cacheWriteOneBlock(blockReq)) { ok = false; break; } @@ -276,13 +243,9 @@ bool BlockFileIO::write( const IORequest &req ) return ok; } -int BlockFileIO::blockSize() const -{ - return _blockSize; -} +int BlockFileIO::blockSize() const { return _blockSize; } -void BlockFileIO::padFile( off_t oldSize, off_t newSize, bool forceWrite ) -{ +void BlockFileIO::padFile(off_t oldSize, off_t newSize, bool forceWrite) { off_t oldLastBlock = oldSize / _blockSize; off_t newLastBlock = newSize / _blockSize; int lastBlockSize = newSize % _blockSize; @@ -290,78 +253,69 @@ void BlockFileIO::padFile( off_t oldSize, off_t newSize, bool forceWrite ) IORequest req; MemBlock mb; - if(oldLastBlock == newLastBlock) - { + if (oldLastBlock == newLastBlock) { // when the real write occurs, it will have to read in the existing // data and pad it anyway, so we won't do it here (unless we're // forced). - if( forceWrite ) - { - mb.allocate( _blockSize ); + if (forceWrite) { + mb.allocate(_blockSize); req.data = mb.data; req.offset = oldLastBlock * _blockSize; req.dataLen = oldSize % _blockSize; - int outSize = newSize % _blockSize; // outSize > req.dataLen + int outSize = newSize % _blockSize; // outSize > req.dataLen - if(outSize) - { - memset( mb.data, 0, outSize ); - cacheReadOneBlock( req ); + if (outSize) { + memset(mb.data, 0, outSize); + cacheReadOneBlock(req); req.dataLen = outSize; - cacheWriteOneBlock( req ); + cacheWriteOneBlock(req); } } else VLOG(1) << "optimization: not padding last block"; - } else - { - mb.allocate( _blockSize ); + } else { + mb.allocate(_blockSize); req.data = mb.data; // 1. extend the first block to full length // 2. write the middle empty blocks - // 3. write the last block + // 3. write the last block req.offset = oldLastBlock * _blockSize; req.dataLen = oldSize % _blockSize; // 1. req.dataLen == 0, iff oldSize was already a multiple of blocksize - if(req.dataLen != 0) - { + if (req.dataLen != 0) { VLOG(1) << "padding block " << oldLastBlock; - memset( mb.data, 0, _blockSize ); - cacheReadOneBlock( req ); - req.dataLen = _blockSize; // expand to full block size - cacheWriteOneBlock( req ); + memset(mb.data, 0, _blockSize); + cacheReadOneBlock(req); + req.dataLen = _blockSize; // expand to full block size + cacheWriteOneBlock(req); ++oldLastBlock; } // 2, pad zero blocks unless holes are allowed - if(!_allowHoles) - { - for(; oldLastBlock != newLastBlock; ++oldLastBlock) - { + if (!_allowHoles) { + for (; oldLastBlock != newLastBlock; ++oldLastBlock) { VLOG(1) << "padding block " << oldLastBlock; req.offset = oldLastBlock * _blockSize; req.dataLen = _blockSize; - memset( mb.data, 0, req.dataLen ); - cacheWriteOneBlock( req ); + memset(mb.data, 0, req.dataLen); + cacheWriteOneBlock(req); } } // 3. only necessary if write is forced and block is non 0 length - if(forceWrite && lastBlockSize) - { + if (forceWrite && lastBlockSize) { req.offset = newLastBlock * _blockSize; req.dataLen = lastBlockSize; - memset( mb.data, 0, req.dataLen ); - cacheWriteOneBlock( req ); + memset(mb.data, 0, req.dataLen); + cacheWriteOneBlock(req); } } } -int BlockFileIO::blockTruncate( off_t size, FileIO *base ) -{ +int BlockFileIO::blockTruncate(off_t size, FileIO *base) { rAssert(size >= 0); int partialBlock = size % _blockSize; @@ -369,61 +323,51 @@ int BlockFileIO::blockTruncate( off_t size, FileIO *base ) off_t oldSize = getSize(); - if( size > oldSize ) - { + if (size > oldSize) { // truncate can be used to extend a file as well. truncate man page // states that it will pad with 0's. // do the truncate so that the underlying filesystem can allocate // the space, and then we'll fill it in padFile.. - if(base) - base->truncate( size ); + if (base) base->truncate(size); const bool forceWrite = true; - padFile( oldSize, size, forceWrite ); - } else - if( size == oldSize ) - { - // the easiest case, but least likely.... - } else - if( partialBlock ) - { - // partial block after truncate. Need to read in the block being - // truncated before the truncate. Then write it back out afterwards, - // since the encoding will change.. - off_t blockNum = size / _blockSize; - MemBlock mb; - mb.allocate( _blockSize ); + padFile(oldSize, size, forceWrite); + } else if (size == oldSize) { + // the easiest case, but least likely.... + } else if (partialBlock) { + // partial block after truncate. Need to read in the block being + // truncated before the truncate. Then write it back out afterwards, + // since the encoding will change.. + off_t blockNum = size / _blockSize; + MemBlock mb; + mb.allocate(_blockSize); - IORequest req; - req.offset = blockNum * _blockSize; - req.dataLen = _blockSize; - req.data = mb.data; + IORequest req; + req.offset = blockNum * _blockSize; + req.dataLen = _blockSize; + req.data = mb.data; - ssize_t rdSz = cacheReadOneBlock( req ); + ssize_t rdSz = cacheReadOneBlock(req); - // do the truncate - if(base) - res = base->truncate( size ); + // do the truncate + if (base) res = base->truncate(size); - // write back out partial block - req.dataLen = partialBlock; - bool wrRes = cacheWriteOneBlock( req ); + // write back out partial block + req.dataLen = partialBlock; + bool wrRes = cacheWriteOneBlock(req); - if((rdSz < 0) || (!wrRes)) - { - LOG(ERROR) << "truncate failure: read size " << rdSz - << ", partial block of " << partialBlock; - } + if ((rdSz < 0) || (!wrRes)) { + LOG(ERROR) << "truncate failure: read size " << rdSz + << ", partial block of " << partialBlock; + } - } else - { - // truncating on a block bounday. No need to re-encode the last - // block.. - if(base) - res = base->truncate( size ); - } + } else { + // truncating on a block bounday. No need to re-encode the last + // block.. + if (base) res = base->truncate(size); + } - return res; + return res; } } // namespace encfs diff --git a/fs/BlockFileIO.h b/fs/BlockFileIO.h index 4cc8898..7adf3f6 100644 --- a/fs/BlockFileIO.h +++ b/fs/BlockFileIO.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -28,45 +28,42 @@ namespace encfs { /* Implements block scatter / gather interface. Requires derived classes to - implement readOneBlock() / writeOneBlock() at a minimum. + implement readOneBlock() / writeOneBlock() at a minimum. When a partial block write is requested it will be turned into a read of the existing block, merge with the write request, and a write of the full block. */ -class BlockFileIO : public FileIO -{ -public: - BlockFileIO( int blockSize, const FSConfigPtr &cfg ); - virtual ~BlockFileIO(); +class BlockFileIO : public FileIO { + public: + BlockFileIO(int blockSize, const FSConfigPtr &cfg); + virtual ~BlockFileIO(); - // implemented in terms of blocks. - virtual ssize_t read( const IORequest &req ) const; - virtual bool write( const IORequest &req ); + // implemented in terms of blocks. + virtual ssize_t read(const IORequest &req) const; + virtual bool write(const IORequest &req); - virtual int blockSize() const; + virtual int blockSize() const; -protected: + protected: + int blockTruncate(off_t size, FileIO *base); + void padFile(off_t oldSize, off_t newSize, bool forceWrite); - int blockTruncate( off_t size, FileIO *base ); - void padFile( off_t oldSize, off_t newSize, bool forceWrite ); + // same as read(), except that the request.offset field is guarenteed to be + // block aligned, and the request size will not be larger then 1 block. + virtual ssize_t readOneBlock(const IORequest &req) const = 0; + virtual bool writeOneBlock(const IORequest &req) = 0; - // same as read(), except that the request.offset field is guarenteed to be - // block aligned, and the request size will not be larger then 1 block. - virtual ssize_t readOneBlock( const IORequest &req ) const =0; - virtual bool writeOneBlock( const IORequest &req ) =0; - - ssize_t cacheReadOneBlock( const IORequest &req ) const; - bool cacheWriteOneBlock( const IORequest &req ); + ssize_t cacheReadOneBlock(const IORequest &req) const; + bool cacheWriteOneBlock(const IORequest &req); - int _blockSize; - bool _allowHoles; + int _blockSize; + bool _allowHoles; - // cache last block for speed... - mutable IORequest _cache; + // cache last block for speed... + mutable IORequest _cache; }; } // namespace encfs #endif - diff --git a/fs/BlockNameIO.cpp b/fs/BlockNameIO.cpp index 293e76f..25248a3 100644 --- a/fs/BlockNameIO.cpp +++ b/fs/BlockNameIO.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -30,33 +30,30 @@ namespace encfs { -static shared_ptr NewBlockNameIO( const Interface &iface, - const shared_ptr &cipher ) -{ - return shared_ptr( - new BlockNameIO( iface, cipher, false)); +static shared_ptr NewBlockNameIO(const Interface &iface, + const shared_ptr &cipher) { + return shared_ptr(new BlockNameIO(iface, cipher, false)); } -static shared_ptr NewBlockNameIO32( const Interface &iface, - const shared_ptr &cipher ) -{ - return shared_ptr( - new BlockNameIO( iface, cipher, true)); +static shared_ptr NewBlockNameIO32(const Interface &iface, + const shared_ptr &cipher) { + return shared_ptr(new BlockNameIO(iface, cipher, true)); } -static bool BlockIO_registered = NameIO::Register("Block", +static bool BlockIO_registered = NameIO::Register( + "Block", // description of block name encoding algorithm.. // xgroup(setup) gettext_noop("Block encoding, hides file name size somewhat"), - BlockNameIO::CurrentInterface(false), - NewBlockNameIO, false); + BlockNameIO::CurrentInterface(false), NewBlockNameIO, false); -static bool BlockIO32_registered = NameIO::Register("Block32", +static bool BlockIO32_registered = NameIO::Register( + "Block32", // description of block name encoding algorithm.. // xgroup(setup) - gettext_noop("Block encoding with base32 output for case-sensitive systems"), - BlockNameIO::CurrentInterface(true), - NewBlockNameIO32, false); + gettext_noop( + "Block encoding with base32 output for case-sensitive systems"), + BlockNameIO::CurrentInterface(true), NewBlockNameIO32, false); /* - Version 1.0 computed MAC over the filename, but not the padding bytes. @@ -75,8 +72,7 @@ static bool BlockIO32_registered = NameIO::Register("Block32", - Version 4.0 adds support for base32, creating names more suitable for case-insensitive filesystems (eg Mac). */ -Interface BlockNameIO::CurrentInterface(bool caseSensitive) -{ +Interface BlockNameIO::CurrentInterface(bool caseSensitive) { // implement major version 4 plus support for two prior versions if (caseSensitive) return makeInterface("nameio/block32", 4, 0, 2); @@ -84,172 +80,146 @@ Interface BlockNameIO::CurrentInterface(bool caseSensitive) return makeInterface("nameio/block", 4, 0, 2); } -BlockNameIO::BlockNameIO( const Interface &iface, - const shared_ptr &cipher, - bool caseSensitiveEncoding ) - : _interface( iface.major() ) - , _bs( cipher->cipherBlockSize() ) - , _cipher( cipher ) - , _caseSensitive( caseSensitiveEncoding ) -{ - rAssert( _bs < 128 ); +BlockNameIO::BlockNameIO(const Interface &iface, + const shared_ptr &cipher, + bool caseSensitiveEncoding) + : _interface(iface.major()), + _bs(cipher->cipherBlockSize()), + _cipher(cipher), + _caseSensitive(caseSensitiveEncoding) { + rAssert(_bs < 128); } -BlockNameIO::~BlockNameIO() -{ -} +BlockNameIO::~BlockNameIO() {} -Interface BlockNameIO::interface() const -{ +Interface BlockNameIO::interface() const { return CurrentInterface(_caseSensitive); } -int BlockNameIO::maxEncodedNameLen( int plaintextNameLen ) const -{ +int BlockNameIO::maxEncodedNameLen(int plaintextNameLen) const { // number of blocks, rounded up.. Only an estimate at this point, err on // the size of too much space rather then too little. - int numBlocks = ( plaintextNameLen + _bs ) / _bs; - int encodedNameLen = numBlocks * _bs + 2; // 2 checksum bytes + int numBlocks = (plaintextNameLen + _bs) / _bs; + int encodedNameLen = numBlocks * _bs + 2; // 2 checksum bytes if (_caseSensitive) - return B256ToB32Bytes( encodedNameLen ); + return B256ToB32Bytes(encodedNameLen); else - return B256ToB64Bytes( encodedNameLen ); + return B256ToB64Bytes(encodedNameLen); } -int BlockNameIO::maxDecodedNameLen( int encodedNameLen ) const -{ - int decLen256 = _caseSensitive ? - B32ToB256Bytes( encodedNameLen ) : - B64ToB256Bytes( encodedNameLen ); - return decLen256 - 2; // 2 checksum bytes removed.. +int BlockNameIO::maxDecodedNameLen(int encodedNameLen) const { + int decLen256 = _caseSensitive ? B32ToB256Bytes(encodedNameLen) + : B64ToB256Bytes(encodedNameLen); + return decLen256 - 2; // 2 checksum bytes removed.. } -int BlockNameIO::encodeName( const char *plaintextName, int length, - uint64_t *iv, char *encodedName ) const -{ +int BlockNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv, + char *encodedName) const { // copy the data into the encoding buffer.. - memcpy( encodedName+2, plaintextName, length ); + memcpy(encodedName + 2, plaintextName, length); // Pad encryption buffer to block boundary.. int padding = _bs - length % _bs; - if(padding == 0) - padding = _bs; // padding a full extra block! + if (padding == 0) padding = _bs; // padding a full extra block! - memset( encodedName+length+2, (unsigned char)padding, padding ); + memset(encodedName + length + 2, (unsigned char)padding, padding); // store the IV before it is modified by the MAC call. uint64_t tmpIV = 0; - if( iv && _interface >= 3 ) - tmpIV = *iv; + if (iv && _interface >= 3) tmpIV = *iv; // include padding in MAC computation unsigned int mac = _cipher->reduceMac16( - _cipher->MAC_64( (unsigned char *)encodedName+2, - length+padding, iv )); + _cipher->MAC_64((unsigned char *)encodedName + 2, length + padding, iv)); // add checksum bytes encodedName[0] = (mac >> 8) & 0xff; - encodedName[1] = (mac ) & 0xff; + encodedName[1] = (mac) & 0xff; - _cipher->blockEncode( (unsigned char *)encodedName+2, length+padding, - (uint64_t)mac ^ tmpIV ); + _cipher->blockEncode((unsigned char *)encodedName + 2, length + padding, + (uint64_t)mac ^ tmpIV); // convert to base 64 ascii int encodedStreamLen = length + 2 + padding; int encLen; - if (_caseSensitive) - { - encLen = B256ToB32Bytes( encodedStreamLen ); + if (_caseSensitive) { + encLen = B256ToB32Bytes(encodedStreamLen); - changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen, - 8, 5, true ); - B32ToAscii( (unsigned char *)encodedName, encLen ); - } else - { - encLen = B256ToB64Bytes( encodedStreamLen ); + changeBase2Inline((unsigned char *)encodedName, encodedStreamLen, 8, 5, + true); + B32ToAscii((unsigned char *)encodedName, encLen); + } else { + encLen = B256ToB64Bytes(encodedStreamLen); - changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen, - 8, 6, true ); - B64ToAscii( (unsigned char *)encodedName, encLen ); + changeBase2Inline((unsigned char *)encodedName, encodedStreamLen, 8, 6, + true); + B64ToAscii((unsigned char *)encodedName, encLen); } return encLen; } -int BlockNameIO::decodeName( const char *encodedName, int length, - uint64_t *iv, char *plaintextName ) const -{ - int decLen256 = _caseSensitive ? - B32ToB256Bytes( length ) : - B64ToB256Bytes( length ); +int BlockNameIO::decodeName(const char *encodedName, int length, uint64_t *iv, + char *plaintextName) const { + int decLen256 = + _caseSensitive ? B32ToB256Bytes(length) : B64ToB256Bytes(length); int decodedStreamLen = decLen256 - 2; // don't bother trying to decode files which are too small - if(decodedStreamLen < _bs) - throw Error("Filename too small to decode"); + if (decodedStreamLen < _bs) throw Error("Filename too small to decode"); - BUFFER_INIT( tmpBuf, 32, (unsigned int)length ); + BUFFER_INIT(tmpBuf, 32, (unsigned int)length); // decode into tmpBuf, - if (_caseSensitive) - { + if (_caseSensitive) { AsciiToB32((unsigned char *)tmpBuf, (unsigned char *)encodedName, length); changeBase2Inline((unsigned char *)tmpBuf, length, 5, 8, false); - } else - { + } else { AsciiToB64((unsigned char *)tmpBuf, (unsigned char *)encodedName, length); changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false); } // pull out the header information - unsigned int mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 - | ((unsigned int)((unsigned char)tmpBuf[1])); + unsigned int mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 | + ((unsigned int)((unsigned char)tmpBuf[1])); uint64_t tmpIV = 0; - if( iv && _interface >= 3 ) - tmpIV = *iv; + if (iv && _interface >= 3) tmpIV = *iv; - _cipher->blockDecode( (unsigned char *)tmpBuf+2, decodedStreamLen, - (uint64_t)mac ^ tmpIV ); + _cipher->blockDecode((unsigned char *)tmpBuf + 2, decodedStreamLen, + (uint64_t)mac ^ tmpIV); // find out true string length - int padding = (unsigned char)tmpBuf[2+decodedStreamLen-1]; + int padding = (unsigned char)tmpBuf[2 + decodedStreamLen - 1]; int finalSize = decodedStreamLen - padding; // might happen if there is an error decoding.. - if(padding > _bs || finalSize < 0) - { - VLOG(1) << "padding, _bx, finalSize = " << padding - << ", " << _bs << ", " << finalSize; - throw Error( "invalid padding size" ); + if (padding > _bs || finalSize < 0) { + VLOG(1) << "padding, _bx, finalSize = " << padding << ", " << _bs << ", " + << finalSize; + throw Error("invalid padding size"); } // copy out the result.. - memcpy(plaintextName, tmpBuf+2, finalSize); + memcpy(plaintextName, tmpBuf + 2, finalSize); plaintextName[finalSize] = '\0'; // check the mac unsigned int mac2 = _cipher->reduceMac16( - _cipher->MAC_64((const unsigned char *)tmpBuf+2, - decodedStreamLen, iv)); + _cipher->MAC_64((const unsigned char *)tmpBuf + 2, decodedStreamLen, iv)); - BUFFER_RESET( tmpBuf ); + BUFFER_RESET(tmpBuf); - if(mac2 != mac) - { - LOG(INFO) << "checksum mismatch: expected " << mac << ", got " - << mac2 << " on decode of " << finalSize << " bytes"; - throw Error( "checksum mismatch in filename decode" ); + if (mac2 != mac) { + LOG(INFO) << "checksum mismatch: expected " << mac << ", got " << mac2 + << " on decode of " << finalSize << " bytes"; + throw Error("checksum mismatch in filename decode"); } return finalSize; } -bool BlockNameIO::Enabled() -{ - return true; -} +bool BlockNameIO::Enabled() { return true; } } // namespace encfs - diff --git a/fs/BlockNameIO.h b/fs/BlockNameIO.h index bd19791..9fb61d7 100644 --- a/fs/BlockNameIO.h +++ b/fs/BlockNameIO.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -34,28 +34,27 @@ class CipherV1; mode to encode filenames. The filenames are padded to be a multiple of the cipher block size. */ -class BlockNameIO : public NameIO -{ +class BlockNameIO : public NameIO { public: static Interface CurrentInterface(bool caseSensitive = false); - BlockNameIO(const Interface &iface, - const shared_ptr &cipher, - bool caseSensitiveEncoding = false ); + BlockNameIO(const Interface &iface, const shared_ptr &cipher, + bool caseSensitiveEncoding = false); virtual ~BlockNameIO(); virtual Interface interface() const; - virtual int maxEncodedNameLen( int plaintextNameLen ) const; - virtual int maxDecodedNameLen( int encodedNameLen ) const; + virtual int maxEncodedNameLen(int plaintextNameLen) const; + virtual int maxDecodedNameLen(int encodedNameLen) const; // hack to help with static builds static bool Enabled(); + protected: - virtual int encodeName(const char *plaintextName, int length, - uint64_t *iv, char *encodedName ) const; - virtual int decodeName(const char *encodedName, int length, - uint64_t *iv, char *plaintextName ) const; + virtual int encodeName(const char *plaintextName, int length, uint64_t *iv, + char *encodedName) const; + virtual int decodeName(const char *encodedName, int length, uint64_t *iv, + char *plaintextName) const; private: int _interface; @@ -67,4 +66,3 @@ class BlockNameIO : public NameIO } // namespace encfs #endif - diff --git a/fs/CipherFileIO.cpp b/fs/CipherFileIO.cpp index 2bb4438..f567c98 100644 --- a/fs/CipherFileIO.cpp +++ b/fs/CipherFileIO.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -40,90 +40,68 @@ namespace encfs { */ static Interface CipherFileIO_iface = makeInterface("FileIO/Cipher", 3, 0, 2); -CipherFileIO::CipherFileIO( const shared_ptr &_base, - const FSConfigPtr &cfg) - : BlockFileIO( cfg->config->block_size(), cfg ) - , base( _base ) - , headerLen( 0 ) - , perFileIV( cfg->config->unique_iv() ) - , externalIV( 0 ) - , fileIV( 0 ) - , lastFlags( 0 ) -{ +CipherFileIO::CipherFileIO(const shared_ptr &_base, + const FSConfigPtr &cfg) + : BlockFileIO(cfg->config->block_size(), cfg), + base(_base), + headerLen(0), + perFileIV(cfg->config->unique_iv()), + externalIV(0), + fileIV(0), + lastFlags(0) { fsConfig = cfg; cipher = cfg->cipher; - if ( perFileIV ) - headerLen += sizeof(uint64_t); // 64bit IV per file + if (perFileIV) headerLen += sizeof(uint64_t); // 64bit IV per file - int blockBoundary = fsConfig->config->block_size() % - fsConfig->cipher->cipherBlockSize(); - if(blockBoundary != 0) - { - LOG_FIRST_N(ERROR, 1) - << "CipherFileIO: blocks should be multiple of cipher block size"; + int blockBoundary = + fsConfig->config->block_size() % fsConfig->cipher->cipherBlockSize(); + if (blockBoundary != 0) { + LOG_FIRST_N(ERROR, 1) + << "CipherFileIO: blocks should be multiple of cipher block size"; } } -CipherFileIO::~CipherFileIO() -{ -} +CipherFileIO::~CipherFileIO() {} -Interface CipherFileIO::interface() const -{ - return CipherFileIO_iface; -} +Interface CipherFileIO::interface() const { return CipherFileIO_iface; } -int CipherFileIO::open( int flags ) -{ - int res = base->open( flags ); - - if( res >= 0 ) - lastFlags = flags; +int CipherFileIO::open(int flags) { + int res = base->open(flags); + + if (res >= 0) lastFlags = flags; return res; } -void CipherFileIO::setFileName( const char *fileName ) -{ - base->setFileName( fileName ); +void CipherFileIO::setFileName(const char *fileName) { + base->setFileName(fileName); } -const char *CipherFileIO::getFileName() const -{ - return base->getFileName(); -} +const char *CipherFileIO::getFileName() const { return base->getFileName(); } -bool CipherFileIO::setIV( uint64_t iv ) -{ - VLOG(1) << "in setIV, current IV = " << externalIV - << ", new IV = " << iv << ", fileIV = " << fileIV; - if(externalIV == 0) - { +bool CipherFileIO::setIV(uint64_t iv) { + VLOG(1) << "in setIV, current IV = " << externalIV << ", new IV = " << iv + << ", fileIV = " << fileIV; + if (externalIV == 0) { // we're just being told about which IV to use. since we haven't // initialized the fileIV, there is no need to just yet.. externalIV = iv; - LOG_IF(WARNING, fileIV != 0) - << "fileIV initialized before externalIV! (" << fileIV - << ", " << externalIV << ")"; - } else if(perFileIV) - { + LOG_IF(WARNING, fileIV != 0) << "fileIV initialized before externalIV! (" + << fileIV << ", " << externalIV << ")"; + } else if (perFileIV) { // we have an old IV, and now a new IV, so we need to update the fileIV // on disk. - if(fileIV == 0) - { + if (fileIV == 0) { // ensure the file is open for read/write.. int newFlags = lastFlags | O_RDWR; - int res = base->open( newFlags ); - if(res < 0) - { - if(res == -EISDIR) - { + int res = base->open(newFlags); + if (res < 0) { + if (res == -EISDIR) { // duh -- there are no file headers for directories! externalIV = iv; - return base->setIV( iv ); - } else - { + return base->setIV(iv); + } else { VLOG(1) << "writeHeader failed to re-open for write"; return false; } @@ -133,46 +111,40 @@ bool CipherFileIO::setIV( uint64_t iv ) uint64_t oldIV = externalIV; externalIV = iv; - if(!writeHeader()) - { + if (!writeHeader()) { externalIV = oldIV; return false; } } - return base->setIV( iv ); + return base->setIV(iv); } -off_t CipherFileIO::adjustedSize(off_t rawSize) const -{ +off_t CipherFileIO::adjustedSize(off_t rawSize) const { off_t size = rawSize; - if (rawSize >= headerLen) - size -= headerLen; + if (rawSize >= headerLen) size -= headerLen; return size; } -int CipherFileIO::getAttr( struct stat *stbuf ) const -{ - int res = base->getAttr( stbuf ); +int CipherFileIO::getAttr(struct stat *stbuf) const { + int res = base->getAttr(stbuf); // adjust size if we have a file header - if((res == 0) && S_ISREG(stbuf->st_mode)) + if ((res == 0) && S_ISREG(stbuf->st_mode)) stbuf->st_size = adjustedSize(stbuf->st_size); return res; } -off_t CipherFileIO::getSize() const -{ +off_t CipherFileIO::getSize() const { // No check on S_ISREG here -- getSize only for normal files! off_t size = base->getSize(); return adjustedSize(size); } -void CipherFileIO::initHeader( ) -{ +void CipherFileIO::initHeader() { int cbs = cipher->cipherBlockSize(); MemBlock mb; @@ -181,90 +153,79 @@ void CipherFileIO::initHeader( ) // check if the file has a header, and read it if it does.. Otherwise, // create one. off_t rawSize = base->getSize(); - if(rawSize >= headerLen) - { + if (rawSize >= headerLen) { VLOG(1) << "reading existing header, rawSize = " << rawSize; IORequest req; req.offset = 0; req.data = mb.data; req.dataLen = sizeof(uint64_t); - base->read( req ); + base->read(req); - if (perFileIV) - { - cipher->streamDecode( mb.data, sizeof(uint64_t), externalIV ); + if (perFileIV) { + cipher->streamDecode(mb.data, sizeof(uint64_t), externalIV); fileIV = 0; - for(unsigned int i=0; ipseudoRandomize( mb.data, 8 )) + do { + if (!cipher->pseudoRandomize(mb.data, 8)) throw Error("Unable to generate a random file IV"); fileIV = 0; - for(unsigned int i=0; istreamEncode( mb.data, sizeof(uint64_t), externalIV ); + << "Unexpected result: randomize returned 8 null bytes!"; + } while (fileIV == 0); // don't accept 0 as an option.. - if( base->isWritable() ) - { + cipher->streamEncode(mb.data, sizeof(uint64_t), externalIV); + + if (base->isWritable()) { IORequest req; req.offset = 0; req.data = mb.data; req.dataLen = sizeof(uint64_t); - base->write( req ); + base->write(req); } else VLOG(1) << "base not writable, IV not written.."; } VLOG(1) << "initHeader finished, fileIV = " << fileIV; } -bool CipherFileIO::writeHeader( ) -{ - if( !base->isWritable() ) - { +bool CipherFileIO::writeHeader() { + if (!base->isWritable()) { // open for write.. int newFlags = lastFlags | O_RDWR; - if( base->open( newFlags ) < 0 ) - { + if (base->open(newFlags) < 0) { VLOG(1) << "writeHeader failed to re-open for write"; return false; } - } + } - LOG_IF(ERROR, fileIV == 0) - << "Internal error: fileIV == 0 in writeHeader!!!"; + LOG_IF(ERROR, fileIV == 0) << "Internal error: fileIV == 0 in writeHeader!!!"; VLOG(1) << "writing fileIV " << fileIV; MemBlock mb; mb.allocate(headerLen); - if (perFileIV) - { + if (perFileIV) { unsigned char *buf = mb.data; - for(int i=sizeof(buf)-1; i>=0; --i) - { + for (int i = sizeof(buf) - 1; i >= 0; --i) { buf[i] = (unsigned char)(fileIV & 0xff); fileIV >>= 8; } - cipher->streamEncode( buf, sizeof(uint64_t), externalIV ); + cipher->streamEncode(buf, sizeof(uint64_t), externalIV); } IORequest req; @@ -272,13 +233,12 @@ bool CipherFileIO::writeHeader( ) req.data = mb.data; req.dataLen = headerLen; - base->write( req ); + base->write(req); return true; } -ssize_t CipherFileIO::readOneBlock( const IORequest &req ) const -{ +ssize_t CipherFileIO::readOneBlock(const IORequest &req) const { // read raw data, then decipher it.. int bs = blockSize(); rAssert(req.dataLen <= bs); @@ -292,31 +252,25 @@ ssize_t CipherFileIO::readOneBlock( const IORequest &req ) const tmpReq.offset += headerLen; int maxReadSize = req.dataLen; - readSize = base->read( tmpReq ); + readSize = base->read(tmpReq); bool ok; - if(readSize > 0) - { - if(headerLen != 0 && fileIV == 0) - const_cast(this)->initHeader(); + if (readSize > 0) { + if (headerLen != 0 && fileIV == 0) + const_cast(this)->initHeader(); - if(readSize == bs) - { - ok = blockRead( tmpReq.data, bs, blockNum ^ fileIV); - } else - { - ok = streamRead( tmpReq.data, (int)readSize, blockNum ^ fileIV); + if (readSize == bs) { + ok = blockRead(tmpReq.data, bs, blockNum ^ fileIV); + } else { + ok = streamRead(tmpReq.data, (int)readSize, blockNum ^ fileIV); } - if(!ok) - { - VLOG(1) << "decodeBlock failed for block " << blockNum - << ", size " << readSize; + if (!ok) { + VLOG(1) << "decodeBlock failed for block " << blockNum << ", size " + << readSize; readSize = -1; - } else if (tmpReq.data != req.data) - { - if (readSize > maxReadSize) - readSize = maxReadSize; + } else if (tmpReq.data != req.data) { + if (readSize > maxReadSize) readSize = maxReadSize; memcpy(req.data, tmpReq.data, readSize); } } else @@ -325,38 +279,28 @@ ssize_t CipherFileIO::readOneBlock( const IORequest &req ) const return readSize; } - -bool CipherFileIO::writeOneBlock( const IORequest &req ) -{ +bool CipherFileIO::writeOneBlock(const IORequest &req) { int bs = blockSize(); off_t blockNum = req.offset / bs; - if(headerLen != 0 && fileIV == 0) - initHeader(); + if (headerLen != 0 && fileIV == 0) initHeader(); MemBlock mb; bool ok; - if (req.dataLen == bs) - { - ok = blockWrite( req.data, bs, blockNum ^ fileIV ); - } else - { - ok = streamWrite( req.data, (int)req.dataLen, - blockNum ^ fileIV ); + if (req.dataLen == bs) { + ok = blockWrite(req.data, bs, blockNum ^ fileIV); + } else { + ok = streamWrite(req.data, (int)req.dataLen, blockNum ^ fileIV); } - if( ok ) - { - if(headerLen != 0) - { + if (ok) { + if (headerLen != 0) { IORequest nreq = req; - if (mb.data == NULL) - { + if (mb.data == NULL) { nreq.offset += headerLen; - } else - { + } else { // Partial block is stored at front of file. nreq.offset = 0; nreq.data = mb.data; @@ -364,78 +308,66 @@ bool CipherFileIO::writeOneBlock( const IORequest &req ) base->truncate(req.offset + req.dataLen + headerLen); } - ok = base->write( nreq ); + ok = base->write(nreq); } else - ok = base->write( req ); - } else - { - VLOG(1) << "encodeBlock failed for block " << blockNum - << ", size " << req.dataLen; + ok = base->write(req); + } else { + VLOG(1) << "encodeBlock failed for block " << blockNum << ", size " + << req.dataLen; ok = false; } return ok; } -bool CipherFileIO::blockWrite( unsigned char *buf, int size, - uint64_t _iv64 ) const -{ +bool CipherFileIO::blockWrite(unsigned char *buf, int size, + uint64_t _iv64) const { if (!fsConfig->reverseEncryption) - return cipher->blockEncode( buf, size, _iv64 ); + return cipher->blockEncode(buf, size, _iv64); else - return cipher->blockDecode( buf, size, _iv64 ); -} + return cipher->blockDecode(buf, size, _iv64); +} -bool CipherFileIO::streamWrite( unsigned char *buf, int size, - uint64_t _iv64 ) const -{ +bool CipherFileIO::streamWrite(unsigned char *buf, int size, + uint64_t _iv64) const { if (!fsConfig->reverseEncryption) - return cipher->streamEncode( buf, size, _iv64 ); + return cipher->streamEncode(buf, size, _iv64); else - return cipher->streamDecode( buf, size, _iv64 ); -} + return cipher->streamDecode(buf, size, _iv64); +} - -bool CipherFileIO::blockRead( unsigned char *buf, int size, - uint64_t _iv64 ) const -{ +bool CipherFileIO::blockRead(unsigned char *buf, int size, + uint64_t _iv64) const { if (fsConfig->reverseEncryption) - return cipher->blockEncode( buf, size, _iv64 ); - else if(_allowHoles) - { + return cipher->blockEncode(buf, size, _iv64); + else if (_allowHoles) { // special case - leave all 0's alone - for(int i=0; iblockDecode( buf, size, _iv64 ); + for (int i = 0; i < size; ++i) + if (buf[i] != 0) return cipher->blockDecode(buf, size, _iv64); return true; } else - return cipher->blockDecode( buf, size, _iv64 ); -} + return cipher->blockDecode(buf, size, _iv64); +} -bool CipherFileIO::streamRead( unsigned char *buf, int size, - uint64_t _iv64 ) const -{ +bool CipherFileIO::streamRead(unsigned char *buf, int size, + uint64_t _iv64) const { if (fsConfig->reverseEncryption) - return cipher->streamEncode( buf, size, _iv64 ); + return cipher->streamEncode(buf, size, _iv64); else - return cipher->streamDecode( buf, size, _iv64 ); -} + return cipher->streamDecode(buf, size, _iv64); +} -int CipherFileIO::truncate( off_t size ) -{ +int CipherFileIO::truncate(off_t size) { rAssert(size >= 0); - if(headerLen == 0) - { - return blockTruncate( size, base.get() ); - } else if(0 == fileIV) - { + if (headerLen == 0) { + return blockTruncate(size, base.get()); + } else if (0 == fileIV) { // empty file.. create the header.. - if( !base->isWritable() ) - { + if (!base->isWritable()) { // open for write.. int newFlags = lastFlags | O_RDWR; - if( base->open( newFlags ) < 0 ) + if (base->open(newFlags) < 0) VLOG(1) << "writeHeader failed to re-open for write"; } initHeader(); @@ -443,17 +375,13 @@ int CipherFileIO::truncate( off_t size ) // can't let BlockFileIO call base->truncate(), since it would be using // the wrong size.. - int res = blockTruncate( size, 0 ); + int res = blockTruncate(size, 0); - if(res == 0) - base->truncate( size + headerLen ); + if (res == 0) base->truncate(size + headerLen); return res; } -bool CipherFileIO::isWritable() const -{ - return base->isWritable(); -} +bool CipherFileIO::isWritable() const { return base->isWritable(); } } // namespace encfs diff --git a/fs/CipherFileIO.h b/fs/CipherFileIO.h index 2c17f5b..f3f3bfa 100644 --- a/fs/CipherFileIO.h +++ b/fs/CipherFileIO.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -32,66 +32,60 @@ namespace encfs { class CipherV1; /* - Implement the FileIO interface encrypting data in blocks. - + Implement the FileIO interface encrypting data in blocks. + Uses BlockFileIO to handle the block scatter / gather issues. */ -class CipherFileIO : public BlockFileIO -{ -public: - CipherFileIO( const shared_ptr &base, - const FSConfigPtr &cfg); - virtual ~CipherFileIO(); +class CipherFileIO : public BlockFileIO { + public: + CipherFileIO(const shared_ptr &base, const FSConfigPtr &cfg); + virtual ~CipherFileIO(); - virtual Interface interface() const; + virtual Interface interface() const; - virtual void setFileName( const char *fileName ); - virtual const char *getFileName() const; - virtual bool setIV( uint64_t iv ); + virtual void setFileName(const char *fileName); + virtual const char *getFileName() const; + virtual bool setIV(uint64_t iv); - virtual int open( int flags ); + virtual int open(int flags); - virtual int getAttr( struct stat *stbuf ) const; - virtual off_t getSize() const; + virtual int getAttr(struct stat *stbuf) const; + virtual off_t getSize() const; - // NOTE: if truncate is used to extend the file, the extended plaintext is - // not 0. The extended ciphertext may be 0, resulting in non-zero - // plaintext. - virtual int truncate( off_t size ); + // NOTE: if truncate is used to extend the file, the extended plaintext is + // not 0. The extended ciphertext may be 0, resulting in non-zero + // plaintext. + virtual int truncate(off_t size); - virtual bool isWritable() const; + virtual bool isWritable() const; -private: - virtual ssize_t readOneBlock( const IORequest &req ) const; - virtual bool writeOneBlock( const IORequest &req ); + private: + virtual ssize_t readOneBlock(const IORequest &req) const; + virtual bool writeOneBlock(const IORequest &req); - void initHeader(); - bool writeHeader(); - bool blockRead( unsigned char *buf, int size, - uint64_t iv64 ) const; - bool streamRead( unsigned char *buf, int size, - uint64_t iv64 ) const; - bool blockWrite( unsigned char *buf, int size, - uint64_t iv64 ) const; - bool streamWrite( unsigned char *buf, int size, - uint64_t iv64 ) const; + void initHeader(); + bool writeHeader(); + bool blockRead(unsigned char *buf, int size, uint64_t iv64) const; + bool streamRead(unsigned char *buf, int size, uint64_t iv64) const; + bool blockWrite(unsigned char *buf, int size, uint64_t iv64) const; + bool streamWrite(unsigned char *buf, int size, uint64_t iv64) const; - off_t adjustedSize(off_t size) const; + off_t adjustedSize(off_t size) const; - shared_ptr base; + shared_ptr base; - FSConfigPtr fsConfig; + FSConfigPtr fsConfig; - // if haveHeader is true, then we have a transparent file header which - int headerLen; + // if haveHeader is true, then we have a transparent file header which + int headerLen; - bool perFileIV; - bool externalIVChaining; - uint64_t externalIV; - uint64_t fileIV; - int lastFlags; + bool perFileIV; + bool externalIVChaining; + uint64_t externalIV; + uint64_t fileIV; + int lastFlags; - shared_ptr cipher; + shared_ptr cipher; }; } // namespace encfs diff --git a/fs/Context.cpp b/fs/Context.cpp index a4900a0..44691f0 100644 --- a/fs/Context.cpp +++ b/fs/Context.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -27,67 +27,55 @@ namespace encfs { -EncFS_Context::EncFS_Context() -{ +EncFS_Context::EncFS_Context() { #ifdef CMAKE_USE_PTHREADS_INIT - pthread_cond_init( &wakeupCond, 0 ); + pthread_cond_init(&wakeupCond, 0); #endif usageCount = 0; } -EncFS_Context::~EncFS_Context() -{ +EncFS_Context::~EncFS_Context() { #ifdef CMAKE_USE_PTHREADS_INIT - pthread_cond_destroy( &wakeupCond ); + pthread_cond_destroy(&wakeupCond); #endif // release all entries from map openFiles.clear(); } -shared_ptr EncFS_Context::getRoot(int *errCode) -{ +shared_ptr EncFS_Context::getRoot(int *errCode) { shared_ptr ret; - do - { + do { { - Lock lock( contextMutex ); + Lock lock(contextMutex); ret = root; ++usageCount; } - if(!ret) - { - int res = remountFS( this ); - if(res != 0) - { + if (!ret) { + int res = remountFS(this); + if (res != 0) { *errCode = res; break; } } - } while(!ret); + } while (!ret); return ret; } -void EncFS_Context::setRoot(const shared_ptr &r) -{ - Lock lock( contextMutex ); +void EncFS_Context::setRoot(const shared_ptr &r) { + Lock lock(contextMutex); root = r; - if(r) - rootCipherDir = r->rootDirectory(); + if (r) rootCipherDir = r->rootDirectory(); } -bool EncFS_Context::isMounted() -{ - return root; -} +bool EncFS_Context::isMounted() { return root; } -int EncFS_Context::getAndResetUsageCounter() -{ - Lock lock( contextMutex ); +int EncFS_Context::getAndResetUsageCounter() { + Lock lock(contextMutex); int count = usageCount; usageCount = 0; @@ -95,79 +83,69 @@ int EncFS_Context::getAndResetUsageCounter() return count; } -int EncFS_Context::openFileCount() const -{ - Lock lock( contextMutex ); +int EncFS_Context::openFileCount() const { + Lock lock(contextMutex); return openFiles.size(); } -shared_ptr EncFS_Context::lookupNode(const char *path) -{ - Lock lock( contextMutex ); +shared_ptr EncFS_Context::lookupNode(const char *path) { + Lock lock(contextMutex); - FileMap::iterator it = openFiles.find( std::string(path) ); - if(it != openFiles.end()) - { + FileMap::iterator it = openFiles.find(std::string(path)); + if (it != openFiles.end()) { // all the items in the set point to the same node.. so just use the // first return (*it->second.begin())->node; - } else - { + } else { return shared_ptr(); } } -void EncFS_Context::renameNode(const char *from, const char *to) -{ - Lock lock( contextMutex ); +void EncFS_Context::renameNode(const char *from, const char *to) { + Lock lock(contextMutex); - FileMap::iterator it = openFiles.find( std::string(from) ); - if(it != openFiles.end()) - { + FileMap::iterator it = openFiles.find(std::string(from)); + if (it != openFiles.end()) { std::set val = it->second; openFiles.erase(it); - openFiles[ std::string(to) ] = val; + openFiles[std::string(to)] = val; } } -shared_ptr EncFS_Context::getNode(void *pl) -{ - Placeholder *ph = (Placeholder*)pl; +shared_ptr EncFS_Context::getNode(void *pl) { + Placeholder *ph = (Placeholder *)pl; return ph->node; } -void *EncFS_Context::putNode(const char *path, - const shared_ptr &node) -{ - Lock lock( contextMutex ); - Placeholder *pl = new Placeholder( node ); - openFiles[ std::string(path) ].insert(pl); +void *EncFS_Context::putNode(const char *path, + const shared_ptr &node) { + Lock lock(contextMutex); + Placeholder *pl = new Placeholder(node); + openFiles[std::string(path)].insert(pl); return (void *)pl; } -void EncFS_Context::eraseNode(const char *path, void *pl) -{ - Lock lock( contextMutex ); +void EncFS_Context::eraseNode(const char *path, void *pl) { + Lock lock(contextMutex); Placeholder *ph = (Placeholder *)pl; - FileMap::iterator it = openFiles.find( std::string(path) ); + FileMap::iterator it = openFiles.find(std::string(path)); rAssert(it != openFiles.end()); - int rmCount = it->second.erase( ph ); + int rmCount = it->second.erase(ph); rAssert(rmCount == 1); // if no more references to this file, remove the record all together - if(it->second.empty()) - { + if (it->second.empty()) { // attempts to make use of shallow copy to clear memory used to hold // unencrypted filenames.. not sure this does any good.. std::string storedName = it->first; - openFiles.erase( it ); - storedName.assign( storedName.length(), '\0' ); + openFiles.erase(it); + storedName.assign(storedName.length(), '\0'); } delete ph; diff --git a/fs/Context.h b/fs/Context.h index 00426c3..92ca0cc 100644 --- a/fs/Context.h +++ b/fs/Context.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -43,8 +43,7 @@ struct EncFS_Opts; class FileNode; class DirNode; -class EncFS_Context -{ +class EncFS_Context { public: EncFS_Context(); ~EncFS_Context(); @@ -91,15 +90,14 @@ class EncFS_Context * release() is called. shared_ptr then does our reference counting for * us. */ - struct Placeholder - { + struct Placeholder { shared_ptr node; - Placeholder( const shared_ptr &ptr ) : node(ptr) {} + Placeholder(const shared_ptr &ptr) : node(ptr) {} }; // set of open files, indexed by path - typedef unordered_map > FileMap; + typedef unordered_map > FileMap; #ifdef CMAKE_USE_PTHREADS_INIT mutable Mutex contextMutex; @@ -111,9 +109,8 @@ class EncFS_Context shared_ptr root; }; -int remountFS( EncFS_Context *ctx ); +int remountFS(EncFS_Context *ctx); } // namespace encfs #endif - diff --git a/fs/DirNode.cpp b/fs/DirNode.cpp index 21e5452..8b5ee16 100644 --- a/fs/DirNode.cpp +++ b/fs/DirNode.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -39,7 +39,6 @@ #include "fs/FileUtils.h" #include "fs/fsconfig.pb.h" - #include #include @@ -49,33 +48,19 @@ using std::string; namespace encfs { -class DirDeleter -{ -public: - void operator () ( DIR *d ) - { - ::closedir( d ); - } +class DirDeleter { + public: + void operator()(DIR *d) { ::closedir(d); } }; - -DirTraverse::DirTraverse(const shared_ptr &_dirPtr, - uint64_t _iv, const shared_ptr &_naming) - : dir( _dirPtr ) - , iv( _iv ) - , naming( _naming ) -{ -} +DirTraverse::DirTraverse(const shared_ptr &_dirPtr, uint64_t _iv, + const shared_ptr &_naming) + : dir(_dirPtr), iv(_iv), naming(_naming) {} DirTraverse::DirTraverse(const DirTraverse &src) - : dir( src.dir ) - , iv( src.iv ) - , naming( src.naming ) -{ -} + : dir(src.dir), iv(src.iv), naming(src.naming) {} -DirTraverse &DirTraverse::operator = (const DirTraverse &src) -{ +DirTraverse &DirTraverse::operator=(const DirTraverse &src) { dir = src.dir; iv = src.iv; naming = src.naming; @@ -83,23 +68,18 @@ DirTraverse &DirTraverse::operator = (const DirTraverse &src) return *this; } -DirTraverse::~DirTraverse() -{ +DirTraverse::~DirTraverse() { dir.reset(); iv = 0; naming.reset(); } -static -bool _nextName(struct dirent *&de, const shared_ptr &dir, - int *fileType, ino_t *inode) -{ - de = ::readdir( dir.get() ); +static bool _nextName(struct dirent *&de, const shared_ptr &dir, + int *fileType, ino_t *inode) { + de = ::readdir(dir.get()); - if(de) - { - if(fileType) - { + if (de) { + if (fileType) { #if defined(_DIRENT_HAVE_D_TYPE) || defined(__FreeBSD__) *fileType = de->d_type; #else @@ -107,63 +87,51 @@ bool _nextName(struct dirent *&de, const shared_ptr &dir, *fileType = 0; #endif } - if(inode) - *inode = de->d_ino; + if (inode) *inode = de->d_ino; return true; - } else - { - if(fileType) - *fileType = 0; + } else { + if (fileType) *fileType = 0; return false; } } - -std::string DirTraverse::nextPlaintextName(int *fileType, ino_t *inode) -{ - struct dirent *de=0; - while(_nextName(de, dir, fileType, inode)) - { - try - { +std::string DirTraverse::nextPlaintextName(int *fileType, ino_t *inode) { + struct dirent *de = 0; + while (_nextName(de, dir, fileType, inode)) { + try { uint64_t localIv = iv; - return naming->decodePath( de->d_name, &localIv ); - } catch ( Error &ex ) - { + return naming->decodePath(de->d_name, &localIv); + } + catch (Error &ex) { // .. .problem decoding, ignore it and continue on to next name.. - VLOG(1) << "error decoding filename " << de->d_name - << " : " << ex.what(); + VLOG(1) << "error decoding filename " << de->d_name << " : " << ex.what(); } } return string(); } -std::string DirTraverse::nextInvalid() -{ - struct dirent *de=0; +std::string DirTraverse::nextInvalid() { + struct dirent *de = 0; // find the first name which produces a decoding error... - while(_nextName(de, dir, (int*)0, (ino_t*)0)) - { - try - { + while (_nextName(de, dir, (int *)0, (ino_t *)0)) { + try { uint64_t localIv = iv; - naming->decodePath( de->d_name, &localIv ); + naming->decodePath(de->d_name, &localIv); continue; - } catch( Error &ex ) - { - return string( de->d_name ); + } + catch (Error &ex) { + return string(de->d_name); } } return string(); } -struct RenameEl -{ +struct RenameEl { // ciphertext names string oldCName; - string newCName; // intermediate name (not final cname) + string newCName; // intermediate name (not final cname) // plaintext names string oldPName; @@ -172,59 +140,44 @@ struct RenameEl bool isDirectory; }; -class RenameOp -{ -private: +class RenameOp { + private: DirNode *dn; - shared_ptr< list > renameList; + shared_ptr > renameList; list::const_iterator last; -public: - RenameOp( DirNode *_dn, const shared_ptr< list > &_renameList ) - : dn(_dn), renameList(_renameList) - { + public: + RenameOp(DirNode *_dn, const shared_ptr > &_renameList) + : dn(_dn), renameList(_renameList) { last = renameList->begin(); } RenameOp(const RenameOp &src) - : dn(src.dn) - , renameList(src.renameList) - , last(src.last) - { - } + : dn(src.dn), renameList(src.renameList), last(src.last) {} ~RenameOp(); - operator bool () const - { - return renameList; - } + operator bool() const { return renameList; } bool apply(); void undo(); }; -RenameOp::~RenameOp() -{ - if(renameList) - { +RenameOp::~RenameOp() { + if (renameList) { // got a bunch of decoded filenames sitting in memory.. do a little // cleanup before leaving.. list::iterator it; - for(it = renameList->begin(); it != renameList->end(); ++it) - { - it->oldPName.assign( it->oldPName.size(), ' ' ); - it->newPName.assign( it->newPName.size(), ' ' ); + for (it = renameList->begin(); it != renameList->end(); ++it) { + it->oldPName.assign(it->oldPName.size(), ' '); + it->newPName.assign(it->newPName.size(), ' '); } } } -bool RenameOp::apply() -{ - try - { - while(last != renameList->end()) - { +bool RenameOp::apply() { + try { + while (last != renameList->end()) { // backing store rename. VLOG(2) << "renaming " << last->oldCName << "-> " << last->newCName; @@ -232,22 +185,17 @@ bool RenameOp::apply() bool preserve_mtime = ::stat(last->oldCName.c_str(), &st) == 0; // internal node rename.. - dn->renameNode( last->oldPName.c_str(), - last->newPName.c_str() ); + dn->renameNode(last->oldPName.c_str(), last->newPName.c_str()); // rename on disk.. - if(::rename( last->oldCName.c_str(), - last->newCName.c_str() ) == -1) - { - LOG(WARNING) << "Error renaming " << last->oldCName << ": " << - strerror(errno); - dn->renameNode( last->newPName.c_str(), - last->oldPName.c_str(), false ); + if (::rename(last->oldCName.c_str(), last->newCName.c_str()) == -1) { + LOG(WARNING) << "Error renaming " << last->oldCName << ": " + << strerror(errno); + dn->renameNode(last->newPName.c_str(), last->oldPName.c_str(), false); return false; } - if(preserve_mtime) - { + if (preserve_mtime) { struct utimbuf ut; ut.actime = st.st_atime; ut.modtime = st.st_mtime; @@ -258,21 +206,19 @@ bool RenameOp::apply() } return true; - } catch( Error &err ) - { + } + catch (Error &err) { LOG(WARNING) << "caught error in rename application: " << err.what(); return false; } } -void RenameOp::undo() -{ +void RenameOp::undo() { VLOG(1) << "in undoRename"; - if(last == renameList->begin()) - { + if (last == renameList->begin()) { VLOG(1) << "nothing to undo"; - return; // nothing to undo + return; // nothing to undo } // list has to be processed backwards, otherwise we may rename @@ -281,19 +227,16 @@ void RenameOp::undo() int errorCount = 0; list::const_iterator it = last; - while( it != renameList->begin() ) - { + while (it != renameList->begin()) { --it; VLOG(1) << "undo: renaming " << it->newCName << " -> " << it->oldCName; - ::rename( it->newCName.c_str(), it->oldCName.c_str() ); - try - { - dn->renameNode( it->newPName.c_str(), - it->oldPName.c_str(), false ); - } catch( Error &err ) - { + ::rename(it->newCName.c_str(), it->oldCName.c_str()); + try { + dn->renameNode(it->newPName.c_str(), it->oldPName.c_str(), false); + } + catch (Error &err) { if (++errorCount == 1) LOG(WARNING) << "error in rename und: " << err.what(); // continue on anyway... @@ -304,11 +247,9 @@ void RenameOp::undo() LOG(WARNING) << "Undo rename count: " << undoCount; } -DirNode::DirNode(EncFS_Context *_ctx, - const string &sourceDir, - const FSConfigPtr &_config) -{ - Lock _lock( mutex ); +DirNode::DirNode(EncFS_Context *_ctx, const string &sourceDir, + const FSConfigPtr &_config) { + Lock _lock(mutex); ctx = _ctx; rootDir = sourceDir; @@ -316,169 +257,138 @@ DirNode::DirNode(EncFS_Context *_ctx, // make sure rootDir ends in '/', so that we can form a path by appending // the rest.. - if( rootDir[ rootDir.length()-1 ] != '/' ) - rootDir.append( 1, '/'); + if (rootDir[rootDir.length() - 1] != '/') rootDir.append(1, '/'); naming = fsConfig->nameCoding; } -DirNode::~DirNode() -{ -} +DirNode::~DirNode() {} -bool DirNode::hasDirectoryNameDependency() const -{ +bool DirNode::hasDirectoryNameDependency() const { return naming ? naming->getChainedNameIV() : false; } -string DirNode::rootDirectory() -{ +string DirNode::rootDirectory() { // don't update last access here, otherwise 'du' would cause lastAccess to // be reset. // chop off '/' terminator from root dir. - return string( rootDir, 0, rootDir.length()-1 ); + return string(rootDir, 0, rootDir.length() - 1); } -string DirNode::cipherPath( const char *plaintextPath ) -{ - return rootDir + naming->encodePath( plaintextPath ); +string DirNode::cipherPath(const char *plaintextPath) { + return rootDir + naming->encodePath(plaintextPath); } -string DirNode::cipherPathWithoutRoot( const char *plaintextPath ) -{ - return naming->encodePath( plaintextPath ); +string DirNode::cipherPathWithoutRoot(const char *plaintextPath) { + return naming->encodePath(plaintextPath); } -string DirNode::plainPath( const char *cipherPath_ ) -{ - try - { - if( !strncmp( cipherPath_, rootDir.c_str(), - rootDir.length() ) ) - { - return naming->decodePath( cipherPath_ + rootDir.length() ); - } else - { - if ( cipherPath_[0] == '+' ) - { +string DirNode::plainPath(const char *cipherPath_) { + try { + if (!strncmp(cipherPath_, rootDir.c_str(), rootDir.length())) { + return naming->decodePath(cipherPath_ + rootDir.length()); + } else { + if (cipherPath_[0] == '+') { // decode as fully qualified path - return string("/") + naming->decodeName( cipherPath_+1, - strlen(cipherPath_+1) ); - } else - { - return naming->decodePath( cipherPath_ ); + return string("/") + + naming->decodeName(cipherPath_ + 1, strlen(cipherPath_ + 1)); + } else { + return naming->decodePath(cipherPath_); } } - - } catch( Error &err ) - { + } + catch (Error &err) { LOG(ERROR) << "decode err: " << err.what(); return string(); } } -string DirNode::relativeCipherPath( const char *plaintextPath ) -{ - try - { - if(plaintextPath[0] == '/') - { +string DirNode::relativeCipherPath(const char *plaintextPath) { + try { + if (plaintextPath[0] == '/') { // mark with '+' to indicate special decoding.. - return string("+") + naming->encodeName(plaintextPath+1, - strlen(plaintextPath+1)); - } else - { - return naming->encodePath( plaintextPath ); + return string("+") + + naming->encodeName(plaintextPath + 1, strlen(plaintextPath + 1)); + } else { + return naming->encodePath(plaintextPath); } - } catch( Error &err ) - { + } + catch (Error &err) { LOG(ERROR) << "encode err: " << err.what(); return string(); } } -DirTraverse DirNode::openDir(const char *plaintextPath) -{ - string cyName = rootDir + naming->encodePath( plaintextPath ); - //rDebug("openDir on %s", cyName.c_str() ); +DirTraverse DirNode::openDir(const char *plaintextPath) { + string cyName = rootDir + naming->encodePath(plaintextPath); + // rDebug("openDir on %s", cyName.c_str() ); - DIR *dir = ::opendir( cyName.c_str() ); - if(dir == NULL) - { + DIR *dir = ::opendir(cyName.c_str()); + if (dir == NULL) { VLOG(1) << "opendir error " << strerror(errno); - return DirTraverse( shared_ptr(), 0, shared_ptr() ); - } else - { - shared_ptr dp( dir, DirDeleter() ); + return DirTraverse(shared_ptr(), 0, shared_ptr()); + } else { + shared_ptr dp(dir, DirDeleter()); uint64_t iv = 0; // if we're using chained IV mode, then compute the IV at this // directory level.. - try - { - if( naming->getChainedNameIV() ) - naming->encodePath( plaintextPath, &iv ); - } catch( Error &err ) - { + try { + if (naming->getChainedNameIV()) naming->encodePath(plaintextPath, &iv); + } + catch (Error &err) { LOG(ERROR) << "encode err: " << err.what(); } - return DirTraverse( dp, iv, naming ); + return DirTraverse(dp, iv, naming); } } -bool DirNode::genRenameList( list &renameList, - const char *fromP, const char *toP ) -{ +bool DirNode::genRenameList(list &renameList, const char *fromP, + const char *toP) { uint64_t fromIV = 0, toIV = 0; // compute the IV for both paths - string fromCPart = naming->encodePath( fromP, &fromIV ); - string toCPart = naming->encodePath( toP, &toIV ); + string fromCPart = naming->encodePath(fromP, &fromIV); + string toCPart = naming->encodePath(toP, &toIV); // where the files live before the rename.. string sourcePath = rootDir + fromCPart; // ok..... we wish it was so simple.. should almost never happen - if(fromIV == toIV) - return true; + if (fromIV == toIV) return true; // generate the real destination path, where we expect to find the files.. VLOG(1) << "opendir " << sourcePath; - shared_ptr dir = shared_ptr( - opendir( sourcePath.c_str() ), DirDeleter() ); - if(!dir) - return false; + shared_ptr dir = + shared_ptr(opendir(sourcePath.c_str()), DirDeleter()); + if (!dir) return false; struct dirent *de = NULL; - while((de = ::readdir( dir.get() )) != NULL) - { + while ((de = ::readdir(dir.get())) != NULL) { // decode the name using the oldIV uint64_t localIV = fromIV; string plainName; - if((de->d_name[0] == '.') && - ((de->d_name[1] == '\0') - || ((de->d_name[1] == '.') && (de->d_name[2] == '\0')))) - { + if ((de->d_name[0] == '.') && + ((de->d_name[1] == '\0') || + ((de->d_name[1] == '.') && (de->d_name[2] == '\0')))) { // skip "." and ".." continue; } - try - { - plainName = naming->decodePath( de->d_name, &localIV ); - } catch( Error &ex ) - { + try { + plainName = naming->decodePath(de->d_name, &localIV); + } + catch (Error &ex) { // if filename can't be decoded, then ignore it.. continue; } // any error in the following will trigger a rename failure. - try - { + try { // re-encode using the new IV.. localIV = toIV; - string newName = naming->encodePath( plainName.c_str(), &localIV ); + string newName = naming->encodePath(plainName.c_str(), &localIV); // store rename information.. string oldFull = sourcePath + '/' + de->d_name; @@ -492,38 +402,34 @@ bool DirNode::genRenameList( list &renameList, bool isDir; #if defined(_DIRENT_HAVE_D_TYPE) - if(de->d_type != DT_UNKNOWN) - { + if (de->d_type != DT_UNKNOWN) { isDir = (de->d_type == DT_DIR); } else #endif { - isDir = isDirectory( oldFull.c_str() ); + isDir = isDirectory(oldFull.c_str()); } ren.isDirectory = isDir; - if(isDir) - { + if (isDir) { // recurse.. We want to add subdirectory elements before the // parent, as that is the logical rename order.. - if(!genRenameList( renameList, - ren.oldPName.c_str(), - ren.newPName.c_str())) - { + if (!genRenameList(renameList, ren.oldPName.c_str(), + ren.newPName.c_str())) { return false; } } VLOG(1) << "adding file " << oldFull << " to rename list"; - renameList.push_back( ren ); - - } catch( Error &err ) - { + renameList.push_back(ren); + } + catch (Error &err) { // We can't convert this name, because we don't have a valid IV for // it (or perhaps a valid key).. It will be inaccessible.. - LOG(WARNING) << "Aborting rename: error on file " << - fromCPart.append(1, '/').append(de->d_name) << ":" << err.what(); + LOG(WARNING) << "Aborting rename: error on file " + << fromCPart.append(1, '/').append(de->d_name) << ":" + << err.what(); // abort.. Err on the side of safety and disallow rename, rather // then loosing files.. @@ -534,7 +440,6 @@ bool DirNode::genRenameList( list &renameList, return true; } - /* A bit of a pain.. If a directory is renamed in a filesystem with directory initialization vector chaining, then we have to recursively @@ -543,49 +448,39 @@ bool DirNode::genRenameList( list &renameList, Returns a list of renamed items on success, a null list on failure. */ -shared_ptr -DirNode::newRenameOp( const char *fromP, const char *toP ) -{ +shared_ptr DirNode::newRenameOp(const char *fromP, const char *toP) { // Do the rename in two stages to avoid chasing our tail // Undo everything if we encounter an error! - shared_ptr< list > renameList(new list); - if(!genRenameList( *renameList.get(), fromP, toP )) - { + shared_ptr > renameList(new list); + if (!genRenameList(*renameList.get(), fromP, toP)) { LOG(WARNING) << "Error during generation of recursive rename list"; return shared_ptr(); } else - return shared_ptr( new RenameOp(this, renameList) ); + return shared_ptr(new RenameOp(this, renameList)); } - -int DirNode::mkdir(const char *plaintextPath, mode_t mode, - uid_t uid, gid_t gid) -{ - string cyName = rootDir + naming->encodePath( plaintextPath ); - rAssert( !cyName.empty() ); +int DirNode::mkdir(const char *plaintextPath, mode_t mode, uid_t uid, + gid_t gid) { + string cyName = rootDir + naming->encodePath(plaintextPath); + rAssert(!cyName.empty()); VLOG(1) << "mkdir on " << cyName; // if uid or gid are set, then that should be the directory owner int olduid = -1; int oldgid = -1; - if(uid != 0) - olduid = setfsuid( uid ); - if(gid != 0) - oldgid = setfsgid( gid ); + if (uid != 0) olduid = setfsuid(uid); + if (gid != 0) oldgid = setfsgid(gid); - int res = ::mkdir( cyName.c_str(), mode ); + int res = ::mkdir(cyName.c_str(), mode); - if(olduid >= 0) - setfsuid( olduid ); - if(oldgid >= 0) - setfsgid( oldgid ); + if (olduid >= 0) setfsuid(olduid); + if (oldgid >= 0) setfsgid(oldgid); - if(res == -1) - { + if (res == -1) { int eno = errno; - LOG(WARNING) << "mkdir error on " << cyName - << " mode " << mode << ": " << strerror(eno); + LOG(WARNING) << "mkdir error on " << cyName << " mode " << mode << ": " + << strerror(eno); res = -eno; } else res = 0; @@ -593,30 +488,25 @@ int DirNode::mkdir(const char *plaintextPath, mode_t mode, return res; } -int -DirNode::rename( const char *fromPlaintext, const char *toPlaintext ) -{ - Lock _lock( mutex ); +int DirNode::rename(const char *fromPlaintext, const char *toPlaintext) { + Lock _lock(mutex); - string fromCName = rootDir + naming->encodePath( fromPlaintext ); - string toCName = rootDir + naming->encodePath( toPlaintext ); - rAssert( !fromCName.empty() ); - rAssert( !toCName.empty() ); + string fromCName = rootDir + naming->encodePath(fromPlaintext); + string toCName = rootDir + naming->encodePath(toPlaintext); + rAssert(!fromCName.empty()); + rAssert(!toCName.empty()); VLOG(1) << "rename " << fromCName << " -> " << toCName; - shared_ptr toNode = findOrCreate( toPlaintext ); + shared_ptr toNode = findOrCreate(toPlaintext); shared_ptr renameOp; - if( hasDirectoryNameDependency() && isDirectory( fromCName.c_str() )) - { + if (hasDirectoryNameDependency() && isDirectory(fromCName.c_str())) { VLOG(1) << "recursive rename begin"; - renameOp = newRenameOp( fromPlaintext, toPlaintext ); + renameOp = newRenameOp(fromPlaintext, toPlaintext); - if(!renameOp || !renameOp->apply()) - { - if(renameOp) - renameOp->undo(); + if (!renameOp || !renameOp->apply()) { + if (renameOp) renameOp->undo(); LOG(WARNING) << "rename aborted"; return -EACCES; @@ -625,65 +515,57 @@ DirNode::rename( const char *fromPlaintext, const char *toPlaintext ) } int res = 0; - try - { + try { struct stat st; bool preserve_mtime = ::stat(fromCName.c_str(), &st) == 0; - renameNode( fromPlaintext, toPlaintext ); - res = ::rename( fromCName.c_str(), toCName.c_str() ); + renameNode(fromPlaintext, toPlaintext); + res = ::rename(fromCName.c_str(), toCName.c_str()); - if(res == -1) - { + if (res == -1) { // undo res = -errno; - renameNode( toPlaintext, fromPlaintext, false ); + renameNode(toPlaintext, fromPlaintext, false); - if(renameOp) - renameOp->undo(); - } else if(preserve_mtime) - { + if (renameOp) renameOp->undo(); + } else if (preserve_mtime) { struct utimbuf ut; ut.actime = st.st_atime; ut.modtime = st.st_mtime; ::utime(toCName.c_str(), &ut); } - } catch( Error &err ) - { + } + catch (Error &err) { // exception from renameNode, just show the error and continue.. LOG(ERROR) << "rename err: " << err.what(); res = -EIO; } - if(res != 0) - { - VLOG(1) << "rename failed: " << strerror( errno ); + if (res != 0) { + VLOG(1) << "rename failed: " << strerror(errno); res = -errno; } return res; } -int DirNode::link( const char *from, const char *to ) -{ - Lock _lock( mutex ); +int DirNode::link(const char *from, const char *to) { + Lock _lock(mutex); - string fromCName = rootDir + naming->encodePath( from ); - string toCName = rootDir + naming->encodePath( to ); + string fromCName = rootDir + naming->encodePath(from); + string toCName = rootDir + naming->encodePath(to); - rAssert( !fromCName.empty() ); - rAssert( !toCName.empty() ); + rAssert(!fromCName.empty()); + rAssert(!toCName.empty()); VLOG(1) << "link " << fromCName << " -> " << toCName; int res = -EPERM; - if( fsConfig->config->external_iv() ) - { + if (fsConfig->config->external_iv()) { VLOG(1) << "hard links not supported with external IV chaining!"; - } else - { - res = ::link( fromCName.c_str(), toCName.c_str() ); - if(res == -1) + } else { + res = ::link(fromCName.c_str(), toCName.c_str()); + if (res == -1) res = -errno; else res = 0; @@ -696,31 +578,25 @@ int DirNode::link( const char *from, const char *to ) The node is keyed by filename, so a rename means the internal node names must be changed. */ -shared_ptr DirNode::renameNode( const char *from, const char *to ) -{ - return renameNode( from, to, true ); +shared_ptr DirNode::renameNode(const char *from, const char *to) { + return renameNode(from, to, true); } -shared_ptr DirNode::renameNode( const char *from, const char *to, - bool forwardMode ) -{ - shared_ptr node = findOrCreate( from ); +shared_ptr DirNode::renameNode(const char *from, const char *to, + bool forwardMode) { + shared_ptr node = findOrCreate(from); - if(node) - { + if (node) { uint64_t newIV = 0; - string cname = rootDir + naming->encodePath( to, &newIV ); + string cname = rootDir + naming->encodePath(to, &newIV); - VLOG(1) << "renaming internal node " << node->cipherName() - << " -> " << cname.c_str(); + VLOG(1) << "renaming internal node " << node->cipherName() << " -> " + << cname.c_str(); - if(node->setName( to, cname.c_str(), newIV, forwardMode )) - { - if(ctx) - ctx->renameNode( from, to ); - } else - { - // rename error! - put it back + if (node->setName(to, cname.c_str(), newIV, forwardMode)) { + if (ctx) ctx->renameNode(from, to); + } else { + // rename error! - put it back LOG(ERROR) << "renameNode failed"; throw Error("Internal node name change failed!"); } @@ -729,22 +605,17 @@ shared_ptr DirNode::renameNode( const char *from, const char *to, return node; } -shared_ptr DirNode::findOrCreate( const char *plainName) -{ +shared_ptr DirNode::findOrCreate(const char *plainName) { shared_ptr node; - if(ctx) - node = ctx->lookupNode( plainName ); + if (ctx) node = ctx->lookupNode(plainName); - if(!node) - { + if (!node) { uint64_t iv = 0; - string cipherName = naming->encodePath( plainName, &iv ); - node.reset( new FileNode( this, fsConfig, - plainName, - (rootDir + cipherName).c_str())); + string cipherName = naming->encodePath(plainName, &iv); + node.reset(new FileNode(this, fsConfig, plainName, + (rootDir + cipherName).c_str())); - if(fsConfig->config->external_iv()) - node->setName(0, 0, iv); + if (fsConfig->config->external_iv()) node->setName(0, 0, iv); VLOG(1) << "created FileNode for " << node->cipherName(); } @@ -752,13 +623,12 @@ shared_ptr DirNode::findOrCreate( const char *plainName) return node; } -shared_ptr -DirNode::lookupNode( const char *plainName, const char * requestor ) -{ +shared_ptr DirNode::lookupNode(const char *plainName, + const char *requestor) { (void)requestor; - Lock _lock( mutex ); + Lock _lock(mutex); - shared_ptr node = findOrCreate( plainName ); + shared_ptr node = findOrCreate(plainName); return node; } @@ -768,51 +638,45 @@ DirNode::lookupNode( const char *plainName, const char * requestor ) node on sucess.. This is done in one step to avoid any race conditions with the stored state of the file. */ -shared_ptr -DirNode::openNode( const char *plainName, const char * requestor, int flags, - int *result ) -{ +shared_ptr DirNode::openNode(const char *plainName, + const char *requestor, int flags, + int *result) { (void)requestor; - rAssert( result != NULL ); - Lock _lock( mutex ); + rAssert(result != NULL); + Lock _lock(mutex); - shared_ptr node = findOrCreate( plainName ); + shared_ptr node = findOrCreate(plainName); - if( node && (*result = node->open( flags )) >= 0 ) + if (node && (*result = node->open(flags)) >= 0) return node; else return shared_ptr(); } -int DirNode::unlink( const char *plaintextName ) -{ - string cyName = naming->encodePath( plaintextName ); +int DirNode::unlink(const char *plaintextName) { + string cyName = naming->encodePath(plaintextName); VLOG(1) << "unlink " << cyName; - Lock _lock( mutex ); + Lock _lock(mutex); int res = 0; - if(ctx && ctx->lookupNode( plaintextName )) - { + if (ctx && ctx->lookupNode(plaintextName)) { // If FUSE is running with "hard_remove" option where it doesn't // hide open files for us, then we can't allow an unlink of an open // file.. - LOG(WARNING) << "Refusing to unlink open file: " - << cyName << ", hard_remove option is probably in effect"; + LOG(WARNING) << "Refusing to unlink open file: " << cyName + << ", hard_remove option is probably in effect"; res = -EBUSY; - } else - { + } else { string fullName = rootDir + cyName; - res = ::unlink( fullName.c_str() ); - if(res == -1) - { + res = ::unlink(fullName.c_str()); + if (res == -1) { res = -errno; VLOG(1) << "unlink error: " << strerror(errno); - } + } } return res; } } // namespace encfs - diff --git a/fs/DirNode.h b/fs/DirNode.h index 7360536..0e96c45 100644 --- a/fs/DirNode.h +++ b/fs/DirNode.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -44,133 +44,129 @@ class RenameOp; struct RenameEl; class EncFS_Context; -class DirTraverse -{ -public: - DirTraverse(const shared_ptr &dirPtr, uint64_t iv, - const shared_ptr &naming); - DirTraverse(const DirTraverse &src); - ~DirTraverse(); +class DirTraverse { + public: + DirTraverse(const shared_ptr &dirPtr, uint64_t iv, + const shared_ptr &naming); + DirTraverse(const DirTraverse &src); + ~DirTraverse(); - DirTraverse &operator = (const DirTraverse &src); + DirTraverse &operator=(const DirTraverse &src); - // returns FALSE to indicate an invalid DirTraverse (such as when - // an invalid directory is requested for traversal) - bool valid() const; + // returns FALSE to indicate an invalid DirTraverse (such as when + // an invalid directory is requested for traversal) + bool valid() const; - // return next plaintext filename - // If fileType is not 0, then it is used to return the filetype (or 0 if - // unknown) - std::string nextPlaintextName(int *fileType=0, ino_t *inode=0); + // return next plaintext filename + // If fileType is not 0, then it is used to return the filetype (or 0 if + // unknown) + std::string nextPlaintextName(int *fileType = 0, ino_t *inode = 0); - /* Return cipher name of next undecodable filename.. - The opposite of nextPlaintextName(), as that skips undecodable names.. - */ - std::string nextInvalid(); -private: + /* Return cipher name of next undecodable filename.. + The opposite of nextPlaintextName(), as that skips undecodable names.. + */ + std::string nextInvalid(); - shared_ptr dir; // struct DIR - // initialization vector to use. Not very general purpose, but makes it - // more efficient to support filename IV chaining.. - uint64_t iv; - shared_ptr naming; + private: + shared_ptr dir; // struct DIR + // initialization vector to use. Not very general purpose, but makes it + // more efficient to support filename IV chaining.. + uint64_t iv; + shared_ptr naming; }; inline bool DirTraverse::valid() const { return dir != 0; } -class DirNode -{ -public: - // sourceDir points to where raw files are stored - DirNode(EncFS_Context *ctx, - const std::string &sourceDir, - const FSConfigPtr &config ); - ~DirNode(); +class DirNode { + public: + // sourceDir points to where raw files are stored + DirNode(EncFS_Context *ctx, const std::string &sourceDir, + const FSConfigPtr &config); + ~DirNode(); - // return the path to the root directory - std::string rootDirectory(); + // return the path to the root directory + std::string rootDirectory(); - // find files - shared_ptr lookupNode( const char *plaintextName, - const char *requestor ); + // find files + shared_ptr lookupNode(const char *plaintextName, + const char *requestor); - /* - Combined lookupNode + node->open() call. If the open fails, then the - node is not retained. If the open succeeds, then the node is returned. - */ - shared_ptr openNode( const char *plaintextName, - const char *requestor, int flags, int *openResult ); + /* + Combined lookupNode + node->open() call. If the open fails, then the + node is not retained. If the open succeeds, then the node is returned. + */ + shared_ptr openNode(const char *plaintextName, + const char *requestor, int flags, + int *openResult); - std::string cipherPath( const char *plaintextPath ); - std::string cipherPathWithoutRoot( const char *plaintextPath ); - std::string plainPath( const char *cipherPath ); + std::string cipherPath(const char *plaintextPath); + std::string cipherPathWithoutRoot(const char *plaintextPath); + std::string plainPath(const char *cipherPath); - // relative cipherPath is the same as cipherPath except that it doesn't - // prepent the mount point. That it, it doesn't return a fully qualified - // name, just a relative path within the encrypted filesystem. - std::string relativeCipherPath( const char *plaintextPath ); + // relative cipherPath is the same as cipherPath except that it doesn't + // prepent the mount point. That it, it doesn't return a fully qualified + // name, just a relative path within the encrypted filesystem. + std::string relativeCipherPath(const char *plaintextPath); - /* - Returns true if file names are dependent on the parent directory name. - If a directory name is changed, then all the filenames must also be - changed. - */ - bool hasDirectoryNameDependency() const; + /* + Returns true if file names are dependent on the parent directory name. + If a directory name is changed, then all the filenames must also be + changed. + */ + bool hasDirectoryNameDependency() const; - // unlink the specified file - int unlink( const char *plaintextName ); + // unlink the specified file + int unlink(const char *plaintextName); - // traverse directory - DirTraverse openDir( const char *plainDirName ); + // traverse directory + DirTraverse openDir(const char *plainDirName); - // uid and gid are used as the directory owner, only if not zero - int mkdir( const char *plaintextPath, mode_t mode, - uid_t uid = 0, gid_t gid = 0); + // uid and gid are used as the directory owner, only if not zero + int mkdir(const char *plaintextPath, mode_t mode, uid_t uid = 0, + gid_t gid = 0); - int rename( const char *fromPlaintext, const char *toPlaintext ); + int rename(const char *fromPlaintext, const char *toPlaintext); - int link( const char *from, const char *to ); - - // returns idle time of filesystem in seconds - int idleSeconds(); + int link(const char *from, const char *to); -protected: + // returns idle time of filesystem in seconds + int idleSeconds(); - /* - notify that a file is being renamed. - This renames the internal node, if any. If the file is not open, then - this call has no effect. - Returns the FileNode if it was found. - */ - shared_ptr renameNode( const char *from, const char *to ); - shared_ptr renameNode( const char *from, const char *to, - bool forwardMode ); + protected: + /* + notify that a file is being renamed. + This renames the internal node, if any. If the file is not open, then + this call has no effect. + Returns the FileNode if it was found. + */ + shared_ptr renameNode(const char *from, const char *to); + shared_ptr renameNode(const char *from, const char *to, + bool forwardMode); - /* - when directory IV chaining is enabled, a directory can't be renamed - without renaming all its contents as well. recursiveRename should be - called after renaming the directory, passing in the plaintext from and - to paths. - */ - shared_ptr newRenameOp( const char *from, const char *to ); + /* + when directory IV chaining is enabled, a directory can't be renamed + without renaming all its contents as well. recursiveRename should be + called after renaming the directory, passing in the plaintext from and + to paths. + */ + shared_ptr newRenameOp(const char *from, const char *to); -private: + private: + friend class RenameOp; - friend class RenameOp; + bool genRenameList(std::list &list, const char *fromP, + const char *toP); - bool genRenameList( std::list &list, const char *fromP, - const char *toP ); - - shared_ptr findOrCreate( const char *plainName); + shared_ptr findOrCreate(const char *plainName); - Mutex mutex; + Mutex mutex; - EncFS_Context *ctx; + EncFS_Context *ctx; - // passed in as configuration - std::string rootDir; - FSConfigPtr fsConfig; + // passed in as configuration + std::string rootDir; + FSConfigPtr fsConfig; - shared_ptr naming; + shared_ptr naming; }; } // namespace encfs diff --git a/fs/FSConfig.h b/fs/FSConfig.h index 94d1bea..a38a814 100644 --- a/fs/FSConfig.h +++ b/fs/FSConfig.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -31,15 +31,14 @@ namespace encfs { -enum ConfigType -{ - Config_None = 0, - Config_Prehistoric, - Config_V3 = 3, - Config_V4 = 4, - Config_V5 = 5, - Config_V6 = 6, - Config_V7 = 7 +enum ConfigType { + Config_None = 0, + Config_Prehistoric, + Config_V3 = 3, + Config_V4 = 4, + Config_V5 = 5, + Config_V6 = 6, + Config_V7 = 7 }; struct EncFS_Opts; @@ -51,35 +50,32 @@ CipherKey getUserKey(const EncfsConfig &config, const std::string &passwordProgram, const std::string &rootDir); -CipherKey getNewUserKey(EncfsConfig &config, bool useStdin, - const std::string &program, const std::string &rootDir); - +CipherKey getNewUserKey(EncfsConfig &config, bool useStdin, + const std::string &program, const std::string &rootDir); + shared_ptr getCipher(const EncfsConfig &cfg); shared_ptr getCipher(const Interface &iface, int keySize); // helpers for serializing to/from a stream -std::ostream &operator << (std::ostream &os, const EncfsConfig &cfg); -std::istream &operator >> (std::istream &os, EncfsConfig &cfg); +std::ostream &operator<<(std::ostream &os, const EncfsConfig &cfg); +std::istream &operator>>(std::istream &os, EncfsConfig &cfg); // Filesystem state -struct FSConfig -{ - shared_ptr config; - shared_ptr opts; +struct FSConfig { + shared_ptr config; + shared_ptr opts; - shared_ptr cipher; - CipherKey key; - shared_ptr nameCoding; + shared_ptr cipher; + CipherKey key; + shared_ptr nameCoding; - bool forceDecode; // force decode on MAC block failures - bool reverseEncryption; // reverse encryption operation + bool forceDecode; // force decode on MAC block failures + bool reverseEncryption; // reverse encryption operation - bool idleTracking; // turn on idle monitoring of filesystem + bool idleTracking; // turn on idle monitoring of filesystem - FSConfig() - : forceDecode(false), - reverseEncryption(false), - idleTracking(false) { } + FSConfig() + : forceDecode(false), reverseEncryption(false), idleTracking(false) {} }; typedef shared_ptr FSConfigPtr; @@ -87,4 +83,3 @@ typedef shared_ptr FSConfigPtr; } // namespace encfs #endif - diff --git a/fs/FileIO.cpp b/fs/FileIO.cpp index 7f44bb0..e414c1c 100644 --- a/fs/FileIO.cpp +++ b/fs/FileIO.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -22,23 +22,15 @@ namespace encfs { -FileIO::FileIO() -{ -} +FileIO::FileIO() {} -FileIO::~FileIO() -{ -} +FileIO::~FileIO() {} -int FileIO::blockSize() const -{ - return 1; -} +int FileIO::blockSize() const { return 1; } -bool FileIO::setIV( uint64_t iv ) -{ - (void)iv; - return true; +bool FileIO::setIV(uint64_t iv) { + (void)iv; + return true; } } // namespace encfs diff --git a/fs/FileIO.h b/fs/FileIO.h index dca4831..f94b78b 100644 --- a/fs/FileIO.h +++ b/fs/FileIO.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -28,63 +28,56 @@ namespace encfs { -struct IORequest -{ - off_t offset; +struct IORequest { + off_t offset; - // amount of bytes to read/write. - int dataLen; - unsigned char *data; + // amount of bytes to read/write. + int dataLen; + unsigned char *data; - IORequest(); + IORequest(); }; -inline IORequest::IORequest() - : offset(0) - , dataLen(0) - , data(0) -{ -} +inline IORequest::IORequest() : offset(0), dataLen(0), data(0) {} -class FileIO -{ -public: - FileIO(); - virtual ~FileIO(); +class FileIO { + public: + FileIO(); + virtual ~FileIO(); - virtual Interface interface() const =0; + virtual Interface interface() const = 0; - // default implementation returns 1, meaning this is not block oriented. - virtual int blockSize() const; + // default implementation returns 1, meaning this is not block oriented. + virtual int blockSize() const; - virtual void setFileName(const char *fileName) =0; - virtual const char *getFileName() const =0; + virtual void setFileName(const char *fileName) = 0; + virtual const char *getFileName() const = 0; - // Not sure about this -- it is specific to CipherFileIO, but the - // alternative methods of exposing this interface aren't much nicer.. - virtual bool setIV( uint64_t iv ); + // Not sure about this -- it is specific to CipherFileIO, but the + // alternative methods of exposing this interface aren't much nicer.. + virtual bool setIV(uint64_t iv); - // open file for specified mode. There is no corresponding close, so a - // file is open until the FileIO interface is destroyed. - virtual int open( int flags ) =0; - - // get filesystem attributes for a file - virtual int getAttr( struct stat *stbuf ) const =0; - virtual off_t getSize( ) const =0; + // open file for specified mode. There is no corresponding close, so a + // file is open until the FileIO interface is destroyed. + virtual int open(int flags) = 0; - virtual ssize_t read( const IORequest &req ) const =0; - virtual bool write( const IORequest &req ) =0; + // get filesystem attributes for a file + virtual int getAttr(struct stat *stbuf) const = 0; + virtual off_t getSize() const = 0; - virtual int truncate( off_t size ) =0; + virtual ssize_t read(const IORequest &req) const = 0; + virtual bool write(const IORequest &req) = 0; - virtual bool isWritable() const =0; -private: - // not implemented.. - FileIO( const FileIO & ); - FileIO &operator = ( const FileIO & ); + virtual int truncate(off_t size) = 0; + + virtual bool isWritable() const = 0; + + private: + // not implemented.. + FileIO(const FileIO &); + FileIO &operator=(const FileIO &); }; } // namespace encfs #endif - diff --git a/fs/FileNode.cpp b/fs/FileNode.cpp index 1895f07..8ec379d 100644 --- a/fs/FileNode.cpp +++ b/fs/FileNode.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -63,9 +63,8 @@ namespace encfs { */ FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg, - const char *plaintextName_, const char *cipherName_) -{ - Lock _lock( mutex ); + const char *plaintextName_, const char *cipherName_) { + Lock _lock(mutex); this->_pname = plaintextName_; this->_cname = cipherName_; @@ -74,79 +73,59 @@ FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg, this->fsConfig = cfg; // chain RawFileIO & CipherFileIO - shared_ptr rawIO( new RawFileIO( _cname ) ); - io = shared_ptr( new CipherFileIO( rawIO, fsConfig )); + shared_ptr rawIO(new RawFileIO(_cname)); + io = shared_ptr(new CipherFileIO(rawIO, fsConfig)); - if(cfg->config->block_mac_bytes() || cfg->config->block_mac_rand_bytes()) + if (cfg->config->block_mac_bytes() || cfg->config->block_mac_rand_bytes()) io = shared_ptr(new MACFileIO(io, fsConfig)); } -FileNode::~FileNode() -{ +FileNode::~FileNode() { // FileNode mutex should be locked before the destructor is called - _pname.assign( _pname.length(), '\0' ); - _cname.assign( _cname.length(), '\0' ); + _pname.assign(_pname.length(), '\0'); + _cname.assign(_cname.length(), '\0'); io.reset(); } -const char *FileNode::cipherName() const -{ - return _cname.c_str(); -} +const char *FileNode::cipherName() const { return _cname.c_str(); } -const char *FileNode::plaintextName() const -{ - return _pname.c_str(); -} +const char *FileNode::plaintextName() const { return _pname.c_str(); } -string FileNode::plaintextParent() const -{ - return parentDirectory( _pname ); -} +string FileNode::plaintextParent() const { return parentDirectory(_pname); } -static bool setIV(const shared_ptr &io, uint64_t iv) -{ +static bool setIV(const shared_ptr &io, uint64_t iv) { struct stat stbuf; - if((io->getAttr(&stbuf) < 0) || S_ISREG(stbuf.st_mode)) - return io->setIV( iv ); + if ((io->getAttr(&stbuf) < 0) || S_ISREG(stbuf.st_mode)) + return io->setIV(iv); else return true; } -bool FileNode::setName( const char *plaintextName_, const char *cipherName_, - uint64_t iv, bool setIVFirst ) -{ - //Lock _lock( mutex ); +bool FileNode::setName(const char *plaintextName_, const char *cipherName_, + uint64_t iv, bool setIVFirst) { + // Lock _lock( mutex ); VLOG(1) << "calling setIV on " << cipherName_; - if(setIVFirst) - { - if(fsConfig->config->external_iv() && !setIV(io, iv)) - return false; + if (setIVFirst) { + if (fsConfig->config->external_iv() && !setIV(io, iv)) return false; // now change the name.. - if(plaintextName_) - this->_pname = plaintextName_; - if(cipherName_) - { + if (plaintextName_) this->_pname = plaintextName_; + if (cipherName_) { this->_cname = cipherName_; - io->setFileName( cipherName_ ); + io->setFileName(cipherName_); } - } else - { + } else { std::string oldPName = _pname; std::string oldCName = _cname; - if(plaintextName_) - this->_pname = plaintextName_; - if(cipherName_) - { + if (plaintextName_) this->_pname = plaintextName_; + if (cipherName_) { this->_cname = cipherName_; - io->setFileName( cipherName_ ); + io->setFileName(cipherName_); } - if(fsConfig->config->external_iv() && !setIV(io, iv)) - { + if (fsConfig->config->external_iv() && !setIV(io, iv)) { _pname = oldPName; _cname = oldCName; return false; @@ -156,27 +135,22 @@ bool FileNode::setName( const char *plaintextName_, const char *cipherName_, return true; } -int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid) -{ - Lock _lock( mutex ); +int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid) { + Lock _lock(mutex); int res; int olduid = -1; int oldgid = -1; - if(uid != 0) - { - olduid = setfsuid( uid ); - if(olduid == -1) - { + if (uid != 0) { + olduid = setfsuid(uid); + if (olduid == -1) { LOG(INFO) << "setfsuid error: " << strerror(errno); return -EPERM; } } - if(gid != 0) - { - oldgid = setfsgid( gid ); - if(oldgid == -1) - { + if (gid != 0) { + oldgid = setfsgid(gid); + if (oldgid == -1) { LOG(INFO) << "setfsgid error: " << strerror(errno); return -EPERM; } @@ -187,22 +161,18 @@ int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid) * The regular file stuff could be stripped off if there * were a create method (advised to have) */ - if (S_ISREG( mode )) { - res = ::open( _cname.c_str(), O_CREAT | O_EXCL | O_WRONLY, mode ); - if (res >= 0) - res = ::close( res ); - } else if (S_ISFIFO( mode )) - res = ::mkfifo( _cname.c_str(), mode ); + if (S_ISREG(mode)) { + res = ::open(_cname.c_str(), O_CREAT | O_EXCL | O_WRONLY, mode); + if (res >= 0) res = ::close(res); + } else if (S_ISFIFO(mode)) + res = ::mkfifo(_cname.c_str(), mode); else - res = ::mknod( _cname.c_str(), mode, rdev ); + res = ::mknod(_cname.c_str(), mode, rdev); - if(olduid >= 0) - setfsuid( olduid ); - if(oldgid >= 0) - setfsgid( oldgid ); + if (olduid >= 0) setfsuid(olduid); + if (oldgid >= 0) setfsgid(oldgid); - if(res == -1) - { + if (res == -1) { int eno = errno; VLOG(1) << "mknod error: " << strerror(eno); res = -eno; @@ -211,85 +181,75 @@ int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid) return res; } -int FileNode::open(int flags) const -{ - Lock _lock( mutex ); +int FileNode::open(int flags) const { + Lock _lock(mutex); - int res = io->open( flags ); + int res = io->open(flags); return res; } -int FileNode::getAttr(struct stat *stbuf) const -{ - Lock _lock( mutex ); +int FileNode::getAttr(struct stat *stbuf) const { + Lock _lock(mutex); - int res = io->getAttr( stbuf ); + int res = io->getAttr(stbuf); return res; } -off_t FileNode::getSize() const -{ - Lock _lock( mutex ); +off_t FileNode::getSize() const { + Lock _lock(mutex); int res = io->getSize(); return res; } -ssize_t FileNode::read( off_t offset, unsigned char *data, ssize_t size ) const -{ +ssize_t FileNode::read(off_t offset, unsigned char *data, ssize_t size) const { IORequest req; req.offset = offset; req.dataLen = size; req.data = data; - Lock _lock( mutex ); + Lock _lock(mutex); - return io->read( req ); + return io->read(req); } -bool FileNode::write(off_t offset, unsigned char *data, ssize_t size) -{ - VLOG(1) << "FileNode::write offset " << offset - << ", data size " << size; +bool FileNode::write(off_t offset, unsigned char *data, ssize_t size) { + VLOG(1) << "FileNode::write offset " << offset << ", data size " << size; IORequest req; req.offset = offset; req.dataLen = size; req.data = data; - Lock _lock( mutex ); + Lock _lock(mutex); - return io->write( req ); + return io->write(req); } -int FileNode::truncate( off_t size ) -{ - Lock _lock( mutex ); +int FileNode::truncate(off_t size) { + Lock _lock(mutex); - return io->truncate( size ); + return io->truncate(size); } -int FileNode::sync(bool datasync) -{ - Lock _lock( mutex ); +int FileNode::sync(bool datasync) { + Lock _lock(mutex); - int fh = io->open( O_RDONLY ); - if(fh >= 0) - { + int fh = io->open(O_RDONLY); + if (fh >= 0) { int res = -EIO; #ifdef linux - if(datasync) - res = fdatasync( fh ); + if (datasync) + res = fdatasync(fh); else - res = fsync( fh ); + res = fsync(fh); #else // no fdatasync support // TODO: use autoconfig to check for it.. res = fsync(fh); #endif - if(res == -1) - res = -errno; + if (res == -1) res = -errno; return res; } else diff --git a/fs/FileNode.h b/fs/FileNode.h index a4e6633..caebe53 100644 --- a/fs/FileNode.h +++ b/fs/FileNode.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ - + #ifndef _FileNode_incl_ #define _FileNode_incl_ @@ -36,69 +36,64 @@ class Cipher; class FileIO; class DirNode; -class FileNode -{ -public: - FileNode(DirNode *parent, - const FSConfigPtr &cfg, - const char *plaintextName, - const char *cipherName); - ~FileNode(); +class FileNode { + public: + FileNode(DirNode *parent, const FSConfigPtr &cfg, const char *plaintextName, + const char *cipherName); + ~FileNode(); - const char *plaintextName() const; - const char *cipherName() const; + const char *plaintextName() const; + const char *cipherName() const; - // directory portion of plaintextName - std::string plaintextParent() const; + // directory portion of plaintextName + std::string plaintextParent() const; - // if setIVFirst is true, then the IV is changed before the name is changed - // (default). The reverse is also supported for special cases.. - bool setName( const char *plaintextName, const char *cipherName, - uint64_t iv, bool setIVFirst = true); + // if setIVFirst is true, then the IV is changed before the name is changed + // (default). The reverse is also supported for special cases.. + bool setName(const char *plaintextName, const char *cipherName, uint64_t iv, + bool setIVFirst = true); - // create node - // If uid/gid are not 0, then chown is used change ownership as specified - int mknod(mode_t mode, dev_t rdev, uid_t uid = 0, gid_t gid = 0); + // create node + // If uid/gid are not 0, then chown is used change ownership as specified + int mknod(mode_t mode, dev_t rdev, uid_t uid = 0, gid_t gid = 0); - // Returns < 0 on error (-errno), file descriptor on success. - int open(int flags) const; + // Returns < 0 on error (-errno), file descriptor on success. + int open(int flags) const; - // getAttr returns 0 on success, -errno on failure - int getAttr(struct stat *stbuf) const; - off_t getSize() const; + // getAttr returns 0 on success, -errno on failure + int getAttr(struct stat *stbuf) const; + off_t getSize() const; - ssize_t read(off_t offset, unsigned char *data, ssize_t size) const; - bool write(off_t offset, unsigned char *data, ssize_t size); + ssize_t read(off_t offset, unsigned char *data, ssize_t size) const; + bool write(off_t offset, unsigned char *data, ssize_t size); - // truncate the file to a particular size - int truncate( off_t size ); + // truncate the file to a particular size + int truncate(off_t size); - // datasync or full sync - int sync(bool dataSync); -private: + // datasync or full sync + int sync(bool dataSync); - // doing locking at the FileNode level isn't as efficient as at the - // lowest level of RawFileIO, since that means locks are held longer - // (held during CPU intensive crypto operations!). However it makes it - // easier to avoid any race conditions with operations such as - // truncate() which may result in multiple calls down to the FileIO - // level. - mutable Mutex mutex; + private: + // doing locking at the FileNode level isn't as efficient as at the + // lowest level of RawFileIO, since that means locks are held longer + // (held during CPU intensive crypto operations!). However it makes it + // easier to avoid any race conditions with operations such as + // truncate() which may result in multiple calls down to the FileIO + // level. + mutable Mutex mutex; - FSConfigPtr fsConfig; + FSConfigPtr fsConfig; - shared_ptr io; - std::string _pname; // plaintext name - std::string _cname; // encrypted name - DirNode *parent; - -private: - FileNode(const FileNode &src); - FileNode &operator = (const FileNode &src); + shared_ptr io; + std::string _pname; // plaintext name + std::string _cname; // encrypted name + DirNode *parent; + private: + FileNode(const FileNode &src); + FileNode &operator=(const FileNode &src); }; } // namespace encfs #endif - diff --git a/fs/FileUtils.cpp b/fs/FileUtils.cpp index 40c4195..ada05dd 100644 --- a/fs/FileUtils.cpp +++ b/fs/FileUtils.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -20,9 +20,9 @@ // defines needed for RedHat 7.3... #ifdef linux -#define _XOPEN_SOURCE 500 // make sure pwrite() is pulled in +#define _XOPEN_SOURCE 500 // make sure pwrite() is pulled in #endif -#define _BSD_SOURCE // pick up setenv on RH7.3 +#define _BSD_SOURCE // pick up setenv on RH7.3 #include "fs/encfs.h" #include "fs/fsconfig.pb.h" @@ -80,8 +80,8 @@ static const int DefaultBlockSize = 2048; // use the extpass option, as extpass can return arbitrary length binary data. static const int MaxPassBuf = 2048; -static const int NormalKDFDuration = 500; // 1/2 a second -static const int ParanoiaKDFDuration = 3000; // 3 seconds +static const int NormalKDFDuration = 500; // 1/2 a second +static const int ParanoiaKDFDuration = 3000; // 3 seconds // environment variable names for values encfs stores in the environment when // calling an external password program. @@ -89,171 +89,141 @@ static const char ENCFS_ENV_ROOTDIR[] = "encfs_root"; static const char ENCFS_ENV_STDOUT[] = "encfs_stdout"; static const char ENCFS_ENV_STDERR[] = "encfs_stderr"; -const int V5Latest = 20040813; // fix MACFileIO block size issues +const int V5Latest = 20040813; // fix MACFileIO block size issues const int ProtoSubVersion = 20120902; const char ConfigFileName[] = ".encfs.txt"; -struct ConfigInfo -{ +struct ConfigInfo { ConfigType type; const char *fileName; const char *environmentOverride; - bool (*loadFunc)(const char *fileName, - EncfsConfig &config, ConfigInfo *cfg); + bool (*loadFunc)(const char *fileName, EncfsConfig &config, ConfigInfo *cfg); } ConfigFileMapping[] = { - {Config_V7, ConfigFileName, "ENCFS_CONFIG", readProtoConfig }, - {Config_V6, ".encfs6.xml", "ENCFS6_CONFIG", readV6Config }, - // backward compatible support for older versions - {Config_V5, ".encfs5", "ENCFS5_CONFIG", readV5Config }, - {Config_V4, ".encfs4", NULL, readV4Config }, - // prehistoric - no longer support - {Config_V3, ".encfs3", NULL, NULL }, - {Config_Prehistoric, ".encfs2", NULL, NULL }, - {Config_Prehistoric, ".encfs", NULL, NULL }, - {Config_None, NULL, NULL, NULL } }; + {Config_V7, ConfigFileName, "ENCFS_CONFIG", readProtoConfig}, + {Config_V6, ".encfs6.xml", "ENCFS6_CONFIG", readV6Config}, + // backward compatible support for older versions + {Config_V5, ".encfs5", "ENCFS5_CONFIG", readV5Config}, + {Config_V4, ".encfs4", NULL, readV4Config}, + // prehistoric - no longer support + {Config_V3, ".encfs3", NULL, NULL}, + {Config_Prehistoric, ".encfs2", NULL, NULL}, + {Config_Prehistoric, ".encfs", NULL, NULL}, + {Config_None, NULL, NULL, NULL}}; -EncFS_Root::EncFS_Root() -{ -} +EncFS_Root::EncFS_Root() {} -EncFS_Root::~EncFS_Root() -{ -} +EncFS_Root::~EncFS_Root() {} - -bool fileExists( const char * fileName ) -{ +bool fileExists(const char *fileName) { struct stat buf; - if(!lstat( fileName, &buf )) - { + if (!lstat(fileName, &buf)) { return true; - } else - { + } else { // XXX show perror? return false; } } -bool isDirectory( const char *fileName ) -{ +bool isDirectory(const char *fileName) { struct stat buf; - if( !lstat( fileName, &buf )) - { - return S_ISDIR( buf.st_mode ); - } else - { + if (!lstat(fileName, &buf)) { + return S_ISDIR(buf.st_mode); + } else { return false; } } -bool isAbsolutePath( const char *fileName ) -{ - if(fileName && fileName[0] != '\0' && fileName[0] == '/') +bool isAbsolutePath(const char *fileName) { + if (fileName && fileName[0] != '\0' && fileName[0] == '/') return true; else return false; } -const char *lastPathElement( const char *name ) -{ - const char *loc = strrchr( name, '/' ); +const char *lastPathElement(const char *name) { + const char *loc = strrchr(name, '/'); return loc ? loc + 1 : name; } -std::string parentDirectory( const std::string &path ) -{ - size_t last = path.find_last_of( '/' ); - if(last == string::npos) +std::string parentDirectory(const std::string &path) { + size_t last = path.find_last_of('/'); + if (last == string::npos) return string(""); else return path.substr(0, last); } -bool userAllowMkdir(const char *path, mode_t mode ) -{ - return userAllowMkdir(0, path, mode); +bool userAllowMkdir(const char *path, mode_t mode) { + return userAllowMkdir(0, path, mode); } -bool userAllowMkdir(int promptno, const char *path, mode_t mode ) -{ +bool userAllowMkdir(int promptno, const char *path, mode_t mode) { // TODO: can we internationalize the y/n names? Seems strange to prompt in // their own language but then have to respond 'y' or 'n'. // xgroup(setup) - cerr << autosprintf( _("The directory \"%s\" does not exist. " - "Should it be created? (y,n) "), path ); + cerr << autosprintf(_("The directory \"%s\" does not exist. " + "Should it be created? (y,n) "), + path); char answer[10]; char *res; - switch (promptno) - { - case 1: - cerr << endl << "$PROMPT$ create_root_dir" << endl; - break; - case 2: - cerr << endl << "$PROMPT$ create_mount_point" << endl; - break; - default: - break; + switch (promptno) { + case 1: + cerr << endl << "$PROMPT$ create_root_dir" << endl; + break; + case 2: + cerr << endl << "$PROMPT$ create_mount_point" << endl; + break; + default: + break; } - res = fgets( answer, sizeof(answer), stdin ); + res = fgets(answer, sizeof(answer), stdin); - if(res != 0 && toupper(answer[0]) == 'Y') - { - int result = mkdir( path, mode ); - if(result < 0) - { - perror( _("Unable to create directory: ") ); + if (res != 0 && toupper(answer[0]) == 'Y') { + int result = mkdir(path, mode); + if (result < 0) { + perror(_("Unable to create directory: ")); return false; } else return true; - } else - { + } else { // Directory not created, by user request cerr << _("Directory not created.") << "\n"; return false; } } -ConfigType readConfig_load( ConfigInfo *nm, const char *path, - EncfsConfig &config ) -{ - if( nm->loadFunc ) - { - try - { - if( (*nm->loadFunc)( path, config, nm )) - return nm->type; - } catch( Error &err ) - { +ConfigType readConfig_load(ConfigInfo *nm, const char *path, + EncfsConfig &config) { + if (nm->loadFunc) { + try { + if ((*nm->loadFunc)(path, config, nm)) return nm->type; + } + catch (Error &err) { LOG(WARNING) << "readConfig failed: " << err.what(); } LOG(ERROR) << "Found config file " << path << ", but failed to load"; return Config_None; - } else - { + } else { // No load function - must be an unsupported type.. return Config_None; } } -ConfigType readConfig( const string &rootDir, EncfsConfig &config ) -{ +ConfigType readConfig(const string &rootDir, EncfsConfig &config) { ConfigInfo *nm = ConfigFileMapping; - while(nm->fileName) - { + while (nm->fileName) { // allow environment variable to override default config path - if( nm->environmentOverride != NULL ) - { - char *envFile = getenv( nm->environmentOverride ); - if( envFile != NULL ) - return readConfig_load( nm, envFile, config ); + if (nm->environmentOverride != NULL) { + char *envFile = getenv(nm->environmentOverride); + if (envFile != NULL) return readConfig_load(nm, envFile, config); } // the standard place to look is in the root directory string path = rootDir + nm->fileName; - if( fileExists( path.c_str() ) ) - return readConfig_load( nm, path.c_str(), config); + if (fileExists(path.c_str())) + return readConfig_load(nm, path.c_str(), config); ++nm; } @@ -262,14 +232,11 @@ ConfigType readConfig( const string &rootDir, EncfsConfig &config ) } // Read a boost::serialization config file using an Xml reader.. -bool readV6Config( const char *configFile, - EncfsConfig &cfg, ConfigInfo *info) -{ +bool readV6Config(const char *configFile, EncfsConfig &cfg, ConfigInfo *info) { (void)info; XmlReader rdr; - if (!rdr.load(configFile)) - { + if (!rdr.load(configFile)) { LOG(ERROR) << "Failed to load config file " << configFile; return false; } @@ -291,25 +258,19 @@ bool readV6Config( const char *configFile, return false; } - // version numbering was complicated by boost::archive - if (version == 20 || version >= 20100713) - { + // version numbering was complicated by boost::archive + if (version == 20 || version >= 20100713) { VLOG(1) << "found new serialization format"; cfg.set_revision(version); - } else if (version == 26800) - { + } else if (version == 26800) { VLOG(1) << "found 20080816 version"; cfg.set_revision(20080816); - } else if (version == 26797) - { + } else if (version == 26797) { VLOG(1) << "found 20080813"; cfg.set_revision(20080813); - } else if (version < V5Latest) - { - LOG(ERROR) << "Invalid version " << version - << " - please fix config file"; - } else - { + } else if (version < V5Latest) { + LOG(ERROR) << "Invalid version " << version << " - please fix config file"; + } else { LOG(INFO) << "Boost <= 1.41 compatibility mode"; cfg.set_revision(version); } @@ -346,13 +307,12 @@ bool readV6Config( const char *configFile, config->readB64("encodedKeyData", key, encodedSize); encryptedKey->set_ciphertext(key, encodedSize); delete[] key; - + int keySize; config->read("keySize", &keySize); - encryptedKey->set_size(keySize / 8); // save as size in bytes + encryptedKey->set_size(keySize / 8); // save as size in bytes - if(cfg.revision() >= 20080816) - { + if (cfg.revision() >= 20080816) { int saltLen; config->read("saltLen", &saltLen); unsigned char *salt = new unsigned char[saltLen]; @@ -365,8 +325,7 @@ bool readV6Config( const char *configFile, config->read("desiredKDFDuration", &desiredKDFDuration); encryptedKey->set_kdf_iterations(kdfIterations); encryptedKey->set_kdf_duration(desiredKDFDuration); - } else - { + } else { encryptedKey->clear_salt(); encryptedKey->set_kdf_iterations(16); encryptedKey->clear_kdf_duration(); @@ -376,31 +335,27 @@ bool readV6Config( const char *configFile, } // Read a v5 archive, which is a proprietary binary format. -bool readV5Config( const char *configFile, - EncfsConfig &config, ConfigInfo *) -{ +bool readV5Config(const char *configFile, EncfsConfig &config, ConfigInfo *) { bool ok = false; // use Config to parse the file and query it.. ConfigReader cfgRdr; - if(cfgRdr.load( configFile )) - { - try - { + if (cfgRdr.load(configFile)) { + try { config.set_revision(cfgRdr["subVersion"].readInt(0)); - if(config.revision() > V5Latest) - { + if (config.revision() > V5Latest) { /* config file specifies a version outside our supported range.. */ - LOG(ERROR) << "Config subversion " << config.revision() - << " found, but this version of encfs only supports up to version " - << V5Latest; + LOG(ERROR) + << "Config subversion " << config.revision() + << " found, but this version of encfs only supports up to version " + << V5Latest; return false; } - if( config.revision() < V5Latest ) - { - LOG(ERROR) << "This version of EncFS doesn't support " - << "filesystems created with EncFS releases before 2004-08-13"; + if (config.revision() < V5Latest) { + LOG(ERROR) + << "This version of EncFS doesn't support " + << "filesystems created with EncFS releases before 2004-08-13"; return false; } @@ -418,17 +373,17 @@ bool readV5Config( const char *configFile, encryptedKey->set_size(keySize / 8); cfgRdr["keyData"] >> (*encryptedKey->mutable_ciphertext()); - config.set_unique_iv( cfgRdr["uniqueIV"].readBool( false ) ); - config.set_chained_iv( cfgRdr["chainedIV"].readBool( false ) ); - config.set_external_iv( cfgRdr["externalIV"].readBool( false ) ); - config.set_block_mac_bytes( cfgRdr["blockMACBytes"].readInt(0) ); - config.set_block_mac_rand_bytes( cfgRdr["blockMACRandBytes"].readInt(0) ); + config.set_unique_iv(cfgRdr["uniqueIV"].readBool(false)); + config.set_chained_iv(cfgRdr["chainedIV"].readBool(false)); + config.set_external_iv(cfgRdr["externalIV"].readBool(false)); + config.set_block_mac_bytes(cfgRdr["blockMACBytes"].readInt(0)); + config.set_block_mac_rand_bytes(cfgRdr["blockMACRandBytes"].readInt(0)); ok = true; - } catch( Error &err) - { - LOG(WARNING) << "Error parsing data in config file " << configFile - << "; " << err.what(); + } + catch (Error &err) { + LOG(WARNING) << "Error parsing data in config file " << configFile << "; " + << err.what(); ok = false; } } @@ -436,17 +391,13 @@ bool readV5Config( const char *configFile, return ok; } -bool readV4Config( const char *configFile, - EncfsConfig &config, ConfigInfo *) -{ +bool readV4Config(const char *configFile, EncfsConfig &config, ConfigInfo *) { bool ok = false; // use Config to parse the file and query it.. ConfigReader cfgRdr; - if(cfgRdr.load( configFile )) - { - try - { + if (cfgRdr.load(configFile)) { + try { cfgRdr["cipher"] >> (*config.mutable_cipher()); int blockSize; cfgRdr["blockSize"] >> blockSize; @@ -456,14 +407,15 @@ bool readV4Config( const char *configFile, cfgRdr["keyData"] >> (*key->mutable_ciphertext()); // fill in default for V4 - config.mutable_naming()->MergeFrom( makeInterface("nameio/stream", 1, 0, 0) ); - config.set_creator( "EncFS 1.0.x" ); + config.mutable_naming()->MergeFrom( + makeInterface("nameio/stream", 1, 0, 0)); + config.set_creator("EncFS 1.0.x"); ok = true; - } catch( Error &err) - { - LOG(WARNING) << "Error parsing config file " << configFile - << ": " << err.what(); + } + catch (Error &err) { + LOG(WARNING) << "Error parsing config file " << configFile << ": " + << err.what(); ok = false; } } @@ -471,44 +423,38 @@ bool readV4Config( const char *configFile, return ok; } -bool writeTextConfig( const char *fileName, const EncfsConfig &cfg ) -{ - int fd = ::open( fileName, O_RDWR | O_CREAT, 0640 ); - if (fd < 0) - { +bool writeTextConfig(const char *fileName, const EncfsConfig &cfg) { + int fd = ::open(fileName, O_RDWR | O_CREAT, 0640); + if (fd < 0) { LOG(ERROR) << "Unable to open or create file " << fileName; return false; } - google::protobuf::io::FileOutputStream fos( fd ); - google::protobuf::TextFormat::Print( cfg, &fos ); + google::protobuf::io::FileOutputStream fos(fd); + google::protobuf::TextFormat::Print(cfg, &fos); fos.Close(); return true; } -bool saveConfig( const string &rootDir, const EncfsConfig &config ) -{ +bool saveConfig(const string &rootDir, const EncfsConfig &config) { bool ok = false; ConfigInfo *nm = ConfigFileMapping; - + // TODO(vgough): remove old config after saving a new one? string path = rootDir + ConfigFileName; - if( nm->environmentOverride != NULL ) - { + if (nm->environmentOverride != NULL) { // use environment file if specified.. - const char *envFile = getenv( nm->environmentOverride ); - if( envFile != NULL ) - path.assign( envFile ); + const char *envFile = getenv(nm->environmentOverride); + if (envFile != NULL) path.assign(envFile); } - try - { - const_cast(config).set_writer("EncFS " VERSION ); - ok = writeTextConfig( path.c_str(), config ); - } catch( Error &err ) - { + try { + const_cast(config).set_writer("EncFS " VERSION); + ok = writeTextConfig(path.c_str(), config); + } + catch (Error &err) { LOG(WARNING) << "saveConfig failed: " << err.what(); ok = false; } @@ -516,31 +462,24 @@ bool saveConfig( const string &rootDir, const EncfsConfig &config ) return ok; } -bool readProtoConfig( const char *fileName, EncfsConfig &config, - struct ConfigInfo *) -{ - int fd = ::open( fileName, O_RDONLY, 0640 ); - if (fd < 0) - { +bool readProtoConfig(const char *fileName, EncfsConfig &config, + struct ConfigInfo *) { + int fd = ::open(fileName, O_RDONLY, 0640); + if (fd < 0) { LOG(ERROR) << "Unable to open file " << fileName; return false; } - google::protobuf::io::FileInputStream fis( fd ); - google::protobuf::TextFormat::Parse( &fis, &config ); + google::protobuf::io::FileInputStream fis(fd); + google::protobuf::TextFormat::Parse(&fis, &config); return true; } -static -CipherV1::CipherAlgorithm findCipherAlgorithm(const char *name, - int keySize ) -{ - for (auto &it : CipherV1::GetAlgorithmList()) - { - if( !strcmp( name, it.name.c_str() ) - && it.keyLength.allowed( keySize )) - { +static CipherV1::CipherAlgorithm findCipherAlgorithm(const char *name, + int keySize) { + for (auto &it : CipherV1::GetAlgorithmList()) { + if (!strcmp(name, it.name.c_str()) && it.keyLength.allowed(keySize)) { return it; } } @@ -549,112 +488,95 @@ CipherV1::CipherAlgorithm findCipherAlgorithm(const char *name, return result; } -static -CipherV1::CipherAlgorithm selectCipherAlgorithm() -{ - for(;;) - { +static CipherV1::CipherAlgorithm selectCipherAlgorithm() { + for (;;) { // figure out what cipher they want to use.. // xgroup(setup) cout << _("The following cipher algorithms are available:") << "\n"; int optNum = 0; auto algorithms = CipherV1::GetAlgorithmList(); - for (auto &it : algorithms) - { - cout << ++optNum << ". " << it.name - << " : " << gettext(it.description.c_str()) << "\n"; - if(it.keyLength.min() == it.keyLength.max()) - { + for (auto &it : algorithms) { + cout << ++optNum << ". " << it.name << " : " + << gettext(it.description.c_str()) << "\n"; + if (it.keyLength.min() == it.keyLength.max()) { // shown after algorithm name and description. // xgroup(setup) - cout << autosprintf(_(" -- key length %i bits") - , it.keyLength.min()) << "\n"; - } else - { + cout << autosprintf(_(" -- key length %i bits"), it.keyLength.min()) + << "\n"; + } else { cout << autosprintf( - // shown after algorithm name and description. - // xgroup(setup) - _(" -- Supports key lengths of %i to %i bits"), - it.keyLength.min(), it.keyLength.max()) << "\n"; + // shown after algorithm name and description. + // xgroup(setup) + _(" -- Supports key lengths of %i to %i bits"), + it.keyLength.min(), it.keyLength.max()) << "\n"; } - if(it.blockSize.min() == it.blockSize.max()) - { + if (it.blockSize.min() == it.blockSize.max()) { cout << autosprintf( - // shown after algorithm name and description. - // xgroup(setup) - _(" -- block size %i bytes"), it.blockSize.min()) - << "\n"; - } else - { + // shown after algorithm name and description. + // xgroup(setup) + _(" -- block size %i bytes"), it.blockSize.min()) << "\n"; + } else { cout << autosprintf( - // shown after algorithm name and description. - // xgroup(setup) - _(" -- Supports block sizes of %i to %i bytes"), - it.blockSize.min(), it.blockSize.max()) << "\n"; + // shown after algorithm name and description. + // xgroup(setup) + _(" -- Supports block sizes of %i to %i bytes"), + it.blockSize.min(), it.blockSize.max()) << "\n"; } } // xgroup(setup) cout << "\n" << _("Enter the number corresponding to your choice: "); char answer[10]; - char *res = fgets( answer, sizeof(answer), stdin ); - int cipherNum = (res == 0 ? 0 : atoi( answer )); + char *res = fgets(answer, sizeof(answer), stdin); + int cipherNum = (res == 0 ? 0 : atoi(answer)); cout << "\n"; - if( cipherNum < 1 || cipherNum > (int)algorithms.size() ) - { + if (cipherNum < 1 || cipherNum > (int)algorithms.size()) { cerr << _("Invalid selection.") << "\n"; continue; } CipherV1::CipherAlgorithm alg; - for (auto &it : algorithms) - { - if (!--cipherNum) - { + for (auto &it : algorithms) { + if (!--cipherNum) { alg = it; break; } } // xgroup(setup) - cout << autosprintf(_("Selected algorithm \"%s\""), alg.name.c_str()) - << "\n\n"; + cout << autosprintf(_("Selected algorithm \"%s\""), alg.name.c_str()) + << "\n\n"; return alg; } } -static -Interface selectNameCoding(const CipherV1::CipherAlgorithm &alg) -{ - for(;;) - { +static Interface selectNameCoding(const CipherV1::CipherAlgorithm &alg) { + for (;;) { // figure out what cipher they want to use.. // xgroup(setup) cout << _("The following filename encoding algorithms are available:") - << "\n"; + << "\n"; NameIO::AlgorithmList algorithms = NameIO::GetAlgorithmList(); NameIO::AlgorithmList::const_iterator it; int optNum = 1; map algMap; - for(it = algorithms.begin(); it != algorithms.end(); ++it) - { - cout << optNum << ". " << it->name - << " : " << gettext(it->description.c_str()) << "\n"; + for (it = algorithms.begin(); it != algorithms.end(); ++it) { + cout << optNum << ". " << it->name << " : " + << gettext(it->description.c_str()) << "\n"; algMap[optNum++] = it; } // xgroup(setup) cout << "\n" << _("Enter the number corresponding to your choice: "); char answer[10]; - char *res = fgets( answer, sizeof(answer), stdin ); - int algNum = (res == 0 ? 0 : atoi( answer )); + char *res = fgets(answer, sizeof(answer), stdin); + int algNum = (res == 0 ? 0 : atoi(answer)); cout << "\n"; - if( algNum < 1 || algNum >= optNum ) - { + if (algNum < 1 || algNum >= optNum) { cerr << _("Invalid selection.") << "\n"; continue; } @@ -662,61 +584,55 @@ Interface selectNameCoding(const CipherV1::CipherAlgorithm &alg) it = algMap[algNum]; // xgroup(setup) - cout << autosprintf(_("Selected algorithm \"%s\""), it->name.c_str()) - << "\"\n\n"; + cout << autosprintf(_("Selected algorithm \"%s\""), it->name.c_str()) + << "\"\n\n"; return it->iface; } } static int selectKDFDuration() { - cout << autosprintf(_("Select desired KDF duration in milliseconds.\n" - "The default is 500 (half a second): ")); + cout << autosprintf( + _("Select desired KDF duration in milliseconds.\n" + "The default is 500 (half a second): ")); char answer[10]; - char *res = fgets( answer, sizeof(answer), stdin ); - int duration = (res == 0 ? 0 : atoi( answer )); + char *res = fgets(answer, sizeof(answer), stdin); + int duration = (res == 0 ? 0 : atoi(answer)); cout << "\n"; return duration; } -static -int selectKeySize( const CipherV1::CipherAlgorithm &alg ) -{ - if(alg.keyLength.min() == alg.keyLength.max()) - { - cout << autosprintf(_("Using key size of %i bits"), - alg.keyLength.min()) << "\n"; +static int selectKeySize(const CipherV1::CipherAlgorithm &alg) { + if (alg.keyLength.min() == alg.keyLength.max()) { + cout << autosprintf(_("Using key size of %i bits"), alg.keyLength.min()) + << "\n"; return alg.keyLength.min(); } - cout << autosprintf( - // xgroup(setup) - _("Please select a key size in bits. The cipher you have chosen\n" - "supports sizes from %i to %i bits in increments of %i bits.\n" - "For example: "), alg.keyLength.min(), alg.keyLength.max(), - alg.keyLength.inc()) << "\n"; + cout + << autosprintf( + // xgroup(setup) + _("Please select a key size in bits. The cipher you have chosen\n" + "supports sizes from %i to %i bits in increments of %i bits.\n" + "For example: "), + alg.keyLength.min(), alg.keyLength.max(), alg.keyLength.inc()) + << "\n"; - int numAvail = (alg.keyLength.max() - alg.keyLength.min()) - / alg.keyLength.inc(); + int numAvail = + (alg.keyLength.max() - alg.keyLength.min()) / alg.keyLength.inc(); - if(numAvail < 5) - { + if (numAvail < 5) { // show them all - for(int i=0; i<=numAvail; ++i) - { - if(i) - cout << ", "; + for (int i = 0; i <= numAvail; ++i) { + if (i) cout << ", "; cout << alg.keyLength.min() + i * alg.keyLength.inc(); } - } else - { + } else { // partial - for(int i=0; i<3; ++i) - { - if(i) - cout << ", "; + for (int i = 0; i < 3; ++i) { + if (i) cout << ", "; cout << alg.keyLength.min() + i * alg.keyLength.inc(); } cout << " ... " << alg.keyLength.max() - alg.keyLength.inc(); @@ -726,11 +642,11 @@ int selectKeySize( const CipherV1::CipherAlgorithm &alg ) cout << "\n" << _("Selected key size: "); char answer[10]; - char *res = fgets( answer, sizeof(answer), stdin ); - int keySize = (res == 0 ? 0 : atoi( answer )); + char *res = fgets(answer, sizeof(answer), stdin); + int keySize = (res == 0 ? 0 : atoi(answer)); cout << "\n"; - keySize = alg.keyLength.closest( keySize ); + keySize = alg.keyLength.closest(keySize); // xgroup(setup) cout << autosprintf(_("Using key size of %i bits"), keySize) << "\n\n"; @@ -738,66 +654,58 @@ int selectKeySize( const CipherV1::CipherAlgorithm &alg ) return keySize; } -static -int selectBlockSize( const CipherV1::CipherAlgorithm &alg ) -{ - if(alg.blockSize.min() == alg.blockSize.max()) - { +static int selectBlockSize(const CipherV1::CipherAlgorithm &alg) { + if (alg.blockSize.min() == alg.blockSize.max()) { cout << autosprintf( - // xgroup(setup) - _("Using filesystem block size of %i bytes"), - alg.blockSize.min()) << "\n"; + // xgroup(setup) + _("Using filesystem block size of %i bytes"), + alg.blockSize.min()) << "\n"; return alg.blockSize.min(); } cout << autosprintf( - // xgroup(setup) - _("Select a block size in bytes. The cipher you have chosen\n" - "supports sizes from %i to %i bytes in increments of %i.\n" - "Or just hit enter for the default (%i bytes)\n"), - alg.blockSize.min(), alg.blockSize.max(), alg.blockSize.inc(), - DefaultBlockSize); + // xgroup(setup) + _("Select a block size in bytes. The cipher you have chosen\n" + "supports sizes from %i to %i bytes in increments of %i.\n" + "Or just hit enter for the default (%i bytes)\n"), + alg.blockSize.min(), alg.blockSize.max(), alg.blockSize.inc(), + DefaultBlockSize); // xgroup(setup) cout << "\n" << _("filesystem block size: "); int blockSize = DefaultBlockSize; char answer[10]; - char *res = fgets( answer, sizeof(answer), stdin ); + char *res = fgets(answer, sizeof(answer), stdin); cout << "\n"; - if( res != 0 && atoi( answer ) >= alg.blockSize.min() ) - blockSize = atoi( answer ); + if (res != 0 && atoi(answer) >= alg.blockSize.min()) blockSize = atoi(answer); - blockSize = alg.blockSize.closest( blockSize ); + blockSize = alg.blockSize.closest(blockSize); // xgroup(setup) - cout << autosprintf(_("Using filesystem block size of %i bytes"), - blockSize) << "\n\n"; + cout << autosprintf(_("Using filesystem block size of %i bytes"), blockSize) + << "\n\n"; return blockSize; } -static -bool boolDefaultNo(const char *prompt) -{ +static bool boolDefaultNo(const char *prompt) { cout << prompt << "\n"; cout << _("The default here is No.\n" - "Any response that does not begin with 'y' will mean No: "); + "Any response that does not begin with 'y' will mean No: "); char answer[10]; - char *res = fgets( answer, sizeof(answer), stdin ); + char *res = fgets(answer, sizeof(answer), stdin); cout << "\n"; - if(res != 0 && tolower(answer[0]) == 'y') + if (res != 0 && tolower(answer[0]) == 'y') return true; else return false; } -static -void selectBlockMAC(int *macBytes, int *macRandBytes) -{ +static void selectBlockMAC(int *macBytes, int *macRandBytes) { // xgroup(setup) bool addMAC = boolDefaultNo( _("Enable block authentication code headers\n" @@ -806,54 +714,48 @@ void selectBlockMAC(int *macBytes, int *macRandBytes) "performance but it also means [almost] any modifications or errors\n" "within a block will be caught and will cause a read error.")); - if(addMAC) + if (addMAC) *macBytes = 8; else *macBytes = 0; // xgroup(setup) cout << _("Add random bytes to each block header?\n" - "This adds a performance penalty, but ensures that blocks\n" - "have different authentication codes. Note that you can\n" - "have the same benefits by enabling per-file initialization\n" - "vectors, which does not come with as great of performance\n" - "penalty. \n" - "Select a number of bytes, from 0 (no random bytes) to 8: "); + "This adds a performance penalty, but ensures that blocks\n" + "have different authentication codes. Note that you can\n" + "have the same benefits by enabling per-file initialization\n" + "vectors, which does not come with as great of performance\n" + "penalty. \n" + "Select a number of bytes, from 0 (no random bytes) to 8: "); char answer[10]; int randSize = 0; - char *res = fgets( answer, sizeof(answer), stdin ); + char *res = fgets(answer, sizeof(answer), stdin); cout << "\n"; - randSize = (res == 0 ? 0 : atoi( answer )); - if(randSize < 0) - randSize = 0; - if(randSize > 8) - randSize = 8; + randSize = (res == 0 ? 0 : atoi(answer)); + if (randSize < 0) randSize = 0; + if (randSize > 8) randSize = 8; *macRandBytes = randSize; } -static -bool boolDefaultYes(const char *prompt) -{ +static bool boolDefaultYes(const char *prompt) { cout << prompt << "\n"; cout << _("The default here is Yes.\n" - "Any response that does not begin with 'n' will mean Yes: "); + "Any response that does not begin with 'n' will mean Yes: "); char answer[10]; - char *res = fgets( answer, sizeof(answer), stdin ); + char *res = fgets(answer, sizeof(answer), stdin); cout << "\n"; - if(res != 0 && tolower(answer[0]) == 'n') + if (res != 0 && tolower(answer[0]) == 'n') return false; else return true; } -static -bool selectUniqueIV() -{ +static bool selectUniqueIV() { // xgroup(setup) return boolDefaultYes( _("Enable per-file initialization vectors?\n" @@ -862,9 +764,7 @@ bool selectUniqueIV() "which rely on block-aligned file io for performance.")); } -static -bool selectChainedIV() -{ +static bool selectChainedIV() { // xgroup(setup) return boolDefaultYes( _("Enable filename initialization vector chaining?\n" @@ -872,9 +772,7 @@ bool selectChainedIV() "rather than encoding each path element individually.")); } -static -bool selectExternalChainedIV() -{ +static bool selectExternalChainedIV() { // xgroup(setup) return boolDefaultNo( _("Enable filename to IV header chaining?\n" @@ -885,18 +783,14 @@ bool selectExternalChainedIV() "in the filesystem.")); } -static -bool selectZeroBlockPassThrough() -{ +static bool selectZeroBlockPassThrough() { // xgroup(setup) return boolDefaultYes( _("Enable file-hole pass-through?\n" "This avoids writing encrypted blocks when file holes are created.")); } -RootPtr createConfig( EncFS_Context *ctx, - const shared_ptr &opts ) -{ +RootPtr createConfig(EncFS_Context *ctx, const shared_ptr &opts) { const std::string rootDir = opts->rootDir; bool enableIdleTracking = opts->idleTracking; bool forceDecode = opts->forceDecode; @@ -914,19 +808,17 @@ RootPtr createConfig( EncFS_Context *ctx, cout << _("Creating new encrypted volume.") << endl; char answer[10] = {0}; - if(configMode == Config_Prompt) - { + if (configMode == Config_Prompt) { // xgroup(setup) cout << _("Please choose from one of the following options:\n" - " enter \"x\" for expert configuration mode,\n" - " enter \"p\" for pre-configured paranoia mode,\n" - " anything else, or an empty line will select standard mode.\n" - "?> "); + " enter \"x\" for expert configuration mode,\n" + " enter \"p\" for pre-configured paranoia mode,\n" + " anything else, or an empty line will select standard mode.\n" + "?> "); - if (annotate) - cerr << "$PROMPT$ config_option" << endl; + if (annotate) cerr << "$PROMPT$ config_option" << endl; - char *res = fgets( answer, sizeof(answer), stdin ); + char *res = fgets(answer, sizeof(answer), stdin); (void)res; cout << "\n"; } @@ -943,8 +835,7 @@ RootPtr createConfig( EncFS_Context *ctx, bool allowHoles = true; long desiredKDFDuration = NormalKDFDuration; - if (reverseEncryption) - { + if (reverseEncryption) { uniqueIV = false; chainedIV = false; externalIV = false; @@ -952,10 +843,8 @@ RootPtr createConfig( EncFS_Context *ctx, blockMACRandBytes = 0; } - if(configMode == Config_Paranoia || answer[0] == 'p') - { - if (reverseEncryption) - { + if (configMode == Config_Paranoia || answer[0] == 'p') { + if (reverseEncryption) { LOG(ERROR) << "Paranoia configuration not supported for --reverse"; return rootInfo; } @@ -972,13 +861,12 @@ RootPtr createConfig( EncFS_Context *ctx, alg = findCipherAlgorithm("AES", keySize); nameIOIface = BlockNameIO::CurrentInterface(); blockMACBytes = 8; - blockMACRandBytes = 0; // using uniqueIV, so this isn't necessary + 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') - { + } else if (configMode == Config_Standard || answer[0] != 'x') { // xgroup(setup) cout << _("Standard configuration selected.") << "\n"; // AES w/ 192 bit key, block name encoding, per-file initialization @@ -990,27 +878,21 @@ RootPtr createConfig( EncFS_Context *ctx, externalIV = false; nameIOIface = BlockNameIO::CurrentInterface(); - if (reverseEncryption) - { - cout << _("--reverse specified, not using unique/chained IV") - << "\n"; - } else - { + if (reverseEncryption) { + cout << _("--reverse specified, not using unique/chained IV") << "\n"; + } else { uniqueIV = true; chainedIV = true; } } - if(answer[0] == 'x' || alg.name.empty()) - { - if(answer[0] != 'x') - { + if (answer[0] == 'x' || alg.name.empty()) { + if (answer[0] != 'x') { // xgroup(setup) cout << _("Sorry, unable to locate cipher for predefined " - "configuration...\n" - "Falling through to Manual configuration mode."); - } else - { + "configuration...\n" + "Falling through to Manual configuration mode."); + } else { // xgroup(setup) cout << _("Manual configuration mode selected."); } @@ -1018,24 +900,21 @@ RootPtr createConfig( EncFS_Context *ctx, // query user for settings.. alg = selectCipherAlgorithm(); - keySize = selectKeySize( alg ); - blockSize = selectBlockSize( alg ); - nameIOIface = selectNameCoding( alg ); - if (reverseEncryption) - { + keySize = selectKeySize(alg); + blockSize = selectBlockSize(alg); + nameIOIface = selectNameCoding(alg); + if (reverseEncryption) { cout << _("--reverse specified, not using unique/chained IV") << "\n"; - } else - { + } else { chainedIV = selectChainedIV(); uniqueIV = selectUniqueIV(); - if(chainedIV && uniqueIV) + if (chainedIV && uniqueIV) externalIV = selectExternalChainedIV(); - else - { + else { // xgroup(setup) cout << _("External chained IV disabled, as both 'IV chaining'\n" - "and 'unique IV' features are required for this option.") - << "\n"; + "and 'unique IV' features are required for this option.") + << "\n"; externalIV = false; } selectBlockMAC(&blockMACBytes, &blockMACRandBytes); @@ -1044,112 +923,102 @@ RootPtr createConfig( EncFS_Context *ctx, desiredKDFDuration = selectKDFDuration(); } - shared_ptr cipher = CipherV1::New( alg.iface, keySize ); - if(!cipher) - { - LOG(ERROR) << "Unable to instanciate cipher " << alg.name - << ", key size " << keySize << ", block size " << blockSize; + shared_ptr cipher = CipherV1::New(alg.iface, keySize); + if (!cipher) { + LOG(ERROR) << "Unable to instanciate cipher " << alg.name << ", key size " + << keySize << ", block size " << blockSize; return rootInfo; - } else - { - VLOG(1) << "Using cipher " << alg.name - << ", key size " << keySize << ", block size " << blockSize; + } else { + VLOG(1) << "Using cipher " << alg.name << ", key size " << keySize + << ", block size " << blockSize; } EncfsConfig config; - config.mutable_cipher()->MergeFrom( cipher->interface() ); - config.set_block_size( blockSize ); - config.mutable_naming()->MergeFrom( nameIOIface ); - config.set_creator( "EncFS " VERSION ); - config.set_revision( ProtoSubVersion ); - config.set_block_mac_bytes( blockMACBytes ); - config.set_block_mac_rand_bytes( blockMACRandBytes ); - config.set_unique_iv( uniqueIV ); - config.set_chained_iv( chainedIV ); - config.set_external_iv( externalIV ); - config.set_allow_holes( allowHoles ); + config.mutable_cipher()->MergeFrom(cipher->interface()); + config.set_block_size(blockSize); + config.mutable_naming()->MergeFrom(nameIOIface); + config.set_creator("EncFS " VERSION); + config.set_revision(ProtoSubVersion); + config.set_block_mac_bytes(blockMACBytes); + config.set_block_mac_rand_bytes(blockMACRandBytes); + config.set_unique_iv(uniqueIV); + config.set_chained_iv(chainedIV); + config.set_external_iv(externalIV); + config.set_allow_holes(allowHoles); EncryptedKey *key = config.mutable_key(); key->clear_salt(); - key->clear_kdf_iterations(); // filled in by keying function - key->set_kdf_duration( desiredKDFDuration ); + key->clear_kdf_iterations(); // filled in by keying function + key->set_kdf_duration(desiredKDFDuration); key->set_size(keySize / 8); cout << "\n"; // xgroup(setup) cout << _("Configuration finished. The filesystem to be created has\n" - "the following properties:") << endl; - showFSInfo( config ); + "the following properties:") << endl; + showFSInfo(config); - if( config.external_iv() ) - { - cout << - _("-------------------------- WARNING --------------------------\n") - << - _("The external initialization-vector chaining option has been\n" - "enabled. This option disables the use of hard links on the\n" - "filesystem. Without hard links, some programs may not work.\n" - "The programs 'mutt' and 'procmail' are known to fail. For\n" - "more information, please see the encfs mailing list.\n" - "If you would like to choose another configuration setting,\n" - "please press CTRL-C now to abort and start over.") << endl; + if (config.external_iv()) { + cout << _("-------------------------- WARNING --------------------------\n") + << _("The external initialization-vector chaining option has been\n" + "enabled. This option disables the use of hard links on the\n" + "filesystem. Without hard links, some programs may not work.\n" + "The programs 'mutt' and 'procmail' are known to fail. For\n" + "more information, please see the encfs mailing list.\n" + "If you would like to choose another configuration setting,\n" + "please press CTRL-C now to abort and start over.") << endl; cout << endl; } // xgroup(setup) cout << _("Now you will need to enter a password for your filesystem.\n" - "You will need to remember this password, as there is absolutely\n" - "no recovery mechanism. However, the password can be changed\n" - "later using encfsctl.\n\n"); + "You will need to remember this password, as there is absolutely\n" + "no recovery mechanism. However, the password can be changed\n" + "later using encfsctl.\n\n"); int encodedKeySize = cipher->encodedKeySize(); - unsigned char *encodedKey = new unsigned char[ encodedKeySize ]; + unsigned char *encodedKey = new unsigned char[encodedKeySize]; CipherKey volumeKey = cipher->newRandomKey(); // get user key and use it to encode volume key CipherKey userKey; VLOG(1) << "useStdin: " << useStdin; - if(useStdin) - { - if (annotate) - cerr << "$PROMPT$ new_passwd" << endl; + if (useStdin) { + if (annotate) cerr << "$PROMPT$ new_passwd" << endl; } - userKey = getNewUserKey( config, useStdin, passwordProgram, rootDir ); + userKey = getNewUserKey(config, useStdin, passwordProgram, rootDir); - cipher->setKey( userKey ); - cipher->writeKey( volumeKey, encodedKey ); + cipher->setKey(userKey); + cipher->writeKey(volumeKey, encodedKey); userKey.reset(); key->set_ciphertext(encodedKey, encodedKeySize); delete[] encodedKey; - if(!volumeKey.valid()) - { + if (!volumeKey.valid()) { LOG(ERROR) << "Failure generating new volume key! " - << "Please report this error."; + << "Please report this error."; return rootInfo; } - cipher->setKey( volumeKey ); - if(!saveConfig( rootDir, config )) - return rootInfo; + cipher->setKey(volumeKey); + if (!saveConfig(rootDir, config)) return rootInfo; // fill in config struct - shared_ptr nameCoder = NameIO::New( config.naming(), cipher ); - if(!nameCoder) - { + shared_ptr nameCoder = NameIO::New(config.naming(), cipher); + if (!nameCoder) { LOG(WARNING) << "Name coding interface not supported"; - cout << _("The filename encoding interface requested is not available") - << endl; + cout << _("The filename encoding interface requested is not available") + << endl; return rootInfo; } - nameCoder->setChainedNameIV( config.chained_iv() ); - nameCoder->setReverseEncryption( reverseEncryption ); + nameCoder->setChainedNameIV(config.chained_iv()); + nameCoder->setReverseEncryption(reverseEncryption); - FSConfigPtr fsConfig (new FSConfig); + FSConfigPtr fsConfig(new FSConfig); fsConfig->cipher = cipher; fsConfig->key = volumeKey; fsConfig->nameCoding = nameCoder; @@ -1159,37 +1028,33 @@ RootPtr createConfig( EncFS_Context *ctx, fsConfig->idleTracking = enableIdleTracking; fsConfig->opts = opts; - rootInfo = RootPtr( new EncFS_Root ); + rootInfo = RootPtr(new EncFS_Root); rootInfo->cipher = cipher; rootInfo->volumeKey = volumeKey; - rootInfo->root = shared_ptr( - new DirNode( ctx, rootDir, fsConfig )); + rootInfo->root = shared_ptr(new DirNode(ctx, rootDir, fsConfig)); return rootInfo; } -void showFSInfo( const EncfsConfig &config ) -{ - shared_ptr cipher = CipherV1::New( config.cipher(), - config.key().size() ); +void showFSInfo(const EncfsConfig &config) { + shared_ptr cipher = + CipherV1::New(config.cipher(), config.key().size()); { cout << autosprintf( - // xgroup(diag) - _("Filesystem cipher: \"%s\", version %i:%i:%i"), - config.cipher().name().c_str(), config.cipher().major(), - config.cipher().minor(), config.cipher().age()); + // xgroup(diag) + _("Filesystem cipher: \"%s\", version %i:%i:%i"), + config.cipher().name().c_str(), config.cipher().major(), + config.cipher().minor(), config.cipher().age()); // check if we support this interface.. - if(!cipher) + if (!cipher) cout << _(" (NOT supported)\n"); - else - { + else { // if we're using a newer interface, show the version number - if( config.cipher() != cipher->interface() ) - { + if (config.cipher() != cipher->interface()) { Interface iface = cipher->interface(); // xgroup(diag) - cout << autosprintf(_(" (using %i:%i:%i)\n"), - iface.major(), iface.minor(), iface.age()); + cout << autosprintf(_(" (using %i:%i:%i)\n"), iface.major(), + iface.minor(), iface.age()); } else cout << "\n"; } @@ -1197,28 +1062,23 @@ void showFSInfo( const EncfsConfig &config ) // xgroup(diag) cout << autosprintf(_("Filename encoding: \"%s\", version %i:%i:%i"), - config.naming().name().c_str(), config.naming().major(), - config.naming().minor(), config.naming().age()); - - if (!cipher) - { - cout << "\n"; - } else - { + config.naming().name().c_str(), config.naming().major(), + config.naming().minor(), config.naming().age()); + + if (!cipher) { + cout << "\n"; + } else { // check if we support the filename encoding interface.. - shared_ptr nameCoder = NameIO::New( config.naming(), cipher ); - if(!nameCoder) - { + shared_ptr nameCoder = NameIO::New(config.naming(), cipher); + if (!nameCoder) { // xgroup(diag) cout << _(" (NOT supported)\n"); - } else - { + } else { // if we're using a newer interface, show the version number - if( config.naming() != nameCoder->interface() ) - { + if (config.naming() != nameCoder->interface()) { Interface iface = nameCoder->interface(); - cout << autosprintf(_(" (using %i:%i:%i)\n"), - iface.major(), iface.minor(), iface.age()); + cout << autosprintf(_(" (using %i:%i:%i)\n"), iface.major(), + iface.minor(), iface.age()); } else cout << "\n"; } @@ -1227,125 +1087,108 @@ void showFSInfo( const EncfsConfig &config ) { cout << autosprintf(_("Key Size: %i bits"), 8 * key.size()); cipher = getCipher(config); - if(!cipher) - { + if (!cipher) { // xgroup(diag) cout << _(" (NOT supported)\n"); } else cout << "\n"; } - if(key.kdf_iterations() > 0 && key.salt().size() > 0) - { - cout << autosprintf(_("Using PBKDF2, with %i iterations"), - key.kdf_iterations()) << "\n"; - cout << autosprintf(_("Salt Size: %i bits"), - 8*(int)key.salt().size()) << "\n"; + if (key.kdf_iterations() > 0 && key.salt().size() > 0) { + cout << autosprintf(_("Using PBKDF2, with %i iterations"), + key.kdf_iterations()) << "\n"; + cout << autosprintf(_("Salt Size: %i bits"), 8 * (int)key.salt().size()) + << "\n"; } - if(config.block_mac_bytes() || config.block_mac_rand_bytes()) - { - if(config.revision() < V5Latest) - { + if (config.block_mac_bytes() || config.block_mac_rand_bytes()) { + if (config.revision() < V5Latest) { cout << autosprintf( - // xgroup(diag) - _("Block Size: %i bytes + %i byte MAC header"), - config.block_size(), - config.block_mac_bytes() + config.block_mac_rand_bytes()) << endl; - } else - { + // xgroup(diag) + _("Block Size: %i bytes + %i byte MAC header"), + config.block_size(), + config.block_mac_bytes() + config.block_mac_rand_bytes()) + << endl; + } else { // new version stores the header as part of that block size.. cout << autosprintf( - // xgroup(diag) - _("Block Size: %i bytes, including %i byte MAC header"), - config.block_size(), - config.block_mac_bytes() + config.block_mac_rand_bytes()) << endl; + // xgroup(diag) + _("Block Size: %i bytes, including %i byte MAC header"), + config.block_size(), + config.block_mac_bytes() + config.block_mac_rand_bytes()) + << endl; } - } else - { + } else { // xgroup(diag) cout << autosprintf(_("Block Size: %i bytes"), config.block_size()); cout << "\n"; } - if(config.unique_iv()) - { + if (config.unique_iv()) { // xgroup(diag) cout << _("Each file contains 8 byte header with unique IV data.\n"); } - if(config.chained_iv()) - { + if (config.chained_iv()) { // xgroup(diag) cout << _("Filenames encoded using IV chaining mode.\n"); } - if(config.external_iv()) - { + if (config.external_iv()) { // xgroup(diag) cout << _("File data IV is chained to filename IV.\n"); } - if(config.allow_holes()) - { + if (config.allow_holes()) { // xgroup(diag) cout << _("File holes passed through to ciphertext.\n"); } cout << "\n"; } -shared_ptr getCipher(const EncfsConfig &config) -{ +shared_ptr getCipher(const EncfsConfig &config) { return getCipher(config.cipher(), 8 * config.key().size()); } -shared_ptr getCipher(const Interface &iface, int keySize) -{ - return CipherV1::New( iface, keySize ); +shared_ptr getCipher(const Interface &iface, int keySize) { + return CipherV1::New(iface, keySize); } -CipherKey makeNewKey(EncfsConfig &config, const char *password, int passwdLen) -{ +CipherKey makeNewKey(EncfsConfig &config, const char *password, int passwdLen) { CipherKey userKey; shared_ptr cipher = getCipher(config); EncryptedKey *key = config.mutable_key(); unsigned char salt[20]; - if(!cipher->pseudoRandomize( salt, sizeof(salt))) - { + if (!cipher->pseudoRandomize(salt, sizeof(salt))) { cout << _("Error creating salt\n"); return userKey; } key->set_salt(salt, sizeof(salt)); int iterations = key->kdf_iterations(); - userKey = cipher->newKey(password, passwdLen, - &iterations, key->kdf_duration(), - salt, sizeof(salt)); + userKey = cipher->newKey(password, passwdLen, &iterations, + key->kdf_duration(), salt, sizeof(salt)); key->set_kdf_iterations(iterations); return userKey; } -CipherKey decryptKey(const EncfsConfig &config, const char *password, int passwdLen) -{ +CipherKey decryptKey(const EncfsConfig &config, const char *password, + int passwdLen) { const EncryptedKey &key = config.key(); CipherKey userKey; shared_ptr cipher = getCipher(config.cipher(), 8 * key.size()); - if(!key.salt().empty()) - { + if (!key.salt().empty()) { int iterations = key.kdf_iterations(); - userKey = cipher->newKey(password, passwdLen, - &iterations, key.kdf_duration(), - (const byte *)key.salt().data(), - key.salt().size()); + userKey = + cipher->newKey(password, passwdLen, &iterations, key.kdf_duration(), + (const byte *)key.salt().data(), key.salt().size()); - if (iterations != key.kdf_iterations()) - { + if (iterations != key.kdf_iterations()) { LOG(ERROR) << "Error in KDF, iteration mismatch"; return userKey; } - } else - { + } else { // old KDF, no salt.. - userKey = cipher->newKey( password, passwdLen ); + userKey = cipher->newKey(password, passwdLen); } return userKey; @@ -1353,18 +1196,15 @@ CipherKey decryptKey(const EncfsConfig &config, const char *password, int passwd // Doesn't use SecureMem, since we don't know how much will be read. // Besides, password is being produced by another program. -std::string readPassword( int FD ) -{ +std::string readPassword(int FD) { SecureMem *buf = new SecureMem(1024); string result; - while(1) - { + while (1) { ssize_t rdSize = recv(FD, buf->data(), buf->size(), 0); - if(rdSize > 0) - { - result.append( (char*)buf->data(), rdSize ); + if (rdSize > 0) { + result.append((char *)buf->data(), rdSize); } else break; } @@ -1372,39 +1212,35 @@ std::string readPassword( int FD ) // chop off trailing "\n" if present.. // This is done so that we can use standard programs like ssh-askpass // without modification, as it returns trailing newline.. - if(!result.empty() && result[ result.length()-1 ] == '\n' ) - result.resize( result.length() -1 ); + if (!result.empty() && result[result.length() - 1] == '\n') + result.resize(result.length() - 1); delete buf; return result; } SecureMem *passwordFromProgram(const std::string &passProg, - const std::string &rootDir) -{ + const std::string &rootDir) { // have a child process run the command and get the result back to us. int fds[2], pid; int res; res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); - if(res == -1) - { + if (res == -1) { perror(_("Internal error: socketpair() failed")); return NULL; } VLOG(1) << "getUserKey: fds = " << fds[0] << ", " << fds[1]; pid = fork(); - if(pid == -1) - { + if (pid == -1) { perror(_("Internal error: fork() failed")); close(fds[0]); close(fds[1]); return NULL; } - if(pid == 0) - { + if (pid == 0) { const char *argv[4]; argv[0] = "/bin/sh"; argv[1] = "-c"; @@ -1412,18 +1248,18 @@ SecureMem *passwordFromProgram(const std::string &passProg, argv[3] = 0; // child process.. run the command and send output to fds[0] - close(fds[1]); // we don't use the other half.. + close(fds[1]); // we don't use the other half.. // make a copy of stdout and stderr descriptors, and set an environment // variable telling where to find them, in case a child wants it.. - int stdOutCopy = dup( STDOUT_FILENO ); - int stdErrCopy = dup( STDERR_FILENO ); + int stdOutCopy = dup(STDOUT_FILENO); + int stdErrCopy = dup(STDERR_FILENO); // replace STDOUT with our socket, which we'll used to receive the // password.. - dup2( fds[0], STDOUT_FILENO ); + dup2(fds[0], STDOUT_FILENO); // ensure that STDOUT_FILENO and stdout/stderr are not closed on exec.. - fcntl(STDOUT_FILENO, F_SETFD, 0); // don't close on exec.. + fcntl(STDOUT_FILENO, F_SETFD, 0); // don't close on exec.. fcntl(stdOutCopy, F_SETFD, 0); fcntl(stdErrCopy, F_SETFD, 0); @@ -1431,13 +1267,13 @@ SecureMem *passwordFromProgram(const std::string &passProg, setenv(ENCFS_ENV_ROOTDIR, rootDir.c_str(), 1); - snprintf(tmpBuf, sizeof(tmpBuf)-1, "%i", stdOutCopy); + snprintf(tmpBuf, sizeof(tmpBuf) - 1, "%i", stdOutCopy); setenv(ENCFS_ENV_STDOUT, tmpBuf, 1); - snprintf(tmpBuf, sizeof(tmpBuf)-1, "%i", stdErrCopy); + snprintf(tmpBuf, sizeof(tmpBuf) - 1, "%i", stdErrCopy); setenv(ENCFS_ENV_STDERR, tmpBuf, 1); - execvp( argv[0], (char * const *)argv ); // returns only on error.. + execvp(argv[0], (char * const *)argv); // returns only on error.. perror(_("Internal error: failed to exec program")); exit(1); @@ -1449,77 +1285,67 @@ SecureMem *passwordFromProgram(const std::string &passProg, waitpid(pid, NULL, 0); - SecureMem *result = new SecureMem(password.length()+1); - if (result) - strncpy((char *)result->data(), password.c_str(), result->size()); + SecureMem *result = new SecureMem(password.length() + 1); + if (result) strncpy((char *)result->data(), password.c_str(), result->size()); password.assign(password.length(), '\0'); return result; } -SecureMem *passwordFromStdin() -{ +SecureMem *passwordFromStdin() { SecureMem *buf = new SecureMem(MaxPassBuf); - char *res = fgets( (char *)buf->data(), buf->size(), stdin ); - if (res) - { + char *res = fgets((char *)buf->data(), buf->size(), stdin); + if (res) { // Kill the trailing newline. int last = strnlen((char *)buf->data(), buf->size()); - if (last > 0 && buf->data()[last-1] == '\n') - buf->data()[ last-1 ] = '\0'; + if (last > 0 && buf->data()[last - 1] == '\n') buf->data()[last - 1] = '\0'; } - + return buf; } -SecureMem *passwordFromPrompt() -{ +SecureMem *passwordFromPrompt() { SecureMem *buf = new SecureMem(MaxPassBuf); // xgroup(common) - char *res = readpassphrase( _("EncFS Password: "), - (char *)buf->data(), buf->size()-1, RPP_ECHO_OFF ); - if (!res) - { + char *res = readpassphrase(_("EncFS Password: "), (char *)buf->data(), + buf->size() - 1, RPP_ECHO_OFF); + if (!res) { delete buf; buf = NULL; } - + return buf; } -SecureMem *passwordFromPrompts() -{ +SecureMem *passwordFromPrompts() { SecureMem *buf = new SecureMem(MaxPassBuf); SecureMem *buf2 = new SecureMem(MaxPassBuf); - do - { + do { // xgroup(common) - char *res1 = readpassphrase(_("New Encfs Password: "), - (char *)buf->data(), buf->size()-1, RPP_ECHO_OFF); + char *res1 = readpassphrase(_("New Encfs Password: "), (char *)buf->data(), + buf->size() - 1, RPP_ECHO_OFF); // xgroup(common) - char *res2 = readpassphrase(_("Verify Encfs Password: "), - (char *)buf2->data(), buf2->size()-1, RPP_ECHO_OFF); + char *res2 = + readpassphrase(_("Verify Encfs Password: "), (char *)buf2->data(), + buf2->size() - 1, RPP_ECHO_OFF); - if(res1 && res2 - && !strncmp((char*)buf->data(), (char*)buf2->data(), MaxPassBuf)) - { - break; - } else - { + if (res1 && res2 && + !strncmp((char *)buf->data(), (char *)buf2->data(), MaxPassBuf)) { + break; + } else { // xgroup(common) -- probably not common, but group with the others cerr << _("Passwords did not match, please try again\n"); } - } while(1); + } while (1); delete buf2; return buf; } -CipherKey getUserKey(const EncfsConfig &config, bool useStdin) -{ +CipherKey getUserKey(const EncfsConfig &config, bool useStdin) { CipherKey userKey; SecureMem *password; @@ -1528,36 +1354,32 @@ CipherKey getUserKey(const EncfsConfig &config, bool useStdin) else password = passwordFromPrompt(); - if (password) - { - userKey = decryptKey(config, (char*)password->data(), - strlen((char*)password->data())); + if (password) { + userKey = decryptKey(config, (char *)password->data(), + strlen((char *)password->data())); delete password; } return userKey; } -CipherKey getUserKey( const EncfsConfig &config, const std::string &passProg, - const std::string &rootDir ) -{ +CipherKey getUserKey(const EncfsConfig &config, const std::string &passProg, + const std::string &rootDir) { CipherKey result; SecureMem *password = passwordFromProgram(passProg, rootDir); - if (password) - { - result = decryptKey(config, (char*)password->data(), - strlen((char*)password->data())); + if (password) { + result = decryptKey(config, (char *)password->data(), + strlen((char *)password->data())); delete password; } return result; } -CipherKey getNewUserKey(EncfsConfig &config, - bool useStdin, const std::string &passProg, - const std::string &rootDir) -{ +CipherKey getNewUserKey(EncfsConfig &config, bool useStdin, + const std::string &passProg, + const std::string &rootDir) { CipherKey result; SecureMem *password; @@ -1568,50 +1390,42 @@ CipherKey getNewUserKey(EncfsConfig &config, else password = passwordFromPrompts(); - if (password) - { - result = makeNewKey(config, (char*)password->data(), - strlen((char*)password->data())); + if (password) { + result = makeNewKey(config, (char *)password->data(), + strlen((char *)password->data())); delete password; } return result; } -RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) -{ +RootPtr initFS(EncFS_Context *ctx, const shared_ptr &opts) { RootPtr rootInfo; EncfsConfig config; - if(readConfig( opts->rootDir, config ) != Config_None) - { - if(opts->reverseEncryption) - { - if (config.block_mac_bytes() != 0 || config.block_mac_rand_bytes() != 0 - || config.unique_iv() || config.external_iv() - || config.chained_iv() ) - { - cout << _("The configuration loaded is not compatible with --reverse\n"); + if (readConfig(opts->rootDir, config) != Config_None) { + if (opts->reverseEncryption) { + if (config.block_mac_bytes() != 0 || config.block_mac_rand_bytes() != 0 || + config.unique_iv() || config.external_iv() || config.chained_iv()) { + cout + << _("The configuration loaded is not compatible with --reverse\n"); return rootInfo; } } // first, instanciate the cipher. shared_ptr cipher = getCipher(config); - if(!cipher) - { + if (!cipher) { Interface iface = config.cipher(); - LOG(ERROR) << "Unable to find cipher " << iface.name() - << ", version " << iface.major() - << ":" << iface.minor() << ":" << iface.age(); + LOG(ERROR) << "Unable to find cipher " << iface.name() << ", version " + << iface.major() << ":" << iface.minor() << ":" << iface.age(); // xgroup(diag) cout << _("The requested cipher interface is not available\n"); return rootInfo; } - if(opts->delayMount) - { - rootInfo = RootPtr( new EncFS_Root ); + if (opts->delayMount) { + rootInfo = RootPtr(new EncFS_Root); rootInfo->cipher = cipher; rootInfo->root = shared_ptr(); return rootInfo; @@ -1620,27 +1434,24 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) // get user key CipherKey userKey; - if(opts->passwordProgram.empty()) - { - if (opts->annotate) - cerr << "$PROMPT$ passwd" << endl; - userKey = getUserKey( config, opts->useStdin ); + if (opts->passwordProgram.empty()) { + if (opts->annotate) cerr << "$PROMPT$ passwd" << endl; + userKey = getUserKey(config, opts->useStdin); } else - userKey = getUserKey( config, opts->passwordProgram, opts->rootDir ); + userKey = getUserKey(config, opts->passwordProgram, opts->rootDir); - if(!userKey.valid()) - return rootInfo; + if (!userKey.valid()) return rootInfo; - cipher->setKey(userKey); + cipher->setKey(userKey); VLOG(1) << "cipher encoded key size = " << cipher->encodedKeySize(); // decode volume key.. - CipherKey volumeKey = cipher->readKey( - (const unsigned char *)config.key().ciphertext().data(), opts->checkKey); + CipherKey volumeKey = + cipher->readKey((const unsigned char *)config.key().ciphertext().data(), + opts->checkKey); userKey.reset(); - if(!volumeKey.valid()) - { + if (!volumeKey.valid()) { // xgroup(diag) cout << _("Error decoding volume key, password incorrect\n"); return rootInfo; @@ -1648,23 +1459,22 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) cipher->setKey(volumeKey); - shared_ptr nameCoder = NameIO::New( config.naming(), cipher ); - if(!nameCoder) - { + shared_ptr nameCoder = NameIO::New(config.naming(), cipher); + if (!nameCoder) { Interface iface = config.naming(); LOG(ERROR) << "Unable to find nameio interface " << iface.name() - << ", version " << iface.major() - << ":" << iface.minor() << ":" << iface.age(); + << ", version " << iface.major() << ":" << iface.minor() << ":" + << iface.age(); // xgroup(diag) cout << _("The requested filename coding interface is " - "not available\n"); + "not available\n"); return rootInfo; } - nameCoder->setChainedNameIV( config.chained_iv() ); - nameCoder->setReverseEncryption( opts->reverseEncryption ); + nameCoder->setChainedNameIV(config.chained_iv()); + nameCoder->setReverseEncryption(opts->reverseEncryption); - FSConfigPtr fsConfig( new FSConfig ); + FSConfigPtr fsConfig(new FSConfig); fsConfig->cipher = cipher; fsConfig->key = volumeKey; fsConfig->nameCoding = nameCoder; @@ -1673,34 +1483,29 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) fsConfig->reverseEncryption = opts->reverseEncryption; fsConfig->opts = opts; - rootInfo = RootPtr( new EncFS_Root ); + rootInfo = RootPtr(new EncFS_Root); rootInfo->cipher = cipher; rootInfo->volumeKey = volumeKey; - rootInfo->root = shared_ptr( - new DirNode( ctx, opts->rootDir, fsConfig )); - } else - { - if(opts->createIfNotFound) - { + rootInfo->root = + shared_ptr(new DirNode(ctx, opts->rootDir, fsConfig)); + } else { + if (opts->createIfNotFound) { // creating a new encrypted filesystem - rootInfo = createConfig( ctx, opts ); + rootInfo = createConfig(ctx, opts); } } return rootInfo; } -int remountFS(EncFS_Context *ctx) -{ +int remountFS(EncFS_Context *ctx) { VLOG(1) << "Attempting to reinitialize filesystem"; - RootPtr rootInfo = initFS( ctx, ctx->opts ); - if(rootInfo) - { + RootPtr rootInfo = initFS(ctx, ctx->opts); + if (rootInfo) { ctx->setRoot(rootInfo->root); return 0; - } else - { + } else { LOG(WARNING) << "Remount failed"; return -EACCES; } diff --git a/fs/FileUtils.h b/fs/FileUtils.h index a821838..a8df155 100644 --- a/fs/FileUtils.h +++ b/fs/FileUtils.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ - + #ifndef _FileUtils_incl_ #define _FileUtils_incl_ @@ -29,26 +29,25 @@ namespace encfs { // true if the path points to an existing node (of any type) -bool fileExists( const char *fileName ); +bool fileExists(const char *fileName); // true if path is a directory -bool isDirectory( const char *fileName ); +bool isDirectory(const char *fileName); // true if starts with '/' -bool isAbsolutePath( const char *fileName ); +bool isAbsolutePath(const char *fileName); // pointer to just after the last '/' -const char *lastPathElement( const char *name ); +const char *lastPathElement(const char *name); -std::string parentDirectory( const std::string &path ); +std::string parentDirectory(const std::string &path); // ask the user for permission to create the directory. If they say ok, then // do it and return true. -bool userAllowMkdir(const char *dirPath, mode_t mode ); -bool userAllowMkdir(int promptno, const char *dirPath, mode_t mode ); +bool userAllowMkdir(const char *dirPath, mode_t mode); +bool userAllowMkdir(int promptno, const char *dirPath, mode_t mode); class CipherV1; class DirNode; -struct EncFS_Root -{ +struct EncFS_Root { shared_ptr cipher; CipherKey volumeKey; shared_ptr root; @@ -59,36 +58,33 @@ struct EncFS_Root typedef shared_ptr RootPtr; -enum ConfigMode -{ +enum ConfigMode { Config_Prompt, Config_Standard, Config_Paranoia }; -struct EncFS_Opts -{ +struct EncFS_Opts { std::string rootDir; bool createIfNotFound; // create filesystem if not found - bool idleTracking; // turn on idle monitoring of filesystem - bool mountOnDemand; // mounting on-demand - bool delayMount; // delay initial mount + bool idleTracking; // turn on idle monitoring of filesystem + bool mountOnDemand; // mounting on-demand + bool delayMount; // delay initial mount - bool checkKey; // check crypto key decoding - bool forceDecode; // force decode on MAC block failures + bool checkKey; // check crypto key decoding + bool forceDecode; // force decode on MAC block failures - std::string passwordProgram; // path to password program (or empty) - bool useStdin; // read password from stdin rather then prompting - bool annotate; // print annotation line prompt to stderr. + std::string passwordProgram; // path to password program (or empty) + bool useStdin; // read password from stdin rather then prompting + bool annotate; // print annotation line prompt to stderr. - bool ownerCreate; // set owner of new files to caller + bool ownerCreate; // set owner of new files to caller - bool reverseEncryption; // Reverse encryption + bool reverseEncryption; // Reverse encryption ConfigMode configMode; - EncFS_Opts() - { + EncFS_Opts() { createIfNotFound = true; idleTracking = false; mountOnDemand = false; @@ -106,35 +102,33 @@ struct EncFS_Opts /* Read existing config file. Looks for any supported configuration version. */ -ConfigType readConfig( const std::string &rootDir, EncfsConfig &config ); +ConfigType readConfig(const std::string &rootDir, EncfsConfig &config); /* Save the configuration. Saves back as the same configuration type as was read from. */ -bool saveConfig( const std::string &rootdir, const EncfsConfig &config ); +bool saveConfig(const std::string &rootdir, const EncfsConfig &config); class EncFS_Context; -RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ); +RootPtr initFS(EncFS_Context *ctx, const shared_ptr &opts); -RootPtr createConfig( EncFS_Context *ctx, - const shared_ptr &opts ); +RootPtr createConfig(EncFS_Context *ctx, const shared_ptr &opts); -void showFSInfo( const EncfsConfig &config ); +void showFSInfo(const EncfsConfig &config); -bool readV4Config( const char *configFile, EncfsConfig &config, - struct ConfigInfo *); +bool readV4Config(const char *configFile, EncfsConfig &config, + struct ConfigInfo *); -bool readV5Config( const char *configFile, EncfsConfig &config, - struct ConfigInfo *); +bool readV5Config(const char *configFile, EncfsConfig &config, + struct ConfigInfo *); -bool readV6Config( const char *configFile, EncfsConfig &config, - struct ConfigInfo *); - -bool readProtoConfig( const char *configFile, EncfsConfig &config, - struct ConfigInfo *); +bool readV6Config(const char *configFile, EncfsConfig &config, + struct ConfigInfo *); +bool readProtoConfig(const char *configFile, EncfsConfig &config, + struct ConfigInfo *); } // namespace encfs #endif diff --git a/fs/MACFileIO.cpp b/fs/MACFileIO.cpp index db48c81..64ef3f6 100644 --- a/fs/MACFileIO.cpp +++ b/fs/MACFileIO.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -47,64 +47,44 @@ namespace encfs { // static Interface MACFileIO_iface = makeInterface("FileIO/MAC", 2, 1, 0); -int dataBlockSize(const FSConfigPtr &cfg) -{ - return cfg->config->block_size() - - cfg->config->block_mac_bytes() - - cfg->config->block_mac_rand_bytes(); +int dataBlockSize(const FSConfigPtr &cfg) { + return cfg->config->block_size() - cfg->config->block_mac_bytes() - + cfg->config->block_mac_rand_bytes(); } -MACFileIO::MACFileIO( const shared_ptr &_base, - const FSConfigPtr &cfg ) - : BlockFileIO( dataBlockSize( cfg ), cfg ) - , base( _base ) - , cipher( cfg->cipher ) - , macBytes( cfg->config->block_mac_bytes() ) - , randBytes( cfg->config->block_mac_rand_bytes() ) - , warnOnly( cfg->opts->forceDecode ) -{ - rAssert( macBytes >= 0 && macBytes <= 8 ); - rAssert( randBytes >= 0 ); +MACFileIO::MACFileIO(const shared_ptr &_base, const FSConfigPtr &cfg) + : BlockFileIO(dataBlockSize(cfg), cfg), + base(_base), + cipher(cfg->cipher), + macBytes(cfg->config->block_mac_bytes()), + randBytes(cfg->config->block_mac_rand_bytes()), + warnOnly(cfg->opts->forceDecode) { + rAssert(macBytes >= 0 && macBytes <= 8); + rAssert(randBytes >= 0); VLOG(1) << "fs block size = " << cfg->config->block_size() - << ", macBytes = " << cfg->config->block_mac_bytes() - << ", randBytes = " << cfg->config->block_mac_rand_bytes(); + << ", macBytes = " << cfg->config->block_mac_bytes() + << ", randBytes = " << cfg->config->block_mac_rand_bytes(); } -MACFileIO::~MACFileIO() -{ +MACFileIO::~MACFileIO() {} + +Interface MACFileIO::interface() const { return MACFileIO_iface; } + +int MACFileIO::open(int flags) { return base->open(flags); } + +void MACFileIO::setFileName(const char *fileName) { + base->setFileName(fileName); } -Interface MACFileIO::interface() const -{ - return MACFileIO_iface; -} +const char *MACFileIO::getFileName() const { return base->getFileName(); } -int MACFileIO::open( int flags ) -{ - return base->open( flags ); -} +bool MACFileIO::setIV(uint64_t iv) { return base->setIV(iv); } -void MACFileIO::setFileName( const char *fileName ) -{ - base->setFileName( fileName ); -} - -const char *MACFileIO::getFileName() const -{ - return base->getFileName(); -} - -bool MACFileIO::setIV( uint64_t iv ) -{ - return base->setIV( iv ); -} - -inline static off_t roundUpDivide( off_t numerator, int denominator ) -{ +inline static off_t roundUpDivide(off_t numerator, int denominator) { // integer arithmetic always rounds down, so we can round up by adding // enough so that any value other then a multiple of denominator gets // rouned to the next highest value. - return ( numerator + denominator - 1 ) / denominator; + return (numerator + denominator - 1) / denominator; } // Convert from a location in the raw file to a location when MAC headers are @@ -117,9 +97,8 @@ inline static off_t roundUpDivide( off_t numerator, int denominator ) // ... blockNum = 1 // ... partialBlock = 0 // ... adjLoc = 1 * blockSize -static off_t locWithHeader( off_t offset, int blockSize, int headerSize ) -{ - off_t blockNum = roundUpDivide( offset , blockSize - headerSize ); +static off_t locWithHeader(off_t offset, int blockSize, int headerSize) { + off_t blockNum = roundUpDivide(offset, blockSize - headerSize); return offset + blockNum * headerSize; } @@ -128,92 +107,77 @@ static off_t locWithHeader( off_t offset, int blockSize, int headerSize ) // The output value will always be less then the input value, because the // headers are stored at the beginning of the block, so even the first data is // offset by the size of the header. -static off_t locWithoutHeader( off_t offset, int blockSize, int headerSize ) -{ - off_t blockNum = roundUpDivide( offset , blockSize ); +static off_t locWithoutHeader(off_t offset, int blockSize, int headerSize) { + off_t blockNum = roundUpDivide(offset, blockSize); return offset - blockNum * headerSize; } -int MACFileIO::getAttr( struct stat *stbuf ) const -{ - int res = base->getAttr( stbuf ); +int MACFileIO::getAttr(struct stat *stbuf) const { + int res = base->getAttr(stbuf); - if(res == 0 && S_ISREG(stbuf->st_mode)) - { + if (res == 0 && S_ISREG(stbuf->st_mode)) { // have to adjust size field.. int headerSize = macBytes + randBytes; int bs = blockSize() + headerSize; - stbuf->st_size = locWithoutHeader( stbuf->st_size, bs, headerSize ); + stbuf->st_size = locWithoutHeader(stbuf->st_size, bs, headerSize); } return res; } -off_t MACFileIO::getSize() const -{ +off_t MACFileIO::getSize() const { // adjust the size to hide the header overhead we tack on.. int headerSize = macBytes + randBytes; int bs = blockSize() + headerSize; off_t size = base->getSize(); - if(size > 0) - size = locWithoutHeader( size, bs, headerSize ); + if (size > 0) size = locWithoutHeader(size, bs, headerSize); return size; } -ssize_t MACFileIO::readOneBlock( const IORequest &req ) const -{ +ssize_t MACFileIO::readOneBlock(const IORequest &req) const { int headerSize = macBytes + randBytes; int bs = blockSize() + headerSize; MemBlock mb; - mb.allocate( bs ); + mb.allocate(bs); IORequest tmp; - tmp.offset = locWithHeader( req.offset, bs, headerSize ); + tmp.offset = locWithHeader(req.offset, bs, headerSize); tmp.data = mb.data; tmp.dataLen = headerSize + req.dataLen; // get the data from the base FileIO layer - ssize_t readSize = base->read( tmp ); + ssize_t readSize = base->read(tmp); // don't store zeros if configured for zero-block pass-through bool skipBlock = true; - if( _allowHoles ) - { - for(int i=0; i 0) - skipBlock = false; + } else if (macBytes > 0) + skipBlock = false; - if(readSize > headerSize) - { - if(!skipBlock) - { + if (readSize > headerSize) { + if (!skipBlock) { // At this point the data has been decoded. So, compute the MAC of // the block and check against the checksum stored in the header.. - uint64_t mac = cipher->MAC_64( tmp.data + macBytes, - readSize - macBytes ); + uint64_t mac = cipher->MAC_64(tmp.data + macBytes, readSize - macBytes); - for(int i=0; i>= 8) - { + for (int i = 0; i < macBytes; ++i, mac >>= 8) { int test = mac & 0xff; int stored = tmp.data[i]; - if(test != stored) - { - // uh oh.. + if (test != stored) { + // uh oh.. long blockNum = req.offset / bs; LOG(WARNING) << "MAC comparison failure in block " << blockNum; - if( !warnOnly ) - { - throw Error( - _("MAC comparison failure, refusing to read")); + if (!warnOnly) { + throw Error(_("MAC comparison failure, refusing to read")); } break; } @@ -222,75 +186,64 @@ ssize_t MACFileIO::readOneBlock( const IORequest &req ) const // now copy the data to the output buffer readSize -= headerSize; - memcpy( req.data, tmp.data + headerSize, readSize ); - } else - { + memcpy(req.data, tmp.data + headerSize, readSize); + } else { VLOG(1) << "readSize " << readSize << " at offset " << req.offset; - if(readSize > 0) - readSize = 0; + if (readSize > 0) readSize = 0; } return readSize; } -bool MACFileIO::writeOneBlock( const IORequest &req ) -{ +bool MACFileIO::writeOneBlock(const IORequest &req) { int headerSize = macBytes + randBytes; int bs = blockSize() + headerSize; // we have the unencrypted data, so we need to attach a header to it. MemBlock mb; - mb.allocate( bs ); + mb.allocate(bs); IORequest newReq; - newReq.offset = locWithHeader( req.offset, bs, headerSize ); + newReq.offset = locWithHeader(req.offset, bs, headerSize); newReq.data = mb.data; newReq.dataLen = headerSize + req.dataLen; - memset( newReq.data, 0, headerSize ); - memcpy( newReq.data + headerSize, req.data, req.dataLen ); - if(randBytes > 0) - { - if(!cipher->pseudoRandomize( newReq.data+macBytes, randBytes)) + memset(newReq.data, 0, headerSize); + memcpy(newReq.data + headerSize, req.data, req.dataLen); + if (randBytes > 0) { + if (!cipher->pseudoRandomize(newReq.data + macBytes, randBytes)) return false; } - if(macBytes > 0) - { + if (macBytes > 0) { // compute the mac (which includes the random data) and fill it in - uint64_t mac = cipher->MAC_64( newReq.data+macBytes, - req.dataLen + randBytes ); + uint64_t mac = + cipher->MAC_64(newReq.data + macBytes, req.dataLen + randBytes); - for(int i=0; i>= 8; } } // now, we can let the next level have it.. - bool ok = base->write( newReq ); + bool ok = base->write(newReq); return ok; } -int MACFileIO::truncate( off_t size ) -{ +int MACFileIO::truncate(off_t size) { int headerSize = macBytes + randBytes; int bs = blockSize() + headerSize; - int res = blockTruncate( size, 0 ); + int res = blockTruncate(size, 0); - if(res == 0) - base->truncate( locWithHeader( size, bs, headerSize ) ); + if (res == 0) base->truncate(locWithHeader(size, bs, headerSize)); return res; } -bool MACFileIO::isWritable() const -{ - return base->isWritable(); -} +bool MACFileIO::isWritable() const { return base->isWritable(); } } // namespace encfs diff --git a/fs/MACFileIO.h b/fs/MACFileIO.h index 07974d5..d3d676c 100644 --- a/fs/MACFileIO.h +++ b/fs/MACFileIO.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -26,45 +26,42 @@ namespace encfs { -class MACFileIO : public BlockFileIO -{ -public: - /* - If warnOnlyMode is enabled, then a MAC comparison failure will only - result in a warning message from encfs -- the garbled data will still - be made available.. - */ - MACFileIO( const shared_ptr &base, - const FSConfigPtr &cfg ); - MACFileIO(); - virtual ~MACFileIO(); +class MACFileIO : public BlockFileIO { + public: + /* + If warnOnlyMode is enabled, then a MAC comparison failure will only + result in a warning message from encfs -- the garbled data will still + be made available.. + */ + MACFileIO(const shared_ptr &base, const FSConfigPtr &cfg); + MACFileIO(); + virtual ~MACFileIO(); - virtual Interface interface() const; + virtual Interface interface() const; - virtual void setFileName( const char *fileName ); - virtual const char *getFileName() const; - virtual bool setIV( uint64_t iv ); + virtual void setFileName(const char *fileName); + virtual const char *getFileName() const; + virtual bool setIV(uint64_t iv); - virtual int open( int flags ); - virtual int getAttr( struct stat *stbuf ) const; - virtual off_t getSize() const; + virtual int open(int flags); + virtual int getAttr(struct stat *stbuf) const; + virtual off_t getSize() const; - virtual int truncate( off_t size ); + virtual int truncate(off_t size); - virtual bool isWritable() const; + virtual bool isWritable() const; -private: - virtual ssize_t readOneBlock( const IORequest &req ) const; - virtual bool writeOneBlock( const IORequest &req ); + private: + virtual ssize_t readOneBlock(const IORequest &req) const; + virtual bool writeOneBlock(const IORequest &req); - shared_ptr base; - shared_ptr cipher; - int macBytes; - int randBytes; - bool warnOnly; + shared_ptr base; + shared_ptr cipher; + int macBytes; + int randBytes; + bool warnOnly; }; } // namespace encfs #endif - diff --git a/fs/MemBlockFileIO.cpp b/fs/MemBlockFileIO.cpp index dd85989..92eef12 100644 --- a/fs/MemBlockFileIO.cpp +++ b/fs/MemBlockFileIO.cpp @@ -8,7 +8,7 @@ * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS @@ -26,39 +26,29 @@ namespace encfs { -static Interface MemBlockFileIO_iface = makeInterface("FileIO/MemBlock", - 1, 0, 0); +static Interface MemBlockFileIO_iface = + makeInterface("FileIO/MemBlock", 1, 0, 0); -MemBlockFileIO::MemBlockFileIO(int blockSize, const FSConfigPtr &cfg) - : BlockFileIO(blockSize, cfg), impl(new MemFileIO(0)) { -} +MemBlockFileIO::MemBlockFileIO(int blockSize, const FSConfigPtr& cfg) + : BlockFileIO(blockSize, cfg), impl(new MemFileIO(0)) {} -MemBlockFileIO::~MemBlockFileIO() { -} +MemBlockFileIO::~MemBlockFileIO() {} -Interface MemBlockFileIO::interface() const { - return MemBlockFileIO_iface; -} +Interface MemBlockFileIO::interface() const { return MemBlockFileIO_iface; } -void MemBlockFileIO::setFileName(const char *name) { +void MemBlockFileIO::setFileName(const char* name) { return impl->setFileName(name); } -const char *MemBlockFileIO::getFileName() const { - return impl->getFileName(); -} +const char* MemBlockFileIO::getFileName() const { return impl->getFileName(); } -int MemBlockFileIO::open(int flags) { - return impl->open(flags); -} +int MemBlockFileIO::open(int flags) { return impl->open(flags); } int MemBlockFileIO::getAttr(struct stat* stbuf) const { return impl->getAttr(stbuf); } -off_t MemBlockFileIO::getSize() const { - return impl->getSize(); -} +off_t MemBlockFileIO::getSize() const { return impl->getSize(); } ssize_t MemBlockFileIO::readOneBlock(const IORequest& req) const { return impl->read(req); @@ -68,12 +58,8 @@ bool MemBlockFileIO::writeOneBlock(const IORequest& req) { return impl->write(req); } -int MemBlockFileIO::truncate(off_t size) { - return impl->truncate(size); -} +int MemBlockFileIO::truncate(off_t size) { return impl->truncate(size); } -bool MemBlockFileIO::isWritable() const { - return impl->isWritable(); -} +bool MemBlockFileIO::isWritable() const { return impl->isWritable(); } } // namespace encfs diff --git a/fs/MemBlockFileIO.h b/fs/MemBlockFileIO.h index b1bf64e..8b13efa 100644 --- a/fs/MemBlockFileIO.h +++ b/fs/MemBlockFileIO.h @@ -8,7 +8,7 @@ * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS @@ -42,13 +42,14 @@ class MemBlockFileIO : public BlockFileIO { virtual const char *getFileName() const; virtual int open(int flags); - + virtual int getAttr(struct stat *stbuf) const; virtual off_t getSize() const; virtual bool isWritable() const; virtual int truncate(off_t size); + protected: virtual ssize_t readOneBlock(const IORequest &req) const; virtual bool writeOneBlock(const IORequest &req); @@ -60,4 +61,3 @@ class MemBlockFileIO : public BlockFileIO { } // namespace encfs #endif - diff --git a/fs/MemFileIO.cpp b/fs/MemFileIO.cpp index 0ca5a5b..6910db3 100644 --- a/fs/MemFileIO.cpp +++ b/fs/MemFileIO.cpp @@ -8,7 +8,7 @@ * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS @@ -34,25 +34,15 @@ MemFileIO* NewMemFileIO(const Interface& iface) { return new MemFileIO(0); } -MemFileIO::MemFileIO(int size) - : writable(false) { - buf.resize(size); -} +MemFileIO::MemFileIO(int size) : writable(false) { buf.resize(size); } -MemFileIO::~MemFileIO() { -} +MemFileIO::~MemFileIO() {} -Interface MemFileIO::interface() const { - return MemFileIO_iface; -} +Interface MemFileIO::interface() const { return MemFileIO_iface; } -void MemFileIO::setFileName(const char *name) { - this->name = name; -} +void MemFileIO::setFileName(const char* name) { this->name = name; } -const char *MemFileIO::getFileName() const { - return name.c_str(); -} +const char* MemFileIO::getFileName() const { return name.c_str(); } int MemFileIO::open(int flags) { bool requestWrite = ((flags & O_RDWR) || (flags & O_WRONLY)); @@ -67,9 +57,7 @@ int MemFileIO::getAttr(struct stat* stbuf) const { return 0; } -off_t MemFileIO::getSize() const { - return buf.size(); -} +off_t MemFileIO::getSize() const { return buf.size(); } ssize_t MemFileIO::read(const IORequest& req) const { rAssert(req.offset >= 0); @@ -102,8 +90,6 @@ int MemFileIO::truncate(off_t size) { return 0; } -bool MemFileIO::isWritable() const { - return writable; -} +bool MemFileIO::isWritable() const { return writable; } } // namespace encfs diff --git a/fs/MemFileIO.h b/fs/MemFileIO.h index 804a107..50f2afa 100644 --- a/fs/MemFileIO.h +++ b/fs/MemFileIO.h @@ -8,7 +8,7 @@ * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS @@ -40,12 +40,12 @@ class MemFileIO : public FileIO { virtual const char *getFileName() const; virtual int open(int flags); - + virtual int getAttr(struct stat *stbuf) const; virtual off_t getSize() const; - virtual ssize_t read(const IORequest& req) const; - virtual bool write(const IORequest& req); + virtual ssize_t read(const IORequest &req) const; + virtual bool write(const IORequest &req); virtual int truncate(off_t size); virtual bool isWritable() const; @@ -59,4 +59,3 @@ class MemFileIO : public FileIO { } // namespace encfs #endif - diff --git a/fs/NameIO.cpp b/fs/NameIO.cpp index b8c6740..4c2be73 100644 --- a/fs/NameIO.cpp +++ b/fs/NameIO.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -42,23 +42,18 @@ using std::string; namespace encfs { -#define REF_MODULE(TYPE) \ - do { \ - if(!TYPE::Enabled() ) \ - cerr << "referenceModule: should never happen\n"; \ - } while(0) +#define REF_MODULE(TYPE) \ + do { \ + if (!TYPE::Enabled()) cerr << "referenceModule: should never happen\n"; \ + } while (0) -static -void AddSymbolReferences() -{ +static void AddSymbolReferences() { REF_MODULE(BlockNameIO); REF_MODULE(StreamNameIO); REF_MODULE(NullNameIO); } - -struct NameIOAlg -{ +struct NameIOAlg { bool hidden; NameIO::Constructor constructor; string description; @@ -66,30 +61,25 @@ struct NameIOAlg bool needsStreamMode; }; -typedef multimap< string, NameIOAlg > NameIOMap_t; +typedef multimap NameIOMap_t; static NameIOMap_t *gNameIOMap = 0; - -list< NameIO::Algorithm > NameIO::GetAlgorithmList( bool includeHidden ) -{ +list NameIO::GetAlgorithmList(bool includeHidden) { AddSymbolReferences(); - list< Algorithm > result; - if(gNameIOMap) - { + list result; + if (gNameIOMap) { NameIOMap_t::const_iterator it; NameIOMap_t::const_iterator end = gNameIOMap->end(); - for(it = gNameIOMap->begin(); it != end; ++it) - { - if(includeHidden || !it->second.hidden) - { + for (it = gNameIOMap->begin(); it != end; ++it) { + if (includeHidden || !it->second.hidden) { Algorithm tmp; tmp.name = it->first; tmp.description = it->second.description; tmp.iface = it->second.iface; tmp.needsStreamMode = it->second.needsStreamMode; - result.push_back( tmp ); + result.push_back(tmp); } } } @@ -97,13 +87,10 @@ list< NameIO::Algorithm > NameIO::GetAlgorithmList( bool includeHidden ) return result; } -bool NameIO::Register( const char *name, const char *description, - const Interface &iface, Constructor constructor, - bool needsStreamMode, - bool hidden ) -{ - if( !gNameIOMap ) - gNameIOMap = new NameIOMap_t; +bool NameIO::Register(const char *name, const char *description, + const Interface &iface, Constructor constructor, + bool needsStreamMode, bool hidden) { + if (!gNameIOMap) gNameIOMap = new NameIOMap_t; NameIOAlg alg; alg.hidden = hidden; @@ -112,40 +99,33 @@ bool NameIO::Register( const char *name, const char *description, alg.iface = iface; alg.needsStreamMode = needsStreamMode; - gNameIOMap->insert( make_pair( string(name), alg )); + gNameIOMap->insert(make_pair(string(name), alg)); return true; } -shared_ptr NameIO::New(const string &name, - const shared_ptr &cipher) -{ +shared_ptr NameIO::New(const string &name, + const shared_ptr &cipher) { shared_ptr result; - if(gNameIOMap) - { - NameIOMap_t::const_iterator it = gNameIOMap->find( name ); - if(it != gNameIOMap->end()) - { + if (gNameIOMap) { + NameIOMap_t::const_iterator it = gNameIOMap->find(name); + if (it != gNameIOMap->end()) { Constructor fn = it->second.constructor; - result = (*fn)( it->second.iface, cipher ); + result = (*fn)(it->second.iface, cipher); } } return result; } -shared_ptr NameIO::New(const Interface &iface, - const shared_ptr &cipher) -{ +shared_ptr NameIO::New(const Interface &iface, + const shared_ptr &cipher) { shared_ptr result; - if(gNameIOMap) - { + if (gNameIOMap) { NameIOMap_t::const_iterator it; NameIOMap_t::const_iterator end = gNameIOMap->end(); - for(it = gNameIOMap->begin(); it != end; ++it) - { - if( implements(it->second.iface, iface )) - { + for (it = gNameIOMap->begin(); it != end; ++it) { + if (implements(it->second.iface, iface)) { Constructor fn = it->second.constructor; - result = (*fn)( iface, cipher ); + result = (*fn)(iface, cipher); break; } } @@ -153,195 +133,148 @@ shared_ptr NameIO::New(const Interface &iface, return result; } +NameIO::NameIO() : chainedNameIV(false), reverseEncryption(false) {} +NameIO::~NameIO() {} -NameIO::NameIO() - : chainedNameIV( false ), reverseEncryption( false ) -{ -} +void NameIO::setChainedNameIV(bool enable) { chainedNameIV = enable; } -NameIO::~NameIO() -{ -} +bool NameIO::getChainedNameIV() const { return chainedNameIV; } -void NameIO::setChainedNameIV( bool enable ) -{ - chainedNameIV = enable; -} +void NameIO::setReverseEncryption(bool enable) { reverseEncryption = enable; } -bool NameIO::getChainedNameIV() const -{ - return chainedNameIV; -} +bool NameIO::getReverseEncryption() const { return reverseEncryption; } -void NameIO::setReverseEncryption( bool enable ) -{ - reverseEncryption = enable; -} - -bool NameIO::getReverseEncryption() const -{ - return reverseEncryption; -} - - -std::string NameIO::recodePath( const char *path, - int (NameIO::*_length)(int) const, - int (NameIO::*_code)(const char*, int, uint64_t *, char*) const, - uint64_t *iv ) const -{ +std::string NameIO::recodePath(const char *path, + int (NameIO::*_length)(int) const, + int (NameIO::*_code)(const char *, int, + uint64_t *, char *) const, + uint64_t *iv) const { string output; - while( *path ) - { - if( *path == '/' ) - { - if( !output.empty() ) // don't start the string with '/' + while (*path) { + if (*path == '/') { + if (!output.empty()) // don't start the string with '/' output += '/'; ++path; - } else - { + } else { bool isDotFile = (*path == '.'); - const char *next = strchr( path, '/' ); - int len = next ? next - path : strlen( path ); + const char *next = strchr(path, '/'); + int len = next ? next - path : strlen(path); // at this point we know that len > 0 - if( isDotFile && (path[len-1] == '.') && (len <= 2) ) - { - output.append(len, '.'); // append [len] copies of '.' + if (isDotFile && (path[len - 1] == '.') && (len <= 2)) { + output.append(len, '.'); // append [len] copies of '.' path += len; continue; } // figure out buffer sizes - int approxLen = (this->*_length)( len ); - if(approxLen <= 0) - throw Error("Filename too small to decode"); + int approxLen = (this->*_length)(len); + if (approxLen <= 0) throw Error("Filename too small to decode"); - BUFFER_INIT( codeBuf, 32, (unsigned int)approxLen+1 ); + BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1); // code the name - int codedLen = (this->*_code)( path, len, iv, codeBuf ); - rAssert( codedLen <= approxLen ); - rAssert( codeBuf[codedLen] == '\0' ); + int codedLen = (this->*_code)(path, len, iv, codeBuf); + rAssert(codedLen <= approxLen); + rAssert(codeBuf[codedLen] == '\0'); path += len; // append result to string - output += (char*)codeBuf; + output += (char *)codeBuf; - BUFFER_RESET( codeBuf ); + BUFFER_RESET(codeBuf); } } return output; } -std::string NameIO::encodePath( const char *plaintextPath ) const -{ +std::string NameIO::encodePath(const char *plaintextPath) const { uint64_t iv = 0; - return encodePath( plaintextPath, &iv); + return encodePath(plaintextPath, &iv); } -std::string NameIO::decodePath( const char *cipherPath ) const -{ +std::string NameIO::decodePath(const char *cipherPath) const { uint64_t iv = 0; - return decodePath( cipherPath, &iv ); + return decodePath(cipherPath, &iv); } -std::string NameIO::_encodePath( const char *plaintextPath, uint64_t *iv ) const -{ - // if chaining is not enabled, then the iv pointer is not used.. - if(!chainedNameIV) - iv = 0; - return recodePath( plaintextPath, - &NameIO::maxEncodedNameLen, &NameIO::encodeName, iv); -} - -std::string NameIO::_decodePath( const char *cipherPath, uint64_t *iv ) const -{ +std::string NameIO::_encodePath(const char *plaintextPath, uint64_t *iv) const { // if chaining is not enabled, then the iv pointer is not used.. - if(!chainedNameIV) - iv = 0; - return recodePath( cipherPath, - &NameIO::maxDecodedNameLen, &NameIO::decodeName, iv); + if (!chainedNameIV) iv = 0; + return recodePath(plaintextPath, &NameIO::maxEncodedNameLen, + &NameIO::encodeName, iv); } -std::string NameIO::encodePath( const char *path, uint64_t *iv ) const -{ - return getReverseEncryption() ? - _decodePath( path, iv ) : - _encodePath( path, iv ); -} - -std::string NameIO::decodePath( const char *path, uint64_t *iv ) const -{ - return getReverseEncryption() ? - _encodePath( path, iv ) : - _decodePath( path, iv ); -} - - -int NameIO::encodeName( const char *input, int length, char *output ) const -{ - return encodeName( input, length, (uint64_t*)0, output ); +std::string NameIO::_decodePath(const char *cipherPath, uint64_t *iv) const { + // if chaining is not enabled, then the iv pointer is not used.. + if (!chainedNameIV) iv = 0; + return recodePath(cipherPath, &NameIO::maxDecodedNameLen, &NameIO::decodeName, + iv); } -int NameIO::decodeName( const char *input, int length, char *output ) const -{ - return decodeName( input, length, (uint64_t*)0, output ); +std::string NameIO::encodePath(const char *path, uint64_t *iv) const { + return getReverseEncryption() ? _decodePath(path, iv) : _encodePath(path, iv); } -std::string NameIO::_encodeName( const char *plaintextName, int length ) const -{ - int approxLen = maxEncodedNameLen( length ); +std::string NameIO::decodePath(const char *path, uint64_t *iv) const { + return getReverseEncryption() ? _encodePath(path, iv) : _decodePath(path, iv); +} - BUFFER_INIT( codeBuf, 32, (unsigned int)approxLen+1 ); +int NameIO::encodeName(const char *input, int length, char *output) const { + return encodeName(input, length, (uint64_t *)0, output); +} + +int NameIO::decodeName(const char *input, int length, char *output) const { + return decodeName(input, length, (uint64_t *)0, output); +} + +std::string NameIO::_encodeName(const char *plaintextName, int length) const { + int approxLen = maxEncodedNameLen(length); + + BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1); // code the name - int codedLen = encodeName( plaintextName, length, 0, codeBuf ); - rAssert( codedLen <= approxLen ); - rAssert( codeBuf[codedLen] == '\0' ); + int codedLen = encodeName(plaintextName, length, 0, codeBuf); + rAssert(codedLen <= approxLen); + rAssert(codeBuf[codedLen] == '\0'); // append result to string - std::string result = (char*)codeBuf; + std::string result = (char *)codeBuf; - BUFFER_RESET( codeBuf ); + BUFFER_RESET(codeBuf); return result; } -std::string NameIO::_decodeName( const char *encodedName, int length ) const -{ - int approxLen = maxDecodedNameLen( length ); +std::string NameIO::_decodeName(const char *encodedName, int length) const { + int approxLen = maxDecodedNameLen(length); - BUFFER_INIT( codeBuf, 32, (unsigned int)approxLen+1 ); + BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1); // code the name - int codedLen = decodeName( encodedName, length, 0, codeBuf ); - rAssert( codedLen <= approxLen ); - rAssert( codeBuf[codedLen] == '\0' ); + int codedLen = decodeName(encodedName, length, 0, codeBuf); + rAssert(codedLen <= approxLen); + rAssert(codeBuf[codedLen] == '\0'); // append result to string - std::string result = (char*)codeBuf; + std::string result = (char *)codeBuf; - BUFFER_RESET( codeBuf ); + BUFFER_RESET(codeBuf); return result; } -std::string NameIO::encodeName( const char *path, int length ) const -{ - return getReverseEncryption() ? - _decodeName( path, length ) : - _encodeName( path, length ); +std::string NameIO::encodeName(const char *path, int length) const { + return getReverseEncryption() ? _decodeName(path, length) + : _encodeName(path, length); } -std::string NameIO::decodeName( const char *path, int length ) const -{ - return getReverseEncryption() ? - _encodeName( path, length ) : - _decodeName( path, length ); +std::string NameIO::decodeName(const char *path, int length) const { + return getReverseEncryption() ? _encodeName(path, length) + : _decodeName(path, length); } } // namespace encfs - diff --git a/fs/NameIO.h b/fs/NameIO.h index 548df9e..5f3e11c 100644 --- a/fs/NameIO.h +++ b/fs/NameIO.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -33,14 +33,12 @@ namespace encfs { class CipherV1; -class NameIO -{ +class NameIO { public: - typedef shared_ptr (*Constructor)(const Interface &iface, - const shared_ptr &cipher); + typedef shared_ptr(*Constructor)(const Interface &iface, + const shared_ptr &cipher); - struct Algorithm - { + struct Algorithm { std::string name; std::string description; Interface iface; @@ -48,72 +46,65 @@ class NameIO }; typedef std::list AlgorithmList; - static AlgorithmList GetAlgorithmList( bool includeHidden = false ); + static AlgorithmList GetAlgorithmList(bool includeHidden = false); static shared_ptr New(const Interface &iface, const shared_ptr &cipher); static shared_ptr New(const std::string &name, const shared_ptr &cipher); - static bool Register( const char *name, const char *description, - const Interface &iface, Constructor constructor, - bool needsStreamMode, - bool hidden = false); - + static bool Register(const char *name, const char *description, + const Interface &iface, Constructor constructor, + bool needsStreamMode, bool hidden = false); NameIO(); virtual ~NameIO(); - virtual Interface interface() const =0; + virtual Interface interface() const = 0; - void setChainedNameIV( bool enable ); + void setChainedNameIV(bool enable); bool getChainedNameIV() const; - void setReverseEncryption( bool enable ); + void setReverseEncryption(bool enable); bool getReverseEncryption() const; - std::string encodePath( const char *plaintextPath ) const; - std::string decodePath( const char *encodedPath ) const; + std::string encodePath(const char *plaintextPath) const; + std::string decodePath(const char *encodedPath) const; - std::string encodePath( const char *plaintextPath, uint64_t *iv ) const; - std::string decodePath( const char *encodedPath, uint64_t *iv ) const; + std::string encodePath(const char *plaintextPath, uint64_t *iv) const; + std::string decodePath(const char *encodedPath, uint64_t *iv) const; - virtual int maxEncodedNameLen( int plaintextNameLen ) const =0; - virtual int maxDecodedNameLen( int encodedNameLen ) const =0; + virtual int maxEncodedNameLen(int plaintextNameLen) const = 0; + virtual int maxDecodedNameLen(int encodedNameLen) const = 0; - std::string encodeName( const char *plaintextName, int length ) const; - std::string decodeName( const char *encodedName, int length ) const; + std::string encodeName(const char *plaintextName, int length) const; + std::string decodeName(const char *encodedName, int length) const; - protected: - virtual int encodeName( const char *plaintextName, int length, - char *encodedName ) const; - virtual int decodeName( const char *encodedName, int length, - char *plaintextName ) const; - - virtual int encodeName( const char *plaintextName, int length, - uint64_t *iv, char *encodedName ) const =0; - virtual int decodeName( const char *encodedName, int length, - uint64_t *iv, char *plaintextName ) const =0; + protected: + virtual int encodeName(const char *plaintextName, int length, + char *encodedName) const; + virtual int decodeName(const char *encodedName, int length, + char *plaintextName) const; + virtual int encodeName(const char *plaintextName, int length, uint64_t *iv, + char *encodedName) const = 0; + virtual int decodeName(const char *encodedName, int length, uint64_t *iv, + char *plaintextName) const = 0; private: - - std::string recodePath( const char *path, - int (NameIO::*codingLen)(int) const, - int (NameIO::*codingFunc)(const char *, int, + std::string recodePath(const char *path, int (NameIO::*codingLen)(int) const, + int (NameIO::*codingFunc)(const char *, int, uint64_t *, char *) const, - uint64_t *iv ) const; + uint64_t *iv) const; - std::string _encodePath( const char *plaintextPath, uint64_t *iv ) const; - std::string _decodePath( const char *encodedPath, uint64_t *iv ) const; - std::string _encodeName( const char *plaintextName, int length ) const; - std::string _decodeName( const char *encodedName, int length ) const; + std::string _encodePath(const char *plaintextPath, uint64_t *iv) const; + std::string _decodePath(const char *encodedPath, uint64_t *iv) const; + std::string _encodeName(const char *plaintextName, int length) const; + std::string _decodeName(const char *encodedName, int length) const; bool chainedNameIV; bool reverseEncryption; }; - - /* Helper macros for creating temporary buffers with an optimization that below a given size (OptimizedSize) is allocated on the stack, and when a @@ -121,23 +112,22 @@ class NameIO BUFFER_RESET should be called for the same name as BUFFER_INIT */ -#define BUFFER_INIT( Name, OptimizedSize, Size ) \ - char Name ## _Raw [ OptimizedSize ]; \ - char *Name = Name ## _Raw; \ - if( sizeof(Name ## _Raw) < Size ) { \ - Name = new char[ Size ];\ - } \ - memset( Name, 0, Size ) +#define BUFFER_INIT(Name, OptimizedSize, Size) \ + char Name##_Raw[OptimizedSize]; \ + char *Name = Name##_Raw; \ + if (sizeof(Name##_Raw) < Size) { \ + Name = new char[Size]; \ + } \ + memset(Name, 0, Size) -#define BUFFER_RESET( Name ) \ - do { \ - if( Name != Name ## _Raw ) { \ - delete[] Name; \ - Name = Name ## _Raw; \ - } \ - } while(0) +#define BUFFER_RESET(Name) \ + do { \ + if (Name != Name##_Raw) { \ + delete[] Name; \ + Name = Name##_Raw; \ + } \ + } while (0) } // namespace encfs #endif - diff --git a/fs/NullNameIO.cpp b/fs/NullNameIO.cpp index 0b78e64..79cc9f1 100644 --- a/fs/NullNameIO.cpp +++ b/fs/NullNameIO.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -26,63 +26,43 @@ namespace encfs { -static shared_ptr NewNNIO( const Interface &, - const shared_ptr & ) -{ - return shared_ptr( new NullNameIO() ); +static shared_ptr NewNNIO(const Interface &, + const shared_ptr &) { + return shared_ptr(new NullNameIO()); } static Interface NNIOIface = makeInterface("nameio/null", 1, 0, 0); -static bool NullNameIO_registered = NameIO::Register("Null", - "No encryption of filenames", NNIOIface, NewNNIO, false); +static bool NullNameIO_registered = NameIO::Register( + "Null", "No encryption of filenames", NNIOIface, NewNNIO, false); -NullNameIO::NullNameIO( ) -{ -} +NullNameIO::NullNameIO() {} -NullNameIO::~NullNameIO() -{ -} +NullNameIO::~NullNameIO() {} -Interface NullNameIO::interface() const -{ - return NNIOIface; -} +Interface NullNameIO::interface() const { return NNIOIface; } -Interface NullNameIO::CurrentInterface() -{ - return NNIOIface; -} +Interface NullNameIO::CurrentInterface() { return NNIOIface; } - -int NullNameIO::maxEncodedNameLen( int plaintextNameLen ) const -{ +int NullNameIO::maxEncodedNameLen(int plaintextNameLen) const { return plaintextNameLen; } -int NullNameIO::maxDecodedNameLen( int encodedNameLen ) const -{ +int NullNameIO::maxDecodedNameLen(int encodedNameLen) const { return encodedNameLen; } -int NullNameIO::encodeName( const char *plaintextName, int length, - uint64_t *iv, char *encodedName ) const -{ - memcpy( encodedName, plaintextName, length ); +int NullNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv, + char *encodedName) const { + memcpy(encodedName, plaintextName, length); return length; } -int NullNameIO::decodeName( const char *encodedName, int length, - uint64_t *iv, char *plaintextName ) const -{ - memcpy( plaintextName, encodedName, length ); +int NullNameIO::decodeName(const char *encodedName, int length, uint64_t *iv, + char *plaintextName) const { + memcpy(plaintextName, encodedName, length); return length; } -bool NullNameIO::Enabled() -{ - return true; -} +bool NullNameIO::Enabled() { return true; } } // namespace encfs - diff --git a/fs/NullNameIO.h b/fs/NullNameIO.h index 3f1f1f1..acdbb12 100644 --- a/fs/NullNameIO.h +++ b/fs/NullNameIO.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -25,31 +25,31 @@ namespace encfs { -class NullNameIO : public NameIO -{ -public: - static Interface CurrentInterface(); +class NullNameIO : public NameIO { + public: + static Interface CurrentInterface(); - NullNameIO( ); + NullNameIO(); - virtual ~NullNameIO(); + virtual ~NullNameIO(); - virtual Interface interface() const; + virtual Interface interface() const; - virtual int maxEncodedNameLen( int plaintextNameLen ) const; - virtual int maxDecodedNameLen( int encodedNameLen ) const; + virtual int maxEncodedNameLen(int plaintextNameLen) const; + virtual int maxDecodedNameLen(int encodedNameLen) const; - // hack to help with static builds - static bool Enabled(); -protected: - virtual int encodeName( const char *plaintextName, int length, - uint64_t *iv, char *encodedName ) const; - virtual int decodeName( const char *encodedName, int length, - uint64_t *iv, char *plaintextName ) const; -private: + // hack to help with static builds + static bool Enabled(); + + protected: + virtual int encodeName(const char *plaintextName, int length, uint64_t *iv, + char *encodedName) const; + virtual int decodeName(const char *encodedName, int length, uint64_t *iv, + char *plaintextName) const; + + private: }; } // namespace encfs #endif - diff --git a/fs/RawFileIO.cpp b/fs/RawFileIO.cpp index fa76676..d4d129e 100644 --- a/fs/RawFileIO.cpp +++ b/fs/RawFileIO.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -19,7 +19,7 @@ */ #ifdef linux -#define _XOPEN_SOURCE 500 // pick up pread , pwrite +#define _XOPEN_SOURCE 500 // pick up pread , pwrite #endif #include @@ -39,57 +39,41 @@ namespace encfs { static Interface RawFileIO_iface = makeInterface("FileIO/Raw", 1, 0, 0); -FileIO *NewRawFileIO( const Interface &iface ) -{ - (void)iface; - return new RawFileIO(); +FileIO *NewRawFileIO(const Interface &iface) { + (void)iface; + return new RawFileIO(); } -inline void swap( int &x, int &y ) -{ - int tmp = x; - x = y; - y = tmp; +inline void swap(int &x, int &y) { + int tmp = x; + x = y; + y = tmp; } -RawFileIO::RawFileIO( ) - : knownSize( false ) - , fileSize(0) - , fd( -1 ) - , oldfd( -1 ) - , canWrite( false ) -{ -} +RawFileIO::RawFileIO() + : knownSize(false), fileSize(0), fd(-1), oldfd(-1), canWrite(false) {} -RawFileIO::RawFileIO( const std::string &fileName ) - : name( fileName ) - , knownSize( false ) - , fileSize( 0 ) - , fd( -1 ) - , oldfd( -1 ) - , canWrite( false ) -{ -} +RawFileIO::RawFileIO(const std::string &fileName) + : name(fileName), + knownSize(false), + fileSize(0), + fd(-1), + oldfd(-1), + canWrite(false) {} -RawFileIO::~RawFileIO() -{ +RawFileIO::~RawFileIO() { int _fd = -1; int _oldfd = -1; - swap( _fd, fd ); - swap( _oldfd, oldfd ); + swap(_fd, fd); + swap(_oldfd, oldfd); - if( _oldfd != -1 ) - close( _oldfd ); + if (_oldfd != -1) close(_oldfd); - if( _fd != -1 ) - close( _fd ); + if (_fd != -1) close(_fd); } -Interface RawFileIO::interface() const -{ - return RawFileIO_iface; -} +Interface RawFileIO::interface() const { return RawFileIO_iface; } /* Workaround for opening a file for write when permissions don't allow. @@ -98,19 +82,16 @@ Interface RawFileIO::interface() const be called with a lock around it so that there won't be a race condition with calls to lstat picking up the wrong permissions. */ -static int open_readonly_workaround(const char *path, int flags) -{ +static int open_readonly_workaround(const char *path, int flags) { int fd = -1; struct stat stbuf; memset(&stbuf, 0, sizeof(struct stat)); - if(lstat( path, &stbuf ) != -1) - { + if (lstat(path, &stbuf) != -1) { // make sure user has read/write permission.. - chmod( path , stbuf.st_mode | 0600 ); - fd = ::open( path , flags ); - chmod( path , stbuf.st_mode ); - } else - { + chmod(path, stbuf.st_mode | 0600); + fd = ::open(path, flags); + chmod(path, stbuf.st_mode); + } else { LOG(INFO) << "can't stat file " << path; } @@ -126,48 +107,40 @@ static int open_readonly_workaround(const char *path, int flags) - Also keep the O_LARGEFILE flag, in case the underlying filesystem needs it.. */ -int RawFileIO::open(int flags) -{ +int RawFileIO::open(int flags) { bool requestWrite = ((flags & O_RDWR) || (flags & O_WRONLY)); - VLOG(1) << "open call for " - << (requestWrite ? "writable" : "read only") - << " file"; + VLOG(1) << "open call for " << (requestWrite ? "writable" : "read only") + << " file"; int result = 0; // if we have a descriptor and it is writable, or we don't need writable.. - if((fd >= 0) && (canWrite || !requestWrite)) - { + if ((fd >= 0) && (canWrite || !requestWrite)) { VLOG(1) << "using existing file descriptor"; - result = fd; // success - } else - { + result = fd; // success + } else { int finalFlags = requestWrite ? O_RDWR : O_RDONLY; #if defined(O_LARGEFILE) - if( flags & O_LARGEFILE ) - finalFlags |= O_LARGEFILE; + if (flags & O_LARGEFILE) finalFlags |= O_LARGEFILE; #else #warning O_LARGEFILE not supported #endif - int newFd = ::open( name.c_str(), finalFlags ); + int newFd = ::open(name.c_str(), finalFlags); VLOG(1) << "open file with flags " << finalFlags << ", result = " << newFd; - if((newFd == -1) && (errno == EACCES)) - { + if ((newFd == -1) && (errno == EACCES)) { VLOG(1) << "using readonly workaround for open"; - newFd = open_readonly_workaround( name.c_str(), finalFlags ); + newFd = open_readonly_workaround(name.c_str(), finalFlags); } - if(newFd >= 0) - { - if(oldfd >= 0) - { - LOG(ERROR) << "leaking FD?: oldfd = " - << oldfd << ", fd = " << fd << ", newfd = " << newFd; + if (newFd >= 0) { + if (oldfd >= 0) { + LOG(ERROR) << "leaking FD?: oldfd = " << oldfd << ", fd = " << fd + << ", newfd = " << newFd; } // the old fd might still be in use, so just keep it around for @@ -175,8 +148,7 @@ int RawFileIO::open(int flags) canWrite = requestWrite; oldfd = fd; result = fd = newFd; - } else - { + } else { result = -errno; LOG(INFO) << "::open error: " << strerror(errno); } @@ -187,68 +159,53 @@ int RawFileIO::open(int flags) return result; } -int RawFileIO::getAttr( struct stat *stbuf ) const -{ - int res = lstat( name.c_str(), stbuf ); +int RawFileIO::getAttr(struct stat *stbuf) const { + int res = lstat(name.c_str(), stbuf); int eno = errno; - LOG_IF(INFO, res < 0) << "getAttr error on " << name - << ": " << strerror( eno ); + LOG_IF(INFO, res < 0) << "getAttr error on " << name << ": " << strerror(eno); - return ( res < 0 ) ? -eno : 0; + return (res < 0) ? -eno : 0; } -void RawFileIO::setFileName( const char *fileName ) -{ - name = fileName; -} +void RawFileIO::setFileName(const char *fileName) { name = fileName; } -const char *RawFileIO::getFileName() const -{ - return name.c_str(); -} +const char *RawFileIO::getFileName() const { return name.c_str(); } -off_t RawFileIO::getSize() const -{ - if(!knownSize) - { +off_t RawFileIO::getSize() const { + if (!knownSize) { struct stat stbuf; - memset( &stbuf, 0, sizeof( struct stat )); - int res = lstat( name.c_str(), &stbuf ); + memset(&stbuf, 0, sizeof(struct stat)); + int res = lstat(name.c_str(), &stbuf); - if(res == 0) - { + if (res == 0) { fileSize = stbuf.st_size; knownSize = true; return fileSize; } else return -1; - } else - { + } else { return fileSize; } } -ssize_t RawFileIO::read( const IORequest &req ) const -{ - rAssert( fd >= 0 ); +ssize_t RawFileIO::read(const IORequest &req) const { + rAssert(fd >= 0); VLOG(2) << "Read " << req.dataLen << " bytes from offset " << req.offset; - ssize_t readSize = pread( fd, req.data, req.dataLen, req.offset ); + ssize_t readSize = pread(fd, req.data, req.dataLen, req.offset); - if(readSize < 0) - { - LOG(INFO) << "read failed at offset " << req.offset - << " for " << req.dataLen << " bytes: " << strerror(errno); + if (readSize < 0) { + LOG(INFO) << "read failed at offset " << req.offset << " for " + << req.dataLen << " bytes: " << strerror(errno); } return readSize; } -bool RawFileIO::write( const IORequest &req ) -{ - rAssert( fd >= 0 ); - rAssert( true == canWrite ); +bool RawFileIO::write(const IORequest &req) { + rAssert(fd >= 0); + rAssert(true == canWrite); VLOG(2) << "Write " << req.dataLen << " bytes to offset " << req.offset; @@ -257,65 +214,55 @@ bool RawFileIO::write( const IORequest &req ) ssize_t bytes = req.dataLen; off_t offset = req.offset; - while( bytes && retrys > 0 ) - { - ssize_t writeSize = ::pwrite( fd, buf, bytes, offset ); + while (bytes && retrys > 0) { + ssize_t writeSize = ::pwrite(fd, buf, bytes, offset); - if( writeSize < 0 ) - { + if (writeSize < 0) { knownSize = false; - LOG(INFO) << "write failed at offset " << offset << " for " - << bytes << " bytes: " << strerror(errno); + LOG(INFO) << "write failed at offset " << offset << " for " << bytes + << " bytes: " << strerror(errno); return false; } bytes -= writeSize; offset += writeSize; - buf = (void*)((char*)buf + writeSize); + buf = (void *)((char *)buf + writeSize); --retrys; } - if(bytes != 0) - { - LOG(ERROR) << "Write error: wrote " << (req.dataLen-bytes) - << " bytes of " << req.dataLen << ", max retries reached"; + if (bytes != 0) { + LOG(ERROR) << "Write error: wrote " << (req.dataLen - bytes) << " bytes of " + << req.dataLen << ", max retries reached"; knownSize = false; return false; - } else - { - if(knownSize) - { + } else { + if (knownSize) { off_t last = req.offset + req.dataLen; - if(last > fileSize) - fileSize = last; + if (last > fileSize) fileSize = last; } return true; } } -int RawFileIO::truncate( off_t size ) -{ +int RawFileIO::truncate(off_t size) { int res; - if(fd >= 0 && canWrite) - { - res = ::ftruncate( fd, size ); + if (fd >= 0 && canWrite) { + res = ::ftruncate(fd, size); #ifndef __FreeBSD__ - ::fdatasync( fd ); + ::fdatasync(fd); #endif } else - res = ::truncate( name.c_str(), size ); + res = ::truncate(name.c_str(), size); - if(res < 0) - { + if (res < 0) { int eno = errno; - LOG(INFO) << "truncate failed for " << name - << " (" << fd << ") size " << size << ", error " << strerror(eno); + LOG(INFO) << "truncate failed for " << name << " (" << fd << ") size " + << size << ", error " << strerror(eno); res = -eno; knownSize = false; - } else - { + } else { res = 0; fileSize = size; knownSize = true; @@ -324,10 +271,6 @@ int RawFileIO::truncate( off_t size ) return res; } -bool RawFileIO::isWritable() const -{ - return canWrite; -} +bool RawFileIO::isWritable() const { return canWrite; } } // namespace encfs - diff --git a/fs/RawFileIO.h b/fs/RawFileIO.h index dc7c7ab..97ead7f 100644 --- a/fs/RawFileIO.h +++ b/fs/RawFileIO.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -27,42 +27,40 @@ namespace encfs { -class RawFileIO : public FileIO -{ -public: - RawFileIO(); - RawFileIO( const std::string &fileName ); - virtual ~RawFileIO(); +class RawFileIO : public FileIO { + public: + RawFileIO(); + RawFileIO(const std::string &fileName); + virtual ~RawFileIO(); - virtual Interface interface() const; + virtual Interface interface() const; - virtual void setFileName( const char *fileName ); - virtual const char *getFileName() const; + virtual void setFileName(const char *fileName); + virtual const char *getFileName() const; - virtual int open( int flags ); - - virtual int getAttr( struct stat *stbuf ) const; - virtual off_t getSize() const; + virtual int open(int flags); - virtual ssize_t read( const IORequest & req ) const; - virtual bool write( const IORequest &req ); + virtual int getAttr(struct stat *stbuf) const; + virtual off_t getSize() const; - virtual int truncate( off_t size ); + virtual ssize_t read(const IORequest &req) const; + virtual bool write(const IORequest &req); - virtual bool isWritable() const; -protected: + virtual int truncate(off_t size); - std::string name; + virtual bool isWritable() const; - mutable bool knownSize; - mutable off_t fileSize; + protected: + std::string name; - int fd; - int oldfd; - bool canWrite; + mutable bool knownSize; + mutable off_t fileSize; + + int fd; + int oldfd; + bool canWrite; }; } // namespace encfs #endif - diff --git a/fs/StreamNameIO.cpp b/fs/StreamNameIO.cpp index 77968cf..f92acc6 100644 --- a/fs/StreamNameIO.cpp +++ b/fs/StreamNameIO.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -30,17 +30,15 @@ namespace encfs { -static shared_ptr NewStreamNameIO( const Interface &iface, - const shared_ptr &cipher ) -{ - return shared_ptr( new StreamNameIO( iface, cipher ) ); +static shared_ptr NewStreamNameIO(const Interface &iface, + const shared_ptr &cipher) { + return shared_ptr(new StreamNameIO(iface, cipher)); } -static bool StreamIO_registered = NameIO::Register("Stream", +static bool StreamIO_registered = NameIO::Register( + "Stream", gettext_noop("Stream encoding, keeps filenames as short as possible"), - StreamNameIO::CurrentInterface(), - NewStreamNameIO, true); - + StreamNameIO::CurrentInterface(), NewStreamNameIO, true); /* - Version 0.1 is for EncFS 0.x support. The difference to 1.0 is that 0.x @@ -63,144 +61,117 @@ static bool StreamIO_registered = NameIO::Register("Stream", - Version 2.1 adds support for version 0 for EncFS 0.x compatibility. */ -Interface StreamNameIO::CurrentInterface() -{ +Interface StreamNameIO::CurrentInterface() { // implement major version 2, 1, and 0 return makeInterface("nameio/stream", 2, 1, 2); } -StreamNameIO::StreamNameIO( const Interface &iface, - const shared_ptr &cipher ) - : _interface( iface.major() ) - , _cipher( cipher ) -{ +StreamNameIO::StreamNameIO(const Interface &iface, + const shared_ptr &cipher) + : _interface(iface.major()), _cipher(cipher) {} -} +StreamNameIO::~StreamNameIO() {} -StreamNameIO::~StreamNameIO() -{ -} +Interface StreamNameIO::interface() const { return CurrentInterface(); } -Interface StreamNameIO::interface() const -{ - return CurrentInterface(); -} - -int StreamNameIO::maxEncodedNameLen( int plaintextStreamLen ) const -{ +int StreamNameIO::maxEncodedNameLen(int plaintextStreamLen) const { int encodedStreamLen = 2 + plaintextStreamLen; - return B256ToB64Bytes( encodedStreamLen ); + return B256ToB64Bytes(encodedStreamLen); } -int StreamNameIO::maxDecodedNameLen( int encodedStreamLen ) const -{ - int decLen256 = B64ToB256Bytes( encodedStreamLen ); +int StreamNameIO::maxDecodedNameLen(int encodedStreamLen) const { + int decLen256 = B64ToB256Bytes(encodedStreamLen); return decLen256 - 2; } -int StreamNameIO::encodeName( const char *plaintextName, int length, - uint64_t *iv, char *encodedName ) const -{ +int StreamNameIO::encodeName(const char *plaintextName, int length, + uint64_t *iv, char *encodedName) const { uint64_t tmpIV = 0; - if( iv && _interface >= 2 ) - tmpIV = *iv; + if (iv && _interface >= 2) tmpIV = *iv; unsigned int mac = _cipher->reduceMac16( - _cipher->MAC_64((const byte *)plaintextName, length, iv )); + _cipher->MAC_64((const byte *)plaintextName, length, iv)); // add on checksum bytes unsigned char *encodeBegin; - if(_interface >= 1) - { + if (_interface >= 1) { // current versions store the checksum at the beginning encodedName[0] = (mac >> 8) & 0xff; - encodedName[1] = (mac ) & 0xff; - encodeBegin = (unsigned char *)encodedName+2; - } else - { + encodedName[1] = (mac) & 0xff; + encodeBegin = (unsigned char *)encodedName + 2; + } else { // encfs 0.x stored checksums at the end. encodedName[length] = (mac >> 8) & 0xff; - encodedName[length+1] = (mac ) & 0xff; + encodedName[length + 1] = (mac) & 0xff; encodeBegin = (unsigned char *)encodedName; } // stream encode the plaintext bytes - memcpy( encodeBegin, plaintextName, length ); - _cipher->streamEncode( encodeBegin, length, (uint64_t)mac ^ tmpIV); + memcpy(encodeBegin, plaintextName, length); + _cipher->streamEncode(encodeBegin, length, (uint64_t)mac ^ tmpIV); // convert the entire thing to base 64 ascii.. int encodedStreamLen = length + 2; - int encLen64 = B256ToB64Bytes( encodedStreamLen ); + int encLen64 = B256ToB64Bytes(encodedStreamLen); - changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen, - 8, 6, true ); - B64ToAscii( (unsigned char *)encodedName, encLen64 ); + changeBase2Inline((unsigned char *)encodedName, encodedStreamLen, 8, 6, true); + B64ToAscii((unsigned char *)encodedName, encLen64); return encLen64; } -int StreamNameIO::decodeName( const char *encodedName, int length, - uint64_t *iv, char *plaintextName ) const -{ +int StreamNameIO::decodeName(const char *encodedName, int length, uint64_t *iv, + char *plaintextName) const { rAssert(length > 2); - int decLen256 = B64ToB256Bytes( length ); + int decLen256 = B64ToB256Bytes(length); int decodedStreamLen = decLen256 - 2; - if(decodedStreamLen <= 0) - throw Error("Filename too small to decode"); + if (decodedStreamLen <= 0) throw Error("Filename too small to decode"); - BUFFER_INIT( tmpBuf, 32, (unsigned int)length ); + BUFFER_INIT(tmpBuf, 32, (unsigned int)length); // decode into tmpBuf, because this step produces more data then we can fit // into the result buffer.. - AsciiToB64( (unsigned char *)tmpBuf, (unsigned char *)encodedName, length ); + AsciiToB64((unsigned char *)tmpBuf, (unsigned char *)encodedName, length); changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false); // pull out the checksum value which is used as an initialization vector uint64_t tmpIV = 0; unsigned int mac; - if(_interface >= 1) - { + if (_interface >= 1) { // current versions store the checksum at the beginning - mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 - | ((unsigned int)((unsigned char)tmpBuf[1])); + mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 | + ((unsigned int)((unsigned char)tmpBuf[1])); // version 2 adds support for IV chaining.. - if( iv && _interface >= 2 ) - tmpIV = *iv; + if (iv && _interface >= 2) tmpIV = *iv; - memcpy( plaintextName, tmpBuf+2, decodedStreamLen ); - } else - { + memcpy(plaintextName, tmpBuf + 2, decodedStreamLen); + } else { // encfs 0.x stored checksums at the end. - mac = ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen])) << 8 - | ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen+1])); + mac = ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen])) << 8 | + ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen + 1])); - memcpy( plaintextName, tmpBuf, decodedStreamLen ); + memcpy(plaintextName, tmpBuf, decodedStreamLen); } - _cipher->streamDecode( (unsigned char *)plaintextName, decodedStreamLen, - (uint64_t)mac ^ tmpIV ); + _cipher->streamDecode((unsigned char *)plaintextName, decodedStreamLen, + (uint64_t)mac ^ tmpIV); // compute MAC to check with stored value unsigned int mac2 = _cipher->reduceMac16( _cipher->MAC_64((const byte *)plaintextName, decodedStreamLen, iv)); - BUFFER_RESET( tmpBuf ); - if(mac2 != mac) - { + BUFFER_RESET(tmpBuf); + if (mac2 != mac) { VLOG(1) << "checksum mismatch: expected " << mac << ", got " << mac2 - << "on decode of " << decodedStreamLen << " bytes"; - throw Error( "checksum mismatch in filename decode" ); + << "on decode of " << decodedStreamLen << " bytes"; + throw Error("checksum mismatch in filename decode"); } return decodedStreamLen; } -bool StreamNameIO::Enabled() -{ - return true; -} +bool StreamNameIO::Enabled() { return true; } } // namespace encfs - diff --git a/fs/StreamNameIO.h b/fs/StreamNameIO.h index 60b03de..923ee1c 100644 --- a/fs/StreamNameIO.h +++ b/fs/StreamNameIO.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -27,33 +27,32 @@ namespace encfs { class CipherV1; -class StreamNameIO : public NameIO -{ -public: - static Interface CurrentInterface(); +class StreamNameIO : public NameIO { + public: + static Interface CurrentInterface(); - StreamNameIO( const Interface &iface, - const shared_ptr &cipher); - virtual ~StreamNameIO(); + StreamNameIO(const Interface &iface, const shared_ptr &cipher); + virtual ~StreamNameIO(); - virtual Interface interface() const; + virtual Interface interface() const; - virtual int maxEncodedNameLen( int plaintextNameLen ) const; - virtual int maxDecodedNameLen( int encodedNameLen ) const; + virtual int maxEncodedNameLen(int plaintextNameLen) const; + virtual int maxDecodedNameLen(int encodedNameLen) const; - // hack to help with static builds - static bool Enabled(); -protected: - virtual int encodeName( const char *plaintextName, int length, - uint64_t *iv, char *encodedName ) const; - virtual int decodeName( const char *encodedName, int length, - uint64_t *iv, char *plaintextName ) const; -private: - int _interface; - shared_ptr _cipher; + // hack to help with static builds + static bool Enabled(); + + protected: + virtual int encodeName(const char *plaintextName, int length, uint64_t *iv, + char *encodedName) const; + virtual int decodeName(const char *encodedName, int length, uint64_t *iv, + char *plaintextName) const; + + private: + int _interface; + shared_ptr _cipher; }; } // namespace encfs #endif - diff --git a/fs/checkops.cpp b/fs/checkops.cpp index 48f5b9c..cf8ed02 100644 --- a/fs/checkops.cpp +++ b/fs/checkops.cpp @@ -54,47 +54,40 @@ namespace encfs { const int FSBlockSize = 256; -static -int checkErrorPropogation( const shared_ptr &cipher, - int size, int byteToChange ) -{ +static int checkErrorPropogation(const shared_ptr &cipher, int size, + int byteToChange) { MemBlock orig; orig.allocate(size); MemBlock data; data.allocate(size); - for(int i=0; istreamEncode( data.data, size, 0 ); + if (size != FSBlockSize) + cipher->streamEncode(data.data, size, 0); else - cipher->blockEncode( data.data, size, 0 ); + cipher->blockEncode(data.data, size, 0); // intoduce an error in the encoded data, so we can check error propogation - if(byteToChange >= 0 && byteToChange < size) - { + if (byteToChange >= 0 && byteToChange < size) { unsigned char previousValue = data.data[byteToChange]; - do - { + do { data.data[byteToChange] = rand(); - } while(data.data[byteToChange] == previousValue); + } while (data.data[byteToChange] == previousValue); } - if(size != FSBlockSize) - cipher->streamDecode( data.data, size, 0 ); + if (size != FSBlockSize) + cipher->streamDecode(data.data, size, 0); else - cipher->blockDecode( data.data, size, 0 ); + cipher->blockDecode(data.data, size, 0); int numByteErrors = 0; - for(int i=0; i &cipher, const char TEST_ROOTDIR[] = "/foo"; -static -bool testNameCoding( DirNode &dirNode, bool verbose, - bool collisionTest = false ) -{ +static bool testNameCoding(DirNode &dirNode, bool verbose, + bool collisionTest = false) { // encrypt a name const char *name[] = { - "1234567", - "12345678", - "123456789", - "123456789ABCDEF", - "123456789ABCDEF0", - "123456789ABCDEF01", - "test-name", - "test-name2", - "test", - "../test", - "/foo/bar/blah", - "test-name.21", - "test-name.22", - "test-name.o", - "1.test", - "2.test", - "a/b/c/d", - "a/c/d/e", - "b/c/d/e", - "b/a/c/d", - NULL - }; + "1234567", "12345678", "123456789", + "123456789ABCDEF", "123456789ABCDEF0", "123456789ABCDEF01", + "test-name", "test-name2", "test", + "../test", "/foo/bar/blah", "test-name.21", + "test-name.22", "test-name.o", "1.test", + "2.test", "a/b/c/d", "a/c/d/e", + "b/c/d/e", "b/a/c/d", NULL}; const char **orig = name; - while(*orig) - { - if(verbose) - cerr << " coding name \"" << *orig << "\""; + while (*orig) { + if (verbose) cerr << " coding name \"" << *orig << "\""; - string encName = dirNode.relativeCipherPath( *orig ); + string encName = dirNode.relativeCipherPath(*orig); - if(verbose) - cerr << " -> \"" << encName.c_str() << "\""; + if (verbose) cerr << " -> \"" << encName.c_str() << "\""; // decrypt name - string decName = dirNode.plainPath( encName.c_str() ); + string decName = dirNode.plainPath(encName.c_str()); - if(decName == *orig) - { - if(verbose) - cerr << " OK\n"; - } else - { - if(verbose) - cerr << " FAILED (got " << decName << ")\n"; + if (decName == *orig) { + if (verbose) cerr << " OK\n"; + } else { + if (verbose) cerr << " FAILED (got " << decName << ")\n"; return false; } orig++; } - if (collisionTest) - { + if (collisionTest) { if (verbose) cerr << "Checking for name collections, this will take a while..\n"; // check for collision rate char buf[64]; unordered_set encryptedNames; - for (long i=0; i < 10000000; i++) - { + for (long i = 0; i < 10000000; i++) { snprintf(buf, sizeof(buf), "%li", i); - string encName = dirNode.relativeCipherPath( buf ); + string encName = dirNode.relativeCipherPath(buf); // simulate a case-insisitive filesystem.. std::transform(encName.begin(), encName.end(), encName.begin(), - ::toupper); + ::toupper); if (encryptedNames.insert(encName).second == false) { cerr << "collision detected after " << i << " iterations"; @@ -185,60 +152,51 @@ bool testNameCoding( DirNode &dirNode, bool verbose, return true; } -bool runTests(const shared_ptr &cipher, bool verbose) -{ +bool runTests(const shared_ptr &cipher, bool verbose) { // create a random key - if(verbose) + if (verbose) cerr << "Generating new key, output will be different on each run\n\n"; CipherKey key = cipher->newRandomKey(); - if(verbose) - cerr << "Testing key save / restore :"; + if (verbose) cerr << "Testing key save / restore :"; { CipherKey encodingKey = cipher->newRandomKey(); int encodedKeySize = cipher->encodedKeySize(); - unsigned char *keyBuf = new unsigned char [ encodedKeySize ]; + unsigned char *keyBuf = new unsigned char[encodedKeySize]; cipher->setKey(encodingKey); - cipher->writeKey( key, keyBuf ); - CipherKey key2 = cipher->readKey( keyBuf, true ); + cipher->writeKey(key, keyBuf); + CipherKey key2 = cipher->readKey(keyBuf, true); delete[] keyBuf; - if(!key2.valid()) - { - if(verbose) - cerr << " FAILED (decode error)\n"; + if (!key2.valid()) { + if (verbose) cerr << " FAILED (decode error)\n"; return false; } - if(key == key2) - { - if(verbose) - cerr << " OK\n"; - } else - { - if(verbose) - cerr << " FAILED\n"; + if (key == key2) { + if (verbose) cerr << " OK\n"; + } else { + if (verbose) cerr << " FAILED\n"; return false; } } - if(verbose) - cerr << "Testing Config interface load / store :"; + if (verbose) cerr << "Testing Config interface load / store :"; { CipherKey encodingKey = cipher->newRandomKey(); int encodedKeySize = cipher->encodedKeySize(); - unsigned char *keyBuf = new unsigned char [ encodedKeySize ]; + unsigned char *keyBuf = new unsigned char[encodedKeySize]; cipher->setKey(encodingKey); - cipher->writeKey( key, keyBuf ); + cipher->writeKey(key, keyBuf); // store in config struct.. EncfsConfig cfg; cfg.mutable_cipher()->MergeFrom(cipher->interface()); EncryptedKey *encryptedKey = cfg.mutable_key(); encryptedKey->set_size(8 * cipher->keySize()); - encryptedKey->set_ciphertext( keyBuf, encodedKeySize ); + encryptedKey->set_ciphertext(keyBuf, encodedKeySize); cfg.set_block_size(FSBlockSize); delete[] keyBuf; @@ -252,27 +210,22 @@ bool runTests(const shared_ptr &cipher, bool verbose) google::protobuf::TextFormat::ParseFromString(data, &cfg2); // check.. - rAssert( implements(cfg.cipher(),cfg2.cipher()) ); - rAssert( cfg.key().size() == cfg2.key().size() ); - rAssert( cfg.block_size() == cfg2.block_size() ); + rAssert(implements(cfg.cipher(), cfg2.cipher())); + rAssert(cfg.key().size() == cfg2.key().size()); + rAssert(cfg.block_size() == cfg2.block_size()); // try decoding key.. - CipherKey key2 = cipher->readKey( (unsigned char *)cfg2.key().ciphertext().data(), true ); - if(!key2.valid()) - { - if(verbose) - cerr << " FAILED (decode error)\n"; + CipherKey key2 = + cipher->readKey((unsigned char *)cfg2.key().ciphertext().data(), true); + if (!key2.valid()) { + if (verbose) cerr << " FAILED (decode error)\n"; return false; } - if(key == key2) - { - if(verbose) - cerr << " OK\n"; - } else - { - if(verbose) - cerr << " FAILED\n"; + if (key == key2) { + if (verbose) cerr << " OK\n"; + } else { + if (verbose) cerr << " FAILED\n"; return false; } } @@ -285,175 +238,145 @@ bool runTests(const shared_ptr &cipher, bool verbose) fsCfg->opts.reset(new EncFS_Opts); cipher->setKey(key); - if(verbose) + if (verbose) cerr << "Testing name encode/decode (stream coding w/ IV chaining)\n"; { fsCfg->opts->idleTracking = false; fsCfg->config->set_unique_iv(false); - fsCfg->nameCoding.reset( new StreamNameIO( - StreamNameIO::CurrentInterface(), cipher) ); - fsCfg->nameCoding->setChainedNameIV( true ); + fsCfg->nameCoding.reset( + new StreamNameIO(StreamNameIO::CurrentInterface(), cipher)); + fsCfg->nameCoding->setChainedNameIV(true); - DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); + DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg); - if(!testNameCoding( dirNode, verbose )) - return false; + if (!testNameCoding(dirNode, verbose)) return false; } - if(verbose) + if (verbose) cerr << "Testing name encode/decode (block coding w/ IV chaining)\n"; { fsCfg->opts->idleTracking = false; fsCfg->config->set_unique_iv(false); - fsCfg->nameCoding.reset( new BlockNameIO( - BlockNameIO::CurrentInterface(), cipher) ); - fsCfg->nameCoding->setChainedNameIV( true ); + fsCfg->nameCoding.reset( + new BlockNameIO(BlockNameIO::CurrentInterface(), cipher)); + fsCfg->nameCoding->setChainedNameIV(true); - DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); + DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg); - if(!testNameCoding( dirNode, verbose )) - return false; + if (!testNameCoding(dirNode, verbose)) return false; } - if(verbose) - cerr << "Testing name encode/decode (block coding w/ IV chaining, base32)\n"; + if (verbose) + cerr + << "Testing name encode/decode (block coding w/ IV chaining, base32)\n"; { fsCfg->opts->idleTracking = false; fsCfg->config->set_unique_iv(false); - fsCfg->nameCoding.reset( new BlockNameIO( - BlockNameIO::CurrentInterface(), cipher) ); - fsCfg->nameCoding->setChainedNameIV( true ); + fsCfg->nameCoding.reset( + new BlockNameIO(BlockNameIO::CurrentInterface(), cipher)); + fsCfg->nameCoding->setChainedNameIV(true); - DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); + DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg); - if(!testNameCoding( dirNode, verbose )) - return false; + if (!testNameCoding(dirNode, verbose)) return false; } - if(!verbose) - { + if (!verbose) { { // test stream mode, this time without IV chaining - fsCfg->nameCoding = - shared_ptr( new StreamNameIO( - StreamNameIO::CurrentInterface(), cipher) ); - fsCfg->nameCoding->setChainedNameIV( false ); + fsCfg->nameCoding = shared_ptr( + new StreamNameIO(StreamNameIO::CurrentInterface(), cipher)); + fsCfg->nameCoding->setChainedNameIV(false); - DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); + DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg); - if(!testNameCoding( dirNode, verbose )) - return false; + if (!testNameCoding(dirNode, verbose)) return false; } { // test block mode, this time without IV chaining - fsCfg->nameCoding = shared_ptr( new BlockNameIO( - BlockNameIO::CurrentInterface(), cipher) ); - fsCfg->nameCoding->setChainedNameIV( false ); + fsCfg->nameCoding = shared_ptr( + new BlockNameIO(BlockNameIO::CurrentInterface(), cipher)); + fsCfg->nameCoding->setChainedNameIV(false); - DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); + DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg); - if(!testNameCoding( dirNode, verbose )) - return false; + if (!testNameCoding(dirNode, verbose)) return false; } } - if(verbose) - cerr << "Testing block encode/decode on full block - "; + if (verbose) cerr << "Testing block encode/decode on full block - "; { - int numErrors = checkErrorPropogation( cipher, - FSBlockSize, -1 ); - if(numErrors) - { - if(verbose) - cerr << " FAILED!\n"; + int numErrors = checkErrorPropogation(cipher, FSBlockSize, -1); + if (numErrors) { + if (verbose) cerr << " FAILED!\n"; return false; - } else - { - if(verbose) - cerr << " OK\n"; + } else { + if (verbose) cerr << " OK\n"; } } - if(verbose) - cerr << "Testing block encode/decode on partial block - "; + if (verbose) cerr << "Testing block encode/decode on partial block - "; { - int numErrors = checkErrorPropogation( cipher, - FSBlockSize-1, -1 ); - if(numErrors) - { - if(verbose) - cerr << " FAILED!\n"; + int numErrors = checkErrorPropogation(cipher, FSBlockSize - 1, -1); + if (numErrors) { + if (verbose) cerr << " FAILED!\n"; return false; - } else - { - if(verbose) - cerr << " OK\n"; + } else { + if (verbose) cerr << " OK\n"; } } - if(verbose) - cerr << "Checking error propogation in partial block:\n"; + if (verbose) cerr << "Checking error propogation in partial block:\n"; { - int minChanges = FSBlockSize-1; + int minChanges = FSBlockSize - 1; int maxChanges = 0; int minAt = 0; int maxAt = 0; - for(int i=0; i maxChanges) - { + if (numErrors > maxChanges) { maxChanges = numErrors; maxAt = i; } } - if(verbose) - { + if (verbose) { cerr << "modification of 1 byte affected between " << minChanges - << " and " << maxChanges << " decoded bytes\n"; - cerr << "minimum change at byte " << minAt - << " and maximum at byte " << maxAt << "\n"; + << " and " << maxChanges << " decoded bytes\n"; + cerr << "minimum change at byte " << minAt << " and maximum at byte " + << maxAt << "\n"; } } - if(verbose) - cerr << "Checking error propogation on full block:\n"; + if (verbose) cerr << "Checking error propogation on full block:\n"; { int minChanges = FSBlockSize; int maxChanges = 0; int minAt = 0; int maxAt = 0; - for(int i=0; i maxChanges) - { + if (numErrors > maxChanges) { maxChanges = numErrors; maxAt = i; } } - if(verbose) - { + if (verbose) { cerr << "modification of 1 byte affected between " << minChanges - << " and " << maxChanges << " decoded bytes\n"; - cerr << "minimum change at byte " << minAt - << " and maximum at byte " << maxAt << "\n"; + << " and " << maxChanges << " decoded bytes\n"; + cerr << "minimum change at byte " << minAt << " and maximum at byte " + << maxAt << "\n"; } } @@ -462,8 +385,7 @@ bool runTests(const shared_ptr &cipher, bool verbose) } // namespace encfs -int main(int argc, char *argv[]) -{ +int main(int argc, char *argv[]) { FLAGS_logtostderr = 1; FLAGS_minloglevel = 1; @@ -473,50 +395,42 @@ int main(int argc, char *argv[]) bool isThreaded = false; CipherV1::init(isThreaded); - srand( time(0) ); + srand(time(0)); // get a list of the available algorithms std::list algorithms = - CipherV1::GetAlgorithmList(); + CipherV1::GetAlgorithmList(); std::list::const_iterator it; cerr << "Supported Crypto interfaces:\n"; - for(it = algorithms.begin(); it != algorithms.end(); ++it) - { - cerr << it->name - << " ( " << it->iface.name() << " " - << it->iface.major() << ":" - << it->iface.minor() << ":" - << it->iface.age() << " ) : " << it->description << "\n"; + for (it = algorithms.begin(); it != algorithms.end(); ++it) { + cerr << it->name << " ( " << it->iface.name() << " " << it->iface.major() + << ":" << it->iface.minor() << ":" << it->iface.age() + << " ) : " << it->description << "\n"; cerr << " - key length " << it->keyLength.min() << " to " - << it->keyLength.max() << " , block size " << it->blockSize.min() - << " to " << it->blockSize.max() << "\n"; + << it->keyLength.max() << " , block size " << it->blockSize.min() + << " to " << it->blockSize.max() << "\n"; } cerr << "\n"; cerr << "Testing interfaces\n"; - for(it = algorithms.begin(); it != algorithms.end(); ++it) - { - int blockSize = it->blockSize.closest( 256 ); - for(int keySize = it->keyLength.min(); keySize <= it->keyLength.max(); - keySize += it->keyLength.inc()) - { - cerr << it->name << ", key length " << keySize - << ", block size " << blockSize << ": "; + for (it = algorithms.begin(); it != algorithms.end(); ++it) { + int blockSize = it->blockSize.closest(256); + for (int keySize = it->keyLength.min(); keySize <= it->keyLength.max(); + keySize += it->keyLength.inc()) { + cerr << it->name << ", key length " << keySize << ", block size " + << blockSize << ": "; - shared_ptr cipher = CipherV1::New( it->name, keySize ); - if(!cipher) - { + shared_ptr cipher = CipherV1::New(it->name, keySize); + if (!cipher) { cerr << "FAILED TO CREATE\n"; - } else - { - try - { - if(runTests( cipher, false )) + } else { + try { + if (runTests(cipher, false)) cerr << "OK\n"; else cerr << "FAILED\n"; - } catch( Error &er ) - { + } + catch (Error &er) { cerr << "Error: " << er.what() << "\n"; } } @@ -525,20 +439,17 @@ int main(int argc, char *argv[]) // run one test with verbose output too.. shared_ptr cipher = CipherV1::New("AES", 192); - if(!cipher) - { + if (!cipher) { cerr << "\nNo AES cipher found, skipping verbose test.\n"; - } else - { - cerr << "\nVerbose output for " << cipher->interface().name() - << " test, key length " << cipher->keySize()*8 << ", block size " - << FSBlockSize << ":\n"; + } else { + cerr << "\nVerbose output for " << cipher->interface().name() + << " test, key length " << cipher->keySize() * 8 << ", block size " + << FSBlockSize << ":\n"; - runTests( cipher, true ); + runTests(cipher, true); } CipherV1::shutdown(isThreaded); return 0; } - diff --git a/fs/encfs.cpp b/fs/encfs.cpp index e3e4f18..bfaaacc 100644 --- a/fs/encfs.cpp +++ b/fs/encfs.cpp @@ -3,8 +3,8 @@ * ***************************************************************************** * Copyright (c) 2003-2007, Valient Gough - * - * This program is free software; you can distribute it and/or modify it under + * + * This program is free software; you can distribute it and/or modify it under * the terms of the GNU General Public License (GPL), as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. @@ -71,16 +71,15 @@ using std::vector; namespace encfs { #ifndef MIN -#define MIN(a,b) (((a)<(b)) ? (a): (b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif #define ESUCCESS 0 -#define GET_FN(ctx, finfo) ctx->getNode((void*)(uintptr_t)finfo->fh) +#define GET_FN(ctx, finfo) ctx->getNode((void *)(uintptr_t)finfo->fh) -static EncFS_Context * context() -{ - return (EncFS_Context*)fuse_get_context()->private_data; +static EncFS_Context *context() { + return (EncFS_Context *)fuse_get_context()->private_data; } /* @@ -95,94 +94,82 @@ static EncFS_Context * context() */ // helper function -- apply a functor to a cipher path, given the plain path -template -static int withCipherPath( const char *opName, const char *path, - int (*op)(EncFS_Context *, const string &name, T data ), T data, - bool passReturnCode = false ) -{ +template +static int withCipherPath(const char *opName, const char *path, + int (*op)(EncFS_Context *, const string &name, + T data), + T data, bool passReturnCode = false) { EncFS_Context *ctx = context(); int res = -EIO; shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; + if (!FSRoot) return res; - try - { - string cyName = FSRoot->cipherPath( path ); + try { + string cyName = FSRoot->cipherPath(path); VLOG(1) << opName << " " << cyName.c_str(); - res = op( ctx, cyName, data ); + res = op(ctx, cyName, data); - if(res == -1) - { + if (res == -1) { res = -errno; LOG(INFO) << opName << " error: " << strerror(-res); - } else if(!passReturnCode) + } else if (!passReturnCode) res = ESUCCESS; - } catch( Error &err ) - { - LOG(ERROR) << "error caught in " << opName << - ":" << err.what(); + } + catch (Error &err) { + LOG(ERROR) << "error caught in " << opName << ":" << err.what(); } return res; } // helper function -- apply a functor to a node -template -static int withFileNode( const char *opName, - const char *path, struct fuse_file_info *fi, - int (*op)(FileNode *, T data ), T data ) -{ +template +static int withFileNode(const char *opName, const char *path, + struct fuse_file_info *fi, + int (*op)(FileNode *, T data), T data) { EncFS_Context *ctx = context(); int res = -EIO; shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; + if (!FSRoot) return res; - try - { + try { shared_ptr fnode; - if(fi != NULL) + if (fi != NULL) fnode = GET_FN(ctx, fi); else - fnode = FSRoot->lookupNode( path, opName ); + fnode = FSRoot->lookupNode(path, opName); rAssert(fnode != NULL); VLOG(1) << opName << " " << fnode->cipherName(); - res = op( fnode.get(), data ); + res = op(fnode.get(), data); LOG_IF(INFO, res < 0) << opName << " error: " << strerror(-res); - } catch( Error &err ) - { - LOG(ERROR) << "error caught in " << opName << - ":" << err.what(); + } + catch (Error &err) { + LOG(ERROR) << "error caught in " << opName << ":" << err.what(); } return res; } -int _do_getattr(FileNode *fnode, struct stat *stbuf) -{ +int _do_getattr(FileNode *fnode, struct stat *stbuf) { int res = fnode->getAttr(stbuf); - if(res == ESUCCESS && S_ISLNK(stbuf->st_mode)) - { + if (res == ESUCCESS && S_ISLNK(stbuf->st_mode)) { EncFS_Context *ctx = context(); shared_ptr FSRoot = ctx->getRoot(&res); - if(FSRoot) - { + if (FSRoot) { // determine plaintext link size.. Easiest to read and decrypt.. - vector buf(stbuf->st_size+1, 0); + vector buf(stbuf->st_size + 1, 0); - res = ::readlink( fnode->cipherName(), &buf[0], stbuf->st_size ); - if(res >= 0) - { + res = ::readlink(fnode->cipherName(), &buf[0], stbuf->st_size); + if (res >= 0) { // other functions expect c-strings to be null-terminated, which // readlink doesn't provide buf[res] = '\0'; - stbuf->st_size = FSRoot->plainPath( &buf[0] ).length(); + stbuf->st_size = FSRoot->plainPath(&buf[0]).length(); res = ESUCCESS; } else @@ -193,234 +180,199 @@ int _do_getattr(FileNode *fnode, struct stat *stbuf) return res; } -int encfs_getattr(const char *path, struct stat *stbuf) -{ - return withFileNode( "getattr", path, NULL, _do_getattr, stbuf ); +int encfs_getattr(const char *path, struct stat *stbuf) { + return withFileNode("getattr", path, NULL, _do_getattr, stbuf); } int encfs_fgetattr(const char *path, struct stat *stbuf, - struct fuse_file_info *fi) -{ - return withFileNode( "fgetattr", path, fi, _do_getattr, stbuf ); + struct fuse_file_info *fi) { + return withFileNode("fgetattr", path, fi, _do_getattr, stbuf); } -int encfs_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler) -{ +int encfs_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler) { EncFS_Context *ctx = context(); int res = ESUCCESS; shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; + if (!FSRoot) return res; - try - { + try { - DirTraverse dt = FSRoot->openDir( path ); + DirTraverse dt = FSRoot->openDir(path); VLOG(1) << "getdir on " << FSRoot->cipherPath(path); - if(dt.valid()) - { + if (dt.valid()) { int fileType = 0; ino_t inode = 0; - std::string name = dt.nextPlaintextName( &fileType, &inode ); - while( !name.empty() ) - { - res = filler( h, name.c_str(), fileType, inode ); + std::string name = dt.nextPlaintextName(&fileType, &inode); + while (!name.empty()) { + res = filler(h, name.c_str(), fileType, inode); - if(res != ESUCCESS) - break; + if (res != ESUCCESS) break; - name = dt.nextPlaintextName( &fileType, &inode ); + name = dt.nextPlaintextName(&fileType, &inode); } - } else - { + } else { LOG(INFO) << "getdir request invalid, path: '" << path << "'"; } return res; - } catch( Error &err ) - { + } + catch (Error &err) { LOG(ERROR) << "error caught in getdir: " << err.what(); return -EIO; } } -int encfs_mknod(const char *path, mode_t mode, dev_t rdev) -{ +int encfs_mknod(const char *path, mode_t mode, dev_t rdev) { EncFS_Context *ctx = context(); int res = -EIO; shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; + if (!FSRoot) return res; - try - { - shared_ptr fnode = FSRoot->lookupNode( path, "mknod" ); + try { + shared_ptr fnode = FSRoot->lookupNode(path, "mknod"); - VLOG(1) << "mknod on " << fnode->cipherName() - << ", mode " << mode << ", dev " << rdev; + VLOG(1) << "mknod on " << fnode->cipherName() << ", mode " << mode + << ", dev " << rdev; uid_t uid = 0; gid_t gid = 0; - if(ctx->publicFilesystem) - { + if (ctx->publicFilesystem) { fuse_context *context = fuse_get_context(); uid = context->uid; gid = context->gid; } - res = fnode->mknod( mode, rdev, uid, gid ); + res = fnode->mknod(mode, rdev, uid, gid); // Is this error due to access problems? - if(ctx->publicFilesystem && -res == EACCES) - { + if (ctx->publicFilesystem && -res == EACCES) { // try again using the parent dir's group string parent = fnode->plaintextParent(); - LOG(INFO) << "attempting public filesystem workaround for " + LOG(INFO) << "attempting public filesystem workaround for " << parent.c_str(); - shared_ptr dnode = - FSRoot->lookupNode( parent.c_str(), "mknod" ); + shared_ptr dnode = FSRoot->lookupNode(parent.c_str(), "mknod"); struct stat st; - if(dnode->getAttr( &st ) == 0) - res = fnode->mknod( mode, rdev, uid, st.st_gid ); + if (dnode->getAttr(&st) == 0) + res = fnode->mknod(mode, rdev, uid, st.st_gid); } - } catch( Error &err ) - { + } + catch (Error &err) { LOG(ERROR) << "error caught in mknod: " << err.what(); } return res; } -int encfs_mkdir(const char *path, mode_t mode) -{ +int encfs_mkdir(const char *path, mode_t mode) { fuse_context *fctx = fuse_get_context(); EncFS_Context *ctx = context(); int res = -EIO; shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; + if (!FSRoot) return res; - try - { + try { uid_t uid = 0; gid_t gid = 0; - if(ctx->publicFilesystem) - { + if (ctx->publicFilesystem) { uid = fctx->uid; gid = fctx->gid; } - res = FSRoot->mkdir( path, mode, uid, gid ); + res = FSRoot->mkdir(path, mode, uid, gid); // Is this error due to access problems? - if(ctx->publicFilesystem && -res == EACCES) - { + if (ctx->publicFilesystem && -res == EACCES) { // try again using the parent dir's group - string parent = parentDirectory( path ); - shared_ptr dnode = - FSRoot->lookupNode( parent.c_str(), "mkdir" ); + string parent = parentDirectory(path); + shared_ptr dnode = FSRoot->lookupNode(parent.c_str(), "mkdir"); struct stat st; - if(dnode->getAttr( &st ) == 0) - res = FSRoot->mkdir( path, mode, uid, st.st_gid ); + if (dnode->getAttr(&st) == 0) + res = FSRoot->mkdir(path, mode, uid, st.st_gid); } - } catch( Error &err ) - { + } + catch (Error &err) { LOG(ERROR) << "error caught in mkdir: " << err.what(); } return res; } -int encfs_unlink(const char *path) -{ +int encfs_unlink(const char *path) { EncFS_Context *ctx = context(); int res = -EIO; shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; + if (!FSRoot) return res; - try - { + try { // let DirNode handle it atomically so that it can handle race // conditions - res = FSRoot->unlink( path ); - } catch( Error &err ) - { + res = FSRoot->unlink(path); + } + catch (Error &err) { LOG(ERROR) << "error caught in unlink: " << err.what(); } return res; } -int _do_rmdir(EncFS_Context *, const string &cipherPath, int ) -{ - return rmdir( cipherPath.c_str() ); +int _do_rmdir(EncFS_Context *, const string &cipherPath, int) { + return rmdir(cipherPath.c_str()); } -int encfs_rmdir(const char *path) -{ - return withCipherPath( "rmdir", path, _do_rmdir, 0 ); +int encfs_rmdir(const char *path) { + return withCipherPath("rmdir", path, _do_rmdir, 0); } int _do_readlink(EncFS_Context *ctx, const string &cyName, - tuple data ) -{ + tuple data) { char *buf = get<0>(data); size_t size = get<1>(data); int res = ESUCCESS; shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; + if (!FSRoot) return res; - res = ::readlink( cyName.c_str(), buf, size-1 ); + res = ::readlink(cyName.c_str(), buf, size - 1); - if(res == -1) - return -errno; + if (res == -1) return -errno; - buf[res] = '\0'; // ensure null termination + buf[res] = '\0'; // ensure null termination string decodedName; - try - { - decodedName = FSRoot->plainPath( buf ); - } catch(...) { } + try { + decodedName = FSRoot->plainPath(buf); + } + catch (...) { + } - if(!decodedName.empty()) - { - strncpy(buf, decodedName.c_str(), size-1); - buf[size-1] = '\0'; + if (!decodedName.empty()) { + strncpy(buf, decodedName.c_str(), size - 1); + buf[size - 1] = '\0'; return ESUCCESS; - } else - { + } else { LOG(WARNING) << "Error decoding link"; return -1; } } -int encfs_readlink(const char *path, char *buf, size_t size) -{ - return withCipherPath( "readlink", path, _do_readlink, - make_tuple(buf, size) ); +int encfs_readlink(const char *path, char *buf, size_t size) { + return withCipherPath("readlink", path, _do_readlink, make_tuple(buf, size)); } -int encfs_symlink(const char *from, const char *to) -{ +int encfs_symlink(const char *from, const char *to) { EncFS_Context *ctx = context(); int res = -EIO; shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; + if (!FSRoot) return res; - try - { + try { // allow fully qualified names in symbolic links. - string fromCName = FSRoot->relativeCipherPath( from ); - string toCName = FSRoot->cipherPath( to ); + string fromCName = FSRoot->relativeCipherPath(from); + string toCName = FSRoot->cipherPath(to); VLOG(1) << "symlink " << fromCName << " -> " << toCName; @@ -428,191 +380,159 @@ int encfs_symlink(const char *from, const char *to) // uid/gid provided by the fuse_context. int olduid = -1; int oldgid = -1; - if(ctx->publicFilesystem) - { + if (ctx->publicFilesystem) { fuse_context *context = fuse_get_context(); - olduid = setfsuid( context->uid ); - oldgid = setfsgid( context->gid ); + olduid = setfsuid(context->uid); + oldgid = setfsgid(context->gid); } - res = ::symlink( fromCName.c_str(), toCName.c_str() ); - if(olduid >= 0) - setfsuid( olduid ); - if(oldgid >= 0) - setfsgid( oldgid ); + res = ::symlink(fromCName.c_str(), toCName.c_str()); + if (olduid >= 0) setfsuid(olduid); + if (oldgid >= 0) setfsgid(oldgid); - if(res == -1) + if (res == -1) res = -errno; else res = ESUCCESS; - } catch( Error &err ) - { + } + catch (Error &err) { LOG(ERROR) << "error caught in symlink: " << err.what(); } return res; } -int encfs_link(const char *from, const char *to) -{ +int encfs_link(const char *from, const char *to) { EncFS_Context *ctx = context(); int res = -EIO; shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; + if (!FSRoot) return res; - try - { - res = FSRoot->link( from, to ); - } catch( Error &err ) - { + try { + res = FSRoot->link(from, to); + } + catch (Error &err) { LOG(ERROR) << "error caught in link: " << err.what(); } return res; } -int encfs_rename(const char *from, const char *to) -{ +int encfs_rename(const char *from, const char *to) { EncFS_Context *ctx = context(); int res = -EIO; shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; + if (!FSRoot) return res; - try - { - res = FSRoot->rename( from, to ); - } catch( Error &err ) - { + try { + res = FSRoot->rename(from, to); + } + catch (Error &err) { LOG(ERROR) << "error caught in rename: " << err.what(); } return res; } -int _do_chmod(EncFS_Context *, const string &cipherPath, mode_t mode) -{ +int _do_chmod(EncFS_Context *, const string &cipherPath, mode_t mode) { #ifdef HAVE_LCHMOD - return lchmod( cipherPath.c_str(), mode ); + return lchmod(cipherPath.c_str(), mode); #else - return chmod( cipherPath.c_str(), mode ); + return chmod(cipherPath.c_str(), mode); #endif } -int encfs_chmod(const char *path, mode_t mode) -{ - return withCipherPath( "chmod", path, _do_chmod, mode ); +int encfs_chmod(const char *path, mode_t mode) { + return withCipherPath("chmod", path, _do_chmod, mode); } -int _do_chown(EncFS_Context *, const string &cyName, - tuple data) -{ - int res = lchown( cyName.c_str(), get<0>(data), get<1>(data) ); +int _do_chown(EncFS_Context *, const string &cyName, tuple data) { + int res = lchown(cyName.c_str(), get<0>(data), get<1>(data)); return (res == -1) ? -errno : ESUCCESS; } -int encfs_chown(const char *path, uid_t uid, gid_t gid) -{ - return withCipherPath( "chown", path, _do_chown, make_tuple(uid, gid)); +int encfs_chown(const char *path, uid_t uid, gid_t gid) { + return withCipherPath("chown", path, _do_chown, make_tuple(uid, gid)); } -int _do_truncate( FileNode *fnode, off_t size ) -{ - return fnode->truncate( size ); +int _do_truncate(FileNode *fnode, off_t size) { return fnode->truncate(size); } + +int encfs_truncate(const char *path, off_t size) { + return withFileNode("truncate", path, NULL, _do_truncate, size); } -int encfs_truncate(const char *path, off_t size) -{ - return withFileNode( "truncate", path, NULL, _do_truncate, size ); +int encfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi) { + return withFileNode("ftruncate", path, fi, _do_truncate, size); } -int encfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi) -{ - return withFileNode( "ftruncate", path, fi, _do_truncate, size ); -} - -int _do_utime(EncFS_Context *, const string &cyName, struct utimbuf *buf) -{ - int res = utime( cyName.c_str(), buf); +int _do_utime(EncFS_Context *, const string &cyName, struct utimbuf *buf) { + int res = utime(cyName.c_str(), buf); return (res == -1) ? -errno : ESUCCESS; } -int encfs_utime(const char *path, struct utimbuf *buf) -{ - return withCipherPath( "utime", path, _do_utime, buf ); +int encfs_utime(const char *path, struct utimbuf *buf) { + return withCipherPath("utime", path, _do_utime, buf); } -int _do_utimens(EncFS_Context *, const string &cyName, - const struct timespec ts[2]) -{ +int _do_utimens(EncFS_Context *, const string &cyName, + const struct timespec ts[2]) { struct timeval tv[2]; tv[0].tv_sec = ts[0].tv_sec; tv[0].tv_usec = ts[0].tv_nsec / 1000; tv[1].tv_sec = ts[1].tv_sec; tv[1].tv_usec = ts[1].tv_nsec / 1000; - int res = lutimes( cyName.c_str(), tv); + int res = lutimes(cyName.c_str(), tv); return (res == -1) ? -errno : ESUCCESS; } -int encfs_utimens(const char *path, const struct timespec ts[2] ) -{ - return withCipherPath( "utimens", path, _do_utimens, ts ); +int encfs_utimens(const char *path, const struct timespec ts[2]) { + return withCipherPath("utimens", path, _do_utimens, ts); } -int encfs_open(const char *path, struct fuse_file_info *file) -{ +int encfs_open(const char *path, struct fuse_file_info *file) { EncFS_Context *ctx = context(); int res = -EIO; shared_ptr FSRoot = ctx->getRoot(&res); - if(!FSRoot) - return res; + if (!FSRoot) return res; - try - { - shared_ptr fnode = - FSRoot->openNode( path, "open", file->flags, &res ); + try { + shared_ptr fnode = + FSRoot->openNode(path, "open", file->flags, &res); - if(fnode) - { - VLOG(1) << "encfs_open for " << fnode->cipherName() - << ", flags " << file->flags; + if (fnode) { + VLOG(1) << "encfs_open for " << fnode->cipherName() << ", flags " + << file->flags; - if( res >= 0 ) - { + if (res >= 0) { file->fh = (uintptr_t)ctx->putNode(path, fnode); res = ESUCCESS; } } - } catch( Error &err ) - { + } + catch (Error &err) { LOG(ERROR) << "error caught in open: " << err.what(); } return res; } -int _do_flush(FileNode *fnode, int ) -{ +int _do_flush(FileNode *fnode, int) { /* Flush can be called multiple times for an open file, so it doesn't close the file. However it is important to call close() for some underlying filesystems (like NFS). */ - int res = fnode->open( O_RDONLY ); - if(res >= 0) - { + int res = fnode->open(O_RDONLY); + if (res >= 0) { int fh = res; res = close(dup(fh)); - if(res == -1) - res = -errno; + if (res == -1) res = -errno; } return res; } -int encfs_flush(const char *path, struct fuse_file_info *fi) -{ - return withFileNode( "flush", path, fi, _do_flush, 0 ); +int encfs_flush(const char *path, struct fuse_file_info *fi) { + return withFileNode("flush", path, fi, _do_flush, 0); } /* @@ -620,83 +540,70 @@ Note: This is advisory -- it might benefit us to keep file nodes around for a bit after they are released just in case they are reopened soon. But that requires a cache layer. */ -int encfs_release(const char *path, struct fuse_file_info *finfo) -{ +int encfs_release(const char *path, struct fuse_file_info *finfo) { EncFS_Context *ctx = context(); - try - { - ctx->eraseNode( path, (void*)(uintptr_t)finfo->fh ); + try { + ctx->eraseNode(path, (void *)(uintptr_t)finfo->fh); return ESUCCESS; - } catch( Error &err ) - { + } + catch (Error &err) { LOG(ERROR) << "error caught in release: " << err.what(); return -EIO; } } -int _do_read(FileNode *fnode, tuple data) -{ - return fnode->read( get<2>(data), get<0>(data), get<1>(data)); +int _do_read(FileNode *fnode, tuple data) { + return fnode->read(get<2>(data), get<0>(data), get<1>(data)); } int encfs_read(const char *path, char *buf, size_t size, off_t offset, - struct fuse_file_info *file) -{ - return withFileNode( "read", path, file, _do_read, - make_tuple((unsigned char *)buf, size, offset)); + struct fuse_file_info *file) { + return withFileNode("read", path, file, _do_read, + make_tuple((unsigned char *)buf, size, offset)); } -int _do_fsync(FileNode *fnode, int dataSync) -{ - return fnode->sync( dataSync != 0 ); +int _do_fsync(FileNode *fnode, int dataSync) { + return fnode->sync(dataSync != 0); } -int encfs_fsync(const char *path, int dataSync, - struct fuse_file_info *file) -{ - return withFileNode( "fsync", path, file, _do_fsync, dataSync ); +int encfs_fsync(const char *path, int dataSync, struct fuse_file_info *file) { + return withFileNode("fsync", path, file, _do_fsync, dataSync); } -int _do_write(FileNode *fnode, tuple data) -{ +int _do_write(FileNode *fnode, tuple data) { size_t size = get<1>(data); - if(fnode->write( get<2>(data), (unsigned char *)get<0>(data), size )) + if (fnode->write(get<2>(data), (unsigned char *)get<0>(data), size)) return size; else return -EIO; } -int encfs_write(const char *path, const char *buf, size_t size, - off_t offset, struct fuse_file_info *file) -{ +int encfs_write(const char *path, const char *buf, size_t size, off_t offset, + struct fuse_file_info *file) { return withFileNode("write", path, file, _do_write, - make_tuple(buf, size, offset)); + make_tuple(buf, size, offset)); } // statfs works even if encfs is detached.. -int encfs_statfs(const char *path, struct statvfs *st) -{ +int encfs_statfs(const char *path, struct statvfs *st) { EncFS_Context *ctx = context(); int res = -EIO; - try - { - (void)path; // path should always be '/' for now.. - rAssert( st != NULL ); + try { + (void)path; // path should always be '/' for now.. + rAssert(st != NULL); string cyName = ctx->rootCipherDir; VLOG(1) << "doing statfs of " << cyName; - res = statvfs( cyName.c_str(), st ); - if(!res) - { + res = statvfs(cyName.c_str(), st); + if (!res) { // adjust maximum name length.. - st->f_namemax = 6 * (st->f_namemax - 2) / 8; // approx.. + st->f_namemax = 6 * (st->f_namemax - 2) / 8; // approx.. } - if(res == -1) - res = -errno; - } catch( Error &err ) - { + if (res == -1) res = -errno; + } + catch (Error &err) { LOG(ERROR) << "error caught in statfs: " << err.what(); } return res; @@ -706,102 +613,87 @@ int encfs_statfs(const char *path, struct statvfs *st) #ifdef XATTR_ADD_OPT -int _do_setxattr(EncFS_Context *, const string &cyName, - tuple data) -{ +int _do_setxattr(EncFS_Context *, const string &cyName, + tuple data) { int options = XATTR_NOFOLLOW; - return ::setxattr( cyName.c_str(), get<0>(data), get<1>(data), - get<2>(data), get<3>(data), options ); + return ::setxattr(cyName.c_str(), get<0>(data), get<1>(data), get<2>(data), + get<3>(data), options); } -int encfs_setxattr( const char *path, const char *name, - const char *value, size_t size, int flags, uint32_t position ) -{ +int encfs_setxattr(const char *path, const char *name, const char *value, + size_t size, int flags, uint32_t position) { (void)flags; - return withCipherPath( "setxattr", path, _do_setxattr, - make_tuple(name, value, size, position) ); + return withCipherPath("setxattr", path, _do_setxattr, + make_tuple(name, value, size, position)); } #else -int _do_setxattr(EncFS_Context *, const string &cyName, - tuple data) -{ - return ::setxattr( cyName.c_str(), get<0>(data), get<1>(data), - get<2>(data), get<3>(data) ); +int _do_setxattr(EncFS_Context *, const string &cyName, + tuple data) { + return ::setxattr(cyName.c_str(), get<0>(data), get<1>(data), get<2>(data), + get<3>(data)); } -int encfs_setxattr( const char *path, const char *name, - const char *value, size_t size, int flags ) -{ - return withCipherPath( "setxattr", path, _do_setxattr, - make_tuple(name, value, size, flags) ); +int encfs_setxattr(const char *path, const char *name, const char *value, + size_t size, int flags) { + return withCipherPath("setxattr", path, _do_setxattr, + make_tuple(name, value, size, flags)); } #endif #ifdef XATTR_ADD_OPT int _do_getxattr(EncFS_Context *, const string &cyName, - tuple data) -{ + tuple data) { int options = 0; - return ::getxattr( cyName.c_str(), get<0>(data), - get<1>(data), get<2>(data), get<3>(data), options ); + return ::getxattr(cyName.c_str(), get<0>(data), get<1>(data), get<2>(data), + get<3>(data), options); } -int encfs_getxattr( const char *path, const char *name, - char *value, size_t size, uint32_t position ) -{ - return withCipherPath( "getxattr", path, _do_getxattr, - make_tuple(name, (void *)value, size, position), true ); +int encfs_getxattr(const char *path, const char *name, char *value, size_t size, + uint32_t position) { + return withCipherPath("getxattr", path, _do_getxattr, + make_tuple(name, (void *)value, size, position), true); } #else int _do_getxattr(EncFS_Context *, const string &cyName, - tuple data) -{ - return ::getxattr( cyName.c_str(), get<0>(data), - get<1>(data), get<2>(data)); + tuple data) { + return ::getxattr(cyName.c_str(), get<0>(data), get<1>(data), get<2>(data)); } -int encfs_getxattr( const char *path, const char *name, - char *value, size_t size ) -{ - return withCipherPath( "getxattr", path, _do_getxattr, - make_tuple(name, (void *)value, size), true ); +int encfs_getxattr(const char *path, const char *name, char *value, + size_t size) { + return withCipherPath("getxattr", path, _do_getxattr, + make_tuple(name, (void *)value, size), true); } #endif int _do_listxattr(EncFS_Context *, const string &cyName, - tuple data) -{ + tuple data) { #ifdef XATTR_ADD_OPT int options = 0; - int res = ::listxattr( cyName.c_str(), get<0>(data), get<1>(data), - options ); + int res = ::listxattr(cyName.c_str(), get<0>(data), get<1>(data), options); #else - int res = ::listxattr( cyName.c_str(), get<0>(data), get<1>(data) ); + int res = ::listxattr(cyName.c_str(), get<0>(data), get<1>(data)); #endif return (res == -1) ? -errno : res; } -int encfs_listxattr( const char *path, char *list, size_t size ) -{ - return withCipherPath( "listxattr", path, _do_listxattr, - make_tuple(list, size), true ); +int encfs_listxattr(const char *path, char *list, size_t size) { + return withCipherPath("listxattr", path, _do_listxattr, + make_tuple(list, size), true); } -int _do_removexattr(EncFS_Context *, const string &cyName, const char *name) -{ +int _do_removexattr(EncFS_Context *, const string &cyName, const char *name) { #ifdef XATTR_ADD_OPT int options = 0; - int res = ::removexattr( cyName.c_str(), name, options ); + int res = ::removexattr(cyName.c_str(), name, options); #else - int res = ::removexattr( cyName.c_str(), name ); + int res = ::removexattr(cyName.c_str(), name); #endif return (res == -1) ? -errno : res; } -int encfs_removexattr( const char *path, const char *name ) -{ - return withCipherPath( "removexattr", path, _do_removexattr, name ); +int encfs_removexattr(const char *path, const char *name) { + return withCipherPath("removexattr", path, _do_removexattr, name); } } // namespace encfs -#endif // HAVE_XATTR - +#endif // HAVE_XATTR diff --git a/fs/encfs.h b/fs/encfs.h index d380185..bd3d183 100644 --- a/fs/encfs.h +++ b/fs/encfs.h @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -32,36 +32,32 @@ #ifndef linux #include -static __inline int setfsuid(uid_t uid) -{ - uid_t olduid = geteuid(); +static __inline int setfsuid(uid_t uid) { + uid_t olduid = geteuid(); - seteuid(uid); + seteuid(uid); - if (errno != EINVAL) - errno = 0; + if (errno != EINVAL) errno = 0; - return olduid; + return olduid; } -static __inline int setfsgid(gid_t gid) -{ - gid_t oldgid = getegid(); +static __inline int setfsgid(gid_t gid) { + gid_t oldgid = getegid(); - setegid(gid); + setegid(gid); - if (errno != EINVAL) - errno = 0; + if (errno != EINVAL) errno = 0; - return oldgid; + return oldgid; } #endif namespace encfs { int encfs_getattr(const char *path, struct stat *stbuf); -int encfs_fgetattr(const char *path, struct stat *stbuf, - struct fuse_file_info *fi); +int encfs_fgetattr(const char *path, struct stat *stbuf, + struct fuse_file_info *fi); int encfs_readlink(const char *path, char *buf, size_t size); int encfs_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler); int encfs_mknod(const char *path, mode_t mode, dev_t rdev); @@ -74,40 +70,38 @@ int encfs_link(const char *from, const char *to); int encfs_chmod(const char *path, mode_t mode); int encfs_chown(const char *path, uid_t uid, gid_t gid); int encfs_truncate(const char *path, off_t size); -int encfs_ftruncate(const char *path, off_t size, - struct fuse_file_info *fi); +int encfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi); int encfs_utime(const char *path, struct utimbuf *buf); int encfs_open(const char *path, struct fuse_file_info *info); int encfs_release(const char *path, struct fuse_file_info *info); int encfs_read(const char *path, char *buf, size_t size, off_t offset, - struct fuse_file_info *info); + struct fuse_file_info *info); int encfs_write(const char *path, const char *buf, size_t size, off_t offset, - struct fuse_file_info *info); + struct fuse_file_info *info); int encfs_statfs(const char *, struct statvfs *fst); int encfs_flush(const char *, struct fuse_file_info *info); int encfs_fsync(const char *path, int flags, struct fuse_file_info *info); #ifdef HAVE_XATTR -# ifdef XATTR_ADD_OPT -int encfs_setxattr( const char *path, const char *name, const char *value, - size_t size, int flags, uint32_t position); -int encfs_getxattr( const char *path, const char *name, char *value, - size_t size, uint32_t position ); -# else -int encfs_setxattr( const char *path, const char *name, const char *value, - size_t size, int flags); -int encfs_getxattr( const char *path, const char *name, char *value, - size_t size ); -# endif - -int encfs_listxattr( const char *path, char *list, size_t size ); -int encfs_removexattr( const char *path, const char *name ); +#ifdef XATTR_ADD_OPT +int encfs_setxattr(const char *path, const char *name, const char *value, + size_t size, int flags, uint32_t position); +int encfs_getxattr(const char *path, const char *name, char *value, size_t size, + uint32_t position); +#else +int encfs_setxattr(const char *path, const char *name, const char *value, + size_t size, int flags); +int encfs_getxattr(const char *path, const char *name, char *value, + size_t size); #endif -int encfs_utimens( const char *path, const struct timespec ts[2] ); +int encfs_listxattr(const char *path, char *list, size_t size); +int encfs_removexattr(const char *path, const char *name); +#endif + +int encfs_utimens(const char *path, const struct timespec ts[2]); } // namespace encfs #endif - diff --git a/fs/test_BlockIO.cpp b/fs/test_BlockIO.cpp index 6b43be7..d79c32f 100644 --- a/fs/test_BlockIO.cpp +++ b/fs/test_BlockIO.cpp @@ -7,7 +7,7 @@ * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS @@ -39,7 +39,7 @@ TEST(BlockFileIOTest, BasicIO) { MemFileIO base(1024); ASSERT_EQ(1024, base.getSize()); - FSConfigPtr cfg = makeConfig( CipherV1::New("Null"), 512); + FSConfigPtr cfg = makeConfig(CipherV1::New("Null"), 512); MemBlockFileIO block(512, cfg); block.truncate(1024); ASSERT_EQ(1024, block.getSize()); @@ -56,7 +56,7 @@ TEST(BlockFileIOTest, BasicIO) { req.offset = i * 256; memset(req.data, 0, req.dataLen); ASSERT_TRUE(base.write(req)); - + req.offset = i * 256; memset(req.data, 0, req.dataLen); ASSERT_TRUE(block.write(req)); @@ -66,4 +66,3 @@ TEST(BlockFileIOTest, BasicIO) { } } // namespace encfs - diff --git a/fs/test_IO.cpp b/fs/test_IO.cpp index 9e4bfd6..63852ed 100644 --- a/fs/test_IO.cpp +++ b/fs/test_IO.cpp @@ -8,7 +8,7 @@ * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS @@ -68,13 +68,9 @@ void testMacIO(FSConfigPtr& cfg) { comparisonTest(cfg, test.get(), dup.get()); } -TEST(IOTest, NullMacIO) { - runWithCipher("Null", 512, testMacIO); -} +TEST(IOTest, NullMacIO) { runWithCipher("Null", 512, testMacIO); } -TEST(IOTest, MacIO) { - runWithAllCiphers(testMacIO); -} +TEST(IOTest, MacIO) { runWithAllCiphers(testMacIO); } void testBasicCipherIO(FSConfigPtr& cfg) { shared_ptr base(new MemFileIO(0)); @@ -97,16 +93,13 @@ void testBasicCipherIO(FSConfigPtr& cfg) { for (unsigned int i = 0; i < sizeof(buf); ++i) { bool match = (buf[i] == req.data[i]); ASSERT_TRUE(match) << "mismatched data at offset " << i; - if (!match) - break; + if (!match) break; } delete[] req.data; } -TEST(IOTest, BasicCipherFileIO) { - runWithAllCiphers(testBasicCipherIO); -} +TEST(IOTest, BasicCipherFileIO) { runWithAllCiphers(testBasicCipherIO); } void testCipherIO(FSConfigPtr& cfg) { shared_ptr base(new MemFileIO(0)); @@ -116,13 +109,8 @@ void testCipherIO(FSConfigPtr& cfg) { comparisonTest(cfg, test.get(), dup.get()); } -TEST(IOTest, NullCipherFileIO) { - runWithCipher("Null", 512, testCipherIO); -} +TEST(IOTest, NullCipherFileIO) { runWithCipher("Null", 512, testCipherIO); } -TEST(IOTest, CipherFileIO) { - runWithAllCiphers(testCipherIO); -} +TEST(IOTest, CipherFileIO) { runWithAllCiphers(testCipherIO); } } // namespace - diff --git a/fs/testing.cpp b/fs/testing.cpp index 960843b..a5a0aef 100644 --- a/fs/testing.cpp +++ b/fs/testing.cpp @@ -8,7 +8,7 @@ * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS @@ -19,7 +19,6 @@ * along with this program. If not, see . */ - #include "fs/testing.h" #include @@ -68,8 +67,9 @@ void runWithAllCiphers(void (*func)(FSConfigPtr& config)) { for (it = algorithms.begin(); it != algorithms.end(); ++it) { int blockSize = it->blockSize.closest(512); int keyLength = it->keyLength.closest(128); - SCOPED_TRACE(testing::Message() << "Testng with cipher " << it->name - << ", blocksize " << blockSize << ", keyLength " << keyLength); + SCOPED_TRACE(testing::Message() << "Testng with cipher " << it->name + << ", blocksize " << blockSize + << ", keyLength " << keyLength); shared_ptr cipher = CipherV1::New(it->iface, keyLength); ASSERT_TRUE(cipher.get() != NULL); @@ -80,7 +80,7 @@ void runWithAllCiphers(void (*func)(FSConfigPtr& config)) { void truncate(FileIO* a, FileIO* b, int len) { SCOPED_TRACE(testing::Message() << "Truncate from " << a->getSize() - << " to len " << len); + << " to len " << len); a->truncate(len); ASSERT_EQ(len, a->getSize()); @@ -100,8 +100,8 @@ void writeRandom(FSConfigPtr& cfg, FileIO* a, FileIO* b, int offset, int len) { if (b->getSize() < offset + len) { b->truncate(offset + len); } - - unsigned char *buf = new unsigned char[len]; + + unsigned char* buf = new unsigned char[len]; ASSERT_TRUE(cfg->cipher->pseudoRandomize(buf, len)); IORequest req; @@ -117,7 +117,7 @@ void writeRandom(FSConfigPtr& cfg, FileIO* a, FileIO* b, int offset, int len) { req.dataLen = len; ASSERT_EQ(len, a->read(req)); ASSERT_TRUE(memcmp(req.data, buf, len) == 0); - + memcpy(req.data, buf, len); req.offset = offset; req.dataLen = len; @@ -137,9 +137,9 @@ void writeRandom(FSConfigPtr& cfg, FileIO* a, FileIO* b, int offset, int len) { void compare(FileIO* a, FileIO* b, int offset, int len) { SCOPED_TRACE(testing::Message() << "compare " << offset << ", " << len - << " from file length " << a->getSize()); - unsigned char *buf1 = new unsigned char[len]; - unsigned char *buf2 = new unsigned char[len]; + << " from file length " << a->getSize()); + unsigned char* buf1 = new unsigned char[len]; + unsigned char* buf2 = new unsigned char[len]; memset(buf1, 0, len); memset(buf2, 0, len); @@ -155,12 +155,12 @@ void compare(FileIO* a, FileIO* b, int offset, int len) { ssize_t size2 = b->read(req); ASSERT_EQ(size1, size2); - for(int i = 0; i < len; i++) { + for (int i = 0; i < len; i++) { bool match = (buf1[i] == buf2[i]); ASSERT_TRUE(match) << "mismatched data at offset " << i << " of " << len - << ", got " << int(buf1[i]) << " and " << int(buf2[i]); - if(!match) { - break; + << ", got " << int(buf1[i]) << " and " << int(buf2[i]); + if (!match) { + break; } } @@ -169,15 +169,14 @@ void compare(FileIO* a, FileIO* b, int offset, int len) { } void comparisonTest(FSConfigPtr& cfg, FileIO* a, FileIO* b) { - const int size = 2*1024; + const int size = 2 * 1024; writeRandom(cfg, a, b, 0, size); if (testing::Test::HasFatalFailure()) return; for (int i = 0; i < 10000; i++) { SCOPED_TRACE(testing::Message() << "Test Loop " << i); int len = 128 + random() % 512; - int offset = (len == a->getSize()) ? 0 - : random() % (a->getSize() - len); + int offset = (len == a->getSize()) ? 0 : random() % (a->getSize() - len); writeRandom(cfg, a, b, offset, len); if (testing::Test::HasFatalFailure()) return; ASSERT_EQ(a->getSize(), b->getSize()); @@ -187,10 +186,9 @@ void comparisonTest(FSConfigPtr& cfg, FileIO* a, FileIO* b) { compare(a, b, 0, a->getSize()); } -int main(int argc, char **argv) { +int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } } // namespace encfs - diff --git a/fs/testing.h b/fs/testing.h index 04ec7c3..39f4ce4 100644 --- a/fs/testing.h +++ b/fs/testing.h @@ -24,4 +24,3 @@ void compare(FileIO* a, FileIO* b, int offset, int len); } // namespace encfs #endif - diff --git a/util/encfsctl.cpp b/util/encfsctl.cpp index 7e0d49f..92f6ff3 100644 --- a/util/encfsctl.cpp +++ b/util/encfsctl.cpp @@ -3,8 +3,8 @@ * ***************************************************************************** * Copyright (c) 2004, Valient Gough - * - * This program is free software; you can distribute it and/or modify it under + * + * This program is free software; you can distribute it and/or modify it under * the terms of the GNU General Public License (GPL), as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. @@ -15,7 +15,6 @@ * more details. */ - #include "fs/encfs.h" #include "base/autosprintf.h" @@ -54,112 +53,121 @@ using std::endl; using std::string; using std::vector; -static int showInfo( int argc, char **argv ); -static int showVersion( int argc, char **argv ); -static int showCiphers( int argc, char **argv ); -static int chpasswd( int argc, char **argv ); -static int chpasswdAutomaticly( int argc, char **argv ); -static int cmd_ls( int argc, char **argv ); -static int cmd_decode( int argc, char **argv ); -static int cmd_encode( int argc, char **argv ); -static int cmd_showcruft( int argc, char **argv ); -static int cmd_cat( int argc, char **argv ); -static int cmd_export( int argc, char **argv ); -static int cmd_showKey( int argc, char **argv ); +static int showInfo(int argc, char **argv); +static int showVersion(int argc, char **argv); +static int showCiphers(int argc, char **argv); +static int chpasswd(int argc, char **argv); +static int chpasswdAutomaticly(int argc, char **argv); +static int cmd_ls(int argc, char **argv); +static int cmd_decode(int argc, char **argv); +static int cmd_encode(int argc, char **argv); +static int cmd_showcruft(int argc, char **argv); +static int cmd_cat(int argc, char **argv); +static int cmd_export(int argc, char **argv); +static int cmd_showKey(int argc, char **argv); -struct CommandOpts -{ +struct CommandOpts { const char *name; int minOptions; int maxOptions; int (*func)(int argc, char **argv); const char *argStr; const char *usageStr; -} commands[] = -{ - {"info", 1, 1, showInfo, "(root dir)", - // xgroup(usage) - gettext_noop(" -- show information (Default command)")}, - {"showKey", 1, 1, cmd_showKey, "(root dir)", - // xgroup(usage) - gettext_noop(" -- show key")}, - {"passwd", 1, 1, chpasswd, "(root dir)", - // xgroup(usage) - gettext_noop(" -- change password for volume")}, - {"autopasswd", 1, 1, chpasswdAutomaticly, "(root dir)", - // xgroup(usage) - gettext_noop(" -- change password for volume, taking password" - " from standard input.\n\tNo prompts are issued.")}, - {"ls", 1, 2, cmd_ls, 0,0}, - {"showcruft", 1, 1, cmd_showcruft, "(root dir)", - // xgroup(usage) - gettext_noop(" -- show undecodable filenames in the volume")}, - {"cat", 2, 2, cmd_cat, "(root dir) path", - // xgroup(usage) - gettext_noop(" -- decodes the file and cats it to standard out")}, - {"decode", 1, 100, cmd_decode, "[--extpass=prog] (root dir) [encoded-name ...]", - // xgroup(usage) - gettext_noop(" -- decodes name and prints plaintext version")}, - {"encode", 1, 100, cmd_encode, "[--extpass=prog] (root dir) [plaintext-name ...]", - // xgroup(usage) - gettext_noop(" -- encodes a filename and print result")}, - {"export", 2, 2, cmd_export, "(root dir) path", - // xgroup(usage) - gettext_noop(" -- decrypts a volume and writes results to path")}, - {"ciphers", 0, 0, showCiphers, "", - // xgroup(usage) - gettext_noop(" -- show available ciphers")}, - {"version", 0, 0, showVersion, "", - // xgroup(usage) - gettext_noop(" -- print version number and exit")}, - {0,0,0,0,0,0} -}; +} commands[] = { + {"info", 1, 1, + showInfo, "(root dir)", + // xgroup(usage) + gettext_noop(" -- show information (Default command)")}, + {"showKey", 1, 1, cmd_showKey, "(root dir)", + // xgroup(usage) + gettext_noop(" -- show key")}, + {"passwd", 1, 1, + chpasswd, "(root dir)", + // xgroup(usage) + gettext_noop(" -- change password for volume")}, + {"autopasswd", 1, 1, chpasswdAutomaticly, "(root dir)", + // xgroup(usage) + gettext_noop( + " -- change password for volume, taking password" + " from standard input.\n\tNo prompts are issued.")}, + {"ls", 1, 2, cmd_ls, 0, 0}, + {"showcruft", + 1, + 1, + cmd_showcruft, + "(root dir)", + // xgroup(usage) + gettext_noop(" -- show undecodable filenames in the volume")}, + {"cat", + 2, + 2, + cmd_cat, + "(root dir) path", + // xgroup(usage) + gettext_noop(" -- decodes the file and cats it to standard out")}, + {"decode", + 1, + 100, + cmd_decode, + "[--extpass=prog] (root dir) [encoded-name ...]", + // xgroup(usage) + gettext_noop(" -- decodes name and prints plaintext version")}, + {"encode", 1, + 100, cmd_encode, + "[--extpass=prog] (root dir) [plaintext-name ...]", + // xgroup(usage) + gettext_noop(" -- encodes a filename and print result")}, + {"export", + 2, + 2, + cmd_export, + "(root dir) path", + // xgroup(usage) + gettext_noop(" -- decrypts a volume and writes results to path")}, + {"ciphers", 0, 0, showCiphers, "", + // xgroup(usage) + gettext_noop(" -- show available ciphers")}, + {"version", 0, 0, showVersion, "", + // xgroup(usage) + gettext_noop(" -- print version number and exit")}, + {0, 0, 0, 0, 0, 0}}; - -static -void usage(const char *name) -{ +static void usage(const char *name) { cerr << autosprintf(_("encfsctl version %s"), VERSION) << "\n" - << _("Usage:\n") - // displays usage commands, eg "./encfs (root dir) ..." - // xgroup(usage) - << autosprintf(_("%s (root dir)\n" - " -- displays information about the filesystem, or \n"), name); + << _("Usage:\n") + // displays usage commands, eg "./encfs (root dir) ..." + // xgroup(usage) + << autosprintf( + _("%s (root dir)\n" + " -- displays information about the filesystem, or \n"), + name); int offset = 0; - while(commands[offset].name != 0) - { - if( commands[offset].argStr != 0 ) - { - cerr << "encfsctl " << commands[offset].name << " " - << commands[offset].argStr << "\n" - << gettext( commands[offset].usageStr ) << "\n"; + while (commands[offset].name != 0) { + if (commands[offset].argStr != 0) { + cerr << "encfsctl " << commands[offset].name << " " + << commands[offset].argStr << "\n" + << gettext(commands[offset].usageStr) << "\n"; } ++offset; } cerr << "\n" - // xgroup(usage) - << autosprintf(_("Example: \n%s info ~/.crypt\n"), name) - << "\n"; + // xgroup(usage) + << autosprintf(_("Example: \n%s info ~/.crypt\n"), name) << "\n"; } -static bool checkDir( string &rootDir ) -{ - if( !isDirectory( rootDir.c_str() )) - { - cout << autosprintf(_("directory %s does not exist.\n"), - rootDir.c_str()); +static bool checkDir(string &rootDir) { + if (!isDirectory(rootDir.c_str())) { + cout << autosprintf(_("directory %s does not exist.\n"), rootDir.c_str()); return false; } - if(rootDir[ rootDir.length()-1 ] != '/') - rootDir.append("/"); + if (rootDir[rootDir.length() - 1] != '/') rootDir.append("/"); return true; } -static int showVersion( int argc, char **argv ) -{ +static int showVersion(int argc, char **argv) { (void)argc; (void)argv; // xgroup(usage) @@ -168,46 +176,45 @@ static int showVersion( int argc, char **argv ) return EXIT_SUCCESS; } -static int showCiphers( int argc, char **argv ) -{ +static int showCiphers(int argc, char **argv) { (void)argc; (void)argv; cout << _("Block modes:\n"); - for (const string& name : BlockCipher::GetRegistry().GetAll()) { + for (const string &name : BlockCipher::GetRegistry().GetAll()) { auto props = BlockCipher::GetRegistry().GetProperties(name.c_str()); cout << _("Implementation: ") << name << "\n"; cout << "\t" << _("Provider: ") << props->library << "\n"; - cout << "\t" << _("Block cipher: ") << props->cipher << " / " - << props->mode << "\n"; + cout << "\t" << _("Block cipher: ") << props->cipher << " / " << props->mode + << "\n"; cout << "\t" << _("Key Sizes: ") << props->keySize << "\n"; } cout << "\n"; cout << _("Stream modes:\n"); - for (const string& name : StreamCipher::GetRegistry().GetAll()) { + for (const string &name : StreamCipher::GetRegistry().GetAll()) { auto props = StreamCipher::GetRegistry().GetProperties(name.c_str()); cout << _("Implementation: ") << name << "\n"; cout << "\t" << _("Provider: ") << props->library << "\n"; cout << "\t" << _("Stream cipher: ") << props->cipher << " / " - << props->mode << "\n"; + << props->mode << "\n"; cout << "\t" << _("Key Sizes: ") << props->keySize << "\n"; } cout << "\n"; - + cout << _("MAC modes:\n"); - for (const string& name : MAC::GetRegistry().GetAll()) { + for (const string &name : MAC::GetRegistry().GetAll()) { auto props = MAC::GetRegistry().GetProperties(name.c_str()); cout << _("Implementation: ") << name << "\n"; cout << "\t" << _("Provider: ") << props->library << "\n"; cout << "\t" << _("Hash mode: ") << props->hashFunction << " / " - << props->mode << "\n"; + << props->mode << "\n"; cout << "\t" << _("Block size: ") << props->blockSize << "\n"; } cout << "\n"; cout << _("PBKDF modes:\n"); - for (const string& name : PBKDF::GetRegistry().GetAll()) { + for (const string &name : PBKDF::GetRegistry().GetAll()) { auto props = PBKDF::GetRegistry().GetProperties(name.c_str()); cout << _("Implementation: ") << name << "\n"; cout << "\t" << _("Provider: ") << props->library << "\n"; @@ -218,140 +225,123 @@ static int showCiphers( int argc, char **argv ) return EXIT_SUCCESS; } -static int showInfo( int argc, char **argv ) -{ +static int showInfo(int argc, char **argv) { (void)argc; string rootDir = argv[1]; - if( !checkDir( rootDir )) - return EXIT_FAILURE; + if (!checkDir(rootDir)) return EXIT_FAILURE; EncfsConfig config; - ConfigType type = readConfig( rootDir, config ); + ConfigType type = readConfig(rootDir, config); // show information stored in config.. - switch(type) - { - case Config_None: - // xgroup(diag) - cout << _("Unable to load or parse config file\n"); - return EXIT_FAILURE; - case Config_Prehistoric: - // xgroup(diag) - cout << _("A really old EncFS filesystem was found. \n" - "It is not supported in this EncFS build.\n"); - return EXIT_FAILURE; - case Config_V3: - // xgroup(diag) - cout << "\n" << autosprintf(_("Version 3 configuration; " - "created by %s\n"), config.creator().c_str()); - break; - case Config_V4: - // xgroup(diag) - cout << "\n" << autosprintf(_("Version 4 configuration; " - "created by %s\n"), config.creator().c_str()); - break; - case Config_V5: - case Config_V6: - case Config_V7: - // xgroup(diag) - cout << "\n" << autosprintf(_("Version %i configuration; " - "created by %s (revision %i)\n"), - type, - config.creator().c_str(), - config.revision()); - break; + switch (type) { + case Config_None: + // xgroup(diag) + cout << _("Unable to load or parse config file\n"); + return EXIT_FAILURE; + case Config_Prehistoric: + // xgroup(diag) + cout << _("A really old EncFS filesystem was found. \n" + "It is not supported in this EncFS build.\n"); + return EXIT_FAILURE; + case Config_V3: + // xgroup(diag) + cout << "\n" << autosprintf(_("Version 3 configuration; " + "created by %s\n"), + config.creator().c_str()); + break; + case Config_V4: + // xgroup(diag) + cout << "\n" << autosprintf(_("Version 4 configuration; " + "created by %s\n"), + config.creator().c_str()); + break; + case Config_V5: + case Config_V6: + case Config_V7: + // xgroup(diag) + cout << "\n" + << autosprintf(_("Version %i configuration; " + "created by %s (revision %i)\n"), + type, config.creator().c_str(), config.revision()); + break; } - showFSInfo( config ); + showFSInfo(config); return EXIT_SUCCESS; } -static RootPtr initRootInfo(int &argc, char ** &argv) -{ +static RootPtr initRootInfo(int &argc, char **&argv) { RootPtr result; - shared_ptr opts( new EncFS_Opts() ); + shared_ptr opts(new EncFS_Opts()); opts->createIfNotFound = false; opts->checkKey = false; - static struct option long_options[] = { - {"extpass", 1, 0, 'p'}, - {0,0,0,0} - }; + static struct option long_options[] = {{"extpass", 1, 0, 'p'}, {0, 0, 0, 0}}; - for(;;) - { + for (;;) { int option_index = 0; - int res = getopt_long( argc, argv, "", - long_options, &option_index); - if(res == -1) - break; + int res = getopt_long(argc, argv, "", long_options, &option_index); + if (res == -1) break; - switch(res) - { - case 'p': - opts->passwordProgram.assign(optarg); - break; - default: - LOG(WARNING) << "getopt error: " << res; - break; + switch (res) { + case 'p': + opts->passwordProgram.assign(optarg); + break; + default: + LOG(WARNING) << "getopt error: " << res; + break; } } argc -= optind; argv += optind; - if(argc == 0) - { + if (argc == 0) { cerr << _("Incorrect number of arguments") << "\n"; - } else - { - opts->rootDir = string( argv[0] ); + } else { + opts->rootDir = string(argv[0]); --argc; ++argv; - if(checkDir( opts->rootDir )) - result = initFS( NULL, opts ); + if (checkDir(opts->rootDir)) result = initFS(NULL, opts); - if(!result) + if (!result) cerr << _("Unable to initialize encrypted filesystem - check path.\n"); } return result; } -static RootPtr initRootInfo(const char* crootDir) -{ +static RootPtr initRootInfo(const char *crootDir) { string rootDir(crootDir); RootPtr result; - if(checkDir( rootDir )) - { - shared_ptr opts( new EncFS_Opts() ); + if (checkDir(rootDir)) { + shared_ptr opts(new EncFS_Opts()); opts->rootDir = rootDir; opts->createIfNotFound = false; opts->checkKey = false; - result = initFS( NULL, opts ); + result = initFS(NULL, opts); } - if(!result) + if (!result) cerr << _("Unable to initialize encrypted filesystem - check path.\n"); return result; } -static int cmd_showKey( int argc, char **argv ) -{ +static int cmd_showKey(int argc, char **argv) { RootPtr rootInfo = initRootInfo(argv[1]); - if(!rootInfo) + if (!rootInfo) return EXIT_FAILURE; - else - { + else { // encode with itself - string b64Key = rootInfo->cipher->encodeAsString( rootInfo->volumeKey ); + string b64Key = rootInfo->cipher->encodeAsString(rootInfo->volumeKey); cout << b64Key << "\n"; @@ -359,86 +349,69 @@ static int cmd_showKey( int argc, char **argv ) } } -static int cmd_decode( int argc, char **argv ) -{ +static int cmd_decode(int argc, char **argv) { RootPtr rootInfo = initRootInfo(argc, argv); - if(!rootInfo) - return EXIT_FAILURE; + if (!rootInfo) return EXIT_FAILURE; - if(argc > 0) - { - for(int i=0; iroot->plainPath( argv[i] ); + if (argc > 0) { + for (int i = 0; i < argc; ++i) { + string name = rootInfo->root->plainPath(argv[i]); cout << name << "\n"; } - } else - { - char buf[PATH_MAX+1]; - while(cin.getline(buf,PATH_MAX)) - { - cout << rootInfo->root->plainPath( buf ) << "\n"; + } else { + char buf[PATH_MAX + 1]; + while (cin.getline(buf, PATH_MAX)) { + cout << rootInfo->root->plainPath(buf) << "\n"; } } return EXIT_SUCCESS; } -static int cmd_encode( int argc, char **argv ) -{ +static int cmd_encode(int argc, char **argv) { RootPtr rootInfo = initRootInfo(argc, argv); - if(!rootInfo) - return EXIT_FAILURE; + if (!rootInfo) return EXIT_FAILURE; - if(argc > 0) - { - for(int i=0; i 0) { + for (int i = 0; i < argc; ++i) { string name = rootInfo->root->cipherPathWithoutRoot(argv[i]); cout << name << "\n"; } - } else - { - char buf[PATH_MAX+1]; - while(cin.getline(buf,PATH_MAX)) - { - cout << rootInfo->root->cipherPathWithoutRoot( buf ) << "\n"; + } else { + char buf[PATH_MAX + 1]; + while (cin.getline(buf, PATH_MAX)) { + cout << rootInfo->root->cipherPathWithoutRoot(buf) << "\n"; } } return EXIT_SUCCESS; } -static int cmd_ls( int argc, char **argv ) -{ +static int cmd_ls(int argc, char **argv) { (void)argc; RootPtr rootInfo = initRootInfo(argv[1]); - if(!rootInfo) - return EXIT_FAILURE; + if (!rootInfo) return EXIT_FAILURE; // show files in directory { DirTraverse dt = rootInfo->root->openDir("/"); - if(dt.valid()) - { - for(string name = dt.nextPlaintextName(); !name.empty(); - name = dt.nextPlaintextName()) - { - shared_ptr fnode = - rootInfo->root->lookupNode( name.c_str(), "encfsctl-ls" ); + if (dt.valid()) { + for (string name = dt.nextPlaintextName(); !name.empty(); + name = dt.nextPlaintextName()) { + shared_ptr fnode = + rootInfo->root->lookupNode(name.c_str(), "encfsctl-ls"); struct stat stbuf; - fnode->getAttr( &stbuf ); + fnode->getAttr(&stbuf); struct tm stm; - localtime_r( &stbuf.st_mtime, &stm ); + localtime_r(&stbuf.st_mtime, &stm); stm.tm_year += 1900; // TODO: when I add "%s" to the end and name.c_str(), I get a // seg fault from within strlen. Why ??? - printf("%11i %4i-%02i-%02i %02i:%02i:%02i %s\n", - int(stbuf.st_size), - int(stm.tm_year), int(stm.tm_mon), int(stm.tm_mday), - int(stm.tm_hour), int(stm.tm_min), int(stm.tm_sec), - name.c_str()); + printf("%11i %4i-%02i-%02i %02i:%02i:%02i %s\n", int(stbuf.st_size), + int(stm.tm_year), int(stm.tm_mon), int(stm.tm_mday), + int(stm.tm_hour), int(stm.tm_min), int(stm.tm_sec), + name.c_str()); } } } @@ -447,83 +420,70 @@ static int cmd_ls( int argc, char **argv ) } // apply an operation to every block in the file -template -int processContents( const shared_ptr &rootInfo, - const char *path, T &op ) -{ +template +int processContents(const shared_ptr &rootInfo, const char *path, + T &op) { int errCode = 0; - shared_ptr node = rootInfo->root->openNode( path, "encfsctl", - O_RDONLY, &errCode ); + shared_ptr node = + rootInfo->root->openNode(path, "encfsctl", O_RDONLY, &errCode); - if(!node) - { + if (!node) { // try treating filename as an enciphered path - string plainName = rootInfo->root->plainPath( path ); - node = rootInfo->root->lookupNode( plainName.c_str(), "encfsctl" ); - if(node) - { - errCode = node->open( O_RDONLY ); - if(errCode < 0) - node.reset(); + string plainName = rootInfo->root->plainPath(path); + node = rootInfo->root->lookupNode(plainName.c_str(), "encfsctl"); + if (node) { + errCode = node->open(O_RDONLY); + if (errCode < 0) node.reset(); } } - if(!node) - { + if (!node) { cerr << "unable to open " << path << "\n"; return errCode; - } else - { + } else { unsigned char buf[512]; - int blocks = (node->getSize() + sizeof(buf)-1) / sizeof(buf); + int blocks = (node->getSize() + sizeof(buf) - 1) / sizeof(buf); // read all the data in blocks - for(int i=0; iread(i*sizeof(buf), buf, sizeof(buf)); + for (int i = 0; i < blocks; ++i) { + int bytes = node->read(i * sizeof(buf), buf, sizeof(buf)); int res = op(buf, bytes); - if(res < 0) - return res; + if (res < 0) return res; } } return 0; -} - -class WriteOutput -{ +} + +class WriteOutput { int _fd; -public: + + public: WriteOutput(int fd) { _fd = fd; } ~WriteOutput() { close(_fd); } - int operator()(const void *buf, int count) - { + int operator()(const void *buf, int count) { return (int)write(_fd, buf, count); } }; -static int cmd_cat( int argc, char **argv ) -{ +static int cmd_cat(int argc, char **argv) { (void)argc; RootPtr rootInfo = initRootInfo(argv[1]); - if(!rootInfo) - return EXIT_FAILURE; + if (!rootInfo) return EXIT_FAILURE; const char *path = argv[2]; WriteOutput output(STDOUT_FILENO); - int errCode = processContents( rootInfo, path, output ); + int errCode = processContents(rootInfo, path, output); return errCode; } -static int copyLink(const struct stat &stBuf, - const shared_ptr &rootInfo, - const string &cpath, const string &destName ) -{ - vector buf(stBuf.st_size+1, 0); - int res = ::readlink( cpath.c_str(), &buf[0], stBuf.st_size ); - if(res == -1) - { +static int copyLink(const struct stat &stBuf, + const shared_ptr &rootInfo, const string &cpath, + const string &destName) { + vector buf(stBuf.st_size + 1, 0); + int res = ::readlink(cpath.c_str(), &buf[0], stBuf.st_size); + if (res == -1) { cerr << "unable to readlink of " << cpath << "\n"; return EXIT_FAILURE; } @@ -531,160 +491,128 @@ static int copyLink(const struct stat &stBuf, buf[res] = '\0'; string decodedLink = rootInfo->root->plainPath(&buf[0]); - res = ::symlink( decodedLink.c_str(), destName.c_str() ); - if(res == -1) - { - cerr << "unable to create symlink for " << cpath - << " to " << decodedLink << "\n"; + res = ::symlink(decodedLink.c_str(), destName.c_str()); + if (res == -1) { + cerr << "unable to create symlink for " << cpath << " to " << decodedLink + << "\n"; } return EXIT_SUCCESS; } -static int copyContents(const shared_ptr &rootInfo, - const char* encfsName, const char* targetName) -{ - shared_ptr node = - rootInfo->root->lookupNode( encfsName, "encfsctl" ); +static int copyContents(const shared_ptr &rootInfo, + const char *encfsName, const char *targetName) { + shared_ptr node = rootInfo->root->lookupNode(encfsName, "encfsctl"); - if(!node) - { + if (!node) { cerr << "unable to open " << encfsName << "\n"; return EXIT_FAILURE; - } else - { + } else { struct stat st; - if(node->getAttr(&st) != 0) - return EXIT_FAILURE; + if (node->getAttr(&st) != 0) return EXIT_FAILURE; - if((st.st_mode & S_IFLNK) == S_IFLNK) - { + if ((st.st_mode & S_IFLNK) == S_IFLNK) { string d = rootInfo->root->cipherPath(encfsName); - char linkContents[PATH_MAX+2]; + char linkContents[PATH_MAX + 2]; - if(readlink (d.c_str(), linkContents, PATH_MAX + 1) <= 0) - { + if (readlink(d.c_str(), linkContents, PATH_MAX + 1) <= 0) { cerr << "unable to read link " << encfsName << "\n"; return EXIT_FAILURE; } - symlink(rootInfo->root->plainPath(linkContents).c_str(), - targetName); - } else - { + symlink(rootInfo->root->plainPath(linkContents).c_str(), targetName); + } else { int outfd = creat(targetName, st.st_mode); WriteOutput output(outfd); - processContents( rootInfo, encfsName, output ); + processContents(rootInfo, encfsName, output); } } return EXIT_SUCCESS; } -static bool endsWith(const string &str, char ch) -{ - if(str.empty()) +static bool endsWith(const string &str, char ch) { + if (str.empty()) return false; else - return str[str.length()-1] == ch; + return str[str.length() - 1] == ch; } -static int traverseDirs(const shared_ptr &rootInfo, - string volumeDir, string destDir) -{ - if(!endsWith(volumeDir, '/')) - volumeDir.append("/"); - if(!endsWith(destDir, '/')) - destDir.append("/"); +static int traverseDirs(const shared_ptr &rootInfo, + string volumeDir, string destDir) { + if (!endsWith(volumeDir, '/')) volumeDir.append("/"); + if (!endsWith(destDir, '/')) destDir.append("/"); // Lookup directory node so we can create a destination directory // with the same permissions { struct stat st; - shared_ptr dirNode = - rootInfo->root->lookupNode( volumeDir.c_str(), "encfsctl" ); - if(dirNode->getAttr(&st)) - return EXIT_FAILURE; + shared_ptr dirNode = + rootInfo->root->lookupNode(volumeDir.c_str(), "encfsctl"); + if (dirNode->getAttr(&st)) return EXIT_FAILURE; mkdir(destDir.c_str(), st.st_mode); } // show files in directory DirTraverse dt = rootInfo->root->openDir(volumeDir.c_str()); - if(dt.valid()) - { - for(string name = dt.nextPlaintextName(); !name.empty(); - name = dt.nextPlaintextName()) - { + if (dt.valid()) { + for (string name = dt.nextPlaintextName(); !name.empty(); + name = dt.nextPlaintextName()) { // Recurse to subdirectories - if(name != "." && name != "..") - { + if (name != "." && name != "..") { string plainPath = volumeDir + name; string cpath = rootInfo->root->cipherPath(plainPath.c_str()); string destName = destDir + name; int r = EXIT_SUCCESS; struct stat stBuf; - if( !lstat( cpath.c_str(), &stBuf )) - { - if( S_ISDIR( stBuf.st_mode ) ) - { - traverseDirs(rootInfo, (plainPath + '/').c_str(), - destName + '/'); - } else if( S_ISLNK( stBuf.st_mode )) - { - r = copyLink( stBuf, rootInfo, cpath, destName ); - } else - { - r = copyContents(rootInfo, plainPath.c_str(), - destName.c_str()); + if (!lstat(cpath.c_str(), &stBuf)) { + if (S_ISDIR(stBuf.st_mode)) { + traverseDirs(rootInfo, (plainPath + '/').c_str(), destName + '/'); + } else if (S_ISLNK(stBuf.st_mode)) { + r = copyLink(stBuf, rootInfo, cpath, destName); + } else { + r = copyContents(rootInfo, plainPath.c_str(), destName.c_str()); } - } else - { + } else { r = EXIT_FAILURE; } - if(r != EXIT_SUCCESS) - return r; + if (r != EXIT_SUCCESS) return r; } } } return EXIT_SUCCESS; } -static int cmd_export( int argc, char **argv ) -{ +static int cmd_export(int argc, char **argv) { (void)argc; RootPtr rootInfo = initRootInfo(argv[1]); - if(!rootInfo) - return EXIT_FAILURE; + if (!rootInfo) return EXIT_FAILURE; string destDir = argv[2]; // if the dir doesn't exist, then create it (with user permission) - if(!checkDir(destDir) && !userAllowMkdir(destDir.c_str(), 0700)) + if (!checkDir(destDir) && !userAllowMkdir(destDir.c_str(), 0700)) return EXIT_FAILURE; return traverseDirs(rootInfo, "/", destDir); } -int showcruft( const shared_ptr &rootInfo, const char *dirName ) -{ +int showcruft(const shared_ptr &rootInfo, const char *dirName) { int found = 0; - DirTraverse dt = rootInfo->root->openDir( dirName ); - if(dt.valid()) - { + DirTraverse dt = rootInfo->root->openDir(dirName); + if (dt.valid()) { bool showedDir = false; - for(string name = dt.nextInvalid(); !name.empty(); - name = dt.nextInvalid()) - { - string cpath = rootInfo->root->cipherPath( dirName ); + for (string name = dt.nextInvalid(); !name.empty(); + name = dt.nextInvalid()) { + string cpath = rootInfo->root->cipherPath(dirName); cpath += '/'; cpath += name; - if(!showedDir) - { + if (!showedDir) { // just before showing a list of files in a directory cout << autosprintf(_("In directory %s: \n"), dirName); showedDir = true; @@ -694,23 +622,20 @@ int showcruft( const shared_ptr &rootInfo, const char *dirName ) } // now go back and look for directories to recurse into.. - dt = rootInfo->root->openDir( dirName ); - if(dt.valid()) - { - for(string name = dt.nextPlaintextName(); !name.empty(); - name = dt.nextPlaintextName()) - { - if( name == "." || name == "..") - continue; + dt = rootInfo->root->openDir(dirName); + if (dt.valid()) { + for (string name = dt.nextPlaintextName(); !name.empty(); + name = dt.nextPlaintextName()) { + if (name == "." || name == "..") continue; string plainPath = dirName; plainPath += '/'; plainPath += name; - string cpath = rootInfo->root->cipherPath( plainPath.c_str() ); + string cpath = rootInfo->root->cipherPath(plainPath.c_str()); - if(isDirectory( cpath.c_str() )) - found += showcruft( rootInfo, plainPath.c_str() ); + if (isDirectory(cpath.c_str())) + found += showcruft(rootInfo, plainPath.c_str()); } } } @@ -722,63 +647,54 @@ int showcruft( const shared_ptr &rootInfo, const char *dirName ) iterate recursively through the filesystem and print out names of files which have filenames which cannot be decoded with the given key.. */ -static int cmd_showcruft( int argc, char **argv ) -{ +static int cmd_showcruft(int argc, char **argv) { (void)argc; RootPtr rootInfo = initRootInfo(argv[1]); - if(!rootInfo) - return EXIT_FAILURE; + if (!rootInfo) return EXIT_FAILURE; - int filesFound = showcruft( rootInfo, "/" ); + int filesFound = showcruft(rootInfo, "/"); cout << autosprintf("Found %i invalid file(s).", filesFound) << "\n"; return EXIT_SUCCESS; } -static int do_chpasswd( bool useStdin, bool annotate, int argc, char **argv ) -{ +static int do_chpasswd(bool useStdin, bool annotate, int argc, char **argv) { (void)argc; string rootDir = argv[1]; - if( !checkDir( rootDir )) - return EXIT_FAILURE; + if (!checkDir(rootDir)) return EXIT_FAILURE; EncfsConfig config; - ConfigType cfgType = readConfig( rootDir, config ); + ConfigType cfgType = readConfig(rootDir, config); - if(cfgType == Config_None) - { + if (cfgType == Config_None) { cout << _("Unable to load or parse config file\n"); return EXIT_FAILURE; } // ask for existing password cout << _("Enter current Encfs password\n"); - if (annotate) - cerr << "$PROMPT$ passwd" << endl; - CipherKey userKey = getUserKey( config, useStdin ); - if(!userKey.valid()) - return EXIT_FAILURE; + if (annotate) cerr << "$PROMPT$ passwd" << endl; + CipherKey userKey = getUserKey(config, useStdin); + if (!userKey.valid()) return EXIT_FAILURE; // instanciate proper cipher shared_ptr cipher = getCipher(config); - if(!cipher) - { + if (!cipher) { cout << autosprintf(_("Unable to find specified cipher \"%s\"\n"), - config.cipher().name().c_str()); + config.cipher().name().c_str()); return EXIT_FAILURE; } cipher->setKey(userKey); // decode volume key using user key -- at this point we detect an incorrect // password if the key checksum does not match (causing readKey to fail). - CipherKey volumeKey = cipher->readKey( - (const unsigned char *)config.key().ciphertext().data(), true ); + CipherKey volumeKey = cipher->readKey( + (const unsigned char *)config.key().ciphertext().data(), true); - if(!volumeKey.valid()) - { + if (!volumeKey.valid()) { cout << _("Invalid password\n"); return EXIT_FAILURE; } @@ -790,42 +706,36 @@ static int do_chpasswd( bool useStdin, bool annotate, int argc, char **argv ) cout << _("Enter new Encfs password\n"); // create new key - if( useStdin ) - { - if (annotate) - cerr << "$PROMPT$ new_passwd" << endl; + if (useStdin) { + if (annotate) cerr << "$PROMPT$ new_passwd" << endl; } - userKey = getNewUserKey( config, useStdin, string(), string() ); + userKey = getNewUserKey(config, useStdin, string(), string()); // re-encode the volume key using the new user key and write it out.. int result = EXIT_FAILURE; - if(userKey.valid()) - { + if (userKey.valid()) { int encodedKeySize = cipher->encodedKeySize(); - unsigned char *keyBuf = new unsigned char[ encodedKeySize ]; + unsigned char *keyBuf = new unsigned char[encodedKeySize]; // encode volume key with new user key cipher->setKey(userKey); - cipher->writeKey( volumeKey, keyBuf ); + cipher->writeKey(volumeKey, keyBuf); userKey.reset(); cipher->setKey(volumeKey); EncryptedKey *key = config.mutable_key(); - key->set_ciphertext( keyBuf, encodedKeySize ); + key->set_ciphertext(keyBuf, encodedKeySize); delete[] keyBuf; - if(saveConfig( rootDir, config )) - { + if (saveConfig(rootDir, config)) { // password modified -- changes volume key of filesystem.. cout << _("Volume Key successfully updated.\n"); result = EXIT_SUCCESS; - } else - { + } else { cout << _("Error saving modified config file.\n"); } - } else - { + } else { cout << _("Error creating key\n"); } @@ -834,19 +744,15 @@ static int do_chpasswd( bool useStdin, bool annotate, int argc, char **argv ) return result; } -static int chpasswd( int argc, char **argv ) -{ - return do_chpasswd( false, false, argc, argv ); +static int chpasswd(int argc, char **argv) { + return do_chpasswd(false, false, argc, argv); } -static int chpasswdAutomaticly( int argc, char **argv ) -{ - return do_chpasswd( true, false, argc, argv ); +static int chpasswdAutomaticly(int argc, char **argv) { + return do_chpasswd(true, false, argc, argv); } - -int main(int argc, char **argv) -{ +int main(int argc, char **argv) { FLAGS_logtostderr = 1; FLAGS_minloglevel = 1; @@ -858,42 +764,35 @@ int main(int argc, char **argv) google::InstallFailureSignalHandler(); #ifdef LOCALEDIR - setlocale( LC_ALL, "" ); - bindtextdomain( PACKAGE, LOCALEDIR ); - textdomain( PACKAGE ); + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); #endif bool isThreaded = false; CipherV1::init(isThreaded); - if(argc < 2) - { - usage( argv[0] ); + if (argc < 2) { + usage(argv[0]); return EXIT_FAILURE; } // find the specified command int offset = 0; - while(commands[offset].name != 0) - { - if(!strcmp( argv[1], commands[offset].name )) - break; + while (commands[offset].name != 0) { + if (!strcmp(argv[1], commands[offset].name)) break; ++offset; } - if(commands[offset].name == 0) - { + if (commands[offset].name == 0) { cerr << autosprintf(_("invalid command: \"%s\""), argv[1]) << "\n"; - } else - { - if((argc-2 < commands[offset].minOptions) || - (argc-2 > commands[offset].maxOptions)) - { - cerr << autosprintf( - _("Incorrect number of arguments for command \"%s\""), - argv[1]) << "\n"; + } else { + if ((argc - 2 < commands[offset].minOptions) || + (argc - 2 > commands[offset].maxOptions)) { + cerr << autosprintf(_("Incorrect number of arguments for command \"%s\""), + argv[1]) << "\n"; } else - return (*commands[offset].func)( argc-1, argv+1 ); + return (*commands[offset].func)(argc - 1, argv + 1); } CipherV1::shutdown(isThreaded); diff --git a/util/makeKey.cpp b/util/makeKey.cpp index fb93585..737511c 100644 --- a/util/makeKey.cpp +++ b/util/makeKey.cpp @@ -4,10 +4,10 @@ ***************************************************************************** * Copyright (c) 2008, Valient Gough * - * This program is free software: you can redistribute it and/or modify it + * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -29,36 +29,32 @@ #include #include -void genKey( const shared_ptr &cipher ) -{ - CipherKey key = cipher->newRandomKey(); +void genKey(const shared_ptr &cipher) { + CipherKey key = cipher->newRandomKey(); - // encode with itself - string b64Key = cipher->encodeAsString( key, key ); + // encode with itself + string b64Key = cipher->encodeAsString(key, key); - cout << b64Key << "\n"; + cout << b64Key << "\n"; } -int main(int argc, char **argv) -{ - pid_t pid = getpid(); - cerr << "pid = " << pid << "\n"; +int main(int argc, char **argv) { + pid_t pid = getpid(); + cerr << "pid = " << pid << "\n"; - if(argc != 3) - { - cerr << "usage: makeKey [AES|Blowfish] [128|160|192|224|256]\n"; - return 1; - } + if (argc != 3) { + cerr << "usage: makeKey [AES|Blowfish] [128|160|192|224|256]\n"; + return 1; + } - const char *type = argv[1]; - int size = atoi(argv[2]); + const char *type = argv[1]; + int size = atoi(argv[2]); - openssl_init(false); + openssl_init(false); - // get a list of the available algorithms - shared_ptr cipher = Cipher::New( type, size ); - genKey( cipher ); - - //openssl_shutdown(false); -} + // get a list of the available algorithms + shared_ptr cipher = Cipher::New(type, size); + genKey(cipher); + // openssl_shutdown(false); +} From 88f041a0b228bfd8cdbee3ff410addb60cf45766 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Sat, 19 Oct 2013 22:42:44 +0000 Subject: [PATCH 40/51] minor cleanup git-svn-id: http://encfs.googlecode.com/svn/trunk@122 db9cf616-1c43-0410-9cb8-a902689de0d6 --- fs/CipherFileIO.h | 1 - util/encfsctl.cpp | 48 ++++++++++++----------------------------------- 2 files changed, 12 insertions(+), 37 deletions(-) diff --git a/fs/CipherFileIO.h b/fs/CipherFileIO.h index f3f3bfa..bbeaf1f 100644 --- a/fs/CipherFileIO.h +++ b/fs/CipherFileIO.h @@ -80,7 +80,6 @@ class CipherFileIO : public BlockFileIO { int headerLen; bool perFileIV; - bool externalIVChaining; uint64_t externalIV; uint64_t fileIV; int lastFlags; diff --git a/util/encfsctl.cpp b/util/encfsctl.cpp index 92f6ff3..d2fef02 100644 --- a/util/encfsctl.cpp +++ b/util/encfsctl.cpp @@ -74,15 +74,13 @@ struct CommandOpts { const char *argStr; const char *usageStr; } commands[] = { - {"info", 1, 1, - showInfo, "(root dir)", + {"info", 1, 1, showInfo, "(root dir)", // xgroup(usage) - gettext_noop(" -- show information (Default command)")}, - {"showKey", 1, 1, cmd_showKey, "(root dir)", + gettext_noop(" -- show information")}, + {"showKey", 1, 1, cmd_showKey, "(root dir)", // xgroup(usage) gettext_noop(" -- show key")}, - {"passwd", 1, 1, - chpasswd, "(root dir)", + {"passwd", 1, 1, chpasswd, "(root dir)", // xgroup(usage) gettext_noop(" -- change password for volume")}, {"autopasswd", 1, 1, chpasswdAutomaticly, "(root dir)", @@ -91,56 +89,34 @@ struct CommandOpts { " -- change password for volume, taking password" " from standard input.\n\tNo prompts are issued.")}, {"ls", 1, 2, cmd_ls, 0, 0}, - {"showcruft", - 1, - 1, - cmd_showcruft, - "(root dir)", + {"showcruft", 1, 1, cmd_showcruft, "(root dir)", // xgroup(usage) gettext_noop(" -- show undecodable filenames in the volume")}, - {"cat", - 2, - 2, - cmd_cat, - "(root dir) path", + {"cat", 2, 2, cmd_cat, "(root dir) path", // xgroup(usage) gettext_noop(" -- decodes the file and cats it to standard out")}, - {"decode", - 1, - 100, - cmd_decode, + {"decode", 1, 100, cmd_decode, "[--extpass=prog] (root dir) [encoded-name ...]", // xgroup(usage) gettext_noop(" -- decodes name and prints plaintext version")}, - {"encode", 1, - 100, cmd_encode, + {"encode", 1, 100, cmd_encode, "[--extpass=prog] (root dir) [plaintext-name ...]", // xgroup(usage) gettext_noop(" -- encodes a filename and print result")}, - {"export", - 2, - 2, - cmd_export, - "(root dir) path", + {"export", 2, 2, cmd_export, "(root dir) path", // xgroup(usage) gettext_noop(" -- decrypts a volume and writes results to path")}, - {"ciphers", 0, 0, showCiphers, "", + {"ciphers", 0, 0, showCiphers, "", // xgroup(usage) gettext_noop(" -- show available ciphers")}, - {"version", 0, 0, showVersion, "", + {"version", 0, 0, showVersion, "", // xgroup(usage) gettext_noop(" -- print version number and exit")}, {0, 0, 0, 0, 0, 0}}; static void usage(const char *name) { cerr << autosprintf(_("encfsctl version %s"), VERSION) << "\n" - << _("Usage:\n") - // displays usage commands, eg "./encfs (root dir) ..." - // xgroup(usage) - << autosprintf( - _("%s (root dir)\n" - " -- displays information about the filesystem, or \n"), - name); + << _("Usage:\n"); int offset = 0; while (commands[offset].name != 0) { From d1a9ccdd1950a6a764ba33ca5028b45a127f5e30 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Mon, 21 Oct 2013 05:38:27 +0000 Subject: [PATCH 41/51] rework NameIO interface to use string instead of C-strings, avoid leaking memory if error occurs git-svn-id: http://encfs.googlecode.com/svn/trunk@123 db9cf616-1c43-0410-9cb8-a902689de0d6 --- base/Interface.cpp | 7 +- base/Interface.h | 2 +- base/base64.cpp | 16 +- base/base64.h | 9 +- fs/{test_BlockIO.cpp => BlockFileIO_test.cpp} | 0 fs/BlockNameIO.cpp | 95 ++++++------ fs/BlockNameIO.h | 15 +- fs/CMakeLists.txt | 8 +- fs/DirNode.cpp | 16 +- fs/{test_IO.cpp => IO_test.cpp} | 0 fs/NameIO.cpp | 139 ++++++------------ fs/NameIO.h | 63 +++----- fs/NameIO_test.cpp | 59 ++++++++ fs/NullNameIO.cpp | 15 +- fs/NullNameIO.h | 14 +- fs/StreamNameIO.cpp | 96 ++++++------ fs/StreamNameIO.h | 14 +- fs/testing.cpp | 3 + 18 files changed, 265 insertions(+), 306 deletions(-) rename fs/{test_BlockIO.cpp => BlockFileIO_test.cpp} (100%) rename fs/{test_IO.cpp => IO_test.cpp} (100%) create mode 100644 fs/NameIO_test.cpp diff --git a/base/Interface.cpp b/base/Interface.cpp index f7229cd..f8b3eb6 100644 --- a/base/Interface.cpp +++ b/base/Interface.cpp @@ -27,7 +27,10 @@ namespace encfs { -std::ostream &operator<<(std::ostream &out, const Interface &iface) { +using std::string; +using std::ostream; + +ostream &operator<<(ostream &out, const Interface &iface) { out << iface.name() << "(" << iface.major() << ":" << iface.minor() << ":" << iface.age() << ")"; return out; @@ -42,7 +45,7 @@ bool implements(const Interface &A, const Interface &B) { return (currentDiff >= 0 && currentDiff <= (int)A.age()); } -Interface makeInterface(const char *name, int major, int minor, int age) { +Interface makeInterface(const string &name, int major, int minor, int age) { Interface iface; iface.set_name(name); iface.set_major(major); diff --git a/base/Interface.h b/base/Interface.h index d93b1d7..1970c0a 100644 --- a/base/Interface.h +++ b/base/Interface.h @@ -32,7 +32,7 @@ namespace encfs { // compatibility. Even if A.implements(B) is true, B > A may also be // true, meaning B is a newer revision of the interface then A. bool implements(const Interface &a, const Interface &b); -Interface makeInterface(const char *name, int major, int minor, int age); +Interface makeInterface(const std::string &name, int major, int minor, int age); // Read operation class ConfigVar; diff --git a/base/base64.cpp b/base/base64.cpp index 071a989..d5933bf 100644 --- a/base/base64.cpp +++ b/base/base64.cpp @@ -132,11 +132,9 @@ static const byte Ascii2B64Table[] = " 01 23456789:; "; // 0123456789 123456789 123456789 123456789 123456789 123456789 1234 // 0 1 2 3 4 5 6 -void AsciiToB64(byte *in, int length) { return AsciiToB64(in, in, length); } - -void AsciiToB64(byte *out, const byte *in, int length) { +void AsciiToB64(byte *buf, int length) { while (length--) { - byte ch = *in++; + byte ch = *buf; if (ch >= 'A') { if (ch >= 'a') ch += 38 - 'a'; @@ -145,7 +143,7 @@ void AsciiToB64(byte *out, const byte *in, int length) { } else ch = Ascii2B64Table[ch] - '0'; - *out++ = ch; + *buf++ = ch; } } @@ -161,18 +159,16 @@ void B32ToAscii(byte *buf, int len) { } } -void AsciiToB32(byte *in, int length) { return AsciiToB32(in, in, length); } - -void AsciiToB32(byte *out, const byte *in, int length) { +void AsciiToB32(byte *buf, int length) { while (length--) { - byte ch = *in++; + byte ch = *buf; int lch = toupper(ch); if (lch >= 'A') lch -= 'A'; else lch += 26 - '2'; - *out++ = (byte)lch; + *buf++ = (byte)lch; } } diff --git a/base/base64.h b/base/base64.h index 5977c29..36784ee 100644 --- a/base/base64.h +++ b/base/base64.h @@ -54,19 +54,22 @@ void changeBase2Inline(byte *buf, int srcLength, int srcPow2, int dst2Pow, bool outputPartialLastByte); // inplace translation from values [0,2^6] => base64 ASCII +// This is a nonstandard B64 encoding, which uses ',' and '-' as +// non-alphanumeric chars. void B64ToAscii(byte *buf, int length); // inplace translation from values [0,2^5] => base32 ASCII void B32ToAscii(byte *buf, int length); // inplace translation from values base64 ASCII => [0,2^6] +// This is a nonstandard B64 encoding, which uses ',' and '-' as +// non-alphanumeric chars. void AsciiToB64(byte *buf, int length); -void AsciiToB64(byte *out, const byte *in, int length); // inplace translation from values base32 ASCII => [0,2^5] void AsciiToB32(byte *buf, int length); -void AsciiToB32(byte *out, const byte *in, int length); -// Decode B64 standard into the output array. +// Decode standard B64 into the output array. +// Used only to decode legacy Boost XML serialized config format. // The output size must be at least B64ToB256Bytes(inputLen). bool B64StandardDecode(byte *out, const byte *in, int inputLen); diff --git a/fs/test_BlockIO.cpp b/fs/BlockFileIO_test.cpp similarity index 100% rename from fs/test_BlockIO.cpp rename to fs/BlockFileIO_test.cpp diff --git a/fs/BlockNameIO.cpp b/fs/BlockNameIO.cpp index 25248a3..1ad12f8 100644 --- a/fs/BlockNameIO.cpp +++ b/fs/BlockNameIO.cpp @@ -26,10 +26,15 @@ #include "cipher/CipherV1.h" #include +#include + #include namespace encfs { +using std::string; +using std::vector; + static shared_ptr NewBlockNameIO(const Interface &iface, const shared_ptr &cipher) { return shared_ptr(new BlockNameIO(iface, cipher, false)); @@ -67,13 +72,13 @@ static bool BlockIO32_registered = NameIO::Register( - Version 3.0 uses full 64 bit initialization vector during IV chaining. Prior versions used only the output from the MAC_16 call, giving a 1 in 2^16 chance of the same name being produced. Using the full 64 bit IV - changes that to a 1 in 2^64 chance.. + reduces to a 1 in 2^64 chance.. - - Version 4.0 adds support for base32, creating names more suitable for + - Version 4.0 adds support for base32, creating names better suited to case-insensitive filesystems (eg Mac). */ Interface BlockNameIO::CurrentInterface(bool caseSensitive) { - // implement major version 4 plus support for two prior versions + // implement major version 4 plus support for prior versions if (caseSensitive) return makeInterface("nameio/block32", 4, 0, 2); else @@ -113,16 +118,20 @@ int BlockNameIO::maxDecodedNameLen(int encodedNameLen) const { return decLen256 - 2; // 2 checksum bytes removed.. } -int BlockNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv, - char *encodedName) const { - // copy the data into the encoding buffer.. - memcpy(encodedName + 2, plaintextName, length); - +string BlockNameIO::encodeName(const string &plaintextName, + uint64_t *iv) const { + int length = plaintextName.length(); // Pad encryption buffer to block boundary.. int padding = _bs - length % _bs; - if (padding == 0) padding = _bs; // padding a full extra block! + int encodedStreamLen = length + 2 + padding; + int encLen = _caseSensitive ? B256ToB32Bytes(encodedStreamLen) + : B256ToB64Bytes(encodedStreamLen); - memset(encodedName + length + 2, (unsigned char)padding, padding); + vector tmpBuf(encLen); + + // copy the data into the encoding buffer.. + memcpy(tmpBuf.data() + 2, plaintextName.data(), length); + memset(tmpBuf.data() + length + 2, (unsigned char)padding, padding); // store the IV before it is modified by the MAC call. uint64_t tmpIV = 0; @@ -130,38 +139,29 @@ int BlockNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv, // include padding in MAC computation unsigned int mac = _cipher->reduceMac16( - _cipher->MAC_64((unsigned char *)encodedName + 2, length + padding, iv)); + _cipher->MAC_64(tmpBuf.data() + 2, length + padding, iv)); + tmpIV ^= (uint64_t)mac; // add checksum bytes - encodedName[0] = (mac >> 8) & 0xff; - encodedName[1] = (mac) & 0xff; + tmpBuf[0] = (mac >> 8) & 0xff; + tmpBuf[1] = (mac) & 0xff; - _cipher->blockEncode((unsigned char *)encodedName + 2, length + padding, - (uint64_t)mac ^ tmpIV); - - // convert to base 64 ascii - int encodedStreamLen = length + 2 + padding; - int encLen; + _cipher->blockEncode(tmpBuf.data() + 2, length + padding, tmpIV); + // convert to base 32 or 64 ascii if (_caseSensitive) { - encLen = B256ToB32Bytes(encodedStreamLen); - - changeBase2Inline((unsigned char *)encodedName, encodedStreamLen, 8, 5, - true); - B32ToAscii((unsigned char *)encodedName, encLen); + changeBase2Inline(tmpBuf.data(), encodedStreamLen, 8, 5, true); + B32ToAscii(tmpBuf.data(), encLen); } else { - encLen = B256ToB64Bytes(encodedStreamLen); - - changeBase2Inline((unsigned char *)encodedName, encodedStreamLen, 8, 6, - true); - B64ToAscii((unsigned char *)encodedName, encLen); + changeBase2Inline(tmpBuf.data(), encodedStreamLen, 8, 6, true); + B64ToAscii(tmpBuf.data(), encLen); } - return encLen; + return string(reinterpret_cast(tmpBuf.data()), encLen); } -int BlockNameIO::decodeName(const char *encodedName, int length, uint64_t *iv, - char *plaintextName) const { +string BlockNameIO::decodeName(const string &encodedName, uint64_t *iv) const { + int length = encodedName.length(); int decLen256 = _caseSensitive ? B32ToB256Bytes(length) : B64ToB256Bytes(length); int decodedStreamLen = decLen256 - 2; @@ -169,29 +169,30 @@ int BlockNameIO::decodeName(const char *encodedName, int length, uint64_t *iv, // don't bother trying to decode files which are too small if (decodedStreamLen < _bs) throw Error("Filename too small to decode"); - BUFFER_INIT(tmpBuf, 32, (unsigned int)length); + vector tmpBuf(length, 0); + memcpy(tmpBuf.data(), encodedName.data(), length); // decode into tmpBuf, if (_caseSensitive) { - AsciiToB32((unsigned char *)tmpBuf, (unsigned char *)encodedName, length); - changeBase2Inline((unsigned char *)tmpBuf, length, 5, 8, false); + AsciiToB32(tmpBuf.data(), length); + changeBase2Inline(tmpBuf.data(), length, 5, 8, false); } else { - AsciiToB64((unsigned char *)tmpBuf, (unsigned char *)encodedName, length); - changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false); + AsciiToB64(tmpBuf.data(), length); + changeBase2Inline(tmpBuf.data(), length, 6, 8, false); } // pull out the header information - unsigned int mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 | - ((unsigned int)((unsigned char)tmpBuf[1])); + unsigned int mac = ((unsigned int)tmpBuf[0]) << 8 | + ((unsigned int)tmpBuf[1]); uint64_t tmpIV = 0; if (iv && _interface >= 3) tmpIV = *iv; + tmpIV ^= (uint64_t)mac; - _cipher->blockDecode((unsigned char *)tmpBuf + 2, decodedStreamLen, - (uint64_t)mac ^ tmpIV); + _cipher->blockDecode(&tmpBuf.at(2), decodedStreamLen, tmpIV); // find out true string length - int padding = (unsigned char)tmpBuf[2 + decodedStreamLen - 1]; + int padding = tmpBuf[2 + decodedStreamLen - 1]; int finalSize = decodedStreamLen - padding; // might happen if there is an error decoding.. @@ -201,15 +202,9 @@ int BlockNameIO::decodeName(const char *encodedName, int length, uint64_t *iv, throw Error("invalid padding size"); } - // copy out the result.. - memcpy(plaintextName, tmpBuf + 2, finalSize); - plaintextName[finalSize] = '\0'; - // check the mac unsigned int mac2 = _cipher->reduceMac16( - _cipher->MAC_64((const unsigned char *)tmpBuf + 2, decodedStreamLen, iv)); - - BUFFER_RESET(tmpBuf); + _cipher->MAC_64(&tmpBuf.at(2), decodedStreamLen, iv)); if (mac2 != mac) { LOG(INFO) << "checksum mismatch: expected " << mac << ", got " << mac2 @@ -217,7 +212,7 @@ int BlockNameIO::decodeName(const char *encodedName, int length, uint64_t *iv, throw Error("checksum mismatch in filename decode"); } - return finalSize; + return string(reinterpret_cast(&tmpBuf.at(2)), finalSize); } bool BlockNameIO::Enabled() { return true; } diff --git a/fs/BlockNameIO.h b/fs/BlockNameIO.h index 9fb61d7..d8bb04d 100644 --- a/fs/BlockNameIO.h +++ b/fs/BlockNameIO.h @@ -24,6 +24,7 @@ #include "fs/NameIO.h" #include +#include namespace encfs { @@ -42,19 +43,19 @@ class BlockNameIO : public NameIO { bool caseSensitiveEncoding = false); virtual ~BlockNameIO(); - virtual Interface interface() const; + virtual Interface interface() const override; - virtual int maxEncodedNameLen(int plaintextNameLen) const; - virtual int maxDecodedNameLen(int encodedNameLen) const; + virtual int maxEncodedNameLen(int plaintextNameLen) const override; + virtual int maxDecodedNameLen(int encodedNameLen) const override; // hack to help with static builds static bool Enabled(); protected: - virtual int encodeName(const char *plaintextName, int length, uint64_t *iv, - char *encodedName) const; - virtual int decodeName(const char *encodedName, int length, uint64_t *iv, - char *plaintextName) const; + virtual std::string encodeName(const std::string &plaintextName, + uint64_t *iv) const override; + virtual std::string decodeName(const std::string &encodedName, + uint64_t *iv) const override; private: int _interface; diff --git a/fs/CMakeLists.txt b/fs/CMakeLists.txt index bb73eb4..7bdcc76 100644 --- a/fs/CMakeLists.txt +++ b/fs/CMakeLists.txt @@ -41,12 +41,14 @@ if (GTEST_FOUND) link_directories (${PROJECT_BINARY_DIR}/cipher) include_directories (${GTEST_INCLUDE_DIR}) + + file (GLOB TEST_FILES "*_test.cpp") + add_executable (fs-tests MemBlockFileIO.cpp MemFileIO.cpp testing.cpp - test_IO.cpp - test_BlockIO.cpp + ${TEST_FILES} ) target_link_libraries (fs-tests @@ -58,5 +60,5 @@ if (GTEST_FOUND) ) add_test (FSTests fs-tests) - GTEST_ADD_TESTS (fs-tests "${FSTestArgs}" test_IO.cpp test_BlockIO.cpp) + GTEST_ADD_TESTS (fs-tests "${FSTestArgs}" ${TEST_FILES}) endif (GTEST_FOUND) diff --git a/fs/DirNode.cpp b/fs/DirNode.cpp index 8b5ee16..57843aa 100644 --- a/fs/DirNode.cpp +++ b/fs/DirNode.cpp @@ -288,13 +288,7 @@ string DirNode::plainPath(const char *cipherPath_) { if (!strncmp(cipherPath_, rootDir.c_str(), rootDir.length())) { return naming->decodePath(cipherPath_ + rootDir.length()); } else { - if (cipherPath_[0] == '+') { - // decode as fully qualified path - return string("/") + - naming->decodeName(cipherPath_ + 1, strlen(cipherPath_ + 1)); - } else { - return naming->decodePath(cipherPath_); - } + return naming->decodePath(cipherPath_); } } catch (Error &err) { @@ -305,13 +299,7 @@ string DirNode::plainPath(const char *cipherPath_) { string DirNode::relativeCipherPath(const char *plaintextPath) { try { - if (plaintextPath[0] == '/') { - // mark with '+' to indicate special decoding.. - return string("+") + - naming->encodeName(plaintextPath + 1, strlen(plaintextPath + 1)); - } else { - return naming->encodePath(plaintextPath); - } + return naming->encodePath(plaintextPath); } catch (Error &err) { LOG(ERROR) << "encode err: " << err.what(); diff --git a/fs/test_IO.cpp b/fs/IO_test.cpp similarity index 100% rename from fs/test_IO.cpp rename to fs/IO_test.cpp diff --git a/fs/NameIO.cpp b/fs/NameIO.cpp index 4c2be73..b4c5605 100644 --- a/fs/NameIO.cpp +++ b/fs/NameIO.cpp @@ -24,27 +24,28 @@ #include -#include +#include #include +#include +#include // for static build. Need to reference the modules which are registered at // run-time, to ensure that the linker doesn't optimize them away. -#include #include "fs/BlockNameIO.h" #include "fs/StreamNameIO.h" #include "fs/NullNameIO.h" -using std::cerr; using std::list; using std::make_pair; using std::multimap; using std::string; +using std::vector; namespace encfs { -#define REF_MODULE(TYPE) \ - do { \ - if (!TYPE::Enabled()) cerr << "referenceModule: should never happen\n"; \ +#define REF_MODULE(TYPE) \ + do { \ + CHECK(TYPE::Enabled()) << "referenceModule: should never happen"; \ } while (0) static void AddSymbolReferences() { @@ -62,7 +63,7 @@ struct NameIOAlg { }; typedef multimap NameIOMap_t; -static NameIOMap_t *gNameIOMap = 0; +static NameIOMap_t *gNameIOMap = nullptr; list NameIO::GetAlgorithmList(bool includeHidden) { AddSymbolReferences(); @@ -145,136 +146,84 @@ void NameIO::setReverseEncryption(bool enable) { reverseEncryption = enable; } bool NameIO::getReverseEncryption() const { return reverseEncryption; } -std::string NameIO::recodePath(const char *path, - int (NameIO::*_length)(int) const, - int (NameIO::*_code)(const char *, int, - uint64_t *, char *) const, - uint64_t *iv) const { +string NameIO::recodePath(const string &path, int (NameIO::*_length)(int) const, + string (NameIO::*_code)(const string &, + uint64_t *) const, + uint64_t *iv) const { string output; - while (*path) { - if (*path == '/') { - if (!output.empty()) // don't start the string with '/' - output += '/'; - ++path; - } else { - bool isDotFile = (*path == '.'); - const char *next = strchr(path, '/'); - int len = next ? next - path : strlen(path); + for (auto it = path.begin(); it != path.end();) { + bool isDotFile = (*it == '.'); + auto next = std::find(it, path.end(), '/'); + int len = std::distance(it, next); - // at this point we know that len > 0 - if (isDotFile && (path[len - 1] == '.') && (len <= 2)) { + if (*it == '/') { + // don't start the string with '/' + output += output.empty() ? '+' : '/'; + len = 1; + } else if (*it == '+' && output.empty()) { + output += '/'; + len = 1; + } else if (isDotFile && (len <= 2) && (it[len - 1] == '.')) { output.append(len, '.'); // append [len] copies of '.' - path += len; - continue; - } - - // figure out buffer sizes + } else { int approxLen = (this->*_length)(len); if (approxLen <= 0) throw Error("Filename too small to decode"); - BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1); - // code the name - int codedLen = (this->*_code)(path, len, iv, codeBuf); - rAssert(codedLen <= approxLen); - rAssert(codeBuf[codedLen] == '\0'); - path += len; + string input(it, it + len); + string coded = (this->*_code)(input, iv); // append result to string - output += (char *)codeBuf; - - BUFFER_RESET(codeBuf); + output.append(coded); } + + it += len; } return output; } -std::string NameIO::encodePath(const char *plaintextPath) const { +string NameIO::encodePath(const string &plaintextPath) const { uint64_t iv = 0; return encodePath(plaintextPath, &iv); } -std::string NameIO::decodePath(const char *cipherPath) const { +string NameIO::decodePath(const string &cipherPath) const { uint64_t iv = 0; return decodePath(cipherPath, &iv); } -std::string NameIO::_encodePath(const char *plaintextPath, uint64_t *iv) const { +string NameIO::_encodePath(const string &plaintextPath, uint64_t *iv) const { // if chaining is not enabled, then the iv pointer is not used.. - if (!chainedNameIV) iv = 0; + if (!chainedNameIV) iv = nullptr; return recodePath(plaintextPath, &NameIO::maxEncodedNameLen, &NameIO::encodeName, iv); } -std::string NameIO::_decodePath(const char *cipherPath, uint64_t *iv) const { +string NameIO::_decodePath(const string &cipherPath, uint64_t *iv) const { // if chaining is not enabled, then the iv pointer is not used.. - if (!chainedNameIV) iv = 0; + if (!chainedNameIV) iv = nullptr; return recodePath(cipherPath, &NameIO::maxDecodedNameLen, &NameIO::decodeName, iv); } -std::string NameIO::encodePath(const char *path, uint64_t *iv) const { +string NameIO::encodePath(const string &path, uint64_t *iv) const { return getReverseEncryption() ? _decodePath(path, iv) : _encodePath(path, iv); } -std::string NameIO::decodePath(const char *path, uint64_t *iv) const { +string NameIO::decodePath(const string &path, uint64_t *iv) const { return getReverseEncryption() ? _encodePath(path, iv) : _decodePath(path, iv); } -int NameIO::encodeName(const char *input, int length, char *output) const { - return encodeName(input, length, (uint64_t *)0, output); +string NameIO::encodeName(const string &name) const { + return getReverseEncryption() ? decodeName(name, nullptr) + : encodeName(name, nullptr); } -int NameIO::decodeName(const char *input, int length, char *output) const { - return decodeName(input, length, (uint64_t *)0, output); -} - -std::string NameIO::_encodeName(const char *plaintextName, int length) const { - int approxLen = maxEncodedNameLen(length); - - BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1); - - // code the name - int codedLen = encodeName(plaintextName, length, 0, codeBuf); - rAssert(codedLen <= approxLen); - rAssert(codeBuf[codedLen] == '\0'); - - // append result to string - std::string result = (char *)codeBuf; - - BUFFER_RESET(codeBuf); - - return result; -} - -std::string NameIO::_decodeName(const char *encodedName, int length) const { - int approxLen = maxDecodedNameLen(length); - - BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1); - - // code the name - int codedLen = decodeName(encodedName, length, 0, codeBuf); - rAssert(codedLen <= approxLen); - rAssert(codeBuf[codedLen] == '\0'); - - // append result to string - std::string result = (char *)codeBuf; - - BUFFER_RESET(codeBuf); - - return result; -} - -std::string NameIO::encodeName(const char *path, int length) const { - return getReverseEncryption() ? _decodeName(path, length) - : _encodeName(path, length); -} - -std::string NameIO::decodeName(const char *path, int length) const { - return getReverseEncryption() ? _encodeName(path, length) - : _decodeName(path, length); +string NameIO::decodeName(const string &name) const { + return getReverseEncryption() ? encodeName(name, nullptr) + : decodeName(name, nullptr); } } // namespace encfs diff --git a/fs/NameIO.h b/fs/NameIO.h index 5f3e11c..ad20ad3 100644 --- a/fs/NameIO.h +++ b/fs/NameIO.h @@ -28,6 +28,7 @@ #include "base/Interface.h" #include "base/shared_ptr.h" +#include "base/types.h" namespace encfs { @@ -67,67 +68,39 @@ class NameIO { void setReverseEncryption(bool enable); bool getReverseEncryption() const; - std::string encodePath(const char *plaintextPath) const; - std::string decodePath(const char *encodedPath) const; + std::string encodePath(const std::string &plaintextPath) const; + std::string decodePath(const std::string &encodedPath) const; - std::string encodePath(const char *plaintextPath, uint64_t *iv) const; - std::string decodePath(const char *encodedPath, uint64_t *iv) const; + std::string encodePath(const std::string &plaintextPath, uint64_t *iv) const; + std::string decodePath(const std::string &encodedPath, uint64_t *iv) const; virtual int maxEncodedNameLen(int plaintextNameLen) const = 0; virtual int maxDecodedNameLen(int encodedNameLen) const = 0; - std::string encodeName(const char *plaintextName, int length) const; - std::string decodeName(const char *encodedName, int length) const; + std::string encodeName(const std::string &plaintextName) const; + std::string decodeName(const std::string &encodedName) const; protected: - virtual int encodeName(const char *plaintextName, int length, - char *encodedName) const; - virtual int decodeName(const char *encodedName, int length, - char *plaintextName) const; - - virtual int encodeName(const char *plaintextName, int length, uint64_t *iv, - char *encodedName) const = 0; - virtual int decodeName(const char *encodedName, int length, uint64_t *iv, - char *plaintextName) const = 0; + // Encode & decode methods implemented by derived classes. + virtual std::string encodeName(const std::string &name, + uint64_t *iv) const = 0; + virtual std::string decodeName(const std::string &name, + uint64_t *iv) const = 0; private: - std::string recodePath(const char *path, int (NameIO::*codingLen)(int) const, - int (NameIO::*codingFunc)(const char *, int, - uint64_t *, char *) const, + std::string recodePath(const std::string &path, + int (NameIO::*codingLen)(int) const, + std::string (NameIO::*codingFunc)(const std::string &, + uint64_t *) const, uint64_t *iv) const; - std::string _encodePath(const char *plaintextPath, uint64_t *iv) const; - std::string _decodePath(const char *encodedPath, uint64_t *iv) const; - std::string _encodeName(const char *plaintextName, int length) const; - std::string _decodeName(const char *encodedName, int length) const; + std::string _encodePath(const std::string &plaintextPath, uint64_t *iv) const; + std::string _decodePath(const std::string &encodedPath, uint64_t *iv) const; bool chainedNameIV; bool reverseEncryption; }; -/* - Helper macros for creating temporary buffers with an optimization that - below a given size (OptimizedSize) is allocated on the stack, and when a - larger size is requested it is allocated on the heap. - - BUFFER_RESET should be called for the same name as BUFFER_INIT - */ -#define BUFFER_INIT(Name, OptimizedSize, Size) \ - char Name##_Raw[OptimizedSize]; \ - char *Name = Name##_Raw; \ - if (sizeof(Name##_Raw) < Size) { \ - Name = new char[Size]; \ - } \ - memset(Name, 0, Size) - -#define BUFFER_RESET(Name) \ - do { \ - if (Name != Name##_Raw) { \ - delete[] Name; \ - Name = Name##_Raw; \ - } \ - } while (0) - } // namespace encfs #endif diff --git a/fs/NameIO_test.cpp b/fs/NameIO_test.cpp new file mode 100644 index 0000000..ae1a7ca --- /dev/null +++ b/fs/NameIO_test.cpp @@ -0,0 +1,59 @@ +#include +#include + +#include "cipher/CipherV1.h" + +#include "fs/BlockNameIO.h" +#include "fs/NameIO.h" +#include "fs/NullNameIO.h" +#include "fs/StreamNameIO.h" +#include "fs/testing.h" + +namespace { + +using namespace encfs; +using std::string; + +string TEST_PATHS[] = {"a/b/c/d/e", // + "/a/b", // + "/a", // + "/", // + "../../foo/bar", // + "./.encfs", // + "."}; + +TEST(NameIOTest, NameIO) { + NameIO::AlgorithmList algorithms = NameIO::GetAlgorithmList(true); + // Test all NameIO algorithms. + for (auto algorithm : algorithms) { + shared_ptr cipher = CipherV1::New("AES", 256); + CipherKey key = cipher->newRandomKey(); + cipher->setKey(key); + + // Test all supported versions. + for (unsigned int version = algorithm.iface.major() - algorithm.iface.age(); + version <= algorithm.iface.major(); ++version) { + Interface iface = makeInterface(algorithm.iface.name(), version, 0, 0); + SCOPED_TRACE(testing::Message() << "Testing " << iface.DebugString()); + + auto io = NameIO::New(iface, cipher); + + // Check round-trip of test paths. + for (string path : TEST_PATHS) { + string encoded = io->encodePath(path); + string decoded = io->decodePath(encoded); + ASSERT_EQ(path, decoded); + } + + // Try encoding names of various lengths. + for (int len = 1; len < 40; ++len) { + string name(len, 'A'); + string encoded = io->encodeName(name); + string decoded = io->decodeName(encoded); + ASSERT_EQ(name, decoded); + } + } + } +} + +} // namespace diff --git a/fs/NullNameIO.cpp b/fs/NullNameIO.cpp index 79cc9f1..b8b0100 100644 --- a/fs/NullNameIO.cpp +++ b/fs/NullNameIO.cpp @@ -23,9 +23,12 @@ #include "fs/NullNameIO.h" #include +#include namespace encfs { +using std::string; + static shared_ptr NewNNIO(const Interface &, const shared_ptr &) { return shared_ptr(new NullNameIO()); @@ -51,16 +54,12 @@ int NullNameIO::maxDecodedNameLen(int encodedNameLen) const { return encodedNameLen; } -int NullNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv, - char *encodedName) const { - memcpy(encodedName, plaintextName, length); - return length; +string NullNameIO::encodeName(const string &plaintextName, uint64_t *iv) const { + return plaintextName; } -int NullNameIO::decodeName(const char *encodedName, int length, uint64_t *iv, - char *plaintextName) const { - memcpy(plaintextName, encodedName, length); - return length; +string NullNameIO::decodeName(const string &encodedName, uint64_t *iv) const { + return encodedName; } bool NullNameIO::Enabled() { return true; } diff --git a/fs/NullNameIO.h b/fs/NullNameIO.h index acdbb12..e3e43aa 100644 --- a/fs/NullNameIO.h +++ b/fs/NullNameIO.h @@ -33,19 +33,19 @@ class NullNameIO : public NameIO { virtual ~NullNameIO(); - virtual Interface interface() const; + virtual Interface interface() const override; - virtual int maxEncodedNameLen(int plaintextNameLen) const; - virtual int maxDecodedNameLen(int encodedNameLen) const; + virtual int maxEncodedNameLen(int plaintextNameLen) const override; + virtual int maxDecodedNameLen(int encodedNameLen) const override; // hack to help with static builds static bool Enabled(); protected: - virtual int encodeName(const char *plaintextName, int length, uint64_t *iv, - char *encodedName) const; - virtual int decodeName(const char *encodedName, int length, uint64_t *iv, - char *plaintextName) const; + virtual std::string encodeName(const std::string &plaintextName, + uint64_t *iv) const override; + virtual std::string decodeName(const std::string &encodedName, + uint64_t *iv) const override; private: }; diff --git a/fs/StreamNameIO.cpp b/fs/StreamNameIO.cpp index f92acc6..3b6e708 100644 --- a/fs/StreamNameIO.cpp +++ b/fs/StreamNameIO.cpp @@ -27,9 +27,14 @@ #include #include +#include +#include namespace encfs { +using std::string; +using std::vector; + static shared_ptr NewStreamNameIO(const Interface &iface, const shared_ptr &cipher) { return shared_ptr(new StreamNameIO(iface, cipher)); @@ -60,10 +65,12 @@ static bool StreamIO_registered = NameIO::Register( bits. - Version 2.1 adds support for version 0 for EncFS 0.x compatibility. + + - Version 3.0 drops Encfs 0.x support. */ Interface StreamNameIO::CurrentInterface() { - // implement major version 2, 1, and 0 - return makeInterface("nameio/stream", 2, 1, 2); + // implements support for version 3, 2, and 1. + return makeInterface("nameio/stream", 3, 0, 2); } StreamNameIO::StreamNameIO(const Interface &iface, @@ -84,92 +91,73 @@ int StreamNameIO::maxDecodedNameLen(int encodedStreamLen) const { return decLen256 - 2; } -int StreamNameIO::encodeName(const char *plaintextName, int length, - uint64_t *iv, char *encodedName) const { +string StreamNameIO::encodeName(const string &plaintextName, + uint64_t *iv) const { uint64_t tmpIV = 0; + int length = plaintextName.length(); if (iv && _interface >= 2) tmpIV = *iv; - unsigned int mac = _cipher->reduceMac16( - _cipher->MAC_64((const byte *)plaintextName, length, iv)); + unsigned int mac = _cipher->reduceMac16(_cipher->MAC_64( + reinterpret_cast(plaintextName.data()), length, iv)); + tmpIV ^= (uint64_t)mac; - // add on checksum bytes - unsigned char *encodeBegin; - if (_interface >= 1) { - // current versions store the checksum at the beginning - encodedName[0] = (mac >> 8) & 0xff; - encodedName[1] = (mac) & 0xff; - encodeBegin = (unsigned char *)encodedName + 2; - } else { - // encfs 0.x stored checksums at the end. - encodedName[length] = (mac >> 8) & 0xff; - encodedName[length + 1] = (mac) & 0xff; - encodeBegin = (unsigned char *)encodedName; - } - - // stream encode the plaintext bytes - memcpy(encodeBegin, plaintextName, length); - _cipher->streamEncode(encodeBegin, length, (uint64_t)mac ^ tmpIV); - - // convert the entire thing to base 64 ascii.. int encodedStreamLen = length + 2; int encLen64 = B256ToB64Bytes(encodedStreamLen); - changeBase2Inline((unsigned char *)encodedName, encodedStreamLen, 8, 6, true); - B64ToAscii((unsigned char *)encodedName, encLen64); + // add on checksum bytes + vector encoded(encLen64); + encoded[0] = static_cast((mac >> 8) & 0xff); + encoded[1] = static_cast((mac) & 0xff); - return encLen64; + // stream encode the plaintext bytes + memcpy(&encoded[2], plaintextName.data(), length); + _cipher->streamEncode(&encoded[2], length, tmpIV); + + // convert the entire thing to base 64 ascii.. + changeBase2Inline(encoded.data(), encodedStreamLen, 8, 6, true); + B64ToAscii(encoded.data(), encLen64); + + return string(encoded.begin(), encoded.end()); } -int StreamNameIO::decodeName(const char *encodedName, int length, uint64_t *iv, - char *plaintextName) const { +string StreamNameIO::decodeName(const string &encodedName, + uint64_t *iv) const { + int length = encodedName.length(); rAssert(length > 2); int decLen256 = B64ToB256Bytes(length); int decodedStreamLen = decLen256 - 2; if (decodedStreamLen <= 0) throw Error("Filename too small to decode"); - BUFFER_INIT(tmpBuf, 32, (unsigned int)length); + vector tmpBuf(length, 0); // decode into tmpBuf, because this step produces more data then we can fit // into the result buffer.. - AsciiToB64((unsigned char *)tmpBuf, (unsigned char *)encodedName, length); - changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false); + memcpy(tmpBuf.data(), encodedName.data(), length); + AsciiToB64(tmpBuf.data(), length); + changeBase2Inline(tmpBuf.data(), length, 6, 8, false); // pull out the checksum value which is used as an initialization vector uint64_t tmpIV = 0; - unsigned int mac; - if (_interface >= 1) { - // current versions store the checksum at the beginning - mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 | - ((unsigned int)((unsigned char)tmpBuf[1])); + unsigned int mac = ((unsigned int)tmpBuf[0]) << 8 | ((unsigned int)tmpBuf[1]); - // version 2 adds support for IV chaining.. - if (iv && _interface >= 2) tmpIV = *iv; + // version 2 adds support for IV chaining.. + if (iv && _interface >= 2) tmpIV = *iv; - memcpy(plaintextName, tmpBuf + 2, decodedStreamLen); - } else { - // encfs 0.x stored checksums at the end. - mac = ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen])) << 8 | - ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen + 1])); - - memcpy(plaintextName, tmpBuf, decodedStreamLen); - } - - _cipher->streamDecode((unsigned char *)plaintextName, decodedStreamLen, - (uint64_t)mac ^ tmpIV); + tmpIV ^= (uint64_t)mac; + _cipher->streamDecode(&tmpBuf.at(2), decodedStreamLen, tmpIV); // compute MAC to check with stored value unsigned int mac2 = _cipher->reduceMac16( - _cipher->MAC_64((const byte *)plaintextName, decodedStreamLen, iv)); + _cipher->MAC_64(&tmpBuf.at(2), decodedStreamLen, iv)); - BUFFER_RESET(tmpBuf); if (mac2 != mac) { VLOG(1) << "checksum mismatch: expected " << mac << ", got " << mac2 << "on decode of " << decodedStreamLen << " bytes"; throw Error("checksum mismatch in filename decode"); } - return decodedStreamLen; + return string(reinterpret_cast(&tmpBuf.at(2)), decodedStreamLen); } bool StreamNameIO::Enabled() { return true; } diff --git a/fs/StreamNameIO.h b/fs/StreamNameIO.h index 923ee1c..ccc4bc7 100644 --- a/fs/StreamNameIO.h +++ b/fs/StreamNameIO.h @@ -34,19 +34,19 @@ class StreamNameIO : public NameIO { StreamNameIO(const Interface &iface, const shared_ptr &cipher); virtual ~StreamNameIO(); - virtual Interface interface() const; + virtual Interface interface() const override; - virtual int maxEncodedNameLen(int plaintextNameLen) const; - virtual int maxDecodedNameLen(int encodedNameLen) const; + virtual int maxEncodedNameLen(int plaintextNameLen) const override; + virtual int maxDecodedNameLen(int encodedNameLen) const override; // hack to help with static builds static bool Enabled(); protected: - virtual int encodeName(const char *plaintextName, int length, uint64_t *iv, - char *encodedName) const; - virtual int decodeName(const char *encodedName, int length, uint64_t *iv, - char *plaintextName) const; + virtual std::string encodeName(const std::string &plaintextName, + uint64_t *iv) const override; + virtual std::string decodeName(const std::string &encodedName, + uint64_t *iv) const override; private: int _interface; diff --git a/fs/testing.cpp b/fs/testing.cpp index a5a0aef..012d044 100644 --- a/fs/testing.cpp +++ b/fs/testing.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include "cipher/CipherV1.h" @@ -188,6 +189,8 @@ void comparisonTest(FSConfigPtr& cfg, FileIO* a, FileIO* b) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); + google::InitGoogleLogging(argv[0]); + return RUN_ALL_TESTS(); } From b606ef122b00f3056ad4c9740992fa6e0c0d1a99 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Mon, 21 Oct 2013 05:38:54 +0000 Subject: [PATCH 42/51] cleanup warnings from cppcheck git-svn-id: http://encfs.googlecode.com/svn/trunk@124 db9cf616-1c43-0410-9cb8-a902689de0d6 --- base/ConfigReader.cpp | 35 ----------------------------------- base/ConfigReader.h | 2 -- cipher/CipherKey.cpp | 3 ++- cipher/CipherKey.h | 2 +- cipher/CipherV1.cpp | 6 +++--- cipher/CipherV1.h | 4 ++-- cipher/botan.cpp | 2 +- cipher/openssl.cpp | 4 ++-- encfs/main.cpp | 25 ++++++++++++++++--------- fs/BlockFileIO.cpp | 2 +- fs/CipherFileIO.cpp | 2 +- fs/Context.cpp | 8 ++++---- fs/Context.h | 4 ++-- fs/DirNode.cpp | 4 ++-- fs/DirNode.h | 2 +- fs/FileNode.cpp | 2 +- fs/MemFileIO.cpp | 5 ----- fs/RawFileIO.cpp | 5 ----- fs/encfs.cpp | 2 +- 19 files changed, 40 insertions(+), 79 deletions(-) diff --git a/base/ConfigReader.cpp b/base/ConfigReader.cpp index 18378f4..8339071 100644 --- a/base/ConfigReader.cpp +++ b/base/ConfigReader.cpp @@ -92,41 +92,6 @@ bool ConfigReader::loadFromVar(ConfigVar &in) { return true; } -bool ConfigReader::save(const char *fileName) const { - // write everything to a ConfigVar, then output to disk - ConfigVar out = toVar(); - - int fd = ::open(fileName, O_RDWR | O_CREAT, 0640); - if (fd >= 0) { - int retVal = ::write(fd, out.buffer(), out.size()); - close(fd); - if (retVal != out.size()) { - LOG(ERROR) << "Error writing to config file " << fileName; - return false; - } - } else { - LOG(ERROR) << "Unable to open or create file " << fileName; - return false; - } - - return true; -} - -ConfigVar ConfigReader::toVar() const { - // write everything to a ConfigVar, then output to disk - ConfigVar out; - out.writeInt(vars.size()); - map::const_iterator it; - for (it = vars.begin(); it != vars.end(); ++it) { - out.writeInt(it->first.size()); - out.write((byte *)it->first.data(), it->first.size()); - out.writeInt(it->second.size()); - out.write((byte *)it->second.buffer(), it->second.size()); - } - - return out; -} - ConfigVar ConfigReader::operator[](const std::string &varName) const { // read only map::const_iterator it = vars.find(varName); diff --git a/base/ConfigReader.h b/base/ConfigReader.h index c53fe6d..4fa15d0 100644 --- a/base/ConfigReader.h +++ b/base/ConfigReader.h @@ -51,9 +51,7 @@ class ConfigReader { ~ConfigReader(); bool load(const char *fileName); - bool save(const char *fileName) const; - ConfigVar toVar() const; bool loadFromVar(ConfigVar &var); ConfigVar operator[](const std::string &varName) const; diff --git a/cipher/CipherKey.cpp b/cipher/CipherKey.cpp index c2e329f..1e95501 100644 --- a/cipher/CipherKey.cpp +++ b/cipher/CipherKey.cpp @@ -43,9 +43,10 @@ CipherKey::CipherKey(const CipherKey &src) CipherKey::~CipherKey() {} -void CipherKey::operator=(const CipherKey &src) { +CipherKey &CipherKey::operator=(const CipherKey &src) { _mem = src._mem; _valid = src._valid; + return *this; } byte *CipherKey::data() const { return !_mem ? NULL : _mem->data(); } diff --git a/cipher/CipherKey.h b/cipher/CipherKey.h index 9fc5e9e..835782f 100644 --- a/cipher/CipherKey.h +++ b/cipher/CipherKey.h @@ -38,7 +38,7 @@ class CipherKey { CipherKey(const CipherKey &src); ~CipherKey(); - void operator=(const CipherKey &src); + CipherKey &operator=(const CipherKey &src); byte *data() const; int size() const; diff --git a/cipher/CipherV1.cpp b/cipher/CipherV1.cpp index 82b74f1..54f2a54 100644 --- a/cipher/CipherV1.cpp +++ b/cipher/CipherV1.cpp @@ -231,7 +231,7 @@ shared_ptr CipherV1::New(const Interface &iface, int keyLen) { return result; } -CipherV1::CipherV1() {} +CipherV1::CipherV1() : _keySize(0), _ivLength(0), _keySet(false) {} bool CipherV1::initCiphers(const Interface &iface, const Interface &realIface, int keyLength) { @@ -471,7 +471,7 @@ CipherKey CipherV1::readKey(const byte *data, bool checkKey) { return key; } -void CipherV1::writeKey(const CipherKey &ckey, byte *out) { +void CipherV1::writeKey(const CipherKey &ckey, byte *out) const { rAssert(_keySet); SecureMem tmpBuf(ckey.size()); @@ -490,7 +490,7 @@ void CipherV1::writeKey(const CipherKey &ckey, byte *out) { memcpy(out + KEY_CHECKSUM_BYTES, tmpBuf.data(), tmpBuf.size()); } -std::string CipherV1::encodeAsString(const CipherKey &key) { +std::string CipherV1::encodeAsString(const CipherKey &key) const { rAssert(_keySet); int encodedSize = encodedKeySize(); vector buf(encodedSize); diff --git a/cipher/CipherV1.h b/cipher/CipherV1.h index 3a197d4..26b72a4 100644 --- a/cipher/CipherV1.h +++ b/cipher/CipherV1.h @@ -136,10 +136,10 @@ class CipherV1 { CipherKey readKey(const byte *data, bool checkKey); // Encrypt and write the given key. - void writeKey(const CipherKey &key, byte *data); + void writeKey(const CipherKey &key, byte *data) const; // Encrypt and store a key as a string. - std::string encodeAsString(const CipherKey &key); + std::string encodeAsString(const CipherKey &key) const; // meta-data about the cypher int keySize() const; diff --git a/cipher/botan.cpp b/cipher/botan.cpp index e074c67..5d6516e 100644 --- a/cipher/botan.cpp +++ b/cipher/botan.cpp @@ -121,7 +121,7 @@ class BotanBlockCipher : public BlockCipher { shared_ptr decryptor; public: - BotanBlockCipher() {} + BotanBlockCipher() : encryption(nullptr), decryption(nullptr) {} virtual ~BotanBlockCipher() {} bool rekey(const CipherKey& key, const string& cipherMode) { diff --git a/cipher/openssl.cpp b/cipher/openssl.cpp index 71f0ed6..8d94e4b 100644 --- a/cipher/openssl.cpp +++ b/cipher/openssl.cpp @@ -97,9 +97,9 @@ class OpenSSLCipher : public BlockCipher { static bool randomize(CipherKey *key) { int result = RAND_bytes(key->data(), key->size()); if (result != 1) { - char errStr[120]; // specs require string at least 120 bytes long.. unsigned long errVal = 0; if ((errVal = ERR_get_error()) != 0) + char errStr[120]; // specs require string at least 120 bytes long.. LOG(ERROR) << "openssl error: " << ERR_error_string(errVal, errStr); return false; @@ -118,9 +118,9 @@ class OpenSSLCipher : public BlockCipher { #endif int result = RAND_pseudo_bytes(out, length); if (result != 1) { - char errStr[120]; // specs require string at least 120 bytes long.. unsigned long errVal = 0; if ((errVal = ERR_get_error()) != 0) + char errStr[120]; // specs require string at least 120 bytes long.. LOG(ERROR) << "openssl error: " << ERR_error_string(errVal, errStr); return false; diff --git a/encfs/main.cpp b/encfs/main.cpp index 90c7783..ae8a84b 100644 --- a/encfs/main.cpp +++ b/encfs/main.cpp @@ -53,10 +53,6 @@ extern "C" void fuse_unmount_compat22(const char *mountpoint); #define fuse_unmount fuse_unmount_compat22 -#ifndef MAX -inline static int MAX(int a, int b) { return (a > b) ? a : b; } -#endif - using namespace encfs; using gnu::autosprintf; using std::cerr; @@ -84,7 +80,7 @@ struct EncFS_Args { // In case someone sends me a log dump, I want to know how what options are // in effect. Not internationalized, since it is something that is mostly // useful for me! - string toString() { + string toString() const { ostringstream ss; ss << (isDaemon ? "(daemon) " : "(fg) "); ss << (isThreaded ? "(threaded) " : "(UP) "); @@ -102,7 +98,17 @@ struct EncFS_Args { return ss.str(); } - EncFS_Args() : opts(new EncFS_Opts()) {} + EncFS_Args() + : isDaemon(false), + isThreaded(false), + isVerbose(false), + idleTimeout(0), + fuseArgc(0), + opts(new EncFS_Opts()) { + for (int i = 0; i < MaxFuseArgs; ++i) { + fuseArgv[i] = nullptr; + } + } }; static int oldStderr = STDERR_FILENO; @@ -420,7 +426,8 @@ static bool processArgs(int argc, char *argv[], static void *idleMonitor(void *); void *encfs_init(fuse_conn_info *conn) { - EncFS_Context *ctx = (EncFS_Context *)fuse_get_context()->private_data; + EncFS_Context *ctx = + static_cast(fuse_get_context()->private_data); // set fuse connection options conn->async_read = true; @@ -448,7 +455,7 @@ void *encfs_init(fuse_conn_info *conn) { } void encfs_destroy(void *_ctx) { - EncFS_Context *ctx = (EncFS_Context *)_ctx; + EncFS_Context *ctx = static_cast(_ctx); if (ctx->args->idleTimeout > 0) { ctx->running = false; @@ -667,7 +674,7 @@ const int ActivityCheckInterval = 10; static bool unmountFS(EncFS_Context *ctx); static void *idleMonitor(void *_arg) { - EncFS_Context *ctx = (EncFS_Context *)_arg; + EncFS_Context *ctx = static_cast(_arg); shared_ptr arg = ctx->args; const int timeoutCycles = 60 * arg->idleTimeout / ActivityCheckInterval; diff --git a/fs/BlockFileIO.cpp b/fs/BlockFileIO.cpp index c4f63ad..93de416 100644 --- a/fs/BlockFileIO.cpp +++ b/fs/BlockFileIO.cpp @@ -97,13 +97,13 @@ ssize_t BlockFileIO::read(const IORequest &req) const { int partialOffset = req.offset % _blockSize; off_t blockNum = req.offset / _blockSize; - ssize_t result = 0; if (partialOffset == 0 && req.dataLen <= _blockSize) { // read completely within a single block -- can be handled as-is by // readOneBloc(). return cacheReadOneBlock(req); } else { + ssize_t result = 0; size_t size = req.dataLen; // if the request is larger then a block, then request each block diff --git a/fs/CipherFileIO.cpp b/fs/CipherFileIO.cpp index f567c98..dc63ffb 100644 --- a/fs/CipherFileIO.cpp +++ b/fs/CipherFileIO.cpp @@ -254,8 +254,8 @@ ssize_t CipherFileIO::readOneBlock(const IORequest &req) const { int maxReadSize = req.dataLen; readSize = base->read(tmpReq); - bool ok; if (readSize > 0) { + bool ok; if (headerLen != 0 && fileIV == 0) const_cast(this)->initHeader(); diff --git a/fs/Context.cpp b/fs/Context.cpp index 44691f0..d7e1c3a 100644 --- a/fs/Context.cpp +++ b/fs/Context.cpp @@ -27,7 +27,7 @@ namespace encfs { -EncFS_Context::EncFS_Context() { +EncFS_Context::EncFS_Context() : publicFilesystem(false), running(false) { #ifdef CMAKE_USE_PTHREADS_INIT pthread_cond_init(&wakeupCond, 0); #endif @@ -72,7 +72,7 @@ void EncFS_Context::setRoot(const shared_ptr &r) { if (r) rootCipherDir = r->rootDirectory(); } -bool EncFS_Context::isMounted() { return root; } +bool EncFS_Context::isMounted() const { return root; } int EncFS_Context::getAndResetUsageCounter() { Lock lock(contextMutex); @@ -114,7 +114,7 @@ void EncFS_Context::renameNode(const char *from, const char *to) { } shared_ptr EncFS_Context::getNode(void *pl) { - Placeholder *ph = (Placeholder *)pl; + Placeholder *ph = static_cast(pl); return ph->node; } @@ -130,7 +130,7 @@ void *EncFS_Context::putNode(const char *path, void EncFS_Context::eraseNode(const char *path, void *pl) { Lock lock(contextMutex); - Placeholder *ph = (Placeholder *)pl; + Placeholder *ph = static_cast(pl); FileMap::iterator it = openFiles.find(std::string(path)); rAssert(it != openFiles.end()); diff --git a/fs/Context.h b/fs/Context.h index 92ca0cc..9b3c23f 100644 --- a/fs/Context.h +++ b/fs/Context.h @@ -48,7 +48,7 @@ class EncFS_Context { EncFS_Context(); ~EncFS_Context(); - shared_ptr getNode(void *ptr); + static shared_ptr getNode(void *ptr); shared_ptr lookupNode(const char *path); int getAndResetUsageCounter(); @@ -62,7 +62,7 @@ class EncFS_Context { void setRoot(const shared_ptr &root); shared_ptr getRoot(int *err); - bool isMounted(); + bool isMounted() const; shared_ptr args; shared_ptr opts; diff --git a/fs/DirNode.cpp b/fs/DirNode.cpp index 57843aa..9ffcdc2 100644 --- a/fs/DirNode.cpp +++ b/fs/DirNode.cpp @@ -50,7 +50,7 @@ namespace encfs { class DirDeleter { public: - void operator()(DIR *d) { ::closedir(d); } + void operator()(DIR *d) const { ::closedir(d); } }; DirTraverse::DirTraverse(const shared_ptr &_dirPtr, uint64_t _iv, @@ -268,7 +268,7 @@ bool DirNode::hasDirectoryNameDependency() const { return naming ? naming->getChainedNameIV() : false; } -string DirNode::rootDirectory() { +string DirNode::rootDirectory() const { // don't update last access here, otherwise 'du' would cause lastAccess to // be reset. // chop off '/' terminator from root dir. diff --git a/fs/DirNode.h b/fs/DirNode.h index 0e96c45..6cceb83 100644 --- a/fs/DirNode.h +++ b/fs/DirNode.h @@ -84,7 +84,7 @@ class DirNode { ~DirNode(); // return the path to the root directory - std::string rootDirectory(); + std::string rootDirectory() const; // find files shared_ptr lookupNode(const char *plaintextName, diff --git a/fs/FileNode.cpp b/fs/FileNode.cpp index 8ec379d..b4188f3 100644 --- a/fs/FileNode.cpp +++ b/fs/FileNode.cpp @@ -237,7 +237,7 @@ int FileNode::sync(bool datasync) { int fh = io->open(O_RDONLY); if (fh >= 0) { - int res = -EIO; + int res; #ifdef linux if (datasync) res = fdatasync(fh); diff --git a/fs/MemFileIO.cpp b/fs/MemFileIO.cpp index 6910db3..493ab67 100644 --- a/fs/MemFileIO.cpp +++ b/fs/MemFileIO.cpp @@ -29,11 +29,6 @@ namespace encfs { static Interface MemFileIO_iface = makeInterface("FileIO/Mem", 1, 0, 0); -MemFileIO* NewMemFileIO(const Interface& iface) { - (void)iface; - return new MemFileIO(0); -} - MemFileIO::MemFileIO(int size) : writable(false) { buf.resize(size); } MemFileIO::~MemFileIO() {} diff --git a/fs/RawFileIO.cpp b/fs/RawFileIO.cpp index d4d129e..c01657f 100644 --- a/fs/RawFileIO.cpp +++ b/fs/RawFileIO.cpp @@ -39,11 +39,6 @@ namespace encfs { static Interface RawFileIO_iface = makeInterface("FileIO/Raw", 1, 0, 0); -FileIO *NewRawFileIO(const Interface &iface) { - (void)iface; - return new RawFileIO(); -} - inline void swap(int &x, int &y) { int tmp = x; x = y; diff --git a/fs/encfs.cpp b/fs/encfs.cpp index bfaaacc..b97fe9c 100644 --- a/fs/encfs.cpp +++ b/fs/encfs.cpp @@ -79,7 +79,7 @@ namespace encfs { #define GET_FN(ctx, finfo) ctx->getNode((void *)(uintptr_t)finfo->fh) static EncFS_Context *context() { - return (EncFS_Context *)fuse_get_context()->private_data; + return static_cast(fuse_get_context()->private_data); } /* From 96a5f19e02a47cf8ef304f958fbe474b7f559f7a Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Mon, 21 Oct 2013 06:24:39 +0000 Subject: [PATCH 43/51] fix some path issues after NameIO api change git-svn-id: http://encfs.googlecode.com/svn/trunk@125 db9cf616-1c43-0410-9cb8-a902689de0d6 --- fs/DirNode.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/fs/DirNode.cpp b/fs/DirNode.cpp index 9ffcdc2..28362c4 100644 --- a/fs/DirNode.cpp +++ b/fs/DirNode.cpp @@ -276,6 +276,9 @@ string DirNode::rootDirectory() const { } string DirNode::cipherPath(const char *plaintextPath) { + if (plaintextPath[0] == '/') { + ++plaintextPath; + } return rootDir + naming->encodePath(plaintextPath); } @@ -308,7 +311,7 @@ string DirNode::relativeCipherPath(const char *plaintextPath) { } DirTraverse DirNode::openDir(const char *plaintextPath) { - string cyName = rootDir + naming->encodePath(plaintextPath); + string cyName = cipherPath(plaintextPath); // rDebug("openDir on %s", cyName.c_str() ); DIR *dir = ::opendir(cyName.c_str()); @@ -449,7 +452,7 @@ shared_ptr DirNode::newRenameOp(const char *fromP, const char *toP) { int DirNode::mkdir(const char *plaintextPath, mode_t mode, uid_t uid, gid_t gid) { - string cyName = rootDir + naming->encodePath(plaintextPath); + string cyName = cipherPath(plaintextPath); rAssert(!cyName.empty()); VLOG(1) << "mkdir on " << cyName; @@ -479,8 +482,8 @@ int DirNode::mkdir(const char *plaintextPath, mode_t mode, uid_t uid, int DirNode::rename(const char *fromPlaintext, const char *toPlaintext) { Lock _lock(mutex); - string fromCName = rootDir + naming->encodePath(fromPlaintext); - string toCName = rootDir + naming->encodePath(toPlaintext); + string fromCName = cipherPath(fromPlaintext); + string toCName = cipherPath(toPlaintext); rAssert(!fromCName.empty()); rAssert(!toCName.empty()); @@ -540,8 +543,8 @@ int DirNode::rename(const char *fromPlaintext, const char *toPlaintext) { int DirNode::link(const char *from, const char *to) { Lock _lock(mutex); - string fromCName = rootDir + naming->encodePath(from); - string toCName = rootDir + naming->encodePath(to); + string fromCName = cipherPath(from); + string toCName = cipherPath(to); rAssert(!fromCName.empty()); rAssert(!toCName.empty()); @@ -599,6 +602,9 @@ shared_ptr DirNode::findOrCreate(const char *plainName) { if (!node) { uint64_t iv = 0; + if (plainName[0] == '/') { + ++plainName; + } string cipherName = naming->encodePath(plainName, &iv); node.reset(new FileNode(this, fsConfig, plainName, (rootDir + cipherName).c_str())); @@ -642,7 +648,7 @@ shared_ptr DirNode::openNode(const char *plainName, } int DirNode::unlink(const char *plaintextName) { - string cyName = naming->encodePath(plaintextName); + string cyName = cipherPath(plaintextName); VLOG(1) << "unlink " << cyName; Lock _lock(mutex); @@ -656,8 +662,7 @@ int DirNode::unlink(const char *plaintextName) { << ", hard_remove option is probably in effect"; res = -EBUSY; } else { - string fullName = rootDir + cyName; - res = ::unlink(fullName.c_str()); + res = ::unlink(cyName.c_str()); if (res == -1) { res = -errno; VLOG(1) << "unlink error: " << strerror(errno); From 452690a7a35837ee9ee60ef3f01efb5499da331a Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Mon, 4 Nov 2013 06:41:08 +0000 Subject: [PATCH 44/51] fix build of mainline code for OSX 10.9 git-svn-id: http://encfs.googlecode.com/svn/trunk@126 db9cf616-1c43-0410-9cb8-a902689de0d6 --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b218fdd..16a6a0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,9 @@ include_directories (${FUSE_INCLUDE_DIR}) add_definitions (-D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=26) if (APPLE) add_definitions (-D__FreeBSD__=10) + # XXX: Fall back to stdc++, due to clang 5.0.1 header file issues + # (missing sys/endian.h, needed by standard c++ header files). + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.7") endif (APPLE) # Packaging config. From f377d34dffa4b74c4991883e7b03b18ec9aa0141 Mon Sep 17 00:00:00 2001 From: Sam Gleske Date: Fri, 25 Jul 2014 00:00:17 -0400 Subject: [PATCH 45/51] doc: encfs spelling and grammar corrections --- encfs/encfs.pod | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/encfs/encfs.pod b/encfs/encfs.pod index d264b83..3136d2e 100644 --- a/encfs/encfs.pod +++ b/encfs/encfs.pod @@ -272,7 +272,7 @@ to decode filenames if desired. B is not a true filesystem. It does not deal with any of the actual storage or maintenance of files. It translates requests (encrypting or decrypting as necessary) and passes the requests through to the underlying -host filesystem. Therefor any limitations of the host filesystem will be +host filesystem. Therefore any limitations of the host filesystem will be inherited by B (or possibly be further limited). One such limitation is filename length. If your underlying filesystem limits @@ -328,7 +328,7 @@ in the keying function is selected based on wall clock time to generate the key. In standard mode, a target time of 0.5 seconds is used, and in paranoia mode a target of 3.0 seconds is used. -On a 1.6Ghz AMD 64 system, it rougly 64k iterations of the key derivation +On a 1.6Ghz AMD 64 system, roughly 64k iterations of the key derivation function can be handled in half a second. The exact number of iterations to use is stored in the configuration file, as it is needed to remount the filesystem. From 712c242e307b0421fc9033b52d0f32b8cf7385df Mon Sep 17 00:00:00 2001 From: Sam Gleske Date: Fri, 25 Jul 2014 00:20:19 -0400 Subject: [PATCH 46/51] doc: encfs add file-hole pass-through doc Previously undocumented though file-hole pass-through has been available in encfs since 1.4.1. --- encfs/encfs.pod | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/encfs/encfs.pod b/encfs/encfs.pod index 3136d2e..22328d4 100644 --- a/encfs/encfs.pod +++ b/encfs/encfs.pod @@ -306,6 +306,7 @@ I mode uses the following settings: Filesystem Block Size: 1024 bytes Filename Encoding: Block encoding with IV chaining Unique initialization vector file headers + File holes passed through I mode uses the following settings: Cipher: AES @@ -316,6 +317,7 @@ I mode uses the following settings: Unique initialization vector file headers Message Authentication Code block headers External IV Chaining + File holes passed through In the expert / manual configuration mode, each of the above options is configurable. Here is a list of current options with some notes about what @@ -465,6 +467,14 @@ When this is not enabled and if B is asked to read modified or corrupted data, it will have no way to verify that the decoded data is what was originally encoded. +=item I + +Make encfs leave holes in files. If a block is read as all zeros, it will be +assumed to be a hole and will be left as 0's when read (not deciphered). This +is required if accessing encfs using the SMB protocol. + +Enabled by default. Can be disabled in expert mode. + =back =head1 Attacks From 556bc812b4d783c9fa5a79076dba82a12d79d3cf Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Thu, 24 Jul 2014 23:49:06 -0700 Subject: [PATCH 47/51] Create README.md Add initial intro page. --- README.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..0865c61 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# EncFS - and Encrypted Filesystem for FUSE + +## About + +EncFS provides an encrypted filesystem in user-space. It runs in userspace, using the FUSE library for +the filesystem interface. EncFS is open source software, licensed under the LGPL. + +EncFS is now over 10 years old (first release in 2003). It came about because older NFS-based encrypted +filesystems such as CFS had not kept pace with Linux development. When FUSE became available, +I wrote a CFS replacement for my own use and released the first version to Open Source in 2003. + +As with most encrypted filesystems, Encfs was meant to provide security against off-line attacks; +ie your notebook or backups fall into the wrong hands, etc. EncFS encrypts individual files, by +translating all requests for the virtual EncFS filesystem into the equivalent encrypted operations on +the raw filesystem. + +## Status + +Over the last 10 years, a number of good alternatives have grown up. Computing power has increased +to the point where it is reasonable to encrypt the entire filesystem of personal computers (and even +mobile phones!). On Linux, ecryptfs provides a nice dynamically mountable encrypted home directory, +and is well integrated in distributions I use, such as Ubuntu. + +EncFS has been dormant for a while. I've started cleaning up in order to try and provide a better +base for a version 2, but whether EncFS flowers again depends upon community interest. +In order to make it easier for anyone to contribute, I'm looking at Github as the next home +for EncFS. So if you're interested in EncFS, please dive in! + +## GitHub page + +GitHub hosting for EncFS is in progress. See also the original, and more complete, +introduction page at http://www.arg0.net/encfs From 723209aad2586794a1b330db4df71748bf0ff35f Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Thu, 24 Jul 2014 23:51:56 -0700 Subject: [PATCH 48/51] Update README.md update header --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0865c61..e4ff0f0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# EncFS - and Encrypted Filesystem for FUSE +# EncFS - an Encrypted Filesystem ## About From 401bb9e737f049c014316d95ffe587488eb89880 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Thu, 24 Jul 2014 23:57:21 -0700 Subject: [PATCH 49/51] Update encfs.pod Update encfs references to use pod markdown --- encfs/encfs.pod | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/encfs/encfs.pod b/encfs/encfs.pod index 22328d4..60d6153 100644 --- a/encfs/encfs.pod +++ b/encfs/encfs.pod @@ -108,7 +108,7 @@ password. If this succeeds, then the filesystem becomes available again. =item B<--delaymount> -Do not mount the filesystem when encfs starts; instead, delay mounting until +Do not mount the filesystem when B starts; instead, delay mounting until first use. This option only makes sense with B<--ondemand>. =item B<--reverse> @@ -469,9 +469,9 @@ originally encoded. =item I -Make encfs leave holes in files. If a block is read as all zeros, it will be +Make B leave holes in files. If a block is read as all zeros, it will be assumed to be a hole and will be left as 0's when read (not deciphered). This -is required if accessing encfs using the SMB protocol. +is required if accessing B using the SMB protocol. Enabled by default. Can be disabled in expert mode. From ad9db84ceacf520c7fcfd26546f1f8a0979f2d1e Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Thu, 24 Jul 2014 23:58:51 -0700 Subject: [PATCH 50/51] reformat file for shorter lines --- README.md | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index e4ff0f0..6b80c5a 100644 --- a/README.md +++ b/README.md @@ -2,31 +2,36 @@ ## About -EncFS provides an encrypted filesystem in user-space. It runs in userspace, using the FUSE library for -the filesystem interface. EncFS is open source software, licensed under the LGPL. +EncFS provides an encrypted filesystem in user-space. It runs in userspace, +using the FUSE library for the filesystem interface. EncFS is open source +software, licensed under the LGPL. -EncFS is now over 10 years old (first release in 2003). It came about because older NFS-based encrypted -filesystems such as CFS had not kept pace with Linux development. When FUSE became available, -I wrote a CFS replacement for my own use and released the first version to Open Source in 2003. +EncFS is now over 10 years old (first release in 2003). It came about because +older NFS-based encrypted filesystems such as CFS had not kept pace with Linux +development. When FUSE became available, I wrote a CFS replacement for my own +use and released the first version to Open Source in 2003. -As with most encrypted filesystems, Encfs was meant to provide security against off-line attacks; -ie your notebook or backups fall into the wrong hands, etc. EncFS encrypts individual files, by -translating all requests for the virtual EncFS filesystem into the equivalent encrypted operations on -the raw filesystem. +As with most encrypted filesystems, Encfs was meant to provide security against +off-line attacks; ie your notebook or backups fall into the wrong hands, etc. +EncFS encrypts individual files, by translating all requests for the virtual +EncFS filesystem into the equivalent encrypted operations on the raw +filesystem. ## Status -Over the last 10 years, a number of good alternatives have grown up. Computing power has increased -to the point where it is reasonable to encrypt the entire filesystem of personal computers (and even -mobile phones!). On Linux, ecryptfs provides a nice dynamically mountable encrypted home directory, -and is well integrated in distributions I use, such as Ubuntu. +Over the last 10 years, a number of good alternatives have grown up. Computing +power has increased to the point where it is reasonable to encrypt the entire +filesystem of personal computers (and even mobile phones!). On Linux, ecryptfs +provides a nice dynamically mountable encrypted home directory, and is well +integrated in distributions I use, such as Ubuntu. -EncFS has been dormant for a while. I've started cleaning up in order to try and provide a better -base for a version 2, but whether EncFS flowers again depends upon community interest. -In order to make it easier for anyone to contribute, I'm looking at Github as the next home -for EncFS. So if you're interested in EncFS, please dive in! +EncFS has been dormant for a while. I've started cleaning up in order to try +and provide a better base for a version 2, but whether EncFS flowers again +depends upon community interest. In order to make it easier for anyone to +contribute, I'm looking at Github as the next home for EncFS. So if you're +interested in EncFS, please dive in! ## GitHub page -GitHub hosting for EncFS is in progress. See also the original, and more complete, -introduction page at http://www.arg0.net/encfs +GitHub hosting for EncFS is in progress. See also the original, and more +complete, introduction page at http://www.arg0.net/encfs From 59477525b3d017168e181c57d5785cc255f1b1eb Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Mon, 18 Aug 2014 22:12:31 -0700 Subject: [PATCH 51/51] add encfs combo image --- images/encfs-combo-400.jpg | Bin 0 -> 12676 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/encfs-combo-400.jpg diff --git a/images/encfs-combo-400.jpg b/images/encfs-combo-400.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1408d3521b9b7c8a43f795a303dc91527ebe481f GIT binary patch literal 12676 zcmch7Wl$ST)NXJoUZA*BT#LJFan}k`fS&9z0MWSa7#O`TBnM z&;5J<+%vN~d-m)c+nJqtp4sQ6=M4anhKjlh0Og->p>P2J&zk^pWj~-j0HCD>-~<2w z*#E{qd0qu50$yNa<6>jIz{SDE$9sWKOhZCUNJz{?NkvM-!NSGK&cepVBPb`z!!OOx z#wPYwTv}0COM; zp)dhZiBZsqQJx0@)Bpeq1`5jmN%ntdOaLkxItJE%Mr9%ZDhe7JDmp3_1|}Ld8VUdf z6%Bw+j6uSPDezKW?*o$ush~nwQeguYnSS34IWx-}&rP9^jjY0o;gF)Ub0q_t{(o*L zQ2=QF`t*Or_!j~N9pj&glNf-C`Y#4L3i?0q|0^h{#3YPpOak)gFZDin2!<7&Dd;El zJ+A=p{+&Q2Mk5Bu0=E5xzB^iV8MNRTn>EQdEoM|pg2E0pb_r2#8t%HWgiQ6`VW#0r zrD8?ocXYcH5P*{M*m0TrN+Wc}V$PD}bm97a<>BqSIiz&*TcJffWodK9KK{5Gd8WIu zxLhv(d|#UV47HbHIB_iG+R5T(x9502*Gi~peezCG4zI7YX|7RVX_i2m9i>x?r>sQ3 z97dI-qT`4f^XH#h8}(E@N5?PuQu!}&e;U!hjE!UFb$|I`Dtk9jlieTw>H{tHmc?SJtHc}pJW8gqe% zNlCXAi_7sbjbkT$gzD1$ssM8e39KGdki@K`$Ueq(E2`oRMOFaSYn3JkT{8P3AOgbY= zQIrDzs}A0ipQ{!_kr2Sm9s#V^7xBR@X1S@he${L_;}R5XKglH1RV6Dij>}HM?=*l^ z57aj><=;=~swjr2Q55+gfAG{EZ)c9-_fk=Q9kXO6IOtu}ZDcwucOyJ6zbeVDqT`(O zbt>f)((ykVMljGzw#dqOnem|Mn;^De1@o@sGr$UX-pB396sopIW;EJ-!yM@@E&`@^ zymg-p462^S5DVKeY+zqU28#=4tgkB!GV(+$eZI^Z(0Xll%A$<%(S$K4o>VXL=#0HH z5oH`L|3gf7g*i{X23##lv?(&jcN1krDYg?z=_M>2SYnpjB?Y~K!AoS_PQKljnjPPhHeB3V~B zt}8C;BJ=2leM^A;nri@<`+(+s4)LCOx5o#Xmlm-O3xZ?n?>R2Z6%dZSz@yUUbb@lq zjeDvfU?|RM)*Dz&(gW|Lrwl7I+hP{s*-fYa`@f{;d1@w9(g2@JA;dVtv9+xa@mDh_|}iLrr*7RfpUwHFWV*xjbwH+U*{x~xS;KX zG>UpyK@gg)f&Qeu87mx?4Y*F&yj)8^ja^){&(a}FdrPO6DHt{tpN zNJiJ4vu*EyQoeXTjB?d%Hm|MCn7U^xg>Zk}zrLs(@u zoD=W|JE@j?ae-{D?aY?red(07E**z00}D`ic%o2J2R@g4Hit-ZaWJQ(xet6_{(I#O zTj9xViQ^gM|C)q-Y`TVHgMSErdM)spU&X;PohAZ*n%iqIBlT}|VbaK;7>(?;N2=y3w)IccbP z`KMn7ODSgGsjt~p^A4KlsrY7^9cD4MjNpK(m3LG%=r?Psw=LBmm@)OR9C%j4uaj0~ z8pWn;bsUF;pCn@GR;D+EjHbiG%*;p-1%cYc)=a;`6vJPHaFyy@RE<<>Qby}XU(ig8 zv-I&ap38Y1^yV2*)(zL3#=}t14E+uIawM)0Vv30ud40fx6c_>C?@Wg|taagl+SN$4#Sc2V?Ek zPco|#;k^&q`L()k_4&hfK%O6_Kir-HjXw7a%PDpQI3<#^Lku`922=rEZD_w14QELC zv~-e}@jbVxX{pTBYaw!;D=hjwcut5BYnM5x3H7W~n)em-(87TuQ&+)TrX8OE z$s{T{fS}adyQr=E2~Gtg#)S*ZodQ_1)y|Y(Z-!d6v#qkg-ZcrUdmVCRXxn7*EdPOC zm+8Cw#q%fu>Ap$Uq#YGL&66}q82huRl~_<-;3~yqJCJl!5uH${B7F~=DwYilXT+L{Vy##Uha#CzQ8Z3u(schfAd&Pnr@5F&sRG~1$hRP zgfy`uP=4gh>>cy2O9lgturQ?(hQnAeOp?|+7)#%RZ;rmi6H3iYDZyXOcw>Xc0RFcV zs3RWXgu=q#YQ4+f)OKYXJ9GV+XUQopv?>2lc-_UlVw}&J@P&wQz1g=YlOVKeQj`UZ zUCUwJf2tOk2D)8TPAm$R4tLajx#}CR zFX7dHXx6w*!$JQCWC?3m!J6>LjOxI=0d{1OrQWh*MO+NAu~-;OQE5l6EAezRcfI?n zJk2JPNx#tH0AY~%UU*V8?a~ZfF=bV1AEq>Y`ta{w_E#P`$#^qiJ{%0Pwen4mspM44e&0SltD5? zAm-fBp?6d|s@!?-+jpqVN@~&WUy?w-*oQ@kXhH3%_)LTbF!}IM0 zQitChsu<59Z!?Ijs_8c;2{#-*-$dHGI5RM~suLwmxhf0Mx**97N`P!`eyc%pY#Q0&aEGyA0wU zbyK6}r8et+UG{y?2HMlR=9#VA@iPg;oKjlnm#kZqeG_5Lr)Y`!42XV92vXKROd}?| z*mb6%v57#gSN}9L9YzWC7ol&$_xO{1FTtPC7xomLPoo_gk++ux@-nO2E$Cg85AO8$+Sa5L) zc4~r13Cd%^YEh>W%g^hgM7P2F<*zq5606?C9fxBN$rz8wO4#aA+M)!t*QG8+CKnw@ z_|%>ET^ZV|%0p@-6L!EKf8@(8+R9OC^7Y`5&2S%MP4mRi5aPJY99(Q3AKRJk<#5L> z3!Kv@*7Inn`$)nKK1n2$dAqBhEqTB{<~)g4yRTD=(k9S6!8{*&GO1G_XDWz}#zf#~ zC9n~%_QD2suG-GbFUS4FSJ^<2hfo6RPXMo&;O>nO1~_#dry9vuW(m0#?{xfoIPg(w5wL-JOFmxs2JZR zP|&td*k6M^*$mdB4Y5e}(4IIQo&nm(IAJUN8jsGGXRQm5`)Ji&N(WqDQ+A>$NA@J; zPH&AE)}mP|sDskj7P{bQ3A*yVl`QaqC7+6LFzxbGvsamXQ6hrwnx8^fV7*xG1!zLe z5B=WAG%7}MQtGhG0iEt^oSCPH`tN`5eC%y8?MqV#Er#=w$ihdmu6P~Cy=(P0PM+R} z$*(nQnxAG(l2<<=J(JL#2^nly5;}!&iuTQITXfeC<|bz?A^JjM6j+q6Vw}UU?Fp`_PrJS0El9kxb?dS~f_WAEHD+BqY zng9(SRnBwsF{5q*xe3o)UXYs~3mOaBkatL4hWad3h8=ooY^%)u-_)szkgYquAya-8 zXnDR-vcUt(kyaOUfZ+45)2XSL@(APUGXrA?d|R$59w+RUoCJR_J<+2f_2|DKu;^0D=W9vVILbyyDKV;Z*Wceo5ndMI z?7STnHWy|HenP2Om2_o&#T`5ZqOK7hEWvxU4)LD7>MThv_D)L)Rx@XGTV3DP^7k zl(p6^Z4j9xwc2ba_{gk=eBV+zeI+Sj!QrczEbpwJcizbq&}!S6cUGfYSCh$n(VLMm zicP^?jpvVt@d8eecfZ**eKDTSY>^!@(Lg7ct9_QX_B=*L*0HL+?-bR^z%>y?m4yqA z(=(0FcnjW-33yaN2~Fu=0cdR$r@GK!3ULat4SMs`iIXvyaU4!l97>I)GR?V~D*o0d zdT;$1p?je}{mT8Lgzi#(6?ykm_IK_$(APDp)!fPo72C&Cscu#VZ_18VpNfC61+uM( zWCZ40bLGN$i5?#h3;)iDG?yi{vhmxt<}V9R)h*&KZKGKcpD1XmI74680ev9awqBf4 z0+T_PhNTa~O;?&pu0JZD0fPVn8SfC4Md~8ma_QW!yerT$UOpIk*7_O=>oXuX6z!U9 z%4>qt%Gam7>Y$#;AD3e%H|jJ&L%1h3K}C!8=Y0cQdGtu6LU_tWIO^kEQDY|UTkT0o zfBYKj?<+hile{;HJt)7cAx<*3_7C!xbMu;9gr$CAxO zHAlsO&_^{*^hs>e){$=&g4A4A8Uy;emg6{L1huPhy#!OS4kQmx^f=4%NB^6`k-FMV z>YP3LJcmeAVx1Xs!Sl5CJGra92jijcA5`Y5yzkp4Lmoct(dBtFhZkJxLc}j*t{39% zP133Fb~}YD9NZ$%5_u4NQwQB1-*zsXN|3?Yymhwc1-K2Xb!sOb&}YCw>48DTj5St^ z)l(rHUUL&5oiofnBF~N=!Q2!02QS1s*KIby@4#!;BqidCW?h z5Ef78G=jZ=ue3dn3(Sr;gv=wi`YI=yf*Cqkb1^yaP9;B96Q-jz))F#mVR2Hla4CLm zN9wwiR%PY6YsD=(f-5LeZ>Rz}LI0?~ao?tHHpiFK0{P($@ z){A<$nbF_gpiDG6rOQ*jHz-T)l4$y4G7Qu*^K_nsHdfdX9K-FhV|h?Y(xnmfd`{5& z?fHDq5NuQb-DaWDn3T8YZ6VDmfmzFQg&;SY2uacH^HcQ+)1wf+`GS0tEVBn=iWQs9 zU=aoXNrHYkXt%9A$i?LoCO3%+M36G4b?+@|)_-tk3Pk5D-u!$1{U>L*|1ATt zQbPp=ZaLd&twVG5y=DE0Db6JirFq(|{?9qMvP`ra-fRWO*Gc&!zgpvbx9#Ct-@kYm z{sN=7yRE|2m8{5a5spbEkDk6~K<4LK{}RPuwrF9vdSAbSjn$-1Yhtz4JC`dfk^a}a z%F(f)n^sI4A*Uf}p`2Y=` zZ?OxXzLOU2-zA!wn`}_tlG|;8S~Na1Ky21aGuJ>Nc0XtAypeQL)DwH}q#__rXxzP9 z=#!;oYeeNr0e8Lsm(fuGNzg$D+!EN&v6boDqJlE|F4rl=I15bYI zng-huTWLR$;e@2{Is25JX-Sn@`_ZsGJo7m`zE zjJ9fiX4QjsLKRZ5X$p7r1!|*mVjpy@5O$^R;3z?)i4hZqkm0E^CHuB7x?+nZb_A4*?ZGXkXZq+A}`!_ zGXflOYaEhX6xsBnhu3pzG;Bo^nCV&U-e+LxnG-xgtFF1a zgaSf{e+^epz;}mAog4ORwl@+;dnoxD)2h!6z5lw^*=o=z0>;7uKO$RhpHxMB&H7`Z zLoBBBadvI>n9a!-gl#DaU&zJxP;-jp;dzgE#wW%8F!DKd8`cs{j+1F<(%ns^kQ1$Z z?Nl`H{f?wUI5zk*vDm3%vZmL^uMOQgpf_f~>Ng}dk!U+-(>tTAmdRmo6r{2=kV;v) zi4${ai}wB!^~;GL{%^PPQc?2RH_7eUd_2ZpcgwAU`Bkc9M$lpZ@;*jwD8#8w1EIDT zTWJ~$s?w6xT3?D*IBAcI4{8*D!gvqd(}|xH=jGW+Q?b`a3nff1b($!)rWVb@UQx?Y z<#MKudht6!+lg~Zt*2uyl`%TwM7+26^w5&n3HL{%X4QUN(cH`QrgmLFEWgt`1C}h7 zFFZ}o)oYpAELlxYeAOM#faKM2_j-d;VXdE}^1-dRrO;o|ur8)>xS9%Kp4jW?*WFo& zk|Q3Se|%GFHIq!*ynT}4>hUd$9%g;{-=i6?RZm~Bls&q(f0VD8x?^U8&Ipkwal6!+ zBe?_Gx+@+%}y{^CCyQFs6{ssu(j~*I{iSDKMM%1d%t|kI(DOn< zQWY!1TiSVX0HWx0a9qO^8(}>G){lnU7=4J90@_a8ELCoehDWIb227pupsanXcprTV z2HeCm|6ygN?x{RZgYCfiWflb}I)dhpo;_pgc5bkFN1-v1_(0_1sRnm@%ZA0xP@12_L$~)@~p(sj* z5QeCZ{UCSA60pW@kD-{`X8&A$vVtt&UX`;Rv?Xv{Iq(!`y9HV9 zt_a_Zq!6A7@W}LvQpkCqztFyrBiCtpZbi2Yk%&rSp3K8i zTR68v3l~6I3lA3GffQ|wauLykxfk^AfKRfswWC#%RowqTl_(|3FsAeqG}U8cGF#Yu z_nkA$&6}%GWyM5%MU}D!wy+ZzRHK_tLm$CHXx`voC0#?LzBzcvwEfu!Wzrp#!1>G6 zjIR4L8F5xuzf*TFswqEj$b- zeV!bkj}tP2L5&=Unr)nkFY;*d zR0>iY=qLEejeY>EE3WM;;t-sOXQXbU^PBro-B z*tQf=FosvZaM4TO9}+rsj%#2|Cbhv}OCw+;^s+k3bSkE&z-ae@J4IFx#$BG|yhRLY z2jj&{RqhW9t-NxTjSMqtHltQ=Zh~MBD4l~FK8!-es%%U_GSh`~lw-ELUFDboB2JXc zpTSwccDqX(vs;NOWyV2!C0rak=lH;&N~mG04UvTp9UH@sGptRs*cZG{qChMs#FJ6- zyh)t53y{?5JY9_5+q?tj;=(2{?z$1Sq@MHV=2+J$ab>*F^j)EsKW`WR#1ekHY_2Sg zRjfECKm>d|8H|JgB&qy+C+89gONGGT#iDp}qd%5to#J)rq`No^D(EG;n22PseS1>` zp1_b-E}F|tF^&E)=lfy!nFlMoLtSrx$ql) z2HX~@cf8XCl1*gMNo6FARgcePY3}M2H+@>ZtMfj-e_K1XLy1=7Y*@`A%03oCZVX76 zEU+${6QwcN7`)vET@E>q&zL)(nM?JL%*S(o)hfnsyc zPpWmG6l;U(qx1aUe|h(E_Fflns)k5As*cLcQ=V{@GU1ghTjbu z?`*XaTstuT#^&esio^7JV5xv*_#Gf2U;=sQ)!mp|Cf65*g*MwYPmq(jvNx~xJ3_xX z&F;*anBiLcAHFfoq9>QGVMG((RAas@)GluQHbxC}2~%aM_6$K-WLX`qAr~(AN4>ZI z%&;38CaU-#)9|9*_*-L4i+Me(40G~_E4_css^b@Rx(f7G0qCy7DlEs=^oZ8o8!OP} znt|7r-%JZx5*28khASy-*q@>~%s)yD4>%rO({m#*(Hsza@+M}lv~s{U^xP&UxHAMMKYs14#?*VPm!2*e z3dTzx7V;!IHy2BaRJ+g};Umya>rxgH6jyt+8I_GZDoTam0U~GMmsUr+0MH( zXu8zAcK!@EWP!5&<#1xWA`KqZzyY-+b+DF;5R5Aa6Al`!tWeQTwrN-A5+&3(<-&Mn zVrLSnNQ1jLck-djgN5qLQ8A=547wImUcPVcQZ^^t8czYx{502AI3fM_>%7VfPbC*F z)dV-rUrcj@@RH6fD{miH?{c6m>ri8;$M3B|jz%n-)ydY5BI9)9j8?BO*@GI6?0`%7 z{h}(>tSuY7T!4b2o*}bH%14UoMji~K?0c8%#p)PsJz2HlpFaf17(F-s(6PuUe))TN_+$ zzgyWSSmJ?X6k*>~t-%5EZEV>ang~(H5XrHx+0!&C3k<>U1gvk5|IswuzErAHWUH#I zsXGr>^0S}`nF=FY_8>ttLQeXWAcd9=;g~}_)!<0_xKErtBBIol#RZzIFb|a}zs!Ul zgKv-cA}#^c)kZBA88hju%i?V3Qo7}a>r<>-W`lP}b^kcKX6FEN*h)gl>8T9u>iFpB=wBler(>23i&ak@iWh&cs9Ez9YU=XQk6Gkz zzOjJ`_DEH7g+I}z{3*5J*B=iR_zRN}t2-iHJqmZ>z1c&upRx!t*d3o zH^rjSTqd(~(s|)6nX0P))u6548 z-Ahy7#uwdg!+^M1LeAL($$H{cos{<>-j)GH+E>3wf+~qqx98+9>n)N@id2)#CcIYP zD;x!Vr2w|feYVR3)FM#FTc@PvLn5L?+S>a7G!YlV&G<*Uj^<##xN1*$fT6g>=LTyD zw0f`cPK>w{W;<0t#P4Uox2D=FHNIli=8lg7=Nx?uGl6RsYl9!Nog0$k>XDZMb?U9LHCruii@QjPhi$}XH^aKF!ArETJp zsSWRU%X4~Eh8bFlDVva)E}E`@c%6_dX-}W^k#_v}H-|$nuY z5qDYLKl`U^_L3Rn`Xllki($t4YD{TD+^EMa{{GJZi8%P2U7&Ia3GzRh@n>wf*()i~ zl5R+`h(w-3*E1jr?Q+QM$D&PZlbY-M&rEB|tn&Jd<O78MHqo(KDvP#C&H}_4(K`7pZ`Oe~ zjXKTYzK>gn6j*#f9E=J$LNNl^+SfV~nLD2I=kUb@s{Nd7FJz?^yfFE0@<-Nv2Mnry zEhaf7e0meGAsFGF6R&+aBX8lZoR08x&# zp>!)|HP=a!%_1go)pH&zat3hvpsu@LB&z%nJ+1M~xnJX)EmBgyRI&G>lPuGDBbi$( z%h+h<+D`YZgcOGF?3UPRlEW;lSkYDw%G6EJJ`4xllcl?QfT-!*`(yWBxOkNF;o64o z?fSs(>9z1NI{B~tFJTvAfCS3VsWdF-Q9d`pU#3MGoR}Qr1Ua0)JN7)lKd!Yv>{d)D z_Jle5XNwwAMeXoWKm57I+0KOud4oW&rprJHUnz1PtMh;} zdF!vKM}6`tW$zZ|VD>z19B9b=R;$=mIX{LkRirFAa9>jzHZ06Ff0g-dL`EQTl!BwcVB zWF1MFirZ9KsX8YK*`@GhTvXcTyv^2XqbCrfxU7k4=EEh`E#?%^$9G6*@`SbB?(*qpuFgVWch$bRxSmzIea{bb}%0Ob2;SS*#a8ktHSwH84m(ev5(^lx4)TfAs&KQ4G`wq4^%py zRZ#M@j>NRr%1oxtSrWI&rjJF^>t*~P+QZ5+qE>7-5GjSZ@zOLc2uLQy4FOea4u~u= zAj{;k0xb<8`2zHobLqP78||)=TVR<8X02=LO!xj_46aFqkHz`=^E5Wps*e$5`8b?TZ1;>z)}ZCr)pC-h{4K2X(|3<==6iqMM&1;K|UMWq=i(Y6W-C8SyS z*n>ZQ)Ugs@65IEbOq{hq6cB8>k3x7$13x0RJ|V z+OU!F`hbJ4u6Q7;{IB$0LI=4%SCxCigwEa882>?jz5H`x1kCsuV4`ystT8ctxuGxI zkUV4NZBZv>ntC^+bSr;Lj}gWuJ!JRyEPXNN>fKv7fkS^6byDL>bw=77Od^|ujhDLA zU2PsO=^1dy6r>diG&dfHl-w*Eq$5))FqIE$Rgi_Y^r#35tg#=-p+6;5kjtj@0x|xU zZ(prva*}nvw&w=yCNaD>Fb##$c30*k!)N4eu7O`xx{r#FCy(zMssby)Lm3cHodC0P zq7ZkGMWPcO`9fUOuRw~x1x%p*w;Jw{UiIDXI605bq&>aeGzV05GT%pZ#QMLj51mQ7 zoZPb$D7N1iC#e%a+A9?V6eNx`vl9SQGk(BDIprH8Pp7rvP?0NXOQZ=8Umbriwy=S5 z`_oRvgpVa=%681;Xld4%2=qvHP?pL!61qr6uEo8Op=QH;9Aix$vQ%-YDTE?19HsaQ z3x<2u2G_`{PqyBkCN~rOM1ffE`ZQH)0tebolRK_Cs$9MepZQHkJjL|mm%#m7>}P;_ z#Scv(T{9uS7`eVgM2m?~=_*$`Z$ZOo?^eMC_cVGj3hs$@(7Cmr(;mYkr__I017A5- zi1!Wy4-OLoDzk1qY6=?r+@0K%4_?o@lqiYWPZCZ>ic(#^j``u7XK0+1X&Iy{1q-2< zH8psnDO^U95jIR?l1DDHRB`byEA(*grv`maDD@|wgZkuug?xC2C0)RjTQY@K_L+_WS&`r@`AGkXdl|Roapil*c0l1jEV3lZClVaT`{aQpx`vD R)I}}TNCo_VSbTn7{vR>!dN%+7 literal 0 HcmV?d00001