Generic library for working with PN532-like chips

Fork of PN532 by Seeed

Committer:
r4z0r7o3
Date:
Wed Feb 04 19:26:03 2015 +0000
Revision:
11:5b8afec8bee6
Parent:
10:f959b305a571
Fix missing space in tag print()

Who changed what in which revision?

UserRevisionLine numberNew contents of line
yihui 3:4189a10038e6 1 #include "MifareClassic.h"
yihui 3:4189a10038e6 2 #include "PN532_debug.h"
yihui 3:4189a10038e6 3
yihui 3:4189a10038e6 4 #define BLOCK_SIZE 16
yihui 3:4189a10038e6 5 #define LONG_TLV_SIZE 4
yihui 3:4189a10038e6 6 #define SHORT_TLV_SIZE 2
yihui 3:4189a10038e6 7
yihui 3:4189a10038e6 8 #define MIFARE_CLASSIC ("Mifare Classic")
yihui 3:4189a10038e6 9
r4z0r7o3 10:f959b305a571 10 const uint8_t keys_len = 9;
r4z0r7o3 10:f959b305a571 11 const uint8_t keys[keys_len][6] = {
r4z0r7o3 10:f959b305a571 12 { 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF },
r4z0r7o3 10:f959b305a571 13 { 0XD3, 0XF7, 0XD3, 0XF7, 0XD3, 0XF7 },
r4z0r7o3 10:f959b305a571 14 { 0XA0, 0XA1, 0XA2, 0XA3, 0XA4, 0XA5 },
r4z0r7o3 10:f959b305a571 15 { 0XB0, 0XB1, 0XB2, 0XB3, 0XB4, 0XB5 },
r4z0r7o3 10:f959b305a571 16 { 0X4D, 0X3A, 0X99, 0XC3, 0X51, 0XDD },
r4z0r7o3 10:f959b305a571 17 { 0X1A, 0X98, 0X2C, 0X7E, 0X45, 0X9A },
r4z0r7o3 10:f959b305a571 18 { 0XAA, 0XBB, 0XCC, 0XDD, 0XEE, 0XFF },
r4z0r7o3 10:f959b305a571 19 { 0X00, 0X00, 0X00, 0X00, 0X00, 0X00 },
r4z0r7o3 10:f959b305a571 20 { 0XAB, 0XCD, 0XEF, 0X12, 0X34, 0X56 },
r4z0r7o3 10:f959b305a571 21 };
r4z0r7o3 10:f959b305a571 22
yihui 3:4189a10038e6 23 MifareClassic::MifareClassic(PN532& nfcShield)
yihui 3:4189a10038e6 24 {
yihui 3:4189a10038e6 25 _nfcShield = &nfcShield;
yihui 3:4189a10038e6 26 }
yihui 3:4189a10038e6 27
yihui 3:4189a10038e6 28 MifareClassic::~MifareClassic()
yihui 3:4189a10038e6 29 {
yihui 3:4189a10038e6 30 }
yihui 3:4189a10038e6 31
yihui 3:4189a10038e6 32 NfcTag MifareClassic::read(uint8_t *uid, unsigned int uidLength)
yihui 3:4189a10038e6 33 {
yihui 3:4189a10038e6 34 int currentBlock = 4;
yihui 3:4189a10038e6 35 int messageStartIndex = 0;
yihui 3:4189a10038e6 36 int messageLength = 0;
yihui 3:4189a10038e6 37 uint8_t data[BLOCK_SIZE];
yihui 3:4189a10038e6 38
yihui 3:4189a10038e6 39 // read first block to get message length
r4z0r7o3 10:f959b305a571 40 int success = 0;
r4z0r7o3 10:f959b305a571 41 for (uint8_t i=0; i < keys_len; i++) {
r4z0r7o3 10:f959b305a571 42 success = _nfcShield->mifareclassic_AuthenticateBlock(uid, uidLength, currentBlock, 0, keys[i]);
r4z0r7o3 10:f959b305a571 43 if (success)
r4z0r7o3 10:f959b305a571 44 break;
r4z0r7o3 10:f959b305a571 45 }
r4z0r7o3 10:f959b305a571 46
yihui 3:4189a10038e6 47 if (success)
yihui 3:4189a10038e6 48 {
yihui 3:4189a10038e6 49 success = _nfcShield->mifareclassic_ReadDataBlock(currentBlock, data);
yihui 3:4189a10038e6 50 if (success)
yihui 3:4189a10038e6 51 {
yihui 3:4189a10038e6 52 if (!decodeTlv(data, messageLength, messageStartIndex)) {
yihui 3:4189a10038e6 53 return NfcTag(uid, uidLength, "ERROR"); // TODO should the error message go in NfcTag?
yihui 3:4189a10038e6 54 }
yihui 3:4189a10038e6 55 }
yihui 3:4189a10038e6 56 else
yihui 3:4189a10038e6 57 {
yihui 3:4189a10038e6 58 DMSG("Error. Failed read block ");
yihui 3:4189a10038e6 59 DMSG_INT(currentBlock);
r4z0r7o3 10:f959b305a571 60 DMSG("\n");
yihui 3:4189a10038e6 61 return NfcTag(uid, uidLength, MIFARE_CLASSIC);
yihui 3:4189a10038e6 62 }
yihui 3:4189a10038e6 63 }
yihui 3:4189a10038e6 64 else
yihui 3:4189a10038e6 65 {
r4z0r7o3 10:f959b305a571 66 DMSG("Tag is not NDEF formatted.\n");
yihui 3:4189a10038e6 67 // TODO set tag.isFormatted = false
yihui 3:4189a10038e6 68 return NfcTag(uid, uidLength, MIFARE_CLASSIC);
yihui 3:4189a10038e6 69 }
yihui 3:4189a10038e6 70
yihui 3:4189a10038e6 71 // this should be nested in the message length loop
yihui 3:4189a10038e6 72 int index = 0;
yihui 3:4189a10038e6 73 int bufferSize = getBufferSize(messageLength);
yihui 3:4189a10038e6 74 uint8_t buffer[bufferSize];
yihui 3:4189a10038e6 75
yihui 3:4189a10038e6 76 #ifdef MIFARE_CLASSIC_DEBUG
yihui 3:4189a10038e6 77 DMSG("Message Length ");
yihui 3:4189a10038e6 78 DMSG_INT(messageLength);
yihui 3:4189a10038e6 79 DMSG("Buffer Size ");
yihui 3:4189a10038e6 80 DMSG_INT(bufferSize);
r4z0r7o3 10:f959b305a571 81 DMSG("\n");
yihui 3:4189a10038e6 82 #endif
yihui 3:4189a10038e6 83
yihui 3:4189a10038e6 84 while (index < bufferSize)
yihui 3:4189a10038e6 85 {
yihui 3:4189a10038e6 86
yihui 3:4189a10038e6 87 // authenticate on every sector
yihui 3:4189a10038e6 88 if (_nfcShield->mifareclassic_IsFirstBlock(currentBlock))
yihui 3:4189a10038e6 89 {
r4z0r7o3 10:f959b305a571 90 int success = 0;
r4z0r7o3 10:f959b305a571 91 for (uint8_t i=0; i < keys_len; i++) {
r4z0r7o3 10:f959b305a571 92 success = _nfcShield->mifareclassic_AuthenticateBlock(uid, uidLength, currentBlock, 0, keys[i]);
r4z0r7o3 10:f959b305a571 93 if (success)
r4z0r7o3 10:f959b305a571 94 break;
r4z0r7o3 10:f959b305a571 95 }
r4z0r7o3 10:f959b305a571 96
yihui 3:4189a10038e6 97 if (!success)
yihui 3:4189a10038e6 98 {
yihui 3:4189a10038e6 99 DMSG("Error. Block Authentication failed for ");
yihui 3:4189a10038e6 100 DMSG_INT(currentBlock);
r4z0r7o3 10:f959b305a571 101 DMSG("\n");
yihui 3:4189a10038e6 102 // TODO error handling
yihui 3:4189a10038e6 103 }
yihui 3:4189a10038e6 104 }
yihui 3:4189a10038e6 105
yihui 3:4189a10038e6 106 // read the data
yihui 3:4189a10038e6 107 success = _nfcShield->mifareclassic_ReadDataBlock(currentBlock, &buffer[index]);
yihui 3:4189a10038e6 108 if (success)
yihui 3:4189a10038e6 109 {
yihui 3:4189a10038e6 110 #ifdef MIFARE_CLASSIC_DEBUG
yihui 3:4189a10038e6 111 DMSG("Block ");
yihui 3:4189a10038e6 112 DMSG_INT(currentBlock);
yihui 3:4189a10038e6 113 _nfcShield->PrintHexChar(&buffer[index], BLOCK_SIZE);
r4z0r7o3 10:f959b305a571 114 DMSG("\n");
yihui 3:4189a10038e6 115 #endif
yihui 3:4189a10038e6 116 }
yihui 3:4189a10038e6 117 else
yihui 3:4189a10038e6 118 {
yihui 3:4189a10038e6 119 DMSG("Read failed ");
yihui 3:4189a10038e6 120 DMSG_INT(currentBlock);
r4z0r7o3 10:f959b305a571 121 DMSG("\n");
yihui 3:4189a10038e6 122 // TODO handle errors here
yihui 3:4189a10038e6 123 }
yihui 3:4189a10038e6 124
yihui 3:4189a10038e6 125 index += BLOCK_SIZE;
yihui 3:4189a10038e6 126 currentBlock++;
yihui 3:4189a10038e6 127
yihui 3:4189a10038e6 128 // skip the trailer block
yihui 3:4189a10038e6 129 if (_nfcShield->mifareclassic_IsTrailerBlock(currentBlock))
yihui 3:4189a10038e6 130 {
yihui 3:4189a10038e6 131 #ifdef MIFARE_CLASSIC_DEBUG
yihui 3:4189a10038e6 132 DMSG("Skipping block ");
yihui 3:4189a10038e6 133 DMSG_INT(currentBlock);
r4z0r7o3 10:f959b305a571 134 DMSG("\n");
yihui 3:4189a10038e6 135 #endif
yihui 3:4189a10038e6 136 currentBlock++;
yihui 3:4189a10038e6 137 }
yihui 3:4189a10038e6 138 }
yihui 3:4189a10038e6 139
yihui 3:4189a10038e6 140 return NfcTag(uid, uidLength, MIFARE_CLASSIC, &buffer[messageStartIndex], messageLength);
yihui 3:4189a10038e6 141 }
yihui 3:4189a10038e6 142
yihui 3:4189a10038e6 143 int MifareClassic::getBufferSize(int messageLength)
yihui 3:4189a10038e6 144 {
yihui 3:4189a10038e6 145
yihui 3:4189a10038e6 146 int bufferSize = messageLength;
yihui 3:4189a10038e6 147
yihui 3:4189a10038e6 148 // TLV header is 2 or 4 uint8_ts, TLV terminator is 1 uint8_t.
yihui 3:4189a10038e6 149 if (messageLength < 0xFF)
yihui 3:4189a10038e6 150 {
yihui 3:4189a10038e6 151 bufferSize += SHORT_TLV_SIZE + 1;
yihui 3:4189a10038e6 152 }
yihui 3:4189a10038e6 153 else
yihui 3:4189a10038e6 154 {
yihui 3:4189a10038e6 155 bufferSize += LONG_TLV_SIZE + 1;
yihui 3:4189a10038e6 156 }
yihui 3:4189a10038e6 157
yihui 3:4189a10038e6 158 // bufferSize needs to be a multiple of BLOCK_SIZE
yihui 3:4189a10038e6 159 if (bufferSize % BLOCK_SIZE != 0)
yihui 3:4189a10038e6 160 {
yihui 3:4189a10038e6 161 bufferSize = ((bufferSize / BLOCK_SIZE) + 1) * BLOCK_SIZE;
yihui 3:4189a10038e6 162 }
yihui 3:4189a10038e6 163
yihui 3:4189a10038e6 164 return bufferSize;
yihui 3:4189a10038e6 165 }
yihui 3:4189a10038e6 166
yihui 3:4189a10038e6 167 // skip null tlvs (0x0) before the real message
yihui 3:4189a10038e6 168 // technically unlimited null tlvs, but we assume
yihui 3:4189a10038e6 169 // T & L of TLV in the first block we read
yihui 3:4189a10038e6 170 int MifareClassic::getNdefStartIndex(uint8_t *data)
yihui 3:4189a10038e6 171 {
yihui 3:4189a10038e6 172
yihui 3:4189a10038e6 173 for (int i = 0; i < BLOCK_SIZE; i++)
yihui 3:4189a10038e6 174 {
yihui 3:4189a10038e6 175 if (data[i] == 0x0)
yihui 3:4189a10038e6 176 {
yihui 3:4189a10038e6 177 // do nothing, skip
yihui 3:4189a10038e6 178 }
yihui 3:4189a10038e6 179 else if (data[i] == 0x3)
yihui 3:4189a10038e6 180 {
yihui 3:4189a10038e6 181 return i;
yihui 3:4189a10038e6 182 }
yihui 3:4189a10038e6 183 else
yihui 3:4189a10038e6 184 {
yihui 3:4189a10038e6 185 DMSG("Unknown TLV ");
yihui 3:4189a10038e6 186 DMSG_HEX(data[i]);
r4z0r7o3 10:f959b305a571 187 DMSG("\n");
yihui 3:4189a10038e6 188 return -2;
yihui 3:4189a10038e6 189 }
yihui 3:4189a10038e6 190 }
yihui 3:4189a10038e6 191
yihui 3:4189a10038e6 192 return -1;
yihui 3:4189a10038e6 193 }
yihui 3:4189a10038e6 194
yihui 3:4189a10038e6 195 // Decode the NDEF data length from the Mifare TLV
yihui 3:4189a10038e6 196 // Leading null TLVs (0x0) are skipped
yihui 3:4189a10038e6 197 // Assuming T & L of TLV will be in the first block
yihui 3:4189a10038e6 198 // messageLength and messageStartIndex written to the parameters
yihui 3:4189a10038e6 199 // success or failure status is returned
yihui 3:4189a10038e6 200 //
yihui 3:4189a10038e6 201 // { 0x3, LENGTH }
yihui 3:4189a10038e6 202 // { 0x3, 0xFF, LENGTH, LENGTH }
yihui 3:4189a10038e6 203 bool MifareClassic::decodeTlv(uint8_t *data, int &messageLength, int &messageStartIndex)
yihui 3:4189a10038e6 204 {
yihui 3:4189a10038e6 205 int i = getNdefStartIndex(data);
yihui 3:4189a10038e6 206
yihui 3:4189a10038e6 207 if (i < 0 || data[i] != 0x3)
yihui 3:4189a10038e6 208 {
r4z0r7o3 10:f959b305a571 209 DMSG("Error. Can't decode message length.\n");
yihui 3:4189a10038e6 210 return false;
yihui 3:4189a10038e6 211 }
yihui 3:4189a10038e6 212 else
yihui 3:4189a10038e6 213 {
yihui 3:4189a10038e6 214 if (data[i+1] == 0xFF)
yihui 3:4189a10038e6 215 {
yihui 3:4189a10038e6 216 messageLength = ((0xFF & data[i+2]) << 8) | (0xFF & data[i+3]);
yihui 3:4189a10038e6 217 messageStartIndex = i + LONG_TLV_SIZE;
yihui 3:4189a10038e6 218 }
yihui 3:4189a10038e6 219 else
yihui 3:4189a10038e6 220 {
yihui 3:4189a10038e6 221 messageLength = data[i+1];
yihui 3:4189a10038e6 222 messageStartIndex = i + SHORT_TLV_SIZE;
yihui 3:4189a10038e6 223 }
yihui 3:4189a10038e6 224 }
yihui 3:4189a10038e6 225
yihui 3:4189a10038e6 226 return true;
yihui 3:4189a10038e6 227 }
yihui 3:4189a10038e6 228
yihui 3:4189a10038e6 229 bool MifareClassic::write(NdefMessage& m, uint8_t * uid, unsigned int uidLength)
yihui 3:4189a10038e6 230 {
yihui 3:4189a10038e6 231
yihui 3:4189a10038e6 232 uint8_t encoded[m.getEncodedSize()];
yihui 3:4189a10038e6 233 m.encode(encoded);
yihui 3:4189a10038e6 234
yihui 3:4189a10038e6 235 uint8_t buffer[getBufferSize(sizeof(encoded))];
yihui 3:4189a10038e6 236 memset(buffer, 0, sizeof(buffer));
yihui 3:4189a10038e6 237
yihui 3:4189a10038e6 238 #ifdef MIFARE_CLASSIC_DEBUG
r4z0r7o3 10:f959b305a571 239 DMSG("sizeof(encoded) ");DMSG_INT(sizeof(encoded));
r4z0r7o3 10:f959b305a571 240 DMSG("sizeof(buffer) ");DMSG_INT(sizeof(buffer));
r4z0r7o3 10:f959b305a571 241 DMSG("\n");
yihui 3:4189a10038e6 242 #endif
yihui 3:4189a10038e6 243
yihui 3:4189a10038e6 244 if (sizeof(encoded) < 0xFF)
yihui 3:4189a10038e6 245 {
yihui 3:4189a10038e6 246 buffer[0] = 0x3;
yihui 3:4189a10038e6 247 buffer[1] = sizeof(encoded);
yihui 3:4189a10038e6 248 memcpy(&buffer[2], encoded, sizeof(encoded));
yihui 3:4189a10038e6 249 buffer[2+sizeof(encoded)] = 0xFE; // terminator
yihui 3:4189a10038e6 250 }
yihui 3:4189a10038e6 251 else
yihui 3:4189a10038e6 252 {
yihui 3:4189a10038e6 253 buffer[0] = 0x3;
yihui 3:4189a10038e6 254 buffer[1] = 0xFF;
yihui 3:4189a10038e6 255 buffer[2] = ((sizeof(encoded) >> 8) & 0xFF);
yihui 3:4189a10038e6 256 buffer[3] = (sizeof(encoded) & 0xFF);
yihui 3:4189a10038e6 257 memcpy(&buffer[4], encoded, sizeof(encoded));
yihui 3:4189a10038e6 258 buffer[4+sizeof(encoded)] = 0xFE; // terminator
yihui 3:4189a10038e6 259 }
yihui 3:4189a10038e6 260
yihui 3:4189a10038e6 261 // Write to tag
yihui 3:4189a10038e6 262 int index = 0;
yihui 3:4189a10038e6 263 int currentBlock = 4;
yihui 3:4189a10038e6 264
yihui 3:4189a10038e6 265 while (index < sizeof(buffer))
yihui 3:4189a10038e6 266 {
yihui 3:4189a10038e6 267
yihui 3:4189a10038e6 268 if (_nfcShield->mifareclassic_IsFirstBlock(currentBlock))
yihui 3:4189a10038e6 269 {
r4z0r7o3 10:f959b305a571 270 int success = 0;
r4z0r7o3 10:f959b305a571 271 for (uint8_t i=0; i < keys_len; i++) {
r4z0r7o3 10:f959b305a571 272 success = _nfcShield->mifareclassic_AuthenticateBlock(uid, uidLength, currentBlock, 0, keys[i]);
r4z0r7o3 10:f959b305a571 273 if (success)
r4z0r7o3 10:f959b305a571 274 break;
r4z0r7o3 10:f959b305a571 275 }
yihui 3:4189a10038e6 276 if (!success)
yihui 3:4189a10038e6 277 {
yihui 3:4189a10038e6 278 DMSG("Error. Block Authentication failed for ");DMSG_INT(currentBlock);
r4z0r7o3 10:f959b305a571 279 DMSG("\n");
yihui 3:4189a10038e6 280 return false;
yihui 3:4189a10038e6 281 }
yihui 3:4189a10038e6 282 }
yihui 3:4189a10038e6 283 int write_success = _nfcShield->mifareclassic_WriteDataBlock (currentBlock, &buffer[index]);
yihui 3:4189a10038e6 284 if (write_success)
yihui 3:4189a10038e6 285 {
yihui 3:4189a10038e6 286 #ifdef MIFARE_CLASSIC_DEBUG
r4z0r7o3 10:f959b305a571 287 DMSG("Wrote block ");DMSG_INT(currentBlock);DMSG(" - ");
yihui 3:4189a10038e6 288 _nfcShield->PrintHexChar(&buffer[index], BLOCK_SIZE);
r4z0r7o3 10:f959b305a571 289 DMSG("\n");
yihui 3:4189a10038e6 290 #endif
yihui 3:4189a10038e6 291 }
yihui 3:4189a10038e6 292 else
yihui 3:4189a10038e6 293 {
yihui 3:4189a10038e6 294 DMSG("Write failed ");DMSG_INT(currentBlock);
r4z0r7o3 10:f959b305a571 295 DMSG("\n");
yihui 3:4189a10038e6 296 return false;
yihui 3:4189a10038e6 297 }
yihui 3:4189a10038e6 298 index += BLOCK_SIZE;
yihui 3:4189a10038e6 299 currentBlock++;
yihui 3:4189a10038e6 300
yihui 3:4189a10038e6 301 if (_nfcShield->mifareclassic_IsTrailerBlock(currentBlock))
yihui 3:4189a10038e6 302 {
yihui 3:4189a10038e6 303 // can't write to trailer block
yihui 3:4189a10038e6 304 #ifdef MIFARE_CLASSIC_DEBUG
r4z0r7o3 10:f959b305a571 305 DMSG("Skipping block ");DMSG_INT(currentBlock);
r4z0r7o3 10:f959b305a571 306 DMSG("\n");
yihui 3:4189a10038e6 307 #endif
yihui 3:4189a10038e6 308 currentBlock++;
yihui 3:4189a10038e6 309 }
yihui 3:4189a10038e6 310
yihui 3:4189a10038e6 311 }
yihui 3:4189a10038e6 312
yihui 3:4189a10038e6 313 return true;
yihui 3:4189a10038e6 314 }