proxmark3/client/reveng/model.c

224 lines
6.4 KiB
C
Raw Normal View History

/* model.c
* Greg Cook, 26/Jul/2016
*/
/* CRC RevEng: arbitrary-precision CRC calculator and algorithm finder
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016 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 <https://www.gnu.org/licenses/>.
*/
/* 2016-02-22: split off preset.c
* 2012-03-03: single-line Williams model string conversion
* 2011-09-03: added mrev(), mnovel()
* 2011-01-17: fixed ANSI C warnings (except preset models)
* 2010-12-26: renamed CRC RevEng
* 2010-12-18: minor change to mtostr() output format
* 2010-12-15: added mcmp()
* 2010-12-14: finished mtostr()
* 2010-12-12: started models.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "reveng.h"
/* Private declarations */
static const poly_t pzero = PZERO;
/* Definitions */
void
mcpy(model_t *dest, const model_t *src) {
/* Copies the parameters of src to dest.
* dest must be an initialised model.
*/
if(!dest || !src) return;
pcpy(&dest->spoly, src->spoly);
pcpy(&dest->init, src->init);
pcpy(&dest->xorout, src->xorout);
pcpy(&dest->check, src->check);
dest->flags = src->flags;
/* link to the name as it is static */
dest->name = src->name;
}
void
mfree(model_t *model) {
/* Frees the parameters of model. */
if(!model) return;
pfree(&model->spoly);
pfree(&model->init);
pfree(&model->xorout);
pfree(&model->check);
/* not name as it is static */
/* not model either, it might point to an array! */
}
int
mcmp(const model_t *a, const model_t *b) {
/* Compares a and b for identical effect, i.e. disregarding
* trailing zeroes in parameter polys.
* Intended for bsearch().
*/
int result;
if(!a || !b) return(!b - !a);
if((result = psncmp(&a->spoly, &b->spoly))) return(result);
if((result = psncmp(&a->init, &b->init))) return(result);
if((a->flags & P_REFIN) && (~b->flags & P_REFIN)) return(1);
if((~a->flags & P_REFIN) && (b->flags & P_REFIN)) return(-1);
if((a->flags & P_REFOUT) && (~b->flags & P_REFOUT)) return(1);
if((~a->flags & P_REFOUT) && (b->flags & P_REFOUT)) return(-1);
return(psncmp(&a->xorout, &b->xorout));
}
char *
mtostr(const model_t *model) {
/* Returns a malloc()-ed string containing a Williams model
* record representing the input model.
* mcanon() should be called on the argument before printing.
*/
size_t size;
char *polystr, *initstr, *xorotstr, *checkstr, strbuf[512], *string = NULL;
if(!model) return(NULL);
polystr = ptostr(model->spoly, P_RTJUST, 4);
initstr = ptostr(model->init, P_RTJUST, 4);
xorotstr = ptostr(model->xorout, P_RTJUST, 4);
checkstr = ptostr(model->check, P_RTJUST, 4);
sprintf(strbuf, "%lu", plen(model->spoly));
size =
70
+ (model->name && *model->name ? 2 + strlen(model->name) : 6)
+ strlen(strbuf)
+ (polystr && *polystr ? strlen(polystr) : 6)
+ (initstr && *initstr ? strlen(initstr) : 6)
+ (model->flags & P_REFIN ? 4 : 5)
+ (model->flags & P_REFOUT ? 4 : 5)
+ (xorotstr && *xorotstr ? strlen(xorotstr) : 6)
+ (checkstr && *checkstr ? strlen(checkstr) : 6);
if((string = malloc(size))) {
sprintf(strbuf, "\"%s\"", model->name);
sprintf(string,
"width=%lu "
"poly=0x%s "
"init=0x%s "
"refin=%s "
"refout=%s "
"xorout=0x%s "
"check=0x%s "
"name=%s",
plen(model->spoly),
polystr && *polystr ? polystr : "(none)",
initstr && *initstr ? initstr : "(none)",
(model->flags & P_REFIN) ? "true" : "false",
(model->flags & P_REFOUT) ? "true" : "false",
xorotstr && *xorotstr ? xorotstr : "(none)",
checkstr && *checkstr ? checkstr : "(none)",
(model->name && *model->name) ? strbuf : "(none)");
}
free(polystr);
free(initstr);
free(xorotstr);
free(checkstr);
if(!string)
uerror("cannot allocate memory for model description");
return(string);
}
void
mcanon(model_t *model) {
/* canonicalise a model */
unsigned long dlen;
if(!model) return;
/* extending on the right here. This preserves the functionality
* of a presumed working model.
*/
psnorm(&model->spoly);
dlen = plen(model->spoly);
praloc(&model->init, dlen);
praloc(&model->xorout, dlen);
/* only calculate Check if missing. Relying on all functions
* changing parameters to call mnovel(). This is to ensure that
* the Check value stored in the preset table is printed when
* the model is dumped. If something goes wrong with the
* calculator then the discrepancy with the stored Check value
* might be noticed. Storing the Check value with each preset
* is highly preferred.
*/
if(!plen(model->check))
mcheck(model);
}
void
mcheck(model_t *model) {
/* calculate a check for the model */
poly_t checkstr, check;
/* generate the check string with the correct bit order */
checkstr = strtop("313233343536373839", model->flags, 8);
check = pcrc(checkstr, model->spoly, model->init, pzero, model->flags);
if(model->flags & P_REFOUT)
prev(&check);
psum(&check, model->xorout, 0UL);
model->check = check;
pfree(&checkstr);
}
void
mrev(model_t *model) {
/* reverse the model to calculate reversed CRCs */
/* Here we invert RefIn and RefOut so that the user need only
* reverse the order of characters in the arguments, not the
* characters themselves. If RefOut=True, the mirror image of
* Init seen through RefOut becomes XorOut, and as RefOut
* becomes false, the XorOut value moved to Init stays upright.
* If RefOut=False, Init transfers to XorOut without reflection
* but the new Init must be reflected to present the same image,
* as RefOut becomes true.
*/
poly_t temp;
prcp(&model->spoly);
if(model->flags & P_REFOUT)
prev(&model->init);
else
prev(&model->xorout);
/* exchange init and xorout */
temp = model->init;
model->init = model->xorout;
model->xorout = temp;
/* invert refin and refout */
model->flags ^= P_REFIN | P_REFOUT;
mnovel(model);
}
void
mnovel(model_t *model) {
/* remove name and check string from modified model */
model->name = NULL;
pfree(&model->check);
}