MifareClassic.java revision 734e9b0c73483fdaa582c21dedc24107b1fe8838
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.nfc.tech; 18 19import android.nfc.Tag; 20import android.nfc.TagLostException; 21import android.os.RemoteException; 22 23import java.io.IOException; 24import java.nio.ByteBuffer; 25import java.nio.ByteOrder; 26 27/** 28 * Provides access to MIFARE Classic properties and I/O operations on a {@link Tag}. 29 * 30 * <p>Acquire a {@link MifareClassic} object using {@link #get}. 31 * 32 * <p>MIFARE Classic is also known as MIFARE Standard. 33 * <p>MIFARE Classic tags are divided into sectors, and each sector is sub-divided into 34 * blocks. Block size is always 16 bytes ({@link #BLOCK_SIZE}. Sector size varies. 35 * <ul> 36 * <li>MIFARE Classic Mini are 320 bytes ({@link #SIZE_MINI}), with 5 sectors each of 4 blocks. 37 * <li>MIFARE Classic 1k are 1024 bytes ({@link #SIZE_1K}), with 16 sectors each of 4 blocks. 38 * <li>MIFARE Classic 2k are 2048 bytes ({@link #SIZE_2K}), with 32 sectors each of 4 blocks. 39 * <li>MIFARE Classic 4k} are 4096 bytes ({@link #SIZE_4K}). The first 32 sectors contain 4 blocks 40 * and the last 8 sectors contain 16 blocks. 41 * </ul> 42 * 43 * <p>MIFARE Classic tags require authentication on a per-sector basis before any 44 * other I/O operations on that sector can be performed. There are two keys per sector, 45 * and ACL bits determine what I/O operations are allowed on that sector after 46 * authenticating with a key. {@see #authenticateSectorWithKeyA} and 47 * {@see #authenticateSectorWithKeyB}. 48 * 49 * <p>Three well-known authentication keys are defined in this class: 50 * {@link #KEY_DEFAULT}, {@link #KEY_MIFARE_APPLICATION_DIRECTORY}, 51 * {@link #KEY_NFC_FORUM}. 52 * <ul> 53 * <li>{@link #KEY_DEFAULT} is the default factory key for MIFARE Classic. 54 * <li>{@link #KEY_MIFARE_APPLICATION_DIRECTORY} is the well-known key for 55 * MIFARE Classic cards that have been formatted according to the 56 * MIFARE Application Directory (MAD) specification. 57 * <li>{@link #KEY_NFC_FORUM} is the well-known key for MIFARE Classic cards that 58 * have been formatted according to the NXP specification for NDEF on MIFARE Classic. 59 * 60 * <p>Implementation of this class on a Android NFC device is optional. 61 * If it is not implemented, then 62 * {@link MifareClassic} will never be enumerated in {@link Tag#getTechList}. 63 * If it is enumerated, then all {@link MifareClassic} I/O operations will be supported, 64 * and {@link Ndef#MIFARE_CLASSIC} NDEF tags will also be supported. In either case, 65 * {@link NfcA} will also be enumerated on the tag, because all MIFARE Classic tags are also 66 * {@link NfcA}. 67 * 68 * <p class="note"><strong>Note:</strong> Methods that perform I/O operations 69 * require the {@link android.Manifest.permission#NFC} permission. 70 */ 71public final class MifareClassic extends BasicTagTechnology { 72 /** 73 * The default factory key. 74 */ 75 public static final byte[] KEY_DEFAULT = 76 {(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF}; 77 /** 78 * The well-known key for tags formatted according to the 79 * MIFARE Application Directory (MAD) specification. 80 */ 81 public static final byte[] KEY_MIFARE_APPLICATION_DIRECTORY = 82 {(byte)0xA0,(byte)0xA1,(byte)0xA2,(byte)0xA3,(byte)0xA4,(byte)0xA5}; 83 /** 84 * The well-known key for tags formatted according to the 85 * NDEF on MIFARE Classic specification. 86 */ 87 public static final byte[] KEY_NFC_FORUM = 88 {(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7}; 89 90 /** A MIFARE Classic compatible card of unknown type */ 91 public static final int TYPE_UNKNOWN = -1; 92 /** A MIFARE Classic tag */ 93 public static final int TYPE_CLASSIC = 0; 94 /** A MIFARE Plus tag */ 95 public static final int TYPE_PLUS = 1; 96 /** A MIFARE Pro tag */ 97 public static final int TYPE_PRO = 2; 98 99 /** Tag contains 16 sectors, each with 4 blocks. */ 100 public static final int SIZE_1K = 1024; 101 /** Tag contains 32 sectors, each with 4 blocks. */ 102 public static final int SIZE_2K = 2048; 103 /** 104 * Tag contains 40 sectors. The first 32 sectors contain 4 blocks and the last 8 sectors 105 * contain 16 blocks. 106 */ 107 public static final int SIZE_4K = 4096; 108 /** Tag contains 5 sectors, each with 4 blocks. */ 109 public static final int SIZE_MINI = 320; 110 111 /** Size of a MIFARE Classic block (in bytes) */ 112 public static final int BLOCK_SIZE = 16; 113 114 private static final int MAX_BLOCK_COUNT = 256; 115 private static final int MAX_SECTOR_COUNT = 40; 116 117 private boolean mIsEmulated; 118 private int mType; 119 private int mSize; 120 121 /** 122 * Get an instance of {@link MifareClassic} for the given tag. 123 * <p>Does not cause any RF activity and does not block. 124 * <p>Returns null if {@link MifareClassic} was not enumerated in {@link Tag#getTechList}. 125 * This indicates the tag is not MIFARE Classic compatible, or this Android 126 * device does not support MIFARE Classic. 127 * 128 * @param tag an MIFARE Classic compatible tag 129 * @return MIFARE Classic object 130 */ 131 public static MifareClassic get(Tag tag) { 132 if (!tag.hasTech(TagTechnology.MIFARE_CLASSIC)) return null; 133 try { 134 return new MifareClassic(tag); 135 } catch (RemoteException e) { 136 return null; 137 } 138 } 139 140 /** @hide */ 141 public MifareClassic(Tag tag) throws RemoteException { 142 super(tag, TagTechnology.MIFARE_CLASSIC); 143 144 NfcA a = NfcA.get(tag); // MIFARE Classic is always based on NFC a 145 146 mIsEmulated = false; 147 148 switch (a.getSak()) { 149 case 0x08: 150 mType = TYPE_CLASSIC; 151 mSize = SIZE_1K; 152 break; 153 case 0x09: 154 mType = TYPE_CLASSIC; 155 mSize = SIZE_MINI; 156 break; 157 case 0x10: 158 mType = TYPE_PLUS; 159 mSize = SIZE_2K; 160 // SecLevel = SL2 161 break; 162 case 0x11: 163 mType = TYPE_PLUS; 164 mSize = SIZE_4K; 165 // Seclevel = SL2 166 break; 167 case 0x18: 168 mType = TYPE_CLASSIC; 169 mSize = SIZE_4K; 170 break; 171 case 0x28: 172 mType = TYPE_CLASSIC; 173 mSize = SIZE_1K; 174 mIsEmulated = true; 175 break; 176 case 0x38: 177 mType = TYPE_CLASSIC; 178 mSize = SIZE_4K; 179 mIsEmulated = true; 180 break; 181 case 0x88: 182 mType = TYPE_CLASSIC; 183 mSize = SIZE_1K; 184 // NXP-tag: false 185 break; 186 case 0x98: 187 case 0xB8: 188 mType = TYPE_PRO; 189 mSize = SIZE_4K; 190 break; 191 default: 192 // Stack incorrectly reported a MifareClassic. We cannot handle this 193 // gracefully - we have no idea of the memory layout. Bail. 194 throw new RuntimeException( 195 "Tag incorrectly enumerated as MIFARE Classic, SAK = " + a.getSak()); 196 } 197 } 198 199 /** 200 * Return the type of this MIFARE Classic compatible tag. 201 * <p>One of {@link #TYPE_UNKNOWN}, {@link #TYPE_CLASSIC}, {@link #TYPE_PLUS} or 202 * {@link #TYPE_PRO}. 203 * <p>Does not cause any RF activity and does not block. 204 * 205 * @return type 206 */ 207 public int getType() { 208 return mType; 209 } 210 211 /** 212 * Return the size of the tag in bytes 213 * <p>One of {@link #SIZE_MINI}, {@link #SIZE_1K}, {@link #SIZE_2K}, {@link #SIZE_4K}. 214 * These constants are equal to their respective size in bytes. 215 * <p>Does not cause any RF activity and does not block. 216 * @return size in bytes 217 */ 218 public int getSize() { 219 return mSize; 220 } 221 222 /** 223 * Return true if the tag is emulated, determined at discovery time. 224 * These are actually smart-cards that emulate a MIFARE Classic interface. 225 * They can be treated identically to a MIFARE Classic tag. 226 * @hide 227 */ 228 public boolean isEmulated() { 229 return mIsEmulated; 230 } 231 232 /** 233 * Return the number of MIFARE Classic sectors. 234 * <p>Does not cause any RF activity and does not block. 235 * @return number of sectors 236 */ 237 public int getSectorCount() { 238 switch (mSize) { 239 case SIZE_1K: 240 return 16; 241 case SIZE_2K: 242 return 32; 243 case SIZE_4K: 244 return 40; 245 case SIZE_MINI: 246 return 5; 247 default: 248 return 0; 249 } 250 } 251 252 /** 253 * Return the total number of MIFARE Classic blocks. 254 * <p>Does not cause any RF activity and does not block. 255 * @return total number of blocks 256 */ 257 public int getBlockCount() { 258 return mSize / BLOCK_SIZE; 259 } 260 261 /** 262 * Return the number of blocks in the given sector. 263 * <p>Does not cause any RF activity and does not block. 264 * 265 * @param sectorIndex index of sector, starting from 0 266 * @return number of blocks in the sector 267 */ 268 public int getBlockCountInSector(int sectorIndex) { 269 validateSector(sectorIndex); 270 271 if (sectorIndex < 32) { 272 return 4; 273 } else { 274 return 16; 275 } 276 } 277 278 /** 279 * Return the sector that contains a given block. 280 * <p>Does not cause any RF activity and does not block. 281 * 282 * @param blockIndex index of block to lookup, starting from 0 283 * @return sector index that contains the block 284 */ 285 public int blockToSector(int blockIndex) { 286 validateBlock(blockIndex); 287 288 if (blockIndex < 32 * 4) { 289 return blockIndex / 4; 290 } else { 291 return 32 + (blockIndex - 32 * 4) / 16; 292 } 293 } 294 295 /** 296 * Return the first block of a given sector. 297 * <p>Does not cause any RF activity and does not block. 298 * 299 * @param sectorIndex index of sector to lookup, starting from 0 300 * @return block index of first block in sector 301 */ 302 public int sectorToBlock(int sectorIndex) { 303 if (sectorIndex < 32) { 304 return sectorIndex * 4; 305 } else { 306 return 32 * 4 + (sectorIndex - 32) * 16; 307 } 308 } 309 310 /** 311 * Authenticate a sector with key A. 312 * 313 * <p>Successful authentication of a sector with key A enables other 314 * I/O operations on that sector. The set of operations granted by key A 315 * key depends on the ACL bits set in that sector. For more information 316 * see the MIFARE Classic specification on {@see http://www.nxp.com}. 317 * 318 * <p>A failed authentication attempt causes an implicit reconnection to the 319 * tag, so authentication to other sectors will be lost. 320 * 321 * <p>This is an I/O operation and will block until complete. It must 322 * not be called from the main application thread. A blocked call will be canceled with 323 * {@link IOException} if {@link #close} is called from another thread. 324 * 325 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 326 * 327 * @param sectorIndex index of sector to authenticate, starting from 0 328 * @param key 6-byte authentication key 329 * @return true on success, false on authentication failure 330 * @throws TagLostException if the tag leaves the field 331 * @throws IOException if there is an I/O failure, or the operation is canceled 332 */ 333 public boolean authenticateSectorWithKeyA(int sectorIndex, byte[] key) throws IOException { 334 return authenticate(sectorIndex, key, true); 335 } 336 337 /** 338 * Authenticate a sector with key B. 339 * 340 * <p>Successful authentication of a sector with key B enables other 341 * I/O operations on that sector. The set of operations granted by key B 342 * depends on the ACL bits set in that sector. For more information 343 * see the MIFARE Classic specification on {@see http://www.nxp.com}. 344 * 345 * <p>A failed authentication attempt causes an implicit reconnection to the 346 * tag, so authentication to other sectors will be lost. 347 * 348 * <p>This is an I/O operation and will block until complete. It must 349 * not be called from the main application thread. A blocked call will be canceled with 350 * {@link IOException} if {@link #close} is called from another thread. 351 * 352 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 353 * 354 * @param sectorIndex index of sector to authenticate, starting from 0 355 * @param key 6-byte authentication key 356 * @return true on success, false on authentication failure 357 * @throws TagLostException if the tag leaves the field 358 * @throws IOException if there is an I/O failure, or the operation is canceled 359 */ 360 public boolean authenticateSectorWithKeyB(int sectorIndex, byte[] key) throws IOException { 361 return authenticate(sectorIndex, key, false); 362 } 363 364 private boolean authenticate(int sector, byte[] key, boolean keyA) throws IOException { 365 validateSector(sector); 366 checkConnected(); 367 368 byte[] cmd = new byte[12]; 369 370 // First byte is the command 371 if (keyA) { 372 cmd[0] = 0x60; // phHal_eMifareAuthentA 373 } else { 374 cmd[0] = 0x61; // phHal_eMifareAuthentB 375 } 376 377 // Second byte is block address 378 // Authenticate command takes a block address. Authenticating a block 379 // of a sector will authenticate the entire sector. 380 cmd[1] = (byte) sectorToBlock(sector); 381 382 // Next 4 bytes are last 4 bytes of UID 383 byte[] uid = getTag().getId(); 384 System.arraycopy(uid, uid.length - 4, cmd, 2, 4); 385 386 // Next 6 bytes are key 387 System.arraycopy(key, 0, cmd, 6, 6); 388 389 try { 390 if (transceive(cmd, false) != null) { 391 return true; 392 } 393 } catch (TagLostException e) { 394 throw e; 395 } catch (IOException e) { 396 // No need to deal with, will return false anyway 397 } 398 return false; 399 } 400 401 /** 402 * Read 16-byte block. 403 * 404 * <p>This is an I/O operation and will block until complete. It must 405 * not be called from the main application thread. A blocked call will be canceled with 406 * {@link IOException} if {@link #close} is called from another thread. 407 * 408 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 409 * 410 * @param blockIndex index of block to read, starting from 0 411 * @return 16 byte block 412 * @throws TagLostException if the tag leaves the field 413 * @throws IOException if there is an I/O failure, or the operation is canceled 414 */ 415 public byte[] readBlock(int blockIndex) throws IOException { 416 validateBlock(blockIndex); 417 checkConnected(); 418 419 byte[] cmd = { 0x30, (byte) blockIndex }; 420 return transceive(cmd, false); 421 } 422 423 /** 424 * Write 16-byte block. 425 * 426 * <p>This is an I/O operation and will block until complete. It must 427 * not be called from the main application thread. A blocked call will be canceled with 428 * {@link IOException} if {@link #close} is called from another thread. 429 * 430 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 431 * 432 * @param blockIndex index of block to write, starting from 0 433 * @param data 16 bytes of data to write 434 * @throws TagLostException if the tag leaves the field 435 * @throws IOException if there is an I/O failure, or the operation is canceled 436 */ 437 public void writeBlock(int blockIndex, byte[] data) throws IOException { 438 validateBlock(blockIndex); 439 checkConnected(); 440 if (data.length != 16) { 441 throw new IllegalArgumentException("must write 16-bytes"); 442 } 443 444 byte[] cmd = new byte[data.length + 2]; 445 cmd[0] = (byte) 0xA0; // MF write command 446 cmd[1] = (byte) blockIndex; 447 System.arraycopy(data, 0, cmd, 2, data.length); 448 449 transceive(cmd, false); 450 } 451 452 /** 453 * Increment a value block, storing the result in the temporary block on the tag. 454 * 455 * <p>This is an I/O operation and will block until complete. It must 456 * not be called from the main application thread. A blocked call will be canceled with 457 * {@link IOException} if {@link #close} is called from another thread. 458 * 459 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 460 * 461 * @param blockIndex index of block to increment, starting from 0 462 * @param value non-negative to increment by 463 * @throws TagLostException if the tag leaves the field 464 * @throws IOException if there is an I/O failure, or the operation is canceled 465 */ 466 public void increment(int blockIndex, int value) throws IOException { 467 validateBlock(blockIndex); 468 validateValueOperand(value); 469 checkConnected(); 470 471 ByteBuffer cmd = ByteBuffer.allocate(6); 472 cmd.order(ByteOrder.LITTLE_ENDIAN); 473 cmd.put( (byte) 0xC1 ); 474 cmd.put( (byte) blockIndex ); 475 cmd.putInt(value); 476 477 transceive(cmd.array(), false); 478 } 479 480 /** 481 * Decrement a value block, storing the result in the temporary block on the tag. 482 * 483 * <p>This is an I/O operation and will block until complete. It must 484 * not be called from the main application thread. A blocked call will be canceled with 485 * {@link IOException} if {@link #close} is called from another thread. 486 * 487 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 488 * 489 * @param blockIndex index of block to decrement, starting from 0 490 * @param value non-negative to decrement by 491 * @throws TagLostException if the tag leaves the field 492 * @throws IOException if there is an I/O failure, or the operation is canceled 493 */ 494 public void decrement(int blockIndex, int value) throws IOException { 495 validateBlock(blockIndex); 496 validateValueOperand(value); 497 checkConnected(); 498 499 ByteBuffer cmd = ByteBuffer.allocate(6); 500 cmd.order(ByteOrder.LITTLE_ENDIAN); 501 cmd.put( (byte) 0xC0 ); 502 cmd.put( (byte) blockIndex ); 503 cmd.putInt(value); 504 505 transceive(cmd.array(), false); 506 } 507 508 /** 509 * Copy from the temporary block to a value block. 510 * 511 * <p>This is an I/O operation and will block until complete. It must 512 * not be called from the main application thread. A blocked call will be canceled with 513 * {@link IOException} if {@link #close} is called from another thread. 514 * 515 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 516 * 517 * @param blockIndex index of block to copy to 518 * @throws TagLostException if the tag leaves the field 519 * @throws IOException if there is an I/O failure, or the operation is canceled 520 */ 521 public void transfer(int blockIndex) throws IOException { 522 validateBlock(blockIndex); 523 checkConnected(); 524 525 byte[] cmd = { (byte) 0xB0, (byte) blockIndex }; 526 527 transceive(cmd, false); 528 } 529 530 /** 531 * Copy from a value block to the temporary block. 532 * 533 * <p>This is an I/O operation and will block until complete. It must 534 * not be called from the main application thread. A blocked call will be canceled with 535 * {@link IOException} if {@link #close} is called from another thread. 536 * 537 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 538 * 539 * @param blockIndex index of block to copy from 540 * @throws TagLostException if the tag leaves the field 541 * @throws IOException if there is an I/O failure, or the operation is canceled 542 */ 543 public void restore(int blockIndex) throws IOException { 544 validateBlock(blockIndex); 545 checkConnected(); 546 547 byte[] cmd = { (byte) 0xC2, (byte) blockIndex }; 548 549 transceive(cmd, false); 550 } 551 552 /** 553 * Send raw NfcA data to a tag and receive the response. 554 * 555 * <p>This is equivalent to connecting to this tag via {@link NfcA} 556 * and calling {@link NfcA#transceive}. Note that all MIFARE Classic 557 * tags are based on {@link NfcA} technology. 558 * 559 * <p>This is an I/O operation and will block until complete. It must 560 * not be called from the main application thread. A blocked call will be canceled with 561 * {@link IOException} if {@link #close} is called from another thread. 562 * 563 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 564 * 565 * @see NfcA#transceive 566 */ 567 public byte[] transceive(byte[] data) throws IOException { 568 return transceive(data, true); 569 } 570 571 private static void validateSector(int sector) { 572 // Do not be too strict on upper bounds checking, since some cards 573 // have more addressable memory than they report. For example, 574 // MIFARE Plus 2k cards will appear as MIFARE Classic 1k cards when in 575 // MIFARE Classic compatibility mode. 576 // Note that issuing a command to an out-of-bounds block is safe - the 577 // tag should report error causing IOException. This validation is a 578 // helper to guard against obvious programming mistakes. 579 if (sector < 0 || sector >= MAX_SECTOR_COUNT) { 580 throw new IndexOutOfBoundsException("sector out of bounds: " + sector); 581 } 582 } 583 584 private static void validateBlock(int block) { 585 // Just looking for obvious out of bounds... 586 if (block < 0 || block >= MAX_BLOCK_COUNT) { 587 throw new IndexOutOfBoundsException("block out of bounds: " + block); 588 } 589 } 590 591 private static void validateValueOperand(int value) { 592 if (value < 0) { 593 throw new IllegalArgumentException("value operand negative"); 594 } 595 } 596} 597