예제 #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();
    }
  }
예제 #2
0
 /**
  * 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;
 }
예제 #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();
    }
  }
예제 #4
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;
  }
예제 #5
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;
  }
예제 #6
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