9 static const char *
const TAG =
"pn7150.mifare_classic";
12 uint8_t current_block = 4;
13 uint8_t message_start_index = 0;
14 uint32_t message_length = 0;
17 ESP_LOGE(TAG,
"Tag auth failed while attempting to read tag data");
18 return nfc::STATUS_FAILED;
20 std::vector<uint8_t> data;
24 return nfc::STATUS_FAILED;
27 ESP_LOGE(TAG,
"Failed to read block %u", current_block);
28 return nfc::STATUS_FAILED;
33 std::vector<uint8_t> buffer;
35 while (index < buffer_size) {
38 ESP_LOGE(TAG,
"Block authentication failed for %u", current_block);
39 return nfc::STATUS_FAILED;
42 std::vector<uint8_t> block_data;
44 ESP_LOGE(TAG,
"Error reading block %u", current_block);
45 return nfc::STATUS_FAILED;
47 buffer.insert(buffer.end(), block_data.begin(), block_data.end());
50 index += nfc::MIFARE_CLASSIC_BLOCK_SIZE;
58 if (buffer.begin() + message_start_index < buffer.end()) {
59 buffer.erase(buffer.begin(), buffer.begin() + message_start_index);
61 return nfc::STATUS_FAILED;
66 return nfc::STATUS_OK;
71 nfc::NciMessage tx(nfc::NCI_PKT_MT_DATA, {XCHG_DATA_OID, nfc::MIFARE_CMD_READ, block_num});
73 ESP_LOGVV(TAG,
"Read XCHG_DATA_REQ: %s",
nfc::format_bytes(tx.get_message()).c_str());
75 ESP_LOGE(TAG,
"Timeout reading tag data");
76 return nfc::STATUS_FAILED;
81 ESP_LOGE(TAG,
"MFC read block failed - block 0x%02x", block_num);
83 return nfc::STATUS_FAILED;
89 return nfc::STATUS_OK;
97 case nfc::MIFARE_CMD_AUTH_A:
98 tx.
get_message().back() = MFC_AUTHENTICATE_PARAM_KS_A;
101 case nfc::MIFARE_CMD_AUTH_B:
102 tx.get_message().back() = MFC_AUTHENTICATE_PARAM_KS_B;
109 if (key !=
nullptr) {
110 tx.get_message().back() |= MFC_AUTHENTICATE_PARAM_EMBED_KEY;
111 tx.get_message().insert(tx.get_message().end(), key, key + 6);
114 ESP_LOGVV(TAG,
"MFC_AUTHENTICATE_REQ: %s",
nfc::format_bytes(tx.get_message()).c_str());
116 ESP_LOGE(TAG,
"Sending MFC_AUTHENTICATE_REQ failed");
117 return nfc::STATUS_FAILED;
121 ESP_LOGE(TAG,
"MFC authentication failed - block 0x%02x", block_num);
123 return nfc::STATUS_FAILED;
126 ESP_LOGV(TAG,
"MFC block %u authentication succeeded", block_num);
127 return nfc::STATUS_OK;
131 const uint8_t first_high_block = nfc::MIFARE_CLASSIC_BLOCKS_PER_SECT_LOW * nfc::MIFARE_CLASSIC_16BLOCK_SECT_START;
132 if (block_num >= first_high_block) {
133 return ((block_num - first_high_block) / nfc::MIFARE_CLASSIC_BLOCKS_PER_SECT_HIGH) +
134 nfc::MIFARE_CLASSIC_16BLOCK_SECT_START;
136 return block_num / nfc::MIFARE_CLASSIC_BLOCKS_PER_SECT_LOW;
140 std::vector<uint8_t> blank_buffer(
141 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
142 std::vector<uint8_t> trailer_buffer(
143 {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF});
145 auto status = nfc::STATUS_OK;
147 for (
int block = 0; block < 64; block += 4) {
153 ESP_LOGE(TAG,
"Unable to write block %u", block);
154 status = nfc::STATUS_FAILED;
158 ESP_LOGE(TAG,
"Unable to write block %u", block + 1);
159 status = nfc::STATUS_FAILED;
162 ESP_LOGE(TAG,
"Unable to write block %u", block + 2);
163 status = nfc::STATUS_FAILED;
166 ESP_LOGE(TAG,
"Unable to write block %u", block + 3);
167 status = nfc::STATUS_FAILED;
175 std::vector<uint8_t> empty_ndef_message(
176 {0x03, 0x03, 0xD0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
177 std::vector<uint8_t> blank_block(
178 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
179 std::vector<uint8_t> block_1_data(
180 {0x14, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1});
181 std::vector<uint8_t> block_2_data(
182 {0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1});
183 std::vector<uint8_t> block_3_trailer(
184 {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77, 0x88, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF});
185 std::vector<uint8_t> ndef_trailer(
186 {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07, 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF});
189 ESP_LOGE(TAG,
"Unable to authenticate block 0 for formatting");
190 return nfc::STATUS_FAILED;
193 return nfc::STATUS_FAILED;
196 return nfc::STATUS_FAILED;
199 return nfc::STATUS_FAILED;
202 ESP_LOGD(TAG,
"Sector 0 formatted with NDEF");
204 auto status = nfc::STATUS_OK;
206 for (
int block = 4; block < 64; block += 4) {
208 return nfc::STATUS_FAILED;
212 ESP_LOGE(TAG,
"Unable to write block %u", block);
213 status = nfc::STATUS_FAILED;
217 ESP_LOGE(TAG,
"Unable to write block %u", block);
218 status = nfc::STATUS_FAILED;
222 ESP_LOGE(TAG,
"Unable to write block %u", block + 1);
223 status = nfc::STATUS_FAILED;
226 ESP_LOGE(TAG,
"Unable to write block %u", block + 2);
227 status = nfc::STATUS_FAILED;
230 ESP_LOGE(TAG,
"Unable to write trailer block %u", block + 3);
231 status = nfc::STATUS_FAILED;
239 nfc::NciMessage tx(nfc::NCI_PKT_MT_DATA, {XCHG_DATA_OID, nfc::MIFARE_CMD_WRITE, block_num});
241 ESP_LOGVV(TAG,
"Write XCHG_DATA_REQ 1: %s",
nfc::format_bytes(tx.get_message()).c_str());
243 ESP_LOGE(TAG,
"Sending XCHG_DATA_REQ failed");
244 return nfc::STATUS_FAILED;
247 tx.set_payload({XCHG_DATA_OID});
248 tx.get_message().insert(tx.get_message().end(), write_data.begin(), write_data.end());
250 ESP_LOGVV(TAG,
"Write XCHG_DATA_REQ 2: %s",
nfc::format_bytes(tx.get_message()).c_str());
251 if (this->
transceive_(tx, rx, NFCC_TAG_WRITE_TIMEOUT) != nfc::STATUS_OK) {
252 ESP_LOGE(TAG,
"MFC XCHG_DATA timed out waiting for XCHG_DATA_RSP during block write");
253 return nfc::STATUS_FAILED;
258 ESP_LOGE(TAG,
"MFC write block failed - block 0x%02x", block_num);
260 return nfc::STATUS_FAILED;
263 return nfc::STATUS_OK;
267 auto encoded = message->encode();
269 uint32_t message_length = encoded.size();
272 encoded.insert(encoded.begin(), 0x03);
273 if (message_length < 255) {
274 encoded.insert(encoded.begin() + 1, message_length);
276 encoded.insert(encoded.begin() + 1, 0xFF);
277 encoded.insert(encoded.begin() + 2, (message_length >> 8) & 0xFF);
278 encoded.insert(encoded.begin() + 3, message_length & 0xFF);
280 encoded.push_back(0xFE);
282 encoded.resize(buffer_length, 0);
285 uint8_t current_block = 4;
287 while (index < buffer_length) {
290 return nfc::STATUS_FAILED;
294 std::vector<uint8_t> data(encoded.begin() + index, encoded.begin() + index + nfc::MIFARE_CLASSIC_BLOCK_SIZE);
296 return nfc::STATUS_FAILED;
298 index += nfc::MIFARE_CLASSIC_BLOCK_SIZE;
306 return nfc::STATUS_OK;
311 nfc::NciMessage tx(nfc::NCI_PKT_MT_DATA, {XCHG_DATA_OID, nfc::MIFARE_CMD_HALT, 0});
313 ESP_LOGVV(TAG,
"Halt XCHG_DATA_REQ: %s",
nfc::format_bytes(tx.get_message()).c_str());
314 if (this->
transceive_(tx, rx, NFCC_TAG_WRITE_TIMEOUT) != nfc::STATUS_OK) {
315 ESP_LOGE(TAG,
"Sending halt XCHG_DATA_REQ failed");
316 return nfc::STATUS_FAILED;
318 return nfc::STATUS_OK;
uint32_t get_mifare_classic_buffer_size(uint32_t message_length)
bool mifare_classic_is_trailer_block(uint8_t block_num)
uint8_t read_mifare_classic_block_(uint8_t block_num, std::vector< uint8_t > &data)
void set_ndef_message(std::unique_ptr< NdefMessage > ndef_message)
bool decode_mifare_classic_tlv(std::vector< uint8_t > &data, uint32_t &message_length, uint8_t &message_start_index)
uint8_t format_mifare_classic_ndef_()
uint8_t sect_to_auth_(uint8_t block_num)
bool message_type_is(uint8_t message_type) const
uint8_t transceive_(nfc::NciMessage &tx, nfc::NciMessage &rx, uint16_t timeout=NFCC_DEFAULT_TIMEOUT, bool expect_notification=true)
uint8_t format_mifare_classic_mifare_()
std::vector< uint8_t > & get_message()
bool simple_status_response_is(uint8_t response) const
bool mifare_classic_is_first_block(uint8_t block_num)
uint8_t read_mifare_classic_tag_(nfc::NfcTag &tag)
uint8_t write_mifare_classic_block_(uint8_t block_num, std::vector< uint8_t > &data)
bool message_length_is(uint8_t message_length, bool recompute=false)
Implementation of SPI Controller mode.
uint8_t write_mifare_classic_tag_(const std::shared_ptr< nfc::NdefMessage > &message)
uint8_t auth_mifare_classic_block_(uint8_t block_num, uint8_t key_num, const uint8_t *key)
std::string format_bytes(std::vector< uint8_t > &bytes)
uint8_t halt_mifare_classic_tag_()