package itu.assignments.fluidphotobrowser; import java.nio.ByteBuffer; import java.util.List; import java.util.Observable; import javax.smartcardio.Card; import javax.smartcardio.CardChannel; import javax.smartcardio.CardException; import javax.smartcardio.CardTerminal; import javax.smartcardio.TerminalFactory; public class NFCUtil extends Observable implements Runnable { private boolean isUserAuthenticated; private String activeUser; private String currentCardBalance; public String getActiveUser() { return activeUser; } public boolean isUserAuthenticated() { return isUserAuthenticated; } public CardTerminal InitializeTerminal() throws CardException { //Get terminal System.out.println("Searching for terminals..."); CardTerminal terminal = null; TerminalFactory factory = TerminalFactory.getDefault(); List<CardTerminal> terminals = factory.terminals().list(); //Print list of terminals for(CardTerminal ter:terminals) { System.out.println("Found: " +ter.getName().toString()); terminal = terminals.get(0);// We assume just one is connected } return terminal; } public boolean IsCardPresent(CardTerminal terminal) throws CardException { System.out.println("Waiting for card..."); boolean isCard = false; while (!isCard) { isCard = terminal.waitForCardPresent(0); if(isCard) System.out.println("Card was found ! :-)"); } return true; } public CardChannel GetCardAndOpenChannel(CardTerminal terminal) throws CardException { Card card = terminal.connect("*"); CardChannel channel = card.getBasicChannel(); byte[] baReadUID = new byte[5]; baReadUID = new byte[]{(byte) 0xFF, (byte) 0xCA, (byte) 0x00, (byte) 0x00, (byte) 0x00}; //FF CA 00 00 00 System.out.println("UID: " + SendCommand(baReadUID, channel)); return channel; } public boolean LoadBasicKey(CardChannel channel) // LOADS 6BIT KEY: FF FF FF FF FF FF { byte[] baLoadKey = new byte[12]; baLoadKey = new byte[]{(byte) 0xFF, (byte) 0x82, (byte) 0x00, (byte) 0x00, (byte) 0x06, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}; //FF 82 00 00 06 [FF FF FF FF FF FF] if(SendCommand(baLoadKey, channel).equals("9000")) { System.out.println("Key succefully loaded to the reader!! "); return true; } else { return false; } } public boolean AuthenticateBlock1(CardChannel channel) { byte[] baAuth = new byte[10]; baAuth = new byte[]{(byte) 0xFF, (byte) 0x86, (byte) 0x00, (byte) 0x00, (byte) 0x05, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x60, (byte) 0x00}; //FF 86 00 00 05 01 00 01 60 00 if(SendCommand(baAuth, channel).equals("9000")) { System.out.println("Authentication for block 0x01 succeded! "); return true; } else { System.out.println("Authentication failed!"); return false; } } public boolean AuthenticateBlock2(CardChannel channel) { byte[] baAuth = new byte[10]; baAuth = new byte[]{(byte) 0xFF, (byte) 0x86, (byte) 0x00, (byte) 0x00, (byte) 0x05, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x60, (byte) 0x00}; //FF 86 00 00 05 01 00 01 60 00 if(SendCommand(baAuth, channel).equals("9000")) { System.out.println("Authentication for block 0x02 succeded! "); return true; } else { System.out.println("Authentication failed!"); return false; } } public static String SendCommand(byte[] cmd, CardChannel channel) { String response = ""; byte[] baResp = new byte[258]; ByteBuffer bufCmd = ByteBuffer.wrap(cmd); ByteBuffer bufResp = ByteBuffer.wrap(baResp); int output = 0; try{ output = channel.transmit(bufCmd, bufResp); } catch(CardException ex){ ex.printStackTrace(); } for (int i = 0; i < output; i++) { response += String.format("%02X", baResp[i]); } return response; } @Override public void run() { //Authenticate CardTerminal terminal; CardChannel channel; try { terminal = this.InitializeTerminal(); if(this.IsCardPresent(terminal)) { channel = this.GetCardAndOpenChannel(terminal); //Returns CarChannel object (TO DO: put and store inside class) this.LoadBasicKey(channel); this.AuthenticateBlock1(channel); byte[] baRead = new byte[5]; baRead = new byte[]{(byte) 0xFF, (byte) 0xB0, (byte) 0x00, (byte) 0x01, (byte) 0x10}; //Read 16bits from block 01 String hexUser = this.SendCommand(baRead, channel); hexUser = hexUser.substring(0, hexUser.length() - 4); String stringUser = HexStringConverter.getHexStringConverterInstance().hexToString(hexUser); stringUser = stringUser.replace(".", ""); String desiredUser = "WIKTOR"; System.out.println(stringUser); if(stringUser.equals(desiredUser)){ this.isUserAuthenticated = true; this.activeUser = stringUser; setChanged(); notifyObservers(); } else { this.isUserAuthenticated = false; setChanged(); notifyObservers(); Thread.sleep(3000L); run(); } } } catch (CardException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public String getCardBalance(){ CardTerminal terminal; CardChannel channel; String currentBalanceString; try{ terminal = this.InitializeTerminal(); if(this.IsCardPresent(terminal)){ channel = this.GetCardAndOpenChannel(terminal); //Returns CarChannel object (TO DO: put and store inside class) this.AuthenticateBlock2(channel); byte[] baRead = new byte[5]; baRead = new byte[]{(byte) 0xFF, (byte) 0xB1, (byte) 0x00, (byte) 0x02, (byte) 0x04}; String currentBalanceHex = this.SendCommand(baRead, channel); System.out.println(currentBalanceHex); currentBalanceHex = currentBalanceHex.substring(0, currentBalanceHex.length() - 4); System.out.println(currentBalanceHex); currentBalanceString = HexStringConverter.getHexStringConverterInstance().hexToDecimalAsString(currentBalanceHex); this.currentCardBalance = currentBalanceString; System.out.println("Current card balance is: " + currentBalanceString); } } catch (CardException e) { // TODO Auto-generated catch block e.printStackTrace(); } return this.currentCardBalance; } public String decrementBalance(int amount) throws InterruptedException { CardTerminal terminal; CardChannel channel; String currentBalanceString; String amountStr = "0x0" + amount; try{ terminal = this.InitializeTerminal(); if(this.IsCardPresent(terminal)){ channel = this.GetCardAndOpenChannel(terminal); //Returns CarChannel object (TO DO: put and store inside class) this.AuthenticateBlock2(channel); byte[] baDecrement = new byte[10]; baDecrement = new byte[]{(byte) 0xFF, (byte) 0xD7, (byte) 0x00, (byte) 0x02, (byte) 0x05, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) Byte.decode(amountStr)}; this.SendCommand(baDecrement, channel); Thread.sleep(2000L); byte[] baRead = new byte[5]; baRead = new byte[]{(byte) 0xFF, (byte) 0xB1, (byte) 0x00, (byte) 0x02, (byte) 0x04}; String currentBalanceHex = this.SendCommand(baRead, channel); System.out.println(currentBalanceHex); currentBalanceHex = currentBalanceHex.substring(0, currentBalanceHex.length() - 4); System.out.println(currentBalanceHex); currentBalanceString = HexStringConverter.getHexStringConverterInstance().hexToDecimalAsString(currentBalanceHex); this.currentCardBalance = currentBalanceString; System.out.println("Current card balance is: " + currentBalanceString); } } catch (CardException e) { // TODO Auto-generated catch block e.printStackTrace(); } return this.currentCardBalance; } }