Generic library for working with PN532-like chips

Fork of PN532 by Seeed

Committer:
r4z0r7o3
Date:
Wed Feb 04 19:04:54 2015 +0000
Revision:
10:f959b305a571
Parent:
5:51f820fbd18a
Try multiple known auth. keys on classic.  Also fixed all debugging messages so they all end with newlines.

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 }