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