* You also can use this license: http://www.wtfpl.net
* The latest sources: https://github.com/republib
*/
-\r
-#include "base/rebase.hpp"\r
-#include "math/remath.hpp"\r
-\r
-const int ReMD5::m_s[RE_DIGEST_CHUNK_SIZE] = { 7, 12, 17, 22, 7, 12, 17, 22, 7,\r
- 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9,\r
- 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10,\r
- 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 };\r
-// for x in [1..64] : int(2**32 * sin(x))\r
-const uint32_t ReMD5::m_K[RE_DIGEST_CHUNK_SIZE] = { 0xd76aa478, 0xe8c7b756,\r
- 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,\r
- 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193,\r
- 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,\r
- 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6,\r
- 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,\r
- 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9,\r
- 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,\r
- 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97,\r
- 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,\r
- 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235,\r
- 0x2ad7d2bb, 0xeb86d391 };\r
-\r
-/**\r
- * Constructor.\r
- *\r
- * @param digest the buffer for the binary checksum\r
- * @param digestSize the length of <code>digest</code>\r
- * @param waiting a buffer for a chunk. Must have space for at least 2*chunksize bytes\r
- * NULL: an intrinsic buffer will be used\r
- * @param chunkSize the length of one full input block\r
- */\r
-ReDigest::ReDigest(uint8_t* digest, size_t digestSize, uint8_t* waiting,\r
- size_t chunkSize) :\r
- m_digest(digest),\r
- m_digestSize(digestSize),\r
- // m_waitingBuffer[RE_DIGEST_CHUNK_SIZE];\r
- m_waiting(waiting != NULL ? waiting : m_waitingBuffer),\r
- m_lengthWaiting(0),\r
- m_chunkSize(chunkSize),\r
- m_length(0),\r
- m_finalized(false),\r
- m_salt(0) {\r
-}\r
-/**\r
- * Destructor.\r
- */\r
-ReDigest::~ReDigest() {\r
-}\r
-/**\r
- * Returns the binary digest value.\r
- *\r
- * @return the binary digest (16 byte array)\r
- */\r
-const uint8_t* ReDigest::digest() {\r
- if (!m_finalized) {\r
- finalize();\r
- }\r
- return m_digest;\r
-}\r
-\r
-/**\r
- * Returns the binary digest value.\r
- *\r
- * @return the binary digest (16 byte array)\r
- */\r
-const ReByteArray& ReDigest::hexDigest() {\r
- if (m_hexDigest.empty()) {\r
- digest();\r
- for (size_t ix = 0; ix < m_digestSize; ix++) {\r
- m_hexDigest.appendInt(m_digest[ix], "%02x");\r
- }\r
- }\r
- return m_hexDigest;\r
-}\r
-\r
-/**\r
- * Processes a 64 byte block.\r
- *\r
- * @param block a block which should be added to the digest\r
- * @param blockLength the length of <code>block</code>\r
- */\r
-void ReDigest::update(const uint8_t* block, int blockLength) {\r
- if (blockLength == -1)\r
- blockLength = strlen((const char*) block);\r
- // process the "waiting" input (incomplete chunk):\r
- m_length += blockLength;\r
- if (m_lengthWaiting > 0) {\r
- int rest = m_chunkSize - m_lengthWaiting;\r
- if (rest > blockLength)\r
- rest = blockLength;\r
- memcpy(m_waiting + m_lengthWaiting, block, rest);\r
- blockLength -= rest;\r
- block += rest;\r
- m_lengthWaiting += rest;\r
- // Is the chunk complete?\r
- if (m_lengthWaiting == m_chunkSize) {\r
- processChunk(m_waiting);\r
- m_lengthWaiting = 0;\r
- }\r
- }\r
- // process full 512 bit chunks (64 byte blocks):\r
- for (int ix = blockLength / m_chunkSize; ix > 0; ix--) {\r
- processChunk(block);\r
- block += m_chunkSize;\r
- }\r
- blockLength %= m_chunkSize;\r
- if (blockLength != 0) {\r
- assert(m_lengthWaiting == 0);\r
- memcpy(m_waiting, block, blockLength);\r
- m_lengthWaiting = blockLength;\r
- }\r
-}\r
-\r
-/**\r
- * Sets the salt of the checksum algorithm.\r
- *\r
- * Important: set the salt before you make the first <code>update()</code>!\r
- *\r
- * The salt makes that the checksum of the same input is (extremly) different\r
- * to another salt.\r
- *\r
- * @param salt the salt to set\r
- */\r
-void ReDigest::setSalt(uint64_t salt) {\r
- m_salt = salt;\r
-}\r
-/**\r
- * Constructor.\r
- */\r
-ReMD5::ReMD5() :\r
- ReDigest(m_digest, sizeof m_digest),\r
- m_a0(0x67452301),\r
- m_b0(0xefcdab89),\r
- m_c0(0x98badcfe),\r
- m_d0(0x10325476) {\r
-}\r
-\r
-/**\r
- * Destructor.\r
- */\r
-ReMD5::~ReMD5() {\r
-}\r
-\r
-/**\r
- * Finalizes the digest.\r
- *\r
- * Handles the rest block (< 64 byte) and append a special tail: a "1" bit\r
- * and the length of the total input length (in bits).\r
- *\r
- * @param block the rest input (incomplete chunk)\r
- * @param blockLength the length of the block: 0..63\r
- */\r
-void ReMD5::finalize() {\r
- uint8_t* block = m_waiting;\r
- int blockLength = m_lengthWaiting;\r
- // append "1" bit to message\r
- // Notice: the input bytes are considered as bits strings,\r
- // where the first bit is the most significant bit of the byte.\r
- block[blockLength++] = 0x80;\r
- //Pre-processing: padding with zeros\r
- //append "0" bit until message length in bits ≡ 448 (mod 512)\r
- // fill the rest of the chunk with '\0'.\r
- // the last 8 bytes is set to the length in bits (length in bytes * 8)\r
- int restLength = (m_length + 1) % RE_DIGEST_CHUNK_SIZE;\r
- // 0 -> 56, 1 -> 55, 2 -> 54, ... 55 -> 1, 56 -> 0,\r
- // 57 -> 63, 58 -> 62, ... 63 -> 57\r
- int zeros = restLength <= 56 ? 56 - restLength : 120 - restLength;\r
- memset(block + blockLength, 0, zeros);\r
- blockLength += zeros;\r
- //append original length in bits mod (2 pow 64) to message\r
- uint64_t lengthBits = 8LL * m_length + m_salt;\r
-#if defined __LITTLE_ENDIAN__\r
- memcpy(block + blockLength, &lengthBits, 8);\r
- blockLength += 8;\r
-#else\r
- block[blockLength++] = lengthBits;\r
- lengthBits >>= 8;\r
- block[blockLength++] = lengthBits;\r
- lengthBits >>= 8;\r
- block[blockLength++] = lengthBits;\r
- lengthBits >>= 8;\r
- block[blockLength++] = lengthBits;\r
- lengthBits >>= 8;\r
- block[blockLength++] = lengthBits;\r
- lengthBits >>= 8;\r
- block[blockLength++] = lengthBits;\r
- lengthBits >>= 8;\r
- block[blockLength++] = lengthBits;\r
- lengthBits >>= 8;\r
- block[blockLength++] = lengthBits;\r
-#endif\r
- processChunk(block);\r
- if (blockLength > RE_DIGEST_CHUNK_SIZE)\r
- processChunk(block + RE_DIGEST_CHUNK_SIZE);\r
-#if defined __LITTLE_ENDIAN__\r
- memcpy(m_digest, &m_a0, 4);\r
- memcpy(m_digest + 4, &m_b0, 4);\r
- memcpy(m_digest + 8, &m_c0, 4);\r
- memcpy(m_digest + 12, &m_d0, 4);\r
-#else\r
+
+#include "base/rebase.hpp"
+#include "math/remath.hpp"
+
+const int ReMD5::m_s[RE_DIGEST_CHUNK_SIZE] = { 7, 12, 17, 22, 7, 12, 17, 22, 7,
+ 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9,
+ 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 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 uint32_t ReMD5::m_K[RE_DIGEST_CHUNK_SIZE] = { 0xd76aa478, 0xe8c7b756,
+ 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193,
+ 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+ 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6,
+ 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9,
+ 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
+ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97,
+ 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235,
+ 0x2ad7d2bb, 0xeb86d391 };
+
+/**
+ * Constructor.
+ *
+ * @param digest the buffer for the binary checksum
+ * @param digestSize the length of <code>digest</code>
+ * @param waiting a buffer for a chunk. Must have space for at least 2*chunksize bytes
+ * NULL: an intrinsic buffer will be used
+ * @param chunkSize the length of one full input block
+ */
+ReDigest::ReDigest(uint8_t* digest, size_t digestSize, uint8_t* waiting,
+ size_t chunkSize) :
+ m_digest(digest),
+ m_digestSize(digestSize),
+ // m_waitingBuffer[RE_DIGEST_CHUNK_SIZE];
+ m_waiting(waiting != NULL ? waiting : m_waitingBuffer),
+ m_lengthWaiting(0),
+ m_chunkSize(chunkSize),
+ m_length(0),
+ m_finalized(false),
+ m_salt(0) {
+}
+/**
+ * Destructor.
+ */
+ReDigest::~ReDigest() {
+}
+/**
+ * Returns the binary digest value.
+ *
+ * @return the binary digest (16 byte array)
+ */
+const uint8_t* ReDigest::digest() {
+ if (!m_finalized) {
+ finalize();
+ }
+ return m_digest;
+}
+
+/**
+ * Returns the binary digest value.
+ *
+ * @return the binary digest (16 byte array)
+ */
+const ReByteArray& ReDigest::hexDigest() {
+ if (m_hexDigest.empty()) {
+ digest();
+ for (size_t ix = 0; ix < m_digestSize; ix++) {
+ m_hexDigest.appendInt(m_digest[ix], "%02x");
+ }
+ }
+ return m_hexDigest;
+}
+
+/**
+ * Processes a 64 byte block.
+ *
+ * @param block a block which should be added to the digest
+ * @param blockLength the length of <code>block</code>
+ */
+void ReDigest::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) {
+ int rest = m_chunkSize - m_lengthWaiting;
+ if (rest > blockLength)
+ rest = blockLength;
+ memcpy(m_waiting + m_lengthWaiting, block, rest);
+ blockLength -= rest;
+ block += rest;
+ m_lengthWaiting += rest;
+ // Is the chunk complete?
+ if (m_lengthWaiting == m_chunkSize) {
+ processChunk(m_waiting);
+ m_lengthWaiting = 0;
+ }
+ }
+ // process full 512 bit chunks (64 byte blocks):
+ for (int ix = blockLength / m_chunkSize; ix > 0; ix--) {
+ processChunk(block);
+ block += m_chunkSize;
+ }
+ blockLength %= m_chunkSize;
+ if (blockLength != 0) {
+ assert(m_lengthWaiting == 0);
+ memcpy(m_waiting, block, blockLength);
+ m_lengthWaiting = blockLength;
+ }
+}
+
+/**
+ * Sets the salt of the checksum algorithm.
+ *
+ * Important: set the salt before you make the first <code>update()</code>!
+ *
+ * The salt makes that the checksum of the same input is (extremly) different
+ * to another salt.
+ *
+ * @param salt the salt to set
+ */
+void ReDigest::setSalt(uint64_t salt) {
+ m_salt = salt;
+}
+/**
+ * Constructor.
+ */
+ReMD5::ReMD5() :
+ ReDigest(m_digest, sizeof m_digest),
+ m_a0(0x67452301),
+ m_b0(0xefcdab89),
+ m_c0(0x98badcfe),
+ m_d0(0x10325476) {
+}
+
+/**
+ * Destructor.
+ */
+ReMD5::~ReMD5() {
+}
+
+/**
+ * Finalizes the digest.
+ *
+ * Handles the rest block (< 64 byte) and append a special tail: a "1" bit
+ * and the length of the total input length (in bits).
+ *
+ * @param block the rest input (incomplete chunk)
+ * @param blockLength the length of the block: 0..63
+ */
+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.
+ block[blockLength++] = 0x80;
+ //Pre-processing: padding with zeros
+ //append "0" bit until message length in bits ≡ 448 (mod 512)
+ // fill the rest of the chunk with '\0'.
+ // the last 8 bytes is set to the length in bits (length in bytes * 8)
+ int restLength = (m_length + 1) % RE_DIGEST_CHUNK_SIZE;
+ // 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, 0, zeros);
+ blockLength += zeros;
+ //append original length in bits mod (2 pow 64) to message
+ uint64_t lengthBits = 8LL * m_length + m_salt;
+#if defined __LITTLE_ENDIAN__
+ memcpy(block + blockLength, &lengthBits, 8);
+ blockLength += 8;
+#else
+ 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 > RE_DIGEST_CHUNK_SIZE)
+ processChunk(block + RE_DIGEST_CHUNK_SIZE);
+#if defined __LITTLE_ENDIAN__
+ memcpy(m_digest, &m_a0, 4);
+ memcpy(m_digest + 4, &m_b0, 4);
+ memcpy(m_digest + 8, &m_c0, 4);
+ memcpy(m_digest + 12, &m_d0, 4);
+#else
#define oneWord(word, ix) m_digest[ix] = word; word >>= 8; \\r
m_digest[ix + 1] = word; word >>= 8; m_digest[ix + 2] = word; word >>= 8; \\r
- m_digest[ix + 3] = word\r
- oneWord(m_a0, 0);\r
- oneWord(m_b0, 4);\r
- oneWord(m_c0, 8);\r
- oneWord(m_d0, 12);\r
-#endif\r
-}\r
-\r
-/**\r
- * Processes a 512 bit block ("chunk").\r
- *\r
- * This method is a direct programming of the algorithm described in wikipedia.\r
- */\r
-void ReMD5::processChunk2(const uint8_t block[RE_DIGEST_CHUNK_SIZE]) {\r
- uint32_t M[16];\r
- // break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15\r
- for (int ix = 0; ix < 16; ix++) {\r
- uint32_t x = block[3];\r
- for (int jj = 2; jj >= 0; jj--) {\r
- x = (x << 8) + block[jj];\r
- }\r
- M[ix] = x;\r
- block += 4;\r
- }\r
- //Initialize hash value for this chunk:\r
- uint32_t A = m_a0;\r
- uint32_t B = m_b0;\r
- uint32_t C = m_c0;\r
- uint32_t D = m_d0;\r
- //Main loop:\r
-\r
- int F, g;\r
-//#define TRACE_MD5\r
-#if defined TRACE_MD5\r
- printf("neu: (%s)\n", block);\r
-#endif\r
- for (int i = 0; i < RE_DIGEST_CHUNK_SIZE; i++) {\r
-#if defined TRACE_MD5\r
- if (i < 8)\r
- printf("%2d: A: %08x B: %08x C: %08x D%08x\n", i, A, B, C, D);\r
-#endif\r
- if (i < 16) {\r
-# define F1(B, C, D) ((B & C) | (~ B & D))\r
- // F := (B and C) or ((not B) and D)\r
- F = F1(B, C, D);\r
- g = i;\r
- } else if (i < 32) {\r
- // F := (D and B) or (C and (not D))\r
- // g := (5×i + 1) mod 16\r
-# define F2(B, C, D) ((D & B) | (C & ~ D))\r
- F = F2(B, C, D);\r
- g = (5 * i + 1) % 16;\r
- } else if (i < 48) {\r
- // F := B xor C xor D\r
- // g := (3×i + 5) mod 16\r
-# define F3(B, C, D) ((B ^ C) ^ D)\r
- F = F3(B, C, D);\r
- g = (3 * i + 5) % 16;\r
- } else {\r
- // F := C xor (B or (not D))\r
-# define F4(B, C, D) (C ^ (B | ~ D))\r
- // g := (7×i) mod 16\r
- F = F4(B, C, D);\r
- g = (7 * i) % 16;\r
- }\r
-#if defined TRACE_MD5\r
- if (i < 8)\r
- printf(" K[%2d]: %08x M[%2d]: %08x shift: %02d\n",\r
- i, m_K[i], g, M[g], m_s[i]);\r
-#endif\r
- uint32_t dTemp = D;\r
- D = C;\r
- C = B;\r
- // B := B + leftrotate((A + F + K[i] + M[g]), s[i])\r
- uint32_t x = (A + F + m_K[i] + M[g]);\r
- int shift = m_s[i];\r
- B += (x << shift) | (x >> (32 - shift));\r
- A = dTemp;\r
- }\r
- //Add this chunk's hash to result so far:\r
- m_a0 += A;\r
- m_b0 += B;\r
- m_c0 += C;\r
- m_d0 += D;\r
-}\r
-/** ----------------------\r
- */\r
-#if defined OPTIMIZER_WORKS_GREAT\r
-inline void rotate_left_and_add(uint32_t& rc, uint32_t data, int shift, uint32_t term) {\r
- rc = ((data << shift) | (data >> (32-shift))) + term;\r
-}\r
-//#define TRACE_MD5\r
-#if defined TRACE_MD5\r
-static int s_ix = 0;\r
-#endif\r
-inline void X1(uint32_t &var, uint32_t x, uint32_t y, uint32_t z,\r
- uint32_t data, uint32_t aConst, uint32_t shift) {\r
-#if defined TRACE_MD5\r
- printf("%2d: A: %08x B: %08x C: %08x D%08x\n", s_ix++ % 16, var, x, y, z);\r
- printf(" K[%2d]: %08x M[?]: %08x shift: %02d\n",\r
- s_ix - 1, aConst, data, shift);\r
-#endif\r
- rotate_left_and_add(var, var + F1(x, y, z) + data + aConst, shift, x);\r
-}\r
-inline void X2(uint32_t& var, uint32_t x, uint32_t y, uint32_t z,\r
- uint32_t data, uint32_t aConst, uint32_t shift) {\r
-#if defined TRACE_MD5\r
- printf("%2d: A: %08x B: %08x C: %08x D%08x\n", s_ix++ % 16, var, x, y, z);\r
- printf(" K[%2d]: %08x M[?]: %08x shift: %02d\n",\r
- s_ix - 1, aConst, data, shift);\r
-#endif\r
- rotate_left_and_add(var, var + F2(x, y, z) + data + aConst, shift, x);\r
-}\r
-\r
-inline void X3(uint32_t& var, uint32_t x, uint32_t y, uint32_t z,\r
- uint32_t data, uint32_t aConst, uint32_t shift) {\r
-#if defined TRACE_MD5\r
- printf("%2d: A: %08x B: %08x C: %08x D%08x\n", s_ix++ % 16, var, x, y, z);\r
- printf(" K[%2d]: %08x M[?]: %08x shift: %02d\n",\r
- s_ix - 1, aConst, data, shift);\r
-#endif\r
- rotate_left_and_add(var, var + F3(x, y, z) + data + aConst, shift, x);\r
-}\r
-\r
-inline void X4(uint32_t& var, uint32_t x, uint32_t y, uint32_t z,\r
- uint32_t data, uint32_t aConst, uint32_t shift) {\r
-#if defined TRACE_MD5\r
- printf("%2d: A: %08x B: %08x C: %08x D%08x\n", s_ix++ % 16, var, x, y, z);\r
- printf(" K[%2d]: %08x M[?]: %08x shift: %02d\n",\r
- s_ix - 1, aConst, data, shift);\r
-#endif\r
- rotate_left_and_add(var, var + F4(x, y, z) + data + aConst, shift, x);\r
-}\r
-#else\r
+ m_digest[ix + 3] = word
+ oneWord(m_a0, 0);
+ oneWord(m_b0, 4);
+ oneWord(m_c0, 8);
+ oneWord(m_d0, 12);
+#endif
+}
+
+/**
+ * Processes a 512 bit block ("chunk").
+ *
+ * This method is a direct programming of the algorithm described in wikipedia.
+ */
+void ReMD5::processChunk2(const uint8_t block[RE_DIGEST_CHUNK_SIZE]) {
+ uint32_t M[16];
+ // break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15
+ for (int ix = 0; ix < 16; ix++) {
+ uint32_t x = block[3];
+ for (int jj = 2; jj >= 0; jj--) {
+ x = (x << 8) + block[jj];
+ }
+ M[ix] = x;
+ block += 4;
+ }
+ //Initialize hash value for this chunk:
+ 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;
+//#define TRACE_MD5
+#if defined TRACE_MD5
+ printf("neu: (%s)\n", block);
+#endif
+ for (int i = 0; i < RE_DIGEST_CHUNK_SIZE; i++) {
+#if defined TRACE_MD5
+ if (i < 8)
+ printf("%2d: A: %08x B: %08x C: %08x D%08x\n", i, A, B, C, D);
+#endif
+ if (i < 16) {
+# define F1(B, C, D) ((B & C) | (~ B & D))
+ // F := (B and C) or ((not B) and D)
+ F = F1(B, C, D);
+ g = i;
+ } else if (i < 32) {
+ // F := (D and B) or (C and (not D))
+ // g := (5×i + 1) mod 16
+# define F2(B, C, D) ((D & B) | (C & ~ D))
+ F = F2(B, C, D);
+ g = (5 * i + 1) % 16;
+ } else if (i < 48) {
+ // F := B xor C xor D
+ // g := (3×i + 5) mod 16
+# define F3(B, C, D) ((B ^ C) ^ D)
+ F = F3(B, C, D);
+ g = (3 * i + 5) % 16;
+ } else {
+ // F := C xor (B or (not D))
+# define F4(B, C, D) (C ^ (B | ~ D))
+ // g := (7×i) mod 16
+ F = F4(B, C, D);
+ g = (7 * i) % 16;
+ }
+#if defined TRACE_MD5
+ if (i < 8)
+ printf(" K[%2d]: %08x M[%2d]: %08x shift: %02d\n",
+ i, m_K[i], g, M[g], m_s[i]);
+#endif
+ uint32_t dTemp = D;
+ D = C;
+ C = B;
+ // B := B + leftrotate((A + F + K[i] + M[g]), s[i])
+ uint32_t x = (A + F + m_K[i] + M[g]);
+ int shift = m_s[i];
+ B += (x << shift) | (x >> (32 - shift));
+ A = dTemp;
+ }
+ //Add this chunk's hash to result so far:
+ m_a0 += A;
+ m_b0 += B;
+ m_c0 += C;
+ m_d0 += D;
+}
+/** ----------------------
+ */
+#if defined OPTIMIZER_WORKS_GREAT
+inline void rotate_left_and_add(uint32_t& rc, uint32_t data, int shift, uint32_t term) {
+ rc = ((data << shift) | (data >> (32-shift))) + term;
+}
+//#define TRACE_MD5
+#if defined TRACE_MD5
+static int s_ix = 0;
+#endif
+inline void X1(uint32_t &var, uint32_t x, uint32_t y, uint32_t z,
+ uint32_t data, uint32_t aConst, uint32_t shift) {
+#if defined TRACE_MD5
+ printf("%2d: A: %08x B: %08x C: %08x D%08x\n", s_ix++ % 16, var, x, y, z);
+ printf(" K[%2d]: %08x M[?]: %08x shift: %02d\n",
+ s_ix - 1, aConst, data, shift);
+#endif
+ rotate_left_and_add(var, var + F1(x, y, z) + data + aConst, shift, x);
+}
+inline void X2(uint32_t& var, uint32_t x, uint32_t y, uint32_t z,
+ uint32_t data, uint32_t aConst, uint32_t shift) {
+#if defined TRACE_MD5
+ printf("%2d: A: %08x B: %08x C: %08x D%08x\n", s_ix++ % 16, var, x, y, z);
+ printf(" K[%2d]: %08x M[?]: %08x shift: %02d\n",
+ s_ix - 1, aConst, data, shift);
+#endif
+ rotate_left_and_add(var, var + F2(x, y, z) + data + aConst, shift, x);
+}
+
+inline void X3(uint32_t& var, uint32_t x, uint32_t y, uint32_t z,
+ uint32_t data, uint32_t aConst, uint32_t shift) {
+#if defined TRACE_MD5
+ printf("%2d: A: %08x B: %08x C: %08x D%08x\n", s_ix++ % 16, var, x, y, z);
+ printf(" K[%2d]: %08x M[?]: %08x shift: %02d\n",
+ s_ix - 1, aConst, data, shift);
+#endif
+ rotate_left_and_add(var, var + F3(x, y, z) + data + aConst, shift, x);
+}
+
+inline void X4(uint32_t& var, uint32_t x, uint32_t y, uint32_t z,
+ uint32_t data, uint32_t aConst, uint32_t shift) {
+#if defined TRACE_MD5
+ printf("%2d: A: %08x B: %08x C: %08x D%08x\n", s_ix++ % 16, var, x, y, z);
+ printf(" K[%2d]: %08x M[?]: %08x shift: %02d\n",
+ s_ix - 1, aConst, data, shift);
+#endif
+ rotate_left_and_add(var, var + F4(x, y, z) + data + aConst, shift, x);
+}
+#else
#define rotate_left_and_add(var, data, shift, term) { \\r
uint32_t val = data; \\r
var = ((val << shift) | (val >> (32-shift))) + term; \\r
-}\r
+}
#define X1(var, x, y, z, data, aConst, shift) \\r
- rotate_left_and_add(var, var + F1(x, y, z) + data + aConst, shift, x)\r
+ rotate_left_and_add(var, var + F1(x, y, z) + data + aConst, shift, x)
#define X2(var, x, y, z, data, aConst, shift) \\r
- rotate_left_and_add(var, var + F2(x, y, z) + data + aConst, shift, x)\r
+ rotate_left_and_add(var, var + F2(x, y, z) + data + aConst, shift, x)
#define X3(var, x, y, z, data, aConst, shift) \\r
- rotate_left_and_add(var, var + F3(x, y, z) + data + aConst, shift, x)\r
+ rotate_left_and_add(var, var + F3(x, y, z) + data + aConst, shift, x)
#define X4(var, x, y, z, data, aConst, shift) \\r
- rotate_left_and_add(var, var + F4(x, y, z) + data + aConst, shift, x)\r
-#endif /* OPTIMIZER_WORKS_GREAT */\r
-\r
-/**\r
- * Processes a 512 bit block ("chunk").\r
- *\r
- * This is a optimized version, derived from the method above.\r
- * We unroll the loop, this brings speed with factor 2.\r
- * <pre>\r
- * B := B + leftrotate((A + F + K[i] + M[g]), s[i])\r
- * D := C;\r
- * C := B;\r
- * B := B + leftrotate((A + F + K[i] + M[g]), s[i])\r
- * A := D(old)\r
- * (D, C, B, A) = (C, B, B + leftrotate((A + F + K[i] + M[g]), s[i]), D)\r
- * ==> (A, B, C, D) = (D, B + leftrotate((A + F + K[i] + M[g]), s[i]), B, A)\r
- * The unrolled loop:\r
- * i = g = 0;\r
- * (A, B, C, D) = (D, B + leftrotate((A + F1(B, C, D) + K[0] + M[0]), s[0]), B, A)\r
- * only one var must be calculated, the other 3 are exchanged only.\r
- * i = g = 1;\r
- * (A, B, C, D) = (D, B + leftrotate((A + F1(B, C, D) + K[1] + M[1]), s[1]), B, A)\r
- * i = g = 2;\r
- * (A, B, C, D) = (D, B + leftrotate((A + F1(B, C, D) + K[2] + M[2]), s[2]), B, A)\r
- * i = g = 3;\r
- * (A, B, C, D) = (D, B + leftrotate((A + F1(B, C, D) + K[3] + M[3]), s[3]), B, A)\r
- * in each of the 4 statements another variable (of A, B, C and D) will be calculated\r
- * so we do not exchange in each step, we calculate in the end position\r
- * we define a function to do this:\r
- * void X1(uint32_t &var, uint32_t x, uint32_t y, uint32_t z, uint32_t data, uint32_t shift, uint32_t aConst){\r
- * var = rotate_left(var+ F1(x, y, z) + data + aConst, shift) + x;\r
- * }\r
- * Note: the input parameter of X1 must respect the exchange:\r
- * A -> D -> C -> B ...\r
- * X1(A, B, C, D, M[0], K[0], s[0]);\r
- * X1(D, A, B, C, M[1], K[1], s[1]);\r
- * X1(C, D, A, B, M[2], K[2], s[2]);\r
- * X1(B, C, D, A, M[3], K[3], s[3]);\r
- * ...\r
- * </pre>\r
- */\r
-void ReMD5::processChunk(const uint8_t block[RE_DIGEST_CHUNK_SIZE]) {\r
- uint32_t M[16];\r
- // break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15\r
-#ifdef __LITTLE_ENDIAN__\r
- for (int ix = 0; ix < 16; ix++) {\r
- //memcpy(&M[ix], block + ix * 4, 4);\r
- M[ix] = *(uint32_t*) (block + ix * 4);\r
- }\r
-#elif defined __BIG_ENDIAN__\r
- for (int ix = 0; ix < 16; ix++) {\r
- uint32_t x = block[3];\r
- for (int jj = 2; jj >= 0; jj--) {\r
- x = (x << 8) + block[jj];\r
- }\r
- M[ix] = x;\r
- block += 4;\r
- }\r
-#else\r
-# error "missing __LITTLE_ENDIAN__ or __BIG_ENDIAN__"\r
-#endif\r
- //Initialize hash value for this chunk:\r
- uint32_t A = m_a0;\r
- uint32_t B = m_b0;\r
- uint32_t C = m_c0;\r
- uint32_t D = m_d0;\r
-#if defined NeverAndNeverAndNeverAgain\r
- // Derivation of the optimization:\r
-\r
-#endif\r
- /* Round 1 */\r
- X1(A, B, C, D, M[0], 0xd76aa478, 7);\r
- X1(D, A, B, C, M[1], 0xe8c7b756, 12);\r
- X1(C, D, A, B, M[2], 0x242070db, 17);\r
- X1(B, C, D, A, M[3], 0xc1bdceee, 22);\r
- X1(A, B, C, D, M[4], 0xf57c0faf, 7);\r
- X1(D, A, B, C, M[5], 0x4787c62a, 12);\r
- X1(C, D, A, B, M[6], 0xa8304613, 17);\r
- X1(B, C, D, A, M[7], 0xfd469501, 22);\r
- X1(A, B, C, D, M[8], 0x698098d8, 7);\r
- X1(D, A, B, C, M[9], 0x8b44f7af, 12);\r
- X1(C, D, A, B, M[10], 0xffff5bb1, 17);\r
- X1(B, C, D, A, M[11], 0x895cd7be, 22);\r
- X1(A, B, C, D, M[12], 0x6b901122, 7);\r
- X1(D, A, B, C, M[13], 0xfd987193, 12);\r
- X1(C, D, A, B, M[14], 0xa679438e, 17);\r
- X1(B, C, D, A, M[15], 0x49b40821, 22);\r
-\r
- /* Round 2 */\r
- X2(A, B, C, D, M[1], 0xf61e2562, 5);\r
- X2(D, A, B, C, M[6], 0xc040b340, 9);\r
- X2(C, D, A, B, M[11], 0x265e5a51, 14);\r
- X2(B, C, D, A, M[0], 0xe9b6c7aa, 20);\r
- X2(A, B, C, D, M[5], 0xd62f105d, 5);\r
- X2(D, A, B, C, M[10], 0x02441453, 9);\r
- X2(C, D, A, B, M[15], 0xd8a1e681, 14);\r
- X2(B, C, D, A, M[4], 0xe7d3fbc8, 20);\r
- X2(A, B, C, D, M[9], 0x21e1cde6, 5);\r
- X2(D, A, B, C, M[14], 0xc33707d6, 9);\r
- X2(C, D, A, B, M[3], 0xf4d50d87, 14);\r
- X2(B, C, D, A, M[8], 0x455a14ed, 20);\r
- X2(A, B, C, D, M[13], 0xa9e3e905, 5);\r
- X2(D, A, B, C, M[2], 0xfcefa3f8, 9);\r
- X2(C, D, A, B, M[7], 0x676f02d9, 14);\r
- X2(B, C, D, A, M[12], 0x8d2a4c8a, 20);\r
-\r
- /* Round 3 */\r
- X3(A, B, C, D, M[5], 0xfffa3942, 4);\r
- X3(D, A, B, C, M[8], 0x8771f681, 11);\r
- X3(C, D, A, B, M[11], 0x6d9d6122, 16);\r
- X3(B, C, D, A, M[14], 0xfde5380c, 23);\r
- X3(A, B, C, D, M[1], 0xa4beea44, 4);\r
- X3(D, A, B, C, M[4], 0x4bdecfa9, 11);\r
- X3(C, D, A, B, M[7], 0xf6bb4b60, 16);\r
- X3(B, C, D, A, M[10], 0xbebfbc70, 23);\r
- X3(A, B, C, D, M[13], 0x289b7ec6, 4);\r
- X3(D, A, B, C, M[0], 0xeaa127fa, 11);\r
- X3(C, D, A, B, M[3], 0xd4ef3085, 16);\r
- X3(B, C, D, A, M[6], 0x04881d05, 23);\r
- X3(A, B, C, D, M[9], 0xd9d4d039, 4);\r
- X3(D, A, B, C, M[12], 0xe6db99e5, 11);\r
- X3(C, D, A, B, M[15], 0x1fa27cf8, 16);\r
- X3(B, C, D, A, M[2], 0xc4ac5665, 23);\r
-\r
- /* Round 4 */\r
- X4(A, B, C, D, M[0], 0xf4292244, 6);\r
- X4(D, A, B, C, M[7], 0x432aff97, 10);\r
- X4(C, D, A, B, M[14], 0xab9423a7, 15);\r
- X4(B, C, D, A, M[5], 0xfc93a039, 21);\r
- X4(A, B, C, D, M[12], 0x655b59c3, 6);\r
- X4(D, A, B, C, M[3], 0x8f0ccc92, 10);\r
- X4(C, D, A, B, M[10], 0xffeff47d, 15);\r
- X4(B, C, D, A, M[1], 0x85845dd1, 21);\r
- X4(A, B, C, D, M[8], 0x6fa87e4f, 6);\r
- X4(D, A, B, C, M[15], 0xfe2ce6e0, 10);\r
- X4(C, D, A, B, M[6], 0xa3014314, 15);\r
- X4(B, C, D, A, M[13], 0x4e0811a1, 21);\r
- X4(A, B, C, D, M[4], 0xf7537e82, 6);\r
- X4(D, A, B, C, M[11], 0xbd3af235, 10);\r
- X4(C, D, A, B, M[2], 0x2ad7d2bb, 15);\r
- X4(B, C, D, A, M[9], 0xeb86d391, 21);\r
-\r
- //Add this chunk's hash to result so far:\r
- m_a0 += A;\r
- m_b0 += B;\r
- m_c0 += C;\r
- m_d0 += D;\r
-}\r
-/**\r
- * Prepares the instance for a new checksum.\r
- */\r
-void ReMD5::reset() {\r
- m_a0 = 0x67452301;\r
- m_b0 = 0xefcdab89;\r
- m_c0 = 0x98badcfe;\r
- m_d0 = 0x10325476;\r
- memset(m_digest, 0, sizeof m_digest);\r
- memset(m_waiting, 0, m_chunkSize);\r
- m_lengthWaiting = 0;\r
- m_length = 0;\r
- m_hexDigest.setLength(0);\r
- m_finalized = false;\r
-}\r
+ rotate_left_and_add(var, var + F4(x, y, z) + data + aConst, shift, x)
+#endif /* OPTIMIZER_WORKS_GREAT */
+
+/**
+ * Processes a 512 bit block ("chunk").
+ *
+ * This is a optimized version, derived from the method above.
+ * We unroll the loop, this brings speed with factor 2.
+ * <pre>
+ * B := B + leftrotate((A + F + K[i] + M[g]), s[i])
+ * D := C;
+ * C := B;
+ * B := B + leftrotate((A + F + K[i] + M[g]), s[i])
+ * A := D(old)
+ * (D, C, B, A) = (C, B, B + leftrotate((A + F + K[i] + M[g]), s[i]), D)
+ * ==> (A, B, C, D) = (D, B + leftrotate((A + F + K[i] + M[g]), s[i]), B, A)
+ * The unrolled loop:
+ * i = g = 0;
+ * (A, B, C, D) = (D, B + leftrotate((A + F1(B, C, D) + K[0] + M[0]), s[0]), B, A)
+ * only one var must be calculated, the other 3 are exchanged only.
+ * i = g = 1;
+ * (A, B, C, D) = (D, B + leftrotate((A + F1(B, C, D) + K[1] + M[1]), s[1]), B, A)
+ * i = g = 2;
+ * (A, B, C, D) = (D, B + leftrotate((A + F1(B, C, D) + K[2] + M[2]), s[2]), B, A)
+ * i = g = 3;
+ * (A, B, C, D) = (D, B + leftrotate((A + F1(B, C, D) + K[3] + M[3]), s[3]), B, A)
+ * in each of the 4 statements another variable (of A, B, C and D) will be calculated
+ * so we do not exchange in each step, we calculate in the end position
+ * we define a function to do this:
+ * void X1(uint32_t &var, uint32_t x, uint32_t y, uint32_t z, uint32_t data, uint32_t shift, uint32_t aConst){
+ * var = rotate_left(var+ F1(x, y, z) + data + aConst, shift) + x;
+ * }
+ * Note: the input parameter of X1 must respect the exchange:
+ * A -> D -> C -> B ...
+ * X1(A, B, C, D, M[0], K[0], s[0]);
+ * X1(D, A, B, C, M[1], K[1], s[1]);
+ * X1(C, D, A, B, M[2], K[2], s[2]);
+ * X1(B, C, D, A, M[3], K[3], s[3]);
+ * ...
+ * </pre>
+ */
+void ReMD5::processChunk(const uint8_t block[RE_DIGEST_CHUNK_SIZE]) {
+ 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);
+ M[ix] = *(uint32_t*) (block + ix * 4);
+ }
+#elif defined __BIG_ENDIAN__
+ for (int ix = 0; ix < 16; ix++) {
+ uint32_t x = block[3];
+ for (int jj = 2; jj >= 0; jj--) {
+ x = (x << 8) + block[jj];
+ }
+ M[ix] = x;
+ block += 4;
+ }
+#else
+# error "missing __LITTLE_ENDIAN__ or __BIG_ENDIAN__"
+#endif
+ //Initialize hash value for this chunk:
+ uint32_t A = m_a0;
+ uint32_t B = m_b0;
+ uint32_t C = m_c0;
+ uint32_t D = m_d0;
+#if defined NeverAndNeverAndNeverAgain
+ // Derivation of the optimization:
+
+#endif
+ /* Round 1 */
+ X1(A, B, C, D, M[0], 0xd76aa478, 7);
+ X1(D, A, B, C, M[1], 0xe8c7b756, 12);
+ X1(C, D, A, B, M[2], 0x242070db, 17);
+ X1(B, C, D, A, M[3], 0xc1bdceee, 22);
+ X1(A, B, C, D, M[4], 0xf57c0faf, 7);
+ X1(D, A, B, C, M[5], 0x4787c62a, 12);
+ X1(C, D, A, B, M[6], 0xa8304613, 17);
+ X1(B, C, D, A, M[7], 0xfd469501, 22);
+ X1(A, B, C, D, M[8], 0x698098d8, 7);
+ X1(D, A, B, C, M[9], 0x8b44f7af, 12);
+ X1(C, D, A, B, M[10], 0xffff5bb1, 17);
+ X1(B, C, D, A, M[11], 0x895cd7be, 22);
+ X1(A, B, C, D, M[12], 0x6b901122, 7);
+ X1(D, A, B, C, M[13], 0xfd987193, 12);
+ X1(C, D, A, B, M[14], 0xa679438e, 17);
+ X1(B, C, D, A, M[15], 0x49b40821, 22);
+
+ /* Round 2 */
+ X2(A, B, C, D, M[1], 0xf61e2562, 5);
+ X2(D, A, B, C, M[6], 0xc040b340, 9);
+ X2(C, D, A, B, M[11], 0x265e5a51, 14);
+ X2(B, C, D, A, M[0], 0xe9b6c7aa, 20);
+ X2(A, B, C, D, M[5], 0xd62f105d, 5);
+ X2(D, A, B, C, M[10], 0x02441453, 9);
+ X2(C, D, A, B, M[15], 0xd8a1e681, 14);
+ X2(B, C, D, A, M[4], 0xe7d3fbc8, 20);
+ X2(A, B, C, D, M[9], 0x21e1cde6, 5);
+ X2(D, A, B, C, M[14], 0xc33707d6, 9);
+ X2(C, D, A, B, M[3], 0xf4d50d87, 14);
+ X2(B, C, D, A, M[8], 0x455a14ed, 20);
+ X2(A, B, C, D, M[13], 0xa9e3e905, 5);
+ X2(D, A, B, C, M[2], 0xfcefa3f8, 9);
+ X2(C, D, A, B, M[7], 0x676f02d9, 14);
+ X2(B, C, D, A, M[12], 0x8d2a4c8a, 20);
+
+ /* Round 3 */
+ X3(A, B, C, D, M[5], 0xfffa3942, 4);
+ X3(D, A, B, C, M[8], 0x8771f681, 11);
+ X3(C, D, A, B, M[11], 0x6d9d6122, 16);
+ X3(B, C, D, A, M[14], 0xfde5380c, 23);
+ X3(A, B, C, D, M[1], 0xa4beea44, 4);
+ X3(D, A, B, C, M[4], 0x4bdecfa9, 11);
+ X3(C, D, A, B, M[7], 0xf6bb4b60, 16);
+ X3(B, C, D, A, M[10], 0xbebfbc70, 23);
+ X3(A, B, C, D, M[13], 0x289b7ec6, 4);
+ X3(D, A, B, C, M[0], 0xeaa127fa, 11);
+ X3(C, D, A, B, M[3], 0xd4ef3085, 16);
+ X3(B, C, D, A, M[6], 0x04881d05, 23);
+ X3(A, B, C, D, M[9], 0xd9d4d039, 4);
+ X3(D, A, B, C, M[12], 0xe6db99e5, 11);
+ X3(C, D, A, B, M[15], 0x1fa27cf8, 16);
+ X3(B, C, D, A, M[2], 0xc4ac5665, 23);
+
+ /* Round 4 */
+ X4(A, B, C, D, M[0], 0xf4292244, 6);
+ X4(D, A, B, C, M[7], 0x432aff97, 10);
+ X4(C, D, A, B, M[14], 0xab9423a7, 15);
+ X4(B, C, D, A, M[5], 0xfc93a039, 21);
+ X4(A, B, C, D, M[12], 0x655b59c3, 6);
+ X4(D, A, B, C, M[3], 0x8f0ccc92, 10);
+ X4(C, D, A, B, M[10], 0xffeff47d, 15);
+ X4(B, C, D, A, M[1], 0x85845dd1, 21);
+ X4(A, B, C, D, M[8], 0x6fa87e4f, 6);
+ X4(D, A, B, C, M[15], 0xfe2ce6e0, 10);
+ X4(C, D, A, B, M[6], 0xa3014314, 15);
+ X4(B, C, D, A, M[13], 0x4e0811a1, 21);
+ X4(A, B, C, D, M[4], 0xf7537e82, 6);
+ X4(D, A, B, C, M[11], 0xbd3af235, 10);
+ X4(C, D, A, B, M[2], 0x2ad7d2bb, 15);
+ X4(B, C, D, A, M[9], 0xeb86d391, 21);
+
+ //Add this chunk's hash to result so far:
+ m_a0 += A;
+ m_b0 += B;
+ m_c0 += C;
+ m_d0 += D;
+}
+/**
+ * Prepares the instance for a new checksum.
+ */
+void ReMD5::reset() {
+ m_a0 = 0x67452301;
+ m_b0 = 0xefcdab89;
+ m_c0 = 0x98badcfe;
+ m_d0 = 0x10325476;
+ memset(m_digest, 0, sizeof m_digest);
+ memset(m_waiting, 0, m_chunkSize);
+ m_lengthWaiting = 0;
+ m_length = 0;
+ m_hexDigest.setLength(0);
+ m_finalized = false;
+}