From 299d1ac57464f8ef0967c22cc01a146f5f79454e Mon Sep 17 00:00:00 2001 From: hama Date: Mon, 2 Feb 2015 21:02:12 +0100 Subject: [PATCH] hexdump --- base/ReByteBuffer.cpp | 77 +++++++++ base/ReByteBuffer.hpp | 4 + cunit/cuReByteBuffer.cpp | 25 +++ cunit/cuReMD5.cpp | 16 ++ cunit/testall.cpp | 8 +- math/ReMD5.cpp | 98 ++++++----- math/ReMD5.hpp | 14 +- math/md5.cpp | 362 +++++++++++++++++++++++++++++++++++++++ math/md5.hpp | 93 ++++++++++ 9 files changed, 642 insertions(+), 55 deletions(-) create mode 100644 math/md5.cpp create mode 100644 math/md5.hpp diff --git a/base/ReByteBuffer.cpp b/base/ReByteBuffer.cpp index acf4992..234bd8e 100644 --- a/base/ReByteBuffer.cpp +++ b/base/ReByteBuffer.cpp @@ -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. + * + *
Example:
+ * buffer.appendHex("01234567890abcde", -1, 0x10, 16, "%0x8x", 1, -1, " | ");
+ * 
+ * Buffer contains:
+ * 00000010  30 31 32 33 34 35 36 37  38 39 30 61 62 63 64 65 | 01234567890abcde
+ * 
+ * + * @param data data to dump + * @param length length of data. -1: strlen(data) + * @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 true: the data is interpreted as ASCII too + * @param groupWidth behind groupWidth hex bytes a ' ' is appended + * @param gapBehind behind gapBehind hex bytes a ' ' is appended
+ * -1: bytePerLine / 2 + * @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 diff --git a/base/ReByteBuffer.hpp b/base/ReByteBuffer.hpp index a3bcc5b..9dcc9f9 100644 --- a/base/ReByteBuffer.hpp +++ b/base/ReByteBuffer.hpp @@ -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. diff --git a/cunit/cuReByteBuffer.cpp b/cunit/cuReByteBuffer.cpp index 982d3fd..4823b2f 100644 --- a/cunit/cuReByteBuffer.cpp +++ b/cunit/cuReByteBuffer.cpp @@ -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); diff --git a/cunit/cuReMD5.cpp b/cunit/cuReMD5.cpp index c3fd456..3bac001 100644 --- a/cunit/cuReMD5.cpp +++ b/cunit/cuReMD5.cpp @@ -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); diff --git a/cunit/testall.cpp b/cunit/testall.cpp index 844d604..2634bb6 100644 --- a/cunit/testall.cpp +++ b/cunit/testall.cpp @@ -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(); diff --git a/math/ReMD5.cpp b/math/ReMD5.cpp index 4621c31..403522e 100644 --- a/math/ReMD5.cpp +++ b/math/ReMD5.cpp @@ -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 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){ @@ -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; + } } } diff --git a/math/ReMD5.hpp b/math/ReMD5.hpp index 7c885ee..1294bc3 100644 --- a/math/ReMD5.hpp +++ b/math/ReMD5.hpp @@ -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 index 0000000..0c1b9dc --- /dev/null +++ b/math/md5.cpp @@ -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 + + +// 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 index 0000000..e6f3e4c --- /dev/null +++ b/math/md5.hpp @@ -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 +#include + + +// 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 -- 2.39.5