| 1 | // Merlok, 2011, 2012\r |
| 2 | // people from mifare@nethemba.com, 2010\r |
| 3 | //\r |
| 4 | // This code is licensed to you under the terms of the GNU GPL, version 2 or,\r |
| 5 | // at your option, any later version. See the LICENSE.txt file for the text of\r |
| 6 | // the license.\r |
| 7 | //-----------------------------------------------------------------------------\r |
| 8 | // mifare commands\r |
| 9 | //-----------------------------------------------------------------------------\r |
| 10 | \r |
| 11 | #include <stdio.h>\r |
| 12 | #include <stdlib.h> \r |
| 13 | #include <string.h>\r |
| 14 | #include <pthread.h>\r |
| 15 | #include "mifarehost.h"\r |
| 16 | #include "proxmark3.h"\r |
| 17 | \r |
| 18 | #define llx PRIx64\r |
| 19 | \r |
| 20 | // MIFARE\r |
| 21 | int compar_int(const void * a, const void * b) {\r |
| 22 | // didn't work: (the result is truncated to 32 bits)\r |
| 23 | //return (*(uint64_t*)b - *(uint64_t*)a);\r |
| 24 | \r |
| 25 | // better:\r |
| 26 | if (*(uint64_t*)b == *(uint64_t*)a) return 0;\r |
| 27 | else if (*(uint64_t*)b > *(uint64_t*)a) return 1;\r |
| 28 | else return -1;\r |
| 29 | }\r |
| 30 | \r |
| 31 | // Compare 16 Bits out of cryptostate\r |
| 32 | int Compare16Bits(const void * a, const void * b) {\r |
| 33 | if ((*(uint64_t*)b & 0x00ff000000ff0000) == (*(uint64_t*)a & 0x00ff000000ff0000)) return 0;\r |
| 34 | else if ((*(uint64_t*)b & 0x00ff000000ff0000) > (*(uint64_t*)a & 0x00ff000000ff0000)) return 1;\r |
| 35 | else return -1;\r |
| 36 | }\r |
| 37 | \r |
| 38 | typedef \r |
| 39 | struct {\r |
| 40 | union {\r |
| 41 | struct Crypto1State *slhead;\r |
| 42 | uint64_t *keyhead;\r |
| 43 | } head;\r |
| 44 | union {\r |
| 45 | struct Crypto1State *sltail;\r |
| 46 | uint64_t *keytail;\r |
| 47 | } tail;\r |
| 48 | uint32_t len;\r |
| 49 | uint32_t uid;\r |
| 50 | uint32_t blockNo;\r |
| 51 | uint32_t keyType;\r |
| 52 | uint32_t nt;\r |
| 53 | uint32_t ks1;\r |
| 54 | } StateList_t;\r |
| 55 | \r |
| 56 | \r |
| 57 | // wrapper function for multi-threaded lfsr_recovery32\r |
| 58 | void* nested_worker_thread(void *arg)\r |
| 59 | {\r |
| 60 | struct Crypto1State *p1;\r |
| 61 | StateList_t *statelist = arg;\r |
| 62 | \r |
| 63 | statelist->head.slhead = lfsr_recovery32(statelist->ks1, statelist->nt ^ statelist->uid);\r |
| 64 | for (p1 = statelist->head.slhead; *(uint64_t *)p1 != 0; p1++);\r |
| 65 | statelist->len = p1 - statelist->head.slhead;\r |
| 66 | statelist->tail.sltail = --p1;\r |
| 67 | qsort(statelist->head.slhead, statelist->len, sizeof(uint64_t), Compare16Bits);\r |
| 68 | \r |
| 69 | return statelist->head.slhead;\r |
| 70 | }\r |
| 71 | \r |
| 72 | int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * resultKey, bool calibrate) \r |
| 73 | {\r |
| 74 | uint16_t i, len;\r |
| 75 | uint32_t uid;\r |
| 76 | UsbCommand resp;\r |
| 77 | StateList_t statelists[2];\r |
| 78 | struct Crypto1State *p1, *p2, *p3, *p4;\r |
| 79 | \r |
| 80 | // flush queue\r |
| 81 | WaitForResponseTimeout(CMD_ACK,NULL,100);\r |
| 82 | \r |
| 83 | UsbCommand c = {CMD_MIFARE_NESTED, {blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, calibrate}};\r |
| 84 | memcpy(c.d.asBytes, key, 6);\r |
| 85 | SendCommand(&c);\r |
| 86 | \r |
| 87 | if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {\r |
| 88 | len = resp.arg[1];\r |
| 89 | if (len == 2) { \r |
| 90 | memcpy(&uid, resp.d.asBytes, 4);\r |
| 91 | PrintAndLog("uid:%08x len=%d trgbl=%d trgkey=%x", uid, len, (uint16_t)resp.arg[2] & 0xff, (uint16_t)resp.arg[2] >> 8);\r |
| 92 | \r |
| 93 | for (i = 0; i < 2; i++) {\r |
| 94 | statelists[i].blockNo = resp.arg[2] & 0xff;\r |
| 95 | statelists[i].keyType = (resp.arg[2] >> 8) & 0xff;\r |
| 96 | statelists[i].uid = uid;\r |
| 97 | \r |
| 98 | memcpy(&statelists[i].nt, (void *)(resp.d.asBytes + 4 + i * 8 + 0), 4);\r |
| 99 | memcpy(&statelists[i].ks1, (void *)(resp.d.asBytes + 4 + i * 8 + 4), 4);\r |
| 100 | }\r |
| 101 | }\r |
| 102 | else {\r |
| 103 | PrintAndLog("Got 0 keys from proxmark."); \r |
| 104 | return 1;\r |
| 105 | }\r |
| 106 | }\r |
| 107 | \r |
| 108 | // calc keys\r |
| 109 | \r |
| 110 | pthread_t thread_id[2];\r |
| 111 | \r |
| 112 | // create and run worker threads\r |
| 113 | for (i = 0; i < 2; i++) {\r |
| 114 | pthread_create(thread_id + i, NULL, nested_worker_thread, &statelists[i]);\r |
| 115 | }\r |
| 116 | \r |
| 117 | // wait for threads to terminate:\r |
| 118 | for (i = 0; i < 2; i++) {\r |
| 119 | pthread_join(thread_id[i], (void*)&statelists[i].head.slhead);\r |
| 120 | }\r |
| 121 | \r |
| 122 | \r |
| 123 | // the first 16 Bits of the cryptostate already contain part of our key.\r |
| 124 | // Create the intersection of the two lists based on these 16 Bits and\r |
| 125 | // roll back the cryptostate\r |
| 126 | p1 = p3 = statelists[0].head.slhead; \r |
| 127 | p2 = p4 = statelists[1].head.slhead;\r |
| 128 | while (p1 <= statelists[0].tail.sltail && p2 <= statelists[1].tail.sltail) {\r |
| 129 | if (Compare16Bits(p1, p2) == 0) {\r |
| 130 | struct Crypto1State savestate, *savep = &savestate;\r |
| 131 | savestate = *p1;\r |
| 132 | while(Compare16Bits(p1, savep) == 0 && p1 <= statelists[0].tail.sltail) {\r |
| 133 | *p3 = *p1;\r |
| 134 | lfsr_rollback_word(p3, statelists[0].nt ^ statelists[0].uid, 0);\r |
| 135 | p3++;\r |
| 136 | p1++;\r |
| 137 | }\r |
| 138 | savestate = *p2;\r |
| 139 | while(Compare16Bits(p2, savep) == 0 && p2 <= statelists[1].tail.sltail) {\r |
| 140 | *p4 = *p2;\r |
| 141 | lfsr_rollback_word(p4, statelists[1].nt ^ statelists[1].uid, 0);\r |
| 142 | p4++;\r |
| 143 | p2++;\r |
| 144 | }\r |
| 145 | }\r |
| 146 | else {\r |
| 147 | while (Compare16Bits(p1, p2) == -1) p1++;\r |
| 148 | while (Compare16Bits(p1, p2) == 1) p2++;\r |
| 149 | }\r |
| 150 | }\r |
| 151 | p3->even = 0; p3->odd = 0;\r |
| 152 | p4->even = 0; p4->odd = 0;\r |
| 153 | statelists[0].len = p3 - statelists[0].head.slhead;\r |
| 154 | statelists[1].len = p4 - statelists[1].head.slhead;\r |
| 155 | statelists[0].tail.sltail=--p3;\r |
| 156 | statelists[1].tail.sltail=--p4;\r |
| 157 | \r |
| 158 | // the statelists now contain possible keys. The key we are searching for must be in the\r |
| 159 | // intersection of both lists. Create the intersection:\r |
| 160 | qsort(statelists[0].head.keyhead, statelists[0].len, sizeof(uint64_t), compar_int);\r |
| 161 | qsort(statelists[1].head.keyhead, statelists[1].len, sizeof(uint64_t), compar_int);\r |
| 162 | \r |
| 163 | uint64_t *p5, *p6, *p7;\r |
| 164 | p5 = p7 = statelists[0].head.keyhead; \r |
| 165 | p6 = statelists[1].head.keyhead;\r |
| 166 | while (p5 <= statelists[0].tail.keytail && p6 <= statelists[1].tail.keytail) {\r |
| 167 | if (compar_int(p5, p6) == 0) {\r |
| 168 | *p7++ = *p5++;\r |
| 169 | p6++;\r |
| 170 | }\r |
| 171 | else {\r |
| 172 | while (compar_int(p5, p6) == -1) p5++;\r |
| 173 | while (compar_int(p5, p6) == 1) p6++;\r |
| 174 | }\r |
| 175 | }\r |
| 176 | statelists[0].len = p7 - statelists[0].head.keyhead;\r |
| 177 | statelists[0].tail.keytail=--p7;\r |
| 178 | \r |
| 179 | memset(resultKey, 0, 6);\r |
| 180 | // The list may still contain several key candidates. Test each of them with mfCheckKeys\r |
| 181 | for (i = 0; i < statelists[0].len; i++) {\r |
| 182 | uint8_t keyBlock[6];\r |
| 183 | uint64_t key64;\r |
| 184 | crypto1_get_lfsr(statelists[0].head.slhead + i, &key64);\r |
| 185 | num_to_bytes(key64, 6, keyBlock);\r |
| 186 | key64 = 0;\r |
| 187 | if (!mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, 1, keyBlock, &key64)) {\r |
| 188 | num_to_bytes(key64, 6, resultKey);\r |
| 189 | break;\r |
| 190 | }\r |
| 191 | }\r |
| 192 | \r |
| 193 | free(statelists[0].head.slhead);\r |
| 194 | free(statelists[1].head.slhead);\r |
| 195 | \r |
| 196 | return 0;\r |
| 197 | }\r |
| 198 | \r |
| 199 | int mfCheckKeys (uint8_t blockNo, uint8_t keyType, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key){\r |
| 200 | \r |
| 201 | *key = 0;\r |
| 202 | \r |
| 203 | UsbCommand c = {CMD_MIFARE_CHKKEYS, {blockNo, keyType, keycnt}};\r |
| 204 | memcpy(c.d.asBytes, keyBlock, 6 * keycnt);\r |
| 205 | SendCommand(&c);\r |
| 206 | \r |
| 207 | UsbCommand resp;\r |
| 208 | if (!WaitForResponseTimeout(CMD_ACK,&resp,3000)) return 1;\r |
| 209 | if ((resp.arg[0] & 0xff) != 0x01) return 2;\r |
| 210 | *key = bytes_to_num(resp.d.asBytes, 6);\r |
| 211 | return 0;\r |
| 212 | }\r |
| 213 | \r |
| 214 | // EMULATOR\r |
| 215 | \r |
| 216 | int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount) {\r |
| 217 | UsbCommand c = {CMD_MIFARE_EML_MEMGET, {blockNum, blocksCount, 0}};\r |
| 218 | SendCommand(&c);\r |
| 219 | \r |
| 220 | UsbCommand resp;\r |
| 221 | if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) return 1;\r |
| 222 | memcpy(data, resp.d.asBytes, blocksCount * 16);\r |
| 223 | return 0;\r |
| 224 | }\r |
| 225 | \r |
| 226 | int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount) {\r |
| 227 | UsbCommand c = {CMD_MIFARE_EML_MEMSET, {blockNum, blocksCount, 0}};\r |
| 228 | memcpy(c.d.asBytes, data, blocksCount * 16); \r |
| 229 | SendCommand(&c);\r |
| 230 | return 0;\r |
| 231 | }\r |
| 232 | \r |
| 233 | // "MAGIC" CARD\r |
| 234 | \r |
| 235 | int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, bool wantWipe) {\r |
| 236 | uint8_t oldblock0[16] = {0x00};\r |
| 237 | uint8_t block0[16] = {0x00};\r |
| 238 | \r |
| 239 | int old = mfCGetBlock(0, oldblock0, CSETBLOCK_SINGLE_OPER);\r |
| 240 | if (old == 0) {\r |
| 241 | memcpy(block0, oldblock0, 16);\r |
| 242 | PrintAndLog("old block 0: %s", sprint_hex(block0,16));\r |
| 243 | } else {\r |
| 244 | PrintAndLog("Couldn't get old data. Will write over the last bytes of Block 0.");\r |
| 245 | }\r |
| 246 | \r |
| 247 | // fill in the new values\r |
| 248 | // UID\r |
| 249 | memcpy(block0, uid, 4); \r |
| 250 | // Mifare UID BCC\r |
| 251 | block0[4] = block0[0]^block0[1]^block0[2]^block0[3];\r |
| 252 | // mifare classic SAK(byte 5) and ATQA(byte 6 and 7, reversed)\r |
| 253 | if (sak!=NULL)\r |
| 254 | block0[5]=sak[0];\r |
| 255 | if (atqa!=NULL) {\r |
| 256 | block0[6]=atqa[1];\r |
| 257 | block0[7]=atqa[0];\r |
| 258 | }\r |
| 259 | PrintAndLog("new block 0: %s", sprint_hex(block0,16));\r |
| 260 | return mfCSetBlock(0, block0, oldUID, wantWipe, CSETBLOCK_SINGLE_OPER);\r |
| 261 | }\r |
| 262 | \r |
| 263 | int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, bool wantWipe, uint8_t params) {\r |
| 264 | \r |
| 265 | uint8_t isOK = 0;\r |
| 266 | UsbCommand c = {CMD_MIFARE_CSETBLOCK, {wantWipe, params & (0xFE | (uid == NULL ? 0:1)), blockNo}};\r |
| 267 | memcpy(c.d.asBytes, data, 16); \r |
| 268 | SendCommand(&c);\r |
| 269 | \r |
| 270 | UsbCommand resp;\r |
| 271 | if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {\r |
| 272 | isOK = resp.arg[0] & 0xff;\r |
| 273 | if (uid != NULL) \r |
| 274 | memcpy(uid, resp.d.asBytes, 4);\r |
| 275 | if (!isOK) \r |
| 276 | return 2;\r |
| 277 | } else {\r |
| 278 | PrintAndLog("Command execute timeout");\r |
| 279 | return 1;\r |
| 280 | }\r |
| 281 | return 0;\r |
| 282 | }\r |
| 283 | \r |
| 284 | int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params) {\r |
| 285 | uint8_t isOK = 0;\r |
| 286 | \r |
| 287 | UsbCommand c = {CMD_MIFARE_CGETBLOCK, {params, 0, blockNo}};\r |
| 288 | SendCommand(&c);\r |
| 289 | \r |
| 290 | UsbCommand resp;\r |
| 291 | if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {\r |
| 292 | isOK = resp.arg[0] & 0xff;\r |
| 293 | memcpy(data, resp.d.asBytes, 16);\r |
| 294 | if (!isOK) return 2;\r |
| 295 | } else {\r |
| 296 | PrintAndLog("Command execute timeout");\r |
| 297 | return 1;\r |
| 298 | }\r |
| 299 | return 0;\r |
| 300 | }\r |
| 301 | \r |
| 302 | // SNIFFER\r |
| 303 | \r |
| 304 | // constants\r |
| 305 | static uint8_t trailerAccessBytes[4] = {0x08, 0x77, 0x8F, 0x00};\r |
| 306 | \r |
| 307 | // variables\r |
| 308 | char logHexFileName[FILE_PATH_SIZE] = {0x00};\r |
| 309 | static uint8_t traceCard[4096] = {0x00};\r |
| 310 | static char traceFileName[FILE_PATH_SIZE] = {0x00};\r |
| 311 | static int traceState = TRACE_IDLE;\r |
| 312 | static uint8_t traceCurBlock = 0;\r |
| 313 | static uint8_t traceCurKey = 0;\r |
| 314 | \r |
| 315 | struct Crypto1State *traceCrypto1 = NULL;\r |
| 316 | \r |
| 317 | struct Crypto1State *revstate = NULL;\r |
| 318 | \r |
| 319 | uint64_t key = 0;\r |
| 320 | uint32_t ks2 = 0;\r |
| 321 | uint32_t ks3 = 0;\r |
| 322 | \r |
| 323 | uint32_t uid = 0; // serial number\r |
| 324 | uint32_t nt =0; // tag challenge\r |
| 325 | uint32_t nr_enc =0; // encrypted reader challenge\r |
| 326 | uint32_t ar_enc =0; // encrypted reader response\r |
| 327 | uint32_t at_enc =0; // encrypted tag response\r |
| 328 | \r |
| 329 | int isTraceCardEmpty(void) {\r |
| 330 | return ((traceCard[0] == 0) && (traceCard[1] == 0) && (traceCard[2] == 0) && (traceCard[3] == 0));\r |
| 331 | }\r |
| 332 | \r |
| 333 | int isBlockEmpty(int blockN) {\r |
| 334 | for (int i = 0; i < 16; i++) \r |
| 335 | if (traceCard[blockN * 16 + i] != 0) return 0;\r |
| 336 | \r |
| 337 | return 1;\r |
| 338 | }\r |
| 339 | \r |
| 340 | int isBlockTrailer(int blockN) {\r |
| 341 | return ((blockN & 0x03) == 0x03);\r |
| 342 | }\r |
| 343 | \r |
| 344 | int loadTraceCard(uint8_t *tuid) {\r |
| 345 | FILE * f;\r |
| 346 | char buf[64] = {0x00};\r |
| 347 | uint8_t buf8[64] = {0x00};\r |
| 348 | int i, blockNum;\r |
| 349 | \r |
| 350 | if (!isTraceCardEmpty()) \r |
| 351 | saveTraceCard();\r |
| 352 | \r |
| 353 | memset(traceCard, 0x00, 4096);\r |
| 354 | memcpy(traceCard, tuid + 3, 4);\r |
| 355 | \r |
| 356 | FillFileNameByUID(traceFileName, tuid, ".eml", 7);\r |
| 357 | \r |
| 358 | f = fopen(traceFileName, "r");\r |
| 359 | if (!f) return 1;\r |
| 360 | \r |
| 361 | blockNum = 0;\r |
| 362 | \r |
| 363 | while(!feof(f)){\r |
| 364 | \r |
| 365 | memset(buf, 0, sizeof(buf));\r |
| 366 | if (fgets(buf, sizeof(buf), f) == NULL) {\r |
| 367 | PrintAndLog("File reading error.");\r |
| 368 | fclose(f);\r |
| 369 | return 2;\r |
| 370 | }\r |
| 371 | \r |
| 372 | if (strlen(buf) < 32){\r |
| 373 | if (feof(f)) break;\r |
| 374 | PrintAndLog("File content error. Block data must include 32 HEX symbols");\r |
| 375 | fclose(f);\r |
| 376 | return 2;\r |
| 377 | }\r |
| 378 | for (i = 0; i < 32; i += 2)\r |
| 379 | sscanf(&buf[i], "%02x", (unsigned int *)&buf8[i / 2]);\r |
| 380 | \r |
| 381 | memcpy(traceCard + blockNum * 16, buf8, 16);\r |
| 382 | \r |
| 383 | blockNum++;\r |
| 384 | }\r |
| 385 | fclose(f);\r |
| 386 | \r |
| 387 | return 0;\r |
| 388 | }\r |
| 389 | \r |
| 390 | int saveTraceCard(void) {\r |
| 391 | FILE * f;\r |
| 392 | \r |
| 393 | if ((!strlen(traceFileName)) || (isTraceCardEmpty())) return 0;\r |
| 394 | \r |
| 395 | f = fopen(traceFileName, "w+");\r |
| 396 | if ( !f ) return 1;\r |
| 397 | \r |
| 398 | for (int i = 0; i < 64; i++) { // blocks\r |
| 399 | for (int j = 0; j < 16; j++) // bytes\r |
| 400 | fprintf(f, "%02x", *(traceCard + i * 16 + j)); \r |
| 401 | fprintf(f,"\n");\r |
| 402 | }\r |
| 403 | fclose(f);\r |
| 404 | return 0;\r |
| 405 | }\r |
| 406 | \r |
| 407 | int mfTraceInit(uint8_t *tuid, uint8_t *atqa, uint8_t sak, bool wantSaveToEmlFile) {\r |
| 408 | \r |
| 409 | if (traceCrypto1) \r |
| 410 | crypto1_destroy(traceCrypto1);\r |
| 411 | \r |
| 412 | traceCrypto1 = NULL;\r |
| 413 | \r |
| 414 | if (wantSaveToEmlFile) \r |
| 415 | loadTraceCard(tuid);\r |
| 416 | \r |
| 417 | traceCard[4] = traceCard[0] ^ traceCard[1] ^ traceCard[2] ^ traceCard[3];\r |
| 418 | traceCard[5] = sak;\r |
| 419 | memcpy(&traceCard[6], atqa, 2);\r |
| 420 | traceCurBlock = 0;\r |
| 421 | uid = bytes_to_num(tuid + 3, 4);\r |
| 422 | \r |
| 423 | traceState = TRACE_IDLE;\r |
| 424 | \r |
| 425 | return 0;\r |
| 426 | }\r |
| 427 | \r |
| 428 | void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted){\r |
| 429 | uint8_t bt = 0;\r |
| 430 | int i;\r |
| 431 | \r |
| 432 | if (len != 1) {\r |
| 433 | for (i = 0; i < len; i++)\r |
| 434 | data[i] = crypto1_byte(pcs, 0x00, isEncrypted) ^ data[i];\r |
| 435 | } else {\r |
| 436 | bt = 0;\r |
| 437 | for (i = 0; i < 4; i++)\r |
| 438 | bt |= (crypto1_bit(pcs, 0, isEncrypted) ^ BIT(data[0], i)) << i;\r |
| 439 | \r |
| 440 | data[0] = bt;\r |
| 441 | }\r |
| 442 | return;\r |
| 443 | }\r |
| 444 | \r |
| 445 | \r |
| 446 | int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile) {\r |
| 447 | uint8_t data[64];\r |
| 448 | \r |
| 449 | if (traceState == TRACE_ERROR) return 1;\r |
| 450 | if (len > 64) {\r |
| 451 | traceState = TRACE_ERROR;\r |
| 452 | return 1;\r |
| 453 | }\r |
| 454 | \r |
| 455 | memcpy(data, data_src, len);\r |
| 456 | if ((traceCrypto1) && ((traceState == TRACE_IDLE) || (traceState > TRACE_AUTH_OK))) {\r |
| 457 | mf_crypto1_decrypt(traceCrypto1, data, len, 0);\r |
| 458 | PrintAndLog("dec> %s", sprint_hex(data, len));\r |
| 459 | AddLogHex(logHexFileName, "dec> ", data, len); \r |
| 460 | }\r |
| 461 | \r |
| 462 | switch (traceState) {\r |
| 463 | case TRACE_IDLE: \r |
| 464 | // check packet crc16!\r |
| 465 | if ((len >= 4) && (!CheckCrc14443(CRC_14443_A, data, len))) {\r |
| 466 | PrintAndLog("dec> CRC ERROR!!!");\r |
| 467 | AddLogLine(logHexFileName, "dec> ", "CRC ERROR!!!"); \r |
| 468 | traceState = TRACE_ERROR; // do not decrypt the next commands\r |
| 469 | return 1;\r |
| 470 | }\r |
| 471 | \r |
| 472 | // AUTHENTICATION\r |
| 473 | if ((len == 4) && ((data[0] == 0x60) || (data[0] == 0x61))) {\r |
| 474 | traceState = TRACE_AUTH1;\r |
| 475 | traceCurBlock = data[1];\r |
| 476 | traceCurKey = data[0] == 60 ? 1:0;\r |
| 477 | return 0;\r |
| 478 | }\r |
| 479 | \r |
| 480 | // READ\r |
| 481 | if ((len ==4) && ((data[0] == 0x30))) {\r |
| 482 | traceState = TRACE_READ_DATA;\r |
| 483 | traceCurBlock = data[1];\r |
| 484 | return 0;\r |
| 485 | }\r |
| 486 | \r |
| 487 | // WRITE\r |
| 488 | if ((len ==4) && ((data[0] == 0xA0))) {\r |
| 489 | traceState = TRACE_WRITE_OK;\r |
| 490 | traceCurBlock = data[1];\r |
| 491 | return 0;\r |
| 492 | }\r |
| 493 | \r |
| 494 | // HALT\r |
| 495 | if ((len ==4) && ((data[0] == 0x50) && (data[1] == 0x00))) {\r |
| 496 | traceState = TRACE_ERROR; // do not decrypt the next commands\r |
| 497 | return 0;\r |
| 498 | }\r |
| 499 | \r |
| 500 | return 0;\r |
| 501 | break;\r |
| 502 | \r |
| 503 | case TRACE_READ_DATA: \r |
| 504 | if (len == 18) {\r |
| 505 | traceState = TRACE_IDLE;\r |
| 506 | \r |
| 507 | if (isBlockTrailer(traceCurBlock)) {\r |
| 508 | memcpy(traceCard + traceCurBlock * 16 + 6, data + 6, 4);\r |
| 509 | } else {\r |
| 510 | memcpy(traceCard + traceCurBlock * 16, data, 16);\r |
| 511 | }\r |
| 512 | if (wantSaveToEmlFile) saveTraceCard();\r |
| 513 | return 0;\r |
| 514 | } else {\r |
| 515 | traceState = TRACE_ERROR;\r |
| 516 | return 1;\r |
| 517 | }\r |
| 518 | break;\r |
| 519 | \r |
| 520 | case TRACE_WRITE_OK: \r |
| 521 | if ((len == 1) && (data[0] == 0x0a)) {\r |
| 522 | traceState = TRACE_WRITE_DATA;\r |
| 523 | \r |
| 524 | return 0;\r |
| 525 | } else {\r |
| 526 | traceState = TRACE_ERROR;\r |
| 527 | return 1;\r |
| 528 | }\r |
| 529 | break;\r |
| 530 | \r |
| 531 | case TRACE_WRITE_DATA: \r |
| 532 | if (len == 18) {\r |
| 533 | traceState = TRACE_IDLE;\r |
| 534 | \r |
| 535 | memcpy(traceCard + traceCurBlock * 16, data, 16);\r |
| 536 | if (wantSaveToEmlFile) saveTraceCard();\r |
| 537 | return 0;\r |
| 538 | } else {\r |
| 539 | traceState = TRACE_ERROR;\r |
| 540 | return 1;\r |
| 541 | }\r |
| 542 | break;\r |
| 543 | \r |
| 544 | case TRACE_AUTH1: \r |
| 545 | if (len == 4) {\r |
| 546 | traceState = TRACE_AUTH2;\r |
| 547 | nt = bytes_to_num(data, 4);\r |
| 548 | return 0;\r |
| 549 | } else {\r |
| 550 | traceState = TRACE_ERROR;\r |
| 551 | return 1;\r |
| 552 | }\r |
| 553 | break;\r |
| 554 | \r |
| 555 | case TRACE_AUTH2: \r |
| 556 | if (len == 8) {\r |
| 557 | traceState = TRACE_AUTH_OK;\r |
| 558 | \r |
| 559 | nr_enc = bytes_to_num(data, 4);\r |
| 560 | ar_enc = bytes_to_num(data + 4, 4);\r |
| 561 | return 0;\r |
| 562 | } else {\r |
| 563 | traceState = TRACE_ERROR;\r |
| 564 | return 1;\r |
| 565 | }\r |
| 566 | break;\r |
| 567 | \r |
| 568 | case TRACE_AUTH_OK: \r |
| 569 | if (len ==4) {\r |
| 570 | traceState = TRACE_IDLE;\r |
| 571 | \r |
| 572 | at_enc = bytes_to_num(data, 4);\r |
| 573 | \r |
| 574 | // decode key here)\r |
| 575 | ks2 = ar_enc ^ prng_successor(nt, 64);\r |
| 576 | ks3 = at_enc ^ prng_successor(nt, 96);\r |
| 577 | revstate = lfsr_recovery64(ks2, ks3);\r |
| 578 | lfsr_rollback_word(revstate, 0, 0);\r |
| 579 | lfsr_rollback_word(revstate, 0, 0);\r |
| 580 | lfsr_rollback_word(revstate, nr_enc, 1);\r |
| 581 | lfsr_rollback_word(revstate, uid ^ nt, 0);\r |
| 582 | \r |
| 583 | crypto1_get_lfsr(revstate, &key);\r |
| 584 | printf("Key: %012"llx"\n",key);\r |
| 585 | AddLogUint64(logHexFileName, "key: ", key); \r |
| 586 | \r |
| 587 | int blockShift = ((traceCurBlock & 0xFC) + 3) * 16;\r |
| 588 | if (isBlockEmpty((traceCurBlock & 0xFC) + 3)) memcpy(traceCard + blockShift + 6, trailerAccessBytes, 4);\r |
| 589 | \r |
| 590 | if (traceCurKey) {\r |
| 591 | num_to_bytes(key, 6, traceCard + blockShift + 10);\r |
| 592 | } else {\r |
| 593 | num_to_bytes(key, 6, traceCard + blockShift);\r |
| 594 | }\r |
| 595 | if (wantSaveToEmlFile) saveTraceCard();\r |
| 596 | \r |
| 597 | if (traceCrypto1) {\r |
| 598 | crypto1_destroy(traceCrypto1);\r |
| 599 | }\r |
| 600 | \r |
| 601 | // set cryptosystem state\r |
| 602 | traceCrypto1 = lfsr_recovery64(ks2, ks3);\r |
| 603 | \r |
| 604 | // nt = crypto1_word(traceCrypto1, nt ^ uid, 1) ^ nt;\r |
| 605 | \r |
| 606 | /* traceCrypto1 = crypto1_create(key); // key in lfsr\r |
| 607 | crypto1_word(traceCrypto1, nt ^ uid, 0);\r |
| 608 | crypto1_word(traceCrypto1, ar, 1);\r |
| 609 | crypto1_word(traceCrypto1, 0, 0);\r |
| 610 | crypto1_word(traceCrypto1, 0, 0);*/\r |
| 611 | \r |
| 612 | return 0;\r |
| 613 | } else {\r |
| 614 | traceState = TRACE_ERROR;\r |
| 615 | return 1;\r |
| 616 | }\r |
| 617 | break;\r |
| 618 | \r |
| 619 | default: \r |
| 620 | traceState = TRACE_ERROR;\r |
| 621 | return 1;\r |
| 622 | }\r |
| 623 | \r |
| 624 | return 0;\r |
| 625 | }\r |