Package org.nfctools.spi.file

Source Code of org.nfctools.spi.file.FileMfReaderWriter

/**
* Copyright 2011-2012 Adrian Stabiszewski, as@nfctools.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*       http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.nfctools.spi.file;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.nfctools.mf.MfAccess;
import org.nfctools.mf.MfCardListener;
import org.nfctools.mf.MfException;
import org.nfctools.mf.MfLoginException;
import org.nfctools.mf.MfReaderWriter;
import org.nfctools.mf.block.BlockResolver;
import org.nfctools.mf.block.MfBlock;
import org.nfctools.mf.block.TrailerBlock;
import org.nfctools.mf.card.MfCard;
import org.nfctools.mf.card.MfCard1k;
import org.nfctools.mf.card.MfCard4k;
import org.nfctools.mf.classic.Key;
import org.nfctools.utils.NfcUtils;

public class FileMfReaderWriter implements MfReaderWriter {

  private Map<MfCard, Map<Integer, MfBlock>> cardBlockMap = new HashMap<MfCard, Map<Integer, MfBlock>>();
  private MfCardListener cardListener;

  public MfCard loadCardFromFile(String fileName) throws IOException {
    Collection<String> lines = readLinesFromFile(fileName);

    MfCard mfCard = lines.size() == 256 ? new MfCard4k(null, null) : lines.size() == 64 ? new MfCard1k(null, null)
        : null;
    if (mfCard == null)
      throw new MfException("unknown card. lines " + lines.size());

    BlockResolver blockResolver = new BlockResolver();

    Map<Integer, MfBlock> blockMap = new HashMap<Integer, MfBlock>();
    int blockNumber = 0;
    Pattern pattern = Pattern
        .compile("S(.*)\\|B(.*) Key: (............).*\\[(................................)\\]");

    for (String data : lines) {
      Matcher matcher = pattern.matcher(data);
      if (matcher.matches()) {
        int sectorId = Integer.parseInt(matcher.group(1));
        int blockId = Integer.parseInt(matcher.group(2));
        byte[] keyA = NfcUtils.convertASCIIToBin(matcher.group(3));
        byte[] blockData = NfcUtils.convertASCIIToBin(matcher.group(4));

        MfBlock resolvedBlock = blockResolver.resolveBlock(mfCard, sectorId, blockId, blockData);
        if (mfCard.isTrailerBlock(sectorId, blockId))
          System.arraycopy(keyA, 0, blockData, 0, 6);
        blockMap.put(blockNumber, resolvedBlock);
        blockNumber++;
      }
    }

    if (blockNumber == 0)
      throw new RuntimeException("not valid data for card");

    cardBlockMap.put(mfCard, blockMap);
    if (cardListener != null)
      cardListener.cardDetected(mfCard, this);

    return mfCard;
  }

  private Collection<String> readLinesFromFile(String fileName) throws IOException {
    List<String> lines = new ArrayList<String>();
    BufferedReader br = new BufferedReader(new InputStreamReader(ClassLoader.getSystemResourceAsStream(fileName)));
    while (br.ready()) {
      lines.add(br.readLine());
    }
    return lines;
  }

  @Override
  public void setCardIntoHalt(MfCard mfCard) throws IOException {
    cardBlockMap.remove(mfCard);
  }

  @Override
  public void reselectCard(MfCard mfCard) throws IOException {
  }

  @Override
  public MfBlock[] readBlock(MfAccess mfAccess) throws IOException {
    checkReadAccess(mfAccess);
    Map<Integer, MfBlock> blockMap = cardBlockMap.get(mfAccess.getCard());
    MfBlock[] blocks = new MfBlock[mfAccess.getBlocksToRead()];
    for (int x = 0; x < mfAccess.getBlocksToRead(); x++) {
      blocks[x] = blockMap.get(mfAccess.getCard().getBlockNumber(mfAccess.getSector(), mfAccess.getBlock() + x));
    }
    return blocks;
  }

  private void checkReadAccess(MfAccess mfAccess) throws IOException {
    int trailerBlockId = mfAccess.getCard().getTrailerBlockNumberForSector(mfAccess.getSector());
    Map<Integer, MfBlock> blockMap = cardBlockMap.get(mfAccess.getCard());

    TrailerBlock trailerBlock = (TrailerBlock)blockMap.get(mfAccess.getCard().getBlockNumber(mfAccess.getSector(),
        trailerBlockId));

    byte[] key = trailerBlock.getKey(mfAccess.getKey());

    if (Key.B.equals(mfAccess.getKey()) && trailerBlock.isKeyBReadable())
      throw new MfException("Cannot login with Key B. Key B is readable");

    if (!NfcUtils.isEqualArray(key, mfAccess.getKeyValue())) {
      throw new MfLoginException("Login failed. Sector: " + mfAccess.getSector() + ", Block: "
          + mfAccess.getBlock() + " Key: " + mfAccess.getKey().name() + " Given: "
          + NfcUtils.convertBinToASCII(mfAccess.getKeyValue()) + ", Expected: "
          + NfcUtils.convertBinToASCII(key));

    }
  }

  @Override
  public void writeBlock(MfAccess mfAccess, MfBlock... mfBlock) throws IOException {
    Map<Integer, MfBlock> blockMap = cardBlockMap.get(mfAccess.getCard());

    for (int currentBlock = 0; currentBlock < mfBlock.length; currentBlock++) {
      checkWriteAccess(mfAccess, mfAccess.getBlock() + currentBlock);
      int blockNumber = mfAccess.getCard().getBlockNumber(mfAccess.getSector(), mfAccess.getBlock())
          + currentBlock;
      blockMap.put(blockNumber, mfBlock[currentBlock]);
    }
  }

  private void checkWriteAccess(MfAccess mfAccess, int blockId) throws IOException {
    int trailerBlockId = mfAccess.getCard().getTrailerBlockNumberForSector(mfAccess.getSector());
    Map<Integer, MfBlock> blockMap = cardBlockMap.get(mfAccess.getCard());

    TrailerBlock trailerBlock = (TrailerBlock)blockMap.get(mfAccess.getCard().getBlockNumber(mfAccess.getSector(),
        trailerBlockId));

    byte[] key = trailerBlock.getKey(mfAccess.getKey());

    if (Key.B.equals(mfAccess.getKey()) && trailerBlock.isKeyBReadable())
      throw new MfLoginException("Cannot login with Key B. Key B is readable. Sector: " + mfAccess.getSector()
          + ", Block: " + blockId);

    int dataArea = (int)(mfAccess.getCard().getBlocksPerSector(mfAccess.getSector()) > 3 ? Math
        .floor((double)mfAccess.getCard().getBlocksPerSector(mfAccess.getSector()) / 5.0) : blockId);

    if ((blockId == trailerBlockId && !trailerBlock.canWriteTrailerBlock(mfAccess.getKey()))
        || (blockId != trailerBlockId && !trailerBlock.canWriteDataBlock(mfAccess.getKey(), dataArea))) {
      throw new MfLoginException("Write Access Denied. Sector: " + mfAccess.getSector() + ", Block: " + blockId
          + " Key: " + mfAccess.getKey().name());

    }

    if (!NfcUtils.isEqualArray(key, mfAccess.getKeyValue())) {
      throw new MfLoginException("Login failed. Sector: " + mfAccess.getSector() + ", Block: " + blockId
          + " Key: " + mfAccess.getKey().name() + " Given: "
          + NfcUtils.convertBinToASCII(mfAccess.getKeyValue()) + ", Expected: "
          + NfcUtils.convertBinToASCII(key));
    }
  }

  @Override
  public void setCardListener(MfCardListener mfCardListener) throws IOException {
    this.cardListener = mfCardListener;
  }

  @Override
  public boolean waitForCard(MfCardListener mfCardListener, int timeout) throws IOException {
    throw new UnsupportedOperationException();
  }

  @Override
  public void removeCardListener() {
    this.cardListener = null;
  }

}
TOP

Related Classes of org.nfctools.spi.file.FileMfReaderWriter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.