Porting MD5 Code

Last week my wife and I returned from a one week trip to Portugal. We had not been there in more than a decade. Some things have changed while other not. People continue to be very nice and helpful especially when you attempt to utter a few words in Portuguese.

We arrived in Lisbon and headed to the rental car office. In less than an hour from arrival we were heading south to the Algarve. We have watched a few YouTube videos by Rick Steves and had purchases one of his travel guides for Portugal. In more than one occasion Rick has mentioned that Salema is his favorite beach in the Algarve. By experience we now know why. It is a small town sitting on a relatively small bay with blue and green waters. The population is less than 300 people. My wife took a picture at a restaurant on the beach while the temperature was hitting 96 F and we were enjoying delicious fresh sea food and drinking Sagres beer. From our table we could hear people conversion and different languages. Our waiter was taking care of a few tables and was able to switch to the language spoken by the customers (English, French and German). We only spent two days and headed back to Lisbon.

We also spent some time sightseeing, eating and drinking in Lagos. The town is much larger than Salema and is full of tourist and boats.

It is incredible what the European Union has done for the highways in Portugal. A couple decades ago I would not have driven to the Algarve for such a short period of time. Today it is possible to make a one day trip from Lisbon to the Algarve.

I will cover our stay in Lisbon in the next post.

As I have mentioned, I am porting some C/C++ code from 32 to 54 bits. The code is just a reduced set of APIs for the storage server at work. The following C code illustrates the current calls:

SENCOR_EXPORT	int __stdcall	MD5Compare			(
													char			*fileName,
													char			*otherFileName,
													unsigned char	digest[MD5_DIGEST_LEN],
													BOOL			*identical
													);

SENCOR_EXPORT	int __stdcall	MD5DigestToString	(
													unsigned char	digest[MD5_DIGEST_LEN],
													char			md5[MD5_DIGEST_STRING_LEN]
													);

SENCOR_EXPORT	int __stdcall	MD5Init				(
													MD5_CTX			*context
													);

SENCOR_EXPORT	int __stdcall	MD5Final			(
													unsigned char	digest[MD5_DIGEST_LEN],
													MD5_CTX			*context
													);

SENCOR_EXPORT	int __stdcall	MD5Print			(
													unsigned char	digest[MD5_DIGEST_LEN]
													);

SENCOR_EXPORT	int __stdcall	MD5Update			(
													MD5_CTX			*context,
													unsigned char	*input,
													unsigned int	inputLen
													);

The following code (still work in progress) illustrates the replacement code in C++ using the Boost library:

#include "pch.h"

#include <iostream>

#include <algorithm>
#include <iterator>
#include <boost/uuid/detail/md5.hpp>
#include <boost/algorithm/hex.hpp>

using boost::uuids::detail::md5;
using namespace std;


/*
*
*/
int MD5Init	(
			md5		*hash
			)
{

	hash = new md5();

	// **** inform the caller what went on ****
	return 0;
}


/*
*
*/
int MD5Final	(
				md5		*hash
				)
{

	// **** inform the caller what went on ****
	return 0;
}


/*
*
*/
int MD5Update	(
				md5		*hash,
				string	str
				)
{
	hash->process_bytes(str.data(), str.size());

	// **** inform the caller what went on ****
	return 0;
}


/*
*
*/
int	MD5Final	(
				md5					*hash,
				md5::digest_type	*digest
				)
{
	hash->get_digest(*digest);

	// **** inform the caller what went on ****
	return 0;
}


/*
* Convert MD5 digest to string.
*/
int MD5DigestToString	(
						const md5::digest_type	&digest,
						string					&digestStr
						)
{

	// **** ****
	digestStr = "";

	// **** convert to char[] ****
	const auto charDigest = reinterpret_cast<const char *>(&digest);

	// **** convert char[] digest to string ****
	boost::algorithm::hex(charDigest, charDigest + sizeof(md5::digest_type), std::back_inserter(digestStr));

	// ???? ????
	cout << "MD5DigestToString <<< digestString ==>" << digestStr << "<==" << endl;

	// **** inform the caller what went on ****
	return 0;
}


/*
* Basic test to verify MD5 operation.
*/
void basicTest() {

	// **** general purpose string ****
	string	str;
	string	digestStr = "";

	// **** prompt for first string ****
	cout << "basicTest >>> str: ";

	// **** loop processing input ****
	while (getline(cin, str)) {

		// **** check if we are done ****
		if (str.compare(string("-1")) == 0) {
			break;
		}

		// **** display string ****
		cout << "basicTest <<< str ==>" << str << "<==\n";

		// **** generate a MD5 digest ****
		md5					hash;
		md5::digest_type	digest;

		hash.process_bytes(str.data(), str.size());
		hash.get_digest(digest);

		// **** convert to string and display MD5 digest ****
		MD5DigestToString(	digest,
							digestStr);
		cout << "basicTest <<< digestStr ==>" << digestStr << "<==\n";

		// **** prompt for next string to process ****
		cout << "basicTest >>> str [-1 to exit]: ";
	}
}


/*
* Test scaffolding.
*/
int main()
{

	bool				done;									// done looping flag

	char				buffer[BUFSIZ];							// general purpose buffer

	md5::digest_type	digest;									// MD5 digest

	int					retVal,									// returned by this function
						selection,								// user selection
						status;									// returned by function calls

	md5					hash;									// MD5 hash

	string				digestStr,								// digest string
						str;									// string

	// **** initialization ****
	retVal		= 0;											// hope all goes well

	digestStr	= "";											// for starters
	done		= false;										// for starters
	selection	= 1;											// for starters

	memset((void *)buffer, (int)0x00, sizeof(buffer));

	// **** welcome message ****
	cout << "**** MD5 using Boost C++ Libraries ****\n"; // **** loop testing functions **** do { // **** display menu **** printf("\n"); printf("1\tbasicTest()\n"); printf("\n"); printf("2\tMD5Init()\n"); printf("3\tMD5Update()\n"); printf("4\tMD5Final()\n"); printf("5\tMD5DigestToString()\n"); printf("\n"); printf("-1\tQUIT\n"); // **** prompt and get user selection **** printf("\n>>> selection [%d]: ", selection);
		fgets(	buffer,
				BUFSIZ,
				stdin);
		buffer[strlen(buffer) - 1] = '\0';
		if (buffer[0] != '\0')
			selection = atoi(buffer);

		// **** process user selection ****
		switch (selection) {
		case -1:
			done = true;
			break;

		case 1:
			basicTest();
			break;

		case 2:
			status = MD5Init(&hash);
			break;

		case 3:
			str = "hello world";
			status = MD5Update(	&hash,
								str);
			break;

		case 4:
			status = MD5Final(	&hash,
								&digest);
			break;

		case 5:
			status = MD5DigestToString(	digest,
										digestStr);

			// ???? ????
			cout << "main <<< digestStr =>" << digestStr << "<==\n";
			break;

		default:
			printf("main <<< invalid selection: %d\n", selection);
			break;
		}
	} while (!done);

	// **** clean up ****
done:

	// **** inform caller what went on ****
	return retVal;
}

Following is a run of the test code:

C:\Users\John\Documents\Visual Studio 2017\Projects\testmd5\x64\Debug>testmd5
**** MD5 using Boost C++ Libraries ****

1       basicTest()

2       MD5Init()
3       MD5Update()
4       MD5Final()
5       MD5DigestToString()

-1      QUIT

>>> selection [1]: 1
basicTest >>> str: hello world
basicTest <<< str ==>hello world<==
MD5DigestToString <<< digestString ==>5EB63BBBE01EEED093CB22BB8F5ACDC3<==
basicTest <<< digestStr ==>5EB63BBBE01EEED093CB22BB8F5ACDC3<== basicTest >>> str [-1 to exit]: -1

1       basicTest()

2       MD5Init()
3       MD5Update()
4       MD5Final()
5       MD5DigestToString()

-1      QUIT

>>> selection [1]: 2

1       basicTest()

2       MD5Init()
3       MD5Update()
4       MD5Final()
5       MD5DigestToString()

-1      QUIT

>>> selection [2]: 3

1       basicTest()

2       MD5Init()
3       MD5Update()
4       MD5Final()
5       MD5DigestToString()

-1      QUIT

>>> selection [3]: 4

1       basicTest()

2       MD5Init()
3       MD5Update()
4       MD5Final()
5       MD5DigestToString()

-1      QUIT

>>> selection [4]: 5
MD5DigestToString <<< digestString ==>5EB63BBBE01EEED093CB22BB8F5ACDC3<==
main <<< digestStr =>5EB63BBBE01EEED093CB22BB8F5ACDC3<==

1       basicTest()

2       MD5Init()
3       MD5Update()
4       MD5Final()
5       MD5DigestToString()

-1      QUIT

The same string is used for both sets. I will make some changes to the code to be able to prompt and accept different string.

The next step is to run some tests and will integrate into the code being ported.

If you are interested, the MD5 code can be found in my GitHub repository.

If you have comments or questions regarding this or any other post in this blog, or if you would like me to help with any phase in the SDLC (Software Development Life Cycle) of a product or service, please do not hesitate and leave me a note below. Requests for help will remain private.

Keep on reading and experimenting. It is the best way to learn!

John

Follow me on Twitter:  @john_canessa

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.