1 #include "lib.h"
2 #include "md5.h"
3 
add_hexword(Str * str,Word32 w)4 static void add_hexword(Str *str, Word32 w) {
5   static char hexdigits[] = "0123456789abcdef";
6   char buf[8];
7   for (int i = 0; i < 4; i++) {
8     buf[2*i] = hexdigits[(w >> 4) & 0xf];
9     buf[2*i+1] = hexdigits[w &0xf];
10     w >>= 8;
11   }
12   str->add(buf, sizeof(buf));
13 }
14 
add_word(Str * str,Word32 w)15 static void add_word(Str *str, Word32 w) {
16   char buf[4];
17   for (int i = 0; i < 4; i++) {
18     buf[i] = w & 0xff;
19     w >>= 8;
20   }
21   str->add(buf, sizeof(buf));
22 }
23 
digest()24 MD5Digest MD5::digest() {
25   return state;
26 }
27 
hexdigest()28 Str *MD5::hexdigest() {
29   Str *result = new Str(32);
30   finish();
31   add_hexword(result, state.a);
32   add_hexword(result, state.b);
33   add_hexword(result, state.c);
34   add_hexword(result, state.d);
35   return result;
36 }
37 
bytedigest()38 Str *MD5::bytedigest() {
39   Str *result = new Str(16);
40   finish();
41   add_word(result, state.a);
42   add_word(result, state.b);
43   add_word(result, state.c);
44   add_word(result, state.d);
45   return result;
46 }
47 
digest(Str * str)48 MD5Digest MD5::digest(Str *str) {
49   MD5 digest;
50   digest.update(str);
51   return digest.state;
52 }
53 
hexdigest(Str * str)54 Str *MD5::hexdigest(Str *str) {
55   MD5 digest;
56   digest.update(str);
57   return digest.hexdigest();
58 }
59 
bytedigest(Str * str)60 Str *MD5::bytedigest(Str *str) {
61   MD5 digest;
62   digest.update(str);
63   return digest.bytedigest();
64 }
65 
update(const void * data,Int len)66 void MD5::update(const void *data, Int len) {
67   require(len >= 0, "negative length");
68   const unsigned char *ptr = (const unsigned char *) data;
69   total_length += len;
70   if (len + fragment_length < sizeof(fragment)) {
71     memcpy(fragment + fragment_length, ptr, len);
72     fragment_length += len;
73     return;
74   }
75   if (fragment_length != 0) {
76     memcpy(fragment + fragment_length, ptr, 64 - fragment_length);
77     update_block(fragment);
78     len -= (64 - fragment_length);
79     ptr += (64 - fragment_length);
80     fragment_length = 0;
81   }
82   while (len >= 64) {
83     update_block(ptr);
84     ptr += 64;
85     len -= 64;
86   }
87   memcpy(fragment, ptr, len);
88   fragment_length = len;
89 }
90 
finish()91 void MD5::finish() {
92   if (finished)
93     return;
94   fragment[fragment_length++] = 0x80;
95   if (fragment_length > 56) {
96     memset(fragment + fragment_length, 0, 64 - fragment_length);
97     update_block(fragment);
98     fragment_length = 0;
99   }
100   memset(fragment + fragment_length, 0, 56 - fragment_length);
101   unsigned char * p = fragment + 56;
102   Word n = total_length * 8;
103   for (int i = 0; i < 8; i++) {
104     *p++ = (unsigned char) n;
105     n >>= 8;
106   }
107   update_block(fragment);
108   finished = true;
109 }
110 
update_block(const unsigned char * data)111 void MD5::update_block(const unsigned char *data) {
112   Word32 buf[16];
113   Word32 a = state.a;
114   Word32 b = state.b;
115   Word32 c = state.c;
116   Word32 d = state.d;
117   for (int i = 0; i < 16; i++) {
118     Word32 t = *data++;
119     t |= (*data++) << 8;
120     t |= (*data++) << 16;
121     t |= (*data++) << 24;
122     buf[i] = t;
123   }
124 #include "md5block.h"
125   state.a += a;
126   state.b += b;
127   state.c += c;
128   state.d += d;
129 }
130