fix one too small
[RRG-proxmark3.git] / client / src / cmdhftexkom.c
blobb033050bad9ae3143b28ff2a60cb60344d9a519e
1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // High frequency proximity cards from TEXCOM commands
17 //-----------------------------------------------------------------------------
19 #include "cmdhftexkom.h"
21 #include <stdio.h>
22 #include <string.h>
23 #include <ctype.h>
24 #include "cliparser.h"
25 #include "cmdparser.h" // command_t
26 #include "comms.h"
27 #include "ui.h"
28 #include "cmdhf14a.h"
29 #include "cmddata.h"
30 #include "graph.h"
32 #define TEXKOM_NOISE_THRESHOLD (10)
34 static inline uint32_t GetGraphBuffer(uint32_t indx) {
35 if (g_GraphBuffer[indx] < -128)
36 return 0;
37 else
38 return g_GraphBuffer[indx] + 128;
41 static uint32_t TexkomAVGField(void) {
42 if (g_GraphTraceLen == 0)
43 return 0;
45 uint64_t vsum = 0;
46 for (uint32_t i = 0; i < g_GraphTraceLen; i++)
47 vsum += GetGraphBuffer(i);
49 return vsum / g_GraphTraceLen;
52 static uint32_t TexkomSearchStart(uint32_t indx, uint32_t threshold) {
53 // one bit length = 27, minimal noise = 60
54 uint32_t lownoisectr = 0;
55 for (uint32_t i = indx; i < g_GraphTraceLen; i++) {
56 if (lownoisectr > 60) {
57 if (GetGraphBuffer(i) > threshold)
58 return i;
59 } else {
60 if (GetGraphBuffer(i) > threshold)
61 lownoisectr = 0;
62 else
63 lownoisectr++;
67 return 0;
70 static uint32_t TexkomSearchLength(uint32_t indx, uint32_t threshold) {
71 // one bit length = 27, minimal noise = 60
72 uint32_t lownoisectr = 0;
73 uint32_t datalen = 0;
74 for (uint32_t i = indx; i < g_GraphTraceLen; i++) {
75 if (lownoisectr > 60) {
76 break;
77 } else {
78 if (GetGraphBuffer(i) > threshold) {
79 lownoisectr = 0;
80 datalen = i - indx + 27;
81 } else {
82 lownoisectr++;
87 return datalen;
90 static uint32_t TexkomSearchMax(uint32_t indx, uint32_t len) {
91 uint32_t res = 0;
93 for (uint32_t i = 0; i < len; i++) {
94 if (i + indx > g_GraphTraceLen)
95 break;
97 if (GetGraphBuffer(indx + i) > res)
98 res = GetGraphBuffer(indx + i);
101 return res;
104 static bool TexkomCorrelate(uint32_t indx, uint32_t threshold) {
105 if (indx < 2 || indx + 2 > g_GraphTraceLen)
106 return false;
108 uint32_t g1 = GetGraphBuffer(indx - 2);
109 uint32_t g2 = GetGraphBuffer(indx - 1);
110 uint32_t g3 = GetGraphBuffer(indx);
111 uint32_t g4 = GetGraphBuffer(indx + 1);
112 uint32_t g5 = GetGraphBuffer(indx + 2);
114 return (
115 (g3 > threshold) &&
116 (g3 >= g2) && (g3 >= g1) && (g3 > g4) && (g3 > g5)
120 static bool TexkomCalculateMaxMin(const uint32_t *data, uint32_t len, uint32_t *dmax, uint32_t *dmin) {
121 *dmax = 0;
122 *dmin = 0xffffffff;
123 for (size_t i = 0; i < len; i++) {
124 if (data[i] > *dmax)
125 *dmax = data[i];
126 if (data[i] < *dmin)
127 *dmin = data[i];
130 return (*dmax != 0) && (*dmin != 0xffffffff) && (*dmax > *dmin);
133 static bool TexkomCalculateBitLengths(uint32_t *data, uint32_t len, uint32_t *hi, uint32_t *low, uint32_t *lmax, uint32_t *lmin) {
134 *hi = 0;
135 *low = 0;
137 uint32_t dmax = 0;
138 uint32_t dmin = 0xffffffff;
139 if (!TexkomCalculateMaxMin(data, len, &dmax, &dmin))
140 return false;
142 uint32_t dmiddle = (dmax + dmin) / 2;
143 uint32_t sumhi = 0;
144 uint32_t lenhi = 0;
145 uint32_t sumlow = 0;
146 uint32_t lenlow = 0;
147 for (size_t i = 0; i < len; i++) {
148 if (data[i] > dmiddle) {
149 sumhi += data[i];
150 lenhi++;
151 } else {
152 sumlow += data[i];
153 lenlow++;
157 if (lenhi)
158 *hi = sumhi / lenhi;
160 if (lenlow)
161 *low = sumlow / lenlow;
163 if (lmax != NULL)
164 *lmax = dmax;
165 if (lmin != NULL)
166 *lmin = dmin;
168 return (*hi != 0) && (*low != 0) && (*hi > *low);
171 static inline bool TexcomCalculateBit(uint32_t data, uint32_t bitlen, uint32_t threshold) {
172 return
173 (data < (bitlen + threshold)) &&
174 (data > (bitlen - threshold));
177 // code from https://github.com/li0ard/crclib/blob/main/index.js
178 static uint8_t TexcomTK13CRC(const uint8_t *data) {
179 uint8_t crc = 0;
180 uint8_t indx = 0;
181 while (indx < 4) {
182 crc = crc ^ data[indx++];
184 for (uint8_t i = 0; i < 8; i++)
185 if (crc & 0x80) {
186 crc = 0x31 ^ (crc << 1);
187 } else
188 crc <<= 1;
191 return crc;
194 static uint8_t MMBITCRC(const uint8_t *data) {
195 return
196 (((data[0] & 0x0f) ^ ((data[0] >> 4) & 0x0f) ^
197 (data[1] & 0x0f) ^ ((data[1] >> 4) & 0x0f) ^
198 (data[2] & 0x0f) ^ ((data[2] >> 4) & 0x0f)
199 ) ^ 0x0f
200 ) & 0x0f;
203 static unsigned char dallas_crc8(const unsigned char *data, const unsigned int size) {
204 unsigned char crc = 0;
205 for (unsigned int i = 0; i < size; ++i) {
206 unsigned char inbyte = data[i];
207 for (unsigned char j = 0; j < 8; ++j) {
208 unsigned char mix = (crc ^ inbyte) & 0x01;
209 crc >>= 1;
210 if (mix) crc ^= 0x8C;
211 inbyte >>= 1;
214 return crc;
217 // code from https://github.com/li0ard/crclib/blob/main/index.js
218 static uint8_t TexcomTK17CRC(uint8_t *data) {
219 uint8_t ddata[8] = {0x00, 0x00, 0x00, data[0], data[1], data[2], data[3], 0x00};
221 return dallas_crc8(ddata, 7);
224 static bool TexcomTK13Decode(uint32_t *implengths, uint32_t implengthslen, char *bitstring, char *cbitstring, bool verbose) {
225 bitstring[0] = 0;
226 cbitstring[0] = 0;
227 if (implengthslen == 0)
228 return false;
230 uint32_t hilength = 0;
231 uint32_t lowlength = 0;
232 if (!TexkomCalculateBitLengths(implengths, implengthslen, &hilength, &lowlength, NULL, NULL))
233 return false;
235 uint32_t threshold = (hilength - lowlength) / 3 + 1;
236 //PrintAndLogEx(WARNING, "--- hi: %d, low: %d, threshold: %d", hilength, lowlength, threshold);
238 bool biterror = false;
239 for (uint32_t i = 0; i < implengthslen; i++) {
240 if (TexcomCalculateBit(implengths[i], hilength, threshold))
241 strcat(bitstring, "1");
242 else if (TexcomCalculateBit(implengths[i], lowlength, threshold))
243 strcat(bitstring, "0");
244 else {
245 //PrintAndLogEx(INFO, "ERROR string [%zu]: %s, bit: %d, blen: %d", strlen(bitstring), bitstring, i, implengths[i]);
247 biterror = true;
248 break;
252 if (biterror || strlen(bitstring) == 0)
253 return false;
255 if (verbose)
256 PrintAndLogEx(INFO, "raw bit string [%3zu]... %s", strlen(bitstring), bitstring);
258 // add trailing impulse (some tags just ignore it)
259 if (strlen(bitstring) % 2 != 0) {
260 if (bitstring[strlen(bitstring) - 1] == '1')
261 strcat(bitstring, "0");
262 else
263 strcat(bitstring, "1");
266 for (uint32_t i = 0; i < strlen(bitstring); i = i + 2) {
267 if (bitstring[i] == bitstring[i + 1]) {
268 cbitstring[0] = 0;
269 if (verbose)
270 PrintAndLogEx(WARNING, "Raw bit string have error at offset %d.", i);
271 break;
273 if (bitstring[i] == '1')
274 strcat(cbitstring, "1");
275 else
276 strcat(cbitstring, "0");
279 if (strlen(cbitstring) == 0)
280 return false;
282 if (verbose)
283 PrintAndLogEx(INFO, "bit string [%3zu].... %s", strlen(cbitstring), cbitstring);
285 return ((strlen(cbitstring) == 64) && (strncmp(cbitstring, "1111111111111111", 16) == 0));
288 // general decode of the very bad signal. maybe here will be some of tk-13 old badges
289 static bool TexcomTK15Decode(uint32_t *implengths, uint32_t implengthslen, char *bitstring, char *cbitstring, bool verbose) {
290 bitstring[0] = 0;
291 cbitstring[0] = 0;
292 if (implengthslen == 0)
293 return false;
295 bool biterror = false;
296 for (uint32_t i = 0; i < implengthslen / 2; i++) {
297 if (implengths[i * 2] == implengths[i * 2 + 1]) {
298 biterror = true;
299 break;
300 } else if (implengths[i * 2] > implengths[i * 2 + 1]) {
301 strcat(bitstring, "10");
302 strcat(cbitstring, "1");
303 } else {
304 strcat(bitstring, "01");
305 strcat(cbitstring, "0");
309 if (implengthslen > 2 && implengthslen % 2 != 0) {
310 int lastimplen = implengths[implengthslen - 1];
311 bool prevbit = (implengths[implengthslen - 3] > implengths[implengthslen - 2]);
312 bool thesamebit = (abs(lastimplen - (int)implengths[implengthslen - 3]) < abs(lastimplen - (int)implengths[implengthslen - 2]));
314 if (prevbit ^ (!thesamebit)) {
315 strcat(bitstring, "10");
316 strcat(cbitstring, "1");
317 } else {
318 strcat(bitstring, "01");
319 strcat(cbitstring, "0");
323 if (biterror || strlen(bitstring) == 0 || strlen(cbitstring) == 0)
324 return false;
326 if (verbose) {
327 PrintAndLogEx(INFO, "raw bit string [%3zu]... %s", strlen(bitstring), bitstring);
328 PrintAndLogEx(INFO, "bit string [%3zu]....... %s", strlen(cbitstring), cbitstring);
331 return ((strlen(cbitstring) == 64) && (strncmp(cbitstring, "1111111111111111", 16) == 0));
334 static inline int TexcomTK17Get2Bits(uint32_t len1, uint32_t len2) {
335 uint32_t xlen = (len2 * 100) / (len1 + len2);
336 if (xlen < 10 || xlen > 90)
337 return TK17WrongBit;
338 if (xlen < 30)
339 return TK17Bit00;
340 if (xlen < 50)
341 return TK17Bit10;
342 if (xlen < 70)
343 return TK17Bit01;
344 return TK17Bit11;
347 static bool TexcomTK17Decode(uint32_t *implengths, uint32_t implengthslen, char *bitstring, char *cbitstring, bool verbose) {
348 bitstring[0] = 0;
349 cbitstring[0] = 0;
350 if (implengthslen == 0)
351 return false;
353 for (uint32_t i = 0; i < implengthslen; i = i + 2) {
354 int dbit = TexcomTK17Get2Bits(implengths[i], implengths[i + 1]);
355 if (dbit == TK17WrongBit)
356 return false;
358 switch (dbit) {
359 case TK17Bit00:
360 strcat(bitstring, "00");
361 break;
362 case TK17Bit01:
363 strcat(bitstring, "01");
364 break;
365 case TK17Bit10:
366 strcat(bitstring, "10");
367 break;
368 case TK17Bit11:
369 strcat(bitstring, "11");
370 break;
371 default:
372 return false;
376 if (verbose)
377 PrintAndLogEx(INFO, "TK17 raw bit string [%zu]: %s", strlen(bitstring), bitstring);
379 for (uint32_t i = 0; i < 8; i++) {
380 memcpy(&cbitstring[i * 8 + 0], &bitstring[i * 8 + 6], 2);
381 memcpy(&cbitstring[i * 8 + 2], &bitstring[i * 8 + 4], 2);
382 memcpy(&cbitstring[i * 8 + 4], &bitstring[i * 8 + 2], 2);
383 memcpy(&cbitstring[i * 8 + 6], &bitstring[i * 8 + 0], 2);
386 if (verbose)
387 PrintAndLogEx(INFO, "TK17 bit string [%zu]: %s", strlen(cbitstring), cbitstring);
389 return (strlen(bitstring) == 64) && (strncmp(cbitstring, "1111111111111111", 16) == 0);
392 static bool TexcomGeneralDecode(uint32_t *implengths, uint32_t implengthslen, char *bitstring, bool verbose) {
393 uint32_t hilength = 0;
394 uint32_t lowlength = 0;
395 if (!TexkomCalculateBitLengths(implengths, implengthslen, &hilength, &lowlength, NULL, NULL))
396 return false;
398 uint32_t threshold = (hilength - lowlength) / 3 + 1;
400 bitstring[0] = 0;
401 bool biterror = false;
402 for (uint32_t i = 0; i < implengthslen; i++) {
403 if (TexcomCalculateBit(implengths[i], hilength, threshold))
404 strcat(bitstring, "1");
405 else if (TexcomCalculateBit(implengths[i], lowlength, threshold))
406 strcat(bitstring, "0");
407 else {
408 if (verbose) {
409 PrintAndLogEx(INFO, "ERROR string [%zu]: %s, bit: %d, blen: %d", strlen(bitstring), bitstring, i, implengths[i]);
411 PrintAndLogEx(INFO, "Length array:");
412 for (uint32_t j = 0; j < implengthslen; j++) {
413 PrintAndLogEx(NORMAL, "%u, " NOLF, implengths[j]);
415 PrintAndLogEx(NORMAL, "");
418 biterror = true;
419 break;
422 if (verbose)
423 PrintAndLogEx(INFO, "General raw bit string [%zu]... %s", strlen(bitstring), bitstring);
425 return (!biterror && strlen(bitstring) > 0);
428 static void TexcomReverseCode(const uint8_t *code, int length, uint8_t *reverse_code) {
429 for (int i = 0; i < length; i++) {
430 reverse_code[i] = code[(length - 1) - i];
434 static int texkom_get_type(texkom_card_select_t *card, bool verbose) {
436 if (card == NULL) {
437 return PM3_EINVARG;
440 // get samples from tag.
442 uint32_t samplesCount = 30000;
443 clearCommandBuffer();
444 SendCommandNG(CMD_HF_ACQ_RAW_ADC, (uint8_t *)&samplesCount, sizeof(uint32_t));
445 PacketResponseNG resp;
446 if (WaitForResponseTimeout(CMD_HF_ACQ_RAW_ADC, &resp, 2500) == false) {
447 if (verbose) {
448 PrintAndLogEx(WARNING, "command execution time out");
450 return PM3_ETIMEOUT;
453 uint32_t size = (resp.data.asDwords[0]);
454 if (size > 0) {
455 if (getSamples(samplesCount, false) != PM3_SUCCESS) {
456 if (verbose)
457 PrintAndLogEx(ERR, "Get samples error");
459 return PM3_EFAILED;
463 // decode samples to 8 bytes
464 char bitstring[256] = {0};
465 char cbitstring[128] = {0};
466 char genbitstring[256] = {0};
467 int found = TexkomModError;
468 uint32_t sindx = 0;
470 while (sindx < samplesCount - 5) {
472 sindx = TexkomSearchStart(sindx, TEXKOM_NOISE_THRESHOLD);
473 if (sindx == 0 || sindx > samplesCount - 5) {
474 if (TexkomAVGField() > 30 && verbose) {
475 PrintAndLogEx(WARNING, "Too noisy environment. Try to move the tag from the antenna a bit.");
477 break;
480 uint32_t slen = TexkomSearchLength(sindx, TEXKOM_NOISE_THRESHOLD);
481 if (slen == 0) {
482 continue;
485 uint32_t maxlvl = TexkomSearchMax(sindx, 1760);
486 if (maxlvl < TEXKOM_NOISE_THRESHOLD) {
487 sindx += 1700;
488 continue;
491 uint32_t noiselvl = maxlvl / 5;
492 if (noiselvl < TEXKOM_NOISE_THRESHOLD) {
493 noiselvl = TEXKOM_NOISE_THRESHOLD;
496 uint32_t implengths[256] = { 0 };
497 uint32_t implengthslen = 0;
498 uint32_t impulseindx = 0;
499 uint32_t impulsecnt = 0;
500 for (uint32_t i = 0; i < slen; i++) {
501 if (TexkomCorrelate(sindx + i, noiselvl)) {
502 impulsecnt++;
504 if (impulseindx != 0) {
505 if (implengthslen < 256) {
506 implengths[implengthslen++] = sindx + i - impulseindx;
509 impulseindx = sindx + i;
513 // check if it TK-17 modulation
514 // 65 impulses and 64 intervals (1 interval = 2 bits, interval length encoding) that represents 128 bit of card code
515 if (impulsecnt == 65) {
516 if (TexcomTK17Decode(implengths, implengthslen, bitstring, cbitstring, verbose)) {
517 found = TexkomModTK17;
518 break;
522 // check if it TK-13 or TK-15 modulation
523 // it have 127 or 128 impulses and 128 double-intervals that represents 128 bit of card code
524 if (impulsecnt == 127 || impulsecnt == 128) {
525 if (TexcomTK13Decode(implengths, implengthslen, bitstring, cbitstring, verbose)) {
526 found = TexkomModTK13;
527 break;
528 } else if (TexcomTK15Decode(implengths, implengthslen, bitstring, cbitstring, verbose)) {
529 found = TexkomModTK15;
530 break;
534 // general decoding. it thought that there is 2 types of intervals "long" (1) and "short" (0)
535 // and tries to decode sequence. shows only raw data
536 if (verbose)
537 TexcomGeneralDecode(implengths, implengthslen, genbitstring, verbose);
540 if (found != TexkomModError) {
542 for (uint32_t i = 0; i < strlen(cbitstring); i++) {
543 card->tcode[i / 8] = (card->tcode[i / 8] << 1) | ((cbitstring[i] == '1') ? 1 : 0);
546 TexcomReverseCode(card->tcode, sizeof(card->tcode), card->rtcode);
547 return PM3_SUCCESS;
549 return PM3_ESOFT;
552 int read_texkom_uid(bool loop, bool verbose) {
554 do {
555 texkom_card_select_t card;
557 int res = texkom_get_type(&card, verbose);
559 if (loop) {
560 if (res != PM3_SUCCESS) {
561 continue;
563 } else {
564 switch (res) {
565 case PM3_EFAILED:
566 case PM3_EINVARG:
567 return res;
568 case PM3_ETIMEOUT:
569 if (verbose) {
570 PrintAndLogEx(WARNING, "command execution time out");
572 return res;
573 case PM3_ESOFT:
574 if (verbose) {
575 PrintAndLogEx(WARNING, "texkom card select failed");
577 return PM3_ESOFT;
578 default:
579 break;
583 // decoding code
584 if (card.tcode[0] == 0xff && card.tcode[1] == 0xff) {
586 if (loop == false) {
587 PrintAndLogEx(NORMAL, "");
590 bool crc = (TexcomTK13CRC(&card.tcode[3]) == card.tcode[7]);
591 bool printed = false;
593 if (card.tcode[2] == 0x63) {
594 PrintAndLogEx(INFO, "TYPE..... " _YELLOW_("TK13"));
595 PrintAndLogEx(INFO, "UID...... " _GREEN_("%s"), sprint_hex(&card.tcode[3], 4));
596 if (verbose) {
597 PrintAndLogEx(INFO, "CRC...... %s", (crc) ? _GREEN_("ok") : _RED_("fail"));
599 printed = true;
600 } else if (card.tcode[2] == 0xCA) {
601 PrintAndLogEx(INFO, "TYPE..... " _YELLOW_("TK17"));
602 PrintAndLogEx(INFO, "UID...... " _GREEN_("%s"), sprint_hex(&card.tcode[3], 4));
603 if (verbose) {
604 PrintAndLogEx(INFO, "CRC...... %s", (crc) ? _GREEN_("ok") : _RED_("fail"));
606 printed = true;
607 } else if (card.tcode[2] == 0xFF && card.tcode[3] == 0xFF) {
608 PrintAndLogEx(INFO, "TYPE..... " _YELLOW_("MMBIT"));
609 PrintAndLogEx(INFO, "UID...... " _GREEN_("%s"), sprint_hex(&card.tcode[4], 3));
610 if (verbose) {
611 crc = (MMBITCRC(&card.tcode[4]) == card.tcode[7] >> 4);
612 PrintAndLogEx(INFO, "CRC...... %s", (crc) ? _GREEN_("ok") : _RED_("fail"));
614 printed = true;
617 if (verbose) {
618 PrintAndLogEx(INFO, "Raw....... " _YELLOW_("%s"), sprint_hex(card.tcode, 8));
619 PrintAndLogEx(INFO, "Raw rev... " _YELLOW_("%s"), sprint_hex(card.rtcode, 8));
621 if (printed && loop) {
622 PrintAndLogEx(NORMAL, "");
626 } while (loop && kbd_enter_pressed() == false);
628 return PM3_SUCCESS;
631 static int CmdHFTexkomReader(const char *Cmd) {
632 CLIParserContext *ctx;
633 CLIParserInit(&ctx, "hf texkom reader",
634 "Read a texkom tag",
635 "hf texkom reader\n"
636 "hf texkom reader -@ -> continuous reader mode"
639 void *argtable[] = {
640 arg_param_begin,
641 arg_lit0("1", NULL, "Use data from Graphbuffer (offline mode)"),
642 arg_lit0("v", "verbose", "Verbose output"),
643 arg_lit0("@", NULL, "optional - continuous reader mode"),
644 arg_param_end
646 CLIExecWithReturn(ctx, Cmd, argtable, true);
648 bool gbuffer = arg_get_lit(ctx, 1);
649 bool verbose = arg_get_lit(ctx, 2);
650 bool cm = arg_get_lit(ctx, 3);
652 CLIParserFree(ctx);
654 if (cm) {
655 PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
656 return read_texkom_uid(cm, verbose);
659 uint32_t samplesCount = 30000;
660 if (gbuffer) {
661 samplesCount = g_GraphTraceLen;
662 } else {
663 clearCommandBuffer();
664 SendCommandNG(CMD_HF_ACQ_RAW_ADC, (uint8_t *)&samplesCount, sizeof(uint32_t));
666 PacketResponseNG resp;
667 if (!WaitForResponseTimeout(CMD_HF_ACQ_RAW_ADC, &resp, 2500)) {
668 PrintAndLogEx(WARNING, "command execution time out");
669 return PM3_ETIMEOUT;
672 uint32_t size = (resp.data.asDwords[0]);
673 if (size > 0) {
674 if (getSamples(samplesCount, false) != PM3_SUCCESS) {
675 PrintAndLogEx(ERR, "Get samples error");
676 return PM3_EFAILED;
681 char bitstring[256] = {0};
682 char cbitstring[128] = {0};
683 char genbitstring[256] = {0};
684 int codefound = TexkomModError;
685 uint32_t sindx = 0;
686 while (sindx < samplesCount - 5) {
687 sindx = TexkomSearchStart(sindx, TEXKOM_NOISE_THRESHOLD);
688 if (sindx == 0 || sindx > samplesCount - 5) {
689 if (TexkomAVGField() > 30)
690 PrintAndLogEx(WARNING, "Too noisy environment. Try to move the tag from the antenna a bit.");
691 break;
694 uint32_t slen = TexkomSearchLength(sindx, TEXKOM_NOISE_THRESHOLD);
695 if (slen == 0)
696 continue;
698 uint32_t maxlvl = TexkomSearchMax(sindx, 1760);
699 if (maxlvl < TEXKOM_NOISE_THRESHOLD) {
700 sindx += 1700;
701 continue;
704 uint32_t noiselvl = maxlvl / 5;
705 if (noiselvl < TEXKOM_NOISE_THRESHOLD)
706 noiselvl = TEXKOM_NOISE_THRESHOLD;
708 //PrintAndLogEx(WARNING, "--- indx: %d, len: %d, max: %d, noise: %d", sindx, slen, maxlvl, noiselvl);
710 uint32_t implengths[256] = { 0 };
711 uint32_t implengthslen = 0;
712 uint32_t impulseindx = 0;
713 uint32_t impulsecnt = 0;
714 for (uint32_t i = 0; i < slen; i++) {
715 if (TexkomCorrelate(sindx + i, noiselvl)) {
716 impulsecnt++;
718 if (impulseindx != 0) {
719 if (implengthslen < 256)
720 implengths[implengthslen++] = sindx + i - impulseindx;
722 impulseindx = sindx + i;
725 //PrintAndLogEx(WARNING, "--- impulses: %d, lenarray: %d, [%d,%d]", impulsecnt, implengthslen, implengths[0], implengths[1]);
727 // check if it TK-17 modulation
728 // 65 impulses and 64 intervals (1 interval = 2 bits, interval length encoding) that represents 128 bit of card code
729 if (impulsecnt == 65) {
730 if (TexcomTK17Decode(implengths, implengthslen, bitstring, cbitstring, verbose)) {
731 codefound = TexkomModTK17;
732 break;
736 // check if it TK-13 modulation
737 // it have 127 or 128 impulses and 128 double-intervals that represents 128 bit of card code
738 if (impulsecnt == 127 || impulsecnt == 128) {
739 if (TexcomTK13Decode(implengths, implengthslen, bitstring, cbitstring, verbose)) {
740 codefound = TexkomModTK13;
741 break;
742 } else if (TexcomTK15Decode(implengths, implengthslen, bitstring, cbitstring, verbose)) {
743 codefound = TexkomModTK15;
744 break;
748 // general decoding. it thought that there is 2 types of intervals "long" (1) and "short" (0)
749 // and tries to decode sequence. shows only raw data
750 if (verbose)
751 TexcomGeneralDecode(implengths, implengthslen, genbitstring, verbose);
754 if (codefound != TexkomModError) {
755 uint8_t tcode[8] = {0};
756 for (uint32_t i = 0; i < strlen(cbitstring); i++) {
757 tcode[i / 8] = (tcode[i / 8] << 1) | ((cbitstring[i] == '1') ? 1 : 0);
760 uint8_t rtcode[8] = {0};
761 TexcomReverseCode(tcode, 8, rtcode);
763 if (verbose) {
764 PrintAndLogEx(INFO, "Hex code............ %s", sprint_hex(tcode, 8));
765 PrintAndLogEx(INFO, "Hex code rev........ %s", sprint_hex(rtcode, 8));
768 if (tcode[0] == 0xff && tcode[1] == 0xff) {
769 // decoding code
771 if (verbose == false) {
772 PrintAndLogEx(SUCCESS, "Texkom.............. %s", sprint_hex(tcode, 8));
773 PrintAndLogEx(SUCCESS, "Texkom duplicator... %s", sprint_hex(rtcode, 8));
776 if (codefound == TexkomModTK13)
777 PrintAndLogEx(SUCCESS, "Modulation.......... " _YELLOW_("TK13"));
778 else if (codefound == TexkomModTK15)
779 PrintAndLogEx(SUCCESS, "Modulation.......... " _YELLOW_("TK15"));
780 else if (codefound == TexkomModTK17)
781 PrintAndLogEx(SUCCESS, "Modulation.......... " _YELLOW_("TK17"));
782 else
783 PrintAndLogEx(INFO, "Modulation.......... " _YELLOW_("unknown"));
785 if (tcode[2] == 0x63) {
786 // TK13 and TK15. differs only by timings. TK15 has impulse 0 and 1 lengths very close to each other.
787 if (codefound == TexkomModTK13)
788 PrintAndLogEx(SUCCESS, "Type................ " _YELLOW_("TK13"));
789 else if (codefound == TexkomModTK15)
790 PrintAndLogEx(SUCCESS, "Type................ " _YELLOW_("TK15"));
791 else
792 PrintAndLogEx(WARNING, "Type................ " _RED_("fail"));
794 PrintAndLogEx(SUCCESS, "UID................. " _YELLOW_("%s"), sprint_hex(&tcode[3], 4));
795 PrintAndLogEx(INFO, "CRC................ " NOLF);
796 if (TexcomTK13CRC(&tcode[3]) == tcode[7])
797 PrintAndLogEx(NORMAL, "( " _GREEN_("ok") " )");
798 else
799 PrintAndLogEx(NORMAL, "( " _RED_("fail") " )");
801 } else if (tcode[2] == 0xFF && tcode[3] == 0xFF) {
802 // MMBIT
803 if (codefound != TexkomModTK13 && codefound != TexkomModTK15) {
804 PrintAndLogEx(WARNING, "Mod type............ " _RED_("fail"));
806 PrintAndLogEx(SUCCESS, "Type................ " _YELLOW_("MMBIT"));
807 PrintAndLogEx(SUCCESS, "UID................. " _YELLOW_("%s"), sprint_hex(&tcode[4], 3));
808 PrintAndLogEx(INFO, "CRC................ " NOLF);
809 if (MMBITCRC(&tcode[4]) == tcode[7] >> 4)
810 PrintAndLogEx(NORMAL, "( " _GREEN_("ok") " )");
811 else
812 PrintAndLogEx(NORMAL, "( " _RED_("fail") " )");
815 } else if (tcode[2] == 0xCA) {
816 // TK17
817 if (codefound != TexkomModTK17) {
818 PrintAndLogEx(WARNING, "Mod type............ " _RED_("fail"));
820 PrintAndLogEx(SUCCESS, "Type............... " _YELLOW_("TK17"));
821 PrintAndLogEx(SUCCESS, "UID................ " _YELLOW_("%s"), sprint_hex(&tcode[3], 4));
822 PrintAndLogEx(INFO, "CRC................ " NOLF);
823 if (TexcomTK17CRC(&tcode[3]) == tcode[7])
824 PrintAndLogEx(NORMAL, "( " _GREEN_("ok") " )");
825 else
826 PrintAndLogEx(NORMAL, "( " _RED_("fail") " )");
828 } else {
829 PrintAndLogEx(INFO, "Type............... unknown");
830 PrintAndLogEx(INFO, "UID................ %s (maybe)", sprint_hex(&tcode[3], 4));
832 } else {
833 PrintAndLogEx(ERR, "Code have no preamble FFFF... %s", sprint_hex(tcode, 8));
835 } else {
836 if (strlen(genbitstring) > 0)
837 PrintAndLogEx(INFO, "General decoding bitstring... %s", genbitstring);
838 if (strlen(bitstring) > 0)
839 PrintAndLogEx(INFO, "last raw bit string [%zu].... %s", strlen(bitstring), bitstring);
840 if (strlen(cbitstring) > 0)
841 PrintAndLogEx(INFO, "last bit string [%zu]........ %s", strlen(cbitstring), cbitstring);
843 PrintAndLogEx(ERR, "Texkom card is not found");
846 return PM3_SUCCESS;
849 static int CmdHFTexkomSim(const char *Cmd) {
850 CLIParserContext *ctx;
851 CLIParserInit(&ctx, "hf texkom sim",
852 "Simulate a texkom tag",
853 "hf texkom sim \n"
854 "hf texkom sim --raw FFFF638C7DC45553 -> simulate TK13 tag with id 8C7DC455\n"
855 "hf texkom sim --tk17 --raw FFFFCA17F31EC512 -> simulate TK17 tag with id 17F31EC5\n"
856 "hf texkom sim --id 8C7DC455 -> simulate TK13 tag with id 8C7DC455\n"
857 "hf texkom sim --id 8C7DC455 --tk17 -> simulate TK17 tag with id 17F31EC5");
859 void *argtable[] = {
860 arg_param_begin,
861 arg_lit0("v", "verbose", "Verbose output"),
862 arg_lit0("t", "tk17", "Use TK-17 modulation (TK-13 by default)"),
863 arg_str0(NULL, "raw", "<hex 8 bytes>", "Raw data for texkom card, 8 bytes. Manual modulation select."),
864 arg_str0(NULL, "id", "<hex 4 bytes>", "Raw data for texkom card, 8 bytes. Manual modulation select."),
865 arg_int0(NULL, "timeout", "<dec, ms>", "Simulation timeout in the ms. If not specified or 0 - infinite. Command can be skipped by pressing the button"),
866 arg_param_end
868 CLIExecWithReturn(ctx, Cmd, argtable, true);
870 // <texkom data 8bytes><modulation type 1b><timeout ms 4b>
871 struct p {
872 uint8_t data[8];
873 uint8_t modulation;
874 uint32_t timeout;
875 } PACKED payload = {0};
877 bool verbose = arg_get_lit(ctx, 1);
878 payload.modulation = 0; // tk-13
879 if (arg_get_lit(ctx, 2))
880 payload.modulation = 1; //tk-17
882 uint8_t rawdata[250] = {0};
883 int rawdatalen = 0;
884 CLIGetHexWithReturn(ctx, 3, rawdata, &rawdatalen);
886 uint8_t iddata[250] = {0};
887 int iddatalen = 0;
888 CLIGetHexWithReturn(ctx, 4, iddata, &iddatalen);
890 payload.timeout = arg_get_int_def(ctx, 5, 0);
892 CLIParserFree(ctx);
894 if (rawdatalen == 0 && iddatalen == 0) {
895 PrintAndLogEx(ERR, "<raw data> or <id> must be specified to simulate");
896 return PM3_EINVARG;
899 if (iddatalen > 0 && iddatalen != 4) {
900 PrintAndLogEx(ERR, "<id> must be 4 bytes long instead of: %d", iddatalen);
901 return PM3_EINVARG;
904 if (iddatalen == 4) {
905 rawdata[0] = 0xff;
906 rawdata[1] = 0xff;
907 rawdata[2] = (payload.modulation == 0) ? 0x63 : 0xCA;
908 memcpy(&rawdata[3], iddata, 4);
909 rawdata[7] = (payload.modulation == 0) ? TexcomTK13CRC(iddata) : TexcomTK17CRC(iddata);
910 rawdatalen = 8;
913 if (rawdatalen > 0 && rawdatalen != 8) {
914 PrintAndLogEx(ERR, "<raw data> must be 8 bytes long instead of: %d", rawdatalen);
915 return PM3_EINVARG;
918 memcpy(payload.data, rawdata, 8);
920 clearCommandBuffer();
921 SendCommandNG(CMD_HF_TEXKOM_SIMULATE, (uint8_t *)&payload, sizeof(payload));
923 if (payload.timeout > 0 && payload.timeout < 2800) {
924 PrintAndLogEx(INFO, "simulate command started");
925 PacketResponseNG resp;
926 if (WaitForResponseTimeout(CMD_HF_TEXKOM_SIMULATE, &resp, 3000) == false) {
927 if (verbose) {
928 PrintAndLogEx(WARNING, "(hf texkom simulate) command execution time out");
930 return PM3_ETIMEOUT;
932 PrintAndLogEx(INFO, "simulate command execution done");
933 } else {
934 PrintAndLogEx(INFO, "simulate command started...");
937 return PM3_SUCCESS;
940 static int CmdHelp(const char *Cmd);
942 static command_t CommandTable[] = {
943 {"help", CmdHelp, AlwaysAvailable, "This help"},
944 {"reader", CmdHFTexkomReader, IfPm3Iso14443a, "Act like a Texkom reader"},
945 {"sim", CmdHFTexkomSim, IfPm3Iso14443a, "Simulate a Texkom tag"},
946 //{"write", CmdHFTexkomWrite, IfPm3Iso14443a, "Write a Texkom tag"},
947 {NULL, NULL, 0, NULL}
950 static int CmdHelp(const char *Cmd) {
951 (void)Cmd; // Cmd is not used so far
952 CmdsHelp(CommandTable);
953 return PM3_SUCCESS;
956 int CmdHFTexkom(const char *Cmd) {
957 clearCommandBuffer();
958 return CmdsParse(CommandTable, Cmd);