Finished writing this a little while ago but unfortunately the generated MD5 doesn't match other application's hashes.

I have basically used Wikipedia for reference. I have a feeling my error is introduced in the padding stage but I can't be certain, hoping a fresh set of eyes could point out the issue for me so I can get on and fix it!

int k[64];

int r[] = {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};
	 
int left_rotate(int x, int c)
{
	return (x << c) | (x >> (32 - c));
}

void c_md5::md5(const char *input, int length)
{
	int h0 = 0x67452301;
	int h1 = 0xEFCDAB89;
	int h2 = 0x98BADCFE;
	int h3 = 0x10325476;
	char *buffer;
	int bufLen;
	
	// set k
	for(int loop = 0; loop < 64; loop++)
	{
		floor(fabs(sin(loop + 1)) * (pow(2, 32)));
	}
	
	// get the original input length
	bufLen = length;
	
	if((bufLen % 64) > 0)
	{
		if(64 - bufLen < 8)
		{
			bufLen += 64;
		}		
		int tempVal;
		tempVal = bufLen % 64;
		bufLen += 64 - tempVal;
	}
	printf("Checking if buffer length is divisible by 64... ");
	if(bufLen % 64 == 0)
	{
		printf("done!\n");
	}
	else
	{
		printf("failed!\n");
		return;
	}
	
	// create our new buffer
	buffer = new char [bufLen];
	printf("Checking if buffer is created... ");
	if(buffer)
	{
		printf("done!\n");
	}
	else
	{
		printf("failed\n");
		return;
	}
	
	// copy content over
	for(int loop = 0; loop < length; loop++)
	{
		buffer[loop] = input[loop];
	}
	
	// blank remaining bits
	for(int loop = length; loop < bufLen; loop++)
	{
		buffer[loop] = 0x0;
	}
	
	// fill in the length of the original stream into the padding
	{
		int tempLength = length * 8;
		int tempVal;
		tempVal = tempLength;
		
		// use some bitwise shifting to access the length correctly
		buffer[bufLen - 1] = (char)tempVal;
		tempVal = tempLength >> 8;
		buffer[bufLen - 2] = (char)tempVal;
		tempVal = tempLength >> 16;
		buffer[bufLen - 3] = (char)tempVal;
		tempVal = tempLength >> 24;
		buffer[bufLen - 4] = (char)tempVal;		
	}
	printf("Checking reported length = stream length... ");
	if((unsigned char)buffer[bufLen - 4] * 256 * 256 * 256 + (unsigned char)buffer[bufLen - 3] * 256 * 256 + (unsigned char)buffer[bufLen - 2] * 256 + (unsigned char)buffer[bufLen - 1] == length * 8)
	{
		printf("done!\n");
	}
	else
	{
		printf("failed!\n");
		printf("length (in bits) : %i\n", length * 8);
		printf("padding(in bits) : %i\n", (unsigned char)buffer[bufLen - 4] * 256 * 256 * 256 + (unsigned char)buffer[bufLen - 3] * 256 * 256 + (unsigned char)buffer[bufLen - 2] * 256 + (unsigned char)buffer[bufLen - 1]);
		return;
	}	
	
	// set the first bit of the padding
	buffer[length] = buffer[length] | 0x80;
	
	// below based on psuedo code from Wikipedia
	for(int MD5_loop = 0; MD5_loop < bufLen / 64; MD5_loop++)
	{
		int a, b, c, d;
		a = h0;
		b = h1;
		c = h2;
		d = h3;
		
		int word[16];		
		for(int loop = 0; loop < 16; loop++)
		{
			word[loop] = buffer[MD5_loop * 64 + loop * 16];
		}
		
		int f, g, tempVal;
		for(int loop = 0; loop < 64; loop++)
		{
			if(loop < 16)
			{
				f = ((b & c) | (!b) & d);
				g = loop;
			}
			else if(loop < 32)
			{
				f = ((d & b) | (!d) & c);
				g = (5 * loop + 1) % 16;
			}
			else if(loop < 48)
			{
				f = (b ^ c ^ d);
				g = (3 * loop + 5) % 16;
			}
			else if(loop < 64)
			{
				f = (c ^ (b | (!d)));
				g = (7 * loop) % 16;
			}
			
			tempVal = d;
			d = c;
			c = b;
			b = b + left_rotate(a + f + k[loop] + word[g], r[loop]);
			a = tempVal;
		}
		
		h0 += a;
		h1 += b;
		h2 += c;
		h3 += d;
	}
	
	printf("%04X%04X%04X%04X\n", h0, h1, h2, h3);
}

Cheers!

Recommended Answers

All 4 Replies

Did your compiler return any errors or warnings?

Nope, no errors or warnings through Mingw.

Doing a checksum on "" returns 67452301EFCDAB8998BADCFE10325476 as opposed to d41d8cd98f00b204e9800998ecf8427e on Wikipedia.

Got 20 minutes or so free at work today so I took another look over my code, a fresh pair of eyes really did help!

Fixed a number of issues; added padding with input of 0 bytes and fixed the word loop to take more than just the first byte of data being two of the main ones.

Below is the new code (I can't seem to find an edit button, maybe I'm just overlooking it?) I am getting some warnings as well as the hash returning incorrect still. I have ruled out padding issues (by dumping the padding, it's exactly as I'd expect), also ruled out the generation of k by taking constants found elsewhere (which did in fact match up with my values anyway I believe). I think the discrepancy is arising because of k still (check the warnings), hopefully someone can point me in the right direction.

// generated by using floor(fabs(sin(loop + 1))) * 2^32 where 0 <= loop < 16
unsigned int k[] =
{
	3614090360, 3905402710,  606105819, 3250441966, 4118548399, 1200080426, 2821735955, 4249261313,
	1770035416, 2336552879, 4294925233, 2304563134, 1804603682, 4254626195, 2792965006, 1236535329,
	4129170786, 3225465664,  643717713, 3921069994, 3593408605,   38016083, 3634488961, 3889429448,
	 568446438, 3275163606, 4107603335, 1163531501, 2850285829, 4243563512, 1735328473, 2368359562,
	4294588738, 2272392833, 1839030562, 4259657740, 2763975236, 1272893353, 4139469664, 3200236656,
	 681279174, 3936430074, 3572445317,   76029189, 3654602809, 3873151461,  530742520, 3299628645,
	4096336452, 1126891415, 2878612391, 4237533241, 1700485571, 2399980690, 4293915773, 2240044497,
	1873313359, 4264355552, 2734768916, 1309151649, 4149444226, 3174756917,  718787259, 3951481745
};


unsigned int r[] =
{
	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
};
	 
inline unsigned int left_rotate(unsigned int x, unsigned int c)
{
	return (x << c) | (x >> (32 - c));
}

void c_md5::md5(const char *input, int length)
{
	unsigned int h0 = 0x67452301;
	unsigned int h1 = 0xEFCDAB89;
	unsigned int h2 = 0x98BADCFE;
	unsigned int h3 = 0x10325476;
	char *buffer;
	int bufLen;
	
	// get the original input length
	bufLen = length;
	
	if(((bufLen % 64) > 0) || (bufLen == 0))
	{
		if(64 - bufLen < 8)
		{
			bufLen += 64;
		}		
		int tempVal;
		tempVal = bufLen % 64;
		bufLen += 64 - tempVal;
	}
	if(debug)
	{
		printf("Checking if buffer length is divisible by 512... ");
		if(bufLen % 64 == 0)
		{
			printf("done!\n");
		}
		else
		{
			printf("failed!\n");
			return;
		}
	}
	
	// create our new buffer
	buffer = new char [bufLen];
	if(debug)
	{
		printf("Checking if buffer is created... ");
		if(buffer)
		{
			printf("done!\n");
		}
		else
		{
			printf("failed\n");
			return;
		}
	}
	
	// copy content over
	for(int loop = 0; loop < length; loop++)
	{
		buffer[loop] = input[loop];
	}

	// blank the padding
	for(int loop = length; loop < bufLen; loop++)
	{
		buffer[loop] = 0x00;
	}
	// set the first bit of the padding
	buffer[length] = 0x80;
	
	// fill in the length of the original stream into the padding
	{
		int tempLength = length * 8;
		int tempVal;
		tempVal = tempLength;
		
		// use some bitwise shifting to access the length correctly
		buffer[bufLen - 1] = (char)tempVal;
		tempVal = tempLength >> 8;
		buffer[bufLen - 2] = (char)tempVal;
		tempVal = tempLength >> 16;
		buffer[bufLen - 3] = (char)tempVal;
		tempVal = tempLength >> 24;
		buffer[bufLen - 4] = (char)tempVal;		
	}
	if(debug)
	{
		printf("Checking reported length = stream length... ");
		if((unsigned char)buffer[bufLen - 4] * 256 * 256 * 256 + (unsigned char)buffer[bufLen - 3] * 256 * 256 + (unsigned char)buffer[bufLen - 2] * 256 + (unsigned char)buffer[bufLen - 1] == length * 8)
		{
			printf("done!\n");
		}
		else
		{
			printf("failed!\n");
			printf("length (in bits) : %i\n", length * 8);
			printf("padding(in bits) : %i\n", (unsigned char)buffer[bufLen - 4] * 256 * 256 * 256 + (unsigned char)buffer[bufLen - 3] * 256 * 256 + (unsigned char)buffer[bufLen - 2] * 256 + (unsigned char)buffer[bufLen - 1]);
			return;
		}
	}
	
	// below based on psuedo code from Wikipedia
	for(int MD5_loop = 0; MD5_loop < bufLen / 64; MD5_loop++)
	{
		unsigned int a, b, c, d;
		a = h0;
		b = h1;
		c = h2;
		d = h3;
		
		unsigned int word[16];		
		for(int loop = 0; loop < 16; loop++)
		{
			int tempVal;
			tempVal = 0;
			
			tempVal |= buffer[MD5_loop * 64 + loop];
			tempVal <<= 8;
			tempVal |= buffer[MD5_loop * 64 + loop + 1];
			tempVal <<= 8;
			tempVal |= buffer[MD5_loop * 64 + loop + 2];
			tempVal <<= 8;
			tempVal |= buffer[MD5_loop * 64 + loop + 3];
			printf("%08x\n", tempVal);
			
			word[loop] = tempVal;
		}
		
		unsigned int f, g, tempVal;
		for(int loop = 0; loop < 64; loop++)
		{
			if(loop < 16)
			{
				// (b and c) or (not b and d)
				f = ((b & c) | ((!b) & d));
				g = loop;
			}
			else if(loop < 32)
			{
				// (d and b) or (not d and c)
				f = ((d & b) | ((!d) & c));
				g = (5 * loop + 1) % 16;
			}
			else if(loop < 48)
			{
				// b xor c xor d
				f = (b ^ c ^ d);
				g = (3 * loop + 5) % 16;
			}
			else if(loop < 64)
			{
				// c xor (b or not d)
				f = (c ^ (b | (!d)));
				g = (7 * loop) % 16;
			}
			
			tempVal = d;
			d = c;
			c = b;
			b = (unsigned int)b + (unsigned int)left_rotate(a + f + k[loop] + word[g], r[loop]);
			a = tempVal;
		}
		
		h0 += a;
		h1 += b;
		h2 += c;
		h3 += d;
	}
	
	if(debug)
	{
		printf("Stream content:\n");
		for(int loop = 0; loop < bufLen; loop++)
		{
			printf("0x%02X ", (unsigned char)buffer[loop]);
		}
	}
	
	printf("%08x%08x%08x%08x\n", h0, h1, h2, h3);
}

the below error occurs for pretty much every value of k

warning: this decimal constant is unsigned only in ISO C90

however I thought all my values would be in range, isn't the max size of an int 4294967296 on an x86 system?

Got 20 minutes or so free at work today so I took another look over my code, a fresh pair of eyes really did help!

Fixed a number of issues; added padding with input of 0 bytes and fixed the word loop to take more than just the first byte of data being two of the main ones.

Below is the new code (I can't seem to find an edit button, maybe I'm just overlooking it?) I am getting some warnings as well as the hash returning incorrect still. I have ruled out padding issues (by dumping the padding, it's exactly as I'd expect), also ruled out the generation of k by taking constants found elsewhere (which did in fact match up with my values anyway I believe). I think the discrepancy is arising because of k still (check the warnings), hopefully someone can point me in the right direction.

// generated by using floor(fabs(sin(loop + 1))) * 2^32 where 0 <= loop < 16
unsigned int k[] =
{
	3614090360, 3905402710,  606105819, 3250441966, 4118548399, 1200080426, 2821735955, 4249261313,
	1770035416, 2336552879, 4294925233, 2304563134, 1804603682, 4254626195, 2792965006, 1236535329,
	4129170786, 3225465664,  643717713, 3921069994, 3593408605,   38016083, 3634488961, 3889429448,
	 568446438, 3275163606, 4107603335, 1163531501, 2850285829, 4243563512, 1735328473, 2368359562,
	4294588738, 2272392833, 1839030562, 4259657740, 2763975236, 1272893353, 4139469664, 3200236656,
	 681279174, 3936430074, 3572445317,   76029189, 3654602809, 3873151461,  530742520, 3299628645,
	4096336452, 1126891415, 2878612391, 4237533241, 1700485571, 2399980690, 4293915773, 2240044497,
	1873313359, 4264355552, 2734768916, 1309151649, 4149444226, 3174756917,  718787259, 3951481745
};


unsigned int r[] =
{
	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
};
	 
inline unsigned int left_rotate(unsigned int x, unsigned int c)
{
	return (x << c) | (x >> (32 - c));
}

void c_md5::md5(const char *input, int length)
{
	unsigned int h0 = 0x67452301;
	unsigned int h1 = 0xEFCDAB89;
	unsigned int h2 = 0x98BADCFE;
	unsigned int h3 = 0x10325476;
	char *buffer;
	int bufLen;
	
	// get the original input length
	bufLen = length;
	
	if(((bufLen % 64) > 0) || (bufLen == 0))
	{
		if(64 - bufLen < 8)
		{
			bufLen += 64;
		}		
		int tempVal;
		tempVal = bufLen % 64;
		bufLen += 64 - tempVal;
	}
	if(debug)
	{
		printf("Checking if buffer length is divisible by 512... ");
		if(bufLen % 64 == 0)
		{
			printf("done!\n");
		}
		else
		{
			printf("failed!\n");
			return;
		}
	}
	
	// create our new buffer
	buffer = new char [bufLen];
	if(debug)
	{
		printf("Checking if buffer is created... ");
		if(buffer)
		{
			printf("done!\n");
		}
		else
		{
			printf("failed\n");
			return;
		}
	}
	
	// copy content over
	for(int loop = 0; loop < length; loop++)
	{
		buffer[loop] = input[loop];
	}

	// blank the padding
	for(int loop = length; loop < bufLen; loop++)
	{
		buffer[loop] = 0x00;
	}
	// set the first bit of the padding
	buffer[length] = 0x80;
	
	// fill in the length of the original stream into the padding
	{
		int tempLength = length * 8;
		int tempVal;
		tempVal = tempLength;
		
		// use some bitwise shifting to access the length correctly
		buffer[bufLen - 1] = (char)tempVal;
		tempVal = tempLength >> 8;
		buffer[bufLen - 2] = (char)tempVal;
		tempVal = tempLength >> 16;
		buffer[bufLen - 3] = (char)tempVal;
		tempVal = tempLength >> 24;
		buffer[bufLen - 4] = (char)tempVal;		
	}
	if(debug)
	{
		printf("Checking reported length = stream length... ");
		if((unsigned char)buffer[bufLen - 4] * 256 * 256 * 256 + (unsigned char)buffer[bufLen - 3] * 256 * 256 + (unsigned char)buffer[bufLen - 2] * 256 + (unsigned char)buffer[bufLen - 1] == length * 8)
		{
			printf("done!\n");
		}
		else
		{
			printf("failed!\n");
			printf("length (in bits) : %i\n", length * 8);
			printf("padding(in bits) : %i\n", (unsigned char)buffer[bufLen - 4] * 256 * 256 * 256 + (unsigned char)buffer[bufLen - 3] * 256 * 256 + (unsigned char)buffer[bufLen - 2] * 256 + (unsigned char)buffer[bufLen - 1]);
			return;
		}
	}
	
	// below based on psuedo code from Wikipedia
	for(int MD5_loop = 0; MD5_loop < bufLen / 64; MD5_loop++)
	{
		unsigned int a, b, c, d;
		a = h0;
		b = h1;
		c = h2;
		d = h3;
		
		unsigned int word[16];		
		for(int loop = 0; loop < 16; loop++)
		{
			int tempVal;
			tempVal = 0;
			
			tempVal |= buffer[MD5_loop * 64 + loop];
			tempVal <<= 8;
			tempVal |= buffer[MD5_loop * 64 + loop + 1];
			tempVal <<= 8;
			tempVal |= buffer[MD5_loop * 64 + loop + 2];
			tempVal <<= 8;
			tempVal |= buffer[MD5_loop * 64 + loop + 3];
			printf("%08x\n", tempVal);
			
			word[loop] = tempVal;
		}
		
		unsigned int f, g, tempVal;
		for(int loop = 0; loop < 64; loop++)
		{
			if(loop < 16)
			{
				// (b and c) or (not b and d)
				f = ((b & c) | ((!b) & d));
				g = loop;
			}
			else if(loop < 32)
			{
				// (d and b) or (not d and c)
				f = ((d & b) | ((!d) & c));
				g = (5 * loop + 1) % 16;
			}
			else if(loop < 48)
			{
				// b xor c xor d
				f = (b ^ c ^ d);
				g = (3 * loop + 5) % 16;
			}
			else if(loop < 64)
			{
				// c xor (b or not d)
				f = (c ^ (b | (!d)));
				g = (7 * loop) % 16;
			}
			
			tempVal = d;
			d = c;
			c = b;
			b = (unsigned int)b + (unsigned int)left_rotate(a + f + k[loop] + word[g], r[loop]);
			a = tempVal;
		}
		
		h0 += a;
		h1 += b;
		h2 += c;
		h3 += d;
	}
	
	if(debug)
	{
		printf("Stream content:\n");
		for(int loop = 0; loop < bufLen; loop++)
		{
			printf("0x%02X ", (unsigned char)buffer[loop]);
		}
	}
	
	printf("%08x%08x%08x%08x\n", h0, h1, h2, h3);
}

the below error occurs for pretty much every value of k

however I thought all my values would be in range, isn't the max size of an int 4294967296 on an x86 system?

The max size of a 32bit int is (2^32), which is 4,294,967,296 - so your correct :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.