/**
   * 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;
  }
Exemple #2
0
  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;
  }
Exemple #5
0
 @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             |"));
 }
Exemple #6
0
  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();
      }
    }
  }
Exemple #7
0
  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);
    }
  }