ESPHome  2022.5.1
pn532_mifare_classic.cpp
Go to the documentation of this file.
1 #include <memory>
2 
3 #include "pn532.h"
4 #include "esphome/core/log.h"
5 
6 namespace esphome {
7 namespace pn532 {
8 
9 static const char *const TAG = "pn532.mifare_classic";
10 
11 std::unique_ptr<nfc::NfcTag> PN532::read_mifare_classic_tag_(std::vector<uint8_t> &uid) {
12  uint8_t current_block = 4;
13  uint8_t message_start_index = 0;
14  uint32_t message_length = 0;
15 
16  if (this->auth_mifare_classic_block_(uid, current_block, nfc::MIFARE_CMD_AUTH_A, nfc::NDEF_KEY)) {
17  std::vector<uint8_t> data;
18  if (this->read_mifare_classic_block_(current_block, data)) {
19  if (!nfc::decode_mifare_classic_tlv(data, message_length, message_start_index)) {
20  return make_unique<nfc::NfcTag>(uid, nfc::ERROR);
21  }
22  } else {
23  ESP_LOGE(TAG, "Failed to read block %d", current_block);
24  return make_unique<nfc::NfcTag>(uid, nfc::MIFARE_CLASSIC);
25  }
26  } else {
27  ESP_LOGV(TAG, "Tag is not NDEF formatted");
28  return make_unique<nfc::NfcTag>(uid, nfc::MIFARE_CLASSIC);
29  }
30 
31  uint32_t index = 0;
32  uint32_t buffer_size = nfc::get_mifare_classic_buffer_size(message_length);
33  std::vector<uint8_t> buffer;
34 
35  while (index < buffer_size) {
36  if (nfc::mifare_classic_is_first_block(current_block)) {
37  if (!this->auth_mifare_classic_block_(uid, current_block, nfc::MIFARE_CMD_AUTH_A, nfc::NDEF_KEY)) {
38  ESP_LOGE(TAG, "Error, Block authentication failed for %d", current_block);
39  }
40  }
41  std::vector<uint8_t> block_data;
42  if (this->read_mifare_classic_block_(current_block, block_data)) {
43  buffer.insert(buffer.end(), block_data.begin(), block_data.end());
44  } else {
45  ESP_LOGE(TAG, "Error reading block %d", current_block);
46  }
47 
48  index += nfc::MIFARE_CLASSIC_BLOCK_SIZE;
49  current_block++;
50 
51  if (nfc::mifare_classic_is_trailer_block(current_block)) {
52  current_block++;
53  }
54  }
55  buffer.erase(buffer.begin(), buffer.begin() + message_start_index);
56  return make_unique<nfc::NfcTag>(uid, nfc::MIFARE_CLASSIC, buffer);
57 }
58 
59 bool PN532::read_mifare_classic_block_(uint8_t block_num, std::vector<uint8_t> &data) {
60  if (!this->write_command_({
61  PN532_COMMAND_INDATAEXCHANGE,
62  0x01, // One card
63  nfc::MIFARE_CMD_READ,
64  block_num,
65  })) {
66  return false;
67  }
68 
69  if (!this->read_response(PN532_COMMAND_INDATAEXCHANGE, data) || data[0] != 0x00) {
70  return false;
71  }
72  data.erase(data.begin());
73 
74  ESP_LOGVV(TAG, " Block %d: %s", block_num, nfc::format_bytes(data).c_str());
75  return true;
76 }
77 
78 bool PN532::auth_mifare_classic_block_(std::vector<uint8_t> &uid, uint8_t block_num, uint8_t key_num,
79  const uint8_t *key) {
80  std::vector<uint8_t> data({
81  PN532_COMMAND_INDATAEXCHANGE,
82  0x01, // One card
83  key_num, // Mifare Key slot
84  block_num, // Block number
85  });
86  data.insert(data.end(), key, key + 6);
87  data.insert(data.end(), uid.begin(), uid.end());
88  if (!this->write_command_(data)) {
89  ESP_LOGE(TAG, "Authentication failed - Block %d", block_num);
90  return false;
91  }
92 
93  std::vector<uint8_t> response;
94  if (!this->read_response(PN532_COMMAND_INDATAEXCHANGE, response) || response[0] != 0x00) {
95  ESP_LOGE(TAG, "Authentication failed - Block 0x%02x", block_num);
96  return false;
97  }
98 
99  return true;
100 }
101 
102 bool PN532::format_mifare_classic_mifare_(std::vector<uint8_t> &uid) {
103  std::vector<uint8_t> blank_buffer(
104  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
105  std::vector<uint8_t> trailer_buffer(
106  {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF});
107 
108  bool error = false;
109 
110  for (int block = 0; block < 64; block += 4) {
111  if (!this->auth_mifare_classic_block_(uid, block + 3, nfc::MIFARE_CMD_AUTH_B, nfc::DEFAULT_KEY)) {
112  continue;
113  }
114  if (block != 0) {
115  if (!this->write_mifare_classic_block_(block, blank_buffer)) {
116  ESP_LOGE(TAG, "Unable to write block %d", block);
117  error = true;
118  }
119  }
120  if (!this->write_mifare_classic_block_(block + 1, blank_buffer)) {
121  ESP_LOGE(TAG, "Unable to write block %d", block + 1);
122  error = true;
123  }
124  if (!this->write_mifare_classic_block_(block + 2, blank_buffer)) {
125  ESP_LOGE(TAG, "Unable to write block %d", block + 2);
126  error = true;
127  }
128  if (!this->write_mifare_classic_block_(block + 3, trailer_buffer)) {
129  ESP_LOGE(TAG, "Unable to write block %d", block + 3);
130  error = true;
131  }
132  }
133 
134  return !error;
135 }
136 
137 bool PN532::format_mifare_classic_ndef_(std::vector<uint8_t> &uid) {
138  std::vector<uint8_t> empty_ndef_message(
139  {0x03, 0x03, 0xD0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
140  std::vector<uint8_t> blank_block(
141  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
142  std::vector<uint8_t> block_1_data(
143  {0x14, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1});
144  std::vector<uint8_t> block_2_data(
145  {0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1});
146  std::vector<uint8_t> block_3_trailer(
147  {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77, 0x88, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF});
148  std::vector<uint8_t> ndef_trailer(
149  {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07, 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF});
150 
151  if (!this->auth_mifare_classic_block_(uid, 0, nfc::MIFARE_CMD_AUTH_B, nfc::DEFAULT_KEY)) {
152  ESP_LOGE(TAG, "Unable to authenticate block 0 for formatting!");
153  return false;
154  }
155  if (!this->write_mifare_classic_block_(1, block_1_data))
156  return false;
157  if (!this->write_mifare_classic_block_(2, block_2_data))
158  return false;
159  if (!this->write_mifare_classic_block_(3, block_3_trailer))
160  return false;
161 
162  ESP_LOGD(TAG, "Sector 0 formatted to NDEF");
163 
164  for (int block = 4; block < 64; block += 4) {
165  if (!this->auth_mifare_classic_block_(uid, block + 3, nfc::MIFARE_CMD_AUTH_B, nfc::DEFAULT_KEY)) {
166  return false;
167  }
168  if (block == 4) {
169  if (!this->write_mifare_classic_block_(block, empty_ndef_message))
170  ESP_LOGE(TAG, "Unable to write block %d", block);
171  } else {
172  if (!this->write_mifare_classic_block_(block, blank_block))
173  ESP_LOGE(TAG, "Unable to write block %d", block);
174  }
175  if (!this->write_mifare_classic_block_(block + 1, blank_block))
176  ESP_LOGE(TAG, "Unable to write block %d", block + 1);
177  if (!this->write_mifare_classic_block_(block + 2, blank_block))
178  ESP_LOGE(TAG, "Unable to write block %d", block + 2);
179  if (!this->write_mifare_classic_block_(block + 3, ndef_trailer))
180  ESP_LOGE(TAG, "Unable to write trailer block %d", block + 3);
181  }
182  return true;
183 }
184 
185 bool PN532::write_mifare_classic_block_(uint8_t block_num, std::vector<uint8_t> &write_data) {
186  std::vector<uint8_t> data({
187  PN532_COMMAND_INDATAEXCHANGE,
188  0x01, // One card
189  nfc::MIFARE_CMD_WRITE,
190  block_num,
191  });
192  data.insert(data.end(), write_data.begin(), write_data.end());
193  if (!this->write_command_(data)) {
194  ESP_LOGE(TAG, "Error writing block %d", block_num);
195  return false;
196  }
197 
198  std::vector<uint8_t> response;
199  if (!this->read_response(PN532_COMMAND_INDATAEXCHANGE, response)) {
200  ESP_LOGE(TAG, "Error writing block %d", block_num);
201  return false;
202  }
203 
204  return true;
205 }
206 
207 bool PN532::write_mifare_classic_tag_(std::vector<uint8_t> &uid, nfc::NdefMessage *message) {
208  auto encoded = message->encode();
209 
210  uint32_t message_length = encoded.size();
211  uint32_t buffer_length = nfc::get_mifare_classic_buffer_size(message_length);
212 
213  encoded.insert(encoded.begin(), 0x03);
214  if (message_length < 255) {
215  encoded.insert(encoded.begin() + 1, message_length);
216  } else {
217  encoded.insert(encoded.begin() + 1, 0xFF);
218  encoded.insert(encoded.begin() + 2, (message_length >> 8) & 0xFF);
219  encoded.insert(encoded.begin() + 3, message_length & 0xFF);
220  }
221  encoded.push_back(0xFE);
222 
223  encoded.resize(buffer_length, 0);
224 
225  uint32_t index = 0;
226  uint8_t current_block = 4;
227 
228  while (index < buffer_length) {
229  if (nfc::mifare_classic_is_first_block(current_block)) {
230  if (!this->auth_mifare_classic_block_(uid, current_block, nfc::MIFARE_CMD_AUTH_A, nfc::NDEF_KEY)) {
231  return false;
232  }
233  }
234 
235  std::vector<uint8_t> data(encoded.begin() + index, encoded.begin() + index + nfc::MIFARE_CLASSIC_BLOCK_SIZE);
236  if (!this->write_mifare_classic_block_(current_block, data)) {
237  return false;
238  }
239  index += nfc::MIFARE_CLASSIC_BLOCK_SIZE;
240  current_block++;
241 
242  if (nfc::mifare_classic_is_trailer_block(current_block)) {
243  // Skipping as cannot write to trailer
244  current_block++;
245  }
246  }
247  return true;
248 }
249 
250 } // namespace pn532
251 } // namespace esphome
bool format_mifare_classic_ndef_(std::vector< uint8_t > &uid)
virtual bool write_data(const std::vector< uint8_t > &data)=0
virtual bool read_response(uint8_t command, std::vector< uint8_t > &data)=0
uint32_t get_mifare_classic_buffer_size(uint32_t message_length)
Definition: nfc.cpp:78
bool mifare_classic_is_trailer_block(uint8_t block_num)
Definition: nfc.cpp:99
bool decode_mifare_classic_tlv(std::vector< uint8_t > &data, uint32_t &message_length, uint8_t &message_start_index)
Definition: nfc.cpp:55
bool write_mifare_classic_block_(uint8_t block_num, std::vector< uint8_t > &data)
bool format_mifare_classic_mifare_(std::vector< uint8_t > &uid)
bool auth_mifare_classic_block_(std::vector< uint8_t > &uid, uint8_t block_num, uint8_t key_num, const uint8_t *key)
std::vector< uint8_t > encode()
bool write_mifare_classic_tag_(std::vector< uint8_t > &uid, nfc::NdefMessage *message)
bool mifare_classic_is_first_block(uint8_t block_num)
Definition: nfc.cpp:91
Definition: a4988.cpp:4
std::unique_ptr< nfc::NfcTag > read_mifare_classic_tag_(std::vector< uint8_t > &uid)
bool write_command_(const std::vector< uint8_t > &data)
Definition: pn532.cpp:208
std::string format_bytes(std::vector< uint8_t > &bytes)
Definition: nfc.cpp:22
bool read_mifare_classic_block_(uint8_t block_num, std::vector< uint8_t > &data)