MD5.c (8303B)
1 /* 2 * MD5 Implementation 3 * Note: MD5 is cryptographically broken, use for compatibility/checksums only 4 */ 5 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 #include <stdint.h> 10 11 // MD5 context 12 typedef struct { 13 uint32_t state[4]; 14 uint64_t count; 15 uint8_t buffer[64]; 16 } md5_context; 17 18 // MD5 functions 19 #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) 20 #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) 21 #define H(x, y, z) ((x) ^ (y) ^ (z)) 22 #define I(x, y, z) ((y) ^ ((x) | ~(z))) 23 24 // Rotate left 25 #define ROTL_MD5(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) 26 27 // MD5 constants 28 static const uint32_t T[64] = { 29 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 30 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 31 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 32 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 33 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 34 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 35 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 36 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 37 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 38 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 39 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 40 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 41 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 42 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 43 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 44 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 45 }; 46 47 // MD5 transform 48 static void md5_transform(uint32_t state[4], const uint8_t block[64]) { 49 uint32_t a, b, c, d, x[16]; 50 int i; 51 52 // Decode block into x 53 for (i = 0; i < 16; i++) { 54 x[i] = ((uint32_t)block[i * 4]) | 55 ((uint32_t)block[i * 4 + 1] << 8) | 56 ((uint32_t)block[i * 4 + 2] << 16) | 57 ((uint32_t)block[i * 4 + 3] << 24); 58 } 59 60 a = state[0]; 61 b = state[1]; 62 c = state[2]; 63 d = state[3]; 64 65 // Round 1 66 #define FF(a, b, c, d, x, s, ac) { \ 67 (a) += F((b), (c), (d)) + (x) + (ac); \ 68 (a) = ROTL_MD5((a), (s)); \ 69 (a) += (b); \ 70 } 71 72 FF(a, b, c, d, x[ 0], 7, T[ 0]); FF(d, a, b, c, x[ 1], 12, T[ 1]); 73 FF(c, d, a, b, x[ 2], 17, T[ 2]); FF(b, c, d, a, x[ 3], 22, T[ 3]); 74 FF(a, b, c, d, x[ 4], 7, T[ 4]); FF(d, a, b, c, x[ 5], 12, T[ 5]); 75 FF(c, d, a, b, x[ 6], 17, T[ 6]); FF(b, c, d, a, x[ 7], 22, T[ 7]); 76 FF(a, b, c, d, x[ 8], 7, T[ 8]); FF(d, a, b, c, x[ 9], 12, T[ 9]); 77 FF(c, d, a, b, x[10], 17, T[10]); FF(b, c, d, a, x[11], 22, T[11]); 78 FF(a, b, c, d, x[12], 7, T[12]); FF(d, a, b, c, x[13], 12, T[13]); 79 FF(c, d, a, b, x[14], 17, T[14]); FF(b, c, d, a, x[15], 22, T[15]); 80 81 // Round 2 82 #define GG(a, b, c, d, x, s, ac) { \ 83 (a) += G((b), (c), (d)) + (x) + (ac); \ 84 (a) = ROTL_MD5((a), (s)); \ 85 (a) += (b); \ 86 } 87 88 GG(a, b, c, d, x[ 1], 5, T[16]); GG(d, a, b, c, x[ 6], 9, T[17]); 89 GG(c, d, a, b, x[11], 14, T[18]); GG(b, c, d, a, x[ 0], 20, T[19]); 90 GG(a, b, c, d, x[ 5], 5, T[20]); GG(d, a, b, c, x[10], 9, T[21]); 91 GG(c, d, a, b, x[15], 14, T[22]); GG(b, c, d, a, x[ 4], 20, T[23]); 92 GG(a, b, c, d, x[ 9], 5, T[24]); GG(d, a, b, c, x[14], 9, T[25]); 93 GG(c, d, a, b, x[ 3], 14, T[26]); GG(b, c, d, a, x[ 8], 20, T[27]); 94 GG(a, b, c, d, x[13], 5, T[28]); GG(d, a, b, c, x[ 2], 9, T[29]); 95 GG(c, d, a, b, x[ 7], 14, T[30]); GG(b, c, d, a, x[12], 20, T[31]); 96 97 // Round 3 98 #define HH(a, b, c, d, x, s, ac) { \ 99 (a) += H((b), (c), (d)) + (x) + (ac); \ 100 (a) = ROTL_MD5((a), (s)); \ 101 (a) += (b); \ 102 } 103 104 HH(a, b, c, d, x[ 5], 4, T[32]); HH(d, a, b, c, x[ 8], 11, T[33]); 105 HH(c, d, a, b, x[11], 16, T[34]); HH(b, c, d, a, x[14], 23, T[35]); 106 HH(a, b, c, d, x[ 1], 4, T[36]); HH(d, a, b, c, x[ 4], 11, T[37]); 107 HH(c, d, a, b, x[ 7], 16, T[38]); HH(b, c, d, a, x[10], 23, T[39]); 108 HH(a, b, c, d, x[13], 4, T[40]); HH(d, a, b, c, x[ 0], 11, T[41]); 109 HH(c, d, a, b, x[ 3], 16, T[42]); HH(b, c, d, a, x[ 6], 23, T[43]); 110 HH(a, b, c, d, x[ 9], 4, T[44]); HH(d, a, b, c, x[12], 11, T[45]); 111 HH(c, d, a, b, x[15], 16, T[46]); HH(b, c, d, a, x[ 2], 23, T[47]); 112 113 // Round 4 114 #define II(a, b, c, d, x, s, ac) { \ 115 (a) += I((b), (c), (d)) + (x) + (ac); \ 116 (a) = ROTL_MD5((a), (s)); \ 117 (a) += (b); \ 118 } 119 120 II(a, b, c, d, x[ 0], 6, T[48]); II(d, a, b, c, x[ 7], 10, T[49]); 121 II(c, d, a, b, x[14], 15, T[50]); II(b, c, d, a, x[ 5], 21, T[51]); 122 II(a, b, c, d, x[12], 6, T[52]); II(d, a, b, c, x[ 3], 10, T[53]); 123 II(c, d, a, b, x[10], 15, T[54]); II(b, c, d, a, x[ 1], 21, T[55]); 124 II(a, b, c, d, x[ 8], 6, T[56]); II(d, a, b, c, x[15], 10, T[57]); 125 II(c, d, a, b, x[ 6], 15, T[58]); II(b, c, d, a, x[13], 21, T[59]); 126 II(a, b, c, d, x[ 4], 6, T[60]); II(d, a, b, c, x[11], 10, T[61]); 127 II(c, d, a, b, x[ 2], 15, T[62]); II(b, c, d, a, x[ 9], 21, T[63]); 128 129 state[0] += a; 130 state[1] += b; 131 state[2] += c; 132 state[3] += d; 133 } 134 135 // Initialize MD5 context 136 void md5_init(md5_context *ctx) { 137 ctx->state[0] = 0x67452301; 138 ctx->state[1] = 0xefcdab89; 139 ctx->state[2] = 0x98badcfe; 140 ctx->state[3] = 0x10325476; 141 ctx->count = 0; 142 } 143 144 // Update MD5 with data 145 void md5_update(md5_context *ctx, const uint8_t *data, size_t len) { 146 size_t i, index, part_len; 147 148 index = (size_t)(ctx->count & 0x3F); 149 ctx->count += len; 150 part_len = 64 - index; 151 152 if (len >= part_len) { 153 memcpy(&ctx->buffer[index], data, part_len); 154 md5_transform(ctx->state, ctx->buffer); 155 156 for (i = part_len; i + 63 < len; i += 64) { 157 md5_transform(ctx->state, &data[i]); 158 } 159 index = 0; 160 } else { 161 i = 0; 162 } 163 164 memcpy(&ctx->buffer[index], &data[i], len - i); 165 } 166 167 // Finalize MD5 and produce digest 168 void md5_final(md5_context *ctx, uint8_t digest[16]) { 169 uint8_t bits[8]; 170 size_t index, pad_len; 171 uint64_t bit_count = ctx->count * 8; 172 173 // Encode bit count (little-endian) 174 for (int i = 0; i < 8; i++) { 175 bits[i] = (uint8_t)(bit_count >> (i * 8)); 176 } 177 178 // Pad 179 index = (size_t)(ctx->count & 0x3F); 180 pad_len = (index < 56) ? (56 - index) : (120 - index); 181 182 uint8_t padding[64]; 183 padding[0] = 0x80; 184 memset(padding + 1, 0, pad_len - 1); 185 186 md5_update(ctx, padding, pad_len); 187 md5_update(ctx, bits, 8); 188 189 // Store digest (little-endian) 190 for (int i = 0; i < 4; i++) { 191 digest[i * 4] = (uint8_t)(ctx->state[i]); 192 digest[i * 4 + 1] = (uint8_t)(ctx->state[i] >> 8); 193 digest[i * 4 + 2] = (uint8_t)(ctx->state[i] >> 16); 194 digest[i * 4 + 3] = (uint8_t)(ctx->state[i] >> 24); 195 } 196 } 197 198 // One-shot MD5 199 void md5(const uint8_t *data, size_t len, uint8_t digest[16]) { 200 md5_context ctx; 201 md5_init(&ctx); 202 md5_update(&ctx, data, len); 203 md5_final(&ctx, digest); 204 } 205 206 // Test program 207 #ifndef LIB_MODE 208 int main(void) { 209 printf("MD5 Implementation\n"); 210 printf("==================\n"); 211 printf("WARNING: MD5 is cryptographically broken. Use for checksums only!\n\n"); 212 213 // Test vectors 214 const char *test1 = ""; 215 const char *test2 = "a"; 216 const char *test3 = "abc"; 217 const char *test4 = "message digest"; 218 219 uint8_t digest[16]; 220 221 // Test 1 222 printf("Test 1: \"%s\"\n", test1); 223 md5((uint8_t*)test1, strlen(test1), digest); 224 printf("MD5: "); 225 for (int i = 0; i < 16; i++) printf("%02x", digest[i]); 226 printf("\n"); 227 printf("Expected: d41d8cd98f00b204e9800998ecf8427e\n\n"); 228 229 // Test 2 230 printf("Test 2: \"%s\"\n", test2); 231 md5((uint8_t*)test2, strlen(test2), digest); 232 printf("MD5: "); 233 for (int i = 0; i < 16; i++) printf("%02x", digest[i]); 234 printf("\n"); 235 printf("Expected: 0cc175b9c0f1b6a831c399e269772661\n\n"); 236 237 // Test 3 238 printf("Test 3: \"%s\"\n", test3); 239 md5((uint8_t*)test3, strlen(test3), digest); 240 printf("MD5: "); 241 for (int i = 0; i < 16; i++) printf("%02x", digest[i]); 242 printf("\n"); 243 printf("Expected: 900150983cd24fb0d6963f7d28e17f72\n\n"); 244 245 // Test 4 246 printf("Test 4: \"%s\"\n", test4); 247 md5((uint8_t*)test4, strlen(test4), digest); 248 printf("MD5: "); 249 for (int i = 0; i < 16; i++) printf("%02x", digest[i]); 250 printf("\n"); 251 printf("Expected: f96b697d7cb7938d525a2f31aaf161d0\n\n"); 252 253 return 0; 254 } 255 #endif