1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
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.
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"
24 #include "cliparser.h"
25 #include "cmdparser.h" // command_t
32 #define TEXKOM_NOISE_THRESHOLD (10)
34 static inline uint32_t GetGraphBuffer(uint32_t indx
) {
35 if (g_GraphBuffer
[indx
] < -128)
38 return g_GraphBuffer
[indx
] + 128;
41 static uint32_t TexkomAVGField(void) {
42 if (g_GraphTraceLen
== 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
)
60 if (GetGraphBuffer(i
) > threshold
)
70 static uint32_t TexkomSearchLength(uint32_t indx
, uint32_t threshold
) {
71 // one bit length = 27, minimal noise = 60
72 uint32_t lownoisectr
= 0;
74 for (uint32_t i
= indx
; i
< g_GraphTraceLen
; i
++) {
75 if (lownoisectr
> 60) {
78 if (GetGraphBuffer(i
) > threshold
) {
80 datalen
= i
- indx
+ 27;
90 static uint32_t TexkomSearchMax(uint32_t indx
, uint32_t len
) {
93 for (uint32_t i
= 0; i
< len
; i
++) {
94 if (i
+ indx
> g_GraphTraceLen
)
97 if (GetGraphBuffer(indx
+ i
) > res
)
98 res
= GetGraphBuffer(indx
+ i
);
104 static bool TexkomCorrelate(uint32_t indx
, uint32_t threshold
) {
105 if (indx
< 2 || indx
+ 2 > g_GraphTraceLen
)
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);
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
) {
123 for (size_t i
= 0; i
< len
; 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
) {
138 uint32_t dmin
= 0xffffffff;
139 if (!TexkomCalculateMaxMin(data
, len
, &dmax
, &dmin
))
142 uint32_t dmiddle
= (dmax
+ dmin
) / 2;
147 for (size_t i
= 0; i
< len
; i
++) {
148 if (data
[i
] > dmiddle
) {
161 *low
= sumlow
/ lenlow
;
168 return (*hi
!= 0) && (*low
!= 0) && (*hi
> *low
);
171 static inline bool TexcomCalculateBit(uint32_t data
, uint32_t bitlen
, uint32_t threshold
) {
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
) {
182 crc
= crc
^ data
[indx
++];
184 for (uint8_t i
= 0; i
< 8; i
++)
186 crc
= 0x31 ^ (crc
<< 1);
194 static uint8_t MMBITCRC(const uint8_t *data
) {
196 (((data
[0] & 0x0f) ^ ((data
[0] >> 4) & 0x0f) ^
197 (data
[1] & 0x0f) ^ ((data
[1] >> 4) & 0x0f) ^
198 (data
[2] & 0x0f) ^ ((data
[2] >> 4) & 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;
210 if (mix
) crc
^= 0x8C;
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
) {
227 if (implengthslen
== 0)
230 uint32_t hilength
= 0;
231 uint32_t lowlength
= 0;
232 if (!TexkomCalculateBitLengths(implengths
, implengthslen
, &hilength
, &lowlength
, NULL
, NULL
))
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");
245 //PrintAndLogEx(INFO, "ERROR string [%zu]: %s, bit: %d, blen: %d", strlen(bitstring), bitstring, i, implengths[i]);
252 if (biterror
|| strlen(bitstring
) == 0)
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");
263 strcat(bitstring
, "1");
266 for (uint32_t i
= 0; i
< strlen(bitstring
); i
= i
+ 2) {
267 if (bitstring
[i
] == bitstring
[i
+ 1]) {
270 PrintAndLogEx(WARNING
, "Raw bit string have error at offset %d.", i
);
273 if (bitstring
[i
] == '1')
274 strcat(cbitstring
, "1");
276 strcat(cbitstring
, "0");
279 if (strlen(cbitstring
) == 0)
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
) {
292 if (implengthslen
== 0)
295 bool biterror
= false;
296 for (uint32_t i
= 0; i
< implengthslen
/ 2; i
++) {
297 if (implengths
[i
* 2] == implengths
[i
* 2 + 1]) {
300 } else if (implengths
[i
* 2] > implengths
[i
* 2 + 1]) {
301 strcat(bitstring
, "10");
302 strcat(cbitstring
, "1");
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");
318 strcat(bitstring
, "01");
319 strcat(cbitstring
, "0");
323 if (biterror
|| strlen(bitstring
) == 0 || strlen(cbitstring
) == 0)
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)
347 static bool TexcomTK17Decode(uint32_t *implengths
, uint32_t implengthslen
, char *bitstring
, char *cbitstring
, bool verbose
) {
350 if (implengthslen
== 0)
353 for (uint32_t i
= 0; i
< implengthslen
; i
= i
+ 2) {
354 int dbit
= TexcomTK17Get2Bits(implengths
[i
], implengths
[i
+ 1]);
355 if (dbit
== TK17WrongBit
)
360 strcat(bitstring
, "00");
363 strcat(bitstring
, "01");
366 strcat(bitstring
, "10");
369 strcat(bitstring
, "11");
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);
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
))
398 uint32_t threshold
= (hilength
- lowlength
) / 3 + 1;
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");
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
, "");
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
) {
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) {
448 PrintAndLogEx(WARNING
, "command execution time out");
453 uint32_t size
= (resp
.data
.asDwords
[0]);
455 if (getSamples(samplesCount
, false) != PM3_SUCCESS
) {
457 PrintAndLogEx(ERR
, "Get samples error");
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
;
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.");
480 uint32_t slen
= TexkomSearchLength(sindx
, TEXKOM_NOISE_THRESHOLD
);
485 uint32_t maxlvl
= TexkomSearchMax(sindx
, 1760);
486 if (maxlvl
< TEXKOM_NOISE_THRESHOLD
) {
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
)) {
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
;
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
;
528 } else if (TexcomTK15Decode(implengths
, implengthslen
, bitstring
, cbitstring
, verbose
)) {
529 found
= TexkomModTK15
;
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
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
);
552 int read_texkom_uid(bool loop
, bool verbose
) {
555 texkom_card_select_t card
;
557 int res
= texkom_get_type(&card
, verbose
);
560 if (res
!= PM3_SUCCESS
) {
570 PrintAndLogEx(WARNING
, "command execution time out");
575 PrintAndLogEx(WARNING
, "texkom card select failed");
584 if (card
.tcode
[0] == 0xff && card
.tcode
[1] == 0xff) {
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));
597 PrintAndLogEx(INFO
, "CRC...... %s", (crc
) ? _GREEN_("ok") : _RED_("fail"));
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));
604 PrintAndLogEx(INFO
, "CRC...... %s", (crc
) ? _GREEN_("ok") : _RED_("fail"));
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));
611 crc
= (MMBITCRC(&card
.tcode
[4]) == card
.tcode
[7] >> 4);
612 PrintAndLogEx(INFO
, "CRC...... %s", (crc
) ? _GREEN_("ok") : _RED_("fail"));
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);
631 static int CmdHFTexkomReader(const char *Cmd
) {
632 CLIParserContext
*ctx
;
633 CLIParserInit(&ctx
, "hf texkom reader",
636 "hf texkom reader -@ -> continuous reader mode"
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"),
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);
655 PrintAndLogEx(INFO
, "Press " _GREEN_("<Enter>") " to exit");
656 return read_texkom_uid(cm
, verbose
);
659 uint32_t samplesCount
= 30000;
661 samplesCount
= g_GraphTraceLen
;
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");
672 uint32_t size
= (resp
.data
.asDwords
[0]);
674 if (getSamples(samplesCount
, false) != PM3_SUCCESS
) {
675 PrintAndLogEx(ERR
, "Get samples error");
681 char bitstring
[256] = {0};
682 char cbitstring
[128] = {0};
683 char genbitstring
[256] = {0};
684 int codefound
= TexkomModError
;
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.");
694 uint32_t slen
= TexkomSearchLength(sindx
, TEXKOM_NOISE_THRESHOLD
);
698 uint32_t maxlvl
= TexkomSearchMax(sindx
, 1760);
699 if (maxlvl
< TEXKOM_NOISE_THRESHOLD
) {
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
)) {
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
;
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
;
742 } else if (TexcomTK15Decode(implengths
, implengthslen
, bitstring
, cbitstring
, verbose
)) {
743 codefound
= TexkomModTK15
;
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
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
);
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) {
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"));
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"));
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") " )");
799 PrintAndLogEx(NORMAL
, "( " _RED_("fail") " )");
801 } else if (tcode
[2] == 0xFF && tcode
[3] == 0xFF) {
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") " )");
812 PrintAndLogEx(NORMAL
, "( " _RED_("fail") " )");
815 } else if (tcode
[2] == 0xCA) {
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") " )");
826 PrintAndLogEx(NORMAL
, "( " _RED_("fail") " )");
829 PrintAndLogEx(INFO
, "Type............... unknown");
830 PrintAndLogEx(INFO
, "UID................ %s (maybe)", sprint_hex(&tcode
[3], 4));
833 PrintAndLogEx(ERR
, "Code have no preamble FFFF... %s", sprint_hex(tcode
, 8));
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");
849 static int CmdHFTexkomSim(const char *Cmd
) {
850 CLIParserContext
*ctx
;
851 CLIParserInit(&ctx
, "hf texkom sim",
852 "Simulate a texkom tag",
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");
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"),
868 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
870 // <texkom data 8bytes><modulation type 1b><timeout ms 4b>
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};
884 CLIGetHexWithReturn(ctx
, 3, rawdata
, &rawdatalen
);
886 uint8_t iddata
[250] = {0};
888 CLIGetHexWithReturn(ctx
, 4, iddata
, &iddatalen
);
890 payload
.timeout
= arg_get_int_def(ctx
, 5, 0);
894 if (rawdatalen
== 0 && iddatalen
== 0) {
895 PrintAndLogEx(ERR
, "<raw data> or <id> must be specified to simulate");
899 if (iddatalen
> 0 && iddatalen
!= 4) {
900 PrintAndLogEx(ERR
, "<id> must be 4 bytes long instead of: %d", iddatalen
);
904 if (iddatalen
== 4) {
907 rawdata
[2] = (payload
.modulation
== 0) ? 0x63 : 0xCA;
908 memcpy(&rawdata
[3], iddata
, 4);
909 rawdata
[7] = (payload
.modulation
== 0) ? TexcomTK13CRC(iddata
) : TexcomTK17CRC(iddata
);
913 if (rawdatalen
> 0 && rawdatalen
!= 8) {
914 PrintAndLogEx(ERR
, "<raw data> must be 8 bytes long instead of: %d", rawdatalen
);
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) {
928 PrintAndLogEx(WARNING
, "(hf texkom simulate) command execution time out");
932 PrintAndLogEx(INFO
, "simulate command execution done");
934 PrintAndLogEx(INFO
, "simulate command started...");
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
);
956 int CmdHFTexkom(const char *Cmd
) {
957 clearCommandBuffer();
958 return CmdsParse(CommandTable
, Cmd
);