]> gitweb.hamatoma.de Git - crepublib/commitdiff
hexdump
authorhama <hama@siduction.net>
Mon, 2 Feb 2015 20:02:12 +0000 (21:02 +0100)
committerhama <hama@siduction.net>
Mon, 2 Feb 2015 20:04:19 +0000 (21:04 +0100)
base/ReByteBuffer.cpp
base/ReByteBuffer.hpp
cunit/cuReByteBuffer.cpp
cunit/cuReMD5.cpp
cunit/testall.cpp
math/ReMD5.cpp
math/ReMD5.hpp
math/md5.cpp [new file with mode: 0644]
math/md5.hpp [new file with mode: 0644]

index acf4992168d07d9e1ca345ff295f3fc7150a2ba1..234bd8ea6c1c26cd071b603db26b2b848b1c18df 100644 (file)
@@ -168,6 +168,83 @@ ReByteBuffer&  ReByteBuffer::appendInt(int number, const char* format){
 ReByteBuffer& ReByteBuffer::append(const ReByteBuffer& source){
        return append(source.str(), source.length());
 }
+
+/**
+ * Appends a hexadecimal dump of a memory array.
+ *
+ * <pre>Example:
+ * <code>buffer.appendHex("01234567890abcde", -1, 0x10, 16, "%0x8x", 1, -1, " | ");
+ * </code>
+ * Buffer contains:
+ * 00000010  30 31 32 33 34 35 36 37  38 39 30 61 62 63 64 65 | 01234567890abcde
+ * </pre>
+ *
+ * @param data                 data to dump
+ * @param length               length of <code>data</code>. -1: <code>strlen(data)</code>
+ * @param offset               a format which is used to append a preceeding position
+ *                                             of source. NULL: no offset is appended
+ * @param bytesPerLine number of bytes in one line. If length is greater more
+ *                                             lines are appended
+ * @param offsetFormat NULL or the sprintf format of the offset, e.g. "0x04x "
+ * @param withAscii            <code>true</code>: the data is interpreted as ASCII too
+ * @param groupWidth   behind <code>groupWidth</code> hex bytes a ' ' is appended
+ * @param gapBehind            behind <code>gapBehind</code> hex bytes a ' ' is appended<br>
+ *                                             -1: <code>bytePerLine / 2</code>
+ * @param separator            NULL or a string between hex area and ASCII area
+ */
+ReByteBuffer& ReByteBuffer::appendHexDump(const char* data, size_t length,
+               int offset, int bytesPerLine, const char* offsetFormat,
+               bool withAscii, int groupWidth, int gapBehind, const char* separator){
+       if (length == -1)
+               length = strlen(data);
+       if (gapBehind < 0)
+               gapBehind = bytesPerLine / 2;
+       ensureSize(32);
+       int offsetLength = 0;
+       if (offsetFormat != NULL){
+               snprintf(m_buffer, 31, offsetFormat, offset + length);
+               offsetLength = strlen(m_buffer);
+       }
+       ensureSize((length + bytesPerLine - 1) / bytesPerLine
+               * (4 + offsetLength + (gapBehind <= 0 ? 0 : bytesPerLine / gapBehind + 1)
+               + (separator == NULL ? 0 : strlen(separator))+ 1));
+       while(length > 0){
+               if (offsetFormat != NULL)
+                       appendInt(offset, offsetFormat);
+               int ix;
+               for (ix = 0; ix < bytesPerLine; ix++){
+                       if (ix < length)
+                               appendInt((unsigned) data[ix] % 0xff, "%02x");
+                       else
+                               append("  ");
+                       if (ix < bytesPerLine - 1
+                                       && (groupWidth == 1 || ix % groupWidth == groupWidth - 1))
+                               append(" ", 1);
+                       if (ix < bytesPerLine - 1 && gapBehind > 0
+                                       && (gapBehind == 1 || ix % gapBehind == gapBehind - 1))
+                               append(" ", 1);
+               }
+               if (withAscii){
+                       if (separator != NULL)
+                               append(separator, -1);
+               }
+               char cc;
+               for (ix = 0; ix < bytesPerLine; ix++){
+                       if (ix < length)
+                               appendInt( (cc = data[ix]) < ' ' || cc > 127 ? '.' : cc, "%c");
+                       else
+                               append(" ");
+                       if (ix < bytesPerLine - 1 && gapBehind > 0
+                                       && (gapBehind == 1 || ix % gapBehind == gapBehind - 1))
+                               append(" ", 1);
+               }
+               append("\n", 1);
+               length = length <= bytesPerLine ? 0 : length - bytesPerLine;
+               data += bytesPerLine;
+               offset += bytesPerLine;
+       }
+}
+
 /** @brief Appends a time (given in milli seconds) as 'dd:HH:MM.mmm'.
  *
  * @param time         the time (duration) in msec
index a3bcc5ba09350492acb239df90f2b5ac17d96567..9dcc9f99445c671b09e0314258417ea378d39ded 100644 (file)
@@ -46,6 +46,10 @@ public:
 public:
        ReByteBuffer& append(const Byte* source, size_t length = -1);
        ReByteBuffer& append(const ReByteBuffer& source);
+       ReByteBuffer& appendHexDump(const char* data, size_t length = -1,
+               int offset = 0, int bytePerLine = 16,
+               const char* offsetFormat = "%04x: ", bool withAscii = true,
+               int groupWidth = 1, int gapBehind = -1, const char* separator = " | ");
        ReByteBuffer& appendInt(int number, const char* format = "%d");
        ReByteBuffer& appendMilliSec(int time, int minLength = 5);
        /** @brief Returns the n-th byte of the internal buffer.
index 982d3fdf0312567ccfbf9db957614c7add7fb189..4823b2fa07370d0ef055fe01dfb41f1bc844510e 100644 (file)
@@ -15,6 +15,7 @@ public:
        }
 private:
        void run(){
+               testHexDump();
                testFill();
                testAppendMilliSec();
                testSetDelta();
@@ -36,6 +37,30 @@ private:
                testSplice();
                testReplace();
        }
+       void testHexDump(){
+               ReByteBuffer buf;
+               /* appendHexDump(const char* data, size_t length, int offset = 0, int bytePerLine = 16,
+               const char* offsetFormat = "%04x ", bool withAscii = true,
+               int groupWidth = 1, int gapBehind = -1, const char* separator = " | ");
+               */
+               buf.appendHexDump("abcdefghijklmnopq");
+               checkEqu("0000: 61 62 63 64 65 66 67 68  69 6a 6b 6c 6d 6e 6f 70 | abcdefgh ijklmnop\n"
+                                "0010: 71                                               | q                \n",
+                                buf.str());
+               buf.setLength(0).appendHexDump("abcdefghijklmnopq", 16);
+               checkEqu("0000: 61 62 63 64 65 66 67 68  69 6a 6b 6c 6d 6e 6f 70 | abcdefgh ijklmnop\n",
+                                buf.str());
+               buf.setLength(0).appendHexDump("\t\nü23456789x123456", -1, 20, 8, "%3d: ", true,
+                       4, 0, NULL);
+               checkEqu(" 20: 090ac3bc 32333435....2345\n"
+                       " 28: 36373839 783132336789x123\n"
+                       " 36: 343536           456     \n", buf.str());
+               buf.setLength(0).appendHexDump("abcdefghijk", -1, 0, 8, "%3d: ", true, 2, 4);
+               printf("%s", buf.str());
+               checkEqu(" 20: 090ac3bc 32333435....2345\n"
+                       " 28: 36373839 783132336789x123\n"
+                       " 36: 343536           456     \n", buf.str());
+       }
        void testFill(){
                ReByteBuffer buf;
                buf.fill('=', 0, 3);
index c3fd45615ed2021d0fb9ec5ec744c688c7389c13..3bac001c90bea57a1761ec68488b7a66a660152c 100644 (file)
@@ -18,6 +18,7 @@
 
 #include "base/rebase.hpp"
 #include "math/remath.hpp"
+//#include "math/md5.hpp"
 
 class TestReMd5 : public ReTestUnit {
 public:
@@ -26,13 +27,28 @@ public:
        }
 private:
        void run(){
+               testOld();
                testBase();
        }
+       void testOld(){
+#if 0
+               MD5 md5;
+               md5.update("", 0);
+               md5.finalize();
+               std::string dig = md5.hexdigest();
+               const char* dig2 = (const char*) dig.c_str();
+               dig2++;
+#endif
+       }
        void testBase(){
                ReMD5 md5;
                md5.update((const uint8_t*)"", 0);
                checkEqu("d41d8cd98f00b204e9800998ecf8427e",
                        md5.hexDigest().str());
+               md5.reset();
+               md5.update((const uint8_t*)"01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVEXYZ01234567890\n", -1);
+               checkEqu("c0a278c051a6898f6ad05da7fa80a1c4",
+                       md5.hexDigest().str());
        }
 };
 extern void testReMD5(void);
index 844d604a7998d91773de6bbee2319b7debee3426..2634bb6d9650c8cbf909034df051a3e1e0f74353 100644 (file)
@@ -13,8 +13,8 @@
 #endif
 
 void testBase(){
-       extern void testReProgramArgs(void);
-       testReProgramArgs();
+       extern void testReByteBuffer();
+       testReByteBuffer();
 
        extern void testReTestUnit();
        //testReTestUnit();
@@ -70,8 +70,8 @@ void testMath(){
 void testAll(){
        try
        {
-               testMath();
-               
+               testBase();
+
                testOs();
                testBase();
                testMath();
index 4621c315275e1937a6d15aca7f5724f5dcad41d9..403522e03597d17be41503195cd79edbd9916907 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "base/rebase.hpp"
 #include "math/remath.hpp"
+
 #define __LITTLE_ENDIAN__
 
 const int ReMD5::m_s[64] = {
@@ -15,7 +16,7 @@ const int ReMD5::m_s[64] = {
        6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21
 };
 //  for x in [1..64] : int(2**32 * sin(x))
-const int ReMD5::m_K[64] = {
+const uint32_t ReMD5::m_K[64] = {
        0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
        0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
        0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
@@ -81,7 +82,6 @@ const uint8_t* ReMD5::digest(){
 void ReMD5::finalize(){
        uint8_t* block = m_waiting;
        int blockLength = m_lengthWaiting;
-
        // append "1" bit to message
        // Notice: the input bytes are considered as bits strings,
        // where the first bit is the most significant bit of the byte.
@@ -94,7 +94,7 @@ void ReMD5::finalize(){
        // 0 -> 56, 1 -> 55, 2 -> 54, ... 55 -> 1, 56 -> 0,
        // 57 -> 63, 58 -> 62, ... 63 -> 57
        int zeros = restLength <= 56 ? 56 - restLength : 120 - restLength;
-       memset(block + blockLength + 1, 0, zeros);
+       memset(block + blockLength, 0, zeros);
        blockLength += zeros;
        //append original length in bits mod (2 pow 64) to message
        uint64_t lengthBits = 8LL * m_length;
@@ -102,21 +102,21 @@ void ReMD5::finalize(){
        memcpy(block + blockLength, &lengthBits, 8);
        blockLength += 8;
 #else
-       block[blockLength++] = lengthBits & 0xff;
-       lengthBits >>= 4;
-       block[blockLength++] = lengthBits & 0xff;
-       lengthBits >>= 4;
-       block[blockLength++] = lengthBits & 0xff;
-       lengthBits >>= 4;
-       block[blockLength++] = lengthBits & 0xff;
-       lengthBits >>= 4;
-       block[blockLength++] = lengthBits & 0xff;
-       lengthBits >>= 4;
-       block[blockLength++] = lengthBits & 0xff;
-       lengthBits >>= 4;
-       block[blockLength++] = lengthBits & 0xff;
-       lengthBits >>= 4;
-       block[blockLength++] = lengthBits & 0xff;
+       block[blockLength++] = lengthBits;
+       lengthBits >>= 8;
+       block[blockLength++] = lengthBits;
+       lengthBits >>= 8;
+       block[blockLength++] = lengthBits;
+       lengthBits >>= 8;
+       block[blockLength++] = lengthBits;
+       lengthBits >>= 8;
+       block[blockLength++] = lengthBits;
+       lengthBits >>= 8;
+       block[blockLength++] = lengthBits;
+       lengthBits >>= 8;
+       block[blockLength++] = lengthBits;
+       lengthBits >>= 8;
+       block[blockLength++] = lengthBits;
 #endif
        processChunk(block);
        if (blockLength > 64)
@@ -126,10 +126,9 @@ void ReMD5::finalize(){
        memcpy(m_digest + 4, &m_b0, 4);
        memcpy(m_digest + 8, &m_c0, 4);
        memcpy(m_digest + 12, &m_d0, 4);
-       blockLength += 8;
 #else
-#define oneWord(word, ix) m_digest[ix] = word; word >>= 4; \
-       m_digest[ix + 1] = word; word >>= 4; m_digest[ix + 2] = word; word >>= 4; \
+#define oneWord(word, ix) m_digest[ix] = word; word >>= 8; \
+       m_digest[ix + 1] = word; word >>= 8; m_digest[ix + 2] = word; word >>= 8; \
        m_digest[ix + 3] = word
        oneWord(m_a0, 0);
        oneWord(m_b0, 4);
@@ -157,17 +156,18 @@ const ReByteBuffer& ReMD5::hexDigest(){
  * Processes a 512 bit block ("chunk").
  */
 void ReMD5::processChunk(const uint8_t block[64]){
-       int M[16];
+       uint32_t M[16];
        //      break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15
 #ifdef __LITTLE_ENDIAN__
        for (int ix = 0; ix < 16; ix++)
                memcpy(&M[ix], block + ix * 4, 4);
 #elif defined __BIG_ENDIAN__
        for (int ix = 0; ix < 16; ix++){
-               M[ix] = block[3];
-               for (jj = 2; jj >= 0; jj--){
-                       M[ix] = (M[ix] << 4) + block[jj];
+               uint32_t x = block[3];
+               for (int jj = 2; jj >= 0; jj--){
+                       x = (x << 8) + block[jj];
                }
+               M[ix] = x;
                block += 4;
        }
 #else
@@ -175,23 +175,23 @@ void ReMD5::processChunk(const uint8_t block[64]){
 #endif
 
        //Initialize hash value for this chunk:
-       int A = m_a0;
-       int B = m_b0;
-       int C = m_c0;
-       int D = m_d0;
+       uint32_t A = m_a0;
+       uint32_t B = m_b0;
+       uint32_t C = m_c0;
+       uint32_t D = m_d0;
        //Main loop:
        int F, g;
        for (int i = 0; i < 64; i++){
-               if (i <= 15){
+               if (i < 16){
                        // F := (B and C) or ((not B) and D)
                        F = (B & C) | (~ B & D);
                        g = i;
-               } else if (i > 15 && i <= 31){
-                       // F := (D and B) or ((not D) and C)
-                       F = (D & B) | (~ D & C);
+               } else if (i < 32){
+                       // F := (D and B) or (C and (not D))
+                       F = (D & B) | (C & ~ D);
                        // g := (5×i + 1) mod 16
                        g = (5*i + 1) % 16;
-               } else if (i > 31 && i <= 47){
+               } else if (i < 48){
                        // F := B xor C xor D
                        F = (B ^ C) ^ D;
                        // g := (3×i + 5) mod 16
@@ -202,11 +202,11 @@ void ReMD5::processChunk(const uint8_t block[64]){
                        // g := (7×i) mod 16
                        g = (7*i) % 16;
                }
-               int dTemp = D;
+               uint32_t dTemp = D;
                D = C;
                C = B;
                // B := B + leftrotate((A + F + K[i] + M[g]), s[i])
-               int x = (A + F + m_K[i] + M[g]) & 0xffffffff;
+               uint32_t x = (A + F + m_K[i] + M[g]);
                int shift = m_s[i];
                B += (x << shift) | (x >> (32 - shift));
                A = dTemp;
@@ -230,6 +230,8 @@ void ReMD5::reset(){
        memset(m_waiting, 0, sizeof m_waiting);
        m_lengthWaiting = 0;
        m_length = 0;
+       m_hexDigest.setLength(0);
+       m_finalized = false;
 }
 /**
  * Processes a 64 byte block.
@@ -238,6 +240,8 @@ void ReMD5::reset(){
  * @param blockLength  the length of <code>block</code>
  */
 void ReMD5::update(const uint8_t* block, int blockLength){
+       if (blockLength == -1)
+               blockLength = strlen((const char*) block);
        // process the "waiting" input (incomplete chunk):
        m_length += blockLength;
        if (m_lengthWaiting > 0){
@@ -255,15 +259,19 @@ void ReMD5::update(const uint8_t* block, int blockLength){
                }
        }
        // process full 512 bit chunks (64 byte blocks):
-       for (int ix = blockLength / 64; ix >= 0; ix--){
-               processChunk(block);
-               block += 64;
-       }
-       blockLength %= 64;
-       if (blockLength != 0){
-               assert(m_lengthWaiting == 0);
-               memcpy(m_waiting, block, blockLength);
-               m_lengthWaiting = blockLength;
+       if (blockLength > 0){
+               if (blockLength > 64){
+                       for (int ix = blockLength / 64; ix >= 0; ix--){
+                               processChunk(block);
+                               block += 64;
+                       }
+               }
+               blockLength %= 64;
+               if (blockLength != 0){
+                       assert(m_lengthWaiting == 0);
+                       memcpy(m_waiting, block, blockLength);
+                       m_lengthWaiting = blockLength;
+               }
        }
 }
 
index 7c885ee20986a7683db2b5fdaf69cd33cb538686..1294bc360b83d0be6c3fb7e8ae6ffce944459c0e 100644 (file)
@@ -35,15 +35,17 @@ private:
        uint8_t m_waiting[64+64];
        int m_lengthWaiting;
        // total count of input bytes:
-       int m_length;
-       int m_a0;
-       int m_b0;
-       int m_c0;
-       int m_d0;
+       uint32_t m_length;
+       uint32_t m_a0;
+       uint32_t m_b0;
+       uint32_t m_c0;
+       uint32_t m_d0;
        bool m_finalized;
 private:
+       // number of shifts per round:
        static const int m_s[64];
-       static const int m_K[64];
+       // Constants:
+       static const uint32_t m_K[64];
 };
 
 #endif /* MATH_REMD5_HPP_ */
diff --git a/math/md5.cpp b/math/md5.cpp
new file mode 100644 (file)
index 0000000..0c1b9dc
--- /dev/null
@@ -0,0 +1,362 @@
+/* MD5
+ converted to C++ class by Frank Thilo (thilo@unix-ag.org)
+ for bzflag (http://www.bzflag.org)
+
+   based on:
+
+   md5.h and md5.c
+   reference implemantion of RFC 1321
+
+   Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+
+*/
+
+/* interface header */
+#include "math/md5.hpp"
+
+/* system implementation headers */
+#include <cstdio>
+
+
+// Constants for MD5Transform routine.
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+///////////////////////////////////////////////
+
+// F, G, H and I are basic MD5 functions.
+inline MD5::uint4 MD5::F(uint4 x, uint4 y, uint4 z) {
+  return x&y | ~x&z;
+}
+
+inline MD5::uint4 MD5::G(uint4 x, uint4 y, uint4 z) {
+  return x&z | y&~z;
+}
+
+inline MD5::uint4 MD5::H(uint4 x, uint4 y, uint4 z) {
+  return x^y^z;
+}
+
+inline MD5::uint4 MD5::I(uint4 x, uint4 y, uint4 z) {
+  return y ^ (x | ~z);
+}
+
+// rotate_left rotates x left n bits.
+inline MD5::uint4 MD5::rotate_left(uint4 x, int n) {
+  return (x << n) | (x >> (32-n));
+}
+
+// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+// Rotation is separate from addition to prevent recomputation.
+inline void MD5::FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
+  a = rotate_left(a+ F(b,c,d) + x + ac, s) + b;
+}
+
+inline void MD5::GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
+  a = rotate_left(a + G(b,c,d) + x + ac, s) + b;
+}
+
+inline void MD5::HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
+  a = rotate_left(a + H(b,c,d) + x + ac, s) + b;
+}
+
+inline void MD5::II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
+  a = rotate_left(a + I(b,c,d) + x + ac, s) + b;
+}
+
+//////////////////////////////////////////////
+
+// default ctor, just initailize
+MD5::MD5()
+{
+  init();
+}
+
+//////////////////////////////////////////////
+
+// nifty shortcut ctor, compute MD5 for string and finalize it right away
+MD5::MD5(const std::string &text)
+{
+  init();
+  update(text.c_str(), text.length());
+  finalize();
+}
+
+//////////////////////////////
+
+void MD5::init()
+{
+  finalized=false;
+
+  count[0] = 0;
+  count[1] = 0;
+
+  // load magic initialization constants.
+  state[0] = 0x67452301;
+  state[1] = 0xefcdab89;
+  state[2] = 0x98badcfe;
+  state[3] = 0x10325476;
+}
+
+//////////////////////////////
+
+// decodes input (unsigned char) into output (uint4). Assumes len is a multiple of 4.
+void MD5::decode(uint4 output[], const uint1 input[], size_type len)
+{
+  for (unsigned int i = 0, j = 0; j < len; i++, j += 4)
+    output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) |
+      (((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24);
+}
+
+//////////////////////////////
+
+// encodes input (uint4) into output (unsigned char). Assumes len is
+// a multiple of 4.
+void MD5::encode(uint1 output[], const uint4 input[], size_type len)
+{
+  for (size_type i = 0, j = 0; j < len; i++, j += 4) {
+    output[j] = input[i] & 0xff;
+    output[j+1] = (input[i] >> 8) & 0xff;
+    output[j+2] = (input[i] >> 16) & 0xff;
+    output[j+3] = (input[i] >> 24) & 0xff;
+  }
+}
+
+//////////////////////////////
+
+// apply MD5 algo on a block
+void MD5::transform(const uint1 block[blocksize])
+{
+  uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+  decode (x, block, blocksize);
+
+  /* Round 1 */
+  FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+  FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+  FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+  FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+  FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+  FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+  FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+  FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+  FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+  FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+  FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+  FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+  FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+  FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+  FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+  FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+  /* Round 2 */
+  GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+  GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+  GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+  GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+  GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+  GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
+  GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+  GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+  GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+  GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+  GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+  GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+  GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+  GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+  GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+  GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+  /* Round 3 */
+  HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+  HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+  HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+  HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+  HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+  HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+  HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+  HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+  HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+  HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+  HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+  HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
+  HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+  HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+  HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+  HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+  /* Round 4 */
+  II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+  II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+  II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+  II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+  II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+  II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+  II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+  II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+  II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+  II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+  II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+  II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+  II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+  II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+  II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+  II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+  state[0] += a;
+  state[1] += b;
+  state[2] += c;
+  state[3] += d;
+
+  // Zeroize sensitive information.
+  memset(x, 0, sizeof x);
+}
+
+//////////////////////////////
+
+// MD5 block update operation. Continues an MD5 message-digest
+// operation, processing another message block
+void MD5::update(const unsigned char input[], size_type length)
+{
+  // compute number of bytes mod 64
+  size_type index = count[0] / 8 % blocksize;
+
+  // Update number of bits
+  if ((count[0] += (length << 3)) < (length << 3))
+    count[1]++;
+  count[1] += (length >> 29);
+
+  // number of bytes we need to fill in buffer
+  size_type firstpart = 64 - index;
+
+  size_type i;
+
+  // transform as many times as possible.
+  if (length >= firstpart)
+  {
+    // fill buffer first, transform
+    memcpy(&buffer[index], input, firstpart);
+    transform(buffer);
+
+    // transform chunks of blocksize (64 bytes)
+    for (i = firstpart; i + blocksize <= length; i += blocksize)
+      transform(&input[i]);
+
+    index = 0;
+  }
+  else
+    i = 0;
+
+  // buffer remaining input
+  memcpy(&buffer[index], &input[i], length-i);
+}
+
+//////////////////////////////
+
+// for convenience provide a verson with signed char
+void MD5::update(const char input[], size_type length)
+{
+  update((const unsigned char*)input, length);
+}
+
+//////////////////////////////
+
+// MD5 finalization. Ends an MD5 message-digest operation, writing the
+// the message digest and zeroizing the context.
+MD5& MD5::finalize()
+{
+  static unsigned char padding[64] = {
+    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+  };
+
+  if (!finalized) {
+    // Save number of bits
+    unsigned char bits[8];
+    encode(bits, count, 8);
+
+    // pad out to 56 mod 64.
+    size_type index = count[0] / 8 % 64;
+    size_type padLen = (index < 56) ? (56 - index) : (120 - index);
+    update(padding, padLen);
+
+    // Append length (before padding)
+    update(bits, 8);
+
+    // Store state in digest
+    encode(digest, state, 16);
+
+    // Zeroize sensitive information.
+    memset(buffer, 0, sizeof buffer);
+    memset(count, 0, sizeof count);
+
+    finalized=true;
+  }
+
+  return *this;
+}
+
+//////////////////////////////
+
+// return hex representation of digest as string
+std::string MD5::hexdigest() const
+{
+  if (!finalized)
+    return "";
+
+  char buf[33];
+  for (int i=0; i<16; i++)
+    sprintf(buf+i*2, "%02x", digest[i]);
+  buf[32]=0;
+
+  return std::string(buf);
+}
+
+//////////////////////////////
+
+std::ostream& operator<<(std::ostream& out, MD5 md5)
+{
+  return out << md5.hexdigest();
+}
+
+//////////////////////////////
+
+std::string md5(const std::string str)
+{
+    MD5 md5 = MD5(str);
+
+    return md5.hexdigest();
+}
diff --git a/math/md5.hpp b/math/md5.hpp
new file mode 100644 (file)
index 0000000..e6f3e4c
--- /dev/null
@@ -0,0 +1,93 @@
+/* MD5
+ converted to C++ class by Frank Thilo (thilo@unix-ag.org)
+ for bzflag (http://www.bzflag.org)
+
+   based on:
+
+   md5.h and md5.c
+   reference implementation of RFC 1321
+
+   Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+
+*/
+
+#ifndef BZF_MD5_H
+#define BZF_MD5_H
+
+#include <cstring>
+#include <iostream>
+
+
+// a small class for calculating MD5 hashes of strings or byte arrays
+// it is not meant to be fast or secure
+//
+// usage: 1) feed it blocks of uchars with update()
+//      2) finalize()
+//      3) get hexdigest() string
+//      or
+//      MD5(std::string).hexdigest()
+//
+// assumes that char is 8 bit and int is 32 bit
+class MD5
+{
+public:
+  typedef unsigned int size_type; // must be 32bit
+
+  MD5();
+  MD5(const std::string& text);
+  void update(const unsigned char *buf, size_type length);
+  void update(const char *buf, size_type length);
+  MD5& finalize();
+  std::string hexdigest() const;
+  friend std::ostream& operator<<(std::ostream&, MD5 md5);
+
+private:
+  void init();
+  typedef unsigned char uint1; //  8bit
+  typedef unsigned int uint4;  // 32bit
+  enum {blocksize = 64}; // VC6 won't eat a const static int here
+
+  void transform(const uint1 block[blocksize]);
+  static void decode(uint4 output[], const uint1 input[], size_type len);
+  static void encode(uint1 output[], const uint4 input[], size_type len);
+
+  bool finalized;
+  uint1 buffer[blocksize]; // bytes that didn't fit in last 64 byte chunk
+  uint4 count[2];   // 64bit counter for number of bits (lo, hi)
+  uint4 state[4];   // digest so far
+  uint1 digest[16]; // the result
+
+  // low level logic operations
+  static inline uint4 F(uint4 x, uint4 y, uint4 z);
+  static inline uint4 G(uint4 x, uint4 y, uint4 z);
+  static inline uint4 H(uint4 x, uint4 y, uint4 z);
+  static inline uint4 I(uint4 x, uint4 y, uint4 z);
+  static inline uint4 rotate_left(uint4 x, int n);
+  static inline void FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
+  static inline void GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
+  static inline void HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
+  static inline void II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
+};
+
+std::string md5(const std::string str);
+
+#endif