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