From 17071239d81348ff9d7ded436e10fef7d6fa34ea Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Mon, 30 Aug 2010 06:32:05 +0000 Subject: [PATCH] Cleanup option passing to make it simpler to pass options around. Add new initialization vector setup mode for new filesystems. git-svn-id: http://encfs.googlecode.com/svn/trunk@59 db9cf616-1c43-0410-9cb8-a902689de0d6 --- ChangeLog | 10 ++ configure.ac | 5 +- encfs/BlockFileIO.cpp | 11 +- encfs/BlockFileIO.h | 8 +- encfs/CipherFileIO.cpp | 41 ++++---- encfs/CipherFileIO.h | 14 +-- encfs/Context.cpp | 1 + encfs/Context.h | 2 + encfs/DirNode.cpp | 36 ++----- encfs/DirNode.h | 38 +------ encfs/FSConfig.h | 132 +++++++++++++++++++++++ encfs/FileNode.cpp | 31 ++---- encfs/FileNode.h | 21 ++-- encfs/FileUtils.cpp | 232 ++++++++++++++++++++--------------------- encfs/FileUtils.h | 144 +++++++------------------ encfs/MACFileIO.cpp | 37 ++++--- encfs/MACFileIO.h | 7 +- encfs/Makefile.am | 3 +- encfs/SSL_Cipher.cpp | 60 +++++++---- encfs/SSL_Cipher.h | 6 +- encfs/encfsctl.cpp | 40 +++---- encfs/test.cpp | 55 ++++------ m4/Makefile.am | 15 ++- makedist2.sh.in | 2 +- 24 files changed, 479 insertions(+), 472 deletions(-) create mode 100644 encfs/FSConfig.h diff --git a/ChangeLog b/ChangeLog index 62697d45..402690d4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +Sun Aug 29 2010 Valient Gough + * new IV initialization + * tag version 1.7 + +Sat Aug 28 2010 Valient Gough + * fix component configuration to ease adding flags or config + +Thu Jun 17 2010 Valient Gough + * bump version to 1.6 + Mon Jun 14 2010 Valient Gough * fix compile error for boost < 1.41 and change rWarning to rInfo * fix compiler warnings about unused result from fgets diff --git a/configure.ac b/configure.ac index d4c4d655..34fdba3f 100644 --- a/configure.ac +++ b/configure.ac @@ -1,10 +1,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 -AM_INIT_AUTOMAKE(encfs, 1.5.1) dnl searches for some needed programs - -RELEASE=1 -AC_SUBST(RELEASE) +AM_INIT_AUTOMAKE(encfs, 1.7) dnl searches for some needed programs AC_CANONICAL_HOST AM_CONDITIONAL([DARWIN], diff --git a/encfs/BlockFileIO.cpp b/encfs/BlockFileIO.cpp index 769e02fd..e6b9df56 100644 --- a/encfs/BlockFileIO.cpp +++ b/encfs/BlockFileIO.cpp @@ -36,9 +36,9 @@ static void clearCache( IORequest &req, int blockSize ) req.dataLen = 0; } -BlockFileIO::BlockFileIO( int dataSize ) - : _blockSize( dataSize ) - , _allowHoles( false ) +BlockFileIO::BlockFileIO( int blockSize, const FSConfigPtr &cfg ) + : _blockSize( blockSize ) + , _allowHoles( cfg->config->allowHoles ) { rAssert( _blockSize > 1 ); _cache.data = new unsigned char [ _blockSize ]; @@ -98,11 +98,6 @@ bool BlockFileIO::cacheWriteOneBlock( const IORequest &req ) return ok; } -void BlockFileIO::allowHoles( bool allow ) -{ - _allowHoles = allow; -} - ssize_t BlockFileIO::read( const IORequest &req ) const { rAssert( _blockSize != 0 ); diff --git a/encfs/BlockFileIO.h b/encfs/BlockFileIO.h index ff5fa803..b7780fbc 100644 --- a/encfs/BlockFileIO.h +++ b/encfs/BlockFileIO.h @@ -19,6 +19,7 @@ #define _BlockFileIO_incl_ #include "FileIO.h" +#include "FSConfig.h" /* Implements block scatter / gather interface. Requires derived classes to @@ -31,7 +32,7 @@ class BlockFileIO : public FileIO { public: - BlockFileIO(int blockDataSize); + BlockFileIO( int blockSize, const FSConfigPtr &cfg ); virtual ~BlockFileIO(); // implemented in terms of blocks. @@ -40,11 +41,6 @@ class BlockFileIO : public FileIO virtual int blockSize() const; - // default is false, but setting this to true will allow holes to be stored - // in the file. Only works if supported by the underlying FileIO - // implementation.. - virtual void allowHoles( bool allow ); - protected: int truncate( off_t size, FileIO *base ); diff --git a/encfs/CipherFileIO.cpp b/encfs/CipherFileIO.cpp index 19c58b66..11e97a05 100644 --- a/encfs/CipherFileIO.cpp +++ b/encfs/CipherFileIO.cpp @@ -50,23 +50,23 @@ static bool checkSize( int fsBlockSize, int cipherBlockSize ) } CipherFileIO::CipherFileIO( const shared_ptr &_base, - const shared_ptr &_cipher, - const CipherKey &_key, int fsBlockSize, - bool uniqueIV, bool _reverseEncryption ) - : BlockFileIO( fsBlockSize ) + const FSConfigPtr &cfg) + : BlockFileIO( cfg->config->blockSize, cfg ) , base( _base ) - , cipher( _cipher ) - , key( _key ) - , haveHeader( uniqueIV ) + , haveHeader( cfg->config->uniqueIV ) , externalIV( 0 ) , fileIV( 0 ) , lastFlags( 0 ) - , reverseEncryption( _reverseEncryption ) { + fsConfig = cfg; + cipher = cfg->cipher; + key = cfg->key; + static bool warnOnce = false; if(!warnOnce) - warnOnce = checkSize( fsBlockSize, cipher->cipherBlockSize() ); + warnOnce = checkSize( fsConfig->config->blockSize, + fsConfig->cipher->cipherBlockSize() ); } CipherFileIO::~CipherFileIO() @@ -193,7 +193,8 @@ void CipherFileIO::initHeader( ) req.dataLen = 8; base->read( req ); - cipher->streamDecode( buf, sizeof(buf), externalIV, key ); + cipher->streamDecode( buf, sizeof(buf), + externalIV, key ); fileIV = 0; for(int i=0; i<8; ++i) @@ -277,13 +278,11 @@ ssize_t CipherFileIO::readOneBlock( const IORequest &req ) const off_t blockNum = req.offset / bs; ssize_t readSize = 0; + IORequest tmpReq = req; + if(haveHeader) - { - IORequest tmpReq = req; tmpReq.offset += HEADER_SIZE; - readSize = base->read( tmpReq ); - } else - readSize = base->read( req ); + readSize = base->read( tmpReq ); bool ok; if(readSize > 0) @@ -293,10 +292,10 @@ ssize_t CipherFileIO::readOneBlock( const IORequest &req ) const if(readSize != bs) { - ok = streamRead( req.data, (int)readSize, blockNum ^ fileIV); + ok = streamRead( tmpReq.data, (int)readSize, blockNum ^ fileIV); } else { - ok = blockRead( req.data, (int)readSize, blockNum ^ fileIV); + ok = blockRead( tmpReq.data, (int)readSize, blockNum ^ fileIV); } if(!ok) @@ -352,7 +351,7 @@ bool CipherFileIO::writeOneBlock( const IORequest &req ) bool CipherFileIO::blockWrite( unsigned char *buf, int size, uint64_t _iv64 ) const { - if (!reverseEncryption) + if (!fsConfig->reverseEncryption) return cipher->blockEncode( buf, size, _iv64, key ); else return cipher->blockDecode( buf, size, _iv64, key ); @@ -361,7 +360,7 @@ bool CipherFileIO::blockWrite( unsigned char *buf, int size, bool CipherFileIO::streamWrite( unsigned char *buf, int size, uint64_t _iv64 ) const { - if (!reverseEncryption) + if (!fsConfig->reverseEncryption) return cipher->streamEncode( buf, size, _iv64, key ); else return cipher->streamDecode( buf, size, _iv64, key ); @@ -371,7 +370,7 @@ bool CipherFileIO::streamWrite( unsigned char *buf, int size, bool CipherFileIO::blockRead( unsigned char *buf, int size, uint64_t _iv64 ) const { - if (reverseEncryption) + if (fsConfig->reverseEncryption) return cipher->blockEncode( buf, size, _iv64, key ); else { @@ -391,7 +390,7 @@ bool CipherFileIO::blockRead( unsigned char *buf, int size, bool CipherFileIO::streamRead( unsigned char *buf, int size, uint64_t _iv64 ) const { - if (reverseEncryption) + if (fsConfig->reverseEncryption) return cipher->streamEncode( buf, size, _iv64, key ); else return cipher->streamDecode( buf, size, _iv64, key ); diff --git a/encfs/CipherFileIO.h b/encfs/CipherFileIO.h index 99aa429e..04200d58 100644 --- a/encfs/CipherFileIO.h +++ b/encfs/CipherFileIO.h @@ -20,6 +20,7 @@ #include "BlockFileIO.h" #include "CipherKey.h" +#include "FileUtils.h" #include @@ -34,9 +35,7 @@ class CipherFileIO : public BlockFileIO { public: CipherFileIO( const boost::shared_ptr &base, - const boost::shared_ptr &cipher, - const CipherKey &key, int blockSize, - bool uniqueIV, bool reverseEncryption ); + const FSConfigPtr &cfg); virtual ~CipherFileIO(); virtual rel::Interface interface() const; @@ -70,8 +69,9 @@ class CipherFileIO : public BlockFileIO uint64_t iv64 ) const; boost::shared_ptr base; - boost::shared_ptr cipher; - CipherKey key; + + FSConfigPtr fsConfig; + // if haveHeader is true, then we have a transparent file header which // contains a 64 bit initialization vector. bool haveHeader; @@ -79,7 +79,9 @@ class CipherFileIO : public BlockFileIO uint64_t externalIV; uint64_t fileIV; int lastFlags; - bool reverseEncryption; + + boost::shared_ptr cipher; + CipherKey key; }; #endif diff --git a/encfs/Context.cpp b/encfs/Context.cpp index 9d74a9ce..3ab84354 100644 --- a/encfs/Context.cpp +++ b/encfs/Context.cpp @@ -22,6 +22,7 @@ #include "Context.h" #include "Mutex.h" #include "FileUtils.h" +#include "DirNode.h" #include diff --git a/encfs/Context.h b/encfs/Context.h index 5a77c086..5628bd23 100644 --- a/encfs/Context.h +++ b/encfs/Context.h @@ -31,6 +31,8 @@ using boost::shared_ptr; struct EncFS_Args; struct EncFS_Opts; +class FileNode; +class DirNode; class EncFS_Context { diff --git a/encfs/DirNode.cpp b/encfs/DirNode.cpp index 7c1a6438..91a6580b 100644 --- a/encfs/DirNode.cpp +++ b/encfs/DirNode.cpp @@ -302,7 +302,8 @@ void RenameOp::undo() } DirNode::DirNode(EncFS_Context *_ctx, - const string &sourceDir, const shared_ptr &_config) + const string &sourceDir, + const FSConfigPtr &_config) { pthread_mutex_init( &mutex, 0 ); @@ -310,14 +311,14 @@ DirNode::DirNode(EncFS_Context *_ctx, ctx = _ctx; rootDir = sourceDir; - config = _config; + 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 = config->nameCoding; + naming = fsConfig->nameCoding; } DirNode::~DirNode() @@ -689,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( config->externalIVChaining ) + if( fsConfig->config->externalIVChaining ) { rLog(Info, "hard links not supported with external IV chaining!"); } else @@ -745,16 +746,8 @@ shared_ptr DirNode::directLookup( const char *path ) { return shared_ptr( new FileNode( this, - config->fsSubVersion, - "unknown", path, - config->cipher, config->key, - config->blockSize, config->blockMACBytes, - config->blockMACRandBytes, - config->uniqueIV, - config->externalIVChaining, - config->forceDecode, - config->reverseEncryption, - config->allowHoles) ); + fsConfig, + "unknown", path )); } shared_ptr DirNode::findOrCreate( const char *plainName) @@ -767,20 +760,11 @@ shared_ptr DirNode::findOrCreate( const char *plainName) { uint64_t iv = 0; string cipherName = naming->encodePath( plainName, &iv ); - node.reset( new FileNode( this, - config->fsSubVersion, + node.reset( new FileNode( this, fsConfig, plainName, - (rootDir + cipherName).c_str(), - config->cipher, config->key, - config->blockSize, config->blockMACBytes, - config->blockMACRandBytes, - config->uniqueIV, - config->externalIVChaining, - config->forceDecode, - config->reverseEncryption, - config->allowHoles) ); + (rootDir + cipherName).c_str())); - if(config->externalIVChaining) + if(fsConfig->config->externalIVChaining) node->setName(0, 0, iv); rLog(Info, "created FileNode for %s", node->cipherName()); diff --git a/encfs/DirNode.h b/encfs/DirNode.h index bd97ae90..2f413f82 100644 --- a/encfs/DirNode.h +++ b/encfs/DirNode.h @@ -30,6 +30,7 @@ #include "FileNode.h" #include "NameIO.h" #include "CipherKey.h" +#include "FSConfig.h" using boost::shared_ptr; @@ -87,38 +88,10 @@ namespace __gnu_cxx class DirNode { public: - struct Config - { - shared_ptr cipher; // cipher to use - CipherKey key; // cipher key to use - shared_ptr nameCoding; // filename encoding implementation - int fsSubVersion; // filesystem version number at creation - int blockSize; // file data block size - bool inactivityTimer; // enables inactivity tracking - int blockMACBytes; // >0 enables per-file-block MAC headers - int blockMACRandBytes; // random bytes in MAC headers - bool uniqueIV; // enable per-file initialization vectors - bool externalIVChaining; - bool forceDecode; // force decoding, even if errors are detected - bool reverseEncryption; - bool allowHoles; // allow holes in files - Config() - : fsSubVersion(0) - , blockSize(1) - , inactivityTimer( false ) - , blockMACBytes( 0 ) - , blockMACRandBytes( 0 ) - , uniqueIV( false ) - , externalIVChaining( false ) - , forceDecode( false ) - , reverseEncryption ( false ) - , allowHoles( false ) - { } - }; - // sourceDir points to where raw files are stored - DirNode( EncFS_Context *ctx, - const std::string &sourceDir, const shared_ptr &config ); + DirNode(EncFS_Context *ctx, + const std::string &sourceDir, + const FSConfigPtr &config ); ~DirNode(); // return the path to the root directory @@ -207,9 +180,8 @@ class DirNode // passed in as configuration std::string rootDir; - shared_ptr config; + FSConfigPtr fsConfig; - // stored here to reduce access through config var.. shared_ptr naming; }; diff --git a/encfs/FSConfig.h b/encfs/FSConfig.h new file mode 100644 index 00000000..81ac0eb3 --- /dev/null +++ b/encfs/FSConfig.h @@ -0,0 +1,132 @@ +/***************************************************************************** + * Author: Valient Gough + * + ***************************************************************************** + * 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 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 _FSConfig_incl_ +#define _FSConfig_incl_ + +#include "encfs.h" +#include "Interface.h" +#include "CipherKey.h" + +#include +#include + +enum ConfigType +{ + Config_None = 0, + Config_Prehistoric, + Config_V3, + Config_V4, + Config_V5, + Config_V6 +}; + +class EncFS_Opts; +class Cipher; +class NameIO; + +struct EncFSConfig +{ + ConfigType cfgType; + + 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(); + + boost::shared_ptr getCipher() const; + + // 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); + +struct FSConfig +{ + boost::shared_ptr config; + boost::shared_ptr opts; + + boost::shared_ptr cipher; + CipherKey key; + boost::shared_ptr nameCoding; + + bool forceDecode; // force decode on MAC block failures + bool reverseEncryption; // reverse encryption operation + + bool idleTracking; // turn on idle monitoring of filesystem +}; + +typedef boost::shared_ptr FSConfigPtr; + +#endif + diff --git a/encfs/FileNode.cpp b/encfs/FileNode.cpp index c7fa3573..65181995 100644 --- a/encfs/FileNode.cpp +++ b/encfs/FileNode.cpp @@ -63,13 +63,8 @@ using boost::dynamic_pointer_cast; static RLogChannel *Info = DEF_CHANNEL("info/FileNode", Log_Info); -FileNode::FileNode(DirNode *parent_, - int fsSubVersion, - const char *plaintextName_, const char *cipherName_, - const shared_ptr &dataCipher, const CipherKey &key, - int blockSize, int blockMACBytes, int blockMACRandBytes, bool uniqueIV, - bool externalIVChaining_, bool forceDecode, bool reverseEncryption_, - bool allowHoles ) +FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg, + const char *plaintextName_, const char *cipherName_) { pthread_mutex_init( &mutex, 0 ); @@ -78,23 +73,15 @@ FileNode::FileNode(DirNode *parent_, this->_pname = plaintextName_; this->_cname = cipherName_; this->parent = parent_; - this->externalIVChaining = externalIVChaining_; - this->reverseEncryption = reverseEncryption_; + + this->fsConfig = cfg; // chain RawFileIO & CipherFileIO shared_ptr rawIO( new RawFileIO( _cname ) ); - io = shared_ptr( - new CipherFileIO( rawIO, dataCipher, key, blockSize, - uniqueIV, reverseEncryption )); - - if(blockMACBytes) - { - io = shared_ptr(new MACFileIO(io, dataCipher, key, - blockSize,blockMACBytes,blockMACRandBytes,forceDecode)); - } + io = shared_ptr( new CipherFileIO( rawIO, fsConfig )); - if(allowHoles) - dynamic_pointer_cast(io)->allowHoles( allowHoles ); + if(cfg->config->blockMACBytes) + io = shared_ptr(new MACFileIO(io, fsConfig)); } FileNode::~FileNode() @@ -140,7 +127,7 @@ bool FileNode::setName( const char *plaintextName_, const char *cipherName_, rDebug("calling setIV on %s", cipherName_); if(setIVFirst) { - if(externalIVChaining && !setIV(io, iv)) + if(fsConfig->config->externalIVChaining && !setIV(io, iv)) return false; // now change the name.. @@ -164,7 +151,7 @@ bool FileNode::setName( const char *plaintextName_, const char *cipherName_, io->setFileName( cipherName_ ); } - if(externalIVChaining && !setIV(io, iv)) + if(fsConfig->config->externalIVChaining && !setIV(io, iv)) { _pname = oldPName; _cname = oldCName; diff --git a/encfs/FileNode.h b/encfs/FileNode.h index 732c02e2..6ad954a0 100644 --- a/encfs/FileNode.h +++ b/encfs/FileNode.h @@ -20,6 +20,7 @@ #include "encfs.h" #include "CipherKey.h" +#include "FileUtils.h" #include #include @@ -33,18 +34,10 @@ using boost::shared_ptr; class FileNode { public: - FileNode(DirNode *parent, - int fsSubVersion, // version number for the filesystem - const char *plaintextName, - const char *cipherName, - const shared_ptr &cipher, const CipherKey &key, int blockSize, - int blockMACBytes, // per-block random bytes in header - int blockMACRandBytes, // per-block random bytes in header - bool uniqueIV, // enable per-file initialization vectors - bool externalIVChaining, - bool forceDecode, // decode, even if decoding errors are detected - bool reverseEncryption, - bool allowHoles ); + FileNode(DirNode *parent, + const FSConfigPtr &cfg, + const char *plaintextName, + const char *cipherName); ~FileNode(); const char *plaintextName() const; @@ -86,8 +79,8 @@ class FileNode // truncate() which may result in multiple calls down to the FileIO // level. mutable pthread_mutex_t mutex; - bool externalIVChaining; - bool reverseEncryption; + + FSConfigPtr fsConfig; shared_ptr io; std::string _pname; // plaintext name diff --git a/encfs/FileUtils.cpp b/encfs/FileUtils.cpp index 2b4ec709..b5077a68 100644 --- a/encfs/FileUtils.cpp +++ b/encfs/FileUtils.cpp @@ -29,6 +29,7 @@ #include "FileUtils.h" #include "ConfigReader.h" +#include "FSConfig.h" #include "DirNode.h" #include "Cipher.h" @@ -105,9 +106,11 @@ struct ConfigInfo const char *fileName; ConfigType type; const char *environmentOverride; - bool (*loadFunc)(const char *fileName, EncFSConfig *config, + bool (*loadFunc)(const char *fileName, + const boost::shared_ptr &config, ConfigInfo *cfg); - bool (*saveFunc)(const char *fileName, EncFSConfig *config); + bool (*saveFunc)(const char *fileName, + const boost::shared_ptr &config); int currentSubVersion; int defaultSubVersion; } ConfigFileMapping[] = { @@ -338,7 +341,7 @@ bool userAllowMkdir( const char *path, mode_t mode ) } ConfigType readConfig_load( ConfigInfo *nm, const char *path, - EncFSConfig *config ) + const boost::shared_ptr &config ) { if( nm->loadFunc ) { @@ -364,7 +367,8 @@ ConfigType readConfig_load( ConfigInfo *nm, const char *path, } } -ConfigType readConfig( const string &rootDir, EncFSConfig *config ) +ConfigType readConfig( const string &rootDir, + const boost::shared_ptr &config ) { ConfigInfo *nm = ConfigFileMapping; while(nm->fileName) @@ -387,7 +391,8 @@ ConfigType readConfig( const string &rootDir, EncFSConfig *config ) return Config_None; } -bool readV6Config( const char *configFile, EncFSConfig *config, +bool readV6Config( const char *configFile, + const boost::shared_ptr &config, ConfigInfo *info) { (void)info; @@ -413,7 +418,8 @@ bool readV6Config( const char *configFile, EncFSConfig *config, } } -bool readV5Config( const char *configFile, EncFSConfig *config, +bool readV5Config( const char *configFile, + const boost::shared_ptr &config, ConfigInfo *info) { bool ok = false; @@ -470,7 +476,8 @@ bool readV5Config( const char *configFile, EncFSConfig *config, return ok; } -bool readV4Config( const char *configFile, EncFSConfig *config, +bool readV4Config( const char *configFile, + const boost::shared_ptr &config, ConfigInfo *info) { bool ok = false; @@ -511,7 +518,7 @@ bool readV4Config( const char *configFile, EncFSConfig *config, } bool saveConfig( ConfigType type, const string &rootDir, - EncFSConfig *config ) + const boost::shared_ptr &config ) { bool ok = false; @@ -545,15 +552,14 @@ bool saveConfig( ConfigType type, const string &rootDir, return ok; } -bool writeV6Config( const char *configFile, EncFSConfig *config ) +bool writeV6Config( const char *configFile, + const boost::shared_ptr &config ) { fs::ofstream st( configFile ); if(!st.is_open()) return false; - boost::archive::xml_oarchive oa(st); - oa << BOOST_SERIALIZATION_NVP( config ); - + st << *config; return true; } @@ -573,7 +579,8 @@ std::istream &operator >> (std::istream &st, EncFSConfig &cfg) return st; } -bool writeV5Config( const char *configFile, EncFSConfig *config ) +bool writeV5Config( const char *configFile, + const boost::shared_ptr &config ) { ConfigReader cfg; @@ -595,7 +602,8 @@ bool writeV5Config( const char *configFile, EncFSConfig *config ) return cfg.save( configFile ); } -bool writeV4Config( const char *configFile, EncFSConfig *config ) +bool writeV4Config( const char *configFile, + const boost::shared_ptr &config ) { ConfigReader cfg; @@ -1114,25 +1122,25 @@ RootPtr createV6Config( EncFS_Context *ctx, const std::string &rootDir, alg.name.c_str(), keySize, blockSize); } - 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.salt.clear(); - config.kdfIterations = 0; // filled in by keying function - config.desiredKDFDuration = desiredKDFDuration; + 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) @@ -1140,7 +1148,7 @@ RootPtr createV6Config( EncFS_Context *ctx, const std::string &rootDir, "the following properties:") << endl; showFSInfo( config ); - if( config.externalIVChaining ) + if( config->externalIVChaining ) { cout << _("-------------------------- WARNING --------------------------\n") @@ -1170,16 +1178,16 @@ RootPtr createV6Config( EncFS_Context *ctx, const std::string &rootDir, CipherKey userKey; rDebug( "useStdin: %i", useStdin ); if(useStdin) - userKey = config.getUserKey( useStdin ); + userKey = config->getUserKey( useStdin ); else if(!passwordProgram.empty()) - userKey = config.getUserKey( passwordProgram, rootDir ); + userKey = config->getUserKey( passwordProgram, rootDir ); else - userKey = config.getNewUserKey(); + userKey = config->getNewUserKey(); cipher->writeKey( volumeKey, encodedKey, userKey ); userKey.reset(); - config.assignKeyData(encodedKey, encodedKeySize); + config->assignKeyData(encodedKey, encodedKeySize); delete[] encodedKey; if(!volumeKey) @@ -1189,11 +1197,11 @@ RootPtr createV6Config( EncFS_Context *ctx, const std::string &rootDir, return rootInfo; } - if(!saveConfig( Config_V6, rootDir, &config )) + if(!saveConfig( Config_V6, rootDir, config )) return rootInfo; // fill in config struct - shared_ptr nameCoder = NameIO::New( config.nameIface, + shared_ptr nameCoder = NameIO::New( config->nameIface, cipher, volumeKey ); if(!nameCoder) { @@ -1203,49 +1211,43 @@ RootPtr createV6Config( EncFS_Context *ctx, const std::string &rootDir, return rootInfo; } - nameCoder->setChainedNameIV( config.chainedNameIV ); + nameCoder->setChainedNameIV( config->chainedNameIV ); nameCoder->setReverseEncryption( reverseEncryption ); - shared_ptr dirNodeConfig (new DirNode::Config); - dirNodeConfig->cipher = cipher; - dirNodeConfig->key = volumeKey; - dirNodeConfig->nameCoding = nameCoder; - dirNodeConfig->fsSubVersion = config.subVersion; - dirNodeConfig->blockSize = blockSize; - dirNodeConfig->inactivityTimer = enableIdleTracking; - dirNodeConfig->blockMACBytes = config.blockMACBytes; - dirNodeConfig->blockMACRandBytes = config.blockMACRandBytes; - dirNodeConfig->uniqueIV = config.uniqueIV; - dirNodeConfig->externalIVChaining = config.externalIVChaining; - dirNodeConfig->forceDecode = forceDecode; - dirNodeConfig->reverseEncryption = reverseEncryption; - dirNodeConfig->allowHoles = config.allowHoles; + 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; rootInfo = RootPtr( new EncFS_Root ); rootInfo->cipher = cipher; rootInfo->volumeKey = volumeKey; rootInfo->root = shared_ptr( - new DirNode( ctx, rootDir, dirNodeConfig )); + new DirNode( ctx, rootDir, fsConfig )); return rootInfo; } -void showFSInfo( const EncFSConfig &config ) +void showFSInfo( const boost::shared_ptr &config ) { - shared_ptr cipher = Cipher::New( config.cipherIface, -1 ); + 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()); + 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() ) + if( config->cipherIface != cipher->interface() ) { Interface iface = cipher->interface(); // xgroup(diag) @@ -1258,11 +1260,11 @@ void showFSInfo( const EncFSConfig &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->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, + shared_ptr nameCoder = NameIO::New( config->nameIface, cipher, CipherKey() ); if(!nameCoder) { @@ -1271,7 +1273,7 @@ void showFSInfo( const EncFSConfig &config ) } else { // if we're using a newer interface, show the version number - if( config.nameIface != nameCoder->interface() ) + if( config->nameIface != nameCoder->interface() ) { Interface iface = nameCoder->interface(); cout << autosprintf(_(" (using %i:%i:%i)\n"), @@ -1281,8 +1283,8 @@ void showFSInfo( const EncFSConfig &config ) } } { - cout << autosprintf(_("Key Size: %i bits"), config.keySize); - cipher = config.getCipher(); + cout << autosprintf(_("Key Size: %i bits"), config->keySize); + cipher = config->getCipher(); if(!cipher) { // xgroup(diag) @@ -1290,54 +1292,54 @@ void showFSInfo( const EncFSConfig &config ) } else cout << "\n"; } - if(config.kdfIterations > 0 && config.salt.size() > 0) + if(config->kdfIterations > 0 && config->salt.size() > 0) { cout << autosprintf(_("Using PBKDF2, with %i iterations"), - config.kdfIterations) << "\n"; + config->kdfIterations) << "\n"; cout << autosprintf(_("Salt Size: %i bits"), - 8*(int)config.salt.size()) << "\n"; + 8*(int)config->salt.size()) << "\n"; } - if(config.blockMACBytes) + if(config->blockMACBytes) { - if(config.subVersion < 20040813) + if(config->subVersion < 20040813) { cout << autosprintf( // xgroup(diag) _("Block Size: %i bytes + %i byte MAC header"), - config.blockSize, - config.blockMACBytes + config.blockMACRandBytes) << endl; + 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; + config->blockSize, + config->blockMACBytes + config->blockMACRandBytes) << endl; } } else { // xgroup(diag) - cout << autosprintf(_("Block Size: %i bytes"), config.blockSize); + cout << autosprintf(_("Block Size: %i bytes"), config->blockSize); cout << "\n"; } - if(config.uniqueIV) + if(config->uniqueIV) { // xgroup(diag) cout << _("Each file contains 8 byte header with unique IV data.\n"); } - if(config.chainedNameIV) + if(config->chainedNameIV) { // xgroup(diag) cout << _("Filenames encoded using IV chaining mode.\n"); } - if(config.externalIVChaining) + if(config->externalIVChaining) { // xgroup(diag) cout << _("File data IV is chained to filename IV.\n"); } - if(config.allowHoles) + if(config->allowHoles) { // xgroup(diag) cout << _("File holes passed through to ciphertext.\n"); @@ -1359,16 +1361,12 @@ void EncFSConfig::assignKeyData(const std::string &in) void EncFSConfig::assignKeyData(unsigned char *data, int len) { - keyData.resize(len); - for(int i=0; i &opts ) { RootPtr rootInfo; - EncFSConfig config; + boost::shared_ptr config(new EncFSConfig); - if(readConfig( opts->rootDir, &config ) != Config_None) + if(readConfig( opts->rootDir, config ) != Config_None) { if(opts->reverseEncryption) { - if (config.blockMACBytes != 0 || config.blockMACRandBytes != 0 - || config.uniqueIV == true || config.externalIVChaining == true - || config.chainedNameIV == true ) + 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; @@ -1601,14 +1599,14 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) } // first, instanciate the cipher. - shared_ptr cipher = config.getCipher(); + 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()); + 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; @@ -1620,9 +1618,9 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) if(opts->passwordProgram.empty()) { rDebug( "useStdin: %i", opts->useStdin ); - userKey = config.getUserKey( opts->useStdin ); + userKey = config->getUserKey( opts->useStdin ); } else - userKey = config.getUserKey( opts->passwordProgram, opts->rootDir ); + userKey = config->getUserKey( opts->passwordProgram, opts->rootDir ); if(!userKey) return rootInfo; @@ -1630,7 +1628,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); + config->getKeyData(), userKey, opts->checkKey); userKey.reset(); if(!volumeKey) @@ -1640,43 +1638,37 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) return rootInfo; } - shared_ptr nameCoder = NameIO::New( config.nameIface, + 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()); + 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->setChainedNameIV( config->chainedNameIV ); nameCoder->setReverseEncryption( opts->reverseEncryption ); - shared_ptr dirNodeConfig (new DirNode::Config); - dirNodeConfig->cipher = cipher; - dirNodeConfig->key = volumeKey; - dirNodeConfig->nameCoding = nameCoder; - dirNodeConfig->fsSubVersion = config.subVersion; - dirNodeConfig->blockSize = config.blockSize; - dirNodeConfig->inactivityTimer = opts->idleTracking; - dirNodeConfig->blockMACBytes = config.blockMACBytes; - dirNodeConfig->blockMACRandBytes = config.blockMACRandBytes; - dirNodeConfig->uniqueIV = config.uniqueIV; - dirNodeConfig->externalIVChaining = config.externalIVChaining; - dirNodeConfig->forceDecode = opts->forceDecode; - dirNodeConfig->reverseEncryption = 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->forceDecode; rootInfo = RootPtr( new EncFS_Root ); rootInfo->cipher = cipher; rootInfo->volumeKey = volumeKey; rootInfo->root = shared_ptr( - new DirNode( ctx, opts->rootDir, dirNodeConfig )); + new DirNode( ctx, opts->rootDir, fsConfig )); } else { if(opts->createIfNotFound) diff --git a/encfs/FileUtils.h b/encfs/FileUtils.h index 85bffaa3..cc160f5a 100644 --- a/encfs/FileUtils.h +++ b/encfs/FileUtils.h @@ -20,8 +20,8 @@ #include "encfs.h" #include "Interface.h" -#include "DirNode.h" #include "CipherKey.h" +#include "FSConfig.h" // true if the path points to an existing node (of any type) bool fileExists( const char *fileName ); @@ -38,85 +38,8 @@ std::string parentDirectory( const std::string &path ); // do it and return true. bool userAllowMkdir( const char *dirPath, mode_t mode ); -enum ConfigType -{ - Config_None = 0, - Config_Prehistoric, - Config_V3, - Config_V4, - Config_V5, - Config_V6 -}; - -struct EncFSConfig -{ - ConfigType cfgType; - - 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(); - - shared_ptr getCipher() const; - - // 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); -}; - -std::ostream &operator << (std::ostream &os, const EncFSConfig &cfg); -std::istream &operator >> (std::istream &os, EncFSConfig &cfg); - class Cipher; +class DirNode; struct EncFS_Root { @@ -130,18 +53,6 @@ struct EncFS_Root typedef boost::shared_ptr RootPtr; -/* - Read existing config file. Looks for any supported configuration version. -*/ -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, - EncFSConfig *config ); - enum ConfigMode { Config_Prompt, @@ -170,21 +81,34 @@ struct EncFS_Opts EncFS_Opts() { - createIfNotFound = true; - idleTracking = false; - mountOnDemand = false; - checkKey = true; - forceDecode = false; - useStdin = false; - ownerCreate = false; - reverseEncryption = false; + createIfNotFound = true; + idleTracking = false; + mountOnDemand = false; + checkKey = true; + forceDecode = false; + useStdin = 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 ); + +/* + 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 ); + class EncFS_Context; -RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ); +RootPtr initFS( EncFS_Context *ctx, const boost::shared_ptr &opts ); RootPtr createV6Config( EncFS_Context *ctx, const std::string &rootDir, bool enableIdleTracking, @@ -193,18 +117,24 @@ RootPtr createV6Config( EncFS_Context *ctx, const std::string &rootDir, bool allowHoles, ConfigMode mode ); -void showFSInfo( const EncFSConfig &config ); +void showFSInfo( const boost::shared_ptr &config ); -bool readV4Config( const char *configFile, EncFSConfig *config, +bool readV4Config( const char *configFile, + const boost::shared_ptr &config, struct ConfigInfo *); -bool writeV4Config( const char *configFile, EncFSConfig *config); +bool writeV4Config( const char *configFile, + const boost::shared_ptr &config); -bool readV5Config( const char *configFile, EncFSConfig *config, +bool readV5Config( const char *configFile, + const boost::shared_ptr &config, struct ConfigInfo *); -bool writeV5Config( const char *configFile, EncFSConfig *config); +bool writeV5Config( const char *configFile, + const boost::shared_ptr &config); -bool readV6Config( const char *configFile, EncFSConfig *config, +bool readV6Config( const char *configFile, + const boost::shared_ptr &config, struct ConfigInfo *); -bool writeV6Config( const char *configFile, EncFSConfig *config); +bool writeV6Config( const char *configFile, + const boost::shared_ptr &config); #endif diff --git a/encfs/MACFileIO.cpp b/encfs/MACFileIO.cpp index bb347607..5cee7dfc 100644 --- a/encfs/MACFileIO.cpp +++ b/encfs/MACFileIO.cpp @@ -18,6 +18,7 @@ #include "MACFileIO.h" #include "MemoryPool.h" +#include "FileUtils.h" #include #include @@ -48,23 +49,29 @@ static RLogChannel *Info = DEF_CHANNEL("info/MACFileIO", Log_Info); // static rel::Interface MACFileIO_iface("FileIO/MAC", 2, 0, 0); +int dataBlockSize(const FSConfigPtr &cfg) +{ + return cfg->config->blockSize + - cfg->config->blockMACBytes + - cfg->config->blockMACRandBytes; +} + MACFileIO::MACFileIO( const shared_ptr &_base, - const shared_ptr &_cipher, - const CipherKey &_key, int fsBlockSize, - int _macBytes, int _randBytes, - bool warnOnlyMode ) - : BlockFileIO( fsBlockSize - _macBytes - _randBytes ) + const FSConfigPtr &cfg ) + : BlockFileIO( dataBlockSize( cfg ), cfg ) , base( _base ) - , cipher( _cipher ) - , key( _key ) - , macBytes( _macBytes ) - , randBytes( _randBytes ) - , warnOnly( warnOnlyMode ) + , cipher( cfg->cipher ) + , key( cfg->key ) + , macBytes( cfg->config->blockMACBytes ) + , randBytes( cfg->config->blockMACRandBytes ) + , warnOnly( cfg->opts->forceDecode ) { rAssert( macBytes > 0 && macBytes <= 8 ); rAssert( randBytes >= 0 ); rLog(Info, "fs block size = %i, macBytes = %i, randBytes = %i", - fsBlockSize, macBytes, randBytes); + cfg->config->blockSize, + cfg->config->blockMACBytes, + cfg->config->blockMACRandBytes); } MACFileIO::~MACFileIO() @@ -159,14 +166,6 @@ off_t MACFileIO::getSize() const return size; } -void MACFileIO::allowHoles( bool allow ) -{ - BlockFileIO::allowHoles( allow ); - shared_ptr bf = dynamic_pointer_cast( base ); - if(bf) - bf->allowHoles( allow ); -} - ssize_t MACFileIO::readOneBlock( const IORequest &req ) const { int headerSize = macBytes + randBytes; diff --git a/encfs/MACFileIO.h b/encfs/MACFileIO.h index 75fa01ce..46573a6b 100644 --- a/encfs/MACFileIO.h +++ b/encfs/MACFileIO.h @@ -32,10 +32,7 @@ class MACFileIO : public BlockFileIO be made available.. */ MACFileIO( const shared_ptr &base, - const shared_ptr &cipher, - const CipherKey &key, int blockSize, - int macBytes, int randBytes, - bool warnOnlyMode ); + const FSConfigPtr &cfg ); MACFileIO(); virtual ~MACFileIO(); @@ -53,8 +50,6 @@ class MACFileIO : public BlockFileIO virtual bool isWritable() const; - virtual void allowHoles( bool allow ); - private: virtual ssize_t readOneBlock( const IORequest &req ) const; virtual bool writeOneBlock( const IORequest &req ); diff --git a/encfs/Makefile.am b/encfs/Makefile.am index 49fdecf0..7dd9ebee 100644 --- a/encfs/Makefile.am +++ b/encfs/Makefile.am @@ -47,7 +47,7 @@ endif # : : 0 => no new interfaces, but breaks old apps # : +1 : => internal changes, nothing breaks # -libencfs_la_LDFLAGS = -version-info 5:0:2 +libencfs_la_LDFLAGS = -version-info 6:0:0 libencfs_la_LIBADD = @RLOG_LIBS@ \ @OPENSSL_LIBS@ \ @BOOST_SERIALIZATION_LIB@ @BOOST_FILESYSTEM_LIB@ @BOOST_SYSTEM_LIB@ @@ -101,6 +101,7 @@ encfsctl_SOURCES = \ noinst_HEADERS = \ base64.h \ + boost-versioning.h \ BlockFileIO.h \ BlockNameIO.h \ CipherFileIO.h \ diff --git a/encfs/SSL_Cipher.cpp b/encfs/SSL_Cipher.cpp index 14ec041b..a6e9290c 100644 --- a/encfs/SSL_Cipher.cpp +++ b/encfs/SSL_Cipher.cpp @@ -173,8 +173,9 @@ int TimedPBKDF2(const char *pass, int passlen, // 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 -static Interface BlowfishInterface( "ssl/blowfish", 2, 2, 1 ); -static Interface AESInterface( "ssl/aes", 2, 2, 1 ); +// - Version 3:0 adds a new IV mechanism +static Interface BlowfishInterface( "ssl/blowfish", 3, 0, 2 ); +static Interface AESInterface( "ssl/aes", 3, 0, 2 ); #if defined(HAVE_EVP_BF) @@ -399,13 +400,6 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength, int &iterationCount, long desiredDuration, const unsigned char *salt, int saltLen) { - const EVP_MD *md = EVP_sha1(); - if(!md) - { - rError("Unknown digest SHA1"); - return CipherKey(); - } - shared_ptr key( new SSLKey( _keySize, _ivLength) ); if(iterationCount == 0) @@ -441,13 +435,6 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength, CipherKey SSL_Cipher::newKey(const char *password, int passwdLength) { - const EVP_MD *md = EVP_sha1(); - if(!md) - { - rError("Unknown digest SHA1"); - return CipherKey(); - } - shared_ptr key( new SSLKey( _keySize, _ivLength) ); int bytes = 0; @@ -545,7 +532,7 @@ static uint64_t _checksum_64( SSLKey *key, HMAC_Final( &key->mac_ctx, md, &mdLen ); - rAssert(mdLen != 0); + rAssert(mdLen >= 8); // chop this down to a 64bit value.. unsigned char h[8] = {0,0,0,0,0,0,0,0}; @@ -690,8 +677,45 @@ int SSL_Cipher::cipherBlockSize() const return EVP_CIPHER_block_size( _blockCipher ); } -void SSL_Cipher::setIVec( unsigned char *ivec, unsigned int seed, +void SSL_Cipher::setIVec( unsigned char *ivec, uint64_t seed, const shared_ptr &key) const +{ + if (iface.current() >= 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); + } +} + +/** For backward compatibility. + 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 { /* These multiplication constants chosen as they represent (non optimal) Golumb rulers, the idea being to spread around the information in the diff --git a/encfs/SSL_Cipher.h b/encfs/SSL_Cipher.h index 595bae9d..cb5ab4a4 100644 --- a/encfs/SSL_Cipher.h +++ b/encfs/SSL_Cipher.h @@ -137,8 +137,12 @@ class SSL_Cipher : public Cipher // hack to help with static builds static bool Enabled(); private: - void setIVec( unsigned char *ivec, unsigned int seed, + 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; }; diff --git a/encfs/encfsctl.cpp b/encfs/encfsctl.cpp index 1d66ded8..f2f8d523 100644 --- a/encfs/encfsctl.cpp +++ b/encfs/encfsctl.cpp @@ -25,6 +25,8 @@ #include "Cipher.h" #include "Context.h" +#include "FileNode.h" +#include "DirNode.h" #include #include @@ -174,8 +176,8 @@ static int showInfo( int argc, char **argv ) if( !checkDir( rootDir )) return EXIT_FAILURE; - EncFSConfig config; - ConfigType type = readConfig( rootDir, &config ); + boost::shared_ptr config(new EncFSConfig); + ConfigType type = readConfig( rootDir, config ); // show information stored in config.. switch(type) @@ -192,24 +194,24 @@ 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); + "created by %s (revision %i)\n"), config->creator.c_str(), + config->subVersion); break; case Config_V6: // xgroup(diag) cout << "\n" << autosprintf(_("Version 6 configuration; " - "created by %s (revision %i)\n"), config.creator.c_str(), - config.subVersion); + "created by %s (revision %i)\n"), config->creator.c_str(), + config->subVersion); break; } @@ -698,8 +700,8 @@ static int do_chpasswd( bool useStdin, int argc, char **argv ) if( !checkDir( rootDir )) return EXIT_FAILURE; - EncFSConfig config; - ConfigType cfgType = readConfig( rootDir, &config ); + boost::shared_ptr config(new EncFSConfig); + ConfigType cfgType = readConfig( rootDir, config ); if(cfgType == Config_None) { @@ -709,23 +711,23 @@ static int do_chpasswd( bool useStdin, int argc, char **argv ) // instanciate proper cipher shared_ptr cipher = Cipher::New( - config.cipherIface, config.keySize ); + config->cipherIface, config->keySize ); if(!cipher) { cout << autosprintf(_("Unable to find specified cipher \"%s\"\n"), - config.cipherIface.name().c_str()); + config->cipherIface.name().c_str()); return EXIT_FAILURE; } // ask for existing password cout << _("Enter current Encfs password\n"); - CipherKey userKey = config.getUserKey( useStdin ); + CipherKey userKey = config->getUserKey( 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( config->getKeyData(), userKey ); if(!volumeKey) { @@ -737,12 +739,12 @@ static int do_chpasswd( bool useStdin, int argc, char **argv ) userKey.reset(); cout << _("Enter new Encfs password\n"); // reinitialize salt and iteration count - config.kdfIterations = 0; // generate new + config->kdfIterations = 0; // generate new if( useStdin ) - userKey = config.getUserKey( true ); + userKey = config->getUserKey( true ); else - userKey = config.getNewUserKey(); + userKey = config->getNewUserKey(); // re-encode the volume key using the new user key and write it out.. int result = EXIT_FAILURE; @@ -755,10 +757,10 @@ static int do_chpasswd( bool useStdin, int argc, char **argv ) cipher->writeKey( volumeKey, keyBuf, userKey ); userKey.reset(); - config.assignKeyData( keyBuf, encodedKeySize ); + config->assignKeyData( keyBuf, encodedKeySize ); delete[] keyBuf; - if(saveConfig( cfgType, rootDir, &config )) + if(saveConfig( cfgType, rootDir, config )) { // password modified -- changes volume key of filesystem.. cout << _("Volume Key successfully updated.\n"); diff --git a/encfs/test.cpp b/encfs/test.cpp index 2fd4ea7e..ed11b189 100644 --- a/encfs/test.cpp +++ b/encfs/test.cpp @@ -257,23 +257,24 @@ bool runTests(const shared_ptr &cipher, bool verbose) } } - shared_ptr dnConfig( new DirNode::Config ); - dnConfig->cipher = cipher; - dnConfig->key = key; - dnConfig->blockSize = FSBlockSize; + FSConfigPtr fsCfg = FSConfigPtr(new FSConfig); + fsCfg->cipher = cipher; + fsCfg->key = key; + fsCfg->config.reset(new EncFSConfig); + fsCfg->config->blockSize = FSBlockSize; if(verbose) cerr << "Testing name encode/decode (stream coding w/ IV chaining)\n"; { - dnConfig->inactivityTimer = false; - dnConfig->blockMACBytes = 0; - dnConfig->blockMACRandBytes = 0; - dnConfig->uniqueIV = false; - dnConfig->nameCoding = shared_ptr( new StreamNameIO( + fsCfg->opts.reset(new EncFS_Opts); + fsCfg->opts->idleTracking = false; + fsCfg->config->uniqueIV = false; + + fsCfg->nameCoding.reset( new StreamNameIO( StreamNameIO::CurrentInterface(), cipher, key ) ); - dnConfig->nameCoding->setChainedNameIV( true ); + fsCfg->nameCoding->setChainedNameIV( true ); - DirNode dirNode( NULL, TEST_ROOTDIR, dnConfig ); + DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); if(!testNameCoding( dirNode, verbose )) return false; @@ -282,16 +283,14 @@ bool runTests(const shared_ptr &cipher, bool verbose) if(verbose) cerr << "Testing name encode/decode (block coding w/ IV chaining)\n"; { - dnConfig->inactivityTimer = false; - dnConfig->blockMACBytes = 0; - dnConfig->blockMACRandBytes = 0; - dnConfig->uniqueIV = false; - dnConfig->nameCoding = shared_ptr( new BlockNameIO( + fsCfg->opts->idleTracking = false; + fsCfg->config->uniqueIV = false; + fsCfg->nameCoding.reset( new BlockNameIO( BlockNameIO::CurrentInterface(), cipher, key, cipher->cipherBlockSize() ) ); - dnConfig->nameCoding->setChainedNameIV( true ); + fsCfg->nameCoding->setChainedNameIV( true ); - DirNode dirNode( NULL, TEST_ROOTDIR, dnConfig ); + DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); if(!testNameCoding( dirNode, verbose )) return false; @@ -301,16 +300,12 @@ bool runTests(const shared_ptr &cipher, bool verbose) { { // test stream mode, this time without IV chaining - dnConfig->inactivityTimer = false; - dnConfig->blockMACBytes = 0; - dnConfig->blockMACRandBytes = 0; - dnConfig->uniqueIV = false; - dnConfig->nameCoding = + fsCfg->nameCoding = shared_ptr( new StreamNameIO( StreamNameIO::CurrentInterface(), cipher, key ) ); - dnConfig->nameCoding->setChainedNameIV( false ); + fsCfg->nameCoding->setChainedNameIV( false ); - DirNode dirNode( NULL, TEST_ROOTDIR, dnConfig ); + DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); if(!testNameCoding( dirNode, verbose )) return false; @@ -318,16 +313,12 @@ bool runTests(const shared_ptr &cipher, bool verbose) { // test block mode, this time without IV chaining - dnConfig->inactivityTimer = false; - dnConfig->blockMACBytes = 0; - dnConfig->blockMACRandBytes = 0; - dnConfig->uniqueIV = false; - dnConfig->nameCoding = shared_ptr( new BlockNameIO( + fsCfg->nameCoding = shared_ptr( new BlockNameIO( BlockNameIO::CurrentInterface(), cipher, key, cipher->cipherBlockSize() ) ); - dnConfig->nameCoding->setChainedNameIV( false ); + fsCfg->nameCoding->setChainedNameIV( false ); - DirNode dirNode( NULL, TEST_ROOTDIR, dnConfig ); + DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); if(!testNameCoding( dirNode, verbose )) return false; diff --git a/m4/Makefile.am b/m4/Makefile.am index 62e15007..08de7f1b 100644 --- a/m4/Makefile.am +++ b/m4/Makefile.am @@ -1,9 +1,8 @@ EXTRA_DIST = \ - codeset.m4 inttypes_h.m4 lib-link.m4 printf-posix.m4 \ - ulonglong.m4 gettext.m4 inttypes.m4 lib-prefix.m4 \ - progtest.m4 wchar_t.m4 glibc21.m4 inttypes-pri.m4 \ - longdouble.m4 signed.m4 wint_t.m4 iconv.m4 isc-posix.m4 \ - longlong.m4 size_max.m4 xsize.m4 intdiv0.m4 lcmessage.m4 \ - nls.m4 stdint_h.m4 intmax.m4 lib-ld.m4 po.m4 uintmax_t.m4 \ - acx_pthread.m4 - + acx_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/makedist2.sh.in b/makedist2.sh.in index 7c8dd46c..8034705e 100644 --- a/makedist2.sh.in +++ b/makedist2.sh.in @@ -4,7 +4,7 @@ make dist # create tar archive and signature -tarArchive=@PACKAGE@-@VERSION@-@RELEASE@.tgz +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";