/** * Splits an octet stream into the separate parts that would be the payloads of concatenated SMS * messages. * * @param messageBinary * @param sourcePort * @param destinationPort * @return Supplied byte[] split into parts. These parts should reconcatenate to form the original * byte array. Supplying a zero-length byte[] should return a single, empty part. */ public static byte[][] getPayloads(byte[] messageBinary, int sourcePort, int destinationPort) { if (messageBinary.length == 0) return new byte[][] {new byte[0]}; boolean isPorted = sourcePort > 0 || destinationPort > 0; int totalParts = getMessagesNeeded_8bit(messageBinary.length, isPorted); byte[][] payloadParts = new byte[totalParts][]; int udhLength = getUDHSize(true, isPorted, totalParts > 1); String encodedText = HexUtils.encode(messageBinary); for (int i = 0; i < payloadParts.length; i++) { payloadParts[i] = HexUtils.decode(extractPayload(encodedText, i + 1, udhLength)); } return payloadParts; }
public static ArrayList<String> getRecords(Reader mReader, byte[] data) { ArrayList<String> al = new ArrayList<String>(); if (data.length % 4 != 0) { Log.i("EMVUtils", "Exc in EMVUtils + data: " + HexUtils.toHexString(data)); al.add("Wrong AFL data"); return al; } Log.i("EMVUtils", "else..." + data.length); for (int i = 0; i < data.length / 4; i++) { int mSfi = data[i * 4] >>> 3; mSfi = (mSfi << 3) | 4; Log.i("EMVUtils", "mSfi: " + mSfi); int startRec = data[i * 4 + 1] & 0xFF; int endRec = data[i * 4 + 2] & 0xFF; for (int record = startRec; record <= endRec; record++) { Log.i("EMVUtils", "Read record, sfi: " + mSfi + " , record: " + record); try { String response = APDU.transmitByteCommand( mReader, new byte[] {(byte) 0x00, (byte) 0xB2, (byte) record, (byte) mSfi, (byte) 0x00}); Log.i("EMVUtils", "response: " + response); if (response.substring(response.length() - 4).equals("9000")) { al.add(response); } } catch (ReaderException e) { e.printStackTrace(); } } } return al; }
private static ByteSetPayload fetchByteSetContent( byte[] copy, ByteSet byteSet, int start, boolean read) { PayloadType payloadType = byteSet.payloadType; ByteSetPayload byteSetPayload = new ByteSetPayload(); byteSetPayload.owner = byteSet; byteSetPayload.start = start; switch (payloadType) { case TWO_BYTES: { if (start + 1 > copy.length) { throw new PhotoUtilsException( String.format( "Attempted to read byteset %s. However, it was found that the payload index was out of range", byteSet.name)); } byteSetPayload.end = start + 1; if (read) { byteSetPayload.payload = new byte[] {copy[start], copy[start + 1]}; } } case VARIABLE_LENGTH: { byte[] length = {copy[start], copy[start + 1]}; int numberOfBytesToRead = HexUtils.toInt(length[0], length[1]); byteSetPayload.start = start + 2; byteSetPayload.end = start + numberOfBytesToRead - 1; if (read) { byte[] payload = new byte[numberOfBytesToRead - 2]; int payloadIndex = 0; for (int i = start + 2; i < start + numberOfBytesToRead; i++) { payload[payloadIndex] = copy[i]; payloadIndex++; } System.out.println("Payload:" + Arrays.toString(HexUtils.bytesToHex(payload))); byteSetPayload.payload = payload; } } case NONE: { byteSetPayload.end = start; } } return byteSetPayload; }
public String preparePassword(String password) { if (messageDigest != null && this.encoding != null) { System.out.println("Cifrando password" + password); byte[] bytes = messageDigest.digest(password.getBytes()); if (this.encoding.equalsIgnoreCase("BASE64")) { bytes = Base64.encodeBase64(bytes); return new String(bytes); } else if (this.encoding.equalsIgnoreCase("HEX")) { return HexUtils.convert(bytes); } } return password; }
@Test public void shouldRenderCorrectlyWithoutAddress() throws IOException { byte[] buffer = line.getBytes("UTF-8"); StringBuilder builder = new StringBuilder(); HexUtils.dump(buffer, builder, 16); String[] lines = builder.toString().split("\n"); assertThat(lines.length, is(7)); assertThat( lines[0], is("57 6f 6e 64 65 72 69 6e 67 20 68 6f 77 20 74 68 |Wondering.how.th|")); assertThat( lines[1], is("69 73 20 77 6f 72 6b 73 20 6f 75 74 2e 20 49 20 |is.works.out..I.|")); assertThat( lines[2], is("77 6f 75 6c 64 20 65 78 70 65 63 74 20 69 74 27 |would.expect.it.|")); assertThat( lines[3], is("73 20 61 6c 6c 20 67 6f 69 6e 67 20 74 6f 20 77 |s.all.going.to.w|")); assertThat( lines[4], is("6f 72 6b 20 6f 75 74 20 66 69 6e 65 2c 20 62 75 |ork.out.fine..bu|")); assertThat( lines[5], is("74 20 69 74 27 73 20 68 61 72 64 20 74 6f 20 74 |t.it.s.hard.to.t|")); assertThat( lines[6], is("65 6c 6c |ell |")); }
private static void work(CardTerminal reader, OptionSet args) throws CardException { if (!reader.isCardPresent()) { System.out.println("No card in " + reader.getName()); return; } FileOutputStream o = null; if (args.has(OPT_DUMP)) { try { o = new FileOutputStream((File) args.valueOf(OPT_DUMP)); } catch (FileNotFoundException e) { System.err.println("Can not dump to " + args.valueOf(OPT_DUMP)); } } reader = LoggingCardTerminal.getInstance(reader, o); // This allows to override the protocol for RemoteTerminal as well. final String protocol; if (args.has(OPT_T0)) { protocol = "T=0"; } else if (args.has(OPT_T1)) { protocol = "T=1"; } else { protocol = "*"; } if (args.has(CMD_APDU)) { Card c = null; try { c = reader.connect(protocol); if (args.has(CMD_APDU)) { for (Object s : args.valuesOf(CMD_APDU)) { CommandAPDU a = new CommandAPDU(HexUtils.stringToBin((String) s)); ResponseAPDU r = c.getBasicChannel().transmit(a); if (args.has(OPT_ERROR) && r.getSW() != 0x9000) { System.out.println( "Card returned " + String.format("%04X", r.getSW()) + ", exiting!"); return; } } } } catch (CardException e) { if (TerminalManager.getExceptionMessage(e) != null) { System.out.println("PC/SC failure: " + TerminalManager.getExceptionMessage(e)); } else { throw e; } } finally { if (c != null) { c.disconnect(true); } } } else if (args.has(OPT_CONNECT)) { String remote = (String) args.valueOf(OPT_CONNECT); JSONMessagePipe transport = null; try { if (remote.startsWith("http://") || remote.startsWith("https://")) { if (args.has(OPT_PINNED)) { transport = HTTPTransport.open( new URL(remote), certFromPEM(((File) args.valueOf(OPT_PINNED)).getPath())); } else { transport = HTTPTransport.open(new URL(remote), null); } } else { transport = SocketTransport.connect(string2socket(remote), null); } // Connect the transport and the terminal CmdlineRemoteTerminal c = new CmdlineRemoteTerminal(transport, reader); c.forceProtocol(protocol); // Run c.run(); } catch (IOException e) { System.err.println("Communication error: " + e.getMessage()); } finally { if (transport != null) transport.close(); } } }
public static void main(String[] argv) throws Exception { OptionSet args = parseOptions(argv); if (args.has(OPT_VERBOSE)) { verbose = true; // Set up slf4j simple in a way that pleases us System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "debug"); System.setProperty("org.slf4j.simpleLogger.showThreadName", "true"); System.setProperty("org.slf4j.simpleLogger.showShortLogName", "true"); System.setProperty("org.slf4j.simpleLogger.levelInBrackets", "true"); } else { System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "warn"); } if (args.has(OPT_VERSION)) { String version = "apdu4j " + getVersion(SCTool.class); // Append host information version += "\nRunning on " + System.getProperty("os.name"); version += " " + System.getProperty("os.version"); version += " " + System.getProperty("os.arch"); version += ", Java " + System.getProperty("java.version"); version += " by " + System.getProperty("java.vendor"); System.out.println(version); } if (args.has(OPT_TEST_SERVER)) { // TODO: have the possibility to run SocketServer as well? RemoteTerminalServer srv = new RemoteTerminalServer(TestServer.class); srv.start(string2socket((String) args.valueOf(OPT_TEST_SERVER))); System.console().readLine("Press enter to stop\n"); srv.stop(1); System.exit(0); } // List TerminalFactory providers if (args.has(OPT_PROVIDERS)) { Provider providers[] = Security.getProviders("TerminalFactory.PC/SC"); if (providers != null) { System.out.println("Existing TerminalFactory providers:"); for (Provider p : providers) { System.out.println(p.getName()); } } } // Fix properties on non-windows platforms TerminalManager.fixPlatformPaths(); // Only applies to SunPCSC if (args.has(OPT_NO_GET_RESPONSE)) { System.setProperty("sun.security.smartcardio.t0GetResponse", "false"); System.setProperty("sun.security.smartcardio.t1GetResponse", "false"); } // Override PC/SC library path if (args.has(OPT_LIB)) { System.setProperty("sun.security.smartcardio.library", (String) args.valueOf(OPT_LIB)); } TerminalFactory tf = null; CardTerminals terminals = null; try { // Get a terminal factory if (args.has(OPT_PROVIDER)) { String pn = (String) args.valueOf(OPT_PROVIDER); String pt = (String) args.valueOf(OPT_PROVIDER_TYPE); tf = loadFactory(pn, pt); } else if (args.has(OPT_SUN)) { tf = loadFactory(SUN_CLASS, null); } else if (args.has(OPT_JNA)) { tf = loadFactory(JNA_CLASS, null); } else { tf = TerminalFactory.getDefault(); } if (verbose) { System.out.println( "# Using " + tf.getProvider().getClass().getCanonicalName() + " - " + tf.getProvider()); if (System.getProperty(TerminalManager.lib_prop) != null) { System.out.println( "# " + TerminalManager.lib_prop + "=" + System.getProperty(TerminalManager.lib_prop)); } } // Get all terminals terminals = tf.terminals(); } catch (Exception e) { // XXX: we catch generic Exception here to avoid importing JNA. // Try to get a meaningful message String msg = TerminalManager.getExceptionMessage(e); if (msg == null) msg = e.getMessage(); System.out.println("No readers: " + msg); System.exit(1); } // Terminals to work on List<CardTerminal> do_readers = new ArrayList<CardTerminal>(); try { // List Terminals if (args.has(CMD_LIST)) { List<CardTerminal> terms = terminals.list(); if (verbose) { System.out.println( "# Found " + terms.size() + " terminal" + (terms.size() == 1 ? "" : "s")); } if (terms.size() == 0) { System.err.println("No readers found"); System.exit(1); } for (CardTerminal t : terms) { String vmd = " "; try (PinPadTerminal pp = new PinPadTerminal(t)) { pp.probe(); // Verify, Modify, Display if (verbose) { vmd += "["; vmd += pp.canVerify() ? "V" : " "; vmd += pp.canModify() ? "M" : " "; vmd += pp.hasDisplay() ? "D" : " "; vmd += "] "; } } catch (CardException e) { if (verbose) { System.err.println("Could not probe PinPad: " + e.getMessage()); } } System.out.println((t.isCardPresent() ? "[*]" : "[ ]") + vmd + t.getName()); if (args.has(OPT_VERBOSE) && t.isCardPresent()) { Card c = t.connect("DIRECT"); String atr = HexUtils.encodeHexString(c.getATR().getBytes()).toUpperCase(); c.disconnect(false); System.out.println(" " + atr); if (args.has(OPT_WEB)) { String url = "http://smartcard-atr.appspot.com/parse?ATR=" + atr; if (Desktop.isDesktopSupported()) { Desktop.getDesktop().browse(new URI(url + "&from=apdu4j")); } else { System.out.println(" " + url); } } } } } // Select terminals to work on if (args.has(OPT_READER)) { String reader = (String) args.valueOf(OPT_READER); CardTerminal t = terminals.getTerminal(reader); if (t == null) { System.err.println("Reader \"" + reader + "\" not found."); System.exit(1); } do_readers = Arrays.asList(t); } else { do_readers = terminals.list(State.CARD_PRESENT); if (do_readers.size() > 1 && !args.hasArgument(OPT_ALL)) { System.err.println("More than one reader with a card found."); System.err.println("Run with --" + OPT_ALL + " to work with all found cards"); System.exit(1); } else if (do_readers.size() == 0 && !args.has(CMD_LIST)) { // But if there is a single reader, wait for a card insertion List<CardTerminal> empty = terminals.list(State.CARD_ABSENT); if (empty.size() == 1 && args.has(OPT_WAIT)) { CardTerminal rdr = empty.get(0); System.out.println("Please enter a card into " + rdr.getName()); if (!empty.get(0).waitForCardPresent(30000)) { System.out.println("Timeout."); } else { do_readers = Arrays.asList(rdr); } } else { System.err.println("No reader with a card found!"); System.exit(1); } } } } catch (CardException e) { System.out.println("Could not list readers: " + TerminalManager.getExceptionMessage(e)); e.printStackTrace(); } for (CardTerminal t : do_readers) { work(t, args); } }
/** * Generates the TPDUs for a UCS-2-encoded text message. The TPDUs are returned as hex-encoded * binary strings. * * @param messageText * @param smscNumber * @param recipientMsisdn * @param concatReferenceNumber Reference number to embed in multipart message parts' UDH * @param sourcePort * @param destinationPort * @param requestStatusReport * @param validityPeriod Validity period of this message, in hours. Maximum validity will be * requested if this is set to zero. * @param protocolIdentifier * @param dataCodingScheme * @return The PDUs to be sent for the message */ public static String[] generatePdus_ucs2( String messageText, String smscNumber, String recipientMsisdn, int concatReferenceNumber, int sourcePort, int destinationPort, boolean requestStatusReport, int validityPeriod, int protocolIdentifier, int dataCodingScheme) { boolean isPorted = sourcePort > 0 || destinationPort > 0; String[] messageParts = splitText_ucs2(messageText, isPorted); final int totalParts = messageParts.length; boolean isMultipart = totalParts > 1; boolean requiresUdh = isMultipart || isPorted; String[] pdus = new String[totalParts]; try { for (int partNumber = 1; partNumber <= totalParts; ++partNumber) { ByteArrayOutputStream out = new ByteArrayOutputStream(); out.write(encodeMsisdnAsAddressField(smscNumber, true)); // get the front byte, which identifies message content out.write(getByteZero(TP_MTI_MO_SUBMIT, requiresUdh, requestStatusReport)); // Message reference. Always zero here. /** [TP-MR: TP-Message-Reference] Parameter identifying the SMS-SUBMIT. */ out.write(0); // Add the recipient's MSISDN /** [TP-DA: TP-Destination-Address] Address of the destination SME. */ out.write(encodeMsisdnAsAddressField(recipientMsisdn, false)); /** * [TP-PID: TP-Protocol-Identifier] Parameter identifying the above layer protocol, if any. */ out.write(protocolIdentifier); /** * [TP-DCS: TP-Data-CodingScheme] Parameter identifying the coding scheme within the * TP-User-Data. */ out.write(dataCodingScheme); /** * [TP-VP: TP-Validity-Period] Parameter identifying the time from where the message is no * longer valid. Here, this is always relative. */ out.write(getRelativeVP(validityPeriod)); // Build the UD // First build the UDH /** * Total length of the udh, including the UDHL. Do not confuse with udhBytes.length, which * is the length of the UDH's content */ int udhTotalLength = getUDHSize(true, isPorted, isMultipart); byte[] encodedText = encodeUcs2Text(messageParts[partNumber - 1]); /** The length, in octets, of the user data, including the header. */ int dataLen = encodedText.length + udhTotalLength; /** [TP-UDL: TP-User-Data-Length] Length of the UD, specific to the encoding. */ out.write(dataLen); if (requiresUdh) { /** Now write the octet content of the UDH */ out.write( generateUDH( partNumber, totalParts, concatReferenceNumber, sourcePort, destinationPort)); } /** Add the MS to the PDU */ out.write(encodedText); pdus[partNumber - 1] = HexUtils.encode(out.toByteArray()); } return pdus; } catch (IOException ex) { throw new RuntimeException(ex); } }
/** * Generate PDUs for a text message encoded using {@link SmsMessageEncoding#GSM_7BIT}. * * @param messageText * @param smscNumber * @param recipientMsisdn * @param concatReferenceNumber * @param sourcePort * @param destinationPort * @param requestStatusReport * @param validityPeriod * @param protocolIdentifier * @param dataCodingScheme * @return An ordered list of PDUs encoded as hexadecimal strings which combine to recreate the * original text message. */ public static String[] generatePdus_gsm7bit( String messageText, String smscNumber, String recipientMsisdn, int concatReferenceNumber, int sourcePort, int destinationPort, boolean requestStatusReport, int validityPeriod, int protocolIdentifier, int dataCodingScheme) { boolean isPorted = sourcePort > 0 || destinationPort > 0; String[] messageParts = GsmAlphabet.splitText(messageText, isPorted); final int totalParts = messageParts.length; boolean isMultipart = totalParts > 1; boolean requiresUdh = isMultipart || isPorted; /** PDUs that make up this message, encoded as hexadecimal strings. */ String[] pdus = new String[totalParts]; try { for (int partNumber = 1; partNumber <= totalParts; ++partNumber) { ByteArrayOutputStream out = new ByteArrayOutputStream(); out.write(encodeMsisdnAsAddressField(smscNumber, true)); // get the front byte, which identifies message content out.write(getByteZero(TP_MTI_MO_SUBMIT, requiresUdh, requestStatusReport)); // Message reference. Always zero here. /** [TP-MR: TP-Message-Reference] Parameter identifying the SMS-SUBMIT. */ out.write(0); // Add the recipient's MSISDN /** [TP-DA: TP-Destination-Address] Address of the destination SME. */ out.write(encodeMsisdnAsAddressField(recipientMsisdn, false)); /** * [TP-PID: TP-Protocol-Identifier] Parameter identifying the above layer protocol, if any. */ out.write(protocolIdentifier); /** * [TP-DCS: TP-Data-CodingScheme] Parameter identifying the coding scheme within the * TP-User-Data. */ out.write(dataCodingScheme); /** * [TP-VP: TP-Validity-Period] Parameter identifying the time from where the message is no * longer valid. Here, this is always relative. */ out.write(getRelativeVP(validityPeriod)); // Build the UD // First build the UDH /** * Total length of the udh, including the UDHL. Do not confuse with udhBytes.length, which * is the length of the UDH's content */ int udhTotalLength = getUDHSize(true, isPorted, isMultipart); byte[] encodedMessageSeptets = GsmAlphabet.stringToBytes(messageParts[partNumber - 1]); /** Encode the message text using the standard 7-bit GSM alphabet. */ int skipBits = GsmAlphabet.calculateBitSkip(udhTotalLength); byte[] encodedMessageText = GsmAlphabet.septetStream2octetStream(encodedMessageSeptets, skipBits); /** * [TP-UDL: TP-User-Data-Length] Length of the UD, specific to the encoding. For a 7-bit GSM * charset message, this is the number of septets in the UD. */ int udLength = (int) Math.ceil( ((udhTotalLength * 8) + (encodedMessageSeptets.length * 7) + skipBits) / 7.0); out.write(udLength); if (requiresUdh) { /** Now write the octet content of the UDH */ out.write( generateUDH( partNumber, totalParts, concatReferenceNumber, sourcePort, destinationPort)); } out.write(encodedMessageText); pdus[partNumber - 1] = HexUtils.encode(out.toByteArray()); } return pdus; } catch (IOException ex) { throw new RuntimeException(ex); } }