/* NFCard 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. NFCard 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 Wget. If not, see <http://www.gnu.org/licenses/>. Additional permission under GNU GPL version 3 section 7 */ package com.zzx.factorytest.nfc.card.pboc; import java.util.ArrayList; import android.content.res.Resources; import com.zzx.factorytest.R; import com.zzx.factorytest.nfc.Util; import com.zzx.factorytest.nfc.tech.Iso7816; import com.zzx.factorytest.nfc.tech.Iso7816.BerT; final class HardReader extends PbocCard { public static final byte TMPL_PDR = 0x70; // Payment Directory Entry Record public static final byte TMPL_PDE = 0x61; // Payment Directory Entry private HardReader(Iso7816.Tag tag, byte[] name, Resources res) { super(tag); this.name = (name != null) ? Util.toHexString(name, 0, name.length) : res.getString(R.string.name_unknowntag); } @SuppressWarnings("unchecked") final static HardReader load(Iso7816.Tag tag, Resources res) { /*--------------------------------------------------------------*/ // select PSF (1PAY.SYS.DDF01) /*--------------------------------------------------------------*/ if (!tag.selectByName(DFN_PSE).isOkey() && !tag.selectByID(DFI_MF).isOkey()) return null; /*--------------------------------------------------------------*/ // read balance /*--------------------------------------------------------------*/ Iso7816.Response CASH = getBalance(tag); Iso7816.Response INFO = null; ArrayList<byte[]> LOG = new ArrayList<byte[]>(); byte[] name = null; /*--------------------------------------------------------------*/ // try to find AID list /*--------------------------------------------------------------*/ ArrayList<byte[]> AIDs = findAIDs(tag); for (final byte[] aid : AIDs) { /*--------------------------------------------------------------*/ // select Main Application /*--------------------------------------------------------------*/ if ((name = selectAID(tag, aid)) != null) { /*--------------------------------------------------------------*/ // read balance /*--------------------------------------------------------------*/ if (!CASH.isOkey()) CASH = getBalance(tag); /*--------------------------------------------------------------*/ // read card info file, binary (21) /*--------------------------------------------------------------*/ if (INFO == null || !INFO.isOkey()) INFO = tag.readBinary(SFI_EXTRA); /*--------------------------------------------------------------*/ // read log file, record (24) /*--------------------------------------------------------------*/ LOG.addAll(readLog(tag, SFI_LOG)); } } /*--------------------------------------------------------------*/ // try to PXX AID /*--------------------------------------------------------------*/ if ((INFO == null || !INFO.isOkey()) && ((name = selectAID(tag, DFN_PXX)) != null)) { if (!CASH.isOkey()) CASH = getBalance(tag); INFO = tag.readBinary(SFI_EXTRA); LOG.addAll(readLog(tag, SFI_LOG)); } /*--------------------------------------------------------------*/ // try to 0x1001 AID /*--------------------------------------------------------------*/ if ((INFO == null || !INFO.isOkey()) && tag.selectByID(DFI_EP).isOkey()) { name = DFI_EP; if (!CASH.isOkey()) CASH = getBalance(tag); INFO = tag.readBinary(SFI_EXTRA); LOG.addAll(readLog(tag, SFI_LOG)); } if (!CASH.isOkey() && INFO == null && LOG.isEmpty() && name == null) return null; /*--------------------------------------------------------------*/ // build result string /*--------------------------------------------------------------*/ final HardReader ret = new HardReader(tag, name, res); ret.parseBalance(CASH); if (INFO != null) ret.parseInfo(INFO, 0, false); ret.parseLog(LOG); return ret; } private static byte[] selectAID(Iso7816.Tag tag, byte[] aid) { if (!tag.selectByName(DFN_PSE).isOkey() && !tag.selectByID(DFI_MF).isOkey()) return null; final Iso7816.Response rsp = tag.selectByName(aid); if (!rsp.isOkey()) return null; Iso7816.BerTLV tlv = Iso7816.BerTLV.read(rsp); if (tlv.t.match(Iso7816.BerT.TMPL_FCI)) { tlv = tlv.getChildByTag(Iso7816.BerT.CLASS_DFN); if (tlv != null) return tlv.v.getBytes(); } return aid; } private static ArrayList<byte[]> findAIDs(Iso7816.Tag tag) { ArrayList<byte[]> ret = new ArrayList<byte[]>(); for (int i = 1; i <= 31; ++i) { Iso7816.Response r = tag.readRecord(i, 1); for (int p = 2; r.isOkey(); ++p) { byte[] aid = findAID(r); if (aid == null) break; ret.add(aid); r = tag.readRecord(i, p); } } return ret; } private static byte[] findAID(Iso7816.Response record) { Iso7816.BerTLV tlv = Iso7816.BerTLV.read(record); if (tlv.t.match(TMPL_PDR)) { tlv = tlv.getChildByTag(BerT.CLASS_ADO); if (tlv != null) { tlv = tlv.getChildByTag(BerT.CLASS_AID); return (tlv != null) ? tlv.v.getBytes() : null; } } return null; } private static Iso7816.Response getBalance(Iso7816.Tag tag) { final Iso7816.Response rsp = tag.getBalance(true); return rsp.isOkey() ? rsp : tag.getBalance(false); } }