]>
Commit | Line | Data |
---|---|---|
a553f267 | 1 | //----------------------------------------------------------------------------- |
f89c7050 | 2 | // 2011, Merlok |
534983d7 | 3 | // Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch |
a553f267 | 4 | // |
5 | // This code is licensed to you under the terms of the GNU GPL, version 2 or, | |
6 | // at your option, any later version. See the LICENSE.txt file for the text of | |
7 | // the license. | |
8 | //----------------------------------------------------------------------------- | |
9 | // High frequency ISO14443A commands | |
10 | //----------------------------------------------------------------------------- | |
11 | ||
7fe9b0b7 | 12 | #include <stdio.h> |
590f8ff9 | 13 | #include <stdlib.h> |
7fe9b0b7 | 14 | #include <string.h> |
f397b5cc M |
15 | #include <unistd.h> |
16 | #include <ctype.h> | |
20f9a2a1 | 17 | #include "util.h" |
7fe9b0b7 | 18 | #include "iso14443crc.h" |
19 | #include "data.h" | |
20 | #include "proxusb.h" | |
21 | #include "ui.h" | |
22 | #include "cmdparser.h" | |
23 | #include "cmdhf14a.h" | |
534983d7 | 24 | #include "common.h" |
20f9a2a1 | 25 | #include "cmdmain.h" |
f89c7050 M |
26 | #include "nonce2key/nonce2key.h" |
27 | #include "nonce2key/crapto1.h" | |
f397b5cc | 28 | #include "mifarehost.h" |
7fe9b0b7 | 29 | |
30 | static int CmdHelp(const char *Cmd); | |
31 | ||
32 | int CmdHF14AList(const char *Cmd) | |
33 | { | |
34 | uint8_t got[1920]; | |
35 | GetFromBigBuf(got, sizeof(got)); | |
36 | ||
37 | PrintAndLog("recorded activity:"); | |
38 | PrintAndLog(" ETU :rssi: who bytes"); | |
39 | PrintAndLog("---------+----+----+-----------"); | |
40 | ||
41 | int i = 0; | |
42 | int prev = -1; | |
43 | ||
44 | for (;;) { | |
45 | if(i >= 1900) { | |
46 | break; | |
47 | } | |
48 | ||
49 | bool isResponse; | |
50 | int timestamp = *((uint32_t *)(got+i)); | |
51 | if (timestamp & 0x80000000) { | |
52 | timestamp &= 0x7fffffff; | |
53 | isResponse = 1; | |
54 | } else { | |
55 | isResponse = 0; | |
56 | } | |
57 | ||
58 | int metric = 0; | |
59 | int parityBits = *((uint32_t *)(got+i+4)); | |
60 | // 4 bytes of additional information... | |
61 | // maximum of 32 additional parity bit information | |
62 | // | |
63 | // TODO: | |
64 | // at each quarter bit period we can send power level (16 levels) | |
65 | // or each half bit period in 256 levels. | |
66 | ||
67 | ||
68 | int len = got[i+8]; | |
69 | ||
70 | if (len > 100) { | |
71 | break; | |
72 | } | |
73 | if (i + len >= 1900) { | |
74 | break; | |
75 | } | |
76 | ||
77 | uint8_t *frame = (got+i+9); | |
78 | ||
79 | // Break and stick with current result if buffer was not completely full | |
80 | if (frame[0] == 0x44 && frame[1] == 0x44 && frame[3] == 0x44) { break; } | |
81 | ||
82 | char line[1000] = ""; | |
83 | int j; | |
84 | for (j = 0; j < len; j++) { | |
85 | int oddparity = 0x01; | |
86 | int k; | |
87 | ||
88 | for (k=0;k<8;k++) { | |
89 | oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01); | |
90 | } | |
91 | ||
92 | //if((parityBits >> (len - j - 1)) & 0x01) { | |
93 | if (isResponse && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) { | |
94 | sprintf(line+(j*4), "%02x! ", frame[j]); | |
95 | } | |
96 | else { | |
97 | sprintf(line+(j*4), "%02x ", frame[j]); | |
98 | } | |
99 | } | |
100 | ||
101 | char *crc; | |
102 | crc = ""; | |
103 | if (len > 2) { | |
104 | uint8_t b1, b2; | |
105 | for (j = 0; j < (len - 1); j++) { | |
106 | // gives problems... search for the reason.. | |
107 | /*if(frame[j] == 0xAA) { | |
108 | switch(frame[j+1]) { | |
109 | case 0x01: | |
110 | crc = "[1] Two drops close after each other"; | |
111 | break; | |
112 | case 0x02: | |
113 | crc = "[2] Potential SOC with a drop in second half of bitperiod"; | |
114 | break; | |
115 | case 0x03: | |
116 | crc = "[3] Segment Z after segment X is not possible"; | |
117 | break; | |
118 | case 0x04: | |
119 | crc = "[4] Parity bit of a fully received byte was wrong"; | |
120 | break; | |
121 | default: | |
122 | crc = "[?] Unknown error"; | |
123 | break; | |
124 | } | |
125 | break; | |
126 | }*/ | |
127 | } | |
128 | ||
129 | if (strlen(crc)==0) { | |
130 | ComputeCrc14443(CRC_14443_A, frame, len-2, &b1, &b2); | |
131 | if (b1 != frame[len-2] || b2 != frame[len-1]) { | |
132 | crc = (isResponse & (len < 6)) ? "" : " !crc"; | |
133 | } else { | |
134 | crc = ""; | |
135 | } | |
136 | } | |
137 | } else { | |
138 | crc = ""; // SHORT | |
139 | } | |
140 | ||
141 | char metricString[100]; | |
142 | if (isResponse) { | |
143 | sprintf(metricString, "%3d", metric); | |
144 | } else { | |
145 | strcpy(metricString, " "); | |
146 | } | |
147 | ||
148 | PrintAndLog(" +%7d: %s: %s %s %s", | |
149 | (prev < 0 ? 0 : (timestamp - prev)), | |
150 | metricString, | |
151 | (isResponse ? "TAG" : " "), line, crc); | |
152 | ||
153 | prev = timestamp; | |
154 | i += (len + 9); | |
155 | } | |
f89c7050 | 156 | return 0; |
7fe9b0b7 | 157 | } |
158 | ||
534983d7 | 159 | void iso14a_set_timeout(uint32_t timeout) { |
160 | UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_SET_TIMEOUT, 0, timeout}}; | |
161 | SendCommand(&c); | |
162 | } | |
163 | ||
7fe9b0b7 | 164 | int CmdHF14AMifare(const char *Cmd) |
165 | { | |
f89c7050 M |
166 | uint32_t uid = 0; |
167 | uint32_t nt = 0; | |
168 | uint64_t par_list = 0, ks_list = 0, r_key = 0; | |
169 | uint8_t isOK = 0; | |
f397b5cc | 170 | uint8_t keyBlock[6] = {0,0,0,0,0,0}; |
f89c7050 | 171 | |
f397b5cc M |
172 | if (param_getchar(Cmd, 0) && param_gethex(Cmd, 0, keyBlock, 8)) { |
173 | PrintAndLog("Nt must include 8 HEX symbols"); | |
174 | return 1; | |
175 | } | |
176 | ||
177 | UsbCommand c = {CMD_READER_MIFARE, {(uint32_t)bytes_to_num(keyBlock, 4), 0, 0}}; | |
f89c7050 M |
178 | SendCommand(&c); |
179 | ||
180 | //flush queue | |
f397b5cc | 181 | while (ukbhit()) getchar(); |
f89c7050 M |
182 | |
183 | // message | |
184 | printf("-------------------------------------------------------------------------\n"); | |
185 | printf("Executing command. It may take up to 30 min.\n"); | |
186 | printf("Press the key on proxmark3 device to abort proxmark3.\n"); | |
187 | printf("Press the key on the proxmark3 device to abort both proxmark3 and client.\n"); | |
188 | printf("-------------------------------------------------------------------------\n"); | |
189 | ||
190 | // wait cycle | |
191 | while (true) { | |
192 | printf("."); | |
f397b5cc | 193 | if (ukbhit()) { |
f89c7050 M |
194 | getchar(); |
195 | printf("\naborted via keyboard!\n"); | |
196 | break; | |
197 | } | |
198 | ||
199 | UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 2000); | |
200 | if (resp != NULL) { | |
201 | isOK = resp->arg[0] & 0xff; | |
202 | ||
203 | uid = (uint32_t)bytes_to_num(resp->d.asBytes + 0, 4); | |
204 | nt = (uint32_t)bytes_to_num(resp->d.asBytes + 4, 4); | |
205 | par_list = bytes_to_num(resp->d.asBytes + 8, 8); | |
206 | ks_list = bytes_to_num(resp->d.asBytes + 16, 8); | |
207 | ||
208 | printf("\n\n"); | |
209 | PrintAndLog("isOk:%02x", isOK); | |
210 | if (!isOK) PrintAndLog("Proxmark can't get statistic info. Execution aborted.\n"); | |
211 | break; | |
212 | } | |
213 | } | |
214 | printf("\n"); | |
215 | ||
216 | // error | |
217 | if (isOK != 1) return 1; | |
218 | ||
219 | // execute original function from util nonce2key | |
220 | if (nonce2key(uid, nt, par_list, ks_list, &r_key)) return 2; | |
f397b5cc | 221 | printf("------------------------------------------------------------------\n"); |
f89c7050 | 222 | PrintAndLog("Key found:%012llx \n", r_key); |
f397b5cc M |
223 | |
224 | num_to_bytes(r_key, 6, keyBlock); | |
225 | isOK = mfCheckKeys(0, 0, 1, keyBlock, &r_key); | |
226 | if (!isOK) | |
227 | PrintAndLog("Found valid key:%012llx", r_key); | |
228 | else | |
229 | PrintAndLog("Found invalid key. ("); | |
230 | ||
f89c7050 M |
231 | |
232 | return 0; | |
7fe9b0b7 | 233 | } |
234 | ||
20f9a2a1 M |
235 | int CmdHF14AMfWrBl(const char *Cmd) |
236 | { | |
20f9a2a1 M |
237 | uint8_t blockNo = 0; |
238 | uint8_t keyType = 0; | |
239 | uint8_t key[6] = {0, 0, 0, 0, 0, 0}; | |
240 | uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | |
241 | ||
f397b5cc | 242 | char cmdp = 0x00; |
20f9a2a1 M |
243 | |
244 | if (strlen(Cmd)<3) { | |
245 | PrintAndLog("Usage: hf 14 mfwrbl <block number> <key A/B> <key (12 hex symbols)> <block data (32 hex symbols)>"); | |
f397b5cc | 246 | PrintAndLog(" sample: hf 14a mfwrbl 0 A FFFFFFFFFFFF 000102030405060708090A0B0C0D0E0F"); |
20f9a2a1 M |
247 | return 0; |
248 | } | |
20f9a2a1 | 249 | |
f397b5cc M |
250 | blockNo = param_get8(Cmd, 0); |
251 | cmdp = param_getchar(Cmd, 1); | |
252 | if (cmdp == 0x00) { | |
253 | PrintAndLog("Key type must be A or B"); | |
254 | return 1; | |
20f9a2a1 | 255 | } |
f397b5cc M |
256 | if (cmdp != 'A' && cmdp != 'a') keyType = 1; |
257 | if (param_gethex(Cmd, 2, key, 12)) { | |
258 | PrintAndLog("Key must include 12 HEX symbols"); | |
259 | return 1; | |
20f9a2a1 | 260 | } |
f397b5cc M |
261 | if (param_gethex(Cmd, 3, bldata, 32)) { |
262 | PrintAndLog("Block data must include 32 HEX symbols"); | |
263 | return 1; | |
264 | } | |
265 | PrintAndLog("--block no:%02x key type:%02x key:%s", blockNo, keyType, sprint_hex(key, 6)); | |
266 | PrintAndLog("--data: %s", sprint_hex(bldata, 16)); | |
20f9a2a1 M |
267 | |
268 | UsbCommand c = {CMD_MIFARE_WRITEBL, {blockNo, keyType, 0}}; | |
269 | memcpy(c.d.asBytes, key, 6); | |
270 | memcpy(c.d.asBytes + 10, bldata, 16); | |
271 | SendCommand(&c); | |
272 | UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500); | |
273 | ||
274 | if (resp != NULL) { | |
275 | uint8_t isOK = resp->arg[0] & 0xff; | |
276 | ||
277 | PrintAndLog("isOk:%02x", isOK); | |
278 | } else { | |
279 | PrintAndLog("Command execute timeout"); | |
280 | } | |
281 | ||
282 | return 0; | |
283 | } | |
284 | ||
285 | int CmdHF14AMfRdBl(const char *Cmd) | |
286 | { | |
20f9a2a1 M |
287 | uint8_t blockNo = 0; |
288 | uint8_t keyType = 0; | |
289 | uint8_t key[6] = {0, 0, 0, 0, 0, 0}; | |
290 | ||
f397b5cc | 291 | char cmdp = 0x00; |
20f9a2a1 M |
292 | |
293 | ||
294 | if (strlen(Cmd)<3) { | |
295 | PrintAndLog("Usage: hf 14 mfrdbl <block number> <key A/B> <key (12 hex symbols)>"); | |
f397b5cc | 296 | PrintAndLog(" sample: hf 14a mfrdbl 0 A FFFFFFFFFFFF "); |
20f9a2a1 M |
297 | return 0; |
298 | } | |
299 | ||
f397b5cc M |
300 | blockNo = param_get8(Cmd, 0); |
301 | cmdp = param_getchar(Cmd, 1); | |
302 | if (cmdp == 0x00) { | |
303 | PrintAndLog("Key type must be A or B"); | |
304 | return 1; | |
20f9a2a1 | 305 | } |
f397b5cc M |
306 | if (cmdp != 'A' && cmdp != 'a') keyType = 1; |
307 | if (param_gethex(Cmd, 2, key, 12)) { | |
308 | PrintAndLog("Key must include 12 HEX symbols"); | |
309 | return 1; | |
20f9a2a1 | 310 | } |
f397b5cc | 311 | PrintAndLog("--block no:%02x key type:%02x key:%s ", blockNo, keyType, sprint_hex(key, 6)); |
20f9a2a1 M |
312 | |
313 | UsbCommand c = {CMD_MIFARE_READBL, {blockNo, keyType, 0}}; | |
314 | memcpy(c.d.asBytes, key, 6); | |
315 | SendCommand(&c); | |
316 | UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500); | |
317 | ||
318 | if (resp != NULL) { | |
319 | uint8_t isOK = resp->arg[0] & 0xff; | |
320 | uint8_t * data = resp->d.asBytes; | |
321 | ||
f397b5cc M |
322 | if (isOK) |
323 | PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 16)); | |
324 | else | |
325 | PrintAndLog("isOk:%02x", isOK); | |
20f9a2a1 M |
326 | } else { |
327 | PrintAndLog("Command execute timeout"); | |
328 | } | |
329 | ||
330 | return 0; | |
331 | } | |
332 | ||
333 | int CmdHF14AMfRdSc(const char *Cmd) | |
334 | { | |
f397b5cc | 335 | int i; |
20f9a2a1 M |
336 | uint8_t sectorNo = 0; |
337 | uint8_t keyType = 0; | |
338 | uint8_t key[6] = {0, 0, 0, 0, 0, 0}; | |
339 | ||
f397b5cc M |
340 | uint8_t isOK = 0; |
341 | uint8_t * data = NULL; | |
20f9a2a1 | 342 | |
f397b5cc | 343 | char cmdp = 0x00; |
20f9a2a1 M |
344 | |
345 | if (strlen(Cmd)<3) { | |
346 | PrintAndLog("Usage: hf 14 mfrdsc <sector number> <key A/B> <key (12 hex symbols)>"); | |
f397b5cc | 347 | PrintAndLog(" sample: hf 14a mfrdsc 0 A FFFFFFFFFFFF "); |
20f9a2a1 M |
348 | return 0; |
349 | } | |
350 | ||
f397b5cc M |
351 | sectorNo = param_get8(Cmd, 0); |
352 | if (sectorNo > 63) { | |
353 | PrintAndLog("Sector number must be less than 64"); | |
354 | return 1; | |
20f9a2a1 | 355 | } |
f397b5cc M |
356 | cmdp = param_getchar(Cmd, 1); |
357 | if (cmdp == 0x00) { | |
358 | PrintAndLog("Key type must be A or B"); | |
359 | return 1; | |
20f9a2a1 | 360 | } |
f397b5cc M |
361 | if (cmdp != 'A' && cmdp != 'a') keyType = 1; |
362 | if (param_gethex(Cmd, 2, key, 12)) { | |
363 | PrintAndLog("Key must include 12 HEX symbols"); | |
364 | return 1; | |
365 | } | |
366 | PrintAndLog("--sector no:%02x key type:%02x key:%s ", sectorNo, keyType, sprint_hex(key, 6)); | |
20f9a2a1 M |
367 | |
368 | UsbCommand c = {CMD_MIFARE_READSC, {sectorNo, keyType, 0}}; | |
369 | memcpy(c.d.asBytes, key, 6); | |
370 | SendCommand(&c); | |
371 | UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500); | |
372 | PrintAndLog(" "); | |
373 | ||
374 | if (resp != NULL) { | |
f397b5cc M |
375 | isOK = resp->arg[0] & 0xff; |
376 | data = resp->d.asBytes; | |
20f9a2a1 M |
377 | |
378 | PrintAndLog("isOk:%02x", isOK); | |
f397b5cc M |
379 | if (isOK) |
380 | for (i = 0; i < 2; i++) { | |
381 | PrintAndLog("data:%s", sprint_hex(data + i * 16, 16)); | |
382 | } | |
20f9a2a1 M |
383 | } else { |
384 | PrintAndLog("Command1 execute timeout"); | |
385 | } | |
386 | ||
387 | // response2 | |
388 | resp = WaitForResponseTimeout(CMD_ACK, 500); | |
389 | PrintAndLog(" "); | |
390 | ||
391 | if (resp != NULL) { | |
f397b5cc M |
392 | isOK = resp->arg[0] & 0xff; |
393 | data = resp->d.asBytes; | |
20f9a2a1 | 394 | |
f397b5cc M |
395 | if (isOK) |
396 | for (i = 0; i < 2; i++) { | |
397 | PrintAndLog("data:%s", sprint_hex(data + i * 16, 16)); | |
20f9a2a1 M |
398 | } |
399 | } else { | |
400 | PrintAndLog("Command2 execute timeout"); | |
401 | } | |
402 | ||
403 | return 0; | |
404 | } | |
405 | ||
4abe4f58 M |
406 | int CmdHF14AMfNested(const char *Cmd) |
407 | { | |
f397b5cc M |
408 | int i, j, res, iterations; |
409 | sector * e_sector = NULL; | |
410 | uint8_t blockNo = 0; | |
4abe4f58 | 411 | uint8_t keyType = 0; |
f397b5cc M |
412 | uint8_t trgBlockNo = 0; |
413 | uint8_t trgKeyType = 0; | |
414 | uint8_t blDiff = 0; | |
415 | int SectorsCnt = 0; | |
4abe4f58 | 416 | uint8_t key[6] = {0, 0, 0, 0, 0, 0}; |
f397b5cc M |
417 | uint8_t keyBlock[16 * 6]; |
418 | uint64_t key64 = 0; | |
4abe4f58 | 419 | |
f397b5cc | 420 | char cmdp, ctmp; |
4abe4f58 | 421 | |
4abe4f58 | 422 | if (strlen(Cmd)<3) { |
f397b5cc M |
423 | PrintAndLog("Usage:"); |
424 | PrintAndLog(" all sectors: hf 14a nested <card memory> <block number> <key A/B> <key (12 hex symbols)>"); | |
425 | PrintAndLog(" one sector: hf 14a nested o <block number> <key A/B> <key (12 hex symbols)>"); | |
426 | PrintAndLog(" <target block number> <target key A/B>"); | |
427 | PrintAndLog("card memory - 1 - 1K, 2 - 2K, 4 - 4K, <other> - 1K"); | |
428 | PrintAndLog(" "); | |
429 | PrintAndLog(" sample1: hf 14a nested 1 0 A FFFFFFFFFFFF "); | |
430 | PrintAndLog(" sample2: hf 14a nested o 0 A FFFFFFFFFFFF 4 A"); | |
4abe4f58 M |
431 | return 0; |
432 | } | |
433 | ||
f397b5cc M |
434 | cmdp = param_getchar(Cmd, 0); |
435 | blockNo = param_get8(Cmd, 1); | |
436 | ctmp = param_getchar(Cmd, 2); | |
437 | if (ctmp == 0x00) { | |
438 | PrintAndLog("Key type must be A or B"); | |
439 | return 1; | |
4abe4f58 | 440 | } |
f397b5cc M |
441 | if (ctmp != 'A' && ctmp != 'a') keyType = 1; |
442 | if (param_gethex(Cmd, 3, key, 12)) { | |
443 | PrintAndLog("Key must include 12 HEX symbols"); | |
444 | return 1; | |
4abe4f58 M |
445 | } |
446 | ||
f397b5cc M |
447 | if (cmdp =='o' || cmdp == 'O') { |
448 | cmdp = 'o'; | |
449 | trgBlockNo = param_get8(Cmd, 4); | |
450 | ctmp = param_getchar(Cmd, 5); | |
451 | if (ctmp == 0x00) { | |
452 | PrintAndLog("Target key type must be A or B"); | |
453 | return 1; | |
454 | } | |
455 | if (ctmp != 'A' && ctmp != 'a') trgKeyType = 1; | |
456 | } else { | |
457 | switch (cmdp) { | |
458 | case '1': SectorsCnt = 16; break; | |
459 | case '2': SectorsCnt = 32; break; | |
460 | case '4': SectorsCnt = 64; break; | |
461 | default: SectorsCnt = 16; | |
462 | } | |
463 | } | |
4abe4f58 | 464 | |
f397b5cc M |
465 | PrintAndLog("--block no:%02x key type:%02x key:%s ", blockNo, keyType, sprint_hex(key, 6)); |
466 | if (cmdp == 'o') | |
467 | PrintAndLog("--target block no:%02x target key type:%02x ", trgBlockNo, trgKeyType); | |
4abe4f58 | 468 | |
f397b5cc M |
469 | if (cmdp == 'o') { |
470 | if (mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock)) { | |
471 | PrintAndLog("Nested error."); | |
472 | return 2; | |
473 | } | |
4abe4f58 | 474 | |
f397b5cc M |
475 | for (i = 0; i < 16; i++) { |
476 | PrintAndLog("cnt=%d key= %s", i, sprint_hex(keyBlock + i * 6, 6)); | |
477 | } | |
478 | ||
479 | // test keys | |
480 | res = mfCheckKeys(trgBlockNo, trgKeyType, 8, keyBlock, &key64); | |
481 | if (res) | |
482 | res = mfCheckKeys(trgBlockNo, trgKeyType, 8, &keyBlock[6 * 8], &key64); | |
483 | if (!res) | |
484 | PrintAndLog("Found valid key:%012llx", key64); | |
485 | else | |
486 | PrintAndLog("No valid key found"); | |
487 | } else // ------------------------------------ multiple sectors working | |
488 | { | |
489 | blDiff = blockNo % 4; | |
490 | PrintAndLog("Block shift=%d", blDiff); | |
491 | e_sector = calloc(SectorsCnt, sizeof(sector)); | |
492 | if (e_sector == NULL) return 1; | |
493 | ||
494 | //test current key 4 sectors | |
495 | memcpy(keyBlock, key, 6); | |
496 | num_to_bytes(0xa0a1a2a3a4a5, 6, (uint8_t*)(keyBlock + 1 * 6)); | |
497 | num_to_bytes(0xb0b1b2b3b4b5, 6, (uint8_t*)(keyBlock + 2 * 6)); | |
498 | num_to_bytes(0xffffffffffff, 6, (uint8_t*)(keyBlock + 3 * 6)); | |
499 | num_to_bytes(0x000000000000, 6, (uint8_t*)(keyBlock + 4 * 6)); | |
500 | num_to_bytes(0xaabbccddeeff, 6, (uint8_t*)(keyBlock + 5 * 6)); | |
501 | ||
502 | PrintAndLog("Testing known keys. Sector count=%d", SectorsCnt); | |
503 | for (i = 0; i < SectorsCnt; i++) { | |
504 | for (j = 0; j < 2; j++) { | |
505 | if (e_sector[i].foundKey[j]) continue; | |
506 | ||
507 | res = mfCheckKeys(i * 4 + blDiff, j, 6, keyBlock, &key64); | |
508 | ||
509 | if (!res) { | |
510 | e_sector[i].Key[j] = key64; | |
511 | e_sector[i].foundKey[j] = 1; | |
512 | } | |
513 | } | |
514 | } | |
515 | ||
516 | ||
517 | // nested sectors | |
518 | iterations = 0; | |
519 | PrintAndLog("nested..."); | |
520 | for (i = 0; i < NESTED_SECTOR_RETRY; i++) { | |
521 | for (trgBlockNo = blDiff; trgBlockNo < SectorsCnt * 4; trgBlockNo = trgBlockNo + 4) | |
522 | for (trgKeyType = 0; trgKeyType < 2; trgKeyType++) { | |
523 | if (e_sector[trgBlockNo / 4].foundKey[trgKeyType]) continue; | |
524 | if (mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock)) continue; | |
525 | ||
526 | iterations++; | |
527 | ||
528 | //try keys from nested | |
529 | res = mfCheckKeys(trgBlockNo, trgKeyType, 8, keyBlock, &key64); | |
530 | if (res) | |
531 | res = mfCheckKeys(trgBlockNo, trgKeyType, 8, &keyBlock[6 * 8], &key64); | |
532 | if (!res) { | |
533 | PrintAndLog("Found valid key:%012llx", key64); | |
534 | e_sector[trgBlockNo / 4].foundKey[trgKeyType] = 1; | |
535 | e_sector[trgBlockNo / 4].Key[trgKeyType] = key64; | |
536 | } | |
537 | } | |
50193c1e M |
538 | } |
539 | ||
f397b5cc M |
540 | PrintAndLog("Iterations count: %d", iterations); |
541 | //print them | |
542 | PrintAndLog("|---|----------------|---|----------------|---|"); | |
543 | PrintAndLog("|blk|key A |res|key B |res|"); | |
544 | PrintAndLog("|---|----------------|---|----------------|---|"); | |
545 | for (i = 0; i < SectorsCnt; i++) { | |
546 | PrintAndLog("|%03d| %012llx | %d | %012llx | %d |", i, | |
547 | e_sector[i].Key[0], e_sector[i].foundKey[0], e_sector[i].Key[1], e_sector[i].foundKey[1]); | |
548 | } | |
549 | PrintAndLog("|---|----------------|---|----------------|---|"); | |
550 | ||
551 | free(e_sector); | |
552 | } | |
50193c1e | 553 | |
f397b5cc M |
554 | return 0; |
555 | } | |
50193c1e | 556 | |
f397b5cc M |
557 | int CmdHF14AMfChk(const char *Cmd) |
558 | { | |
559 | int i, res; | |
560 | int keycnt = 0; | |
561 | char ctmp = 0x00; | |
562 | uint8_t blockNo = 0; | |
563 | uint8_t keyType = 0; | |
564 | uint8_t keyBlock[8 * 6]; | |
565 | uint64_t key64 = 0; | |
50193c1e | 566 | |
f397b5cc | 567 | memset(keyBlock, 0x00, sizeof(keyBlock)); |
50193c1e | 568 | |
f397b5cc M |
569 | if (strlen(Cmd)<3) { |
570 | PrintAndLog("Usage: hf 14a chk <block number> <key A/B> [<key (12 hex symbols)>]"); | |
571 | PrintAndLog(" sample: hf 14a chk 0 A FFFFFFFFFFFF a0a1a2a3a4a5 b01b2b3b4b5 "); | |
572 | return 0; | |
573 | } | |
574 | ||
575 | blockNo = param_get8(Cmd, 0); | |
576 | ctmp = param_getchar(Cmd, 1); | |
577 | if (ctmp == 0x00) { | |
578 | PrintAndLog("Key type must be A or B"); | |
579 | return 1; | |
580 | } | |
581 | if (ctmp != 'A' && ctmp != 'a') keyType = 1; | |
582 | ||
583 | for (i = 0; i < 6; i++) { | |
584 | if (!isxdigit(param_getchar(Cmd, 2 + i))) break; | |
50193c1e | 585 | |
f397b5cc M |
586 | if (param_gethex(Cmd, 2 + i, keyBlock + 6 * i, 12)) { |
587 | PrintAndLog("Key[%d] must include 12 HEX symbols", i); | |
588 | return 1; | |
4abe4f58 | 589 | } |
f397b5cc | 590 | keycnt = i + 1; |
4abe4f58 | 591 | } |
50193c1e | 592 | |
f397b5cc M |
593 | if (keycnt == 0) { |
594 | PrintAndLog("There is must be at least one key"); | |
595 | return 1; | |
596 | } | |
597 | ||
598 | PrintAndLog("--block no:%02x key type:%02x key count:%d ", blockNo, keyType, keycnt); | |
50193c1e | 599 | |
f397b5cc M |
600 | res = mfCheckKeys(blockNo, keyType, keycnt, keyBlock, &key64); |
601 | if (res !=1) { | |
602 | if (!res) | |
603 | PrintAndLog("isOk:%02x valid key:%012llx", 1, key64); | |
604 | else | |
605 | PrintAndLog("isOk:%02x", 0); | |
606 | } else { | |
607 | PrintAndLog("Command execute timeout"); | |
608 | } | |
4abe4f58 M |
609 | |
610 | return 0; | |
611 | } | |
612 | ||
613 | int CmdHF14AMf1kSim(const char *Cmd) | |
614 | { | |
615 | int i, temp; | |
616 | uint8_t uid[4] = {0, 0, 0, 0}; | |
617 | ||
618 | const char *cmdp = Cmd; | |
619 | ||
620 | ||
621 | if (strlen(Cmd)<3) { | |
622 | PrintAndLog("Usage: hf 14a mfsim <uid (8 hex symbols)>"); | |
623 | PrintAndLog(" sample: hf 14a mfsim 0a0a0a0a "); | |
624 | return 0; | |
625 | } | |
626 | ||
627 | // skip spaces | |
628 | while (*cmdp==' ' || *cmdp=='\t') cmdp++; | |
629 | ||
630 | if (strlen(cmdp) != 8) { | |
631 | PrintAndLog("Length of UID must be 8 hex symbols"); | |
632 | return 0; | |
633 | } | |
634 | ||
635 | for(i = 0; i < 4; i++) { | |
636 | sscanf((char[]){cmdp[0],cmdp[1],0},"%X",&temp); | |
637 | uid[i] = temp & 0xff; | |
638 | cmdp++; | |
639 | cmdp++; | |
640 | } | |
641 | PrintAndLog(" uid:%s ", sprint_hex(uid, 4)); | |
642 | ||
643 | UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {0, 0, 0}}; | |
644 | memcpy(c.d.asBytes, uid, 6); | |
645 | SendCommand(&c); | |
646 | ||
647 | return 0; | |
648 | } | |
649 | ||
650 | ||
7fe9b0b7 | 651 | int CmdHF14AReader(const char *Cmd) |
652 | { | |
534983d7 | 653 | UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}}; |
654 | SendCommand(&c); | |
655 | UsbCommand * resp = WaitForResponse(CMD_ACK); | |
656 | uint8_t * uid = resp->d.asBytes; | |
657 | iso14a_card_select_t * card = uid + 12; | |
658 | ||
659 | if(resp->arg[0] == 0) { | |
660 | PrintAndLog("iso14443a card select failed"); | |
661 | return 0; | |
662 | } | |
663 | ||
664 | PrintAndLog("ATQA : %02x %02x", card->atqa[0], card->atqa[1]); | |
665 | PrintAndLog(" UID : %s", sprint_hex(uid, 12)); | |
666 | PrintAndLog(" SAK : %02x [%d]", card->sak, resp->arg[0]); | |
667 | if(resp->arg[0] == 1) | |
668 | PrintAndLog(" ATS : %s", sprint_hex(card->ats, card->ats_len)); | |
669 | else | |
670 | PrintAndLog("proprietary non-iso14443a card found, RATS not supported"); | |
671 | ||
672 | return resp->arg[0]; | |
7fe9b0b7 | 673 | } |
674 | ||
675 | // ## simulate iso14443a tag | |
676 | // ## greg - added ability to specify tag UID | |
677 | int CmdHF14ASim(const char *Cmd) | |
678 | { | |
679 | ||
680 | unsigned int hi = 0, lo = 0; | |
681 | int n = 0, i = 0; | |
682 | while (sscanf(&Cmd[i++], "%1x", &n ) == 1) { | |
683 | hi= (hi << 4) | (lo >> 28); | |
684 | lo= (lo << 4) | (n & 0xf); | |
685 | } | |
686 | ||
687 | // c.arg should be set to *Cmd or convert *Cmd to the correct format for a uid | |
688 | UsbCommand c = {CMD_SIMULATE_TAG_ISO_14443a, {hi, lo, 0}}; | |
689 | PrintAndLog("Emulating 14443A TAG with UID %x%16x", hi, lo); | |
690 | SendCommand(&c); | |
691 | return 0; | |
692 | } | |
693 | ||
694 | int CmdHF14ASnoop(const char *Cmd) | |
695 | { | |
696 | UsbCommand c = {CMD_SNOOP_ISO_14443a}; | |
697 | SendCommand(&c); | |
698 | return 0; | |
699 | } | |
700 | ||
701 | static command_t CommandTable[] = | |
702 | { | |
4abe4f58 M |
703 | {"help", CmdHelp, 1, "This help"}, |
704 | {"list", CmdHF14AList, 0, "List ISO 14443a history"}, | |
f89c7050 | 705 | {"mifare", CmdHF14AMifare, 0, "Read out sector 0 parity error messages. param - <used card nonce>"}, |
4abe4f58 M |
706 | {"mfrdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"}, |
707 | {"mfrdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"}, | |
708 | {"mfwrbl", CmdHF14AMfWrBl, 0, "Write MIFARE classic block"}, | |
709 | {"nested", CmdHF14AMfNested, 0, "Test nested authentication"}, | |
f397b5cc | 710 | {"chk", CmdHF14AMfChk, 0, "Test block up to 8 keys"}, |
4abe4f58 M |
711 | {"mfsim", CmdHF14AMf1kSim, 0, "Simulate MIFARE 1k card - NOT WORKING!!!"}, |
712 | {"reader", CmdHF14AReader, 0, "Act like an ISO14443 Type A reader"}, | |
713 | {"sim", CmdHF14ASim, 0, "<UID> -- Fake ISO 14443a tag"}, | |
714 | {"snoop", CmdHF14ASnoop, 0, "Eavesdrop ISO 14443 Type A"}, | |
7fe9b0b7 | 715 | {NULL, NULL, 0, NULL} |
716 | }; | |
717 | ||
718 | int CmdHF14A(const char *Cmd) | |
719 | { | |
f397b5cc M |
720 | // flush |
721 | while (WaitForResponseTimeout(CMD_ACK, 500) != NULL) ; | |
722 | ||
723 | // parse | |
7fe9b0b7 | 724 | CmdsParse(CommandTable, Cmd); |
725 | return 0; | |
726 | } | |
727 | ||
728 | int CmdHelp(const char *Cmd) | |
729 | { | |
730 | CmdsHelp(CommandTable); | |
731 | return 0; | |
732 | } |