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

@ -27,406 +27,347 @@
#include "i18n.h"
template<typename Type>
inline Type min( Type A, Type B )
{
return (B < A) ? B : A;
template <typename Type>
inline Type min(Type A, Type B) {
return (B < A) ? B : A;
}
static void clearCache( IORequest &req, int blockSize )
{
memset( req.data, 0, blockSize );
req.dataLen = 0;
static void clearCache(IORequest &req, int blockSize) {
memset(req.data, 0, blockSize);
req.dataLen = 0;
}
BlockFileIO::BlockFileIO( int blockSize, const FSConfigPtr &cfg )
: _blockSize( blockSize )
, _allowHoles( cfg->config->allowHoles )
{
rAssert( _blockSize > 1 );
_cache.data = new unsigned char [ _blockSize ];
BlockFileIO::BlockFileIO(int blockSize, const FSConfigPtr &cfg)
: _blockSize(blockSize), _allowHoles(cfg->config->allowHoles) {
rAssert(_blockSize > 1);
_cache.data = new unsigned char[_blockSize];
}
BlockFileIO::~BlockFileIO()
{
clearCache( _cache, _blockSize );
delete[] _cache.data;
BlockFileIO::~BlockFileIO() {
clearCache(_cache, _blockSize);
delete[] _cache.data;
}
ssize_t BlockFileIO::cacheReadOneBlock( const IORequest &req ) const
{
// we can satisfy the request even if _cache.dataLen is too short, because
// we always request a full block during reads..
if((req.offset == _cache.offset) && (_cache.dataLen != 0))
{
// satisfy request from cache
int len = req.dataLen;
if(_cache.dataLen < len)
len = _cache.dataLen;
memcpy( req.data, _cache.data, len );
return len;
} else
{
if(_cache.dataLen > 0)
clearCache( _cache, _blockSize );
ssize_t BlockFileIO::cacheReadOneBlock(const IORequest &req) const {
// we can satisfy the request even if _cache.dataLen is too short, because
// we always request a full block during reads..
if ((req.offset == _cache.offset) && (_cache.dataLen != 0)) {
// satisfy request from cache
int len = req.dataLen;
if (_cache.dataLen < len) len = _cache.dataLen;
memcpy(req.data, _cache.data, len);
return len;
} else {
if (_cache.dataLen > 0) clearCache(_cache, _blockSize);
// cache results of read -- issue reads for full blocks
IORequest tmp;
tmp.offset = req.offset;
tmp.data = _cache.data;
tmp.dataLen = _blockSize;
ssize_t result = readOneBlock( tmp );
if(result > 0)
{
_cache.offset = req.offset;
_cache.dataLen = result; // the amount we really have
if(result > req.dataLen)
result = req.dataLen; // only as much as requested
memcpy( req.data, _cache.data, result );
}
return result;
// cache results of read -- issue reads for full blocks
IORequest tmp;
tmp.offset = req.offset;
tmp.data = _cache.data;
tmp.dataLen = _blockSize;
ssize_t result = readOneBlock(tmp);
if (result > 0) {
_cache.offset = req.offset;
_cache.dataLen = result; // the amount we really have
if (result > req.dataLen)
result = req.dataLen; // only as much as requested
memcpy(req.data, _cache.data, result);
}
}
bool BlockFileIO::cacheWriteOneBlock( const IORequest &req )
{
// cache results of write (before pass-thru, because it may be modified
// in-place)
memcpy( _cache.data, req.data, req.dataLen );
_cache.offset = req.offset;
_cache.dataLen = req.dataLen;
bool ok = writeOneBlock( req );
if(!ok)
clearCache( _cache, _blockSize );
return ok;
}
ssize_t BlockFileIO::read( const IORequest &req ) const
{
rAssert( _blockSize != 0 );
int partialOffset = req.offset % _blockSize;
off_t blockNum = req.offset / _blockSize;
ssize_t result = 0;
if(partialOffset == 0 && req.dataLen <= _blockSize)
{
// read completely within a single block -- can be handled as-is by
// readOneBloc().
return cacheReadOneBlock( req );
} else
{
size_t size = req.dataLen;
// if the request is larger then a block, then request each block
// individually
MemBlock mb; // in case we need to allocate a temporary block..
IORequest blockReq; // for requests we may need to make
blockReq.dataLen = _blockSize;
blockReq.data = NULL;
unsigned char *out = req.data;
while( size )
{
blockReq.offset = blockNum * _blockSize;
// if we're reading a full block, then read directly into the
// result buffer instead of using a temporary
if(partialOffset == 0 && size >= (size_t)_blockSize)
blockReq.data = out;
else
{
if(!mb.data)
mb = MemoryPool::allocate( _blockSize );
blockReq.data = mb.data;
}
ssize_t readSize = cacheReadOneBlock( blockReq );
if(unlikely(readSize <= partialOffset))
break; // didn't get enough bytes
int cpySize = min( (size_t)(readSize - partialOffset), size );
rAssert(cpySize <= readSize);
// if we read to a temporary buffer, then move the data
if(blockReq.data != out)
memcpy( out, blockReq.data + partialOffset, cpySize );
result += cpySize;
size -= cpySize;
out += cpySize;
++blockNum;
partialOffset = 0;
if(unlikely(readSize < _blockSize))
break;
}
if(mb.data)
MemoryPool::release( mb );
}
return result;
}
}
bool BlockFileIO::write( const IORequest &req )
{
rAssert( _blockSize != 0 );
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;
}
off_t fileSize = getSize();
ssize_t BlockFileIO::read(const IORequest &req) const {
rAssert(_blockSize != 0);
// where write request begins
off_t blockNum = req.offset / _blockSize;
int partialOffset = req.offset % _blockSize;
int partialOffset = req.offset % _blockSize;
off_t blockNum = req.offset / _blockSize;
ssize_t result = 0;
// 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;
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;
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 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;
if(blockNum > lastNonEmptyBlock)
{
// just pad..
blockReq.dataLen = toCopy + partialOffset;
} else
{
// have to merge with existing block data..
blockReq.dataLen = _blockSize;
blockReq.dataLen = cacheReadOneBlock( blockReq );
unsigned char *out = req.data;
while (size) {
blockReq.offset = blockNum * _blockSize;
// 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 );
}
// 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;
}
// Finally, write the damn thing!
if(!cacheWriteOneBlock( blockReq ))
{
ok = false;
break;
}
ssize_t readSize = cacheReadOneBlock(blockReq);
if (unlikely(readSize <= partialOffset))
break; // didn't get enough bytes
// prepare to start all over with the next block..
size -= toCopy;
inPtr += toCopy;
++blockNum;
partialOffset = 0;
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 );
if (mb.data) MemoryPool::release(mb);
}
return ok;
return result;
}
int BlockFileIO::blockSize() const
{
return _blockSize;
bool BlockFileIO::write(const IORequest &req) {
rAssert(_blockSize != 0);
off_t fileSize = getSize();
// where write request begins
off_t blockNum = req.offset / _blockSize;
int partialOffset = req.offset % _blockSize;
// last block of file (for testing write overlaps with file boundary)
off_t lastFileBlock = fileSize / _blockSize;
ssize_t lastBlockSize = fileSize % _blockSize;
off_t lastNonEmptyBlock = lastFileBlock;
if (lastBlockSize == 0) --lastNonEmptyBlock;
if (req.offset > fileSize) {
// extend file first to fill hole with 0's..
const bool forceWrite = false;
padFile(fileSize, req.offset, forceWrite);
}
// check against edge cases where we can just let the base class handle the
// request as-is..
if (partialOffset == 0 && req.dataLen <= _blockSize) {
// if writing a full block.. pretty safe..
if (req.dataLen == _blockSize) return cacheWriteOneBlock(req);
// if writing a partial block, but at least as much as what is
// already there..
if (blockNum == lastFileBlock && req.dataLen >= lastBlockSize)
return cacheWriteOneBlock(req);
}
// have to merge data with existing block(s)..
MemBlock mb;
IORequest blockReq;
blockReq.data = NULL;
blockReq.dataLen = _blockSize;
bool ok = true;
size_t size = req.dataLen;
unsigned char *inPtr = req.data;
while (size) {
blockReq.offset = blockNum * _blockSize;
int toCopy = min((size_t)(_blockSize - partialOffset), size);
// if writing an entire block, or writing a partial block that requires
// no merging with existing data..
if ((toCopy == _blockSize) ||
(partialOffset == 0 && blockReq.offset + toCopy >= fileSize)) {
// write directly from buffer
blockReq.data = inPtr;
blockReq.dataLen = toCopy;
} else {
// need a temporary buffer, since we have to either merge or pad
// the data.
if (!mb.data) mb = MemoryPool::allocate(_blockSize);
memset(mb.data, 0, _blockSize);
blockReq.data = mb.data;
if (blockNum > lastNonEmptyBlock) {
// just pad..
blockReq.dataLen = toCopy + partialOffset;
} else {
// have to merge with existing block data..
blockReq.dataLen = _blockSize;
blockReq.dataLen = cacheReadOneBlock(blockReq);
// extend data if necessary..
if (partialOffset + toCopy > blockReq.dataLen)
blockReq.dataLen = partialOffset + toCopy;
}
// merge in the data to be written..
memcpy(blockReq.data + partialOffset, inPtr, toCopy);
}
// Finally, write the damn thing!
if (!cacheWriteOneBlock(blockReq)) {
ok = false;
break;
}
// prepare to start all over with the next block..
size -= toCopy;
inPtr += toCopy;
++blockNum;
partialOffset = 0;
}
if (mb.data) MemoryPool::release(mb);
return ok;
}
void BlockFileIO::padFile( off_t oldSize, off_t newSize, bool forceWrite )
{
off_t oldLastBlock = oldSize / _blockSize;
off_t newLastBlock = newSize / _blockSize;
int newBlockSize = newSize % _blockSize;
int BlockFileIO::blockSize() const { return _blockSize; }
void BlockFileIO::padFile(off_t oldSize, off_t newSize, bool forceWrite) {
off_t oldLastBlock = oldSize / _blockSize;
off_t newLastBlock = newSize / _blockSize;
int newBlockSize = newSize % _blockSize;
IORequest req;
MemBlock mb;
if (oldLastBlock == newLastBlock) {
// when the real write occurs, it will have to read in the existing
// data and pad it anyway, so we won't do it here (unless we're
// forced).
if (forceWrite) {
mb = MemoryPool::allocate(_blockSize);
req.data = mb.data;
req.offset = oldLastBlock * _blockSize;
req.dataLen = oldSize % _blockSize;
int outSize = newSize % _blockSize; // outSize > req.dataLen
if (outSize) {
memset(mb.data, 0, outSize);
cacheReadOneBlock(req);
req.dataLen = outSize;
cacheWriteOneBlock(req);
}
} else
rDebug("optimization: not padding last block");
} else {
mb = MemoryPool::allocate(_blockSize);
req.data = mb.data;
// 1. extend the first block to full length
// 2. write the middle empty blocks
// 3. write the last block
req.offset = oldLastBlock * _blockSize;
req.dataLen = oldSize % _blockSize;
// 1. req.dataLen == 0, iff oldSize was already a multiple of blocksize
if (req.dataLen != 0) {
rDebug("padding block %" PRIi64, oldLastBlock);
memset(mb.data, 0, _blockSize);
cacheReadOneBlock(req);
req.dataLen = _blockSize; // expand to full block size
cacheWriteOneBlock(req);
++oldLastBlock;
}
// 2, pad zero blocks unless holes are allowed
if (!_allowHoles) {
for (; oldLastBlock != newLastBlock; ++oldLastBlock) {
rDebug("padding block %" PRIi64, oldLastBlock);
req.offset = oldLastBlock * _blockSize;
req.dataLen = _blockSize;
memset(mb.data, 0, req.dataLen);
cacheWriteOneBlock(req);
}
}
// 3. only necessary if write is forced and block is non 0 length
if (forceWrite && newBlockSize) {
req.offset = newLastBlock * _blockSize;
req.dataLen = newBlockSize;
memset(mb.data, 0, req.dataLen);
cacheWriteOneBlock(req);
}
}
if (mb.data) MemoryPool::release(mb);
}
int BlockFileIO::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;
MemBlock mb;
req.offset = blockNum * _blockSize;
req.dataLen = _blockSize;
req.data = mb.data;
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;
ssize_t rdSz = cacheReadOneBlock(req);
req.offset = oldLastBlock * _blockSize;
req.dataLen = oldSize % _blockSize;
int outSize = newSize % _blockSize; // outSize > req.dataLen
// do the truncate
if (base) res = base->truncate(size);
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;
// write back out partial block
req.dataLen = partialBlock;
bool wrRes = cacheWriteOneBlock(req);
// 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 ((rdSz < 0) || (!wrRes)) {
// rwarning - unlikely to ever occur..
rWarning(_("truncate failure: read %i bytes, partial block of %i"),
(int)rdSz, partialBlock);
}
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

@ -32,37 +32,34 @@
the existing block, merge with the write request, and a write of the full
block.
*/
class BlockFileIO : public FileIO
{
public:
BlockFileIO( int blockSize, const FSConfigPtr &cfg );
virtual ~BlockFileIO();
class BlockFileIO : public FileIO {
public:
BlockFileIO(int blockSize, const FSConfigPtr &cfg);
virtual ~BlockFileIO();
// implemented in terms of blocks.
virtual ssize_t read( const IORequest &req ) const;
virtual bool write( const IORequest &req );
// implemented in terms of blocks.
virtual ssize_t read(const IORequest &req) const;
virtual bool write(const IORequest &req);
virtual int blockSize() const;
virtual int blockSize() const;
protected:
protected:
int truncateBase(off_t size, FileIO *base);
void padFile(off_t oldSize, off_t newSize, bool forceWrite);
int truncateBase( off_t size, FileIO *base );
void padFile( off_t oldSize, off_t newSize, bool forceWrite );
// same as read(), except that the request.offset field is guarenteed to be
// block aligned, and the request size will not be larger then 1 block.
virtual ssize_t readOneBlock(const IORequest &req) const = 0;
virtual bool writeOneBlock(const IORequest &req) = 0;
// same as read(), except that the request.offset field is guarenteed to be
// block aligned, and the request size will not be larger then 1 block.
virtual ssize_t readOneBlock( const IORequest &req ) const =0;
virtual bool writeOneBlock( const IORequest &req ) =0;
ssize_t cacheReadOneBlock(const IORequest &req) const;
bool cacheWriteOneBlock(const IORequest &req);
ssize_t cacheReadOneBlock( const IORequest &req ) const;
bool cacheWriteOneBlock( const IORequest &req );
int _blockSize;
bool _allowHoles;
int _blockSize;
bool _allowHoles;
// cache last block for speed...
mutable IORequest _cache;
// cache last block for speed...
mutable IORequest _cache;
};
#endif

View File

@ -33,44 +33,42 @@
using namespace rlog;
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,
const shared_ptr<Cipher> &cipher, const CipherKey &key )
{
int blockSize = 8;
if(cipher)
blockSize = cipher->cipherBlockSize();
return shared_ptr<NameIO>(
new BlockNameIO( iface, cipher, key, blockSize, false));
return shared_ptr<NameIO>(
new BlockNameIO(iface, cipher, key, blockSize, false));
}
static shared_ptr<NameIO> NewBlockNameIO32( const Interface &iface,
const shared_ptr<Cipher> &cipher, const CipherKey &key )
{
int blockSize = 8;
if(cipher)
blockSize = cipher->cipherBlockSize();
static shared_ptr<NameIO> NewBlockNameIO32(const Interface &iface,
const shared_ptr<Cipher> &cipher,
const CipherKey &key) {
int blockSize = 8;
if (cipher) blockSize = cipher->cipherBlockSize();
return shared_ptr<NameIO>(
new BlockNameIO( iface, cipher, key, blockSize, true));
return shared_ptr<NameIO>(
new BlockNameIO(iface, cipher, key, blockSize, true));
}
static bool BlockIO_registered = NameIO::Register("Block",
// description of block name encoding algorithm..
// xgroup(setup)
gettext_noop("Block encoding, hides file name size somewhat"),
BlockNameIO::CurrentInterface(false),
NewBlockNameIO);
static bool BlockIO_registered = NameIO::Register(
"Block",
// description of block name encoding algorithm..
// xgroup(setup)
gettext_noop("Block encoding, hides file name size somewhat"),
BlockNameIO::CurrentInterface(false), NewBlockNameIO);
static bool BlockIO32_registered = NameIO::Register("Block32",
// description of block name encoding algorithm..
// xgroup(setup)
gettext_noop("Block encoding with base32 output for case-sensitive systems"),
BlockNameIO::CurrentInterface(true),
NewBlockNameIO32);
static bool BlockIO32_registered = NameIO::Register(
"Block32",
// description of block name encoding algorithm..
// xgroup(setup)
gettext_noop(
"Block encoding with base32 output for case-sensitive systems"),
BlockNameIO::CurrentInterface(true), NewBlockNameIO32);
/*
- Version 1.0 computed MAC over the filename, but not the padding bytes.
@ -89,180 +87,153 @@ static bool BlockIO32_registered = NameIO::Register("Block32",
- Version 4.0 adds support for base32, creating names more suitable for
case-insensitive filesystems (eg Mac).
*/
Interface BlockNameIO::CurrentInterface(bool caseSensitive)
{
// implement major version 4 plus support for two prior versions
if (caseSensitive)
return Interface("nameio/block32", 4, 0, 2);
else
return Interface("nameio/block", 4, 0, 2);
Interface BlockNameIO::CurrentInterface(bool caseSensitive) {
// implement major version 4 plus support for two prior versions
if (caseSensitive)
return Interface("nameio/block32", 4, 0, 2);
else
return Interface("nameio/block", 4, 0, 2);
}
BlockNameIO::BlockNameIO( const rel::Interface &iface,
const shared_ptr<Cipher> &cipher,
const CipherKey &key, int blockSize,
bool caseSensitiveEncoding )
: _interface( iface.current() )
, _bs( blockSize )
, _cipher( cipher )
, _key( key )
, _caseSensitive( caseSensitiveEncoding )
{
// just to be safe..
rAssert( blockSize < 128 );
BlockNameIO::BlockNameIO(const rel::Interface &iface,
const shared_ptr<Cipher> &cipher, const CipherKey &key,
int blockSize, bool caseSensitiveEncoding)
: _interface(iface.current()),
_bs(blockSize),
_cipher(cipher),
_key(key),
_caseSensitive(caseSensitiveEncoding) {
// just to be safe..
rAssert(blockSize < 128);
}
BlockNameIO::~BlockNameIO()
{
BlockNameIO::~BlockNameIO() {}
Interface BlockNameIO::interface() const {
return CurrentInterface(_caseSensitive);
}
Interface BlockNameIO::interface() const
{
return CurrentInterface(_caseSensitive);
int BlockNameIO::maxEncodedNameLen(int plaintextNameLen) const {
// number of blocks, rounded up.. Only an estimate at this point, err on
// the size of too much space rather then too little.
int numBlocks = (plaintextNameLen + _bs) / _bs;
int encodedNameLen = numBlocks * _bs + 2; // 2 checksum bytes
if (_caseSensitive)
return B256ToB32Bytes(encodedNameLen);
else
return B256ToB64Bytes(encodedNameLen);
}
int BlockNameIO::maxEncodedNameLen( int plaintextNameLen ) const
{
// number of blocks, rounded up.. Only an estimate at this point, err on
// the size of too much space rather then too little.
int numBlocks = ( plaintextNameLen + _bs ) / _bs;
int encodedNameLen = numBlocks * _bs + 2; // 2 checksum bytes
if (_caseSensitive)
return B256ToB32Bytes( encodedNameLen );
else
return B256ToB64Bytes( encodedNameLen );
int BlockNameIO::maxDecodedNameLen(int encodedNameLen) const {
int decLen256 = _caseSensitive ? B32ToB256Bytes(encodedNameLen)
: B64ToB256Bytes(encodedNameLen);
return decLen256 - 2; // 2 checksum bytes removed..
}
int BlockNameIO::maxDecodedNameLen( int encodedNameLen ) const
{
int decLen256 = _caseSensitive ?
B32ToB256Bytes( encodedNameLen ) :
B64ToB256Bytes( encodedNameLen );
return decLen256 - 2; // 2 checksum bytes removed..
int BlockNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv,
char *encodedName) const {
// copy the data into the encoding buffer..
memcpy(encodedName + 2, plaintextName, length);
// Pad encryption buffer to block boundary..
int padding = _bs - length % _bs;
if (padding == 0) padding = _bs; // padding a full extra block!
memset(encodedName + length + 2, (unsigned char)padding, padding);
// store the IV before it is modified by the MAC call.
uint64_t tmpIV = 0;
if (iv && _interface >= 3) tmpIV = *iv;
// include padding in MAC computation
unsigned int mac = _cipher->MAC_16((unsigned char *)encodedName + 2,
length + padding, _key, iv);
// add checksum bytes
encodedName[0] = (mac >> 8) & 0xff;
encodedName[1] = (mac) & 0xff;
_cipher->blockEncode((unsigned char *)encodedName + 2, length + padding,
(uint64_t)mac ^ tmpIV, _key);
// convert to base 64 ascii
int encodedStreamLen = length + 2 + padding;
int encLen;
if (_caseSensitive) {
encLen = B256ToB32Bytes(encodedStreamLen);
changeBase2Inline((unsigned char *)encodedName, encodedStreamLen, 8, 5,
true);
B32ToAscii((unsigned char *)encodedName, encLen);
} else {
encLen = B256ToB64Bytes(encodedStreamLen);
changeBase2Inline((unsigned char *)encodedName, encodedStreamLen, 8, 6,
true);
B64ToAscii((unsigned char *)encodedName, encLen);
}
return encLen;
}
int BlockNameIO::encodeName( const char *plaintextName, int length,
uint64_t *iv, char *encodedName ) const
{
// copy the data into the encoding buffer..
memcpy( encodedName+2, plaintextName, length );
int BlockNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
char *plaintextName) const {
int decLen256 =
_caseSensitive ? B32ToB256Bytes(length) : B64ToB256Bytes(length);
int decodedStreamLen = decLen256 - 2;
// Pad encryption buffer to block boundary..
int padding = _bs - length % _bs;
if(padding == 0)
padding = _bs; // padding a full extra block!
// don't bother trying to decode files which are too small
if (decodedStreamLen < _bs) throw ERROR("Filename too small to decode");
memset( encodedName+length+2, (unsigned char)padding, padding );
BUFFER_INIT(tmpBuf, 32, (unsigned int)length);
// store the IV before it is modified by the MAC call.
uint64_t tmpIV = 0;
if( iv && _interface >= 3 )
tmpIV = *iv;
// decode into tmpBuf,
if (_caseSensitive) {
AsciiToB32((unsigned char *)tmpBuf, (unsigned char *)encodedName, length);
changeBase2Inline((unsigned char *)tmpBuf, length, 5, 8, false);
} else {
AsciiToB64((unsigned char *)tmpBuf, (unsigned char *)encodedName, length);
changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false);
}
// include padding in MAC computation
unsigned int mac = _cipher->MAC_16( (unsigned char *)encodedName+2,
length+padding, _key, iv );
// pull out the header information
unsigned int mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 |
((unsigned int)((unsigned char)tmpBuf[1]));
// add checksum bytes
encodedName[0] = (mac >> 8) & 0xff;
encodedName[1] = (mac ) & 0xff;
uint64_t tmpIV = 0;
if (iv && _interface >= 3) tmpIV = *iv;
_cipher->blockEncode( (unsigned char *)encodedName+2, length+padding,
(uint64_t)mac ^ tmpIV, _key);
_cipher->blockDecode((unsigned char *)tmpBuf + 2, decodedStreamLen,
(uint64_t)mac ^ tmpIV, _key);
// convert to base 64 ascii
int encodedStreamLen = length + 2 + padding;
int encLen;
// find out true string length
int padding = (unsigned char)tmpBuf[2 + decodedStreamLen - 1];
int finalSize = decodedStreamLen - padding;
if (_caseSensitive)
{
encLen = B256ToB32Bytes( encodedStreamLen );
// 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");
}
changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen,
8, 5, true );
B32ToAscii( (unsigned char *)encodedName, encLen );
} else
{
encLen = B256ToB64Bytes( encodedStreamLen );
// copy out the result..
memcpy(plaintextName, tmpBuf + 2, finalSize);
plaintextName[finalSize] = '\0';
changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen,
8, 6, true );
B64ToAscii( (unsigned char *)encodedName, encLen );
}
// check the mac
unsigned int mac2 = _cipher->MAC_16((const unsigned char *)tmpBuf + 2,
decodedStreamLen, _key, iv);
return encLen;
}
int BlockNameIO::decodeName( const char *encodedName, int length,
uint64_t *iv, char *plaintextName ) const
{
int decLen256 = _caseSensitive ?
B32ToB256Bytes( length ) :
B64ToB256Bytes( length );
int decodedStreamLen = decLen256 - 2;
// don't bother trying to decode files which are too small
if(decodedStreamLen < _bs)
throw ERROR("Filename too small to decode");
BUFFER_INIT( tmpBuf, 32, (unsigned int)length );
// decode into tmpBuf,
if (_caseSensitive)
{
AsciiToB32((unsigned char *)tmpBuf, (unsigned char *)encodedName, length);
changeBase2Inline((unsigned char *)tmpBuf, length, 5, 8, false);
} else
{
AsciiToB64((unsigned char *)tmpBuf, (unsigned char *)encodedName, length);
changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false);
}
// pull out the header information
unsigned int mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8
| ((unsigned int)((unsigned char)tmpBuf[1]));
uint64_t tmpIV = 0;
if( iv && _interface >= 3 )
tmpIV = *iv;
_cipher->blockDecode( (unsigned char *)tmpBuf+2, decodedStreamLen,
(uint64_t)mac ^ tmpIV, _key);
// find out true string length
int padding = (unsigned char)tmpBuf[2+decodedStreamLen-1];
int finalSize = decodedStreamLen - padding;
// might happen if there is an error decoding..
if(padding > _bs || finalSize < 0)
{
rDebug("padding, _bx, finalSize = %i, %i, %i", padding,
_bs, finalSize);
throw ERROR( "invalid padding size" );
}
// copy out the result..
memcpy(plaintextName, tmpBuf+2, finalSize);
plaintextName[finalSize] = '\0';
// check the mac
unsigned int mac2 = _cipher->MAC_16((const unsigned char *)tmpBuf+2,
decodedStreamLen, _key, iv);
BUFFER_RESET( tmpBuf );
if(mac2 != mac)
{
rDebug("checksum mismatch: expected %u, got %u", mac, mac2);
rDebug("on decode of %i bytes", finalSize);
throw ERROR( "checksum mismatch in filename decode" );
}
return finalSize;
}
bool BlockNameIO::Enabled()
{
return true;
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; }

View File

@ -32,38 +32,35 @@ class Cipher;
mode to encode filenames. The filenames are padded to be a multiple of the
cipher block size.
*/
class BlockNameIO : public NameIO
{
public:
static rel::Interface CurrentInterface(bool caseSensitive = false);
class BlockNameIO : public NameIO {
public:
static rel::Interface CurrentInterface(bool caseSensitive = false);
BlockNameIO( const rel::Interface &iface,
const shared_ptr<Cipher> &cipher,
const CipherKey &key, int blockSize,
bool caseSensitiveEncoding = false );
virtual ~BlockNameIO();
BlockNameIO(const rel::Interface &iface, const shared_ptr<Cipher> &cipher,
const CipherKey &key, int blockSize,
bool caseSensitiveEncoding = false);
virtual ~BlockNameIO();
virtual rel::Interface interface() const;
virtual rel::Interface interface() const;
virtual int maxEncodedNameLen( int plaintextNameLen ) const;
virtual int maxDecodedNameLen( int encodedNameLen ) const;
virtual int maxEncodedNameLen(int plaintextNameLen) const;
virtual int maxDecodedNameLen(int encodedNameLen) const;
// hack to help with static builds
static bool Enabled();
protected:
virtual int encodeName( const char *plaintextName, int length,
uint64_t *iv, char *encodedName ) const;
virtual int decodeName( const char *encodedName, int length,
uint64_t *iv, char *plaintextName ) const;
// hack to help with static builds
static bool Enabled();
private:
int _interface;
int _bs;
shared_ptr<Cipher> _cipher;
CipherKey _key;
bool _caseSensitive;
protected:
virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
char *encodedName) const;
virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
char *plaintextName) const;
private:
int _interface;
int _bs;
shared_ptr<Cipher> _cipher;
CipherKey _key;
bool _caseSensitive;
};
#endif

View File

@ -38,191 +38,164 @@
using namespace std;
using namespace rel;
#define REF_MODULE(TYPE) \
if( !TYPE::Enabled() ) \
cerr << "referenceModule: should never happen\n";
#define REF_MODULE(TYPE) \
if (!TYPE::Enabled()) cerr << "referenceModule: should never happen\n";
static
void AddSymbolReferences()
{
REF_MODULE(SSL_Cipher)
REF_MODULE(NullCipher)
static void AddSymbolReferences() {
REF_MODULE(SSL_Cipher)
REF_MODULE(NullCipher)
}
struct CipherAlg
{
bool hidden;
Cipher::CipherConstructor constructor;
string description;
Interface iface;
Range keyLength;
Range blockSize;
struct CipherAlg {
bool hidden;
Cipher::CipherConstructor constructor;
string description;
Interface iface;
Range keyLength;
Range blockSize;
};
typedef multimap< string, CipherAlg> CipherMap_t;
typedef multimap<string, CipherAlg> CipherMap_t;
static CipherMap_t *gCipherMap = NULL;
std::list<Cipher::CipherAlgorithm>
Cipher::GetAlgorithmList( bool includeHidden )
{
AddSymbolReferences();
std::list<Cipher::CipherAlgorithm> Cipher::GetAlgorithmList(
bool includeHidden) {
AddSymbolReferences();
list<CipherAlgorithm> result;
list<CipherAlgorithm> result;
if(!gCipherMap)
return result;
if (!gCipherMap) return result;
CipherMap_t::const_iterator it;
CipherMap_t::const_iterator mapEnd = gCipherMap->end();
for (it = gCipherMap->begin(); it != mapEnd; ++it) {
if (includeHidden || !it->second.hidden) {
CipherAlgorithm tmp;
tmp.name = it->first;
tmp.description = it->second.description;
tmp.iface = it->second.iface;
tmp.keyLength = it->second.keyLength;
tmp.blockSize = it->second.blockSize;
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 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,
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 );
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;
}
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;
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);
CipherAlg ca;
ca.hidden = hidden;
ca.constructor = fn;
ca.description = description;
ca.iface = iface;
ca.keyLength = keyLength;
ca.blockSize = blockSize;
unsigned int mac32 = ((mac64 >> 32) & 0xffffffff) ^ (mac64 & 0xffffffff);
unsigned int mac16 = ((mac32 >> 16) & 0xffff) ^ (mac32 & 0xffff);
gCipherMap->insert( make_pair(string(name), ca) );
return true;
return mac16;
}
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;
bool Cipher::nameEncode(unsigned char *data, int len, uint64_t iv64,
const CipherKey &key) const {
return streamEncode(data, len, iv64, key);
}
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 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 );
bool Cipher::nameDecode(unsigned char *data, int len, uint64_t iv64,
const CipherKey &key) const {
return streamDecode(data, len, iv64, key);
}
string Cipher::encodeAsString(const CipherKey &key,
const CipherKey &encodingKey )
{
int encodedKeySize = this->encodedKeySize();
unsigned char *keyBuf = new unsigned char[ encodedKeySize ];
const CipherKey &encodingKey) {
int encodedKeySize = this->encodedKeySize();
unsigned char *keyBuf = new unsigned char[encodedKeySize];
// write the key, encoding it with itself.
this->writeKey( key, keyBuf, encodingKey );
// write the key, encoding it with itself.
this->writeKey(key, keyBuf, encodingKey);
int b64Len = B256ToB64Bytes( encodedKeySize );
unsigned char *b64Key = new unsigned char[ b64Len + 1 ];
int b64Len = B256ToB64Bytes(encodedKeySize);
unsigned char *b64Key = new unsigned char[b64Len + 1];
changeBase2( keyBuf, encodedKeySize, 8, b64Key, b64Len, 6 );
B64ToAscii( b64Key, b64Len );
b64Key[ b64Len - 1 ] = '\0';
changeBase2(keyBuf, encodedKeySize, 8, b64Key, b64Len, 6);
B64ToAscii(b64Key, b64Len);
b64Key[b64Len - 1] = '\0';
return string( (const char *)b64Key );
return string((const char *)b64Key);
}

View File

@ -37,129 +37,116 @@
Cipher's should register themselves so they can be instanciated via
Cipher::New().
*/
class Cipher
{
public:
// if no key length was indicated when cipher was registered, then keyLen
// <= 0 will be used.
typedef shared_ptr<Cipher> (*CipherConstructor)( const rel::Interface &iface,
int keyLenBits );
class Cipher {
public:
// if no key length was indicated when cipher was registered, then keyLen
// <= 0 will be used.
typedef shared_ptr<Cipher>(*CipherConstructor)(const rel::Interface &iface,
int keyLenBits);
struct CipherAlgorithm
{
std::string name;
std::string description;
rel::Interface iface;
Range keyLength;
Range blockSize;
};
struct CipherAlgorithm {
std::string name;
std::string description;
rel::Interface iface;
Range keyLength;
Range blockSize;
};
typedef std::list<CipherAlgorithm> AlgorithmList;
static AlgorithmList GetAlgorithmList(bool includeHidden = false);
typedef std::list<CipherAlgorithm> AlgorithmList;
static AlgorithmList GetAlgorithmList( bool includeHidden = false );
static shared_ptr<Cipher> New(const rel::Interface &iface, int keyLen = -1);
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,
int keyLen = -1);
static shared_ptr<Cipher> New( const std::string &cipherName,
int keyLen = -1 );
Cipher();
virtual ~Cipher();
virtual rel::Interface interface() const = 0;
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);
// create a new key based on a password
// if iterationCount == 0, then iteration count will be determined
// by newKey function and filled in.
// If iterationCount == 0, then desiredFunctionDuration is how many
// milliseconds the password derivation function should take to run.
virtual CipherKey newKey(const char *password, int passwdLength,
int &iterationCount, long desiredFunctionDuration,
const unsigned char *salt, int saltLen) = 0;
// deprecated - for backward compatibility
virtual CipherKey newKey(const char *password, int passwdLength) = 0;
// create a new random key
virtual CipherKey newRandomKey() = 0;
// 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 ~Cipher();
virtual std::string encodeAsString(const CipherKey &key,
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
// if iterationCount == 0, then iteration count will be determined
// by newKey function and filled in.
// If iterationCount == 0, then desiredFunctionDuration is how many
// milliseconds the password derivation function should take to run.
virtual CipherKey newKey(const char *password, int passwdLength,
int &iterationCount, long desiredFunctionDuration,
const unsigned char *salt, int saltLen) =0;
// deprecated - for backward compatibility
virtual CipherKey newKey(const char *password, int passwdLength ) =0;
// create a new random key
virtual CipherKey newRandomKey() =0;
// meta-data about the cypher
virtual int keySize() const = 0;
virtual int encodedKeySize() const = 0; // size
virtual int cipherBlockSize() const = 0; // size of a cipher block
// 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;
// fill the supplied buffer with random data
// The data may be pseudo random and might not be suitable for key
// generation. For generating keys, uses newRandomKey() instead.
// Returns true on success, false on failure.
virtual bool randomize(unsigned char *buf, int len,
bool strongRandom) const = 0;
virtual std::string encodeAsString(const CipherKey &key,
const CipherKey &encodingKey );
// 64 bit MAC of the data with the given key
virtual uint64_t MAC_64(const unsigned char *src, int len,
const CipherKey &key,
uint64_t *chainedIV = 0) const = 0;
// based on reductions of MAC_64
unsigned int MAC_32(const unsigned char *src, int len, const CipherKey &key,
uint64_t *chainedIV = 0) const;
unsigned int MAC_16(const unsigned char *src, int len, const CipherKey &key,
uint64_t *chainedIV = 0) const;
// for testing purposes
virtual bool compareKey( const CipherKey &A, const CipherKey &B ) const =0;
// functional interfaces
/*
Stream encoding of data in-place. The stream data can be any length.
*/
virtual bool streamEncode(unsigned char *data, int len, uint64_t iv64,
const CipherKey &key) const = 0;
virtual bool streamDecode(unsigned char *data, int len, uint64_t iv64,
const CipherKey &key) const = 0;
// meta-data about the cypher
virtual int keySize() const=0;
virtual int encodedKeySize() const=0; // size
virtual int cipherBlockSize() const=0; // size of a cipher block
/*
These are just aliases of streamEncode / streamDecode, but there are
provided here for backward compatibility for earlier ciphers that has
effectively two stream modes - one for encoding partial blocks and
another for encoding filenames.
*/
virtual bool nameEncode(unsigned char *data, int len, uint64_t iv64,
const CipherKey &key) const;
virtual bool nameDecode(unsigned char *data, int len, uint64_t iv64,
const CipherKey &key) const;
// fill the supplied buffer with random data
// The data may be pseudo random and might not be suitable for key
// generation. For generating keys, uses newRandomKey() instead.
// Returns true on success, false on failure.
virtual bool randomize( unsigned char *buf, int len,
bool strongRandom ) const =0;
// 64 bit MAC of the data with the given key
virtual uint64_t MAC_64( const unsigned char *src, int len,
const CipherKey &key, uint64_t *chainedIV = 0 ) const =0;
// based on reductions of MAC_64
unsigned int MAC_32( const unsigned char *src, int len,
const CipherKey &key, uint64_t *chainedIV = 0 ) const;
unsigned int MAC_16( const unsigned char *src, int len,
const CipherKey &key, uint64_t *chainedIV = 0 ) const;
// functional interfaces
/*
Stream encoding of data in-place. The stream data can be any length.
*/
virtual bool streamEncode( unsigned char *data, int len,
uint64_t iv64, const CipherKey &key) const=0;
virtual bool streamDecode( unsigned char *data, int len,
uint64_t iv64, const CipherKey &key) const=0;
/*
These are just aliases of streamEncode / streamDecode, but there are
provided here for backward compatibility for earlier ciphers that has
effectively two stream modes - one for encoding partial blocks and
another for encoding filenames.
*/
virtual bool nameEncode( unsigned char *data, int len,
uint64_t iv64, const CipherKey &key) const;
virtual bool nameDecode( unsigned char *data, int len,
uint64_t iv64, const CipherKey &key) const;
/*
Block encoding of data in-place. The data size should be a multiple of
the cipher block size.
*/
virtual bool blockEncode(unsigned char *buf, int size,
uint64_t iv64, const CipherKey &key) const=0;
virtual bool blockDecode(unsigned char *buf, int size,
uint64_t iv64, const CipherKey &key) const=0;
/*
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

View File

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

View File

@ -34,56 +34,50 @@ class Cipher;
Uses BlockFileIO to handle the block scatter / gather issues.
*/
class CipherFileIO : public BlockFileIO
{
public:
CipherFileIO( const shared_ptr<FileIO> &base,
const FSConfigPtr &cfg);
virtual ~CipherFileIO();
class CipherFileIO : public BlockFileIO {
public:
CipherFileIO(const shared_ptr<FileIO> &base, const FSConfigPtr &cfg);
virtual ~CipherFileIO();
virtual rel::Interface interface() const;
virtual rel::Interface interface() const;
virtual void setFileName( const char *fileName );
virtual const char *getFileName() const;
virtual bool setIV( uint64_t iv );
virtual void setFileName(const char *fileName);
virtual const char *getFileName() const;
virtual bool setIV(uint64_t iv);
virtual int open( int flags );
virtual int open(int flags);
virtual int getAttr( struct stat *stbuf ) const;
virtual off_t getSize() const;
virtual int getAttr(struct stat *stbuf) const;
virtual off_t getSize() const;
virtual int truncate( off_t size );
virtual int truncate(off_t size);
virtual bool isWritable() const;
virtual bool isWritable() const;
private:
virtual ssize_t readOneBlock( const IORequest &req ) const;
virtual bool writeOneBlock( const IORequest &req );
private:
virtual ssize_t readOneBlock(const IORequest &req) const;
virtual bool writeOneBlock(const IORequest &req);
void initHeader();
bool writeHeader();
bool blockRead( unsigned char *buf, int size,
uint64_t iv64 ) const;
bool streamRead( unsigned char *buf, int size,
uint64_t iv64 ) const;
bool blockWrite( unsigned char *buf, int size,
uint64_t iv64 ) const;
bool streamWrite( unsigned char *buf, int size,
uint64_t iv64 ) const;
void initHeader();
bool writeHeader();
bool blockRead(unsigned char *buf, int size, uint64_t iv64) const;
bool streamRead(unsigned char *buf, int size, uint64_t iv64) const;
bool blockWrite(unsigned char *buf, int size, uint64_t iv64) const;
bool streamWrite(unsigned char *buf, int size, uint64_t iv64) const;
shared_ptr<FileIO> base;
shared_ptr<FileIO> base;
FSConfigPtr fsConfig;
FSConfigPtr fsConfig;
// if haveHeader is true, then we have a transparent file header which
// contains a 64 bit initialization vector.
bool haveHeader;
uint64_t externalIV;
uint64_t fileIV;
int lastFlags;
// if haveHeader is true, then we have a transparent file header which
// contains a 64 bit initialization vector.
bool haveHeader;
uint64_t externalIV;
uint64_t fileIV;
int lastFlags;
shared_ptr<Cipher> cipher;
CipherKey key;
shared_ptr<Cipher> cipher;
CipherKey key;
};
#endif

View File

@ -20,11 +20,6 @@
#include "CipherKey.h"
AbstractCipherKey::AbstractCipherKey()
{
}
AbstractCipherKey::~AbstractCipherKey()
{
}
AbstractCipherKey::AbstractCipherKey() {}
AbstractCipherKey::~AbstractCipherKey() {}

View File

@ -23,14 +23,12 @@
#include "shared_ptr.h"
class AbstractCipherKey
{
public:
AbstractCipherKey();
virtual ~AbstractCipherKey();
class AbstractCipherKey {
public:
AbstractCipherKey();
virtual ~AbstractCipherKey();
};
typedef shared_ptr<AbstractCipherKey> CipherKey;
#endif

View File

@ -28,135 +28,109 @@
#include <unistd.h>
#include <cstring>
using namespace std;
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
// into mapped variables.
bool
ConfigReader::load(const char *fileName)
{
struct stat stbuf;
memset( &stbuf, 0, sizeof(struct stat));
if( lstat( fileName, &stbuf ) != 0)
return false;
bool ConfigReader::load(const char *fileName) {
struct stat stbuf;
memset(&stbuf, 0, sizeof(struct stat));
if (lstat(fileName, &stbuf) != 0) return false;
int size = stbuf.st_size;
int size = stbuf.st_size;
int fd = open( fileName, O_RDONLY );
if(fd < 0)
return false;
int fd = open(fileName, O_RDONLY);
if (fd < 0) return false;
char *buf = new char[size];
char *buf = new char[size];
int res = ::read( fd, buf, size );
close( fd );
int res = ::read(fd, buf, size);
close(fd);
if( res != size )
{
rWarning("Partial read of config file, expecting %i bytes, got %i",
size, res);
delete[] buf;
return false;
}
ConfigVar in;
in.write( (unsigned char *)buf, size );
if (res != size) {
rWarning("Partial read of config file, expecting %i bytes, got %i", size,
res);
delete[] buf;
return false;
}
return loadFromVar( in );
ConfigVar in;
in.write((unsigned char *)buf, size);
delete[] buf;
return loadFromVar(in);
}
bool
ConfigReader::loadFromVar(ConfigVar &in)
{
in.resetOffset();
bool ConfigReader::loadFromVar(ConfigVar &in) {
in.resetOffset();
// parse.
int numEntries = in.readInt();
// parse.
int numEntries = in.readInt();
for(int i=0; i<numEntries; ++i)
{
string key, value;
in >> key >> value;
for (int i = 0; i < numEntries; ++i) {
string key, value;
in >> key >> value;
if(key.length() == 0)
{
rError("Invalid key encoding in buffer");
return false;
}
ConfigVar newVar( value );
vars.insert( make_pair( key, newVar ) );
if (key.length() == 0) {
rError("Invalid key encoding in buffer");
return false;
}
ConfigVar newVar(value);
vars.insert(make_pair(key, newVar));
}
return true;
return true;
}
bool
ConfigReader::save(const char *fileName) const
{
// write everything to a ConfigVar, then output to disk
ConfigVar out = toVar();
bool ConfigReader::save(const char *fileName) const {
// write everything to a ConfigVar, then output to disk
ConfigVar out = toVar();
int fd = ::open( fileName, O_RDWR | O_CREAT, 0640 );
if(fd >= 0)
{
int retVal = ::write( fd, out.buffer(), out.size() );
close( fd );
if(retVal != out.size())
{
rError("Error writing to config file %s", fileName);
return false;
}
} else
{
rError("Unable to open or create file %s", fileName);
return false;
int fd = ::open(fileName, O_RDWR | O_CREAT, 0640);
if (fd >= 0) {
int retVal = ::write(fd, out.buffer(), out.size());
close(fd);
if (retVal != out.size()) {
rError("Error writing to config file %s", fileName);
return false;
}
} else {
rError("Unable to open or create file %s", fileName);
return false;
}
return true;
return true;
}
ConfigVar
ConfigReader::toVar() const
{
// write everything to a ConfigVar, then output to disk
ConfigVar out;
out.writeInt( vars.size() );
map<string, ConfigVar>::const_iterator it;
for(it = vars.begin(); it != vars.end(); ++it)
{
out.writeInt( it->first.size() );
out.write( (unsigned char*)it->first.data(), it->first.size() );
out.writeInt( it->second.size() );
out.write( (unsigned char*)it->second.buffer(), it->second.size() );
}
ConfigVar ConfigReader::toVar() const {
// write everything to a ConfigVar, then output to disk
ConfigVar out;
out.writeInt(vars.size());
map<string, ConfigVar>::const_iterator it;
for (it = vars.begin(); it != vars.end(); ++it) {
out.writeInt(it->first.size());
out.write((unsigned char *)it->first.data(), it->first.size());
out.writeInt(it->second.size());
out.write((unsigned char *)it->second.buffer(), it->second.size());
}
return out;
return out;
}
ConfigVar ConfigReader::operator[] ( const std::string &varName ) const
{
// read only
map<string, ConfigVar>::const_iterator it = vars.find( varName );
if( it == vars.end() )
return ConfigVar();
else
return it->second;
ConfigVar ConfigReader::operator[](const std::string &varName) const {
// read only
map<string, ConfigVar>::const_iterator it = vars.find(varName);
if (it == vars.end())
return ConfigVar();
else
return it->second;
}
ConfigVar &ConfigReader::operator[] ( const std::string &varName )
{
return vars[ varName ];
ConfigVar &ConfigReader::operator[](const std::string &varName) {
return vars[varName];
}

View File

@ -43,24 +43,22 @@
ConfigReader cfg;
cfg["cipher"] << cipher->interface();
*/
class ConfigReader
{
public:
ConfigReader();
~ConfigReader();
class ConfigReader {
public:
ConfigReader();
~ConfigReader();
bool load(const char *fileName);
bool save(const char *fileName) const;
bool load(const char *fileName);
bool save(const char *fileName) const;
ConfigVar toVar() const;
bool loadFromVar( ConfigVar &var );
ConfigVar toVar() const;
bool loadFromVar(ConfigVar &var);
ConfigVar operator[](const std::string &varName) const;
ConfigVar &operator[](const std::string &varName);
ConfigVar operator[](const std::string &varName) const;
ConfigVar &operator[](const std::string &varName);
private:
std::map<std::string, ConfigVar> vars;
private:
std::map<std::string, ConfigVar> vars;
};
#endif

View File

@ -26,227 +26,175 @@
using namespace rlog;
#ifndef MIN
inline int MIN(int a, int b)
{
return (a < b) ? a : b;
}
inline int MIN(int a, int b) { return (a < b) ? a : b; }
#endif
ConfigVar::ConfigVar() : pd(new ConfigVarData) { pd->offset = 0; }
ConfigVar::ConfigVar()
: pd( new ConfigVarData )
{
pd->offset = 0;
ConfigVar::ConfigVar(const std::string &buf) : pd(new ConfigVarData) {
pd->buffer = buf;
pd->offset = 0;
}
ConfigVar::ConfigVar(const std::string &buf)
: pd( new ConfigVarData )
{
pd->buffer = buf;
pd->offset = 0;
}
ConfigVar::ConfigVar(const ConfigVar &src) { pd = src.pd; }
ConfigVar::ConfigVar(const ConfigVar &src)
{
pd = src.pd;
}
ConfigVar::~ConfigVar()
{
pd.reset();
}
ConfigVar & ConfigVar::operator = (const ConfigVar &src)
{
if(src.pd == pd)
return *this;
else
pd = src.pd;
ConfigVar::~ConfigVar() { pd.reset(); }
ConfigVar &ConfigVar::operator=(const ConfigVar &src) {
if (src.pd == pd)
return *this;
else
pd = src.pd;
return *this;
}
void ConfigVar::resetOffset()
{
pd->offset = 0;
void ConfigVar::resetOffset() { pd->offset = 0; }
int ConfigVar::read(unsigned char *buffer_, int bytes) const {
int toCopy = MIN(bytes, pd->buffer.size() - pd->offset);
if (toCopy > 0) memcpy(buffer_, pd->buffer.data() + pd->offset, toCopy);
pd->offset += toCopy;
return toCopy;
}
int ConfigVar::read(unsigned char *buffer_, int bytes) const
{
int toCopy = MIN( bytes, pd->buffer.size() - pd->offset );
int ConfigVar::write(const unsigned char *data, int bytes) {
if (pd->buffer.size() == (unsigned int)pd->offset) {
pd->buffer.append((const char *)data, bytes);
} else {
pd->buffer.insert(pd->offset, (const char *)data, bytes);
}
if(toCopy > 0)
memcpy( buffer_, pd->buffer.data() + pd->offset, toCopy );
pd->offset += bytes;
pd->offset += toCopy;
return toCopy;
return bytes;
}
int ConfigVar::write(const unsigned char *data, int bytes)
{
if(pd->buffer.size() == (unsigned int)pd->offset)
{
pd->buffer.append( (const char *)data, bytes );
} else
{
pd->buffer.insert( pd->offset, (const char *)data, bytes );
}
int ConfigVar::size() const { return pd->buffer.size(); }
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
void ConfigVar::writeInt(int val)
{
// we can represent 7 bits per char output, so a 32bit number may take up
// to 5 bytes.
// first byte: 0x0000007f 0111,1111
// second byte: 0x00003f80 0011,1111 1000,0000
// third byte: 0x001fb000 0000,0000 0001,1111 1100,0000 0000,0000
// fourth byte: 0x0fe00000 0000,1111 1110,0000
// fifth byte: 0xf0000000 1111,0000
unsigned char digit[5];
void ConfigVar::writeInt(int val) {
// we can represent 7 bits per char output, so a 32bit number may take up
// to 5 bytes.
// first byte: 0x0000007f 0111,1111
// second byte: 0x00003f80 0011,1111 1000,0000
// third byte: 0x001fb000 0000,0000 0001,1111 1100,0000 0000,0000
// fourth byte: 0x0fe00000 0000,1111 1110,0000
// fifth byte: 0xf0000000 1111,0000
unsigned char digit[5];
digit[4] = (unsigned char)((val & 0x0000007f));
digit[3] = 0x80 | (unsigned char)((val & 0x00003f80) >> 7);
digit[2] = 0x80 | (unsigned char)((val & 0x001fc000) >> 14);
digit[1] = 0x80 | (unsigned char)((val & 0x0fe00000) >> 21);
digit[0] = 0x80 | (unsigned char)((val & 0xf0000000) >> 28);
digit[4] = (unsigned char)((val & 0x0000007f));
digit[3] = 0x80 | (unsigned char)((val & 0x00003f80) >> 7);
digit[2] = 0x80 | (unsigned char)((val & 0x001fc000) >> 14);
digit[1] = 0x80 | (unsigned char)((val & 0x0fe00000) >> 21);
digit[0] = 0x80 | (unsigned char)((val & 0xf0000000) >> 28);
// find the starting point - we only need to output starting at the most
// significant non-zero digit..
int start = 0;
while(digit[start] == 0x80)
++start;
// find the starting point - we only need to output starting at the most
// significant non-zero digit..
int start = 0;
while (digit[start] == 0x80) ++start;
write( digit + start, 5-start );
write(digit + start, 5 - start);
}
int ConfigVar::readInt() const
{
const unsigned char * buf = (const unsigned char *)buffer();
int bytes = this->size();
int offset = at();
int value = 0;
bool highBitSet;
int ConfigVar::readInt() const {
const unsigned char *buf = (const unsigned char *)buffer();
int bytes = this->size();
int offset = at();
int value = 0;
bool highBitSet;
rAssert( offset < bytes );
rAssert(offset < bytes);
do
{
unsigned char tmp = buf[offset++];
highBitSet = tmp & 0x80;
do {
unsigned char tmp = buf[offset++];
highBitSet = tmp & 0x80;
value = (value << 7) | (int)(tmp & 0x7f);
} while(highBitSet && offset < bytes);
value = (value << 7) | (int)(tmp & 0x7f);
} while (highBitSet && offset < bytes);
pd->offset = offset;
pd->offset = offset;
// should never end up with a negative number..
rAssert( value >= 0 );
// should never end up with a negative number..
rAssert(value >= 0);
return value;
return value;
}
int ConfigVar::readInt( int defaultValue ) const
{
int bytes = this->size();
int offset = at();
int ConfigVar::readInt(int defaultValue) const {
int bytes = this->size();
int offset = at();
if(offset >= bytes)
return defaultValue;
else
return readInt();
if (offset >= bytes)
return defaultValue;
else
return readInt();
}
bool ConfigVar::readBool( bool defaultValue ) const
{
int tmp = readInt( defaultValue ? 1 : 0 );
return (tmp != 0);
bool ConfigVar::readBool(bool defaultValue) const {
int tmp = readInt(defaultValue ? 1 : 0);
return (tmp != 0);
}
ConfigVar & operator << (ConfigVar &src, bool value)
{
src.writeInt( value ? 1 : 0 );
return src;
ConfigVar &operator<<(ConfigVar &src, bool value) {
src.writeInt(value ? 1 : 0);
return src;
}
ConfigVar & operator << (ConfigVar &src, int var)
{
src.writeInt( var );
return src;
ConfigVar &operator<<(ConfigVar &src, int var) {
src.writeInt(var);
return src;
}
ConfigVar & operator << (ConfigVar &src, const std::string &str)
{
src.writeString( str.data(), str.length() );
return src;
ConfigVar &operator<<(ConfigVar &src, const std::string &str) {
src.writeString(str.data(), str.length());
return src;
}
const ConfigVar & operator >> (const ConfigVar &src, bool &result)
{
int tmp = src.readInt();
result = (tmp != 0);
return src;
const ConfigVar &operator>>(const ConfigVar &src, bool &result) {
int tmp = src.readInt();
result = (tmp != 0);
return src;
}
const ConfigVar & operator >> (const ConfigVar &src, int &result)
{
result = src.readInt();
return src;
const ConfigVar &operator>>(const ConfigVar &src, int &result) {
result = src.readInt();
return src;
}
const ConfigVar & operator >> (const ConfigVar &src, std::string &result)
{
int length = src.readInt();
//rAssert(length > 0);
const ConfigVar &operator>>(const ConfigVar &src, std::string &result) {
int length = src.readInt();
// rAssert(length > 0);
int readLen;
int readLen;
unsigned char tmpBuf[32];
if(length > (int)sizeof(tmpBuf))
{
unsigned char *ptr = new unsigned char[length];
readLen = src.read( ptr, length );
result.assign( (char*)ptr, length );
delete[] ptr;
} else
{
readLen = src.read( tmpBuf, length );
result.assign( (char*)tmpBuf, length );
}
unsigned char tmpBuf[32];
if (length > (int)sizeof(tmpBuf)) {
unsigned char *ptr = new unsigned char[length];
readLen = src.read(ptr, length);
result.assign((char *)ptr, length);
delete[] ptr;
} else {
readLen = src.read(tmpBuf, length);
result.assign((char *)tmpBuf, length);
}
if(readLen != length)
{
rDebug("string encoded as size %i bytes, read %i", length, readLen );
}
rAssert(readLen == length);
if (readLen != length) {
rDebug("string encoded as size %i bytes, read %i", length, readLen);
}
rAssert(readLen == length);
return src;
return src;
}

View File

@ -24,58 +24,55 @@
#include <string>
#include "shared_ptr.h"
class ConfigVar
{
struct ConfigVarData
{
std::string buffer;
int offset;
};
class ConfigVar {
struct ConfigVarData {
std::string buffer;
int offset;
};
shared_ptr<ConfigVarData> pd;
shared_ptr<ConfigVarData> pd;
public:
ConfigVar();
ConfigVar(const std::string &buffer);
ConfigVar(const ConfigVar &src);
~ConfigVar();
public:
ConfigVar();
ConfigVar(const std::string &buffer);
ConfigVar(const ConfigVar &src);
~ConfigVar();
ConfigVar & operator = (const ConfigVar &src);
ConfigVar &operator=(const ConfigVar &src);
// reset read/write offset..
void resetOffset();
// reset read/write offset..
void resetOffset();
// read bytes
int read(unsigned char *buffer, int size) const;
// read bytes
int read(unsigned char *buffer, int size) const;
// write bytes..
int write(const unsigned char *data, int size);
// write bytes..
int write(const unsigned char *data, int size);
int readInt() const;
int readInt( int defaultValue ) const;
void writeInt(int value);
int readInt() const;
int readInt(int defaultValue) const;
void writeInt(int value);
bool readBool( bool defaultValue ) const;
bool readBool(bool defaultValue) const;
void writeString(const char *data, int size);
void writeString(const char *data, int size);
// return amount of data in var
int size() const;
// return data pointer - returns front of data pointer, not the current
// position.
const char *buffer() const;
// return amount of data in var
int size() const;
// return data pointer - returns front of data pointer, not the current
// position.
const char *buffer() const;
// return current position in data() buffer.
int at() const;
// return current position in data() buffer.
int at() const;
};
ConfigVar & operator << (ConfigVar &, bool);
ConfigVar & operator << (ConfigVar &, int);
ConfigVar & operator << (ConfigVar &, const std::string &str);
ConfigVar &operator<<(ConfigVar &, bool);
ConfigVar &operator<<(ConfigVar &, int);
ConfigVar &operator<<(ConfigVar &, const std::string &str);
const ConfigVar & operator >> (const ConfigVar &, bool &);
const ConfigVar & operator >> (const ConfigVar &, int &);
const ConfigVar & operator >> (const ConfigVar &, std::string &str);
const ConfigVar &operator>>(const ConfigVar &, bool &);
const ConfigVar &operator>>(const ConfigVar &, int &);
const ConfigVar &operator>>(const ConfigVar &, std::string &str);
#endif

View File

@ -29,149 +29,126 @@
using namespace rel;
using namespace rlog;
EncFS_Context::EncFS_Context()
{
pthread_cond_init( &wakeupCond, 0 );
pthread_mutex_init( &wakeupMutex, 0 );
pthread_mutex_init( &contextMutex, 0 );
EncFS_Context::EncFS_Context() {
pthread_cond_init(&wakeupCond, 0);
pthread_mutex_init(&wakeupMutex, 0);
pthread_mutex_init(&contextMutex, 0);
usageCount = 0;
usageCount = 0;
}
EncFS_Context::~EncFS_Context()
{
pthread_mutex_destroy( &contextMutex );
pthread_mutex_destroy( &wakeupMutex );
pthread_cond_destroy( &wakeupCond );
EncFS_Context::~EncFS_Context() {
pthread_mutex_destroy(&contextMutex);
pthread_mutex_destroy(&wakeupMutex);
pthread_cond_destroy(&wakeupCond);
// release all entries from map
openFiles.clear();
// release all entries from map
openFiles.clear();
}
shared_ptr<DirNode> EncFS_Context::getRoot(int *errCode)
{
shared_ptr<DirNode> ret;
do
shared_ptr<DirNode> EncFS_Context::getRoot(int *errCode) {
shared_ptr<DirNode> ret;
do {
{
{
Lock lock( contextMutex );
ret = root;
++usageCount;
}
if(!ret)
{
int res = remountFS( this );
if(res != 0)
{
*errCode = res;
break;
}
}
} while(!ret);
return ret;
}
void EncFS_Context::setRoot(const shared_ptr<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>();
Lock lock(contextMutex);
ret = root;
++usageCount;
}
}
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;
if (!ret) {
int res = remountFS(this);
if (res != 0) {
*errCode = res;
break;
}
}
} while (!ret);
return ret;
}
shared_ptr<FileNode> EncFS_Context::getNode(void *pl)
{
Placeholder *ph = (Placeholder*)pl;
return ph->node;
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);
const shared_ptr<FileNode> &node) {
Lock lock(contextMutex);
Placeholder *pl = new Placeholder(node);
openFiles[std::string(path)].insert(pl);
return (void *)pl;
return (void *)pl;
}
void EncFS_Context::eraseNode(const char *path, void *pl)
{
Lock lock( contextMutex );
void EncFS_Context::eraseNode(const char *path, void *pl) {
Lock lock(contextMutex);
Placeholder *ph = (Placeholder *)pl;
Placeholder *ph = (Placeholder *)pl;
FileMap::iterator it = openFiles.find( std::string(path) );
rAssert(it != openFiles.end());
FileMap::iterator it = openFiles.find(std::string(path));
rAssert(it != openFiles.end());
int rmCount = it->second.erase( ph );
int rmCount = it->second.erase(ph);
rAssert(rmCount == 1);
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' );
}
// 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;
delete ph;
}

View File

@ -37,75 +37,70 @@ struct EncFS_Opts;
class FileNode;
class DirNode;
class EncFS_Context
{
public:
EncFS_Context();
~EncFS_Context();
class EncFS_Context {
public:
EncFS_Context();
~EncFS_Context();
shared_ptr<FileNode> getNode(void *ptr);
shared_ptr<FileNode> lookupNode(const char *path);
shared_ptr<FileNode> getNode(void *ptr);
shared_ptr<FileNode> lookupNode(const char *path);
int getAndResetUsageCounter();
int openFileCount() const;
int getAndResetUsageCounter();
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);
shared_ptr<DirNode> getRoot(int *err);
bool isMounted();
void setRoot(const shared_ptr<DirNode> &root);
shared_ptr<DirNode> getRoot(int *err);
bool isMounted();
shared_ptr<EncFS_Args> args;
shared_ptr<EncFS_Opts> opts;
bool publicFilesystem;
shared_ptr<EncFS_Args> args;
shared_ptr<EncFS_Opts> opts;
bool publicFilesystem;
// root path to cipher dir
std::string rootCipherDir;
// root path to cipher dir
std::string rootCipherDir;
// for idle monitor
bool running;
pthread_t monitorThread;
pthread_cond_t wakeupCond;
pthread_mutex_t wakeupMutex;
// for idle monitor
bool running;
pthread_t monitorThread;
pthread_cond_t wakeupCond;
pthread_mutex_t wakeupMutex;
private:
/* This placeholder is what is referenced in FUSE context (passed to
* callbacks).
*
* A FileNode may be opened many times, but only one FileNode instance per
* file is kept. Rather then doing reference counting in FileNode, we
* store a unique Placeholder for each open() until the corresponding
* release() is called. shared_ptr then does our reference counting for
* us.
*/
struct Placeholder
{
shared_ptr<FileNode> node;
private:
/* This placeholder is what is referenced in FUSE context (passed to
* callbacks).
*
* A FileNode may be opened many times, but only one FileNode instance per
* file is kept. Rather then doing reference counting in FileNode, we
* store a unique Placeholder for each open() until the corresponding
* release() is called. shared_ptr then does our reference counting for
* us.
*/
struct Placeholder {
shared_ptr<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
typedef __gnu_cxx::hash_map<std::string,
std::set<Placeholder*> > FileMap;
// set of open files, indexed by path
typedef __gnu_cxx::hash_map<std::string, std::set<Placeholder *> > FileMap;
#else
typedef std::map< std::string,
std::set<Placeholder*> > FileMap;
typedef std::map<std::string, std::set<Placeholder *> > FileMap;
#endif
mutable pthread_mutex_t contextMutex;
FileMap openFiles;
mutable pthread_mutex_t contextMutex;
FileMap openFiles;
int usageCount;
shared_ptr<DirNode> root;
int usageCount;
shared_ptr<DirNode> root;
};
int remountFS( EncFS_Context *ctx );
int remountFS(EncFS_Context *ctx);
#endif

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -28,105 +28,98 @@
#include "CipherKey.h"
#include "shared_ptr.h"
enum ConfigType
{
Config_None = 0,
Config_Prehistoric,
Config_V3,
Config_V4,
Config_V5,
Config_V6
enum ConfigType {
Config_None = 0,
Config_Prehistoric,
Config_V3,
Config_V4,
Config_V5,
Config_V6
};
struct EncFS_Opts;
class Cipher;
class NameIO;
struct EncFSConfig
{
ConfigType cfgType;
struct EncFSConfig {
ConfigType cfgType;
std::string creator;
int subVersion;
std::string creator;
int subVersion;
// interface of cipher
rel::Interface cipherIface;
// interface used for file name coding
rel::Interface nameIface;
int keySize; // reported in bits
int blockSize; // reported in bytes
// interface of cipher
rel::Interface cipherIface;
// interface used for file name coding
rel::Interface nameIface;
int keySize; // reported in bits
int blockSize; // reported in bytes
std::vector<unsigned char> keyData;
std::vector<unsigned char> keyData;
std::vector<unsigned char> salt;
int kdfIterations;
long desiredKDFDuration;
std::vector<unsigned char> salt;
int kdfIterations;
long desiredKDFDuration;
int blockMACBytes; // MAC headers on blocks..
int blockMACRandBytes; // number of random bytes in the block header
int blockMACBytes; // MAC headers on blocks..
int blockMACRandBytes; // number of random bytes in the block header
bool uniqueIV; // per-file Initialization Vector
bool externalIVChaining; // IV seeding by filename IV chaining
bool uniqueIV; // per-file Initialization Vector
bool externalIVChaining; // IV seeding by filename IV chaining
bool chainedNameIV; // filename IV chaining
bool allowHoles; // allow holes in files (implicit zero blocks)
bool chainedNameIV; // filename IV chaining
bool allowHoles; // allow holes in files (implicit zero blocks)
EncFSConfig()
: keyData()
, salt()
{
cfgType = Config_None;
subVersion = 0;
blockMACBytes = 0;
blockMACRandBytes = 0;
uniqueIV = false;
externalIVChaining = false;
chainedNameIV = false;
allowHoles = false;
EncFSConfig() : keyData(), salt() {
cfgType = Config_None;
subVersion = 0;
blockMACBytes = 0;
blockMACRandBytes = 0;
uniqueIV = false;
externalIVChaining = false;
chainedNameIV = false;
allowHoles = false;
kdfIterations = 0;
desiredKDFDuration = 500;
}
kdfIterations = 0;
desiredKDFDuration = 500;
}
CipherKey getUserKey(bool useStdin);
CipherKey getUserKey(const std::string &passwordProgram,
const std::string &rootDir);
CipherKey getNewUserKey();
CipherKey getUserKey(bool useStdin);
CipherKey getUserKey(const std::string &passwordProgram,
const std::string &rootDir);
CipherKey getNewUserKey();
shared_ptr<Cipher> getCipher() const;
shared_ptr<Cipher> getCipher() const;
// deprecated
void assignKeyData(const std::string &in);
void assignKeyData(unsigned char *data, int length);
void assignSaltData(unsigned char *data, int length);
// deprecated
void assignKeyData(const std::string &in);
void assignKeyData(unsigned char *data, int length);
void assignSaltData(unsigned char *data, int length);
unsigned char *getKeyData() const;
unsigned char *getSaltData() const;
unsigned char *getKeyData() const;
unsigned char *getSaltData() const;
private:
CipherKey makeKey(const char *password, int passwdLen);
private:
CipherKey makeKey(const char *password, int passwdLen);
};
// helpers for serializing to/from a stream
std::ostream &operator << (std::ostream &os, const EncFSConfig &cfg);
std::istream &operator >> (std::istream &os, EncFSConfig &cfg);
std::ostream &operator<<(std::ostream &os, const EncFSConfig &cfg);
std::istream &operator>>(std::istream &os, EncFSConfig &cfg);
struct FSConfig
{
shared_ptr<EncFSConfig> config;
shared_ptr<EncFS_Opts> opts;
struct FSConfig {
shared_ptr<EncFSConfig> config;
shared_ptr<EncFS_Opts> opts;
shared_ptr<Cipher> cipher;
CipherKey key;
shared_ptr<NameIO> nameCoding;
shared_ptr<Cipher> cipher;
CipherKey key;
shared_ptr<NameIO> nameCoding;
bool forceDecode; // force decode on MAC block failures
bool reverseEncryption; // reverse encryption operation
bool forceDecode; // force decode on MAC block failures
bool reverseEncryption; // reverse encryption operation
bool idleTracking; // turn on idle monitoring of filesystem
bool idleTracking; // turn on idle monitoring of filesystem
};
typedef shared_ptr<FSConfig> FSConfigPtr;
#endif

View File

@ -20,22 +20,13 @@
#include "FileIO.h"
FileIO::FileIO()
{
}
FileIO::FileIO() {}
FileIO::~FileIO()
{
}
FileIO::~FileIO() {}
int FileIO::blockSize() const
{
return 1;
}
int FileIO::blockSize() const { return 1; }
bool FileIO::setIV( uint64_t iv )
{
(void)iv;
return true;
bool FileIO::setIV(uint64_t iv) {
(void)iv;
return true;
}

View File

@ -27,61 +27,54 @@
#include "Interface.h"
struct IORequest
{
off_t offset;
struct IORequest {
off_t offset;
// amount of bytes to read/write.
int dataLen;
unsigned char *data;
// amount of bytes to read/write.
int dataLen;
unsigned char *data;
IORequest();
IORequest();
};
inline IORequest::IORequest()
: offset(0)
, dataLen(0)
, data(0)
{
}
inline IORequest::IORequest() : offset(0), dataLen(0), data(0) {}
class FileIO
{
public:
FileIO();
virtual ~FileIO();
class FileIO {
public:
FileIO();
virtual ~FileIO();
virtual rel::Interface interface() const =0;
virtual rel::Interface interface() const = 0;
// default implementation returns 1, meaning this is not block oriented.
virtual int blockSize() const;
// default implementation returns 1, meaning this is not block oriented.
virtual int blockSize() const;
virtual void setFileName(const char *fileName) =0;
virtual const char *getFileName() const =0;
virtual void setFileName(const char *fileName) = 0;
virtual const char *getFileName() const = 0;
// Not sure about this -- it is specific to CipherFileIO, but the
// alternative methods of exposing this interface aren't much nicer..
virtual bool setIV( uint64_t iv );
// Not sure about this -- it is specific to CipherFileIO, but the
// alternative methods of exposing this interface aren't much nicer..
virtual bool setIV(uint64_t iv);
// open file for specified mode. There is no corresponding close, so a
// file is open until the FileIO interface is destroyed.
virtual int open( int flags ) =0;
// open file for specified mode. There is no corresponding close, so a
// file is open until the FileIO interface is destroyed.
virtual int open(int flags) = 0;
// get filesystem attributes for a file
virtual int getAttr( struct stat *stbuf ) const =0;
virtual off_t getSize( ) const =0;
// 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;
virtual bool write( const IORequest &req ) =0;
virtual ssize_t read(const IORequest &req) const = 0;
virtual bool write(const IORequest &req) = 0;
virtual int truncate( off_t size ) =0;
virtual int truncate(off_t size) = 0;
virtual bool isWritable() const =0;
private:
// not implemented..
FileIO( const FileIO & );
FileIO &operator = ( const FileIO & );
virtual bool isWritable() const = 0;
private:
// not implemented..
FileIO(const FileIO &);
FileIO &operator=(const FileIO &);
};
#endif

View File

@ -66,242 +66,202 @@ using namespace rlog;
static RLogChannel *Info = DEF_CHANNEL("info/FileNode", Log_Info);
FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg,
const char *plaintextName_, const char *cipherName_)
{
pthread_mutex_init( &mutex, 0 );
const char *plaintextName_, const char *cipherName_) {
pthread_mutex_init(&mutex, 0);
Lock _lock( mutex );
Lock _lock(mutex);
this->_pname = plaintextName_;
this->_cname = cipherName_;
this->parent = parent_;
this->_pname = plaintextName_;
this->_cname = cipherName_;
this->parent = parent_;
this->fsConfig = cfg;
this->fsConfig = cfg;
// chain RawFileIO & CipherFileIO
shared_ptr<FileIO> rawIO( new RawFileIO( _cname ) );
io = shared_ptr<FileIO>( new CipherFileIO( rawIO, fsConfig ));
// chain RawFileIO & CipherFileIO
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));
if (cfg->config->blockMACBytes || cfg->config->blockMACRandBytes)
io = shared_ptr<FileIO>(new MACFileIO(io, fsConfig));
}
FileNode::~FileNode()
{
// FileNode mutex should be locked before the destructor is called
//pthread_mutex_lock( &mutex );
FileNode::~FileNode() {
// FileNode mutex should be locked before the destructor is called
// pthread_mutex_lock( &mutex );
_pname.assign( _pname.length(), '\0' );
_cname.assign( _cname.length(), '\0' );
io.reset();
_pname.assign(_pname.length(), '\0');
_cname.assign(_cname.length(), '\0');
io.reset();
pthread_mutex_destroy( &mutex );
pthread_mutex_destroy(&mutex);
}
const char *FileNode::cipherName() const
{
return _cname.c_str();
}
const char *FileNode::cipherName() const { return _cname.c_str(); }
const char *FileNode::plaintextName() const
{
return _pname.c_str();
}
const char *FileNode::plaintextName() const { return _pname.c_str(); }
string FileNode::plaintextParent() const
{
return parentDirectory( _pname );
}
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;
}
}
string FileNode::plaintextParent() const { 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;
}
int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid)
{
Lock _lock( mutex );
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;
int res;
int olduid = -1;
int oldgid = -1;
if(uid != 0)
{
olduid = setfsuid( uid );
if(olduid == -1)
{
rInfo("setfsuid error: %s", strerror(errno));
return -EPERM;
}
// now change the name..
if (plaintextName_) this->_pname = plaintextName_;
if (cipherName_) {
this->_cname = cipherName_;
io->setFileName(cipherName_);
}
if(gid != 0)
{
oldgid = setfsgid( gid );
if(oldgid == -1)
{
rInfo("setfsgid error: %s", strerror(errno));
return -EPERM;
}
} else {
std::string oldPName = _pname;
std::string oldCName = _cname;
if (plaintextName_) this->_pname = plaintextName_;
if (cipherName_) {
this->_cname = cipherName_;
io->setFileName(cipherName_);
}
/*
* 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;
if (fsConfig->config->externalIVChaining && !setIV(io, iv)) {
_pname = oldPName;
_cname = oldCName;
return false;
}
}
return res;
return true;
}
int FileNode::open(int flags) const
{
Lock _lock( mutex );
int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid) {
Lock _lock(mutex);
int res = io->open( flags );
return res;
int res;
int olduid = -1;
int oldgid = -1;
if (uid != 0) {
olduid = setfsuid(uid);
if (olduid == -1) {
rInfo("setfsuid error: %s", strerror(errno));
return -EPERM;
}
}
if (gid != 0) {
oldgid = setfsgid(gid);
if (oldgid == -1) {
rInfo("setfsgid error: %s", strerror(errno));
return -EPERM;
}
}
/*
* cf. xmp_mknod() in fusexmp.c
* The regular file stuff could be stripped off if there
* were a create method (advised to have)
*/
if (S_ISREG(mode)) {
res = ::open(_cname.c_str(), O_CREAT | O_EXCL | O_WRONLY, mode);
if (res >= 0) res = ::close(res);
} else if (S_ISFIFO(mode))
res = ::mkfifo(_cname.c_str(), mode);
else
res = ::mknod(_cname.c_str(), mode, rdev);
if (olduid >= 0) setfsuid(olduid);
if (oldgid >= 0) setfsgid(oldgid);
if (res == -1) {
int eno = errno;
rDebug("mknod error: %s", strerror(eno));
res = -eno;
}
return res;
}
int FileNode::getAttr(struct stat *stbuf) const
{
Lock _lock( mutex );
int FileNode::open(int flags) const {
Lock _lock(mutex);
int res = io->getAttr( stbuf );
return res;
int res = io->open(flags);
return res;
}
off_t FileNode::getSize() const
{
Lock _lock( mutex );
int FileNode::getAttr(struct stat *stbuf) const {
Lock _lock(mutex);
int res = io->getSize();
return res;
int res = io->getAttr(stbuf);
return res;
}
ssize_t FileNode::read( off_t offset, unsigned char *data, ssize_t size ) const
{
IORequest req;
req.offset = offset;
req.dataLen = size;
req.data = data;
off_t FileNode::getSize() const {
Lock _lock(mutex);
Lock _lock( mutex );
return io->read( req );
int res = io->getSize();
return res;
}
bool FileNode::write(off_t offset, unsigned char *data, ssize_t size)
{
rLog(Info, "FileNode::write offset %" PRIi64 ", data size %i",
offset, (int)size);
ssize_t FileNode::read(off_t offset, unsigned char *data, ssize_t size) const {
IORequest req;
req.offset = offset;
req.dataLen = size;
req.data = data;
IORequest req;
req.offset = offset;
req.dataLen = size;
req.data = data;
Lock _lock(mutex);
Lock _lock( mutex );
return io->write( req );
return io->read(req);
}
int FileNode::truncate( off_t size )
{
Lock _lock( mutex );
bool FileNode::write(off_t offset, unsigned char *data, ssize_t size) {
rLog(Info, "FileNode::write offset %" PRIi64 ", data size %i", offset,
(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)
{
Lock _lock( mutex );
int FileNode::truncate(off_t size) {
Lock _lock(mutex);
int fh = io->open( O_RDONLY );
if(fh >= 0)
{
int res = -EIO;
return io->truncate(size);
}
int FileNode::sync(bool datasync) {
Lock _lock(mutex);
int fh = io->open(O_RDONLY);
if (fh >= 0) {
int res = -EIO;
#ifdef linux
if(datasync)
res = fdatasync( fh );
else
res = fsync( fh );
if (datasync)
res = fdatasync(fh);
else
res = fsync(fh);
#else
(void)datasync;
// no fdatasync support
// TODO: use autoconfig to check for it..
res = fsync(fh);
(void)datasync;
// no fdatasync support
// TODO: use autoconfig to check for it..
res = fsync(fh);
#endif
if(res == -1)
res = -errno;
if (res == -1) res = -errno;
return res;
} else
return fh;
return res;
} else
return fh;
}

View File

@ -33,68 +33,62 @@ class Cipher;
class FileIO;
class DirNode;
class FileNode
{
public:
FileNode(DirNode *parent,
const FSConfigPtr &cfg,
const char *plaintextName,
const char *cipherName);
~FileNode();
class FileNode {
public:
FileNode(DirNode *parent, const FSConfigPtr &cfg, const char *plaintextName,
const char *cipherName);
~FileNode();
const char *plaintextName() const;
const char *cipherName() const;
const char *plaintextName() const;
const char *cipherName() const;
// directory portion of plaintextName
std::string plaintextParent() const;
// directory portion of plaintextName
std::string plaintextParent() const;
// if setIVFirst is true, then the IV is changed before the name is changed
// (default). The reverse is also supported for special cases..
bool setName( const char *plaintextName, const char *cipherName,
uint64_t iv, bool setIVFirst = true);
// if setIVFirst is true, then the IV is changed before the name is changed
// (default). The reverse is also supported for special cases..
bool setName(const char *plaintextName, const char *cipherName, uint64_t iv,
bool setIVFirst = true);
// create node
// If uid/gid are not 0, then chown is used change ownership as specified
int mknod(mode_t mode, dev_t rdev, uid_t uid = 0, gid_t gid = 0);
// create node
// If uid/gid are not 0, then chown is used change ownership as specified
int mknod(mode_t mode, dev_t rdev, uid_t uid = 0, gid_t gid = 0);
// Returns < 0 on error (-errno), file descriptor on success.
int open(int flags) const;
// Returns < 0 on error (-errno), file descriptor on success.
int open(int flags) const;
// getAttr returns 0 on success, -errno on failure
int getAttr(struct stat *stbuf) const;
off_t getSize() const;
// getAttr returns 0 on success, -errno on failure
int getAttr(struct stat *stbuf) const;
off_t getSize() const;
ssize_t read(off_t offset, unsigned char *data, ssize_t size) const;
bool write(off_t offset, unsigned char *data, ssize_t size);
ssize_t read(off_t offset, unsigned char *data, ssize_t size) const;
bool write(off_t offset, unsigned char *data, ssize_t size);
// truncate the file to a particular size
int truncate( off_t size );
// truncate the file to a particular size
int truncate(off_t size);
// datasync or full sync
int sync(bool dataSync);
private:
// datasync or full sync
int sync(bool dataSync);
// doing locking at the FileNode level isn't as efficient as at the
// lowest level of RawFileIO, since that means locks are held longer
// (held during CPU intensive crypto operations!). However it makes it
// easier to avoid any race conditions with operations such as
// truncate() which may result in multiple calls down to the FileIO
// level.
mutable pthread_mutex_t mutex;
private:
// doing locking at the FileNode level isn't as efficient as at the
// lowest level of RawFileIO, since that means locks are held longer
// (held during CPU intensive crypto operations!). However it makes it
// easier to avoid any race conditions with operations such as
// truncate() which may result in multiple calls down to the FileIO
// level.
mutable pthread_mutex_t mutex;
FSConfigPtr fsConfig;
FSConfigPtr fsConfig;
shared_ptr<FileIO> io;
std::string _pname; // plaintext name
std::string _cname; // encrypted name
DirNode *parent;
private:
FileNode(const FileNode &src);
FileNode &operator = (const FileNode &src);
shared_ptr<FileIO> io;
std::string _pname; // plaintext name
std::string _cname; // encrypted name
DirNode *parent;
private:
FileNode(const FileNode &src);
FileNode &operator=(const FileNode &src);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -27,118 +27,106 @@
#include "FSConfig.h"
// true if the path points to an existing node (of any type)
bool fileExists( const char *fileName );
bool fileExists(const char *fileName);
// true if path is a directory
bool isDirectory( const char *fileName );
bool isDirectory(const char *fileName);
// true if starts with '/'
bool isAbsolutePath( const char *fileName );
bool isAbsolutePath(const char *fileName);
// pointer to just after the last '/'
const char *lastPathElement( const char *name );
const char *lastPathElement(const char *name);
std::string parentDirectory( const std::string &path );
std::string parentDirectory(const std::string &path);
// ask the user for permission to create the directory. If they say ok, then
// do it and return true.
bool userAllowMkdir(const char *dirPath, mode_t mode );
bool userAllowMkdir(int promptno, const char *dirPath, mode_t mode );
bool userAllowMkdir(const char *dirPath, mode_t mode);
bool userAllowMkdir(int promptno, const char *dirPath, mode_t mode);
class Cipher;
class DirNode;
struct EncFS_Root
{
shared_ptr<Cipher> cipher;
CipherKey volumeKey;
shared_ptr<DirNode> root;
struct EncFS_Root {
shared_ptr<Cipher> cipher;
CipherKey volumeKey;
shared_ptr<DirNode> root;
EncFS_Root();
~EncFS_Root();
EncFS_Root();
~EncFS_Root();
};
typedef shared_ptr<EncFS_Root> RootPtr;
enum ConfigMode
{
Config_Prompt,
Config_Standard,
Config_Paranoia
};
enum ConfigMode { Config_Prompt, Config_Standard, Config_Paranoia };
struct EncFS_Opts
{
std::string rootDir;
bool createIfNotFound; // create filesystem if not found
bool idleTracking; // turn on idle monitoring of filesystem
bool mountOnDemand; // mounting on-demand
bool delayMount; // delay initial mount
struct EncFS_Opts {
std::string rootDir;
bool createIfNotFound; // create filesystem if not found
bool idleTracking; // turn on idle monitoring of filesystem
bool mountOnDemand; // mounting on-demand
bool delayMount; // delay initial mount
bool checkKey; // check crypto key decoding
bool forceDecode; // force decode on MAC block failures
bool checkKey; // check crypto key decoding
bool forceDecode; // force decode on MAC block failures
std::string passwordProgram; // path to password program (or empty)
bool useStdin; // read password from stdin rather then prompting
bool annotate; // print annotation line prompt to stderr.
std::string passwordProgram; // path to password program (or empty)
bool useStdin; // read password from stdin rather then prompting
bool annotate; // print annotation line prompt to stderr.
bool ownerCreate; // set owner of new files to caller
bool ownerCreate; // set owner of new files to caller
bool reverseEncryption; // Reverse encryption
bool reverseEncryption; // Reverse encryption
ConfigMode configMode;
ConfigMode configMode;
EncFS_Opts()
{
createIfNotFound = true;
idleTracking = false;
mountOnDemand = false;
delayMount = false;
checkKey = true;
forceDecode = false;
useStdin = false;
annotate = false;
ownerCreate = false;
reverseEncryption = false;
configMode = Config_Prompt;
}
EncFS_Opts() {
createIfNotFound = true;
idleTracking = false;
mountOnDemand = false;
delayMount = false;
checkKey = true;
forceDecode = false;
useStdin = false;
annotate = false;
ownerCreate = false;
reverseEncryption = false;
configMode = Config_Prompt;
}
};
/*
Read existing config file. Looks for any supported configuration version.
*/
ConfigType readConfig( const std::string &rootDir,
const shared_ptr<EncFSConfig> &config );
ConfigType readConfig(const std::string &rootDir,
const shared_ptr<EncFSConfig> &config);
/*
Save the configuration. Saves back as the same configuration type as was
read from.
*/
bool saveConfig( ConfigType type, const std::string &rootdir,
const shared_ptr<EncFSConfig> &config );
bool saveConfig(ConfigType type, const std::string &rootdir,
const shared_ptr<EncFSConfig> &config);
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,
const shared_ptr<EncFS_Opts> &opts );
RootPtr createV6Config(EncFS_Context *ctx, 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,
const shared_ptr<EncFSConfig> &config,
struct ConfigInfo *);
bool writeV4Config( const char *configFile,
const shared_ptr<EncFSConfig> &config);
bool readV4Config(const char *configFile, const shared_ptr<EncFSConfig> &config,
struct ConfigInfo *);
bool writeV4Config(const char *configFile,
const shared_ptr<EncFSConfig> &config);
bool readV5Config( const char *configFile,
const shared_ptr<EncFSConfig> &config,
struct ConfigInfo *);
bool writeV5Config( const char *configFile,
const shared_ptr<EncFSConfig> &config);
bool readV5Config(const char *configFile, const shared_ptr<EncFSConfig> &config,
struct ConfigInfo *);
bool writeV5Config(const char *configFile,
const shared_ptr<EncFSConfig> &config);
bool readV6Config( const char *configFile,
const shared_ptr<EncFSConfig> &config,
struct ConfigInfo *);
bool writeV6Config( const char *configFile,
const shared_ptr<EncFSConfig> &config);
bool readV6Config(const char *configFile, const shared_ptr<EncFSConfig> &config,
struct ConfigInfo *);
bool writeV6Config(const char *configFile,
const shared_ptr<EncFSConfig> &config);
#endif

View File

@ -28,103 +28,55 @@
using namespace rel;
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)
: _name( name_ )
, _current( Current )
, _revision( Revision )
, _age( Age )
{
}
: _name(name_), _current(Current), _revision(Revision), _age(Age) {}
Interface::Interface(const std::string &name_, int Current,
int Revision, int Age)
: _name( name_ )
, _current( Current )
, _revision( Revision )
, _age( Age )
{
}
Interface::Interface(const std::string &name_, int Current, int Revision,
int Age)
: _name(name_), _current(Current), _revision(Revision), _age(Age) {}
Interface::Interface(const Interface &src)
: _name( src._name )
, _current( src._current )
, _revision( src._revision )
, _age( src._age )
{
: _name(src._name),
_current(src._current),
_revision(src._revision),
_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()
: _current( 0 )
, _revision( 0 )
, _age( 0 )
{
const std::string &Interface::name() const { return _name; }
std::string &Interface::name() { return _name; }
int Interface::current() const { return _current; }
int &Interface::current() { return _current; }
int Interface::revision() const { return _revision; }
int &Interface::revision() { return _revision; }
int Interface::age() const { return _age; }
int &Interface::age() { return _age; }
bool operator==(const Interface &A, const Interface &B) {
return (A.name() == B.name() && A.current() == B.current() &&
A.revision() == B.revision() && A.age() == B.age());
}
Interface &Interface::operator = (const Interface &src)
{
_name = src._name;
_current = src._current;
_revision = src._revision;
_age = src._age;
return *this;
}
const std::string & Interface::name() const
{
return _name;
}
std::string & Interface::name()
{
return _name;
}
int Interface::current() const
{
return _current;
}
int &Interface::current()
{
return _current;
}
int Interface::revision() const
{
return _revision;
}
int &Interface::revision()
{
return _revision;
}
int Interface::age() const
{
return _age;
}
int &Interface::age()
{
return _age;
}
bool operator == (const Interface &A, const Interface &B)
{
return ( A.name() == B.name()
&& A.current() == B.current()
&& A.revision() == B.revision()
&& A.age() == B.age() );
}
bool operator != (const Interface &A, const Interface &B)
{
return ( A.name() != B.name()
|| A.current() != B.current()
|| A.revision() != B.revision()
|| A.age() != B.age() );
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..
@ -139,91 +91,74 @@ static int sign( int a, int b )
}
#else
// simple, easy to check, unlikely to break due to unforseen events..
static int sign( int a, int b )
{
if(a < b)
return 0;
else if(a == b)
return 1;
else
return 2;
static int sign(int a, int b) {
if (a < b)
return 0;
else if (a == b)
return 1;
else
return 2;
}
#endif
static int diffSum( const Interface &A, const Interface &B )
{
int cS = sign( A.current() , B.current() );
int aS = sign( A.age(), B.age() );
int rS = sign( A.revision(), B.revision() );
static int diffSum(const Interface &A, const Interface &B) {
int cS = sign(A.current(), B.current());
int aS = sign(A.age(), B.age());
int rS = sign(A.revision(), B.revision());
return (cS * 3 + aS) * 3 + rS;
return (cS * 3 + aS) * 3 + rS;
}
const int EqualVersion = (1 * 3 + 1) * 3 + 1;
bool Interface::implements(const Interface &B) const
{
rLog(Info, "checking if %s(%i:%i:%i) implements %s(%i:%i:%i)",
name().c_str(), current(), revision(), age(),
B.name().c_str(), B.current(), B.revision(), B.age());
bool Interface::implements(const Interface &B) const {
rLog(Info, "checking if %s(%i:%i:%i) implements %s(%i:%i:%i)", name().c_str(),
current(), revision(), age(), B.name().c_str(), B.current(),
B.revision(), B.age());
if( name() != B.name() )
return false;
if (name() != B.name()) return false;
int currentDiff = current() - B.current();
return ( currentDiff >= 0 && currentDiff <= age() );
int currentDiff = current() - B.current();
return (currentDiff >= 0 && currentDiff <= age());
}
bool operator < (const Interface &A, const Interface &B)
{
if( A.name() == B.name() )
{
return ( diffSum(A,B) < EqualVersion );
} else
return A.name() < B.name();
bool operator<(const Interface &A, const Interface &B) {
if (A.name() == B.name()) {
return (diffSum(A, B) < EqualVersion);
} else
return A.name() < B.name();
}
bool operator > (const Interface &A, const Interface &B)
{
if( A.name() == B.name() )
{
return ( diffSum(A,B) > EqualVersion );
} else
return A.name() < B.name();
bool operator>(const Interface &A, const Interface &B) {
if (A.name() == B.name()) {
return (diffSum(A, B) > EqualVersion);
} else
return A.name() < B.name();
}
bool operator <= (const Interface &A, const Interface &B)
{
if( A.name() == B.name() )
{
return ( diffSum(A,B) <= EqualVersion );
} else
return A.name() < B.name();
bool operator<=(const Interface &A, const Interface &B) {
if (A.name() == B.name()) {
return (diffSum(A, B) <= EqualVersion);
} else
return A.name() < B.name();
}
bool operator >= (const Interface &A, const Interface &B)
{
if( A.name() == B.name() )
{
return ( diffSum(A,B) >= EqualVersion );
} else
return A.name() < B.name();
bool operator>=(const Interface &A, const Interface &B) {
if (A.name() == B.name()) {
return (diffSum(A, B) >= EqualVersion);
} else
return A.name() < B.name();
}
ConfigVar & operator << (ConfigVar &dst, const rel::Interface &iface)
{
dst << iface.name() << iface.current() << iface.revision() << iface.age();
return dst;
ConfigVar &operator<<(ConfigVar &dst, const rel::Interface &iface) {
dst << iface.name() << iface.current() << iface.revision() << iface.age();
return dst;
}
const ConfigVar & operator >> (const ConfigVar &src, Interface &iface)
{
src >> iface.name();
src >> iface.current();
src >> iface.revision();
src >> iface.age();
return src;
const ConfigVar &operator>>(const ConfigVar &src, Interface &iface) {
src >> iface.name();
src >> iface.current();
src >> iface.revision();
src >> iface.age();
return src;
}

View File

@ -26,62 +26,57 @@
class ConfigVar;
// part of REL library..
namespace rel
{
namespace rel {
class Interface
{
public:
class Interface {
public:
/*!
Version numbers as described by libtool: info://libtool/versioning
Current - the most recent interface api that is implemented.
Revision - the implementation number of the current interface.
Age - the difference between the newest and oldest interfaces that
are implemented.
*/
Interface(const char *name, int Current, int Revision, int Age);
Interface(const std::string &name, int Current, int Revision, int Age);
Interface(const Interface &src);
Interface();
/*!
Version numbers as described by libtool: info://libtool/versioning
Current - the most recent interface api that is implemented.
Revision - the implementation number of the current interface.
Age - the difference between the newest and oldest interfaces that
are implemented.
*/
Interface( const char *name, int Current, int Revision, int Age );
Interface( const std::string &name, int Current, int Revision, int Age);
Interface(const Interface &src);
Interface();
// check if we implement the interface described by B.
// Note that A.implements(B) is not the same as B.implements(A)
// This checks the current() version and age() against B.current() for
// compatibility. Even if A.implements(B) is true, B > A may also be
// true, meaning B is a newer revision of the interface then A.
bool implements(const Interface &dst) const;
// check if we implement the interface described by B.
// Note that A.implements(B) is not the same as B.implements(A)
// This checks the current() version and age() against B.current() for
// compatibility. Even if A.implements(B) is true, B > A may also be
// true, meaning B is a newer revision of the interface then A.
bool implements( const Interface &dst ) const;
const std::string &name() const;
int current() const;
int revision() const;
int age() const;
const std::string &name() const;
int current() const;
int revision() const;
int age() const;
std::string &name();
int &current();
int &revision();
int &age();
std::string &name();
int &current();
int &revision();
int &age();
Interface &operator = ( const Interface &src );
private:
std::string _name;
int _current;
int _revision;
int _age;
};
Interface &operator=(const Interface &src);
private:
std::string _name;
int _current;
int _revision;
int _age;
};
}
ConfigVar & operator << (ConfigVar &, const rel::Interface &);
const ConfigVar & operator >> (const ConfigVar &, rel::Interface &);
ConfigVar &operator<<(ConfigVar &, const rel::Interface &);
const ConfigVar &operator>>(const ConfigVar &, rel::Interface &);
bool operator < (const rel::Interface &A, const rel::Interface &B);
bool operator > (const rel::Interface &A, const rel::Interface &B);
bool operator <= (const rel::Interface &A, const rel::Interface &B);
bool operator >= (const rel::Interface &A, const rel::Interface &B);
bool operator == (const rel::Interface &A, const rel::Interface &B);
bool operator != (const rel::Interface &A, const rel::Interface &B);
bool operator<(const 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

View File

@ -51,66 +51,45 @@ static RLogChannel *Info = DEF_CHANNEL("info/MACFileIO", Log_Info);
//
static rel::Interface MACFileIO_iface("FileIO/MAC", 2, 1, 0);
int dataBlockSize(const FSConfigPtr &cfg)
{
return cfg->config->blockSize
- cfg->config->blockMACBytes
- cfg->config->blockMACRandBytes;
int dataBlockSize(const FSConfigPtr &cfg) {
return cfg->config->blockSize - cfg->config->blockMACBytes -
cfg->config->blockMACRandBytes;
}
MACFileIO::MACFileIO( const shared_ptr<FileIO> &_base,
const FSConfigPtr &cfg )
: BlockFileIO( dataBlockSize( cfg ), cfg )
, base( _base )
, cipher( cfg->cipher )
, key( cfg->key )
, macBytes( cfg->config->blockMACBytes )
, randBytes( cfg->config->blockMACRandBytes )
, warnOnly( cfg->opts->forceDecode )
{
rAssert( macBytes >= 0 && macBytes <= 8 );
rAssert( randBytes >= 0 );
rLog(Info, "fs block size = %i, macBytes = %i, randBytes = %i",
cfg->config->blockSize,
cfg->config->blockMACBytes,
cfg->config->blockMACRandBytes);
MACFileIO::MACFileIO(const shared_ptr<FileIO> &_base, const FSConfigPtr &cfg)
: BlockFileIO(dataBlockSize(cfg), cfg),
base(_base),
cipher(cfg->cipher),
key(cfg->key),
macBytes(cfg->config->blockMACBytes),
randBytes(cfg->config->blockMACRandBytes),
warnOnly(cfg->opts->forceDecode) {
rAssert(macBytes >= 0 && macBytes <= 8);
rAssert(randBytes >= 0);
rLog(Info, "fs block size = %i, macBytes = %i, randBytes = %i",
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
{
return MACFileIO_iface;
}
const char *MACFileIO::getFileName() const { return base->getFileName(); }
int MACFileIO::open( int flags )
{
return base->open( flags );
}
bool MACFileIO::setIV(uint64_t iv) { return base->setIV(iv); }
void MACFileIO::setFileName( const char *fileName )
{
base->setFileName( fileName );
}
const char *MACFileIO::getFileName() const
{
return base->getFileName();
}
bool MACFileIO::setIV( uint64_t iv )
{
return base->setIV( iv );
}
inline static off_t roundUpDivide( off_t numerator, int denominator )
{
// 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;
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
@ -123,10 +102,9 @@ inline static off_t roundUpDivide( off_t numerator, int denominator )
// ... blockNum = 1
// ... partialBlock = 0
// ... adjLoc = 1 * blockSize
static off_t locWithHeader( off_t offset, int blockSize, int headerSize )
{
off_t blockNum = roundUpDivide( offset , blockSize - headerSize );
return offset + blockNum * headerSize;
static off_t locWithHeader(off_t offset, int blockSize, int headerSize) {
off_t blockNum = roundUpDivide(offset, blockSize - headerSize);
return offset + blockNum * headerSize;
}
// convert from a given location in the stream containing headers, and return a
@ -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
// headers are stored at the beginning of the block, so even the first data is
// offset by the size of the header.
static off_t locWithoutHeader( off_t offset, int blockSize, int headerSize )
{
off_t blockNum = roundUpDivide( offset , blockSize );
return offset - blockNum * headerSize;
static off_t locWithoutHeader(off_t offset, int blockSize, int headerSize) {
off_t blockNum = roundUpDivide(offset, blockSize);
return offset - blockNum * headerSize;
}
int MACFileIO::getAttr( struct stat *stbuf ) const
{
int res = base->getAttr( stbuf );
int MACFileIO::getAttr(struct stat *stbuf) const {
int res = base->getAttr(stbuf);
if(res == 0 && S_ISREG(stbuf->st_mode))
{
// 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..
if (res == 0 && S_ISREG(stbuf->st_mode)) {
// have to adjust size field..
int headerSize = macBytes + randBytes;
int bs = blockSize() + headerSize;
stbuf->st_size = locWithoutHeader(stbuf->st_size, bs, headerSize);
}
off_t size = base->getSize();
if(size > 0)
size = locWithoutHeader( size, bs, headerSize );
return size;
return res;
}
ssize_t MACFileIO::readOneBlock( const IORequest &req ) const
{
int headerSize = macBytes + randBytes;
off_t MACFileIO::getSize() const {
// adjust the size to hide the header overhead we tack on..
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;
tmp.offset = locWithHeader( req.offset, bs, headerSize );
tmp.data = mb.data;
tmp.dataLen = headerSize + req.dataLen;
ssize_t MACFileIO::readOneBlock(const IORequest &req) const {
int headerSize = macBytes + randBytes;
// get the data from the base FileIO layer
ssize_t readSize = base->read( tmp );
int bs = blockSize() + headerSize;
// 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;
MemBlock mb = MemoryPool::allocate(bs);
if(readSize > headerSize)
{
if(!skipBlock)
{
// At this point the data has been decoded. So, compute the MAC of
// the block and check against the checksum stored in the header..
uint64_t mac = cipher->MAC_64( tmp.data + macBytes,
readSize - macBytes, key );
IORequest tmp;
tmp.offset = locWithHeader(req.offset, bs, headerSize);
tmp.data = mb.data;
tmp.dataLen = headerSize + req.dataLen;
// Constant time comparision to prevent timing attacks
unsigned char fail = 0;
for(int i=0; i<macBytes; ++i, mac >>= 8)
{
int test = mac & 0xff;
int stored = tmp.data[i];
// get the data from the base FileIO layer
ssize_t readSize = base->read(tmp);
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 )
{
// 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"));
}
}
if (readSize > headerSize) {
if (!skipBlock) {
// At this point the data has been decoded. So, compute the MAC of
// the block and check against the checksum stored in the header..
uint64_t mac =
cipher->MAC_64(tmp.data + macBytes, readSize - macBytes, key);
// Constant time comparision to prevent timing attacks
unsigned char fail = 0;
for (int i = 0; i < macBytes; ++i, mac >>= 8) {
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 )
{
int headerSize = macBytes + randBytes;
bool MACFileIO::writeOneBlock(const IORequest &req) {
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.
MemBlock mb = MemoryPool::allocate( bs );
// we have the unencrypted data, so we need to attach a header to it.
MemBlock mb = MemoryPool::allocate(bs);
IORequest newReq;
newReq.offset = locWithHeader( req.offset, bs, headerSize );
newReq.data = mb.data;
newReq.dataLen = headerSize + req.dataLen;
IORequest newReq;
newReq.offset = locWithHeader(req.offset, bs, headerSize);
newReq.data = mb.data;
newReq.dataLen = headerSize + req.dataLen;
memset( newReq.data, 0, headerSize );
memcpy( newReq.data + headerSize, req.data, req.dataLen );
if(randBytes > 0)
{
if(!cipher->randomize( newReq.data+macBytes, randBytes, false ))
return false;
memset(newReq.data, 0, headerSize);
memcpy(newReq.data + headerSize, req.data, req.dataLen);
if (randBytes > 0) {
if (!cipher->randomize(newReq.data + macBytes, randBytes, false))
return false;
}
if (macBytes > 0) {
// compute the mac (which includes the random data) and fill it in
uint64_t mac =
cipher->MAC_64(newReq.data + macBytes, req.dataLen + randBytes, key);
for (int i = 0; i < macBytes; ++i) {
newReq.data[i] = mac & 0xff;
mac >>= 8;
}
}
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 );
// now, we can let the next level have it..
bool ok = base->write(newReq);
for(int i=0; i<macBytes; ++i)
{
newReq.data[i] = mac & 0xff;
mac >>= 8;
}
}
MemoryPool::release(mb);
// now, we can let the next level have it..
bool ok = base->write( newReq );
MemoryPool::release( mb );
return ok;
return ok;
}
int MACFileIO::truncate( off_t size )
{
int headerSize = macBytes + randBytes;
int bs = blockSize() + headerSize;
int MACFileIO::truncate(off_t size) {
int headerSize = macBytes + randBytes;
int bs = blockSize() + headerSize;
int res = BlockFileIO::truncateBase( size, 0 );
int res = BlockFileIO::truncateBase(size, 0);
if(res == 0)
base->truncate( locWithHeader( size, bs, headerSize ) );
if (res == 0) base->truncate(locWithHeader(size, bs, headerSize));
return res;
return res;
}
bool MACFileIO::isWritable() const
{
return base->isWritable();
}
bool MACFileIO::isWritable() const { return base->isWritable(); }

View File

@ -24,44 +24,41 @@
#include "BlockFileIO.h"
#include "Cipher.h"
class MACFileIO : public BlockFileIO
{
public:
/*
If warnOnlyMode is enabled, then a MAC comparison failure will only
result in a warning message from encfs -- the garbled data will still
be made available..
*/
MACFileIO( const shared_ptr<FileIO> &base,
const FSConfigPtr &cfg );
MACFileIO();
virtual ~MACFileIO();
class MACFileIO : public BlockFileIO {
public:
/*
If warnOnlyMode is enabled, then a MAC comparison failure will only
result in a warning message from encfs -- the garbled data will still
be made available..
*/
MACFileIO(const shared_ptr<FileIO> &base, const FSConfigPtr &cfg);
MACFileIO();
virtual ~MACFileIO();
virtual rel::Interface interface() const;
virtual rel::Interface interface() const;
virtual void setFileName( const char *fileName );
virtual const char *getFileName() const;
virtual bool setIV( uint64_t iv );
virtual void setFileName(const char *fileName);
virtual const char *getFileName() const;
virtual bool setIV(uint64_t iv);
virtual int open( int flags );
virtual int getAttr( struct stat *stbuf ) const;
virtual off_t getSize() const;
virtual int open(int flags);
virtual int getAttr(struct stat *stbuf) const;
virtual off_t getSize() const;
virtual int truncate( off_t size );
virtual int truncate(off_t size);
virtual bool isWritable() const;
virtual bool isWritable() const;
private:
virtual ssize_t readOneBlock( const IORequest &req ) const;
virtual bool writeOneBlock( const IORequest &req );
private:
virtual ssize_t readOneBlock(const IORequest &req) const;
virtual bool writeOneBlock(const IORequest &req);
shared_ptr<FileIO> base;
shared_ptr<Cipher> cipher;
CipherKey key;
int macBytes;
int randBytes;
bool warnOnly;
shared_ptr<FileIO> base;
shared_ptr<Cipher> cipher;
CipherKey key;
int macBytes;
int randBytes;
bool warnOnly;
};
#endif

View File

@ -30,116 +30,101 @@
#ifdef HAVE_VALGRIND_MEMCHECK_H
#include <valgrind/memcheck.h>
#else
#define VALGRIND_MAKE_MEM_NOACCESS( a, b )
#define VALGRIND_MAKE_MEM_UNDEFINED( a, b )
#define VALGRIND_MAKE_MEM_NOACCESS(a, b)
#define VALGRIND_MAKE_MEM_UNDEFINED(a, b)
#endif
using namespace rlog;
# include <openssl/buffer.h>
#define BLOCKDATA( BLOCK ) (unsigned char*)BLOCK->data->data
#include <openssl/buffer.h>
#define BLOCKDATA(BLOCK) (unsigned char *) BLOCK->data->data
struct BlockList
{
BlockList *next;
int size;
BUF_MEM *data;
struct BlockList {
BlockList *next;
int size;
BUF_MEM *data;
};
static BlockList *allocBlock( int size )
{
BlockList *block = new BlockList;
block->size = size;
block->data = BUF_MEM_new( );
BUF_MEM_grow( block->data, size );
VALGRIND_MAKE_MEM_NOACCESS( block->data->data, block->data->max );
static BlockList *allocBlock(int size) {
BlockList *block = new BlockList;
block->size = size;
block->data = BUF_MEM_new();
BUF_MEM_grow(block->data, size);
VALGRIND_MAKE_MEM_NOACCESS(block->data->data, block->data->max);
return block;
return block;
}
static void freeBlock( BlockList *el )
{
VALGRIND_MAKE_MEM_UNDEFINED( el->data->data, el->data->max );
BUF_MEM_free( el->data );
static void freeBlock(BlockList *el) {
VALGRIND_MAKE_MEM_UNDEFINED(el->data->data, el->data->max);
BUF_MEM_free(el->data);
delete el;
delete el;
}
static pthread_mutex_t gMPoolMutex = PTHREAD_MUTEX_INITIALIZER;
static BlockList *gMemPool = NULL;
MemBlock MemoryPool::allocate(int size) {
pthread_mutex_lock(&gMPoolMutex);
BlockList *parent = NULL;
BlockList *block = gMemPool;
// check if we already have a large enough block available..
while (block != NULL && block->size < size) {
parent = block;
block = block->next;
}
MemBlock MemoryPool::allocate( int size )
{
pthread_mutex_lock( &gMPoolMutex );
// unlink block from list
if (block) {
if (!parent)
gMemPool = block->next;
else
parent->next = block->next;
}
pthread_mutex_unlock(&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;
}
if (!block) block = allocBlock(size);
block->next = NULL;
// unlink block from list
if(block)
{
if(!parent)
gMemPool = block->next;
else
parent->next = block->next;
}
pthread_mutex_unlock( &gMPoolMutex );
MemBlock result;
result.data = BLOCKDATA(block);
result.internalData = block;
if(!block)
block = allocBlock( size );
block->next = NULL;
VALGRIND_MAKE_MEM_UNDEFINED(result.data, size);
MemBlock result;
result.data = BLOCKDATA(block);
result.internalData = block;
VALGRIND_MAKE_MEM_UNDEFINED( result.data, size );
return result;
return result;
}
void MemoryPool::release( const MemBlock &mb )
{
pthread_mutex_lock( &gMPoolMutex );
void MemoryPool::release(const MemBlock &mb) {
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..
VALGRIND_MAKE_MEM_UNDEFINED( block->data->data, block->size );
memset( BLOCKDATA(block) , 0, block->size);
VALGRIND_MAKE_MEM_NOACCESS( block->data->data, block->data->max );
// just to be sure there's nothing important left in buffers..
VALGRIND_MAKE_MEM_UNDEFINED(block->data->data, block->size);
memset(BLOCKDATA(block), 0, block->size);
VALGRIND_MAKE_MEM_NOACCESS(block->data->data, block->data->max);
block->next = gMemPool;
gMemPool = block;
block->next = gMemPool;
gMemPool = block;
pthread_mutex_unlock( &gMPoolMutex );
pthread_mutex_unlock(&gMPoolMutex);
}
void MemoryPool::destroyAll()
{
pthread_mutex_lock( &gMPoolMutex );
void MemoryPool::destroyAll() {
pthread_mutex_lock(&gMPoolMutex);
BlockList *block = gMemPool;
gMemPool = NULL;
BlockList *block = gMemPool;
gMemPool = NULL;
pthread_mutex_unlock( &gMPoolMutex );
pthread_mutex_unlock(&gMPoolMutex);
while(block != NULL)
{
BlockList *next = block->next;
while (block != NULL) {
BlockList *next = block->next;
freeBlock( block );
block = next;
}
freeBlock(block);
block = next;
}
}

View File

@ -21,20 +21,15 @@
#ifndef _MemoryPool_incl_
#define _MemoryPool_incl_
struct MemBlock {
unsigned char *data;
struct MemBlock
{
unsigned char *data;
void *internalData;
void *internalData;
MemBlock();
MemBlock();
};
inline MemBlock::MemBlock()
: data(0), internalData(0)
{
}
inline MemBlock::MemBlock() : data(0), internalData(0) {}
/*
Memory Pool for fixed sized objects.
@ -45,12 +40,10 @@ inline MemBlock::MemBlock()
unsigned char *buffer = mb.data;
MemoryPool::release( mb );
*/
namespace MemoryPool
{
MemBlock allocate( int size );
void release( const MemBlock &el );
void destroyAll();
namespace MemoryPool {
MemBlock allocate(int size);
void release(const MemBlock &el);
void destroyAll();
}
#endif

View File

@ -23,43 +23,33 @@
#include <pthread.h>
namespace rel
{
namespace rel {
class Lock
{
public:
Lock( pthread_mutex_t &mutex );
~Lock();
class Lock {
public:
Lock(pthread_mutex_t &mutex);
~Lock();
// leave the lock as it is. When the Lock wrapper is destroyed, it
// will do nothing with the pthread mutex.
void leave();
// leave the lock as it is. When the Lock wrapper is destroyed, it
// will do nothing with the pthread mutex.
void leave();
private:
Lock(const Lock &src); // not allowed
Lock &operator = (const Lock &src); // not allowed
private:
Lock(const Lock &src); // not allowed
Lock &operator=(const Lock &src); // not allowed
pthread_mutex_t *_mutex;
};
pthread_mutex_t *_mutex;
};
inline Lock::Lock( pthread_mutex_t &mutex )
: _mutex( &mutex )
{
pthread_mutex_lock( _mutex );
}
inline Lock::Lock(pthread_mutex_t &mutex) : _mutex(&mutex) {
pthread_mutex_lock(_mutex);
}
inline Lock::~Lock( )
{
if(_mutex)
pthread_mutex_unlock( _mutex );
}
inline Lock::~Lock() {
if (_mutex) pthread_mutex_unlock(_mutex);
}
inline void Lock::leave()
{
_mutex = 0;
}
inline void Lock::leave() { _mutex = 0; }
}
#endif

View File

@ -39,314 +39,250 @@ using namespace rel;
using namespace rlog;
#define REF_MODULE(TYPE) \
if(!TYPE::Enabled() ) \
cerr << "referenceModule: should never happen\n";
if (!TYPE::Enabled()) cerr << "referenceModule: should never happen\n";
static
void AddSymbolReferences()
{
REF_MODULE(BlockNameIO)
REF_MODULE(StreamNameIO)
REF_MODULE(NullNameIO)
static void AddSymbolReferences() {
REF_MODULE(BlockNameIO)
REF_MODULE(StreamNameIO)
REF_MODULE(NullNameIO)
}
struct NameIOAlg
{
bool hidden;
NameIO::Constructor constructor;
string description;
Interface iface;
struct NameIOAlg {
bool hidden;
NameIO::Constructor constructor;
string description;
Interface iface;
};
typedef multimap< string, NameIOAlg > NameIOMap_t;
typedef multimap<string, NameIOAlg> NameIOMap_t;
static NameIOMap_t *gNameIOMap = 0;
list<NameIO::Algorithm> NameIO::GetAlgorithmList(bool includeHidden) {
AddSymbolReferences();
list< NameIO::Algorithm >
NameIO::GetAlgorithmList( bool includeHidden )
{
AddSymbolReferences();
list<Algorithm> result;
if (gNameIOMap) {
NameIOMap_t::const_iterator it;
NameIOMap_t::const_iterator end = gNameIOMap->end();
for (it = gNameIOMap->begin(); it != end; ++it) {
if (includeHidden || !it->second.hidden) {
Algorithm tmp;
tmp.name = it->first;
tmp.description = it->second.description;
tmp.iface = it->second.iface;
list< Algorithm > result;
if(gNameIOMap)
{
NameIOMap_t::const_iterator it;
NameIOMap_t::const_iterator end = gNameIOMap->end();
for(it = gNameIOMap->begin(); it != end; ++it)
{
if(includeHidden || !it->second.hidden)
{
Algorithm tmp;
tmp.name = it->first;
tmp.description = it->second.description;
tmp.iface = it->second.iface;
result.push_back( tmp );
}
}
result.push_back(tmp);
}
}
}
return result;
return result;
}
bool NameIO::Register( const char *name, const char *description,
const Interface &iface, Constructor constructor,
bool hidden )
{
if( !gNameIOMap )
gNameIOMap = new NameIOMap_t;
bool NameIO::Register(const char *name, const char *description,
const Interface &iface, Constructor constructor,
bool hidden) {
if (!gNameIOMap) gNameIOMap = new NameIOMap_t;
NameIOAlg alg;
alg.hidden = hidden;
alg.constructor = constructor;
alg.description = description;
alg.iface = iface;
NameIOAlg alg;
alg.hidden = hidden;
alg.constructor = constructor;
alg.description = description;
alg.iface = iface;
gNameIOMap->insert( make_pair( string(name), alg ));
return true;
gNameIOMap->insert(make_pair(string(name), alg));
return true;
}
shared_ptr<NameIO> NameIO::New( const string &name,
const shared_ptr<Cipher> &cipher, const CipherKey &key)
{
shared_ptr<NameIO> result;
if(gNameIOMap)
{
NameIOMap_t::const_iterator it = gNameIOMap->find( name );
if(it != gNameIOMap->end())
{
Constructor fn = it->second.constructor;
result = (*fn)( it->second.iface, cipher, key );
}
shared_ptr<NameIO> NameIO::New(const string &name,
const shared_ptr<Cipher> &cipher,
const CipherKey &key) {
shared_ptr<NameIO> result;
if (gNameIOMap) {
NameIOMap_t::const_iterator it = gNameIOMap->find(name);
if (it != gNameIOMap->end()) {
Constructor fn = it->second.constructor;
result = (*fn)(it->second.iface, cipher, key);
}
return result;
}
return result;
}
shared_ptr<NameIO> NameIO::New( const Interface &iface,
const shared_ptr<Cipher> &cipher, const CipherKey &key )
{
shared_ptr<NameIO> result;
if(gNameIOMap)
{
NameIOMap_t::const_iterator it;
NameIOMap_t::const_iterator end = gNameIOMap->end();
for(it = gNameIOMap->begin(); it != end; ++it)
{
if( it->second.iface.implements( iface ))
{
Constructor fn = it->second.constructor;
result = (*fn)( iface, cipher, key );
break;
}
}
shared_ptr<NameIO> NameIO::New(const Interface &iface,
const shared_ptr<Cipher> &cipher,
const CipherKey &key) {
shared_ptr<NameIO> result;
if (gNameIOMap) {
NameIOMap_t::const_iterator it;
NameIOMap_t::const_iterator end = gNameIOMap->end();
for (it = gNameIOMap->begin(); it != end; ++it) {
if (it->second.iface.implements(iface)) {
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()
: chainedNameIV( false ), reverseEncryption( false )
{
}
void NameIO::setChainedNameIV(bool enable) { chainedNameIV = enable; }
NameIO::~NameIO()
{
}
bool NameIO::getChainedNameIV() const { return chainedNameIV; }
void NameIO::setChainedNameIV( bool enable )
{
chainedNameIV = enable;
}
void NameIO::setReverseEncryption(bool enable) { reverseEncryption = enable; }
bool NameIO::getChainedNameIV() const
{
return chainedNameIV;
}
bool NameIO::getReverseEncryption() const { return reverseEncryption; }
void NameIO::setReverseEncryption( bool enable )
{
reverseEncryption = enable;
}
std::string NameIO::recodePath(const char *path,
int (NameIO::*_length)(int) const,
int (NameIO::*_code)(const char *, int,
uint64_t *, char *) const,
uint64_t *iv) const {
string output;
bool NameIO::getReverseEncryption() const
{
return reverseEncryption;
}
while (*path) {
if (*path == '/') {
if (!output.empty()) // don't start the string with '/'
output += '/';
++path;
} else {
bool isDotFile = (*path == '.');
const char *next = strchr(path, '/');
int len = next ? next - path : strlen(path);
// at this point we know that len > 0
if (isDotFile && (path[len - 1] == '.') && (len <= 2)) {
output.append(len, '.'); // append [len] copies of '.'
path += len;
continue;
}
std::string NameIO::recodePath( const char *path,
int (NameIO::*_length)(int) const,
int (NameIO::*_code)(const char*, int, uint64_t *, char*) const,
uint64_t *iv ) const
{
string output;
// figure out buffer sizes
int approxLen = (this->*_length)(len);
if (approxLen <= 0) throw ERROR("Filename too small to decode");
while( *path )
{
if( *path == '/' )
{
if( !output.empty() ) // don't start the string with '/'
output += '/';
++path;
} else
{
bool isDotFile = (*path == '.');
const char *next = strchr( path, '/' );
int len = next ? next - path : strlen( path );
BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1)
// 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;
}
// code the name
int codedLen = (this->*_code)(path, len, iv, codeBuf);
rAssert(codedLen <= approxLen);
rAssert(codeBuf[codedLen] == '\0');
path += len;
// figure out buffer sizes
int approxLen = (this->*_length)( len );
if(approxLen <= 0)
throw ERROR("Filename too small to decode");
// append result to string
output += (char *)codeBuf;
BUFFER_INIT( codeBuf, 32, (unsigned int)approxLen+1 )
// code the name
int codedLen = (this->*_code)( path, len, iv, codeBuf );
rAssert( codedLen <= approxLen );
rAssert( codeBuf[codedLen] == '\0' );
path += len;
// append result to string
output += (char*)codeBuf;
BUFFER_RESET( codeBuf )
}
BUFFER_RESET(codeBuf)
}
}
return output;
return output;
}
std::string NameIO::encodePath( const char *plaintextPath ) const
{
uint64_t iv = 0;
return encodePath( plaintextPath, &iv);
std::string NameIO::encodePath(const char *plaintextPath) const {
uint64_t iv = 0;
return encodePath(plaintextPath, &iv);
}
std::string NameIO::decodePath( const char *cipherPath ) const
{
uint64_t iv = 0;
return decodePath( cipherPath, &iv );
std::string NameIO::decodePath(const char *cipherPath) const {
uint64_t iv = 0;
return decodePath(cipherPath, &iv);
}
std::string NameIO::_encodePath( const char *plaintextPath, uint64_t *iv ) const
{
// if chaining is not enabled, then the iv pointer is not used..
if(!chainedNameIV)
iv = 0;
return recodePath( plaintextPath,
&NameIO::maxEncodedNameLen, &NameIO::encodeName, iv);
std::string NameIO::_encodePath(const char *plaintextPath, uint64_t *iv) const {
// if chaining is not enabled, then the iv pointer is not used..
if (!chainedNameIV) iv = 0;
return recodePath(plaintextPath, &NameIO::maxEncodedNameLen,
&NameIO::encodeName, iv);
}
std::string NameIO::_decodePath( const char *cipherPath, uint64_t *iv ) const
{
// if chaining is not enabled, then the iv pointer is not used..
if(!chainedNameIV)
iv = 0;
return recodePath( cipherPath,
&NameIO::maxDecodedNameLen, &NameIO::decodeName, iv);
std::string NameIO::_decodePath(const char *cipherPath, uint64_t *iv) const {
// if chaining is not enabled, then the iv pointer is not used..
if (!chainedNameIV) iv = 0;
return recodePath(cipherPath, &NameIO::maxDecodedNameLen, &NameIO::decodeName,
iv);
}
std::string NameIO::encodePath( const char *path, uint64_t *iv ) const
{
return getReverseEncryption() ?
_decodePath( path, iv ) :
_encodePath( path, iv );
std::string NameIO::encodePath(const char *path, uint64_t *iv) const {
return getReverseEncryption() ? _decodePath(path, iv) : _encodePath(path, iv);
}
std::string NameIO::decodePath( const char *path, uint64_t *iv ) const
{
return getReverseEncryption() ?
_encodePath( path, iv ) :
_decodePath( path, iv );
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::encodeName(const char *input, int length, char *output) const {
return encodeName(input, length, (uint64_t *)0, output);
}
int NameIO::decodeName( const char *input, int length, char *output ) const
{
return decodeName( input, length, (uint64_t*)0, output );
int NameIO::decodeName(const char *input, int length, char *output) const {
return decodeName(input, length, (uint64_t *)0, output);
}
std::string NameIO::_encodeName( const char *plaintextName, int length ) const
{
int approxLen = maxEncodedNameLen( length );
std::string NameIO::_encodeName(const char *plaintextName, int length) const {
int approxLen = maxEncodedNameLen(length);
BUFFER_INIT( codeBuf, 32, (unsigned int)approxLen+1 )
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' );
// 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;
// append result to string
std::string result = (char *)codeBuf;
BUFFER_RESET( codeBuf )
BUFFER_RESET(codeBuf)
return result;
return result;
}
std::string NameIO::_decodeName( const char *encodedName, int length ) const
{
int approxLen = maxDecodedNameLen( length );
std::string NameIO::_decodeName(const char *encodedName, int length) const {
int approxLen = maxDecodedNameLen(length);
BUFFER_INIT( codeBuf, 32, (unsigned int)approxLen+1 )
BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1)
// code the name
int codedLen = decodeName( encodedName, length, 0, codeBuf );
rAssert( codedLen <= approxLen );
rAssert( codeBuf[codedLen] == '\0' );
// 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;
// append result to string
std::string result = (char *)codeBuf;
BUFFER_RESET( codeBuf )
BUFFER_RESET(codeBuf)
return result;
return result;
}
std::string NameIO::encodeName( const char *path, int length ) const
{
return getReverseEncryption() ?
_decodeName( path, length ) :
_encodeName( path, length );
std::string NameIO::encodeName(const char *path, int length) const {
return getReverseEncryption() ? _decodeName(path, length)
: _encodeName(path, length);
}
std::string NameIO::decodeName( const char *path, int length ) const
{
return getReverseEncryption() ?
_encodeName( path, length ) :
_decodeName( path, length );
std::string NameIO::decodeName(const char *path, int length) const {
return getReverseEncryption() ? _encodeName(path, length)
: _decodeName(path, length);
}
/*
int NameIO::encodeName( const char *path, int length,
char *output ) const
char *output ) const
{
return getReverseEncryption() ?
_decodeName( path, length, output ) :
_encodeName( path, length, output );
_decodeName( path, length, output ) :
_encodeName( path, length, output );
}
int NameIO::decodeName( const char *path, int length,
char *output ) const
char *output ) const
{
return getReverseEncryption() ?
_encodeName( path, length, output ) :
_decodeName( path, length, output );
_encodeName( path, length, output ) :
_decodeName( path, length, output );
}
*/

View File

@ -31,85 +31,80 @@
class Cipher;
class NameIO
{
public:
typedef shared_ptr<NameIO> (*Constructor)( const rel::Interface &iface,
const shared_ptr<Cipher> &cipher, const CipherKey &key);
class NameIO {
public:
typedef shared_ptr<NameIO>(*Constructor)(const rel::Interface &iface,
const shared_ptr<Cipher> &cipher,
const CipherKey &key);
struct Algorithm
{
std::string name;
std::string description;
rel::Interface iface;
};
struct Algorithm {
std::string name;
std::string description;
rel::Interface iface;
};
typedef std::list<Algorithm> AlgorithmList;
static AlgorithmList GetAlgorithmList( bool includeHidden = false );
typedef std::list<Algorithm> AlgorithmList;
static AlgorithmList GetAlgorithmList(bool includeHidden = false);
static shared_ptr<NameIO> New( const rel::Interface &iface,
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 shared_ptr<NameIO> New(const rel::Interface &iface,
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,
const rel::Interface &iface, Constructor constructor,
bool hidden = false);
static bool Register(const char *name, const char *description,
const rel::Interface &iface, Constructor constructor,
bool hidden = false);
NameIO();
virtual ~NameIO();
NameIO();
virtual ~NameIO();
virtual rel::Interface interface() const = 0;
virtual rel::Interface interface() const =0;
void setChainedNameIV(bool enable);
bool getChainedNameIV() const;
void setReverseEncryption(bool enable);
bool getReverseEncryption() const;
void setChainedNameIV( bool enable );
bool getChainedNameIV() const;
void setReverseEncryption( bool enable );
bool getReverseEncryption() const;
std::string encodePath(const char *plaintextPath) const;
std::string decodePath(const char *encodedPath) const;
std::string encodePath( const char *plaintextPath ) const;
std::string decodePath( const char *encodedPath ) const;
std::string encodePath(const char *plaintextPath, uint64_t *iv) const;
std::string decodePath(const char *encodedPath, uint64_t *iv) const;
std::string encodePath( const char *plaintextPath, uint64_t *iv ) const;
std::string decodePath( const char *encodedPath, uint64_t *iv ) const;
virtual int maxEncodedNameLen(int plaintextNameLen) const = 0;
virtual int maxDecodedNameLen(int encodedNameLen) const = 0;
virtual int maxEncodedNameLen( int plaintextNameLen ) const =0;
virtual int maxDecodedNameLen( int encodedNameLen ) const =0;
std::string encodeName(const char *plaintextName, int length) const;
std::string decodeName(const char *encodedName, int length) const;
std::string encodeName( const char *plaintextName, int length ) const;
std::string decodeName( const char *encodedName, int length ) const;
protected:
virtual int encodeName(const char *plaintextName, int length,
char *encodedName) const;
virtual int decodeName(const char *encodedName, int length,
char *plaintextName) const;
protected:
virtual int encodeName( const char *plaintextName, int length,
char *encodedName ) const;
virtual int decodeName( const char *encodedName, int length,
char *plaintextName ) const;
virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
char *encodedName) const = 0;
virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
char *plaintextName) const = 0;
virtual int encodeName( const char *plaintextName, int length,
uint64_t *iv, char *encodedName ) const =0;
virtual int decodeName( const char *encodedName, int length,
uint64_t *iv, char *plaintextName ) const =0;
private:
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;
private:
std::string recodePath( const char *path,
int (NameIO::*codingLen)(int) const,
int (NameIO::*codingFunc)(const char *, int,
uint64_t *, char *) const,
uint64_t *iv ) const;
std::string _encodePath( const char *plaintextPath, uint64_t *iv ) const;
std::string _decodePath( const char *encodedPath, uint64_t *iv ) const;
std::string _encodeName( const char *plaintextName, int length ) const;
std::string _decodeName( const char *encodedName, int length ) const;
bool chainedNameIV;
bool reverseEncryption;
bool chainedNameIV;
bool reverseEncryption;
};
/*
Helper macros for creating temporary buffers with an optimization that
below a given size (OptimizedSize) is allocated on the stack, and when a
@ -117,22 +112,18 @@ private:
BUFFER_RESET should be called for the same name as BUFFER_INIT
*/
#define BUFFER_INIT( Name, OptimizedSize, Size ) \
char Name ## _Raw [ OptimizedSize ]; \
char *Name = Name ## _Raw; \
if( sizeof(Name ## _Raw) < Size ) \
Name = new char[ Size ];\
memset( Name, 0, Size );
#define BUFFER_RESET( Name ) \
do { \
if( Name != Name ## _Raw ) \
{ \
delete[] Name; \
Name = Name ## _Raw; \
} \
} while(0);
#define BUFFER_INIT(Name, OptimizedSize, Size) \
char Name##_Raw[OptimizedSize]; \
char *Name = Name##_Raw; \
if (sizeof(Name##_Raw) < Size) Name = new char[Size]; \
memset(Name, 0, Size);
#define BUFFER_RESET(Name) \
do { \
if (Name != Name##_Raw) { \
delete[] Name; \
Name = Name##_Raw; \
} \
} while (0);
#endif

View File

@ -18,7 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "NullCipher.h"
#include <cstring>
@ -32,153 +31,109 @@ using namespace std;
using namespace rel;
using namespace rlog;
static Interface NullInterface( "nullCipher", 1, 0, 0 );
static Interface NullInterface("nullCipher", 1, 0, 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)
{
(void)keyLen;
return shared_ptr<Cipher>( new NullCipher( iface ) );
static shared_ptr<Cipher> NewNullCipher(const Interface &iface, int keyLen) {
(void)keyLen;
return shared_ptr<Cipher>(new NullCipher(iface));
}
const bool HiddenCipher = true;
static bool NullCipher_registered = Cipher::Register("Null",
"Non encrypting cipher. For testing only!",
NullInterface, NullKeyRange, NullBlockRange, NewNullCipher,
HiddenCipher);
static bool NullCipher_registered = Cipher::Register(
"Null", "Non encrypting cipher. For testing only!", NullInterface,
NullKeyRange, NullBlockRange, NewNullCipher, HiddenCipher);
class NullKey : public AbstractCipherKey
{
public:
NullKey() {}
virtual ~NullKey() {}
class NullKey : public AbstractCipherKey {
public:
NullKey() {}
virtual ~NullKey() {}
};
class NullDestructor
{
public:
NullDestructor() {}
NullDestructor(const NullDestructor &) {}
~NullDestructor() {}
class NullDestructor {
public:
NullDestructor() {}
NullDestructor(const NullDestructor &) {}
~NullDestructor() {}
NullDestructor &operator = (const NullDestructor &){ return *this; }
void operator ()(NullKey *&) {}
NullDestructor &operator=(const NullDestructor &) { return *this; }
void operator()(NullKey *&) {}
};
shared_ptr<AbstractCipherKey> gNullKey( new NullKey(), NullDestructor() );
shared_ptr<AbstractCipherKey> gNullKey(new NullKey(), NullDestructor());
NullCipher::NullCipher(const Interface &iface_)
{
this->iface = iface_;
NullCipher::NullCipher(const Interface &iface_) { this->iface = iface_; }
NullCipher::~NullCipher() {}
Interface NullCipher::interface() const { return iface; }
CipherKey NullCipher::newKey(const char *, int, int &, long,
const 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
{
return iface;
uint64_t NullCipher::MAC_64(const unsigned char *, int, const CipherKey &,
uint64_t *) const {
return 0;
}
CipherKey NullCipher::newKey(const char *, int,
int &, long, const unsigned char *, int )
{
return gNullKey;
}
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;
}
uint64_t NullCipher::MAC_64(const unsigned char *, int ,
const CipherKey &, uint64_t *) const
{
return 0;
}
CipherKey NullCipher::readKey( const unsigned char *,
const CipherKey &, bool)
{
return gNullKey;
CipherKey NullCipher::readKey(const unsigned char *, const CipherKey &, bool) {
return gNullKey;
}
void NullCipher::writeKey(const CipherKey &, unsigned char *,
const CipherKey &)
{
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();
}
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;
}
int NullCipher::encodedKeySize() const
{
return 0;
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;
}
int NullCipher::keySize() const
{
return 0;
bool NullCipher::blockEncode(unsigned char *, int, uint64_t,
const CipherKey &) const {
return true;
}
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::blockDecode(unsigned char *, int, uint64_t,
const CipherKey &) const {
return true;
}
bool NullCipher::Enabled() { return true; }

View File

@ -28,59 +28,53 @@
Implements Cipher interface for a pass-through mode. May be useful for
testing, but that's it.
*/
class NullCipher : public Cipher
{
rel::Interface iface;
class NullCipher : public Cipher {
rel::Interface iface;
public:
NullCipher(const rel::Interface &iface);
virtual ~NullCipher();
public:
NullCipher(const rel::Interface &iface);
virtual ~NullCipher();
virtual rel::Interface interface() const;
virtual rel::Interface interface() const;
// create a new key based on a password
virtual CipherKey newKey(const char *password, int passwdLength,
int &iterationCount, long desiredDuration,
const unsigned char *salt, int saltLen);
virtual CipherKey newKey(const char *password, int passwdLength);
// create a new random key
virtual CipherKey newRandomKey();
// create a new key based on a password
virtual CipherKey newKey(const char *password, int passwdLength,
int &iterationCount, long desiredDuration,
const unsigned char *salt, int saltLen);
virtual CipherKey newKey(const char *password, int passwdLength);
// create a new random key
virtual CipherKey newRandomKey();
// data must be len keySize()
virtual CipherKey readKey(const unsigned char *data,
const CipherKey &encodingKey,
bool checkKey);
virtual void writeKey(const CipherKey &key, unsigned char *data,
const CipherKey &encodingKey);
virtual bool compareKey( const CipherKey &A,
const CipherKey &B ) const;
// data must be len keySize()
virtual CipherKey readKey(const unsigned char *data,
const CipherKey &encodingKey, bool checkKey);
virtual void writeKey(const CipherKey &key, unsigned char *data,
const CipherKey &encodingKey);
virtual bool compareKey(const CipherKey &A, const CipherKey &B) const;
// meta-data about the cypher
virtual int keySize() const;
virtual int encodedKeySize() const;
virtual int cipherBlockSize() const;
// meta-data about the cypher
virtual int keySize() const;
virtual int encodedKeySize() const;
virtual int cipherBlockSize() const;
virtual bool randomize( unsigned char *buf, int len,
bool strongRandom ) const;
virtual bool randomize(unsigned char *buf, int len, bool strongRandom) const;
virtual uint64_t MAC_64(const unsigned char *data, int len,
const CipherKey &key, uint64_t *chainedIV) const;
virtual uint64_t MAC_64(const unsigned char *data, int len,
const CipherKey &key, uint64_t *chainedIV) const;
// functional interfaces
virtual bool streamEncode(unsigned char *in, int len,
uint64_t iv64, const CipherKey &key) const;
virtual bool streamDecode(unsigned char *in, int len,
uint64_t iv64, const CipherKey &key) const;
// functional interfaces
virtual bool streamEncode(unsigned char *in, int len, uint64_t iv64,
const CipherKey &key) const;
virtual bool streamDecode(unsigned char *in, int len, uint64_t iv64,
const CipherKey &key) const;
virtual bool blockEncode(unsigned char *buf, int size,
uint64_t iv64, const CipherKey &key) const;
virtual bool blockDecode(unsigned char *buf, int size,
uint64_t iv64, const CipherKey &key) const;
virtual bool blockEncode(unsigned char *buf, int size, uint64_t iv64,
const CipherKey &key) const;
virtual bool blockDecode(unsigned char *buf, int size, uint64_t iv64,
const CipherKey &key) const;
// hack to help with static builds
static bool Enabled();
// hack to help with static builds
static bool Enabled();
};
#endif

View File

@ -27,66 +27,45 @@
using namespace rel;
static shared_ptr<NameIO> NewNNIO( const Interface &,
const shared_ptr<Cipher> &, const CipherKey & )
{
return shared_ptr<NameIO>( new NullNameIO() );
static shared_ptr<NameIO> NewNNIO(const Interface &, const shared_ptr<Cipher> &,
const CipherKey &) {
return shared_ptr<NameIO>(new NullNameIO());
}
static Interface NNIOIface("nameio/null", 1, 0, 0);
static bool NullNameIO_registered = NameIO::Register("Null",
"No encryption of filenames", NNIOIface, NewNNIO);
static bool NullNameIO_registered =
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
{
return NNIOIface;
int NullNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv,
char *encodedName) const {
(void)iv;
memcpy(encodedName, plaintextName, length);
return length;
}
Interface NullNameIO::CurrentInterface()
{
return NNIOIface;
}
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;
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; }

View File

@ -23,30 +23,29 @@
#include "NameIO.h"
class NullNameIO : public NameIO
{
public:
static rel::Interface CurrentInterface();
class NullNameIO : public NameIO {
public:
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 maxDecodedNameLen( int encodedNameLen ) const;
virtual int maxEncodedNameLen(int plaintextNameLen) const;
virtual int maxDecodedNameLen(int encodedNameLen) const;
// hack to help with static builds
static bool Enabled();
protected:
virtual int encodeName( const char *plaintextName, int length,
uint64_t *iv, char *encodedName ) const;
virtual int decodeName( const char *encodedName, int length,
uint64_t *iv, char *plaintextName ) const;
private:
// hack to help with static builds
static bool Enabled();
protected:
virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
char *encodedName) const;
virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
char *plaintextName) const;
private:
};
#endif

View File

@ -21,93 +21,69 @@
#ifndef _Range_incl_
#define _Range_incl_
class Range {
int minVal;
int maxVal;
int increment;
class Range
{
int minVal;
int maxVal;
int increment;
public:
Range();
Range(int minMax);
Range(int min, int max, 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 max() const;
int inc() const;
int min() const;
int max() const;
int inc() const;
};
inline Range::Range(int minMax)
{
this->minVal = minMax;
this->maxVal = minMax;
this->increment = 1;
inline Range::Range(int minMax) {
this->minVal = minMax;
this->maxVal = minMax;
this->increment = 1;
}
inline Range::Range(int min_, int max_, int increment_)
{
this->minVal = min_;
this->maxVal = max_;
this->increment = increment_;
if(increment == 0)
this->increment = 1;
inline Range::Range(int min_, int max_, int increment_) {
this->minVal = min_;
this->maxVal = max_;
this->increment = increment_;
if (increment == 0) this->increment = 1;
}
inline Range::Range()
: minVal(-1)
, maxVal(-1)
, increment(1)
{
}
inline Range::Range() : minVal(-1), maxVal(-1), increment(1) {}
inline bool Range::allowed(int value) const
{
if(value >= minVal && value <= maxVal)
{
int tmp = value - minVal;
if((tmp % increment) == 0)
return true;
}
return false;
}
inline int Range::closest(int value) const
{
if(allowed(value))
return value;
else
if(value < minVal)
return minVal;
else
if(value > maxVal)
return maxVal;
// must be inbetween but not matched with increment
inline bool Range::allowed(int value) const {
if (value >= minVal && value <= maxVal) {
int tmp = value - minVal;
// try rounding to the nearest increment..
tmp += (increment >> 1);
tmp -= (tmp % increment);
return closest( value + tmp );
if ((tmp % increment) == 0) return true;
}
return false;
}
inline int Range::min() const
{
inline int Range::closest(int value) const {
if (allowed(value))
return value;
else if (value < minVal)
return minVal;
}
inline int Range::max() const
{
else if (value > maxVal)
return maxVal;
// must be inbetween but not matched with increment
int tmp = value - minVal;
// try rounding to the nearest increment..
tmp += (increment >> 1);
tmp -= (tmp % increment);
return closest(value + tmp);
}
inline int Range::inc() const
{
return increment;
}
inline int Range::min() const { return minVal; }
inline int Range::max() const { return maxVal; }
inline int Range::inc() const { return increment; }
#endif

View File

@ -19,7 +19,7 @@
*/
#ifdef linux
#define _XOPEN_SOURCE 500 // pick up pread , pwrite
#define _XOPEN_SOURCE 500 // pick up pread , pwrite
#endif
#include <unistd.h>
@ -38,57 +38,41 @@ using namespace std;
static rel::Interface RawFileIO_iface("FileIO/Raw", 1, 0, 0);
FileIO *NewRawFileIO( const rel::Interface &iface )
{
(void)iface;
return new RawFileIO();
FileIO *NewRawFileIO(const rel::Interface &iface) {
(void)iface;
return new RawFileIO();
}
inline void swap( int &x, int &y )
{
int tmp = x;
x = y;
y = tmp;
inline void swap(int &x, int &y) {
int tmp = x;
x = y;
y = tmp;
}
RawFileIO::RawFileIO( )
: knownSize( false )
, fileSize(0)
, fd( -1 )
, oldfd( -1 )
, canWrite( false )
{
RawFileIO::RawFileIO()
: knownSize(false), fileSize(0), fd(-1), oldfd(-1), canWrite(false) {}
RawFileIO::RawFileIO(const std::string &fileName)
: name(fileName),
knownSize(false),
fileSize(0),
fd(-1),
oldfd(-1),
canWrite(false) {}
RawFileIO::~RawFileIO() {
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 )
: 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;
}
rel::Interface RawFileIO::interface() const { return RawFileIO_iface; }
/*
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
with calls to lstat picking up the wrong permissions.
*/
static int open_readonly_workaround(const char *path, int flags)
{
int fd = -1;
struct stat stbuf;
memset(&stbuf, 0, sizeof(struct stat));
if(lstat( path, &stbuf ) != -1)
{
// make sure user has read/write permission..
chmod( path , stbuf.st_mode | 0600 );
fd = ::open( path , flags );
chmod( path , stbuf.st_mode );
} else
{
rInfo("can't stat file %s", path );
}
static int open_readonly_workaround(const char *path, int flags) {
int fd = -1;
struct stat stbuf;
memset(&stbuf, 0, sizeof(struct stat));
if (lstat(path, &stbuf) != -1) {
// make sure user has read/write permission..
chmod(path, stbuf.st_mode | 0600);
fd = ::open(path, flags);
chmod(path, stbuf.st_mode);
} else {
rInfo("can't stat file %s", path);
}
return fd;
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
it..
*/
int RawFileIO::open(int flags)
{
bool requestWrite = ((flags & O_RDWR) || (flags & O_WRONLY));
int RawFileIO::open(int flags) {
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((fd >= 0) && (canWrite || !requestWrite))
{
rDebug("using existing file descriptor");
result = fd; // success
} else
{
int finalFlags = requestWrite ? O_RDWR : O_RDONLY;
// if we have a descriptor and it is writable, or we don't need writable..
if ((fd >= 0) && (canWrite || !requestWrite)) {
rDebug("using existing file descriptor");
result = fd; // success
} else {
int finalFlags = requestWrite ? O_RDWR : O_RDONLY;
#if defined(O_LARGEFILE)
if( flags & O_LARGEFILE )
finalFlags |= O_LARGEFILE;
if (flags & O_LARGEFILE) finalFlags |= O_LARGEFILE;
#else
#warning O_LARGEFILE not supported
#endif
int newFd = ::open( name.c_str(), finalFlags );
int newFd = ::open(name.c_str(), finalFlags);
rDebug("open file with flags %i, result = %i", finalFlags, newFd);
rDebug("open file with flags %i, result = %i", finalFlags, newFd);
if((newFd == -1) && (errno == EACCES))
{
rDebug("using readonly workaround for open");
newFd = open_readonly_workaround( name.c_str(), finalFlags );
}
if(newFd >= 0)
{
if(oldfd >= 0)
{
rError("leaking FD?: oldfd = %i, fd = %i, newfd = %i",
oldfd, fd, newFd);
}
// the old fd might still be in use, so just keep it around for
// now.
canWrite = requestWrite;
oldfd = fd;
result = fd = newFd;
} else
{
result = -errno;
rInfo("::open error: %s", strerror(errno));
}
if ((newFd == -1) && (errno == EACCES)) {
rDebug("using readonly workaround for open");
newFd = open_readonly_workaround(name.c_str(), finalFlags);
}
if(result < 0)
rInfo("file %s open failure: %i", name.c_str(), -result);
if (newFd >= 0) {
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 res = lstat( name.c_str(), stbuf );
int eno = errno;
int RawFileIO::getAttr(struct stat *stbuf) const {
int res = lstat(name.c_str(), stbuf);
int eno = errno;
if(res < 0)
rInfo("getAttr error on %s: %s", name.c_str(), strerror( eno ));
if (res < 0) 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 )
{
name = fileName;
}
void RawFileIO::setFileName(const char *fileName) { name = fileName; }
const char *RawFileIO::getFileName() const
{
return name.c_str();
}
const char *RawFileIO::getFileName() const { return name.c_str(); }
off_t RawFileIO::getSize() const
{
if(!knownSize)
{
struct stat stbuf;
memset( &stbuf, 0, sizeof( struct stat ));
int res = lstat( name.c_str(), &stbuf );
off_t RawFileIO::getSize() const {
if (!knownSize) {
struct stat stbuf;
memset(&stbuf, 0, sizeof(struct stat));
int res = lstat(name.c_str(), &stbuf);
if(res == 0)
{
const_cast<RawFileIO*>(this)->fileSize = stbuf.st_size;
const_cast<RawFileIO*>(this)->knownSize = true;
return fileSize;
} else
return -1;
if (res == 0) {
const_cast<RawFileIO *>(this)->fileSize = stbuf.st_size;
const_cast<RawFileIO *>(this)->knownSize = true;
return fileSize;
} else
{
return fileSize;
}
return -1;
} else {
return fileSize;
}
}
ssize_t RawFileIO::read( const IORequest &req ) const
{
rAssert( fd >= 0 );
ssize_t RawFileIO::read(const IORequest &req) const {
rAssert(fd >= 0);
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)
{
rInfo("read failed at offset %" PRIi64 " for %i bytes: %s",
req.offset, req.dataLen, strerror( errno ));
}
if (readSize < 0) {
rInfo("read failed at offset %" PRIi64 " for %i bytes: %s", req.offset,
req.dataLen, strerror(errno));
}
return readSize;
return readSize;
}
bool RawFileIO::write( const IORequest &req )
{
rAssert( fd >= 0 );
rAssert( true == canWrite );
bool RawFileIO::write(const IORequest &req) {
rAssert(fd >= 0);
rAssert(true == canWrite);
int retrys = 10;
void *buf = req.data;
ssize_t bytes = req.dataLen;
off_t offset = req.offset;
int retrys = 10;
void *buf = req.data;
ssize_t bytes = req.dataLen;
off_t offset = req.offset;
while( bytes && retrys > 0 )
{
ssize_t writeSize = ::pwrite( fd, buf, bytes, offset );
while (bytes && retrys > 0) {
ssize_t writeSize = ::pwrite(fd, buf, bytes, offset);
if( writeSize < 0 )
{
knownSize = false;
rInfo("write failed at offset %" PRIi64 " for %i bytes: %s",
offset, (int)bytes, strerror( errno ));
return false;
}
bytes -= writeSize;
offset += writeSize;
buf = (void*)((char*)buf + writeSize);
--retrys;
if (writeSize < 0) {
knownSize = false;
rInfo("write failed at offset %" PRIi64 " for %i bytes: %s", offset,
(int)bytes, strerror(errno));
return false;
}
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;
}
bytes -= writeSize;
offset += writeSize;
buf = (void *)((char *)buf + writeSize);
--retrys;
}
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 res;
int RawFileIO::truncate(off_t size) {
int res;
if(fd >= 0 && canWrite)
{
res = ::ftruncate( fd, size );
if (fd >= 0 && canWrite) {
res = ::ftruncate(fd, size);
#if !defined(__FreeBSD__) && !defined(__APPLE__)
::fdatasync( fd );
::fdatasync(fd);
#endif
} else
res = ::truncate( name.c_str(), size );
} else
res = ::truncate(name.c_str(), size);
if(res < 0)
{
int eno = errno;
rInfo("truncate failed for %s (%i) size %" PRIi64 ", error %s",
name.c_str(), fd, size, strerror(eno));
res = -eno;
knownSize = false;
} else
{
res = 0;
fileSize = size;
knownSize = true;
}
if (res < 0) {
int eno = errno;
rInfo("truncate failed for %s (%i) size %" PRIi64 ", error %s",
name.c_str(), fd, size, strerror(eno));
res = -eno;
knownSize = false;
} else {
res = 0;
fileSize = size;
knownSize = true;
}
return res;
return res;
}
bool RawFileIO::isWritable() const
{
return canWrite;
}
bool RawFileIO::isWritable() const { return canWrite; }

View File

@ -25,40 +25,38 @@
#include <string>
class RawFileIO : public FileIO
{
public:
RawFileIO();
RawFileIO( const std::string &fileName );
virtual ~RawFileIO();
class RawFileIO : public FileIO {
public:
RawFileIO();
RawFileIO(const std::string &fileName);
virtual ~RawFileIO();
virtual rel::Interface interface() const;
virtual rel::Interface interface() const;
virtual void setFileName( const char *fileName );
virtual const char *getFileName() const;
virtual void setFileName(const char *fileName);
virtual const char *getFileName() const;
virtual int open( int flags );
virtual int open(int flags);
virtual int getAttr( struct stat *stbuf ) const;
virtual off_t getSize() const;
virtual int getAttr(struct stat *stbuf) const;
virtual off_t getSize() const;
virtual ssize_t read( const IORequest & req ) const;
virtual bool write( const IORequest &req );
virtual ssize_t read(const IORequest &req) const;
virtual bool write(const IORequest &req);
virtual int truncate( off_t size );
virtual int truncate(off_t size);
virtual bool isWritable() const;
protected:
virtual bool isWritable() const;
std::string name;
protected:
std::string name;
bool knownSize;
off_t fileSize;
bool knownSize;
off_t fileSize;
int fd;
int oldfd;
bool canWrite;
int fd;
int oldfd;
bool canWrite;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -55,9 +55,9 @@ typedef struct evp_cipher_st EVP_CIPHER;
as:
1. shuffle
2. encrypt
3. reverse
4. shuffle
5. encrypt
3. reverse
4. shuffle
5. encrypt
The reason for the shuffle and reverse steps (and the second encrypt pass)
is to try and propogate any changed bits to a larger set. If only a single
pass was made with the stream cipher in CFB mode, then a change to one byte
@ -68,83 +68,78 @@ typedef struct evp_cipher_st EVP_CIPHER;
initial value vector to randomize the output. But it makes the code
simpler to reuse the encryption algorithm as is.
*/
class SSL_Cipher : public Cipher
{
rel::Interface iface;
rel::Interface realIface;
const EVP_CIPHER *_blockCipher;
const EVP_CIPHER *_streamCipher;
unsigned int _keySize; // in bytes
unsigned int _ivLength;
class SSL_Cipher : public Cipher {
rel::Interface iface;
rel::Interface realIface;
const EVP_CIPHER *_blockCipher;
const EVP_CIPHER *_streamCipher;
unsigned int _keySize; // in bytes
unsigned int _ivLength;
public:
SSL_Cipher(const rel::Interface &iface, const rel::Interface &realIface,
const EVP_CIPHER *blockCipher, const EVP_CIPHER *streamCipher,
int keyLength);
virtual ~SSL_Cipher();
public:
SSL_Cipher(const rel::Interface &iface, const rel::Interface &realIface,
const EVP_CIPHER *blockCipher, const EVP_CIPHER *streamCipher,
int keyLength);
virtual ~SSL_Cipher();
// returns the real interface, not the one we're emulating (if any)..
virtual rel::Interface interface() const;
// returns the real interface, not the one we're emulating (if any)..
virtual rel::Interface interface() const;
// create a new key based on a password
virtual CipherKey newKey(const char *password, int passwdLength,
int &iterationCount, long desiredDuration,
const unsigned char *salt, int saltLen);
// deprecated - for backward compatibility
virtual CipherKey newKey(const char *password, int passwdLength);
// create a new random key
virtual CipherKey newRandomKey();
// create a new key based on a password
virtual CipherKey newKey(const char *password, int passwdLength,
int &iterationCount, long desiredDuration,
const unsigned char *salt, int saltLen);
// deprecated - for backward compatibility
virtual CipherKey newKey(const char *password, int passwdLength);
// create a new random key
virtual CipherKey newRandomKey();
// data must be len keySize()
virtual CipherKey readKey(const unsigned char *data,
const CipherKey &encodingKey,
bool checkKey);
virtual void writeKey(const CipherKey &key, unsigned char *data,
const CipherKey &encodingKey);
virtual bool compareKey( const CipherKey &A,
const CipherKey &B ) const;
// data must be len keySize()
virtual CipherKey readKey(const unsigned char *data,
const CipherKey &encodingKey, bool checkKey);
virtual void writeKey(const CipherKey &key, unsigned char *data,
const CipherKey &encodingKey);
virtual bool compareKey(const CipherKey &A, const CipherKey &B) const;
// meta-data about the cypher
virtual int keySize() const;
virtual int encodedKeySize() const;
virtual int cipherBlockSize() const;
// meta-data about the cypher
virtual int keySize() const;
virtual int encodedKeySize() const;
virtual int cipherBlockSize() const;
virtual bool randomize( unsigned char *buf, int len,
bool strongRandom ) const;
virtual bool randomize(unsigned char *buf, int len, bool strongRandom) const;
virtual uint64_t MAC_64( const unsigned char *src, int len,
const CipherKey &key, uint64_t *augment ) const;
virtual uint64_t MAC_64(const unsigned char *src, int len,
const CipherKey &key, uint64_t *augment) const;
// functional interfaces
/*
Stream encoding in-place.
*/
virtual bool streamEncode(unsigned char *in, int len,
uint64_t iv64, const CipherKey &key) const;
virtual bool streamDecode(unsigned char *in, int len,
uint64_t iv64, const CipherKey &key) const;
// functional interfaces
/*
Stream encoding in-place.
*/
virtual bool streamEncode(unsigned char *in, int len, uint64_t iv64,
const CipherKey &key) const;
virtual bool streamDecode(unsigned char *in, int len, uint64_t iv64,
const CipherKey &key) const;
/*
Block encoding is done in-place. Partial blocks are supported, but
blocks are always expected to begin on a block boundary. See
blockSize().
*/
virtual bool blockEncode(unsigned char *buf, int size,
uint64_t iv64, const CipherKey &key) const;
virtual bool blockDecode(unsigned char *buf, int size,
uint64_t iv64, const CipherKey &key) const;
/*
Block encoding is done in-place. Partial blocks are supported, but
blocks are always expected to begin on a block boundary. See
blockSize().
*/
virtual bool blockEncode(unsigned char *buf, int size, uint64_t iv64,
const CipherKey &key) const;
virtual bool blockDecode(unsigned char *buf, int size, uint64_t iv64,
const CipherKey &key) const;
// hack to help with static builds
static bool Enabled();
private:
void setIVec( unsigned char *ivec, uint64_t seed,
const shared_ptr<SSLKey> &key ) const;
// hack to help with static builds
static bool Enabled();
// deprecated - for backward compatibility
void setIVec_old( unsigned char *ivec, unsigned int seed,
const shared_ptr<SSLKey> &key ) const;
private:
void setIVec(unsigned char *ivec, uint64_t seed,
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

View File

@ -32,17 +32,16 @@
using namespace rel;
using namespace std;
static shared_ptr<NameIO> NewStreamNameIO( const Interface &iface,
const shared_ptr<Cipher> &cipher, const CipherKey &key)
{
return shared_ptr<NameIO>( new StreamNameIO( iface, cipher, key ) );
static shared_ptr<NameIO> NewStreamNameIO(const Interface &iface,
const shared_ptr<Cipher> &cipher,
const CipherKey &key) {
return shared_ptr<NameIO>(new StreamNameIO(iface, cipher, key));
}
static bool StreamIO_registered = NameIO::Register("Stream",
gettext_noop("Stream encoding, keeps filenames as short as possible"),
StreamNameIO::CurrentInterface(),
NewStreamNameIO);
static bool StreamIO_registered = NameIO::Register(
"Stream",
gettext_noop("Stream encoding, keeps filenames as short as possible"),
StreamNameIO::CurrentInterface(), NewStreamNameIO);
/*
- Version 0.1 is for EncFS 0.x support. The difference to 1.0 is that 0.x
@ -65,145 +64,117 @@ static bool StreamIO_registered = NameIO::Register("Stream",
- Version 2.1 adds support for version 0 for EncFS 0.x compatibility.
*/
Interface StreamNameIO::CurrentInterface()
{
// implement major version 2, 1, and 0
return Interface("nameio/stream", 2, 1, 2);
Interface StreamNameIO::CurrentInterface() {
// implement major version 2, 1, and 0
return Interface("nameio/stream", 2, 1, 2);
}
StreamNameIO::StreamNameIO( const rel::Interface &iface,
const shared_ptr<Cipher> &cipher,
const CipherKey &key )
: _interface( iface.current() )
, _cipher( cipher )
, _key( key )
{
StreamNameIO::StreamNameIO(const rel::Interface &iface,
const shared_ptr<Cipher> &cipher,
const CipherKey &key)
: _interface(iface.current()), _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
{
return CurrentInterface();
int StreamNameIO::encodeName(const char *plaintextName, int length,
uint64_t *iv, char *encodedName) const {
uint64_t tmpIV = 0;
if (iv && _interface >= 2) tmpIV = *iv;
unsigned int mac =
_cipher->MAC_16((const unsigned char *)plaintextName, length, _key, iv);
// add on checksum bytes
unsigned char *encodeBegin;
if (_interface >= 1) {
// current versions store the checksum at the beginning
encodedName[0] = (mac >> 8) & 0xff;
encodedName[1] = (mac) & 0xff;
encodeBegin = (unsigned char *)encodedName + 2;
} else {
// encfs 0.x stored checksums at the end.
encodedName[length] = (mac >> 8) & 0xff;
encodedName[length + 1] = (mac) & 0xff;
encodeBegin = (unsigned char *)encodedName;
}
// stream encode the plaintext bytes
memcpy(encodeBegin, plaintextName, length);
_cipher->nameEncode(encodeBegin, length, (uint64_t)mac ^ tmpIV, _key);
// convert the entire thing to base 64 ascii..
int encodedStreamLen = length + 2;
int encLen64 = B256ToB64Bytes(encodedStreamLen);
changeBase2Inline((unsigned char *)encodedName, encodedStreamLen, 8, 6, true);
B64ToAscii((unsigned char *)encodedName, encLen64);
return encLen64;
}
int StreamNameIO::maxEncodedNameLen( int plaintextStreamLen ) const
{
int encodedStreamLen = 2 + plaintextStreamLen;
return B256ToB64Bytes( encodedStreamLen );
}
int StreamNameIO::maxDecodedNameLen( int encodedStreamLen ) const
{
int decLen256 = B64ToB256Bytes( encodedStreamLen );
return decLen256 - 2;
}
int StreamNameIO::encodeName( const char *plaintextName, int length,
uint64_t *iv, char *encodedName ) const
{
uint64_t tmpIV = 0;
if( iv && _interface >= 2 )
tmpIV = *iv;
unsigned int mac = _cipher->MAC_16( (const unsigned char *)plaintextName,
length, _key, iv );
// add on checksum bytes
unsigned char *encodeBegin;
if(_interface >= 1)
{
// current versions store the checksum at the beginning
encodedName[0] = (mac >> 8) & 0xff;
encodedName[1] = (mac ) & 0xff;
encodeBegin = (unsigned char *)encodedName+2;
} else
{
// encfs 0.x stored checksums at the end.
encodedName[length] = (mac >> 8) & 0xff;
encodedName[length+1] = (mac ) & 0xff;
encodeBegin = (unsigned char *)encodedName;
}
// stream encode the plaintext bytes
memcpy( encodeBegin, plaintextName, length );
_cipher->nameEncode( encodeBegin, length, (uint64_t)mac ^ tmpIV, _key);
// convert the entire thing to base 64 ascii..
int encodedStreamLen = length + 2;
int encLen64 = B256ToB64Bytes( encodedStreamLen );
changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen,
8, 6, true );
B64ToAscii( (unsigned char *)encodedName, encLen64 );
return encLen64;
}
int StreamNameIO::decodeName( const char *encodedName, int length,
uint64_t *iv, char *plaintextName ) const
{
rAssert(length > 2);
int decLen256 = B64ToB256Bytes( length );
int decodedStreamLen = decLen256 - 2;
if(decodedStreamLen <= 0)
throw ERROR("Filename too small to decode");
BUFFER_INIT( tmpBuf, 32, (unsigned int)length );
// decode into tmpBuf, because this step produces more data then we can fit
// into the result buffer..
AsciiToB64( (unsigned char *)tmpBuf, (unsigned char *)encodedName, length );
changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false);
// pull out the checksum value which is used as an initialization vector
uint64_t tmpIV = 0;
unsigned int mac;
if(_interface >= 1)
{
// current versions store the checksum at the beginning
mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8
| ((unsigned int)((unsigned char)tmpBuf[1]));
// version 2 adds support for IV chaining..
if( iv && _interface >= 2 )
tmpIV = *iv;
memcpy( plaintextName, tmpBuf+2, decodedStreamLen );
} else
{
// encfs 0.x stored checksums at the end.
mac = ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen])) << 8
| ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen+1]));
memcpy( plaintextName, tmpBuf, decodedStreamLen );
}
// use nameDeocde instead of streamDecode for backward compatibility
_cipher->nameDecode( (unsigned char *)plaintextName, decodedStreamLen,
(uint64_t)mac ^ tmpIV, _key);
// compute MAC to check with stored value
unsigned int mac2 = _cipher->MAC_16((const unsigned char *)plaintextName,
decodedStreamLen, _key, iv);
BUFFER_RESET( tmpBuf );
if(mac2 != mac)
{
rDebug("checksum mismatch: expected %u, got %u", mac, mac2);
rDebug("on decode of %i bytes", decodedStreamLen);
throw ERROR( "checksum mismatch in filename decode" );
}
return decodedStreamLen;
}
bool StreamNameIO::Enabled()
{
return true;
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; }

View File

@ -26,34 +26,32 @@
class Cipher;
class StreamNameIO : public NameIO
{
public:
static rel::Interface CurrentInterface();
class StreamNameIO : public NameIO {
public:
static rel::Interface CurrentInterface();
StreamNameIO( const rel::Interface &iface,
const shared_ptr<Cipher> &cipher,
const CipherKey &key );
virtual ~StreamNameIO();
StreamNameIO(const rel::Interface &iface, const shared_ptr<Cipher> &cipher,
const CipherKey &key);
virtual ~StreamNameIO();
virtual rel::Interface interface() const;
virtual rel::Interface interface() const;
virtual int maxEncodedNameLen( int plaintextNameLen ) const;
virtual int maxDecodedNameLen( int encodedNameLen ) const;
virtual int maxEncodedNameLen(int plaintextNameLen) const;
virtual int maxDecodedNameLen(int encodedNameLen) const;
// hack to help with static builds
static bool Enabled();
protected:
virtual int encodeName( const char *plaintextName, int length,
uint64_t *iv, char *encodedName ) const;
virtual int decodeName( const char *encodedName, int length,
uint64_t *iv, char *plaintextName ) const;
private:
int _interface;
shared_ptr<Cipher> _cipher;
CipherKey _key;
// hack to help with static builds
static bool Enabled();
protected:
virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
char *encodedName) const;
virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
char *plaintextName) const;
private:
int _interface;
shared_ptr<Cipher> _cipher;
CipherKey _key;
};
#endif

View File

@ -27,32 +27,28 @@
// It is the caller's responsibility to make sure the output array is large
// enough.
void changeBase2(unsigned char *src, int srcLen, int src2Pow,
unsigned char *dst, int dstLen, int dst2Pow)
{
unsigned long work = 0;
int workBits = 0; // number of bits left in the work buffer
unsigned char *end = src + srcLen;
unsigned char *origDst = dst;
const int mask = (1 << dst2Pow) -1;
unsigned char *dst, int dstLen, int dst2Pow) {
unsigned long work = 0;
int workBits = 0; // number of bits left in the work buffer
unsigned char *end = src + srcLen;
unsigned char *origDst = dst;
const int mask = (1 << dst2Pow) - 1;
// copy the new bits onto the high bits of the stream.
// The bits that fall off the low end are the output bits.
while(src != end)
{
work |= ((unsigned long)(*src++)) << workBits;
workBits += src2Pow;
// copy the new bits onto the high bits of the stream.
// The bits that fall off the low end are the output bits.
while (src != end) {
work |= ((unsigned long)(*src++)) << workBits;
workBits += src2Pow;
while(workBits >= dst2Pow)
{
*dst++ = work & mask;
work >>= dst2Pow;
workBits -= dst2Pow;
}
while (workBits >= dst2Pow) {
*dst++ = work & mask;
work >>= dst2Pow;
workBits -= dst2Pow;
}
}
// now, we could have a partial value left in the work buffer..
if(workBits && ((dst - origDst) < dstLen))
*dst++ = work & mask;
// now, we could have a partial value left in the work buffer..
if (workBits && ((dst - origDst) < dstLen)) *dst++ = work & mask;
}
/*
@ -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
to be written, then write the value at the tail end of the recursion.
*/
static
void changeBase2Inline(unsigned char *src, int srcLen,
int src2Pow, int dst2Pow,
bool outputPartialLastByte,
unsigned long work,
int workBits,
unsigned char *outLoc)
{
const int mask = (1 << dst2Pow) -1;
if(!outLoc)
outLoc = src;
static void changeBase2Inline(unsigned char *src, int srcLen, int src2Pow,
int dst2Pow, bool outputPartialLastByte,
unsigned long work, int workBits,
unsigned char *outLoc) {
const int mask = (1 << dst2Pow) - 1;
if (!outLoc) outLoc = src;
// copy the new bits onto the high bits of the stream.
// The bits that fall off the low end are the output bits.
while(srcLen && workBits < dst2Pow)
{
work |= ((unsigned long)(*src++)) << workBits;
workBits += src2Pow;
--srcLen;
}
// we have at least one value that can be output
unsigned char outVal = work & mask;
work >>= dst2Pow;
workBits -= dst2Pow;
if(srcLen)
{
// more input left, so recurse
changeBase2Inline( src, srcLen, src2Pow, dst2Pow,
outputPartialLastByte, work, workBits, outLoc+1);
*outLoc = outVal;
} else
{
// no input left, we can write remaining values directly
*outLoc++ = outVal;
// we could have a partial value left in the work buffer..
if(outputPartialLastByte)
{
while(workBits > 0)
{
*outLoc++ = work & mask;
work >>= dst2Pow;
workBits -= dst2Pow;
}
}
// copy the new bits onto the high bits of the stream.
// The bits that fall off the low end are the output bits.
while (srcLen && workBits < dst2Pow) {
work |= ((unsigned long)(*src++)) << workBits;
workBits += src2Pow;
--srcLen;
}
// we have at least one value that can be output
unsigned char outVal = work & mask;
work >>= dst2Pow;
workBits -= dst2Pow;
if (srcLen) {
// more input left, so recurse
changeBase2Inline(src, srcLen, src2Pow, dst2Pow, outputPartialLastByte,
work, workBits, outLoc + 1);
*outLoc = outVal;
} else {
// no input left, we can write remaining values directly
*outLoc++ = outVal;
// we could have a partial value left in the work buffer..
if (outputPartialLastByte) {
while (workBits > 0) {
*outLoc++ = work & mask;
work >>= dst2Pow;
workBits -= dst2Pow;
}
}
}
}
void changeBase2Inline(unsigned char *src, int srcLen,
int src2Pow, int dst2Pow,
bool outputPartialLastByte)
{
changeBase2Inline(src, srcLen, src2Pow, dst2Pow,
outputPartialLastByte, 0, 0, 0);
void changeBase2Inline(unsigned char *src, int srcLen, int src2Pow, int dst2Pow,
bool outputPartialLastByte) {
changeBase2Inline(src, srcLen, src2Pow, dst2Pow, outputPartialLastByte, 0, 0,
0);
}
// character set for ascii b64:
// ",-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
// a standard base64 (eg a64l doesn't use ',-' but uses './'. We don't
@ -128,83 +111,69 @@ void changeBase2Inline(unsigned char *src, int srcLen,
// '.' included in the encrypted names, so that it can be reserved for files
// with special meaning.
static const char B642AsciiTable[] = ",-0123456789";
void B64ToAscii(unsigned char *in, int length)
{
for(int offset=0; offset<length; ++offset)
{
int ch = in[offset];
if(ch > 11)
{
if(ch > 37)
ch += 'a' - 38;
else
ch += 'A' - 12;
} else
ch = B642AsciiTable[ ch ];
void B64ToAscii(unsigned char *in, int length) {
for (int offset = 0; offset < length; ++offset) {
int ch = in[offset];
if (ch > 11) {
if (ch > 37)
ch += 'a' - 38;
else
ch += 'A' - 12;
} else
ch = B642AsciiTable[ch];
in[offset] = ch;
}
in[offset] = ch;
}
}
static const unsigned char Ascii2B64Table[] =
" 01 23456789:; ";
// 0123456789 123456789 123456789 123456789 123456789 123456789 1234
// 0 1 2 3 4 5 6
void AsciiToB64(unsigned char *in, int length)
{
return AsciiToB64(in, in, length);
" 01 23456789:; ";
// 0123456789 123456789 123456789 123456789 123456789 123456789 1234
// 0 1 2 3 4 5 6
void AsciiToB64(unsigned char *in, int length) {
return AsciiToB64(in, in, length);
}
void AsciiToB64(unsigned char *out, const unsigned char *in, int length)
{
while(length--)
{
unsigned char ch = *in++;
if(ch >= 'A')
{
if(ch >= 'a')
ch += 38 - 'a';
else
ch += 12 - 'A';
} else
ch = Ascii2B64Table[ ch ] - '0';
void AsciiToB64(unsigned char *out, const unsigned char *in, int length) {
while (length--) {
unsigned char ch = *in++;
if (ch >= 'A') {
if (ch >= 'a')
ch += 38 - 'a';
else
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)
{
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;
}
buf[offset] = ch;
}
}
void AsciiToB32(unsigned char *in, int length)
{
return AsciiToB32(in, in, length);
void AsciiToB32(unsigned char *in, int length) {
return AsciiToB32(in, in, length);
}
void AsciiToB32(unsigned char *out, const unsigned char *in, int length)
{
while(length--)
{
unsigned char ch = *in++;
int lch = toupper(ch);
if (lch >= 'A')
lch -= 'A';
else
lch += 26 - '2';
void AsciiToB32(unsigned char *out, const unsigned char *in, int length) {
while (length--) {
unsigned char ch = *in++;
int lch = toupper(ch);
if (lch >= 'A')
lch -= 'A';
else
lch += 26 - '2';
*out++ = (unsigned char)lch;
}
*out++ = (unsigned char)lch;
}
}

View File

@ -21,41 +21,33 @@
#ifndef _base64_incl_
#define _base64_incl_
inline int B64ToB256Bytes( int numB64Bytes )
{
return (numB64Bytes * 6) / 8; // round down
inline int B64ToB256Bytes(int numB64Bytes) {
return (numB64Bytes * 6) / 8; // round down
}
inline int B32ToB256Bytes( int numB32Bytes )
{
return (numB32Bytes * 5) / 8; // round down
inline int B32ToB256Bytes(int numB32Bytes) {
return (numB32Bytes * 5) / 8; // round down
}
inline int B256ToB64Bytes( int numB256Bytes )
{
return (numB256Bytes * 8 + 5) / 6; // round up
inline int B256ToB64Bytes(int numB256Bytes) {
return (numB256Bytes * 8 + 5) / 6; // round up
}
inline int B256ToB32Bytes( int numB256Bytes )
{
return (numB256Bytes * 8 + 4) / 5; // round up
inline int B256ToB32Bytes(int numB256Bytes) {
return (numB256Bytes * 8 + 4) / 5; // round up
}
/*
convert data between different bases - each being a power of 2.
*/
void changeBase2(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.
*/
void changeBase2Inline(unsigned char *buf, int srcLength,
int srcPow2, int dst2Pow,
bool outputPartialLastByte);
void changeBase2Inline(unsigned char *buf, int srcLength, int srcPow2,
int dst2Pow, bool outputPartialLastByte);
// inplace translation from values [0,2^6] => base64 ASCII
void B64ToAscii(unsigned char *buf, int length);
@ -71,4 +63,3 @@ void AsciiToB32(unsigned char *buf, int length);
void AsciiToB32(unsigned char *out, const unsigned char *in, int length);
#endif

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -32,34 +32,30 @@
#ifndef linux
#include <cerrno>
static __inline int setfsuid(uid_t uid)
{
uid_t olduid = geteuid();
static __inline int setfsuid(uid_t uid) {
uid_t olduid = geteuid();
seteuid(uid);
seteuid(uid);
if (errno != EINVAL)
errno = 0;
if (errno != EINVAL) errno = 0;
return olduid;
return olduid;
}
static __inline int setfsgid(gid_t gid)
{
gid_t oldgid = getegid();
static __inline int setfsgid(gid_t gid) {
gid_t oldgid = getegid();
setegid(gid);
setegid(gid);
if (errno != EINVAL)
errno = 0;
if (errno != EINVAL) errno = 0;
return oldgid;
return oldgid;
}
#endif
int encfs_getattr(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_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler);
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_chown(const char *path, uid_t uid, gid_t gid);
int encfs_truncate(const char *path, off_t size);
int encfs_ftruncate(const char *path, off_t size,
struct fuse_file_info *fi);
int encfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi);
int encfs_utime(const char *path, struct utimbuf *buf);
int encfs_open(const char *path, struct fuse_file_info *info);
int encfs_release(const char *path, struct fuse_file_info *info);
int encfs_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *info);
struct fuse_file_info *info);
int encfs_write(const char *path, const char *buf, size_t size, off_t offset,
struct fuse_file_info *info);
struct fuse_file_info *info);
int encfs_statfs(const char *, struct statvfs *fst);
int encfs_flush(const char *, struct fuse_file_info *info);
int encfs_fsync(const char *path, int flags, struct fuse_file_info *info);
#ifdef HAVE_XATTR
# ifdef XATTR_ADD_OPT
int encfs_setxattr( const char *path, const char *name, const char *value,
size_t size, int flags, uint32_t position);
int encfs_getxattr( const char *path, const char *name, char *value,
size_t size, uint32_t position );
# else
int encfs_setxattr( const char *path, const char *name, const char *value,
size_t size, int flags);
int encfs_getxattr( const char *path, const char *name, char *value,
size_t size );
# endif
int encfs_listxattr( const char *path, char *list, size_t size );
int encfs_removexattr( const char *path, const char *name );
#ifdef XATTR_ADD_OPT
int encfs_setxattr(const char *path, const char *name, const char *value,
size_t size, int flags, uint32_t position);
int encfs_getxattr(const char *path, const char *name, char *value, size_t size,
uint32_t position);
#else
int encfs_setxattr(const char *path, const char *name, const char *value,
size_t size, int flags);
int encfs_getxattr(const char *path, const char *name, char *value,
size_t size);
#endif
int encfs_utimens( const char *path, const struct timespec ts[2] );
int encfs_listxattr(const char *path, char *list, size_t size);
int encfs_removexattr(const char *path, const char *name);
#endif
int encfs_utimens(const char *path, const struct timespec ts[2]);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -25,8 +25,6 @@
#include "intl/gettext.h"
// make shortcut for gettext
# define _(STR) gettext (STR)
#define _(STR) gettext(STR)
#endif

File diff suppressed because it is too large Load Diff

View File

@ -31,36 +31,32 @@
using namespace std;
void genKey( const shared_ptr<Cipher> &cipher )
{
CipherKey key = cipher->newRandomKey();
void genKey(const shared_ptr<Cipher> &cipher) {
CipherKey key = cipher->newRandomKey();
// encode with itself
string b64Key = cipher->encodeAsString( key, key );
// encode with itself
string b64Key = cipher->encodeAsString(key, key);
cout << b64Key << "\n";
cout << b64Key << "\n";
}
int main(int argc, char **argv)
{
pid_t pid = getpid();
cerr << "pid = " << pid << "\n";
int main(int argc, char **argv) {
pid_t pid = getpid();
cerr << "pid = " << pid << "\n";
if(argc != 3)
{
cerr << "usage: makeKey [AES|Blowfish] [128|160|192|224|256]\n";
return 1;
}
if (argc != 3) {
cerr << "usage: makeKey [AES|Blowfish] [128|160|192|224|256]\n";
return 1;
}
const char *type = argv[1];
int size = atoi(argv[2]);
const char *type = argv[1];
int size = atoi(argv[2]);
openssl_init(false);
openssl_init(false);
// get a list of the available algorithms
shared_ptr<Cipher> cipher = Cipher::New( type, size );
genKey( cipher );
// get a list of the available algorithms
shared_ptr<Cipher> cipher = Cipher::New(type, size);
genKey(cipher);
//openssl_shutdown(false);
// openssl_shutdown(false);
}

View File

@ -31,79 +31,65 @@
#include <openssl/engine.h>
#endif
unsigned long pthreads_thread_id()
{
return (unsigned long)pthread_self();
}
unsigned long pthreads_thread_id() { return (unsigned long)pthread_self(); }
static pthread_mutex_t *crypto_locks = NULL;
void pthreads_locking_callback( int mode, int n,
const char *caller_file, int caller_line )
{
(void)caller_file;
(void)caller_line;
void pthreads_locking_callback(int mode, int n, const char *caller_file,
int caller_line) {
(void)caller_file;
(void)caller_line;
if(!crypto_locks)
{
rDebug("Allocating %i locks for OpenSSL", CRYPTO_num_locks() );
crypto_locks = new pthread_mutex_t[ CRYPTO_num_locks() ];
for(int i=0; i<CRYPTO_num_locks(); ++i)
pthread_mutex_init( crypto_locks+i, 0 );
}
if (!crypto_locks) {
rDebug("Allocating %i locks for OpenSSL", CRYPTO_num_locks());
crypto_locks = new pthread_mutex_t[CRYPTO_num_locks()];
for (int i = 0; i < CRYPTO_num_locks(); ++i)
pthread_mutex_init(crypto_locks + i, 0);
}
if(mode & CRYPTO_LOCK)
{
pthread_mutex_lock( crypto_locks + n );
} else
{
pthread_mutex_unlock( crypto_locks + n );
}
if (mode & CRYPTO_LOCK) {
pthread_mutex_lock(crypto_locks + n);
} else {
pthread_mutex_unlock(crypto_locks + n);
}
}
void pthreads_locking_cleanup()
{
if(crypto_locks)
{
for(int i=0; i<CRYPTO_num_locks(); ++i)
pthread_mutex_destroy( crypto_locks+i );
delete[] crypto_locks;
crypto_locks = NULL;
}
void pthreads_locking_cleanup() {
if (crypto_locks) {
for (int i = 0; i < CRYPTO_num_locks(); ++i)
pthread_mutex_destroy(crypto_locks + i);
delete[] crypto_locks;
crypto_locks = NULL;
}
}
void openssl_init(bool threaded)
{
// initialize the SSL library
SSL_load_error_strings();
SSL_library_init();
void openssl_init(bool threaded) {
// initialize the SSL library
SSL_load_error_strings();
SSL_library_init();
unsigned int randSeed = 0;
RAND_bytes( (unsigned char*)&randSeed, sizeof(randSeed) );
srand( randSeed );
unsigned int randSeed = 0;
RAND_bytes((unsigned char *)&randSeed, sizeof(randSeed));
srand(randSeed);
#ifndef OPENSSL_NO_ENGINE
/* Load all bundled ENGINEs into memory and make them visible */
ENGINE_load_builtin_engines();
/* Register all of them for every algorithm they collectively implement */
ENGINE_register_all_complete();
#endif // NO_ENGINE
/* Load all bundled ENGINEs into memory and make them visible */
ENGINE_load_builtin_engines();
/* Register all of them for every algorithm they collectively implement */
ENGINE_register_all_complete();
#endif // NO_ENGINE
if(threaded)
{
// provide locking functions to OpenSSL since we'll be running with
// threads accessing openssl in parallel.
CRYPTO_set_id_callback( pthreads_thread_id );
CRYPTO_set_locking_callback( pthreads_locking_callback );
}
if (threaded) {
// provide locking functions to OpenSSL since we'll be running with
// threads accessing openssl in parallel.
CRYPTO_set_id_callback(pthreads_thread_id);
CRYPTO_set_locking_callback(pthreads_locking_callback);
}
}
void openssl_shutdown(bool threaded)
{
void openssl_shutdown(bool threaded) {
#ifndef OPENSSL_NO_ENGINE
ENGINE_cleanup();
ENGINE_cleanup();
#endif
if(threaded)
pthreads_locking_cleanup();
if (threaded) pthreads_locking_cleanup();
}

View File

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

View File

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