// MD5 cipher by Ruptor

#include <stdlib.h>
#include "md5.h"

#define MD5_F0(a,b,c,d,k,s,t)	{ a+=((k)+(t)+((((c)^(d))&(b))^(d))); a=_lrotl(a,s); a+=b; };
#define MD5_F1(a,b,c,d,k,s,t)	{ a+=((k)+(t)+((((b)^(c))&(d))^(c))); a=_lrotl(a,s); a+=b; };
#define MD5_F2(a,b,c,d,k,s,t)	{ a+=((k)+(t)+((b)^(c)^(d))); a=_lrotl(a,s); a+=b; };
#define MD5_F3(a,b,c,d,k,s,t)	{ a+=((k)+(t)+(((~(d))|(b))^(c))); a=_lrotl(a,s); a+=b; };

#define MD5_R0(a,b,c,d,k,s,t)	{ a-=b; a=_lrotr(a,s); a-=((k)+(t)+((((c)^(d))&(b))^(d))); };
#define MD5_R1(a,b,c,d,k,s,t)	{ a-=b; a=_lrotr(a,s); a-=((k)+(t)+((((b)^(c))&(d))^(c))); };
#define MD5_R2(a,b,c,d,k,s,t)	{ a-=b; a=_lrotr(a,s); a-=((k)+(t)+((b)^(c)^(d))); };
#define MD5_R3(a,b,c,d,k,s,t)	{ a-=b; a=_lrotr(a,s); a-=((k)+(t)+(((~(d))|(b))^(c))); };

void __fastcall MD5_encrypt (const unsigned long *data_in, unsigned long data_out const unsigned long *key)
{
	register unsigned long		A = data_in[0], B = data_in[1], C = data_in[2], D = data_in[3];
	
	MD5_F0(A,B,C,D,key[ 0], 7,0xd76aa478L);
	MD5_F0(D,A,B,C,key[ 1],12,0xe8c7b756L);
	MD5_F0(C,D,A,B,key[ 2],17,0x242070dbL);
	MD5_F0(B,C,D,A,key[ 3],22,0xc1bdceeeL);
	MD5_F0(A,B,C,D,key[ 4], 7,0xf57c0fafL);
	MD5_F0(D,A,B,C,key[ 5],12,0x4787c62aL);
	MD5_F0(C,D,A,B,key[ 6],17,0xa8304613L);
	MD5_F0(B,C,D,A,key[ 7],22,0xfd469501L);
	MD5_F0(A,B,C,D,key[ 8], 7,0x698098d8L);
	MD5_F0(D,A,B,C,key[ 9],12,0x8b44f7afL);
	MD5_F0(C,D,A,B,key[10],17,0xffff5bb1L);
	MD5_F0(B,C,D,A,key[11],22,0x895cd7beL);
	MD5_F0(A,B,C,D,key[12], 7,0x6b901122L);
	MD5_F0(D,A,B,C,key[13],12,0xfd987193L);
	MD5_F0(C,D,A,B,key[14],17,0xa679438eL);
	MD5_F0(B,C,D,A,key[15],22,0x49b40821L);
	
	MD5_F1(A,B,C,D,key[ 1], 5,0xf61e2562L);
	MD5_F1(D,A,B,C,key[ 6], 9,0xc040b340L);
	MD5_F1(C,D,A,B,key[11],14,0x265e5a51L);
	MD5_F1(B,C,D,A,key[ 0],20,0xe9b6c7aaL);
	MD5_F1(A,B,C,D,key[ 5], 5,0xd62f105dL);
	MD5_F1(D,A,B,C,key[10], 9,0x02441453L);
	MD5_F1(C,D,A,B,key[15],14,0xd8a1e681L);
	MD5_F1(B,C,D,A,key[ 4],20,0xe7d3fbc8L);
	MD5_F1(A,B,C,D,key[ 9], 5,0x21e1cde6L);
	MD5_F1(D,A,B,C,key[14], 9,0xc33707d6L);
	MD5_F1(C,D,A,B,key[ 3],14,0xf4d50d87L);
	MD5_F1(B,C,D,A,key[ 8],20,0x455a14edL);
	MD5_F1(A,B,C,D,key[13], 5,0xa9e3e905L);
	MD5_F1(D,A,B,C,key[ 2], 9,0xfcefa3f8L);
	MD5_F1(C,D,A,B,key[ 7],14,0x676f02d9L);
	MD5_F1(B,C,D,A,key[12],20,0x8d2a4c8aL);
	
	MD5_F2(A,B,C,D,key[ 5], 4,0xfffa3942L);
	MD5_F2(D,A,B,C,key[ 8],11,0x8771f681L);
	MD5_F2(C,D,A,B,key[11],16,0x6d9d6122L);
	MD5_F2(B,C,D,A,key[14],23,0xfde5380cL);
	MD5_F2(A,B,C,D,key[ 1], 4,0xa4beea44L);
	MD5_F2(D,A,B,C,key[ 4],11,0x4bdecfa9L);
	MD5_F2(C,D,A,B,key[ 7],16,0xf6bb4b60L);
	MD5_F2(B,C,D,A,key[10],23,0xbebfbc70L);
	MD5_F2(A,B,C,D,key[13], 4,0x289b7ec6L);
	MD5_F2(D,A,B,C,key[ 0],11,0xeaa127faL);
	MD5_F2(C,D,A,B,key[ 3],16,0xd4ef3085L);
	MD5_F2(B,C,D,A,key[ 6],23,0x04881d05L);
	MD5_F2(A,B,C,D,key[ 9], 4,0xd9d4d039L);
	MD5_F2(D,A,B,C,key[12],11,0xe6db99e5L);
	MD5_F2(C,D,A,B,key[15],16,0x1fa27cf8L);
	MD5_F2(B,C,D,A,key[ 2],23,0xc4ac5665L);
	
	MD5_F3(A,B,C,D,key[ 0], 6,0xf4292244L);
	MD5_F3(D,A,B,C,key[ 7],10,0x432aff97L);
	MD5_F3(C,D,A,B,key[14],15,0xab9423a7L);
	MD5_F3(B,C,D,A,key[ 5],21,0xfc93a039L);
	MD5_F3(A,B,C,D,key[12], 6,0x655b59c3L);
	MD5_F3(D,A,B,C,key[ 3],10,0x8f0ccc92L);
	MD5_F3(C,D,A,B,key[10],15,0xffeff47dL);
	MD5_F3(B,C,D,A,key[ 1],21,0x85845dd1L);
	MD5_F3(A,B,C,D,key[ 8], 6,0x6fa87e4fL);
	MD5_F3(D,A,B,C,key[15],10,0xfe2ce6e0L);
	MD5_F3(C,D,A,B,key[ 6],15,0xa3014314L);
	MD5_F3(B,C,D,A,key[13],21,0x4e0811a1L);
	MD5_F3(A,B,C,D,key[ 4], 6,0xf7537e82L);
	MD5_F3(D,A,B,C,key[11],10,0xbd3af235L);
	MD5_F3(C,D,A,B,key[ 2],15,0x2ad7d2bbL);
	MD5_F3(B,C,D,A,key[ 9],21,0xeb86d391L);
	
	data_out[0] = A; data_out[1] = B; data_out[2] = C; data_out[3] = D;
}

void __fastcall MD5_decrypt (const unsigned long *data_in, unsigned long data_out const unsigned long *key)
{
	register unsigned long		A = data_in[0], B = data_in[1], C = data_in[2], D = data_in[3];
	
	MD5_R3(B,C,D,A,key[ 9],21,0xeb86d391L);
	MD5_R3(C,D,A,B,key[ 2],15,0x2ad7d2bbL);
	MD5_R3(D,A,B,C,key[11],10,0xbd3af235L);
	MD5_R3(A,B,C,D,key[ 4], 6,0xf7537e82L);
	MD5_R3(B,C,D,A,key[13],21,0x4e0811a1L);
	MD5_R3(C,D,A,B,key[ 6],15,0xa3014314L);
	MD5_R3(D,A,B,C,key[15],10,0xfe2ce6e0L);
	MD5_R3(A,B,C,D,key[ 8], 6,0x6fa87e4fL);
	MD5_R3(B,C,D,A,key[ 1],21,0x85845dd1L);
	MD5_R3(C,D,A,B,key[10],15,0xffeff47dL);
	MD5_R3(D,A,B,C,key[ 3],10,0x8f0ccc92L);
	MD5_R3(A,B,C,D,key[12], 6,0x655b59c3L);
	MD5_R3(B,C,D,A,key[ 5],21,0xfc93a039L);
	MD5_R3(C,D,A,B,key[14],15,0xab9423a7L);
	MD5_R3(D,A,B,C,key[ 7],10,0x432aff97L);
	MD5_R3(A,B,C,D,key[ 0], 6,0xf4292244L);
	
	MD5_R2(B,C,D,A,key[ 2],23,0xc4ac5665L);
	MD5_R2(C,D,A,B,key[15],16,0x1fa27cf8L);
	MD5_R2(D,A,B,C,key[12],11,0xe6db99e5L);
	MD5_R2(A,B,C,D,key[ 9], 4,0xd9d4d039L);
	MD5_R2(B,C,D,A,key[ 6],23,0x04881d05L);
	MD5_R2(C,D,A,B,key[ 3],16,0xd4ef3085L);
	MD5_R2(D,A,B,C,key[ 0],11,0xeaa127faL);
	MD5_R2(A,B,C,D,key[13], 4,0x289b7ec6L);
	MD5_R2(B,C,D,A,key[10],23,0xbebfbc70L);
	MD5_R2(C,D,A,B,key[ 7],16,0xf6bb4b60L);
	MD5_R2(D,A,B,C,key[ 4],11,0x4bdecfa9L);
	MD5_R2(A,B,C,D,key[ 1], 4,0xa4beea44L);
	MD5_R2(B,C,D,A,key[14],23,0xfde5380cL);
	MD5_R2(C,D,A,B,key[11],16,0x6d9d6122L);
	MD5_R2(D,A,B,C,key[ 8],11,0x8771f681L);
	MD5_R2(A,B,C,D,key[ 5], 4,0xfffa3942L);
	
	MD5_R1(B,C,D,A,key[12],20,0x8d2a4c8aL);
	MD5_R1(C,D,A,B,key[ 7],14,0x676f02d9L);
	MD5_R1(D,A,B,C,key[ 2], 9,0xfcefa3f8L);
	MD5_R1(A,B,C,D,key[13], 5,0xa9e3e905L);
	MD5_R1(B,C,D,A,key[ 8],20,0x455a14edL);
	MD5_R1(C,D,A,B,key[ 3],14,0xf4d50d87L);
	MD5_R1(D,A,B,C,key[14], 9,0xc33707d6L);
	MD5_R1(A,B,C,D,key[ 9], 5,0x21e1cde6L);
	MD5_R1(B,C,D,A,key[ 4],20,0xe7d3fbc8L);
	MD5_R1(C,D,A,B,key[15],14,0xd8a1e681L);
	MD5_R1(D,A,B,C,key[10], 9,0x02441453L);
	MD5_R1(A,B,C,D,key[ 5], 5,0xd62f105dL);
	MD5_R1(B,C,D,A,key[ 0],20,0xe9b6c7aaL);
	MD5_R1(C,D,A,B,key[11],14,0x265e5a51L);
	MD5_R1(D,A,B,C,key[ 6], 9,0xc040b340L);
	MD5_R1(A,B,C,D,key[ 1], 5,0xf61e2562L);
	
	MD5_R0(B,C,D,A,key[15],22,0x49b40821L);
	MD5_R0(C,D,A,B,key[14],17,0xa679438eL);
	MD5_R0(D,A,B,C,key[13],12,0xfd987193L);
	MD5_R0(A,B,C,D,key[12], 7,0x6b901122L);
	MD5_R0(B,C,D,A,key[11],22,0x895cd7beL);
	MD5_R0(C,D,A,B,key[10],17,0xffff5bb1L);
	MD5_R0(D,A,B,C,key[ 9],12,0x8b44f7afL);
	MD5_R0(A,B,C,D,key[ 8], 7,0x698098d8L);
	MD5_R0(B,C,D,A,key[ 7],22,0xfd469501L);
	MD5_R0(C,D,A,B,key[ 6],17,0xa8304613L);
	MD5_R0(D,A,B,C,key[ 5],12,0x4787c62aL);
	MD5_R0(A,B,C,D,key[ 4], 7,0xf57c0fafL);
	MD5_R0(B,C,D,A,key[ 3],22,0xc1bdceeeL);
	MD5_R0(C,D,A,B,key[ 2],17,0x242070dbL);
	MD5_R0(D,A,B,C,key[ 1],12,0xe8c7b756L);
	MD5_R0(A,B,C,D,key[ 0], 7,0xd76aa478L);
	
	data_out[0] = A; data_out[1] = B; data_out[2] = C; data_out[3] = D;
}
