]> git.zerfleddert.de Git - proxmark3-svn/blame - client/reveng/cli.c
begin reveng add-ons for lua
[proxmark3-svn] / client / reveng / cli.c
CommitLineData
fe81b478 1/* cli.c
2 * Greg Cook, 9/Apr/2015
3 */
4
5/* CRC RevEng, an arbitrary-precision CRC calculator and algorithm finder
6 * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 Gregory Cook
7 *
8 * This file is part of CRC RevEng.
9 *
10 * CRC RevEng is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * CRC RevEng is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with CRC RevEng. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24/* 2015-04-03: added -z
25 * 2013-09-16: do not search with -M
26 * 2013-06-11: uprog() suppresses first progress report
27 * 2013-04-22: uprog() prints poly same as mtostr()
28 * 2013-02-07: added -q, uprog(), removed -W, R_ODDLY
29 * 2012-05-24: -D dumps parameters of all models
30 * 2012-03-03: added code to test sort order of model table
31 * 2012-02-20: set stdin to binary (MinGW). offer -D if preset unknown.
32 * 2011-09-06: -s reads arguments once. stdin not closed.
33 * 2011-09-06: fixed bad argument-freeing loops.
34 * 2011-08-27: validates BMP_C()
35 * 2011-08-26: validates BMPBIT and BMPSUB
36 * 2011-08-25: fixed Init/Xorout reflection logic in -V and -v
37 * 2011-01-17: fixed ANSI C warnings
38 * 2011-01-15: added NOFORCE
39 * 2011-01-14: added -k, -P
40 * 2011-01-10: reorganised switches, added -V, -X
41 * 2010-12-26: renamed CRC RevEng
42 * 2010-12-18: implemented -c, -C
43 * 2010-12-14: added and implemented -d, -D, fixed -ipx entry
44 * 2010-12-11: implemented -e. first tests
45 * 2010-12-10: finalised option processing. started input validation
46 * 2010-12-07: started cli
47 */
48
49#include <stdio.h>
50#include <stdlib.h>
51#include "getopt.h"
52#ifdef _WIN32
53# include <io.h>
54# include <fcntl.h>
55# ifndef STDIN_FILENO
56# define STDIN_FILENO 0
57# endif /* STDIN_FILENO */
58#endif /* _WIN32 */
59
60#include "reveng.h"
61
62static FILE *oread(const char *);
63static poly_t rdpoly(const char *, int, int);
64static void usage(void);
65
66static const char *myname = "reveng"; /* name of our program */
67
68int reveng_main(int argc, char *argv[]) {
69 /* Command-line interface for CRC RevEng.
70 * Process options and switches in the argument list and
71 * run the required function.
72 */
73
74 /* default values */
75 model_t model = {
76 PZERO, /* no CRC polynomial, user must specify */
77 PZERO, /* Init = 0 */
78 P_BE, /* RefIn = false, RefOut = false, plus P_RTJUST setting in reveng.h */
79 PZERO, /* XorOut = 0 */
80 PZERO, /* check value unused */
81 NULL /* no model name */
82 };
83 int ibperhx = 8, obperhx = 8;
84 int rflags = 0, uflags = 0; /* search and UI flags */
85
86 unsigned long width = 0UL;
87 int c, mode = 0, args, psets, pass;
88 poly_t apoly, crc, qpoly = PZERO, *apolys, *pptr = NULL, *qptr = NULL;
89 model_t pset = model, *candmods, *mptr;
90 char *string;
91
f46c3663 92 myname = argv[0];
fe81b478 93
94 /* stdin must be binary */
95#ifdef _WIN32
96 _setmode(STDIN_FILENO, _O_BINARY);
97#endif /* _WIN32 */
98
99 SETBMP();
f46c3663 100
101 pos=0;
102 optind=1;
fe81b478 103 do {
104 c=getopt(argc, argv, "?A:BDFLMP:SVXa:bcdefhi:k:lm:p:q:rstuvw:x:yz");
105 switch(c) {
106 case 'A': /* A: bits per output character */
107 case 'a': /* a: bits per character */
108 if((obperhx = atoi(optarg)) > BMP_BIT) {
109 fprintf(stderr,"%s: argument to -%c must be between 1 and %d\n", myname, c, BMP_BIT);
110 return 0;
111 //exit(EXIT_FAILURE);
112 }
113 if(c == 'a') ibperhx = obperhx;
114 break;
115 case 'b': /* b big-endian (RefIn = false, RefOut = false ) */
116 model.flags &= ~P_REFIN;
117 rflags |= R_HAVERI;
118 /* fall through: */
119 case 'B': /* B big-endian output (RefOut = false) */
120 model.flags &= ~P_REFOUT;
121 rflags |= R_HAVERO;
122 mnovel(&model);
123 /* fall through: */
124 case 'r': /* r right-justified */
125 model.flags |= P_RTJUST;
126 break;
127 case 'c': /* c calculate CRC */
128 case 'D': /* D list primary model names */
129 case 'd': /* d dump CRC model */
130 case 'e': /* e echo arguments */
131 case 's': /* s search for algorithm */
132 case 'v': /* v calculate reversed CRC */
133 if(mode) {
134 fprintf(stderr,"%s: more than one mode switch specified. Use %s -h for help.\n", myname, myname);
135 return 0;
136 //exit(EXIT_FAILURE);
137 }
138 mode = c;
139 break;
140 case 'F': /* F force search */
141#ifndef NOFORCE
142 uflags |= C_FORCE;
143#endif
144 break;
145 case 'f': /* f arguments are filenames */
146 uflags |= C_INFILE;
147 break;
148 case 'h': /* h get help / usage */
149 case 'u': /* u get help / usage */
150 case '?': /* ? get help / usage */
151 default:
152 usage();
153 return 0;
154 //exit(EXIT_FAILURE);
155 break;
156 case 'i': /* i: Init value */
157 pptr = &model.init;
158 rflags |= R_HAVEI;
159 goto ippx;
160 case 'k': /* k: polynomial in Koopman notation */
161 pfree(&model.spoly);
162 model.spoly = strtop(optarg, 0, 4);
163 pkchop(&model.spoly);
164 width = plen(model.spoly);
165 rflags |= R_HAVEP;
166 mnovel(&model);
167 break;
168 case 'l': /* l little-endian input and output */
169 model.flags |= P_REFIN;
170 rflags |= R_HAVERI;
171 /* fall through: */
172 case 'L': /* L little-endian output */
173 model.flags |= P_REFOUT;
174 rflags |= R_HAVERO;
175 mnovel(&model);
176 /* fall through: */
177 case 't': /* t left-justified */
178 model.flags &= ~P_RTJUST;
179 break;
180 case 'm': /* m: select preset CRC model */
181 if(!(c = mbynam(&model, optarg))) {
182 fprintf(stderr,"%s: preset model '%s' not found. Use %s -D to list presets.\n", myname, optarg, myname);
183 return 0;
184 //exit(EXIT_FAILURE);
185 }
186 if(c < 0)
187 uerror("no preset models available");
188 /* must set width so that parameter to -ipx is not zeroed */
189 width = plen(model.spoly);
190 rflags |= R_HAVEP | R_HAVEI | R_HAVERI | R_HAVERO | R_HAVEX;
191 break;
192 case 'M': /* M non-augmenting algorithm */
193 model.flags &= ~P_MULXN;
194 break;
195 case 'P': /* P: reversed polynomial */
196 case 'p': /* p: polynomial */
197 pptr = &model.spoly;
198 rflags &= ~R_HAVEQ;
199 rflags |= R_HAVEP;
200ippx:
201 pfree(pptr);
202 *pptr = strtop(optarg, 0, 4);
203 pright(pptr, width);
204 if(c == 'P')
205 prev(pptr);
206 mnovel(&model);
207 break;
208 case 'q': /* q: range end polynomial */
209 pptr = &qpoly;
210 rflags &= ~R_HAVEP;
211 rflags |= R_HAVEQ;
212 goto ippx;
213 case 'S': /* s space between output characters */
214 model.flags |= P_SPACE;
215 break;
216 case 'V': /* v reverse algorithm */
217 /* Distinct from the -v switch as the
218 * user will have to reverse his or her
219 * own arguments. The user cannot dump
220 * the model generated by -v either.
221 */
222 mrev(&model);
223 break;
224 case 'w': /* w: CRC width = order - 1 */
225 width = (unsigned long) atol(optarg);
226 break;
227 case 'X': /* X print uppercase hex */
228 model.flags |= P_UPPER;
229 break;
230 case 'x': /* x: XorOut value */
231 pptr = &model.xorout;
232 rflags |= R_HAVEX;
233 goto ippx;
234 case 'y': /* y little-endian byte order in files */
235 model.flags |= P_LTLBYT;
236 break;
237 case 'z': /* z raw binary arguments */
238 model.flags |= P_DIRECT;
239 break;
240 case -1: /* no more options, continue */
241 ;
242 }
243 } while(c != -1);
244
245 /* canonicalise the model, so the one we dump is the one we
246 * calculate with (not with -s, spoly may be blank which will
247 * normalise to zero and clear init and xorout.)
248 */
249 if(mode != 's')
250 mcanon(&model);
251
252 switch(mode) {
253 case 'v': /* v calculate reversed CRC */
254 /* Distinct from the -V switch as this causes
255 * the arguments and output to be reversed as well.
256 */
257 /* reciprocate Poly */
258 prcp(&model.spoly);
259
260 /* mrev() does:
261 * if(refout) prev(init); else prev(xorout);
262 * but here the entire argument polynomial is
263 * reflected, not just the characters, so RefIn
264 * and RefOut are not inverted as with -V.
265 * Consequently Init is the mirror image of the
266 * one resulting from -V, and so we have:
267 */
268 if(~model.flags & P_REFOUT) {
269 prev(&model.init);
270 prev(&model.xorout);
271 }
272
273 /* swap init and xorout */
274 apoly = model.init;
275 model.init = model.xorout;
276 model.xorout = apoly;
277
278 /* fall through: */
279 case 'c': /* c calculate CRC */
280
281 /* validate inputs */
282 /* if(plen(model.spoly) == 0) {
283 * fprintf(stderr,"%s: no polynomial specified for -%c (add -w WIDTH -p POLY)\n", myname, mode);
284 * exit(EXIT_FAILURE);
285 * }
286 */
287
288 /* in the Williams model, xorout is applied after the refout stage.
289 * as refout is part of ptostr(), we reverse xorout here.
290 */
291 if(model.flags & P_REFOUT)
292 prev(&model.xorout);
293
294 for(; optind < argc; ++optind) {
295 if(uflags & C_INFILE)
296 apoly = rdpoly(argv[optind], model.flags, ibperhx);
297 else
298 apoly = strtop(argv[optind], model.flags, ibperhx);
299
300 if(mode == 'v')
301 prev(&apoly);
302
303 crc = pcrc(apoly, model.spoly, model.init, model.xorout, model.flags);
304
305 if(mode == 'v')
306 prev(&crc);
307
308 string = ptostr(crc, model.flags, obperhx);
309 puts(string);
310 free(string);
311 pfree(&crc);
312 pfree(&apoly);
313 }
314 break;
315 case 'D': /* D dump all models */
316 args = mcount();
317 if(!args)
318 uerror("no preset models available");
319 for(mode = 0; mode < args; ++mode) {
320 mbynum(&model, mode);
321 mcanon(&model);
322 ufound(&model);
323 }
324 break;
325 case 'd': /* d dump CRC model */
326 /* maybe we don't want to do this:
327 * either attaching names to arbitrary models or forcing to a preset
328 * mmatch(&model, M_OVERWR);
329 */
330 if(~model.flags & P_MULXN)
331 uerror("not a Williams model compliant algorithm");
332 string = mtostr(&model);
333 puts(string);
334 free(string);
335 break;
336 case 'e': /* e echo arguments */
337 for(; optind < argc; ++optind) {
338 if(uflags & C_INFILE)
339 apoly = rdpoly(argv[optind], model.flags, ibperhx);
340 else
341 apoly = strtop(argv[optind], model.flags, ibperhx);
342
343 psum(&apoly, model.init, 0UL);
344 string = ptostr(apoly, model.flags, obperhx);
345 puts(string);
346 free(string);
347 pfree(&apoly);
348 }
349 break;
350 case 's': /* s search for algorithm */
351 if(!width)
352 uerror("must specify positive -k or -w before -s");
353 if(~model.flags & P_MULXN)
354 uerror("cannot search for non-Williams compliant models");
355 praloc(&model.spoly, width);
356 praloc(&model.init, width);
357 praloc(&model.xorout, width);
358 if(!plen(model.spoly))
359 palloc(&model.spoly, width);
360 else
361 width = plen(model.spoly);
362
363 /* special case if qpoly is zero, search to end of range */
364 if(!ptst(qpoly))
365 rflags &= ~R_HAVEQ;
366
367 /* allocate argument array */
368 args = argc - optind;
369 if(!(apolys = malloc(args * sizeof(poly_t))))
370 uerror("cannot allocate memory for argument list");
371
372 for(pptr = apolys; optind < argc; ++optind) {
373 if(uflags & C_INFILE)
374 *pptr++ = rdpoly(argv[optind], model.flags, ibperhx);
375 else
376 *pptr++ = strtop(argv[optind], model.flags, ibperhx);
377 }
378 /* exit value of pptr is used hereafter! */
379
380 /* if endianness not specified, try
381 * little-endian then big-endian.
382 * NB: crossed-endian algorithms will not be
383 * searched.
384 */
385
386 /* scan against preset models */
387 if(~uflags & C_FORCE) {
388 pass = 0;
389 do {
390 psets = mcount();
391 while(psets) {
392 mbynum(&pset, --psets);
393 /* skip if different width, or refin or refout don't match */
394 if(plen(pset.spoly) != width || (model.flags ^ pset.flags) & (P_REFIN | P_REFOUT))
395 continue;
396 /* skip if the preset doesn't match specified parameters */
397 if(rflags & R_HAVEP && pcmp(&model.spoly, &pset.spoly))
398 continue;
399 if(rflags & R_HAVEI && psncmp(&model.init, &pset.init))
400 continue;
401 if(rflags & R_HAVEX && psncmp(&model.xorout, &pset.xorout))
402 continue;
403 apoly = pclone(pset.xorout);
404 if(pset.flags & P_REFOUT)
405 prev(&apoly);
406 for(qptr = apolys; qptr < pptr; ++qptr) {
407 crc = pcrc(*qptr, pset.spoly, pset.init, apoly, 0);
408 if(ptst(crc)) {
409 pfree(&crc);
410 break;
411 } else
412 pfree(&crc);
413 }
414 pfree(&apoly);
415 if(qptr == pptr) {
416 /* the selected model solved all arguments */
417 mcanon(&pset);
418 ufound(&pset);
419 uflags |= C_RESULT;
420 }
421 }
422 mfree(&pset);
423
424 /* toggle refIn/refOut and reflect arguments */
425 if(~rflags & R_HAVERI) {
426 model.flags ^= P_REFIN | P_REFOUT;
427 for(qptr = apolys; qptr < pptr; ++qptr)
428 prevch(qptr, ibperhx);
429 }
430 } while(~rflags & R_HAVERI && ++pass < 2);
431 }
432 if(uflags & C_RESULT) {
433 for(qptr = apolys; qptr < pptr; ++qptr)
434 pfree(qptr);
435 return 1;
436 //exit(EXIT_SUCCESS);
437 }
438 if(!(model.flags & P_REFIN) != !(model.flags & P_REFOUT))
439 uerror("cannot search for crossed-endian models");
440 pass = 0;
441 do {
442 mptr = candmods = reveng(&model, qpoly, rflags, args, apolys);
443 if(mptr && plen(mptr->spoly))
444 uflags |= C_RESULT;
445 while(mptr && plen(mptr->spoly)) {
446 /* results were printed by the callback
447 * string = mtostr(mptr);
448 * puts(string);
449 * free(string);
450 */
451 mfree(mptr++);
452 }
453 free(candmods);
454 if(~rflags & R_HAVERI) {
455 model.flags ^= P_REFIN | P_REFOUT;
456 for(qptr = apolys; qptr < pptr; ++qptr)
457 prevch(qptr, ibperhx);
458 }
459 } while(~rflags & R_HAVERI && ++pass < 2);
460 for(qptr = apolys; qptr < pptr; ++qptr)
461 pfree(qptr);
462 free(apolys);
463 if(~uflags & C_RESULT)
464 uerror("no models found");
465 break;
466 default: /* no mode specified */
467 fprintf(stderr, "%s: no mode switch specified. Use %s -h for help.\n", myname, myname);
468 return 0;
469 //exit(EXIT_FAILURE);
470 }
471
472 return 1;
473 //exit(EXIT_SUCCESS);
474}
475
476void
477ufound(const model_t *model) {
478 /* Callback function to report each model found */
479 char *string;
480
481 if(!model) return;
482 /* generated models will be canonical */
483 string = mtostr(model);
484 puts(string);
485 free(string);
486}
487
488void
489uerror(const char *msg) {
490 /* Callback function to report fatal errors */
491 fprintf(stderr, "%s: %s\n", myname, msg);
f46c3663 492 return;
493 //exit(EXIT_FAILURE);
fe81b478 494}
495
496void
497uprog(const poly_t gpoly, int flags, unsigned long seq) {
498 /* Callback function to report search progress */
499 char *string;
500
501 /* Suppress first report in CLI */
502 if(!seq)
503 return;
504 string = ptostr(gpoly, P_RTJUST, 4);
505 fprintf(stderr, "%s: searching: width=%ld poly=0x%s refin=%s refout=%s\n",
506 myname, plen(gpoly), string,
507 (flags & P_REFIN ? "true" : "false"),
508 (flags & P_REFOUT ? "true" : "false")
509 );
510 free(string);
511}
512
513static poly_t
514rdpoly(const char *name, int flags, int bperhx) {
515 /* read poly from file in chunks and report errors */
516
517 poly_t apoly = PZERO, chunk = PZERO;
518 FILE *input;
519
520 input = oread(name);
521 while(!feof(input) && !ferror(input)) {
522 chunk = filtop(input, BUFFER, flags, bperhx);
523 psum(&apoly, chunk, plen(apoly));
524 pfree(&chunk);
525 }
526 if(ferror(input)) {
527 fprintf(stderr,"%s: error condition on file '%s'\n", myname, name);
528 exit(EXIT_FAILURE);
529 }
530 /* close file unless stdin */
531 if(input == stdin)
532 /* reset EOF condition */
533 clearerr(input);
534 else if(fclose(input)) {
535 fprintf(stderr,"%s: error closing file '%s'\n", myname, name);
536 exit(EXIT_FAILURE);
537 }
538 return(apoly);
539}
540
541static FILE *
542oread(const char *name) {
543 /* open file for reading and report errors */
544 FILE *handle;
545
546 /* recognise special name '-' as standard input */
547 if(*name == '-' && name[1] == '\0')
548 return(stdin);
549 if(!(handle = fopen(name, "rb"))) {
550 fprintf(stderr, "%s: cannot open '%s' for reading\n", myname, name);
f46c3663 551 return 0;
552 //exit(EXIT_FAILURE);
fe81b478 553 }
554 return(handle);
555}
556
557static void
558usage(void) {
559 /* print usage if asked, or if syntax incorrect */
560 fprintf(stderr,
561 "CRC RevEng, an arbitrary-precision CRC calculator and algorithm finder\n"
562 "Usage:\t");
563 fputs(myname, stderr);
564 fprintf(stderr,
565 "\t-cdDesvhu? [-bBfFlLMrStVXyz]\n"
566 "\t\t[-a BITS] [-A OBITS] [-i INIT] [-k KPOLY] [-m MODEL]\n"
567 "\t\t[-p POLY] [-P RPOLY] [-q QPOLY] [-w WIDTH] [-x XOROUT]\n"
568 "\t\t[STRING...]\n"
569 "Options:\n"
570 "\t-a BITS\t\tbits per character (1 to %d)\n"
571 "\t-A OBITS\tbits per output character (1 to %d)\n"
572 "\t-i INIT\t\tinitial register value\n"
573 "\t-k KPOLY\tgenerator in Koopman notation (implies WIDTH)\n"
574 "\t-m MODEL\tpreset CRC algorithm\n"
575 "\t-p POLY\t\tgenerator or search range start polynomial\n"
576 "\t-P RPOLY\treversed generator polynomial\n",
577 BMP_BIT, BMP_BIT);
578 fprintf(stderr,
579 "\t-q QPOLY\tsearch range end polynomial\n"
580 "\t-w WIDTH\tregister size, in bits\n"
581 "\t-x XOROUT\tfinal register XOR value\n"
582 "Modifier switches:\n"
583 "\t-b big-endian CRC\t\t-B big-endian CRC output\n"
584 "\t-f read files named in STRINGs\t-F find presets less quickly\n"
585 "\t-l little-endian CRC\t\t-L little-endian CRC output\n"
586 "\t-M non-augmenting algorithm\t-r right-justified output\n"
587 "\t-S print spaces between chars\t-t left-justified output\n"
588 "\t-V reverse algorithm only\t-X print uppercase hex\n"
589 "\t-y low bytes first in files\t-z raw binary STRINGs\n");
590 fprintf(stderr,
591 "Mode switches:\n"
592 "\t-c calculate CRCs\t\t-d dump algorithm parameters\n"
593 "\t-D list preset algorithms\t-e echo (and reformat) input\n"
594 "\t-s search for algorithm\t\t-v calculate reversed CRCs\n"
595 "\t-h | -u | -? show this help\n"
596 "\n"
597 "Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 Gregory Cook\n"
598 "This is free software; see the source for copying conditions. There is NO\n"
599 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
600 "Version "
601 VERSION
602 "\t\t\t\t <http://reveng.sourceforge.net/>\n");
603}
Impressum, Datenschutz