X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/07b5a3c3ba774ec93007827cf1233b4edb699bad..fe81b4781103a51117b904681ad2c259bf16c084:/client/reveng/reveng.c
diff --git a/client/reveng/reveng.c b/client/reveng/reveng.c
new file mode 100644
index 00000000..3c6da126
--- /dev/null
+++ b/client/reveng/reveng.c
@@ -0,0 +1,488 @@
+/* reveng.c
+ * Greg Cook, 9/Apr/2015
+ */
+
+/* CRC RevEng, an arbitrary-precision CRC calculator and algorithm finder
+ * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 Gregory Cook
+ *
+ * This file is part of CRC RevEng.
+ *
+ * CRC RevEng is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * CRC RevEng is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with CRC RevEng. If not, see .
+ */
+
+/* 2013-09-16: calini(), calout() work on shortest argument
+ * 2013-06-11: added sequence number to uprog() calls
+ * 2013-02-08: added polynomial range search
+ * 2013-01-18: refactored model checking to pshres(); renamed chkres()
+ * 2012-05-24: efficiently build Init contribution string
+ * 2012-05-24: removed broken search for crossed-endian algorithms
+ * 2012-05-23: rewrote engini() after Ewing; removed modini()
+ * 2011-01-17: fixed ANSI C warnings
+ * 2011-01-08: fixed calini(), modini() caters for crossed-endian algos
+ * 2011-01-04: renamed functions, added calini(), factored pshres();
+ * rewrote engini() and implemented quick Init search
+ * 2011-01-01: reveng() initialises terminating entry, addparms()
+ * initialises all fields
+ * 2010-12-26: renamed CRC RevEng. right results, rejects polys faster
+ * 2010-12-24: completed, first tests (unsuccessful)
+ * 2010-12-21: completed modulate(), partial sketch of reveng()
+ * 2010-12-19: started reveng
+ */
+
+/* reveng() can in theory be modified to search for polynomials shorter
+ * than the full width as well, but this imposes a heavy time burden on
+ * the full width search, which is the primary use case, as well as
+ * complicating the search range function introduced in version 1.1.0.
+ * It is more effective to search for each shorter width directly.
+ */
+
+#include
+
+#define FILE void
+#include "reveng.h"
+
+static poly_t *modpol(const poly_t init, int rflags, int args, const poly_t *argpolys);
+static void engini(int *resc, model_t **result, const poly_t divisor, int flags, int args, const poly_t *argpolys);
+static void calout(int *resc, model_t **result, const poly_t divisor, const poly_t init, int flags, int args, const poly_t *argpolys);
+static void calini(int *resc, model_t **result, const poly_t divisor, int flags, const poly_t xorout, int args, const poly_t *argpolys);
+static void chkres(int *resc, model_t **result, const poly_t divisor, const poly_t init, int flags, const poly_t xorout, int args, const poly_t *argpolys);
+
+static const poly_t pzero = PZERO;
+
+model_t *
+reveng(const model_t *guess, const poly_t qpoly, int rflags, int args, const poly_t *argpolys) {
+ /* Complete the parameters of a model by calculation or brute search. */
+ poly_t *pworks, *wptr, rem, gpoly;
+ model_t *result = NULL, *rptr;
+ int resc = 0;
+ unsigned long spin = 0, seq = 0;
+
+ if(~rflags & R_HAVEP) {
+ /* The poly is not known.
+ * Produce a list of differences between the arguments.
+ */
+ pworks = modpol(guess->init, rflags, args, argpolys);
+ if(!pworks || !plen(*pworks)) {
+ free(pworks);
+ goto requit;
+ }
+ /* Initialise the guessed poly to the starting value. */
+ gpoly = pclone(guess->spoly);
+ /* Clear the least significant term, to be set in the
+ * loop. qpoly does not need fixing as it is only
+ * compared with odd polys.
+ */
+ if(plen(gpoly))
+ pshift(&gpoly, gpoly, 0UL, 0UL, plen(gpoly) - 1UL, 1UL);
+
+ while(piter(&gpoly) && (~rflags & R_HAVEQ || pcmp(&gpoly, &qpoly) < 0)) {
+ /* For each possible poly of this size, try
+ * dividing all the differences in the list.
+ */
+ if(!(spin++ & R_SPMASK)) {
+ uprog(gpoly, guess->flags, seq++);
+ }
+ for(wptr = pworks; plen(*wptr); ++wptr) {
+ /* straight divide message by poly, don't multiply by x^n */
+ rem = pcrc(*wptr, gpoly, pzero, pzero, 0);
+ if(ptst(rem)) {
+ pfree(&rem);
+ break;
+ } else
+ pfree(&rem);
+ }
+ /* If gpoly divides all the differences, it is a
+ * candidate. Search for an Init value for this
+ * poly or if Init is known, log the result.
+ */
+ if(!plen(*wptr)) {
+ /* gpoly is a candidate poly */
+ if(rflags & R_HAVEI && rflags & R_HAVEX)
+ chkres(&resc, &result, gpoly, guess->init, guess->flags, guess->xorout, args, argpolys);
+ else if(rflags & R_HAVEI)
+ calout(&resc, &result, gpoly, guess->init, guess->flags, args, argpolys);
+ else if(rflags & R_HAVEX)
+ calini(&resc, &result, gpoly, guess->flags, guess->xorout, args, argpolys);
+ else
+ engini(&resc, &result, gpoly, guess->flags, args, argpolys);
+ }
+ if(!piter(&gpoly))
+ break;
+ }
+ /* Finished with gpoly and the differences list, free them.
+ */
+ pfree(&gpoly);
+ for(wptr = pworks; plen(*wptr); ++wptr)
+ pfree(wptr);
+ free(pworks);
+ }
+ else if(rflags & R_HAVEI && rflags & R_HAVEX)
+ /* All parameters are known! Submit the result if we get here */
+ chkres(&resc, &result, guess->spoly, guess->init, guess->flags, guess->xorout, args, argpolys);
+ else if(rflags & R_HAVEI)
+ /* Poly and Init are known, calculate XorOut */
+ calout(&resc, &result, guess->spoly, guess->init, guess->flags, args, argpolys);
+ else if(rflags & R_HAVEX)
+ /* Poly and XorOut are known, calculate Init */
+ calini(&resc, &result, guess->spoly, guess->flags, guess->xorout, args, argpolys);
+ else
+ /* Poly is known but not Init; search for Init. */
+ engini(&resc, &result, guess->spoly, guess->flags, args, argpolys);
+
+requit:
+ if(!(result = realloc(result, ++resc * sizeof(model_t))))
+ uerror("cannot reallocate result array");
+ rptr = result + resc - 1;
+ rptr->spoly = pzero;
+ rptr->init = pzero;
+ rptr->flags = 0;
+ rptr->xorout = pzero;
+ rptr->check = pzero;
+ rptr->name = NULL;
+
+ return(result);
+}
+
+static poly_t *
+modpol(const poly_t init, int rflags, int args, const poly_t *argpolys) {
+ /* Produce, in ascending length order, a list of differences
+ * between the arguments in the list by summing pairs of arguments.
+ * If R_HAVEI is not set in rflags, only pairs of equal length are
+ * summed.
+ * Otherwise, sums of right-aligned pairs are also returned, with
+ * the supplied init poly added to the leftmost terms of each
+ * poly of the pair.
+ */
+ poly_t work, swap, *result, *rptr, *iptr;
+ const poly_t *aptr, *bptr, *eptr = argpolys + args;
+ unsigned long alen, blen;
+
+ if(args < 2) return(NULL);
+
+ if(!(result = malloc(((((args - 1) * args) >> 1) + 1) * sizeof(poly_t))))
+ uerror("cannot allocate memory for codeword table");
+
+ rptr = result;
+
+ for(aptr = argpolys; aptr < eptr; ++aptr) {
+ alen = plen(*aptr);
+ for(bptr = aptr + 1; bptr < eptr; ++bptr) {
+ blen = plen(*bptr);
+ if(alen == blen) {
+ work = pclone(*aptr);
+ psum(&work, *bptr, 0UL);
+ } else if(rflags & R_HAVEI && alen < blen) {
+ work = pclone(*bptr);
+ psum(&work, *aptr, blen - alen);
+ psum(&work, init, 0UL);
+ psum(&work, init, blen - alen);
+ } else if(rflags & R_HAVEI /* && alen > blen */) {
+ work = pclone(*aptr);
+ psum(&work, *bptr, alen - blen);
+ psum(&work, init, 0UL);
+ psum(&work, init, alen - blen);
+ } else
+ work = pzero;
+
+ if(plen(work))
+ pnorm(&work);
+ if((blen = plen(work))) {
+ /* insert work into result[] in ascending order of length */
+ for(iptr = result; iptr < rptr; ++iptr) {
+ if(plen(work) < plen(*iptr)) {
+ swap = *iptr;
+ *iptr = work;
+ work = swap;
+ }
+ else if(plen(*iptr) == blen && !pcmp(&work, iptr)) {
+ pfree(&work);
+ work = *--rptr;
+ break;
+ }
+ }
+ *rptr++ = work;
+ }
+ }
+ }
+ *rptr = pzero;
+ return(result);
+}
+
+static void
+engini(int *resc, model_t **result, const poly_t divisor, int flags, int args, const poly_t *argpolys) {
+ /* Search for init values implied by the arguments.
+ * Method from: Ewing, Gregory C. (March 2010).
+ * "Reverse-Engineering a CRC Algorithm". Christchurch:
+ * University of Canterbury.
+ *
+ */
+ poly_t apoly = PZERO, bpoly, pone = PZERO, *mat, *jptr;
+ const poly_t *aptr, *bptr, *iptr;
+ unsigned long alen, blen, dlen, ilen, i, j;
+ int cy;
+
+ dlen = plen(divisor);
+
+ /* Allocate the CRC matrix */
+ if(!(mat = (poly_t *) malloc((dlen << 1) * sizeof(poly_t))))
+ uerror("cannot allocate memory for CRC matrix");
+
+ /* Find arguments of the two shortest lengths */
+ alen = blen = plen(*(aptr = bptr = iptr = argpolys));
+ for(++iptr; iptr < argpolys + args; ++iptr) {
+ ilen = plen(*iptr);
+ if(ilen < alen) {
+ bptr = aptr; blen = alen;
+ aptr = iptr; alen = ilen;
+ } else if(ilen > alen && (aptr == bptr || ilen < blen)) {
+ bptr = iptr; blen = ilen;
+ }
+ }
+ if(aptr == bptr) {
+ /* if no arguments are suitable, calculate Init with an
+ * assumed XorOut of 0. Create a padded XorOut
+ */
+ palloc(&apoly, dlen);
+ calini(resc, result, divisor, flags, apoly, args, argpolys);
+ pfree(&apoly);
+ return;
+ }
+
+ /* Find the potential contribution of the bottom bit of Init */
+ palloc(&pone, 1UL);
+ piter(&pone);
+ if(blen < (dlen << 1)) {
+ palloc(&apoly, dlen); /* >= 1 */
+ psum(&apoly, pone, (dlen << 1) - 1UL - blen); /* >= 0 */
+ psum(&apoly, pone, (dlen << 1) - 1UL - alen); /* >= 1 */
+ } else {
+ palloc(&apoly, blen - dlen + 1UL); /* > dlen */
+ psum(&apoly, pone, 0UL);
+ psum(&apoly, pone, blen - alen); /* >= 1 */
+ }
+ if(plen(apoly) > dlen) {
+ mat[dlen] = pcrc(apoly, divisor, pzero, pzero, 0);
+ pfree(&apoly);
+ } else {
+ mat[dlen] = apoly;
+ }
+
+ /* Find the actual contribution of Init */
+ apoly = pcrc(*aptr, divisor, pzero, pzero, 0);
+ bpoly = pcrc(*bptr, divisor, pzero, apoly, 0);
+
+ /* Populate the matrix */
+ palloc(&apoly, 1UL);
+ for(jptr=mat; jptr j */
+ j = pfirst(apoly);
+ }
+ if(j < dlen)
+ mat[j] = apoly; /* pident(mat[j], pzero) || pfirst(mat[j]) == j */
+ else
+ pfree(&apoly);
+ }
+ palloc(&bpoly, dlen + 1UL);
+ psum(&bpoly, pone, dlen);
+
+ /* Iterate through all solutions */
+ do {
+ /* Solve the matrix by Gaussian elimination.
+ * The parity of the result, masked by each row, should be even.
+ */
+ cy = 1;
+ apoly = pclone(bpoly);
+ jptr = mat + dlen;
+ for(i=0UL; ispoly = pclone(divisor);
+ rptr->init = pclone(init);
+ rptr->flags = flags;
+ rptr->xorout = pclone(xorout);
+ rptr->name = NULL;
+
+ /* compute check value for this model */
+ mcheck(rptr);
+
+ /* callback to notify new model */
+ ufound(rptr);
+}