]> gitweb.hamatoma.de Git - reqt/commitdiff
dayly work
authorJ. Hamatoma <hama@siduction.net>
Sat, 30 Nov 2013 11:22:06 +0000 (12:22 +0100)
committerJ. Hamatoma <hama@siduction.net>
Sat, 30 Nov 2013 11:22:06 +0000 (12:22 +0100)
rplmath/rplenigma.cpp
rplmath/rplenigma.hpp
rplmath/rplrandom.cpp
rplmath/rplrandom.hpp
rplnet/rpltcpserver.cpp

index 1f0306815786f30fb3cc985e7bef867ae098cf61..18f864351c06ef8c0322c56bfe49255ab4594d2e 100644 (file)
  * 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.
  *
  */
 /**
 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<br>
+ *                  OUT: data encoded
+ * @param size      length of <code>data</code>. 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<br>
+ *                  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<br>
+ *                  OUT: data decoded
+ * @param size      length of <code>data</code>. 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<br>
+ *                  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<br>
+ *                  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<secret_t*>::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<QByteArray> 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;
+}
index 842c05ef206b6398800c82b364385dd6cf38c1c5..9fa51b3fe037e4178397f8ba9e42e5b192d7827b 100644 (file)
@@ -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<QByteArray> 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 <code>m_random</code>' seed
+    QList<secret_t*> 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
index a0a38e2beed124c2dfc8898ec523e6815ac4d20e..390c1e93ac1fa549aec774010a4e92b96c7b9c91 100644 (file)
@@ -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;
 }
+
index db6c9836b8c6347ef4f3b545431e125087e63289..aa084667648165527a1303989d15c19f95f00786 100644 (file)
@@ -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);
index 59a388d6a5e8a8a978c88b95b28a29592324b449..d2a190425b59750c30bf5b7ec687e9e30fb5cf8a 100644 (file)
@@ -165,7 +165,7 @@ int RplTaskHandler::getThreadId() const{
  * <li>string user: the login will be done for this user.
  * <li>integer current_salt: the random generator must be initialized by this value.
  *      Then the embedded data can be decrypted.
- *      <b>Note: other user specific data (certificate) affects the encryption as well.</li>
+ *      <b>Note:</b> other user specific data (certificate) affects the encryption as well.</li>
  * <li>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.