]>
Commit | Line | Data |
---|---|---|
9962091e | 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 | ||
60e86577 | 11 | #include <stdlib.h> |
12 | #ifdef _WIN32 | |
13 | # include <io.h> | |
14 | # include <fcntl.h> | |
15 | # ifndef STDIN_FILENO | |
16 | # define STDIN_FILENO 0 | |
17 | # endif /* STDIN_FILENO */ | |
18 | #endif /* _WIN32 */ | |
19 | ||
9962091e | 20 | #include <stdio.h> |
21 | #include <string.h> | |
a71ece51 | 22 | #include "cmdmain.h" |
9962091e | 23 | #include "cmdcrc.h" |
a71ece51 | 24 | #include "reveng/reveng.h" |
25 | #include "ui.h" | |
26 | #include "util.h" | |
9962091e | 27 | |
a71ece51 | 28 | #define MAX_ARGS 20 |
9962091e | 29 | |
60e86577 | 30 | int uerr(char *msg){ |
31 | PrintAndLog("%s",msg); | |
32 | return 0; | |
33 | } | |
34 | ||
a71ece51 | 35 | int split(char *str, char *arr[MAX_ARGS]){ |
36 | int beginIndex = 0; | |
37 | int endIndex; | |
38 | int maxWords = MAX_ARGS; | |
39 | int wordCnt = 0; | |
40 | ||
41 | while(1){ | |
9c624f67 | 42 | while(isspace(str[beginIndex])) { |
a71ece51 | 43 | ++beginIndex; |
44 | } | |
9c624f67 | 45 | if(str[beginIndex] == '\0') { |
a71ece51 | 46 | break; |
9c624f67 | 47 | } |
a71ece51 | 48 | endIndex = beginIndex; |
9c624f67 | 49 | while (str[endIndex] && !isspace(str[endIndex])) { |
a71ece51 | 50 | ++endIndex; |
51 | } | |
52 | int len = endIndex - beginIndex; | |
53 | char *tmp = calloc(len + 1, sizeof(char)); | |
54 | memcpy(tmp, &str[beginIndex], len); | |
55 | arr[wordCnt++] = tmp; | |
56 | //PrintAndLog("cnt: %d, %s",wordCnt-1, arr[wordCnt-1]); | |
57 | beginIndex = endIndex; | |
58 | if (wordCnt == maxWords) | |
59 | break; | |
60 | } | |
61 | return wordCnt; | |
62 | } | |
9962091e | 63 | |
64 | int CmdCrc(const char *Cmd) | |
65 | { | |
a71ece51 | 66 | char name[] = {"reveng "}; |
67 | char Cmd2[50 + 7]; | |
68 | memcpy(Cmd2, name, 7); | |
69 | memcpy(Cmd2 + 7, Cmd, 50); | |
70 | char *argv[MAX_ARGS]; | |
71 | int argc = split(Cmd2, argv); | |
99789601 | 72 | |
73 | if (argc == 3 && memcmp(argv[1],"-g",2)==0) { | |
74 | CmdrevengSearch(argv[2]); | |
75 | } else { | |
13629a71 | 76 | reveng_main(argc, argv); |
99789601 | 77 | } |
78 | //PrintAndLog("DEBUG argc: %d, %s %s Cmd: %s",argc, argv[0], Cmd2, Cmd); | |
13629a71 | 79 | for(int i = 0; i < argc; ++i) { |
a71ece51 | 80 | free(argv[i]); |
81 | } | |
82 | ||
9962091e | 83 | return 0; |
84 | } | |
85 | ||
99789601 | 86 | //returns array of model names and the count of models returning |
87 | // as well as a width array for the width of each model | |
88 | int GetModels(char *Models[], int *count, uint8_t *width){ | |
60e86577 | 89 | /* default values */ |
90 | static model_t model = { | |
91 | PZERO, /* no CRC polynomial, user must specify */ | |
92 | PZERO, /* Init = 0 */ | |
93 | P_BE, /* RefIn = false, RefOut = false, plus P_RTJUST setting in reveng.h */ | |
94 | PZERO, /* XorOut = 0 */ | |
95 | PZERO, /* check value unused */ | |
96 | NULL /* no model name */ | |
97 | }; | |
dd1df490 | 98 | |
60e86577 | 99 | int ibperhx = 8;//, obperhx = 8; |
100 | int rflags = 0, uflags = 0; /* search and UI flags */ | |
60e86577 | 101 | poly_t apoly, crc, qpoly = PZERO, *apolys = NULL, *pptr = NULL, *qptr = NULL; |
102 | model_t pset = model, *candmods, *mptr; | |
103 | ||
104 | /* stdin must be binary */ | |
105 | #ifdef _WIN32 | |
106 | _setmode(STDIN_FILENO, _O_BINARY); | |
107 | #endif /* _WIN32 */ | |
108 | ||
109 | SETBMP(); | |
110 | ||
111 | int args = 0, psets, pass; | |
112 | int Cnt = 0; | |
99789601 | 113 | if (width[0] == 0) { //reveng -D |
60e86577 | 114 | *count = mcount(); |
60e86577 | 115 | if(!*count) |
116 | return uerr("no preset models available"); | |
117 | ||
118 | for(int mode = 0; mode < *count; ++mode) { | |
119 | mbynum(&model, mode); | |
120 | mcanon(&model); | |
121 | size_t size = (model.name && *model.name) ? strlen(model.name) : 6; | |
60e86577 | 122 | char *tmp = calloc(size+1, sizeof(char)); |
123 | if (tmp==NULL) | |
124 | return uerr("out of memory?"); | |
125 | ||
126 | memcpy(tmp, model.name, size); | |
127 | Models[mode] = tmp; | |
99789601 | 128 | width[mode] = plen(model.spoly); |
60e86577 | 129 | } |
dd1df490 | 130 | mfree(&model); |
60e86577 | 131 | } else { //reveng -s |
132 | ||
13629a71 | 133 | if(~model.flags & P_MULXN) |
134 | return uerr("cannot search for non-Williams compliant models"); | |
60e86577 | 135 | |
99789601 | 136 | praloc(&model.spoly, (unsigned long)width[0]); |
137 | praloc(&model.init, (unsigned long)width[0]); | |
138 | praloc(&model.xorout, (unsigned long)width[0]); | |
13629a71 | 139 | |
140 | if(!plen(model.spoly)) | |
99789601 | 141 | palloc(&model.spoly, (unsigned long)width[0]); |
13629a71 | 142 | else |
99789601 | 143 | width[0] = (uint8_t)plen(model.spoly); |
60e86577 | 144 | |
13629a71 | 145 | /* special case if qpoly is zero, search to end of range */ |
146 | if(!ptst(qpoly)) | |
147 | rflags &= ~R_HAVEQ; | |
60e86577 | 148 | |
13629a71 | 149 | /* if endianness not specified, try |
150 | * little-endian then big-endian. | |
151 | * NB: crossed-endian algorithms will not be | |
152 | * searched. | |
153 | */ | |
154 | /* scan against preset models */ | |
9c624f67 | 155 | if (~uflags & C_FORCE) { |
13629a71 | 156 | pass = 0; |
157 | Cnt = 0; | |
158 | do { | |
159 | psets = mcount(); | |
160 | ||
161 | while(psets) { | |
162 | mbynum(&pset, --psets); | |
163 | ||
164 | /* skip if different width, or refin or refout don't match */ | |
9c624f67 | 165 | if( plen(pset.spoly) != width[0] || (model.flags ^ pset.flags) & (P_REFIN | P_REFOUT)) |
13629a71 | 166 | continue; |
167 | /* skip if the preset doesn't match specified parameters */ | |
9c624f67 | 168 | if (rflags & R_HAVEP && pcmp(&model.spoly, &pset.spoly)) |
13629a71 | 169 | continue; |
9c624f67 | 170 | if (rflags & R_HAVEI && psncmp(&model.init, &pset.init)) |
13629a71 | 171 | continue; |
9c624f67 | 172 | if (rflags & R_HAVEX && psncmp(&model.xorout, &pset.xorout)) |
13629a71 | 173 | continue; |
174 | ||
9c624f67 | 175 | //for additional args (not used yet, maybe future?) |
13629a71 | 176 | apoly = pclone(pset.xorout); |
9c624f67 | 177 | |
178 | if (pset.flags & P_REFOUT) | |
13629a71 | 179 | prev(&apoly); |
9c624f67 | 180 | |
181 | ||
182 | for (qptr = apolys; qptr < pptr; ++qptr) { | |
13629a71 | 183 | crc = pcrc(*qptr, pset.spoly, pset.init, apoly, 0); |
9c624f67 | 184 | if (ptst(crc)) { |
13629a71 | 185 | pfree(&crc); |
186 | break; | |
9c624f67 | 187 | } |
188 | pfree(&crc); | |
60e86577 | 189 | } |
13629a71 | 190 | pfree(&apoly); |
9c624f67 | 191 | |
192 | if (qptr == pptr) { | |
99789601 | 193 | |
13629a71 | 194 | /* the selected model solved all arguments */ |
13629a71 | 195 | mcanon(&pset); |
196 | ||
197 | size_t size = (pset.name && *pset.name) ? strlen(pset.name) : 6; | |
198 | //PrintAndLog("Size: %d, %s, count: %d",size,pset.name, Cnt); | |
199 | char *tmp = calloc(size+1, sizeof(char)); | |
200 | if (tmp == NULL){ | |
201 | PrintAndLog("out of memory?"); | |
202 | return 0; | |
203 | } | |
9c624f67 | 204 | width[Cnt] = width[0]; |
13629a71 | 205 | memcpy(tmp, pset.name, size); |
206 | Models[Cnt++] = tmp; | |
207 | *count = Cnt; | |
208 | uflags |= C_RESULT; | |
209 | } | |
60e86577 | 210 | } |
13629a71 | 211 | mfree(&pset); |
212 | ||
213 | /* toggle refIn/refOut and reflect arguments */ | |
9c624f67 | 214 | if (~rflags & R_HAVERI) { |
60e86577 | 215 | model.flags ^= P_REFIN | P_REFOUT; |
9c624f67 | 216 | for (qptr = apolys; qptr < pptr; ++qptr) { |
60e86577 | 217 | prevch(qptr, ibperhx); |
9c624f67 | 218 | } |
60e86577 | 219 | } |
9c624f67 | 220 | } while (~rflags & R_HAVERI && ++pass < 2); |
13629a71 | 221 | } |
222 | //got everything now free the memory... | |
223 | ||
9c624f67 | 224 | if (uflags & C_RESULT) { |
225 | for (qptr = apolys; qptr < pptr; ++qptr) { | |
60e86577 | 226 | pfree(qptr); |
9c624f67 | 227 | } |
13629a71 | 228 | } |
9c624f67 | 229 | if (!(model.flags & P_REFIN) != !(model.flags & P_REFOUT)) |
13629a71 | 230 | return uerr("cannot search for crossed-endian models"); |
231 | ||
232 | pass = 0; | |
233 | do { | |
234 | mptr = candmods = reveng(&model, qpoly, rflags, args, apolys); | |
9c624f67 | 235 | if (mptr && plen(mptr->spoly)) { |
13629a71 | 236 | uflags |= C_RESULT; |
9c624f67 | 237 | } |
238 | while (mptr && plen(mptr->spoly)) { | |
13629a71 | 239 | mfree(mptr++); |
240 | } | |
241 | free(candmods); | |
9c624f67 | 242 | if (~rflags & R_HAVERI) { |
13629a71 | 243 | model.flags ^= P_REFIN | P_REFOUT; |
9c624f67 | 244 | for (qptr = apolys; qptr < pptr; ++qptr) { |
13629a71 | 245 | prevch(qptr, ibperhx); |
9c624f67 | 246 | } |
13629a71 | 247 | } |
9c624f67 | 248 | } while (~rflags & R_HAVERI && ++pass < 2); |
249 | ||
250 | for (qptr = apolys; qptr < pptr; ++qptr) { | |
13629a71 | 251 | pfree(qptr); |
9c624f67 | 252 | } |
13629a71 | 253 | free(apolys); |
9c624f67 | 254 | if (~uflags & C_RESULT) |
13629a71 | 255 | return uerr("no models found"); |
9c624f67 | 256 | |
13629a71 | 257 | mfree(&model); |
60e86577 | 258 | } |
259 | return 1; | |
260 | } | |
261 | ||
262 | //-c || -v | |
263 | //inModel = valid model name string - CRC-8 | |
264 | //inHexStr = input hex string to calculate crc on | |
265 | //reverse = reverse calc option if true | |
266 | //endian = {0 = calc default endian input and output, b = big endian input and output, B = big endian output, r = right justified | |
267 | // l = little endian input and output, L = little endian output only, t = left justified} | |
268 | //result = calculated crc hex string | |
269 | int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *result){ | |
270 | /* default values */ | |
271 | static model_t model = { | |
272 | PZERO, // no CRC polynomial, user must specify | |
273 | PZERO, // Init = 0 | |
274 | P_BE, // RefIn = false, RefOut = false, plus P_RTJUST setting in reveng.h | |
275 | PZERO, // XorOut = 0 | |
276 | PZERO, // check value unused | |
277 | NULL // no model name | |
278 | }; | |
279 | int ibperhx = 8, obperhx = 8; | |
280 | int rflags = 0; // search flags | |
281 | int c; | |
60e86577 | 282 | poly_t apoly, crc; |
283 | ||
284 | char *string; | |
285 | ||
286 | // stdin must be binary | |
287 | #ifdef _WIN32 | |
288 | _setmode(STDIN_FILENO, _O_BINARY); | |
289 | #endif /* _WIN32 */ | |
290 | ||
291 | SETBMP(); | |
292 | //set model | |
9c624f67 | 293 | if (!(c = mbynam(&model, inModel))) { |
dd1df490 | 294 | PrintAndLog("error: preset model '%s' not found. Use reveng -D to list presets.", inModel); |
60e86577 | 295 | return 0; |
296 | } | |
9c624f67 | 297 | if (c < 0) |
60e86577 | 298 | return uerr("no preset models available"); |
299 | ||
60e86577 | 300 | rflags |= R_HAVEP | R_HAVEI | R_HAVERI | R_HAVERO | R_HAVEX; |
301 | ||
302 | //set flags | |
303 | switch (endian) { | |
304 | case 'b': /* b big-endian (RefIn = false, RefOut = false ) */ | |
305 | model.flags &= ~P_REFIN; | |
306 | rflags |= R_HAVERI; | |
307 | /* fall through: */ | |
308 | case 'B': /* B big-endian output (RefOut = false) */ | |
309 | model.flags &= ~P_REFOUT; | |
310 | rflags |= R_HAVERO; | |
311 | mnovel(&model); | |
312 | /* fall through: */ | |
313 | case 'r': /* r right-justified */ | |
314 | model.flags |= P_RTJUST; | |
315 | break; | |
316 | case 'l': /* l little-endian input and output */ | |
317 | model.flags |= P_REFIN; | |
318 | rflags |= R_HAVERI; | |
319 | /* fall through: */ | |
320 | case 'L': /* L little-endian output */ | |
321 | model.flags |= P_REFOUT; | |
322 | rflags |= R_HAVERO; | |
323 | mnovel(&model); | |
324 | /* fall through: */ | |
325 | case 't': /* t left-justified */ | |
326 | model.flags &= ~P_RTJUST; | |
327 | break; | |
328 | } | |
13629a71 | 329 | /* canonicalise the model, so the one we dump is the one we |
330 | * calculate with (not with -s, spoly may be blank which will | |
331 | * normalise to zero and clear init and xorout.) | |
332 | */ | |
60e86577 | 333 | mcanon(&model); |
334 | ||
13629a71 | 335 | |
60e86577 | 336 | if (reverse) { |
337 | // v calculate reversed CRC | |
338 | /* Distinct from the -V switch as this causes | |
339 | * the arguments and output to be reversed as well. | |
340 | */ | |
341 | // reciprocate Poly | |
342 | prcp(&model.spoly); | |
343 | ||
344 | /* mrev() does: | |
345 | * if(refout) prev(init); else prev(xorout); | |
346 | * but here the entire argument polynomial is | |
347 | * reflected, not just the characters, so RefIn | |
348 | * and RefOut are not inverted as with -V. | |
349 | * Consequently Init is the mirror image of the | |
350 | * one resulting from -V, and so we have: | |
351 | */ | |
9c624f67 | 352 | if (~model.flags & P_REFOUT) { |
60e86577 | 353 | prev(&model.init); |
354 | prev(&model.xorout); | |
355 | } | |
356 | ||
357 | // swap init and xorout | |
358 | apoly = model.init; | |
359 | model.init = model.xorout; | |
360 | model.xorout = apoly; | |
361 | } | |
362 | // c calculate CRC | |
363 | ||
364 | /* in the Williams model, xorout is applied after the refout stage. | |
365 | * as refout is part of ptostr(), we reverse xorout here. | |
366 | */ | |
9c624f67 | 367 | if (model.flags & P_REFOUT) |
60e86577 | 368 | prev(&model.xorout); |
369 | ||
370 | apoly = strtop(inHexStr, model.flags, ibperhx); | |
371 | ||
9c624f67 | 372 | if (reverse) |
60e86577 | 373 | prev(&apoly); |
374 | ||
375 | crc = pcrc(apoly, model.spoly, model.init, model.xorout, model.flags); | |
376 | ||
9c624f67 | 377 | if (reverse) |
60e86577 | 378 | prev(&crc); |
379 | ||
380 | string = ptostr(crc, model.flags, obperhx); | |
381 | for (int i = 0; i < 50; i++){ | |
382 | result[i] = string[i]; | |
383 | if (result[i]==0) break; | |
384 | } | |
385 | free(string); | |
386 | pfree(&crc); | |
387 | pfree(&apoly); | |
388 | return 1; | |
389 | } | |
99789601 | 390 | //returns a calloced string (needs to be freed) |
391 | char *SwapEndianStr(const char *inStr, const size_t len, const uint8_t blockSize){ | |
392 | char *tmp = calloc(len+1, sizeof(char)); | |
393 | for (uint8_t block=0; block < (uint8_t)(len/blockSize); block++){ | |
394 | for (size_t i = 0; i < blockSize; i+=2){ | |
395 | tmp[i+(blockSize*block)] = inStr[(blockSize-1-i-1)+(blockSize*block)]; | |
396 | tmp[i+(blockSize*block)+1] = inStr[(blockSize-1-i)+(blockSize*block)]; | |
397 | } | |
398 | } | |
399 | return tmp; | |
400 | } | |
401 | ||
402 | // takes hex string in and searches for a matching result (hex string must include checksum) | |
403 | int CmdrevengSearch(const char *Cmd){ | |
404 | char inHexStr[50] = {0x00}; | |
405 | int dataLen = param_getstr(Cmd, 0, inHexStr); | |
406 | if (dataLen < 4) return 0; | |
407 | ||
408 | char *Models[80]; | |
409 | int count = 0; | |
410 | uint8_t width[80]; | |
411 | width[0] = 0; | |
412 | uint8_t crcChars = 0; | |
413 | char result[30]; | |
414 | char revResult[30]; | |
415 | int ans = GetModels(Models, &count, width); | |
416 | bool found = false; | |
417 | if (!ans) return 0; | |
418 | ||
419 | // try each model and get result | |
420 | for (int i = 0; i < count; i++){ | |
421 | /*if (found) { | |
422 | free(Models[i]); | |
423 | continue; | |
424 | }*/ | |
425 | // round up to # of characters in this model's crc | |
426 | crcChars = ((width[i]+7)/8)*2; | |
427 | // can't test a model that has more crc digits than our data | |
428 | if (crcChars >= dataLen) | |
429 | continue; | |
430 | memset(result, 0, 30); | |
431 | char *inCRC = calloc(crcChars+1, sizeof(char)); | |
432 | memcpy(inCRC, inHexStr+(dataLen-crcChars), crcChars); | |
433 | ||
434 | char *outHex = calloc(dataLen-crcChars+1, sizeof(char)); | |
435 | memcpy(outHex, inHexStr, dataLen-crcChars); | |
436 | ||
437 | //PrintAndLog("DEBUG: dataLen: %d, crcChars: %d, Model: %s, CRC: %s, width: %d, outHex: %s",dataLen, crcChars, Models[i], inCRC, width[i], outHex); | |
438 | ans = RunModel(Models[i], outHex, false, 0, result); | |
439 | if (ans) { | |
440 | //test for match | |
441 | if (memcmp(result, inCRC, crcChars)==0){ | |
1417a7f9 | 442 | PrintAndLog("\nFound a possible match!\nModel: %s\nValue: %s\n",Models[i], result); |
99789601 | 443 | //optional - stop searching if found... |
444 | found = true; | |
445 | } else { | |
446 | if (crcChars > 2){ | |
447 | char *swapEndian = SwapEndianStr(result, crcChars, crcChars); | |
448 | if (memcmp(swapEndian, inCRC, crcChars)==0){ | |
1417a7f9 | 449 | PrintAndLog("\nFound a possible match!\nModel: %s\nValue EndianSwapped: %s\n",Models[i], swapEndian); |
99789601 | 450 | //optional - stop searching if found... |
451 | found = true; | |
452 | } | |
453 | free(swapEndian); | |
454 | } | |
455 | } | |
456 | } | |
457 | ||
458 | //if (!found){ | |
459 | ans = RunModel(Models[i], outHex, true, 0, revResult); | |
460 | if (ans) { | |
461 | //test for match | |
462 | if (memcmp(revResult, inCRC, crcChars)==0){ | |
1417a7f9 | 463 | PrintAndLog("\nFound a possible match!\nModel Reversed: %s\nValue: %s\n",Models[i], revResult); |
99789601 | 464 | //optional - stop searching if found... |
465 | found = true; | |
466 | } else { | |
467 | if (crcChars > 2){ | |
468 | char *swapEndian = SwapEndianStr(revResult, crcChars, crcChars); | |
469 | if (memcmp(swapEndian, inCRC, crcChars)==0){ | |
1417a7f9 | 470 | PrintAndLog("\nFound a possible match!\nModel Reversed: %s\nValue EndianSwapped: %s\n",Models[i], swapEndian); |
99789601 | 471 | //optional - stop searching if found... |
472 | found = true; | |
473 | } | |
474 | free(swapEndian); | |
475 | } | |
476 | } | |
477 | } | |
478 | //} | |
479 | free(inCRC); | |
480 | free(outHex); | |
481 | free(Models[i]); | |
482 | } | |
483 | if (!found) PrintAndLog("\nNo matches found\n"); | |
484 | return 1; | |
1417a7f9 | 485 | } |