Exemplo n.º 1
0
  /**
   * Write all the blocks in a Tag to the Mifare tag.
   *
   * @param t
   * @throws IOException
   */
  public void write(Tag t) throws IOException {

    if (t.getSectorCount() > mKeys.getSectorCount()) throw new IOException("Too few keys");

    mTag.connect();

    int sectors = mTag.getSectorCount();

    try {

      for (int s = 0; s < sectors; ++s) {

        // Authenticate for each sector (try B key, then A key)
        if (!mTag.authenticateSectorWithKeyB(s, mKeys.getKeyB(s))
            && !mTag.authenticateSectorWithKeyA(s, mKeys.getKeyA(s)))
          throw new IOException("Auth error");

        // Write to tag. Skip block 0 and the trailer of each sector
        int blockOffset = mTag.sectorToBlock(s);
        int lastBlock = blockOffset + mTag.getBlockCountInSector(s);

        // Skip block 0
        blockOffset = blockOffset == 0 ? 1 : blockOffset;

        for (int b = blockOffset; b < lastBlock; ++b) {
          mTag.writeBlock(b, t.getBlock(b));
          if (mProgressListener != null)
            mProgressListener.publishProgress((100 * b) / t.getBlockCount());
        }
      }
    } finally {
      mTag.close();
    }
  }
Exemplo n.º 2
0
  private void resolveIntent(Intent intent) {
    String action = intent.getAction();
    toast("resolving intent");
    if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
      toast("RESOLVE THIS INTENT");
      Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
      receiveTab.append("\nResolve Intent for NDEF discovery");
    } else if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {
      Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
      MifareClassic mfc = MifareClassic.get(tagFromIntent);
      byte[] data;
      receiveTab.append("\nNew tech tag received");
      try {
        mfc.connect();
        boolean auth = false;
        String cardData = null;
        int secCount = mfc.getSectorCount();
        int bCount = 0;
        int bIndex = 0;
        for (int j = 0; j < secCount; j++) {
          auth = mfc.authenticateSectorWithKeyA(j, MifareClassic.KEY_DEFAULT);
          if (auth) {
            bCount = mfc.getBlockCountInSector(j);
            bIndex = 0;
            for (int i = 0; i < bCount; i++) {
              bIndex = mfc.sectorToBlock(j);
              data = mfc.readBlock(bIndex);
              cardData = new String(data);
              receiveTab.append("\n" + cardData);
              bIndex++;
            }
          } else {
            Toast.makeText(this, "Auth failed", Toast.LENGTH_LONG).show();
          }
        }
      } catch (IOException ex) {
        Toast.makeText(this, "IO Error while attempting to read mifare", Toast.LENGTH_LONG).show();
      }
    } else if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) {
      receiveTab.append("\nSome Tag found from card");
      Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);

      receiveTab.append("\n" + tagFromIntent.toString());
      for (int k = 0; k < tagFromIntent.getTechList().length; k++) {
        receiveTab.append("\nTech List: " + tagFromIntent.getTechList()[k]);
        if (tagFromIntent.getTechList()[k].equals("android.nfc.tech.NfcA")) {
          // Run connection method
          parseNfcATag(tagFromIntent);
          // connectToNDEF(tagFromIntent);
          // parseMifareTag(tagFromIntent);
        } else if (tagFromIntent.getTechList()[k].equals("android.nfc.tech.Ndef")) {
          connectToNDEF(tagFromIntent);
          // receiveTab.append("\nRun connect to NDEF");
        }
      }
    }
  }
Exemplo n.º 3
0
  /**
   * Read all blocks from the Mifare tag and return the data in a Tag object.
   *
   * @return A Tag object containing the data of the Mifare tag.
   * @throws IOException
   */
  public Tag read() throws IOException {

    int sectors = mTag.getSectorCount();
    Tag t = new Tag(TagType.getType(sectors));

    if (t.getSectorCount() > mKeys.getSectorCount()) throw new IOException("Too few keys");

    mTag.connect();

    try {

      for (int s = 0; s < sectors; ++s) {

        byte[] aKey = mKeys.getKeyA(s);
        byte[] bKey = mKeys.getKeyB(s);

        // Authenticate for each sector (try A key, then B key)
        if (!mTag.authenticateSectorWithKeyA(s, aKey) && !mTag.authenticateSectorWithKeyB(s, bKey))
          throw new IOException("Auth error");

        // Read every block of the sector
        int blockOffset = mTag.sectorToBlock(s);
        int lastBlock = blockOffset + mTag.getBlockCountInSector(s);
        for (int b = blockOffset; b < lastBlock; ++b) {
          byte[] readBuffer = mTag.readBlock(b);

          // Manually transfer key data to tag since it is usually not
          // readable
          if (b == lastBlock - 1) {
            for (int i = 0; i < Tag.KEY_SIZE; ++i) {
              readBuffer[i] = aKey[i];
              readBuffer[Tag.BLOCK_SIZE - Tag.KEY_SIZE + i] = bKey[i];
            }
          }

          t.setBlock(b, readBuffer);
          if (mProgressListener != null)
            mProgressListener.publishProgress((100 * b) / t.getBlockCount());
        }
      }

      return t;

    } finally {
      mTag.close();
    }
  }
Exemplo n.º 4
0
 /**
  * Write a block of 16 byte data to tag.
  *
  * @param sectorIndex The sector to where the data should be written
  * @param blockIndex The block to where the data should be written
  * @param data 16 byte of data.
  * @param key The Mifare Classic key for the given sector.
  * @param useAsKeyB If true, key will be treated as key B for authentication.
  * @return The return codes are:<br>
  *     <ul>
  *       <li>0 - Everything went fine.
  *       <li>1 - Sector index is out of range.
  *       <li>2 - Block index is out of range.
  *       <li>3 - Data are not 16 byte.
  *       <li>4 - Authentication went wrong.
  *       <li>-1 - Error while writing to tag.
  *     </ul>
  *
  * @see #authenticate(int, byte[], boolean)
  */
 public int writeBlock(
     int sectorIndex, int blockIndex, byte[] data, byte[] key, boolean useAsKeyB) {
   if (mMFC.getSectorCount() - 1 < sectorIndex) {
     return 1;
   }
   if (mMFC.getBlockCountInSector(sectorIndex) - 1 < blockIndex) {
     return 2;
   }
   if (data.length != 16) {
     return 3;
   }
   if (!authenticate(sectorIndex, key, useAsKeyB)) {
     return 4;
   }
   // Write block.
   int block = mMFC.sectorToBlock(sectorIndex) + blockIndex;
   try {
     mMFC.writeBlock(block, data);
   } catch (IOException e) {
     Log.e(LOG_TAG, "Error while writing block to tag.", e);
     return -1;
   }
   return 0;
 }
Exemplo n.º 5
0
  /**
   * This method checks if the present tag is writable with the provided keys on the given positions
   * (sectors, blocks). This is done by authenticating with one of the keys followed by reading and
   * interpreting ({@link Common#getOperationInfoForBlock(byte, byte, byte,
   * de.syss.MifareClassicTool.Common.Operations, boolean, boolean)}) of the Access Conditions.
   *
   * @param pos A map of positions (key = sector, value = Array of blocks). For each of these
   *     positions you will get the write information (see return values).
   * @param keyMap A key map a generated by {@link Activities.KeyMapCreator}.
   * @return A map within a map (all with type = Integer). The key of the outer map is the sector
   *     number and the value is another map with key = block number and value = write information.
   *     The write information indicates which key is needed to write to the present tag on the
   *     given position.<br>
   *     <br>
   *     Write informations are:<br>
   *     <ul>
   *       <li>0 - Never
   *       <li>1 - Key A
   *       <li>2 - Key B
   *       <li>3 - Key A|B
   *       <li>4 - Key A, but AC never
   *       <li>5 - Key B, but AC never
   *       <li>6 - Key B, but keys never
   *       <li>-1 - Error
   *       <li>Inner map == null - Whole sector is dead (IO Error) or ACs are incorrect
   *       <li>null - Authentication error
   *     </ul>
   */
  public HashMap<Integer, HashMap<Integer, Integer>> isWritableOnPositions(
      HashMap<Integer, int[]> pos, SparseArray<byte[][]> keyMap) {
    HashMap<Integer, HashMap<Integer, Integer>> ret =
        new HashMap<Integer, HashMap<Integer, Integer>>();
    for (int i = 0; i < keyMap.size(); i++) {
      int sector = keyMap.keyAt(i);
      if (pos.containsKey(sector)) {
        byte[][] keys = keyMap.get(sector);
        byte[] ac = null;
        // Authenticate.
        if (keys[0] != null) {
          if (authenticate(sector, keys[0], false) == false) {
            return null;
          }
        } else if (keys[1] != null) {
          if (authenticate(sector, keys[1], true) == false) {
            return null;
          }
        } else {
          return null;
        }
        // Read Mifare Access Conditions.
        int acBlock = mMFC.sectorToBlock(sector) + mMFC.getBlockCountInSector(sector) - 1;
        try {
          ac = mMFC.readBlock(acBlock);
        } catch (IOException e) {
          ret.put(sector, null);
          continue;
        }
        ac = Arrays.copyOfRange(ac, 6, 9);
        byte[][] acMatrix = Common.acBytesToACMatrix(ac);
        if (acMatrix == null) {
          ret.put(sector, null);
          continue;
        }
        boolean isKeyBReadable =
            Common.isKeyBReadable(acMatrix[0][3], acMatrix[1][3], acMatrix[2][3]);

        // Check all Blocks with data (!= null).
        HashMap<Integer, Integer> blockWithWriteInfo = new HashMap<Integer, Integer>();
        for (int block : pos.get(sector)) {
          if ((block == 3 && sector <= 31) || (block == 15 && sector >= 32)) {
            // Sector Trailer.
            // Are the Access Bits writable?
            int acValue =
                Common.getOperationInfoForBlock(
                    acMatrix[0][3],
                    acMatrix[1][3],
                    acMatrix[2][3],
                    Common.Operations.WriteAC,
                    true,
                    isKeyBReadable);
            // Is key A writable? (If so, key B will be writable
            // with the same key.)
            int keyABValue =
                Common.getOperationInfoForBlock(
                    acMatrix[0][3],
                    acMatrix[1][3],
                    acMatrix[2][3],
                    Common.Operations.WriteKeyA,
                    true,
                    isKeyBReadable);

            int result = keyABValue;
            if (acValue == 0 && keyABValue != 0) {
              // Write key found, but ac-bits are not writable.
              result += 3;
            } else if (acValue == 2 && keyABValue == 0) {
              // Access Bits are writable with key B,
              // but keys are not writable.
              result = 6;
            }
            blockWithWriteInfo.put(block, result);
          } else {
            // Data block.
            int acBitsForBlock = block;
            // Handle Mifare Classic 4k Tags.
            if (sector >= 32) {
              if (block >= 0 && block <= 4) {
                acBitsForBlock = 0;
              } else if (block >= 5 && block <= 9) {
                acBitsForBlock = 1;
              } else if (block >= 10 && block <= 14) {
                acBitsForBlock = 2;
              }
            }
            blockWithWriteInfo.put(
                block,
                Common.getOperationInfoForBlock(
                    acMatrix[0][acBitsForBlock],
                    acMatrix[1][acBitsForBlock],
                    acMatrix[2][acBitsForBlock],
                    Common.Operations.Write,
                    false,
                    isKeyBReadable));
          }
        }
        if (blockWithWriteInfo.size() > 0) {
          ret.put(sector, blockWithWriteInfo);
        }
      }
    }
    return ret;
  }
Exemplo n.º 6
0
  /**
   * Read a as much as possible from a sector with the given key. Best results are gained from a
   * valid key B (except key B is marked as readable in the access conditions).
   *
   * @param sectorIndex Index of the Sector to read. (For Mifare Classic 1K: 0-63)
   * @param key Key for the authentication.
   * @param useAsKeyB If true, key will be treated as key B for authentication.
   * @return Array of blocks (index 0-3 or 0-15). If a block or a key is marked with {@link
   *     #NO_DATA} or {@link #NO_KEY} it means that this data could be read or found. On
   *     authentication error "null" will be returned.
   * @throws TagLostException When tag is lost.
   * @see #mergeSectorData(String[], String[])
   */
  public String[] readSector(int sectorIndex, byte[] key, boolean useAsKeyB)
      throws TagLostException {
    boolean auth = authenticate(sectorIndex, key, useAsKeyB);
    String[] ret = null;
    // Read sector.
    if (auth) {
      // Read all blocks.
      ArrayList<String> blocks = new ArrayList<String>();
      int firstBlock = mMFC.sectorToBlock(sectorIndex);
      int lastBlock = firstBlock + 4;
      if (mMFC.getSize() == MifareClassic.SIZE_4K && sectorIndex > 31) {
        lastBlock = firstBlock + 16;
      }
      for (int i = firstBlock; i < lastBlock; i++) {
        try {
          byte blockBytes[] = mMFC.readBlock(i);
          // mMFC.readBlock(i) must return 16 bytes or throw an error.
          // At least this is what the documentation says.
          // On Samsungs Galaxy S5 however, it sometimes
          // returns < 16 bytes for unknown reasons.
          if (blockBytes.length != 16) {
            throw new IOException();
          }
          blocks.add(Common.byte2HexString(blockBytes));
        } catch (TagLostException e) {
          throw e;
        } catch (IOException e) {
          // Could not read block.
          // (Maybe due to key/authentication method.)
          Log.d(LOG_TAG, "Error while reading block " + i + " from tag.");
          blocks.add(NO_DATA);
          if (!mMFC.isConnected()) {
            throw new TagLostException("Tag removed during readSector(...)");
          }
          // After error reauthentication is needed.
          auth = authenticate(sectorIndex, key, useAsKeyB);
        }
      }
      ret = blocks.toArray(new String[blocks.size()]);
      int last = ret.length - 1;

      // Merge key in last block (sector trailer).
      if (!useAsKeyB) {
        if (isKeyBReadable(Common.hexStringToByteArray(ret[last].substring(12, 20)))) {
          ret[last] = Common.byte2HexString(key) + ret[last].substring(12, 32);
        } else {
          ret[last] = Common.byte2HexString(key) + ret[last].substring(12, 20) + NO_KEY;
        }
      } else {
        if (ret[0].equals(NO_DATA)) {
          // If Key B may be read in the corresponding Sector Trailer,
          // it cannot serve for authentication (according to NXP).
          // What they mean is that you can authenticate successfully,
          // but can not read data. In this case the
          // readBlock() result is 0 for each block.
          ret = null;
        } else {
          ret[last] = NO_KEY + ret[last].substring(12, 20) + Common.byte2HexString(key);
        }
      }
    }
    return ret;
  }
Exemplo n.º 7
0
  private void resolveIntent(Intent intent) {
    // 1) Parse the intent and get the action that triggered this intent
    String action = intent.getAction();
    // 2) Check if it was triggered by a tag discovered interruption.
    if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {

      mydialog = ProgressDialog.show(ReadCardActivity.this, "loading", "loading");

      // 3) Get an instance of the TAG from the NfcAdapter
      Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
      // 4) Get an instance of the Mifare classic card from this TAG
      // intent
      MifareClassic mfc = MifareClassic.get(tagFromIntent);
      MifareClassCard mifareClassCard = null;

      try {
        // 5.1) Connect to card
        mfc.connect();

        // 5.2) and get the number of sectors this card has..and loop
        // thru these sectors
        int secCount = mfc.getSectorCount();
        mifareClassCard = new MifareClassCard(secCount);

        // init information
        String techtemp = "";
        for (String tech : mfc.getTag().getTechList()) {
          techtemp = techtemp + tech + "\n";
        }

        mifareClassCard.addValue("UID", Converter.getHexString(mfc.getTag().getId()));
        mifareClassCard.addValue("TechList", techtemp);
        // mifareClassCard.addValue("MemorySize", mfc.get);

        int bCount = 0;
        int bIndex = 0;
        for (int j = 0; j < secCount; j++) {
          boolean authKeyA = false;
          boolean authKeyB = false;

          MifareSector mifareSector = new MifareSector();
          mifareSector.sectorIndex = j;
          // 6.1) authenticate the sector

          for (String key : defaultKeys) {
            if (!authKeyA) {
              authKeyA = mfc.authenticateSectorWithKeyA(j, Converter.hexStringToByteArray(key));
              mifareSector.keyA = new MifareKey(Converter.hexStringToByteArray(key));
            }

            if (!authKeyB) {
              authKeyB = mfc.authenticateSectorWithKeyB(j, Converter.hexStringToByteArray(key));
              mifareSector.keyB = new MifareKey(Converter.hexStringToByteArray(key));
            }

            // 都满足则break
            if (authKeyA && authKeyB) {
              break;
            }
          }

          if ((authKeyA && authKeyB) || authKeyA || authKeyB) {
            mifareSector.authorized = true;

            // 6.2) In each sector - get the block count
            bCount = mfc.getBlockCountInSector(j);
            bCount = Math.min(bCount, MifareSector.BLOCKCOUNT);
            bIndex = mfc.sectorToBlock(j);

            // set access condition
            byte[] acdata = mfc.readBlock(bIndex + 3);
            String hexString = Converter.getHexString(acdata, 16);
            mifareSector.accessCondition = hexString.substring(12, 20);

            for (int i = 0; i < bCount; i++) {

              // 6.3) Read the block
              byte[] data = mfc.readBlock(bIndex);
              // System.out.println(Converter.getHexString(data, 16));
              MifareBlock mifareBlock = new MifareBlock(mifareSector);
              mifareBlock.setData(data);
              mifareBlock.setIndex(bIndex);
              // 7) Convert the data into a string from Hex
              // format.

              bIndex++;
              mifareSector.blocks[i] = mifareBlock;
            }
            mifareClassCard.setSector(mifareSector.sectorIndex, mifareSector);
          } else { // Authentication failed - Handle it
            mifareSector.authorized = false;
          }
        }
        this.mydialog.dismiss();
        mfc.close();
        Intent dataIntent = new Intent(this, ViewCardActivity.class);
        Bundle bundle = new Bundle();
        bundle.putSerializable("mifare", mifareClassCard);
        dataIntent.putExtras(bundle);
        this.startActivityForResult(dataIntent, 0);
        this.finish();
      } catch (IOException e) {
        Log.e(TAG, e.getLocalizedMessage());
        showAlert(3);
        this.mydialog.dismiss();
      } finally {

        if (mifareClassCard != null) {
          // mifareClassCard.debugPrint();
        }
      }
    } // End of IF
  } // End of method