Java tutorial
/** * The MIT License (MIT) * * Copyright (c) 2015 Marc de Verdelhan * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package eu.verdelhan.acr122urw; import static eu.verdelhan.acr122urw.HexUtils.bytesToHexString; import static eu.verdelhan.acr122urw.HexUtils.hexStringToBytes; import static eu.verdelhan.acr122urw.HexUtils.isHexString; import java.io.IOException; import java.util.Arrays; import java.util.List; import javax.smartcardio.CardException; import org.nfctools.mf.MfAccess; import org.nfctools.mf.MfException; import org.nfctools.mf.MfReaderWriter; import org.nfctools.mf.block.BlockResolver; import org.nfctools.mf.block.MfBlock; import org.nfctools.mf.card.MfCard; import org.nfctools.mf.classic.Key; import org.nfctools.mf.classic.MemoryLayout; import org.apache.commons.codec.binary.Hex; /** * Mifare utility class. */ public final class MifareUtils { /** Mifare Classic 1K sector count */ public static final int MIFARE_1K_SECTOR_COUNT = 16; /** Mifare Classic 1K block count (per sector) */ public static final int MIFARE_1K_PER_SECTOR_BLOCK_COUNT = 4; /** Common Mifare Classic 1K keys */ public static final List<String> COMMON_MIFARE_CLASSIC_1K_KEYS = Arrays.asList("001122334455", "000102030405", "A0A1A2A3A4A5", "B0B1B2B3B4B5", "AAAAAAAAAAAA", "BBBBBBBBBBBB", "AABBCCDDEEFF", "FFFFFFFFFFFF"); private MifareUtils() { } /** * @param s a string * @return true if the provided string is a valid Mifare Classic 1K key, false otherwise */ public static boolean isValidMifareClassic1KKey(String s) { return isHexString(s) && (s.length() == 12); } /** * @param s a string * @return true if the provided string is a valid Mifare Classic 1K sector index, false otherwise */ public static boolean isValidMifareClassic1KSectorIndex(String s) { try { int sectorIndex = Integer.parseInt(s); return sectorIndex >= 0 && sectorIndex < MIFARE_1K_SECTOR_COUNT; } catch (NumberFormatException nfe) { return false; } } /** * @param s a string * @return true if the provided string is a valid Mifare Classic 1K block index, false otherwise */ public static boolean isValidMifareClassic1KBlockIndex(String s) { try { int sectorIndex = Integer.parseInt(s); return sectorIndex >= 0 && sectorIndex < MIFARE_1K_PER_SECTOR_BLOCK_COUNT; } catch (NumberFormatException nfe) { return false; } } /** * Dumps a Mifare Classic 1K card. * @param reader the reader * @param card the card * @param keys the keys to be tested for reading */ public static String dumpMifareClassic1KCard(MfReaderWriter reader, MfCard card, List<String> keys) throws CardException { String value = ""; for (int sectorIndex = 1; sectorIndex < 2; sectorIndex++) { // For each sector... for (int blockIndex = 2; blockIndex <= 2; blockIndex++) { // For each block... value = dumpMifareClassic1KBlock(reader, card, sectorIndex, blockIndex, keys); } } return value; } /** * Write data to a Mifare Classic 1K card. * @param reader the reader * @param card the card * @param sectorId the sector to be written * @param blockId the block to be written * @param key the key to be used for writing * @param dataString the data hex string to be written */ public static void writeToMifareClassic1KCard(MfReaderWriter reader, MfCard card, int sectorId, int blockId, String key, String dataString) throws CardException { if (!isValidMifareClassic1KKey(key)) { System.out.println("The key " + key + "is not valid."); return; } if (!isHexString(dataString)) { System.out.println(dataString + " is not an hex string."); return; } byte[] keyBytes = hexStringToBytes(key); // Reading with key A MfAccess access = new MfAccess(card, sectorId, blockId, Key.A, keyBytes); String blockData = readMifareClassic1KBlock(reader, access); if (blockData == null) { // Reading with key B access = new MfAccess(card, sectorId, blockId, Key.B, keyBytes); blockData = readMifareClassic1KBlock(reader, access); } System.out.print("Old block data: "); if (blockData == null) { // Failed to read block System.out.println("<Failed to read block>"); } else { // Block read System.out.println(blockData + " (Key " + access.getKey() + ": " + key + ")"); // Writing with same key boolean written = false; try { byte[] data = hexStringToBytes(dataString); MfBlock block = BlockResolver.resolveBlock(MemoryLayout.CLASSIC_1K, sectorId, blockId, data); written = writeMifareClassic1KBlock(reader, access, block); } catch (MfException me) { System.out.println(me.getMessage()); } if (written) { blockData = readMifareClassic1KBlock(reader, access); System.out.print("New block data: "); if (blockData == null) { // Failed to read block System.out.println("<Failed to read block>"); } else { // Block read //System.out.println(blockData + " (Key " + access.getKey() + ": " + key + ")"); } } } } /** * Reads a Mifare Classic 1K block. * @param reader the reader * @param access the access * @return a string representation of the block data, null if the block can't be read */ private static String readMifareClassic1KBlock(MfReaderWriter reader, MfAccess access) throws CardException { String data = null; try { MfBlock block = reader.readBlock(access)[0]; data = bytesToHexString(block.getData()); } catch (IOException ioe) { if (ioe.getCause() instanceof CardException) { throw (CardException) ioe.getCause(); } } return data; } /** * Writes a Mifare Classic 1K block. * @param reader the reader * @param access the access * @param block the block to be written * @return true if the block has been written, false otherwise */ private static boolean writeMifareClassic1KBlock(MfReaderWriter reader, MfAccess access, MfBlock block) throws CardException { boolean written = false; try { reader.writeBlock(access, block); written = true; } catch (IOException ioe) { if (ioe.getCause() instanceof CardException) { throw (CardException) ioe.getCause(); } } return written; } /** * Dumps Mifare Classic 1K block data. * @param reader the reader * @param card the card * @param sectorId the sector to be read * @param blockId the block to be read * @param keys the keys to be tested for reading */ private static String dumpMifareClassic1KBlock(MfReaderWriter reader, MfCard card, int sectorId, int blockId, List<String> keys) throws CardException { //System.out.printf("%02d block%02d: ", sectorId, blockId); String blockData = ""; for (String key : keys) { // For each provided key... if (isValidMifareClassic1KKey(key)) { byte[] keyBytes = hexStringToBytes(key); // Reading with key A MfAccess access = new MfAccess(card, sectorId, blockId, Key.A, keyBytes); blockData = readMifareClassic1KBlock(reader, access); //System.out.println("sd " + blockData); if (blockData == null) { // Reading with key B access = new MfAccess(card, sectorId, blockId, Key.B, keyBytes); blockData = readMifareClassic1KBlock(reader, access); } if (blockData != null) { // Block read //System.out.println(blockData + " (Key " + access.getKey() + ": " + key + ")"); return blockData; } } } // All keys tested, failed to read block //System.out.println("<Failed to read block>"); return blockData; } public static String convertHexToText(String hexString) { String result = ""; try { byte[] bytes = Hex.decodeHex(hexString.toCharArray()); result = new String(bytes, "UTF-8"); } catch (Exception e) { System.out.println(e.getMessage()); } return result; } }