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 // Low frequency Securakey tag commands
17 // ASK/Manchester, RF/40, 96 bits long (unknown cs)
18 //-----------------------------------------------------------------------------
19 #include "cmdlfsecurakey.h"
20 #include <string.h> // memcpy
21 #include <ctype.h> // tolower
22 #include "commonutil.h" // ARRAYLEN
23 #include "cmdparser.h" // command_t
28 #include "lfdemod.h" // preamble test
29 #include "parity.h" // for wiegand parity test
30 #include "protocols.h" // t55xx defines
31 #include "cmdlft55xx.h" // clone..
32 #include "cliparser.h"
33 #include "cmdlfem4x05.h" // EM defines
35 static int CmdHelp(const char *Cmd
);
37 //see ASKDemod for what args are accepted
38 int demodSecurakey(bool verbose
) {
39 (void) verbose
; // unused so far
43 if (ASKDemod_ext(40, 0, 0, 0, false, false, false, 1, &st
) != PM3_SUCCESS
) {
44 PrintAndLogEx(DEBUG
, "DEBUG: Error - Securakey: ASK/Manchester Demod failed");
50 size_t size
= g_DemodBufferLen
;
51 int ans
= detectSecurakey(g_DemodBuffer
, &size
);
54 PrintAndLogEx(DEBUG
, "DEBUG: Error - Securakey: too few bits found");
56 PrintAndLogEx(DEBUG
, "DEBUG: Error - Securakey: preamble not found");
58 PrintAndLogEx(DEBUG
, "DEBUG: Error - Securakey: Size not correct: %zu", size
);
60 PrintAndLogEx(DEBUG
, "DEBUG: Error - Securakey: ans: %d", ans
);
63 setDemodBuff(g_DemodBuffer
, 96, ans
);
64 setClockGrid(g_DemodClock
, g_DemodStartIdx
+ (ans
* g_DemodClock
));
67 uint32_t raw1
= bytebits_to_byte(g_DemodBuffer
, 32);
68 uint32_t raw2
= bytebits_to_byte(g_DemodBuffer
+ 32, 32);
69 uint32_t raw3
= bytebits_to_byte(g_DemodBuffer
+ 64, 32);
72 // preamble ??bitlen reserved EPx xxxxxxxy yyyyyyyy yyyyyyyOP CS? CS2?
73 // 0111111111 0 01011010 0 00000000 0 00000010 0 00110110 0 00111110 0 01100010 0 00001111 0 01100000 0 00000000 0 0000
76 // preamble ??bitlen reserved EPxxxxxxx xxxxxxxy yyyyyyyy yyyyyyyOP CS? CS2?
77 // 0111111111 0 01100000 0 00000000 0 10000100 0 11001010 0 01011011 0 01010110 0 00010110 0 11100000 0 00000000 0 0000
81 // standard wiegand parities.
82 // unknown checksum 11 bits? at the end
83 uint8_t bits_no_spacer
[85];
84 memcpy(bits_no_spacer
, g_DemodBuffer
+ 11, 85);
86 // remove marker bits (0's every 9th digit after preamble) (pType = 3 (always 0s))
87 size
= removeParity(bits_no_spacer
, 0, 9, 3, 85);
89 PrintAndLogEx(DEBUG
, "DEBUG: Error removeParity: %zu", size
);
93 uint8_t bitLen
= (uint8_t)bytebits_to_byte(bits_no_spacer
+ 2, 6);
94 uint32_t fc
= 0, lWiegand
= 0, rWiegand
= 0;
95 if (bitLen
> 40) { //securakey's max bitlen is 40 bits...
96 PrintAndLogEx(DEBUG
, "DEBUG: Error bitLen too long: %u", bitLen
);
99 // get left 1/2 wiegand & right 1/2 wiegand (for parity test and wiegand print)
100 lWiegand
= bytebits_to_byte(bits_no_spacer
+ 48 - bitLen
, bitLen
/ 2);
101 rWiegand
= bytebits_to_byte(bits_no_spacer
+ 48 - bitLen
+ bitLen
/ 2, bitLen
/ 2);
103 fc
= bytebits_to_byte(bits_no_spacer
+ 49 - bitLen
, bitLen
- 2 - 16);
106 if (bitLen
!= 26 && bitLen
!= 32)
107 PrintAndLogEx(NORMAL
, "***unknown securakey bitLen - share with forum***");
109 uint32_t cardid
= bytebits_to_byte(bits_no_spacer
+ 8 + 23, 16);
110 // test parities - evenparity32 looks to add an even parity returns 0 if already even...
111 bool parity
= !evenparity32(lWiegand
) && !oddparity32(rWiegand
);
113 PrintAndLogEx(SUCCESS
, "Securakey - len: " _GREEN_("%u") " FC: " _GREEN_("0x%X")" Card: " _GREEN_("%u") ", Raw: %08X%08X%08X", bitLen
, fc
, cardid
, raw1
, raw2
, raw3
);
115 PrintAndLogEx(SUCCESS
, "Wiegand: " _GREEN_("%08X") " parity ( %s )", (lWiegand
<< (bitLen
/ 2)) | rWiegand
, parity
? _GREEN_("ok") : _RED_("fail"));
118 PrintAndLogEx(INFO
, "\nHow the FC translates to printed FC is unknown");
119 PrintAndLogEx(INFO
, "How the checksum is calculated is unknown");
120 PrintAndLogEx(INFO
, "Help the community identify this format further\nby sharing your tag on the pm3 forum or discord");
125 static int CmdSecurakeyDemod(const char *Cmd
) {
126 CLIParserContext
*ctx
;
127 CLIParserInit(&ctx
, "lf securakey demod",
128 "Try to find Securakey preamble, if found decode / descramble data",
136 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
138 return demodSecurakey(true);
141 static int CmdSecurakeyReader(const char *Cmd
) {
142 CLIParserContext
*ctx
;
143 CLIParserInit(&ctx
, "lf securakey reader",
144 "read a Securakey tag",
145 "lf securakey reader -@ -> continuous reader mode"
150 arg_lit0("@", NULL
, "optional - continuous reader mode"),
153 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
154 bool cm
= arg_get_lit(ctx
, 1);
158 PrintAndLogEx(INFO
, "Press " _GREEN_("<Enter>") " to exit");
162 lf_read(false, 8000);
164 } while (cm
&& !kbd_enter_pressed());
169 static int CmdSecurakeyClone(const char *Cmd
) {
171 CLIParserContext
*ctx
;
172 CLIParserInit(&ctx
, "lf securakey clone",
173 "clone a Securakey tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
174 "lf securakey clone --raw 7FCB400001ADEA5344300000 -> encode for T55x7 tag\n"
175 "lf securakey clone --raw 7FCB400001ADEA5344300000 --q5 -> encode for Q5/T5555 tag\n"
176 "lf securakey clone --raw 7FCB400001ADEA5344300000 --em -> encode for EM4305/4469"
181 arg_str1("r", "raw", "<hex>", "raw hex data. 12 bytes"),
182 arg_lit0(NULL
, "q5", "optional - specify writing to Q5/T5555 tag"),
183 arg_lit0(NULL
, "em", "optional - specify writing to EM4305/4469 tag"),
186 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
189 // skip first block, 3*4 = 12 bytes left
190 uint8_t raw
[12] = {0};
191 CLIGetHexWithReturn(ctx
, 1, raw
, &raw_len
);
192 bool q5
= arg_get_lit(ctx
, 2);
193 bool em
= arg_get_lit(ctx
, 3);
197 PrintAndLogEx(FAILED
, "Can't specify both Q5 and EM4305 at the same time");
202 PrintAndLogEx(ERR
, "Data must be 12 bytes (24 HEX characters) %d", raw_len
);
207 for (uint8_t i
= 1; i
< ARRAYLEN(blocks
); i
++) {
208 blocks
[i
] = bytes_to_num(raw
+ ((i
- 1) * 4), sizeof(uint32_t));
211 //Securakey - compat mode, ASK/Man, data rate 40, 3 data blocks
212 blocks
[0] = T55x7_MODULATION_MANCHESTER
| T55x7_BITRATE_RF_40
| 3 << T55x7_MAXBLOCK_SHIFT
;
213 char cardtype
[16] = {"T55x7"};
216 blocks
[0] = T5555_FIXED
| T5555_MODULATION_MANCHESTER
| T5555_SET_BITRATE(40) | T5555_ST_TERMINATOR
| 3 << T5555_MAXBLOCK_SHIFT
;
217 snprintf(cardtype
, sizeof(cardtype
), "Q5/T5555");
222 blocks
[0] = EM4305_SECURAKEY_CONFIG_BLOCK
;
223 snprintf(cardtype
, sizeof(cardtype
), "EM4305/4469");
226 PrintAndLogEx(INFO
, "Preparing to clone Securakey to " _YELLOW_("%s") " with raw hex", cardtype
);
227 print_blocks(blocks
, ARRAYLEN(blocks
));
231 res
= em4x05_clone_tag(blocks
, ARRAYLEN(blocks
), 0, false);
233 res
= clone_t55xx_tag(blocks
, ARRAYLEN(blocks
));
235 PrintAndLogEx(SUCCESS
, "Done!");
236 PrintAndLogEx(HINT
, "Hint: try " _YELLOW_("`lf securakey reader`") " to verify");
240 static int CmdSecurakeySim(const char *Cmd
) {
242 CLIParserContext
*ctx
;
243 CLIParserInit(&ctx
, "lf securakey sim",
244 "Enables simulation of secura card with specified card number.\n"
245 "Simulation runs until the button is pressed or another USB command is issued.",
246 "lf securakey sim --raw 7FCB400001ADEA5344300000"
251 arg_str0("r", "raw", "<hex>", " raw hex data. 12 bytes"),
254 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
257 // skip first block, 3*4 = 12 bytes left
258 uint8_t raw
[12] = {0};
259 CLIGetHexWithReturn(ctx
, 1, raw
, &raw_len
);
263 PrintAndLogEx(ERR
, "Data must be 12 bytes (24 HEX characters) %d", raw_len
);
267 PrintAndLogEx(SUCCESS
, "Simulating SecuraKey - raw " _YELLOW_("%s"), sprint_hex_inrow(raw
, sizeof(raw
)));
269 uint8_t bs
[sizeof(raw
) * 8];
270 bytes_to_bytebits(raw
, sizeof(raw
), bs
);
272 lf_asksim_t
*payload
= calloc(1, sizeof(lf_asksim_t
) + sizeof(bs
));
273 payload
->encoding
= 1;
275 payload
->separator
= 0;
277 memcpy(payload
->data
, bs
, sizeof(bs
));
279 clearCommandBuffer();
280 SendCommandNG(CMD_LF_ASK_SIMULATE
, (uint8_t *)payload
, sizeof(lf_asksim_t
) + sizeof(bs
));
283 PacketResponseNG resp
;
284 WaitForResponse(CMD_LF_ASK_SIMULATE
, &resp
);
286 PrintAndLogEx(INFO
, "Done!");
287 if (resp
.status
!= PM3_EOPABORTED
) {
293 static command_t CommandTable
[] = {
294 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
295 {"demod", CmdSecurakeyDemod
, AlwaysAvailable
, "demodulate an Securakey tag from the GraphBuffer"},
296 {"reader", CmdSecurakeyReader
, IfPm3Lf
, "attempt to read and extract tag data"},
297 {"clone", CmdSecurakeyClone
, IfPm3Lf
, "clone Securakey tag to T55x7, Q5/T5555 or EM4305/4469"},
298 {"sim", CmdSecurakeySim
, IfPm3Lf
, "simulate Securakey tag"},
299 {NULL
, NULL
, NULL
, NULL
}
302 static int CmdHelp(const char *Cmd
) {
303 (void)Cmd
; // Cmd is not used so far
304 CmdsHelp(CommandTable
);
308 int CmdLFSecurakey(const char *Cmd
) {
309 clearCommandBuffer();
310 return CmdsParse(CommandTable
, Cmd
);
314 // find Securakey preamble in already demoded data
315 int detectSecurakey(uint8_t *dest
, size_t *size
) {
316 if (*size
< 96) return -1; //make sure buffer has data
318 uint8_t preamble
[] = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1};
319 if (!preambleSearch(dest
, preamble
, sizeof(preamble
), size
, &startIdx
))
320 return -2; //preamble not found
321 if (*size
!= 96) return -3; //wrong demoded size
322 //return start position
323 return (int)startIdx
;