Esempio n. 1
0
 private void parseMifareTag(Tag tag) {
   MifareClassic mfc = MifareClassic.get(tag);
   try {
     mfc.connect();
     receiveTab.append("\nThis worked for Mifare");
   } catch (IOException ex) {
     receiveTab.append("\nMifare read attempt threw an error");
   }
 }
 /**
  * Authenticate to given sector of the tag.
  *
  * @param sectorIndex The sector to authenticate to.
  * @param key Key for the authentication.
  * @param useAsKeyB If true, key will be treated as key B for authentication.
  * @return True if authentication was successful. False otherwise.
  */
 private boolean authenticate(int sectorIndex, byte[] key, boolean useAsKeyB) {
   try {
     if (!useAsKeyB) {
       // Key A.
       return mMFC.authenticateSectorWithKeyA(sectorIndex, key);
     } else {
       // Key B.
       return mMFC.authenticateSectorWithKeyB(sectorIndex, key);
     }
   } catch (IOException e) {
     Log.d(LOG_TAG, "Error while authenticate with tag.");
   }
   return false;
 }
Esempio n. 3
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();
    }
  }
 /** Close the connection between reader an tag. */
 public void close() {
   try {
     mMFC.close();
   } catch (IOException e) {
     Log.d(LOG_TAG, "Error on closing tag.");
   }
 }
Esempio n. 5
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");
        }
      }
    }
  }
 /** Connect the reader to the tag. */
 public void connect() throws IOException {
   try {
     mMFC.connect();
   } catch (IOException e) {
     Log.d(LOG_TAG, "Error while connecting to tag.");
     throw e;
   }
 }
 @Override
 protected String doInBackground(Intent... params) {
   Intent mIntent = params[0];
   Tag tagFromIntent = mIntent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
   MifareClassic tag = MifareClassic.get(tagFromIntent);
   try {
     tag.connect();
   } catch (IOException e) {
     // Die Karte wurde schnell entfernt, ist nicht schlimm,  wir brauchen an
     // dieser Stelle nichts zu tun, es ist vorgesehen, dass es einfach weiter geht.
   }
   while (tag.isConnected()) {
     // Hier passiert nichts! Waehrend dieser Schleife werden naemlich
     // die Daten des Fahrers dargestellt. Man bleibt in der Schleife,
     // so lange man den Tag an dem NFC-Lesegeraet haelt. Wird der Tag
     // vom Lesegeraet entfernt, dann verlassen wir die Schleife.
   }
   return null;
 }
 /**
  * Set the mapping range for {@link #buildNextKeyMapPart()}.
  *
  * @param firstSector Index of the first sector of the key map.
  * @param lastSector Index of the last sector of the key map.
  * @return True if range parameters were correct. False otherwise.
  */
 public boolean setMappingRange(int firstSector, int lastSector) {
   if (firstSector >= 0 && lastSector < mMFC.getSectorCount() && firstSector <= lastSector) {
     mFirstSector = firstSector;
     mLastSector = lastSector;
     // Init. status of buildNextKeyMapPart to create a new key map.
     mKeyMapStatus = lastSector + 1;
     return true;
   }
   return false;
 }
Esempio n. 9
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();
    }
  }
Esempio n. 10
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;
 }
Esempio n. 11
0
  /**
   * Test if all the keys in the KeyChain are valid, i.e. can be used for authenticating.
   *
   * @return true if all A and B keys can be used to authenticate, false otherwise.
   * @throws IOException
   */
  public boolean testKeys() throws IOException {

    // Tag and key sector count mismatch.
    // Need at least as many keys as there are sectors.
    if (mTag.getSectorCount() > mKeys.getSectorCount()) return false;

    mTag.connect();

    try {
      for (int i = 0; i < mTag.getSectorCount(); ++i) {
        if (!mTag.authenticateSectorWithKeyA(i, mKeys.getKeyA(i))
            || !mTag.authenticateSectorWithKeyB(i, mKeys.getKeyB(i))) {
          return false;
        }
      }
    } finally {
      mTag.close();
    }

    return true;
  }
Esempio n. 12
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;
  }
Esempio n. 13
0
  /**
   * Build Key-Value Pairs in which keys represent the sector and values are one or both of the
   * Mifare keys (A/B). The Mifare key information must be set before calling this method (use
   * {@link #setKeyFile(File[], Context)}). Also the mapping range must be specified before calling
   * this method (use {@link #setMappingRange(int, int)}).<br>
   * <br>
   * The mapping works like some kind of dictionary attack. All keys are checked against the next
   * sector with both authentication methods (A/B). If at least one key was found for a sector, the
   * map will be extended with an entry, containing the key(s) and the information for what sector
   * the key(s) are. You can get this Key-Value Pairs by calling {@link #getKeyMap()}. A full key
   * map can be gained by calling this method as often as there are sectors on the tag (See {@link
   * #getSectorCount()}). If you call this method once more after a full key map was created, it
   * resets the key map an starts all over.
   *
   * @return The sector that was checked at the moment. On error it returns "-1" and resets the key
   *     map to "null".
   * @see #getKeyMap()
   * @see #setKeyFile(File[], Context)
   * @see #setMappingRange(int, int)
   * @see #readAsMuchAsPossible(SparseArray)
   */
  public int buildNextKeyMapPart() {
    // Clear status and key map before new walk through sectors.
    boolean error = false;
    if (mKeysWithOrder != null && mLastSector != -1) {
      if (mKeyMapStatus == mLastSector + 1) {
        mKeyMapStatus = mFirstSector;
        mKeyMap = new SparseArray<byte[][]>();
      }

      // Get auto reconnect setting.
      boolean autoReconnect =
          Common.getPreferences().getBoolean(Preference.AutoReconnect.toString(), false);

      byte[][] keys = new byte[2][];
      boolean[] foundKeys = new boolean[] {false, false};

      // Check next sector against all keys (lines) with
      // authentication method A and B.
      for (int i = 0; i < mKeysWithOrder.size(); ) {
        byte[] key = mKeysWithOrder.get(i);
        try {
          if (!foundKeys[0] && mMFC.authenticateSectorWithKeyA(mKeyMapStatus, key)) {
            keys[0] = key;
            foundKeys[0] = true;
          }
          if (!foundKeys[1] && mMFC.authenticateSectorWithKeyB(mKeyMapStatus, key)) {
            keys[1] = key;
            foundKeys[1] = true;
          }
        } catch (Exception e) {
          Log.d(LOG_TAG, "Error while building next key map part");
          // Is auto reconnect enabled?
          if (autoReconnect) {
            Log.d(LOG_TAG, "Auto recconect is enabled");
            while (!isConnected()) {
              // Sleep for 500ms.
              try {
                Thread.sleep(500);
              } catch (InterruptedException ex) {
                // Do nothing.
              }
              // Try to reconnect.
              try {
                connect();
              } catch (IOException ex) {
                // Do nothing.
              }
            }
            // Repeat last loop (do not incr. i).
            continue;
          } else {
            error = true;
            break;
          }
        }
        if (foundKeys[0] && foundKeys[1]) {
          // Both keys found. Continue with next sector.
          break;
        }
        i++;
      }
      if (!error && (foundKeys[0] || foundKeys[1])) {
        // At least one key found. Add key(s).
        mKeyMap.put(mKeyMapStatus, keys);
        // Key reuse is very likely, so try these first
        // for the next sector.
        if (foundKeys[0]) {
          mKeysWithOrder.remove(keys[0]);
          mKeysWithOrder.add(0, keys[0]);
        }
        if (foundKeys[1]) {
          mKeysWithOrder.remove(keys[1]);
          mKeysWithOrder.add(0, keys[1]);
        }
      }
      mKeyMapStatus++;
    } else {
      error = true;
    }

    if (error) {
      mKeyMapStatus = 0;
      mKeyMap = null;
      return -1;
    }
    return mKeyMapStatus - 1;
  }
Esempio n. 14
0
 /**
  * Return the block count in a specific sector.
  *
  * @param sectorIndex Index of a sector.
  * @return Block count in given sector.
  */
 public int getBlockCountInSector(int sectorIndex) {
   return mMFC.getBlockCountInSector(sectorIndex);
 }
Esempio n. 15
0
 /**
  * Check if the reader is connected to the tag.
  *
  * @return True if the reader is connected. False otherwise.
  */
 public boolean isConnected() {
   return mMFC.isConnected();
 }
Esempio n. 16
0
 /**
  * Return the block count of the Mifare Classic tag.
  *
  * @return The block count of the current tag.
  */
 public int getBlockCount() {
   return mMFC.getBlockCount();
 }
Esempio n. 17
0
 /**
  * Return the sector count of the Mifare Classic tag.
  *
  * @return The sector count of the current tag.
  */
 public int getSectorCount() {
   return mMFC.getSectorCount();
 }
Esempio n. 18
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
Esempio n. 19
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;
  }
Esempio n. 20
0
 /**
  * Initialize a Mifare Classic reader for the given tag.
  *
  * @param tag The tag to operate on.
  */
 private MCReader(Tag tag) {
   mTag = tag;
   mMFC = MifareClassic.get(mTag);
 }
Esempio n. 21
0
 @Override
 protected void writeChunk(int chunkIndex, byte[] chunk) throws IOException {
   mifareTag.writeBlock(chunkIndex, chunk);
 }
Esempio n. 22
0
 /**
  * Return the size of the Mifare Classic tag in bit. (e.g. Mifare Classic 1k = 1024)
  *
  * @return The size of the current tag.
  */
 public int getSize() {
   return mMFC.getSize();
 }