/** * Write all the blocks in a Tag to the Mifare tag. * * @param t * @throws IOException */ public void write(Tag t) throws IOException { if (t.getSectorCount() > mKeys.getSectorCount()) throw new IOException("Too few keys"); mTag.connect(); int sectors = mTag.getSectorCount(); try { for (int s = 0; s < sectors; ++s) { // Authenticate for each sector (try B key, then A key) if (!mTag.authenticateSectorWithKeyB(s, mKeys.getKeyB(s)) && !mTag.authenticateSectorWithKeyA(s, mKeys.getKeyA(s))) throw new IOException("Auth error"); // Write to tag. Skip block 0 and the trailer of each sector int blockOffset = mTag.sectorToBlock(s); int lastBlock = blockOffset + mTag.getBlockCountInSector(s); // Skip block 0 blockOffset = blockOffset == 0 ? 1 : blockOffset; for (int b = blockOffset; b < lastBlock; ++b) { mTag.writeBlock(b, t.getBlock(b)); if (mProgressListener != null) mProgressListener.publishProgress((100 * b) / t.getBlockCount()); } } } finally { mTag.close(); } }
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(); } }
/** * Write a block of 16 byte data to tag. * * @param sectorIndex The sector to where the data should be written * @param blockIndex The block to where the data should be written * @param data 16 byte of data. * @param key The Mifare Classic key for the given sector. * @param useAsKeyB If true, key will be treated as key B for authentication. * @return The return codes are:<br> * <ul> * <li>0 - Everything went fine. * <li>1 - Sector index is out of range. * <li>2 - Block index is out of range. * <li>3 - Data are not 16 byte. * <li>4 - Authentication went wrong. * <li>-1 - Error while writing to tag. * </ul> * * @see #authenticate(int, byte[], boolean) */ public int writeBlock( int sectorIndex, int blockIndex, byte[] data, byte[] key, boolean useAsKeyB) { if (mMFC.getSectorCount() - 1 < sectorIndex) { return 1; } if (mMFC.getBlockCountInSector(sectorIndex) - 1 < blockIndex) { return 2; } if (data.length != 16) { return 3; } if (!authenticate(sectorIndex, key, useAsKeyB)) { return 4; } // Write block. int block = mMFC.sectorToBlock(sectorIndex) + blockIndex; try { mMFC.writeBlock(block, data); } catch (IOException e) { Log.e(LOG_TAG, "Error while writing block to tag.", e); return -1; } return 0; }
/** * Return the block count in a specific sector. * * @param sectorIndex Index of a sector. * @return Block count in given sector. */ public int getBlockCountInSector(int sectorIndex) { return mMFC.getBlockCountInSector(sectorIndex); }
/** * 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; }
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