reformat with clang-format -style=Google

git-svn-id: http://encfs.googlecode.com/svn/trunk@121 db9cf616-1c43-0410-9cb8-a902689de0d6
This commit is contained in:
Valient Gough 2013-10-19 22:35:26 +00:00
parent 154ce001a1
commit a89752dfe7
92 changed files with 4420 additions and 6245 deletions

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -36,90 +36,75 @@ using std::string;
namespace encfs { namespace encfs {
ConfigReader::ConfigReader() ConfigReader::ConfigReader() {}
{
}
ConfigReader::~ConfigReader() ConfigReader::~ConfigReader() {}
{
}
// read the entire file into a ConfigVar instance and then use that to decode // read the entire file into a ConfigVar instance and then use that to decode
// into mapped variables. // into mapped variables.
bool ConfigReader::load(const char *fileName) bool ConfigReader::load(const char *fileName) {
{
struct stat stbuf; struct stat stbuf;
memset( &stbuf, 0, sizeof(struct stat)); memset(&stbuf, 0, sizeof(struct stat));
if( lstat( fileName, &stbuf ) != 0) if (lstat(fileName, &stbuf) != 0) return false;
return false;
int size = stbuf.st_size; int size = stbuf.st_size;
int fd = open( fileName, O_RDONLY ); int fd = open(fileName, O_RDONLY);
if(fd < 0) if (fd < 0) return false;
return false;
char *buf = new char[size]; char *buf = new char[size];
int res = ::read( fd, buf, size ); int res = ::read(fd, buf, size);
close( fd ); close(fd);
if( res != size ) if (res != size) {
{ LOG(WARNING) << "Partial read of config file, expecting " << size
LOG(WARNING) << "Partial read of config file, expecting " << " bytes, got " << res;
<< size << " bytes, got " << res;
delete[] buf; delete[] buf;
return false; return false;
} }
ConfigVar in; ConfigVar in;
in.write( (byte *)buf, size ); in.write((byte *)buf, size);
delete[] buf; delete[] buf;
return loadFromVar( in ); return loadFromVar(in);
} }
bool ConfigReader::loadFromVar(ConfigVar &in) bool ConfigReader::loadFromVar(ConfigVar &in) {
{
in.resetOffset(); in.resetOffset();
// parse. // parse.
int numEntries = in.readInt(); int numEntries = in.readInt();
for(int i=0; i<numEntries; ++i) for (int i = 0; i < numEntries; ++i) {
{
string key, value; string key, value;
in >> key >> value; in >> key >> value;
if(key.length() == 0) if (key.length() == 0) {
{
LOG(ERROR) << "Invalid key encoding in buffer"; LOG(ERROR) << "Invalid key encoding in buffer";
return false; return false;
} }
ConfigVar newVar( value ); ConfigVar newVar(value);
vars.insert( make_pair( key, newVar ) ); vars.insert(make_pair(key, newVar));
} }
return true; 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 // write everything to a ConfigVar, then output to disk
ConfigVar out = toVar(); ConfigVar out = toVar();
int fd = ::open( fileName, O_RDWR | O_CREAT, 0640 ); int fd = ::open(fileName, O_RDWR | O_CREAT, 0640);
if(fd >= 0) if (fd >= 0) {
{ int retVal = ::write(fd, out.buffer(), out.size());
int retVal = ::write( fd, out.buffer(), out.size() ); close(fd);
close( fd ); if (retVal != out.size()) {
if(retVal != out.size())
{
LOG(ERROR) << "Error writing to config file " << fileName; LOG(ERROR) << "Error writing to config file " << fileName;
return false; return false;
} }
} else } else {
{
LOG(ERROR) << "Unable to open or create file " << fileName; LOG(ERROR) << "Unable to open or create file " << fileName;
return false; return false;
} }
@ -127,36 +112,32 @@ bool ConfigReader::save(const char *fileName) const
return true; return true;
} }
ConfigVar ConfigReader::toVar() const ConfigVar ConfigReader::toVar() const {
{
// write everything to a ConfigVar, then output to disk // write everything to a ConfigVar, then output to disk
ConfigVar out; ConfigVar out;
out.writeInt( vars.size() ); out.writeInt(vars.size());
map<string, ConfigVar>::const_iterator it; map<string, ConfigVar>::const_iterator it;
for(it = vars.begin(); it != vars.end(); ++it) for (it = vars.begin(); it != vars.end(); ++it) {
{ out.writeInt(it->first.size());
out.writeInt( it->first.size() ); out.write((byte *)it->first.data(), it->first.size());
out.write( (byte*)it->first.data(), it->first.size() ); out.writeInt(it->second.size());
out.writeInt( it->second.size() ); out.write((byte *)it->second.buffer(), it->second.size());
out.write( (byte*)it->second.buffer(), it->second.size() );
} }
return out; return out;
} }
ConfigVar ConfigReader::operator[] ( const std::string &varName ) const ConfigVar ConfigReader::operator[](const std::string &varName) const {
{
// read only // read only
map<string, ConfigVar>::const_iterator it = vars.find( varName ); map<string, ConfigVar>::const_iterator it = vars.find(varName);
if( it == vars.end() ) if (it == vars.end())
return ConfigVar(); return ConfigVar();
else else
return it->second; return it->second;
} }
ConfigVar &ConfigReader::operator[] ( const std::string &varName ) ConfigVar &ConfigReader::operator[](const std::string &varName) {
{ return vars[varName];
return vars[ varName ];
} }
} // namespace encfs } // namespace encfs

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * 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 * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _ConfigReader_incl_ #ifndef _ConfigReader_incl_
#define _ConfigReader_incl_ #define _ConfigReader_incl_
@ -45,26 +45,24 @@ namespace encfs {
ConfigReader cfg; ConfigReader cfg;
cfg["cipher"] << cipher->interface(); cfg["cipher"] << cipher->interface();
*/ */
class ConfigReader class ConfigReader {
{ public:
public: ConfigReader();
ConfigReader(); ~ConfigReader();
~ConfigReader();
bool load(const char *fileName); bool load(const char *fileName);
bool save(const char *fileName) const; bool save(const char *fileName) const;
ConfigVar toVar() const; ConfigVar toVar() const;
bool loadFromVar( ConfigVar &var ); bool loadFromVar(ConfigVar &var);
ConfigVar operator[](const std::string &varName) const; ConfigVar operator[](const std::string &varName) const;
ConfigVar &operator[](const std::string &varName); ConfigVar &operator[](const std::string &varName);
private: private:
std::map<std::string, ConfigVar> vars; std::map<std::string, ConfigVar> vars;
}; };
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -27,39 +27,22 @@
namespace encfs { namespace encfs {
#ifndef MIN #ifndef MIN
inline int MIN(int a, int b) inline int MIN(int a, int b) { return (a < b) ? a : b; }
{
return (a < b) ? a : b;
}
#endif #endif
ConfigVar::ConfigVar() : pd(new ConfigVarData) { pd->offset = 0; }
ConfigVar::ConfigVar() ConfigVar::ConfigVar(const std::string &buf) : pd(new ConfigVarData) {
: pd( new ConfigVarData )
{
pd->offset = 0;
}
ConfigVar::ConfigVar(const std::string &buf)
: pd( new ConfigVarData )
{
pd->buffer = buf; pd->buffer = buf;
pd->offset = 0; pd->offset = 0;
} }
ConfigVar::ConfigVar(const ConfigVar &src) ConfigVar::ConfigVar(const ConfigVar &src) { pd = src.pd; }
{
pd = src.pd;
}
ConfigVar::~ConfigVar() ConfigVar::~ConfigVar() { pd.reset(); }
{
pd.reset();
}
ConfigVar & ConfigVar::operator = (const ConfigVar &src) ConfigVar &ConfigVar::operator=(const ConfigVar &src) {
{ if (src.pd == pd)
if(src.pd == pd)
return *this; return *this;
else else
pd = src.pd; pd = src.pd;
@ -67,31 +50,23 @@ ConfigVar & ConfigVar::operator = (const ConfigVar &src)
return *this; return *this;
} }
void ConfigVar::resetOffset() void ConfigVar::resetOffset() { pd->offset = 0; }
{
pd->offset = 0;
}
int ConfigVar::read(byte *buffer_, int bytes) const int ConfigVar::read(byte *buffer_, int bytes) const {
{ int toCopy = MIN(bytes, pd->buffer.size() - pd->offset);
int toCopy = MIN( bytes, pd->buffer.size() - pd->offset );
if(toCopy > 0) if (toCopy > 0) memcpy(buffer_, pd->buffer.data() + pd->offset, toCopy);
memcpy( buffer_, pd->buffer.data() + pd->offset, toCopy );
pd->offset += toCopy; pd->offset += toCopy;
return toCopy; return toCopy;
} }
int ConfigVar::write(const byte *data, int bytes) int ConfigVar::write(const byte *data, int bytes) {
{ if (pd->buffer.size() == (unsigned int)pd->offset) {
if(pd->buffer.size() == (unsigned int)pd->offset) pd->buffer.append((const char *)data, bytes);
{ } else {
pd->buffer.append( (const char *)data, bytes ); pd->buffer.insert(pd->offset, (const char *)data, bytes);
} else
{
pd->buffer.insert( pd->offset, (const char *)data, bytes );
} }
pd->offset += bytes; pd->offset += bytes;
@ -99,31 +74,19 @@ int ConfigVar::write(const byte *data, int bytes)
return bytes; return bytes;
} }
int ConfigVar::size() const int ConfigVar::size() const { return pd->buffer.size(); }
{
return pd->buffer.size();
}
const char *ConfigVar::buffer() const const char *ConfigVar::buffer() const { return pd->buffer.data(); }
{
return pd->buffer.data();
}
int ConfigVar::at() const int ConfigVar::at() const { return pd->offset; }
{
return pd->offset;
}
void ConfigVar::writeString(const char *data, int bytes) void ConfigVar::writeString(const char *data, int bytes) {
{ writeInt(bytes);
writeInt( bytes ); write((const byte *)data, bytes);
write( (const byte *)data, bytes );
} }
// convert integer to BER encoded integer // 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 // we can represent 7 bits per char output, so a 32bit number may take up
// to 5 bytes. // to 5 bytes.
// first byte: 0x0000007f 0111,1111 // first byte: 0x0000007f 0111,1111
@ -133,7 +96,7 @@ void ConfigVar::writeInt(int val)
// fifth byte: 0xf0000000 1111,0000 // fifth byte: 0xf0000000 1111,0000
byte digit[5]; byte digit[5];
digit[4] = (byte)((val & 0x0000007f)); digit[4] = (byte)((val & 0x0000007f));
digit[3] = 0x80 | (byte)((val & 0x00003f80) >> 7); digit[3] = 0x80 | (byte)((val & 0x00003f80) >> 7);
digit[2] = 0x80 | (byte)((val & 0x001fc000) >> 14); digit[2] = 0x80 | (byte)((val & 0x001fc000) >> 14);
digit[1] = 0x80 | (byte)((val & 0x0fe00000) >> 21); 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 // find the starting point - we only need to output starting at the most
// significant non-zero digit.. // significant non-zero digit..
int start = 0; int start = 0;
while(digit[start] == 0x80) while (digit[start] == 0x80) ++start;
++start;
write( digit + start, 5-start ); write(digit + start, 5 - start);
} }
int ConfigVar::readInt() const int ConfigVar::readInt() const {
{ const byte *buf = (const byte *)buffer();
const byte * buf = (const byte *)buffer();
int bytes = this->size(); int bytes = this->size();
int offset = at(); int offset = at();
int value = 0; int value = 0;
bool highBitSet; bool highBitSet;
rAssert( offset < bytes ); rAssert(offset < bytes);
do do {
{
byte tmp = buf[offset++]; byte tmp = buf[offset++];
highBitSet = tmp & 0x80; highBitSet = tmp & 0x80;
value = (value << 7) | (int)(tmp & 0x7f); value = (value << 7) | (int)(tmp & 0x7f);
} while(highBitSet && offset < bytes); } while (highBitSet && offset < bytes);
pd->offset = offset; pd->offset = offset;
// should never end up with a negative number.. // should never end up with a negative number..
rAssert( value >= 0 ); rAssert(value >= 0);
return value; return value;
} }
int ConfigVar::readInt( int defaultValue ) const int ConfigVar::readInt(int defaultValue) const {
{
int bytes = this->size(); int bytes = this->size();
int offset = at(); int offset = at();
if(offset >= bytes) if (offset >= bytes)
return defaultValue; return defaultValue;
else else
return readInt(); return readInt();
} }
bool ConfigVar::readBool( bool defaultValue ) const bool ConfigVar::readBool(bool defaultValue) const {
{ int tmp = readInt(defaultValue ? 1 : 0);
int tmp = readInt( defaultValue ? 1 : 0 );
return (tmp != 0); return (tmp != 0);
} }
ConfigVar & operator << (ConfigVar &src, bool value) ConfigVar &operator<<(ConfigVar &src, bool value) {
{ src.writeInt(value ? 1 : 0);
src.writeInt( value ? 1 : 0 );
return src; return src;
} }
ConfigVar & operator << (ConfigVar &src, int var) ConfigVar &operator<<(ConfigVar &src, int var) {
{ src.writeInt(var);
src.writeInt( var );
return src; return src;
} }
ConfigVar & operator << (ConfigVar &src, const std::string &str) ConfigVar &operator<<(ConfigVar &src, const std::string &str) {
{ src.writeString(str.data(), str.length());
src.writeString( str.data(), str.length() );
return src; return src;
} }
const ConfigVar & operator >> (const ConfigVar &src, bool &result) const ConfigVar &operator>>(const ConfigVar &src, bool &result) {
{
int tmp = src.readInt(); int tmp = src.readInt();
result = (tmp != 0); result = (tmp != 0);
return src; return src;
} }
const ConfigVar & operator >> (const ConfigVar &src, int &result) const ConfigVar &operator>>(const ConfigVar &src, int &result) {
{
result = src.readInt(); result = src.readInt();
return src; return src;
} }
const ConfigVar & operator >> (const ConfigVar &src, std::string &result) const ConfigVar &operator>>(const ConfigVar &src, std::string &result) {
{
int length = src.readInt(); int length = src.readInt();
LOG_IF(WARNING, length <= 0) << "Invalid config length " << length; LOG_IF(WARNING, length <= 0) << "Invalid config length " << length;
int readLen; int readLen;
byte tmpBuf[32]; byte tmpBuf[32];
if(length > (int)sizeof(tmpBuf)) if (length > (int)sizeof(tmpBuf)) {
{
byte *ptr = new byte[length]; byte *ptr = new byte[length];
readLen = src.read( ptr, length ); readLen = src.read(ptr, length);
result.assign( (char*)ptr, length ); result.assign((char *)ptr, length);
delete[] ptr; delete[] ptr;
} else } else {
{ readLen = src.read(tmpBuf, length);
readLen = src.read( tmpBuf, length ); result.assign((char *)tmpBuf, length);
result.assign( (char*)tmpBuf, length );
} }
if(readLen != length) if (readLen != length) {
{ VLOG(1) << "string encoded as size " << length << " bytes, read "
VLOG(1) << "string encoded as size " << length << readLen;
<< " bytes, read " << readLen;
} }
rAssert(readLen == length); rAssert(readLen == length);

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -27,60 +27,57 @@
namespace encfs { namespace encfs {
class ConfigVar class ConfigVar {
{ struct ConfigVarData {
struct ConfigVarData std::string buffer;
{ int offset;
std::string buffer; };
int offset;
};
shared_ptr<ConfigVarData> pd; shared_ptr<ConfigVarData> pd;
public: public:
ConfigVar(); ConfigVar();
ConfigVar(const std::string &buffer); ConfigVar(const std::string &buffer);
ConfigVar(const ConfigVar &src); ConfigVar(const ConfigVar &src);
~ConfigVar(); ~ConfigVar();
ConfigVar & operator = (const ConfigVar &src); ConfigVar &operator=(const ConfigVar &src);
// reset read/write offset.. // reset read/write offset..
void resetOffset(); void resetOffset();
// read bytes // read bytes
int read(byte *buffer, int size) const; int read(byte *buffer, int size) const;
// write bytes.. // write bytes..
int write(const byte *data, int size); int write(const byte *data, int size);
int readInt() const; int readInt() const;
int readInt( int defaultValue ) const; int readInt(int defaultValue) const;
void writeInt(int value); 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 // return amount of data in var
int size() const; int size() const;
// return data pointer - returns front of data pointer, not the current // return data pointer - returns front of data pointer, not the current
// position. // position.
const char *buffer() const; const char *buffer() const;
// return current position in data() buffer. // return current position in data() buffer.
int at() const; int at() const;
}; };
ConfigVar & operator << (ConfigVar &, bool); ConfigVar &operator<<(ConfigVar &, bool);
ConfigVar & operator << (ConfigVar &, int); ConfigVar &operator<<(ConfigVar &, int);
ConfigVar & operator << (ConfigVar &, const std::string &str); ConfigVar &operator<<(ConfigVar &, const std::string &str);
const ConfigVar & operator >> (const ConfigVar &, bool &); const ConfigVar &operator>>(const ConfigVar &, bool &);
const ConfigVar & operator >> (const ConfigVar &, int &); const ConfigVar &operator>>(const ConfigVar &, int &);
const ConfigVar & operator >> (const ConfigVar &, std::string &str); const ConfigVar &operator>>(const ConfigVar &, std::string &str);
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -2,9 +2,6 @@
namespace encfs { namespace encfs {
Error::Error(const char *msg) Error::Error(const char *msg) : runtime_error(msg) {}
: runtime_error(msg)
{
}
} // namespace encfs } // namespace encfs

View File

@ -6,24 +6,21 @@
namespace encfs { namespace encfs {
class Error : public std::runtime_error class Error : public std::runtime_error {
{ public:
public:
Error(const char *msg); Error(const char *msg);
}; };
#define STR(X) #X #define STR(X) #X
#define rAssert( cond ) \ #define rAssert(cond) \
do { \ do { \
if( (cond) == false) \ if ((cond) == false) { \
{ LOG(ERROR) << "Assert failed: " << STR(cond); \ LOG(ERROR) << "Assert failed: " << STR(cond); \
throw Error(STR(cond)); \ throw Error(STR(cond)); \
} \ } \
} while(0) } while (0)
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * 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 * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "base/Interface.h" #include "base/Interface.h"
#include "base/ConfigVar.h" #include "base/ConfigVar.h"
@ -27,26 +27,22 @@
namespace encfs { namespace encfs {
std::ostream& operator << (std::ostream& out, const Interface &iface) std::ostream &operator<<(std::ostream &out, const Interface &iface) {
{ out << iface.name() << "(" << iface.major() << ":" << iface.minor() << ":"
out << iface.name() << "(" << iface.major() << iface.age() << ")";
<< ":" << iface.minor() << ":" << iface.age() << ")";
return out; 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; VLOG(1) << "checking if " << A << " implements " << B;
if( A.name() != B.name() ) if (A.name() != B.name()) return false;
return false;
int currentDiff = A.major() - B.major(); 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; Interface iface;
iface.set_name(name); iface.set_name(name);
iface.set_major(major); iface.set_major(major);
@ -55,15 +51,13 @@ Interface makeInterface(const char *name, int major, int minor, int age)
return iface; 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() dst << iface.name() << (int)iface.major() << (int)iface.minor()
<< (int)iface.age(); << (int)iface.age();
return dst; return dst;
} }
const ConfigVar & operator >> (const ConfigVar &src, Interface &iface) const ConfigVar &operator>>(const ConfigVar &src, Interface &iface) {
{
src >> *iface.mutable_name(); src >> *iface.mutable_name();
int major, minor, age; int major, minor, age;
src >> major >> minor >> age; src >> major >> minor >> age;
@ -73,13 +67,10 @@ const ConfigVar & operator >> (const ConfigVar &src, Interface &iface)
return src; return src;
} }
bool operator != (const Interface &a, const Interface &b) bool operator!=(const Interface &a, const Interface &b) {
{ if (a.major() != b.major()) return true;
if (a.major() != b.major())
return true;
if (a.minor() != b.minor()) if (a.minor() != b.minor()) return true;
return true;
return false; return false;
} }

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * 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 // This checks the current() version and age() against B.current() for
// compatibility. Even if A.implements(B) is true, B > A may also be // 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. // true, meaning B is a newer revision of the interface then A.
bool implements( const Interface &a, const Interface &b ); bool implements(const Interface &a, const Interface &b);
Interface makeInterface( const char *name, int major, int minor, int age ); Interface makeInterface(const char *name, int major, int minor, int age);
// Read operation // Read operation
class ConfigVar; 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 } // namespace encfs
#endif #endif

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -29,76 +29,58 @@
#warning No thread support. #warning No thread support.
#endif #endif
namespace encfs namespace encfs {
{
class Mutex class Mutex {
{
public: public:
#ifdef CMAKE_USE_PTHREADS_INIT #ifdef CMAKE_USE_PTHREADS_INIT
pthread_mutex_t _mutex; pthread_mutex_t _mutex;
Mutex() { Mutex() { pthread_mutex_init(&_mutex, 0); }
pthread_mutex_init( &_mutex, 0 ); ~Mutex() { pthread_mutex_destroy(&_mutex); }
}
~Mutex() {
pthread_mutex_destroy( &_mutex );
}
#endif #endif
void lock(); void lock();
void unlock(); void unlock();
}; };
class Lock class Lock {
{ public:
public: explicit Lock(Mutex &mutex);
explicit Lock( Mutex &mutex );
~Lock(); ~Lock();
// leave the lock as it is. When the Lock wrapper is destroyed, it // leave the lock as it is. When the Lock wrapper is destroyed, it
// will do nothing with the pthread mutex. // will do nothing with the pthread mutex.
void leave(); void leave();
private: private:
Lock(const Lock &src); // not allowed Lock(const Lock &src); // not allowed
Lock &operator = (const Lock &src); // not allowed Lock &operator=(const Lock &src); // not allowed
Mutex *_mutex; Mutex *_mutex;
}; };
inline void Mutex::lock() inline void Mutex::lock() {
{
#ifdef CMAKE_USE_PTHREADS_INIT #ifdef CMAKE_USE_PTHREADS_INIT
pthread_mutex_lock( &_mutex ); pthread_mutex_lock(&_mutex);
#endif #endif
} }
inline void Mutex::unlock() inline void Mutex::unlock() {
{
#ifdef CMAKE_USE_PTHREADS_INIT #ifdef CMAKE_USE_PTHREADS_INIT
pthread_mutex_unlock( &_mutex ); pthread_mutex_unlock(&_mutex);
#endif #endif
} }
inline Lock::Lock( Mutex &mutex ) inline Lock::Lock(Mutex &mutex) : _mutex(&mutex) {
: _mutex( &mutex ) if (_mutex) _mutex->lock();
{
if (_mutex)
_mutex->lock();
} }
inline Lock::~Lock( ) inline Lock::~Lock() {
{ if (_mutex) _mutex->unlock();
if(_mutex)
_mutex->unlock();
} }
inline void Lock::leave() inline void Lock::leave() { _mutex = NULL; }
{
_mutex = NULL;
}
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * 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 * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _Range_incl_ #ifndef _Range_incl_
#define _Range_incl_ #define _Range_incl_
@ -25,26 +25,26 @@
namespace encfs { namespace encfs {
class Range class Range {
{ int minVal;
int minVal; int maxVal;
int maxVal; int increment;
int increment;
public:
Range();
Range(int minMax);
Range(int min, int max, 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 closest(int value) const;
int max() const;
int inc() 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; bool separator = false;
for (int size = r.min(); size <= r.max(); size += r.inc()) { for (int size = r.min(); size <= r.max(); size += r.inc()) {
if (separator) if (separator)
@ -56,76 +56,52 @@ inline std::ostream & operator << (std::ostream &st, const Range &r) {
return st; return st;
} }
inline Range::Range(int minMax) inline Range::Range(int minMax) {
{ this->minVal = minMax;
this->minVal = minMax; this->maxVal = minMax;
this->maxVal = minMax; this->increment = 1;
this->increment = 1;
} }
inline Range::Range(int min_, int max_, int increment_) inline Range::Range(int min_, int max_, int increment_) {
{ this->minVal = min_;
this->minVal = min_; this->maxVal = max_;
this->maxVal = max_; this->increment = increment_;
this->increment = increment_; if (increment == 0) this->increment = 1;
if(increment == 0)
this->increment = 1;
} }
inline Range::Range() inline Range::Range() : minVal(-1), maxVal(-1), increment(1) {}
: minVal(-1)
, maxVal(-1)
, increment(1)
{
}
inline bool Range::allowed(int value) const inline bool Range::allowed(int value) const {
{ if (minVal < 0 && maxVal < 0) return true;
if(minVal < 0 && maxVal < 0) if (value >= minVal && value <= maxVal) {
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
int tmp = value - minVal; int tmp = value - minVal;
// try rounding to the nearest increment.. if ((tmp % increment) == 0) return true;
tmp += (increment >> 1); }
tmp -= (tmp % increment); return false;
return closest( value + tmp );
} }
inline int Range::min() const inline int Range::closest(int value) const {
{ if (allowed(value))
return value;
else if (value < minVal)
return minVal; return minVal;
} else if (value > maxVal)
inline int Range::max() const
{
return 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 inline int Range::min() const { return minVal; }
{
return increment;
}
} // namespace encfs inline int Range::max() const { return maxVal; }
inline int Range::inc() const { return increment; }
} // namespace encfs
#endif #endif

View File

@ -8,34 +8,29 @@
namespace encfs { namespace encfs {
template <typename T> template <typename T>
class Registry class Registry {
{ public:
public:
typedef T *(*FactoryFn)(); typedef T *(*FactoryFn)();
struct Data { struct Data {
FactoryFn constructor; FactoryFn constructor;
typename T::Properties properties; typename T::Properties properties;
}; };
void Register(const char *name, FactoryFn fn, void Register(const char *name, FactoryFn fn,
typename T::Properties properties) typename T::Properties properties) {
{
Data d; Data d;
d.constructor = fn; d.constructor = fn;
d.properties = properties; d.properties = properties;
data[name] = d; data[name] = d;
} }
T* Create(const char *name) T *Create(const char *name) {
{
auto it = data.find(name); auto it = data.find(name);
if (it == data.end()) if (it == data.end()) return NULL;
return NULL;
return (*it->second.constructor)(); return (*it->second.constructor)();
} }
T* CreateForMatch(const std::string &description) T *CreateForMatch(const std::string &description) {
{
for (auto &it : data) { for (auto &it : data) {
auto name = it.second.properties.toString(); auto name = it.second.properties.toString();
if (!name.compare(0, description.size(), description)) if (!name.compare(0, description.size(), description))
@ -54,11 +49,10 @@ public:
const typename T::Properties *GetProperties(const char *name) const { const typename T::Properties *GetProperties(const char *name) const {
auto it = data.find(name); auto it = data.find(name);
if (it == data.end()) if (it == data.end()) return NULL;
return NULL;
return &(it->second.properties); return &(it->second.properties);
} }
const typename T::Properties *GetPropertiesForMatch( const typename T::Properties *GetPropertiesForMatch(
const std::string &description) const { const std::string &description) const {
for (auto &it : data) { for (auto &it : data) {
@ -69,39 +63,32 @@ public:
return NULL; return NULL;
} }
private:
private:
std::map<std::string, Data> data; std::map<std::string, Data> data;
}; };
template <typename T, typename BASE> template <typename T, typename BASE>
class Registrar class Registrar {
{ public:
public: Registrar(const char *name) {
Registrar(const char *name) BASE::GetRegistry().Register(name, Registrar<T, BASE>::Construct,
{
BASE::GetRegistry().Register(name,
Registrar<T, BASE>::Construct,
T::GetProperties()); T::GetProperties());
} }
static BASE *Construct() { static BASE *Construct() { return new T(); }
return new T();
}
}; };
#define DECLARE_REGISTERABLE_TYPE(TYPE) \ #define DECLARE_REGISTERABLE_TYPE(TYPE) static Registry<TYPE> &GetRegistry()
static Registry<TYPE>& GetRegistry()
#define DEFINE_REGISTERABLE_TYPE(TYPE) \ #define DEFINE_REGISTERABLE_TYPE(TYPE) \
Registry<TYPE>& TYPE::GetRegistry() { \ Registry<TYPE> &TYPE::GetRegistry() { \
static Registry<TYPE> registry; \ static Registry<TYPE> registry; \
return registry; \ return registry; \
} }
#define REGISTER_CLASS(DERIVED, BASE) \ #define REGISTER_CLASS(DERIVED, BASE) \
static Registrar<DERIVED, BASE> registrar_ ## DERIVED ## _ ## BASE (#DERIVED) static Registrar<DERIVED, BASE> registrar_##DERIVED##_##BASE(#DERIVED)
} // namespace encfs } // namespace encfs
#endif // REGISTRY_H #endif // REGISTRY_H

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -38,90 +38,70 @@
namespace encfs { namespace encfs {
XmlValue::~XmlValue() XmlValue::~XmlValue() {}
{
}
XmlValuePtr XmlValue::operator[] (const char *path) const XmlValuePtr XmlValue::operator[](const char *path) const { return find(path); }
{
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 << ")"; LOG_FIRST_N(ERROR, 1) << "in XmlValue::find( " << path << ")";
return XmlValuePtr(); 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); XmlValuePtr value = find(path);
if (!value) if (!value) return false;
return false;
*out = value->text(); *out = value->text();
return true; return true;
} }
bool XmlValue::read(const char *path, int *out) const bool XmlValue::read(const char *path, int *out) const {
{
XmlValuePtr value = find(path); XmlValuePtr value = find(path);
if (!value) if (!value) return false;
return false;
*out = atoi(value->text().c_str()); *out = atoi(value->text().c_str());
return true; return true;
} }
bool XmlValue::read(const char *path, long *out) const bool XmlValue::read(const char *path, long *out) const {
{
XmlValuePtr value = find(path); XmlValuePtr value = find(path);
if (!value) if (!value) return false;
return false;
*out = atol(value->text().c_str()); *out = atol(value->text().c_str());
return true; return true;
} }
bool XmlValue::read(const char *path, double *out) const bool XmlValue::read(const char *path, double *out) const {
{
XmlValuePtr value = find(path); XmlValuePtr value = find(path);
if (!value) if (!value) return false;
return false;
*out = atof(value->text().c_str()); *out = atof(value->text().c_str());
return true; return true;
} }
bool XmlValue::read(const char *path, bool *out) const bool XmlValue::read(const char *path, bool *out) const {
{
XmlValuePtr value = find(path); XmlValuePtr value = find(path);
if (!value) if (!value) return false;
return false;
*out = atoi(value->text().c_str()); *out = atoi(value->text().c_str());
return true; 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); XmlValuePtr value = find(path);
if (!value) if (!value) return false;
return false;
std::string s = value->text(); std::string s = value->text();
s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end()); 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()); int decodedSize = B64ToB256Bytes(s.size());
if (decodedSize != length) if (decodedSize != length) {
{ LOG(ERROR) << "decoding bytes len " << s.size() << ", expecting output len "
LOG(ERROR) << "decoding bytes len " << s.size() << length << ", got " << decodedSize;
<< ", expecting output len " << length
<< ", got " << decodedSize;
return false; 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; LOG(ERROR) << "B64 decode failure on " << s;
return false; return false;
} }
@ -129,67 +109,51 @@ bool XmlValue::readB64(const char *path, byte *data, int length) const
return true; return true;
} }
bool XmlValue::read(const char *path, Interface *out) const bool XmlValue::read(const char *path, Interface *out) const {
{
XmlValuePtr node = find(path); XmlValuePtr node = find(path);
if (!node) if (!node) return false;
return false;
int major, minor; int major, minor;
bool ok = node->read("name", out->mutable_name()) bool ok = node->read("name", out->mutable_name()) &&
&& node->read("major", &major) node->read("major", &major) && node->read("minor", &minor);
&& node->read("minor", &minor);
if (!ok) if (!ok) return false;
return false;
out->set_major(major); out->set_major(major);
out->set_minor(minor); out->set_minor(minor);
return true; return true;
} }
std::string safeValueForNode(const TiXmlElement *element) std::string safeValueForNode(const TiXmlElement *element) {
{
std::string value; std::string value;
if (element == NULL) if (element == NULL) return value;
return value;
const TiXmlNode *child = element->FirstChild(); const TiXmlNode *child = element->FirstChild();
if (child) if (child) {
{
const TiXmlText *childText = child->ToText(); const TiXmlText *childText = child->ToText();
if (childText) if (childText) value = childText->Value();
value = childText->Value();
} }
return value; return value;
} }
class XmlNode : virtual public XmlValue class XmlNode : virtual public XmlValue {
{
const TiXmlElement *element; const TiXmlElement *element;
public:
public:
XmlNode(const TiXmlElement *element_) XmlNode(const TiXmlElement *element_)
: XmlValue(safeValueForNode(element_)) : XmlValue(safeValueForNode(element_)), element(element_) {}
, element(element_)
{
}
virtual ~XmlNode() virtual ~XmlNode() {}
{
}
virtual XmlValuePtr find(const char *name) const virtual XmlValuePtr find(const char *name) const {
{ if (name[0] == '@') {
if (name[0] == '@') const char *value = element->Attribute(name + 1);
{
const char *value = element->Attribute(name+1);
if (value) if (value)
return XmlValuePtr(new XmlValue(value)); return XmlValuePtr(new XmlValue(value));
else else
return XmlValuePtr(); return XmlValuePtr();
} else } else {
{
const TiXmlElement *el = element->FirstChildElement(name); const TiXmlElement *el = element->FirstChildElement(name);
if (el) if (el)
return XmlValuePtr(new XmlNode(el)); return XmlValuePtr(new XmlNode(el));
@ -199,39 +163,29 @@ public:
} }
}; };
struct XmlReader::XmlReaderData struct XmlReader::XmlReaderData {
{
shared_ptr<TiXmlDocument> doc; shared_ptr<TiXmlDocument> doc;
}; };
XmlReader::XmlReader() XmlReader::XmlReader() : pd(new XmlReaderData()) {}
: 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)); pd->doc.reset(new TiXmlDocument(fileName));
return pd->doc->LoadFile(); return pd->doc->LoadFile();
} }
XmlValuePtr XmlReader::operator[] ( const char *name ) const XmlValuePtr XmlReader::operator[](const char *name) const {
{
TiXmlNode *node = pd->doc->FirstChild(name); TiXmlNode *node = pd->doc->FirstChild(name);
if (node == NULL) if (node == NULL) {
{
LOG(ERROR) << "Xml node " << name << " not found"; LOG(ERROR) << "Xml node " << name << " not found";
return XmlValuePtr(new XmlValue()); return XmlValuePtr(new XmlValue());
} }
TiXmlElement *element = node->ToElement(); TiXmlElement *element = node->ToElement();
if (element == NULL) if (element == NULL) {
{
LOG(ERROR) << "Xml node " << name LOG(ERROR) << "Xml node " << name
<< " not element, type = " << node->Type(); << " not element, type = " << node->Type();
return XmlValuePtr(new XmlValue()); return XmlValuePtr(new XmlValue());

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * 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 * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _XmlReader_incl_ #ifndef _XmlReader_incl_
#define _XmlReader_incl_ #define _XmlReader_incl_
@ -32,26 +32,18 @@ typedef shared_ptr<XmlValue> XmlValuePtr;
class Interface; class Interface;
class XmlValue class XmlValue {
{
std::string value; std::string value;
public:
XmlValue()
{
}
XmlValue(const std::string &value) public:
{ XmlValue() {}
this->value = value;
} XmlValue(const std::string &value) { this->value = value; }
virtual ~XmlValue(); virtual ~XmlValue();
XmlValuePtr operator[] (const char *path) const; XmlValuePtr operator[](const char *path) const;
const std::string &text() const const std::string &text() const { return value; }
{
return value;
}
bool read(const char *path, std::string *out) const; bool read(const char *path, std::string *out) const;
bool readB64(const char *path, byte *out, int length) const; bool readB64(const char *path, byte *out, int length) const;
@ -63,13 +55,12 @@ public:
bool read(const char *path, Interface *out) const; bool read(const char *path, Interface *out) const;
protected: protected:
virtual XmlValuePtr find(const char *name) const; virtual XmlValuePtr find(const char *name) const;
}; };
class XmlReader class XmlReader {
{ public:
public:
XmlReader(); XmlReader();
~XmlReader(); ~XmlReader();
@ -77,7 +68,7 @@ public:
XmlValuePtr operator[](const char *name) const; XmlValuePtr operator[](const char *name) const;
private: private:
struct XmlReaderData; struct XmlReaderData;
shared_ptr<XmlReaderData> pd; shared_ptr<XmlReaderData> pd;
}; };

View File

@ -21,7 +21,7 @@
This must come before <config.h> because <config.h> may include This must come before <config.h> because <config.h> may include
<features.h>, and once <features.h> has been included, it's too late. */ <features.h>, and once <features.h> has been included, it's too late. */
#ifndef _GNU_SOURCE #ifndef _GNU_SOURCE
# define _GNU_SOURCE 1 #define _GNU_SOURCE 1
#endif #endif
/* Specification. */ /* Specification. */
@ -33,46 +33,35 @@
//#include "lib-asprintf.h" //#include "lib-asprintf.h"
#include <stdio.h> #include <stdio.h>
namespace gnu namespace gnu {
{
/* Constructor: takes a format string and the printf arguments. */ /* Constructor: takes a format string and the printf arguments. */
autosprintf::autosprintf (const char *format, ...) autosprintf::autosprintf(const char *format, ...) {
{ va_list args;
va_list args; va_start(args, format);
va_start (args, format); if (vasprintf(&str, format, args) < 0) str = NULL;
if (vasprintf (&str, format, args) < 0) va_end(args);
str = NULL; }
va_end (args);
} /* Copy constructor. Necessary because the destructor is nontrivial. */
autosprintf::autosprintf(const autosprintf &src) {
/* Copy constructor. Necessary because the destructor is nontrivial. */ str = (src.str != NULL ? strdup(src.str) : NULL);
autosprintf::autosprintf (const autosprintf& src) }
{
str = (src.str != NULL ? strdup (src.str) : NULL); /* Destructor: frees the temporarily allocated string. */
} autosprintf::~autosprintf() { free(str); }
/* Destructor: frees the temporarily allocated string. */ /* Conversion to string. */
autosprintf::~autosprintf () autosprintf::operator char *() const {
{ if (str != NULL) {
free (str); size_t length = strlen(str) + 1;
} char *copy = new char[length];
memcpy(copy, str, length);
/* Conversion to string. */ return copy;
autosprintf::operator char * () const } else
{ return NULL;
if (str != NULL) }
{ autosprintf::operator std::string() const {
size_t length = strlen (str) + 1; return std::string(str ? str : "(error in autosprintf)");
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)");
}
} }

View File

@ -21,46 +21,45 @@
#ifndef __attribute__ #ifndef __attribute__
/* This feature is available in gcc versions 2.5 and later. */ /* This feature is available in gcc versions 2.5 and later. */
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__ #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
# define __attribute__(Spec) /* empty */ #define __attribute__(Spec) /* empty */
# endif #endif
/* The __-protected variants of `format' and `printf' attributes /* The __-protected variants of `format' and `printf' attributes
are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
# define __format__ format #define __format__ format
# define __printf__ printf #define __printf__ printf
# endif #endif
#endif #endif
#include <string> #include <string>
#include <iostream> #include <iostream>
namespace gnu namespace gnu {
{ /* A temporary object, usually allocated on the stack, representing
/* A temporary object, usually allocated on the stack, representing the result of an asprintf() call. */
the result of an asprintf() call. */ class autosprintf {
class autosprintf public:
{ /* Constructor: takes a format string and the printf arguments. */
public: autosprintf(const char* format, ...)
/* Constructor: takes a format string and the printf arguments. */ __attribute__((__format__(__printf__, 2, 3)));
autosprintf (const char *format, ...) /* Copy constructor. */
__attribute__ ((__format__ (__printf__, 2, 3))); autosprintf(const autosprintf& src);
/* Copy constructor. */ /* Destructor: frees the temporarily allocated string. */
autosprintf (const autosprintf& src); ~autosprintf();
/* Destructor: frees the temporarily allocated string. */ /* Conversion to string. */
~autosprintf (); operator char*() const;
/* Conversion to string. */ operator std::string() const;
operator char * () const; /* Output to an ostream. */
operator std::string () const; friend inline std::ostream& operator<<(std::ostream& stream,
/* Output to an ostream. */ const autosprintf& tmp) {
friend inline std::ostream& operator<< (std::ostream& stream, const autosprintf& tmp) stream << (tmp.str ? tmp.str : "(error in autosprintf)");
{ return stream;
stream << (tmp.str ? tmp.str : "(error in autosprintf)"); }
return stream;
} private:
private: char* str;
char *str; };
};
} }
#endif /* _AUTOSPRINTF_H */ #endif /* _AUTOSPRINTF_H */

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -29,33 +29,29 @@ namespace encfs {
// arrays. // arrays.
// It is the caller's responsibility to make sure the output array is large // It is the caller's responsibility to make sure the output array is large
// enough. // enough.
void changeBase2(byte *src, int srcLen, int src2Pow, void changeBase2(byte *src, int srcLen, int src2Pow, byte *dst, int dstLen,
byte *dst, int dstLen, int dst2Pow) int dst2Pow) {
{ unsigned long work = 0;
unsigned long work = 0; int workBits = 0; // number of bits left in the work buffer
int workBits = 0; // number of bits left in the work buffer byte *end = src + srcLen;
byte *end = src + srcLen; byte *origDst = dst;
byte *origDst = dst; const int mask = (1 << dst2Pow) - 1;
const int mask = (1 << dst2Pow) -1;
// copy the new bits onto the high bits of the stream. // copy the new bits onto the high bits of the stream.
// The bits that fall off the low end are the output bits. // The bits that fall off the low end are the output bits.
while(src != end) while (src != end) {
{ work |= ((unsigned long)(*src++)) << workBits;
work |= ((unsigned long)(*src++)) << workBits; workBits += src2Pow;
workBits += src2Pow;
while(workBits >= dst2Pow) while (workBits >= dst2Pow) {
{ *dst++ = work & mask;
*dst++ = work & mask; work >>= dst2Pow;
work >>= dst2Pow; workBits -= dst2Pow;
workBits -= dst2Pow;
}
} }
}
// now, we could have a partial value left in the work buffer.. // now, we could have a partial value left in the work buffer..
if(workBits && ((dst - origDst) < dstLen)) if (workBits && ((dst - origDst) < dstLen)) *dst++ = work & mask;
*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 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. to be written, then write the value at the tail end of the recursion.
*/ */
static static void changeBase2Inline(byte *src, int srcLen, int src2Pow, int dst2Pow,
void changeBase2Inline(byte *src, int srcLen, bool outputPartialLastByte, unsigned long work,
int src2Pow, int dst2Pow, int workBits, byte *outLoc) {
bool outputPartialLastByte, const int mask = (1 << dst2Pow) - 1;
unsigned long work, if (!outLoc) outLoc = src;
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. // copy the new bits onto the high bits of the stream.
// The bits that fall off the low end are the output bits. // The bits that fall off the low end are the output bits.
while(srcLen && workBits < dst2Pow) while (srcLen && workBits < dst2Pow) {
{ work |= ((unsigned long)(*src++)) << workBits;
work |= ((unsigned long)(*src++)) << workBits; workBits += src2Pow;
workBits += src2Pow; --srcLen;
--srcLen; }
}
// we have at least one value that can be output
// we have at least one value that can be output byte outVal = work & mask;
byte outVal = work & mask; work >>= dst2Pow;
work >>= dst2Pow; workBits -= dst2Pow;
workBits -= dst2Pow;
if (srcLen) {
if(srcLen) // more input left, so recurse
{ changeBase2Inline(src, srcLen, src2Pow, dst2Pow, outputPartialLastByte,
// more input left, so recurse work, workBits, outLoc + 1);
changeBase2Inline( src, srcLen, src2Pow, dst2Pow, *outLoc = outVal;
outputPartialLastByte, work, workBits, outLoc+1); } else {
*outLoc = outVal; // no input left, we can write remaining values directly
} else *outLoc++ = outVal;
{
// no input left, we can write remaining values directly // we could have a partial value left in the work buffer..
*outLoc++ = outVal; if (outputPartialLastByte) {
while (workBits > 0) {
// we could have a partial value left in the work buffer.. *outLoc++ = work & mask;
if(outputPartialLastByte) work >>= dst2Pow;
{ workBits -= dst2Pow;
while(workBits > 0) }
{
*outLoc++ = work & mask;
work >>= dst2Pow;
workBits -= dst2Pow;
}
}
} }
}
} }
void changeBase2Inline(byte *src, int srcLen, void changeBase2Inline(byte *src, int srcLen, int src2Pow, int dst2Pow,
int src2Pow, int dst2Pow, bool outputPartialLastByte) {
bool outputPartialLastByte) changeBase2Inline(src, srcLen, src2Pow, dst2Pow, outputPartialLastByte, 0, 0,
{ 0);
changeBase2Inline(src, srcLen, src2Pow, dst2Pow,
outputPartialLastByte, 0, 0, 0);
} }
// character set for ascii b64: // character set for ascii b64:
// ",-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" // ",-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
// a standard base64 (eg a64l doesn't use ',-' but uses './'. We don't // 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 // '.' included in the encrypted names, so that it can be reserved for files
// with special meaning. // with special meaning.
static const char B642AsciiTable[] = ",-0123456789"; static const char B642AsciiTable[] = ",-0123456789";
void B64ToAscii(byte *in, int length) void B64ToAscii(byte *in, int length) {
{ for (int offset = 0; offset < length; ++offset) {
for(int offset=0; offset<length; ++offset)
{
int ch = in[offset]; int ch = in[offset];
if(ch > 11) if (ch > 11) {
{ if (ch > 37)
if(ch > 37)
ch += 'a' - 38; ch += 'a' - 38;
else else
ch += 'A' - 12; ch += 'A' - 12;
} else } else
ch = B642AsciiTable[ ch ]; ch = B642AsciiTable[ch];
in[offset] = ch; in[offset] = ch;
} }
} }
static const byte Ascii2B64Table[] = static const byte Ascii2B64Table[] =
" 01 23456789:; "; " 01 23456789:; ";
// 0123456789 123456789 123456789 123456789 123456789 123456789 1234 // 0123456789 123456789 123456789 123456789 123456789 123456789 1234
// 0 1 2 3 4 5 6 // 0 1 2 3 4 5 6
void AsciiToB64(byte *in, int length) void AsciiToB64(byte *in, int length) { return AsciiToB64(in, in, length); }
{
return AsciiToB64(in, in, length);
}
void AsciiToB64(byte *out, const byte *in, int length) void AsciiToB64(byte *out, const byte *in, int length) {
{ while (length--) {
while(length--)
{
byte ch = *in++; byte ch = *in++;
if(ch >= 'A') if (ch >= 'A') {
{ if (ch >= 'a')
if(ch >= 'a')
ch += 38 - 'a'; ch += 38 - 'a';
else else
ch += 12 - 'A'; ch += 12 - 'A';
} else } else
ch = Ascii2B64Table[ ch ] - '0'; ch = Ascii2B64Table[ch] - '0';
*out++ = ch; *out++ = ch;
} }
} }
void B32ToAscii(byte *buf, int len) {
void B32ToAscii(byte *buf, int len) for (int offset = 0; offset < len; ++offset) {
{
for(int offset=0; offset<len; ++offset)
{
int ch = buf[offset]; int ch = buf[offset];
if (ch >= 0 && ch < 26) if (ch >= 0 && ch < 26)
ch += 'A'; ch += 'A';
@ -191,15 +161,10 @@ void B32ToAscii(byte *buf, int len)
} }
} }
void AsciiToB32(byte *in, int length) 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) void AsciiToB32(byte *out, const byte *in, int length) {
{ while (length--) {
while(length--)
{
byte ch = *in++; byte ch = *in++;
int lch = toupper(ch); int lch = toupper(ch);
if (lch >= 'A') if (lch >= 'A')
@ -211,33 +176,24 @@ void AsciiToB32(byte *out, const byte *in, int length)
} }
} }
#define WHITESPACE 64 #define WHITESPACE 64
#define EQUALS 65 #define EQUALS 65
#define INVALID 66 #define INVALID 66
static const byte d[] = { static const byte d[] = {
66,66,66,66,66,66,66,66,66,64, 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, 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,
66,66,66,66,66,66,66,66,66,66, 55, 56, 57, 58, 59, 60, 61, 66, 66, // 50-59
66,66,66,62,66,66,66,63,52,53, 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 bool B64StandardDecode(byte *out, const byte *in, int inLen) {
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; const byte *end = in + inLen;
size_t buf = 1; size_t buf = 1;
while (in < end) { while (in < end) {
byte v = *in++; byte v = *in++;
if (v > 'z') { if (v > 'z') {
@ -247,31 +203,31 @@ bool B64StandardDecode(byte *out, const byte *in, int inLen) {
byte c = d[v]; byte c = d[v];
switch (c) { switch (c) {
case WHITESPACE: continue; /* skip whitespace */ case WHITESPACE:
case INVALID: continue; /* skip whitespace */
LOG(ERROR) << "Invalid character: " << (unsigned int)v; case INVALID:
return false; /* invalid input, return error */ LOG(ERROR) << "Invalid character: " << (unsigned int)v;
case EQUALS: /* pad character, end of data */ return false; /* invalid input, return error */
in = end; case EQUALS: /* pad character, end of data */
continue; in = end;
default: continue;
buf = buf << 6 | c; default:
buf = buf << 6 | c;
/* If the buffer is full, split it into bytes */
if (buf & 0x1000000) { /* If the buffer is full, split it into bytes */
*out++ = buf >> 16; if (buf & 0x1000000) {
*out++ = buf >> 8; *out++ = buf >> 16;
*out++ = buf; *out++ = buf >> 8;
buf = 1; *out++ = buf;
} buf = 1;
}
} }
} }
if (buf & 0x40000) { if (buf & 0x40000) {
*out++ = buf >> 10; *out++ = buf >> 10;
*out++ = buf >> 2; *out++ = buf >> 2;
} } else if (buf & 0x1000) {
else if (buf & 0x1000) {
*out++ = buf >> 4; *out++ = buf >> 4;
} }

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -25,40 +25,33 @@
namespace encfs { namespace encfs {
inline int B64ToB256Bytes( int numB64Bytes ) inline int B64ToB256Bytes(int numB64Bytes) {
{ return (numB64Bytes * 6) / 8; // round down
return (numB64Bytes * 6) / 8; // round down
} }
inline int B32ToB256Bytes( int numB32Bytes ) inline int B32ToB256Bytes(int numB32Bytes) {
{ return (numB32Bytes * 5) / 8; // round down
return (numB32Bytes * 5) / 8; // round down
} }
inline int B256ToB64Bytes( int numB256Bytes ) inline int B256ToB64Bytes(int numB256Bytes) {
{ return (numB256Bytes * 8 + 5) / 6; // round up
return (numB256Bytes * 8 + 5) / 6; // round up
} }
inline int B256ToB32Bytes( int numB256Bytes ) inline int B256ToB32Bytes(int numB256Bytes) {
{ return (numB256Bytes * 8 + 4) / 5; // round up
return (numB256Bytes * 8 + 4) / 5; // round up
} }
/* /*
convert data between different bases - each being a power of 2. convert data between different bases - each being a power of 2.
*/ */
void changeBase2(byte *src, int srcLength, int srcPow2, void changeBase2(byte *src, int srcLength, int srcPow2, byte *dst,
byte *dst, int dstLength, int dstPow2); int dstLength, int dstPow2);
/* /*
same as changeBase2, but writes output over the top of input data. same as changeBase2, but writes output over the top of input data.
*/ */
void changeBase2Inline(byte *buf, int srcLength, void changeBase2Inline(byte *buf, int srcLength, int srcPow2, int dst2Pow,
int srcPow2, int dst2Pow, bool outputPartialLastByte);
bool outputPartialLastByte);
// inplace translation from values [0,2^6] => base64 ASCII // inplace translation from values [0,2^6] => base64 ASCII
void B64ToAscii(byte *buf, int length); void B64ToAscii(byte *buf, int length);
@ -80,4 +73,3 @@ bool B64StandardDecode(byte *out, const byte *in, int inputLen);
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -23,19 +23,18 @@
#if ENABLE_NLS #if ENABLE_NLS
/* Get declarations of GNU message catalog functions. */ /* Get declarations of GNU message catalog functions. */
# include <libintl.h> #include <libintl.h>
/* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by /* 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 the gettext() and ngettext() macros. This is an alternative to calling
textdomain(), and is useful for libraries. */ textdomain(), and is useful for libraries. */
# ifdef DEFAULT_TEXT_DOMAIN #ifdef DEFAULT_TEXT_DOMAIN
# undef gettext #undef gettext
# define gettext(Msgid) \ #define gettext(Msgid) dgettext(DEFAULT_TEXT_DOMAIN, Msgid)
dgettext (DEFAULT_TEXT_DOMAIN, Msgid) #undef ngettext
# undef ngettext #define ngettext(Msgid1, Msgid2, N) \
# define ngettext(Msgid1, Msgid2, N) \ dngettext(DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N)
dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N) #endif
# endif
#else #else
@ -46,17 +45,17 @@
and also including <libintl.h> would fail on SunOS 4, whereas <locale.h> and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
is OK. */ is OK. */
#if defined(__sun) #if defined(__sun)
# include <locale.h> #include <locale.h>
#endif #endif
/* Many header files from the libstdc++ coming with g++ 3.3 or newer include /* Many header files from the libstdc++ coming with g++ 3.3 or newer include
<libintl.h>, which chokes if dcgettext is defined as a macro. So include <libintl.h>, which chokes if dcgettext is defined as a macro. So include
it now, to make later inclusions of <libintl.h> a NOP. */ it now, to make later inclusions of <libintl.h> a NOP. */
#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) #if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3)
# include <cstdlib> #include <cstdlib>
# if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H #if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H
# include <libintl.h> #include <libintl.h>
# endif #endif
#endif #endif
/* Disabled NLS. /* Disabled NLS.
@ -64,23 +63,22 @@
for invalid uses of the value returned from these functions. for invalid uses of the value returned from these functions.
On pre-ANSI systems without 'const', the config.h file is supposed to On pre-ANSI systems without 'const', the config.h file is supposed to
contain "#define const". */ contain "#define const". */
# define gettext(Msgid) ((const char *) (Msgid)) #define gettext(Msgid) ((const char *)(Msgid))
# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid)) #define dgettext(Domainname, Msgid) ((void)(Domainname), gettext(Msgid))
# define dcgettext(Domainname, Msgid, Category) \ #define dcgettext(Domainname, Msgid, Category) \
((void) (Category), dgettext (Domainname, Msgid)) ((void)(Category), dgettext(Domainname, Msgid))
# define ngettext(Msgid1, Msgid2, N) \ #define ngettext(Msgid1, Msgid2, N) \
((N) == 1 \ ((N) == 1 ? ((void)(Msgid2), (const char *)(Msgid1)) \
? ((void) (Msgid2), (const char *) (Msgid1)) \ : ((void)(Msgid1), (const char *)(Msgid2)))
: ((void) (Msgid1), (const char *) (Msgid2))) #define dngettext(Domainname, Msgid1, Msgid2, N) \
# define dngettext(Domainname, Msgid1, Msgid2, N) \ ((void)(Domainname), ngettext(Msgid1, Msgid2, N))
((void) (Domainname), ngettext (Msgid1, Msgid2, N)) #define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ ((void)(Category), dngettext(Domainname, Msgid1, Msgid2, N))
((void) (Category), dngettext(Domainname, Msgid1, Msgid2, N)) #define textdomain(Domainname) ((const char *)(Domainname))
# define textdomain(Domainname) ((const char *) (Domainname)) #define bindtextdomain(Domainname, Dirname) \
# define bindtextdomain(Domainname, Dirname) \ ((void)(Domainname), (const char *)(Dirname))
((void) (Domainname), (const char *) (Dirname)) #define bind_textdomain_codeset(Domainname, Codeset) \
# define bind_textdomain_codeset(Domainname, Codeset) \ ((void)(Domainname), (const char *)(Codeset))
((void) (Domainname), (const char *) (Codeset))
#endif #endif
@ -101,27 +99,33 @@
short and rarely need to change. short and rarely need to change.
The letter 'p' stands for 'particular' or 'special'. */ The letter 'p' stands for 'particular' or 'special'. */
#ifdef DEFAULT_TEXT_DOMAIN #ifdef DEFAULT_TEXT_DOMAIN
# define pgettext(Msgctxt, Msgid) \ #define pgettext(Msgctxt, Msgid) \
pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) pgettext_aux(DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, \
LC_MESSAGES)
#else #else
# define pgettext(Msgctxt, Msgid) \ #define pgettext(Msgctxt, Msgid) \
pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) pgettext_aux(NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
#endif #endif
#define dpgettext(Domainname, Msgctxt, Msgid) \ #define dpgettext(Domainname, Msgctxt, Msgid) \
pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) pgettext_aux(Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, \
LC_MESSAGES)
#define dcpgettext(Domainname, Msgctxt, Msgid, Category) \ #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 #ifdef DEFAULT_TEXT_DOMAIN
# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ #define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) npgettext_aux(DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, \
Msgid, MsgidPlural, N, LC_MESSAGES)
#else #else
# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ #define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) npgettext_aux(NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, \
N, LC_MESSAGES)
#endif #endif
#define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ #define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) npgettext_aux(Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, \
MsgidPlural, N, LC_MESSAGES)
#define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \ #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__ #ifdef __GNUC__
__inline __inline
@ -130,12 +134,10 @@ __inline
inline inline
#endif #endif
#endif #endif
static const char * static const char *
pgettext_aux (const char *domain, pgettext_aux(const char *domain, const char *msg_ctxt_id, const char *msgid,
const char *msg_ctxt_id, const char *msgid, int category) {
int category) const char *translation = dcgettext(domain, msg_ctxt_id, category);
{
const char *translation = dcgettext (domain, msg_ctxt_id, category);
if (translation == msg_ctxt_id) if (translation == msg_ctxt_id)
return msgid; return msgid;
else else
@ -149,14 +151,11 @@ __inline
inline inline
#endif #endif
#endif #endif
static const char * static const char *
npgettext_aux (const char *domain, npgettext_aux(const char *domain, const char *msg_ctxt_id, const char *msgid,
const char *msg_ctxt_id, const char *msgid, const char *msgid_plural, unsigned long int n, int category) {
const char *msgid_plural, unsigned long int n,
int category)
{
const char *translation = 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) if (translation == msg_ctxt_id || translation == msgid_plural)
return (n == 1 ? msgid : msgid_plural); return (n == 1 ? msgid : msgid_plural);
else else
@ -169,18 +168,18 @@ npgettext_aux (const char *domain,
#include <string.h> #include <string.h>
#define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS \ #define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS \
(((__GNUC__ >= 3 || __GNUG__ >= 2) && !__STRICT_ANSI__) \ (((__GNUC__ >= 3 || __GNUG__ >= 2) && !__STRICT_ANSI__) \
/* || __STDC_VERSION__ >= 199901L */ ) /* || __STDC_VERSION__ >= 199901L */)
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
#include <stdlib.h> #include <stdlib.h>
#endif #endif
#define pgettext_expr(Msgctxt, Msgid) \ #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) \ #define dpgettext_expr(Domainname, Msgctxt, Msgid) \
dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES) dcpgettext_expr(Domainname, Msgctxt, Msgid, LC_MESSAGES)
#ifdef __GNUC__ #ifdef __GNUC__
__inline __inline
@ -189,43 +188,38 @@ __inline
inline inline
#endif #endif
#endif #endif
static const char * static const char *
dcpgettext_expr (const char *domain, dcpgettext_expr(const char *domain, const char *msgctxt, const char *msgid,
const char *msgctxt, const char *msgid, int category) {
int category) size_t msgctxt_len = strlen(msgctxt) + 1;
{ size_t msgid_len = strlen(msgid) + 1;
size_t msgctxt_len = strlen (msgctxt) + 1;
size_t msgid_len = strlen (msgid) + 1;
const char *translation; const char *translation;
#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
char msg_ctxt_id[msgctxt_len + msgid_len]; char msg_ctxt_id[msgctxt_len + msgid_len];
#else #else
char buf[1024]; char buf[1024];
char *msg_ctxt_id = char *msg_ctxt_id = (msgctxt_len + msgid_len <= sizeof(buf)
(msgctxt_len + msgid_len <= sizeof (buf) ? buf
? buf : (char *)malloc(msgctxt_len + msgid_len));
: (char *) malloc (msgctxt_len + msgid_len));
if (msg_ctxt_id != NULL) if (msg_ctxt_id != NULL)
#endif #endif
{ {
memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); memcpy(msg_ctxt_id, msgctxt, msgctxt_len - 1);
msg_ctxt_id[msgctxt_len - 1] = '\004'; msg_ctxt_id[msgctxt_len - 1] = '\004';
memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); memcpy(msg_ctxt_id + msgctxt_len, msgid, msgid_len);
translation = dcgettext (domain, msg_ctxt_id, category); translation = dcgettext(domain, msg_ctxt_id, category);
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
if (msg_ctxt_id != buf) if (msg_ctxt_id != buf) free(msg_ctxt_id);
free (msg_ctxt_id);
#endif #endif
if (translation != msg_ctxt_id) if (translation != msg_ctxt_id) return translation;
return translation; }
}
return msgid; return msgid;
} }
#define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \ #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) \ #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__ #ifdef __GNUC__
__inline __inline
@ -234,37 +228,32 @@ __inline
inline inline
#endif #endif
#endif #endif
static const char * static const char *
dcnpgettext_expr (const char *domain, dcnpgettext_expr(const char *domain, const char *msgctxt, const char *msgid,
const char *msgctxt, const char *msgid, const char *msgid_plural, unsigned long int n, int category) {
const char *msgid_plural, unsigned long int n, size_t msgctxt_len = strlen(msgctxt) + 1;
int category) size_t msgid_len = strlen(msgid) + 1;
{
size_t msgctxt_len = strlen (msgctxt) + 1;
size_t msgid_len = strlen (msgid) + 1;
const char *translation; const char *translation;
#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
char msg_ctxt_id[msgctxt_len + msgid_len]; char msg_ctxt_id[msgctxt_len + msgid_len];
#else #else
char buf[1024]; char buf[1024];
char *msg_ctxt_id = char *msg_ctxt_id = (msgctxt_len + msgid_len <= sizeof(buf)
(msgctxt_len + msgid_len <= sizeof (buf) ? buf
? buf : (char *)malloc(msgctxt_len + msgid_len));
: (char *) malloc (msgctxt_len + msgid_len));
if (msg_ctxt_id != NULL) if (msg_ctxt_id != NULL)
#endif #endif
{ {
memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); memcpy(msg_ctxt_id, msgctxt, msgctxt_len - 1);
msg_ctxt_id[msgctxt_len - 1] = '\004'; msg_ctxt_id[msgctxt_len - 1] = '\004';
memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); memcpy(msg_ctxt_id + msgctxt_len, msgid, msgid_len);
translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); translation = dcngettext(domain, msg_ctxt_id, msgid_plural, n, category);
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
if (msg_ctxt_id != buf) if (msg_ctxt_id != buf) free(msg_ctxt_id);
free (msg_ctxt_id);
#endif #endif
if (!(translation == msg_ctxt_id || translation == msgid_plural)) if (!(translation == msg_ctxt_id || translation == msgid_plural))
return translation; return translation;
} }
return (n == 1 ? msgid : msgid_plural); return (n == 1 ? msgid : msgid_plural);
} }

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -23,22 +23,20 @@
#if defined(LOCALEDIR) #if defined(LOCALEDIR)
# include "base/gettext.h" #include "base/gettext.h"
// make shortcut for gettext // make shortcut for gettext
# define _(STR) gettext (STR) #define _(STR) gettext(STR)
# include "base/autosprintf.h" #include "base/autosprintf.h"
using gnu::autosprintf; using gnu::autosprintf;
#else #else
# define gettext(STR) (STR) #define gettext(STR) (STR)
# define gettext_noop(STR) (STR) #define gettext_noop(STR) (STR)
# define _(STR) (STR) #define _(STR) (STR)
# define N_(STR) (STR) #define N_(STR) (STR)
#endif #endif
#endif #endif

View File

@ -8,7 +8,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -25,14 +25,13 @@
#include "base/config.h" #include "base/config.h"
#ifdef HAVE_TR1_MEMORY #ifdef HAVE_TR1_MEMORY
#include <tr1/memory> #include <tr1/memory>
using std::tr1::shared_ptr; using std::tr1::shared_ptr;
using std::tr1::dynamic_pointer_cast; using std::tr1::dynamic_pointer_cast;
#else #else
#include <memory> #include <memory>
using std::shared_ptr; using std::shared_ptr;
using std::dynamic_pointer_cast; using std::dynamic_pointer_cast;
#endif #endif
#endif #endif

View File

@ -4,7 +4,6 @@
namespace encfs { namespace encfs {
typedef unsigned char byte; typedef unsigned char byte;
} }
#endif // TYPES_H #endif // TYPES_H

View File

@ -13,12 +13,10 @@
namespace encfs { namespace encfs {
Registry<BlockCipher>& BlockCipher::GetRegistry() Registry<BlockCipher>& BlockCipher::GetRegistry() {
{
static Registry<BlockCipher> registry; static Registry<BlockCipher> registry;
static bool first = true; static bool first = true;
if (first) if (first) {
{
#ifdef WITH_OPENSSL #ifdef WITH_OPENSSL
OpenSSL::registerCiphers(); OpenSSL::registerCiphers();
#endif #endif
@ -31,13 +29,8 @@ Registry<BlockCipher>& BlockCipher::GetRegistry()
return registry; return registry;
} }
BlockCipher::BlockCipher() BlockCipher::BlockCipher() {}
{
}
BlockCipher::~BlockCipher() BlockCipher::~BlockCipher() {}
{
}
} // namespace encfs } // namespace encfs

View File

@ -15,8 +15,7 @@ static const char NAME_BLOWFISH_CBC[] = "Blowfish/CBC";
// BlockCipher is a StreamCipher with a block size. // BlockCipher is a StreamCipher with a block size.
// Encryption and decryption must be in multiples of the block size. // Encryption and decryption must be in multiples of the block size.
class BlockCipher : public StreamCipher class BlockCipher : public StreamCipher {
{
public: public:
DECLARE_REGISTERABLE_TYPE(BlockCipher); 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 // Not valid until a key has been set, as they key size may determine the
// block size. // block size.
virtual int blockSize() const =0; virtual int blockSize() const = 0;
}; };
} // namespace encfs } // namespace encfs
#endif // BLOCKCIPHER_H #endif // BLOCKCIPHER_H

View File

@ -8,7 +8,7 @@
* This program is free software: you can redistribute it and/or modify it under * 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 * 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 * 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 * 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 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
@ -43,9 +43,7 @@ namespace {
class BlockCipherTest : public testing::Test { class BlockCipherTest : public testing::Test {
public: public:
virtual void SetUp() { virtual void SetUp() { CipherV1::init(false); }
CipherV1::init(false);
}
}; };
void compare(const byte *a, const byte *b, int size) { 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 #endif
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
bool match = (a[i] == b[i]); bool match = (a[i] == b[i]);
ASSERT_TRUE(match) << "mismatched data at offset " << i ASSERT_TRUE(match) << "mismatched data at offset " << i << " of " << size;
<< " of " << size; if (!match) break;
if (!match)
break;
} }
} }
@ -79,26 +75,25 @@ TEST_F(BlockCipherTest, RequiredStreamCiphers) {
} }
template <typename T> template <typename T>
void checkTestVector(const char *cipherName, void checkTestVector(const char *cipherName, const char *hexKey,
const char *hexKey, const char *hexIv, const char *hexPlaintext,
const char *hexIv,
const char *hexPlaintext,
const char *hexCipher) { const char *hexCipher) {
SCOPED_TRACE(testing::Message() << "Testing cipher: " << cipherName SCOPED_TRACE(testing::Message() << "Testing cipher: " << cipherName
<< ", key = " << hexKey << ", plaintext = " << hexPlaintext); << ", key = " << hexKey
<< ", plaintext = " << hexPlaintext);
auto cipher = T::GetRegistry().CreateForMatch(cipherName); auto cipher = T::GetRegistry().CreateForMatch(cipherName);
ASSERT_TRUE(cipher != NULL); ASSERT_TRUE(cipher != NULL);
CipherKey key(strlen(hexKey)/2); CipherKey key(strlen(hexKey) / 2);
setDataFromHex(key.data(), key.size(), hexKey); setDataFromHex(key.data(), key.size(), hexKey);
ASSERT_TRUE(cipher->setKey(key)); ASSERT_TRUE(cipher->setKey(key));
byte iv[strlen(hexIv)/2]; byte iv[strlen(hexIv) / 2];
setDataFromHex(iv, sizeof(iv), hexIv); setDataFromHex(iv, sizeof(iv), hexIv);
byte plaintext[strlen(hexPlaintext)/2]; byte plaintext[strlen(hexPlaintext) / 2];
setDataFromHex(plaintext, sizeof(plaintext), hexPlaintext); setDataFromHex(plaintext, sizeof(plaintext), hexPlaintext);
byte ciphertext[sizeof(plaintext)]; byte ciphertext[sizeof(plaintext)];
@ -120,45 +115,41 @@ void checkTestVector(const char *cipherName,
TEST_F(BlockCipherTest, TestVectors) { TEST_F(BlockCipherTest, TestVectors) {
// BF128 CBC // BF128 CBC
checkTestVector<BlockCipher>(NAME_BLOWFISH_CBC, checkTestVector<BlockCipher>(
"0123456789abcdeff0e1d2c3b4a59687", NAME_BLOWFISH_CBC, "0123456789abcdeff0e1d2c3b4a59687", "fedcba9876543210",
"fedcba9876543210",
"37363534333231204e6f77206973207468652074696d6520666f722000000000", "37363534333231204e6f77206973207468652074696d6520666f722000000000",
"6b77b4d63006dee605b156e27403979358deb9e7154616d959f1652bd5ff92cc"); "6b77b4d63006dee605b156e27403979358deb9e7154616d959f1652bd5ff92cc");
// BF128 CFB // BF128 CFB
checkTestVector<StreamCipher>(NAME_BLOWFISH_CFB, checkTestVector<StreamCipher>(
"0123456789abcdeff0e1d2c3b4a59687", NAME_BLOWFISH_CFB, "0123456789abcdeff0e1d2c3b4a59687", "fedcba9876543210",
"fedcba9876543210",
"37363534333231204e6f77206973207468652074696d6520666f722000", "37363534333231204e6f77206973207468652074696d6520666f722000",
"e73214a2822139caf26ecf6d2eb9e76e3da3de04d1517200519d57a6c3"); "e73214a2822139caf26ecf6d2eb9e76e3da3de04d1517200519d57a6c3");
// AES128 CBC // AES128 CBC
checkTestVector<BlockCipher>(NAME_AES_CBC, checkTestVector<BlockCipher>(NAME_AES_CBC, "2b7e151628aed2a6abf7158809cf4f3c",
"2b7e151628aed2a6abf7158809cf4f3c", "000102030405060708090a0b0c0d0e0f",
"000102030405060708090a0b0c0d0e0f", "6bc1bee22e409f96e93d7e117393172a",
"6bc1bee22e409f96e93d7e117393172a", "7649abac8119b246cee98e9b12e9197d");
"7649abac8119b246cee98e9b12e9197d");
// AES128 CFB // AES128 CFB
checkTestVector<StreamCipher>(NAME_AES_CFB, checkTestVector<StreamCipher>(
"2b7e151628aed2a6abf7158809cf4f3c", NAME_AES_CFB, "2b7e151628aed2a6abf7158809cf4f3c",
"000102030405060708090a0b0c0d0e0f", "000102030405060708090a0b0c0d0e0f", "6bc1bee22e409f96e93d7e117393172a",
"6bc1bee22e409f96e93d7e117393172a",
"3b3fd92eb72dad20333449f8e83cfb4a"); "3b3fd92eb72dad20333449f8e83cfb4a");
// AES256 CBC // AES256 CBC
checkTestVector<BlockCipher>(NAME_AES_CBC, checkTestVector<BlockCipher>(
NAME_AES_CBC,
"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
"000102030405060708090a0b0c0d0e0f", "000102030405060708090a0b0c0d0e0f", "6bc1bee22e409f96e93d7e117393172a",
"6bc1bee22e409f96e93d7e117393172a",
"f58c4c04d6e5f1ba779eabfb5f7bfbd6"); "f58c4c04d6e5f1ba779eabfb5f7bfbd6");
// AES256 CFB // AES256 CFB
checkTestVector<StreamCipher>(NAME_AES_CFB, checkTestVector<StreamCipher>(
NAME_AES_CFB,
"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
"000102030405060708090a0b0c0d0e0f", "000102030405060708090a0b0c0d0e0f", "6bc1bee22e409f96e93d7e117393172a",
"6bc1bee22e409f96e93d7e117393172a",
"dc7e84bfda79164b7ecd8486985d3860"); "dc7e84bfda79164b7ecd8486985d3860");
} }
@ -168,7 +159,7 @@ TEST_F(BlockCipherTest, BlockEncryptionTest) {
shared_ptr<PBKDF> pbkdf( shared_ptr<PBKDF> pbkdf(
PBKDF::GetRegistry().CreateForMatch(NAME_PBKDF2_HMAC_SHA1)); PBKDF::GetRegistry().CreateForMatch(NAME_PBKDF2_HMAC_SHA1));
list<string> ciphers = registry.GetAll(); list<string> ciphers = registry.GetAll();
for (const string &name : ciphers) { for (const string &name : ciphers) {
const BlockCipher::Properties *properties = const BlockCipher::Properties *properties =
registry.GetProperties(name.c_str()); registry.GetProperties(name.c_str());
@ -179,7 +170,7 @@ TEST_F(BlockCipherTest, BlockEncryptionTest) {
keySize += properties->keySize.inc()) { keySize += properties->keySize.inc()) {
SCOPED_TRACE(testing::Message() << "Key size " << keySize); SCOPED_TRACE(testing::Message() << "Key size " << keySize);
shared_ptr<BlockCipher> cipher (registry.Create(name.c_str())); shared_ptr<BlockCipher> cipher(registry.Create(name.c_str()));
CipherKey key = pbkdf->randomKey(keySize / 8); CipherKey key = pbkdf->randomKey(keySize / 8);
ASSERT_TRUE(key.valid()); ASSERT_TRUE(key.valid());
@ -206,14 +197,14 @@ TEST_F(BlockCipherTest, BlockEncryptionTest) {
MemBlock encrypted; MemBlock encrypted;
encrypted.allocate(16 * blockSize); encrypted.allocate(16 * blockSize);
ASSERT_TRUE(cipher->encrypt(iv.data, mb.data, ASSERT_TRUE(
encrypted.data, 16 * blockSize)); cipher->encrypt(iv.data, mb.data, encrypted.data, 16 * blockSize));
// Decrypt. // Decrypt.
MemBlock decrypted; MemBlock decrypted;
decrypted.allocate(16 * blockSize); decrypted.allocate(16 * blockSize);
ASSERT_TRUE(cipher->decrypt(iv.data, encrypted.data, ASSERT_TRUE(cipher->decrypt(iv.data, encrypted.data, decrypted.data,
decrypted.data, 16 * blockSize)); 16 * blockSize));
compare(mb.data, decrypted.data, 16 * blockSize); compare(mb.data, decrypted.data, 16 * blockSize);
} }

View File

@ -8,7 +8,7 @@
* This program is free software: you can redistribute it and/or modify it under * 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 * 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 * 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 * 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 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
@ -27,67 +27,41 @@
namespace encfs { namespace encfs {
CipherKey::CipherKey() CipherKey::CipherKey() : _valid(false) {}
: _valid(false)
{ CipherKey::CipherKey(int length) : _valid(true) {
if (length > 0) _mem.reset(new SecureMem(length));
} }
CipherKey::CipherKey(int length) CipherKey::CipherKey(const byte *data, int length) : _valid(true) {
: _valid(true)
{
if (length > 0)
_mem.reset(new SecureMem(length));
}
CipherKey::CipherKey(const byte *data, int length)
: _valid(true)
{
_mem.reset(new SecureMem(length)); _mem.reset(new SecureMem(length));
memcpy(_mem->data(), data, length); memcpy(_mem->data(), data, length);
} }
CipherKey::CipherKey(const CipherKey& src) CipherKey::CipherKey(const CipherKey &src)
: _valid(src._valid), : _valid(src._valid), _mem(src._mem) {}
_mem(src._mem)
{
}
CipherKey::~CipherKey() CipherKey::~CipherKey() {}
{
}
void CipherKey::operator = (const CipherKey& src) void CipherKey::operator=(const CipherKey &src) {
{
_mem = src._mem; _mem = src._mem;
_valid = src._valid; _valid = src._valid;
} }
byte *CipherKey::data() const byte *CipherKey::data() const { return !_mem ? NULL : _mem->data(); }
{
return !_mem ? NULL : _mem->data();
}
int CipherKey::size() const int CipherKey::size() const { return !_mem ? 0 : _mem->size(); }
{
return !_mem ? 0 : _mem->size();
}
void CipherKey::reset() void CipherKey::reset() {
{
_mem.reset(); _mem.reset();
_valid = false; _valid = false;
} }
bool CipherKey::valid() const bool CipherKey::valid() const { return _valid; }
{
return _valid;
}
bool operator == (const CipherKey &a, const CipherKey &b) { bool operator==(const CipherKey &a, const CipherKey &b) {
if (a.size() != b.size()) if (a.size() != b.size()) return false;
return false;
return memcmp(a.data(), b.data(), a.size()) == 0; return memcmp(a.data(), b.data(), a.size()) == 0;
} }
} // namespace encfs } // namespace encfs

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -30,16 +30,15 @@ namespace encfs {
class SecureMem; class SecureMem;
class CipherKey class CipherKey {
{
public: public:
CipherKey(); // Creates a key for which valid() returns false. CipherKey(); // Creates a key for which valid() returns false.
explicit CipherKey(int length); explicit CipherKey(int length);
CipherKey(const byte *data, int length); CipherKey(const byte *data, int length);
CipherKey(const CipherKey& src); CipherKey(const CipherKey &src);
~CipherKey(); ~CipherKey();
void operator = (const CipherKey& src); void operator=(const CipherKey &src);
byte *data() const; byte *data() const;
int size() const; int size() const;
@ -54,9 +53,8 @@ class CipherKey
shared_ptr<SecureMem> _mem; shared_ptr<SecureMem> _mem;
}; };
bool operator == (const CipherKey &a, const CipherKey &b); bool operator==(const CipherKey &a, const CipherKey &b);
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -21,9 +21,7 @@ namespace {
class CipherKeyTest : public testing::Test { class CipherKeyTest : public testing::Test {
protected: protected:
virtual void SetUp() { virtual void SetUp() { CipherV1::init(false); }
CipherV1::init(false);
}
}; };
TEST_F(CipherKeyTest, ReadWrite) { TEST_F(CipherKeyTest, ReadWrite) {
@ -49,5 +47,4 @@ TEST_F(CipherKeyTest, ReadWrite) {
} }
} }
} // namespace
} // namespace

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -59,15 +59,12 @@ using std::vector;
namespace encfs { 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 MAX_IVLENGTH = 16;
const int KEY_CHECKSUM_BYTES = 4; const int KEY_CHECKSUM_BYTES = 4;
#ifndef MIN #ifndef MIN
inline int MIN(int a, int b) inline int MIN(int a, int b) { return (a < b) ? a : b; }
{
return (a < b) ? a : b;
}
#endif #endif
void CipherV1::init(bool threaded) { 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 This duplicated some code in OpenSSL, correcting an issue with key lengths
produced for Blowfish. produced for Blowfish.
*/ */
bool BytesToKey(const byte *data, int dataLen, bool BytesToKey(const byte *data, int dataLen, unsigned int rounds,
unsigned int rounds, CipherKey *key) CipherKey *key) {
{
Registry<MAC> registry = MAC::GetRegistry(); Registry<MAC> registry = MAC::GetRegistry();
shared_ptr<MAC> sha1(registry.CreateForMatch("SHA-1")); shared_ptr<MAC> sha1(registry.CreateForMatch("SHA-1"));
if (!sha1) if (!sha1) return false;
return false;
if( data == NULL || dataLen == 0 ) if (data == NULL || dataLen == 0)
return false; // OpenSSL returns nkey here, but why? It is a failure.. return false; // OpenSSL returns nkey here, but why? It is a failure..
SecureMem mdBuf( sha1->outputSize() ); SecureMem mdBuf(sha1->outputSize());
int addmd = 0; int addmd = 0;
int remaining = key->size(); int remaining = key->size();
for(;;) for (;;) {
{
sha1->init(); sha1->init();
if( addmd++ ) if (addmd++) sha1->update(mdBuf.data(), mdBuf.size());
sha1->update(mdBuf.data(), mdBuf.size());
sha1->update(data, dataLen); sha1->update(data, dataLen);
sha1->write(mdBuf.data()); sha1->write(mdBuf.data());
for(unsigned int i=1; i < rounds; ++i) for (unsigned int i = 1; i < rounds; ++i) {
{
sha1->init(); sha1->init();
sha1->update(mdBuf.data(), mdBuf.size()); sha1->update(mdBuf.data(), mdBuf.size());
sha1->write(mdBuf.data()); sha1->write(mdBuf.data());
} }
int offset = 0; int offset = 0;
int toCopy = MIN( remaining, mdBuf.size() - offset ); int toCopy = MIN(remaining, mdBuf.size() - offset);
if( toCopy ) if (toCopy) {
{ memcpy(key->data(), mdBuf.data() + offset, toCopy);
memcpy( key->data(), mdBuf.data()+offset, toCopy );
key += toCopy; key += toCopy;
remaining -= toCopy; remaining -= toCopy;
offset += toCopy; offset += toCopy;
} }
if(remaining == 0) break; if (remaining == 0) break;
} }
return true; 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 + 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, int CipherV1::TimedPBKDF2(const char *pass, int passlen, const byte *salt,
const byte *salt, int saltlen, int saltlen, CipherKey *key, long desiredPDFTime) {
CipherKey *key, long desiredPDFTime)
{
#ifdef HAVE_VALGRIND_MEMCHECK_H #ifdef HAVE_VALGRIND_MEMCHECK_H
VALGRIND_CHECK_MEM_IS_DEFINED(pass, passlen); VALGRIND_CHECK_MEM_IS_DEFINED(pass, passlen);
VALGRIND_CHECK_MEM_IS_DEFINED(salt, saltlen); VALGRIND_CHECK_MEM_IS_DEFINED(salt, saltlen);
#endif #endif
Registry<PBKDF> registry = PBKDF::GetRegistry(); Registry<PBKDF> registry = PBKDF::GetRegistry();
shared_ptr<PBKDF> impl(registry.CreateForMatch(NAME_PBKDF2_HMAC_SHA1)); shared_ptr<PBKDF> impl(registry.CreateForMatch(NAME_PBKDF2_HMAC_SHA1));
if (!impl) if (!impl) return -1;
return -1;
int iter = 1000; int iter = 1000;
timeval start, end; timeval start, end;
for(;;) for (;;) {
{ gettimeofday(&start, 0);
gettimeofday( &start, 0 ); if (!impl->makeKey(pass, passlen, salt, saltlen, iter, key)) return -1;
if (!impl->makeKey(pass, passlen, salt, saltlen, iter, key))
return -1;
gettimeofday( &end, 0 ); gettimeofday(&end, 0);
long delta = time_diff(end, start); long delta = time_diff(end, start);
if(delta < desiredPDFTime / 8) if (delta < desiredPDFTime / 8) {
{
iter *= 4; iter *= 4;
} else if(delta < (5 * desiredPDFTime / 6)) } else if (delta < (5 * desiredPDFTime / 6)) {
{
// estimate number of iterations to get close to desired time // estimate number of iterations to get close to desired time
iter = (int)((double)iter * (double)desiredPDFTime iter = (int)((double)iter * (double)desiredPDFTime / (double)delta);
/ (double)delta);
} else } else
return iter; return iter;
} }
} }
// - Version 1:0 used EVP_BytesToKey, which didn't do the right thing for // - Version 1:0 used EVP_BytesToKey, which didn't do the right thing for
// Blowfish key lengths > 128 bit. // 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 // 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:1 adds support for Message Digest function interface
// - Version 2:2 adds PBKDF2 for password derivation // - Version 2:2 adds PBKDF2 for password derivation
// - Version 3:0 adds a new IV mechanism // - Version 3:0 adds a new IV mechanism
// - Version 3:1 drops support for verison 1:0 blowfish keys, in order to avoid // - 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. // having to duplicate the behavior of old EVP_BytesToKey implementations.
static Interface BlowfishInterface = makeInterface( "ssl/blowfish", 3, 1, 1 ); static Interface BlowfishInterface = makeInterface("ssl/blowfish", 3, 1, 1);
static Interface AESInterface = makeInterface( "ssl/aes", 3, 1, 2 ); 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 int BFDefaultKeyLen = 160;
static Range AESKeyRange(128,256,64); static Range AESKeyRange(128, 256, 64);
static int AESDefaultKeyLen = 192; static int AESDefaultKeyLen = 192;
list<CipherV1::CipherAlgorithm> CipherV1::GetAlgorithmList() list<CipherV1::CipherAlgorithm> CipherV1::GetAlgorithmList() {
{
list<CipherV1::CipherAlgorithm> result; list<CipherV1::CipherAlgorithm> result;
Registry<BlockCipher> blockCipherRegistry = BlockCipher::GetRegistry(); Registry<BlockCipher> blockCipherRegistry = BlockCipher::GetRegistry();
@ -213,7 +193,7 @@ list<CipherV1::CipherAlgorithm> CipherV1::GetAlgorithmList()
alg.iface = AESInterface; alg.iface = AESInterface;
alg.keyLength = AESKeyRange; alg.keyLength = AESKeyRange;
alg.blockSize = Range(64, 4096, 16); alg.blockSize = Range(64, 4096, 16);
result.push_back(alg); result.push_back(alg);
} }
if (blockCipherRegistry.GetPropertiesForMatch(NAME_BLOWFISH_CBC) != NULL) { if (blockCipherRegistry.GetPropertiesForMatch(NAME_BLOWFISH_CBC) != NULL) {
@ -223,7 +203,7 @@ list<CipherV1::CipherAlgorithm> CipherV1::GetAlgorithmList()
alg.iface = BlowfishInterface; alg.iface = BlowfishInterface;
alg.keyLength = BFKeyRange; alg.keyLength = BFKeyRange;
alg.blockSize = Range(64, 4096, 8); alg.blockSize = Range(64, 4096, 8);
result.push_back(alg); result.push_back(alg);
} }
CipherV1::CipherAlgorithm alg; CipherV1::CipherAlgorithm alg;
@ -232,15 +212,14 @@ list<CipherV1::CipherAlgorithm> CipherV1::GetAlgorithmList()
alg.iface = NullCipherInterface; alg.iface = NullCipherInterface;
alg.keyLength = Range(0); alg.keyLength = Range(0);
alg.blockSize = Range(64, 4096, 8); alg.blockSize = Range(64, 4096, 8);
result.push_back(alg); result.push_back(alg);
return result; return result;
} }
shared_ptr<CipherV1> CipherV1::New(const std::string& name, int keyLen) { shared_ptr<CipherV1> CipherV1::New(const std::string &name, int keyLen) {
for (auto &it : GetAlgorithmList()) { for (auto &it : GetAlgorithmList()) {
if (it.name == name) if (it.name == name) return New(it.iface, keyLen);
return New(it.iface, keyLen);
} }
return shared_ptr<CipherV1>(); return shared_ptr<CipherV1>();
@ -248,18 +227,14 @@ shared_ptr<CipherV1> CipherV1::New(const std::string& name, int keyLen) {
shared_ptr<CipherV1> CipherV1::New(const Interface &iface, int keyLen) { shared_ptr<CipherV1> CipherV1::New(const Interface &iface, int keyLen) {
shared_ptr<CipherV1> result(new CipherV1()); shared_ptr<CipherV1> result(new CipherV1());
if (!result->initCiphers(iface, iface, keyLen)) if (!result->initCiphers(iface, iface, keyLen)) result.reset();
result.reset();
return result; return result;
} }
CipherV1::CipherV1() CipherV1::CipherV1() {}
{
}
bool CipherV1::initCiphers(const Interface &iface, const Interface &realIface, bool CipherV1::initCiphers(const Interface &iface, const Interface &realIface,
int keyLength) int keyLength) {
{
this->iface = iface; this->iface = iface;
this->realIface = realIface; this->realIface = realIface;
@ -270,21 +245,20 @@ bool CipherV1::initCiphers(const Interface &iface, const Interface &realIface,
Range keyRange; Range keyRange;
if (implements(AESInterface, iface)) { if (implements(AESInterface, iface)) {
keyRange = AESKeyRange; keyRange = AESKeyRange;
defaultKeyLength = AESDefaultKeyLen; defaultKeyLength = AESDefaultKeyLen;
_blockCipher.reset( blockCipherRegistry.CreateForMatch(NAME_AES_CBC) ); _blockCipher.reset(blockCipherRegistry.CreateForMatch(NAME_AES_CBC));
_streamCipher.reset( streamCipherRegistry.CreateForMatch(NAME_AES_CFB) ); _streamCipher.reset(streamCipherRegistry.CreateForMatch(NAME_AES_CFB));
} else if (implements(BlowfishInterface, iface)) { } else if (implements(BlowfishInterface, iface)) {
keyRange = BFKeyRange; keyRange = BFKeyRange;
defaultKeyLength = BFDefaultKeyLen; defaultKeyLength = BFDefaultKeyLen;
_blockCipher.reset( blockCipherRegistry.CreateForMatch(NAME_BLOWFISH_CBC) ); _blockCipher.reset(blockCipherRegistry.CreateForMatch(NAME_BLOWFISH_CBC));
_streamCipher.reset( streamCipherRegistry.CreateForMatch _streamCipher.reset(streamCipherRegistry.CreateForMatch(NAME_BLOWFISH_CFB));
(NAME_BLOWFISH_CFB) );
} else if (implements(NullCipherInterface, iface)) { } else if (implements(NullCipherInterface, iface)) {
keyRange = Range(0); keyRange = Range(0);
defaultKeyLength = 0; defaultKeyLength = 0;
_blockCipher.reset( blockCipherRegistry.CreateForMatch("NullCipher") ); _blockCipher.reset(blockCipherRegistry.CreateForMatch("NullCipher"));
_streamCipher.reset( streamCipherRegistry.CreateForMatch("NullCipher") ); _streamCipher.reset(streamCipherRegistry.CreateForMatch("NullCipher"));
} }
if (!_blockCipher || !_streamCipher) { if (!_blockCipher || !_streamCipher) {
@ -297,8 +271,7 @@ bool CipherV1::initCiphers(const Interface &iface, const Interface &realIface,
else else
_keySize = keyRange.closest(keyLength) / 8; _keySize = keyRange.closest(keyLength) / 8;
_pbkdf.reset(PBKDF::GetRegistry().CreateForMatch( _pbkdf.reset(PBKDF::GetRegistry().CreateForMatch(NAME_PBKDF2_HMAC_SHA1));
NAME_PBKDF2_HMAC_SHA1));
if (!_pbkdf) { if (!_pbkdf) {
LOG(ERROR) << "PBKDF missing"; LOG(ERROR) << "PBKDF missing";
return false; return false;
@ -322,14 +295,9 @@ bool CipherV1::initCiphers(const Interface &iface, const Interface &realIface,
return true; return true;
} }
CipherV1::~CipherV1() CipherV1::~CipherV1() {}
{
}
Interface CipherV1::interface() const Interface CipherV1::interface() const { return realIface; }
{
return realIface;
}
/* /*
Create a key from the password. Create a key from the password.
@ -340,33 +308,27 @@ Interface CipherV1::interface() const
*/ */
CipherKey CipherV1::newKey(const char *password, int passwdLength, CipherKey CipherV1::newKey(const char *password, int passwdLength,
int *iterationCount, long desiredDuration, int *iterationCount, long desiredDuration,
const byte *salt, int saltLen) const byte *salt, int saltLen) {
{
#ifdef HAVE_VALGRIND_MEMCHECK_H #ifdef HAVE_VALGRIND_MEMCHECK_H
VALGRIND_CHECK_MEM_IS_DEFINED(password, passwdLength); VALGRIND_CHECK_MEM_IS_DEFINED(password, passwdLength);
VALGRIND_CHECK_MEM_IS_DEFINED(salt, saltLen); VALGRIND_CHECK_MEM_IS_DEFINED(salt, saltLen);
#endif #endif
CipherKey key(_keySize + _ivLength); CipherKey key(_keySize + _ivLength);
if(*iterationCount == 0) if (*iterationCount == 0) {
{
// timed run, fills in iteration count // timed run, fills in iteration count
int res = TimedPBKDF2(password, passwdLength, int res = TimedPBKDF2(password, passwdLength, salt, saltLen, &key,
salt, saltLen, &key,
1000 * desiredDuration); 1000 * desiredDuration);
if(res <= 0) if (res <= 0) {
{
LOG(ERROR) << "openssl error, PBKDF2 failed"; LOG(ERROR) << "openssl error, PBKDF2 failed";
return CipherKey(); return CipherKey();
} else { } else {
*iterationCount = res; *iterationCount = res;
} }
} else } else {
{
// known iteration length // known iteration length
if (!_pbkdf->makeKey(password, passwdLength, if (!_pbkdf->makeKey(password, passwdLength, salt, saltLen, *iterationCount,
salt, saltLen, *iterationCount, &key)) &key)) {
{
LOG(ERROR) << "openssl error, PBKDF2 failed"; LOG(ERROR) << "openssl error, PBKDF2 failed";
return CipherKey(); 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. // Deprecated - for use only with filesystems which used a fixed-round PBKDF.
// Such configurations are replaced with a new PBKDF2 implementation when the // Such configurations are replaced with a new PBKDF2 implementation when the
// password is changed or configuration is rewritten. // 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 #ifdef HAVE_VALGRIND_MEMCHECK_H
VALGRIND_CHECK_MEM_IS_DEFINED(password, passwdLength); VALGRIND_CHECK_MEM_IS_DEFINED(password, passwdLength);
#endif #endif
@ -387,37 +348,33 @@ CipherKey CipherV1::newKey(const char *password, int passwdLength)
bool ok = BytesToKey((byte *)password, passwdLength, 16, &key); bool ok = BytesToKey((byte *)password, passwdLength, 16, &key);
LOG_IF(ERROR, !ok) << "newKey: BytesToKey failed"; LOG_IF(ERROR, !ok) << "newKey: BytesToKey failed";
if (!ok) if (!ok) throw Error("BytesToKey failed");
throw Error("BytesToKey failed");
return key; return key;
} }
CipherKey CipherV1::newRandomKey() CipherKey CipherV1::newRandomKey() {
{
return _pbkdf->randomKey(_keySize + _ivLength); return _pbkdf->randomKey(_keySize + _ivLength);
} }
bool CipherV1::pseudoRandomize( byte *buf, int len ) bool CipherV1::pseudoRandomize(byte *buf, int len) {
{
return _pbkdf->pseudoRandom(buf, len); return _pbkdf->pseudoRandom(buf, len);
} }
bool CipherV1::setKey(const CipherKey &keyIv) { bool CipherV1::setKey(const CipherKey &keyIv) {
Lock l(_hmacMutex); Lock l(_hmacMutex);
LOG_IF(ERROR, (int)(_keySize + _ivLength) != keyIv.size()) LOG_IF(ERROR, (int)(_keySize + _ivLength) != keyIv.size())
<< "Mismatched key size: passed " << "Mismatched key size: passed " << keyIv.size() << ", expecting "
<< keyIv.size() << ", expecting " << _keySize; << _keySize;
// Key is actually key plus iv, so extract the different parts. // Key is actually key plus iv, so extract the different parts.
CipherKey key(_keySize); CipherKey key(_keySize);
memcpy(key.data(), keyIv.data(), _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) if (_blockCipher->setKey(key) && _streamCipher->setKey(key) &&
&& _streamCipher->setKey(key) _hmac->setKey(key)) {
&& _hmac->setKey(key)) {
_keySet = true; _keySet = true;
return 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 CipherV1::MAC_64(const byte *data, int len,
uint64_t *chainedIV ) const uint64_t *chainedIV) const {
{ rAssert(len > 0);
rAssert( len > 0 ); rAssert(_keySet);
rAssert( _keySet );
byte md[_hmac->outputSize()]; byte md[_hmac->outputSize()];
Lock l(_hmacMutex); Lock l(_hmacMutex);
_hmac->init(); _hmac->init();
_hmac->update(data, len); _hmac->update(data, len);
if(chainedIV) if (chainedIV) {
{
// toss in the chained IV as well // toss in the chained IV as well
uint64_t tmp = *chainedIV; uint64_t tmp = *chainedIV;
byte h[8]; byte h[8];
for(unsigned int i=0; i<8; ++i) for (unsigned int i = 0; i < 8; ++i) {
{
h[i] = tmp & 0xff; h[i] = tmp & 0xff;
tmp >>= 8; tmp >>= 8;
} }
@ -455,174 +409,151 @@ uint64_t CipherV1::MAC_64(const byte *data, int len,
rAssert(ok); rAssert(ok);
// chop this down to a 64bit value.. // 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 // XXX: the last byte off the hmac isn't used. This minor inconsistency
// must be maintained in order to maintain backward compatiblity with earlier // must be maintained in order to maintain backward compatiblity with earlier
// releases. // releases.
for(int i=0; i<_hmac->outputSize()-1; ++i) for (int i = 0; i < _hmac->outputSize() - 1; ++i) h[i % 8] ^= (byte)(md[i]);
h[i%8] ^= (byte)(md[i]);
uint64_t value = (uint64_t)h[0]; uint64_t value = (uint64_t)h[0];
for(int i=1; i<8; ++i) for (int i = 1; i < 8; ++i) value = (value << 8) | (uint64_t)h[i];
value = (value << 8) | (uint64_t)h[i];
// TODO: should not be here. // TODO: should not be here.
if(chainedIV) if (chainedIV) *chainedIV = value;
*chainedIV = value;
return value; return value;
} }
unsigned int CipherV1::reduceMac32(uint64_t mac64) unsigned int CipherV1::reduceMac32(uint64_t mac64) {
{
return ((mac64 >> 32) & 0xffffffff) ^ (mac64 & 0xffffffff); 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); unsigned int mac32 = reduceMac32(mac64);
return ((mac32 >> 16) & 0xffff) ^ (mac32 & 0xffff); return ((mac32 >> 16) & 0xffff) ^ (mac32 & 0xffff);
} }
CipherKey CipherV1::readKey(const byte *data, bool checkKey) CipherKey CipherV1::readKey(const byte *data, bool checkKey) {
{ rAssert(_keySet);
rAssert( _keySet );
CipherKey key(_keySize + _ivLength); CipherKey key(_keySize + _ivLength);
// First N bytes are checksum bytes. // First N bytes are checksum bytes.
unsigned int checksum = 0; unsigned int checksum = 0;
for(int i=0; i<KEY_CHECKSUM_BYTES; ++i) for (int i = 0; i < KEY_CHECKSUM_BYTES; ++i)
checksum = (checksum << 8) | (unsigned int)data[i]; checksum = (checksum << 8) | (unsigned int)data[i];
memcpy( key.data(), data+KEY_CHECKSUM_BYTES, key.size() ); memcpy(key.data(), data + KEY_CHECKSUM_BYTES, key.size());
if (!streamDecode(key.data(), key.size(), checksum)) { if (!streamDecode(key.data(), key.size(), checksum)) {
LOG(ERROR) << "stream decode failure"; LOG(ERROR) << "stream decode failure";
return CipherKey(); return CipherKey();
} }
// check for success // check for success
#ifdef HAVE_VALGRIND_MEMCHECK_H #ifdef HAVE_VALGRIND_MEMCHECK_H
VALGRIND_CHECK_MEM_IS_DEFINED(key.data(), key.size()); VALGRIND_CHECK_MEM_IS_DEFINED(key.data(), key.size());
#endif #endif
unsigned int checksum2 = reduceMac32( unsigned int checksum2 = reduceMac32(MAC_64(key.data(), key.size(), NULL));
MAC_64( key.data(), key.size(), NULL ));
#ifdef HAVE_VALGRIND_MEMCHECK_H #ifdef HAVE_VALGRIND_MEMCHECK_H
VALGRIND_CHECK_VALUE_IS_DEFINED(checksum2); VALGRIND_CHECK_VALUE_IS_DEFINED(checksum2);
VALGRIND_CHECK_VALUE_IS_DEFINED(checksum); VALGRIND_CHECK_VALUE_IS_DEFINED(checksum);
#endif #endif
if(checkKey && (checksum2 != checksum)) if (checkKey && (checksum2 != checksum)) {
{ LOG(INFO) << "checksum mismatch: expected " << checksum << ", got "
LOG(INFO) << "checksum mismatch: expected " << checksum << checksum2 << "on decode of " << _keySize + _ivLength
<< ", got " << checksum2 << " bytes";
<< "on decode of " << _keySize + _ivLength << " bytes";
return CipherKey(); return CipherKey();
} }
return key; return key;
} }
void CipherV1::writeKey(const CipherKey &ckey, byte *out) void CipherV1::writeKey(const CipherKey &ckey, byte *out) {
{ rAssert(_keySet);
rAssert( _keySet );
SecureMem tmpBuf(ckey.size()); SecureMem tmpBuf(ckey.size());
memcpy(tmpBuf.data(), ckey.data(), tmpBuf.size()); memcpy(tmpBuf.data(), ckey.data(), tmpBuf.size());
unsigned int checksum = reduceMac32( unsigned int checksum =
MAC_64(tmpBuf.data(), tmpBuf.size(), NULL)); reduceMac32(MAC_64(tmpBuf.data(), tmpBuf.size(), NULL));
streamEncode(tmpBuf.data(), tmpBuf.size(), checksum); streamEncode(tmpBuf.data(), tmpBuf.size(), checksum);
// first N bytes contain HMAC derived checksum.. // first N bytes contain HMAC derived checksum..
for(int i=1; i<=KEY_CHECKSUM_BYTES; ++i) for (int i = 1; i <= KEY_CHECKSUM_BYTES; ++i) {
{ out[KEY_CHECKSUM_BYTES - i] = checksum & 0xff;
out[KEY_CHECKSUM_BYTES-i] = checksum & 0xff;
checksum >>= 8; 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) std::string CipherV1::encodeAsString(const CipherKey &key) {
{ rAssert(_keySet);
rAssert( _keySet );
int encodedSize = encodedKeySize(); int encodedSize = encodedKeySize();
vector<byte> buf(encodedSize); vector<byte> buf(encodedSize);
writeKey(key, buf.data()); writeKey(key, buf.data());
int b64Len = B256ToB64Bytes( encodedSize ); int b64Len = B256ToB64Bytes(encodedSize);
byte *b64Key = new byte[b64Len + 1]; byte *b64Key = new byte[b64Len + 1];
changeBase2( buf.data(), encodedSize, 8, b64Key, b64Len, 6); changeBase2(buf.data(), encodedSize, 8, b64Key, b64Len, 6);
B64ToAscii( b64Key, b64Len ); B64ToAscii(b64Key, b64Len);
b64Key[ b64Len - 1 ] = '\0'; 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; return _keySize + _ivLength + KEY_CHECKSUM_BYTES;
} }
int CipherV1::keySize() const int CipherV1::keySize() const { return _keySize; }
{
return _keySize;
}
int CipherV1::cipherBlockSize() const int CipherV1::cipherBlockSize() const { return _blockCipher->blockSize(); }
{
return _blockCipher->blockSize();
}
// Deprecated: For backward compatibility only. // Deprecated: For backward compatibility only.
// A watermark attack was published against this data-independent IV schedule. // A watermark attack was published against this data-independent IV schedule.
// The replacement incorporates the filesystem key, making it unique to each // The replacement incorporates the filesystem key, making it unique to each
// filesystem. // filesystem.
static void setIVec_old(byte *ivec, int ivLen, unsigned int seed) static void setIVec_old(byte *ivec, int ivLen, unsigned int seed) {
{ unsigned int var1 = 0x060a4011 * seed;
unsigned int var1 = 0x060a4011 * seed;
unsigned int var2 = 0x0221040d * (seed ^ 0xD3FEA11C); unsigned int var2 = 0x0221040d * (seed ^ 0xD3FEA11C);
ivec[0] ^= (var1 >> 24) & 0xff; ivec[0] ^= (var1 >> 24) & 0xff;
ivec[1] ^= (var2 >> 16) & 0xff; ivec[1] ^= (var2 >> 16) & 0xff;
ivec[2] ^= (var1 >> 8 ) & 0xff; ivec[2] ^= (var1 >> 8) & 0xff;
ivec[3] ^= (var2 ) & 0xff; ivec[3] ^= (var2) & 0xff;
ivec[4] ^= (var2 >> 24) & 0xff; ivec[4] ^= (var2 >> 24) & 0xff;
ivec[5] ^= (var1 >> 16) & 0xff; ivec[5] ^= (var1 >> 16) & 0xff;
ivec[6] ^= (var2 >> 8 ) & 0xff; ivec[6] ^= (var2 >> 8) & 0xff;
ivec[7] ^= (var1 ) & 0xff; ivec[7] ^= (var1) & 0xff;
if(ivLen > 8) if (ivLen > 8) {
{ ivec[8 + 0] ^= (var1) & 0xff;
ivec[8+0] ^= (var1 ) & 0xff; ivec[8 + 1] ^= (var2 >> 8) & 0xff;
ivec[8+1] ^= (var2 >> 8 ) & 0xff; ivec[8 + 2] ^= (var1 >> 16) & 0xff;
ivec[8+2] ^= (var1 >> 16) & 0xff; ivec[8 + 3] ^= (var2 >> 24) & 0xff;
ivec[8+3] ^= (var2 >> 24) & 0xff; ivec[8 + 4] ^= (var1 >> 24) & 0xff;
ivec[8+4] ^= (var1 >> 24) & 0xff; ivec[8 + 5] ^= (var2 >> 16) & 0xff;
ivec[8+5] ^= (var2 >> 16) & 0xff; ivec[8 + 6] ^= (var1 >> 8) & 0xff;
ivec[8+6] ^= (var1 >> 8 ) & 0xff; ivec[8 + 7] ^= (var2) & 0xff;
ivec[8+7] ^= (var2 ) & 0xff;
} }
} }
void CipherV1::setIVec(byte *ivec, uint64_t seed) const void CipherV1::setIVec(byte *ivec, uint64_t seed) const {
{ rAssert(_keySet);
rAssert( _keySet ); memcpy(ivec, _iv->data(), _ivLength);
memcpy( ivec, _iv->data(), _ivLength ); if (iface.major() < 3) {
if (iface.major() < 3)
{
// Backward compatible mode. // Backward compatible mode.
setIVec_old(ivec, _ivLength, seed); setIVec_old(ivec, _ivLength, seed);
return; return;
} }
vector<byte> md(_hmac->outputSize()); vector<byte> md(_hmac->outputSize());
for(int i=0; i<8; ++i) for (int i = 0; i < 8; ++i) {
{
md[i] = (byte)(seed & 0xff); md[i] = (byte)(seed & 0xff);
seed >>= 8; seed >>= 8;
} }
@ -637,102 +568,86 @@ void CipherV1::setIVec(byte *ivec, uint64_t seed) const
memcpy(ivec, md.data(), _ivLength); memcpy(ivec, md.data(), _ivLength);
} }
static void flipBytes(byte *buf, int size) static void flipBytes(byte *buf, int size) {
{
byte revBuf[64]; byte revBuf[64];
int bytesLeft = size; int bytesLeft = size;
while(bytesLeft) while (bytesLeft) {
{ int toFlip = MIN((int)sizeof(revBuf), bytesLeft);
int toFlip = MIN( (int)sizeof(revBuf), bytesLeft );
for(int i=0; i<toFlip; ++i) for (int i = 0; i < toFlip; ++i) revBuf[i] = buf[toFlip - (i + 1)];
revBuf[i] = buf[toFlip - (i+1)];
memcpy( buf, revBuf, toFlip ); memcpy(buf, revBuf, toFlip);
bytesLeft -= toFlip; bytesLeft -= toFlip;
buf += toFlip; buf += toFlip;
} }
memset(revBuf, 0, sizeof(revBuf)); memset(revBuf, 0, sizeof(revBuf));
} }
static void shuffleBytes(byte *buf, int size) static void shuffleBytes(byte *buf, int size) {
{ for (int i = 0; i < size - 1; ++i) buf[i + 1] ^= buf[i];
for(int i=0; i<size-1; ++i)
buf[i+1] ^= buf[i];
} }
static void unshuffleBytes(byte *buf, int size) static void unshuffleBytes(byte *buf, int size) {
{ for (int i = size - 1; i; --i) buf[i] ^= buf[i - 1];
for(int i=size-1; i; --i)
buf[i] ^= buf[i-1];
} }
/* Partial blocks are encoded with a stream cipher. We make multiple passes on /* Partial blocks are encoded with a stream cipher. We make multiple passes on
the data to ensure that the ends of the data depend on each other. the data to ensure that the ends of the data depend on each other.
*/ */
bool CipherV1::streamEncode(byte *buf, int size, uint64_t iv64) const bool CipherV1::streamEncode(byte *buf, int size, uint64_t iv64) const {
{ rAssert(_keySet);
rAssert( _keySet ); rAssert(size > 0);
rAssert( size > 0 );
vector<byte> ivec(_ivLength); vector<byte> ivec(_ivLength);
shuffleBytes( buf, size ); shuffleBytes(buf, size);
setIVec( ivec.data(), iv64 ); setIVec(ivec.data(), iv64);
if (!_streamCipher->encrypt(ivec.data(), buf, buf, size)) if (!_streamCipher->encrypt(ivec.data(), buf, buf, size)) return false;
return false;
flipBytes( buf, size ); flipBytes(buf, size);
shuffleBytes( buf, size ); shuffleBytes(buf, size);
setIVec( ivec.data(), iv64 + 1 ); setIVec(ivec.data(), iv64 + 1);
if (!_streamCipher->encrypt(ivec.data(), buf, buf, size)) if (!_streamCipher->encrypt(ivec.data(), buf, buf, size)) return false;
return false;
return true; return true;
} }
bool CipherV1::streamDecode(byte *buf, int size, uint64_t iv64) const bool CipherV1::streamDecode(byte *buf, int size, uint64_t iv64) const {
{ rAssert(_keySet);
rAssert( _keySet ); rAssert(size > 0);
rAssert( size > 0 );
vector<byte> ivec(_ivLength); vector<byte> ivec(_ivLength);
setIVec( ivec.data(), iv64 + 1 ); setIVec(ivec.data(), iv64 + 1);
if (!_streamCipher->decrypt(ivec.data(), buf, buf, size)) if (!_streamCipher->decrypt(ivec.data(), buf, buf, size)) return false;
return false;
unshuffleBytes( buf, size ); unshuffleBytes(buf, size);
flipBytes( buf, size ); flipBytes(buf, size);
setIVec( ivec.data(), iv64 ); setIVec(ivec.data(), iv64);
if (!_streamCipher->decrypt(ivec.data(), buf, buf, size)) if (!_streamCipher->decrypt(ivec.data(), buf, buf, size)) return false;
return false;
unshuffleBytes( buf, size ); unshuffleBytes(buf, size);
return true; return true;
} }
bool CipherV1::blockEncode(byte *buf, int size, uint64_t iv64) const {
bool CipherV1::blockEncode(byte *buf, int size, uint64_t iv64) const rAssert(_keySet);
{ rAssert(size > 0);
rAssert( _keySet );
rAssert( size > 0 );
vector<byte> ivec(_ivLength); vector<byte> ivec(_ivLength);
setIVec( ivec.data(), iv64 ); setIVec(ivec.data(), iv64);
return _blockCipher->encrypt(ivec.data(), buf, buf, size); return _blockCipher->encrypt(ivec.data(), buf, buf, size);
} }
bool CipherV1::blockDecode(byte *buf, int size, uint64_t iv64) const bool CipherV1::blockDecode(byte *buf, int size, uint64_t iv64) const {
{ rAssert(_keySet);
rAssert( _keySet ); rAssert(size > 0);
rAssert( size > 0 );
vector<byte> ivec(_ivLength); vector<byte> ivec(_ivLength);
setIVec( ivec.data(), iv64 ); setIVec(ivec.data(), iv64);
return _blockCipher->decrypt(ivec.data(), buf, buf, size); return _blockCipher->decrypt(ivec.data(), buf, buf, size);
} }

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * 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 initial value vector to randomize the output. But it makes the code
simpler to reuse the encryption algorithm as is. simpler to reuse the encryption algorithm as is.
*/ */
class CipherV1 class CipherV1 {
{
Interface iface; Interface iface;
Interface realIface; Interface realIface;
@ -85,16 +84,14 @@ class CipherV1
mutable Mutex _hmacMutex; mutable Mutex _hmacMutex;
mutable shared_ptr<MAC> _hmac; mutable shared_ptr<MAC> _hmac;
unsigned int _keySize; // in bytes unsigned int _keySize; // in bytes
unsigned int _ivLength; unsigned int _ivLength;
shared_ptr<SecureMem> _iv; shared_ptr<SecureMem> _iv;
bool _keySet; bool _keySet;
public: public:
struct CipherAlgorithm {
struct CipherAlgorithm
{
std::string name; std::string name;
std::string description; std::string description;
Interface iface; Interface iface;
@ -113,23 +110,22 @@ class CipherV1
// Password-based key derivation function which determines the // Password-based key derivation function which determines the
// number of iterations based on a desired execution time (in microseconds). // number of iterations based on a desired execution time (in microseconds).
// Returns the number of iterations applied. // Returns the number of iterations applied.
static int TimedPBKDF2(const char *pass, int passLen, static int TimedPBKDF2(const char *pass, int passLen, const byte *salt,
const byte *salt, int saltLen, int saltLen, CipherKey *out,
CipherKey *out, long desiredPDFTimeMicroseconds); long desiredPDFTimeMicroseconds);
CipherV1(); CipherV1();
~CipherV1(); ~CipherV1();
bool initCiphers(const Interface &iface, bool initCiphers(const Interface &iface, const Interface &realIface,
const Interface &realIface, int keyLength); int keyLength);
// returns the real interface, not the one we're emulating (if any).. // returns the real interface, not the one we're emulating (if any)..
Interface interface() const; Interface interface() const;
// create a new key based on a password // create a new key based on a password
CipherKey newKey(const char *password, int passwdLength, CipherKey newKey(const char *password, int passwdLength, int *iterationCount,
int *iterationCount, long desiredDuration, long desiredDuration, const byte *salt, int saltLen);
const byte *salt, int saltLen);
// deprecated - for backward compatibility // deprecated - for backward compatibility
CipherKey newKey(const char *password, int passwdLength); CipherKey newKey(const char *password, int passwdLength);
// create a new random key // create a new random key
@ -140,11 +136,10 @@ class CipherV1
CipherKey readKey(const byte *data, bool checkKey); CipherKey readKey(const byte *data, bool checkKey);
// Encrypt and write the given key. // 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. // Encrypt and store a key as a string.
std::string encodeAsString(const CipherKey &key); std::string encodeAsString(const CipherKey &key);
// meta-data about the cypher // meta-data about the cypher
int keySize() const; int keySize() const;
@ -156,8 +151,7 @@ class CipherV1
// Sets the key used for encoding / decoding, and MAC operations. // Sets the key used for encoding / decoding, and MAC operations.
bool setKey(const CipherKey &key); bool setKey(const CipherKey &key);
uint64_t MAC_64(const byte *src, int len, uint64_t MAC_64(const byte *src, int len, uint64_t *augment = NULL) const;
uint64_t *augment = NULL) const;
static unsigned int reduceMac32(uint64_t mac64); static unsigned int reduceMac32(uint64_t mac64);
static unsigned int reduceMac16(uint64_t mac64); static unsigned int reduceMac16(uint64_t mac64);
@ -184,4 +178,3 @@ class CipherV1
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -8,7 +8,7 @@
* This program is free software: you can redistribute it and/or modify it under * 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 * 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 * 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 * 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 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
@ -42,18 +42,16 @@ namespace commoncrypto {
class PbkdfPkcs5Hmac : public PBKDF { class PbkdfPkcs5Hmac : public PBKDF {
CCPseudoRandomAlgorithm prf_; CCPseudoRandomAlgorithm prf_;
public:
PbkdfPkcs5Hmac(CCPseudoRandomAlgorithm prf) public:
: prf_(prf) {} PbkdfPkcs5Hmac(CCPseudoRandomAlgorithm prf) : prf_(prf) {}
virtual ~PbkdfPkcs5Hmac() {} virtual ~PbkdfPkcs5Hmac() {}
virtual bool makeKey(const char *password, int passwordLength, virtual bool makeKey(const char *password, int passwordLength,
const byte *salt, int saltLength, const byte *salt, int saltLength, int numIterations,
int numIterations,
CipherKey *outKey) { CipherKey *outKey) {
int ret = CCKeyDerivationPBKDF(kCCPBKDF2, password, passwordLength, int ret = CCKeyDerivationPBKDF(kCCPBKDF2, password, passwordLength, salt,
salt, saltLength, prf_, saltLength, prf_, numIterations,
numIterations,
outKey->data(), outKey->size()); outKey->data(), outKey->size());
if (ret != 0) { if (ret != 0) {
PLOG(ERROR) << "CCKeyDerivationPBKDF failed"; PLOG(ERROR) << "CCKeyDerivationPBKDF failed";
@ -75,7 +73,7 @@ public:
#endif #endif
return key; return key;
} }
virtual bool pseudoRandom(byte *out, int length) { virtual bool pseudoRandom(byte *out, int length) {
if (length == 0) return true; if (length == 0) return true;
#ifdef HAVE_SEC_RANDOM_H #ifdef HAVE_SEC_RANDOM_H
@ -90,9 +88,8 @@ public:
} }
}; };
class PbkdfPkcs5HmacSha1CC : public PbkdfPkcs5Hmac { class PbkdfPkcs5HmacSha1CC : public PbkdfPkcs5Hmac {
public: public:
PbkdfPkcs5HmacSha1CC() : PbkdfPkcs5Hmac(kCCPRFHmacAlgSHA1) {} PbkdfPkcs5HmacSha1CC() : PbkdfPkcs5Hmac(kCCPRFHmacAlgSHA1) {}
~PbkdfPkcs5HmacSha1CC() {} ~PbkdfPkcs5HmacSha1CC() {}
@ -106,7 +103,7 @@ public:
REGISTER_CLASS(PbkdfPkcs5HmacSha1CC, PBKDF); REGISTER_CLASS(PbkdfPkcs5HmacSha1CC, PBKDF);
class PbkdfPkcs5HmacSha256CC : public PbkdfPkcs5Hmac { class PbkdfPkcs5HmacSha256CC : public PbkdfPkcs5Hmac {
public: public:
PbkdfPkcs5HmacSha256CC() : PbkdfPkcs5Hmac(kCCPRFHmacAlgSHA256) {} PbkdfPkcs5HmacSha256CC() : PbkdfPkcs5Hmac(kCCPRFHmacAlgSHA256) {}
~PbkdfPkcs5HmacSha256CC() {} ~PbkdfPkcs5HmacSha256CC() {}
@ -123,9 +120,10 @@ class CCCipher : public BlockCipher {
CipherKey key; CipherKey key;
CCAlgorithm algorithm; CCAlgorithm algorithm;
CCMode mode; CCMode mode;
public: public:
CCCipher() { } CCCipher() {}
virtual ~CCCipher() { } virtual ~CCCipher() {}
bool rekey(const CipherKey &key, CCAlgorithm algorithm, CCMode mode) { bool rekey(const CipherKey &key, CCAlgorithm algorithm, CCMode mode) {
this->key = key; this->key = key;
@ -136,20 +134,18 @@ class CCCipher : public BlockCipher {
virtual bool encrypt(const byte *iv, const byte *in, byte *out, int size) { virtual bool encrypt(const byte *iv, const byte *in, byte *out, int size) {
CCCryptorRef cryptor; CCCryptorRef cryptor;
CCCryptorCreateWithMode(kCCEncrypt, mode, algorithm, 0, CCCryptorCreateWithMode(kCCEncrypt, mode, algorithm, 0, iv, key.data(),
iv, key.data(), key.size(), key.size(), NULL, 0, 0, 0, &cryptor);
NULL, 0, 0, 0, &cryptor);
size_t updateLength = 0; size_t updateLength = 0;
CCCryptorUpdate(cryptor, in, size, out, size, &updateLength); CCCryptorUpdate(cryptor, in, size, out, size, &updateLength);
CCCryptorRelease(cryptor); CCCryptorRelease(cryptor);
return true; return true;
} }
virtual bool decrypt(const byte *iv, const byte *in, byte *out, int size) { virtual bool decrypt(const byte *iv, const byte *in, byte *out, int size) {
CCCryptorRef cryptor; CCCryptorRef cryptor;
CCCryptorCreateWithMode(kCCDecrypt, mode, algorithm, 0, CCCryptorCreateWithMode(kCCDecrypt, mode, algorithm, 0, iv, key.data(),
iv, key.data(), key.size(), key.size(), NULL, 0, 0, 0, &cryptor);
NULL, 0, 0, 0, &cryptor);
size_t updateLength = 0; size_t updateLength = 0;
CCCryptorUpdate(cryptor, in, size, out, size, &updateLength); CCCryptorUpdate(cryptor, in, size, out, size, &updateLength);
CCCryptorRelease(cryptor); CCCryptorRelease(cryptor);
@ -166,12 +162,10 @@ class BfCbc : public CCCipher {
return CCCipher::rekey(key, kCCAlgorithmBlowfish, kCCModeCBC); return CCCipher::rekey(key, kCCAlgorithmBlowfish, kCCModeCBC);
} }
virtual int blockSize() const { virtual int blockSize() const { return kCCBlockSizeBlowfish; }
return kCCBlockSizeBlowfish;
}
static Properties GetProperties() { 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); REGISTER_CLASS(BfCbc, BlockCipher);
@ -184,13 +178,11 @@ class AesCbc : public CCCipher {
virtual bool setKey(const CipherKey &key) { virtual bool setKey(const CipherKey &key) {
return CCCipher::rekey(key, kCCAlgorithmAES128, kCCModeCBC); return CCCipher::rekey(key, kCCAlgorithmAES128, kCCModeCBC);
} }
virtual int blockSize() const { virtual int blockSize() const { return kCCBlockSizeAES128; }
return kCCBlockSizeAES128;
}
static Properties GetProperties() { 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); REGISTER_CLASS(AesCbc, BlockCipher);
@ -207,7 +199,7 @@ class BfCfb : public CCCipher {
virtual int blockSize() const { return 1; } virtual int blockSize() const { return 1; }
static Properties GetProperties() { 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); REGISTER_CLASS(BfCfb, StreamCipher);
@ -220,11 +212,11 @@ class AesCfb : public CCCipher {
virtual bool setKey(const CipherKey &key) { virtual bool setKey(const CipherKey &key) {
return CCCipher::rekey(key, kCCAlgorithmAES128, kCCModeCFB); return CCCipher::rekey(key, kCCAlgorithmAES128, kCCModeCFB);
} }
virtual int blockSize() const { return 1; } virtual int blockSize() const { return 1; }
static Properties GetProperties() { 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); REGISTER_CLASS(AesCfb, StreamCipher);
@ -234,9 +226,7 @@ class Sha1HMac : public MAC {
Sha1HMac() {} Sha1HMac() {}
virtual ~Sha1HMac() {} virtual ~Sha1HMac() {}
virtual int outputSize() const { virtual int outputSize() const { return CC_SHA1_DIGEST_LENGTH; }
return CC_SHA1_DIGEST_LENGTH;
}
virtual bool setKey(const CipherKey &key) { virtual bool setKey(const CipherKey &key) {
this->key = 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); CCHmacUpdate(&ctx, in, length);
return true; return true;
} }
@ -280,7 +270,6 @@ REGISTER_CLASS(Sha1HMac, MAC);
} // namespace commoncrypto } // namespace commoncrypto
void CommonCrypto::registerCiphers() { void CommonCrypto::registerCiphers() {}
}
} // namespace encfs } // namespace encfs

View File

@ -8,7 +8,7 @@
* This program is free software: you can redistribute it and/or modify it under * 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 * 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 * 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 * 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 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
@ -30,6 +30,4 @@ struct CommonCrypto {
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -4,13 +4,8 @@ namespace encfs {
DEFINE_REGISTERABLE_TYPE(MAC) DEFINE_REGISTERABLE_TYPE(MAC)
MAC::MAC() MAC::MAC() {}
{
}
MAC::~MAC() MAC::~MAC() {}
{
}
} // namespace encfs } // namespace encfs

View File

@ -12,35 +12,32 @@ namespace encfs {
static const char NAME_SHA1_HMAC[] = "SHA-1/HMAC"; static const char NAME_SHA1_HMAC[] = "SHA-1/HMAC";
// MAC provides keyed MessageAuthenticationCode algorithms, eg HMAC. // MAC provides keyed MessageAuthenticationCode algorithms, eg HMAC.
class MAC class MAC {
{
public: public:
DECLARE_REGISTERABLE_TYPE(MAC); DECLARE_REGISTERABLE_TYPE(MAC);
struct Properties { struct Properties {
int blockSize; // Block length of hash function. int blockSize; // Block length of hash function.
std::string hashFunction; std::string hashFunction;
std::string mode; std::string mode;
std::string library; std::string library;
std::string toString() const { std::string toString() const { return hashFunction + "/" + mode; }
return hashFunction + "/" + mode;
}
}; };
MAC(); MAC();
virtual ~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. // Init must be called before any calls to update.
virtual void init() =0; virtual void init() = 0;
virtual bool update(const byte *in, int length) =0; virtual bool update(const byte *in, int length) = 0;
virtual bool write(byte *out) =0; virtual bool write(byte *out) = 0;
}; };
} // namespace encfs } // namespace encfs
#endif // ENCFS_MAC_H #endif // ENCFS_MAC_H

View File

@ -8,7 +8,7 @@
* This program is free software: you can redistribute it and/or modify it under * 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 * 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 * 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 * 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 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
@ -19,7 +19,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h> #include <string.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
@ -34,15 +33,14 @@ namespace {
TEST(HMacSha1Test, MAC) { TEST(HMacSha1Test, MAC) {
Registry<MAC> registry = MAC::GetRegistry(); Registry<MAC> registry = MAC::GetRegistry();
shared_ptr<MAC> hmac( registry.CreateForMatch( NAME_SHA1_HMAC )); shared_ptr<MAC> hmac(registry.CreateForMatch(NAME_SHA1_HMAC));
ASSERT_FALSE(!hmac); ASSERT_FALSE(!hmac);
// Test cases from rfc2202 // Test cases from rfc2202
// Test case 1 // Test case 1
CipherKey key(20); CipherKey key(20);
byte out[20]; byte out[20];
for (int i = 0; i < 20; ++i) for (int i = 0; i < 20; ++i) key.data()[i] = 0x0b;
key.data()[i] = 0x0b;
hmac->setKey(key); hmac->setKey(key);
hmac->init(); hmac->init();
hmac->update((byte *)"Hi There", 8); hmac->update((byte *)"Hi There", 8);
@ -59,8 +57,7 @@ TEST(HMacSha1Test, MAC) {
// Test case 3 // Test case 3
key = CipherKey(20); key = CipherKey(20);
for (int i = 0; i < 20; ++i) for (int i = 0; i < 20; ++i) key.data()[i] = 0xaa;
key.data()[i] = 0xaa;
hmac->setKey(key); hmac->setKey(key);
hmac->init(); hmac->init();
{ {
@ -82,6 +79,4 @@ TEST(HMacSha1Test, MAC) {
ASSERT_EQ("e8e99d0f45237d786d6bbaa7965c7808bbff1a91", stringToHex(out, 20)); ASSERT_EQ("e8e99d0f45237d786d6bbaa7965c7808bbff1a91", stringToHex(out, 20));
} }
} // namespace } // namespace

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -35,34 +35,32 @@
#ifdef HAVE_VALGRIND_MEMCHECK_H #ifdef HAVE_VALGRIND_MEMCHECK_H
#include <valgrind/memcheck.h> #include <valgrind/memcheck.h>
#else #else
#define VALGRIND_MAKE_MEM_NOACCESS( a, b ) #define VALGRIND_MAKE_MEM_NOACCESS(a, b)
#define VALGRIND_MAKE_MEM_UNDEFINED( a, b ) #define VALGRIND_MAKE_MEM_UNDEFINED(a, b)
#endif #endif
#include <map> #include <map>
#include <list> #include <list>
#ifdef WITH_OPENSSL #ifdef WITH_OPENSSL
# include <openssl/crypto.h> #include <openssl/crypto.h>
# include <openssl/buffer.h> #include <openssl/buffer.h>
#endif #endif
#ifdef WITH_BOTAN #ifdef WITH_BOTAN
# include <botan/botan.h> #include <botan/botan.h>
# include <botan/version.h> #include <botan/version.h>
#endif #endif
namespace encfs { namespace encfs {
#ifdef WITH_OPENSSL #ifdef WITH_OPENSSL
static byte *allocBlock( int size ) static byte *allocBlock(int size) {
{
byte *block = (byte *)OPENSSL_malloc(size); byte *block = (byte *)OPENSSL_malloc(size);
return block; return block;
} }
static void freeBlock( byte *block, int size ) static void freeBlock(byte *block, int size) {
{
OPENSSL_cleanse(block, size); OPENSSL_cleanse(block, size);
OPENSSL_free(block); OPENSSL_free(block);
} }
@ -78,88 +76,69 @@ unsigned char cleanse_ctr = 0;
static void freeBlock(byte *data, int len) { static void freeBlock(byte *data, int len) {
byte *p = data; byte *p = data;
size_t loop = len, ctr = cleanse_ctr; size_t loop = len, ctr = cleanse_ctr;
while(loop--) while (loop--) {
{
*(p++) = (unsigned char)ctr; *(p++) = (unsigned char)ctr;
ctr += (17 + ((size_t)p & 0xF)); ctr += (17 + ((size_t)p & 0xF));
} }
// Try to ensure the compiler doesn't optimize away the loop. // Try to ensure the compiler doesn't optimize away the loop.
p=(byte *)memchr(data, (unsigned char)ctr, len); p = (byte *)memchr(data, (unsigned char)ctr, len);
if(p) if (p) ctr += (63 + (size_t)p);
ctr += (63 + (size_t)p);
cleanse_ctr = (unsigned char)ctr; cleanse_ctr = (unsigned char)ctr;
delete[] data; delete[] data;
} }
#endif #endif
void MemBlock::allocate(int size) void MemBlock::allocate(int size) {
{
rAssert(size > 0); rAssert(size > 0);
this->data = allocBlock(size); this->data = allocBlock(size);
this->size = size; this->size = size;
} }
MemBlock::~MemBlock() MemBlock::~MemBlock() { freeBlock(data, size); }
{
freeBlock(data, size);
}
#ifdef WITH_BOTAN #ifdef WITH_BOTAN
SecureMem::SecureMem(int len) SecureMem::SecureMem(int len)
: data_(new Botan::SecureVector<unsigned char>(len)) : data_(new Botan::SecureVector<unsigned char>(len)) {
{
rAssert(len > 0); rAssert(len > 0);
} }
SecureMem::~SecureMem() SecureMem::~SecureMem() {
{ #if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1, 11, 0)
# if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0)
data_->destroy(); data_->destroy();
# endif #endif
delete data_; delete data_;
} }
byte* SecureMem::data() const { byte *SecureMem::data() const { return const_cast<byte *>(data_->begin()); }
return const_cast<byte*>(data_->begin());
}
int SecureMem::size() const { int SecureMem::size() const { return data_->size(); }
return data_->size();
}
#else #else
SecureMem::SecureMem(int len) SecureMem::SecureMem(int len) {
{
rAssert(len > 0); rAssert(len > 0);
data_ = allocBlock(len); data_ = allocBlock(len);
if (data_) if (data_) {
{
size_ = len; size_ = len;
mlock(data_, size_); mlock(data_, size_);
} else } else {
{
size_ = 0; size_ = 0;
} }
} }
SecureMem::~SecureMem() SecureMem::~SecureMem() {
{ if (size_) {
if (size_)
{
freeBlock(data_, size_); freeBlock(data_, size_);
munlock(data_, size_); munlock(data_, size_);
data_ = NULL; data_ = NULL;
size_ = 0; size_ = 0;
} }
} }
#endif #endif
bool operator == (const SecureMem &a, const SecureMem &b) { bool operator==(const SecureMem &a, const SecureMem &b) {
return (a.size() == b.size()) && return (a.size() == b.size()) && (memcmp(a.data(), b.data(), a.size()) == 0);
(memcmp(a.data(), b.data(), a.size()) == 0);
} }
} // namespace encfs } // namespace encfs

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -26,7 +26,8 @@
#ifdef WITH_BOTAN #ifdef WITH_BOTAN
namespace Botan { namespace Botan {
template <typename T> class SecureVector; template <typename T>
class SecureVector;
} }
#endif #endif
@ -44,26 +45,21 @@ namespace encfs {
// memblock freed when destructed // memblock freed when destructed
*/ */
struct MemBlock struct MemBlock {
{ byte *data;
byte *data; int size;
int size;
MemBlock(); MemBlock();
~MemBlock(); ~MemBlock();
void allocate(int size); void allocate(int size);
}; };
inline MemBlock::MemBlock() inline MemBlock::MemBlock() : data(0), size(0) {}
: data(0), size(0)
{
}
class SecureMem class SecureMem {
{
public: public:
byte* data() const; byte *data() const;
int size() const; int size() const;
explicit SecureMem(int len); explicit SecureMem(int len);
@ -79,17 +75,12 @@ class SecureMem
}; };
#ifndef WITH_BOTAN #ifndef WITH_BOTAN
inline byte* SecureMem::data() const { inline byte *SecureMem::data() const { return data_; }
return data_; inline int SecureMem::size() const { return size_; }
}
inline int SecureMem::size() const {
return size_;
}
#endif #endif
bool operator == (const SecureMem &a, const SecureMem &b); bool operator==(const SecureMem &a, const SecureMem &b);
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -8,7 +8,7 @@
* This program is free software: you can redistribute it and/or modify it under * 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 * 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 * 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 * 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 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
@ -30,25 +30,19 @@ class NullCipher : public BlockCipher {
public: public:
virtual ~NullCipher() {} virtual ~NullCipher() {}
virtual int blockSize() const { virtual int blockSize() const { return 8; }
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; return true;
} }
virtual bool encrypt(const byte *iv, const byte *in, virtual bool decrypt(const byte *iv, const byte *in, byte *out,
byte *out, int numBytes) { int numBytes) {
if (in != out) if (in != out) memcpy(out, in, numBytes);
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; return true;
} }
@ -66,8 +60,7 @@ REGISTER_CLASS(NullCipher, BlockCipher);
REGISTER_CLASS(NullCipher, StreamCipher); REGISTER_CLASS(NullCipher, StreamCipher);
void NullCiphers::registerCiphers() { void NullCiphers::registerCiphers() {
// Nothing required. // Nothing required.
} }
} // namespace encfs } // namespace encfs

View File

@ -8,7 +8,7 @@
* This program is free software: you can redistribute it and/or modify it under * 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 * 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 * 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 * 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 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
@ -34,4 +34,3 @@ class NullCiphers {
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -4,13 +4,8 @@ namespace encfs {
DEFINE_REGISTERABLE_TYPE(PBKDF) DEFINE_REGISTERABLE_TYPE(PBKDF)
PBKDF::PBKDF() PBKDF::PBKDF() {}
{
}
PBKDF::~PBKDF() PBKDF::~PBKDF() {}
{
}
} // namespace encfs } // namespace encfs

View File

@ -14,8 +14,7 @@ static const char NAME_PBKDF2_HMAC_SHA1[] = "PBKDF2_HMAC_SHA1";
static const char NAME_PBKDF2_HMAC_SHA256[] = "PBKDF2_HMAC_SHA256"; static const char NAME_PBKDF2_HMAC_SHA256[] = "PBKDF2_HMAC_SHA256";
// Password Based Key Derivation Function. // Password Based Key Derivation Function.
class PBKDF class PBKDF {
{
public: public:
DECLARE_REGISTERABLE_TYPE(PBKDF); DECLARE_REGISTERABLE_TYPE(PBKDF);
@ -30,17 +29,17 @@ class PBKDF
virtual ~PBKDF(); virtual ~PBKDF();
virtual bool makeKey(const char *password, int passwordLength, virtual bool makeKey(const char *password, int passwordLength,
const byte *salt, int saltLength, const byte *salt, int saltLength, int numIterations,
int numIterations, CipherKey *outKey) = 0; CipherKey *outKey) = 0;
// Create a new key with strong randomization. // 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 // Randomize the output. Pseudo randomization is allowed, so this may not be
// used for keys or other critical values. // 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 } // namespace encfs
#endif // ENCFS_PBKDF_H #endif // ENCFS_PBKDF_H

View File

@ -8,7 +8,7 @@
* This program is free software: you can redistribute it and/or modify it under * 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 * 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 * 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 * 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 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
@ -19,7 +19,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h> #include <string.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
@ -34,23 +33,21 @@ namespace {
TEST(PKCS5_PBKDF2_HMAC_SHA1, PBKDF) { TEST(PKCS5_PBKDF2_HMAC_SHA1, PBKDF) {
Registry<PBKDF> registry = PBKDF::GetRegistry(); Registry<PBKDF> registry = PBKDF::GetRegistry();
shared_ptr<PBKDF> impl( registry.CreateForMatch(NAME_PBKDF2_HMAC_SHA1)); shared_ptr<PBKDF> impl(registry.CreateForMatch(NAME_PBKDF2_HMAC_SHA1));
ASSERT_FALSE(!impl); ASSERT_FALSE(!impl);
// Test cases from rfc6070 // Test cases from rfc6070
// Test case 1 // Test case 1
{ {
CipherKey key(20); CipherKey key(20);
bool ok = impl->makeKey("password", 8, bool ok = impl->makeKey("password", 8, (byte*)"salt", 4, 1, &key);
(byte*)"salt", 4,
1, &key);
ASSERT_TRUE(ok); ASSERT_TRUE(ok);
ASSERT_EQ("0c60c80f961f0e71f3a9b524af6012062fe037a6", stringToHex(key)); ASSERT_EQ("0c60c80f961f0e71f3a9b524af6012062fe037a6", stringToHex(key));
} }
{ {
CipherKey key(25); CipherKey key(25);
bool ok = impl->makeKey("passwordPASSWORDpassword", 24, bool ok = impl->makeKey("passwordPASSWORDpassword", 24,
(byte*)"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, (byte*)"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36,
4096, &key); 4096, &key);
ASSERT_TRUE(ok); ASSERT_TRUE(ok);
@ -60,9 +57,7 @@ TEST(PKCS5_PBKDF2_HMAC_SHA1, PBKDF) {
{ {
CipherKey key(16); CipherKey key(16);
bool ok = impl->makeKey("pass\0word", 9, bool ok = impl->makeKey("pass\0word", 9, (byte*)"sa\0lt", 5, 4096, &key);
(byte*)"sa\0lt", 5,
4096, &key);
ASSERT_TRUE(ok); ASSERT_TRUE(ok);
ASSERT_EQ("56fa6aa75548099dcc37d7f03425e0c3", stringToHex(key)); ASSERT_EQ("56fa6aa75548099dcc37d7f03425e0c3", stringToHex(key));
} }
@ -70,48 +65,45 @@ TEST(PKCS5_PBKDF2_HMAC_SHA1, PBKDF) {
TEST(PKCS5_PBKDF2_HMAC_SHA256, PBKDF) { TEST(PKCS5_PBKDF2_HMAC_SHA256, PBKDF) {
Registry<PBKDF> registry = PBKDF::GetRegistry(); Registry<PBKDF> registry = PBKDF::GetRegistry();
shared_ptr<PBKDF> impl( shared_ptr<PBKDF> impl(registry.CreateForMatch(NAME_PBKDF2_HMAC_SHA256));
registry.CreateForMatch(NAME_PBKDF2_HMAC_SHA256));
ASSERT_FALSE(!impl); ASSERT_FALSE(!impl);
// Test case 1 // Test case 1
{ {
CipherKey key(32); CipherKey key(32);
bool ok = impl->makeKey("password", 8, bool ok = impl->makeKey("password", 8, (byte*)"salt", 4, 1, &key);
(byte*)"salt", 4,
1, &key);
ASSERT_TRUE(ok); ASSERT_TRUE(ok);
ASSERT_EQ("120fb6cffcf8b32c" ASSERT_EQ(
"43e7225256c4f837" "120fb6cffcf8b32c"
"a86548c92ccc3548" "43e7225256c4f837"
"0805987cb70be17b", stringToHex(key)); "a86548c92ccc3548"
"0805987cb70be17b",
stringToHex(key));
} }
// Test case 2 // Test case 2
{ {
CipherKey key(40); CipherKey key(40);
bool ok = impl->makeKey("passwordPASSWORDpassword", 24, bool ok = impl->makeKey("passwordPASSWORDpassword", 24,
(byte*)"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, (byte*)"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36,
4096, &key); 4096, &key);
ASSERT_TRUE(ok); ASSERT_TRUE(ok);
ASSERT_EQ("348c89dbcbd32b2f" ASSERT_EQ(
"32d814b8116e84cf" "348c89dbcbd32b2f"
"2b17347ebc180018" "32d814b8116e84cf"
"1c4e2a1fb8dd53e1" "2b17347ebc180018"
"c635518c7dac47e9", "1c4e2a1fb8dd53e1"
stringToHex(key)); "c635518c7dac47e9",
stringToHex(key));
} }
// Test case 3 // Test case 3
{ {
CipherKey key(16); CipherKey key(16);
bool ok = impl->makeKey("pass\0word", 9, bool ok = impl->makeKey("pass\0word", 9, (byte*)"sa\0lt", 5, 4096, &key);
(byte*)"sa\0lt", 5,
4096, &key);
ASSERT_TRUE(ok); ASSERT_TRUE(ok);
ASSERT_EQ("89b69d0516f829893c696226650a8687", stringToHex(key)); ASSERT_EQ("89b69d0516f829893c696226650a8687", stringToHex(key));
} }
} }
} // namespace } // namespace

View File

@ -4,13 +4,8 @@ namespace encfs {
DEFINE_REGISTERABLE_TYPE(StreamCipher); DEFINE_REGISTERABLE_TYPE(StreamCipher);
StreamCipher::StreamCipher() StreamCipher::StreamCipher() {}
{
}
StreamCipher::~StreamCipher() StreamCipher::~StreamCipher() {}
{
}
} // namespace encfs } // namespace encfs

View File

@ -8,7 +8,7 @@
* This program is free software: you can redistribute it and/or modify it under * 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 * 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 * 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 * 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 * 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_AES_CFB[] = "AES/CFB";
static const char NAME_BLOWFISH_CFB[] = "Blowfish/CFB"; static const char NAME_BLOWFISH_CFB[] = "Blowfish/CFB";
class StreamCipher class StreamCipher {
{
public: public:
DECLARE_REGISTERABLE_TYPE(StreamCipher); DECLARE_REGISTERABLE_TYPE(StreamCipher);
@ -43,31 +42,24 @@ class StreamCipher
std::string cipher; std::string cipher;
std::string mode; std::string mode;
std::string library; std::string library;
std::string toString() const { std::string toString() const { return cipher + "/" + mode; }
return cipher + "/" + mode;
}
Properties() {} Properties() {}
Properties(Range keys, const char *cipher_, const char *mode_, Properties(Range keys, const char *cipher_, const char *mode_,
const char *library_) const char *library_)
: keySize(keys), : keySize(keys), cipher(cipher_), mode(mode_), library(library_) {}
cipher(cipher_),
mode(mode_),
library(library_) { }
}; };
StreamCipher(); StreamCipher();
virtual ~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, virtual bool encrypt(const byte *ivec, const byte *in, byte *out,
byte *out, int numBytes) =0; int numBytes) = 0;
virtual bool decrypt(const byte *ivec, const byte *in, virtual bool decrypt(const byte *ivec, const byte *in, byte *out,
byte *out, int numBytes) =0; int numBytes) = 0;
}; };
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -8,7 +8,7 @@
* This program is free software: you can redistribute it and/or modify it under * 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 * 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 * 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 * 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 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
@ -54,14 +54,11 @@ class PbkdfPkcs5Hmac : public PBKDF {
public: public:
PbkdfPkcs5Hmac(Botan::PBKDF* pbkdf) : pbkdf_(pbkdf) {} PbkdfPkcs5Hmac(Botan::PBKDF* pbkdf) : pbkdf_(pbkdf) {}
virtual ~PbkdfPkcs5Hmac() { virtual ~PbkdfPkcs5Hmac() { delete pbkdf_; }
delete pbkdf_;
}
virtual bool makeKey(const char *password, int passwordLength, virtual bool makeKey(const char* password, int passwordLength,
const byte *salt, int saltLength, const byte* salt, int saltLength, int numIterations,
int numIterations, CipherKey* outKey) {
CipherKey *outKey) {
if (pbkdf_ == NULL) { if (pbkdf_ == NULL) {
// TODO: error message // TODO: error message
return false; return false;
@ -69,10 +66,8 @@ class PbkdfPkcs5Hmac : public PBKDF {
std::string pass; std::string pass;
pass.assign(password, passwordLength); pass.assign(password, passwordLength);
OctetString key = pbkdf_->derive_key(outKey->size(), OctetString key = pbkdf_->derive_key(outKey->size(), pass, salt, saltLength,
pass, numIterations);
salt, saltLength,
numIterations);
memcpy(outKey->data(), key.begin(), outKey->size()); memcpy(outKey->data(), key.begin(), outKey->size());
return true; return true;
} }
@ -83,19 +78,18 @@ class PbkdfPkcs5Hmac : public PBKDF {
return key; return key;
} }
virtual bool pseudoRandom(byte *out, int length) { virtual bool pseudoRandom(byte* out, int length) {
rng.randomize(out, length); rng.randomize(out, length);
return true; return true;
} }
AutoSeeded_RNG rng; AutoSeeded_RNG rng;
}; };
class PbkdfPkcs5HmacSha1 : public PbkdfPkcs5Hmac { class PbkdfPkcs5HmacSha1 : public PbkdfPkcs5Hmac {
public: public:
PbkdfPkcs5HmacSha1() PbkdfPkcs5HmacSha1() : PbkdfPkcs5Hmac(get_pbkdf("PBKDF2(SHA-1)")) {}
: PbkdfPkcs5Hmac( get_pbkdf("PBKDF2(SHA-1)")) { } ~PbkdfPkcs5HmacSha1() {}
~PbkdfPkcs5HmacSha1() {}
static Properties GetProperties() { static Properties GetProperties() {
Properties props; Properties props;
@ -108,9 +102,8 @@ REGISTER_CLASS(PbkdfPkcs5HmacSha1, PBKDF);
class PbkdfPkcs5HmacSha256 : public PbkdfPkcs5Hmac { class PbkdfPkcs5HmacSha256 : public PbkdfPkcs5Hmac {
public: public:
PbkdfPkcs5HmacSha256() PbkdfPkcs5HmacSha256() : PbkdfPkcs5Hmac(get_pbkdf("PBKDF2(SHA-256)")) {}
: PbkdfPkcs5Hmac( get_pbkdf("PBKDF2(SHA-256)")) { } ~PbkdfPkcs5HmacSha256() {}
~PbkdfPkcs5HmacSha256() {}
static Properties GetProperties() { static Properties GetProperties() {
Properties props; Properties props;
@ -121,12 +114,12 @@ class PbkdfPkcs5HmacSha256 : public PbkdfPkcs5Hmac {
}; };
REGISTER_CLASS(PbkdfPkcs5HmacSha256, PBKDF); REGISTER_CLASS(PbkdfPkcs5HmacSha256, PBKDF);
class BotanBlockCipher : public BlockCipher { class BotanBlockCipher : public BlockCipher {
Keyed_Filter *encryption; // Not owned. Keyed_Filter* encryption; // Not owned.
Keyed_Filter *decryption; // Not owned. Keyed_Filter* decryption; // Not owned.
shared_ptr<Pipe> encryptor; shared_ptr<Pipe> encryptor;
shared_ptr<Pipe> decryptor; shared_ptr<Pipe> decryptor;
public: public:
BotanBlockCipher() {} BotanBlockCipher() {}
virtual ~BotanBlockCipher() {} virtual ~BotanBlockCipher() {}
@ -147,7 +140,7 @@ class BotanBlockCipher : public BlockCipher {
virtual bool encrypt(const byte* iv, const byte* in, byte* out, int size) { virtual bool encrypt(const byte* iv, const byte* in, byte* out, int size) {
#ifdef HAVE_VALGRIND_MEMCHECK_H #ifdef HAVE_VALGRIND_MEMCHECK_H
if (VALGRIND_CHECK_MEM_IS_ADDRESSABLE(in, size) != 0 || 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())) { VALGRIND_CHECK_MEM_IS_ADDRESSABLE(iv, blockSize())) {
return false; return false;
} }
@ -156,9 +149,9 @@ class BotanBlockCipher : public BlockCipher {
encryptor->process_msg(in, size); encryptor->process_msg(in, size);
auto written = encryptor->read(out, size, Pipe::LAST_MESSAGE); auto written = encryptor->read(out, size, Pipe::LAST_MESSAGE);
LOG_IF(ERROR, (int)written != size) << "expected output size " << size LOG_IF(ERROR, (int)written != size) << "expected output size " << size
<< ", got " << written; << ", got " << written;
LOG_IF(ERROR, encryptor->remaining() > 0) << "unread bytes in pipe: " LOG_IF(ERROR, encryptor->remaining() > 0)
<< encryptor->remaining(); << "unread bytes in pipe: " << encryptor->remaining();
return true; return true;
} }
@ -174,9 +167,9 @@ class BotanBlockCipher : public BlockCipher {
decryptor->process_msg(in, size); decryptor->process_msg(in, size);
auto written = decryptor->read(out, size, Pipe::LAST_MESSAGE); auto written = decryptor->read(out, size, Pipe::LAST_MESSAGE);
LOG_IF(ERROR, (int)written != size) << "expected output size " << size LOG_IF(ERROR, (int)written != size) << "expected output size " << size
<< ", got " << written; << ", got " << written;
LOG_IF(ERROR, decryptor->remaining() > 0) << "unread bytes in pipe: " LOG_IF(ERROR, decryptor->remaining() > 0)
<< decryptor->remaining(); << "unread bytes in pipe: " << decryptor->remaining();
return true; return true;
} }
}; };
@ -192,12 +185,10 @@ class BotanAesCbc : public BotanBlockCipher {
return rekey(key, ss.str()); return rekey(key, ss.str());
} }
virtual int blockSize() const { virtual int blockSize() const { return 128 >> 3; }
return 128 >> 3;
}
static Properties GetProperties() { 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); REGISTER_CLASS(BotanAesCbc, BlockCipher);
@ -213,12 +204,10 @@ class BotanAesCfb : public BotanBlockCipher {
return rekey(key, ss.str()); return rekey(key, ss.str());
} }
virtual int blockSize() const { virtual int blockSize() const { return 128 >> 3; }
return 128 >> 3;
}
static Properties GetProperties() { 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); REGISTER_CLASS(BotanAesCfb, StreamCipher);
@ -230,16 +219,15 @@ class BotanBlowfishCbc : public BotanBlockCipher {
virtual bool setKey(const CipherKey& key) { virtual bool setKey(const CipherKey& key) {
std::ostringstream ss; std::ostringstream ss;
ss << "Blowfish" << "/CBC/NoPadding"; ss << "Blowfish"
<< "/CBC/NoPadding";
return rekey(key, ss.str()); return rekey(key, ss.str());
} }
virtual int blockSize() const { virtual int blockSize() const { return 64 >> 3; }
return 64 >> 3;
}
static Properties GetProperties() { 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); REGISTER_CLASS(BotanBlowfishCbc, BlockCipher);
@ -251,49 +239,42 @@ class BotanBlowfishCfb : public BotanBlockCipher {
virtual bool setKey(const CipherKey& key) { virtual bool setKey(const CipherKey& key) {
std::ostringstream ss; std::ostringstream ss;
ss << "Blowfish" << "/CFB"; ss << "Blowfish"
<< "/CFB";
return rekey(key, ss.str()); return rekey(key, ss.str());
} }
virtual int blockSize() const { virtual int blockSize() const { return 64 >> 3; }
return 64 >> 3;
}
static Properties GetProperties() { 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); REGISTER_CLASS(BotanBlowfishCfb, StreamCipher);
class Sha1HMac : public MAC { class Sha1HMac : public MAC {
MessageAuthenticationCode *mac; MessageAuthenticationCode* mac;
public: public:
Sha1HMac() : mac(Botan::get_mac("HMAC(SHA-1)")) {} Sha1HMac() : mac(Botan::get_mac("HMAC(SHA-1)")) {}
virtual ~Sha1HMac() { virtual ~Sha1HMac() { delete mac; }
delete mac;
}
virtual int outputSize() const { virtual int outputSize() const { return mac->output_length(); }
return mac->output_length();
}
virtual bool setKey(const CipherKey &key) { virtual bool setKey(const CipherKey& key) {
SymmetricKey bkey(key.data(), key.size()); SymmetricKey bkey(key.data(), key.size());
mac->set_key(bkey); mac->set_key(bkey);
return true; 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); mac->update(in, length);
return true; return true;
} }
virtual bool write(byte *out) { virtual bool write(byte* out) {
#ifdef HAVE_VALGRIND_MEMCHECK_H #ifdef HAVE_VALGRIND_MEMCHECK_H
if (VALGRIND_CHECK_MEM_IS_ADDRESSABLE(out, outputSize()) != 0) { if (VALGRIND_CHECK_MEM_IS_ADDRESSABLE(out, outputSize()) != 0) {
return false; return false;
@ -336,4 +317,3 @@ void Botan_registerCiphers() {
} }
} // namespace encfs } // namespace encfs

View File

@ -8,7 +8,7 @@
* This program is free software: you can redistribute it and/or modify it under * 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 * 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 * 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 * 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 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
@ -33,4 +33,3 @@ extern void Botan_registerCiphers();
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -59,53 +59,48 @@
namespace encfs { 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 MAX_IVLENGTH = 16;
const int KEY_CHECKSUM_BYTES = 4; const int KEY_CHECKSUM_BYTES = 4;
#ifndef MIN #ifndef MIN
inline int MIN(int a, int b) inline int MIN(int a, int b) { return (a < b) ? a : b; }
{
return (a < b) ? a : b;
}
#endif #endif
// Base for {Block,Stream}Cipher implementation. // Base for {Block,Stream}Cipher implementation.
class OpenSSLCipher : public BlockCipher { class OpenSSLCipher : public BlockCipher {
public: public:
OpenSSLCipher() { OpenSSLCipher() {
EVP_CIPHER_CTX_init( &enc ); EVP_CIPHER_CTX_init(&enc);
EVP_CIPHER_CTX_init( &dec ); EVP_CIPHER_CTX_init(&dec);
} }
virtual ~OpenSSLCipher() { virtual ~OpenSSLCipher() {
EVP_CIPHER_CTX_cleanup( &enc ); EVP_CIPHER_CTX_cleanup(&enc);
EVP_CIPHER_CTX_cleanup( &dec ); EVP_CIPHER_CTX_cleanup(&dec);
} }
bool rekey(const EVP_CIPHER *cipher, const CipherKey &key) { bool rekey(const EVP_CIPHER *cipher, const CipherKey &key) {
VLOG(1) << "setting key length " << key.size(); VLOG(1) << "setting key length " << key.size();
EVP_EncryptInit_ex( &enc, cipher, NULL, NULL, NULL); EVP_EncryptInit_ex(&enc, cipher, NULL, NULL, NULL);
EVP_CIPHER_CTX_set_key_length( &enc, key.size() ); EVP_CIPHER_CTX_set_key_length(&enc, key.size());
EVP_CIPHER_CTX_set_padding( &enc, 0 ); EVP_CIPHER_CTX_set_padding(&enc, 0);
EVP_EncryptInit_ex( &enc, NULL, NULL, key.data(), NULL); EVP_EncryptInit_ex(&enc, NULL, NULL, key.data(), NULL);
EVP_DecryptInit_ex( &dec, cipher, NULL, NULL, NULL); EVP_DecryptInit_ex(&dec, cipher, NULL, NULL, NULL);
EVP_CIPHER_CTX_set_key_length( &dec, key.size() ); EVP_CIPHER_CTX_set_key_length(&dec, key.size());
EVP_CIPHER_CTX_set_padding( &dec, 0 ); EVP_CIPHER_CTX_set_padding(&dec, 0);
EVP_DecryptInit_ex( &dec, NULL, NULL, key.data(), NULL); EVP_DecryptInit_ex(&dec, NULL, NULL, key.data(), NULL);
return true; return true;
} }
static bool randomize(CipherKey *key) { static bool randomize(CipherKey *key) {
int result = RAND_bytes( key->data(), key->size() ); int result = RAND_bytes(key->data(), key->size());
if(result != 1) if (result != 1) {
{ char errStr[120]; // specs require string at least 120 bytes long..
char errStr[120]; // specs require string at least 120 bytes long..
unsigned long errVal = 0; unsigned long errVal = 0;
if((errVal = ERR_get_error()) != 0) if ((errVal = ERR_get_error()) != 0)
LOG(ERROR) << "openssl error: " << ERR_error_string( errVal, errStr ); LOG(ERROR) << "openssl error: " << ERR_error_string(errVal, errStr);
return false; return false;
} }
@ -114,20 +109,19 @@ class OpenSSLCipher : public BlockCipher {
#endif #endif
return true; return true;
} }
static bool pseudoRandomize(byte *out, int length) { static bool pseudoRandomize(byte *out, int length) {
#ifdef HAVE_VALGRIND_MEMCHECK_H #ifdef HAVE_VALGRIND_MEMCHECK_H
if (VALGRIND_CHECK_MEM_IS_ADDRESSABLE(out, length) != 0) { if (VALGRIND_CHECK_MEM_IS_ADDRESSABLE(out, length) != 0) {
return false; return false;
} }
#endif #endif
int result = RAND_pseudo_bytes( out, length ); int result = RAND_pseudo_bytes(out, length);
if(result != 1) if (result != 1) {
{ char errStr[120]; // specs require string at least 120 bytes long..
char errStr[120]; // specs require string at least 120 bytes long..
unsigned long errVal = 0; unsigned long errVal = 0;
if((errVal = ERR_get_error()) != 0) if ((errVal = ERR_get_error()) != 0)
LOG(ERROR) << "openssl error: " << ERR_error_string( errVal, errStr ); LOG(ERROR) << "openssl error: " << ERR_error_string(errVal, errStr);
return false; return false;
} }
@ -141,8 +135,7 @@ class OpenSSLCipher : public BlockCipher {
bool rekey(const EVP_CIPHER *cipher, int keyLength) { bool rekey(const EVP_CIPHER *cipher, int keyLength) {
CipherKey key(keyLength); CipherKey key(keyLength);
if (!randomize(&key)) if (!randomize(&key)) return false;
return false;
return rekey(cipher, key); return rekey(cipher, key);
} }
@ -150,13 +143,11 @@ class OpenSSLCipher : public BlockCipher {
virtual int blockSize() const { virtual int blockSize() const {
int len = 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.. // Some versions of OpenSSL report 1 for block size os AES_XTS..
if (len == 1) if (len == 1) len = EVP_CIPHER_CTX_key_length(&enc);
len = EVP_CIPHER_CTX_key_length(&enc);
return len; return len;
} }
virtual bool encrypt(const byte *ivec, const byte *in, virtual bool encrypt(const byte *ivec, const byte *in, byte *out, int size) {
byte *out, int size) {
int dstLen = 0, tmpLen = 0; int dstLen = 0, tmpLen = 0;
#ifdef HAVE_VALGRIND_MEMCHECK_H #ifdef HAVE_VALGRIND_MEMCHECK_H
int ivLen = EVP_CIPHER_CTX_iv_length(&enc); int ivLen = EVP_CIPHER_CTX_iv_length(&enc);
@ -169,22 +160,21 @@ class OpenSSLCipher : public BlockCipher {
return false; return false;
} }
#endif #endif
EVP_EncryptInit_ex( &enc, NULL, NULL, NULL, ivec); EVP_EncryptInit_ex(&enc, NULL, NULL, NULL, ivec);
EVP_EncryptUpdate( &enc, out, &dstLen, in, size); EVP_EncryptUpdate(&enc, out, &dstLen, in, size);
EVP_EncryptFinal_ex( &enc, out+dstLen, &tmpLen ); EVP_EncryptFinal_ex(&enc, out + dstLen, &tmpLen);
dstLen += tmpLen; dstLen += tmpLen;
if (dstLen != size) { if (dstLen != size) {
LOG(ERROR) << "encoding " << size LOG(ERROR) << "encoding " << size << " bytes, got back " << dstLen << " ("
<< " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; << tmpLen << " in final_ex)";
return false; return false;
} }
return true; return true;
} }
virtual bool decrypt(const byte *ivec, const byte *in, virtual bool decrypt(const byte *ivec, const byte *in, byte *out, int size) {
byte *out, int size) {
int dstLen = 0, tmpLen = 0; int dstLen = 0, tmpLen = 0;
#ifdef HAVE_VALGRIND_MEMCHECK_H #ifdef HAVE_VALGRIND_MEMCHECK_H
int ivLen = EVP_CIPHER_CTX_iv_length(&enc); int ivLen = EVP_CIPHER_CTX_iv_length(&enc);
@ -197,14 +187,14 @@ class OpenSSLCipher : public BlockCipher {
return false; return false;
} }
#endif #endif
EVP_DecryptInit_ex( &dec, NULL, NULL, NULL, ivec); EVP_DecryptInit_ex(&dec, NULL, NULL, NULL, ivec);
EVP_DecryptUpdate( &dec, out, &dstLen, in, size ); EVP_DecryptUpdate(&dec, out, &dstLen, in, size);
EVP_DecryptFinal_ex( &dec, out+dstLen, &tmpLen ); EVP_DecryptFinal_ex(&dec, out + dstLen, &tmpLen);
dstLen += tmpLen; dstLen += tmpLen;
if (dstLen != size) { if (dstLen != size) {
LOG(ERROR) << "decoding " << size LOG(ERROR) << "decoding " << size << " bytes, got back " << dstLen << " ("
<< " bytes, got back " << dstLen << " (" << tmpLen << " in final_ex)"; << tmpLen << " in final_ex)";
return false; return false;
} }
@ -216,9 +206,8 @@ class OpenSSLCipher : public BlockCipher {
EVP_CIPHER_CTX dec; EVP_CIPHER_CTX dec;
}; };
#if defined(HAVE_EVP_BF) #if defined(HAVE_EVP_BF)
static Range BfKeyRange(128,256,32); static Range BfKeyRange(128, 256, 32);
class BfCbcBlockCipher : public OpenSSLCipher { class BfCbcBlockCipher : public OpenSSLCipher {
public: public:
BfCbcBlockCipher() {} BfCbcBlockCipher() {}
@ -263,28 +252,29 @@ class BfCfbStreamCipher : public OpenSSLCipher {
REGISTER_CLASS(BfCfbStreamCipher, StreamCipher); REGISTER_CLASS(BfCfbStreamCipher, StreamCipher);
#endif #endif
#if defined(HAVE_EVP_AES) #if defined(HAVE_EVP_AES)
static Range AesKeyRange(128,256,64); static Range AesKeyRange(128, 256, 64);
class AesCbcBlockCipher : public OpenSSLCipher { class AesCbcBlockCipher : public OpenSSLCipher {
public: public:
AesCbcBlockCipher() {} AesCbcBlockCipher() {}
virtual ~AesCbcBlockCipher() {} virtual ~AesCbcBlockCipher() {}
virtual bool setKey(const CipherKey& key) { virtual bool setKey(const CipherKey &key) {
const EVP_CIPHER *cipher = getCipher(key.size()); const EVP_CIPHER *cipher = getCipher(key.size());
return (cipher != NULL) && rekey(cipher, key); return (cipher != NULL) && rekey(cipher, key);
} }
static const EVP_CIPHER *getCipher(int keyLength) { static const EVP_CIPHER *getCipher(int keyLength) {
switch(keyLength * 8) switch (keyLength * 8) {
{ case 128:
case 128: return EVP_aes_128_cbc(); return EVP_aes_128_cbc();
case 192: return EVP_aes_192_cbc(); case 192:
case 256: return EVP_aes_256_cbc(); return EVP_aes_192_cbc();
case 256:
return EVP_aes_256_cbc();
default: default:
LOG(INFO) << "Unsupported key length: " << keyLength; LOG(INFO) << "Unsupported key length: " << keyLength;
return NULL; return NULL;
} }
} }
@ -304,20 +294,22 @@ class AesCfbStreamCipher : public OpenSSLCipher {
AesCfbStreamCipher() {} AesCfbStreamCipher() {}
virtual ~AesCfbStreamCipher() {} virtual ~AesCfbStreamCipher() {}
virtual bool setKey(const CipherKey& key) { virtual bool setKey(const CipherKey &key) {
const EVP_CIPHER *cipher = getCipher(key.size()); const EVP_CIPHER *cipher = getCipher(key.size());
return (cipher != NULL) && rekey(cipher, key); return (cipher != NULL) && rekey(cipher, key);
} }
static const EVP_CIPHER *getCipher(int keyLength) { static const EVP_CIPHER *getCipher(int keyLength) {
switch(keyLength * 8) switch (keyLength * 8) {
{ case 128:
case 128: return EVP_aes_128_cfb(); return EVP_aes_128_cfb();
case 192: return EVP_aes_192_cfb(); case 192:
case 256: return EVP_aes_256_cfb(); return EVP_aes_192_cfb();
case 256:
return EVP_aes_256_cfb();
default: default:
LOG(INFO) << "Unsupported key length: " << keyLength; LOG(INFO) << "Unsupported key length: " << keyLength;
return NULL; return NULL;
} }
} }
@ -334,7 +326,7 @@ REGISTER_CLASS(AesCfbStreamCipher, StreamCipher);
#endif #endif
#if defined(HAVE_EVP_AES_XTS) #if defined(HAVE_EVP_AES_XTS)
static Range AesXtsKeyRange(128,256,128); static Range AesXtsKeyRange(128, 256, 128);
class AesXtsBlockCipher : public OpenSSLCipher { class AesXtsBlockCipher : public OpenSSLCipher {
public: public:
AesXtsBlockCipher() {} AesXtsBlockCipher() {}
@ -346,11 +338,13 @@ class AesXtsBlockCipher : public OpenSSLCipher {
} }
static const EVP_CIPHER *getCipher(int keyLength) { static const EVP_CIPHER *getCipher(int keyLength) {
switch(keyLength * 8) switch (keyLength * 8) {
{ case 128:
case 128: return EVP_aes_128_xts(); return EVP_aes_128_xts();
case 256: return EVP_aes_256_xts(); case 256:
default: return NULL; return EVP_aes_256_xts();
default:
return NULL;
} }
} }
@ -368,15 +362,11 @@ REGISTER_CLASS(AesXtsBlockCipher, BlockCipher);
class Sha1HMac : public MAC { class Sha1HMac : public MAC {
public: public:
Sha1HMac() { Sha1HMac() { HMAC_CTX_init(&ctx); }
HMAC_CTX_init(&ctx); virtual ~Sha1HMac() { HMAC_CTX_cleanup(&ctx); }
}
virtual ~Sha1HMac() {
HMAC_CTX_cleanup(&ctx);
}
virtual int outputSize() const { virtual int outputSize() const {
return 20; // 160 bit. return 20; // 160 bit.
} }
virtual bool setKey(const CipherKey &key) { virtual bool setKey(const CipherKey &key) {
@ -384,10 +374,8 @@ class Sha1HMac : public MAC {
return true; return true;
} }
virtual void init() { virtual void init() { HMAC_Init_ex(&ctx, 0, 0, 0, 0); }
HMAC_Init_ex(&ctx, 0, 0, 0, 0);
}
virtual bool update(const byte *in, int length) { virtual bool update(const byte *in, int length) {
HMAC_Update(&ctx, in, length); HMAC_Update(&ctx, in, length);
return true; return true;
@ -416,31 +404,28 @@ class Sha1HMac : public MAC {
props.library = "OpenSSL"; props.library = "OpenSSL";
return props; return props;
} }
private: private:
HMAC_CTX ctx; HMAC_CTX ctx;
}; };
REGISTER_CLASS(Sha1HMac, MAC); REGISTER_CLASS(Sha1HMac, MAC);
class PbkdfPkcs5HmacSha1 : public PBKDF { class PbkdfPkcs5HmacSha1 : public PBKDF {
public: public:
PbkdfPkcs5HmacSha1() {} PbkdfPkcs5HmacSha1() {}
virtual ~PbkdfPkcs5HmacSha1() {} virtual ~PbkdfPkcs5HmacSha1() {}
virtual bool makeKey(const char *password, int passwordLength, virtual bool makeKey(const char *password, int passwordLength,
const byte *salt, int saltLength, const byte *salt, int saltLength, int numIterations,
int numIterations,
CipherKey *outKey) { CipherKey *outKey) {
return PKCS5_PBKDF2_HMAC_SHA1( return PKCS5_PBKDF2_HMAC_SHA1(
password, passwordLength, password, passwordLength, const_cast<byte *>(salt), saltLength,
const_cast<byte *>(salt), saltLength, numIterations, outKey->size(), outKey->data()) == 1;
numIterations, outKey->size(), outKey->data()) == 1;
} }
virtual CipherKey randomKey(int length) { virtual CipherKey randomKey(int length) {
CipherKey key(length); CipherKey key(length);
if (!OpenSSLCipher::randomize(&key)) if (!OpenSSLCipher::randomize(&key)) key.reset();
key.reset();
return key; return key;
} }
@ -463,20 +448,16 @@ class PbkdfPkcs5HmacSha256 : public PBKDF {
virtual ~PbkdfPkcs5HmacSha256() {} virtual ~PbkdfPkcs5HmacSha256() {}
virtual bool makeKey(const char *password, int passwordLength, virtual bool makeKey(const char *password, int passwordLength,
const byte *salt, int saltLength, const byte *salt, int saltLength, int numIterations,
int numIterations,
CipherKey *outKey) { CipherKey *outKey) {
return PKCS5_PBKDF2_HMAC( return PKCS5_PBKDF2_HMAC(password, passwordLength, const_cast<byte *>(salt),
password, passwordLength, saltLength, numIterations, EVP_sha256(),
const_cast<byte *>(salt), saltLength, outKey->size(), outKey->data()) == 1;
numIterations, EVP_sha256(),
outKey->size(), outKey->data()) == 1;
} }
virtual CipherKey randomKey(int length) { virtual CipherKey randomKey(int length) {
CipherKey key(length); CipherKey key(length);
if (!OpenSSLCipher::randomize(&key)) if (!OpenSSLCipher::randomize(&key)) key.reset();
key.reset();
return key; return key;
} }
@ -493,85 +474,70 @@ class PbkdfPkcs5HmacSha256 : public PBKDF {
}; };
REGISTER_CLASS(PbkdfPkcs5HmacSha256, 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; static pthread_mutex_t *crypto_locks = NULL;
void pthreads_locking_callback( int mode, int n, void pthreads_locking_callback(int mode, int n, const char *caller_file,
const char *caller_file, int caller_line ) int caller_line) {
{
(void)caller_file; (void)caller_file;
(void)caller_line; (void)caller_line;
if(!crypto_locks) if (!crypto_locks) {
{
VLOG(1) << "Allocating " << CRYPTO_num_locks() << " locks for OpenSSL"; VLOG(1) << "Allocating " << CRYPTO_num_locks() << " locks for OpenSSL";
crypto_locks = new pthread_mutex_t[ CRYPTO_num_locks() ]; crypto_locks = new pthread_mutex_t[CRYPTO_num_locks()];
for(int i=0; i<CRYPTO_num_locks(); ++i) for (int i = 0; i < CRYPTO_num_locks(); ++i)
pthread_mutex_init( crypto_locks+i, 0 ); pthread_mutex_init(crypto_locks + i, 0);
} }
if(mode & CRYPTO_LOCK) if (mode & CRYPTO_LOCK) {
{ pthread_mutex_lock(crypto_locks + n);
pthread_mutex_lock( crypto_locks + n ); } else {
} else pthread_mutex_unlock(crypto_locks + n);
{
pthread_mutex_unlock( crypto_locks + n );
} }
} }
void pthreads_locking_cleanup() void pthreads_locking_cleanup() {
{ if (crypto_locks) {
if(crypto_locks) for (int i = 0; i < CRYPTO_num_locks(); ++i)
{ pthread_mutex_destroy(crypto_locks + i);
for(int i=0; i<CRYPTO_num_locks(); ++i)
pthread_mutex_destroy( crypto_locks+i );
delete[] crypto_locks; delete[] crypto_locks;
crypto_locks = NULL; crypto_locks = NULL;
} }
} }
void OpenSSL::init(bool threaded) void OpenSSL::init(bool threaded) {
{
// initialize the SSL library // initialize the SSL library
SSL_load_error_strings(); SSL_load_error_strings();
SSL_library_init(); SSL_library_init();
unsigned int randSeed = 0; unsigned int randSeed = 0;
RAND_bytes( (unsigned char*)&randSeed, sizeof(randSeed) ); RAND_bytes((unsigned char *)&randSeed, sizeof(randSeed));
srand( randSeed ); srand(randSeed);
#ifndef OPENSSL_NO_ENGINE #ifndef OPENSSL_NO_ENGINE
/* Load all bundled ENGINEs into memory and make them visible */ /* Load all bundled ENGINEs into memory and make them visible */
ENGINE_load_builtin_engines(); ENGINE_load_builtin_engines();
/* Register all of them for every algorithm they collectively implement */ /* Register all of them for every algorithm they collectively implement */
ENGINE_register_all_complete(); ENGINE_register_all_complete();
#endif // NO_ENGINE #endif // NO_ENGINE
if(threaded) if (threaded) {
{
// provide locking functions to OpenSSL since we'll be running with // provide locking functions to OpenSSL since we'll be running with
// threads accessing openssl in parallel. // threads accessing openssl in parallel.
CRYPTO_set_id_callback( pthreads_thread_id ); CRYPTO_set_id_callback(pthreads_thread_id);
CRYPTO_set_locking_callback( pthreads_locking_callback ); CRYPTO_set_locking_callback(pthreads_locking_callback);
} }
} }
void OpenSSL::shutdown(bool threaded) void OpenSSL::shutdown(bool threaded) {
{
#ifndef OPENSSL_NO_ENGINE #ifndef OPENSSL_NO_ENGINE
ENGINE_cleanup(); ENGINE_cleanup();
#endif #endif
if(threaded) if (threaded) pthreads_locking_cleanup();
pthreads_locking_cleanup();
} }
void OpenSSL::registerCiphers() void OpenSSL::registerCiphers() {
{
// Nothing required.. Just need to reference this code block to get static // Nothing required.. Just need to reference this code block to get static
// initializers. // initializers.
} }

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -36,5 +36,3 @@ class OpenSSL {
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -1,4 +1,5 @@
/* $OpenBSD: readpassphrase.c,v 1.12 2001/12/15 05:41:00 millert Exp $ */ /* $OpenBSD: readpassphrase.c,v 1.12 2001/12/15 05:41:00 millert Exp $
*/
/* /*
* Copyright (c) 2000 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 2000 Todd C. Miller <Todd.Miller@courtesan.com>
@ -28,7 +29,8 @@
*/ */
#if defined(LIBC_SCCS) && !defined(lint) #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 */ #endif /* LIBC_SCCS and not lint */
//#include "includes.h" //#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" #include "cipher/readpassphrase.h"
#ifdef TCSASOFT #ifdef TCSASOFT
# define _T_FLUSH (TCSAFLUSH|TCSASOFT) #define _T_FLUSH (TCSAFLUSH | TCSASOFT)
#else #else
# define _T_FLUSH (TCSAFLUSH) #define _T_FLUSH (TCSAFLUSH)
#endif #endif
/* SunOS 4.x which lacks _POSIX_VDISABLE, but has VDISABLE */ /* SunOS 4.x which lacks _POSIX_VDISABLE, but has VDISABLE */
#if !defined(_POSIX_VDISABLE) && defined(VDISABLE) #if !defined(_POSIX_VDISABLE) && defined(VDISABLE)
# define _POSIX_VDISABLE VDISABLE #define _POSIX_VDISABLE VDISABLE
#endif #endif
static volatile sig_atomic_t signo; static volatile sig_atomic_t signo;
static void handler(int); static void handler(int);
char * char *readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) {
readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) ssize_t nr;
{ int input, output, save_errno;
ssize_t nr; char ch, *p, *end;
int input, output, save_errno; struct termios term, oterm;
char ch, *p, *end; struct sigaction sa, saveint, savehup, savequit, saveterm;
struct termios term, oterm; struct sigaction savetstp, savettin, savettou;
struct sigaction sa, saveint, savehup, savequit, saveterm;
struct sigaction savetstp, savettin, savettou;
/* I suppose we could alloc on demand in this case (XXX). */ /* I suppose we could alloc on demand in this case (XXX). */
if (bufsiz == 0) { if (bufsiz == 0) {
errno = EINVAL; errno = EINVAL;
return(NULL); return (NULL);
} }
restart: restart:
/* /*
* Read and write to /dev/tty if available. If not, read from * Read and write to /dev/tty if available. If not, read from
* stdin and write to stderr unless a tty is required. * stdin and write to stderr unless a tty is required.
*/ */
if ((input = output = open(_PATH_TTY, O_RDWR)) == -1) { if ((input = output = open(_PATH_TTY, O_RDWR)) == -1) {
if (flags & RPP_REQUIRE_TTY) { if (flags & RPP_REQUIRE_TTY) {
errno = ENOTTY; errno = ENOTTY;
return(NULL); return (NULL);
} }
input = STDIN_FILENO; input = STDIN_FILENO;
output = STDERR_FILENO; output = STDERR_FILENO;
} }
/* /*
* Catch signals that would otherwise cause the user to end * Catch signals that would otherwise cause the user to end
* up with echo turned off in the shell. Don't worry about * up with echo turned off in the shell. Don't worry about
* things like SIGALRM and SIGPIPE for now. * things like SIGALRM and SIGPIPE for now.
*/ */
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
sa.sa_flags = 0; /* don't restart system calls */ sa.sa_flags = 0; /* don't restart system calls */
sa.sa_handler = handler; sa.sa_handler = handler;
(void)sigaction(SIGINT, &sa, &saveint); (void)sigaction(SIGINT, &sa, &saveint);
(void)sigaction(SIGHUP, &sa, &savehup); (void)sigaction(SIGHUP, &sa, &savehup);
(void)sigaction(SIGQUIT, &sa, &savequit); (void)sigaction(SIGQUIT, &sa, &savequit);
(void)sigaction(SIGTERM, &sa, &saveterm); (void)sigaction(SIGTERM, &sa, &saveterm);
(void)sigaction(SIGTSTP, &sa, &savetstp); (void)sigaction(SIGTSTP, &sa, &savetstp);
(void)sigaction(SIGTTIN, &sa, &savettin); (void)sigaction(SIGTTIN, &sa, &savettin);
(void)sigaction(SIGTTOU, &sa, &savettou); (void)sigaction(SIGTTOU, &sa, &savettou);
/* Turn off echo if possible. */ /* Turn off echo if possible. */
if (tcgetattr(input, &oterm) == 0) { if (tcgetattr(input, &oterm) == 0) {
memcpy(&term, &oterm, sizeof(term)); memcpy(&term, &oterm, sizeof(term));
if (!(flags & RPP_ECHO_ON)) if (!(flags & RPP_ECHO_ON)) term.c_lflag &= ~(ECHO | ECHONL);
term.c_lflag &= ~(ECHO | ECHONL);
#ifdef VSTATUS #ifdef VSTATUS
if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
term.c_cc[VSTATUS] = _POSIX_VDISABLE; term.c_cc[VSTATUS] = _POSIX_VDISABLE;
#endif #endif
(void)tcsetattr(input, _T_FLUSH, &term); (void)tcsetattr(input, _T_FLUSH, &term);
} else { } else {
memset(&term, 0, sizeof(term)); memset(&term, 0, sizeof(term));
memset(&oterm, 0, sizeof(oterm)); memset(&oterm, 0, sizeof(oterm));
} }
(void)write(output, prompt, strlen(prompt)); (void)write(output, prompt, strlen(prompt));
end = buf + bufsiz - 1; end = buf + bufsiz - 1;
for (p = buf; (nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r';) { for (p = buf; (nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r';) {
if (p < end) { if (p < end) {
if ((flags & RPP_SEVENBIT)) if ((flags & RPP_SEVENBIT)) ch &= 0x7f;
ch &= 0x7f; if (isalpha(ch)) {
if (isalpha(ch)) { if ((flags & RPP_FORCELOWER)) ch = tolower(ch);
if ((flags & RPP_FORCELOWER)) if ((flags & RPP_FORCEUPPER)) ch = toupper(ch);
ch = tolower(ch); }
if ((flags & RPP_FORCEUPPER)) *p++ = ch;
ch = toupper(ch); }
} }
*p++ = ch; *p = '\0';
} save_errno = errno;
} if (!(term.c_lflag & ECHO)) (void)write(output, "\n", 1);
*p = '\0';
save_errno = errno;
if (!(term.c_lflag & ECHO))
(void)write(output, "\n", 1);
/* Restore old terminal settings and signals. */ /* Restore old terminal settings and signals. */
if (memcmp(&term, &oterm, sizeof(term)) != 0) if (memcmp(&term, &oterm, sizeof(term)) != 0)
(void)tcsetattr(input, _T_FLUSH, &oterm); (void)tcsetattr(input, _T_FLUSH, &oterm);
(void)sigaction(SIGINT, &saveint, NULL); (void)sigaction(SIGINT, &saveint, NULL);
(void)sigaction(SIGHUP, &savehup, NULL); (void)sigaction(SIGHUP, &savehup, NULL);
(void)sigaction(SIGQUIT, &savequit, NULL); (void)sigaction(SIGQUIT, &savequit, NULL);
(void)sigaction(SIGTERM, &saveterm, NULL); (void)sigaction(SIGTERM, &saveterm, NULL);
(void)sigaction(SIGTSTP, &savetstp, NULL); (void)sigaction(SIGTSTP, &savetstp, NULL);
(void)sigaction(SIGTTIN, &savettin, NULL); (void)sigaction(SIGTTIN, &savettin, NULL);
(void)sigaction(SIGTTOU, &savettou, NULL); (void)sigaction(SIGTTOU, &savettou, NULL);
if (input != STDIN_FILENO) if (input != STDIN_FILENO) (void)close(input);
(void)close(input);
/* /*
* If we were interrupted by a signal, resend it to ourselves * If we were interrupted by a signal, resend it to ourselves
* now that we have restored the signal handlers. * now that we have restored the signal handlers.
*/ */
if (signo) { if (signo) {
kill(getpid(), signo); kill(getpid(), signo);
switch (signo) { switch (signo) {
case SIGTSTP: case SIGTSTP:
case SIGTTIN: case SIGTTIN:
case SIGTTOU: case SIGTTOU:
signo = 0; signo = 0;
goto restart; goto restart;
} }
} }
errno = save_errno; errno = save_errno;
return(nr == -1 ? NULL : buf); return (nr == -1 ? NULL : buf);
} }
#endif /* HAVE_READPASSPHRASE */ #endif /* HAVE_READPASSPHRASE */
#if 0 #if 0
char * char *
getpass(const char *prompt) getpass(const char *prompt)
@ -188,8 +182,4 @@ getpass(const char *prompt)
} }
#endif #endif
static void handler(int s) static void handler(int s) { signo = s; }
{
signo = s;
}

View File

@ -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 <Todd.Miller@courtesan.com> * Copyright (c) 2000 Todd C. Miller <Todd.Miller@courtesan.com>
@ -35,17 +36,19 @@
#ifndef HAVE_READPASSPHRASE #ifndef HAVE_READPASSPHRASE
#define RPP_ECHO_OFF 0x00 /* Turn off echo (default). */ #define RPP_ECHO_OFF 0x00 /* Turn off echo (default). */
#define RPP_ECHO_ON 0x01 /* Leave echo on. */ #define RPP_ECHO_ON 0x01 /* Leave echo on. */
#define RPP_REQUIRE_TTY 0x02 /* Fail if there is no tty. */ #define RPP_REQUIRE_TTY 0x02 /* Fail if there is no tty. */
#define RPP_FORCELOWER 0x04 /* Force input to lower case. */ #define RPP_FORCELOWER 0x04 /* Force input to lower case. */
#define RPP_FORCEUPPER 0x08 /* Force input to upper case. */ #define RPP_FORCEUPPER 0x08 /* Force input to upper case. */
#define RPP_SEVENBIT 0x10 /* Strip the high bit from input. */ #define RPP_SEVENBIT 0x10 /* Strip the high bit from input. */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
#endif #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 */ #endif /* HAVE_READPASSPHRASE */

View File

@ -35,7 +35,7 @@ void setDataFromHex(byte *out, int len, const char *hex) {
unsigned int last = 0; unsigned int last = 0;
while (len > 0 && *hex != '\0') { while (len > 0 && *hex != '\0') {
byte nibble = *hex++; byte nibble = *hex++;
if (nibble >= '0' && nibble <= '9') if (nibble >= '0' && nibble <= '9')
nibble -= '0'; nibble -= '0';
else if (nibble >= 'A' && nibble <= 'F') else if (nibble >= 'A' && nibble <= 'F')
nibble -= 'A' - 10; nibble -= 'A' - 10;
@ -64,4 +64,3 @@ int main(int argc, char **argv) {
} }
} // namespace encfs } // namespace encfs

View File

@ -8,7 +8,7 @@
* This program is free software: you can redistribute it and/or modify it under * 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 * 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 * 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 * 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 * 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); std::string stringToHex(const byte *data, int len);
template <typename T> template <typename T>
std::string stringToHex(const T& value) { std::string stringToHex(const T &value) {
return stringToHex(value.data(), value.size()); return stringToHex(value.data(), value.size());
} }
@ -40,4 +40,3 @@ void setDataFromHex(byte *out, int size, const char *hex);
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -54,10 +54,7 @@ extern "C" void fuse_unmount_compat22(const char *mountpoint);
#define fuse_unmount fuse_unmount_compat22 #define fuse_unmount fuse_unmount_compat22
#ifndef MAX #ifndef MAX
inline static int MAX(int a, int b) inline static int MAX(int a, int b) { return (a > b) ? a : b; }
{
return (a > b) ? a : b;
}
#endif #endif
using namespace encfs; using namespace encfs;
@ -72,13 +69,12 @@ namespace encfs {
// Maximum number of arguments that we're going to pass on to fuse. Doesn't // 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.. // affect how many arguments we can handle, just how many we can pass on..
const int MaxFuseArgs = 32; const int MaxFuseArgs = 32;
struct EncFS_Args struct EncFS_Args {
{ string mountPoint; // where to make filesystem visible
string mountPoint; // where to make filesystem visible bool isDaemon; // true == spawn in background, log to syslog
bool isDaemon; // true == spawn in background, log to syslog bool isThreaded; // true == threaded
bool isThreaded; // true == threaded bool isVerbose; // false == only enable warning/error messages
bool isVerbose; // false == only enable warning/error messages int idleTimeout; // 0 == idle time in minutes to trigger unmount
int idleTimeout; // 0 == idle time in minutes to trigger unmount
const char *fuseArgv[MaxFuseArgs]; const char *fuseArgv[MaxFuseArgs];
int fuseArgc; 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 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 // in effect. Not internationalized, since it is something that is mostly
// useful for me! // useful for me!
string toString() string toString() {
{
ostringstream ss; ostringstream ss;
ss << (isDaemon ? "(daemon) " : "(fg) "); ss << (isDaemon ? "(daemon) " : "(fg) ");
ss << (isThreaded ? "(threaded) " : "(UP) "); ss << (isThreaded ? "(threaded) " : "(UP) ");
if(idleTimeout > 0) if (idleTimeout > 0) ss << "(timeout " << idleTimeout << ") ";
ss << "(timeout " << idleTimeout << ") "; if (opts->checkKey) ss << "(keyCheck) ";
if(opts->checkKey) ss << "(keyCheck) "; if (opts->forceDecode) ss << "(forceDecode) ";
if(opts->forceDecode) ss << "(forceDecode) "; if (opts->ownerCreate) ss << "(ownerCreate) ";
if(opts->ownerCreate) ss << "(ownerCreate) "; if (opts->useStdin) ss << "(useStdin) ";
if(opts->useStdin) ss << "(useStdin) "; if (opts->annotate) ss << "(annotate) ";
if(opts->annotate) ss << "(annotate) "; if (opts->reverseEncryption) ss << "(reverseEncryption) ";
if(opts->reverseEncryption) ss << "(reverseEncryption) "; if (opts->mountOnDemand) ss << "(mountOnDemand) ";
if(opts->mountOnDemand) ss << "(mountOnDemand) "; if (opts->delayMount) ss << "(delayMount) ";
if(opts->delayMount) ss << "(delayMount) "; for (int i = 0; i < fuseArgc; ++i) ss << fuseArgv[i] << ' ';
for(int i=0; i<fuseArgc; ++i)
ss << fuseArgv[i] << ' ';
return ss.str(); return ss.str();
} }
EncFS_Args() EncFS_Args() : opts(new EncFS_Opts()) {}
: opts( new EncFS_Opts() )
{
}
}; };
static int oldStderr = STDERR_FILENO; static int oldStderr = STDERR_FILENO;
} // namespace encfs } // namespace encfs
static static void usage(const char *name) {
void usage(const char *name)
{
// xgroup(usage) // xgroup(usage)
cerr << autosprintf( _("Build: encfs version %s"), VERSION ) cerr << autosprintf(_("Build: encfs version %s"), VERSION) << "\n\n"
<< "\n\n" // xgroup(usage)
// xgroup(usage) << autosprintf(_("Usage: %s [options] rootDir mountPoint [-- [FUSE "
<< autosprintf(_("Usage: %s [options] rootDir mountPoint [-- [FUSE Mount Options]]"), name) << "\n\n" "Mount Options]]"),
// xgroup(usage) name) << "\n\n"
<< _("Common Options:\n" // xgroup(usage)
" -H\t\t\t" "show optional FUSE Mount Options\n" << _("Common Options:\n"
" -s\t\t\t" "disable multithreaded operation\n" " -H\t\t\t"
" -f\t\t\t" "run in foreground (don't spawn daemon).\n" "show optional FUSE Mount Options\n"
"\t\t\tError messages will be sent to stderr\n" " -s\t\t\t"
"\t\t\tinstead of syslog.\n") "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) // xgroup(usage)
<< _(" -v, --verbose\t\t" "verbose: output encfs debug messages\n" << _(" -v, --verbose\t\t"
" -i, --idle=MINUTES\t""Auto unmount after period of inactivity\n" "verbose: output encfs debug messages\n"
" --anykey\t\t" "Do not verify correct key is being used\n" " -i, --idle=MINUTES\t"
" --forcedecode\t\t" "decode data even if an error is detected\n" "Auto unmount after period of inactivity\n"
"\t\t\t(for filesystems using MAC block headers)\n") " --anykey\t\t"
<< _(" --public\t\t" "act as a typical multi-user filesystem\n" "Do not verify correct key is being used\n"
"\t\t\t(encfs must be run as root)\n") " --forcedecode\t\t"
<< _(" --reverse\t\t" "reverse encryption\n") "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) // xgroup(usage)
<< _(" --extpass=program\tUse external program for password prompt\n" << _(" --extpass=program\tUse external program for password prompt\n"
"\n" "\n"
"Example, to mount at ~/crypt with raw storage in ~/.crypt :\n" "Example, to mount at ~/crypt with raw storage in ~/.crypt :\n"
" encfs ~/.crypt ~/crypt\n" " encfs ~/.crypt ~/crypt\n"
"\n") "\n")
// xgroup(usage) // xgroup(usage)
<< _("For more information, see the man page encfs(1)") << "\n" << _("For more information, see the man page encfs(1)") << "\n" << endl;
<< endl;
} }
static static void FuseUsage() {
void FuseUsage()
{
// xgroup(usage) // xgroup(usage)
cerr << _("encfs [options] rootDir mountPoint -- [FUSE Mount Options]\n" 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; int argc = 2;
const char *argv[] = {"...", "-h"}; const char *argv[] = {"...", "-h"};
fuse_main( argc, const_cast<char**>(argv), (fuse_operations*)NULL, NULL); fuse_main(argc, const_cast<char **>(argv), (fuse_operations *)NULL, NULL);
} }
#define PUSHARG(ARG) do { \ #define PUSHARG(ARG) \
rAssert(out->fuseArgc < MaxFuseArgs); \ do { \
out->fuseArgv[out->fuseArgc++] = (ARG); } \ rAssert(out->fuseArgc < MaxFuseArgs); \
while(0) out->fuseArgv[out->fuseArgc++] = (ARG); \
} while (0)
static static string slashTerminate(const string &src) {
string slashTerminate( const string &src )
{
string result = src; string result = src;
if( result[ result.length()-1 ] != '/' ) if (result[result.length() - 1] != '/') result.append("/");
result.append( "/" );
return result; return result;
} }
static static bool processArgs(int argc, char *argv[],
bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out) const shared_ptr<EncFS_Args> &out) {
{
// set defaults // set defaults
out->isDaemon = true; out->isDaemon = true;
out->isThreaded = true; out->isThreaded = true;
@ -212,30 +203,28 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
// TODO: can flags be internationalized? // TODO: can flags be internationalized?
static struct option long_options[] = { static struct option long_options[] = {
{"fuse-debug", 0, 0, 'd'}, // Fuse debug mode {"fuse-debug", 0, 0, 'd'}, // Fuse debug mode
{"forcedecode", 0, 0, 'D'}, // force decode {"forcedecode", 0, 0, 'D'}, // force decode
// {"foreground", 0, 0, 'f'}, // foreground mode (no daemon) // {"foreground", 0, 0, 'f'}, // foreground mode (no daemon)
{"fuse-help", 0, 0, 'H'}, // fuse_mount usage {"fuse-help", 0, 0, 'H'}, // fuse_mount usage
{"idle", 1, 0, 'i'}, // idle timeout {"idle", 1, 0, 'i'}, // idle timeout
{"anykey", 0, 0, 'k'}, // skip key checks {"anykey", 0, 0, 'k'}, // skip key checks
{"no-default-flags", 0, 0, 'N'}, // don't use default fuse flags {"no-default-flags", 0, 0, 'N'}, // don't use default fuse flags
{"ondemand", 0, 0, 'm'}, // mount on-demand {"ondemand", 0, 0, 'm'}, // mount on-demand
{"delaymount", 0, 0, 'M'}, // delay initial mount until use {"delaymount", 0, 0, 'M'}, // delay initial mount until use
{"public", 0, 0, 'P'}, // public mode {"public", 0, 0, 'P'}, // public mode
{"extpass", 1, 0, 'p'}, // external password program {"extpass", 1, 0, 'p'}, // external password program
// {"single-thread", 0, 0, 's'}, // single-threaded mode // {"single-thread", 0, 0, 's'}, // single-threaded mode
{"stdinpass", 0, 0, 'S'}, // read password from stdin {"stdinpass", 0, 0, 'S'}, // read password from stdin
{"annotate", 0, 0, 513}, // Print annotation lines to stderr {"annotate", 0, 0, 513}, // Print annotation lines to stderr
{"verbose", 0, 0, 'v'}, // verbose mode {"verbose", 0, 0, 'v'}, // verbose mode
{"version", 0, 0, 'V'}, //version {"version", 0, 0, 'V'}, // version
{"reverse", 0, 0, 'r'}, // reverse encryption {"reverse", 0, 0, 'r'}, // reverse encryption
{"standard", 0, 0, '1'}, // standard configuration {"standard", 0, 0, '1'}, // standard configuration
{"paranoia", 0, 0, '2'}, // standard configuration {"paranoia", 0, 0, '2'}, // standard configuration
{0,0,0,0} {0, 0, 0, 0}};
};
while (1) while (1) {
{
int option_index = 0; int option_index = 0;
// 's' : single-threaded mode // 's' : single-threaded mode
@ -246,107 +235,102 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
// 'm' : mount-on-demand // 'm' : mount-on-demand
// 'S' : password from stdin // 'S' : password from stdin
// 'o' : arguments meant for fuse // 'o' : arguments meant for fuse
int res = getopt_long( argc, argv, "HsSfvVdmi:o:", int res =
long_options, &option_index); getopt_long(argc, argv, "HsSfvVdmi:o:", long_options, &option_index);
if(res == -1) if (res == -1) break;
break;
switch( res ) switch (res) {
{ case '1':
case '1': out->opts->configMode = Config_Standard;
out->opts->configMode = Config_Standard; break;
break; case '2':
case '2': out->opts->configMode = Config_Paranoia;
out->opts->configMode = Config_Paranoia; break;
break; case 's':
case 's': out->isThreaded = false;
out->isThreaded = false; break;
break; case 'S':
case 'S': out->opts->useStdin = true;
out->opts->useStdin = true; break;
break; case 513:
case 513: out->opts->annotate = true;
out->opts->annotate = true; break;
break; case 'f':
case 'f': out->isDaemon = false;
out->isDaemon = false; // this option was added in fuse 2.x
// this option was added in fuse 2.x PUSHARG("-f");
PUSHARG("-f"); break;
break; case 'v':
case 'v': out->isVerbose = true;
out->isVerbose = true; break;
break; case 'd':
case 'd': PUSHARG("-d");
PUSHARG("-d"); break;
break; case 'i':
case 'i': out->idleTimeout = strtol(optarg, (char **)NULL, 10);
out->idleTimeout = strtol( optarg, (char**)NULL, 10); out->opts->idleTracking = true;
out->opts->idleTracking = true; break;
break; case 'k':
case 'k': out->opts->checkKey = false;
out->opts->checkKey = false; break;
break; case 'D':
case 'D': out->opts->forceDecode = true;
out->opts->forceDecode = true; break;
break; case 'r':
case 'r': out->opts->reverseEncryption = true;
out->opts->reverseEncryption = true; break;
break; case 'm':
case 'm': out->opts->mountOnDemand = true;
out->opts->mountOnDemand = true; break;
break; case 'M':
case 'M': out->opts->delayMount = true;
out->opts->delayMount = true; break;
break; case 'N':
case 'N': useDefaultFlags = false;
useDefaultFlags = false; break;
break; case 'o':
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("-o");
PUSHARG("allow_other"); PUSHARG(optarg);
} break;
break; case 'p':
case 'V': out->opts->passwordProgram.assign(optarg);
// xgroup(usage) break;
cerr << autosprintf(_("encfs version %s"), VERSION) << endl; case 'P':
exit(EXIT_SUCCESS); if (geteuid() != 0)
break; LOG(WARNING) << "option '--public' ignored for non-root user";
case 'H': else {
FuseUsage(); out->opts->ownerCreate = true;
exit(EXIT_SUCCESS); // add 'allow_other' option
break; // add 'default_permissions' option (default)
case '?': PUSHARG("-o");
// invalid options.. PUSHARG("allow_other");
break; }
case ':': break;
// missing parameter for option.. case 'V':
break; // xgroup(usage)
default: cerr << autosprintf(_("encfs version %s"), VERSION) << endl;
LOG(WARNING) << "getopt error: " << res; exit(EXIT_SUCCESS);
break; 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) if (!out->isThreaded) PUSHARG("-s");
PUSHARG("-s");
if(useDefaultFlags) if (useDefaultFlags) {
{
PUSHARG("-o"); PUSHARG("-o");
PUSHARG("use_ino"); PUSHARG("use_ino");
PUSHARG("-o"); PUSHARG("-o");
@ -355,24 +339,20 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
// we should have at least 2 arguments left over - the source directory and // we should have at least 2 arguments left over - the source directory and
// the mount point. // the mount point.
if(optind+2 <= argc) if (optind + 2 <= argc) {
{ out->opts->rootDir = slashTerminate(argv[optind++]);
out->opts->rootDir = slashTerminate( argv[optind++] );
out->mountPoint = argv[optind++]; out->mountPoint = argv[optind++];
} else } else {
{
// no mount point specified // no mount point specified
LOG(ERROR) << "Missing one or more arguments, aborting."; LOG(ERROR) << "Missing one or more arguments, aborting.";
return false; return false;
} }
// If there are still extra unparsed arguments, pass them onto FUSE.. // If there are still extra unparsed arguments, pass them onto FUSE..
if(optind < argc) if (optind < argc) {
{
rAssert(out->fuseArgc < MaxFuseArgs); rAssert(out->fuseArgc < MaxFuseArgs);
while(optind < argc) while (optind < argc) {
{
rAssert(out->fuseArgc < MaxFuseArgs); rAssert(out->fuseArgc < MaxFuseArgs);
out->fuseArgv[out->fuseArgc++] = argv[optind]; out->fuseArgv[out->fuseArgc++] = argv[optind];
++optind; ++optind;
@ -380,65 +360,53 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
} }
// sanity check // sanity check
if(out->isDaemon && if (out->isDaemon && (!isAbsolutePath(out->mountPoint.c_str()) ||
(!isAbsolutePath( out->mountPoint.c_str() ) || !isAbsolutePath(out->opts->rootDir.c_str()))) {
!isAbsolutePath( out->opts->rootDir.c_str() ) ) cerr <<
) // xgroup(usage)
{ _("When specifying daemon mode, you must use absolute paths "
cerr << "(beginning with '/')") << endl;
// xgroup(usage)
_("When specifying daemon mode, you must use absolute paths "
"(beginning with '/')")
<< endl;
return false; return false;
} }
// the raw directory may not be a subdirectory of the mount point. // the raw directory may not be a subdirectory of the mount point.
{ {
string testMountPoint = slashTerminate( out->mountPoint ); string testMountPoint = slashTerminate(out->mountPoint);
string testRootDir = string testRootDir = out->opts->rootDir.substr(0, testMountPoint.length());
out->opts->rootDir.substr(0, testMountPoint.length());
if( testMountPoint == testRootDir ) if (testMountPoint == testRootDir) {
{ cerr <<
cerr << // xgroup(usage)
// xgroup(usage) _("The raw directory may not be a subdirectory of the "
_("The raw directory may not be a subdirectory of the "
"mount point.") << endl; "mount point.") << endl;
return false; return false;
} }
} }
if(out->opts->delayMount && !out->opts->mountOnDemand) if (out->opts->delayMount && !out->opts->mountOnDemand) {
{
cerr << cerr <<
// xgroup(usage) // xgroup(usage)
_("You must use mount-on-demand with delay-mount") _("You must use mount-on-demand with delay-mount") << endl;
<< endl;
return false; return false;
} }
if(out->opts->mountOnDemand && out->opts->passwordProgram.empty()) if (out->opts->mountOnDemand && out->opts->passwordProgram.empty()) {
{ cerr <<
cerr << // xgroup(usage)
// xgroup(usage) _("Must set password program when using mount-on-demand") << endl;
_("Must set password program when using mount-on-demand")
<< endl;
return false; return false;
} }
// check that the directories exist, or that we can create them.. // check that the directories exist, or that we can create them..
if(!isDirectory( out->opts->rootDir.c_str() ) && if (!isDirectory(out->opts->rootDir.c_str()) &&
!userAllowMkdir( out->opts->annotate? 1:0, !userAllowMkdir(out->opts->annotate ? 1 : 0, out->opts->rootDir.c_str(),
out->opts->rootDir.c_str() ,0700)) 0700)) {
{
LOG(WARNING) << "Unable to locate root directory, aborting."; LOG(WARNING) << "Unable to locate root directory, aborting.";
return false; return false;
} }
if(!isDirectory( out->mountPoint.c_str() ) && if (!isDirectory(out->mountPoint.c_str()) &&
!userAllowMkdir( out->opts->annotate? 2:0, !userAllowMkdir(out->opts->annotate ? 2 : 0, out->mountPoint.c_str(),
out->mountPoint.c_str(),0700)) 0700)) {
{
LOG(WARNING) << "Unable to locate mount point, aborting."; LOG(WARNING) << "Unable to locate mount point, aborting.";
return false; return false;
} }
@ -449,99 +417,89 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
return true; return true;
} }
static void * idleMonitor(void *); static void *idleMonitor(void *);
void *encfs_init(fuse_conn_info *conn) 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 // set fuse connection options
conn->async_read = true; conn->async_read = true;
// if an idle timeout is specified, then setup a thread to monitor the // if an idle timeout is specified, then setup a thread to monitor the
// filesystem. // filesystem.
if(ctx->args->idleTimeout > 0) if (ctx->args->idleTimeout > 0) {
{
VLOG(1) << "starting idle monitoring thread"; VLOG(1) << "starting idle monitoring thread";
ctx->running = true; ctx->running = true;
int res = pthread_create( &ctx->monitorThread, 0, idleMonitor, int res = pthread_create(&ctx->monitorThread, 0, idleMonitor, (void *)ctx);
(void*)ctx ); if (res != 0) {
if(res != 0)
{
LOG(ERROR) << "error starting idle monitor thread, " 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"; VLOG(1) << "Closing stderr";
close(oldStderr); close(oldStderr);
oldStderr = -1; oldStderr = -1;
} }
return (void*)ctx; return (void *)ctx;
} }
void encfs_destroy( void *_ctx ) void encfs_destroy(void *_ctx) {
{ EncFS_Context *ctx = (EncFS_Context *)_ctx;
EncFS_Context *ctx = (EncFS_Context*)_ctx; if (ctx->args->idleTimeout > 0) {
if(ctx->args->idleTimeout > 0)
{
ctx->running = false; ctx->running = false;
#ifdef CMAKE_USE_PTHREADS_INIT #ifdef CMAKE_USE_PTHREADS_INIT
// wake up the thread if it is waiting.. // wake up the thread if it is waiting..
VLOG(1) << "waking up monitoring thread"; VLOG(1) << "waking up monitoring thread";
ctx->wakeupMutex.lock(); ctx->wakeupMutex.lock();
pthread_cond_signal( &ctx->wakeupCond ); pthread_cond_signal(&ctx->wakeupCond);
ctx->wakeupMutex.unlock(); ctx->wakeupMutex.unlock();
VLOG(1) << "joining with idle monitoring thread"; VLOG(1) << "joining with idle monitoring thread";
pthread_join( ctx->monitorThread , 0 ); pthread_join(ctx->monitorThread, 0);
VLOG(1) << "join done"; VLOG(1) << "join done";
#endif #endif
} }
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[]) {
{
cerr << "\n\n"; cerr << "\n\n";
cerr << "====== WARNING ======= WARNING ======== WARNING ========\n"; cerr << "====== WARNING ======= WARNING ======== WARNING ========\n";
cerr << "NOTE: this version of Encfs comes from SVN mainline and is\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 << " USE AT YOUR OWN RISK!\n";
cerr << "Stable releases are available from the Encfs website, or look\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"; cerr << "\n\n";
// log to stderr by default.. // log to stderr by default..
FLAGS_logtostderr = 1; FLAGS_logtostderr = 1;
FLAGS_minloglevel = 1; // WARNING and above. FLAGS_minloglevel = 1; // WARNING and above.
google::InitGoogleLogging(argv[0]); google::InitGoogleLogging(argv[0]);
google::InstallFailureSignalHandler(); google::InstallFailureSignalHandler();
#ifdef LOCALEDIR #ifdef LOCALEDIR
setlocale( LC_ALL, "" ); setlocale(LC_ALL, "");
bindtextdomain( PACKAGE, LOCALEDIR ); bindtextdomain(PACKAGE, LOCALEDIR);
textdomain( PACKAGE ); textdomain(PACKAGE);
#endif #endif
// anything that comes from the user should be considered tainted until // anything that comes from the user should be considered tainted until
// we've processed it and only allowed through what we support. // we've processed it and only allowed through what we support.
shared_ptr<EncFS_Args> encfsArgs( new EncFS_Args ); shared_ptr<EncFS_Args> encfsArgs(new EncFS_Args);
for(int i=0; i<MaxFuseArgs; ++i) for (int i = 0; i < MaxFuseArgs; ++i)
encfsArgs->fuseArgv[i] = NULL; // libfuse expects null args.. 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]); usage(argv[0]);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if(encfsArgs->isVerbose) if (encfsArgs->isVerbose) FLAGS_minloglevel = 0;
FLAGS_minloglevel = 0;
LOG(INFO) << "Root directory: " << encfsArgs->opts->rootDir; LOG(INFO) << "Root directory: " << encfsArgs->opts->rootDir;
LOG(INFO) << "Fuse arguments: " << encfsArgs->toString(); LOG(INFO) << "Fuse arguments: " << encfsArgs->toString();
@ -554,7 +512,7 @@ int main(int argc, char *argv[])
encfs_oper.getattr = encfs_getattr; encfs_oper.getattr = encfs_getattr;
encfs_oper.readlink = encfs_readlink; 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.mknod = encfs_mknod;
encfs_oper.mkdir = encfs_mkdir; encfs_oper.mkdir = encfs_mkdir;
encfs_oper.unlink = encfs_unlink; encfs_oper.unlink = encfs_unlink;
@ -565,7 +523,7 @@ int main(int argc, char *argv[])
encfs_oper.chmod = encfs_chmod; encfs_oper.chmod = encfs_chmod;
encfs_oper.chown = encfs_chown; encfs_oper.chown = encfs_chown;
encfs_oper.truncate = encfs_truncate; 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.open = encfs_open;
encfs_oper.read = encfs_read; encfs_oper.read = encfs_read;
encfs_oper.write = encfs_write; encfs_oper.write = encfs_write;
@ -578,130 +536,122 @@ int main(int argc, char *argv[])
encfs_oper.getxattr = encfs_getxattr; encfs_oper.getxattr = encfs_getxattr;
encfs_oper.listxattr = encfs_listxattr; encfs_oper.listxattr = encfs_listxattr;
encfs_oper.removexattr = encfs_removexattr; encfs_oper.removexattr = encfs_removexattr;
#endif // HAVE_XATTR #endif // HAVE_XATTR
//encfs_oper.opendir = encfs_opendir; // encfs_oper.opendir = encfs_opendir;
//encfs_oper.readdir = encfs_readdir; // encfs_oper.readdir = encfs_readdir;
//encfs_oper.releasedir = encfs_releasedir; // encfs_oper.releasedir = encfs_releasedir;
//encfs_oper.fsyncdir = encfs_fsyncdir; // encfs_oper.fsyncdir = encfs_fsyncdir;
encfs_oper.init = encfs_init; encfs_oper.init = encfs_init;
encfs_oper.destroy = encfs_destroy; encfs_oper.destroy = encfs_destroy;
//encfs_oper.access = encfs_access; // encfs_oper.access = encfs_access;
//encfs_oper.create = encfs_create; // encfs_oper.create = encfs_create;
encfs_oper.ftruncate = encfs_ftruncate; encfs_oper.ftruncate = encfs_ftruncate;
encfs_oper.fgetattr = encfs_fgetattr; encfs_oper.fgetattr = encfs_fgetattr;
//encfs_oper.lock = encfs_lock; // encfs_oper.lock = encfs_lock;
encfs_oper.utimens = encfs_utimens; encfs_oper.utimens = encfs_utimens;
//encfs_oper.bmap = encfs_bmap; // encfs_oper.bmap = encfs_bmap;
#if (__FreeBSD__ >= 10) #if (__FreeBSD__ >= 10)
// encfs_oper.setvolname // encfs_oper.setvolname
// encfs_oper.exchange // encfs_oper.exchange
// encfs_oper.getxtimes // encfs_oper.getxtimes
// encfs_oper.setbkuptime // encfs_oper.setbkuptime
// encfs_oper.setchgtime // encfs_oper.setchgtime
// encfs_oper.setcrtime // encfs_oper.setcrtime
// encfs_oper.chflags // encfs_oper.chflags
// encfs_oper.setattr_x // encfs_oper.setattr_x
// encfs_oper.fsetattr_x // encfs_oper.fsetattr_x
#endif #endif
CipherV1::init( encfsArgs->isThreaded ); CipherV1::init(encfsArgs->isThreaded);
// context is not a smart pointer because it will live for the life of // context is not a smart pointer because it will live for the life of
// the filesystem. // the filesystem.
EncFS_Context *ctx = new EncFS_Context; EncFS_Context *ctx = new EncFS_Context;
ctx->publicFilesystem = encfsArgs->opts->ownerCreate; ctx->publicFilesystem = encfsArgs->opts->ownerCreate;
RootPtr rootInfo = initFS( ctx, encfsArgs->opts ); RootPtr rootInfo = initFS(ctx, encfsArgs->opts);
int returnCode = EXIT_FAILURE; int returnCode = EXIT_FAILURE;
if( rootInfo ) if (rootInfo) {
{
// turn off delayMount, as our prior call to initFS has already // turn off delayMount, as our prior call to initFS has already
// respected any delay, and we want future calls to actually mount. // respected any delay, and we want future calls to actually mount.
encfsArgs->opts->delayMount = false; encfsArgs->opts->delayMount = false;
// set the globally visible root directory node // set the globally visible root directory node
ctx->setRoot( rootInfo->root ); ctx->setRoot(rootInfo->root);
ctx->args = encfsArgs; ctx->args = encfsArgs;
ctx->opts = encfsArgs->opts; ctx->opts = encfsArgs->opts;
if(encfsArgs->isThreaded == false && encfsArgs->idleTimeout > 0) if (encfsArgs->isThreaded == false && encfsArgs->idleTimeout > 0) {
{
// xgroup(usage) // xgroup(usage)
cerr << _("Note: requested single-threaded mode, but an idle\n" cerr << _("Note: requested single-threaded mode, but an idle\n"
"timeout was specified. The filesystem will operate\n" "timeout was specified. The filesystem will operate\n"
"single-threaded, but threads will still be used to\n" "single-threaded, but threads will still be used to\n"
"implement idle checking.") << endl; "implement idle checking.") << endl;
} }
// reset umask now, since we don't want it to interfere with the // reset umask now, since we don't want it to interfere with the
// pass-thru calls.. // pass-thru calls..
umask( 0 ); umask(0);
if(encfsArgs->isDaemon) if (encfsArgs->isDaemon) {
{
// switch to logging just warning and error messages via syslog // switch to logging just warning and error messages via syslog
FLAGS_minloglevel = 1; FLAGS_minloglevel = 1;
FLAGS_logtostderr = 0; FLAGS_logtostderr = 0;
// keep around a pointer just in case we end up needing it to // keep around a pointer just in case we end up needing it to
// report a fatal condition later (fuse_main exits unexpectedly)... // report a fatal condition later (fuse_main exits unexpectedly)...
oldStderr = dup( STDERR_FILENO ); oldStderr = dup(STDERR_FILENO);
} }
try try {
{
time_t startTime, endTime; time_t startTime, endTime;
if (encfsArgs->opts->annotate) if (encfsArgs->opts->annotate) cerr << "$STATUS$ fuse_main_start" << endl;
cerr << "$STATUS$ fuse_main_start" << endl;
// FIXME: workaround for fuse_main returning an error on normal // FIXME: workaround for fuse_main returning an error on normal
// exit. Only print information if fuse_main returned // exit. Only print information if fuse_main returned
// immediately.. // immediately..
time( &startTime ); time(&startTime);
// fuse_main returns an error code in newer versions of fuse.. // fuse_main returns an error code in newer versions of fuse..
int res = fuse_main( encfsArgs->fuseArgc, int res = fuse_main(encfsArgs->fuseArgc,
const_cast<char**>(encfsArgs->fuseArgv), const_cast<char **>(encfsArgs->fuseArgv), &encfs_oper,
&encfs_oper, (void*)ctx); (void *)ctx);
time( &endTime ); time(&endTime);
if (encfsArgs->opts->annotate) if (encfsArgs->opts->annotate) cerr << "$STATUS$ fuse_main_end" << endl;
cerr << "$STATUS$ fuse_main_end" << endl;
if(res == 0) if (res == 0) returnCode = EXIT_SUCCESS;
returnCode = EXIT_SUCCESS;
if(res != 0 && encfsArgs->isDaemon && (oldStderr >= 0) if (res != 0 && encfsArgs->isDaemon && (oldStderr >= 0) &&
&& (endTime - startTime <= 1) ) (endTime - startTime <= 1)) {
{
// the users will not have seen any message from fuse, so say a // the users will not have seen any message from fuse, so say a
// few words in libfuse's memory.. // few words in libfuse's memory..
FILE *out = fdopen( oldStderr, "a" ); FILE *out = fdopen(oldStderr, "a");
// xgroup(usage) // xgroup(usage)
fprintf(out, _("fuse failed. Common problems:\n" fprintf(out, _("fuse failed. Common problems:\n"
" - fuse kernel module not installed (modprobe fuse)\n" " - fuse kernel module not installed (modprobe fuse)\n"
" - invalid options -- see usage message\n")); " - invalid options -- see usage message\n"));
fclose(out); fclose(out);
} }
} catch(std::exception &ex) }
{ catch (std::exception &ex) {
LOG(ERROR) << "Internal error: Caught exception from main loop: " LOG(ERROR) << "Internal error: Caught exception from main loop: "
<< ex.what(); << ex.what();
} catch(...) }
{ catch (...) {
LOG(ERROR) << "Internal error: Caught unexpected exception"; LOG(ERROR) << "Internal error: Caught unexpected exception";
} }
} }
// cleanup so that we can check for leaked resources.. // cleanup so that we can check for leaked resources..
rootInfo.reset(); rootInfo.reset();
ctx->setRoot( shared_ptr<DirNode>() ); ctx->setRoot(shared_ptr<DirNode>());
CipherV1::shutdown( encfsArgs->isThreaded ); CipherV1::shutdown(encfsArgs->isThreaded);
return returnCode; return returnCode;
} }
@ -716,10 +666,8 @@ int main(int argc, char *argv[])
const int ActivityCheckInterval = 10; const int ActivityCheckInterval = 10;
static bool unmountFS(EncFS_Context *ctx); static bool unmountFS(EncFS_Context *ctx);
static static void *idleMonitor(void *_arg) {
void * idleMonitor(void *_arg) EncFS_Context *ctx = (EncFS_Context *)_arg;
{
EncFS_Context *ctx = (EncFS_Context*)_arg;
shared_ptr<EncFS_Args> arg = ctx->args; shared_ptr<EncFS_Args> arg = ctx->args;
const int timeoutCycles = 60 * arg->idleTimeout / ActivityCheckInterval; const int timeoutCycles = 60 * arg->idleTimeout / ActivityCheckInterval;
@ -727,23 +675,20 @@ void * idleMonitor(void *_arg)
ctx->wakeupMutex.lock(); ctx->wakeupMutex.lock();
while(ctx->running) while (ctx->running) {
{
int usage = ctx->getAndResetUsageCounter(); int usage = ctx->getAndResetUsageCounter();
if(usage == 0 && ctx->isMounted()) if (usage == 0 && ctx->isMounted())
++idleCycles; ++idleCycles;
else else
idleCycles = 0; idleCycles = 0;
if(idleCycles >= timeoutCycles) if (idleCycles >= timeoutCycles) {
{
int openCount = ctx->openFileCount(); int openCount = ctx->openFileCount();
if( openCount == 0 && unmountFS( ctx ) ) if (openCount == 0 && unmountFS(ctx)) {
{
#ifdef CMAKE_USE_PTHREADS_INIT #ifdef CMAKE_USE_PTHREADS_INIT
// wait for main thread to wake us up // 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 #endif
break; break;
} }
@ -751,17 +696,17 @@ void * idleMonitor(void *_arg)
VLOG(1) << "num open files: " << openCount; VLOG(1) << "num open files: " << openCount;
} }
VLOG(1) << "idle cycle count: " << idleCycles VLOG(1) << "idle cycle count: " << idleCycles << ", timeout after "
<< ", timeout after " << timeoutCycles; << timeoutCycles;
struct timeval currentTime; struct timeval currentTime;
gettimeofday( &currentTime, 0 ); gettimeofday(&currentTime, 0);
struct timespec wakeupTime; struct timespec wakeupTime;
wakeupTime.tv_sec = currentTime.tv_sec + ActivityCheckInterval; wakeupTime.tv_sec = currentTime.tv_sec + ActivityCheckInterval;
wakeupTime.tv_nsec = currentTime.tv_usec * 1000; wakeupTime.tv_nsec = currentTime.tv_usec * 1000;
#ifdef CMAKE_USE_PTHREADS_INIT #ifdef CMAKE_USE_PTHREADS_INIT
pthread_cond_timedwait( &ctx->wakeupCond, pthread_cond_timedwait(&ctx->wakeupCond, &ctx->wakeupMutex._mutex,
&ctx->wakeupMutex._mutex, &wakeupTime ); &wakeupTime);
#endif #endif
} }
@ -772,20 +717,16 @@ void * idleMonitor(void *_arg)
return 0; return 0;
} }
static bool unmountFS(EncFS_Context *ctx) static bool unmountFS(EncFS_Context *ctx) {
{
shared_ptr<EncFS_Args> arg = ctx->args; shared_ptr<EncFS_Args> arg = ctx->args;
LOG(INFO) << "Detaching filesystem " << arg->mountPoint LOG(INFO) << "Detaching filesystem " << arg->mountPoint
<< " due to inactivity"; << " due to inactivity";
if( arg->opts->mountOnDemand ) if (arg->opts->mountOnDemand) {
{ ctx->setRoot(shared_ptr<DirNode>());
ctx->setRoot( shared_ptr<DirNode>() );
return false; return false;
} else } else {
{ fuse_unmount(arg->mountPoint.c_str());
fuse_unmount( arg->mountPoint.c_str() );
return true; return true;
} }
} }

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -30,131 +30,111 @@
namespace encfs { namespace encfs {
template<typename Type> template <typename Type>
inline Type min( Type A, Type B ) inline Type min(Type A, Type B) {
{
return (B < A) ? B : A; return (B < A) ? B : A;
} }
static void clearCache( IORequest &req, int blockSize ) static void clearCache(IORequest &req, int blockSize) {
{ memset(req.data, 0, blockSize);
memset( req.data, 0, blockSize );
req.dataLen = 0; req.dataLen = 0;
} }
BlockFileIO::BlockFileIO( int blockSize, const FSConfigPtr &cfg ) BlockFileIO::BlockFileIO(int blockSize, const FSConfigPtr &cfg)
: _blockSize( blockSize ) : _blockSize(blockSize), _allowHoles(cfg->config->allow_holes()) {
, _allowHoles( cfg->config->allow_holes() ) rAssert(_blockSize > 1);
{ _cache.data = new unsigned char[_blockSize];
rAssert( _blockSize > 1 );
_cache.data = new unsigned char [ _blockSize ];
} }
BlockFileIO::~BlockFileIO() BlockFileIO::~BlockFileIO() {
{ clearCache(_cache, _blockSize);
clearCache( _cache, _blockSize );
delete[] _cache.data; 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 can satisfy the request even if _cache.dataLen is too short, because
// we always request a full block during reads.. // 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 // satisfy request from cache
int len = req.dataLen; int len = req.dataLen;
if(_cache.dataLen < len) if (_cache.dataLen < len) len = _cache.dataLen;
len = _cache.dataLen; memcpy(req.data, _cache.data, len);
memcpy( req.data, _cache.data, len );
return len; return len;
} else } else {
{ if (_cache.dataLen > 0) clearCache(_cache, _blockSize);
if(_cache.dataLen > 0)
clearCache( _cache, _blockSize );
// cache results of read -- issue reads for full blocks // cache results of read -- issue reads for full blocks
IORequest tmp; IORequest tmp;
tmp.offset = req.offset; tmp.offset = req.offset;
tmp.data = _cache.data; tmp.data = _cache.data;
tmp.dataLen = _blockSize; tmp.dataLen = _blockSize;
ssize_t result = readOneBlock( tmp ); ssize_t result = readOneBlock(tmp);
if(result > 0) if (result > 0) {
{
_cache.offset = req.offset; _cache.offset = req.offset;
_cache.dataLen = result; // the amount we really have _cache.dataLen = result; // the amount we really have
if(result > req.dataLen) if (result > req.dataLen)
result = req.dataLen; // only as much as requested result = req.dataLen; // only as much as requested
memcpy( req.data, _cache.data, result ); memcpy(req.data, _cache.data, result);
} }
return 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 // cache results of write (before pass-thru, because it may be modified
// in-place) // in-place)
memcpy( _cache.data, req.data, req.dataLen ); memcpy(_cache.data, req.data, req.dataLen);
_cache.offset = req.offset; _cache.offset = req.offset;
_cache.dataLen = req.dataLen; _cache.dataLen = req.dataLen;
bool ok = writeOneBlock( req ); bool ok = writeOneBlock(req);
if(!ok) if (!ok) clearCache(_cache, _blockSize);
clearCache( _cache, _blockSize );
return ok; return ok;
} }
ssize_t BlockFileIO::read( const IORequest &req ) const ssize_t BlockFileIO::read(const IORequest &req) const {
{ rAssert(_blockSize != 0);
rAssert( _blockSize != 0 );
int partialOffset = req.offset % _blockSize; int partialOffset = req.offset % _blockSize;
off_t blockNum = req.offset / _blockSize; off_t blockNum = req.offset / _blockSize;
ssize_t result = 0; 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 // read completely within a single block -- can be handled as-is by
// readOneBloc(). // readOneBloc().
return cacheReadOneBlock( req ); return cacheReadOneBlock(req);
} else } else {
{
size_t size = req.dataLen; size_t size = req.dataLen;
// if the request is larger then a block, then request each block // if the request is larger then a block, then request each block
// individually // individually
MemBlock mb; // in case we need to allocate a temporary block.. MemBlock mb; // in case we need to allocate a temporary block..
IORequest blockReq; // for requests we may need to make IORequest blockReq; // for requests we may need to make
blockReq.dataLen = _blockSize; blockReq.dataLen = _blockSize;
blockReq.data = NULL; blockReq.data = NULL;
unsigned char *out = req.data; unsigned char *out = req.data;
while( size ) while (size) {
{
blockReq.offset = blockNum * _blockSize; blockReq.offset = blockNum * _blockSize;
// if we're reading a full block, then read directly into the // if we're reading a full block, then read directly into the
// result buffer instead of using a temporary // result buffer instead of using a temporary
if(partialOffset == 0 && size >= (size_t)_blockSize) if (partialOffset == 0 && size >= (size_t)_blockSize)
blockReq.data = out; blockReq.data = out;
else else {
{ if (!mb.data) mb.allocate(_blockSize);
if(!mb.data)
mb.allocate( _blockSize );
blockReq.data = mb.data; blockReq.data = mb.data;
} }
ssize_t readSize = cacheReadOneBlock( blockReq ); ssize_t readSize = cacheReadOneBlock(blockReq);
if(readSize <= partialOffset) if (readSize <= partialOffset) break; // didn't get enough bytes
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); rAssert(cpySize <= readSize);
// if we read to a temporary buffer, then move the data // if we read to a temporary buffer, then move the data
if(blockReq.data != out) if (blockReq.data != out)
memcpy( out, blockReq.data + partialOffset, cpySize ); memcpy(out, blockReq.data + partialOffset, cpySize);
result += cpySize; result += cpySize;
size -= cpySize; size -= cpySize;
@ -162,17 +142,15 @@ ssize_t BlockFileIO::read( const IORequest &req ) const
++blockNum; ++blockNum;
partialOffset = 0; partialOffset = 0;
if(readSize < _blockSize) if (readSize < _blockSize) break;
break;
} }
return result; return result;
} }
} }
bool BlockFileIO::write( const IORequest &req ) bool BlockFileIO::write(const IORequest &req) {
{ rAssert(_blockSize != 0);
rAssert( _blockSize != 0 );
off_t fileSize = getSize(); off_t fileSize = getSize();
@ -185,29 +163,25 @@ bool BlockFileIO::write( const IORequest &req )
ssize_t lastBlockSize = fileSize % _blockSize; ssize_t lastBlockSize = fileSize % _blockSize;
off_t lastNonEmptyBlock = lastFileBlock; off_t lastNonEmptyBlock = lastFileBlock;
if(lastBlockSize == 0) if (lastBlockSize == 0) --lastNonEmptyBlock;
--lastNonEmptyBlock;
if( req.offset > fileSize ) if (req.offset > fileSize) {
{
// extend file first to fill hole with 0's.. // extend file first to fill hole with 0's..
const bool forceWrite = false; 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 // check against edge cases where we can just let the base class handle the
// request as-is.. // request as-is..
if(partialOffset == 0 && req.dataLen <= _blockSize) if (partialOffset == 0 && req.dataLen <= _blockSize) {
{
// if writing a full block.. pretty safe.. // if writing a full block.. pretty safe..
if( req.dataLen == _blockSize ) if (req.dataLen == _blockSize) return cacheWriteOneBlock(req);
return cacheWriteOneBlock( req );
// if writing a partial block, but at least as much as what is // if writing a partial block, but at least as much as what is
// already there.. // already there..
if(blockNum == lastFileBlock && req.dataLen >= lastBlockSize) if (blockNum == lastFileBlock && req.dataLen >= lastBlockSize)
return cacheWriteOneBlock( req ); return cacheWriteOneBlock(req);
} }
// have to merge data with existing block(s).. // have to merge data with existing block(s)..
MemBlock mb; MemBlock mb;
@ -219,49 +193,42 @@ bool BlockFileIO::write( const IORequest &req )
bool ok = true; bool ok = true;
size_t size = req.dataLen; size_t size = req.dataLen;
unsigned char *inPtr = req.data; unsigned char *inPtr = req.data;
while( size ) while (size) {
{
blockReq.offset = blockNum * _blockSize; blockReq.offset = blockNum * _blockSize;
int toCopy = min((size_t)(_blockSize - partialOffset), size); int toCopy = min((size_t)(_blockSize - partialOffset), size);
// if writing an entire block, or writing a partial block that requires // if writing an entire block, or writing a partial block that requires
// no merging with existing data.. // no merging with existing data..
if( (toCopy == _blockSize) if ((toCopy == _blockSize) ||
||(partialOffset == 0 && blockReq.offset + toCopy >= fileSize)) (partialOffset == 0 && blockReq.offset + toCopy >= fileSize)) {
{
// write directly from buffer // write directly from buffer
blockReq.data = inPtr; blockReq.data = inPtr;
blockReq.dataLen = toCopy; blockReq.dataLen = toCopy;
} else } else {
{
// need a temporary buffer, since we have to either merge or pad // need a temporary buffer, since we have to either merge or pad
// the data. // the data.
if(!mb.data) if (!mb.data) mb.allocate(_blockSize);
mb.allocate( _blockSize ); memset(mb.data, 0, _blockSize);
memset( mb.data, 0, _blockSize );
blockReq.data = mb.data; blockReq.data = mb.data;
if(blockNum > lastNonEmptyBlock) if (blockNum > lastNonEmptyBlock) {
{
// just pad.. // just pad..
blockReq.dataLen = toCopy + partialOffset; blockReq.dataLen = toCopy + partialOffset;
} else } else {
{
// have to merge with existing block data.. // have to merge with existing block data..
blockReq.dataLen = _blockSize; blockReq.dataLen = _blockSize;
blockReq.dataLen = cacheReadOneBlock( blockReq ); blockReq.dataLen = cacheReadOneBlock(blockReq);
// extend data if necessary.. // extend data if necessary..
if( partialOffset + toCopy > blockReq.dataLen ) if (partialOffset + toCopy > blockReq.dataLen)
blockReq.dataLen = partialOffset + toCopy; blockReq.dataLen = partialOffset + toCopy;
} }
// merge in the data to be written.. // merge in the data to be written..
memcpy( blockReq.data + partialOffset, inPtr, toCopy ); memcpy(blockReq.data + partialOffset, inPtr, toCopy);
} }
// Finally, write the damn thing! // Finally, write the damn thing!
if(!cacheWriteOneBlock( blockReq )) if (!cacheWriteOneBlock(blockReq)) {
{
ok = false; ok = false;
break; break;
} }
@ -276,13 +243,9 @@ bool BlockFileIO::write( const IORequest &req )
return ok; return ok;
} }
int BlockFileIO::blockSize() const int BlockFileIO::blockSize() const { return _blockSize; }
{
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 oldLastBlock = oldSize / _blockSize;
off_t newLastBlock = newSize / _blockSize; off_t newLastBlock = newSize / _blockSize;
int lastBlockSize = newSize % _blockSize; int lastBlockSize = newSize % _blockSize;
@ -290,78 +253,69 @@ void BlockFileIO::padFile( off_t oldSize, off_t newSize, bool forceWrite )
IORequest req; IORequest req;
MemBlock mb; MemBlock mb;
if(oldLastBlock == newLastBlock) if (oldLastBlock == newLastBlock) {
{
// when the real write occurs, it will have to read in the existing // 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 // data and pad it anyway, so we won't do it here (unless we're
// forced). // forced).
if( forceWrite ) if (forceWrite) {
{ mb.allocate(_blockSize);
mb.allocate( _blockSize );
req.data = mb.data; req.data = mb.data;
req.offset = oldLastBlock * _blockSize; req.offset = oldLastBlock * _blockSize;
req.dataLen = oldSize % _blockSize; req.dataLen = oldSize % _blockSize;
int outSize = newSize % _blockSize; // outSize > req.dataLen int outSize = newSize % _blockSize; // outSize > req.dataLen
if(outSize) if (outSize) {
{ memset(mb.data, 0, outSize);
memset( mb.data, 0, outSize ); cacheReadOneBlock(req);
cacheReadOneBlock( req );
req.dataLen = outSize; req.dataLen = outSize;
cacheWriteOneBlock( req ); cacheWriteOneBlock(req);
} }
} else } else
VLOG(1) << "optimization: not padding last block"; VLOG(1) << "optimization: not padding last block";
} else } else {
{ mb.allocate(_blockSize);
mb.allocate( _blockSize );
req.data = mb.data; req.data = mb.data;
// 1. extend the first block to full length // 1. extend the first block to full length
// 2. write the middle empty blocks // 2. write the middle empty blocks
// 3. write the last block // 3. write the last block
req.offset = oldLastBlock * _blockSize; req.offset = oldLastBlock * _blockSize;
req.dataLen = oldSize % _blockSize; req.dataLen = oldSize % _blockSize;
// 1. req.dataLen == 0, iff oldSize was already a multiple of 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; VLOG(1) << "padding block " << oldLastBlock;
memset( mb.data, 0, _blockSize ); memset(mb.data, 0, _blockSize);
cacheReadOneBlock( req ); cacheReadOneBlock(req);
req.dataLen = _blockSize; // expand to full block size req.dataLen = _blockSize; // expand to full block size
cacheWriteOneBlock( req ); cacheWriteOneBlock(req);
++oldLastBlock; ++oldLastBlock;
} }
// 2, pad zero blocks unless holes are allowed // 2, pad zero blocks unless holes are allowed
if(!_allowHoles) if (!_allowHoles) {
{ for (; oldLastBlock != newLastBlock; ++oldLastBlock) {
for(; oldLastBlock != newLastBlock; ++oldLastBlock)
{
VLOG(1) << "padding block " << oldLastBlock; VLOG(1) << "padding block " << oldLastBlock;
req.offset = oldLastBlock * _blockSize; req.offset = oldLastBlock * _blockSize;
req.dataLen = _blockSize; req.dataLen = _blockSize;
memset( mb.data, 0, req.dataLen ); memset(mb.data, 0, req.dataLen);
cacheWriteOneBlock( req ); cacheWriteOneBlock(req);
} }
} }
// 3. only necessary if write is forced and block is non 0 length // 3. only necessary if write is forced and block is non 0 length
if(forceWrite && lastBlockSize) if (forceWrite && lastBlockSize) {
{
req.offset = newLastBlock * _blockSize; req.offset = newLastBlock * _blockSize;
req.dataLen = lastBlockSize; req.dataLen = lastBlockSize;
memset( mb.data, 0, req.dataLen ); memset(mb.data, 0, req.dataLen);
cacheWriteOneBlock( req ); cacheWriteOneBlock(req);
} }
} }
} }
int BlockFileIO::blockTruncate( off_t size, FileIO *base ) int BlockFileIO::blockTruncate(off_t size, FileIO *base) {
{
rAssert(size >= 0); rAssert(size >= 0);
int partialBlock = size % _blockSize; int partialBlock = size % _blockSize;
@ -369,61 +323,51 @@ int BlockFileIO::blockTruncate( off_t size, FileIO *base )
off_t oldSize = getSize(); off_t oldSize = getSize();
if( size > oldSize ) if (size > oldSize) {
{
// truncate can be used to extend a file as well. truncate man page // truncate can be used to extend a file as well. truncate man page
// states that it will pad with 0's. // states that it will pad with 0's.
// do the truncate so that the underlying filesystem can allocate // do the truncate so that the underlying filesystem can allocate
// the space, and then we'll fill it in padFile.. // the space, and then we'll fill it in padFile..
if(base) if (base) base->truncate(size);
base->truncate( size );
const bool forceWrite = true; const bool forceWrite = true;
padFile( oldSize, size, forceWrite ); padFile(oldSize, size, forceWrite);
} else } else if (size == oldSize) {
if( size == oldSize ) // the easiest case, but least likely....
{ } else if (partialBlock) {
// the easiest case, but least likely.... // partial block after truncate. Need to read in the block being
} else // truncated before the truncate. Then write it back out afterwards,
if( partialBlock ) // since the encoding will change..
{ off_t blockNum = size / _blockSize;
// partial block after truncate. Need to read in the block being MemBlock mb;
// truncated before the truncate. Then write it back out afterwards, mb.allocate(_blockSize);
// since the encoding will change..
off_t blockNum = size / _blockSize;
MemBlock mb;
mb.allocate( _blockSize );
IORequest req; IORequest req;
req.offset = blockNum * _blockSize; req.offset = blockNum * _blockSize;
req.dataLen = _blockSize; req.dataLen = _blockSize;
req.data = mb.data; req.data = mb.data;
ssize_t rdSz = cacheReadOneBlock( req ); ssize_t rdSz = cacheReadOneBlock(req);
// do the truncate // do the truncate
if(base) if (base) res = base->truncate(size);
res = base->truncate( size );
// write back out partial block // write back out partial block
req.dataLen = partialBlock; req.dataLen = partialBlock;
bool wrRes = cacheWriteOneBlock( req ); bool wrRes = cacheWriteOneBlock(req);
if((rdSz < 0) || (!wrRes)) if ((rdSz < 0) || (!wrRes)) {
{ LOG(ERROR) << "truncate failure: read size " << rdSz
LOG(ERROR) << "truncate failure: read size " << rdSz << ", partial block of " << partialBlock;
<< ", partial block of " << partialBlock; }
}
} else } else {
{ // truncating on a block bounday. No need to re-encode the last
// truncating on a block bounday. No need to re-encode the last // block..
// block.. if (base) res = base->truncate(size);
if(base) }
res = base->truncate( size );
}
return res; return res;
} }
} // namespace encfs } // namespace encfs

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * 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 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 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 the existing block, merge with the write request, and a write of the full
block. block.
*/ */
class BlockFileIO : public FileIO class BlockFileIO : public FileIO {
{ public:
public: BlockFileIO(int blockSize, const FSConfigPtr &cfg);
BlockFileIO( int blockSize, const FSConfigPtr &cfg ); virtual ~BlockFileIO();
virtual ~BlockFileIO();
// implemented in terms of blocks. // implemented in terms of blocks.
virtual ssize_t read( const IORequest &req ) const; virtual ssize_t read(const IORequest &req) const;
virtual bool write( const IORequest &req ); 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 ); // same as read(), except that the request.offset field is guarenteed to be
void padFile( off_t oldSize, off_t newSize, bool forceWrite ); // 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 ssize_t cacheReadOneBlock(const IORequest &req) const;
// block aligned, and the request size will not be larger then 1 block. bool cacheWriteOneBlock(const IORequest &req);
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 );
int _blockSize; int _blockSize;
bool _allowHoles; bool _allowHoles;
// cache last block for speed... // cache last block for speed...
mutable IORequest _cache; mutable IORequest _cache;
}; };
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -30,33 +30,30 @@
namespace encfs { namespace encfs {
static shared_ptr<NameIO> NewBlockNameIO( const Interface &iface, static shared_ptr<NameIO> NewBlockNameIO(const Interface &iface,
const shared_ptr<CipherV1> &cipher ) const shared_ptr<CipherV1> &cipher) {
{ return shared_ptr<NameIO>(new BlockNameIO(iface, cipher, false));
return shared_ptr<NameIO>(
new BlockNameIO( iface, cipher, false));
} }
static shared_ptr<NameIO> NewBlockNameIO32( const Interface &iface, static shared_ptr<NameIO> NewBlockNameIO32(const Interface &iface,
const shared_ptr<CipherV1> &cipher ) const shared_ptr<CipherV1> &cipher) {
{ return shared_ptr<NameIO>(new BlockNameIO(iface, cipher, true));
return shared_ptr<NameIO>(
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.. // description of block name encoding algorithm..
// xgroup(setup) // xgroup(setup)
gettext_noop("Block encoding, hides file name size somewhat"), gettext_noop("Block encoding, hides file name size somewhat"),
BlockNameIO::CurrentInterface(false), BlockNameIO::CurrentInterface(false), NewBlockNameIO, false);
NewBlockNameIO, false);
static bool BlockIO32_registered = NameIO::Register("Block32", static bool BlockIO32_registered = NameIO::Register(
"Block32",
// description of block name encoding algorithm.. // description of block name encoding algorithm..
// xgroup(setup) // xgroup(setup)
gettext_noop("Block encoding with base32 output for case-sensitive systems"), gettext_noop(
BlockNameIO::CurrentInterface(true), "Block encoding with base32 output for case-sensitive systems"),
NewBlockNameIO32, false); BlockNameIO::CurrentInterface(true), NewBlockNameIO32, false);
/* /*
- Version 1.0 computed MAC over the filename, but not the padding bytes. - 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 - Version 4.0 adds support for base32, creating names more suitable for
case-insensitive filesystems (eg Mac). 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 // implement major version 4 plus support for two prior versions
if (caseSensitive) if (caseSensitive)
return makeInterface("nameio/block32", 4, 0, 2); return makeInterface("nameio/block32", 4, 0, 2);
@ -84,172 +80,146 @@ Interface BlockNameIO::CurrentInterface(bool caseSensitive)
return makeInterface("nameio/block", 4, 0, 2); return makeInterface("nameio/block", 4, 0, 2);
} }
BlockNameIO::BlockNameIO( const Interface &iface, BlockNameIO::BlockNameIO(const Interface &iface,
const shared_ptr<CipherV1> &cipher, const shared_ptr<CipherV1> &cipher,
bool caseSensitiveEncoding ) bool caseSensitiveEncoding)
: _interface( iface.major() ) : _interface(iface.major()),
, _bs( cipher->cipherBlockSize() ) _bs(cipher->cipherBlockSize()),
, _cipher( cipher ) _cipher(cipher),
, _caseSensitive( caseSensitiveEncoding ) _caseSensitive(caseSensitiveEncoding) {
{ rAssert(_bs < 128);
rAssert( _bs < 128 );
} }
BlockNameIO::~BlockNameIO() BlockNameIO::~BlockNameIO() {}
{
}
Interface BlockNameIO::interface() const Interface BlockNameIO::interface() const {
{
return CurrentInterface(_caseSensitive); 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 // number of blocks, rounded up.. Only an estimate at this point, err on
// the size of too much space rather then too little. // the size of too much space rather then too little.
int numBlocks = ( plaintextNameLen + _bs ) / _bs; int numBlocks = (plaintextNameLen + _bs) / _bs;
int encodedNameLen = numBlocks * _bs + 2; // 2 checksum bytes int encodedNameLen = numBlocks * _bs + 2; // 2 checksum bytes
if (_caseSensitive) if (_caseSensitive)
return B256ToB32Bytes( encodedNameLen ); return B256ToB32Bytes(encodedNameLen);
else else
return B256ToB64Bytes( encodedNameLen ); return B256ToB64Bytes(encodedNameLen);
} }
int BlockNameIO::maxDecodedNameLen( int encodedNameLen ) const int BlockNameIO::maxDecodedNameLen(int encodedNameLen) const {
{ int decLen256 = _caseSensitive ? B32ToB256Bytes(encodedNameLen)
int decLen256 = _caseSensitive ? : B64ToB256Bytes(encodedNameLen);
B32ToB256Bytes( encodedNameLen ) : return decLen256 - 2; // 2 checksum bytes removed..
B64ToB256Bytes( encodedNameLen );
return decLen256 - 2; // 2 checksum bytes removed..
} }
int BlockNameIO::encodeName( const char *plaintextName, int length, int BlockNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv,
uint64_t *iv, char *encodedName ) const char *encodedName) const {
{
// copy the data into the encoding buffer.. // copy the data into the encoding buffer..
memcpy( encodedName+2, plaintextName, length ); memcpy(encodedName + 2, plaintextName, length);
// Pad encryption buffer to block boundary.. // Pad encryption buffer to block boundary..
int padding = _bs - length % _bs; int padding = _bs - length % _bs;
if(padding == 0) if (padding == 0) padding = _bs; // padding a full extra block!
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. // store the IV before it is modified by the MAC call.
uint64_t tmpIV = 0; uint64_t tmpIV = 0;
if( iv && _interface >= 3 ) if (iv && _interface >= 3) tmpIV = *iv;
tmpIV = *iv;
// include padding in MAC computation // include padding in MAC computation
unsigned int mac = _cipher->reduceMac16( unsigned int mac = _cipher->reduceMac16(
_cipher->MAC_64( (unsigned char *)encodedName+2, _cipher->MAC_64((unsigned char *)encodedName + 2, length + padding, iv));
length+padding, iv ));
// add checksum bytes // add checksum bytes
encodedName[0] = (mac >> 8) & 0xff; encodedName[0] = (mac >> 8) & 0xff;
encodedName[1] = (mac ) & 0xff; encodedName[1] = (mac) & 0xff;
_cipher->blockEncode( (unsigned char *)encodedName+2, length+padding, _cipher->blockEncode((unsigned char *)encodedName + 2, length + padding,
(uint64_t)mac ^ tmpIV ); (uint64_t)mac ^ tmpIV);
// convert to base 64 ascii // convert to base 64 ascii
int encodedStreamLen = length + 2 + padding; int encodedStreamLen = length + 2 + padding;
int encLen; int encLen;
if (_caseSensitive) if (_caseSensitive) {
{ encLen = B256ToB32Bytes(encodedStreamLen);
encLen = B256ToB32Bytes( encodedStreamLen );
changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen, changeBase2Inline((unsigned char *)encodedName, encodedStreamLen, 8, 5,
8, 5, true ); true);
B32ToAscii( (unsigned char *)encodedName, encLen ); B32ToAscii((unsigned char *)encodedName, encLen);
} else } else {
{ encLen = B256ToB64Bytes(encodedStreamLen);
encLen = B256ToB64Bytes( encodedStreamLen );
changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen, changeBase2Inline((unsigned char *)encodedName, encodedStreamLen, 8, 6,
8, 6, true ); true);
B64ToAscii( (unsigned char *)encodedName, encLen ); B64ToAscii((unsigned char *)encodedName, encLen);
} }
return encLen; return encLen;
} }
int BlockNameIO::decodeName( const char *encodedName, int length, int BlockNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
uint64_t *iv, char *plaintextName ) const char *plaintextName) const {
{ int decLen256 =
int decLen256 = _caseSensitive ? _caseSensitive ? B32ToB256Bytes(length) : B64ToB256Bytes(length);
B32ToB256Bytes( length ) :
B64ToB256Bytes( length );
int decodedStreamLen = decLen256 - 2; int decodedStreamLen = decLen256 - 2;
// don't bother trying to decode files which are too small // don't bother trying to decode files which are too small
if(decodedStreamLen < _bs) if (decodedStreamLen < _bs) throw Error("Filename too small to decode");
throw Error("Filename too small to decode");
BUFFER_INIT( tmpBuf, 32, (unsigned int)length ); BUFFER_INIT(tmpBuf, 32, (unsigned int)length);
// decode into tmpBuf, // decode into tmpBuf,
if (_caseSensitive) if (_caseSensitive) {
{
AsciiToB32((unsigned char *)tmpBuf, (unsigned char *)encodedName, length); AsciiToB32((unsigned char *)tmpBuf, (unsigned char *)encodedName, length);
changeBase2Inline((unsigned char *)tmpBuf, length, 5, 8, false); changeBase2Inline((unsigned char *)tmpBuf, length, 5, 8, false);
} else } else {
{
AsciiToB64((unsigned char *)tmpBuf, (unsigned char *)encodedName, length); AsciiToB64((unsigned char *)tmpBuf, (unsigned char *)encodedName, length);
changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false); changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false);
} }
// pull out the header information // pull out the header information
unsigned int mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 unsigned int mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 |
| ((unsigned int)((unsigned char)tmpBuf[1])); ((unsigned int)((unsigned char)tmpBuf[1]));
uint64_t tmpIV = 0; uint64_t tmpIV = 0;
if( iv && _interface >= 3 ) if (iv && _interface >= 3) tmpIV = *iv;
tmpIV = *iv;
_cipher->blockDecode( (unsigned char *)tmpBuf+2, decodedStreamLen, _cipher->blockDecode((unsigned char *)tmpBuf + 2, decodedStreamLen,
(uint64_t)mac ^ tmpIV ); (uint64_t)mac ^ tmpIV);
// find out true string length // 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; int finalSize = decodedStreamLen - padding;
// might happen if there is an error decoding.. // might happen if there is an error decoding..
if(padding > _bs || finalSize < 0) if (padding > _bs || finalSize < 0) {
{ VLOG(1) << "padding, _bx, finalSize = " << padding << ", " << _bs << ", "
VLOG(1) << "padding, _bx, finalSize = " << padding << finalSize;
<< ", " << _bs << ", " << finalSize; throw Error("invalid padding size");
throw Error( "invalid padding size" );
} }
// copy out the result.. // copy out the result..
memcpy(plaintextName, tmpBuf+2, finalSize); memcpy(plaintextName, tmpBuf + 2, finalSize);
plaintextName[finalSize] = '\0'; plaintextName[finalSize] = '\0';
// check the mac // check the mac
unsigned int mac2 = _cipher->reduceMac16( unsigned int mac2 = _cipher->reduceMac16(
_cipher->MAC_64((const unsigned char *)tmpBuf+2, _cipher->MAC_64((const unsigned char *)tmpBuf + 2, decodedStreamLen, iv));
decodedStreamLen, iv));
BUFFER_RESET( tmpBuf ); BUFFER_RESET(tmpBuf);
if(mac2 != mac) if (mac2 != mac) {
{ LOG(INFO) << "checksum mismatch: expected " << mac << ", got " << mac2
LOG(INFO) << "checksum mismatch: expected " << mac << ", got " << " on decode of " << finalSize << " bytes";
<< mac2 << " on decode of " << finalSize << " bytes"; throw Error("checksum mismatch in filename decode");
throw Error( "checksum mismatch in filename decode" );
} }
return finalSize; return finalSize;
} }
bool BlockNameIO::Enabled() bool BlockNameIO::Enabled() { return true; }
{
return true;
}
} // namespace encfs } // namespace encfs

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * 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 mode to encode filenames. The filenames are padded to be a multiple of the
cipher block size. cipher block size.
*/ */
class BlockNameIO : public NameIO class BlockNameIO : public NameIO {
{
public: public:
static Interface CurrentInterface(bool caseSensitive = false); static Interface CurrentInterface(bool caseSensitive = false);
BlockNameIO(const Interface &iface, BlockNameIO(const Interface &iface, const shared_ptr<CipherV1> &cipher,
const shared_ptr<CipherV1> &cipher, bool caseSensitiveEncoding = false);
bool caseSensitiveEncoding = false );
virtual ~BlockNameIO(); virtual ~BlockNameIO();
virtual Interface interface() const; virtual Interface interface() const;
virtual int maxEncodedNameLen( int plaintextNameLen ) const; virtual int maxEncodedNameLen(int plaintextNameLen) const;
virtual int maxDecodedNameLen( int encodedNameLen ) const; virtual int maxDecodedNameLen(int encodedNameLen) const;
// hack to help with static builds // hack to help with static builds
static bool Enabled(); static bool Enabled();
protected: protected:
virtual int encodeName(const char *plaintextName, int length, virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
uint64_t *iv, char *encodedName ) const; char *encodedName) const;
virtual int decodeName(const char *encodedName, int length, virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
uint64_t *iv, char *plaintextName ) const; char *plaintextName) const;
private: private:
int _interface; int _interface;
@ -67,4 +66,3 @@ class BlockNameIO : public NameIO
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * 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); static Interface CipherFileIO_iface = makeInterface("FileIO/Cipher", 3, 0, 2);
CipherFileIO::CipherFileIO( const shared_ptr<FileIO> &_base, CipherFileIO::CipherFileIO(const shared_ptr<FileIO> &_base,
const FSConfigPtr &cfg) const FSConfigPtr &cfg)
: BlockFileIO( cfg->config->block_size(), cfg ) : BlockFileIO(cfg->config->block_size(), cfg),
, base( _base ) base(_base),
, headerLen( 0 ) headerLen(0),
, perFileIV( cfg->config->unique_iv() ) perFileIV(cfg->config->unique_iv()),
, externalIV( 0 ) externalIV(0),
, fileIV( 0 ) fileIV(0),
, lastFlags( 0 ) lastFlags(0) {
{
fsConfig = cfg; fsConfig = cfg;
cipher = cfg->cipher; cipher = cfg->cipher;
if ( perFileIV ) if (perFileIV) headerLen += sizeof(uint64_t); // 64bit IV per file
headerLen += sizeof(uint64_t); // 64bit IV per file
int blockBoundary = fsConfig->config->block_size() % int blockBoundary =
fsConfig->cipher->cipherBlockSize(); fsConfig->config->block_size() % fsConfig->cipher->cipherBlockSize();
if(blockBoundary != 0) if (blockBoundary != 0) {
{ LOG_FIRST_N(ERROR, 1)
LOG_FIRST_N(ERROR, 1) << "CipherFileIO: blocks should be multiple of cipher block size";
<< "CipherFileIO: blocks should be multiple of cipher block size";
} }
} }
CipherFileIO::~CipherFileIO() CipherFileIO::~CipherFileIO() {}
{
}
Interface CipherFileIO::interface() const Interface CipherFileIO::interface() const { return CipherFileIO_iface; }
{
return CipherFileIO_iface;
}
int CipherFileIO::open( int flags ) int CipherFileIO::open(int flags) {
{ int res = base->open(flags);
int res = base->open( flags );
if (res >= 0) lastFlags = flags;
if( res >= 0 )
lastFlags = flags;
return res; return res;
} }
void CipherFileIO::setFileName( const char *fileName ) void CipherFileIO::setFileName(const char *fileName) {
{ base->setFileName(fileName);
base->setFileName( fileName );
} }
const char *CipherFileIO::getFileName() const const char *CipherFileIO::getFileName() const { return base->getFileName(); }
{
return base->getFileName();
}
bool CipherFileIO::setIV( uint64_t iv ) bool CipherFileIO::setIV(uint64_t iv) {
{ VLOG(1) << "in setIV, current IV = " << externalIV << ", new IV = " << iv
VLOG(1) << "in setIV, current IV = " << externalIV << ", fileIV = " << fileIV;
<< ", new IV = " << iv << ", fileIV = " << fileIV; if (externalIV == 0) {
if(externalIV == 0)
{
// we're just being told about which IV to use. since we haven't // we're just being told about which IV to use. since we haven't
// initialized the fileIV, there is no need to just yet.. // initialized the fileIV, there is no need to just yet..
externalIV = iv; externalIV = iv;
LOG_IF(WARNING, fileIV != 0) LOG_IF(WARNING, fileIV != 0) << "fileIV initialized before externalIV! ("
<< "fileIV initialized before externalIV! (" << fileIV << fileIV << ", " << externalIV << ")";
<< ", " << externalIV << ")"; } else if (perFileIV) {
} else if(perFileIV)
{
// we have an old IV, and now a new IV, so we need to update the fileIV // we have an old IV, and now a new IV, so we need to update the fileIV
// on disk. // on disk.
if(fileIV == 0) if (fileIV == 0) {
{
// ensure the file is open for read/write.. // ensure the file is open for read/write..
int newFlags = lastFlags | O_RDWR; int newFlags = lastFlags | O_RDWR;
int res = base->open( newFlags ); int res = base->open(newFlags);
if(res < 0) if (res < 0) {
{ if (res == -EISDIR) {
if(res == -EISDIR)
{
// duh -- there are no file headers for directories! // duh -- there are no file headers for directories!
externalIV = iv; externalIV = iv;
return base->setIV( iv ); return base->setIV(iv);
} else } else {
{
VLOG(1) << "writeHeader failed to re-open for write"; VLOG(1) << "writeHeader failed to re-open for write";
return false; return false;
} }
@ -133,46 +111,40 @@ bool CipherFileIO::setIV( uint64_t iv )
uint64_t oldIV = externalIV; uint64_t oldIV = externalIV;
externalIV = iv; externalIV = iv;
if(!writeHeader()) if (!writeHeader()) {
{
externalIV = oldIV; externalIV = oldIV;
return false; 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; off_t size = rawSize;
if (rawSize >= headerLen) if (rawSize >= headerLen) size -= headerLen;
size -= headerLen;
return size; return size;
} }
int CipherFileIO::getAttr( struct stat *stbuf ) const int CipherFileIO::getAttr(struct stat *stbuf) const {
{ int res = base->getAttr(stbuf);
int res = base->getAttr( stbuf );
// adjust size if we have a file header // 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); stbuf->st_size = adjustedSize(stbuf->st_size);
return res; return res;
} }
off_t CipherFileIO::getSize() const off_t CipherFileIO::getSize() const {
{
// No check on S_ISREG here -- getSize only for normal files! // No check on S_ISREG here -- getSize only for normal files!
off_t size = base->getSize(); off_t size = base->getSize();
return adjustedSize(size); return adjustedSize(size);
} }
void CipherFileIO::initHeader( ) void CipherFileIO::initHeader() {
{
int cbs = cipher->cipherBlockSize(); int cbs = cipher->cipherBlockSize();
MemBlock mb; MemBlock mb;
@ -181,90 +153,79 @@ void CipherFileIO::initHeader( )
// check if the file has a header, and read it if it does.. Otherwise, // check if the file has a header, and read it if it does.. Otherwise,
// create one. // create one.
off_t rawSize = base->getSize(); off_t rawSize = base->getSize();
if(rawSize >= headerLen) if (rawSize >= headerLen) {
{
VLOG(1) << "reading existing header, rawSize = " << rawSize; VLOG(1) << "reading existing header, rawSize = " << rawSize;
IORequest req; IORequest req;
req.offset = 0; req.offset = 0;
req.data = mb.data; req.data = mb.data;
req.dataLen = sizeof(uint64_t); req.dataLen = sizeof(uint64_t);
base->read( req ); base->read(req);
if (perFileIV) if (perFileIV) {
{ cipher->streamDecode(mb.data, sizeof(uint64_t), externalIV);
cipher->streamDecode( mb.data, sizeof(uint64_t), externalIV );
fileIV = 0; fileIV = 0;
for(unsigned int i=0; i<sizeof(uint64_t); ++i) for (unsigned int i = 0; i < sizeof(uint64_t); ++i)
fileIV = (fileIV << 8) | (uint64_t)mb.data[i]; fileIV = (fileIV << 8) | (uint64_t)mb.data[i];
rAssert(fileIV != 0); // 0 is never used.. rAssert(fileIV != 0); // 0 is never used..
} }
} else if (perFileIV) } else if (perFileIV) {
{
VLOG(1) << "creating new file IV header"; VLOG(1) << "creating new file IV header";
do do {
{ if (!cipher->pseudoRandomize(mb.data, 8))
if(!cipher->pseudoRandomize( mb.data, 8 ))
throw Error("Unable to generate a random file IV"); throw Error("Unable to generate a random file IV");
fileIV = 0; fileIV = 0;
for(unsigned int i=0; i<sizeof(uint64_t); ++i) for (unsigned int i = 0; i < sizeof(uint64_t); ++i)
fileIV = (fileIV << 8) | (uint64_t)mb.data[i]; fileIV = (fileIV << 8) | (uint64_t)mb.data[i];
LOG_IF(WARNING, fileIV == 0) LOG_IF(WARNING, fileIV == 0)
<< "Unexpected result: randomize returned 8 null bytes!"; << "Unexpected result: randomize returned 8 null bytes!";
} while(fileIV == 0); // don't accept 0 as an option.. } while (fileIV == 0); // don't accept 0 as an option..
cipher->streamEncode( mb.data, sizeof(uint64_t), externalIV );
if( base->isWritable() ) cipher->streamEncode(mb.data, sizeof(uint64_t), externalIV);
{
if (base->isWritable()) {
IORequest req; IORequest req;
req.offset = 0; req.offset = 0;
req.data = mb.data; req.data = mb.data;
req.dataLen = sizeof(uint64_t); req.dataLen = sizeof(uint64_t);
base->write( req ); base->write(req);
} else } else
VLOG(1) << "base not writable, IV not written.."; VLOG(1) << "base not writable, IV not written..";
} }
VLOG(1) << "initHeader finished, fileIV = " << fileIV; VLOG(1) << "initHeader finished, fileIV = " << fileIV;
} }
bool CipherFileIO::writeHeader( ) bool CipherFileIO::writeHeader() {
{ if (!base->isWritable()) {
if( !base->isWritable() )
{
// open for write.. // open for write..
int newFlags = lastFlags | O_RDWR; int newFlags = lastFlags | O_RDWR;
if( base->open( newFlags ) < 0 ) if (base->open(newFlags) < 0) {
{
VLOG(1) << "writeHeader failed to re-open for write"; VLOG(1) << "writeHeader failed to re-open for write";
return false; return false;
} }
} }
LOG_IF(ERROR, fileIV == 0) LOG_IF(ERROR, fileIV == 0) << "Internal error: fileIV == 0 in writeHeader!!!";
<< "Internal error: fileIV == 0 in writeHeader!!!";
VLOG(1) << "writing fileIV " << fileIV; VLOG(1) << "writing fileIV " << fileIV;
MemBlock mb; MemBlock mb;
mb.allocate(headerLen); mb.allocate(headerLen);
if (perFileIV) if (perFileIV) {
{
unsigned char *buf = mb.data; 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); buf[i] = (unsigned char)(fileIV & 0xff);
fileIV >>= 8; fileIV >>= 8;
} }
cipher->streamEncode( buf, sizeof(uint64_t), externalIV ); cipher->streamEncode(buf, sizeof(uint64_t), externalIV);
} }
IORequest req; IORequest req;
@ -272,13 +233,12 @@ bool CipherFileIO::writeHeader( )
req.data = mb.data; req.data = mb.data;
req.dataLen = headerLen; req.dataLen = headerLen;
base->write( req ); base->write(req);
return true; return true;
} }
ssize_t CipherFileIO::readOneBlock( const IORequest &req ) const ssize_t CipherFileIO::readOneBlock(const IORequest &req) const {
{
// read raw data, then decipher it.. // read raw data, then decipher it..
int bs = blockSize(); int bs = blockSize();
rAssert(req.dataLen <= bs); rAssert(req.dataLen <= bs);
@ -292,31 +252,25 @@ ssize_t CipherFileIO::readOneBlock( const IORequest &req ) const
tmpReq.offset += headerLen; tmpReq.offset += headerLen;
int maxReadSize = req.dataLen; int maxReadSize = req.dataLen;
readSize = base->read( tmpReq ); readSize = base->read(tmpReq);
bool ok; bool ok;
if(readSize > 0) if (readSize > 0) {
{ if (headerLen != 0 && fileIV == 0)
if(headerLen != 0 && fileIV == 0) const_cast<CipherFileIO *>(this)->initHeader();
const_cast<CipherFileIO*>(this)->initHeader();
if(readSize == bs) if (readSize == bs) {
{ ok = blockRead(tmpReq.data, bs, blockNum ^ fileIV);
ok = blockRead( tmpReq.data, bs, blockNum ^ fileIV); } else {
} else ok = streamRead(tmpReq.data, (int)readSize, blockNum ^ fileIV);
{
ok = streamRead( tmpReq.data, (int)readSize, blockNum ^ fileIV);
} }
if(!ok) if (!ok) {
{ VLOG(1) << "decodeBlock failed for block " << blockNum << ", size "
VLOG(1) << "decodeBlock failed for block " << blockNum << readSize;
<< ", size " << readSize;
readSize = -1; readSize = -1;
} else if (tmpReq.data != req.data) } else if (tmpReq.data != req.data) {
{ if (readSize > maxReadSize) readSize = maxReadSize;
if (readSize > maxReadSize)
readSize = maxReadSize;
memcpy(req.data, tmpReq.data, readSize); memcpy(req.data, tmpReq.data, readSize);
} }
} else } else
@ -325,38 +279,28 @@ ssize_t CipherFileIO::readOneBlock( const IORequest &req ) const
return readSize; return readSize;
} }
bool CipherFileIO::writeOneBlock(const IORequest &req) {
bool CipherFileIO::writeOneBlock( const IORequest &req )
{
int bs = blockSize(); int bs = blockSize();
off_t blockNum = req.offset / bs; off_t blockNum = req.offset / bs;
if(headerLen != 0 && fileIV == 0) if (headerLen != 0 && fileIV == 0) initHeader();
initHeader();
MemBlock mb; MemBlock mb;
bool ok; bool ok;
if (req.dataLen == bs) if (req.dataLen == bs) {
{ ok = blockWrite(req.data, bs, blockNum ^ fileIV);
ok = blockWrite( req.data, bs, blockNum ^ fileIV ); } else {
} else ok = streamWrite(req.data, (int)req.dataLen, blockNum ^ fileIV);
{
ok = streamWrite( req.data, (int)req.dataLen,
blockNum ^ fileIV );
} }
if( ok ) if (ok) {
{ if (headerLen != 0) {
if(headerLen != 0)
{
IORequest nreq = req; IORequest nreq = req;
if (mb.data == NULL) if (mb.data == NULL) {
{
nreq.offset += headerLen; nreq.offset += headerLen;
} else } else {
{
// Partial block is stored at front of file. // Partial block is stored at front of file.
nreq.offset = 0; nreq.offset = 0;
nreq.data = mb.data; nreq.data = mb.data;
@ -364,78 +308,66 @@ bool CipherFileIO::writeOneBlock( const IORequest &req )
base->truncate(req.offset + req.dataLen + headerLen); base->truncate(req.offset + req.dataLen + headerLen);
} }
ok = base->write( nreq ); ok = base->write(nreq);
} else } else
ok = base->write( req ); ok = base->write(req);
} else } else {
{ VLOG(1) << "encodeBlock failed for block " << blockNum << ", size "
VLOG(1) << "encodeBlock failed for block " << blockNum << req.dataLen;
<< ", size " << req.dataLen;
ok = false; ok = false;
} }
return ok; return ok;
} }
bool CipherFileIO::blockWrite( unsigned char *buf, int size, bool CipherFileIO::blockWrite(unsigned char *buf, int size,
uint64_t _iv64 ) const uint64_t _iv64) const {
{
if (!fsConfig->reverseEncryption) if (!fsConfig->reverseEncryption)
return cipher->blockEncode( buf, size, _iv64 ); return cipher->blockEncode(buf, size, _iv64);
else else
return cipher->blockDecode( buf, size, _iv64 ); return cipher->blockDecode(buf, size, _iv64);
} }
bool CipherFileIO::streamWrite( unsigned char *buf, int size, bool CipherFileIO::streamWrite(unsigned char *buf, int size,
uint64_t _iv64 ) const uint64_t _iv64) const {
{
if (!fsConfig->reverseEncryption) if (!fsConfig->reverseEncryption)
return cipher->streamEncode( buf, size, _iv64 ); return cipher->streamEncode(buf, size, _iv64);
else else
return cipher->streamDecode( buf, size, _iv64 ); return cipher->streamDecode(buf, size, _iv64);
} }
bool CipherFileIO::blockRead(unsigned char *buf, int size,
bool CipherFileIO::blockRead( unsigned char *buf, int size, uint64_t _iv64) const {
uint64_t _iv64 ) const
{
if (fsConfig->reverseEncryption) if (fsConfig->reverseEncryption)
return cipher->blockEncode( buf, size, _iv64 ); return cipher->blockEncode(buf, size, _iv64);
else if(_allowHoles) else if (_allowHoles) {
{
// special case - leave all 0's alone // special case - leave all 0's alone
for(int i=0; i<size; ++i) for (int i = 0; i < size; ++i)
if(buf[i] != 0) if (buf[i] != 0) return cipher->blockDecode(buf, size, _iv64);
return cipher->blockDecode( buf, size, _iv64 );
return true; return true;
} else } else
return cipher->blockDecode( buf, size, _iv64 ); return cipher->blockDecode(buf, size, _iv64);
} }
bool CipherFileIO::streamRead( unsigned char *buf, int size, bool CipherFileIO::streamRead(unsigned char *buf, int size,
uint64_t _iv64 ) const uint64_t _iv64) const {
{
if (fsConfig->reverseEncryption) if (fsConfig->reverseEncryption)
return cipher->streamEncode( buf, size, _iv64 ); return cipher->streamEncode(buf, size, _iv64);
else 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); rAssert(size >= 0);
if(headerLen == 0) if (headerLen == 0) {
{ return blockTruncate(size, base.get());
return blockTruncate( size, base.get() ); } else if (0 == fileIV) {
} else if(0 == fileIV)
{
// empty file.. create the header.. // empty file.. create the header..
if( !base->isWritable() ) if (!base->isWritable()) {
{
// open for write.. // open for write..
int newFlags = lastFlags | O_RDWR; int newFlags = lastFlags | O_RDWR;
if( base->open( newFlags ) < 0 ) if (base->open(newFlags) < 0)
VLOG(1) << "writeHeader failed to re-open for write"; VLOG(1) << "writeHeader failed to re-open for write";
} }
initHeader(); initHeader();
@ -443,17 +375,13 @@ int CipherFileIO::truncate( off_t size )
// can't let BlockFileIO call base->truncate(), since it would be using // can't let BlockFileIO call base->truncate(), since it would be using
// the wrong size.. // the wrong size..
int res = blockTruncate( size, 0 ); int res = blockTruncate(size, 0);
if(res == 0) if (res == 0) base->truncate(size + headerLen);
base->truncate( size + headerLen );
return res; return res;
} }
bool CipherFileIO::isWritable() const bool CipherFileIO::isWritable() const { return base->isWritable(); }
{
return base->isWritable();
}
} // namespace encfs } // namespace encfs

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -32,66 +32,60 @@ namespace encfs {
class CipherV1; 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. Uses BlockFileIO to handle the block scatter / gather issues.
*/ */
class CipherFileIO : public BlockFileIO class CipherFileIO : public BlockFileIO {
{ public:
public: CipherFileIO(const shared_ptr<FileIO> &base, const FSConfigPtr &cfg);
CipherFileIO( const shared_ptr<FileIO> &base, virtual ~CipherFileIO();
const FSConfigPtr &cfg);
virtual ~CipherFileIO();
virtual Interface interface() const; virtual Interface interface() const;
virtual void setFileName( const char *fileName ); virtual void setFileName(const char *fileName);
virtual const char *getFileName() const; virtual const char *getFileName() const;
virtual bool setIV( uint64_t iv ); virtual bool setIV(uint64_t iv);
virtual int open( int flags ); virtual int open(int flags);
virtual int getAttr( struct stat *stbuf ) const; virtual int getAttr(struct stat *stbuf) const;
virtual off_t getSize() const; virtual off_t getSize() const;
// NOTE: if truncate is used to extend the file, the extended plaintext is // 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 // not 0. The extended ciphertext may be 0, resulting in non-zero
// plaintext. // plaintext.
virtual int truncate( off_t size ); virtual int truncate(off_t size);
virtual bool isWritable() const; virtual bool isWritable() const;
private: private:
virtual ssize_t readOneBlock( const IORequest &req ) const; virtual ssize_t readOneBlock(const IORequest &req) const;
virtual bool writeOneBlock( const IORequest &req ); virtual bool writeOneBlock(const IORequest &req);
void initHeader(); void initHeader();
bool writeHeader(); bool writeHeader();
bool blockRead( unsigned char *buf, int size, bool blockRead(unsigned char *buf, int size, uint64_t iv64) const;
uint64_t iv64 ) const; bool streamRead(unsigned char *buf, int size, uint64_t iv64) const;
bool streamRead( unsigned char *buf, int size, bool blockWrite(unsigned char *buf, int size, uint64_t iv64) const;
uint64_t iv64 ) const; bool streamWrite(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<FileIO> base; shared_ptr<FileIO> base;
FSConfigPtr fsConfig; FSConfigPtr fsConfig;
// if haveHeader is true, then we have a transparent file header which // if haveHeader is true, then we have a transparent file header which
int headerLen; int headerLen;
bool perFileIV; bool perFileIV;
bool externalIVChaining; bool externalIVChaining;
uint64_t externalIV; uint64_t externalIV;
uint64_t fileIV; uint64_t fileIV;
int lastFlags; int lastFlags;
shared_ptr<CipherV1> cipher; shared_ptr<CipherV1> cipher;
}; };
} // namespace encfs } // namespace encfs

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -27,67 +27,55 @@
namespace encfs { namespace encfs {
EncFS_Context::EncFS_Context() EncFS_Context::EncFS_Context() {
{
#ifdef CMAKE_USE_PTHREADS_INIT #ifdef CMAKE_USE_PTHREADS_INIT
pthread_cond_init( &wakeupCond, 0 ); pthread_cond_init(&wakeupCond, 0);
#endif #endif
usageCount = 0; usageCount = 0;
} }
EncFS_Context::~EncFS_Context() EncFS_Context::~EncFS_Context() {
{
#ifdef CMAKE_USE_PTHREADS_INIT #ifdef CMAKE_USE_PTHREADS_INIT
pthread_cond_destroy( &wakeupCond ); pthread_cond_destroy(&wakeupCond);
#endif #endif
// release all entries from map // release all entries from map
openFiles.clear(); openFiles.clear();
} }
shared_ptr<DirNode> EncFS_Context::getRoot(int *errCode) shared_ptr<DirNode> EncFS_Context::getRoot(int *errCode) {
{
shared_ptr<DirNode> ret; shared_ptr<DirNode> ret;
do do {
{
{ {
Lock lock( contextMutex ); Lock lock(contextMutex);
ret = root; ret = root;
++usageCount; ++usageCount;
} }
if(!ret) if (!ret) {
{ int res = remountFS(this);
int res = remountFS( this ); if (res != 0) {
if(res != 0)
{
*errCode = res; *errCode = res;
break; break;
} }
} }
} while(!ret); } while (!ret);
return ret; return ret;
} }
void EncFS_Context::setRoot(const shared_ptr<DirNode> &r) void EncFS_Context::setRoot(const shared_ptr<DirNode> &r) {
{ Lock lock(contextMutex);
Lock lock( contextMutex );
root = r; root = r;
if(r) if (r) rootCipherDir = r->rootDirectory();
rootCipherDir = r->rootDirectory();
} }
bool EncFS_Context::isMounted() bool EncFS_Context::isMounted() { return root; }
{
return root;
}
int EncFS_Context::getAndResetUsageCounter() int EncFS_Context::getAndResetUsageCounter() {
{ Lock lock(contextMutex);
Lock lock( contextMutex );
int count = usageCount; int count = usageCount;
usageCount = 0; usageCount = 0;
@ -95,79 +83,69 @@ int EncFS_Context::getAndResetUsageCounter()
return count; return count;
} }
int EncFS_Context::openFileCount() const int EncFS_Context::openFileCount() const {
{ Lock lock(contextMutex);
Lock lock( contextMutex );
return openFiles.size(); return openFiles.size();
} }
shared_ptr<FileNode> EncFS_Context::lookupNode(const char *path) shared_ptr<FileNode> EncFS_Context::lookupNode(const char *path) {
{ Lock lock(contextMutex);
Lock lock( contextMutex );
FileMap::iterator it = openFiles.find( std::string(path) ); FileMap::iterator it = openFiles.find(std::string(path));
if(it != openFiles.end()) if (it != openFiles.end()) {
{
// all the items in the set point to the same node.. so just use the // all the items in the set point to the same node.. so just use the
// first // first
return (*it->second.begin())->node; return (*it->second.begin())->node;
} else } else {
{
return shared_ptr<FileNode>(); return shared_ptr<FileNode>();
} }
} }
void EncFS_Context::renameNode(const char *from, const char *to) void EncFS_Context::renameNode(const char *from, const char *to) {
{ Lock lock(contextMutex);
Lock lock( contextMutex );
FileMap::iterator it = openFiles.find( std::string(from) ); FileMap::iterator it = openFiles.find(std::string(from));
if(it != openFiles.end()) if (it != openFiles.end()) {
{
std::set<Placeholder *> val = it->second; std::set<Placeholder *> val = it->second;
openFiles.erase(it); openFiles.erase(it);
openFiles[ std::string(to) ] = val; openFiles[std::string(to)] = val;
} }
} }
shared_ptr<FileNode> EncFS_Context::getNode(void *pl) shared_ptr<FileNode> EncFS_Context::getNode(void *pl) {
{ Placeholder *ph = (Placeholder *)pl;
Placeholder *ph = (Placeholder*)pl;
return ph->node; return ph->node;
} }
void *EncFS_Context::putNode(const char *path, void *EncFS_Context::putNode(const char *path,
const shared_ptr<FileNode> &node) const shared_ptr<FileNode> &node) {
{ Lock lock(contextMutex);
Lock lock( contextMutex ); Placeholder *pl = new Placeholder(node);
Placeholder *pl = new Placeholder( node ); openFiles[std::string(path)].insert(pl);
openFiles[ std::string(path) ].insert(pl);
return (void *)pl; return (void *)pl;
} }
void EncFS_Context::eraseNode(const char *path, void *pl) void EncFS_Context::eraseNode(const char *path, void *pl) {
{ Lock lock(contextMutex);
Lock lock( contextMutex );
Placeholder *ph = (Placeholder *)pl; Placeholder *ph = (Placeholder *)pl;
FileMap::iterator it = openFiles.find( std::string(path) ); FileMap::iterator it = openFiles.find(std::string(path));
rAssert(it != openFiles.end()); rAssert(it != openFiles.end());
int rmCount = it->second.erase( ph ); int rmCount = it->second.erase(ph);
rAssert(rmCount == 1); rAssert(rmCount == 1);
// if no more references to this file, remove the record all together // 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 // attempts to make use of shallow copy to clear memory used to hold
// unencrypted filenames.. not sure this does any good.. // unencrypted filenames.. not sure this does any good..
std::string storedName = it->first; std::string storedName = it->first;
openFiles.erase( it ); openFiles.erase(it);
storedName.assign( storedName.length(), '\0' ); storedName.assign(storedName.length(), '\0');
} }
delete ph; delete ph;

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -43,8 +43,7 @@ struct EncFS_Opts;
class FileNode; class FileNode;
class DirNode; class DirNode;
class EncFS_Context class EncFS_Context {
{
public: public:
EncFS_Context(); EncFS_Context();
~EncFS_Context(); ~EncFS_Context();
@ -91,15 +90,14 @@ class EncFS_Context
* release() is called. shared_ptr then does our reference counting for * release() is called. shared_ptr then does our reference counting for
* us. * us.
*/ */
struct Placeholder struct Placeholder {
{
shared_ptr<FileNode> node; shared_ptr<FileNode> node;
Placeholder( const shared_ptr<FileNode> &ptr ) : node(ptr) {} Placeholder(const shared_ptr<FileNode> &ptr) : node(ptr) {}
}; };
// set of open files, indexed by path // set of open files, indexed by path
typedef unordered_map<std::string, std::set<Placeholder*> > FileMap; typedef unordered_map<std::string, std::set<Placeholder *> > FileMap;
#ifdef CMAKE_USE_PTHREADS_INIT #ifdef CMAKE_USE_PTHREADS_INIT
mutable Mutex contextMutex; mutable Mutex contextMutex;
@ -111,9 +109,8 @@ class EncFS_Context
shared_ptr<DirNode> root; shared_ptr<DirNode> root;
}; };
int remountFS( EncFS_Context *ctx ); int remountFS(EncFS_Context *ctx);
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -39,7 +39,6 @@
#include "fs/FileUtils.h" #include "fs/FileUtils.h"
#include "fs/fsconfig.pb.h" #include "fs/fsconfig.pb.h"
#include <glog/logging.h> #include <glog/logging.h>
#include <iostream> #include <iostream>
@ -49,33 +48,19 @@ using std::string;
namespace encfs { namespace encfs {
class DirDeleter class DirDeleter {
{ public:
public: void operator()(DIR *d) { ::closedir(d); }
void operator () ( DIR *d )
{
::closedir( d );
}
}; };
DirTraverse::DirTraverse(const shared_ptr<DIR> &_dirPtr, uint64_t _iv,
DirTraverse::DirTraverse(const shared_ptr<DIR> &_dirPtr, const shared_ptr<NameIO> &_naming)
uint64_t _iv, const shared_ptr<NameIO> &_naming) : dir(_dirPtr), iv(_iv), naming(_naming) {}
: dir( _dirPtr )
, iv( _iv )
, naming( _naming )
{
}
DirTraverse::DirTraverse(const DirTraverse &src) DirTraverse::DirTraverse(const DirTraverse &src)
: dir( src.dir ) : dir(src.dir), iv(src.iv), naming(src.naming) {}
, iv( src.iv )
, naming( src.naming )
{
}
DirTraverse &DirTraverse::operator = (const DirTraverse &src) DirTraverse &DirTraverse::operator=(const DirTraverse &src) {
{
dir = src.dir; dir = src.dir;
iv = src.iv; iv = src.iv;
naming = src.naming; naming = src.naming;
@ -83,23 +68,18 @@ DirTraverse &DirTraverse::operator = (const DirTraverse &src)
return *this; return *this;
} }
DirTraverse::~DirTraverse() DirTraverse::~DirTraverse() {
{
dir.reset(); dir.reset();
iv = 0; iv = 0;
naming.reset(); naming.reset();
} }
static static bool _nextName(struct dirent *&de, const shared_ptr<DIR> &dir,
bool _nextName(struct dirent *&de, const shared_ptr<DIR> &dir, int *fileType, ino_t *inode) {
int *fileType, ino_t *inode) de = ::readdir(dir.get());
{
de = ::readdir( dir.get() );
if(de) if (de) {
{ if (fileType) {
if(fileType)
{
#if defined(_DIRENT_HAVE_D_TYPE) || defined(__FreeBSD__) #if defined(_DIRENT_HAVE_D_TYPE) || defined(__FreeBSD__)
*fileType = de->d_type; *fileType = de->d_type;
#else #else
@ -107,63 +87,51 @@ bool _nextName(struct dirent *&de, const shared_ptr<DIR> &dir,
*fileType = 0; *fileType = 0;
#endif #endif
} }
if(inode) if (inode) *inode = de->d_ino;
*inode = de->d_ino;
return true; return true;
} else } else {
{ if (fileType) *fileType = 0;
if(fileType)
*fileType = 0;
return false; return false;
} }
} }
std::string DirTraverse::nextPlaintextName(int *fileType, ino_t *inode) {
std::string DirTraverse::nextPlaintextName(int *fileType, ino_t *inode) struct dirent *de = 0;
{ while (_nextName(de, dir, fileType, inode)) {
struct dirent *de=0; try {
while(_nextName(de, dir, fileType, inode))
{
try
{
uint64_t localIv = iv; uint64_t localIv = iv;
return naming->decodePath( de->d_name, &localIv ); return naming->decodePath(de->d_name, &localIv);
} catch ( Error &ex ) }
{ catch (Error &ex) {
// .. .problem decoding, ignore it and continue on to next name.. // .. .problem decoding, ignore it and continue on to next name..
VLOG(1) << "error decoding filename " << de->d_name VLOG(1) << "error decoding filename " << de->d_name << " : " << ex.what();
<< " : " << ex.what();
} }
} }
return string(); return string();
} }
std::string DirTraverse::nextInvalid() std::string DirTraverse::nextInvalid() {
{ struct dirent *de = 0;
struct dirent *de=0;
// find the first name which produces a decoding error... // find the first name which produces a decoding error...
while(_nextName(de, dir, (int*)0, (ino_t*)0)) while (_nextName(de, dir, (int *)0, (ino_t *)0)) {
{ try {
try
{
uint64_t localIv = iv; uint64_t localIv = iv;
naming->decodePath( de->d_name, &localIv ); naming->decodePath(de->d_name, &localIv);
continue; continue;
} catch( Error &ex ) }
{ catch (Error &ex) {
return string( de->d_name ); return string(de->d_name);
} }
} }
return string(); return string();
} }
struct RenameEl struct RenameEl {
{
// ciphertext names // ciphertext names
string oldCName; string oldCName;
string newCName; // intermediate name (not final cname) string newCName; // intermediate name (not final cname)
// plaintext names // plaintext names
string oldPName; string oldPName;
@ -172,59 +140,44 @@ struct RenameEl
bool isDirectory; bool isDirectory;
}; };
class RenameOp class RenameOp {
{ private:
private:
DirNode *dn; DirNode *dn;
shared_ptr< list<RenameEl> > renameList; shared_ptr<list<RenameEl> > renameList;
list<RenameEl>::const_iterator last; list<RenameEl>::const_iterator last;
public: public:
RenameOp( DirNode *_dn, const shared_ptr< list<RenameEl> > &_renameList ) RenameOp(DirNode *_dn, const shared_ptr<list<RenameEl> > &_renameList)
: dn(_dn), renameList(_renameList) : dn(_dn), renameList(_renameList) {
{
last = renameList->begin(); last = renameList->begin();
} }
RenameOp(const RenameOp &src) RenameOp(const RenameOp &src)
: dn(src.dn) : dn(src.dn), renameList(src.renameList), last(src.last) {}
, renameList(src.renameList)
, last(src.last)
{
}
~RenameOp(); ~RenameOp();
operator bool () const operator bool() const { return renameList; }
{
return renameList;
}
bool apply(); bool apply();
void undo(); void undo();
}; };
RenameOp::~RenameOp() RenameOp::~RenameOp() {
{ if (renameList) {
if(renameList)
{
// got a bunch of decoded filenames sitting in memory.. do a little // got a bunch of decoded filenames sitting in memory.. do a little
// cleanup before leaving.. // cleanup before leaving..
list<RenameEl>::iterator it; list<RenameEl>::iterator it;
for(it = renameList->begin(); it != renameList->end(); ++it) for (it = renameList->begin(); it != renameList->end(); ++it) {
{ it->oldPName.assign(it->oldPName.size(), ' ');
it->oldPName.assign( it->oldPName.size(), ' ' ); it->newPName.assign(it->newPName.size(), ' ');
it->newPName.assign( it->newPName.size(), ' ' );
} }
} }
} }
bool RenameOp::apply() bool RenameOp::apply() {
{ try {
try while (last != renameList->end()) {
{
while(last != renameList->end())
{
// backing store rename. // backing store rename.
VLOG(2) << "renaming " << last->oldCName << "-> " << last->newCName; VLOG(2) << "renaming " << last->oldCName << "-> " << last->newCName;
@ -232,22 +185,17 @@ bool RenameOp::apply()
bool preserve_mtime = ::stat(last->oldCName.c_str(), &st) == 0; bool preserve_mtime = ::stat(last->oldCName.c_str(), &st) == 0;
// internal node rename.. // internal node rename..
dn->renameNode( last->oldPName.c_str(), dn->renameNode(last->oldPName.c_str(), last->newPName.c_str());
last->newPName.c_str() );
// rename on disk.. // rename on disk..
if(::rename( last->oldCName.c_str(), if (::rename(last->oldCName.c_str(), last->newCName.c_str()) == -1) {
last->newCName.c_str() ) == -1) LOG(WARNING) << "Error renaming " << last->oldCName << ": "
{ << strerror(errno);
LOG(WARNING) << "Error renaming " << last->oldCName << ": " << dn->renameNode(last->newPName.c_str(), last->oldPName.c_str(), false);
strerror(errno);
dn->renameNode( last->newPName.c_str(),
last->oldPName.c_str(), false );
return false; return false;
} }
if(preserve_mtime) if (preserve_mtime) {
{
struct utimbuf ut; struct utimbuf ut;
ut.actime = st.st_atime; ut.actime = st.st_atime;
ut.modtime = st.st_mtime; ut.modtime = st.st_mtime;
@ -258,21 +206,19 @@ bool RenameOp::apply()
} }
return true; return true;
} catch( Error &err ) }
{ catch (Error &err) {
LOG(WARNING) << "caught error in rename application: " << err.what(); LOG(WARNING) << "caught error in rename application: " << err.what();
return false; return false;
} }
} }
void RenameOp::undo() void RenameOp::undo() {
{
VLOG(1) << "in undoRename"; VLOG(1) << "in undoRename";
if(last == renameList->begin()) if (last == renameList->begin()) {
{
VLOG(1) << "nothing to undo"; VLOG(1) << "nothing to undo";
return; // nothing to undo return; // nothing to undo
} }
// list has to be processed backwards, otherwise we may rename // list has to be processed backwards, otherwise we may rename
@ -281,19 +227,16 @@ void RenameOp::undo()
int errorCount = 0; int errorCount = 0;
list<RenameEl>::const_iterator it = last; list<RenameEl>::const_iterator it = last;
while( it != renameList->begin() ) while (it != renameList->begin()) {
{
--it; --it;
VLOG(1) << "undo: renaming " << it->newCName << " -> " << it->oldCName; VLOG(1) << "undo: renaming " << it->newCName << " -> " << it->oldCName;
::rename( it->newCName.c_str(), it->oldCName.c_str() ); ::rename(it->newCName.c_str(), it->oldCName.c_str());
try try {
{ dn->renameNode(it->newPName.c_str(), it->oldPName.c_str(), false);
dn->renameNode( it->newPName.c_str(), }
it->oldPName.c_str(), false ); catch (Error &err) {
} catch( Error &err )
{
if (++errorCount == 1) if (++errorCount == 1)
LOG(WARNING) << "error in rename und: " << err.what(); LOG(WARNING) << "error in rename und: " << err.what();
// continue on anyway... // continue on anyway...
@ -304,11 +247,9 @@ void RenameOp::undo()
LOG(WARNING) << "Undo rename count: " << undoCount; LOG(WARNING) << "Undo rename count: " << undoCount;
} }
DirNode::DirNode(EncFS_Context *_ctx, DirNode::DirNode(EncFS_Context *_ctx, const string &sourceDir,
const string &sourceDir, const FSConfigPtr &_config) {
const FSConfigPtr &_config) Lock _lock(mutex);
{
Lock _lock( mutex );
ctx = _ctx; ctx = _ctx;
rootDir = sourceDir; 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 // make sure rootDir ends in '/', so that we can form a path by appending
// the rest.. // the rest..
if( rootDir[ rootDir.length()-1 ] != '/' ) if (rootDir[rootDir.length() - 1] != '/') rootDir.append(1, '/');
rootDir.append( 1, '/');
naming = fsConfig->nameCoding; naming = fsConfig->nameCoding;
} }
DirNode::~DirNode() DirNode::~DirNode() {}
{
}
bool DirNode::hasDirectoryNameDependency() const bool DirNode::hasDirectoryNameDependency() const {
{
return naming ? naming->getChainedNameIV() : false; return naming ? naming->getChainedNameIV() : false;
} }
string DirNode::rootDirectory() string DirNode::rootDirectory() {
{
// don't update last access here, otherwise 'du' would cause lastAccess to // don't update last access here, otherwise 'du' would cause lastAccess to
// be reset. // be reset.
// chop off '/' terminator from root dir. // 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 ) string DirNode::cipherPath(const char *plaintextPath) {
{ return rootDir + naming->encodePath(plaintextPath);
return rootDir + naming->encodePath( plaintextPath );
} }
string DirNode::cipherPathWithoutRoot( const char *plaintextPath ) string DirNode::cipherPathWithoutRoot(const char *plaintextPath) {
{ return naming->encodePath(plaintextPath);
return naming->encodePath( plaintextPath );
} }
string DirNode::plainPath( const char *cipherPath_ ) string DirNode::plainPath(const char *cipherPath_) {
{ try {
try if (!strncmp(cipherPath_, rootDir.c_str(), rootDir.length())) {
{ return naming->decodePath(cipherPath_ + rootDir.length());
if( !strncmp( cipherPath_, rootDir.c_str(), } else {
rootDir.length() ) ) if (cipherPath_[0] == '+') {
{
return naming->decodePath( cipherPath_ + rootDir.length() );
} else
{
if ( cipherPath_[0] == '+' )
{
// decode as fully qualified path // decode as fully qualified path
return string("/") + naming->decodeName( cipherPath_+1, return string("/") +
strlen(cipherPath_+1) ); naming->decodeName(cipherPath_ + 1, strlen(cipherPath_ + 1));
} else } else {
{ return naming->decodePath(cipherPath_);
return naming->decodePath( cipherPath_ );
} }
} }
}
} catch( Error &err ) catch (Error &err) {
{
LOG(ERROR) << "decode err: " << err.what(); LOG(ERROR) << "decode err: " << err.what();
return string(); return string();
} }
} }
string DirNode::relativeCipherPath( const char *plaintextPath ) string DirNode::relativeCipherPath(const char *plaintextPath) {
{ try {
try if (plaintextPath[0] == '/') {
{
if(plaintextPath[0] == '/')
{
// mark with '+' to indicate special decoding.. // mark with '+' to indicate special decoding..
return string("+") + naming->encodeName(plaintextPath+1, return string("+") +
strlen(plaintextPath+1)); naming->encodeName(plaintextPath + 1, strlen(plaintextPath + 1));
} else } else {
{ return naming->encodePath(plaintextPath);
return naming->encodePath( plaintextPath );
} }
} catch( Error &err ) }
{ catch (Error &err) {
LOG(ERROR) << "encode err: " << err.what(); LOG(ERROR) << "encode err: " << err.what();
return string(); return string();
} }
} }
DirTraverse DirNode::openDir(const char *plaintextPath) DirTraverse DirNode::openDir(const char *plaintextPath) {
{ string cyName = rootDir + naming->encodePath(plaintextPath);
string cyName = rootDir + naming->encodePath( plaintextPath ); // rDebug("openDir on %s", cyName.c_str() );
//rDebug("openDir on %s", cyName.c_str() );
DIR *dir = ::opendir( cyName.c_str() ); DIR *dir = ::opendir(cyName.c_str());
if(dir == NULL) if (dir == NULL) {
{
VLOG(1) << "opendir error " << strerror(errno); VLOG(1) << "opendir error " << strerror(errno);
return DirTraverse( shared_ptr<DIR>(), 0, shared_ptr<NameIO>() ); return DirTraverse(shared_ptr<DIR>(), 0, shared_ptr<NameIO>());
} else } else {
{ shared_ptr<DIR> dp(dir, DirDeleter());
shared_ptr<DIR> dp( dir, DirDeleter() );
uint64_t iv = 0; uint64_t iv = 0;
// if we're using chained IV mode, then compute the IV at this // if we're using chained IV mode, then compute the IV at this
// directory level.. // directory level..
try try {
{ if (naming->getChainedNameIV()) naming->encodePath(plaintextPath, &iv);
if( naming->getChainedNameIV() ) }
naming->encodePath( plaintextPath, &iv ); catch (Error &err) {
} catch( Error &err )
{
LOG(ERROR) << "encode err: " << err.what(); LOG(ERROR) << "encode err: " << err.what();
} }
return DirTraverse( dp, iv, naming ); return DirTraverse(dp, iv, naming);
} }
} }
bool DirNode::genRenameList( list<RenameEl> &renameList, bool DirNode::genRenameList(list<RenameEl> &renameList, const char *fromP,
const char *fromP, const char *toP ) const char *toP) {
{
uint64_t fromIV = 0, toIV = 0; uint64_t fromIV = 0, toIV = 0;
// compute the IV for both paths // compute the IV for both paths
string fromCPart = naming->encodePath( fromP, &fromIV ); string fromCPart = naming->encodePath(fromP, &fromIV);
string toCPart = naming->encodePath( toP, &toIV ); string toCPart = naming->encodePath(toP, &toIV);
// where the files live before the rename.. // where the files live before the rename..
string sourcePath = rootDir + fromCPart; string sourcePath = rootDir + fromCPart;
// ok..... we wish it was so simple.. should almost never happen // ok..... we wish it was so simple.. should almost never happen
if(fromIV == toIV) if (fromIV == toIV) return true;
return true;
// generate the real destination path, where we expect to find the files.. // generate the real destination path, where we expect to find the files..
VLOG(1) << "opendir " << sourcePath; VLOG(1) << "opendir " << sourcePath;
shared_ptr<DIR> dir = shared_ptr<DIR>( shared_ptr<DIR> dir =
opendir( sourcePath.c_str() ), DirDeleter() ); shared_ptr<DIR>(opendir(sourcePath.c_str()), DirDeleter());
if(!dir) if (!dir) return false;
return false;
struct dirent *de = NULL; struct dirent *de = NULL;
while((de = ::readdir( dir.get() )) != NULL) while ((de = ::readdir(dir.get())) != NULL) {
{
// decode the name using the oldIV // decode the name using the oldIV
uint64_t localIV = fromIV; uint64_t localIV = fromIV;
string plainName; string plainName;
if((de->d_name[0] == '.') && if ((de->d_name[0] == '.') &&
((de->d_name[1] == '\0') ((de->d_name[1] == '\0') ||
|| ((de->d_name[1] == '.') && (de->d_name[2] == '\0')))) ((de->d_name[1] == '.') && (de->d_name[2] == '\0')))) {
{
// skip "." and ".." // skip "." and ".."
continue; continue;
} }
try try {
{ plainName = naming->decodePath(de->d_name, &localIV);
plainName = naming->decodePath( de->d_name, &localIV ); }
} catch( Error &ex ) catch (Error &ex) {
{
// if filename can't be decoded, then ignore it.. // if filename can't be decoded, then ignore it..
continue; continue;
} }
// any error in the following will trigger a rename failure. // any error in the following will trigger a rename failure.
try try {
{
// re-encode using the new IV.. // re-encode using the new IV..
localIV = toIV; localIV = toIV;
string newName = naming->encodePath( plainName.c_str(), &localIV ); string newName = naming->encodePath(plainName.c_str(), &localIV);
// store rename information.. // store rename information..
string oldFull = sourcePath + '/' + de->d_name; string oldFull = sourcePath + '/' + de->d_name;
@ -492,38 +402,34 @@ bool DirNode::genRenameList( list<RenameEl> &renameList,
bool isDir; bool isDir;
#if defined(_DIRENT_HAVE_D_TYPE) #if defined(_DIRENT_HAVE_D_TYPE)
if(de->d_type != DT_UNKNOWN) if (de->d_type != DT_UNKNOWN) {
{
isDir = (de->d_type == DT_DIR); isDir = (de->d_type == DT_DIR);
} else } else
#endif #endif
{ {
isDir = isDirectory( oldFull.c_str() ); isDir = isDirectory(oldFull.c_str());
} }
ren.isDirectory = isDir; ren.isDirectory = isDir;
if(isDir) if (isDir) {
{
// recurse.. We want to add subdirectory elements before the // recurse.. We want to add subdirectory elements before the
// parent, as that is the logical rename order.. // parent, as that is the logical rename order..
if(!genRenameList( renameList, if (!genRenameList(renameList, ren.oldPName.c_str(),
ren.oldPName.c_str(), ren.newPName.c_str())) {
ren.newPName.c_str()))
{
return false; return false;
} }
} }
VLOG(1) << "adding file " << oldFull << " to rename list"; VLOG(1) << "adding file " << oldFull << " to rename list";
renameList.push_back( ren ); renameList.push_back(ren);
}
} catch( Error &err ) catch (Error &err) {
{
// We can't convert this name, because we don't have a valid IV for // 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.. // it (or perhaps a valid key).. It will be inaccessible..
LOG(WARNING) << "Aborting rename: error on file " << LOG(WARNING) << "Aborting rename: error on file "
fromCPart.append(1, '/').append(de->d_name) << ":" << err.what(); << fromCPart.append(1, '/').append(de->d_name) << ":"
<< err.what();
// abort.. Err on the side of safety and disallow rename, rather // abort.. Err on the side of safety and disallow rename, rather
// then loosing files.. // then loosing files..
@ -534,7 +440,6 @@ bool DirNode::genRenameList( list<RenameEl> &renameList,
return true; return true;
} }
/* /*
A bit of a pain.. If a directory is renamed in a filesystem with A bit of a pain.. If a directory is renamed in a filesystem with
directory initialization vector chaining, then we have to recursively directory initialization vector chaining, then we have to recursively
@ -543,49 +448,39 @@ bool DirNode::genRenameList( list<RenameEl> &renameList,
Returns a list of renamed items on success, a null list on failure. Returns a list of renamed items on success, a null list on failure.
*/ */
shared_ptr<RenameOp> shared_ptr<RenameOp> DirNode::newRenameOp(const char *fromP, const char *toP) {
DirNode::newRenameOp( const char *fromP, const char *toP )
{
// Do the rename in two stages to avoid chasing our tail // Do the rename in two stages to avoid chasing our tail
// Undo everything if we encounter an error! // Undo everything if we encounter an error!
shared_ptr< list<RenameEl> > renameList(new list<RenameEl>); shared_ptr<list<RenameEl> > renameList(new list<RenameEl>);
if(!genRenameList( *renameList.get(), fromP, toP )) if (!genRenameList(*renameList.get(), fromP, toP)) {
{
LOG(WARNING) << "Error during generation of recursive rename list"; LOG(WARNING) << "Error during generation of recursive rename list";
return shared_ptr<RenameOp>(); return shared_ptr<RenameOp>();
} else } else
return shared_ptr<RenameOp>( new RenameOp(this, renameList) ); return shared_ptr<RenameOp>(new RenameOp(this, renameList));
} }
int DirNode::mkdir(const char *plaintextPath, mode_t mode, uid_t uid,
int DirNode::mkdir(const char *plaintextPath, mode_t mode, gid_t gid) {
uid_t uid, gid_t gid) string cyName = rootDir + naming->encodePath(plaintextPath);
{ rAssert(!cyName.empty());
string cyName = rootDir + naming->encodePath( plaintextPath );
rAssert( !cyName.empty() );
VLOG(1) << "mkdir on " << cyName; VLOG(1) << "mkdir on " << cyName;
// if uid or gid are set, then that should be the directory owner // if uid or gid are set, then that should be the directory owner
int olduid = -1; int olduid = -1;
int oldgid = -1; int oldgid = -1;
if(uid != 0) if (uid != 0) olduid = setfsuid(uid);
olduid = setfsuid( uid ); if (gid != 0) oldgid = setfsgid(gid);
if(gid != 0)
oldgid = setfsgid( gid );
int res = ::mkdir( cyName.c_str(), mode ); int res = ::mkdir(cyName.c_str(), mode);
if(olduid >= 0) if (olduid >= 0) setfsuid(olduid);
setfsuid( olduid ); if (oldgid >= 0) setfsgid(oldgid);
if(oldgid >= 0)
setfsgid( oldgid );
if(res == -1) if (res == -1) {
{
int eno = errno; int eno = errno;
LOG(WARNING) << "mkdir error on " << cyName LOG(WARNING) << "mkdir error on " << cyName << " mode " << mode << ": "
<< " mode " << mode << ": " << strerror(eno); << strerror(eno);
res = -eno; res = -eno;
} else } else
res = 0; res = 0;
@ -593,30 +488,25 @@ int DirNode::mkdir(const char *plaintextPath, mode_t mode,
return res; return res;
} }
int int DirNode::rename(const char *fromPlaintext, const char *toPlaintext) {
DirNode::rename( const char *fromPlaintext, const char *toPlaintext ) Lock _lock(mutex);
{
Lock _lock( mutex );
string fromCName = rootDir + naming->encodePath( fromPlaintext ); string fromCName = rootDir + naming->encodePath(fromPlaintext);
string toCName = rootDir + naming->encodePath( toPlaintext ); string toCName = rootDir + naming->encodePath(toPlaintext);
rAssert( !fromCName.empty() ); rAssert(!fromCName.empty());
rAssert( !toCName.empty() ); rAssert(!toCName.empty());
VLOG(1) << "rename " << fromCName << " -> " << toCName; VLOG(1) << "rename " << fromCName << " -> " << toCName;
shared_ptr<FileNode> toNode = findOrCreate( toPlaintext ); shared_ptr<FileNode> toNode = findOrCreate(toPlaintext);
shared_ptr<RenameOp> renameOp; shared_ptr<RenameOp> renameOp;
if( hasDirectoryNameDependency() && isDirectory( fromCName.c_str() )) if (hasDirectoryNameDependency() && isDirectory(fromCName.c_str())) {
{
VLOG(1) << "recursive rename begin"; VLOG(1) << "recursive rename begin";
renameOp = newRenameOp( fromPlaintext, toPlaintext ); renameOp = newRenameOp(fromPlaintext, toPlaintext);
if(!renameOp || !renameOp->apply()) if (!renameOp || !renameOp->apply()) {
{ if (renameOp) renameOp->undo();
if(renameOp)
renameOp->undo();
LOG(WARNING) << "rename aborted"; LOG(WARNING) << "rename aborted";
return -EACCES; return -EACCES;
@ -625,65 +515,57 @@ DirNode::rename( const char *fromPlaintext, const char *toPlaintext )
} }
int res = 0; int res = 0;
try try {
{
struct stat st; struct stat st;
bool preserve_mtime = ::stat(fromCName.c_str(), &st) == 0; bool preserve_mtime = ::stat(fromCName.c_str(), &st) == 0;
renameNode( fromPlaintext, toPlaintext ); renameNode(fromPlaintext, toPlaintext);
res = ::rename( fromCName.c_str(), toCName.c_str() ); res = ::rename(fromCName.c_str(), toCName.c_str());
if(res == -1) if (res == -1) {
{
// undo // undo
res = -errno; res = -errno;
renameNode( toPlaintext, fromPlaintext, false ); renameNode(toPlaintext, fromPlaintext, false);
if(renameOp) if (renameOp) renameOp->undo();
renameOp->undo(); } else if (preserve_mtime) {
} else if(preserve_mtime)
{
struct utimbuf ut; struct utimbuf ut;
ut.actime = st.st_atime; ut.actime = st.st_atime;
ut.modtime = st.st_mtime; ut.modtime = st.st_mtime;
::utime(toCName.c_str(), &ut); ::utime(toCName.c_str(), &ut);
} }
} catch( Error &err ) }
{ catch (Error &err) {
// exception from renameNode, just show the error and continue.. // exception from renameNode, just show the error and continue..
LOG(ERROR) << "rename err: " << err.what(); LOG(ERROR) << "rename err: " << err.what();
res = -EIO; res = -EIO;
} }
if(res != 0) if (res != 0) {
{ VLOG(1) << "rename failed: " << strerror(errno);
VLOG(1) << "rename failed: " << strerror( errno );
res = -errno; res = -errno;
} }
return res; return res;
} }
int DirNode::link( const char *from, const char *to ) int DirNode::link(const char *from, const char *to) {
{ Lock _lock(mutex);
Lock _lock( mutex );
string fromCName = rootDir + naming->encodePath( from ); string fromCName = rootDir + naming->encodePath(from);
string toCName = rootDir + naming->encodePath( to ); string toCName = rootDir + naming->encodePath(to);
rAssert( !fromCName.empty() ); rAssert(!fromCName.empty());
rAssert( !toCName.empty() ); rAssert(!toCName.empty());
VLOG(1) << "link " << fromCName << " -> " << toCName; VLOG(1) << "link " << fromCName << " -> " << toCName;
int res = -EPERM; int res = -EPERM;
if( fsConfig->config->external_iv() ) if (fsConfig->config->external_iv()) {
{
VLOG(1) << "hard links not supported with external IV chaining!"; VLOG(1) << "hard links not supported with external IV chaining!";
} else } else {
{ res = ::link(fromCName.c_str(), toCName.c_str());
res = ::link( fromCName.c_str(), toCName.c_str() ); if (res == -1)
if(res == -1)
res = -errno; res = -errno;
else else
res = 0; 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 The node is keyed by filename, so a rename means the internal node names
must be changed. must be changed.
*/ */
shared_ptr<FileNode> DirNode::renameNode( const char *from, const char *to ) shared_ptr<FileNode> DirNode::renameNode(const char *from, const char *to) {
{ return renameNode(from, to, true);
return renameNode( from, to, true );
} }
shared_ptr<FileNode> DirNode::renameNode( const char *from, const char *to, shared_ptr<FileNode> DirNode::renameNode(const char *from, const char *to,
bool forwardMode ) bool forwardMode) {
{ shared_ptr<FileNode> node = findOrCreate(from);
shared_ptr<FileNode> node = findOrCreate( from );
if(node) if (node) {
{
uint64_t newIV = 0; 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() VLOG(1) << "renaming internal node " << node->cipherName() << " -> "
<< " -> " << cname.c_str(); << cname.c_str();
if(node->setName( to, cname.c_str(), newIV, forwardMode )) if (node->setName(to, cname.c_str(), newIV, forwardMode)) {
{ if (ctx) ctx->renameNode(from, to);
if(ctx) } else {
ctx->renameNode( from, to ); // rename error! - put it back
} else
{
// rename error! - put it back
LOG(ERROR) << "renameNode failed"; LOG(ERROR) << "renameNode failed";
throw Error("Internal node name change failed!"); throw Error("Internal node name change failed!");
} }
@ -729,22 +605,17 @@ shared_ptr<FileNode> DirNode::renameNode( const char *from, const char *to,
return node; return node;
} }
shared_ptr<FileNode> DirNode::findOrCreate( const char *plainName) shared_ptr<FileNode> DirNode::findOrCreate(const char *plainName) {
{
shared_ptr<FileNode> node; shared_ptr<FileNode> node;
if(ctx) if (ctx) node = ctx->lookupNode(plainName);
node = ctx->lookupNode( plainName );
if(!node) if (!node) {
{
uint64_t iv = 0; uint64_t iv = 0;
string cipherName = naming->encodePath( plainName, &iv ); string cipherName = naming->encodePath(plainName, &iv);
node.reset( new FileNode( this, fsConfig, node.reset(new FileNode(this, fsConfig, plainName,
plainName, (rootDir + cipherName).c_str()));
(rootDir + cipherName).c_str()));
if(fsConfig->config->external_iv()) if (fsConfig->config->external_iv()) node->setName(0, 0, iv);
node->setName(0, 0, iv);
VLOG(1) << "created FileNode for " << node->cipherName(); VLOG(1) << "created FileNode for " << node->cipherName();
} }
@ -752,13 +623,12 @@ shared_ptr<FileNode> DirNode::findOrCreate( const char *plainName)
return node; return node;
} }
shared_ptr<FileNode> shared_ptr<FileNode> DirNode::lookupNode(const char *plainName,
DirNode::lookupNode( const char *plainName, const char * requestor ) const char *requestor) {
{
(void)requestor; (void)requestor;
Lock _lock( mutex ); Lock _lock(mutex);
shared_ptr<FileNode> node = findOrCreate( plainName ); shared_ptr<FileNode> node = findOrCreate(plainName);
return node; 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 node on sucess.. This is done in one step to avoid any race conditions
with the stored state of the file. with the stored state of the file.
*/ */
shared_ptr<FileNode> shared_ptr<FileNode> DirNode::openNode(const char *plainName,
DirNode::openNode( const char *plainName, const char * requestor, int flags, const char *requestor, int flags,
int *result ) int *result) {
{
(void)requestor; (void)requestor;
rAssert( result != NULL ); rAssert(result != NULL);
Lock _lock( mutex ); Lock _lock(mutex);
shared_ptr<FileNode> node = findOrCreate( plainName ); shared_ptr<FileNode> node = findOrCreate(plainName);
if( node && (*result = node->open( flags )) >= 0 ) if (node && (*result = node->open(flags)) >= 0)
return node; return node;
else else
return shared_ptr<FileNode>(); return shared_ptr<FileNode>();
} }
int DirNode::unlink( const char *plaintextName ) int DirNode::unlink(const char *plaintextName) {
{ string cyName = naming->encodePath(plaintextName);
string cyName = naming->encodePath( plaintextName );
VLOG(1) << "unlink " << cyName; VLOG(1) << "unlink " << cyName;
Lock _lock( mutex ); Lock _lock(mutex);
int res = 0; 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 // 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 // hide open files for us, then we can't allow an unlink of an open
// file.. // file..
LOG(WARNING) << "Refusing to unlink open file: " LOG(WARNING) << "Refusing to unlink open file: " << cyName
<< cyName << ", hard_remove option is probably in effect"; << ", hard_remove option is probably in effect";
res = -EBUSY; res = -EBUSY;
} else } else {
{
string fullName = rootDir + cyName; string fullName = rootDir + cyName;
res = ::unlink( fullName.c_str() ); res = ::unlink(fullName.c_str());
if(res == -1) if (res == -1) {
{
res = -errno; res = -errno;
VLOG(1) << "unlink error: " << strerror(errno); VLOG(1) << "unlink error: " << strerror(errno);
} }
} }
return res; return res;
} }
} // namespace encfs } // namespace encfs

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -44,133 +44,129 @@ class RenameOp;
struct RenameEl; struct RenameEl;
class EncFS_Context; class EncFS_Context;
class DirTraverse class DirTraverse {
{ public:
public: DirTraverse(const shared_ptr<DIR> &dirPtr, uint64_t iv,
DirTraverse(const shared_ptr<DIR> &dirPtr, uint64_t iv, const shared_ptr<NameIO> &naming);
const shared_ptr<NameIO> &naming); DirTraverse(const DirTraverse &src);
DirTraverse(const DirTraverse &src); ~DirTraverse();
~DirTraverse();
DirTraverse &operator = (const DirTraverse &src); DirTraverse &operator=(const DirTraverse &src);
// returns FALSE to indicate an invalid DirTraverse (such as when // returns FALSE to indicate an invalid DirTraverse (such as when
// an invalid directory is requested for traversal) // an invalid directory is requested for traversal)
bool valid() const; bool valid() const;
// return next plaintext filename // return next plaintext filename
// If fileType is not 0, then it is used to return the filetype (or 0 if // If fileType is not 0, then it is used to return the filetype (or 0 if
// unknown) // unknown)
std::string nextPlaintextName(int *fileType=0, ino_t *inode=0); std::string nextPlaintextName(int *fileType = 0, ino_t *inode = 0);
/* Return cipher name of next undecodable filename.. /* Return cipher name of next undecodable filename..
The opposite of nextPlaintextName(), as that skips undecodable names.. The opposite of nextPlaintextName(), as that skips undecodable names..
*/ */
std::string nextInvalid(); std::string nextInvalid();
private:
shared_ptr<DIR> dir; // struct DIR private:
// initialization vector to use. Not very general purpose, but makes it shared_ptr<DIR> dir; // struct DIR
// more efficient to support filename IV chaining.. // initialization vector to use. Not very general purpose, but makes it
uint64_t iv; // more efficient to support filename IV chaining..
shared_ptr<NameIO> naming; uint64_t iv;
shared_ptr<NameIO> naming;
}; };
inline bool DirTraverse::valid() const { return dir != 0; } inline bool DirTraverse::valid() const { return dir != 0; }
class DirNode class DirNode {
{ public:
public: // sourceDir points to where raw files are stored
// sourceDir points to where raw files are stored DirNode(EncFS_Context *ctx, const std::string &sourceDir,
DirNode(EncFS_Context *ctx, const FSConfigPtr &config);
const std::string &sourceDir, ~DirNode();
const FSConfigPtr &config );
~DirNode();
// return the path to the root directory // return the path to the root directory
std::string rootDirectory(); std::string rootDirectory();
// find files // find files
shared_ptr<FileNode> lookupNode( const char *plaintextName, shared_ptr<FileNode> lookupNode(const char *plaintextName,
const char *requestor ); const char *requestor);
/* /*
Combined lookupNode + node->open() call. If the open fails, then the Combined lookupNode + node->open() call. If the open fails, then the
node is not retained. If the open succeeds, then the node is returned. node is not retained. If the open succeeds, then the node is returned.
*/ */
shared_ptr<FileNode> openNode( const char *plaintextName, shared_ptr<FileNode> openNode(const char *plaintextName,
const char *requestor, int flags, int *openResult ); const char *requestor, int flags,
int *openResult);
std::string cipherPath( const char *plaintextPath ); std::string cipherPath(const char *plaintextPath);
std::string cipherPathWithoutRoot( const char *plaintextPath ); std::string cipherPathWithoutRoot(const char *plaintextPath);
std::string plainPath( const char *cipherPath ); std::string plainPath(const char *cipherPath);
// relative cipherPath is the same as cipherPath except that it doesn't // 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 // prepent the mount point. That it, it doesn't return a fully qualified
// name, just a relative path within the encrypted filesystem. // name, just a relative path within the encrypted filesystem.
std::string relativeCipherPath( const char *plaintextPath ); std::string relativeCipherPath(const char *plaintextPath);
/* /*
Returns true if file names are dependent on the parent directory name. 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 If a directory name is changed, then all the filenames must also be
changed. changed.
*/ */
bool hasDirectoryNameDependency() const; bool hasDirectoryNameDependency() const;
// unlink the specified file // unlink the specified file
int unlink( const char *plaintextName ); int unlink(const char *plaintextName);
// traverse directory // traverse directory
DirTraverse openDir( const char *plainDirName ); DirTraverse openDir(const char *plainDirName);
// uid and gid are used as the directory owner, only if not zero // uid and gid are used as the directory owner, only if not zero
int mkdir( const char *plaintextPath, mode_t mode, int mkdir(const char *plaintextPath, mode_t mode, uid_t uid = 0,
uid_t uid = 0, gid_t gid = 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 ); int link(const char *from, const char *to);
// returns idle time of filesystem in seconds
int idleSeconds();
protected: // returns idle time of filesystem in seconds
int idleSeconds();
/* protected:
notify that a file is being renamed. /*
This renames the internal node, if any. If the file is not open, then notify that a file is being renamed.
this call has no effect. This renames the internal node, if any. If the file is not open, then
Returns the FileNode if it was found. this call has no effect.
*/ Returns the FileNode if it was found.
shared_ptr<FileNode> renameNode( const char *from, const char *to ); */
shared_ptr<FileNode> renameNode( const char *from, const char *to, shared_ptr<FileNode> renameNode(const char *from, const char *to);
bool forwardMode ); shared_ptr<FileNode> renameNode(const char *from, const char *to,
bool forwardMode);
/* /*
when directory IV chaining is enabled, a directory can't be renamed when directory IV chaining is enabled, a directory can't be renamed
without renaming all its contents as well. recursiveRename should be without renaming all its contents as well. recursiveRename should be
called after renaming the directory, passing in the plaintext from and called after renaming the directory, passing in the plaintext from and
to paths. to paths.
*/ */
shared_ptr<RenameOp> newRenameOp( const char *from, const char *to ); shared_ptr<RenameOp> newRenameOp(const char *from, const char *to);
private: private:
friend class RenameOp;
friend class RenameOp; bool genRenameList(std::list<RenameEl> &list, const char *fromP,
const char *toP);
bool genRenameList( std::list<RenameEl> &list, const char *fromP, shared_ptr<FileNode> findOrCreate(const char *plainName);
const char *toP );
shared_ptr<FileNode> findOrCreate( const char *plainName);
Mutex mutex; Mutex mutex;
EncFS_Context *ctx; EncFS_Context *ctx;
// passed in as configuration // passed in as configuration
std::string rootDir; std::string rootDir;
FSConfigPtr fsConfig; FSConfigPtr fsConfig;
shared_ptr<NameIO> naming; shared_ptr<NameIO> naming;
}; };
} // namespace encfs } // namespace encfs

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -31,15 +31,14 @@
namespace encfs { namespace encfs {
enum ConfigType enum ConfigType {
{ Config_None = 0,
Config_None = 0, Config_Prehistoric,
Config_Prehistoric, Config_V3 = 3,
Config_V3 = 3, Config_V4 = 4,
Config_V4 = 4, Config_V5 = 5,
Config_V5 = 5, Config_V6 = 6,
Config_V6 = 6, Config_V7 = 7
Config_V7 = 7
}; };
struct EncFS_Opts; struct EncFS_Opts;
@ -51,35 +50,32 @@ CipherKey getUserKey(const EncfsConfig &config,
const std::string &passwordProgram, const std::string &passwordProgram,
const std::string &rootDir); const std::string &rootDir);
CipherKey getNewUserKey(EncfsConfig &config, bool useStdin, CipherKey getNewUserKey(EncfsConfig &config, bool useStdin,
const std::string &program, const std::string &rootDir); const std::string &program, const std::string &rootDir);
shared_ptr<CipherV1> getCipher(const EncfsConfig &cfg); shared_ptr<CipherV1> getCipher(const EncfsConfig &cfg);
shared_ptr<CipherV1> getCipher(const Interface &iface, int keySize); shared_ptr<CipherV1> getCipher(const Interface &iface, int keySize);
// helpers for serializing to/from a stream // helpers for serializing to/from a stream
std::ostream &operator << (std::ostream &os, const EncfsConfig &cfg); std::ostream &operator<<(std::ostream &os, const EncfsConfig &cfg);
std::istream &operator >> (std::istream &os, EncfsConfig &cfg); std::istream &operator>>(std::istream &os, EncfsConfig &cfg);
// Filesystem state // Filesystem state
struct FSConfig struct FSConfig {
{ shared_ptr<EncfsConfig> config;
shared_ptr<EncfsConfig> config; shared_ptr<EncFS_Opts> opts;
shared_ptr<EncFS_Opts> opts;
shared_ptr<CipherV1> cipher; shared_ptr<CipherV1> cipher;
CipherKey key; CipherKey key;
shared_ptr<NameIO> nameCoding; shared_ptr<NameIO> nameCoding;
bool forceDecode; // force decode on MAC block failures bool forceDecode; // force decode on MAC block failures
bool reverseEncryption; // reverse encryption operation bool reverseEncryption; // reverse encryption operation
bool idleTracking; // turn on idle monitoring of filesystem bool idleTracking; // turn on idle monitoring of filesystem
FSConfig() FSConfig()
: forceDecode(false), : forceDecode(false), reverseEncryption(false), idleTracking(false) {}
reverseEncryption(false),
idleTracking(false) { }
}; };
typedef shared_ptr<FSConfig> FSConfigPtr; typedef shared_ptr<FSConfig> FSConfigPtr;
@ -87,4 +83,3 @@ typedef shared_ptr<FSConfig> FSConfigPtr;
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -22,23 +22,15 @@
namespace encfs { namespace encfs {
FileIO::FileIO() FileIO::FileIO() {}
{
}
FileIO::~FileIO() FileIO::~FileIO() {}
{
}
int FileIO::blockSize() const int FileIO::blockSize() const { return 1; }
{
return 1;
}
bool FileIO::setIV( uint64_t iv ) bool FileIO::setIV(uint64_t iv) {
{ (void)iv;
(void)iv; return true;
return true;
} }
} // namespace encfs } // namespace encfs

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -28,63 +28,56 @@
namespace encfs { namespace encfs {
struct IORequest struct IORequest {
{ off_t offset;
off_t offset;
// amount of bytes to read/write. // amount of bytes to read/write.
int dataLen; int dataLen;
unsigned char *data; unsigned char *data;
IORequest(); IORequest();
}; };
inline IORequest::IORequest() inline IORequest::IORequest() : offset(0), dataLen(0), data(0) {}
: offset(0)
, dataLen(0)
, data(0)
{
}
class FileIO class FileIO {
{ public:
public: FileIO();
FileIO(); virtual ~FileIO();
virtual ~FileIO();
virtual Interface interface() const =0; virtual Interface interface() const = 0;
// default implementation returns 1, meaning this is not block oriented. // default implementation returns 1, meaning this is not block oriented.
virtual int blockSize() const; virtual int blockSize() const;
virtual void setFileName(const char *fileName) =0; virtual void setFileName(const char *fileName) = 0;
virtual const char *getFileName() const =0; virtual const char *getFileName() const = 0;
// Not sure about this -- it is specific to CipherFileIO, but the // Not sure about this -- it is specific to CipherFileIO, but the
// alternative methods of exposing this interface aren't much nicer.. // alternative methods of exposing this interface aren't much nicer..
virtual bool setIV( uint64_t iv ); virtual bool setIV(uint64_t iv);
// open file for specified mode. There is no corresponding close, so a // open file for specified mode. There is no corresponding close, so a
// file is open until the FileIO interface is destroyed. // file is open until the FileIO interface is destroyed.
virtual int open( int flags ) =0; 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;
virtual ssize_t read( const IORequest &req ) const =0; // get filesystem attributes for a file
virtual bool write( const IORequest &req ) =0; 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; virtual int truncate(off_t size) = 0;
private:
// not implemented.. virtual bool isWritable() const = 0;
FileIO( const FileIO & );
FileIO &operator = ( const FileIO & ); private:
// not implemented..
FileIO(const FileIO &);
FileIO &operator=(const FileIO &);
}; };
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -63,9 +63,8 @@ namespace encfs {
*/ */
FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg, FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg,
const char *plaintextName_, const char *cipherName_) const char *plaintextName_, const char *cipherName_) {
{ Lock _lock(mutex);
Lock _lock( mutex );
this->_pname = plaintextName_; this->_pname = plaintextName_;
this->_cname = cipherName_; this->_cname = cipherName_;
@ -74,79 +73,59 @@ FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg,
this->fsConfig = cfg; this->fsConfig = cfg;
// chain RawFileIO & CipherFileIO // chain RawFileIO & CipherFileIO
shared_ptr<FileIO> rawIO( new RawFileIO( _cname ) ); shared_ptr<FileIO> rawIO(new RawFileIO(_cname));
io = shared_ptr<FileIO>( new CipherFileIO( rawIO, fsConfig )); io = shared_ptr<FileIO>(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<FileIO>(new MACFileIO(io, fsConfig)); io = shared_ptr<FileIO>(new MACFileIO(io, fsConfig));
} }
FileNode::~FileNode() FileNode::~FileNode() {
{
// FileNode mutex should be locked before the destructor is called // FileNode mutex should be locked before the destructor is called
_pname.assign( _pname.length(), '\0' ); _pname.assign(_pname.length(), '\0');
_cname.assign( _cname.length(), '\0' ); _cname.assign(_cname.length(), '\0');
io.reset(); io.reset();
} }
const char *FileNode::cipherName() const const char *FileNode::cipherName() const { return _cname.c_str(); }
{
return _cname.c_str();
}
const char *FileNode::plaintextName() const const char *FileNode::plaintextName() const { return _pname.c_str(); }
{
return _pname.c_str();
}
string FileNode::plaintextParent() const string FileNode::plaintextParent() const { return parentDirectory(_pname); }
{
return parentDirectory( _pname );
}
static bool setIV(const shared_ptr<FileIO> &io, uint64_t iv) static bool setIV(const shared_ptr<FileIO> &io, uint64_t iv) {
{
struct stat stbuf; struct stat stbuf;
if((io->getAttr(&stbuf) < 0) || S_ISREG(stbuf.st_mode)) if ((io->getAttr(&stbuf) < 0) || S_ISREG(stbuf.st_mode))
return io->setIV( iv ); return io->setIV(iv);
else else
return true; return true;
} }
bool FileNode::setName( const char *plaintextName_, const char *cipherName_, bool FileNode::setName(const char *plaintextName_, const char *cipherName_,
uint64_t iv, bool setIVFirst ) uint64_t iv, bool setIVFirst) {
{ // Lock _lock( mutex );
//Lock _lock( mutex );
VLOG(1) << "calling setIV on " << cipherName_; VLOG(1) << "calling setIV on " << cipherName_;
if(setIVFirst) if (setIVFirst) {
{ if (fsConfig->config->external_iv() && !setIV(io, iv)) return false;
if(fsConfig->config->external_iv() && !setIV(io, iv))
return false;
// now change the name.. // now change the name..
if(plaintextName_) if (plaintextName_) this->_pname = plaintextName_;
this->_pname = plaintextName_; if (cipherName_) {
if(cipherName_)
{
this->_cname = cipherName_; this->_cname = cipherName_;
io->setFileName( cipherName_ ); io->setFileName(cipherName_);
} }
} else } else {
{
std::string oldPName = _pname; std::string oldPName = _pname;
std::string oldCName = _cname; std::string oldCName = _cname;
if(plaintextName_) if (plaintextName_) this->_pname = plaintextName_;
this->_pname = plaintextName_; if (cipherName_) {
if(cipherName_)
{
this->_cname = 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; _pname = oldPName;
_cname = oldCName; _cname = oldCName;
return false; return false;
@ -156,27 +135,22 @@ bool FileNode::setName( const char *plaintextName_, const char *cipherName_,
return true; return true;
} }
int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid) int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid) {
{ Lock _lock(mutex);
Lock _lock( mutex );
int res; int res;
int olduid = -1; int olduid = -1;
int oldgid = -1; int oldgid = -1;
if(uid != 0) if (uid != 0) {
{ olduid = setfsuid(uid);
olduid = setfsuid( uid ); if (olduid == -1) {
if(olduid == -1)
{
LOG(INFO) << "setfsuid error: " << strerror(errno); LOG(INFO) << "setfsuid error: " << strerror(errno);
return -EPERM; return -EPERM;
} }
} }
if(gid != 0) if (gid != 0) {
{ oldgid = setfsgid(gid);
oldgid = setfsgid( gid ); if (oldgid == -1) {
if(oldgid == -1)
{
LOG(INFO) << "setfsgid error: " << strerror(errno); LOG(INFO) << "setfsgid error: " << strerror(errno);
return -EPERM; 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 * The regular file stuff could be stripped off if there
* were a create method (advised to have) * were a create method (advised to have)
*/ */
if (S_ISREG( mode )) { if (S_ISREG(mode)) {
res = ::open( _cname.c_str(), O_CREAT | O_EXCL | O_WRONLY, mode ); res = ::open(_cname.c_str(), O_CREAT | O_EXCL | O_WRONLY, mode);
if (res >= 0) if (res >= 0) res = ::close(res);
res = ::close( res ); } else if (S_ISFIFO(mode))
} else if (S_ISFIFO( mode )) res = ::mkfifo(_cname.c_str(), mode);
res = ::mkfifo( _cname.c_str(), mode );
else else
res = ::mknod( _cname.c_str(), mode, rdev ); res = ::mknod(_cname.c_str(), mode, rdev);
if(olduid >= 0) if (olduid >= 0) setfsuid(olduid);
setfsuid( olduid ); if (oldgid >= 0) setfsgid(oldgid);
if(oldgid >= 0)
setfsgid( oldgid );
if(res == -1) if (res == -1) {
{
int eno = errno; int eno = errno;
VLOG(1) << "mknod error: " << strerror(eno); VLOG(1) << "mknod error: " << strerror(eno);
res = -eno; res = -eno;
@ -211,85 +181,75 @@ int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid)
return res; return res;
} }
int FileNode::open(int flags) const int FileNode::open(int flags) const {
{ Lock _lock(mutex);
Lock _lock( mutex );
int res = io->open( flags ); int res = io->open(flags);
return res; return res;
} }
int FileNode::getAttr(struct stat *stbuf) const int FileNode::getAttr(struct stat *stbuf) const {
{ Lock _lock(mutex);
Lock _lock( mutex );
int res = io->getAttr( stbuf ); int res = io->getAttr(stbuf);
return res; return res;
} }
off_t FileNode::getSize() const off_t FileNode::getSize() const {
{ Lock _lock(mutex);
Lock _lock( mutex );
int res = io->getSize(); int res = io->getSize();
return res; 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; IORequest req;
req.offset = offset; req.offset = offset;
req.dataLen = size; req.dataLen = size;
req.data = data; 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) bool FileNode::write(off_t offset, unsigned char *data, ssize_t size) {
{ VLOG(1) << "FileNode::write offset " << offset << ", data size " << size;
VLOG(1) << "FileNode::write offset " << offset
<< ", data size " << size;
IORequest req; IORequest req;
req.offset = offset; req.offset = offset;
req.dataLen = size; req.dataLen = size;
req.data = data; req.data = data;
Lock _lock( mutex ); Lock _lock(mutex);
return io->write( req ); return io->write(req);
} }
int FileNode::truncate( off_t size ) int FileNode::truncate(off_t size) {
{ Lock _lock(mutex);
Lock _lock( mutex );
return io->truncate( size ); return io->truncate(size);
} }
int FileNode::sync(bool datasync) int FileNode::sync(bool datasync) {
{ Lock _lock(mutex);
Lock _lock( mutex );
int fh = io->open( O_RDONLY ); int fh = io->open(O_RDONLY);
if(fh >= 0) if (fh >= 0) {
{
int res = -EIO; int res = -EIO;
#ifdef linux #ifdef linux
if(datasync) if (datasync)
res = fdatasync( fh ); res = fdatasync(fh);
else else
res = fsync( fh ); res = fsync(fh);
#else #else
// no fdatasync support // no fdatasync support
// TODO: use autoconfig to check for it.. // TODO: use autoconfig to check for it..
res = fsync(fh); res = fsync(fh);
#endif #endif
if(res == -1) if (res == -1) res = -errno;
res = -errno;
return res; return res;
} else } else

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * 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 * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _FileNode_incl_ #ifndef _FileNode_incl_
#define _FileNode_incl_ #define _FileNode_incl_
@ -36,69 +36,64 @@ class Cipher;
class FileIO; class FileIO;
class DirNode; class DirNode;
class FileNode class FileNode {
{ public:
public: FileNode(DirNode *parent, const FSConfigPtr &cfg, const char *plaintextName,
FileNode(DirNode *parent, const char *cipherName);
const FSConfigPtr &cfg, ~FileNode();
const char *plaintextName,
const char *cipherName);
~FileNode();
const char *plaintextName() const; const char *plaintextName() const;
const char *cipherName() const; const char *cipherName() const;
// directory portion of plaintextName // directory portion of plaintextName
std::string plaintextParent() const; std::string plaintextParent() const;
// if setIVFirst is true, then the IV is changed before the name is changed // if setIVFirst is true, then the IV is changed before the name is changed
// (default). The reverse is also supported for special cases.. // (default). The reverse is also supported for special cases..
bool setName( const char *plaintextName, const char *cipherName, bool setName(const char *plaintextName, const char *cipherName, uint64_t iv,
uint64_t iv, bool setIVFirst = true); bool setIVFirst = true);
// create node // create node
// If uid/gid are not 0, then chown is used change ownership as specified // 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); 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. // Returns < 0 on error (-errno), file descriptor on success.
int open(int flags) const; int open(int flags) const;
// getAttr returns 0 on success, -errno on failure // getAttr returns 0 on success, -errno on failure
int getAttr(struct stat *stbuf) const; int getAttr(struct stat *stbuf) const;
off_t getSize() const; off_t getSize() const;
ssize_t read(off_t offset, unsigned char *data, ssize_t size) 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); bool write(off_t offset, unsigned char *data, ssize_t size);
// truncate the file to a particular size // truncate the file to a particular size
int truncate( off_t size ); int truncate(off_t size);
// datasync or full sync // datasync or full sync
int sync(bool dataSync); int sync(bool dataSync);
private:
// doing locking at the FileNode level isn't as efficient as at the private:
// lowest level of RawFileIO, since that means locks are held longer // doing locking at the FileNode level isn't as efficient as at the
// (held during CPU intensive crypto operations!). However it makes it // lowest level of RawFileIO, since that means locks are held longer
// easier to avoid any race conditions with operations such as // (held during CPU intensive crypto operations!). However it makes it
// truncate() which may result in multiple calls down to the FileIO // easier to avoid any race conditions with operations such as
// level. // truncate() which may result in multiple calls down to the FileIO
mutable Mutex mutex; // level.
mutable Mutex mutex;
FSConfigPtr fsConfig; FSConfigPtr fsConfig;
shared_ptr<FileIO> io; shared_ptr<FileIO> io;
std::string _pname; // plaintext name std::string _pname; // plaintext name
std::string _cname; // encrypted name std::string _cname; // encrypted name
DirNode *parent; DirNode *parent;
private:
FileNode(const FileNode &src);
FileNode &operator = (const FileNode &src);
private:
FileNode(const FileNode &src);
FileNode &operator=(const FileNode &src);
}; };
} // namespace encfs } // namespace encfs
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * 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 * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _FileUtils_incl_ #ifndef _FileUtils_incl_
#define _FileUtils_incl_ #define _FileUtils_incl_
@ -29,26 +29,25 @@
namespace encfs { namespace encfs {
// true if the path points to an existing node (of any type) // 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 // true if path is a directory
bool isDirectory( const char *fileName ); bool isDirectory(const char *fileName);
// true if starts with '/' // true if starts with '/'
bool isAbsolutePath( const char *fileName ); bool isAbsolutePath(const char *fileName);
// pointer to just after the last '/' // 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 // ask the user for permission to create the directory. If they say ok, then
// do it and return true. // do it and return true.
bool userAllowMkdir(const char *dirPath, mode_t mode ); bool userAllowMkdir(const char *dirPath, mode_t mode);
bool userAllowMkdir(int promptno, const char *dirPath, mode_t mode ); bool userAllowMkdir(int promptno, const char *dirPath, mode_t mode);
class CipherV1; class CipherV1;
class DirNode; class DirNode;
struct EncFS_Root struct EncFS_Root {
{
shared_ptr<CipherV1> cipher; shared_ptr<CipherV1> cipher;
CipherKey volumeKey; CipherKey volumeKey;
shared_ptr<DirNode> root; shared_ptr<DirNode> root;
@ -59,36 +58,33 @@ struct EncFS_Root
typedef shared_ptr<EncFS_Root> RootPtr; typedef shared_ptr<EncFS_Root> RootPtr;
enum ConfigMode enum ConfigMode {
{
Config_Prompt, Config_Prompt,
Config_Standard, Config_Standard,
Config_Paranoia Config_Paranoia
}; };
struct EncFS_Opts struct EncFS_Opts {
{
std::string rootDir; std::string rootDir;
bool createIfNotFound; // create filesystem if not found bool createIfNotFound; // create filesystem if not found
bool idleTracking; // turn on idle monitoring of filesystem bool idleTracking; // turn on idle monitoring of filesystem
bool mountOnDemand; // mounting on-demand bool mountOnDemand; // mounting on-demand
bool delayMount; // delay initial mount bool delayMount; // delay initial mount
bool checkKey; // check crypto key decoding bool checkKey; // check crypto key decoding
bool forceDecode; // force decode on MAC block failures bool forceDecode; // force decode on MAC block failures
std::string passwordProgram; // path to password program (or empty) std::string passwordProgram; // path to password program (or empty)
bool useStdin; // read password from stdin rather then prompting bool useStdin; // read password from stdin rather then prompting
bool annotate; // print annotation line prompt to stderr. 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() EncFS_Opts() {
{
createIfNotFound = true; createIfNotFound = true;
idleTracking = false; idleTracking = false;
mountOnDemand = false; mountOnDemand = false;
@ -106,35 +102,33 @@ struct EncFS_Opts
/* /*
Read existing config file. Looks for any supported configuration version. 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 Save the configuration. Saves back as the same configuration type as was
read from. read from.
*/ */
bool saveConfig( const std::string &rootdir, const EncfsConfig &config ); bool saveConfig(const std::string &rootdir, const EncfsConfig &config);
class EncFS_Context; class EncFS_Context;
RootPtr initFS( EncFS_Context *ctx, const shared_ptr<EncFS_Opts> &opts ); RootPtr initFS(EncFS_Context *ctx, const shared_ptr<EncFS_Opts> &opts);
RootPtr createConfig( EncFS_Context *ctx, RootPtr createConfig(EncFS_Context *ctx, const shared_ptr<EncFS_Opts> &opts);
const shared_ptr<EncFS_Opts> &opts );
void showFSInfo( const EncfsConfig &config ); void showFSInfo(const EncfsConfig &config);
bool readV4Config( const char *configFile, EncfsConfig &config, bool readV4Config(const char *configFile, EncfsConfig &config,
struct ConfigInfo *); struct ConfigInfo *);
bool readV5Config( const char *configFile, EncfsConfig &config, bool readV5Config(const char *configFile, EncfsConfig &config,
struct ConfigInfo *); struct ConfigInfo *);
bool readV6Config( const char *configFile, EncfsConfig &config, bool readV6Config(const char *configFile, EncfsConfig &config,
struct ConfigInfo *); struct ConfigInfo *);
bool readProtoConfig( const char *configFile, EncfsConfig &config,
struct ConfigInfo *);
bool readProtoConfig(const char *configFile, EncfsConfig &config,
struct ConfigInfo *);
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * 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); static Interface MACFileIO_iface = makeInterface("FileIO/MAC", 2, 1, 0);
int dataBlockSize(const FSConfigPtr &cfg) int dataBlockSize(const FSConfigPtr &cfg) {
{ return cfg->config->block_size() - cfg->config->block_mac_bytes() -
return cfg->config->block_size() cfg->config->block_mac_rand_bytes();
- cfg->config->block_mac_bytes()
- cfg->config->block_mac_rand_bytes();
} }
MACFileIO::MACFileIO( const shared_ptr<FileIO> &_base, MACFileIO::MACFileIO(const shared_ptr<FileIO> &_base, const FSConfigPtr &cfg)
const FSConfigPtr &cfg ) : BlockFileIO(dataBlockSize(cfg), cfg),
: BlockFileIO( dataBlockSize( cfg ), cfg ) base(_base),
, base( _base ) cipher(cfg->cipher),
, cipher( cfg->cipher ) macBytes(cfg->config->block_mac_bytes()),
, macBytes( cfg->config->block_mac_bytes() ) randBytes(cfg->config->block_mac_rand_bytes()),
, randBytes( cfg->config->block_mac_rand_bytes() ) warnOnly(cfg->opts->forceDecode) {
, warnOnly( cfg->opts->forceDecode ) rAssert(macBytes >= 0 && macBytes <= 8);
{ rAssert(randBytes >= 0);
rAssert( macBytes >= 0 && macBytes <= 8 );
rAssert( randBytes >= 0 );
VLOG(1) << "fs block size = " << cfg->config->block_size() VLOG(1) << "fs block size = " << cfg->config->block_size()
<< ", macBytes = " << cfg->config->block_mac_bytes() << ", macBytes = " << cfg->config->block_mac_bytes()
<< ", randBytes = " << cfg->config->block_mac_rand_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 const char *MACFileIO::getFileName() const { return base->getFileName(); }
{
return MACFileIO_iface;
}
int MACFileIO::open( int flags ) bool MACFileIO::setIV(uint64_t iv) { return base->setIV(iv); }
{
return base->open( flags );
}
void MACFileIO::setFileName( const char *fileName ) inline static off_t roundUpDivide(off_t numerator, int denominator) {
{
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 // integer arithmetic always rounds down, so we can round up by adding
// enough so that any value other then a multiple of denominator gets // enough so that any value other then a multiple of denominator gets
// rouned to the next highest value. // 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 // 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 // ... blockNum = 1
// ... partialBlock = 0 // ... partialBlock = 0
// ... adjLoc = 1 * blockSize // ... adjLoc = 1 * blockSize
static off_t locWithHeader( off_t offset, int blockSize, int headerSize ) static off_t locWithHeader(off_t offset, int blockSize, int headerSize) {
{ off_t blockNum = roundUpDivide(offset, blockSize - headerSize);
off_t blockNum = roundUpDivide( offset , blockSize - headerSize );
return offset + blockNum * 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 // 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 // headers are stored at the beginning of the block, so even the first data is
// offset by the size of the header. // offset by the size of the header.
static off_t locWithoutHeader( off_t offset, int blockSize, int headerSize ) static off_t locWithoutHeader(off_t offset, int blockSize, int headerSize) {
{ off_t blockNum = roundUpDivide(offset, blockSize);
off_t blockNum = roundUpDivide( offset , blockSize );
return offset - blockNum * headerSize; return offset - blockNum * headerSize;
} }
int MACFileIO::getAttr( struct stat *stbuf ) const int MACFileIO::getAttr(struct stat *stbuf) const {
{ int res = base->getAttr(stbuf);
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.. // have to adjust size field..
int headerSize = macBytes + randBytes; int headerSize = macBytes + randBytes;
int bs = blockSize() + headerSize; int bs = blockSize() + headerSize;
stbuf->st_size = locWithoutHeader( stbuf->st_size, bs, headerSize ); stbuf->st_size = locWithoutHeader(stbuf->st_size, bs, headerSize);
} }
return res; return res;
} }
off_t MACFileIO::getSize() const off_t MACFileIO::getSize() const {
{
// adjust the size to hide the header overhead we tack on.. // adjust the size to hide the header overhead we tack on..
int headerSize = macBytes + randBytes; int headerSize = macBytes + randBytes;
int bs = blockSize() + headerSize; int bs = blockSize() + headerSize;
off_t size = base->getSize(); off_t size = base->getSize();
if(size > 0) if (size > 0) size = locWithoutHeader(size, bs, headerSize);
size = locWithoutHeader( size, bs, headerSize );
return size; return size;
} }
ssize_t MACFileIO::readOneBlock( const IORequest &req ) const ssize_t MACFileIO::readOneBlock(const IORequest &req) const {
{
int headerSize = macBytes + randBytes; int headerSize = macBytes + randBytes;
int bs = blockSize() + headerSize; int bs = blockSize() + headerSize;
MemBlock mb; MemBlock mb;
mb.allocate( bs ); mb.allocate(bs);
IORequest tmp; IORequest tmp;
tmp.offset = locWithHeader( req.offset, bs, headerSize ); tmp.offset = locWithHeader(req.offset, bs, headerSize);
tmp.data = mb.data; tmp.data = mb.data;
tmp.dataLen = headerSize + req.dataLen; tmp.dataLen = headerSize + req.dataLen;
// get the data from the base FileIO layer // 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 // don't store zeros if configured for zero-block pass-through
bool skipBlock = true; bool skipBlock = true;
if( _allowHoles ) if (_allowHoles) {
{ for (int i = 0; i < readSize; ++i)
for(int i=0; i<readSize; ++i) if (tmp.data[i] != 0) {
if(tmp.data[i] != 0)
{
skipBlock = false; skipBlock = false;
break; break;
} }
} else if(macBytes > 0) } else if (macBytes > 0)
skipBlock = false; skipBlock = false;
if(readSize > headerSize) if (readSize > headerSize) {
{ if (!skipBlock) {
if(!skipBlock)
{
// At this point the data has been decoded. So, compute the MAC of // At this point the data has been decoded. So, compute the MAC of
// the block and check against the checksum stored in the header.. // the block and check against the checksum stored in the header..
uint64_t mac = cipher->MAC_64( tmp.data + macBytes, uint64_t mac = cipher->MAC_64(tmp.data + macBytes, readSize - macBytes);
readSize - macBytes );
for(int i=0; i<macBytes; ++i, mac >>= 8) for (int i = 0; i < macBytes; ++i, mac >>= 8) {
{
int test = mac & 0xff; int test = mac & 0xff;
int stored = tmp.data[i]; int stored = tmp.data[i];
if(test != stored) if (test != stored) {
{ // uh oh..
// uh oh..
long blockNum = req.offset / bs; long blockNum = req.offset / bs;
LOG(WARNING) << "MAC comparison failure in block " << blockNum; LOG(WARNING) << "MAC comparison failure in block " << blockNum;
if( !warnOnly ) if (!warnOnly) {
{ throw Error(_("MAC comparison failure, refusing to read"));
throw Error(
_("MAC comparison failure, refusing to read"));
} }
break; break;
} }
@ -222,75 +186,64 @@ ssize_t MACFileIO::readOneBlock( const IORequest &req ) const
// now copy the data to the output buffer // now copy the data to the output buffer
readSize -= headerSize; readSize -= headerSize;
memcpy( req.data, tmp.data + headerSize, readSize ); memcpy(req.data, tmp.data + headerSize, readSize);
} else } else {
{
VLOG(1) << "readSize " << readSize << " at offset " << req.offset; VLOG(1) << "readSize " << readSize << " at offset " << req.offset;
if(readSize > 0) if (readSize > 0) readSize = 0;
readSize = 0;
} }
return readSize; return readSize;
} }
bool MACFileIO::writeOneBlock( const IORequest &req ) bool MACFileIO::writeOneBlock(const IORequest &req) {
{
int headerSize = macBytes + randBytes; int headerSize = macBytes + randBytes;
int bs = blockSize() + headerSize; int bs = blockSize() + headerSize;
// we have the unencrypted data, so we need to attach a header to it. // we have the unencrypted data, so we need to attach a header to it.
MemBlock mb; MemBlock mb;
mb.allocate( bs ); mb.allocate(bs);
IORequest newReq; IORequest newReq;
newReq.offset = locWithHeader( req.offset, bs, headerSize ); newReq.offset = locWithHeader(req.offset, bs, headerSize);
newReq.data = mb.data; newReq.data = mb.data;
newReq.dataLen = headerSize + req.dataLen; newReq.dataLen = headerSize + req.dataLen;
memset( newReq.data, 0, headerSize ); memset(newReq.data, 0, headerSize);
memcpy( newReq.data + headerSize, req.data, req.dataLen ); memcpy(newReq.data + headerSize, req.data, req.dataLen);
if(randBytes > 0) if (randBytes > 0) {
{ if (!cipher->pseudoRandomize(newReq.data + macBytes, randBytes))
if(!cipher->pseudoRandomize( newReq.data+macBytes, randBytes))
return false; return false;
} }
if(macBytes > 0) if (macBytes > 0) {
{
// compute the mac (which includes the random data) and fill it in // compute the mac (which includes the random data) and fill it in
uint64_t mac = cipher->MAC_64( newReq.data+macBytes, uint64_t mac =
req.dataLen + randBytes ); cipher->MAC_64(newReq.data + macBytes, req.dataLen + randBytes);
for(int i=0; i<macBytes; ++i) for (int i = 0; i < macBytes; ++i) {
{
newReq.data[i] = mac & 0xff; newReq.data[i] = mac & 0xff;
mac >>= 8; mac >>= 8;
} }
} }
// now, we can let the next level have it.. // now, we can let the next level have it..
bool ok = base->write( newReq ); bool ok = base->write(newReq);
return ok; return ok;
} }
int MACFileIO::truncate( off_t size ) int MACFileIO::truncate(off_t size) {
{
int headerSize = macBytes + randBytes; int headerSize = macBytes + randBytes;
int bs = blockSize() + headerSize; int bs = blockSize() + headerSize;
int res = blockTruncate( size, 0 ); int res = blockTruncate(size, 0);
if(res == 0) if (res == 0) base->truncate(locWithHeader(size, bs, headerSize));
base->truncate( locWithHeader( size, bs, headerSize ) );
return res; return res;
} }
bool MACFileIO::isWritable() const bool MACFileIO::isWritable() const { return base->isWritable(); }
{
return base->isWritable();
}
} // namespace encfs } // namespace encfs

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -26,45 +26,42 @@
namespace encfs { namespace encfs {
class MACFileIO : public BlockFileIO class MACFileIO : public BlockFileIO {
{ public:
public: /*
/* If warnOnlyMode is enabled, then a MAC comparison failure will only
If warnOnlyMode is enabled, then a MAC comparison failure will only result in a warning message from encfs -- the garbled data will still
result in a warning message from encfs -- the garbled data will still be made available..
be made available.. */
*/ MACFileIO(const shared_ptr<FileIO> &base, const FSConfigPtr &cfg);
MACFileIO( const shared_ptr<FileIO> &base, MACFileIO();
const FSConfigPtr &cfg ); virtual ~MACFileIO();
MACFileIO();
virtual ~MACFileIO();
virtual Interface interface() const; virtual Interface interface() const;
virtual void setFileName( const char *fileName ); virtual void setFileName(const char *fileName);
virtual const char *getFileName() const; virtual const char *getFileName() const;
virtual bool setIV( uint64_t iv ); virtual bool setIV(uint64_t iv);
virtual int open( int flags ); virtual int open(int flags);
virtual int getAttr( struct stat *stbuf ) const; virtual int getAttr(struct stat *stbuf) const;
virtual off_t getSize() 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: private:
virtual ssize_t readOneBlock( const IORequest &req ) const; virtual ssize_t readOneBlock(const IORequest &req) const;
virtual bool writeOneBlock( const IORequest &req ); virtual bool writeOneBlock(const IORequest &req);
shared_ptr<FileIO> base; shared_ptr<FileIO> base;
shared_ptr<CipherV1> cipher; shared_ptr<CipherV1> cipher;
int macBytes; int macBytes;
int randBytes; int randBytes;
bool warnOnly; bool warnOnly;
}; };
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -8,7 +8,7 @@
* This program is free software: you can redistribute it and/or modify it under * 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 * 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 * 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 * 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 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
@ -26,39 +26,29 @@
namespace encfs { namespace encfs {
static Interface MemBlockFileIO_iface = makeInterface("FileIO/MemBlock", static Interface MemBlockFileIO_iface =
1, 0, 0); makeInterface("FileIO/MemBlock", 1, 0, 0);
MemBlockFileIO::MemBlockFileIO(int blockSize, const FSConfigPtr &cfg) MemBlockFileIO::MemBlockFileIO(int blockSize, const FSConfigPtr& cfg)
: BlockFileIO(blockSize, cfg), impl(new MemFileIO(0)) { : BlockFileIO(blockSize, cfg), impl(new MemFileIO(0)) {}
}
MemBlockFileIO::~MemBlockFileIO() { MemBlockFileIO::~MemBlockFileIO() {}
}
Interface MemBlockFileIO::interface() const { Interface MemBlockFileIO::interface() const { return MemBlockFileIO_iface; }
return MemBlockFileIO_iface;
}
void MemBlockFileIO::setFileName(const char *name) { void MemBlockFileIO::setFileName(const char* name) {
return impl->setFileName(name); return impl->setFileName(name);
} }
const char *MemBlockFileIO::getFileName() const { const char* MemBlockFileIO::getFileName() const { return impl->getFileName(); }
return impl->getFileName();
}
int MemBlockFileIO::open(int flags) { int MemBlockFileIO::open(int flags) { return impl->open(flags); }
return impl->open(flags);
}
int MemBlockFileIO::getAttr(struct stat* stbuf) const { int MemBlockFileIO::getAttr(struct stat* stbuf) const {
return impl->getAttr(stbuf); return impl->getAttr(stbuf);
} }
off_t MemBlockFileIO::getSize() const { off_t MemBlockFileIO::getSize() const { return impl->getSize(); }
return impl->getSize();
}
ssize_t MemBlockFileIO::readOneBlock(const IORequest& req) const { ssize_t MemBlockFileIO::readOneBlock(const IORequest& req) const {
return impl->read(req); return impl->read(req);
@ -68,12 +58,8 @@ bool MemBlockFileIO::writeOneBlock(const IORequest& req) {
return impl->write(req); return impl->write(req);
} }
int MemBlockFileIO::truncate(off_t size) { int MemBlockFileIO::truncate(off_t size) { return impl->truncate(size); }
return impl->truncate(size);
}
bool MemBlockFileIO::isWritable() const { bool MemBlockFileIO::isWritable() const { return impl->isWritable(); }
return impl->isWritable();
}
} // namespace encfs } // namespace encfs

View File

@ -8,7 +8,7 @@
* This program is free software: you can redistribute it and/or modify it under * 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 * 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 * 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 * 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 * 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 const char *getFileName() const;
virtual int open(int flags); virtual int open(int flags);
virtual int getAttr(struct stat *stbuf) const; virtual int getAttr(struct stat *stbuf) const;
virtual off_t getSize() const; virtual off_t getSize() const;
virtual bool isWritable() const; virtual bool isWritable() const;
virtual int truncate(off_t size); virtual int truncate(off_t size);
protected: protected:
virtual ssize_t readOneBlock(const IORequest &req) const; virtual ssize_t readOneBlock(const IORequest &req) const;
virtual bool writeOneBlock(const IORequest &req); virtual bool writeOneBlock(const IORequest &req);
@ -60,4 +61,3 @@ class MemBlockFileIO : public BlockFileIO {
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -8,7 +8,7 @@
* This program is free software: you can redistribute it and/or modify it under * 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 * 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 * 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 * 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 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
@ -34,25 +34,15 @@ MemFileIO* NewMemFileIO(const Interface& iface) {
return new MemFileIO(0); return new MemFileIO(0);
} }
MemFileIO::MemFileIO(int size) MemFileIO::MemFileIO(int size) : writable(false) { buf.resize(size); }
: writable(false) {
buf.resize(size);
}
MemFileIO::~MemFileIO() { MemFileIO::~MemFileIO() {}
}
Interface MemFileIO::interface() const { Interface MemFileIO::interface() const { return MemFileIO_iface; }
return MemFileIO_iface;
}
void MemFileIO::setFileName(const char *name) { void MemFileIO::setFileName(const char* name) { this->name = name; }
this->name = name;
}
const char *MemFileIO::getFileName() const { const char* MemFileIO::getFileName() const { return name.c_str(); }
return name.c_str();
}
int MemFileIO::open(int flags) { int MemFileIO::open(int flags) {
bool requestWrite = ((flags & O_RDWR) || (flags & O_WRONLY)); bool requestWrite = ((flags & O_RDWR) || (flags & O_WRONLY));
@ -67,9 +57,7 @@ int MemFileIO::getAttr(struct stat* stbuf) const {
return 0; return 0;
} }
off_t MemFileIO::getSize() const { off_t MemFileIO::getSize() const { return buf.size(); }
return buf.size();
}
ssize_t MemFileIO::read(const IORequest& req) const { ssize_t MemFileIO::read(const IORequest& req) const {
rAssert(req.offset >= 0); rAssert(req.offset >= 0);
@ -102,8 +90,6 @@ int MemFileIO::truncate(off_t size) {
return 0; return 0;
} }
bool MemFileIO::isWritable() const { bool MemFileIO::isWritable() const { return writable; }
return writable;
}
} // namespace encfs } // namespace encfs

View File

@ -8,7 +8,7 @@
* This program is free software: you can redistribute it and/or modify it under * 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 * 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 * 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 * 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 * 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 const char *getFileName() const;
virtual int open(int flags); virtual int open(int flags);
virtual int getAttr(struct stat *stbuf) const; virtual int getAttr(struct stat *stbuf) const;
virtual off_t getSize() const; virtual off_t getSize() const;
virtual ssize_t read(const IORequest& req) const; virtual ssize_t read(const IORequest &req) const;
virtual bool write(const IORequest& req); virtual bool write(const IORequest &req);
virtual int truncate(off_t size); virtual int truncate(off_t size);
virtual bool isWritable() const; virtual bool isWritable() const;
@ -59,4 +59,3 @@ class MemFileIO : public FileIO {
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -42,23 +42,18 @@ using std::string;
namespace encfs { namespace encfs {
#define REF_MODULE(TYPE) \ #define REF_MODULE(TYPE) \
do { \ do { \
if(!TYPE::Enabled() ) \ if (!TYPE::Enabled()) cerr << "referenceModule: should never happen\n"; \
cerr << "referenceModule: should never happen\n"; \ } while (0)
} while(0)
static static void AddSymbolReferences() {
void AddSymbolReferences()
{
REF_MODULE(BlockNameIO); REF_MODULE(BlockNameIO);
REF_MODULE(StreamNameIO); REF_MODULE(StreamNameIO);
REF_MODULE(NullNameIO); REF_MODULE(NullNameIO);
} }
struct NameIOAlg {
struct NameIOAlg
{
bool hidden; bool hidden;
NameIO::Constructor constructor; NameIO::Constructor constructor;
string description; string description;
@ -66,30 +61,25 @@ struct NameIOAlg
bool needsStreamMode; bool needsStreamMode;
}; };
typedef multimap< string, NameIOAlg > NameIOMap_t; typedef multimap<string, NameIOAlg> NameIOMap_t;
static NameIOMap_t *gNameIOMap = 0; static NameIOMap_t *gNameIOMap = 0;
list<NameIO::Algorithm> NameIO::GetAlgorithmList(bool includeHidden) {
list< NameIO::Algorithm > NameIO::GetAlgorithmList( bool includeHidden )
{
AddSymbolReferences(); AddSymbolReferences();
list< Algorithm > result; list<Algorithm> result;
if(gNameIOMap) if (gNameIOMap) {
{
NameIOMap_t::const_iterator it; NameIOMap_t::const_iterator it;
NameIOMap_t::const_iterator end = gNameIOMap->end(); NameIOMap_t::const_iterator end = gNameIOMap->end();
for(it = gNameIOMap->begin(); it != end; ++it) for (it = gNameIOMap->begin(); it != end; ++it) {
{ if (includeHidden || !it->second.hidden) {
if(includeHidden || !it->second.hidden)
{
Algorithm tmp; Algorithm tmp;
tmp.name = it->first; tmp.name = it->first;
tmp.description = it->second.description; tmp.description = it->second.description;
tmp.iface = it->second.iface; tmp.iface = it->second.iface;
tmp.needsStreamMode = it->second.needsStreamMode; 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; return result;
} }
bool NameIO::Register( const char *name, const char *description, bool NameIO::Register(const char *name, const char *description,
const Interface &iface, Constructor constructor, const Interface &iface, Constructor constructor,
bool needsStreamMode, bool needsStreamMode, bool hidden) {
bool hidden ) if (!gNameIOMap) gNameIOMap = new NameIOMap_t;
{
if( !gNameIOMap )
gNameIOMap = new NameIOMap_t;
NameIOAlg alg; NameIOAlg alg;
alg.hidden = hidden; alg.hidden = hidden;
@ -112,40 +99,33 @@ bool NameIO::Register( const char *name, const char *description,
alg.iface = iface; alg.iface = iface;
alg.needsStreamMode = needsStreamMode; alg.needsStreamMode = needsStreamMode;
gNameIOMap->insert( make_pair( string(name), alg )); gNameIOMap->insert(make_pair(string(name), alg));
return true; return true;
} }
shared_ptr<NameIO> NameIO::New(const string &name, shared_ptr<NameIO> NameIO::New(const string &name,
const shared_ptr<CipherV1> &cipher) const shared_ptr<CipherV1> &cipher) {
{
shared_ptr<NameIO> result; shared_ptr<NameIO> result;
if(gNameIOMap) if (gNameIOMap) {
{ NameIOMap_t::const_iterator it = gNameIOMap->find(name);
NameIOMap_t::const_iterator it = gNameIOMap->find( name ); if (it != gNameIOMap->end()) {
if(it != gNameIOMap->end())
{
Constructor fn = it->second.constructor; Constructor fn = it->second.constructor;
result = (*fn)( it->second.iface, cipher ); result = (*fn)(it->second.iface, cipher);
} }
} }
return result; return result;
} }
shared_ptr<NameIO> NameIO::New(const Interface &iface, shared_ptr<NameIO> NameIO::New(const Interface &iface,
const shared_ptr<CipherV1> &cipher) const shared_ptr<CipherV1> &cipher) {
{
shared_ptr<NameIO> result; shared_ptr<NameIO> result;
if(gNameIOMap) if (gNameIOMap) {
{
NameIOMap_t::const_iterator it; NameIOMap_t::const_iterator it;
NameIOMap_t::const_iterator end = gNameIOMap->end(); NameIOMap_t::const_iterator end = gNameIOMap->end();
for(it = gNameIOMap->begin(); it != end; ++it) for (it = gNameIOMap->begin(); it != end; ++it) {
{ if (implements(it->second.iface, iface)) {
if( implements(it->second.iface, iface ))
{
Constructor fn = it->second.constructor; Constructor fn = it->second.constructor;
result = (*fn)( iface, cipher ); result = (*fn)(iface, cipher);
break; break;
} }
} }
@ -153,195 +133,148 @@ shared_ptr<NameIO> NameIO::New(const Interface &iface,
return result; return result;
} }
NameIO::NameIO() : chainedNameIV(false), reverseEncryption(false) {}
NameIO::~NameIO() {}
NameIO::NameIO() void NameIO::setChainedNameIV(bool enable) { chainedNameIV = enable; }
: chainedNameIV( false ), reverseEncryption( false )
{
}
NameIO::~NameIO() bool NameIO::getChainedNameIV() const { return chainedNameIV; }
{
}
void NameIO::setChainedNameIV( bool enable ) void NameIO::setReverseEncryption(bool enable) { reverseEncryption = enable; }
{
chainedNameIV = enable;
}
bool NameIO::getChainedNameIV() const bool NameIO::getReverseEncryption() const { return reverseEncryption; }
{
return chainedNameIV;
}
void NameIO::setReverseEncryption( bool enable ) std::string NameIO::recodePath(const char *path,
{ int (NameIO::*_length)(int) const,
reverseEncryption = enable; int (NameIO::*_code)(const char *, int,
} uint64_t *, char *) const,
uint64_t *iv) const {
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; string output;
while( *path ) while (*path) {
{ if (*path == '/') {
if( *path == '/' ) if (!output.empty()) // don't start the string with '/'
{
if( !output.empty() ) // don't start the string with '/'
output += '/'; output += '/';
++path; ++path;
} else } else {
{
bool isDotFile = (*path == '.'); bool isDotFile = (*path == '.');
const char *next = strchr( path, '/' ); const char *next = strchr(path, '/');
int len = next ? next - path : strlen( path ); int len = next ? next - path : strlen(path);
// at this point we know that len > 0 // at this point we know that len > 0
if( isDotFile && (path[len-1] == '.') && (len <= 2) ) if (isDotFile && (path[len - 1] == '.') && (len <= 2)) {
{ output.append(len, '.'); // append [len] copies of '.'
output.append(len, '.'); // append [len] copies of '.'
path += len; path += len;
continue; continue;
} }
// figure out buffer sizes // figure out buffer sizes
int approxLen = (this->*_length)( len ); int approxLen = (this->*_length)(len);
if(approxLen <= 0) if (approxLen <= 0) throw Error("Filename too small to decode");
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 // code the name
int codedLen = (this->*_code)( path, len, iv, codeBuf ); int codedLen = (this->*_code)(path, len, iv, codeBuf);
rAssert( codedLen <= approxLen ); rAssert(codedLen <= approxLen);
rAssert( codeBuf[codedLen] == '\0' ); rAssert(codeBuf[codedLen] == '\0');
path += len; path += len;
// append result to string // append result to string
output += (char*)codeBuf; output += (char *)codeBuf;
BUFFER_RESET( codeBuf ); BUFFER_RESET(codeBuf);
} }
} }
return output; return output;
} }
std::string NameIO::encodePath( const char *plaintextPath ) const std::string NameIO::encodePath(const char *plaintextPath) const {
{
uint64_t iv = 0; 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; uint64_t iv = 0;
return decodePath( cipherPath, &iv ); return decodePath(cipherPath, &iv);
} }
std::string NameIO::_encodePath( const char *plaintextPath, 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( 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 chaining is not enabled, then the iv pointer is not used..
if(!chainedNameIV) if (!chainedNameIV) iv = 0;
iv = 0; return recodePath(plaintextPath, &NameIO::maxEncodedNameLen,
return recodePath( cipherPath, &NameIO::encodeName, iv);
&NameIO::maxDecodedNameLen, &NameIO::decodeName, iv);
} }
std::string NameIO::encodePath( const char *path, uint64_t *iv ) const std::string NameIO::_decodePath(const char *cipherPath, uint64_t *iv) const {
{ // if chaining is not enabled, then the iv pointer is not used..
return getReverseEncryption() ? if (!chainedNameIV) iv = 0;
_decodePath( path, iv ) : return recodePath(cipherPath, &NameIO::maxDecodedNameLen, &NameIO::decodeName,
_encodePath( path, iv ); 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 std::string NameIO::encodePath(const char *path, uint64_t *iv) const {
{ return getReverseEncryption() ? _decodePath(path, iv) : _encodePath(path, iv);
return decodeName( input, length, (uint64_t*)0, output );
} }
std::string NameIO::_encodeName( const char *plaintextName, int length ) const std::string NameIO::decodePath(const char *path, uint64_t *iv) const {
{ return getReverseEncryption() ? _encodePath(path, iv) : _decodePath(path, iv);
int approxLen = maxEncodedNameLen( length ); }
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 // code the name
int codedLen = encodeName( plaintextName, length, 0, codeBuf ); int codedLen = encodeName(plaintextName, length, 0, codeBuf);
rAssert( codedLen <= approxLen ); rAssert(codedLen <= approxLen);
rAssert( codeBuf[codedLen] == '\0' ); rAssert(codeBuf[codedLen] == '\0');
// append result to string // append result to string
std::string result = (char*)codeBuf; std::string result = (char *)codeBuf;
BUFFER_RESET( codeBuf ); BUFFER_RESET(codeBuf);
return result; return result;
} }
std::string NameIO::_decodeName( const char *encodedName, int length ) const std::string NameIO::_decodeName(const char *encodedName, int length) const {
{ int approxLen = maxDecodedNameLen(length);
int approxLen = maxDecodedNameLen( length );
BUFFER_INIT( codeBuf, 32, (unsigned int)approxLen+1 ); BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1);
// code the name // code the name
int codedLen = decodeName( encodedName, length, 0, codeBuf ); int codedLen = decodeName(encodedName, length, 0, codeBuf);
rAssert( codedLen <= approxLen ); rAssert(codedLen <= approxLen);
rAssert( codeBuf[codedLen] == '\0' ); rAssert(codeBuf[codedLen] == '\0');
// append result to string // append result to string
std::string result = (char*)codeBuf; std::string result = (char *)codeBuf;
BUFFER_RESET( codeBuf ); BUFFER_RESET(codeBuf);
return result; return result;
} }
std::string NameIO::encodeName( const char *path, int length ) const std::string NameIO::encodeName(const char *path, int length) const {
{ return getReverseEncryption() ? _decodeName(path, length)
return getReverseEncryption() ? : _encodeName(path, length);
_decodeName( path, length ) :
_encodeName( path, length );
} }
std::string NameIO::decodeName( const char *path, int length ) const std::string NameIO::decodeName(const char *path, int length) const {
{ return getReverseEncryption() ? _encodeName(path, length)
return getReverseEncryption() ? : _decodeName(path, length);
_encodeName( path, length ) :
_decodeName( path, length );
} }
} // namespace encfs } // namespace encfs

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -33,14 +33,12 @@ namespace encfs {
class CipherV1; class CipherV1;
class NameIO class NameIO {
{
public: public:
typedef shared_ptr<NameIO> (*Constructor)(const Interface &iface, typedef shared_ptr<NameIO>(*Constructor)(const Interface &iface,
const shared_ptr<CipherV1> &cipher); const shared_ptr<CipherV1> &cipher);
struct Algorithm struct Algorithm {
{
std::string name; std::string name;
std::string description; std::string description;
Interface iface; Interface iface;
@ -48,72 +46,65 @@ class NameIO
}; };
typedef std::list<Algorithm> AlgorithmList; typedef std::list<Algorithm> AlgorithmList;
static AlgorithmList GetAlgorithmList( bool includeHidden = false ); static AlgorithmList GetAlgorithmList(bool includeHidden = false);
static shared_ptr<NameIO> New(const Interface &iface, static shared_ptr<NameIO> New(const Interface &iface,
const shared_ptr<CipherV1> &cipher); const shared_ptr<CipherV1> &cipher);
static shared_ptr<NameIO> New(const std::string &name, static shared_ptr<NameIO> New(const std::string &name,
const shared_ptr<CipherV1> &cipher); const shared_ptr<CipherV1> &cipher);
static bool Register( const char *name, const char *description, static bool Register(const char *name, const char *description,
const Interface &iface, Constructor constructor, const Interface &iface, Constructor constructor,
bool needsStreamMode, bool needsStreamMode, bool hidden = false);
bool hidden = false);
NameIO(); NameIO();
virtual ~NameIO(); virtual ~NameIO();
virtual Interface interface() const =0; virtual Interface interface() const = 0;
void setChainedNameIV( bool enable ); void setChainedNameIV(bool enable);
bool getChainedNameIV() const; bool getChainedNameIV() const;
void setReverseEncryption( bool enable ); void setReverseEncryption(bool enable);
bool getReverseEncryption() const; bool getReverseEncryption() const;
std::string encodePath( const char *plaintextPath ) const; std::string encodePath(const char *plaintextPath) const;
std::string decodePath( const char *encodedPath ) const; std::string decodePath(const char *encodedPath) const;
std::string encodePath( const char *plaintextPath, 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 decodePath(const char *encodedPath, uint64_t *iv) const;
virtual int maxEncodedNameLen( int plaintextNameLen ) const =0; virtual int maxEncodedNameLen(int plaintextNameLen) const = 0;
virtual int maxDecodedNameLen( int encodedNameLen ) const =0; virtual int maxDecodedNameLen(int encodedNameLen) const = 0;
std::string encodeName( const char *plaintextName, int length ) const; std::string encodeName(const char *plaintextName, int length) const;
std::string decodeName( const char *encodedName, int length ) const; std::string decodeName(const char *encodedName, int length) const;
protected: protected:
virtual int encodeName( const char *plaintextName, int length, virtual int encodeName(const char *plaintextName, int length,
char *encodedName ) const; char *encodedName) const;
virtual int decodeName( const char *encodedName, int length, virtual int decodeName(const char *encodedName, int length,
char *plaintextName ) const; 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,
std::string recodePath( const char *path, int (NameIO::*codingFunc)(const char *, int,
int (NameIO::*codingLen)(int) const,
int (NameIO::*codingFunc)(const char *, int,
uint64_t *, char *) const, uint64_t *, char *) const,
uint64_t *iv ) const; uint64_t *iv) const;
std::string _encodePath( const char *plaintextPath, 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 _decodePath(const char *encodedPath, uint64_t *iv) const;
std::string _encodeName( const char *plaintextName, int length ) const; std::string _encodeName(const char *plaintextName, int length) const;
std::string _decodeName( const char *encodedName, int length ) const; std::string _decodeName(const char *encodedName, int length) const;
bool chainedNameIV; bool chainedNameIV;
bool reverseEncryption; bool reverseEncryption;
}; };
/* /*
Helper macros for creating temporary buffers with an optimization that Helper macros for creating temporary buffers with an optimization that
below a given size (OptimizedSize) is allocated on the stack, and when a 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 BUFFER_RESET should be called for the same name as BUFFER_INIT
*/ */
#define BUFFER_INIT( Name, OptimizedSize, Size ) \ #define BUFFER_INIT(Name, OptimizedSize, Size) \
char Name ## _Raw [ OptimizedSize ]; \ char Name##_Raw[OptimizedSize]; \
char *Name = Name ## _Raw; \ char *Name = Name##_Raw; \
if( sizeof(Name ## _Raw) < Size ) { \ if (sizeof(Name##_Raw) < Size) { \
Name = new char[ Size ];\ Name = new char[Size]; \
} \ } \
memset( Name, 0, Size ) memset(Name, 0, Size)
#define BUFFER_RESET( Name ) \ #define BUFFER_RESET(Name) \
do { \ do { \
if( Name != Name ## _Raw ) { \ if (Name != Name##_Raw) { \
delete[] Name; \ delete[] Name; \
Name = Name ## _Raw; \ Name = Name##_Raw; \
} \ } \
} while(0) } while (0)
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -26,63 +26,43 @@
namespace encfs { namespace encfs {
static shared_ptr<NameIO> NewNNIO( const Interface &, static shared_ptr<NameIO> NewNNIO(const Interface &,
const shared_ptr<CipherV1> & ) const shared_ptr<CipherV1> &) {
{ return shared_ptr<NameIO>(new NullNameIO());
return shared_ptr<NameIO>( new NullNameIO() );
} }
static Interface NNIOIface = makeInterface("nameio/null", 1, 0, 0); static Interface NNIOIface = makeInterface("nameio/null", 1, 0, 0);
static bool NullNameIO_registered = NameIO::Register("Null", static bool NullNameIO_registered = NameIO::Register(
"No encryption of filenames", NNIOIface, NewNNIO, false); "Null", "No encryption of filenames", NNIOIface, NewNNIO, false);
NullNameIO::NullNameIO( ) NullNameIO::NullNameIO() {}
{
}
NullNameIO::~NullNameIO() NullNameIO::~NullNameIO() {}
{
}
Interface NullNameIO::interface() const Interface NullNameIO::interface() const { return NNIOIface; }
{
return NNIOIface;
}
Interface NullNameIO::CurrentInterface() Interface NullNameIO::CurrentInterface() { return NNIOIface; }
{
return NNIOIface;
}
int NullNameIO::maxEncodedNameLen(int plaintextNameLen) const {
int NullNameIO::maxEncodedNameLen( int plaintextNameLen ) const
{
return plaintextNameLen; return plaintextNameLen;
} }
int NullNameIO::maxDecodedNameLen( int encodedNameLen ) const int NullNameIO::maxDecodedNameLen(int encodedNameLen) const {
{
return encodedNameLen; return encodedNameLen;
} }
int NullNameIO::encodeName( const char *plaintextName, int length, int NullNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv,
uint64_t *iv, char *encodedName ) const char *encodedName) const {
{ memcpy(encodedName, plaintextName, length);
memcpy( encodedName, plaintextName, length );
return length; return length;
} }
int NullNameIO::decodeName( const char *encodedName, int length, int NullNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
uint64_t *iv, char *plaintextName ) const char *plaintextName) const {
{ memcpy(plaintextName, encodedName, length);
memcpy( plaintextName, encodedName, length );
return length; return length;
} }
bool NullNameIO::Enabled() bool NullNameIO::Enabled() { return true; }
{
return true;
}
} // namespace encfs } // namespace encfs

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -25,31 +25,31 @@
namespace encfs { namespace encfs {
class NullNameIO : public NameIO class NullNameIO : public NameIO {
{ public:
public: static Interface CurrentInterface();
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 maxEncodedNameLen(int plaintextNameLen) const;
virtual int maxDecodedNameLen( int encodedNameLen ) const; virtual int maxDecodedNameLen(int encodedNameLen) const;
// hack to help with static builds // hack to help with static builds
static bool Enabled(); static bool Enabled();
protected:
virtual int encodeName( const char *plaintextName, int length, protected:
uint64_t *iv, char *encodedName ) const; virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
virtual int decodeName( const char *encodedName, int length, char *encodedName) const;
uint64_t *iv, char *plaintextName ) const; virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
private: char *plaintextName) const;
private:
}; };
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -19,7 +19,7 @@
*/ */
#ifdef linux #ifdef linux
#define _XOPEN_SOURCE 500 // pick up pread , pwrite #define _XOPEN_SOURCE 500 // pick up pread , pwrite
#endif #endif
#include <unistd.h> #include <unistd.h>
@ -39,57 +39,41 @@ namespace encfs {
static Interface RawFileIO_iface = makeInterface("FileIO/Raw", 1, 0, 0); static Interface RawFileIO_iface = makeInterface("FileIO/Raw", 1, 0, 0);
FileIO *NewRawFileIO( const Interface &iface ) FileIO *NewRawFileIO(const Interface &iface) {
{ (void)iface;
(void)iface; return new RawFileIO();
return new RawFileIO();
} }
inline void swap( int &x, int &y ) inline void swap(int &x, int &y) {
{ int tmp = x;
int tmp = x; x = y;
x = y; y = tmp;
y = tmp;
} }
RawFileIO::RawFileIO( ) RawFileIO::RawFileIO()
: knownSize( false ) : knownSize(false), fileSize(0), fd(-1), oldfd(-1), canWrite(false) {}
, fileSize(0)
, fd( -1 )
, oldfd( -1 )
, canWrite( false )
{
}
RawFileIO::RawFileIO( const std::string &fileName ) RawFileIO::RawFileIO(const std::string &fileName)
: name( fileName ) : name(fileName),
, knownSize( false ) knownSize(false),
, fileSize( 0 ) fileSize(0),
, fd( -1 ) fd(-1),
, oldfd( -1 ) oldfd(-1),
, canWrite( false ) canWrite(false) {}
{
}
RawFileIO::~RawFileIO() RawFileIO::~RawFileIO() {
{
int _fd = -1; int _fd = -1;
int _oldfd = -1; int _oldfd = -1;
swap( _fd, fd ); swap(_fd, fd);
swap( _oldfd, oldfd ); swap(_oldfd, oldfd);
if( _oldfd != -1 ) if (_oldfd != -1) close(_oldfd);
close( _oldfd );
if( _fd != -1 ) if (_fd != -1) close(_fd);
close( _fd );
} }
Interface RawFileIO::interface() const Interface RawFileIO::interface() const { return RawFileIO_iface; }
{
return RawFileIO_iface;
}
/* /*
Workaround for opening a file for write when permissions don't allow. 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 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. 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; int fd = -1;
struct stat stbuf; struct stat stbuf;
memset(&stbuf, 0, sizeof(struct stat)); memset(&stbuf, 0, sizeof(struct stat));
if(lstat( path, &stbuf ) != -1) if (lstat(path, &stbuf) != -1) {
{
// make sure user has read/write permission.. // make sure user has read/write permission..
chmod( path , stbuf.st_mode | 0600 ); chmod(path, stbuf.st_mode | 0600);
fd = ::open( path , flags ); fd = ::open(path, flags);
chmod( path , stbuf.st_mode ); chmod(path, stbuf.st_mode);
} else } else {
{
LOG(INFO) << "can't stat file " << path; 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 - Also keep the O_LARGEFILE flag, in case the underlying filesystem needs
it.. it..
*/ */
int RawFileIO::open(int flags) int RawFileIO::open(int flags) {
{
bool requestWrite = ((flags & O_RDWR) || (flags & O_WRONLY)); bool requestWrite = ((flags & O_RDWR) || (flags & O_WRONLY));
VLOG(1) << "open call for " VLOG(1) << "open call for " << (requestWrite ? "writable" : "read only")
<< (requestWrite ? "writable" : "read only") << " file";
<< " file";
int result = 0; int result = 0;
// if we have a descriptor and it is writable, or we don't need writable.. // 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"; VLOG(1) << "using existing file descriptor";
result = fd; // success result = fd; // success
} else } else {
{
int finalFlags = requestWrite ? O_RDWR : O_RDONLY; int finalFlags = requestWrite ? O_RDWR : O_RDONLY;
#if defined(O_LARGEFILE) #if defined(O_LARGEFILE)
if( flags & O_LARGEFILE ) if (flags & O_LARGEFILE) finalFlags |= O_LARGEFILE;
finalFlags |= O_LARGEFILE;
#else #else
#warning O_LARGEFILE not supported #warning O_LARGEFILE not supported
#endif #endif
int newFd = ::open( name.c_str(), finalFlags ); int newFd = ::open(name.c_str(), finalFlags);
VLOG(1) << "open file with flags " << finalFlags << ", result = " << newFd; 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"; 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 (newFd >= 0) {
{ if (oldfd >= 0) {
if(oldfd >= 0) LOG(ERROR) << "leaking FD?: oldfd = " << oldfd << ", fd = " << fd
{ << ", newfd = " << newFd;
LOG(ERROR) << "leaking FD?: oldfd = "
<< oldfd << ", fd = " << fd << ", newfd = " << newFd;
} }
// the old fd might still be in use, so just keep it around for // 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; canWrite = requestWrite;
oldfd = fd; oldfd = fd;
result = fd = newFd; result = fd = newFd;
} else } else {
{
result = -errno; result = -errno;
LOG(INFO) << "::open error: " << strerror(errno); LOG(INFO) << "::open error: " << strerror(errno);
} }
@ -187,68 +159,53 @@ int RawFileIO::open(int flags)
return result; return result;
} }
int RawFileIO::getAttr( struct stat *stbuf ) const int RawFileIO::getAttr(struct stat *stbuf) const {
{ int res = lstat(name.c_str(), stbuf);
int res = lstat( name.c_str(), stbuf );
int eno = errno; int eno = errno;
LOG_IF(INFO, res < 0) << "getAttr error on " << name LOG_IF(INFO, res < 0) << "getAttr error on " << name << ": " << strerror(eno);
<< ": " << strerror( eno );
return ( res < 0 ) ? -eno : 0; return (res < 0) ? -eno : 0;
} }
void RawFileIO::setFileName( const char *fileName ) void RawFileIO::setFileName(const char *fileName) { name = fileName; }
{
name = fileName;
}
const char *RawFileIO::getFileName() const const char *RawFileIO::getFileName() const { return name.c_str(); }
{
return name.c_str();
}
off_t RawFileIO::getSize() const off_t RawFileIO::getSize() const {
{ if (!knownSize) {
if(!knownSize)
{
struct stat stbuf; struct stat stbuf;
memset( &stbuf, 0, sizeof( struct stat )); memset(&stbuf, 0, sizeof(struct stat));
int res = lstat( name.c_str(), &stbuf ); int res = lstat(name.c_str(), &stbuf);
if(res == 0) if (res == 0) {
{
fileSize = stbuf.st_size; fileSize = stbuf.st_size;
knownSize = true; knownSize = true;
return fileSize; return fileSize;
} else } else
return -1; return -1;
} else } else {
{
return fileSize; return fileSize;
} }
} }
ssize_t RawFileIO::read( const IORequest &req ) const ssize_t RawFileIO::read(const IORequest &req) const {
{ rAssert(fd >= 0);
rAssert( fd >= 0 );
VLOG(2) << "Read " << req.dataLen << " bytes from offset " << req.offset; 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) if (readSize < 0) {
{ LOG(INFO) << "read failed at offset " << req.offset << " for "
LOG(INFO) << "read failed at offset " << req.offset << req.dataLen << " bytes: " << strerror(errno);
<< " for " << req.dataLen << " bytes: " << strerror(errno);
} }
return readSize; return readSize;
} }
bool RawFileIO::write( const IORequest &req ) bool RawFileIO::write(const IORequest &req) {
{ rAssert(fd >= 0);
rAssert( fd >= 0 ); rAssert(true == canWrite);
rAssert( true == canWrite );
VLOG(2) << "Write " << req.dataLen << " bytes to offset " << req.offset; 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; ssize_t bytes = req.dataLen;
off_t offset = req.offset; off_t offset = req.offset;
while( bytes && retrys > 0 ) while (bytes && retrys > 0) {
{ ssize_t writeSize = ::pwrite(fd, buf, bytes, offset);
ssize_t writeSize = ::pwrite( fd, buf, bytes, offset );
if( writeSize < 0 ) if (writeSize < 0) {
{
knownSize = false; knownSize = false;
LOG(INFO) << "write failed at offset " << offset << " for " LOG(INFO) << "write failed at offset " << offset << " for " << bytes
<< bytes << " bytes: " << strerror(errno); << " bytes: " << strerror(errno);
return false; return false;
} }
bytes -= writeSize; bytes -= writeSize;
offset += writeSize; offset += writeSize;
buf = (void*)((char*)buf + writeSize); buf = (void *)((char *)buf + writeSize);
--retrys; --retrys;
} }
if(bytes != 0) if (bytes != 0) {
{ LOG(ERROR) << "Write error: wrote " << (req.dataLen - bytes) << " bytes of "
LOG(ERROR) << "Write error: wrote " << (req.dataLen-bytes) << req.dataLen << ", max retries reached";
<< " bytes of " << req.dataLen << ", max retries reached";
knownSize = false; knownSize = false;
return false; return false;
} else } else {
{ if (knownSize) {
if(knownSize)
{
off_t last = req.offset + req.dataLen; off_t last = req.offset + req.dataLen;
if(last > fileSize) if (last > fileSize) fileSize = last;
fileSize = last;
} }
return true; return true;
} }
} }
int RawFileIO::truncate( off_t size ) int RawFileIO::truncate(off_t size) {
{
int res; int res;
if(fd >= 0 && canWrite) if (fd >= 0 && canWrite) {
{ res = ::ftruncate(fd, size);
res = ::ftruncate( fd, size );
#ifndef __FreeBSD__ #ifndef __FreeBSD__
::fdatasync( fd ); ::fdatasync(fd);
#endif #endif
} else } else
res = ::truncate( name.c_str(), size ); res = ::truncate(name.c_str(), size);
if(res < 0) if (res < 0) {
{
int eno = errno; int eno = errno;
LOG(INFO) << "truncate failed for " << name LOG(INFO) << "truncate failed for " << name << " (" << fd << ") size "
<< " (" << fd << ") size " << size << ", error " << strerror(eno); << size << ", error " << strerror(eno);
res = -eno; res = -eno;
knownSize = false; knownSize = false;
} else } else {
{
res = 0; res = 0;
fileSize = size; fileSize = size;
knownSize = true; knownSize = true;
@ -324,10 +271,6 @@ int RawFileIO::truncate( off_t size )
return res; return res;
} }
bool RawFileIO::isWritable() const bool RawFileIO::isWritable() const { return canWrite; }
{
return canWrite;
}
} // namespace encfs } // namespace encfs

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -27,42 +27,40 @@
namespace encfs { namespace encfs {
class RawFileIO : public FileIO class RawFileIO : public FileIO {
{ public:
public: RawFileIO();
RawFileIO(); RawFileIO(const std::string &fileName);
RawFileIO( const std::string &fileName ); virtual ~RawFileIO();
virtual ~RawFileIO();
virtual Interface interface() const; virtual Interface interface() const;
virtual void setFileName( const char *fileName ); virtual void setFileName(const char *fileName);
virtual const char *getFileName() const; virtual const char *getFileName() const;
virtual int open( int flags ); 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 int getAttr(struct stat *stbuf) const;
virtual bool write( const IORequest &req ); 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; virtual int truncate(off_t size);
protected:
std::string name; virtual bool isWritable() const;
mutable bool knownSize; protected:
mutable off_t fileSize; std::string name;
int fd; mutable bool knownSize;
int oldfd; mutable off_t fileSize;
bool canWrite;
int fd;
int oldfd;
bool canWrite;
}; };
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -30,17 +30,15 @@
namespace encfs { namespace encfs {
static shared_ptr<NameIO> NewStreamNameIO( const Interface &iface, static shared_ptr<NameIO> NewStreamNameIO(const Interface &iface,
const shared_ptr<CipherV1> &cipher ) const shared_ptr<CipherV1> &cipher) {
{ return shared_ptr<NameIO>(new StreamNameIO(iface, cipher));
return shared_ptr<NameIO>( 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"), gettext_noop("Stream encoding, keeps filenames as short as possible"),
StreamNameIO::CurrentInterface(), StreamNameIO::CurrentInterface(), NewStreamNameIO, true);
NewStreamNameIO, true);
/* /*
- Version 0.1 is for EncFS 0.x support. The difference to 1.0 is that 0.x - 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. - 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 // implement major version 2, 1, and 0
return makeInterface("nameio/stream", 2, 1, 2); return makeInterface("nameio/stream", 2, 1, 2);
} }
StreamNameIO::StreamNameIO( const Interface &iface, StreamNameIO::StreamNameIO(const Interface &iface,
const shared_ptr<CipherV1> &cipher ) const shared_ptr<CipherV1> &cipher)
: _interface( iface.major() ) : _interface(iface.major()), _cipher(cipher) {}
, _cipher( cipher )
{
} StreamNameIO::~StreamNameIO() {}
StreamNameIO::~StreamNameIO() Interface StreamNameIO::interface() const { return CurrentInterface(); }
{
}
Interface StreamNameIO::interface() const int StreamNameIO::maxEncodedNameLen(int plaintextStreamLen) const {
{
return CurrentInterface();
}
int StreamNameIO::maxEncodedNameLen( int plaintextStreamLen ) const
{
int encodedStreamLen = 2 + plaintextStreamLen; int encodedStreamLen = 2 + plaintextStreamLen;
return B256ToB64Bytes( encodedStreamLen ); return B256ToB64Bytes(encodedStreamLen);
} }
int StreamNameIO::maxDecodedNameLen( int encodedStreamLen ) const int StreamNameIO::maxDecodedNameLen(int encodedStreamLen) const {
{ int decLen256 = B64ToB256Bytes(encodedStreamLen);
int decLen256 = B64ToB256Bytes( encodedStreamLen );
return decLen256 - 2; return decLen256 - 2;
} }
int StreamNameIO::encodeName( const char *plaintextName, int length, int StreamNameIO::encodeName(const char *plaintextName, int length,
uint64_t *iv, char *encodedName ) const uint64_t *iv, char *encodedName) const {
{
uint64_t tmpIV = 0; uint64_t tmpIV = 0;
if( iv && _interface >= 2 ) if (iv && _interface >= 2) tmpIV = *iv;
tmpIV = *iv;
unsigned int mac = _cipher->reduceMac16( 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 // add on checksum bytes
unsigned char *encodeBegin; unsigned char *encodeBegin;
if(_interface >= 1) if (_interface >= 1) {
{
// current versions store the checksum at the beginning // current versions store the checksum at the beginning
encodedName[0] = (mac >> 8) & 0xff; encodedName[0] = (mac >> 8) & 0xff;
encodedName[1] = (mac ) & 0xff; encodedName[1] = (mac) & 0xff;
encodeBegin = (unsigned char *)encodedName+2; encodeBegin = (unsigned char *)encodedName + 2;
} else } else {
{
// encfs 0.x stored checksums at the end. // encfs 0.x stored checksums at the end.
encodedName[length] = (mac >> 8) & 0xff; encodedName[length] = (mac >> 8) & 0xff;
encodedName[length+1] = (mac ) & 0xff; encodedName[length + 1] = (mac) & 0xff;
encodeBegin = (unsigned char *)encodedName; encodeBegin = (unsigned char *)encodedName;
} }
// stream encode the plaintext bytes // stream encode the plaintext bytes
memcpy( encodeBegin, plaintextName, length ); memcpy(encodeBegin, plaintextName, length);
_cipher->streamEncode( encodeBegin, length, (uint64_t)mac ^ tmpIV); _cipher->streamEncode(encodeBegin, length, (uint64_t)mac ^ tmpIV);
// convert the entire thing to base 64 ascii.. // convert the entire thing to base 64 ascii..
int encodedStreamLen = length + 2; int encodedStreamLen = length + 2;
int encLen64 = B256ToB64Bytes( encodedStreamLen ); int encLen64 = B256ToB64Bytes(encodedStreamLen);
changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen, changeBase2Inline((unsigned char *)encodedName, encodedStreamLen, 8, 6, true);
8, 6, true ); B64ToAscii((unsigned char *)encodedName, encLen64);
B64ToAscii( (unsigned char *)encodedName, encLen64 );
return encLen64; return encLen64;
} }
int StreamNameIO::decodeName( const char *encodedName, int length, int StreamNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
uint64_t *iv, char *plaintextName ) const char *plaintextName) const {
{
rAssert(length > 2); rAssert(length > 2);
int decLen256 = B64ToB256Bytes( length ); int decLen256 = B64ToB256Bytes(length);
int decodedStreamLen = decLen256 - 2; int decodedStreamLen = decLen256 - 2;
if(decodedStreamLen <= 0) if (decodedStreamLen <= 0) throw Error("Filename too small to decode");
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 // decode into tmpBuf, because this step produces more data then we can fit
// into the result buffer.. // 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); changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false);
// pull out the checksum value which is used as an initialization vector // pull out the checksum value which is used as an initialization vector
uint64_t tmpIV = 0; uint64_t tmpIV = 0;
unsigned int mac; unsigned int mac;
if(_interface >= 1) if (_interface >= 1) {
{
// current versions store the checksum at the beginning // current versions store the checksum at the beginning
mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 |
| ((unsigned int)((unsigned char)tmpBuf[1])); ((unsigned int)((unsigned char)tmpBuf[1]));
// version 2 adds support for IV chaining.. // version 2 adds support for IV chaining..
if( iv && _interface >= 2 ) if (iv && _interface >= 2) tmpIV = *iv;
tmpIV = *iv;
memcpy( plaintextName, tmpBuf+2, decodedStreamLen ); memcpy(plaintextName, tmpBuf + 2, decodedStreamLen);
} else } else {
{
// encfs 0.x stored checksums at the end. // encfs 0.x stored checksums at the end.
mac = ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen])) << 8 mac = ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen])) << 8 |
| ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen+1])); ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen + 1]));
memcpy( plaintextName, tmpBuf, decodedStreamLen ); memcpy(plaintextName, tmpBuf, decodedStreamLen);
} }
_cipher->streamDecode( (unsigned char *)plaintextName, decodedStreamLen, _cipher->streamDecode((unsigned char *)plaintextName, decodedStreamLen,
(uint64_t)mac ^ tmpIV ); (uint64_t)mac ^ tmpIV);
// compute MAC to check with stored value // compute MAC to check with stored value
unsigned int mac2 = _cipher->reduceMac16( unsigned int mac2 = _cipher->reduceMac16(
_cipher->MAC_64((const byte *)plaintextName, decodedStreamLen, iv)); _cipher->MAC_64((const byte *)plaintextName, decodedStreamLen, iv));
BUFFER_RESET( tmpBuf ); BUFFER_RESET(tmpBuf);
if(mac2 != mac) if (mac2 != mac) {
{
VLOG(1) << "checksum mismatch: expected " << mac << ", got " << mac2 VLOG(1) << "checksum mismatch: expected " << mac << ", got " << mac2
<< "on decode of " << decodedStreamLen << " bytes"; << "on decode of " << decodedStreamLen << " bytes";
throw Error( "checksum mismatch in filename decode" ); throw Error("checksum mismatch in filename decode");
} }
return decodedStreamLen; return decodedStreamLen;
} }
bool StreamNameIO::Enabled() bool StreamNameIO::Enabled() { return true; }
{
return true;
}
} // namespace encfs } // namespace encfs

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -27,33 +27,32 @@ namespace encfs {
class CipherV1; class CipherV1;
class StreamNameIO : public NameIO class StreamNameIO : public NameIO {
{ public:
public: static Interface CurrentInterface();
static Interface CurrentInterface();
StreamNameIO( const Interface &iface, StreamNameIO(const Interface &iface, const shared_ptr<CipherV1> &cipher);
const shared_ptr<CipherV1> &cipher); virtual ~StreamNameIO();
virtual ~StreamNameIO();
virtual Interface interface() const; virtual Interface interface() const;
virtual int maxEncodedNameLen( int plaintextNameLen ) const; virtual int maxEncodedNameLen(int plaintextNameLen) const;
virtual int maxDecodedNameLen( int encodedNameLen ) const; virtual int maxDecodedNameLen(int encodedNameLen) const;
// hack to help with static builds // hack to help with static builds
static bool Enabled(); static bool Enabled();
protected:
virtual int encodeName( const char *plaintextName, int length, protected:
uint64_t *iv, char *encodedName ) const; virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
virtual int decodeName( const char *encodedName, int length, char *encodedName) const;
uint64_t *iv, char *plaintextName ) const; virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
private: char *plaintextName) const;
int _interface;
shared_ptr<CipherV1> _cipher; private:
int _interface;
shared_ptr<CipherV1> _cipher;
}; };
} // namespace encfs } // namespace encfs
#endif #endif

View File

@ -54,47 +54,40 @@ namespace encfs {
const int FSBlockSize = 256; const int FSBlockSize = 256;
static static int checkErrorPropogation(const shared_ptr<CipherV1> &cipher, int size,
int checkErrorPropogation( const shared_ptr<CipherV1> &cipher, int byteToChange) {
int size, int byteToChange )
{
MemBlock orig; MemBlock orig;
orig.allocate(size); orig.allocate(size);
MemBlock data; MemBlock data;
data.allocate(size); data.allocate(size);
for(int i=0; i<size; ++i) for (int i = 0; i < size; ++i) {
{
unsigned char tmp = rand(); unsigned char tmp = rand();
orig.data[i] = tmp; orig.data[i] = tmp;
data.data[i] = tmp; data.data[i] = tmp;
} }
if(size != FSBlockSize) if (size != FSBlockSize)
cipher->streamEncode( data.data, size, 0 ); cipher->streamEncode(data.data, size, 0);
else 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 // 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]; unsigned char previousValue = data.data[byteToChange];
do do {
{
data.data[byteToChange] = rand(); data.data[byteToChange] = rand();
} while(data.data[byteToChange] == previousValue); } while (data.data[byteToChange] == previousValue);
} }
if(size != FSBlockSize) if (size != FSBlockSize)
cipher->streamDecode( data.data, size, 0 ); cipher->streamDecode(data.data, size, 0);
else else
cipher->blockDecode( data.data, size, 0 ); cipher->blockDecode(data.data, size, 0);
int numByteErrors = 0; int numByteErrors = 0;
for(int i=0; i<size; ++i) for (int i = 0; i < size; ++i) {
{ if (data.data[i] != orig.data[i]) ++numByteErrors;
if( data.data[i] != orig.data[i] )
++numByteErrors;
} }
return numByteErrors; return numByteErrors;
@ -102,77 +95,51 @@ int checkErrorPropogation( const shared_ptr<CipherV1> &cipher,
const char TEST_ROOTDIR[] = "/foo"; const char TEST_ROOTDIR[] = "/foo";
static static bool testNameCoding(DirNode &dirNode, bool verbose,
bool testNameCoding( DirNode &dirNode, bool verbose, bool collisionTest = false) {
bool collisionTest = false )
{
// encrypt a name // encrypt a name
const char *name[] = { const char *name[] = {
"1234567", "1234567", "12345678", "123456789",
"12345678", "123456789ABCDEF", "123456789ABCDEF0", "123456789ABCDEF01",
"123456789", "test-name", "test-name2", "test",
"123456789ABCDEF", "../test", "/foo/bar/blah", "test-name.21",
"123456789ABCDEF0", "test-name.22", "test-name.o", "1.test",
"123456789ABCDEF01", "2.test", "a/b/c/d", "a/c/d/e",
"test-name", "b/c/d/e", "b/a/c/d", NULL};
"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; const char **orig = name;
while(*orig) while (*orig) {
{ if (verbose) cerr << " coding name \"" << *orig << "\"";
if(verbose)
cerr << " coding name \"" << *orig << "\"";
string encName = dirNode.relativeCipherPath( *orig ); string encName = dirNode.relativeCipherPath(*orig);
if(verbose) if (verbose) cerr << " -> \"" << encName.c_str() << "\"";
cerr << " -> \"" << encName.c_str() << "\"";
// decrypt name // decrypt name
string decName = dirNode.plainPath( encName.c_str() ); string decName = dirNode.plainPath(encName.c_str());
if(decName == *orig) if (decName == *orig) {
{ if (verbose) cerr << " OK\n";
if(verbose) } else {
cerr << " OK\n"; if (verbose) cerr << " FAILED (got " << decName << ")\n";
} else
{
if(verbose)
cerr << " FAILED (got " << decName << ")\n";
return false; return false;
} }
orig++; orig++;
} }
if (collisionTest) if (collisionTest) {
{
if (verbose) if (verbose)
cerr << "Checking for name collections, this will take a while..\n"; cerr << "Checking for name collections, this will take a while..\n";
// check for collision rate // check for collision rate
char buf[64]; char buf[64];
unordered_set<string> encryptedNames; unordered_set<string> encryptedNames;
for (long i=0; i < 10000000; i++) for (long i = 0; i < 10000000; i++) {
{
snprintf(buf, sizeof(buf), "%li", i); snprintf(buf, sizeof(buf), "%li", i);
string encName = dirNode.relativeCipherPath( buf ); string encName = dirNode.relativeCipherPath(buf);
// simulate a case-insisitive filesystem.. // simulate a case-insisitive filesystem..
std::transform(encName.begin(), encName.end(), encName.begin(), std::transform(encName.begin(), encName.end(), encName.begin(),
::toupper); ::toupper);
if (encryptedNames.insert(encName).second == false) { if (encryptedNames.insert(encName).second == false) {
cerr << "collision detected after " << i << " iterations"; cerr << "collision detected after " << i << " iterations";
@ -185,60 +152,51 @@ bool testNameCoding( DirNode &dirNode, bool verbose,
return true; return true;
} }
bool runTests(const shared_ptr<CipherV1> &cipher, bool verbose) bool runTests(const shared_ptr<CipherV1> &cipher, bool verbose) {
{
// create a random key // create a random key
if(verbose) if (verbose)
cerr << "Generating new key, output will be different on each run\n\n"; cerr << "Generating new key, output will be different on each run\n\n";
CipherKey key = cipher->newRandomKey(); CipherKey key = cipher->newRandomKey();
if(verbose) if (verbose) cerr << "Testing key save / restore :";
cerr << "Testing key save / restore :";
{ {
CipherKey encodingKey = cipher->newRandomKey(); CipherKey encodingKey = cipher->newRandomKey();
int encodedKeySize = cipher->encodedKeySize(); int encodedKeySize = cipher->encodedKeySize();
unsigned char *keyBuf = new unsigned char [ encodedKeySize ]; unsigned char *keyBuf = new unsigned char[encodedKeySize];
cipher->setKey(encodingKey); cipher->setKey(encodingKey);
cipher->writeKey( key, keyBuf ); cipher->writeKey(key, keyBuf);
CipherKey key2 = cipher->readKey( keyBuf, true ); CipherKey key2 = cipher->readKey(keyBuf, true);
delete[] keyBuf; delete[] keyBuf;
if(!key2.valid()) if (!key2.valid()) {
{ if (verbose) cerr << " FAILED (decode error)\n";
if(verbose)
cerr << " FAILED (decode error)\n";
return false; return false;
} }
if(key == key2) if (key == key2) {
{ if (verbose) cerr << " OK\n";
if(verbose) } else {
cerr << " OK\n"; if (verbose) cerr << " FAILED\n";
} else
{
if(verbose)
cerr << " FAILED\n";
return false; return false;
} }
} }
if(verbose) if (verbose) cerr << "Testing Config interface load / store :";
cerr << "Testing Config interface load / store :";
{ {
CipherKey encodingKey = cipher->newRandomKey(); CipherKey encodingKey = cipher->newRandomKey();
int encodedKeySize = cipher->encodedKeySize(); int encodedKeySize = cipher->encodedKeySize();
unsigned char *keyBuf = new unsigned char [ encodedKeySize ]; unsigned char *keyBuf = new unsigned char[encodedKeySize];
cipher->setKey(encodingKey); cipher->setKey(encodingKey);
cipher->writeKey( key, keyBuf ); cipher->writeKey(key, keyBuf);
// store in config struct.. // store in config struct..
EncfsConfig cfg; EncfsConfig cfg;
cfg.mutable_cipher()->MergeFrom(cipher->interface()); cfg.mutable_cipher()->MergeFrom(cipher->interface());
EncryptedKey *encryptedKey = cfg.mutable_key(); EncryptedKey *encryptedKey = cfg.mutable_key();
encryptedKey->set_size(8 * cipher->keySize()); encryptedKey->set_size(8 * cipher->keySize());
encryptedKey->set_ciphertext( keyBuf, encodedKeySize ); encryptedKey->set_ciphertext(keyBuf, encodedKeySize);
cfg.set_block_size(FSBlockSize); cfg.set_block_size(FSBlockSize);
delete[] keyBuf; delete[] keyBuf;
@ -252,27 +210,22 @@ bool runTests(const shared_ptr<CipherV1> &cipher, bool verbose)
google::protobuf::TextFormat::ParseFromString(data, &cfg2); google::protobuf::TextFormat::ParseFromString(data, &cfg2);
// check.. // check..
rAssert( implements(cfg.cipher(),cfg2.cipher()) ); 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() ); rAssert(cfg.block_size() == cfg2.block_size());
// try decoding key.. // try decoding key..
CipherKey key2 = cipher->readKey( (unsigned char *)cfg2.key().ciphertext().data(), true ); CipherKey key2 =
if(!key2.valid()) cipher->readKey((unsigned char *)cfg2.key().ciphertext().data(), true);
{ if (!key2.valid()) {
if(verbose) if (verbose) cerr << " FAILED (decode error)\n";
cerr << " FAILED (decode error)\n";
return false; return false;
} }
if(key == key2) if (key == key2) {
{ if (verbose) cerr << " OK\n";
if(verbose) } else {
cerr << " OK\n"; if (verbose) cerr << " FAILED\n";
} else
{
if(verbose)
cerr << " FAILED\n";
return false; return false;
} }
} }
@ -285,175 +238,145 @@ bool runTests(const shared_ptr<CipherV1> &cipher, bool verbose)
fsCfg->opts.reset(new EncFS_Opts); fsCfg->opts.reset(new EncFS_Opts);
cipher->setKey(key); cipher->setKey(key);
if(verbose) if (verbose)
cerr << "Testing name encode/decode (stream coding w/ IV chaining)\n"; cerr << "Testing name encode/decode (stream coding w/ IV chaining)\n";
{ {
fsCfg->opts->idleTracking = false; fsCfg->opts->idleTracking = false;
fsCfg->config->set_unique_iv(false); fsCfg->config->set_unique_iv(false);
fsCfg->nameCoding.reset( new StreamNameIO( fsCfg->nameCoding.reset(
StreamNameIO::CurrentInterface(), cipher) ); new StreamNameIO(StreamNameIO::CurrentInterface(), cipher));
fsCfg->nameCoding->setChainedNameIV( true ); fsCfg->nameCoding->setChainedNameIV(true);
DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg);
if(!testNameCoding( dirNode, verbose )) if (!testNameCoding(dirNode, verbose)) return false;
return false;
} }
if(verbose) if (verbose)
cerr << "Testing name encode/decode (block coding w/ IV chaining)\n"; cerr << "Testing name encode/decode (block coding w/ IV chaining)\n";
{ {
fsCfg->opts->idleTracking = false; fsCfg->opts->idleTracking = false;
fsCfg->config->set_unique_iv(false); fsCfg->config->set_unique_iv(false);
fsCfg->nameCoding.reset( new BlockNameIO( fsCfg->nameCoding.reset(
BlockNameIO::CurrentInterface(), cipher) ); new BlockNameIO(BlockNameIO::CurrentInterface(), cipher));
fsCfg->nameCoding->setChainedNameIV( true ); fsCfg->nameCoding->setChainedNameIV(true);
DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg);
if(!testNameCoding( dirNode, verbose )) if (!testNameCoding(dirNode, verbose)) return false;
return false;
} }
if(verbose) if (verbose)
cerr << "Testing name encode/decode (block coding w/ IV chaining, base32)\n"; cerr
<< "Testing name encode/decode (block coding w/ IV chaining, base32)\n";
{ {
fsCfg->opts->idleTracking = false; fsCfg->opts->idleTracking = false;
fsCfg->config->set_unique_iv(false); fsCfg->config->set_unique_iv(false);
fsCfg->nameCoding.reset( new BlockNameIO( fsCfg->nameCoding.reset(
BlockNameIO::CurrentInterface(), cipher) ); new BlockNameIO(BlockNameIO::CurrentInterface(), cipher));
fsCfg->nameCoding->setChainedNameIV( true ); fsCfg->nameCoding->setChainedNameIV(true);
DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg);
if(!testNameCoding( dirNode, verbose )) if (!testNameCoding(dirNode, verbose)) return false;
return false;
} }
if(!verbose) if (!verbose) {
{
{ {
// test stream mode, this time without IV chaining // test stream mode, this time without IV chaining
fsCfg->nameCoding = fsCfg->nameCoding = shared_ptr<NameIO>(
shared_ptr<NameIO>( new StreamNameIO( new StreamNameIO(StreamNameIO::CurrentInterface(), cipher));
StreamNameIO::CurrentInterface(), cipher) ); fsCfg->nameCoding->setChainedNameIV(false);
fsCfg->nameCoding->setChainedNameIV( false );
DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg);
if(!testNameCoding( dirNode, verbose )) if (!testNameCoding(dirNode, verbose)) return false;
return false;
} }
{ {
// test block mode, this time without IV chaining // test block mode, this time without IV chaining
fsCfg->nameCoding = shared_ptr<NameIO>( new BlockNameIO( fsCfg->nameCoding = shared_ptr<NameIO>(
BlockNameIO::CurrentInterface(), cipher) ); new BlockNameIO(BlockNameIO::CurrentInterface(), cipher));
fsCfg->nameCoding->setChainedNameIV( false ); fsCfg->nameCoding->setChainedNameIV(false);
DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg ); DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg);
if(!testNameCoding( dirNode, verbose )) if (!testNameCoding(dirNode, verbose)) return false;
return false;
} }
} }
if(verbose) if (verbose) cerr << "Testing block encode/decode on full block - ";
cerr << "Testing block encode/decode on full block - ";
{ {
int numErrors = checkErrorPropogation( cipher, int numErrors = checkErrorPropogation(cipher, FSBlockSize, -1);
FSBlockSize, -1 ); if (numErrors) {
if(numErrors) if (verbose) cerr << " FAILED!\n";
{
if(verbose)
cerr << " FAILED!\n";
return false; return false;
} else } else {
{ if (verbose) cerr << " OK\n";
if(verbose)
cerr << " OK\n";
} }
} }
if(verbose) if (verbose) cerr << "Testing block encode/decode on partial block - ";
cerr << "Testing block encode/decode on partial block - ";
{ {
int numErrors = checkErrorPropogation( cipher, int numErrors = checkErrorPropogation(cipher, FSBlockSize - 1, -1);
FSBlockSize-1, -1 ); if (numErrors) {
if(numErrors) if (verbose) cerr << " FAILED!\n";
{
if(verbose)
cerr << " FAILED!\n";
return false; return false;
} else } else {
{ if (verbose) cerr << " OK\n";
if(verbose)
cerr << " OK\n";
} }
} }
if(verbose) if (verbose) cerr << "Checking error propogation in partial block:\n";
cerr << "Checking error propogation in partial block:\n";
{ {
int minChanges = FSBlockSize-1; int minChanges = FSBlockSize - 1;
int maxChanges = 0; int maxChanges = 0;
int minAt = 0; int minAt = 0;
int maxAt = 0; int maxAt = 0;
for(int i=0; i<FSBlockSize-1; ++i) for (int i = 0; i < FSBlockSize - 1; ++i) {
{ int numErrors = checkErrorPropogation(cipher, FSBlockSize - 1, i);
int numErrors = checkErrorPropogation( cipher,
FSBlockSize-1, i );
if(numErrors < minChanges) if (numErrors < minChanges) {
{
minChanges = numErrors; minChanges = numErrors;
minAt = i; minAt = i;
} }
if(numErrors > maxChanges) if (numErrors > maxChanges) {
{
maxChanges = numErrors; maxChanges = numErrors;
maxAt = i; maxAt = i;
} }
} }
if(verbose) if (verbose) {
{
cerr << "modification of 1 byte affected between " << minChanges cerr << "modification of 1 byte affected between " << minChanges
<< " and " << maxChanges << " decoded bytes\n"; << " and " << maxChanges << " decoded bytes\n";
cerr << "minimum change at byte " << minAt cerr << "minimum change at byte " << minAt << " and maximum at byte "
<< " and maximum at byte " << maxAt << "\n"; << maxAt << "\n";
} }
} }
if(verbose) if (verbose) cerr << "Checking error propogation on full block:\n";
cerr << "Checking error propogation on full block:\n";
{ {
int minChanges = FSBlockSize; int minChanges = FSBlockSize;
int maxChanges = 0; int maxChanges = 0;
int minAt = 0; int minAt = 0;
int maxAt = 0; int maxAt = 0;
for(int i=0; i<FSBlockSize; ++i) for (int i = 0; i < FSBlockSize; ++i) {
{ int numErrors = checkErrorPropogation(cipher, FSBlockSize, i);
int numErrors = checkErrorPropogation( cipher,
FSBlockSize, i );
if(numErrors < minChanges) if (numErrors < minChanges) {
{
minChanges = numErrors; minChanges = numErrors;
minAt = i; minAt = i;
} }
if(numErrors > maxChanges) if (numErrors > maxChanges) {
{
maxChanges = numErrors; maxChanges = numErrors;
maxAt = i; maxAt = i;
} }
} }
if(verbose) if (verbose) {
{
cerr << "modification of 1 byte affected between " << minChanges cerr << "modification of 1 byte affected between " << minChanges
<< " and " << maxChanges << " decoded bytes\n"; << " and " << maxChanges << " decoded bytes\n";
cerr << "minimum change at byte " << minAt cerr << "minimum change at byte " << minAt << " and maximum at byte "
<< " and maximum at byte " << maxAt << "\n"; << maxAt << "\n";
} }
} }
@ -462,8 +385,7 @@ bool runTests(const shared_ptr<CipherV1> &cipher, bool verbose)
} // namespace encfs } // namespace encfs
int main(int argc, char *argv[]) int main(int argc, char *argv[]) {
{
FLAGS_logtostderr = 1; FLAGS_logtostderr = 1;
FLAGS_minloglevel = 1; FLAGS_minloglevel = 1;
@ -473,50 +395,42 @@ int main(int argc, char *argv[])
bool isThreaded = false; bool isThreaded = false;
CipherV1::init(isThreaded); CipherV1::init(isThreaded);
srand( time(0) ); srand(time(0));
// get a list of the available algorithms // get a list of the available algorithms
std::list<CipherV1::CipherAlgorithm> algorithms = std::list<CipherV1::CipherAlgorithm> algorithms =
CipherV1::GetAlgorithmList(); CipherV1::GetAlgorithmList();
std::list<CipherV1::CipherAlgorithm>::const_iterator it; std::list<CipherV1::CipherAlgorithm>::const_iterator it;
cerr << "Supported Crypto interfaces:\n"; cerr << "Supported Crypto interfaces:\n";
for(it = algorithms.begin(); it != algorithms.end(); ++it) for (it = algorithms.begin(); it != algorithms.end(); ++it) {
{ cerr << it->name << " ( " << it->iface.name() << " " << it->iface.major()
cerr << it->name << ":" << it->iface.minor() << ":" << it->iface.age()
<< " ( " << it->iface.name() << " " << " ) : " << it->description << "\n";
<< it->iface.major() << ":"
<< it->iface.minor() << ":"
<< it->iface.age() << " ) : " << it->description << "\n";
cerr << " - key length " << it->keyLength.min() << " to " cerr << " - key length " << it->keyLength.min() << " to "
<< it->keyLength.max() << " , block size " << it->blockSize.min() << it->keyLength.max() << " , block size " << it->blockSize.min()
<< " to " << it->blockSize.max() << "\n"; << " to " << it->blockSize.max() << "\n";
} }
cerr << "\n"; cerr << "\n";
cerr << "Testing interfaces\n"; cerr << "Testing interfaces\n";
for(it = algorithms.begin(); it != algorithms.end(); ++it) for (it = algorithms.begin(); it != algorithms.end(); ++it) {
{ int blockSize = it->blockSize.closest(256);
int blockSize = it->blockSize.closest( 256 ); for (int keySize = it->keyLength.min(); keySize <= it->keyLength.max();
for(int keySize = it->keyLength.min(); keySize <= it->keyLength.max(); keySize += it->keyLength.inc()) {
keySize += it->keyLength.inc()) cerr << it->name << ", key length " << keySize << ", block size "
{ << blockSize << ": ";
cerr << it->name << ", key length " << keySize
<< ", block size " << blockSize << ": ";
shared_ptr<CipherV1> cipher = CipherV1::New( it->name, keySize ); shared_ptr<CipherV1> cipher = CipherV1::New(it->name, keySize);
if(!cipher) if (!cipher) {
{
cerr << "FAILED TO CREATE\n"; cerr << "FAILED TO CREATE\n";
} else } else {
{ try {
try if (runTests(cipher, false))
{
if(runTests( cipher, false ))
cerr << "OK\n"; cerr << "OK\n";
else else
cerr << "FAILED\n"; cerr << "FAILED\n";
} catch( Error &er ) }
{ catch (Error &er) {
cerr << "Error: " << er.what() << "\n"; cerr << "Error: " << er.what() << "\n";
} }
} }
@ -525,20 +439,17 @@ int main(int argc, char *argv[])
// run one test with verbose output too.. // run one test with verbose output too..
shared_ptr<CipherV1> cipher = CipherV1::New("AES", 192); shared_ptr<CipherV1> cipher = CipherV1::New("AES", 192);
if(!cipher) if (!cipher) {
{
cerr << "\nNo AES cipher found, skipping verbose test.\n"; cerr << "\nNo AES cipher found, skipping verbose test.\n";
} else } else {
{ cerr << "\nVerbose output for " << cipher->interface().name()
cerr << "\nVerbose output for " << cipher->interface().name() << " test, key length " << cipher->keySize() * 8 << ", block size "
<< " test, key length " << cipher->keySize()*8 << ", block size " << FSBlockSize << ":\n";
<< FSBlockSize << ":\n";
runTests( cipher, true ); runTests(cipher, true);
} }
CipherV1::shutdown(isThreaded); CipherV1::shutdown(isThreaded);
return 0; return 0;
} }

View File

@ -3,8 +3,8 @@
* *
***************************************************************************** *****************************************************************************
* Copyright (c) 2003-2007, Valient Gough * 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 * 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) * Software Foundation; either version 2 of the License, or (at your option)
* any later version. * any later version.
@ -71,16 +71,15 @@ using std::vector;
namespace encfs { namespace encfs {
#ifndef MIN #ifndef MIN
#define MIN(a,b) (((a)<(b)) ? (a): (b)) #define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif #endif
#define ESUCCESS 0 #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() static EncFS_Context *context() {
{ return (EncFS_Context *)fuse_get_context()->private_data;
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 // helper function -- apply a functor to a cipher path, given the plain path
template<typename T> template <typename T>
static int withCipherPath( const char *opName, const char *path, static int withCipherPath(const char *opName, const char *path,
int (*op)(EncFS_Context *, const string &name, T data ), T data, int (*op)(EncFS_Context *, const string &name,
bool passReturnCode = false ) T data),
{ T data, bool passReturnCode = false) {
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
int res = -EIO; int res = -EIO;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
try try {
{ string cyName = FSRoot->cipherPath(path);
string cyName = FSRoot->cipherPath( path );
VLOG(1) << opName << " " << cyName.c_str(); VLOG(1) << opName << " " << cyName.c_str();
res = op( ctx, cyName, data ); res = op(ctx, cyName, data);
if(res == -1) if (res == -1) {
{
res = -errno; res = -errno;
LOG(INFO) << opName << " error: " << strerror(-res); LOG(INFO) << opName << " error: " << strerror(-res);
} else if(!passReturnCode) } else if (!passReturnCode)
res = ESUCCESS; res = ESUCCESS;
} catch( Error &err ) }
{ catch (Error &err) {
LOG(ERROR) << "error caught in " << opName << LOG(ERROR) << "error caught in " << opName << ":" << err.what();
":" << err.what();
} }
return res; return res;
} }
// helper function -- apply a functor to a node // helper function -- apply a functor to a node
template<typename T> template <typename T>
static int withFileNode( const char *opName, static int withFileNode(const char *opName, const char *path,
const char *path, struct fuse_file_info *fi, struct fuse_file_info *fi,
int (*op)(FileNode *, T data ), T data ) int (*op)(FileNode *, T data), T data) {
{
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
int res = -EIO; int res = -EIO;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
try try {
{
shared_ptr<FileNode> fnode; shared_ptr<FileNode> fnode;
if(fi != NULL) if (fi != NULL)
fnode = GET_FN(ctx, fi); fnode = GET_FN(ctx, fi);
else else
fnode = FSRoot->lookupNode( path, opName ); fnode = FSRoot->lookupNode(path, opName);
rAssert(fnode != NULL); rAssert(fnode != NULL);
VLOG(1) << opName << " " << fnode->cipherName(); VLOG(1) << opName << " " << fnode->cipherName();
res = op( fnode.get(), data ); res = op(fnode.get(), data);
LOG_IF(INFO, res < 0) << opName << " error: " << strerror(-res); LOG_IF(INFO, res < 0) << opName << " error: " << strerror(-res);
} catch( Error &err ) }
{ catch (Error &err) {
LOG(ERROR) << "error caught in " << opName << LOG(ERROR) << "error caught in " << opName << ":" << err.what();
":" << err.what();
} }
return res; return res;
} }
int _do_getattr(FileNode *fnode, struct stat *stbuf) int _do_getattr(FileNode *fnode, struct stat *stbuf) {
{
int res = fnode->getAttr(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(); EncFS_Context *ctx = context();
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(FSRoot) if (FSRoot) {
{
// determine plaintext link size.. Easiest to read and decrypt.. // determine plaintext link size.. Easiest to read and decrypt..
vector<char> buf(stbuf->st_size+1, 0); vector<char> buf(stbuf->st_size + 1, 0);
res = ::readlink( fnode->cipherName(), &buf[0], stbuf->st_size ); res = ::readlink(fnode->cipherName(), &buf[0], stbuf->st_size);
if(res >= 0) if (res >= 0) {
{
// other functions expect c-strings to be null-terminated, which // other functions expect c-strings to be null-terminated, which
// readlink doesn't provide // readlink doesn't provide
buf[res] = '\0'; buf[res] = '\0';
stbuf->st_size = FSRoot->plainPath( &buf[0] ).length(); stbuf->st_size = FSRoot->plainPath(&buf[0]).length();
res = ESUCCESS; res = ESUCCESS;
} else } else
@ -193,234 +180,199 @@ int _do_getattr(FileNode *fnode, struct stat *stbuf)
return res; return res;
} }
int encfs_getattr(const char *path, struct stat *stbuf) int encfs_getattr(const char *path, struct stat *stbuf) {
{ return withFileNode("getattr", path, NULL, _do_getattr, stbuf);
return withFileNode( "getattr", path, NULL, _do_getattr, stbuf );
} }
int encfs_fgetattr(const char *path, struct stat *stbuf, int encfs_fgetattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi) struct fuse_file_info *fi) {
{ return withFileNode("fgetattr", path, fi, _do_getattr, stbuf);
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(); EncFS_Context *ctx = context();
int res = ESUCCESS; int res = ESUCCESS;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
try try {
{
DirTraverse dt = FSRoot->openDir( path ); DirTraverse dt = FSRoot->openDir(path);
VLOG(1) << "getdir on " << FSRoot->cipherPath(path); VLOG(1) << "getdir on " << FSRoot->cipherPath(path);
if(dt.valid()) if (dt.valid()) {
{
int fileType = 0; int fileType = 0;
ino_t inode = 0; ino_t inode = 0;
std::string name = dt.nextPlaintextName( &fileType, &inode ); std::string name = dt.nextPlaintextName(&fileType, &inode);
while( !name.empty() ) while (!name.empty()) {
{ res = filler(h, name.c_str(), fileType, inode);
res = filler( h, name.c_str(), fileType, inode );
if(res != ESUCCESS) if (res != ESUCCESS) break;
break;
name = dt.nextPlaintextName( &fileType, &inode ); name = dt.nextPlaintextName(&fileType, &inode);
} }
} else } else {
{
LOG(INFO) << "getdir request invalid, path: '" << path << "'"; LOG(INFO) << "getdir request invalid, path: '" << path << "'";
} }
return res; return res;
} catch( Error &err ) }
{ catch (Error &err) {
LOG(ERROR) << "error caught in getdir: " << err.what(); LOG(ERROR) << "error caught in getdir: " << err.what();
return -EIO; 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(); EncFS_Context *ctx = context();
int res = -EIO; int res = -EIO;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
try try {
{ shared_ptr<FileNode> fnode = FSRoot->lookupNode(path, "mknod");
shared_ptr<FileNode> fnode = FSRoot->lookupNode( path, "mknod" );
VLOG(1) << "mknod on " << fnode->cipherName() VLOG(1) << "mknod on " << fnode->cipherName() << ", mode " << mode
<< ", mode " << mode << ", dev " << rdev; << ", dev " << rdev;
uid_t uid = 0; uid_t uid = 0;
gid_t gid = 0; gid_t gid = 0;
if(ctx->publicFilesystem) if (ctx->publicFilesystem) {
{
fuse_context *context = fuse_get_context(); fuse_context *context = fuse_get_context();
uid = context->uid; uid = context->uid;
gid = context->gid; gid = context->gid;
} }
res = fnode->mknod( mode, rdev, uid, gid ); res = fnode->mknod(mode, rdev, uid, gid);
// Is this error due to access problems? // 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 // try again using the parent dir's group
string parent = fnode->plaintextParent(); string parent = fnode->plaintextParent();
LOG(INFO) << "attempting public filesystem workaround for " LOG(INFO) << "attempting public filesystem workaround for "
<< parent.c_str(); << parent.c_str();
shared_ptr<FileNode> dnode = shared_ptr<FileNode> dnode = FSRoot->lookupNode(parent.c_str(), "mknod");
FSRoot->lookupNode( parent.c_str(), "mknod" );
struct stat st; struct stat st;
if(dnode->getAttr( &st ) == 0) if (dnode->getAttr(&st) == 0)
res = fnode->mknod( mode, rdev, uid, st.st_gid ); res = fnode->mknod(mode, rdev, uid, st.st_gid);
} }
} catch( Error &err ) }
{ catch (Error &err) {
LOG(ERROR) << "error caught in mknod: " << err.what(); LOG(ERROR) << "error caught in mknod: " << err.what();
} }
return res; 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(); fuse_context *fctx = fuse_get_context();
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
int res = -EIO; int res = -EIO;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
try try {
{
uid_t uid = 0; uid_t uid = 0;
gid_t gid = 0; gid_t gid = 0;
if(ctx->publicFilesystem) if (ctx->publicFilesystem) {
{
uid = fctx->uid; uid = fctx->uid;
gid = fctx->gid; gid = fctx->gid;
} }
res = FSRoot->mkdir( path, mode, uid, gid ); res = FSRoot->mkdir(path, mode, uid, gid);
// Is this error due to access problems? // 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 // try again using the parent dir's group
string parent = parentDirectory( path ); string parent = parentDirectory(path);
shared_ptr<FileNode> dnode = shared_ptr<FileNode> dnode = FSRoot->lookupNode(parent.c_str(), "mkdir");
FSRoot->lookupNode( parent.c_str(), "mkdir" );
struct stat st; struct stat st;
if(dnode->getAttr( &st ) == 0) if (dnode->getAttr(&st) == 0)
res = FSRoot->mkdir( path, mode, uid, st.st_gid ); res = FSRoot->mkdir(path, mode, uid, st.st_gid);
} }
} catch( Error &err ) }
{ catch (Error &err) {
LOG(ERROR) << "error caught in mkdir: " << err.what(); LOG(ERROR) << "error caught in mkdir: " << err.what();
} }
return res; return res;
} }
int encfs_unlink(const char *path) int encfs_unlink(const char *path) {
{
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
int res = -EIO; int res = -EIO;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
try try {
{
// let DirNode handle it atomically so that it can handle race // let DirNode handle it atomically so that it can handle race
// conditions // conditions
res = FSRoot->unlink( path ); res = FSRoot->unlink(path);
} catch( Error &err ) }
{ catch (Error &err) {
LOG(ERROR) << "error caught in unlink: " << err.what(); LOG(ERROR) << "error caught in unlink: " << err.what();
} }
return res; return res;
} }
int _do_rmdir(EncFS_Context *, const string &cipherPath, int ) int _do_rmdir(EncFS_Context *, const string &cipherPath, int) {
{ return rmdir(cipherPath.c_str());
return rmdir( cipherPath.c_str() );
} }
int encfs_rmdir(const char *path) int encfs_rmdir(const char *path) {
{ return withCipherPath("rmdir", path, _do_rmdir, 0);
return withCipherPath( "rmdir", path, _do_rmdir, 0 );
} }
int _do_readlink(EncFS_Context *ctx, const string &cyName, int _do_readlink(EncFS_Context *ctx, const string &cyName,
tuple<char *, size_t> data ) tuple<char *, size_t> data) {
{
char *buf = get<0>(data); char *buf = get<0>(data);
size_t size = get<1>(data); size_t size = get<1>(data);
int res = ESUCCESS; int res = ESUCCESS;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
res = ::readlink( cyName.c_str(), buf, size-1 ); res = ::readlink(cyName.c_str(), buf, size - 1);
if(res == -1) if (res == -1) return -errno;
return -errno;
buf[res] = '\0'; // ensure null termination buf[res] = '\0'; // ensure null termination
string decodedName; string decodedName;
try try {
{ decodedName = FSRoot->plainPath(buf);
decodedName = FSRoot->plainPath( buf ); }
} catch(...) { } catch (...) {
}
if(!decodedName.empty()) if (!decodedName.empty()) {
{ strncpy(buf, decodedName.c_str(), size - 1);
strncpy(buf, decodedName.c_str(), size-1); buf[size - 1] = '\0';
buf[size-1] = '\0';
return ESUCCESS; return ESUCCESS;
} else } else {
{
LOG(WARNING) << "Error decoding link"; LOG(WARNING) << "Error decoding link";
return -1; return -1;
} }
} }
int encfs_readlink(const char *path, char *buf, size_t size) int encfs_readlink(const char *path, char *buf, size_t size) {
{ return withCipherPath("readlink", path, _do_readlink, make_tuple(buf, 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(); EncFS_Context *ctx = context();
int res = -EIO; int res = -EIO;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
try try {
{
// allow fully qualified names in symbolic links. // allow fully qualified names in symbolic links.
string fromCName = FSRoot->relativeCipherPath( from ); string fromCName = FSRoot->relativeCipherPath(from);
string toCName = FSRoot->cipherPath( to ); string toCName = FSRoot->cipherPath(to);
VLOG(1) << "symlink " << fromCName << " -> " << toCName; 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. // uid/gid provided by the fuse_context.
int olduid = -1; int olduid = -1;
int oldgid = -1; int oldgid = -1;
if(ctx->publicFilesystem) if (ctx->publicFilesystem) {
{
fuse_context *context = fuse_get_context(); fuse_context *context = fuse_get_context();
olduid = setfsuid( context->uid ); olduid = setfsuid(context->uid);
oldgid = setfsgid( context->gid ); oldgid = setfsgid(context->gid);
} }
res = ::symlink( fromCName.c_str(), toCName.c_str() ); res = ::symlink(fromCName.c_str(), toCName.c_str());
if(olduid >= 0) if (olduid >= 0) setfsuid(olduid);
setfsuid( olduid ); if (oldgid >= 0) setfsgid(oldgid);
if(oldgid >= 0)
setfsgid( oldgid );
if(res == -1) if (res == -1)
res = -errno; res = -errno;
else else
res = ESUCCESS; res = ESUCCESS;
} catch( Error &err ) }
{ catch (Error &err) {
LOG(ERROR) << "error caught in symlink: " << err.what(); LOG(ERROR) << "error caught in symlink: " << err.what();
} }
return res; return res;
} }
int encfs_link(const char *from, const char *to) int encfs_link(const char *from, const char *to) {
{
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
int res = -EIO; int res = -EIO;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
try try {
{ res = FSRoot->link(from, to);
res = FSRoot->link( from, to ); }
} catch( Error &err ) catch (Error &err) {
{
LOG(ERROR) << "error caught in link: " << err.what(); LOG(ERROR) << "error caught in link: " << err.what();
} }
return res; return res;
} }
int encfs_rename(const char *from, const char *to) int encfs_rename(const char *from, const char *to) {
{
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
int res = -EIO; int res = -EIO;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
try try {
{ res = FSRoot->rename(from, to);
res = FSRoot->rename( from, to ); }
} catch( Error &err ) catch (Error &err) {
{
LOG(ERROR) << "error caught in rename: " << err.what(); LOG(ERROR) << "error caught in rename: " << err.what();
} }
return res; 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 #ifdef HAVE_LCHMOD
return lchmod( cipherPath.c_str(), mode ); return lchmod(cipherPath.c_str(), mode);
#else #else
return chmod( cipherPath.c_str(), mode ); return chmod(cipherPath.c_str(), mode);
#endif #endif
} }
int encfs_chmod(const char *path, mode_t mode) int encfs_chmod(const char *path, mode_t mode) {
{ return withCipherPath("chmod", path, _do_chmod, mode);
return withCipherPath( "chmod", path, _do_chmod, mode );
} }
int _do_chown(EncFS_Context *, const string &cyName, int _do_chown(EncFS_Context *, const string &cyName, tuple<uid_t, gid_t> data) {
tuple<uid_t, gid_t> data) int res = lchown(cyName.c_str(), get<0>(data), get<1>(data));
{
int res = lchown( cyName.c_str(), get<0>(data), get<1>(data) );
return (res == -1) ? -errno : ESUCCESS; return (res == -1) ? -errno : ESUCCESS;
} }
int encfs_chown(const char *path, uid_t uid, gid_t gid) int encfs_chown(const char *path, uid_t uid, gid_t gid) {
{ return withCipherPath("chown", path, _do_chown, make_tuple(uid, gid));
return withCipherPath( "chown", path, _do_chown, make_tuple(uid, gid));
} }
int _do_truncate( FileNode *fnode, off_t size ) int _do_truncate(FileNode *fnode, off_t size) { return fnode->truncate(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) int encfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi) {
{ return withFileNode("ftruncate", path, fi, _do_truncate, size);
return withFileNode( "truncate", path, NULL, _do_truncate, size );
} }
int encfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi) int _do_utime(EncFS_Context *, const string &cyName, struct utimbuf *buf) {
{ int res = utime(cyName.c_str(), buf);
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; return (res == -1) ? -errno : ESUCCESS;
} }
int encfs_utime(const char *path, struct utimbuf *buf) int encfs_utime(const char *path, struct utimbuf *buf) {
{ return withCipherPath("utime", path, _do_utime, buf);
return withCipherPath( "utime", path, _do_utime, buf );
} }
int _do_utimens(EncFS_Context *, const string &cyName, int _do_utimens(EncFS_Context *, const string &cyName,
const struct timespec ts[2]) const struct timespec ts[2]) {
{
struct timeval tv[2]; struct timeval tv[2];
tv[0].tv_sec = ts[0].tv_sec; tv[0].tv_sec = ts[0].tv_sec;
tv[0].tv_usec = ts[0].tv_nsec / 1000; tv[0].tv_usec = ts[0].tv_nsec / 1000;
tv[1].tv_sec = ts[1].tv_sec; tv[1].tv_sec = ts[1].tv_sec;
tv[1].tv_usec = ts[1].tv_nsec / 1000; 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; return (res == -1) ? -errno : ESUCCESS;
} }
int encfs_utimens(const char *path, const struct timespec ts[2] ) int encfs_utimens(const char *path, const struct timespec ts[2]) {
{ return withCipherPath("utimens", path, _do_utimens, ts);
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(); EncFS_Context *ctx = context();
int res = -EIO; int res = -EIO;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
try try {
{ shared_ptr<FileNode> fnode =
shared_ptr<FileNode> fnode = FSRoot->openNode(path, "open", file->flags, &res);
FSRoot->openNode( path, "open", file->flags, &res );
if(fnode) if (fnode) {
{ VLOG(1) << "encfs_open for " << fnode->cipherName() << ", flags "
VLOG(1) << "encfs_open for " << fnode->cipherName() << file->flags;
<< ", flags " << file->flags;
if( res >= 0 ) if (res >= 0) {
{
file->fh = (uintptr_t)ctx->putNode(path, fnode); file->fh = (uintptr_t)ctx->putNode(path, fnode);
res = ESUCCESS; res = ESUCCESS;
} }
} }
} catch( Error &err ) }
{ catch (Error &err) {
LOG(ERROR) << "error caught in open: " << err.what(); LOG(ERROR) << "error caught in open: " << err.what();
} }
return res; 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 /* 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 close the file. However it is important to call close() for some
underlying filesystems (like NFS). underlying filesystems (like NFS).
*/ */
int res = fnode->open( O_RDONLY ); int res = fnode->open(O_RDONLY);
if(res >= 0) if (res >= 0) {
{
int fh = res; int fh = res;
res = close(dup(fh)); res = close(dup(fh));
if(res == -1) if (res == -1) res = -errno;
res = -errno;
} }
return res; return res;
} }
int encfs_flush(const char *path, struct fuse_file_info *fi) int encfs_flush(const char *path, struct fuse_file_info *fi) {
{ return withFileNode("flush", path, fi, _do_flush, 0);
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 bit after they are released just in case they are reopened soon. But that
requires a cache layer. 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(); EncFS_Context *ctx = context();
try try {
{ ctx->eraseNode(path, (void *)(uintptr_t)finfo->fh);
ctx->eraseNode( path, (void*)(uintptr_t)finfo->fh );
return ESUCCESS; return ESUCCESS;
} catch( Error &err ) }
{ catch (Error &err) {
LOG(ERROR) << "error caught in release: " << err.what(); LOG(ERROR) << "error caught in release: " << err.what();
return -EIO; return -EIO;
} }
} }
int _do_read(FileNode *fnode, tuple<unsigned char *, size_t, off_t> data) int _do_read(FileNode *fnode, tuple<unsigned char *, size_t, off_t> data) {
{ return fnode->read(get<2>(data), get<0>(data), get<1>(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, int encfs_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *file) struct fuse_file_info *file) {
{ return withFileNode("read", path, file, _do_read,
return withFileNode( "read", path, file, _do_read, make_tuple((unsigned char *)buf, size, offset));
make_tuple((unsigned char *)buf, size, offset));
} }
int _do_fsync(FileNode *fnode, int dataSync) int _do_fsync(FileNode *fnode, int dataSync) {
{ return fnode->sync(dataSync != 0);
return fnode->sync( dataSync != 0 );
} }
int encfs_fsync(const char *path, int dataSync, int encfs_fsync(const char *path, int dataSync, struct fuse_file_info *file) {
struct fuse_file_info *file) return withFileNode("fsync", path, file, _do_fsync, dataSync);
{
return withFileNode( "fsync", path, file, _do_fsync, dataSync );
} }
int _do_write(FileNode *fnode, tuple<const char *, size_t, off_t> data) int _do_write(FileNode *fnode, tuple<const char *, size_t, off_t> data) {
{
size_t size = get<1>(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; return size;
else else
return -EIO; return -EIO;
} }
int encfs_write(const char *path, const char *buf, size_t size, int encfs_write(const char *path, const char *buf, size_t size, off_t offset,
off_t offset, struct fuse_file_info *file) struct fuse_file_info *file) {
{
return withFileNode("write", path, file, _do_write, return withFileNode("write", path, file, _do_write,
make_tuple(buf, size, offset)); make_tuple(buf, size, offset));
} }
// statfs works even if encfs is detached.. // 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(); EncFS_Context *ctx = context();
int res = -EIO; int res = -EIO;
try try {
{ (void)path; // path should always be '/' for now..
(void)path; // path should always be '/' for now.. rAssert(st != NULL);
rAssert( st != NULL );
string cyName = ctx->rootCipherDir; string cyName = ctx->rootCipherDir;
VLOG(1) << "doing statfs of " << cyName; VLOG(1) << "doing statfs of " << cyName;
res = statvfs( cyName.c_str(), st ); res = statvfs(cyName.c_str(), st);
if(!res) if (!res) {
{
// adjust maximum name length.. // 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) if (res == -1) res = -errno;
res = -errno; }
} catch( Error &err ) catch (Error &err) {
{
LOG(ERROR) << "error caught in statfs: " << err.what(); LOG(ERROR) << "error caught in statfs: " << err.what();
} }
return res; return res;
@ -706,102 +613,87 @@ int encfs_statfs(const char *path, struct statvfs *st)
#ifdef XATTR_ADD_OPT #ifdef XATTR_ADD_OPT
int _do_setxattr(EncFS_Context *, const string &cyName, int _do_setxattr(EncFS_Context *, const string &cyName,
tuple<const char *, const char *, size_t, uint32_t> data) tuple<const char *, const char *, size_t, uint32_t> data) {
{
int options = XATTR_NOFOLLOW; int options = XATTR_NOFOLLOW;
return ::setxattr( cyName.c_str(), get<0>(data), get<1>(data), return ::setxattr(cyName.c_str(), get<0>(data), get<1>(data), get<2>(data),
get<2>(data), get<3>(data), options ); get<3>(data), options);
} }
int encfs_setxattr( const char *path, const char *name, int encfs_setxattr(const char *path, const char *name, const char *value,
const char *value, size_t size, int flags, uint32_t position ) size_t size, int flags, uint32_t position) {
{
(void)flags; (void)flags;
return withCipherPath( "setxattr", path, _do_setxattr, return withCipherPath("setxattr", path, _do_setxattr,
make_tuple(name, value, size, position) ); make_tuple(name, value, size, position));
} }
#else #else
int _do_setxattr(EncFS_Context *, const string &cyName, int _do_setxattr(EncFS_Context *, const string &cyName,
tuple<const char *, const char *, size_t, int> data) tuple<const char *, const char *, size_t, int> data) {
{ return ::setxattr(cyName.c_str(), get<0>(data), get<1>(data), get<2>(data),
return ::setxattr( cyName.c_str(), get<0>(data), get<1>(data), get<3>(data));
get<2>(data), get<3>(data) );
} }
int encfs_setxattr( const char *path, const char *name, int encfs_setxattr(const char *path, const char *name, const char *value,
const char *value, size_t size, int flags ) size_t size, int flags) {
{ return withCipherPath("setxattr", path, _do_setxattr,
return withCipherPath( "setxattr", path, _do_setxattr, make_tuple(name, value, size, flags));
make_tuple(name, value, size, flags) );
} }
#endif #endif
#ifdef XATTR_ADD_OPT #ifdef XATTR_ADD_OPT
int _do_getxattr(EncFS_Context *, const string &cyName, int _do_getxattr(EncFS_Context *, const string &cyName,
tuple<const char *, void *, size_t, uint32_t> data) tuple<const char *, void *, size_t, uint32_t> data) {
{
int options = 0; int options = 0;
return ::getxattr( cyName.c_str(), get<0>(data), return ::getxattr(cyName.c_str(), get<0>(data), get<1>(data), get<2>(data),
get<1>(data), get<2>(data), get<3>(data), options ); get<3>(data), options);
} }
int encfs_getxattr( const char *path, const char *name, int encfs_getxattr(const char *path, const char *name, char *value, size_t size,
char *value, size_t size, uint32_t position ) uint32_t position) {
{ return withCipherPath("getxattr", path, _do_getxattr,
return withCipherPath( "getxattr", path, _do_getxattr, make_tuple(name, (void *)value, size, position), true);
make_tuple(name, (void *)value, size, position), true );
} }
#else #else
int _do_getxattr(EncFS_Context *, const string &cyName, int _do_getxattr(EncFS_Context *, const string &cyName,
tuple<const char *, void *, size_t> data) tuple<const char *, void *, size_t> data) {
{ return ::getxattr(cyName.c_str(), get<0>(data), get<1>(data), get<2>(data));
return ::getxattr( cyName.c_str(), get<0>(data),
get<1>(data), get<2>(data));
} }
int encfs_getxattr( const char *path, const char *name, int encfs_getxattr(const char *path, const char *name, char *value,
char *value, size_t size ) size_t size) {
{ return withCipherPath("getxattr", path, _do_getxattr,
return withCipherPath( "getxattr", path, _do_getxattr, make_tuple(name, (void *)value, size), true);
make_tuple(name, (void *)value, size), true );
} }
#endif #endif
int _do_listxattr(EncFS_Context *, const string &cyName, int _do_listxattr(EncFS_Context *, const string &cyName,
tuple<char *, size_t> data) tuple<char *, size_t> data) {
{
#ifdef XATTR_ADD_OPT #ifdef XATTR_ADD_OPT
int options = 0; int options = 0;
int res = ::listxattr( cyName.c_str(), get<0>(data), get<1>(data), int res = ::listxattr(cyName.c_str(), get<0>(data), get<1>(data), options);
options );
#else #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 #endif
return (res == -1) ? -errno : res; return (res == -1) ? -errno : res;
} }
int encfs_listxattr( const char *path, char *list, size_t size ) int encfs_listxattr(const char *path, char *list, size_t size) {
{ return withCipherPath("listxattr", path, _do_listxattr,
return withCipherPath( "listxattr", path, _do_listxattr, make_tuple(list, size), true);
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 #ifdef XATTR_ADD_OPT
int options = 0; int options = 0;
int res = ::removexattr( cyName.c_str(), name, options ); int res = ::removexattr(cyName.c_str(), name, options);
#else #else
int res = ::removexattr( cyName.c_str(), name ); int res = ::removexattr(cyName.c_str(), name);
#endif #endif
return (res == -1) ? -errno : res; return (res == -1) ? -errno : res;
} }
int encfs_removexattr( const char *path, const char *name ) int encfs_removexattr(const char *path, const char *name) {
{ return withCipherPath("removexattr", path, _do_removexattr, name);
return withCipherPath( "removexattr", path, _do_removexattr, name );
} }
} // namespace encfs } // namespace encfs
#endif // HAVE_XATTR #endif // HAVE_XATTR

View File

@ -7,7 +7,7 @@
* 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 Lesser General Public License as published by the * 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 * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -32,36 +32,32 @@
#ifndef linux #ifndef linux
#include <cerrno> #include <cerrno>
static __inline int setfsuid(uid_t uid) static __inline int setfsuid(uid_t uid) {
{ uid_t olduid = geteuid();
uid_t olduid = geteuid();
seteuid(uid); seteuid(uid);
if (errno != EINVAL) if (errno != EINVAL) errno = 0;
errno = 0;
return olduid; return olduid;
} }
static __inline int setfsgid(gid_t gid) static __inline int setfsgid(gid_t gid) {
{ gid_t oldgid = getegid();
gid_t oldgid = getegid();
setegid(gid); setegid(gid);
if (errno != EINVAL) if (errno != EINVAL) errno = 0;
errno = 0;
return oldgid; return oldgid;
} }
#endif #endif
namespace encfs { namespace encfs {
int encfs_getattr(const char *path, struct stat *stbuf); int encfs_getattr(const char *path, struct stat *stbuf);
int encfs_fgetattr(const char *path, struct stat *stbuf, int encfs_fgetattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi); struct fuse_file_info *fi);
int encfs_readlink(const char *path, char *buf, size_t size); 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_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler);
int encfs_mknod(const char *path, mode_t mode, dev_t rdev); 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_chmod(const char *path, mode_t mode);
int encfs_chown(const char *path, uid_t uid, gid_t gid); int encfs_chown(const char *path, uid_t uid, gid_t gid);
int encfs_truncate(const char *path, off_t size); int encfs_truncate(const char *path, off_t size);
int encfs_ftruncate(const char *path, off_t size, int encfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi);
struct fuse_file_info *fi);
int encfs_utime(const char *path, struct utimbuf *buf); int encfs_utime(const char *path, struct utimbuf *buf);
int encfs_open(const char *path, struct fuse_file_info *info); int encfs_open(const char *path, struct fuse_file_info *info);
int encfs_release(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, 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, 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_statfs(const char *, struct statvfs *fst);
int encfs_flush(const char *, struct fuse_file_info *info); int encfs_flush(const char *, struct fuse_file_info *info);
int encfs_fsync(const char *path, int flags, struct fuse_file_info *info); int encfs_fsync(const char *path, int flags, struct fuse_file_info *info);
#ifdef HAVE_XATTR #ifdef HAVE_XATTR
# ifdef XATTR_ADD_OPT #ifdef XATTR_ADD_OPT
int encfs_setxattr( const char *path, const char *name, const char *value, int encfs_setxattr(const char *path, const char *name, const char *value,
size_t size, int flags, uint32_t position); size_t size, int flags, uint32_t position);
int encfs_getxattr( const char *path, const char *name, char *value, int encfs_getxattr(const char *path, const char *name, char *value, size_t size,
size_t size, uint32_t position ); uint32_t position);
# else #else
int encfs_setxattr( const char *path, const char *name, const char *value, int encfs_setxattr(const char *path, const char *name, const char *value,
size_t size, int flags); size_t size, int flags);
int encfs_getxattr( const char *path, const char *name, char *value, int encfs_getxattr(const char *path, const char *name, char *value,
size_t size ); size_t size);
# endif
int encfs_listxattr( const char *path, char *list, size_t size );
int encfs_removexattr( const char *path, const char *name );
#endif #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 } // namespace encfs
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it under * 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 * 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 * 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 * 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 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
@ -39,7 +39,7 @@ TEST(BlockFileIOTest, BasicIO) {
MemFileIO base(1024); MemFileIO base(1024);
ASSERT_EQ(1024, base.getSize()); ASSERT_EQ(1024, base.getSize());
FSConfigPtr cfg = makeConfig( CipherV1::New("Null"), 512); FSConfigPtr cfg = makeConfig(CipherV1::New("Null"), 512);
MemBlockFileIO block(512, cfg); MemBlockFileIO block(512, cfg);
block.truncate(1024); block.truncate(1024);
ASSERT_EQ(1024, block.getSize()); ASSERT_EQ(1024, block.getSize());
@ -56,7 +56,7 @@ TEST(BlockFileIOTest, BasicIO) {
req.offset = i * 256; req.offset = i * 256;
memset(req.data, 0, req.dataLen); memset(req.data, 0, req.dataLen);
ASSERT_TRUE(base.write(req)); ASSERT_TRUE(base.write(req));
req.offset = i * 256; req.offset = i * 256;
memset(req.data, 0, req.dataLen); memset(req.data, 0, req.dataLen);
ASSERT_TRUE(block.write(req)); ASSERT_TRUE(block.write(req));
@ -66,4 +66,3 @@ TEST(BlockFileIOTest, BasicIO) {
} }
} // namespace encfs } // namespace encfs

View File

@ -8,7 +8,7 @@
* This program is free software: you can redistribute it and/or modify it under * 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 * 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 * 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 * 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 * 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()); comparisonTest(cfg, test.get(), dup.get());
} }
TEST(IOTest, NullMacIO) { TEST(IOTest, NullMacIO) { runWithCipher("Null", 512, testMacIO); }
runWithCipher("Null", 512, testMacIO);
}
TEST(IOTest, MacIO) { TEST(IOTest, MacIO) { runWithAllCiphers(testMacIO); }
runWithAllCiphers(testMacIO);
}
void testBasicCipherIO(FSConfigPtr& cfg) { void testBasicCipherIO(FSConfigPtr& cfg) {
shared_ptr<MemFileIO> base(new MemFileIO(0)); shared_ptr<MemFileIO> base(new MemFileIO(0));
@ -97,16 +93,13 @@ void testBasicCipherIO(FSConfigPtr& cfg) {
for (unsigned int i = 0; i < sizeof(buf); ++i) { for (unsigned int i = 0; i < sizeof(buf); ++i) {
bool match = (buf[i] == req.data[i]); bool match = (buf[i] == req.data[i]);
ASSERT_TRUE(match) << "mismatched data at offset " << i; ASSERT_TRUE(match) << "mismatched data at offset " << i;
if (!match) if (!match) break;
break;
} }
delete[] req.data; delete[] req.data;
} }
TEST(IOTest, BasicCipherFileIO) { TEST(IOTest, BasicCipherFileIO) { runWithAllCiphers(testBasicCipherIO); }
runWithAllCiphers(testBasicCipherIO);
}
void testCipherIO(FSConfigPtr& cfg) { void testCipherIO(FSConfigPtr& cfg) {
shared_ptr<MemFileIO> base(new MemFileIO(0)); shared_ptr<MemFileIO> base(new MemFileIO(0));
@ -116,13 +109,8 @@ void testCipherIO(FSConfigPtr& cfg) {
comparisonTest(cfg, test.get(), dup.get()); comparisonTest(cfg, test.get(), dup.get());
} }
TEST(IOTest, NullCipherFileIO) { TEST(IOTest, NullCipherFileIO) { runWithCipher("Null", 512, testCipherIO); }
runWithCipher("Null", 512, testCipherIO);
}
TEST(IOTest, CipherFileIO) { TEST(IOTest, CipherFileIO) { runWithAllCiphers(testCipherIO); }
runWithAllCiphers(testCipherIO);
}
} // namespace } // namespace

View File

@ -8,7 +8,7 @@
* This program is free software: you can redistribute it and/or modify it under * 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 * 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 * 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 * 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 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
@ -19,7 +19,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "fs/testing.h" #include "fs/testing.h"
#include <list> #include <list>
@ -68,8 +67,9 @@ void runWithAllCiphers(void (*func)(FSConfigPtr& config)) {
for (it = algorithms.begin(); it != algorithms.end(); ++it) { for (it = algorithms.begin(); it != algorithms.end(); ++it) {
int blockSize = it->blockSize.closest(512); int blockSize = it->blockSize.closest(512);
int keyLength = it->keyLength.closest(128); int keyLength = it->keyLength.closest(128);
SCOPED_TRACE(testing::Message() << "Testng with cipher " << it->name SCOPED_TRACE(testing::Message() << "Testng with cipher " << it->name
<< ", blocksize " << blockSize << ", keyLength " << keyLength); << ", blocksize " << blockSize
<< ", keyLength " << keyLength);
shared_ptr<CipherV1> cipher = CipherV1::New(it->iface, keyLength); shared_ptr<CipherV1> cipher = CipherV1::New(it->iface, keyLength);
ASSERT_TRUE(cipher.get() != NULL); ASSERT_TRUE(cipher.get() != NULL);
@ -80,7 +80,7 @@ void runWithAllCiphers(void (*func)(FSConfigPtr& config)) {
void truncate(FileIO* a, FileIO* b, int len) { void truncate(FileIO* a, FileIO* b, int len) {
SCOPED_TRACE(testing::Message() << "Truncate from " << a->getSize() SCOPED_TRACE(testing::Message() << "Truncate from " << a->getSize()
<< " to len " << len); << " to len " << len);
a->truncate(len); a->truncate(len);
ASSERT_EQ(len, a->getSize()); 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) { if (b->getSize() < offset + len) {
b->truncate(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)); ASSERT_TRUE(cfg->cipher->pseudoRandomize(buf, len));
IORequest req; IORequest req;
@ -117,7 +117,7 @@ void writeRandom(FSConfigPtr& cfg, FileIO* a, FileIO* b, int offset, int len) {
req.dataLen = len; req.dataLen = len;
ASSERT_EQ(len, a->read(req)); ASSERT_EQ(len, a->read(req));
ASSERT_TRUE(memcmp(req.data, buf, len) == 0); ASSERT_TRUE(memcmp(req.data, buf, len) == 0);
memcpy(req.data, buf, len); memcpy(req.data, buf, len);
req.offset = offset; req.offset = offset;
req.dataLen = len; 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) { void compare(FileIO* a, FileIO* b, int offset, int len) {
SCOPED_TRACE(testing::Message() << "compare " << offset << ", " << len SCOPED_TRACE(testing::Message() << "compare " << offset << ", " << len
<< " from file length " << a->getSize()); << " from file length " << a->getSize());
unsigned char *buf1 = new unsigned char[len]; unsigned char* buf1 = new unsigned char[len];
unsigned char *buf2 = new unsigned char[len]; unsigned char* buf2 = new unsigned char[len];
memset(buf1, 0, len); memset(buf1, 0, len);
memset(buf2, 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); ssize_t size2 = b->read(req);
ASSERT_EQ(size1, size2); ASSERT_EQ(size1, size2);
for(int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
bool match = (buf1[i] == buf2[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]); << ", got " << int(buf1[i]) << " and " << int(buf2[i]);
if(!match) { if (!match) {
break; break;
} }
} }
@ -169,15 +169,14 @@ void compare(FileIO* a, FileIO* b, int offset, int len) {
} }
void comparisonTest(FSConfigPtr& cfg, FileIO* a, FileIO* b) { void comparisonTest(FSConfigPtr& cfg, FileIO* a, FileIO* b) {
const int size = 2*1024; const int size = 2 * 1024;
writeRandom(cfg, a, b, 0, size); writeRandom(cfg, a, b, 0, size);
if (testing::Test::HasFatalFailure()) return; if (testing::Test::HasFatalFailure()) return;
for (int i = 0; i < 10000; i++) { for (int i = 0; i < 10000; i++) {
SCOPED_TRACE(testing::Message() << "Test Loop " << i); SCOPED_TRACE(testing::Message() << "Test Loop " << i);
int len = 128 + random() % 512; int len = 128 + random() % 512;
int offset = (len == a->getSize()) ? 0 int offset = (len == a->getSize()) ? 0 : random() % (a->getSize() - len);
: random() % (a->getSize() - len);
writeRandom(cfg, a, b, offset, len); writeRandom(cfg, a, b, offset, len);
if (testing::Test::HasFatalFailure()) return; if (testing::Test::HasFatalFailure()) return;
ASSERT_EQ(a->getSize(), b->getSize()); ASSERT_EQ(a->getSize(), b->getSize());
@ -187,10 +186,9 @@ void comparisonTest(FSConfigPtr& cfg, FileIO* a, FileIO* b) {
compare(a, b, 0, a->getSize()); compare(a, b, 0, a->getSize());
} }
int main(int argc, char **argv) { int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv); ::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS(); return RUN_ALL_TESTS();
} }
} // namespace encfs } // namespace encfs

View File

@ -24,4 +24,3 @@ void compare(FileIO* a, FileIO* b, int offset, int len);
} // namespace encfs } // namespace encfs
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -4,10 +4,10 @@
***************************************************************************** *****************************************************************************
* Copyright (c) 2008, Valient Gough * 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 * under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * 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 * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -29,36 +29,32 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
void genKey( const shared_ptr<Cipher> &cipher ) void genKey(const shared_ptr<Cipher> &cipher) {
{ CipherKey key = cipher->newRandomKey();
CipherKey key = cipher->newRandomKey();
// encode with itself // encode with itself
string b64Key = cipher->encodeAsString( key, key ); string b64Key = cipher->encodeAsString(key, key);
cout << b64Key << "\n"; cout << b64Key << "\n";
} }
int main(int argc, char **argv) int main(int argc, char **argv) {
{ pid_t pid = getpid();
pid_t pid = getpid(); cerr << "pid = " << pid << "\n";
cerr << "pid = " << pid << "\n";
if(argc != 3) if (argc != 3) {
{ cerr << "usage: makeKey [AES|Blowfish] [128|160|192|224|256]\n";
cerr << "usage: makeKey [AES|Blowfish] [128|160|192|224|256]\n"; return 1;
return 1; }
}
const char *type = argv[1]; const char *type = argv[1];
int size = atoi(argv[2]); int size = atoi(argv[2]);
openssl_init(false); openssl_init(false);
// get a list of the available algorithms // get a list of the available algorithms
shared_ptr<Cipher> cipher = Cipher::New( type, size ); shared_ptr<Cipher> cipher = Cipher::New(type, size);
genKey( cipher ); genKey(cipher);
//openssl_shutdown(false);
}
// openssl_shutdown(false);
}