zic: Remove from tree.
[haiku.git] / src / bin / rmd160 / main.c
blobe65ebf2a0e3d28b9efe64b43f7d12322b6dd71f9
1 /*
2 rmd.c
3 RIPEMD-160 generate and check utility
4 by Po Shan Cheah, Copyright (c) 1997
5 You may distribute this program freely provided this notice
6 is retained.
8 January 5, 1997:
9 Initial release.
13 #include "rmd160.h"
14 #include <ctype.h>
15 #include <errno.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
21 #define BUFLEN 4096
22 #define RMDBITS 160
24 int binary_mode = 0;
25 int verbose_mode = 0;
26 char *progname = "";
28 int prog_rc = 0;
30 void setrc(int newrc) {
32 /* raises but never lowers the program return code to newrc */
34 if (newrc > prog_rc)
35 prog_rc = newrc;
38 int cvthex(char c) {
39 /* convert a hex digit to an integer */
41 c = toupper(c);
43 if (c >= 'A' && c <= 'F')
44 return c - 'A' + 10;
46 return c - '0';
49 int hexdigit(char c) {
50 /* returns true if character is a hexadecimal digit */
52 return
53 (c >= '0' && c <= '9') ||
54 (toupper(c) >= 'A' && toupper(c) <= 'F');
57 #define ESCAPE '%'
59 char *encodestr(char *instr) {
60 /* replace unprintable characters and % itself with %HH */
62 static char buf[BUFLEN];
63 char *outstr = buf;
65 for ( ; *instr; ++instr) {
66 if (isprint(*instr) && !isspace(*instr) && *instr != ESCAPE)
67 *outstr++ = *instr;
68 else {
69 sprintf(outstr, "%%%02x", *instr);
70 outstr += 3;
73 *outstr = '\0';
74 return buf;
77 char *decodestr(char *instr) {
78 /* undo what encodestr did */
80 static char buf[BUFLEN];
81 char *outstr = buf;
83 while (*instr) {
84 if (*instr == ESCAPE &&
85 hexdigit(instr[1]) &&
86 hexdigit(instr[2])) {
87 *outstr++ = cvthex(instr[1]) << 4 | cvthex(instr[2]);
88 instr += 3;
90 else
91 *outstr++ = *instr ++;
93 *outstr = '\0';
94 return buf;
97 void pack_chunk(word *chunk, byte *buf) {
98 /* pack 64 bytes into 16 little-endian 32-bit words */
100 int j;
102 for (j = 0; j < 16; ++j, buf += 4)
103 *chunk++ = (word) buf[0] | (word) buf[1] << 8 |
104 (word) buf[2] << 16 | (word) buf[3] << 24 ;
107 byte *rmdfp(char *fname, FILE *fp) {
108 /* calculate the message digest of a file
109 and return it in string form */
111 int bytesread;
112 int i;
113 word tmp;
114 word chunk[16];
115 char buf[BUFLEN];
116 word length[2];
117 word mdbuf[RMDBITS / 32];
118 static byte code[RMDBITS / 8];
120 length[0] = length[1] = 0;
121 MDinit(mdbuf);
123 /* do all full BUFLEN portions */
125 while ((bytesread = fread(buf, 1, BUFLEN, fp)) == BUFLEN) {
127 for (i = 0; i < BUFLEN; i += 64) {
128 pack_chunk(chunk, buf + i);
129 MDcompress(mdbuf, chunk);
132 if ((tmp = length[0] + bytesread) < length[0])
133 ++ length[1]; /* overflow */
134 length[0] = tmp;
137 if (ferror(fp)) {
138 fprintf(stderr, "%s: %s\n", fname, strerror(errno));
139 setrc(2);
140 return NULL;
143 /* do all the remaining 64-byte blocks */
145 for (i = 0; i < bytesread - 63; i += 64) {
146 pack_chunk(chunk, buf + i);
147 MDcompress(mdbuf, chunk);
150 if ((tmp = length[0] + bytesread) < length[0])
151 ++ length[1]; /* overflow */
152 length[0] = tmp;
154 /* do the last partial or zero length block */
156 MDfinish(mdbuf, buf + i, length[0] << 3,
157 length[0] >> 29 | length[1] << 3);
159 /* convert to 64-byte string using little-endian conversion */
161 for (i = 0; i < RMDBITS / 8; i += 4) {
163 word wd = mdbuf[i >> 2];
165 code[i] = (byte) (wd);
166 code[i + 1] = (byte) (wd >> 8);
167 code[i + 2] = (byte) (wd >> 16);
168 code[i + 3] = (byte) (wd >> 24);
171 return code;
174 void printcode(byte *code) {
175 /* print a RIPEMD-160 code */
177 int i;
179 for (i = 0; i < RMDBITS / 8; ++i)
180 printf("%02x", code[i]);
183 byte *rmdfile(char *fname) {
184 /* calculate the message digest of a single file
185 and output the digest followed by the file name */
187 FILE *fp;
189 fp = fopen(fname, binary_mode ? "rb" : "r");
190 if (fp == NULL) {
191 fprintf(stderr, "%s: %s\n", fname, strerror(errno));
192 setrc(2);
193 return NULL;
196 else {
197 byte *code = rmdfp(fname, fp);
198 fclose(fp);
199 return code;
203 int checkdigest(char *digest) {
204 /* returns true if string is a valid message digest string */
206 if (strlen(digest) != RMDBITS / 8 * 2)
207 return 0;
209 for ( ; *digest; ++digest) {
210 if ( ! hexdigit(*digest))
211 return 0;
214 return 1;
217 void stringtocode(byte *code, char *str) {
218 /* convert message digest string into 20 byte code */
220 int i;
222 for (i = 0; i < RMDBITS / 8; ++i, str += 2)
223 *code++ = cvthex(str[0]) << 4 | cvthex(str[1]);
226 void checkfp(char *fname, FILE *fp) {
227 /* check message digests. message digest data comes from
228 the given open file handle. */
230 int lineno = 0;
231 int nfail = 0;
232 int nfile = 0;
233 char *filename;
234 byte *code;
235 byte inputcode[RMDBITS / 8];
236 char line[BUFLEN];
237 char digest[BUFLEN];
238 char infilename[BUFLEN];
240 while (fgets(line, BUFLEN, fp)) {
242 ++lineno;
244 /* error checking */
246 if (sscanf(line, "%s%s", digest, infilename) < 2) {
247 fprintf(stderr, "%s: invalid input on line %d\n",
248 progname, lineno);
249 setrc(2);
250 continue;
253 if (!checkdigest(digest)) {
254 fprintf(stderr, "%s: invalid message digest on line %d\n",
255 progname, lineno);
256 setrc(2);
257 continue;
260 stringtocode(inputcode, digest);
262 /* calculate message digest for file */
264 filename = decodestr(infilename);
266 code = rmdfile(filename);
267 if (code) {
269 ++nfile;
271 /* compare digests */
273 if (memcmp(inputcode, code, RMDBITS / 8) != 0) {
274 ++nfail;
275 setrc(1);
277 if (verbose_mode)
278 printf("FAILED %s\n", filename);
279 else
280 printf("%s: RIPEMD-160 check failed for `%s'\n",
281 progname, filename);
284 else {
285 if (verbose_mode)
286 printf("GOOD %s\n", filename);
291 if (verbose_mode && nfail)
292 printf("%s: %d of %d file(s) failed RIPEMD-160 check\n",
293 progname, nfail, nfile);
295 if (ferror(fp)) {
296 fprintf(stderr, "%s: %s\n", fname, strerror(errno));
297 setrc(2);
301 void checkfile(char *fname) {
302 /* check message digests. message digest data comes from
303 the named file. */
305 FILE *fp;
307 fp = fopen(fname, "r");
308 if (fp == NULL) {
309 fprintf(stderr, "%s: %s\n", fname, strerror(errno));
310 setrc(2);
313 else {
314 checkfp(fname, fp);
315 fclose(fp);
319 int main(int argc, char *argv[]) {
321 int c;
322 int check_mode = 0;
324 progname = argv[0];
326 /* parse command line arguments */
328 while ((c = getopt(argc, argv, "bcvh")) >= 0) {
330 switch (c) {
332 case 'b':
333 binary_mode = 1;
334 break;
336 case 'c':
337 check_mode = 1;
338 break;
340 case 'v':
341 verbose_mode = 1;
342 break;
344 case 'h':
345 case ':':
346 case '?':
347 printf("Usage: %s [-b] [-c] [-v] [<file>...]\n"
348 "Generates or checks RIPEMD-160 message digests\n"
349 " -b read files in binary mode\n"
350 " -c check message digests\n"
351 " -v verbose, print file names while checking\n\n"
352 "If -c is not specified, then one message digest is "
353 "generated per file\n"
354 "and sent to standard output. If no files are specified "
355 "then input is\n"
356 "taken from standard input and only one message digest "
357 "will be\n"
358 "generated.\n\n"
359 "If -c is specified then message digests for a list of "
360 "files are\n"
361 "checked. The input should be a table in the same format "
362 "as the output\n"
363 "of this program when message digests are generated. If a "
364 "file is\n"
365 "specified then the message digest table is read from that "
366 "file. If no\n"
367 "file is specified, then the message digest table is read "
368 "from standard\n"
369 "input.\n", progname);
370 exit(0);
374 if (check_mode) {
376 if (optind < argc) {
378 /* check using data from file named on command line */
380 checkfile(argv[optind]);
384 else {
386 /* check using data from standard input */
388 checkfp("(stdin)", stdin);
393 else {
395 if (optind < argc) {
397 /* process file arguments */
399 for ( ; optind < argc; ++optind) {
401 byte *code = rmdfile(argv[optind]);
403 if (code) {
404 printcode(code);
405 printf(" %s\n", encodestr(argv[optind]));
410 else {
412 /* no file arguments so take input from stdin */
414 byte *code = rmdfp("(stdin)", stdin);
416 if (code) {
417 printcode(code);
418 printf("\n");
423 return prog_rc;