fix little endian vs big endian in the macros... again... but this time correct
[RRG-proxmark3.git] / client / src / cmdcrc.c
blob4f241dcee1485c9aa7a811929ad762fb38266ff7
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2015 iceman <iceman at iuse.se>
3 //
4 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
5 // at your option, any later version. See the LICENSE.txt file for the text of
6 // the license.
7 //-----------------------------------------------------------------------------
8 // CRC Calculations from the software reveng commands
9 //-----------------------------------------------------------------------------
10 #include "cmdcrc.h"
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <ctype.h>
17 #ifdef _WIN32
18 # include <io.h>
19 # include <fcntl.h>
20 # ifndef STDIN_FILENO
21 # define STDIN_FILENO 0
22 # endif /* STDIN_FILENO */
23 #endif /* _WIN32 */
25 #include "reveng.h"
26 #include "ui.h"
27 #include "util.h"
28 #include "pm3_cmd.h"
30 #define MAX_ARGS 20
32 static int split(char *str, char *arr[MAX_ARGS]) {
33 int beginIndex = 0;
34 int wordCnt = 0;
36 while (1) {
37 while (isspace(str[beginIndex])) {
38 ++beginIndex;
40 if (str[beginIndex] == '\0') {
41 break;
43 int endIndex = beginIndex;
44 while (str[endIndex] && !isspace(str[endIndex])) {
45 ++endIndex;
47 int len = endIndex - beginIndex;
48 char *tmp = calloc(len + 1, sizeof(char));
49 memcpy(tmp, &str[beginIndex], len);
50 arr[wordCnt++] = tmp;
51 beginIndex = endIndex;
52 if (wordCnt == MAX_ARGS)
53 break;
55 return wordCnt;
58 //returns array of model names and the count of models returning
59 // as well as a width array for the width of each model
60 int GetModels(char *Models[], int *count, uint8_t *width) {
61 /* default values */
62 static model_t model = MZERO;
64 poly_t apoly, crc, qpoly = PZERO, *apolys = NULL, *pptr = NULL, *qptr = NULL;
65 model_t pset = model;
67 /* stdin must be binary */
68 #ifdef _WIN32
69 _setmode(STDIN_FILENO, _O_BINARY);
70 #endif /* _WIN32 */
72 SETBMP();
74 if (width[0] == 0) { //reveng -D
75 *count = mcount();
76 if (!*count) {
77 PrintAndLogEx(WARNING, "no preset models available");
78 return 0;
80 for (int mode = 0; mode < *count; ++mode) {
81 mbynum(&model, mode);
82 mcanon(&model);
83 size_t size = (model.name && *model.name) ? strlen(model.name) : 7;
84 char *tmp = calloc(size + 1, sizeof(char));
85 if (tmp == NULL) {
86 PrintAndLogEx(WARNING, "out of memory?");
87 return 0;
89 if (model.name != NULL) {
90 memcpy(tmp, model.name, size);
91 Models[mode] = tmp;
92 width[mode] = plen(model.spoly);
93 } else {
94 free(tmp);
97 mfree(&model);
98 } else { //reveng -s
100 int ibperhx = 8;//, obperhx = 8;
101 int rflags = 0, uflags = 0; /* search and UI flags */
102 if (~model.flags & P_MULXN) {
103 PrintAndLogEx(WARNING, "cannot search for non-Williams compliant models");
104 return 0;
106 praloc(&model.spoly, (unsigned long)width[0]);
107 praloc(&model.init, (unsigned long)width[0]);
108 praloc(&model.xorout, (unsigned long)width[0]);
110 if (!plen(model.spoly))
111 palloc(&model.spoly, (unsigned long)width[0]);
112 else
113 width[0] = (uint8_t)plen(model.spoly);
115 /* special case if qpoly is zero, search to end of range */
116 if (!ptst(qpoly))
117 rflags &= ~R_HAVEQ;
119 int pass;
121 /* if endianness not specified, try
122 * little-endian then big-endian.
123 * NB: crossed-endian algorithms will not be
124 * searched.
126 /* scan against preset models */
127 if (~uflags & C_NOPCK) {
128 pass = 0;
129 int Cnt = 0;
130 do {
131 int psets = mcount();
133 while (psets) {
134 mbynum(&pset, --psets);
136 /* skip if different width, or refin or refout don't match */
137 if (plen(pset.spoly) != width[0] || (model.flags ^ pset.flags) & (P_REFIN | P_REFOUT))
138 continue;
139 /* skip if the preset doesn't match specified parameters */
140 if (rflags & R_HAVEP && pcmp(&model.spoly, &pset.spoly))
141 continue;
142 if (rflags & R_HAVEI && psncmp(&model.init, &pset.init))
143 continue;
144 if (rflags & R_HAVEX && psncmp(&model.xorout, &pset.xorout))
145 continue;
147 //for additional args (not used yet, maybe future?)
148 apoly = pclone(pset.xorout);
150 if (pset.flags & P_REFOUT)
151 prev(&apoly);
154 for (qptr = apolys; qptr < pptr; ++qptr) {
155 crc = pcrc(*qptr, pset.spoly, pset.init, apoly, 0);
156 if (ptst(crc)) {
157 pfree(&crc);
158 break;
160 pfree(&crc);
162 pfree(&apoly);
164 if (qptr == pptr) {
166 /* the selected model solved all arguments */
167 mcanon(&pset);
169 size_t size = (pset.name && *pset.name) ? strlen(pset.name) : 7;
170 //PrintAndLogEx(NORMAL, "Size: %d, %s, count: %d",size,pset.name, Cnt);
171 char *tmp = calloc(size + 1, sizeof(char));
172 if (tmp == NULL) {
173 PrintAndLogEx(WARNING, "out of memory?");
174 return 0;
176 width[Cnt] = width[0];
177 memcpy(tmp, pset.name, size);
178 Models[Cnt++] = tmp;
179 *count = Cnt;
180 uflags |= C_RESULT;
183 mfree(&pset);
185 /* toggle refIn/refOut and reflect arguments */
186 if (~rflags & R_HAVERI) {
187 model.flags ^= P_REFIN | P_REFOUT;
188 for (qptr = apolys; qptr < pptr; ++qptr) {
189 prevch(qptr, ibperhx);
192 } while (~rflags & R_HAVERI && ++pass < 2);
194 //got everything now free the memory...
196 if (uflags & C_RESULT) {
197 for (qptr = apolys; qptr < pptr; ++qptr) {
198 pfree(qptr);
201 if (uflags & C_NOBFS && ~rflags & R_HAVEP) {
202 PrintAndLogEx(WARNING, "no models found");
203 return 0;
206 if (!(model.flags & P_REFIN) != !(model.flags & P_REFOUT)) {
207 PrintAndLogEx(WARNING, "cannot search for crossed-endian models");
208 return 0;
210 pass = 0;
211 int args = 0;
212 do {
213 model_t *candmods = reveng(&model, qpoly, rflags, args, apolys);
214 model_t *mptr = candmods;
215 if (mptr && plen(mptr->spoly)) {
216 uflags |= C_RESULT;
218 while (mptr && plen(mptr->spoly)) {
219 mfree(mptr++);
221 free(candmods);
222 if (~rflags & R_HAVERI) {
223 model.flags ^= P_REFIN | P_REFOUT;
224 for (qptr = apolys; qptr < pptr; ++qptr) {
225 prevch(qptr, ibperhx);
228 } while (~rflags & R_HAVERI && ++pass < 2);
230 for (qptr = apolys; qptr < pptr; ++qptr) {
231 pfree(qptr);
233 free(apolys);
234 mfree(&model);
236 if (~uflags & C_RESULT) {
237 PrintAndLogEx(WARNING, "no models found");
238 return 0;
241 return 1;
244 //-c || -v
245 //inModel = valid model name string - CRC-8
246 //inHexStr = input hex string to calculate crc on
247 //reverse = reverse calc option if true
248 //endian = {0 = calc default endian input and output, b = big endian input and output, B = big endian output, r = right justified
249 // l = little endian input and output, L = little endian output only, t = left justified}
250 //result = calculated crc hex string
251 int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *result) {
252 /* default values */
253 static model_t model = MZERO;
255 int ibperhx = 8, obperhx = 8;
256 // int rflags = 0; // search flags
257 poly_t apoly, crc;
259 char *string;
261 // stdin must be binary
262 #ifdef _WIN32
263 _setmode(STDIN_FILENO, _O_BINARY);
264 #endif /* _WIN32 */
266 SETBMP();
267 //set model
268 int c = mbynam(&model, inModel);
269 if (!c) {
270 PrintAndLogEx(ERR, "error: preset model '%s' not found. Use reveng -D to list presets. [%d]", inModel, c);
271 return 0;
273 if (c < 0) {
274 PrintAndLogEx(WARNING, "no preset models available");
275 return 0;
277 // rflags |= R_HAVEP | R_HAVEI | R_HAVERI | R_HAVERO | R_HAVEX;
279 //set flags
280 switch (endian) {
281 case 'b': /* b big-endian (RefIn = false, RefOut = false ) */
282 model.flags &= ~P_REFIN;
283 //rflags |= R_HAVERI;
284 /* fall through: */
285 case 'B': /* B big-endian output (RefOut = false) */
286 model.flags &= ~P_REFOUT;
287 //rflags |= R_HAVERO;
288 mnovel(&model);
289 /* fall through: */
290 case 'r': /* r right-justified */
291 model.flags |= P_RTJUST;
292 break;
293 case 'l': /* l little-endian input and output */
294 model.flags |= P_REFIN;
295 //rflags |= R_HAVERI;
296 /* fall through: */
297 case 'L': /* L little-endian output */
298 model.flags |= P_REFOUT;
299 //rflags |= R_HAVERO;
300 mnovel(&model);
301 /* fall through: */
302 case 't': /* t left-justified */
303 model.flags &= ~P_RTJUST;
304 break;
306 /* canonicalise the model, so the one we dump is the one we
307 * calculate with (not with -s, spoly may be blank which will
308 * normalise to zero and clear init and xorout.)
310 mcanon(&model);
313 if (reverse) {
314 // v calculate reversed CRC
315 /* Distinct from the -V switch as this causes
316 * the arguments and output to be reversed as well.
318 // reciprocate Poly
319 prcp(&model.spoly);
321 /* mrev() does:
322 * if(refout) prev(init); else prev(xorout);
323 * but here the entire argument polynomial is
324 * reflected, not just the characters, so RefIn
325 * and RefOut are not inverted as with -V.
326 * Consequently Init is the mirror image of the
327 * one resulting from -V, and so we have:
329 if (~model.flags & P_REFOUT) {
330 prev(&model.init);
331 prev(&model.xorout);
334 // swap init and xorout
335 apoly = model.init;
336 model.init = model.xorout;
337 model.xorout = apoly;
339 // c calculate CRC
341 /* in the Williams model, xorout is applied after the refout stage.
342 * as refout is part of ptostr(), we reverse xorout here.
344 if (model.flags & P_REFOUT)
345 prev(&model.xorout);
347 apoly = strtop(inHexStr, model.flags, ibperhx);
349 if (reverse)
350 prev(&apoly);
352 crc = pcrc(apoly, model.spoly, model.init, model.xorout, model.flags);
354 if (reverse)
355 prev(&crc);
357 string = ptostr(crc, model.flags, obperhx);
358 for (int i = 0; i < 50; i++) {
359 result[i] = string[i];
360 if (result[i] == 0) break;
362 free(string);
363 pfree(&crc);
364 pfree(&apoly);
365 return 1;
368 //test call to RunModel
369 static int CmdrevengTestC(const char *Cmd) {
370 int cmdp = 0;
371 char inModel[30] = {0x00};
372 char inHexStr[30] = {0x00};
373 char result[30];
374 int dataLen;
375 char endian = 0;
376 dataLen = param_getstr(Cmd, cmdp++, inModel, sizeof(inModel));
377 if (dataLen < 4) return 0;
378 dataLen = param_getstr(Cmd, cmdp++, inHexStr, sizeof(inHexStr));
379 if (dataLen < 4) return 0;
380 bool reverse = (param_get8(Cmd, cmdp++)) ? true : false;
381 endian = param_getchar(Cmd, cmdp++);
383 //PrintAndLogEx(NORMAL, "mod: %s, hex: %s, rev %d", inModel, inHexStr, reverse);
384 int ans = RunModel(inModel, inHexStr, reverse, endian, result);
385 if (!ans) return 0;
387 PrintAndLogEx(SUCCESS, "result: %s", result);
388 return 1;
391 //returns a calloced string (needs to be freed)
392 static char *SwapEndianStr(const char *inStr, const size_t len, const uint8_t blockSize) {
393 char *tmp = calloc(len + 1, sizeof(char));
394 for (uint8_t block = 0; block < (uint8_t)(len / blockSize); block++) {
395 for (size_t i = 0; i < blockSize; i += 2) {
396 tmp[i + (blockSize * block)] = inStr[(blockSize - 1 - i - 1) + (blockSize * block)];
397 tmp[i + (blockSize * block) + 1] = inStr[(blockSize - 1 - i) + (blockSize * block)];
400 return tmp;
403 // takes hex string in and searches for a matching result (hex string must include checksum)
404 static int CmdrevengSearch(const char *Cmd) {
406 #define NMODELS 106
408 char inHexStr[256] = {0x00};
409 int dataLen = param_getstr(Cmd, 0, inHexStr, sizeof(inHexStr));
410 if (dataLen < 4) return 0;
412 // these two arrays, must match preset size.
413 char *Models[NMODELS];
414 uint8_t width[NMODELS] = {0};
415 int count = 0;
417 char result[30];
418 char revResult[30];
419 int ans = GetModels(Models, &count, width);
420 bool found = false;
421 if (!ans) {
422 for (int i = 0; i < count; i++) {
423 free(Models[i]);
425 return 0;
428 // try each model and get result
429 for (int i = 0; i < count; i++) {
430 /*if (found) {
431 free(Models[i]);
432 continue;
434 // round up to # of characters in this model's crc
435 uint8_t crcChars = ((width[i] + 7) / 8) * 2;
436 // can't test a model that has more crc digits than our data
437 if (crcChars >= dataLen) {
438 free(Models[i]);
439 continue;
442 PrintAndLogEx(DEBUG
443 , "DEBUG: dataLen %d, crcChars %u, width[i] %u"
444 , dataLen
445 , crcChars
446 , width[i]
449 if (crcChars == 0) {
450 free(Models[i]);
451 continue;
454 memset(result, 0, 30);
455 char *inCRC = calloc(crcChars + 1, sizeof(char));
456 memcpy(inCRC, inHexStr + (dataLen - crcChars), crcChars);
458 char *outHex = calloc(dataLen - crcChars + 1, sizeof(char));
459 memcpy(outHex, inHexStr, dataLen - crcChars);
461 ans = RunModel(Models[i], outHex, false, 0, result);
462 if (ans) {
463 // test for match
464 if (memcmp(result, inCRC, crcChars) == 0) {
465 PrintAndLogEx(SUCCESS, "\nfound possible match\nmodel: %s | value: %s\n", Models[i], result);
466 //optional - stop searching if found...
467 found = true;
468 } else {
469 if (crcChars > 2) {
470 char *swapEndian = SwapEndianStr(result, crcChars, crcChars);
471 if (memcmp(swapEndian, inCRC, crcChars) == 0) {
472 PrintAndLogEx(SUCCESS, "\nfound possible match\nmodel: %s | value endian swapped: %s\n", Models[i], swapEndian);
473 // optional - stop searching if found...
474 found = true;
476 free(swapEndian);
480 ans = RunModel(Models[i], outHex, true, 0, revResult);
481 if (ans) {
482 // test for match
483 if (memcmp(revResult, inCRC, crcChars) == 0) {
484 PrintAndLogEx(SUCCESS, "\nfound possible match\nmodel reversed: %s | value: %s\n", Models[i], revResult);
485 // optional - stop searching if found...
486 found = true;
487 } else {
488 if (crcChars > 2) {
489 char *swapEndian = SwapEndianStr(revResult, crcChars, crcChars);
490 if (memcmp(swapEndian, inCRC, crcChars) == 0) {
491 PrintAndLogEx(SUCCESS, "\nfound possible match\nmodel reversed: %s | value endian swapped: %s\n", Models[i], swapEndian);
492 // optional - stop searching if found...
493 found = true;
495 free(swapEndian);
499 free(inCRC);
500 free(outHex);
501 free(Models[i]);
504 if (found == false)
505 PrintAndLogEx(FAILED, "\nno matches found\n");
507 return PM3_SUCCESS;
510 int CmdCrc(const char *Cmd) {
511 char c[100 + 7];
512 snprintf(c, sizeof(c), "reveng ");
513 snprintf(c + strlen(c), sizeof(c) - strlen(c), Cmd, strlen(Cmd));
515 char *argv[MAX_ARGS];
516 int argc = split(c, argv);
518 if (argc == 3 && memcmp(argv[1], "-g", 2) == 0) {
519 CmdrevengSearch(argv[2]);
520 } else {
521 reveng_main(argc, argv);
524 for (int i = 0; i < argc; ++i) {
525 free(argv[i]);
527 return PM3_SUCCESS;