Author | Message | Time |
---|---|---|
HdxBmx27 | Well I decided I wanted to do MD5 verification of Warden modules, but then relized that I 1) Had no implementation of it in C, and 2) All the code I found online was really really fucking ugly. (Exa: here MD5STEP WTFUX?) So I did a bit of research and realized that MD5 is damn near SHA1 [Makes sense as it's its predecessor]. So a bit of cleaning up I ended up with this: [code]#ifndef MD5_H #define MD5_H #include "stdint.h" #include "math.h" #ifndef _MD5_enum_ #define _MD5_enum_ enum{ md5_success = 0, md5_null, /* Null pointer parameter */ md5_input_too_long, /* input data too long */ md5_state_error /* called Input after Result */ }; #endif #define md5_hash_size 16 /* Data structure for MD5 (Message Digest) computation */ typedef struct { uint32_t i[2]; /* number of _bits_ handled mod 2^64 */ uint32_t buf[4]; /* scratch buffer */ uint8_t in[64]; /* input buffer */ uint8_t digest[16]; /* actual digest after MD5Final call */ } MD5_CTX; typedef struct md5_context{ uint32_t intermediate_hash[md5_hash_size / 4]; /* Message Digest */ uint32_t length_low; /* Message length in bits */ uint32_t length_high; /* Message length in bits */ int_least16_t message_block_index; /* Index into message block array */ uint8_t message_block[64]; /* 512-bit message blocks */ uint8_t computed; /* Is the digest computed? */ uint8_t corrupted; /* Is the message digest corrupted? */ } md5_context; int __stdcall md5_reset(md5_context *); int __stdcall md5_input(md5_context *, const uint8_t *, uint32_t); int __stdcall md5_digest(md5_context *, uint8_t *); int __stdcall md5_verify_data(uint8_t *, uint32_t, const uint8_t *); #endif[/code][code]#include "md5.h" void md5_process_message_block(md5_context *); #define md5_batoi(ba, i) \ ((ba[i+3] << 24) | (ba[i+2] << 16) | (ba[i+1] << 8) | ba[i]) #define md5_rol(word, bits) \ (((word) << (bits)) | ((word) >> (32-(bits)))) #define md5_itoba(a, ba, i) \ (ba[i+3] = (uint8_t)(a >> 24)); (ba[i+2] = (uint8_t)(a >> 16)); (ba[i+1] = (uint8_t)(a >> 8)); (ba[i] = (uint8_t)a); uint32_t md5_math(uint16_t t, uint32_t B, uint32_t C, uint32_t D){ if(t < 16) return (D ^ (B & (C ^ D))); else if(t < 32) return (C ^ (D & (B ^ C))); else if(t < 48) return (B ^ C ^ D); else return (C ^ (B | ~D)); } uint16_t md5_index(uint16_t t){ if(t < 16) return t; else if(t < 32) return (5 * t + 1) % 16; else if(t < 48) return (3 * t + 5) % 16; else return (7 * t) % 16; } uint16_t md5_shift(uint16_t t){ if(t < 16) return (((t % 4) + 1) * 5 + 2); else if(t < 32) return (t % 4 == 0 ? 5 : (t % 4 == 1 ? 9 : (t % 4 == 2 ? 14 : 20))); else if(t < 48) return (t % 4 == 0 ? 4 : (t % 4 == 1 ? 11 : (t % 4 == 2 ? 16 : 23))); else return (t % 4 == 0 ? 6 : (t % 4 == 1 ? 10 : (t % 4 == 2 ? 15 : 21))); } int __stdcall md5_reset(md5_context *ctx){ uint8_t x = 0; if(!ctx) return md5_null; ctx->length_low = 0; ctx->length_high = 0; ctx->computed = 0; ctx->corrupted = 0; ctx->message_block_index = 0; for(x = 0; x < 64; x++) ctx->message_block[x] = 0; ctx->intermediate_hash[0] = 0x67452301; ctx->intermediate_hash[1] = 0xEFCDAB89; ctx->intermediate_hash[2] = 0x98BADCFE; ctx->intermediate_hash[3] = 0x10325476; return md5_success; } int __stdcall md5_input(md5_context *ctx, const uint8_t *data, uint32_t length){ uint32_t x; if(!length) return md5_success; if(!ctx || !data) return md5_null; if(ctx->computed){ ctx->corrupted = md5_state_error; return md5_state_error; } for(x = 0; x < length; x++){ ctx->message_block[ctx->message_block_index++] = (data[x] & 0xFF); ctx->length_low += 8; if (ctx->length_low == 0){ ctx->length_high++; if(ctx->length_high == 0){ ctx->corrupted = md5_input_too_long; return md5_input_too_long; } } if(ctx->message_block_index == 64) md5_process_message_block(ctx); } return md5_success; } int __stdcall md5_digest(md5_context *ctx, uint8_t *digest){ int i; if (!ctx || !digest) return md5_null; if (ctx->corrupted) return ctx->corrupted; if (!ctx->computed){ if (ctx->message_block_index > 55){ ctx->message_block[ctx->message_block_index++] = 0x80; while(ctx->message_block_index < 64) ctx->message_block[ctx->message_block_index++] = 0; md5_process_message_block(ctx); }else{ ctx->message_block[ctx->message_block_index++] = 0x80; } while(ctx->message_block_index < 56) ctx->message_block[ctx->message_block_index++] = 0; md5_itoba(ctx->length_high, ctx->message_block, 60); md5_itoba(ctx->length_low, ctx->message_block, 56); md5_process_message_block(ctx); ctx->length_low = 0; ctx->length_high = 0; ctx->computed = 1; } for(i = 0; i < 4; i++){ md5_itoba(ctx->intermediate_hash[i], digest, i * 4); } return md5_success; } void md5_process_message_block(md5_context *ctx){ uint16_t t; /* Loop counter */ uint32_t temp; /* Temporary word value*/ uint32_t W[16]; /* Word sequence */ uint32_t A, B, C, D; /* Word buffers */ const uint32_t K[] = { /* K = floor(abs(sin(x+1) & (2 pow 32))) */ 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 }; for(t = 0; t < 16; t++) W[t] = md5_batoi(ctx->message_block, t * 4); A = ctx->intermediate_hash[0]; B = ctx->intermediate_hash[1]; C = ctx->intermediate_hash[2]; D = ctx->intermediate_hash[3]; for(t = 0; t < 64; t++){ temp = B + md5_rol((A + md5_math(t, B, C, D) + W[md5_index(t)] + K[t]), md5_shift(t)); A = D; D = C; C = B; B = temp; } ctx->intermediate_hash[0] += A; ctx->intermediate_hash[1] += B; ctx->intermediate_hash[2] += C; ctx->intermediate_hash[3] += D; ctx->message_block_index = 0; } int __stdcall md5_verify_data(uint8_t *data, uint32_t length, const uint8_t *correct_md5){ md5_context ctx; uint8_t digest[16]; uint32_t x; md5_reset(&ctx); md5_input(&ctx, data, length); md5_digest(&ctx, digest); if(!correct_md5) return 0; for(x = 0; x < 16; x++){ if(digest[x] != correct_md5[x]) return 0; } return 1; }[/code] Note, its not perfect [it works 100% but meh] Its not efficient, its not as clean as it could be, but hey, It looks better then the MD5STEP crap. If anyone has suggestions on ways to make it cleaner/better ive it a shout. I really want to replace that block of ints, but C dosen't like doing 64-bit math. To gen K it looks like this: [code]for(int x = 0; x < 64; x++) K[x] = floor(asb(((uint64_t)sin(x + 1)) << 32))[/code] | April 18, 2009, 6:31 AM |
Myndfyr | What was wrong with this, which is the first result from Googling "C MD5"? Mostly I'm just curious; it looked great to me. I don't see your test cases. | April 18, 2009, 7:53 AM |
HdxBmx27 | [code]#define S41 6 #define S42 10 #define S43 15 #define S44 21 II ( a, b, c, d, in[ 0], S41, 4096336452); /* 49 */ II ( d, a, b, c, in[ 7], S42, 1126891415); /* 50 */ II ( c, d, a, b, in[14], S43, 2878612391); /* 51 */ II ( b, c, d, a, in[ 5], S44, 4237533241); /* 52 */ II ( a, b, c, d, in[12], S41, 1700485571); /* 53 */ II ( d, a, b, c, in[ 3], S42, 2399980690); /* 54 */ II ( c, d, a, b, in[10], S43, 4293915773); /* 55 */ II ( b, c, d, a, in[ 1], S44, 2240044497); /* 56 */ II ( a, b, c, d, in[ 8], S41, 1873313359); /* 57 */ II ( d, a, b, c, in[15], S42, 4264355552); /* 58 */ II ( c, d, a, b, in[ 6], S43, 2734768916); /* 59 */ II ( b, c, d, a, in[13], S44, 1309151649); /* 60 */ II ( a, b, c, d, in[ 4], S41, 4149444226); /* 61 */ II ( d, a, b, c, in[11], S42, 3174756917); /* 62 */ II ( c, d, a, b, in[ 2], S43, 718787259); /* 63 */ II ( b, c, d, a, in[ 9], S44, 3951481745); /* 64 */[/code] That, it works fine, its just... eww. I also jsut noticed I put this in the wrong forum, oh well. | April 18, 2009, 7:55 AM |
Yegg | I also have a version that looks pretty similar to the one MyndFyre just provided, though not identical. This one also came from searching Google and it looks pretty nice. | April 18, 2009, 12:06 PM |
BreW | I don't think that hdx realizes those "ugly" versions of MD5 have their loops unrolled for performance reasons. | April 18, 2009, 1:36 PM |
HdxBmx27 | [quote author=brew link=topic=17911.msg182424#msg182424 date=1240061809] I don't think that hdx realizes those "ugly" versions of MD5 have their loops unrolled for performance reasons. [/quote]I Do | April 18, 2009, 5:37 PM |
Quarantine | Yeah, I don't really know why they'd use a Macro vs an Inline Function. | April 19, 2009, 6:29 PM |
Myndfyr | [quote author=Warrior link=topic=17911.msg182449#msg182449 date=1240165781] Yeah, I don't really know why they'd use a Macro vs an Inline Function. [/quote] Because an inline function isn't always guaranteed to be inlined. | April 20, 2009, 4:31 AM |