Browse Source

Use internal MD5 calculation

Tindy X 5 years ago
parent
commit
5aa47c7cf2
4 changed files with 876 additions and 0 deletions
  1. 1 0
      CMakeLists.txt
  2. 655 0
      src/md5.cpp
  3. 207 0
      src/md5.h
  4. 13 0
      src/misc.cpp

+ 1 - 0
CMakeLists.txt

@@ -42,6 +42,7 @@ ADD_EXECUTABLE(subconverter
     src/interfaces.cpp
     src/logger.cpp
     src/main.cpp
+    src/md5.cpp
     src/misc.cpp
     src/multithread.cpp
     src/nodemanip.cpp

+ 655 - 0
src/md5.cpp

@@ -0,0 +1,655 @@
+#include <cassert>
+#include <cstring>
+#include <iostream>
+
+#include "md5.h"
+
+namespace md5 {
+    /*
+     * T denotes the integer part of the i-th element of the function:
+     * T[i] = 4294967296 * abs(sin(i)), where i is in radians.
+     */
+    const unsigned int T[64] = {
+        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
+    };
+
+    /*
+     * Constants for the MD5 Transform routine as defined in RFC 1321
+     */
+    const unsigned int S1[4] = {7, 12, 17, 22};
+    const unsigned int S2[4] = {5, 9,  14, 20};
+    const unsigned int S3[4] = {4, 11, 16, 23};
+    const unsigned int S4[4] = {6, 10, 15, 21};
+
+    /*
+     * Function to perform the cyclic left rotation of blocks of data
+     */
+    inline unsigned int cyclic_left_rotate(unsigned int data, unsigned int shift_bits) {
+        return (data << shift_bits) | (data >> (32 - shift_bits));
+    }
+
+    inline unsigned int F(unsigned int x, unsigned int y, unsigned int z) {return (x & y) | (~x & z);};
+    inline unsigned int G(unsigned int x, unsigned int y, unsigned int z) {return (x & z) | (y & ~z);};
+    inline unsigned int H(unsigned int x, unsigned int y, unsigned int z) {return x ^ y ^ z;};
+    inline unsigned int I(unsigned int x, unsigned int y, unsigned int z) {return y ^ (x | ~z);};
+
+    inline void FF(unsigned int &a, unsigned int b, unsigned int c, unsigned int d, unsigned int Xk, unsigned int s, unsigned int i) {
+        #if MD5_DEBUG
+            std::cout << "\nA: " << a << "\nB: " << b << "\nC: " << c << "\nD: " << d << "\nX[" << i << "]: " << Xk << "\ns: " << S1[s] << "\nT: " << T[i] << "\n";
+        #endif
+
+        a += F(b,c,d) + Xk + T[i];
+        a = cyclic_left_rotate(a, S1[s]);
+        a += b;
+
+        #if MD5_DEBUG
+            std::cout << "A = " << a << "\n";
+        #endif
+    };
+
+    inline void GG(unsigned int &a, unsigned int b, unsigned int c, unsigned int d, unsigned int Xk, unsigned int s, unsigned int i) {
+        #if MD5_DEBUG
+            std::cout << "\nA: " << a << "\nB: " << b << "\nC: " << c << "\nD: " << d << "\nX[" << i - 16 << "]: " << Xk << "\ns: " << S2[s] << "\nT: " << T[i] << "\n";
+        #endif // MD5_DEBUG
+
+        a += G(b,c,d) + Xk + T[i];
+        a = cyclic_left_rotate(a, S2[s]);
+        a += b;
+
+        #if MD5_DEBUG
+            std::cout << "A = " << a << "\n";
+        #endif // MD5_DEBUG
+    };
+
+    inline void HH(unsigned int &a, unsigned int b, unsigned int c, unsigned int d, unsigned int Xk, unsigned int s, unsigned int i) {
+        #if MD5_DEBUG
+            std::cout << "\nA: " << a << "\nB: " << b << "\nC: " << c << "\nD: " << d << "\nX[" << i - 32 << "]: " << Xk << "\ns: " << S3[s] << "\nT: " << T[i] << "\n";
+        #endif // MD5_DEBUG
+
+        a += H(b,c,d) + Xk + T[i];
+        a = cyclic_left_rotate(a, S3[s]);
+        a += b;
+
+        #if MD5_DEBUG
+            std::cout << "A = " << a << "\n";
+        #endif // MD5_DEBUG
+    };
+    inline void II(unsigned int &a, unsigned int b, unsigned int c, unsigned int d, unsigned int Xk, unsigned int s, unsigned int i) {
+        #if MD5_DEBUG
+            std::cout << "\nA: " << a << "\nB: " << b << "\nC: " << c << "\nD: " << d << "\nX[" << i - 48 << "]: " << Xk << "\ns: " << S4[s] << "\nT: " << T[i] << "\n";
+        #endif // MD5_DEBUG
+
+        a += I(b,c,d) + Xk + T[i];
+        a = cyclic_left_rotate(a, S4[s]);
+        a += b;
+
+        #if MD5_DEBUG
+            std::cout << "A = " << a << "\n";
+        #endif // MD5_DEBUG
+    };
+
+    /*
+     * Define my endian-ness.  Could not do in a portable manner using the
+     * include files -- grumble.
+     */
+    #if MD5_BIG_ENDIAN
+
+    /*
+     * big endian - big is better
+     */
+    #define MD5_SWAP(n) (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
+
+    #else
+
+    /*
+     * little endian
+     */
+    #define MD5_SWAP(n) (n)
+
+    #endif // MD5_BIG_ENDIAN
+
+    const char* HEX_STRING = "0123456789abcdef";    /* to convert to hex */
+
+    /****************************** Public Functions ******************************/
+
+    /*
+     * md5_t
+     *
+     * DESCRIPTION:
+     *
+     * Initialize structure containing state of MD5 computation. (RFC 1321,
+     * 3.3: Step 3).  This is for progressive MD5 calculations only.  If
+     * you have the complete string available, call it as below.
+     * process should be called for each bunch of bytes and after the
+     * last process call, finish should be called to get the signature.
+     *
+     * RETURNS:
+     *
+     * None.
+     *
+     * ARGUMENTS:
+     *
+     * None.
+     */
+    md5_t::md5_t() {
+        initialise();
+    }
+
+    /*
+     * md5_t
+     *
+     * DESCRIPTION:
+     *
+     * This function is used to calculate a MD5 signature for a buffer of
+     * bytes.  If you only have part of a buffer that you want to process
+     * then md5_t, process, and finish should be used.
+     *
+     * RETURNS:
+     *
+     * None.
+     *
+     * ARGUMENTS:
+     *
+     * buffer - A buffer of bytes whose MD5 signature we are calculating.
+     *
+     * input_length - The length of the buffer.
+     *
+     * signature - A 16 byte buffer that will contain the MD5 signature.
+     */
+    md5_t::md5_t(const void* input, const unsigned int input_length, void* signature) {
+        /* initialize the computation context */
+        initialise();
+
+        /* process whole buffer but last input_length % MD5_BLOCK bytes */
+        process(input, input_length);
+
+        /* put result in desired memory area */
+        finish(signature);
+    }
+
+    /*
+     * process
+     *
+     * DESCRIPTION:
+     *
+     * This function is used to progressively calculate a MD5 signature some
+     * number of bytes at a time.
+     *
+     * RETURNS:
+     *
+     * None.
+     *
+     * ARGUMENTS:
+     *
+     * buffer - A buffer of bytes whose MD5 signature we are calculating.
+     *
+     * input_length - The length of the buffer.
+     */
+    void md5_t::process(const void* input, const unsigned int input_length) {
+        if (!finished) {
+            unsigned int processed = 0;
+
+            /*
+             * If we have any data stored from a previous call to process then we use these
+             * bytes first, and the new data is large enough to create a complete block then
+             * we process these bytes first.
+             */
+            if (stored_size and input_length + stored_size >= md5::BLOCK_SIZE) {
+                unsigned char block[md5::BLOCK_SIZE];
+                memcpy(block, stored, stored_size);
+                memcpy(block + stored_size, input, md5::BLOCK_SIZE - stored_size);
+                processed = md5::BLOCK_SIZE - stored_size;
+                stored_size = 0;
+                process_block(block);
+            }
+
+            /*
+             * While there is enough data to create a complete block, process it.
+             */
+            while (processed + md5::BLOCK_SIZE <= input_length) {
+                process_block((unsigned char*)input + processed);
+                processed += md5::BLOCK_SIZE;
+            }
+
+            /*
+             * If there are any unprocessed bytes left over that do not create a complete block
+             * then we store these bytes for processing next time.
+             */
+            if (processed != input_length) {
+                memcpy(stored + stored_size, (char*)input + processed, input_length - processed);
+                stored_size += input_length - processed;
+            } else {
+                stored_size = 0;
+            }
+        } else {
+            // throw error when trying to process after completion?
+        }
+    }
+
+    /*
+     * finish
+     *
+     * DESCRIPTION:
+     *
+     * Finish a progressing MD5 calculation and copy the resulting MD5
+     * signature into the result buffer which should be 16 bytes
+     * (MD5_SIZE).  After this call, the MD5 structure cannot process
+	 * additional bytes.
+     *
+     * RETURNS:
+     *
+     * None.
+     *
+     * ARGUMENTS:
+     *
+     * signature - A 16 byte buffer that will contain the MD5 signature.
+     */
+    void md5_t::finish(void* signature_) {
+        if (!finished) {
+            if (message_length[0] + stored_size < message_length[0])
+                message_length[1]++;
+            message_length[0] += stored_size;
+
+            int pad = md5::BLOCK_SIZE - (sizeof(unsigned int) * 2) - stored_size;
+            if (pad <= 0)
+                pad += md5::BLOCK_SIZE;
+
+            /*
+             * Modified from a fixed array to this assignment and memset to be
+             * more flexible with block-sizes -- Gray 10/97.
+             */
+            if (pad > 0) {
+                stored[stored_size] = 0x80;
+                if (pad > 1)
+                    memset(stored + stored_size + 1, 0, pad - 1);
+                stored_size += pad;
+            }
+
+            /*
+             * Put the 64-bit file length in _bits_ (i.e. *8) at the end of the
+             * buffer. appears to be in beg-endian format in the buffer?
+             */
+            unsigned int size_low = ((message_length[0] & 0x1FFFFFFF) << 3);
+            memcpy(stored + stored_size, &size_low, sizeof(unsigned int));
+            stored_size += sizeof(unsigned int);
+
+            /* shift the high word over by 3 and add in the top 3 bits from the low */
+            unsigned int size_high = (message_length[1] << 3) | ((message_length[0] & 0xE0000000) >> 29);
+            memcpy(stored + stored_size, &size_high, sizeof(unsigned int));
+            stored_size += sizeof(unsigned int);
+
+            /*
+             * process the last block of data.
+             * if the length of the message was already exactly sized, then we have
+             * 2 messages to process
+             */
+            process_block(stored);
+            if (stored_size > md5::BLOCK_SIZE)
+                process_block(stored + md5::BLOCK_SIZE);
+
+            /* Arrange the results into a signature */
+            get_result(static_cast<void*>(signature));
+
+            /* store the signature into a readable sring */
+            sig_to_string(signature, str, MD5_STRING_SIZE);
+
+            if (signature_ != NULL) {
+                memcpy(signature_, static_cast<void*>(signature), MD5_SIZE);
+            }
+
+            finished = true;
+        } else {
+            // add error?
+        }
+    }
+
+    /*
+     * get_sig
+     *
+     * DESCRIPTION:
+     *
+     * Retrieves the previously calculated signature from the MD5 object.
+     *
+     * RETURNS:
+     *
+     * None.
+     *
+     * ARGUMENTS:
+     *
+     * signature_ - A 16 byte buffer that will contain the MD5 signature.
+     */
+    void md5_t::get_sig(void* signature_) {
+        if (finished) {
+            memcpy(signature_, signature, MD5_SIZE);
+        } else {
+            //error?
+        }
+    }
+
+    /*
+     * get_string
+     *
+     * DESCRIPTION:
+     *
+     * Retrieves the previously calculated signature from the MD5 object in
+     * printable format.
+     *
+     * RETURNS:
+     *
+     * None.
+     *
+     * ARGUMENTS:
+     *
+     * str_ - a string of characters which should be at least 33 bytes long
+     * (2 characters per MD5 byte and 1 for the \0).
+     */
+    void md5_t::get_string(void* str_) {
+        if (finished) {
+            memcpy(str_, str, MD5_STRING_SIZE);
+        } else {
+            // error?
+        }
+    }
+
+    /****************************** Private Functions ******************************/
+
+    /*
+     * initialise
+     *
+     * DESCRIPTION:
+     *
+     * Initialize structure containing state of MD5 computation. (RFC 1321,
+     * 3.3: Step 3).
+     *
+     * RETURNS:
+     *
+     * None.
+     *
+     * ARGUMENTS:
+     *
+     * None.
+     */
+    void md5_t::initialise() {
+        /*
+         * ensures that unsigned int is 4 bytes on this platform, will need modifying
+         * if we are to use on a different sized platform.
+         */
+        assert(MD5_SIZE == 16);
+
+        A = 0x67452301;
+        B = 0xefcdab89;
+        C = 0x98badcfe;
+        D = 0x10325476;
+
+        message_length[0] = 0;
+        message_length[1] = 0;
+        stored_size = 0;
+
+        finished = false;
+    }
+
+    /*
+     * process_block
+     *
+     * DESCRIPTION:
+     *
+     * Process a block of bytes into a MD5 state structure.
+     *
+     * RETURNS:
+     *
+     * None.
+     *
+     * ARGUMENTS:
+     *
+     * buffer - A buffer of bytes whose MD5 signature we are calculating.
+     *
+     * input_length - The length of the buffer.
+     */
+    void md5_t::process_block(const unsigned char* block) {
+    /* Process each 16-word block. */
+
+        /*
+         * we check for when the lower word rolls over, and increment the
+         * higher word. we do not need to worry if the higher word rolls over
+         * as only the two words we maintain are needed in the function later
+         */
+        if (message_length[0] + md5::BLOCK_SIZE < message_length[0])
+            message_length[1]++;
+        message_length[0] += BLOCK_SIZE;
+
+        // Copy the block into X. */
+        unsigned int X[16];
+        for (unsigned int i = 0; i < 16; i++) {
+            memcpy(X + i, block + 4 * i, 4);
+        }
+
+        /* Save A as AA, B as BB, C as CC, and D as DD. */
+        unsigned int AA = A, BB = B, CC = C, DD = D;
+
+        /* Round 1
+         * Let [abcd k s i] denote the operation
+         * a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s)
+         * Do the following 16 operations
+         * [ABCD  0  7  1]  [DABC  1 12  2]  [CDAB  2 17  3]  [BCDA  3 22  4]
+         * [ABCD  4  7  5]  [DABC  5 12  6]  [CDAB  6 17  7]  [BCDA  7 22  8]
+         * [ABCD  8  7  9]  [DABC  9 12 10]  [CDAB 10 17 11]  [BCDA 11 22 12]
+         * [ABCD 12  7 13]  [DABC 13 12 14]  [CDAB 14 17 15]  [BCDA 15 22 16]
+         */
+        md5::FF(A, B, C, D, X[0 ], 0, 0 );
+        md5::FF(D, A, B, C, X[1 ], 1, 1 );
+        md5::FF(C, D, A, B, X[2 ], 2, 2 );
+        md5::FF(B, C, D, A, X[3 ], 3, 3 );
+        md5::FF(A, B, C, D, X[4 ], 0, 4 );
+        md5::FF(D, A, B, C, X[5 ], 1, 5 );
+        md5::FF(C, D, A, B, X[6 ], 2, 6 );
+        md5::FF(B, C, D, A, X[7 ], 3, 7 );
+        md5::FF(A, B, C, D, X[8 ], 0, 8 );
+        md5::FF(D, A, B, C, X[9 ], 1, 9 );
+        md5::FF(C, D, A, B, X[10], 2, 10);
+        md5::FF(B, C, D, A, X[11], 3, 11);
+        md5::FF(A, B, C, D, X[12], 0, 12);
+        md5::FF(D, A, B, C, X[13], 1, 13);
+        md5::FF(C, D, A, B, X[14], 2, 14);
+        md5::FF(B, C, D, A, X[15], 3, 15);
+
+        /* Round 2
+         * Let [abcd k s i] denote the operation
+         * a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s)
+         * Do the following 16 operations
+         * [ABCD  1  5 17]  [DABC  6  9 18]  [CDAB 11 14 19]  [BCDA  0 20 20]
+         * [ABCD  5  5 21]  [DABC 10  9 22]  [CDAB 15 14 23]  [BCDA  4 20 24]
+         * [ABCD  9  5 25]  [DABC 14  9 26]  [CDAB  3 14 27]  [BCDA  8 20 28]
+         * [ABCD 13  5 29]  [DABC  2  9 30]  [CDAB  7 14 31]  [BCDA 12 20 32]
+         */
+        md5::GG(A, B, C, D, X[1 ], 0, 16);
+        md5::GG(D, A, B, C, X[6 ], 1, 17);
+        md5::GG(C, D, A, B, X[11], 2, 18);
+        md5::GG(B, C, D, A, X[0 ], 3, 19);
+        md5::GG(A, B, C, D, X[5 ], 0, 20);
+        md5::GG(D, A, B, C, X[10], 1, 21);
+        md5::GG(C, D, A, B, X[15], 2, 22);
+        md5::GG(B, C, D, A, X[4 ], 3, 23);
+        md5::GG(A, B, C, D, X[9 ], 0, 24);
+        md5::GG(D, A, B, C, X[14], 1, 25);
+        md5::GG(C, D, A, B, X[3 ], 2, 26);
+        md5::GG(B, C, D, A, X[8 ], 3, 27);
+        md5::GG(A, B, C, D, X[13], 0, 28);
+        md5::GG(D, A, B, C, X[2 ], 1, 29);
+        md5::GG(C, D, A, B, X[7 ], 2, 30);
+        md5::GG(B, C, D, A, X[12], 3, 31);
+
+        /* Round 3
+         * Let [abcd k s i] denote the operation
+         * a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s)
+         * Do the following 16 operations
+         * [ABCD  5  4 33]  [DABC  8 11 34]  [CDAB 11 16 35]  [BCDA 14 23 36]
+         * [ABCD  1  4 37]  [DABC  4 11 38]  [CDAB  7 16 39]  [BCDA 10 23 40]
+         * [ABCD 13  4 41]  [DABC  0 11 42]  [CDAB  3 16 43]  [BCDA  6 23 44]
+         * [ABCD  9  4 45]  [DABC 12 11 46]  [CDAB 15 16 47]  [BCDA  2 23 48]
+         */
+        md5::HH(A, B, C, D, X[5 ], 0, 32);
+        md5::HH(D, A, B, C, X[8 ], 1, 33);
+        md5::HH(C, D, A, B, X[11], 2, 34);
+        md5::HH(B, C, D, A, X[14], 3, 35);
+        md5::HH(A, B, C, D, X[1 ], 0, 36);
+        md5::HH(D, A, B, C, X[4 ], 1, 37);
+        md5::HH(C, D, A, B, X[7 ], 2, 38);
+        md5::HH(B, C, D, A, X[10], 3, 39);
+        md5::HH(A, B, C, D, X[13], 0, 40);
+        md5::HH(D, A, B, C, X[0 ], 1, 41);
+        md5::HH(C, D, A, B, X[3 ], 2, 42);
+        md5::HH(B, C, D, A, X[6 ], 3, 43);
+        md5::HH(A, B, C, D, X[9 ], 0, 44);
+        md5::HH(D, A, B, C, X[12], 1, 45);
+        md5::HH(C, D, A, B, X[15], 2, 46);
+        md5::HH(B, C, D, A, X[2 ], 3, 47);
+
+        /* Round 4
+         * Let [abcd k s i] denote the operation
+         * a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s)
+         * Do the following 16 operations
+         * [ABCD  0  6 49]  [DABC  7 10 50]  [CDAB 14 15 51]  [BCDA  5 21 52]
+         * [ABCD 12  6 53]  [DABC  3 10 54]  [CDAB 10 15 55]  [BCDA  1 21 56]
+         * [ABCD  8  6 57]  [DABC 15 10 58]  [CDAB  6 15 59]  [BCDA 13 21 60]
+         * [ABCD  4  6 61]  [DABC 11 10 62]  [CDAB  2 15 63]  [BCDA  9 21 64]
+         */
+        md5::II(A, B, C, D, X[0 ], 0, 48);
+        md5::II(D, A, B, C, X[7 ], 1, 49);
+        md5::II(C, D, A, B, X[14], 2, 50);
+        md5::II(B, C, D, A, X[5 ], 3, 51);
+        md5::II(A, B, C, D, X[12], 0, 52);
+        md5::II(D, A, B, C, X[3 ], 1, 53);
+        md5::II(C, D, A, B, X[10], 2, 54);
+        md5::II(B, C, D, A, X[1 ], 3, 55);
+        md5::II(A, B, C, D, X[8 ], 0, 56);
+        md5::II(D, A, B, C, X[15], 1, 57);
+        md5::II(C, D, A, B, X[6 ], 2, 58);
+        md5::II(B, C, D, A, X[13], 3, 59);
+        md5::II(A, B, C, D, X[4 ], 0, 60);
+        md5::II(D, A, B, C, X[11], 1, 61);
+        md5::II(C, D, A, B, X[2 ], 2, 62);
+        md5::II(B, C, D, A, X[9 ], 3, 63);
+
+        /* Then perform the following additions. (That is increment each
+        of the four registers by the value it had before this block
+        was started.) */
+        A += AA;
+        B += BB;
+        C += CC;
+        D += DD;
+    }
+
+    /*
+     * get_result
+     *
+     * DESCRIPTION:
+     *
+     * Copy the resulting MD5 signature into the first 16 bytes (MD5_SIZE)
+     * of the result buffer.
+     *
+     * RETURNS:
+     *
+     * None.
+     *
+     * ARGUMENTS:
+     *
+     * result - A 16 byte buffer that will contain the MD5 signature.
+     */
+    void md5_t::get_result(void *result) {
+        memcpy((char*)result, &A, sizeof(unsigned int));
+        memcpy((char*)result + sizeof(unsigned int), &B, sizeof(unsigned int));
+        memcpy((char*)result + 2 * sizeof(unsigned int), &C, sizeof(unsigned int));
+        memcpy((char*)result + 3 * sizeof(unsigned int), &D, sizeof(unsigned int));
+    }
+
+    /****************************** Exported Functions ******************************/
+
+    /*
+     * sig_to_string
+     *
+     * DESCRIPTION:
+     *
+     * Convert a MD5 signature in a 16 byte buffer into a hexadecimal string
+     * representation.
+     *
+     * RETURNS:
+     *
+     * None.
+     *
+     * ARGUMENTS:
+     *
+     * signature_ - a 16 byte buffer that contains the MD5 signature.
+     *
+     * str_ - a string of charactes which should be at least 33 bytes long (2
+     * characters per MD5 byte and 1 for the \0).
+     *
+     * str_len - the length of the string.
+     */
+    void sig_to_string(const void* signature_, char* str_, const int str_len) {
+        unsigned char* sig_p;
+        char* str_p;
+        char* max_p;
+        unsigned int high, low;
+
+        str_p = str_;
+        max_p = str_ + str_len;
+
+        for (sig_p = (unsigned char*)signature_; sig_p < (unsigned char*)signature_ + MD5_SIZE; sig_p++) {
+            high = *sig_p / 16;
+            low = *sig_p % 16;
+            /* account for 2 chars */
+            if (str_p + 1 >= max_p) {
+                break;
+            }
+            *str_p++ = md5::HEX_STRING[high];
+            *str_p++ = md5::HEX_STRING[low];
+        }
+        /* account for 2 chars */
+        if (str_p < max_p) {
+            *str_p++ = '\0';
+        }
+    }
+
+    /*
+     * sig_from_string
+     *
+     * DESCRIPTION:
+     *
+     * Convert a MD5 signature from a hexadecimal string representation into
+     * a 16 byte buffer.
+     *
+     * RETURNS:
+     *
+     * None.
+     *
+     * ARGUMENTS:
+     *
+     * signature_ - A 16 byte buffer that will contain the MD5 signature.
+     *
+     * str_ - A string of charactes which _must_ be at least 32 bytes long (2
+     * characters per MD5 byte).
+     */
+    void sig_from_string(void* signature_, const char* str_) {
+        unsigned char *sig_p;
+        const char *str_p;
+        char* hex;
+        unsigned int high, low, val;
+
+        hex = (char*)md5::HEX_STRING;
+        sig_p = static_cast<unsigned char*>(signature_);
+
+        for (str_p = str_; str_p < str_ + MD5_SIZE * 2; str_p += 2) {
+            high = strchr(hex, *str_p) - hex;
+            low = strchr(hex, *(str_p + 1)) - hex;
+            val = high * 16 + low;
+            *sig_p++ = val;
+        }
+    }
+} // namespace md5

+ 207 - 0
src/md5.h

@@ -0,0 +1,207 @@
+#ifndef __MD5_H__
+#define __MD5_H__
+
+/*
+ * Size of a standard MD5 signature in bytes.  This definition is for
+ * external programs only.  The MD5 routines themselves reference the
+ * signature as 4 unsigned 32-bit integers.
+ */
+const unsigned int MD5_SIZE = (4 * sizeof(unsigned int));   /* 16 */
+const unsigned int MD5_STRING_SIZE = 2 * MD5_SIZE + 1;      /* 33 */
+
+ namespace md5 {
+    /*
+     * The MD5 algorithm works on blocks of characters of 64 bytes.  This
+     * is an internal value only and is not necessary for external use.
+     */
+    const unsigned int BLOCK_SIZE = 64;
+
+    class md5_t {
+        public:
+            /*
+             * md5_t
+             *
+             * DESCRIPTION:
+             *
+             * Initialize structure containing state of MD5 computation. (RFC 1321,
+             * 3.3: Step 3).  This is for progressive MD5 calculations only.  If
+             * you have the complete string available, call it as below.
+             * process should be called for each bunch of bytes and after the last
+             * process call, finish should be called to get the signature.
+             *
+             * RETURNS:
+             *
+             * None.
+             *
+             * ARGUMENTS:
+             *
+             * None.
+             */
+            md5_t();
+
+            /*
+             * md5_t
+             *
+             * DESCRIPTION:
+             *
+             * This function is used to calculate a MD5 signature for a buffer of
+             * bytes.  If you only have part of a buffer that you want to process
+             * then md5_t, process, and finish should be used.
+             *
+             * RETURNS:
+             *
+             * None.
+             *
+             * ARGUMENTS:
+             *
+             * input - A buffer of bytes whose MD5 signature we are calculating.
+             *
+             * input_length - The length of the buffer.
+             *
+             * signature_ - A 16 byte buffer that will contain the MD5 signature.
+             */
+            md5_t(const void* input, const unsigned int input_length, void* signature_ = NULL);
+
+            /*
+             * process
+             *
+             * DESCRIPTION:
+             *
+             * This function is used to progressively calculate an MD5 signature some
+             * number of bytes at a time.
+             *
+             * RETURNS:
+             *
+             * None.
+             *
+             * ARGUMENTS:
+             *
+             * input - A buffer of bytes whose MD5 signature we are calculating.
+             *
+             * input_length - The length of the buffer.
+             */
+            void process(const void* input, const unsigned int input_length);
+
+            /*
+             * finish
+             *
+             * DESCRIPTION:
+             *
+             * Finish a progressing MD5 calculation and copy the resulting MD5
+             * signature into the result buffer which should be 16 bytes
+             * (MD5_SIZE).  After this call, the MD5 structure cannot be used
+             * to calculate a new md5, it can only return its signature.
+             *
+             * RETURNS:
+             *
+             * None.
+             *
+             * ARGUMENTS:
+             *
+             * signature_ - A 16 byte buffer that will contain the MD5 signature.
+             */
+            void finish(void* signature_ = NULL);
+
+            /*
+             * get_sig
+             *
+             * DESCRIPTION:
+             *
+             * Retrieves the previously calculated signature from the MD5 object.
+             *
+             * RETURNS:
+             *
+             * None.
+             *
+             * ARGUMENTS:
+             *
+             * signature_ - A 16 byte buffer that will contain the MD5 signature.
+             */
+            void get_sig(void* signature_);
+
+            /*
+             * get_string
+             *
+             * DESCRIPTION:
+             *
+             * Retrieves the previously calculated signature from the MD5 object in
+             * printable format.
+             *
+             * RETURNS:
+             *
+             * None.
+             *
+             * ARGUMENTS:
+             *
+             * str_ - a string of characters which should be at least 33 bytes long
+             * (2 characters per MD5 byte and 1 for the \0).
+             */
+            void get_string(void* str_);
+
+        private:
+            /* internal functions */
+            void initialise();
+            void process_block(const unsigned char*);
+            void get_result(void*);
+
+            unsigned int A;                             /* accumulator 1 */
+            unsigned int B;                             /* accumulator 2 */
+            unsigned int C;                             /* accumulator 3 */
+            unsigned int D;                             /* accumulator 4 */
+
+            unsigned int message_length[2];             /* length of data */
+            unsigned int stored_size;                   /* length of stored bytes */
+            unsigned char stored[md5::BLOCK_SIZE * 2];  /* stored bytes */
+
+            bool finished;                              /* object state */
+
+            char signature[MD5_SIZE];                   /* stored signature */
+            char str[MD5_STRING_SIZE];                  /* stored plain text hash */
+    };
+
+    /*
+     * sig_to_string
+     *
+     * DESCRIPTION:
+     *
+     * Convert a MD5 signature in a 16 byte buffer into a hexadecimal string
+     * representation.
+     *
+     * RETURNS:
+     *
+     * None.
+     *
+     * ARGUMENTS:
+     *
+     * signature - a 16 byte buffer that contains the MD5 signature.
+     *
+     * str - a string of characters which should be at least 33 bytes long (2
+     * characters per MD5 byte and 1 for the \0).
+     *
+     * str_len - the length of the string.
+     */
+    extern void sig_to_string(const void* signature, char* str, const int str_len);
+
+    /*
+     * sig_from_string
+     *
+     * DESCRIPTION:
+     *
+     * Convert a MD5 signature from a hexadecimal string representation into
+     * a 16 byte buffer.
+     *
+     * RETURNS:
+     *
+     * None.
+     *
+     * ARGUMENTS:
+     *
+     * signature - A 16 byte buffer that will contain the MD5 signature.
+     *
+     * str - A string of charactes which _must_ be at least 32 bytes long (2
+     * characters per MD5 byte).
+     */
+    extern void sig_from_string(void* signature, const char* str);
+} // namespace md5
+
+#endif /* ! __MD5_H__ */

+ 13 - 0
src/misc.cpp

@@ -21,11 +21,14 @@ typedef jpcre2::select<char> jp;
 
 #include <rapidjson/document.h>
 
+/*
 #ifdef USE_MBEDTLS
 #include <mbedtls/md5.h>
 #else
 #include <openssl/md5.h>
 #endif // USE_MBEDTLS
+*/
+#include "md5.h"
 
 #include "misc.h"
 
@@ -768,6 +771,8 @@ std::string urlsafe_base64_encode(const std::string &string_to_encode)
 std::string getMD5(const std::string &data)
 {
     std::string result;
+
+    /*
     unsigned int i = 0;
     unsigned char digest[16] = {};
 
@@ -793,6 +798,14 @@ std::string getMD5(const std::string &data)
         snprintf(tmp, 3, "%02x", digest[i]);
         result += tmp;
     }
+    */
+
+    char result_str[MD5_STRING_SIZE];
+    md5::md5_t md5;
+    md5.process(data.data(), data.size());
+    md5.finish();
+    md5.get_string(result_str);
+    result.assign(result_str);
 
     return result;
 }