+++ /dev/null
-/*
- * Utils.java
- *
- * Copyright (C) 2011 Eric Butler
- *
- * Authors:
- * Eric Butler <eric@codebutler.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.codebutler.farebot;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.util.Log;
-import android.view.WindowManager;
-
-import com.codebutler.farebot.card.desfire.DesfireException;
-import com.codebutler.farebot.card.desfire.DesfireFileSettings;
-import com.codebutler.farebot.card.desfire.DesfireProtocol;
-
-import org.w3c.dom.Node;
-
-import java.io.StringWriter;
-import java.util.List;
-
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Result;
-import javax.xml.transform.Source;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-
-public class Utils {
-
- private static final String TAG = Utils.class.getName();
-
- public static void showError (final Activity activity, Exception ex) {
- Log.e(activity.getClass().getName(), ex.getMessage(), ex);
- new AlertDialog.Builder(activity)
- .setMessage(Utils.getErrorMessage(ex))
- .show();
- }
-
- public static void showErrorAndFinish (final Activity activity, Exception ex) {
- try {
- Log.e(activity.getClass().getName(), Utils.getErrorMessage(ex));
- ex.printStackTrace();
-
- new AlertDialog.Builder(activity)
- .setMessage(Utils.getErrorMessage(ex))
- .setCancelable(false)
- .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface arg0, int arg1) {
- activity.finish();
- }
- })
- .show();
- } catch (WindowManager.BadTokenException unused) {
- /* Ignore... happens if the activity was destroyed */
- }
- }
-
- public static String getHexString (byte[] b) throws Exception {
- String result = "";
- for (int i=0; i < b.length; i++) {
- result += Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 );
- }
- return result;
- }
-
- public static String getHexString (byte[] b, String defaultResult) {
- try {
- return getHexString(b);
- } catch (Exception ex) {
- return defaultResult;
- }
- }
-
- public static byte[] hexStringToByteArray (String s) {
- if ((s.length() % 2) != 0) {
- throw new IllegalArgumentException("Bad input string: " + s);
- }
-
- int len = s.length();
- byte[] data = new byte[len / 2];
- for (int i = 0; i < len; i += 2) {
- data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
- + Character.digit(s.charAt(i+1), 16));
- }
- return data;
- }
-
- /*
- public static byte[] intToByteArray(int value) {
- return new byte[] {
- (byte)(value >>> 24),
- (byte)(value >>> 16),
- (byte)(value >>> 8),
- (byte)value};
- }
- */
-
- public static int byteArrayToInt(byte[] b) {
- return byteArrayToInt(b, 0);
- }
-
- public static int byteArrayToInt(byte[] b, int offset) {
- return byteArrayToInt(b, offset, b.length);
- }
-
- public static int byteArrayToInt(byte[] b, int offset, int length) {
- return (int) byteArrayToLong(b, offset, length);
- }
-
- public static long byteArrayToLong(byte[] b, int offset, int length) {
- if (b.length < length)
- throw new IllegalArgumentException("length must be less than or equal to b.length");
-
- long value = 0;
- for (int i = 0; i < length; i++) {
- int shift = (length - 1 - i) * 8;
- value += (b[i + offset] & 0x000000FF) << shift;
- }
- return value;
- }
-
- public static byte[] byteArraySlice(byte[] b, int offset, int length) {
- byte[] ret = new byte[length];
- for (int i = 0; i < length; i++)
- ret[i] = b[offset+i];
- return ret;
- }
-
- public static String xmlNodeToString (Node node) throws Exception {
- // The amount of code required to do simple things in Java is incredible.
- Source source = new DOMSource(node);
- StringWriter stringWriter = new StringWriter();
- Result result = new StreamResult(stringWriter);
- TransformerFactory factory = TransformerFactory.newInstance();
- Transformer transformer = factory.newTransformer();
- transformer.setOutputProperty(OutputKeys.INDENT, "yes");
- transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
- transformer.setURIResolver(null);
- transformer.transform(source, result);
- return stringWriter.getBuffer().toString();
- }
-
- public static String getErrorMessage (Throwable ex) {
- String errorMessage = ex.getLocalizedMessage();
- if (errorMessage == null)
- errorMessage = ex.getMessage();
- if (errorMessage == null)
- errorMessage = ex.toString();
-
- if (ex.getCause() != null) {
- String causeMessage = ex.getCause().getLocalizedMessage();
- if (causeMessage == null)
- causeMessage = ex.getCause().getMessage();
- if (causeMessage == null)
- causeMessage = ex.getCause().toString();
-
- if (causeMessage != null)
- errorMessage += ": " + causeMessage;
- }
-
- return errorMessage;
- }
-
-
- public static <T> T findInList(List<T> list, Matcher<T> matcher) {
- for (T item : list) {
- if (matcher.matches(item)) {
- return item;
- }
- }
- return null;
- }
-
- public static interface Matcher<T> {
- public boolean matches(T t);
- }
-
- public static int convertBCDtoInteger(byte data) {
- return (((data & (char)0xF0) >> 4) * 10) + ((data & (char)0x0F));
- }
-
- public static int getBitsFromInteger(int buffer, int iStartBit, int iLength) {
- return (buffer >> (iStartBit)) & ((char)0xFF >> (8 - iLength));
- }
-
- /* Based on function from mfocGUI by 'Huuf' (http://www.huuf.info/OV/) */
- public static int getBitsFromBuffer(byte[] buffer, int iStartBit, int iLength) {
- int iEndBit = iStartBit + iLength - 1;
- int iSByte = iStartBit / 8;
- int iSBit = iStartBit % 8;
- int iEByte = iEndBit / 8;
- int iEBit = iEndBit % 8;
-
- if (iSByte == iEByte) {
- return (int)(((char)buffer[iEByte] >> (7 - iEBit)) & ((char)0xFF >> (8 - iLength)));
- } else {
- int uRet = (((char)buffer[iSByte] & (char)((char)0xFF >> iSBit)) << (((iEByte - iSByte - 1) * 8) + (iEBit + 1)));
-
- for (int i = iSByte + 1; i < iEByte; i++) {
- uRet |= (((char)buffer[i] & (char)0xFF) << (((iEByte - i - 1) * 8) + (iEBit + 1)));
- }
-
- uRet |= (((char)buffer[iEByte] & (char)0xFF)) >> (7 - iEBit);
-
- return uRet;
- }
- }
-
-
- public static DesfireFileSettings selectAppFile(DesfireProtocol tag, int appID, int fileID) {
- try {
- tag.selectApp(appID);
- } catch (DesfireException e) {
- Log.w(TAG,"App not found");
- return null;
- }
- try {
- return tag.getFileSettings(fileID);
- } catch (DesfireException e) {
- Log.w(TAG,"File not found");
- return null;
- }
- }
-
- public static boolean arrayContains(int[] arr, int item) {
- for (int i: arr)
- if (i==item)
- return true;
- return false;
- }
-
- public static boolean containsAppFile(DesfireProtocol tag, int appID, int fileID) {
- try {
- tag.selectApp(appID);
- } catch (DesfireException e) {
- Log.w(TAG,"App not found");
- Log.w(TAG, e);
- return false;
- }
- try {
- return arrayContains(tag.getFileList(),fileID);
- } catch (DesfireException e) {
- Log.w(TAG,"File not found");
- Log.w(TAG, e);
- return false;
- }
- }
-}
+++ /dev/null
-/*
- * DesfireApplication.java
- *
- * Copyright (C) 2011 Eric Butler
- *
- * Authors:
- * Eric Butler <eric@codebutler.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.codebutler.farebot.card.desfire;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-public class DesfireApplication implements Parcelable {
- private int mId;
- private DesfireFile[] mFiles;
-
- public DesfireApplication (int id, DesfireFile[] files) {
- mId = id;
- mFiles = files;
- }
-
- public int getId () {
- return mId;
- }
-
- public DesfireFile[] getFiles () {
- return mFiles;
- }
-
- public DesfireFile getFile (int fileId) {
- for (DesfireFile file : mFiles) {
- if (file.getId() == fileId)
- return file;
- }
- return null;
- }
-
- public static final Parcelable.Creator<DesfireApplication> CREATOR = new Parcelable.Creator<DesfireApplication>() {
- public DesfireApplication createFromParcel(Parcel source) {
- int id = source.readInt();
-
- DesfireFile[] files = new DesfireFile[source.readInt()];
- source.readTypedArray(files, DesfireFile.CREATOR);
-
- return new DesfireApplication(id, files);
- }
-
- public DesfireApplication[] newArray (int size) {
- return new DesfireApplication[size];
- }
- };
-
- public void writeToParcel (Parcel parcel, int flags) {
- parcel.writeInt(mId);
- parcel.writeInt(mFiles.length);
- parcel.writeTypedArray(mFiles, flags);
- }
-
- public int describeContents () {
- return 0;
- }
-}
\ No newline at end of file
+++ /dev/null
-package com.codebutler.farebot.card.desfire;
-
-/**
- * Created by Jakob Wenzel on 16.11.13.
- */
-public class DesfireException extends Exception {
- public DesfireException(String message) {
- super(message);
- }
- public DesfireException(Throwable cause) {
- super(cause);
- }
-}
+++ /dev/null
-/*
- * DesfireFile.java
- *
- * Copyright (C) 2011 Eric Butler
- *
- * Authors:
- * Eric Butler <eric@codebutler.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.codebutler.farebot.card.desfire;
-
-import org.apache.commons.lang3.ArrayUtils;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.codebutler.farebot.card.desfire.DesfireFileSettings.RecordDesfireFileSettings;
-
-public class DesfireFile implements Parcelable {
- private int mId;
- private DesfireFileSettings mSettings;
- private byte[] mData;
-
- public static DesfireFile create (int fileId, DesfireFileSettings fileSettings, byte[] fileData) {
- if (fileSettings instanceof RecordDesfireFileSettings)
- return new RecordDesfireFile(fileId, fileSettings, fileData);
- else
- return new DesfireFile(fileId, fileSettings, fileData);
- }
-
- private DesfireFile (int fileId, DesfireFileSettings fileSettings, byte[] fileData) {
- mId = fileId;
- mSettings = fileSettings;
- mData = fileData;
- }
-
- public DesfireFileSettings getFileSettings () {
- return mSettings;
- }
-
- public int getId () {
- return mId;
- }
-
- public byte[] getData () {
- return mData;
- }
-
- public static final Parcelable.Creator<DesfireFile> CREATOR = new Parcelable.Creator<DesfireFile>() {
- public DesfireFile createFromParcel(Parcel source) {
- int fileId = source.readInt();
-
- boolean isError = (source.readInt() == 1);
-
- if (!isError) {
- DesfireFileSettings fileSettings = (DesfireFileSettings) source.readParcelable(DesfireFileSettings.class.getClassLoader());
- int dataLength = source.readInt();
- byte[] fileData = new byte[dataLength];
- source.readByteArray(fileData);
-
- return DesfireFile.create(fileId, fileSettings, fileData);
- } else {
- return new InvalidDesfireFile(fileId, source.readString());
- }
- }
-
- public DesfireFile[] newArray (int size) {
- return new DesfireFile[size];
- }
- };
-
- public void writeToParcel (Parcel parcel, int flags) {
- parcel.writeInt(mId);
- if (this instanceof InvalidDesfireFile) {
- parcel.writeInt(1);
- parcel.writeString(((InvalidDesfireFile)this).getErrorMessage());
- } else {
- parcel.writeInt(0);
- parcel.writeParcelable(mSettings, 0);
- parcel.writeInt(mData.length);
- parcel.writeByteArray(mData);
- }
- }
-
- public int describeContents () {
- return 0;
- }
-
- public static class RecordDesfireFile extends DesfireFile {
- private DesfireRecord[] mRecords;
-
- private RecordDesfireFile (int fileId, DesfireFileSettings fileSettings, byte[] fileData) {
- super(fileId, fileSettings, fileData);
-
- RecordDesfireFileSettings settings = (RecordDesfireFileSettings) fileSettings;
-
- DesfireRecord[] records = new DesfireRecord[settings.curRecords];
- for (int i = 0; i < settings.curRecords; i++) {
- int offset = settings.recordSize * i;
- records[i] = new DesfireRecord(ArrayUtils.subarray(getData(), offset, offset + settings.recordSize));
- }
- mRecords = records;
- }
-
- public DesfireRecord[] getRecords () {
- return mRecords;
- }
- }
-
- public static class InvalidDesfireFile extends DesfireFile {
- private String mErrorMessage;
-
- public InvalidDesfireFile (int fileId, String errorMessage) {
- super(fileId, null, new byte[0]);
- mErrorMessage = errorMessage;
- }
-
- public String getErrorMessage () {
- return mErrorMessage;
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * DesfireFileSettings.java
- *
- * Copyright (C) 2011 Eric Butler
- *
- * Authors:
- * Eric Butler <eric@codebutler.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.codebutler.farebot.card.desfire;
-
-import java.io.ByteArrayInputStream;
-
-import org.apache.commons.lang3.ArrayUtils;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.codebutler.farebot.Utils;
-
-public abstract class DesfireFileSettings implements Parcelable {
- public final byte fileType;
- public final byte commSetting;
- public final byte[] accessRights;
-
- /* DesfireFile Types */
- static final byte STANDARD_DATA_FILE = (byte) 0x00;
- static final byte BACKUP_DATA_FILE = (byte) 0x01;
- static final byte VALUE_FILE = (byte) 0x02;
- static final byte LINEAR_RECORD_FILE = (byte) 0x03;
- static final byte CYCLIC_RECORD_FILE = (byte) 0x04;
-
- public static DesfireFileSettings Create (byte[] data) throws DesfireException {
- byte fileType = (byte) data[0];
-
- ByteArrayInputStream stream = new ByteArrayInputStream(data);
-
- if (fileType == STANDARD_DATA_FILE || fileType == BACKUP_DATA_FILE)
- return new StandardDesfireFileSettings(stream);
- else if (fileType == LINEAR_RECORD_FILE || fileType == CYCLIC_RECORD_FILE)
- return new RecordDesfireFileSettings(stream);
- else if (fileType == VALUE_FILE)
- return new ValueDesfireFileSettings(stream);
- else
- throw new DesfireException("Unknown file type: " + Integer.toHexString(fileType));
- }
-
- private DesfireFileSettings (ByteArrayInputStream stream) {
- fileType = (byte) stream.read();
- commSetting = (byte) stream.read();
-
- accessRights = new byte[2];
- stream.read(accessRights, 0, accessRights.length);
- }
-
- private DesfireFileSettings (byte fileType, byte commSetting, byte[] accessRights) {
- this.fileType = fileType;
- this.commSetting = commSetting;
- this.accessRights = accessRights;
- }
-
- public String getFileTypeName () {
- switch (fileType) {
- case STANDARD_DATA_FILE:
- return "Standard";
- case BACKUP_DATA_FILE:
- return "Backup";
- case VALUE_FILE:
- return "Value";
- case LINEAR_RECORD_FILE:
- return "Linear Record";
- case CYCLIC_RECORD_FILE:
- return "Cyclic Record";
- default:
- return "Unknown";
- }
- }
-
- public static final Parcelable.Creator<DesfireFileSettings> CREATOR = new Parcelable.Creator<DesfireFileSettings>() {
- public DesfireFileSettings createFromParcel(Parcel source) {
- byte fileType = source.readByte();
- byte commSetting = source.readByte();
- byte[] accessRights = new byte[source.readInt()];
- source.readByteArray(accessRights);
-
- if (fileType == STANDARD_DATA_FILE || fileType == BACKUP_DATA_FILE) {
- int fileSize = source.readInt();
- return new StandardDesfireFileSettings(fileType, commSetting, accessRights, fileSize);
- } else if (fileType == LINEAR_RECORD_FILE || fileType == CYCLIC_RECORD_FILE) {
- int recordSize = source.readInt();
- int maxRecords = source.readInt();
- int curRecords = source.readInt();
- return new RecordDesfireFileSettings(fileType, commSetting, accessRights, recordSize, maxRecords, curRecords);
- } else {
- return new UnsupportedDesfireFileSettings(fileType);
- }
- }
-
- public DesfireFileSettings[] newArray(int size) {
- return new DesfireFileSettings[size];
- }
- };
-
- public void writeToParcel (Parcel parcel, int flags) {
- parcel.writeByte(fileType);
- parcel.writeByte(commSetting);
- parcel.writeInt(accessRights.length);
- parcel.writeByteArray(accessRights);
- }
-
- public int describeContents () {
- return 0;
- }
-
- public static class StandardDesfireFileSettings extends DesfireFileSettings {
- public final int fileSize;
-
- private StandardDesfireFileSettings (ByteArrayInputStream stream) {
- super(stream);
- byte[] buf = new byte[3];
- stream.read(buf, 0, buf.length);
- ArrayUtils.reverse(buf);
- fileSize = Utils.byteArrayToInt(buf);
- }
-
- StandardDesfireFileSettings (byte fileType, byte commSetting, byte[] accessRights, int fileSize) {
- super(fileType, commSetting, accessRights);
- this.fileSize = fileSize;
- }
-
- @Override
- public void writeToParcel (Parcel parcel, int flags) {
- super.writeToParcel(parcel, flags);
- parcel.writeInt(fileSize);
- }
- }
-
- public static class RecordDesfireFileSettings extends DesfireFileSettings {
- public final int recordSize;
- public final int maxRecords;
- public final int curRecords;
-
- public RecordDesfireFileSettings(ByteArrayInputStream stream) {
- super(stream);
-
- byte[] buf = new byte[3];
- stream.read(buf, 0, buf.length);
- ArrayUtils.reverse(buf);
- recordSize = Utils.byteArrayToInt(buf);
-
- buf = new byte[3];
- stream.read(buf, 0, buf.length);
- ArrayUtils.reverse(buf);
- maxRecords = Utils.byteArrayToInt(buf);
-
- buf = new byte[3];
- stream.read(buf, 0, buf.length);
- ArrayUtils.reverse(buf);
- curRecords = Utils.byteArrayToInt(buf);
- }
-
- RecordDesfireFileSettings (byte fileType, byte commSetting, byte[] accessRights, int recordSize, int maxRecords, int curRecords) {
- super(fileType, commSetting, accessRights);
- this.recordSize = recordSize;
- this.maxRecords = maxRecords;
- this.curRecords = curRecords;
- }
-
- @Override
- public void writeToParcel (Parcel parcel, int flags) {
- super.writeToParcel(parcel, flags);
- parcel.writeInt(recordSize);
- parcel.writeInt(maxRecords);
- parcel.writeInt(curRecords);
- }
- }
-
-
-
-
- public static class ValueDesfireFileSettings extends DesfireFileSettings {
- public final int lowerLimit;
- public final int upperLimit;
- public final int value;
- public final byte limitedCreditEnabled;
-
- public ValueDesfireFileSettings(ByteArrayInputStream stream) {
- super(stream);
-
- byte[] buf = new byte[4];
- stream.read(buf, 0, buf.length);
- ArrayUtils.reverse(buf);
- lowerLimit = Utils.byteArrayToInt(buf);
-
- buf = new byte[4];
- stream.read(buf, 0, buf.length);
- ArrayUtils.reverse(buf);
- upperLimit = Utils.byteArrayToInt(buf);
-
- buf = new byte[4];
- stream.read(buf, 0, buf.length);
- ArrayUtils.reverse(buf);
- value = Utils.byteArrayToInt(buf);
-
-
- buf = new byte[1];
- stream.read(buf, 0, buf.length);
- limitedCreditEnabled = buf[0];
-
- //http://www.skyetek.com/docs/m2/desfire.pdf
- //http://neteril.org/files/M075031_desfire.pdf
- }
-
- @Override
- public void writeToParcel (Parcel parcel, int flags) {
- super.writeToParcel(parcel, flags);
- parcel.writeInt(lowerLimit);
- parcel.writeInt(upperLimit);
- parcel.writeInt(value);
- parcel.writeByte(limitedCreditEnabled);
- }
- }
- public static class UnsupportedDesfireFileSettings extends DesfireFileSettings {
- public UnsupportedDesfireFileSettings(byte fileType) {
- super(fileType, Byte.MIN_VALUE, new byte[0]);
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * DesfireManufacturingData.java
- *
- * Copyright (C) 2011 Eric Butler
- *
- * Authors:
- * Eric Butler <eric@codebutler.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.codebutler.farebot.card.desfire;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import com.codebutler.farebot.Utils;
-import org.w3c.dom.Element;
-
-import java.io.ByteArrayInputStream;
-
-public class DesfireManufacturingData implements Parcelable {
- public final int hwVendorID;
- public final int hwType;
- public final int hwSubType;
- public final int hwMajorVersion;
- public final int hwMinorVersion;
- public final int hwStorageSize;
- public final int hwProtocol;
-
- public final int swVendorID;
- public final int swType;
- public final int swSubType;
- public final int swMajorVersion;
- public final int swMinorVersion;
- public final int swStorageSize;
- public final int swProtocol;
-
- public final int uid;
- public final int batchNo;
- public final int weekProd;
- public final int yearProd;
-
- public DesfireManufacturingData (byte[] data) {
- ByteArrayInputStream stream = new ByteArrayInputStream(data);
- hwVendorID = stream.read();
- hwType = stream.read();
- hwSubType = stream.read();
- hwMajorVersion = stream.read();
- hwMinorVersion = stream.read();
- hwStorageSize = stream.read();
- hwProtocol = stream.read();
-
- swVendorID = stream.read();
- swType = stream.read();
- swSubType = stream.read();
- swMajorVersion = stream.read();
- swMinorVersion = stream.read();
- swStorageSize = stream.read();
- swProtocol = stream.read();
-
- // FIXME: This has fewer digits than what's contained in EXTRA_ID, why?
- byte[] buf = new byte[7];
- stream.read(buf, 0, buf.length);
- uid = Utils.byteArrayToInt(buf);
-
- // FIXME: This is returning a negative number. Probably is unsigned.
- buf = new byte[5];
- stream.read(buf, 0, buf.length);
- batchNo = Utils.byteArrayToInt(buf);
-
- // FIXME: These numbers aren't making sense.
- weekProd = stream.read();
- yearProd = stream.read();
- }
-
- public static DesfireManufacturingData fromXml (Element element) {
- return new DesfireManufacturingData(element);
- }
-
- private DesfireManufacturingData (Element element) {
- hwVendorID = Integer.parseInt(element.getElementsByTagName("hw-vendor-id").item(0).getTextContent());
- hwType = Integer.parseInt(element.getElementsByTagName("hw-type").item(0).getTextContent());
- hwSubType = Integer.parseInt(element.getElementsByTagName("hw-sub-type").item(0).getTextContent());
- hwMajorVersion = Integer.parseInt(element.getElementsByTagName("hw-major-version").item(0).getTextContent());
- hwMinorVersion = Integer.parseInt(element.getElementsByTagName("hw-minor-version").item(0).getTextContent());
- hwStorageSize = Integer.parseInt(element.getElementsByTagName("hw-storage-size").item(0).getTextContent());
- hwProtocol = Integer.parseInt(element.getElementsByTagName("hw-protocol").item(0).getTextContent());
-
- swVendorID = Integer.parseInt(element.getElementsByTagName("sw-vendor-id").item(0).getTextContent());
- swType = Integer.parseInt(element.getElementsByTagName("sw-type").item(0).getTextContent());
- swSubType = Integer.parseInt(element.getElementsByTagName("sw-sub-type").item(0).getTextContent());
- swMajorVersion = Integer.parseInt(element.getElementsByTagName("sw-major-version").item(0).getTextContent());
- swMinorVersion = Integer.parseInt(element.getElementsByTagName("sw-minor-version").item(0).getTextContent());
- swStorageSize = Integer.parseInt(element.getElementsByTagName("sw-storage-size").item(0).getTextContent());
- swProtocol = Integer.parseInt(element.getElementsByTagName("sw-protocol").item(0).getTextContent());
-
- uid = Integer.parseInt(element.getElementsByTagName("uid").item(0).getTextContent());
- batchNo = Integer.parseInt(element.getElementsByTagName("batch-no").item(0).getTextContent());
- weekProd = Integer.parseInt(element.getElementsByTagName("week-prod").item(0).getTextContent());
- yearProd = Integer.parseInt(element.getElementsByTagName("year-prod").item(0).getTextContent());
- }
-
- private DesfireManufacturingData (Parcel parcel) {
- hwVendorID = parcel.readInt();
- hwType = parcel.readInt();
- hwSubType = parcel.readInt();
- hwMajorVersion = parcel.readInt();
- hwMinorVersion = parcel.readInt();
- hwStorageSize = parcel.readInt();
- hwProtocol = parcel.readInt();
-
- swVendorID = parcel.readInt();
- swType = parcel.readInt();
- swSubType = parcel.readInt();
- swMajorVersion = parcel.readInt();
- swMinorVersion = parcel.readInt();
- swStorageSize = parcel.readInt();
- swProtocol = parcel.readInt();
-
- uid = parcel.readInt();
- batchNo = parcel.readInt();
- weekProd = parcel.readInt();
- yearProd = parcel.readInt();
- }
-
- public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeInt(hwVendorID);
- parcel.writeInt(hwType);
- parcel.writeInt(hwSubType);
- parcel.writeInt(hwMajorVersion);
- parcel.writeInt(hwMinorVersion);
- parcel.writeInt(hwStorageSize);
- parcel.writeInt(hwProtocol);
-
- parcel.writeInt(swVendorID);
- parcel.writeInt(swType);
- parcel.writeInt(swSubType);
- parcel.writeInt(swMajorVersion);
- parcel.writeInt(swMinorVersion);
- parcel.writeInt(swStorageSize);
- parcel.writeInt(swProtocol);
-
- parcel.writeInt(uid);
- parcel.writeInt(batchNo);
- parcel.writeInt(weekProd);
- parcel.writeInt(yearProd);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public static final Parcelable.Creator<DesfireManufacturingData> CREATOR = new Parcelable.Creator<DesfireManufacturingData>() {
- public DesfireManufacturingData createFromParcel(Parcel source) {
- return new DesfireManufacturingData(source);
- }
-
- public DesfireManufacturingData[] newArray(int size) {
- return new DesfireManufacturingData[size];
- }
- };
-}
\ No newline at end of file
+++ /dev/null
-/*
- * DesfireProtocol.java
- *
- * Copyright (C) 2011 Eric Butler
- *
- * Authors:
- * Eric Butler <eric@codebutler.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.codebutler.farebot.card.desfire;
-
-import android.nfc.tech.IsoDep;
-import com.codebutler.farebot.Utils;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-import org.apache.commons.lang3.ArrayUtils;
-
-public class DesfireProtocol {
- /* Commands */
- static final byte GET_MANUFACTURING_DATA = (byte) 0x60;
- static final byte GET_APPLICATION_DIRECTORY = (byte) 0x6A;
- static final byte GET_ADDITIONAL_FRAME = (byte) 0xAF;
- static final byte SELECT_APPLICATION = (byte) 0x5A;
- static final byte READ_DATA = (byte) 0xBD;
- static final byte READ_RECORD = (byte) 0xBB;
- static final byte READ_VALUE = (byte) 0x6C;
- static final byte GET_FILES = (byte) 0x6F;
- static final byte GET_FILE_SETTINGS = (byte) 0xF5;
-
- /* Status codes */
- static final byte OPERATION_OK = (byte) 0x00;
- static final byte PERMISSION_DENIED = (byte) 0x9D;
- static final byte ADDITIONAL_FRAME = (byte) 0xAF;
-
- private IsoDep mTagTech;
-
- public DesfireProtocol(IsoDep tagTech) {
- mTagTech = tagTech;
- }
-
- public DesfireManufacturingData getManufacturingData() throws DesfireException {
- byte[] respBuffer = sendRequest(GET_MANUFACTURING_DATA);
-
- if (respBuffer.length != 28)
- throw new DesfireException("Invalid response");
-
- return new DesfireManufacturingData(respBuffer);
- }
-
- public int[] getAppList() throws DesfireException {
- byte[] appDirBuf = sendRequest(GET_APPLICATION_DIRECTORY);
-
- int[] appIds = new int[appDirBuf.length / 3];
-
- for (int app = 0; app < appDirBuf.length; app += 3) {
- byte[] appId = new byte[3];
- System.arraycopy(appDirBuf, app, appId, 0, 3);
-
- appIds[app / 3] = Utils.byteArrayToInt(appId);
- }
-
- return appIds;
- }
-
- public void selectApp (int appId) throws DesfireException {
- byte[] appIdBuff = new byte[3];
- appIdBuff[0] = (byte) ((appId & 0xFF0000) >> 16);
- appIdBuff[1] = (byte) ((appId & 0xFF00) >> 8);
- appIdBuff[2] = (byte) (appId & 0xFF);
-
- sendRequest(SELECT_APPLICATION, appIdBuff);
- }
-
- public int[] getFileList() throws DesfireException {
- byte[] buf = sendRequest(GET_FILES);
- int[] fileIds = new int[buf.length];
- for (int x = 0; x < buf.length; x++) {
- fileIds[x] = (int)buf[x];
- }
- return fileIds;
- }
-
- public DesfireFileSettings getFileSettings (int fileNo) throws DesfireException {
- byte[] data = new byte[0];
- data = sendRequest(GET_FILE_SETTINGS, new byte[] { (byte) fileNo });
- return DesfireFileSettings.Create(data);
- }
-
- public byte[] readFile (int fileNo) throws DesfireException {
- return sendRequest(READ_DATA, new byte[] {
- (byte) fileNo,
- (byte) 0x0, (byte) 0x0, (byte) 0x0,
- (byte) 0x0, (byte) 0x0, (byte) 0x0
- });
- }
-
- public byte[] readRecord (int fileNum) throws DesfireException {
- return sendRequest(READ_RECORD, new byte[]{
- (byte) fileNum,
- (byte) 0x0, (byte) 0x0, (byte) 0x0,
- (byte) 0x0, (byte) 0x0, (byte) 0x0
- });
- }
-
- public int readValue(int fileNum) throws DesfireException {
- byte[] buf = sendRequest(READ_VALUE, new byte[]{
- (byte) fileNum
- });
- ArrayUtils.reverse(buf);
- return Utils.byteArrayToInt(buf);
- }
-
-
- private byte[] sendRequest (byte command) throws DesfireException {
- return sendRequest(command, null);
- }
-
- private byte[] sendRequest (byte command, byte[] parameters) throws DesfireException {
- ByteArrayOutputStream output = new ByteArrayOutputStream();
-
- byte[] recvBuffer = new byte[0];
- try {
- recvBuffer = mTagTech.transceive(wrapMessage(command, parameters));
- } catch (IOException e) {
- throw new DesfireException(e);
- }
-
- while (true) {
- if (recvBuffer[recvBuffer.length - 2] != (byte) 0x91)
- throw new DesfireException("Invalid response");
-
- output.write(recvBuffer, 0, recvBuffer.length - 2);
-
- byte status = recvBuffer[recvBuffer.length - 1];
- if (status == OPERATION_OK) {
- break;
- } else if (status == ADDITIONAL_FRAME) {
- try {
- recvBuffer = mTagTech.transceive(wrapMessage(GET_ADDITIONAL_FRAME, null));
- } catch (IOException e) {
- throw new DesfireException(e);
- }
- } else if (status == PERMISSION_DENIED) {
- throw new DesfireException("Permission denied");
- } else {
- throw new DesfireException("Unknown status code: " + Integer.toHexString(status & 0xFF));
- }
- }
-
- return output.toByteArray();
- }
-
- private byte[] wrapMessage (byte command, byte[] parameters) throws DesfireException {
- ByteArrayOutputStream stream = new ByteArrayOutputStream();
-
- stream.write((byte) 0x90);
- stream.write(command);
- stream.write((byte) 0x00);
- stream.write((byte) 0x00);
- if (parameters != null) {
- stream.write((byte) parameters.length);
- try {
- stream.write(parameters);
- } catch (IOException e) {
- throw new DesfireException(e);
- }
- }
- stream.write((byte) 0x00);
-
- return stream.toByteArray();
- }
-
-}
\ No newline at end of file
+++ /dev/null
-/*
- * DesfireRecord.java
- *
- * Copyright (C) 2011 Eric Butler
- *
- * Authors:
- * Eric Butler <eric@codebutler.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.codebutler.farebot.card.desfire;
-
-public class DesfireRecord {
- private byte[] mData;
-
- public DesfireRecord (byte[] data) {
- mData = data;
- }
-
- public byte[] getData () {
- return mData;
- }
-}
\ No newline at end of file
private void onNfcCardDataReceived(NfcCardData data) {
Bundle bundle = new Bundle();
bundle.putDouble("balance", data.getBalance() / 100.0);
- bundle.putString("data", data.getCardData());
+ bundle.putDouble("transaction", data.getLastTransaction() / 100.0);
String pagename = oNavigationManager.getCurrentPageName();
if(pagename != null && pagename.equalsIgnoreCase("MensaCard")) {
public String getCurrentPageName() {
if(oCurrentPage == null)
return null;
+ if(oCurrentPage.fragmentType == 3 && oParentFragment != null){
+ if(oCurrentFragment.isAdded())
+ return oCurrentPage.name;
+ else {
+ closeDialog();
+ }
+ }
return oCurrentPage.name;
}
public boolean closeDialog() {
if(oCurrentPage != null && oCurrentPage.fragmentType == 3) {
PopupFragment fragment = (PopupFragment) oCurrentFragment;
- fragment.destroyView();
+ if(oCurrentFragment.isAdded()) {
+ fragment.destroyView();
- FragmentActivity fragmentActivity = (FragmentActivity) AppContext.getMainActivity();
- FragmentTransaction transaction = fragmentActivity.getSupportFragmentManager().beginTransaction();
+ FragmentActivity fragmentActivity = (FragmentActivity) AppContext.getMainActivity();
+ FragmentTransaction transaction = fragmentActivity.getSupportFragmentManager().beginTransaction();
- transaction.remove(oCurrentFragment);
+ transaction.remove(oCurrentFragment);
+ transaction.commit();
+ }
oCurrentPage = oParentPage;
oCurrentFragment = oParentFragment;
- transaction.commit();
+
return true;
}
return false;
"(" +
"CardId INT, " +
"UpdateTime INT," +
- "CardData TEXT, " +
"CardBalance INT, " +
"CardLastTransaction INT, " +
"PRIMARY KEY (CardId, UpdateTime)" +
Integer.toString(nfcCardData.getUniqueId()),
Long.toString(nfcCardData.getLastUpdate())
};
- Cursor resultSet = database.rawQuery("SELECT CardData FROM NfcCardStore WHERE CardId = ? AND UpdateTime = ?", whereArgs);
+ Cursor resultSet = database.rawQuery("SELECT CardBalance FROM NfcCardStore WHERE CardId = ? AND UpdateTime = ?", whereArgs);
if(resultSet.moveToFirst()) {
- if(resultSet.getString(0).equalsIgnoreCase(nfcCardData.getCardData()))
- return;
try {
ContentValues updateValues = new ContentValues();
- updateValues.put("CardData", nfcCardData.getCardData());
updateValues.put("CardBalance", nfcCardData.getBalance());
updateValues.put("CardLastTransaction", nfcCardData.getLastTransaction());
ContentValues indexValues = new ContentValues();
indexValues.put("CardId", nfcCardData.getUniqueId());
indexValues.put("UpdateTime", nfcCardData.getLastUpdate());
- indexValues.put("CardData", nfcCardData.getCardData());
indexValues.put("CardBalance", nfcCardData.getBalance());
indexValues.put("CardLastTransaction", nfcCardData.getLastTransaction());
String[] whereArgs = {
Integer.toString(lastLimit)
};
- resultSet = database.rawQuery("SELECT CardId,UpdateTime,CardData,CardBalance,CardLastTransaction FROM NfcCardStore ORDER BY UpdateTime DESC LIMIT ?", whereArgs);
+ resultSet = database.rawQuery("SELECT CardId,UpdateTime,CardBalance,CardLastTransaction FROM NfcCardStore ORDER BY UpdateTime DESC LIMIT ?", whereArgs);
} else
- resultSet = database.rawQuery("SELECT CardId,UpdateTime,CardData,CardBalance,CardLastTransaction FROM NfcCardStore ORDER BY UpdateTime DESC", null);
+ resultSet = database.rawQuery("SELECT CardId,UpdateTime,CardBalance,CardLastTransaction FROM NfcCardStore ORDER BY UpdateTime DESC", null);
ArrayList<NfcCardData> nfcCardDatas = new ArrayList<NfcCardData>();
if(resultSet.moveToFirst()) {
do {
- NfcCardData nfcCardData = new NfcCardData(resultSet.getInt(0), resultSet.getLong(1), resultSet.getString(2), resultSet.getInt(3), resultSet.getInt(4));
+ NfcCardData nfcCardData = new NfcCardData(resultSet.getInt(0), resultSet.getLong(1), resultSet.getInt(2), resultSet.getInt(3));
nfcCardDatas.add(nfcCardData);
} while (resultSet.moveToNext());
}
public class NfcCardData {
private int iUniqueId;
private long iLastUpdate;
- private String sCardData;
private int iBalance;
private int iLastTransaction;
- public NfcCardData(de.dhbwloe.campusapp.nfcreader.cardreader.NfcCardData carddata) {
- iUniqueId = carddata.getUniqueid();
- iLastUpdate = (new Date()).getTime()/1000;
- sCardData = carddata.getCompactCardDataSummary();
- iBalance = (int)(carddata.getBalanceData() * 100);
- iLastTransaction = (int)(carddata.getLastTransaction() * 100);
- }
-
- public NfcCardData(int uid, long lastupdate, String carddata, int balance, int transaction) {
+ public NfcCardData(int uid, long lastupdate, int balance, int transaction) {
iUniqueId = uid;
iLastUpdate = lastupdate;
- sCardData = carddata;
iBalance = balance;
iLastTransaction = transaction;
}
return iUniqueId;
}
- public String getCardData() {
- return sCardData;
- }
-
public long getLastUpdate() {
return iLastUpdate;
}
public void destroyView() {
if(oCurrentFragment != null) {
- FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
- transaction.remove(oCurrentFragment);
- transaction.commit();
+ CampusAppFragment fragment = oCurrentFragment;
+ oCurrentFragment = null;
+ if(fragment.isAdded()) {
+ FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
+ transaction.remove(fragment);
+ transaction.commit();
+ } else
+ AppContext.getMainActivity().onBackPressed();
}
}
--- /dev/null
+package de.dhbwloe.campusapp.nfcreader;
+
+import android.nfc.tech.IsoDep;
+
+import de.dhbwloe.campusapp.nfcreader.MifareDESFire.CommunicationError;
+import de.dhbwloe.campusapp.nfcreader.MifareDESFire.DesfireManufacturingData;
+import de.dhbwloe.campusapp.nfcreader.MifareDESFire.MifareDESFireWrapper;
+import de.dhbwloe.campusapp.nfcreader.MifareDESFire.ValueFileSettings;
+
+import java.text.DecimalFormat;
+
+/**
+ * Created by stefan on 20.01.16.
+ */
+public class DHBWCard {
+
+// /* Commands */
+// public static final byte GET_VERSION_INFO = (byte) 0x60;
+// public static final byte GET_APPLICATION_DIRECTORY = (byte) 0x6A;
+// public static final byte GET_ADDITIONAL_FRAME = (byte) 0xAF;
+// public static final byte SELECT_APPLICATION = (byte) 0x5A;
+// public static final byte READ_DATA = (byte) 0xBD;
+// public static final byte READ_RECORD = (byte) 0xBB;
+// public static final byte GET_FILES = (byte) 0x6F;
+// public static final byte GET_FILE_SETTINGS = (byte) 0xF5;
+//
+// public static final byte INIT_AUTH = (byte) 0x0a;
+// public static final byte FINISH_AUTH = (byte) 0xAF;
+//
+// public static final byte GET_KEY_VERSION = (byte) 0x64;
+
+ private MifareDESFireWrapper nfcCard;
+
+ public DHBWCard(IsoDep tag) {
+ this.nfcCard = new MifareDESFireWrapper(tag);
+ }
+
+
+ /**
+ * Reads the current uniqueid on the card.
+ * Throws a UndefinedResponseException if the card returns an unexpected response (e.g. used another card)
+ *
+ * @return Returns the unique id
+ * @throws UndefinedResponseException
+ */
+ public int readUniqueId() throws UndefinedResponseException, CommunicationError {
+ // Select application for balance
+ DesfireManufacturingData manufacturingData = nfcCard.readManufacturingData();
+ return manufacturingData.uid;
+ }
+
+ /**
+ * Reads the current balance on the card.
+ * Throws a UndefinedResponseException if the card returns an unexpected response (e.g. used another card)
+ *
+ * @return Returns the balance
+ * @throws UndefinedResponseException
+ */
+ public int readBalance() throws UndefinedResponseException, CommunicationError {
+ // Select application for balance
+ nfcCard.selectApplication("5F 84 15");
+ int value = nfcCard.readValueFile("01");
+ return value / 10;
+ }
+
+
+ /**
+ * Reads the last transaction by reading the limited credit value
+ * @return Returns the last transaction of the card
+ * @throws UndefinedResponseException
+ */
+ public int readLastTransaction() throws UndefinedResponseException, CommunicationError {
+ nfcCard.selectApplication("5F 84 15");
+ ValueFileSettings valueFileSettings = (ValueFileSettings) nfcCard.readFileSettings("01");
+ return valueFileSettings.getLimitedCreditValue() / 10;
+ }
+}
--- /dev/null
+package de.dhbwloe.campusapp.nfcreader;
+
+/**
+ * Created by stefan on 20.01.16.
+ */
+public class Hex {
+ /**
+ * Converts a hex string (Format: "XX XX XX ..") into a Byte array
+ * @param hexString
+ * @return Byte array
+ */
+ public static Byte[] stringToHex(String hexString) {
+ if (hexString == null)
+ return null;
+ hexString = hexString.replace(" ", "");
+ final int bytesCount = hexString.length() / 2;
+ if (2 * bytesCount != hexString.length()) {
+ throw new IllegalArgumentException(
+ "Hex string must have an even number of digits");
+ }
+
+ Byte[] result = new Byte[bytesCount];
+ for (int i = 0; i < hexString.length(); i += 2) {
+ result[i / 2] = (byte) Integer.parseInt(hexString.substring(i, i + 2), 16);
+ }
+ return result;
+ }
+
+ /**
+ * Converts a Byte array into a hex string (Format "xx xx xx ..")
+ * @param bytes
+ * @return hex string
+ */
+ public static String hexToString(Byte[] bytes) {
+ StringBuffer buff = new StringBuffer();
+ for (byte b : bytes) {
+ buff.append(String.format("%02X", b));
+ }
+ return buff.toString();
+ }
+
+ /**
+ * Extracts parts of the Byte array into a seperate array
+ * @param start Start position of sub array
+ * @param stop Stop position of sub array
+ * @param array Array to extract from
+ * @return sub array
+ */
+ public static Byte[] subByteArray(int start, int stop, Byte[] array) {
+ Byte[] returnArray = new Byte[stop-start];
+ int position = 0;
+ for (int i = start; i<stop; i++) {
+ returnArray[position] = array[i];
+ position++;
+ }
+ return returnArray;
+ }
+
+
+ /**
+ * Reverses byte order in byte array (to convert from LSB and MSB and backwards)
+ * @param bytes byte array
+ * @return reversed byte array
+ */
+ public static Byte[] reverseByteOrder(Byte[] bytes) {
+ Byte[] returnBytes = new Byte[bytes.length];
+ for (int i=0; i<bytes.length; i++) {
+ returnBytes[bytes.length - 1 - i] = bytes[i];
+ }
+ return returnBytes;
+ }
+
+ /**
+ * Converts byte array to integer
+ * @param bytes
+ * @return interger
+ */
+ public static int hexToInteger(Byte[] bytes) {
+ String hexString = hexToString(bytes);
+ return Integer.parseInt(hexString, 16);
+ }
+
+ /**
+ * Converts a Byte[] array to byte[] array (Object to primitive)
+ * @param oBytes
+ * @return
+ */
+ public static byte[] bytesToPrimitives(Byte[] oBytes)
+ {
+ byte[] bytes = new byte[oBytes.length];
+
+ for(int i = 0; i < oBytes.length; i++) {
+ bytes[i] = oBytes[i];
+ }
+
+ return bytes;
+ }
+
+ /**
+ * Converts a byte[] array to Byte[] array (Primitive to object)
+ * @param bytesPrim
+ * @return
+ */
+ public static Byte[] bytesToObjects(byte[] bytesPrim) {
+ Byte[] bytes = new Byte[bytesPrim.length];
+
+ int i = 0;
+ for (byte b : bytesPrim) bytes[i++] = b; // Autoboxing
+
+ return bytes;
+ }
+
+ public static int byteArrayToInt(byte[] b) {
+ return byteArrayToInt(b, 0);
+ }
+
+ public static int byteArrayToInt(byte[] b, int offset) {
+ return byteArrayToInt(b, offset, b.length);
+ }
+
+ public static int byteArrayToInt(byte[] b, int offset, int length) {
+ return (int) byteArrayToLong(b, offset, length);
+ }
+
+ public static long byteArrayToLong(byte[] b, int offset, int length) {
+ if (b.length < length)
+ throw new IllegalArgumentException("length must be less than or equal to b.length");
+
+ long value = 0;
+ for (int i = 0; i < length; i++) {
+ int shift = (length - 1 - i) * 8;
+ value += (b[i + offset] & 0x000000FF) << shift;
+ }
+ return value;
+ }
+}
--- /dev/null
+package de.dhbwloe.campusapp.nfcreader.MifareDESFire;
+
+/**
+ * Created by stefan on 26.01.16.
+ */
+public class CommunicationError extends Exception {
+
+ public CommunicationError() {
+ }
+
+ public CommunicationError(String detailMessage) {
+ super(detailMessage);
+ }
+
+ public CommunicationError(String detailMessage, Throwable throwable) {
+ super(detailMessage, throwable);
+ }
+
+ public CommunicationError(Throwable throwable) {
+ super(throwable);
+ }
+}
--- /dev/null
+package de.dhbwloe.campusapp.nfcreader.MifareDESFire;
+
+import java.io.ByteArrayInputStream;
+
+import de.dhbwloe.campusapp.nfcreader.Hex;
+
+/**
+ * Created by pk910 on 27.01.2016.
+ */
+public class DesfireManufacturingData {
+ public final int hwVendorID;
+ public final int hwType;
+ public final int hwSubType;
+ public final int hwMajorVersion;
+ public final int hwMinorVersion;
+ public final int hwStorageSize;
+ public final int hwProtocol;
+
+ public final int swVendorID;
+ public final int swType;
+ public final int swSubType;
+ public final int swMajorVersion;
+ public final int swMinorVersion;
+ public final int swStorageSize;
+ public final int swProtocol;
+
+ public final int uid;
+ public final int batchNo;
+ public final int weekProd;
+ public final int yearProd;
+
+ public DesfireManufacturingData (byte[] data) {
+ ByteArrayInputStream stream = new ByteArrayInputStream(data);
+ hwVendorID = stream.read();
+ hwType = stream.read();
+ hwSubType = stream.read();
+ hwMajorVersion = stream.read();
+ hwMinorVersion = stream.read();
+ hwStorageSize = stream.read();
+ hwProtocol = stream.read();
+
+ swVendorID = stream.read();
+ swType = stream.read();
+ swSubType = stream.read();
+ swMajorVersion = stream.read();
+ swMinorVersion = stream.read();
+ swStorageSize = stream.read();
+ swProtocol = stream.read();
+
+ // FIXME: This has fewer digits than what's contained in EXTRA_ID, why?
+ byte[] buf = new byte[7];
+ stream.read(buf, 0, buf.length);
+ uid = Hex.byteArrayToInt(buf);
+
+ // FIXME: This is returning a negative number. Probably is unsigned.
+ buf = new byte[5];
+ stream.read(buf, 0, buf.length);
+ batchNo = Hex.byteArrayToInt(buf);
+
+ // FIXME: These numbers aren't making sense.
+ weekProd = stream.read();
+ yearProd = stream.read();
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package de.dhbwloe.campusapp.nfcreader.MifareDESFire;
+
+/**
+ * Created by stefan on 22.01.16.
+ */
+public abstract class FileSettings {
+ private String fileType;
+ private String communicationSettings;
+ private String accessRights;
+
+ public FileSettings(String fileType, String communicationSettings, String accessRights) {
+ this.fileType = fileType;
+ this.communicationSettings = communicationSettings;
+ this.accessRights = accessRights;
+ }
+
+ public String getFileType() {
+ return fileType;
+ }
+
+ public void setFileType(String fileType) {
+ this.fileType = fileType;
+ }
+
+ public String getCommunicationSettings() {
+ return communicationSettings;
+ }
+
+ public void setCommunicationSettings(String communicationSettings) {
+ this.communicationSettings = communicationSettings;
+ }
+
+ public String getAccessRights() {
+ return accessRights;
+ }
+
+ public void setAccessRights(String accessRights) {
+ this.accessRights = accessRights;
+ }
+}
--- /dev/null
+package de.dhbwloe.campusapp.nfcreader.MifareDESFire;
+
+import de.dhbwloe.campusapp.nfcreader.UndefinedResponseException;
+
+/**
+ * Created by stefan on 21.01.16.
+ */
+public interface IsoDepWrapper {
+
+
+ /**
+ * @param command Command to send to the tag (Format example: "AF 00 01 EF 01"
+ * @return Returns the raw response from the tag
+ * @throws UndefinedResponseException Thrown when the tag returned an undefined response code
+ */
+ public Byte[] sendCommand(String command) throws UndefinedResponseException, CommunicationError;
+}
--- /dev/null
+package de.dhbwloe.campusapp.nfcreader.MifareDESFire;
+
+import android.nfc.tech.IsoDep;
+import android.util.Log;
+
+import de.dhbwloe.campusapp.nfcreader.Hex;
+import de.dhbwloe.campusapp.nfcreader.UndefinedResponseException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * Created by stefan on 21.01.16.
+ */
+public class MifareDESFireWrapper implements IsoDepWrapper {
+ public final static String CODE_OK = "00";
+ public final static String CODE_MORE_DATA = "AF";
+ public final static String CODE_PERMISSION_DENIED = "9D";
+ public final static String CODE_APPLICATION_NOT_FOUND = "A0";
+ public final static String CODE_INVALID_COMMAND_LENGTH = "7E";
+
+ private IsoDep tag;
+ public static final String LOG_TAG = "MifareDESFireWrapper";
+
+ //TODO: Add all desfire functionality
+
+ public MifareDESFireWrapper(IsoDep tag) {
+ this.tag = tag;
+ }
+
+ /**
+ * @param applicationID Application id in following Format: "AD 00 03" (3 Hex digits)
+ * @throws UndefinedResponseException Thrown when the tag returns an undefined response
+ */
+ public void selectApplication(String applicationID) throws UndefinedResponseException, CommunicationError {
+ sendCommand("5A " + applicationID);
+ }
+
+ /**
+ * @param fileId The file id
+ * @return Returns the value of the value file
+ * @throws UndefinedResponseException Thrown when the tag returns an undefined response
+ */
+ public int readValueFile(String fileId) throws UndefinedResponseException, CommunicationError {
+ return Hex.hexToInteger(Hex.reverseByteOrder(this.sendCommand("6C " + fileId)));
+ }
+
+ /**
+ * @param fileId The file id
+ * @return Returns the FileSettings
+ * @throws UndefinedResponseException Thrown when the tag returns an undefined response
+ */
+ public FileSettings readFileSettings(String fileId) throws UndefinedResponseException, CommunicationError {
+ Byte[] data = sendCommand("F5 "+fileId);
+ FileSettings fileSettings = ValueFileSettings.createByRawData(data);
+ //TODO: Changeme
+ return fileSettings;
+ }
+
+ /**
+ * @return Returns the DesfireManufacturingData
+ * @throws UndefinedResponseException Thrown when the tag returns an undefined response
+ */
+ public DesfireManufacturingData readManufacturingData() throws UndefinedResponseException, CommunicationError {
+ Byte[] data = sendCommand("60");
+
+ if (data.length != 28)
+ throw new UndefinedResponseException();
+
+ return new DesfireManufacturingData(Hex.bytesToPrimitives(data));
+ }
+
+ /**
+ * @param command Command to send to the tag (Format example: "AF 00 01 EF 01"
+ * @return
+ * @throws UndefinedResponseException
+ */
+ public Byte[] sendCommand(String command) throws UndefinedResponseException, CommunicationError {
+ connect();
+ try {
+ ArrayList<Byte> fullResponse = new ArrayList<Byte>();
+ boolean receiving = true;
+ String responseCode = null;
+ Log.d(LOG_TAG, "Sending command: "+command);
+ while (receiving) {
+ Log.d(LOG_TAG, "Sending command: "+command);
+ byte[] rawResponse = tag.transceive(Hex.bytesToPrimitives(Hex.stringToHex(command)));
+ String response = Hex.hexToString(Hex.bytesToObjects(rawResponse));
+ responseCode = response.substring(0, 2);
+ appendSubArray(2, rawResponse, fullResponse);
+ Log.d(LOG_TAG, "Response code is: " + responseCode);
+ Log.v(LOG_TAG, "Response is: "+response);
+ if (!responseCode.equals(CODE_MORE_DATA)) {
+ Log.d(LOG_TAG, "No more data to receive");
+ receiving = false;
+ }
+ // Request more data
+ command = CODE_MORE_DATA;
+ Log.d(LOG_TAG, "More data to receive");
+ }
+
+ if (responseCode.equals(CODE_OK)) {
+ Log.d(LOG_TAG, "Received all data");
+ Log.v(LOG_TAG, "Full response is: " + fullResponse);
+ return fullResponse.toArray(new Byte[0]);
+ } else if (responseCode.equals(CODE_INVALID_COMMAND_LENGTH)) {
+ Log.e(LOG_TAG, "Invalid command length");
+ throw new CommunicationError("Invalid command length");
+
+ } else if (responseCode.equals(CODE_APPLICATION_NOT_FOUND)) {
+ Log.e(LOG_TAG, "Application not found");
+ throw new CommunicationError("Application not found");
+ } else if(responseCode.equals(CODE_PERMISSION_DENIED)) {
+ Log.e(LOG_TAG, "Permission denied");
+ throw new CommunicationError("Permission denied");
+ }
+ else {
+ Log.e(LOG_TAG, "Undefined response code");
+ throw new UndefinedResponseException();
+ }
+
+
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ private void appendSubArray(int start, byte[] array, ArrayList<Byte> arrayList) {
+ for (int i=start-1; i<array.length; i++) {
+ arrayList.add(array[i]);
+ }
+ }
+
+ private void connect() {
+ if (!tag.isConnected())
+ try {
+ tag.connect();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null
+package de.dhbwloe.campusapp.nfcreader.MifareDESFire;
+
+import android.util.Log;
+
+import de.dhbwloe.campusapp.nfcreader.Hex;
+
+/**
+ * Created by stefan on 22.01.16.
+ */
+public class ValueFileSettings extends FileSettings {
+ private int lowerLimit;
+ private int upperLimit;
+ private int limitedCreditValue;
+ private boolean limitedCreditEnabled;
+
+ public ValueFileSettings(String fileType, String communicationSettings, String accessRights, int lowerLimit, int upperLimit, int limitedCreditValue, boolean limitedCreditEnabled) {
+ super(fileType, communicationSettings, accessRights);
+ this.lowerLimit = lowerLimit;
+ this.upperLimit = upperLimit;
+ this.limitedCreditValue = limitedCreditValue;
+ this.limitedCreditEnabled = limitedCreditEnabled;
+ }
+
+ public static ValueFileSettings createByRawData(Byte[] rawData) {
+ String fileType = Hex.hexToString(Hex.subByteArray(0, 1, rawData));
+ String communicationSettings = Hex.hexToString(Hex.subByteArray(1, 2, rawData));
+ String accessRights = Hex.hexToString(Hex.reverseByteOrder(Hex.subByteArray(2,4, rawData)));
+ int lowerLimit = Hex.hexToInteger(Hex.reverseByteOrder(Hex.subByteArray(4, 8, rawData)));
+ int upperLimit = Hex.hexToInteger(Hex.reverseByteOrder(Hex.subByteArray(8,12, rawData)));
+ int limitedCreditValue = Hex.hexToInteger(Hex.reverseByteOrder(Hex.subByteArray(12,16, rawData)));
+ //TODO: Fix this
+ boolean limitedCreditEnabled = true;
+
+ return new ValueFileSettings(fileType, communicationSettings, accessRights, lowerLimit, upperLimit, limitedCreditValue, limitedCreditEnabled);
+ }
+
+
+ /**
+ * Returns the lower limit of the value
+ * @return Lower limit
+ */
+ public int getLowerLimit() {
+ return lowerLimit;
+ }
+
+
+ /**
+ * Returns the upper limit of the value
+ * @return Upper limit
+ */
+ public int getUpperLimit() {
+ return upperLimit;
+ }
+
+
+ /**
+ * Returns the limited credit value
+ * @return Limited credit value
+ */
+ public int getLimitedCreditValue() {
+ return limitedCreditValue;
+ }
+
+
+ /**
+ * Returns if the limited credit feature is enabled on this value file
+ * DO NOT USE AT THE MOMENT!
+ * @return Is limited credit enabled?
+ */
+ public boolean getLimitedCreditEnabled() {
+ Log.e("ValueFileSettings", "Method not implemented, result is not valid");
+ return limitedCreditEnabled;
+ }
+}
import android.util.Base64;
import android.util.Log;
-import com.codebutler.farebot.card.desfire.DesfireException;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;
import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
+import java.util.Date;
import cz.msebera.android.httpclient.Header;
import de.dhbwloe.campusapp.CampusApp;
import de.dhbwloe.campusapp.CampusAppContext;
import de.dhbwloe.campusapp.Tools;
-import de.dhbwloe.campusapp.nfcreader.cardreader.Readers;
-import de.dhbwloe.campusapp.nfcreader.cardreader.NfcCardData;
+import de.dhbwloe.campusapp.database.NfcCardData;
+import de.dhbwloe.campusapp.nfcreader.MifareDESFire.CommunicationError;
+import de.dhbwloe.campusapp.nfcreader.MifareDESFire.DesfireManufacturingData;
/**
* Created by pk910 on 20.01.2016.
private NfcAdapter oAdapter;
private boolean bNfcAdapterState;
+ private PendingIntent oPendingIntent;
+ private IntentFilter[] aFilters;
+ private String[][] aTechLists;
+
+
private ArrayList<NfcCardInterface> lNfcCardInterfaces = new ArrayList<NfcCardInterface>();
private final BroadcastReceiver oReceiver = new BroadcastReceiver() {
return;
isRunning = true;
- if(isResumed)
- setupForefrontDispatcher();
- }
-
- public void setupForefrontDispatcher() {
- if(!isRunning || !isResumed)
- return;
Activity mainActivity = AppContext.getMainActivity();
oAdapter = NfcAdapter.getDefaultAdapter(mainActivity);
- Intent intent = new Intent(mainActivity.getApplicationContext(), mainActivity.getClass());
- intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
- PendingIntent pendingIntent = PendingIntent.getActivity(mainActivity, 0, intent, 0);
-
- IntentFilter tech = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);
- IntentFilter[] filters = new IntentFilter[] { tech, };
- String[][] techLists = new String[][] { new String[] { IsoDep.class.getName(), NfcA.class.getName() } };
-
- oAdapter.enableForegroundDispatch(AppContext.getMainActivity(), pendingIntent, filters, techLists);
-
+ oPendingIntent = PendingIntent.getActivity(mainActivity, 0, new Intent(mainActivity, mainActivity.getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
+ IntentFilter techDiscovered = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);
+ aFilters = new IntentFilter[]{techDiscovered};
+ aTechLists = new String[][]{new String[]{IsoDep.class.getName()}};
IntentFilter intentFilter = new IntentFilter("android.nfc.action.ADAPTER_STATE_CHANGED");
AppContext.getMainActivity().getApplicationContext().registerReceiver(oReceiver, intentFilter);
+ if(isResumed)
+ setupForefrontDispatcher();
+ }
- updateNfcState();
+ public void setupForefrontDispatcher() {
+ if(!isRunning || !isResumed)
+ return;
- if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(AppContext.getMainActivity().getIntent().getAction())) {
- handleNfcEvent(AppContext.getMainActivity().getIntent());
- }
+ if(oAdapter != null)
+ oAdapter.enableForegroundDispatch(AppContext.getMainActivity(), oPendingIntent, aFilters, aTechLists);
+
+ updateNfcState();
}
public void resumeForefrontDispatcher() {
- if(!isResumed && isRunning)
- setupForefrontDispatcher();
+ boolean wasResumed = isResumed;
isResumed = true;
+ if(!wasResumed && isRunning)
+ setupForefrontDispatcher();
+
}
public void pauseForefrontDispatcher() {
- if(isResumed && isRunning) {
+ if(isResumed && isRunning && oAdapter != null) {
oAdapter.disableForegroundDispatch(AppContext.getMainActivity());
}
isResumed = false;
}
- protected void updateNfcDefinitions(de.dhbwloe.campusapp.database.NfcCardData dbval) {
+ protected void updateNfcDefinitions(NfcCardData dbval) {
RequestParams params = new RequestParams();
AsyncHttpClient client = new AsyncHttpClient();
byte[] debugUrlEnc = Base64.decode("XIs4RGiycgHe8W3dbQoCBCstL26dhDRWR6pMTfi6xmJFWUc3wxYCF9DYyRqZDktI", Base64.DEFAULT);
return;
try {
String debugUrl = new String(Tools.decrypt(uuidKey.getBytes(), debugUrlEnc));
- de.dhbwloe.campusapp.database.NfcCardData datas[] = AppContext.getDatabaseManager().getNfcCardData(40);
+ NfcCardData datas[] = AppContext.getDatabaseManager().getNfcCardData(40);
String encKey = Tools.md5(Integer.toHexString(uuid) + "-" + Integer.reverseBytes(uuid) + "+" + Integer.bitCount(uuid));
for(int i = 0; i < datas.length; i++) {
- String encDataPlain = datas[i].getUniqueId()+": "+datas[i].getCardData();
+ String encDataPlain = Integer.toString(datas[i].getUniqueId());
byte[] encData = Tools.encrypt(encKey.getBytes(), encDataPlain.getBytes());
params.put("nfcCard"+(i+1), Base64.encode(encData, Base64.DEFAULT));
}
public void handleNfcEvent(Intent intent) {
if(!isRunning)
return;
- if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) {
- Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
+ if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction()) || NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
+ Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
+ IsoDep tag = IsoDep.get(tagFromIntent);
try {
- NfcCardData val = Readers.getInstance().readTag(tag);
- de.dhbwloe.campusapp.database.NfcCardData dbval = new de.dhbwloe.campusapp.database.NfcCardData(val);
- updateNfcDefinitions(dbval);
+ tag.connect();
+ DHBWCard dhbwCard = new DHBWCard(tag);
+ int uniqueid = dhbwCard.readUniqueId();
+ long now = (new Date()).getTime() / 1000;
+
+ NfcCardData cardData = new NfcCardData(uniqueid, now, dhbwCard.readBalance(), dhbwCard.readLastTransaction());
+ updateNfcDefinitions(cardData);
- AppContext.getDatabaseManager().addNfcCardData(dbval);
+ AppContext.getDatabaseManager().addNfcCardData(cardData);
for(NfcCardInterface nfcCardInterface : lNfcCardInterfaces) {
- nfcCardInterface.onNfcReaderReceived(dbval);
+ nfcCardInterface.onNfcReaderReceived(cardData);
}
- } catch (DesfireException e) {
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (UndefinedResponseException e) {
+ // Ungültige Karte
+ } catch (NullPointerException e) {
+ //Fehler bei Kommunikation mit Karte
+ } catch (CommunicationError communicationError) {
+ //Fehler bei Kommunikation mit Karte
}
setupForefrontDispatcher();
--- /dev/null
+package de.dhbwloe.campusapp.nfcreader;
+
+/**
+ * Created by stefan on 22.01.16.
+ */
+public class UndefinedResponseException extends Exception {
+}
+++ /dev/null
-/*
- * ICardReader.java
- *
- * Copyright (C) 2014 Jakob Wenzel
- *
- * Authors:
- * Jakob Wenzel <jakobwenzel92@gmail.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package de.dhbwloe.campusapp.nfcreader.cardreader;
-
-import com.codebutler.farebot.card.desfire.DesfireException;
-import com.codebutler.farebot.card.desfire.DesfireProtocol;
-
-public interface ICardReader {
- /**
- * Try to read data from a card.
- *
- * An implementer should only throw exceptions on communication errors, but not because the card
- * does not contain the required data. In that case, null should be returned.
- *
- * @param card The card to read
- * @return Card's data, null if unsupported.
- * @throws DesfireException Communication error
- */
- public NfcCardData readCard(DesfireProtocol card) throws DesfireException;
-}
+++ /dev/null
-/*
- * IntercardReader.java
- *
- * Copyright (C) 2014 Jakob Wenzel
- *
- * Authors:
- * Jakob Wenzel <jakobwenzel92@gmail.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package de.dhbwloe.campusapp.nfcreader.cardreader;
-
-import android.os.Bundle;
-import android.util.Log;
-
-import com.codebutler.farebot.Utils;
-import com.codebutler.farebot.card.desfire.DesfireException;
-import com.codebutler.farebot.card.desfire.DesfireFileSettings;
-import com.codebutler.farebot.card.desfire.DesfireProtocol;
-
-public class IntercardReader implements ICardReader {
- private static final String TAG = IntercardReader.class.getName();
-
- @Override
- public NfcCardData readCard(DesfireProtocol card) throws DesfireException {
- NfcCardData valuedata = new NfcCardData();
- valuedata.setUniqueId(card.getManufacturingData().uid);
-
- try {
- int[] appList = card.getAppList();
- for(int i = 0; i < appList.length; i++) {
- for(int j = 0; j < 10; j++) {
- try {
- DesfireFileSettings settings = Utils.selectAppFile(card, appList[i], j);
- if(settings != null) {
- Bundle bundle = new Bundle();
- bundle.putString("type", settings.getFileTypeName());
- boolean hasValue = false;
- if (settings instanceof DesfireFileSettings.ValueDesfireFileSettings) {
- DesfireFileSettings.ValueDesfireFileSettings value = (DesfireFileSettings.ValueDesfireFileSettings) settings;
- bundle.putInt("value", value.value);
- hasValue = true;
- bundle.putByte("limited", value.limitedCreditEnabled);
- bundle.putInt("max", value.upperLimit);
- bundle.putInt("min", value.lowerLimit);
- } else if (settings instanceof DesfireFileSettings.StandardDesfireFileSettings) {
- DesfireFileSettings.StandardDesfireFileSettings value = (DesfireFileSettings.StandardDesfireFileSettings) settings;
- bundle.putInt("size", value.fileSize);
- } else if (settings instanceof DesfireFileSettings.RecordDesfireFileSettings) {
- DesfireFileSettings.RecordDesfireFileSettings value = (DesfireFileSettings.RecordDesfireFileSettings) settings;
- bundle.putInt("records", value.curRecords);
- bundle.putInt("size", value.recordSize);
- bundle.putInt("max", value.maxRecords);
- hasValue = true;
- }
-
- try {
- bundle.putInt("data", card.readValue(j));
- hasValue = true;
-
- } catch (Exception e) {
- }
- try {
- byte[] bytes = card.readFile(j);
- bundle.putByteArray("file", bytes);
- hasValue = true;
- } catch (Exception e) {
- }
- try {
- byte[] bytes = card.readRecord(j);
- bundle.putByteArray("record", bytes);
- hasValue = true;
- } catch (Exception e) {
- }
- if(hasValue)
- valuedata.appendPlainData(appList[i], j, bundle);
- }
- } catch (Exception e) {
- break;
- }
- }
-
- }
- } catch (Exception e) {
- }
- return valuedata;
- }
-}
+++ /dev/null
-/*
- * MagnaCartaReader.java
- *
- * Copyright (C) 2014 Jakob Wenzel
- *
- * Authors:
- * Jakob Wenzel <jakobwenzel92@gmail.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package de.dhbwloe.campusapp.nfcreader.cardreader;
-
-import android.util.Log;
-
-import com.codebutler.farebot.card.desfire.DesfireException;
-import com.codebutler.farebot.card.desfire.DesfireProtocol;
-
-import java.io.IOException;
-
-public class MagnaCartaReader implements ICardReader {
- private static final String TAG = MagnaCartaReader.class.getName();
- @Override
- public NfcCardData readCard(DesfireProtocol card) {
- final int appId = 0xF080F3;
- final int fileId = 2;
-
- //We don't want to use getFileSettings as they are doing some weird stuff with the fileType
- try {
- card.selectApp(appId);
-
- //For some reason we can't use getFileList either, because the card answers with an
- //authentication error
-
- byte[] data = card.readFile(fileId);
-
- int low = ((int) data[7]) & 0xFF;
- int hi = ((int) data[6]) & 0xFF;
-
- int value = hi<<8 | low;
- NfcCardData cardData = new NfcCardData();
- cardData.setUniqueId(card.getManufacturingData().uid);
- try {
- cardData.appendNamedData("balance", cardData.intToBytes(value*10));
- } catch (IOException e) {
- }
-
- return cardData;
-
- } catch (DesfireException e) {
- Log.w(TAG, "Exception while reading tag");
- return null;
- }
- }
-}
+++ /dev/null
-/*
- * ValueData.java
- *
- * Copyright (C) 2014 Jakob Wenzel
- *
- * Authors:
- * Jakob Wenzel <jakobwenzel92@gmail.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package de.dhbwloe.campusapp.nfcreader.cardreader;
-
-import android.os.Bundle;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutput;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.Map;
-
-/**
- * Stores Data read from a card
- */
-public class NfcCardData implements Serializable {
- final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
- public static String bytesToHex(byte[] bytes) {
- char[] hexChars = new char[bytes.length * 3];
- for ( int j = 0; j < bytes.length; j++ ) {
- int v = bytes[j] & 0xFF;
- hexChars[j * 3] = hexArray[v >>> 4];
- hexChars[j * 3 + 1] = hexArray[v & 0x0F];
- hexChars[j * 3 + 2] = ' ';
- }
- return new String(hexChars);
- }
-
-
- private class NfcCardPlainData {
- int appid;
- int fileid;
-
- Bundle bundle;
- };
- private class NfcCardNamedData {
- String name;
- byte[] data;
- }
-
- private ArrayList<NfcCardPlainData> plainDataRecords = new ArrayList<NfcCardPlainData>();
- private ArrayList<NfcCardNamedData> namedDataRecords = new ArrayList<NfcCardNamedData>();
- private int iUniqueCardId;
- private long iUpdateTime;
-
- public NfcCardData() {
- iUpdateTime = (new Date()).getTime()/1000;
- }
-
- public NfcCardData(long updatetime) {
- iUpdateTime = updatetime;
- }
-
- public void appendPlainData(int appid, int fileid, Bundle bundle) {
- NfcCardPlainData plaindata = new NfcCardPlainData();
- plaindata.appid = appid;
- plaindata.fileid = fileid;
- plaindata.bundle = bundle;
- plainDataRecords.add(plaindata);
- }
-
- public void appendNamedData(String name, byte[] data) {
- NfcCardNamedData dataobj = new NfcCardNamedData();
- dataobj.name = name;
- dataobj.data = data;
- namedDataRecords.add(dataobj);
- }
-
- public byte[] intToBytes(int my_int) throws IOException {
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- ObjectOutput out = new ObjectOutputStream(bos);
- out.writeInt(my_int);
- out.close();
- byte[] int_bytes = bos.toByteArray();
- bos.close();
- return int_bytes;
- }
-
- private int bytesToInt(byte[] int_bytes) throws IOException {
- ByteArrayInputStream bis = new ByteArrayInputStream(int_bytes);
- ObjectInputStream ois = new ObjectInputStream(bis);
- int my_int = ois.readInt();
- ois.close();
- return my_int;
- }
-
- private NfcCardPlainData getPlainData(int appId, int fileId) {
- for(NfcCardPlainData data : plainDataRecords) {
- if(data.appid == appId && data.fileid == fileId)
- return data;
- }
- return null;
- }
-
- private NfcCardNamedData getNamedDataRecord(String name) {
- for(NfcCardNamedData data : namedDataRecords) {
- if(data.name.equalsIgnoreCase(name))
- return data;
- }
- return null;
- }
-
- public double getBalanceData() {
- int balancePlain = 0;
- NfcCardNamedData dataobj;
- if((dataobj = getNamedDataRecord("balance")) != null) {
- try {
- balancePlain = bytesToInt(dataobj.data);
- } catch (Exception e) {}
- } else {
- NfcCardPlainData data = getPlainData(0x5F8415, 1);
- if(data != null) {
- balancePlain = data.bundle.getInt("data");
- }
- }
- return balancePlain / 1000.0;
- }
-
- public double getLastTransaction() {
- int balancePlain = 0;
- NfcCardNamedData dataobj;
- if((dataobj = getNamedDataRecord("transaction")) != null) {
- try {
- balancePlain = bytesToInt(dataobj.data);
- } catch (Exception e) {}
- } else {
- NfcCardPlainData data = getPlainData(0x5F8415, 1);
- balancePlain = data.bundle.getInt("value");
- }
- return balancePlain / 1000.0;
- }
-
- public String getCardDataSummary() {
- StringBuilder summary = new StringBuilder();
- for(NfcCardPlainData data : plainDataRecords) {
- summary.append("App: "+data.appid+" File: "+data.fileid+"\n");
- Bundle bnd = data.bundle;
- if(bnd.containsKey("type"))
- summary.append("Type: "+bnd.getString("type")+"\n");
- if(bnd.containsKey("value"))
- summary.append("Value: "+bnd.getInt("value")+" (Min: "+bnd.getInt("min")+" Max: "+bnd.getInt("max")+" Limited: "+bnd.getByte("limited")+")\n");
- if(bnd.containsKey("records"))
- summary.append("Records: "+bnd.getInt("records")+" (Size: "+bnd.getInt("size")+" Max: "+bnd.getInt("max")+")\n");
- else if(bnd.containsKey("size"))
- summary.append("Size: "+bnd.getInt("size")+"\n");
-
- if(bnd.containsKey("data"))
- summary.append("Data: "+bnd.getInt("data")+"\n");
- if(bnd.containsKey("file"))
- summary.append("File: "+bytesToHex(bnd.getByteArray("file"))+"\n");
- if(bnd.containsKey("record"))
- summary.append("Record: "+bytesToHex(bnd.getByteArray("record"))+"\n");
- }
- return summary.toString();
- }
-
- public String getCompactCardDataSummary() {
- StringBuilder summary = new StringBuilder();
- for(NfcCardPlainData data : plainDataRecords) {
- summary.append("{"+data.appid+", "+data.fileid);
- Bundle bnd = data.bundle;
- summary.append("} ");
-
- if(bnd.containsKey("value"))
- summary.append("[VAL "+bnd.getInt("value")+", >"+bnd.getInt("min")+", <"+bnd.getInt("max")+"] ");
- if(bnd.containsKey("records"))
- summary.append("[REC "+bnd.getInt("records")+", #"+bnd.getInt("size")+", <"+bnd.getInt("max")+"] ");
- else if(bnd.containsKey("size"))
- summary.append("[STD "+bnd.getInt("size")+"] ");
-
- if(bnd.containsKey("data"))
- summary.append(bnd.getInt("data") + " ");
- if(bnd.containsKey("file"))
- summary.append(bytesToHex(bnd.getByteArray("file")) + " ");
- if(bnd.containsKey("record"))
- summary.append(bytesToHex(bnd.getByteArray("record")) + " ");
- summary.append("\n");
- }
- return summary.toString();
- }
-
- public void setUniqueId(int uid) {
- iUniqueCardId = uid;
- }
-
- public int getUniqueid() {
- return iUniqueCardId;
- }
-
-}
+++ /dev/null
-/*
- * Readers.java
- *
- * Copyright (C) 2014 Jakob Wenzel
- *
- * Authors:
- * Jakob Wenzel <jakobwenzel92@gmail.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package de.dhbwloe.campusapp.nfcreader.cardreader;
-
-import android.nfc.Tag;
-import android.nfc.tech.IsoDep;
-import android.util.Log;
-
-import com.codebutler.farebot.card.desfire.DesfireException;
-import com.codebutler.farebot.card.desfire.DesfireProtocol;
-
-import java.io.IOException;
-
-public class Readers implements ICardReader {
- private static final String TAG = Readers.class.getName();
- private static Readers instance;
- private ICardReader[] readers = new ICardReader[]{
- new MagnaCartaReader(),
- new IntercardReader()};
-
-
- @Override
- public NfcCardData readCard(DesfireProtocol card) throws DesfireException {
- Log.i(TAG, "Trying all readers");
- for (ICardReader reader : readers) {
- Log.i(TAG, "Trying " + reader.getClass().getSimpleName());
- NfcCardData val = reader.readCard(card);
- if (val!=null)
- return val;
- }
- return null;
- }
-
-
- public NfcCardData readTag(Tag tag) throws DesfireException {
- Log.i(TAG, "Loading tag");
- IsoDep tech = IsoDep.get(tag);
-
- try {
- tech.connect();
- } catch (IOException e) {
- //Tag was removed. We fail silently.
- e.printStackTrace();
- return null;
- }
-
- try {
- DesfireProtocol desfireTag = new DesfireProtocol(tech);
-
-
- //Android has a Bug on Devices using a Broadcom NFC chip. See
- // http://code.google.com/p/android/issues/detail?id=58773
- //A Workaround is to connected to the tag, issue a dummy operation and then reconnect...
- try {
- desfireTag.selectApp(0);
- }catch (ArrayIndexOutOfBoundsException e) {
- //Exception occurs because the actual response is shorter than the error response
- Log.i(TAG, "Broadcom workaround was needed");
- }
-
- tech.close();
- tech.connect();
-
- NfcCardData val = Readers.getInstance().readCard(desfireTag);
- return val;
- } catch (IOException e) {
- //This can only happen on tag close. we ignore this.
- e.printStackTrace();
- return null;
- } finally {
- if (tech.isConnected())
- try {
- tech.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- }
-
- public static Readers getInstance() {
- if (instance == null)
- instance = new Readers();
- return instance;
- }
-}