luajitos

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

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