diff options
author | Simon Tatham <anakin@pobox.com> | 2017-05-18 06:43:51 +0100 |
---|---|---|
committer | Simon Tatham <anakin@pobox.com> | 2017-05-18 06:43:51 +0100 |
commit | ca59ebf60df4ef45a1e4d681980e29e3db853bba (patch) | |
tree | 15651c55c8d273181f93dd72377b09623d50b6f1 /md5.c | |
parent | 7de9585efbbd148df26cd180900db69e11c36061 (diff) | |
download | wix-on-linux-ca59ebf60df4ef45a1e4d681980e29e3db853bba.tar.gz wix-on-linux-ca59ebf60df4ef45a1e4d681980e29e3db853bba.tar.bz2 wix-on-linux-ca59ebf60df4ef45a1e4d681980e29e3db853bba.zip |
Move MD5 out into its own file.
This begins a programme of code reorganisation at the end of which I'd
like to end up with something almost legible :-)
Diffstat (limited to 'md5.c')
-rw-r--r-- | md5.c | 271 |
1 files changed, 271 insertions, 0 deletions
@@ -0,0 +1,271 @@ | |||
1 | /* | ||
2 | * Implement MsiGetFileHash(). | ||
3 | * | ||
4 | * Experimenting with a small test program on Windows calling the | ||
5 | * original version of that function suggests that the hash it | ||
6 | * implements is just MD5, only repackaged as an array of four | ||
7 | * little-endian 32-bit words instead of the usual 16 bytes. | ||
8 | */ | ||
9 | |||
10 | #include <stdio.h> | ||
11 | #include <stdint.h> | ||
12 | #include <string.h> | ||
13 | #include <stdbool.h> | ||
14 | |||
15 | #include <sys/types.h> | ||
16 | #include <sys/stat.h> | ||
17 | #include <fcntl.h> | ||
18 | #include <unistd.h> | ||
19 | |||
20 | #include <err.h> | ||
21 | |||
22 | #include "fake-lib.h" | ||
23 | |||
24 | /* ---------------------------------------------------------------------- | ||
25 | * Core MD5 algorithm: processes 16-word blocks into a message digest. | ||
26 | */ | ||
27 | |||
28 | typedef struct { | ||
29 | uint32_t h[4]; | ||
30 | } MD5_Core_State; | ||
31 | |||
32 | struct MD5Context { | ||
33 | MD5_Core_State core; | ||
34 | unsigned char block[64]; | ||
35 | int blkused; | ||
36 | uint64_t len; | ||
37 | }; | ||
38 | |||
39 | #define F(x,y,z) ( ((x) & (y)) | ((~(x)) & (z)) ) | ||
40 | #define G(x,y,z) ( ((x) & (z)) | ((~(z)) & (y)) ) | ||
41 | #define H(x,y,z) ( (x) ^ (y) ^ (z) ) | ||
42 | #define I(x,y,z) ( (y) ^ ( (x) | ~(z) ) ) | ||
43 | |||
44 | #define rol(x,y) ( ((x) << (y)) | (((uint32_t)x) >> (32-y)) ) | ||
45 | |||
46 | #define subround(f,w,x,y,z,k,s,ti) \ | ||
47 | w = x + rol(w + f(x,y,z) + block[k] + ti, s) | ||
48 | |||
49 | static void MD5_Core_Init(MD5_Core_State * s) | ||
50 | { | ||
51 | s->h[0] = 0x67452301; | ||
52 | s->h[1] = 0xefcdab89; | ||
53 | s->h[2] = 0x98badcfe; | ||
54 | s->h[3] = 0x10325476; | ||
55 | } | ||
56 | |||
57 | static void MD5_Block(MD5_Core_State * s, uint32_t * block) | ||
58 | { | ||
59 | uint32_t a, b, c, d; | ||
60 | |||
61 | a = s->h[0]; | ||
62 | b = s->h[1]; | ||
63 | c = s->h[2]; | ||
64 | d = s->h[3]; | ||
65 | |||
66 | subround(F, a, b, c, d, 0, 7, 0xd76aa478); | ||
67 | subround(F, d, a, b, c, 1, 12, 0xe8c7b756); | ||
68 | subround(F, c, d, a, b, 2, 17, 0x242070db); | ||
69 | subround(F, b, c, d, a, 3, 22, 0xc1bdceee); | ||
70 | subround(F, a, b, c, d, 4, 7, 0xf57c0faf); | ||
71 | subround(F, d, a, b, c, 5, 12, 0x4787c62a); | ||
72 | subround(F, c, d, a, b, 6, 17, 0xa8304613); | ||
73 | subround(F, b, c, d, a, 7, 22, 0xfd469501); | ||
74 | subround(F, a, b, c, d, 8, 7, 0x698098d8); | ||
75 | subround(F, d, a, b, c, 9, 12, 0x8b44f7af); | ||
76 | subround(F, c, d, a, b, 10, 17, 0xffff5bb1); | ||
77 | subround(F, b, c, d, a, 11, 22, 0x895cd7be); | ||
78 | subround(F, a, b, c, d, 12, 7, 0x6b901122); | ||
79 | subround(F, d, a, b, c, 13, 12, 0xfd987193); | ||
80 | subround(F, c, d, a, b, 14, 17, 0xa679438e); | ||
81 | subround(F, b, c, d, a, 15, 22, 0x49b40821); | ||
82 | subround(G, a, b, c, d, 1, 5, 0xf61e2562); | ||
83 | subround(G, d, a, b, c, 6, 9, 0xc040b340); | ||
84 | subround(G, c, d, a, b, 11, 14, 0x265e5a51); | ||
85 | subround(G, b, c, d, a, 0, 20, 0xe9b6c7aa); | ||
86 | subround(G, a, b, c, d, 5, 5, 0xd62f105d); | ||
87 | subround(G, d, a, b, c, 10, 9, 0x02441453); | ||
88 | subround(G, c, d, a, b, 15, 14, 0xd8a1e681); | ||
89 | subround(G, b, c, d, a, 4, 20, 0xe7d3fbc8); | ||
90 | subround(G, a, b, c, d, 9, 5, 0x21e1cde6); | ||
91 | subround(G, d, a, b, c, 14, 9, 0xc33707d6); | ||
92 | subround(G, c, d, a, b, 3, 14, 0xf4d50d87); | ||
93 | subround(G, b, c, d, a, 8, 20, 0x455a14ed); | ||
94 | subround(G, a, b, c, d, 13, 5, 0xa9e3e905); | ||
95 | subround(G, d, a, b, c, 2, 9, 0xfcefa3f8); | ||
96 | subround(G, c, d, a, b, 7, 14, 0x676f02d9); | ||
97 | subround(G, b, c, d, a, 12, 20, 0x8d2a4c8a); | ||
98 | subround(H, a, b, c, d, 5, 4, 0xfffa3942); | ||
99 | subround(H, d, a, b, c, 8, 11, 0x8771f681); | ||
100 | subround(H, c, d, a, b, 11, 16, 0x6d9d6122); | ||
101 | subround(H, b, c, d, a, 14, 23, 0xfde5380c); | ||
102 | subround(H, a, b, c, d, 1, 4, 0xa4beea44); | ||
103 | subround(H, d, a, b, c, 4, 11, 0x4bdecfa9); | ||
104 | subround(H, c, d, a, b, 7, 16, 0xf6bb4b60); | ||
105 | subround(H, b, c, d, a, 10, 23, 0xbebfbc70); | ||
106 | subround(H, a, b, c, d, 13, 4, 0x289b7ec6); | ||
107 | subround(H, d, a, b, c, 0, 11, 0xeaa127fa); | ||
108 | subround(H, c, d, a, b, 3, 16, 0xd4ef3085); | ||
109 | subround(H, b, c, d, a, 6, 23, 0x04881d05); | ||
110 | subround(H, a, b, c, d, 9, 4, 0xd9d4d039); | ||
111 | subround(H, d, a, b, c, 12, 11, 0xe6db99e5); | ||
112 | subround(H, c, d, a, b, 15, 16, 0x1fa27cf8); | ||
113 | subround(H, b, c, d, a, 2, 23, 0xc4ac5665); | ||
114 | subround(I, a, b, c, d, 0, 6, 0xf4292244); | ||
115 | subround(I, d, a, b, c, 7, 10, 0x432aff97); | ||
116 | subround(I, c, d, a, b, 14, 15, 0xab9423a7); | ||
117 | subround(I, b, c, d, a, 5, 21, 0xfc93a039); | ||
118 | subround(I, a, b, c, d, 12, 6, 0x655b59c3); | ||
119 | subround(I, d, a, b, c, 3, 10, 0x8f0ccc92); | ||
120 | subround(I, c, d, a, b, 10, 15, 0xffeff47d); | ||
121 | subround(I, b, c, d, a, 1, 21, 0x85845dd1); | ||
122 | subround(I, a, b, c, d, 8, 6, 0x6fa87e4f); | ||
123 | subround(I, d, a, b, c, 15, 10, 0xfe2ce6e0); | ||
124 | subround(I, c, d, a, b, 6, 15, 0xa3014314); | ||
125 | subround(I, b, c, d, a, 13, 21, 0x4e0811a1); | ||
126 | subround(I, a, b, c, d, 4, 6, 0xf7537e82); | ||
127 | subround(I, d, a, b, c, 11, 10, 0xbd3af235); | ||
128 | subround(I, c, d, a, b, 2, 15, 0x2ad7d2bb); | ||
129 | subround(I, b, c, d, a, 9, 21, 0xeb86d391); | ||
130 | |||
131 | s->h[0] += a; | ||
132 | s->h[1] += b; | ||
133 | s->h[2] += c; | ||
134 | s->h[3] += d; | ||
135 | } | ||
136 | |||
137 | /* ---------------------------------------------------------------------- | ||
138 | * Outer MD5 algorithm: take an arbitrary length byte string, | ||
139 | * convert it into 16-word blocks with the prescribed padding at | ||
140 | * the end, and pass those blocks to the core MD5 algorithm. | ||
141 | */ | ||
142 | |||
143 | #define BLKSIZE 64 | ||
144 | |||
145 | static void MD5Init(struct MD5Context *s) | ||
146 | { | ||
147 | MD5_Core_Init(&s->core); | ||
148 | s->blkused = 0; | ||
149 | s->len = 0; | ||
150 | } | ||
151 | |||
152 | static void MD5Update(struct MD5Context *s, unsigned char const *p, | ||
153 | unsigned len) | ||
154 | { | ||
155 | unsigned char *q = (unsigned char *) p; | ||
156 | uint32_t wordblock[16]; | ||
157 | int i; | ||
158 | |||
159 | /* | ||
160 | * Update the length field. | ||
161 | */ | ||
162 | s->len += len; | ||
163 | |||
164 | if (s->blkused + len < BLKSIZE) { | ||
165 | /* | ||
166 | * Trivial case: just add to the block. | ||
167 | */ | ||
168 | memcpy(s->block + s->blkused, q, len); | ||
169 | s->blkused += len; | ||
170 | } else { | ||
171 | /* | ||
172 | * We must complete and process at least one block. | ||
173 | */ | ||
174 | while (s->blkused + len >= BLKSIZE) { | ||
175 | memcpy(s->block + s->blkused, q, BLKSIZE - s->blkused); | ||
176 | q += BLKSIZE - s->blkused; | ||
177 | len -= BLKSIZE - s->blkused; | ||
178 | /* Now process the block. Gather bytes little-endian into words */ | ||
179 | for (i = 0; i < 16; i++) { | ||
180 | wordblock[i] = | ||
181 | (((uint32_t) s->block[i * 4 + 3]) << 24) | | ||
182 | (((uint32_t) s->block[i * 4 + 2]) << 16) | | ||
183 | (((uint32_t) s->block[i * 4 + 1]) << 8) | | ||
184 | (((uint32_t) s->block[i * 4 + 0]) << 0); | ||
185 | } | ||
186 | MD5_Block(&s->core, wordblock); | ||
187 | s->blkused = 0; | ||
188 | } | ||
189 | memcpy(s->block, q, len); | ||
190 | s->blkused = len; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | static void MD5Final(uint32_t output[4], struct MD5Context *s) | ||
195 | { | ||
196 | int i; | ||
197 | unsigned pad; | ||
198 | unsigned char c[64]; | ||
199 | uint64_t len; | ||
200 | |||
201 | if (s->blkused >= 56) | ||
202 | pad = 56 + 64 - s->blkused; | ||
203 | else | ||
204 | pad = 56 - s->blkused; | ||
205 | |||
206 | len = s->len << 3; | ||
207 | |||
208 | memset(c, 0, pad); | ||
209 | c[0] = 0x80; | ||
210 | MD5Update(s, c, pad); | ||
211 | |||
212 | c[7] = (len >> (8*7)) & 0xFF; | ||
213 | c[6] = (len >> (8*6)) & 0xFF; | ||
214 | c[5] = (len >> (8*5)) & 0xFF; | ||
215 | c[4] = (len >> (8*4)) & 0xFF; | ||
216 | c[3] = (len >> (8*3)) & 0xFF; | ||
217 | c[2] = (len >> (8*2)) & 0xFF; | ||
218 | c[1] = (len >> (8*1)) & 0xFF; | ||
219 | c[0] = (len >> (8*0)) & 0xFF; | ||
220 | |||
221 | MD5Update(s, c, 8); | ||
222 | |||
223 | for (i = 0; i < 4; i++) | ||
224 | output[i] = s->core.h[i]; | ||
225 | } | ||
226 | |||
227 | struct MsiHash { | ||
228 | uint32_t structure_size; | ||
229 | uint32_t hash_words[4]; | ||
230 | }; | ||
231 | |||
232 | uint32_t MsiGetFileHashW(const char16_t *filename, uint32_t options, | ||
233 | struct MsiHash *hash) | ||
234 | { | ||
235 | char *fname = ascii(filename, true); | ||
236 | uint32_t toret; | ||
237 | char buffer[4096]; | ||
238 | int fd = -1, retd; | ||
239 | struct MD5Context ctx; | ||
240 | |||
241 | fd = open(fname, O_RDONLY); | ||
242 | if (fd < 0) { | ||
243 | /* Could do some better errno -> GetLastError translation here */ | ||
244 | warnx("MsiGetFileHash(%s) -> ERROR_OPEN_FAILED", fname); | ||
245 | toret = 110; | ||
246 | goto cleanup; | ||
247 | } | ||
248 | |||
249 | MD5Init(&ctx); | ||
250 | |||
251 | while ((retd = read(fd, buffer, sizeof(buffer)) > 0)) | ||
252 | MD5Update(&ctx, buffer, retd); | ||
253 | if (retd < 0) { | ||
254 | warnx("MsiGetFileHash(%s) -> ERROR_READ_FAULT", fname); | ||
255 | toret = 30; | ||
256 | goto cleanup; | ||
257 | } | ||
258 | |||
259 | MD5Final(hash->hash_words, &ctx); | ||
260 | |||
261 | warnx("MsiGetFileHash(%s) -> %08x:%08x:%08x:%08x", fname, | ||
262 | (unsigned)hash->hash_words[0], (unsigned)hash->hash_words[1], | ||
263 | (unsigned)hash->hash_words[2], (unsigned)hash->hash_words[3]); | ||
264 | toret = 0; | ||
265 | |||
266 | cleanup: | ||
267 | if (fd != -1) | ||
268 | close(fd); | ||
269 | sfree(fname); | ||
270 | return toret; | ||
271 | } | ||