private void resolveIntent(Intent intent) { String action = intent.getAction(); toast("resolving intent"); if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) { toast("RESOLVE THIS INTENT"); Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); receiveTab.append("\nResolve Intent for NDEF discovery"); } else if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) { Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); MifareClassic mfc = MifareClassic.get(tagFromIntent); byte[] data; receiveTab.append("\nNew tech tag received"); try { mfc.connect(); boolean auth = false; String cardData = null; int secCount = mfc.getSectorCount(); int bCount = 0; int bIndex = 0; for (int j = 0; j < secCount; j++) { auth = mfc.authenticateSectorWithKeyA(j, MifareClassic.KEY_DEFAULT); if (auth) { bCount = mfc.getBlockCountInSector(j); bIndex = 0; for (int i = 0; i < bCount; i++) { bIndex = mfc.sectorToBlock(j); data = mfc.readBlock(bIndex); cardData = new String(data); receiveTab.append("\n" + cardData); bIndex++; } } else { Toast.makeText(this, "Auth failed", Toast.LENGTH_LONG).show(); } } } catch (IOException ex) { Toast.makeText(this, "IO Error while attempting to read mifare", Toast.LENGTH_LONG).show(); } } else if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) { receiveTab.append("\nSome Tag found from card"); Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); receiveTab.append("\n" + tagFromIntent.toString()); for (int k = 0; k < tagFromIntent.getTechList().length; k++) { receiveTab.append("\nTech List: " + tagFromIntent.getTechList()[k]); if (tagFromIntent.getTechList()[k].equals("android.nfc.tech.NfcA")) { // Run connection method parseNfcATag(tagFromIntent); // connectToNDEF(tagFromIntent); // parseMifareTag(tagFromIntent); } else if (tagFromIntent.getTechList()[k].equals("android.nfc.tech.Ndef")) { connectToNDEF(tagFromIntent); // receiveTab.append("\nRun connect to NDEF"); } } } }
/** * Read all blocks from the Mifare tag and return the data in a Tag object. * * @return A Tag object containing the data of the Mifare tag. * @throws IOException */ public Tag read() throws IOException { int sectors = mTag.getSectorCount(); Tag t = new Tag(TagType.getType(sectors)); if (t.getSectorCount() > mKeys.getSectorCount()) throw new IOException("Too few keys"); mTag.connect(); try { for (int s = 0; s < sectors; ++s) { byte[] aKey = mKeys.getKeyA(s); byte[] bKey = mKeys.getKeyB(s); // Authenticate for each sector (try A key, then B key) if (!mTag.authenticateSectorWithKeyA(s, aKey) && !mTag.authenticateSectorWithKeyB(s, bKey)) throw new IOException("Auth error"); // Read every block of the sector int blockOffset = mTag.sectorToBlock(s); int lastBlock = blockOffset + mTag.getBlockCountInSector(s); for (int b = blockOffset; b < lastBlock; ++b) { byte[] readBuffer = mTag.readBlock(b); // Manually transfer key data to tag since it is usually not // readable if (b == lastBlock - 1) { for (int i = 0; i < Tag.KEY_SIZE; ++i) { readBuffer[i] = aKey[i]; readBuffer[Tag.BLOCK_SIZE - Tag.KEY_SIZE + i] = bKey[i]; } } t.setBlock(b, readBuffer); if (mProgressListener != null) mProgressListener.publishProgress((100 * b) / t.getBlockCount()); } } return t; } finally { mTag.close(); } }
/** * This method checks if the present tag is writable with the provided keys on the given positions * (sectors, blocks). This is done by authenticating with one of the keys followed by reading and * interpreting ({@link Common#getOperationInfoForBlock(byte, byte, byte, * de.syss.MifareClassicTool.Common.Operations, boolean, boolean)}) of the Access Conditions. * * @param pos A map of positions (key = sector, value = Array of blocks). For each of these * positions you will get the write information (see return values). * @param keyMap A key map a generated by {@link Activities.KeyMapCreator}. * @return A map within a map (all with type = Integer). The key of the outer map is the sector * number and the value is another map with key = block number and value = write information. * The write information indicates which key is needed to write to the present tag on the * given position.<br> * <br> * Write informations are:<br> * <ul> * <li>0 - Never * <li>1 - Key A * <li>2 - Key B * <li>3 - Key A|B * <li>4 - Key A, but AC never * <li>5 - Key B, but AC never * <li>6 - Key B, but keys never * <li>-1 - Error * <li>Inner map == null - Whole sector is dead (IO Error) or ACs are incorrect * <li>null - Authentication error * </ul> */ public HashMap<Integer, HashMap<Integer, Integer>> isWritableOnPositions( HashMap<Integer, int[]> pos, SparseArray<byte[][]> keyMap) { HashMap<Integer, HashMap<Integer, Integer>> ret = new HashMap<Integer, HashMap<Integer, Integer>>(); for (int i = 0; i < keyMap.size(); i++) { int sector = keyMap.keyAt(i); if (pos.containsKey(sector)) { byte[][] keys = keyMap.get(sector); byte[] ac = null; // Authenticate. if (keys[0] != null) { if (authenticate(sector, keys[0], false) == false) { return null; } } else if (keys[1] != null) { if (authenticate(sector, keys[1], true) == false) { return null; } } else { return null; } // Read Mifare Access Conditions. int acBlock = mMFC.sectorToBlock(sector) + mMFC.getBlockCountInSector(sector) - 1; try { ac = mMFC.readBlock(acBlock); } catch (IOException e) { ret.put(sector, null); continue; } ac = Arrays.copyOfRange(ac, 6, 9); byte[][] acMatrix = Common.acBytesToACMatrix(ac); if (acMatrix == null) { ret.put(sector, null); continue; } boolean isKeyBReadable = Common.isKeyBReadable(acMatrix[0][3], acMatrix[1][3], acMatrix[2][3]); // Check all Blocks with data (!= null). HashMap<Integer, Integer> blockWithWriteInfo = new HashMap<Integer, Integer>(); for (int block : pos.get(sector)) { if ((block == 3 && sector <= 31) || (block == 15 && sector >= 32)) { // Sector Trailer. // Are the Access Bits writable? int acValue = Common.getOperationInfoForBlock( acMatrix[0][3], acMatrix[1][3], acMatrix[2][3], Common.Operations.WriteAC, true, isKeyBReadable); // Is key A writable? (If so, key B will be writable // with the same key.) int keyABValue = Common.getOperationInfoForBlock( acMatrix[0][3], acMatrix[1][3], acMatrix[2][3], Common.Operations.WriteKeyA, true, isKeyBReadable); int result = keyABValue; if (acValue == 0 && keyABValue != 0) { // Write key found, but ac-bits are not writable. result += 3; } else if (acValue == 2 && keyABValue == 0) { // Access Bits are writable with key B, // but keys are not writable. result = 6; } blockWithWriteInfo.put(block, result); } else { // Data block. int acBitsForBlock = block; // Handle Mifare Classic 4k Tags. if (sector >= 32) { if (block >= 0 && block <= 4) { acBitsForBlock = 0; } else if (block >= 5 && block <= 9) { acBitsForBlock = 1; } else if (block >= 10 && block <= 14) { acBitsForBlock = 2; } } blockWithWriteInfo.put( block, Common.getOperationInfoForBlock( acMatrix[0][acBitsForBlock], acMatrix[1][acBitsForBlock], acMatrix[2][acBitsForBlock], Common.Operations.Write, false, isKeyBReadable)); } } if (blockWithWriteInfo.size() > 0) { ret.put(sector, blockWithWriteInfo); } } } return ret; }
/** * Read a as much as possible from a sector with the given key. Best results are gained from a * valid key B (except key B is marked as readable in the access conditions). * * @param sectorIndex Index of the Sector to read. (For Mifare Classic 1K: 0-63) * @param key Key for the authentication. * @param useAsKeyB If true, key will be treated as key B for authentication. * @return Array of blocks (index 0-3 or 0-15). If a block or a key is marked with {@link * #NO_DATA} or {@link #NO_KEY} it means that this data could be read or found. On * authentication error "null" will be returned. * @throws TagLostException When tag is lost. * @see #mergeSectorData(String[], String[]) */ public String[] readSector(int sectorIndex, byte[] key, boolean useAsKeyB) throws TagLostException { boolean auth = authenticate(sectorIndex, key, useAsKeyB); String[] ret = null; // Read sector. if (auth) { // Read all blocks. ArrayList<String> blocks = new ArrayList<String>(); int firstBlock = mMFC.sectorToBlock(sectorIndex); int lastBlock = firstBlock + 4; if (mMFC.getSize() == MifareClassic.SIZE_4K && sectorIndex > 31) { lastBlock = firstBlock + 16; } for (int i = firstBlock; i < lastBlock; i++) { try { byte blockBytes[] = mMFC.readBlock(i); // mMFC.readBlock(i) must return 16 bytes or throw an error. // At least this is what the documentation says. // On Samsungs Galaxy S5 however, it sometimes // returns < 16 bytes for unknown reasons. if (blockBytes.length != 16) { throw new IOException(); } blocks.add(Common.byte2HexString(blockBytes)); } catch (TagLostException e) { throw e; } catch (IOException e) { // Could not read block. // (Maybe due to key/authentication method.) Log.d(LOG_TAG, "Error while reading block " + i + " from tag."); blocks.add(NO_DATA); if (!mMFC.isConnected()) { throw new TagLostException("Tag removed during readSector(...)"); } // After error reauthentication is needed. auth = authenticate(sectorIndex, key, useAsKeyB); } } ret = blocks.toArray(new String[blocks.size()]); int last = ret.length - 1; // Merge key in last block (sector trailer). if (!useAsKeyB) { if (isKeyBReadable(Common.hexStringToByteArray(ret[last].substring(12, 20)))) { ret[last] = Common.byte2HexString(key) + ret[last].substring(12, 32); } else { ret[last] = Common.byte2HexString(key) + ret[last].substring(12, 20) + NO_KEY; } } else { if (ret[0].equals(NO_DATA)) { // If Key B may be read in the corresponding Sector Trailer, // it cannot serve for authentication (according to NXP). // What they mean is that you can authenticate successfully, // but can not read data. In this case the // readBlock() result is 0 for each block. ret = null; } else { ret[last] = NO_KEY + ret[last].substring(12, 20) + Common.byte2HexString(key); } } } return ret; }
private void resolveIntent(Intent intent) { // 1) Parse the intent and get the action that triggered this intent String action = intent.getAction(); // 2) Check if it was triggered by a tag discovered interruption. if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) { mydialog = ProgressDialog.show(ReadCardActivity.this, "loading", "loading"); // 3) Get an instance of the TAG from the NfcAdapter Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); // 4) Get an instance of the Mifare classic card from this TAG // intent MifareClassic mfc = MifareClassic.get(tagFromIntent); MifareClassCard mifareClassCard = null; try { // 5.1) Connect to card mfc.connect(); // 5.2) and get the number of sectors this card has..and loop // thru these sectors int secCount = mfc.getSectorCount(); mifareClassCard = new MifareClassCard(secCount); // init information String techtemp = ""; for (String tech : mfc.getTag().getTechList()) { techtemp = techtemp + tech + "\n"; } mifareClassCard.addValue("UID", Converter.getHexString(mfc.getTag().getId())); mifareClassCard.addValue("TechList", techtemp); // mifareClassCard.addValue("MemorySize", mfc.get); int bCount = 0; int bIndex = 0; for (int j = 0; j < secCount; j++) { boolean authKeyA = false; boolean authKeyB = false; MifareSector mifareSector = new MifareSector(); mifareSector.sectorIndex = j; // 6.1) authenticate the sector for (String key : defaultKeys) { if (!authKeyA) { authKeyA = mfc.authenticateSectorWithKeyA(j, Converter.hexStringToByteArray(key)); mifareSector.keyA = new MifareKey(Converter.hexStringToByteArray(key)); } if (!authKeyB) { authKeyB = mfc.authenticateSectorWithKeyB(j, Converter.hexStringToByteArray(key)); mifareSector.keyB = new MifareKey(Converter.hexStringToByteArray(key)); } // 都满足则break if (authKeyA && authKeyB) { break; } } if ((authKeyA && authKeyB) || authKeyA || authKeyB) { mifareSector.authorized = true; // 6.2) In each sector - get the block count bCount = mfc.getBlockCountInSector(j); bCount = Math.min(bCount, MifareSector.BLOCKCOUNT); bIndex = mfc.sectorToBlock(j); // set access condition byte[] acdata = mfc.readBlock(bIndex + 3); String hexString = Converter.getHexString(acdata, 16); mifareSector.accessCondition = hexString.substring(12, 20); for (int i = 0; i < bCount; i++) { // 6.3) Read the block byte[] data = mfc.readBlock(bIndex); // System.out.println(Converter.getHexString(data, 16)); MifareBlock mifareBlock = new MifareBlock(mifareSector); mifareBlock.setData(data); mifareBlock.setIndex(bIndex); // 7) Convert the data into a string from Hex // format. bIndex++; mifareSector.blocks[i] = mifareBlock; } mifareClassCard.setSector(mifareSector.sectorIndex, mifareSector); } else { // Authentication failed - Handle it mifareSector.authorized = false; } } this.mydialog.dismiss(); mfc.close(); Intent dataIntent = new Intent(this, ViewCardActivity.class); Bundle bundle = new Bundle(); bundle.putSerializable("mifare", mifareClassCard); dataIntent.putExtras(bundle); this.startActivityForResult(dataIntent, 0); this.finish(); } catch (IOException e) { Log.e(TAG, e.getLocalizedMessage()); showAlert(3); this.mydialog.dismiss(); } finally { if (mifareClassCard != null) { // mifareClassCard.debugPrint(); } } } // End of IF } // End of method