diff options
author | Simon Tatham <anakin@pobox.com> | 2017-05-16 19:06:45 +0100 |
---|---|---|
committer | Simon Tatham <anakin@pobox.com> | 2017-05-16 19:06:45 +0100 |
commit | 74592eecf350ca3dad569b6bfa8820d3f2f922db (patch) | |
tree | 246adde400a76ed99c255b880d38fdd15cb38a04 | |
parent | af3d986af771c8ce6401df5dd69504fb350c7de9 (diff) | |
download | wix-on-linux-74592eecf350ca3dad569b6bfa8820d3f2f922db.tar.gz wix-on-linux-74592eecf350ca3dad569b6bfa8820d3f2f922db.tar.bz2 wix-on-linux-74592eecf350ca3dad569b6bfa8820d3f2f922db.zip |
Implement MsiGetFileHash.
A quick experiment or two with the real Windows version suggests that
the hash function in question is just MD5, repackaged as an array of
four little-endian 32-bit words instead of 16 bytes.
-rw-r--r-- | fake-lib.c | 214 | ||||
-rw-r--r-- | fake-lib.h | 1 | ||||
-rw-r--r-- | fake-msi.c | 38 |
3 files changed, 253 insertions, 0 deletions
@@ -140,3 +140,217 @@ unsigned le(const unsigned char *buf, size_t len, size_t off, size_t nbytes) | |||
140 | } | 140 | } |
141 | return toret; | 141 | return toret; |
142 | } | 142 | } |
143 | |||
144 | /* ---------------------------------------------------------------------- | ||
145 | * Core MD5 algorithm: processes 16-word blocks into a message digest. | ||
146 | */ | ||
147 | |||
148 | typedef struct { | ||
149 | uint32_t h[4]; | ||
150 | } MD5_Core_State; | ||
151 | |||
152 | struct MD5Context { | ||
153 | MD5_Core_State core; | ||
154 | unsigned char block[64]; | ||
155 | int blkused; | ||
156 | uint32_t lenhi, lenlo; | ||
157 | }; | ||
158 | |||
159 | #define F(x,y,z) ( ((x) & (y)) | ((~(x)) & (z)) ) | ||
160 | #define G(x,y,z) ( ((x) & (z)) | ((~(z)) & (y)) ) | ||
161 | #define H(x,y,z) ( (x) ^ (y) ^ (z) ) | ||
162 | #define I(x,y,z) ( (y) ^ ( (x) | ~(z) ) ) | ||
163 | |||
164 | #define rol(x,y) ( ((x) << (y)) | (((uint32_t)x) >> (32-y)) ) | ||
165 | |||
166 | #define subround(f,w,x,y,z,k,s,ti) \ | ||
167 | w = x + rol(w + f(x,y,z) + block[k] + ti, s) | ||
168 | |||
169 | static void MD5_Core_Init(MD5_Core_State * s) | ||
170 | { | ||
171 | s->h[0] = 0x67452301; | ||
172 | s->h[1] = 0xefcdab89; | ||
173 | s->h[2] = 0x98badcfe; | ||
174 | s->h[3] = 0x10325476; | ||
175 | } | ||
176 | |||
177 | static void MD5_Block(MD5_Core_State * s, uint32_t * block) | ||
178 | { | ||
179 | uint32_t a, b, c, d; | ||
180 | |||
181 | a = s->h[0]; | ||
182 | b = s->h[1]; | ||
183 | c = s->h[2]; | ||
184 | d = s->h[3]; | ||
185 | |||
186 | subround(F, a, b, c, d, 0, 7, 0xd76aa478); | ||
187 | subround(F, d, a, b, c, 1, 12, 0xe8c7b756); | ||
188 | subround(F, c, d, a, b, 2, 17, 0x242070db); | ||
189 | subround(F, b, c, d, a, 3, 22, 0xc1bdceee); | ||
190 | subround(F, a, b, c, d, 4, 7, 0xf57c0faf); | ||
191 | subround(F, d, a, b, c, 5, 12, 0x4787c62a); | ||
192 | subround(F, c, d, a, b, 6, 17, 0xa8304613); | ||
193 | subround(F, b, c, d, a, 7, 22, 0xfd469501); | ||
194 | subround(F, a, b, c, d, 8, 7, 0x698098d8); | ||
195 | subround(F, d, a, b, c, 9, 12, 0x8b44f7af); | ||
196 | subround(F, c, d, a, b, 10, 17, 0xffff5bb1); | ||
197 | subround(F, b, c, d, a, 11, 22, 0x895cd7be); | ||
198 | subround(F, a, b, c, d, 12, 7, 0x6b901122); | ||
199 | subround(F, d, a, b, c, 13, 12, 0xfd987193); | ||
200 | subround(F, c, d, a, b, 14, 17, 0xa679438e); | ||
201 | subround(F, b, c, d, a, 15, 22, 0x49b40821); | ||
202 | subround(G, a, b, c, d, 1, 5, 0xf61e2562); | ||
203 | subround(G, d, a, b, c, 6, 9, 0xc040b340); | ||
204 | subround(G, c, d, a, b, 11, 14, 0x265e5a51); | ||
205 | subround(G, b, c, d, a, 0, 20, 0xe9b6c7aa); | ||
206 | subround(G, a, b, c, d, 5, 5, 0xd62f105d); | ||
207 | subround(G, d, a, b, c, 10, 9, 0x02441453); | ||
208 | subround(G, c, d, a, b, 15, 14, 0xd8a1e681); | ||
209 | subround(G, b, c, d, a, 4, 20, 0xe7d3fbc8); | ||
210 | subround(G, a, b, c, d, 9, 5, 0x21e1cde6); | ||
211 | subround(G, d, a, b, c, 14, 9, 0xc33707d6); | ||
212 | subround(G, c, d, a, b, 3, 14, 0xf4d50d87); | ||
213 | subround(G, b, c, d, a, 8, 20, 0x455a14ed); | ||
214 | subround(G, a, b, c, d, 13, 5, 0xa9e3e905); | ||
215 | subround(G, d, a, b, c, 2, 9, 0xfcefa3f8); | ||
216 | subround(G, c, d, a, b, 7, 14, 0x676f02d9); | ||
217 | subround(G, b, c, d, a, 12, 20, 0x8d2a4c8a); | ||
218 | subround(H, a, b, c, d, 5, 4, 0xfffa3942); | ||
219 | subround(H, d, a, b, c, 8, 11, 0x8771f681); | ||
220 | subround(H, c, d, a, b, 11, 16, 0x6d9d6122); | ||
221 | subround(H, b, c, d, a, 14, 23, 0xfde5380c); | ||
222 | subround(H, a, b, c, d, 1, 4, 0xa4beea44); | ||
223 | subround(H, d, a, b, c, 4, 11, 0x4bdecfa9); | ||
224 | subround(H, c, d, a, b, 7, 16, 0xf6bb4b60); | ||
225 | subround(H, b, c, d, a, 10, 23, 0xbebfbc70); | ||
226 | subround(H, a, b, c, d, 13, 4, 0x289b7ec6); | ||
227 | subround(H, d, a, b, c, 0, 11, 0xeaa127fa); | ||
228 | subround(H, c, d, a, b, 3, 16, 0xd4ef3085); | ||
229 | subround(H, b, c, d, a, 6, 23, 0x04881d05); | ||
230 | subround(H, a, b, c, d, 9, 4, 0xd9d4d039); | ||
231 | subround(H, d, a, b, c, 12, 11, 0xe6db99e5); | ||
232 | subround(H, c, d, a, b, 15, 16, 0x1fa27cf8); | ||
233 | subround(H, b, c, d, a, 2, 23, 0xc4ac5665); | ||
234 | subround(I, a, b, c, d, 0, 6, 0xf4292244); | ||
235 | subround(I, d, a, b, c, 7, 10, 0x432aff97); | ||
236 | subround(I, c, d, a, b, 14, 15, 0xab9423a7); | ||
237 | subround(I, b, c, d, a, 5, 21, 0xfc93a039); | ||
238 | subround(I, a, b, c, d, 12, 6, 0x655b59c3); | ||
239 | subround(I, d, a, b, c, 3, 10, 0x8f0ccc92); | ||
240 | subround(I, c, d, a, b, 10, 15, 0xffeff47d); | ||
241 | subround(I, b, c, d, a, 1, 21, 0x85845dd1); | ||
242 | subround(I, a, b, c, d, 8, 6, 0x6fa87e4f); | ||
243 | subround(I, d, a, b, c, 15, 10, 0xfe2ce6e0); | ||
244 | subround(I, c, d, a, b, 6, 15, 0xa3014314); | ||
245 | subround(I, b, c, d, a, 13, 21, 0x4e0811a1); | ||
246 | subround(I, a, b, c, d, 4, 6, 0xf7537e82); | ||
247 | subround(I, d, a, b, c, 11, 10, 0xbd3af235); | ||
248 | subround(I, c, d, a, b, 2, 15, 0x2ad7d2bb); | ||
249 | subround(I, b, c, d, a, 9, 21, 0xeb86d391); | ||
250 | |||
251 | s->h[0] += a; | ||
252 | s->h[1] += b; | ||
253 | s->h[2] += c; | ||
254 | s->h[3] += d; | ||
255 | } | ||
256 | |||
257 | /* ---------------------------------------------------------------------- | ||
258 | * Outer MD5 algorithm: take an arbitrary length byte string, | ||
259 | * convert it into 16-word blocks with the prescribed padding at | ||
260 | * the end, and pass those blocks to the core MD5 algorithm. | ||
261 | */ | ||
262 | |||
263 | #define BLKSIZE 64 | ||
264 | |||
265 | void MD5Init(struct MD5Context *s) | ||
266 | { | ||
267 | MD5_Core_Init(&s->core); | ||
268 | s->blkused = 0; | ||
269 | s->lenhi = s->lenlo = 0; | ||
270 | } | ||
271 | |||
272 | void MD5Update(struct MD5Context *s, unsigned char const *p, unsigned len) | ||
273 | { | ||
274 | unsigned char *q = (unsigned char *) p; | ||
275 | uint32_t wordblock[16]; | ||
276 | uint32_t lenw = len; | ||
277 | int i; | ||
278 | |||
279 | /* | ||
280 | * Update the length field. | ||
281 | */ | ||
282 | s->lenlo += lenw; | ||
283 | s->lenhi += (s->lenlo < lenw); | ||
284 | |||
285 | if (s->blkused + len < BLKSIZE) { | ||
286 | /* | ||
287 | * Trivial case: just add to the block. | ||
288 | */ | ||
289 | memcpy(s->block + s->blkused, q, len); | ||
290 | s->blkused += len; | ||
291 | } else { | ||
292 | /* | ||
293 | * We must complete and process at least one block. | ||
294 | */ | ||
295 | while (s->blkused + len >= BLKSIZE) { | ||
296 | memcpy(s->block + s->blkused, q, BLKSIZE - s->blkused); | ||
297 | q += BLKSIZE - s->blkused; | ||
298 | len -= BLKSIZE - s->blkused; | ||
299 | /* Now process the block. Gather bytes little-endian into words */ | ||
300 | for (i = 0; i < 16; i++) { | ||
301 | wordblock[i] = | ||
302 | (((uint32_t) s->block[i * 4 + 3]) << 24) | | ||
303 | (((uint32_t) s->block[i * 4 + 2]) << 16) | | ||
304 | (((uint32_t) s->block[i * 4 + 1]) << 8) | | ||
305 | (((uint32_t) s->block[i * 4 + 0]) << 0); | ||
306 | } | ||
307 | MD5_Block(&s->core, wordblock); | ||
308 | s->blkused = 0; | ||
309 | } | ||
310 | memcpy(s->block, q, len); | ||
311 | s->blkused = len; | ||
312 | } | ||
313 | } | ||
314 | |||
315 | void MD5Final(uint32_t output[4], struct MD5Context *s) | ||
316 | { | ||
317 | int i; | ||
318 | unsigned pad; | ||
319 | unsigned char c[64]; | ||
320 | uint32_t lenhi, lenlo; | ||
321 | |||
322 | if (s->blkused >= 56) | ||
323 | pad = 56 + 64 - s->blkused; | ||
324 | else | ||
325 | pad = 56 - s->blkused; | ||
326 | |||
327 | lenhi = (s->lenhi << 3) | (s->lenlo >> (32 - 3)); | ||
328 | lenlo = (s->lenlo << 3); | ||
329 | |||
330 | memset(c, 0, pad); | ||
331 | c[0] = 0x80; | ||
332 | MD5Update(s, c, pad); | ||
333 | |||
334 | c[7] = (lenhi >> 24) & 0xFF; | ||
335 | c[6] = (lenhi >> 16) & 0xFF; | ||
336 | c[5] = (lenhi >> 8) & 0xFF; | ||
337 | c[4] = (lenhi >> 0) & 0xFF; | ||
338 | c[3] = (lenlo >> 24) & 0xFF; | ||
339 | c[2] = (lenlo >> 16) & 0xFF; | ||
340 | c[1] = (lenlo >> 8) & 0xFF; | ||
341 | c[0] = (lenlo >> 0) & 0xFF; | ||
342 | |||
343 | MD5Update(s, c, 8); | ||
344 | |||
345 | for (i = 0; i < 4; i++) | ||
346 | output[i] = s->core.h[i]; | ||
347 | } | ||
348 | |||
349 | void MD5Simple(void const *p, unsigned len, uint32_t output[4]) | ||
350 | { | ||
351 | struct MD5Context s; | ||
352 | |||
353 | MD5Init(&s); | ||
354 | MD5Update(&s, (unsigned char const *)p, len); | ||
355 | MD5Final(output, &s); | ||
356 | } | ||
@@ -6,6 +6,7 @@ void *smalloc(size_t size); | |||
6 | void *srealloc(void *ptr, size_t size); | 6 | void *srealloc(void *ptr, size_t size); |
7 | char *dupcat(const char *str, ...); | 7 | char *dupcat(const char *str, ...); |
8 | unsigned le(const unsigned char *buf, size_t len, size_t off, size_t nbytes); | 8 | unsigned le(const unsigned char *buf, size_t len, size_t off, size_t nbytes); |
9 | void MD5Simple(void const *p, unsigned len, uint32_t output[4]); | ||
9 | 10 | ||
10 | #define snew(type) ((type *)smalloc(sizeof(type))) | 11 | #define snew(type) ((type *)smalloc(sizeof(type))) |
11 | #define snewn(n,type) ((type *)smalloc((n)*sizeof(type))) | 12 | #define snewn(n,type) ((type *)smalloc((n)*sizeof(type))) |
@@ -193,6 +193,44 @@ uint32_t MsiGetFileVersionW(const char16_t *filename, | |||
193 | sfree(fname); | 193 | sfree(fname); |
194 | return toret; | 194 | return toret; |
195 | } | 195 | } |
196 | |||
197 | struct MsiHash { | ||
198 | uint32_t structure_size; | ||
199 | uint32_t hash_words[4]; | ||
200 | }; | ||
201 | |||
202 | uint32_t MsiGetFileHashW(const char16_t *filename, uint32_t options, | ||
203 | struct MsiHash *hash) | ||
204 | { | ||
205 | char *fname = ascii(filename, true); | ||
206 | int fd = -1; | ||
207 | void *mapv = MAP_FAILED; | ||
208 | uint32_t toret; | ||
209 | |||
210 | fd = open(fname, O_RDONLY); | ||
211 | if (fd < 0) | ||
212 | err(1, "%s: open", fname); | ||
213 | struct stat st; | ||
214 | if (fstat(fd, &st) < 0) | ||
215 | err(1, "%s: fstat", fname); | ||
216 | size_t fsize = st.st_size; | ||
217 | mapv = mmap(NULL, fsize, PROT_READ, MAP_PRIVATE, fd, 0); | ||
218 | if (mapv == MAP_FAILED) | ||
219 | err(1, "%s: mmap", fname); | ||
220 | |||
221 | MD5Simple(mapv, fsize, hash->hash_words); | ||
222 | warnx("MsiGetFileHash(%s) -> %08x:%08x:%08x:%08x", fname, | ||
223 | (unsigned)hash->hash_words[0], (unsigned)hash->hash_words[1], | ||
224 | (unsigned)hash->hash_words[2], (unsigned)hash->hash_words[3]); | ||
225 | toret = 0; | ||
226 | |||
227 | cleanup: | ||
228 | if (mapv != MAP_FAILED) | ||
229 | munmap(mapv, fsize); | ||
230 | if (fd != -1) | ||
231 | close(fd); | ||
232 | sfree(fname); | ||
233 | return toret; | ||
196 | } | 234 | } |
197 | 235 | ||
198 | typedef struct MsiTypePrefix { | 236 | typedef struct MsiTypePrefix { |