Java tutorial
/******************************************************************************* * Copyright 2015 * Center for Information, Media and Technology (ZIMT) * HAWK University for Applied Sciences and Arts Hildesheim/Holzminden/Gttingen * * This file is part of HAWK RFID Library Tools. * * HAWK RFID Library Tools is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Diese Datei ist Teil von HAWK RFID Library Tools. * * HAWK RFID Library Tools ist Freie Software: Sie knnen es unter den Bedingungen * der GNU General Public License, wie von der Free Software Foundation, * Version 3 der Lizenz oder (nach Ihrer Wahl) jeder neueren * verffentlichten Version, weiterverbreiten und/oder modifizieren. * * Dieses Programm wird in der Hoffnung, dass es ntzlich sein wird, aber * OHNE JEDE GEWHRLEISTUNG, bereitgestellt; sogar ohne die implizite * Gewhrleistung der MARKTFHIGKEIT oder EIGNUNG FR EINEN BESTIMMTEN ZWECK. * Siehe die GNU General Public License fr weitere Details. * * Sie sollten eine Kopie der GNU General Public License zusammen mit diesem * Programm erhalten haben. Wenn nicht, siehe <http://www.gnu.org/licenses/>. *******************************************************************************/ package org.objectspace.rfid.elatec; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; import java.nio.ByteBuffer; import java.util.Arrays; import org.apache.commons.configuration2.AbstractConfiguration; import org.objectspace.rfid.TagCallback; import org.objectspace.rfid.library.ISO15693Reader; import com.fazecast.jSerialComm.SerialPort; /** * @author Juergen Enge * */ public class ElatecRFID { private static final boolean DEBUG = false; final protected static char[] hexArray = "0123456789ABCDEF".toCharArray(); /** the constant 2^64 */ public static final BigInteger TWO_64 = BigInteger.ONE.shiftLeft(64); /** the constant 2^32 */ public static final BigInteger TWO_32 = BigInteger.ONE.shiftLeft(32); /** the constant 2^8 */ public static final BigInteger TWO_8 = BigInteger.ONE.shiftLeft(8); public static final byte ERR_NONE = 0; public static final byte ERR_UNKNOWN_FUNCTION = 1; public static final byte ERR_MISSING_PARAMETER = 2; public static final byte ERR_UNUSED_PARAMETERS = 3; public static final byte ERR_INVALID_FUNCTION = 4; public static final byte ERR_PARSER = 5; public static final byte CRYPTO_ENV0 = 0; public static final byte CRYPTO_ENV1 = 1; public static final byte CRYPTO_ENV2 = 2; public static final byte CRYPTO_ENV3 = 3; public static final byte CRYPTO_ENV_CNT = 4; public static final byte CRYPTOMODE_AES128 = 0; public static final byte CRYPTOMODE_AES192 = 1; public static final byte CRYPTOMODE_AES256 = 2; public static final byte CRYPTOMODE_3DES = 3; public static final byte CRYPTOMODE_3K3DES = 4; public static final byte CRYPTOMODE_CBC_DES = 5; public static final byte CRYPTOMODE_CBC_DFN_DES = 6; public static final byte CRYPTOMODE_CBC_3DES = 7; public static final byte CRYPTOMODE_CBC_DFN_3DES = 8; public static final byte CRYPTOMODE_CBC_3K3DES = 9; public static final byte CRYPTOMODE_CBC_AES128 = 10; public static final byte DESF_FILETYPE_STDDATAFILE = 0; public static final byte DESF_FILETYPE_BACKUPDATAFILE = 1; public static final byte DESF_FILETYPE_VALUEFILE = 2; public static final byte DESF_FILETYPE_LINEARRECORDFILE = 3; public static final byte DESF_FILETYPE_CYCLICRECORDFILE = 4; public static final byte DESF_COMMSET_PLAIN = 0; public static final byte DESF_COMMSET_PLAIN_MACED = 1; public static final byte DESF_COMMSET_FULLY_ENC = 3; public static final byte DESF_AUTHMODE_COMPATIBLE = 0; public static final byte DESF_AUTHMODE_EV1 = 1; public static final byte DESF_KEYTYPE_3DES = 0; public static final byte DESF_KEYTYPE_3K3DES = 1; public static final byte DESF_KEYTYPE_AES = 2; public static final byte DESF_KEYLEN_3DES = 16; public static final byte DESF_KEYLEN_3K3DES = 24; public static final byte DESF_KEYLEN_AES = 16; /** * */ public ElatecRFID(AbstractConfiguration config) { this.config = config; } public void connect() throws Exception { String portString = config.getString("device.elatec.port", "Serial RFID Device"); SerialPort[] ports = SerialPort.getCommPorts(); for (SerialPort p : ports) { if (p.getDescriptivePortName().contains(portString)) { port = p; } } if (port == null) throw new Exception("could not find port " + portString); checkPort(); } private boolean checkPort() { if (port.isOpen()) return true; port.openPort(); port.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 1000, 0); return port.isOpen(); } public byte[] ISO15693_ReadSingleBlock(int BlockNumber, byte BufferSize) throws Exception { byte[] result = callFunction((byte) 0x0D, (byte) 0x05, BlockNumber, BufferSize, 6); if (result[0] == 0) return null; int size = result[1]; return Arrays.copyOfRange(result, 2, 2 + size); } public boolean ISO15693_WriteSingleBlock(int BlockNumber, byte[] data) throws Exception { byte[] result = callFunction((byte) 0x0D, (byte) 0x07, BlockNumber, data, 1); return (result[0] != 0); } /* public ElatecDESFireKeySettings DESFire_GetKeySettings(byte CryptoEnv) throws Exception { byte[] result = callFunction((byte) 0x0F, (byte) 0x05, CryptoEnv); if (result[0] == 0) return null; return new ElatecDESFireKeySettings(Arrays.copyOfRange(result, 1, result.length)); } public byte[] DESFire_ReadData(byte CryptoEnv, byte fileID, int offset, byte length, byte commSet) throws Exception { if (DEBUG) System.out.println("DESFire_ReadData()"); byte[] result = callFunction((byte) 0x0F, (byte) 0x08, CryptoEnv, fileID, offset, length, commSet); if (result[0] == 0) return null; return Arrays.copyOfRange(result, 1, result.length); } public ElatecDESFireFileSettings DESFire_GetFileSettings(byte CryptoEnv, byte fileID, long aid) throws Exception { if (DEBUG) System.out.println("DESFire_GetFileSettings()"); byte[] result = callFunction((byte) 0x0F, (byte) 0x07, CryptoEnv, fileID); if (result[0] == 0) return null; System.out.println("Filesettings Size:" + result.length); return new ElatecDESFireFileSettings(aid, fileID, Arrays.copyOfRange(result, 1, result.length)); } public byte[] DESFire_GetFileIDs(byte CryptoEnv, byte MaxFileIDCount) throws Exception { if (DEBUG) System.out.println("DESFire_GetFileIDs()"); byte[] result = callFunction((byte) 0x0f, (byte) 0x06, CryptoEnv, MaxFileIDCount); if (result[0] == 0) return new byte[0]; byte num = result[1]; return Arrays.copyOfRange(result, 2, 2 + num); } public boolean DESFire_SelectApplication(byte CryptoEnv, long AID) throws Exception { if (DEBUG) System.out.println("DESFire_SelectApplication()"); byte[] result = callFunction((byte) 0x0f, (byte) 0x03, CryptoEnv, AID); return result[0] > 0; } public long[] DESFire_GetApplicationIDs(byte CryptoEnv, byte MaxAIDCnt) throws Exception { if (DEBUG) System.out.println("DESFire_GetApplicationIDs()"); byte[] result = callFunction((byte) 0x0f, (byte) 0x00, CryptoEnv, MaxAIDCnt); System.out.println(bytesToHex(result)); if (result[0] == 0) return new long[0]; byte num = result[1]; long[] ret = new long[num]; for (int i = 0; i < (int) num; i++) { ret[i] = LSBBytesToLong(Arrays.copyOfRange(result, i * 4 + 2, i * 4 + 2 + 4)); } return ret; } public byte[] DESFire_GetCardUID(byte CryptoEnv, byte BufferSize) throws Exception { if (DEBUG) System.out.println("DESFire_GetCardUID()"); byte[] ret = callFunction((byte) 0x0F, (byte) 0x16, CryptoEnv, BufferSize); if (ret[0] == 0) return new byte[0]; byte length = ret[1]; return Arrays.copyOfRange(ret, 2, 2 + length); } public boolean DESFire_Authenticate(byte CryptoEnv, byte KeyNoTag, byte[] Key, byte KeyType, byte Mode) throws Exception { if (DEBUG) System.out.println("DESFire_Authenticate()"); byte[] ret = callFunction((byte) 0x0F, (byte) 0x04, CryptoEnv, KeyNoTag, Key, KeyType, Mode); return ret[0] > 0; } */ public void reset() throws Exception { if (DEBUG) System.out.println("reset()"); callFunction((byte) 0x00, (byte) 0x01, -1); } public String GetVersionString() throws Exception { if (DEBUG) System.out.println("GetVersionString()"); byte MaxLen = 30; byte[] buffer = callFunction((byte) 0x00, (byte) 0x04, (byte) MaxLen, MaxLen + 1); String ret = new String(buffer).trim(); return ret; } public void SetTagTypes(long tagTypesLF, long tagTypesHF) throws Exception { if (DEBUG) System.out.println("SetTagTypes()"); callFunction((byte) 0x05, (byte) 0x02, tagTypesLF, tagTypesHF, 0); } public ElatecTag SearchTag() throws Exception { return SearchTag((byte) 16); } public ElatecTag SearchTag(byte MaxIDBytes) throws Exception { if (DEBUG) System.out.println("SearchTag()"); // Response: 00 01 82 40 08 E0 04 01 50 2D 42 10 E3 byte[] data = callFunction((byte) 0x05, (byte) 0x00, MaxIDBytes, MaxIDBytes + 5); if (data == null) return null; return new ElatecTag(data); } public String DESFire_GetVersion(byte cryptoEnv) throws Exception { if (DEBUG) System.out.println("DESFire_GetVersion()"); byte[] buffer = callFunction((byte) 0x0F, (byte) 0x12, cryptoEnv); if (buffer == null) return null; return bytesToHex(buffer); } private byte[] getResult(int resultSize) throws Exception { if (!checkPort()) throw new Exception(port.getDescriptivePortName() + "disconnected"); /* ByteBuffer buffer = ByteBuffer.allocate(1024); int bytesAvailable = 0; // wait for data Thread.sleep(80); int count = 0; while ((bytesAvailable = port.bytesAvailable()) == 0) { Thread.sleep(20); count++; if (count > 100) break; } // read all // Thread.sleep(millis); while ((bytesAvailable = port.bytesAvailable()) > 0) { byte[] buf = new byte[bytesAvailable]; int numBytes = port.readBytes(buf, bytesAvailable); buffer.put(buf); } buffer.flip(); for (byte b : buffer.array()) { */ String hexString = ""; // 2 char per byte, execution level, result, carriage return byte[] buf = new byte[resultSize * 2 + 2 + 1]; int numBytes = port.readBytes(buf, resultSize * 2 + 2 + 1); for (byte b : buf) { // if (b == 0x0D) { // break; // } hexString += (char) (b & 0xFF); } byte[] result = hexStringToByteArray(hexString.trim()); if (result[0] != 0) throw new ElatecException(result[0]); if (result.length <= 1) return null; return Arrays.copyOfRange(result, 1, result.length); } private byte[] executeHexString(String command, int resultSize) throws Exception { if (!checkPort()) throw new Exception(port.getDescriptivePortName() + "disconnected"); byte[] hexBytes = command.getBytes(); int numWrite = port.writeBytes(hexBytes, hexBytes.length); if (numWrite != hexBytes.length) throw new ElatecException((byte) 6); if (resultSize < 0) return null; return getResult(resultSize); } private byte[] callFunction(byte func1, byte func2, int resultSize) throws Exception { String hexString = bytesToHex(new byte[] { func1, func2 }) + (char) 0x0D; return executeHexString(hexString, resultSize); } private byte[] callFunction(byte func1, byte func2, byte bParam, int resultSize) throws Exception { String hexString = bytesToHex(new byte[] { func1, func2, bParam }) + (char) 0x0D; return executeHexString(hexString, resultSize); } private byte[] callFunction(byte func1, byte func2, byte bParam1, byte bParam2, int resultSize) throws Exception { String hexString = bytesToHex(new byte[] { func1, func2, bParam1, bParam2 }) + (char) 0x0D; return executeHexString(hexString, resultSize); } private byte[] callFunction(byte func1, byte func2, byte bParam1, byte bParam2, byte[] bList, byte bParam3, byte bParam4, int resultSize) throws Exception { byte[] bytes1 = new byte[] { func1, func2, bParam1, bParam2, (byte) bList.length }; byte[] bytes2 = new byte[bytes1.length + bList.length + 2]; System.arraycopy(bytes1, 0, bytes2, 0, bytes1.length); System.arraycopy(bList, 0, bytes2, bytes1.length, bList.length); bytes2[bytes2.length - 2] = bParam3; bytes2[bytes2.length - 1] = bParam4; String hexString = bytesToHex(bytes2) + (char) 0x0D; return executeHexString(hexString, resultSize); } private byte[] callFunction(byte func1, byte func2, int iParam, byte[] bList, int resultSize) throws Exception { String hexString = bytesToHex(new byte[] { func1, func2 }) + intToLSBHex(iParam) + bytesToHex(new byte[] { (byte) bList.length }) + bytesToHex(bList) + (char) 0x0D; return executeHexString(hexString, resultSize); } private byte[] callFunction(byte func1, byte func2, byte bParam1, long lParam1, int resultSize) throws Exception { String hexString = bytesToHex(new byte[] { func1, func2, bParam1 }) + longToLSBHex(lParam1) + (char) 0x0D; return executeHexString(hexString, resultSize); } private byte[] callFunction(byte func1, byte func2, long lParam1, long lParam2, int resultSize) throws Exception { String hexString = bytesToHex(new byte[] { func1, func2 }) + longToLSBHex(lParam1) + longToLSBHex(lParam2) + (char) 0x0D; return executeHexString(hexString, resultSize); } private byte[] callFunction(byte func1, byte func2, int iParam1, byte bParam1, int resultSize) throws Exception { String hexString = bytesToHex(new byte[] { func1, func2 }) + intToLSBHex(iParam1) + bytesToHex(new byte[] { bParam1 }) + (char) 0x0D; return executeHexString(hexString, resultSize); } private byte[] callFunction(byte func1, byte func2, byte bParam1, byte bParam2, int iParam, byte bParam3, byte bParam4, int resultSize) throws Exception { String hexString = bytesToHex(new byte[] { func1, func2, bParam1, bParam2 }) + intToHex(iParam) + bytesToHex(new byte[] { bParam3, bParam4 }) + (char) 0x0D; return executeHexString(hexString, resultSize); } public static byte[] hexStringToByteArray(String s) { int len = s.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16)); } return data; } public static String bytesToHex(byte[] bytes) { char[] hexChars = new char[bytes.length * 2]; for (int j = 0; j < bytes.length; j++) { int v = bytes[j] & 0xFF; hexChars[j * 2] = hexArray[v >>> 4]; hexChars[j * 2 + 1] = hexArray[v & 0x0F]; } return new String(hexChars); } public static String longToHex(long l) { BigInteger b = BigInteger.valueOf(l); if (b.signum() < 0) b = b.add(TWO_64); String str = b.toString(16); if (str.length() == 16) str = str.substring(8); while (str.length() < 8) str = "0" + str; return str; } public static String longToLSBHex(long l) { String str = longToHex(l); String ret = ""; for (int i = 0; i < 4; i++) { ret += str.substring((3 - i) * 2, (3 - i) * 2 + 2); } return ret; } public static String intToHex(int i) { BigInteger b = BigInteger.valueOf(i); if (b.signum() < 0) b = b.add(TWO_64); String str = b.toString(16); if (str.length() == 16) str = str.substring(12); while (str.length() < 4) str = "0" + str; return str; } public static String intToLSBHex(int i) { String str = intToHex(i); String ret = ""; for (int j = 0; j < 2; j++) { ret += str.substring((1 - j) * 2, (1 - j) * 2 + 2); } return ret; } public static long LSBHexToLong(String str) { String ret = ""; for (int i = 0; i < 4; i++) { ret += str.substring((3 - i) * 2, (3 - i) * 2 + 2); } return (new BigInteger(ret, 16)).longValue(); } public static long LSBBytesToLong(byte[] b) { return LSBHexToLong(bytesToHex(b)); } public static int LSBHexToInt(String str) { String ret = ""; for (int i = 0; i < 2; i++) { ret += str.substring((1 - i) * 2, (1 - i) * 2 + 2); } return (new BigInteger(ret, 16)).intValue(); } public static int LSBBytesToInt(byte[] b) { return LSBHexToInt(bytesToHex(b)); } public static long LSBHexToLong(byte[] b) { return LSBHexToLong(new String(b)); } public static String hexDump(byte[] data, int bpl) { String ret = ""; int p = 0; String asc = ""; for (byte b : data) { if (p % bpl == 0) { if (asc.length() > 0) { ret += " " + asc + "\n"; } asc = ""; p = 0; } ret += String.format("%02x ", b); if (b < 32) asc += "."; else asc += (char) b; p++; } while (p < bpl - 1) { ret += " "; p++; } ret += " " + asc + "\n"; return ret; } private AbstractConfiguration config; private OutputStream out = null; private InputStream in = null; private SerialPort port = null; }