From: J. Hamatoma Date: Sat, 30 Nov 2013 11:22:06 +0000 (+0100) Subject: dayly work X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=72c2a8e1700f5b9b737addc336d682422dcb5a33;p=reqt dayly work --- diff --git a/rplmath/rplenigma.cpp b/rplmath/rplenigma.cpp index 1f03068..18f8643 100644 --- a/rplmath/rplenigma.cpp +++ b/rplmath/rplenigma.cpp @@ -19,8 +19,10 @@ * More than one certificate can be used. * * The encryption is done with an pseudo random generator. - * The portability (over the hardware architecture) is guaranteed if the - * pseudo random generator is portable. + * + * The portability (over byte order) is guaranteed if the + * pseudo random generator is portable (nomalizing big/little endian) + * and a 64 bit integer arithmetic is available. * */ /** @@ -31,9 +33,11 @@ RplEnigma::RplEnigma(RplRandom* random) : m_random(random), m_ownsRandom(false), - m_byteSeeds(), - m_ixSeed(0) + m_secrets(), + m_randomCalls(0), + m_randomSource("4711") { + m_randomSource.reserve(8096); if (random == NULL){ m_random = new RplRandom(); m_ownsRandom = true; @@ -42,7 +46,12 @@ RplEnigma::RplEnigma(RplRandom* random) : /** * @brief Destructor. */ -RplEnigma::~RplEnigma(); +RplEnigma::~RplEnigma(){ + if (m_ownsRandom){ + delete m_random; + m_random = NULL; + } +} /** * @brief Reads a certificate. @@ -58,39 +67,168 @@ QByteArray RplEnigma::readCertificate(const char* filename){ return rc; } +inline void buildBooster(QByteArray& booster, const char* charSet){ + int size = 256; + booster.fill(0, size); + int ix = 0; + char cc; + while( (cc = *charSet++) != '\0'){ + booster[cc] = ++ix; + } + booster[0] = ix; +} + +/** + * @brief Encodes a string in place with a given character set. + * + * If a character of data is not included in the character set + * it remains unchanged + * + * @param data IN: data to encode
+ * OUT: data encoded + * @param size length of data. If 0 + * @param charSet a string containing all valid characters + * @param booster a performance booster. Once built it can be shared + * between all calls of encodeChar() and decodeChar() + * with the same character set
+ * IN: "": not initialized otherwise: ready for work + * OUT: ready for work + */ +void RplEnigma::encode(char* data, int size, const char* charSet, QByteArray& booster){ + if (booster.length() == 0){ + buildBooster(booster, charSet); + } + int lengthOfCharSet = booster.at(0); + for (int ii = 0; ii < size; ii++){ + char cc = *data; + int ix = booster.at(cc); + if (ix != 0){ + ix = (ix + nextInt(lengthOfCharSet)) % lengthOfCharSet; + *data++ = charSet[ix]; + } + } +} +/** + * @brief Decodes a string in place with a given character set. + * + * If a character of data is not included in the character set + * it remains unchanged + * + * @param data IN: data to decode
+ * OUT: data decoded + * @param size length of data. If 0 + * @param charSet a string containing all valid characters + * @param booster a performance booster. Once built it can be shared + * between all calls of encodeChar() and decodeChar() + * with the same character set
+ * IN: "": not initialized otherwise: ready for work + * OUT: ready for work + */ +void RplEnigma::decode(char* data, int size, const char* charSet, QByteArray& booster){ + if (booster.length() == 0){ + buildBooster(booster, charSet); + } + int lengthOfCharSet = booster.at(0); + for (int ii = 0; ii < size; ii++){ + char cc = *data; + int ix = booster.at(cc); + if (ix != 0){ + ix = (lengthOfCharSet + ix - nextInt(lengthOfCharSet)) % lengthOfCharSet; + *data++ = charSet[ix]; + } + } +} /** - * @brief Encodes one character. + * @brief Encodes or decode a byte array. + * + * The encoding method is symetric. Therefore it can encode and decode. * - * @param byte value to encode - * @param mode affects the possible values of the result - * @return the encoded character + * @param data IN: data to encode/decoded
+ * OUT: data encoded/decoded */ -char RplEnigma::encodeChar(char byte, mode_t mode = MODE_STANDARD){ - char rc = 0; +void RplEnigma::change(QByteArray& data){ + int randomLength = m_randomSource.length(); + for (int ix = data.length() - 1; ix >= 0; ix--){ + char item = data.at(ix); + item = (item ^ nextInt(0xff) ^ m_randomSource.at(ix % randomLength)); + data[ix] = item; + } +} - switch(mode){ - case MODE_DECIMAL: +/** + * @brief Adds a random source given by an byte array. + * + * A random source can be the binary form of an certificate, + * a salt, a password or similar. + * + * @param byteSecret a byte sequence which influences the random generation + */ +void RplEnigma::addByteSecret(QByteArray byteSecret){ + // we expand it to a multiple of 64 bit: + int oldSize = byteSecret.length(); + int newSize = (oldSize + 7) / 8 * 8; + int ix; + if (newSize > oldSize){ + byteSecret.resize(newSize); + int sum = 0; + int start = oldSize > 8 ? oldSize - 8 : 0; + for (ix = start; ix < oldSize; ix++){ + sum += ix + byteSecret.at(ix); + } + for (ix = oldSize; ix < newSize; ix--){ + sum += ix + 7; + byteSecret[ix] = (char) (sum + byteSecret.at(ix-1)); + } + } + int count = newSize / 8; + secret_t* secret = new secret_t(); + secret->m_count = count; + secret->m_list = new u_int64_t[count]; + m_secrets.append(secret); + for (ix = 0; ix < count; ix++){ + u_int64_t value = 0; + for (int ix2 = 0; ix2 < 8; ix2++) + value = (value << 8) + byteSecret.at(ix * 8 + ix2); + secret->m_list[ix] = value; + } + QByteArray value; + QCryptographicHash hash(QCryptographicHash::Md5); + RplRandom rand; + hash.addData(m_randomSource.constData(), 4); + for (ix = 0; ix < byteSecret.length(); ix++){ + hash.addData(byteSecret.constData() + ix, 1); + QByteArray current = hash.result(); + int ix2 = rand.nextInt(0, m_randomSource.length() - 1); + m_randomSource[ix2] = (m_randomSource.at(ix2) ^ current.at(0)); + m_randomSource.insert(0, current); + } +} - break; - case MODE_HEXADECIMAL: - case MODE_ALPHA_NUMERIC: - case MODE_ASCII: - case MODE_CHAR255: - case MODE_FILENAME: - break; - case MODE_STANDARD: - default: - rc = - ; - break; +/** + * @brief Returns the next random integer + * @param maxValue + * @return + */ +int RplEnigma::nextInt(int maxValue){ + u_int64_t seed = 0; + QList::const_iterator it; + int ixSecret = m_randomCalls++; + int ix = ixSecret; + for (it = m_secrets.constBegin(); it != m_secrets.constEnd(); ++it){ + secret_t* secret = *it; + seed |= ((secret->m_list[ixSecret % secret->m_count]) >> (ix % 8)); } + m_random->xorSeed(seed); + int rc = m_random->nextInt(0, maxValue); return rc; } -void RplEnigma::encode(QByteArray& value, mode_t mode = MODE_STANDARD); -void RplEnigma::addByteSeed(const QByteArray& byteSeed); -void RplEnigma::setSeed(u_int64_t seed); - protected: - QList m_byteSeeds; - ///> each call of setSeed sets this value to 0. - int m_ixSeed; - }; + +/** + * @brief Sets the pseudo random to a define state. + * + * @param seed the initial state + */ +void RplEnigma::setSeed(u_int64_t seed){ + m_random->setSeed(seed); + m_randomCalls = 0; +} diff --git a/rplmath/rplenigma.hpp b/rplmath/rplenigma.hpp index 842c05e..9fa51b3 100644 --- a/rplmath/rplenigma.hpp +++ b/rplmath/rplenigma.hpp @@ -2,33 +2,42 @@ #define RPLENIGMA_HPP class RplEnigma { - public: - typedef enum { - MODE_STANDARD = 1, ///< no limitation - MODE_DECIMAL, ///< a decimal will be encrypted by an decimal - MODE_HEXADECIMAL, ///< a hexadecimal will be encrypted by an hexadecimal - MODE_ALPHA_NUMERIC, ///< [a-zA-Z0-9_] remains in this class - MODE_FILENAME, ///< [a-zA-Z0-9_!^$%=+-#~.] remains in this class - MODE_ASCII, ///< chr(32)..chr(127) remains in this class - MODE_CHAR255 ///< chr(32)..chr(255) remains in this class - } mode_t; - public: - RplEnigma(RplRandom* random = NULL); - virtual ~RplEnigma(); - public: - QByteArray readCertificate(); - char encodeChar(char byte, mode_t mode = MODE_STANDARD); - void encode(QByteArray& value, mode_t mode = MODE_STANDARD); - void addByteSeed(const QByteArray& byteSeed); - void setSeed(u_int64_t seed); - protected: - ///> a pseudo random generator - RplRandom* m_random; - ///> true: m_random must be destroyed (in the destructor). - bool m_ownsRandom; - QList m_byteSeeds; - ///> each call of setSeed sets this value to 0. - int m_ixSeed; - }; +public: + static const char* SET_32_127; ///< ' ' .. chr(127) + static const char* SET_DECIMALS; ///< '0'..'9' + static const char* SET_HEXDIGITS; ///< '0'..'9' 'a'..'f' + static const char* SET_ALPHANUM; ///< '0'..'9' 'A'..'Z' a'..'z' '_' + static const char* SET_FILENAME; ///< '0'..'9' 'A'..'Z' z'..'z' '_' + static const char* SET_32_255; ///< ' ' .. chr(255) +protected: + typedef struct { + int m_count; + u_int64_t* m_list; + } secret_t; +public: + RplEnigma(RplRandom* random = NULL); + virtual ~RplEnigma(); +public: + void encode(char* data, int size, const char* charSet, QByteArray& cache); + void decode(char* data, int size, const char* charSet, QByteArray& cache); + void change(QByteArray& data); + void addByteSecret(QByteArray byteSeed); + void setSeed(u_int64_t seed); + QByteArray readCertificate(const char* filename); +protected: + int nextInt(int maxValue); + +protected: + ///> a pseudo random generator + RplRandom* m_random; + ///> true: m_random must be destroyed (in the destructor). + bool m_ownsRandom; + ///> This values will be mixed with m_random' seed + QList m_secrets; + ///> each call of setSeed sets this value to 0. + int m_randomCalls; + ///> a byte sequence derived from the secrets + QByteArray m_randomSource; +}; #endif // RPLENIGMA_HPP diff --git a/rplmath/rplrandom.cpp b/rplmath/rplrandom.cpp index a0a38e2..390c1e9 100644 --- a/rplmath/rplrandom.cpp +++ b/rplmath/rplrandom.cpp @@ -33,7 +33,7 @@ RplRandom::~RplRandom(){ * @return the next random number. */ u_int64_t RplRandom::nextInt64(){ - // Knuth recommands (64-Bit): + // Donald Knuth recommands (for 64-Bit): m_seed = m_seed * 6364136223846793005L + 1442695040888963407L; return m_seed; } @@ -45,6 +45,14 @@ u_int64_t RplRandom::nextInt64(){ void RplRandom::setSeed(u_int64_t seed){ m_seed = seed; } +/** + * @brief Modifies the seed. + * + * @param seed the XOR operand. + */ +void RplRandom::xorSeed(u_int64_t seed){ + m_seed ^= seed; +} /** * @brief nextByte returns the next random byte. @@ -84,11 +92,11 @@ int RplRandom::nextInt(int minValue, int maxValue){ * @param maxChar all characters of the result are lower or equal than this value * @return a random string */ -QByteArray RplRandom::nextString(int length = 8, char minChar = ' ', char maxChar = 127){ +QByteArray RplRandom::nextString(int length, char minChar, char maxChar){ QByteArray rc; rc.resize(length); for (int ii = 0; ii < length; ii++){ - rc[ii] = minChar + nextInt(maxChar + 1); + rc[ii] = nextInt(minChar, maxChar); } return rc; } @@ -100,7 +108,7 @@ QByteArray RplRandom::nextString(int length = 8, char minChar = ' ', char maxCha * @param charSet a string with all allowed characters * @return a random string with characters from the given set */ -QByteArray RplRandom::nextString(int length = 8, char* charSet){ +QByteArray RplRandom::nextString(int length, char* charSet){ QByteArray rc; rc.resize(length); int ubound = strlen(charSet) - 1; @@ -109,3 +117,4 @@ QByteArray RplRandom::nextString(int length = 8, char* charSet){ } return rc; } + diff --git a/rplmath/rplrandom.hpp b/rplmath/rplrandom.hpp index db6c983..aa08466 100644 --- a/rplmath/rplrandom.hpp +++ b/rplmath/rplrandom.hpp @@ -6,10 +6,11 @@ class RplRandom { public: RplRandom(); - ~RplRandom(); + virtual ~RplRandom(); public: virtual u_int64_t nextInt64(); virtual void setSeed(u_int64_t seed); + void xorSeed(u_int64_t seed); u_int8_t nextByte(); int nextInt(int minValue, int maxValue); QByteArray nextString(int length = 8, char minChar = ' ', char maxChar = 127); diff --git a/rplnet/rpltcpserver.cpp b/rplnet/rpltcpserver.cpp index 59a388d..d2a1904 100644 --- a/rplnet/rpltcpserver.cpp +++ b/rplnet/rpltcpserver.cpp @@ -165,7 +165,7 @@ int RplTaskHandler::getThreadId() const{ *
  • string user: the login will be done for this user. *
  • integer current_salt: the random generator must be initialized by this value. * Then the embedded data can be decrypted. - * Note: other user specific data (certificate) affects the encryption as well.
  • + * Note: other user specific data (certificate) affects the encryption as well. *
  • integer salt": this is the encrypted version of the current salt: * Only if the sender knows the user's credentials this value can be calculated correctly. * This is the authentification.