From 7b941c8d7f8d8203316fdfaf1ad0038fc4864cf1 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 15 Jan 2015 15:27:44 +0100 Subject: [PATCH 01/16] Fixed memory corruption after reader-attack in armsrc, fixed annoying LED --- armsrc/iclass.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 329e1765..72cfbefc 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -998,7 +998,7 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain else if(simType == 2) { - uint8_t mac_responses[64] = { 0 }; + uint8_t mac_responses[USB_CMD_DATA_SIZE] = { 0 }; Dbprintf("Going into attack mode, %d CSNS sent", numberOfCSNS); // In this mode, a number of csns are within datain. We'll simulate each one, one at a time // in order to collect MAC's from the reader. This can later be used in an offlne-attack @@ -1248,6 +1248,8 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader //Dbprintf("%x", cmdsRecvd); LED_A_OFF(); LED_B_OFF(); + LED_C_OFF(); + if(buttonPressed) { DbpString("Button pressed"); -- 2.39.5 From 09b69422e221428d7e4870ae413fdda9042eac5f Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 15 Jan 2015 15:29:03 +0100 Subject: [PATCH 02/16] This was resynthezised along with my hf-changes. Nothing changed though --- fpga/fpga_lf.bit | Bin 42175 -> 42175 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/fpga/fpga_lf.bit b/fpga/fpga_lf.bit index e942921a8685731cbcf0e7bb6f86a11ea629dd0c..51b0681cd6a082550a19dccd794ff40439e393f9 100644 GIT binary patch literal 42175 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 literal 42175 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�$DR4HSsNmqcrsV|eYUj>P75ugYUv3T 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 -- 2.39.5 From 6b038d192a8418ec7c5ab74c344b4d4b216efc5e Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 15 Jan 2015 15:45:54 +0100 Subject: [PATCH 03/16] Minor dox --- armsrc/iclass.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 72cfbefc..e7dd9535 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -921,7 +921,7 @@ static void CodeIClassTagAnswer(const uint8_t *cmd, int len) * - A 1-bit input to the FPGA becomes 8 pulses on 423.5kHz (fc/32) (18.88us). * - A 0-bit inptu to the FPGA becomes an unmodulated time of 18.88us * - * In thist mode the SOF can be written as 00011101 = 0x1D + * In this mode the SOF can be written as 00011101 = 0x1D * The EOF can be written as 10111000 = 0xb8 * A logic 1 is 01 * A logic 0 is 10 @@ -1215,12 +1215,7 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader cmdsRecvd++; } /** - After changes to parity calculation - Time between reader EOT and pm3 SOF - delay 21 -> 480uS - delay 10 -> 220us - delay 16 -> 388us - A legit tag has about 380us. + A legit tag has about 380us delay between reader EOT and tag SOF. **/ if(modulated_response_size > 0) { SendIClassAnswer(modulated_response, modulated_response_size, 1); -- 2.39.5 From 758f1fd1f37d52678af1e9b1f72d58aecf41cac4 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 15 Jan 2015 16:07:58 +0100 Subject: [PATCH 04/16] Fixed issue #43 on github --- armsrc/iso14443a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index cf55e606..d326be2c 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1772,7 +1772,7 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u Dbprintf("Multiple tags detected. Collision after Bit %d", Demod.collisionPos); for (uint16_t i = collision_answer_offset; i < Demod.collisionPos; i++, uid_resp_bits++) { // add valid UID bits before collision point uint16_t UIDbit = (resp[i/8] >> (i % 8)) & 0x01; - uid_resp[uid_resp_bits & 0xf8] |= UIDbit << (uid_resp_bits % 8); + uid_resp[uid_resp_bits / 8] |= UIDbit << (uid_resp_bits % 8); } uid_resp[uid_resp_bits/8] |= 1 << (uid_resp_bits % 8); // next time select the card(s) with a 1 in the collision position uid_resp_bits++; -- 2.39.5 From d60418a05f2cbaa97140c569ba63f1a1eb831a79 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 15 Jan 2015 16:28:28 +0100 Subject: [PATCH 05/16] Synchronized loclass library, imported the legal warning --- client/loclass/cipher.c | 20 +++++++++-- client/loclass/cipher.h | 20 +++++++++-- client/loclass/cipherutils.c | 19 +++++++++-- client/loclass/cipherutils.h | 20 +++++++++-- client/loclass/elite_crack.c | 62 +++++++++++++++++++++++++++++++++-- client/loclass/elite_crack.h | 39 ++++++++++++++++++++++ client/loclass/fileutils.c | 43 ++++++++++++++++++++++-- client/loclass/fileutils.h | 38 +++++++++++++++++++++ client/loclass/ikeys.c | 24 ++++++++++---- client/loclass/ikeys.h | 38 +++++++++++++++++++++ client/loclass/loclass_main.h | 4 +++ client/loclass/main.c | 40 +++++++++++++++++++--- 12 files changed, 342 insertions(+), 25 deletions(-) create mode 100644 client/loclass/loclass_main.h diff --git a/client/loclass/cipher.c b/client/loclass/cipher.c index 463ba9be..d3b1e799 100644 --- a/client/loclass/cipher.c +++ b/client/loclass/cipher.c @@ -1,5 +1,17 @@ /***************************************************************************** - * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by @@ -18,9 +30,13 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with IClassCipher. If not, see . + * along with loclass. If not, see . + * + * + * ****************************************************************************/ + #include "cipher.h" #include "cipherutils.h" #include diff --git a/client/loclass/cipher.h b/client/loclass/cipher.h index 4bfbe0b7..176a2976 100644 --- a/client/loclass/cipher.h +++ b/client/loclass/cipher.h @@ -1,5 +1,17 @@ /***************************************************************************** - * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by @@ -18,9 +30,13 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with IClassCipher. If not, see . + * along with loclass. If not, see . + * + * + * ****************************************************************************/ + #ifndef CIPHER_H #define CIPHER_H #include diff --git a/client/loclass/cipherutils.c b/client/loclass/cipherutils.c index e11e8d22..f9c62273 100644 --- a/client/loclass/cipherutils.c +++ b/client/loclass/cipherutils.c @@ -1,5 +1,17 @@ /***************************************************************************** - * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by @@ -18,7 +30,10 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with IClassCipher. If not, see . + * along with loclass. If not, see . + * + * + * ****************************************************************************/ #include diff --git a/client/loclass/cipherutils.h b/client/loclass/cipherutils.h index acf96115..cb090f69 100644 --- a/client/loclass/cipherutils.h +++ b/client/loclass/cipherutils.h @@ -1,5 +1,17 @@ /***************************************************************************** - * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by @@ -18,9 +30,13 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with IClassCipher. If not, see . + * along with loclass. If not, see . + * + * + * ****************************************************************************/ + #ifndef CIPHERUTILS_H #define CIPHERUTILS_H #include diff --git a/client/loclass/elite_crack.c b/client/loclass/elite_crack.c index adedba85..a8ab869e 100644 --- a/client/loclass/elite_crack.c +++ b/client/loclass/elite_crack.c @@ -1,3 +1,41 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with loclass. If not, see . + * + * + * + ****************************************************************************/ + #include #include #include @@ -514,6 +552,7 @@ int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]) */ int bruteforceFile(const char *filename, uint16_t keytable[]) { + FILE *f = fopen(filename, "rb"); if(!f) { prnlog("Failed to read from file '%s'", filename); @@ -621,6 +660,21 @@ int _test_iclass_key_permutation() prnlog("[+] Iclass key permutation OK!"); return 0; } +int _testHash1() +{ + uint8_t csn[8]= {0x01,0x02,0x03,0x04,0xF7,0xFF,0x12,0xE0}; + uint8_t k[8] = {0}; + hash1(csn, k); + uint8_t expected[8] = {0x7E,0x72,0x2F,0x40,0x2D,0x02,0x51,0x42}; + if(memcmp(k,expected,8) != 0) + { + prnlog("Error with hash1!"); + printarr("calculated", k, 8); + printarr("expected", expected, 8); + return 1; + } + return 0; +} int testElite() { @@ -653,11 +707,13 @@ int testElite() prnlog("[+] Hash2 looks fine..."); } - prnlog("[+] Testing key diversification ..."); - int errors = 0 ; - errors +=_test_iclass_key_permutation(); + prnlog("[+] Testing hash1..."); + errors += _testHash1(); + prnlog("[+] Testing key diversification ..."); + errors +=_test_iclass_key_permutation(); errors += _testBruteforce(); + return errors; } diff --git a/client/loclass/elite_crack.h b/client/loclass/elite_crack.h index 21004e59..fb27355f 100644 --- a/client/loclass/elite_crack.h +++ b/client/loclass/elite_crack.h @@ -1,3 +1,42 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with loclass. If not, see . + * + * + * + ****************************************************************************/ + + #ifndef ELITE_CRACK_H #define ELITE_CRACK_H void permutekey(uint8_t key[8], uint8_t dest[8]); diff --git a/client/loclass/fileutils.c b/client/loclass/fileutils.c index 206d9695..4079dccf 100644 --- a/client/loclass/fileutils.c +++ b/client/loclass/fileutils.c @@ -1,3 +1,41 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with loclass. If not, see . + * + * + * + ****************************************************************************/ + #include #include #include @@ -40,14 +78,13 @@ int saveFile(const char *preferredName, const char *suffix, const void* data, si /*Opening file for writing in binary mode*/ FILE *fileHandle=fopen(fileName,"wb"); if(!fileHandle) { - PrintAndLog("Failed to write to file '%s'", fileName); + prnlog("Failed to write to file '%s'", fileName); free(fileName); return 1; } fwrite(data, 1, datalen, fileHandle); fclose(fileHandle); - PrintAndLog("Saved data to '%s'", fileName); - + prnlog("Saved data to '%s'", fileName); free(fileName); return 0; diff --git a/client/loclass/fileutils.h b/client/loclass/fileutils.h index e02079d5..623190a6 100644 --- a/client/loclass/fileutils.h +++ b/client/loclass/fileutils.h @@ -1,3 +1,41 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with loclass. If not, see . + * + * + * + ****************************************************************************/ + #ifndef FILEUTILS_H #define FILEUTILS_H /** diff --git a/client/loclass/ikeys.c b/client/loclass/ikeys.c index f7115b19..b21ecdbc 100644 --- a/client/loclass/ikeys.c +++ b/client/loclass/ikeys.c @@ -1,15 +1,23 @@ /***************************************************************************** - * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and * Milosch Meriac in the paper "Dismantling IClass". * - * This is a reference implementation of iclass key diversification. I'm sure it can be - * optimized heavily. It is written for ease of understanding and correctness, please take it - * and tweak it and make a super fast version instead, using this for testing and verification. - * Copyright (C) 2014 Martin Holst Swende * * This is free software: you can redistribute it and/or modify @@ -22,8 +30,12 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with IClassCipher. If not, see . + * along with loclass. If not, see . + * + * + * ****************************************************************************/ + /** diff --git a/client/loclass/ikeys.h b/client/loclass/ikeys.h index 1de46b62..13096194 100644 --- a/client/loclass/ikeys.h +++ b/client/loclass/ikeys.h @@ -1,3 +1,41 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with loclass. If not, see . + * + * + * + ****************************************************************************/ + #ifndef IKEYS_H #define IKEYS_H diff --git a/client/loclass/loclass_main.h b/client/loclass/loclass_main.h new file mode 100644 index 00000000..b6d58a8b --- /dev/null +++ b/client/loclass/loclass_main.h @@ -0,0 +1,4 @@ +#ifndef LOCLASS_MAIN_H +#define LOCLASS_MAIN_H + +#endif // LOCLASS_MAIN_H diff --git a/client/loclass/main.c b/client/loclass/main.c index 42019072..d1b0359b 100644 --- a/client/loclass/main.c +++ b/client/loclass/main.c @@ -1,5 +1,17 @@ /***************************************************************************** - * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by @@ -18,11 +30,14 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with IClassCipher. If not, see . + * along with loclass. If not, see . + * + * + * ****************************************************************************/ + #include -#include #include #include #include @@ -40,11 +55,15 @@ int unitTests() errors += testMAC(); errors += doKeyTests(0); errors += testElite(); + if(errors) + { + prnlog("OBS! There were errors!!!"); + } return errors; } int showHelp() { - prnlog("Usage: iclazz [options]"); + prnlog("Usage: loclass [options]"); prnlog("Options:"); prnlog("-t Perform self-test"); prnlog("-h Show this help"); @@ -64,7 +83,18 @@ int main (int argc, char **argv) { prnlog("IClass Cipher version 1.2, Copyright (C) 2014 Martin Holst Swende\n"); prnlog("Comes with ABSOLUTELY NO WARRANTY"); - prnlog("This is free software, and you are welcome to use, abuse and repackage, please keep the credits\n"); + prnlog("Released as GPLv2\n"); + prnlog("WARNING"); + prnlog(""); + prnlog("THIS TOOL IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. "); + prnlog(""); + prnlog("USAGE OF THIS TOOL IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL "); + prnlog("PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, "); + prnlog("AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. "); + prnlog(""); + prnlog("THIS TOOL SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. "); + + char *fileName = NULL; int c; while ((c = getopt (argc, argv, "thf:")) != -1) -- 2.39.5 From 49726b4088b78027b7ce3215c432cbb99a283f27 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 15 Jan 2015 23:00:39 +0100 Subject: [PATCH 06/16] Improved 'hf list iclass' a bit, better understanding of the protocol and when to apply CRC checks --- client/cmdhf.c | 112 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 87 insertions(+), 25 deletions(-) diff --git a/client/cmdhf.c b/client/cmdhf.c index 762fada4..33d01aee 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -123,14 +123,19 @@ NXP/Philips CUSTOM COMMANDS 40 = Long Range CMD (Standard ISO/TR7003:1990) */ -#define ICLASS_CMD_ACTALL 0x0A +#define ICLASS_CMD_ACTALL 0x0A #define ICLASS_CMD_READ_OR_IDENTIFY 0x0C -#define ICLASS_CMD_SELECT 0x81 -#define ICLASS_CMD_PAGESEL 0x84 -#define ICLASS_CMD_READCHECK 0x88 -#define ICLASS_CMD_CHECK 0x05 -#define ICLASS_CMD_SOF 0x0F -#define ICLASS_CMD_HALT 0x00 +#define ICLASS_CMD_SELECT 0x81 +#define ICLASS_CMD_PAGESEL 0x84 +#define ICLASS_CMD_READCHECK_KD 0x88 +#define ICLASS_CMD_READCHECK_KC 0x18 +#define ICLASS_CMD_CHECK 0x05 +#define ICLASS_CMD_DETECT 0x0F +#define ICLASS_CMD_HALT 0x00 +#define ICLASS_CMD_UPDATE 0x87 +#define ICLASS_CMD_ACT 0x8E +#define ICLASS_CMD_READ4 0x06 + #define ISO14443_CMD_REQA 0x26 #define ISO14443_CMD_READBLOCK 0x30 @@ -235,11 +240,15 @@ void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) break; } case ICLASS_CMD_SELECT: snprintf(exp,size,"SELECT"); break; - case ICLASS_CMD_PAGESEL: snprintf(exp,size,"PAGESEL"); break; - case ICLASS_CMD_READCHECK: snprintf(exp,size,"READCHECK"); break; + case ICLASS_CMD_PAGESEL: snprintf(exp,size,"PAGESEL(%d)", cmd[1]); break; + case ICLASS_CMD_READCHECK_KC:snprintf(exp,size,"READCHECK[Kc](%d)", cmd[1]); break; + case ICLASS_CMD_READCHECK_KD:snprintf(exp,size,"READCHECK[Kd](%d)", cmd[1]); break; case ICLASS_CMD_CHECK: snprintf(exp,size,"CHECK"); break; - case ICLASS_CMD_SOF: snprintf(exp,size,"SOF"); break; + case ICLASS_CMD_DETECT: snprintf(exp,size,"DETECT"); break; case ICLASS_CMD_HALT: snprintf(exp,size,"HALT"); break; + case ICLASS_CMD_UPDATE: snprintf(exp,size,"UPDATE(%d)",cmd[1]); break; + case ICLASS_CMD_ACT: snprintf(exp,size,"ACT"); break; + case ICLASS_CMD_READ4: snprintf(exp,size,"READ4(%d)",cmd[1]); break; default: snprintf(exp,size,"?"); break; } return; @@ -276,6 +285,66 @@ void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) } } } +/** + * @brief iclass_CRC_Ok Checks CRC in command or response + * @param isResponse + * @param data + * @param len + * @return 0 : CRC-command, CRC not ok + * 1 : CRC-command, CRC ok + * 2 : Not crc-command + */ +uint8_t iclass_CRC_Ok(bool isResponse, uint8_t* data, uint8_t len) +{ + if(len < 4) return 2;//CRC commands (and responses) are all at least 4 bytes + + uint8_t b1, b2; + + if(!isResponse)//Commands to tag + { + /** + These commands should have CRC. Total length leftmost + 4 READ + 4 READ4 + 12 UPDATE - unsecured, ends with CRC16 + 14 UPDATE - secured, ends with signature instead + 4 PAGESEL + **/ + if(len == 4 || len == 12)//Covers three of them + { + //Don't include the command byte + ComputeCrc14443(CRC_ICLASS, (data+1), len-3, &b1, &b2); + return b1 == data[len -2] && b2 == data[len-1]; + } + return 2; + }else{ + /** + These tag responses should have CRC. Total length leftmost + + 10 READ data[8] crc[2] + 34 READ4 data[32]crc[2] + 10 UPDATE data[8] crc[2] + 10 SELECT csn[8] crc[2] + 10 IDENTIFY asnb[8] crc[2] + 10 PAGESEL block1[8] crc[2] + 10 DETECT csn[8] crc[2] + + These should not + + 4 CHECK chip_response[4] + 8 READCHECK data[8] + 1 ACTALL sof[1] + 1 ACT sof[1] + + In conclusion, without looking at the command; any response + of length 10 or 34 should have CRC + **/ + if(len != 10 && len != 34) return true; + + ComputeCrc14443(CRC_ICLASS, data, len-2, &b1, &b2); + return b1 == data[len -2] && b2 == data[len-1]; + } +} uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool showWaitCycles) { @@ -332,24 +401,14 @@ uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool sho } } //--- Draw the CRC column - bool crcError = false; + uint8_t crcStatus = 2; if (data_len > 2) { uint8_t b1, b2; if(iclass) { - if(!isResponse && data_len == 4 ) { - // Rough guess that this is a command from the reader - // For iClass the command byte is not part of the CRC - ComputeCrc14443(CRC_ICLASS, &frame[1], data_len-3, &b1, &b2); - } else { - // For other data.. CRC might not be applicable (UPDATE commands etc.) - ComputeCrc14443(CRC_ICLASS, frame, data_len-2, &b1, &b2); - } - - if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { - crcError = true; - } + //The following commands have crc + crcStatus = iclass_CRC_Ok(isResponse, frame, data_len); }else{//Iso 14443a @@ -358,12 +417,15 @@ uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool sho if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { if(!(isResponse & (data_len < 6))) { - crcError = true; + crcStatus = 0; } } } } - char *crc = crcError ? "!crc" :" "; + //0 CRC-command, CRC not ok + //1 CRC-command, CRC ok + //2 Not crc-command + char *crc = (crcStatus == 0 ? "!crc" : (crcStatus == 1 ? " ok " : " ")); EndOfTransmissionTimestamp = timestamp + duration; -- 2.39.5 From 41fdd0f061ae7ef4cdc5bfc027f1097c990c3318 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 16 Jan 2015 22:41:19 +0100 Subject: [PATCH 07/16] First stab at adding 'hf list 14b' and 'hf list raw' --- client/cmdhf.c | 112 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 83 insertions(+), 29 deletions(-) diff --git a/client/cmdhf.c b/client/cmdhf.c index 33d01aee..20ca057b 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -137,14 +137,14 @@ NXP/Philips CUSTOM COMMANDS #define ICLASS_CMD_READ4 0x06 -#define ISO14443_CMD_REQA 0x26 -#define ISO14443_CMD_READBLOCK 0x30 -#define ISO14443_CMD_WUPA 0x52 -#define ISO14443_CMD_ANTICOLL_OR_SELECT 0x93 -#define ISO14443_CMD_ANTICOLL_OR_SELECT_2 0x95 -#define ISO14443_CMD_WRITEBLOCK 0xA0 // or 0xA2 ? -#define ISO14443_CMD_HALT 0x50 -#define ISO14443_CMD_RATS 0xE0 +#define ISO14443A_CMD_REQA 0x26 +#define ISO14443A_CMD_READBLOCK 0x30 +#define ISO14443A_CMD_WUPA 0x52 +#define ISO14443A_CMD_ANTICOLL_OR_SELECT 0x93 +#define ISO14443A_CMD_ANTICOLL_OR_SELECT_2 0x95 +#define ISO14443A_CMD_WRITEBLOCK 0xA0 // or 0xA2 ? +#define ISO14443A_CMD_HALT 0x50 +#define ISO14443A_CMD_RATS 0xE0 #define MIFARE_AUTH_KEYA 0x60 #define MIFARE_AUTH_KEYB 0x61 @@ -180,14 +180,17 @@ NXP/Philips CUSTOM COMMANDS #define ISO15693_READ_MULTI_SECSTATUS 0x2C +#define ISO_14443A 0 +#define ICLASS 1 +#define ISO_14443B 2 void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) { switch(cmd[0]) { - case ISO14443_CMD_WUPA: snprintf(exp,size,"WUPA"); break; - case ISO14443_CMD_ANTICOLL_OR_SELECT:{ + case ISO14443A_CMD_WUPA: snprintf(exp,size,"WUPA"); break; + case ISO14443A_CMD_ANTICOLL_OR_SELECT:{ // 93 20 = Anticollision (usage: 9320 - answer: 4bytes UID+1byte UID-bytes-xor) // 93 70 = Select (usage: 9370+5bytes 9320 answer - answer: 1byte SAK) if(cmd[2] == 0x70) @@ -198,7 +201,7 @@ void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) snprintf(exp,size,"ANTICOLL"); break; } } - case ISO14443_CMD_ANTICOLL_OR_SELECT_2:{ + case ISO14443A_CMD_ANTICOLL_OR_SELECT_2:{ //95 20 = Anticollision of cascade level2 //95 70 = Select of cascade level2 if(cmd[2] == 0x70) @@ -209,11 +212,11 @@ void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) snprintf(exp,size,"ANTICOLL-2"); break; } } - case ISO14443_CMD_REQA: snprintf(exp,size,"REQA"); break; - case ISO14443_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break; - case ISO14443_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break; - case ISO14443_CMD_HALT: snprintf(exp,size,"HALT"); break; - case ISO14443_CMD_RATS: snprintf(exp,size,"RATS"); break; + case ISO14443A_CMD_REQA: snprintf(exp,size,"REQA"); break; + case ISO14443A_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break; + case ISO14443A_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break; + case ISO14443A_CMD_HALT: snprintf(exp,size,"HALT"); break; + case ISO14443A_CMD_RATS: snprintf(exp,size,"RATS"); break; case MIFARE_CMD_INC: snprintf(exp,size,"INC(%d)",cmd[1]); break; case MIFARE_CMD_DEC: snprintf(exp,size,"DEC(%d)",cmd[1]); break; case MIFARE_CMD_RESTORE: snprintf(exp,size,"RESTORE(%d)",cmd[1]); break; @@ -281,10 +284,44 @@ void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) case ISO15693_LOCK_DSFID :snprintf(exp, size, "LOCK_DSFID");break; case ISO15693_GET_SYSTEM_INFO :snprintf(exp, size, "GET_SYSTEM_INFO");break; case ISO15693_READ_MULTI_SECSTATUS :snprintf(exp, size, "READ_MULTI_SECSTATUS");break; - default: snprintf(exp,size,"?"); break; + default: snprintf(exp,size,"?"); break; } } } +void annotateIso14443b(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) +{ + switch(cmd[0]){ + case ISO14443B_REQB : snprintf(exp,size,"REQB");break; + case ISO14443B_ATTRIB : snprintf(exp,size,"ATTRIB");break; + case ISO14443B_HALT : snprintf(exp,size,"HALT");break; + default: snprintf(exp,size ,"?");break; + } + +} + +/** + * @brief iso14443B_CRC_Ok Checks CRC in command or response + * @param isResponse + * @param data + * @param len + * @return 0 : CRC-command, CRC not ok + * 1 : CRC-command, CRC ok + * 2 : Not crc-command + */ + +uint8_t iso14443B_CRC_check(bool isResponse, uint8_t* data, uint8_t len) +{ + uint8_t b1,b2; + + if(len <= 2) return 2; + + ComputeCrc14443(CRC_14443_B, data, len-2, &b1, &b2); + if(b1 != data[len-2] || b2 != data[len-1]) { + return 0; + } + return 1; +} + /** * @brief iclass_CRC_Ok Checks CRC in command or response * @param isResponse @@ -294,7 +331,7 @@ void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) * 1 : CRC-command, CRC ok * 2 : Not crc-command */ -uint8_t iclass_CRC_Ok(bool isResponse, uint8_t* data, uint8_t len) +uint8_t iclass_CRC_check(bool isResponse, uint8_t* data, uint8_t len) { if(len < 4) return 2;//CRC commands (and responses) are all at least 4 bytes @@ -346,7 +383,7 @@ uint8_t iclass_CRC_Ok(bool isResponse, uint8_t* data, uint8_t len) } } -uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool showWaitCycles) +uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, uint8_t protocol, bool showWaitCycles) { bool isResponse; uint16_t duration, data_len,parity_len; @@ -405,12 +442,15 @@ uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool sho if (data_len > 2) { uint8_t b1, b2; - if(iclass) + if(protocol == ICLASS) { - //The following commands have crc - crcStatus = iclass_CRC_Ok(isResponse, frame, data_len); + crcStatus = iclass_CRC_check(isResponse, frame, data_len); - }else{//Iso 14443a + }else if (protocol == ISO_14443B) + { + crcStatus = iso14443B_CRC_check(isResponse, frame, data_len); + } + else if (protocol == ISO_14443A){//Iso 14443a ComputeCrc14443(CRC_14443_A, frame, data_len-2, &b1, &b2); @@ -431,10 +471,12 @@ uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool sho if(!isResponse) { - if(iclass) + if(protocol == ICLASS) annotateIclass(explanation,sizeof(explanation),frame,data_len); - else + else if (protocol == ISO_14443A) annotateIso14443a(explanation,sizeof(explanation),frame,data_len); + else if(protocol == ISO_14443B) + annotateIso14443b(explanation,sizeof(explanation),frame,data_len); } int num_lines = (data_len - 1)/16 + 1; @@ -477,7 +519,7 @@ int CmdHFList(const char *Cmd) int tlen = param_getstr(Cmd,0,type); char param = param_getchar(Cmd, 1); bool errors = false; - bool iclass = false; + uint8_t protocol = false; //Validate params if(tlen == 0 || (strcmp(type, "iclass") != 0 && strcmp(type,"14a") != 0)) { @@ -490,9 +532,11 @@ int CmdHFList(const char *Cmd) if (errors) { PrintAndLog("List protocol data in trace buffer."); - PrintAndLog("Usage: hf list [14a|iclass] [f]"); + PrintAndLog("Usage: hf list [14a|14b|iclass] [f]"); PrintAndLog(" 14a - interpret data as iso14443a communications"); + PrintAndLog(" 14b - interpret data as iso14443b communications"); PrintAndLog(" iclass - interpret data as iclass communications"); + PrintAndLog(" raw - just show raw data"); PrintAndLog(" f - show frame delay times as well"); PrintAndLog(""); PrintAndLog("example: hf list 14a f"); @@ -501,7 +545,17 @@ int CmdHFList(const char *Cmd) } if(strcmp(type, "iclass") == 0) { - iclass = true; + protocol = ICLASS; + }else if(strcmp(type, "14a") == 0) + { + protocol = ISO_14443A; + } + else if(strcmp(type, "14b") == 0) + { + protocol = ISO_14443B; + }else if(strcmp(type,"raw")== 0) + { + protocol = -1;//No crc, no annotations } if (param == 'f') { @@ -525,7 +579,7 @@ int CmdHFList(const char *Cmd) while(tracepos < TRACE_SIZE) { - tracepos = printTraceLine(tracepos, trace, iclass, showWaitCycles); + tracepos = printTraceLine(tracepos, trace, protocol, showWaitCycles); } return 0; } -- 2.39.5 From b689b842b68c061340f18ff595ffdabf34bdc4f0 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 16 Jan 2015 22:48:30 +0100 Subject: [PATCH 08/16] Bugfix 'hf list 14b' and 'hf list raw' --- client/cmdhf.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/client/cmdhf.c b/client/cmdhf.c index 20ca057b..9acc9825 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -519,9 +519,9 @@ int CmdHFList(const char *Cmd) int tlen = param_getstr(Cmd,0,type); char param = param_getchar(Cmd, 1); bool errors = false; - uint8_t protocol = false; + uint8_t protocol = 0; //Validate params - if(tlen == 0 || (strcmp(type, "iclass") != 0 && strcmp(type,"14a") != 0)) + if(tlen == 0) { errors = true; } @@ -529,6 +529,25 @@ int CmdHFList(const char *Cmd) { errors = true; } + if(!errors) + { + if(strcmp(type, "iclass") == 0) + { + protocol = ICLASS; + }else if(strcmp(type, "14a") == 0) + { + protocol = ISO_14443A; + } + else if(strcmp(type, "14b") == 0) + { + protocol = ISO_14443B; + }else if(strcmp(type,"raw")== 0) + { + protocol = -1;//No crc, no annotations + }else{ + errors = true; + } + } if (errors) { PrintAndLog("List protocol data in trace buffer."); @@ -543,20 +562,7 @@ int CmdHFList(const char *Cmd) PrintAndLog("example: hf list iclass"); return 0; } - if(strcmp(type, "iclass") == 0) - { - protocol = ICLASS; - }else if(strcmp(type, "14a") == 0) - { - protocol = ISO_14443A; - } - else if(strcmp(type, "14b") == 0) - { - protocol = ISO_14443B; - }else if(strcmp(type,"raw")== 0) - { - protocol = -1;//No crc, no annotations - } + if (param == 'f') { showWaitCycles = true; -- 2.39.5 From 5ee701292ff2e28abf098e2266a42954f381e3ad Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 20 Jan 2015 21:23:04 +0100 Subject: [PATCH 09/16] Step 2 - Ultralight / Ultralight-C With this the Pentura Labs / Midnitsnakes's original ultralight / ultralight-c implementation is enhanced and move to its own file. cmdhfmfu.c --- client/Makefile | 1 + client/cmdhf.c | 2 + client/cmdhf14a.c | 4 +- client/cmdhf14b.c | 4 +- client/cmdhfmf.c | 221 +++------------------------------------------- client/cmdlf.c | 2 +- common/usb_cdc.c | 2 +- 7 files changed, 20 insertions(+), 216 deletions(-) diff --git a/client/Makefile b/client/Makefile index 77fee4e6..12d92631 100644 --- a/client/Makefile +++ b/client/Makefile @@ -78,6 +78,7 @@ CMDSRCS = nonce2key/crapto1.c\ cmdhflegic.c \ cmdhficlass.c \ cmdhfmf.c \ + cmdhfmfu.c \ cmdhw.c \ cmdlf.c \ cmdlfio.c \ diff --git a/client/cmdhf.c b/client/cmdhf.c index 9acc9825..637b2b08 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -22,6 +22,7 @@ #include "cmdhflegic.h" #include "cmdhficlass.h" #include "cmdhfmf.h" +#include "cmdhfmfu.h" static int CmdHelp(const char *Cmd); @@ -601,6 +602,7 @@ static command_t CommandTable[] = {"legic", CmdHFLegic, 0, "{ LEGIC RFIDs... }"}, {"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"}, {"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"}, + {"mfu", CmdHFMFUltra, 1, "{ MIFARE Ultralight RFIDs... }"}, {"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"}, {"list", CmdHFList, 1, "List protocol data in trace buffer"}, {NULL, NULL, 0, NULL} diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 01602d76..593661a5 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -412,9 +412,9 @@ int CmdHF14ASim(const char *Cmd) PrintAndLog(" syntax: hf 14a sim "); PrintAndLog(" types: 1 = MIFARE Classic"); PrintAndLog(" 2 = MIFARE Ultralight"); - PrintAndLog(" 3 = MIFARE DESFIRE"); + PrintAndLog(" 3 = MIFARE Desfire"); PrintAndLog(" 4 = ISO/IEC 14443-4"); - PrintAndLog(" 5 = MIFARE TNP3XXX"); + PrintAndLog(" 5 = MIFARE Tnp3xxx"); PrintAndLog(""); return 1; } diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c index e3d0fc23..0350fc31 100644 --- a/client/cmdhf14b.c +++ b/client/cmdhf14b.c @@ -280,7 +280,7 @@ int CmdHF14BCmdRaw (const char *cmd) { uint8_t power=0; char buf[5]=""; int i=0; - uint8_t data[100]; + uint8_t data[100] = {0x00}; unsigned int datalen=0, temp; char *hexout; @@ -334,7 +334,7 @@ int CmdHF14BCmdRaw (const char *cmd) { continue; } PrintAndLog("Invalid char on input"); - return 0; + return 1; } if (datalen == 0) { diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index aae6290d..28f7b078 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -140,117 +140,6 @@ int CmdHF14AMfWrBl(const char *Cmd) return 0; } -int CmdHF14AMfUWrBl(const char *Cmd) -{ - uint8_t blockNo = 0; - bool chinese_card=0; - uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - UsbCommand resp; - - if (strlen(Cmd)<3) { - PrintAndLog("Usage: hf mf uwrbl "); - PrintAndLog(" sample: hf mf uwrbl 0 01020304"); - return 0; - } - - blockNo = param_get8(Cmd, 0); - if (param_gethex(Cmd, 1, bldata, 8)) { - PrintAndLog("Block data must include 8 HEX symbols"); - return 1; - } - - if (strchr(Cmd,'w') != 0) { - chinese_card=1; - } - - switch(blockNo){ - case 0: - if (!chinese_card){ - PrintAndLog("Access Denied"); - }else{ - PrintAndLog("--specialblock no:%d", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(d.d.asBytes,bldata, 4); - SendCommand(&d); - - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - } - break; - case 1: - if (!chinese_card){ - PrintAndLog("Access Denied"); - }else{ - PrintAndLog("--specialblock no:%d", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(d.d.asBytes,bldata, 4); - SendCommand(&d); - - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - } - break; - case 2: - if (!chinese_card){ - PrintAndLog("Access Denied"); - }else{ - PrintAndLog("--specialblock no:%d", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(c.d.asBytes, bldata, 4); - SendCommand(&c); - - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - } - break; - case 3: - PrintAndLog("--specialblock no:%d", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(d.d.asBytes,bldata, 4); - SendCommand(&d); - - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - break; - default: - PrintAndLog("--block no:%d", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(e.d.asBytes,bldata, 4); - SendCommand(&e); - - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - break; - } - return 0; -} - - int CmdHF14AMfRdBl(const char *Cmd) { uint8_t blockNo = 0; @@ -299,87 +188,6 @@ int CmdHF14AMfRdBl(const char *Cmd) return 0; } -int CmdHF14AMfURdBl(const char *Cmd) -{ - uint8_t blockNo = 0; - - if (strlen(Cmd)<1) { - PrintAndLog("Usage: hf mf urdbl "); - PrintAndLog(" sample: hf mf urdbl 0"); - return 0; - } - - blockNo = param_get8(Cmd, 0); - PrintAndLog("--block no:%d", blockNo); - - UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}}; - SendCommand(&c); - - UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - uint8_t *data = resp.d.asBytes; - - if (isOK) - PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 4)); - else - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - - return 0; -} - - -int CmdHF14AMfURdCard(const char *Cmd) -{ - int i; - uint8_t sectorNo = 0; - uint8_t *lockbytes_t=NULL; - uint8_t lockbytes[2]={0,0}; - bool bit[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - - uint8_t isOK = 0; - uint8_t * data = NULL; - - PrintAndLog("Attempting to Read Ultralight... "); - - UsbCommand c = {CMD_MIFAREU_READCARD, {sectorNo}}; - SendCommand(&c); - - UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - isOK = resp.arg[0] & 0xff; - data = resp.d.asBytes; - - PrintAndLog("isOk:%02x", isOK); - if (isOK) - { // bit 0 and 1 - PrintAndLog("Block %3d:%s ", 0,sprint_hex(data + 0 * 4, 4)); - PrintAndLog("Block %3d:%s ", 1,sprint_hex(data + 1 * 4, 4)); - // bit 2 - //process lock bytes - lockbytes_t=data+(2*4); - lockbytes[0]=lockbytes_t[2]; - lockbytes[1]=lockbytes_t[3]; - for(int j=0; j<16; j++){ - bit[j]=lockbytes[j/8] & ( 1 <<(7-j%8)); - } - //remaining - for (i = 3; i < 16; i++) { - int bitnum = (23-i) % 16; - PrintAndLog("Block %3d:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[bitnum]); - } - - } - } else { - PrintAndLog("Command execute timeout"); - } - return 0; -} - - int CmdHF14AMfRdSc(const char *Cmd) { int i; @@ -1288,7 +1096,7 @@ int CmdHF14AMfDbg(const char *Cmd) int CmdHF14AMfEGet(const char *Cmd) { uint8_t blockNo = 0; - uint8_t data[16]; + uint8_t data[16] = {0x00}; if (strlen(Cmd) < 1 || param_getchar(Cmd, 0) == 'h') { PrintAndLog("Usage: hf mf eget "); @@ -1355,14 +1163,11 @@ int CmdHF14AMfELoad(const char *Cmd) FILE * f; char filename[FILE_PATH_SIZE]; char *fnameptr = filename; - char buf[64]; - uint8_t buf8[64]; + char buf[64] = {0x00}; + uint8_t buf8[64] = {0x00}; int i, len, blockNum, numBlocks; int nameParamNo = 1; - memset(filename, 0, sizeof(filename)); - memset(buf, 0, sizeof(buf)); - char ctmp = param_getchar(Cmd, 0); if ( ctmp == 'h' || ctmp == 0x00) { @@ -1432,11 +1237,13 @@ int CmdHF14AMfELoad(const char *Cmd) fclose(f); return 3; } + printf("."); blockNum++; if (blockNum >= numBlocks) break; } fclose(f); + printf("\n"); if ((blockNum != numBlocks)) { PrintAndLog("File content error. Got %d must be %d blocks.",blockNum, numBlocks); @@ -1653,11 +1460,10 @@ int CmdHF14AMfCSetUID(const char *Cmd) int CmdHF14AMfCSetBlk(const char *Cmd) { - uint8_t uid[8]; - uint8_t memBlock[16]; + uint8_t uid[8] = {0x00}; + uint8_t memBlock[16] = {0x00}; uint8_t blockNo = 0; int res; - memset(memBlock, 0x00, sizeof(memBlock)); if (strlen(Cmd) < 1 || param_getchar(Cmd, 0) == 'h') { PrintAndLog("Usage: hf mf csetblk "); @@ -1814,10 +1620,9 @@ int CmdHF14AMfCGetBlk(const char *Cmd) { int CmdHF14AMfCGetSc(const char *Cmd) { - uint8_t memBlock[16]; + uint8_t memBlock[16] = {0x00}; uint8_t sectorNo = 0; int i, res, flags; - memset(memBlock, 0x00, sizeof(memBlock)); if (strlen(Cmd) < 1 || param_getchar(Cmd, 0) == 'h') { PrintAndLog("Usage: hf mf cgetsc "); @@ -1957,14 +1762,13 @@ int CmdHF14AMfSniff(const char *Cmd){ int blockLen = 0; int num = 0; int pckNum = 0; - uint8_t uid[7]; + uint8_t uid[7] = {0x00}; uint8_t uid_len; - uint8_t atqa[2]; + uint8_t atqa[2] = {0x00}; uint8_t sak; bool isTag; - uint8_t buf[3000]; + uint8_t buf[3000] = {0x00}; uint8_t * bufPtr = buf; - memset(buf, 0x00, 3000); if (param_getchar(Cmd, 0) == 'h') { PrintAndLog("It continuously gets data from the field and saves it to: log, emulator, emulator file."); @@ -2080,9 +1884,6 @@ static command_t CommandTable[] = {"help", CmdHelp, 1, "This help"}, {"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"}, {"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"}, - {"urdbl", CmdHF14AMfURdBl, 0, "Read MIFARE Ultralight block"}, - {"urdcard", CmdHF14AMfURdCard, 0,"Read MIFARE Ultralight Card"}, - {"uwrbl", CmdHF14AMfUWrBl, 0,"Write MIFARE Ultralight block"}, {"rdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"}, {"dump", CmdHF14AMfDump, 0, "Dump MIFARE classic tag to binary file"}, {"restore", CmdHF14AMfRestore, 0, "Restore MIFARE classic binary file to BLANK tag"}, diff --git a/client/cmdlf.c b/client/cmdlf.c index e3361cb5..491fd082 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -465,7 +465,7 @@ int CmdLFSnoop(const char *Cmd) sscanf(Cmd, "h %"lli, &c.arg[1]); } else if (sscanf(Cmd, "%"lli" %"lli, &c.arg[0], &c.arg[1]) < 1) { PrintAndLog("usage 1: snoop"); - PrintAndLog(" 2: snoop {l,h} [trigger threshold]"); + PrintAndLog(" 2: snoop [trigger threshold]"); PrintAndLog(" 3: snoop [trigger threshold]"); return 0; } diff --git a/common/usb_cdc.c b/common/usb_cdc.c index 54f6a8e8..ccbb3c50 100644 --- a/common/usb_cdc.c +++ b/common/usb_cdc.c @@ -370,7 +370,7 @@ uint32_t usb_write(const byte_t* data, const size_t len) { //* \fn AT91F_USB_SendData //* \brief Send Data through the control endpoint //*---------------------------------------------------------------------------- -unsigned int csrTab[100]; +unsigned int csrTab[100] = {0x00}; unsigned char csrIdx = 0; static void AT91F_USB_SendData(AT91PS_UDP pUdp, const char *pData, uint32_t length) { -- 2.39.5 From 81740aa519046d407faa39411973347db593f0b7 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 20 Jan 2015 21:29:55 +0100 Subject: [PATCH 10/16] STEP 3 - the actual new files for Ultralight. ADD: script remagic.lua -- a script to make a "dead" Mifare s50 generation 1 alive again. ADD: tracetest.lua - This script will load several traces files in ../traces/ folder and do "data load" "lf search" ADD: test_t55x7_psk.lua - iterates thru a lot of calls to check the new psk demods. all new scripts implements the "-h" for help text. --- client/cmdhfmfu.c | 649 ++++++++++++++++++++++++++++++ client/cmdhfmfu.h | 19 + client/scripts/remagic.lua | 63 +++ client/scripts/test_t55x7_psk.lua | 173 ++++++++ client/scripts/tracetest.lua | 132 ++++++ 5 files changed, 1036 insertions(+) create mode 100644 client/cmdhfmfu.c create mode 100644 client/cmdhfmfu.h create mode 100644 client/scripts/remagic.lua create mode 100644 client/scripts/test_t55x7_psk.lua create mode 100644 client/scripts/tracetest.lua diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c new file mode 100644 index 00000000..8bd6ec87 --- /dev/null +++ b/client/cmdhfmfu.c @@ -0,0 +1,649 @@ +//----------------------------------------------------------------------------- +// Ultralight Code (c) 2013,2014 Midnitesnake & Andy Davies of Pentura +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// High frequency MIFARE ULTRALIGHT (C) commands +//----------------------------------------------------------------------------- +#include +#include "cmdhfmfu.h" +#include "cmdhfmf.h" +#include "cmdhf14a.h" + + +#define MAX_ULTRA_BLOCKS 0x0f +#define MAX_ULTRAC_BLOCKS 0x2f +//#define MAX_ULTRAC_BLOCKS 0x2c +uint8_t key1_blnk_data[16] = { 0x00 }; +uint8_t key2_defa_data[16] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }; +uint8_t key3_3des_data[16] = { 0x49,0x45,0x4D,0x4B,0x41,0x45,0x52,0x42,0x21,0x4E,0x41,0x43,0x55,0x4F,0x59,0x46 }; +uint8_t key4_nfc_data[16] = { 0x42,0x52,0x45,0x41,0x4b,0x4d,0x45,0x49,0x46,0x59,0x4f,0x55,0x43,0x41,0x4e,0x21 }; +uint8_t key5_ones_data[16] = { 0x01 }; + +static int CmdHelp(const char *Cmd); + +int CmdHF14AMfUInfo(const char *Cmd){ + + uint8_t datatemp[7] = {0x00}; + uint8_t isOK = 0; + uint8_t *data = NULL; + + UsbCommand c = {CMD_MIFAREU_READCARD, {0, 4}}; + SendCommand(&c); + UsbCommand resp; + + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + isOK = resp.arg[0] & 0xff; + data = resp.d.asBytes; + + if (!isOK) { + PrintAndLog("Error reading from tag"); + return -1; + } + } else { + PrintAndLog("Command execute timed out"); + return -1; + } + + PrintAndLog(""); + PrintAndLog("-- Mifare Ultralight / Ultralight-C Tag Information ---------"); + PrintAndLog("-------------------------------------------------------------"); + + // UID + memcpy( datatemp, data, 3); + memcpy( datatemp+3, data+4, 4); + + PrintAndLog("MANUFACTURER : %s", getTagInfo(datatemp[0])); + PrintAndLog(" UID : %s ", sprint_hex(datatemp, 7)); + // BBC + // CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2 + int crc0 = 0x88 ^ data[0] ^ data[1] ^data[2]; + if ( data[3] == crc0 ) + PrintAndLog(" BCC0 : %02x - Ok", data[3]); + else + PrintAndLog(" BCC0 : %02x - crc should be %02x", data[3], crc0); + + int crc1 = data[4] ^ data[5] ^ data[6] ^data[7]; + if ( data[8] == crc1 ) + PrintAndLog(" BCC1 : %02x - Ok", data[8]); + else + PrintAndLog(" BCC1 : %02x - crc should be %02x", data[8], crc1 ); + + PrintAndLog(" Internal : %s ", sprint_hex(data + 9, 1)); + + memcpy(datatemp, data+10, 2); + PrintAndLog(" Lock : %s - %s", sprint_hex(datatemp, 2),printBits( 2, &datatemp) ); + PrintAndLog(" OneTimePad : %s ", sprint_hex(data + 3*4, 4)); + PrintAndLog(""); + + int len = CmdHF14AMfucAuth("K 0"); +// PrintAndLog("CODE: %d",len); + + PrintAndLog("Seems to be a Ultralight %s", (len==0) ? "-C" :""); + return 0; +} + +// +// Mifare Ultralight Write Single Block +// +int CmdHF14AMfUWrBl(const char *Cmd){ + uint8_t blockNo = -1; + bool chinese_card = FALSE; + uint8_t bldata[16] = {0x00}; + UsbCommand resp; + + char cmdp = param_getchar(Cmd, 0); + if (strlen(Cmd) < 3 || cmdp == 'h' || cmdp == 'H') { + PrintAndLog("Usage: hf mfu wrbl [w]"); + PrintAndLog(" [block number]"); + PrintAndLog(" [block data] - (8 hex symbols)"); + PrintAndLog(" [w] - Chinese magic ultralight tag"); + PrintAndLog(""); + PrintAndLog(" sample: hf mfu wrbl 0 01020304"); + PrintAndLog(""); + return 0; + } + + blockNo = param_get8(Cmd, 0); + + if (blockNo > MAX_ULTRA_BLOCKS){ + PrintAndLog("Error: Maximum number of blocks is 15 for Ultralight Cards!"); + return 1; + } + + if (param_gethex(Cmd, 1, bldata, 8)) { + PrintAndLog("Block data must include 8 HEX symbols"); + return 1; + } + + if (strchr(Cmd,'w') != 0 || strchr(Cmd,'W') != 0 ) { + chinese_card = TRUE; + } + + if ( blockNo <= 3) { + if (!chinese_card){ + PrintAndLog("Access Denied"); + } else { + PrintAndLog("--specialblock no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(d.d.asBytes,bldata, 4); + SendCommand(&d); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + } + } else { + PrintAndLog("--block no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(e.d.asBytes,bldata, 4); + SendCommand(&e); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + } + return 0; +} + +// +// Mifare Ultralight Read Single Block +// +int CmdHF14AMfURdBl(const char *Cmd){ + + uint8_t blockNo = -1; + + char cmdp = param_getchar(Cmd, 0); + + if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') { + PrintAndLog("Usage: hf mfu rdbl "); + PrintAndLog(" sample: hfu mfu rdbl 0"); + return 0; + } + + blockNo = param_get8(Cmd, 0); + + if (blockNo > MAX_ULTRA_BLOCKS){ + PrintAndLog("Error: Maximum number of blocks is 15 for Ultralight Cards!"); + return 1; + } + + PrintAndLog("--block no:0x%02X (%d)", (int)blockNo, blockNo); + UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}}; + SendCommand(&c); + + UsbCommand resp; + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + uint8_t * data = resp.d.asBytes; + + PrintAndLog("isOk: %02x", isOK); + + if (isOK) + PrintAndLog("Data: %s", sprint_hex(data, 4)); + } else { + PrintAndLog("Command execute timeout"); + } + return 0; +} + +// +// Mifare Ultralight / Ultralight-C; Read and Dump Card Contents +// +int CmdHF14AMfUDump(const char *Cmd){ + + FILE *fout; + char filename[FILE_PATH_SIZE] = {0x00}; + char * fnameptr = filename; + + uint8_t *lockbytes_t = NULL; + uint8_t lockbytes[2] = {0x00}; + + uint8_t *lockbytes_t2 = NULL; + uint8_t lockbytes2[2] = {0x00}; + + bool bit[16] = {0x00}; + bool bit2[16] = {0x00}; + + int i; + uint8_t BlockNo = 0; + int Pages = 16; + + bool tmplockbit = false; + uint8_t isOK = 0; + uint8_t *data = NULL; + + char cmdp = param_getchar(Cmd, 0); + + if (cmdp == 'h' || cmdp == 'H') { + PrintAndLog("Reads all pages from Mifare Ultralight or Ultralight-C tag."); + PrintAndLog("It saves binary dump into the file `filename.bin` or `cardUID.bin`"); + PrintAndLog("Usage: hf mfu dump "); + PrintAndLog(" optional cardtype c == Ultralight-C, if not defaults to Ultralight"); + PrintAndLog(" sample: hf mfu dump"); + PrintAndLog(" : hf mfu dump myfile"); + PrintAndLog(" : hf mfu dump c myfile"); + return 0; + } + + // UL or UL-C? + Pages = (cmdp == 'c' || cmdp == 'C') ? 44 : 16; + + PrintAndLog("Dumping Ultralight%s Card Data...", (Pages ==16)?"":"-C"); + + UsbCommand c = {CMD_MIFAREU_READCARD, {BlockNo,Pages}}; + SendCommand(&c); + UsbCommand resp; + + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + isOK = resp.arg[0] & 0xff; + if (!isOK) { + PrintAndLog("Command error"); + return 0; + } + data = resp.d.asBytes; + } else { + PrintAndLog("Command execute timeout"); + return 0; + } + + // Load lock bytes. + int j = 0; + + lockbytes_t = data + 8; + lockbytes[0] = lockbytes_t[2]; + lockbytes[1] = lockbytes_t[3]; + for(j = 0; j < 16; j++){ + bit[j] = lockbytes[j/8] & ( 1 <<(7-j%8)); + } + + // Load bottom lockbytes if available + if ( Pages == 44 ) { + + lockbytes_t2 = data + (40*4); + lockbytes2[0] = lockbytes_t2[2]; + lockbytes2[1] = lockbytes_t2[3]; + for (j = 0; j < 16; j++) { + bit2[j] = lockbytes2[j/8] & ( 1 <<(7-j%8)); + } + } + + for (i = 0; i < Pages; ++i) { + + if ( i < 3 ) { + PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); + continue; + } + + switch(i){ + case 3: tmplockbit = bit[4]; break; + case 4: tmplockbit = bit[3]; break; + case 5: tmplockbit = bit[2]; break; + case 6: tmplockbit = bit[1]; break; + case 7: tmplockbit = bit[0]; break; + case 8: tmplockbit = bit[15]; break; + case 9: tmplockbit = bit[14]; break; + case 10: tmplockbit = bit[13]; break; + case 11: tmplockbit = bit[12]; break; + case 12: tmplockbit = bit[11]; break; + case 13: tmplockbit = bit[10]; break; + case 14: tmplockbit = bit[9]; break; + case 15: tmplockbit = bit[8]; break; + case 16: + case 17: + case 18: + case 19: tmplockbit = bit2[6]; break; + case 20: + case 21: + case 22: + case 23: tmplockbit = bit2[5]; break; + case 24: + case 25: + case 26: + case 27: tmplockbit = bit2[4]; break; + case 28: + case 29: + case 30: + case 31: tmplockbit = bit2[2]; break; + case 32: + case 33: + case 34: + case 35: tmplockbit = bit2[1]; break; + case 36: + case 37: + case 38: + case 39: tmplockbit = bit2[0]; break; + case 40: tmplockbit = bit2[12]; break; + case 41: tmplockbit = bit2[11]; break; + case 42: tmplockbit = bit2[10]; break; //auth0 + case 43: tmplockbit = bit2[9]; break; //auth1 + default: break; + } + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),tmplockbit); + } + + int len = 0; + if ( Pages == 16 ) + len = param_getstr(Cmd,0,filename); + else + len = param_getstr(Cmd,1,filename); + + if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; + + // user supplied filename? + if (len < 1) { + + // UID = data 0-1-2 4-5-6-7 (skips a beat) + sprintf(fnameptr, "%02X", data[0]); + fnameptr += 2; + sprintf(fnameptr, "%02X", data[1]); + fnameptr += 2; + sprintf(fnameptr, "%02X", data[2]); + fnameptr += 2; + sprintf(fnameptr, "%02X", data[4]); + fnameptr += 2; + sprintf(fnameptr, "%02X", data[5]); + fnameptr += 2; + sprintf(fnameptr, "%02X", data[6]); + fnameptr += 2; + sprintf(fnameptr, "%02X", data[7]); + fnameptr += 2; + + } else { + fnameptr += len; + } + + // add file extension + sprintf(fnameptr, ".bin"); + + if ((fout = fopen(filename,"wb")) == NULL) { + PrintAndLog("Could not create file name %s", filename); + return 1; + } + fwrite( data, 1, Pages*4, fout ); + fclose(fout); + + PrintAndLog("Dumped %d pages, wrote %d bytes to %s", Pages, Pages*4, filename); + return 0; +} + +// Needed to Authenticate to Ultralight C tags +void rol (uint8_t *data, const size_t len){ + uint8_t first = data[0]; + for (size_t i = 0; i < len-1; i++) { + data[i] = data[i+1]; + } + data[len-1] = first; +} + +//------------------------------------------------------------------------------- +// Ultralight C Methods +//------------------------------------------------------------------------------- + +// +// Ultralight C Authentication Demo {currently uses hard-coded key} +// +int CmdHF14AMfucAuth(const char *Cmd){ + + uint8_t blockNo = 0, keyNo = 0; + uint8_t e_RndB[8] = {0x00}; + uint32_t cuid = 0; + unsigned char RndARndB[16] = {0x00}; + uint8_t key[16] = {0x00}; + DES_cblock RndA, RndB; + DES_cblock iv; + DES_key_schedule ks1,ks2; + DES_cblock key1,key2; + + char cmdp = param_getchar(Cmd, 0); + // + memset(iv, 0, 8); + + if (cmdp == 'h' || cmdp == 'H') { + PrintAndLog("Usage: hf mfu cauth k "); + PrintAndLog(" 1 = all zeros key"); + PrintAndLog(" 2 = 0x00-0x0F key"); + PrintAndLog(" 3 = nfc key"); + PrintAndLog(" 4 = all ones key"); + PrintAndLog(" defaults to 3DES standard key"); + PrintAndLog(" sample : hf mfu cauth k"); + PrintAndLog(" : hf mfu cauth k 3"); + return 0; + } + + //Change key to user defined one + if (cmdp == 'k' || cmdp == 'K'){ + + keyNo = param_get8(Cmd, 1); + + switch(keyNo){ + case 0: + memcpy(key,key1_blnk_data,16); + break; + case 1: + memcpy(key,key2_defa_data,16); + break; + case 2: + memcpy(key,key4_nfc_data,16); + break; + case 3: + memcpy(key,key5_ones_data,16); + break; + default: + memcpy(key,key3_3des_data,16); + break; + } + } else { + memcpy(key,key3_3des_data,16); + } + + memcpy(key1,key,8); + memcpy(key2,key+8,8); + DES_set_key((DES_cblock *)key1,&ks1); + DES_set_key((DES_cblock *)key2,&ks2); + + //Auth1 + UsbCommand c = {CMD_MIFAREUC_AUTH1, {blockNo}}; + SendCommand(&c); + UsbCommand resp; + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + cuid = resp.arg[1]; + uint8_t * data= resp.d.asBytes; + + if (isOK){ + PrintAndLog("enc(RndB):%s", sprint_hex(data+1, 8)); + memcpy(e_RndB,data+1,8); + } else { + return 2; // auth failed. + } + } else { + PrintAndLog("Command execute timeout"); + return 1; + } + + //Do crypto magic + DES_random_key(&RndA); + DES_ede2_cbc_encrypt(e_RndB,RndB,sizeof(e_RndB),&ks1,&ks2,&iv,0); + PrintAndLog(" RndB:%s",sprint_hex(RndB, 8)); + PrintAndLog(" RndA:%s",sprint_hex(RndA, 8)); + rol(RndB,8); + memcpy(RndARndB,RndA,8); + memcpy(RndARndB+8,RndB,8); + PrintAndLog(" RA+B:%s",sprint_hex(RndARndB, 16)); + DES_ede2_cbc_encrypt(RndARndB,RndARndB,sizeof(RndARndB),&ks1,&ks2,&e_RndB,1); + PrintAndLog("enc(RA+B):%s",sprint_hex(RndARndB, 16)); + + //Auth2 + UsbCommand d = {CMD_MIFAREUC_AUTH2, {cuid}}; + memcpy(d.d.asBytes,RndARndB, 16); + SendCommand(&d); + + UsbCommand respb; + if (WaitForResponseTimeout(CMD_ACK,&respb,1500)) { + uint8_t isOK = respb.arg[0] & 0xff; + uint8_t * data2= respb.d.asBytes; + + if (isOK){ + PrintAndLog("enc(RndA'):%s", sprint_hex(data2+1, 8)); + } else { + return 2; + } + + } else { + PrintAndLog("Command execute timeout"); + return 1; + } + return 0; +} + +// +// Ultralight C Read Single Block +// +int CmdHF14AMfUCRdBl(const char *Cmd) +{ + uint8_t blockNo = -1; + char cmdp = param_getchar(Cmd, 0); + + if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') { + PrintAndLog("Usage: hf mfu crdbl "); + PrintAndLog(" sample: hf mfu crdbl 0"); + return 0; + } + + blockNo = param_get8(Cmd, 0); + if (blockNo < 0) { + PrintAndLog("Wrong block number"); + return 1; + } + + if (blockNo > MAX_ULTRAC_BLOCKS ){ + PrintAndLog("Error: Maximum number of readable blocks is 47 for Ultralight-C Cards!"); + return 1; + } + + PrintAndLog("--block no: 0x%02X (%d)", (int)blockNo, blockNo); + + //Read Block + UsbCommand e = {CMD_MIFAREU_READBL, {blockNo}}; + SendCommand(&e); + UsbCommand resp_c; + if (WaitForResponseTimeout(CMD_ACK,&resp_c,1500)) { + uint8_t isOK = resp_c.arg[0] & 0xff; + uint8_t *data = resp_c.d.asBytes; + + PrintAndLog("isOk: %02x", isOK); + if (isOK) + PrintAndLog("Data: %s", sprint_hex(data, 4)); + + } else { + PrintAndLog("Command execute timeout"); + } + return 0; +} + +// +// Mifare Ultralight C Write Single Block +// +int CmdHF14AMfUCWrBl(const char *Cmd){ + + uint8_t blockNo = -1; + bool chinese_card = FALSE; + uint8_t bldata[16] = {0x00}; + UsbCommand resp; + + char cmdp = param_getchar(Cmd, 0); + + if (strlen(Cmd) < 3 || cmdp == 'h' || cmdp == 'H') { + PrintAndLog("Usage: hf mfu cwrbl [w]"); + PrintAndLog(" [block number]"); + PrintAndLog(" [block data] - (8 hex symbols)"); + PrintAndLog(" [w] - Chinese magic ultralight tag"); + PrintAndLog(""); + PrintAndLog(" sample: hf mfu cwrbl 0 01020304"); + PrintAndLog(""); + return 0; + } + + blockNo = param_get8(Cmd, 0); + if (blockNo > MAX_ULTRAC_BLOCKS ){ + PrintAndLog("Error: Maximum number of blocks is 47 for Ultralight-C Cards!"); + return 1; + } + + if (param_gethex(Cmd, 1, bldata, 8)) { + PrintAndLog("Block data must include 8 HEX symbols"); + return 1; + } + + if (strchr(Cmd,'w') != 0 || strchr(Cmd,'W') != 0 ) { + chinese_card = TRUE; + } + + if ( blockNo <= 3 ) { + if (!chinese_card){ + PrintAndLog("Access Denied"); + } else { + PrintAndLog("--Special block no: 0x%02x", blockNo); + PrintAndLog("--Data: %s", sprint_hex(bldata, 4)); + UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(d.d.asBytes,bldata, 4); + SendCommand(&d); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + } + } else { + PrintAndLog("--Block no : 0x%02x", blockNo); + PrintAndLog("--Data: %s", sprint_hex(bldata, 4)); + UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(e.d.asBytes,bldata, 4); + SendCommand(&e); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk : %02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + } + return 0; +} + +//------------------------------------ +// Menu Stuff +//------------------------------------ +static command_t CommandTable[] = +{ + {"help", CmdHelp, 1,"This help"}, + {"dbg", CmdHF14AMfDbg, 0,"Set default debug mode"}, + {"info", CmdHF14AMfUInfo, 0,"Taginfo"}, + {"dump", CmdHF14AMfUDump, 0,"Dump MIFARE Ultralight / Ultralight-C tag to binary file"}, + {"rdbl", CmdHF14AMfURdBl, 0,"Read block - MIFARE Ultralight"}, + {"wrbl", CmdHF14AMfUWrBl, 0,"Write block - MIFARE Ultralight"}, + {"crdbl", CmdHF14AMfUCRdBl, 0,"Read block - MIFARE Ultralight C"}, + {"cwrbl", CmdHF14AMfUCWrBl, 0,"Write MIFARE Ultralight C block"}, + {"cauth", CmdHF14AMfucAuth, 0,"try a Ultralight C Authentication"}, + {NULL, NULL, 0, NULL} +}; + +int CmdHFMFUltra(const char *Cmd){ + WaitForResponseTimeout(CMD_ACK,NULL,100); + CmdsParse(CommandTable, Cmd); + return 0; +} + +int CmdHelp(const char *Cmd){ + CmdsHelp(CommandTable); + return 0; +} \ No newline at end of file diff --git a/client/cmdhfmfu.h b/client/cmdhfmfu.h new file mode 100644 index 00000000..c4bc0341 --- /dev/null +++ b/client/cmdhfmfu.h @@ -0,0 +1,19 @@ +#include "cmdhfmf.h" +#include "cmdhf14a.h" + +//standard ultralight +int CmdHF14AMfUWrBl(const char *Cmd); +int CmdHF14AMfURdBl(const char *Cmd); + +//Crypto Cards +int CmdHF14AMfUCRdBl(const char *Cmd); +int CmdHF14AMfUCRdCard(const char *Cmd); +int CmdHF14AMfucAuth(const char *Cmd); + +//general stuff +int CmdHF14AMfUDump(const char *Cmd); +void rol (uint8_t *data, const size_t len); + + +int CmdHFMFUltra(const char *Cmd); +int CmdHF14AMfUInfo(const char *Cmd); diff --git a/client/scripts/remagic.lua b/client/scripts/remagic.lua new file mode 100644 index 00000000..d2b869c3 --- /dev/null +++ b/client/scripts/remagic.lua @@ -0,0 +1,63 @@ +local getopt = require('getopt') + +example = "script run remagic" +author = "Iceman" + +desc = +[[ +This is a script that tries to bring back a chinese magic card (1k generation1) +from the dead when it's block 0 has been written with bad values. + +Arguments: + -h this help +]] +--- +-- A debug printout-function +function dbg(args) + if DEBUG then + print("###", args) + end +end +--- +-- This is only meant to be used when errors occur +function oops(err) + print("ERROR: ",err) +end + +--- +-- Usage help +function help() + print(desc) + print("Example usage") + print(example) +end + +--- +-- The main entry point +function main(args) + + + -- Read the parameters + for o, a in getopt.getopt(args, 'h') do + if o == "h" then help() return end + end + + local _cmds = { + --[[ + --]] + [0] = "hf 14a raw -p -a -b 7 40", + [1] = "hf 14a raw -p -a 43", + [2] = "hf 14a raw -c -p -a A000", + [3] = "hf 14a raw -c -p -a 01 02 03 04 04 98 02 00 00 00 00 00 00 00 10 01", + } + core.clearCommandBuffer() + + local i + --for _,c in pairs(_cmds) do + for i = 0, 3 do + print ( _cmds[i] ) + core.console( _cmds[i] ) + end +end + +main(args) diff --git a/client/scripts/test_t55x7_psk.lua b/client/scripts/test_t55x7_psk.lua new file mode 100644 index 00000000..1b964094 --- /dev/null +++ b/client/scripts/test_t55x7_psk.lua @@ -0,0 +1,173 @@ +local cmds = require('commands') +local getopt = require('getopt') +local bin = require('bin') +local utils = require('utils') +local dumplib = require('html_dumplib') + +example =[[ + 1. script run tracetest + 2. script run tracetest -o + +]] +author = "Iceman" +usage = "script run test_t55x7_psk -o " +desc =[[ +This script will program a T55x7 TAG with the configuration: block 0x00 data 0x00088040 +The outlined procedure is as following: + +"lf t55xx write 0 00088040" +"lf read" +"data samples" +"data pskdet" +"data psknrz" +"data pskindala" +"data psknrzraw" + +Loop OUTER: + change the configuretion block 0 with: + -xxxx8xxx = PSK RF/2 with Manchester modulation + -xxxx1xxx = PSK RF/2 with PSK1 modulation (phase change when input changes) + -xxxx2xxx = PSK RF/2 with PSk2 modulation (phase change on bitclk if input high) + -xxxx3xxx = PSK RF/2 with PSk3 modulation (phase change on rising edge of input) + Loop INNER + for each outer configuration, also do + XXXXX0XX = PSK RF/2 + XXXXX4XX = PSK RF/4 + XXXXX8XX = PSK RF/8 + +In all 12 individual test for the PSK demod + +Arguments: + -h : this help + -o : logfile name +]] + +local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds +local DEBUG = true -- the debug flag + +--BLOCK 0 = 00088040 +local config1 = '0008' +local config2 = '40' + +local procedurecmds = { + [1] = '%s%s%s%s', + [2] = 'lf read', + --[3] = '', + [3] = 'data samples', + [4] = 'data pskdetectclock', + [5] = 'data psknrzrawdemod', + [6] = 'data pskindalademod', +} + +--- +-- A debug printout-function +function dbg(args) + if not DEBUG then + return + end + + if type(args) == "table" then + local i = 1 + while args[i] do + dbg(args[i]) + i = i+1 + end + else + print("###", args) + end +end +--- +-- This is only meant to be used when errors occur +function oops(err) + print("ERROR: ",err) +end +--- +-- Usage help +function help() + print(desc) + print("Example usage") + print(example) +end +-- +-- Exit message +function ExitMsg(msg) + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() +end + +function pskTest(modulation) + local y + for y = 0, 8, 4 do + for _ = 1, #procedurecmds do + local cmd = procedurecmds[_] + + if #cmd == 0 then + + elseif _ == 1 then + + dbg("Writing to T55x7 TAG") + + local configdata = cmd:format( config1, modulation , y, config2) + + dbg( configdata) + + local writecommand = Command:new{cmd = cmds.CMD_T55XX_WRITE_BLOCK, arg1 = configdata ,arg2 = 0, arg3 = 0} + local err = core.SendCommand(writecommand:getBytes()) + if err then return oops(err) end + local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT) + + if response then + local count,cmd,arg0 = bin.unpack('LL',response) + if(arg0==1) then + dbg("Writing success") + else + return nil, "Couldn't read block.." + end + end + + else + dbg(cmd) + core.console( cmd ) + end + end + core.clearCommandBuffer() + end + print( string.rep('--',20) ) + +end + +local function main(args) + + print( string.rep('--',20) ) + print( string.rep('--',20) ) + + local outputTemplate = os.date("testpsk_%Y-%m-%d_%H%M%S") + + -- Arguments for the script + for o, arg in getopt.getopt(args, 'ho:') do + if o == "h" then return help() end + if o == "o" then outputTemplate = arg end + end + + core.clearCommandBuffer() + + pskTest(1) + pskTest(2) + pskTest(3) + pskTest(8) + + print( string.rep('--',20) ) +end +main(args) + +-- Where it iterates over + -- xxxx8xxx = PSK RF/2 with Manchester modulation + -- xxxx1xxx = PSK RF/2 with PSK1 modulation (phase change when input changes) + -- xxxx2xxx = PSK RF/2 with PSk2 modulation (phase change on bitclk if input high) + -- xxxx3xxx = PSK RF/2 with PSk3 modulation (phase change on rising edge of input) + + -- XXXXX0XX = PSK RF/2 + -- XXXXX4XX = PSK RF/4 + -- XXXXX8XX = PSK RF/8 \ No newline at end of file diff --git a/client/scripts/tracetest.lua b/client/scripts/tracetest.lua new file mode 100644 index 00000000..e4a9215c --- /dev/null +++ b/client/scripts/tracetest.lua @@ -0,0 +1,132 @@ +local cmds = require('commands') +local getopt = require('getopt') +local bin = require('bin') +local utils = require('utils') +local dumplib = require('html_dumplib') + +example =[[ + 1. script run tracetest + 2. script run tracetest -o + +]] +author = "Iceman" +usage = "script run tracetest -o " +desc =[[ +This script will load several traces files in ../traces/ folder and do +"data load" +"lf search" + +Arguments: + -h : this help + -o : logfile name +]] + +local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds +local DEBUG = true -- the debug flag +--- +-- A debug printout-function +function dbg(args) + if not DEBUG then + return + end + + if type(args) == "table" then + local i = 1 + while result[i] do + dbg(result[i]) + i = i+1 + end + else + print("###", args) + end +end +--- +-- This is only meant to be used when errors occur +function oops(err) + print("ERROR: ",err) +end +--- +-- Usage help +function help() + print(desc) + print("Example usage") + print(example) +end +-- +-- Exit message +function ExitMsg(msg) + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() +end + + +local function main(args) + + print( string.rep('--',20) ) + print( string.rep('--',20) ) + + local cmdDataLoad = 'data load %s'; + local tracesEM = "find '../traces/' -iname 'em*.pm3' -type f" + local tracesMOD = "find '../traces/' -iname 'm*.pm3' -type f" + + local outputTemplate = os.date("testtest_%Y-%m-%d_%H%M%S") + + -- Arguments for the script + for o, arg in getopt.getopt(args, 'ho:') do + if o == "h" then return help() end + if o == "o" then outputTemplate = arg end + end + + core.clearCommandBuffer() + + local files = {} + + -- Find a set of traces staring with EM + local p = assert( io.popen(tracesEM)) + for file in p:lines() do + table.insert(files, file) + end + p.close(); + + -- Find a set of traces staring with MOD + p = assert( io.popen(tracesMOD) ) + for file in p:lines() do + table.insert(files, file) + end + p.close(); + + local cmdLFSEARCH = "lf search 1" + + -- main loop + io.write('Starting to test traces > ') + for _,file in pairs(files) do + + local x = "data load "..file + dbg(x) + core.console(x) + + dbg(cmdLFSEARCH) + core.console(cmdLFSEARCH) + + core.clearCommandBuffer() + + if core.ukbhit() then + print("aborted by user") + break + end + end + io.write('\n') + + -- Write dump to files + if not DEBUG then + local bar = dumplib.SaveAsText(emldata, outputTemplate..'.txt') + print(("Wrote output to: %s"):format(bar)) + end + + -- Show info + print( string.rep('--',20) ) + +end +main(args) \ No newline at end of file -- 2.39.5 From e3c235654f60acf16d13581d952b4125a774cdcd Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 20 Jan 2015 21:48:39 +0100 Subject: [PATCH 11/16] Minor fixes to some help-texts. --- client/cmdhfmf.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 28f7b078..24d04dc2 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -778,12 +778,14 @@ int CmdHF14AMfNested(const char *Cmd) int CmdHF14AMfChk(const char *Cmd) { if (strlen(Cmd)<3) { - PrintAndLog("Usage: hf mf chk |<*card memory> [t] [] []"); + PrintAndLog("Usage: hf mf chk |<*card memory> [t|d] [] []"); PrintAndLog(" * - all sectors"); PrintAndLog("card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, - 1K"); PrintAndLog("d - write keys to binary file\n"); + PrintAndLog("t - write keys to emulator memory"); PrintAndLog(" sample: hf mf chk 0 A 1234567890ab keys.dic"); PrintAndLog(" hf mf chk *1 ? t"); + PrintAndLog(" hf mf chk *1 ? d"); return 0; } @@ -1010,12 +1012,16 @@ int CmdHF14AMf1kSim(const char *Cmd) uint8_t exitAfterNReads = 0; uint8_t flags = 0; - if (param_getchar(Cmd, 0) == 'h') { + uint8_t cmdp = param_getchar(Cmd, 0); + + if (cmdp == 'h' || cmdp == 'H') { PrintAndLog("Usage: hf mf sim u n i x"); + PrintAndLog(" h this help"); PrintAndLog(" u (Optional) UID. If not specified, the UID from emulator memory will be used"); PrintAndLog(" n (Optional) Automatically exit simulation after blocks have been read by reader. 0 = infinite"); PrintAndLog(" i (Optional) Interactive, means that console will not be returned until simulation finishes or is aborted"); PrintAndLog(" x (Optional) Crack, performs the 'reader attack', nr/ar attack against a legitimate reader, fishes out the key(s)"); + PrintAndLog(""); PrintAndLog(" sample: hf mf sim u 0a0a0a0a "); return 0; } @@ -1445,7 +1451,7 @@ int CmdHF14AMfCSetUID(const char *Cmd) char ctmp = param_getchar(Cmd, 1); if (ctmp == 'w' || ctmp == 'W') wipeCard = 1; - PrintAndLog("--wipe card:%02x uid:%s", wipeCard, sprint_hex(uid, 4)); + PrintAndLog("--wipe card:%s uid:%s", (wipeCard)?"YES":"NO", sprint_hex(uid, 4)); res = mfCSetUID(uid, oldUid, wipeCard); if (res) { @@ -1488,7 +1494,6 @@ int CmdHF14AMfCSetBlk(const char *Cmd) return 1; } - PrintAndLog("UID:%s", sprint_hex(uid, 4)); return 0; } @@ -1503,11 +1508,8 @@ int CmdHF14AMfCLoad(const char *Cmd) uint8_t fillFromEmulator = 0; int i, len, blockNum, flags; - // memset(filename, 0, sizeof(filename)); - // memset(buf, 0, sizeof(buf)); - if (param_getchar(Cmd, 0) == 'h' || param_getchar(Cmd, 0)== 0x00) { - PrintAndLog("It loads magic Chinese card (only works with!!!) from the file `filename.eml`"); + PrintAndLog("It loads magic Chinese card from the file `filename.eml`"); PrintAndLog("or from emulator memory (option `e`)"); PrintAndLog("Usage: hf mf cload "); PrintAndLog(" or: hf mf cload e "); @@ -1554,7 +1556,9 @@ int CmdHF14AMfCLoad(const char *Cmd) blockNum = 0; flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC; while(!feof(f)){ + memset(buf, 0, sizeof(buf)); + if (fgets(buf, sizeof(buf), f) == NULL) { PrintAndLog("File reading error."); return 2; @@ -1589,6 +1593,7 @@ int CmdHF14AMfCLoad(const char *Cmd) PrintAndLog("Loaded from file: %s", filename); return 0; } + return 0; } int CmdHF14AMfCGetBlk(const char *Cmd) { @@ -1770,7 +1775,8 @@ int CmdHF14AMfSniff(const char *Cmd){ uint8_t buf[3000] = {0x00}; uint8_t * bufPtr = buf; - if (param_getchar(Cmd, 0) == 'h') { + char ctmp = param_getchar(Cmd, 0); + if ( ctmp == 'h' || ctmp == 'H' ) { PrintAndLog("It continuously gets data from the field and saves it to: log, emulator, emulator file."); PrintAndLog("You can specify:"); PrintAndLog(" l - save encrypted sequence to logfile `uid.log`"); @@ -1783,7 +1789,7 @@ int CmdHF14AMfSniff(const char *Cmd){ } for (int i = 0; i < 4; i++) { - char ctmp = param_getchar(Cmd, i); + ctmp = param_getchar(Cmd, i); if (ctmp == 'l' || ctmp == 'L') wantLogToFile = true; if (ctmp == 'd' || ctmp == 'D') wantDecrypt = true; //if (ctmp == 'e' || ctmp == 'E') wantSaveToEml = true; TODO -- 2.39.5 From fe5b3a4424bdbb1455f879e05ec248abc8c70867 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 20 Jan 2015 21:50:49 +0100 Subject: [PATCH 12/16] FIX: The 14b write command (CmdHF14BWrite) now turns off antenna after call. --- client/cmdhf14b.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c index 0350fc31..ea07b894 100644 --- a/client/cmdhf14b.c +++ b/client/cmdhf14b.c @@ -448,7 +448,7 @@ int CmdHF14BWrite( const char *Cmd){ else PrintAndLog("[%s] Write block %02X [ %s ]", (isSrix4k)?"SRIX4K":"SRI512", blockno, sprint_hex(data,4) ); - sprintf(str, "-c -p 09 %02x %02x%02x%02x%02x", blockno, data[0], data[1], data[2], data[3]); + sprintf(str, "-c 09 %02x %02x%02x%02x%02x", blockno, data[0], data[1], data[2], data[3]); CmdHF14BCmdRaw(str); return 0; -- 2.39.5 From 80b1b53fa35b51a05bb8b32cbb9498132e94430b Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 20 Jan 2015 21:55:19 +0100 Subject: [PATCH 13/16] SUGGESTED FIX: Issue: https://github.com/Proxmark/proxmark3/issues/35 Forum: http://www.proxmark.org/forum/viewtopic.php?pid=7883#p7883 Where "hf mf csetuid" empties the rest of the block0 bytes. This fix loads the old block0 and replaces the uid+sak+ataq bytes only. --- client/mifarehost.c | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/client/mifarehost.c b/client/mifarehost.c index d025918d..e62d6260 100644 --- a/client/mifarehost.c +++ b/client/mifarehost.c @@ -232,14 +232,27 @@ int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount) { // "MAGIC" CARD int mfCSetUID(uint8_t *uid, uint8_t *oldUID, bool wantWipe) { + + uint8_t oldblock0[16] = {0x00}; uint8_t block0[16] = {0x00}; memcpy(block0, uid, 4); block0[4] = block0[0]^block0[1]^block0[2]^block0[3]; // Mifare UID BCC // mifare classic SAK(byte 5) and ATQA(byte 6 and 7) - block0[5] = 0x08; - block0[6] = 0x04; - block0[7] = 0x00; + //block0[5] = 0x08; + //block0[6] = 0x04; + //block0[7] = 0x00; + + block0[5] = 0x01; //sak + block0[6] = 0x01; + block0[7] = 0x0f; + int old = mfCGetBlock(0, oldblock0, CSETBLOCK_SINGLE_OPER); + if ( old == 0) { + memcpy(block0+8, oldblock0+8, 8); + PrintAndLog("block 0: %s", sprint_hex(block0,16)); + } else { + PrintAndLog("Couldn't get olddata. Will write over the last bytes of Block 0."); + } return mfCSetBlock(0, block0, oldUID, wantWipe, CSETBLOCK_SINGLE_OPER); } @@ -253,8 +266,10 @@ int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, bool wantWipe, uin UsbCommand resp; if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { isOK = resp.arg[0] & 0xff; - if (uid != NULL) memcpy(uid, resp.d.asBytes, 4); - if (!isOK) return 2; + if (uid != NULL) + memcpy(uid, resp.d.asBytes, 4); + if (!isOK) + return 2; } else { PrintAndLog("Command execute timeout"); return 1; @@ -323,13 +338,16 @@ int isBlockTrailer(int blockN) { int loadTraceCard(uint8_t *tuid) { FILE * f; - char buf[64]; - uint8_t buf8[64]; + char buf[64] = {0x00}; + uint8_t buf8[64] = {0x00}; int i, blockNum; - if (!isTraceCardEmpty()) saveTraceCard(); + if (!isTraceCardEmpty()) + saveTraceCard(); + memset(traceCard, 0x00, 4096); memcpy(traceCard, tuid + 3, 4); + FillFileNameByUID(traceFileName, tuid, ".eml", 7); f = fopen(traceFileName, "r"); @@ -380,10 +398,14 @@ int saveTraceCard(void) { int mfTraceInit(uint8_t *tuid, uint8_t *atqa, uint8_t sak, bool wantSaveToEmlFile) { - if (traceCrypto1) crypto1_destroy(traceCrypto1); + if (traceCrypto1) + crypto1_destroy(traceCrypto1); + traceCrypto1 = NULL; - if (wantSaveToEmlFile) loadTraceCard(tuid); + if (wantSaveToEmlFile) + loadTraceCard(tuid); + traceCard[4] = traceCard[0] ^ traceCard[1] ^ traceCard[2] ^ traceCard[3]; traceCard[5] = sak; memcpy(&traceCard[6], atqa, 2); -- 2.39.5 From e4691591454edf2c11697096ea72d650a7dbda79 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 20 Jan 2015 21:58:53 +0100 Subject: [PATCH 14/16] FIX: another file_path found in loadTraceCard and saveTraceCard, is now corrected to follow FILE_PATH_SIZE variable. FIX: some filehandles that didn't get closed. --- client/mifarehost.c | 17 +++++++++++++---- client/mifarehost.h | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/client/mifarehost.c b/client/mifarehost.c index e62d6260..7f784850 100644 --- a/client/mifarehost.c +++ b/client/mifarehost.c @@ -301,9 +301,9 @@ int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params) { static uint8_t trailerAccessBytes[4] = {0x08, 0x77, 0x8F, 0x00}; // variables -char logHexFileName[200] = {0x00}; +char logHexFileName[FILE_PATH_SIZE] = {0x00}; static uint8_t traceCard[4096] = {0x00}; -static char traceFileName[200] = {0x00}; +static char traceFileName[FILE_PATH_SIZE] = {0x00}; static int traceState = TRACE_IDLE; static uint8_t traceCurBlock = 0; static uint8_t traceCurKey = 0; @@ -351,10 +351,15 @@ int loadTraceCard(uint8_t *tuid) { FillFileNameByUID(traceFileName, tuid, ".eml", 7); f = fopen(traceFileName, "r"); - if (!f) return 1; + if (!f) { + fclose(f); + return 1; + } blockNum = 0; + while(!feof(f)){ + memset(buf, 0, sizeof(buf)); if (fgets(buf, sizeof(buf), f) == NULL) { PrintAndLog("File reading error."); @@ -386,13 +391,17 @@ int saveTraceCard(void) { if ((!strlen(traceFileName)) || (isTraceCardEmpty())) return 0; f = fopen(traceFileName, "w+"); + if ( !f ) { + fclose(f); + return 1; + } + for (int i = 0; i < 64; i++) { // blocks for (int j = 0; j < 16; j++) // bytes fprintf(f, "%02x", *(traceCard + i * 16 + j)); fprintf(f,"\n"); } fclose(f); - return 0; } diff --git a/client/mifarehost.h b/client/mifarehost.h index 3e946cd9..96eb75f7 100644 --- a/client/mifarehost.h +++ b/client/mifarehost.h @@ -47,7 +47,7 @@ typedef struct { int foundKey[2]; } sector; -extern char logHexFileName[200]; +extern char logHexFileName[FILE_PATH_SIZE]; int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * ResultKeys, bool calibrate); int mfCheckKeys (uint8_t blockNo, uint8_t keyType, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key); -- 2.39.5 From a1557c4c2f3905fd760dbac16cba5be890948634 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 20 Jan 2015 22:14:56 +0100 Subject: [PATCH 15/16] Minor fixes: Array inits, some array bounds checks. ADD: some extra help text for lf snoop ADD: HasGraphData - function in graph.c ADD: DetectHighLowInGraph - function in graph.c --- client/cmddata.c | 9 ++------- client/cmdlf.c | 3 +++ client/graph.c | 49 ++++++++++++++++++++++++++++++++++++++++++++---- client/graph.h | 4 +++- 4 files changed, 53 insertions(+), 12 deletions(-) diff --git a/client/cmddata.c b/client/cmddata.c index a88fa4e1..820e44e2 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -511,10 +511,6 @@ int CmdBitstream(const char *Cmd) bit ^= 1; AppendGraph(0, clock, bit); - // for (j = 0; j < (int)(clock/2); j++) - // GraphBuffer[(i * clock) + j] = bit ^ 1; - // for (j = (int)(clock/2); j < clock; j++) - // GraphBuffer[(i * clock) + j] = bit; } RepaintGraphWindow(); @@ -800,8 +796,7 @@ int CmdFSKdemod(const char *Cmd) //old CmdFSKdemod needs updating PrintAndLog("actual data bits start at sample %d", maxPos); PrintAndLog("length %d/%d", highLen, lowLen); - uint8_t bits[46]; - bits[sizeof(bits)-1] = '\0'; + uint8_t bits[46] = {0x00}; // find bit pairs and manchester decode them for (i = 0; i < arraylen(bits) - 1; ++i) { @@ -1054,7 +1049,7 @@ int CmdHpf(const char *Cmd) int CmdSamples(const char *Cmd) { - uint8_t got[40000]; + uint8_t got[40000] = {0x00}; int n = strtol(Cmd, NULL, 0); if (n == 0) diff --git a/client/cmdlf.c b/client/cmdlf.c index 491fd082..729a3875 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -467,6 +467,9 @@ int CmdLFSnoop(const char *Cmd) PrintAndLog("usage 1: snoop"); PrintAndLog(" 2: snoop [trigger threshold]"); PrintAndLog(" 3: snoop [trigger threshold]"); + PrintAndLog(""); + PrintAndLog("Sample: lf snoop l 200"); + PrintAndLog(" : lf snoop 95 200"); return 0; } diff --git a/client/graph.c b/client/graph.c index 6362c8fe..0f998fe1 100644 --- a/client/graph.c +++ b/client/graph.c @@ -9,6 +9,7 @@ //----------------------------------------------------------------------------- #include +#include #include #include "ui.h" #include "graph.h" @@ -50,7 +51,11 @@ int ClearGraph(int redraw) void setGraphBuf(uint8_t *buff, size_t size) { - int i=0; + if ( buff == NULL ) return; + + uint16_t i = 0; + if ( size > MAX_GRAPH_TRACE_LEN ) + size = MAX_GRAPH_TRACE_LEN; ClearGraph(0); for (; i < size; ++i){ GraphBuffer[i]=buff[i]-128; @@ -61,6 +66,8 @@ void setGraphBuf(uint8_t *buff, size_t size) } size_t getFromGraphBuf(uint8_t *buff) { + if ( buff == NULL ) return -1; + uint32_t i; for (i=0;i127) GraphBuffer[i]=127; //trim @@ -82,16 +89,50 @@ int GetClock(const char *str, int peak, int verbose) { uint8_t grph[MAX_GRAPH_TRACE_LEN]={0}; size_t size = getFromGraphBuf(grph); + if ( size < 0 ) { + PrintAndLog("Failed to copy from graphbuffer"); + return -1; + } clock = DetectASKClock(grph,size,0); // Only print this message if we're not looping something if (!verbose){ PrintAndLog("Auto-detected clock rate: %d", clock); } - } - return clock; } +// A simple test to see if there is any data inside Graphbuffer. +bool HasGraphData(){ + + if ( GraphTraceLen <= 0) { + PrintAndLog("No data available, try reading something first"); + return false; + } + return true; +} + +// Detect high and lows in Grapbuffer. +// Only loops the first 256 values. +void DetectHighLowInGraph(int *high, int *low, bool addFuzz) { + + uint8_t loopMax = 255; + if ( loopMax > GraphTraceLen) + loopMax = GraphTraceLen; + + for (uint8_t i = 0; i < loopMax; ++i) { + if (GraphBuffer[i] > *high) + *high = GraphBuffer[i]; + else if (GraphBuffer[i] < *low) + *low = GraphBuffer[i]; + } + + //12% fuzz in case highs and lows aren't clipped + if (addFuzz) { + *high = (int)(*high * .88); + *low = (int)(*low * .88); + } +} + int GetNRZpskClock(const char *str, int peak, int verbose) { int clock; @@ -111,4 +152,4 @@ int GetNRZpskClock(const char *str, int peak, int verbose) } } return clock; -} +} \ No newline at end of file diff --git a/client/graph.h b/client/graph.h index 1abeeb25..fe35d4f1 100644 --- a/client/graph.h +++ b/client/graph.h @@ -20,8 +20,10 @@ int GetClock(const char *str, int peak, int verbose); int GetNRZpskClock(const char *str, int peak, int verbose); void setGraphBuf(uint8_t *buff, size_t size); +bool HasGraphData(); +void DetectHighLowInGraph(int *high, int *low, bool addFuzz); + #define MAX_GRAPH_TRACE_LEN (1024*128) extern int GraphBuffer[MAX_GRAPH_TRACE_LEN]; extern int GraphTraceLen; - #endif -- 2.39.5 From df3e429d71bb4efdbc256e65ca1b09f7716ffc48 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 21 Jan 2015 21:24:37 +0100 Subject: [PATCH 16/16] minor fix for a help in "hf 14a snoop" --- client/cmdhf14a.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 593661a5..147e790e 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -480,7 +480,8 @@ int CmdHF14ASim(const char *Cmd) int CmdHF14ASnoop(const char *Cmd) { int param = 0; - if (param_getchar(Cmd, 0) == 'h') { + uint8_t ctmp = param_getchar(Cmd, 0) ; + if (ctmp == 'h' || ctmp == 'H') { PrintAndLog("It get data from the field and saves it into command buffer."); PrintAndLog("Buffer accessible from command hf list 14a."); PrintAndLog("Usage: hf 14a snoop [c][r]"); @@ -491,7 +492,7 @@ int CmdHF14ASnoop(const char *Cmd) { } for (int i = 0; i < 2; i++) { - char ctmp = param_getchar(Cmd, i); + ctmp = param_getchar(Cmd, i); if (ctmp == 'c' || ctmp == 'C') param |= 0x01; if (ctmp == 'r' || ctmp == 'R') param |= 0x02; } @@ -670,7 +671,7 @@ static command_t CommandTable[] = {"list", CmdHF14AList, 0, "[Deprecated] List ISO 14443a history"}, {"reader", CmdHF14AReader, 0, "Act like an ISO14443 Type A reader"}, {"cuids", CmdHF14ACUIDs, 0, " Collect n>0 ISO14443 Type A UIDs in one go"}, - {"sim", CmdHF14ASim, 0, " -- Fake ISO 14443a tag"}, + {"sim", CmdHF14ASim, 0, " -- Simulate ISO 14443a tag"}, {"snoop", CmdHF14ASnoop, 0, "Eavesdrop ISO 14443 Type A"}, {"raw", CmdHF14ACmdRaw, 0, "Send raw hex data to tag"}, {NULL, NULL, 0, NULL} -- 2.39.5