]>
Commit | Line | Data |
---|---|---|
f38a1528 | 1 | //----------------------------------------------------------------------------- |
2 | // Ultralight Code (c) 2013,2014 Midnitesnake & Andy Davies of Pentura | |
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 | // High frequency MIFARE ULTRALIGHT (C) commands | |
9 | //----------------------------------------------------------------------------- | |
10 | #include <openssl/des.h> | |
5f2cb31b | 11 | #include "cmdhfmfu.h" |
f38a1528 | 12 | #include "cmdhfmf.h" |
99a71418 | 13 | #include "cmdhf14a.h" |
f38a1528 | 14 | |
5f2cb31b | 15 | |
99a71418 | 16 | uint8_t MAX_ULTRA_BLOCKS = 0x0f; |
17 | uint8_t MAX_ULTRAC_BLOCKS = 0x2c; | |
18 | uint8_t key1_blnk_data[16] = { 0x00 }; | |
f38a1528 | 19 | uint8_t key2_defa_data[16] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }; |
20 | uint8_t key3_3des_data[16] = { 0x49,0x45,0x4D,0x4B,0x41,0x45,0x52,0x42,0x21,0x4E,0x41,0x43,0x55,0x4F,0x59,0x46 }; | |
21 | uint8_t key4_nfc_data[16] = { 0x42,0x52,0x45,0x41,0x4b,0x4d,0x45,0x49,0x46,0x59,0x4f,0x55,0x43,0x41,0x4e,0x21 }; | |
99a71418 | 22 | uint8_t key5_ones_data[16] = { 0x01 }; |
f38a1528 | 23 | |
24 | static int CmdHelp(const char *Cmd); | |
25 | ||
e3ab50ca | 26 | int CmdHF14AMfUInfo(const char *Cmd){ |
27 | ||
28 | uint8_t datatemp[7] = {0x00}; | |
29 | uint8_t isOK = 0; | |
30 | uint8_t *data = NULL; | |
31 | ||
32 | UsbCommand c = {CMD_MIFAREU_READCARD, {0, 4}}; | |
33 | SendCommand(&c); | |
34 | UsbCommand resp; | |
35 | ||
36 | if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { | |
37 | isOK = resp.arg[0] & 0xff; | |
38 | data = resp.d.asBytes; | |
39 | ||
40 | if (!isOK) { | |
41 | PrintAndLog("Error reading from tag"); | |
42 | return -1; | |
43 | } | |
44 | } else { | |
45 | PrintAndLog("Command execute timed out"); | |
46 | return -1; | |
47 | } | |
48 | ||
99a71418 | 49 | PrintAndLog(""); |
50 | PrintAndLog("-- Mifare Ultralight / Ultralight-C Tag Information ---------"); | |
51 | PrintAndLog("-------------------------------------------------------------"); | |
52 | ||
e3ab50ca | 53 | // UID |
99a71418 | 54 | memcpy( datatemp, data, 3); |
e3ab50ca | 55 | memcpy( datatemp+3, data+4, 4); |
99a71418 | 56 | |
57 | PrintAndLog("MANUFACTURER : %s", getTagInfo(datatemp[0])); | |
58 | PrintAndLog(" UID : %s ", sprint_hex(datatemp, 7)); | |
e3ab50ca | 59 | // BBC |
60 | // CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2 | |
61 | int crc0 = 0x88 ^ data[0] ^ data[1] ^data[2]; | |
62 | if ( data[3] == crc0 ) | |
99a71418 | 63 | PrintAndLog(" BCC0 : %02x - Ok", data[3]); |
e3ab50ca | 64 | else |
99a71418 | 65 | PrintAndLog(" BCC0 : %02x - crc should be %02x", data[3], crc0); |
e3ab50ca | 66 | |
67 | int crc1 = data[4] ^ data[5] ^ data[6] ^data[7]; | |
68 | if ( data[8] == crc1 ) | |
99a71418 | 69 | PrintAndLog(" BCC1 : %02x - Ok", data[8]); |
e3ab50ca | 70 | else |
99a71418 | 71 | PrintAndLog(" BCC1 : %02x - crc should be %02x", data[8], crc1 ); |
e3ab50ca | 72 | |
99a71418 | 73 | PrintAndLog(" Internal : %s ", sprint_hex(data + 9, 1)); |
e3ab50ca | 74 | |
75 | memcpy(datatemp, data+10, 2); | |
99a71418 | 76 | PrintAndLog(" Lock : %s - %s", sprint_hex(datatemp, 2),printBits( 2, &datatemp) ); |
77 | PrintAndLog(" OneTimePad : %s ", sprint_hex(data + 3*4, 4)); | |
e3ab50ca | 78 | PrintAndLog(""); |
79 | ||
5f2cb31b | 80 | int len = CmdHF14AMfucAuth("K 0"); |
81 | // PrintAndLog("CODE: %d",len); | |
82 | ||
83 | PrintAndLog("Seems to be a Ultralight %s", (len==0) ? "-C" :""); | |
e3ab50ca | 84 | return 0; |
85 | } | |
86 | ||
f38a1528 | 87 | // |
88 | // Mifare Ultralight Write Single Block | |
89 | // | |
90 | int CmdHF14AMfUWrBl(const char *Cmd){ | |
149aeada | 91 | uint8_t blockNo = 0; |
5f2cb31b | 92 | bool chinese_card = FALSE; |
149aeada | 93 | uint8_t bldata[16] = {0x00}; |
f38a1528 | 94 | UsbCommand resp; |
5f2cb31b | 95 | |
96 | char cmdp = param_getchar(Cmd, 0); | |
97 | if (strlen(Cmd) < 3 || cmdp == 'h' || cmdp == 'H') { | |
98 | PrintAndLog("Usage: hf mfu wrbl <block number> <block data (8 hex symbols)> [w]"); | |
99 | PrintAndLog(" [block number]"); | |
99a71418 | 100 | PrintAndLog(" [block data] - (8 hex symbols)"); |
5f2cb31b | 101 | PrintAndLog(" [w] - Chinese magic ultralight tag"); |
99a71418 | 102 | PrintAndLog(""); |
225ccb91 | 103 | PrintAndLog(" sample: hf mfu wrbl 0 01020304"); |
5f2cb31b | 104 | PrintAndLog(""); |
f38a1528 | 105 | return 0; |
106 | } | |
5f2cb31b | 107 | |
108 | blockNo = param_get8(Cmd, 0); | |
109 | if (blockNo > MAX_ULTRA_BLOCKS){ | |
f38a1528 | 110 | PrintAndLog("Error: Maximum number of blocks is 15 for Ultralight Cards!"); |
111 | return 1; | |
112 | } | |
5f2cb31b | 113 | |
f38a1528 | 114 | if (param_gethex(Cmd, 1, bldata, 8)) { |
115 | PrintAndLog("Block data must include 8 HEX symbols"); | |
116 | return 1; | |
117 | } | |
5f2cb31b | 118 | |
119 | if (strchr(Cmd,'w') != 0 || strchr(Cmd,'W') != 0 ) { | |
120 | chinese_card = TRUE; | |
f38a1528 | 121 | } |
5f2cb31b | 122 | |
123 | if ( blockNo <= 3) { | |
124 | if (!chinese_card){ | |
125 | PrintAndLog("Access Denied"); | |
126 | } else { | |
127 | PrintAndLog("--specialblock no:%02x", blockNo); | |
128 | PrintAndLog("--data: %s", sprint_hex(bldata, 4)); | |
129 | UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; | |
130 | memcpy(d.d.asBytes,bldata, 4); | |
131 | SendCommand(&d); | |
132 | if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { | |
133 | uint8_t isOK = resp.arg[0] & 0xff; | |
134 | PrintAndLog("isOk:%02x", isOK); | |
135 | } else { | |
136 | PrintAndLog("Command execute timeout"); | |
137 | } | |
138 | } | |
139 | } else { | |
f38a1528 | 140 | PrintAndLog("--block no:%02x", blockNo); |
141 | PrintAndLog("--data: %s", sprint_hex(bldata, 4)); | |
142 | UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}}; | |
5f2cb31b | 143 | memcpy(e.d.asBytes,bldata, 4); |
144 | SendCommand(&e); | |
f38a1528 | 145 | if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { |
146 | uint8_t isOK = resp.arg[0] & 0xff; | |
147 | PrintAndLog("isOk:%02x", isOK); | |
148 | } else { | |
149 | PrintAndLog("Command execute timeout"); | |
150 | } | |
f38a1528 | 151 | } |
152 | return 0; | |
153 | } | |
154 | ||
155 | // | |
156 | // Mifare Ultralight Read Single Block | |
157 | // | |
158 | int CmdHF14AMfURdBl(const char *Cmd){ | |
159 | ||
160 | uint8_t blockNo = 0; | |
5f2cb31b | 161 | |
162 | char cmdp = param_getchar(Cmd, 0); | |
163 | ||
164 | if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') { | |
225ccb91 | 165 | PrintAndLog("Usage: hf mfu rdbl <block number>"); |
166 | PrintAndLog(" sample: hfu mfu rdbl 0"); | |
f38a1528 | 167 | return 0; |
168 | } | |
169 | ||
170 | blockNo = param_get8(Cmd, 0); | |
171 | // if (blockNo>MAX_ULTRA_BLOCKS){ | |
172 | // PrintAndLog("Error: Maximum number of blocks is 15 for Ultralight Cards!"); | |
173 | // return 1; | |
174 | // } | |
5f2cb31b | 175 | PrintAndLog("--block no:0x%02X (%d)", (int)blockNo, blockNo); |
f38a1528 | 176 | UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}}; |
177 | SendCommand(&c); | |
178 | ||
179 | UsbCommand resp; | |
180 | if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { | |
181 | uint8_t isOK = resp.arg[0] & 0xff; | |
182 | uint8_t * data = resp.d.asBytes; | |
5f2cb31b | 183 | |
184 | PrintAndLog("isOk: %02x", isOK); | |
185 | ||
f38a1528 | 186 | if (isOK) |
5f2cb31b | 187 | PrintAndLog("Data: %s", sprint_hex(data, 4)); |
188 | } else { | |
d3499d36 | 189 | PrintAndLog("Command execute timeout"); |
190 | } | |
f38a1528 | 191 | return 0; |
192 | } | |
193 | ||
194 | // | |
99a71418 | 195 | // Mifare Ultralight / Ultralight-C; Read and Dump Card Contents |
f38a1528 | 196 | // |
99a71418 | 197 | int CmdHF14AMfUDump(const char *Cmd){ |
198 | ||
199 | FILE *fout; | |
200 | char filename[FILE_PATH_SIZE] = {0x00}; | |
201 | char * fnameptr = filename; | |
202 | ||
e3ab50ca | 203 | uint8_t *lockbytes_t = NULL; |
204 | uint8_t lockbytes[2] = {0x00}; | |
99a71418 | 205 | |
206 | uint8_t *lockbytes_t2 = NULL; | |
207 | uint8_t lockbytes2[2] = {0x00}; | |
f38a1528 | 208 | |
99a71418 | 209 | bool bit[16] = {0x00}; |
210 | bool bit2[16] = {0x00}; | |
211 | ||
f38a1528 | 212 | int i; |
149aeada | 213 | uint8_t BlockNo = 0; |
214 | int Pages = 16; | |
99a71418 | 215 | |
216 | bool tmplockbit = false; | |
149aeada | 217 | uint8_t isOK = 0; |
99a71418 | 218 | uint8_t *data = NULL; |
f38a1528 | 219 | |
99a71418 | 220 | char cmdp = param_getchar(Cmd, 0); |
221 | ||
222 | if (cmdp == 'h' || cmdp == 'H') { | |
223 | PrintAndLog("Reads all pages from Mifare Ultralight or Ultralight-C tag."); | |
224 | PrintAndLog("It saves binary dump into the file `filename.bin` or `cardUID.bin`"); | |
225 | PrintAndLog("Usage: hf mfu dump <c> <filename w/o .bin>"); | |
226 | PrintAndLog(" <c> optional cardtype c == Ultralight-C, if not defaults to Ultralight"); | |
227 | PrintAndLog(" sample: hf mfu dump"); | |
228 | PrintAndLog(" : hf mfu dump myfile"); | |
229 | PrintAndLog(" : hf mfu dump c myfile"); | |
230 | return 0; | |
231 | } | |
232 | ||
233 | // UL or UL-C? | |
234 | Pages = (cmdp == 'c' || cmdp == 'C') ? 44 : 16; | |
235 | ||
236 | PrintAndLog("Dumping Ultralight%s Card Data...", (Pages ==16)?"":"-C"); | |
f38a1528 | 237 | |
f38a1528 | 238 | UsbCommand c = {CMD_MIFAREU_READCARD, {BlockNo,Pages}}; |
239 | SendCommand(&c); | |
240 | UsbCommand resp; | |
241 | ||
242 | if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { | |
99a71418 | 243 | isOK = resp.arg[0] & 0xff; |
244 | if (!isOK) { | |
245 | PrintAndLog("Command error"); | |
246 | return 0; | |
247 | } | |
248 | data = resp.d.asBytes; | |
249 | } else { | |
250 | PrintAndLog("Command execute timeout"); | |
251 | return 0; | |
252 | } | |
253 | ||
254 | // Load lock bytes. | |
255 | int j = 0; | |
256 | ||
257 | lockbytes_t = data + 8; | |
258 | lockbytes[0] = lockbytes_t[2]; | |
259 | lockbytes[1] = lockbytes_t[3]; | |
260 | for(j = 0; j < 16; j++){ | |
261 | bit[j] = lockbytes[j/8] & ( 1 <<(7-j%8)); | |
262 | } | |
263 | ||
264 | // Load bottom lockbytes if available | |
265 | if ( Pages == 44 ) { | |
266 | ||
267 | lockbytes_t2 = data + (40*4); | |
268 | lockbytes2[0] = lockbytes_t2[2]; | |
269 | lockbytes2[1] = lockbytes_t2[3]; | |
270 | for (j = 0; j < 16; j++) { | |
271 | bit2[j] = lockbytes2[j/8] & ( 1 <<(7-j%8)); | |
272 | } | |
f38a1528 | 273 | } |
99a71418 | 274 | |
275 | for (i = 0; i < Pages; ++i) { | |
276 | ||
277 | if ( i < 3 ) { | |
278 | PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); | |
279 | continue; | |
280 | } | |
281 | ||
282 | switch(i){ | |
283 | case 3: tmplockbit = bit[4]; break; | |
284 | case 4: tmplockbit = bit[3]; break; | |
285 | case 5: tmplockbit = bit[2]; break; | |
286 | case 6: tmplockbit = bit[1]; break; | |
287 | case 7: tmplockbit = bit[0]; break; | |
288 | case 8: tmplockbit = bit[15]; break; | |
289 | case 9: tmplockbit = bit[14]; break; | |
290 | case 10: tmplockbit = bit[13]; break; | |
291 | case 11: tmplockbit = bit[12]; break; | |
292 | case 12: tmplockbit = bit[11]; break; | |
293 | case 13: tmplockbit = bit[10]; break; | |
294 | case 14: tmplockbit = bit[9]; break; | |
295 | case 15: tmplockbit = bit[8]; break; | |
296 | case 16: | |
297 | case 17: | |
298 | case 18: | |
299 | case 19: tmplockbit = bit2[6]; break; | |
300 | case 20: | |
301 | case 21: | |
302 | case 22: | |
303 | case 23: tmplockbit = bit2[5]; break; | |
304 | case 24: | |
305 | case 25: | |
306 | case 26: | |
307 | case 27: tmplockbit = bit2[4]; break; | |
308 | case 28: | |
309 | case 29: | |
310 | case 30: | |
311 | case 31: tmplockbit = bit2[2]; break; | |
312 | case 32: | |
313 | case 33: | |
314 | case 34: | |
315 | case 35: tmplockbit = bit2[1]; break; | |
316 | case 36: | |
317 | case 37: | |
318 | case 38: | |
319 | case 39: tmplockbit = bit2[0]; break; | |
320 | case 40: tmplockbit = bit2[12]; break; | |
321 | case 41: tmplockbit = bit2[11]; break; | |
322 | case 42: tmplockbit = bit2[10]; break; //auth0 | |
323 | case 43: tmplockbit = bit2[9]; break; //auth1 | |
324 | default: break; | |
325 | } | |
326 | PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),tmplockbit); | |
327 | } | |
328 | ||
329 | int len = 0; | |
330 | if ( Pages == 16 ) | |
331 | len = param_getstr(Cmd,0,filename); | |
332 | else | |
333 | len = param_getstr(Cmd,1,filename); | |
334 | ||
335 | if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; | |
336 | ||
337 | // user supplied filename? | |
338 | if (len < 1) { | |
339 | ||
340 | // UID = data 0-1-2 4-5-6-7 (skips a beat) | |
341 | sprintf(fnameptr, "%02X", data[0]); | |
342 | fnameptr += 2; | |
343 | sprintf(fnameptr, "%02X", data[1]); | |
344 | fnameptr += 2; | |
345 | sprintf(fnameptr, "%02X", data[2]); | |
346 | fnameptr += 2; | |
347 | sprintf(fnameptr, "%02X", data[4]); | |
348 | fnameptr += 2; | |
349 | sprintf(fnameptr, "%02X", data[5]); | |
350 | fnameptr += 2; | |
351 | sprintf(fnameptr, "%02X", data[6]); | |
352 | fnameptr += 2; | |
353 | sprintf(fnameptr, "%02X", data[7]); | |
354 | fnameptr += 2; | |
355 | ||
356 | } else { | |
357 | fnameptr += len; | |
358 | } | |
359 | ||
360 | // add file extension | |
361 | sprintf(fnameptr, ".bin"); | |
362 | ||
363 | if ((fout = fopen(filename,"wb")) == NULL) { | |
364 | PrintAndLog("Could not create file name %s", filename); | |
365 | return 1; | |
366 | } | |
367 | fwrite( data, 1, Pages*4, fout ); | |
368 | fclose(fout); | |
369 | ||
370 | PrintAndLog("Dumped %d pages, wrote %d bytes to %s", Pages, Pages*4, filename); | |
f38a1528 | 371 | return 0; |
372 | } | |
373 | ||
374 | // Needed to Authenticate to Ultralight C tags | |
375 | void rol (uint8_t *data, const size_t len){ | |
376 | uint8_t first = data[0]; | |
377 | for (size_t i = 0; i < len-1; i++) { | |
378 | data[i] = data[i+1]; | |
379 | } | |
380 | data[len-1] = first; | |
381 | } | |
382 | ||
383 | //------------------------------------------------------------------------------- | |
384 | // Ultralight C Methods | |
385 | //------------------------------------------------------------------------------- | |
386 | ||
387 | // | |
388 | // Ultralight C Authentication Demo {currently uses hard-coded key} | |
389 | // | |
390 | int CmdHF14AMfucAuth(const char *Cmd){ | |
391 | ||
99a71418 | 392 | uint8_t blockNo = 0, keyNo = 0; |
149aeada | 393 | uint8_t e_RndB[8] = {0x00}; |
99a71418 | 394 | uint32_t cuid = 0; |
149aeada | 395 | unsigned char RndARndB[16] = {0x00}; |
396 | uint8_t key[16] = {0x00}; | |
f38a1528 | 397 | DES_cblock RndA, RndB; |
db297e69 | 398 | DES_cblock iv; |
f38a1528 | 399 | DES_key_schedule ks1,ks2; |
400 | DES_cblock key1,key2; | |
401 | ||
225ccb91 | 402 | char cmdp = param_getchar(Cmd, 0); |
db297e69 | 403 | // |
404 | memset(iv, 0, 8); | |
405 | ||
225ccb91 | 406 | if (cmdp == 'h' || cmdp == 'H') { |
5f2cb31b | 407 | PrintAndLog("Usage: hf mfu cauth k <key number>"); |
225ccb91 | 408 | PrintAndLog(" 1 = all zeros key"); |
409 | PrintAndLog(" 2 = 0x00-0x0F key"); | |
410 | PrintAndLog(" 3 = nfc key"); | |
411 | PrintAndLog(" 4 = all ones key"); | |
412 | PrintAndLog(" defaults to 3DES standard key"); | |
5f2cb31b | 413 | PrintAndLog(" sample : hf mfu cauth k"); |
414 | PrintAndLog(" : hf mfu cauth k 3"); | |
f38a1528 | 415 | return 0; |
416 | } | |
417 | ||
418 | //Change key to user defined one | |
225ccb91 | 419 | if (cmdp == 'k' || cmdp == 'K'){ |
420 | ||
421 | keyNo = param_get8(Cmd, 1); | |
422 | ||
423 | switch(keyNo){ | |
f38a1528 | 424 | case 0: |
425 | memcpy(key,key1_blnk_data,16); | |
426 | break; | |
427 | case 1: | |
428 | memcpy(key,key2_defa_data,16); | |
429 | break; | |
225ccb91 | 430 | case 2: |
f38a1528 | 431 | memcpy(key,key4_nfc_data,16); |
432 | break; | |
225ccb91 | 433 | case 3: |
f38a1528 | 434 | memcpy(key,key5_ones_data,16); |
435 | break; | |
436 | default: | |
437 | memcpy(key,key3_3des_data,16); | |
438 | break; | |
439 | } | |
225ccb91 | 440 | } else { |
f38a1528 | 441 | memcpy(key,key3_3des_data,16); |
442 | } | |
225ccb91 | 443 | |
f38a1528 | 444 | memcpy(key1,key,8); |
445 | memcpy(key2,key+8,8); | |
446 | DES_set_key((DES_cblock *)key1,&ks1); | |
447 | DES_set_key((DES_cblock *)key2,&ks2); | |
448 | ||
225ccb91 | 449 | //Auth1 |
450 | UsbCommand c = {CMD_MIFAREUC_AUTH1, {blockNo}}; | |
451 | SendCommand(&c); | |
452 | UsbCommand resp; | |
453 | if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { | |
454 | uint8_t isOK = resp.arg[0] & 0xff; | |
455 | cuid = resp.arg[1]; | |
456 | uint8_t * data= resp.d.asBytes; | |
457 | ||
458 | if (isOK){ | |
459 | PrintAndLog("enc(RndB):%s", sprint_hex(data+1, 8)); | |
460 | memcpy(e_RndB,data+1,8); | |
5f2cb31b | 461 | } else { |
462 | return 2; // auth failed. | |
463 | } | |
225ccb91 | 464 | } else { |
465 | PrintAndLog("Command execute timeout"); | |
5f2cb31b | 466 | return 1; |
f38a1528 | 467 | } |
f38a1528 | 468 | |
469 | //Do crypto magic | |
470 | DES_random_key(&RndA); | |
471 | DES_ede2_cbc_encrypt(e_RndB,RndB,sizeof(e_RndB),&ks1,&ks2,&iv,0); | |
472 | PrintAndLog(" RndB:%s",sprint_hex(RndB, 8)); | |
473 | PrintAndLog(" RndA:%s",sprint_hex(RndA, 8)); | |
474 | rol(RndB,8); | |
475 | memcpy(RndARndB,RndA,8); | |
476 | memcpy(RndARndB+8,RndB,8); | |
477 | PrintAndLog(" RA+B:%s",sprint_hex(RndARndB, 16)); | |
478 | DES_ede2_cbc_encrypt(RndARndB,RndARndB,sizeof(RndARndB),&ks1,&ks2,&e_RndB,1); | |
479 | PrintAndLog("enc(RA+B):%s",sprint_hex(RndARndB, 16)); | |
480 | ||
481 | //Auth2 | |
482 | UsbCommand d = {CMD_MIFAREUC_AUTH2, {cuid}}; | |
483 | memcpy(d.d.asBytes,RndARndB, 16); | |
484 | SendCommand(&d); | |
485 | ||
225ccb91 | 486 | UsbCommand respb; |
487 | if (WaitForResponseTimeout(CMD_ACK,&respb,1500)) { | |
488 | uint8_t isOK = respb.arg[0] & 0xff; | |
489 | uint8_t * data2= respb.d.asBytes; | |
f38a1528 | 490 | |
225ccb91 | 491 | if (isOK){ |
492 | PrintAndLog("enc(RndA'):%s", sprint_hex(data2+1, 8)); | |
5f2cb31b | 493 | } else { |
494 | return 2; | |
225ccb91 | 495 | } |
5f2cb31b | 496 | |
225ccb91 | 497 | } else { |
498 | PrintAndLog("Command execute timeout"); | |
5f2cb31b | 499 | return 1; |
225ccb91 | 500 | } |
5f2cb31b | 501 | return 0; |
f38a1528 | 502 | } |
503 | ||
504 | // | |
505 | // Ultralight C Read Single Block | |
506 | // | |
507 | int CmdHF14AMfUCRdBl(const char *Cmd) | |
508 | { | |
5f2cb31b | 509 | uint8_t blockNo = -1; |
510 | char cmdp = param_getchar(Cmd, 0); | |
511 | ||
512 | if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') { | |
225ccb91 | 513 | PrintAndLog("Usage: hf mfu crdbl <block number>"); |
514 | PrintAndLog(" sample: hf mfu crdbl 0"); | |
f38a1528 | 515 | return 0; |
516 | } | |
517 | ||
518 | blockNo = param_get8(Cmd, 0); | |
5f2cb31b | 519 | if (blockNo < 0) { |
520 | PrintAndLog("Wrong block number"); | |
521 | return 1; | |
522 | } | |
523 | ||
524 | if (blockNo > (MAX_ULTRAC_BLOCKS+4) ){ | |
525 | PrintAndLog("Error: Maximum number of readable blocks is 47 for Ultralight-C Cards!"); | |
f38a1528 | 526 | return 1; |
5f2cb31b | 527 | } |
528 | ||
529 | PrintAndLog("--block no: 0x%02X (%d)", (int)blockNo, blockNo); | |
f38a1528 | 530 | |
531 | //Read Block | |
532 | UsbCommand e = {CMD_MIFAREU_READBL, {blockNo}}; | |
533 | SendCommand(&e); | |
534 | UsbCommand resp_c; | |
535 | if (WaitForResponseTimeout(CMD_ACK,&resp_c,1500)) { | |
5f2cb31b | 536 | uint8_t isOK = resp_c.arg[0] & 0xff; |
537 | uint8_t *data = resp_c.d.asBytes; | |
538 | ||
539 | PrintAndLog("isOk: %02x", isOK); | |
f38a1528 | 540 | if (isOK) |
5f2cb31b | 541 | PrintAndLog("Data: %s", sprint_hex(data, 4)); |
542 | ||
543 | } else { | |
544 | PrintAndLog("Command execute timeout"); | |
545 | } | |
f38a1528 | 546 | return 0; |
547 | } | |
548 | ||
f38a1528 | 549 | // |
550 | // Mifare Ultralight C Write Single Block | |
551 | // | |
552 | int CmdHF14AMfUCWrBl(const char *Cmd){ | |
553 | ||
554 | uint8_t blockNo = 0; | |
5f2cb31b | 555 | bool chinese_card = FALSE; |
149aeada | 556 | uint8_t bldata[16] = {0x00}; |
f38a1528 | 557 | UsbCommand resp; |
5f2cb31b | 558 | |
559 | char cmdp = param_getchar(Cmd, 0); | |
560 | ||
561 | if (strlen(Cmd) < 3 || cmdp == 'h' || cmdp == 'H') { | |
225ccb91 | 562 | PrintAndLog("Usage: hf mfu cwrbl <block number> <block data (8 hex symbols)> [w]"); |
5f2cb31b | 563 | PrintAndLog(" [block number]"); |
564 | PrintAndLog(" [block data] - (8 hex symbols)"); | |
565 | PrintAndLog(" [w] - Chinese magic ultralight tag"); | |
566 | PrintAndLog(""); | |
567 | PrintAndLog(" sample: hf mfu cwrbl 0 01020304"); | |
568 | PrintAndLog(""); | |
f38a1528 | 569 | return 0; |
5f2cb31b | 570 | } |
571 | ||
f38a1528 | 572 | blockNo = param_get8(Cmd, 0); |
5f2cb31b | 573 | if (blockNo > (MAX_ULTRAC_BLOCKS+4) ){ |
574 | PrintAndLog("Error: Maximum number of blocks is 47 for Ultralight-C Cards!"); | |
f38a1528 | 575 | return 1; |
576 | } | |
5f2cb31b | 577 | |
f38a1528 | 578 | if (param_gethex(Cmd, 1, bldata, 8)) { |
579 | PrintAndLog("Block data must include 8 HEX symbols"); | |
580 | return 1; | |
581 | } | |
5f2cb31b | 582 | |
583 | if (strchr(Cmd,'w') != 0 || strchr(Cmd,'W') != 0 ) { | |
584 | chinese_card = TRUE; | |
f38a1528 | 585 | } |
5f2cb31b | 586 | |
587 | if ( blockNo <= 3 ) { | |
588 | if (!chinese_card){ | |
589 | PrintAndLog("Access Denied"); | |
590 | } else { | |
591 | PrintAndLog("--Special block no: 0x%02x", blockNo); | |
592 | PrintAndLog("--Data: %s", sprint_hex(bldata, 4)); | |
593 | UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; | |
594 | memcpy(d.d.asBytes,bldata, 4); | |
595 | SendCommand(&d); | |
596 | if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { | |
597 | uint8_t isOK = resp.arg[0] & 0xff; | |
598 | PrintAndLog("isOk:%02x", isOK); | |
599 | } else { | |
600 | PrintAndLog("Command execute timeout"); | |
601 | } | |
602 | } | |
603 | } else { | |
604 | PrintAndLog("--Block no : 0x%02x", blockNo); | |
605 | PrintAndLog("--Data: %s", sprint_hex(bldata, 4)); | |
f38a1528 | 606 | UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}}; |
607 | memcpy(e.d.asBytes,bldata, 4); | |
608 | SendCommand(&e); | |
609 | if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { | |
610 | uint8_t isOK = resp.arg[0] & 0xff; | |
5f2cb31b | 611 | PrintAndLog("isOk : %02x", isOK); |
f38a1528 | 612 | } else { |
613 | PrintAndLog("Command execute timeout"); | |
614 | } | |
5f2cb31b | 615 | } |
616 | return 0; | |
f38a1528 | 617 | } |
618 | ||
619 | //------------------------------------ | |
620 | // Menu Stuff | |
621 | //------------------------------------ | |
622 | static command_t CommandTable[] = | |
623 | { | |
e3ab50ca | 624 | {"help", CmdHelp, 1,"This help"}, |
625 | {"dbg", CmdHF14AMfDbg, 0,"Set default debug mode"}, | |
626 | {"info", CmdHF14AMfUInfo, 0,"Taginfo"}, | |
5f2cb31b | 627 | {"dump", CmdHF14AMfUDump, 0,"Dump MIFARE Ultralight / Ultralight-C tag to binary file"}, |
e3ab50ca | 628 | {"rdbl", CmdHF14AMfURdBl, 0,"Read block - MIFARE Ultralight"}, |
5f2cb31b | 629 | {"wrbl", CmdHF14AMfUWrBl, 0,"Write block - MIFARE Ultralight"}, |
e3ab50ca | 630 | {"crdbl", CmdHF14AMfUCRdBl, 0,"Read block - MIFARE Ultralight C"}, |
5f2cb31b | 631 | {"cwrbl", CmdHF14AMfUCWrBl, 0,"Write MIFARE Ultralight C block"}, |
632 | {"cauth", CmdHF14AMfucAuth, 0,"try a Ultralight C Authentication"}, | |
f38a1528 | 633 | {NULL, NULL, 0, NULL} |
634 | }; | |
635 | ||
636 | int CmdHFMFUltra(const char *Cmd){ | |
f38a1528 | 637 | WaitForResponseTimeout(CMD_ACK,NULL,100); |
638 | CmdsParse(CommandTable, Cmd); | |
639 | return 0; | |
640 | } | |
641 | ||
642 | int CmdHelp(const char *Cmd){ | |
643 | CmdsHelp(CommandTable); | |
644 | return 0; | |
645 | } |