PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

MFRC522Hack.cpp 6.4KB

il y a 4 ans
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. #include "MFRC522Hack.h"
  2. /**
  3. * Performs the "magic sequence" needed to get Chinese UID changeable
  4. * Mifare cards to allow writing to sector 0, where the card UID is stored.
  5. *
  6. * Note that you do not need to have selected the card through REQA or WUPA,
  7. * this sequence works immediately when the card is in the reader vicinity.
  8. * This means you can use this method even on "bricked" cards that your reader does
  9. * not recognise anymore (see MFRC522Hack::MIFARE_UnbrickUidSector).
  10. *
  11. * Of course with non-bricked devices, you're free to select them before calling this function.
  12. */
  13. bool MFRC522Hack::MIFARE_OpenUidBackdoor(const bool logErrors) const {
  14. // Magic sequence:
  15. // > 50 00 57 CD (HALT + CRC)
  16. // > 40 (7 bits only)
  17. // < A (4 bits only)
  18. // > 43
  19. // < A (4 bits only)
  20. // Then you can write to sector 0 without authenticating
  21. _device->PICC_HaltA(); // 50 00 57 CD
  22. byte cmd = 0x40;
  23. byte validBits = 7; /* Our command is only 7 bits. After receiving card response,
  24. this will contain amount of valid response bits. */
  25. byte response[32]; // Card's response is written here
  26. byte received;
  27. MFRC522::StatusCode status = _device->PCD_TransceiveData(&cmd, (byte) 1, response, &received, &validBits, (byte) 0,
  28. false); // 40
  29. if (status != MFRC522::STATUS_OK) {
  30. if (logErrors) {
  31. Serial.println(
  32. F("Card did not respond to 0x40 after HALT command. Are you sure it is a UID changeable one?"));
  33. Serial.print(F("Error name: "));
  34. Serial.println(MFRC522Debug::GetStatusCodeName(status));
  35. }
  36. return false;
  37. }
  38. if (received != 1 || response[0] != 0x0A) {
  39. if (logErrors) {
  40. Serial.print(F("Got bad response on backdoor 0x40 command: "));
  41. Serial.print(response[0], HEX);
  42. Serial.print(F(" ("));
  43. Serial.print(validBits);
  44. Serial.print(F(" valid bits)\r\n"));
  45. }
  46. return false;
  47. }
  48. cmd = 0x43;
  49. validBits = 8;
  50. status = _device->PCD_TransceiveData(&cmd, (byte) 1, response, &received, &validBits, (byte) 0, false); // 43
  51. if (status != MFRC522::STATUS_OK) {
  52. if (logErrors) {
  53. Serial.println(F("Error in communication at command 0x43, after successfully executing 0x40"));
  54. Serial.print(F("Error name: "));
  55. Serial.println(MFRC522Debug::GetStatusCodeName(status));
  56. }
  57. return false;
  58. }
  59. if (received != 1 || response[0] != 0x0A) {
  60. if (logErrors) {
  61. Serial.print(F("Got bad response on backdoor 0x43 command: "));
  62. Serial.print(response[0], HEX);
  63. Serial.print(F(" ("));
  64. Serial.print(validBits);
  65. Serial.print(F(" valid bits)\r\n"));
  66. }
  67. return false;
  68. }
  69. // You can now write to sector 0 without authenticating!
  70. return true;
  71. } // End MIFARE_OpenUidBackdoor()
  72. /**
  73. * Reads entire block 0, including all manufacturer data, and overwrites
  74. * that block with the new UID, a freshly calculated BCC, and the original
  75. * manufacturer data.
  76. *
  77. * It assumes a default KEY A of 0xFFFFFFFFFFFF.
  78. * Make sure to have selected the card before this function is called.
  79. */
  80. bool MFRC522Hack::MIFARE_SetUid(const byte *newUid, const byte uidSize, const bool logErrors) const {
  81. // UID + BCC byte can not be larger than 16 together
  82. if (!newUid || !uidSize || uidSize > 15) {
  83. if (logErrors) {
  84. Serial.println(F("New UID buffer empty, size 0, or size > 15 given"));
  85. }
  86. return false;
  87. }
  88. // Authenticate for reading
  89. MFRC522::MIFARE_Key key = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
  90. MFRC522::StatusCode status = _device->PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, (byte) 1, &key, &(_device->uid));
  91. if (status != MFRC522::STATUS_OK) {
  92. if (status == MFRC522::STATUS_TIMEOUT) {
  93. // We get a read timeout if no card is selected yet, so let's select one
  94. // Wake the card up again if sleeping
  95. // byte atqa_answer[2];
  96. // byte atqa_size = 2;
  97. // PICC_WakeupA(atqa_answer, &atqa_size);
  98. if (!_device->PICC_IsNewCardPresent() || !_device->PICC_ReadCardSerial()) {
  99. Serial.println(F("No card was previously selected, and none are available. Failed to set UID."));
  100. return false;
  101. }
  102. status = _device->PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, (byte) 1, &key, &(_device->uid));
  103. if (status != MFRC522::STATUS_OK) {
  104. // We tried, time to give up
  105. if (logErrors) {
  106. Serial.println(F("Failed to authenticate to card for reading, could not set UID: "));
  107. Serial.println(MFRC522Debug::GetStatusCodeName(status));
  108. }
  109. return false;
  110. }
  111. } else {
  112. if (logErrors) {
  113. Serial.print(F("PCD_Authenticate() failed: "));
  114. Serial.println(MFRC522Debug::GetStatusCodeName(status));
  115. }
  116. return false;
  117. }
  118. }
  119. // Read block 0
  120. byte block0_buffer[18];
  121. byte byteCount = sizeof(block0_buffer);
  122. status = _device->MIFARE_Read((byte) 0, block0_buffer, &byteCount);
  123. if (status != MFRC522::STATUS_OK) {
  124. if (logErrors) {
  125. Serial.print(F("MIFARE_Read() failed: "));
  126. Serial.println(MFRC522Debug::GetStatusCodeName(status));
  127. Serial.println(F("Are you sure your KEY A for sector 0 is 0xFFFFFFFFFFFF?"));
  128. }
  129. return false;
  130. }
  131. // Write new UID to the data we just read, and calculate BCC byte
  132. byte bcc = 0;
  133. for (uint8_t i = 0; i < uidSize; i++) {
  134. block0_buffer[i] = newUid[i];
  135. bcc ^= newUid[i];
  136. }
  137. // Write BCC byte to buffer
  138. block0_buffer[uidSize] = bcc;
  139. // Stop encrypted traffic so we can send raw bytes
  140. _device->PCD_StopCrypto1();
  141. // Activate UID backdoor
  142. if (!MIFARE_OpenUidBackdoor(logErrors)) {
  143. if (logErrors) {
  144. Serial.println(F("Activating the UID backdoor failed."));
  145. }
  146. return false;
  147. }
  148. // Write modified block 0 back to card
  149. status = _device->MIFARE_Write((byte) 0, block0_buffer, (byte) 16);
  150. if (status != MFRC522::STATUS_OK) {
  151. if (logErrors) {
  152. Serial.print(F("MIFARE_Write() failed: "));
  153. Serial.println(MFRC522Debug::GetStatusCodeName(status));
  154. }
  155. return false;
  156. }
  157. // Wake the card up again
  158. byte atqa_answer[2];
  159. byte atqa_size = 2;
  160. _device->PICC_WakeupA(atqa_answer, &atqa_size);
  161. return true;
  162. }
  163. /**
  164. * Resets entire sector 0 to zeroes, so the card can be read again by readers.
  165. */
  166. bool MFRC522Hack::MIFARE_UnbrickUidSector(const bool logErrors) const {
  167. MIFARE_OpenUidBackdoor(logErrors);
  168. byte block0_buffer[] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  169. 0x00};
  170. // Write modified block 0 back to card
  171. MFRC522::StatusCode status = _device->MIFARE_Write((byte) 0, block0_buffer, (byte) 16);
  172. if (status != MFRC522::STATUS_OK) {
  173. if (logErrors) {
  174. Serial.print(F("MIFARE_Write() failed: "));
  175. Serial.println(MFRC522Debug::GetStatusCodeName(status));
  176. }
  177. return false;
  178. }
  179. return true;
  180. }