reformat using clang

This commit is contained in:
Valient Gough 2014-10-18 19:19:33 -07:00
parent 744f56b95d
commit b3c851982f
59 changed files with 8004 additions and 9714 deletions

52
.clang-format Normal file
View File

@ -0,0 +1,52 @@
---
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -1
ConstructorInitializerIndentWidth: 4
AlignEscapedNewlinesLeft: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AllowShortFunctionsOnASingleLine: true
AlwaysBreakTemplateDeclarations: true
AlwaysBreakBeforeMultilineStrings: true
BreakBeforeBinaryOperators: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BinPackParameters: true
ColumnLimit: 80
ConstructorInitializerAllOnOneLineOrOnePerLine: true
DerivePointerBinding: true
ExperimentalAutoDetectBinPacking: false
IndentCaseLabels: true
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakString: 1000
PenaltyBreakFirstLessLess: 120
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerBindsToType: true
SpacesBeforeTrailingComments: 2
Cpp11BracedListStyle: true
Standard: Auto
IndentWidth: 2
TabWidth: 8
UseTab: Never
BreakBeforeBraces: Attach
IndentFunctionDeclarationAfterType: true
SpacesInParentheses: false
SpacesInAngles: false
SpaceInEmptyParentheses: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: true
SpaceBeforeAssignmentOperators: true
ContinuationIndentWidth: 4
CommentPragmas: '^ IWYU pragma:'
SpaceBeforeParens: ControlStatements
...

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -27,406 +27,347 @@
#include "i18n.h" #include "i18n.h"
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->allowHoles) {
, _allowHoles( cfg->config->allowHoles ) 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
{ int len = req.dataLen;
// satisfy request from cache if (_cache.dataLen < len) len = _cache.dataLen;
int len = req.dataLen; memcpy(req.data, _cache.data, len);
if(_cache.dataLen < len) return len;
len = _cache.dataLen; } else {
memcpy( req.data, _cache.data, len ); if (_cache.dataLen > 0) clearCache(_cache, _blockSize);
return len;
} else
{
if(_cache.dataLen > 0)
clearCache( _cache, _blockSize );
// cache results of read -- issue reads for full blocks // cache results of read -- issue reads for full blocks
IORequest tmp; IORequest tmp;
tmp.offset = req.offset; tmp.offset = req.offset;
tmp.data = _cache.data; tmp.data = _cache.data;
tmp.dataLen = _blockSize; tmp.dataLen = _blockSize;
ssize_t result = readOneBlock( tmp ); ssize_t result = readOneBlock(tmp);
if(result > 0) if (result > 0) {
{ _cache.offset = req.offset;
_cache.offset = req.offset; _cache.dataLen = result; // the amount we really have
_cache.dataLen = result; // the amount we really have if (result > req.dataLen)
if(result > req.dataLen) result = req.dataLen; // only as much as requested
result = req.dataLen; // only as much as requested memcpy(req.data, _cache.data, result);
memcpy( req.data, _cache.data, result );
}
return result;
} }
}
bool BlockFileIO::cacheWriteOneBlock( const IORequest &req )
{
// cache results of write (before pass-thru, because it may be modified
// in-place)
memcpy( _cache.data, req.data, req.dataLen );
_cache.offset = req.offset;
_cache.dataLen = req.dataLen;
bool ok = writeOneBlock( req );
if(!ok)
clearCache( _cache, _blockSize );
return ok;
}
ssize_t BlockFileIO::read( const IORequest &req ) const
{
rAssert( _blockSize != 0 );
int partialOffset = req.offset % _blockSize;
off_t blockNum = req.offset / _blockSize;
ssize_t result = 0;
if(partialOffset == 0 && req.dataLen <= _blockSize)
{
// read completely within a single block -- can be handled as-is by
// readOneBloc().
return cacheReadOneBlock( req );
} else
{
size_t size = req.dataLen;
// if the request is larger then a block, then request each block
// individually
MemBlock mb; // in case we need to allocate a temporary block..
IORequest blockReq; // for requests we may need to make
blockReq.dataLen = _blockSize;
blockReq.data = NULL;
unsigned char *out = req.data;
while( size )
{
blockReq.offset = blockNum * _blockSize;
// if we're reading a full block, then read directly into the
// result buffer instead of using a temporary
if(partialOffset == 0 && size >= (size_t)_blockSize)
blockReq.data = out;
else
{
if(!mb.data)
mb = MemoryPool::allocate( _blockSize );
blockReq.data = mb.data;
}
ssize_t readSize = cacheReadOneBlock( blockReq );
if(unlikely(readSize <= partialOffset))
break; // didn't get enough bytes
int cpySize = min( (size_t)(readSize - partialOffset), size );
rAssert(cpySize <= readSize);
// if we read to a temporary buffer, then move the data
if(blockReq.data != out)
memcpy( out, blockReq.data + partialOffset, cpySize );
result += cpySize;
size -= cpySize;
out += cpySize;
++blockNum;
partialOffset = 0;
if(unlikely(readSize < _blockSize))
break;
}
if(mb.data)
MemoryPool::release( mb );
}
return result; return result;
}
} }
bool BlockFileIO::write( const IORequest &req ) bool BlockFileIO::cacheWriteOneBlock(const IORequest &req) {
{ // cache results of write (before pass-thru, because it may be modified
rAssert( _blockSize != 0 ); // in-place)
memcpy(_cache.data, req.data, req.dataLen);
_cache.offset = req.offset;
_cache.dataLen = req.dataLen;
bool ok = writeOneBlock(req);
if (!ok) clearCache(_cache, _blockSize);
return ok;
}
off_t fileSize = getSize(); ssize_t BlockFileIO::read(const IORequest &req) const {
rAssert(_blockSize != 0);
// where write request begins int partialOffset = req.offset % _blockSize;
off_t blockNum = req.offset / _blockSize; off_t blockNum = req.offset / _blockSize;
int partialOffset = req.offset % _blockSize; ssize_t result = 0;
// last block of file (for testing write overlaps with file boundary) if (partialOffset == 0 && req.dataLen <= _blockSize) {
off_t lastFileBlock = fileSize / _blockSize; // read completely within a single block -- can be handled as-is by
ssize_t lastBlockSize = fileSize % _blockSize; // readOneBloc().
return cacheReadOneBlock(req);
off_t lastNonEmptyBlock = lastFileBlock; } else {
if(lastBlockSize == 0)
--lastNonEmptyBlock;
if( req.offset > fileSize )
{
// extend file first to fill hole with 0's..
const bool forceWrite = false;
padFile( fileSize, req.offset, forceWrite );
}
// check against edge cases where we can just let the base class handle the
// request as-is..
if(partialOffset == 0 && req.dataLen <= _blockSize)
{
// if writing a full block.. pretty safe..
if( req.dataLen == _blockSize )
return cacheWriteOneBlock( req );
// if writing a partial block, but at least as much as what is
// already there..
if(blockNum == lastFileBlock && req.dataLen >= lastBlockSize)
return cacheWriteOneBlock( req );
}
// have to merge data with existing block(s)..
MemBlock mb;
IORequest blockReq;
blockReq.data = NULL;
blockReq.dataLen = _blockSize;
bool ok = true;
size_t size = req.dataLen; size_t size = req.dataLen;
unsigned char *inPtr = req.data;
while( size )
{
blockReq.offset = blockNum * _blockSize;
int toCopy = min((size_t)(_blockSize - partialOffset), size);
// if writing an entire block, or writing a partial block that requires // if the request is larger then a block, then request each block
// no merging with existing data.. // individually
if( (toCopy == _blockSize) MemBlock mb; // in case we need to allocate a temporary block..
||(partialOffset == 0 && blockReq.offset + toCopy >= fileSize)) IORequest blockReq; // for requests we may need to make
{ blockReq.dataLen = _blockSize;
// write directly from buffer blockReq.data = NULL;
blockReq.data = inPtr;
blockReq.dataLen = toCopy;
} else
{
// need a temporary buffer, since we have to either merge or pad
// the data.
if(!mb.data)
mb = MemoryPool::allocate( _blockSize );
memset( mb.data, 0, _blockSize );
blockReq.data = mb.data;
if(blockNum > lastNonEmptyBlock) unsigned char *out = req.data;
{ while (size) {
// just pad.. blockReq.offset = blockNum * _blockSize;
blockReq.dataLen = toCopy + partialOffset;
} else
{
// have to merge with existing block data..
blockReq.dataLen = _blockSize;
blockReq.dataLen = cacheReadOneBlock( blockReq );
// extend data if necessary.. // if we're reading a full block, then read directly into the
if( partialOffset + toCopy > blockReq.dataLen ) // result buffer instead of using a temporary
blockReq.dataLen = partialOffset + toCopy; if (partialOffset == 0 && size >= (size_t)_blockSize)
} blockReq.data = out;
// merge in the data to be written.. else {
memcpy( blockReq.data + partialOffset, inPtr, toCopy ); if (!mb.data) mb = MemoryPool::allocate(_blockSize);
} blockReq.data = mb.data;
}
// Finally, write the damn thing! ssize_t readSize = cacheReadOneBlock(blockReq);
if(!cacheWriteOneBlock( blockReq )) if (unlikely(readSize <= partialOffset))
{ break; // didn't get enough bytes
ok = false;
break;
}
// prepare to start all over with the next block.. int cpySize = min((size_t)(readSize - partialOffset), size);
size -= toCopy; rAssert(cpySize <= readSize);
inPtr += toCopy;
++blockNum; // if we read to a temporary buffer, then move the data
partialOffset = 0; if (blockReq.data != out)
memcpy(out, blockReq.data + partialOffset, cpySize);
result += cpySize;
size -= cpySize;
out += cpySize;
++blockNum;
partialOffset = 0;
if (unlikely(readSize < _blockSize)) break;
} }
if(mb.data) if (mb.data) MemoryPool::release(mb);
MemoryPool::release( mb ); }
return ok; return result;
} }
int BlockFileIO::blockSize() const bool BlockFileIO::write(const IORequest &req) {
{ rAssert(_blockSize != 0);
return _blockSize;
off_t fileSize = getSize();
// where write request begins
off_t blockNum = req.offset / _blockSize;
int partialOffset = req.offset % _blockSize;
// last block of file (for testing write overlaps with file boundary)
off_t lastFileBlock = fileSize / _blockSize;
ssize_t lastBlockSize = fileSize % _blockSize;
off_t lastNonEmptyBlock = lastFileBlock;
if (lastBlockSize == 0) --lastNonEmptyBlock;
if (req.offset > fileSize) {
// extend file first to fill hole with 0's..
const bool forceWrite = false;
padFile(fileSize, req.offset, forceWrite);
}
// check against edge cases where we can just let the base class handle the
// request as-is..
if (partialOffset == 0 && req.dataLen <= _blockSize) {
// if writing a full block.. pretty safe..
if (req.dataLen == _blockSize) return cacheWriteOneBlock(req);
// if writing a partial block, but at least as much as what is
// already there..
if (blockNum == lastFileBlock && req.dataLen >= lastBlockSize)
return cacheWriteOneBlock(req);
}
// have to merge data with existing block(s)..
MemBlock mb;
IORequest blockReq;
blockReq.data = NULL;
blockReq.dataLen = _blockSize;
bool ok = true;
size_t size = req.dataLen;
unsigned char *inPtr = req.data;
while (size) {
blockReq.offset = blockNum * _blockSize;
int toCopy = min((size_t)(_blockSize - partialOffset), size);
// if writing an entire block, or writing a partial block that requires
// no merging with existing data..
if ((toCopy == _blockSize) ||
(partialOffset == 0 && blockReq.offset + toCopy >= fileSize)) {
// write directly from buffer
blockReq.data = inPtr;
blockReq.dataLen = toCopy;
} else {
// need a temporary buffer, since we have to either merge or pad
// the data.
if (!mb.data) mb = MemoryPool::allocate(_blockSize);
memset(mb.data, 0, _blockSize);
blockReq.data = mb.data;
if (blockNum > lastNonEmptyBlock) {
// just pad..
blockReq.dataLen = toCopy + partialOffset;
} else {
// have to merge with existing block data..
blockReq.dataLen = _blockSize;
blockReq.dataLen = cacheReadOneBlock(blockReq);
// extend data if necessary..
if (partialOffset + toCopy > blockReq.dataLen)
blockReq.dataLen = partialOffset + toCopy;
}
// merge in the data to be written..
memcpy(blockReq.data + partialOffset, inPtr, toCopy);
}
// Finally, write the damn thing!
if (!cacheWriteOneBlock(blockReq)) {
ok = false;
break;
}
// prepare to start all over with the next block..
size -= toCopy;
inPtr += toCopy;
++blockNum;
partialOffset = 0;
}
if (mb.data) MemoryPool::release(mb);
return ok;
} }
void BlockFileIO::padFile( off_t oldSize, off_t newSize, bool forceWrite ) int BlockFileIO::blockSize() const { return _blockSize; }
{
off_t oldLastBlock = oldSize / _blockSize; void BlockFileIO::padFile(off_t oldSize, off_t newSize, bool forceWrite) {
off_t newLastBlock = newSize / _blockSize; off_t oldLastBlock = oldSize / _blockSize;
int newBlockSize = newSize % _blockSize; off_t newLastBlock = newSize / _blockSize;
int newBlockSize = newSize % _blockSize;
IORequest req;
MemBlock mb;
if (oldLastBlock == newLastBlock) {
// when the real write occurs, it will have to read in the existing
// data and pad it anyway, so we won't do it here (unless we're
// forced).
if (forceWrite) {
mb = MemoryPool::allocate(_blockSize);
req.data = mb.data;
req.offset = oldLastBlock * _blockSize;
req.dataLen = oldSize % _blockSize;
int outSize = newSize % _blockSize; // outSize > req.dataLen
if (outSize) {
memset(mb.data, 0, outSize);
cacheReadOneBlock(req);
req.dataLen = outSize;
cacheWriteOneBlock(req);
}
} else
rDebug("optimization: not padding last block");
} else {
mb = MemoryPool::allocate(_blockSize);
req.data = mb.data;
// 1. extend the first block to full length
// 2. write the middle empty blocks
// 3. write the last block
req.offset = oldLastBlock * _blockSize;
req.dataLen = oldSize % _blockSize;
// 1. req.dataLen == 0, iff oldSize was already a multiple of blocksize
if (req.dataLen != 0) {
rDebug("padding block %" PRIi64, oldLastBlock);
memset(mb.data, 0, _blockSize);
cacheReadOneBlock(req);
req.dataLen = _blockSize; // expand to full block size
cacheWriteOneBlock(req);
++oldLastBlock;
}
// 2, pad zero blocks unless holes are allowed
if (!_allowHoles) {
for (; oldLastBlock != newLastBlock; ++oldLastBlock) {
rDebug("padding block %" PRIi64, oldLastBlock);
req.offset = oldLastBlock * _blockSize;
req.dataLen = _blockSize;
memset(mb.data, 0, req.dataLen);
cacheWriteOneBlock(req);
}
}
// 3. only necessary if write is forced and block is non 0 length
if (forceWrite && newBlockSize) {
req.offset = newLastBlock * _blockSize;
req.dataLen = newBlockSize;
memset(mb.data, 0, req.dataLen);
cacheWriteOneBlock(req);
}
}
if (mb.data) MemoryPool::release(mb);
}
int BlockFileIO::truncateBase(off_t size, FileIO *base) {
int partialBlock = size % _blockSize;
int res = 0;
off_t oldSize = getSize();
if (size > oldSize) {
// truncate can be used to extend a file as well. truncate man page
// states that it will pad with 0's.
// do the truncate so that the underlying filesystem can allocate
// the space, and then we'll fill it in padFile..
if (base) base->truncate(size);
const bool forceWrite = true;
padFile(oldSize, size, forceWrite);
} else if (size == oldSize) {
// the easiest case, but least likely....
} else if (partialBlock) {
// partial block after truncate. Need to read in the block being
// truncated before the truncate. Then write it back out afterwards,
// since the encoding will change..
off_t blockNum = size / _blockSize;
MemBlock mb = MemoryPool::allocate(_blockSize);
IORequest req; IORequest req;
MemBlock mb; req.offset = blockNum * _blockSize;
req.dataLen = _blockSize;
req.data = mb.data;
if(oldLastBlock == newLastBlock) ssize_t rdSz = cacheReadOneBlock(req);
{
// when the real write occurs, it will have to read in the existing
// data and pad it anyway, so we won't do it here (unless we're
// forced).
if( forceWrite )
{
mb = MemoryPool::allocate( _blockSize );
req.data = mb.data;
req.offset = oldLastBlock * _blockSize; // do the truncate
req.dataLen = oldSize % _blockSize; if (base) res = base->truncate(size);
int outSize = newSize % _blockSize; // outSize > req.dataLen
if(outSize) // write back out partial block
{ req.dataLen = partialBlock;
memset( mb.data, 0, outSize ); bool wrRes = cacheWriteOneBlock(req);
cacheReadOneBlock( req );
req.dataLen = outSize;
cacheWriteOneBlock( req );
}
} else
rDebug("optimization: not padding last block");
} else
{
mb = MemoryPool::allocate( _blockSize );
req.data = mb.data;
// 1. extend the first block to full length if ((rdSz < 0) || (!wrRes)) {
// 2. write the middle empty blocks // rwarning - unlikely to ever occur..
// 3. write the last block rWarning(_("truncate failure: read %i bytes, partial block of %i"),
(int)rdSz, partialBlock);
req.offset = oldLastBlock * _blockSize;
req.dataLen = oldSize % _blockSize;
// 1. req.dataLen == 0, iff oldSize was already a multiple of blocksize
if(req.dataLen != 0)
{
rDebug("padding block %" PRIi64, oldLastBlock);
memset( mb.data, 0, _blockSize );
cacheReadOneBlock( req );
req.dataLen = _blockSize; // expand to full block size
cacheWriteOneBlock( req );
++oldLastBlock;
}
// 2, pad zero blocks unless holes are allowed
if(!_allowHoles)
{
for(; oldLastBlock != newLastBlock; ++oldLastBlock)
{
rDebug("padding block %" PRIi64, oldLastBlock);
req.offset = oldLastBlock * _blockSize;
req.dataLen = _blockSize;
memset( mb.data, 0, req.dataLen );
cacheWriteOneBlock( req );
}
}
// 3. only necessary if write is forced and block is non 0 length
if(forceWrite && newBlockSize)
{
req.offset = newLastBlock * _blockSize;
req.dataLen = newBlockSize;
memset( mb.data, 0, req.dataLen );
cacheWriteOneBlock( req );
}
} }
if(mb.data) MemoryPool::release(mb);
MemoryPool::release( mb ); } else {
// truncating on a block bounday. No need to re-encode the last
// block..
if (base) res = base->truncate(size);
}
return res;
} }
int BlockFileIO::truncateBase( off_t size, FileIO *base )
{
int partialBlock = size % _blockSize;
int res = 0;
off_t oldSize = getSize();
if( size > oldSize )
{
// truncate can be used to extend a file as well. truncate man page
// states that it will pad with 0's.
// do the truncate so that the underlying filesystem can allocate
// the space, and then we'll fill it in padFile..
if(base)
base->truncate( size );
const bool forceWrite = true;
padFile( oldSize, size, forceWrite );
} else
if( size == oldSize )
{
// the easiest case, but least likely....
} else
if( partialBlock )
{
// partial block after truncate. Need to read in the block being
// truncated before the truncate. Then write it back out afterwards,
// since the encoding will change..
off_t blockNum = size / _blockSize;
MemBlock mb = MemoryPool::allocate( _blockSize );
IORequest req;
req.offset = blockNum * _blockSize;
req.dataLen = _blockSize;
req.data = mb.data;
ssize_t rdSz = cacheReadOneBlock( req );
// do the truncate
if(base)
res = base->truncate( size );
// write back out partial block
req.dataLen = partialBlock;
bool wrRes = cacheWriteOneBlock( req );
if((rdSz < 0) || (!wrRes))
{
// rwarning - unlikely to ever occur..
rWarning(_("truncate failure: read %i bytes, partial block of %i"),
(int)rdSz, partialBlock );
}
MemoryPool::release( mb );
} else
{
// truncating on a block bounday. No need to re-encode the last
// block..
if(base)
res = base->truncate( size );
}
return res;
}

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -26,43 +26,40 @@
/* /*
Implements block scatter / gather interface. Requires derived classes to Implements block scatter / gather interface. Requires derived classes to
implement readOneBlock() / writeOneBlock() at a minimum. implement readOneBlock() / writeOneBlock() at a minimum.
When a partial block write is requested it will be turned into a read of When a partial block write is requested it will be turned into a read of
the existing block, merge with the write request, and a write of the full the existing block, merge with the write request, and a write of the full
block. block.
*/ */
class BlockFileIO : public FileIO class BlockFileIO : public FileIO {
{ public:
public: BlockFileIO(int blockSize, const FSConfigPtr &cfg);
BlockFileIO( int blockSize, const FSConfigPtr &cfg ); virtual ~BlockFileIO();
virtual ~BlockFileIO();
// implemented in terms of blocks. // implemented in terms of blocks.
virtual ssize_t read( const IORequest &req ) const; virtual ssize_t read(const IORequest &req) const;
virtual bool write( const IORequest &req ); virtual bool write(const IORequest &req);
virtual int blockSize() const; virtual int blockSize() const;
protected: protected:
int truncateBase(off_t size, FileIO *base);
void padFile(off_t oldSize, off_t newSize, bool forceWrite);
int truncateBase( off_t size, FileIO *base ); // same as read(), except that the request.offset field is guarenteed to be
void padFile( off_t oldSize, off_t newSize, bool forceWrite ); // block aligned, and the request size will not be larger then 1 block.
virtual ssize_t readOneBlock(const IORequest &req) const = 0;
virtual bool writeOneBlock(const IORequest &req) = 0;
// same as read(), except that the request.offset field is guarenteed to be ssize_t cacheReadOneBlock(const IORequest &req) const;
// block aligned, and the request size will not be larger then 1 block. bool cacheWriteOneBlock(const IORequest &req);
virtual ssize_t readOneBlock( const IORequest &req ) const =0;
virtual bool writeOneBlock( const IORequest &req ) =0;
ssize_t cacheReadOneBlock( const IORequest &req ) const;
bool cacheWriteOneBlock( const IORequest &req );
int _blockSize; int _blockSize;
bool _allowHoles; bool _allowHoles;
// cache last block for speed... // cache last block for speed...
mutable IORequest _cache; mutable IORequest _cache;
}; };
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -33,44 +33,42 @@
using namespace rlog; using namespace rlog;
using namespace rel; using namespace rel;
static RLogChannel * Info = DEF_CHANNEL( "info/nameio", Log_Info ); static RLogChannel *Info = DEF_CHANNEL("info/nameio", Log_Info);
static shared_ptr<NameIO> NewBlockNameIO(const Interface &iface,
const shared_ptr<Cipher> &cipher,
const CipherKey &key) {
int blockSize = 8;
if (cipher) blockSize = cipher->cipherBlockSize();
static shared_ptr<NameIO> NewBlockNameIO( const Interface &iface, return shared_ptr<NameIO>(
const shared_ptr<Cipher> &cipher, const CipherKey &key ) new BlockNameIO(iface, cipher, key, blockSize, false));
{
int blockSize = 8;
if(cipher)
blockSize = cipher->cipherBlockSize();
return shared_ptr<NameIO>(
new BlockNameIO( iface, cipher, key, blockSize, false));
} }
static shared_ptr<NameIO> NewBlockNameIO32( const Interface &iface, static shared_ptr<NameIO> NewBlockNameIO32(const Interface &iface,
const shared_ptr<Cipher> &cipher, const CipherKey &key ) const shared_ptr<Cipher> &cipher,
{ const CipherKey &key) {
int blockSize = 8; int blockSize = 8;
if(cipher) if (cipher) blockSize = cipher->cipherBlockSize();
blockSize = cipher->cipherBlockSize();
return shared_ptr<NameIO>( return shared_ptr<NameIO>(
new BlockNameIO( iface, cipher, key, blockSize, true)); new BlockNameIO(iface, cipher, key, blockSize, true));
} }
static bool BlockIO_registered = NameIO::Register("Block", static bool BlockIO_registered = NameIO::Register(
// description of block name encoding algorithm.. "Block",
// xgroup(setup) // description of block name encoding algorithm..
gettext_noop("Block encoding, hides file name size somewhat"), // xgroup(setup)
BlockNameIO::CurrentInterface(false), gettext_noop("Block encoding, hides file name size somewhat"),
NewBlockNameIO); BlockNameIO::CurrentInterface(false), NewBlockNameIO);
static bool BlockIO32_registered = NameIO::Register("Block32", static bool BlockIO32_registered = NameIO::Register(
// description of block name encoding algorithm.. "Block32",
// xgroup(setup) // description of block name encoding algorithm..
gettext_noop("Block encoding with base32 output for case-sensitive systems"), // xgroup(setup)
BlockNameIO::CurrentInterface(true), gettext_noop(
NewBlockNameIO32); "Block encoding with base32 output for case-sensitive systems"),
BlockNameIO::CurrentInterface(true), NewBlockNameIO32);
/* /*
- Version 1.0 computed MAC over the filename, but not the padding bytes. - Version 1.0 computed MAC over the filename, but not the padding bytes.
@ -89,180 +87,153 @@ 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 Interface("nameio/block32", 4, 0, 2);
return Interface("nameio/block32", 4, 0, 2); else
else return Interface("nameio/block", 4, 0, 2);
return Interface("nameio/block", 4, 0, 2);
} }
BlockNameIO::BlockNameIO( const rel::Interface &iface, BlockNameIO::BlockNameIO(const rel::Interface &iface,
const shared_ptr<Cipher> &cipher, const shared_ptr<Cipher> &cipher, const CipherKey &key,
const CipherKey &key, int blockSize, int blockSize, bool caseSensitiveEncoding)
bool caseSensitiveEncoding ) : _interface(iface.current()),
: _interface( iface.current() ) _bs(blockSize),
, _bs( blockSize ) _cipher(cipher),
, _cipher( cipher ) _key(key),
, _key( key ) _caseSensitive(caseSensitiveEncoding) {
, _caseSensitive( caseSensitiveEncoding ) // just to be safe..
{ rAssert(blockSize < 128);
// just to be safe..
rAssert( blockSize < 128 );
} }
BlockNameIO::~BlockNameIO() BlockNameIO::~BlockNameIO() {}
{
Interface BlockNameIO::interface() const {
return CurrentInterface(_caseSensitive);
} }
Interface BlockNameIO::interface() const int BlockNameIO::maxEncodedNameLen(int plaintextNameLen) const {
{ // number of blocks, rounded up.. Only an estimate at this point, err on
return CurrentInterface(_caseSensitive); // the size of too much space rather then too little.
int numBlocks = (plaintextNameLen + _bs) / _bs;
int encodedNameLen = numBlocks * _bs + 2; // 2 checksum bytes
if (_caseSensitive)
return B256ToB32Bytes(encodedNameLen);
else
return B256ToB64Bytes(encodedNameLen);
} }
int BlockNameIO::maxEncodedNameLen( int plaintextNameLen ) const int BlockNameIO::maxDecodedNameLen(int encodedNameLen) const {
{ int decLen256 = _caseSensitive ? B32ToB256Bytes(encodedNameLen)
// number of blocks, rounded up.. Only an estimate at this point, err on : B64ToB256Bytes(encodedNameLen);
// the size of too much space rather then too little. return decLen256 - 2; // 2 checksum bytes removed..
int numBlocks = ( plaintextNameLen + _bs ) / _bs;
int encodedNameLen = numBlocks * _bs + 2; // 2 checksum bytes
if (_caseSensitive)
return B256ToB32Bytes( encodedNameLen );
else
return B256ToB64Bytes( encodedNameLen );
} }
int BlockNameIO::maxDecodedNameLen( int encodedNameLen ) const int BlockNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv,
{ char *encodedName) const {
int decLen256 = _caseSensitive ? // copy the data into the encoding buffer..
B32ToB256Bytes( encodedNameLen ) : memcpy(encodedName + 2, plaintextName, length);
B64ToB256Bytes( encodedNameLen );
return decLen256 - 2; // 2 checksum bytes removed.. // Pad encryption buffer to block boundary..
int padding = _bs - length % _bs;
if (padding == 0) padding = _bs; // padding a full extra block!
memset(encodedName + length + 2, (unsigned char)padding, padding);
// store the IV before it is modified by the MAC call.
uint64_t tmpIV = 0;
if (iv && _interface >= 3) tmpIV = *iv;
// include padding in MAC computation
unsigned int mac = _cipher->MAC_16((unsigned char *)encodedName + 2,
length + padding, _key, iv);
// add checksum bytes
encodedName[0] = (mac >> 8) & 0xff;
encodedName[1] = (mac) & 0xff;
_cipher->blockEncode((unsigned char *)encodedName + 2, length + padding,
(uint64_t)mac ^ tmpIV, _key);
// convert to base 64 ascii
int encodedStreamLen = length + 2 + padding;
int encLen;
if (_caseSensitive) {
encLen = B256ToB32Bytes(encodedStreamLen);
changeBase2Inline((unsigned char *)encodedName, encodedStreamLen, 8, 5,
true);
B32ToAscii((unsigned char *)encodedName, encLen);
} else {
encLen = B256ToB64Bytes(encodedStreamLen);
changeBase2Inline((unsigned char *)encodedName, encodedStreamLen, 8, 6,
true);
B64ToAscii((unsigned char *)encodedName, encLen);
}
return encLen;
} }
int BlockNameIO::encodeName( const char *plaintextName, int length, int BlockNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
uint64_t *iv, char *encodedName ) const char *plaintextName) const {
{ int decLen256 =
// copy the data into the encoding buffer.. _caseSensitive ? B32ToB256Bytes(length) : B64ToB256Bytes(length);
memcpy( encodedName+2, plaintextName, length ); int decodedStreamLen = decLen256 - 2;
// Pad encryption buffer to block boundary..
int padding = _bs - length % _bs;
if(padding == 0)
padding = _bs; // padding a full extra block!
memset( encodedName+length+2, (unsigned char)padding, padding ); // don't bother trying to decode files which are too small
if (decodedStreamLen < _bs) throw ERROR("Filename too small to decode");
// store the IV before it is modified by the MAC call.
uint64_t tmpIV = 0;
if( iv && _interface >= 3 )
tmpIV = *iv;
// include padding in MAC computation BUFFER_INIT(tmpBuf, 32, (unsigned int)length);
unsigned int mac = _cipher->MAC_16( (unsigned char *)encodedName+2,
length+padding, _key, iv );
// add checksum bytes // decode into tmpBuf,
encodedName[0] = (mac >> 8) & 0xff; if (_caseSensitive) {
encodedName[1] = (mac ) & 0xff; AsciiToB32((unsigned char *)tmpBuf, (unsigned char *)encodedName, length);
changeBase2Inline((unsigned char *)tmpBuf, length, 5, 8, false);
} else {
AsciiToB64((unsigned char *)tmpBuf, (unsigned char *)encodedName, length);
changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false);
}
_cipher->blockEncode( (unsigned char *)encodedName+2, length+padding, // pull out the header information
(uint64_t)mac ^ tmpIV, _key); unsigned int mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 |
((unsigned int)((unsigned char)tmpBuf[1]));
// convert to base 64 ascii uint64_t tmpIV = 0;
int encodedStreamLen = length + 2 + padding; if (iv && _interface >= 3) tmpIV = *iv;
int encLen;
if (_caseSensitive)
{
encLen = B256ToB32Bytes( encodedStreamLen );
changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen, _cipher->blockDecode((unsigned char *)tmpBuf + 2, decodedStreamLen,
8, 5, true ); (uint64_t)mac ^ tmpIV, _key);
B32ToAscii( (unsigned char *)encodedName, encLen );
} else
{
encLen = B256ToB64Bytes( encodedStreamLen );
changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen, // find out true string length
8, 6, true ); int padding = (unsigned char)tmpBuf[2 + decodedStreamLen - 1];
B64ToAscii( (unsigned char *)encodedName, encLen ); int finalSize = decodedStreamLen - padding;
}
return encLen; // might happen if there is an error decoding..
} if (padding > _bs || finalSize < 0) {
rDebug("padding, _bx, finalSize = %i, %i, %i", padding, _bs, finalSize);
int BlockNameIO::decodeName( const char *encodedName, int length, throw ERROR("invalid padding size");
uint64_t *iv, char *plaintextName ) const }
{
int decLen256 = _caseSensitive ? // copy out the result..
B32ToB256Bytes( length ) : memcpy(plaintextName, tmpBuf + 2, finalSize);
B64ToB256Bytes( length ); plaintextName[finalSize] = '\0';
int decodedStreamLen = decLen256 - 2;
// check the mac
// don't bother trying to decode files which are too small unsigned int mac2 = _cipher->MAC_16((const unsigned char *)tmpBuf + 2,
if(decodedStreamLen < _bs) decodedStreamLen, _key, iv);
throw ERROR("Filename too small to decode");
BUFFER_RESET(tmpBuf);
BUFFER_INIT( tmpBuf, 32, (unsigned int)length );
if (mac2 != mac) {
// decode into tmpBuf, rDebug("checksum mismatch: expected %u, got %u", mac, mac2);
if (_caseSensitive) rDebug("on decode of %i bytes", finalSize);
{ throw ERROR("checksum mismatch in filename decode");
AsciiToB32((unsigned char *)tmpBuf, (unsigned char *)encodedName, length); }
changeBase2Inline((unsigned char *)tmpBuf, length, 5, 8, false);
} else return finalSize;
{
AsciiToB64((unsigned char *)tmpBuf, (unsigned char *)encodedName, length);
changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false);
}
// pull out the header information
unsigned int mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8
| ((unsigned int)((unsigned char)tmpBuf[1]));
uint64_t tmpIV = 0;
if( iv && _interface >= 3 )
tmpIV = *iv;
_cipher->blockDecode( (unsigned char *)tmpBuf+2, decodedStreamLen,
(uint64_t)mac ^ tmpIV, _key);
// find out true string length
int padding = (unsigned char)tmpBuf[2+decodedStreamLen-1];
int finalSize = decodedStreamLen - padding;
// might happen if there is an error decoding..
if(padding > _bs || finalSize < 0)
{
rDebug("padding, _bx, finalSize = %i, %i, %i", padding,
_bs, finalSize);
throw ERROR( "invalid padding size" );
}
// copy out the result..
memcpy(plaintextName, tmpBuf+2, finalSize);
plaintextName[finalSize] = '\0';
// check the mac
unsigned int mac2 = _cipher->MAC_16((const unsigned char *)tmpBuf+2,
decodedStreamLen, _key, iv);
BUFFER_RESET( tmpBuf );
if(mac2 != mac)
{
rDebug("checksum mismatch: expected %u, got %u", mac, mac2);
rDebug("on decode of %i bytes", finalSize);
throw ERROR( "checksum mismatch in filename decode" );
}
return finalSize;
}
bool BlockNameIO::Enabled()
{
return true;
} }
bool BlockNameIO::Enabled() { return true; }

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -32,38 +32,35 @@ class Cipher;
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 rel::Interface CurrentInterface(bool caseSensitive = false);
static rel::Interface CurrentInterface(bool caseSensitive = false);
BlockNameIO( const rel::Interface &iface, BlockNameIO(const rel::Interface &iface, const shared_ptr<Cipher> &cipher,
const shared_ptr<Cipher> &cipher, const CipherKey &key, int blockSize,
const CipherKey &key, int blockSize, bool caseSensitiveEncoding = false);
bool caseSensitiveEncoding = false ); virtual ~BlockNameIO();
virtual ~BlockNameIO();
virtual rel::Interface interface() const; virtual rel::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,
uint64_t *iv, char *encodedName ) const;
virtual int decodeName( const char *encodedName, int length,
uint64_t *iv, char *plaintextName ) const;
private: protected:
int _interface; virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
int _bs; char *encodedName) const;
shared_ptr<Cipher> _cipher; virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
CipherKey _key; char *plaintextName) const;
bool _caseSensitive;
private:
int _interface;
int _bs;
shared_ptr<Cipher> _cipher;
CipherKey _key;
bool _caseSensitive;
}; };
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -38,191 +38,164 @@
using namespace std; using namespace std;
using namespace rel; using namespace rel;
#define REF_MODULE(TYPE) \ #define REF_MODULE(TYPE) \
if( !TYPE::Enabled() ) \ if (!TYPE::Enabled()) cerr << "referenceModule: should never happen\n";
cerr << "referenceModule: should never happen\n";
static static void AddSymbolReferences() {
void AddSymbolReferences() REF_MODULE(SSL_Cipher)
{ REF_MODULE(NullCipher)
REF_MODULE(SSL_Cipher)
REF_MODULE(NullCipher)
} }
struct CipherAlg {
struct CipherAlg bool hidden;
{ Cipher::CipherConstructor constructor;
bool hidden; string description;
Cipher::CipherConstructor constructor; Interface iface;
string description; Range keyLength;
Interface iface; Range blockSize;
Range keyLength;
Range blockSize;
}; };
typedef multimap< string, CipherAlg> CipherMap_t; typedef multimap<string, CipherAlg> CipherMap_t;
static CipherMap_t *gCipherMap = NULL; static CipherMap_t *gCipherMap = NULL;
std::list<Cipher::CipherAlgorithm> std::list<Cipher::CipherAlgorithm> Cipher::GetAlgorithmList(
Cipher::GetAlgorithmList( bool includeHidden ) bool includeHidden) {
{ AddSymbolReferences();
AddSymbolReferences();
list<CipherAlgorithm> result; list<CipherAlgorithm> result;
if(!gCipherMap) if (!gCipherMap) return result;
return result;
CipherMap_t::const_iterator it;
CipherMap_t::const_iterator mapEnd = gCipherMap->end();
for (it = gCipherMap->begin(); it != mapEnd; ++it) {
if (includeHidden || !it->second.hidden) {
CipherAlgorithm tmp;
tmp.name = it->first;
tmp.description = it->second.description;
tmp.iface = it->second.iface;
tmp.keyLength = it->second.keyLength;
tmp.blockSize = it->second.blockSize;
result.push_back(tmp);
}
}
return result;
}
bool Cipher::Register(const char *name, const char *description,
const Interface &iface, CipherConstructor fn,
bool hidden) {
Range keyLength(-1, -1, 1);
Range blockSize(-1, -1, 1);
return Cipher::Register(name, description, iface, keyLength, blockSize, fn,
hidden);
}
bool Cipher::Register(const char *name, const char *description,
const Interface &iface, const Range &keyLength,
const Range &blockSize, CipherConstructor fn,
bool hidden) {
if (!gCipherMap) gCipherMap = new CipherMap_t;
CipherAlg ca;
ca.hidden = hidden;
ca.constructor = fn;
ca.description = description;
ca.iface = iface;
ca.keyLength = keyLength;
ca.blockSize = blockSize;
gCipherMap->insert(make_pair(string(name), ca));
return true;
}
shared_ptr<Cipher> Cipher::New(const string &name, int keyLen) {
shared_ptr<Cipher> result;
if (gCipherMap) {
CipherMap_t::const_iterator it = gCipherMap->find(name);
if (it != gCipherMap->end()) {
CipherConstructor fn = it->second.constructor;
// use current interface..
result = (*fn)(it->second.iface, keyLen);
}
}
return result;
}
shared_ptr<Cipher> Cipher::New(const Interface &iface, int keyLen) {
shared_ptr<Cipher> result;
if (gCipherMap) {
CipherMap_t::const_iterator it; CipherMap_t::const_iterator it;
CipherMap_t::const_iterator mapEnd = gCipherMap->end(); CipherMap_t::const_iterator mapEnd = gCipherMap->end();
for(it = gCipherMap->begin(); it != mapEnd; ++it)
{
if(includeHidden || !it->second.hidden)
{
CipherAlgorithm tmp;
tmp.name = it->first;
tmp.description = it->second.description;
tmp.iface = it->second.iface;
tmp.keyLength = it->second.keyLength;
tmp.blockSize = it->second.blockSize;
result.push_back( tmp ); for (it = gCipherMap->begin(); it != mapEnd; ++it) {
} // TODO: we should look for the newest implementation..
if (it->second.iface.implements(iface)) {
CipherConstructor fn = it->second.constructor;
// pass in requested interface..
result = (*fn)(iface, keyLen);
// if we're not going to compare the options, then just stop
// now..
break;
}
} }
}
return result; return result;
} }
bool Cipher::Register(const char *name, const char *description, Cipher::Cipher() {}
const Interface &iface, CipherConstructor fn, bool hidden)
{ Cipher::~Cipher() {}
Range keyLength(-1,-1,1);
Range blockSize(-1,-1,1); unsigned int Cipher::MAC_32(const unsigned char *src, int len,
return Cipher::Register( name, description, iface, const CipherKey &key, uint64_t *chainedIV) const {
keyLength, blockSize, fn, hidden ); uint64_t mac64 = MAC_64(src, len, key, chainedIV);
unsigned int mac32 = ((mac64 >> 32) & 0xffffffff) ^ (mac64 & 0xffffffff);
return mac32;
} }
bool Cipher::Register(const char *name, const char *description, unsigned int Cipher::MAC_16(const unsigned char *src, int len,
const Interface &iface, const Range &keyLength, const CipherKey &key, uint64_t *chainedIV) const {
const Range &blockSize, uint64_t mac64 = MAC_64(src, len, key, chainedIV);
CipherConstructor fn, bool hidden)
{
if(!gCipherMap)
gCipherMap = new CipherMap_t;
CipherAlg ca; unsigned int mac32 = ((mac64 >> 32) & 0xffffffff) ^ (mac64 & 0xffffffff);
ca.hidden = hidden; unsigned int mac16 = ((mac32 >> 16) & 0xffff) ^ (mac32 & 0xffff);
ca.constructor = fn;
ca.description = description;
ca.iface = iface;
ca.keyLength = keyLength;
ca.blockSize = blockSize;
gCipherMap->insert( make_pair(string(name), ca) ); return mac16;
return true;
} }
shared_ptr<Cipher> Cipher::New(const string &name, int keyLen) bool Cipher::nameEncode(unsigned char *data, int len, uint64_t iv64,
{ const CipherKey &key) const {
shared_ptr<Cipher> result; return streamEncode(data, len, iv64, key);
if(gCipherMap)
{
CipherMap_t::const_iterator it = gCipherMap->find( name );
if(it != gCipherMap->end())
{
CipherConstructor fn = it->second.constructor;
// use current interface..
result = (*fn)( it->second.iface, keyLen );
}
}
return result;
} }
shared_ptr<Cipher> Cipher::New( const Interface &iface, int keyLen ) bool Cipher::nameDecode(unsigned char *data, int len, uint64_t iv64,
{ const CipherKey &key) const {
shared_ptr<Cipher> result; return streamDecode(data, len, iv64, key);
if(gCipherMap)
{
CipherMap_t::const_iterator it;
CipherMap_t::const_iterator mapEnd = gCipherMap->end();
for(it = gCipherMap->begin(); it != mapEnd; ++it)
{
// TODO: we should look for the newest implementation..
if( it->second.iface.implements( iface ) )
{
CipherConstructor fn = it->second.constructor;
// pass in requested interface..
result = (*fn)( iface, keyLen );
// if we're not going to compare the options, then just stop
// now..
break;
}
}
}
return result;
}
Cipher::Cipher()
{
}
Cipher::~Cipher()
{
}
unsigned int Cipher::MAC_32( const unsigned char *src, int len,
const CipherKey &key, uint64_t *chainedIV ) const
{
uint64_t mac64 = MAC_64( src, len, key, chainedIV );
unsigned int mac32 = ((mac64 >> 32) & 0xffffffff) ^ (mac64 & 0xffffffff);
return mac32;
}
unsigned int Cipher::MAC_16( const unsigned char *src, int len,
const CipherKey &key, uint64_t *chainedIV ) const
{
uint64_t mac64 = MAC_64( src, len, key, chainedIV );
unsigned int mac32 = ((mac64 >> 32) & 0xffffffff) ^ (mac64 & 0xffffffff);
unsigned int mac16 = ((mac32 >> 16) & 0xffff) ^ (mac32 & 0xffff);
return mac16;
}
bool Cipher::nameEncode( unsigned char *data, int len,
uint64_t iv64, const CipherKey &key ) const
{
return streamEncode( data, len, iv64, key );
}
bool Cipher::nameDecode( unsigned char *data, int len,
uint64_t iv64, const CipherKey &key ) const
{
return streamDecode( data, len, iv64, key );
} }
string Cipher::encodeAsString(const CipherKey &key, string Cipher::encodeAsString(const CipherKey &key,
const CipherKey &encodingKey ) const CipherKey &encodingKey) {
{ int encodedKeySize = this->encodedKeySize();
int encodedKeySize = this->encodedKeySize(); unsigned char *keyBuf = new unsigned char[encodedKeySize];
unsigned char *keyBuf = new unsigned char[ encodedKeySize ];
// write the key, encoding it with itself. // write the key, encoding it with itself.
this->writeKey( key, keyBuf, encodingKey ); this->writeKey(key, keyBuf, encodingKey);
int b64Len = B256ToB64Bytes( encodedKeySize ); int b64Len = B256ToB64Bytes(encodedKeySize);
unsigned char *b64Key = new unsigned char[ b64Len + 1 ]; unsigned char *b64Key = new unsigned char[b64Len + 1];
changeBase2( keyBuf, encodedKeySize, 8, b64Key, b64Len, 6 ); changeBase2(keyBuf, encodedKeySize, 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);
} }

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -37,129 +37,116 @@
Cipher's should register themselves so they can be instanciated via Cipher's should register themselves so they can be instanciated via
Cipher::New(). Cipher::New().
*/ */
class Cipher class Cipher {
{ public:
public: // if no key length was indicated when cipher was registered, then keyLen
// if no key length was indicated when cipher was registered, then keyLen // <= 0 will be used.
// <= 0 will be used. typedef shared_ptr<Cipher>(*CipherConstructor)(const rel::Interface &iface,
typedef shared_ptr<Cipher> (*CipherConstructor)( const rel::Interface &iface, int keyLenBits);
int keyLenBits );
struct CipherAlgorithm struct CipherAlgorithm {
{ std::string name;
std::string name; std::string description;
std::string description; rel::Interface iface;
rel::Interface iface; Range keyLength;
Range keyLength; Range blockSize;
Range blockSize; };
};
typedef std::list<CipherAlgorithm> AlgorithmList;
static AlgorithmList GetAlgorithmList(bool includeHidden = false);
typedef std::list<CipherAlgorithm> AlgorithmList; static shared_ptr<Cipher> New(const rel::Interface &iface, int keyLen = -1);
static AlgorithmList GetAlgorithmList( bool includeHidden = false ); static shared_ptr<Cipher> New(const std::string &cipherName, int keyLen = -1);
static bool Register(const char *cipherName, const char *description,
const rel::Interface &iface,
CipherConstructor constructor, bool hidden = false);
static bool Register(const char *cipherName, const char *description,
const rel::Interface &iface, const Range &keyLength,
const Range &blockSize, CipherConstructor constructor,
bool hidden = false);
static shared_ptr<Cipher> New( const rel::Interface &iface, Cipher();
int keyLen = -1); virtual ~Cipher();
static shared_ptr<Cipher> New( const std::string &cipherName,
int keyLen = -1 );
virtual rel::Interface interface() const = 0;
static bool Register(const char *cipherName, // create a new key based on a password
const char *description, // if iterationCount == 0, then iteration count will be determined
const rel::Interface &iface, // by newKey function and filled in.
CipherConstructor constructor, // If iterationCount == 0, then desiredFunctionDuration is how many
bool hidden = false); // milliseconds the password derivation function should take to run.
static bool Register(const char *cipherName, virtual CipherKey newKey(const char *password, int passwdLength,
const char *description, int &iterationCount, long desiredFunctionDuration,
const rel::Interface &iface, const unsigned char *salt, int saltLen) = 0;
const Range &keyLength, const Range &blockSize, // deprecated - for backward compatibility
CipherConstructor constructor, virtual CipherKey newKey(const char *password, int passwdLength) = 0;
bool hidden = false); // create a new random key
virtual CipherKey newRandomKey() = 0;
// data must be len encodedKeySize()
virtual CipherKey readKey(const unsigned char *data,
const CipherKey &encodingKey,
bool checkKey = true) = 0;
virtual void writeKey(const CipherKey &key, unsigned char *data,
const CipherKey &encodingKey) = 0;
Cipher(); virtual std::string encodeAsString(const CipherKey &key,
virtual ~Cipher(); const CipherKey &encodingKey);
virtual rel::Interface interface() const =0; // for testing purposes
virtual bool compareKey(const CipherKey &A, const CipherKey &B) const = 0;
// create a new key based on a password // meta-data about the cypher
// if iterationCount == 0, then iteration count will be determined virtual int keySize() const = 0;
// by newKey function and filled in. virtual int encodedKeySize() const = 0; // size
// If iterationCount == 0, then desiredFunctionDuration is how many virtual int cipherBlockSize() const = 0; // size of a cipher block
// milliseconds the password derivation function should take to run.
virtual CipherKey newKey(const char *password, int passwdLength,
int &iterationCount, long desiredFunctionDuration,
const unsigned char *salt, int saltLen) =0;
// deprecated - for backward compatibility
virtual CipherKey newKey(const char *password, int passwdLength ) =0;
// create a new random key
virtual CipherKey newRandomKey() =0;
// data must be len encodedKeySize() // fill the supplied buffer with random data
virtual CipherKey readKey(const unsigned char *data, // The data may be pseudo random and might not be suitable for key
const CipherKey &encodingKey, // generation. For generating keys, uses newRandomKey() instead.
bool checkKey = true) =0; // Returns true on success, false on failure.
virtual void writeKey(const CipherKey &key, unsigned char *data, virtual bool randomize(unsigned char *buf, int len,
const CipherKey &encodingKey) =0; bool strongRandom) const = 0;
virtual std::string encodeAsString(const CipherKey &key, // 64 bit MAC of the data with the given key
const CipherKey &encodingKey ); virtual uint64_t MAC_64(const unsigned char *src, int len,
const CipherKey &key,
uint64_t *chainedIV = 0) const = 0;
// based on reductions of MAC_64
unsigned int MAC_32(const unsigned char *src, int len, const CipherKey &key,
uint64_t *chainedIV = 0) const;
unsigned int MAC_16(const unsigned char *src, int len, const CipherKey &key,
uint64_t *chainedIV = 0) const;
// for testing purposes // functional interfaces
virtual bool compareKey( const CipherKey &A, const CipherKey &B ) const =0; /*
Stream encoding of data in-place. The stream data can be any length.
*/
virtual bool streamEncode(unsigned char *data, int len, uint64_t iv64,
const CipherKey &key) const = 0;
virtual bool streamDecode(unsigned char *data, int len, uint64_t iv64,
const CipherKey &key) const = 0;
// meta-data about the cypher /*
virtual int keySize() const=0; These are just aliases of streamEncode / streamDecode, but there are
virtual int encodedKeySize() const=0; // size provided here for backward compatibility for earlier ciphers that has
virtual int cipherBlockSize() const=0; // size of a cipher block effectively two stream modes - one for encoding partial blocks and
another for encoding filenames.
*/
virtual bool nameEncode(unsigned char *data, int len, uint64_t iv64,
const CipherKey &key) const;
virtual bool nameDecode(unsigned char *data, int len, uint64_t iv64,
const CipherKey &key) const;
// fill the supplied buffer with random data /*
// The data may be pseudo random and might not be suitable for key Block encoding of data in-place. The data size should be a multiple of
// generation. For generating keys, uses newRandomKey() instead. the cipher block size.
// Returns true on success, false on failure. */
virtual bool randomize( unsigned char *buf, int len, virtual bool blockEncode(unsigned char *buf, int size, uint64_t iv64,
bool strongRandom ) const =0; const CipherKey &key) const = 0;
virtual bool blockDecode(unsigned char *buf, int size, uint64_t iv64,
// 64 bit MAC of the data with the given key const CipherKey &key) const = 0;
virtual uint64_t MAC_64( const unsigned char *src, int len,
const CipherKey &key, uint64_t *chainedIV = 0 ) const =0;
// based on reductions of MAC_64
unsigned int MAC_32( const unsigned char *src, int len,
const CipherKey &key, uint64_t *chainedIV = 0 ) const;
unsigned int MAC_16( const unsigned char *src, int len,
const CipherKey &key, uint64_t *chainedIV = 0 ) const;
// functional interfaces
/*
Stream encoding of data in-place. The stream data can be any length.
*/
virtual bool streamEncode( unsigned char *data, int len,
uint64_t iv64, const CipherKey &key) const=0;
virtual bool streamDecode( unsigned char *data, int len,
uint64_t iv64, const CipherKey &key) const=0;
/*
These are just aliases of streamEncode / streamDecode, but there are
provided here for backward compatibility for earlier ciphers that has
effectively two stream modes - one for encoding partial blocks and
another for encoding filenames.
*/
virtual bool nameEncode( unsigned char *data, int len,
uint64_t iv64, const CipherKey &key) const;
virtual bool nameDecode( unsigned char *data, int len,
uint64_t iv64, const CipherKey &key) const;
/*
Block encoding of data in-place. The data size should be a multiple of
the cipher block size.
*/
virtual bool blockEncode(unsigned char *buf, int size,
uint64_t iv64, const CipherKey &key) const=0;
virtual bool blockDecode(unsigned char *buf, int size,
uint64_t iv64, const CipherKey &key) const=0;
}; };
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -37,401 +37,326 @@
*/ */
static rel::Interface CipherFileIO_iface("FileIO/Cipher", 2, 0, 1); static rel::Interface CipherFileIO_iface("FileIO/Cipher", 2, 0, 1);
const int HEADER_SIZE = 8; // 64 bit initialization vector.. const int HEADER_SIZE = 8; // 64 bit initialization vector..
static bool checkSize( int fsBlockSize, int cipherBlockSize ) static bool checkSize(int fsBlockSize, int cipherBlockSize) {
{ int blockBoundary = fsBlockSize % cipherBlockSize;
int blockBoundary = fsBlockSize % cipherBlockSize ; if (blockBoundary != 0) {
if(blockBoundary != 0) rError("CipherFileIO: blocks should be multiple of cipher block size");
{ return true;
rError("CipherFileIO: blocks should be multiple of cipher block size"); } else
return true; return false;
} else
return false;
} }
CipherFileIO::CipherFileIO( const shared_ptr<FileIO> &_base, CipherFileIO::CipherFileIO(const shared_ptr<FileIO> &_base,
const FSConfigPtr &cfg) const FSConfigPtr &cfg)
: BlockFileIO( cfg->config->blockSize, cfg ) : BlockFileIO(cfg->config->blockSize, cfg),
, base( _base ) base(_base),
, haveHeader( cfg->config->uniqueIV ) haveHeader(cfg->config->uniqueIV),
, externalIV( 0 ) externalIV(0),
, fileIV( 0 ) fileIV(0),
, lastFlags( 0 ) lastFlags(0) {
{ fsConfig = cfg;
fsConfig = cfg; cipher = cfg->cipher;
cipher = cfg->cipher; key = cfg->key;
key = cfg->key;
static bool warnOnce = false; static bool warnOnce = false;
if(!warnOnce) if (!warnOnce)
warnOnce = checkSize( fsConfig->config->blockSize, warnOnce = checkSize(fsConfig->config->blockSize,
fsConfig->cipher->cipherBlockSize() ); fsConfig->cipher->cipherBlockSize());
} }
CipherFileIO::~CipherFileIO() CipherFileIO::~CipherFileIO() {}
{
rel::Interface CipherFileIO::interface() const { return CipherFileIO_iface; }
int CipherFileIO::open(int flags) {
int res = base->open(flags);
if (res >= 0) lastFlags = flags;
return res;
} }
rel::Interface CipherFileIO::interface() const void CipherFileIO::setFileName(const char *fileName) {
{ base->setFileName(fileName);
return CipherFileIO_iface;
} }
int CipherFileIO::open( int flags ) const char *CipherFileIO::getFileName() const { return base->getFileName(); }
{
int res = base->open( flags );
if( res >= 0 )
lastFlags = flags;
return res; bool CipherFileIO::setIV(uint64_t iv) {
} rDebug("in setIV, current IV = %" PRIu64 ", new IV = %" PRIu64
", fileIV = %" PRIu64,
void CipherFileIO::setFileName( const char *fileName ) externalIV, iv, fileIV);
{ if (externalIV == 0) {
base->setFileName( fileName ); // we're just being told about which IV to use. since we haven't
} // initialized the fileIV, there is no need to just yet..
externalIV = iv;
const char *CipherFileIO::getFileName() const if (fileIV != 0)
{ rWarning("fileIV initialized before externalIV! (%" PRIu64 ", %" PRIu64
return base->getFileName(); ")",
} fileIV, externalIV);
} else if (haveHeader) {
bool CipherFileIO::setIV( uint64_t iv ) // we have an old IV, and now a new IV, so we need to update the fileIV
{ // on disk.
rDebug("in setIV, current IV = %" PRIu64 ", new IV = %" PRIu64 if (fileIV == 0) {
", fileIV = %" PRIu64, // ensure the file is open for read/write..
externalIV, iv, fileIV); int newFlags = lastFlags | O_RDWR;
if(externalIV == 0) int res = base->open(newFlags);
{ if (res < 0) {
// we're just being told about which IV to use. since we haven't if (res == -EISDIR) {
// initialized the fileIV, there is no need to just yet.. // duh -- there are no file headers for directories!
externalIV = iv; externalIV = iv;
if(fileIV != 0) return base->setIV(iv);
rWarning("fileIV initialized before externalIV! (%" PRIu64 } else {
", %" PRIu64 ")", fileIV, externalIV); rDebug("writeHeader failed to re-open for write");
} else return false;
if(haveHeader) }
{ }
// we have an old IV, and now a new IV, so we need to update the fileIV initHeader();
// on disk.
if(fileIV == 0)
{
// ensure the file is open for read/write..
int newFlags = lastFlags | O_RDWR;
int res = base->open( newFlags );
if(res < 0)
{
if(res == -EISDIR)
{
// duh -- there are no file headers for directories!
externalIV = iv;
return base->setIV( iv );
} else
{
rDebug("writeHeader failed to re-open for write");
return false;
}
}
initHeader();
}
uint64_t oldIV = externalIV;
externalIV = iv;
if(!writeHeader())
{
externalIV = oldIV;
return false;
}
} }
return base->setIV( iv ); uint64_t oldIV = externalIV;
} externalIV = iv;
if (!writeHeader()) {
int CipherFileIO::getAttr( struct stat *stbuf ) const externalIV = oldIV;
{ return false;
int res = base->getAttr( stbuf );
// adjust size if we have a file header
if((res == 0) && haveHeader &&
S_ISREG(stbuf->st_mode) && (stbuf->st_size > 0))
{
rAssert(stbuf->st_size >= HEADER_SIZE);
stbuf->st_size -= HEADER_SIZE;
} }
}
return res; return base->setIV(iv);
} }
off_t CipherFileIO::getSize() const int CipherFileIO::getAttr(struct stat *stbuf) const {
{ int res = base->getAttr(stbuf);
off_t size = base->getSize(); // adjust size if we have a file header
// No check on S_ISREG here -- don't call getSize over getAttr unless this if ((res == 0) && haveHeader && S_ISREG(stbuf->st_mode) &&
// is a normal file! (stbuf->st_size > 0)) {
if(haveHeader && size > 0) rAssert(stbuf->st_size >= HEADER_SIZE);
{ stbuf->st_size -= HEADER_SIZE;
rAssert(size >= HEADER_SIZE); }
size -= HEADER_SIZE;
} return res;
return size;
} }
void CipherFileIO::initHeader( ) off_t CipherFileIO::getSize() const {
{ off_t size = base->getSize();
// check if the file has a header, and read it if it does.. Otherwise, // No check on S_ISREG here -- don't call getSize over getAttr unless this
// create one. // is a normal file!
off_t rawSize = base->getSize(); if (haveHeader && size > 0) {
if(rawSize >= HEADER_SIZE) rAssert(size >= HEADER_SIZE);
{ size -= HEADER_SIZE;
rDebug("reading existing header, rawSize = %" PRIi64, rawSize); }
// has a header.. read it return size;
unsigned char buf[8] = {0};
IORequest req;
req.offset = 0;
req.data = buf;
req.dataLen = 8;
base->read( req );
cipher->streamDecode( buf, sizeof(buf),
externalIV, key );
fileIV = 0;
for(int i=0; i<8; ++i)
fileIV = (fileIV << 8) | (uint64_t)buf[i];
rAssert(fileIV != 0); // 0 is never used..
} else
{
rDebug("creating new file IV header");
unsigned char buf[8] = {0};
do
{
if(!cipher->randomize( buf, 8, false ))
throw ERROR("Unable to generate a random file IV");
fileIV = 0;
for(int i=0; i<8; ++i)
fileIV = (fileIV << 8) | (uint64_t)buf[i];
if(fileIV == 0)
rWarning("Unexpected result: randomize returned 8 null bytes!");
} while(fileIV == 0); // don't accept 0 as an option..
if( base->isWritable() )
{
cipher->streamEncode( buf, sizeof(buf), externalIV, key );
IORequest req;
req.offset = 0;
req.data = buf;
req.dataLen = 8;
base->write( req );
} else
rDebug("base not writable, IV not written..");
}
rDebug("initHeader finished, fileIV = %" PRIu64 , fileIV);
} }
bool CipherFileIO::writeHeader( ) void CipherFileIO::initHeader() {
{ // check if the file has a header, and read it if it does.. Otherwise,
if( !base->isWritable() ) // create one.
{ off_t rawSize = base->getSize();
// open for write.. if (rawSize >= HEADER_SIZE) {
int newFlags = lastFlags | O_RDWR; rDebug("reading existing header, rawSize = %" PRIi64, rawSize);
if( base->open( newFlags ) < 0 ) // has a header.. read it
{
rDebug("writeHeader failed to re-open for write");
return false;
}
}
if(fileIV == 0)
rError("Internal error: fileIV == 0 in writeHeader!!!");
rDebug("writing fileIV %" PRIu64 , fileIV);
unsigned char buf[8] = {0}; unsigned char buf[8] = {0};
for(int i=0; i<8; ++i)
{
buf[sizeof(buf)-1-i] = (unsigned char)(fileIV & 0xff);
fileIV >>= 8;
}
cipher->streamEncode( buf, sizeof(buf), externalIV, key );
IORequest req; IORequest req;
req.offset = 0; req.offset = 0;
req.data = buf; req.data = buf;
req.dataLen = 8; req.dataLen = 8;
base->read(req);
base->write( req ); cipher->streamDecode(buf, sizeof(buf), externalIV, key);
return true; fileIV = 0;
for (int i = 0; i < 8; ++i) fileIV = (fileIV << 8) | (uint64_t)buf[i];
rAssert(fileIV != 0); // 0 is never used..
} else {
rDebug("creating new file IV header");
unsigned char buf[8] = {0};
do {
if (!cipher->randomize(buf, 8, false))
throw ERROR("Unable to generate a random file IV");
fileIV = 0;
for (int i = 0; i < 8; ++i) fileIV = (fileIV << 8) | (uint64_t)buf[i];
if (fileIV == 0)
rWarning("Unexpected result: randomize returned 8 null bytes!");
} while (fileIV == 0); // don't accept 0 as an option..
if (base->isWritable()) {
cipher->streamEncode(buf, sizeof(buf), externalIV, key);
IORequest req;
req.offset = 0;
req.data = buf;
req.dataLen = 8;
base->write(req);
} else
rDebug("base not writable, IV not written..");
}
rDebug("initHeader finished, fileIV = %" PRIu64, fileIV);
} }
ssize_t CipherFileIO::readOneBlock( const IORequest &req ) const bool CipherFileIO::writeHeader() {
{ if (!base->isWritable()) {
// read raw data, then decipher it.. // open for write..
int bs = blockSize(); int newFlags = lastFlags | O_RDWR;
off_t blockNum = req.offset / bs; if (base->open(newFlags) < 0) {
rDebug("writeHeader failed to re-open for write");
ssize_t readSize = 0; return false;
IORequest tmpReq = req; }
}
if(haveHeader) if (fileIV == 0) rError("Internal error: fileIV == 0 in writeHeader!!!");
tmpReq.offset += HEADER_SIZE; rDebug("writing fileIV %" PRIu64, fileIV);
readSize = base->read( tmpReq );
bool ok; unsigned char buf[8] = {0};
if(readSize > 0) for (int i = 0; i < 8; ++i) {
{ buf[sizeof(buf) - 1 - i] = (unsigned char)(fileIV & 0xff);
if(haveHeader && fileIV == 0) fileIV >>= 8;
const_cast<CipherFileIO*>(this)->initHeader(); }
if(readSize != bs) cipher->streamEncode(buf, sizeof(buf), externalIV, key);
{
ok = streamRead( tmpReq.data, (int)readSize, blockNum ^ fileIV);
} else
{
ok = blockRead( tmpReq.data, (int)readSize, blockNum ^ fileIV);
}
if(!ok) IORequest req;
{ req.offset = 0;
rDebug("decodeBlock failed for block %" PRIi64 ", size %i", req.data = buf;
blockNum, (int)readSize ); req.dataLen = 8;
readSize = -1;
}
} else
rDebug("readSize zero for offset %" PRIi64, req.offset);
return readSize; base->write(req);
return true;
} }
ssize_t CipherFileIO::readOneBlock(const IORequest &req) const {
// read raw data, then decipher it..
int bs = blockSize();
off_t blockNum = req.offset / bs;
bool CipherFileIO::writeOneBlock( const IORequest &req ) ssize_t readSize = 0;
{ IORequest tmpReq = req;
int bs = blockSize();
off_t blockNum = req.offset / bs;
if(haveHeader && fileIV == 0) if (haveHeader) tmpReq.offset += HEADER_SIZE;
initHeader(); readSize = base->read(tmpReq);
bool ok; bool ok;
if( req.dataLen != bs ) if (readSize > 0) {
{ if (haveHeader && fileIV == 0)
ok = streamWrite( req.data, (int)req.dataLen, const_cast<CipherFileIO *>(this)->initHeader();
blockNum ^ fileIV );
} else if (readSize != bs) {
{ ok = streamRead(tmpReq.data, (int)readSize, blockNum ^ fileIV);
ok = blockWrite( req.data, (int)req.dataLen, } else {
blockNum ^ fileIV ); ok = blockRead(tmpReq.data, (int)readSize, blockNum ^ fileIV);
} }
if( ok ) if (!ok) {
{ rDebug("decodeBlock failed for block %" PRIi64 ", size %i", blockNum,
if(haveHeader) (int)readSize);
{ readSize = -1;
IORequest tmpReq = req; }
tmpReq.offset += HEADER_SIZE; } else
ok = base->write( tmpReq ); rDebug("readSize zero for offset %" PRIi64, req.offset);
} else
ok = base->write( req ); return readSize;
}
bool CipherFileIO::writeOneBlock(const IORequest &req) {
int bs = blockSize();
off_t blockNum = req.offset / bs;
if (haveHeader && fileIV == 0) initHeader();
bool ok;
if (req.dataLen != bs) {
ok = streamWrite(req.data, (int)req.dataLen, blockNum ^ fileIV);
} else {
ok = blockWrite(req.data, (int)req.dataLen, blockNum ^ fileIV);
}
if (ok) {
if (haveHeader) {
IORequest tmpReq = req;
tmpReq.offset += HEADER_SIZE;
ok = base->write(tmpReq);
} else } else
{ ok = base->write(req);
rDebug("encodeBlock failed for block %" PRIi64 ", size %i", } else {
blockNum, req.dataLen); rDebug("encodeBlock failed for block %" PRIi64 ", size %i", blockNum,
ok = false; req.dataLen);
} 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, key);
return cipher->blockEncode( buf, size, _iv64, key ); else
else return cipher->blockDecode(buf, size, _iv64, key);
return cipher->blockDecode( buf, size, _iv64, key ); }
}
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, key);
return cipher->streamEncode( buf, size, _iv64, key ); else
else return cipher->streamDecode(buf, size, _iv64, key);
return cipher->streamDecode( buf, size, _iv64, key ); }
}
bool CipherFileIO::blockRead(unsigned char *buf, int size,
uint64_t _iv64) const {
if (fsConfig->reverseEncryption)
return cipher->blockEncode(buf, size, _iv64, key);
else {
if (_allowHoles) {
// special case - leave all 0's alone
for (int i = 0; i < size; ++i)
if (buf[i] != 0) return cipher->blockDecode(buf, size, _iv64, key);
bool CipherFileIO::blockRead( unsigned char *buf, int size, return true;
uint64_t _iv64 ) const
{
if (fsConfig->reverseEncryption)
return cipher->blockEncode( buf, size, _iv64, key );
else
{
if(_allowHoles)
{
// special case - leave all 0's alone
for(int i=0; i<size; ++i)
if(buf[i] != 0)
return cipher->blockDecode( buf, size, _iv64, key );
return true;
} else
return cipher->blockDecode( buf, size, _iv64, key );
}
}
bool CipherFileIO::streamRead( unsigned char *buf, int size,
uint64_t _iv64 ) const
{
if (fsConfig->reverseEncryption)
return cipher->streamEncode( buf, size, _iv64, key );
else
return cipher->streamDecode( buf, size, _iv64, key );
}
int CipherFileIO::truncate( off_t size )
{
int res = 0;
if(!haveHeader)
{
res = BlockFileIO::truncateBase( size, base.get() );
} else } else
{ return cipher->blockDecode(buf, size, _iv64, key);
if(0 == fileIV) }
{ }
// empty file.. create the header..
if( !base->isWritable() )
{
// open for write..
int newFlags = lastFlags | O_RDWR;
if( base->open( newFlags ) < 0 )
rDebug("writeHeader failed to re-open for write");
}
initHeader();
}
// can't let BlockFileIO call base->truncate(), since it would be using bool CipherFileIO::streamRead(unsigned char *buf, int size,
// the wrong size.. uint64_t _iv64) const {
res = BlockFileIO::truncateBase( size, 0 ); if (fsConfig->reverseEncryption)
return cipher->streamEncode(buf, size, _iv64, key);
else
return cipher->streamDecode(buf, size, _iv64, key);
}
if(res == 0) int CipherFileIO::truncate(off_t size) {
base->truncate( size + HEADER_SIZE ); int res = 0;
if (!haveHeader) {
res = BlockFileIO::truncateBase(size, base.get());
} else {
if (0 == fileIV) {
// empty file.. create the header..
if (!base->isWritable()) {
// open for write..
int newFlags = lastFlags | O_RDWR;
if (base->open(newFlags) < 0)
rDebug("writeHeader failed to re-open for write");
}
initHeader();
} }
return res;
} // can't let BlockFileIO call base->truncate(), since it would be using
// the wrong size..
bool CipherFileIO::isWritable() const res = BlockFileIO::truncateBase(size, 0);
{
return base->isWritable(); if (res == 0) base->truncate(size + HEADER_SIZE);
}
return res;
} }
bool CipherFileIO::isWritable() const { return base->isWritable(); }

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -30,60 +30,54 @@
class Cipher; class Cipher;
/* /*
Implement the FileIO interface encrypting data in blocks. Implement the FileIO interface encrypting data in blocks.
Uses BlockFileIO to handle the block scatter / gather issues. Uses BlockFileIO to handle the block scatter / gather issues.
*/ */
class CipherFileIO : public BlockFileIO class CipherFileIO : public BlockFileIO {
{ public:
public: CipherFileIO(const shared_ptr<FileIO> &base, const FSConfigPtr &cfg);
CipherFileIO( const shared_ptr<FileIO> &base, virtual ~CipherFileIO();
const FSConfigPtr &cfg);
virtual ~CipherFileIO();
virtual rel::Interface interface() const; virtual rel::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);
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;
shared_ptr<FileIO> base; shared_ptr<FileIO> base;
FSConfigPtr fsConfig; FSConfigPtr fsConfig;
// if haveHeader is true, then we have a transparent file header which // if haveHeader is true, then we have a transparent file header which
// contains a 64 bit initialization vector. // contains a 64 bit initialization vector.
bool haveHeader; bool haveHeader;
uint64_t externalIV; uint64_t externalIV;
uint64_t fileIV; uint64_t fileIV;
int lastFlags; int lastFlags;
shared_ptr<Cipher> cipher; shared_ptr<Cipher> cipher;
CipherKey key; CipherKey key;
}; };
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -20,11 +20,6 @@
#include "CipherKey.h" #include "CipherKey.h"
AbstractCipherKey::AbstractCipherKey() AbstractCipherKey::AbstractCipherKey() {}
{
}
AbstractCipherKey::~AbstractCipherKey()
{
}
AbstractCipherKey::~AbstractCipherKey() {}

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -23,14 +23,12 @@
#include "shared_ptr.h" #include "shared_ptr.h"
class AbstractCipherKey class AbstractCipherKey {
{ public:
public: AbstractCipherKey();
AbstractCipherKey(); virtual ~AbstractCipherKey();
virtual ~AbstractCipherKey();
}; };
typedef shared_ptr<AbstractCipherKey> CipherKey; typedef shared_ptr<AbstractCipherKey> CipherKey;
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -28,135 +28,109 @@
#include <unistd.h> #include <unistd.h>
#include <cstring> #include <cstring>
using namespace std; using namespace std;
using namespace rlog; using namespace rlog;
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 bool ConfigReader::load(const char *fileName) {
ConfigReader::load(const char *fileName) struct stat stbuf;
{ memset(&stbuf, 0, sizeof(struct stat));
struct stat stbuf; if (lstat(fileName, &stbuf) != 0) return false;
memset( &stbuf, 0, sizeof(struct stat));
if( lstat( fileName, &stbuf ) != 0)
return false;
int size = stbuf.st_size; int 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) {
{ rWarning("Partial read of config file, expecting %i bytes, got %i", size,
rWarning("Partial read of config file, expecting %i bytes, got %i", res);
size, res);
delete[] buf;
return false;
}
ConfigVar in;
in.write( (unsigned char *)buf, size );
delete[] buf; delete[] buf;
return false;
}
return loadFromVar( in ); ConfigVar in;
in.write((unsigned char *)buf, size);
delete[] buf;
return loadFromVar(in);
} }
bool bool ConfigReader::loadFromVar(ConfigVar &in) {
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) {
{ rError("Invalid key encoding in buffer");
rError("Invalid key encoding in buffer"); return false;
return false;
}
ConfigVar newVar( value );
vars.insert( make_pair( key, newVar ) );
} }
ConfigVar newVar(value);
vars.insert(make_pair(key, newVar));
}
return true; return true;
} }
bool bool ConfigReader::save(const char *fileName) const {
ConfigReader::save(const char *fileName) const // write everything to a ConfigVar, then output to disk
{ ConfigVar out = toVar();
// write everything to a ConfigVar, then output to disk
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()) rError("Error writing to config file %s", fileName);
{ return false;
rError("Error writing to config file %s", fileName);
return false;
}
} else
{
rError("Unable to open or create file %s", fileName);
return false;
} }
} else {
rError("Unable to open or create file %s", fileName);
return false;
}
return true; return true;
} }
ConfigVar ConfigVar ConfigReader::toVar() const {
ConfigReader::toVar() const // write everything to a ConfigVar, then output to disk
{ ConfigVar out;
// write everything to a ConfigVar, then output to disk out.writeInt(vars.size());
ConfigVar out; map<string, ConfigVar>::const_iterator it;
out.writeInt( vars.size() ); for (it = vars.begin(); it != vars.end(); ++it) {
map<string, ConfigVar>::const_iterator it; out.writeInt(it->first.size());
for(it = vars.begin(); it != vars.end(); ++it) out.write((unsigned char *)it->first.data(), it->first.size());
{ out.writeInt(it->second.size());
out.writeInt( it->first.size() ); out.write((unsigned char *)it->second.buffer(), it->second.size());
out.write( (unsigned char*)it->first.data(), it->first.size() ); }
out.writeInt( it->second.size() );
out.write( (unsigned char*)it->second.buffer(), it->second.size() );
}
return out; 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 ];
} }

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -17,7 +17,7 @@
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _ConfigReader_incl_ #ifndef _ConfigReader_incl_
#define _ConfigReader_incl_ #define _ConfigReader_incl_
@ -43,24 +43,22 @@
ConfigReader cfg; ConfigReader cfg;
cfg["cipher"] << cipher->interface(); cfg["cipher"] << cipher->interface();
*/ */
class ConfigReader class ConfigReader {
{ public:
public: ConfigReader();
ConfigReader(); ~ConfigReader();
~ConfigReader();
bool load(const char *fileName); bool load(const char *fileName);
bool save(const char *fileName) const; bool save(const char *fileName) const;
ConfigVar toVar() const; ConfigVar toVar() const;
bool loadFromVar( ConfigVar &var ); bool loadFromVar(ConfigVar &var);
ConfigVar operator[](const std::string &varName) const; ConfigVar operator[](const std::string &varName) const;
ConfigVar &operator[](const std::string &varName); ConfigVar &operator[](const std::string &varName);
private: private:
std::map<std::string, ConfigVar> vars; std::map<std::string, ConfigVar> vars;
}; };
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -26,227 +26,175 @@
using namespace rlog; using namespace rlog;
#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->buffer = buf;
{ pd->offset = 0;
pd->offset = 0;
} }
ConfigVar::ConfigVar(const std::string &buf) ConfigVar::ConfigVar(const ConfigVar &src) { pd = src.pd; }
: pd( new ConfigVarData )
{
pd->buffer = buf;
pd->offset = 0;
}
ConfigVar::ConfigVar(const ConfigVar &src) ConfigVar::~ConfigVar() { pd.reset(); }
{
pd = src.pd;
}
ConfigVar::~ConfigVar()
{
pd.reset();
}
ConfigVar & ConfigVar::operator = (const ConfigVar &src)
{
if(src.pd == pd)
return *this;
else
pd = src.pd;
ConfigVar &ConfigVar::operator=(const ConfigVar &src) {
if (src.pd == pd)
return *this; return *this;
else
pd = src.pd;
return *this;
} }
void ConfigVar::resetOffset() void ConfigVar::resetOffset() { pd->offset = 0; }
{
pd->offset = 0; int ConfigVar::read(unsigned char *buffer_, int bytes) const {
int toCopy = MIN(bytes, pd->buffer.size() - pd->offset);
if (toCopy > 0) memcpy(buffer_, pd->buffer.data() + pd->offset, toCopy);
pd->offset += toCopy;
return toCopy;
} }
int ConfigVar::read(unsigned char *buffer_, int bytes) const int ConfigVar::write(const unsigned char *data, int bytes) {
{ if (pd->buffer.size() == (unsigned int)pd->offset) {
int toCopy = MIN( bytes, pd->buffer.size() - pd->offset ); pd->buffer.append((const char *)data, bytes);
} else {
pd->buffer.insert(pd->offset, (const char *)data, bytes);
}
if(toCopy > 0) pd->offset += bytes;
memcpy( buffer_, pd->buffer.data() + pd->offset, toCopy );
pd->offset += toCopy; return bytes;
return toCopy;
} }
int ConfigVar::write(const unsigned char *data, int bytes) int ConfigVar::size() const { return pd->buffer.size(); }
{
if(pd->buffer.size() == (unsigned int)pd->offset)
{
pd->buffer.append( (const char *)data, bytes );
} else
{
pd->buffer.insert( pd->offset, (const char *)data, bytes );
}
pd->offset += bytes; const char *ConfigVar::buffer() const { return pd->buffer.data(); }
return bytes; int ConfigVar::at() const { return pd->offset; }
void ConfigVar::writeString(const char *data, int bytes) {
writeInt(bytes);
write((const unsigned char *)data, bytes);
} }
int ConfigVar::size() const
{
return pd->buffer.size();
}
const char *ConfigVar::buffer() const
{
return pd->buffer.data();
}
int ConfigVar::at() const
{
return pd->offset;
}
void ConfigVar::writeString(const char *data, int bytes)
{
writeInt( bytes );
write( (const unsigned char *)data, bytes );
}
// convert integer to BER encoded integer // 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 // second byte: 0x00003f80 0011,1111 1000,0000
// second byte: 0x00003f80 0011,1111 1000,0000 // third byte: 0x001fb000 0000,0000 0001,1111 1100,0000 0000,0000
// third byte: 0x001fb000 0000,0000 0001,1111 1100,0000 0000,0000 // fourth byte: 0x0fe00000 0000,1111 1110,0000
// fourth byte: 0x0fe00000 0000,1111 1110,0000 // fifth byte: 0xf0000000 1111,0000
// fifth byte: 0xf0000000 1111,0000 unsigned char digit[5];
unsigned char digit[5];
digit[4] = (unsigned char)((val & 0x0000007f)); digit[4] = (unsigned char)((val & 0x0000007f));
digit[3] = 0x80 | (unsigned char)((val & 0x00003f80) >> 7); digit[3] = 0x80 | (unsigned char)((val & 0x00003f80) >> 7);
digit[2] = 0x80 | (unsigned char)((val & 0x001fc000) >> 14); digit[2] = 0x80 | (unsigned char)((val & 0x001fc000) >> 14);
digit[1] = 0x80 | (unsigned char)((val & 0x0fe00000) >> 21); digit[1] = 0x80 | (unsigned char)((val & 0x0fe00000) >> 21);
digit[0] = 0x80 | (unsigned char)((val & 0xf0000000) >> 28); digit[0] = 0x80 | (unsigned char)((val & 0xf0000000) >> 28);
// 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 unsigned char *buf = (const unsigned char *)buffer();
const unsigned char * buf = (const unsigned char *)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 {
{ unsigned char tmp = buf[offset++];
unsigned char 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(); // rAssert(length > 0);
//rAssert(length > 0);
int readLen; int readLen;
unsigned char tmpBuf[32]; unsigned char tmpBuf[32];
if(length > (int)sizeof(tmpBuf)) if (length > (int)sizeof(tmpBuf)) {
{ unsigned char *ptr = new unsigned char[length];
unsigned char *ptr = new unsigned char[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);
{ result.assign((char *)tmpBuf, length);
readLen = src.read( tmpBuf, length ); }
result.assign( (char*)tmpBuf, length );
}
if(readLen != length) if (readLen != length) {
{ rDebug("string encoded as size %i bytes, read %i", length, readLen);
rDebug("string encoded as size %i bytes, read %i", length, readLen ); }
} rAssert(readLen == length);
rAssert(readLen == length);
return src; return src;
} }

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -24,58 +24,55 @@
#include <string> #include <string>
#include "shared_ptr.h" #include "shared_ptr.h"
class ConfigVar class ConfigVar {
{ struct ConfigVarData {
struct ConfigVarData std::string buffer;
{ int offset;
std::string buffer; };
int offset;
};
shared_ptr<ConfigVarData> pd; shared_ptr<ConfigVarData> pd;
public: public:
ConfigVar(); ConfigVar();
ConfigVar(const std::string &buffer); ConfigVar(const std::string &buffer);
ConfigVar(const ConfigVar &src); ConfigVar(const ConfigVar &src);
~ConfigVar(); ~ConfigVar();
ConfigVar & operator = (const ConfigVar &src); ConfigVar &operator=(const ConfigVar &src);
// reset read/write offset.. // reset read/write offset..
void resetOffset(); void resetOffset();
// read bytes // read bytes
int read(unsigned char *buffer, int size) const; int read(unsigned char *buffer, int size) const;
// write bytes.. // write bytes..
int write(const unsigned char *data, int size); int write(const unsigned char *data, int size);
int readInt() const; int readInt() const;
int readInt( int defaultValue ) const; int readInt(int defaultValue) const;
void writeInt(int value); void writeInt(int value);
bool readBool( bool defaultValue ) const; bool readBool(bool defaultValue) const;
void writeString(const char *data, int size); void writeString(const char *data, int size);
// return amount of data in var // return amount of data in var
int size() const; int size() const;
// return data pointer - returns front of data pointer, not the current // return data pointer - returns front of data pointer, not the current
// position. // position.
const char *buffer() const; const char *buffer() const;
// return current position in data() buffer. // return current position in data() buffer.
int at() const; int at() const;
}; };
ConfigVar & operator << (ConfigVar &, bool); ConfigVar &operator<<(ConfigVar &, bool);
ConfigVar & operator << (ConfigVar &, int); ConfigVar &operator<<(ConfigVar &, int);
ConfigVar & operator << (ConfigVar &, const std::string &str); ConfigVar &operator<<(ConfigVar &, const std::string &str);
const ConfigVar & operator >> (const ConfigVar &, bool &); const ConfigVar &operator>>(const ConfigVar &, bool &);
const ConfigVar & operator >> (const ConfigVar &, int &); const ConfigVar &operator>>(const ConfigVar &, int &);
const ConfigVar & operator >> (const ConfigVar &, std::string &str); const ConfigVar &operator>>(const ConfigVar &, std::string &str);
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -29,149 +29,126 @@
using namespace rel; using namespace rel;
using namespace rlog; using namespace rlog;
EncFS_Context::EncFS_Context() EncFS_Context::EncFS_Context() {
{ pthread_cond_init(&wakeupCond, 0);
pthread_cond_init( &wakeupCond, 0 ); pthread_mutex_init(&wakeupMutex, 0);
pthread_mutex_init( &wakeupMutex, 0 ); pthread_mutex_init(&contextMutex, 0);
pthread_mutex_init( &contextMutex, 0 );
usageCount = 0; usageCount = 0;
} }
EncFS_Context::~EncFS_Context() EncFS_Context::~EncFS_Context() {
{ pthread_mutex_destroy(&contextMutex);
pthread_mutex_destroy( &contextMutex ); pthread_mutex_destroy(&wakeupMutex);
pthread_mutex_destroy( &wakeupMutex ); pthread_cond_destroy(&wakeupCond);
pthread_cond_destroy( &wakeupCond );
// 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)
{
int res = remountFS( this );
if(res != 0)
{
*errCode = res;
break;
}
}
} while(!ret);
return ret;
}
void EncFS_Context::setRoot(const shared_ptr<DirNode> &r)
{
Lock lock( contextMutex );
root = r;
if(r)
rootCipherDir = r->rootDirectory();
}
bool EncFS_Context::isMounted()
{
return root;
}
int EncFS_Context::getAndResetUsageCounter()
{
Lock lock( contextMutex );
int count = usageCount;
usageCount = 0;
return count;
}
int EncFS_Context::openFileCount() const
{
Lock lock( contextMutex );
return openFiles.size();
}
shared_ptr<FileNode> EncFS_Context::lookupNode(const char *path)
{
Lock lock( contextMutex );
FileMap::iterator it = openFiles.find( std::string(path) );
if(it != openFiles.end())
{
// all the items in the set point to the same node.. so just use the
// first
return (*it->second.begin())->node;
} else
{
return shared_ptr<FileNode>();
}
}
void EncFS_Context::renameNode(const char *from, const char *to)
{
Lock lock( contextMutex );
FileMap::iterator it = openFiles.find( std::string(from) );
if(it != openFiles.end())
{
std::set<Placeholder *> val = it->second;
openFiles.erase(it);
openFiles[ std::string(to) ] = val;
}
}
shared_ptr<FileNode> EncFS_Context::getNode(void *pl)
{
Placeholder *ph = (Placeholder*)pl;
return ph->node;
}
void *EncFS_Context::putNode(const char *path,
const shared_ptr<FileNode> &node)
{
Lock lock( contextMutex );
Placeholder *pl = new Placeholder( node );
openFiles[ std::string(path) ].insert(pl);
return (void *)pl;
}
void EncFS_Context::eraseNode(const char *path, void *pl)
{
Lock lock( contextMutex );
Placeholder *ph = (Placeholder *)pl;
FileMap::iterator it = openFiles.find( std::string(path) );
rAssert(it != openFiles.end());
int rmCount = it->second.erase( ph );
rAssert(rmCount == 1);
// if no more references to this file, remove the record all together
if(it->second.empty())
{
// attempts to make use of shallow copy to clear memory used to hold
// unencrypted filenames.. not sure this does any good..
std::string storedName = it->first;
openFiles.erase( it );
storedName.assign( storedName.length(), '\0' );
} }
delete ph; if (!ret) {
int res = remountFS(this);
if (res != 0) {
*errCode = res;
break;
}
}
} while (!ret);
return ret;
} }
void EncFS_Context::setRoot(const shared_ptr<DirNode> &r) {
Lock lock(contextMutex);
root = r;
if (r) rootCipherDir = r->rootDirectory();
}
bool EncFS_Context::isMounted() { return root; }
int EncFS_Context::getAndResetUsageCounter() {
Lock lock(contextMutex);
int count = usageCount;
usageCount = 0;
return count;
}
int EncFS_Context::openFileCount() const {
Lock lock(contextMutex);
return openFiles.size();
}
shared_ptr<FileNode> EncFS_Context::lookupNode(const char *path) {
Lock lock(contextMutex);
FileMap::iterator it = openFiles.find(std::string(path));
if (it != openFiles.end()) {
// all the items in the set point to the same node.. so just use the
// first
return (*it->second.begin())->node;
} else {
return shared_ptr<FileNode>();
}
}
void EncFS_Context::renameNode(const char *from, const char *to) {
Lock lock(contextMutex);
FileMap::iterator it = openFiles.find(std::string(from));
if (it != openFiles.end()) {
std::set<Placeholder *> val = it->second;
openFiles.erase(it);
openFiles[std::string(to)] = val;
}
}
shared_ptr<FileNode> EncFS_Context::getNode(void *pl) {
Placeholder *ph = (Placeholder *)pl;
return ph->node;
}
void *EncFS_Context::putNode(const char *path,
const shared_ptr<FileNode> &node) {
Lock lock(contextMutex);
Placeholder *pl = new Placeholder(node);
openFiles[std::string(path)].insert(pl);
return (void *)pl;
}
void EncFS_Context::eraseNode(const char *path, void *pl) {
Lock lock(contextMutex);
Placeholder *ph = (Placeholder *)pl;
FileMap::iterator it = openFiles.find(std::string(path));
rAssert(it != openFiles.end());
int rmCount = it->second.erase(ph);
rAssert(rmCount == 1);
// if no more references to this file, remove the record all together
if (it->second.empty()) {
// attempts to make use of shallow copy to clear memory used to hold
// unencrypted filenames.. not sure this does any good..
std::string storedName = it->first;
openFiles.erase(it);
storedName.assign(storedName.length(), '\0');
}
delete ph;
}

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -37,75 +37,70 @@ 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();
shared_ptr<FileNode> getNode(void *ptr); shared_ptr<FileNode> getNode(void *ptr);
shared_ptr<FileNode> lookupNode(const char *path); shared_ptr<FileNode> lookupNode(const char *path);
int getAndResetUsageCounter(); int getAndResetUsageCounter();
int openFileCount() const; int openFileCount() const;
void *putNode(const char *path, const shared_ptr<FileNode> &node); void *putNode(const char *path, const shared_ptr<FileNode> &node);
void eraseNode(const char *path, void *placeholder); void eraseNode(const char *path, void *placeholder);
void renameNode(const char *oldName, const char *newName); void renameNode(const char *oldName, const char *newName);
void setRoot(const shared_ptr<DirNode> &root); void setRoot(const shared_ptr<DirNode> &root);
shared_ptr<DirNode> getRoot(int *err); shared_ptr<DirNode> getRoot(int *err);
bool isMounted(); bool isMounted();
shared_ptr<EncFS_Args> args; shared_ptr<EncFS_Args> args;
shared_ptr<EncFS_Opts> opts; shared_ptr<EncFS_Opts> opts;
bool publicFilesystem; bool publicFilesystem;
// root path to cipher dir // root path to cipher dir
std::string rootCipherDir; std::string rootCipherDir;
// for idle monitor // for idle monitor
bool running; bool running;
pthread_t monitorThread; pthread_t monitorThread;
pthread_cond_t wakeupCond; pthread_cond_t wakeupCond;
pthread_mutex_t wakeupMutex; pthread_mutex_t wakeupMutex;
private: private:
/* This placeholder is what is referenced in FUSE context (passed to /* This placeholder is what is referenced in FUSE context (passed to
* callbacks). * callbacks).
* *
* A FileNode may be opened many times, but only one FileNode instance per * A FileNode may be opened many times, but only one FileNode instance per
* file is kept. Rather then doing reference counting in FileNode, we * file is kept. Rather then doing reference counting in FileNode, we
* store a unique Placeholder for each open() until the corresponding * store a unique Placeholder for each open() until the corresponding
* 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
#ifdef USE_HASHMAP #ifdef USE_HASHMAP
typedef __gnu_cxx::hash_map<std::string, // set of open files, indexed by path
std::set<Placeholder*> > FileMap; typedef __gnu_cxx::hash_map<std::string, std::set<Placeholder *> > FileMap;
#else #else
typedef std::map< std::string, typedef std::map<std::string, std::set<Placeholder *> > FileMap;
std::set<Placeholder*> > FileMap;
#endif #endif
mutable pthread_mutex_t contextMutex; mutable pthread_mutex_t contextMutex;
FileMap openFiles; FileMap openFiles;
int usageCount; int usageCount;
shared_ptr<DirNode> root; shared_ptr<DirNode> root;
}; };
int remountFS( EncFS_Context *ctx ); int remountFS(EncFS_Context *ctx);
#endif #endif

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -28,105 +28,98 @@
#include "CipherKey.h" #include "CipherKey.h"
#include "shared_ptr.h" #include "shared_ptr.h"
enum ConfigType enum ConfigType {
{ Config_None = 0,
Config_None = 0, Config_Prehistoric,
Config_Prehistoric, Config_V3,
Config_V3, Config_V4,
Config_V4, Config_V5,
Config_V5, Config_V6
Config_V6
}; };
struct EncFS_Opts; struct EncFS_Opts;
class Cipher; class Cipher;
class NameIO; class NameIO;
struct EncFSConfig struct EncFSConfig {
{ ConfigType cfgType;
ConfigType cfgType;
std::string creator; std::string creator;
int subVersion; int subVersion;
// interface of cipher // interface of cipher
rel::Interface cipherIface; rel::Interface cipherIface;
// interface used for file name coding // interface used for file name coding
rel::Interface nameIface; rel::Interface nameIface;
int keySize; // reported in bits int keySize; // reported in bits
int blockSize; // reported in bytes int blockSize; // reported in bytes
std::vector<unsigned char> keyData; std::vector<unsigned char> keyData;
std::vector<unsigned char> salt; std::vector<unsigned char> salt;
int kdfIterations; int kdfIterations;
long desiredKDFDuration; long desiredKDFDuration;
int blockMACBytes; // MAC headers on blocks.. int blockMACBytes; // MAC headers on blocks..
int blockMACRandBytes; // number of random bytes in the block header int blockMACRandBytes; // number of random bytes in the block header
bool uniqueIV; // per-file Initialization Vector bool uniqueIV; // per-file Initialization Vector
bool externalIVChaining; // IV seeding by filename IV chaining bool externalIVChaining; // IV seeding by filename IV chaining
bool chainedNameIV; // filename IV chaining bool chainedNameIV; // filename IV chaining
bool allowHoles; // allow holes in files (implicit zero blocks) bool allowHoles; // allow holes in files (implicit zero blocks)
EncFSConfig() EncFSConfig() : keyData(), salt() {
: keyData() cfgType = Config_None;
, salt() subVersion = 0;
{ blockMACBytes = 0;
cfgType = Config_None; blockMACRandBytes = 0;
subVersion = 0; uniqueIV = false;
blockMACBytes = 0; externalIVChaining = false;
blockMACRandBytes = 0; chainedNameIV = false;
uniqueIV = false; allowHoles = false;
externalIVChaining = false;
chainedNameIV = false;
allowHoles = false;
kdfIterations = 0; kdfIterations = 0;
desiredKDFDuration = 500; desiredKDFDuration = 500;
} }
CipherKey getUserKey(bool useStdin); CipherKey getUserKey(bool useStdin);
CipherKey getUserKey(const std::string &passwordProgram, CipherKey getUserKey(const std::string &passwordProgram,
const std::string &rootDir); const std::string &rootDir);
CipherKey getNewUserKey(); CipherKey getNewUserKey();
shared_ptr<Cipher> getCipher() const;
// deprecated shared_ptr<Cipher> getCipher() const;
void assignKeyData(const std::string &in);
void assignKeyData(unsigned char *data, int length);
void assignSaltData(unsigned char *data, int length);
unsigned char *getKeyData() const; // deprecated
unsigned char *getSaltData() const; void assignKeyData(const std::string &in);
void assignKeyData(unsigned char *data, int length);
void assignSaltData(unsigned char *data, int length);
private: unsigned char *getKeyData() const;
CipherKey makeKey(const char *password, int passwdLen); unsigned char *getSaltData() const;
private:
CipherKey makeKey(const char *password, int passwdLen);
}; };
// 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);
struct FSConfig struct FSConfig {
{ shared_ptr<EncFSConfig> config;
shared_ptr<EncFSConfig> config; shared_ptr<EncFS_Opts> opts;
shared_ptr<EncFS_Opts> opts;
shared_ptr<Cipher> cipher; shared_ptr<Cipher> cipher;
CipherKey key; CipherKey key;
shared_ptr<NameIO> nameCoding; shared_ptr<NameIO> nameCoding;
bool forceDecode; // force decode on MAC block failures bool forceDecode; // force decode on MAC block failures
bool reverseEncryption; // reverse encryption operation bool reverseEncryption; // reverse encryption operation
bool idleTracking; // turn on idle monitoring of filesystem bool idleTracking; // turn on idle monitoring of filesystem
}; };
typedef shared_ptr<FSConfig> FSConfigPtr; typedef shared_ptr<FSConfig> FSConfigPtr;
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -20,22 +20,13 @@
#include "FileIO.h" #include "FileIO.h"
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;
} }

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -27,61 +27,54 @@
#include "Interface.h" #include "Interface.h"
struct IORequest struct IORequest {
{ off_t offset;
off_t offset;
// amount of bytes to read/write. // amount of bytes to read/write.
int dataLen; int dataLen;
unsigned char *data; unsigned char *data;
IORequest(); IORequest();
}; };
inline IORequest::IORequest() inline IORequest::IORequest() : offset(0), dataLen(0), data(0) {}
: offset(0)
, dataLen(0)
, data(0)
{
}
class FileIO class FileIO {
{ public:
public: FileIO();
FileIO(); virtual ~FileIO();
virtual ~FileIO();
virtual rel::Interface interface() const =0; virtual rel::Interface interface() const = 0;
// default implementation returns 1, meaning this is not block oriented. // default implementation returns 1, meaning this is not block oriented.
virtual int blockSize() const; virtual int blockSize() const;
virtual void setFileName(const char *fileName) =0; virtual void setFileName(const char *fileName) = 0;
virtual const char *getFileName() const =0; virtual const char *getFileName() const = 0;
// Not sure about this -- it is specific to CipherFileIO, but the // Not sure about this -- it is specific to CipherFileIO, but the
// alternative methods of exposing this interface aren't much nicer.. // alternative methods of exposing this interface aren't much nicer..
virtual bool setIV( uint64_t iv ); virtual bool setIV(uint64_t iv);
// open file for specified mode. There is no corresponding close, so a // open file for specified mode. There is no corresponding close, so a
// file is open until the FileIO interface is destroyed. // file is open until the FileIO interface is destroyed.
virtual int open( int flags ) =0; virtual int open(int flags) = 0;
// get filesystem attributes for a file
virtual int getAttr( struct stat *stbuf ) const =0;
virtual off_t getSize( ) const =0;
virtual ssize_t read( const IORequest &req ) const =0; // get filesystem attributes for a file
virtual bool write( const IORequest &req ) =0; virtual int getAttr(struct stat *stbuf) const = 0;
virtual off_t getSize() const = 0;
virtual int truncate( off_t size ) =0; virtual ssize_t read(const IORequest &req) const = 0;
virtual bool write(const IORequest &req) = 0;
virtual bool isWritable() const =0; virtual int truncate(off_t size) = 0;
private:
// not implemented.. virtual bool isWritable() const = 0;
FileIO( const FileIO & );
FileIO &operator = ( const FileIO & ); private:
// not implemented..
FileIO(const FileIO &);
FileIO &operator=(const FileIO &);
}; };
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -66,242 +66,202 @@ using namespace rlog;
static RLogChannel *Info = DEF_CHANNEL("info/FileNode", Log_Info); static RLogChannel *Info = DEF_CHANNEL("info/FileNode", Log_Info);
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_) {
{ pthread_mutex_init(&mutex, 0);
pthread_mutex_init( &mutex, 0 );
Lock _lock( mutex );
this->_pname = plaintextName_; Lock _lock(mutex);
this->_cname = cipherName_;
this->parent = parent_;
this->fsConfig = cfg; this->_pname = plaintextName_;
this->_cname = cipherName_;
this->parent = parent_;
// chain RawFileIO & CipherFileIO this->fsConfig = cfg;
shared_ptr<FileIO> rawIO( new RawFileIO( _cname ) );
io = shared_ptr<FileIO>( new CipherFileIO( rawIO, fsConfig ));
if(cfg->config->blockMACBytes || cfg->config->blockMACRandBytes) // chain RawFileIO & CipherFileIO
io = shared_ptr<FileIO>(new MACFileIO(io, fsConfig)); shared_ptr<FileIO> rawIO(new RawFileIO(_cname));
io = shared_ptr<FileIO>(new CipherFileIO(rawIO, fsConfig));
if (cfg->config->blockMACBytes || cfg->config->blockMACRandBytes)
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 // pthread_mutex_lock( &mutex );
//pthread_mutex_lock( &mutex );
_pname.assign( _pname.length(), '\0' ); _pname.assign(_pname.length(), '\0');
_cname.assign( _cname.length(), '\0' ); _cname.assign(_cname.length(), '\0');
io.reset(); io.reset();
pthread_mutex_destroy( &mutex ); pthread_mutex_destroy(&mutex);
} }
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)
{
struct stat stbuf;
if((io->getAttr(&stbuf) < 0) || S_ISREG(stbuf.st_mode))
return io->setIV( iv );
else
return true;
}
bool FileNode::setName( const char *plaintextName_, const char *cipherName_,
uint64_t iv, bool setIVFirst )
{
//Lock _lock( mutex );
rDebug("calling setIV on %s", cipherName_);
if(setIVFirst)
{
if(fsConfig->config->externalIVChaining && !setIV(io, iv))
return false;
// now change the name..
if(plaintextName_)
this->_pname = plaintextName_;
if(cipherName_)
{
this->_cname = cipherName_;
io->setFileName( cipherName_ );
}
} else
{
std::string oldPName = _pname;
std::string oldCName = _cname;
if(plaintextName_)
this->_pname = plaintextName_;
if(cipherName_)
{
this->_cname = cipherName_;
io->setFileName( cipherName_ );
}
if(fsConfig->config->externalIVChaining && !setIV(io, iv))
{
_pname = oldPName;
_cname = oldCName;
return false;
}
}
static bool setIV(const shared_ptr<FileIO> &io, uint64_t iv) {
struct stat stbuf;
if ((io->getAttr(&stbuf) < 0) || S_ISREG(stbuf.st_mode))
return io->setIV(iv);
else
return true; return true;
} }
int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid) bool FileNode::setName(const char *plaintextName_, const char *cipherName_,
{ uint64_t iv, bool setIVFirst) {
Lock _lock( mutex ); // Lock _lock( mutex );
rDebug("calling setIV on %s", cipherName_);
if (setIVFirst) {
if (fsConfig->config->externalIVChaining && !setIV(io, iv)) return false;
int res; // now change the name..
int olduid = -1; if (plaintextName_) this->_pname = plaintextName_;
int oldgid = -1; if (cipherName_) {
if(uid != 0) this->_cname = cipherName_;
{ io->setFileName(cipherName_);
olduid = setfsuid( uid );
if(olduid == -1)
{
rInfo("setfsuid error: %s", strerror(errno));
return -EPERM;
}
} }
if(gid != 0) } else {
{ std::string oldPName = _pname;
oldgid = setfsgid( gid ); std::string oldCName = _cname;
if(oldgid == -1)
{ if (plaintextName_) this->_pname = plaintextName_;
rInfo("setfsgid error: %s", strerror(errno)); if (cipherName_) {
return -EPERM; this->_cname = cipherName_;
} io->setFileName(cipherName_);
} }
/* if (fsConfig->config->externalIVChaining && !setIV(io, iv)) {
* cf. xmp_mknod() in fusexmp.c _pname = oldPName;
* The regular file stuff could be stripped off if there _cname = oldCName;
* were a create method (advised to have) return false;
*/
if (S_ISREG( mode )) {
res = ::open( _cname.c_str(), O_CREAT | O_EXCL | O_WRONLY, mode );
if (res >= 0)
res = ::close( res );
} else if (S_ISFIFO( mode ))
res = ::mkfifo( _cname.c_str(), mode );
else
res = ::mknod( _cname.c_str(), mode, rdev );
if(olduid >= 0)
setfsuid( olduid );
if(oldgid >= 0)
setfsgid( oldgid );
if(res == -1)
{
int eno = errno;
rDebug("mknod error: %s", strerror(eno));
res = -eno;
} }
}
return res; return true;
} }
int FileNode::open(int flags) const int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid) {
{ Lock _lock(mutex);
Lock _lock( mutex );
int res = io->open( flags ); int res;
return res; int olduid = -1;
int oldgid = -1;
if (uid != 0) {
olduid = setfsuid(uid);
if (olduid == -1) {
rInfo("setfsuid error: %s", strerror(errno));
return -EPERM;
}
}
if (gid != 0) {
oldgid = setfsgid(gid);
if (oldgid == -1) {
rInfo("setfsgid error: %s", strerror(errno));
return -EPERM;
}
}
/*
* cf. xmp_mknod() in fusexmp.c
* The regular file stuff could be stripped off if there
* were a create method (advised to have)
*/
if (S_ISREG(mode)) {
res = ::open(_cname.c_str(), O_CREAT | O_EXCL | O_WRONLY, mode);
if (res >= 0) res = ::close(res);
} else if (S_ISFIFO(mode))
res = ::mkfifo(_cname.c_str(), mode);
else
res = ::mknod(_cname.c_str(), mode, rdev);
if (olduid >= 0) setfsuid(olduid);
if (oldgid >= 0) setfsgid(oldgid);
if (res == -1) {
int eno = errno;
rDebug("mknod error: %s", strerror(eno));
res = -eno;
}
return res;
} }
int FileNode::getAttr(struct stat *stbuf) const int FileNode::open(int flags) const {
{ Lock _lock(mutex);
Lock _lock( mutex );
int res = io->getAttr( stbuf ); int res = io->open(flags);
return res; return res;
} }
off_t FileNode::getSize() const int FileNode::getAttr(struct stat *stbuf) const {
{ Lock _lock(mutex);
Lock _lock( mutex );
int res = io->getSize(); int res = io->getAttr(stbuf);
return res; return res;
} }
ssize_t FileNode::read( off_t offset, unsigned char *data, ssize_t size ) const off_t FileNode::getSize() const {
{ Lock _lock(mutex);
IORequest req;
req.offset = offset;
req.dataLen = size;
req.data = data;
Lock _lock( mutex ); int res = io->getSize();
return res;
return io->read( req );
} }
bool FileNode::write(off_t offset, unsigned char *data, ssize_t size) ssize_t FileNode::read(off_t offset, unsigned char *data, ssize_t size) const {
{ IORequest req;
rLog(Info, "FileNode::write offset %" PRIi64 ", data size %i", req.offset = offset;
offset, (int)size); req.dataLen = size;
req.data = data;
IORequest req; Lock _lock(mutex);
req.offset = offset;
req.dataLen = size;
req.data = data;
Lock _lock( mutex );
return io->write( req ); return io->read(req);
} }
int FileNode::truncate( off_t size ) bool FileNode::write(off_t offset, unsigned char *data, ssize_t size) {
{ rLog(Info, "FileNode::write offset %" PRIi64 ", data size %i", offset,
Lock _lock( mutex ); (int)size);
return io->truncate( size ); IORequest req;
req.offset = offset;
req.dataLen = size;
req.data = data;
Lock _lock(mutex);
return io->write(req);
} }
int FileNode::sync(bool datasync) int FileNode::truncate(off_t size) {
{ Lock _lock(mutex);
Lock _lock( mutex );
int fh = io->open( O_RDONLY ); return io->truncate(size);
if(fh >= 0) }
{
int res = -EIO; int FileNode::sync(bool datasync) {
Lock _lock(mutex);
int fh = io->open(O_RDONLY);
if (fh >= 0) {
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
(void)datasync; (void)datasync;
// 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)
res = -errno;
return res; if (res == -1) res = -errno;
} else
return fh; return res;
} else
return fh;
} }

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -17,7 +17,7 @@
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _FileUtils_incl_ #ifndef _FileUtils_incl_
#define _FileUtils_incl_ #define _FileUtils_incl_
@ -27,118 +27,106 @@
#include "FSConfig.h" #include "FSConfig.h"
// 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 Cipher; class Cipher;
class DirNode; class DirNode;
struct EncFS_Root struct EncFS_Root {
{ shared_ptr<Cipher> cipher;
shared_ptr<Cipher> cipher; CipherKey volumeKey;
CipherKey volumeKey; shared_ptr<DirNode> root;
shared_ptr<DirNode> root;
EncFS_Root(); EncFS_Root();
~EncFS_Root(); ~EncFS_Root();
}; };
typedef shared_ptr<EncFS_Root> RootPtr; typedef shared_ptr<EncFS_Root> RootPtr;
enum ConfigMode enum ConfigMode { Config_Prompt, Config_Standard, Config_Paranoia };
{
Config_Prompt,
Config_Standard,
Config_Paranoia
};
struct EncFS_Opts struct EncFS_Opts {
{ std::string rootDir;
std::string rootDir; bool createIfNotFound; // create filesystem if not found
bool createIfNotFound; // create filesystem if not found bool idleTracking; // turn on idle monitoring of filesystem
bool idleTracking; // turn on idle monitoring of filesystem bool mountOnDemand; // mounting on-demand
bool mountOnDemand; // mounting on-demand bool delayMount; // delay initial mount
bool delayMount; // delay initial mount
bool checkKey; // check crypto key decoding bool checkKey; // check crypto key decoding
bool forceDecode; // force decode on MAC block failures bool forceDecode; // force decode on MAC block failures
std::string passwordProgram; // path to password program (or empty) std::string passwordProgram; // path to password program (or empty)
bool useStdin; // read password from stdin rather then prompting bool useStdin; // read password from stdin rather then prompting
bool annotate; // print annotation line prompt to stderr. bool annotate; // print annotation line prompt to stderr.
bool ownerCreate; // set owner of new files to caller bool ownerCreate; // set owner of new files to caller
bool reverseEncryption; // Reverse encryption bool reverseEncryption; // Reverse encryption
ConfigMode configMode; ConfigMode configMode;
EncFS_Opts() EncFS_Opts() {
{ createIfNotFound = true;
createIfNotFound = true; idleTracking = false;
idleTracking = false; mountOnDemand = false;
mountOnDemand = false; delayMount = false;
delayMount = false; checkKey = true;
checkKey = true; forceDecode = false;
forceDecode = false; useStdin = false;
useStdin = false; annotate = false;
annotate = false; ownerCreate = false;
ownerCreate = false; reverseEncryption = false;
reverseEncryption = false; configMode = Config_Prompt;
configMode = Config_Prompt; }
}
}; };
/* /*
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, ConfigType readConfig(const std::string &rootDir,
const shared_ptr<EncFSConfig> &config ); const shared_ptr<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( ConfigType type, const std::string &rootdir, bool saveConfig(ConfigType type, const std::string &rootdir,
const shared_ptr<EncFSConfig> &config ); const shared_ptr<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 createV6Config( EncFS_Context *ctx, RootPtr createV6Config(EncFS_Context *ctx, const shared_ptr<EncFS_Opts> &opts);
const shared_ptr<EncFS_Opts> &opts );
void showFSInfo( const shared_ptr<EncFSConfig> &config ); void showFSInfo(const shared_ptr<EncFSConfig> &config);
bool readV4Config( const char *configFile, bool readV4Config(const char *configFile, const shared_ptr<EncFSConfig> &config,
const shared_ptr<EncFSConfig> &config, struct ConfigInfo *);
struct ConfigInfo *); bool writeV4Config(const char *configFile,
bool writeV4Config( const char *configFile, const shared_ptr<EncFSConfig> &config);
const shared_ptr<EncFSConfig> &config);
bool readV5Config( const char *configFile, bool readV5Config(const char *configFile, const shared_ptr<EncFSConfig> &config,
const shared_ptr<EncFSConfig> &config, struct ConfigInfo *);
struct ConfigInfo *); bool writeV5Config(const char *configFile,
bool writeV5Config( const char *configFile, const shared_ptr<EncFSConfig> &config);
const shared_ptr<EncFSConfig> &config);
bool readV6Config( const char *configFile, bool readV6Config(const char *configFile, const shared_ptr<EncFSConfig> &config,
const shared_ptr<EncFSConfig> &config, struct ConfigInfo *);
struct ConfigInfo *); bool writeV6Config(const char *configFile,
bool writeV6Config( const char *configFile, const shared_ptr<EncFSConfig> &config);
const shared_ptr<EncFSConfig> &config);
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -17,7 +17,7 @@
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Interface.h" #include "Interface.h"
#include "ConfigVar.h" #include "ConfigVar.h"
@ -28,106 +28,58 @@
using namespace rel; using namespace rel;
using namespace rlog; using namespace rlog;
static RLogChannel * Info = DEF_CHANNEL( "info/iface", Log_Info ); static RLogChannel *Info = DEF_CHANNEL("info/iface", Log_Info);
Interface::Interface(const char *name_, int Current, int Revision, int Age) Interface::Interface(const char *name_, int Current, int Revision, int Age)
: _name( name_ ) : _name(name_), _current(Current), _revision(Revision), _age(Age) {}
, _current( Current )
, _revision( Revision )
, _age( Age )
{
}
Interface::Interface(const std::string &name_, int Current, Interface::Interface(const std::string &name_, int Current, int Revision,
int Revision, int Age) int Age)
: _name( name_ ) : _name(name_), _current(Current), _revision(Revision), _age(Age) {}
, _current( Current )
, _revision( Revision )
, _age( Age )
{
}
Interface::Interface(const Interface &src) Interface::Interface(const Interface &src)
: _name( src._name ) : _name(src._name),
, _current( src._current ) _current(src._current),
, _revision( src._revision ) _revision(src._revision),
, _age( src._age ) _age(src._age) {}
{
Interface::Interface() : _current(0), _revision(0), _age(0) {}
Interface &Interface::operator=(const Interface &src) {
_name = src._name;
_current = src._current;
_revision = src._revision;
_age = src._age;
return *this;
} }
Interface::Interface() const std::string &Interface::name() const { return _name; }
: _current( 0 )
, _revision( 0 ) std::string &Interface::name() { return _name; }
, _age( 0 )
{ int Interface::current() const { return _current; }
int &Interface::current() { return _current; }
int Interface::revision() const { return _revision; }
int &Interface::revision() { return _revision; }
int Interface::age() const { return _age; }
int &Interface::age() { return _age; }
bool operator==(const Interface &A, const Interface &B) {
return (A.name() == B.name() && A.current() == B.current() &&
A.revision() == B.revision() && A.age() == B.age());
} }
Interface &Interface::operator = (const Interface &src) bool operator!=(const Interface &A, const Interface &B) {
{ return (A.name() != B.name() || A.current() != B.current() ||
_name = src._name; A.revision() != B.revision() || A.age() != B.age());
_current = src._current;
_revision = src._revision;
_age = src._age;
return *this;
} }
const std::string & Interface::name() const // zero branch method of getting comparison sign..
{
return _name;
}
std::string & Interface::name()
{
return _name;
}
int Interface::current() const
{
return _current;
}
int &Interface::current()
{
return _current;
}
int Interface::revision() const
{
return _revision;
}
int &Interface::revision()
{
return _revision;
}
int Interface::age() const
{
return _age;
}
int &Interface::age()
{
return _age;
}
bool operator == (const Interface &A, const Interface &B)
{
return ( A.name() == B.name()
&& A.current() == B.current()
&& A.revision() == B.revision()
&& A.age() == B.age() );
}
bool operator != (const Interface &A, const Interface &B)
{
return ( A.name() != B.name()
|| A.current() != B.current()
|| A.revision() != B.revision()
|| A.age() != B.age() );
}
// zero branch method of getting comparison sign..
// tricky.. makes assumptions // tricky.. makes assumptions
#if 0 #if 0
static int sign( int a, int b ) static int sign( int a, int b )
@ -139,91 +91,74 @@ static int sign( int a, int b )
} }
#else #else
// simple, easy to check, unlikely to break due to unforseen events.. // simple, easy to check, unlikely to break due to unforseen events..
static int sign( int a, int b ) static int sign(int a, int b) {
{ if (a < b)
if(a < b) return 0;
return 0; else if (a == b)
else if(a == b) return 1;
return 1; else
else return 2;
return 2;
} }
#endif #endif
static int diffSum( const Interface &A, const Interface &B ) static int diffSum(const Interface &A, const Interface &B) {
{ int cS = sign(A.current(), B.current());
int cS = sign( A.current() , B.current() ); int aS = sign(A.age(), B.age());
int aS = sign( A.age(), B.age() ); int rS = sign(A.revision(), B.revision());
int rS = sign( A.revision(), B.revision() );
return (cS * 3 + aS) * 3 + rS; return (cS * 3 + aS) * 3 + rS;
} }
const int EqualVersion = (1 * 3 + 1) * 3 + 1; const int EqualVersion = (1 * 3 + 1) * 3 + 1;
bool Interface::implements(const Interface &B) const bool Interface::implements(const Interface &B) const {
{ rLog(Info, "checking if %s(%i:%i:%i) implements %s(%i:%i:%i)", name().c_str(),
rLog(Info, "checking if %s(%i:%i:%i) implements %s(%i:%i:%i)", current(), revision(), age(), B.name().c_str(), B.current(),
name().c_str(), current(), revision(), age(), B.revision(), B.age());
B.name().c_str(), B.current(), B.revision(), B.age());
if( name() != B.name() ) if (name() != B.name()) return false;
return false;
int currentDiff = current() - B.current(); int currentDiff = current() - B.current();
return ( currentDiff >= 0 && currentDiff <= age() ); return (currentDiff >= 0 && currentDiff <= age());
} }
bool operator<(const Interface &A, const Interface &B) {
bool operator < (const Interface &A, const Interface &B) if (A.name() == B.name()) {
{ return (diffSum(A, B) < EqualVersion);
if( A.name() == B.name() ) } else
{ return A.name() < B.name();
return ( diffSum(A,B) < EqualVersion );
} else
return A.name() < B.name();
} }
bool operator > (const Interface &A, const Interface &B) bool operator>(const Interface &A, const Interface &B) {
{ if (A.name() == B.name()) {
if( A.name() == B.name() ) return (diffSum(A, B) > EqualVersion);
{ } else
return ( diffSum(A,B) > EqualVersion ); return A.name() < B.name();
} else
return A.name() < B.name();
} }
bool operator <= (const Interface &A, const Interface &B) bool operator<=(const Interface &A, const Interface &B) {
{ if (A.name() == B.name()) {
if( A.name() == B.name() ) return (diffSum(A, B) <= EqualVersion);
{ } else
return ( diffSum(A,B) <= EqualVersion ); return A.name() < B.name();
} else
return A.name() < B.name();
} }
bool operator >= (const Interface &A, const Interface &B) bool operator>=(const Interface &A, const Interface &B) {
{ if (A.name() == B.name()) {
if( A.name() == B.name() ) return (diffSum(A, B) >= EqualVersion);
{ } else
return ( diffSum(A,B) >= EqualVersion ); return A.name() < B.name();
} else
return A.name() < B.name();
} }
ConfigVar &operator<<(ConfigVar &dst, const rel::Interface &iface) {
ConfigVar & operator << (ConfigVar &dst, const rel::Interface &iface) dst << iface.name() << iface.current() << iface.revision() << iface.age();
{ return dst;
dst << iface.name() << iface.current() << iface.revision() << iface.age();
return dst;
} }
const ConfigVar & operator >> (const ConfigVar &src, Interface &iface) const ConfigVar &operator>>(const ConfigVar &src, Interface &iface) {
{ src >> iface.name();
src >> iface.name(); src >> iface.current();
src >> iface.current(); src >> iface.revision();
src >> iface.revision(); src >> iface.age();
src >> iface.age(); return src;
return src;
} }

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -26,62 +26,57 @@
class ConfigVar; class ConfigVar;
// part of REL library.. // part of REL library..
namespace rel namespace rel {
{
class Interface class Interface {
{ public:
public: /*!
Version numbers as described by libtool: info://libtool/versioning
Current - the most recent interface api that is implemented.
Revision - the implementation number of the current interface.
Age - the difference between the newest and oldest interfaces that
are implemented.
*/
Interface(const char *name, int Current, int Revision, int Age);
Interface(const std::string &name, int Current, int Revision, int Age);
Interface(const Interface &src);
Interface();
/*! // check if we implement the interface described by B.
Version numbers as described by libtool: info://libtool/versioning // Note that A.implements(B) is not the same as B.implements(A)
Current - the most recent interface api that is implemented. // This checks the current() version and age() against B.current() for
Revision - the implementation number of the current interface. // compatibility. Even if A.implements(B) is true, B > A may also be
Age - the difference between the newest and oldest interfaces that // true, meaning B is a newer revision of the interface then A.
are implemented. bool implements(const Interface &dst) const;
*/
Interface( const char *name, int Current, int Revision, int Age );
Interface( const std::string &name, int Current, int Revision, int Age);
Interface(const Interface &src);
Interface();
// check if we implement the interface described by B. const std::string &name() const;
// Note that A.implements(B) is not the same as B.implements(A) int current() const;
// This checks the current() version and age() against B.current() for int revision() const;
// compatibility. Even if A.implements(B) is true, B > A may also be int age() const;
// true, meaning B is a newer revision of the interface then A.
bool implements( const Interface &dst ) const;
const std::string &name() const; std::string &name();
int current() const; int &current();
int revision() const; int &revision();
int age() const; int &age();
std::string &name();
int &current();
int &revision();
int &age();
Interface &operator = ( const Interface &src ); Interface &operator=(const Interface &src);
private: private:
std::string _name; std::string _name;
int _current; int _current;
int _revision; int _revision;
int _age; int _age;
}; };
} }
ConfigVar & operator << (ConfigVar &, const rel::Interface &); ConfigVar &operator<<(ConfigVar &, const rel::Interface &);
const ConfigVar & operator >> (const ConfigVar &, rel::Interface &); const ConfigVar &operator>>(const ConfigVar &, rel::Interface &);
bool operator < (const rel::Interface &A, const rel::Interface &B); bool operator<(const rel::Interface &A, const rel::Interface &B);
bool operator > (const rel::Interface &A, const rel::Interface &B); bool operator>(const rel::Interface &A, const rel::Interface &B);
bool operator <= (const rel::Interface &A, const rel::Interface &B); bool operator<=(const rel::Interface &A, const rel::Interface &B);
bool operator >= (const rel::Interface &A, const rel::Interface &B); bool operator>=(const rel::Interface &A, const rel::Interface &B);
bool operator == (const rel::Interface &A, const rel::Interface &B); bool operator==(const rel::Interface &A, const rel::Interface &B);
bool operator != (const rel::Interface &A, const rel::Interface &B); bool operator!=(const rel::Interface &A, const rel::Interface &B);
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -51,66 +51,45 @@ static RLogChannel *Info = DEF_CHANNEL("info/MACFileIO", Log_Info);
// //
static rel::Interface MACFileIO_iface("FileIO/MAC", 2, 1, 0); static rel::Interface MACFileIO_iface("FileIO/MAC", 2, 1, 0);
int dataBlockSize(const FSConfigPtr &cfg) int dataBlockSize(const FSConfigPtr &cfg) {
{ return cfg->config->blockSize - cfg->config->blockMACBytes -
return cfg->config->blockSize cfg->config->blockMACRandBytes;
- cfg->config->blockMACBytes
- cfg->config->blockMACRandBytes;
} }
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 ) key(cfg->key),
, key( cfg->key ) macBytes(cfg->config->blockMACBytes),
, macBytes( cfg->config->blockMACBytes ) randBytes(cfg->config->blockMACRandBytes),
, randBytes( cfg->config->blockMACRandBytes ) warnOnly(cfg->opts->forceDecode) {
, warnOnly( cfg->opts->forceDecode ) rAssert(macBytes >= 0 && macBytes <= 8);
{ rAssert(randBytes >= 0);
rAssert( macBytes >= 0 && macBytes <= 8 ); rLog(Info, "fs block size = %i, macBytes = %i, randBytes = %i",
rAssert( randBytes >= 0 ); cfg->config->blockSize, cfg->config->blockMACBytes,
rLog(Info, "fs block size = %i, macBytes = %i, randBytes = %i", cfg->config->blockMACRandBytes);
cfg->config->blockSize,
cfg->config->blockMACBytes,
cfg->config->blockMACRandBytes);
} }
MACFileIO::~MACFileIO() MACFileIO::~MACFileIO() {}
{
rel::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);
} }
rel::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) {
{ // integer arithmetic always rounds down, so we can round up by adding
base->setFileName( fileName ); // enough so that any value other then a multiple of denominator gets
} // rouned to the next highest value.
return (numerator + denominator - 1) / denominator;
const char *MACFileIO::getFileName() const
{
return base->getFileName();
}
bool MACFileIO::setIV( uint64_t iv )
{
return base->setIV( iv );
}
inline static off_t roundUpDivide( off_t numerator, int denominator )
{
// integer arithmetic always rounds down, so we can round up by adding
// enough so that any value other then a multiple of denominator gets
// rouned to the next highest value.
return ( numerator + denominator - 1 ) / denominator;
} }
// Convert from a location in the raw file to a location when MAC headers are // Convert from a location in the raw file to a location when MAC headers are
@ -123,10 +102,9 @@ 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;
} }
// convert from a given location in the stream containing headers, and return a // convert from a given location in the stream containing headers, and return a
@ -134,175 +112,149 @@ 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 bs = blockSize() + headerSize;
stbuf->st_size = locWithoutHeader( stbuf->st_size, bs, headerSize );
}
return res;
}
off_t MACFileIO::getSize() const
{
// adjust the size to hide the header overhead we tack on..
int headerSize = macBytes + randBytes; int headerSize = macBytes + randBytes;
int bs = blockSize() + headerSize; int bs = blockSize() + headerSize;
stbuf->st_size = locWithoutHeader(stbuf->st_size, bs, headerSize);
}
off_t size = base->getSize(); return res;
if(size > 0)
size = locWithoutHeader( size, bs, headerSize );
return size;
} }
ssize_t MACFileIO::readOneBlock( const IORequest &req ) const off_t MACFileIO::getSize() const {
{ // 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();
if (size > 0) size = locWithoutHeader(size, bs, headerSize);
MemBlock mb = MemoryPool::allocate( bs ); return size;
}
IORequest tmp; ssize_t MACFileIO::readOneBlock(const IORequest &req) const {
tmp.offset = locWithHeader( req.offset, bs, headerSize ); int headerSize = macBytes + randBytes;
tmp.data = mb.data;
tmp.dataLen = headerSize + req.dataLen;
// get the data from the base FileIO layer int bs = blockSize() + headerSize;
ssize_t readSize = base->read( tmp );
// don't store zeros if configured for zero-block pass-through MemBlock mb = MemoryPool::allocate(bs);
bool skipBlock = true;
if( _allowHoles )
{
for(int i=0; i<readSize; ++i)
if(tmp.data[i] != 0)
{
skipBlock = false;
break;
}
} else if(macBytes > 0)
skipBlock = false;
if(readSize > headerSize) IORequest tmp;
{ tmp.offset = locWithHeader(req.offset, bs, headerSize);
if(!skipBlock) tmp.data = mb.data;
{ tmp.dataLen = headerSize + req.dataLen;
// At this point the data has been decoded. So, compute the MAC of
// the block and check against the checksum stored in the header..
uint64_t mac = cipher->MAC_64( tmp.data + macBytes,
readSize - macBytes, key );
// Constant time comparision to prevent timing attacks // get the data from the base FileIO layer
unsigned char fail = 0; ssize_t readSize = base->read(tmp);
for(int i=0; i<macBytes; ++i, mac >>= 8)
{
int test = mac & 0xff;
int stored = tmp.data[i];
fail |= (test ^ stored); // don't store zeros if configured for zero-block pass-through
} bool skipBlock = true;
if (_allowHoles) {
for (int i = 0; i < readSize; ++i)
if (tmp.data[i] != 0) {
skipBlock = false;
break;
}
} else if (macBytes > 0)
skipBlock = false;
if( fail > 0 ) if (readSize > headerSize) {
{ if (!skipBlock) {
// uh oh.. // At this point the data has been decoded. So, compute the MAC of
long blockNum = req.offset / bs; // the block and check against the checksum stored in the header..
rWarning(_("MAC comparison failure in block %li"), uint64_t mac =
blockNum); cipher->MAC_64(tmp.data + macBytes, readSize - macBytes, key);
if( !warnOnly )
{ // Constant time comparision to prevent timing attacks
MemoryPool::release( mb ); unsigned char fail = 0;
throw ERROR( for (int i = 0; i < macBytes; ++i, mac >>= 8) {
_("MAC comparison failure, refusing to read")); int test = mac & 0xff;
} int stored = tmp.data[i];
}
fail |= (test ^ stored);
}
if (fail > 0) {
// uh oh..
long blockNum = req.offset / bs;
rWarning(_("MAC comparison failure in block %li"), blockNum);
if (!warnOnly) {
MemoryPool::release(mb);
throw ERROR(_("MAC comparison failure, refusing to read"));
} }
}
// now copy the data to the output buffer
readSize -= headerSize;
memcpy( req.data, tmp.data + headerSize, readSize );
} else
{
rDebug("readSize %i at offset %" PRIi64, (int)readSize, req.offset);
if(readSize > 0)
readSize = 0;
} }
MemoryPool::release( mb ); // now copy the data to the output buffer
readSize -= headerSize;
memcpy(req.data, tmp.data + headerSize, readSize);
} else {
rDebug("readSize %i at offset %" PRIi64, (int)readSize, req.offset);
if (readSize > 0) readSize = 0;
}
return readSize; MemoryPool::release(mb);
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 = MemoryPool::allocate( bs ); MemBlock mb = MemoryPool::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->randomize(newReq.data + macBytes, randBytes, false))
if(!cipher->randomize( newReq.data+macBytes, randBytes, false )) return false;
return false; }
if (macBytes > 0) {
// compute the mac (which includes the random data) and fill it in
uint64_t mac =
cipher->MAC_64(newReq.data + macBytes, req.dataLen + randBytes, key);
for (int i = 0; i < macBytes; ++i) {
newReq.data[i] = mac & 0xff;
mac >>= 8;
} }
}
if(macBytes > 0) // now, we can let the next level have it..
{ bool ok = base->write(newReq);
// compute the mac (which includes the random data) and fill it in
uint64_t mac = cipher->MAC_64( newReq.data+macBytes,
req.dataLen + randBytes, key );
for(int i=0; i<macBytes; ++i) MemoryPool::release(mb);
{
newReq.data[i] = mac & 0xff;
mac >>= 8;
}
}
// now, we can let the next level have it.. return ok;
bool ok = base->write( newReq );
MemoryPool::release( mb );
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 = BlockFileIO::truncateBase( size, 0 ); int res = BlockFileIO::truncateBase(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();
}

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -24,44 +24,41 @@
#include "BlockFileIO.h" #include "BlockFileIO.h"
#include "Cipher.h" #include "Cipher.h"
class MACFileIO : public BlockFileIO class MACFileIO : public BlockFileIO {
{ public:
public: /*
/* If warnOnlyMode is enabled, then a MAC comparison failure will only
If warnOnlyMode is enabled, then a MAC comparison failure will only result in a warning message from encfs -- the garbled data will still
result in a warning message from encfs -- the garbled data will still be made available..
be made available.. */
*/ MACFileIO(const shared_ptr<FileIO> &base, const FSConfigPtr &cfg);
MACFileIO( const shared_ptr<FileIO> &base, MACFileIO();
const FSConfigPtr &cfg ); virtual ~MACFileIO();
MACFileIO();
virtual ~MACFileIO();
virtual rel::Interface interface() const; virtual rel::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<Cipher> cipher; shared_ptr<Cipher> cipher;
CipherKey key; CipherKey key;
int macBytes; int macBytes;
int randBytes; int randBytes;
bool warnOnly; bool warnOnly;
}; };
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -30,116 +30,101 @@
#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
using namespace rlog; using namespace rlog;
# include <openssl/buffer.h> #include <openssl/buffer.h>
#define BLOCKDATA( BLOCK ) (unsigned char*)BLOCK->data->data #define BLOCKDATA(BLOCK) (unsigned char *) BLOCK->data->data
struct BlockList {
struct BlockList BlockList *next;
{ int size;
BlockList *next; BUF_MEM *data;
int size;
BUF_MEM *data;
}; };
static BlockList *allocBlock( int size ) static BlockList *allocBlock(int size) {
{ BlockList *block = new BlockList;
BlockList *block = new BlockList; block->size = size;
block->size = size; block->data = BUF_MEM_new();
block->data = BUF_MEM_new( ); BUF_MEM_grow(block->data, size);
BUF_MEM_grow( block->data, size ); VALGRIND_MAKE_MEM_NOACCESS(block->data->data, block->data->max);
VALGRIND_MAKE_MEM_NOACCESS( block->data->data, block->data->max );
return block; return block;
} }
static void freeBlock( BlockList *el ) static void freeBlock(BlockList *el) {
{ VALGRIND_MAKE_MEM_UNDEFINED(el->data->data, el->data->max);
VALGRIND_MAKE_MEM_UNDEFINED( el->data->data, el->data->max ); BUF_MEM_free(el->data);
BUF_MEM_free( el->data );
delete el;
delete el;
} }
static pthread_mutex_t gMPoolMutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t gMPoolMutex = PTHREAD_MUTEX_INITIALIZER;
static BlockList *gMemPool = NULL; static BlockList *gMemPool = NULL;
MemBlock MemoryPool::allocate(int size) {
pthread_mutex_lock(&gMPoolMutex);
BlockList *parent = NULL;
BlockList *block = gMemPool;
// check if we already have a large enough block available..
while (block != NULL && block->size < size) {
parent = block;
block = block->next;
}
MemBlock MemoryPool::allocate( int size ) // unlink block from list
{ if (block) {
pthread_mutex_lock( &gMPoolMutex ); if (!parent)
gMemPool = block->next;
else
parent->next = block->next;
}
pthread_mutex_unlock(&gMPoolMutex);
BlockList *parent = NULL; if (!block) block = allocBlock(size);
BlockList *block = gMemPool; block->next = NULL;
// check if we already have a large enough block available..
while(block != NULL && block->size < size)
{
parent = block;
block = block->next;
}
// unlink block from list MemBlock result;
if(block) result.data = BLOCKDATA(block);
{ result.internalData = block;
if(!parent)
gMemPool = block->next;
else
parent->next = block->next;
}
pthread_mutex_unlock( &gMPoolMutex );
if(!block) VALGRIND_MAKE_MEM_UNDEFINED(result.data, size);
block = allocBlock( size );
block->next = NULL;
MemBlock result; return result;
result.data = BLOCKDATA(block);
result.internalData = block;
VALGRIND_MAKE_MEM_UNDEFINED( result.data, size );
return result;
} }
void MemoryPool::release( const MemBlock &mb ) void MemoryPool::release(const MemBlock &mb) {
{ pthread_mutex_lock(&gMPoolMutex);
pthread_mutex_lock( &gMPoolMutex );
BlockList *block = (BlockList*)mb.internalData; BlockList *block = (BlockList *)mb.internalData;
// just to be sure there's nothing important left in buffers.. // just to be sure there's nothing important left in buffers..
VALGRIND_MAKE_MEM_UNDEFINED( block->data->data, block->size ); VALGRIND_MAKE_MEM_UNDEFINED(block->data->data, block->size);
memset( BLOCKDATA(block) , 0, block->size); memset(BLOCKDATA(block), 0, block->size);
VALGRIND_MAKE_MEM_NOACCESS( block->data->data, block->data->max ); VALGRIND_MAKE_MEM_NOACCESS(block->data->data, block->data->max);
block->next = gMemPool; block->next = gMemPool;
gMemPool = block; gMemPool = block;
pthread_mutex_unlock( &gMPoolMutex ); pthread_mutex_unlock(&gMPoolMutex);
} }
void MemoryPool::destroyAll() void MemoryPool::destroyAll() {
{ pthread_mutex_lock(&gMPoolMutex);
pthread_mutex_lock( &gMPoolMutex );
BlockList *block = gMemPool;
gMemPool = NULL;
pthread_mutex_unlock( &gMPoolMutex );
while(block != NULL) BlockList *block = gMemPool;
{ gMemPool = NULL;
BlockList *next = block->next;
freeBlock( block ); pthread_mutex_unlock(&gMPoolMutex);
block = next;
} while (block != NULL) {
BlockList *next = block->next;
freeBlock(block);
block = next;
}
} }

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -21,20 +21,15 @@
#ifndef _MemoryPool_incl_ #ifndef _MemoryPool_incl_
#define _MemoryPool_incl_ #define _MemoryPool_incl_
struct MemBlock {
unsigned char *data;
struct MemBlock void *internalData;
{
unsigned char *data;
void *internalData; MemBlock();
MemBlock();
}; };
inline MemBlock::MemBlock() inline MemBlock::MemBlock() : data(0), internalData(0) {}
: data(0), internalData(0)
{
}
/* /*
Memory Pool for fixed sized objects. Memory Pool for fixed sized objects.
@ -45,12 +40,10 @@ inline MemBlock::MemBlock()
unsigned char *buffer = mb.data; unsigned char *buffer = mb.data;
MemoryPool::release( mb ); MemoryPool::release( mb );
*/ */
namespace MemoryPool namespace MemoryPool {
{ MemBlock allocate(int size);
MemBlock allocate( int size ); void release(const MemBlock &el);
void release( const MemBlock &el ); void destroyAll();
void destroyAll();
} }
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -23,43 +23,33 @@
#include <pthread.h> #include <pthread.h>
namespace rel namespace rel {
{
class Lock class Lock {
{ public:
public: Lock(pthread_mutex_t &mutex);
Lock( pthread_mutex_t &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
pthread_mutex_t *_mutex; pthread_mutex_t *_mutex;
}; };
inline Lock::Lock( pthread_mutex_t &mutex ) inline Lock::Lock(pthread_mutex_t &mutex) : _mutex(&mutex) {
: _mutex( &mutex ) pthread_mutex_lock(_mutex);
{ }
pthread_mutex_lock( _mutex );
}
inline Lock::~Lock( ) inline Lock::~Lock() {
{ if (_mutex) pthread_mutex_unlock(_mutex);
if(_mutex) }
pthread_mutex_unlock( _mutex );
}
inline void Lock::leave() inline void Lock::leave() { _mutex = 0; }
{
_mutex = 0;
}
} }
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -39,314 +39,250 @@ using namespace rel;
using namespace rlog; using namespace rlog;
#define REF_MODULE(TYPE) \ #define REF_MODULE(TYPE) \
if(!TYPE::Enabled() ) \ if (!TYPE::Enabled()) cerr << "referenceModule: should never happen\n";
cerr << "referenceModule: should never happen\n";
static static void AddSymbolReferences() {
void AddSymbolReferences() REF_MODULE(BlockNameIO)
{ REF_MODULE(StreamNameIO)
REF_MODULE(BlockNameIO) REF_MODULE(NullNameIO)
REF_MODULE(StreamNameIO)
REF_MODULE(NullNameIO)
} }
struct NameIOAlg {
struct NameIOAlg bool hidden;
{ NameIO::Constructor constructor;
bool hidden; string description;
NameIO::Constructor constructor; Interface iface;
string description;
Interface iface;
}; };
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) {
AddSymbolReferences();
list< NameIO::Algorithm > list<Algorithm> result;
NameIO::GetAlgorithmList( bool includeHidden ) if (gNameIOMap) {
{ NameIOMap_t::const_iterator it;
AddSymbolReferences(); NameIOMap_t::const_iterator end = gNameIOMap->end();
for (it = gNameIOMap->begin(); it != end; ++it) {
if (includeHidden || !it->second.hidden) {
Algorithm tmp;
tmp.name = it->first;
tmp.description = it->second.description;
tmp.iface = it->second.iface;
list< Algorithm > result; result.push_back(tmp);
if(gNameIOMap) }
{
NameIOMap_t::const_iterator it;
NameIOMap_t::const_iterator end = gNameIOMap->end();
for(it = gNameIOMap->begin(); it != end; ++it)
{
if(includeHidden || !it->second.hidden)
{
Algorithm tmp;
tmp.name = it->first;
tmp.description = it->second.description;
tmp.iface = it->second.iface;
result.push_back( tmp );
}
}
} }
}
return result; 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 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;
alg.constructor = constructor; alg.constructor = constructor;
alg.description = description; alg.description = description;
alg.iface = iface; alg.iface = iface;
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<Cipher> &cipher, const CipherKey &key) const shared_ptr<Cipher> &cipher,
{ const CipherKey &key) {
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;
{ result = (*fn)(it->second.iface, cipher, key);
Constructor fn = it->second.constructor;
result = (*fn)( it->second.iface, cipher, key );
}
} }
return result; }
return result;
} }
shared_ptr<NameIO> NameIO::New( const Interface &iface, shared_ptr<NameIO> NameIO::New(const Interface &iface,
const shared_ptr<Cipher> &cipher, const CipherKey &key ) const shared_ptr<Cipher> &cipher,
{ const CipherKey &key) {
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 (it->second.iface.implements(iface)) {
{ Constructor fn = it->second.constructor;
if( it->second.iface.implements( iface )) result = (*fn)(iface, cipher, key);
{ break;
Constructor fn = it->second.constructor; }
result = (*fn)( iface, cipher, key );
break;
}
}
} }
return result; }
return result;
} }
NameIO::NameIO() : chainedNameIV(false), reverseEncryption(false) {}
NameIO::~NameIO() {}
NameIO::NameIO() void NameIO::setChainedNameIV(bool enable) { chainedNameIV = enable; }
: chainedNameIV( false ), reverseEncryption( false )
{
}
NameIO::~NameIO() bool NameIO::getChainedNameIV() const { return chainedNameIV; }
{
}
void NameIO::setChainedNameIV( bool enable ) void NameIO::setReverseEncryption(bool enable) { reverseEncryption = enable; }
{
chainedNameIV = enable;
}
bool NameIO::getChainedNameIV() const bool NameIO::getReverseEncryption() const { return reverseEncryption; }
{
return chainedNameIV;
}
void NameIO::setReverseEncryption( bool enable ) std::string NameIO::recodePath(const char *path,
{ int (NameIO::*_length)(int) const,
reverseEncryption = enable; int (NameIO::*_code)(const char *, int,
} uint64_t *, char *) const,
uint64_t *iv) const {
string output;
bool NameIO::getReverseEncryption() const while (*path) {
{ if (*path == '/') {
return reverseEncryption; if (!output.empty()) // don't start the string with '/'
} output += '/';
++path;
} else {
bool isDotFile = (*path == '.');
const char *next = strchr(path, '/');
int len = next ? next - path : strlen(path);
// at this point we know that len > 0
if (isDotFile && (path[len - 1] == '.') && (len <= 2)) {
output.append(len, '.'); // append [len] copies of '.'
path += len;
continue;
}
std::string NameIO::recodePath( const char *path, // figure out buffer sizes
int (NameIO::*_length)(int) const, int approxLen = (this->*_length)(len);
int (NameIO::*_code)(const char*, int, uint64_t *, char*) const, if (approxLen <= 0) throw ERROR("Filename too small to decode");
uint64_t *iv ) const
{
string output;
while( *path ) BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1)
{
if( *path == '/' )
{
if( !output.empty() ) // don't start the string with '/'
output += '/';
++path;
} else
{
bool isDotFile = (*path == '.');
const char *next = strchr( path, '/' );
int len = next ? next - path : strlen( path );
// at this point we know that len > 0 // code the name
if( isDotFile && (path[len-1] == '.') && (len <= 2) ) int codedLen = (this->*_code)(path, len, iv, codeBuf);
{ rAssert(codedLen <= approxLen);
output.append(len, '.'); // append [len] copies of '.' rAssert(codeBuf[codedLen] == '\0');
path += len; path += len;
continue;
}
// figure out buffer sizes // append result to string
int approxLen = (this->*_length)( len ); output += (char *)codeBuf;
if(approxLen <= 0)
throw ERROR("Filename too small to decode");
BUFFER_INIT( codeBuf, 32, (unsigned int)approxLen+1 ) BUFFER_RESET(codeBuf)
// code the name
int codedLen = (this->*_code)( path, len, iv, codeBuf );
rAssert( codedLen <= approxLen );
rAssert( codeBuf[codedLen] == '\0' );
path += len;
// append result to string
output += (char*)codeBuf;
BUFFER_RESET( codeBuf )
}
} }
}
return output; 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) iv = 0;
if(!chainedNameIV) return recodePath(plaintextPath, &NameIO::maxEncodedNameLen,
iv = 0; &NameIO::encodeName, iv);
return recodePath( plaintextPath,
&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) iv = 0;
if(!chainedNameIV) return recodePath(cipherPath, &NameIO::maxDecodedNameLen, &NameIO::decodeName,
iv = 0; iv);
return recodePath( cipherPath,
&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
{
return getReverseEncryption() ?
_encodePath( path, iv ) :
_decodePath( path, iv );
}
int NameIO::encodeName( const char *input, int length, char *output ) const
{
return encodeName( input, length, (uint64_t*)0, output );
} }
int NameIO::decodeName( const char *input, int length, char *output ) const std::string NameIO::decodePath(const char *path, uint64_t *iv) const {
{ return getReverseEncryption() ? _encodePath(path, iv) : _decodePath(path, iv);
return decodeName( input, length, (uint64_t*)0, output );
} }
std::string NameIO::_encodeName( const char *plaintextName, int length ) const int NameIO::encodeName(const char *input, int length, char *output) const {
{ return encodeName(input, length, (uint64_t *)0, output);
int approxLen = maxEncodedNameLen( length );
BUFFER_INIT( codeBuf, 32, (unsigned int)approxLen+1 )
// code the name
int codedLen = encodeName( plaintextName, length, 0, codeBuf );
rAssert( codedLen <= approxLen );
rAssert( codeBuf[codedLen] == '\0' );
// append result to string
std::string result = (char*)codeBuf;
BUFFER_RESET( codeBuf )
return result;
} }
std::string NameIO::_decodeName( const char *encodedName, int length ) const int NameIO::decodeName(const char *input, int length, char *output) const {
{ return decodeName(input, length, (uint64_t *)0, output);
int approxLen = maxDecodedNameLen( length );
BUFFER_INIT( codeBuf, 32, (unsigned int)approxLen+1 )
// code the name
int codedLen = decodeName( encodedName, length, 0, codeBuf );
rAssert( codedLen <= approxLen );
rAssert( codeBuf[codedLen] == '\0' );
// append result to string
std::string result = (char*)codeBuf;
BUFFER_RESET( codeBuf )
return result;
} }
std::string NameIO::encodeName( const char *path, int length ) const std::string NameIO::_encodeName(const char *plaintextName, int length) const {
{ int approxLen = maxEncodedNameLen(length);
return getReverseEncryption() ?
_decodeName( path, length ) : BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1)
_encodeName( path, length );
// code the name
int codedLen = encodeName(plaintextName, length, 0, codeBuf);
rAssert(codedLen <= approxLen);
rAssert(codeBuf[codedLen] == '\0');
// append result to string
std::string result = (char *)codeBuf;
BUFFER_RESET(codeBuf)
return result;
} }
std::string NameIO::decodeName( const char *path, int length ) const std::string NameIO::_decodeName(const char *encodedName, int length) const {
{ int approxLen = maxDecodedNameLen(length);
return getReverseEncryption() ?
_encodeName( path, length ) : BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1)
_decodeName( path, length );
// code the name
int codedLen = decodeName(encodedName, length, 0, codeBuf);
rAssert(codedLen <= approxLen);
rAssert(codeBuf[codedLen] == '\0');
// append result to string
std::string result = (char *)codeBuf;
BUFFER_RESET(codeBuf)
return result;
}
std::string NameIO::encodeName(const char *path, int length) const {
return getReverseEncryption() ? _decodeName(path, length)
: _encodeName(path, length);
}
std::string NameIO::decodeName(const char *path, int length) const {
return getReverseEncryption() ? _encodeName(path, length)
: _decodeName(path, length);
} }
/* /*
int NameIO::encodeName( const char *path, int length, int NameIO::encodeName( const char *path, int length,
char *output ) const char *output ) const
{ {
return getReverseEncryption() ? return getReverseEncryption() ?
_decodeName( path, length, output ) : _decodeName( path, length, output ) :
_encodeName( path, length, output ); _encodeName( path, length, output );
} }
int NameIO::decodeName( const char *path, int length, int NameIO::decodeName( const char *path, int length,
char *output ) const char *output ) const
{ {
return getReverseEncryption() ? return getReverseEncryption() ?
_encodeName( path, length, output ) : _encodeName( path, length, output ) :
_decodeName( path, length, output ); _decodeName( path, length, output );
} }
*/ */

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -31,85 +31,80 @@
class Cipher; class Cipher;
class NameIO class NameIO {
{ public:
public: typedef shared_ptr<NameIO>(*Constructor)(const rel::Interface &iface,
typedef shared_ptr<NameIO> (*Constructor)( const rel::Interface &iface, const shared_ptr<Cipher> &cipher,
const shared_ptr<Cipher> &cipher, const CipherKey &key); const CipherKey &key);
struct Algorithm struct Algorithm {
{ std::string name;
std::string name; std::string description;
std::string description; rel::Interface iface;
rel::Interface iface; };
};
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 rel::Interface &iface, static shared_ptr<NameIO> New(const rel::Interface &iface,
const shared_ptr<Cipher> &cipher, const CipherKey &key); const shared_ptr<Cipher> &cipher,
static shared_ptr<NameIO> New( const std::string &name, const CipherKey &key);
const shared_ptr<Cipher> &cipher, const CipherKey &key); static shared_ptr<NameIO> New(const std::string &name,
const shared_ptr<Cipher> &cipher,
const CipherKey &key);
static bool Register( const char *name, const char *description, static bool Register(const char *name, const char *description,
const rel::Interface &iface, Constructor constructor, const rel::Interface &iface, Constructor constructor,
bool hidden = false); bool hidden = false);
NameIO();
virtual ~NameIO();
NameIO(); virtual rel::Interface interface() const = 0;
virtual ~NameIO();
virtual rel::Interface interface() const =0; void setChainedNameIV(bool enable);
bool getChainedNameIV() const;
void setReverseEncryption(bool enable);
bool getReverseEncryption() const;
void setChainedNameIV( bool enable ); std::string encodePath(const char *plaintextPath) const;
bool getChainedNameIV() const; std::string decodePath(const char *encodedPath) const;
void setReverseEncryption( bool enable );
bool getReverseEncryption() const;
std::string encodePath( const char *plaintextPath ) const; std::string encodePath(const char *plaintextPath, uint64_t *iv) const;
std::string decodePath( const char *encodedPath ) const; std::string decodePath(const char *encodedPath, uint64_t *iv) const;
std::string encodePath( const char *plaintextPath, uint64_t *iv ) const; virtual int maxEncodedNameLen(int plaintextNameLen) const = 0;
std::string decodePath( const char *encodedPath, uint64_t *iv ) const; virtual int maxDecodedNameLen(int encodedNameLen) const = 0;
virtual int maxEncodedNameLen( int plaintextNameLen ) const =0; std::string encodeName(const char *plaintextName, int length) const;
virtual int maxDecodedNameLen( int encodedNameLen ) const =0; std::string decodeName(const char *encodedName, int length) const;
std::string encodeName( const char *plaintextName, int length ) const; protected:
std::string decodeName( const char *encodedName, int length ) const; virtual int encodeName(const char *plaintextName, int length,
char *encodedName) const;
virtual int decodeName(const char *encodedName, int length,
char *plaintextName) const;
protected: virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
virtual int encodeName( const char *plaintextName, int length, char *encodedName) const = 0;
char *encodedName ) const; virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
virtual int decodeName( const char *encodedName, int length, char *plaintextName) const = 0;
char *plaintextName ) const;
virtual int encodeName( const char *plaintextName, int length, private:
uint64_t *iv, char *encodedName ) const =0; std::string recodePath(const char *path, int (NameIO::*codingLen)(int) const,
virtual int decodeName( const char *encodedName, int length, int (NameIO::*codingFunc)(const char *, int,
uint64_t *iv, char *plaintextName ) const =0; uint64_t *, char *) const,
uint64_t *iv) const;
std::string _encodePath(const char *plaintextPath, uint64_t *iv) const;
std::string _decodePath(const char *encodedPath, uint64_t *iv) const;
std::string _encodeName(const char *plaintextName, int length) const;
std::string _decodeName(const char *encodedName, int length) const;
private: bool chainedNameIV;
bool reverseEncryption;
std::string recodePath( const char *path,
int (NameIO::*codingLen)(int) const,
int (NameIO::*codingFunc)(const char *, int,
uint64_t *, char *) const,
uint64_t *iv ) const;
std::string _encodePath( const char *plaintextPath, uint64_t *iv ) const;
std::string _decodePath( const char *encodedPath, uint64_t *iv ) const;
std::string _encodeName( const char *plaintextName, int length ) const;
std::string _decodeName( const char *encodedName, int length ) const;
bool chainedNameIV;
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
@ -117,22 +112,18 @@ private:
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 ) \
do { \
if( Name != Name ## _Raw ) \
{ \
delete[] Name; \
Name = Name ## _Raw; \
} \
} while(0);
#define BUFFER_RESET(Name) \
do { \
if (Name != Name##_Raw) { \
delete[] Name; \
Name = Name##_Raw; \
} \
} while (0);
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -18,7 +18,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 "NullCipher.h" #include "NullCipher.h"
#include <cstring> #include <cstring>
@ -32,153 +31,109 @@ using namespace std;
using namespace rel; using namespace rel;
using namespace rlog; using namespace rlog;
static Interface NullInterface( "nullCipher", 1, 0, 0 ); static Interface NullInterface("nullCipher", 1, 0, 0);
static Range NullKeyRange(0); static Range NullKeyRange(0);
static Range NullBlockRange(1,4096,1); static Range NullBlockRange(1, 4096, 1);
static shared_ptr<Cipher> NewNullCipher(const Interface &iface, int keyLen) static shared_ptr<Cipher> NewNullCipher(const Interface &iface, int keyLen) {
{ (void)keyLen;
(void)keyLen; return shared_ptr<Cipher>(new NullCipher(iface));
return shared_ptr<Cipher>( new NullCipher( iface ) );
} }
const bool HiddenCipher = true; const bool HiddenCipher = true;
static bool NullCipher_registered = Cipher::Register("Null", static bool NullCipher_registered = Cipher::Register(
"Non encrypting cipher. For testing only!", "Null", "Non encrypting cipher. For testing only!", NullInterface,
NullInterface, NullKeyRange, NullBlockRange, NewNullCipher, NullKeyRange, NullBlockRange, NewNullCipher, HiddenCipher);
HiddenCipher);
class NullKey : public AbstractCipherKey class NullKey : public AbstractCipherKey {
{ public:
public: NullKey() {}
NullKey() {} virtual ~NullKey() {}
virtual ~NullKey() {}
}; };
class NullDestructor class NullDestructor {
{ public:
public: NullDestructor() {}
NullDestructor() {} NullDestructor(const NullDestructor &) {}
NullDestructor(const NullDestructor &) {} ~NullDestructor() {}
~NullDestructor() {}
NullDestructor &operator = (const NullDestructor &){ return *this; } NullDestructor &operator=(const NullDestructor &) { return *this; }
void operator ()(NullKey *&) {} void operator()(NullKey *&) {}
}; };
shared_ptr<AbstractCipherKey> gNullKey( new NullKey(), NullDestructor() ); shared_ptr<AbstractCipherKey> gNullKey(new NullKey(), NullDestructor());
NullCipher::NullCipher(const Interface &iface_) NullCipher::NullCipher(const Interface &iface_) { this->iface = iface_; }
{
this->iface = iface_; NullCipher::~NullCipher() {}
Interface NullCipher::interface() const { return iface; }
CipherKey NullCipher::newKey(const char *, int, int &, long,
const unsigned char *, int) {
return gNullKey;
} }
NullCipher::~NullCipher() CipherKey NullCipher::newKey(const char *, int) { return gNullKey; }
{
CipherKey NullCipher::newRandomKey() { return gNullKey; }
bool NullCipher::randomize(unsigned char *buf, int len, bool) const {
memset(buf, 0, len);
return true;
} }
Interface NullCipher::interface() const uint64_t NullCipher::MAC_64(const unsigned char *, int, const CipherKey &,
{ uint64_t *) const {
return iface; return 0;
} }
CipherKey NullCipher::newKey(const char *, int, CipherKey NullCipher::readKey(const unsigned char *, const CipherKey &, bool) {
int &, long, const unsigned char *, int ) return gNullKey;
{
return gNullKey;
} }
CipherKey NullCipher::newKey(const char *, int) void NullCipher::writeKey(const CipherKey &, unsigned char *,
{ const CipherKey &) {}
return gNullKey;
bool NullCipher::compareKey(const CipherKey &A_, const CipherKey &B_) const {
shared_ptr<NullKey> A = dynamic_pointer_cast<NullKey>(A_);
shared_ptr<NullKey> B = dynamic_pointer_cast<NullKey>(B_);
return A.get() == B.get();
} }
CipherKey NullCipher::newRandomKey() int NullCipher::encodedKeySize() const { return 0; }
{
return gNullKey; int NullCipher::keySize() const { return 0; }
int NullCipher::cipherBlockSize() const { return 1; }
bool NullCipher::streamEncode(unsigned char *src, int len, uint64_t iv64,
const CipherKey &key) const {
(void)src;
(void)len;
(void)iv64;
(void)key;
return true;
} }
bool NullCipher::randomize( unsigned char *buf, int len, bool ) const bool NullCipher::streamDecode(unsigned char *src, int len, uint64_t iv64,
{ const CipherKey &key) const {
memset( buf, 0, len ); (void)src;
return true; (void)len;
(void)iv64;
(void)key;
return true;
} }
uint64_t NullCipher::MAC_64(const unsigned char *, int , bool NullCipher::blockEncode(unsigned char *, int, uint64_t,
const CipherKey &, uint64_t *) const const CipherKey &) const {
{ return true;
return 0;
} }
CipherKey NullCipher::readKey( const unsigned char *, bool NullCipher::blockDecode(unsigned char *, int, uint64_t,
const CipherKey &, bool) const CipherKey &) const {
{ return true;
return gNullKey;
}
void NullCipher::writeKey(const CipherKey &, unsigned char *,
const CipherKey &)
{
}
bool NullCipher::compareKey(const CipherKey &A_,
const CipherKey &B_) const
{
shared_ptr<NullKey> A = dynamic_pointer_cast<NullKey>(A_);
shared_ptr<NullKey> B = dynamic_pointer_cast<NullKey>(B_);
return A.get() == B.get();
}
int NullCipher::encodedKeySize() const
{
return 0;
}
int NullCipher::keySize() const
{
return 0;
}
int NullCipher::cipherBlockSize() const
{
return 1;
}
bool NullCipher::streamEncode( unsigned char *src, int len,
uint64_t iv64, const CipherKey &key) const
{
(void)src;
(void)len;
(void)iv64;
(void)key;
return true;
}
bool NullCipher::streamDecode( unsigned char *src, int len,
uint64_t iv64, const CipherKey &key) const
{
(void)src;
(void)len;
(void)iv64;
(void)key;
return true;
}
bool NullCipher::blockEncode( unsigned char *, int , uint64_t,
const CipherKey & ) const
{
return true;
}
bool NullCipher::blockDecode( unsigned char *, int, uint64_t,
const CipherKey & ) const
{
return true;
}
bool NullCipher::Enabled()
{
return true;
} }
bool NullCipher::Enabled() { return true; }

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -28,59 +28,53 @@
Implements Cipher interface for a pass-through mode. May be useful for Implements Cipher interface for a pass-through mode. May be useful for
testing, but that's it. testing, but that's it.
*/ */
class NullCipher : public Cipher class NullCipher : public Cipher {
{ rel::Interface iface;
rel::Interface iface;
public: public:
NullCipher(const rel::Interface &iface); NullCipher(const rel::Interface &iface);
virtual ~NullCipher(); virtual ~NullCipher();
virtual rel::Interface interface() const; virtual rel::Interface interface() const;
// create a new key based on a password // create a new key based on a password
virtual CipherKey newKey(const char *password, int passwdLength, virtual CipherKey newKey(const char *password, int passwdLength,
int &iterationCount, long desiredDuration, int &iterationCount, long desiredDuration,
const unsigned char *salt, int saltLen); const unsigned char *salt, int saltLen);
virtual CipherKey newKey(const char *password, int passwdLength); virtual CipherKey newKey(const char *password, int passwdLength);
// create a new random key // create a new random key
virtual CipherKey newRandomKey(); virtual CipherKey newRandomKey();
// data must be len keySize() // data must be len keySize()
virtual CipherKey readKey(const unsigned char *data, virtual CipherKey readKey(const unsigned char *data,
const CipherKey &encodingKey, const CipherKey &encodingKey, bool checkKey);
bool checkKey); virtual void writeKey(const CipherKey &key, unsigned char *data,
virtual void writeKey(const CipherKey &key, unsigned char *data, const CipherKey &encodingKey);
const CipherKey &encodingKey); virtual bool compareKey(const CipherKey &A, const CipherKey &B) const;
virtual bool compareKey( const CipherKey &A,
const CipherKey &B ) const;
// meta-data about the cypher // meta-data about the cypher
virtual int keySize() const; virtual int keySize() const;
virtual int encodedKeySize() const; virtual int encodedKeySize() const;
virtual int cipherBlockSize() const; virtual int cipherBlockSize() const;
virtual bool randomize( unsigned char *buf, int len, virtual bool randomize(unsigned char *buf, int len, bool strongRandom) const;
bool strongRandom ) const;
virtual uint64_t MAC_64(const unsigned char *data, int len, virtual uint64_t MAC_64(const unsigned char *data, int len,
const CipherKey &key, uint64_t *chainedIV) const; const CipherKey &key, uint64_t *chainedIV) const;
// functional interfaces // functional interfaces
virtual bool streamEncode(unsigned char *in, int len, virtual bool streamEncode(unsigned char *in, int len, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const; const CipherKey &key) const;
virtual bool streamDecode(unsigned char *in, int len, virtual bool streamDecode(unsigned char *in, int len, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const; const CipherKey &key) const;
virtual bool blockEncode(unsigned char *buf, int size, virtual bool blockEncode(unsigned char *buf, int size, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const; const CipherKey &key) const;
virtual bool blockDecode(unsigned char *buf, int size, virtual bool blockDecode(unsigned char *buf, int size, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const; const CipherKey &key) const;
// hack to help with static builds // hack to help with static builds
static bool Enabled(); static bool Enabled();
}; };
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -27,66 +27,45 @@
using namespace rel; using namespace rel;
static shared_ptr<NameIO> NewNNIO( const Interface &, static shared_ptr<NameIO> NewNNIO(const Interface &, const shared_ptr<Cipher> &,
const shared_ptr<Cipher> &, const CipherKey & ) const CipherKey &) {
{ return shared_ptr<NameIO>(new NullNameIO());
return shared_ptr<NameIO>( new NullNameIO() );
} }
static Interface NNIOIface("nameio/null", 1, 0, 0); static Interface NNIOIface("nameio/null", 1, 0, 0);
static bool NullNameIO_registered = NameIO::Register("Null", static bool NullNameIO_registered =
"No encryption of filenames", NNIOIface, NewNNIO); NameIO::Register("Null", "No encryption of filenames", NNIOIface, NewNNIO);
NullNameIO::NullNameIO( ) NullNameIO::NullNameIO() {}
{
NullNameIO::~NullNameIO() {}
Interface NullNameIO::interface() const { return NNIOIface; }
Interface NullNameIO::CurrentInterface() { return NNIOIface; }
int NullNameIO::maxEncodedNameLen(int plaintextNameLen) const {
return plaintextNameLen;
} }
NullNameIO::~NullNameIO() int NullNameIO::maxDecodedNameLen(int encodedNameLen) const {
{ return encodedNameLen;
} }
Interface NullNameIO::interface() const int NullNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv,
{ char *encodedName) const {
return NNIOIface; (void)iv;
memcpy(encodedName, plaintextName, length);
return length;
} }
Interface NullNameIO::CurrentInterface() int NullNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
{ char *plaintextName) const {
return NNIOIface; (void)iv;
} memcpy(plaintextName, encodedName, length);
return length;
int NullNameIO::maxEncodedNameLen( int plaintextNameLen ) const
{
return plaintextNameLen;
}
int NullNameIO::maxDecodedNameLen( int encodedNameLen ) const
{
return encodedNameLen;
}
int NullNameIO::encodeName( const char *plaintextName, int length,
uint64_t *iv, char *encodedName ) const
{
(void)iv;
memcpy( encodedName, plaintextName, length );
return length;
}
int NullNameIO::decodeName( const char *encodedName, int length,
uint64_t *iv, char *plaintextName ) const
{
(void)iv;
memcpy( plaintextName, encodedName, length );
return length;
}
bool NullNameIO::Enabled()
{
return true;
} }
bool NullNameIO::Enabled() { return true; }

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -23,30 +23,29 @@
#include "NameIO.h" #include "NameIO.h"
class NullNameIO : public NameIO class NullNameIO : public NameIO {
{ public:
public: static rel::Interface CurrentInterface();
static rel::Interface CurrentInterface();
NullNameIO( ); NullNameIO();
virtual ~NullNameIO(); virtual ~NullNameIO();
virtual rel::Interface interface() const; virtual rel::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:
}; };
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -17,97 +17,73 @@
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _Range_incl_ #ifndef _Range_incl_
#define _Range_incl_ #define _Range_incl_
class Range {
int minVal;
int maxVal;
int increment;
class Range public:
{ Range();
int minVal; Range(int minMax);
int maxVal; Range(int min, int max, int increment);
int increment;
public:
Range();
Range(int minMax);
Range(int min, int max, int increment);
bool allowed(int value) const; bool allowed(int value) const;
int closest(int value) const; int closest(int value) const;
int min() const; int min() const;
int max() const; int max() const;
int inc() const; int inc() const;
}; };
inline Range::Range(int minMax) inline Range::Range(int minMax) {
{ this->minVal = minMax;
this->minVal = minMax; this->maxVal = minMax;
this->maxVal = minMax; this->increment = 1;
this->increment = 1;
} }
inline Range::Range(int min_, int max_, int increment_) inline Range::Range(int min_, int max_, int increment_) {
{ this->minVal = min_;
this->minVal = min_; this->maxVal = max_;
this->maxVal = max_; this->increment = increment_;
this->increment = increment_; if (increment == 0) this->increment = 1;
if(increment == 0)
this->increment = 1;
} }
inline Range::Range() inline Range::Range() : minVal(-1), maxVal(-1), increment(1) {}
: minVal(-1)
, maxVal(-1)
, increment(1)
{
}
inline bool Range::allowed(int value) const inline bool Range::allowed(int value) const {
{ if (value >= minVal && value <= maxVal) {
if(value >= minVal && value <= maxVal)
{
int tmp = value - minVal;
if((tmp % increment) == 0)
return true;
}
return false;
}
inline int Range::closest(int value) const
{
if(allowed(value))
return value;
else
if(value < minVal)
return minVal;
else
if(value > maxVal)
return maxVal;
// must be inbetween but not matched with increment
int tmp = value - minVal; int tmp = value - minVal;
// try rounding to the nearest increment.. if ((tmp % increment) == 0) return true;
tmp += (increment >> 1); }
tmp -= (tmp % increment); return false;
return closest( value + tmp );
} }
inline int Range::min() const inline int Range::closest(int value) const {
{ if (allowed(value))
return value;
else if (value < minVal)
return minVal; return minVal;
} else if (value > maxVal)
inline int Range::max() const
{
return maxVal; return maxVal;
// must be inbetween but not matched with increment
int tmp = value - minVal;
// try rounding to the nearest increment..
tmp += (increment >> 1);
tmp -= (tmp % increment);
return closest(value + tmp);
} }
inline int Range::inc() const inline int Range::min() const { return minVal; }
{
return increment; inline int Range::max() const { return maxVal; }
}
inline int Range::inc() const { return increment; }
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -19,7 +19,7 @@
*/ */
#ifdef linux #ifdef linux
#define _XOPEN_SOURCE 500 // pick up pread , pwrite #define _XOPEN_SOURCE 500 // pick up pread , pwrite
#endif #endif
#include <unistd.h> #include <unistd.h>
@ -38,57 +38,41 @@ using namespace std;
static rel::Interface RawFileIO_iface("FileIO/Raw", 1, 0, 0); static rel::Interface RawFileIO_iface("FileIO/Raw", 1, 0, 0);
FileIO *NewRawFileIO( const rel::Interface &iface ) FileIO *NewRawFileIO(const rel::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 ) RawFileIO::RawFileIO(const std::string &fileName)
, oldfd( -1 ) : name(fileName),
, canWrite( false ) knownSize(false),
{ fileSize(0),
fd(-1),
oldfd(-1),
canWrite(false) {}
RawFileIO::~RawFileIO() {
int _fd = -1;
int _oldfd = -1;
swap(_fd, fd);
swap(_oldfd, oldfd);
if (_oldfd != -1) close(_oldfd);
if (_fd != -1) close(_fd);
} }
RawFileIO::RawFileIO( const std::string &fileName ) rel::Interface RawFileIO::interface() const { return RawFileIO_iface; }
: name( fileName )
, knownSize( false )
, fileSize( 0 )
, fd( -1 )
, oldfd( -1 )
, canWrite( false )
{
}
RawFileIO::~RawFileIO()
{
int _fd = -1;
int _oldfd = -1;
swap( _fd, fd );
swap( _oldfd, oldfd );
if( _oldfd != -1 )
close( _oldfd );
if( _fd != -1 )
close( _fd );
}
rel::Interface RawFileIO::interface() const
{
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.
@ -97,23 +81,20 @@ rel::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..
{ chmod(path, stbuf.st_mode | 0600);
// make sure user has read/write permission.. fd = ::open(path, flags);
chmod( path , stbuf.st_mode | 0600 ); chmod(path, stbuf.st_mode);
fd = ::open( path , flags ); } else {
chmod( path , stbuf.st_mode ); rInfo("can't stat file %s", path);
} else }
{
rInfo("can't stat file %s", path );
}
return fd; return fd;
} }
/* /*
@ -125,201 +106,164 @@ 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));
rDebug("open call for %s file", requestWrite ? "writable" : "read only"); rDebug("open call for %s file", requestWrite ? "writable" : "read only");
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)) {
{ rDebug("using existing file descriptor");
rDebug("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);
rDebug("open file with flags %i, result = %i", finalFlags, newFd);
if((newFd == -1) && (errno == EACCES)) rDebug("open file with flags %i, result = %i", finalFlags, newFd);
{
rDebug("using readonly workaround for open");
newFd = open_readonly_workaround( name.c_str(), finalFlags );
}
if(newFd >= 0) if ((newFd == -1) && (errno == EACCES)) {
{ rDebug("using readonly workaround for open");
if(oldfd >= 0) newFd = open_readonly_workaround(name.c_str(), finalFlags);
{
rError("leaking FD?: oldfd = %i, fd = %i, newfd = %i",
oldfd, fd, newFd);
}
// the old fd might still be in use, so just keep it around for
// now.
canWrite = requestWrite;
oldfd = fd;
result = fd = newFd;
} else
{
result = -errno;
rInfo("::open error: %s", strerror(errno));
}
} }
if(result < 0) if (newFd >= 0) {
rInfo("file %s open failure: %i", name.c_str(), -result); if (oldfd >= 0) {
rError("leaking FD?: oldfd = %i, fd = %i, newfd = %i", oldfd, fd,
newFd);
}
return result; // the old fd might still be in use, so just keep it around for
// now.
canWrite = requestWrite;
oldfd = fd;
result = fd = newFd;
} else {
result = -errno;
rInfo("::open error: %s", strerror(errno));
}
}
if (result < 0) rInfo("file %s open failure: %i", name.c_str(), -result);
return result;
} }
int RawFileIO::getAttr( struct stat *stbuf ) const int 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;
if(res < 0) if (res < 0) rInfo("getAttr error on %s: %s", name.c_str(), strerror(eno));
rInfo("getAttr error on %s: %s", name.c_str(), 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;
{ memset(&stbuf, 0, sizeof(struct stat));
struct stat stbuf; int res = lstat(name.c_str(), &stbuf);
memset( &stbuf, 0, sizeof( struct stat ));
int res = lstat( name.c_str(), &stbuf );
if(res == 0) if (res == 0) {
{ const_cast<RawFileIO *>(this)->fileSize = stbuf.st_size;
const_cast<RawFileIO*>(this)->fileSize = stbuf.st_size; const_cast<RawFileIO *>(this)->knownSize = true;
const_cast<RawFileIO*>(this)->knownSize = true; return fileSize;
return fileSize;
} else
return -1;
} else } else
{ return -1;
return fileSize; } else {
} return fileSize;
}
} }
ssize_t RawFileIO::read( const IORequest &req ) const ssize_t RawFileIO::read(const IORequest &req) const {
{ rAssert(fd >= 0);
rAssert( fd >= 0 );
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) {
{ rInfo("read failed at offset %" PRIi64 " for %i bytes: %s", req.offset,
rInfo("read failed at offset %" PRIi64 " for %i bytes: %s", req.dataLen, strerror(errno));
req.offset, req.dataLen, 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 );
int retrys = 10; int retrys = 10;
void *buf = req.data; void *buf = req.data;
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; rInfo("write failed at offset %" PRIi64 " for %i bytes: %s", offset,
rInfo("write failed at offset %" PRIi64 " for %i bytes: %s", (int)bytes, strerror(errno));
offset, (int)bytes, strerror( errno )); return false;
return false;
}
bytes -= writeSize;
offset += writeSize;
buf = (void*)((char*)buf + writeSize);
--retrys;
} }
if(bytes != 0) bytes -= writeSize;
{ offset += writeSize;
rError("Write error: wrote %i bytes of %i, max retries reached\n", buf = (void *)((char *)buf + writeSize);
(int)(req.dataLen - bytes), req.dataLen ); --retrys;
knownSize = false; }
return false;
} else
{
if(knownSize)
{
off_t last = req.offset + req.dataLen;
if(last > fileSize)
fileSize = last;
}
return true; if (bytes != 0) {
rError("Write error: wrote %i bytes of %i, max retries reached\n",
(int)(req.dataLen - bytes), req.dataLen);
knownSize = false;
return false;
} else {
if (knownSize) {
off_t last = req.offset + req.dataLen;
if (last > fileSize) fileSize = last;
} }
return true;
}
} }
int RawFileIO::truncate( off_t size ) int 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 );
#if !defined(__FreeBSD__) && !defined(__APPLE__) #if !defined(__FreeBSD__) && !defined(__APPLE__)
::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; rInfo("truncate failed for %s (%i) size %" PRIi64 ", error %s",
rInfo("truncate failed for %s (%i) size %" PRIi64 ", error %s", name.c_str(), fd, size, strerror(eno));
name.c_str(), fd, size, strerror(eno)); res = -eno;
res = -eno; knownSize = false;
knownSize = false; } else {
} else res = 0;
{ fileSize = size;
res = 0; knownSize = true;
fileSize = size; }
knownSize = true;
}
return res; return res;
} }
bool RawFileIO::isWritable() const bool RawFileIO::isWritable() const { return canWrite; }
{
return canWrite;
}

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -25,40 +25,38 @@
#include <string> #include <string>
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 rel::Interface interface() const; virtual rel::Interface interface() const;
virtual void setFileName( const char *fileName ); virtual void setFileName(const char *fileName);
virtual const char *getFileName() const; virtual const char *getFileName() const;
virtual int open( int flags ); virtual int open(int flags);
virtual int getAttr( struct stat *stbuf ) const;
virtual off_t getSize() const;
virtual ssize_t read( const IORequest & req ) const; virtual int getAttr(struct stat *stbuf) const;
virtual bool write( const IORequest &req ); virtual off_t getSize() const;
virtual int truncate( off_t size ); virtual ssize_t read(const IORequest &req) const;
virtual bool write(const IORequest &req);
virtual bool isWritable() const; virtual int truncate(off_t size);
protected:
std::string name; virtual bool isWritable() const;
bool knownSize; protected:
off_t fileSize; std::string name;
int fd; bool knownSize;
int oldfd; off_t fileSize;
bool canWrite;
int fd;
int oldfd;
bool canWrite;
}; };
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -55,9 +55,9 @@ typedef struct evp_cipher_st EVP_CIPHER;
as: as:
1. shuffle 1. shuffle
2. encrypt 2. encrypt
3. reverse 3. reverse
4. shuffle 4. shuffle
5. encrypt 5. encrypt
The reason for the shuffle and reverse steps (and the second encrypt pass) The reason for the shuffle and reverse steps (and the second encrypt pass)
is to try and propogate any changed bits to a larger set. If only a single is to try and propogate any changed bits to a larger set. If only a single
pass was made with the stream cipher in CFB mode, then a change to one byte pass was made with the stream cipher in CFB mode, then a change to one byte
@ -68,83 +68,78 @@ typedef struct evp_cipher_st EVP_CIPHER;
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 SSL_Cipher : public Cipher class SSL_Cipher : public Cipher {
{ rel::Interface iface;
rel::Interface iface; rel::Interface realIface;
rel::Interface realIface; const EVP_CIPHER *_blockCipher;
const EVP_CIPHER *_blockCipher; const EVP_CIPHER *_streamCipher;
const EVP_CIPHER *_streamCipher; unsigned int _keySize; // in bytes
unsigned int _keySize; // in bytes unsigned int _ivLength;
unsigned int _ivLength;
public: public:
SSL_Cipher(const rel::Interface &iface, const rel::Interface &realIface, SSL_Cipher(const rel::Interface &iface, const rel::Interface &realIface,
const EVP_CIPHER *blockCipher, const EVP_CIPHER *streamCipher, const EVP_CIPHER *blockCipher, const EVP_CIPHER *streamCipher,
int keyLength); int keyLength);
virtual ~SSL_Cipher(); virtual ~SSL_Cipher();
// returns the real interface, not the one we're emulating (if any).. // returns the real interface, not the one we're emulating (if any)..
virtual rel::Interface interface() const; virtual rel::Interface interface() const;
// create a new key based on a password // create a new key based on a password
virtual CipherKey newKey(const char *password, int passwdLength, virtual CipherKey newKey(const char *password, int passwdLength,
int &iterationCount, long desiredDuration, int &iterationCount, long desiredDuration,
const unsigned char *salt, int saltLen); const unsigned char *salt, int saltLen);
// deprecated - for backward compatibility // deprecated - for backward compatibility
virtual CipherKey newKey(const char *password, int passwdLength); virtual CipherKey newKey(const char *password, int passwdLength);
// create a new random key // create a new random key
virtual CipherKey newRandomKey(); virtual CipherKey newRandomKey();
// data must be len keySize() // data must be len keySize()
virtual CipherKey readKey(const unsigned char *data, virtual CipherKey readKey(const unsigned char *data,
const CipherKey &encodingKey, const CipherKey &encodingKey, bool checkKey);
bool checkKey); virtual void writeKey(const CipherKey &key, unsigned char *data,
virtual void writeKey(const CipherKey &key, unsigned char *data, const CipherKey &encodingKey);
const CipherKey &encodingKey); virtual bool compareKey(const CipherKey &A, const CipherKey &B) const;
virtual bool compareKey( const CipherKey &A,
const CipherKey &B ) const;
// meta-data about the cypher // meta-data about the cypher
virtual int keySize() const; virtual int keySize() const;
virtual int encodedKeySize() const; virtual int encodedKeySize() const;
virtual int cipherBlockSize() const; virtual int cipherBlockSize() const;
virtual bool randomize( unsigned char *buf, int len, virtual bool randomize(unsigned char *buf, int len, bool strongRandom) const;
bool strongRandom ) const;
virtual uint64_t MAC_64( const unsigned char *src, int len, virtual uint64_t MAC_64(const unsigned char *src, int len,
const CipherKey &key, uint64_t *augment ) const; const CipherKey &key, uint64_t *augment) const;
// functional interfaces // functional interfaces
/* /*
Stream encoding in-place. Stream encoding in-place.
*/ */
virtual bool streamEncode(unsigned char *in, int len, virtual bool streamEncode(unsigned char *in, int len, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const; const CipherKey &key) const;
virtual bool streamDecode(unsigned char *in, int len, virtual bool streamDecode(unsigned char *in, int len, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const; const CipherKey &key) const;
/* /*
Block encoding is done in-place. Partial blocks are supported, but Block encoding is done in-place. Partial blocks are supported, but
blocks are always expected to begin on a block boundary. See blocks are always expected to begin on a block boundary. See
blockSize(). blockSize().
*/ */
virtual bool blockEncode(unsigned char *buf, int size, virtual bool blockEncode(unsigned char *buf, int size, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const; const CipherKey &key) const;
virtual bool blockDecode(unsigned char *buf, int size, virtual bool blockDecode(unsigned char *buf, int size, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const; const CipherKey &key) const;
// hack to help with static builds // hack to help with static builds
static bool Enabled(); static bool Enabled();
private:
void setIVec( unsigned char *ivec, uint64_t seed,
const shared_ptr<SSLKey> &key ) const;
// deprecated - for backward compatibility private:
void setIVec_old( unsigned char *ivec, unsigned int seed, void setIVec(unsigned char *ivec, uint64_t seed,
const shared_ptr<SSLKey> &key ) const; const shared_ptr<SSLKey> &key) const;
// deprecated - for backward compatibility
void setIVec_old(unsigned char *ivec, unsigned int seed,
const shared_ptr<SSLKey> &key) const;
}; };
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -32,17 +32,16 @@
using namespace rel; using namespace rel;
using namespace std; using namespace std;
static shared_ptr<NameIO> NewStreamNameIO( const Interface &iface, static shared_ptr<NameIO> NewStreamNameIO(const Interface &iface,
const shared_ptr<Cipher> &cipher, const CipherKey &key) const shared_ptr<Cipher> &cipher,
{ const CipherKey &key) {
return shared_ptr<NameIO>( new StreamNameIO( iface, cipher, key ) ); return shared_ptr<NameIO>(new StreamNameIO(iface, cipher, key));
} }
static bool StreamIO_registered = NameIO::Register("Stream", static bool StreamIO_registered = NameIO::Register(
gettext_noop("Stream encoding, keeps filenames as short as possible"), "Stream",
StreamNameIO::CurrentInterface(), gettext_noop("Stream encoding, keeps filenames as short as possible"),
NewStreamNameIO); StreamNameIO::CurrentInterface(), NewStreamNameIO);
/* /*
- 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
@ -65,145 +64,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 Interface("nameio/stream", 2, 1, 2);
return Interface("nameio/stream", 2, 1, 2);
} }
StreamNameIO::StreamNameIO( const rel::Interface &iface, StreamNameIO::StreamNameIO(const rel::Interface &iface,
const shared_ptr<Cipher> &cipher, const shared_ptr<Cipher> &cipher,
const CipherKey &key ) const CipherKey &key)
: _interface( iface.current() ) : _interface(iface.current()), _cipher(cipher), _key(key) {}
, _cipher( cipher )
, _key( key )
{
StreamNameIO::~StreamNameIO() {}
Interface StreamNameIO::interface() const { return CurrentInterface(); }
int StreamNameIO::maxEncodedNameLen(int plaintextStreamLen) const {
int encodedStreamLen = 2 + plaintextStreamLen;
return B256ToB64Bytes(encodedStreamLen);
} }
StreamNameIO::~StreamNameIO() int StreamNameIO::maxDecodedNameLen(int encodedStreamLen) const {
{ int decLen256 = B64ToB256Bytes(encodedStreamLen);
return decLen256 - 2;
} }
Interface StreamNameIO::interface() const int StreamNameIO::encodeName(const char *plaintextName, int length,
{ uint64_t *iv, char *encodedName) const {
return CurrentInterface(); uint64_t tmpIV = 0;
if (iv && _interface >= 2) tmpIV = *iv;
unsigned int mac =
_cipher->MAC_16((const unsigned char *)plaintextName, length, _key, iv);
// add on checksum bytes
unsigned char *encodeBegin;
if (_interface >= 1) {
// current versions store the checksum at the beginning
encodedName[0] = (mac >> 8) & 0xff;
encodedName[1] = (mac) & 0xff;
encodeBegin = (unsigned char *)encodedName + 2;
} else {
// encfs 0.x stored checksums at the end.
encodedName[length] = (mac >> 8) & 0xff;
encodedName[length + 1] = (mac) & 0xff;
encodeBegin = (unsigned char *)encodedName;
}
// stream encode the plaintext bytes
memcpy(encodeBegin, plaintextName, length);
_cipher->nameEncode(encodeBegin, length, (uint64_t)mac ^ tmpIV, _key);
// convert the entire thing to base 64 ascii..
int encodedStreamLen = length + 2;
int encLen64 = B256ToB64Bytes(encodedStreamLen);
changeBase2Inline((unsigned char *)encodedName, encodedStreamLen, 8, 6, true);
B64ToAscii((unsigned char *)encodedName, encLen64);
return encLen64;
} }
int StreamNameIO::maxEncodedNameLen( int plaintextStreamLen ) const int StreamNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
{ char *plaintextName) const {
int encodedStreamLen = 2 + plaintextStreamLen; rAssert(length > 2);
return B256ToB64Bytes( encodedStreamLen ); int decLen256 = B64ToB256Bytes(length);
} int decodedStreamLen = decLen256 - 2;
int StreamNameIO::maxDecodedNameLen( int encodedStreamLen ) const if (decodedStreamLen <= 0) throw ERROR("Filename too small to decode");
{
int decLen256 = B64ToB256Bytes( encodedStreamLen ); BUFFER_INIT(tmpBuf, 32, (unsigned int)length);
return decLen256 - 2;
} // decode into tmpBuf, because this step produces more data then we can fit
// into the result buffer..
int StreamNameIO::encodeName( const char *plaintextName, int length, AsciiToB64((unsigned char *)tmpBuf, (unsigned char *)encodedName, length);
uint64_t *iv, char *encodedName ) const changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false);
{
uint64_t tmpIV = 0; // pull out the checksum value which is used as an initialization vector
if( iv && _interface >= 2 ) uint64_t tmpIV = 0;
tmpIV = *iv; unsigned int mac;
if (_interface >= 1) {
unsigned int mac = _cipher->MAC_16( (const unsigned char *)plaintextName, // current versions store the checksum at the beginning
length, _key, iv ); mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 |
((unsigned int)((unsigned char)tmpBuf[1]));
// add on checksum bytes
unsigned char *encodeBegin; // version 2 adds support for IV chaining..
if(_interface >= 1) if (iv && _interface >= 2) tmpIV = *iv;
{
// current versions store the checksum at the beginning memcpy(plaintextName, tmpBuf + 2, decodedStreamLen);
encodedName[0] = (mac >> 8) & 0xff; } else {
encodedName[1] = (mac ) & 0xff; // encfs 0.x stored checksums at the end.
encodeBegin = (unsigned char *)encodedName+2; mac = ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen])) << 8 |
} else ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen + 1]));
{
// encfs 0.x stored checksums at the end. memcpy(plaintextName, tmpBuf, decodedStreamLen);
encodedName[length] = (mac >> 8) & 0xff; }
encodedName[length+1] = (mac ) & 0xff;
encodeBegin = (unsigned char *)encodedName; // use nameDeocde instead of streamDecode for backward compatibility
} _cipher->nameDecode((unsigned char *)plaintextName, decodedStreamLen,
(uint64_t)mac ^ tmpIV, _key);
// stream encode the plaintext bytes
memcpy( encodeBegin, plaintextName, length ); // compute MAC to check with stored value
_cipher->nameEncode( encodeBegin, length, (uint64_t)mac ^ tmpIV, _key); unsigned int mac2 = _cipher->MAC_16((const unsigned char *)plaintextName,
decodedStreamLen, _key, iv);
// convert the entire thing to base 64 ascii..
int encodedStreamLen = length + 2; BUFFER_RESET(tmpBuf);
int encLen64 = B256ToB64Bytes( encodedStreamLen ); if (mac2 != mac) {
rDebug("checksum mismatch: expected %u, got %u", mac, mac2);
changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen, rDebug("on decode of %i bytes", decodedStreamLen);
8, 6, true ); throw ERROR("checksum mismatch in filename decode");
B64ToAscii( (unsigned char *)encodedName, encLen64 ); }
return encLen64; return decodedStreamLen;
}
int StreamNameIO::decodeName( const char *encodedName, int length,
uint64_t *iv, char *plaintextName ) const
{
rAssert(length > 2);
int decLen256 = B64ToB256Bytes( length );
int decodedStreamLen = decLen256 - 2;
if(decodedStreamLen <= 0)
throw ERROR("Filename too small to decode");
BUFFER_INIT( tmpBuf, 32, (unsigned int)length );
// decode into tmpBuf, because this step produces more data then we can fit
// into the result buffer..
AsciiToB64( (unsigned char *)tmpBuf, (unsigned char *)encodedName, length );
changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false);
// pull out the checksum value which is used as an initialization vector
uint64_t tmpIV = 0;
unsigned int mac;
if(_interface >= 1)
{
// current versions store the checksum at the beginning
mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8
| ((unsigned int)((unsigned char)tmpBuf[1]));
// version 2 adds support for IV chaining..
if( iv && _interface >= 2 )
tmpIV = *iv;
memcpy( plaintextName, tmpBuf+2, decodedStreamLen );
} else
{
// encfs 0.x stored checksums at the end.
mac = ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen])) << 8
| ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen+1]));
memcpy( plaintextName, tmpBuf, decodedStreamLen );
}
// use nameDeocde instead of streamDecode for backward compatibility
_cipher->nameDecode( (unsigned char *)plaintextName, decodedStreamLen,
(uint64_t)mac ^ tmpIV, _key);
// compute MAC to check with stored value
unsigned int mac2 = _cipher->MAC_16((const unsigned char *)plaintextName,
decodedStreamLen, _key, iv);
BUFFER_RESET( tmpBuf );
if(mac2 != mac)
{
rDebug("checksum mismatch: expected %u, got %u", mac, mac2);
rDebug("on decode of %i bytes", decodedStreamLen);
throw ERROR( "checksum mismatch in filename decode" );
}
return decodedStreamLen;
}
bool StreamNameIO::Enabled()
{
return true;
} }
bool StreamNameIO::Enabled() { return true; }

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -26,34 +26,32 @@
class Cipher; class Cipher;
class StreamNameIO : public NameIO class StreamNameIO : public NameIO {
{ public:
public: static rel::Interface CurrentInterface();
static rel::Interface CurrentInterface();
StreamNameIO( const rel::Interface &iface, StreamNameIO(const rel::Interface &iface, const shared_ptr<Cipher> &cipher,
const shared_ptr<Cipher> &cipher, const CipherKey &key);
const CipherKey &key ); virtual ~StreamNameIO();
virtual ~StreamNameIO();
virtual rel::Interface interface() const; virtual rel::Interface interface() const;
virtual int maxEncodedNameLen( int plaintextNameLen ) const; virtual int maxEncodedNameLen(int plaintextNameLen) const;
virtual int maxDecodedNameLen( int encodedNameLen ) const; virtual int maxDecodedNameLen(int encodedNameLen) const;
// hack to help with static builds // hack to help with static builds
static bool Enabled(); static bool Enabled();
protected:
virtual int encodeName( const char *plaintextName, int length, protected:
uint64_t *iv, char *encodedName ) const; virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
virtual int decodeName( const char *encodedName, int length, char *encodedName) const;
uint64_t *iv, char *plaintextName ) const; virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
private: char *plaintextName) const;
int _interface;
shared_ptr<Cipher> _cipher; private:
CipherKey _key; int _interface;
shared_ptr<Cipher> _cipher;
CipherKey _key;
}; };
#endif #endif

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -27,32 +27,28 @@
// 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(unsigned char *src, int srcLen, int src2Pow, void changeBase2(unsigned char *src, int srcLen, int src2Pow,
unsigned char *dst, int dstLen, int dst2Pow) unsigned char *dst, int dstLen, 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 unsigned char *end = src + srcLen;
unsigned char *end = src + srcLen; unsigned char *origDst = dst;
unsigned char *origDst = dst; const int mask = (1 << dst2Pow) - 1;
const int mask = (1 << dst2Pow) -1;
// copy the new bits onto the high bits of the stream. // copy the new bits onto the high bits of the stream.
// The bits that fall off the low end are the output bits. // The bits that fall off the low end are the output bits.
while(src != end) while (src != end) {
{ work |= ((unsigned long)(*src++)) << workBits;
work |= ((unsigned long)(*src++)) << workBits; workBits += src2Pow;
workBits += src2Pow;
while(workBits >= dst2Pow) while (workBits >= dst2Pow) {
{ *dst++ = work & mask;
*dst++ = work & mask; work >>= dst2Pow;
work >>= dst2Pow; workBits -= dst2Pow;
workBits -= dst2Pow;
}
} }
}
// now, we could have a partial value left in the work buffer.. // now, we could have a partial value left in the work buffer..
if(workBits && ((dst - origDst) < dstLen)) if (workBits && ((dst - origDst) < dstLen)) *dst++ = work & mask;
*dst++ = work & mask;
} }
/* /*
@ -62,65 +58,52 @@ void changeBase2(unsigned char *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(unsigned char *src, int srcLen, int src2Pow,
void changeBase2Inline(unsigned char *src, int srcLen, int dst2Pow, bool outputPartialLastByte,
int src2Pow, int dst2Pow, unsigned long work, int workBits,
bool outputPartialLastByte, unsigned char *outLoc) {
unsigned long work, const int mask = (1 << dst2Pow) - 1;
int workBits, if (!outLoc) outLoc = src;
unsigned char *outLoc)
{
const int mask = (1 << dst2Pow) -1;
if(!outLoc)
outLoc = src;
// copy the new bits onto the high bits of the stream. // copy the new bits onto the high bits of the stream.
// The bits that fall off the low end are the output bits. // The bits that fall off the low end are the output bits.
while(srcLen && workBits < dst2Pow) while (srcLen && workBits < dst2Pow) {
{ work |= ((unsigned long)(*src++)) << workBits;
work |= ((unsigned long)(*src++)) << workBits; workBits += src2Pow;
workBits += src2Pow; --srcLen;
--srcLen; }
}
// we have at least one value that can be output
// we have at least one value that can be output unsigned char outVal = work & mask;
unsigned char outVal = work & mask; work >>= dst2Pow;
work >>= dst2Pow; workBits -= dst2Pow;
workBits -= dst2Pow;
if (srcLen) {
if(srcLen) // more input left, so recurse
{ changeBase2Inline(src, srcLen, src2Pow, dst2Pow, outputPartialLastByte,
// more input left, so recurse work, workBits, outLoc + 1);
changeBase2Inline( src, srcLen, src2Pow, dst2Pow, *outLoc = outVal;
outputPartialLastByte, work, workBits, outLoc+1); } else {
*outLoc = outVal; // no input left, we can write remaining values directly
} else *outLoc++ = outVal;
{
// no input left, we can write remaining values directly // we could have a partial value left in the work buffer..
*outLoc++ = outVal; if (outputPartialLastByte) {
while (workBits > 0) {
// we could have a partial value left in the work buffer.. *outLoc++ = work & mask;
if(outputPartialLastByte) work >>= dst2Pow;
{ workBits -= dst2Pow;
while(workBits > 0) }
{
*outLoc++ = work & mask;
work >>= dst2Pow;
workBits -= dst2Pow;
}
}
} }
}
} }
void changeBase2Inline(unsigned char *src, int srcLen, void changeBase2Inline(unsigned char *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
@ -128,83 +111,69 @@ void changeBase2Inline(unsigned char *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(unsigned char *in, int length) void B64ToAscii(unsigned char *in, int length) {
{ for (int offset = 0; offset < length; ++offset) {
for(int offset=0; offset<length; ++offset) int ch = in[offset];
{ if (ch > 11) {
int ch = in[offset]; if (ch > 37)
if(ch > 11) ch += 'a' - 38;
{ else
if(ch > 37) ch += 'A' - 12;
ch += 'a' - 38; } else
else ch = B642AsciiTable[ch];
ch += 'A' - 12;
} else in[offset] = ch;
ch = B642AsciiTable[ ch ]; }
in[offset] = ch;
}
} }
static const unsigned char Ascii2B64Table[] = static const unsigned char 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(unsigned char *in, int length) void AsciiToB64(unsigned char *in, int length) {
{ return AsciiToB64(in, in, length);
return AsciiToB64(in, in, length);
} }
void AsciiToB64(unsigned char *out, const unsigned char *in, int length) void AsciiToB64(unsigned char *out, const unsigned char *in, int length) {
{ while (length--) {
while(length--) unsigned char ch = *in++;
{ if (ch >= 'A') {
unsigned char ch = *in++; if (ch >= 'a')
if(ch >= 'A') ch += 38 - 'a';
{ else
if(ch >= 'a') ch += 12 - 'A';
ch += 38 - 'a'; } else
else ch = Ascii2B64Table[ch] - '0';
ch += 12 - 'A';
} else
ch = Ascii2B64Table[ ch ] - '0';
*out++ = ch; *out++ = ch;
} }
} }
void B32ToAscii(unsigned char *buf, int len) {
for (int offset = 0; offset < len; ++offset) {
int ch = buf[offset];
if (ch >= 0 && ch < 26)
ch += 'A';
else
ch += '2' - 26;
void B32ToAscii(unsigned char *buf, int len) buf[offset] = ch;
{ }
for(int offset=0; offset<len; ++offset)
{
int ch = buf[offset];
if (ch >= 0 && ch < 26)
ch += 'A';
else
ch += '2' - 26;
buf[offset] = ch;
}
} }
void AsciiToB32(unsigned char *in, int length) void AsciiToB32(unsigned char *in, int length) {
{ return AsciiToB32(in, in, length);
return AsciiToB32(in, in, length);
} }
void AsciiToB32(unsigned char *out, const unsigned char *in, int length) void AsciiToB32(unsigned char *out, const unsigned char *in, int length) {
{ while (length--) {
while(length--) unsigned char ch = *in++;
{ int lch = toupper(ch);
unsigned char ch = *in++; if (lch >= 'A')
int lch = toupper(ch); lch -= 'A';
if (lch >= 'A') else
lch -= 'A'; lch += 26 - '2';
else
lch += 26 - '2';
*out++ = (unsigned char)lch; *out++ = (unsigned char)lch;
} }
} }

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -21,41 +21,33 @@
#ifndef _base64_incl_ #ifndef _base64_incl_
#define _base64_incl_ #define _base64_incl_
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(unsigned char *src, int srcLength, int srcPow2, void changeBase2(unsigned char *src, int srcLength, int srcPow2,
unsigned char *dst, int dstLength, int dstPow2); unsigned char *dst, 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(unsigned char *buf, int srcLength, void changeBase2Inline(unsigned char *buf, int srcLength, int srcPow2,
int srcPow2, int dst2Pow, 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(unsigned char *buf, int length); void B64ToAscii(unsigned char *buf, int length);
@ -71,4 +63,3 @@ void AsciiToB32(unsigned char *buf, int length);
void AsciiToB32(unsigned char *out, const unsigned char *in, int length); void AsciiToB32(unsigned char *out, const unsigned char *in, int length);
#endif #endif

View File

@ -4,7 +4,6 @@
// This header stores workaround code for dealing with incompatible changes // This header stores workaround code for dealing with incompatible changes
// made to boost archive/serialization classes. // made to boost archive/serialization classes.
#if (BOOST_VERSION <= 104100) #if (BOOST_VERSION <= 104100)
// Easy case, boost archive serial numbers are sizeof(int) // Easy case, boost archive serial numbers are sizeof(int)
BOOST_CLASS_VERSION(EncFSConfig, V6SubVersion) BOOST_CLASS_VERSION(EncFSConfig, V6SubVersion)
@ -23,74 +22,60 @@ BOOST_CLASS_VERSION(EncFSConfig, V6SubVersion)
BOOST_CLASS_VERSION(EncFSConfig, 20) BOOST_CLASS_VERSION(EncFSConfig, 20)
namespace boost { namespace boost {
namespace archive { namespace archive {
namespace detail { namespace detail {
// Specialize iserializer class in order to get rid of version check // Specialize iserializer class in order to get rid of version check
template<class Archive> template <class Archive>
class iserializer<Archive, EncFSConfig> : public basic_iserializer class iserializer<Archive, EncFSConfig> : public basic_iserializer {
{ private:
private: virtual void destroy(/*const*/ void *address) const {
virtual void destroy(/*const*/ void *address) const { boost::serialization::access::destroy(static_cast<EncFSConfig *>(address));
boost::serialization::access::destroy(static_cast<EncFSConfig *>(address)); }
}
protected: protected:
explicit iserializer() : explicit iserializer()
basic_iserializer( : basic_iserializer(boost::serialization::singleton<
boost::serialization::singleton< BOOST_DEDUCED_TYPENAME boost::serialization::
BOOST_DEDUCED_TYPENAME type_info_implementation<
boost::serialization::type_info_implementation<EncFSConfig>::type EncFSConfig>::type>::get_const_instance()) {}
>::get_const_instance()
) public:
{} virtual BOOST_DLLEXPORT void load_object_data(
public: basic_iarchive &ar, void *x,
virtual BOOST_DLLEXPORT void load_object_data( const unsigned int file_version) const BOOST_USED;
basic_iarchive & ar, virtual bool class_info() const {
void *x, return boost::serialization::implementation_level<EncFSConfig>::value >=
const unsigned int file_version boost::serialization::object_class_info;
) const BOOST_USED; }
virtual bool class_info() const { virtual bool tracking(const unsigned int /* flags */) const {
return boost::serialization::implementation_level<EncFSConfig>::value return boost::serialization::tracking_level<EncFSConfig>::value ==
>= boost::serialization::object_class_info; boost::serialization::track_always ||
} (boost::serialization::tracking_level<EncFSConfig>::value ==
virtual bool tracking(const unsigned int /* flags */) const { boost::serialization::track_selectively &&
return boost::serialization::tracking_level<EncFSConfig>::value serialized_as_pointer());
== boost::serialization::track_always }
|| ( boost::serialization::tracking_level<EncFSConfig>::value virtual version_type version() const {
== boost::serialization::track_selectively return version_type(::boost::serialization::version<EncFSConfig>::value);
&& serialized_as_pointer()); }
} virtual bool is_polymorphic() const {
virtual version_type version() const { return boost::is_polymorphic<EncFSConfig>::value;
return version_type(::boost::serialization::version<EncFSConfig>::value); }
} virtual ~iserializer() {};
virtual bool is_polymorphic() const {
return boost::is_polymorphic<EncFSConfig>::value;
}
virtual ~iserializer(){};
}; };
template<class Archive> template <class Archive>
BOOST_DLLEXPORT void iserializer<Archive, EncFSConfig>::load_object_data( BOOST_DLLEXPORT void iserializer<Archive, EncFSConfig>::load_object_data(
basic_iarchive & ar, basic_iarchive &ar, void *x, const unsigned int file_version) const {
void *x, boost::serialization::serialize_adl(
const unsigned int file_version boost::serialization::smart_cast_reference<Archive &>(ar),
) const { *static_cast<EncFSConfig *>(x), file_version);
boost::serialization::serialize_adl(
boost::serialization::smart_cast_reference<Archive &>(ar),
* static_cast<EncFSConfig *>(x),
file_version
);
} }
} }
} }
} }
#endif #endif
#endif // BOOST_VERSIONING_INCL
#endif // BOOST_VERSIONING_INCL

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -32,34 +32,30 @@
#ifndef linux #ifndef linux
#include <cerrno> #include <cerrno>
static __inline int setfsuid(uid_t uid) static __inline int setfsuid(uid_t uid) {
{ uid_t olduid = geteuid();
uid_t olduid = geteuid();
seteuid(uid); seteuid(uid);
if (errno != EINVAL) if (errno != EINVAL) errno = 0;
errno = 0;
return olduid; return olduid;
} }
static __inline int setfsgid(gid_t gid) static __inline int setfsgid(gid_t gid) {
{ gid_t oldgid = getegid();
gid_t oldgid = getegid();
setegid(gid); setegid(gid);
if (errno != EINVAL) if (errno != EINVAL) errno = 0;
errno = 0;
return oldgid; return oldgid;
} }
#endif #endif
int encfs_getattr(const char *path, struct stat *stbuf); int encfs_getattr(const char *path, struct stat *stbuf);
int encfs_fgetattr(const char *path, struct stat *stbuf, int encfs_fgetattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi); struct fuse_file_info *fi);
int encfs_readlink(const char *path, char *buf, size_t size); int encfs_readlink(const char *path, char *buf, size_t size);
int encfs_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler); int encfs_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler);
int encfs_mknod(const char *path, mode_t mode, dev_t rdev); int encfs_mknod(const char *path, mode_t mode, dev_t rdev);
@ -72,38 +68,36 @@ int encfs_link(const char *from, const char *to);
int encfs_chmod(const char *path, mode_t mode); int encfs_chmod(const char *path, mode_t mode);
int encfs_chown(const char *path, uid_t uid, gid_t gid); int encfs_chown(const char *path, uid_t uid, gid_t gid);
int encfs_truncate(const char *path, off_t size); int encfs_truncate(const char *path, off_t size);
int encfs_ftruncate(const char *path, off_t size, int encfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi);
struct fuse_file_info *fi);
int encfs_utime(const char *path, struct utimbuf *buf); int encfs_utime(const char *path, struct utimbuf *buf);
int encfs_open(const char *path, struct fuse_file_info *info); int encfs_open(const char *path, struct fuse_file_info *info);
int encfs_release(const char *path, struct fuse_file_info *info); int encfs_release(const char *path, struct fuse_file_info *info);
int encfs_read(const char *path, char *buf, size_t size, off_t offset, int encfs_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *info); struct fuse_file_info *info);
int encfs_write(const char *path, const char *buf, size_t size, off_t offset, int encfs_write(const char *path, const char *buf, size_t size, off_t offset,
struct fuse_file_info *info); struct fuse_file_info *info);
int encfs_statfs(const char *, struct statvfs *fst); int encfs_statfs(const char *, struct statvfs *fst);
int encfs_flush(const char *, struct fuse_file_info *info); int encfs_flush(const char *, struct fuse_file_info *info);
int encfs_fsync(const char *path, int flags, struct fuse_file_info *info); int encfs_fsync(const char *path, int flags, struct fuse_file_info *info);
#ifdef HAVE_XATTR #ifdef HAVE_XATTR
# ifdef XATTR_ADD_OPT #ifdef XATTR_ADD_OPT
int encfs_setxattr( const char *path, const char *name, const char *value, int encfs_setxattr(const char *path, const char *name, const char *value,
size_t size, int flags, uint32_t position); size_t size, int flags, uint32_t position);
int encfs_getxattr( const char *path, const char *name, char *value, int encfs_getxattr(const char *path, const char *name, char *value, size_t size,
size_t size, uint32_t position ); uint32_t position);
# else #else
int encfs_setxattr( const char *path, const char *name, const char *value, int encfs_setxattr(const char *path, const char *name, const char *value,
size_t size, int flags); size_t size, int flags);
int encfs_getxattr( const char *path, const char *name, char *value, int encfs_getxattr(const char *path, const char *name, char *value,
size_t size ); size_t size);
# endif
int encfs_listxattr( const char *path, char *list, size_t size );
int encfs_removexattr( const char *path, const char *name );
#endif #endif
int encfs_utimens( const char *path, const struct timespec ts[2] ); int encfs_listxattr(const char *path, char *list, size_t size);
int encfs_removexattr(const char *path, const char *name);
#endif #endif
int encfs_utimens(const char *path, const struct timespec ts[2]);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -25,8 +25,6 @@
#include "intl/gettext.h" #include "intl/gettext.h"
// make shortcut for gettext // make shortcut for gettext
# define _(STR) gettext (STR) #define _(STR) gettext(STR)
#endif #endif

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -31,79 +31,65 @@
#include <openssl/engine.h> #include <openssl/engine.h>
#endif #endif
unsigned long pthreads_thread_id() unsigned long pthreads_thread_id() { return (unsigned long)pthread_self(); }
{
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) {
{ rDebug("Allocating %i locks for OpenSSL", CRYPTO_num_locks());
rDebug("Allocating %i locks for OpenSSL", CRYPTO_num_locks() ); 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) delete[] crypto_locks;
pthread_mutex_destroy( crypto_locks+i ); crypto_locks = NULL;
delete[] crypto_locks; }
crypto_locks = NULL;
}
} }
void openssl_init(bool threaded) void openssl_init(bool threaded) {
{ // initialize the SSL library
// initialize the SSL library SSL_load_error_strings();
SSL_load_error_strings(); SSL_library_init();
SSL_library_init();
unsigned int randSeed = 0; unsigned int randSeed = 0;
RAND_bytes( (unsigned char*)&randSeed, sizeof(randSeed) ); RAND_bytes((unsigned char *)&randSeed, sizeof(randSeed));
srand( randSeed ); srand(randSeed);
#ifndef OPENSSL_NO_ENGINE #ifndef OPENSSL_NO_ENGINE
/* Load all bundled ENGINEs into memory and make them visible */ /* Load all bundled ENGINEs into memory and make them visible */
ENGINE_load_builtin_engines(); ENGINE_load_builtin_engines();
/* Register all of them for every algorithm they collectively implement */ /* Register all of them for every algorithm they collectively implement */
ENGINE_register_all_complete(); ENGINE_register_all_complete();
#endif // NO_ENGINE #endif // NO_ENGINE
if(threaded) if (threaded) {
{ // provide locking functions to OpenSSL since we'll be running with
// provide locking functions to OpenSSL since we'll be running with // threads accessing openssl in parallel.
// threads accessing openssl in parallel. CRYPTO_set_id_callback(pthreads_thread_id);
CRYPTO_set_id_callback( pthreads_thread_id ); CRYPTO_set_locking_callback(pthreads_locking_callback);
CRYPTO_set_locking_callback( pthreads_locking_callback ); }
}
} }
void openssl_shutdown(bool threaded) void openssl_shutdown(bool threaded) {
{
#ifndef OPENSSL_NO_ENGINE #ifndef OPENSSL_NO_ENGINE
ENGINE_cleanup(); ENGINE_cleanup();
#endif #endif
if(threaded) if (threaded) pthreads_locking_cleanup();
pthreads_locking_cleanup();
} }

View File

@ -7,7 +7,7 @@
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your * Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -25,5 +25,3 @@ void openssl_init(bool isThreaded);
void openssl_shutdown(bool isThreaded); void openssl_shutdown(bool isThreaded);
#endif #endif

View File

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

View File

@ -47,491 +47,398 @@
#endif #endif
#endif #endif
using namespace std; using namespace std;
using namespace rel; using namespace rel;
using namespace rlog; using namespace rlog;
const int FSBlockSize = 256; const int FSBlockSize = 256;
static static int checkErrorPropogation(const shared_ptr<Cipher> &cipher, int size,
int checkErrorPropogation( const shared_ptr<Cipher> &cipher, int byteToChange, const CipherKey &key) {
int size, int byteToChange, const CipherKey &key ) MemBlock orig = MemoryPool::allocate(size);
{ MemBlock data = MemoryPool::allocate(size);
MemBlock orig = MemoryPool::allocate(size);
MemBlock data = MemoryPool::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, key ); cipher->streamEncode(data.data, size, 0, key);
else else
cipher->blockEncode( data.data, size, 0, key ); cipher->blockEncode(data.data, size, 0, key);
// intoduce an error in the encoded data, so we can check error propogation
if(byteToChange >= 0 && byteToChange < size)
{
unsigned char previousValue = data.data[byteToChange];
do
{
data.data[byteToChange] = rand();
} while(data.data[byteToChange] == previousValue);
}
if(size != FSBlockSize) // intoduce an error in the encoded data, so we can check error propogation
cipher->streamDecode( data.data, size, 0, key ); if (byteToChange >= 0 && byteToChange < size) {
else unsigned char previousValue = data.data[byteToChange];
cipher->blockDecode( data.data, size, 0, key ); do {
data.data[byteToChange] = rand();
} while (data.data[byteToChange] == previousValue);
}
int numByteErrors = 0; if (size != FSBlockSize)
for(int i=0; i<size; ++i) cipher->streamDecode(data.data, size, 0, key);
{ else
if( data.data[i] != orig.data[i] ) cipher->blockDecode(data.data, size, 0, key);
++numByteErrors;
}
MemoryPool::release( data ); int numByteErrors = 0;
MemoryPool::release( orig ); for (int i = 0; i < size; ++i) {
if (data.data[i] != orig.data[i]) ++numByteErrors;
}
return numByteErrors; MemoryPool::release(data);
MemoryPool::release(orig);
return numByteErrors;
} }
const char TEST_ROOTDIR[] = "/foo"; const char TEST_ROOTDIR[] = "/foo";
static static bool testNameCoding(DirNode &dirNode, bool verbose) {
bool testNameCoding( DirNode &dirNode, bool verbose ) // encrypt a name
{ const char *name[] = {
// encrypt a name "1234567", "12345678", "123456789",
const char *name[] = { "123456789ABCDEF", "123456789ABCDEF0", "123456789ABCDEF01",
"1234567", "test-name", "test-name2", "test",
"12345678", "../test", "/foo/bar/blah", "test-name.21",
"123456789", "test-name.22", "test-name.o", "1.test",
"123456789ABCDEF", "2.test", "a/b/c/d", "a/c/d/e",
"123456789ABCDEF0", "b/c/d/e", "b/a/c/d", NULL};
"123456789ABCDEF01",
"test-name",
"test-name2",
"test",
"../test",
"/foo/bar/blah",
"test-name.21",
"test-name.22",
"test-name.o",
"1.test",
"2.test",
"a/b/c/d",
"a/c/d/e",
"b/c/d/e",
"b/a/c/d",
NULL
};
const char **orig = name; 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 return false;
{
if(verbose)
cerr << " FAILED (got " << decName << ")\n";
return false;
}
orig++;
} }
return true; orig++;
}
return true;
} }
bool runTests(const shared_ptr<Cipher> &cipher, bool verbose) bool runTests(const shared_ptr<Cipher> &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->writeKey( key, keyBuf, encodingKey ); cipher->writeKey(key, keyBuf, encodingKey);
CipherKey key2 = cipher->readKey( keyBuf, encodingKey ); CipherKey key2 = cipher->readKey(keyBuf, encodingKey);
if(!key2) if (!key2) {
{ if (verbose) cerr << " FAILED (decode error)\n";
if(verbose) return false;
cerr << " FAILED (decode error)\n";
return false;
}
if(cipher->compareKey( key, key2 ))
{
if(verbose)
cerr << " OK\n";
} else
{
if(verbose)
cerr << " FAILED\n";
return false;
}
}
if(verbose)
cerr << "Testing Config interface load / store :";
{
CipherKey encodingKey = cipher->newRandomKey();
int encodedKeySize = cipher->encodedKeySize();
unsigned char *keyBuf = new unsigned char [ encodedKeySize ];
cipher->writeKey( key, keyBuf, encodingKey );
// store in config struct..
EncFSConfig cfg;
cfg.cipherIface = cipher->interface();
cfg.keySize = 8 * cipher->keySize();
cfg.blockSize = FSBlockSize;
cfg.assignKeyData( keyBuf, encodedKeySize );
// save config
string data;
{
ostringstream st;
st << cfg;
data = st.str();
}
// read back in and check everything..
EncFSConfig cfg2;
{
istringstream st(data);
st >> cfg2;
}
// check..
rAssert( cfg.cipherIface.implements(cfg2.cipherIface) );
rAssert( cfg.keySize == cfg2.keySize );
rAssert( cfg.blockSize == cfg2.blockSize );
// try decoding key..
CipherKey key2 = cipher->readKey( cfg2.getKeyData(), encodingKey );
if(!key2)
{
if(verbose)
cerr << " FAILED (decode error)\n";
return false;
}
if(cipher->compareKey( key, key2 ))
{
if(verbose)
cerr << " OK\n";
} else
{
if(verbose)
cerr << " FAILED\n";
return false;
}
} }
FSConfigPtr fsCfg = FSConfigPtr(new FSConfig); if (cipher->compareKey(key, key2)) {
fsCfg->cipher = cipher; if (verbose) cerr << " OK\n";
fsCfg->key = key; } else {
fsCfg->config.reset(new EncFSConfig); if (verbose) cerr << " FAILED\n";
fsCfg->config->blockSize = FSBlockSize; return false;
if(verbose)
cerr << "Testing name encode/decode (stream coding w/ IV chaining)\n";
{
fsCfg->opts.reset(new EncFS_Opts);
fsCfg->opts->idleTracking = false;
fsCfg->config->uniqueIV = false;
fsCfg->nameCoding.reset( new StreamNameIO(
StreamNameIO::CurrentInterface(), cipher, key ) );
fsCfg->nameCoding->setChainedNameIV( true );
DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg );
if(!testNameCoding( dirNode, verbose ))
return false;
} }
}
if(verbose)
cerr << "Testing name encode/decode (block coding w/ IV chaining)\n"; if (verbose) cerr << "Testing Config interface load / store :";
{
CipherKey encodingKey = cipher->newRandomKey();
int encodedKeySize = cipher->encodedKeySize();
unsigned char *keyBuf = new unsigned char[encodedKeySize];
cipher->writeKey(key, keyBuf, encodingKey);
// store in config struct..
EncFSConfig cfg;
cfg.cipherIface = cipher->interface();
cfg.keySize = 8 * cipher->keySize();
cfg.blockSize = FSBlockSize;
cfg.assignKeyData(keyBuf, encodedKeySize);
// save config
string data;
{ {
fsCfg->opts->idleTracking = false; ostringstream st;
fsCfg->config->uniqueIV = false; st << cfg;
fsCfg->nameCoding.reset( new BlockNameIO( data = st.str();
BlockNameIO::CurrentInterface(), cipher, key,
cipher->cipherBlockSize() ) );
fsCfg->nameCoding->setChainedNameIV( true );
DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg );
if(!testNameCoding( dirNode, verbose ))
return false;
}
if(verbose)
cerr << "Testing name encode/decode (block coding w/ IV chaining, base32)\n";
{
fsCfg->opts->idleTracking = false;
fsCfg->config->uniqueIV = false;
fsCfg->nameCoding.reset( new BlockNameIO(
BlockNameIO::CurrentInterface(), cipher, key,
cipher->cipherBlockSize(), true ) );
fsCfg->nameCoding->setChainedNameIV( true );
DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg );
if(!testNameCoding( dirNode, verbose ))
return false;
}
if(!verbose)
{
{
// test stream mode, this time without IV chaining
fsCfg->nameCoding =
shared_ptr<NameIO>( new StreamNameIO(
StreamNameIO::CurrentInterface(), cipher, key ) );
fsCfg->nameCoding->setChainedNameIV( false );
DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg );
if(!testNameCoding( dirNode, verbose ))
return false;
}
{
// test block mode, this time without IV chaining
fsCfg->nameCoding = shared_ptr<NameIO>( new BlockNameIO(
BlockNameIO::CurrentInterface(), cipher, key,
cipher->cipherBlockSize() ) );
fsCfg->nameCoding->setChainedNameIV( false );
DirNode dirNode( NULL, TEST_ROOTDIR, fsCfg );
if(!testNameCoding( dirNode, verbose ))
return false;
}
} }
if(verbose) // read back in and check everything..
cerr << "Testing block encode/decode on full block - "; EncFSConfig cfg2;
{ {
int numErrors = checkErrorPropogation( cipher, istringstream st(data);
FSBlockSize, -1, key ); st >> cfg2;
if(numErrors)
{
if(verbose)
cerr << " FAILED!\n";
return false;
} else
{
if(verbose)
cerr << " OK\n";
}
}
if(verbose)
cerr << "Testing block encode/decode on partial block - ";
{
int numErrors = checkErrorPropogation( cipher,
FSBlockSize-1, -1, key );
if(numErrors)
{
if(verbose)
cerr << " FAILED!\n";
return false;
} else
{
if(verbose)
cerr << " OK\n";
}
} }
if(verbose) // check..
cerr << "Checking error propogation in partial block:\n"; rAssert(cfg.cipherIface.implements(cfg2.cipherIface));
{ rAssert(cfg.keySize == cfg2.keySize);
int minChanges = FSBlockSize-1; rAssert(cfg.blockSize == cfg2.blockSize);
int maxChanges = 0;
int minAt = 0;
int maxAt = 0;
for(int i=0; i<FSBlockSize-1; ++i)
{
int numErrors = checkErrorPropogation( cipher,
FSBlockSize-1, i, key );
if(numErrors < minChanges) // try decoding key..
{
minChanges = numErrors;
minAt = i;
}
if(numErrors > maxChanges)
{
maxChanges = numErrors;
maxAt = i;
}
}
if(verbose) CipherKey key2 = cipher->readKey(cfg2.getKeyData(), encodingKey);
{ if (!key2) {
cerr << "modification of 1 byte affected between " << minChanges if (verbose) cerr << " FAILED (decode error)\n";
<< " and " << maxChanges << " decoded bytes\n"; return false;
cerr << "minimum change at byte " << minAt
<< " and maximum at byte " << maxAt << "\n";
}
}
if(verbose)
cerr << "Checking error propogation on full block:\n";
{
int minChanges = FSBlockSize;
int maxChanges = 0;
int minAt = 0;
int maxAt = 0;
for(int i=0; i<FSBlockSize; ++i)
{
int numErrors = checkErrorPropogation( cipher,
FSBlockSize, i, key );
if(numErrors < minChanges)
{
minChanges = numErrors;
minAt = i;
}
if(numErrors > maxChanges)
{
maxChanges = numErrors;
maxAt = i;
}
}
if(verbose)
{
cerr << "modification of 1 byte affected between " << minChanges
<< " and " << maxChanges << " decoded bytes\n";
cerr << "minimum change at byte " << minAt
<< " and maximum at byte " << maxAt << "\n";
}
} }
return true; if (cipher->compareKey(key, key2)) {
if (verbose) cerr << " OK\n";
} else {
if (verbose) cerr << " FAILED\n";
return false;
}
}
FSConfigPtr fsCfg = FSConfigPtr(new FSConfig);
fsCfg->cipher = cipher;
fsCfg->key = key;
fsCfg->config.reset(new EncFSConfig);
fsCfg->config->blockSize = FSBlockSize;
if (verbose)
cerr << "Testing name encode/decode (stream coding w/ IV chaining)\n";
{
fsCfg->opts.reset(new EncFS_Opts);
fsCfg->opts->idleTracking = false;
fsCfg->config->uniqueIV = false;
fsCfg->nameCoding.reset(
new StreamNameIO(StreamNameIO::CurrentInterface(), cipher, key));
fsCfg->nameCoding->setChainedNameIV(true);
DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg);
if (!testNameCoding(dirNode, verbose)) return false;
}
if (verbose)
cerr << "Testing name encode/decode (block coding w/ IV chaining)\n";
{
fsCfg->opts->idleTracking = false;
fsCfg->config->uniqueIV = false;
fsCfg->nameCoding.reset(new BlockNameIO(BlockNameIO::CurrentInterface(),
cipher, key,
cipher->cipherBlockSize()));
fsCfg->nameCoding->setChainedNameIV(true);
DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg);
if (!testNameCoding(dirNode, verbose)) return false;
}
if (verbose)
cerr
<< "Testing name encode/decode (block coding w/ IV chaining, base32)\n";
{
fsCfg->opts->idleTracking = false;
fsCfg->config->uniqueIV = false;
fsCfg->nameCoding.reset(new BlockNameIO(BlockNameIO::CurrentInterface(),
cipher, key,
cipher->cipherBlockSize(), true));
fsCfg->nameCoding->setChainedNameIV(true);
DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg);
if (!testNameCoding(dirNode, verbose)) return false;
}
if (!verbose) {
{
// test stream mode, this time without IV chaining
fsCfg->nameCoding = shared_ptr<NameIO>(
new StreamNameIO(StreamNameIO::CurrentInterface(), cipher, key));
fsCfg->nameCoding->setChainedNameIV(false);
DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg);
if (!testNameCoding(dirNode, verbose)) return false;
}
{
// test block mode, this time without IV chaining
fsCfg->nameCoding = shared_ptr<NameIO>(
new BlockNameIO(BlockNameIO::CurrentInterface(), cipher, key,
cipher->cipherBlockSize()));
fsCfg->nameCoding->setChainedNameIV(false);
DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg);
if (!testNameCoding(dirNode, verbose)) return false;
}
}
if (verbose) cerr << "Testing block encode/decode on full block - ";
{
int numErrors = checkErrorPropogation(cipher, FSBlockSize, -1, key);
if (numErrors) {
if (verbose) cerr << " FAILED!\n";
return false;
} else {
if (verbose) cerr << " OK\n";
}
}
if (verbose) cerr << "Testing block encode/decode on partial block - ";
{
int numErrors = checkErrorPropogation(cipher, FSBlockSize - 1, -1, key);
if (numErrors) {
if (verbose) cerr << " FAILED!\n";
return false;
} else {
if (verbose) cerr << " OK\n";
}
}
if (verbose) cerr << "Checking error propogation in partial block:\n";
{
int minChanges = FSBlockSize - 1;
int maxChanges = 0;
int minAt = 0;
int maxAt = 0;
for (int i = 0; i < FSBlockSize - 1; ++i) {
int numErrors = checkErrorPropogation(cipher, FSBlockSize - 1, i, key);
if (numErrors < minChanges) {
minChanges = numErrors;
minAt = i;
}
if (numErrors > maxChanges) {
maxChanges = numErrors;
maxAt = i;
}
}
if (verbose) {
cerr << "modification of 1 byte affected between " << minChanges
<< " and " << maxChanges << " decoded bytes\n";
cerr << "minimum change at byte " << minAt << " and maximum at byte "
<< maxAt << "\n";
}
}
if (verbose) cerr << "Checking error propogation on full block:\n";
{
int minChanges = FSBlockSize;
int maxChanges = 0;
int minAt = 0;
int maxAt = 0;
for (int i = 0; i < FSBlockSize; ++i) {
int numErrors = checkErrorPropogation(cipher, FSBlockSize, i, key);
if (numErrors < minChanges) {
minChanges = numErrors;
minAt = i;
}
if (numErrors > maxChanges) {
maxChanges = numErrors;
maxAt = i;
}
}
if (verbose) {
cerr << "modification of 1 byte affected between " << minChanges
<< " and " << maxChanges << " decoded bytes\n";
cerr << "minimum change at byte " << minAt << " and maximum at byte "
<< maxAt << "\n";
}
}
return true;
} }
int main(int argc, char *argv[]) {
RLogInit(argc, argv);
int main(int argc, char *argv[]) StdioNode stdLog(STDERR_FILENO);
{ stdLog.subscribeTo(RLOG_CHANNEL("error"));
RLogInit( argc, argv ); stdLog.subscribeTo(RLOG_CHANNEL("warning"));
StdioNode stdLog( STDERR_FILENO );
stdLog.subscribeTo( RLOG_CHANNEL("error") );
stdLog.subscribeTo( RLOG_CHANNEL("warning") );
#ifndef NO_DEBUG #ifndef NO_DEBUG
stdLog.subscribeTo( RLOG_CHANNEL("debug") ); stdLog.subscribeTo(RLOG_CHANNEL("debug"));
#endif #endif
#ifdef HAVE_SSL #ifdef HAVE_SSL
SSL_load_error_strings(); SSL_load_error_strings();
SSL_library_init(); SSL_library_init();
#ifndef OPENSSL_NO_ENGINE #ifndef OPENSSL_NO_ENGINE
ENGINE_load_builtin_engines(); ENGINE_load_builtin_engines();
ENGINE_register_all_ciphers(); ENGINE_register_all_ciphers();
ENGINE_register_all_digests(); ENGINE_register_all_digests();
ENGINE_register_all_RAND(); ENGINE_register_all_RAND();
#endif #endif
#endif #endif
srand( time(0) ); srand(time(0));
// get a list of the available algorithms // get a list of the available algorithms
std::list<Cipher::CipherAlgorithm> algorithms = std::list<Cipher::CipherAlgorithm> algorithms = Cipher::GetAlgorithmList();
Cipher::GetAlgorithmList(); std::list<Cipher::CipherAlgorithm>::const_iterator it;
std::list<Cipher::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.current()
{ << ":" << it->iface.revision() << ":" << it->iface.age()
cerr << it->name << " ) : " << it->description << "\n";
<< " ( " << it->iface.name() << " " cerr << " - key length " << it->keyLength.min() << " to "
<< it->iface.current() << ":" << it->keyLength.max() << " , block size " << it->blockSize.min()
<< it->iface.revision() << ":" << " to " << it->blockSize.max() << "\n";
<< it->iface.age() << " ) : " << it->description << "\n"; }
cerr << " - key length " << it->keyLength.min() << " to " cerr << "\n";
<< it->keyLength.max() << " , block size " << it->blockSize.min()
<< " to " << it->blockSize.max() << "\n"; cerr << "Testing interfaces\n";
for (it = algorithms.begin(); it != algorithms.end(); ++it) {
int blockSize = it->blockSize.closest(256);
for (int keySize = it->keyLength.min(); keySize <= it->keyLength.max();
keySize += it->keyLength.inc()) {
cerr << it->name << ", key length " << keySize << ", block size "
<< blockSize << ": ";
shared_ptr<Cipher> cipher = Cipher::New(it->name, keySize);
if (!cipher) {
cerr << "FAILED TO CREATE\n";
} else {
try {
if (runTests(cipher, false))
cerr << "OK\n";
else
cerr << "FAILED\n";
}
catch (rlog::Error &er) {
cerr << "Error: " << er.what() << "\n";
}
}
} }
cerr << "\n"; }
cerr << "Testing interfaces\n"; // run one test with verbose output too..
for(it = algorithms.begin(); it != algorithms.end(); ++it) shared_ptr<Cipher> cipher = Cipher::New("AES", 192);
{ if (!cipher) {
int blockSize = it->blockSize.closest( 256 ); cerr << "\nNo AES cipher found, skipping verbose test.\n";
for(int keySize = it->keyLength.min(); keySize <= it->keyLength.max(); } else {
keySize += it->keyLength.inc()) cerr << "\nVerbose output for " << cipher->interface().name()
{ << " test, key length " << cipher->keySize() * 8 << ", block size "
cerr << it->name << ", key length " << keySize << FSBlockSize << ":\n";
<< ", block size " << blockSize << ": ";
shared_ptr<Cipher> cipher = Cipher::New( it->name, keySize ); runTests(cipher, true);
if(!cipher) }
{
cerr << "FAILED TO CREATE\n";
} else
{
try
{
if(runTests( cipher, false ))
cerr << "OK\n";
else
cerr << "FAILED\n";
} catch( rlog::Error &er )
{
cerr << "Error: " << er.what() << "\n";
}
}
}
}
// run one test with verbose output too.. MemoryPool::destroyAll();
shared_ptr<Cipher> cipher = Cipher::New("AES", 192);
if(!cipher)
{
cerr << "\nNo AES cipher found, skipping verbose test.\n";
} else
{
cerr << "\nVerbose output for " << cipher->interface().name()
<< " test, key length " << cipher->keySize()*8 << ", block size "
<< FSBlockSize << ":\n";
runTests( cipher, true ); return 0;
}
MemoryPool::destroyAll();
return 0;
} }