blob: c0294f4cd49a732e45288e409edfe309596b8798 [file] [log] [blame]
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001/* md5sum.c - Compute MD5 checksum of files or strings according to the
2 * definition of MD5 in RFC 1321 from April 1992.
3 * Copyright (C) 1995-1999 Free Software Foundation, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu> */
21/* Hacked to work with BusyBox by Alfred M. Szmidt <ams@trillian.itslinux.org> */
22
Eric Andersendb15cb72001-06-29 20:44:51 +000023/*
24 * June 29, 2001 Manuel Novoa III
25 *
26 * Added MD5SUM_SIZE_VS_SPEED configuration option.
27 *
28 * Current valid values, with data from my system for comparison, are:
29 * (using uClibc and running on linux-2.4.4.tar.bz2)
30 * user times (sec) text size (386)
31 * 0 (fastest) 1.1 6144
32 * 1 1.4 5392
33 * 2 3.0 5088
34 * 3 (smallest) 5.1 4912
35 */
36
37#define MD5SUM_SIZE_VS_SPEED 2
38
39/**********************************************************************/
40
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000041#include <stdio.h>
42#include <errno.h>
43#include <ctype.h>
Eric Andersen999bf722000-07-09 06:59:58 +000044#include <getopt.h>
Eric Andersene0c07572001-06-23 13:49:14 +000045#include <stdlib.h>
46#include <string.h>
47#include <endian.h>
48#include <sys/types.h>
49#if defined HAVE_LIMITS_H
50# include <limits.h>
51#endif
Eric Andersencbe31da2001-02-20 06:14:08 +000052#include "busybox.h"
Eric Andersen999bf722000-07-09 06:59:58 +000053
Eric Andersene111d692000-12-20 23:19:42 +000054/* For some silly reason, this file uses backwards TRUE and FALSE conventions */
55#undef TRUE
56#undef FALSE
57#define FALSE ((int) 1)
58#define TRUE ((int) 0)
59
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000060//----------------------------------------------------------------------------
61//--------md5.c
62//----------------------------------------------------------------------------
63
64/* md5.c - Functions to compute MD5 message digest of files or memory blocks
65 * according to the definition of MD5 in RFC 1321 from April 1992.
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000066 */
67
68/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */
69
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000070//----------------------------------------------------------------------------
71//--------md5.h
72//----------------------------------------------------------------------------
73
74/* md5.h - Declaration of functions and data types used for MD5 sum
Eric Andersen55522082001-07-10 16:31:29 +000075 computing library functions. */
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000076
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000077typedef u_int32_t md5_uint32;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000078
79/* Structure to save state of computation between the single steps. */
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +000080struct md5_ctx {
81 md5_uint32 A;
82 md5_uint32 B;
83 md5_uint32 C;
84 md5_uint32 D;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000085
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +000086 md5_uint32 total[2];
87 md5_uint32 buflen;
88 char buffer[128];
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000089};
90
91/*
92 * The following three functions are build up the low level used in
93 * the functions `md5_stream' and `md5_buffer'.
94 */
95
96/* Initialize structure containing state of computation.
97 (RFC 1321, 3.3: Step 3) */
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +000098static void md5_init_ctx __P((struct md5_ctx * ctx));
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000099
100/* Starting with the result of former calls of this function (or the
101 initialization function update the context for the next LEN bytes
102 starting at BUFFER.
103 It is necessary that LEN is a multiple of 64!!! */
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000104static void md5_process_block __P((const void *buffer, size_t len,
105 struct md5_ctx * ctx));
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000106
107/* Starting with the result of former calls of this function (or the
108 initialization function update the context for the next LEN bytes
109 starting at BUFFER.
110 It is NOT required that LEN is a multiple of 64. */
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000111static void md5_process_bytes __P((const void *buffer, size_t len,
112 struct md5_ctx * ctx));
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000113
114/* Process the remaining bytes in the buffer and put result from CTX
115 in first 16 bytes following RESBUF. The result is always in little
116 endian byte order, so that a byte-wise output yields to the wanted
117 ASCII representation of the message digest.
118
119 IMPORTANT: On some systems it is required that RESBUF is correctly
120 aligned for a 32 bits value. */
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000121static void *md5_finish_ctx __P((struct md5_ctx * ctx, void *resbuf));
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000122
123
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000124
125
126/* Compute MD5 message digest for bytes read from STREAM. The
127 resulting message digest number will be written into the 16 bytes
128 beginning at RESBLOCK. */
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000129static int md5_stream __P((FILE * stream, void *resblock));
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000130
131/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
132 result is always in little endian byte order, so that a byte-wise
133 output yields to the wanted ASCII representation of the message
134 digest. */
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000135static void *md5_buffer __P((const char *buffer, size_t len, void *resblock));
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000136
137//----------------------------------------------------------------------------
138//--------end of md5.h
139//----------------------------------------------------------------------------
140
Eric Andersen4a2e4632001-04-14 03:33:33 +0000141/* Handle endian-ness */
142#if __BYTE_ORDER == __LITTLE_ENDIAN
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000143#define SWAP(n) (n)
Eric Andersen4a2e4632001-04-14 03:33:33 +0000144#else
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000145#define SWAP(n) ((n << 24) | ((n&65280)<<8) | ((n&16711680)>>8) | (n>>24))
Eric Andersen4a2e4632001-04-14 03:33:33 +0000146#endif
147
148
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000149
Eric Andersendb15cb72001-06-29 20:44:51 +0000150#if MD5SUM_SIZE_VS_SPEED == 0
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000151/* This array contains the bytes used to pad the buffer to the next
152 64-byte boundary. (RFC 1321, 3.1: Step 1) */
153static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
Eric Andersendb15cb72001-06-29 20:44:51 +0000154#endif
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000155
156/* Initialize structure containing state of computation.
157 (RFC 1321, 3.3: Step 3) */
158void md5_init_ctx(struct md5_ctx *ctx)
159{
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000160 ctx->A = 0x67452301;
161 ctx->B = 0xefcdab89;
162 ctx->C = 0x98badcfe;
163 ctx->D = 0x10325476;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000164
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000165 ctx->total[0] = ctx->total[1] = 0;
166 ctx->buflen = 0;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000167}
168
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000169/* Process the remaining bytes in the internal buffer and the usual
170 prolog according to the standard and write the result to RESBUF.
171
172 IMPORTANT: On some systems it is required that RESBUF is correctly
173 aligned for a 32 bits value. */
Eric Andersen55522082001-07-10 16:31:29 +0000174static void *md5_finish_ctx(struct md5_ctx *ctx, void *resbuf)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000175{
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000176 /* Take yet unprocessed bytes into account. */
177 md5_uint32 bytes = ctx->buflen;
178 size_t pad;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000179
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000180 /* Now count remaining bytes. */
181 ctx->total[0] += bytes;
182 if (ctx->total[0] < bytes)
183 ++ctx->total[1];
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000184
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000185 pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
Eric Andersendb15cb72001-06-29 20:44:51 +0000186#if MD5SUM_SIZE_VS_SPEED > 0
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000187 memset(&ctx->buffer[bytes], 0, pad);
188 ctx->buffer[bytes] = 0x80;
Eric Andersendb15cb72001-06-29 20:44:51 +0000189#else
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000190 memcpy(&ctx->buffer[bytes], fillbuf, pad);
Eric Andersendb15cb72001-06-29 20:44:51 +0000191#endif
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000192
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000193 /* Put the 64-bit file length in *bits* at the end of the buffer. */
194 *(md5_uint32 *) & ctx->buffer[bytes + pad] = SWAP(ctx->total[0] << 3);
195 *(md5_uint32 *) & ctx->buffer[bytes + pad + 4] =
196 SWAP(((ctx->total[1] << 3) | (ctx->total[0] >> 29)));
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000197
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000198 /* Process last bytes. */
199 md5_process_block(ctx->buffer, bytes + pad + 8, ctx);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000200
Eric Andersen55522082001-07-10 16:31:29 +0000201/* Put result from CTX in first 16 bytes following RESBUF. The result is
202 always in little endian byte order, so that a byte-wise output yields
203 to the wanted ASCII representation of the message digest.
204
205 IMPORTANT: On some systems it is required that RESBUF is correctly
206 aligned for a 32 bits value. */
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000207 ((md5_uint32 *) resbuf)[0] = SWAP(ctx->A);
208 ((md5_uint32 *) resbuf)[1] = SWAP(ctx->B);
209 ((md5_uint32 *) resbuf)[2] = SWAP(ctx->C);
210 ((md5_uint32 *) resbuf)[3] = SWAP(ctx->D);
Eric Andersen55522082001-07-10 16:31:29 +0000211
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000212 return resbuf;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000213}
214
215/* Compute MD5 message digest for bytes read from STREAM. The
216 resulting message digest number will be written into the 16 bytes
217 beginning at RESBLOCK. */
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000218static int md5_stream(FILE * stream, void *resblock)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000219{
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000220 /* Important: BLOCKSIZE must be a multiple of 64. */
221 static const int BLOCKSIZE = 4096;
222 struct md5_ctx ctx;
223 char buffer[BLOCKSIZE + 72];
224 size_t sum;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000225
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000226 /* Initialize the computation context. */
227 md5_init_ctx(&ctx);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000228
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000229 /* Iterate over full file contents. */
230 while (1) {
231 /* We read the file in blocks of BLOCKSIZE bytes. One call of the
232 computation function processes the whole buffer so that with the
233 next round of the loop another block can be read. */
234 size_t n;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000235
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000236 sum = 0;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000237
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000238 /* Read block. Take care for partial reads. */
239 do {
240 n = fread(buffer + sum, 1, BLOCKSIZE - sum, stream);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000241
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000242 sum += n;
243 }
244 while (sum < BLOCKSIZE && n != 0);
245 if (n == 0 && ferror(stream))
246 return 1;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000247
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000248 /* If end of file is reached, end the loop. */
249 if (n == 0)
250 break;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000251
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000252 /* Process buffer with BLOCKSIZE bytes. Note that
253 BLOCKSIZE % 64 == 0
254 */
255 md5_process_block(buffer, BLOCKSIZE, &ctx);
256 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000257
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000258 /* Add the last bytes if necessary. */
259 if (sum > 0)
260 md5_process_bytes(buffer, sum, &ctx);
261
262 /* Construct result in desired memory. */
263 md5_finish_ctx(&ctx, resblock);
264 return 0;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000265}
266
267/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
268 result is always in little endian byte order, so that a byte-wise
269 output yields to the wanted ASCII representation of the message
270 digest. */
Eric Andersen55522082001-07-10 16:31:29 +0000271static void *md5_buffer(const char *buffer, size_t len, void *resblock)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000272{
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000273 struct md5_ctx ctx;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000274
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000275 /* Initialize the computation context. */
276 md5_init_ctx(&ctx);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000277
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000278 /* Process whole buffer but last len % 64 bytes. */
279 md5_process_bytes(buffer, len, &ctx);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000280
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000281 /* Put result in desired memory area. */
282 return md5_finish_ctx(&ctx, resblock);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000283}
284
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000285static void md5_process_bytes(const void *buffer, size_t len,
286 struct md5_ctx *ctx)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000287{
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000288 /* When we already have some bits in our internal buffer concatenate
289 both inputs first. */
290 if (ctx->buflen != 0) {
291 size_t left_over = ctx->buflen;
292 size_t add = 128 - left_over > len ? len : 128 - left_over;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000293
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000294 memcpy(&ctx->buffer[left_over], buffer, add);
295 ctx->buflen += add;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000296
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000297 if (left_over + add > 64) {
298 md5_process_block(ctx->buffer, (left_over + add) & ~63, ctx);
299 /* The regions in the following copy operation cannot overlap. */
300 memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
301 (left_over + add) & 63);
302 ctx->buflen = (left_over + add) & 63;
303 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000304
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000305 buffer = (const char *) buffer + add;
306 len -= add;
307 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000308
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000309 /* Process available complete blocks. */
310 if (len > 64) {
311 md5_process_block(buffer, len & ~63, ctx);
312 buffer = (const char *) buffer + (len & ~63);
313 len &= 63;
314 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000315
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000316 /* Move remaining bytes in internal buffer. */
317 if (len > 0) {
318 memcpy(ctx->buffer, buffer, len);
319 ctx->buflen = len;
320 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000321}
322
323/* These are the four functions used in the four steps of the MD5 algorithm
324 and defined in the RFC 1321. The first function is a little bit optimized
325 (as found in Colin Plumbs public domain implementation). */
326/* #define FF(b, c, d) ((b & c) | (~b & d)) */
327#define FF(b, c, d) (d ^ (b & (c ^ d)))
328#define FG(b, c, d) FF (d, b, c)
329#define FH(b, c, d) (b ^ c ^ d)
330#define FI(b, c, d) (c ^ (b | ~d))
331
332/* Process LEN bytes of BUFFER, accumulating context into CTX.
333 It is assumed that LEN % 64 == 0. */
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000334static void md5_process_block(const void *buffer, size_t len,
335 struct md5_ctx *ctx)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000336{
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000337 md5_uint32 correct_words[16];
338 const md5_uint32 *words = buffer;
339 size_t nwords = len / sizeof(md5_uint32);
340 const md5_uint32 *endp = words + nwords;
341
Eric Andersendb15cb72001-06-29 20:44:51 +0000342#if MD5SUM_SIZE_VS_SPEED > 0
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000343 static const md5_uint32 C_array[] = {
344 /* round 1 */
345 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
346 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
347 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
348 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
349 /* round 2 */
350 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
351 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8,
352 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
353 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
354 /* round 3 */
355 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
356 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
357 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
358 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
359 /* round 4 */
360 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
361 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
362 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
363 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
364 };
Eric Andersendb15cb72001-06-29 20:44:51 +0000365
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000366 static const char P_array[] = {
Eric Andersendb15cb72001-06-29 20:44:51 +0000367#if MD5SUM_SIZE_VS_SPEED > 1
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000368 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
Eric Andersendb15cb72001-06-29 20:44:51 +0000369#endif
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000370 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
371 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
372 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */
373 };
Eric Andersendb15cb72001-06-29 20:44:51 +0000374
375#if MD5SUM_SIZE_VS_SPEED > 1
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000376 static const char S_array[] = {
377 7, 12, 17, 22,
378 5, 9, 14, 20,
379 4, 11, 16, 23,
380 6, 10, 15, 21
381 };
Eric Andersendb15cb72001-06-29 20:44:51 +0000382#endif
383#endif
384
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000385 md5_uint32 A = ctx->A;
386 md5_uint32 B = ctx->B;
387 md5_uint32 C = ctx->C;
388 md5_uint32 D = ctx->D;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000389
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000390 /* First increment the byte count. RFC 1321 specifies the possible
391 length of the file up to 2^64 bits. Here we only compute the
392 number of bytes. Do a double word increment. */
393 ctx->total[0] += len;
394 if (ctx->total[0] < len)
395 ++ctx->total[1];
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000396
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000397 /* Process all bytes in the buffer with 64 bytes in each round of
398 the loop. */
399 while (words < endp) {
400 md5_uint32 *cwp = correct_words;
401 md5_uint32 A_save = A;
402 md5_uint32 B_save = B;
403 md5_uint32 C_save = C;
404 md5_uint32 D_save = D;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000405
Eric Andersendb15cb72001-06-29 20:44:51 +0000406#if MD5SUM_SIZE_VS_SPEED > 1
407#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
408
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000409 const md5_uint32 *pc;
410 const char *pp;
411 const char *ps;
412 int i;
413 md5_uint32 temp;
Eric Andersendb15cb72001-06-29 20:44:51 +0000414
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000415 for (i = 0; i < 16; i++) {
416 cwp[i] = SWAP(words[i]);
417 }
418 words += 16;
Eric Andersendb15cb72001-06-29 20:44:51 +0000419
420#if MD5SUM_SIZE_VS_SPEED > 2
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000421 pc = C_array;
422 pp = P_array;
423 ps = S_array - 4;
Eric Andersendb15cb72001-06-29 20:44:51 +0000424
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000425 for (i = 0; i < 64; i++) {
426 if ((i & 0x0f) == 0)
427 ps += 4;
428 temp = A;
429 switch (i >> 4) {
430 case 0:
431 temp += FF(B, C, D);
432 break;
433 case 1:
434 temp += FG(B, C, D);
435 break;
436 case 2:
437 temp += FH(B, C, D);
438 break;
439 case 3:
440 temp += FI(B, C, D);
441 }
442 temp += cwp[(int) (*pp++)] + *pc++;
443 CYCLIC(temp, ps[i & 3]);
444 temp += B;
445 A = D;
446 D = C;
447 C = B;
448 B = temp;
449 }
Eric Andersendb15cb72001-06-29 20:44:51 +0000450#else
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000451 pc = C_array;
452 pp = P_array;
453 ps = S_array;
Eric Andersendb15cb72001-06-29 20:44:51 +0000454
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000455 for (i = 0; i < 16; i++) {
456 temp = A + FF(B, C, D) + cwp[(int) (*pp++)] + *pc++;
457 CYCLIC(temp, ps[i & 3]);
458 temp += B;
459 A = D;
460 D = C;
461 C = B;
462 B = temp;
463 }
Eric Andersendb15cb72001-06-29 20:44:51 +0000464
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000465 ps += 4;
466 for (i = 0; i < 16; i++) {
467 temp = A + FG(B, C, D) + cwp[(int) (*pp++)] + *pc++;
468 CYCLIC(temp, ps[i & 3]);
469 temp += B;
470 A = D;
471 D = C;
472 C = B;
473 B = temp;
474 }
475 ps += 4;
476 for (i = 0; i < 16; i++) {
477 temp = A + FH(B, C, D) + cwp[(int) (*pp++)] + *pc++;
478 CYCLIC(temp, ps[i & 3]);
479 temp += B;
480 A = D;
481 D = C;
482 C = B;
483 B = temp;
484 }
485 ps += 4;
486 for (i = 0; i < 16; i++) {
487 temp = A + FI(B, C, D) + cwp[(int) (*pp++)] + *pc++;
488 CYCLIC(temp, ps[i & 3]);
489 temp += B;
490 A = D;
491 D = C;
492 C = B;
493 B = temp;
494 }
Eric Andersendb15cb72001-06-29 20:44:51 +0000495
496#endif
497#else
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000498 /* First round: using the given function, the context and a constant
499 the next context is computed. Because the algorithms processing
500 unit is a 32-bit word and it is determined to work on words in
501 little endian byte order we perhaps have to change the byte order
502 before the computation. To reduce the work for the next steps
503 we store the swapped words in the array CORRECT_WORDS. */
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000504
505#define OP(a, b, c, d, s, T) \
506 do \
507 { \
508 a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \
509 ++words; \
510 CYCLIC (a, s); \
511 a += b; \
512 } \
513 while (0)
514
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000515 /* It is unfortunate that C does not provide an operator for
516 cyclic rotation. Hope the C compiler is smart enough. */
517 /* gcc 2.95.4 seems to be --aaronl */
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000518#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
519
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000520 /* Before we start, one word to the strange constants.
521 They are defined in RFC 1321 as
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000522
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000523 T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
524 */
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000525
Eric Andersendb15cb72001-06-29 20:44:51 +0000526#if MD5SUM_SIZE_VS_SPEED == 1
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000527 const md5_uint32 *pc;
528 const char *pp;
529 int i;
Eric Andersendb15cb72001-06-29 20:44:51 +0000530#endif
531
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000532 /* Round 1. */
Eric Andersendb15cb72001-06-29 20:44:51 +0000533#if MD5SUM_SIZE_VS_SPEED == 1
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000534 pc = C_array;
535 for (i = 0; i < 4; i++) {
536 OP(A, B, C, D, 7, *pc++);
537 OP(D, A, B, C, 12, *pc++);
538 OP(C, D, A, B, 17, *pc++);
539 OP(B, C, D, A, 22, *pc++);
540 }
Eric Andersendb15cb72001-06-29 20:44:51 +0000541#else
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000542 OP(A, B, C, D, 7, 0xd76aa478);
543 OP(D, A, B, C, 12, 0xe8c7b756);
544 OP(C, D, A, B, 17, 0x242070db);
545 OP(B, C, D, A, 22, 0xc1bdceee);
546 OP(A, B, C, D, 7, 0xf57c0faf);
547 OP(D, A, B, C, 12, 0x4787c62a);
548 OP(C, D, A, B, 17, 0xa8304613);
549 OP(B, C, D, A, 22, 0xfd469501);
550 OP(A, B, C, D, 7, 0x698098d8);
551 OP(D, A, B, C, 12, 0x8b44f7af);
552 OP(C, D, A, B, 17, 0xffff5bb1);
553 OP(B, C, D, A, 22, 0x895cd7be);
554 OP(A, B, C, D, 7, 0x6b901122);
555 OP(D, A, B, C, 12, 0xfd987193);
556 OP(C, D, A, B, 17, 0xa679438e);
557 OP(B, C, D, A, 22, 0x49b40821);
Eric Andersendb15cb72001-06-29 20:44:51 +0000558#endif
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000559
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000560 /* For the second to fourth round we have the possibly swapped words
561 in CORRECT_WORDS. Redefine the macro to take an additional first
562 argument specifying the function to use. */
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000563#undef OP
564#define OP(f, a, b, c, d, k, s, T) \
565 do \
566 { \
567 a += f (b, c, d) + correct_words[k] + T; \
568 CYCLIC (a, s); \
569 a += b; \
570 } \
571 while (0)
572
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000573 /* Round 2. */
Eric Andersendb15cb72001-06-29 20:44:51 +0000574#if MD5SUM_SIZE_VS_SPEED == 1
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000575 pp = P_array;
576 for (i = 0; i < 4; i++) {
577 OP(FG, A, B, C, D, (int) (*pp++), 5, *pc++);
578 OP(FG, D, A, B, C, (int) (*pp++), 9, *pc++);
579 OP(FG, C, D, A, B, (int) (*pp++), 14, *pc++);
580 OP(FG, B, C, D, A, (int) (*pp++), 20, *pc++);
581 }
Eric Andersendb15cb72001-06-29 20:44:51 +0000582#else
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000583 OP(FG, A, B, C, D, 1, 5, 0xf61e2562);
584 OP(FG, D, A, B, C, 6, 9, 0xc040b340);
585 OP(FG, C, D, A, B, 11, 14, 0x265e5a51);
586 OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
587 OP(FG, A, B, C, D, 5, 5, 0xd62f105d);
588 OP(FG, D, A, B, C, 10, 9, 0x02441453);
589 OP(FG, C, D, A, B, 15, 14, 0xd8a1e681);
590 OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
591 OP(FG, A, B, C, D, 9, 5, 0x21e1cde6);
592 OP(FG, D, A, B, C, 14, 9, 0xc33707d6);
593 OP(FG, C, D, A, B, 3, 14, 0xf4d50d87);
594 OP(FG, B, C, D, A, 8, 20, 0x455a14ed);
595 OP(FG, A, B, C, D, 13, 5, 0xa9e3e905);
596 OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8);
597 OP(FG, C, D, A, B, 7, 14, 0x676f02d9);
598 OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
Eric Andersendb15cb72001-06-29 20:44:51 +0000599#endif
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000600
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000601 /* Round 3. */
Eric Andersendb15cb72001-06-29 20:44:51 +0000602#if MD5SUM_SIZE_VS_SPEED == 1
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000603 for (i = 0; i < 4; i++) {
604 OP(FH, A, B, C, D, (int) (*pp++), 4, *pc++);
605 OP(FH, D, A, B, C, (int) (*pp++), 11, *pc++);
606 OP(FH, C, D, A, B, (int) (*pp++), 16, *pc++);
607 OP(FH, B, C, D, A, (int) (*pp++), 23, *pc++);
608 }
Eric Andersendb15cb72001-06-29 20:44:51 +0000609#else
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000610 OP(FH, A, B, C, D, 5, 4, 0xfffa3942);
611 OP(FH, D, A, B, C, 8, 11, 0x8771f681);
612 OP(FH, C, D, A, B, 11, 16, 0x6d9d6122);
613 OP(FH, B, C, D, A, 14, 23, 0xfde5380c);
614 OP(FH, A, B, C, D, 1, 4, 0xa4beea44);
615 OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9);
616 OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60);
617 OP(FH, B, C, D, A, 10, 23, 0xbebfbc70);
618 OP(FH, A, B, C, D, 13, 4, 0x289b7ec6);
619 OP(FH, D, A, B, C, 0, 11, 0xeaa127fa);
620 OP(FH, C, D, A, B, 3, 16, 0xd4ef3085);
621 OP(FH, B, C, D, A, 6, 23, 0x04881d05);
622 OP(FH, A, B, C, D, 9, 4, 0xd9d4d039);
623 OP(FH, D, A, B, C, 12, 11, 0xe6db99e5);
624 OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8);
625 OP(FH, B, C, D, A, 2, 23, 0xc4ac5665);
Eric Andersendb15cb72001-06-29 20:44:51 +0000626#endif
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000627
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000628 /* Round 4. */
Eric Andersendb15cb72001-06-29 20:44:51 +0000629#if MD5SUM_SIZE_VS_SPEED == 1
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000630 for (i = 0; i < 4; i++) {
631 OP(FI, A, B, C, D, (int) (*pp++), 6, *pc++);
632 OP(FI, D, A, B, C, (int) (*pp++), 10, *pc++);
633 OP(FI, C, D, A, B, (int) (*pp++), 15, *pc++);
634 OP(FI, B, C, D, A, (int) (*pp++), 21, *pc++);
635 }
Eric Andersendb15cb72001-06-29 20:44:51 +0000636#else
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000637 OP(FI, A, B, C, D, 0, 6, 0xf4292244);
638 OP(FI, D, A, B, C, 7, 10, 0x432aff97);
639 OP(FI, C, D, A, B, 14, 15, 0xab9423a7);
640 OP(FI, B, C, D, A, 5, 21, 0xfc93a039);
641 OP(FI, A, B, C, D, 12, 6, 0x655b59c3);
642 OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92);
643 OP(FI, C, D, A, B, 10, 15, 0xffeff47d);
644 OP(FI, B, C, D, A, 1, 21, 0x85845dd1);
645 OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f);
646 OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
647 OP(FI, C, D, A, B, 6, 15, 0xa3014314);
648 OP(FI, B, C, D, A, 13, 21, 0x4e0811a1);
649 OP(FI, A, B, C, D, 4, 6, 0xf7537e82);
650 OP(FI, D, A, B, C, 11, 10, 0xbd3af235);
651 OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
652 OP(FI, B, C, D, A, 9, 21, 0xeb86d391);
Eric Andersendb15cb72001-06-29 20:44:51 +0000653#endif
654#endif
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000655
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000656 /* Add the starting values of the context. */
657 A += A_save;
658 B += B_save;
659 C += C_save;
660 D += D_save;
661 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000662
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000663 /* Put checksum in context given as argument. */
664 ctx->A = A;
665 ctx->B = B;
666 ctx->C = C;
667 ctx->D = D;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000668}
669
670//----------------------------------------------------------------------------
671//--------end of md5.c
672//----------------------------------------------------------------------------
673
674#define ISWHITE(c) ((c) == ' ' || (c) == '\t')
Eric Andersen55522082001-07-10 16:31:29 +0000675#define ISXDIGIT(c) (isxdigit (c))
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000676
677/* The minimum length of a valid digest line in a file produced
678 by `md5sum FILE' and read by `md5sum -c'. This length does
679 not include any newline character at the end of a line. */
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000680static const int MIN_DIGEST_LINE_LENGTH = 35; /* 32 - message digest length
681 2 - blank and binary indicator
682 1 - minimum filename length */
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000683
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000684static int have_read_stdin; /* Nonzero if any of the files read were
685 the standard input. */
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000686
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000687static int status_only = 0; /* With -c, don't generate any output.
688 The exit code indicates success or failure */
689static int warn = 0; /* With -w, print a message to standard error warning
690 about each improperly formatted MD5 checksum line */
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000691
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000692static int split_3(char *s, size_t s_len, unsigned char **u, char **w)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000693{
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000694 size_t i = 0;
695 int escaped_filename = 0;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000696
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000697 while (ISWHITE(s[i]))
698 ++i;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000699
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000700 /* The line must have at least 35 (36 if the first is a backslash)
701 more characters to contain correct message digest information.
702 Ignore this line if it is too short. */
703 if (!(s_len - i >= MIN_DIGEST_LINE_LENGTH
704 || (s[i] == '\\' && s_len - i >= 1 + MIN_DIGEST_LINE_LENGTH)))
705 return FALSE;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000706
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000707 if (s[i] == '\\') {
708 ++i;
709 escaped_filename = 1;
710 }
711 *u = (unsigned char *) &s[i];
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000712
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000713 /* The first field has to be the 32-character hexadecimal
714 representation of the message digest. If it is not followed
715 immediately by a white space it's an error. */
716 i += 32;
717 if (!ISWHITE(s[i]))
718 return FALSE;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000719
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000720 s[i++] = '\0';
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000721
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000722 if (s[i] != ' ' && s[i] != '*')
723 return FALSE;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000724
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000725 /* All characters between the type indicator and end of line are
726 significant -- that includes leading and trailing white space. */
727 *w = &s[++i];
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000728
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000729 if (escaped_filename) {
730 /* Translate each `\n' string in the file name to a NEWLINE,
731 and each `\\' string to a backslash. */
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000732
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000733 char *dst = &s[i];
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000734
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000735 while (i < s_len) {
736 switch (s[i]) {
737 case '\\':
738 if (i == s_len - 1) {
739 /* A valid line does not end with a backslash. */
740 return FALSE;
741 }
742 ++i;
743 switch (s[i++]) {
744 case 'n':
745 *dst++ = '\n';
746 break;
747 case '\\':
748 *dst++ = '\\';
749 break;
750 default:
751 /* Only `\' or `n' may follow a backslash. */
752 return FALSE;
753 }
754 break;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000755
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000756 case '\0':
757 /* The file name may not contain a NUL. */
758 return FALSE;
759 break;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000760
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000761 default:
762 *dst++ = s[i++];
763 break;
764 }
765 }
766 *dst = '\0';
767 }
768 return TRUE;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000769}
770
Eric Andersen55522082001-07-10 16:31:29 +0000771static inline int hex_digits(unsigned char const *s)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000772{
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000773 while (*s) {
774 if (!ISXDIGIT(*s))
775 return TRUE;
776 ++s;
777 }
778 return FALSE;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000779}
780
781/* An interface to md5_stream. Operate on FILENAME (it may be "-") and
782 put the result in *MD5_RESULT. Return non-zero upon failure, zero
783 to indicate success. */
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000784static int md5_file(const char *filename, unsigned char *md5_result)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000785{
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000786 FILE *fp;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000787
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000788 if (filename[0] == '-' && filename[1] == '\0') {
789 have_read_stdin = 1;
790 fp = stdin;
791 } else {
792 fp = bb_wfopen(filename, "r");
793 if (fp == NULL)
794 return FALSE;
795 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000796
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000797 if (md5_stream(fp, md5_result)) {
798 bb_perror_msg("%s", filename);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000799
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000800 if (fp != stdin)
801 fclose(fp);
802 return FALSE;
803 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000804
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000805 if (fp != stdin && fclose(fp) == EOF) {
806 bb_perror_msg("%s", filename);
807 return FALSE;
808 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000809
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000810 return TRUE;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000811}
812
813static int md5_check(const char *checkfile_name)
814{
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000815 FILE *checkfile_stream;
816 int n_properly_formated_lines = 0;
817 int n_mismatched_checksums = 0;
818 int n_open_or_read_failures = 0;
819 unsigned char md5buffer[16];
820 size_t line_number;
821 char line[BUFSIZ];
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000822
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000823 if (checkfile_name[0] == '-' && checkfile_name[1] == '\0') {
824 have_read_stdin = 1;
825 checkfile_stream = stdin;
826 } else {
827 checkfile_stream = bb_wfopen(checkfile_name, "r");
828 if (checkfile_stream == NULL)
829 return FALSE;
830 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000831
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000832 line_number = 0;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000833
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000834 do {
835 char *filename;
836 unsigned char *md5num;
837 int line_length;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000838
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000839 ++line_number;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000840
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000841 fgets(line, BUFSIZ - 1, checkfile_stream);
842 line_length = strlen(line);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000843
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000844 if (line_length <= 0 || line == NULL)
845 break;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000846
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000847 /* Ignore comment lines, which begin with a '#' character. */
848 if (line[0] == '#')
849 continue;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000850
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000851 /* Remove any trailing newline. */
852 if (line[line_length - 1] == '\n')
853 line[--line_length] = '\0';
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000854
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000855 if (split_3(line, line_length, &md5num, &filename)
856 || !hex_digits(md5num)) {
857 if (warn) {
858 bb_error_msg
859 ("%s: %lu: improperly formatted MD5 checksum line",
860 checkfile_name, (unsigned long) line_number);
861 }
862 } else {
863 static const char bin2hex[] = {
864 '0', '1', '2', '3',
865 '4', '5', '6', '7',
866 '8', '9', 'a', 'b',
867 'c', 'd', 'e', 'f'
868 };
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000869
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000870 ++n_properly_formated_lines;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000871
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000872 if (md5_file(filename, md5buffer)) {
873 ++n_open_or_read_failures;
874 if (!status_only) {
875 printf("%s: FAILED open or read\n", filename);
876 fflush(stdout);
877 }
878 } else {
879 size_t cnt;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000880
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000881 /* Compare generated binary number with text representation
882 in check file. Ignore case of hex digits. */
883 for (cnt = 0; cnt < 16; ++cnt) {
884 if (tolower(md5num[2 * cnt])
885 != bin2hex[md5buffer[cnt] >> 4]
886 || (tolower(md5num[2 * cnt + 1])
887 != (bin2hex[md5buffer[cnt] & 0xf])))
888 break;
889 }
890 if (cnt != 16)
891 ++n_mismatched_checksums;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000892
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000893 if (!status_only) {
894 printf("%s: %s\n", filename,
895 (cnt != 16 ? "FAILED" : "OK"));
896 fflush(stdout);
897 }
898 }
899 }
900 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000901
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000902 while (!feof(checkfile_stream) && !ferror(checkfile_stream));
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000903
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000904 if (ferror(checkfile_stream)) {
905 bb_error_msg("%s: read error", checkfile_name);
906 return FALSE;
907 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000908
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000909 if (checkfile_stream != stdin && fclose(checkfile_stream) == EOF) {
910 bb_perror_msg("md5sum: %s", checkfile_name);
911 return FALSE;
912 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000913
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000914 if (n_properly_formated_lines == 0) {
915 /* Warn if no tests are found. */
916 bb_error_msg("%s: no properly formatted MD5 checksum lines found",
917 checkfile_name);
918 return FALSE;
919 } else {
920 if (!status_only) {
921 int n_computed_checkums = (n_properly_formated_lines
922 - n_open_or_read_failures);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000923
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000924 if (n_open_or_read_failures > 0) {
925 bb_error_msg
926 ("WARNING: %d of %d listed files could not be read",
927 n_open_or_read_failures, n_properly_formated_lines);
928 return FALSE;
929 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000930
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000931 if (n_mismatched_checksums > 0) {
932 bb_error_msg
933 ("WARNING: %d of %d computed checksums did NOT match",
934 n_mismatched_checksums, n_computed_checkums);
935 return FALSE;
936 }
937 }
938 }
939
940 return ((n_properly_formated_lines > 0 && n_mismatched_checksums == 0
941 && n_open_or_read_failures == 0) ? 0 : 1);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000942}
943
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000944int md5sum_main(int argc, char **argv)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000945{
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000946 unsigned char md5buffer[16];
947 int do_check = 0;
948 int opt;
949 char **string = NULL;
950 size_t n_strings = 0;
951 size_t err = 0;
952 char file_type_specified = 0;
953 char binary = 0;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000954
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000955 while ((opt = getopt(argc, argv, "g:bcstw")) != -1) {
956 switch (opt) {
957 case 'g':{ /* read a string */
958 if (string == NULL)
959 string = (char **) xmalloc((argc - 1) * sizeof(char *));
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000960
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000961 string[n_strings++] = optarg;
962 break;
963 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000964
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000965 case 'b': /* read files in binary mode */
966 file_type_specified = 1;
967 binary = 1;
968 break;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000969
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000970 case 'c': /* check MD5 sums against given list */
971 do_check = 1;
972 break;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000973
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000974 case 's': /* don't output anything, status code shows success */
975 status_only = 1;
976 warn = 0;
977 break;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000978
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000979 case 't': /* read files in text mode (default) */
980 file_type_specified = 1;
981 binary = 0;
982 break;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000983
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000984 case 'w': /* warn about improperly formated MD5 checksum lines */
985 status_only = 0;
986 warn = 1;
987 break;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000988
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000989 default:
990 bb_show_usage();
991 }
992 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000993
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000994 if (file_type_specified && do_check) {
995 bb_error_msg_and_die
996 ("the -b and -t options are meaningless when verifying checksums");
997 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000998
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +0000999 if (n_strings > 0 && do_check) {
1000 bb_error_msg_and_die("the -g and -c options are mutually exclusive");
1001 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001002
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +00001003 if (status_only && !do_check) {
1004 bb_error_msg_and_die
1005 ("the -s option is meaningful only when verifying checksums");
1006 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001007
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +00001008 if (warn && !do_check) {
1009 bb_error_msg_and_die
1010 ("the -w option is meaningful only when verifying checksums");
1011 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001012
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +00001013 if (n_strings > 0) {
1014 size_t i;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001015
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +00001016 if (optind < argc) {
1017 bb_error_msg_and_die("no files may be specified when using -g");
1018 }
1019 for (i = 0; i < n_strings; ++i) {
1020 size_t cnt;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001021
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +00001022 md5_buffer(string[i], strlen(string[i]), md5buffer);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001023
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +00001024 for (cnt = 0; cnt < 16; ++cnt)
1025 printf("%02x", md5buffer[cnt]);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001026
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +00001027 printf(" \"%s\"\n", string[i]);
1028 }
1029 } else if (do_check) {
1030 if (optind + 1 < argc) {
1031 bb_error_msg("only one argument may be specified when using -c");
1032 }
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001033
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +00001034 err = md5_check((optind == argc) ? "-" : argv[optind]);
1035 } else {
1036 if (optind == argc)
1037 argv[argc++] = "-";
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001038
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +00001039 for (; optind < argc; ++optind) {
1040 int fail;
1041 char *file = argv[optind];
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001042
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +00001043 fail = md5_file(file, md5buffer);
1044 err |= fail;
1045 if (!fail && file[0] == '-' && file[1] == '\0') {
1046 size_t i;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001047
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +00001048 for (i = 0; i < 16; ++i)
1049 printf("%02x", md5buffer[i]);
1050 putchar('\n');
1051 } else if (!fail) {
1052 size_t i;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001053
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +00001054 /* Output a leading backslash if the file name contains
1055 a newline or backslash. */
1056 if (strchr(file, '\n') || strchr(file, '\\'))
1057 putchar('\\');
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001058
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +00001059 for (i = 0; i < 16; ++i)
1060 printf("%02x", md5buffer[i]);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001061
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +00001062 putchar(' ');
1063 if (binary)
1064 putchar('*');
1065 else
1066 putchar(' ');
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001067
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +00001068 /* Translate each NEWLINE byte to the string, "\\n",
1069 and each backslash to "\\\\". */
1070 for (i = 0; i < strlen(file); ++i) {
1071 switch (file[i]) {
1072 case '\n':
1073 fputs("\\n", stdout);
1074 break;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001075
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +00001076 case '\\':
1077 fputs("\\\\", stdout);
1078 break;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001079
Glenn L McGrath7aa62cf2003-06-07 14:54:24 +00001080 default:
1081 putchar(file[i]);
1082 break;
1083 }
1084 }
1085 putchar('\n');
1086 }
1087 }
1088 }
1089
1090 if (fclose(stdout) == EOF) {
1091 bb_error_msg_and_die("write error");
1092 }
1093
1094 if (have_read_stdin && fclose(stdin) == EOF) {
1095 bb_error_msg_and_die(bb_msg_standard_input);
1096 }
1097
1098 if (err == 0)
1099 return EXIT_SUCCESS;
1100 else
1101 return EXIT_FAILURE;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001102}