mirror of
https://github.com/vgough/encfs.git
synced 2024-11-25 17:33:19 +01:00
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:
parent
154ce001a1
commit
a89752dfe7
@ -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
|
||||||
|
@ -45,9 +45,8 @@ namespace encfs {
|
|||||||
ConfigReader cfg;
|
ConfigReader cfg;
|
||||||
cfg["cipher"] << cipher->interface();
|
cfg["cipher"] << cipher->interface();
|
||||||
*/
|
*/
|
||||||
class ConfigReader
|
class ConfigReader {
|
||||||
{
|
public:
|
||||||
public:
|
|
||||||
ConfigReader();
|
ConfigReader();
|
||||||
~ConfigReader();
|
~ConfigReader();
|
||||||
|
|
||||||
@ -55,16 +54,15 @@ public:
|
|||||||
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
|
||||||
|
@ -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
|
||||||
@ -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);
|
||||||
|
@ -27,23 +27,21 @@
|
|||||||
|
|
||||||
namespace encfs {
|
namespace encfs {
|
||||||
|
|
||||||
class ConfigVar
|
class ConfigVar {
|
||||||
{
|
struct ConfigVarData {
|
||||||
struct ConfigVarData
|
|
||||||
{
|
|
||||||
std::string buffer;
|
std::string buffer;
|
||||||
int offset;
|
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();
|
||||||
@ -55,10 +53,10 @@ public:
|
|||||||
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);
|
||||||
|
|
||||||
@ -72,15 +70,14 @@ public:
|
|||||||
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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
15
base/Error.h
15
base/Error.h
@ -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
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
54
base/Mutex.h
54
base/Mutex.h
@ -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
|
||||||
|
|
||||||
|
64
base/Range.h
64
base/Range.h
@ -25,12 +25,12 @@
|
|||||||
|
|
||||||
namespace encfs {
|
namespace encfs {
|
||||||
|
|
||||||
class Range
|
class Range {
|
||||||
{
|
|
||||||
int minVal;
|
int minVal;
|
||||||
int maxVal;
|
int maxVal;
|
||||||
int increment;
|
int increment;
|
||||||
public:
|
|
||||||
|
public:
|
||||||
Range();
|
Range();
|
||||||
Range(int minMax);
|
Range(int minMax);
|
||||||
Range(int min, int max, int increment);
|
Range(int min, int max, int increment);
|
||||||
@ -44,7 +44,7 @@ public:
|
|||||||
int inc() 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,51 +56,36 @@ 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)
|
if (increment == 0) this->increment = 1;
|
||||||
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;
|
int tmp = value - minVal;
|
||||||
if((tmp % increment) == 0)
|
if ((tmp % increment) == 0) return true;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int Range::closest(int value) const
|
inline int Range::closest(int value) const {
|
||||||
{
|
if (allowed(value))
|
||||||
if(allowed(value))
|
|
||||||
return value;
|
return value;
|
||||||
else
|
else if (value < minVal)
|
||||||
if(value < minVal)
|
|
||||||
return minVal;
|
return minVal;
|
||||||
else
|
else if (value > maxVal)
|
||||||
if(value > maxVal)
|
|
||||||
return maxVal;
|
return maxVal;
|
||||||
|
|
||||||
// must be inbetween but not matched with increment
|
// must be inbetween but not matched with increment
|
||||||
@ -109,23 +94,14 @@ inline int Range::closest(int value) const
|
|||||||
tmp += (increment >> 1);
|
tmp += (increment >> 1);
|
||||||
tmp -= (tmp % increment);
|
tmp -= (tmp % increment);
|
||||||
|
|
||||||
return closest( value + tmp );
|
return closest(value + tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int Range::min() const
|
inline int Range::min() const { return minVal; }
|
||||||
{
|
|
||||||
return minVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int Range::max() const
|
inline int Range::max() const { return maxVal; }
|
||||||
{
|
|
||||||
return maxVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int Range::inc() const
|
inline int Range::inc() const { return increment; }
|
||||||
{
|
|
||||||
return increment;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace encfs
|
} // namespace encfs
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,9 +8,8 @@
|
|||||||
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;
|
||||||
@ -18,24 +17,20 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
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,8 +49,7 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,38 +63,31 @@ 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
|
||||||
|
|
||||||
|
@ -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());
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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)
|
if (vasprintf(&str, format, args) < 0) str = NULL;
|
||||||
str = NULL;
|
va_end(args);
|
||||||
va_end (args);
|
}
|
||||||
}
|
|
||||||
|
/* Copy constructor. Necessary because the destructor is nontrivial. */
|
||||||
/* Copy constructor. Necessary because the destructor is nontrivial. */
|
autosprintf::autosprintf(const autosprintf &src) {
|
||||||
autosprintf::autosprintf (const autosprintf& src)
|
str = (src.str != NULL ? strdup(src.str) : NULL);
|
||||||
{
|
}
|
||||||
str = (src.str != NULL ? strdup (src.str) : NULL);
|
|
||||||
}
|
/* Destructor: frees the temporarily allocated string. */
|
||||||
|
autosprintf::~autosprintf() { free(str); }
|
||||||
/* Destructor: frees the temporarily allocated string. */
|
|
||||||
autosprintf::~autosprintf ()
|
/* Conversion to string. */
|
||||||
{
|
autosprintf::operator char *() const {
|
||||||
free (str);
|
if (str != NULL) {
|
||||||
}
|
size_t length = strlen(str) + 1;
|
||||||
|
char *copy = new char[length];
|
||||||
/* Conversion to string. */
|
memcpy(copy, str, length);
|
||||||
autosprintf::operator char * () const
|
return copy;
|
||||||
{
|
} else
|
||||||
if (str != NULL)
|
return NULL;
|
||||||
{
|
}
|
||||||
size_t length = strlen (str) + 1;
|
autosprintf::operator std::string() const {
|
||||||
char *copy = new char[length];
|
return std::string(str ? str : "(error in autosprintf)");
|
||||||
memcpy (copy, str, length);
|
}
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
autosprintf::operator std::string () const
|
|
||||||
{
|
|
||||||
return std::string (str ? str : "(error in autosprintf)");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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:
|
public:
|
||||||
/* Constructor: takes a format string and the printf arguments. */
|
/* Constructor: takes a format string and the printf arguments. */
|
||||||
autosprintf (const char *format, ...)
|
autosprintf(const char* format, ...)
|
||||||
__attribute__ ((__format__ (__printf__, 2, 3)));
|
__attribute__((__format__(__printf__, 2, 3)));
|
||||||
/* Copy constructor. */
|
/* Copy constructor. */
|
||||||
autosprintf (const autosprintf& src);
|
autosprintf(const autosprintf& src);
|
||||||
/* Destructor: frees the temporarily allocated string. */
|
/* Destructor: frees the temporarily allocated string. */
|
||||||
~autosprintf ();
|
~autosprintf();
|
||||||
/* Conversion to string. */
|
/* Conversion to string. */
|
||||||
operator char * () const;
|
operator char*() const;
|
||||||
operator std::string () const;
|
operator std::string() const;
|
||||||
/* Output to an ostream. */
|
/* Output to an ostream. */
|
||||||
friend inline std::ostream& operator<< (std::ostream& stream, const autosprintf& tmp)
|
friend inline std::ostream& operator<<(std::ostream& stream,
|
||||||
{
|
const autosprintf& tmp) {
|
||||||
stream << (tmp.str ? tmp.str : "(error in autosprintf)");
|
stream << (tmp.str ? tmp.str : "(error in autosprintf)");
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char *str;
|
char* str;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _AUTOSPRINTF_H */
|
#endif /* _AUTOSPRINTF_H */
|
||||||
|
146
base/base64.cpp
146
base/base64.cpp
@ -29,24 +29,21 @@ 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;
|
||||||
@ -54,8 +51,7 @@ void changeBase2(byte *src, int srcLen, int src2Pow,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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,22 +61,15 @@ 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;
|
||||||
@ -91,22 +80,18 @@ void changeBase2Inline(byte *src, int srcLen,
|
|||||||
work >>= dst2Pow;
|
work >>= dst2Pow;
|
||||||
workBits -= dst2Pow;
|
workBits -= dst2Pow;
|
||||||
|
|
||||||
if(srcLen)
|
if (srcLen) {
|
||||||
{
|
|
||||||
// more input left, so recurse
|
// more input left, so recurse
|
||||||
changeBase2Inline( src, srcLen, src2Pow, dst2Pow,
|
changeBase2Inline(src, srcLen, src2Pow, dst2Pow, outputPartialLastByte,
|
||||||
outputPartialLastByte, work, workBits, outLoc+1);
|
work, workBits, outLoc + 1);
|
||||||
*outLoc = outVal;
|
*outLoc = outVal;
|
||||||
} else
|
} else {
|
||||||
{
|
|
||||||
// no input left, we can write remaining values directly
|
// no input left, we can write remaining values directly
|
||||||
*outLoc++ = outVal;
|
*outLoc++ = outVal;
|
||||||
|
|
||||||
// we could have a partial value left in the work buffer..
|
// we could have a partial value left in the work buffer..
|
||||||
if(outputPartialLastByte)
|
if (outputPartialLastByte) {
|
||||||
{
|
while (workBits > 0) {
|
||||||
while(workBits > 0)
|
|
||||||
{
|
|
||||||
*outLoc++ = work & mask;
|
*outLoc++ = work & mask;
|
||||||
work >>= dst2Pow;
|
work >>= dst2Pow;
|
||||||
workBits -= dst2Pow;
|
workBits -= dst2Pow;
|
||||||
@ -115,15 +100,12 @@ void changeBase2Inline(byte *src, int srcLen,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,19 +113,16 @@ 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;
|
||||||
}
|
}
|
||||||
@ -151,36 +130,27 @@ void B64ToAscii(byte *in, int length)
|
|||||||
|
|
||||||
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,28 +176,19 @@ 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,
|
||||||
54,55,56,57,58,59,60,61,66,66, // 50-59
|
66, 66, 66, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // 100-109
|
||||||
66,65,66,66,66, 0, 1, 2, 3, 4,
|
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51};
|
||||||
5, 6, 7, 8, 9,10,11,12,13,14,
|
|
||||||
15,16,17,18,19,20,21,22,23,24,
|
|
||||||
25,66,66,66,66,66,66,26,27,28,
|
|
||||||
|
|
||||||
29,30,31,32,33,34,35,36,37,38, // 100-109
|
|
||||||
39,40,41,42,43,44,45,46,47,48,
|
|
||||||
49,50,51
|
|
||||||
};
|
|
||||||
|
|
||||||
bool B64StandardDecode(byte *out, const byte *in, int inLen) {
|
bool B64StandardDecode(byte *out, const byte *in, int inLen) {
|
||||||
const byte *end = in + inLen;
|
const byte *end = in + inLen;
|
||||||
@ -247,7 +203,8 @@ 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:
|
||||||
|
continue; /* skip whitespace */
|
||||||
case INVALID:
|
case INVALID:
|
||||||
LOG(ERROR) << "Invalid character: " << (unsigned int)v;
|
LOG(ERROR) << "Invalid character: " << (unsigned int)v;
|
||||||
return false; /* invalid input, return error */
|
return false; /* invalid input, return error */
|
||||||
@ -270,8 +227,7 @@ bool B64StandardDecode(byte *out, const byte *in, int inLen) {
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,41 +25,34 @@
|
|||||||
|
|
||||||
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);
|
||||||
// inplace translation from values [0,2^5] => base32 ASCII
|
// inplace translation from values [0,2^5] => base32 ASCII
|
||||||
@ -80,4 +73,3 @@ bool B64StandardDecode(byte *out, const byte *in, int inputLen);
|
|||||||
} // namespace encfs
|
} // namespace encfs
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
177
base/gettext.h
177
base/gettext.h
@ -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
|
||||||
@ -171,16 +170,16 @@ npgettext_aux (const char *domain,
|
|||||||
|
|
||||||
#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,33 +228,28 @@ __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;
|
||||||
|
16
base/i18n.h
16
base/i18n.h
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
namespace encfs {
|
namespace encfs {
|
||||||
|
|
||||||
typedef unsigned char byte;
|
typedef unsigned char byte;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // TYPES_H
|
#endif // TYPES_H
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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,7 +24,7 @@ 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
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -64,10 +64,7 @@ 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,96 +88,80 @@ 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.
|
||||||
@ -190,19 +171,18 @@ int CipherV1::TimedPBKDF2(const char *pass, int passlen,
|
|||||||
// - 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();
|
||||||
|
|
||||||
@ -237,10 +217,9 @@ list<CipherV1::CipherAlgorithm> CipherV1::GetAlgorithmList()
|
|||||||
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;
|
||||||
|
|
||||||
@ -272,19 +247,18 @@ bool CipherV1::initCiphers(const Interface &iface, const Interface &realIface,
|
|||||||
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,19 +348,16 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,17 +365,16 @@ 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,10 +383,9 @@ 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()];
|
||||||
|
|
||||||
@ -437,13 +393,11 @@ uint64_t CipherV1::MAC_64(const byte *data, int len,
|
|||||||
|
|
||||||
_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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
@ -92,9 +91,7 @@ class CipherV1
|
|||||||
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
|
||||||
@ -145,7 +141,6 @@ class CipherV1
|
|||||||
// 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;
|
||||||
int encodedKeySize() const;
|
int encodedKeySize() 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
|
||||||
|
|
||||||
|
@ -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";
|
||||||
@ -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,9 +134,8 @@ 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);
|
||||||
@ -147,9 +144,8 @@ class CCCipher : public BlockCipher {
|
|||||||
|
|
||||||
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);
|
||||||
@ -185,12 +179,10 @@ class AesCbc : public CCCipher {
|
|||||||
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);
|
||||||
@ -224,7 +216,7 @@ class AesCfb : 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,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
|
||||||
|
@ -30,6 +30,4 @@ struct CommonCrypto {
|
|||||||
|
|
||||||
} // namespace encfs
|
} // namespace encfs
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
17
cipher/MAC.h
17
cipher/MAC.h
@ -12,8 +12,7 @@ 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);
|
||||||
|
|
||||||
@ -23,22 +22,20 @@ class MAC
|
|||||||
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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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,75 +76,58 @@ 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_);
|
||||||
|
|
||||||
@ -156,10 +137,8 @@ SecureMem::~SecureMem()
|
|||||||
}
|
}
|
||||||
#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
|
||||||
|
|
||||||
|
@ -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,8 +45,7 @@ namespace encfs {
|
|||||||
|
|
||||||
// memblock freed when destructed
|
// memblock freed when destructed
|
||||||
*/
|
*/
|
||||||
struct MemBlock
|
struct MemBlock {
|
||||||
{
|
|
||||||
byte *data;
|
byte *data;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
@ -55,15 +55,11 @@ struct 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
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,4 +64,3 @@ void NullCiphers::registerCiphers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace encfs
|
} // namespace encfs
|
||||||
|
|
||||||
|
@ -34,4 +34,3 @@ class NullCiphers {
|
|||||||
} // namespace encfs
|
} // namespace encfs
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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,15 +29,15 @@ 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
|
||||||
|
@ -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,16 +33,14 @@ 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));
|
||||||
}
|
}
|
||||||
@ -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,21 +65,20 @@ 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(
|
||||||
|
"120fb6cffcf8b32c"
|
||||||
"43e7225256c4f837"
|
"43e7225256c4f837"
|
||||||
"a86548c92ccc3548"
|
"a86548c92ccc3548"
|
||||||
"0805987cb70be17b", stringToHex(key));
|
"0805987cb70be17b",
|
||||||
|
stringToHex(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test case 2
|
// Test case 2
|
||||||
@ -94,7 +88,8 @@ TEST(PKCS5_PBKDF2_HMAC_SHA256, PBKDF) {
|
|||||||
(byte*)"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36,
|
(byte*)"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36,
|
||||||
4096, &key);
|
4096, &key);
|
||||||
ASSERT_TRUE(ok);
|
ASSERT_TRUE(ok);
|
||||||
ASSERT_EQ("348c89dbcbd32b2f"
|
ASSERT_EQ(
|
||||||
|
"348c89dbcbd32b2f"
|
||||||
"32d814b8116e84cf"
|
"32d814b8116e84cf"
|
||||||
"2b17347ebc180018"
|
"2b17347ebc180018"
|
||||||
"1c4e2a1fb8dd53e1"
|
"1c4e2a1fb8dd53e1"
|
||||||
@ -105,13 +100,10 @@ TEST(PKCS5_PBKDF2_HMAC_SHA256, PBKDF) {
|
|||||||
// 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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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,9 +66,7 @@ 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,
|
|
||||||
salt, saltLength,
|
|
||||||
numIterations);
|
numIterations);
|
||||||
memcpy(outKey->data(), key.begin(), outKey->size());
|
memcpy(outKey->data(), key.begin(), outKey->size());
|
||||||
return true;
|
return true;
|
||||||
@ -83,7 +78,7 @@ 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;
|
||||||
}
|
}
|
||||||
@ -93,8 +88,7 @@ class PbkdfPkcs5Hmac : public PBKDF {
|
|||||||
|
|
||||||
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() {
|
||||||
@ -108,8 +102,7 @@ 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() {
|
||||||
@ -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() {}
|
||||||
@ -157,8 +150,8 @@ class BotanBlockCipher : public BlockCipher {
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,8 +168,8 @@ class BotanBlockCipher : public BlockCipher {
|
|||||||
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
|
||||||
|
|
||||||
|
@ -33,4 +33,3 @@ extern void Botan_registerCiphers();
|
|||||||
} // namespace encfs
|
} // namespace encfs
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -64,48 +64,43 @@ 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;
|
||||||
}
|
}
|
||||||
@ -121,13 +116,12 @@ class OpenSSLCipher : public BlockCipher {
|
|||||||
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,25 +252,26 @@ 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,17 +294,19 @@ 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,12 +362,8 @@ 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.
|
||||||
@ -384,9 +374,7 @@ 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);
|
||||||
@ -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,
|
|
||||||
numIterations, EVP_sha256(),
|
|
||||||
outKey->size(), outKey->data()) == 1;
|
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,56 +474,45 @@ 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 */
|
||||||
@ -551,27 +521,23 @@ void OpenSSL::init(bool threaded)
|
|||||||
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.
|
||||||
}
|
}
|
||||||
|
@ -36,5 +36,3 @@ class OpenSSL {
|
|||||||
} // namespace encfs
|
} // namespace encfs
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -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,23 +52,21 @@ 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;
|
ssize_t nr;
|
||||||
int input, output, save_errno;
|
int input, output, save_errno;
|
||||||
char ch, *p, *end;
|
char ch, *p, *end;
|
||||||
@ -77,7 +77,7 @@ readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
|
|||||||
/* 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:
|
||||||
@ -88,7 +88,7 @@ restart:
|
|||||||
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;
|
||||||
@ -113,8 +113,7 @@ restart:
|
|||||||
/* 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;
|
||||||
@ -129,21 +128,17 @@ restart:
|
|||||||
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))
|
if ((flags & RPP_FORCELOWER)) ch = tolower(ch);
|
||||||
ch = tolower(ch);
|
if ((flags & RPP_FORCEUPPER)) ch = toupper(ch);
|
||||||
if ((flags & RPP_FORCEUPPER))
|
|
||||||
ch = toupper(ch);
|
|
||||||
}
|
}
|
||||||
*p++ = ch;
|
*p++ = ch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
save_errno = errno;
|
save_errno = errno;
|
||||||
if (!(term.c_lflag & ECHO))
|
if (!(term.c_lflag & ECHO)) (void)write(output, "\n", 1);
|
||||||
(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)
|
||||||
@ -155,8 +150,7 @@ restart:
|
|||||||
(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
|
||||||
@ -174,7 +168,7 @@ restart:
|
|||||||
}
|
}
|
||||||
|
|
||||||
errno = save_errno;
|
errno = save_errno;
|
||||||
return(nr == -1 ? NULL : buf);
|
return (nr == -1 ? NULL : buf);
|
||||||
}
|
}
|
||||||
#endif /* HAVE_READPASSPHRASE */
|
#endif /* HAVE_READPASSPHRASE */
|
||||||
|
|
||||||
@ -188,8 +182,4 @@ getpass(const char *prompt)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void handler(int s)
|
static void handler(int s) { signo = s; }
|
||||||
{
|
|
||||||
|
|
||||||
signo = s;
|
|
||||||
}
|
|
||||||
|
@ -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>
|
||||||
@ -45,7 +46,9 @@
|
|||||||
#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 */
|
||||||
|
|
||||||
|
@ -64,4 +64,3 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace encfs
|
} // namespace encfs
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
387
encfs/main.cpp
387
encfs/main.cpp
@ -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,8 +69,7 @@ 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
|
||||||
@ -88,62 +84,63 @@ 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 Mount Options]]"), name) << "\n\n"
|
<< autosprintf(_("Usage: %s [options] rootDir mountPoint [-- [FUSE "
|
||||||
|
"Mount Options]]"),
|
||||||
|
name) << "\n\n"
|
||||||
// xgroup(usage)
|
// xgroup(usage)
|
||||||
<< _("Common Options:\n"
|
<< _("Common Options:\n"
|
||||||
" -H\t\t\t" "show optional FUSE Mount Options\n"
|
" -H\t\t\t"
|
||||||
" -s\t\t\t" "disable multithreaded operation\n"
|
"show optional FUSE Mount Options\n"
|
||||||
" -f\t\t\t" "run in foreground (don't spawn daemon).\n"
|
" -s\t\t\t"
|
||||||
|
"disable multithreaded operation\n"
|
||||||
|
" -f\t\t\t"
|
||||||
|
"run in foreground (don't spawn daemon).\n"
|
||||||
"\t\t\tError messages will be sent to stderr\n"
|
"\t\t\tError messages will be sent to stderr\n"
|
||||||
"\t\t\tinstead of syslog.\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"
|
||||||
|
" --anykey\t\t"
|
||||||
|
"Do not verify correct key is being used\n"
|
||||||
|
" --forcedecode\t\t"
|
||||||
|
"decode data even if an error is detected\n"
|
||||||
"\t\t\t(for filesystems using MAC block headers)\n")
|
"\t\t\t(for filesystems using MAC block headers)\n")
|
||||||
<< _(" --public\t\t" "act as a typical multi-user filesystem\n"
|
<< _(" --public\t\t"
|
||||||
"\t\t\t(encfs must be run as root)\n")
|
"act as a typical multi-user filesystem\n"
|
||||||
<< _(" --reverse\t\t" "reverse encryption\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"
|
||||||
@ -152,39 +149,33 @@ void usage(const char *name)
|
|||||||
" 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) \
|
||||||
|
do { \
|
||||||
rAssert(out->fuseArgc < MaxFuseArgs); \
|
rAssert(out->fuseArgc < MaxFuseArgs); \
|
||||||
out->fuseArgv[out->fuseArgc++] = (ARG); } \
|
out->fuseArgv[out->fuseArgc++] = (ARG); \
|
||||||
while(0)
|
} 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;
|
||||||
@ -227,15 +218,13 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
|
|||||||
{"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,14 +235,12 @@ 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;
|
||||||
@ -281,7 +268,7 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
|
|||||||
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':
|
||||||
@ -304,16 +291,15 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
|
|||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
PUSHARG("-o");
|
PUSHARG("-o");
|
||||||
PUSHARG( optarg );
|
PUSHARG(optarg);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
out->opts->passwordProgram.assign( optarg );
|
out->opts->passwordProgram.assign(optarg);
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
if(geteuid() != 0)
|
if (geteuid() != 0)
|
||||||
LOG(WARNING) << "option '--public' ignored for non-root user";
|
LOG(WARNING) << "option '--public' ignored for non-root user";
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
out->opts->ownerCreate = true;
|
out->opts->ownerCreate = true;
|
||||||
// add 'allow_other' option
|
// add 'allow_other' option
|
||||||
// add 'default_permissions' option (default)
|
// add 'default_permissions' option (default)
|
||||||
@ -342,11 +328,9 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,27 +360,21 @@ 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 <<
|
cerr <<
|
||||||
// xgroup(usage)
|
// xgroup(usage)
|
||||||
_("When specifying daemon mode, you must use absolute paths "
|
_("When specifying daemon mode, you must use absolute paths "
|
||||||
"(beginning with '/')")
|
"(beginning with '/')") << endl;
|
||||||
<< 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 "
|
||||||
@ -409,36 +383,30 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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")
|
_("Must set password program when using mount-on-demand") << endl;
|
||||||
<< 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,63 +417,55 @@ 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"
|
||||||
@ -523,25 +483,23 @@ int main(int argc, char *argv[])
|
|||||||
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();
|
||||||
@ -579,55 +537,53 @@ int main(int argc, char *argv[])
|
|||||||
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"
|
||||||
@ -637,71 +593,65 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
// 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( ¤tTime, 0 );
|
gettimeofday(¤tTime, 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,48 +30,38 @@
|
|||||||
|
|
||||||
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;
|
||||||
@ -79,47 +69,41 @@ ssize_t BlockFileIO::cacheReadOneBlock( const IORequest &req ) const
|
|||||||
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
|
||||||
@ -130,31 +114,27 @@ ssize_t BlockFileIO::read( const IORequest &req ) const
|
|||||||
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,28 +163,24 @@ 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)..
|
||||||
@ -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,32 +253,28 @@ 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
|
||||||
@ -326,42 +285,37 @@ void BlockFileIO::padFile( off_t oldSize, off_t newSize, bool forceWrite )
|
|||||||
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,58 +323,48 @@ 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....
|
// the easiest case, but least likely....
|
||||||
} else
|
} else if (partialBlock) {
|
||||||
if( partialBlock )
|
|
||||||
{
|
|
||||||
// partial block after truncate. Need to read in the block being
|
// partial block after truncate. Need to read in the block being
|
||||||
// truncated before the truncate. Then write it back out afterwards,
|
// truncated before the truncate. Then write it back out afterwards,
|
||||||
// since the encoding will change..
|
// since the encoding will change..
|
||||||
off_t blockNum = size / _blockSize;
|
off_t blockNum = size / _blockSize;
|
||||||
MemBlock mb;
|
MemBlock mb;
|
||||||
mb.allocate( _blockSize );
|
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)
|
if (base) res = base->truncate(size);
|
||||||
res = base->truncate( size );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
@ -34,30 +34,28 @@ namespace encfs {
|
|||||||
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);
|
||||||
int blockTruncate( off_t size, FileIO *base );
|
void padFile(off_t oldSize, off_t newSize, bool forceWrite);
|
||||||
void padFile( off_t oldSize, off_t newSize, bool forceWrite );
|
|
||||||
|
|
||||||
// same as read(), except that the request.offset field is guarenteed to be
|
// same as read(), except that the request.offset field is guarenteed to be
|
||||||
// block aligned, and the request size will not be larger then 1 block.
|
// block aligned, and the request size will not be larger then 1 block.
|
||||||
virtual ssize_t readOneBlock( const IORequest &req ) const =0;
|
virtual ssize_t readOneBlock(const IORequest &req) const = 0;
|
||||||
virtual bool writeOneBlock( const IORequest &req ) =0;
|
virtual bool writeOneBlock(const IORequest &req) = 0;
|
||||||
|
|
||||||
ssize_t cacheReadOneBlock( const IORequest &req ) const;
|
ssize_t cacheReadOneBlock(const IORequest &req) const;
|
||||||
bool cacheWriteOneBlock( const IORequest &req );
|
bool cacheWriteOneBlock(const IORequest &req);
|
||||||
|
|
||||||
int _blockSize;
|
int _blockSize;
|
||||||
bool _allowHoles;
|
bool _allowHoles;
|
||||||
@ -69,4 +67,3 @@ protected:
|
|||||||
} // namespace encfs
|
} // namespace encfs
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -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 ) :
|
|
||||||
B64ToB256Bytes( encodedNameLen );
|
|
||||||
return decLen256 - 2; // 2 checksum bytes removed..
|
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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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 )
|
if (res >= 0) lastFlags = flags;
|
||||||
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 );
|
cipher->streamEncode(mb.data, sizeof(uint64_t), externalIV);
|
||||||
|
|
||||||
if( base->isWritable() )
|
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
|
||||||
|
@ -36,45 +36,39 @@ class CipherV1;
|
|||||||
|
|
||||||
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,
|
|
||||||
const FSConfigPtr &cfg);
|
|
||||||
virtual ~CipherFileIO();
|
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;
|
||||||
|
|
||||||
|
106
fs/Context.cpp
106
fs/Context.cpp
@ -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;
|
||||||
|
13
fs/Context.h
13
fs/Context.h
@ -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
|
||||||
|
|
||||||
|
590
fs/DirNode.cpp
590
fs/DirNode.cpp
@ -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,60 +87,48 @@ 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)
|
||||||
@ -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,19 +206,17 @@ 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
|
||||||
}
|
}
|
||||||
@ -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,30 +578,24 @@ 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 );
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
// rename error! - put it back
|
// 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,44 +638,39 @@ 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);
|
||||||
}
|
}
|
||||||
@ -815,4 +680,3 @@ int DirNode::unlink( const char *plaintextName )
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace encfs
|
} // namespace encfs
|
||||||
|
|
||||||
|
70
fs/DirNode.h
70
fs/DirNode.h
@ -44,15 +44,14 @@ 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)
|
||||||
@ -61,14 +60,14 @@ public:
|
|||||||
// 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:
|
|
||||||
|
|
||||||
|
private:
|
||||||
shared_ptr<DIR> dir; // struct DIR
|
shared_ptr<DIR> dir; // struct DIR
|
||||||
// initialization vector to use. Not very general purpose, but makes it
|
// initialization vector to use. Not very general purpose, but makes it
|
||||||
// more efficient to support filename IV chaining..
|
// more efficient to support filename IV chaining..
|
||||||
@ -77,37 +76,36 @@ private:
|
|||||||
};
|
};
|
||||||
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,
|
DirNode(EncFS_Context *ctx, const std::string &sourceDir,
|
||||||
const std::string &sourceDir,
|
const FSConfigPtr &config);
|
||||||
const FSConfigPtr &config );
|
|
||||||
~DirNode();
|
~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.
|
||||||
@ -117,33 +115,32 @@ public:
|
|||||||
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
|
// returns idle time of filesystem in seconds
|
||||||
int idleSeconds();
|
int idleSeconds();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
notify that a file is being renamed.
|
notify that a file is being renamed.
|
||||||
This renames the internal node, if any. If the file is not open, then
|
This renames the internal node, if any. If the file is not open, then
|
||||||
this call has no effect.
|
this call has no effect.
|
||||||
Returns the FileNode if it was found.
|
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,
|
shared_ptr<FileNode> renameNode(const char *from, const char *to,
|
||||||
bool forwardMode );
|
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
|
||||||
@ -151,16 +148,15 @@ protected:
|
|||||||
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,
|
bool genRenameList(std::list<RenameEl> &list, const char *fromP,
|
||||||
const char *toP );
|
const char *toP);
|
||||||
|
|
||||||
shared_ptr<FileNode> findOrCreate( const char *plainName);
|
shared_ptr<FileNode> findOrCreate(const char *plainName);
|
||||||
|
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
|
|
||||||
|
@ -31,8 +31,7 @@
|
|||||||
|
|
||||||
namespace encfs {
|
namespace encfs {
|
||||||
|
|
||||||
enum ConfigType
|
enum ConfigType {
|
||||||
{
|
|
||||||
Config_None = 0,
|
Config_None = 0,
|
||||||
Config_Prehistoric,
|
Config_Prehistoric,
|
||||||
Config_V3 = 3,
|
Config_V3 = 3,
|
||||||
@ -58,12 +57,11 @@ 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;
|
||||||
|
|
||||||
@ -77,9 +75,7 @@ struct FSConfig
|
|||||||
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
|
||||||
|
|
||||||
|
@ -22,21 +22,13 @@
|
|||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
45
fs/FileIO.h
45
fs/FileIO.h
@ -28,8 +28,7 @@
|
|||||||
|
|
||||||
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.
|
||||||
@ -39,52 +38,46 @@ struct IORequest
|
|||||||
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
|
// get filesystem attributes for a file
|
||||||
virtual int getAttr( struct stat *stbuf ) const =0;
|
virtual int getAttr(struct stat *stbuf) const = 0;
|
||||||
virtual off_t getSize( ) const =0;
|
virtual off_t getSize() const = 0;
|
||||||
|
|
||||||
virtual ssize_t read( const IORequest &req ) const =0;
|
virtual ssize_t read(const IORequest &req) const = 0;
|
||||||
virtual bool write( const IORequest &req ) =0;
|
virtual bool write(const IORequest &req) = 0;
|
||||||
|
|
||||||
virtual int truncate( off_t size ) =0;
|
virtual int truncate(off_t size) = 0;
|
||||||
|
|
||||||
virtual bool isWritable() const =0;
|
virtual bool isWritable() const = 0;
|
||||||
private:
|
|
||||||
|
private:
|
||||||
// not implemented..
|
// not implemented..
|
||||||
FileIO( const FileIO & );
|
FileIO(const FileIO &);
|
||||||
FileIO &operator = ( const FileIO & );
|
FileIO &operator=(const FileIO &);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace encfs
|
} // namespace encfs
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
180
fs/FileNode.cpp
180
fs/FileNode.cpp
@ -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
|
||||||
|
@ -36,12 +36,9 @@ 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 FSConfigPtr &cfg,
|
|
||||||
const char *plaintextName,
|
|
||||||
const char *cipherName);
|
const char *cipherName);
|
||||||
~FileNode();
|
~FileNode();
|
||||||
|
|
||||||
@ -53,8 +50,8 @@ public:
|
|||||||
|
|
||||||
// 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
|
||||||
@ -71,12 +68,12 @@ public:
|
|||||||
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:
|
|
||||||
|
|
||||||
|
private:
|
||||||
// doing locking at the FileNode level isn't as efficient as at the
|
// doing locking at the FileNode level isn't as efficient as at the
|
||||||
// lowest level of RawFileIO, since that means locks are held longer
|
// lowest level of RawFileIO, since that means locks are held longer
|
||||||
// (held during CPU intensive crypto operations!). However it makes it
|
// (held during CPU intensive crypto operations!). However it makes it
|
||||||
@ -92,13 +89,11 @@ private:
|
|||||||
std::string _cname; // encrypted name
|
std::string _cname; // encrypted name
|
||||||
DirNode *parent;
|
DirNode *parent;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FileNode(const FileNode &src);
|
FileNode(const FileNode &src);
|
||||||
FileNode &operator = (const FileNode &src);
|
FileNode &operator=(const FileNode &src);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace encfs
|
} // namespace encfs
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
965
fs/FileUtils.cpp
965
fs/FileUtils.cpp
File diff suppressed because it is too large
Load Diff
@ -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,15 +58,13 @@ 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
|
||||||
@ -87,8 +84,7 @@ struct EncFS_Opts
|
|||||||
|
|
||||||
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,
|
bool readProtoConfig(const char *configFile, EncfsConfig &config,
|
||||||
struct ConfigInfo *);
|
struct ConfigInfo *);
|
||||||
|
|
||||||
|
|
||||||
} // namespace encfs
|
} // namespace encfs
|
||||||
#endif
|
#endif
|
||||||
|
183
fs/MACFileIO.cpp
183
fs/MACFileIO.cpp
@ -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
|
||||||
|
@ -26,36 +26,34 @@
|
|||||||
|
|
||||||
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,
|
MACFileIO(const shared_ptr<FileIO> &base, const FSConfigPtr &cfg);
|
||||||
const FSConfigPtr &cfg );
|
|
||||||
MACFileIO();
|
MACFileIO();
|
||||||
virtual ~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;
|
||||||
@ -67,4 +65,3 @@ private:
|
|||||||
} // namespace encfs
|
} // namespace encfs
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -49,6 +49,7 @@ class MemBlockFileIO : public BlockFileIO {
|
|||||||
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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -44,8 +44,8 @@ class MemFileIO : public FileIO {
|
|||||||
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
|
||||||
|
|
||||||
|
251
fs/NameIO.cpp
251
fs/NameIO.cpp
@ -44,21 +44,16 @@ 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,
|
||||||
{
|
|
||||||
reverseEncryption = enable;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NameIO::getReverseEncryption() const
|
|
||||||
{
|
|
||||||
return reverseEncryption;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::string NameIO::recodePath( const char *path,
|
|
||||||
int (NameIO::*_length)(int) const,
|
int (NameIO::*_length)(int) const,
|
||||||
int (NameIO::*_code)(const char*, int, uint64_t *, char*) const,
|
int (NameIO::*_code)(const char *, int,
|
||||||
uint64_t *iv ) const
|
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 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( plaintextPath,
|
&NameIO::encodeName, iv);
|
||||||
&NameIO::maxEncodedNameLen, &NameIO::encodeName, iv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string NameIO::_decodePath( const char *cipherPath, 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..
|
// if chaining is not enabled, then the iv pointer is not used..
|
||||||
if(!chainedNameIV)
|
if (!chainedNameIV) iv = 0;
|
||||||
iv = 0;
|
return recodePath(cipherPath, &NameIO::maxDecodedNameLen, &NameIO::decodeName,
|
||||||
return recodePath( cipherPath,
|
iv);
|
||||||
&NameIO::maxDecodedNameLen, &NameIO::decodeName, iv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string NameIO::encodePath( const char *path, uint64_t *iv ) const
|
std::string NameIO::encodePath(const char *path, uint64_t *iv) const {
|
||||||
{
|
return getReverseEncryption() ? _decodePath(path, iv) : _encodePath(path, iv);
|
||||||
return getReverseEncryption() ?
|
|
||||||
_decodePath( path, iv ) :
|
|
||||||
_encodePath( path, iv );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string NameIO::decodePath( const char *path, uint64_t *iv ) const
|
std::string NameIO::decodePath(const char *path, uint64_t *iv) const {
|
||||||
{
|
return getReverseEncryption() ? _encodePath(path, iv) : _decodePath(path, iv);
|
||||||
return getReverseEncryption() ?
|
|
||||||
_encodePath( path, iv ) :
|
|
||||||
_decodePath( path, iv );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int NameIO::encodeName(const char *input, int length, char *output) const {
|
||||||
int NameIO::encodeName( const char *input, int length, char *output ) const
|
return encodeName(input, length, (uint64_t *)0, output);
|
||||||
{
|
|
||||||
return encodeName( input, length, (uint64_t*)0, output );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int NameIO::decodeName( const char *input, int length, char *output ) const
|
int NameIO::decodeName(const char *input, int length, char *output) const {
|
||||||
{
|
return decodeName(input, length, (uint64_t *)0, output);
|
||||||
return decodeName( input, length, (uint64_t*)0, output );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string NameIO::_encodeName( const char *plaintextName, int length ) const
|
std::string NameIO::_encodeName(const char *plaintextName, int length) const {
|
||||||
{
|
int approxLen = maxEncodedNameLen(length);
|
||||||
int approxLen = maxEncodedNameLen( 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 = 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
|
||||||
|
|
||||||
|
92
fs/NameIO.h
92
fs/NameIO.h
@ -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::*codingLen)(int) const,
|
|
||||||
int (NameIO::*codingFunc)(const char *, int,
|
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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
215
fs/RawFileIO.cpp
215
fs/RawFileIO.cpp
@ -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
|
||||||
|
|
||||||
|
@ -27,31 +27,30 @@
|
|||||||
|
|
||||||
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 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;
|
||||||
protected:
|
|
||||||
|
|
||||||
|
protected:
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
mutable bool knownSize;
|
mutable bool knownSize;
|
||||||
@ -65,4 +64,3 @@ protected:
|
|||||||
} // namespace encfs
|
} // namespace encfs
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -27,28 +27,28 @@ 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;
|
||||||
|
|
||||||
|
private:
|
||||||
int _interface;
|
int _interface;
|
||||||
shared_ptr<CipherV1> _cipher;
|
shared_ptr<CipherV1> _cipher;
|
||||||
};
|
};
|
||||||
@ -56,4 +56,3 @@ private:
|
|||||||
} // namespace encfs
|
} // namespace encfs
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
395
fs/checkops.cpp
395
fs/checkops.cpp
@ -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,74 +95,48 @@ 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);
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) cerr << "Testing block encode/decode on full block - ";
|
||||||
|
{
|
||||||
|
int numErrors = checkErrorPropogation(cipher, FSBlockSize, -1);
|
||||||
|
if (numErrors) {
|
||||||
|
if (verbose) cerr << " FAILED!\n";
|
||||||
return false;
|
return false;
|
||||||
|
} else {
|
||||||
|
if (verbose) cerr << " OK\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (verbose) cerr << "Testing block encode/decode on partial block - ";
|
||||||
|
{
|
||||||
|
int numErrors = checkErrorPropogation(cipher, FSBlockSize - 1, -1);
|
||||||
|
if (numErrors) {
|
||||||
|
if (verbose) cerr << " FAILED!\n";
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
if (verbose) cerr << " OK\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(verbose)
|
if (verbose) cerr << "Checking error propogation in partial block:\n";
|
||||||
cerr << "Testing block encode/decode on full block - ";
|
|
||||||
{
|
{
|
||||||
int numErrors = checkErrorPropogation( cipher,
|
int minChanges = FSBlockSize - 1;
|
||||||
FSBlockSize, -1 );
|
|
||||||
if(numErrors)
|
|
||||||
{
|
|
||||||
if(verbose)
|
|
||||||
cerr << " FAILED!\n";
|
|
||||||
return false;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
if(verbose)
|
|
||||||
cerr << " OK\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(verbose)
|
|
||||||
cerr << "Testing block encode/decode on partial block - ";
|
|
||||||
{
|
|
||||||
int numErrors = checkErrorPropogation( cipher,
|
|
||||||
FSBlockSize-1, -1 );
|
|
||||||
if(numErrors)
|
|
||||||
{
|
|
||||||
if(verbose)
|
|
||||||
cerr << " FAILED!\n";
|
|
||||||
return false;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
if(verbose)
|
|
||||||
cerr << " OK\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(verbose)
|
|
||||||
cerr << "Checking error propogation in partial block:\n";
|
|
||||||
{
|
|
||||||
int minChanges = FSBlockSize-1;
|
|
||||||
int maxChanges = 0;
|
int 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,20 +395,17 @@ 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";
|
||||||
@ -494,29 +413,24 @@ int main(int argc, char *argv[])
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
574
fs/encfs.cpp
574
fs/encfs.cpp
@ -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;
|
||||||
@ -707,101 +614,86 @@ 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
|
||||||
|
|
||||||
|
42
fs/encfs.h
42
fs/encfs.h
@ -32,26 +32,22 @@
|
|||||||
#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;
|
||||||
}
|
}
|
||||||
@ -74,8 +70,7 @@ 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);
|
||||||
@ -89,25 +84,24 @@ 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
|
||||||
|
|
||||||
|
@ -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());
|
||||||
@ -66,4 +66,3 @@ TEST(BlockFileIOTest, BasicIO) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace encfs
|
} // namespace encfs
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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>
|
||||||
@ -69,7 +68,8 @@ void runWithAllCiphers(void (*func)(FSConfigPtr& config)) {
|
|||||||
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);
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ void writeRandom(FSConfigPtr& cfg, FileIO* a, FileIO* b, int offset, int 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;
|
||||||
@ -138,8 +138,8 @@ 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,11 +155,11 @@ 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
|
||||||
|
|
||||||
|
@ -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
@ -29,23 +29,20 @@
|
|||||||
#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;
|
||||||
}
|
}
|
||||||
@ -56,9 +53,8 @@ int main(int argc, char **argv)
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user