From 2c24e8a41f228d0d8fa4df0fd90b39e96f43a610 Mon Sep 17 00:00:00 2001 From: hama Date: Sun, 4 Oct 2015 02:05:36 +0200 Subject: [PATCH] ReCryptFileSystem --- base/ReRandomizer.cpp | 339 ++++++++++++++++++++++++++++++++++++++++++ base/ReRandomizer.hpp | 93 ++++++++++++ base/rebase.hpp | 3 +- cunit/cunit.pro | 5 +- os/ReFileSystem.cpp | 279 ++++++++++++++++++++++++---------- os/ReFileSystem.hpp | 63 ++++++-- tools/mk_nodeChar.pl | 29 ++++ 7 files changed, 716 insertions(+), 95 deletions(-) create mode 100644 base/ReRandomizer.cpp create mode 100644 base/ReRandomizer.hpp create mode 100644 tools/mk_nodeChar.pl diff --git a/base/ReRandomizer.cpp b/base/ReRandomizer.cpp new file mode 100644 index 0000000..9c5b69f --- /dev/null +++ b/base/ReRandomizer.cpp @@ -0,0 +1,339 @@ +/* + * ReRandomizer.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +#include "base/rebase.hpp" + +static bool s_trace = false; +/** + * @brief Constructor. + */ +ReRandomizer::ReRandomizer() { +} +/** + * @brief Destructor. + */ +ReRandomizer::~ReRandomizer() { +} + +#if defined __linux__ +inline int abs(int x) { + return x < 0 ? -x : x; +} +#endif +/** + * @brief Returns the next random character. + * + * The character is in the range ' ' .. chr(127) (inclusive). + * + * @return The next random character. + */ +char ReRandomizer::nextChar() { + char rc = nextInt(' ', ' ' + CHARRANGE - 1); + return rc; +} + +/** + * @brief Returns a random number which is not predictable. + * + * @return a number which is not predictable + */ +ReRandomizer::seed_t ReRandomizer::nearTrueRandom() { + seed_t rc = 0; +#if defined __linux__ + int fh = open("/dev/urandom", O_RDONLY); + char buffer[sizeof(seed_t)]; + if (read(fh, buffer, sizeof buffer) > 0) + rc ^= *(seed_t*) buffer; + close(fh); +#else + time_t random = time(NULL); + static int dummy = 5; + void* dummy2 = malloc(1); + free(dummy2); + rc = (((seed_t) random) << 31) + ((seed_t) &dummy << 9) + + ((-random ^ 0x20111958) ^ (seed_t(dummy2))); +#endif + return rc; +} +/** + * @brief Returns the next random integer. + * + * + * @param maxValue The maximum of the result (including). + * @param minValue The minimum of the result. + * + * @return The next seed. + */ +int ReRandomizer::nextInt(int maxValue, int minValue) { + int rc; + if (minValue > maxValue) { + rc = minValue; + minValue = maxValue; + maxValue = rc; + } + seed_t seed = nextSeed(); + if (minValue == maxValue) + rc = minValue; + else { + // we calculate in 64 bit, no range overflow: + int64_t range = (int64_t) maxValue - minValue + 1; + int64_t offset = seed % range; + rc = (int) (minValue + offset); + } + if (s_trace) { + static int count = 0; + printf("%c %8x ", count++ % 4 == 0 ? '\n' : ' ', rc); + } + return rc; +} + +/** + * @brief Returns the next random integer. + * + * + * @param maxValue The maximum of the result (including). + * @param minValue The minimum of the result. + * + * @return The next seed. + */ +int64_t ReRandomizer::nextInt64(int64_t maxValue, int64_t minValue) { + seed_t rc; + if (minValue > maxValue) { + rc = minValue; + minValue = maxValue; + maxValue = rc; + } + seed_t seed = nextSeed(); + if (minValue == maxValue) + rc = minValue; + else if (minValue == 0 && maxValue == LLONG_MAX) + rc = abs((int64_t) seed); + else if (uint64_t(maxValue - minValue) < LLONG_MAX) + // no signed int64 overflow: + rc = minValue + seed % (maxValue - minValue + 1); + else { + // int64 overflow: we need a higher precision: + double rc2 = (double) minValue + + fmod((double) seed, (double) (maxValue - minValue)); + rc = (int) rc2; + } + if (s_trace) { + static int count = 0; + printf("%c %16llx ", count++ % 4 == 0 ? '\n' : ' ', (long long) rc); + } + return rc; +} + +/** + * @brief Calculates the next seed for the generator. + * + * @return The next seed. + */ +ReRandomizer::seed_t ReCongruentialGenerator::nextSeed() { + m_seed = m_seed * m_factor + m_increment; + return m_seed; +} + +/** + * @brief Returns a string with random characters. + * + * All character will be inside the range ' ' .. chr(127). + * + * @param minLength The minimum length of the result string. + * @param maxLength The maximum length of the result string. + * @param buffer Out: The place for the string. + * + * @result The buffer. + */ +const char* ReRandomizer::nextString(int minLength, int maxLength, + QByteArray &buffer) { + int len = nextInt(maxLength, minLength); + buffer.resize(len); + char* ptr = buffer.data(); + for (int ii = 0; ii < len; ii++) { + ptr[ii] = nextChar(); + } + return buffer.constData(); +} + +/** + * @brief Builds a random permutation of an array. + * + * The operation will be done in place: + * + * @param array In/Out: The array to shuffle. + * @param length The length of the array. + * @param elemSize The size of one element of the array. + */ +void ReRandomizer::shuffle(void* array, size_t length, size_t elemSize) { + int ii; + char* cptr; + int* iptr; + int count = length * 3 / 2; + + switch (elemSize) { + case 1: + cptr = (char*) array; + for (ii = 0; ii < count; ii++) { + int ix1 = length - nextInt(1, length); + int ix2 = length - nextInt(1, length); + char x = cptr[ix1]; + cptr[ix1] = cptr[ix2]; + cptr[ix2] = x; + } + break; + case sizeof(int): + iptr = (int*) array; + for (ii = 0; ii < count; ii++) { + int ix1 = length - nextInt(1, length); + int ix2 = length - nextInt(1, length); + int x = iptr[ix1]; + iptr[ix1] = iptr[ix2]; + iptr[ix2] = x; + } + break; + default: { + char buffer[0x10000]; + assert(elemSize < sizeof buffer); + iptr = (int*) array; + for (ii = 0; ii < count; ii++) { + int ix1 = length - nextInt(1, length); + int ix2 = length - nextInt(1, length); + char* p1 = ((char*) array) + ix1 * elemSize; + char* p2 = ((char*) array) + ix2 * elemSize; + memcpy(buffer, p1, elemSize); + memcpy(p1, p2, elemSize); + memcpy(p2, buffer, elemSize); + } + break; + } + } +} +/** + * @brief Constructor. + */ +ReCongruentialGenerator::ReCongruentialGenerator() : + m_seed(0x4711), + m_factor(214013), + m_increment(2531011), + m_lastSetSeed(0x4711) { +} +/** + * @brief Destructor. + */ +ReCongruentialGenerator::~ReCongruentialGenerator() { +} + +/** + * @brief Returns the current factor. + * + * @return The current factor. + */ +ReRandomizer::seed_t ReCongruentialGenerator::factor() const { + return m_factor; +} + +/** + * @brief Returns the current increment. + * + * @return The current increment. + */ +ReRandomizer::seed_t ReCongruentialGenerator::increment() const { + return m_increment; +} + +/** + * Returns the current seed. + * + * @return The current seed. + */ +ReRandomizer::seed_t ReCongruentialGenerator::seed() const { + return m_seed; +} + +/** + * @brief Sets the seed to the value given by the last setSeed(). + * + * Note: The constructor does the first setSeed(). + */ +void ReCongruentialGenerator::reset() { + m_seed = m_lastSetSeed; +} + +/** + * Sets the factor. + * + * @param factor The new factor. + */ +void ReCongruentialGenerator::setFactor(seed_t factor) { + this->m_factor = factor; +} + +/** + * Sets the increment. + * + * @param increment The new increment. + */ +void ReCongruentialGenerator::setIncrement(seed_t increment) { + this->m_increment = increment; +} + +/** @brief Sets the current seed. + * + * @param seed The seed to set. + */ +void ReCongruentialGenerator::setSeed(seed_t seed) { + m_seed = m_lastSetSeed = seed; + if (s_trace) + printf(" Seed: %llx ", (long long) seed); +} + +/** + * Gets the current point of pseudo random. + * + * @param seed the current point of pseudo random + */ +void ReCongruentialGenerator::seed(QByteArray& seed) { + seed.resize(sizeof m_seed); + memcpy(seed.data(), &m_seed, sizeof m_seed); +} + +/** + * Sets the current point of pseudo random. + * + * @param seed the current point of pseudo random + */ +void ReCongruentialGenerator::setSeed(const QByteArray& seed) { + if (seed.size() >= sizeof(seed_t)) { + memcpy(&m_seed, seed.constData(), sizeof m_seed); + } else { + QByteArray buffer = seed; + buffer.resize(sizeof m_seed); + memset(buffer.data() + seed.size(), 0, sizeof(m_seed) - seed.size()); + memcpy(&m_seed, buffer.constData(), sizeof m_seed); + } + m_lastSetSeed = m_seed; + +} + +/** @brief Returns the next 64 bit pseudo random number. + * + * A congruential generator produces good random in the most significant + * bits. Therefore we exchange the bits of the result. + * Then x % m returns better results. + * + * @return a pseudo random number + */ +ReRandomizer::seed_t ReShiftRandom::nextSeed() { + seed_t rc = ReCongruentialGenerator::nextSeed(); + rc = ((rc & 0x7fffffff) << 33) | ((rc >> 31) & 0x1ffffffffll); + return rc; +} diff --git a/base/ReRandomizer.hpp b/base/ReRandomizer.hpp new file mode 100644 index 0000000..6e24fa7 --- /dev/null +++ b/base/ReRandomizer.hpp @@ -0,0 +1,93 @@ +/* + * ReRandomizer.hpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +#ifndef RANDOMIZER_H_ +#define RANDOMIZER_H_ + +/** + * This implements an abstract base class for random generators. + */ +class ReRandomizer { +public: + enum { + START_RANGE = ' ', + CHARRANGE = 128 - START_RANGE + }; + typedef uint64_t seed_t; +public: + ReRandomizer(); + virtual ~ReRandomizer(); +public: + virtual int nextInt(int maxValue = INT_MAX, int minValue = 0); + virtual int64_t nextInt64(int64_t maxValue = LLONG_MAX, + int64_t minValue = 0); + char nextChar(); + const char* nextString(int minLength, int maxLength, QByteArray& buffer); + void shuffle(void* array, size_t length, size_t elemSize); + /** @brief Sets the instance to a defined start state. + */ + virtual void reset() = 0; + /** + * Gets the current point of pseudo random. + * + * @param seed the current point of pseudo random + */ + virtual void seed(QByteArray& seed) = 0; + /** + * Sets the current point of pseudo random. + * + * @param seed the current point of pseudo random + */ + virtual void setSeed(QByteArray& seed) = 0; +protected: + /** @brief Returns the next pseudo random number. + * @return the next pseudo random number + * */ + virtual seed_t nextSeed() = 0; +public: + seed_t nearTrueRandom(); +}; + +/** + * Implements a simple random generator. + * A linear congruential generator produces the next value using this formula: + * seed = (seed * factor + increment) % modulus + * In this implementation modulus is 2**64. + */ +class ReCongruentialGenerator: public ReRandomizer { +public: + ReCongruentialGenerator(); + virtual ~ReCongruentialGenerator(); +public: + seed_t factor() const; + seed_t increment() const; + virtual void reset(); + seed_t seed() const; + virtual void seed(QByteArray& seed); + void setFactor(seed_t factor); + void setIncrement(seed_t increment); + void setSeed(seed_t m_seed); + virtual void setSeed(const QByteArray& seed); +protected: + friend class ReShiftRandom; + virtual seed_t nextSeed(); +private: + seed_t m_seed; + seed_t m_factor; + seed_t m_increment; + seed_t m_lastSetSeed; +}; + +class ReShiftRandom: public ReCongruentialGenerator { +protected: + virtual seed_t nextSeed(); +}; +#endif /* RANDOMIZER_H_ */ diff --git a/base/rebase.hpp b/base/rebase.hpp index 407cb78..cb8e2db 100644 --- a/base/rebase.hpp +++ b/base/rebase.hpp @@ -23,6 +23,7 @@ #ifdef __linux__ #include #include +#include #else #include #include @@ -113,5 +114,5 @@ inline int roundInt(double value) { #include "base/ReDiff.hpp" #include "base/ReMatcher.hpp" #include "base/ReTest.hpp" - +#include "base/ReRandomizer.hpp" #endif // REBASE_HPP diff --git a/cunit/cunit.pro b/cunit/cunit.pro index 717246b..7f33dea 100644 --- a/cunit/cunit.pro +++ b/cunit/cunit.pro @@ -36,6 +36,7 @@ SOURCES += main.cpp \ ../base/ReMatcher.cpp \ ../base/ReTest.cpp \ ../base/ReWriter.cpp \ + ../base/ReRandomizer.cpp \ ../gui/ReStateStorage.cpp \ ../gui/ReSettings.cpp \ ../gui/ReEdit.cpp \ @@ -54,4 +55,6 @@ SOURCES += main.cpp \ HEADERS += \ ../base/ReFile.hpp \ ../base/rebase.hpp \ - ../gui/ReEdit.hpp + ../gui/ReEdit.hpp \ + ../math/ReMatrix.hpp \ + ../math/remath.hpp diff --git a/os/ReFileSystem.cpp b/os/ReFileSystem.cpp index 06c819d..842814d 100644 --- a/os/ReFileSystem.cpp +++ b/os/ReFileSystem.cpp @@ -32,22 +32,40 @@ enum { LOC_SET_PROPERTIES_5, // 12017 }; +const char ReCryptFileSystem::ESC = '%'; +const int ReCryptFileSystem::m_indexOfNodeChar[] = { -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 0, 1, -1, 2, 3, 4, 5, 6, 7, 8, -1, 9, 10, 11, 12, + -1, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, -1, -1, -1, 23, -1, -1, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, -1, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, }; +const char ReCryptFileSystem::m_nodeChars[] = { ' ', '!', '#', '$', '%', '&', + '\'', '(', ')', '+', ',', '-', '.', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '=', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '[', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', + 'z', '{', '|', '}', '~', '\x7f', }; +const int ReCryptFileSystem::m_countNodeChars = + sizeof ReCryptFileSystem::m_nodeChars; /** * Constructor. * * @param name the name of the filesystem */ ReFileSystem::ReFileSystem(const QString& name, ReLogger* logger) : - m_name(name), + m_name(name), #ifdef __linux__ - m_uid(geteuid()), - m_gid(getegid()), + m_uid(geteuid()), + m_gid(getegid()), #endif - m_writeable(false), - m_logger(logger), - m_buffer(), - m_blocksize(4 * 1024 * 1024), - m_undefinedTime() { + m_writeable(false), + m_logger(logger), + m_buffer(), + m_blocksize(4 * 1024 * 1024), + m_undefinedTime() { } @@ -66,14 +84,14 @@ ReFileSystem::~ReFileSystem() { * */ ReFileSystem::ErrorCode ReFileSystem::copy(ReFileMetaData& source, - ReFileSystem& sourceFS) { + ReFileSystem& sourceFS) { int blocksize = min(m_blocksize, sourceFS.blocksize()); ErrorCode rc = EC_SUCCESS; ErrorCode rc2; int64_t size = 0; while (rc == EC_SUCCESS && size < source.m_size) { if ((rc2 = sourceFS.read(source, size, blocksize, m_buffer)) - != EC_SUCCESS) + != EC_SUCCESS) rc = rc2; else if ((rc2 = write(source.m_node, size, m_buffer)) != EC_SUCCESS) rc = rc2; @@ -82,7 +100,7 @@ ReFileSystem::ErrorCode ReFileSystem::copy(ReFileMetaData& source, close(); sourceFS.close(); ReFileMetaData target(source.m_node, ReFileUtils::m_undefinedTime, - ReFileUtils::m_undefinedTime, m_uid, m_gid); + ReFileUtils::m_undefinedTime, m_uid, m_gid); setProperties(source, target, false); return rc; } @@ -136,7 +154,7 @@ bool ReFileSystem::first(const QString& pattern, ReFileMetaData& file) { QStringList names; names.append(pattern); ReIncludeExcludeMatcher matcher(names, ReQStringUtils::m_emptyList, - Qt::CaseInsensitive, true); + Qt::CaseInsensitive, true); listInfos(matcher, list); bool rc = list.size() > 0; if (rc) @@ -162,11 +180,11 @@ void ReFileSystem::setBlocksize(int blocksize) { * @param logger */ ReLocalFileSytem::ReLocalFileSytem(const QString& basePath, ReLogger* logger) : - ReFileSystem("localfs", logger), - m_basePath(basePath), - m_dir(basePath), - m_readFile(NULL), - m_writeFile(NULL) { + ReFileSystem("localfs", logger), + m_basePath(basePath), + m_dir(basePath), + m_readFile(NULL), + m_writeFile(NULL) { m_directory = basePath; ReQStringUtils::ensureLastChar(m_directory, OS_SEPARATOR); setWriteable(true); @@ -209,11 +227,11 @@ void ReLocalFileSytem::close() { * @return the count of the found entries (list.size()) */ int ReLocalFileSytem::listInfos(const ReIncludeExcludeMatcher& matcher, - ReFileMetaDataList& list) { + ReFileMetaDataList& list) { list.clear(); const QStringList& patterns = matcher.includes().patterns(); QStringList nodes = - patterns.size() == 0 ? m_dir.entryList() : m_dir.entryList(patterns); + patterns.size() == 0 ? m_dir.entryList() : m_dir.entryList(patterns); QStringList::const_iterator it; QByteArray full = m_directory.toUtf8(); full.append(OS_SEPARATOR); @@ -225,9 +243,9 @@ int ReLocalFileSytem::listInfos(const ReIncludeExcludeMatcher& matcher, full.append(node.toUtf8()); if (stat(full.constData(), &info) == 0) { list.append( - ReFileMetaData(node, QDateTime::fromTime_t(info.st_mtime), - QDateTime::fromTime_t(info.st_ctime), info.st_uid, - info.st_gid, info.st_mode, info.st_size)); + ReFileMetaData(node, QDateTime::fromTime_t(info.st_mtime), + QDateTime::fromTime_t(info.st_ctime), info.st_uid, + info.st_gid, info.st_mode, info.st_size)); } } return list.size(); @@ -247,11 +265,11 @@ ReFileSystem::ErrorCode ReLocalFileSytem::makeDir(const QString& node) { rc = EC_FS_READ_ONLY; } else if (m_dir.exists(node)) { m_logger->logv(LOG_ERROR, LOC_MAKE_DIR_2, "node exists already: %s", - fullNameAsUTF8(node).constData()); + fullNameAsUTF8(node).constData()); rc = EC_ALREADY_EXISTS; } else if (!m_dir.mkdir(node)) { m_logger->logv(LOG_ERROR, LOC_MAKE_DIR_2, "cannot create directory: %s", - fullNameAsUTF8(node).constData()); + fullNameAsUTF8(node).constData()); rc = EC_NOT_ACCESSIBLE; } return rc; @@ -284,7 +302,7 @@ ReFileSystem::ErrorCode ReLocalFileSytem::setDirectory(const QString& path) { * EC_READ: error while reading */ ReFileSystem::ErrorCode ReLocalFileSytem::read(const ReFileMetaData& source, - int64_t offset, int size, QByteArray& buffer) { + int64_t offset, int size, QByteArray& buffer) { ErrorCode rc = EC_SUCCESS; if (offset == 0) { if (m_readFile != NULL) @@ -292,8 +310,8 @@ ReFileSystem::ErrorCode ReLocalFileSytem::read(const ReFileMetaData& source, QString fn = fullName(source.m_node); if ((m_readFile = fopen(fn.toUtf8().constData(), "rb")) == NULL) { m_logger->logv(LOG_ERROR, LOC_READ_1, - "cannot open for reading (%d): %s", errno, - fn.toUtf8().constData()); + "cannot open for reading (%d): %s", errno, + fn.toUtf8().constData()); rc = EC_NOT_READABLE; } } @@ -303,7 +321,7 @@ ReFileSystem::ErrorCode ReLocalFileSytem::read(const ReFileMetaData& source, int nRead = fread(buffer.data(), 1, size, m_readFile); if (nRead < 0) { m_logger->logv(LOG_ERROR, LOC_READ_2, "cannot read (%d): %s", errno, - source.m_node.toUtf8().constData()); + source.m_node.toUtf8().constData()); nRead = 0; rc = EC_READ; } @@ -335,21 +353,21 @@ ReFileSystem::ErrorCode ReLocalFileSytem::remove(const ReFileMetaData& node) { rc = EC_FS_READ_ONLY; } else if (!m_dir.exists(node.m_node)) { m_logger->logv(LOG_ERROR, LOC_REMOVE_2, "node does not exists: %s", - fullNameAsUTF8(node.m_node).constData()); + fullNameAsUTF8(node.m_node).constData()); rc = EC_NOT_EXISTS; } else { if (S_ISDIR(node.m_mode)) { if (!m_dir.rmdir(node.m_node)) { m_logger->logv(LOG_ERROR, LOC_REMOVE_3, - "cannot remove directory: %s", - fullNameAsUTF8(node.m_node).constData()); + "cannot remove directory: %s", + fullNameAsUTF8(node.m_node).constData()); rc = EC_NOT_ACCESSIBLE; } } else { if (!m_dir.remove(node.m_node)) { m_logger->logv(LOG_ERROR, LOC_REMOVE_3, - "cannot remove file: %s", - fullNameAsUTF8(node.m_node).constData()); + "cannot remove file: %s", + fullNameAsUTF8(node.m_node).constData()); rc = EC_NOT_ACCESSIBLE; } } @@ -371,32 +389,31 @@ ReFileSystem::ErrorCode ReLocalFileSytem::remove(const ReFileMetaData& node) { * */ ReFileSystem::ErrorCode ReLocalFileSytem::setProperties( - const ReFileMetaData& source, ReFileMetaData& target, - bool force) { + const ReFileMetaData& source, ReFileMetaData& target, bool force) { ErrorCode rc = EC_SUCCESS; if (!m_writeable) { m_logger->log(LOG_ERROR, LOC_SET_PROPERTIES_1, - "filesystem is readonly"); + "filesystem is readonly"); rc = EC_FS_READ_ONLY; } else do { QByteArray name; bool nameChanged = target.m_node != source.m_node; bool timeChanged = source.m_modified != target.m_modified - && source.m_modified != ReFileUtils::m_undefinedTime; + && source.m_modified != ReFileUtils::m_undefinedTime; #ifdef __linux__ - bool modeChanged = (source.m_mode & ALLPERMS) != (target.m_mode & ALLPERMS) - && source.m_mode != (mode_t) -1; - bool ownerChanged = (source.m_owner != target.m_owner + bool modeChanged = (source.m_mode & ALLPERMS) != (target.m_mode & ALLPERMS) + && source.m_mode != (mode_t) -1; + bool ownerChanged = (source.m_owner != target.m_owner && source.m_owner != -1) || (source.m_group != source.m_group && source.m_group != -1); - if (force && m_uid != 0 && (nameChanged || timeChanged || modeChanged - || ownerChanged)){ - name = fullNameAsUTF8(target.m_node); - chmod(name.constData(), ALLPERMS); - modeChanged = true; - } + if (force && m_uid != 0 && (nameChanged || timeChanged || modeChanged + || ownerChanged)) { + name = fullNameAsUTF8(target.m_node); + chmod(name.constData(), ALLPERMS); + modeChanged = true; + } #endif if (nameChanged) { @@ -405,17 +422,16 @@ ReFileSystem::ErrorCode ReLocalFileSytem::setProperties( name = fullNameAsUTF8(target.m_node); rc = EC_ALREADY_EXISTS; m_logger->logv(LOG_ERROR, LOC_SET_PROPERTIES_2, - "renaming impossible: node exists: %s", - name.constData()); + "renaming impossible: node exists: %s", + name.constData()); break; } else if (!m_dir.rename(target.m_node, source.m_node)) { rc = EC_RENAME; if (name.length() == 0) name = fullNameAsUTF8(target.m_node); m_logger->logv(LOG_ERROR, LOC_SET_PROPERTIES_3, - "renaming impossible: %s -> %s", - source.m_node.toUtf8().constData(), - name.constData()); + "renaming impossible: %s -> %s", + source.m_node.toUtf8().constData(), name.constData()); break; } else { name.resize(0); @@ -426,7 +442,7 @@ ReFileSystem::ErrorCode ReLocalFileSytem::setProperties( if (name.length() == 0) name = fullNameAsUTF8(target.m_node); if (!ReFileUtils::setTimes(name.constData(), source.m_modified, - ReFileUtils::m_undefinedTime, m_logger)) + ReFileUtils::m_undefinedTime, m_logger)) rc = EC_NOT_ACCESSIBLE; } @@ -445,7 +461,7 @@ ReFileSystem::ErrorCode ReLocalFileSytem::setProperties( } if (modeChanged) { mode_t mode = source.m_mode == (mode_t) -1 - ? target.m_mode : source.m_mode; + ? target.m_mode : source.m_mode; if (chmod(name.constData(), mode & ALLPERMS) != 0) { rc = EC_NOT_ACCESSIBLE; m_logger->logv(LOG_ERROR, LOC_SET_PROPERTIES_4, @@ -471,7 +487,7 @@ ReFileSystem::ErrorCode ReLocalFileSytem::setProperties( * */ ReFileSystem::ErrorCode ReLocalFileSytem::write(const QString& node, - int64_t offset, const QByteArray& buffer) { + int64_t offset, const QByteArray& buffer) { ErrorCode rc = EC_SUCCESS; if (!writeable()) { m_logger->log(LOG_ERROR, LOC_WRITE_1, "filesystem is readonly"); @@ -483,8 +499,8 @@ ReFileSystem::ErrorCode ReLocalFileSytem::write(const QString& node, QString fn = fullName(node); if ((m_writeFile = fopen(fn.toUtf8().constData(), "wb")) == NULL) { m_logger->logv(LOG_ERROR, LOC_WRITE_2, - "cannot open for writing (%d): %s", errno, - fn.toUtf8().constData()); + "cannot open for writing (%d): %s", errno, + fn.toUtf8().constData()); rc = EC_NOT_WRITEABLE; } } @@ -493,14 +509,14 @@ ReFileSystem::ErrorCode ReLocalFileSytem::write(const QString& node, if (position != offset) { rc = EC_POSITION; m_logger->logv(LOG_ERROR, LOC_WRITE_4, - "wrong file position: %lld/%lld", offset, position); + "wrong file position: %lld/%lld", offset, position); } else { int nWritten = fwrite(buffer.constData(), 1, buffer.length(), - m_writeFile); + m_writeFile); if (nWritten != buffer.length()) { m_logger->logv(LOG_ERROR, LOC_WRITE_3, - "cannot write (%d): %s written: %d/%d", errno, - node.toUtf8().constData(), nWritten, buffer.length()); + "cannot write (%d): %s written: %d/%d", errno, + node.toUtf8().constData(), nWritten, buffer.length()); rc = EC_WRITE; } fflush(m_writeFile); @@ -514,13 +530,13 @@ ReFileSystem::ErrorCode ReLocalFileSytem::write(const QString& node, * Constructor. */ ReFileMetaData::ReFileMetaData() : - m_node(), - m_modified(), - m_created(), - m_owner(-1), - m_group(-1), - m_mode(-1), - m_size(-1) { + m_node(), + m_modified(), + m_created(), + m_owner(-1), + m_group(-1), + m_mode(-1), + m_size(-1) { } @@ -536,14 +552,14 @@ ReFileMetaData::ReFileMetaData() : * @param size the filesize (0 for directories) */ ReFileMetaData::ReFileMetaData(const QString& node, const QDateTime& modified, - const QDateTime& created, int owner, int group, mode_t mode, int64_t size) : - m_node(node), - m_modified(modified), - m_created(created), - m_owner(owner), - m_group(group), - m_mode(mode), - m_size(size) { + const QDateTime& created, int owner, int group, mode_t mode, int64_t size) : + m_node(node), + m_modified(modified), + m_created(created), + m_owner(owner), + m_group(group), + m_mode(mode), + m_size(size) { } @@ -559,13 +575,13 @@ ReFileMetaData::~ReFileMetaData() { * @param source source to copy */ ReFileMetaData::ReFileMetaData(const ReFileMetaData& source) : - m_node(source.m_node), - m_modified(source.m_modified), - m_created(source.m_created), - m_owner(source.m_owner), - m_group(source.m_group), - m_mode(source.m_mode), - m_size(source.m_size) { + m_node(source.m_node), + m_modified(source.m_modified), + m_created(source.m_created), + m_owner(source.m_owner), + m_group(source.m_group), + m_mode(source.m_mode), + m_size(source.m_size) { } @@ -585,3 +601,102 @@ ReFileMetaData&ReFileMetaData::operator =(const ReFileMetaData& source) { m_size = source.m_size; return *this; } + +/** + * Constructor. + * + * @param hostFileSystem the filesystem which does the storage (with + * encrypted names and content + * @param nameRandom a pseudo random generator for names + * @param contentRandom a pseudo random generator for content + */ +ReCryptFileSystem::ReCryptFileSystem(ReFileSystem& hostFileSystem, + ReRandomizer& nameRandom, ReRandomizer& contentRandom, ReLogger* logger) : + ReFileSystem("cryptfs", logger), + m_host(hostFileSystem), + m_contentRandom(contentRandom), + m_nameRandom(nameRandom), + m_contentSeed(), + m_nameSeed(), + m_buffer() { + m_contentRandom.seed(m_contentSeed); + m_nameRandom.seed(m_nameSeed); + m_buffer.reserve(256); +} + +/** + * Destructor. + */ +ReCryptFileSystem::~ReCryptFileSystem() { +} + +/** + * Makes a clear text filename. + * + * @param name encrypted filename + * @return the clear text filename + */ +QString ReCryptFileSystem::decodeName(const QString& name) { + QString rc = name; + return rc; +} + +void ReCryptFileSystem::decodeContent(const QByteArray& source, + QByteArray& target) { + +} + +QByteArray& ReCryptFileSystem::encodeName(const QByteArray& node) { + QByteArray rc; + int length = node.length(); + int nameLength = rc.lastIndexOf('.'); + if (nameLength < 0) + nameLength = node.length(); + const char* src = node.constData(); + unsigned char cc; + int ix2 = nameLength - 1; + for (int ix = 0; ix < length; ix++) { + cc = (unsigned char) src[ix >= nameLength ? ix : ix2--]; + if (cc != ESC && cc < 128) { + m_buffer.append(cc); + } else { + m_buffer.append(ESC); + char hex[3]; + snprintf(hex, sizeof hex, "%02x", cc); + m_buffer.append(hex, 2); + } + } + m_nameRandom.reset(); + char* trg = m_buffer.data(); + int pred = 0; + for (int ix = 0; ix < length; ix++) { + int ix2 = (m_indexOfNodeChar[*trg] + pred + + m_nameRandom.nextInt(m_countNodeChars - 1)) % m_countNodeChars; + *trg = m_nodeChars[ix2]; + pred = ix2; + } + return m_buffer; +} +QString ReCryptFileSystem::encodeName(const QString& node) { + return encodeName(node.toUtf8()); +} + +void ReCryptFileSystem::encodeContent(const QByteArray& source, + QByteArray& target) { + +} + +int ReCryptFileSystem::listInfos(const ReIncludeExcludeMatcher& matcher, + ReFileMetaDataList& list) { +} + +ReFileSystem::ErrorCode ReCryptFileSystem::makeDir(const QString& node) { +} + +ReFileSystem::ErrorCode ReCryptFileSystem::read(const ReFileMetaData& source, + int64_t offset, int size, QByteArray& buffer) { +} + +ReFileSystem::ErrorCode ReCryptFileSystem::write(const QString& target, + int64_t offset, const QByteArray& buffer) { +} diff --git a/os/ReFileSystem.hpp b/os/ReFileSystem.hpp index 425f38b..b3daa0f 100644 --- a/os/ReFileSystem.hpp +++ b/os/ReFileSystem.hpp @@ -16,9 +16,8 @@ class ReFileMetaData { public: ReFileMetaData(); ReFileMetaData(const QString& node, const QDateTime& modified, - const QDateTime& created, - int owner = -1, int group = -1, - mode_t mode = (mode_t) -1, int64_t size = 0); + const QDateTime& created, int owner = -1, int group = -1, + mode_t mode = (mode_t) - 1, int64_t size = 0); virtual ~ReFileMetaData(); ReFileMetaData(const ReFileMetaData& source); ReFileMetaData& operator =(const ReFileMetaData& source); @@ -74,7 +73,7 @@ public: * @return the count of the found entries (list.size()) */ virtual int listInfos(const ReIncludeExcludeMatcher& matcher, - ReFileMetaDataList& list) = 0; + ReFileMetaDataList& list) = 0; /** Creates a directory. * @param node the name without path (in the current directory) * @return EC_SUCCESS or error code @@ -88,7 +87,7 @@ public: * @return EC_SUCCESS or error code */ virtual ErrorCode read(const ReFileMetaData& source, int64_t offset, - int size, QByteArray& buffer) = 0; + int size, QByteArray& buffer) = 0; /** Removes a file or directory. * @param node the properties ot the node (in the current directory) * @return EC_SUCCESS or error code @@ -109,7 +108,7 @@ public: * @return EC_SUCCESS or error code */ virtual ErrorCode setProperties(const ReFileMetaData& source, - ReFileMetaData& target, bool force) = 0; + ReFileMetaData& target, bool force) = 0; /** Writes a buffer to a file. * @param node the file to write (without path, inside the current directory) * @param offset first position to write @@ -117,7 +116,7 @@ public: * @return EC_SUCCESS or error code */ virtual ErrorCode write(const QString& target, int64_t offset, - const QByteArray& buffer) = 0; + const QByteArray& buffer) = 0; public: virtual ErrorCode copy(ReFileMetaData& source, ReFileSystem& sourceFS); public: @@ -168,15 +167,15 @@ public: // ReFileSystem interface virtual void close(); virtual int listInfos(const ReIncludeExcludeMatcher& matcher, - ReFileMetaDataList& list); + ReFileMetaDataList& list); ErrorCode makeDir(const QString& node); virtual ErrorCode read(const ReFileMetaData& source, int64_t offset, - int size, QByteArray& buffer); + int size, QByteArray& buffer); ErrorCode remove(const ReFileMetaData& node); ErrorCode setProperties(const ReFileMetaData& source, - ReFileMetaData& target, bool force = false); + ReFileMetaData& target, bool force = false); virtual ErrorCode write(const QString& target, int64_t offset, - const QByteArray& buffer); + const QByteArray& buffer); protected: QString m_basePath; @@ -185,5 +184,47 @@ protected: FILE* m_writeFile; }; +/** + * A filesystem with encrypted filenames and file content. + * + * The storage is done with a 'host filesystem'. + * The filenames used in the interface (parameters) are clear text. + * The filenames of the base filesystem are encrypted. + * If a file content is copied / moved to the base filesystem the content + * will be encrypted. In the other direction the file content will be decrypted. + */ +class ReCryptFileSystem: ReFileSystem { +public: + static const char ESC; +public: + ReCryptFileSystem(ReFileSystem& hostFileSystem, ReRandomizer& nameRandom, + ReRandomizer& contentRandom, ReLogger* logger); + ~ReCryptFileSystem(); +public: + QString decodeName(const QString& name); + void decodeContent(const QByteArray& source, QByteArray& target); + QString encodeName(const QString& name); + QByteArray& encodeName(const QByteArray& name); + void encodeContent(const QByteArray& source, QByteArray& target); + virtual int listInfos(const ReIncludeExcludeMatcher& matcher, + ReFileMetaDataList& list); + virtual ErrorCode makeDir(const QString& node); + virtual ErrorCode read(const ReFileMetaData& source, int64_t offset, + int size, QByteArray& buffer); + virtual ErrorCode write(const QString& target, int64_t offset, + const QByteArray& buffer); + +protected: + ReFileSystem& m_host; + ReRandomizer& m_contentRandom; + ReRandomizer& m_nameRandom; + QByteArray m_contentSeed; + QByteArray m_nameSeed; + QByteArray m_buffer; +protected: + static const int m_indexOfNodeChar[]; + static const char m_nodeChars[]; + static const int m_countNodeChars; +}; #endif /* OS_REFILESYSTEM_HPP_ */ diff --git a/tools/mk_nodeChar.pl b/tools/mk_nodeChar.pl new file mode 100644 index 0000000..966691f --- /dev/null +++ b/tools/mk_nodeChar.pl @@ -0,0 +1,29 @@ +#! /usr/bin/perl + +use strict; +my (@index, @chars); + +push @index, "const int ReCryptFileSystem::m_indexOfNodeChar[] = {"; +push @chars, "const char ReCryptFileSystem::m_nodeChars[] = {"; + +for (0..31){ + push @index, "-1,"; +} +my $ix = 0; +for (32..127){ + my $cc = chr($_); + if ($cc !~ m!["*:?<>;\\/]!){ + push @index, $ix++ . ","; + if ($cc eq "'"){ + push @chars, "'\\'',"; + } else { + push @chars, "'$cc',"; + } + } else { + push @index, "-1,"; + } +} +print join("\n", @index), "\n"; +print "};\n"; +print join("\n", @chars), "\n"; +print "};\n"; -- 2.39.5