From: Hamatoma Date: Sat, 28 Feb 2015 23:24:26 +0000 (+0100) Subject: ReDigest + ReRPD64 X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=c7fd25a9915a51305f2bb0930ba6e843e15e8cd4;p=crepublib ReDigest + ReRPD64 --- diff --git a/base/ReLogger.hpp b/base/ReLogger.hpp index 4bb436d..b1e99ec 100644 --- a/base/ReLogger.hpp +++ b/base/ReLogger.hpp @@ -19,7 +19,10 @@ typedef unsigned long int ReLogLocation; * Aborts, errors, warnings and informations. */ enum ReLogClass { - LOG_ABORT = 1, LOG_ERROR = 2, LOG_WARNING = 4, LOG_INFO = 8, + LOG_ABORT = 1, + LOG_ERROR = 2, + LOG_WARNING = 4, + LOG_INFO = 8, LOG_CLASS_ALL = 0xf }; diff --git a/cunit/cuReMD5.cpp b/cunit/cuReMD5.cpp index 6894de8..a80828f 100644 --- a/cunit/cuReMD5.cpp +++ b/cunit/cuReMD5.cpp @@ -9,7 +9,6 @@ #include "base/rebase.hpp" #include "math/remath.hpp" -#include "math/md5.hpp" class TestReMd5: public ReTestUnit { public: diff --git a/cunit/cuReRPD64.cpp b/cunit/cuReRPD64.cpp new file mode 100644 index 0000000..0c2e4b3 --- /dev/null +++ b/cunit/cuReRPD64.cpp @@ -0,0 +1,119 @@ +/* + * cuReMatcher.cpp + * + * License: Public domain + * Do what you want. + * No warranties and disclaimer of any damages. + * The latest sources: https://github.com/republib + */ + +#include "base/rebase.hpp" +#include "math/remath.hpp" + +class TestReRPD64: public ReTestUnit { +public: + TestReRPD64() : + ReTestUnit("ReRPD64", __FILE__) { + run(); + } +private: + void run() { + testBase(); + testSpeed(); + testLong(); + testBig(); + } + void testBase() { + ReRPD64 RPD64; + const char* text = + "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVEXYZ01234567890\n"; + RPD64.update((const uint8_t*) text, strlen(text)); + checkEqu("148517865cc2ca2c4ea2c2130a485769", RPD64.hexDigest()); + RPD64.reset(); + text = "The quick brown fox jumps over the lazy dog"; + RPD64.update((const uint8_t*) text, -1); + checkEqu("064f9242cfaa1e270f9c28d7a90a6bcc", RPD64.hexDigest()); + RPD64.reset(); + RPD64.update((const uint8_t*) "", 0); + checkEqu("e602b42cc6d1e20b6b56f2b2f7542f38", RPD64.hexDigest()); + } + int testOneLong(ReByteBuffer& text, int seed2 = 0) { + ReRPD64 RPD64; + int rc = 0; + ReShiftRandom random; + random.setSeed(text.length() + seed2); + + RPD64.update((uint8_t*) text.str(), text.length()); + ReByteBuffer digest(RPD64.hexDigest()); + RPD64.reset(); + int max2 = text.length() / 20; + if (max2 < 1) + max2 = random.nextInt(20); + while (text.length() > 0) { + int part = random.nextInt(32, 32 + 1 + max2); + if (part > (int) text.length()) + part = text.length(); + RPD64.update((uint8_t*) text.str(), part); + text.remove(0, part); + rc++; + } + checkEqu(digest, RPD64.hexDigest()); + return rc; + } + void testLong() { + ReByteBuffer text( + "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVEXYZ0123456789001234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVEXYZ01234567890\n"); + for (int ii = 178 - 69 + 1; ii > 0; ii--) { + text.setLength(ii); + testOneLong(text, 200 * ii + 0x47111); + } + } + void testBig() { + ReByteBuffer text; + ReShiftRandom random; + int64_t start = timer(); + int count = 1000; + int parts = 0; + int sumLength = 0; + for (int ii = 0; ii < count; ii++) { + random.nextString(10, 20000, text); + sumLength += text.length(); + parts += testOneLong(text, 333 * ii + 0x55221); + } + printf("count: %d updates: %d avg length: %d duration: %s\n", count, + parts, sumLength / count, + ReByteBuffer("").appendMilliSec(milliSecSince(start)).str()); + } + void testSpeed() { + int max = 1024 * 1024 * 50; + ReByteBuffer buffer; + buffer.ensureSize(max); + buffer.setLength(max - 1); + buffer.fill('x', max - 1); + ReRPD64 RPD64; + int passes = 20; + int64_t start = timer(); + for (int ii = 0; ii < passes; ii++) { + RPD64.reset(); + RPD64.update((uint8_t*) buffer.str(), max - 1); + } + int duration = milliSecSince(start); + if (duration == 0) + duration = 1; + printf( + "%s endian size: %.1f MiByte count: %d rate: %.2f MiB/sec duration: %s\n", +#if defined __LITTLE_ENDIAN__ + "little", +#else + "big", +#endif + max / 1024.0 / 1024, passes, + max / 1024.0 / 1024 * 1000 * passes / duration, + ReByteBuffer("").appendMilliSec(duration).str()); + } +}; +extern void testReRPD64(void); + +void testReRPD64(void) { + TestReRPD64 unit; +} diff --git a/cunit/testall.cpp b/cunit/testall.cpp index 7e55440..ddc73ae 100644 --- a/cunit/testall.cpp +++ b/cunit/testall.cpp @@ -71,6 +71,8 @@ void testOs() { void testMath() { extern void testReMD5(); testReMD5(); + extern void testReRPD64(); + testReRPD64(); extern void testReRandomizer(); testReRandomizer(); } diff --git a/math/ReMD5.cpp b/math/ReMD5.cpp index fe9aea3..000252d 100644 --- a/math/ReMD5.cpp +++ b/math/ReMD5.cpp @@ -8,15 +8,15 @@ #include "base/rebase.hpp" #include "math/remath.hpp" -#define __LITTLE_ENDIAN__ - -const int ReMD5::m_s[64] = { 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, +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 }; static int s_ix = 0; // for x in [1..64] : int(2**32 * sin(x)) -const uint32_t ReMD5::m_K[64] = { 0xd76aa478, 0xe8c7b756, 0x242070db, +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, @@ -31,38 +31,105 @@ const uint32_t ReMD5::m_K[64] = { 0xd76aa478, 0xe8c7b756, 0x242070db, /** * Constructor. + * + * @param digest the buffer for the binary checksum + * @param digestSize the length of digest */ -ReMD5::ReMD5() : - //m_digest - // m_hexDigest; - // m_waiting[64]; +ReDigest::ReDigest(uint8_t* digest, size_t digestSize) : + m_digest(digest), + m_digestSize(digestSize), + // m_waiting[RE_DIGEST_CHUNK_SIZE]; m_lengthWaiting(0), m_length(0), - m_a0(0x67452301), - m_b0(0xefcdab89), - m_c0(0x98badcfe), - m_d0(0x10325476), m_finalized(false) { } - /** * Destructor. */ -ReMD5::~ReMD5() { +ReDigest::~ReDigest(){ } - /** * Returns the binary digest value. * * @return the binary digest (16 byte array) */ -const uint8_t* ReMD5::digest() { +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 ReByteBuffer& ReDigest::hexDigest() { + if (m_hexDigest.length() == 0) { + 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 block + */ +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_digestSize - 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 == RE_DIGEST_CHUNK_SIZE) { + processChunk(m_waiting); + m_lengthWaiting = 0; + } + } + // process full 512 bit chunks (64 byte blocks): + for (int ix = blockLength / RE_DIGEST_CHUNK_SIZE; ix > 0; ix--) { + processChunk(block); + block += RE_DIGEST_CHUNK_SIZE; + } + blockLength %= RE_DIGEST_CHUNK_SIZE; + if (blockLength != 0) { + assert(m_lengthWaiting == 0); + memcpy(m_waiting, block, blockLength); + m_lengthWaiting = blockLength; + } +} + +/** + * 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. * @@ -83,7 +150,7 @@ void ReMD5::finalize() { //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) % 64; + 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; @@ -112,8 +179,8 @@ void ReMD5::finalize() { block[blockLength++] = lengthBits; #endif processChunk(block); - if (blockLength > 64) - processChunk(block + 64); + 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); @@ -130,27 +197,12 @@ void ReMD5::finalize() { #endif } -/** - * Returns the binary digest value. - * - * @return the binary digest (16 byte array) - */ -const ReByteBuffer& ReMD5::hexDigest() { - if (m_hexDigest.length() == 0) { - digest(); - for (int ix = 0; ix < 16; ix++) { - m_hexDigest.appendInt(m_digest[ix], "%02x"); - } - } - return m_hexDigest; -} - /** * 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[64]) { +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++) { @@ -173,7 +225,7 @@ void ReMD5::processChunk2(const uint8_t block[64]) { #if defined TRACE_MD5 printf("neu: (%s)\n", block); #endif - for (int i = 0; i < 64; i++) { + 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); @@ -320,7 +372,7 @@ inline void X4(uint32_t& var, uint32_t x, uint32_t y, uint32_t z, * ... * */ -void ReMD5::processChunk(const uint8_t block[64]) { +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__ @@ -442,41 +494,3 @@ void ReMD5::reset() { m_hexDigest.setLength(0); m_finalized = false; } -/** - * Processes a 64 byte block. - * - * @param block a block which should be added to the digest - * @param blockLength the length of block - */ -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) { - int rest = 64 - 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 == 64) { - processChunk(m_waiting); - m_lengthWaiting = 0; - } - } - // 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; - } -} - diff --git a/math/ReMD5.hpp b/math/ReMD5.hpp index d4b5e1a..427db8c 100644 --- a/math/ReMD5.hpp +++ b/math/ReMD5.hpp @@ -8,45 +8,60 @@ #ifndef MATH_REMD5_HPP_ #define MATH_REMD5_HPP_ -typedef uint8_t ReDigest[16]; -/** - * Building of the MD5 checksum. - * - * The algorithm is described in http://en.wikipedia.org/wiki/MD5. - */ -class ReMD5 { +typedef uint8_t ReMD5Digest_t[16]; +#define RE_DIGEST_CHUNK_SIZE 64 + +class ReDigest { public: - ReMD5(); - virtual ~ReMD5(); + ReDigest(uint8_t* buffer, size_t bufferSize); + virtual ~ReDigest(); public: const uint8_t* digest(); const ReByteBuffer& hexDigest(); - void update(const uint8_t* block, int blockLength); - void processChunk(const uint8_t block[64]); - void processChunk2(const uint8_t block[64]); - void reset(); -private: - void finalize(); - -private: - ReDigest m_digest; + virtual void update(const uint8_t* block, int blockLength); + virtual void processChunk(const uint8_t* block) = 0; + virtual void reset() = 0; +protected: + virtual void finalize() = 0; +protected: + uint8_t* m_digest; + size_t m_digestSize; ReByteBuffer m_hexDigest; // normally only the first chunk is used (64 byte), but while finalization // a 2nd chunk may be needed. - uint8_t m_waiting[64 + 64]; + uint8_t m_waiting[RE_DIGEST_CHUNK_SIZE + RE_DIGEST_CHUNK_SIZE]; int m_lengthWaiting; // total count of input bytes: uint32_t m_length; + bool m_finalized; +}; + +/** + * Building of the MD5 checksum. + * + * The algorithm is described in http://en.wikipedia.org/wiki/MD5. + */ +class ReMD5 : public ReDigest { +public: + ReMD5(); + virtual ~ReMD5(); +public: + virtual void processChunk(const uint8_t* block); + void processChunk2(const uint8_t* block); + virtual void reset(); +protected: + virtual void finalize(); +private: + ReMD5Digest_t m_digest; 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_s[RE_DIGEST_CHUNK_SIZE]; // Constants: - static const uint32_t m_K[64]; + static const uint32_t m_K[RE_DIGEST_CHUNK_SIZE]; }; #endif /* MATH_REMD5_HPP_ */ diff --git a/math/ReRPD64.cpp b/math/ReRPD64.cpp new file mode 100644 index 0000000..5fa6a26 --- /dev/null +++ b/math/ReRPD64.cpp @@ -0,0 +1,297 @@ +/* + * ReRPD64.cpp + * + * Created on: 30.01.2015 + * + */ + +#include "base/rebase.hpp" +#include "math/remath.hpp" + +/** + * Constructor. + */ +ReRPD64::ReRPD64() : + //m_digest + // m_hexDigest; + // m_waiting[64]; + m_lengthWaiting(0), + m_length(0), + m_a0(0), + m_b0(0), + m_c0(0), + m_d0(0), + m_finalized(false), + m_salt(1) { + reset(); +} + +/** + * Destructor. + */ +ReRPD64::~ReRPD64() { +} + +/** + * Returns the binary digest value. + * + * @return the binary digest (16 byte array) + */ +const uint8_t* ReRPD64::digest() { + if (!m_finalized) { + finalize(); + } + return m_digest; +} + +/** + * 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 ReRPD64::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) % 64; + // 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 > 64) + processChunk(block + 64); + m_a0 ^= m_b0; + m_c0 ^= m_d0; +#if defined __LITTLE_ENDIAN__ + memcpy(m_digest, &m_a0, 8); + memcpy(m_digest + 8, &m_c0, 8); +#else +#define oneQWord(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; word >>= 8; m_digest[ix + 4] = word; word >>= 8; \ + m_digest[ix + 4] = word; word >>= 8; m_digest[ix + 5] = word; word >>= 8; \ + m_digest[ix + 6] = word; word >>= 8; m_digest[ix + 7] = word + oneWord(m_a0, 0); + oneWord(m_c0, 8); +#endif +} + +/** + * Returns the binary digest value. + * + * @return the binary digest (16 byte array) + */ +const ReByteBuffer& ReRPD64::hexDigest() { + if (m_hexDigest.length() == 0) { + digest(); + for (int ix = 0; ix < 16; ix++) { + m_hexDigest.appendInt(m_digest[ix], "%02x"); + } + } + return m_hexDigest; +} +#define F1(B, C, D) ((B & C) | (~ B & D)) +#define F2(B, C, D) ((D & B) | (C & ~ D)) +#define F3(B, C, D) ((B ^ C) ^ D) +#define F4(B, C, D) (C ^ (B | ~ D)) + +#if defined OPTIMIZER_WORKS_GREAT +inline void rotate_left_and_add(uint64_t& rc, uint64_t data, int shift, uint64_t term) { + rc = ((data << shift) | (data >> (64-shift))) + term; +} +inline void X1(uint64_t &var, uint64_t x, uint64_t y, uint64_t z, + uint64_t data, uint64_t aConst, uint64_t shift) { + rotate_left_and_add(var, var + F1(x, y, z) + data + aConst, shift, x); +} +inline void X2(uint64_t& var, uint64_t x, uint64_t y, uint64_t z, + uint64_t data, uint64_t aConst, uint64_t shift) { + rotate_left_and_add(var, var + F2(x, y, z) + data + aConst, shift, x); +} + +inline void X3(uint64_t& var, uint64_t x, uint64_t y, uint64_t z, + uint64_t data, uint64_t aConst, uint64_t shift) { + rotate_left_and_add(var, var + F3(x, y, z) + data + aConst, shift, x); +} + +inline void X4(uint64_t& var, uint64_t x, uint64_t y, uint64_t z, + uint64_t data, uint64_t aConst, uint64_t shift) { + rotate_left_and_add(var, var + F4(x, y, z) + data + aConst, shift, x); +} +#else +#define rotate_left_and_add(var, data, shift, term) { \ + uint64_t val = data; \ + var = ((val << (shift)) | (val >> (64-(shift)))) + term; \ +} +#define X1(var, x, y, z, data, aConst, shift) \ + rotate_left_and_add(var, var + F1(x, y, z) + data + aConst, shift, x) +#define X2(var, x, y, z, data, aConst, shift) \ + rotate_left_and_add(var, var + F2(x, y, z) + data + aConst, shift, x) +#define X3(var, x, y, z, data, aConst, shift) \ + rotate_left_and_add(var, var + F3(x, y, z) + data + aConst, shift, x) +#define X4(var, x, y, z, data, aConst, shift) \ + rotate_left_and_add(var, var + F4(x, y, z) + data + aConst, shift, x) +#endif /* OPTIMIZER_WORKS_GREAT */ + +/** + * Processes a 512 bit block ("chunk"). + * + */ +void ReRPD64::processChunk(const uint8_t block[64]) { + uint64_t M[8]; + // break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15 +#ifdef __LITTLE_ENDIAN__ + for (int ix = 0; ix < 8; ix++) { + //memcpy(&M[ix], block + ix * 8, 8); + M[ix] = *(uint64_t*) (block + ix * 8); + } +#elif defined __BIG_ENDIAN__ + for (int ix = 0; ix < 16; ix++) { + uint64_t x = block[8-1]; + for (int jj = 8 - 2; jj >= 0; jj--) { + x = (x << 8) + block[jj]; + } + M[ix] = x; + block += 8; + } +#else +# error "missing __LITTLE_ENDIAN__ or __BIG_ENDIAN__" +#endif + //Initialize hash value for this chunk: + uint64_t A = m_a0; + uint64_t B = m_b0; + uint64_t C = m_c0; + uint64_t D = m_d0; + /* Round 1 */ + X1(A, B, C, D, M[0], 0xd76aa478698098d8ll, 7); + X1(D, A, B, C, M[1], 0xe8c7b7568b44f7afll, 12); + X1(C, D, A, B, M[2], 0x242070dbffff5bb1ll, 17); + X1(B, C, D, A, M[3], 0xc1bdceee895cd7bell, 22); + X1(A, B, C, D, M[4], 0xf57c0faf6b901122ll, 32 + 7); + X1(D, A, B, C, M[5], 0x4787c62afd987193ll, 32 + 12); + X1(C, D, A, B, M[6], 0xa8304613a679438ell, 32 + 17); + X1(B, C, D, A, M[7], 0xfd46950149b40821ll, 32 + 22); + + /* Round 2 */ + X2(A, B, C, D, M[1], 0xf61e256221e1cde6ll, 5); + X2(D, A, B, C, M[6], 0xc040b340c33707d6ll, 9); + X2(C, D, A, B, M[3], 0x265e5a51f4d50d87ll, 14); + X2(B, C, D, A, M[0], 0xe9b6c7aa455a14edll, 20); + X2(A, B, C, D, M[5], 0xd62f105da9e3e905ll, 5 + 32); + X2(D, A, B, C, M[2], 0x02441453fcefa3f8ll, 9 + 32); + X2(C, D, A, B, M[7], 0xd8a1e681676f02d9ll, 14 + 32); + X2(B, C, D, A, M[4], 0xe7d3fbc88d2a4c8all, 20 + 32); + + /* Round 3 */ + X3(A, B, C, D, M[5], 0xfffa3942289b7ec6ll, 4); + X3(D, A, B, C, M[2], 0x8771f681eaa127fall, 11); + X3(C, D, A, B, M[7], 0x6d9d6122d4ef3085ll, 16); + X3(B, C, D, A, M[4], 0xfde5380c04881d05ll, 23); + X3(A, B, C, D, M[1], 0xa4beea44d9d4d039ll, 4 + 32); + X3(D, A, B, C, M[6], 0x4bdecfa9e6db99e5ll, 11 + 32); + X3(C, D, A, B, M[3], 0xf6bb4b601fa27cf8ll, 16 + 32); + X3(B, C, D, A, M[0], 0xbebfbc70c4ac5665ll, 23 + 32); + + /* Round 4 */ + X4(A, B, C, D, M[0], 0xf42922446fa87e4fll, 6); + X4(D, A, B, C, M[7], 0x432aff97fe2ce6e0ll, 10); + X4(C, D, A, B, M[4], 0xab9423a7a3014314ll, 15); + X4(B, C, D, A, M[1], 0xfc93a0394e0811a1ll, 21); + X4(A, B, C, D, M[6], 0x655b59c3f7537e82ll, 6 + 32); + X4(D, A, B, C, M[3], 0x8f0ccc92bd3af235ll, 10 + 32); + X4(C, D, A, B, M[0], 0xffeff47d2ad7d2bbll, 15 + 32); + X4(B, C, D, A, M[5], 0x85845dd1eb86d391ll, 21 + 32); + + //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 ReRPD64::reset() { + m_a0 = 0xd76aa478698098d8ll; + m_b0 = 0xe8c7b7568b44f7afll; + m_c0 = 0x242070dbffff5bb1ll; + m_d0 = 0xc1bdceee895cd7bell; + memset(m_digest, 0, sizeof m_digest); + 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. + * + * @param block a block which should be added to the digest + * @param blockLength the length of block + */ +void ReRPD64::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 = 64 - 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 == 64) { + processChunk (m_waiting); + m_lengthWaiting = 0; + } + } + // 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; + } +} + diff --git a/math/ReRPD64.hpp b/math/ReRPD64.hpp new file mode 100644 index 0000000..21ba5fa --- /dev/null +++ b/math/ReRPD64.hpp @@ -0,0 +1,48 @@ +/* + * ReRPD64.hpp + * + * Created on: 30.01.2015 + * Author: hm + */ + +#ifndef MATH_RERPD64_HPP_ +#define MATH_RERPD64_HPP_ + +typedef uint8_t ReRPD64Digest[16]; +/** + * Building of the Real Publib library checksum. + * + * The algorithm is similar to MD5, but calculation is done in 64-bit. + */ +class ReRPD64 { +public: + ReRPD64(); + virtual ~ReRPD64(); +public: + const uint8_t* digest(); + const ReByteBuffer& hexDigest(); + void update(const uint8_t* block, int blockLength); + void processChunk(const uint8_t block[64]); + void reset(); + void setSalt(uint64_t salt); +private: + void finalize(); + +private: + ReRPD64Digest m_digest; + ReByteBuffer m_hexDigest; + // normally only the first chunk is used (64 byte), but while finalization + // a 2nd chunk may be needed. + uint8_t m_waiting[64 + 64]; + int m_lengthWaiting; + // total count of input bytes: + uint64_t m_length; + uint64_t m_a0; + uint64_t m_b0; + uint64_t m_c0; + uint64_t m_d0; + bool m_finalized; + uint64_t m_salt; +}; + +#endif /* MATH_RERPD64_HPP_ */ diff --git a/math/remath.hpp b/math/remath.hpp index b2b5d00..db9eca9 100644 --- a/math/remath.hpp +++ b/math/remath.hpp @@ -14,5 +14,6 @@ #include "math/ReObfuscator.hpp" #include "math/ReRandomizer.hpp" #include "math/ReMD5.hpp" +#include "math/ReRPD64.hpp" #endif /* REMATH_HPP_ */