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