From 144b7619383c8ddba282b71aa5614742c84ea96c Mon Sep 17 00:00:00 2001 From: hama Date: Mon, 9 Nov 2015 00:25:10 +0100 Subject: [PATCH] dayly work --- base/ReQStringUtils.cpp | 2 +- base/ReRandomizer.cpp | 158 +++++++++++----------- base/ReRandomizer.hpp | 41 ++++-- cunit/allTests.cpp | 2 +- cunit/cuReRandomizer.cpp | 50 ++++++- net/renet.hpp | 2 +- os/ReCryptFileSystem.cpp | 277 +++++++++++++++++++++++++++++++++++++-- os/ReCryptFileSystem.hpp | 55 +++++++- os/ReFileSystem.cpp | 9 +- 9 files changed, 479 insertions(+), 117 deletions(-) diff --git a/base/ReQStringUtils.cpp b/base/ReQStringUtils.cpp index 4cd1ea2..1f6e4f1 100644 --- a/base/ReQStringUtils.cpp +++ b/base/ReQStringUtils.cpp @@ -79,7 +79,7 @@ QString& ReQStringUtils::ensureLastChar(QString& value, QChar lastChar) { * otherwise: the length of the integer */ int ReQStringUtils::lengthOfUInt64(const ReString& text, int start, int radix, - int64_t* pValue) { + uint64_t* pValue) { int inputLength = text.size(); int64_t value = 0; int ix = start; diff --git a/base/ReRandomizer.cpp b/base/ReRandomizer.cpp index 29e3ab0..40db7fe 100644 --- a/base/ReRandomizer.cpp +++ b/base/ReRandomizer.cpp @@ -169,6 +169,23 @@ const int ReNameScrambler::m_countNodeChars = sizeof ReNameScrambler::m_nodeChars; +/** + * Returns the hash value as hex string. + * + * Note: After call of this method the hash is reset! + * + * @return the hash value as hex string, stored in "little endian" byte order + */ +QByteArray ReDigest::hexDigest() +{ + QByteArray rc; + QByteArray hash = digest(); + for (int ix = 0; ix < hash.length(); ix++){ + rc.append(ReStringUtils::toNumber(hash.at(ix) & 0xff, "%02x")); + } + return rc; +} + /** * Contructor. * @@ -180,33 +197,40 @@ ReHmHash64::ReHmHash64(int64_t factor, int64_t increment) : m_increment(increment), m_hash(0), m_sumLength(0), - m_closed(false), - m_littleEndian(true) + m_rest() { - int src = 1; - int trg = 0; - memcpy(&trg, &src, 1); - m_littleEndian = trg != 0; } /** * Return the hash value as 64 bit integer. * + * Note: After call of this method the hash is reset! + * * @return the hash value as 64 bit integer */ int64_t ReHmHash64::digestAsInt() { - if (! m_closed){ - m_closed = true; - m_hash ^= (m_sumLength ^ 0x2011195811081965L) * m_factor - + (m_increment >> m_sumLength % 29); +# define CalcNextHash(data) m_hash ^= (data ^ 0x2004199111121989L) \ + * m_factor + (m_increment >> (data % 23)) + // ; printf("%016lx: -> %016lx\n", data, m_hash) + + int64_t rc; + if (m_rest.length() > 0){ + rc = 0; + memcpy(&rc, m_rest.constData(), m_rest.length()); + CalcNextHash(rc); } - return m_hash; + CalcNextHash(m_sumLength); + rc = m_hash; + reset(); + return rc; } /** * Returns the hash value as byte array. * + * Note: After call of this method the hash is reset! + * * @return the hash value as byte array, stored in "little endian" byte order */ QByteArray ReHmHash64::digest() @@ -214,26 +238,7 @@ QByteArray ReHmHash64::digest() QByteArray rc; rc.resize(sizeof m_hash); int64_t value = digestAsInt(); - if (m_littleEndian){ - * (int64_t*) rc.data() = value; - } else { - memcpy(rc.data(), &value, sizeof m_hash); - } - return rc; -} - -/** - * Returns the hash value as hex string. - * @return the hash value as hex string, stored in "big endian" byte order - */ -QByteArray ReHmHash64::hexDigest() -{ - QByteArray rc; - int size = sizeof m_hash * 2; - rc.reserve(size); - rc = QByteArray::number((qlonglong) digestAsInt(), 16); - if (rc.length() != size) - rc.insert(0, QByteArray("0000000000000000").mid(0, size - rc.length())); + memcpy(rc.data(), &value, sizeof m_hash); return rc; } @@ -244,17 +249,7 @@ QByteArray ReHmHash64::hexDigest() */ void ReHmHash64::reset(){ m_hash = m_sumLength = 0; - m_closed = false; -} - -/** - * Sets the flag "handle as little endian". - * - * @param littleEndian true: the byte order is "little endian" - */ -void ReHmHash64::setLittleEndian(bool littleEndian) -{ - m_littleEndian = littleEndian; + m_rest.clear(); } /** @@ -264,45 +259,34 @@ void ReHmHash64::setLittleEndian(bool littleEndian) * @param source the data block which will be added to the hash * @param length the length of the data (in bytes) */ -void ReHmHash64::update(void* source, size_t length) +void ReHmHash64::update(const void* source, size_t length) { -#define CalcNextHash(data) m_hash ^= (data ^ 0x2004199111121989L) \ - * m_factor + (m_increment >> (data % 23)) + const uint8_t* src = reinterpret_cast(source); int64_t data; - if (m_sumLength % sizeof m_hash != 0) - ReLogger::logv(LOG_ERROR, LOC_UPDATE_1, - "ReHmHash64::update() non last block called with wrong length: %d", - m_sumLength); m_sumLength += length; - if (m_littleEndian){ - const int64_t* src = reinterpret_cast(source); - for (int ix = length / sizeof m_hash - 1; ix >= 0; ix--){ - data = *src++; - CalcNextHash(data); - } - int rest = length % sizeof m_hash; - if (rest > 0){ - data = 0; - memcpy(&data, src, rest); - data <<= sizeof m_hash - rest; - CalcNextHash(data); - } - } else { - const int8_t* src = reinterpret_cast(source); - for (int ix = length / sizeof m_hash - 1; ix >= 0; ix--){ - data = 0; - for (int ix2 = 0; ix2 < 8; ix2++) - data |= (*src++ << ix2 * 8); - CalcNextHash(data); - } - int rest = length % sizeof m_hash; - if (rest > 0){ - data = 0; - memcpy(&data, src, rest); - data <<= sizeof m_hash - rest; + if (m_rest.length() > 0){ + size_t needed = sizeof m_hash - m_rest.length(); + if (needed > length){ + m_rest.append(reinterpret_cast(src), length); + length = 0; + } else { + m_rest.append(reinterpret_cast(src), needed); + length -= needed; + src += needed; + memcpy(&data, m_rest.constData(), sizeof data); CalcNextHash(data); + m_rest.clear(); } } + for (int ix = length / sizeof m_hash - 1; ix >= 0; ix--){ + memcpy(&data, src, sizeof data); + src += sizeof data; + CalcNextHash(data); + } + int rest = length % sizeof m_hash; + if (rest > 0){ + m_rest.append(reinterpret_cast(src), rest); + } } /** @@ -442,6 +426,30 @@ char ReRandomizer::nextChar() { return rc; } +/** + * @brief Returns binary data with random bytes. + * + * @param minLength The minimum length of the result data + * @param maxLength The maximum length of the result data + * @param buffer OUT: The place for the data + * + * @return buffer (for chaining) + */ +QByteArray& ReRandomizer::nextData(int minLength, int maxLength, + QByteArray &buffer) { + int len = nextInt(maxLength, minLength); + buffer.resize(len); + seed_t data; + seed_t* ptr = reinterpret_cast(buffer.data()); + for (int ix = len / sizeof data - 1; ix >= 0; ix--) + *ptr = nextSeed64(); + if (len % sizeof data != 0){ + data = nextSeed64(); + memcpy(ptr, &data, len % sizeof data); + } + return buffer; +} + /** * @brief Returns the next random integer. * diff --git a/base/ReRandomizer.hpp b/base/ReRandomizer.hpp index 31d13da..6cfec37 100644 --- a/base/ReRandomizer.hpp +++ b/base/ReRandomizer.hpp @@ -13,33 +13,48 @@ #define RANDOMIZER_H_ /** - * Pure abstract base class for hash generators. + * Abstract base class for hash generators. */ class ReDigest { public: /** Returns the hash value as byte array. + * Note: After call of this method the hash is reset! * @return the hash value as byte array, stored in "little endian" byte order */ virtual QByteArray digest() = 0; - /** Returns the hash value as hex string. - * @return the hash value as hex string, stored in "little endian" byte order - */ - virtual QByteArray hexDigest() = 0; /** Resets the hash. - * The state is equal after the constructor. + * The state of the instance is the same as after the constructor. */ virtual void reset() = 0; - /** Adds the content of a block to the hash. + /** Adds the data to the hash. * @param source the data block which will be added to the hash * @param length the length of the data (in bytes) */ - virtual void update(void* source, size_t length) = 0; + virtual void update(const void* source, size_t length) = 0; +public: + QByteArray hexDigest(); + /** Adds the data to the hash. + * @param source the data block which will be added to the hash + */ + inline virtual void updateBlock(const QByteArray& source){ + update(source.constData(), source.length()); + } }; /** * Implements a very simple (and cheap) checksum. + * + * Features: + *
  • If one bit of the content is changed normally many bits of the sum + * are changed
  • + *
  • If a '\\0' is appended to a sequence of '\\0'' many bits of the sum + * are change too
  • + *
  • 64 bit checksum: low likelihood of collision
  • + *
  • Only 6 basic 64 bit operations (*, 2 ^, +, %, >>) per 8 byte content
  • + *
  • Works for little/big endian architectures
  • + *
*/ -class ReHmHash64 : ReDigest{ +class ReHmHash64 : public ReDigest{ public: ReHmHash64(int64_t factor = 0x70cf79d585f5a313L, int64_t increment = 0x75c280b9881252dbL); @@ -47,18 +62,15 @@ public: int64_t digestAsInt(); public: virtual QByteArray digest(); - virtual QByteArray hexDigest(); virtual void reset(); - virtual void setLittleEndian(bool littleEndian); - virtual void update(void* source, size_t length); + virtual void update(const void* source, size_t length); private: int64_t m_factor; int64_t m_increment; int64_t m_hash; int64_t m_sumLength; - bool m_closed; - bool m_littleEndian; + QByteArray m_rest; }; /** @@ -78,6 +90,7 @@ public: const QByteArray& name() const; seed_t nearTrueRandom(); char nextChar(); + QByteArray& nextData(int minLength, int maxLength, QByteArray& buffer); int nextInt(int maxValue = INT_MAX, int minValue = 0); int64_t nextInt64(int64_t maxValue = LLONG_MAX, int64_t minValue = 0); const char* nextString(int minLength, int maxLength, QByteArray& buffer); diff --git a/cunit/allTests.cpp b/cunit/allTests.cpp index 499b20b..192e6a2 100644 --- a/cunit/allTests.cpp +++ b/cunit/allTests.cpp @@ -41,8 +41,8 @@ static void testBase() { void testReWriter(); void testReFile(); void testReMatcher(); - testReFileUtils(); testReRandomizer(); + testReFileUtils(); testReMatcher(); testReQStringUtil(); testReFile(); diff --git a/cunit/cuReRandomizer.cpp b/cunit/cuReRandomizer.cpp index 2504851..17ccd8d 100644 --- a/cunit/cuReRandomizer.cpp +++ b/cunit/cuReRandomizer.cpp @@ -349,15 +349,27 @@ public: hash.update((void*) "12345678abcdefghABC", 8+8+3); int64_t value = hash.digestAsInt(); hash.reset(); - hash.update((void*) "12345678", 8); - hash.update((void*) "abcdefgh", 8); + hash.update((void*) "1234567", 7); + hash.update((void*) "8abcdefgh", 9); hash.update((void*) "ABC", 3); checkEqu(value, hash.digestAsInt()); + ReKISSRandomizer random; + for (int ii = 0; ii < 1000; ii++){ + QByteArray string; + random.nextString(1, 64, string); + testOneHash(string, random); + } + for (int ii = 0; ii < 1000; ii++){ + QByteArray data; + random.nextData(1, 64, data); + testOneHash(data, random); + } printHash("a"); printHash("b"); printHash("aa"); printHash("ab"); + printHash("ba"); printHash("aaa"); printHash("aab"); printHash("aaaa"); @@ -375,16 +387,42 @@ public: printBinary(ix); log("ready"); } + void testOneHash(QByteArray source, ReRandomizer& random){ + ReHmHash64 hash; + hash.update(source.constData(), source.length()); + int64_t value = hash.digestAsInt(); + + while (source.length() > 8){ + int count = random.nextInt(1, source.length() - 1); + hash.updateBlock(source.mid(0, count)); + source.remove(0, count); + } + hash.updateBlock(source); + checkEqu(value, hash.digestAsInt()); + } + + void hashPerformance(){ + ReHmHash64 hash; + QByteArray data; + data.fill('x', 1024*1024); + clock_t start = clock(); + int count = 100; + for (int ix = 0; ix < 100; ix++){ + hash.update((void*) data.constData(), data.length()); + } + double duration = double (clock() - start) / CLOCKS_PER_SEC; + printf("ReHmHash64: %.3f sec %.3f MByte/sec\n", duration, + count / duration); + } + void special(){ - ReKISSRandomizer rand; - rand.dump(); - rand.nextSeed64(); - rand.dump(); log("ready"); } virtual void run(void) { + special(); testReHmHash64(); + hashPerformance(); testNextString(); testRealRandom(); testShuffle(); diff --git a/net/renet.hpp b/net/renet.hpp index 71bbb0d..489f3f9 100644 --- a/net/renet.hpp +++ b/net/renet.hpp @@ -21,7 +21,7 @@ #include "net/ReTCPPeer.hpp" #include "net/ReTCPServer.hpp" -#include "net/ReTCPClient.hpp" +#include "net/ReTcpClient.hpp" #include "net/ReNetConfig.hpp" #endif // RPLNET_HPP diff --git a/os/ReCryptFileSystem.cpp b/os/ReCryptFileSystem.cpp index a4f93ec..8b4aa2f 100644 --- a/os/ReCryptFileSystem.cpp +++ b/os/ReCryptFileSystem.cpp @@ -18,14 +18,24 @@ * checksum (from offset 16) (8 byte, encrypted with resetted random) * marker (2 byte, encrypted with resetted random) * flags (2 byte) see ReFileHeaderOptions - * reserved (4 byte) + * dynamic filelength (4 byte) * encrypted file content * checksum of the original file content * - * Checksum: sum_n ^= content_n * FAC + INC, - * operands 8 byte signed integer, little endian - * missing bytes (to 8 byte boundary) are padded with 0 - * FAC=0x7b644ac5d1187d25, INC=0x6b85115d6064365b + * Calculation of the checksum:
+ * Algorithm: see ReHmHash64 + * factor=0x7b644ac5d1187d25, increment=0x6b85115d6064365b + * + * Checksum of the unencrypted file content: straight forward + * + * Checksum of the encrypted data:
+ *
  • Reset hash
  • + *
  • Encrypt data and add it to the hash
  • + *
  • Encrypt the checksum of the unencrypted data and add it to the hashStore the data length (without checksum) to the headerAdd the header from offset 16 to the hash
  • + *
  • Add the checksum in the header at offset 8
  • + *
*/ enum { LOC_ADD_ENTRY_1 = LOC_FIRST_OF(LOC_CRYPTFILESYSTEM), // 12301 @@ -36,6 +46,8 @@ enum { LOC_WRITE_META_1, // 12306 LOC_WRITE_META_2, // 12307 LOC_MAKE_DIR_1, // 12308 + LOC_FILE_OPEN_1, // 12309 + LOC_FILE_WRITE_1, // 12310 }; const int ReCryptFileSystem::NODE_LENGHT = 44; @@ -53,6 +65,12 @@ const int ReCryptDirectory::META_DIR_HEADER_LENGTH = sizeof(int64_t) // space for the struct and the node: const int ReCryptDirectory::MAX_ENTRY_SIZE = sizeof(ReCryptDirectory::FileEntry_t) + 512; +const int ReCryptDirectory::FILE_MARKER_LENGTH = 2; +const int ReCryptDirectory::FILE_FLAGS_LENGTH = 2; +const int ReCryptDirectory::FILE_LENGTH_LENGTH = 4; +const int ReCryptDirectory::FILE_HEADER_LENGTH = 2 * sizeof(int64_t) + + FILE_MARKER_LENGTH + FILE_FLAGS_LENGTH + FILE_LENGTH_LENGTH; +const int ReCryptDirectory::FILE_CHECKSUM_LENGTH = sizeof(int64_t); /** * Constructor. @@ -223,7 +241,9 @@ ReFileSystem::ErrorCode ReCryptFileSystem::setProperties(const ReFileMetaData& s */ ReFileSystem::ErrorCode ReCryptFileSystem::write(const QString& target, int64_t offset, const QByteArray& buffer) { - return EC_SUCCESS; + m_contentRandom.reset(); + QByteArray m_header; + return writeFileBlock(target, offset, buffer); } /** @@ -251,7 +271,7 @@ ReCryptDirectory::ReCryptDirectory(ReRandomizer& contentRandom, ReCryptFileSystem* parent, ReLogger* logger) : ReByteScrambler(contentRandom, logger), m_list(), - m_parent(parent), + m_parentFS(parent), m_changed(false), m_logger2(logger), m_currentNode(), @@ -328,6 +348,16 @@ int ReCryptDirectory::buildId(const QString& hostedNode) const{ return id; } +/** + * Returns the buffer for file data blocks. + * + * @return the file buffer + */ +QByteArray& ReCryptDirectory::fileBuffer() +{ + return m_fileBuffer; +} + /** * Search an file entry by name. * @@ -348,6 +378,26 @@ const ReFileMetaData* ReCryptDirectory::find(const QString& node) const return rc; } +/** + * Returns the logger. + * + * @return the logger + */ +ReLogger*ReCryptDirectory::logger() const +{ + return m_logger2; +} + +/** + * Returns the parent filesystem. + * + * @return the parent filesystem + */ +ReCryptFileSystem* ReCryptDirectory::parentFS() const +{ + return m_parentFS; +} + /** * Removes an entry given by the name. * @@ -366,7 +416,7 @@ bool ReCryptDirectory::removeEntry(const QString& node) //@ToDo: //m_list.removeOne(entry2); assert(false); - ReFileSystem& host = m_parent->host(); + ReFileSystem& host = m_parentFS->host(); ReFileMetaData hostedFile; QString hostedNode = buildHostedNode(entry->m_id); if (host.first(hostedNode, hostedFile)) @@ -385,7 +435,7 @@ bool ReCryptDirectory::readMetaFile() { bool rc = true; m_list.clear(); - QString fnMetaFile = m_parent->directory() + ReCryptFileSystem::NODE_META_DIR; + QString fnMetaFile = m_parentFS->directory() + ReCryptFileSystem::NODE_META_DIR; FILE* fp = fopen(fnMetaFile.toUtf8().constData(), "rb"); m_maxFileId = 0; if (fp != NULL){ @@ -454,7 +504,7 @@ bool ReCryptDirectory::writeMetaFile() int length = node.length(); meta2->m_size += length + (length < 256 ? 0 : 1); } - QString fnMetaFile = m_parent->directory() + ReCryptFileSystem::NODE_META_DIR; + QString fnMetaFile = m_parentFS->directory() + ReCryptFileSystem::NODE_META_DIR; FILE* fp = fopen(fnMetaFile.toUtf8().constData(), "rb"); if (fp == NULL){ m_logger->logv(LOG_ERROR, LOC_WRITE_META_1, "cannot write (%d): %s", @@ -538,6 +588,25 @@ void ReCryptDirectory::splitBlock(bool isLast, QByteArray& block){ block.remove(0, srcPtr - block.constData()); printf("List: %d Rest: %d\n", m_list.length(), block.length()); } + +/** + * Returns the block size. + * @return the block size + */ +int ReCryptDirectory::blockSize() const +{ + return m_blockSize; +} +/** + * Sets the block size. + * + * @param blockSize the new block size + */ +void ReCryptDirectory::setBlockSize(int blockSize) +{ + m_blockSize = blockSize; +} + /** * Gets the filename of an entry in the hosted filesystem. * @@ -547,7 +616,193 @@ void ReCryptDirectory::splitBlock(bool isLast, QByteArray& block){ const QString& ReCryptDirectory::hostedFilename(const ReFileMetaData& entry) { QString node = buildHostedNode(entry.m_id); - m_currentNode = ReFileUtils::pathAppend(m_parent->directory(), node); + m_currentNode = ReFileUtils::pathAppend(m_parentFS->directory(), node); return m_currentNode; } +/** + * Writes a buffer to a file. + * + * @param target the file to write (without path, inside the current directory) + * @param offset first position to write + * @param buffer content to write + * @return EC_SUCCESS or error code + */ +ReFileSystem::ErrorCode ReCryptDirectory::writeFileBlock(const QString& target, + int64_t offset, const QByteArray& buffer) +{ + ReFileSystem::ErrorCode rc = ReFileSystem::EC_SUCCESS; + + if (offset == 0){ + ReFileMetaData metaData; + if (! m_parentFS->m_parentFS->exists(target, &metaData)){ + QDateTime now = QDateTime::currentDateTime(); + metaData.m_node = target; + metaData.m_modified = now; + metaData.m_created = now; + metaData.m_owner = m_parentFS->osPermissions().m_user; + metaData.m_group = m_parentFS->osPermissions().m_group; + metaData.m_mode = m_parentFS->osPermissions().m_fileMode; + metaData.m_size = buffer.length() + ReCryptDirectory::FILE_HEADER_LENGTH + + ReCryptDirectory::FILE_CHECKSUM_LENGTH; + metaData.m_id = ++m_maxFileId; + } + } + return rc; +} + +/** + * Constructor. + * + * @param meta the file infos + * @param directory the assoziated directory + */ +ReCryptFile::ReCryptFile(const ReFileMetaData& meta, ReCryptDirectory& directory) : + m_metaData(meta), + m_fullHostedName((directory.parentFS()->host().directory() + + directory.parentFS()->buildHostedNode(meta.m_id)).toUtf8()), + m_fileHeader(), + m_dataSum(0x7b644ac5d1187d25L, 0x6b85115d6064365bL), + m_sumOfEncrypted(0x7b644ac5d1187d25L, 0x6b85115d6064365bL), + m_fp(NULL), + m_directory(directory), + m_dataSize(0) +{ +} + +/** + * Destructor. + */ +ReCryptFile::~ReCryptFile() +{ + close(); +} + +/** + * Initializes the file for reading/writing. + * + * @param writeable true: the file can be written + * @return EC_SUCCESS: success
+ * x + */ +ReFileSystem::ErrorCode ReCryptFile::open(bool writeable) +{ + ReFileSystem::ErrorCode rc = ReFileSystem::EC_SUCCESS; + close(); + m_fp = fopen(m_fullHostedName, writeable? "wb" : "rb"); + if (m_fp == NULL){ + m_directory.logger()->logv(LOG_ERROR, LOC_FILE_OPEN_1, "cannot open hosted file (%d): %s", + errno, m_fullHostedName.constData()); + rc = writeable ? ReFileSystem::EC_NOT_WRITEABLE : ReFileSystem::EC_NOT_READABLE; + } + return rc; +} + +/** + * Writes a block to the hosted file. + * + * @param data data to write + * @return EC_SUCCESS: success + */ +ReFileSystem::ErrorCode ReCryptFile::writeBlock(const QByteArray& data){ + ReFileSystem::ErrorCode rc = ReFileSystem::EC_SUCCESS; + if (m_fp != NULL && fwrite(data.constData(), data.length(), 1, m_fp) + != size_t(data.length())){ + m_directory.logger()->logv(LOG_ERROR, LOC_FILE_WRITE_1, + "cannot write (%d): %s", errno, m_fullHostedName.constData()); + rc = ReFileSystem::EC_NOT_WRITEABLE; + fclose(m_fp); + m_fp = NULL; + } + return rc; +} + +/** + * Writes a data block to the file. + * + * @param data + * @return + */ +ReFileSystem::ErrorCode ReCryptFile::write(const QByteArray& data) +{ + ReFileSystem::ErrorCode rc = ReFileSystem::EC_SUCCESS; + m_dataSum.updateBlock(data); + QByteArray& target = m_directory.fileBuffer(); + int blockSize = m_directory.blockSize(); + if (m_dataSize > 0 && m_dataSize <= blockSize){ + // write the header... + if ( (rc = writeBlock(m_fileHeader)) == ReFileSystem::EC_SUCCESS) + // and the first block... + rc = writeBlock(target); + target.clear(); + } + m_dataSize += data.length(); + if (rc == ReFileSystem::EC_SUCCESS){ + m_directory.encodeContent(data, target); + m_sumOfEncrypted.updateBlock(target); + } + return rc; +} + +/** + * Calculates the "dynamic length". + * + * The dynamic length is the length if it can be stored in a 32 bit integer. + * If the length is greater it will be shifted to right until 32 bit is enough. + * + * @param length the 64 bit length + * @return the dynamic length + */ +uint32_t ReCryptFile::dynamicLength(int64_t length) { + while (length > 0xFFFFffffL) + length >>= 1; + return uint64_t(length); +} + +/** + * Flush data and free resources. + * + * @return EC_SUCCESS: success + */ +ReFileSystem::ErrorCode ReCryptFile::close() +{ + ReFileSystem::ErrorCode rc = ReFileSystem::EC_SUCCESS; + if (m_fp != NULL){ + QByteArray& target = m_directory.fileBuffer(); + int blockSize = m_directory.blockSize(); + bool doFlush = m_dataSize > 0 && m_dataSize <= blockSize; + m_metaData.m_size = m_dataSize; + QByteArray checkSum = m_dataSum.digest(); + + // Add the data checksum at the end of the data block: + target.append(reinterpret_cast(&checkSum), sizeof checkSum); + // Update the encrypted checksum: + m_sumOfEncrypted.update(&checkSum, sizeof checkSum); + + // Update the protected part of the header info: + uint32_t size = dynamicLength(m_dataSize); + memcpy(m_fileHeader.data() + sizeof(ReRandomizer::seed_t) + + ReCryptDirectory::FILE_FLAGS_LENGTH, &size, sizeof size); + + // Add the protected part of the header to the encrypted checksum: + m_sumOfEncrypted.update(m_fileHeader.constData() + 2 * sizeof(int64_t), + m_fileHeader.length() - 2 * sizeof(int64_t)); + // update the unprotected part of the header: + memcpy(m_fileHeader.data() + sizeof(ReRandomizer::seed_t), &checkSum, + sizeof checkSum); + + if (doFlush) + target.insert(0, m_fileHeader); + rc = writeBlock(target); + target.clear(); + if (m_fp != NULL && ! doFlush){ + fseek(m_fp, 0, SEEK_SET); + rc = writeBlock(m_fileHeader); + } + if (m_fp != NULL){ + fclose(m_fp); + m_fp = NULL; + } + } + return rc; +} diff --git a/os/ReCryptFileSystem.hpp b/os/ReCryptFileSystem.hpp index d247076..71a4584 100644 --- a/os/ReCryptFileSystem.hpp +++ b/os/ReCryptFileSystem.hpp @@ -12,7 +12,39 @@ class ReCryptFileSystem; -class ReCryptDirectory : protected ReByteScrambler{ +class ReCryptDirectory; +/** + * Administrates an encrypted file for reading / writing. + */ +class ReCryptFile { +public: + ReCryptFile(const ReFileMetaData& metaData, ReCryptDirectory& directory); + ~ReCryptFile(); +public: + ReFileSystem::ErrorCode open(bool writeable); + ReFileSystem::ErrorCode write(const QByteArray& data); + ReFileSystem::ErrorCode close(); +public: + static uint32_t dynamicLength(int64_t length); +protected: + ReFileSystem::ErrorCode writeBlock(const QByteArray& data); +private: + ReFileMetaData m_metaData; + QByteArray m_fullHostedName; + QByteArray m_fileHeader; + /// checksum of the unencrypted data + ReHmHash64 m_dataSum; + /// checksum of the encrypted data + ReHmHash64 m_sumOfEncrypted; + FILE* m_fp; + ReCryptDirectory& m_directory; + int64_t m_dataSize; +}; + +/** + * Administrates an encrypted directory. + */ +class ReCryptDirectory : public ReByteScrambler{ public: typedef struct { int64_t m_size; @@ -33,17 +65,24 @@ public: } MetaInfo_t; public: ReCryptDirectory(ReRandomizer& contentRandom, ReCryptFileSystem* parent, - ReLogger* logger); + ReLogger* logger); ~ReCryptDirectory(); public: bool addEntry(ReFileMetaData& entry); + int blockSize() const; + QString buildHostedNode(int id) const; + QByteArray& fileBuffer(); const ReFileMetaData* find(const QString& node) const; + ReLogger* logger() const; + ReCryptFileSystem* parentFS() const; bool removeEntry(const QString& entry); bool readMetaFile(); + void setBlockSize(int blockSize); + ReFileSystem::ErrorCode writeFileBlock(const QString& target, int64_t offset, + const QByteArray& buffer); bool writeMetaFile(); protected: int buildId(const QString& hostedNode) const; - QString buildHostedNode(int id) const; const QString& hostedFilename(const ReFileMetaData& entry); void splitBlock(bool isLast, QByteArray& block); public: @@ -51,9 +90,15 @@ public: static const int META_INFO_LENGTH; static const int META_DIR_HEADER_LENGTH; static const int MAX_ENTRY_SIZE; + static const int FILE_MARKER_LENGTH; + static const int FILE_FLAGS_LENGTH; + static const int FILE_LENGTH_LENGTH; + static const int FILE_HEADER_LENGTH; + static const int FILE_CHECKSUM_LENGTH; + protected: ReFileMetaDataList m_list; - ReCryptFileSystem* m_parent; + ReCryptFileSystem* m_parentFS; bool m_changed; // to avoid ambigousity: ReLogger* m_logger2; @@ -74,7 +119,7 @@ protected: * will be encrypted. In the other direction the file content will be decrypted. */ class ReCryptFileSystem: public ReFileSystem, - protected ReCryptDirectory + public ReCryptDirectory { public: static const int NODE_LENGHT; diff --git a/os/ReFileSystem.cpp b/os/ReFileSystem.cpp index 7fc22ee..9e87349 100644 --- a/os/ReFileSystem.cpp +++ b/os/ReFileSystem.cpp @@ -84,6 +84,7 @@ ReFileSystem* ReFileSystem::buildFromUrl(const QString& url) #error "missing evaluating drive" #endif } + return rc; } /** @@ -433,7 +434,7 @@ int ReLocalFileSystem::listInfos(const ReIncludeExcludeMatcher& matcher, full.append(node.toUtf8()); if (stat(full.constData(), &info) == 0) { bool isDir = S_ISDIR(info.st_mode); - if (isDir && ! withDirs || ! isDir && ! withFiles) + if ((isDir && ! withDirs) || (! isDir && ! withFiles)) continue; if (! earlyMatching){ if ( (! isDir || matchDirs) && ! matcher.matches(node)) @@ -754,10 +755,11 @@ ReFileMetaData::ReFileMetaData() : m_node(), m_modified(), m_created(), + m_size(-1), m_owner(-1), m_group(-1), - m_mode(-1), - m_size(-1) { + m_mode(-1) +{ } @@ -870,5 +872,6 @@ ReOSPermissions&ReOSPermissions::operator =(const ReOSPermissions& source) m_group = source.m_group; m_fileMode = source.m_fileMode; m_dirMode = source.m_dirMode; + return *this; } -- 2.39.5